Commit Graph

2 Commits

Author SHA1 Message Date
wandering1 1b450be0ef fix(skill): @build 自持自释 build 锁,根治忘记 release 的泄漏
问题:锁不绑定进程存活(`lock acquire` 是短命进程,真正用 UV4 的是另一个
进程),所以释放只能靠调用方记得。Agent 手工 `lock acquire build` 后忘
了 `release`,锁要挂到 6 小时 TTL 才被下次 acquire 接管——期间其他任务
要么立即失败、要么干等。`done` 自己已用 try/finally 兜住,但手工路径没有。

改法:让**用资源的人**持锁。`keil_build.py` 进入 acquire、`finally`
**无条件** release(构建失败 / 异常 / SystemExit 都会释放)。
- `--lock-task`:持有者名。默认 `$DTU_TASK_ID` → 从 cwd 的
  `_wt/<ID>-<slug>/` 反推 `<ID>` → `build-cli`。反推意味着"手工
  `lock acquire build --task <ID>` 后再跑 @build"仍幂等,不会自我死锁。
- `--lock-wait N`:锁被占时等待(默认 0 = 立即失败)。
- `--no-lock`:完全不加锁。
- 新增退出码 **4 = build 锁被占用**(原先无此语义,占用会直接去构建)。
- 锁工具 = 兄弟 skill `task-worktree`;**找不到则降级为不加锁并告警**,
  保持本 skill 可独立搬运。

`done` 的兼容处理:它自己持锁,给子进程设 `DTU_LOCK_HELD=build` 告知
跳过自持自释。**对"工作树里还是旧 keil_build.py"的在途任务同样安全**
——旧版根本不看该变量、也不会自锁,故不会出现"双重持锁"死锁。

`bench` 锁**不动**:它是**会话作用域**(跨烧录→@test→探针多条命令),
逐命令自动释放会让别的任务插进来扰动设备,必须继续由 Agent 持有。

验证(主工作树实测):
- 自持自释:acquire → BUILD_OK → release,前后 `lock status` 均空闲;
- 被占:由 other-task 占锁 → exit 4,且**未触发构建**;
- 调用方持锁:`DTU_LOCK_HELD=build` → 打印"跳过自持自释",且
  **未释放调用方的锁**(锁仍归 __done__)——关键安全性质;
- 错误路径:无调用方持锁 + `--project` 不存在 → 失败但 **finally 已释放**;
- 持有者名推导:主工作树 → `build-cli`,`_wt/N33-stack-margins` → `N33`;
- 门禁:`mem-numbers` 一致;pre-commit 全绿。
2026-10-12 18:07:58 +08:00
wandering1 e4134a4723 feat(skill): 新增 task-worktree 多任务并行工作树 skill
用 git worktree 给每个任务开独立工作空间,干完由固定命令合回主干,
解决多任务共用同一工作目录时构建产物/日志/登记簿互相踩的问题。

- 机制:worktree + 任务分支 task/<ID>-<slug>(ID 沿用待处理内容编号)
- 目录:仓库同级 _wt/;.venv 与 simulator/SDL2 以 junction 共享
- .workbuddy-ai/ 刻意独占,清场前归并回主工作树
- 命令:new/list/status/sync/lock/done/abort(短命令 @task)
- 锁:build(UV4 不能并发)+ bench(COM6/ST-LINK/设备 IP),
  按时效 TTL 判定,不绑定进程存活
- done:merge-tree 预演 -> merge --no-ff -> 残留审计 -> 重生成产物
  -> 门禁 -> 清场;门禁未绿则保留工作树;不含 push
- 隔离演练(DTU_INTEGRATION_WORKTREE)暴露并修复 4 个缺陷,
  见 docs/环境与部署/并行任务工作树方案.md §11.1

同步:AGENTS.md 主题表、docs/README.md §9.2 与变更记录。
2026-10-12 11:56:13 +08:00