dsh-tower 1.3.0 → 2.0.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/CONTRIBUTING.md +1 -1
  3. package/README.en.md +22 -8
  4. package/README.md +20 -8
  5. package/cordis.patch.yml +10 -0
  6. package/docs/README.md +8 -4
  7. package/docs/architecture/overview.md +13 -9
  8. package/docs/faq.md +33 -2
  9. package/docs/guide/hot-reload.md +189 -0
  10. package/docs/guide/install-upgrade-migration.md +11 -0
  11. package/docs/guide/quickstart.md +33 -1
  12. package/docs/operations/runbook.md +23 -0
  13. package/docs/operations/security.md +23 -0
  14. package/docs/reference/blockers.md +10 -2
  15. package/docs/reference/config.md +65 -2
  16. package/docs/reference/doctor.md +31 -0
  17. package/docs/reference/errors.md +50 -0
  18. package/docs/reference/events.md +45 -0
  19. package/docs/reference/operations.md +52 -0
  20. package/docs/reference/testing.md +61 -0
  21. package/docs/reference/tools.md +65 -23
  22. package/docs/zh/README.md +58 -0
  23. package/docs/zh/faq.md +72 -0
  24. package/docs/zh/guide/hot-reload.md +178 -0
  25. package/docs/zh/guide/install-upgrade-migration.md +57 -0
  26. package/docs/zh/guide/quickstart.md +96 -0
  27. package/docs/zh/operations/security.md +42 -0
  28. package/docs/zh/reference/blockers.md +62 -0
  29. package/docs/zh/reference/config.md +113 -0
  30. package/docs/zh/reference/doctor.md +30 -0
  31. package/docs/zh/reference/errors.md +52 -0
  32. package/docs/zh/reference/events.md +46 -0
  33. package/docs/zh/reference/operations.md +48 -0
  34. package/docs/zh/reference/testing.md +60 -0
  35. package/docs/zh/reference/tools.md +75 -0
  36. package/index.js +261 -13
  37. package/lib/batch.js +578 -0
  38. package/lib/config.js +270 -8
  39. package/lib/doctor.js +165 -0
  40. package/lib/errors.js +111 -0
  41. package/lib/hmr.js +196 -0
  42. package/lib/leases.js +317 -0
  43. package/lib/legacy.js +413 -0
  44. package/lib/modeStore.js +28 -1
  45. package/lib/store.js +24 -1
  46. package/lib/tests.js +628 -0
  47. package/lib/tools.js +1554 -182
  48. package/lib/tower.js +957 -102
  49. package/lib/workspaceLock.js +117 -0
  50. package/lib/worktreeOwnership.js +166 -0
  51. package/package.json +4 -1
  52. package/reviewer.js +1 -0
  53. package/scripts/check-docs.mjs +135 -0
  54. package/scripts/enable-dev-hmr.mjs +347 -0
  55. package/skills/tower-review.md +4 -2
  56. package/skills/tower-worker-protocol.md +3 -1
  57. package/worker.js +4 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,82 @@
1
1
  # Changelog
2
2
 
3
+ > 自 2.0.0 起,每个版本按 **新增 / 变更 / 修复** 三类组织;更早的版本保留原始流水式记录。
4
+
5
+ ## 2.0.0(2026-10-18)
6
+
7
+ ### 新增
8
+
9
+ - **仓库级配置层**:`Tower.open()` 读取 `<git-common-dir>/dsh-tower/config.json`,优先级为
10
+ 代码默认 < profile 配置 < 仓库配置 < 工具参数;`review`/`merge`/`worktrees`/`spawn` 分组生效。
11
+ - **稳定工具错误码**:新增 `lib/errors.js`,工具失败统一 `[tower:<code>]` 前缀,覆盖 17 个 code;
12
+ 新增 `docs/reference/errors.md` 并由 `npm run docs:check` 校验。
13
+ - **finding 生命周期**:新增 `tower_findings`(列表/读取/状态流转/备注),状态为
14
+ `open → triaged → fixed` / `wontfix` 且可重新打开;只有 tower 或 worker 能改状态,reviewer 只读。
15
+ - **中文文档**:新增 `docs/zh/`(文档索引、quickstart、工具/配置/blocker/错误码参考),
16
+ 与英文参考页保持同一套工具名、blocker 与错误码。
17
+ - **测试与门禁**:新增仓库配置、finding 生命周期、工具别名/错误码/输出 schema、spawn mock
18
+ 与全流程 schema 校验用例;`docs:check` 同时校验中英文参考页、工具名、blocker 与错误码。
19
+ - **协议硬化**:`tower_interrupt`(停止 running agent)、`tower_send(interrupt:true)`;
20
+ `tower_init` 支持 `autoGitInit`/`snapshotDirty`/`reanchor`;worker 不能直接完成/放弃/扩界,
21
+ completed 必须经 `tower_complete`;单 mission 单活 worker + `takeover` 接管 + generation。
22
+ - **治理与可观测**:可选 `mode.workspaceLock` 仓库互斥;`spawn.maxLiveWorkers`、`send.maxPerMinute`
23
+ 与 roster stale 标记;`tower_status` 分页/单 mission 明细/gate digest/markdown;`MISSIONS.md`
24
+ 人类可读门板;`tower/*` 进程内事件;`tower_complete.checks` + `gates.requireChecks`。
25
+ - **热重载**:`/tower reload` 与 `tower_reload` 调用 DSH HMR `reconcileProfile`;新增
26
+ `npm run dev:hmr` 脚本把 linked 仓库加入 profile HMR watch root;`docs/guide/hot-reload.md`。
27
+ - **2.1 测试准入**:读取 worktree `package.json` 的 `tower.testDiscovery`(TAP/json-array),支持
28
+ `tests.admission:spawn|complete`、16 MiB/60s 预算、minCount/required;`tower_test` 与
29
+ `tower_complete` 自动生成 `tests` check;`gates.requireTests` / `tests-missing` / `tests-failed`。
30
+ - **2.1 批次与运营**:`tower_batch`(create/status/close,冻结成员、requiredChecks、receiptPaths)、
31
+ `tower_resource`(advisory lease,token/过期显式 force)、`tower_doctor`(只读健康契约)、
32
+ `tower_import_legacy` / `tower_legacy_map`(只读快照 + 审计映射)。
33
+ - **2.1 治理**:per-repo roster watchdog(`spawn.staleMs` 15s 标记 stale 并阻断合并)、
34
+ `spawn.maxWaitMs` 90s、`mode.workspaceLockScope`、plan/tower 互斥(默认清除 plan)、
35
+ `/tower base <branch>`、`docs.boardLocation`、delivery ack、merge intent 持久化。
36
+ - **2.1 UI**:ui-bundle 增加 12 个 tower tool 卡片、composer dock 最新摘要与 shell.overlay 瞬时状态条;
37
+ 纯会话派生,无 Host RPC/iframe。
38
+ - **2.1 文档**:`docs/reference/testing.md`、`operations.md`、`doctor.md` 与中文同步;工具面 28。
39
+
40
+ ### 变更
41
+
42
+ - **结构化输出 schema**:全部工具声明 output schema(spawn/status/diff/merge/review/preflight
43
+ 等核心工具含字段结构),并按 DSH 的输出校验规则保证可空字段可空。
44
+ - **命名统一(兼容别名)**:mission 级工具同时接受 `id` 与 `missionId`;`task_done`/`taskDone`、
45
+ `task_drop`/`taskDrop`、`clear_blockers`/`clearBlockers`、`include_read`/`includeRead`、
46
+ `dry_run`/`dryRun`、`timeoutMs`/`timeout_ms`、`waitMs`/`wait_ms` 等写法均可,并在参数 schema
47
+ 中显式声明;输出保持既有规范。
48
+ - **诊断信息**:`tower_status` 增加 `config.path`、`config.repoConfigPresent` 与
49
+ `findingsByStatus`;worker/reviewer preset 允许 `tower_findings`。
50
+ - **配置解析**:兼容别名只用于补缺——同时设置 `section` 与 `mode.promptSection` 时规范键优先;
51
+ 仓库配置增加 1 MiB 大小上限与 `__proto__`/`constructor`/`prototype` 等危险键拒绝。
52
+ - **配置默认值**:`mode.denyTools` 追加 workflow/ralph/subagent/subagent_fork/wait_agent/team_task_list
53
+ (Tower 模式与其它编排互斥);新增 `spawn.maxLiveWorkers:4`、`spawn.staleMs:15000`、
54
+ `spawn.maxWaitMs:90000`、`send.maxPerMinute:120`、`gates.requireChecks:false`、
55
+ `gates.requireTests:false`、`docs.board:true`、`leases.ttlMs:900000`、`dev.hotReload:true`;
56
+ 随包 patch 打开 `workspaceLock`/`interruptDefault`/`autoGitInit`。
57
+ - **briefing**:worker/reviewer 生成历史审查、上一轮 findings/decision、completion checks 与
58
+ related findings,长文本截断;reviewer 必须核对 completion checks。
59
+ - **输出/工具面**:`tower_status` 增加 total/offset/nextOffset/detail/markdown,并**默认只返回前 20 个 mission**(旧版返回全部;旧调用需要更多时用 `limit`/`offset`);`tower_adopt`
60
+ 支持 `retireMissing:false`;`tower_mode` 返回 pluginVersion/HMR/workspace lock;`tower_roster`
61
+ 增加 `stale`。工具总数最多 28(含 doctor/test/batch/resource/import/legacy_map 与可选的 control/reload)。
62
+ - **离线套件**:测试增至 206 项(含 2.1 discovery/batch/leases/legacy/doctor/UI/plan-mode/integration 用例)。
63
+ - 除 `tower_status` 默认分页与 `mode.denyTools` 默认扩充外,既有工具参数与输出保持兼容。
64
+
65
+ ### 修复
66
+
67
+ - **模式工具 schema 与返回值不一致**:`tower_mode`/`tower_control` 的 `lastChange`、`pausedGoal`、
68
+ `goalNote` 在正常路径返回 `null`,原 schema 会触发 DSH 强制输出校验失败;已改为可空并补回归测试。
69
+ - **错误码分类补全**:state 校验失败统一归为 `state-corrupt`;`tower_complete` 的未完成任务、
70
+ blocker、无提交、未读消息等前置条件归为 `invalid-transition`,不再落到 `tool-internal`。
71
+ - **findings 更新后的计数**:状态流转后返回的 `counts` 之前是旧值,现在按变更后重新统计。
72
+ - **findings 只读路径**:列表/读取不再获取写锁,与工具描述一致,长合并或 hook 期间也能读取。
73
+ - **mission id 规范化**:`tower_mission` 对首尾空白的 `id` 先 trim 再查找,不再误报
74
+ `mission-not-found`。
75
+ - **角色绕过**:worker 之前可经 `tower_mission` 直接 completed/abandoned/扩界或清 blocker,
76
+ 绕过 `tower_complete` 的未读/提交证据;现由服务端角色强制。
77
+ - **并发与接管**:同一 mission 不再允许出现第二个 live worker;stale/interrupted/failed 的
78
+ worker 可显式 takeover,running worker 必须先中断,否则 `takeover-refused`。
79
+
3
80
  ## 1.3.0 — 2026-10-18
4
81
 
5
82
  - **独立的只读 reviewer preset**:新增 `reviewer.js` / `tower-reviewer`,去掉 `write`/`edit`/`pwsh`/
package/CONTRIBUTING.md CHANGED
@@ -21,7 +21,7 @@ Requirements: Node.js 22+, Git. No package installation is needed for the offlin
21
21
 
22
22
  ## Pull request checklist
23
23
 
24
- 1. `npm test` passes locally (26 tests today, including protocol end-to-end against a real temporary Git repository) and `npm run docs:check` passes.
24
+ 1. `npm test` passes locally (206 tests today, including protocol end-to-end against a real temporary Git repository and mock spawn coverage) and `npm run docs:check` passes.
25
25
  2. New behavior has a test. Bug fixes should add a test that fails before the fix.
26
26
  3. No secrets, tokens, personal paths, session logs, or generated artifacts are added. `.gitignore` covers local acceptance output; do not force-add it.
27
27
  4. Keep the public API and state-file formats compatible; if a change is breaking, call it out in `CHANGELOG.md` and bump the version.
package/README.en.md CHANGED
@@ -18,6 +18,14 @@ The repository root **is** the DSH bundle: `package.json` declares `dsh.bundle.p
18
18
  - **Review-gated merges.** A reviewer bound to the current branch tip must submit a `clean` / `merge` verdict; the merge gate re-checks scope, staleness, task completion, review history, and worktree ownership before a `--no-ff` merge.
19
19
  - **Durable coordination.** Roster, inbox, findings, reviews, and mission state are persisted under `.git/dsh-tower/`, so a restart does not lose the plan.
20
20
  - **Safe by default.** While Tower mode is active, `create_goal`, `update_goal(resume)`, `todo_write`, the Team task board, and `spawn_teammate` are refused; a paused goal is never resumed automatically.
21
+ - **Traceable finding lifecycle.** `tower_findings` lists, reads, and moves findings through `open → triaged → fixed` / `wontfix` (and can reopen); only the tower or a worker may change state, while reviewers can only read.
22
+ - **Repository-level config.** Any repository can override review/merge/worktree/spawn policy in `<git-common-dir>/dsh-tower/config.json`; tool arguments override the repository layer, so no profile edit is needed per repository.
23
+ - **Stable error codes.** Tool failures carry a `[tower:<code>]` prefix (for example `mission-not-found`, `preset-missing`, `config-invalid`) so callers can branch deterministically.
24
+ - **Role enforcement and control.** Workers cannot complete/abandon a mission or widen its scope directly (completion goes through the `tower_complete` evidence gate); the tower can stop a runaway agent with `tower_interrupt`, and `tower_send(interrupt:true)` interrupts a running turn.
25
+ - **Workspace exclusivity and limits.** Optional `mode.workspaceLock` allows one Tower session per repository; `spawn.maxLiveWorkers`, `send.maxPerMinute` and roster stale flags bound concurrency and message bursts.
26
+ - **2.1 verification and operations.** `tower_test` runs the worktree's `tower.testDiscovery` (TAP/json-array, admission at spawn or complete), `tower_doctor` is a read-only health contract, `tower_batch` closes finite evidence batches, `tower_resource` manages advisory leases, and `tower_import_legacy`/`tower_legacy_map` import old snapshots and audit-map ids. Adds `worker-stale`, test gates, plan/Tower mutual exclusion, `workspaceLockScope`, `docs.boardLocation` and delivery acknowledgements.
27
+ - **Hot reload.** In a profile with DSH HMR, `/tower reload`, `tower_reload` and `npm run dev:hmr` apply linked plugin changes without a restart; `plugin_manager` install/update already applies live.
28
+ - **Evidence gate and events.** Workers can record `checks` in `tower_complete` and `gates.requireChecks` can require them; every mutation emits `tower/*` events and refreshes `MISSIONS.md`.
21
29
 
22
30
  ## Requirements
23
31
 
@@ -105,14 +113,16 @@ Image and file attachments are forwarded together with the instruction as one co
105
113
  maxDepth: 1
106
114
  ```
107
115
 
108
- - `mode.allowAgentControl` defaults to `false` in code; the bundled `cordis.patch.yml` enables it (`true`) so the model may enter/leave when the user intent or task state warrants it, always stating a reason.
109
- - Every key and default is in [docs/reference/config.md](docs/reference/config.md); unknown keys are rejected so typos cannot silently disable security-relevant settings.
116
+ - `mode.allowAgentControl` defaults to `false` in code; the bundled `cordis.patch.yml` enables it (`true`) so the model may enter/leave when the user intent or task state warrants it, always stating a reason. The bundled patch also enables `mode.workspaceLock` (single-active tower), `send.interruptDefault`, `init.autoGitInit`, and sets `spawn.staleMs` to 15s.
117
+ - `/tower base <branch>` records a session-level init base preference; `/tower on` clears an active plan mode (`mode.planModePolicy:"refuse"` instead refuses entry), keeping plan and Tower mutually exclusive.
118
+ - Repository-level config: put the same JSON shape in `<git-common-dir>/dsh-tower/config.json` (usually `.git/dsh-tower/config.json`) to override `review`/`merge`/`worktrees`/`spawn`. Precedence is code defaults < profile config < repository config < tool arguments. `mode.*` is session-scoped and only the profile layer controls it.
119
+ - Every key and default is in [docs/reference/config.md](docs/reference/config.md); unknown top-level keys are rejected so typos cannot silently disable security-relevant settings, while unknown keys inside a group are ignored. Tool error codes are in [docs/reference/errors.md](docs/reference/errors.md).
110
120
 
111
- ## Tools (18)
121
+ ## Tools (26 core)
112
122
 
113
- `tower_init` · `tower_plan` · `tower_mission` · `tower_status` · `tower_spawn` · `tower_roster` · `tower_adopt` · `tower_diff` · `tower_send` · `tower_inbox` · `tower_complete` · `tower_finding` · `tower_review` · `tower_preflight` · `tower_merge` · `tower_rebase` · `tower_teardown` · `tower_mode`
123
+ `tower_init` · `tower_plan` · `tower_mission` · `tower_status` · `tower_spawn` · `tower_roster` · `tower_adopt` · `tower_diff` · `tower_send` · `tower_inbox` · `tower_complete` · `tower_interrupt` · `tower_finding` · `tower_findings` · `tower_review` · `tower_preflight` · `tower_merge` · `tower_rebase` · `tower_teardown` · `tower_mode` · `tower_doctor` · `tower_test` · `tower_batch` · `tower_resource` · `tower_import_legacy` · `tower_legacy_map`
114
124
 
115
- `tower_control` exists only when `allowAgentControl: true` (the bundled patch enables it, so an installed build exposes 19 tools).
125
+ `tower_control` exists only when `allowAgentControl: true`; `tower_reload` is registered while `dev.hotReload` is on (default true) and returns `reload-unavailable` without an HMR service (so up to 28 tools). Mission-scoped tools also accept `id` as an alias for `missionId`; snake/camel spellings such as `task_done`/`taskDone` are both accepted.
116
126
 
117
127
  ## Safety and guardrails
118
128
 
@@ -122,7 +132,7 @@ Image and file attachments are forwarded together with the instruction as one co
122
132
  - **Worktree ownership.** Dirty worktrees, a running worker, or a branch owned by a closed mission block teardown/merge.
123
133
  - **Goal isolation.** Entering Tower mode pauses the active goal and records it; leaving does not resume it. Use `/tower off` and resume the goal yourself.
124
134
 
125
- 13 stable blocker codes (plus 6 additional gate guards and 6 merge/rebase failure codes) — the complete list with triggers and fixes is in [docs/reference/blockers.md](docs/reference/blockers.md).
135
+ 32 stable blocker/failure codes (including gate guards, `no-check-evidence`, `worker-stale`, test gates, and merge/rebase operation failures) — the complete list with triggers and fixes is in [docs/reference/blockers.md](docs/reference/blockers.md). Tool-level error codes are in [docs/reference/errors.md](docs/reference/errors.md); events are in [docs/reference/events.md](docs/reference/events.md).
126
136
 
127
137
  ## How it works
128
138
 
@@ -156,13 +166,17 @@ Workers use the bundled `tower-worker` preset (writable worktree surface); revie
156
166
  npm test # node --test tests/*.test.mjs
157
167
  ```
158
168
 
169
+ Hot-reload development: `npm run dev:hmr` adds this checkout to the current profile's HMR watch roots
170
+ (one DSH restart); afterwards `/tower reload` or the automatic watcher applies `lib/` edits. See
171
+ [docs/guide/hot-reload.md](docs/guide/hot-reload.md).
172
+
159
173
  The offline suite needs no DSH process and creates throwaway Git repositories in the OS temp directory. `tests/README.md` documents the isolated Web-runtime checks, model-driven acceptance, and the session-diagnostic scripts used while hardening the plugin.
160
174
 
161
175
  ## Documentation
162
176
 
163
177
  - [docs/README.md](docs/README.md) — documentation index (new user / operator / maintainer paths)
164
- - [Quick start](docs/guide/quickstart.md) · [Install, upgrade and migration](docs/guide/install-upgrade-migration.md)
165
- - [Tools reference](docs/reference/tools.md) · [Config reference](docs/reference/config.md) · [Blockers and failure codes](docs/reference/blockers.md)
178
+ - [Chinese docs](docs/zh/README.md) · [Quick start](docs/guide/quickstart.md) · [Install, upgrade and migration](docs/guide/install-upgrade-migration.md)
179
+ - [Tools reference](docs/reference/tools.md) · [Config reference](docs/reference/config.md) · [Blockers and failure codes](docs/reference/blockers.md) · [Error codes](docs/reference/errors.md) · [Events](docs/reference/events.md) · [Testing](docs/reference/testing.md) · [Batches/leases/legacy](docs/reference/operations.md) · [Doctor](docs/reference/doctor.md) · [Hot reload](docs/guide/hot-reload.md)
166
180
  - [Architecture and state machine](docs/architecture/overview.md) · [Operations runbook](docs/operations/runbook.md) · [Security model](docs/operations/security.md)
167
181
  - [FAQ](docs/faq.md) · [Examples](docs/examples/first-mission.md)
168
182
 
package/README.md CHANGED
@@ -18,6 +18,14 @@ Tower 模式与 mission/审查工作流的灵感来自 Moonshot AI 的 **Kimi Co
18
18
  - **审查门禁合并。** 审查者必须针对当前分支 tip 给出 `clean` / `merge` 结论;合并门禁重新校验 scope、分支新鲜度、任务完成度、审查记录与 worktree 归属,通过后才执行 `--no-ff` 合并。
19
19
  - **可恢复的协作状态。** roster、inbox、findings、reviews 与 mission 状态持久化在 `.git/dsh-tower/` 下,重启不会丢计划。
20
20
  - **默认安全。** Tower 模式开启期间拒绝 `create_goal`、`update_goal(resume)`、`todo_write`、Team 任务板与 `spawn_teammate`;被暂停的 goal 不会被自动恢复。
21
+ - **可追溯的 finding 生命周期。** `tower_findings` 列表、读取并按 `open → triaged → fixed` / `wontfix` 流转,也可重新打开;只有 tower 或 worker 能改状态,reviewer 只能读。
22
+ - **仓库级配置。** 每个仓库可用 `<git-common-dir>/dsh-tower/config.json` 覆盖 review/merge/worktree/spawn 策略,工具参数再覆盖仓库配置;无需为不同仓库改 profile。
23
+ - **稳定错误码。** 工具失败统一带 `[tower:<code>]` 前缀(如 `mission-not-found`、`preset-missing`、`config-invalid`),调用方可稳定分支处理。
24
+ - **角色强制与可控中断。** worker 不能直接完成/放弃 mission 或扩界(完成必须走 `tower_complete` 证据门),tower 可随时用 `tower_interrupt` 停止跑偏的 agent;`tower_send(interrupt:true)` 可中止运行中的 turn。
25
+ - **仓库互斥与限流。** 可选 `mode.workspaceLock` 让同一仓库只有一个 Tower 会话;`spawn.maxLiveWorkers`、`send.maxPerMinute`、roster stale 标记约束并发与消息风暴。
26
+ - **可热重载。** 在带 DSH HMR 的 profile 中,`/tower reload`、`tower_reload` 与 `npm run dev:hmr` 让 linked 插件代码改动无需重启即生效;`plugin_manager` 安装/更新本身即时生效。
27
+ - **测试证据门与事件。** worker 可在 `tower_complete` 记录 `checks`,`gates.requireChecks` 可强制;每次 mutation 后发射 `tower/*` 事件并刷新 `MISSIONS.md`。
28
+ - **2.1 验证与运营。** `tower_test` 执行 worktree 声明的 `tower.testDiscovery`(TAP/json-array,准入可设 spawn/complete),`tower_doctor` 只读健康契约,`tower_batch` 批次证据收口,`tower_resource` advisory lease,`tower_import_legacy` / `tower_legacy_map` 只读旧版导入与审计映射;新增 `worker-stale`、tests 门禁、plan/tower 互斥、`workspaceLockScope`、`docs.boardLocation` 与交付 ack。
21
29
 
22
30
  ## 环境要求
23
31
 
@@ -105,14 +113,16 @@ tower_teardown repoRoot=D:\work\repo
105
113
  maxDepth: 1
106
114
  ```
107
115
 
108
- - 代码中 `mode.allowAgentControl` 默认 `false`;随包 `cordis.patch.yml` 设为 `true`:模型可在用户意图/任务状态明确时自行进出,但必须给出理由;设为 `false` 时只有人类能切换。
109
- - 所有键与默认值见 [docs/reference/config.md](docs/reference/config.md);未知键会被拒绝(防止拼写错误静默失效)。
116
+ - 代码中 `mode.allowAgentControl` 默认 `false`;随包 `cordis.patch.yml` 设为 `true`:模型可在用户意图/任务状态明确时自行进出,但必须给出理由;设为 `false` 时只有人类能切换。随包 patch 还默认开启 `mode.workspaceLock`(单活塔)、`send.interruptDefault`、`init.autoGitInit`,并把 `spawn.staleMs` 设为 15s。
117
+ - `/tower base <branch>` 可设置会话级 init base 偏好;`/tower on` 会清除活跃 plan mode(`mode.planModePolicy:"refuse"` 则拒绝进入),保证 plan/tower 互斥。
118
+ - 仓库级配置:在 `<git-common-dir>/dsh-tower/config.json`(通常是 `.git/dsh-tower/config.json`)放入同样的 JSON 结构,可覆盖 `review`/`merge`/`worktrees`/`spawn`;优先级为代码默认 < profile < 仓库配置 < 工具参数。`mode.*` 属于会话级,只在 profile 生效。
119
+ - 所有键与默认值见 [docs/reference/config.md](docs/reference/config.md);未知顶层键会被拒绝(防止拼写错误静默失效),嵌套分组内的未知键会被忽略。工具错误码见 [docs/reference/errors.md](docs/reference/errors.md)。
110
120
 
111
- ## 工具(18 个)
121
+ ## 工具(26 个核心)
112
122
 
113
- `tower_init` · `tower_plan` · `tower_mission` · `tower_status` · `tower_spawn` · `tower_roster` · `tower_adopt` · `tower_diff` · `tower_send` · `tower_inbox` · `tower_complete` · `tower_finding` · `tower_review` · `tower_preflight` · `tower_merge` · `tower_rebase` · `tower_teardown` · `tower_mode`
123
+ `tower_init` · `tower_plan` · `tower_mission` · `tower_status` · `tower_spawn` · `tower_roster` · `tower_adopt` · `tower_diff` · `tower_send` · `tower_inbox` · `tower_complete` · `tower_interrupt` · `tower_finding` · `tower_findings` · `tower_review` · `tower_preflight` · `tower_merge` · `tower_rebase` · `tower_teardown` · `tower_mode` · `tower_doctor` · `tower_test` · `tower_batch` · `tower_resource` · `tower_import_legacy` · `tower_legacy_map`
114
124
 
115
- `tower_control` 仅在 `allowAgentControl: true` 时存在(随包 patch 默认开启,因此安装后共 19 个工具)。
125
+ `tower_control` 仅在 `allowAgentControl: true` 时注册;`tower_reload` 在 `dev.hotReload`(默认 true)时注册,无 HMR 服务调用会返回 `reload-unavailable`(因此最多 28 个工具)。mission 级工具同时接受 `id` 作为 `missionId` 的别名;`task_done`/`taskDone` 等 snake/camel 写法均可。
116
126
 
117
127
  ## 安全与约束
118
128
 
@@ -122,7 +132,7 @@ tower_teardown repoRoot=D:\work\repo
122
132
  - **worktree 归属。** 脏工作树、运行中的 worker、已关闭 mission 的分支都会阻止合并或 teardown。
123
133
  - **goal 隔离。** 进入 Tower 模式会暂停活跃 goal 并记录;退出不会自动恢复,需要你自行恢复。
124
134
 
125
- 13 个稳定 blocker code(另有 6 个 gate 守卫与 6 个 merge/rebase 操作失败码)——完整清单、触发条件与修复动作见 [docs/reference/blockers.md](docs/reference/blockers.md)。
135
+ 32 个稳定 blocker/failure code(含 gate 守卫、`no-check-evidence`、worker-stale、tests 门禁与 merge/rebase 操作失败码)——完整清单、触发条件与修复动作见 [docs/reference/blockers.md](docs/reference/blockers.md)。工具本身抛出的错误码见 [docs/reference/errors.md](docs/reference/errors.md),事件见 [docs/reference/events.md](docs/reference/events.md)。
126
136
 
127
137
  ## 工作原理
128
138
 
@@ -154,13 +164,15 @@ worker 与 reviewer 是使用内置 `tower-worker` preset 的普通 DSH 子代
154
164
  npm test # node --test tests/*.test.mjs
155
165
  ```
156
166
 
167
+ 热重载开发:`npm run dev:hmr` 把本仓库加入当前 profile 的 HMR watch root(需重启 DSH 一次),之后编辑 `lib/` 代码可用 `/tower reload` 或自动 watch 生效;详见 [docs/guide/hot-reload.md](docs/guide/hot-reload.md)。
168
+
157
169
  离线套件不需要 DSH 进程,只在系统临时目录创建一次性 Git 仓库。隔离 Web 运行时检查、模型驱动验收和会话诊断脚本见 `tests/README.md`。
158
170
 
159
171
  ## 文档
160
172
 
161
173
  - [docs/README.md](docs/README.md) — 文档索引(新用户 / 运维 / 维护者三条阅读路径)
162
- - [快速开始](docs/guide/quickstart.md) · [安装、升级与迁移](docs/guide/install-upgrade-migration.md)
163
- - [工具参考](docs/reference/tools.md) · [配置参考](docs/reference/config.md) · [blocker 与失败码](docs/reference/blockers.md)
174
+ - [中文文档](docs/zh/README.md) · [快速开始](docs/guide/quickstart.md) · [安装、升级与迁移](docs/guide/install-upgrade-migration.md)
175
+ - [工具参考](docs/reference/tools.md) · [配置参考](docs/reference/config.md) · [blocker 与失败码](docs/reference/blockers.md) · [错误码](docs/reference/errors.md) · [事件](docs/reference/events.md) · [测试准入](docs/reference/testing.md) · [批次/租约/旧版](docs/reference/operations.md) · [Doctor](docs/reference/doctor.md) · [热重载](docs/guide/hot-reload.md)
164
176
  - [架构与状态机](docs/architecture/overview.md) · [运维 runbook](docs/operations/runbook.md) · [安全模型](docs/operations/security.md)
165
177
  - [FAQ](docs/faq.md) · [示例](docs/examples/first-mission.md)
166
178
 
package/cordis.patch.yml CHANGED
@@ -3,6 +3,16 @@
3
3
  name: 'dsh-tower'
4
4
  config:
5
5
  allowAgentControl: true
6
+ init:
7
+ autoGitInit: true
8
+ mode:
9
+ workspaceLock: true
10
+ workspaceLockScope: all
11
+ planModePolicy: clear
12
+ send:
13
+ interruptDefault: true
14
+ spawn:
15
+ staleMs: 15000
6
16
  - id: tower-skills
7
17
  name: 'dsh-tower/skills'
8
18
  - id: preset-tower-worker
package/docs/README.md CHANGED
@@ -1,13 +1,17 @@
1
1
  # dsh-tower documentation
2
2
 
3
+ English is the source of truth; a Chinese translation lives in [zh/README.md](zh/README.md).
4
+
3
5
  Choose a path:
4
6
 
5
7
  | You are | Start here |
6
8
  |---|---|
7
9
  | New user | [Quick start](guide/quickstart.md) → [Tools](reference/tools.md) → [Example](examples/first-mission.md) |
8
- | Operator | [Runbook](operations/runbook.md) → [Blockers](reference/blockers.md) → [Security](operations/security.md) |
9
- | Maintainer | [Architecture](architecture/overview.md) → [Config](reference/config.md) → [Contributing](../CONTRIBUTING.md) |
10
+ | Operator | [Runbook](operations/runbook.md) → [Blockers](reference/blockers.md) → [Error codes](reference/errors.md) → [Events](reference/events.md) → [Doctor](reference/doctor.md) → [Testing](reference/testing.md) → [Batches/leases/legacy](reference/operations.md) → [Security](operations/security.md) |
11
+ | Maintainer | [Architecture](architecture/overview.md) → [Config](reference/config.md) → [Hot reload](guide/hot-reload.md) → [Contributing](../CONTRIBUTING.md) |
10
12
 
11
- Reference pages are the source of truth for the current release; the [tools reference](reference/tools.md) and [blocker list](reference/blockers.md) are checked by `npm run docs:check` in CI.
13
+ Reference pages are the source of truth for the current release; the [tools reference](reference/tools.md),
14
+ [blocker list](reference/blockers.md) and [error codes](reference/errors.md) are checked against the
15
+ implementation by `npm run docs:check` in CI (including the Chinese pages).
12
16
 
13
- Other useful pages: [Install, upgrade and migration](guide/install-upgrade-migration.md), [FAQ](faq.md), [CHANGELOG](../CHANGELOG.md).
17
+ Other useful pages: [Install, upgrade and migration](guide/install-upgrade-migration.md), [Hot reload](guide/hot-reload.md), [FAQ](faq.md), [CHANGELOG](../CHANGELOG.md).
@@ -4,16 +4,20 @@
4
4
 
5
5
  ```
6
6
  Host plugin (index.js)
7
- ├─ /tower command + Tower mode (guard, prompt section, tower_control)
8
- ├─ lib/tools.js -> 17 tools (+ tower_diff) registered on ctx.tools
9
- └─ lib/tower.js -> Tower domain: missions, gates, worktrees, roster, review, merge
10
- ├─ lib/git.js minimal git port (execFile, bounded output, timeout classification)
11
- ├─ lib/store.js repo-scoped lock + atomic JSON + activity.jsonl
12
- ├─ lib/config.js Config schema + runtime snapshot
13
- └─ lib/modeStore.js per-agent Tower mode persistence
7
+ ├─ /tower command + Tower mode (guard, prompt section, tower_mode/tower_control, /tower reload)
8
+ ├─ lib/tools.js -> 19 repository tools incl. tower_diff, tower_findings and tower_interrupt
9
+ │ (+ tower_reload while dev.hotReload is on; fails reload-unavailable without HMR)
10
+ └─ lib/tower.js -> Tower domain: missions, gates, worktrees, roster, review, findings, merge
11
+ ├─ lib/git.js minimal git port (execFile, bounded output, timeout classification)
12
+ ├─ lib/store.js repo-scoped lock + atomic JSON + activity.jsonl
13
+ ├─ lib/config.js Config schema + profile/repo layers + runtime snapshot
14
+ ├─ lib/errors.js stable tool error codes and classification
15
+ ├─ lib/workspaceLock.js optional one-Tower-session-per-repository advisory lock
16
+ ├─ lib/hmr.js optional DSH HMR bridge (tower_reload / /tower reload)
17
+ └─ lib/modeStore.js per-agent Tower mode persistence
14
18
  Subagents
15
- ├─ tower-worker (dsh-tower/worker) read/write/edit/pwsh + mission tools
16
- └─ tower-reviewer (dsh-tower/reviewer) read/glob/grep + tower_diff + review/finding
19
+ ├─ tower-worker (dsh-tower/worker) read/write/edit/pwsh + mission tools + findings
20
+ └─ tower-reviewer (dsh-tower/reviewer) read/glob/grep + tower_diff + review/finding (read-only)
17
21
  ```
18
22
 
19
23
  The main checkout is the control-tower repo; each mission has a branch `tower/<id>-<slug>` and a
package/docs/faq.md CHANGED
@@ -28,12 +28,43 @@ instead of rebasing.
28
28
  No. Reviewers use the read-only `tower-reviewer` preset (no write/edit/pwsh); a branch changed after the
29
29
  reviewer spawned is rejected. Reviewers file `tower_finding` for issues outside the mission.
30
30
 
31
+ **What is the difference between `tower_finding` and `tower_findings`?**
32
+ `tower_finding` creates one finding (`open`). `tower_findings` is the lifecycle tool: list/read, and
33
+ transition `open → triaged → fixed`/`wontfix` (reopen allowed). Only the tower or a worker may change the
34
+ status; a roster reviewer may list and read.
35
+
36
+ **How do I set config for one repository only?**
37
+ Create `<git-common-dir>/dsh-tower/config.json` (usually `.git/dsh-tower/config.json`) with the same
38
+ JSON groups as the profile config (`review`, `merge`, `worktrees`, `spawn`, and legacy aliases). The
39
+ repository layer wins over the profile; per-call tool arguments win over both. No restart is required
40
+ because the file is read when a Tower tool opens the repository.
41
+
31
42
  **Can workers use Tower tools to merge or spawn?**
32
43
  No. The worker preset contains mission/progress tools only; merge and spawn live in the parent tower.
33
44
 
45
+ **A worker is stuck or runaway. How do I stop it?**
46
+ Use `tower_interrupt({to:"worker-m1",reason:"..."})`; it calls the host subagent interrupt and records the
47
+ roster entry as `interrupted`. If you already interrupted it and want a new owner, spawn with
48
+ `takeover:true`. A still-running worker cannot be taken over (`takeover-refused`).
49
+
50
+ **Two sessions want to drive the same repository.**
51
+ Enable `mode.workspaceLock:true`: the first Tower session to call a repo-scoped tool owns
52
+ `<git-common-dir>/dsh-tower/tower.lock`; other sessions get `[tower:workspace-busy]` until the owner
53
+ runs `/tower off` or the lock is stale (`mode.workspaceStaleMs`).
54
+
55
+ **Can I reload the plugin without restarting DSH?**
56
+ Yes, in a profile with the DSH HMR service: `/tower reload` or the `tower_reload` tool reconciles the
57
+ profile and replaces the changed linked package. Run `npm run dev:hmr` once to add the repository to the
58
+ profile's HMR watch roots (then restart DSH once); see [hot reload](guide/hot-reload.md).
59
+ `plugin_manager` install/update already applies live.
60
+
61
+ **How do I make the completion evidence mandatory?**
62
+ Workers can pass `checks` to `tower_complete`; set `gates.requireChecks:true` to block merging when a
63
+ completed mission has no checks (`no-check-evidence`).
64
+
34
65
  **Where does Tower store state?**
35
- `<git-common-dir>/dsh-tower/state.json` and `activity.jsonl` in the target repo; mode state in
36
- `$DSH_HOME/tower-mode/modes.json`. Worktrees live next to the checkout in `.dsh-tower-worktrees/`.
66
+ `<git-common-dir>/dsh-tower/state.json`, `activity.jsonl` and the human-readable `MISSIONS.md`; mode state
67
+ in `$DSH_HOME/tower-mode/modes.json`. Worktrees live next to the checkout in `.dsh-tower-worktrees/`.
37
68
 
38
69
  **How do I change the review round cap or presets?**
39
70
  Use `review.maxRoundsPerReviewer` and `spawn.workerPreset`/`spawn.reviewerPreset`; see
@@ -0,0 +1,189 @@
1
+ # Hot reload (development)
2
+
3
+ Tower is a Host plugin: its tools and prompt sections are loaded when DSH boots. DSH already ships
4
+ `@deepseek-ai/dsh-hmr`, a service that **reconciles the profile in place** — it re-reads the profile
5
+ patch layers, replaces modules whose files changed (including a linked package such as a `dsh-tower`
6
+ checkout), restarts the affected Loader entries and reports anything that needs a full restart. Tower
7
+ uses that service in development so Host-side changes apply without restarting DSH.
8
+
9
+ This page covers the development loop. It is not required to use Tower.
10
+
11
+ ## What HMR does and does not do
12
+
13
+ `dsh --profile <name> --dump-config` prints the composed hmr row:
14
+
15
+ ```yaml
16
+ - id: hmr
17
+ name: '@deepseek-ai/dsh-hmr'
18
+ disabled: !!js '!ctx.get(''profileContext'')'
19
+ config:
20
+ root: []
21
+ ```
22
+
23
+ - `root: []` is the shipped default: **no source files are watched**. HMR is mounted but idle for
24
+ file-watching, so a running DSH does not reload when you edit the checkout.
25
+ - A reconciliation can still be requested explicitly (`/tower reload`, `tower_reload` or
26
+ `plugin_manager`); it compares already-loaded modules with disk and replaces the changed ones even
27
+ with `root: []`. Watching only makes that happen automatically after a save.
28
+ - HMR is only mounted for profile boots (`disabled` when there is no `profileContext`). A process
29
+ booted without a profile reports reload as unavailable (`tower_reload` stays registered while
30
+ `dev.hotReload` is on, so the tool returns `reload-unavailable` instead of disappearing).
31
+ - The profile patch layer is loaded when DSH boots. Editing it — in practice the hmr `root` list —
32
+ takes effect after **one DSH restart**. Nothing in the running process re-reads the HMR row's own
33
+ configuration.
34
+
35
+ ## Enable watching for a checkout
36
+
37
+ From a checkout of this repository:
38
+
39
+ ```powershell
40
+ npm run dev:hmr
41
+ # equivalent to:
42
+ node scripts/enable-dev-hmr.mjs
43
+ ```
44
+
45
+ The script appends one marked block to the profile's user patch layer,
46
+ `<DSH_HOME>/profiles/<profile>/cordis.patch.yml` (`DSH_HOME` defaults to `~/.dsh`; on Windows
47
+ usually `C:\Users\<you>\.dsh`):
48
+
49
+ ```yaml
50
+ # dsh-tower:dev-hmr
51
+ - id: hmr
52
+ config:
53
+ root:
54
+ - 'D:/work/dsh-tower'
55
+ ```
56
+
57
+ Options:
58
+
59
+ | Flag | Meaning |
60
+ |---|---|
61
+ | `--profile <name>` | Profile to edit. Default `desktop` (the profile the desktop app boots). |
62
+ | `--root <dir>` | Repository directory to watch. Default: the current working directory, canonicalised. |
63
+ | `--dry-run` | Print a diff of the patch file and exit without writing. |
64
+ | `--remove` | Delete the marked block again. |
65
+
66
+ Notes:
67
+
68
+ - The script is idempotent: re-running it replaces the marked block and leaves every other line of the
69
+ patch file untouched. Run it from the repository root, or pass `--root D:\work\dsh-tower`.
70
+ - The value written is the `realpath` of the root, with forward slashes. **HMR `root` accepts
71
+ absolute paths**; relative entries would resolve against the profile directory and are easy to get
72
+ wrong, so the script always writes an absolute one.
73
+ - The profile must already exist. The script never creates a profile and never creates directories
74
+ outside `<DSH_HOME>/profiles/<profile>/`.
75
+ - Pick the profile the desktop app actually boots (`desktop` by default). The desktop profile is
76
+ managed by the Electron app, so restart it by quitting and relaunching DSH.
77
+
78
+ **Restart DSH once** after writing the block. After that restart:
79
+
80
+ - HMR watches the checkout (except `node_modules`, dot-directories, `cache` and `data`, which the
81
+ shipped `ignored` list excludes) and reconciles the profile after edits while DSH stays open.
82
+ - `/tower reload` (and the `tower_reload` tool, when registered) reconciles on demand even for files
83
+ the watcher does not cover.
84
+
85
+ To stop watching, run `npm run dev:hmr -- --remove` and restart DSH once.
86
+
87
+ ## The edit loop
88
+
89
+ 1. Edit `lib/*.js`, `index.js`, `worker.js`, `reviewer.js` or `skills.js`.
90
+ 2. Save the file. The watcher debounces (DSH default 100 ms) and reconciles the profile; changed
91
+ modules are replaced and the affected Loader entries restart.
92
+ 3. Watch the DSH log for `reload plugin at <path>` / `restart required: …` messages.
93
+ 4. Optionally call `/tower reload` or `tower_reload` to reconcile on demand instead of waiting.
94
+
95
+ Editing the repository's bundle patch (`cordis.patch.yml`) changes the plugin declaration itself;
96
+ restart DSH after such a change rather than assuming a hot replacement.
97
+
98
+ The bridge behind the tool follows the `dev` config group:
99
+
100
+ | Config key | Meaning |
101
+ |---|---|
102
+ | `dev.hotReload` | Register `tower_reload`; `/tower reload` is disabled when off (default `true`). Without the HMR service the tool is still registered so it can return `reload-unavailable`. |
103
+ | `dev.reloadDelayMs` | Delay before the scheduled reconciliation runs, in milliseconds (default `50`), so the tool/command result reaches the model before the plugin is replaced. |
104
+ | `dev.reloadRequiredIds` | Loader entry ids the profile must keep active (default `tower`, `tower-skills`, `preset-tower-worker`, `preset-tower-reviewer`). An inactive required entry is reported as a reload failure even if it was already inactive. |
105
+
106
+ A reload is **scheduled, not awaited**: `/tower reload` and `tower_reload` return immediately with
107
+ `scheduled`, `delayMs`, `requiredIds` (and the current `lastError` when one is pending), then HMR
108
+ reconciles the profile after the delay. This is deliberate — the tool result must be delivered before
109
+ the Tower plugin replaces itself. Two consequences:
110
+
111
+ - a burst of reload requests inside the delay coalesces into a single reconciliation;
112
+ - a reconciliation failure is recorded as `lastError` instead of coming back from the tool call, so
113
+ check `tower_mode.hotReload` and the DSH log after a reload.
114
+
115
+ ### Reading a reload result
116
+
117
+ The outcome of the scheduled reconciliation surfaces in:
118
+
119
+ - **the DSH log** — `reload plugin at <path>` for replaced modules, plus HMR's warnings and
120
+ `restart required: <reason>` messages from its own watcher.
121
+ - **`tower_mode.hotReload`** — `{available, requiredIds, delayMs, scheduled, lastRunAt, lastError}`;
122
+ `lastError` keeps the most recent failure and is cleared by the next successful reload.
123
+
124
+ The reconciliation itself also returns `warnings`, `pending` (modules still on their previous code)
125
+ and an optional `restartReason`. When the reload was triggered from Tower those are not returned to
126
+ the model, so treat "new code does not appear" as a signal to restart DSH rather than to retry in a
127
+ loop.
128
+
129
+ If HMR is absent, `/tower reload` answers with an unavailable message and `tower_reload` is not
130
+ registered at all (both are gated on the HMR service at session start).
131
+
132
+ ## Plugin manager and linked packages
133
+
134
+ `plugin_manager` actions (`install_bundle`, `set_plugin`, upgrades) apply to the running profile
135
+ immediately — they reconcile the profile themselves, so installing or updating a bundle does not
136
+ require a restart. This is the intended way to install `dsh-tower` while developing: add the checkout
137
+ as a bundle (`dsh plugin --profile <profile> add <repo-root>` or `install_bundle`), then let HMR and
138
+ the reload tool pick up code edits.
139
+
140
+ With the checkout linked as a package target, a changed file inside the checkout is replaced by the
141
+ next `reconcileProfile` or `plugin_manager` operation **without a restart**, even when `root: []`
142
+ means the change was not watched. What does need a restart:
143
+
144
+ - the hmr row's own configuration (`root`), because that list is read when the service activates;
145
+ - modules reported under `pending` or with a `restartReason`.
146
+
147
+ ## Failure recovery
148
+
149
+ | Symptom | What to do |
150
+ |---|---|
151
+ | `[tower:reload-unavailable]` / "Tower reload is unavailable" | This process has no HMR service (booted without a profile, HMR disabled in the profile, or the service was disposed during shutdown). Restart DSH. To inspect the hmr row, run `dsh --profile <name> --dump-config` on a non-desktop profile (the desktop profile is managed by the Electron app and refuses the dump). |
152
+ | `[tower:reload-failed]` in `hotReload.lastError` with a syntax/import error | Fix the file, then restart DSH. A replacement that fails to import stops the previous plugin instance and its old code no longer runs; the reload itself cannot roll back. |
153
+ | `HMR is disposed` | The service shut down with the process. Restart DSH. |
154
+ | `HMR transactions cannot be nested` | An explicit reload was requested from inside another HMR transaction; call the tool from a normal tool turn instead. |
155
+ | `pending` is non-empty or `restartReason` is set | Restart DSH before trusting the reload result. |
156
+ | Edit saved but nothing reloads | Confirm the file is under the configured `root` (absolute path), is not excluded by `ignored` (`node_modules`, dot-directories, `cache`, `data`), and that the profile patch contains the marked block. Run `/tower reload` to reconcile manually. |
157
+ | Reload keeps reporting an inactive required entry | That Loader entry is disabled or failing: check the profile's plugins/bundles (a `preset-tower-*` entry is missing when a Tower preset bundle was removed) and restart after fixing it. |
158
+
159
+ The offline bridge tests are part of the normal suite:
160
+
161
+ ```powershell
162
+ node --test tests/hmr.test.mjs
163
+ ```
164
+
165
+ ## Client bundles (`ui-bundle`) are different
166
+
167
+ HMR replaces **Host** plugins and prompt/tool code. The optional `ui-bundle` is a Client widget: its
168
+ JavaScript is downloaded and evaluated by the Web page, not by the Host process. After a Host reload
169
+ or a Client bundle install/update, the open page may keep the old widget — refresh the Web page (and,
170
+ if a tool schema changed, open a new session) before assuming the change failed. The Tower UI widget
171
+ is a hint only and is not required for hot reload.
172
+
173
+ For a live check of the reload path against an isolated profile, use
174
+ [`tests/live/hmr.cjs`](../../tests/live/hmr.cjs) with `DSH_TEST_URL` set to the throwaway server URL
175
+ (see [tests/README.md](../../tests/README.md)); it never touches the desktop profile or live sessions.
176
+
177
+ ## Security
178
+
179
+ HMR executes the code it finds in the watched roots **inside the DSH Host process**, with your OS user
180
+ privileges, and it reloads it on save. Treat the profile patch layer like shell startup files:
181
+
182
+ - only point `root` at repositories you trust (this checkout), and keep the list small and absolute;
183
+ - do not add your home directory, a downloads folder, or a shared/network path;
184
+ - the patched profile is same-user trusted configuration; anyone who can write it can run code in
185
+ your DSH process;
186
+ - remove the block (`--remove`) and restart once when you no longer need watching.
187
+
188
+ See also: [install, upgrade and migration](install-upgrade-migration.md),
189
+ [configuration reference](../reference/config.md), [error codes](../reference/errors.md).
@@ -29,6 +29,17 @@ The Host plugin loads at DSH startup: **restart DSH after install or update**.
29
29
 
30
30
  ## Migration notes
31
31
 
32
+ - **1.x → 2.0 (unreleased)**: no state migration is needed (`schemaVersion` stays 1; new fields are
33
+ optional). Behavior changes to review: `mode.denyTools` now also denies `workflow`, `ralph`, `subagent`,
34
+ `subagent_fork`, `wait_agent` and `team_task_list` while Tower mode is active (override with an explicit
35
+ list); `spawn.maxLiveWorkers` defaults to 4; `mode.workspaceLock` is off by default. Workers can no
36
+ longer complete/abandon/scope a mission directly — use `tower_complete`. New tools: `tower_interrupt`,
37
+ and `tower_reload` when HMR is available. Restart DSH once after upgrading; see
38
+ [hot reload](hot-reload.md).
39
+ - **1.3 → 1.4**: no state migration is needed. New: repository-level config
40
+ (`<git-common-dir>/dsh-tower/config.json`), stable `[tower:<code>]` tool errors, `tower_findings`,
41
+ and `id`/`missionId` + snake/camel input aliases. Existing calls keep working; restart DSH to load
42
+ the new tool surface (`tower_findings` and the newer output schemas).
32
43
  - **1.2 → 1.3**: reviewers moved from the shared `tower-worker` preset to the new read-only
33
44
  `tower-reviewer` preset. Reinstall/restart so both preset rows exist. `tower_spawn role=reviewer`
34
45
  now requires the mission to be `completed`.
@@ -58,8 +58,40 @@ worktrees and branches.
58
58
 
59
59
  ## If something fails
60
60
 
61
- Read the blocker code and use [the blocker reference](reference/blockers.md). The most common cases:
61
+ Read the blocker code and use [the blocker reference](../reference/blockers.md). The most common cases:
62
62
  `stale-base` (run `tower_rebase`), `no-review` (spawn a reviewer), `merge-hook-failed` (retry, or raise
63
63
  `timeoutMs`), `tip-moved` (the branch changed after review; review again).
64
64
 
65
+ Thrown tool failures carry a `[tower:<code>]` prefix; see [error codes](../reference/errors.md)
66
+ (e.g. `preset-missing` means restart DSH after installing the bundle, `not-initialized` means run
67
+ `tower_init` first).
68
+
69
+ ## Optional: per-repository config
70
+
71
+ A repository can tune review, merge, worktree and spawn policy without touching the DSH profile. Put a
72
+ JSON file at `<git-common-dir>/dsh-tower/config.json` (usually `.git/dsh-tower/config.json`):
73
+
74
+ ```json
75
+ {
76
+ "review": { "maxRoundsPerReviewer": 3 },
77
+ "merge": { "timeoutMs": 1800000 },
78
+ "worktrees": { "root": "D:/tower-worktrees" }
79
+ }
80
+ ```
81
+
82
+ The repository layer overrides the profile config; per-call tool arguments override both. See the
83
+ [config reference](../reference/config.md) for the full table and precedence.
84
+
85
+ ## Optional: findings
86
+
87
+ Out-of-scope observations go to `tower_finding`. Later, list or close them without editing code:
88
+
89
+ ```
90
+ tower_findings repoRoot=D:\work\repo
91
+ tower_findings repoRoot=D:\work\repo id=F1 status=fixed note="fixed in M2"
92
+ ```
93
+
94
+ Statuses are `open → triaged → fixed` / `wontfix`, and `fixed`/`wontfix` can reopen to `open`. Only the
95
+ tower or a worker may change a finding; reviewers can list and read.
96
+
65
97
  A complete copy-paste example: [examples/first-mission.md](../examples/first-mission.md).