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 +114 -0
- package/LICENSE +21 -0
- package/README.md +259 -3
- package/README_zh.md +224 -0
- package/assets/floating-panel.png +0 -0
- package/assets/icon-180.png +0 -0
- package/assets/icon.svg +19 -0
- package/assets/sidebar-panel.png +0 -0
- package/client.js +736 -0
- package/cordis.patch.yml +12 -0
- package/lib/bridge.js +136 -0
- package/lib/index.js +719 -0
- package/lib/projection.js +51 -0
- package/lib/store.js +568 -0
- package/package.json +55 -6
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
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# dsh-todo-ledger
|
|
2
|
+
|
|
3
|
+
[](https://github.com/haruri03/dsh-todo-ledger/releases) [](https://www.npmjs.com/package/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
|
+
[](https://github.com/haruri03/dsh-todo-ledger/releases) [](https://www.npmjs.com/package/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
|
package/assets/icon.svg
ADDED
|
@@ -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
|