dsh-tower 2.1.0 → 2.4.0
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 +137 -0
- package/COMPATIBILITY.md +6 -1
- package/CONTRIBUTING.md +78 -5
- package/PRINCIPLES.md +163 -0
- package/README.en.md +35 -19
- package/README.md +28 -18
- package/SECURITY.md +6 -0
- package/{lib → adapters}/archive.js +1 -1
- package/{lib → adapters}/caseSensitivity.js +1 -1
- package/adapters/default.js +51 -10
- package/{lib → adapters}/git.js +1 -1
- package/{lib → adapters}/leases.js +1 -1
- package/{lib → adapters}/legacy.js +1 -1
- package/adapters/persistence.js +543 -0
- package/adapters/store-fs.js +28 -1
- package/adapters/store.js +204 -0
- package/{lib → adapters}/tests.js +9 -5
- package/adapters/vcs-git.js +15 -1
- package/{lib → adapters}/workspaceLock.js +1 -1
- package/{lib → adapters}/worktreeOwnership.js +1 -1
- package/app/archive.js +4 -6
- package/app/batch.js +9 -10
- package/app/board.js +2 -4
- package/app/checkCompletion.js +9 -10
- package/app/enrichedMissions.js +2 -4
- package/app/findings.js +6 -7
- package/app/gate.js +1 -2
- package/app/init.js +24 -29
- package/app/merge.js +58 -51
- package/app/messages.js +7 -8
- package/app/mission.js +5 -5
- package/app/plan.js +8 -5
- package/app/provision.js +12 -14
- package/app/read.js +6 -3
- package/app/rebase.js +14 -16
- package/app/recording.js +7 -8
- package/app/review.js +15 -8
- package/app/roster.js +14 -15
- package/{lib → app}/spawn-prechecks.js +4 -3
- package/app/spawn.js +12 -13
- package/app/teardown.js +8 -9
- package/app/tower.js +89 -35
- package/cordis.patch.yml +56 -28
- package/docs/README.md +7 -2
- package/docs/adr/0001-ports-adapters-as-data.md +49 -0
- package/docs/adr/0002-single-state-json.md +50 -0
- package/docs/adr/0003-allow-agent-control-default-true.md +48 -0
- package/docs/adr/0004-surface-budget.md +70 -0
- package/docs/adr/0005-component-surface.md +130 -0
- package/docs/adr/README.md +52 -0
- package/docs/agents/workflow.md +51 -0
- package/docs/architecture/overview.md +192 -43
- package/docs/guide/hot-reload.md +5 -5
- package/docs/guide/install-upgrade-migration.md +13 -0
- package/docs/guide/release.md +1 -1
- package/docs/operations/incident.md +82 -0
- package/docs/operations/runbook.md +12 -3
- package/docs/operations/security.md +1 -1
- package/docs/reference/blockers.md +2 -2
- package/docs/reference/component-surface.md +135 -0
- package/docs/reference/config.generated.md +2 -9
- package/docs/reference/config.md +11 -9
- package/docs/reference/doctor.md +53 -2
- package/docs/reference/errors.generated.md +41 -37
- package/docs/reference/errors.md +53 -41
- package/docs/reference/events.md +38 -6
- package/docs/reference/surface-budget.md +157 -0
- package/docs/reference/tools.generated.md +8 -5
- package/docs/reference/tools.md +10 -7
- package/docs/zh/README.md +1 -1
- package/docs/zh/guide/hot-reload.md +4 -4
- package/docs/zh/guide/install-upgrade-migration.md +10 -0
- package/docs/zh/operations/security.md +1 -1
- package/docs/zh/reference/blockers.md +2 -2
- package/docs/zh/reference/config.md +9 -9
- package/docs/zh/reference/doctor.md +29 -1
- package/docs/zh/reference/tools.md +10 -8
- package/domain/batch.js +2 -2
- package/domain/components.js +641 -0
- package/domain/config/schema.js +62 -28
- package/domain/contracts/outputs.js +16 -2
- package/domain/contracts/tool-inputs/ops.js +1 -0
- package/domain/errors.js +308 -43
- package/domain/events.js +207 -0
- package/domain/integration/gate.js +17 -2
- package/domain/integration/merge.js +35 -0
- package/domain/lockBudget.js +30 -0
- package/domain/mission.js +12 -1
- package/domain/missions/completion.js +14 -0
- package/domain/missions/lifecycle.js +9 -3
- package/domain/missions/plan.js +14 -0
- package/domain/missions/review.js +90 -7
- package/domain/read/views.js +3 -0
- package/domain/state/archive.js +1 -1
- package/domain/state.js +1 -1
- package/domain/surface.js +347 -0
- package/host/capability-batch.js +15 -0
- package/host/capability-hmr.js +30 -0
- package/host/capability-import.js +11 -0
- package/host/capability-leases.js +11 -0
- package/host/capability-registry.js +149 -0
- package/host/capability-tests.js +16 -0
- package/{lib → host}/doctor.js +157 -18
- package/{lib → host}/hmr.js +2 -4
- package/{lib → host}/modeStore.js +1 -1
- package/host/presets.js +77 -0
- package/{lib → host}/tool-registry.js +235 -44
- package/host/tower.js +32 -0
- package/index.js +40 -25
- package/locale/en.json +31 -11
- package/locale/zh.json +30 -10
- package/package.json +24 -4
- package/ports/archive.js +18 -0
- package/ports/caseSensitivity.js +15 -0
- package/ports/clock.js +10 -2
- package/ports/config.js +19 -0
- package/ports/contract.js +38 -0
- package/ports/events.js +24 -0
- package/ports/ids.js +10 -2
- package/ports/index.js +54 -2
- package/ports/ownership.js +17 -0
- package/ports/state.js +16 -0
- package/ports/store.js +52 -3
- package/ports/vcs.js +25 -4
- package/scripts/architecture-waivers.json +19 -0
- package/scripts/architecture.mjs +634 -23
- package/scripts/check-components.mjs +235 -0
- package/scripts/check-docs.mjs +8 -35
- package/scripts/check-pack.mjs +68 -39
- package/scripts/check-philosophy.mjs +266 -0
- package/scripts/component-surface.json +395 -0
- package/scripts/domain-metrics.mjs +13 -4
- package/scripts/generate-component-surface.mjs +59 -0
- package/scripts/generate-config-reference.mjs +14 -1
- package/scripts/generate-error-reference.mjs +68 -14
- package/scripts/generate-events-reference.mjs +83 -0
- package/scripts/generate-tools-reference.mjs +18 -25
- package/scripts/generate-types.mjs +127 -0
- package/scripts/issue-audit.mjs +2 -2
- package/scripts/lib/surface.mjs +87 -0
- package/scripts/lib/tool-surface.mjs +85 -0
- package/scripts/mount-smoke/fixtures.mjs +3 -3
- package/scripts/mount-smoke/surface.mjs +96 -27
- package/scripts/mount-smoke.mjs +3 -1
- package/scripts/pack-manifest.txt +75 -22
- package/scripts/regression-audit.mjs +164 -0
- package/scripts/release-check.mjs +1 -1
- package/scripts/surface-baseline.json +52 -0
- package/scripts/surface-baseline.mjs +118 -0
- package/scripts/types-coverage.mjs +184 -0
- package/scripts/types-strict-manifest.txt +10 -0
- package/scripts/types-strict.mjs +141 -0
- package/skills.js +8 -1
- package/tools/adopt.js +2 -3
- package/tools/batch.js +2 -3
- package/tools/complete.js +2 -3
- package/tools/diff.js +3 -3
- package/tools/doctor.js +7 -10
- package/tools/finding.js +2 -3
- package/tools/findings.js +3 -3
- package/tools/import-legacy.js +3 -5
- package/tools/inbox.js +3 -3
- package/tools/index.js +9 -8
- package/tools/init.js +3 -6
- package/tools/interrupt.js +2 -3
- package/tools/legacy-map.js +3 -5
- package/tools/merge.js +3 -3
- package/tools/mission.js +2 -3
- package/tools/plan.js +6 -5
- package/tools/preflight.js +2 -3
- package/tools/rebase.js +3 -3
- package/tools/recover.js +38 -13
- package/tools/reload.js +36 -40
- package/tools/resource.js +3 -5
- package/tools/review.js +3 -4
- package/tools/roster.js +2 -3
- package/tools/send.js +2 -2
- package/tools/spawn.js +8 -5
- package/tools/status.js +11 -4
- package/tools/teardown.js +2 -3
- package/tools/test.js +2 -2
- package/types/index.d.ts +29 -13
- package/ui-bundle/README.md +37 -3
- package/ui-bundle/client.cards.js +356 -0
- package/ui-bundle/client.denied.js +142 -0
- package/ui-bundle/client.dock.js +333 -0
- package/ui-bundle/client.helpers.js +271 -0
- package/ui-bundle/client.js +79 -1747
- package/ui-bundle/client.locales.js +247 -0
- package/ui-bundle/client.mode.js +206 -0
- package/ui-bundle/client.overlay.js +64 -0
- package/ui-bundle/client.styles.js +151 -0
- package/ui-bundle/client.toolview.js +82 -0
- package/ui-bundle/package.json +1 -0
- package/lib/persistence.js +0 -356
- package/lib/presets.js +0 -35
- package/lib/store.js +0 -133
- /package/{lib → adapters}/stateFile.js +0 -0
- /package/{lib → app}/briefing.js +0 -0
- /package/{lib → app}/spawn-support.js +0 -0
- /package/{lib → host}/compatibility.js +0 -0
- /package/{lib → host}/config.js +0 -0
- /package/{lib → host}/modeState.js +0 -0
|
@@ -73,14 +73,14 @@ merge、worktree 与 spawn 策略。它使用与 profile 配置相同的 JSON
|
|
|
73
73
|
| `spawn.requireLease` | `''` | worker spawn 前必须持有的可选租约名。 |
|
|
74
74
|
| `send.maxPerMinute` | `120` | 每个仓库的 `tower_send` 每分钟速率限制(0 关闭);超出返回 `rate-limited`。 |
|
|
75
75
|
| `send.interruptDefault` | `false`(随包 patch:`true`) | `tower_send.interrupt` 的默认值(投递前先中断运行中的回合)。 |
|
|
76
|
-
| `tests.enabled` | `true` | worktree 的 `package.json`
|
|
76
|
+
| `tests.enabled` | `true` | worktree 的 `package.json` 配置了测试发现时运行它。它只调整可选的 `tower-tests` 组件:该行关闭时既没有 `tower_test` 工具也无法记录回执,`gates.requireTests:true` 会被拒绝而不是静默失效。 |
|
|
77
77
|
| `tests.admission` | `off` | `spawn` 在启动 worker 前运行发现(fail-closed,不启动子代理);`complete` 在 `tower_complete` 时运行;`off` 只在显式 `tower_test` 时运行(默认;不会自动执行仓库代码)。 |
|
|
78
78
|
| `tests.timeoutMs` | `60000` | 每条发现命令的超时。 |
|
|
79
79
|
| `tests.maxBytes` | `16777216`(16 MiB) | 每条命令捕获的 stdout 上限。 |
|
|
80
80
|
| `tests.autoChecks` | `true` | 向完成报告附加自动 `tests` 检查。 |
|
|
81
81
|
| `tests.allowPackageDiscovery` | `true` | 允许仓库控制的 `tower.testDiscovery` 命令(会执行 worktree 代码;见安全页)。 |
|
|
82
82
|
| `gates.requireChecks` | `false` | 合并前要求至少一条 `tower_complete.checks` 证据(`no-check-evidence`)。 |
|
|
83
|
-
| `gates.requireTests` | `false` | 要求针对当前 mission 分支 tip 的通过测试回执(`tests-missing
|
|
83
|
+
| `gates.requireTests` | `false` | 要求针对当前 mission 分支 tip 的通过测试回执(`tests-missing`);与审查门禁独立。`tower-tests` 组件行关闭时,规划/进入模式会带解释拒绝该组合。 |
|
|
84
84
|
| `gates.allowReviewExemption` | `false` | 在 `review.requireReview:true` 时,允许用 `reviewPolicy:"none"` + 非空理由跳过审查 blocker;默认故意关闭;全局审查关闭时无影响。 |
|
|
85
85
|
| `gates.maxReportBytes` | `32768`(32 KiB) | `tower_complete.report` 的 UTF-8 字节硬上限。超出时以 `invalid-argument` 拒绝并给出可执行的 `nextAction`(把全文写进 mission worktree 的文件并引用路径),绝不截断。已存在的超限报告仍可读取。 |
|
|
86
86
|
| `docs.board` | `true` | 变更后写入 `MISSIONS.md`。 |
|
|
@@ -88,16 +88,14 @@ merge、worktree 与 spawn 策略。它使用与 profile 配置相同的 JSON
|
|
|
88
88
|
| `archive.enabled` | `true` | 在变更边界把 worktree 已移除的终态(`merged`/`abandoned`)任务移入 `<git-common-dir>/dsh-tower/archive/`。归档任务保留 tasks、reviews、findings 与完成报告;这是移动,不是删除。 |
|
|
89
89
|
| `archive.afterDays` | `30` | 年龄触发:终态任务超过这么多天未更新,会在下次变更时归档(`0` 表示立即归档)。 |
|
|
90
90
|
| `archive.maxMissions` | `100` | 数量触发:热状态中的终态任务超过此数时,从最旧的开始归档直到满足上限(`0` 表示归档所有符合条件的终态任务)。worktree 仍存在的任务永不归档。 |
|
|
91
|
-
| `tools.exposeOperational` | `true` | 注册 batch/resource/import/legacy/recover/test/doctor 工具;`false` 可缩小固定工具 schema 上下文。 |
|
|
92
91
|
| `leases.ttlMs` | `900000` | 默认咨询式租约寿命;过期不会自动释放。 |
|
|
93
|
-
| `dev.
|
|
94
|
-
| `dev.
|
|
95
|
-
| `dev.reloadRequiredIds` | 五个 Tower loader id | 作为 required 传给 `reconcileProfile` 的条目 id。 |
|
|
92
|
+
| `dev.reloadDelayMs` | `50` | 计划中的 reload 延迟,先让工具结果送达。属于可选的 `tower-hmr` 组件。 |
|
|
93
|
+
| `dev.reloadRequiredIds` | 三个 Tower loader id | `tower-hmr` 组件作为 required 传给 `reconcileProfile` 的条目 id。可选组件行刻意不在 required 中。 |
|
|
96
94
|
|
|
97
95
|
## 示例
|
|
98
96
|
|
|
99
97
|
```yaml
|
|
100
|
-
- id: tower
|
|
98
|
+
- id: tower-host
|
|
101
99
|
name: 'dsh-tower'
|
|
102
100
|
config:
|
|
103
101
|
mode:
|
|
@@ -112,10 +110,12 @@ merge、worktree 与 spawn 策略。它使用与 profile 配置相同的 JSON
|
|
|
112
110
|
reviewerModel:
|
|
113
111
|
provider: deepseek-account
|
|
114
112
|
model: deepseek-flash
|
|
115
|
-
dev:
|
|
116
|
-
hotReload: true
|
|
117
113
|
```
|
|
118
114
|
|
|
115
|
+
可选能力(`tower-skills`、`tower-batch`、`tower-import`、`tower-leases`、
|
|
116
|
+
`tower-tests`、`tower-hmr`、`preset-tower-reviewer`)在插件页切换,而不是用配置键。
|
|
117
|
+
原先用于切换它们的键(`tools.expose*`、`dev.hotReload`)已在 2.4.0 移除,会作为未知键被拒绝。
|
|
118
|
+
|
|
119
119
|
## 查看实际生效的 schema
|
|
120
120
|
|
|
121
121
|
插件声明 `Config` 后(本版本已声明),用 `cordis_inspect_query` 调用
|
|
@@ -11,6 +11,23 @@
|
|
|
11
11
|
{ "id": "git", "status": "pass", "detail": "git version 2.55.0" },
|
|
12
12
|
{ "id": "state", "status": "pass", "detail": ".../state.json revision 7" }
|
|
13
13
|
],
|
|
14
|
+
"stateLock": {
|
|
15
|
+
"held": true,
|
|
16
|
+
"pid": 4242,
|
|
17
|
+
"startedAt": 1761280000000,
|
|
18
|
+
"at": 1761280120000,
|
|
19
|
+
"alive": true,
|
|
20
|
+
"ageMs": 121000,
|
|
21
|
+
"heartbeatAgeMs": 1000,
|
|
22
|
+
"staleAfterMs": 3000,
|
|
23
|
+
"stale": false
|
|
24
|
+
},
|
|
25
|
+
"gitLock": {
|
|
26
|
+
"held": true,
|
|
27
|
+
"pid": 4242,
|
|
28
|
+
"phase": "merge",
|
|
29
|
+
"heldMs": 92000
|
|
30
|
+
},
|
|
14
31
|
"archive": {
|
|
15
32
|
"missions": 3,
|
|
16
33
|
"archivedMissions": 12,
|
|
@@ -33,6 +50,17 @@
|
|
|
33
50
|
}
|
|
34
51
|
```
|
|
35
52
|
|
|
53
|
+
`stateLock`(以及 `state-lock` 检查)报告锁的年龄(`ageMs`,从记录的 `since` 起算)与心跳新鲜度
|
|
54
|
+
(`heartbeatAgeMs`,从最后一次 `at` 起算),并对照过期窗口(`staleAfterMs = 3 × 1000 ms`)。
|
|
55
|
+
PID 存活并不等于写者存活:停止心跳的持有者会报告 `stale: true`,下一次 mutation 会回收它(或用
|
|
56
|
+
`tower_recover clear-stale-lock force:true` 移到备份);心跳新鲜则报告为持有中,绝不会被抢走。
|
|
57
|
+
这样无需手工读取 `state.lock` 就能诊断 PID 被复用的情况。
|
|
58
|
+
|
|
59
|
+
`gitLock`(以及 `git-lock` 检查)报告仓库级 git 互斥锁:被 merge/rebase/init/teardown/provision 持有时为
|
|
60
|
+
`{held, pid, phase, heldMs}`,空闲时为 `{held: false}`。merge 可以合法持有到配置的 merge 超时(默认 15 分钟),
|
|
61
|
+
因此“被持有”是 `warn` 而不是失败;持有者的阶段与时长让卡住的控制塔可被诊断。`tower_status` 返回同一个
|
|
62
|
+
`gitLock` 对象。
|
|
63
|
+
|
|
36
64
|
`archive` 报告终态任务归档:活跃 `missions`、`archivedMissions` 与 `stateBytes`,归档目录的
|
|
37
65
|
`archiveBytes`/`years`/`files`,每条 `unreadable` 诊断,以及配置的 `policy`(`enabled`、`afterDays`、
|
|
38
66
|
`maxMissions`)。归档目录不存在是健康的空归档(`archive` 检查为 `pass`);截断的 index/year 文件是
|
|
@@ -51,7 +79,7 @@ test-discovery 策略、完成报告大小、归档健康度、旧版快照、ba
|
|
|
51
79
|
使用安全的 `case-sensitive` 默认值。
|
|
52
80
|
|
|
53
81
|
检查覆盖:git 可用性、仓库身份、state schema/加载、已探测的大小写模式、仓库配置是否存在、
|
|
54
|
-
worker/reviewer preset 名称、subagents 与 HMR 服务、workspace 锁持有者/是否过期、实时 roster、
|
|
82
|
+
worker/reviewer preset 名称、subagents 与 HMR 服务、state 锁年龄/心跳、workspace 锁持有者/是否过期、实时 roster、
|
|
55
83
|
worktree 是否存在/归属/是否脏、test-discovery 策略、旧版快照、batch 与租约。被 `tower_teardown`
|
|
56
84
|
正常清理的 mission worktree 会被跳过(检查中会注明已移除数量),不会被误报为 missing。`warn` 是提示;`fail` 表示仓库在 spawn/merge 前需要
|
|
57
85
|
处理。state 加载失败会作为失败的检查报告而不是抛出,因此 doctor 在损坏的仓库上仍然有用。
|
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
所有工具都接受 `repoRoot`(目标 Git 仓库内的绝对路径)并返回 JSON。
|
|
6
6
|
本构建最多 29 个工具:下列 19 个核心仓库工具(含 `tower_interrupt`)、`tower_mode`、默认注册的
|
|
7
|
-
`tower_control`(设 `mode.allowAgentControl:false`
|
|
8
|
-
`
|
|
9
|
-
|
|
7
|
+
`tower_control`(设 `mode.allowAgentControl:false` 可禁用)、始终注册的 `tower_doctor` 与
|
|
8
|
+
`tower_recover`(#122),以及由组件行拥有的 `tower_reload`(`tower-hmr`)、`tower_test`
|
|
9
|
+
(`tower-tests`)、`tower_batch`(`tower-batch`)、`tower_resource`(`tower-leases`)、
|
|
10
|
+
`tower_import_legacy` / `tower_legacy_map`(`tower-import`)。关闭某个组件行只会移除它的工具;
|
|
11
|
+
`tower_status` 与 `tower_doctor` 会以 “disabled by component <id>” 报告。
|
|
10
12
|
|
|
11
13
|
`tower_mission` 使用 `id`(别名 `missionId`);其他所有 mission 级工具使用 `missionId`
|
|
12
14
|
(别名 `id`)。其他输入别名:`task_done`/`taskDone`、`task_drop`/`taskDrop`、
|
|
@@ -34,7 +36,7 @@ roster 角色由 `exec.agent` 与 roster 共同决定。mission 级工具(`tow
|
|
|
34
36
|
| `tower_init` | `base?`、`autoGitInit?`、`snapshotDirty?`、`reanchor?` | 创建 `<git-common-dir>/dsh-tower/state.json`。`autoGitInit` 执行 `git init` 并创建空的初始提交;`snapshotDirty` 记录一个游离快照提交作为 mission 基线;`reanchor` 仅在没有非终态 mission 时修改基线。返回 `dirty`、`snapshotCommit`、`reanchored`。 |
|
|
35
37
|
| `tower_plan` | `missions[]`(`title`——可打印 Unicode,NFC 规范化,≤120 字符、`scope[]`、`tasks[]?`、`deps[]?`、`kind?`、`context?`、`references[]?` ≤20、`reviewPolicy?`、`reviewExemptionReason?`) | 创建 mission `M1..`;重叠的 build scope 会自动加依赖;拒绝未知依赖与依赖循环。mission id 保持 ASCII(`M1`、`M2`);不可见字符与超长标题会以 `invalid-argument` 拒绝。`reviewPolicy:"none"` 需要非空理由;审查门禁开启时,preflight 还要求 `gates.allowReviewExemption`。 |
|
|
36
38
|
| `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?` | 默认返回面板。分页 mission 只带 `reportBytes`;`missionId` 返回完整详情(任务/备注/审查/finding/完成报告正文)。`offset`/`limit` 对 mission 分页(默认 20,最大 100),`includeGate` 附带门禁摘要,`format:"markdown"` 返回看板。host 提供 mode hook 时还会包含 `mode.lastChange` 与最近 `history
|
|
39
|
+
| `tower_status` | `missionId?`、`offset?`、`limit?`、`includeGate?`、`format?` | 默认返回面板。分页 mission 只带 `reportBytes`;`missionId` 返回完整详情(任务/备注/审查/finding/完成报告正文)。`offset`/`limit` 对 mission 分页(默认 20,最大 100),`includeGate` 附带门禁摘要,`format:"markdown"` 返回看板。host 提供 mode hook 时还会包含 `mode.lastChange` 与最近 `history`。还返回仓库级 git 互斥锁 `gitLock`(`{held, pid, phase, heldMs}`,空闲时 `{held:false}`)。 |
|
|
38
40
|
| `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
41
|
| `tower_roster` | — | roster 及来自子代理目录的实时活动(`running`/`inactive`/`missing`/`unknown`)与 `stale` 标记。只读。 |
|
|
40
42
|
| `tower_adopt` | `retireMissing?` | 把 roster 条目与持久子代理目录对账。可证明已消失的 agent 会被标记为 retired(默认),或标记为 `missing`(`retireMissing:false`)以便检查/接管。 |
|
|
@@ -45,16 +47,16 @@ roster 角色由 `exec.agent` 与 roster 共同决定。mission 级工具(`tow
|
|
|
45
47
|
| `tower_interrupt` | `to?`(roster 名称)、`agentId?`、`reason?` | 通过 `subagents.interrupt` 中断一个运行中的 roster agent,并记录 `state:"interrupted"`。幂等(未运行 → `interrupted:false`)。 |
|
|
46
48
|
| `tower_finding` | `type`、`title`、`summary`、`details`、`suggested_fix`、`severity?`、`missionId?`、`location?` | 记录 scope 之外的问题;reviewer 用它代替直接改文件。新 finding 初始为 `open`。 |
|
|
47
49
|
| `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
|
|
50
|
+
| `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)。非 clean 结论使 mission 回到 active 后,其他 route 仍可为同一 reviewed tip 提交结论:追加到同一轮(`appended:true`),不再改变状态;tip 已移动时会被明确拒绝。 |
|
|
49
51
|
| `tower_preflight` | `missionId`(别名 `id`) | 只读门禁:返回 `{ok, blockers[], branchTip, baseTip, changedFiles, review}`。 |
|
|
50
52
|
| `tower_merge` | `missionId`(别名 `id`)、`timeoutMs?`(别名 `timeout_ms`) | 门禁全绿后合并。若合并提交已落地则记录(`reconciled`);若命令失败但提交已存在则恢复(`recoveredFromFailure`);区分 `merge-hook-failed` 与 `merge-conflict`。 |
|
|
51
53
|
| `tower_rebase` | `missionId`(别名 `id`) | 在 worktree 内把分支 rebase 到基线。worker 运行中或 worktree 脏时拒绝。分支已包含在基线中时返回 `alreadyMerged` 且保持分支不动。 |
|
|
52
54
|
| `tower_teardown` | `force?`、`exclude?`、`dry_run?`(别名 `dryRun`) | 移除符合条件的 merged/abandoned worktree 与分支;运行中的 agent 始终保留。 |
|
|
53
55
|
| `tower_mode` | — | 报告模式、最近修改、被暂停的 goal、被拒绝的工具、store 路径、插件版本、HMR 可用性、workspace 锁持有者。 |
|
|
54
56
|
| `tower_control` | `action`(`enter`/`exit`)、`reason` | 模型主动切换模式;默认注册,设 `mode.allowAgentControl:false` 可禁用;`reason` 必填。 |
|
|
55
|
-
| `tower_reload` | `repoRoot?` | 仅开发用:请求 DSH HMR 对账 profile 并从磁盘重载 Host 插件。`
|
|
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
|
|
57
|
+
| `tower_reload` | `repoRoot?` | 仅开发用:请求 DSH HMR 对账 profile 并从磁盘重载 Host 插件。`tower-hmr` 组件行开启时注册(该行随包关闭);在工具结果返回后调度(默认 50 ms);没有 HMR 时以 `reload-unavailable` 失败。传入 `repoRoot` 时调用者必须是控制塔。 |
|
|
58
|
+
| `tower_doctor` | —(需要 `repoRoot`) | 只读健康契约:git、state schema、config、preset/subagents/HMR、state 锁的年龄与心跳新鲜度、仓库级 git 锁持有者、workspace 锁、roster、worktree realpath/归属、测试配置、leases。返回 `{ok, checks[{id,status,detail}], stateLock, gitLock, environmentContract}`;`stateLock` 报告 `{held, pid, startedAt, at, alive, ageMs, heartbeatAgeMs, staleAfterMs, stale}`,`gitLock` 报告 `{held, pid, phase, heldMs}`(空闲时 `{held:false}`)并附带 `git-lock` 检查,无需读取文件即可诊断卡住的控制塔。从不写状态。 |
|
|
59
|
+
| `tower_recover` | `action`(`status`/`clear-stale-lock`)、`confirm?`、`force?` | 恢复诊断与显式 stale state-lock 修复。`clear-stale-lock` 需要 `confirm:"CLEAR_STALE_LOCK"`,只把 PID 已死的锁改名为 `.recovered-<ts>` 备份。`force:true` 还能清理 PID 仍存活但心跳静默(PID 被复用)的锁:输出 `{pid, startedAt, ageMs, heartbeatAgeMs}`,记录仍只改名、绝不 unlink。不会重置状态或 worktree。 |
|
|
58
60
|
| `tower_test` | `missionId`(别名 `id`) | 运行 worktree 的 `package.json` 中 `tower.testDiscovery` 配置的发现命令并记录回执;失败时 `ok:false`。自动准入检查请用 `tower_complete`。 |
|
|
59
61
|
| `tower_batch` | `action`(`create`/`status`/`close`/`abandon`)、`missionIds?`、`exclusions?`、`requiredChecks?`、`receiptPaths?`、`batchId?`、`checks?`、`treeTip?`、`receiptHashes?`、`reason?` | 有限证据批次。create 冻结成员/检查/回执;close 校验每条必需检查与回执哈希;`merged` 成员也可参与 close;abandon 可退掉过期的 open batch 且不删除 mission。成员关系不可变。 |
|
|
60
62
|
| `tower_resource` | `action`(`acquire`/`release`/`status`)、`name?`、`holder?`、`token?`、`ttlMs?`、`force?` | 每个仓库的咨询式租约,位于 `<common>/dsh-tower/leases.json`。没有 OS CPU/内存硬上限;过期的租约需要显式 `force` 与正确 token。 |
|
package/domain/batch.js
CHANGED
|
@@ -120,7 +120,7 @@ function normalizeReceiptPathOrNull(value, where) {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
/** Legacy snapshots imported by
|
|
123
|
+
/** Legacy snapshots imported by adapters/legacy.js; only paused missions may be excluded. */
|
|
124
124
|
function pausedLegacyIds(state) {
|
|
125
125
|
const ids = new Set()
|
|
126
126
|
const collectMission = (mission) => {
|
|
@@ -138,7 +138,7 @@ function pausedLegacyIds(state) {
|
|
|
138
138
|
collectList(snapshot.missions)
|
|
139
139
|
if (isPlainObject(snapshot.snapshot)) collectList(snapshot.snapshot.missions)
|
|
140
140
|
if (isPlainObject(snapshot.payload)) collectList(snapshot.payload.missions)
|
|
141
|
-
//
|
|
141
|
+
// adapters/legacy.js stores imported snapshots with `pausedMissionIds`; older,
|
|
142
142
|
// hand-written fixtures may use `pausedIds`.
|
|
143
143
|
for (const key of ['pausedIds', 'pausedMissionIds']) {
|
|
144
144
|
if (Array.isArray(snapshot[key])) {
|