dsh-tower 1.3.0 → 2.0.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.
- package/CHANGELOG.md +109 -0
- package/CONTRIBUTING.md +1 -1
- package/README.en.md +44 -8
- package/README.md +42 -8
- package/cordis.patch.yml +11 -1
- package/docs/README.md +10 -5
- package/docs/architecture/overview.md +13 -9
- package/docs/faq.md +45 -2
- package/docs/guide/hot-reload.md +189 -0
- package/docs/guide/install-upgrade-migration.md +11 -0
- package/docs/guide/quickstart.md +33 -1
- package/docs/guide/scenarios-and-philosophy.md +309 -0
- package/docs/operations/runbook.md +23 -0
- package/docs/operations/security.md +23 -0
- package/docs/reference/blockers.md +10 -2
- package/docs/reference/config.md +65 -2
- package/docs/reference/doctor.md +33 -0
- package/docs/reference/errors.md +50 -0
- package/docs/reference/events.md +45 -0
- package/docs/reference/operations.md +55 -0
- package/docs/reference/testing.md +61 -0
- package/docs/reference/tools.md +65 -23
- package/docs/zh/README.md +60 -0
- package/docs/zh/faq.md +81 -0
- package/docs/zh/guide/hot-reload.md +178 -0
- package/docs/zh/guide/install-upgrade-migration.md +57 -0
- package/docs/zh/guide/quickstart.md +96 -0
- package/docs/zh/guide/scenarios-and-philosophy.md +211 -0
- package/docs/zh/operations/security.md +42 -0
- package/docs/zh/reference/blockers.md +62 -0
- package/docs/zh/reference/config.md +113 -0
- package/docs/zh/reference/doctor.md +31 -0
- package/docs/zh/reference/errors.md +52 -0
- package/docs/zh/reference/events.md +46 -0
- package/docs/zh/reference/operations.md +50 -0
- package/docs/zh/reference/testing.md +60 -0
- package/docs/zh/reference/tools.md +75 -0
- package/index.js +261 -13
- package/lib/batch.js +578 -0
- package/lib/config.js +275 -9
- package/lib/doctor.js +171 -0
- package/lib/errors.js +111 -0
- package/lib/hmr.js +196 -0
- package/lib/leases.js +317 -0
- package/lib/legacy.js +413 -0
- package/lib/modeStore.js +28 -1
- package/lib/store.js +24 -1
- package/lib/tests.js +628 -0
- package/lib/tools.js +1566 -184
- package/lib/tower.js +986 -103
- package/lib/workspaceLock.js +117 -0
- package/lib/worktreeOwnership.js +166 -0
- package/package.json +4 -1
- package/reviewer.js +1 -0
- package/scripts/check-docs.mjs +135 -0
- package/scripts/enable-dev-hmr.mjs +347 -0
- package/skills/tower-review.md +4 -2
- package/skills/tower-worker-protocol.md +3 -1
- package/worker.js +4 -2
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# 安全模型
|
|
2
|
+
|
|
3
|
+
[English](../../operations/security.md) | **简体中文**
|
|
4
|
+
|
|
5
|
+
Tower 提供的是**协作层面的保证**,不是沙箱。需要理解哪些约束由插件强制执行、哪些依赖部署环境。
|
|
6
|
+
|
|
7
|
+
## 由插件强制执行的约束
|
|
8
|
+
|
|
9
|
+
- **审查绑定。** `tower_review` 会记录它检查的分支 tip;tip 变化后门禁会拒绝(`tip-moved`),除非
|
|
10
|
+
一次干净且无冲突的 rebase 给予了豁免。reviewer 在 spawn 之后修改分支会被拒绝
|
|
11
|
+
(`reviewer must not modify the mission branch`)。
|
|
12
|
+
- **角色强制。** 调用方会根据 roster 解析。worker 的 mission 更新仅限于 task/blocker/note;
|
|
13
|
+
`completed`、`abandoned`、扩大 scope 与清除 blocker 仅限控制塔,完成(连同未读消息/提交门禁)必须
|
|
14
|
+
走 `tower_complete`。仅限控制塔的工具会以 `[tower:not-authorized]` 拒绝 roster 中的 worker。
|
|
15
|
+
每个 mission 只能有一个活跃 worker;接管已停止的 worker 必须显式声明。
|
|
16
|
+
- **只读 reviewer preset。** `tower-reviewer` preset 从工具面移除 `write`、`edit`、`pwsh`、
|
|
17
|
+
`tower_mission` 与 `tower_complete`;reviewer 只能读、看 diff、发消息、记录 finding 和提交审查。
|
|
18
|
+
- **Scope 门禁。** mission 只能修改其声明 scope glob 匹配的文件;越界改动会阻止合并。
|
|
19
|
+
- **Worktree 隔离。** worker 在独立 worktree 与分支上工作;主检出只会被 merge/teardown 触及。
|
|
20
|
+
- **人类掌握模式。** `/tower` 归用户所有。开启 `mode.allowAgentControl` 后模型可以切换,但必须
|
|
21
|
+
给出理由;随包 patch 默认开启——设为 `false` 可让模式只由人类控制。
|
|
22
|
+
- **不自动恢复 goal。** 进入模式会暂停活跃 goal;退出时不会恢复它。
|
|
23
|
+
- **建议性 workspace 锁。** `mode.workspaceLock` 防止两个 Tower 会话意外驱动同一个仓库;它是同用户
|
|
24
|
+
之间的协调锁,不是用户间的认证机制。
|
|
25
|
+
|
|
26
|
+
## 不由插件强制执行的约束(部署关注点)
|
|
27
|
+
|
|
28
|
+
- **沙箱。** Host 插件运行在文件系统沙箱之外;reviewer 的 shell 能力是在工具面层面移除的,但底层
|
|
29
|
+
进程仍拥有 DSH 的 OS 权限。需要硬隔离的部署必须自行限制进程/用户。
|
|
30
|
+
- **reviewer 信任。** 审查是 reviewer agent/模型给出的背书;插件能把它绑定到提交,但无法证明
|
|
31
|
+
reviewer 真的推理正确。高价值分支建议使用独立模型/角色。
|
|
32
|
+
- **仓库钩子。** `git merge` 会运行目标仓库的钩子(`pre-merge-commit` 等)。Tower 无法让这些钩子
|
|
33
|
+
变安全;在不受信任的仓库上运行 Tower 前请先审查钩子。
|
|
34
|
+
- **HMR 重载。** 开启 `dev.hotReload` 时,`/tower reload`/`tower_reload` 会让 DSH 从磁盘重新导入
|
|
35
|
+
插件。只为你信任的检出配置 HMR 监视 root;重载会执行这些文件当前的代码。
|
|
36
|
+
- **提示注入。** reviewer 会读取不受信任的分支内容(diff/评论)。只读 preset 限制了影响面,但模型侧
|
|
37
|
+
没有绝对防护。
|
|
38
|
+
- **基线分支保护。** Tower 会写入本地基线分支;服务端的 branch protection/push 规则不属于本插件。
|
|
39
|
+
|
|
40
|
+
## 报告问题
|
|
41
|
+
|
|
42
|
+
不要在公开 issue 中粘贴密钥、token 或会话日志。见 [SECURITY.md](../../../SECURITY.md)。
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# blocker 与失败码
|
|
2
|
+
|
|
3
|
+
[English](../../reference/blockers.md) | **简体中文**
|
|
4
|
+
|
|
5
|
+
`tower_preflight` 返回 `{ok:false, blockers:[{code, detail}]}`。`tower_merge` 与 `tower_rebase`
|
|
6
|
+
在操作失败时返回相同结构。code 稳定;detail 面向人。
|
|
7
|
+
|
|
8
|
+
## 门禁 blocker(26 个)
|
|
9
|
+
|
|
10
|
+
| Code | 含义 / 下一步 |
|
|
11
|
+
|---|---|
|
|
12
|
+
| `mission-missing` | 未知 mission id。用 `tower_status` 查看。 |
|
|
13
|
+
| `mission-not-completed` | mission 不是 `completed`;只有 `completed`(等待审查)的 mission 才能合并。 |
|
|
14
|
+
| `tasks-open` | 仍有未完成任务;worker 必须先完成,或带理由 `task_drop`。 |
|
|
15
|
+
| `blockers-present` | mission 仍有 blocker;解决后清除。 |
|
|
16
|
+
| `no-check-evidence` | 启用了 `gates.requireChecks` 且完成报告没有 `checks`。把 completed mission 退回 `active`,带 checks 重新调用 `tower_complete`,然后重新审查。 |
|
|
17
|
+
| `branch-missing` | 还没有 worktree/分支:先 spawn worker。 |
|
|
18
|
+
| `stale-base` | 分支不包含基线 tip:执行 `tower_rebase`。 |
|
|
19
|
+
| `read-only-survey` | survey mission 修改了文件;survey mission 必须只读。 |
|
|
20
|
+
| `out-of-scope` | 改动文件超出 mission scope;有意为之就扩大 scope,否则回退。 |
|
|
21
|
+
| `base-dirty` | 主检出存在未提交改动,合并会覆盖它们。 |
|
|
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 的免审豁免)。 |
|
|
29
|
+
| `worker-busy` | 该 mission 的 roster agent 正在运行;等待或让其退役。 |
|
|
30
|
+
| `worker-status-unknown` | 父目录不可用,无法证明 live roster agent 已停止;等目录恢复后重试,或先 adopt。 |
|
|
31
|
+
| `base-wrong-branch` | 主检出不在记录的基线分支上。 |
|
|
32
|
+
| `branch-owned-by-closed-missions` | mission 已 merged/abandoned;用新标题重新 plan。 |
|
|
33
|
+
| `worker-stale` | 该 mission 的 roster worker 超过 `spawn.staleMs` 没有目录活动;合并前 adopt(只有确实还在运行时才 interrupt)。 |
|
|
34
|
+
| `tests-missing` | 启用了 `gates.requireTests` 且没有针对被审查 tip 的通过测试回执;运行 `tower_test` 或 `tower_complete`。 |
|
|
35
|
+
| `tests-failed` | 最新测试发现回执失败,或不满足 minCount/required 检查。修复测试并重跑。 |
|
|
36
|
+
| `review-exemption-invalid` | mission 请求 `reviewPolicy:"none"`,但 `gates.allowReviewExemption` 关闭(或缺少理由)。 |
|
|
37
|
+
| `merge-intent-pending` | 崩溃/失败前记录了合并意图;先运行 `tower_merge` 对账,再进行其他门禁。 |
|
|
38
|
+
|
|
39
|
+
## 合并失败(4 个)
|
|
40
|
+
|
|
41
|
+
| Code | 含义 / 下一步 |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `merge-conflict` | 真实的 index 冲突;mission 变为 `blocked`。解决后把 mission 恢复为 `active`/`completed`,再重试。 |
|
|
44
|
+
| `merge-hook-failed` | 在产生提交之前钩子/进程失败;仓库已恢复,mission 保持 `completed`。重试;`timeout: true` 表示 git 进程超时,慢钩子请调大 `timeoutMs`。 |
|
|
45
|
+
| `merge-shape` | Git 产生了意外的合并父提交;检查仓库,不要强推。 |
|
|
46
|
+
| `batch-invalid` | batch id/成员/回执/检查引用无效,或 close 证据不完整。 |
|
|
47
|
+
|
|
48
|
+
已经落地的合并不是 blocker:`tower_merge` 会记录它(`reconciled`、`alreadyLanded`),或从失败调用中恢复
|
|
49
|
+
(`recoveredFromFailure`、`warnings`)。
|
|
50
|
+
|
|
51
|
+
## rebase 失败(3 个;`worker-busy` 与门禁共用)
|
|
52
|
+
|
|
53
|
+
| Code | 含义 / 下一步 |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `worktree-dirty` | 提交或丢弃 worktree 改动后重试。 |
|
|
56
|
+
| `rebase-conflict` | 真实冲突;mission 变为 `blocked`。手工解决后将其恢复为 `active`,再重试。 |
|
|
57
|
+
| `worker-busy` | 该 mission 有 agent 正在运行;先等待或让其退役。 |
|
|
58
|
+
|
|
59
|
+
分支已包含在基线中时,`tower_rebase` 返回 `alreadyMerged: true`;此时调用 `tower_merge` 记录这次
|
|
60
|
+
已落地的合并。
|
|
61
|
+
|
|
62
|
+
稳定的 blocker code 共 32 个(26 个门禁 + 4 个合并失败 + 2 个 rebase 专属;`worker-busy` 与门禁共用)。
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# 配置参考
|
|
2
|
+
|
|
3
|
+
[English](../../reference/config.md) | **简体中文**
|
|
4
|
+
|
|
5
|
+
每个键都是可选的;默认值即随包行为。未知顶层键会被拒绝。
|
|
6
|
+
`section` 与 `allowAgentControl` 是 `mode.promptSection` 与 `mode.allowAgentControl` 的兼容别名。
|
|
7
|
+
兼容别名只用于补缺:同时设置两种写法时,规范的 `mode.*` 键优先。
|
|
8
|
+
|
|
9
|
+
## 层级与优先级
|
|
10
|
+
|
|
11
|
+
从低到高:
|
|
12
|
+
|
|
13
|
+
1. 代码默认值(下表中的默认值),
|
|
14
|
+
2. profile 配置(挂载 `dsh-tower` 的 Cordis patch 传给 `apply()` 的配置),
|
|
15
|
+
3. 仓库配置 `<git-common-dir>/dsh-tower/config.json`(通常是 `.git/dsh-tower/config.json`),
|
|
16
|
+
4. 单次工具参数,例如 `worktreeRoot` 与 `timeoutMs`。
|
|
17
|
+
|
|
18
|
+
每次 Tower 工具打开仓库时都会读取仓库配置层,因此仓库可以在不修改 profile 的情况下调整 review、
|
|
19
|
+
merge、worktree 与 spawn 策略。它使用与 profile 配置相同的 JSON 形状(相同的分组与兼容别名),
|
|
20
|
+
并按分组合并:仓库设置的键优先,仓库未设置的 profile 键保留。`tower_status` 会报告
|
|
21
|
+
`config.path` 与 `config.repoConfigPresent`。
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"review": { "maxRoundsPerReviewer": 3 },
|
|
26
|
+
"merge": { "timeoutMs": 1800000 },
|
|
27
|
+
"worktrees": { "root": "D:/tower-worktrees" },
|
|
28
|
+
"spawn": { "reviewerPreset": "tower-reviewer", "maxDepth": 2 }
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`mode.*` 分组是会话级的,不是仓库级的:为兼容 schema,它可以在仓库文件中出现,但只有 profile
|
|
33
|
+
配置能控制 Tower 模式提示与模型切换开关。文件格式错误、值不是对象、未知顶层键,或违反声明 schema
|
|
34
|
+
的值(例如 `merge.timeoutMs` 小于 1000)会以稳定的 `config-invalid` / `config-unknown-key`
|
|
35
|
+
工具错误码失败。
|
|
36
|
+
|
|
37
|
+
| 键 | 默认值 | 含义 |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `section` | `''` | 兼容别名:替换整段 Tower 模式提示文案。空值保留内置提醒。 |
|
|
40
|
+
| `allowAgentControl` | `false`(随包 patch:`true`) | 兼容别名:注册 `tower_control`。 |
|
|
41
|
+
| `init.autoGitInit` | `false`(随包 patch:`true`) | 当 `repoRoot` 是绝对、已存在但不是仓库的目录时,`tower_init` 可以执行 `git init` 并创建一个空的初始提交。 |
|
|
42
|
+
| `init.snapshotDirty` | `false` | `tower_init` 可以把未提交的**已跟踪**改动快照为游离提交作为 mission 基线(不含未跟踪文件;该提交通过 `refs/tower/snapshot/*` 保持存活)。 |
|
|
43
|
+
| `mode.promptSection` | `''` | 替换用的提示文案(与 `section` 同时设置时优先)。 |
|
|
44
|
+
| `mode.sectionAppend` | `''` | 追加在提醒之后的额外文本(团队约定)。 |
|
|
45
|
+
| `mode.allowAgentControl` | `false` | 注册 `tower_control`;模型可带理由进入/退出。 |
|
|
46
|
+
| `mode.autoPauseGoal` | `true` | 进入模式时暂停活跃 goal;退出时不会自动恢复。 |
|
|
47
|
+
| `mode.requireResumeAuthorization` | `false` | 恢复因 `pauseCause:user` 暂停的 mission 时,必须提供 `authorization` 引用。 |
|
|
48
|
+
| `mode.workspaceLock` | `false`(随包 patch:`true`) | 每个仓库只允许一个 Tower 会话(`tower.lock`);其他会话得到 `workspace-busy`。 |
|
|
49
|
+
| `mode.workspaceLockScope` | `all` | `all` 锁定所有仓库工具;`mutations` 对只读工具跳过 workspace 锁。 |
|
|
50
|
+
| `mode.planModePolicy` | `clear` | 进入 Tower 模式会清除活跃的 plan mode(或 `refuse` 直到退出计划);前置步骤也会清除稍后激活的计划。 |
|
|
51
|
+
| `mode.workspaceStaleMs` | `300000` | 超过该时长的 workspace 锁可以被接管。 |
|
|
52
|
+
| `mode.heartbeatMs` | `10000` | workspace 锁的心跳间隔。 |
|
|
53
|
+
| `mode.denyTools` | goal/todo/team/workflow/subagent 工具(默认 12 个) | 模式激活期间被拒绝的工具。 |
|
|
54
|
+
| `mode.storePath` | `$DSH_HOME/tower-mode` | `modes.json` 所在目录。 |
|
|
55
|
+
| `mode.maxEntries` | `200` | 最多持久化的模式条目数(1–2000)。 |
|
|
56
|
+
| `review.maxRoundsPerReviewer` | `5` | 每个 reviewer 对每条分支的审查轮数上限。 |
|
|
57
|
+
| `merge.timeoutMs` | `900000`(15 分钟) | `tower_merge` 默认超时,包含钩子;单次调用的 `timeoutMs` 优先。 |
|
|
58
|
+
| `merge.maxBufferBytes` | `67108864`(64 MB) | 合并输出缓冲区。 |
|
|
59
|
+
| `worktrees.root` | `''` | 默认 worktree 父目录;空值推导为 `<主检出父目录>/.dsh-tower-worktrees/<hash>`。 |
|
|
60
|
+
| `spawn.workerPreset` | `tower-worker` | `role=worker` 使用的 preset。 |
|
|
61
|
+
| `spawn.reviewerPreset` | `tower-reviewer` | `role=reviewer` 使用的 preset。 |
|
|
62
|
+
| `spawn.maxDepth` | `1` | spawn 时请求的子代理深度。 |
|
|
63
|
+
| `spawn.provider` | `''` | 子代理 provider id;空值优先 `spawn`,否则取第一个 provider。 |
|
|
64
|
+
| `spawn.workerModel` | `{}` | worker 可选模型路由 `{provider, model, reasoningEffort, maxTokens}`。 |
|
|
65
|
+
| `spawn.reviewerModel` | `{}` | reviewer 可选模型路由;使用不同模型可获得更强的独立审查。 |
|
|
66
|
+
| `spawn.maxLiveWorkers` | `4` | 每个仓库同时存活的 worker 上限(空闲 `inactive`、failed/interrupted/missing/stale/retired 不计入);超过返回 `worker-limit`。 |
|
|
67
|
+
| `spawn.staleMs` | `15000` | 超过该时长没有目录活动的 roster 条目会被标记为 `stale` 并阻止合并(`worker-stale`);0 关闭。 |
|
|
68
|
+
| `spawn.maxWaitMs` | `90000` | `tower_spawn.waitMs` 的上限(与 Kimi 兼容的 90s 默认值)。 |
|
|
69
|
+
| `spawn.requireLease` | `''` | worker spawn 前必须持有的可选租约名。 |
|
|
70
|
+
| `send.maxPerMinute` | `120` | 每个仓库的 `tower_send` 每分钟速率限制(0 关闭);超出返回 `rate-limited`。 |
|
|
71
|
+
| `send.interruptDefault` | `false`(随包 patch:`true`) | `tower_send.interrupt` 的默认值(投递前先中断运行中的回合)。 |
|
|
72
|
+
| `tests.enabled` | `true` | worktree 的 `package.json` 配置了测试发现时运行它。 |
|
|
73
|
+
| `tests.admission` | `complete` | `spawn` 在启动 worker 前运行发现(fail-closed,不启动子代理);`complete` 在 `tower_complete` 时运行;`off` 只在显式 `tower_test` 时运行。 |
|
|
74
|
+
| `tests.timeoutMs` | `60000` | 每条发现命令的超时。 |
|
|
75
|
+
| `tests.maxBytes` | `16777216`(16 MiB) | 每条命令捕获的 stdout 上限。 |
|
|
76
|
+
| `tests.autoChecks` | `true` | 向完成报告附加自动 `tests` 检查。 |
|
|
77
|
+
| `tests.allowPackageDiscovery` | `true` | 允许仓库控制的 `tower.testDiscovery` 命令(会执行 worktree 代码;见安全页)。 |
|
|
78
|
+
| `gates.requireChecks` | `false` | 合并前要求至少一条 `tower_complete.checks` 证据(`no-check-evidence`)。 |
|
|
79
|
+
| `gates.requireTests` | `false` | 要求针对被审查 tip 的通过测试回执(`tests-missing`)。 |
|
|
80
|
+
| `gates.allowReviewExemption` | `false` | 允许用 `reviewPolicy:"none"` + 理由跳过审查 blocker;默认故意关闭。 |
|
|
81
|
+
| `docs.board` | `true` | 变更后写入 `MISSIONS.md`。 |
|
|
82
|
+
| `docs.boardLocation` | `common` | `common` = `<git-common-dir>/dsh-tower/MISSIONS.md`;`repo` = `<repoRoot>/MISSIONS.md`。 |
|
|
83
|
+
| `leases.ttlMs` | `900000` | 默认咨询式租约寿命;过期不会自动释放。 |
|
|
84
|
+
| `dev.hotReload` | `true` | 注册 `tower_reload`;关闭时 `/tower reload` 也被禁用。无 HMR 服务时调用返回 `reload-unavailable`。 |
|
|
85
|
+
| `dev.reloadDelayMs` | `50` | 计划中的 reload 延迟,先让工具结果送达。 |
|
|
86
|
+
| `dev.reloadRequiredIds` | 四个 Tower loader id | 作为 required 传给 `reconcileProfile` 的条目 id。 |
|
|
87
|
+
|
|
88
|
+
## 示例
|
|
89
|
+
|
|
90
|
+
```yaml
|
|
91
|
+
- id: tower
|
|
92
|
+
name: 'dsh-tower'
|
|
93
|
+
config:
|
|
94
|
+
mode:
|
|
95
|
+
allowAgentControl: true
|
|
96
|
+
sectionAppend: 'Team conventions: tests are mandatory.'
|
|
97
|
+
workspaceLock: true
|
|
98
|
+
review:
|
|
99
|
+
maxRoundsPerReviewer: 3
|
|
100
|
+
merge:
|
|
101
|
+
timeoutMs: 1800000
|
|
102
|
+
spawn:
|
|
103
|
+
reviewerModel:
|
|
104
|
+
provider: deepseek-account
|
|
105
|
+
model: deepseek-flash
|
|
106
|
+
dev:
|
|
107
|
+
hotReload: true
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 查看实际生效的 schema
|
|
111
|
+
|
|
112
|
+
插件声明 `Config` 后(本版本已声明),用 `cordis_inspect_query` 调用
|
|
113
|
+
`Config.listConfigs({ name: "dsh-tower" })` 可返回投影后的 JSON Schema。
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Doctor
|
|
2
|
+
|
|
3
|
+
[English](../../reference/doctor.md) | **简体中文**
|
|
4
|
+
|
|
5
|
+
`tower_doctor({repoRoot})` 是只读的。它从不获取 state 锁、写状态或改动 Git。它返回:
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"ok": true,
|
|
10
|
+
"checks": [
|
|
11
|
+
{ "id": "git", "status": "pass", "detail": "git version 2.55.0" },
|
|
12
|
+
{ "id": "state", "status": "pass", "detail": ".../state.json revision 7" }
|
|
13
|
+
],
|
|
14
|
+
"environmentContract": {
|
|
15
|
+
"platform": "win32",
|
|
16
|
+
"gitVersion": "git version 2.55.0",
|
|
17
|
+
"repoRoot": "D:/repo",
|
|
18
|
+
"commonDir": "D:/repo/.git",
|
|
19
|
+
"stateDir": "D:/repo/.git/dsh-tower"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
检查覆盖:git 可用性、仓库身份、state schema/加载、仓库配置是否存在、worker/reviewer preset 名称、
|
|
25
|
+
subagents 与 HMR 服务、workspace 锁持有者/是否过期、实时 roster、worktree 是否存在/归属/是否脏、
|
|
26
|
+
test-discovery 策略、旧版快照、batch 与租约。被 `tower_teardown` 正常清理的 mission worktree 会被
|
|
27
|
+
跳过(检查中会注明已移除数量),不会被误报为 missing。`warn` 是提示;`fail` 表示仓库在 spawn/merge 前需要
|
|
28
|
+
处理。state 加载失败会作为失败的检查报告而不是抛出,因此 doctor 在损坏的仓库上仍然有用。
|
|
29
|
+
|
|
30
|
+
环境契约仅供参考;它不是身份或授权证明。`tower_init` 仍要求控制塔角色,`tower_spawn` 仍会检查
|
|
31
|
+
实时子代理目录。
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# 工具错误码
|
|
2
|
+
|
|
3
|
+
[English](../../reference/errors.md) | **简体中文**
|
|
4
|
+
|
|
5
|
+
工具失败是抛出的错误,不是 `{ok:false}` 结果(门禁结果是例外:见 [blockers.md](blockers.md))。
|
|
6
|
+
每个抛出的错误都以稳定 code 作为消息前缀:
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
[tower:mission-not-found] unknown mission "M9"
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
调用方可以匹配前缀,而不必匹配文案。下面的 code 保留给对应条件;没有更具体匹配的消息会报告为
|
|
13
|
+
`tool-internal`。
|
|
14
|
+
|
|
15
|
+
| Code | 含义 | 典型触发 |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `invalid-argument` | 工具参数缺失、格式错误或不被允许。 | 缺少 `missionId`/`id`;未知状态;空 report;非法 scope glob;`timeoutMs < 1000`;更新时传入 `status: "all"`。 |
|
|
18
|
+
| `repo-invalid` | `repoRoot` 缺失、是相对路径,或不在 Git 仓库内。 | 传入的路径所在目录不是仓库 |
|
|
19
|
+
| `not-initialized` | 该仓库尚未初始化 Tower。 | 在 `tower_init` 之前调用读取类工具 |
|
|
20
|
+
| `mission-not-found` | 不存在该 id 的 mission。 | 过期或拼错的 `M9` |
|
|
21
|
+
| `finding-not-found` | 不存在该 id 的 finding。 | `tower_findings({id:"F99"})` |
|
|
22
|
+
| `invalid-transition` | 请求的状态转换不被允许。 | 尝试 blocked→merged;finding 状态图之外的流转;reviewer 修改 finding;在还有未完成任务、blocker、无提交或未读消息时完成 mission。 |
|
|
23
|
+
| `state-locked` | 另一个 Tower 写入者持有 state 锁。 | 锁超时后的并发写 |
|
|
24
|
+
| `state-corrupt` | Tower state 文件不可读或无效。 | 手工编辑过的 `state.json` |
|
|
25
|
+
| `config-invalid` | Tower 配置无效。 | 格式错误的仓库 `config.json`、违反 schema 的值 |
|
|
26
|
+
| `config-unknown-key` | Tower 配置存在未知顶层键。 | 例如把键拼成 `allowAgentToggle` |
|
|
27
|
+
| `git-failed` | git 命令因未归入其他分类的原因失败。 | 被拒绝的合并命令、非法 ref |
|
|
28
|
+
| `git-timeout` | git 命令超时或输出超出缓冲区。 | 慢 pre-merge 钩子、超大 diff |
|
|
29
|
+
| `spawn-unavailable` | subagents 服务不可用。 | 没有 `subagents` 的 Host |
|
|
30
|
+
| `provider-missing` | 没有注册的 subagent provider。 | provider 列表为空 |
|
|
31
|
+
| `preset-missing` | 配置的 agent preset 未注册。 | 缺少 `tower-worker`/`tower-reviewer` preset 行、DSH 未重启 |
|
|
32
|
+
| `reviewer-prerequisite` | reviewer spawn 的前置条件未满足。 | mission 尚未 `completed` 或还没有 worktree 就 spawn reviewer |
|
|
33
|
+
| `not-authorized` | 调用方 agent 角色无权执行该操作。 | worker 调用仅限控制塔的工具,或修改 mission 状态/scope;reviewer 修改 finding |
|
|
34
|
+
| `workspace-busy` | 另一个 Tower 会话持有该仓库的 workspace 锁。 | `mode.workspaceLock:true` 时第二个会话调用仓库级工具 |
|
|
35
|
+
| `worker-limit` | 仓库达到 `spawn.maxLiveWorkers` 个活跃 worker。 | 默认上限下 spawn 第五个 worker |
|
|
36
|
+
| `rate-limited` | 达到 `tower_send` 的每分钟速率限制。 | 超出 `send.maxPerMinute`;稍后重试 |
|
|
37
|
+
| `takeover-refused` | mission 仍有运行中的 worker。 | 在 `tower_interrupt` 之前调用 `tower_spawn({takeover:true})` |
|
|
38
|
+
| `reload-unavailable` | 当前 profile 中没有可用的 DSH HMR 服务。 | 在没有 HMR 的 profile 上调用 `tower_reload` / `/tower reload` |
|
|
39
|
+
| `reload-failed` | HMR reload 失败。 | `reconcileProfile` 抛错;检查 DSH 日志并重启 |
|
|
40
|
+
| `tests-failed` | 声明的测试发现失败,或不满足准入要求。 | 命令非零退出、输出格式错误、minCount/required 不足 |
|
|
41
|
+
| `tests-timeout` | 测试发现超出时间或输出预算。 | `tests.timeoutMs`,或 stdout 超过 `tests.maxBytes` |
|
|
42
|
+
| `lease-busy` | 另一个持有者拥有请求的咨询式租约。 | `heavy-ci` 被持有时调用 `tower_resource acquire` |
|
|
43
|
+
| `lease-token` | 租约释放 token 与持有者不匹配。 | 用另一个会话的 token 释放 |
|
|
44
|
+
| `batch-invalid` | batch 请求或其 close 证据无效。 | 未知成员、重复 id、不安全的回执路径、缺少回执哈希 |
|
|
45
|
+
| `legacy-invalid` | 旧版快照或映射无效。 | 未知 schema、源路径位于 Tower state 目录内、映射重写 |
|
|
46
|
+
| `tool-internal` | 意外失败。 | bug;阅读消息与 activity 日志 |
|
|
47
|
+
|
|
48
|
+
## 为什么抛出?
|
|
49
|
+
|
|
50
|
+
返回 `{ok:false}` 的形状保留给控制塔能决定的预期策略结果(`tower_merge`/`tower_rebase` 的门禁
|
|
51
|
+
blocker 以及 `tower_preflight`)。任何阻止工具给出决策的问题都会抛出,以免模型把它误当成正常的
|
|
52
|
+
否定结果。
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Tower 事件
|
|
2
|
+
|
|
3
|
+
[English](../../reference/events.md) | **简体中文**
|
|
4
|
+
|
|
5
|
+
Tower 在工具成功调用(变更与只读)后发出进程内 Cordis 事件,其他插件因此可以观察仓库,而不必轮询。
|
|
6
|
+
事件**不会**通过网络发送,也不包含遥测。
|
|
7
|
+
|
|
8
|
+
```js
|
|
9
|
+
ctx.on('tower/merge', (payload) => {
|
|
10
|
+
// payload.tool, payload.repoRoot, payload.value (the tool's JSON result)
|
|
11
|
+
})
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
| 事件 | 触发时机 |
|
|
15
|
+
|---|---|
|
|
16
|
+
| `tower/init` | `tower_init` 创建或重新锚定 state 之后 |
|
|
17
|
+
| `tower/plan` | `tower_plan` 创建 mission 之后 |
|
|
18
|
+
| `tower/mission` | `tower_mission` 修改单个 mission 之后 |
|
|
19
|
+
| `tower/spawn` | `tower_spawn` 记录 worker/reviewer 之后 |
|
|
20
|
+
| `tower/complete` | `tower_complete` 记录完成报告之后 |
|
|
21
|
+
| `tower/review` | `tower_review` 记录审查结论之后 |
|
|
22
|
+
| `tower/merge` | `tower_merge` 返回之后(包括门禁失败;检查 `value.ok`) |
|
|
23
|
+
| `tower/rebase` | `tower_rebase` 返回之后 |
|
|
24
|
+
| `tower/teardown` | `tower_teardown` 移除 worktree 之后 |
|
|
25
|
+
| `tower/finding` | `tower_finding` 创建单条 finding 之后 |
|
|
26
|
+
| `tower/findings` | `tower_findings` 读取/列出/更新 finding 之后 |
|
|
27
|
+
| `tower/send` | `tower_send` 持久化消息之后 |
|
|
28
|
+
| `tower/inbox` | `tower_inbox` 确认消息之后 |
|
|
29
|
+
| `tower/interrupt` | `tower_interrupt` 停止运行中的 agent 之后 |
|
|
30
|
+
| `tower/diff` | `tower_diff` 读取 mission diff 之后 |
|
|
31
|
+
| `tower/adopt` | `tower_adopt` 对账 roster 之后 |
|
|
32
|
+
| `tower/roster` | `tower_roster` 读取 roster 之后 |
|
|
33
|
+
| `tower/status` | `tower_status` 读取面板之后 |
|
|
34
|
+
| `tower/preflight` | `tower_preflight` 评估门禁之后 |
|
|
35
|
+
| `tower/doctor` | `tower_doctor` 完成只读检查之后 |
|
|
36
|
+
| `tower/test` | `tower_test` 运行测试发现之后 |
|
|
37
|
+
| `tower/batch` | `tower_batch` 创建、查看或关闭 batch 之后 |
|
|
38
|
+
| `tower/resource` | `tower_resource` 获取/释放/查看租约之后 |
|
|
39
|
+
| `tower/import_legacy` | `tower_import_legacy` 保存旧版快照之后 |
|
|
40
|
+
| `tower/legacy_map` | `tower_legacy_map` 映射或列出旧 id 之后 |
|
|
41
|
+
|
|
42
|
+
`tower_mode`、`tower_control` 与 `tower_reload` 不发出 Tower 事件。payload 是 JSON:
|
|
43
|
+
`{tool, repoRoot, value}`。监听器抛错不会影响工具结果。
|
|
44
|
+
|
|
45
|
+
需要可持久审计的调用链时,请使用 `<git-common-dir>/dsh-tower/activity.jsonl` 与 `MISSIONS.md`;
|
|
46
|
+
事件是进程内的,不会重放。
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# 批次、租约与旧版导入
|
|
2
|
+
|
|
3
|
+
[English](../../reference/operations.md) | **简体中文**
|
|
4
|
+
|
|
5
|
+
## 证据批次
|
|
6
|
+
|
|
7
|
+
`tower_batch` 把有限的 mission 完成证据分组。
|
|
8
|
+
|
|
9
|
+
- `create` 冻结 `missionIds`、`exclusions`、`requiredChecks`(默认 `["check"]`)与精确的相对
|
|
10
|
+
`receiptPaths`。成员必须是已知 mission,且只有暂停的旧版 mission 可以被排除;创建后成员关系不可变。
|
|
11
|
+
- `status` 汇总成员与待处理/失败的检查。
|
|
12
|
+
- `close` 校验已完成、**merged** 或 abandoned 成员的每条必需检查(来自 `completionReport.checks`、
|
|
13
|
+
`testRuns` 或 close 时的 `checks`),在提供 `treeTip` 时校验它,并要求每个冻结的回执路径都在
|
|
14
|
+
`receiptHashes`/`receipts` 中提供(或通过 `receiptHash` 绑定到通过的检查)。缺少证据会返回
|
|
15
|
+
`{ok:false, blockers}`;不会删除任何内容。
|
|
16
|
+
- `abandon` 用 `batchId`(可选 `reason`)退掉过期的 open batch,不修改 mission 状态;当证据窗口
|
|
17
|
+
已过(例如先 merge 后 close)时用它收尾。
|
|
18
|
+
|
|
19
|
+
close 失败不是部分关闭:batch 保持 `open`,修复证据后可以重试。
|
|
20
|
+
|
|
21
|
+
## 咨询式租约
|
|
22
|
+
|
|
23
|
+
`tower_resource` 管理每个仓库的租约,位于 `<git-common-dir>/dsh-tower/leases.json`:
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
tower_resource({action:"acquire", name:"heavy-ci", ttlMs:900000})
|
|
27
|
+
tower_resource({action:"status"})
|
|
28
|
+
tower_resource({action:"release", name:"heavy-ci", token:"<token from acquire>"})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- acquire 仅限控制塔;调用方会得到 token、pid、holder、创建/过期时间戳;
|
|
32
|
+
- 同一个 token 可以续租;另一个持有者会得到 `[tower:lease-busy]`;
|
|
33
|
+
- release 需要 token;**已过期**的租约仍需要 token 与显式 `force:true`(不会静默接管);
|
|
34
|
+
- `spawn.requireLease` 要求持有该租约,否则 worker spawn 失败。
|
|
35
|
+
|
|
36
|
+
租约用于协调本地任务与 CI 窗口。它们**不是** OS CPU/内存硬上限:DSH 没有公开的 Job Object 配额
|
|
37
|
+
API,Tower 无法强制每进程资源限制;这类限制请使用 live-worker 上限以及你的 OS/CI 调度器。
|
|
38
|
+
|
|
39
|
+
## 旧版导入与映射
|
|
40
|
+
|
|
41
|
+
`tower_import_legacy({repoRoot,sourcePath})` 接受 Tower Codex `schemaVersion:1` state 文件或 DSH
|
|
42
|
+
旧版 state。它会:
|
|
43
|
+
|
|
44
|
+
- 要求绝对源路径,且位于 `<git-common-dir>/dsh-tower` 之外;
|
|
45
|
+
- 校验 schema(上限 16 MiB),把原始 payload 逐字节保存到
|
|
46
|
+
`<git-common-dir>/dsh-tower/legacy/<sha256>.json`,并在 `state.legacySnapshots` 中只记录摘要;
|
|
47
|
+
- 绝不激活、接管或恢复暂停的 mission。
|
|
48
|
+
|
|
49
|
+
`tower_legacy_map` 记录仅审计用途的 `sourceHash + oldId → newMissionId?` 映射。映射只追加;把已有
|
|
50
|
+
映射改写到另一个 mission 会被拒绝。映射不会改变 mission 状态。
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# 测试、发现与证据
|
|
2
|
+
|
|
3
|
+
[English](../../reference/testing.md) | **简体中文**
|
|
4
|
+
|
|
5
|
+
Tower 2.1 可以执行仓库声明的测试发现,并把结果变成持久的完成证据。发现是**按配置选择性启用**的:
|
|
6
|
+
worktree 没有 `package.json.tower.testDiscovery` 块时,行为与之前完全一致。
|
|
7
|
+
|
|
8
|
+
## 配置
|
|
9
|
+
|
|
10
|
+
`package.json`(与 Tower Codex 兼容):
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"tower": {
|
|
15
|
+
"testDiscovery": {
|
|
16
|
+
"version": 1,
|
|
17
|
+
"commands": [
|
|
18
|
+
{
|
|
19
|
+
"id": "unit",
|
|
20
|
+
"command": "node --test dist/tests/*.test.js",
|
|
21
|
+
"format": "node-tap",
|
|
22
|
+
"minCount": 1,
|
|
23
|
+
"required": ["smoke"]
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| 字段 | 含义 |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `id` | 唯一,`[A-Za-z0-9][A-Za-z0-9._-]{0,63}`;也用于诊断文件名。 |
|
|
34
|
+
| `command` | 以 worktree 为 cwd 执行的 shell 命令(Windows 用 `pwsh`,POSIX 用 `bash`)。 |
|
|
35
|
+
| `format` | `node-tap`(TAP 的 `ok N - name` / `not ok`)或 `json-array`(`{name, ok?}` 的 JSON 数组)。 |
|
|
36
|
+
| `minCount` | 该命令至少应发现的测试数(默认 1)。 |
|
|
37
|
+
| `required` | 必须出现且通过的测试名。 |
|
|
38
|
+
|
|
39
|
+
Tower 配置中的 `tests.*` 控制准入、超时、输出上限以及是否允许 package discovery。
|
|
40
|
+
`tests.admission` 取 `spawn`(worker 启动前运行;fail-closed,不启动子代理)、`complete`
|
|
41
|
+
(在 `tower_complete` 时运行;默认)或 `off`(只在显式 `tower_test` 时运行)。
|
|
42
|
+
|
|
43
|
+
## 回执与门禁
|
|
44
|
+
|
|
45
|
+
每次运行都会在 `<git-common-dir>/dsh-tower/test-runs/<mission>-<stamp>/` 下保存回执,包含
|
|
46
|
+
stdout/stderr 文件、SHA-256 哈希、退出码、计数、required 名称、worktree tip 以及总体 `ok`。
|
|
47
|
+
`state.missions[].testRuns` 保留最近的 50 条回执。失败时工具返回带诊断的 `ok:false`;自动发现失败时
|
|
48
|
+
`tower_complete` 会抛出 `[tower:tests-failed]`。
|
|
49
|
+
|
|
50
|
+
- `tower_test({repoRoot,missionId})` 按需运行发现并记录回执。
|
|
51
|
+
- `tests.autoChecks` 开启时,`tower_complete` 会添加一条 `tests` 检查。
|
|
52
|
+
- `gates.requireChecks` 要求任意完成检查;`gates.requireTests` 要求针对被审查 tip 的通过回执
|
|
53
|
+
(`tests-missing`)。
|
|
54
|
+
|
|
55
|
+
## 信任边界
|
|
56
|
+
|
|
57
|
+
发现命令是仓库控制的代码。`tests.allowPackageDiscovery:false` 会禁用 package 块;CI 或策略 profile
|
|
58
|
+
在克隆不受信任仓库时应设置它。命令以与 DSH 相同的 OS 权限、在 mission worktree 中运行,Tower 不会
|
|
59
|
+
为它增加网络访问。输出上限为 `tests.maxBytes`(默认 16 MiB),每条命令受 `tests.timeoutMs`
|
|
60
|
+
(默认 60 秒)限制;超出预算的运行 fail closed。
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# 工具参考
|
|
2
|
+
|
|
3
|
+
[English](../../reference/tools.md) | **简体中文**
|
|
4
|
+
|
|
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`、
|
|
9
|
+
`tower_resource`、`tower_import_legacy`、`tower_legacy_map`。
|
|
10
|
+
|
|
11
|
+
`tower_mission` 使用 `id`(别名 `missionId`);其他所有 mission 级工具使用 `missionId`
|
|
12
|
+
(别名 `id`)。其他输入别名:`task_done`/`taskDone`、`task_drop`/`taskDrop`、
|
|
13
|
+
`task_drop_reason`/`taskDropReason`、`clear_blockers`/`clearBlockers`、
|
|
14
|
+
`include_read`/`includeRead`、`dry_run`/`dryRun`、`timeoutMs`/`timeout_ms`、
|
|
15
|
+
`waitMs`/`wait_ms`、finding 上的 `mission_id`/`missionId`、interrupt 上的 `agent_id`/`agentId`、
|
|
16
|
+
status 上的 `include_gate`/`includeGate`、adopt 上的 `retire_missing`/`retireMissing`。
|
|
17
|
+
输出始终使用规范的 camelCase 字段名。
|
|
18
|
+
|
|
19
|
+
## 角色
|
|
20
|
+
|
|
21
|
+
roster 角色由 `exec.agent` 与 roster 共同决定。mission 级工具(`tower_interrupt`、
|
|
22
|
+
`tower_init`、`tower_plan`、`tower_spawn`、`tower_merge`、`tower_rebase`、`tower_teardown`、
|
|
23
|
+
`tower_adopt`、`tower_reload`)**仅限控制塔**。`tower_batch` 的 create/close/abandon、`tower_resource`
|
|
24
|
+
的 acquire/release、`tower_import_legacy`、`tower_legacy_map` 的 map 以及 review-exemption 规划
|
|
25
|
+
仅限控制塔;它们的只读 status 动作对 roster 角色开放。worker 调用 `tower_mission` 时只能使用
|
|
26
|
+
`task_done`/`task_drop`/`blocker`/`note`;状态变更、扩大 scope、`clear_blockers` 与 `completed`
|
|
27
|
+
仅限控制塔(完成必须走 `tower_complete`)。roster 中的 reviewer 可以读取 finding,但不能修改。
|
|
28
|
+
违规会抛出 `[tower:not-authorized]` 或 `[tower:invalid-transition]`。
|
|
29
|
+
|
|
30
|
+
## 工具
|
|
31
|
+
|
|
32
|
+
| 工具 | 参数 | 用途 / 说明 |
|
|
33
|
+
|---|---|---|
|
|
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`。 |
|
|
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"` 返回看板。 |
|
|
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
|
+
| `tower_roster` | — | roster 及来自子代理目录的实时活动(`running`/`inactive`/`missing`/`unknown`)与 `stale` 标记。只读。 |
|
|
40
|
+
| `tower_adopt` | `retireMissing?` | 把 roster 条目与持久子代理目录对账。可证明已消失的 agent 会被标记为 retired(默认),或标记为 `missing`(`retireMissing:false`)以便检查/接管。 |
|
|
41
|
+
| `tower_diff` | `missionId`(别名 `id`)、`maxBytes?` | 只读 merge-base diff:文件、提交、有上限的 patch。供 reviewer 安全使用。 |
|
|
42
|
+
| `tower_send` | `to`、`subject`、`body`、`scope?`、`interrupt?`、`consentRef?` | 向 roster 名称、`tower` 或 `all` 发送持久消息;对运行中的 agent 会即时投递。`interrupt:true` 先中断运行中的回合(Kimi 风格)再投递;`consentRef` 记录用于审计。受 `send.maxPerMinute` 限速。 |
|
|
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]`。 |
|
|
45
|
+
| `tower_interrupt` | `to?`(roster 名称)、`agentId?`、`reason?` | 通过 `subagents.interrupt` 中断一个运行中的 roster agent,并记录 `state:"interrupted"`。幂等(未运行 → `interrupted:false`)。 |
|
|
46
|
+
| `tower_finding` | `type`、`title`、`summary`、`details`、`suggested_fix`、`severity?`、`missionId?`、`location?` | 记录 scope 之外的问题;reviewer 用它代替直接改文件。新 finding 初始为 `open`。 |
|
|
47
|
+
| `tower_findings` | `id?`、`status?`、`note?`、过滤(`type?`、`severity?`、`missionId?`、`open?`、`limit?`) | 生命周期工具:列出/读取/流转。状态为 `open → triaged → fixed`/`wontfix`,允许重新打开。只有控制塔或 worker 能修改;reviewer 只能列出/读取。 |
|
|
48
|
+
| `tower_review` | `missionId`(别名 `id`)、`status`(`clean`/`p1-Nitems`/`p2-Nitems`)、`merge`(`merge`/`fix-then-merge`/`hold`)、`findings`、`decision`、`checks?`、`breakGlassReason?` | 绑定当前 tip 的 reviewer 结论。reviewer 必须是获派的 reviewer(或由控制塔使用 break-glass)。 |
|
|
49
|
+
| `tower_preflight` | `missionId`(别名 `id`) | 只读门禁:返回 `{ok, blockers[], branchTip, baseTip, changedFiles, review}`。 |
|
|
50
|
+
| `tower_merge` | `missionId`(别名 `id`)、`timeoutMs?`(别名 `timeout_ms`) | 门禁全绿后合并。若合并提交已落地则记录(`reconciled`);若命令失败但提交已存在则恢复(`recoveredFromFailure`);区分 `merge-hook-failed` 与 `merge-conflict`。 |
|
|
51
|
+
| `tower_rebase` | `missionId`(别名 `id`) | 在 worktree 内把分支 rebase 到基线。worker 运行中或 worktree 脏时拒绝。分支已包含在基线中时返回 `alreadyMerged` 且保持分支不动。 |
|
|
52
|
+
| `tower_teardown` | `force?`、`exclude?`、`dry_run?`(别名 `dryRun`) | 移除符合条件的 merged/abandoned worktree 与分支;运行中的 agent 始终保留。 |
|
|
53
|
+
| `tower_mode` | — | 报告模式、最近修改、被暂停的 goal、被拒绝的工具、store 路径、插件版本、HMR 可用性、workspace 锁持有者。 |
|
|
54
|
+
| `tower_control` | `action`(`enter`/`exit`)、`reason` | 模型主动切换模式;仅当 `mode.allowAgentControl` 为 `true` 时可用;`reason` 必填。 |
|
|
55
|
+
| `tower_reload` | `repoRoot?` | 仅开发用:请求 DSH HMR 对账 profile 并从磁盘重载 Host 插件。`dev.hotReload` 开启时注册;在工具结果返回后调度(默认 50 ms);没有 HMR 时以 `reload-unavailable` 失败。传入 `repoRoot` 时调用者必须是控制塔。 |
|
|
56
|
+
| `tower_doctor` | —(需要 `repoRoot`) | 只读健康契约:git、state schema、config、preset/subagents/HMR、workspace 锁、roster、worktree realpath/归属、测试配置、leases。返回 `{ok, checks[{id,status,detail}], environmentContract}`。从不写状态。 |
|
|
57
|
+
| `tower_test` | `missionId`(别名 `id`) | 运行 worktree 的 `package.json` 中 `tower.testDiscovery` 配置的发现命令并记录回执;失败时 `ok:false`。自动准入检查请用 `tower_complete`。 |
|
|
58
|
+
| `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
|
+
| `tower_resource` | `action`(`acquire`/`release`/`status`)、`name?`、`holder?`、`token?`、`ttlMs?`、`force?` | 每个仓库的咨询式租约,位于 `<common>/dsh-tower/leases.json`。没有 OS CPU/内存硬上限;过期的租约需要显式 `force` 与正确 token。 |
|
|
60
|
+
| `tower_import_legacy` | `sourcePath` | 只读导入 Tower Codex `schemaVersion:1` 或 DSH 旧版 state。完整 payload 存到 `<common>/dsh-tower/legacy/<sha256>.json`;state 中只保存摘要。绝不激活/接管/恢复暂停的 mission。 |
|
|
61
|
+
| `tower_legacy_map` | `action`(`map`/`status`)、`sourceHash?`、`oldId?`、`newMissionId?` | 仅审计用途的旧 id 映射;映射只追加,绝不容纳 mission。 |
|
|
62
|
+
|
|
63
|
+
## workspace 锁
|
|
64
|
+
|
|
65
|
+
当 `mode.workspaceLock:true` 时(随包 patch 开启),Tower 模式会话的第一次仓库级 Tower 工具调用会
|
|
66
|
+
获取 `<git-common-dir>/dsh-tower/tower.lock`;另一个会话会得到 `[tower:workspace-busy]`,直到持有
|
|
67
|
+
者执行 `/tower off` 或锁超过 `mode.workspaceStaleMs`。`mode.workspaceLockScope:"mutations"` 会跳过
|
|
68
|
+
只读工具的锁。代码默认关闭;随包 patch 开启,以提供与 Kimi 兼容的“单活跃控制塔”行为。
|
|
69
|
+
|
|
70
|
+
## 失败结果
|
|
71
|
+
|
|
72
|
+
门禁类工具返回 `{ok:false, blockers:[{code, detail}]}`;code 列表见 [blockers.md](blockers.md)。
|
|
73
|
+
抛出的工具错误带稳定的 `[tower:<code>]` 前缀(见 [errors.md](errors.md))。成功的变更会发出进程内
|
|
74
|
+
事件(见 [events.md](events.md)),并且在 `docs.board:true` 时刷新
|
|
75
|
+
`<git-common-dir>/dsh-tower/MISSIONS.md`。
|