@@ -1,7 +1,7 @@
---
name: task-worktree
description: 多任务并行开发的空间管理(git worktree 生命周期):new 开一棵工作树 + 任务分支、目录联接共享 .venv 与模拟器 SDK、活跃任务硬上限 3 与腾位、build/bench 两类独占锁(含非登记任务占锁后「缺台账」释放不掉的正解)、done 预演合并回主干、门禁未全绿的补基线收尾、并集合并残留审计、**非登记工作树(detached HEAD / 无台账 / 树内有在飞或未跟踪内容)的安全回收**(逐文件内容分桶 + 联接/reparse 预扫 + 唯一残留先备份再 --force + 悬挂台账清理复验),以及**把仓外 detached worktree 当净室测量仪**——门禁指标异常增长时一次只注入一份在飞文件、与基线差分做逐文件归因;**以及与 DSH worktree 插件(`/worktree` 、模型工具 `worktree_create` ,树在仓内 .dsh-worktrees/)的桥接**——`plugin adopt` 补共享联接、锁归属 `pw:<name>` 、回收仍归 /worktree。规格见 docs/环境与部署/并行任务工作树方案.md。
whenToUse: 要同时推进多个任务、担心同分支同文档互相冲突;要为新任务开一个隔离空间;要把任务合并回主干;或遇到 `new` 报「已有 3 个活跃任务(上限 3 )」、`lock release` 报「任务 X 不存在(缺台账)」、`done` 报「门禁未全绿:工作树与分支保留,未清场」、两个任务抢 COM6 / UV4、"改了文档被覆盖"、并集合并残留时;或**门禁指标异常增长(如 id-check 的不可判定数从 1,162 涨到 1,178、+16)却查不出是哪个文件 / 哪条任务道造成的**、主工作树压着多条在飞改动而不许 stash / 提交 / 改门禁脚本、要按 HEAD 基线只读出像验收时;或**要回收 `@task list` 里根本看不到的工作树**( `git worktree list` 有它、台账没有 / detached HEAD / 树里疑似留着别的会话的在飞或未跟踪内容)、或**要清台账里 branch / path 都已不存在的悬挂条目**(`@task list` 输出发怪、`new` 报「任务已存在」或白占 3 个名额之一);或**这棵隔离空间是 DSH worktree 插件开的**(会话选了「Worktree模式」/ `/worktree create` ,树在仓库内 `.dsh-worktrees/` )——进去发现 `.venv` 不在、`@build` 与门禁全部起跑失败,或想看清谁在占 UV4 / 台架 → F 节。
description: 多任务并行开发的空间管理(git worktree 生命周期):new 开一棵工作树 + 任务分支、目录联接共享 .venv 与模拟器 SDK、活跃任务硬上限 8 与腾位、build/bench 两类独占锁(含非登记任务占锁后「缺台账」释放不掉的正解)、done 预演合并回主干、门禁未全绿的补基线收尾、并集合并残留审计、**非登记工作树(detached HEAD / 无台账 / 树内有在飞或未跟踪内容)的安全回收**(逐文件内容分桶 + 联接/reparse 预扫 + 唯一残留先备份再 --force + 悬挂台账清理复验),以及**把仓外 detached worktree 当净室测量仪**——门禁指标异常增长时一次只注入一份在飞文件、与基线差分做逐文件归因;**以及与 DSH worktree 插件(`/worktree` 、模型工具 `worktree_create` ,树在仓内 .dsh-worktrees/)的桥接**——`plugin adopt` 补共享联接、锁归属 `pw:<name>` 、回收仍归 /worktree。规格见 docs/环境与部署/并行任务工作树方案.md。
whenToUse: 要同时推进多个任务、担心同分支同文档互相冲突;要为新任务开一个隔离空间;要把任务合并回主干;或遇到 `new` 报「已有 8 个活跃任务(上限 8 )」、`lock release` 报「任务 X 不存在(缺台账)」、`done` 报「门禁未全绿:工作树与分支保留,未清场」、两个任务抢 COM6 / UV4、"改了文档被覆盖"、并集合并残留时;或**门禁指标异常增长(如 id-check 的不可判定数从 1,162 涨到 1,178、+16)却查不出是哪个文件 / 哪条任务道造成的**、主工作树压着多条在飞改动而不许 stash / 提交 / 改门禁脚本、要按 HEAD 基线只读出像验收时;或**要回收 `@task list` 里根本看不到的工作树**( `git worktree list` 有它、台账没有 / detached HEAD / 树里疑似留着别的会话的在飞或未跟踪内容)、或**要清台账里 branch / path 都已不存在的悬挂条目**(`@task list` 输出发怪、`new` 报「任务已存在」或白占 8 个名额之一);或**这棵隔离空间是 DSH worktree 插件开的**(会话选了「Worktree模式」/ `/worktree create` ,树在仓库内 `.dsh-worktrees/` )——进去发现 `.venv` 不在、`@build` 与门禁全部起跑失败,或想看清谁在占 UV4 / 台架 → F 节。
---
# task-worktree — 多任务并行开发空间(短命令 `@task`)
@@ -39,7 +39,7 @@ PY=".venv/Scripts/python.exe"; TW=".dsh/skills/task-worktree/scripts/task_worktr
`new` 常用开关:`--base <分支>` (默认 `v2-on-ui` )· `--needs-bench` (无台架 PASS 则 `done` 拒合)·
`--lean` (跳过 Git LFS smudge)· `--no-bootstrap` (不建联接)·
`--force` ( **仅跳过并发上限 3 的检查**,不解决「谁该让位」,见 A 节)。
`--force` ( **仅跳过并发上限 8 的检查**,不解决「谁该让位」,见 A 节)。
`done` 常用开关:`--dry-run` (只预演,零改动)· `--skip-build` · `--skip-gates` · `--force` (清场时强制移除工作树)。
@@ -78,15 +78,15 @@ PY=".venv/Scripts/python.exe"; TW=".dsh/skills/task-worktree/scripts/task_worktr
## 分步操作(六条运行时机制)
### A. `new` 被拒「已有 3 个活跃任务(上限 3 )」——怎么腾位
### A. `new` 被拒「已有 8 个活跃任务(上限 8 )」——怎么腾位
1. 读原文:`前置/环境错误:已有 3 个活跃任务(上限 3 );先 done/abort,或加 --force` ( exit 2)。
上限是脚本常量 `MAX_CONCURRENT = 3 ` ; **「活跃」的判据 = `_wt/.state/<ID>.json` 台账存在,且台账里
1. 读原文:`前置/环境错误:已有 8 个活跃任务(上限 8 );先 done/abort,或加 --force` ( exit 2)。
上限是脚本常量 `MAX_CONCURRENT = 8 ` ; **「活跃」的判据 = `_wt/.state/<ID>.json` 台账存在,且台账里
`path` 指向的目录还在**(手工删了工作树目录就不占名额,但会留下悬挂台账,见第 5 步与 **E 第 6 步 ** )。
2. `$TW list` 看全景(分支 / 落后领先 / 脏文件数)决定谁让位:**已完成的先 `done` **(合并回收,一步不省)。
3. 没人认领、零提交、尚未 claim 的空闲树 → `abort <ID>` 腾位(实测就是 abort 掉排在后面的空闲树换出名额)。
`abort` = 工作树 + 分支一起删、**永久丢弃**;工作树有未提交改动或已有提交时脚本会拒绝,确认可弃再加 `--force` 。
4. 确实要同时开第 4 棵才 `new <ID> <slug> --force` :磁盘代价约 **83 MB/棵 ** ( `--lean` 约 45 MB),
4. 确实要同时开第 9 棵才 `new <ID> <slug> --force` :磁盘代价约 **83 MB/棵 ** ( `--lean` 约 45 MB),
并行度上去了、**冲突面与台架排队也一起上去**——不是免费的。
5. **别用手工 `git worktree remove` 给「登记任务」腾位 ** :台账不会被删(下次 `new` 同 ID 会报「任务 <ID> 已存在」),
还绕过了「先摘联接」(铁律 5),有让 git 递归进联接把主工作树 `.venv` 删掉的风险。要回收的若是**非登记树**
@@ -120,7 +120,7 @@ PY=".venv/Scripts/python.exe"; TW=".dsh/skills/task-worktree/scripts/task_worktr
最后手段(脚本本身都走不通时):锁就是 `_wt/.state/locks/<name>.lock` 里的单行 JSON
( `name/task/pid/host/epoch/at/note/ttl` ),`release` 的实现就是 unlink 它——手工删这个文件等价于
「不记 PASS 的强制释放」,只在前面几步都不可用时才用。**历史遗留的占位台账**(早期为绕这个坑手写的
`_wt/.state/<NAME>.json` )现在已无必要:它活着时既占 `MAX_CONCURRENT = 3 ` 名额又被 `list` 当任务列出,
`_wt/.state/<NAME>.json` )现在已无必要:它活着时既占 `MAX_CONCURRENT = 8 ` 名额又被 `list` 当任务列出,
按 E 第 6 步备份后删掉即可。
### C. `done <ID>` 的正确用法(它是合并点,不是查看器)
@@ -179,7 +179,7 @@ git -C "$WT" status --porcelain # 应为空
"$PY" "$WT/scripts/archive/id_gate/check_ids.py" 2>&1 | tail -25 # ← 口径:id-check 钩子已于 2026-10-28 退役(脚本移入 scripts/archive/id_gate/),按该脚本自身默认参数跑;基线与注入用**同一条命令**
@T3 @
- `--detach` ( **不要 `-b` **):净室没有分支、不写 `_wt/.state/<ID>.json` 台账 → **不占 `MAX_CONCURRENT = 3 `
- `--detach` ( **不要 `-b` **):净室没有分支、不写 `_wt/.state/<ID>.json` 台账 → **不占 `MAX_CONCURRENT = 8 `
名额、不出现在 `$TW list` **,也没人会被误指去对它跑 `done` (建与拆都不走 `$TW new` / `$TW done` )。
- 能这么量的前提:该门禁**只读仓库内文本**。依赖本树构建产物的门禁(`mem-numbers` / `mem-budget` 要 `.map` )
在净室里必然报「找不到 .map 事实源」(见陷阱「新建工作树从未构建过」)——**那类指标不能这么归因**。
@@ -415,7 +415,7 @@ ls "$WTROOT"/.state/locks/ 2>/dev/null # 若该 ID 名下还有 .lock,先按
@T3 @
- **必须 `cp` 先备份再 `rm` **:台账里存着 base / junctions / needs_bench / bench_pass,是真出纠纷时唯一的现场记录。
- 悬挂条目按定义 `path` 已不存在 → 通常**不占** `MAX_CONCURRENT = 3 ` 名额(A 第 1 步的「活跃」判据要求 path 目录还在),
- 悬挂条目按定义 `path` 已不存在 → 通常**不占** `MAX_CONCURRENT = 8 ` 名额(A 第 1 步的「活跃」判据要求 path 目录还在),
但它把 `$TW list` 搅成怪输出、并永久挡住同 ID 复用;**path 还在的占位/残留台账才占名额**(早期为绕 B 节那个坑手写的占位台账就是这种)。两种都要清。
- **仍不对这个 ID 跑 `done` / `abort` **:清场会拿台账里的死 `path` / 死 `branch` 去做 `git worktree remove` 和删分支
(这正是 A 第 5 步说的「手工删目录留下的尾巴」,正解就是本步)。历史遗留的占位台账同理——活着时也别
@@ -448,7 +448,7 @@ ls "$WTROOT"/.state/locks/ 2>/dev/null # 若该 ID 名下还有 .lock,先按
**这棵树是不是插件的 ** : `git worktree list` 里路径含 `.dsh-worktrees/` 就是。`$TW list` 现在会在台账段
下面另起一段列出它们,联接列**点名缺哪一样**(`已联` / `缺 .venv` / `缺 SDL2` / `齐(实体SDL2)` )。**插件树不占
`MAX_CONCURRENT = 3 ` 名额**——回收不归本 skill,
`MAX_CONCURRENT = 8 ` 名额**——回收不归本 skill,
硬计入只会让别人那棵关不掉的树把 `new` 挡死(`new` 会打印一行「另有 N 个插件工作树不计入上限」提醒并发代价)。
三步接上(`<name>` 可带 `worktree/` 前缀,也可多段如 `refactor/logging` ):
@@ -490,7 +490,7 @@ ls "$WTROOT"/.state/locks/ 2>/dev/null # 若该 ID 名下还有 .lock,先按
5. **清场必须先摘联接 ** :脚本会先 `os.rmdir` 掉 `.venv` / `simulator/SDL2` 联接再
`git worktree remove` 。**手工清场时千万别直接 `git worktree remove` **——git 可能递归进联接,
把主工作树的 `.venv` 一起删掉。手工拆任何一棵树之前先跑 **E 第 3 步**的预扫,拿到 `REPARSE: none` 才动手。
6. **活跃任务硬上限 3 ** (脚本常量 `MAX_CONCURRENT = 3 ` ,每棵约 83 MB 检出)。满了 `new` 直接 exit 2,
6. **活跃任务硬上限 8 ** (脚本常量 `MAX_CONCURRENT = 8 ` ,每棵约 83 MB 检出——du 口径,内容字节和 84.0 MiB → `docs/环境与部署/并行任务工作树方案.md` §4 )。满了 `new` 直接 exit 2,
腾位顺序与 `--force` 的代价 → A 节;悬挂台账的清理与复验 → **E 第 6 步 ** 。
7. * * `@task` 的工作树放仓库同级 `_wt/` ,绝不在仓库内部**——否则污染 `git status` 、`pre-commit --all-files`
与全库搜索。唯一例外 = DSH worktree 插件写死的仓内 `.dsh-worktrees/` (改不了;已用「预置 .gitignore +