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.
- package/CHANGELOG.md +77 -0
- package/CONTRIBUTING.md +1 -1
- package/README.en.md +22 -8
- package/README.md +20 -8
- package/cordis.patch.yml +10 -0
- package/docs/README.md +8 -4
- package/docs/architecture/overview.md +13 -9
- package/docs/faq.md +33 -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/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 +31 -0
- package/docs/reference/errors.md +50 -0
- package/docs/reference/events.md +45 -0
- package/docs/reference/operations.md +52 -0
- package/docs/reference/testing.md +61 -0
- package/docs/reference/tools.md +65 -23
- package/docs/zh/README.md +58 -0
- package/docs/zh/faq.md +72 -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/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 +30 -0
- package/docs/zh/reference/errors.md +52 -0
- package/docs/zh/reference/events.md +46 -0
- package/docs/zh/reference/operations.md +48 -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 +270 -8
- package/lib/doctor.js +165 -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 +1554 -182
- package/lib/tower.js +957 -102
- 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
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 (
|
|
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
|
-
-
|
|
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 (
|
|
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` (
|
|
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
|
-
|
|
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
|
-
-
|
|
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
|
-
## 工具(
|
|
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`
|
|
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
|
-
|
|
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)
|
|
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 ->
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
├─ lib/
|
|
12
|
-
├─ lib/
|
|
13
|
-
|
|
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
|
|
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`.
|
package/docs/guide/quickstart.md
CHANGED
|
@@ -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).
|