dsh-global-todo 0.9.1 → 0.11.0
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 +38 -0
- package/README.md +126 -21
- package/README.zh.md +137 -21
- package/docs/DESIGN.md +21 -0
- package/docs/FAQ.md +159 -0
- package/docs/QUICKSTART.md +100 -0
- package/docs/ROADMAP.md +12 -15
- package/docs/screenshots/README.md +39 -0
- package/docs/screenshots/panel-detail.png +0 -0
- package/docs/screenshots/panel-inbox.png +0 -0
- package/docs/screenshots/panel-reminders.png +0 -0
- package/docs/screenshots/panel-review.png +0 -0
- package/docs/screenshots/panel-select.png +0 -0
- package/docs/screenshots/panel.png +0 -0
- package/docs/screenshots/tour.gif +0 -0
- package/lib/client.js +180 -3
- package/lib/index.js +1 -1
- package/lib/markdown.js +135 -0
- package/lib/report.js +88 -0
- package/lib/routes.js +30 -1
- package/lib/service.js +14 -1
- package/package.json +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,41 @@
|
|
|
1
|
+
## [0.11.0] — 2026-10-20
|
|
2
|
+
|
|
3
|
+
Documentation and demo, treated as part of the product.
|
|
4
|
+
|
|
5
|
+
- **A standalone landing page** at `docs/index.html` (GitHub Pages): hero with the install line and
|
|
6
|
+
a 24-second captioned tour, the three claims with evidence, a five-step strip through the real
|
|
7
|
+
screenshots, an honest comparison against `todo_write` and kanban boards, a 3×3 grid of every
|
|
8
|
+
conditional state, and a footer with the data path. One file, inline CSS, no CDN, bilingual
|
|
9
|
+
toggle, 15 images all verified to decode.
|
|
10
|
+
- **`docs/screenshots/demo.mp4`** — a 24s captioned tour built from the same real renders by
|
|
11
|
+
`ffmpeg` (not a screen recording, and the page says so), plus the existing GIF for places that
|
|
12
|
+
cannot autoplay video.
|
|
13
|
+
- **`docs/QUICKSTART.md`** (five minutes, click by click) and **`docs/FAQ.md`** (14 real questions
|
|
14
|
+
answered against the code), and `docs/screenshots/README.md` indexing what each baseline shows
|
|
15
|
+
and what a static image cannot prove.
|
|
16
|
+
- **READMEs explain 0.7–0.10 at last**: steps, evidence, read-back, review, Markdown, weekly report.
|
|
17
|
+
English and Chinese kept as mirror images; stale claims (`21 routes`, `100+ tests`, `@0.4.0`)
|
|
18
|
+
corrected to 24 / 257 / 0.10.0.
|
|
19
|
+
- **Fixed the two mismatches the docs pass found**: the capture prompt said 200 characters where
|
|
20
|
+
`LIMITS.evidence` is 300, and `package.json` did not publish the new docs (so their links would
|
|
21
|
+
have 404'd on npm).
|
|
22
|
+
|
|
23
|
+
## [0.10.0] — 2026-10-20
|
|
24
|
+
|
|
25
|
+
The two remaining high-value items, plus the layout bug written down.
|
|
26
|
+
|
|
27
|
+
- **Markdown in and out.** `GET /export?format=md` writes a task list (title, priority, due,
|
|
28
|
+
tags, evidence, description, steps, attachments as indented metadata); `POST /import` with
|
|
29
|
+
`{ markdown }` reads it back through `create` — new items, never an overwrite, because Markdown
|
|
30
|
+
has no ids. The parser is tolerant: unknown lines ignored, an unreadable date dropped, a blank
|
|
31
|
+
task line is not a todo.
|
|
32
|
+
- **Weekly agent report.** `GET /report?days=7` derives, from completion records alone: what
|
|
33
|
+
finished (newest first, by whom), how many conversations were involved, which files were touched
|
|
34
|
+
and how often, and how many still wait for review. Shown from `⋯ → 本周报告`; nothing is stored.
|
|
35
|
+
- **The scroll bug is documented** in `DESIGN.md` with the measurements (2236px column inside a
|
|
36
|
+
680px slot, `scrollTop 0 → 0`), so the next person who touches the layout knows which two
|
|
37
|
+
declarations hold the contract.
|
|
38
|
+
|
|
1
39
|
## [0.9.1] — 2026-10-20
|
|
2
40
|
|
|
3
41
|
The list could not scroll. One missing declaration, and the panel never owned its own height.
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Three things it does that a session-local plan cannot:
|
|
|
18
18
|
dsh plugin add dsh-global-todo
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
[中文说明](README.zh.md) · [Every state has a baseline image](#screenshots) · [Design notes](docs/DESIGN.md)
|
|
21
|
+
[中文说明](README.zh.md) · [5-minute quickstart](docs/QUICKSTART.md) · [FAQ](docs/FAQ.md) · [Every state has a baseline image](#screenshots) · [Design notes](docs/DESIGN.md)
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
@@ -39,6 +39,93 @@ one record:
|
|
|
39
39
|
| Hand-off | — | **one click: reuse the bound conversation or open a session** |
|
|
40
40
|
| Storage | session event log | one JSON file you can `cat`, edit, diff and back up |
|
|
41
41
|
|
|
42
|
+
## What 0.9 and 0.10 added (and the two just before)
|
|
43
|
+
|
|
44
|
+
Six surfaces these READMEs had never explained. Session read-back and evidence came in 0.9;
|
|
45
|
+
Markdown and the weekly report in 0.10; steps in 0.8 and the review mark in 0.7, which until now
|
|
46
|
+
only existed in the changelog. Each changes what a record can carry, or what you can do with it
|
|
47
|
+
after the fact.
|
|
48
|
+
|
|
49
|
+
### Steps: a plan inside the todo
|
|
50
|
+
|
|
51
|
+
A todo can carry up to 20 steps of 200 characters (`LIMITS` in `lib/model.js`). A step is
|
|
52
|
+
`{ text, done }` — a line inside one unit of work, not a subtask with its own id and status.
|
|
53
|
+
|
|
54
|
+
- **Add them** in "More fields" → Steps, one per line.
|
|
55
|
+
- **Tick them** in the detail panel; the row shows `steps 2/5`.
|
|
56
|
+
- **Hand off** and the dispatch prompt numbers them, prefixing finished ones with `[已完成]`.
|
|
57
|
+
- **Export** and Markdown writes them as nested `- [ ]` lines; import reads them back.
|
|
58
|
+
|
|
59
|
+
### Evidence: the sentence it came from
|
|
60
|
+
|
|
61
|
+
`evidence` is the sentence a captured todo came from, quoted verbatim, up to 300 characters.
|
|
62
|
+
`global_todo_capture` asks the model for it, `global_todo_add` accepts it, and the detail panel
|
|
63
|
+
shows it as a blockquote under **In the author's words**. A todo you typed yourself has none.
|
|
64
|
+
|
|
65
|
+
The field exists for one reason: a capture without its source reads as an opinion later. It is
|
|
66
|
+
also in the Markdown export (`原话:`).
|
|
67
|
+
|
|
68
|
+
### Session read-back
|
|
69
|
+
|
|
70
|
+
A hand-off starts work in another conversation, so the detail panel answers "what did it say"
|
|
71
|
+
without switching away. `GET /api/global-todo/session?id=` returns `alive`, `dir` and a `tail`
|
|
72
|
+
of the last assistant message; the panel shows **Session read-back** with running / dormant, the
|
|
73
|
+
last sentence, and a button that opens that conversation.
|
|
74
|
+
|
|
75
|
+
The tail is bounded and in memory: 200 conversations, 400 characters each, filled from every
|
|
76
|
+
`assistant/message`. Nothing is written to disk, so a Host restart forgets it. A missing tail is
|
|
77
|
+
normal — this process has not seen that conversation speak.
|
|
78
|
+
|
|
79
|
+
### Review: "done" is a claim
|
|
80
|
+
|
|
81
|
+
When an agent finishes (`global_todo_done`, or the watcher on a clean turn), the record becomes
|
|
82
|
+
done **and** carries `review: { pending: true }`. The row gets a **Needs review** badge and the
|
|
83
|
+
header a **Review** chip with the count.
|
|
84
|
+
|
|
85
|
+
| Answer | Effect |
|
|
86
|
+
|---|---|
|
|
87
|
+
| **Confirm done** | stays done, the mark is dropped, the activity trail records who confirmed |
|
|
88
|
+
| **Send back** | back to `open`; `doneAt` and the completion record are cleared; a `reopened` activity entry is added |
|
|
89
|
+
|
|
90
|
+
Both answers are recorded as the person's action. Sending back deletes nothing: title,
|
|
91
|
+
description, steps, attachments and progress notes stay.
|
|
92
|
+
|
|
93
|
+
### Markdown in and out
|
|
94
|
+
|
|
95
|
+
The JSON export is the round-trip format. Markdown is the one you read, diff and edit by hand:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
- [ ] 标题
|
|
99
|
+
优先级: 高 · 截止: 2026-10-21T18:00 · 标签: 发布, 文档
|
|
100
|
+
原话: …
|
|
101
|
+
描述: 第一行
|
|
102
|
+
- [x] 一步
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
| Direction | Where | Behaviour |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| Out | **More actions → Export Markdown**, or `GET /export?format=md` | Grouped 未完成 / 已完成 / 已归档; metadata indented under each task |
|
|
108
|
+
| In | **More actions → Import** (a `.md` file), or `POST /import { markdown }` | Creates new todos through `create`; Markdown has no ids, so it never overwrites an existing record |
|
|
109
|
+
|
|
110
|
+
Tolerant by design: unknown lines are ignored, an unparseable date is dropped, and a file with no
|
|
111
|
+
`- [ ]` line is refused with a reason. Field labels are Chinese (`优先级 / 截止 / 标签 / 原话 /
|
|
112
|
+
描述 / 附件 / #`), and import reads the same set.
|
|
113
|
+
|
|
114
|
+
### Weekly report
|
|
115
|
+
|
|
116
|
+
**More actions → This week** (`GET /report?days=7`) answers "what moved, and did any of it land
|
|
117
|
+
in code". Everything is derived from completion records; nothing is stored.
|
|
118
|
+
|
|
119
|
+
| Field | Meaning |
|
|
120
|
+
|---|---|
|
|
121
|
+
| `finished` | completions in the window, newest first, with the actor and the summary |
|
|
122
|
+
| `sessions` | distinct conversations those completions came from |
|
|
123
|
+
| `created` | todos added in the window |
|
|
124
|
+
| `pendingReview` | done items still waiting for an answer |
|
|
125
|
+
| `files` | file artifacts touched, most frequent first — 12 listed, `fileCount` total |
|
|
126
|
+
|
|
127
|
+
`days` above 90 is clamped to 90; a missing or non-positive value falls back to 7.
|
|
128
|
+
|
|
42
129
|
## Screenshots
|
|
43
130
|
|
|
44
131
|

|
|
@@ -64,6 +151,9 @@ half is rendered to static HTML with no Host and no dependencies, then photograp
|
|
|
64
151
|
into `docs/screenshots/`. Playwright is not a dependency — the tool borrows the copy a DSH
|
|
65
152
|
profile already installed, or whatever `DSH_PLAYWRIGHT` points at.
|
|
66
153
|
|
|
154
|
+
What each file shows, and when it is regenerated, is indexed in
|
|
155
|
+
[docs/screenshots/README.md](docs/screenshots/README.md).
|
|
156
|
+
|
|
67
157
|
## Requirements
|
|
68
158
|
|
|
69
159
|
- DeepSeek Harness `0.2.x` (developed and verified against `0.2.1-rc.2`; `engines.dsh` is
|
|
@@ -90,7 +180,7 @@ The plugin is a Loader row, not a hot-loaded script: **restart the host** (`dsh
|
|
|
90
180
|
after installing, then refresh the page. A "待办 / Todos" entry appears in the sidebar.
|
|
91
181
|
|
|
92
182
|
The npm package is the source of truth. A community catalog can lag behind it or point at an
|
|
93
|
-
older release; pin the version you want (`dsh plugin --profile web add dsh-global-todo@0.
|
|
183
|
+
older release; pin the version you want (`dsh plugin --profile web add dsh-global-todo@0.10.0`)
|
|
94
184
|
when it matters.
|
|
95
185
|
|
|
96
186
|
To roll back:
|
|
@@ -118,8 +208,8 @@ Your list is not touched by install or uninstall: it lives outside the plugin, a
|
|
|
118
208
|
documents and addresses (with 打开 / 复制路径 on each); read the activity trail.
|
|
119
209
|
- **Undo a delete** — deleting keeps the record for eight seconds and offers 撤销, which
|
|
120
210
|
restores it verbatim: same id, same creation time, same attachments.
|
|
121
|
-
- **Keyboard** — `/` focuses search, `n` focuses the new-todo field
|
|
122
|
-
open detail. Row actions appear on hover or keyboard focus.
|
|
211
|
+
- **Keyboard** — `/` focuses search, `n` focuses the new-todo field while the add form is
|
|
212
|
+
open, `Esc` collapses the open detail. Row actions appear on hover or keyboard focus.
|
|
123
213
|
- **Reachable from the LAN and from a tunnel** — the routes defer to the Host's connection fence
|
|
124
214
|
(which honours `--trusted-host`); the plugin's own loopback check is only the fallback for a
|
|
125
215
|
Host without that service. `/health` reports `fence` so you can see which one is in force.
|
|
@@ -253,12 +343,12 @@ produces noise, and a noisy list is worse than an empty one:
|
|
|
253
343
|
The boundary: it **records, it never starts work**. The list belongs to the human, and
|
|
254
344
|
starting a task stays a human decision (see the non-goals in [ROADMAP](docs/ROADMAP.md)).
|
|
255
345
|
|
|
256
|
-
|
|
257
346
|
Capture is not allowed to become noise. Before an item is written, the same normalized title
|
|
258
347
|
(full-width, case, spacing and punctuation folded away), a close paraphrase within the last 72
|
|
259
348
|
hours (Dice similarity over character bigrams, 0.8), and the same errand finished in the last 7
|
|
260
349
|
days are all refused with a reason on the record; archived and cancelled rows do not block a
|
|
261
350
|
new one. The rules live in `lib/capture.js` and are tested on their own.
|
|
351
|
+
|
|
262
352
|
### HTTP API
|
|
263
353
|
|
|
264
354
|
The panel talks to the host over these routes. They are fenced by the host connection
|
|
@@ -269,9 +359,10 @@ fence when that service is present, and by a strict loopback check otherwise.
|
|
|
269
359
|
| GET | `/api/global-todo/list` | `status`, `query`, `tag`, `sort`, `limit` — the reply carries `matched` and `truncated` when the page was cut |
|
|
270
360
|
| GET | `/api/global-todo/dirs` | `path?` — list subdirectories for the panel's built-in folder picker (the shell's own picker is preferred when mounted) |
|
|
271
361
|
| GET | `/api/global-todo/get` | `id` |
|
|
272
|
-
| GET | `/api/global-todo/export` | — (the store's own JSON document
|
|
362
|
+
| GET | `/api/global-todo/export` | — (the store's own JSON document; `?format=md` gives a Markdown task list) |
|
|
273
363
|
| POST | `/api/global-todo/import` | `{ doc, mode?: replace\|merge, dryRun? }` — `replace` is an exact round trip, `merge` updates by id and appends (what the panel sends); `dryRun` returns `wouldCreate` / `wouldUpdate` and writes nothing |
|
|
274
364
|
| POST | `/api/global-todo/reminders/ack` | `{ ids }` — stop listing these passed deadlines as due |
|
|
365
|
+
| POST | `/api/global-todo/note` | `{ id, text }` — append a progress note |
|
|
275
366
|
| POST | `/api/global-todo/capture` | `{ sessionId? }` — ask the current conversation to collect its follow-ups |
|
|
276
367
|
| POST | `/api/global-todo/bulk` | `{ ids, status?, addTags?, removeTags? }` — one change across a selection; a stale id lands in `unmatched` instead of failing the batch |
|
|
277
368
|
| POST | `/api/global-todo/ingest` | `{ items: [{ title, source: { kind }, confidence }], dryRun? }` with `Authorization: Bearer <settings.ingestToken>` — external items; below `ingestConfirmBelow` they wait in the inbox |
|
|
@@ -282,6 +373,8 @@ fence when that service is present, and by a strict loopback check otherwise.
|
|
|
282
373
|
| POST | `/api/global-todo/remove` | `{ id }` |
|
|
283
374
|
| POST | `/api/global-todo/restore` | `{ todo }` — put a removed record back verbatim (undo) |
|
|
284
375
|
| POST | `/api/global-todo/review` | `{ id, decision: confirm\|reject }` — answer an agent's completion |
|
|
376
|
+
| GET | `/api/global-todo/report?days=7` | what the agents finished in the window, and the files it touched |
|
|
377
|
+
| GET | `/api/global-todo/session?id=` | what a bound conversation last said (`tail`, `alive`, `dir`) |
|
|
285
378
|
| POST | `/api/global-todo/link` | `{ id, add?: [...], remove?: [value \| index] }` |
|
|
286
379
|
| POST | `/api/global-todo/dispatch` | `{ id, mode?: auto\|bound\|new\|current, sessionId?, dir? }` |
|
|
287
380
|
| POST | `/api/global-todo/assign` | `{ ids, items?, target?, dir? }` — hand several todos over in one call; an id that matches nothing comes back instead of being sent elsewhere |
|
|
@@ -347,7 +440,7 @@ and [docs/ROADMAP.md](docs/ROADMAP.md) for what could come next.
|
|
|
347
440
|
npm run check # parse every file, assert the shipping shape, and — when a DSH
|
|
348
441
|
# profile is present — validate every tool schema against the
|
|
349
442
|
# Host's own validator
|
|
350
|
-
npm test #
|
|
443
|
+
npm test # 257 unit, contract and bundle tests, zero dependencies
|
|
351
444
|
npm run verify # both
|
|
352
445
|
npm run check:matrix # the running dsh against engines.dsh, then the manifest,
|
|
353
446
|
# bundle and tool-schema contracts (no preview writes)
|
|
@@ -364,6 +457,7 @@ page refresh; host-half edits need a host restart.
|
|
|
364
457
|
```sh
|
|
365
458
|
npm run preview # render the panel to preview/panel.html (+ detail and selection variants)
|
|
366
459
|
npm run screenshots # re-photograph those previews into docs/screenshots/, 1280×720
|
|
460
|
+
npm run tour # rebuild docs/screenshots/tour.gif from those PNGs (needs ffmpeg)
|
|
367
461
|
```
|
|
368
462
|
|
|
369
463
|
The PNGs under `docs/screenshots/` ship with the package and are embedded in both
|
|
@@ -371,20 +465,30 @@ READMEs, so re-run `npm run screenshots` whenever the panel UI changes.
|
|
|
371
465
|
|
|
372
466
|
```text
|
|
373
467
|
lib/
|
|
374
|
-
index.js
|
|
375
|
-
store.js
|
|
376
|
-
model.js
|
|
377
|
-
links.js
|
|
378
|
-
service.js
|
|
379
|
-
routes.js
|
|
380
|
-
tools.js
|
|
381
|
-
dispatch.js
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
468
|
+
index.js host entry: store + service + dispatcher + the optional surfaces
|
|
469
|
+
store.js one JSON file: atomic writes, serialized updates, tolerant loads
|
|
470
|
+
model.js the todo entity: validation, patches, status, attachments, steps, review, notes
|
|
471
|
+
links.js attachment rules (pure: no filesystem access)
|
|
472
|
+
service.js the single write path, filters, sorting and the dispatch prompt
|
|
473
|
+
routes.js the HTTP surface for the panel
|
|
474
|
+
tools.js the ten agent tools
|
|
475
|
+
dispatch.js handing a todo to an agent session (auto / bound / new / current)
|
|
476
|
+
completion.js the clean-turn watcher behind automatic completion
|
|
477
|
+
capture.js the capture duplicate gate (title, paraphrase, recent done)
|
|
478
|
+
ingest.js the external door and its inbox rules
|
|
479
|
+
markdown.js Markdown export and tolerant import
|
|
480
|
+
report.js the weekly aggregate over completion records
|
|
481
|
+
reminders.js the due rule behind the reminder strip
|
|
482
|
+
settings.js host-side switches and the automatic-collect policy
|
|
483
|
+
metrics.js in-memory counters reported by /health
|
|
484
|
+
diagnostics.js the bounded client error log
|
|
485
|
+
errors.js typed failures with stable machine codes
|
|
486
|
+
client.js the browser half (panel + sidebar entry)
|
|
487
|
+
test/ unit, service, tool, route, dispatch, bundle and manifest tests
|
|
488
|
+
tools/ preview.mjs — render the panel to static HTML without a Host
|
|
489
|
+
screenshot.mjs — photograph those previews (borrows the profile's Playwright)
|
|
490
|
+
tour.mjs — assemble the README tour GIF from those PNGs
|
|
491
|
+
docs/ DESIGN.md (data model and rejected alternatives), ROADMAP.md
|
|
388
492
|
```
|
|
389
493
|
|
|
390
494
|
Contributions are welcome — read [CONTRIBUTING.md](CONTRIBUTING.md) first.
|
|
@@ -395,6 +499,7 @@ Questions, bug reports and ideas go to [Discussions](https://github.com/LUgABeEE
|
|
|
395
499
|
When reporting a bug, include the DSH version, the plugin version from the panel footer, your OS and
|
|
396
500
|
the steps that reproduce it; a screenshot of the notice is worth more than a paragraph. Security
|
|
397
501
|
issues go through [SECURITY.md](SECURITY.md) instead, not the discussion board.
|
|
502
|
+
|
|
398
503
|
## Security
|
|
399
504
|
|
|
400
505
|
The HTTP surface is local-only, the list is a local file, and no credential is ever stored.
|
package/README.zh.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
dsh plugin add dsh-global-todo
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
[English](README.md) · [每个条件状态都有基线图](#截图) · [设计说明](docs/DESIGN.md)
|
|
17
|
+
[English](README.md) · [5 分钟上手](docs/QUICKSTART.md) · [常见问题](docs/FAQ.md) · [每个条件状态都有基线图](#截图) · [设计说明](docs/DESIGN.md)
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
@@ -33,6 +33,85 @@ DSH 自带的 `todo_write` 属于**某一个 agent 会话**:整表替换、三
|
|
|
33
33
|
| 交给 Agent | 无 | **一键:复用已绑定会话,或新开一个** |
|
|
34
34
|
| 存储 | 会话事件日志 | 一个 JSON 文件,能 `cat`、能手改、能 diff、能备份 |
|
|
35
35
|
|
|
36
|
+
## 0.9 / 0.10 补了什么(以及再往前两版)
|
|
37
|
+
|
|
38
|
+
六个这两份 README 一直没讲的能力:会话回读与原话是 0.9 的,Markdown 与本周报告是 0.10 的,
|
|
39
|
+
步骤是 0.8 的,待确认标记是 0.7 的——后两个此前只写在 CHANGELOG 里。每一个都改变了记录能装什么,
|
|
40
|
+
或者改变了事后能拿它做什么。
|
|
41
|
+
|
|
42
|
+
### 步骤:待办里的一份计划
|
|
43
|
+
|
|
44
|
+
一条待办最多 20 个步骤、每步 200 字(`lib/model.js` 的 `LIMITS`)。步骤是 `{ text, done }`——
|
|
45
|
+
一条工作里的一行,不是有自己 id 和状态的子任务。
|
|
46
|
+
|
|
47
|
+
- **加**:新增表单的「更多字段」→ 步骤,一行一步。
|
|
48
|
+
- **勾**:详情里每步一个勾选框;行上显示「步骤 2/5」。
|
|
49
|
+
- **交出去**:派发提示词会把步骤编号,已完成的加 `[已完成]` 前缀。
|
|
50
|
+
- **导出**:Markdown 里写成缩进的 `- [ ]`,导入时读回来。
|
|
51
|
+
|
|
52
|
+
### 原话:这条是从哪句话来的
|
|
53
|
+
|
|
54
|
+
`evidence` 是抓取时那条待办**来自的原话**,逐字引用,最多 300 字。`global_todo_capture` 会向模型要它,
|
|
55
|
+
`global_todo_add` 也收,详情里以引用块显示在「原话」下面;你自己敲的条目没有这一项。
|
|
56
|
+
|
|
57
|
+
它只为一件事存在:没有出处的一次抓取,过几天看起来就像一句观点。Markdown 导出里也有这一行(`原话:`)。
|
|
58
|
+
|
|
59
|
+
### 会话回读
|
|
60
|
+
|
|
61
|
+
派发是在**另一个对话**里开工,所以详情要能回答「它说了什么」,不用切过去。
|
|
62
|
+
`GET /api/global-todo/session?id=` 返回 `alive`、`dir` 和最后一条 assistant 消息的 `tail`;
|
|
63
|
+
详情里就是「会话回读」:在跑 / 已休眠、最后一句,以及一个打开该对话的按钮。
|
|
64
|
+
|
|
65
|
+
tail 有上限、只在内存里:200 个会话、每个 400 字,来自每条 `assistant/message`。不落盘,宿主一重启就忘。
|
|
66
|
+
查不到 tail 是正常情况——这个进程没见那个对话说过话。
|
|
67
|
+
|
|
68
|
+
### 待确认:Agent 的「做完了」只是声明
|
|
69
|
+
|
|
70
|
+
Agent 收尾时(`global_todo_done`,或干净一轮后的自动收尾),记录会变成已完成,**同时**带上
|
|
71
|
+
`review: { pending: true }`。行上有「待确认」徽标,顶部多一个带计数的「待确认」筛选。
|
|
72
|
+
|
|
73
|
+
| 你的回答 | 结果 |
|
|
74
|
+
|---|---|
|
|
75
|
+
| **确认完成** | 保持已完成,标记清除,动态里记下是谁确认的 |
|
|
76
|
+
| **退回清单** | 回到 `open`,`doneAt` 与完成记录清空,动态里加一条 `reopened` |
|
|
77
|
+
|
|
78
|
+
两个回答都按**人**的动作记录。退回不删除任何东西:标题、描述、步骤、附件、进展记录都还在。
|
|
79
|
+
|
|
80
|
+
### Markdown 进与出
|
|
81
|
+
|
|
82
|
+
JSON 导出是往返格式;Markdown 是拿来读、diff、手改的那份:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
- [ ] 标题
|
|
86
|
+
优先级: 高 · 截止: 2026-10-21T18:00 · 标签: 发布, 文档
|
|
87
|
+
原话: …
|
|
88
|
+
描述: 第一行
|
|
89
|
+
- [x] 一步
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
| 方向 | 入口 | 行为 |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| 出 | **更多操作 → 导出 Markdown**,或 `GET /export?format=md` | 按「未完成 / 已完成 / 已归档」分组,元数据缩进在每条下面 |
|
|
95
|
+
| 入 | **更多操作 → 导入**(选 `.md`),或 `POST /import { markdown }` | 走正常 `create` 新建;Markdown 没有 id,所以**永远不会覆盖**已有记录 |
|
|
96
|
+
|
|
97
|
+
解析是容错的:不认识的行直接忽略,日期解析失败就丢掉那一项,整份文件里没有一行 `- [ ]` 会明确报错。
|
|
98
|
+
字段标注固定是中文(`优先级 / 截止 / 标签 / 原话 / 描述 / 附件 / #`),导入按同一套读。
|
|
99
|
+
|
|
100
|
+
### 本周报告
|
|
101
|
+
|
|
102
|
+
**更多操作 → 本周报告**(`GET /report?days=7`)回答「这一周动了什么、有没有落到代码上」。
|
|
103
|
+
全部从完成记录推出来,不存任何东西。
|
|
104
|
+
|
|
105
|
+
| 字段 | 含义 |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `finished` | 窗口内完成的条目,最新在前,带完成者和说明 |
|
|
108
|
+
| `sessions` | 这些完成来自多少个不同的对话 |
|
|
109
|
+
| `created` | 窗口内新增的条数 |
|
|
110
|
+
| `pendingReview` | 已完成但还没人回答的条数 |
|
|
111
|
+
| `files` | 触及的文件,按次数排序——列 12 个,`fileCount` 是总数 |
|
|
112
|
+
|
|
113
|
+
`days` 超过 90 会被压到 90;缺省或非正数按 7 算。
|
|
114
|
+
|
|
36
115
|
## 截图
|
|
37
116
|
|
|
38
117
|

|
|
@@ -56,6 +135,8 @@ DSH 自带的 `todo_write` 属于**某一个 agent 会话**:整表替换、三
|
|
|
56
135
|
HTML(不依赖宿主、零依赖),再以 1280×720 拍进 `docs/screenshots/`。Playwright 不是依赖——工具
|
|
57
136
|
借的是 DSH profile 里已经装好的那份,或 `DSH_PLAYWRIGHT` 指向的那份。
|
|
58
137
|
|
|
138
|
+
每张图显示什么状态、什么时候重新生成,见 [docs/screenshots/README.md](docs/screenshots/README.md)。
|
|
139
|
+
|
|
59
140
|
## 环境要求
|
|
60
141
|
|
|
61
142
|
- DeepSeek Harness `0.2.x`(按 `0.2.1-rc.2` 开发与验证;`engines.dsh` 是 `>=0.2.0-rc.1 <0.3.0`,
|
|
@@ -80,7 +161,7 @@ dsh plugin --profile web add /绝对路径/dsh-global-todo
|
|
|
80
161
|
再刷新页面。侧栏会出现「待办」入口。
|
|
81
162
|
|
|
82
163
|
npm 上的包才是事实来源。社区目录可能落后于 npm、或指向某个旧 release;需要确定版本时
|
|
83
|
-
直接钉版本(`dsh plugin --profile web add dsh-global-todo@0.
|
|
164
|
+
直接钉版本(`dsh plugin --profile web add dsh-global-todo@0.10.0`)。
|
|
84
165
|
|
|
85
166
|
回滚:
|
|
86
167
|
|
|
@@ -105,7 +186,7 @@ dsh plugin --profile web remove dsh-global-todo
|
|
|
105
186
|
- **详情**:就地改标题/描述/优先级/截止;挂上或摘掉文档与地址(每条都带「打开 / 复制路径」);
|
|
106
187
|
查看动态(谁在什么时候做了什么)。
|
|
107
188
|
- **删除可撤销**:删掉的记录保留 8 秒,点「撤销」原样恢复——同一个 id、同一个加入时间、同样的附件。
|
|
108
|
-
- **键盘**:`/`
|
|
189
|
+
- **键盘**:`/` 聚焦搜索;新增输入框展开后,`n` 聚焦它;`Esc` 收起详情。行内操作在悬停或键盘聚焦时出现。
|
|
109
190
|
- **访问地址**:面板可以正常从宿主的**本机**、**受信任的局域网地址**(`--trusted-host` 里那些,如 `192.168.1.10:3080`)以及隧道访问——路由会交给宿主的连接围栏判断;只有宿主的围栏**不存在**时才退回「只接受本机请求」的保守检查。`/health` 里的 `fence` 会告诉你当前实际是哪一种。
|
|
110
191
|
- **自动获取(可关,默认关)**:面板上的「自动获取」开关。打开后——你在某个对话里**正常收完一轮**、那个对话**安静满 30 分钟**、且**你人就在那个对话里**(不是派发目标/子 Agent/后台任务),插件才会自动问它一次「有没有要跟进的事」。中断/失败的轮次不问。**它问过之后,只有你在那个对话里再说一句话才会重新问**——因为那条提问本身就是对话里的一条消息,会重置安静计时、并让它自己的回答收尾成一轮,曾经正是这一点让同一个对话整夜追着自己反复问;冷却只是次要的阻尼。开关是**宿主状态**(面板关着也生效,`/health` 可见),关掉就完全靠你和 Agent 手动记。另外每个对话分组旁边有一个**「豁免」**按钮:点一下就把**该对话所在的工作区**整个排除在自动获取之外(再点一下取消)。这是给由机器驱动的对话准备的——比如微信机器人所在的聊天区,它们的会话重启后会换新 id,所以豁免**记在目录上而不是某一条对话上**,才不会悄悄失效。
|
|
111
192
|
- **主动记**:插件会往 system prompt 里注入一段引导,列出该主动记的具体情形(跨会话的跟进、「先做 X 再 Y」、一轮收尾时发现还有一步),并明确写上「问用户要不要记是错的,直接记」。
|
|
@@ -148,8 +229,29 @@ dsh plugin --profile web remove dsh-global-todo
|
|
|
148
229
|
| `global_todo_reopen` | 把**被误标完成**的一条标回未完成(只做 `done` / `cancelled` → `open`);本来就未完成的会被拒绝,动作按 agent 记进活动轨迹 |
|
|
149
230
|
| `global_todo_remove` | 永久删除(做完的请标记,不要删) |
|
|
150
231
|
|
|
151
|
-
|
|
152
|
-
|
|
232
|
+
### 实际联通检查
|
|
233
|
+
|
|
234
|
+
测试用的是替身;`npm run check:live` 检查的是**真正接上线的**宿主:面板实际会调的路由、它实际读的清单,
|
|
235
|
+
以及一条「删掉再撤销」之后仍然完整的记录。它会临时建一条记录,往返后逐字段比对(id、加入时间、附件、
|
|
236
|
+
标签、级别、截止、描述),确认绑定记录带 `sessionAlive` / `sessionDir`,最后即使失败也会删掉这条临时记录。
|
|
237
|
+
它需要一个在跑的宿主,所以不在 `verify` 里。
|
|
238
|
+
|
|
239
|
+
### 主动抓取
|
|
240
|
+
|
|
241
|
+
插件会往 system prompt 里注入一段引导(用 `guidance: false` 关掉)。它把两侧都写清楚:只写「记得记事」的
|
|
242
|
+
提示词只会制造噪音,而吵闹的清单比空清单更糟。
|
|
243
|
+
|
|
244
|
+
- **主动记**:用户提到需要跨会话跟进的事(等对方回复、下周要交、待确认的决定、答应别人的事)、
|
|
245
|
+
一轮结束时还有一步不该在本会话继续、或用户说「记一下 / 别忘了 / 回头办」;
|
|
246
|
+
- **不要记**:你这一步就能做完的、本会话内的计划、纯闲聊;
|
|
247
|
+
- 记完用**一句话**说明记了什么,别复述整条描述;
|
|
248
|
+
- 用户说**「抓一下待办」**,就扫最近对话,用 `global_todo_capture` 一次登记,再回一句汇总。
|
|
249
|
+
|
|
250
|
+
边界是:它**只负责记,从不擅自开工**。清单属于人,开不开工是人决定的(见 [ROADMAP](docs/ROADMAP.md) 里的非目标)。
|
|
251
|
+
|
|
252
|
+
抓取不能变成噪音。写进去之前,同一个规范化标题(全半角、大小写、空格、标点都折叠掉)、
|
|
253
|
+
最近 72 小时内意思很接近的转述(按字符二元组的 Dice 相似度,0.8),以及 7 天内刚做完的同一件事,
|
|
254
|
+
都会被拒绝,并在记录上写出原因;已归档和已取消的条目不挡新条目。规则在 `lib/capture.js`,单独测试。
|
|
153
255
|
|
|
154
256
|
### HTTP 接口
|
|
155
257
|
|
|
@@ -161,7 +263,7 @@ dsh plugin --profile web remove dsh-global-todo
|
|
|
161
263
|
| GET | `/api/global-todo/list` | `status`、`query`、`tag`、`sort`、`limit`——被截断时响应带 `matched` 与 `truncated` |
|
|
162
264
|
| GET | `/api/global-todo/dirs` | `path?`——列子目录,供面板内置的目录浏览器使用(宿主自己的选择器在时会优先) |
|
|
163
265
|
| GET | `/api/global-todo/get` | `id` |
|
|
164
|
-
| GET | `/api/global-todo/export` | ——(存储用的那份 JSON
|
|
266
|
+
| GET | `/api/global-todo/export` | ——(存储用的那份 JSON 文档;`?format=md` 给 Markdown 任务列表) |
|
|
165
267
|
| POST | `/api/global-todo/import` | `{ doc, mode?: replace\|merge, dryRun? }`——`replace` 是无损往返,`merge` 同 id 覆盖、新 id 追加(面板用的是这个);`dryRun` 只返回 `wouldCreate` / `wouldUpdate`,不落盘 |
|
|
166
268
|
| POST | `/api/global-todo/reminders/ack` | `{ ids }`——这些已到期的提醒不再列出来 |
|
|
167
269
|
| POST | `/api/global-todo/note` | `{ id, text }`(追加进展记录) |
|
|
@@ -175,6 +277,8 @@ dsh plugin --profile web remove dsh-global-todo
|
|
|
175
277
|
| POST | `/api/global-todo/remove` | `{ id }` |
|
|
176
278
|
| POST | `/api/global-todo/restore` | `{ todo }` —— 原样还原被删除的记录(撤销) |
|
|
177
279
|
| POST | `/api/global-todo/review` | `{ id, decision: confirm\|reject }` —— 回答 Agent 的完成声明 |
|
|
280
|
+
| GET | `/api/global-todo/report?days=7` | 这段时间里 Agent 完成了什么、触及了哪些文件 |
|
|
281
|
+
| GET | `/api/global-todo/session?id=` | 绑定的会话最后说了什么(`tail` / `alive` / `dir`) |
|
|
178
282
|
| POST | `/api/global-todo/link` | `{ id, add?: [...], remove?: [值 或 下标] }` |
|
|
179
283
|
| POST | `/api/global-todo/dispatch` | `{ id, mode?: auto\|bound\|new\|current, sessionId?, dir? }` |
|
|
180
284
|
| POST | `/api/global-todo/assign` | `{ ids, items?, target?, dir? }`——一次把多条交给 Agent;配不上的 id 原样报回,不擅自送到别处 |
|
|
@@ -235,7 +339,7 @@ epoch 与 ISO,派发提示词也带上它。因为「这事什么时候落到
|
|
|
235
339
|
```sh
|
|
236
340
|
npm run check # 解析全部文件、校验发布形态;本机有 DSH profile 时,还会用宿主
|
|
237
341
|
# 自己的校验器逐条验证工具 schema
|
|
238
|
-
npm test #
|
|
342
|
+
npm test # 257 单元/契约/bundle 测试,零依赖
|
|
239
343
|
npm run verify # 两者都跑
|
|
240
344
|
npm run check:matrix # 当前 dsh 与 engines.dsh 的实际匹配,再跑 manifest/bundle/
|
|
241
345
|
# 工具 schema 三类契约(不写 preview)
|
|
@@ -251,6 +355,7 @@ CI 里也没有构建产物。改 `lib/client.js` 刷新页面即生效;改宿
|
|
|
251
355
|
```sh
|
|
252
356
|
npm run preview # 把面板渲染成 preview/panel.html(另附详情态与选择态)
|
|
253
357
|
npm run screenshots # 把这些预览重新拍成 docs/screenshots/,1280×720
|
|
358
|
+
npm run tour # 用这些 PNG 重新拼 docs/screenshots/tour.gif(需要 ffmpeg)
|
|
254
359
|
```
|
|
255
360
|
|
|
256
361
|
`docs/screenshots/` 下那几张 PNG 会随包发布、并嵌在两份 README 里,所以面板 UI 一改就要重跑
|
|
@@ -258,20 +363,30 @@ npm run screenshots # 把这些预览重新拍成 docs/screenshots/,1280×72
|
|
|
258
363
|
|
|
259
364
|
```text
|
|
260
365
|
lib/
|
|
261
|
-
index.js
|
|
262
|
-
store.js
|
|
263
|
-
model.js
|
|
264
|
-
links.js
|
|
265
|
-
service.js
|
|
266
|
-
routes.js
|
|
267
|
-
tools.js
|
|
268
|
-
dispatch.js
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
366
|
+
index.js 宿主入口:store + service + dispatcher + 可选挂载面
|
|
367
|
+
store.js 一个 JSON 文件:原子写、串行更新、容错读取
|
|
368
|
+
model.js 待办实体:校验、补丁、状态、附件、步骤、待确认、进展
|
|
369
|
+
links.js 附件规则(纯函数,不碰文件系统)
|
|
370
|
+
service.js 唯一写入路径、筛选、排序与派发提示词
|
|
371
|
+
routes.js 面板用的 HTTP 接口
|
|
372
|
+
tools.js 十个 Agent 工具
|
|
373
|
+
dispatch.js 把待办交给 agent 会话(auto / bound / new / current)
|
|
374
|
+
completion.js 干净一轮之后的自动收尾观察者
|
|
375
|
+
capture.js 抓取去重闸门(同名、近义转述、刚完成)
|
|
376
|
+
ingest.js 外部写入入口与收件箱规则
|
|
377
|
+
markdown.js Markdown 导出与容错导入
|
|
378
|
+
report.js 从完成记录推出来的周报
|
|
379
|
+
reminders.js 到点提醒的判定规则
|
|
380
|
+
settings.js 宿主侧开关与自动获取策略
|
|
381
|
+
metrics.js /health 里的进程内计数
|
|
382
|
+
diagnostics.js 有上限的面板错误日志
|
|
383
|
+
errors.js 带机器码的类型化失败
|
|
384
|
+
client.js 浏览器半区(面板 + 侧栏入口)
|
|
385
|
+
test/ 单元、service、工具、路由、派发、bundle、manifest 测试
|
|
386
|
+
tools/ preview.mjs —— 不依赖宿主,把面板渲染成静态 HTML
|
|
387
|
+
screenshot.mjs —— 把预览拍成 PNG(借 profile 里的 Playwright)
|
|
388
|
+
tour.mjs —— 用这些 PNG 拼 README 里的 tour.gif
|
|
389
|
+
docs/ DESIGN.md(数据模型与取舍)、ROADMAP.md
|
|
275
390
|
```
|
|
276
391
|
|
|
277
392
|
欢迎贡献,先读 [CONTRIBUTING.md](CONTRIBUTING.md)。
|
|
@@ -281,6 +396,7 @@ docs/ DESIGN.md(数据模型与取舍)、ROADMAP.md
|
|
|
281
396
|
问题、bug 和想法都发到 [Discussions](https://github.com/LUgABeEEE/dsh-global-todo/discussions)。
|
|
282
397
|
报 bug 时带上 DSH 版本、面板页脚里的插件版本、系统,以及能复现的步骤;提示语截图比一段描述更有用。
|
|
283
398
|
安全问题请走 [SECURITY.md](SECURITY.md),不要发在讨论区。
|
|
399
|
+
|
|
284
400
|
## 安全
|
|
285
401
|
|
|
286
402
|
HTTP 接口只服务本机,清单是本地文件,任何凭据都不会被存储。
|
package/docs/DESIGN.md
CHANGED
|
@@ -57,6 +57,27 @@ $DSH_HOME/global-todo/todos.json ← { version: 1, todos: [ … ] }
|
|
|
57
57
|
version, and a future migration step would run before the first write, keeping the old
|
|
58
58
|
file as a backup.
|
|
59
59
|
|
|
60
|
+
## The panel owns its own scroll
|
|
61
|
+
|
|
62
|
+
A list longer than the slot must scroll **inside** the panel: the header and toolbar stay put, and
|
|
63
|
+
the rows move. That sounds obvious and was broken for two releases, because a flex column does not
|
|
64
|
+
do it by default.
|
|
65
|
+
|
|
66
|
+
- **The bug.** `.gt-inner` is a flex item (`flex: 1`) of `.gt-root`. A flex item's default
|
|
67
|
+
`min-height` is `auto`, so the column refused to shrink below its content: with a long list it
|
|
68
|
+
measured **2236px inside a 680px slot**, `.gt-groups` therefore never had a scroll range, and the
|
|
69
|
+
host's own overflow clipped everything below the fold. Measured proof: a wheel over the list left
|
|
70
|
+
`scrollTop` at **0**.
|
|
71
|
+
- **The fix is two declarations**: `.gt-inner { min-height: 0 }` (let the column shrink) and
|
|
72
|
+
`.gt-root { overflow: hidden }` (the panel clips, so the list is the only scroll owner). After:
|
|
73
|
+
`.gt-groups` is 480px of viewport over a 2036px list, and a wheel moves it 0 → 800.
|
|
74
|
+
- **Why it shipped.** Every screenshot in this repository is a server-rendered preview: no layout
|
|
75
|
+
engine, no wheel, no scrollbar. A static image cannot show that a list is stuck at the top. So the
|
|
76
|
+
render check now asserts the three declarations that make the contract
|
|
77
|
+
(`overflow: hidden` on the panel, `min-height: 0` on the column, `overflow: auto` on the list),
|
|
78
|
+
and anything about scrolling, focus or hover has to be measured with a real browser instead of
|
|
79
|
+
looked at.
|
|
80
|
+
|
|
60
81
|
## Reading the conversation back
|
|
61
82
|
|
|
62
83
|
Handing work over used to be one-way: the panel knew a conversation was bound, and nothing about
|