refactor(#2368): extract capability arm to capability-command-router (ADR-2346 P2) (#2370)

* 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)
This commit is contained in:
Tom Boucher
2026-07-17 11:04:47 -04:00
committed by GitHub
parent 67a9243cf1
commit b302f53ee6
23 changed files with 784 additions and 744 deletions

View File

@@ -300,6 +300,7 @@
"audit-command-router.cjs",
"audit.cjs",
"capability-activation.cjs",
"capability-command-router.cjs",
"capability-consent.cjs",
"capability-ledger.cjs",
"capability-lifecycle.cjs",

View File

@@ -404,6 +404,7 @@ Full listing: `gsd-core/bin/lib/*.cjs`.
| `audit-command-router.cjs` | ADR-959 capability command router for `gsd-tools audit-uat` and `gsd-tools audit-open` — extracted from hardcoded cases in `gsd-tools.cjs`; dispatches to `uat.cjs:cmdAuditUat` and `audit.cjs:{auditOpenArtifacts,formatAuditReport}`; phase 4d-impl-3 |
| `audit.cjs` | Audit dispatch, audit open sessions, audit storage helpers |
| `capability-activation.cjs` | Capability activation resolver shared by config validation and capability-state consumers — resolves registry-owned config keys from raw runtime config without re-centralizing migrated settings |
| `capability-command-router.cjs` | ADR-2346 P2 host command router for `gsd-tools capability` — relocated verbatim from the former 706-line `case 'capability':` arm in `gsd-tools.cjs`; dispatched via `HOST_COMMAND_ROUTERS` in `runCommand`'s default case; wires `capability-lifecycle`/`-trust`/`-consent`/`-state`/`-writer`; hand-authored CJS (sibling of `ensure-runtime-build.cjs`) |
| `capability-consent.cjs` | User-owned capability consent store (#1459) — bounded, non-throwing JSON store at `${GSD_HOME\|\|homedir()}/.gsd/consent.json` (NEVER under a repo) keyed by `${realpath(projectRoot)} <id>`; exports `consentStorePath`/`readConsentStore`/`hasProjectConsent` (matches iff integrity AND disclosureSignature both match)/`recordProjectConsent` (atomic+durable write)/`revokeProjectConsent`; the authoritative consent signal that gates PROJECT-scope third-party capability activation so a forged/cloned project ledger no longer activates anything until the user consents on THIS machine |
| `capability-lock.cjs` | Shared cross-process lock primitive (#1459 finding 4) — the SINGLE hardened lockfile protocol used by BOTH capability-lifecycle (`.gsd/capabilities/.lock`) and capability-consent (`.consent.lock`); exports `acquireLock(lockPath, opts?)`/`releaseLock(handle)` with pid + process-start-time liveness identity, a hard deadman, and token+inode owner-safe release — NEVER stale-steals a verified-live same-host holder, reclaims only a provably-dead/unverifiable holder, never deadlocks; `opts.maxAttempts`/`opts.waitForFresh` let the consent store serialize genuinely-contended writers; `_setLockProbes`/`_resetLockProbes` are test seams |
| `capability-ledger.cjs` | Per-runtime install ledger (ADR-1244 D4) — atomic read/write of `.gsd-capabilities.json` recording `{ id, version, source, integrity, files[], sharedEdits[] }` per installed capability; exports `readLedger`/`writeLedger`/`recordInstall`/`removeEntry`/`reconcile` (orphan detection)/`readSmallRegularFile` (utf8) + `readSmallRegularFileBuffer` (raw bytes, the byte-exact consent-hash reader, #1459 finding 1); atomic commit point and reconciliation basis for Phase-4 upgrade/remove |