* refactor(#2384): leaf dispatch table + runCommand collapse (ADR-2346 P4)
Cutover all 55 remaining case arms from runCommand's switch to
HOST_COMMAND_ROUTERS. runCommand now contains only its default case
(~40 lines): the three-layer dispatch (capability → overlay → host table)
plus the unknown-command diagnostic. The 73-case switch is dissolved.
Each case body was relocated verbatim to a module-scope route*Command
function via a brace-matching extractor; inner break; statements (from
_dispatchNonFamily early-exit patterns) were converted to return;
(5 arms affected); loop break; statements preserved.
Closes#2384
* chore: retrigger CI
* refactor(#2373): cutover resolve/git/config/research host routers (ADR-2346 P3)
Relocate 13 case arms from runCommand's switch to HOST_COMMAND_ROUTERS:
- resolve: resolve-model, resolve-granularity, resolve-execution (3)
- git: git (1)
- config: config-ensure-section, config-set, config-set-model-profile,
config-get, config-new-project, config-path, migrate-config (7)
- research: research-store, research-plan (2)
Each case body moved verbatim to a module-scope route*Command function
(closures over config/commands/output/_dispatchNonFamily preserved).
dispatchHostCommand extended to pass defaultValue + workstreamContext
(needed by config-get and config-path). No new files, no logic change.
Closes#2373
* chore: retrigger CI
* refactor(#2368): extract capability arm to capability-command-router (ADR-2346 P2)
Behavior-preserving relocation of the 706-line case 'capability': arm from
gsd-tools.cjs into a new hand-authored bin/lib/capability-command-router.cjs
(sibling of ensure-runtime-build.cjs). The 15 bin/-relative require paths are
rewritten to sibling-relative (correct for bin/lib/). dispatchHostCommand is
now async (capability's install/upgrade/consent ops await the lifecycle); sync
routers (state/phase/…) pass through await unchanged. case 'capability':
removed; capability dispatches via HOST_COMMAND_ROUTERS.
Validated by the existing capability-lifecycle / -consent / -trust / -loader
test suites (no logic changed). Golden install-parity fixtures regenerated.
Closes#2368 (Slice 1 — relocation). Probe consolidation (capHostVersion→
readHostVersion, capReadStrict dedup) deferred to a follow-up slice.
* fix(#2368): add capabilityState/capabilityWriter requires + INVENTORY row
The relocated capability arm references capabilityState (cmdCapabilityState,
resolveCapabilityRuntimeState) and capabilityWriter (cmdCapabilitySet) — both
module-scope requires in gsd-tools.cjs (L288/289) that the initial closure-dep
scan missed. Added as sibling requires to capability-command-router.cjs. Also
adds the new cli module to docs/INVENTORY.md + regenerates the manifest.
* fix(#2368): correct capHostVersion __dirname depth for bin/lib/ relocation
capHostVersion's VERSION/package.json paths were bin/-relative ('..' and
'..','..'); on relocation to bin/lib/ they resolved one level too deep,
so capHostVersion returned 0.0.0 and capability install failed the
engines.gsd gate (#1920). Added one more '..' to each (now resolves
gsd-core/VERSION and repo-root package.json correctly).
* test(#2368): drop capability from the invocation loop (async/FS vs /fake/cwd)
capability is async and does FS/config reads, so invoking it against the
unit test's /fake/cwd is fragile. The 6 sync Tier-1 routers stay in the
invocation loop; capability is covered by the non-invoking registry-
ownership assertion + the dedicated capability-* test suites.
* chore: retrigger CI (no-changelog label now present)
* refactor(#2360): host dispatch table + state cutover pilot (ADR-2346 P1)
Pilot cutover for ADR-2346 Phase 1 (epic #2345). Introduces the Layer-2 host
dispatch table — dispatchHostCommand + HOST_COMMAND_ROUTERS, consulted in
runCommand's default case after capability/overlay dispatch, before the
unknown-command error. Migrates 'state' as the pilot: removes the hardcoded
case 'state': arm; state now dispatches default -> dispatchHostCommand ->
routeStateCommand, byte-identical to the old path (proven by the new
state-command-cutover equivalence test, 5-category template).
Host commands are NOT capabilities (core, non-toggleable, no tier/activationKey)
— the capability registry stays reserved for toggleable feature bundles per
ADR-959. This is the host-vs-capability distinction the merged ADR-2346 lacked;
the ADR is corrected here alongside the code that realizes it.
- gsd-core/bin/gsd-tools.cjs: HOST_COMMAND_ROUTERS + dispatchHostCommand
(prototype-pollution-safe); wired into default case; case 'state': removed;
dispatchHostCommand + HOST_COMMAND_ROUTERS exported for tests.
- tests/state-command-cutover.test.cjs: UNIT/DISPATCH/BEHAVIOR/REGISTRY
equivalence (recording-mock + runGsdTools end-to-end + pollution guard).
- docs/adr/2346-*.md: refine Decision 1/2 to the host-table vs capability-
registry model (correction that did not land in the merged #2355).
Behavior-preserving. Subsequent P1b/c PRs migrate phase/init/roadmap/validate/
verify using this proven template.
Closes#2360.
* test(#2360): regenerate golden fixtures + allowlist for state cutover
Bookkeeping for the gsd-tools.cjs change: npm run gen:golden regenerates the
install-parity fixtures (gsd-tools.cjs content hash changed), and the new
tests/state-command-cutover.test.cjs is added to the lint-test-file-count
allowlist under the 'state' prefix.
* refactor(#2360): migrate remaining Tier-1 routers (phase/init/roadmap/validate/verify)
Completes P1: all 6 Tier-1 host routers now dispatch via HOST_COMMAND_ROUTERS
(state landed in the pilot commit). init preserves its #1688 warnIfStaleBake
pre-hook; validate binds the output emitter. Cutover test extended to assert
all 6 are consumed + owned. Golden install-parity fixtures regenerated.