dsh-task-ledger 0.0.127 → 0.0.129

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,9 @@ import { failureOf, runLedgerScript } from "./runner.js";
5
5
  function toRecord(raw, workspace) {
6
6
  const src = typeof raw.src === "string" ? raw.src : "";
7
7
  const line = typeof raw.line === "number" ? raw.line : 0;
8
+ // history --json 的 src 相对 repo 根(ledger/history/YYYYMM.md),
9
+ // skill 的 delete --src 只收相对 ledger/ 的路径(history/YYYYMM.md)⇒ 在这里收口一次。
10
+ const deleteSrc = src.startsWith("ledger/") ? src.slice("ledger/".length) : src;
8
11
  const text = (value) => typeof value === "string" ? value : "";
9
12
  return {
10
13
  // ⚠️ 必须带工作区:各仓的 src 都是 `ledger/history/YYYYMM.md`、line 各自编号,
@@ -30,6 +33,8 @@ function toRecord(raw, workspace) {
30
33
  filePath: text(raw.worklog) === ""
31
34
  ? ""
32
35
  : path.join(workspace.path, "ledger", "history", text(raw.worklog)),
36
+ src: deleteSrc,
37
+ line,
33
38
  };
34
39
  }
35
40
  export async function readHistory(workspace, options) {
@@ -1,12 +1,15 @@
1
- /** 界面行内按钮对应的动作:认领 / 释放 / 取消归档 / 正常结案。 */
2
- export type TaskAction = "claim" | "release" | "cancel" | "close";
1
+ /** 界面行内按钮对应的动作:认领 / 释放 / 取消归档 / 正常结案 / 删除。 */
2
+ export type TaskAction = "claim" | "release" | "cancel" | "close" | "delete";
3
3
  /** 写命令的阶段 key(与 skill `runner.go` 里的 `stepf(...)` 一一对应)。 */
4
4
  export type TaskActionStep = "check" | "sync" | "write" | "commit" | "push";
5
5
  /**
6
6
  * 跑一条任务写命令。
7
7
  *
8
- * @param summary - 「取消」与「结案」都用:一句话理由 / 结案摘要,写进历史行与执行记录。
9
- * 留空就不传 `--summary`(skill 允许取消不带摘要;正常结案由界面强制填)。
8
+ * @param summary - 取消 / 结案的摘要、删除的留言;留空就不传 `--summary`。
10
9
  * @param onStep - 过程步骤回调(逐条转发给界面做进度翻牌),不传就不让 skill 打标记。
10
+ * @param history - 给就是删历史行(`delete --src/--line`),不给就是删在办任务(`delete --id`)。
11
11
  */
12
- export declare function runTaskAction(repo: string, id: string, action: TaskAction, summary?: string, onStep?: (step: TaskActionStep) => void): Promise<void>;
12
+ export declare function runTaskAction(repo: string, id: string, action: TaskAction, summary?: string, onStep?: (step: TaskActionStep) => void, history?: {
13
+ readonly src: string;
14
+ readonly line: number;
15
+ }): Promise<void>;
@@ -12,15 +12,16 @@ const ACTION_NAME = {
12
12
  release: "释放",
13
13
  cancel: "取消",
14
14
  close: "结案",
15
+ delete: "删除",
15
16
  };
16
17
  /**
17
18
  * 跑一条任务写命令。
18
19
  *
19
- * @param summary - 「取消」与「结案」都用:一句话理由 / 结案摘要,写进历史行与执行记录。
20
- * 留空就不传 `--summary`(skill 允许取消不带摘要;正常结案由界面强制填)。
20
+ * @param summary - 取消 / 结案的摘要、删除的留言;留空就不传 `--summary`。
21
21
  * @param onStep - 过程步骤回调(逐条转发给界面做进度翻牌),不传就不让 skill 打标记。
22
+ * @param history - 给就是删历史行(`delete --src/--line`),不给就是删在办任务(`delete --id`)。
22
23
  */
23
- export async function runTaskAction(repo, id, action, summary = "", onStep) {
24
+ export async function runTaskAction(repo, id, action, summary = "", onStep, history) {
24
25
  const opts = {
25
26
  timeoutMs: WRITE_TIMEOUT_MS,
26
27
  ...(onStep === undefined
@@ -57,6 +58,17 @@ export async function runTaskAction(repo, id, action, summary = "", onStep) {
57
58
  repo,
58
59
  ], opts);
59
60
  break;
61
+ case "delete":
62
+ // 留言可选;删除时刻由 skill 外壳统一算,插件不补录。
63
+ result = await runLedgerCommand("delete", [
64
+ ...(history === undefined
65
+ ? ["--id", id]
66
+ : ["--src", history.src, "--line", String(history.line)]),
67
+ ...(summary === "" ? [] : ["--summary", summary]),
68
+ "--repo",
69
+ repo,
70
+ ], opts);
71
+ break;
60
72
  }
61
73
  if (!result.ok)
62
74
  throw failureOf(result, `${ACTION_NAME[action]}失败:`);
@@ -271,21 +271,45 @@ export function registerRoutes(webServer, deps) {
271
271
  if (action !== "claim" &&
272
272
  action !== "release" &&
273
273
  action !== "cancel" &&
274
- action !== "close")
275
- throw new Error(`${BAD_REQUEST}action 只能是 claim / release / cancel / close`);
276
- // 摘要 / 理由:一句话就够,超长的截掉(历史行不该被一段小作文撑开)
274
+ action !== "close" &&
275
+ action !== "delete")
276
+ throw new Error(`${BAD_REQUEST}action 只能是 claim / release / cancel / close / delete`);
277
+ // 摘要 / 留言:一句话就够,超长的截掉(历史行不该被一段小作文撑开)
277
278
  const summary = typeof body.summary === "string" ? body.summary.trim().slice(0, 200) : "";
278
- // 正常结案必须有摘要(取消可以没有):空着也要在界面先挡住,这里兜一层
279
+ // 正常结案必须有摘要(取消 / 删除可以没有):空着也要在界面先挡住,这里兜一层
279
280
  if (action === "close" && summary === "")
280
281
  throw new Error(`${BAD_REQUEST}结案必须填一句摘要`);
281
282
  const id = typeof body.id === "string" ? body.id.trim() : "";
282
- if (id === "")
283
+ // 删历史行不用任务号,改用 skill 的 delete --src/--line 定位(src 相对 ledger/)
284
+ const src = typeof body.src === "string" ? body.src.trim() : "";
285
+ const line = typeof body.line === "number" &&
286
+ Number.isInteger(body.line) &&
287
+ body.line > 0
288
+ ? body.line
289
+ : 0;
290
+ const historyDelete = action === "delete" && src !== "";
291
+ if (historyDelete) {
292
+ if (!src.startsWith("history/") ||
293
+ !src.endsWith(".md") ||
294
+ src.includes(".."))
295
+ throw new Error(`${BAD_REQUEST}历史文件路径不合法`);
296
+ if (line === 0)
297
+ throw new Error(`${BAD_REQUEST}历史行号不合法`);
298
+ }
299
+ else if (id === "") {
283
300
  throw new Error(`${BAD_REQUEST}必须给任务号`);
301
+ }
284
302
  const workspaceId = typeof body.workspace === "string" ? body.workspace : "";
285
303
  const workspace = (await workspacesOf(deps)).find((item) => item.id === workspaceId);
286
304
  if (workspace === undefined)
287
305
  throw new Error(`${BAD_REQUEST}找不到这个工作区,改不了任务`);
288
- input = { action, repo: workspace.path, id, summary };
306
+ input = {
307
+ action,
308
+ repo: workspace.path,
309
+ id,
310
+ summary,
311
+ ...(historyDelete ? { src, line } : {}),
312
+ };
289
313
  }
290
314
  catch (error) {
291
315
  sendWriteFailure(res, error);
@@ -5,7 +5,10 @@ export interface TaskActionInput {
5
5
  /** 任务所在工作区根(skill 定位台账用)。 */
6
6
  readonly repo: string;
7
7
  readonly id: string;
8
- /** 取消时的一句话理由(可选;进历史摘要与执行记录)。 */
8
+ /** 删除历史行时的定位(相对 ledger/ 的路径 + 原文行号);不给就是删在办任务。 */
9
+ readonly src?: string;
10
+ readonly line?: number;
11
+ /** 取消 / 删除时的一句话留言(可选;进过程文档执行记录)。 */
9
12
  readonly summary?: string;
10
13
  }
11
14
  /**
@@ -10,6 +10,8 @@ import { runTaskAction, } from "../repositories/task.repository.js";
10
10
  * 命令跑完 / 失败前都会先收到前面那几个阶段,界面据此换文案。
11
11
  */
12
12
  export async function actOnTask(input, onStep) {
13
- await runTaskAction(input.repo, input.id, input.action, input.summary ?? "", onStep);
13
+ await runTaskAction(input.repo, input.id, input.action, input.summary ?? "", onStep, input.src !== undefined && input.line !== undefined
14
+ ? { src: input.src, line: input.line }
15
+ : undefined);
14
16
  invalidate();
15
17
  }
@@ -236,6 +236,10 @@ export interface HistoryRecord {
236
236
  readonly finished: string;
237
237
  /** 过程文档绝对路径;空串 = 这行没有 worklog,不可点开。 */
238
238
  readonly filePath: string;
239
+ /** 历史文件相对 ledger/ 的路径(skill `delete --src` 口径);空 = 定位不到,不给删。 */
240
+ readonly src: string;
241
+ /** 原文行号(1 起);0 = 定位不到,不给删。 */
242
+ readonly line: number;
239
243
  }
240
244
  /** `/history/list` 响应:选中那个月的结案记录(按结案时间正序)。
241
245
  * 分页不在这里做 —— 整月一次下发,前端按行号做虚拟滚动。 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-task-ledger",
3
- "version": "0.0.127",
3
+ "version": "0.0.129",
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.26.0"
60
+ "dsh-plugin-core": "^0.30.1"
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`(12 列),只由脚本写。
11
+ - **已结案**:一行一条在 `ledger/history/<年月>.md`(15 列),只由脚本写。
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` | 已结案(一行一条,12 列) |
23
+ | `ledger/history/<年月>.md` | 已结案(一行一条,15 列) |
24
24
 
25
25
  ## 为什么这么设计
26
26
 
@@ -38,7 +38,7 @@
38
38
 
39
39
  **不需要安装任何东西**:直接执行上面那个路径就行。它是个 `sh` 脚本——若某个安装环节丢了可执行位(报 `Permission denied`),前面加 `sh ` 照样能跑:`sh <SKILL.md 所在目录>/scripts/progress <子命令> --repo <工作区根>`。
40
40
 
41
- 子命令:`new` `claim` `set` `log` `close` `list` `history` `show` `whoami` `validate`。命令参考(参数 / 一句话 / 举例)、任务生命周期、纪律(数据完整性 / 人类授权 / 故障处置)全在 `SKILL.md`;参数细节看 `<子命令> --help`(不要凭记忆编)。
41
+ 子命令:`new` `claim` `set` `log` `close` `delete` `list` `history` `show` `whoami` `validate`。命令参考(参数 / 一句话 / 举例)、任务生命周期、纪律(数据完整性 / 人类授权 / 故障处置)全在 `SKILL.md`;参数细节看 `<子命令> --help`(不要凭记忆编)。
42
42
 
43
43
  ## 深入参考(references/,按需读)
44
44
 
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
  ---
@@ -22,7 +22,7 @@ allowed-tools: Read,Edit,Bash,Grep
22
22
 
23
23
  ## 命令参考
24
24
 
25
- 十四个子命令:`init`(初始化本机身份,一台机器一次)+ 前五个写命令(`new`/`claim`/`set`/`log`/`close`)+ 后八个只读命令(`list` / `stats` / `owners` / `show` / `history` / `root` / `whoami` / `validate`);何时用哪个见「任务生命周期」。参数语法看 `<子命令> --help`;下表说每个参数干什么、何时用。
25
+ 十五个子命令:`init`(初始化本机身份,一台机器一次)+ 前六个写命令(`new`/`claim`/`set`/`log`/`close`/`delete`)+ 后八个只读命令(`list` / `stats` / `owners` / `show` / `history` / `root` / `whoami` / `validate`);何时用哪个见「任务生命周期」。参数语法看 `<子命令> --help`;下表说每个参数干什么、何时用。
26
26
 
27
27
  只读命令里只有 `root` 特殊:**它在定位仓库之前跑**(「这个目录有没有台账」不能要求先有台账),不认 `--repo`、不读台账内容,只按结构判定。其余七个都先定位工作区根(带 `--repo` 或往上找)。
28
28
 
@@ -126,6 +126,21 @@ allowed-tools: Read,Edit,Bash,Grep
126
126
  - 正常结案:`close --id <任务号> --summary "发布流程走通,验证 25 项全过"`
127
127
  - 取消(用户明确说「取消 / 作废」):「这个任务作废掉」→ `close --id <任务号> --cancel --summary "需求已被「xxx」做掉"`
128
128
 
129
+ ### delete — 删除(建错的 / 垃圾任务)
130
+
131
+ **只认一个触发词:用户原话明确说「删除」。**「删掉 / 清掉 / 清理 / 移除」都不算,**不要推测意图、也不要用反问把它们转成删除**,只回一句「要删除请明确说『删除』」;「取消 / 作废」走第 9 条,「不做了 / 先放一放」走第 5 条。
132
+
133
+ **二次确认(硬门槛,一次一条)**:即使用户明确说了「删除」,也**不许直接跑**。先复述要删的是哪一条(在办:任务号 + 标题;历史:`--src` + `--line` + 标题),再问一句「确定要删除这个东西吗?」;**只有用户明确答复确认**(「确定」「删吧」「是」)才执行 `delete`。含糊、改口、没答复、答非所问 ⇒ 不删、停下,不反复追问、不替用户脑补同意。一次确认只对这一条、这一次有效;删下一条要重新问。删了没有恢复入口,原始数据仍留在台账文件里。
134
+
135
+ | 参数 | 含义 |
136
+ |---|---|
137
+ | `--id <任务号>` | 删除在办任务(公共池或自己名下分片):移进历史,结果列留空、删除三列落值;公共池任务不必先 `claim` |
138
+ | `--src <历史文件> --line <行号>` | 删除历史表格里那一行。`--src` 收相对 `ledger/` 的路径(如 `history/202610.md`),`--line` 是 `history --json` 给出的 `line`;行上原来的结果列与摘要一律不动 |
139
+ | `--summary <留言>` | 可省;只进过程文档执行记录,不写历史摘要 |
140
+ | `--repo <工作区根>` | 同上 |
141
+
142
+ `--id` 与 `--src` 二选一。删除后该行从所有列表、统计、趋势中整行消失,**没有开关、没有恢复、没有查询入口**;原始数据仍留在台账文件里。删除是数据纠错,取消仍是「这单被正式作废」的业务事实、照常计入结案统计 —— 别把两者混用。
143
+
129
144
  ### list — 查在办
130
145
 
131
146
  | 参数 | 含义 |
@@ -303,7 +318,7 @@ allowed-tools: Read,Edit,Bash,Grep
303
318
  - 若报 `Permission denied`(某些安装环节会丢可执行位),前面加 `sh `:`sh <本 SKILL.md 所在目录>/scripts/progress <子命令> …`。
304
319
  - **交给用户的命令必须是这个绝对路径**,不许简写成 `progress` —— 用户机器的 PATH 里没有这个命令,简写后用户一跑就是 `command not found`。
305
320
 
306
- - 定位项目:`--repo <工作区根>`(**直接含有 `ledger/` 的那个目录**)给了就校验后用;不给就从当前目录逐级向上找。`ledger/` 本身、以及它下面的任何子目录都不是根,指过去会被直接拒绝(判据只看位置,不看目录里有哪些文件 —— 项目根自带 `pool.json`、`history/`、`worklog/` 都不影响)。
321
+ - 定位项目:`--repo <工作区根>`(**直接含有 `ledger/` 的那个目录**)给了就校验后用;不给就从当前目录逐级向上找。当前目录已经在这个工作区里时不要带 `--repo`,只有要操作别的工作区才带。`ledger/` 本身、以及它下面的任何子目录都不是根,指过去会被直接拒绝(判据只看位置,不看目录里有哪些文件 —— 项目根自带 `pool.json`、`history/`、`worklog/` 都不影响)。
307
322
  - `--no-sync`(放在子命令**前**):用户明确要求「先别同步」时才用;之后自己 `git add ledger && commit && push`。
308
323
  - `--json` 只对只读命令(`list` / `stats` / `owners` / `show` / `history` / `root` / `whoami` / `validate`)有意义;写命令不接收 `--json`,传了是用法错。`stats --trend` 自带 JSON,不用也不接受 `--json`。
309
324
  - **给界面喂数**:要看在办用 `list`、要各面计数用 `stats`、要人选列表用 `owners`、要判断某个目录有没有台账用 `root` —— 都是只读、都不改台账;多个 / 跨工作区自己扇出,脚本一次只服务一个工作区。
@@ -331,7 +346,8 @@ allowed-tools: Read,Edit,Bash,Grep
331
346
  7. **释放**:仅当用户明确说「退回去 / 释放掉」→ `set --id <任务号> --release`。任务回公共池,别人可认领。
332
347
  8. **正常结案(做完了)**:仅当用户明确说「把这个任务结束掉 / close 掉」→ `close --id <任务号> --summary "…"`,**不带 `--cancel`**;说得含糊(「做完了」「验收通过」)先反问「是要结束这个任务吗?」。收尾顺序:**先补完正文 + 记 log,最后才 close** —— 关了就不能再写。
333
348
  9. **取消(作废)**:**只有**用户明确说「取消 / 作废」→ `close --id <任务号> --cancel [--summary "原因"]`。用户说「关闭 / 结案 / 结束」一律走第 8 条,**不许加 `--cancel`**;「不做了 / 先放一放 / 以后再做」是一暂停、不是取消(走第 5 条,状态不动);「需求不成立」只是理由、不是命令。含糊先问「是要**取消(作废)**还是**正常结案(做完了)**?」。公共池任务(未认领)只有这条入口 —— 想正常结案得先 `claim`。
334
- 10. **查询**:在办 `list` / 单条 `show` / 已结案 `history`(默认只近 3 个自然月,更早的要 `--months` / `--since`)。
349
+ 10. **删除**:**只有**用户原话明确说「删除」才进入这条;「删掉 / 清掉 / 清理 / 移除」不算(判定见「delete」节),「取消 / 作废」走第 9 条,「不做了 / 先放一放」走第 5 条。**先二次确认**:复述要删哪条 → 问「确定要删除这个东西吗?」→ 拿到用户明确答复确认,才跑在办 `delete --id <任务号> [--summary "留言"]`(公共池不必先 claim)或历史行 `delete --src <历史文件> --line <行号> [--summary "留言"]`。删了就删了,没有开关、恢复或查询入口;一次确认只对这一条这一次有效。
350
+ 11. **查询**:在办 `list` / 单条 `show` / 已结案 `history`(默认只近 3 个自然月,更早的要 `--months` / `--since`)。
335
351
 
336
352
  ## 过程文档
337
353
 
@@ -379,7 +395,7 @@ allowed-tools: Read,Edit,Bash,Grep
379
395
 
380
396
  ### 数据完整性(脚本管不了的,违反了数据就脏)
381
397
 
382
- - **执行记录禁手改**:只由脚本按 `new / claim / set / release / log / close` 追加,只增不改(**交接记的是 `set`**,看不到 `handoff` 是正常的)。
398
+ - **执行记录禁手改**:只由脚本按 `new / claim / set / release / log / close / cancel / delete` 追加,只增不改(**交接记的是 `set`**,看不到 `handoff` 是正常的;取消记 `cancel`、删除记 `delete`)。
383
399
  - **改正文必配一条日志**:动了 worklog 的正文(改一句、补一节、改标题、修错字都算)就必须立刻跑一次 `log`。
384
400
  - **换人只能「释放 → 认领」**:`set --release` 放回公共池,对方自己 `claim`;不许替别人挂名字。`set --owner <别人>`(预留转接通道,agent 一律不用)。
385
401
  - **身份由脚本从本机 identity 文件自取,agent 全程不传身份**:跑命令前不用查身份;只有当命令**退出码为 100** 时,才按 `references/init-identity.md` 引导用户跑 `init`(一台机器一次)。查自己用 `--mine`,查别人才传**对方 uuid**(`list --owner <uuid>`);释放用 `--release`,不传身份。
@@ -387,7 +403,7 @@ allowed-tools: Read,Edit,Bash,Grep
387
403
 
388
404
  ### 人类授权(跑之前问不问)
389
405
 
390
- 项目没有 `ledger/` ⇒ 先问「要不要建个台账记这活?」,不许自建。用户同意 ⇒ 直接跑第一条写命令,且**必须带 `--repo <工作区根>`**(根是直接含有 `ledger/` 的那个目录,`ledger/` 本身不是根、指到它会被拒绝):不带时脚本只从当前目录逐级往上找第一个含 `ledger/` 的目录,一个都没有就退 1 报「找不到台账」,绝不就地建;台账由这条写命令顺带建出来,身份**不用事先确认** —— 没 `init` 过,这条命令会当场退 100,按「身份闸门」走一遍就好(一台机器一次,写本机身份,与台账无关)。之后可以不带 `--repo`,但查找是**逐级往上**的 —— 在本项目的子目录里跑可能命中上层项目的台账,拿不准就一直带 `--repo <工作区根>`。
406
+ 项目没有 `ledger/` ⇒ 先问「要不要建个台账记这活?」,不许自建。用户同意 ⇒ 直接跑第一条写命令,且**必须带 `--repo <工作区根>`**(根是直接含有 `ledger/` 的那个目录,`ledger/` 本身不是根、指到它会被拒绝):不带时脚本只从当前目录逐级往上找第一个含 `ledger/` 的目录,一个都没有就退 1 报「找不到台账」,绝不就地建;台账由这条写命令顺带建出来,身份**不用事先确认** —— 没 `init` 过,这条命令会当场退 100,按「身份闸门」走一遍就好(一台机器一次,写本机身份,与台账无关)。之后可以不带 `--repo`,但查找是**逐级往上**的 —— 在本项目的子目录里跑可能命中上层项目的台账,拿不准先用 `root --dir <候选> --json` 看清它认的是哪个根,再决定要不要带 `--repo`。
391
407
 
392
408
  | 命令 | 档位 | 要求 |
393
409
  |---|---|---|
@@ -395,6 +411,7 @@ allowed-tools: Read,Edit,Bash,Grep
395
411
  | `log` | 免确认 | 本任务的推进 / 卡点 / 交付记录直接跑,跑完一句话交代「已记执行记录:…」;要替用户下结论,先问(任务不在自己名下会直接被拒) |
396
412
  | `close`(正常结案) | 独立授权 | 仅认明确说「结束掉 / close 掉」(完整判定见生命周期第 8 条);**不带 `--cancel`**;说得含糊必须反问「是要结束这个任务吗?」;**agent 自判「干完了」不算** |
397
413
  | `close --cancel`(取消) | 独立授权 | **只有用户明确说「取消 / 作废」才跑**(生命周期第 9 条);用户没说「取消 / 作废」一律不许加 `--cancel`;「不做了 / 先放一放」是暂停,不是取消;含糊先问「取消还是正常结案」 |
414
+ | `delete`(删除) | 独立授权 + **二次确认** | **只认用户原话明确说「删除」**(生命周期第 10 条 +「delete」节);「删掉 / 清掉 / 清理 / 移除」不算,**不许反问把它们转成删除**;即使说了也**必须先复述要删哪条、问「确定要删除这个东西吗?」**,拿到明确答复确认才跑;「取消 / 作废」走 `close --cancel`,「不做了 / 先放一放」是暂停;一次确认只对一条一次有效,删了没有恢复入口 |
398
415
  | `list` / `stats` / `owners` / `show` / `history` / `root` / `whoami` / `validate` | 只读 | 直接跑 |
399
416
 
400
417
  ### 故障处置(跑之后出事怎么办)
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "task-ledger",
3
- "version": "1.3.48",
3
+ "version": "1.3.51",
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",
@@ -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 文件 12 列**:Finished / Created / Title / Category / Tags / Owner / Owner Name / Creator / Creator Name / Summary / Result / Worklog(2026-10-29 起写英文表头;11 列旧文件不再兼容:读时跳过该行并告警,结案往里追加会直接报错要求先迁移);排序与 `--since` / `--until` 按**结案时间**。(`history` 命令的人话输出只展示其中几列:结案时间、负责人、标题。)
33
+ - **history 文件 15 列**:Finished / Created / Title / Category / Tags / Owner / Owner Name / Creator / Creator Name / Summary / Result / Worklog / Deleted / Deleted By / Deleted At(2026-10-29 起写英文表头);只认 15 列,列数不符的行静默跳过,不告警、不兼容、不提示迁移。末三列是删除标记 `yes` / 删除人 uuid / UTC 删除时刻,未删留空;`Deleted == "yes"` 的行从所有列表、统计、趋势中整行忽略,原始行仍留在文件里。排序与 `--since` / `--until` 按**结案时间**。(`history` 命令的人话输出只展示其中几列:结案时间、负责人、标题。)
34
34
  - **owner / creator 两列存的是 uuid**(与任务里一致,身份只认 uuid);紧随其后的 `owner_name` / `creator_name` 两列**落盘**结案那一刻的显示名 —— 改名不回写旧行,看历史看到的就是当时那个名字。老行(升级前落的)没有名字时按名册兜底补一次展示值,**不回写文件**。
35
35
 
36
36
  ## 任务号
@@ -47,7 +47,7 @@ close → 历史层 + 封卷 + 移出自己名下
47
47
 
48
48
  ## 历史层
49
49
 
50
- - 按**结案时间**分月存放,12 列(列序:Owner 之后是 `Owner Name`,再是 Creator、`Creator Name`,Summary 之后是 Result,末列 Worklog);`close` 写历史行时:分类用任务原值(**建任务后不可改**),标签用终值。
50
+ - 按**结案时间**分月存放,15 列(列序:Owner 之后是 `Owner Name`,再是 Creator、`Creator Name`,Summary 之后是 Result,然后是 Worklog,末尾三列是 `Deleted` / `Deleted By` / `Deleted At`);`close` 写历史行时:分类用任务原值(**建任务后不可改**),标签用终值;`delete` 删在办任务时结果列留空、删除三列落值。
51
51
  - 存量平铺历史文件只读兼容、永不重写;`history` 连同它在内、按下面的月份区间合并。
52
52
  - **查询区间**:`history` 先由时间参数算出要读的月份文件,再逐个「存在才读、缺月跳过」,不扫磁盘。无时间参数默认最近 3 个自然月;`--months N`(近 N 月)与 `--since/--until`(结案时间闭区间)二选一;一次最多读 13 个历史文件(按月分文件,不区分连续/分散,只数总数),超出直接报错、不读任何文件。末列文档链接只按**文件名**消费(取 basename),链接里的 `../worklog/<年月>/` 前缀只为阅读器跳转服务,解析时忽略。
53
- - `history --json` 直接按文件现状解析,旧行没有的列不编造(名字列为空就按名册补展示值,不回写);存量九列的历史文件按 `docs/history-creator-upgrade.md` 一次性升级,脚本不认旧列数。
53
+ - `history --json` 直接按文件现状解析,名字列为空就按名册补展示值,不回写;只认 15 列,脚本不写迁移 / 兼容程序,老工作区由 agent 逐个手工改为 15 列。