dsh-tower 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/COMPATIBILITY.md +1 -0
- package/CONTRIBUTING.md +17 -3
- package/PRINCIPLES.md +18 -0
- package/README.en.md +29 -16
- package/README.md +22 -15
- package/cordis.patch.yml +56 -28
- package/docs/README.md +2 -1
- package/docs/adr/0004-surface-budget.md +20 -0
- package/docs/adr/0005-component-surface.md +130 -0
- package/docs/adr/README.md +1 -0
- package/docs/agents/workflow.md +1 -1
- package/docs/architecture/overview.md +25 -7
- package/docs/guide/hot-reload.md +4 -4
- package/docs/guide/install-upgrade-migration.md +13 -0
- package/docs/operations/security.md +1 -1
- package/docs/reference/component-surface.md +135 -0
- package/docs/reference/config.generated.md +2 -10
- package/docs/reference/config.md +11 -9
- package/docs/reference/doctor.md +14 -9
- package/docs/reference/surface-budget.md +52 -23
- package/docs/reference/tools.generated.md +4 -2
- package/docs/reference/tools.md +6 -3
- package/docs/zh/README.md +1 -1
- package/docs/zh/guide/hot-reload.md +3 -3
- package/docs/zh/guide/install-upgrade-migration.md +10 -0
- package/docs/zh/operations/security.md +1 -1
- package/docs/zh/reference/config.md +9 -9
- package/docs/zh/reference/tools.md +6 -4
- package/domain/components.js +641 -0
- package/domain/config/schema.js +37 -27
- package/domain/contracts/outputs.js +10 -0
- package/domain/errors.js +11 -1
- package/domain/mission.js +12 -1
- package/domain/surface.js +154 -55
- package/host/capability-batch.js +15 -0
- package/host/capability-hmr.js +30 -0
- package/host/capability-import.js +11 -0
- package/host/capability-leases.js +11 -0
- package/host/capability-registry.js +149 -0
- package/host/capability-tests.js +16 -0
- package/host/doctor.js +41 -9
- package/host/hmr.js +2 -4
- package/host/presets.js +51 -9
- package/host/tool-registry.js +150 -34
- package/index.js +32 -20
- package/locale/en.json +31 -11
- package/locale/zh.json +30 -10
- package/package.json +16 -3
- package/scripts/check-components.mjs +235 -0
- package/scripts/component-surface.json +395 -0
- package/scripts/generate-component-surface.mjs +59 -0
- package/scripts/generate-tools-reference.mjs +7 -25
- package/scripts/generate-types.mjs +127 -0
- package/scripts/lib/tool-surface.mjs +85 -0
- package/scripts/mount-smoke/fixtures.mjs +3 -3
- package/scripts/mount-smoke/surface.mjs +96 -27
- package/scripts/mount-smoke.mjs +3 -1
- package/scripts/pack-manifest.txt +17 -0
- package/scripts/surface-baseline.json +35 -4
- package/scripts/surface-baseline.mjs +32 -34
- package/scripts/types-coverage.mjs +184 -0
- package/scripts/types-strict-manifest.txt +10 -0
- package/scripts/types-strict.mjs +141 -0
- package/skills.js +8 -1
- package/tools/index.js +2 -1
- package/tools/reload.js +34 -35
- package/tools/status.js +8 -1
- package/types/index.d.ts +28 -12
|
@@ -2,17 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
## Components
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
Since #121 the bundle ships a mandatory host anchor plus individually switchable
|
|
6
|
+
optional rows: `cordis.patch.yml` declares top-level `tower` (a `cordis:group`
|
|
7
|
+
that mounts the Host plugin and the mandatory worker preset), then
|
|
8
|
+
`tower-skills`, `tower-batch`, `tower-import`, `tower-leases`, `tower-tests`,
|
|
9
|
+
`tower-hmr` (shipped off) and `preset-tower-reviewer`. Turning one optional row
|
|
10
|
+
off removes exactly that capability; the host, the diagnostics and the recovery
|
|
11
|
+
escape keep working.
|
|
12
|
+
|
|
13
|
+
[Principle 11](../../PRINCIPLES.md) and
|
|
14
|
+
[ADR 0005](../adr/0005-component-surface.md) say a component may exist only for
|
|
15
|
+
a capability whose off state leaves the rest intact, and that the host, health,
|
|
16
|
+
recovery, review and merge-gate capabilities are never switches. Which keys are
|
|
17
|
+
allowed to be switches is a table lookup in
|
|
18
|
+
[component-surface.md](../reference/component-surface.md), generated from
|
|
19
|
+
`scripts/component-surface.json`; the component count is baselined and checked by
|
|
20
|
+
`npm run docs:check:components`. That gate also refuses a `tools.expose*` route
|
|
21
|
+
to a tool that is not on the recorded allowlist (empty since #122) and any
|
|
22
|
+
`cordis.patch.yml` row that defaults a forbidden key off.
|
|
9
23
|
|
|
10
24
|
```
|
|
11
25
|
Host plugin (index.js)
|
|
12
|
-
├─ /tower command + Tower mode (guard, prompt section, tower_mode/tower_control
|
|
26
|
+
├─ /tower command + Tower mode (guard, prompt section, tower_mode/tower_control)
|
|
13
27
|
├─ host/tool-registry.js -> registration aggregator, actor guards, shared helpers
|
|
14
|
-
│ (+
|
|
15
|
-
│ (+
|
|
28
|
+
│ (+ 21 define()-registered host tools)
|
|
29
|
+
│ (+ tower_mode/tower_control registered by the Host entry, 29 total
|
|
30
|
+
│ once every optional capability row is on)
|
|
31
|
+
│ (tower_doctor/tower_recover are host tools, never switches)
|
|
32
|
+
├─ host/capability-*.js -> optional capability entry points (batch/import/leases/tests/hmr)
|
|
16
33
|
├─ tools/index.js -> thin public wiring (re-exports the registry + briefings)
|
|
17
34
|
└─ app/tower.js -> orchestration surface; delegates to use-case modules
|
|
18
35
|
├─ app/init.js, provision.js, merge.js, rebase.js, teardown.js
|
|
@@ -24,6 +41,7 @@ Host plugin (index.js)
|
|
|
24
41
|
host/tool-registry.js registration aggregator + shared guards/helpers
|
|
25
42
|
host/config.js profile/repo config layers over the pure schema
|
|
26
43
|
host/doctor.js read-only environment contract and health checks
|
|
44
|
+
host/capability-registry.js mounted-component report for status/doctor
|
|
27
45
|
host/hmr.js optional DSH HMR bridge (tower_reload / /tower reload)
|
|
28
46
|
host/modeStore.js per-agent Tower mode persistence
|
|
29
47
|
host/modeState.js owned in-memory mode state
|
package/docs/guide/hot-reload.md
CHANGED
|
@@ -26,8 +26,8 @@ This page covers the development loop. It is not required to use Tower.
|
|
|
26
26
|
`plugin_manager`); it compares already-loaded modules with disk and replaces the changed ones even
|
|
27
27
|
with `root: []`. Watching only makes that happen automatically after a save.
|
|
28
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
|
-
`
|
|
29
|
+
booted without a profile reports reload as unavailable (`tower_reload` stays registered while the
|
|
30
|
+
`tower-hmr` component row is on, so the tool returns `reload-unavailable` instead of disappearing).
|
|
31
31
|
- The profile patch layer is loaded when DSH boots. Editing it — in practice the hmr `root` list —
|
|
32
32
|
takes effect after **one DSH restart**. Nothing in the running process re-reads the HMR row's own
|
|
33
33
|
configuration.
|
|
@@ -99,9 +99,9 @@ The bridge behind the tool follows the `dev` config group:
|
|
|
99
99
|
|
|
100
100
|
| Config key | Meaning |
|
|
101
101
|
|---|---|
|
|
102
|
-
| `
|
|
102
|
+
| `tower-hmr` (component row) | The switch: on registers `tower_reload` and `/tower reload`, off reports "disabled by component tower-hmr". The row ships off; enable it from the plugin page for a linked dev profile. `dev.hotReload` was removed in 2.4.0 and is now an unknown key. |
|
|
103
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
|
|
104
|
+
| `dev.reloadRequiredIds` | Loader entry ids the profile must keep active (default `tower`, `tower-host`, `preset-tower-worker`). An inactive required entry is reported as a reload failure even if it was already inactive. Optional capability rows are deliberately not required, so a row switched off is not a reload failure. |
|
|
105
105
|
|
|
106
106
|
A reload is **scheduled, not awaited**: `/tower reload` and `tower_reload` return immediately with
|
|
107
107
|
`scheduled`, `delayMs`, `requiredIds` (and the current `lastError` when one is pending), then HMR
|
|
@@ -45,6 +45,19 @@ The Host plugin loads at DSH startup: **restart DSH after install or update**.
|
|
|
45
45
|
overlapping and case-only mismatches are no longer refused by the out-of-scope gate. Stored scope
|
|
46
46
|
strings are never rewritten: the board keeps showing what the operator typed.
|
|
47
47
|
|
|
48
|
+
- **2.3.0 → 2.4.0 (unreleased)**: the single `tower-bundle` group row is gone. `cordis.patch.yml`
|
|
49
|
+
now ships the mandatory `tower` host anchor (the Host plugin and the worker preset are its internal
|
|
50
|
+
sections) plus individually switchable top-level rows: `tower-skills`, `tower-batch`, `tower-import`,
|
|
51
|
+
`tower-leases`, `tower-tests`, `tower-hmr` (shipped off) and `preset-tower-reviewer` (conditional on
|
|
52
|
+
`review.requireReview`). The `tools` config group and `dev.hotReload` were removed: a profile that
|
|
53
|
+
still carries them is now rejected as an unknown key (`config-unknown-key`) and the host stops
|
|
54
|
+
mounting until they are deleted, so no silent no-op switch remains. Move each capability to its row
|
|
55
|
+
in the plugin page instead; `tower-hmr` ships off, so `tower_reload` and `/tower reload` are reported
|
|
56
|
+
as "disabled by component tower-hmr" until you enable it for a linked dev profile. `tower_doctor` and
|
|
57
|
+
`tower_recover` are registered for every configuration and need no key. The reviewer row may be off
|
|
58
|
+
only while `review.requireReview` is false; with the gate on, planning and mode entry refuse the
|
|
59
|
+
combination with an explanatory error. No state migration is needed.
|
|
60
|
+
|
|
48
61
|
- **2.0.4 → 2.1.0-beta.1**: no config migration; the state file migrates automatically (v1/v2 → v3) as
|
|
49
62
|
described above. This is a **pre-release** published on the
|
|
50
63
|
`next` dist-tag, so `latest` still resolves to 2.0.4 — install it with
|
|
@@ -104,7 +104,7 @@ Tower work, and run the host under OS-level isolation.
|
|
|
104
104
|
cannot make those safe; review hooks before running Tower on an untrusted repository.
|
|
105
105
|
- **Package test commands.** Declared discovery commands have the same trust as repository hooks; a
|
|
106
106
|
malicious `package.json` can run code. Disable `tests.allowPackageDiscovery` and review the file.
|
|
107
|
-
- **HMR reload.** With `
|
|
107
|
+
- **HMR reload.** With the `tower-hmr` component row on, `/tower reload`/`tower_reload` asks DSH to re-import the plugin
|
|
108
108
|
from disk. Only enable HMR watch roots for checkouts you trust; a reload executes the current files.
|
|
109
109
|
- **Prompt injection.** The reviewer reads untrusted branch content (diff/comments). The read-only preset
|
|
110
110
|
limits impact, but no model-side protection is absolute.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Component surface (generated)
|
|
2
|
+
|
|
3
|
+
> Generated by `npm run docs:generate:components` from `scripts/component-surface.json` and
|
|
4
|
+
> `scripts/surface-baseline.json`. Do not edit by hand.
|
|
5
|
+
|
|
6
|
+
Decision: [ADR 0005](../adr/0005-component-surface.md) · decision date: 2026-10-23 · baseline 2026-10-23 · visible components: 8 (`tower`, `tower-skills`, `tower-batch`, `tower-import`, `tower-leases`, `tower-tests`, `tower-hmr`, `preset-tower-reviewer`)
|
|
7
|
+
|
|
8
|
+
The component axis answers one question for every config key: may a user turn it
|
|
9
|
+
off, and if so, must that switch be a component? Four classes cover every key, so
|
|
10
|
+
"should this be a component?" is a table lookup rather than a judgement call.
|
|
11
|
+
|
|
12
|
+
| Class | Meaning |
|
|
13
|
+
|---|---|
|
|
14
|
+
| `core` | Removing it breaks the Tower contract. It is never a switch. |
|
|
15
|
+
| `optional-component` | A capability whose off state leaves the rest of Tower intact. It must be a user-visible switch with a documented fallback. |
|
|
16
|
+
| `optional-config` | A tuning knob, not a capability. It stays in the config form and never hides a component. |
|
|
17
|
+
| `forbidden-to-disable` | The host, the health contract, the recovery escape, the review contract and the merge gates. No group, row or boolean key may turn it off. |
|
|
18
|
+
|
|
19
|
+
## Components
|
|
20
|
+
|
|
21
|
+
The shipped `cordis.patch.yml` rows, with the fallback contract each off state
|
|
22
|
+
must satisfy. A visible row is a component the plugin page may switch; an internal
|
|
23
|
+
row is a section of its parent and is not independently switchable.
|
|
24
|
+
|
|
25
|
+
| Component | Scope | Kind | Off state and fallback |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| `tower` | visible | group | Off equals uninstalling Tower: no tools, presets or skills remain. That is the accepted all-off boundary of the mandatory host anchor, not an optional capability. |
|
|
28
|
+
| `tower-host` | internal | row | The Host plugin itself, nested under the mandatory tower anchor. A mandatory dependency, never its own switch. |
|
|
29
|
+
| `tower-skills` | visible | row | The 3 skills leave the catalog; the worker/reviewer PROTOCOL sections still ship through systemPrompt.section, so only the tower-recovery guidance is lost. |
|
|
30
|
+
| `tower-batch` | visible | row | tower_batch is not registered; missions, gates and merges are unaffected because no state depends on a batch. |
|
|
31
|
+
| `tower-import` | visible | row | tower_import_legacy and tower_legacy_map are not registered; new repository state is unaffected. |
|
|
32
|
+
| `tower-leases` | visible | row | tower_resource is not registered; advisory leases are coordination only, so nothing else depends on them. |
|
|
33
|
+
| `tower-tests` | visible | row | tower_test is not registered and no test receipt can be recorded. With gates.requireTests:true planning/mode entry is rejected with an explanation, and the merge gate still reports tests-missing. |
|
|
34
|
+
| `tower-hmr` | visible | row | tower_reload and /tower reload are unavailable; a profile without HMR behaves exactly as before. Shipped disabled: enable the row for a linked dev profile. |
|
|
35
|
+
| `preset-tower-worker` | internal | row | tower_spawn fails without the worker preset. A mandatory dependency, never a switch. |
|
|
36
|
+
| `preset-tower-reviewer` | visible | row | The reviewer cannot be dispatched. Supported while review.requireReview is false (merge is unaffected); with the gate on planning/mode entry is locked with an explanatory error. |
|
|
37
|
+
|
|
38
|
+
## Forbidden to disable
|
|
39
|
+
|
|
40
|
+
The host, the health contract, the recovery escape, the review contract and the
|
|
41
|
+
merge gates are configuration or code, never switches. `npm run
|
|
42
|
+
docs:check:components` derives the live disablers from `host/tool-registry.js`
|
|
43
|
+
and `cordis.patch.yml`; a disabler that is not recorded here fails the gate.
|
|
44
|
+
|
|
45
|
+
| Capability | Why it may not be disabled | Recorded disablers | Decision |
|
|
46
|
+
|---|---|---|---|
|
|
47
|
+
| the Tower host | Without the host the plugin registers nothing; there is no off state that leaves the rest working, and no config boolean may remove it. The visible `tower` anchor is the all-off boundary, and the host section nested under it may never become its own switch. | none | none may exist |
|
|
48
|
+
| tower_doctor (read-only health contract) | Diagnosis must always exist so a failure message can point at it. #122 removed exposeDoctor and the exposeOperational master switch; the tool is registered for every configuration. | none | none may exist |
|
|
49
|
+
| tower_recover (stale state-lock escape) | The escape hatch must exist whenever the lock it repairs can be left behind. #122 removed exposeRecovery and the exposeOperational master switch; the tool is registered for every configuration. | none | none may exist |
|
|
50
|
+
| the review contract | review.requireReview is a merge blocker, not a component; a row may not switch it off. The reviewer row is conditional, not a way to weaken the gate. | none | none may exist |
|
|
51
|
+
| the merge gates | gates.* decides delivery; a component may not bypass it. | none | none may exist |
|
|
52
|
+
|
|
53
|
+
## Gateable tools
|
|
54
|
+
|
|
55
|
+
The allowlist of boolean routes in `host/tool-registry.js`. Every shipped
|
|
56
|
+
`tools.expose*` route must match this table. A route to a tool that is not listed
|
|
57
|
+
here is refused, so no boolean key can quietly remove a review, merge or host
|
|
58
|
+
tool. Since #122 the shipped table is empty: `tower_doctor` and `tower_recover`
|
|
59
|
+
are registered for every configuration and no other capability may become a
|
|
60
|
+
boolean switch.
|
|
61
|
+
|
|
62
|
+
| Tool | Switch key |
|
|
63
|
+
|---|---|
|
|
64
|
+
| _(none)_ | — |
|
|
65
|
+
|
|
66
|
+
## Config keys
|
|
67
|
+
|
|
68
|
+
All keys from `domain/config/schema.js`, classified on the component axis.
|
|
69
|
+
|
|
70
|
+
| Key | Component class | Decision note |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `section` | `core` | Legacy alias for mode.promptSection: the Tower-mode prompt contract, not a capability. |
|
|
73
|
+
| `allowAgentControl` | `core` | Legacy alias for mode.allowAgentControl: the human-owned mode rule (ADR 0003), not a component. |
|
|
74
|
+
| `init.autoGitInit` | `optional-config` | Bootstrap convenience; off only means tower_init will not run git init. |
|
|
75
|
+
| `init.snapshotDirty` | `optional-config` | Dirty-work baseline convenience; no capability is removed. |
|
|
76
|
+
| `init.autoExclude` | `optional-config` | Keeps Tower artifacts out of .git/info/exclude; safe either way. |
|
|
77
|
+
| `mode.promptSection` | `core` | Replaces the whole Tower-mode prompt text; contract text, not a capability. |
|
|
78
|
+
| `mode.sectionAppend` | `optional-config` | Appends team conventions to the prompt. |
|
|
79
|
+
| `mode.allowAgentControl` | `core` | Decides whether the model may toggle the mode (ADR 0003). A governance rule, never a component. |
|
|
80
|
+
| `mode.autoPauseGoal` | `core` | Entering the mode pauses an active goal; exit never resumes it. |
|
|
81
|
+
| `mode.requireResumeAuthorization` | `core` | Guards resuming a user-paused mission. |
|
|
82
|
+
| `mode.requireHumanAckOnFirstEntry` | `core` | First entry can require an explicit human ack. |
|
|
83
|
+
| `mode.workspaceLock` | `core` | One Tower session per repository is a safety contract; a row may not turn it off. |
|
|
84
|
+
| `mode.workspaceLockScope` | `optional-config` | Chooses whether read-only tools take the workspace lock. |
|
|
85
|
+
| `mode.planModePolicy` | `core` | Plan mode and Tower mode stay mutually exclusive. |
|
|
86
|
+
| `mode.workspaceStaleMs` | `optional-config` | Stale window for the advisory workspace lock. |
|
|
87
|
+
| `mode.heartbeatMs` | `optional-config` | Heartbeat interval while the mode is on. |
|
|
88
|
+
| `mode.denyTools` | `core` | The denied-tool list is part of the mode guard. |
|
|
89
|
+
| `mode.storePath` | `optional-config` | Custom mode-store location; no capability is removed. |
|
|
90
|
+
| `mode.maxEntries` | `optional-config` | Bounds the persisted mode store. |
|
|
91
|
+
| `mode.lockTimeoutMs` | `optional-config` | Bounded wait for the cross-process mode lock. |
|
|
92
|
+
| `review.requireReview` | `forbidden-to-disable` | Turns independent review into a merge blocker; no component may switch it off. With it on, the preset-tower-reviewer row may not be off (planning/mode entry refuse the combination). |
|
|
93
|
+
| `review.maxRoundsPerReviewer` | `forbidden-to-disable` | Caps review rounds; part of the review contract. |
|
|
94
|
+
| `merge.timeoutMs` | `optional-config` | Default merge timeout; a per-call value wins. |
|
|
95
|
+
| `merge.maxBufferBytes` | `optional-config` | Captured merge output buffer. |
|
|
96
|
+
| `git.timeoutMs` | `optional-config` | Default Git command timeout outside merge. |
|
|
97
|
+
| `worktrees.root` | `optional-config` | Default worktree placement. |
|
|
98
|
+
| `spawn.workerPreset` | `core` | Chooses the worker tool surface; a dependency, never a switch. |
|
|
99
|
+
| `spawn.reviewerPreset` | `core` | Chooses the read-only reviewer surface; a dependency, never a switch. |
|
|
100
|
+
| `spawn.maxDepth` | `optional-config` | Subagent depth requested at spawn. |
|
|
101
|
+
| `spawn.provider` | `optional-config` | Provider route for spawned agents. |
|
|
102
|
+
| `spawn.workerModel` | `optional-config` | Optional model route for workers. |
|
|
103
|
+
| `spawn.reviewerModel` | `optional-config` | Optional independent model route for reviewers. |
|
|
104
|
+
| `spawn.maxLiveWorkers` | `core` | Resource-safety cap on live workers. |
|
|
105
|
+
| `spawn.staleMs` | `optional-config` | Roster staleness window before merge is blocked. |
|
|
106
|
+
| `spawn.maxWaitMs` | `optional-config` | Upper bound for a blocking spawn wait. |
|
|
107
|
+
| `spawn.requireLease` | `optional-config` | Advisory-lease gate before a worker starts. |
|
|
108
|
+
| `send.maxPerMinute` | `optional-config` | Message rate limit; zero disables it. |
|
|
109
|
+
| `send.interruptDefault` | `optional-config` | Default for the interrupt-before-deliver flag. |
|
|
110
|
+
| `tests.enabled` | `optional-component` | Tuning inside the optional tower-tests component: it decides whether discovery runs when the row is on. Off with gates.requireTests:true is rejected at config resolution. |
|
|
111
|
+
| `tests.admission` | `optional-config` | Chooses when discovery runs inside the optional tests capability. |
|
|
112
|
+
| `tests.timeoutMs` | `optional-config` | Per-command discovery timeout. |
|
|
113
|
+
| `tests.maxBytes` | `optional-config` | Captured discovery output cap. |
|
|
114
|
+
| `tests.autoChecks` | `optional-config` | Attaches a tests check to completion when discovery runs. |
|
|
115
|
+
| `tests.allowPackageDiscovery` | `core` | Allows repository code to execute; a security contract, not a component. |
|
|
116
|
+
| `gates.requireChecks` | `forbidden-to-disable` | Requires completion evidence before merge; a merge gate. |
|
|
117
|
+
| `gates.requireTests` | `forbidden-to-disable` | Requires a test receipt before merge; a merge gate. With the tower-tests row off, planning/mode entry refuse the combination. |
|
|
118
|
+
| `gates.allowReviewExemption` | `forbidden-to-disable` | The review-exemption path is part of the review and merge contract. |
|
|
119
|
+
| `gates.maxReportBytes` | `forbidden-to-disable` | The report cap is part of the completion contract; the refusal itself is never configurable away. |
|
|
120
|
+
| `docs.board` | `optional-config` | Writes the human-readable board; no capability is removed. |
|
|
121
|
+
| `docs.boardLocation` | `optional-config` | Chooses the board location. |
|
|
122
|
+
| `archive.enabled` | `optional-config` | Archival is maintenance, not a tool capability; off only leaves terminal missions hot. |
|
|
123
|
+
| `archive.afterDays` | `optional-config` | Archive age threshold. |
|
|
124
|
+
| `archive.maxMissions` | `optional-config` | Hot terminal-mission cap. |
|
|
125
|
+
| `leases.ttlMs` | `optional-config` | Tuning inside the optional tower-leases component. |
|
|
126
|
+
| `dev.reloadDelayMs` | `optional-config` | Delay so a tool result is delivered before a scheduled reload inside the optional tower-hmr component. |
|
|
127
|
+
| `dev.reloadRequiredIds` | `optional-config` | Loader ids passed to reconcileProfile as required by the tower-hmr component. |
|
|
128
|
+
|
|
129
|
+
## Non-goals
|
|
130
|
+
|
|
131
|
+
This page does not decide whether a key is useful, and it is not an approval
|
|
132
|
+
process. It records the class so the gate can refuse an unclassified or
|
|
133
|
+
forbidden surface.
|
|
134
|
+
|
|
135
|
+
Enforced by: `scripts/check-components.mjs`; tests in `tests/components.test.mjs`; gate: `npm run docs:check:components`.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Config reference (generated)
|
|
2
2
|
|
|
3
3
|
> Generated by `npm run docs:generate:config` from `domain/config/schema.js`. Values are defaults before repo config.
|
|
4
|
-
> Surface: config keys:
|
|
4
|
+
> Surface: config keys: 56 · sections: 14 · tools: 29 · baseline 2026-10-23. Generated from `scripts/surface-baseline.json`; do not edit by hand.
|
|
5
5
|
|
|
6
6
|
| Key | Default | Description |
|
|
7
7
|
|---|---|---|
|
|
@@ -58,14 +58,6 @@
|
|
|
58
58
|
| `archive.enabled` | `true` | Move terminal (merged/abandoned) missions whose worktree is gone into <git-common-dir>/dsh-tower/archive/ at the next mutation, so state.json stops carrying their full history. |
|
|
59
59
|
| `archive.afterDays` | `30` | Terminal missions untouched for at least this many days are archived on the next mutation (0 archives them immediately). |
|
|
60
60
|
| `archive.maxMissions` | `100` | Maximum terminal missions kept hot; once exceeded, the oldest eligible terminal missions are archived until the cap holds (0 archives every eligible terminal mission). |
|
|
61
|
-
| `tools.exposeOperational` | `true` | Master switch for batch/resource/import/legacy/recover/test/doctor tools. |
|
|
62
|
-
| `tools.exposeBatch` | `true` | Register tower_batch. |
|
|
63
|
-
| `tools.exposeImport` | `true` | Register tower_import_legacy/tower_legacy_map. |
|
|
64
|
-
| `tools.exposeLeases` | `true` | Register tower_resource advisory leases. |
|
|
65
|
-
| `tools.exposeTests` | `true` | Register tower_test; gates.requireTests requires it. |
|
|
66
|
-
| `tools.exposeRecovery` | `true` | Register tower_recover (stale state-lock escape). |
|
|
67
|
-
| `tools.exposeDoctor` | `true` | Register tower_doctor (read-only health contract). |
|
|
68
61
|
| `leases.ttlMs` | `900000` | Default advisory lease lifetime; expiry never auto-releases. |
|
|
69
|
-
| `dev.hotReload` | `true` | Register tower_reload and /tower reload when the DSH HMR service is available. |
|
|
70
62
|
| `dev.reloadDelayMs` | `50` | Delay before a scheduled reload, so the tool result is delivered first. |
|
|
71
|
-
| `dev.reloadRequiredIds` | `["tower
|
|
63
|
+
| `dev.reloadRequiredIds` | `["tower","tower-host","preset-tower-worker"]` | Loader entry ids passed to reconcileProfile as required. Optional component rows are deliberately not required, so a row switched off is not a reload failure. |
|
package/docs/reference/config.md
CHANGED
|
@@ -74,14 +74,14 @@ violates the declared schema (for example `merge.timeoutMs` below 1000) fail wit
|
|
|
74
74
|
| `spawn.requireLease` | `''` | Optional lease name that must be held before a worker can spawn. |
|
|
75
75
|
| `send.maxPerMinute` | `120` | Per-repository `tower_send` rate limit (0 disables); exceeding it returns `rate-limited`. |
|
|
76
76
|
| `send.interruptDefault` | `false` (bundled patch: `true`) | Default for `tower_send.interrupt` (interrupt the running turn before delivering). |
|
|
77
|
-
| `tests.enabled` | `true` | Run declared test discovery when the worktree `package.json` configures it. |
|
|
77
|
+
| `tests.enabled` | `true` | Run declared test discovery when the worktree `package.json` configures it. It only tunes the optional `tower-tests` component: with that row off there is no `tower_test` tool and no receipt, and `gates.requireTests:true` is refused rather than silently unmet. |
|
|
78
78
|
| `tests.admission` | `off` | `spawn` runs discovery before starting a worker, `complete` at `tower_complete`, `off` only on explicit `tower_test` (default; repository code is not executed automatically). |
|
|
79
79
|
| `tests.timeoutMs` | `60000` | Per discovery command timeout. |
|
|
80
80
|
| `tests.maxBytes` | `16777216` (16 MiB) | Captured stdout cap per command. |
|
|
81
81
|
| `tests.autoChecks` | `true` | Attach an automatic `tests` check to the completion report. |
|
|
82
82
|
| `tests.allowPackageDiscovery` | `true` | Allow repo-controlled `tower.testDiscovery` commands (executes worktree code; see security). |
|
|
83
83
|
| `gates.requireChecks` | `false` | Require at least one `tower_complete.checks` entry before merge (`no-check-evidence`). |
|
|
84
|
-
| `gates.requireTests` | `false` | Require a passing discovery receipt for the current mission branch tip (`tests-missing`); independent of the review gate. |
|
|
84
|
+
| `gates.requireTests` | `false` | Require a passing discovery receipt for the current mission branch tip (`tests-missing`); independent of the review gate. With the `tower-tests` component row off, planning/mode entry refuse this combination with an explanation. |
|
|
85
85
|
| `gates.allowReviewExemption` | `false` | With `review.requireReview:true`, allow `reviewPolicy:"none"` + a non-empty reason to skip review blockers. Off deliberately; irrelevant while the global review gate is off. |
|
|
86
86
|
| `gates.maxReportBytes` | `32768` (32 KiB) | Hard cap in UTF-8 bytes for `tower_complete.report`. A larger report is rejected with `invalid-argument` and an actionable `nextAction` (file the full text in the mission worktree and reference its path); it is never truncated. Existing larger reports still load. |
|
|
87
87
|
| `docs.board` | `true` | Write `MISSIONS.md` after mutations. |
|
|
@@ -89,16 +89,14 @@ violates the declared schema (for example `merge.timeoutMs` below 1000) fail wit
|
|
|
89
89
|
| `archive.enabled` | `true` | Move terminal (`merged`/`abandoned`) missions whose worktree is gone into `<git-common-dir>/dsh-tower/archive/` at a mutation boundary. Archived missions keep tasks, reviews, findings and the completion report; they are moved, never deleted. |
|
|
90
90
|
| `archive.afterDays` | `30` | Age trigger: a terminal mission untouched for at least this many days is archived on the next mutation (`0` archives immediately). |
|
|
91
91
|
| `archive.maxMissions` | `100` | Cap trigger: once more than this many terminal missions are hot, the oldest eligible ones are archived until the cap holds (`0` archives every eligible terminal mission). A mission with a live worktree is never archived. |
|
|
92
|
-
| `tools.exposeOperational` | `true` | Register batch/resource/import/legacy/recover/test/doctor tools; `false` shrinks the fixed tool-schema context. |
|
|
93
92
|
| `leases.ttlMs` | `900000` | Default advisory lease lifetime; expiry never auto-releases. |
|
|
94
|
-
| `dev.
|
|
95
|
-
| `dev.
|
|
96
|
-
| `dev.reloadRequiredIds` | five Tower loader ids | Entry ids passed to `reconcileProfile` as required. |
|
|
93
|
+
| `dev.reloadDelayMs` | `50` | Delay before a scheduled reload so the tool result is delivered first. Tuning inside the optional `tower-hmr` component. |
|
|
94
|
+
| `dev.reloadRequiredIds` | three Tower loader ids | Entry ids passed to `reconcileProfile` as required by the `tower-hmr` component. Optional component rows are deliberately not required. |
|
|
97
95
|
|
|
98
96
|
## Example
|
|
99
97
|
|
|
100
98
|
```yaml
|
|
101
|
-
- id: tower
|
|
99
|
+
- id: tower-host
|
|
102
100
|
name: 'dsh-tower'
|
|
103
101
|
config:
|
|
104
102
|
mode:
|
|
@@ -113,10 +111,14 @@ violates the declared schema (for example `merge.timeoutMs` below 1000) fail wit
|
|
|
113
111
|
reviewerModel:
|
|
114
112
|
provider: deepseek-account
|
|
115
113
|
model: deepseek-flash
|
|
116
|
-
dev:
|
|
117
|
-
hotReload: true
|
|
118
114
|
```
|
|
119
115
|
|
|
116
|
+
The optional capabilities (`tower-skills`, `tower-batch`, `tower-import`,
|
|
117
|
+
`tower-leases`, `tower-tests`, `tower-hmr`, `preset-tower-reviewer`) are switched
|
|
118
|
+
from the plugin page, not from a config key. The keys that used to switch them
|
|
119
|
+
(`tools.expose*`, `dev.hotReload`) were removed in 2.4.0 and are rejected as
|
|
120
|
+
unknown keys.
|
|
121
|
+
|
|
120
122
|
## Looking up the effective schema
|
|
121
123
|
|
|
122
124
|
`cordis_inspect_query` with `Config.listConfigs({ name: "dsh-tower" })` returns the projected JSON
|
package/docs/reference/doctor.md
CHANGED
|
@@ -8,17 +8,17 @@ It returns:
|
|
|
8
8
|
"ok": true,
|
|
9
9
|
"checks": [
|
|
10
10
|
{ "id": "git", "status": "pass", "detail": "git version 2.55.0" },
|
|
11
|
-
{ "id": "surface", "status": "pass", "detail": "config keys:
|
|
11
|
+
{ "id": "surface", "status": "pass", "detail": "config keys: 56 · sections: 14 · tools: 29 (baseline 2026-10-23)" },
|
|
12
12
|
{ "id": "state", "status": "pass", "detail": ".../state.json revision 7" },
|
|
13
13
|
{ "id": "state-schema", "status": "pass", "detail": "schemaVersion 3 is current" },
|
|
14
14
|
{ "id": "case-mode", "status": "pass", "detail": "caseInsensitive: true; scope matching uses case-insensitive comparison" }
|
|
15
15
|
],
|
|
16
16
|
"surface": {
|
|
17
|
-
"configKeys":
|
|
18
|
-
"sections":
|
|
19
|
-
"tools":
|
|
17
|
+
"configKeys": 56,
|
|
18
|
+
"sections": 14,
|
|
19
|
+
"tools": 29,
|
|
20
20
|
"baselineDate": "2026-10-23",
|
|
21
|
-
"line": "config keys:
|
|
21
|
+
"line": "config keys: 56 · sections: 14 · tools: 29"
|
|
22
22
|
},
|
|
23
23
|
"stateLock": {
|
|
24
24
|
"held": true,
|
|
@@ -67,10 +67,15 @@ It returns:
|
|
|
67
67
|
|
|
68
68
|
`surface` (and the `surface` check) reports the concept budget in the same format
|
|
69
69
|
as the generated references: `config keys: N · sections: N · tools: N`, plus the
|
|
70
|
-
committed baseline date from `scripts/surface-baseline.json`. The counts are live
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
committed baseline date from `scripts/surface-baseline.json`. The counts are live:
|
|
71
|
+
the config schema and every tool the build ships — `define()`-registered tools,
|
|
72
|
+
the `tower_mode`/`tower_control` pair the Host entry registers directly (#118),
|
|
73
|
+
and the capability tools whose optional component row may be off (#121) —
|
|
74
|
+
independent of the operational switches. The `tools` count is therefore the full
|
|
75
|
+
build surface (29 in 2.4.0), even though the shipped profile mounts 28 because
|
|
76
|
+
`tower-hmr` ships off; the `components` check names the mounted subset and every
|
|
77
|
+
disabled row. `npm run surface:check` is what fails when a count grew without an
|
|
78
|
+
ADR, a matching deletion or a recorded measurement correction. See
|
|
74
79
|
[surface-budget.md](surface-budget.md) for the classification table.
|
|
75
80
|
|
|
76
81
|
`stateSchema` describes the file **on disk**, not the in-memory document: `currentVersion` is the
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# Surface budget
|
|
2
2
|
|
|
3
|
-
The plugin measures its user-facing surface in
|
|
4
|
-
**config sections**,
|
|
5
|
-
[`scripts/surface-baseline.json`](../../scripts/surface-baseline.json);
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
The plugin measures its user-facing surface in four numbers: **config leaf keys**,
|
|
4
|
+
**config sections**, **registered tools**, and **visible component rows**. The
|
|
5
|
+
committed baseline is [`scripts/surface-baseline.json`](../../scripts/surface-baseline.json);
|
|
6
|
+
the brakes are `npm run surface:check` for the first three and
|
|
7
|
+
`npm run docs:check:components` for the component count; the decision records are
|
|
8
|
+
[ADR 0004](../adr/0004-surface-budget.md) and
|
|
9
|
+
[ADR 0005](../adr/0005-component-surface.md).
|
|
8
10
|
|
|
9
11
|
Decision date: 2026-10-23
|
|
10
12
|
|
|
@@ -14,6 +16,37 @@ default a user may want to change, and `niche` was added for one workflow and
|
|
|
14
16
|
must carry a removal note for the next minor. A live key or tool missing from
|
|
15
17
|
these tables fails `npm run surface:check`.
|
|
16
18
|
|
|
19
|
+
A second axis asks who may turn a key off. It is generated from
|
|
20
|
+
[`scripts/component-surface.json`](../../scripts/component-surface.json) into
|
|
21
|
+
[component-surface.md](component-surface.md): every key is `core`,
|
|
22
|
+
`optional-component`, `optional-config` or `forbidden-to-disable`, and the
|
|
23
|
+
component count is the fourth baselined surface, two-way: a contraction needs a
|
|
24
|
+
dated decision just like growth does (`npm run docs:check:components`,
|
|
25
|
+
[ADR 0005](../adr/0005-component-surface.md)). The same source of truth records
|
|
26
|
+
the `gateableTools` allowlist; it is empty since #122, so a future
|
|
27
|
+
`tools.expose*` route to any tool is refused before it can remove a review,
|
|
28
|
+
merge or host tool.
|
|
29
|
+
|
|
30
|
+
The 2.3.0 baseline counted 27 tools because it recorded only the `define()` path.
|
|
31
|
+
`tower_mode` and `tower_control` are registered directly by `index.js`, so the
|
|
32
|
+
shipped surface was always 29. The 27 → 29 step is an explicit
|
|
33
|
+
*measurement correction* with a reason and date in
|
|
34
|
+
[`scripts/surface-baseline.json`](../../scripts/surface-baseline.json) (see
|
|
35
|
+
[ADR 0004](../adr/0004-surface-budget.md)), not surface growth; a later count
|
|
36
|
+
change still needs an ADR or a provably matching deletion.
|
|
37
|
+
|
|
38
|
+
The tool count is the **build** surface, not one profile's mounted subset (#121):
|
|
39
|
+
the recorder includes every tool this build can register, so a component row that
|
|
40
|
+
ships off (`tower-hmr`, whose `tower_reload` keeps the count at 29) does not
|
|
41
|
+
shrink the budget. `tower_doctor` reports the same 29 and names the mounted
|
|
42
|
+
subset through its `components` check; the mount smoke asserts the shipped
|
|
43
|
+
profile's 28 loaded tools and pins 29 for the all-rows-on surface.
|
|
44
|
+
|
|
45
|
+
#121 also shrank the config surface: the seven capability `tools.expose*` keys
|
|
46
|
+
and `dev.hotReload` became component rows, so config keys went 64 → 56 and
|
|
47
|
+
sections 15 → 14. Those are recorded shrank values in the committed baseline,
|
|
48
|
+
not free growth: a later increase still needs its own decision.
|
|
49
|
+
|
|
17
50
|
## Config keys
|
|
18
51
|
|
|
19
52
|
| Key | Class | Note |
|
|
@@ -71,53 +104,49 @@ these tables fails `npm run surface:check`.
|
|
|
71
104
|
| `archive.enabled` | core | Controls whether terminal missions leave the hot state. |
|
|
72
105
|
| `archive.afterDays` | tuning | Archive age threshold. |
|
|
73
106
|
| `archive.maxMissions` | tuning | Hot terminal-mission cap. |
|
|
74
|
-
| `tools.exposeOperational` | core | Master switch for the operational tool surface. |
|
|
75
|
-
| `tools.exposeBatch` | core | Registers the evidence-batch tool. |
|
|
76
|
-
| `tools.exposeImport` | core | Registers the legacy import tools. |
|
|
77
|
-
| `tools.exposeLeases` | core | Registers advisory leases. |
|
|
78
|
-
| `tools.exposeTests` | core | Registers test discovery; required when the test gate is on. |
|
|
79
|
-
| `tools.exposeRecovery` | core | Registers the stale-lock escape hatch. |
|
|
80
|
-
| `tools.exposeDoctor` | core | Registers the read-only health contract. |
|
|
81
107
|
| `leases.ttlMs` | tuning | Default advisory lease lifetime. |
|
|
82
|
-
| `dev.hotReload` | tuning | Registers the dev reload tool when HMR exists. |
|
|
83
108
|
| `dev.reloadDelayMs` | tuning | Delay so a tool result is delivered before reload. |
|
|
84
109
|
| `dev.reloadRequiredIds` | niche | Loader ids added for one linked-profile development setup. Removal note: derive the required ids from the bundle manifest in the next minor. |
|
|
85
110
|
|
|
86
111
|
## Tools
|
|
87
112
|
|
|
88
113
|
Tools are `core` when the product does not work without them and `optional` when
|
|
89
|
-
|
|
90
|
-
|
|
114
|
+
a component row (`tower-batch`, `tower-import`, `tower-leases`, `tower-tests`,
|
|
115
|
+
`tower-hmr`), `mode.allowAgentControl`, or the dev mode can legitimately remove
|
|
116
|
+
them from the surface. `tower_doctor` and `tower_recover` are core: #122 made
|
|
117
|
+
them mandatory for every configuration.
|
|
91
118
|
|
|
92
119
|
| Tool | Class | Note |
|
|
93
120
|
|---|---|---|
|
|
94
121
|
| `tower_adopt` | core | Reconciles a restored roster with the durable catalog. |
|
|
95
|
-
| `tower_batch` | optional | Evidence-batch workflow; `
|
|
122
|
+
| `tower_batch` | optional | Evidence-batch workflow; component `tower-batch`. |
|
|
96
123
|
| `tower_complete` | core | The only completion path for a worker. |
|
|
124
|
+
| `tower_control` | optional | Model-initiated mode change; `mode.allowAgentControl:false` removes it (ADR 0003). |
|
|
97
125
|
| `tower_diff` | core | The read-only review view. |
|
|
98
|
-
| `tower_doctor` |
|
|
126
|
+
| `tower_doctor` | core | Read-only health contract; registered for every configuration (#122). |
|
|
99
127
|
| `tower_finding` | core | Out-of-scope issue recording. |
|
|
100
128
|
| `tower_findings` | core | Finding lifecycle. |
|
|
101
|
-
| `tower_import_legacy` | optional | Legacy migration; `
|
|
129
|
+
| `tower_import_legacy` | optional | Legacy migration; component `tower-import`. |
|
|
102
130
|
| `tower_inbox` | core | Message delivery and acknowledgement. |
|
|
103
131
|
| `tower_init` | core | Creates the repository state. |
|
|
104
132
|
| `tower_interrupt` | core | Stops a runaway worker. |
|
|
105
|
-
| `tower_legacy_map` | optional | Legacy audit mapping; `
|
|
133
|
+
| `tower_legacy_map` | optional | Legacy audit mapping; component `tower-import`. |
|
|
106
134
|
| `tower_merge` | core | The only merge path. |
|
|
107
135
|
| `tower_mission` | core | Mission progress and blockers. |
|
|
136
|
+
| `tower_mode` | core | Reports the session stance, workspace lock, HMR and plugin version; always registered. |
|
|
108
137
|
| `tower_plan` | core | Mission planning. |
|
|
109
138
|
| `tower_preflight` | core | The read-only merge gate. |
|
|
110
139
|
| `tower_rebase` | core | Keeps a mission branch current. |
|
|
111
|
-
| `tower_recover` |
|
|
112
|
-
| `tower_reload` | optional | Dev-only reload;
|
|
113
|
-
| `tower_resource` | optional | Advisory leases; `
|
|
140
|
+
| `tower_recover` | core | Stale-lock recovery; registered for every configuration (#122). |
|
|
141
|
+
| `tower_reload` | optional | Dev-only reload; component `tower-hmr` (shipped off). |
|
|
142
|
+
| `tower_resource` | optional | Advisory leases; component `tower-leases`. |
|
|
114
143
|
| `tower_review` | core | Independent review verdicts. |
|
|
115
144
|
| `tower_roster` | core | Roster and live activity. |
|
|
116
145
|
| `tower_send` | core | Durable messages to agents. |
|
|
117
146
|
| `tower_spawn` | core | Starts workers and reviewers. |
|
|
118
147
|
| `tower_status` | core | The dashboard. |
|
|
119
148
|
| `tower_teardown` | core | Worktree cleanup and archiving. |
|
|
120
|
-
| `tower_test` | optional | Explicit discovery; `
|
|
149
|
+
| `tower_test` | optional | Explicit discovery; component `tower-tests`. |
|
|
121
150
|
|
|
122
151
|
## Non-goals
|
|
123
152
|
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# Tools overview (generated)
|
|
2
2
|
|
|
3
3
|
> Generated by `npm run docs:generate:tools` from the registered tool definitions. Do not edit by hand.
|
|
4
|
-
> Surface: config keys:
|
|
4
|
+
> Surface: config keys: 56 · sections: 14 · tools: 29 · baseline 2026-10-23. Generated from `scripts/surface-baseline.json`; do not edit by hand.
|
|
5
5
|
|
|
6
6
|
| Tool | Description |
|
|
7
7
|
|---|---|
|
|
8
8
|
| `tower_adopt` | Reconcile the roster with the durable subagent catalog after a restart or new session. Agents that are provably gone are marked retired (records are kept) or missing (retireMissing:false, so the tower can inspect/take over); agents whose parent catalog cannot be read stay unknown and are never changed. Only the tower may adopt. |
|
|
9
9
|
| `tower_batch` | Manage finite evidence batches: create freezes missionIds/requiredChecks/receiptPaths, status summarizes members, close verifies every required check and receipt hash, abandon retires a stale open batch. Membership and exclusions are immutable after create; close/abandon never remove missions. |
|
|
10
10
|
| `tower_complete` | Worker-only: report mission completion. Enforced by the store: every task done or dropped, no blockers, the current owner, the mission branch has at least one commit since its spawn base, and no unread inbox messages. checks records verifiable evidence (name/command/exitCode/evidence); gates.requireChecks can require at least one before merge. Stores the full report, capped at gates.maxReportBytes (default 32768 UTF-8 bytes); a larger report is rejected with invalid-argument and an actionable nextAction, never truncated. Persists reportBytes on the stored report. completion means ready for preflight and optional review, not merged. |
|
|
11
|
+
| `tower_control` | Enter or leave Tower mode for the calling agent. Allowed only when the deployment enables allowAgentControl; use it when the user intent or task state clearly calls for Tower orchestration or a return to normal collaboration, and always state a concrete reason. |
|
|
11
12
|
| `tower_diff` | Read-only view of a mission branch for review: merge base, changed files, commits, and a capped patch against the recorded base. Safe for reviewers; it never modifies the repository. |
|
|
12
13
|
| `tower_doctor` | Read-only environment and repository health check: the concept-budget surface (config keys/sections/tools), git, state schema, case-sensitivity detection (caseInsensitive and the active scope comparison mode), config, presets/subagents/HMR, the state lock age/heartbeat freshness, the repo-scoped git lock holder (gitLock: {held,pid,phase,heldMs}), workspace lock, roster staleness, worktree ownership, test discovery, leases, and the terminal-mission archive (count, bytes, years, unreadable diagnostics and the configured afterDays/maxMissions policy). Returns checks with pass/warn/fail, state-lock and git-lock reports and an environment contract. Never writes state and never probes the filesystem. |
|
|
13
14
|
| `tower_finding` | File a structured finding (bug / improve / vuln / idea) for the tower to route. Use this for anything notable OUTSIDE your mission scope instead of editing out-of-scope files. Severity is one of low|medium|high|critical. Use tower_findings to list, read, or close findings later. |
|
|
@@ -19,11 +20,12 @@
|
|
|
19
20
|
| `tower_legacy_map` | Audit-only mapping between a legacy snapshot id and a current mission. map records sourceHash/oldId/newMissionId; status lists mappings. Mapping never adopts or resumes a legacy mission. |
|
|
20
21
|
| `tower_merge` | Merge a mission branch into the recorded base branch with --no-ff, after the hard gate passes. Verifies the two merge parents and records the mission as merged. If the merge commit already landed (manual merge, crashed or slow pre-merge hook), it detects the merge commit and records it as reconciled instead of merging again. A failed gate returns stable blocker codes without merging; a hook failure aborts cleanly and returns "merge-hook-failed" while a real content conflict returns "merge-conflict". |
|
|
21
22
|
| `tower_mission` | Update one mission: lifecycle status, decision note, blocker, clear blockers, mark a task done, drop a task with a reason, or widen the scope (tower only). "merged" is never set here; only a future tower_merge records it. Merged and abandoned are terminal. |
|
|
23
|
+
| `tower_mode` | Report whether Tower mode is active for the calling agent, who changed it last, whether the model may toggle it, any goal paused on entry, the workspace lock, HMR availability and the plugin version. |
|
|
22
24
|
| `tower_plan` | Plan one or more missions in an initialized repository. Each mission has a printable-Unicode title (NFC-normalized, at most 120 characters), relative scope globs, optional task checklist, optional mission-id dependencies, and kind build|survey. Assigns M1.. ids and auto-adds a dependency when build scopes overlap (serializes merges); rejects dependency cycles. |
|
|
23
25
|
| `tower_preflight` | Read-only merge gate for one mission: returns ok plus stable blocker codes (branch-missing, deps-unmerged, read-only-survey, stale-base, out-of-scope, base-dirty, branch-owned-by-closed-missions, and mission/worker guards). Review blockers (no-review, review-hold, not-clean, review-not-approved, tip-moved, review-mission-mismatch) apply only when review.requireReview is on. Never changes anything. |
|
|
24
26
|
| `tower_rebase` | Rebase a mission branch onto the current base tip inside its own worktree. Refuses while its worker is running or the worktree is dirty. A clean conflict-free rebase waives re-review for the old review; a conflict is aborted and the mission is marked blocked. If the branch is already contained in the base, it returns alreadyMerged and leaves the branch untouched so tower_merge can record the landed merge. |
|
|
25
27
|
| `tower_recover` | Read-only recovery diagnostics and an explicit stale-state-lock repair. status reports the state lock owner with its age, heartbeat age and staleness; clear-stale-lock requires confirm:"CLEAR_STALE_LOCK" and only moves a lock whose PID is provably dead to a backup file. force:true additionally clears a live-but-silent PID (a recycled PID) and still renames the record to a .recovered-<ts> backup. It never resets Tower state or worktrees. |
|
|
26
|
-
| `tower_reload` | Dev-only: ask DSH HMR to reconcile this profile and reload the Tower Host plugin from disk. The reload is scheduled a few milliseconds after this call returns (so the result reaches the model first). Use after editing the plugin source in a linked profile; plugin_manager install/update already triggers reconciliation by itself.
|
|
28
|
+
| `tower_reload` | Dev-only: ask DSH HMR to reconcile this profile and reload the Tower Host plugin from disk. Registered only while the tower-hmr component is on (the row is shipped off). The reload is scheduled a few milliseconds after this call returns (so the result reaches the model first). Use after editing the plugin source in a linked profile; plugin_manager install/update already triggers reconciliation by itself. Fails with reload-unavailable when the HMR service is absent. |
|
|
27
29
|
| `tower_resource` | Advisory resource leases per repository (coordination only; no OS CPU/memory hard cap). acquire/release require a token and are tower-only; status is read-only. Expired leases are never taken over silently. |
|
|
28
30
|
| `tower_review` | Submit an independent review verdict bound to the current branch tip: a completed mission starts a review round, and while the mission is active a later route may still record a verdict for that same reviewed tip, appending to the same round without changing the status (a moved tip is rejected with an explanation). status is "clean", "p1-Nitems", or "p2-Nitems"; merge is "merge", "fix-then-merge", or "hold" (only clean + merge is later approval). Non-clean returns the mission to active. Reviewers are capped at 5 rounds per branch; a tower-submitted review is break-glass and requires breakGlassReason. |
|
|
29
31
|
| `tower_roster` | List tower roster agents with authoritative live activity from the subagent catalog (running/inactive/missing/unknown). Read-only; never resumes children. Use before completion or merge decisions. |
|
package/docs/reference/tools.md
CHANGED
|
@@ -3,8 +3,11 @@
|
|
|
3
3
|
All tools take `repoRoot` (an absolute path inside the target Git repository) and return JSON.
|
|
4
4
|
The build exposes up to 29 tools: 19 core repository tools below (including `tower_interrupt`),
|
|
5
5
|
`tower_mode`, `tower_control` (registered by default; set `mode.allowAgentControl:false` to disable),
|
|
6
|
-
`
|
|
7
|
-
`
|
|
6
|
+
the always-registered `tower_doctor` and `tower_recover` (#122), and the component-owned tools
|
|
7
|
+
`tower_reload` (`tower-hmr`), `tower_test` (`tower-tests`), `tower_batch` (`tower-batch`),
|
|
8
|
+
`tower_resource` (`tower-leases`), `tower_import_legacy` / `tower_legacy_map` (`tower-import`).
|
|
9
|
+
A component row that is off removes exactly its tools; `tower_status` and `tower_doctor` report it
|
|
10
|
+
as "disabled by component <id>".
|
|
8
11
|
|
|
9
12
|
`tower_mission` uses `id` (alias `missionId`); every other mission-scoped tool uses `missionId`
|
|
10
13
|
(alias `id`). Other input aliases: `task_done`/`taskDone`, `task_drop`/`taskDrop`,
|
|
@@ -52,7 +55,7 @@ findings but not mutate them. Violations throw `[tower:not-authorized]` or
|
|
|
52
55
|
| `tower_teardown` | `force?`, `exclude?`, `dry_run?` (alias `dryRun`) | Remove eligible merged/abandoned worktrees and branches; running agents are always kept. The final pass applies the `archive` policy: terminal missions whose worktree is gone are moved to `<git-common-dir>/dsh-tower/archive/` once `archive.afterDays`/`archive.maxMissions` says so, and `archived` lists their ids. Nothing is deleted; `archive.afterDays:0` archives a just-torn-down mission immediately. |
|
|
53
56
|
| `tower_mode` | — | Report mode, last change, paused goal, denied tools, store path, plugin version, HMR availability, workspace-lock holder. |
|
|
54
57
|
| `tower_control` | `action` (`enter`/`exit`), `reason` | Model-initiated mode change; registered by default; disable with `mode.allowAgentControl:false`; reason is mandatory. |
|
|
55
|
-
| `tower_reload` | `repoRoot?` | Dev-only: ask DSH HMR to reconcile the profile and reload the Host plugin from disk. Registered while `
|
|
58
|
+
| `tower_reload` | `repoRoot?` | Dev-only: ask DSH HMR to reconcile the profile and reload the Host plugin from disk. Registered while the `tower-hmr` component row is on (the row ships off); scheduled after the result (default 50 ms); fails with `reload-unavailable` without HMR. When `repoRoot` is supplied the caller must be the tower. |
|
|
56
59
|
| `tower_doctor` | — (takes `repoRoot`) | Read-only health contract: the concept-budget surface (`config keys: N · sections: N · tools: N`), git, state schema, config, presets/subagents/HMR, the state lock's age and heartbeat freshness, the repo-scoped git lock holder, workspace lock, roster, worktree realpath/ownership, test config, leases and the terminal-mission archive. Returns `{ok, checks[{id,status,detail}], surface, stateLock, gitLock, stateSchema, archive, environmentContract}`; `surface` reports `{configKeys, sections, tools, baselineDate, line}` so growth against `scripts/surface-baseline.json` is visible in the output, `stateLock` reports `{held, pid, startedAt, at, alive, ageMs, heartbeatAgeMs, staleAfterMs, stale}` so a stuck tower is diagnosable without reading the file, and `gitLock` reports `{held, pid, phase, heldMs}` (`{held:false}` when free) with a `git-lock` check. `archive` reports `{missions, archivedMissions, stateBytes, archiveBytes, years, files, unreadable, policy{enabled,afterDays,maxMissions}}`. A missing archive directory is healthy; a corrupt file is a `warn` with its diagnostic. Never writes. |
|
|
57
60
|
| `tower_recover` | `action` (`status`/`clear-stale-lock`), `confirm?`, `force?` | Recovery diagnostics plus an explicit stale state-lock repair. `clear-stale-lock` requires `confirm:"CLEAR_STALE_LOCK"` and only moves a lock whose PID is provably dead to a `.recovered-<ts>` backup. `force:true` additionally clears a live-but-silent PID (a recycled PID): the output names `{pid, startedAt, ageMs, heartbeatAgeMs}` and the record is still renamed, never unlinked. It never resets state/worktrees. |
|
|
58
61
|
| `tower_test` | `missionId` (alias `id`) | Run the worktree's `package.json` `tower.testDiscovery` and record a receipt; `ok:false` on failure. Use `tower_complete` for automatic admission checks. |
|
package/docs/zh/README.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
时如何处理活跃的 plan mode。
|
|
20
20
|
- **可观察性**:成功的工具调用发出进程内 [Tower 事件](reference/events.md);稳定
|
|
21
21
|
[工具错误码](reference/errors.md) 与 [blocker code](reference/blockers.md) 可被程序匹配。
|
|
22
|
-
- **工具面**:本构建最多
|
|
22
|
+
- **工具面**:本构建最多 29 个工具(含可选的 `tower_control` 与 `tower_reload`);详见
|
|
23
23
|
[工具参考](reference/tools.md)。
|
|
24
24
|
|
|
25
25
|
## 选择阅读路径
|
|
@@ -26,7 +26,7 @@ Tower 是 Host 插件:它的工具与提示段落在 DSH 启动时加载。DSH
|
|
|
26
26
|
- 仍然可以显式请求对账(`/tower reload`、`tower_reload` 或 `plugin_manager`);即使 `root: []`,
|
|
27
27
|
它也会比较已加载模块与磁盘,并替换发生变化的模块。监视只是让保存后自动触发这次对账。
|
|
28
28
|
- HMR 只为 profile 启动挂载(没有 `profileContext` 时 `disabled`)。没有 profile 启动的进程会报告
|
|
29
|
-
reload 不可用(`
|
|
29
|
+
reload 不可用(`tower-hmr` 组件行开启时 `tower_reload` 仍注册,因此返回 `reload-unavailable`,
|
|
30
30
|
而不是消失)。
|
|
31
31
|
- profile patch 层在 DSH 启动时加载。编辑它——实际就是 hmr 的 `root` 列表——需要**重启一次 DSH**
|
|
32
32
|
才生效。运行中的进程不会重新读取 HMR 行自身的配置。
|
|
@@ -95,9 +95,9 @@ Windows 上通常是 `C:\Users\<you>\.dsh`):
|
|
|
95
95
|
|
|
96
96
|
| 配置键 | 含义 |
|
|
97
97
|
|---|---|
|
|
98
|
-
| `
|
|
98
|
+
| `tower-hmr`(组件行) | 开关本体:开启时注册 `tower_reload` 与 `/tower reload`,关闭时报告“disabled by component tower-hmr”。该行随包关闭;联动开发 profile 在插件页启用它。`dev.hotReload` 已在 2.4.0 移除,现在会作为未知键被拒绝。 |
|
|
99
99
|
| `dev.reloadDelayMs` | 计划中的对账运行前的延迟,单位毫秒(默认 `50`),让工具/命令结果先送达模型,再替换插件。 |
|
|
100
|
-
| `dev.reloadRequiredIds` | profile 必须保持活跃的 Loader 条目 id(默认 `tower
|
|
100
|
+
| `dev.reloadRequiredIds` | profile 必须保持活跃的 Loader 条目 id(默认 `tower`、`tower-host`、`preset-tower-worker`)。即使某个 required 条目早已处于非活跃状态,也会被报告为重载失败。可选能力行刻意不在 required 中,因此关闭某一行不会被误报为 reload 失败。 |
|
|
101
101
|
|
|
102
102
|
重载是**调度而非等待**:`/tower reload` 与 `tower_reload` 立即返回 `scheduled`、`delayMs`、
|
|
103
103
|
`requiredIds`(以及存在待处理错误时的 `lastError`),随后 HMR 在延迟后对账 profile。这是有意为之——
|