dsh-task-ledger 0.0.123 → 0.0.124

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.
@@ -5,6 +5,7 @@ export declare const TREND_WEEKS = 8;
5
5
  export interface OwnerCounts {
6
6
  readonly added: number;
7
7
  readonly done: number;
8
+ readonly cancelled: number;
8
9
  readonly open: number;
9
10
  }
10
11
  /** 一个周桶;`from` / `to` 是**本机时区**的日期(含边界)。 */
@@ -15,6 +16,8 @@ export interface TrendBucket {
15
16
  readonly added: number;
16
17
  /** 该周结案(全部人合计)。 */
17
18
  readonly done: number;
19
+ /** 该周取消(全部人合计)。 */
20
+ readonly cancelled: number;
18
21
  /** 该周结束时仍未结案(全部人合计,含窗口前遗留)。 */
19
22
  readonly open: number;
20
23
  /** uuid → 按人明细(「只看我的」用;没要 / 该人该周没数据则没有这个 key)。 */
@@ -42,6 +42,7 @@ function parseOwners(raw, where) {
42
42
  out[uuid] = {
43
43
  added: num(cell, "added", where),
44
44
  done: num(cell, "done", where),
45
+ cancelled: num(cell, "cancelled", where),
45
46
  open: num(cell, "open", where),
46
47
  };
47
48
  }
@@ -80,6 +81,7 @@ export function parseTrend(raw, where) {
80
81
  to: day(item, "to", where),
81
82
  added: num(item, "added", where),
82
83
  done: num(item, "done", where),
84
+ cancelled: num(item, "cancelled", where),
83
85
  open: num(item, "open", where),
84
86
  ...(owners === undefined ? {} : { owners }),
85
87
  };
@@ -1,8 +1,10 @@
1
1
  import type { BoardHomePayload, LedgerWorkspace, StatsPayload, TrendView } from "../types.js";
2
- /** 本周 / 上周完成 = 趋势最后两个桶的「结案」(后者为上周)。 */
2
+ /** 本周 / 上周结案总数 = 趋势最后两个桶的 done + cancelled(后者为上周)。 */
3
3
  export interface WeekDone {
4
4
  readonly weekDone: number | null;
5
5
  readonly lastWeekDone: number | null;
6
+ readonly weekCancelled: number | null;
7
+ readonly lastWeekCancelled: number | null;
6
8
  readonly weekFrom: string;
7
9
  readonly weekTo: string;
8
10
  readonly lastWeekFrom: string;
@@ -20,8 +20,10 @@ export function weekDoneFromTrend(trend, fallback, fallbackLast) {
20
20
  const thisWeek = buckets[buckets.length - 1];
21
21
  const lastWeek = buckets[buckets.length - 2];
22
22
  return {
23
- weekDone: thisWeek === undefined ? null : thisWeek.done,
24
- lastWeekDone: lastWeek === undefined ? null : lastWeek.done,
23
+ weekDone: thisWeek === undefined ? null : thisWeek.done + thisWeek.cancelled,
24
+ lastWeekDone: lastWeek === undefined ? null : lastWeek.done + lastWeek.cancelled,
25
+ weekCancelled: thisWeek === undefined ? null : thisWeek.cancelled,
26
+ lastWeekCancelled: lastWeek === undefined ? null : lastWeek.cancelled,
25
27
  weekFrom: thisWeek?.from ?? fallback.from,
26
28
  weekTo: thisWeek?.to ?? fallback.to,
27
29
  lastWeekFrom: lastWeek?.from ?? fallbackLast.from,
@@ -108,9 +110,11 @@ export async function getBoardStats(workspaces, now = new Date()) {
108
110
  : max === null
109
111
  ? item.oldestOpenDays
110
112
  : Math.max(max, item.oldestOpenDays), null),
111
- // 这两格由 getBoardHome 从趋势桶回填(趋势全挂时保持 null ⇒ 界面留 —)
113
+ // 这四个数由 getBoardHome 从趋势桶回填(趋势全挂时保持 null ⇒ 界面留 —)
112
114
  weekDone: null,
113
115
  lastWeekDone: null,
116
+ weekCancelled: null,
117
+ lastWeekCancelled: null,
114
118
  weekFrom: thisWeek.from,
115
119
  weekTo: thisWeek.to,
116
120
  lastWeekFrom: lastWeek.from,
@@ -27,6 +27,7 @@ export function mergeTrend(rows) {
27
27
  to: bucket.to,
28
28
  added: 0,
29
29
  done: 0,
30
+ cancelled: 0,
30
31
  open: 0,
31
32
  owners: {},
32
33
  };
@@ -35,12 +36,14 @@ export function mergeTrend(rows) {
35
36
  // 已有对象就原地累加(同一份数据只在本函数里生成,不会被外部共享)
36
37
  current.added += bucket.added;
37
38
  current.done += bucket.done;
39
+ current.cancelled += bucket.cancelled;
38
40
  current.open += bucket.open;
39
41
  for (const [uuid, cell] of Object.entries(bucket.owners ?? {})) {
40
- const owner = current.owners[uuid] ?? { added: 0, done: 0, open: 0 };
42
+ const owner = current.owners[uuid] ?? { added: 0, done: 0, cancelled: 0, open: 0 };
41
43
  current.owners[uuid] = {
42
44
  added: owner.added + cell.added,
43
45
  done: owner.done + cell.done,
46
+ cancelled: owner.cancelled + cell.cancelled,
44
47
  open: owner.open + cell.open,
45
48
  };
46
49
  }
@@ -102,6 +102,9 @@ export interface BoardStatsView {
102
102
  /** 本周 / 上周完成数(= 趋势最后两个桶);趋势全读不到时为 null(界面留 —)。 */
103
103
  readonly weekDone: number | null;
104
104
  readonly lastWeekDone: number | null;
105
+ /** 其中取消的数量(卡片小字「结案 X · 取消 Y」);0 时不显示小字。 */
106
+ readonly weekCancelled: number | null;
107
+ readonly lastWeekCancelled: number | null;
105
108
  /** 两周的区间(界面悬停用,含边界)。 */
106
109
  readonly weekFrom: string;
107
110
  readonly weekTo: string;
@@ -118,6 +121,7 @@ export interface StatsPayload {
118
121
  export interface TrendOwnerCounts {
119
122
  readonly added: number;
120
123
  readonly done: number;
124
+ readonly cancelled: number;
121
125
  readonly open: number;
122
126
  }
123
127
  /** 趋势图的一根周桶(数字全由 skill `stats --trend --by-owner` 给,插件只跨工作区相加)。 */
@@ -126,6 +130,7 @@ export interface TrendBucketView {
126
130
  readonly to: string;
127
131
  readonly added: number;
128
132
  readonly done: number;
133
+ readonly cancelled: number;
129
134
  readonly open: number;
130
135
  /** uuid → 按人明细;「只看我的」直接取自己那条,勾选零请求。 */
131
136
  readonly owners: Readonly<Record<string, TrendOwnerCounts>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-task-ledger",
3
- "version": "0.0.123",
3
+ "version": "0.0.124",
4
4
  "description": "Task ledger board for dsh (DeepSeek Harness): read-only board over task-ledger skill workspaces. The task-ledger skill is bundled — install the plugin, get the skill globally.",
5
5
  "keywords": [
6
6
  "deepseek",
@@ -57,6 +57,6 @@
57
57
  }
58
58
  },
59
59
  "dependencies": {
60
- "dsh-plugin-core": "^0.8.3"
60
+ "dsh-plugin-core": "^0.10.0"
61
61
  }
62
62
  }
package/skill/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  - **谁在做、做到哪**:状态只在台账 JSON —— `ledger/pool.json`(公共池)+ 每人一份 `ledger/owners/<hash>.json` 分片,索引 `ledger/owners.json`。
10
10
  - **过程正文**:全在 `ledger/worklog/<年月>/<月日>-<时分>-<说明>-<码>.md`(六节),agent 直接编辑前五节,末节「执行记录」只由脚本写。
11
- - **已结案**:一行一条在 `ledger/history/<年月>.md`(9 列),只由脚本写。
11
+ - **已结案**:一行一条在 `ledger/history/<年月>.md`(12 列),只由脚本写。
12
12
 
13
13
  状态改动与正文重写分开、全部经脚本改 —— 不另建副本、不手改状态表和历史。覆盖动作:建任务、认领、释放、结案、查在办、查历史、标签归并、体检。
14
14
 
@@ -20,7 +20,7 @@
20
20
  | `ledger/owners.json` | 索引:身份 uuid → 分片文件(`name` 只做显示 / 模糊筛) |
21
21
  | `ledger/owners/<hash>.json` | 每人一份分片:自己认领的任务 |
22
22
  | `ledger/worklog/<年月>/*.md` | 任务正文(六节) |
23
- | `ledger/history/<年月>.md` | 已结案(一行一条,9 列) |
23
+ | `ledger/history/<年月>.md` | 已结案(一行一条,12 列) |
24
24
 
25
25
  ## 为什么这么设计
26
26
 
package/skill/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: task-ledger
3
- description: 本地任务台账,跨会话记录在办任务的归属、进度与起止。当用户要登记一件新的事(新建任务 / 建个坑 / 这活我领了)、记录已有任务的进展(接着做 / 记一条进展 / 这轮先记下)、查看任务状态或历史(现在该做什么 / 这活谁在做 / 上周做过什么)、给任务结案或退回(做完了 / 验收通过 / 不做了 / 退回待认领)、整理标签或检查台账一致性时加载;只是改代码、讨论方案时不要用。
3
+ description: 本地任务台账,跨会话记录在办任务的归属、进度与起止。当用户要登记一件新的事(新建任务 / 建个坑 / 这活我领了)、记录已有任务的进展(接着做 / 记一条进展 / 这轮先记下)、查看任务状态或历史(现在该做什么 / 这活谁在做 / 上周做过什么)、给任务结案 / 取消作废 / 退回(做完了 / 验收通过 / 取消 / 作废 / 退回待认领)、整理标签或检查台账一致性时加载;只是改代码、讨论方案时不要用。
4
4
  version: 1.3.40
5
5
  allowed-tools: Read,Edit,Bash,Grep
6
6
  ---
@@ -93,18 +93,38 @@ allowed-tools: Read,Edit,Bash,Grep
93
93
 
94
94
  举例:一轮干完 → `log --id <任务号> --note "改了认领即 doing(internal/actions/claim.go:56);下一步同步文档"`。
95
95
 
96
- ### close — 结案
96
+ ### close — 结案 / 取消
97
+
98
+ **结案与取消是两个动作,共用一个命令,只靠 `--cancel` 区分。**
99
+
100
+ - 用户说「关闭 / 结案 / 结束 / close」⇒ **正常结案,不许加 `--cancel`**;
101
+ - 只有用户明确说「**取消 / 作废**」(如「这个任务取消」「作废掉」)⇒ 才加 `--cancel`;
102
+ - 「不做了 / 先不做了 / 以后再做 / 先放一放 / 暂停」**不是取消** —— 那是暂停:状态不动,最多记一条 `log`(见生命周期第 5 条);
103
+ - 「需求不成立 / 已经被别的任务做掉」是**理由**,不是命令:它只能进 `--summary`,不能当取消的触发词;
104
+ - 拿不准(「这个先这样吧」)⇒ 先问「是要**取消(作废)**还是**正常结案(做完了)**?」,问清再跑。
97
105
 
98
106
  | 参数 | 含义 |
99
107
  |---|---|
100
108
  | `--id <任务号>` | 结哪条(必填) |
101
- | `--summary "…"` | 结案摘要(必填;放弃写「放弃:原因」) |
109
+ | `--summary "…"` | 结案摘要(正常结案必填);**取消时可选**,写了就落历史 `Summary` 列并带进执行记录 |
110
+ | `--cancel` | 取消:结果列 `cancelled`、状态行 `cancelled`、执行记录追加 `cancel` 一行。**不写原因也能取消** |
102
111
  | `--finished` | 给漏记的旧任务补用时,补录实际结案时间(`YYYY-MM-DD[ HH:MM[:SS]]`) |
103
112
  | `--tags` | 覆盖标签终值(写进历史行;文档头部只写标签)。**结案时最该给**:任务做完了,最清楚涉及什么;不传则沿用原标签。分类不可改,历史行用它建任务时的值 |
104
113
 
105
- 干什么:结案并封卷过程文档、移出自己名下。**封卷后只读**(见生命周期第 8 条)。
114
+ 干什么:结案(或取消)并封卷过程文档、删掉来源那行。**封卷后只读**(见生命周期第 8 条)。
115
+
116
+ 可用范围:
117
+
118
+ - **公共池任务**(没人认领)→ 只能 `--cancel`(想正常结案先 `claim`);
119
+ - **我名下的任务** → 结案、取消都行;
120
+ - **别人名下的任务** → 拒绝。
106
121
 
107
- 举例:用户明确说「把这个任务结束掉」→ `close --id <任务号> --summary "发布流程走通,验证 25 项全过"`。
122
+ 结果列只有两个值:`done`(正常结案)/ `cancelled`(取消)。历史行的 `owner` / `owner_name` 是**执行这次结案/取消的人**,原创建者仍在 `creator` / `creator_name`。
123
+
124
+ 举例:
125
+
126
+ - 正常结案:`close --id <任务号> --summary "发布流程走通,验证 25 项全过"`
127
+ - 取消(用户明确说「取消 / 作废」):「这个任务作废掉」→ `close --id <任务号> --cancel --summary "需求已被「xxx」做掉"`
108
128
 
109
129
  ### list — 查在办
110
130
 
@@ -162,9 +182,9 @@ allowed-tools: Read,Edit,Bash,Grep
162
182
  | `--mine` / `--owner <uuid>[,<uuid>]` | 只看自己 / 某几个人(`--owner` 可给多个 uuid,与 `--mine` 互斥) |
163
183
  | `--by-owner` | 每个桶额外带按人明细(默认不返回,只给总数) |
164
184
 
165
- 干什么:一次遍历返回**整段桶序列**(不按桶多次调用),每桶三个数 —— `added`(该桶内新建)、`done`(该桶内结案)、`open`(该桶**结束时**仍未结案)。
185
+ 干什么:一次遍历返回**整段桶序列**(不按桶多次调用),每桶四个数 —— `added`(该桶内新建)、`done`(正常结案)、`cancelled`(取消作废)、`open`(该桶**结束时**仍未结案)。
166
186
 
167
- 口径:`added` 按 `created`、`done` 按 `finished`;`open` 由「当前在办 + 今天往前倒推」得出,天然含窗口之前遗留的基线。按人明细里 `added` 按 `creator`、`done` / `open` 按 `owner`(待认领不算任何人)。
187
+ 口径:`added` 按 `created`;`done` / `cancelled` 都按 `finished`,靠历史行 `Result` 列区分(`done` 只算正常结案,取消不算完成);`open` 由「当前在办 + 今天往前倒推」得出,天然含窗口之前遗留的基线 —— 结案和取消**都**会让任务离开在办,倒推时两者都要减。按人明细里 `added` 按 `creator`、`done` / `open` 按 `owner`(待认领不算任何人)。
168
188
 
169
189
  按人的 `open` 只算**你名下**的任务,倒推时同时减去「你在那天之后新建的」(按 owner 计,与展示用的 creator 无关)—— 否则窗口之后才建、早已结案的任务会被当成那天就在办,越靠前的桶虚高得越离谱。负责人转交过的任务按**今天**的负责人归账。
170
190
 
@@ -175,8 +195,8 @@ allowed-tools: Read,Edit,Bash,Grep
175
195
  "granularity": "week",
176
196
  "coverage": { "from": "2026-09-01", "to": "2026-10-29" },
177
197
  "buckets": [
178
- { "from": "2026-09-01", "to": "2026-09-06", "added": 3, "done": 5, "open": 12,
179
- "owners": { "<uuid>": { "name": "某人", "added": 1, "done": 2, "open": 4 } } }
198
+ { "from": "2026-09-01", "to": "2026-09-06", "added": 3, "done": 5, "cancelled": 1, "open": 12,
199
+ "owners": { "<uuid>": { "name": "某人", "added": 1, "done": 2, "cancelled": 0, "open": 4 } } }
180
200
  ],
181
201
  "warnings": []
182
202
  }
@@ -228,7 +248,7 @@ allowed-tools: Read,Edit,Bash,Grep
228
248
 
229
249
  干什么:按结案时间倒序排列,每条一行,只列结案时间、负责人、标题,其他都不在表格里;要摘要 / 分类 / 标签 / 完整时间加 `--json`。不给时间参数 = 最近 3 个自然月;最多 13 个月,超了直接报错。
230
250
 
231
- 要「某个时间窗内结案了多少」**别拿 `history` 数条数**(只覆盖 13 个月,且一给 `--limit`,`count` 就只是返回条数)—— 用 `stats --trend <粒度>` 的桶,`done` 就是该桶结案数。
251
+ 要「某个时间窗内结案了多少」**别拿 `history` 数条数**(只覆盖 13 个月,且一给 `--limit`,`count` 就只是返回条数)—— 用 `stats --trend <粒度>` 的桶,`done + cancelled` 才是该桶结案总数(`done` 只算正常结案)。
232
252
 
233
253
  举例:「上周做过什么」→ `history --since <上周一日期>`;「今年都结掉哪些」→ `history --months 12`(超过 13 个月要分段查)。
234
254
 
@@ -308,11 +328,12 @@ allowed-tools: Read,Edit,Bash,Grep
308
328
  2. **建并认领 —— 仅限明确说法**:用户明确说「新建一个任务**并开始做 / 并执行**」这类带着「现在就开始」的话 → `new --title "…" --self`。直接归自己名下、「进行中」。**除这种明确说法,其他一律按第 1 条只建** —— 别替用户决定他要开始做;拿不定,问一句。
309
329
  3. **找已有的**:用户说「我们来做 X」→ 先 `list --mine` 找自己名下的,在做的直接接着做;没有 → `list --pool` 里找,找到先问用户:「X 还没认领,认领它吗?」→ 用户点头再 `claim`;哪儿都没有 → **不擅自建**:问「要为 X 建个任务吗?」,同意才按第 1/2 条建,不同意就只干活、不登记。
310
330
  4. **认领**:`claim --id <任务号>` —— 认到自己名下,状态即「进行中」。
311
- 5. **推进**:改 worklog 前五节 → 按「过程文档」节的收工三步记 `log`。卡住也 `log`(写清卡在哪,状态不动);「先放一放」同理 —— 是暂停,不是释放。
331
+ 5. **推进**:改 worklog 前五节 → 按「过程文档」节的收工三步记 `log`。卡住也 `log`(写清卡在哪,状态不动);「先放一放 / 现在不做了,一会儿做」同理 —— 是暂停,不是释放,更不是取消(取消只有用户明确说「取消 / 作废」才算)。
312
332
  6. **交付待验收**:任务留「进行中」,「待办」写「待用户验收」,「下一步」写清验收看什么;照收工三步记一条 `log --note "已交付待验收:…"`。
313
333
  7. **释放**:仅当用户明确说「退回去 / 释放掉」→ `set --id <任务号> --release`。任务回公共池,别人可认领。
314
- 8. **结案**:仅当用户明确说「把这个任务结束掉 / close 掉」→ `close --id <任务号> --summary "…"`;说得含糊(「做完了」「验收通过」)先反问「是要结束这个任务吗?」。收尾顺序:**先补完正文 + 记 log,最后才 close** —— 关了就不能再写。
315
- 9. **查询**:在办 `list` / 单条 `show` / 已结案 `history`(默认只近 3 个自然月,更早的要 `--months` / `--since`)。
334
+ 8. **正常结案(做完了)**:仅当用户明确说「把这个任务结束掉 / close 掉」→ `close --id <任务号> --summary "…"`,**不带 `--cancel`**;说得含糊(「做完了」「验收通过」)先反问「是要结束这个任务吗?」。收尾顺序:**先补完正文 + 记 log,最后才 close** —— 关了就不能再写。
335
+ 9. **取消(作废)**:**只有**用户明确说「取消 / 作废」→ `close --id <任务号> --cancel [--summary "原因"]`。用户说「关闭 / 结案 / 结束」一律走第 8 条,**不许加 `--cancel`**;「不做了 / 先放一放 / 以后再做」是一暂停、不是取消(走第 5 条,状态不动);「需求不成立」只是理由、不是命令。含糊先问「是要**取消(作废)**还是**正常结案(做完了)**?」。公共池任务(未认领)只有这条入口 —— 想正常结案得先 `claim`。
336
+ 10. **查询**:在办 `list` / 单条 `show` / 已结案 `history`(默认只近 3 个自然月,更早的要 `--months` / `--since`)。
316
337
 
317
338
  ## 过程文档
318
339
 
@@ -320,27 +341,29 @@ allowed-tools: Read,Edit,Bash,Grep
320
341
 
321
342
  | 节 | 写什么 |
322
343
  |---|---|
323
- | 背景 | 为什么做:触发它的原话 / 现象 / 链接 |
324
- | 待办 | 还没做的、没验证的、等别人给东西的 |
325
- | 下一步 | 下一个**具体动作**(文件:行号 级别),不写「继续推进」 |
326
- | 过程 | 踩坑与证据:带 revision + `文件:行号` 或符号名 |
327
- | 结论 | 做成了什么、留了什么坑;只写可验证事实,评价等用户验收 |
328
- | 执行记录 | 脚本维护,**禁止手写**(见「手写边界」) |
344
+ | Background(背景) | 为什么做:触发它的原话 / 现象 / 链接 |
345
+ | To Do(待办) | 还没做的、没验证的、等别人给东西的 |
346
+ | Next(下一步) | 下一个**具体动作**(文件:行号 级别),不写「继续推进」 |
347
+ | Process(过程) | 踩坑与证据:带 revision + `文件:行号` 或符号名 |
348
+ | Conclusion(结论) | 做成了什么、留了什么坑;只写可验证事实,评价等用户验收 |
349
+ | Execution Log(执行记录) | 脚本维护,**禁止手写**(见「手写边界」) |
350
+
351
+ 节名**写英文**(2026-10-29 起;旧中文节名不再兼容,将统一迁移)。
329
352
 
330
353
  规则:
331
354
 
332
- - 「执行记录」节名一个字都别动;老文档缺这一节也不用补。
355
+ - `## Execution Log` 节名一个字都别动;老文档缺这一节也不用补(脚本补的时候补的是英文那节)。
333
356
  - 过程文档找不到时 `log` 只提示不失败;用 `show` 查路径,不要手写。
334
- - 头部是四行,由脚本维护、**都不要手改**,顺序固定 `标签 → 状态 → 创建 → 封卷`,值一律 `· ` 分隔:
357
+ - 头部是四行,由脚本维护、**都不要手改**,顺序固定 `Tags → Status → Created → Sealed`,值一律 `· ` 分隔:
335
358
 
336
359
  ```markdown
337
- - **标签**:建设、DSH、台账
338
- - **状态**:doing · 2026-10-27 09:12:33 · @某人 · 8d557c6d-…
339
- - **创建**:2026-10-26 23:38:02 · @某人 · 8d557c6d-…
340
- - **封卷**:2026-10-27 09:20:10 · @某人 · 8d557c6d-…
360
+ - **Tags**: 建设, DSH, 台账
361
+ - **Status**: doing · 2026-10-27 09:12:33 · @某人 · 8d557c6d-…
362
+ - **Created**: 2026-10-26 23:38:02 · @某人 · 8d557c6d-…
363
+ - **Sealed**: 2026-10-27 09:20:10 · @某人 · 8d557c6d-…
341
364
  ```
342
365
 
343
- 标签行与封卷行不一定有(没给标签、没结案就没有)。老文档头部可能还带着「**分类**」段,那是旧格式,不用补也不用改(脚本下次改写标签行时会一并清掉)。老文档没有状态行是合法的(`show` 回退查在办,`--json` 标 `legacy: true`),不用补。
366
+ 标签行与封卷行不一定有(没给标签、没结案就没有)。旧中文头部(`- **标签**:…` / 「**分类**」段)是旧格式,不再兼容,将统一迁移;`show --json` 不再标 `legacy`。
344
367
  - 执行记录行格式 `- 时间(UTC) · 类型 · @谁 · 说明`,`@谁` 是这次动手的人、不是任务现归属;只追加、不改旧行。行首「类型」是脚本内部动作名(会见到 `release`,它就是 `set --release`);认不出就别当成新命令,按 `--help` 查。
345
368
  - 只改某条任务的正文:`show --id <任务号>` 拿路径直接改,不另建 md;已结案的用 `history --months 12 --json` 找回链接(**人话输出里没有链接,必须加 `--json`**)——默认只查近 3 个月,结案久了的要显式放大窗口;只读不改。
346
369
 
@@ -370,7 +393,8 @@ allowed-tools: Read,Edit,Bash,Grep
370
393
  |---|---|---|
371
394
  | `new` / `claim` / `set` | 动手类 | 执行前复述完整参数并取得确认;**`new` 仅当用户原话点名要建且标题可直取原话时免复述**,标题需另拟或拿不准仍复述一次(`claim`/`set` 一律复述) |
372
395
  | `log` | 免确认 | 本任务的推进 / 卡点 / 交付记录直接跑,跑完一句话交代「已记执行记录:…」;要替用户下结论,先问(任务不在自己名下会直接被拒) |
373
- | `close` | 独立授权 | 仅认明确说「结束掉 / close 掉」(完整判定见生命周期第 8 条);说得含糊必须反问「是要结束这个任务吗?」;**agent 自判「干完了」不算** |
396
+ | `close`(正常结案) | 独立授权 | 仅认明确说「结束掉 / close 掉」(完整判定见生命周期第 8 条);**不带 `--cancel`**;说得含糊必须反问「是要结束这个任务吗?」;**agent 自判「干完了」不算** |
397
+ | `close --cancel`(取消) | 独立授权 | **只有用户明确说「取消 / 作废」才跑**(生命周期第 9 条);用户没说「取消 / 作废」一律不许加 `--cancel`;「不做了 / 先放一放」是暂停,不是取消;含糊先问「取消还是正常结案」 |
374
398
  | `list` / `stats` / `owners` / `show` / `history` / `root` / `whoami` / `validate` | 只读 | 直接跑 |
375
399
 
376
400
  ### 故障处置(跑之后出事怎么办)
@@ -1,33 +1,34 @@
1
- # <id>:<title>
1
+ # <id>: <title>
2
2
 
3
- - **状态**:<status>
4
- - **创建**:<created> · @<creator>
3
+ - **Status**: <status>
4
+ - **Created**: <created> · @<creator>
5
5
 
6
- <!-- 头部四行由脚本维护,顺序固定:标签 → 状态 → 创建 → 封卷。
7
- 「- **标签**:…」按 new --tags 插在最上面,没有标签就不写(分类只进台账与历史,不进本文档);
8
- 「- **封卷**:…」在结案时加在最后。 -->
6
+ <!-- Header lines are maintained by the script, fixed order: Tags → Status → Created → Sealed.
7
+ The `- **Tags**: …` line is inserted at the top by new --tags; omitted when there are no tags
8
+ (category goes to the ledger and history only, never into this document).
9
+ The `- **Sealed**: …` line is appended on close. -->
9
10
 
10
- ## 背景
11
+ ## Background
11
12
 
12
- <!-- 为什么做:触发它的原话 / 现象 / 链接 -->
13
+ <!-- What this is for: the words that triggered it / the symptom / a link -->
13
14
 
14
- ## 待办
15
+ ## To Do
15
16
 
16
- <!-- 还没做的、没验证的、等别人给东西的 -->
17
+ <!-- Not done yet, not verified, waiting on somebody -->
17
18
 
18
- ## 下一步
19
+ ## Next
19
20
 
20
- <!-- 下一个具体动作(文件:行号 级别),不要写「继续推进」 -->
21
+ <!-- The next concrete action (file:line level), never "keep going" -->
21
22
 
22
- ## 过程
23
+ ## Process
23
24
 
24
- <!-- 踩坑与证据:带 revision + 文件:行号 或符号名 -->
25
+ <!-- Pitfalls and evidence: with revision + file:line or symbol names -->
25
26
 
26
- ## 结论
27
+ ## Conclusion
27
28
 
28
- <!-- 做成了什么、留了什么坑 -->
29
+ <!-- What got done, what got left behind -->
29
30
 
30
- ## 执行记录
31
+ ## Execution Log
31
32
 
32
- <!-- 本节由脚本维护:new / claim / set / release / log / close 自动追加,请勿手改。
33
- 补记用 progress log --id <任务号> --note "一句话"。 -->
33
+ <!-- Maintained by the script: appended by new / claim / set / release / log / close. Do not edit.
34
+ Backfill with: progress log --id <id> --note "...". -->
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "task-ledger",
3
- "version": "1.3.45",
3
+ "version": "1.3.46",
4
4
  "description": "Task-ledger skill for coding agents: per-workspace progress tracking (ledger/pool.json + owners/<hash>.json shards + owners.json index, history, worklog) driven by a CLI script. Standalone install for CodeBuddy and other agents; also bundled inside the dsh-task-ledger DSH plugin.",
5
5
  "keywords": [
6
6
  "skill",
@@ -1,6 +1,6 @@
1
1
  # 状态与时间模型
2
2
 
3
- > TL;DR:状态只有 `open` / `doing`;`done` 由 `close` 产生。认领即 `doing`(`claim` / `new --self` 都直接置)。`started` = 首次认领时间,释放不清、重新认领不刷新。`updated` 由 `new/claim/set/log` 刷新。身份由脚本自取,agent 不传 owner。
3
+ > TL;DR:状态只有 `open` / `doing`;`done`(正常结案)/ `cancelled`(取消,`close --cancel`)由 `close` 产生。认领即 `doing`(`claim` / `new --self` 都直接置)。`started` = 首次认领时间,释放不清、重新认领不刷新。`updated` 由 `new/claim/set/log` 刷新。身份由脚本自取,agent 不传 owner。
4
4
 
5
5
  ## 状态机
6
6
 
@@ -14,7 +14,7 @@ close → 历史层 + 封卷 + 移出自己名下
14
14
  ```
15
15
 
16
16
  - **`started` 是外卖计时器**:首次认领盖上之后,释放(`set --release`)不清、重新认领不刷新 —— 逾期时钟从首次认领一口气跑到结案,转手不重置。防的是「眼看要超时,释放掉再认领回来洗时钟」;全链路没有重置 `started` 的命令(`claim` 的 `or now()` 只在它为空时才盖值;`set` 原样保留)。接手一个已超时的任务,一接单即逾期:单子已经迟了,谁端着谁负责;责任归属看执行记录流水(谁认领 / 谁释放逐笔有记录),计时器只回答「这单迟没迟」。
17
- - 状态只有 `open` / `doing` 两种在办值;`done` 由 `close` 产生(任务从分片消失,只留在历史里)。**没有 `blocked`**,也没有改状态的命令。
17
+ - 状态只有 `open` / `doing` 两种在办值;`done` / `cancelled` 由 `close` 产生(任务从池或分片消失,只留在历史里;`cancelled` 是 `close --cancel`)。**没有 `blocked`**,也没有改状态的命令。
18
18
  - 认领 / 释放 / 交接一律先写目标、再删原处,崩在中间会同一任务号短暂出现在两处 —— 重跑一次同一条命令即幂等收敛(`already_done`),或按 `validate` 的提示删掉多余那份。
19
19
 
20
20
  ## 时间
@@ -30,7 +30,7 @@ close → 历史层 + 封卷 + 移出自己名下
30
30
  - 进门:`--since` / `--until` / `--created` / `--finished` 按本机墙钟给,脚本内部转 UTC 再比较 / 落盘;除这四个参数没有任何地方要调用方传时间。
31
31
  - **过程文档正文不动**:`show --json` 的 `worklog.text` 是原文,里面的时间是当时写进去的 UTC。
32
32
  - 存量老数据写的是写入者本地时间、无标记,无法与 UTC 区分(JSON 是 2026-10-22 前,执行记录行是 2026-10-27 前)。
33
- - **history 文件 11 列**:结案时间 / 创建时间 / 标题 / 分类 / 标签 / owner / owner_name / creator / creator_name / 摘要 / 过程文档;排序与 `--since` / `--until` 按**结案时间**。(`history` 命令的人话输出只展示其中几列:结案时间、负责人、标题。)
33
+ - **history 文件 12 列**:Finished / Created / Title / Category / Tags / Owner / Owner Name / Creator / Creator Name / Summary / Result / Worklog(2026-10-29 起写英文表头;11 列旧文件不再兼容:读时跳过该行并告警,结案往里追加会直接报错要求先迁移);排序与 `--since` / `--until` 按**结案时间**。(`history` 命令的人话输出只展示其中几列:结案时间、负责人、标题。)
34
34
  - **owner / creator 两列存的是 uuid**(与任务里一致,身份只认 uuid);紧随其后的 `owner_name` / `creator_name` 两列**落盘**结案那一刻的显示名 —— 改名不回写旧行,看历史看到的就是当时那个名字。老行(升级前落的)没有名字时按名册兜底补一次展示值,**不回写文件**。
35
35
 
36
36
  ## 任务号
@@ -43,11 +43,11 @@ close → 历史层 + 封卷 + 移出自己名下
43
43
  - 没有 `identity.json`(未初始化)**直接报错**,提示先跑 `init`(一台机器一次);不再有兜底身份,也不读 git / 环境变量。
44
44
  - 全站只认 UUID 这一个身份键;`list --owner` / `history --owner` **只收 uuid**(形态不是 UUID 直接报错,不静默返回空),没有 `me` 缩写,「自己」用 `--mine`。
45
45
  - **名字不进任何判定**:按人模糊找只能走 `--owner-name <片段>`(对名册里的 `name` 做子串、不分大小写匹配,换成 uuid 集合再筛),它只是查询便利,认领 / 释放 / 交接 / 「我的」一律只比 uuid。任务上的 `owner_name` 是冗余显示字段,改名不影响归属。
46
- - `close` / `log` 只对自己名下的任务生效,不在名下直接拒绝;`set --release` 对已在公共池里的任务是幂等空转(退 0);`set --owner <自己>` 会把公共池里的任务认领到自己名下。
46
+ - `log` 只对自己名下的任务生效;`close` 对自己名下的做结案/取消,对公共池任务只能 `--cancel`(`close --cancel`),别人名下的拒绝;`set --release` 对已在公共池里的任务是幂等空转(退 0);`set --owner <自己>` 会把公共池里的任务认领到自己名下。
47
47
 
48
48
  ## 历史层
49
49
 
50
- - 按**结案时间**分月存放,11 列(列序:owner 之后是 `owner_name`,再是 creator、`creator_name`);`close` 写历史行时:分类用任务原值(**建任务后不可改**),标签用终值。
50
+ - 按**结案时间**分月存放,12 列(列序:Owner 之后是 `Owner Name`,再是 Creator、`Creator Name`,Summary 之后是 Result,末列 Worklog);`close` 写历史行时:分类用任务原值(**建任务后不可改**),标签用终值。
51
51
  - 存量平铺历史文件只读兼容、永不重写;`history` 连同它在内、按下面的月份区间合并。
52
52
  - **查询区间**:`history` 先由时间参数算出要读的月份文件,再逐个「存在才读、缺月跳过」,不扫磁盘。无时间参数默认最近 3 个自然月;`--months N`(近 N 月)与 `--since/--until`(结案时间闭区间)二选一;一次最多读 13 个历史文件(按月分文件,不区分连续/分散,只数总数),超出直接报错、不读任何文件。末列文档链接只按**文件名**消费(取 basename),链接里的 `../worklog/<年月>/` 前缀只为阅读器跳转服务,解析时忽略。
53
53
  - `history --json` 直接按文件现状解析,旧行没有的列不编造(名字列为空就按名册补展示值,不回写);存量九列的历史文件按 `docs/history-creator-upgrade.md` 一次性升级,脚本不认旧列数。