dsh-todo-ledger 0.0.0-stage → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,114 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres to
5
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.3.1] - 2026-10-24
8
+
9
+ A follow-up on the floating window: its surface now matches the host's own floating panels, and the
10
+ status colours are the ones the panel has always used.
11
+
12
+ ### Fixed
13
+
14
+ - **The window surface no longer reads as a lighter grey than everything around it.** It used
15
+ `--dsw-alias-bg-overlay`, which resolves to a mid grey in the dark theme. It now takes the raised
16
+ layer the host's own floating panels use: `--dsw-alias-bg-layer-1`, a `--dsw-alias-border-l2`
17
+ border, a 14px radius and the same two-layer shadow.
18
+
19
+ ### Changed
20
+
21
+ - **Status colours are the previous palette again** — blue in progress, slate to do, violet awaiting
22
+ review, red blocked. Only the accept action and error text use the host state tokens.
23
+ - Count chips and task rows stay on `--dsw-alias-bg-layer-2` with a `--dsw-alias-border-l1` border,
24
+ and section titles, slugs and the footer use `--dsw-alias-label-secondary`.
25
+
26
+ ### Added
27
+
28
+ - A storefront icon (`assets/icon-180.png`, rendered from `assets/icon.svg`) and `screenshots.json`
29
+ declaring the sidebar and floating-window captures.
30
+ - Install-from-npm instructions in both READMEs, plus the npm version badge.
31
+
32
+ ## [0.3.0] - 2026-10-24
33
+
34
+ The release that gives the ledger a window of its own, and keeps every view on the session you are
35
+ actually looking at.
36
+
37
+ ### Added
38
+
39
+ - **Floating ledger window.** A `Todo` control under the composer opens a frame-wide window with the
40
+ same sections and sign-off action as the sidebar panel. Drag its header to move it, drag the
41
+ bottom-right grip to resize it (240×180 minimum, clamped to the viewport), and the box is restored
42
+ the next time it opens. Only the task list scrolls, so the counts row and the footer stay put however
43
+ long the queue gets.
44
+ - **Collapsible status groups.** Click a group header to fold it. Clicking a status count expands that
45
+ group and aligns its header to the top of the list, which keeps a long queue navigable without
46
+ dragging the chat page behind the window.
47
+ - **The window follows the session in front.** Switching sessions re-targets an open floating window
48
+ to the new session's workspace instead of leaving it on the session that opened it.
49
+
50
+ ### Changed
51
+
52
+ - The floating window starts at its status counts: the duplicate plugin name and in-body collapse from
53
+ the previous iteration are gone, because its own header already names the panel.
54
+ - The composer control reads as a plain dock item (`Todo`, the book icon, dock font and hover
55
+ treatment) rather than a filled chip.
56
+
57
+ ### Fixed
58
+
59
+ - The sidebar panel kept showing the previous ledger after switching to a session in another
60
+ workspace: the tab registration froze the session injected when it was created. It now reads the
61
+ session the slot dispatches, keeps one resource and one request per session, and re-reads when the
62
+ window comes back into focus.
63
+
64
+ ## [0.2.0] - 2026-10-24
65
+
66
+ The release that turns the ledger from a prompt-only capability into something you can watch and
67
+ sign off without leaving the conversation.
68
+
69
+ ### Added
70
+
71
+ - **Sidebar ledger panel.** A read-only tab in the right sidebar shows the ledger of the current
72
+ session's working directory: `doing`, `todo`, `review` and `blocked` sections with counts, a
73
+ colour per state, and a fixed order so the shape of the queue reads at a glance. It opens from the
74
+ sidebar guide capsule and polls only while visible.
75
+ - **Sign a review task off from the panel.** Each task under `review` carries an accept action; it
76
+ archives through the same path as `todo_complete` and records the click as both evidence and
77
+ sign-off (`accepted from the ledger panel at <ISO timestamp>`). Only `review` tasks can be accepted
78
+ this way; other states are refused with an inline error.
79
+ - **Host routes for the panel:** `GET /todo-ledger/projection?sessionId=…` returns the ledger
80
+ projection, and `GET /todo-ledger/complete?slug=…&sessionId=…` performs the single side-effecting
81
+ call. Both are registered as `prefix` routes and dispatched as `GET`, which is what the host's
82
+ plugin route layer supports.
83
+ - **Dependencies between tasks.** `todo_add` now accepts `depends_on` and `blocker_cause`; a task
84
+ whose predecessors are not yet finished is created as `blocked` with the dependency recorded, and
85
+ is created directly as `todo` when they already are. Unknown, dropped, self-referential and
86
+ circular predecessors are rejected.
87
+ - **Automatic unblocking on formal completion.** Completing a predecessor through `todo_complete` (or
88
+ the panel) promotes its dependents to `todo` once *all* predecessors are formally completed. A
89
+ `review` state, a dropped archive, or a manual blocker never unblocks anything, and hand-edited
90
+ state cannot fake it.
91
+
92
+ ### Changed
93
+
94
+ - The prompt section's hand-edit ban now names the three tool-owned surfaces explicitly — the status
95
+ lines in `todo.md`, the `tasks.md` index, and a task file's frontmatter — and points at
96
+ `todo_doctor` when they disagree, instead of the earlier catch-all wording.
97
+ - `README.md` and `README_zh.md` gained a sidebar panel section covering the opt-in entry point,
98
+ section ordering, visible-only polling, what acceptance records, and the restart/refresh boundary.
99
+
100
+ ### Fixed
101
+
102
+ - Registering the ledger no longer takes the session down when one of its parts fails; the feature
103
+ degrades instead, and the failing file and line are named.
104
+ - The prompt section no longer breaks session startup when a ledger file contains a `{{`-like
105
+ literal (such as another plugin's macro shell); such braces are rendered inert.
106
+ - Agent-written ledger content that would corrupt the state machine is flagged for rewrite instead
107
+ of being written silently.
108
+ - The accept call no longer fails with `HTTP 405`: the client sends `GET` with query parameters, and
109
+ the handler acts on whichever carrier holds the slug.
110
+
111
+ ## [0.1.0]
112
+
113
+ First release: the resident prompt section, the eleven `todo_*` tools, the ledger file format
114
+ (`_todo/` preferred, legacy `todo/` supported), and the `context/` retention files.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dsh-plugin contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,259 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ # dsh-todo-ledger
2
+
3
+ [![release](https://img.shields.io/github/v/release/haruri03/dsh-todo-ledger?sort=semver)](https://github.com/haruri03/dsh-todo-ledger/releases) [![npm](https://img.shields.io/npm/v/dsh-todo-ledger)](https://www.npmjs.com/package/dsh-todo-ledger) [![license](https://img.shields.io/github/license/haruri03/dsh-todo-ledger)](LICENSE)
4
+
5
+ [English](README.md) | [中文](README_zh.md)
6
+
7
+ Repository: https://github.com/haruri03/dsh-todo-ledger
8
+
9
+ A host-level DSH plugin that turns the todo ledger workflow into a resident prompt section,
10
+ a set of native tools, and context stored inside the repository's `_todo/` directory.
11
+
12
+ It addresses the failure mode where rules live in a skill or `AGENTS.md`, the model forgets to
13
+ read them, and the task list has to be rewritten every turn:
14
+
15
+ | Before | This plugin |
16
+ |---|---|
17
+ | Rules live in `AGENTS.md` / a skill and stop working when the model does not read them | A host-level `systemPrompt.section` is present every step of every session, with no load step to forget |
18
+ | The system `todo_write` list is overwritten each turn and progress is lost | Authoritative state lives in the repository's `_todo/` files and survives sessions and compaction |
19
+ | Context exists only in conversation history and disappears after compaction | `todo_checkpoint` / `todo_note` write conclusions and next steps into `_todo/context/`, and a snapshot is injected on every prompt assembly |
20
+ | The model has to assemble shell commands itself | 11 native tools with schema validation and readable errors |
21
+
22
+ The file format is fully compatible with an external todo CLI: the plugin and the original CLI can
23
+ both write the same repository and both can run `doctor` on it.
24
+
25
+ ## Install (manual)
26
+
27
+ Choose one:
28
+
29
+ **Human**: copy this directory to `$HOME/.dsh/profiles/<profile>/node_modules/dsh-todo-ledger`,
30
+ then append this row to the profile's `cordis.patch.yml`:
31
+
32
+ ```yaml
33
+ - insert:
34
+ - id: todo-ledger
35
+ name: './lib/index.js'
36
+ ```
37
+
38
+ **Agent**: run `plugin_manager install_bundle --target "<path-to-plugin>"`.
39
+
40
+ ### Install from Git
41
+
42
+ When the repository root is the package (it contains `package.json` and `dsh.bundle`), install it
43
+ directly from its Git URL:
44
+
45
+ ```powershell
46
+ plugin_manager install_bundle --target "git+https://github.com/haruri03/dsh-todo-ledger.git"
47
+ ```
48
+
49
+ The same operation is available to humans through the Web plugin page ("Add plugin") or the CLI:
50
+
51
+ ```powershell
52
+ dsh plugin --profile <profile> add "git+https://github.com/haruri03/dsh-todo-ledger.git"
53
+ ```
54
+
55
+ ### Install from npm
56
+
57
+ The package is published as `dsh-todo-ledger`, so the npm name alone installs it:
58
+
59
+ ```powershell
60
+ plugin_manager install_bundle --target "dsh-todo-ledger"
61
+ ```
62
+
63
+ ```powershell
64
+ dsh plugin --profile <profile> add dsh-todo-ledger
65
+ ```
66
+
67
+ Tarball URLs are accepted too. To update, remove and reinstall, or wait for an upstream release.
68
+
69
+ After installation, every new session carries a `[todo-ledger · cross-session tasks and context]`
70
+ prompt section, and the tool list gains:
71
+
72
+ `todo_list / todo_add / todo_show / todo_status / todo_complete / todo_archive / todo_note / todo_checkpoint / todo_snapshot / todo_doctor / todo_init`
73
+
74
+ No restart is required.
75
+
76
+ ## Layout
77
+
78
+ Inside the repository root (the directory that contains `_todo/`; a repository that already keeps `todo/` keeps working, the plugin accepts either name):
79
+
80
+ ```
81
+ _todo/
82
+ ├── todo.md queue: `- [status] slug`
83
+ ├── tasks.md index: `- [status] **slug** — title → [details](tasks/slug.md)`
84
+ ├── tasks/<slug>.md details: goal / subtasks / acceptance / progress / blockers / files
85
+ ├── archived/<slug>.md completed + ## Delivery record (includes the sign-off quote)
86
+ ├── AGENTS.md directory notes generated by todo_init
87
+ └── context/ added by this plugin
88
+ ├── now.md current goal / next step / key files (overwritten by todo_checkpoint)
89
+ └── log.md append-only log (automatic tool trace + todo_note)
90
+ ```
91
+
92
+ States are `todo` / `doing` / `blocked` / `review`; there is no `done`. `review` means work is
93
+ finished and waiting for the owner's sign-off. Closing a task requires both `evidence` and
94
+ `signoff` (the owner's own words); neither may be omitted. This is a hard rule of the todo ledger
95
+ workflow.
96
+
97
+ ## Tools
98
+
99
+ | Tool | Purpose |
100
+ |---|---|
101
+ | `todo_list` | List tasks and states (optionally filtered); call it before starting work |
102
+ | `todo_show` | Show one task's details |
103
+ | `todo_add` | Create a task (unique kebab-case slug) |
104
+ | `todo_status` | Change state and sync the task frontmatter, index, and queue |
105
+ | `todo_complete` | Close and archive a task; requires `evidence` + `signoff` |
106
+ | `todo_archive` | Abandon a task; additionally requires `reason` |
107
+ | `todo_note` | Append to `context/log.md`; with `slug`, insert at the end of that task's `## Progress` section (the placeholder is removed on first write); with `state`, advance the state machine in the same call |
108
+ | `todo_checkpoint` | Overwrite `context/now.md`: current goal / next step / key files |
109
+ | `todo_snapshot` | Read-only: return the snapshot that would be injected into the prompt (check whether the ledger is stale) |
110
+ | `todo_doctor` | Two-way consistency check; returns errors and warnings |
111
+ | `todo_init` | Create the `_todo/` skeleton (only when the user asks) |
112
+
113
+ Every tool accepts an optional `root`, so it can operate on repositories outside the workspace:
114
+
115
+ `todo_doctor { root: "<repo-root>" }`.
116
+
117
+ ## Sidebar panel
118
+
119
+ <img src="assets/sidebar-panel.png" width="420" alt="The sidebar ledger panel: in progress, to do, awaiting review with an Accept button, and blocked">
120
+
121
+ The plugin also serves a sidebar panel for the ledger of the current session working directory:
122
+ browsing is read-only, and the panel's only action is accepting a review task. It is opt-in: nothing is injected into the layout until a user opens the panel from the
123
+ right sidebar's guide capsule (named after the plugin); it then renders as a sidebar tab.
124
+
125
+ - Four sections — `doing`, `todo`, `review`, `blocked` — with a count each, plus a per-state colour
126
+ so the shape of the ledger reads at a glance.
127
+ - Ordering is fixed: `doing` first, then `todo`, `review`, `blocked`; an empty section still shows.
128
+ - The panel reads; it does not write task content. Polling runs only while the panel is visible
129
+ (every 5 s), so a closed or backgrounded tab costs nothing.
130
+ - When a session has no ledger above its working directory, or the ledger files disagree, the panel
131
+ says so instead of guessing. Run `todo_doctor` to repair the latter.
132
+
133
+ Each row under `review` carries an **accept** action. Accepting a review task from the panel archives
134
+ it through the same path as `todo_complete`, recording the panel click as both the evidence and the
135
+ sign-off (`accepted from the ledger panel at <ISO timestamp>`). Only `review` tasks can be accepted
136
+ this way; any other state is refused with an inline error rather than an alarm.
137
+
138
+ ### Floating panel
139
+
140
+ A book launcher below the composer opens a movable, resizable Todo Ledger floating panel. Drag
141
+ its header to move it and drag the bottom-right grip to resize it. It is an additional way to view
142
+ the ledger; the original right-sidebar panel remains available. The floating panel's labels follow
143
+ the host locale, and its body starts directly with the status counts because the window header
144
+ already names it. Every surface, border and state colour comes from the host theme tokens, so the
145
+ window follows the active theme — light, dark or a custom one — instead of carrying its own palette.
146
+
147
+ <img src="assets/floating-panel.png" width="360" alt="The floating ledger window: the same four sections, with the header used to drag it and the bottom-right grip used to resize it">
148
+
149
+ Each status group is collapsible: click a group header to fold it. Clicking a status count expands
150
+ that group and scrolls its header to the top of the list, which is how a long queue stays
151
+ navigable. Only the task list scrolls; the counts row and the footer stay put.
152
+
153
+ The panel is bound to the session it is shown in: switching to a session in another workspace
154
+ re-reads that workspace's ledger instead of keeping the previous one, and returning focus to the
155
+ window re-reads it again. The floating panel follows the session in front, so it re-targets when
156
+ the session changes instead of staying on the one that opened it.
157
+
158
+ The viewport-clamped box (position plus size) is saved in browser local storage and restored when
159
+ the panel opens again. Visibility and ledger content are not saved there: opening the panel reads
160
+ the current ledger rather than restoring a previous view.
161
+
162
+ The panel talks to two host routes, both read-only in intent and dispatched as `GET`:
163
+
164
+ | Route | Purpose |
165
+ |---|---|
166
+ | `/todo-ledger/projection?sessionId=<id>` | Ledger projection for that session's working directory |
167
+ | `/todo-ledger/complete?slug=<slug>&sessionId=<id>` | Accept one `review` task; the only side-effecting call |
168
+
169
+ A host restart is required after installing or updating the host-side code; the panel itself is plain
170
+ client JavaScript shipped by the package, so it needs no build step and appears after a page refresh.
171
+
172
+ ## Dependencies
173
+
174
+ Tasks can wait for other tasks. Pass `depends_on` (a list of slugs) to `todo_add`, and the task is
175
+ created `blocked` with `blocker_cause: dependency` until every predecessor is **formally completed**.
176
+ If the predecessors are already completed, the task is created as `todo` straight away.
177
+
178
+ ```mermaid
179
+ graph LR
180
+ spec["Design the API contract<br/>todo"] --> impl["Implement the endpoint<br/>blocked"]
181
+ spec --> form["Wire the form to it<br/>blocked"]
182
+ impl --> notes["Draft the release notes<br/>blocked"]
183
+ form --> notes
184
+ legacy["Migrate the legacy config loader<br/>blocked, manual"]
185
+ ```
186
+
187
+ Completing `spec` promotes `impl` and `form` to `todo` in the same call. `notes` stays blocked until
188
+ both of its predecessors are completed — one is not enough. `legacy` has no predecessor: its
189
+ `blocker_cause: manual` means nothing unblocks it automatically.
190
+
191
+ - **Completion only.** A predecessor in `review` does not count; neither does an archived task that
192
+ was dropped instead of completed. Only `todo_complete` — or the panel's accept — unblocks.
193
+ - **Validated at creation.** Unknown, already-dropped, self-referential and circular predecessors are
194
+ rejected, as is a `dependency` blocker with no predecessor.
195
+ - **Repairable.** `todo_doctor` reports dependency fields that disagree with the archives.
196
+
197
+ ## How context survives
198
+
199
+ 1. On each system-prompt assembly the plugin finds the nearest `_todo/` above the session working
200
+ directory and injects:
201
+ - **Ledger last written: N ago** (the newest mtime among `context/log.md`, `tasks.md`, and `now.md`);
202
+ - **Session staleness**: how many tool calls happened since the last `todo_*` write and how many
203
+ of them were writes; 3 or more writes adds a ⚠ telling the agent to update the ledger first;
204
+ - **Task totals** (four states), **review items** (with `(Nd)` days waiting) and **blocked** slugs;
205
+ - **Progress of doing tasks**: the last real line of the task's `## Progress` section (≤80 chars);
206
+ the whole line is omitted when there is no progress; a state unchanged for 2+ days is marked
207
+ `state Nd unchanged`; template placeholders are filtered out;
208
+ - The body of `context/now.md` and the last 6 log entries.
209
+ 2. At every turn end (`agent/turn-stopping`) the plugin counts write-class operations per **turn
210
+ boundary**. At 3 or more it appends a factual log entry (tool calls / writes / state changes)
211
+ without inventing semantics. If the turn only wrote notes and never advanced a state, the entry
212
+ says the state machine did not advance. It deliberately does **not** measure from the last
213
+ `todo_*` write, because a final `todo_note` would reset the counter and hide a turn that edited
214
+ many files but left a single note.
215
+ 3. `todo_checkpoint` records conclusions, not long excerpts; `todo_note` records small findings;
216
+ writes append a trace automatically.
217
+ 4. After compaction, a new session, or a DSH restart, the next prompt still carries the snapshot,
218
+ so work can continue.
219
+ 5. Without a `_todo/` directory the plugin only injects the rules and mentions `todo_init`; it never
220
+ creates the directory on its own.
221
+
222
+ > The unsolved half: the semantic summary is still written by the model. The plugin turns "the
223
+ > ledger is stale" into a visible fact and a ⚠ instead of inventing conclusions for the model.
224
+
225
+ ## Configuration
226
+
227
+ This row in `cordis.patch.yml` can be adjusted:
228
+
229
+ ```yaml
230
+ - id: todo-ledger
231
+ name: './lib/index.js'
232
+ config:
233
+ root: "<repo-root>" # optional: pin the repository root
234
+ sectionOrder: 180 # prompt section order, default 180
235
+ maxSnapshotChars: 4000 # snapshot size limit, default 4000
236
+ ```
237
+
238
+ Without `root`, the plugin searches upward from the session working directory for
239
+ `_todo/tasks.md`; if that fails it uses the `TODO_ROOT` environment variable.
240
+
241
+ ## Verification
242
+
243
+ ```powershell
244
+ node test/smoke.mjs
245
+ ```
246
+
247
+ Coverage: prompt section registration and snapshot rendering, the schemas of all 11 tools, the full
248
+ init → add → status → note → checkpoint → doctor → complete/archive flow, and rejection of a close
249
+ without `signoff`. When `TODO_CLI` points at an external `todo.js`, the test also verifies
250
+ `list`/`doctor` interoperability.
251
+
252
+ ## Uninstall
253
+
254
+ ```powershell
255
+ plugin_manager remove_bundle --target dsh-todo-ledger
256
+ ```
257
+
258
+ The plugin removes only its own registrations; the `_todo/` directory (including `context/`) is left
259
+ untouched.
package/README_zh.md ADDED
@@ -0,0 +1,224 @@
1
+ # dsh-todo-ledger
2
+
3
+ [![release](https://img.shields.io/github/v/release/haruri03/dsh-todo-ledger?sort=semver)](https://github.com/haruri03/dsh-todo-ledger/releases) [![npm](https://img.shields.io/npm/v/dsh-todo-ledger)](https://www.npmjs.com/package/dsh-todo-ledger) [![license](https://img.shields.io/github/license/haruri03/dsh-todo-ledger)](LICENSE)
4
+
5
+ [English](README.md) | [中文](README_zh.md)
6
+
7
+ 仓库:https://github.com/haruri03/dsh-todo-ledger
8
+
9
+ 把 **todo 账本工作流**做成 DSH 宿主级插件:
10
+ **常驻提示段** + **原生工具** + **待办目录里的上下文留存**。
11
+
12
+ 它解决的是「靠 skill / AGENTS.md 提醒,模型容易忘、要在每轮重写清单」的问题:
13
+
14
+ | 旧做法 | 这个插件 |
15
+ |---|---|
16
+ | 规则写在 AGENTS.md / skill 里,模型不读就失效 | 宿主级 `systemPrompt.section`,每个会话每步都在,不依赖模型记得加载 |
17
+ | 用系统 `todo_write` 每轮覆盖式重写,进度丢失 | 权威状态落在仓库 `_todo/` 文件里,跨会话、跨压缩都在 |
18
+ | 上下文只存在于对话历史,压缩后丢失 | `todo_checkpoint` / `todo_note` 把结论和下一步写进 `_todo/context/`,每次组装自动注入快照 |
19
+ | 模型要自己拼 shell 命令 | 11 个原生工具,schema 校验、错误可读 |
20
+
21
+ 文件格式与外部 todo CLI **完全一致**,同一个仓库插件和原版 CLI 都能写、都能 `doctor`。
22
+
23
+ ## 安装(手动)
24
+
25
+ 任选其一:
26
+
27
+ **人类**:把本目录复制到 `$HOME/.dsh/profiles/<profile>/node_modules/dsh-todo-ledger`,再在 profile 的 `cordis.patch.yml` 追加:
28
+
29
+ ```yaml
30
+ - insert:
31
+ - id: todo-ledger
32
+ name: './lib/index.js'
33
+ ```
34
+
35
+ **Agent**:让 agent 运行 `plugin_manager install_bundle --target "<path-to-plugin>"`。
36
+
37
+ ### 从 Git 自动安装
38
+
39
+ 仓库根就是包(含 `package.json` 与 `dsh.bundle`)时,可以直接用 Git 地址安装:
40
+
41
+ ```powershell
42
+ plugin_manager install_bundle --target "git+https://github.com/haruri03/dsh-todo-ledger.git"
43
+ ```
44
+
45
+ 等价的人类操作:Web 插件页「添加插件」粘贴同一地址,或命令行:
46
+
47
+ ```powershell
48
+ dsh plugin --profile <profile> add "git+https://github.com/haruri03/dsh-todo-ledger.git"
49
+ ```
50
+
51
+ ### 从 npm 安装
52
+
53
+ 包已发布为 `dsh-todo-ledger`,直接写包名即可:
54
+
55
+ ```powershell
56
+ plugin_manager install_bundle --target "dsh-todo-ledger"
57
+ ```
58
+
59
+ ```powershell
60
+ dsh plugin --profile <profile> add dsh-todo-ledger
61
+ ```
62
+
63
+ 也支持 tarball URL。更新时先卸载再安装,或等待上游发版。
64
+
65
+ 装好后新会话的系统提示里会出现「【todo-ledger · 跨会话任务与上下文】」段;工具列表里多出
66
+ `todo_list / todo_add / todo_show / todo_status / todo_complete / todo_archive / todo_note / todo_checkpoint / todo_snapshot / todo_doctor / todo_init`。
67
+ 无需重启。
68
+
69
+ ## 目录与文件格式
70
+
71
+ 在仓库根(含 `_todo/` 的目录)下;已经用 `todo/` 的旧仓库继续可用,两个名字只认其一:
72
+
73
+ ```
74
+ _todo/
75
+ ├── todo.md 队列:`- [status] slug`
76
+ ├── tasks.md 目录:`- [status] **slug** — 标题 → [详情](tasks/slug.md)`
77
+ ├── tasks/<slug>.md 详情:目标 / 子项 / 验收 / 进度 / 阻塞 / 相关文件
78
+ ├── archived/<slug>.md 结案 + ## 交付记录(含签收原话)
79
+ ├── AGENTS.md todo_init 生成的目录说明
80
+ └── context/ ← 本插件新增
81
+ ├── now.md 当前目标 / 下一步 / 关键文件(todo_checkpoint 覆盖写)
82
+ └── log.md 追加式流水(工具操作自动留痕 + todo_note)
83
+ ```
84
+
85
+ 状态只有 `todo` / `doing` / `blocked` / `review`;没有 `done`。`review` = 做完等负责人签收。
86
+ 结案必须带 `evidence` 与 `signoff`(负责人原话),缺一不可——这是 todo 账本工作流的硬规则。
87
+
88
+ ## 工具
89
+
90
+ | 工具 | 作用 |
91
+ |---|---|
92
+ | `todo_list` | 列出任务与状态(可按状态筛),开工先调 |
93
+ | `todo_show` | 看某任务详情 |
94
+ | `todo_add` | 新建任务(slug kebab-case,唯一) |
95
+ | `todo_status` | 改状态,同步详情 frontmatter / 索引 / 队列 |
96
+ | `todo_complete` | 结案归档,必须 `evidence` + `signoff` |
97
+ | `todo_archive` | 放弃归档,另需 `reason` |
98
+ | `todo_note` | 往 `context/log.md` 追加流水;带 `slug` 时**插入该任务「## 进度」节末尾**(首次写入清掉模板占位句);带 `state` 时**顺手推进状态机**(治“只 note 不改状态”) |
99
+ | `todo_checkpoint` | 覆盖写 `context/now.md`:当前目标 / 下一步 / 关键文件 |
100
+ | `todo_snapshot` | 只读:返回当前会注入提示词的那份快照(用来确认账本是不是又旧了) |
101
+ | `todo_doctor` | 双向一致性校验,返回 errors / warns |
102
+ | `todo_init` | 建 `_todo/` 骨架(只在用户要求时) |
103
+
104
+ 所有工具都接受可选 `root`,方便对工作区之外的仓库操作,例如:
105
+ `todo_doctor { root: "<repo-root>" }`。
106
+
107
+ ## 侧栏面板
108
+
109
+ <img src="assets/sidebar-panel.png" width="420" alt="侧栏里的账本面板:进行中、待办、待复核(带「通过」按钮)、阻塞四区">
110
+
111
+ 插件还会为当前会话工作目录的账本提供一个侧栏面板:浏览是只读的,面板上唯一的动作是「通过」一个待复核任务。
112
+ 它是按需打开的:在右侧栏的引导胶囊(以插件名命名)点开之前,布局里不会多出任何东西;点开后作为一个侧栏标签页渲染。
113
+
114
+ - 四个分区 `doing` / `todo` / `review` / `blocked`,各带计数,并按状态配色,扫一眼就能看出账本形状。
115
+ - 顺序固定:`doing` 在最前,然后 `todo`、`review`、`blocked`;空分区保留占位而不是消失。
116
+ - 面板只读,不写任务内容。轮询只在面板可见时进行(每 5 秒一次),关掉或切到后台就不耗资源。
117
+ - 会话工作目录之上没有账本、或账本文件互相矛盾时,面板直接说明,不去猜。后者跑一次 `todo_doctor` 修。
118
+
119
+ `review` 分区里每条都带一个**通过**动作。从面板通过一个待复核任务,走的是与 `todo_complete` 相同的归档路径,
120
+ 把这次点击同时记为验收证据和签收(`accepted from the ledger panel at <ISO 时间戳>`)。只有 `review` 态的任务
121
+ 可以这样通过,其他状态会被拒绝并在面板内联报错,而不是抛异常。
122
+
123
+ ### 浮动面板
124
+
125
+ 输入框下方的书本入口可打开可移动、可缩放的 Todo Ledger 浮动面板:拖动标题栏移动窗口,拖动右下角
126
+ 握把调整大小。这是查看账本的另一种方式,原有右侧栏面板仍可使用;浮动面板的文案跟随宿主语言,
127
+ 面板正文直接从状态计数开始,因为窗口标题栏已经写了名称。所有背景、边框与状态颜色都取自宿主
128
+ 主题 token,所以窗口会跟随当前主题(亮色、暗色或自定义主题),不自带一套配色。
129
+
130
+ <img src="assets/floating-panel.png" width="360" alt="浮动面板:同样四区,标题栏可拖动移动窗口,右下角握把可缩放">
131
+
132
+ 浏览器本地存储保存浮动面板经视口边界限制后的窗口框(位置与尺寸),并在再次打开时恢复。
133
+ 显示状态和账本内容不会保存在本地存储中:打开面板时读取当前账本,而不是恢复上次的内容。
134
+
135
+ 每个状态分组可以折叠:点击分组标题即可收起。点击状态计数会展开该分组,并把它的标题滚到列表
136
+ 顶部——长队列下这就是导航方式。只有任务列表滚动,计数行与页脚保持不动。
137
+
138
+ 面板绑定到它所显示的那个会话:切到别的会话、哪怕换了工作区,也会重新读取那个工作区的账本,
139
+ 而不是继续显示上一个;把焦点切回窗口时也会再读一次。悬浮窗跟着当前最前面的会话走,切会话
140
+ 时它会一起换目标,而不是停在被打开时那个会话上。
141
+
142
+ 面板对接两条宿主路由,都是 `GET` 派发:
143
+
144
+ | 路由 | 作用 |
145
+ |---|---|
146
+ | `/todo-ledger/projection?sessionId=<id>` | 返回该会话工作目录的账本投影 |
147
+ | `/todo-ledger/complete?slug=<slug>&sessionId=<id>` | 通过一个 `review` 任务;唯一有副作用的调用 |
148
+
149
+ 安装或更新宿主侧代码后需要重启宿主;面板本身是包里自带的纯客户端 JavaScript,没有构建步骤,刷新页面即可出现。
150
+
151
+ ## 依赖
152
+
153
+ 任务可以等别的任务。给 `todo_add` 传 `depends_on`(slug 列表),这个任务就会以 `blocked` +
154
+ `blocker_cause: dependency` 建出来,直到所有前驱都被**正式完成**;如果前驱当时已经完成,它直接就是 `todo`。
155
+
156
+ ```mermaid
157
+ graph LR
158
+ spec["设计 API 契约<br/>todo"] --> impl["实现接口<br/>blocked"]
159
+ spec --> form["接上表单<br/>blocked"]
160
+ impl --> notes["写发布说明<br/>blocked"]
161
+ form --> notes
162
+ legacy["迁移旧配置加载器<br/>blocked, manual"]
163
+ ```
164
+
165
+ 完成 `spec` 会在同一次调用里把 `impl` 和 `form` 提升为 `todo`;`notes` 要等两个前驱都完成——只完成一个不够。
166
+ `legacy` 没有前驱,它的 `blocker_cause: manual` 意味着任何签收都不会自动解除它。
167
+
168
+ - **只认正式完成**:前驱处于 `review` 不算,被丢弃(dropped)的归档也不算;只有 `todo_complete`——或面板上的「通过」——才解锁。
169
+ - **创建时就校验**:未知、已被丢弃、自引用、成环的前驱都会被拒绝;`dependency` 却没有前驱同样被拒。
170
+ - **可修**:`todo_doctor` 会报出与归档不一致的依赖字段。
171
+
172
+ ## 上下文是怎么留下来的
173
+
174
+ 1. 每次组装系统提示时,插件读会话工作目录,向上找 `_todo/`,注入:
175
+ - **账本最后写入:X 前**(`context/log.md` / `tasks.md` / `now.md` 的最大 mtime);
176
+ - **本会话记账陈旧度**:最近一次 `todo_*` 写入之后又发生多少次工具调用、其中多少是写入类;
177
+ 写入类 ≥3 时打 ⚠ 要求先补账;
178
+ - **任务总计**(四态计数)+ **待签收 review**(带 `(Nd)` 挂了几天)+ **阻塞 blocked** 的 slug;
179
+ - **doing 任务的进度**:取该任务「## 进度」节**最后一条**真实内容(≤80 字),
180
+ 没有进度就整行省略(不打印「(无进度)」这类空标记);状态 ≥2 天没变会标「状态 Nd 未变」;
181
+ 模板占位句一律过滤。
182
+ - `context/now.md` 正文与最近 6 条流水。
183
+ 2. 每轮结束(`agent/turn-stopping`)按 **turn 边界**统计本轮写入类操作:≥3 次就自动往
184
+ `context/log.md` 补一条事实流水(工具次数 / 写入类次数 / 状态推进次数),不编语义。
185
+ 本轮只有 note 没有状态推进时,会明确写「状态机没推进」。**刻意不以「最后一次 todo 写入」
186
+ 为起点**——否则收尾一条 `todo_note` 会把计数清零,掩盖「本轮猛改一堆文件、只留一句 note」。
187
+ 3. `todo_checkpoint` 写结论(不是大段原文);`todo_note` 记零碎发现;写操作自动追加流水。
188
+ 4. 会话被压缩、换新会话、重启 DSH 之后,下一个回合的提示里仍然带着这份快照 → 接着干。
189
+ 5. 没有 `_todo/` 时只注入规则并提示可以用 `todo_init`,不会擅自建目录。
190
+
191
+ > 还没解决的那一半:语义摘要仍要模型自己写。插件能做的是把「账本旧了」变成提示里的
192
+ > 事实和 ⚠,而不是替模型编造结论。
193
+
194
+ ## 配置
195
+
196
+ `cordis.patch.yml` 里这一行可以改:
197
+
198
+ ```yaml
199
+ - id: todo-ledger
200
+ name: './lib/index.js'
201
+ config:
202
+ root: "<repo-root>" # 可选:固定仓库根
203
+ sectionOrder: 180 # 提示段排序,默认 180
204
+ maxSnapshotChars: 4000 # 快照上限,默认 4000
205
+ ```
206
+
207
+ 不填 `root` 时按「会话工作目录向上找 `_todo/tasks.md`」;再没有就用 `TODO_ROOT` 环境变量。
208
+
209
+ ## 验证
210
+
211
+ ```powershell
212
+ node test/smoke.mjs
213
+ ```
214
+
215
+ 覆盖:提示段注册与快照渲染、11 个工具 schema、init→add→status→note→checkpoint→doctor→complete/archive
216
+ 全流程、缺 `signoff` 拒绝结案。设置 `TODO_CLI` 时额外验证与外部 `todo.js` 的 `list`/`doctor` 互通。
217
+
218
+ ## 卸载
219
+
220
+ ```powershell
221
+ plugin_manager remove_bundle --target dsh-todo-ledger
222
+ ```
223
+
224
+ 插件只删自己的注册;`_todo/` 目录(含 context/)不会被删。
Binary file
Binary file
@@ -0,0 +1,19 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="180" height="180" viewBox="0 0 180 180">
2
+ <defs>
3
+ <linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">
4
+ <stop offset="0" stop-color="#211f2b"/>
5
+ <stop offset="1" stop-color="#121118"/>
6
+ </linearGradient>
7
+ </defs>
8
+ <rect x="8" y="8" width="164" height="164" rx="36" fill="url(#bg)"/>
9
+ <rect x="8.75" y="8.75" width="162.5" height="162.5" rx="35.25" fill="none" stroke="#3a3747" stroke-width="1.5"/>
10
+ <g transform="translate(38,34) scale(4.3333)" fill="none" stroke="#f9fafb" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
11
+ <path d="M12 6c-2.4-1.5-5.3-1.8-9-1v13c3.7-.8 6.6-.5 9 1 2.4-1.5 5.3-1.8 9-1V5c-3.7-.8-6.6-.5-9 1Z"/>
12
+ <path d="M12 6v13"/>
13
+ </g>
14
+ <g fill="#a78bfa">
15
+ <circle cx="70" cy="141" r="3.4"/>
16
+ <circle cx="90" cy="141" r="3.4"/>
17
+ <circle cx="110" cy="141" r="3.4"/>
18
+ </g>
19
+ </svg>
Binary file