<!--
  dsh-todo-list English documentation (default). Chinese version: README.zh.md.
-->

> **English** · [Chinese](README.zh.md)

# dsh-todo-list — a To Do List plugin for DeepSeek Harness (DSH)

A deployment-level DeepSeek Harness (DSH) To Do List plugin: it recognizes key items from conversations — natural chat, imported notifications, announcements, and email content — turns them into dated to-dos, and manages them from the To Do List entry in the left sidebar. The plugin mounts as a bundle into a profile (`dsh plugin add` one-click install) without modifying DSH source. No approval or configuration needed; data and the entry survive restarts.

## Feature Overview

- **Understand-notification skill**: a packaged skill (`understand-notification`, ships in `skills/` and registers through a dedicated `todo-skills` provider) that teaches the model to extract actionable items from notifications, announcements, emails and conversations into a structured JSON — pure extraction rules, no tool calls inside the skill.
- **Extract to-dos with preview & confirm**: the model parses the text per the skill and calls `todo_preview` to stage candidates; a multi-select popup appears, and items are written only after you confirm — nothing is added without your approval.
- **Seven model tools**: `todo_preview` / `todo_add` / `todo_list` / `todo_complete` / `todo_remove` / `todo_update` / `todo_today` for staged-preview and direct CRUD inside a session.
- **REST API**: `/api/todo` with list, batch-add, update, delete and clear-completed endpoints, plus `/api/todo/pending` (list / stage / clear) and `POST /api/todo/pending/confirm` for the preview-confirm flow.
- **Sidebar panel**: a To Do List entry plus Pending/Done tabs; click an item for details (due date, days left, urgency/importance, acceptance, notes). Both the detail popup and the preview popup are draggable by their headers.
- **Settings page**: language (Chinese / English), panel opacity and width, persisted automatically; the preview popup shares the same opacity setting.
- **Reliable persistence**: local JSON with atomic writes and legacy-data migration; nothing is lost on restart.

## Installation

Prerequisites: a working DSH web profile (usually at `$DSH_HOME/profiles/web`, with `DSH_HOME` defaulting to `~/.dsh`) and an available `dsh` command.

### Recommended: `dsh plugin add`

```sh
dsh plugin --profile web add dsh-todo-list
```

This runs `pnpm add dsh-todo-list` inside the profile directory; because the package declares `dsh.bundle.patch`, `dsh plugin` automatically appends it to the profile's bundle layer (`dsh.profile.bundles`) — no manual edits to `package.json` or `cordis.patch.yml`. Restart `dsh web` after installing.

### Alternative: local `file:` install

A `file:` install needs the **project source (this repository)**, not the npm package — the npm tarball only ships the compiled `lib/`, the packaged `skills/` and `cordis.patch.yml`, with no `src/` or TypeScript toolchain to build from. Get the source first:

```sh
git clone https://github.com/perry-ai/dsh-todo-list.git   # or download the zip from GitHub
```

Then build the output and declare the dependency:

```sh
# 1. Build the project in the source directory ($SRC)
cd "$SRC"
pnpm install        # the prepare script compiles src/ → lib/

# 2. Declare the dependency: edit $PROFILE/package.json, add to dependencies
#    "dsh-todo-list": "file:<path to $SRC>"

# 3. Join the composition: edit $PROFILE/cordis.patch.yml, append
#    - insert:
#        - id: dsh-todo-list
#          name: 'dsh-todo-list'

# 4. Install and restart
cd "$PROFILE"
pnpm install
```

A `file:` dependency is installed by copy (not linked); pnpm may skip copying when it detects no content change — use `pnpm install --force` in that case. The plugin is ready after restarting `dsh web`.

## Quick Start

Add to-dos directly in a DSH conversation using natural language, e.g.:

> Please note two items for me: send the draft quarterly business analysis report to management by August 26 — it's important; also submit last month's expense claim in early September, no rush.

The model automatically calls `todo_add`, parsing the text into to-dos (title / due date / urgency / importance / acceptance), e.g.:

```text
Added 2 to-dos:
[ ] 2026-08-26 Draft the quarterly business analysis report and send it to management (urgent, important, top priority) (7 day(s) left) — important
[ ] 2026-09-01 Submit last month's expense claim (13 day(s) left)
Now: 2 pending, 0 done
```

> Note: model tool output is currently rendered in Chinese; the English above is an illustration.

Then you can:

- call `todo_today` so the model converts relative dates ("tomorrow", "next Monday", "end of month") into concrete dates;
- use `todo_list` to view the list, and `todo_complete` / `todo_remove` / `todo_update` to maintain it (title, due date, urgency, importance, acceptance, notes, etc.);
- or open the To Do List entry in the left sidebar: switch between Pending/Done, click an item for details (due date, days left, urgency/importance, acceptance, notes), and open settings to switch the language or adjust opacity/width;
- or use the REST API directly: `GET http://127.0.0.1:3080/api/todo` to list, `POST /api/todo` to batch-add.

## Storage & migration

- The list lives at `$DSH_HOME/storages/dsh-todo-list/todos.json` with the shape `{ version, todos, nextId }`.
- Every change first writes `<file>.tmp` and then atomically renames it, avoiding half-written files.
- On first load, if the legacy `<cwd>/todos.json` from the old dynamic plugin exists, it is migrated to the new location; the original file is kept.
- Reads go through an in-memory snapshot that is refreshed after every write.

## Features

- **Model tools**: the Host registers 7 global tools — `todo_preview` / `todo_add` / `todo_list` / `todo_complete` / `todo_remove` / `todo_update` / `todo_today`. `todo_add` turns multiple items from a piece of text into to-dos in one call, each with a `YYYY-MM-DD` due date; `todo_preview` stages the parsed candidates for the confirm popup instead of writing them directly.
- **Understand-notification skill**: the packaged `understand-notification` skill defines the extraction rules (identify actionable items, resolve due dates — explicit or relative to the current date, judge urgency/importance, acceptance criteria, notes) and the exact JSON output shape; it carries no tool-call instructions — the bridge to `todo_preview` lives in the tool description. The skill is discovered from the package's `skills/` directory via the `todo-skills` provider (independent of the host `filesystem` provider).
- **Fields & priority**: every to-do carries a title, due date, urgency, importance, acceptance criteria and notes. The priority is derived automatically from urgency + importance — both high → urgent, shown as the badge URG in the list, either high → high, both medium → medium, either low → low.
- **REST API**: `GET /api/todo` (list), `POST /api/todo` (batch add), `PATCH /api/todo/:id` (update), `DELETE /api/todo/:id` (delete), `POST /api/todo/clear-completed` (clear completed); preview flow: `GET/POST/DELETE /api/todo/pending` (list / stage / clear candidates) and `POST /api/todo/pending/confirm` (write the checked candidates).
- **Sidebar entry**: a To Do List entry at the bottom of the sidebar — icon + label + pending-count badge in the wide bar, a round icon when collapsed to a rail. Clicking opens a panel with Pending/Done tabs; the pending tab shows a pending-count badge.
- **Detail popup**: click any row to float a detail popup to the right of the panel — due date, days left, color-coded urgency/importance, acceptance criteria and notes; the clicked row is highlighted. The popup is draggable by its header.
- **Preview-confirm popup**: when the model calls `todo_preview`, a popup (registered in the `shell.overlay` slot) shows the candidates with multi-select checkboxes; confirming writes the checked items via `/api/todo/pending/confirm`, cancelling clears them. Its visual language — background, opacity, rows, colors — matches the detail popup exactly, so both look identical side by side. Draggable by its header too.
- **Settings page**: the gear button opens settings to adjust the panel opacity (0.01–0.1) and width (150–350 px) with a slider plus a live numeric display, persisted to localStorage; the detail and preview popups share the same opacity value.
- **Persistence**: the list is stored at `$DSH_HOME/storages/dsh-todo-list/todos.json`, written via temp file + atomic rename so a crash never leaves a half-written file.
- **Theme adaptation**: the panel uses a translucent DeepSeek-brand blue and automatically adapts to DSH web's dark/light theme (based on `body[data-ds-dark-theme]`); the sidebar footer stacking fix is built into the client styles, no platform source changes needed.
- **Internationalization**: every UI string is defined in zh/en dictionaries; the plugin starts in the DSH language and offers a language switcher (Chinese / English) in its settings page.

## Architecture

- `src/index.ts` mounts the `/api/todo` prefix routes through the `webServer` service, registers the 7 model tools through the optional `tools` service, and registers the packaged-skill provider through the optional `skills` service.
- `src/skill-provider.ts` scans the packaged `skills/` directory (`<name>/SKILL.md` or `<name>.md`), parses minimal frontmatter (name / description / whenToUse), and exposes them as a filesystem-style skill provider — zero extra runtime dependencies, and no conflict with the host `filesystem` provider (unique provider name `todo-skills`, scans only its own directory).
- `src/types.ts` declares domain types and shared constants; `src/services.ts` declares the structured subset contracts (types only, zero runtime) of the DSH/Cordis services this plugin consumes.
- `src/store.ts` handles persistence: in-memory snapshot + atomic rename writes, migrating old dynamic-plugin data on first load.
- `src/domain.ts` centralizes validation (title, date format), days-left math, priority derivation (`derivePriority`), item projection and CRUD, plus candidate staging for the preview flow (`stageCandidates` / `pendingSnapshot` / `confirmPending` / `clearPending`).
- `src/api.ts` dispatches REST routes; request bodies are JSON, capped at 1 MiB (413 when exceeded, 400 for invalid JSON). Besides CRUD it serves `/api/todo/pending` (GET list / POST stage / DELETE clear) and `POST /api/todo/pending/confirm`.
- `src/tools.ts` defines the JSON Schemas and text rendering of the 7 `todo_*` tools (`todo_preview` stages candidates without writing).
- `src/client.ts` is the browser half: it self-registers as a single file via `window.__ModuleLoader__`, injects styles, and mounts the sidebar entry, detail popup, settings page and the preview-confirm popup (registered in the `shell.overlay` slot), reading and mutating data through `/api/todo`. The detail and preview popups share the same opacity setting and are draggable by their headers.

## Build

Requires Node 22.19+ / 24+ (same as DSH) and the TypeScript toolchain:

```sh
pnpm install   # installs devDependencies and triggers the prepare build into lib/
pnpm build     # manual build: tsc -p tsconfig.json, src → lib
pnpm typecheck # type-check only: tsc --noEmit
```

`lib/` is build output and is not committed (see `.gitignore`); `pnpm install` regenerates it from `src/` via the `prepare` script, so run `pnpm install` once in this project before a `file:` install. The published package ships `.d.ts` declarations, so TypeScript consumers get types out of the box.

## Manual verification

1. Mount the plugin and restart `dsh web`; confirm the To Do List entry appears at the bottom of the sidebar.
2. In a session, call `todo_today` to get today's date, then `todo_add` to batch-add items.
3. Call `todo_list`; confirm every item returns a title, due date and days left.
4. Open the sidebar panel and switch between Pending/Done; confirm the pending-count badge and that completed items show no due badge.
5. Click an item to open the detail popup; confirm due date, days left, color-coded urgency/importance, acceptance criteria and notes; the clicked row is highlighted.
6. Open the settings page and adjust opacity and width; confirm changes apply immediately and persist.
7. Request `GET /api/todo` and confirm `{"todos":[...]}`; PATCH an item as done, list again, and confirm the done state and pending count change.
8. Restart the Harness and confirm the to-dos are still there.

## Known limitations

- No cross-process file lock: with several Hosts running against the same `$DSH_HOME`, each process keeps its own in-memory snapshot and writes may overwrite each other.
- To-dos are not shown inside the conversation; they are managed only via the sidebar entry and the `todo_*` tools.
- Priority cannot be set manually; it is always derived from urgency and importance.
- The sidebar footer fix depends on the CSS class `[class*="footerActions"]`; renaming it in the platform would break the layout.
- Relative dates (tomorrow / next Monday, etc.) are converted to concrete dates only after the model calls `todo_today` first.
- Preview candidates are held in memory: they are discarded on a process restart, and a new `todo_preview` call replaces the whole pending set. Nothing is written until you confirm in the popup.
