From d3d689a5e92cc96d62d980506edc182681fe05c4 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Thu, 2 Jul 2026 20:34:30 -0400 Subject: [PATCH] fix(#1920): resolve host version from gsd-core/VERSION + ship capability generators (#1938) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The flattened install layout broke the third-party capability ecosystem in two ways. Both are fixed at the host-version / installer boundary. Gap 1 — host version read as 0.0.0. The running GSD version was resolved via require('../../../package.json') (loader/source) and require('../../package.json') (the gsd-tools CLI), which in the installed layout is the versionless CommonJS marker → the fail-closed fallback reported 0.0.0, so `capability install` rejected any manifest with a real engines.gsd range as "incompatible with GSD 0.0.0". For runtimes that get no marker, and for local installs, that walked-up package.json could even be the USER's own project, reporting a wrong version. Fix: readHostVersion() (capability-loader.cts, capability-source.cts) and capHostVersion() (gsd-tools.cjs) now prefer the authoritative gsd-core/VERSION the installer already writes for EVERY runtime (mirrors resolveVersionFrom(), #1383), falling back to the runtime-root package.json for the dev/source tree, then fail-closing. This fixes every runtime and the actual `capability install` CLI path without touching the marker package.json, so uninstall is unchanged (no data-loss surface). Gap 2 — scripts/gen-capability-registry.cjs (+ its sibling gen-loop-host-contract.cjs) were never copied by the installer, so the loader's never-crash invariant discarded every overlay and fell back to the frozen first-party registry (installed capabilities silently inert). Now copied, uninstalled, and manifest-tracked exactly like fix-slash-commands.cjs (#1223). Regenerates the 16 golden-install-parity fixtures to capture the two newly shipped generator scripts and the gsd-tools.cjs change. Regression tests (RED→GREEN): readHostVersion VERSION-first / fallback / fail-closed resolution; an end-to-end `capability install` against a REAL installed layout proving the engines gate sees the real host version, not 0.0.0; and a real-install check that both generators are shipped and manifest-tracked. Co-authored-by: Claude Opus 4.8 --- ...ller-capability-generators-host-version.md | 5 + bin/install.js | 39 ++++ gsd-core/bin/gsd-tools.cjs | 19 +- src/capability-loader.cts | 32 ++- src/capability-source.cts | 26 ++- ...aller-ships-capability-generators.test.cjs | 208 ++++++++++++++++++ .../golden-install-parity/antigravity.json | 4 +- .../golden-install-parity/augment.json | 4 +- .../golden-install-parity/claude.json | 4 +- .../fixtures/golden-install-parity/cline.json | 4 +- .../golden-install-parity/codebuddy.json | 4 +- .../fixtures/golden-install-parity/codex.json | 4 +- .../golden-install-parity/copilot.json | 4 +- .../golden-install-parity/cursor.json | 4 +- .../golden-install-parity/gemini.json | 4 +- .../golden-install-parity/hermes.json | 4 +- .../fixtures/golden-install-parity/kilo.json | 4 +- .../fixtures/golden-install-parity/kimi.json | 4 +- .../golden-install-parity/opencode.json | 4 +- .../fixtures/golden-install-parity/qwen.json | 4 +- .../fixtures/golden-install-parity/trae.json | 4 +- .../golden-install-parity/windsurf.json | 4 +- 22 files changed, 356 insertions(+), 37 deletions(-) create mode 100644 .changeset/1920-installer-capability-generators-host-version.md create mode 100644 tests/fix-1920-installer-ships-capability-generators.test.cjs diff --git a/.changeset/1920-installer-capability-generators-host-version.md b/.changeset/1920-installer-capability-generators-host-version.md new file mode 100644 index 000000000..37d491fe0 --- /dev/null +++ b/.changeset/1920-installer-capability-generators-host-version.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 1938 +--- +**Third-party capabilities now work on installed layouts.** `capability install` no longer rejects capabilities with a real `engines.gsd` range as "incompatible with GSD 0.0.0" — the host version is now read from the authoritative `gsd-core/VERSION` file across every runtime and the `capability install` CLI. The installer also now ships the registry generator scripts (`gen-capability-registry.cjs`, `gen-loop-host-contract.cjs`), so installed third-party capabilities actually compose into the loop instead of being silently discarded. diff --git a/bin/install.js b/bin/install.js index 7ef056e52..81c9f3ce4 100755 --- a/bin/install.js +++ b/bin/install.js @@ -7377,6 +7377,11 @@ function uninstall(isGlobal, runtime = 'claude') { const fixSlashUninstallPath = path.join(targetDir, 'scripts', 'fix-slash-commands.cjs'); try { fs.unlinkSync(fixSlashUninstallPath); } catch (_) { /* best-effort */ } + // Remove the capability registry generator scripts (#1920) — before the scripts/ rmdir + for (const gen of ['gen-capability-registry.cjs', 'gen-loop-host-contract.cjs']) { + try { fs.unlinkSync(path.join(targetDir, 'scripts', gen)); } catch (_) { /* best-effort */ } + } + // If scripts/ dir is now empty, remove it too const scriptsUninstallDir = path.join(targetDir, 'scripts'); if (fs.existsSync(scriptsUninstallDir)) { @@ -8100,6 +8105,15 @@ function writeManifest(configDir, runtime = 'claude', options = {}) { manifest.files['scripts/fix-slash-commands.cjs'] = fileHash(fixSlashInstallPath); } + // Track the capability registry generator scripts (#1920) — top-level scripts/ files + // not covered by the changeset/lib loops. + for (const gen of ['gen-capability-registry.cjs', 'gen-loop-host-contract.cjs']) { + const genInstallPath = path.join(configDir, 'scripts', gen); + if (fs.existsSync(genInstallPath)) { + manifest.files['scripts/' + gen] = fileHash(genInstallPath); + } + } + // Track the OpenCode native plugin adapter (#1914) so update/drift detection // and uninstall can account for it. if (isOpencode) { @@ -9629,6 +9643,31 @@ function install(isGlobal, runtime = 'claude', options = {}) { } } + // Copy scripts/gen-capability-registry.cjs + scripts/gen-loop-host-contract.cjs — + // required by gsd-core/bin/lib/capability-loader.cjs at overlay-composition time via + // require('../../../scripts/gen-capability-registry.cjs') (which itself requires + // gen-loop-host-contract.cjs). Without these, the loader's never-crash invariant + // discards EVERY third-party capability overlay and silently falls back to the frozen + // first-party registry, so installed capabilities are inert (#1920). Same class of + // gap as #1223 (fix-slash-commands.cjs) and copied unconditionally for the same reason: + // any runtime that installs gsd-core/ needs the capability system to compose. + { + const capGenDestDir = path.join(targetDir, 'scripts'); + fs.mkdirSync(capGenDestDir, { recursive: true }); + for (const gen of ['gen-capability-registry.cjs', 'gen-loop-host-contract.cjs']) { + const genSrc = path.join(src, 'scripts', gen); + const genDest = path.join(capGenDestDir, gen); + if (!fs.existsSync(genSrc)) { + failures.push(`scripts/${gen} (source missing from package — reinstall from npm)`); + } else { + fs.copyFileSync(genSrc, genDest); + if (!verifyFileInstalled(genDest, `scripts/${gen}`)) { + failures.push(`scripts/${gen}`); + } + } + } + } + // Remove legacy get-shit-done-cc artifacts and stale update caches (#607). // cleanupLegacyGsdCc handles both the legacy shared cache and the per-package // cache (formerly an inline unlinkSync here). A cleanup failure must never diff --git a/gsd-core/bin/gsd-tools.cjs b/gsd-core/bin/gsd-tools.cjs index 19fe574b1..3cfd9c11a 100755 --- a/gsd-core/bin/gsd-tools.cjs +++ b/gsd-core/bin/gsd-tools.cjs @@ -1667,13 +1667,22 @@ async function runCommand(command, args, cwd, raw, defaultValue, originalCommand return undefined; }; // Running GSD version (hard gate for engines.gsd at install/load); fail-closed to 0.0.0. + // #1920: prefer the authoritative gsd-core/VERSION the installer writes for EVERY runtime + // (gsd-core/bin/ -> ../VERSION), so installed layouts report the true version even when the + // walked-up ../../package.json is the versionless CommonJS marker or the user's own project. + // Fall back to the runtime-root package.json (dev/source tree), then fail-closed. Mirrors + // readHostVersion() in capability-loader.cts. const capHostVersion = () => { + const SEMVER_PREFIX = /^\d+\.\d+\.\d+/; try { - const pkg = require('../../package.json'); // gsd-core/bin/ -> repo root is two up - return typeof pkg.version === 'string' && pkg.version ? pkg.version : '0.0.0'; - } catch { - return '0.0.0'; - } + const v = fs.readFileSync(path.join(__dirname, '..', 'VERSION'), 'utf8').trim(); + if (SEMVER_PREFIX.test(v)) return v; + } catch { /* not an installed tree (no gsd-core/VERSION) */ } + try { + const pkg = require(path.join(__dirname, '..', '..', 'package.json')); // gsd-core/bin/ -> repo root is two up + if (pkg && typeof pkg.version === 'string' && SEMVER_PREFIX.test(pkg.version)) return pkg.version; + } catch { /* runtime root has no package.json */ } + return '0.0.0'; }; // #1459: the USER-OWNED consent home (GSD_HOME||homedir()) where project-scope consent records // live — OUTSIDE any repo. SAME rule as the loader/consent-store path resolution so a record diff --git a/src/capability-loader.cts b/src/capability-loader.cts index 571c2001a..673570770 100644 --- a/src/capability-loader.cts +++ b/src/capability-loader.cts @@ -198,16 +198,29 @@ function _setGeneratorForTest(g: GeneratorModule | null): void { _generatorOverride = g; } -/** Resolve the running GSD version; fail-closed to '0.0.0' if it cannot be read. */ -function readHostVersion(): string { +/** + * Resolve the running GSD version; fail-closed to '0.0.0' if it cannot be read. + * + * Prefer the authoritative `gsd-core/VERSION` the installer writes for EVERY runtime + * (libDir = gsd-core/bin/lib/, so `../../VERSION` = gsd-core/VERSION). This is reliable + * across all installed layouts — including runtimes that get no marker package.json, and + * local installs where the walked-up `../../../package.json` would resolve to the USER's + * own project and report a wrong version (#1920). Fall back to the runtime-root + * package.json for the dev/source tree, then fail-closed. Mirrors resolveVersionFrom() + * (#1383). `libDir` is injectable for tests; it defaults to this module's directory. + */ +export function readHostVersion(libDir: string = __dirname): string { + const SEMVER_PREFIX = /^\d+\.\d+\.\d+/; + try { + const v = fs.readFileSync(path.join(libDir, '..', '..', 'VERSION'), 'utf8').trim(); + if (SEMVER_PREFIX.test(v)) return v; + } catch { /* not an installed tree (no gsd-core/VERSION) */ } try { - // gsd-core/bin/lib/ -> repo/package root is three levels up. // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment - const pkg: { version?: string } = require('../../../package.json'); - return typeof pkg.version === 'string' && pkg.version ? pkg.version : '0.0.0'; - } catch { - return '0.0.0'; - } + const pkg: { version?: string } = require(path.join(libDir, '..', '..', '..', 'package.json')); + if (pkg && typeof pkg.version === 'string' && SEMVER_PREFIX.test(pkg.version)) return pkg.version; + } catch { /* runtime root has no package.json */ } + return '0.0.0'; } /** @@ -848,4 +861,5 @@ export function loadRegistry(options: LoadRegistryOptions = {}): Registry { } } -module.exports = { loadRegistry, _setValidatorForTest, _setGeneratorForTest }; +// readHostVersion is exported for the #1920 regression (VERSION-first host-version resolution). +module.exports = { loadRegistry, readHostVersion, _setValidatorForTest, _setGeneratorForTest }; diff --git a/src/capability-source.cts b/src/capability-source.cts index eee1c3023..5c65d8ea2 100644 --- a/src/capability-source.cts +++ b/src/capability-source.cts @@ -279,15 +279,27 @@ function _setCapabilitySourceHttpGet(fn: HttpGetFn | null): void { // Helpers // --------------------------------------------------------------------------- -/** Resolve the running GSD version; fail-closed to '0.0.0'. */ -function readHostVersion(): string { +/** + * Resolve the running GSD version; fail-closed to '0.0.0'. + * + * Prefer the authoritative `gsd-core/VERSION` the installer writes for EVERY runtime + * (libDir = gsd-core/bin/lib/, so `../../VERSION` = gsd-core/VERSION), so installed + * layouts report the true version even when the walked-up `../../../package.json` is + * absent or belongs to the user's own project (#1920). Fall back to the runtime-root + * package.json (dev/source tree), then fail-closed. Mirrors resolveVersionFrom() (#1383). + */ +function readHostVersion(libDir: string = __dirname): string { + const SEMVER_PREFIX = /^\d+\.\d+\.\d+/; + try { + const v = fs.readFileSync(path.join(libDir, '..', '..', 'VERSION'), 'utf8').trim(); + if (SEMVER_PREFIX.test(v)) return v; + } catch { /* not an installed tree (no gsd-core/VERSION) */ } try { // eslint-disable-next-line @typescript-eslint/no-require-imports - const pkg = require('../../../package.json') as { version?: string }; - return typeof pkg.version === 'string' && pkg.version ? pkg.version : '0.0.0'; - } catch { - return '0.0.0'; - } + const pkg = require(path.join(libDir, '..', '..', '..', 'package.json')) as { version?: string }; + if (pkg && typeof pkg.version === 'string' && SEMVER_PREFIX.test(pkg.version)) return pkg.version; + } catch { /* runtime root has no package.json */ } + return '0.0.0'; } /** Compute sha512- integrity over a buffer. */ diff --git a/tests/fix-1920-installer-ships-capability-generators.test.cjs b/tests/fix-1920-installer-ships-capability-generators.test.cjs new file mode 100644 index 000000000..fda6e6856 --- /dev/null +++ b/tests/fix-1920-installer-ships-capability-generators.test.cjs @@ -0,0 +1,208 @@ +'use strict'; +/** + * Regression tests for #1920: the installer must produce a capability-ecosystem- + * complete flattened layout, and the capability loader must resolve the real host + * version in that layout. + * + * Two gaps broke third-party capabilities on installed (flattened) layouts: + * + * Gap 1 — host version read as 0.0.0. `readHostVersion()` resolved the running GSD + * version via require('../../../package.json'), which in the installed layout is the + * marker package.json ({"type":"commonjs"}, no version) → the fail-closed fallback + * reported 0.0.0, so `capability install` rejected any manifest with a real + * engines.gsd range as "incompatible with GSD 0.0.0". Worse, for runtimes that get + * no marker and for local installs, that walked-up package.json could be the USER's + * own project, reporting a wrong version. Fix: readHostVersion() prefers the + * authoritative gsd-core/VERSION the installer writes for EVERY runtime. + * + * Gap 2 — the registry generator was never shipped. The loader composes overlays via + * require('../../../scripts/gen-capability-registry.cjs'); the installer never copied + * it (nor its sibling gen-loop-host-contract.cjs), so the never-crash invariant + * discarded EVERY overlay and fell back to the frozen first-party registry — + * installed third-party capabilities were silently inert. Same class of gap as #1223 + * (scripts/fix-slash-commands.cjs). + * + * These tests are RED before the fix (loader/install.js) and GREEN after. + */ + +process.env.GSD_TEST_MODE = '1'; + +const { describe, test } = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const os = require('node:os'); +const path = require('node:path'); +const { spawnSync } = require('node:child_process'); +const { cleanup } = require('./helpers.cjs'); + +const ROOT = path.join(__dirname, '..'); +const INSTALL = path.join(ROOT, 'bin', 'install.js'); +const MANIFEST_NAME = 'gsd-file-manifest.json'; + +// The generator scripts the capability loader requires by relative path. +const GENERATORS = ['gen-capability-registry.cjs', 'gen-loop-host-contract.cjs']; + +// --------------------------------------------------------------------------- +// Gap 1 — readHostVersion() prefers gsd-core/VERSION (the installer-written, +// all-runtime authoritative source) over an ambient/absent package.json. +// --------------------------------------------------------------------------- +describe('Gap 1: readHostVersion resolves the real host version in an installed layout (#1920)', () => { + const { readHostVersion } = require('../gsd-core/bin/lib/capability-loader.cjs'); + + /** Build a fake installed tree and return its gsd-core/bin/lib dir (the module libDir). */ + function fakeTree({ version, pkg }) { + const root = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1920-ver-')); + const libDir = path.join(root, 'gsd-core', 'bin', 'lib'); + fs.mkdirSync(libDir, { recursive: true }); + if (version !== undefined) fs.writeFileSync(path.join(root, 'gsd-core', 'VERSION'), version); + if (pkg !== undefined) fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify(pkg)); + return { root, libDir }; + } + + test('prefers gsd-core/VERSION over a wrong ambient package.json version', () => { + // The walked-up package.json belongs to the user's project (wrong version) — must be ignored. + const { root, libDir } = fakeTree({ version: '9.9.9\n', pkg: { name: 'user-app', version: '1.2.3', type: 'commonjs' } }); + try { + assert.strictEqual(readHostVersion(libDir), '9.9.9'); + } finally { + cleanup(root); + } + }); + + test('falls back to the runtime-root package.json when no VERSION file (dev/source tree)', () => { + const { root, libDir } = fakeTree({ pkg: { version: '2.3.4' } }); + try { + assert.strictEqual(readHostVersion(libDir), '2.3.4'); + } finally { + cleanup(root); + } + }); + + test('fail-closes to 0.0.0 when neither VERSION nor a package.json version resolves', () => { + const { root, libDir } = fakeTree({}); + try { + assert.strictEqual(readHostVersion(libDir), '0.0.0'); + } finally { + cleanup(root); + } + }); + + test('a real global install writes gsd-core/VERSION carrying the host version', () => { + const dir = realInstall(); + try { + const vfile = path.join(dir, 'gsd-core', 'VERSION'); + assert.ok(fs.existsSync(vfile), 'installer must write gsd-core/VERSION'); + assert.strictEqual( + fs.readFileSync(vfile, 'utf8').trim(), + require('../package.json').version, + 'gsd-core/VERSION must carry the real host version readHostVersion() reads', + ); + } finally { + cleanup(dir); + } + }); +}); + +// --------------------------------------------------------------------------- +// Gap 2 — the installer ships (and uninstalls / manifest-tracks) the capability +// registry generator scripts. +// --------------------------------------------------------------------------- + +/** Run a real global install into a fresh temp config dir; return that dir. */ +function realInstall() { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1920-')); + // The module-level GSD_TEST_MODE=1 gates the installer's main() off entirely — + // strip it from the child env for the spawned REAL install. + const childEnv = { ...process.env }; + delete childEnv.GSD_TEST_MODE; + const res = spawnSync( + process.execPath, + [INSTALL, '--claude', '--global', '--config-dir', dir], + { encoding: 'utf8', timeout: 120000, env: childEnv }, + ); + assert.strictEqual(res.status, 0, `install --claude failed: ${res.stderr || res.stdout}`); + return dir; +} + +// --------------------------------------------------------------------------- +// Gap 1 (end-to-end CLI) — the actual repro: `gsd-tools capability install` on an +// INSTALLED layout must resolve the real host version for the engines.gsd gate, not +// 0.0.0. The dev tree always has a versioned package.json two levels up, so this only +// reproduces against a real install (where ../../package.json is the versionless marker +// and gsd-core/VERSION carries the truth). The CLI computes hostVersion itself, so this +// covers capHostVersion() in gsd-tools.cjs — a path the loader unit test does not touch. +// --------------------------------------------------------------------------- +describe('Gap 1 (end-to-end CLI): installed capability install uses the real host version (#1920)', () => { + const HOST_MAJOR = require('../package.json').version.split('.')[0]; + + function writeProbeCapability(engines) { + const src = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1920-cap-')); + const cap = { + id: 'p1920-probe', role: 'feature', version: '1.0.0', title: 'probe', + description: 'test capability', tier: 'standard', requires: [], + runtimeCompat: { supported: ['*'], unsupported: [] }, + skills: [], agents: [], hooks: [], config: {}, steps: [], + contributions: [], gates: [], engines, + }; + fs.writeFileSync(path.join(src, 'capability.json'), JSON.stringify(cap, null, 2)); + return src; + } + + test('a capability requiring engines.gsd ">=.0.0" is not rejected as GSD 0.0.0', () => { + const dir = realInstall(); + const home = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1920-home-')); + const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1920-cwd-')); + fs.mkdirSync(path.join(cwd, '.planning'), { recursive: true }); + fs.writeFileSync(path.join(cwd, '.planning', 'config.json'), '{}'); + const src = writeProbeCapability({ gsd: `>=${HOST_MAJOR}.0.0` }); + try { + const installedTools = path.join(dir, 'gsd-core', 'bin', 'gsd-tools.cjs'); + const env = { ...process.env, GSD_HOME: home, GSD_WORKSTREAM: '', GSD_PROJECT: '', GSD_SESSION_KEY: '', CLAUDE_SESSION_ID: '' }; + delete env.GSD_TEST_MODE; + const res = spawnSync( + process.execPath, + [installedTools, 'capability', 'install', src, '--scope', 'global', '--yes', '--json'], + { cwd, env, encoding: 'utf8', timeout: 60000 }, + ); + const combined = `${res.stdout || ''}\n${res.stderr || ''}`; + assert.doesNotMatch( + combined, + /incompatible with GSD 0\.0\.0/, + `installed CLI saw host version 0.0.0 — the engines gate read the versionless marker: ${combined}`, + ); + assert.strictEqual(res.status, 0, `capability install failed on the installed layout: ${combined}`); + } finally { + cleanup(dir); cleanup(home); cleanup(cwd); cleanup(src); + } + }); +}); + +describe('Gap 2: installer ships the capability registry generator scripts (#1920)', () => { + test('the generator scripts are copied into scripts/', () => { + const dir = realInstall(); + try { + for (const gen of GENERATORS) { + const dest = path.join(dir, 'scripts', gen); + assert.ok(fs.existsSync(dest), `installer must ship scripts/${gen}`); + assert.ok(fs.statSync(dest).size > 0, `scripts/${gen} must not be empty`); + } + } finally { + cleanup(dir); + } + }); + + test('the shipped generator scripts are tracked in the file manifest', () => { + const dir = realInstall(); + try { + const manifest = JSON.parse(fs.readFileSync(path.join(dir, MANIFEST_NAME), 'utf8')); + for (const gen of GENERATORS) { + assert.ok( + manifest.files[`scripts/${gen}`], + `manifest must track scripts/${gen} for drift/uninstall accounting`, + ); + } + } finally { + cleanup(dir); + } + }); +}); diff --git a/tests/fixtures/golden-install-parity/antigravity.json b/tests/fixtures/golden-install-parity/antigravity.json index 399095c27..d487a1981 100644 --- a/tests/fixtures/golden-install-parity/antigravity.json +++ b/tests/fixtures/golden-install-parity/antigravity.json @@ -37,7 +37,7 @@ "agents/gsd-verifier.md": "d2bd23b62f95a64f", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "775a6f3d86f8e5e3", + "gsd-core/bin/gsd-tools.cjs": "815b92a0e7b7693e", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -331,6 +331,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd-add-tests/SKILL.md": "95cd3eb1698fc79b", diff --git a/tests/fixtures/golden-install-parity/augment.json b/tests/fixtures/golden-install-parity/augment.json index b92dbbaba..ff2e0f7be 100644 --- a/tests/fixtures/golden-install-parity/augment.json +++ b/tests/fixtures/golden-install-parity/augment.json @@ -106,7 +106,7 @@ "commands/gsd-workstreams.md": "52ab9c585d3a00f3", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "43e6c5810defe512", + "gsd-core/bin/gsd-tools.cjs": "4456f5432471af00", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -400,6 +400,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd-ns-context/SKILL.md": "90ff2716402f8f61", diff --git a/tests/fixtures/golden-install-parity/claude.json b/tests/fixtures/golden-install-parity/claude.json index 236b181b7..ffffae15e 100644 --- a/tests/fixtures/golden-install-parity/claude.json +++ b/tests/fixtures/golden-install-parity/claude.json @@ -36,7 +36,7 @@ "agents/gsd-verifier.md": "d62ffb1f520520c0", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "43e6c5810defe512", + "gsd-core/bin/gsd-tools.cjs": "4456f5432471af00", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -330,6 +330,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd-add-tests/SKILL.md": "6661195a66f25ae8", diff --git a/tests/fixtures/golden-install-parity/cline.json b/tests/fixtures/golden-install-parity/cline.json index 67d968cfa..070f04639 100644 --- a/tests/fixtures/golden-install-parity/cline.json +++ b/tests/fixtures/golden-install-parity/cline.json @@ -40,7 +40,7 @@ "agents/gsd-verifier.md": "5645dfb20b787f01", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "43e6c5810defe512", + "gsd-core/bin/gsd-tools.cjs": "4456f5432471af00", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -312,6 +312,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd-ns-context/SKILL.md": "e278a50f3ecb8f56", diff --git a/tests/fixtures/golden-install-parity/codebuddy.json b/tests/fixtures/golden-install-parity/codebuddy.json index 675284a0f..e04abe209 100644 --- a/tests/fixtures/golden-install-parity/codebuddy.json +++ b/tests/fixtures/golden-install-parity/codebuddy.json @@ -106,7 +106,7 @@ "commands/gsd-workstreams.md": "884b6c8d648422c7", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "43e6c5810defe512", + "gsd-core/bin/gsd-tools.cjs": "4456f5432471af00", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -400,6 +400,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd-add-tests/SKILL.md": "60dd7f9779d5f493", diff --git a/tests/fixtures/golden-install-parity/codex.json b/tests/fixtures/golden-install-parity/codex.json index 690cfe072..035b7e843 100644 --- a/tests/fixtures/golden-install-parity/codex.json +++ b/tests/fixtures/golden-install-parity/codex.json @@ -72,7 +72,7 @@ "config.toml": "a34316b9ac61a620", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "43e6c5810defe512", + "gsd-core/bin/gsd-tools.cjs": "4456f5432471af00", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -346,6 +346,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd-add-tests/SKILL.md": "f3c1594a059de3ee", diff --git a/tests/fixtures/golden-install-parity/copilot.json b/tests/fixtures/golden-install-parity/copilot.json index f38dcf766..5b09c88d2 100644 --- a/tests/fixtures/golden-install-parity/copilot.json +++ b/tests/fixtures/golden-install-parity/copilot.json @@ -38,7 +38,7 @@ "copilot-instructions.md": "1fb04111759f1645", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "775a6f3d86f8e5e3", + "gsd-core/bin/gsd-tools.cjs": "815b92a0e7b7693e", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -311,6 +311,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd-add-tests/SKILL.md": "dfe3f8a07f34c438", diff --git a/tests/fixtures/golden-install-parity/cursor.json b/tests/fixtures/golden-install-parity/cursor.json index 37560cc77..2c6f6be77 100644 --- a/tests/fixtures/golden-install-parity/cursor.json +++ b/tests/fixtures/golden-install-parity/cursor.json @@ -106,7 +106,7 @@ "commands/gsd-workstreams.md": "112660ceb663c750", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "775a6f3d86f8e5e3", + "gsd-core/bin/gsd-tools.cjs": "815b92a0e7b7693e", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -380,6 +380,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd-add-tests/SKILL.md": "2cfc1922a2c0f308", diff --git a/tests/fixtures/golden-install-parity/gemini.json b/tests/fixtures/golden-install-parity/gemini.json index 85678e890..c7f4e2aaf 100644 --- a/tests/fixtures/golden-install-parity/gemini.json +++ b/tests/fixtures/golden-install-parity/gemini.json @@ -106,7 +106,7 @@ "commands/gsd/workstreams.toml": "95f0c349b808a84c", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "43e6c5810defe512", + "gsd-core/bin/gsd-tools.cjs": "4456f5432471af00", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -400,6 +400,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7" } diff --git a/tests/fixtures/golden-install-parity/hermes.json b/tests/fixtures/golden-install-parity/hermes.json index 7836c050c..e5778fc6b 100644 --- a/tests/fixtures/golden-install-parity/hermes.json +++ b/tests/fixtures/golden-install-parity/hermes.json @@ -37,7 +37,7 @@ "agents/gsd-verifier.md": "c5916e463df6306e", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "43e6c5810defe512", + "gsd-core/bin/gsd-tools.cjs": "4456f5432471af00", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -331,6 +331,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd/DESCRIPTION.md": "d93e29a1a09cfd11", diff --git a/tests/fixtures/golden-install-parity/kilo.json b/tests/fixtures/golden-install-parity/kilo.json index 315784cb1..dca999657 100644 --- a/tests/fixtures/golden-install-parity/kilo.json +++ b/tests/fixtures/golden-install-parity/kilo.json @@ -106,7 +106,7 @@ "command/gsd-workstreams.md": "5e57eed1881c3891", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "43e6c5810defe512", + "gsd-core/bin/gsd-tools.cjs": "4456f5432471af00", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -401,6 +401,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd-add-tests/SKILL.md": "addc3a220961a9c7", diff --git a/tests/fixtures/golden-install-parity/kimi.json b/tests/fixtures/golden-install-parity/kimi.json index 1c2eb23da..b73548d73 100644 --- a/tests/fixtures/golden-install-parity/kimi.json +++ b/tests/fixtures/golden-install-parity/kimi.json @@ -73,7 +73,7 @@ "agents/subagents/gsd-verifier.yaml": "2d2bd6b37626f382", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "43e6c5810defe512", + "gsd-core/bin/gsd-tools.cjs": "4456f5432471af00", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -345,6 +345,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd-add-tests/SKILL.md": "217fc2587d3e7ec2", diff --git a/tests/fixtures/golden-install-parity/opencode.json b/tests/fixtures/golden-install-parity/opencode.json index 2abbee7fe..f8935c4e6 100644 --- a/tests/fixtures/golden-install-parity/opencode.json +++ b/tests/fixtures/golden-install-parity/opencode.json @@ -106,7 +106,7 @@ "command/gsd-workstreams.md": "5e57eed1881c3891", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "43e6c5810defe512", + "gsd-core/bin/gsd-tools.cjs": "4456f5432471af00", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -402,6 +402,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd-add-tests/SKILL.md": "f60794b90b48cbac", diff --git a/tests/fixtures/golden-install-parity/qwen.json b/tests/fixtures/golden-install-parity/qwen.json index 0b693965a..63b196302 100644 --- a/tests/fixtures/golden-install-parity/qwen.json +++ b/tests/fixtures/golden-install-parity/qwen.json @@ -37,7 +37,7 @@ "agents/gsd-verifier.md": "7286d42f73e54be1", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "43e6c5810defe512", + "gsd-core/bin/gsd-tools.cjs": "4456f5432471af00", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -331,6 +331,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd-ns-context/SKILL.md": "654c71262d91650c", diff --git a/tests/fixtures/golden-install-parity/trae.json b/tests/fixtures/golden-install-parity/trae.json index 38fd6e3fa..921458af2 100644 --- a/tests/fixtures/golden-install-parity/trae.json +++ b/tests/fixtures/golden-install-parity/trae.json @@ -37,7 +37,7 @@ "agents/gsd-verifier.md": "2fef6afe676b0e34", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "775a6f3d86f8e5e3", + "gsd-core/bin/gsd-tools.cjs": "815b92a0e7b7693e", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -309,6 +309,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7", "skills/gsd-ns-context/SKILL.md": "e278a50f3ecb8f56", diff --git a/tests/fixtures/golden-install-parity/windsurf.json b/tests/fixtures/golden-install-parity/windsurf.json index bec1614fc..575a401be 100644 --- a/tests/fixtures/golden-install-parity/windsurf.json +++ b/tests/fixtures/golden-install-parity/windsurf.json @@ -37,7 +37,7 @@ "agents/gsd-verifier.md": "b16b34a580941124", "gsd-core/VERSION": "ef0deccd81a6723c", "gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74", - "gsd-core/bin/gsd-tools.cjs": "775a6f3d86f8e5e3", + "gsd-core/bin/gsd-tools.cjs": "815b92a0e7b7693e", "gsd-core/bin/gsd_run": "62d9b647ede212e6", "gsd-core/bin/shared/config-defaults.manifest.json": "517e6a7c1e9f4f16", "gsd-core/bin/shared/config-schema.manifest.json": "7d398e94c44e5268", @@ -309,6 +309,8 @@ "scripts/changeset/render.cjs": "e47bc3e1587c3cae", "scripts/changeset/serialize.cjs": "ac0b8fe6f87cdb0e", "scripts/fix-slash-commands.cjs": "0519742531ff3529", + "scripts/gen-capability-registry.cjs": "c52201ff4d1c2cd7", + "scripts/gen-loop-host-contract.cjs": "c7f15237234811a0", "scripts/lib/allowlist-ratchet.cjs": "ffaceaac3efc2660", "scripts/lib/cli-exit.cjs": "612d0c372c75b7e7" }