dsh-task-ledger 0.0.71 → 0.0.73

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.
@@ -1,3 +1,9 @@
1
+ /**
2
+ * 写命令的超时上限(ms):脚本写完会顺手 fetch + commit + push,最坏 30×4 = 120s。
3
+ * 沿用读命令的 10s 会把「已经 commit、还没 push」那一步掐死 —— 界面报失败,台账其实
4
+ * 已经改了,用户一重试就是二次写入。
5
+ */
6
+ export declare const WRITE_TIMEOUT_MS = 120000;
1
7
  export type LedgerScriptResult<T> = {
2
8
  ok: true;
3
9
  data: T;
@@ -5,10 +11,14 @@ export type LedgerScriptResult<T> = {
5
11
  ok: false;
6
12
  error: string;
7
13
  };
8
- /** 写命令的返回:只收 stdout 原文(claim / set 打的是人话,不是 JSON)。 */
14
+ /**
15
+ * 写命令的返回:stdout 原文(claim / set 打的是人话,不是 JSON)+ 退出码 0 时的 stderr。
16
+ * `notice` 有值说明脚本写成功了、但同步(commit / push)没成功 —— 不能当失败抛,也不能吞掉。
17
+ */
9
18
  export type LedgerCommandResult = {
10
19
  ok: true;
11
20
  output: string;
21
+ notice?: string;
12
22
  } | {
13
23
  ok: false;
14
24
  error: string;
@@ -8,6 +8,12 @@ import { fileURLToPath } from 'node:url';
8
8
  const DEFAULT_SCRIPT_PATH = fileURLToPath(new URL('../../../skill/scripts/progress.py', import.meta.url));
9
9
  /** 单次脚本调用超时上限(ms)。实测单仓 5 万行全量 1.2s,10s 是宽松上限。 */
10
10
  const DEFAULT_TIMEOUT_MS = 10_000;
11
+ /**
12
+ * 写命令的超时上限(ms):脚本写完会顺手 fetch + commit + push,最坏 30×4 = 120s。
13
+ * 沿用读命令的 10s 会把「已经 commit、还没 push」那一步掐死 —— 界面报失败,台账其实
14
+ * 已经改了,用户一重试就是二次写入。
15
+ */
16
+ export const WRITE_TIMEOUT_MS = 120_000;
11
17
  /**
12
18
  * 起一次 python3、收 stdout / stderr。出错一律归一成人话(起不了 python3 / 超时 / 非零退出)。
13
19
  * 解析留给调用方:读命令要 JSON,写命令要原文。
@@ -41,7 +47,7 @@ function exec(sub, args, opts) {
41
47
  settle({ ok: false, error: stderr.trim() || `skill 脚本退出码 ${String(code)}` });
42
48
  return;
43
49
  }
44
- settle({ ok: true, stdout });
50
+ settle({ ok: true, stdout, stderr: stderr.trim() });
45
51
  });
46
52
  });
47
53
  }
@@ -72,5 +78,9 @@ export async function runLedgerScript(sub, args, opts) {
72
78
  */
73
79
  export async function runLedgerCommand(sub, args, opts) {
74
80
  const result = await exec(sub, args, opts);
75
- return result.ok ? { ok: true, output: result.stdout.trim() } : result;
81
+ if (!result.ok)
82
+ return result;
83
+ const output = result.stdout.trim();
84
+ // 退出码 0 但 stderr 有字 = 写成功、同步失败(progress.py 的既定行为),必须带出去
85
+ return result.stderr ? { ok: true, output, notice: result.stderr } : { ok: true, output };
76
86
  }
@@ -200,9 +200,10 @@ export function registerWriteRoutes(webServer, deps) {
200
200
  return;
201
201
  }
202
202
  try {
203
- await action(workspace, taskId);
203
+ const notice = await action(workspace, taskId);
204
204
  invalidate(workspace.id);
205
- sendJson(res, 200, { ok: true });
205
+ // notice = 写成功但同步失败的人话:必须让界面看见,不能当成功静默吞掉
206
+ sendJson(res, 200, notice ? { ok: true, notice } : { ok: true });
206
207
  }
207
208
  catch (error) {
208
209
  sendJson(res, 500, { error: error instanceof Error ? error.message : String(error) });
@@ -1,5 +1,5 @@
1
1
  import type { LedgerWorkspace } from '../types.js';
2
2
  /** 认领:只有 open 且无人认领才能接(脚本内判定),owner = 当前工作区的 git 身份。 */
3
- export declare function claimTask(workspace: LedgerWorkspace, taskId: string): Promise<void>;
3
+ export declare function claimTask(workspace: LedgerWorkspace, taskId: string): Promise<string>;
4
4
  /** 释放:退回待认领(owner / started 清空),只许当前 owner 本人(脚本内判定)。 */
5
- export declare function releaseTask(workspace: LedgerWorkspace, taskId: string): Promise<void>;
5
+ export declare function releaseTask(workspace: LedgerWorkspace, taskId: string): Promise<string>;
@@ -6,11 +6,16 @@
6
6
  *
7
7
  * 校验全在脚本里(认领要求 open 且无 owner;释放要求是当前 owner),本层不重复实现。
8
8
  */
9
- import { runLedgerCommand } from '../repositories/runner.js';
9
+ import { WRITE_TIMEOUT_MS, runLedgerCommand } from '../repositories/runner.js';
10
+ /** 返回脚本在退出码 0 时打到 stderr 的提示(同步失败等);没有提示就是空串。 */
10
11
  async function run(workspace, sub, args) {
11
- const result = await runLedgerCommand(sub, [...args, '--repo', workspace.path], { cwd: workspace.path });
12
+ const result = await runLedgerCommand(sub, [...args, '--repo', workspace.path], {
13
+ cwd: workspace.path,
14
+ timeoutMs: WRITE_TIMEOUT_MS,
15
+ });
12
16
  if (!result.ok)
13
17
  throw new Error(`${workspace.title}:${result.error}`);
18
+ return result.notice ?? '';
14
19
  }
15
20
  /** 认领:只有 open 且无人认领才能接(脚本内判定),owner = 当前工作区的 git 身份。 */
16
21
  export function claimTask(workspace, taskId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-task-ledger",
3
- "version": "0.0.71",
3
+ "version": "0.0.73",
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",
package/skill/README.md CHANGED
@@ -120,8 +120,11 @@
120
120
  - 冲突时**报错要求重跑**,不静默覆盖
121
121
  - 写入成功后脚本会**自动同步**:把本次改动的台账文件 `git add <精确文件>` + `commit`(消息 `chore(ledger): <命令> <提交者>`,即 conventional commits 格式,多数仓库装了 commitlint 也认);当前分支有上游跟踪分支时再 `push`。全程确定性脚本,不依赖大模型
122
122
  - 仓库若装了自定义提交检查并拒了这条消息,脚本会**再用 `--no-verify` 提交一次**(台账是数据文件,不过 lint);仍失败则把 git 的报错打到 stderr 并要求手动提交 —— **同步失败绝不静默**,但退出码保持 0(台账本身已写成功)
123
- - 无 git 仓库 / 无上游跟踪 / 被 `.gitignore` 排除 / 无实际变更 都会静默跳过;`--no-sync` 或环境变量 `TASK_LEDGER_NO_SYNC=1` 可关闭
124
- - 冲突**仍不靠 `git pull` / `rebase` 解决**:并发靠指纹复查 + 原子写防覆盖,冲突时**报错要求重跑**,不静默合并
123
+ - 写前会**定向取最新**:只刷新 `ledger/progress.json` 与 `ledger/history/`(这两个只由脚本写);`ledger/worklog/` 里已有的正文一个字都不动,只在本地缺文件时补下远端的新文件(补下的文件随本次提交入库)。本地有未推送的台账提交、未提交改动、或未入库的同名文件时**中止**,不静默覆盖;命令随后失败时,写前刷下来的内容会回滚原样
124
+ - 本地**没有未推送提交**时,写前会先 fast-forward 到上游(只快进、不产生合并提交);有未推送提交就跳过,退回上面那条的定向刷新
125
+ - 同一个 clone 里的写命令**排队**执行(仓级文件锁,最多等 60 秒),避免两个 agent 同时写时,一个把另一个刚写完还没提交的改动静默覆盖
126
+ - 写后推送被拒时,工作树干净才自动 `rebase` 一次再推(各自改各自的任务时按行自动合并);冲突立刻 `rebase --abort`,绝不 `--force`、绝不留 rebase 中间态
127
+ - 无 git 仓库 / 无上游跟踪 / 被 `.gitignore` 排除 / 无实际变更 都会静默跳过;`--no-sync` 或环境变量 `TASK_LEDGER_NO_SYNC=1` 可同时关掉写前取最新与写后同步
125
128
 
126
129
  ### 结案是原子操作
127
130
 
package/skill/SKILL.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: task-ledger
3
3
  description: 本地任务台账,跨会话记录在办任务的归属、进度与起止。当用户要登记一件新的事(新建任务 / 建个坑 / 这活我领了)、记录已有任务的进展(接着做 / 记一条进展 / 这轮先记下)、查看任务状态或历史(现在该做什么 / 这活谁在做 / 上周做过什么)时加载;对某个具体任务要求结案或退回时,只认用户的明确指令;只是改代码、讨论方案时不要用。
4
- version: 1.2.6
4
+ version: 1.2.9
5
5
  allowed-tools: Read,Write,Bash,Grep
6
6
  ---
7
7
 
@@ -115,7 +115,11 @@ python3 <本 SKILL.md 所在目录>/scripts/progress.py <子命令> --repo <当
115
115
  ## 出错即停
116
116
 
117
117
  非 0 退出就停手、原样报告,**不要绕过脚本手改 `progress.json` 或历史层**。
118
+ **退出码 0 不等于没事**:写命令之后的同步(commit / push)失败仍返回 0,原因只写在输出里。写命令跑完必看输出,出现 `提示:` / `错误:` / `警告:` 就先用一句话说清「发生了什么 + 你要做什么」,再附原文关键行,按 `references/troubleshooting.md` 对应条目给步骤;纯告知类(如已用 `--no-verify` 提交)一句话带过。只读命令只有 `错误:` 才需要转述。
118
119
  并发冲突(文件被改动)重跑一次即可,不要用 `git pull` / `rebase` 去「解决」。
120
+ 写前会**定向取最新**:只刷新 `ledger/progress.json` 与 `ledger/history/`,`worklog/` 里已有的正文一个字都不动;
121
+ 本地有未推送的台账提交、未提交改动或未入库的同名文件时会中止 —— 按提示先提交 / 推送,或加 `--no-sync` 继续本地写。
122
+ 同一仓库里写命令**排队**执行(最多等 60 秒),并发时不要重试轰炸,等前一个跑完再重跑。
119
123
 
120
124
  细节见 `references/troubleshooting.md`。
121
125
 
@@ -127,4 +131,4 @@ python3 <本 SKILL.md 所在目录>/scripts/progress.py <子命令> --repo <当
127
131
  | 填正文前、补老任务文档、`log` 报错找不到文档 | `references/worklog.md` |
128
132
  | 拿不准一条记录够不够格、`--note` 怎么写 | `references/log-note.md` |
129
133
  | 写分类/标签、用户说标签太乱要归并 | `references/taxonomy.md` |
130
- | 任何非 0 退出、并发冲突、`validate` 报错 | `references/troubleshooting.md` |
134
+ | 任何非 0 退出、退出码 0 但有 `提示:` / `错误:`、并发冲突、`validate` 报错 | `references/troubleshooting.md` |
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "task-ledger",
3
- "version": "1.2.6",
3
+ "version": "1.2.9",
4
4
  "description": "Task-ledger skill for coding agents: per-workspace progress tracking (ledger/progress.json, 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,12 +1,12 @@
1
1
  # 排错
2
2
 
3
- > TL;DR:非 0 退出就停手、原样报告,别绕过脚本改 JSON。并发冲突重跑一次,不要用 `git pull` / `rebase` 去「解决」。
3
+ > TL;DR:非 0 退出就停手、原样报告;**退出码 0 但输出里有 `提示:` / `错误:` 同样要读并转述**(同步失败仍返回 0)。别绕过脚本改 JSON。并发冲突重跑一次,不要用 `git pull` / `rebase` 去「解决」。
4
4
 
5
5
  ## 退出码
6
6
 
7
7
  | 码 | 含义 | 处置 |
8
8
  |---|---|---|
9
- | 0 | 成功 | — |
9
+ | 0 | 成功(**同步可能失败**:输出里有 `提示:` 就按上面那条读) | — |
10
10
  | 1 | 业务错误(参数值 / 状态 / 权限不对) | 按提示纠正后重试;改不了的报告用户 |
11
11
  | 2 | 命令行参数错误 | 看 `<子命令> --help` 重新拼参数 |
12
12
  | 3 | 未预期的内部失败 | 上报,不要重试 |
@@ -19,6 +19,17 @@
19
19
  - **「状态不一致」**:对已在 `doing` 的任务又跑了 `claim`。直接改正文 + `log` 即可。
20
20
  - **`log` 报「没写进过程文档」**:worklog 路径丢失 / 不可读。用 `show --id` 查路径;`progress.json` 的 `updated` 已刷新,不要手写「执行记录」。
21
21
  - **「文件在操作期间被改动」**(并发指纹冲突):重新执行一次即可。
22
+ - **「本地台账有未提交改动,写前取最新会覆盖它」**:写前只取 `progress.json` / `history/` 的最新版,本地这两处脏就先停下。先提交(`git add ledger/ && git commit -m "chore(ledger): ..."`)再重跑;暂时离线可加 `--no-sync` 继续本地写。
23
+ - **「另一个会话正在同步同一份台账(已等 60 秒)」**:同一仓库里另一个 agent 正在写并推送,锁没抢到。等它跑完再重跑即可,不要并行重试(会把排队队列越堆越长)。
24
+ - **「本地有 N 个台账提交还没推到 …」**:上次推送没成功(离线 / 他人先推 / 认证失败)。先 `git push` —— 推台账时脚本自己会 fetch + rebase 重试一次,被拒就按它打出的提示手动合并,**不要自己 `git pull` / `git rebase` 台账目录**(会把写前同步的护栏绕过去)。推完重跑;离线场景用 `--no-sync`,联网后统一提交推送。
25
+ - **「本地已提交,但推送被拒」**:改动已安全落盘,只是远端没收,**不要重跑台账命令**(会二次写入)。看提示里 `git:` 那行的原文:`! [rejected] ... (fetch first)` = 他人先推,脚本已自动合并过一次仍失败就手动合并台账文件;`Permission denied (publickey)` / `could not read Username` = 凭据问题,找用户修,不要反复重试。
26
+ - **「自动 rebase 未成功(已回滚到 rebase 前)」**:同一条任务被两边同时改了。脚本已 abort,仓库是干净的;按提示里的冲突原文手动合并后 `git push`。
27
+ - **「自动 rebase 冲突后回滚也失败了」**:仓库停在 rebase 中间态,**先别跑任何台账命令**。在仓库根 `git rebase --abort`;仍失败就 `git status` 看残留,必要时删 `.git/rebase-merge` / `.git/rebase-apply` 再重试。
28
+ - **「暂存了你的未提交改动」+ autostash 冲突**:你的未提交改动在 stash 里,没有丢。`git stash list` 确认后用 `git stash pop` 手动解冲突;只想要内容可 `git stash show -p stash@{0}` 取出。
29
+ - **「git add 失败」/「自动提交失败」**:台账已写进本地文件,只是没进 git。按错误原话处理后手动 `git add <文件> && git commit -m "chore(ledger): ..."`。
30
+ - **「没有上游跟踪分支」/「当前是 detached HEAD」**:台账照写、照提交到本地,但**不会推送**。让用户建上游(`git push -u origin <分支>`)或切回分支;离线时这样用,联网后统一推一次。
31
+ - **「写前快进 … 没成功」**:通常是工作区里有未提交改动(git 按文件拦,不看行),脚本改走「只刷新本次要写的台账文件」。想快进就先提交或 stash 那些文件。
32
+ - **「worklog 正文疑似被覆盖成模板骨架」**:`validate` 会对仍只有注释占位的在办任务打提示。从 git 恢复该文件(`git checkout HEAD -- <路径>`)后重写正文,再跑 `log`。
22
33
  - **`validate` 报问题**:按行号读原文,先核对 `progress.json` 与 worklog 是否一致;能通过脚本修的走 `set` / `log`,**不要手改 JSON**。
23
34
 
24
35
  ## 硬约束