dsh-tower 2.1.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +137 -0
- package/COMPATIBILITY.md +6 -1
- package/CONTRIBUTING.md +78 -5
- package/PRINCIPLES.md +163 -0
- package/README.en.md +35 -19
- package/README.md +28 -18
- package/SECURITY.md +6 -0
- package/{lib → adapters}/archive.js +1 -1
- package/{lib → adapters}/caseSensitivity.js +1 -1
- package/adapters/default.js +51 -10
- package/{lib → adapters}/git.js +1 -1
- package/{lib → adapters}/leases.js +1 -1
- package/{lib → adapters}/legacy.js +1 -1
- package/adapters/persistence.js +543 -0
- package/adapters/store-fs.js +28 -1
- package/adapters/store.js +204 -0
- package/{lib → adapters}/tests.js +9 -5
- package/adapters/vcs-git.js +15 -1
- package/{lib → adapters}/workspaceLock.js +1 -1
- package/{lib → adapters}/worktreeOwnership.js +1 -1
- package/app/archive.js +4 -6
- package/app/batch.js +9 -10
- package/app/board.js +2 -4
- package/app/checkCompletion.js +9 -10
- package/app/enrichedMissions.js +2 -4
- package/app/findings.js +6 -7
- package/app/gate.js +1 -2
- package/app/init.js +24 -29
- package/app/merge.js +58 -51
- package/app/messages.js +7 -8
- package/app/mission.js +5 -5
- package/app/plan.js +8 -5
- package/app/provision.js +12 -14
- package/app/read.js +6 -3
- package/app/rebase.js +14 -16
- package/app/recording.js +7 -8
- package/app/review.js +15 -8
- package/app/roster.js +14 -15
- package/{lib → app}/spawn-prechecks.js +4 -3
- package/app/spawn.js +12 -13
- package/app/teardown.js +8 -9
- package/app/tower.js +89 -35
- package/cordis.patch.yml +56 -28
- package/docs/README.md +7 -2
- package/docs/adr/0001-ports-adapters-as-data.md +49 -0
- package/docs/adr/0002-single-state-json.md +50 -0
- package/docs/adr/0003-allow-agent-control-default-true.md +48 -0
- package/docs/adr/0004-surface-budget.md +70 -0
- package/docs/adr/0005-component-surface.md +130 -0
- package/docs/adr/README.md +52 -0
- package/docs/agents/workflow.md +51 -0
- package/docs/architecture/overview.md +192 -43
- package/docs/guide/hot-reload.md +5 -5
- package/docs/guide/install-upgrade-migration.md +13 -0
- package/docs/guide/release.md +1 -1
- package/docs/operations/incident.md +82 -0
- package/docs/operations/runbook.md +12 -3
- package/docs/operations/security.md +1 -1
- package/docs/reference/blockers.md +2 -2
- package/docs/reference/component-surface.md +135 -0
- package/docs/reference/config.generated.md +2 -9
- package/docs/reference/config.md +11 -9
- package/docs/reference/doctor.md +53 -2
- package/docs/reference/errors.generated.md +41 -37
- package/docs/reference/errors.md +53 -41
- package/docs/reference/events.md +38 -6
- package/docs/reference/surface-budget.md +157 -0
- package/docs/reference/tools.generated.md +8 -5
- package/docs/reference/tools.md +10 -7
- package/docs/zh/README.md +1 -1
- package/docs/zh/guide/hot-reload.md +4 -4
- package/docs/zh/guide/install-upgrade-migration.md +10 -0
- package/docs/zh/operations/security.md +1 -1
- package/docs/zh/reference/blockers.md +2 -2
- package/docs/zh/reference/config.md +9 -9
- package/docs/zh/reference/doctor.md +29 -1
- package/docs/zh/reference/tools.md +10 -8
- package/domain/batch.js +2 -2
- package/domain/components.js +641 -0
- package/domain/config/schema.js +62 -28
- package/domain/contracts/outputs.js +16 -2
- package/domain/contracts/tool-inputs/ops.js +1 -0
- package/domain/errors.js +308 -43
- package/domain/events.js +207 -0
- package/domain/integration/gate.js +17 -2
- package/domain/integration/merge.js +35 -0
- package/domain/lockBudget.js +30 -0
- package/domain/mission.js +12 -1
- package/domain/missions/completion.js +14 -0
- package/domain/missions/lifecycle.js +9 -3
- package/domain/missions/plan.js +14 -0
- package/domain/missions/review.js +90 -7
- package/domain/read/views.js +3 -0
- package/domain/state/archive.js +1 -1
- package/domain/state.js +1 -1
- package/domain/surface.js +347 -0
- package/host/capability-batch.js +15 -0
- package/host/capability-hmr.js +30 -0
- package/host/capability-import.js +11 -0
- package/host/capability-leases.js +11 -0
- package/host/capability-registry.js +149 -0
- package/host/capability-tests.js +16 -0
- package/{lib → host}/doctor.js +157 -18
- package/{lib → host}/hmr.js +2 -4
- package/{lib → host}/modeStore.js +1 -1
- package/host/presets.js +77 -0
- package/{lib → host}/tool-registry.js +235 -44
- package/host/tower.js +32 -0
- package/index.js +40 -25
- package/locale/en.json +31 -11
- package/locale/zh.json +30 -10
- package/package.json +24 -4
- package/ports/archive.js +18 -0
- package/ports/caseSensitivity.js +15 -0
- package/ports/clock.js +10 -2
- package/ports/config.js +19 -0
- package/ports/contract.js +38 -0
- package/ports/events.js +24 -0
- package/ports/ids.js +10 -2
- package/ports/index.js +54 -2
- package/ports/ownership.js +17 -0
- package/ports/state.js +16 -0
- package/ports/store.js +52 -3
- package/ports/vcs.js +25 -4
- package/scripts/architecture-waivers.json +19 -0
- package/scripts/architecture.mjs +634 -23
- package/scripts/check-components.mjs +235 -0
- package/scripts/check-docs.mjs +8 -35
- package/scripts/check-pack.mjs +68 -39
- package/scripts/check-philosophy.mjs +266 -0
- package/scripts/component-surface.json +395 -0
- package/scripts/domain-metrics.mjs +13 -4
- package/scripts/generate-component-surface.mjs +59 -0
- package/scripts/generate-config-reference.mjs +14 -1
- package/scripts/generate-error-reference.mjs +68 -14
- package/scripts/generate-events-reference.mjs +83 -0
- package/scripts/generate-tools-reference.mjs +18 -25
- package/scripts/generate-types.mjs +127 -0
- package/scripts/issue-audit.mjs +2 -2
- package/scripts/lib/surface.mjs +87 -0
- package/scripts/lib/tool-surface.mjs +85 -0
- package/scripts/mount-smoke/fixtures.mjs +3 -3
- package/scripts/mount-smoke/surface.mjs +96 -27
- package/scripts/mount-smoke.mjs +3 -1
- package/scripts/pack-manifest.txt +75 -22
- package/scripts/regression-audit.mjs +164 -0
- package/scripts/release-check.mjs +1 -1
- package/scripts/surface-baseline.json +52 -0
- package/scripts/surface-baseline.mjs +118 -0
- package/scripts/types-coverage.mjs +184 -0
- package/scripts/types-strict-manifest.txt +10 -0
- package/scripts/types-strict.mjs +141 -0
- package/skills.js +8 -1
- package/tools/adopt.js +2 -3
- package/tools/batch.js +2 -3
- package/tools/complete.js +2 -3
- package/tools/diff.js +3 -3
- package/tools/doctor.js +7 -10
- package/tools/finding.js +2 -3
- package/tools/findings.js +3 -3
- package/tools/import-legacy.js +3 -5
- package/tools/inbox.js +3 -3
- package/tools/index.js +9 -8
- package/tools/init.js +3 -6
- package/tools/interrupt.js +2 -3
- package/tools/legacy-map.js +3 -5
- package/tools/merge.js +3 -3
- package/tools/mission.js +2 -3
- package/tools/plan.js +6 -5
- package/tools/preflight.js +2 -3
- package/tools/rebase.js +3 -3
- package/tools/recover.js +38 -13
- package/tools/reload.js +36 -40
- package/tools/resource.js +3 -5
- package/tools/review.js +3 -4
- package/tools/roster.js +2 -3
- package/tools/send.js +2 -2
- package/tools/spawn.js +8 -5
- package/tools/status.js +11 -4
- package/tools/teardown.js +2 -3
- package/tools/test.js +2 -2
- package/types/index.d.ts +29 -13
- package/ui-bundle/README.md +37 -3
- package/ui-bundle/client.cards.js +356 -0
- package/ui-bundle/client.denied.js +142 -0
- package/ui-bundle/client.dock.js +333 -0
- package/ui-bundle/client.helpers.js +271 -0
- package/ui-bundle/client.js +79 -1747
- package/ui-bundle/client.locales.js +247 -0
- package/ui-bundle/client.mode.js +206 -0
- package/ui-bundle/client.overlay.js +64 -0
- package/ui-bundle/client.styles.js +151 -0
- package/ui-bundle/client.toolview.js +82 -0
- package/ui-bundle/package.json +1 -0
- package/lib/persistence.js +0 -356
- package/lib/presets.js +0 -35
- package/lib/store.js +0 -133
- /package/{lib → adapters}/stateFile.js +0 -0
- /package/{lib → app}/briefing.js +0 -0
- /package/{lib → app}/spawn-support.js +0 -0
- /package/{lib → host}/compatibility.js +0 -0
- /package/{lib → host}/config.js +0 -0
- /package/{lib → host}/modeState.js +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// The shipped tool surface, derived from the Host entry (#118).
|
|
2
|
+
//
|
|
3
|
+
// `scripts/surface-baseline.mjs` and `scripts/generate-tools-reference.mjs` must
|
|
4
|
+
// measure the tools the plugin actually registers — including `tower_mode` and
|
|
5
|
+
// `tower_control`, which `index.js` registers directly instead of through the
|
|
6
|
+
// `define()` path. Loading the real `apply()` with a minimal Cordis context
|
|
7
|
+
// means the measurement cannot drift from the shipped surface again.
|
|
8
|
+
import os from 'node:os'
|
|
9
|
+
import path from 'node:path'
|
|
10
|
+
import { apply } from '../../index.js'
|
|
11
|
+
import { definedToolNames, registerAllCapabilities, __testResetToolSurface } from '../../host/tool-registry.js'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Apply the real Host entry against a recording mock context.
|
|
15
|
+
*
|
|
16
|
+
* @returns {{
|
|
17
|
+
* names: string[],
|
|
18
|
+
* definitions: Map<string, any>,
|
|
19
|
+
* dispose: () => void,
|
|
20
|
+
* }}
|
|
21
|
+
* `names` is the recorded surface (the same source `tower_doctor` reads);
|
|
22
|
+
* `definitions` is every tool the default profile actually registered.
|
|
23
|
+
*/
|
|
24
|
+
export function loadShippedToolSurface() {
|
|
25
|
+
const definitions = new Map()
|
|
26
|
+
const disposers = []
|
|
27
|
+
const ctx = {
|
|
28
|
+
effect(fn) {
|
|
29
|
+
const dispose = fn()
|
|
30
|
+
if (typeof dispose === 'function') disposers.push(dispose)
|
|
31
|
+
return () => {}
|
|
32
|
+
},
|
|
33
|
+
get() {
|
|
34
|
+
return undefined
|
|
35
|
+
},
|
|
36
|
+
provide() {},
|
|
37
|
+
inject(_deps, callback) {
|
|
38
|
+
callback(ctx)
|
|
39
|
+
},
|
|
40
|
+
on() {
|
|
41
|
+
return () => {}
|
|
42
|
+
},
|
|
43
|
+
logger: { warn() {} },
|
|
44
|
+
tools: {
|
|
45
|
+
register(definition) {
|
|
46
|
+
if (definition && typeof definition.name === 'string') definitions.set(definition.name, definition)
|
|
47
|
+
return () => {}
|
|
48
|
+
},
|
|
49
|
+
guard() {
|
|
50
|
+
return () => {}
|
|
51
|
+
},
|
|
52
|
+
restrict() {
|
|
53
|
+
return () => {}
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
systemPrompt: { section() {} },
|
|
57
|
+
commands: {
|
|
58
|
+
register() {
|
|
59
|
+
return () => {}
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
// Keep the mode store out of the operator's real $DSH_HOME. The path is only
|
|
64
|
+
// read (a missing modes.json is an empty mode set); nothing is written.
|
|
65
|
+
// #121: the host entry registers only the mandatory surface; the shipped
|
|
66
|
+
// profile mounts the optional capability rows. The concept budget measures the
|
|
67
|
+
// *build* surface, so the all-capabilities aggregate is applied on top.
|
|
68
|
+
__testResetToolSurface()
|
|
69
|
+
apply(ctx, { mode: { storePath: path.join(os.tmpdir(), 'dsh-tower-surface-check') } })
|
|
70
|
+
registerAllCapabilities(ctx)
|
|
71
|
+
const names = definedToolNames()
|
|
72
|
+
return {
|
|
73
|
+
names,
|
|
74
|
+
definitions,
|
|
75
|
+
dispose() {
|
|
76
|
+
for (const dispose of disposers.reverse()) {
|
|
77
|
+
try {
|
|
78
|
+
dispose()
|
|
79
|
+
} catch {
|
|
80
|
+
// a recorder fixture must still exit when a disposer fails
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -67,19 +67,19 @@ const fixtures = [
|
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
name: 'dropped-skills-section',
|
|
70
|
-
what: 'the tower-skills row is removed from the bundle patch',
|
|
70
|
+
what: 'the optional tower-skills row is removed from the bundle patch',
|
|
71
71
|
seed(root) {
|
|
72
72
|
const file = path.join(root, 'cordis.patch.yml')
|
|
73
73
|
const text = fs.readFileSync(file, 'utf8')
|
|
74
74
|
const next = replaceOnce(
|
|
75
75
|
text,
|
|
76
|
-
/\n {
|
|
76
|
+
/\n {4}- id: tower-skills\n {6}name: 'dsh-tower\/skills'/,
|
|
77
77
|
'',
|
|
78
78
|
'cordis.patch.yml tower-skills row',
|
|
79
79
|
)
|
|
80
80
|
fs.writeFileSync(file, next)
|
|
81
81
|
},
|
|
82
|
-
expect: ['skill: missing tower-worker-protocol', 'bundle:
|
|
82
|
+
expect: ['skill: missing tower-worker-protocol', 'bundle: missing optional top-level row tower-skills'],
|
|
83
83
|
},
|
|
84
84
|
]
|
|
85
85
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The expected loaded surface of the dsh-tower bundle (#95).
|
|
1
|
+
// The expected loaded surface of the dsh-tower bundle (#95, #121).
|
|
2
2
|
//
|
|
3
3
|
// Pure derivation and comparison only: the mount smoke boots a throwaway
|
|
4
4
|
// profile, and these helpers turn the checked-in source of truth into the ids
|
|
@@ -7,17 +7,53 @@
|
|
|
7
7
|
//
|
|
8
8
|
// The oracle is deliberately source-derived where the source is unambiguous:
|
|
9
9
|
// one tool id per tool module, one skill id per bundled skill file. The bundle
|
|
10
|
-
//
|
|
11
|
-
// contract the
|
|
10
|
+
// rows and presets come from `cordis.patch.yml` and are stated here as the
|
|
11
|
+
// contract the component policy protects: one mandatory host group plus
|
|
12
|
+
// individually switchable optional top-level rows (#121). Tools owned by a row
|
|
13
|
+
// that ships off (today only `tower-hmr` -> `tower_reload`) are trimmed from the
|
|
14
|
+
// expected surface using the same ownership table the runtime reports, so the
|
|
15
|
+
// shipped default profile (28 tools) and the all-rows-on build surface (29)
|
|
16
|
+
// cannot be confused again.
|
|
17
|
+
|
|
18
|
+
import { COMPONENT_TOOLS } from '../../host/capability-registry.js'
|
|
12
19
|
|
|
13
20
|
/** Tools registered by index.js rather than by a handler module under tools/. */
|
|
14
21
|
export const INDEX_TOOL_IDS = ['tower_control', 'tower_mode']
|
|
15
22
|
|
|
16
|
-
/** The
|
|
17
|
-
export const BUNDLE_ID = 'tower
|
|
23
|
+
/** The mandatory host group row: off equals uninstalling. */
|
|
24
|
+
export const BUNDLE_ID = 'tower'
|
|
18
25
|
|
|
19
26
|
/** Rows that must stay nested inside {@link BUNDLE_ID}. */
|
|
20
|
-
export const BUNDLE_CHILD_IDS = ['preset-tower-
|
|
27
|
+
export const BUNDLE_CHILD_IDS = ['preset-tower-worker', 'tower-host']
|
|
28
|
+
|
|
29
|
+
/** The optional capability rows that sit at the top level beside the host. */
|
|
30
|
+
export const OPTIONAL_ROW_IDS = [
|
|
31
|
+
'preset-tower-reviewer',
|
|
32
|
+
'tower-batch',
|
|
33
|
+
'tower-hmr',
|
|
34
|
+
'tower-import',
|
|
35
|
+
'tower-leases',
|
|
36
|
+
'tower-skills',
|
|
37
|
+
'tower-tests',
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
/** Rows shipped off: the mount smoke must not expect them to be active. */
|
|
41
|
+
export const DEFAULT_OFF_ROW_IDS = ['tower-hmr']
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Tool ids owned by the rows in {@link DEFAULT_OFF_ROW_IDS}. The ownership table
|
|
45
|
+
* is the one `host/capability-registry.js` uses to report a disabled component,
|
|
46
|
+
* so the oracle cannot drift from the runtime: turning a row's default off in
|
|
47
|
+
* `cordis.patch.yml` automatically removes its tools from the expected surface.
|
|
48
|
+
* @returns {Set<string>} the tool ids a default profile does not register.
|
|
49
|
+
*/
|
|
50
|
+
export function defaultOffToolIds() {
|
|
51
|
+
const ids = new Set()
|
|
52
|
+
for (const rowId of DEFAULT_OFF_ROW_IDS) {
|
|
53
|
+
for (const toolId of COMPONENT_TOOLS[rowId] ?? []) ids.add(toolId)
|
|
54
|
+
}
|
|
55
|
+
return ids
|
|
56
|
+
}
|
|
21
57
|
|
|
22
58
|
/** Presets the bundle declares for its worker and reviewer roles. */
|
|
23
59
|
export const PRESET_IDS = ['tower-reviewer', 'tower-worker']
|
|
@@ -25,7 +61,7 @@ export const PRESET_IDS = ['tower-reviewer', 'tower-worker']
|
|
|
25
61
|
/** Cordis fiber state 2: mounted and active. */
|
|
26
62
|
const FIBER_ACTIVE = 2
|
|
27
63
|
|
|
28
|
-
const OWNED_ROW_IDS = new Set([BUNDLE_ID, ...BUNDLE_CHILD_IDS])
|
|
64
|
+
const OWNED_ROW_IDS = new Set([BUNDLE_ID, ...BUNDLE_CHILD_IDS, ...OPTIONAL_ROW_IDS])
|
|
29
65
|
|
|
30
66
|
/**
|
|
31
67
|
* Map one tools/ file name to the tool id its module must register.
|
|
@@ -42,14 +78,25 @@ export function toolIdForModule(fileName) {
|
|
|
42
78
|
|
|
43
79
|
/**
|
|
44
80
|
* @param {string[]} moduleFiles - file names under tools/.
|
|
81
|
+
* @param {{ enabledRows?: string[] }} [options] - rows enabled in the profile
|
|
82
|
+
* under test. Defaults to the shipped profile: every optional row except the
|
|
83
|
+
* ones in {@link DEFAULT_OFF_ROW_IDS}. Pass every row id to pin the full
|
|
84
|
+
* build surface (29 tools with the shipped sources).
|
|
45
85
|
* @returns {string[]} sorted tool ids the loaded profile must register.
|
|
46
86
|
*/
|
|
47
|
-
export function expectedToolIds(moduleFiles) {
|
|
87
|
+
export function expectedToolIds(moduleFiles, options = {}) {
|
|
88
|
+
const enabledRows = options.enabledRows === undefined ? null : new Set(options.enabledRows)
|
|
89
|
+
const skipped = new Set()
|
|
90
|
+
for (const rowId of DEFAULT_OFF_ROW_IDS) {
|
|
91
|
+
if (enabledRows !== null && enabledRows.has(rowId)) continue
|
|
92
|
+
for (const toolId of COMPONENT_TOOLS[rowId] ?? []) skipped.add(toolId)
|
|
93
|
+
}
|
|
48
94
|
const ids = new Set(INDEX_TOOL_IDS)
|
|
49
95
|
for (const file of moduleFiles) {
|
|
50
96
|
const id = toolIdForModule(file)
|
|
51
97
|
if (id !== null) ids.add(id)
|
|
52
98
|
}
|
|
99
|
+
for (const id of skipped) ids.delete(id)
|
|
53
100
|
return [...ids].sort()
|
|
54
101
|
}
|
|
55
102
|
|
|
@@ -81,46 +128,55 @@ export function compareIds(label, expectedIds, loadedIds) {
|
|
|
81
128
|
return failures
|
|
82
129
|
}
|
|
83
130
|
|
|
131
|
+
/** Effective loader id for a nested row (`group:child`), falling back to the raw id. */
|
|
132
|
+
function stateKey(id, entryStates) {
|
|
133
|
+
if (entryStates[id] !== undefined) return id
|
|
134
|
+
const nested = `${BUNDLE_ID}:${id}`
|
|
135
|
+
if (entryStates[nested] !== undefined) return nested
|
|
136
|
+
return id
|
|
137
|
+
}
|
|
138
|
+
|
|
84
139
|
/**
|
|
85
|
-
* Assert the bundle
|
|
86
|
-
* every
|
|
87
|
-
* @param {Array<{ id?: string, name?: string, group?: boolean, config?: unknown[] }>} topRows
|
|
88
|
-
* the composed rows at the root of the loaded profile tree.
|
|
140
|
+
* Assert the bundle ships one mandatory host group plus the optional rows and
|
|
141
|
+
* that every expected row actually mounted (the `tower-hmr` row is shipped off).
|
|
142
|
+
* @param {Array<{ id?: string, name?: string, group?: boolean, config?: unknown[], childIds?: unknown[] }>} topRows
|
|
89
143
|
* @param {Record<string, number | undefined>} [entryStates] - fiber state per entry id.
|
|
90
144
|
* @returns {string[]} one message per violated invariant.
|
|
91
145
|
*/
|
|
92
146
|
export function checkBundleRow(topRows, entryStates = {}) {
|
|
93
147
|
const rows = Array.isArray(topRows) ? topRows.filter(Boolean) : []
|
|
94
148
|
const failures = []
|
|
95
|
-
const
|
|
96
|
-
if (
|
|
149
|
+
const hostRows = rows.filter((row) => row.id === BUNDLE_ID)
|
|
150
|
+
if (hostRows.length !== 1) {
|
|
97
151
|
failures.push(
|
|
98
|
-
|
|
99
|
-
? `bundle: no top-level ${BUNDLE_ID} row; the bundle did not compose`
|
|
100
|
-
: `bundle: found ${
|
|
152
|
+
hostRows.length === 0
|
|
153
|
+
? `bundle: no top-level ${BUNDLE_ID} host row; the bundle did not compose`
|
|
154
|
+
: `bundle: found ${hostRows.length} top-level ${BUNDLE_ID} rows, expected exactly 1`,
|
|
101
155
|
)
|
|
102
|
-
if (
|
|
156
|
+
if (hostRows.length === 0) return failures
|
|
103
157
|
}
|
|
104
158
|
|
|
105
|
-
const
|
|
159
|
+
const topIds = new Set(rows.map((row) => String(row.id)))
|
|
160
|
+
for (const id of OPTIONAL_ROW_IDS) {
|
|
161
|
+
if (!topIds.has(id)) failures.push(`bundle: missing optional top-level row ${id}`)
|
|
162
|
+
}
|
|
106
163
|
for (const row of rows) {
|
|
107
164
|
if (row.id === BUNDLE_ID) continue
|
|
108
165
|
const name = typeof row.name === 'string' ? row.name : ''
|
|
109
166
|
const ownedName = name === 'dsh-tower' || name.startsWith('dsh-tower/')
|
|
110
167
|
if (!OWNED_ROW_IDS.has(String(row.id)) && !ownedName) continue
|
|
111
|
-
if (
|
|
112
|
-
leaked.add(String(row.id))
|
|
168
|
+
if (OPTIONAL_ROW_IDS.includes(String(row.id))) continue
|
|
113
169
|
failures.push(`bundle: ${row.id} is a top-level row; it must stay nested in ${BUNDLE_ID}`)
|
|
114
170
|
}
|
|
115
171
|
|
|
116
|
-
const
|
|
117
|
-
if (
|
|
172
|
+
const hostRow = hostRows[0]
|
|
173
|
+
if (hostRow.name !== 'cordis:group' || hostRow.group !== true) {
|
|
118
174
|
failures.push(
|
|
119
|
-
`bundle: ${BUNDLE_ID} is not a cordis:group row (name ${JSON.stringify(
|
|
175
|
+
`bundle: ${BUNDLE_ID} is not a cordis:group row (name ${JSON.stringify(hostRow.name)}, group ${JSON.stringify(hostRow.group)})`,
|
|
120
176
|
)
|
|
121
177
|
}
|
|
122
178
|
|
|
123
|
-
const rawChildren = Array.isArray(
|
|
179
|
+
const rawChildren = Array.isArray(hostRow.childIds) ? hostRow.childIds : Array.isArray(hostRow.config) ? hostRow.config : []
|
|
124
180
|
const children = rawChildren
|
|
125
181
|
.map((child) =>
|
|
126
182
|
child && typeof child === 'object' && child.id !== undefined ? String(child.id) : typeof child === 'string' ? child : null,
|
|
@@ -131,8 +187,21 @@ export function checkBundleRow(topRows, entryStates = {}) {
|
|
|
131
187
|
for (const id of children) if (!expectedChildren.includes(id)) failures.push(`bundle: ${BUNDLE_ID} has unexpected child ${id}`)
|
|
132
188
|
if (new Set(children).size !== children.length) failures.push(`bundle: ${BUNDLE_ID} has duplicate child rows`)
|
|
133
189
|
|
|
134
|
-
for (const id of [BUNDLE_ID, ...
|
|
135
|
-
|
|
190
|
+
for (const id of [BUNDLE_ID, ...OPTIONAL_ROW_IDS]) {
|
|
191
|
+
if (DEFAULT_OFF_ROW_IDS.includes(id)) {
|
|
192
|
+
const state = entryStates[id]
|
|
193
|
+
if (state === FIBER_ACTIVE) failures.push(`bundle: ${id} ships disabled but is active`)
|
|
194
|
+
continue
|
|
195
|
+
}
|
|
196
|
+
const key = stateKey(id, entryStates)
|
|
197
|
+
const state = entryStates[key]
|
|
198
|
+
if (state !== FIBER_ACTIVE) {
|
|
199
|
+
failures.push(`bundle: entry ${id} is not active (entry state ${state === undefined ? 'missing' : state})`)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
for (const id of BUNDLE_CHILD_IDS) {
|
|
203
|
+
const key = stateKey(id, entryStates)
|
|
204
|
+
const state = entryStates[key]
|
|
136
205
|
if (state !== FIBER_ACTIVE) {
|
|
137
206
|
failures.push(`bundle: entry ${id} is not active (entry state ${state === undefined ? 'missing' : state})`)
|
|
138
207
|
}
|
package/scripts/mount-smoke.mjs
CHANGED
|
@@ -21,6 +21,7 @@ import path from 'node:path'
|
|
|
21
21
|
import { fileURLToPath } from 'node:url'
|
|
22
22
|
import {
|
|
23
23
|
BUNDLE_ID,
|
|
24
|
+
DEFAULT_OFF_ROW_IDS,
|
|
24
25
|
INDEX_TOOL_IDS,
|
|
25
26
|
PRESET_IDS,
|
|
26
27
|
checkBundleRow,
|
|
@@ -175,12 +176,13 @@ function verifySurface(surface, root) {
|
|
|
175
176
|
|
|
176
177
|
function summarize(surface, root) {
|
|
177
178
|
const modules = toolModuleNames(root).filter((name) => name !== 'index.js').length
|
|
179
|
+
const expected = expectedToolIds(toolModuleNames(root)).length
|
|
178
180
|
const tools = Array.isArray(surface?.tools?.value) ? surface.tools.value.filter((name) => name.startsWith('tower_')).length : '?'
|
|
179
181
|
const skills = Array.isArray(surface?.skills?.value?.tower) ? surface.skills.value.tower.length : '?'
|
|
180
182
|
const presets = Array.isArray(surface?.presets?.value) ? surface.presets.value.length : '?'
|
|
181
183
|
const commands = Array.isArray(surface?.commands?.value) ? surface.commands.value.filter((name) => name === 'tower').length : '?'
|
|
182
184
|
const rows = Array.isArray(surface?.tree?.value?.top) ? surface.tree.value.top.filter((row) => row.id === BUNDLE_ID).length : '?'
|
|
183
|
-
return `${tools} tower tools (${modules} modules + ${INDEX_TOOL_IDS.length} entry tools), ${skills} skills, ${presets} presets, /tower ${commands === 1 ? 'present' : 'missing'}, ${rows} top-level bundle row`
|
|
185
|
+
return `${tools} of ${expected} tower tools (${modules} modules + ${INDEX_TOOL_IDS.length} entry tools; ${DEFAULT_OFF_ROW_IDS.join(', ')} off), ${skills} skills, ${presets} presets, /tower ${commands === 1 ? 'present' : 'missing'}, ${rows} top-level bundle row`
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
function reportFailure(state, pin, options, error) {
|
|
@@ -2,15 +2,28 @@ CHANGELOG.md
|
|
|
2
2
|
COMPATIBILITY.md
|
|
3
3
|
CONTRIBUTING.md
|
|
4
4
|
LICENSE
|
|
5
|
+
PRINCIPLES.md
|
|
5
6
|
README.en.md
|
|
6
7
|
README.md
|
|
7
8
|
SECURITY.md
|
|
9
|
+
adapters/archive.js
|
|
10
|
+
adapters/caseSensitivity.js
|
|
8
11
|
adapters/default.js
|
|
12
|
+
adapters/git.js
|
|
13
|
+
adapters/leases.js
|
|
14
|
+
adapters/legacy.js
|
|
15
|
+
adapters/persistence.js
|
|
16
|
+
adapters/stateFile.js
|
|
9
17
|
adapters/store-fs.js
|
|
18
|
+
adapters/store.js
|
|
19
|
+
adapters/tests.js
|
|
10
20
|
adapters/vcs-git.js
|
|
21
|
+
adapters/workspaceLock.js
|
|
22
|
+
adapters/worktreeOwnership.js
|
|
11
23
|
app/archive.js
|
|
12
24
|
app/batch.js
|
|
13
25
|
app/board.js
|
|
26
|
+
app/briefing.js
|
|
14
27
|
app/checkCompletion.js
|
|
15
28
|
app/enrichedMissions.js
|
|
16
29
|
app/findings.js
|
|
@@ -27,14 +40,23 @@ app/rebase.js
|
|
|
27
40
|
app/recording.js
|
|
28
41
|
app/review.js
|
|
29
42
|
app/roster.js
|
|
43
|
+
app/spawn-prechecks.js
|
|
44
|
+
app/spawn-support.js
|
|
30
45
|
app/spawn.js
|
|
31
46
|
app/teardown.js
|
|
32
47
|
app/tower.js
|
|
33
48
|
cordis.patch.yml
|
|
34
49
|
docs/README.md
|
|
50
|
+
docs/adr/0001-ports-adapters-as-data.md
|
|
51
|
+
docs/adr/0002-single-state-json.md
|
|
52
|
+
docs/adr/0003-allow-agent-control-default-true.md
|
|
53
|
+
docs/adr/0004-surface-budget.md
|
|
54
|
+
docs/adr/0005-component-surface.md
|
|
55
|
+
docs/adr/README.md
|
|
35
56
|
docs/agents/domain.md
|
|
36
57
|
docs/agents/issue-tracker.md
|
|
37
58
|
docs/agents/triage-labels.md
|
|
59
|
+
docs/agents/workflow.md
|
|
38
60
|
docs/architecture/overview.md
|
|
39
61
|
docs/board.md
|
|
40
62
|
docs/examples/first-mission.md
|
|
@@ -44,9 +66,11 @@ docs/guide/install-upgrade-migration.md
|
|
|
44
66
|
docs/guide/quickstart.md
|
|
45
67
|
docs/guide/release.md
|
|
46
68
|
docs/guide/scenarios-and-philosophy.md
|
|
69
|
+
docs/operations/incident.md
|
|
47
70
|
docs/operations/runbook.md
|
|
48
71
|
docs/operations/security.md
|
|
49
72
|
docs/reference/blockers.md
|
|
73
|
+
docs/reference/component-surface.md
|
|
50
74
|
docs/reference/config.generated.md
|
|
51
75
|
docs/reference/config.md
|
|
52
76
|
docs/reference/doctor.md
|
|
@@ -54,6 +78,7 @@ docs/reference/errors.generated.md
|
|
|
54
78
|
docs/reference/errors.md
|
|
55
79
|
docs/reference/events.md
|
|
56
80
|
docs/reference/operations.md
|
|
81
|
+
docs/reference/surface-budget.md
|
|
57
82
|
docs/reference/testing.md
|
|
58
83
|
docs/reference/tools.generated.md
|
|
59
84
|
docs/reference/tools.md
|
|
@@ -77,6 +102,7 @@ domain/collab/batch.js
|
|
|
77
102
|
domain/collab/messages.js
|
|
78
103
|
domain/collab/roster.js
|
|
79
104
|
domain/collab/spawn.js
|
|
105
|
+
domain/components.js
|
|
80
106
|
domain/config/schema.js
|
|
81
107
|
domain/contracts/outputs.js
|
|
82
108
|
domain/contracts/tool-inputs/collaboration.js
|
|
@@ -87,6 +113,7 @@ domain/contracts/tool-inputs/missions.js
|
|
|
87
113
|
domain/contracts/tool-inputs/ops.js
|
|
88
114
|
domain/contracts/tool-inputs/shared.js
|
|
89
115
|
domain/errors.js
|
|
116
|
+
domain/events.js
|
|
90
117
|
domain/gate.js
|
|
91
118
|
domain/integration/gate.js
|
|
92
119
|
domain/integration/init.js
|
|
@@ -96,6 +123,7 @@ domain/integration/provision.js
|
|
|
96
123
|
domain/integration/rebase.js
|
|
97
124
|
domain/integration/review.js
|
|
98
125
|
domain/integration/teardown.js
|
|
126
|
+
domain/lockBudget.js
|
|
99
127
|
domain/mission.js
|
|
100
128
|
domain/missions/completion.js
|
|
101
129
|
domain/missions/findings.js
|
|
@@ -115,58 +143,74 @@ domain/state/migrations.js
|
|
|
115
143
|
domain/state/schema.js
|
|
116
144
|
domain/state/semantics.js
|
|
117
145
|
domain/summary.js
|
|
146
|
+
domain/surface.js
|
|
118
147
|
domain/vocabulary.js
|
|
148
|
+
host/capability-batch.js
|
|
149
|
+
host/capability-hmr.js
|
|
150
|
+
host/capability-import.js
|
|
151
|
+
host/capability-leases.js
|
|
152
|
+
host/capability-registry.js
|
|
153
|
+
host/capability-tests.js
|
|
154
|
+
host/compatibility.js
|
|
155
|
+
host/config.js
|
|
156
|
+
host/doctor.js
|
|
157
|
+
host/hmr.js
|
|
158
|
+
host/modeState.js
|
|
159
|
+
host/modeStore.js
|
|
160
|
+
host/presets.js
|
|
161
|
+
host/tool-registry.js
|
|
162
|
+
host/tower.js
|
|
119
163
|
icon.svg
|
|
120
164
|
index.js
|
|
121
|
-
lib/archive.js
|
|
122
|
-
lib/briefing.js
|
|
123
|
-
lib/caseSensitivity.js
|
|
124
|
-
lib/compatibility.js
|
|
125
|
-
lib/config.js
|
|
126
|
-
lib/doctor.js
|
|
127
|
-
lib/git.js
|
|
128
|
-
lib/hmr.js
|
|
129
|
-
lib/leases.js
|
|
130
|
-
lib/legacy.js
|
|
131
|
-
lib/modeState.js
|
|
132
|
-
lib/modeStore.js
|
|
133
|
-
lib/persistence.js
|
|
134
|
-
lib/presets.js
|
|
135
|
-
lib/spawn-prechecks.js
|
|
136
|
-
lib/spawn-support.js
|
|
137
|
-
lib/stateFile.js
|
|
138
|
-
lib/store.js
|
|
139
|
-
lib/tests.js
|
|
140
|
-
lib/tool-registry.js
|
|
141
|
-
lib/workspaceLock.js
|
|
142
|
-
lib/worktreeOwnership.js
|
|
143
165
|
locale/en.json
|
|
144
166
|
locale/zh.json
|
|
145
167
|
package.json
|
|
168
|
+
ports/archive.js
|
|
169
|
+
ports/caseSensitivity.js
|
|
146
170
|
ports/clock.js
|
|
171
|
+
ports/config.js
|
|
172
|
+
ports/contract.js
|
|
173
|
+
ports/events.js
|
|
147
174
|
ports/ids.js
|
|
148
175
|
ports/index.js
|
|
176
|
+
ports/ownership.js
|
|
177
|
+
ports/state.js
|
|
149
178
|
ports/store.js
|
|
150
179
|
ports/vcs.js
|
|
151
180
|
reviewer.js
|
|
181
|
+
scripts/architecture-waivers.json
|
|
152
182
|
scripts/architecture.mjs
|
|
183
|
+
scripts/check-components.mjs
|
|
153
184
|
scripts/check-docs.mjs
|
|
154
185
|
scripts/check-pack.mjs
|
|
186
|
+
scripts/check-philosophy.mjs
|
|
187
|
+
scripts/component-surface.json
|
|
155
188
|
scripts/domain-metrics.mjs
|
|
156
189
|
scripts/enable-dev-hmr.mjs
|
|
190
|
+
scripts/generate-component-surface.mjs
|
|
157
191
|
scripts/generate-config-reference.mjs
|
|
158
192
|
scripts/generate-error-reference.mjs
|
|
193
|
+
scripts/generate-events-reference.mjs
|
|
159
194
|
scripts/generate-tools-reference.mjs
|
|
195
|
+
scripts/generate-types.mjs
|
|
160
196
|
scripts/issue-audit.mjs
|
|
161
197
|
scripts/lib/cli.mjs
|
|
198
|
+
scripts/lib/surface.mjs
|
|
162
199
|
scripts/lib/tmp.mjs
|
|
200
|
+
scripts/lib/tool-surface.mjs
|
|
163
201
|
scripts/mount-smoke.mjs
|
|
164
202
|
scripts/mount-smoke/fixtures.mjs
|
|
165
203
|
scripts/mount-smoke/host.json
|
|
166
204
|
scripts/mount-smoke/probe.mjs
|
|
167
205
|
scripts/mount-smoke/surface.mjs
|
|
168
206
|
scripts/pack-manifest.txt
|
|
207
|
+
scripts/regression-audit.mjs
|
|
169
208
|
scripts/release-check.mjs
|
|
209
|
+
scripts/surface-baseline.json
|
|
210
|
+
scripts/surface-baseline.mjs
|
|
211
|
+
scripts/types-coverage.mjs
|
|
212
|
+
scripts/types-strict-manifest.txt
|
|
213
|
+
scripts/types-strict.mjs
|
|
170
214
|
skills.js
|
|
171
215
|
skills/tower-recovery.md
|
|
172
216
|
skills/tower-review.md
|
|
@@ -202,7 +246,16 @@ tools/test.js
|
|
|
202
246
|
types/cordis.d.ts
|
|
203
247
|
types/index.d.ts
|
|
204
248
|
ui-bundle/README.md
|
|
249
|
+
ui-bundle/client.cards.js
|
|
250
|
+
ui-bundle/client.denied.js
|
|
251
|
+
ui-bundle/client.dock.js
|
|
252
|
+
ui-bundle/client.helpers.js
|
|
205
253
|
ui-bundle/client.js
|
|
254
|
+
ui-bundle/client.locales.js
|
|
255
|
+
ui-bundle/client.mode.js
|
|
256
|
+
ui-bundle/client.overlay.js
|
|
257
|
+
ui-bundle/client.styles.js
|
|
258
|
+
ui-bundle/client.toolview.js
|
|
206
259
|
ui-bundle/cordis.patch.yml
|
|
207
260
|
ui-bundle/icon.svg
|
|
208
261
|
ui-bundle/index.js
|