dsh-tower 2.0.3 → 2.1.0-beta.1

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.
Files changed (193) hide show
  1. package/CHANGELOG.md +141 -0
  2. package/COMPATIBILITY.md +38 -0
  3. package/CONTRIBUTING.md +150 -2
  4. package/README.en.md +59 -16
  5. package/README.md +57 -16
  6. package/SECURITY.md +31 -1
  7. package/adapters/default.js +10 -0
  8. package/adapters/store-fs.js +6 -0
  9. package/adapters/vcs-git.js +4 -0
  10. package/app/batch.js +79 -0
  11. package/app/board.js +25 -0
  12. package/app/checkCompletion.js +76 -0
  13. package/app/enrichedMissions.js +26 -0
  14. package/app/findings.js +78 -0
  15. package/app/gate.js +108 -0
  16. package/app/init.js +249 -0
  17. package/app/merge.js +567 -0
  18. package/app/messages.js +66 -0
  19. package/app/mission.js +35 -0
  20. package/app/missionContext.js +14 -0
  21. package/app/plan.js +42 -0
  22. package/app/provision.js +193 -0
  23. package/app/read.js +57 -0
  24. package/app/rebase.js +302 -0
  25. package/app/recording.js +72 -0
  26. package/app/review.js +145 -0
  27. package/app/roster.js +123 -0
  28. package/app/spawn.js +125 -0
  29. package/app/teardown.js +184 -0
  30. package/app/tower.js +524 -0
  31. package/cordis.patch.yml +61 -53
  32. package/docs/README.md +33 -1
  33. package/docs/architecture/overview.md +114 -14
  34. package/docs/board.md +72 -0
  35. package/docs/examples/first-mission.md +2 -1
  36. package/docs/faq.md +11 -7
  37. package/docs/guide/hot-reload.md +1 -1
  38. package/docs/guide/install-upgrade-migration.md +22 -6
  39. package/docs/guide/quickstart.md +12 -7
  40. package/docs/guide/release.md +125 -0
  41. package/docs/guide/scenarios-and-philosophy.md +86 -69
  42. package/docs/operations/security.md +65 -14
  43. package/docs/reference/blockers.md +11 -10
  44. package/docs/reference/config.generated.md +66 -0
  45. package/docs/reference/config.md +11 -7
  46. package/docs/reference/errors.generated.md +39 -0
  47. package/docs/reference/errors.md +10 -2
  48. package/docs/reference/events.md +7 -4
  49. package/docs/reference/testing.md +2 -1
  50. package/docs/reference/tools.generated.md +33 -0
  51. package/docs/reference/tools.md +8 -7
  52. package/docs/zh/README.md +4 -3
  53. package/docs/zh/faq.md +9 -6
  54. package/docs/zh/guide/hot-reload.md +1 -1
  55. package/docs/zh/guide/install-upgrade-migration.md +17 -5
  56. package/docs/zh/guide/quickstart.md +13 -8
  57. package/docs/zh/guide/scenarios-and-philosophy.md +55 -50
  58. package/docs/zh/operations/security.md +43 -7
  59. package/docs/zh/reference/blockers.md +10 -10
  60. package/docs/zh/reference/config.md +11 -7
  61. package/docs/zh/reference/errors.md +4 -1
  62. package/docs/zh/reference/events.md +6 -3
  63. package/docs/zh/reference/testing.md +3 -2
  64. package/docs/zh/reference/tools.md +8 -7
  65. package/domain/collab/batch.js +112 -0
  66. package/domain/collab/messages.js +127 -0
  67. package/domain/collab/roster.js +158 -0
  68. package/domain/collab/spawn.js +188 -0
  69. package/domain/config/schema.js +404 -0
  70. package/domain/contracts/outputs.js +279 -0
  71. package/domain/contracts/tool-inputs/collaboration.js +58 -0
  72. package/domain/contracts/tool-inputs/findings.js +29 -0
  73. package/domain/contracts/tool-inputs/index.js +94 -0
  74. package/domain/contracts/tool-inputs/integration.js +37 -0
  75. package/domain/contracts/tool-inputs/missions.js +94 -0
  76. package/domain/contracts/tool-inputs/ops.js +75 -0
  77. package/domain/contracts/tool-inputs/shared.js +25 -0
  78. package/domain/errors.js +96 -0
  79. package/domain/gate.js +125 -0
  80. package/domain/integration/gate.js +176 -0
  81. package/domain/integration/init.js +225 -0
  82. package/domain/integration/liveness.js +31 -0
  83. package/domain/integration/merge.js +377 -0
  84. package/domain/integration/provision.js +124 -0
  85. package/domain/integration/rebase.js +236 -0
  86. package/domain/integration/review.js +52 -0
  87. package/domain/integration/teardown.js +118 -0
  88. package/domain/mission.js +68 -0
  89. package/domain/missions/completion.js +114 -0
  90. package/domain/missions/findings.js +201 -0
  91. package/domain/missions/lifecycle.js +185 -0
  92. package/domain/missions/plan.js +149 -0
  93. package/domain/missions/review.js +179 -0
  94. package/domain/planning.js +118 -0
  95. package/domain/read/enrichedMissions.js +58 -0
  96. package/domain/read/missionContext.js +53 -0
  97. package/domain/read/views.js +128 -0
  98. package/domain/report.js +59 -0
  99. package/domain/roster.js +40 -0
  100. package/domain/scope.js +105 -0
  101. package/domain/state/schema.js +233 -0
  102. package/domain/state/semantics.js +117 -0
  103. package/domain/state.js +33 -0
  104. package/domain/summary.js +114 -0
  105. package/domain/vocabulary.js +179 -0
  106. package/index.js +86 -34
  107. package/lib/briefing.js +176 -0
  108. package/lib/compatibility.js +108 -0
  109. package/lib/config.js +54 -302
  110. package/lib/doctor.js +108 -9
  111. package/lib/git.js +93 -15
  112. package/lib/hmr.js +4 -3
  113. package/lib/leases.js +3 -2
  114. package/lib/legacy.js +20 -9
  115. package/lib/modeState.js +39 -0
  116. package/lib/modeStore.js +35 -33
  117. package/lib/persistence.js +349 -0
  118. package/lib/presets.js +35 -0
  119. package/lib/spawn-prechecks.js +168 -0
  120. package/lib/spawn-support.js +79 -0
  121. package/lib/store.js +57 -85
  122. package/lib/tests.js +46 -11
  123. package/lib/tool-registry.js +544 -0
  124. package/lib/workspaceLock.js +46 -22
  125. package/lib/worktreeOwnership.js +5 -4
  126. package/locale/en.json +23 -1
  127. package/locale/zh.json +22 -0
  128. package/package.json +33 -4
  129. package/ports/clock.js +6 -0
  130. package/ports/ids.js +7 -0
  131. package/ports/index.js +2 -0
  132. package/ports/store.js +11 -0
  133. package/ports/vcs.js +11 -0
  134. package/scripts/architecture.mjs +94 -0
  135. package/scripts/check-docs.mjs +44 -3
  136. package/scripts/check-pack.mjs +49 -0
  137. package/scripts/domain-metrics.mjs +48 -0
  138. package/scripts/generate-config-reference.mjs +46 -0
  139. package/scripts/generate-error-reference.mjs +29 -0
  140. package/scripts/generate-tools-reference.mjs +56 -0
  141. package/scripts/issue-audit.mjs +259 -0
  142. package/scripts/lib/cli.mjs +76 -0
  143. package/scripts/lib/tmp.mjs +20 -0
  144. package/scripts/mount-smoke/fixtures.mjs +162 -0
  145. package/scripts/mount-smoke/host.json +4 -0
  146. package/scripts/mount-smoke/probe.mjs +125 -0
  147. package/scripts/mount-smoke/surface.mjs +141 -0
  148. package/scripts/mount-smoke.mjs +270 -0
  149. package/scripts/pack-manifest.txt +203 -0
  150. package/scripts/release-check.mjs +303 -0
  151. package/skills/tower-recovery.md +7 -5
  152. package/tools/adopt.js +72 -0
  153. package/tools/batch.js +78 -0
  154. package/tools/complete.js +53 -0
  155. package/tools/diff.js +39 -0
  156. package/tools/doctor.js +50 -0
  157. package/tools/finding.js +40 -0
  158. package/tools/findings.js +39 -0
  159. package/tools/import-legacy.js +42 -0
  160. package/tools/inbox.js +39 -0
  161. package/tools/index.js +39 -0
  162. package/tools/init.js +63 -0
  163. package/tools/interrupt.js +42 -0
  164. package/tools/legacy-map.js +44 -0
  165. package/tools/merge.js +39 -0
  166. package/tools/mission.js +41 -0
  167. package/tools/plan.js +39 -0
  168. package/tools/preflight.js +44 -0
  169. package/tools/rebase.js +39 -0
  170. package/tools/recover.js +45 -0
  171. package/tools/reload.js +52 -0
  172. package/tools/resource.js +54 -0
  173. package/tools/review.js +45 -0
  174. package/tools/roster.js +60 -0
  175. package/tools/send.js +147 -0
  176. package/tools/spawn.js +196 -0
  177. package/tools/status.js +94 -0
  178. package/tools/teardown.js +42 -0
  179. package/tools/test.js +61 -0
  180. package/types/cordis.d.ts +6 -0
  181. package/types/index.d.ts +339 -0
  182. package/ui-bundle/README.md +111 -0
  183. package/ui-bundle/client.js +1980 -0
  184. package/ui-bundle/cordis.patch.yml +3 -0
  185. package/ui-bundle/icon.svg +6 -0
  186. package/ui-bundle/index.js +2 -0
  187. package/ui-bundle/locale/en.json +6 -0
  188. package/ui-bundle/locale/zh.json +6 -0
  189. package/ui-bundle/package.json +35 -0
  190. package/lib/errors.js +0 -111
  191. package/lib/tools.js +0 -2250
  192. package/lib/tower.js +0 -2689
  193. /package/{lib → domain}/batch.js +0 -0
@@ -2,9 +2,9 @@
2
2
 
3
3
  [English](../guide/scenarios-and-philosophy.md)
4
4
 
5
- Tower 不是所有多代理模式的替代品。它是**面向 Git 仓库变更的交付协议**:少量边界清晰的 mission、隔离的写入者、独立审查、证据与合并门禁。本页解释这些设计取舍、适用场景,以及什么时候 Agent Teams、Ralph 循环、Workflow 编排或普通并行子代理更合适。
5
+ Tower 不是所有多代理模式的替代品。它是**面向 Git 仓库变更的交付协议**:少量边界清晰的 mission、隔离的写入者、可选独立审查、证据与合并门禁。本页解释这些设计取舍、适用场景,以及什么时候 Agent Teams、Ralph 循环、Workflow 编排或普通并行子代理更合适。
6
6
 
7
- 如果只记一句话:**输出是需要审查并合入仓库的变更时用 Tower;输出是探索、重复尝试或程序化扇出时用其他模式。**
7
+ 如果只记一句话:**输出是需要经过受控合并落地的仓库变更时用 Tower;输出是探索、重复尝试或程序化扇出时用其他模式。**如果还需要独立审查,开启 `review.requireReview`。
8
8
 
9
9
  ## 1. 设计哲学
10
10
 
@@ -12,7 +12,7 @@ Tower 做了一组刻意的取舍,这解释了它的优势和成本。
12
12
 
13
13
  ### 1.1 仓库是责任单位
14
14
 
15
- mission 不是聊天线程或任务卡,而是绑定到分支与 worktree 的契约:有声明式写范围、依赖、完成证据和审查记录。"改了什么、谁改的、凭什么说改对了"有持久答案,位于 `<git-common-dir>/dsh-tower/state.json` 与 Git 历史,而不只在对话里。
15
+ mission 不是聊天线程或任务卡,而是绑定到分支与 worktree 的契约:有声明式写范围、依赖、完成证据和可选审查记录。"改了什么、谁改的、凭什么说改对了"有持久答案,位于 `<git-common-dir>/dsh-tower/state.json` 与 Git 历史,而不只在对话里。
16
16
 
17
17
  ### 1.2 一个 mission 一个写入者
18
18
 
@@ -24,21 +24,25 @@ mission 不是聊天线程或任务卡,而是绑定到分支与 worktree 的
24
24
 
25
25
  ### 1.4 集成是独立的特权步骤
26
26
 
27
- worker 永远不合并。reviewer 审查特定分支 tip;控制塔运行 preflight;只有之后 `tower_merge` 才执行 `--no-ff` 合并。门禁重新检查 scope、base 新鲜度、任务、审查绑定、worktree 归属、worker 状态、测试与证据。职责分离是重点:写代码的 agent 不批准,批准的 agent 也不合并。
27
+ worker 永远不合并。控制塔运行 preflight;只有之后 `tower_merge` 才执行 `--no-ff` 合并。门禁重新检查 scope、base 新鲜度、任务、worktree 归属、worker 状态、测试与证据。开启审查时,reviewer 还会审查特定分支 tip,门禁检查审查绑定;职责分离(写代码者不批准、批准者不合并)在审查开启时生效。
28
28
 
29
- 独立审查默认可选:设 `review.requireReview:true` 才会强制(此时已完成 mission 必须带有绑定 tip 的 clean/merge 审查)。对敏感仓库建议开启;全局开启时仍可用 `reviewPolicy:"none"` + 理由做单个 mission 豁免。无论开关如何,都可以提交并记录 review。
29
+ 独立审查默认可选:设 `review.requireReview:true` 才会强制(此时已完成 mission 必须带有绑定 tip 的 clean/merge 审查)。对敏感仓库建议开启;全局开启时仍可用 `reviewPolicy:"none"` + 理由 + `gates.allowReviewExemption:true` 做单个 mission 豁免。无论开关如何,都可以提交并记录 review。
30
30
 
31
31
  ### 1.5 证据优先于断言
32
32
 
33
- "完成了"是声明;commit、diff、通过的测试回执、独立审查才是证据。Tower 全部记录:`tower_doctor` 检查环境,`tower_test` 记录发现,`tower_complete` 记录 checks,`tower_review` 把结论绑定到提交,`tower_batch` 只有在有限 mission 集合的必需证据齐全时才允许收口。
33
+ "完成了"是声明;commit、diff、通过的测试回执、审查结论都是证据。Tower 全部记录:`tower_doctor` 检查环境,`tower_test` 记录发现,`tower_complete` 记录 checks,`tower_review` 把结论绑定到提交(开启审查时),`tower_batch` 只有在有限 mission 集合的必需证据齐全时才允许收口。
34
34
 
35
35
  ### 1.6 失败关闭,显式恢复
36
36
 
37
- Tower 宁可显示 blocker,也不静默修复。stale worker 被标记而不是假设已死;脏 base 阻止合并;审查后 tip 变化阻止合并;merge 期间崩溃会留下持久 intent,由下一次 `tower_merge` 对账。代价是偶尔需要人工清理,收益是状态不会谎报已集成的内容。
37
+ Tower 宁可显示 blocker,也不静默修复。stale worker 被标记而不是假设已死;脏 base 阻止合并;开启审查时,审查后 tip 变化阻止合并;merge 期间崩溃会留下持久 intent,由下一次 `tower_merge` 对账。代价是偶尔需要人工清理,收益是状态不会谎报已集成的内容。
38
38
 
39
- ### 1.7 人类拥有模式
39
+ ### 1.7 模式切换显式且可归因
40
40
 
41
- Tower 模式改变会话姿态:收窄工具面并注入 mission 协议。随包 patch 允许模型给出理由后切换,但该模式存在的前提是人类需要交付纪律。进入会暂停活跃 goal 并清除 plan mode;退出不会静默恢复。Tower 激活期间刻意拒绝 `goal`、`todo`、Team 任务板、Workflow、Ralph 与普通 subagent 工具,避免两套编排协议争夺同一会话。
41
+ Tower 模式改变会话姿态:收窄工具面并注入 mission 协议。人类始终可以用 `/tower` 切换;默认情况下
42
+ 模型也可以带具体理由用 `tower_control` 进出,每次变更记录操作者与理由。设计重点不是某一方拥有
43
+ 开关,而是切换必须显式、可见;若部署需要仅人类控制,设 `mode.allowAgentControl:false`。进入会
44
+ 暂停活跃 goal 并清除 plan mode;退出不会静默恢复。Tower 激活期间刻意拒绝 `goal`、`todo`、
45
+ Team 任务板、Workflow、Ralph 与普通 subagent 工具,避免两套编排协议争夺同一会话。
42
46
 
43
47
  ### 1.8 本地优先,无隐藏服务
44
48
 
@@ -50,19 +54,19 @@ Tower 是 Host 插件,只使用本地 Git、本地文件和 DSH subagent 服
50
54
 
51
55
  | 场景 | 具体例子 | 为什么用 Tower |
52
56
  |---|---|---|
53
- | 可拆成独立切片的特性 | 加 OAuth:`token 模型` → `callback 路由` → `UI 按钮` + 迁移,四个 scope 基本独立的 mission | 写入隔离、scope 预留、最终统一审查/合并 |
57
+ | 可拆成独立切片的特性 | 加 OAuth:`token 模型` → `callback 路由` → `UI 按钮` + 迁移,四个 scope 基本独立的 mission | 写入隔离、scope 预留、最终统一合并(可选审查) |
54
58
  | 有顺序的迁移/重构 | monorepo 重命名 `oldApi`:codemod → import 清理 → 快照 → 文档,每步依赖前一步合并 | `deps`、分支新鲜度、合并串行 |
55
59
  | 先调查再修改 | survey mission 映射已弃用 crypto API 的所有调用者;两个 build mission 迁移与补测试 | survey 不能改文件;findings 喂给 build |
56
- | 敏感或发布绑定变更 | 支付服务改动或公共库发布,需要被审查 commit 与测试证据 | 审查绑定、checks/testRuns、人类可审计 |
60
+ | 敏感或发布绑定变更 | 支付服务改动或公共库发布,需要测试证据与可审计合并(需要独立结论时开启审查) | checks/testRuns、可选审查绑定、人类可审计 |
57
61
  | 长期工作 | 多日依赖升级,期间重启、换会话、上下文重置 | mission/roster/review/worktree 持久 |
58
- | 硬集成边界 | monorepo 四个服务各有 owner,最后统一发布审查 | 多 mission 并行,单一合并门禁 |
62
+ | 硬集成边界 | monorepo 四个服务各有 owner,最后统一发布合并 | 多 mission 并行,单一合并门禁 |
59
63
  | 可检查的完成定义 | 任务清单 + 必需测试 + 可选独立审查结论 | 另一个 agent 能检查证据 |
60
64
 
61
65
  ### 2.1 能自然拆成独立切片的特性
62
66
 
63
- 例:OAuth 登录拆成"token 模型"、"callback 路由"、"UI 按钮"、"迁移 + 测试"。切片大多改不同文件,可以并行,最后需要集成审查。Tower 的 scope 预留与重叠自动依赖可以避免碰撞。
67
+ 例:OAuth 登录拆成"token 模型"、"callback 路由"、"UI 按钮"、"迁移 + 测试"。切片大多改不同文件,可以并行,最后统一合并(需要时再加审查)。Tower 的 scope 预留与重叠自动依赖可以避免碰撞。
64
68
 
65
- **为什么用 Tower:** 并行写入被隔离;每个切片有 owner 与审查;合并在最后统一门禁,而不是逐段即兴处理。
69
+ **为什么用 Tower:** 并行写入被隔离;每个切片有 owner,需要时再审查;合并在最后统一门禁,而不是逐段即兴处理。
66
70
 
67
71
  ### 2.2 有顺序约束的迁移或重构
68
72
 
@@ -78,9 +82,9 @@ Tower 是 Host 插件,只使用本地 Git、本地文件和 DSH subagent 服
78
82
 
79
83
  ### 2.4 敏感仓库或与发布绑定的变更
80
84
 
81
- 例:支付服务、有外部用户的库、release 分支。你需要独立 reviewer、特定被审查 commit、测试证据和人类可审计记录。
85
+ 例:支付服务、有外部用户的库、release 分支。你需要测试证据和人类可审计记录;开启审查时,还会得到独立 reviewer、特定被审查 commit 与绑定 tip 的结论。
82
86
 
83
- **为什么用 Tower:** 审查绑定、证据门禁、`MISSIONS.md`、活动日志和可选测试发现提供了可辩护的记录;reviewer 是独立的只读 agent,不是作者。
87
+ **为什么用 Tower:** 证据门禁、`MISSIONS.md`、活动日志和可选测试发现提供了可辩护的记录;开启审查时,reviewer 是独立的只读 agent,不是作者,结论绑定 tip。
84
88
 
85
89
  ### 2.5 跨上下文压缩或重启的长期工作
86
90
 
@@ -90,23 +94,23 @@ Tower 是 Host 插件,只使用本地 Git、本地文件和 DSH subagent 服
90
94
 
91
95
  ### 2.6 有硬集成边界的并行工作
92
96
 
93
- 例:monorepo 中四个独立服务,各有 owner,最后统一发布审查。Tower 给每个 mission 分支/worktree 并预留写范围;控制塔可用 `tower_batch` 审计有限的发布证据。
97
+ 例:monorepo 中四个独立服务,各有 owner,最后统一发布合并。Tower 给每个 mission 分支/worktree 并预留写范围;控制塔可用 `tower_batch` 审计有限的发布证据。
94
98
 
95
99
  **为什么用 Tower:** 并行是真的,但集成仍然是一个统一的、带门禁的步骤。
96
100
 
97
101
  ### 2.7 需要另一个 agent 能检查的"完成定义"
98
102
 
99
- 例:任务清单 + 测试 + 必需审查结论。Tower 的 mission 契约与 completion/review 工具让"完成"可观察。如果你的完成定义只是"用户在聊天里满意",Tower 是过度设计。
103
+ 例:任务清单 + 测试 + 可选审查结论。Tower 的 mission 契约与 completion/review 工具让"完成"可观察。如果你的完成定义只是"用户在聊天里满意",Tower 是过度设计。
100
104
 
101
105
  ## 3. Tower 不适合的场景
102
106
 
103
107
  | 场景 | 更合适的模式 | 原因 |
104
108
  |---|---|---|
105
- | 单文件修改、typo、小 hotfix | 普通会话中的单个 agent | worktree、审查与合并开销大于收益。 |
109
+ | 单文件修改、typo、小 hotfix | 普通会话中的单个 agent | worktree 与合并开销(开启审查时再加审查)大于收益。 |
106
110
  | 需求仍在发现阶段 | 普通 agent、Plan mode 或 Agent Teams | Tower 要求先给 scope/tasks;错误契约会导致重新规划。 |
107
111
  | 开放式研究或头脑风暴 | Agent Teams、Workflow 或普通子代理 | 没有要隔离和合并的仓库变更。 |
108
- | 很多极小的独立任务 | Workflow 或普通并行子代理 | 每个 mission 的审查/合并成本太高。 |
109
- | 交互式 UI 配对或探索式调试 | 普通 agent(或单个 worker) | 需要紧密反馈与频繁人工引导,审查门禁增加延迟。 |
112
+ | 很多极小的独立任务 | Workflow 或普通并行子代理 | 每个 mission 的合并成本(开启审查时再加审查)太高。 |
113
+ | 交互式 UI 配对或探索式调试 | 普通 agent(或单个 worker) | 需要紧密反馈与频繁人工引导,开启审查时门禁增加延迟。 |
110
114
  | 一次性生成、没有集成 | 普通子代理/Workflow | 不需要分支、审查、合并决策。 |
111
115
  | 跨仓库产品工作 | Agent Teams + 普通工具 | Tower 只作用于单个 Git 仓库。 |
112
116
 
@@ -118,11 +122,11 @@ Tower 是 Host 插件,只使用本地 Git、本地文件和 DSH subagent 服
118
122
 
119
123
  | 维度 | Tower | Agent Teams | Ralph 循环 | Workflow 编排 | 普通并行子代理 |
120
124
  |---|---|---|---|---|---|
121
- | 主要目标 | 交付经审查的仓库变更 | 围绕共享目标协作 | 对同一目标用新鲜 agent 反复尝试 | 程序化扇出/流水线 | 并行探索或实现 |
122
- | 工作单位 | mission(分支 + worktree + scope + 任务 + 审查) | 共享任务板上的任务/teammate | 轮次/尝试 | 脚本步骤/阶段 | 每个子代理一个 prompt/任务 |
125
+ | 主要目标 | 交付经门禁集成的仓库变更(可选独立审查) | 围绕共享目标协作 | 对同一目标用新鲜 agent 反复尝试 | 程序化扇出/流水线 | 并行探索或实现 |
126
+ | 工作单位 | mission(分支 + worktree + scope + 任务 + 可选审查) | 共享任务板上的任务/teammate | 轮次/尝试 | 脚本步骤/阶段 | 每个子代理一个 prompt/任务 |
123
127
  | 隔离 | 每 mission 独立 worktree/分支;单写入者 | 共享工作区;靠任务归属协调 | 每轮新 child;无内置分支/合并契约 | 每步 child;无 Git 隔离 | 子会话;可能共享工作区 |
124
128
  | 持久状态 | Git 元数据 + JSON state + 活动日志 + 看板 | Team 任务板 + 会话 | 很少;每轮从零开始 | 运行记录/结果;不是合并账本 | 会话/子代理记录 |
125
- | 集成权限 | 仅控制塔,且需审查 + 门禁 | 人类/teammate 手动合并或编辑 | 通常由父 agent/worker 应用结果 | 脚本应用结果 | 父 agent 应用结果 |
129
+ | 集成权限 | 仅控制塔,经 preflight/merge 门禁(可选再加审查) | 人类/teammate 手动合并或编辑 | 通常由父 agent/worker 应用结果 | 脚本应用结果 | 父 agent 应用结果 |
126
130
  | 审查/门禁 | 可选独立审查(`review.requireReview` 开启)+ preflight/merge 门禁 | 审查是协作约定,不是硬门禁 | 无内置审查门禁 | 无内置审查门禁 | 无内置审查门禁 |
127
131
  | 并行度 | 多 mission、互斥 scope、合并串行 | 多 teammate、共享任务板 | 顺序轮次(或外部扇出) | 高扇出,由脚本控制 | 高扇出 |
128
132
  | 人的角色 | 拥有模式;可检查证据与发布 | 协作者/协调者 | 重复目标的作者 | 编排脚本作者 | 委派者 |
@@ -133,33 +137,41 @@ Tower 是 Host 插件,只使用本地 Git、本地文件和 DSH subagent 服
133
137
 
134
138
  普通 `subagent`/`subagent_fork` 便宜灵活,适合"并行读五个文件"或"试三种方案"。它们不提供写范围、专用 worktree、持久 mission、独立审查或合并门禁。Tower 用这些契约包装同一个子代理原语,因此每个 child 更贵。
135
139
 
136
- 只读、短生命周期、或你准备自己集成结果时,用普通子代理;结果必须落到分支并经过审查时,用 Tower。
140
+ 只读、短生命周期、或你准备自己集成结果时,用普通子代理;结果必须落到分支并经受控合并时,用 Tower;需要独立审查时再开启 `review.requireReview`。
137
141
 
138
142
  ### 4.2 Tower vs Agent Teams
139
143
 
140
144
  Agent Teams 是**协作**模式:共享任务板、持久 teammate、消息、wait/interrupt,以及人类/Lead 协调。它适合横切、探索性或需要多视角的工作,且集成决定通常由人类做。
141
145
 
142
- Tower 是**交付**模式:mission 契约、Git 隔离、审查与硬合并门禁。它的点对点协作更少、结构更多。Agent Teams 可以决定"做什么、是否继续";Tower 可以把决定执行成 mission。二者应顺序或互补,而非并发:Tower 模式会拒绝 Team 任务板工具,避免两套协议争抢同一会话。
146
+ Tower 是**交付**模式:mission 契约、Git 隔离、可选审查门禁与硬合并门禁。它的点对点协作更少、结构更多。Agent Teams 可以决定"做什么、是否继续";Tower 可以把决定执行成 mission。二者应顺序或互补,而非并发:Tower 模式会拒绝 Team 任务板工具,避免两套协议争抢同一会话。
143
147
 
144
148
  ### 4.3 Tower vs Ralph 循环
145
149
 
146
150
  Ralph 用新鲜 agent 一轮轮执行**同一目标**,以工作区为长期记忆。它适合迭代搜索、修复 flaky、以及"换上下文再试一次"。它没有 mission 契约、独立审查或合并门禁。
147
151
 
148
- Tower 是增量的:每个 mission 有边界清晰的交付物,并经审查落地。如果问题是"我不知道能不能做成,反复新鲜尝试也许能找到路",Ralph 往往更合适;如果问题是"我知道切片,需要安全地构建并集成",Tower 更合适。可以在 Tower 模式之外先用 Ralph 找到方案,再把结果编码成 Tower mission。
152
+ Tower 是增量的:每个 mission 有边界清晰的交付物,并经合并门禁落地(开启审查时再经审查)。如果问题是"我不知道能不能做成,反复新鲜尝试也许能找到路",Ralph 往往更合适;如果问题是"我知道切片,需要安全地构建并集成",Tower 更合适。可以在 Tower 模式之外先用 Ralph 找到方案,再把结果编码成 Tower mission。
149
153
 
150
154
  ### 4.4 Tower vs Workflow 编排
151
155
 
152
156
  Workflow 是**程序化编排**:JS 脚本把工作扇出到许多 subagent,带阶段、pipeline 与结构化结果。它适合审计、批量迁移、多角度研究与对抗性验证。它不为每一步提供 Git worktree、审查结论或合并门禁。
153
157
 
154
- Tower 是**仓库交付协议**,mission 数量少,不是高扇出数据平面。用 Workflow "并行分析 200 个文件";用 Tower "把分析证明需要的 6 个修改,经审查与门禁合入"。Tower 模式会拒绝 Workflow,避免脚本在 Tower 契约下制造竞争写入。
158
+ Tower 是**仓库交付协议**,mission 数量少,不是高扇出数据平面。用 Workflow "并行分析 200 个文件";用 Tower "把分析证明需要的 6 个修改,经可选审查与合并门禁落地"。Tower 模式会拒绝 Workflow,避免脚本在 Tower 契约下制造竞争写入。
155
159
 
156
160
  ### 4.5 Tower vs Plan mode
157
161
 
158
162
  Plan mode 决定做什么;Tower 把已决定的计划执行到仓库。进入 Tower 会清除活跃 plan(`mode.planModePolicy:"refuse"` 时拒绝进入),且 Tower 会话不能使用 goal/todo/team/workflow 工具。先规划,再执行;不要指望 Tower 替你发现计划。
159
163
 
160
- ### 4.6 各工作流的具体例子
164
+ ### 4.6 审查默认可选
161
165
 
162
- **Tower** —— 输出是必须经过隔离与审查才能落地的仓库变更:
166
+ `review.requireReview:false` 是默认值,因此低风险仓库、临时工作或人类逐轮监督的会话可以在没有
167
+ reviewer 时合并已完成 mission。设为 `true` 才启用强制独立审查门禁;此时检查 `no-review`、
168
+ `not-clean`、`review-hold`、`review-not-approved`、`tip-moved`、`review-mission-mismatch`。
169
+ `tower_review` 始终可用并记录结论。只豁免单个 mission 时,在全局开启的前提下用
170
+ `reviewPolicy:"none"` + 理由 + `gates.allowReviewExemption:true`。
171
+
172
+ ### 4.7 各工作流的具体例子
173
+
174
+ **Tower** —— 输出是必须经过隔离与合并门禁落地的仓库变更(可选独立审查):
163
175
 
164
176
  - **OAuth 登录**:四个 mission(`token 模型`、`callback 路由`、`接受/拒绝 API`、`UI`);API 依赖 token 与邮件。
165
177
  - **Node 18 → 22 升级**:先 survey 破坏性 API,再拆 codemod、测试更新、CI 配置、release notes 为独立 mission。
@@ -199,17 +211,9 @@ Plan mode 决定做什么;Tower 把已决定的计划执行到仓库。进入
199
211
 
200
212
  1. Workflow 审计 200 个文件 → 结构化 findings。
201
213
  2. Agent Teams 评审 findings,决定前六个改动。
202
- 3. Tower mission 实现这六个改动,经审查与合并落地。
214
+ 3. Tower mission 实现这六个改动,经可选审查与合并门禁落地。
203
215
  4. 合并后仍有一个顽固 flaky 测试、且不需要新 mission 契约时,再用 Ralph。
204
216
 
205
- ### 4.7 审查默认可选
206
-
207
- `review.requireReview:false` 是默认值,因此低风险仓库、临时工作或人类逐轮监督的会话可以在没有
208
- reviewer 时合并已完成 mission。设为 `true` 才启用强制独立审查门禁;此时检查 `no-review`、
209
- `not-clean`、`review-hold`、`review-not-approved`、`tip-moved`、`review-mission-mismatch`。
210
- `tower_review` 始终可用并记录结论。只豁免单个 mission 时,在全局开启的前提下用
211
- `reviewPolicy:"none"` + 理由。
212
-
213
217
  ## 5. 具体场景示例
214
218
 
215
219
  ### 场景 A:四切片特性
@@ -219,24 +223,24 @@ reviewer 时合并已完成 mission。设为 `true` 才启用强制独立审查
219
223
  1. 规划四个 build mission,scope 分别 `src/tokens/**`、`src/email/**`、`src/api/invites/**`、`src/ui/invites/**`;让 API 依赖 token 与 email。
220
224
  2. 对独立 mission 启动 worker;API 等依赖完成。
221
225
  3. 每个 worker 在自己分支提交,带 checks 完成。
222
- 4. 启动 reviewer;要求 clean + merge。
226
+ 4. 若开启 `review.requireReview:true`,启动 reviewer 并要求 clean + merge;否则审查可选。
223
227
  5. 逐 mission `tower_preflight` + `tower_merge`,处理 scope/base/review blocker。
224
228
  6. `tower_teardown`;`MISSIONS.md` 是人类可读记录。
225
229
 
226
- **为什么不用 Team/Workflow?** 这是已知的仓库变更集合,需要按顺序落地并独立审查。Team 任务板不隔离写入;Workflow 会分析但不会门禁合并。
230
+ **为什么不用 Team/Workflow?** 这是已知的仓库变更集合,需要按顺序经受控合并落地(可选独立审查)。Team 任务板不隔离写入;Workflow 会分析但不会门禁合并。
227
231
 
228
232
  ### 场景 B:带 survey 的迁移
229
233
 
230
234
  1. Survey mission:"映射 `oldApi` 的所有调用者",scope 为空,只读。
231
235
  2. Build mission:codemod、测试更新、文档;依赖 survey 结果。
232
- 3. Reviewer 对照 survey 检查 diff;被审查 tip 的测试必须通过。
236
+ 3. 开启审查时,Reviewer 对照 survey 检查 diff;测试门禁仍校验当前分支 tip。默认审查可选时,可跳过 reviewer,仍受门禁/测试约束。
233
237
  4. 按依赖顺序合并。
234
238
 
235
- **为什么不用普通子代理?** survey 不能误改;codemod 不能越界;审查必须绑定精确提交。
239
+ **为什么不用普通子代理?** survey 不能误改;codemod 不能越界;开启审查时,审查必须绑定精确提交。
236
240
 
237
241
  ### 场景 C:事故 hotfix
238
242
 
239
- 生产一行修复。用普通 agent,按你正常的提交/推送流程处理。Tower 会额外增加 worktree、reviewer、门禁与合并步骤;对一行紧急修复主要是延迟。如果"hotfix"实际是多个协调变更,Tower 才合理。
243
+ 生产一行修复。用普通 agent,按你正常的提交/推送流程处理。Tower 会额外增加 worktree、合并门禁与(开启时)reviewer;对一行紧急修复主要是延迟。如果"hotfix"实际是多个协调变更,Tower 才合理。
240
244
 
241
245
  ### 场景 D:大范围代码审计
242
246
 
@@ -244,22 +248,22 @@ reviewer 时合并已完成 mission。设为 `true` 才启用强制独立审查
244
248
 
245
249
  ### 场景 E:敏感发布
246
250
 
247
- 有外部用户的库发布。为变更、迁移指南、release notes 规划 mission;要求测试与审查;用 `tower_batch` 只有在所有必需检查齐全时才收口发布证据;按你的发布流程在 Tower 之外合并/打 tag。
251
+ 有外部用户的库发布。为变更、迁移指南、release notes 规划 mission;如发布需要独立审查,开启 `review.requireReview:true`;要求测试,并用 `tower_batch` 只有在所有必需检查齐全时才收口发布证据;按你的发布流程在 Tower 之外合并/打 tag。
248
252
 
249
253
  ## 6. 实践中的选择路径
250
254
 
251
255
  1. **输出是 Git 变更吗?** 否 → 普通 agent、Agent Teams、Workflow 或 Ralph。
252
256
  2. **你会为它开 PR 吗?** 否 → Tower 太重,用普通 agent。
253
257
  3. **切片有稳定 scope 和已知完成定义吗?** 否 → 先规划/探索,再回到 Tower。
254
- 4. **需要独立审查与合并门禁吗?** 是 → Tower;否,普通子代理可能足够。
258
+ 4. **需要合并门禁吗?** 有集成风险的仓库变更 → Tower;如果还需要独立审查,开启 `review.requireReview:true`。两者都不需要时,普通子代理可能足够。
255
259
  5. **需要大量并行分析或重复新鲜尝试吗?** 那个阶段用 Workflow/Ralph;把结果编码成 Tower mission。
256
260
  6. **需要横切的人类协作吗?** 用 Agent Teams 决定;用 Tower 执行决定的仓库工作。
257
261
 
258
262
  ## 7. 成本、限制与反模式
259
263
 
260
- - **每个 mission 有真实开销**:worktree、spawn、完成检查、审查轮次、门禁、合并。mission 应有意义(大致 PR 大小),不要一个函数一个 mission。
264
+ - **每个 mission 有真实开销**:worktree、spawn、完成检查、可选审查轮次、门禁、合并。mission 应有意义(大致 PR 大小),不要一个函数一个 mission。
261
265
  - **合并会串行**:重叠 scope 自动加依赖;独立 mission 仍然逐个合入 base。合并密集的工作不要期待线性加速。
262
- - **审查不是免费**:每个 mission 需要 reviewer 与 clean 结论;豁免是显式开启且需要理由,不是默认。
266
+ - **审查不是免费的(开启时)**:每个 mission 需要 reviewer 与 clean 结论;`review.requireReview:false`(默认)让审查可选;开启后豁免是显式且需要理由。
263
267
  - **过细的 mission** 增加协调与合并成本;**过粗的 mission** 失去并行审查收益,scope 冲突概率高。
264
268
  - **Tower 不是沙箱**:它是协调协议;Host 权限、仓库 hooks、测试命令仍以 DSH 用户的 OS 权限执行。
265
269
  - **不要同时跑两套编排协议**:Tower 模式会拒绝 Team/Workflow/Ralph/subagent 工具并清除 plan mode;请顺序分阶段。
@@ -269,9 +273,10 @@ reviewer 时合并已完成 mission。设为 `true` 才启用强制独立审查
269
273
 
270
274
  - [ ] 工作会产生值得 PR 式审查的仓库变更。
271
275
  - [ ] 我能列出 2–8 个 scope 不重叠、依赖顺序大致的 mission。
272
- - [ ] 每个 mission 有可测试的完成定义(任务、checks/测试、审查)。
276
+ - [ ] 每个 mission 有可测试的完成定义(任务、checks/测试、可选审查)。
277
+ - [ ] 如果这次变更需要独立审查,已开启 `review.requireReview`(默认关闭)。
273
278
  - [ ] 我知道哪些 mission 可并行、哪些必须等待。
274
- - [ ] 我接受审查/合并开销,并会检查 `MISSIONS.md`/分支。
279
+ - [ ] 我接受合并门禁开销(以及开启审查时的审查开销),并会检查 `MISSIONS.md`/分支。
275
280
  - [ ] 当前没有在同一会话依赖 Team 任务板、Workflow 脚本、Ralph 循环或 plan mode。
276
281
  - [ ] 如果 worker 卡住(interrupt/adopt)或合并冲突,我有恢复路径。
277
282
 
@@ -6,9 +6,9 @@ Tower 提供的是**协作层面的保证**,不是沙箱。需要理解哪些
6
6
 
7
7
  ## 由插件强制执行的约束
8
8
 
9
- - **审查绑定。** `tower_review` 会记录它检查的分支 tip;tip 变化后门禁会拒绝(`tip-moved`),除非
10
- 一次干净且无冲突的 rebase 给予了豁免。reviewer 在 spawn 之后修改分支会被拒绝
11
- (`reviewer must not modify the mission branch`)。
9
+ - **审查绑定(开启审查时)。** `tower_review` 会记录它检查的分支 tip;开启 `review.requireReview` 后
10
+ tip 变化会被门禁拒绝(`tip-moved`),除非一次干净且无冲突的 rebase 给予了豁免。reviewer 在 spawn
11
+ 之后修改分支会被拒绝(`reviewer must not modify the mission branch`)。
12
12
  - **审查默认可选,可配置强制。** `review.requireReview:false` 是默认值;设为 `true` 才启用独立审查
13
13
  门禁。全局开启时,mission 级 `reviewPolicy:"none"` + 理由是更窄的豁免。关闭门禁时插件不强制职责
14
14
  分离;只应用于可信仓库或有人类监督的会话。
@@ -19,26 +19,62 @@ Tower 提供的是**协作层面的保证**,不是沙箱。需要理解哪些
19
19
  - **只读 reviewer preset。** `tower-reviewer` preset 从工具面移除 `write`、`edit`、`pwsh`、
20
20
  `tower_mission` 与 `tower_complete`;reviewer 只能读、看 diff、发消息、记录 finding 和提交审查。
21
21
  - **Scope 门禁。** mission 只能修改其声明 scope glob 匹配的文件;越界改动会阻止合并。
22
- - **Worktree 隔离。** worker 在独立 worktree 与分支上工作;主检出只会被 merge/teardown 触及。
23
- - **人类掌握模式。** `/tower` 归用户所有。开启 `mode.allowAgentControl` 后模型可以切换,但必须
24
- 给出理由;随包 patch 默认开启——设为 `false` 可让模式只由人类控制。
22
+ - **模式控制显式且可配置。** `/tower` 始终可用。`mode.allowAgentControl:true`(默认)时,模型也可以
23
+ 带必填理由用 `tower_control` 进出;每次变更记录操作者与理由。设为 `false` 则仅人类可控制模式。
24
+ 重点是变更可归因,而不是固定由某一方拥有。
25
25
  - **不自动恢复 goal。** 进入模式会暂停活跃 goal;退出时不会恢复它。
26
26
  - **建议性 workspace 锁。** `mode.workspaceLock` 防止两个 Tower 会话意外驱动同一个仓库;它是同用户
27
27
  之间的协调锁,不是用户间的认证机制。
28
28
 
29
+ ## 仓库保护
30
+
31
+ 本节描述的是**本仓库**,不是 Tower 所操作的仓库。服务端分支保护不是插件功能——Tower 只写入本地基线分支,无法配置远端——但 `dsh-tower` 为自己的 `main` 开启了保护,因为门禁代码本身也是攻击者最想修改的代码:
32
+
33
+ - `main` 的所有变更都必须经过 pull request,且**对 admin 同样生效**,因此维护者也无法直接 push。
34
+ - 必需检查为 `test (22)`、`test (24)` 与 `mount`。mount 任务会打包压缩包并在一次性 profile 中启动,所以“测试通过”不能把一个安装后不出现的 bundle 合入。
35
+ - 禁止 force-push 与删除分支,已发布 tag 的历史不能被改写。
36
+ - 不要求强制审批:只有一个维护者时,自我审批只是橡皮图章。替代它的是 two-key 路径的四行 PR 正文(failure mode、change、test、blast radius),见 [CONTRIBUTING.md](../../../CONTRIBUTING.md#landing-changes)。
37
+
38
+ 它带来的保证:未经验证的变更无法进入 `main`,必需检查变红或缺失时连所有者也不能绕过,历史只追加。它**不**提供:第二个审阅者、对泄露的维护者 token 的防护,或对 Tower 所操作仓库的任何保护——那些仍是部署关注点。设置、理由与校验命令记录在 [SECURITY.md](../../../SECURITY.md#repository-protection-on-main)。
39
+
40
+ ## 模型主动进入模式的威胁模型
41
+
42
+ `mode.allowAgentControl:true` 意味着仓库文件、issue 文本或抓取页面中的提示注入可以让模型“进入
43
+ Tower 模式并修复它”。Tower **不认证**这句话背后的人类意图。它提供的是:
44
+
45
+ - 进入会记录操作者、动作、理由与时间;`tower_status.mode.history` 直接展示最近的模式切换,
46
+ 不必手工 grep 活动日志;
47
+ - 模型不能绕过 preflight 门禁、review policy、scope、测试与 clean-base 检查;自己写 plan 也不会
48
+ 自动获得合并权;
49
+ - worker 的工具面受限并被要求留在 worktree,但主检出保护来自 scope/merge 检查与 preset,
50
+ **不是** OS 沙箱;
51
+ - `mode.workspaceLock` 防止第二个 Tower 会话驱动同一仓库。
52
+
53
+ 它**不**防御:完全通过所有门禁但被恶意指令操纵的模型;仓库自己声明的 hooks/测试命令;或无视
54
+ 指令、通过 shell 访问 worktree 之外文件的 worker。更高保证的团队应设
55
+ `mode.allowAgentControl:false`、保持 `review.requireReview:true`、在运行 Tower 前审查仓库,并用
56
+ OS 级隔离运行 host。
57
+
29
58
  ## 不由插件强制执行的约束(部署关注点)
30
59
 
60
+ - **Worktree 隔离是协议约定,不是 OS 沙箱。** worker 会被分配独立 worktree/分支并被要求留在其中,但
61
+ `tower-worker` preset 仍包含 `pwsh`、`write`、`edit`;这些工具可写绝对路径或在主检出执行 Git。
62
+ scope 门禁检查的是提交后的分支 diff,不是文件系统访问。硬隔离需要容器、独立 OS 用户或受限的 host
63
+ 工具策略。
31
64
  - **沙箱。** Host 插件运行在文件系统沙箱之外;reviewer 的 shell 能力是在工具面层面移除的,但底层
32
65
  进程仍拥有 DSH 的 OS 权限。需要硬隔离的部署必须自行限制进程/用户。
33
66
  - **reviewer 信任。** 审查是 reviewer agent/模型给出的背书;插件能把它绑定到提交,但无法证明
34
67
  reviewer 真的推理正确。高价值分支建议使用独立模型/角色。
35
68
  - **仓库钩子。** `git merge` 会运行目标仓库的钩子(`pre-merge-commit` 等)。Tower 无法让这些钩子
36
69
  变安全;在不受信任的仓库上运行 Tower 前请先审查钩子。
70
+ - **测试发现是仓库代码。** `tests.admission` 默认 `off`,只有显式 `tower_test` 才会执行仓库
71
+ `package.json` 的 `tower.testDiscovery` 命令;该命令以 DSH 的 OS 权限运行,不是沙箱。不可信仓库应
72
+ 设 `tests.allowPackageDiscovery:false`。
37
73
  - **HMR 重载。** 开启 `dev.hotReload` 时,`/tower reload`/`tower_reload` 会让 DSH 从磁盘重新导入
38
74
  插件。只为你信任的检出配置 HMR 监视 root;重载会执行这些文件当前的代码。
39
75
  - **提示注入。** reviewer 会读取不受信任的分支内容(diff/评论)。只读 preset 限制了影响面,但模型侧
40
76
  没有绝对防护。
41
- - **基线分支保护。** Tower 会写入本地基线分支;服务端的 branch protection/push 规则不属于本插件。
77
+ - **基线分支保护。** Tower 会写入本地基线分支;服务端 branch protection/push 规则不属于本插件。本仓库自身 `main` 的保护见[仓库保护](#仓库保护);为你运行 Tower 的仓库开启同等保护仍属于部署关注点。
42
78
 
43
79
  ## 报告问题
44
80
 
@@ -3,14 +3,14 @@
3
3
  [English](../../reference/blockers.md) | **简体中文**
4
4
 
5
5
  `tower_preflight` 返回 `{ok:false, blockers:[{code, detail}]}`。`tower_merge` 与 `tower_rebase`
6
- 在操作失败时返回相同结构。code 稳定;detail 面向人。
6
+ 在操作失败时返回相同结构。code 稳定;detail 面向人。下表共定义 32 个稳定 blocker/failure code。
7
7
 
8
8
  ## 门禁 blocker(26 个)
9
9
 
10
10
  | Code | 含义 / 下一步 |
11
11
  |---|---|
12
12
  | `mission-missing` | 未知 mission id。用 `tower_status` 查看。 |
13
- | `mission-not-completed` | mission 不是 `completed`;只有 `completed`(等待审查)的 mission 才能合并。 |
13
+ | `mission-not-completed` | mission 不是 `completed`;只有 `completed`(可进入 preflight/合并)的 mission 才能合并。 |
14
14
  | `tasks-open` | 仍有未完成任务;worker 必须先完成,或带理由 `task_drop`。 |
15
15
  | `blockers-present` | mission 仍有 blocker;解决后清除。 |
16
16
  | `no-check-evidence` | 启用了 `gates.requireChecks` 且完成报告没有 `checks`。把 completed mission 退回 `active`,带 checks 重新调用 `tower_complete`,然后重新审查。 |
@@ -20,20 +20,20 @@
20
20
  | `out-of-scope` | 改动文件超出 mission scope;有意为之就扩大 scope,否则回退。 |
21
21
  | `base-dirty` | 主检出存在未提交改动,合并会覆盖它们。 |
22
22
  | `deps-unmerged` | 依赖 mission 尚未 merged/abandoned。 |
23
- | `no-review` | 分支上没有审查:spawn reviewer。 |
24
- | `review-mission-mismatch` | 最新审查属于另一个 mission。 |
25
- | `not-clean` | 最新审查是 `p1-Nitems`/`p2-Nitems`;需要再来一轮。 |
26
- | `review-hold` | 最新审查建议 hold;必须由后续的干净审查取代。 |
27
- | `review-not-approved` | 最新干净审查给出的是 `fix-then-merge` 或 `hold`;只有 `merge` 才算批准。 |
28
- | `tip-moved` | 审查之后分支发生变化;重新审查(或使用干净 rebase 的免审豁免)。 |
23
+ | `no-review` | `review.requireReview:true` 且分支上没有审查:spawn reviewer(或关闭审查门禁)。 |
24
+ | `review-mission-mismatch` | `review.requireReview:true` 且最新审查属于另一个 mission。 |
25
+ | `not-clean` | `review.requireReview:true` 且最新审查是 `p1-Nitems`/`p2-Nitems`;需要再来一轮。 |
26
+ | `review-hold` | `review.requireReview:true` 且最新审查建议 hold;必须由后续的干净审查取代。 |
27
+ | `review-not-approved` | `review.requireReview:true` 且最新干净审查给出的是 `fix-then-merge` 或 `hold`;只有 `merge` 才算批准。 |
28
+ | `tip-moved` | `review.requireReview:true` 且审查之后分支发生变化;重新审查(或使用干净 rebase 的免审豁免)。 |
29
29
  | `worker-busy` | 该 mission 的 roster agent 正在运行;等待或让其退役。 |
30
30
  | `worker-status-unknown` | 父目录不可用,无法证明 live roster agent 已停止;等目录恢复后重试,或先 adopt。 |
31
31
  | `base-wrong-branch` | 主检出不在记录的基线分支上。 |
32
32
  | `branch-owned-by-closed-missions` | mission 已 merged/abandoned;用新标题重新 plan。 |
33
33
  | `worker-stale` | 该 mission 的 roster worker 超过 `spawn.staleMs` 没有目录活动;合并前 adopt(只有确实还在运行时才 interrupt)。 |
34
- | `tests-missing` | 启用了 `gates.requireTests` 且没有针对被审查 tip 的通过测试回执;运行 `tower_test` 或 `tower_complete`。 |
34
+ | `tests-missing` | 启用了 `gates.requireTests` 且没有针对当前分支 tip 的通过测试回执;运行 `tower_test` 或 `tower_complete`。 |
35
35
  | `tests-failed` | 最新测试发现回执失败,或不满足 minCount/required 检查。修复测试并重跑。 |
36
- | `review-exemption-invalid` | mission 请求 `reviewPolicy:"none"`,但 `gates.allowReviewExemption` 关闭(或缺少理由)。 |
36
+ | `review-exemption-invalid` | `review.requireReview:true` 且 mission 请求 `reviewPolicy:"none"`,但 `gates.allowReviewExemption` 关闭(或缺少理由)。 |
37
37
  | `merge-intent-pending` | 崩溃/失败前记录了合并意图;先运行 `tower_merge` 对账,再进行其他门禁。 |
38
38
 
39
39
  ## 合并失败(4 个)
@@ -22,7 +22,7 @@ merge、worktree 与 spawn 策略。它使用与 profile 配置相同的 JSON
22
22
 
23
23
  ```json
24
24
  {
25
- "review": { "maxRoundsPerReviewer": 3 },
25
+ "review": { "requireReview": true, "maxRoundsPerReviewer": 3 },
26
26
  "merge": { "timeoutMs": 1800000 },
27
27
  "worktrees": { "root": "D:/tower-worktrees" },
28
28
  "spawn": { "reviewerPreset": "tower-reviewer", "maxDepth": 2 }
@@ -37,14 +37,16 @@ merge、worktree 与 spawn 策略。它使用与 profile 配置相同的 JSON
37
37
  | 键 | 默认值 | 含义 |
38
38
  |---|---|---|
39
39
  | `section` | `''` | 兼容别名:替换整段 Tower 模式提示文案。空值保留内置提醒。 |
40
- | `allowAgentControl` | `false`(随包 patch:`true`) | 兼容别名:注册 `tower_control`。 |
40
+ | `allowAgentControl` | `true`(`mode.allowAgentControl` 的别名) | 兼容别名:注册 `tower_control`,允许模型切换模式。 |
41
41
  | `init.autoGitInit` | `false`(随包 patch:`true`) | 当 `repoRoot` 是绝对、已存在但不是仓库的目录时,`tower_init` 可以执行 `git init` 并创建一个空的初始提交。 |
42
42
  | `init.snapshotDirty` | `false` | `tower_init` 可以把未提交的**已跟踪**改动快照为游离提交作为 mission 基线(不含未跟踪文件;该提交通过 `refs/tower/snapshot/*` 保持存活)。 |
43
+ | `init.autoExclude` | `true` | 把仓库内产物(`MISSIONS.md`、仓库内 worktree root)追加到 `.git/info/exclude`;绝不修改 `.gitignore`。 |
43
44
  | `mode.promptSection` | `''` | 替换用的提示文案(与 `section` 同时设置时优先)。 |
44
45
  | `mode.sectionAppend` | `''` | 追加在提醒之后的额外文本(团队约定)。 |
45
- | `mode.allowAgentControl` | `false` | 注册 `tower_control`;模型可带理由进入/退出。 |
46
+ | `mode.allowAgentControl` | `true` | 注册 `tower_control`;模型可带理由进入/退出。设为 `false` 则仅人类可控制模式。 |
46
47
  | `mode.autoPauseGoal` | `true` | 进入模式时暂停活跃 goal;退出时不会自动恢复。 |
47
48
  | `mode.requireResumeAuthorization` | `false` | 恢复因 `pauseCause:user` 暂停的 mission 时,必须提供 `authorization` 引用。 |
49
+ | `mode.requireHumanAckOnFirstEntry` | `false` | 要求人类先执行 `/tower ack`,模型才能在当前会话首次进入 Tower 模式。 |
48
50
  | `mode.workspaceLock` | `false`(随包 patch:`true`) | 每个仓库只允许一个 Tower 会话(`tower.lock`);其他会话得到 `workspace-busy`。 |
49
51
  | `mode.workspaceLockScope` | `all` | `all` 锁定所有仓库工具;`mutations` 对只读工具跳过 workspace 锁。 |
50
52
  | `mode.planModePolicy` | `clear` | 进入 Tower 模式会清除活跃的 plan mode(或 `refuse` 直到退出计划);前置步骤也会清除稍后激活的计划。 |
@@ -57,6 +59,7 @@ merge、worktree 与 spawn 策略。它使用与 profile 配置相同的 JSON
57
59
  | `review.maxRoundsPerReviewer` | `5` | 每个 reviewer 对每条分支的审查轮数上限。 |
58
60
  | `merge.timeoutMs` | `900000`(15 分钟) | `tower_merge` 默认超时,包含钩子;单次调用的 `timeoutMs` 优先。 |
59
61
  | `merge.maxBufferBytes` | `67108864`(64 MB) | 合并输出缓冲区。 |
62
+ | `git.timeoutMs` | `15000` | 除 merge 外 Git 命令的默认超时;merge 使用 `merge.timeoutMs`。 |
60
63
  | `worktrees.root` | `''` | 默认 worktree 父目录;空值推导为 `<主检出父目录>/.dsh-tower-worktrees/<hash>`。 |
61
64
  | `spawn.workerPreset` | `tower-worker` | `role=worker` 使用的 preset。 |
62
65
  | `spawn.reviewerPreset` | `tower-reviewer` | `role=reviewer` 使用的 preset。 |
@@ -71,20 +74,21 @@ merge、worktree 与 spawn 策略。它使用与 profile 配置相同的 JSON
71
74
  | `send.maxPerMinute` | `120` | 每个仓库的 `tower_send` 每分钟速率限制(0 关闭);超出返回 `rate-limited`。 |
72
75
  | `send.interruptDefault` | `false`(随包 patch:`true`) | `tower_send.interrupt` 的默认值(投递前先中断运行中的回合)。 |
73
76
  | `tests.enabled` | `true` | worktree 的 `package.json` 配置了测试发现时运行它。 |
74
- | `tests.admission` | `complete` | `spawn` 在启动 worker 前运行发现(fail-closed,不启动子代理);`complete` 在 `tower_complete` 时运行;`off` 只在显式 `tower_test` 时运行。 |
77
+ | `tests.admission` | `off` | `spawn` 在启动 worker 前运行发现(fail-closed,不启动子代理);`complete` 在 `tower_complete` 时运行;`off` 只在显式 `tower_test` 时运行(默认;不会自动执行仓库代码)。 |
75
78
  | `tests.timeoutMs` | `60000` | 每条发现命令的超时。 |
76
79
  | `tests.maxBytes` | `16777216`(16 MiB) | 每条命令捕获的 stdout 上限。 |
77
80
  | `tests.autoChecks` | `true` | 向完成报告附加自动 `tests` 检查。 |
78
81
  | `tests.allowPackageDiscovery` | `true` | 允许仓库控制的 `tower.testDiscovery` 命令(会执行 worktree 代码;见安全页)。 |
79
82
  | `gates.requireChecks` | `false` | 合并前要求至少一条 `tower_complete.checks` 证据(`no-check-evidence`)。 |
80
- | `gates.requireTests` | `false` | 要求针对被审查 tip 的通过测试回执(`tests-missing`)。 |
81
- | `gates.allowReviewExemption` | `false` | 允许用 `reviewPolicy:"none"` + 理由跳过审查 blocker;默认故意关闭。 |
83
+ | `gates.requireTests` | `false` | 要求针对当前 mission 分支 tip 的通过测试回执(`tests-missing`);与审查门禁独立。 |
84
+ | `gates.allowReviewExemption` | `false` | 在 `review.requireReview:true` 时,允许用 `reviewPolicy:"none"` + 非空理由跳过审查 blocker;默认故意关闭;全局审查关闭时无影响。 |
82
85
  | `docs.board` | `true` | 变更后写入 `MISSIONS.md`。 |
83
86
  | `docs.boardLocation` | `common` | `common` = `<git-common-dir>/dsh-tower/MISSIONS.md`;`repo` = `<repoRoot>/MISSIONS.md`。 |
87
+ | `tools.exposeOperational` | `true` | 注册 batch/resource/import/legacy/recover/test/doctor 工具;`false` 可缩小固定工具 schema 上下文。 |
84
88
  | `leases.ttlMs` | `900000` | 默认咨询式租约寿命;过期不会自动释放。 |
85
89
  | `dev.hotReload` | `true` | 注册 `tower_reload`;关闭时 `/tower reload` 也被禁用。无 HMR 服务时调用返回 `reload-unavailable`。 |
86
90
  | `dev.reloadDelayMs` | `50` | 计划中的 reload 延迟,先让工具结果送达。 |
87
- | `dev.reloadRequiredIds` | 四个 Tower loader id | 作为 required 传给 `reconcileProfile` 的条目 id。 |
91
+ | `dev.reloadRequiredIds` | 五个 Tower loader id | 作为 required 传给 `reconcileProfile` 的条目 id。 |
88
92
 
89
93
  ## 示例
90
94
 
@@ -3,7 +3,7 @@
3
3
  [English](../../reference/errors.md) | **简体中文**
4
4
 
5
5
  工具失败是抛出的错误,不是 `{ok:false}` 结果(门禁结果是例外:见 [blockers.md](blockers.md))。
6
- 每个抛出的错误都以稳定 code 作为消息前缀:
6
+ 每个抛出的错误都以稳定 code 作为消息前缀。本版本定义 33 个工具错误码。
7
7
 
8
8
  ```
9
9
  [tower:mission-not-found] unknown mission "M9"
@@ -20,6 +20,8 @@
20
20
  | `mission-not-found` | 不存在该 id 的 mission。 | 过期或拼错的 `M9` |
21
21
  | `finding-not-found` | 不存在该 id 的 finding。 | `tower_findings({id:"F99"})` |
22
22
  | `invalid-transition` | 请求的状态转换不被允许。 | 尝试 blocked→merged;finding 状态图之外的流转;reviewer 修改 finding;在还有未完成任务、blocker、无提交或未读消息时完成 mission。 |
23
+ | `stale-base` | 操作准备期间仓库状态已变化,需要重试。 | two-phase mutation 重校验 |
24
+ | `worktree-dirty` | mission worktree 有未提交改动,不能完成。 | `tower_complete` 前遗留 staged/modified/untracked 文件 |
23
25
  | `state-locked` | 另一个 Tower 写入者持有 state 锁。 | 锁超时后的并发写 |
24
26
  | `state-corrupt` | Tower state 文件不可读或无效。 | 手工编辑过的 `state.json` |
25
27
  | `config-invalid` | Tower 配置无效。 | 格式错误的仓库 `config.json`、违反 schema 的值 |
@@ -28,6 +30,7 @@
28
30
  | `git-timeout` | git 命令超时或输出超出缓冲区。 | 慢 pre-merge 钩子、超大 diff |
29
31
  | `spawn-unavailable` | subagents 服务不可用。 | 没有 `subagents` 的 Host |
30
32
  | `provider-missing` | 没有注册的 subagent provider。 | provider 列表为空 |
33
+ | `provider-cooldown` | 连续可重试的 provider 失败后,spawn 进入短暂冷却。 | 等待 `blockedUntil` 后重试 |
31
34
  | `preset-missing` | 配置的 agent preset 未注册。 | 缺少 `tower-worker`/`tower-reviewer` preset 行、DSH 未重启 |
32
35
  | `reviewer-prerequisite` | reviewer spawn 的前置条件未满足。 | mission 尚未 `completed` 或还没有 worktree 就 spawn reviewer |
33
36
  | `not-authorized` | 调用方 agent 角色无权执行该操作。 | worker 调用仅限控制塔的工具,或修改 mission 状态/scope;reviewer 修改 finding |
@@ -3,7 +3,7 @@
3
3
  [English](../../reference/events.md) | **简体中文**
4
4
 
5
5
  Tower 在工具成功调用(变更与只读)后发出进程内 Cordis 事件,其他插件因此可以观察仓库,而不必轮询。
6
- 事件**不会**通过网络发送,也不包含遥测。
6
+ 本版本发出 29 个进程内事件。事件**不会**通过网络发送,也不包含遥测。
7
7
 
8
8
  ```js
9
9
  ctx.on('tower/merge', (payload) => {
@@ -33,14 +33,17 @@ ctx.on('tower/merge', (payload) => {
33
33
  | `tower/status` | `tower_status` 读取面板之后 |
34
34
  | `tower/preflight` | `tower_preflight` 评估门禁之后 |
35
35
  | `tower/doctor` | `tower_doctor` 完成只读检查之后 |
36
+ | `tower/recover` | `tower_recover` 查看或清理 stale state 锁之后 |
36
37
  | `tower/test` | `tower_test` 运行测试发现之后 |
37
38
  | `tower/batch` | `tower_batch` 创建、查看或关闭 batch 之后 |
38
39
  | `tower/resource` | `tower_resource` 获取/释放/查看租约之后 |
39
40
  | `tower/import_legacy` | `tower_import_legacy` 保存旧版快照之后 |
40
41
  | `tower/legacy_map` | `tower_legacy_map` 映射或列出旧 id 之后 |
42
+ | `tower/mode` | `tower_mode` 读取/变更会话模式之后(`value.mode`、`allowAgentControl`、`deniedWhileActive`) |
43
+ | `tower/control` | `tower_control` 进入/退出模式之后(`value.mode`,操作者/理由在 `value` 中) |
44
+ | `tower/reload` | `tower_reload` 返回重载调度/结果之后 |
41
45
 
42
- `tower_mode`、`tower_control` 与 `tower_reload` 不发出 Tower 事件。payload 是 JSON:
43
- `{tool, repoRoot, value}`。监听器抛错不会影响工具结果。
46
+ payload 是 JSON:`{tool, repoRoot, value}`。监听器抛错不会影响工具结果。
44
47
 
45
48
  需要可持久审计的调用链时,请使用 `<git-common-dir>/dsh-tower/activity.jsonl` 与 `MISSIONS.md`;
46
49
  事件是进程内的,不会重放。
@@ -49,8 +49,9 @@ stdout/stderr 文件、SHA-256 哈希、退出码、计数、required 名称、w
49
49
 
50
50
  - `tower_test({repoRoot,missionId})` 按需运行发现并记录回执。
51
51
  - `tests.autoChecks` 开启时,`tower_complete` 会添加一条 `tests` 检查。
52
- - `gates.requireChecks` 要求任意完成检查;`gates.requireTests` 要求针对被审查 tip 的通过回执
53
- (`tests-missing`)。
52
+ - `gates.requireChecks` 要求任意完成检查;`gates.requireTests` 要求针对当前 mission 分支 tip 的
53
+ 通过回执(`tests-missing`)。测试门禁与审查独立:即使 `review.requireReview:false`,测试门禁仍
54
+ 检查分支 tip。
54
55
 
55
56
  ## 信任边界
56
57
 
@@ -3,9 +3,9 @@
3
3
  [English](../../reference/tools.md) | **简体中文**
4
4
 
5
5
  所有工具都接受 `repoRoot`(目标 Git 仓库内的绝对路径)并返回 JSON。
6
- 本构建最多 28 个工具:下列 19 个核心仓库工具(含 `tower_interrupt`)、`tower_mode`、
7
- `mode.allowAgentControl` 开启时注册的 `tower_control`、`dev.hotReload` 开启时注册的
8
- `tower_reload`,以及 2.1 的验证/运维工具 `tower_doctor`、`tower_test`、`tower_batch`、
6
+ 本构建最多 29 个工具:下列 19 个核心仓库工具(含 `tower_interrupt`)、`tower_mode`、默认注册的
7
+ `tower_control`(设 `mode.allowAgentControl:false` 可禁用)、`dev.hotReload` 开启时注册的
8
+ `tower_reload`,以及 2.1 的验证/运维工具 `tower_doctor`、`tower_recover`、`tower_test`、`tower_batch`、
9
9
  `tower_resource`、`tower_import_legacy`、`tower_legacy_map`。
10
10
 
11
11
  `tower_mission` 使用 `id`(别名 `missionId`);其他所有 mission 级工具使用 `missionId`
@@ -32,16 +32,16 @@ roster 角色由 `exec.agent` 与 roster 共同决定。mission 级工具(`tow
32
32
  | 工具 | 参数 | 用途 / 说明 |
33
33
  |---|---|---|
34
34
  | `tower_init` | `base?`、`autoGitInit?`、`snapshotDirty?`、`reanchor?` | 创建 `<git-common-dir>/dsh-tower/state.json`。`autoGitInit` 执行 `git init` 并创建空的初始提交;`snapshotDirty` 记录一个游离快照提交作为 mission 基线;`reanchor` 仅在没有非终态 mission 时修改基线。返回 `dirty`、`snapshotCommit`、`reanchored`。 |
35
- | `tower_plan` | `missions[]`(`title`、`scope[]`、`tasks[]?`、`deps[]?`、`kind?`、`context?`、`references[]?` ≤20、`reviewPolicy?`、`reviewExemptionReason?`) | 创建 mission `M1..`;重叠的 build scope 会自动加依赖;拒绝未知依赖与依赖循环。`reviewPolicy:"none"` 需要理由,并且要求 `gates.allowReviewExemption`。 |
35
+ | `tower_plan` | `missions[]`(`title`、`scope[]`、`tasks[]?`、`deps[]?`、`kind?`、`context?`、`references[]?` ≤20、`reviewPolicy?`、`reviewExemptionReason?`) | 创建 mission `M1..`;重叠的 build scope 会自动加依赖;拒绝未知依赖与依赖循环。`reviewPolicy:"none"` 需要非空理由;审查门禁开启时,preflight 还要求 `gates.allowReviewExemption`。 |
36
36
  | `tower_mission` | `id`(别名 `missionId`)、`status?`、`task_done?`、`task_drop?`+`task_drop_reason?`、`blocker?`、`clear_blockers?`、`note?`、`scope?`、`pause_cause?`、`authorization?` | 更新单个 mission。worker 可安全使用的字段是 task/blocker/note;不能在这里设置 `merged`。暂停的 mission 记录 `pause_cause`(user/failure/resource/dependency);恢复用户暂停的 mission 会遵循 `mode.requireResumeAuthorization`。 |
37
- | `tower_status` | `missionId?`、`offset?`、`limit?`、`includeGate?`、`format?` | 默认返回面板。`missionId` 返回完整详情(任务/备注/审查/finding/完成报告)。`offset`/`limit` 对 mission 分页(默认 20,最大 100),`includeGate` 附带门禁摘要,`format:"markdown"` 返回看板。 |
37
+ | `tower_status` | `missionId?`、`offset?`、`limit?`、`includeGate?`、`format?` | 默认返回面板。`missionId` 返回完整详情(任务/备注/审查/finding/完成报告)。`offset`/`limit` 对 mission 分页(默认 20,最大 100),`includeGate` 附带门禁摘要,`format:"markdown"` 返回看板。host 提供 mode hook 时还会包含 `mode.lastChange` 与最近 `history`。 |
38
38
  | `tower_spawn` | `missionId`(别名 `id`)、`role`(`worker`/`reviewer`)、`name?`、`instructions?`、`worktreeRoot?`、`wait?`、`waitMs?`、`takeover?`、`includeDirtyBase?` | 准备或复用 worktree 并启动子代理。worker 使用 `tower-worker`;reviewer 要求 mission 为 `completed`,并使用只读的 `tower-reviewer`。`takeover:true` 替换已不再运行的 worker 条目(ownerGeneration 递增)。每个 mission 只能有一个活跃 worker;`spawn.maxLiveWorkers` 限制整个仓库。 |
39
39
  | `tower_roster` | — | roster 及来自子代理目录的实时活动(`running`/`inactive`/`missing`/`unknown`)与 `stale` 标记。只读。 |
40
40
  | `tower_adopt` | `retireMissing?` | 把 roster 条目与持久子代理目录对账。可证明已消失的 agent 会被标记为 retired(默认),或标记为 `missing`(`retireMissing:false`)以便检查/接管。 |
41
41
  | `tower_diff` | `missionId`(别名 `id`)、`maxBytes?` | 只读 merge-base diff:文件、提交、有上限的 patch。供 reviewer 安全使用。 |
42
42
  | `tower_send` | `to`、`subject`、`body`、`scope?`、`interrupt?`、`consentRef?` | 向 roster 名称、`tower` 或 `all` 发送持久消息;对运行中的 agent 会即时投递。`interrupt:true` 先中断运行中的回合(Kimi 风格)再投递;`consentRef` 记录用于审计。受 `send.maxPerMinute` 限速。 |
43
43
  | `tower_inbox` | `limit?`、`include_read?` | 读取并确认发给调用者的消息;未读消息会阻止 `tower_complete`。 |
44
- | `tower_complete` | `missionId`(别名 `id`)、`report`、`checks?` | worker 报告完成(mission 变为 `completed`,等待审查)。要求当前 owner、无未完成任务/blocker、≥1 个提交、无未读消息。`checks` 记录 `{name, command?, exitCode?, evidence?}` 证据;`gates.requireChecks` 可以强制要求。配置了测试发现时还会自动运行并添加 `tests` 检查;失败会抛出 `[tower:tests-failed]`。 |
44
+ | `tower_complete` | `missionId`(别名 `id`)、`report`、`checks?` | worker 报告完成(mission 变为 `completed`,可进入 preflight 与可选审查)。要求当前 owner、无未完成任务/blocker、≥1 个提交、无未读消息。`checks` 记录 `{name, command?, exitCode?, evidence?}` 证据;`gates.requireChecks` 可以强制要求。配置了测试发现时还会自动运行并添加 `tests` 检查;失败会抛出 `[tower:tests-failed]`。 |
45
45
  | `tower_interrupt` | `to?`(roster 名称)、`agentId?`、`reason?` | 通过 `subagents.interrupt` 中断一个运行中的 roster agent,并记录 `state:"interrupted"`。幂等(未运行 → `interrupted:false`)。 |
46
46
  | `tower_finding` | `type`、`title`、`summary`、`details`、`suggested_fix`、`severity?`、`missionId?`、`location?` | 记录 scope 之外的问题;reviewer 用它代替直接改文件。新 finding 初始为 `open`。 |
47
47
  | `tower_findings` | `id?`、`status?`、`note?`、过滤(`type?`、`severity?`、`missionId?`、`open?`、`limit?`) | 生命周期工具:列出/读取/流转。状态为 `open → triaged → fixed`/`wontfix`,允许重新打开。只有控制塔或 worker 能修改;reviewer 只能列出/读取。 |
@@ -51,9 +51,10 @@ roster 角色由 `exec.agent` 与 roster 共同决定。mission 级工具(`tow
51
51
  | `tower_rebase` | `missionId`(别名 `id`) | 在 worktree 内把分支 rebase 到基线。worker 运行中或 worktree 脏时拒绝。分支已包含在基线中时返回 `alreadyMerged` 且保持分支不动。 |
52
52
  | `tower_teardown` | `force?`、`exclude?`、`dry_run?`(别名 `dryRun`) | 移除符合条件的 merged/abandoned worktree 与分支;运行中的 agent 始终保留。 |
53
53
  | `tower_mode` | — | 报告模式、最近修改、被暂停的 goal、被拒绝的工具、store 路径、插件版本、HMR 可用性、workspace 锁持有者。 |
54
- | `tower_control` | `action`(`enter`/`exit`)、`reason` | 模型主动切换模式;仅当 `mode.allowAgentControl` 为 `true` 时可用;`reason` 必填。 |
54
+ | `tower_control` | `action`(`enter`/`exit`)、`reason` | 模型主动切换模式;默认注册,设 `mode.allowAgentControl:false` 可禁用;`reason` 必填。 |
55
55
  | `tower_reload` | `repoRoot?` | 仅开发用:请求 DSH HMR 对账 profile 并从磁盘重载 Host 插件。`dev.hotReload` 开启时注册;在工具结果返回后调度(默认 50 ms);没有 HMR 时以 `reload-unavailable` 失败。传入 `repoRoot` 时调用者必须是控制塔。 |
56
56
  | `tower_doctor` | —(需要 `repoRoot`) | 只读健康契约:git、state schema、config、preset/subagents/HMR、workspace 锁、roster、worktree realpath/归属、测试配置、leases。返回 `{ok, checks[{id,status,detail}], environmentContract}`。从不写状态。 |
57
+ | `tower_recover` | `action`(`status`/`clear-stale-lock`)、`confirm?` | 恢复诊断与显式 stale state-lock 修复。`clear-stale-lock` 需要 `confirm:"CLEAR_STALE_LOCK"`,只把 PID 已死的锁移到备份文件;不会重置状态或 worktree。 |
57
58
  | `tower_test` | `missionId`(别名 `id`) | 运行 worktree 的 `package.json` 中 `tower.testDiscovery` 配置的发现命令并记录回执;失败时 `ok:false`。自动准入检查请用 `tower_complete`。 |
58
59
  | `tower_batch` | `action`(`create`/`status`/`close`/`abandon`)、`missionIds?`、`exclusions?`、`requiredChecks?`、`receiptPaths?`、`batchId?`、`checks?`、`treeTip?`、`receiptHashes?`、`reason?` | 有限证据批次。create 冻结成员/检查/回执;close 校验每条必需检查与回执哈希;`merged` 成员也可参与 close;abandon 可退掉过期的 open batch 且不删除 mission。成员关系不可变。 |
59
60
  | `tower_resource` | `action`(`acquire`/`release`/`status`)、`name?`、`holder?`、`token?`、`ttlMs?`、`force?` | 每个仓库的咨询式租约,位于 `<common>/dsh-tower/leases.json`。没有 OS CPU/内存硬上限;过期的租约需要显式 `force` 与正确 token。 |