dsh-tower 2.1.0 → 2.3.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 +103 -0
- package/COMPATIBILITY.md +5 -1
- package/CONTRIBUTING.md +64 -5
- package/PRINCIPLES.md +145 -0
- package/README.en.md +7 -4
- package/README.md +7 -4
- package/SECURITY.md +6 -0
- package/{lib → adapters}/archive.js +1 -1
- package/{lib → adapters}/caseSensitivity.js +1 -1
- package/adapters/default.js +51 -10
- package/{lib → adapters}/git.js +1 -1
- package/{lib → adapters}/leases.js +1 -1
- package/{lib → adapters}/legacy.js +1 -1
- package/adapters/persistence.js +543 -0
- package/adapters/store-fs.js +28 -1
- package/adapters/store.js +204 -0
- package/{lib → adapters}/tests.js +9 -5
- package/adapters/vcs-git.js +15 -1
- package/{lib → adapters}/workspaceLock.js +1 -1
- package/{lib → adapters}/worktreeOwnership.js +1 -1
- package/app/archive.js +4 -6
- package/app/batch.js +9 -10
- package/app/board.js +2 -4
- package/app/checkCompletion.js +9 -10
- package/app/enrichedMissions.js +2 -4
- package/app/findings.js +6 -7
- package/app/gate.js +1 -2
- package/app/init.js +24 -29
- package/app/merge.js +58 -51
- package/app/messages.js +7 -8
- package/app/mission.js +5 -5
- package/app/plan.js +8 -5
- package/app/provision.js +12 -14
- package/app/read.js +6 -3
- package/app/rebase.js +14 -16
- package/app/recording.js +7 -8
- package/app/review.js +15 -8
- package/app/roster.js +14 -15
- package/{lib → app}/spawn-prechecks.js +4 -3
- package/app/spawn.js +12 -13
- package/app/teardown.js +8 -9
- package/app/tower.js +89 -35
- package/docs/README.md +6 -2
- package/docs/adr/0001-ports-adapters-as-data.md +49 -0
- package/docs/adr/0002-single-state-json.md +50 -0
- package/docs/adr/0003-allow-agent-control-default-true.md +48 -0
- package/docs/adr/0004-surface-budget.md +50 -0
- package/docs/adr/README.md +51 -0
- package/docs/agents/workflow.md +51 -0
- package/docs/architecture/overview.md +167 -36
- package/docs/guide/hot-reload.md +1 -1
- package/docs/guide/release.md +1 -1
- package/docs/operations/incident.md +82 -0
- package/docs/operations/runbook.md +12 -3
- package/docs/reference/blockers.md +2 -2
- package/docs/reference/config.generated.md +1 -0
- package/docs/reference/doctor.md +48 -2
- package/docs/reference/errors.generated.md +41 -37
- package/docs/reference/errors.md +53 -41
- package/docs/reference/events.md +38 -6
- package/docs/reference/surface-budget.md +128 -0
- package/docs/reference/tools.generated.md +5 -4
- package/docs/reference/tools.md +4 -4
- package/docs/zh/guide/hot-reload.md +1 -1
- package/docs/zh/reference/blockers.md +2 -2
- package/docs/zh/reference/doctor.md +29 -1
- package/docs/zh/reference/tools.md +4 -4
- package/domain/batch.js +2 -2
- package/domain/config/schema.js +25 -1
- package/domain/contracts/outputs.js +6 -2
- package/domain/contracts/tool-inputs/ops.js +1 -0
- package/domain/errors.js +297 -42
- package/domain/events.js +207 -0
- package/domain/integration/gate.js +17 -2
- package/domain/integration/merge.js +35 -0
- package/domain/lockBudget.js +30 -0
- package/domain/missions/completion.js +14 -0
- package/domain/missions/lifecycle.js +9 -3
- package/domain/missions/plan.js +14 -0
- package/domain/missions/review.js +90 -7
- package/domain/read/views.js +3 -0
- package/domain/state/archive.js +1 -1
- package/domain/state.js +1 -1
- package/domain/surface.js +248 -0
- package/{lib → host}/doctor.js +116 -9
- package/{lib → host}/modeStore.js +1 -1
- package/{lib → host}/tool-registry.js +106 -31
- package/host/tower.js +32 -0
- package/index.js +12 -9
- package/package.json +10 -3
- package/ports/archive.js +18 -0
- package/ports/caseSensitivity.js +15 -0
- package/ports/clock.js +10 -2
- package/ports/config.js +19 -0
- package/ports/contract.js +38 -0
- package/ports/events.js +24 -0
- package/ports/ids.js +10 -2
- package/ports/index.js +54 -2
- package/ports/ownership.js +17 -0
- package/ports/state.js +16 -0
- package/ports/store.js +52 -3
- package/ports/vcs.js +25 -4
- package/scripts/architecture-waivers.json +19 -0
- package/scripts/architecture.mjs +634 -23
- package/scripts/check-docs.mjs +8 -35
- package/scripts/check-pack.mjs +68 -39
- package/scripts/check-philosophy.mjs +266 -0
- package/scripts/domain-metrics.mjs +13 -4
- package/scripts/generate-config-reference.mjs +14 -1
- package/scripts/generate-error-reference.mjs +68 -14
- package/scripts/generate-events-reference.mjs +83 -0
- package/scripts/generate-tools-reference.mjs +11 -0
- package/scripts/issue-audit.mjs +2 -2
- package/scripts/lib/surface.mjs +87 -0
- package/scripts/pack-manifest.txt +58 -22
- package/scripts/regression-audit.mjs +164 -0
- package/scripts/release-check.mjs +1 -1
- package/scripts/surface-baseline.json +21 -0
- package/scripts/surface-baseline.mjs +120 -0
- package/tools/adopt.js +2 -3
- package/tools/batch.js +2 -3
- package/tools/complete.js +2 -3
- package/tools/diff.js +3 -3
- package/tools/doctor.js +7 -10
- package/tools/finding.js +2 -3
- package/tools/findings.js +3 -3
- package/tools/import-legacy.js +3 -5
- package/tools/inbox.js +3 -3
- package/tools/index.js +7 -7
- package/tools/init.js +3 -6
- package/tools/interrupt.js +2 -3
- package/tools/legacy-map.js +3 -5
- package/tools/merge.js +3 -3
- package/tools/mission.js +2 -3
- package/tools/plan.js +6 -5
- package/tools/preflight.js +2 -3
- package/tools/rebase.js +3 -3
- package/tools/recover.js +38 -13
- package/tools/reload.js +3 -6
- package/tools/resource.js +3 -5
- package/tools/review.js +3 -4
- package/tools/roster.js +2 -3
- package/tools/send.js +2 -2
- package/tools/spawn.js +8 -5
- package/tools/status.js +3 -3
- package/tools/teardown.js +2 -3
- package/tools/test.js +2 -2
- package/types/index.d.ts +1 -1
- package/ui-bundle/README.md +37 -3
- package/ui-bundle/client.cards.js +356 -0
- package/ui-bundle/client.denied.js +142 -0
- package/ui-bundle/client.dock.js +333 -0
- package/ui-bundle/client.helpers.js +271 -0
- package/ui-bundle/client.js +79 -1747
- package/ui-bundle/client.locales.js +247 -0
- package/ui-bundle/client.mode.js +206 -0
- package/ui-bundle/client.overlay.js +64 -0
- package/ui-bundle/client.styles.js +151 -0
- package/ui-bundle/client.toolview.js +82 -0
- package/ui-bundle/package.json +1 -0
- package/lib/persistence.js +0 -356
- package/lib/store.js +0 -133
- /package/{lib → adapters}/stateFile.js +0 -0
- /package/{lib → app}/briefing.js +0 -0
- /package/{lib → app}/spawn-support.js +0 -0
- /package/{lib → host}/compatibility.js +0 -0
- /package/{lib → host}/config.js +0 -0
- /package/{lib → host}/hmr.js +0 -0
- /package/{lib → host}/modeState.js +0 -0
- /package/{lib → host}/presets.js +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Concept-budget gate (#84): compare the live surface with the committed
|
|
3
|
+
// baseline and require evidence for growth.
|
|
4
|
+
//
|
|
5
|
+
// The surface is three counts the user has to hold at once:
|
|
6
|
+
// config keys leaf keys in domain/config/schema.js (one level deep)
|
|
7
|
+
// sections object groups in that schema
|
|
8
|
+
// tools tool definitions registered by host/tool-registry.js
|
|
9
|
+
//
|
|
10
|
+
// `scripts/surface-baseline.json` freezes those counts. A PR that grows a count
|
|
11
|
+
// fails here until the baseline carries a decision with either an ADR under
|
|
12
|
+
// docs/adr/ or deletions that no longer exist in the live surface. The same
|
|
13
|
+
// file supplies the date and counts printed in the generated config/tools
|
|
14
|
+
// reference headers, so growth is visible in a diff.
|
|
15
|
+
//
|
|
16
|
+
// Usage:
|
|
17
|
+
// node scripts/surface-baseline.mjs [--root <dir>] [--json]
|
|
18
|
+
import fs from 'node:fs'
|
|
19
|
+
import path from 'node:path'
|
|
20
|
+
import { fileURLToPath } from 'node:url'
|
|
21
|
+
import { configSurface } from '../domain/config/schema.js'
|
|
22
|
+
import { SURFACE_CLASSIFICATION_FILE, SURFACE_BASELINE_FILE, surfaceLine } from '../domain/surface.js'
|
|
23
|
+
import { registerTowerTools } from '../tools/index.js'
|
|
24
|
+
import { definedToolNames } from '../host/tool-registry.js'
|
|
25
|
+
import { checkSurfaceBudget } from './lib/surface.mjs'
|
|
26
|
+
import { parseArgs, runMain } from './lib/cli.mjs'
|
|
27
|
+
|
|
28
|
+
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
|
29
|
+
const USAGE = `usage: node scripts/surface-baseline.mjs [--root <dir>] [--json]
|
|
30
|
+
|
|
31
|
+
--root repository root to check (default: this package)
|
|
32
|
+
--json print the report as JSON
|
|
33
|
+
--help print this text
|
|
34
|
+
|
|
35
|
+
Growth is refused by default. To grow a count, update ${SURFACE_BASELINE_FILE}
|
|
36
|
+
with a decision that names an existing docs/adr/ ADR or deletions that are no
|
|
37
|
+
longer in the live surface. The classification table in
|
|
38
|
+
${SURFACE_CLASSIFICATION_FILE} must cover every key and tool exactly once.`
|
|
39
|
+
|
|
40
|
+
/** Register the real tool surface against a minimal mock context. */
|
|
41
|
+
function liveToolNames() {
|
|
42
|
+
const ctx = {
|
|
43
|
+
get() {
|
|
44
|
+
return undefined
|
|
45
|
+
},
|
|
46
|
+
effect(fn) {
|
|
47
|
+
const dispose = fn()
|
|
48
|
+
return typeof dispose === 'function' ? dispose : () => {}
|
|
49
|
+
},
|
|
50
|
+
systemPrompt: { section() {} },
|
|
51
|
+
tools: {
|
|
52
|
+
register() {
|
|
53
|
+
return () => {}
|
|
54
|
+
},
|
|
55
|
+
guard() {
|
|
56
|
+
return () => {}
|
|
57
|
+
},
|
|
58
|
+
restrict() {
|
|
59
|
+
return () => {}
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
registerTowerTools(ctx)
|
|
64
|
+
return definedToolNames()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The live surface used by the gate. Exported so tests can compare the counts
|
|
69
|
+
* with the generated references without spawning the CLI.
|
|
70
|
+
*/
|
|
71
|
+
export function liveSurface() {
|
|
72
|
+
const config = configSurface()
|
|
73
|
+
const tools = liveToolNames()
|
|
74
|
+
return {
|
|
75
|
+
configKeys: config.count,
|
|
76
|
+
sections: config.sections.length,
|
|
77
|
+
tools: tools.length,
|
|
78
|
+
liveNames: {
|
|
79
|
+
configKeys: config.keys,
|
|
80
|
+
sections: config.sections,
|
|
81
|
+
tools,
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function main(argv) {
|
|
87
|
+
const options = parseArgs(argv, {
|
|
88
|
+
initial: { root: PACKAGE_ROOT, json: false, help: false },
|
|
89
|
+
values: { '--root': { key: 'root', parse: path.resolve } },
|
|
90
|
+
flags: { '--json': 'json', '--help': 'help', '-h': 'help' },
|
|
91
|
+
})
|
|
92
|
+
if (options.help) {
|
|
93
|
+
console.log(USAGE)
|
|
94
|
+
return 0
|
|
95
|
+
}
|
|
96
|
+
const root = path.resolve(options.root)
|
|
97
|
+
if (!fs.existsSync(path.join(root, SURFACE_BASELINE_FILE))) {
|
|
98
|
+
console.error(`surface: ${SURFACE_BASELINE_FILE} is missing under ${root}`)
|
|
99
|
+
return 2
|
|
100
|
+
}
|
|
101
|
+
const current = liveSurface()
|
|
102
|
+
const result = checkSurfaceBudget({ root, current })
|
|
103
|
+
if (options.json) {
|
|
104
|
+
console.log(JSON.stringify({ root, current, ...result }, null, 2))
|
|
105
|
+
return result.ok ? 0 : 1
|
|
106
|
+
}
|
|
107
|
+
console.log(`surface: ${surfaceLine(current)}`)
|
|
108
|
+
if (result.baseline) console.log(`surface: baseline ${result.baseline.date} (${SURFACE_BASELINE_FILE})`)
|
|
109
|
+
if (result.classification) {
|
|
110
|
+
const configRows = result.classification.entries.filter((entry) => entry.kind === 'config').length
|
|
111
|
+
const toolRows = result.classification.entries.filter((entry) => entry.kind === 'tools').length
|
|
112
|
+
console.log(`surface: classified ${configRows} config keys and ${toolRows} tools (${SURFACE_CLASSIFICATION_FILE})`)
|
|
113
|
+
}
|
|
114
|
+
for (const finding of result.findings) console.log(`surface: ${finding.level} [${finding.code}] ${finding.message}`)
|
|
115
|
+
if (result.ok) console.log('surface: ok — counts match the committed baseline and every entry is classified')
|
|
116
|
+
else console.log(`surface: ${result.findings.length} problem(s); growth needs an ADR or a matching deletion`)
|
|
117
|
+
return result.ok ? 0 : 1
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
await runMain(import.meta.url, () => main(process.argv.slice(2)), { errorPrefix: 'surface', usage: USAGE })
|
package/tools/adopt.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// tower_adopt: reconcile the roster with the subagent catalog.
|
|
2
|
-
import { Tower } from '../app/tower.js'
|
|
3
2
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
4
3
|
import { TowerToolError } from '../domain/errors.js'
|
|
5
4
|
import { AdoptInput } from '../domain/contracts/tool-inputs/index.js'
|
|
@@ -7,7 +6,7 @@ import { PARENT_STATUS_OK, ROSTER_ACTIVITY, ROSTER_STATE } from '../domain/vocab
|
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @param {any} ctx
|
|
10
|
-
* @param {{ define: import('../types/index.js').DefineTool, actorFor: any, requireTowerActor: any }} deps
|
|
9
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, actorFor: any, requireTowerActor: any }} deps
|
|
11
10
|
*/
|
|
12
11
|
export function registerAdoptTool(ctx, deps) {
|
|
13
12
|
const { define, actorFor, requireTowerActor } = deps
|
|
@@ -19,7 +18,7 @@ export function registerAdoptTool(ctx, deps) {
|
|
|
19
18
|
aliases: { retire_missing: ['retireMissing'] },
|
|
20
19
|
output: output(SCHEMAS.adopt),
|
|
21
20
|
async execute(args, exec) {
|
|
22
|
-
const tower = await
|
|
21
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
23
22
|
const actor = await actorFor(tower, exec)
|
|
24
23
|
requireTowerActor(actor, 'adopt the roster')
|
|
25
24
|
const view = await tower.rosterView()
|
package/tools/batch.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// tower_batch: finite evidence batches.
|
|
2
|
-
import { Tower } from '../app/tower.js'
|
|
3
2
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
4
3
|
import { TowerToolError } from '../domain/errors.js'
|
|
5
4
|
import { BatchInput } from '../domain/contracts/tool-inputs/index.js'
|
|
@@ -7,7 +6,7 @@ import { BATCH_ACTION } from '../domain/vocabulary.js'
|
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @param {any} ctx
|
|
10
|
-
* @param {{ define: import('../types/index.js').DefineTool, actorFor: any, requireTowerActor: any, summarizeBatch: any, verifyBatchReceiptFiles: any }} deps
|
|
9
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, actorFor: any, requireTowerActor: any, summarizeBatch: any, verifyBatchReceiptFiles: any }} deps
|
|
11
10
|
*/
|
|
12
11
|
export function registerBatchTool(ctx, deps) {
|
|
13
12
|
const { define, actorFor, requireTowerActor, summarizeBatch, verifyBatchReceiptFiles } = deps
|
|
@@ -19,7 +18,7 @@ export function registerBatchTool(ctx, deps) {
|
|
|
19
18
|
board: true,
|
|
20
19
|
output: output(SCHEMAS.batch),
|
|
21
20
|
async execute(args, exec) {
|
|
22
|
-
const tower = await
|
|
21
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
23
22
|
const actor = await actorFor(tower, exec)
|
|
24
23
|
if (args.action === BATCH_ACTION.status) {
|
|
25
24
|
const state = await tower.load()
|
package/tools/complete.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// tower_complete: worker completion admission.
|
|
2
|
-
import { Tower } from '../app/tower.js'
|
|
3
2
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
4
3
|
import { TowerToolError } from '../domain/errors.js'
|
|
5
4
|
import { CompleteInput } from '../domain/contracts/tool-inputs/index.js'
|
|
@@ -7,7 +6,7 @@ import { isCompleteAdmission } from '../domain/vocabulary.js'
|
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @param {any} ctx
|
|
10
|
-
* @param {{ define: import('../types/index.js').DefineTool, runMissionDiscovery: any }} deps
|
|
9
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, runMissionDiscovery: any }} deps
|
|
11
10
|
*/
|
|
12
11
|
export function registerCompleteTool(ctx, deps) {
|
|
13
12
|
const { define, runMissionDiscovery } = deps
|
|
@@ -21,7 +20,7 @@ export function registerCompleteTool(ctx, deps) {
|
|
|
21
20
|
board: true,
|
|
22
21
|
output: output(SCHEMAS.complete),
|
|
23
22
|
async execute(args, exec) {
|
|
24
|
-
const tower = await
|
|
23
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
25
24
|
// Validate authorization/state before executing repository-controlled
|
|
26
25
|
// test code or writing a test receipt.
|
|
27
26
|
await tower.checkCompletion({
|
package/tools/diff.js
CHANGED
|
@@ -13,15 +13,15 @@
|
|
|
13
13
|
// The patch cap is enforced by the pure read projection.
|
|
14
14
|
// See docs/reference/tools.generated.md for the public shape.
|
|
15
15
|
// tower_diff: read-only mission branch view.
|
|
16
|
-
import { Tower } from '../app/tower.js'
|
|
17
16
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
18
17
|
import { DiffInput } from '../domain/contracts/tool-inputs/index.js'
|
|
19
18
|
|
|
20
19
|
/**
|
|
21
20
|
* @param {any} ctx
|
|
22
|
-
* @param {{ define: import('../types/index.js').DefineTool }} deps
|
|
21
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any }} deps
|
|
23
22
|
*/
|
|
24
23
|
export function registerDiffTool(ctx, deps) {
|
|
24
|
+
// openTower is injected by the composition root (#69).
|
|
25
25
|
const { define } = deps
|
|
26
26
|
define(ctx, {
|
|
27
27
|
name: 'tower_diff',
|
|
@@ -32,7 +32,7 @@ export function registerDiffTool(ctx, deps) {
|
|
|
32
32
|
requiresMissionId: true,
|
|
33
33
|
output: output(SCHEMAS.diff),
|
|
34
34
|
async execute(args) {
|
|
35
|
-
const tower = await
|
|
35
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
36
36
|
return tower.diff({ missionId: args.missionId, maxBytes: args.maxBytes })
|
|
37
37
|
},
|
|
38
38
|
})
|
package/tools/doctor.js
CHANGED
|
@@ -1,36 +1,33 @@
|
|
|
1
1
|
// tower_doctor: read-only health check.
|
|
2
|
-
import { Tower } from '../app/tower.js'
|
|
3
|
-
import { resolveRepo } from '../lib/git.js'
|
|
4
|
-
import { runtimeConfig } from '../lib/config.js'
|
|
5
|
-
import { runDoctor } from '../lib/doctor.js'
|
|
6
2
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
7
3
|
import { DoctorInput } from '../domain/contracts/tool-inputs/index.js'
|
|
8
4
|
import { DOCTOR_STATUS } from '../domain/vocabulary.js'
|
|
9
5
|
|
|
10
6
|
/**
|
|
11
7
|
* @param {any} ctx
|
|
12
|
-
* @param {import('../types/index.js').DefineTool}
|
|
8
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, createTower: any, resolveRepo: any, runtimeConfig: any, runDoctor: any, surface?: () => { tools?: number } }} deps
|
|
13
9
|
*/
|
|
14
|
-
export function registerDoctorTool(ctx,
|
|
10
|
+
export function registerDoctorTool(ctx, deps) {
|
|
11
|
+
const { define, createTower, resolveRepo, runtimeConfig, runDoctor } = deps
|
|
15
12
|
define(ctx, {
|
|
16
13
|
name: 'tower_doctor',
|
|
17
14
|
description:
|
|
18
|
-
'Read-only\ environment\ and\ repository\ health\ check:\ git,\ state\ schema,\ case-sensitivity\ detection\ \(caseInsensitive\ and\ the\ active\ scope\ comparison\ mode\),\ config,\ presets/subagents/HMR,\ 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\ and\ an\ environment\ contract\.\ Never\ writes\ state\ and\ never\ probes\ the\ filesystem\.',
|
|
15
|
+
'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\.',
|
|
19
16
|
parameters: DoctorInput,
|
|
20
17
|
output: output(SCHEMAS.doctor),
|
|
21
18
|
async execute(args, exec) {
|
|
22
19
|
let tower
|
|
23
20
|
let configError = null
|
|
24
21
|
try {
|
|
25
|
-
tower = await
|
|
22
|
+
tower = await deps.openTower(args.repoRoot)
|
|
26
23
|
} catch (error) {
|
|
27
24
|
const message = String(error?.message ?? error)
|
|
28
25
|
if (error?.code !== 'config-invalid' && error?.code !== 'config-unknown-key') throw error
|
|
29
26
|
configError = message
|
|
30
27
|
const repo = await resolveRepo(args.repoRoot)
|
|
31
|
-
tower =
|
|
28
|
+
tower = deps.createTower(repo, { ...runtimeConfig(), configPath: null, repoConfigPresent: true })
|
|
32
29
|
}
|
|
33
|
-
const report = await runDoctor(/** @type {any} */ ({ tower, ctx, agent: exec.agent }))
|
|
30
|
+
const report = await runDoctor(/** @type {any} */ ({ tower, ctx, agent: exec.agent, surface: deps.surface?.() }))
|
|
34
31
|
if (!configError) return report
|
|
35
32
|
return {
|
|
36
33
|
...report,
|
package/tools/finding.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
// tower_finding: file one structured finding.
|
|
2
|
-
import { Tower } from '../app/tower.js'
|
|
3
2
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
4
3
|
import { FindingInput } from '../domain/contracts/tool-inputs/index.js'
|
|
5
4
|
import { ROLE } from '../domain/vocabulary.js'
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* @param {any} ctx
|
|
9
|
-
* @param {{ define: import('../types/index.js').DefineTool, actorFor: any, requireKnownActor: any }} deps
|
|
8
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, actorFor: any, requireKnownActor: any }} deps
|
|
10
9
|
*/
|
|
11
10
|
export function registerFindingTool(ctx, deps) {
|
|
12
11
|
const { define, actorFor, requireKnownActor } = deps
|
|
@@ -19,7 +18,7 @@ export function registerFindingTool(ctx, deps) {
|
|
|
19
18
|
board: true,
|
|
20
19
|
output: output(SCHEMAS.finding),
|
|
21
20
|
async execute(args, exec) {
|
|
22
|
-
const tower = await
|
|
21
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
23
22
|
const actor = await actorFor(tower, exec)
|
|
24
23
|
requireKnownActor(actor, 'tower_finding')
|
|
25
24
|
const view = await tower.rosterView()
|
package/tools/findings.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// tower_findings: list, read, or update findings.
|
|
2
|
-
import { Tower } from '../app/tower.js'
|
|
3
2
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
4
3
|
import { FindingsInput } from '../domain/contracts/tool-inputs/index.js'
|
|
5
4
|
import { ROLE } from '../domain/vocabulary.js'
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* @param {any} ctx
|
|
9
|
-
* @param {{ define: import('../types/index.js').DefineTool, actorFor: any, requireKnownActor: any }} deps
|
|
8
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, actorFor: any, requireKnownActor: any }} deps
|
|
10
9
|
*/
|
|
11
10
|
export function registerFindingsTool(ctx, deps) {
|
|
11
|
+
// openTower is injected by the composition root (#69).
|
|
12
12
|
const { define, actorFor, requireKnownActor } = deps
|
|
13
13
|
define(ctx, {
|
|
14
14
|
name: 'tower_findings',
|
|
@@ -18,7 +18,7 @@ export function registerFindingsTool(ctx, deps) {
|
|
|
18
18
|
aliases: {"missionId":["mission_id"]},
|
|
19
19
|
output: output(SCHEMAS.findings),
|
|
20
20
|
async execute(args, exec) {
|
|
21
|
-
const tower = await
|
|
21
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
22
22
|
const actor = await actorFor(tower, exec)
|
|
23
23
|
requireKnownActor(actor, 'tower_findings')
|
|
24
24
|
const view = await tower.rosterView()
|
package/tools/import-legacy.js
CHANGED
|
@@ -8,17 +8,15 @@
|
|
|
8
8
|
// Pure legacy validation lives in domain and never runs fs.
|
|
9
9
|
// See docs/reference/tools.generated.md for the public shape.
|
|
10
10
|
// tower_import_legacy: read-only legacy snapshot import.
|
|
11
|
-
import { Tower } from '../app/tower.js'
|
|
12
11
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
13
|
-
import { importLegacySnapshot } from '../lib/legacy.js'
|
|
14
12
|
import { ImportLegacyInput } from '../domain/contracts/tool-inputs/index.js'
|
|
15
13
|
|
|
16
14
|
/**
|
|
17
15
|
* @param {any} ctx
|
|
18
|
-
* @param {{ define: import('../types/index.js').DefineTool, actorFor: any, requireTowerActor: any }} deps
|
|
16
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, actorFor: any, requireTowerActor: any, importLegacySnapshot: any }} deps
|
|
19
17
|
*/
|
|
20
18
|
export function registerImportLegacyTool(ctx, deps) {
|
|
21
|
-
const { define, actorFor, requireTowerActor } = deps
|
|
19
|
+
const { define, actorFor, requireTowerActor, importLegacySnapshot } = deps
|
|
22
20
|
define(ctx, {
|
|
23
21
|
name: 'tower_import_legacy',
|
|
24
22
|
description:
|
|
@@ -27,7 +25,7 @@ export function registerImportLegacyTool(ctx, deps) {
|
|
|
27
25
|
board: true,
|
|
28
26
|
output: output(SCHEMAS.importLegacy),
|
|
29
27
|
async execute(args, exec) {
|
|
30
|
-
const tower = await
|
|
28
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
31
29
|
const actor = await actorFor(tower, exec)
|
|
32
30
|
requireTowerActor(actor, 'import a legacy snapshot')
|
|
33
31
|
const imported = await importLegacySnapshot({
|
package/tools/inbox.js
CHANGED
|
@@ -10,16 +10,16 @@
|
|
|
10
10
|
// The unread calculation is a pure domain/collab projection.
|
|
11
11
|
// See docs/reference/tools.generated.md for the public shape.
|
|
12
12
|
// tower_inbox: read and acknowledge inbound messages.
|
|
13
|
-
import { Tower } from '../app/tower.js'
|
|
14
13
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
15
14
|
import { InboxInput } from '../domain/contracts/tool-inputs/index.js'
|
|
16
15
|
import { ROLE } from '../domain/vocabulary.js'
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
* @param {any} ctx
|
|
20
|
-
* @param {{ define: import('../types/index.js').DefineTool }} deps
|
|
19
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any }} deps
|
|
21
20
|
*/
|
|
22
21
|
export function registerInboxTool(ctx, deps) {
|
|
22
|
+
// openTower is injected by the composition root (#69).
|
|
23
23
|
const { define } = deps
|
|
24
24
|
define(ctx, {
|
|
25
25
|
name: 'tower_inbox',
|
|
@@ -29,7 +29,7 @@ export function registerInboxTool(ctx, deps) {
|
|
|
29
29
|
aliases: {"include_read":["includeRead"]},
|
|
30
30
|
output: output(SCHEMAS.inbox),
|
|
31
31
|
async execute(args, exec) {
|
|
32
|
-
const tower = await
|
|
32
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
33
33
|
const view = await tower.rosterView()
|
|
34
34
|
const self = view.roster.find((entry) => entry.agentId === String(exec.agent.id))
|
|
35
35
|
const reader = self ? self.name : ROLE.tower
|
package/tools/index.js
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
// - tools must not import node:fs or node:child_process directly.
|
|
10
10
|
//
|
|
11
11
|
// Tests import this module for the public surface; they may also
|
|
12
|
-
// import
|
|
12
|
+
// import host/tool-registry.js for low-level test hooks.
|
|
13
13
|
//
|
|
14
|
-
// Packaging: package.json ships tools/*.js and
|
|
14
|
+
// Packaging: package.json ships tools/*.js and host/tool-registry.js.
|
|
15
15
|
// The file intentionally stays tiny so handler modules remain the
|
|
16
16
|
// only place where a tool is defined.
|
|
17
17
|
// Keep this comment and the re-export list in sync when adding tools.
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
//
|
|
21
21
|
// The registration aggregator, guards, rate limits, spawn backoff,
|
|
22
22
|
// repository preparation, discovery helpers, and verb helpers live in
|
|
23
|
-
//
|
|
23
|
+
// host/tool-registry.js. This module only re-exports the public entry
|
|
24
24
|
// points consumed by the Host plugin, tests, and docs generators.
|
|
25
25
|
//
|
|
26
26
|
// Design rules:
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
// - no business logic in this file;
|
|
31
31
|
// - keep the surface stable for index.js and tests.
|
|
32
32
|
//
|
|
33
|
-
// See docs/architecture/overview.md and
|
|
33
|
+
// See docs/architecture/overview.md and host/tool-registry.js.
|
|
34
34
|
// Tower tool surface: thin public wiring (#56 P5).
|
|
35
|
-
// Registration and shared machinery live in
|
|
35
|
+
// Registration and shared machinery live in host/tool-registry.js; one handler
|
|
36
36
|
// module per tool lives under tools/. This file only exposes the public entry
|
|
37
37
|
// points consumed by the Host plugin, tests, and documentation generators.
|
|
38
|
-
export { registerTowerTools, __testSpawnBackoff } from '../
|
|
39
|
-
export { workerBriefing, reviewerBriefing } from '../
|
|
38
|
+
export { registerTowerTools, __testSpawnBackoff } from '../host/tool-registry.js'
|
|
39
|
+
export { workerBriefing, reviewerBriefing } from '../app/briefing.js'
|
package/tools/init.js
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
// tower_init: repository initialization.
|
|
2
|
-
import { Tower } from '../app/tower.js'
|
|
3
2
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
4
3
|
import { TowerToolError } from '../domain/errors.js'
|
|
5
|
-
import { resolveRepo } from '../lib/git.js'
|
|
6
|
-
import { runtimeConfig } from '../lib/config.js'
|
|
7
4
|
import { InitInput } from '../domain/contracts/tool-inputs/index.js'
|
|
8
5
|
import { isTowerRole, isUnknownRole } from '../domain/vocabulary.js'
|
|
9
6
|
|
|
10
7
|
/**
|
|
11
8
|
* @param {any} ctx
|
|
12
|
-
* @param {{ define: import('../types/index.js').DefineTool, actorFor: any, requireTowerActor: any, workspaceHook: any, ensureRepository: any }} deps
|
|
9
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, actorFor: any, requireTowerActor: any, workspaceHook: any, ensureRepository: any, resolveRepo: any, runtimeConfig: any }} deps
|
|
13
10
|
*/
|
|
14
11
|
export function registerInitTool(ctx, deps) {
|
|
15
|
-
const { define, actorFor, requireTowerActor, workspaceHook, ensureRepository } = deps
|
|
12
|
+
const { define, actorFor, requireTowerActor, workspaceHook, ensureRepository, resolveRepo, runtimeConfig } = deps
|
|
16
13
|
define(ctx, {
|
|
17
14
|
name: 'tower_init',
|
|
18
15
|
description:
|
|
@@ -31,7 +28,7 @@ export function registerInitTool(ctx, deps) {
|
|
|
31
28
|
args.autoGitInit === true || (args.autoGitInit === undefined && profileInit.autoGitInit === true)
|
|
32
29
|
repo = await ensureRepository(args.repoRoot, autoGitInit)
|
|
33
30
|
}
|
|
34
|
-
const tower = await
|
|
31
|
+
const tower = await deps.openTower(repo.root)
|
|
35
32
|
const initConfig = tower.config.init ?? {}
|
|
36
33
|
const snapshotDirty =
|
|
37
34
|
args.snapshotDirty === true || (args.snapshotDirty === undefined && initConfig.snapshotDirty === true)
|
package/tools/interrupt.js
CHANGED
|
@@ -8,14 +8,13 @@
|
|
|
8
8
|
// Roster state policy is pure and lives in domain/collab.
|
|
9
9
|
// See docs/reference/tools.generated.md for the public shape.
|
|
10
10
|
// tower_interrupt: interrupt one running roster agent.
|
|
11
|
-
import { Tower } from '../app/tower.js'
|
|
12
11
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
13
12
|
import { TowerToolError } from '../domain/errors.js'
|
|
14
13
|
import { InterruptInput } from '../domain/contracts/tool-inputs/index.js'
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* @param {any} ctx
|
|
18
|
-
* @param {{ define: import('../types/index.js').DefineTool, actorFor: any, requireTowerActor: any, interruptRosterAgent: any }} deps
|
|
17
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, actorFor: any, requireTowerActor: any, interruptRosterAgent: any }} deps
|
|
19
18
|
*/
|
|
20
19
|
export function registerInterruptTool(ctx, deps) {
|
|
21
20
|
const { define, actorFor, requireTowerActor, interruptRosterAgent } = deps
|
|
@@ -27,7 +26,7 @@ export function registerInterruptTool(ctx, deps) {
|
|
|
27
26
|
aliases: { agentId: ['agent_id'] },
|
|
28
27
|
output: output(SCHEMAS.interrupt),
|
|
29
28
|
async execute(args, exec) {
|
|
30
|
-
const tower = await
|
|
29
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
31
30
|
const actor = await actorFor(tower, exec)
|
|
32
31
|
requireTowerActor(actor, 'interrupt tower agents')
|
|
33
32
|
if (!args.to && !args.agentId) throw new TowerToolError('invalid-argument', 'tower_interrupt requires to (roster name) or agentId')
|
package/tools/legacy-map.js
CHANGED
|
@@ -8,19 +8,17 @@
|
|
|
8
8
|
// Pure mapping validation lives in the domain legacy layer.
|
|
9
9
|
// See docs/reference/tools.generated.md for the public shape.
|
|
10
10
|
// tower_legacy_map: audit-only legacy snapshot mapping.
|
|
11
|
-
import { Tower } from '../app/tower.js'
|
|
12
11
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
13
12
|
import { TowerToolError } from '../domain/errors.js'
|
|
14
|
-
import { validateLegacyMap } from '../lib/legacy.js'
|
|
15
13
|
import { LegacyMapInput } from '../domain/contracts/tool-inputs/index.js'
|
|
16
14
|
import { LEGACY_MAP_ACTION } from '../domain/vocabulary.js'
|
|
17
15
|
|
|
18
16
|
/**
|
|
19
17
|
* @param {any} ctx
|
|
20
|
-
* @param {{ define: import('../types/index.js').DefineTool, actorFor: any, requireTowerActor: any }} deps
|
|
18
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, actorFor: any, requireTowerActor: any, validateLegacyMap: any }} deps
|
|
21
19
|
*/
|
|
22
20
|
export function registerLegacyMapTool(ctx, deps) {
|
|
23
|
-
const { define, actorFor, requireTowerActor } = deps
|
|
21
|
+
const { define, actorFor, requireTowerActor, validateLegacyMap } = deps
|
|
24
22
|
define(ctx, {
|
|
25
23
|
name: 'tower_legacy_map',
|
|
26
24
|
description:
|
|
@@ -28,7 +26,7 @@ export function registerLegacyMapTool(ctx, deps) {
|
|
|
28
26
|
parameters: LegacyMapInput,
|
|
29
27
|
output: output(SCHEMAS.legacyMap),
|
|
30
28
|
async execute(args, exec) {
|
|
31
|
-
const tower = await
|
|
29
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
32
30
|
const actor = await actorFor(tower, exec)
|
|
33
31
|
const state = await tower.load()
|
|
34
32
|
if (args.action === LEGACY_MAP_ACTION.status) {
|
package/tools/merge.js
CHANGED
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
// The pure intent/shape decisions live in domain/integration.
|
|
10
10
|
// See docs/reference/tools.generated.md for the public shape.
|
|
11
11
|
// tower_merge: merge a mission branch into the recorded base.
|
|
12
|
-
import { Tower } from '../app/tower.js'
|
|
13
12
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
14
13
|
import { MergeInput } from '../domain/contracts/tool-inputs/index.js'
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* @param {any} ctx
|
|
18
|
-
* @param {{ define: import('../types/index.js').DefineTool, actorFor: any, requireTowerActor: any, observeActivity: any }} deps
|
|
17
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, actorFor: any, requireTowerActor: any, observeActivity: any }} deps
|
|
19
18
|
*/
|
|
20
19
|
export function registerMergeTool(ctx, deps) {
|
|
20
|
+
// openTower is injected by the composition root (#69).
|
|
21
21
|
const { define, actorFor, requireTowerActor, observeActivity } = deps
|
|
22
22
|
define(ctx, {
|
|
23
23
|
name: 'tower_merge',
|
|
@@ -29,7 +29,7 @@ export function registerMergeTool(ctx, deps) {
|
|
|
29
29
|
board: true,
|
|
30
30
|
output: output(SCHEMAS.merge),
|
|
31
31
|
async execute(args, exec) {
|
|
32
|
-
const tower = await
|
|
32
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
33
33
|
const actor = await actorFor(tower, exec)
|
|
34
34
|
requireTowerActor(actor, 'merge missions')
|
|
35
35
|
const { activity, parentStatus } = await observeActivity(ctx, tower)
|
package/tools/mission.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
// tower_mission: mission lifecycle updates.
|
|
2
|
-
import { Tower } from '../app/tower.js'
|
|
3
2
|
import { TowerToolError } from '../domain/errors.js'
|
|
4
3
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
5
4
|
import { MissionInput } from '../domain/contracts/tool-inputs/index.js'
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* @param {any} ctx
|
|
9
|
-
* @param {{ define: import('../types/index.js').DefineTool, actorFor: any, requireKnownActor: any }} deps
|
|
8
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, actorFor: any, requireKnownActor: any }} deps
|
|
10
9
|
*/
|
|
11
10
|
export function registerMissionTool(ctx, deps) {
|
|
12
11
|
const { define, actorFor, requireKnownActor } = deps
|
|
@@ -19,7 +18,7 @@ export function registerMissionTool(ctx, deps) {
|
|
|
19
18
|
board: true,
|
|
20
19
|
output: output(SCHEMAS.mission),
|
|
21
20
|
async execute(args, exec) {
|
|
22
|
-
const tower = await
|
|
21
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
23
22
|
const actor = await actorFor(tower, exec)
|
|
24
23
|
requireKnownActor(actor, 'tower_mission')
|
|
25
24
|
return tower.mission({
|
package/tools/plan.js
CHANGED
|
@@ -10,17 +10,18 @@
|
|
|
10
10
|
// Pure normalization and DAG policy live in domain/missions.
|
|
11
11
|
// See docs/reference/tools.generated.md for the public shape.
|
|
12
12
|
// tower_plan: create missions.
|
|
13
|
-
import { Tower } from '../app/tower.js'
|
|
14
13
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
15
|
-
import { assertPresetsAvailable } from '../lib/presets.js'
|
|
16
14
|
import { PlanInput } from '../domain/contracts/tool-inputs/index.js'
|
|
17
15
|
|
|
18
16
|
/**
|
|
19
17
|
* @param {any} ctx
|
|
20
|
-
* @param {{ define: import('../types/index.js').DefineTool, actorFor: any, requireTowerActor: any }} deps
|
|
18
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, actorFor: any, requireTowerActor: any, assertPresetsAvailable: any }} deps
|
|
21
19
|
*/
|
|
22
20
|
export function registerPlanTool(ctx, deps) {
|
|
23
|
-
|
|
21
|
+
// #70: preset validation is injected by the composition root, so this tool
|
|
22
|
+
// never imports host/ or adapters/ directly.
|
|
23
|
+
// openTower is injected by the composition root (#69).
|
|
24
|
+
const { define, actorFor, requireTowerActor, assertPresetsAvailable } = deps
|
|
24
25
|
define(ctx, {
|
|
25
26
|
name: 'tower_plan',
|
|
26
27
|
description:
|
|
@@ -29,7 +30,7 @@ export function registerPlanTool(ctx, deps) {
|
|
|
29
30
|
board: true,
|
|
30
31
|
output: output(SCHEMAS.plan),
|
|
31
32
|
async execute(args, exec) {
|
|
32
|
-
const tower = await
|
|
33
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
33
34
|
const actor = await actorFor(tower, exec)
|
|
34
35
|
requireTowerActor(actor, 'plan missions')
|
|
35
36
|
await assertPresetsAvailable(ctx, tower.config)
|
package/tools/preflight.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
// tower_preflight: read-only merge gate digest.
|
|
2
|
-
import { Tower } from '../app/tower.js'
|
|
3
2
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
4
3
|
import { classifyError } from '../domain/errors.js'
|
|
5
4
|
import { PreflightInput } from '../domain/contracts/tool-inputs/index.js'
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* @param {any} ctx
|
|
9
|
-
* @param {{ define: import('../types/index.js').DefineTool, observeActivity: any }} deps
|
|
8
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, observeActivity: any }} deps
|
|
10
9
|
*/
|
|
11
10
|
export function registerPreflightTool(ctx, deps) {
|
|
12
11
|
const { define, observeActivity } = deps
|
|
@@ -19,7 +18,7 @@ export function registerPreflightTool(ctx, deps) {
|
|
|
19
18
|
requiresMissionId: true,
|
|
20
19
|
output: output(SCHEMAS.preflight),
|
|
21
20
|
async execute(args) {
|
|
22
|
-
const tower = await
|
|
21
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
23
22
|
const { activity, parentStatus } = await observeActivity(ctx, tower)
|
|
24
23
|
const gate = await tower.evaluateGate({ missionId: args.missionId, activity, parentStatus })
|
|
25
24
|
return {
|
package/tools/rebase.js
CHANGED
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
// Pure intent/waiver decisions live in domain/integration.
|
|
10
10
|
// See docs/reference/tools.generated.md for the public shape.
|
|
11
11
|
// tower_rebase: rebase a mission branch inside its worktree.
|
|
12
|
-
import { Tower } from '../app/tower.js'
|
|
13
12
|
import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
14
13
|
import { RebaseInput } from '../domain/contracts/tool-inputs/index.js'
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* @param {any} ctx
|
|
18
|
-
* @param {{ define: import('../types/index.js').DefineTool, actorFor: any, requireTowerActor: any, observeActivity: any }} deps
|
|
17
|
+
* @param {{ define: import('../types/index.js').DefineTool, openTower: any, actorFor: any, requireTowerActor: any, observeActivity: any }} deps
|
|
19
18
|
*/
|
|
20
19
|
export function registerRebaseTool(ctx, deps) {
|
|
20
|
+
// openTower is injected by the composition root (#69).
|
|
21
21
|
const { define, actorFor, requireTowerActor, observeActivity } = deps
|
|
22
22
|
define(ctx, {
|
|
23
23
|
name: 'tower_rebase',
|
|
@@ -29,7 +29,7 @@ export function registerRebaseTool(ctx, deps) {
|
|
|
29
29
|
board: true,
|
|
30
30
|
output: output(SCHEMAS.rebase),
|
|
31
31
|
async execute(args, exec) {
|
|
32
|
-
const tower = await
|
|
32
|
+
const tower = await deps.openTower(args.repoRoot)
|
|
33
33
|
const actor = await actorFor(tower, exec)
|
|
34
34
|
requireTowerActor(actor, 'rebase missions')
|
|
35
35
|
const { activity } = await observeActivity(ctx, tower)
|