fix(#4132): verify durable runtime surface sources (#4182)

* fix(#4132): verify durable runtime surface sources

* chore(#4132): record PR number in changeset

* test(#4132): cover rejected commands source alias

* fix(#4132): reject aliased package fallback

* test(#4132): cover rejected agents source alias

* test(#4132): cover partially aliased marker provider

* fix(#4132): reject partially aliased source providers

* test(#4132): cover routed source identity probes

* fix(#4132): route installed source identity probes

* refactor(#4132): tighten installer source metadata

* test(#4132): cover corpus trust boundary attacks

* fix(#4132): close installed corpus trust gaps

* refactor(#4132): keep installer authority private

* fix(#4132): preserve private installer fallback

* test(#4132): preserve fixture source authority

* fix(#4132): reject overlapping source fallback

* fix(#4132): avoid redundant installed corpus reads

* refactor(#4132): simplify provider resolution

* test(#4132): sync install tree fixtures after rebase

---------

Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
This commit is contained in:
Zy Deng
2026-09-05 21:32:52 +02:00
committed by GitHub
parent 1017898cb9
commit 4c60879b5d
49 changed files with 3956 additions and 307 deletions

View File

@@ -143,6 +143,10 @@ function buildSourceTree(agentFiles) {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-agent-parity-src-'));
const commandsGsd = path.join(root, 'commands', 'gsd');
fs.mkdirSync(commandsGsd, { recursive: true });
// Runtime Surface source providers are atomic across every source class a
// layout needs. Keep this marker fixture complete for commands + agents so
// the installer resolver does not correctly fall back to the package tree.
fs.writeFileSync(path.join(commandsGsd, 'fixture-command.md'), '# Fixture command\n');
const agentsDir = path.join(root, 'agents');
fs.mkdirSync(agentsDir, { recursive: true });
for (const [name, content] of Object.entries(agentFiles)) {

View File

@@ -136,14 +136,16 @@ function spawnInstall(repoRoot, runtime, scope) {
}
/** Emitted files under `root` that are derived from the probe agent AND contain
* `token`. The `derivedOnly` filter is what keeps shipped library sources —
* which legitimately carry the marker grammar — out of the leak set. */
* `token`. The `derivedOnly` filter keeps shipped library sources and the
* installation-owned raw re-staging corpus — both of which legitimately
* preserve canonical marker grammar — out of the emitted-artifact leak set. */
function filesContaining(root, token, derivedOnly = true) {
if (!fs.existsSync(root)) return [];
const hits = [];
for (const abs of walk(root)) {
const rel = path.relative(root, abs).replace(/\\/g, '/');
if (derivedOnly && !rel.includes(PROBE_STEM)) continue;
if (derivedOnly && (rel.startsWith('gsd-core/agents/') || rel.includes('/gsd-core/agents/'))) continue;
let buf;
try {
buf = fs.readFileSync(abs);

View File

@@ -253,7 +253,8 @@ test('Kimi neutralizes ~/.claude/gsd-core references instead of leaking a repoin
// to see the ORIGINAL `~/.claude/gsd-core` text; kimi/kimi-code capability.json
// now opt out via hostBehaviors.noPathRewrite so that still holds.
const install = installRuntime(t, 'kimi', { scope: 'global' });
const artifacts = emittedAgentArtifacts(install, 'gsd-executor');
// Inspect generated prompts, not the installation-owned raw source corpus.
const artifacts = emittedAgentArtifacts(install, 'gsd-executor', path.join(install.configDir, 'agents'));
assert.ok(artifacts.some((artifact) => artifact.includes('GSD core')),
'a ~/.claude/gsd-core reference must neutralize to prose, not a repointed Kimi path');
assert.ok(artifacts.every((artifact) =>

View File

@@ -1145,6 +1145,10 @@ describe('issue-2322: capability set --runtime materializes an installed third-p
// Step 3 of the issue repro: capability set my-thing --runtime claude --scope global
const rcd = tmpDir('cap-cli-rcd-');
// A global materialization needs one complete Runtime Surface provider.
// This fixture exercises the supported legacy compatibility-marker path;
// source-less global trees now fail closed and must be upgraded first.
fs.writeFileSync(path.join(rcd, '.gsd-source'), path.join(__dirname, '..', 'commands', 'gsd') + '\n');
const setResult = runGsdTools(
['capability', 'set', 'my-thing', '--runtime', 'claude', '--scope', 'global', '--config-dir', rcd, '--raw'],
cwd,

View File

@@ -447,6 +447,11 @@ describe('capability-writer: setCapabilityState', () => {
const materialiseWarning = result.warnings.find((w) => w.includes('materialize failed'));
assert.equal(materialiseWarning, undefined,
`materialise failure must not appear in warnings, got: ${JSON.stringify(result.warnings)}`);
assert.equal(
readSurface(rcd),
null,
'a failed materialization must not publish the computed surface state',
);
} finally {
cleanup(rcd);
cleanup(cwd);

View File

@@ -40,6 +40,18 @@ const {
const _manifest = loadSkillsManifest();
const resolvedProfileFull = resolveProfile({ modes: [], manifest: _manifest });
function installFromFixture(configDir) {
return installRuntimeArtifacts(
'claude',
configDir,
'global',
resolvedProfileFull,
undefined,
undefined,
{ fs },
);
}
/**
* Set up a configDir backed by a custom srcDir via .gsd-source marker.
* Returns { configDir, srcDir } both under tmpDir.
@@ -50,6 +62,12 @@ function setupConfigDir(tmpDir, commandFiles) {
for (const [name, content] of Object.entries(commandFiles)) {
fs.writeFileSync(path.join(srcDir, name), content);
}
// Claude's layout consumes commands and agents from one atomic provider.
// Keep the marker fixture complete so these tests exercise their custom
// command bytes instead of correctly falling back to the package corpus.
const agentsDir = path.join(tmpDir, 'agents');
fs.mkdirSync(agentsDir, { recursive: true });
fs.writeFileSync(path.join(agentsDir, 'gsd-fixture-agent.md'), '---\nname: gsd-fixture-agent\n---\n');
const configDir = path.join(tmpDir, 'config');
fs.mkdirSync(configDir, { recursive: true });
// .gsd-source marker tells findInstallSourceRoot to use our custom srcDir
@@ -212,7 +230,7 @@ describe('installRuntimeArtifacts (claude global) — skill layout', () => {
'health.md': '---\nname: gsd:health\ndescription: Check health\n---\n\nHealth body.',
});
installRuntimeArtifacts('claude', configDir, 'global', resolvedProfileFull);
installFromFixture(configDir);
const skillsDir = path.join(configDir, 'skills');
assert.ok(
@@ -238,7 +256,7 @@ describe('installRuntimeArtifacts (claude global) — skill layout', () => {
// Production sequence: uninstall wipes gsd-* entries, install writes fresh ones
uninstallRuntimeArtifacts('claude', configDir, 'global');
installRuntimeArtifacts('claude', configDir, 'global', resolvedProfileFull);
installFromFixture(configDir);
// Stale skill removed by uninstall
assert.ok(
@@ -264,7 +282,7 @@ describe('installRuntimeArtifacts (claude global) — skill layout', () => {
fs.writeFileSync(path.join(otherDir, 'SKILL.md'), 'custom content');
// Install (no pre-uninstall: uninstall only removes gsd-* prefixed entries)
installRuntimeArtifacts('claude', configDir, 'global', resolvedProfileFull);
installFromFixture(configDir);
// Non-GSD skill preserved
assert.ok(
@@ -291,15 +309,19 @@ describe('installRuntimeArtifacts (claude global) — skill layout', () => {
// an empty dir — _copyStaged then copies nothing into skills/.
const emptySrc = path.join(tmpDir, 'empty-commands', 'gsd');
fs.mkdirSync(emptySrc, { recursive: true });
fs.writeFileSync(path.join(emptySrc, 'README.txt'), 'fixture only\n');
const agentsDir = path.join(tmpDir, 'agents');
fs.mkdirSync(agentsDir, { recursive: true });
fs.writeFileSync(path.join(agentsDir, 'gsd-fixture-agent.md'), '---\nname: gsd-fixture-agent\n---\n');
const configDir = path.join(tmpDir, 'config-empty');
fs.mkdirSync(configDir, { recursive: true });
fs.writeFileSync(path.join(configDir, '.gsd-source'), emptySrc + '\n');
// Should not throw
installRuntimeArtifacts('claude', configDir, 'global', resolvedProfileFull);
// Use the existing installer fs seam to supply this fixture corpus and
// skip production provisioning, which would intentionally replace it.
installFromFixture(configDir);
const skillsDir = path.join(configDir, 'skills');
// If skills dir was created it must contain no gsd-* entries
if (fs.existsSync(skillsDir)) {
const gsdEntries = fs.readdirSync(skillsDir).filter(n => n.startsWith('gsd-'));
assert.strictEqual(gsdEntries.length, 0, 'no gsd-* skills created when src has no .md files');
@@ -339,7 +361,7 @@ describe('installRuntimeArtifacts path replacement in Claude global skills (#165
].join('\n'),
});
installRuntimeArtifacts('claude', configDir, 'global', resolvedProfileFull);
installFromFixture(configDir);
const content = fs.readFileSync(
path.join(configDir, 'skills', 'gsd-manager', 'SKILL.md'), 'utf8'
@@ -363,7 +385,7 @@ describe('installRuntimeArtifacts path replacement in Claude global skills (#165
'debug.md': '---\nname: gsd:debug\ndescription: Debug\n---\n\n@$HOME/.claude/gsd-core/workflows/debug.md',
});
installRuntimeArtifacts('claude', configDir, 'global', resolvedProfileFull);
installFromFixture(configDir);
const content = fs.readFileSync(
path.join(configDir, 'skills', 'gsd-debug', 'SKILL.md'), 'utf8'
@@ -383,7 +405,7 @@ describe('installRuntimeArtifacts path replacement in Claude global skills (#165
'next.md': '---\nname: gsd:next\ndescription: Next\n---\n\n@~/.claude/gsd-core/workflows/next.md',
});
installRuntimeArtifacts('claude', configDir, 'global', resolvedProfileFull);
installFromFixture(configDir);
const content = fs.readFileSync(
path.join(configDir, 'skills', 'gsd-next', 'SKILL.md'), 'utf8'
@@ -422,7 +444,7 @@ describe('Legacy commands/gsd/ cleanup', () => {
// installRuntimeArtifacts calls _runLegacyInstallMigrations which removes
// commands/gsd/ for claude runtime (it's the legacy location for global).
installRuntimeArtifacts('claude', configDir, 'global', resolvedProfileFull);
installFromFixture(configDir);
assert.ok(!fs.existsSync(legacyDir), 'legacy commands/gsd/ removed');
assert.ok(

View File

@@ -47,6 +47,7 @@ const commandRoster = require('../gsd-core/bin/lib/command-roster.cjs');
const slashCommandTransformer = require('../scripts/fix-slash-commands.cjs');
const REAL_COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
const REAL_PACKAGE_ROOT = path.resolve(__dirname, '..');
const MANIFEST = loadSkillsManifest(REAL_COMMANDS_DIR);
const RESOLVED_CORE = resolveProfile({ modes: ['core'], manifest: MANIFEST });
const RESOLVED_FULL = resolveProfile({ modes: ['full'], manifest: MANIFEST });
@@ -149,13 +150,11 @@ const REAL_FS_WRITE_SURFACE = [
'mkdtempSync', 'openSync', 'readSync', 'closeSync',
];
// Package-source roots a correct install is expected to read for real, even
// while a fake DESTINATION adapter is injected (40-design.md "Known limits":
// this seam makes destination IO fake-able; package-source IO stays real by
// design). Mirrors findInstallSourceRoot's/findAgentsSourceRoot's/
// readGsdCommandNames's own targets (commands/gsd/, agents/), all resolved
// the same way REAL_COMMANDS_DIR is above.
const PACKAGE_SOURCE_ROOTS = [REAL_COMMANDS_DIR, path.join(__dirname, '..', 'agents')];
// The provider resolver probes upward through the executing package before it
// reaches commands/gsd and agents. All read-only package-tree probes are valid
// real IO while a fake DESTINATION adapter is active; destination paths remain
// poisoned below.
const PACKAGE_SOURCE_ROOTS = [path.resolve(__dirname, '..')];
function isPackageSourcePath(resolvedPath) {
return PACKAGE_SOURCE_ROOTS.some(
@@ -390,6 +389,29 @@ function sha256Hex(content) {
return crypto.createHash('sha256').update(content).digest('hex');
}
function fakeInstalledCorpusSeed(configDir) {
const coreDir = path.join(configDir, 'gsd-core');
const commandsDir = path.join(coreDir, 'commands');
const commandsGsdDir = path.join(commandsDir, 'gsd');
const agentsDir = path.join(coreDir, 'agents');
return [
[configDir, { type: 'dir' }],
[coreDir, { type: 'dir' }],
[commandsDir, { type: 'dir' }],
[commandsGsdDir, { type: 'dir' }],
[path.join(commandsGsdDir, 'fixture.md'), { type: 'file', content: '# Fixture command\n' }],
[agentsDir, { type: 'dir' }],
[path.join(agentsDir, 'fixture-agent.md'), { type: 'file', content: '# Fixture agent\n' }],
];
}
function fakeInstalledCorpusManifestFiles() {
return {
'gsd-core/commands/gsd/fixture.md': sha256Hex('# Fixture command\n'),
'gsd-core/agents/fixture-agent.md': sha256Hex('# Fixture agent\n'),
};
}
describe('installRuntimeArtifacts — F2: fake-adapter install touches no real filesystem', () => {
test('fake-adapter install touches no real filesystem (claude, skills-only)', (t) => {
// Every real fs method this call tree could reach is poisoned BY PATH
@@ -399,15 +421,16 @@ describe('installRuntimeArtifacts — F2: fake-adapter install touches no real f
// try/finally inside test bodies").
const packageSourceHits = poisonRealFsAgainstDestination(t, '');
const fakeFs = createFakeInstallFs();
// configDir deliberately never created for real — F2 asserts nothing
// real ever gets written under it.
const configDir = path.join(os.tmpdir(), `gsd-f2-must-not-exist-${crypto.randomUUID()}`);
const fakeFs = createFakeInstallFs(fakeInstalledCorpusSeed(configDir));
// configDir exists only in the fake store — F2 asserts nothing real ever
// gets written under it. The installed corpus seed is the new provider
// contract, not destination setup on the host filesystem.
const result = installRuntimeArtifacts(
'claude', configDir, 'global', RESOLVED_CORE, undefined, undefined,
{ fs: fakeFs },
{ fs: fakeFs, packageRoot: REAL_PACKAGE_ROOT },
);
assert.notStrictEqual(
@@ -436,10 +459,13 @@ describe('installRuntimeArtifacts — F2: fake-adapter install touches no real f
const legacyFile = path.join(legacyDir, 'gsd-old-cmd.md');
const content = '# stale legacy command\n';
const manifestPath = path.join(configDir, 'gsd-file-manifest.json');
const manifestJson = JSON.stringify({ files: { 'command/gsd-old-cmd.md': sha256Hex(content) } });
const manifestJson = JSON.stringify({ files: {
...fakeInstalledCorpusManifestFiles(),
'command/gsd-old-cmd.md': sha256Hex(content),
} });
const fakeFs = createFakeInstallFs([
[configDir, { type: 'dir' }],
...fakeInstalledCorpusSeed(configDir),
[legacyDir, { type: 'dir' }],
[legacyFile, { type: 'file', content }],
[manifestPath, { type: 'file', content: manifestJson }],
@@ -447,7 +473,7 @@ describe('installRuntimeArtifacts — F2: fake-adapter install touches no real f
const result = installRuntimeArtifacts(
'opencode', configDir, 'global', RESOLVED_CORE, undefined, undefined,
{ fs: fakeFs },
{ fs: fakeFs, packageRoot: REAL_PACKAGE_ROOT },
);
assert.notStrictEqual(result, undefined, 'F2 (opencode legacy migration): must still return a plan');
@@ -476,7 +502,7 @@ describe('installRuntimeArtifacts — F2: fake-adapter install touches no real f
// the poisoned list (see install-fs-adapter.cts's module doc — it is
// deliberately unrouted, real-fs-only, package-source introspection), so
// resolving this here is safe even after poisoning existsSync et al.
const commandsGsdDir = runtimeArtifactLayout.findInstallSourceRoot();
const commandsGsdDir = REAL_COMMANDS_DIR;
const repoRoot = path.dirname(path.dirname(commandsGsdDir));
const nativePlugin = registry.runtimes.pi.runtime.hostBehaviors.nativePlugin;
assert.ok(nativePlugin && nativePlugin.source, 'pi must declare hostBehaviors.nativePlugin.source (registry drifted)');
@@ -489,7 +515,7 @@ describe('installRuntimeArtifacts — F2: fake-adapter install touches no real f
const result = installRuntimeArtifacts(
'pi', configDir, 'global', RESOLVED_CORE, undefined, undefined,
{ fs: fakeFs },
{ fs: fakeFs, packageRoot: REAL_PACKAGE_ROOT },
);
assert.notStrictEqual(result, undefined, 'F2 (nativePlugin): must still return a plan');
@@ -522,10 +548,13 @@ describe('installRuntimeArtifacts — F2: fake-adapter install touches no real f
const content = '# stale retired artifact\n';
const relPath = `${destSubpath.replace(/\\/g, '/')}/${staleName}`;
const manifestPath = path.join(configDir, 'gsd-file-manifest.json');
const manifestJson = JSON.stringify({ files: { [relPath]: sha256Hex(content) } });
const manifestJson = JSON.stringify({ files: {
...fakeInstalledCorpusManifestFiles(),
[relPath]: sha256Hex(content),
} });
const fakeFs = createFakeInstallFs([
[configDir, { type: 'dir' }],
...fakeInstalledCorpusSeed(configDir),
[destDir, { type: 'dir' }],
[staleFile, { type: 'file', content }],
[manifestPath, { type: 'file', content: manifestJson }],
@@ -1196,6 +1225,19 @@ describe('installRuntimeArtifacts — K3: real install before/after, full recurs
`K3 (${runtime}): the file sets written by two independent installs must match`,
);
for (const [relPath, contentA] of filesA) {
if (relPath === '.gsd-source') {
assert.strictEqual(
contentA.toString('utf8'),
`${path.join(dirA, 'gsd-core', 'commands', 'gsd')}\n`,
`K3 (${runtime}): first marker must target its own installed corpus`,
);
assert.strictEqual(
filesB.get(relPath).toString('utf8'),
`${path.join(dirB, 'gsd-core', 'commands', 'gsd')}\n`,
`K3 (${runtime}): second marker must target its own installed corpus`,
);
continue;
}
assert.ok(
contentA.equals(filesB.get(relPath)),
`K3 (${runtime}): ${relPath} content drifted between two independent installs`,

View File

@@ -37,6 +37,41 @@
"agents/gsd-verifier.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -48,6 +83,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -109,6 +109,41 @@
"commands/gsd-workstreams.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -120,6 +155,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -37,6 +37,41 @@
"agents/gsd-verifier.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -48,6 +83,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -39,6 +39,41 @@
"agents/gsd-verifier.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -50,6 +85,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -109,6 +109,41 @@
"commands/gsd-workstreams.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -120,6 +155,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -73,6 +73,41 @@
"config.toml",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -84,6 +119,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -38,6 +38,41 @@
"copilot-instructions.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -49,6 +84,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -37,6 +37,41 @@
"agents/gsd-verifier.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -48,6 +83,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -37,6 +37,41 @@
"agents/gsd-verifier.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -48,6 +83,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -109,6 +109,41 @@
"command/gsd-workstreams.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -120,6 +155,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -38,6 +38,41 @@
"config.toml",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -49,6 +84,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -74,6 +74,41 @@
"agents/subagents/gsd-verifier.yaml",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -85,6 +120,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -109,6 +109,41 @@
"commands/gsd-workstreams.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -120,6 +155,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -37,6 +37,41 @@
"agents/gsd-verifier.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -48,6 +83,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -37,6 +37,41 @@
"agents/gsd-verifier.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -48,6 +83,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -37,6 +37,41 @@
"agents/gsd-verifier.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",

View File

@@ -109,6 +109,41 @@
"commands/gsd-workstreams.md",
"gsd-core/.gsd-runtime",
"gsd-core/VERSION",
"gsd-core/agents/gsd-advisor-researcher.md",
"gsd-core/agents/gsd-ai-researcher.md",
"gsd-core/agents/gsd-assumptions-analyzer.md",
"gsd-core/agents/gsd-code-fixer.md",
"gsd-core/agents/gsd-code-reviewer.md",
"gsd-core/agents/gsd-codebase-mapper.md",
"gsd-core/agents/gsd-debug-session-manager.md",
"gsd-core/agents/gsd-debugger.md",
"gsd-core/agents/gsd-doc-classifier.md",
"gsd-core/agents/gsd-doc-synthesizer.md",
"gsd-core/agents/gsd-doc-verifier.md",
"gsd-core/agents/gsd-doc-writer.md",
"gsd-core/agents/gsd-dom-verifier.md",
"gsd-core/agents/gsd-domain-researcher.md",
"gsd-core/agents/gsd-eval-auditor.md",
"gsd-core/agents/gsd-eval-planner.md",
"gsd-core/agents/gsd-executor.md",
"gsd-core/agents/gsd-framework-selector.md",
"gsd-core/agents/gsd-integration-checker.md",
"gsd-core/agents/gsd-intel-updater.md",
"gsd-core/agents/gsd-mempalace-curator.md",
"gsd-core/agents/gsd-nyquist-auditor.md",
"gsd-core/agents/gsd-pattern-mapper.md",
"gsd-core/agents/gsd-phase-researcher.md",
"gsd-core/agents/gsd-plan-checker.md",
"gsd-core/agents/gsd-planner.md",
"gsd-core/agents/gsd-project-researcher.md",
"gsd-core/agents/gsd-research-synthesizer.md",
"gsd-core/agents/gsd-roadmapper.md",
"gsd-core/agents/gsd-security-auditor.md",
"gsd-core/agents/gsd-ui-auditor.md",
"gsd-core/agents/gsd-ui-checker.md",
"gsd-core/agents/gsd-ui-researcher.md",
"gsd-core/agents/gsd-user-profiler.md",
"gsd-core/agents/gsd-verifier.md",
"gsd-core/bin/check-latest-version.cjs",
"gsd-core/bin/ensure-runtime-build.cjs",
"gsd-core/bin/gsd-tools.cjs",
@@ -120,6 +155,78 @@
"gsd-core/bin/shared/model-catalog.json",
"gsd-core/bin/shared/runtime-aliases.manifest.json",
"gsd-core/bin/verify-reapply-patches.cjs",
"gsd-core/commands/gsd/add-tests.md",
"gsd-core/commands/gsd/ai-integration-phase.md",
"gsd-core/commands/gsd/audit-fix.md",
"gsd-core/commands/gsd/audit-milestone.md",
"gsd-core/commands/gsd/audit-uat.md",
"gsd-core/commands/gsd/autonomous.md",
"gsd-core/commands/gsd/capture.md",
"gsd-core/commands/gsd/cleanup.md",
"gsd-core/commands/gsd/code-review.md",
"gsd-core/commands/gsd/complete-milestone.md",
"gsd-core/commands/gsd/config.md",
"gsd-core/commands/gsd/debug.md",
"gsd-core/commands/gsd/discuss-phase.md",
"gsd-core/commands/gsd/docs-update.md",
"gsd-core/commands/gsd/eval-review.md",
"gsd-core/commands/gsd/execute-phase.md",
"gsd-core/commands/gsd/explore.md",
"gsd-core/commands/gsd/extract-learnings.md",
"gsd-core/commands/gsd/fast.md",
"gsd-core/commands/gsd/forensics.md",
"gsd-core/commands/gsd/graphify.md",
"gsd-core/commands/gsd/health.md",
"gsd-core/commands/gsd/help.md",
"gsd-core/commands/gsd/import.md",
"gsd-core/commands/gsd/inbox.md",
"gsd-core/commands/gsd/ingest-docs.md",
"gsd-core/commands/gsd/manager.md",
"gsd-core/commands/gsd/map-codebase.md",
"gsd-core/commands/gsd/mempalace-capture.md",
"gsd-core/commands/gsd/mempalace-recall.md",
"gsd-core/commands/gsd/milestone-summary.md",
"gsd-core/commands/gsd/mvp-phase.md",
"gsd-core/commands/gsd/new-milestone.md",
"gsd-core/commands/gsd/new-project.md",
"gsd-core/commands/gsd/next.md",
"gsd-core/commands/gsd/ns-context.md",
"gsd-core/commands/gsd/ns-ideate.md",
"gsd-core/commands/gsd/ns-manage.md",
"gsd-core/commands/gsd/ns-project.md",
"gsd-core/commands/gsd/ns-review.md",
"gsd-core/commands/gsd/ns-workflow.md",
"gsd-core/commands/gsd/onboard.md",
"gsd-core/commands/gsd/pause-work.md",
"gsd-core/commands/gsd/phase.md",
"gsd-core/commands/gsd/plan-phase.md",
"gsd-core/commands/gsd/plan-review-convergence.md",
"gsd-core/commands/gsd/pr-branch.md",
"gsd-core/commands/gsd/profile-user.md",
"gsd-core/commands/gsd/progress.md",
"gsd-core/commands/gsd/quick-batch.md",
"gsd-core/commands/gsd/quick.md",
"gsd-core/commands/gsd/resume-work.md",
"gsd-core/commands/gsd/review-backlog.md",
"gsd-core/commands/gsd/review.md",
"gsd-core/commands/gsd/secure-phase.md",
"gsd-core/commands/gsd/settings.md",
"gsd-core/commands/gsd/ship.md",
"gsd-core/commands/gsd/sketch.md",
"gsd-core/commands/gsd/spec-phase.md",
"gsd-core/commands/gsd/spike.md",
"gsd-core/commands/gsd/stats.md",
"gsd-core/commands/gsd/surface.md",
"gsd-core/commands/gsd/thread.md",
"gsd-core/commands/gsd/ui-phase.md",
"gsd-core/commands/gsd/ui-review.md",
"gsd-core/commands/gsd/ultraplan-phase.md",
"gsd-core/commands/gsd/undo.md",
"gsd-core/commands/gsd/update.md",
"gsd-core/commands/gsd/validate-phase.md",
"gsd-core/commands/gsd/verify-work.md",
"gsd-core/commands/gsd/workspace.md",
"gsd-core/commands/gsd/workstreams.md",
"gsd-core/contexts/dev.md",
"gsd-core/contexts/research.md",
"gsd-core/contexts/review.md",

View File

@@ -133,6 +133,7 @@ const { applySurface } = require('../gsd-core/bin/lib/surface.cjs');
const { loadSkillsManifest, resolveProfile } = require('../gsd-core/bin/lib/install-profiles.cjs');
const { resolveRuntimeArtifactLayout } = require('../gsd-core/bin/lib/runtime-artifact-layout.cjs');
const { cleanup, sandboxHome } = require('./helpers.cjs');
const { runMinimalInstall } = require('./helpers/install-shared.cjs');
const COMMANDS_GSD = path.join(ROOT, 'commands', 'gsd');
@@ -169,13 +170,14 @@ describe('#1575 — golden-parity: surface path matches install path for descrip
for (const runtime of DESCRIPTOR_RUNTIMES) {
test(`${runtime}: surface agents byte-identical to install agents`, (t) => {
const configDir = fs.mkdtempSync(path.join(os.tmpdir(), `gsd-1575-${runtime}-`));
t.after(() => { try { cleanup(configDir); } catch { /* best-effort */ } });
const installed = runMinimalInstall({ runtime, scope: 'global' });
const { configDir, root } = installed;
t.after(() => { try { cleanup(root); } catch { /* best-effort */ } });
// #3738: antigravity's skills/agents kinds declare a global `home`
// override resolved from os.homedir() — sandbox HOME to the configDir
// override resolved from os.homedir() — sandbox HOME to the install root
// (the #3712 marker real-home-guard needs) so the override resolves
// inside the sandbox instead of the runner's real home.
sandboxHome(t, configDir);
sandboxHome(t, root);
// Step 1: install path writes agents
installRuntimeArtifacts(runtime, configDir, 'global', parity1575Profile, resolveAttribution1575);
@@ -224,8 +226,10 @@ describe('#1575 — golden-parity: surface path matches install path for descrip
// is a no-op (it replaces existing lines, doesn't add new ones). But this test
// proves the agentCtx threading is correct for both paths regardless.
const attrResolver = () => 'Test Bot <test@example.com>';
const configDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1575-attr-'));
t.after(() => { try { cleanup(configDir); } catch { /* best-effort */ } });
const installed = runMinimalInstall({ runtime: 'cursor', scope: 'global' });
const { configDir, root } = installed;
t.after(() => { try { cleanup(root); } catch { /* best-effort */ } });
sandboxHome(t, root);
installRuntimeArtifacts('cursor', configDir, 'global', parity1575Profile, attrResolver);
@@ -262,8 +266,9 @@ describe('#1575 — golden-parity: surface path matches install path for descrip
describe('#1575 — surface path: no prune data-loss over pre-existing legacy agents', () => {
test('pre-existing gsd-* agents not in staged set are pruned; user agents preserved', (t) => {
const configDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-1575-prune-'));
t.after(() => { try { cleanup(configDir); } catch { /* best-effort */ } });
const installed = runMinimalInstall({ runtime: 'copilot', scope: 'global' });
const { configDir, root } = installed;
t.after(() => { try { cleanup(root); } catch { /* best-effort */ } });
// Seed a pre-existing legacy .agent.md (simulating a prior install)
const agentsDir = path.join(configDir, 'agents');

View File

@@ -1173,7 +1173,16 @@ function sandboxHome(t, dir) {
});
}
module.exports = { runGsdTools, createTempDir, createTempProject, createTempGitProject, cleanup, tmpRootCandidates, readFileNormalized, readWorkflowCombined, parseFrontmatter, isUsageOutput, captureConsole, toPosixPath, absPlanningPath, runNpm, isolatedNpmEnv, withIsolatedProcessState, delay, waitFor, resetRuntimeWarningCaches, SESSION_ENV_KEYS, saveSessionEnv, restoreSessionEnv, clearSessionEnv, isolateWorkstreamEnv, restoreWorkstreamEnv, TOOLS_PATH, SESSION_IDENTITY_ENV_KEYS, scrubConfigLocationEnv, installSpawnEnv, installSpawnHome, sandboxHome, TEST_HOME_SANDBOX_MARKER, mockPartialWriteThenThrow, captureFdSync };
function writePackageSourceMarkerFixture(configDir) {
fs.mkdirSync(configDir, { recursive: true });
fs.writeFileSync(
path.join(configDir, '.gsd-source'),
path.join(__dirname, '..', 'commands', 'gsd') + '\n',
);
return configDir;
}
module.exports = { runGsdTools, createTempDir, createTempProject, createTempGitProject, cleanup, tmpRootCandidates, readFileNormalized, readWorkflowCombined, parseFrontmatter, isUsageOutput, captureConsole, toPosixPath, absPlanningPath, runNpm, isolatedNpmEnv, withIsolatedProcessState, delay, waitFor, resetRuntimeWarningCaches, SESSION_ENV_KEYS, saveSessionEnv, restoreSessionEnv, clearSessionEnv, isolateWorkstreamEnv, restoreWorkstreamEnv, TOOLS_PATH, SESSION_IDENTITY_ENV_KEYS, scrubConfigLocationEnv, installSpawnEnv, installSpawnHome, sandboxHome, writePackageSourceMarkerFixture, TEST_HOME_SANDBOX_MARKER, mockPartialWriteThenThrow, captureFdSync };
// Lazy, for the reason builtLib() is lazy: reading either of these is what
// forces the built-lib require, so a test file that needs neither can still

View File

@@ -274,6 +274,22 @@ const PROVENANCE_RULES = [
pattern: /^(workflows|references|templates|contexts|bin)\/.+$/,
sources: (m) => [`gsd-core/${m[0]}`],
},
{
id: 'gsd-core-commands-corpus',
kind: 'rewrite',
roots: ['gsd-core'],
pattern: /^commands\/gsd\/(.+)$/,
sources: (m) => [`commands/gsd/${m[1]}`],
transforms: [INSTALL_ENGINE_SRC, INSTALLER_SRC],
},
{
id: 'gsd-core-agents-corpus',
kind: 'rewrite',
roots: ['gsd-core'],
pattern: /^agents\/(.+)$/,
sources: (m) => [`agents/${m[1]}`],
transforms: [INSTALL_ENGINE_SRC, INSTALLER_SRC],
},
{
id: 'scripts-verbatim',
kind: 'identity',

View File

@@ -182,6 +182,12 @@ describe('Hermes Agent: installRuntimeArtifacts', () => {
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-hermes-test-'));
// Hermes consumes commands and agents from one source provider. Keep the
// compatibility-marker fixture complete even when an assertion exercises
// only its command-to-skill output.
const agentsDir = path.join(tmpDir, 'src', 'agents');
fs.mkdirSync(agentsDir, { recursive: true });
fs.writeFileSync(path.join(agentsDir, 'fixture-agent.md'), '# Fixture agent\n');
});
afterEach(() => {
@@ -944,7 +950,7 @@ describe('#2284 fail-closed role resolution', () => {
assert.throws(
() => install(true, 'hermes'),
/could not resolve|refusing to install/i,
/could not resolve|refusing to install|source is unavailable or incomplete/i,
'a real hermes install must fail closed, never silently install workflows with unverifiable role references',
);
});

View File

@@ -37,6 +37,10 @@ const commandRoster = require('../gsd-core/bin/lib/command-roster.cjs');
const {
withInstallFs,
} = require('../gsd-core/bin/lib/install-fs-adapter.cjs');
const {
findInstallSourceRoot,
resolveRuntimeArtifactLayout,
} = require('../gsd-core/bin/lib/runtime-artifact-layout.cjs');
const {
stageSkillsForRuntimeAsSkills,
cleanupStagedSkills,
@@ -155,6 +159,141 @@ describe('command-roster readGsdCommandNames — package-source read stays unrou
});
});
describe('runtime artifact source identity — destination probes stay routed', () => {
test('#4132: installed provider admission streams hashes before reading corpus content', (t) => {
const configDir = createTempDir('gsd-installed-provider-');
t.after(() => cleanup(configDir));
const installedCommands = path.join(configDir, 'gsd-core', 'commands', 'gsd');
const installedAgents = path.join(configDir, 'gsd-core', 'agents');
const commandPath = path.join(installedCommands, 'help.md');
const agentPath = path.join(installedAgents, 'gsd-planner.md');
const manifestPath = path.join(configDir, 'gsd-file-manifest.json');
fs.mkdirSync(installedCommands, { recursive: true });
fs.mkdirSync(installedAgents, { recursive: true });
fs.writeFileSync(commandPath, '# installed command\n');
fs.writeFileSync(agentPath, '# installed agent\n');
fs.writeFileSync(manifestPath, JSON.stringify({ files: {
'gsd-core/commands/gsd/help.md': crypto.createHash('sha256').update(fs.readFileSync(commandPath)).digest('hex'),
'gsd-core/agents/gsd-planner.md': crypto.createHash('sha256').update(fs.readFileSync(agentPath)).digest('hex'),
} }));
const corpusPaths = new Set([commandPath, agentPath].map((candidate) => path.resolve(candidate)));
const hashingDescriptors = new Map();
const streamedHashes = new Set();
const hashedBeforeRead = new Set();
const corpusReadsBeforeHash = [];
const readCalls = [];
const recordingFs = {
...fs,
readFileSync: (candidate, ...args) => {
const resolved = path.resolve(String(candidate));
readCalls.push(resolved);
if (corpusPaths.has(resolved) && !hashedBeforeRead.has(resolved)) {
corpusReadsBeforeHash.push(resolved);
}
return fs.readFileSync(candidate, ...args);
},
openSync: (candidate, ...args) => {
const fd = fs.openSync(candidate, ...args);
const resolved = path.resolve(String(candidate));
if (corpusPaths.has(resolved)) hashingDescriptors.set(fd, resolved);
return fd;
},
readSync: (fd, ...args) => {
const resolved = hashingDescriptors.get(fd);
if (resolved) streamedHashes.add(resolved);
return fs.readSync(fd, ...args);
},
closeSync: (fd) => {
fs.closeSync(fd);
const resolved = hashingDescriptors.get(fd);
if (resolved) hashedBeforeRead.add(resolved);
},
};
const layout = resolveRuntimeArtifactLayout('claude', configDir, 'global');
let stagedSkills;
let stagedAgents;
t.after(() => {
if (stagedSkills) cleanup(stagedSkills);
if (stagedAgents) cleanup(stagedAgents);
});
withInstallFs(recordingFs, () => {
stagedSkills = layout.kinds.find((kind) => kind.kind === 'skills').stage({ skills: '*', agents: '*' });
stagedAgents = layout.kinds.find((kind) => kind.kind === 'agents').stage({ skills: '*', agents: '*' });
});
assert.deepStrictEqual(corpusReadsBeforeHash, [], 'installed corpus files must not be pre-read before manifest hashing');
assert.deepStrictEqual(streamedHashes, corpusPaths, 'commands and agents hashes must stream through readSync');
assert.deepStrictEqual(hashedBeforeRead, corpusPaths, 'commands and agents hashes must use the streaming fd path');
assert.ok(readCalls.includes(path.resolve(manifestPath)), 'provider admission must still read the install manifest');
assert.match(fs.readFileSync(path.join(stagedSkills, 'gsd-help', 'SKILL.md'), 'utf8'), /installed command/);
assert.match(fs.readFileSync(path.join(stagedAgents, 'gsd-planner.md'), 'utf8'), /installed agent/);
});
test('#4132: an installed-root alias is resolved through installFs without routing the package root', () => {
const configDir = path.join(os.tmpdir(), `gsd-fake-config-${crypto.randomUUID()}`);
const installedCommands = path.join(configDir, 'gsd-core', 'commands', 'gsd');
const probes = [];
const missing = (p) => {
const error = new Error(`ENOENT: no such file or directory, '${p}'`);
error.code = 'ENOENT';
throw error;
};
const fakeFs = {
existsSync: () => false,
lstatSync: missing,
realpathSync: (p) => {
probes.push(path.normalize(String(p)));
return path.normalize(String(p)) === path.normalize(installedCommands)
? fs.realpathSync(REAL_COMMANDS_DIR)
: path.normalize(String(p));
},
};
assert.throws(
() => withInstallFs(fakeFs, () => findInstallSourceRoot(configDir)),
/install or upgrade gsd-core/,
);
assert.deepStrictEqual(
probes,
[path.normalize(installedCommands)],
'installed destination identity must use installFs, while package-source identity stays on raw fs',
);
});
test('#4132: an unreadable physical root cannot prove a marker is independent', () => {
const configDir = path.join(os.tmpdir(), `gsd-fake-config-${crypto.randomUUID()}`);
const installedCommands = path.join(configDir, 'gsd-core', 'commands', 'gsd');
const markerCommands = path.join(configDir, 'independent', 'commands', 'gsd');
const fakeFs = createFakeFs([
[configDir, { type: 'dir' }],
[path.join(configDir, 'gsd-core'), { type: 'dir' }],
[path.join(configDir, 'gsd-core', 'commands'), { type: 'dir' }],
[installedCommands, { type: 'dir' }],
[path.join(installedCommands, 'help.md'), { type: 'file', content: '# unverified installed command\n' }],
[path.join(configDir, 'independent'), { type: 'dir' }],
[path.join(configDir, 'independent', 'commands'), { type: 'dir' }],
[markerCommands, { type: 'dir' }],
[path.join(markerCommands, 'help.md'), { type: 'file', content: '# marker command\n' }],
[path.join(configDir, '.gsd-source'), { type: 'file', content: markerCommands + '\n' }],
]);
fakeFs.realpathSync = (p) => {
if ([installedCommands, markerCommands].includes(path.normalize(String(p)))) {
const error = new Error(`EACCES: permission denied, realpath '${p}'`);
error.code = 'EACCES';
throw error;
}
return path.normalize(String(p));
};
assert.throws(
() => withInstallFs(fakeFs, () => findInstallSourceRoot(configDir)),
/install or upgrade gsd-core/,
);
});
});
// ─── (b) cleanupStagedSkills must not perform real IO on fake-staged dirs ──
describe('install-profiles cleanupStagedSkills — deferred cleanup does not leak past the restore', () => {

View File

@@ -29,7 +29,7 @@ const os = require('node:os');
const espree = require('espree');
const { splitLines, joinLines } = require('../gsd-core/bin/lib/text-lines.cjs');
const { createTempDir, cleanup } = require('./helpers.cjs');
const { createTempDir, cleanup, writePackageSourceMarkerFixture } = require('./helpers.cjs');
const { runNode } = require('./helpers/process-seam.cjs');
const { INSTALL_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
const {
@@ -172,6 +172,299 @@ describe('installRuntimeArtifacts — consumes Runtime Artifact Install Plan Mod
});
});
describe('installRuntimeArtifacts — durable Runtime Surface corpus (#4132)', () => {
test('#4132: provisioning refuses a gsd-core ancestor symlink that escapes configDir', (t) => {
const root = createTempDir('gsd-corpus-parent-symlink-');
const configDir = path.join(root, 'config');
const outside = path.join(root, 'outside');
fs.mkdirSync(configDir);
fs.mkdirSync(outside);
t.after(() => cleanup(root));
try {
fs.symlinkSync(outside, path.join(configDir, 'gsd-core'), process.platform === 'win32' ? 'junction' : 'dir');
} catch (error) {
t.skip(`directory symlink creation unavailable: ${error.code || error.message}`);
return;
}
assert.throws(
() => installRuntimeArtifacts('codex', configDir, 'global', RESOLVED_CORE),
/symlink|refusing/i,
);
assert.equal(fs.existsSync(path.join(outside, 'commands')), false, 'commands must not escape configDir');
assert.equal(fs.existsSync(path.join(outside, 'agents')), false, 'agents must not escape configDir');
});
test('#4132: provisioning does not follow a compatibility-marker symlink outside configDir', (t) => {
const root = createTempDir('gsd-corpus-marker-symlink-');
const configDir = path.join(root, '.claude');
const outsideMarker = path.join(root, 'outside-marker');
const outsideCheckout = path.join(root, 'outside-checkout');
fs.mkdirSync(configDir);
fs.cpSync(path.join(__dirname, '..', 'commands'), path.join(outsideCheckout, 'commands'), { recursive: true });
fs.cpSync(path.join(__dirname, '..', 'agents'), path.join(outsideCheckout, 'agents'), { recursive: true });
fs.appendFileSync(path.join(outsideCheckout, 'commands', 'gsd', 'help.md'), '\nMARKER_SYMLINK_SOURCE\n');
const outsideMarkerBytes = path.join(outsideCheckout, 'commands', 'gsd') + '\n';
fs.writeFileSync(outsideMarker, outsideMarkerBytes);
t.after(() => cleanup(root));
try {
fs.symlinkSync(outsideMarker, path.join(configDir, '.gsd-source'), 'file');
} catch (error) {
t.skip(`file symlink creation unavailable: ${error.code || error.message}`);
return;
}
runMinimalInstall({ runtime: 'claude', scope: 'global', root });
assert.equal(
fs.readFileSync(outsideMarker, 'utf8'),
outsideMarkerBytes,
'the compatibility marker write must remain confined to configDir',
);
assert.doesNotMatch(
fs.readFileSync(path.join(configDir, 'skills', 'gsd-help', 'SKILL.md'), 'utf8'),
/MARKER_SYMLINK_SOURCE/,
'the installer must not read a source provider through a symlinked marker file',
);
});
test('global Codex owns the canonical commands and agents corpus', (t) => {
const configDir = createTempDir('gsd-codex-surface-corpus-');
t.after(() => cleanup(configDir));
sandboxHome(t, configDir);
installRuntimeArtifacts('codex', configDir, 'global', RESOLVED_CORE);
assert.deepStrictEqual(
snapshot2362Dir(path.join(configDir, 'gsd-core', 'commands', 'gsd')),
snapshot2362Dir(path.join(__dirname, '..', 'commands', 'gsd')),
'installed commands corpus must match the package source tree',
);
assert.deepStrictEqual(
snapshot2362Dir(path.join(configDir, 'gsd-core', 'agents')),
snapshot2362Dir(path.join(__dirname, '..', 'agents')),
'installed agents corpus must match the package source tree',
);
});
test('agents-only and empty layouts derive corpus needs from layout kinds', (t) => {
const windsurfDir = createTempDir('gsd-windsurf-surface-corpus-');
const piDir = createTempDir('gsd-pi-surface-corpus-');
const vscodeDir = createTempDir('gsd-vscode-surface-corpus-');
t.after(() => { cleanup(windsurfDir); cleanup(piDir); cleanup(vscodeDir); });
installRuntimeArtifacts('windsurf', windsurfDir, 'global', RESOLVED_CORE);
assert.ok(fs.existsSync(path.join(windsurfDir, 'gsd-core', 'agents')));
assert.ok(!fs.existsSync(path.join(windsurfDir, 'gsd-core', 'commands', 'gsd')));
installRuntimeArtifacts('pi', piDir, 'global', RESOLVED_CORE);
installRuntimeArtifacts('vscode', vscodeDir, 'global', RESOLVED_CORE);
assert.ok(!fs.existsSync(path.join(piDir, 'gsd-core', 'commands')));
assert.ok(!fs.existsSync(path.join(piDir, 'gsd-core', 'agents')));
assert.ok(!fs.existsSync(path.join(vscodeDir, 'gsd-core', 'commands')));
assert.ok(!fs.existsSync(path.join(vscodeDir, 'gsd-core', 'agents')));
});
test('local Claude and Codex installs do not gain the global corpus', (t) => {
const claudeDir = createTempDir('gsd-claude-local-no-corpus-');
const codexDir = createTempDir('gsd-codex-local-no-corpus-');
t.after(() => { cleanup(claudeDir); cleanup(codexDir); });
installRuntimeArtifacts('claude', claudeDir, 'local', RESOLVED_CORE);
installRuntimeArtifacts('codex', codexDir, 'local', RESOLVED_CORE);
for (const configDir of [claudeDir, codexDir]) {
assert.ok(!fs.existsSync(path.join(configDir, 'gsd-core', 'commands')));
assert.ok(!fs.existsSync(path.join(configDir, 'gsd-core', 'agents')));
}
});
test('refresh restores canonical bytes and removes only manifest-proven stale corpus files', (t) => {
const configDir = createTempDir('gsd-corpus-refresh-');
t.after(() => cleanup(configDir));
sandboxHome(t, configDir);
installRuntimeArtifacts('codex', configDir, 'global', RESOLVED_CORE);
const commandsDir = path.join(configDir, 'gsd-core', 'commands', 'gsd');
const canonicalName = fs.readdirSync(commandsDir).find((name) => name.endsWith('.md'));
assert.ok(canonicalName);
fs.writeFileSync(path.join(commandsDir, canonicalName), '# corrupted\n');
fs.writeFileSync(path.join(commandsDir, 'stale-owned.md'), '# stale\n');
fs.writeFileSync(path.join(commandsDir, 'unknown-neighbour.md'), '# preserve\n');
fs.writeFileSync(path.join(configDir, 'gsd-file-manifest.json'), JSON.stringify({
files: { 'gsd-core/commands/gsd/stale-owned.md': '0'.repeat(64) },
}));
installRuntimeArtifacts('codex', configDir, 'global', RESOLVED_CORE);
assert.strictEqual(
fs.readFileSync(path.join(commandsDir, canonicalName), 'utf8'),
fs.readFileSync(path.join(__dirname, '..', 'commands', 'gsd', canonicalName), 'utf8'),
);
assert.ok(!fs.existsSync(path.join(commandsDir, 'stale-owned.md')));
assert.strictEqual(fs.readFileSync(path.join(commandsDir, 'unknown-neighbour.md'), 'utf8'), '# preserve\n');
});
test('a partial corpus copy failure is rejected until a later install repairs it', (t) => {
const configDir = createTempDir('gsd-corpus-copy-failure-');
t.after(() => cleanup(configDir));
sandboxHome(t, configDir);
const agentsDestination = path.join(configDir, 'gsd-core', 'agents');
const originalCpSync = fs.cpSync;
t.mock.method(fs, 'cpSync', (source, destination, options) => {
if (destination === agentsDestination) {
fs.mkdirSync(destination, { recursive: true });
fs.writeFileSync(path.join(destination, 'gsd-planner.md'), '# partial agent\n');
throw new Error('injected corpus copy failure');
}
return originalCpSync(source, destination, options);
});
assert.throws(
() => installRuntimeArtifacts('codex', configDir, 'global', RESOLVED_CORE),
/injected corpus copy failure/,
);
const incompleteLayout = resolveRuntimeArtifactLayout('codex', configDir, 'global');
assert.throws(
() => incompleteLayout.kinds.find((kind) => kind.kind === 'skills').stage(RESOLVED_CORE),
/install or upgrade gsd-core/,
);
t.mock.restoreAll();
installRuntimeArtifacts('codex', configDir, 'global', RESOLVED_CORE);
assert.deepStrictEqual(
snapshot2362Dir(agentsDestination),
snapshot2362Dir(path.join(__dirname, '..', 'agents')),
'a later install must heal the partial agents corpus',
);
});
test('an unreadable prior manifest preserves unproven neighbours while refreshing canonical bytes', (t) => {
const configDir = createTempDir('gsd-corpus-manifest-read-failure-');
t.after(() => cleanup(configDir));
sandboxHome(t, configDir);
const commandsDir = path.join(configDir, 'gsd-core', 'commands', 'gsd');
fs.mkdirSync(commandsDir, { recursive: true });
const canonicalName = fs.readdirSync(path.join(__dirname, '..', 'commands', 'gsd'))
.find((name) => name.endsWith('.md'));
assert.ok(canonicalName);
fs.writeFileSync(path.join(commandsDir, canonicalName), '# corrupted\n');
fs.writeFileSync(path.join(commandsDir, 'unproven-neighbour.md'), '# preserve\n');
const manifestPath = path.join(configDir, 'gsd-file-manifest.json');
fs.writeFileSync(manifestPath, JSON.stringify({ files: {
'gsd-core/commands/gsd/unproven-neighbour.md': '0'.repeat(64),
} }));
const originalReadFileSync = fs.readFileSync;
t.mock.method(fs, 'readFileSync', (filePath, ...args) => {
if (filePath === manifestPath) throw new Error('injected manifest read failure');
return originalReadFileSync(filePath, ...args);
});
installRuntimeArtifacts('codex', configDir, 'global', RESOLVED_CORE);
assert.equal(
fs.readFileSync(path.join(commandsDir, canonicalName), 'utf8'),
fs.readFileSync(path.join(__dirname, '..', 'commands', 'gsd', canonicalName), 'utf8'),
);
assert.equal(
fs.readFileSync(path.join(commandsDir, 'unproven-neighbour.md'), 'utf8'),
'# preserve\n',
'an unreadable manifest provides no ownership proof for deletion',
);
});
test('a stale corpus removal failure leaves a resolver-rejected corpus', (t) => {
const configDir = createTempDir('gsd-corpus-remove-failure-');
t.after(() => cleanup(configDir));
sandboxHome(t, configDir);
const commandsDir = path.join(configDir, 'gsd-core', 'commands', 'gsd');
const agentsDir = path.join(configDir, 'gsd-core', 'agents');
fs.mkdirSync(commandsDir, { recursive: true });
fs.mkdirSync(agentsDir, { recursive: true });
const stalePath = path.join(commandsDir, 'removed-by-4132-test.md');
fs.writeFileSync(stalePath, '# stale\n');
fs.writeFileSync(path.join(agentsDir, 'gsd-planner.md'), '# stale agent\n');
const manifestPath = path.join(configDir, 'gsd-file-manifest.json');
const manifestBytes = JSON.stringify({ files: {
'gsd-core/commands/gsd/removed-by-4132-test.md': '0'.repeat(64),
'gsd-core/agents/gsd-planner.md': '0'.repeat(64),
} });
fs.writeFileSync(manifestPath, manifestBytes);
const originalRmSync = fs.rmSync;
t.mock.method(fs, 'rmSync', (target, options) => {
if (target === stalePath) throw new Error('injected stale corpus removal failure');
// eslint-disable-next-line local/no-raw-rmsync-in-tests -- delegate non-target production writes; fixture cleanup still uses cleanup().
return originalRmSync(target, options);
});
assert.throws(
() => installRuntimeArtifacts('codex', configDir, 'global', RESOLVED_CORE),
/injected stale corpus removal failure/,
);
assert.equal(fs.readFileSync(manifestPath, 'utf8'), manifestBytes, 'failed provisioning must not claim a new manifest');
const incompleteLayout = resolveRuntimeArtifactLayout('codex', configDir, 'global');
assert.throws(
() => incompleteLayout.kinds.find((kind) => kind.kind === 'skills').stage(RESOLVED_CORE),
/install or upgrade gsd-core/,
);
});
test('an empty-parent prune failure leaves a resolver-rejected corpus', (t) => {
const configDir = createTempDir('gsd-corpus-prune-failure-');
t.after(() => cleanup(configDir));
sandboxHome(t, configDir);
const commandsDir = path.join(configDir, 'gsd-core', 'commands', 'gsd');
const agentsDir = path.join(configDir, 'gsd-core', 'agents');
const staleParent = path.join(commandsDir, 'retired');
const stalePath = path.join(staleParent, 'removed-by-4132-test.md');
fs.mkdirSync(staleParent, { recursive: true });
fs.mkdirSync(agentsDir, { recursive: true });
fs.writeFileSync(stalePath, '# stale\n');
fs.writeFileSync(path.join(agentsDir, 'gsd-planner.md'), '# stale agent\n');
const manifestPath = path.join(configDir, 'gsd-file-manifest.json');
const manifestBytes = JSON.stringify({ files: {
'gsd-core/commands/gsd/retired/removed-by-4132-test.md': '0'.repeat(64),
'gsd-core/agents/gsd-planner.md': '0'.repeat(64),
} });
fs.writeFileSync(manifestPath, manifestBytes);
const originalRmdirSync = fs.rmdirSync;
t.mock.method(fs, 'rmdirSync', (target, options) => {
if (target === staleParent) throw new Error('injected corpus parent prune failure');
return originalRmdirSync(target, options);
});
assert.throws(
() => installRuntimeArtifacts('codex', configDir, 'global', RESOLVED_CORE),
/injected corpus parent prune failure/,
);
assert.equal(fs.existsSync(stalePath), false, 'owned stale file was removed before parent pruning failed');
assert.equal(fs.existsSync(staleParent), true, 'failed empty parent removal must leave the directory in place');
assert.equal(fs.readFileSync(manifestPath, 'utf8'), manifestBytes, 'failed provisioning must not claim a new manifest');
const incompleteLayout = resolveRuntimeArtifactLayout('codex', configDir, 'global');
assert.throws(
() => incompleteLayout.kinds.find((kind) => kind.kind === 'skills').stage(RESOLVED_CORE),
/install or upgrade gsd-core/,
);
});
for (const runtime of ['codex', 'claude']) {
test(`full global ${runtime} manifest covers every installed corpus file with its hash`, (t) => {
const installed = runMinimalInstall({ runtime, scope: 'global' });
t.after(() => cleanup(installed.root));
const corpusRoots = [
['gsd-core/commands/gsd/', path.join(installed.configDir, 'gsd-core', 'commands', 'gsd')],
['gsd-core/agents/', path.join(installed.configDir, 'gsd-core', 'agents')],
];
for (const [prefix, root] of corpusRoots) {
for (const file of walk(root)) {
const key = prefix + path.relative(root, file).replace(/\\/g, '/');
const hash = crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
assert.strictEqual(installed.manifest.files[key], hash, `${key} must be manifest-owned with the installed hash`);
}
}
});
}
});
const SKILLS_RUNTIMES_LAYOUT = [
'claude', 'cursor', 'codex', 'copilot', 'antigravity',
'augment', 'trae', 'qwen', 'kimi', 'codebuddy',
@@ -415,6 +708,7 @@ describe('installOpencodeFamilySkills — emits skills/<name>/SKILL.md (#784)',
test(`${runtime}: writes gsd-help/SKILL.md with name + description`, (t) => {
const configDir = createTempDir(`gsd-ocs-${runtime}-`);
t.after(() => cleanup(configDir));
writePackageSourceMarkerFixture(configDir);
const raw = stageRawCommands(runtime, configDir);
const count = installOpencodeFamilySkills(runtime, configDir, raw, `${configDir}/`);
@@ -431,6 +725,7 @@ describe('installOpencodeFamilySkills — emits skills/<name>/SKILL.md (#784)',
test(`${runtime}: rewrites body paths to the actual install target (#784 path fix)`, (t) => {
const configDir = createTempDir(`gsd-ocp-${runtime}-`);
t.after(() => cleanup(configDir));
writePackageSourceMarkerFixture(configDir);
// Simulate a custom/local install: pathPrefix points at configDir, NOT the
// runtime's default global config dir. Body refs must use pathPrefix.
@@ -461,6 +756,7 @@ describe('installOpencodeFamilySkills — emits skills/<name>/SKILL.md (#784)',
test(`${runtime}: preserves user-owned gsd-dev-preferences across reinstall (#784)`, (t) => {
const configDir = createTempDir(`gsd-ocd-${runtime}-`);
t.after(() => cleanup(configDir));
writePackageSourceMarkerFixture(configDir);
const userSkill = path.join(configDir, 'skills', 'gsd-dev-preferences');
fs.mkdirSync(userSkill, { recursive: true });
@@ -2656,6 +2952,7 @@ describe('fix-2644 — Cursor has one menu entry per GSD workflow', () => {
version: '1.8.0', timestamp: '2026-07-28T00:00:00.000Z', mode: 'core',
files: { 'commands/gsd-help.md': crypto.createHash('sha256').update(content).digest('hex') },
}));
writePackageSourceMarkerFixture(configDir);
const layout = resolveRuntimeArtifactLayout('cursor', configDir, 'global');
applySurface(configDir, layout, MANIFEST);
@@ -5582,7 +5879,13 @@ const {
*/
function writeMinimalSourceTree(baseDir, stems) {
const srcDir = path.join(baseDir, 'src', 'commands', 'gsd');
const agentsDir = path.join(baseDir, 'src', 'agents');
fs.mkdirSync(srcDir, { recursive: true });
fs.mkdirSync(agentsDir, { recursive: true });
// Hermes resolves one complete provider for its skills+agents layout. Keep
// this legacy-marker fixture complete so it exercises marker compatibility
// without relying on forbidden per-kind provider mixing (#4132).
fs.writeFileSync(path.join(agentsDir, 'gsd-test-agent.md'), '# test agent\n');
for (const stem of stems) {
fs.writeFileSync(path.join(srcDir, `${stem}.md`), [
'---',
@@ -7583,6 +7886,11 @@ describe('#3719: real global Claude install — agents/*.md @-refs must resolve
const failures = [];
for (const file of walk(rootDir)) {
if (!file.endsWith('.md')) continue;
const relative = path.relative(claudeGlobal.configDir, file).replace(/\\/g, '/');
// The installation-owned Runtime Surface corpus is raw package input,
// not an emitted runtime artifact. It must remain byte-identical to the
// package and is validated separately by the corpus parity matrix.
if (relative.startsWith('gsd-core/commands/gsd/') || relative.startsWith('gsd-core/agents/')) continue;
const content = fs.readFileSync(file, 'utf8');
for (const line of splitLines(content)) {
if (/@\$HOME\//.test(line.replace(INLINE_CODE_SPAN_RE, ''))) failures.push({ file, line });

View File

@@ -738,6 +738,13 @@ describe('#3544: spawned installer — gsd-core/ spec tree @-refs resolve on til
const walk = (dir) => {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
const rel = path.relative(rootDir, full);
const topLevel = rel.split(path.sep)[0];
// The durable Runtime Surface corpus is intentionally raw canonical
// input, not an emitted/runtime-rewritten spec tree. Its paths are
// validated when staged, so exclude only these two known corpus roots
// from this legacy emitted-content oracle.
if (topLevel === 'commands' || topLevel === 'agents') continue;
if (entry.isDirectory()) walk(full);
else if (entry.name.endsWith('.md')) {
const content = fs.readFileSync(full, 'utf8');

View File

@@ -136,6 +136,12 @@ describe('Qwen Code: installRuntimeArtifacts', () => {
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-qwen-test-'));
// Qwen's global layout consumes commands and agents from one provider.
// Keep this legacy-marker fixture complete even though these assertions
// exercise only the command-to-skill half of the install.
const agentsDir = path.join(tmpDir, 'src', 'agents');
fs.mkdirSync(agentsDir, { recursive: true });
fs.writeFileSync(path.join(agentsDir, 'fixture-agent.md'), '# Fixture agent\n');
});
afterEach(() => {

View File

@@ -11,6 +11,8 @@ const { describe, test, before, after } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const crypto = require('node:crypto');
const { spawnSync } = require('node:child_process');
const { cleanup, createTempDir, runNpm, isolatedNpmEnv } = require('./helpers.cjs');
const { SMOKE, runSmoke, CHILD_TIMEOUT_MS } = require('../scripts/release-tarball-smoke.cjs');
@@ -21,6 +23,31 @@ const smokeMsg = (label, result) =>
const PKG_PATH = path.join(__dirname, '..', 'package.json');
const pkg = JSON.parse(fs.readFileSync(PKG_PATH, 'utf-8'));
function installedPackageRoot(prefix) {
const parts = pkg.name.split('/');
const posix = path.join(prefix, 'lib', 'node_modules', ...parts);
const windows = path.join(prefix, 'node_modules', ...parts);
return fs.existsSync(posix) ? posix : windows;
}
function hashTree(root) {
const result = new Map();
const visit = (dir) => {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const absolute = path.join(dir, entry.name);
if (entry.isDirectory()) visit(absolute);
else if (entry.isFile()) {
result.set(
path.relative(root, absolute).replace(/\\/g, '/'),
crypto.createHash('sha256').update(fs.readFileSync(absolute)).digest('hex'),
);
}
}
};
visit(root);
return result;
}
// ─── runSmoke install timeout must clear a slow-host cold install (#2335) ────
// Regression: runSmoke()'s internal `npm install -g` used CHILD_TIMEOUT_MS,
// which was 120 s on non-Windows while before()'s pack+install used 600 s. A
@@ -207,6 +234,208 @@ describe('release-tarball-smoke', () => {
smokeMsg('E', result),
);
});
test('F: packed package carries the complete canonical Runtime Surface corpus', () => {
const packageRoot = installedPackageRoot(installPrefix);
assert.deepStrictEqual(
hashTree(path.join(packageRoot, 'commands', 'gsd')),
hashTree(path.join(__dirname, '..', 'commands', 'gsd')),
);
assert.deepStrictEqual(
hashTree(path.join(packageRoot, 'agents')),
hashTree(path.join(__dirname, '..', 'agents')),
);
});
test('G: deployed Codex and Claude modules materially change a surface after package source is unreachable', (t) => {
const runtimeRoot = createTempDir('gsd-smoke-offline-runtime-');
const packageRoot = installedPackageRoot(installPrefix);
const hiddenPackageRoot = `${packageRoot}.offline-${process.pid}`;
t.after(() => {
if (fs.existsSync(hiddenPackageRoot) && !fs.existsSync(packageRoot)) fs.renameSync(hiddenPackageRoot, packageRoot);
cleanup(runtimeRoot);
});
const installs = [];
for (const runtime of ['codex', 'claude']) {
const configDir = path.join(runtimeRoot, `.${runtime}`);
const result = spawnSync(process.execPath, [
path.join(packageRoot, 'bin', 'install.js'),
`--${runtime}`,
'--global',
'--config-dir',
configDir,
], {
cwd: runtimeRoot,
env: {
...process.env,
...isolatedNpmEnv(),
HOME: runtimeRoot,
USERPROFILE: runtimeRoot,
GSD_TEST_MODE: '',
NO_UPDATE_NOTIFIER: '1',
npm_config_update_notifier: 'false',
},
encoding: 'utf8',
timeout: CHILD_TIMEOUT_MS,
});
assert.equal(result.status, 0, `${runtime} packed install failed:\n${result.stdout}\n${result.stderr}`);
installs.push({ runtime, configDir });
}
// Synthetic untouched 1.12-style deployed tree: converted outputs and a
// hash manifest exist, but the raw corpus/marker do not. It must not use
// those outputs as source when the executing package disappears.
const legacyConfigDir = path.join(runtimeRoot, '.legacy-codex');
fs.cpSync(installs.find((entry) => entry.runtime === 'codex').configDir, legacyConfigDir, { recursive: true });
cleanup(path.join(legacyConfigDir, 'gsd-core', 'commands'));
cleanup(path.join(legacyConfigDir, 'gsd-core', 'agents'));
const legacyMarker = path.join(legacyConfigDir, '.gsd-source');
if (fs.existsSync(legacyMarker)) fs.unlinkSync(legacyMarker);
// S04: upgrade a synthetic source-less legacy tree while the fixed
// package is available. Preserve its exact committed selection and an
// unrelated file, converge artifacts to that selection, and later prove
// an offline expansion works from the provisioned corpus alone.
const upgradedHome = path.join(runtimeRoot, 'legacy-codex-upgrade-home');
const upgradeCwd = path.join(runtimeRoot, 'legacy-codex-upgrade-worktree');
const upgradedConfigDir = path.join(upgradedHome, '.codex');
fs.mkdirSync(upgradeCwd, { recursive: true });
fs.cpSync(installs.find((entry) => entry.runtime === 'codex').configDir, upgradedConfigDir, { recursive: true });
fs.cpSync(path.join(runtimeRoot, '.agents', 'skills'), path.join(upgradedHome, '.agents', 'skills'), { recursive: true });
fs.mkdirSync(path.join(upgradedHome, '.agents', 'skills', 'user-owned-skill'), { recursive: true });
fs.writeFileSync(path.join(upgradedHome, '.agents', 'skills', 'user-owned-skill', 'SKILL.md'), '# preserve me\n');
cleanup(path.join(upgradedConfigDir, 'gsd-core', 'commands'));
cleanup(path.join(upgradedConfigDir, 'gsd-core', 'agents'));
const upgradedMarker = path.join(upgradedConfigDir, '.gsd-source');
if (fs.existsSync(upgradedMarker)) fs.unlinkSync(upgradedMarker);
const selectedState = JSON.stringify({ baseProfile: 'core', disabledClusters: [], explicitAdds: [], explicitRemoves: [] }, null, 2) + '\n';
const priorGates = JSON.stringify({ workflow: { code_review: false, research: true } }, null, 2) + '\n';
fs.writeFileSync(path.join(upgradedConfigDir, '.gsd-surface.json'), selectedState);
fs.writeFileSync(path.join(upgradedConfigDir, 'user-owned.txt'), 'preserve me\n');
fs.mkdirSync(path.join(upgradeCwd, '.planning'), { recursive: true });
fs.writeFileSync(path.join(upgradeCwd, '.planning', 'config.json'), priorGates);
const upgradeResult = spawnSync(process.execPath, [
path.join(packageRoot, 'bin', 'install.js'),
'--codex',
'--global',
'--config-dir',
upgradedConfigDir,
], {
cwd: upgradeCwd,
env: {
...process.env,
...isolatedNpmEnv(),
HOME: upgradedHome,
USERPROFILE: upgradedHome,
GSD_TEST_MODE: '',
NO_UPDATE_NOTIFIER: '1',
npm_config_update_notifier: 'false',
},
encoding: 'utf8',
timeout: CHILD_TIMEOUT_MS,
});
assert.equal(upgradeResult.status, 0, `legacy upgrade failed:\n${upgradeResult.stdout}\n${upgradeResult.stderr}`);
assert.equal(fs.readFileSync(path.join(upgradedConfigDir, '.gsd-surface.json'), 'utf8'), selectedState);
assert.equal(fs.readFileSync(path.join(upgradedConfigDir, 'user-owned.txt'), 'utf8'), 'preserve me\n');
assert.equal(fs.readFileSync(path.join(upgradeCwd, '.planning', 'config.json'), 'utf8'), priorGates);
assert.deepStrictEqual(
hashTree(path.join(upgradedConfigDir, 'gsd-core', 'commands', 'gsd')),
hashTree(path.join(packageRoot, 'commands', 'gsd')),
);
assert.deepStrictEqual(
hashTree(path.join(upgradedConfigDir, 'gsd-core', 'agents')),
hashTree(path.join(packageRoot, 'agents')),
);
const upgradedSkillRoot = path.join(upgradedHome, '.agents', 'skills');
const upgradedSkillCount = fs.readdirSync(upgradedSkillRoot).filter((name) => name.startsWith('gsd-')).length;
assert.ok(upgradedSkillCount > 0 && upgradedSkillCount < 71, `upgrade must converge the selected core surface, got ${upgradedSkillCount}`);
assert.equal(fs.readFileSync(path.join(upgradedSkillRoot, 'user-owned-skill', 'SKILL.md'), 'utf8'), '# preserve me\n');
fs.renameSync(packageRoot, hiddenPackageRoot);
const upgradedOfflineScript = [
"const fs=require('node:fs'),path=require('node:path');",
`const configDir=${JSON.stringify(upgradedConfigDir)};`,
"const lib=path.join(configDir,'gsd-core','bin','lib');",
"const surface=require(path.join(lib,'surface.cjs'));",
"const layoutModule=require(path.join(lib,'runtime-artifact-layout.cjs'));",
"const profiles=require(path.join(lib,'install-profiles.cjs'));",
"const clusters=require(path.join(lib,'clusters.cjs'));",
"const manifest=profiles.loadSkillsManifest(path.join(configDir,'gsd-core','commands','gsd'));",
"const layout=layoutModule.resolveRuntimeArtifactLayout('codex',configDir,'global');",
"const skillKind=layout.kinds.find(kind=>kind.kind==='skills');",
"const skillRoot=path.join(skillKind.home||configDir,skillKind.destSubpath);",
"const before=fs.readdirSync(skillRoot).filter(n=>n.startsWith('gsd-')).length;",
"surface.applySurface(configDir,layout,manifest,clusters.CLUSTERS,undefined,{surfaceState:{baseProfile:'full',disabledClusters:[],explicitAdds:[],explicitRemoves:[]}});",
"const after=fs.readdirSync(skillRoot).filter(n=>n.startsWith('gsd-')).length;",
"if(!(after>before))throw new Error(`offline upgraded expansion failed: ${before} -> ${after}`);",
].join('');
const upgradedOfflineResult = spawnSync(process.execPath, ['-e', upgradedOfflineScript], {
cwd: runtimeRoot,
env: { ...process.env, HOME: upgradedHome, USERPROFILE: upgradedHome, GSD_TEST_MODE: '' },
encoding: 'utf8',
timeout: CHILD_TIMEOUT_MS,
});
assert.equal(upgradedOfflineResult.status, 0, `upgraded offline surface failed:\n${upgradedOfflineResult.stdout}\n${upgradedOfflineResult.stderr}`);
const legacyChildScript = [
"const fs=require('node:fs'),path=require('node:path');",
`const configDir=${JSON.stringify(legacyConfigDir)};`,
"const lib=path.join(configDir,'gsd-core','bin','lib');",
"const surface=require(path.join(lib,'surface.cjs'));",
"const layoutModule=require(path.join(lib,'runtime-artifact-layout.cjs'));",
"const profiles=require(path.join(lib,'install-profiles.cjs'));",
"const clusters=require(path.join(lib,'clusters.cjs'));",
"const surfacePath=path.join(configDir,'.gsd-surface.json');",
"const agentPath=path.join(configDir,'agents','gsd-planner.md');",
"const beforeSurface=fs.existsSync(surfacePath)?fs.readFileSync(surfacePath):null;",
"const beforeAgent=fs.readFileSync(agentPath);",
"const layout=layoutModule.resolveRuntimeArtifactLayout('codex',configDir,'global');",
"let error=null;try{surface.applySurface(configDir,layout,new Map(),clusters.CLUSTERS,undefined,{surfaceState:{baseProfile:'core',disabledClusters:[],explicitAdds:[],explicitRemoves:[]}})}catch(value){error=value}",
"if(!error||!/install or upgrade gsd-core/.test(error.message))throw new Error(`expected actionable source failure, got ${error&&error.message}`);",
"const afterSurface=fs.existsSync(surfacePath)?fs.readFileSync(surfacePath):null;",
"if(!Buffer.isBuffer(beforeAgent)||!beforeAgent.equals(fs.readFileSync(agentPath)))throw new Error('legacy output changed');",
"if(beforeSurface===null?afterSurface!==null:!beforeSurface.equals(afterSurface))throw new Error('legacy surface state changed');",
].join('');
const legacyResult = spawnSync(process.execPath, ['-e', legacyChildScript], {
cwd: runtimeRoot,
env: { ...process.env, HOME: runtimeRoot, USERPROFILE: runtimeRoot, GSD_TEST_MODE: '' },
encoding: 'utf8',
timeout: CHILD_TIMEOUT_MS,
});
assert.equal(legacyResult.status, 0, `legacy source-less refusal failed:\n${legacyResult.stdout}\n${legacyResult.stderr}`);
for (const { runtime, configDir } of installs) {
const childScript = [
"const path=require('node:path');",
`const configDir=${JSON.stringify(configDir)};`,
`const runtime=${JSON.stringify(runtime)};`,
"const lib=path.join(configDir,'gsd-core','bin','lib');",
"const surface=require(path.join(lib,'surface.cjs'));",
"const layoutModule=require(path.join(lib,'runtime-artifact-layout.cjs'));",
"const profiles=require(path.join(lib,'install-profiles.cjs'));",
"const clusters=require(path.join(lib,'clusters.cjs'));",
"const corpus=path.join(configDir,'gsd-core','commands','gsd');",
"const manifest=profiles.loadSkillsManifest(corpus);",
"const layout=layoutModule.resolveRuntimeArtifactLayout(runtime,configDir,'global');",
"const before=layout.kinds.map(k=>{const root=path.join(k.home||configDir,k.destSubpath);try{return require('node:fs').readdirSync(root).length}catch{return 0}}).reduce((a,b)=>a+b,0);",
"const state={baseProfile:'core',disabledClusters:[],explicitAdds:[],explicitRemoves:[]};",
"surface.applySurface(configDir,layout,manifest,clusters.CLUSTERS,undefined,{surfaceState:state});",
"const after=layout.kinds.map(k=>{const root=path.join(k.home||configDir,k.destSubpath);try{return require('node:fs').readdirSync(root).length}catch{return 0}}).reduce((a,b)=>a+b,0);",
"if(!(after>0&&after<before))throw new Error(`surface did not materially shrink: ${before} -> ${after}`);",
"process.stdout.write(JSON.stringify({before,after}));",
].join('');
const result = spawnSync(process.execPath, ['-e', childScript], {
cwd: runtimeRoot,
env: { ...process.env, HOME: runtimeRoot, USERPROFILE: runtimeRoot, GSD_TEST_MODE: '' },
encoding: 'utf8',
timeout: CHILD_TIMEOUT_MS,
});
assert.equal(result.status, 0, `${runtime} offline materialization failed:\n${result.stdout}\n${result.stderr}`);
const counts = JSON.parse(result.stdout);
assert.ok(counts.after > 0 && counts.after < counts.before);
}
});
});

View File

@@ -38,7 +38,8 @@ const {
capabilityClusterStems,
CAPABILITY_SKILL_MARKER,
} = require('../gsd-core/bin/lib/install-profiles.cjs');
const { createTempDir, cleanup } = require('./helpers.cjs');
const { createTempDir, cleanup, writePackageSourceMarkerFixture } = require('./helpers.cjs');
const { resolveRuntimeArtifactLayout: resolveLayout } = require('../gsd-core/bin/lib/runtime-artifact-layout.cjs');
const REAL_COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
const REAL_AGENTS_DIR = path.join(__dirname, '..', 'agents');
@@ -738,6 +739,7 @@ function createFixture() {
const configDir = createTempDir('gsd-bug3659-');
const skillsDir = path.join(configDir, 'skills');
fs.mkdirSync(skillsDir, { recursive: true });
fs.writeFileSync(path.join(configDir, '.gsd-source'), REAL_COMMANDS_DIR + '\n');
const gsdExplore = path.join(skillsDir, 'gsd-explore');
const gsdHelp = path.join(skillsDir, 'gsd-help');
@@ -953,7 +955,7 @@ describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disab
const { describe: __issueDescribe, test: __issueTest } = require('node:test');
const surfaceMod = require('../gsd-core/bin/lib/surface.cjs');
const { writeSurface: __writeSurface, applySurface: __applySurface } = surfaceMod;
const { resolveRuntimeArtifactLayout: __resolveRuntimeArtifactLayout } = require('../gsd-core/bin/lib/runtime-artifact-layout.cjs');
const __resolveRuntimeArtifactLayout = resolveLayout;
/** Install a fake already-installed third-party capability skill under a sandboxed GSD_HOME. */
function __installCapSkill(gsdHome, capId, stem, content) {
@@ -1005,7 +1007,7 @@ describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disab
__issueDescribe('issue-2322: applySurface materializes installed third-party capability skills', () => {
__issueTest('(1) primary: installed capability skill materializes at <prefix><stem>/SKILL.md and IS subject to the same runtime body rewrites as first-party content', () => {
const gsdHome = createTempDir('gsd-2322-home-');
const configDir = createTempDir('gsd-2322-cfg-');
const configDir = writePackageSourceMarkerFixture(createTempDir('gsd-2322-cfg-'));
const savedHome = process.env.GSD_HOME;
try {
// #2322 MEDIUM-4: a fixture with NO rewrite-triggering content passes
@@ -1048,7 +1050,7 @@ describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disab
__issueTest('(2) collision: a first-party stem always wins over a same-named third-party capability skill', () => {
const gsdHome = createTempDir('gsd-2322-home-');
const configDir = createTempDir('gsd-2322-cfg-');
const configDir = writePackageSourceMarkerFixture(createTempDir('gsd-2322-cfg-'));
const savedHome = process.env.GSD_HOME;
try {
const EVIL = '---\nname: phase\n---\n\n# EVIL PHASE — must never win over the first-party gsd-phase skill\n';
@@ -1094,7 +1096,7 @@ describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disab
__issueTest('(3) profile filter: a third-party skill outside the resolved profile is not staged; sibling first-party skills are unaffected', () => {
const gsdHome = createTempDir('gsd-2322-home-');
const configDir = createTempDir('gsd-2322-cfg-');
const configDir = writePackageSourceMarkerFixture(createTempDir('gsd-2322-cfg-'));
const savedHome = process.env.GSD_HOME;
try {
__installCapSkill(gsdHome, 'my-thing', 'my-thing', '# my-thing\n');
@@ -1129,7 +1131,7 @@ describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disab
__issueTest('(4) control: a nested-router (doNest) runtime layout is unperturbed by an installed capability skill', () => {
const gsdHome = createTempDir('gsd-2322-home-');
const configDir = createTempDir('gsd-2322-cfg-');
const configDir = writePackageSourceMarkerFixture(createTempDir('gsd-2322-cfg-'));
const savedHome = process.env.GSD_HOME;
try {
__installCapSkill(gsdHome, 'my-thing', 'my-thing', '# my-thing\n');
@@ -1170,8 +1172,8 @@ describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disab
__issueTest('(5) absent/malformed: a registry-referenced capability skill missing on disk must not throw and must not affect first-party output', () => {
const gsdHome = createTempDir('gsd-2322-home-');
const configDirGhost = createTempDir('gsd-2322-cfg-ghost-');
const configDirPartial = createTempDir('gsd-2322-cfg-partial-');
const configDirGhost = writePackageSourceMarkerFixture(createTempDir('gsd-2322-cfg-ghost-'));
const configDirPartial = writePackageSourceMarkerFixture(createTempDir('gsd-2322-cfg-partial-'));
const savedHome = process.env.GSD_HOME;
try {
// Partial case: the capability dir exists but the declared stem's
@@ -1215,7 +1217,7 @@ describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disab
__issueDescribe('issue-2322 BLOCKER 1: capability skill stem hijack via an undeclared/unregistered directory', () => {
__issueTest('an UNDECLARED skills/<stem>/ directory shipped by one capability must never supply another capability\'s declared+registered stem', () => {
const gsdHome = createTempDir('gsd-2322-home-');
const configDir = createTempDir('gsd-2322-cfg-');
const configDir = writePackageSourceMarkerFixture(createTempDir('gsd-2322-cfg-'));
const savedHome = process.env.GSD_HOME;
try {
const EVIL = '---\nname: deploy\n---\n\n# EVIL deploy — planted by aaa-utils, which never declared this skill\n';
@@ -1282,7 +1284,7 @@ describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disab
__issueDescribe('issue-2322 BLOCKER 2: mode=full (the "*" sentinel) must still stage registered third-party capability skills', () => {
__issueTest('resolveProfile({modes:["full"]})\'s "*" sentinel, passed straight to stageSkillsForRuntimeAsSkills, still materializes a registered capability skill', () => {
const gsdHome = createTempDir('gsd-2322-home-');
const configDir = createTempDir('gsd-2322-cfg-');
const configDir = writePackageSourceMarkerFixture(createTempDir('gsd-2322-cfg-'));
const savedHome = process.env.GSD_HOME;
let unitStaged;
let e2eStaged;
@@ -1354,7 +1356,7 @@ describe('bug-3659: applySurface prunes ~/.claude/skills/gsd-*/ on cluster disab
__issueDescribe('issue-2322 HIGH-3: an orphaned (uninstalled/unsurfaced) capability skill is pruned; a genuinely unknown gsd-* dir is still preserved', () => {
__issueTest('uninstalling the capability + re-applying removes its staged skill; an unrelated hand-made gsd-* dir survives with a warning', () => {
const gsdHome = createTempDir('gsd-2322-home-');
const configDir = createTempDir('gsd-2322-cfg-');
const configDir = writePackageSourceMarkerFixture(createTempDir('gsd-2322-cfg-'));
const savedHome = process.env.GSD_HOME;
try {
__installCapSkill(gsdHome, 'my-thing', 'my-thing', '# my-thing\n');
@@ -1521,7 +1523,7 @@ const {
resolveProfile,
} = require('../gsd-core/bin/lib/install-profiles.cjs');
const { applySurface } = require('../gsd-core/bin/lib/surface.cjs');
const { resolveRuntimeArtifactLayout } = require('../gsd-core/bin/lib/runtime-artifact-layout.cjs');
const resolveRuntimeArtifactLayout = resolveLayout;
const MANIFEST = loadSkillsManifest(COMMANDS_GSD);
const RESOLVED_FULL = resolveProfile({ modes: ['full'], manifest: MANIFEST });
@@ -1627,6 +1629,7 @@ describe('bug-924: applySurface on claude preserves flat layout (no re-nesting)'
before(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-924-surface-'));
installRuntimeArtifacts('claude', tmpDir, 'global', RESOLVED_FULL);
writePackageSourceMarkerFixture(tmpDir);
});
after(() => {

View File

@@ -16,7 +16,8 @@ const { writeSurface, readSurface, resolveSurface, listSurface, applySurface } =
const { loadSkillsManifest, writeActiveProfile, resolveProfile } = require('../gsd-core/bin/lib/install-profiles.cjs');
const { resolveRuntimeArtifactLayout } = require('../gsd-core/bin/lib/runtime-artifact-layout.cjs');
const { CLUSTERS, allClusteredSkills } = require('../gsd-core/bin/lib/clusters.cjs');
const { createTempDir, cleanup, sandboxHome } = require('./helpers.cjs');
const { createTempDir, cleanup, sandboxHome, writePackageSourceMarkerFixture } = require('./helpers.cjs');
const { runMinimalInstall } = require('./helpers/install-shared.cjs');
const REAL_COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
@@ -34,6 +35,7 @@ function createFixtureRuntime() {
const agentsDir = path.join(runtimeConfigDir, 'agents');
fs.mkdirSync(commandsDir, { recursive: true });
fs.mkdirSync(agentsDir, { recursive: true });
fs.writeFileSync(path.join(runtimeConfigDir, '.gsd-source'), REAL_COMMANDS_DIR + '\n');
return { base, runtimeConfigDir, commandsDir, agentsDir };
}
@@ -56,9 +58,68 @@ function readFrontmatterDescription(markdown) {
return '';
}
function surfaceBytesForTest(state) {
return JSON.stringify(state, null, 2) + '\n';
}
// ─── applySurface ────────────────────────────────────────────────────────────
describe('applySurface', () => {
test('#4132: an unmanifested installed command cannot become a live instruction', (t) => {
const installed = runMinimalInstall({ runtime: 'claude', scope: 'global' });
const configDir = installed.configDir;
t.after(() => cleanup(installed.root));
const rogueSource = path.join(configDir, 'gsd-core', 'commands', 'gsd', 'rogue.md');
const rogueSkill = path.join(configDir, 'skills', 'gsd-rogue', 'SKILL.md');
fs.writeFileSync(rogueSource, '<instructions>ROGUE</instructions>\n');
const layout = resolveRuntimeArtifactLayout('claude', configDir, 'global');
assert.throws(
() => applySurface(configDir, layout, realManifest(), CLUSTERS, undefined, {
surfaceState: { baseProfile: 'full', disabledClusters: [], explicitAdds: [], explicitRemoves: [] },
}),
/install or upgrade gsd-core/,
);
assert.equal(fs.existsSync(rogueSkill), false, 'unmanifested Markdown must not reach the live skill surface');
});
test('#4132: a marker below rejected installed commands cannot promote instructions', (t) => {
const installed = runMinimalInstall({ runtime: 'claude', scope: 'global' });
const configDir = installed.configDir;
t.after(() => cleanup(installed.root));
const manifest = JSON.parse(fs.readFileSync(path.join(configDir, 'gsd-file-manifest.json'), 'utf8'));
const commandKey = Object.keys(manifest.files).find((key) => key.startsWith('gsd-core/commands/gsd/'));
assert.ok(commandKey, 'precondition: install manifest must own a command corpus file');
fs.appendFileSync(path.join(configDir, ...commandKey.split('/')), '\n# corrupted after install\n');
const installedCommands = path.join(configDir, 'gsd-core', 'commands', 'gsd');
const nestedMarkerCommands = path.join(installedCommands, 'nested');
const markerAgents = path.resolve(path.dirname(nestedMarkerCommands), '..', 'agents');
fs.mkdirSync(nestedMarkerCommands, { recursive: true });
fs.mkdirSync(markerAgents, { recursive: true });
fs.writeFileSync(path.join(nestedMarkerCommands, 'rogue.md'), '<instructions>ROGUE</instructions>\n');
fs.copyFileSync(path.join(__dirname, '..', 'agents', 'gsd-planner.md'), path.join(markerAgents, 'gsd-planner.md'));
fs.appendFileSync(path.join(markerAgents, 'gsd-planner.md'), '\nMARKER_AGENT_USED\n');
fs.writeFileSync(path.join(configDir, '.gsd-source'), nestedMarkerCommands + '\n');
const rogueSkill = path.join(configDir, 'skills', 'gsd-rogue', 'SKILL.md');
const liveAgent = path.join(configDir, 'agents', 'gsd-planner.md');
const oldAgent = fs.readFileSync(liveAgent);
const oldState = { baseProfile: 'full', disabledClusters: [], explicitAdds: [], explicitRemoves: [] };
writeSurface(configDir, oldState);
const oldSurface = fs.readFileSync(path.join(configDir, '.gsd-surface.json'));
const layout = resolveRuntimeArtifactLayout('claude', configDir, 'global');
assert.throws(
() => applySurface(configDir, layout, realManifest(), CLUSTERS, undefined, { surfaceState: oldState }),
/install or upgrade gsd-core/,
);
assert.equal(fs.existsSync(rogueSkill), false, 'nested marker Markdown must not reach the live skill surface');
assert.deepEqual(fs.readFileSync(liveAgent), oldAgent, 'marker agents must not replace live agents');
assert.deepEqual(fs.readFileSync(path.join(configDir, '.gsd-surface.json')), oldSurface);
});
test('core profile: only core skills appear in commandsDir', (t) => {
// #1367: claude local uses flat gsd-<stem>.md files at commands/ (not commands/gsd/<stem>.md).
const { base, runtimeConfigDir, commandsDir } = createFixtureRuntime();
@@ -324,6 +385,7 @@ describe('applySurface', () => {
test('applySurface writes gsd-prefixed command files matching install and preserves user commands (#816)', (t) => {
const configDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-surface-816-'));
t.after(() => cleanup(configDir));
writePackageSourceMarkerFixture(configDir);
writeActiveProfile(configDir, 'standard');
writeSurface(configDir, {
@@ -406,6 +468,7 @@ describe('applySurface', () => {
const installDir = fs.mkdtempSync(path.join(os.tmpdir(), `gsd-816-install-${runtime}-`));
const surfaceDir = fs.mkdtempSync(path.join(os.tmpdir(), `gsd-816-surface-${runtime}-`));
t.after(() => { cleanup(installDir); cleanup(surfaceDir); });
writePackageSourceMarkerFixture(surfaceDir);
// --- Install path ---
installRuntimeArtifacts(runtime, installDir, 'global', resolvedProfile);
@@ -531,6 +594,118 @@ describe('applySurface', () => {
);
});
}
test('#4132: a later kind staging failure leaves exact all-old state and artifacts', (t) => {
const root = createTempDir('gsd-surface-stage-failure-');
t.after(() => cleanup(root));
const firstDest = path.join(root, 'first');
const secondDest = path.join(root, 'second');
fs.mkdirSync(firstDest, { recursive: true });
fs.mkdirSync(secondDest, { recursive: true });
fs.writeFileSync(path.join(firstDest, 'gsd-alpha.md'), 'old alpha\n');
fs.writeFileSync(path.join(secondDest, 'gsd-beta.md'), 'old beta\n');
const stagedFirst = path.join(root, 'staged-first');
fs.mkdirSync(stagedFirst);
fs.writeFileSync(path.join(stagedFirst, 'alpha.md'), 'new alpha\n');
const oldSurface = surfaceBytesForTest({ baseProfile: 'full', disabledClusters: [], explicitAdds: [], explicitRemoves: [] });
fs.writeFileSync(path.join(root, '.gsd-surface.json'), oldSurface);
const layout = {
runtime: 'claude', configDir: root, scope: 'local', kinds: [
{ kind: 'commands', destSubpath: 'first', prefix: 'gsd-', stage: () => stagedFirst },
{ kind: 'commands', destSubpath: 'second', prefix: 'gsd-', stage: () => { throw new Error('later stage failed'); } },
],
};
assert.throws(() => applySurface(root, layout, new Map([['alpha', []], ['beta', []]])), /later stage failed/);
assert.equal(fs.readFileSync(path.join(firstDest, 'gsd-alpha.md'), 'utf8'), 'old alpha\n');
assert.equal(fs.readFileSync(path.join(secondDest, 'gsd-beta.md'), 'utf8'), 'old beta\n');
assert.equal(fs.readFileSync(path.join(root, '.gsd-surface.json'), 'utf8'), oldSurface);
});
test('#4132: a hash-mismatched installed corpus leaves exact all-old state and artifacts', (t) => {
const root = createTempDir('gsd-surface-corrupt-corpus-');
t.after(() => cleanup(root));
const installedCommands = path.join(root, 'gsd-core', 'commands', 'gsd');
const installedAgents = path.join(root, 'gsd-core', 'agents');
fs.mkdirSync(installedCommands, { recursive: true });
fs.mkdirSync(installedAgents, { recursive: true });
fs.writeFileSync(path.join(installedCommands, 'help.md'), '# corrupted command\n');
fs.writeFileSync(path.join(installedAgents, 'gsd-planner.md'), '# corrupted agent\n');
fs.writeFileSync(path.join(root, 'gsd-file-manifest.json'), JSON.stringify({ files: {
'gsd-core/commands/gsd/help.md': '0'.repeat(64),
'gsd-core/agents/gsd-planner.md': '0'.repeat(64),
} }));
const skillPath = path.join(root, 'skills', 'gsd-help', 'SKILL.md');
const agentPath = path.join(root, 'agents', 'gsd-planner.md');
fs.mkdirSync(path.dirname(skillPath), { recursive: true });
fs.mkdirSync(path.dirname(agentPath), { recursive: true });
fs.writeFileSync(skillPath, 'old skill\n');
fs.writeFileSync(agentPath, 'old agent\n');
const oldState = { baseProfile: 'full', disabledClusters: [], explicitAdds: [], explicitRemoves: [] };
const candidate = { ...oldState, explicitRemoves: ['help'] };
const oldSurface = surfaceBytesForTest(oldState);
fs.writeFileSync(path.join(root, '.gsd-surface.json'), oldSurface);
const layout = resolveRuntimeArtifactLayout('claude', root, 'global');
assert.throws(
() => applySurface(root, layout, realManifest(), CLUSTERS, undefined, { surfaceState: candidate }),
/install or upgrade gsd-core/,
);
assert.equal(fs.readFileSync(skillPath, 'utf8'), 'old skill\n');
assert.equal(fs.readFileSync(agentPath, 'utf8'), 'old agent\n');
assert.equal(fs.readFileSync(path.join(root, '.gsd-surface.json'), 'utf8'), oldSurface);
});
test('#4132: candidate surface state is published after materialization', (t) => {
const root = createTempDir('gsd-surface-state-last-');
t.after(() => cleanup(root));
const dest = path.join(root, 'commands');
const staged = path.join(root, 'staged');
fs.mkdirSync(dest, { recursive: true });
fs.mkdirSync(staged);
fs.writeFileSync(path.join(dest, 'gsd-alpha.md'), 'old alpha\n');
fs.writeFileSync(path.join(staged, 'alpha.md'), 'new alpha\n');
const oldState = { baseProfile: 'full', disabledClusters: [], explicitAdds: [], explicitRemoves: [] };
const newState = { ...oldState, disabledClusters: ['ui'] };
writeSurface(root, oldState);
const layout = {
runtime: 'claude', configDir: root, scope: 'local', kinds: [
{ kind: 'commands', destSubpath: 'commands', prefix: 'gsd-', stage: () => {
assert.deepEqual(readSurface(root), oldState, 'candidate must not be visible while staging');
return staged;
} },
],
};
applySurface(root, layout, new Map([['alpha', []]]), undefined, undefined, { surfaceState: newState });
assert.equal(fs.readFileSync(path.join(dest, 'gsd-alpha.md'), 'utf8'), 'new alpha\n');
assert.deepEqual(readSurface(root), newState);
});
test('#4132: reset removes surface state after materialization', (t) => {
const root = createTempDir('gsd-surface-reset-state-last-');
t.after(() => cleanup(root));
const dest = path.join(root, 'commands');
const staged = path.join(root, 'staged');
fs.mkdirSync(dest, { recursive: true });
fs.mkdirSync(staged);
fs.writeFileSync(path.join(staged, 'alpha.md'), 'reset alpha\n');
writeActiveProfile(root, 'full');
writeSurface(root, { baseProfile: 'core', disabledClusters: ['ui'], explicitAdds: [], explicitRemoves: [] });
const layout = {
runtime: 'claude', configDir: root, scope: 'local', kinds: [
{ kind: 'commands', destSubpath: 'commands', prefix: 'gsd-', stage: () => staged },
],
};
applySurface(root, layout, new Map([['alpha', []]]), undefined, undefined, { surfaceState: null });
assert.equal(fs.existsSync(path.join(root, '.gsd-surface.json')), false);
assert.equal(fs.readFileSync(path.join(dest, 'gsd-alpha.md'), 'utf8'), 'reset alpha\n');
});
});
// ─── resolveSurface ──────────────────────────────────────────────────────────
@@ -1201,6 +1376,7 @@ describe('skills-kind destination parity: installer vs surface-apply (#2911)', (
for (const runtime of RUNTIME_IDS) {
const configDir = fs.mkdtempSync(path.join(os.tmpdir(), `gsd-2911-parity-${runtime}-${scope}-`));
t.after(() => cleanup(configDir));
writePackageSourceMarkerFixture(configDir);
withFakeHome(fakeHome, () => {
let layout;
@@ -1295,6 +1471,7 @@ describe('codex skills-kind destination: home override (#2911)', () => {
t.after(() => cleanup(fakeHome));
const codexHome = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-2911-codex-home-dir-'));
t.after(() => cleanup(codexHome));
writePackageSourceMarkerFixture(codexHome);
withFakeHome(fakeHome, () => {
const manifest = loadSkillsManifest(REAL_COMMANDS_DIR);
@@ -1387,6 +1564,7 @@ describe('installOpencodeFamilySkills destination parity (#2911 sibling coverage
const configDir = fs.mkdtempSync(path.join(os.tmpdir(), `gsd-2911-ocfs-${runtime}-`));
const fakeHomeOverride = fs.mkdtempSync(path.join(os.tmpdir(), `gsd-2911-ocfs-home-${runtime}-`));
t.after(() => { cleanup(configDir); cleanup(fakeHomeOverride); });
writePackageSourceMarkerFixture(configDir);
// #3712 — this row drives a skills-kind `home` override on purpose, which is
// exactly what the test-home guard exists to police, so it has to declare the
// sandbox rather than rely on the destination happening to sit outside the
@@ -1458,15 +1636,12 @@ describe('installOpencodeFamilySkills destination parity (#2911 sibling coverage
// flat layout is preserved (not re-nested) rather than a nested one.
describe('issue-69: applySurface preserves nested skill layout (no re-flatten)', () => {
test('cline global full: applySurface keeps 6 router dirs and nested gsd-ns-manage/skills/help/SKILL.md', (t) => {
process.env.GSD_TEST_MODE = '1';
const { installRuntimeArtifacts } = require('../gsd-core/bin/lib/install-engine.cjs');
const dir = tmpDir('gsd-69-surface-');
t.after(() => { try { cleanup(dir); } catch { /* best-effort */ } });
const installed = runMinimalInstall({ runtime: 'cline', scope: 'global' });
const dir = installed.configDir;
t.after(() => { try { cleanup(installed.root); } catch { /* best-effort */ } });
// Step 1: full install
const manifest = loadSkillsManifest(REAL_COMMANDS_DIR);
const resolved = resolveProfile({ modes: ['full'], manifest });
installRuntimeArtifacts('cline', dir, 'global', resolved);
const skillsDir = path.join(dir, 'skills');
@@ -1510,14 +1685,11 @@ describe('issue-69: applySurface preserves nested skill layout (no re-flatten)',
// #924 companion: Claude must use FLAT layout and applySurface must NOT re-nest it.
test('claude global full: install produces flat layout and applySurface preserves it (#924)', (t) => {
process.env.GSD_TEST_MODE = '1';
const { installRuntimeArtifacts } = require('../gsd-core/bin/lib/install-engine.cjs');
const dir = tmpDir('gsd-924-69-');
t.after(() => { try { cleanup(dir); } catch { /* best-effort */ } });
const installed = runMinimalInstall({ runtime: 'claude', scope: 'global' });
const dir = installed.configDir;
t.after(() => { try { cleanup(installed.root); } catch { /* best-effort */ } });
const manifest = loadSkillsManifest(REAL_COMMANDS_DIR);
const resolved = resolveProfile({ modes: ['full'], manifest });
installRuntimeArtifacts('claude', dir, 'global', resolved);
const skillsDir = path.join(dir, 'skills');

View File

@@ -21,12 +21,14 @@ const { test, describe, beforeEach, afterEach, mock } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const crypto = require('node:crypto');
const { resolveRuntimeArtifactLayout, findInstallSourceRoot } = require('../gsd-core/bin/lib/runtime-artifact-layout.cjs');
const capabilityRegistry = require('../gsd-core/bin/lib/capability-registry.cjs');
const installProfiles = require('../gsd-core/bin/lib/install-profiles.cjs');
const { withInstallFs } = require('../gsd-core/bin/lib/install-fs-adapter.cjs');
const { install } = require('../bin/install.js');
const { createTempDir, cleanup, scrubConfigLocationEnv } = require('./helpers.cjs');
const { createTempDir, cleanup, scrubConfigLocationEnv, writePackageSourceMarkerFixture } = require('./helpers.cjs');
const REPO_ROOT = path.join(__dirname, '..');
@@ -533,11 +535,16 @@ const CORE_SKILLS = new Set(['help', 'phase', 'new-project']);
const CORE_AGENTS = new Set(['gsd-planner']);
const PROFILE_CORE = { skills: CORE_SKILLS, agents: CORE_AGENTS };
const PROFILE_FULL = { skills: '*', agents: new Set() };
const FAKE_STAGE_DIR = '/tmp/fake-config-dir-stage';
function createStageConfigDir(t) {
const configDir = writePackageSourceMarkerFixture(createTempDir('gsd-layout-stage-'));
t.after(() => cleanup(configDir));
return configDir;
}
describe('stage — agents kind (claude local)', () => {
test('stage returns a valid directory for the agents kind', () => {
const layout = resolveRuntimeArtifactLayout('claude', FAKE_STAGE_DIR, 'local');
test('stage returns a valid directory for the agents kind', (t) => {
const layout = resolveRuntimeArtifactLayout('claude', createStageConfigDir(t), 'local');
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
assert.ok(agentsKind, 'should have an agents kind');
@@ -548,8 +555,40 @@ describe('stage — agents kind (claude local)', () => {
});
describe('stage — skills kind (claude global)', () => {
test('stage returns a directory containing gsd-<stem>/SKILL.md entries', () => {
const layout = resolveRuntimeArtifactLayout('claude', FAKE_STAGE_DIR, 'global');
test('#4132: an independent source checkout can replace an invalid installed corpus', (t) => {
const configDir = createTempDir('gsd-4132-installer-source-');
t.after(() => cleanup(configDir));
const installedCommands = path.join(configDir, 'gsd-core', 'commands', 'gsd');
const installedAgents = path.join(configDir, 'gsd-core', 'agents');
fs.mkdirSync(installedCommands, { recursive: true });
fs.mkdirSync(installedAgents, { recursive: true });
fs.writeFileSync(path.join(installedCommands, 'help.md'), 'OLD INSTALLED COMMAND\n');
fs.writeFileSync(path.join(installedAgents, 'gsd-planner.md'), 'OLD INSTALLED AGENT\n');
fs.writeFileSync(path.join(configDir, '.gsd-source'), path.join(REPO_ROOT, 'commands', 'gsd') + '\n');
const layout = resolveRuntimeArtifactLayout('claude', configDir, 'global');
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
const agentsKind = layout.kinds.find(k => k.kind === 'agents');
assert.ok(skillsKind);
assert.ok(agentsKind);
const stagedSkills = skillsKind.stage(PROFILE_CORE);
const stagedAgents = agentsKind.stage(PROFILE_CORE);
t.after(() => cleanup(stagedSkills));
t.after(() => cleanup(stagedAgents));
assert.match(
fs.readFileSync(path.join(stagedSkills, 'gsd-help', 'SKILL.md'), 'utf8'),
/Show available GSD commands and usage guide/,
);
assert.doesNotMatch(
fs.readFileSync(path.join(stagedAgents, 'gsd-planner.md'), 'utf8'),
/OLD INSTALLED AGENT/,
);
});
test('stage returns a directory containing gsd-<stem>/SKILL.md entries', (t) => {
const layout = resolveRuntimeArtifactLayout('claude', createStageConfigDir(t), 'global');
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
assert.ok(skillsKind, 'should have a skills kind');
@@ -564,8 +603,8 @@ describe('stage — skills kind (claude global)', () => {
assert.ok(entries.length >= 1, 'at least one skill dir should be staged');
});
test('stage with skills="*" produces flat layout for claude (#924: reverted from nested)', () => {
const layout = resolveRuntimeArtifactLayout('claude', FAKE_STAGE_DIR, 'global');
test('stage with skills="*" produces flat layout for claude (#924: reverted from nested)', (t) => {
const layout = resolveRuntimeArtifactLayout('claude', createStageConfigDir(t), 'global');
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
assert.ok(skillsKind, 'should have a skills kind');
@@ -592,8 +631,8 @@ describe('stage — skills kind (claude global)', () => {
});
describe('stage — skills kind (kimi global)', () => {
test('stage returns Kimi SKILL.md dirs and agent YAML/prompt artifacts', () => {
const layout = resolveRuntimeArtifactLayout('kimi', FAKE_STAGE_DIR, 'global');
test('stage returns Kimi SKILL.md dirs and agent YAML/prompt artifacts', (t) => {
const layout = resolveRuntimeArtifactLayout('kimi', createStageConfigDir(t), 'global');
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
assert.ok(skillsKind, 'should have a skills kind');
@@ -635,8 +674,8 @@ describe('stage — skills kind (kimi global)', () => {
assert.doesNotMatch(executorYaml, /mcp__/);
});
test('tracks Kimi agent staging dir before writing artifacts', () => {
const layout = resolveRuntimeArtifactLayout('kimi', FAKE_STAGE_DIR, 'global');
test('tracks Kimi agent staging dir before writing artifacts', (t) => {
const layout = resolveRuntimeArtifactLayout('kimi', createStageConfigDir(t), 'global');
const agentsKind = layout.kinds.find(k => k.kind === 'kimi-agents');
assert.ok(agentsKind, 'should have a kimi-agents kind');
@@ -673,8 +712,8 @@ describe('stage — skills kind (kimi global)', () => {
});
describe('stage — opencode commands kind', () => {
test('opencode stage returns directory with .md files for selected skills', () => {
const layout = resolveRuntimeArtifactLayout('opencode', FAKE_STAGE_DIR);
test('opencode stage returns directory with .md files for selected skills', (t) => {
const layout = resolveRuntimeArtifactLayout('opencode', createStageConfigDir(t));
const commandsKind = layout.kinds.find(k => k.kind === 'commands');
assert.ok(commandsKind, 'should have a commands kind');
@@ -690,8 +729,8 @@ describe('stage — opencode commands kind', () => {
describe('stage — opencode/kilo skills kind (#784)', () => {
for (const runtime of ['opencode', 'kilo']) {
test(`${runtime} skills stage writes gsd-<stem>/SKILL.md with name + description`, () => {
const layout = resolveRuntimeArtifactLayout(runtime, FAKE_STAGE_DIR);
test(`${runtime} skills stage writes gsd-<stem>/SKILL.md with name + description`, (t) => {
const layout = resolveRuntimeArtifactLayout(runtime, createStageConfigDir(t));
const skillsKind = layout.kinds.find(k => k.kind === 'skills');
assert.ok(skillsKind, 'should have a skills kind');
@@ -717,7 +756,7 @@ describe('stage — opencode/kilo skills kind (#784)', () => {
describe('stage — cursor retired commands kind (#2644)', () => {
test('cursor layout exposes no commands staging surface', () => {
const layout = resolveRuntimeArtifactLayout('cursor', FAKE_STAGE_DIR);
const layout = resolveRuntimeArtifactLayout('cursor', FAKE_DIR);
const commandsKind = layout.kinds.find(k => k.kind === 'commands');
assert.equal(commandsKind, undefined);
});
@@ -921,9 +960,10 @@ describe('#1477 .gsd-source marker provisioning', () => {
});
// ── Failure 1 end-to-end: resolution succeeds FROM the deployed tree ─────────
// The deployed module's __dirname is <claudeDir>/gsd-core/bin/lib, which has no
// commands/gsd ancestor (global skills layout). Only the marker rescues it.
test('deployed global layout resolves the source root via the marker', () => {
// Fixed installs own a raw corpus below the deployed gsd-core tree. The
// marker remains compatible, but offline resolution no longer depends on
// the executing package path surviving.
test('deployed global layout resolves its installation-owned source corpus', () => {
const claudeDir = path.join(tmpRoot, '.claude');
fs.mkdirSync(claudeDir, { recursive: true });
runInstall(true /* isGlobal */, 'claude');
@@ -939,21 +979,93 @@ describe('#1477 .gsd-source marker provisioning', () => {
delete require.cache[deployedLayoutPath];
const deployed = require(deployedLayoutPath);
// Negative proof that the bug condition exists: WITHOUT consulting the marker
// (no configDir argument), walk-up from the deployed tree has nothing to find.
assert.throws(
() => deployed.findInstallSourceRoot(),
/could not locate commands\/gsd/,
'deployed walk-up must fail without the marker — this is the regression condition',
);
const installedCorpus = path.join(claudeDir, 'gsd-core', 'commands', 'gsd');
assert.ok(fs.existsSync(installedCorpus), 'fixed install must own commands/gsd below gsd-core');
assert.equal(fs.realpathSync(deployed.findInstallSourceRoot()), fs.realpathSync(installedCorpus));
// With the marker (configDir provided), list/status resolution succeeds.
let resolved;
assert.doesNotThrow(() => {
resolved = deployed.findInstallSourceRoot(claudeDir);
}, 'findInstallSourceRoot must resolve via the .gsd-source marker');
assert.equal(path.basename(resolved), 'gsd');
assert.ok(fs.existsSync(resolved));
assert.equal(fs.realpathSync(resolved), fs.realpathSync(installedCorpus));
});
test('#4132: deployed findInstallSourceRoot rejects an installed commands corpus whose hash changed', () => {
const claudeDir = path.join(tmpRoot, '.claude');
fs.mkdirSync(claudeDir, { recursive: true });
runInstall(true /* isGlobal */, 'claude');
const manifest = JSON.parse(fs.readFileSync(path.join(claudeDir, 'gsd-file-manifest.json'), 'utf8'));
const commandKey = Object.keys(manifest.files).find((key) => key.startsWith('gsd-core/commands/gsd/'));
assert.ok(commandKey, 'precondition: install manifest must own at least one command corpus file');
const commandPath = path.join(claudeDir, ...commandKey.split('/'));
fs.appendFileSync(commandPath, '\n# corrupted after install\n');
const deployedLayoutPath = path.join(claudeDir, 'gsd-core', 'bin', 'lib', 'runtime-artifact-layout.cjs');
delete require.cache[deployedLayoutPath];
const deployed = require(deployedLayoutPath);
assert.throws(
() => deployed.findInstallSourceRoot(claudeDir),
/install or upgrade gsd-core/,
);
});
test('#4132: deployed finder rejects an installed corpus reached through an ancestor symlink', (t) => {
const claudeDir = path.join(tmpRoot, '.claude');
fs.mkdirSync(claudeDir, { recursive: true });
runInstall(true /* isGlobal */, 'claude');
const commandsParent = path.join(claudeDir, 'gsd-core', 'commands');
const outsideParent = path.join(tmpRoot, 'outside-commands');
fs.renameSync(commandsParent, outsideParent);
try {
fs.symlinkSync(outsideParent, commandsParent, process.platform === 'win32' ? 'junction' : 'dir');
} catch (error) {
fs.renameSync(outsideParent, commandsParent);
if (['EPERM', 'EACCES', 'ENOSYS'].includes(error.code)) {
t.skip(`directory symlink creation unavailable: ${error.code || error.message}`);
return;
}
throw error;
}
const deployedLayoutPath = path.join(claudeDir, 'gsd-core', 'bin', 'lib', 'runtime-artifact-layout.cjs');
delete require.cache[deployedLayoutPath];
const deployed = require(deployedLayoutPath);
const priorOptIn = process.env.GSD_ALLOW_SYMLINKED_DEST;
process.env.GSD_ALLOW_SYMLINKED_DEST = '1';
t.after(() => {
if (priorOptIn === undefined) delete process.env.GSD_ALLOW_SYMLINKED_DEST;
else process.env.GSD_ALLOW_SYMLINKED_DEST = priorOptIn;
});
assert.throws(
() => deployed.findInstallSourceRoot(claudeDir),
/install or upgrade gsd-core/,
);
});
test('#4132: deployed agents layout rejects an installed agents corpus whose hash changed', () => {
const claudeDir = path.join(tmpRoot, '.claude');
fs.mkdirSync(claudeDir, { recursive: true });
runInstall(true /* isGlobal */, 'claude');
const manifest = JSON.parse(fs.readFileSync(path.join(claudeDir, 'gsd-file-manifest.json'), 'utf8'));
const agentKey = Object.keys(manifest.files).find((key) => key.startsWith('gsd-core/agents/'));
assert.ok(agentKey, 'precondition: install manifest must own at least one agent corpus file');
fs.appendFileSync(path.join(claudeDir, ...agentKey.split('/')), '\n# corrupted after install\n');
const deployedLayoutPath = path.join(claudeDir, 'gsd-core', 'bin', 'lib', 'runtime-artifact-layout.cjs');
delete require.cache[deployedLayoutPath];
const deployed = require(deployedLayoutPath);
assert.throws(
() => deployed.resolveRuntimeArtifactLayout('claude', claudeDir, 'global')
.kinds.find((kind) => kind.kind === 'agents').stage(PROFILE_CORE),
/install or upgrade gsd-core/,
);
});
// ── Adversarial marker-reader cases (no full install needed) ─────────────────
@@ -965,6 +1077,7 @@ describe('#1477 .gsd-source marker provisioning', () => {
test('marker pointing at a valid commands/gsd takes precedence over walk-up', () => {
const fakeSrc = path.join(cfgDir, 'pkg', 'commands', 'gsd');
fs.mkdirSync(fakeSrc, { recursive: true });
fs.writeFileSync(path.join(fakeSrc, 'gsd-test.md'), '# marker source\n');
fs.writeFileSync(path.join(cfgDir, '.gsd-source'), fakeSrc + '\n', 'utf8');
const resolved = findInstallSourceRoot(cfgDir);
@@ -981,11 +1094,335 @@ describe('#1477 .gsd-source marker provisioning', () => {
assert.equal(path.resolve(resolved), path.resolve(REPO_ROOT, 'commands', 'gsd'));
});
test('#4132: a missing installed leaf still rejects a marker containing it through a symlinked ancestor', (t) => {
const outsideCore = path.join(cfgDir, 'outside-core');
const markerCommands = path.join(outsideCore, 'commands');
const markerAgents = path.join(cfgDir, 'agents');
fs.mkdirSync(markerCommands, { recursive: true });
fs.mkdirSync(markerAgents, { recursive: true });
fs.writeFileSync(path.join(markerCommands, 'help.md'), '# marker command\n');
fs.writeFileSync(path.join(markerAgents, 'gsd-planner.md'), '# marker agent\n');
try {
fs.symlinkSync(
outsideCore,
path.join(cfgDir, 'gsd-core'),
process.platform === 'win32' ? 'junction' : 'dir',
);
} catch (error) {
t.skip(`directory symlink creation unavailable: ${error.code || error.message}`);
return;
}
fs.writeFileSync(path.join(cfgDir, '.gsd-source'), markerCommands + '\n');
assert.throws(
() => resolveRuntimeArtifactLayout('claude', cfgDir, 'global')
.kinds.find((kind) => kind.kind === 'skills').stage(PROFILE_CORE),
/install or upgrade gsd-core/,
);
});
test('empty / whitespace-only marker is ignored', () => {
fs.writeFileSync(path.join(cfgDir, '.gsd-source'), ' \n', 'utf8');
const resolved = findInstallSourceRoot(cfgDir);
assert.equal(path.resolve(resolved), path.resolve(REPO_ROOT, 'commands', 'gsd'));
});
test('one complete installed provider wins over a different complete marker provider', (t) => {
const installedCommands = path.join(cfgDir, 'gsd-core', 'commands', 'gsd');
const installedAgents = path.join(cfgDir, 'gsd-core', 'agents');
fs.mkdirSync(installedCommands, { recursive: true });
fs.mkdirSync(installedAgents, { recursive: true });
const installedCommandPath = path.join(installedCommands, 'help.md');
const installedAgentPath = path.join(installedAgents, 'gsd-planner.md');
fs.writeFileSync(installedCommandPath, '# installed command\n');
fs.writeFileSync(installedAgentPath, '# installed agent\n');
fs.writeFileSync(path.join(cfgDir, 'gsd-file-manifest.json'), JSON.stringify({ files: {
'gsd-core/commands/gsd/help.md': crypto.createHash('sha256').update(fs.readFileSync(installedCommandPath)).digest('hex'),
'gsd-core/agents/gsd-planner.md': crypto.createHash('sha256').update(fs.readFileSync(installedAgentPath)).digest('hex'),
} }));
const markerCommands = path.join(cfgDir, 'legacy-package', 'commands', 'gsd');
const markerAgents = path.join(cfgDir, 'legacy-package', 'agents');
fs.mkdirSync(markerCommands, { recursive: true });
fs.mkdirSync(markerAgents, { recursive: true });
fs.writeFileSync(path.join(markerCommands, 'help.md'), '# marker command\n');
fs.writeFileSync(path.join(markerAgents, 'gsd-planner.md'), '# marker agent\n');
fs.writeFileSync(path.join(cfgDir, '.gsd-source'), markerCommands + '\n');
const layout = resolveRuntimeArtifactLayout('claude', cfgDir, 'global');
const stagedSkills = layout.kinds.find((kind) => kind.kind === 'skills').stage(PROFILE_CORE);
const stagedAgents = layout.kinds.find((kind) => kind.kind === 'agents').stage(PROFILE_CORE);
t.after(() => cleanup(stagedSkills));
t.after(() => cleanup(stagedAgents));
assert.match(fs.readFileSync(path.join(stagedSkills, 'gsd-help', 'SKILL.md'), 'utf8'), /installed command/);
assert.match(fs.readFileSync(path.join(stagedAgents, 'gsd-planner.md'), 'utf8'), /installed agent/);
});
test('a partial installed corpus is not mixed with a complete marker provider', (t) => {
const installedCommands = path.join(cfgDir, 'gsd-core', 'commands', 'gsd');
fs.mkdirSync(installedCommands, { recursive: true });
fs.writeFileSync(path.join(installedCommands, 'help.md'), '# installed command\n');
const markerCommands = path.join(cfgDir, 'legacy-package', 'commands', 'gsd');
const markerAgents = path.join(cfgDir, 'legacy-package', 'agents');
fs.mkdirSync(markerCommands, { recursive: true });
fs.mkdirSync(markerAgents, { recursive: true });
fs.writeFileSync(path.join(markerCommands, 'help.md'), '# marker command\n');
fs.writeFileSync(path.join(markerAgents, 'gsd-planner.md'), '# marker agent\n');
fs.writeFileSync(path.join(cfgDir, '.gsd-source'), markerCommands + '\n');
const layout = resolveRuntimeArtifactLayout('claude', cfgDir, 'global');
const stagedSkills = layout.kinds.find((kind) => kind.kind === 'skills').stage(PROFILE_CORE);
const stagedAgents = layout.kinds.find((kind) => kind.kind === 'agents').stage(PROFILE_CORE);
t.after(() => cleanup(stagedSkills));
t.after(() => cleanup(stagedAgents));
assert.match(fs.readFileSync(path.join(stagedSkills, 'gsd-help', 'SKILL.md'), 'utf8'), /marker command/);
assert.match(fs.readFileSync(path.join(stagedAgents, 'gsd-planner.md'), 'utf8'), /marker agent/);
});
test('partial providers are not mixed when package fallback is disabled', () => {
const installedCommands = path.join(cfgDir, 'gsd-core', 'commands', 'gsd');
fs.mkdirSync(installedCommands, { recursive: true });
fs.writeFileSync(path.join(installedCommands, 'gsd-test.md'), '# installed command\n');
const markerCommands = path.join(cfgDir, 'legacy-package', 'commands', 'gsd');
fs.mkdirSync(markerCommands, { recursive: true });
fs.writeFileSync(path.join(markerCommands, 'gsd-test.md'), '# marker command\n');
fs.writeFileSync(path.join(cfgDir, '.gsd-source'), markerCommands + '\n');
const layout = resolveRuntimeArtifactLayout('claude', cfgDir, 'global');
assert.throws(() => layout.kinds.find((kind) => kind.kind === 'skills').stage(PROFILE_CORE), /install or upgrade gsd-core/);
});
test('ordinary Runtime Surface staging never falls back to the source checkout package', () => {
const layout = resolveRuntimeArtifactLayout('claude', cfgDir, 'global');
const skills = layout.kinds.find((kind) => kind.kind === 'skills');
assert.ok(skills);
assert.throws(
() => skills.stage(PROFILE_CORE),
/install or upgrade gsd-core/,
);
});
test('#4132: caller-supplied stage context cannot select installer source authority', () => {
const layout = resolveRuntimeArtifactLayout('claude', cfgDir, 'global');
const skills = layout.kinds.find((kind) => kind.kind === 'skills');
assert.throws(
() => skills.stage(PROFILE_CORE, {
[Symbol.for('@open-gsd/runtime-artifact-installer-source-authority')]: true,
}),
/install or upgrade gsd-core/,
);
assert.throws(
() => withInstallFs(undefined, () => skills.stage(PROFILE_CORE)),
/install or upgrade gsd-core/,
);
});
test('an installed corpus without a manifest is not a working fallback', () => {
const installedCommands = path.join(cfgDir, 'gsd-core', 'commands', 'gsd');
const installedAgents = path.join(cfgDir, 'gsd-core', 'agents');
fs.mkdirSync(installedCommands, { recursive: true });
fs.mkdirSync(installedAgents, { recursive: true });
fs.writeFileSync(path.join(installedCommands, 'help.md'), '# unverified command\n');
fs.writeFileSync(path.join(installedAgents, 'gsd-planner.md'), '# unverified agent\n');
const layout = resolveRuntimeArtifactLayout('claude', cfgDir, 'global');
assert.throws(
() => layout.kinds.find((kind) => kind.kind === 'skills').stage(PROFILE_CORE),
/install or upgrade gsd-core/,
);
});
test('an installed corpus whose bytes do not match its manifest is not a working fallback', () => {
const installedCommands = path.join(cfgDir, 'gsd-core', 'commands', 'gsd');
const installedAgents = path.join(cfgDir, 'gsd-core', 'agents');
fs.mkdirSync(installedCommands, { recursive: true });
fs.mkdirSync(installedAgents, { recursive: true });
fs.writeFileSync(path.join(installedCommands, 'help.md'), '# corrupted command\n');
fs.writeFileSync(path.join(installedAgents, 'gsd-planner.md'), '# corrupted agent\n');
fs.writeFileSync(path.join(cfgDir, 'gsd-file-manifest.json'), JSON.stringify({ files: {
'gsd-core/commands/gsd/help.md': '0'.repeat(64),
'gsd-core/agents/gsd-planner.md': '0'.repeat(64),
} }));
const layout = resolveRuntimeArtifactLayout('claude', cfgDir, 'global');
assert.throws(
() => layout.kinds.find((kind) => kind.kind === 'skills').stage(PROFILE_CORE),
/install or upgrade gsd-core/,
);
});
test('a hash-mismatched installed corpus falls back to an independent complete marker provider', (t) => {
const installedCommands = path.join(cfgDir, 'gsd-core', 'commands', 'gsd');
const installedAgents = path.join(cfgDir, 'gsd-core', 'agents');
fs.mkdirSync(installedCommands, { recursive: true });
fs.mkdirSync(installedAgents, { recursive: true });
fs.writeFileSync(path.join(installedCommands, 'help.md'), '# corrupted command\n');
fs.writeFileSync(path.join(installedAgents, 'gsd-planner.md'), '# corrupted agent\n');
fs.writeFileSync(path.join(cfgDir, 'gsd-file-manifest.json'), JSON.stringify({ files: {
'gsd-core/commands/gsd/help.md': '0'.repeat(64),
'gsd-core/agents/gsd-planner.md': '0'.repeat(64),
} }));
const markerCommands = path.join(cfgDir, 'legacy-package', 'commands', 'gsd');
const markerAgents = path.join(cfgDir, 'legacy-package', 'agents');
fs.mkdirSync(markerCommands, { recursive: true });
fs.mkdirSync(markerAgents, { recursive: true });
fs.writeFileSync(path.join(markerCommands, 'help.md'), '# marker command\n');
fs.writeFileSync(path.join(markerAgents, 'gsd-planner.md'), '# marker agent\n');
fs.writeFileSync(path.join(cfgDir, '.gsd-source'), markerCommands + '\n');
const layout = resolveRuntimeArtifactLayout('claude', cfgDir, 'global');
const stagedSkills = layout.kinds.find((kind) => kind.kind === 'skills').stage(PROFILE_CORE);
const stagedAgents = layout.kinds.find((kind) => kind.kind === 'agents').stage(PROFILE_CORE);
t.after(() => cleanup(stagedSkills));
t.after(() => cleanup(stagedAgents));
assert.match(fs.readFileSync(path.join(stagedSkills, 'gsd-help', 'SKILL.md'), 'utf8'), /marker command/);
assert.match(fs.readFileSync(path.join(stagedAgents, 'gsd-planner.md'), 'utf8'), /marker agent/);
});
test('#4132: a marker aliasing any rejected installed root is not an independent provider', (t) => {
const installedCommandsParent = path.join(cfgDir, 'gsd-core', 'commands');
const installedCommands = path.join(installedCommandsParent, 'gsd');
const installedAgents = path.join(cfgDir, 'gsd-core', 'agents');
fs.mkdirSync(installedCommands, { recursive: true });
fs.mkdirSync(installedAgents, { recursive: true });
fs.writeFileSync(path.join(installedCommands, 'help.md'), '# corrupted installed command\n');
const installedAgentPath = path.join(installedAgents, 'gsd-planner.md');
fs.writeFileSync(installedAgentPath, '# installed agent\n');
fs.writeFileSync(path.join(cfgDir, 'gsd-file-manifest.json'), JSON.stringify({ files: {
'gsd-core/commands/gsd/help.md': '0'.repeat(64),
'gsd-core/agents/gsd-planner.md': crypto.createHash('sha256').update(fs.readFileSync(installedAgentPath)).digest('hex'),
} }));
const markerRoot = path.join(cfgDir, 'hybrid-marker');
fs.mkdirSync(markerRoot, { recursive: true });
try {
fs.symlinkSync(
installedCommandsParent,
path.join(markerRoot, 'commands'),
process.platform === 'win32' ? 'junction' : 'dir',
);
} catch (error) {
t.skip(`directory symlink creation unavailable: ${error.code || error.message}`);
return;
}
const markerCommands = path.join(markerRoot, 'commands', 'gsd');
const markerAgents = path.join(markerRoot, 'agents');
fs.mkdirSync(markerAgents, { recursive: true });
fs.writeFileSync(path.join(markerAgents, 'gsd-planner.md'), '# independent marker agent\n');
fs.writeFileSync(path.join(cfgDir, '.gsd-source'), markerCommands + '\n');
assert.equal(fs.realpathSync(markerCommands), fs.realpathSync(installedCommands));
assert.notEqual(fs.realpathSync(markerAgents), fs.realpathSync(installedAgents));
const layout = resolveRuntimeArtifactLayout('claude', cfgDir, 'global');
const skills = layout.kinds.find((kind) => kind.kind === 'skills');
let stagedSkills;
t.after(() => { if (stagedSkills) cleanup(stagedSkills); });
assert.throws(
() => { stagedSkills = skills.stage(PROFILE_CORE); },
/install or upgrade gsd-core/,
);
});
test('#4132: a marker containing a rejected installed root is not an independent provider', () => {
const installedCommandsParent = path.join(cfgDir, 'gsd-core', 'commands');
const installedCommands = path.join(installedCommandsParent, 'gsd');
const installedAgents = path.join(cfgDir, 'gsd-core', 'agents');
const markerAgents = path.join(cfgDir, 'agents');
fs.mkdirSync(installedCommands, { recursive: true });
fs.mkdirSync(installedAgents, { recursive: true });
fs.mkdirSync(markerAgents, { recursive: true });
fs.writeFileSync(path.join(installedCommands, 'help.md'), '# corrupted installed command\n');
const installedAgentPath = path.join(installedAgents, 'gsd-planner.md');
fs.writeFileSync(installedAgentPath, '# installed agent\n');
fs.writeFileSync(path.join(installedCommandsParent, 'rogue.md'), '<instructions>ROGUE</instructions>\n');
fs.writeFileSync(path.join(markerAgents, 'gsd-planner.md'), '# marker agent\n');
fs.writeFileSync(path.join(cfgDir, 'gsd-file-manifest.json'), JSON.stringify({ files: {
'gsd-core/commands/gsd/help.md': '0'.repeat(64),
'gsd-core/agents/gsd-planner.md': crypto.createHash('sha256').update(fs.readFileSync(installedAgentPath)).digest('hex'),
} }));
fs.writeFileSync(path.join(cfgDir, '.gsd-source'), installedCommandsParent + '\n');
const layout = resolveRuntimeArtifactLayout('claude', cfgDir, 'global');
assert.throws(
() => layout.kinds.find((kind) => kind.kind === 'skills').stage(PROFILE_CORE),
/install or upgrade gsd-core/,
);
});
test('#4132: an agents descendant of a rejected installed root rejects the whole provider', () => {
const installedCommands = path.join(cfgDir, 'gsd-core', 'commands', 'gsd');
const installedAgents = path.join(cfgDir, 'gsd-core', 'agents');
fs.mkdirSync(installedCommands, { recursive: true });
fs.mkdirSync(installedAgents, { recursive: true });
const installedCommandPath = path.join(installedCommands, 'help.md');
fs.writeFileSync(installedCommandPath, '# installed command\n');
fs.writeFileSync(path.join(installedAgents, 'gsd-planner.md'), '# corrupted installed agent\n');
fs.writeFileSync(path.join(cfgDir, 'gsd-file-manifest.json'), JSON.stringify({ files: {
'gsd-core/commands/gsd/help.md': '0'.repeat(64),
'gsd-core/agents/gsd-planner.md': '0'.repeat(64),
} }));
const nestedProviderRoot = path.join(installedAgents, 'nested');
const markerCommands = path.join(nestedProviderRoot, 'commands', 'gsd');
const markerAgents = path.join(nestedProviderRoot, 'agents');
fs.mkdirSync(markerCommands, { recursive: true });
fs.mkdirSync(markerAgents, { recursive: true });
fs.writeFileSync(path.join(markerCommands, 'help.md'), '# marker command\n');
fs.writeFileSync(path.join(markerAgents, 'gsd-planner.md'), '# marker agent\n');
fs.writeFileSync(path.join(cfgDir, '.gsd-source'), markerCommands + '\n');
assert.equal(
fs.realpathSync(findInstallSourceRoot(cfgDir)),
fs.realpathSync(markerCommands),
'commands-only resolution must ignore overlap in the non-required agents class',
);
const layout = resolveRuntimeArtifactLayout('claude', cfgDir, 'global');
assert.throws(
() => layout.kinds.find((kind) => kind.kind === 'skills').stage(PROFILE_CORE),
/install or upgrade gsd-core/,
);
});
test('manifest-expected missing corpus file fails closed without reusing its marker alias', () => {
const installedCommands = path.join(cfgDir, 'gsd-core', 'commands', 'gsd');
const installedAgents = path.join(cfgDir, 'gsd-core', 'agents');
fs.mkdirSync(installedCommands, { recursive: true });
fs.mkdirSync(installedAgents, { recursive: true });
fs.writeFileSync(path.join(installedCommands, 'gsd-test.md'), '# installed command\n');
fs.writeFileSync(path.join(installedAgents, 'gsd-test-agent.md'), '# installed agent\n');
fs.writeFileSync(path.join(cfgDir, 'gsd-file-manifest.json'), JSON.stringify({ files: {
'gsd-core/commands/gsd/gsd-test.md': '0'.repeat(64),
'gsd-core/agents/gsd-test-agent.md': '0'.repeat(64),
'gsd-core/agents/removed.md': '0'.repeat(64),
} }));
fs.writeFileSync(path.join(cfgDir, '.gsd-source'), installedCommands + '\n');
const layout = resolveRuntimeArtifactLayout('claude', cfgDir, 'global');
assert.throws(() => layout.kinds.find((kind) => kind.kind === 'skills').stage(PROFILE_CORE), /install or upgrade gsd-core/);
});
test('a symlink inside the installed corpus is not a confined source', (t) => {
const installedCommands = path.join(cfgDir, 'gsd-core', 'commands', 'gsd');
const installedAgents = path.join(cfgDir, 'gsd-core', 'agents');
fs.mkdirSync(installedCommands, { recursive: true });
fs.mkdirSync(installedAgents, { recursive: true });
fs.writeFileSync(path.join(installedCommands, 'gsd-test.md'), '# installed command\n');
const outside = path.join(cfgDir, 'outside.md');
fs.writeFileSync(outside, '# outside\n');
try {
fs.symlinkSync(outside, path.join(installedAgents, 'gsd-test-agent.md'));
} catch (error) {
t.skip(`symlink creation unavailable: ${error.code || error.message}`);
return;
}
const layout = resolveRuntimeArtifactLayout('claude', cfgDir, 'global');
assert.throws(() => layout.kinds.find((kind) => kind.kind === 'skills').stage(PROFILE_CORE), /install or upgrade gsd-core/);
assert.strictEqual(fs.readFileSync(outside, 'utf8'), '# outside\n');
});
});
});
@@ -1054,8 +1491,7 @@ describe('#2624 .gsd-source marker is rewritten before staging reads it', () =>
cleanup(tmpRoot);
});
// The current package's commands/gsd — what the marker MUST point at after install.
const CURRENT_SOURCE = path.join(REPO_ROOT, 'commands', 'gsd');
const installedSource = (claudeDir) => path.join(claudeDir, 'gsd-core', 'commands', 'gsd');
test('claude-global install overwrites a stale .gsd-source marker before staging reads it', (t) => {
const claudeDir = path.join(tmpRoot, '.claude');
@@ -1090,8 +1526,8 @@ describe('#2624 .gsd-source marker is rewritten before staging reads it', () =>
const markerPath = path.join(claudeDir, '.gsd-source');
assert.ok(fs.existsSync(markerPath), 'marker must exist after install');
const finalMarker = path.resolve(fs.readFileSync(markerPath, 'utf8').trim());
assert.equal(finalMarker, path.resolve(CURRENT_SOURCE),
`final marker must point at the current package source, not ${finalMarker}`);
assert.equal(finalMarker, path.resolve(installedSource(claudeDir)),
`final marker must point at the installed current-version corpus, not ${finalMarker}`);
// The decisive assertion: staging must NEVER have resolved the stale source. Before the
// fix, at least one staging resolution returned the stale path (read before rewrite).
@@ -1112,8 +1548,8 @@ describe('#2624 .gsd-source marker is rewritten before staging reads it', () =>
const resolved = fs.readFileSync(markerPath, 'utf8').trim();
assert.equal(
path.resolve(resolved),
path.resolve(CURRENT_SOURCE),
'fresh install marker must point at the current package source',
path.resolve(installedSource(claudeDir)),
'fresh install marker must point at the installed corpus',
);
});
@@ -1132,8 +1568,8 @@ describe('#2624 .gsd-source marker is rewritten before staging reads it', () =>
const resolved = fs.readFileSync(markerPath, 'utf8').trim();
assert.equal(
path.resolve(resolved),
path.resolve(CURRENT_SOURCE),
'ghost marker must be rewritten to the current package source',
path.resolve(installedSource(claudeDir)),
'ghost marker must be rewritten to the installed corpus',
);
});
});

View File

@@ -2508,6 +2508,7 @@ describe('#3706: the layout seam actually threads the variant', () => {
fs.mkdirSync(commandsDir, { recursive: true });
fs.mkdirSync(agentsDir, { recursive: true });
fs.writeFileSync(path.join(configDir, '.gsd-source'), commandsDir + '\n', 'utf8');
fs.writeFileSync(path.join(commandsDir, 'gsd-help.md'), '# complete marker provider\n', 'utf8');
fs.writeFileSync(path.join(agentsDir, 'gsd-executor.md'), agentContent, 'utf8');
return configDir;
}
@@ -2587,4 +2588,3 @@ describe('#3706: the layout seam actually threads the variant', () => {
}
});
});

View File

@@ -39,3 +39,18 @@ describe('#2116 regression: surface.md resolvable require + correct package', ()
);
});
});
describe('#4132 regression: surface.md uses the state-last public contract', () => {
// allow-test-rule: source-text-is-the-product (#4132)
const content = fs.readFileSync(SURFACE_MD, 'utf-8');
test('mutations pass an in-memory candidate without an eager state write', () => {
assert.match(content, /surfaceState/);
assert.match(content, /publishes the candidate state only after/);
assert.doesNotMatch(content, /writeSurface\(runtimeConfigDir, surfaceState\)/);
});
test('reset is represented as an absent-state candidate, not an eager delete', () => {
assert.match(content, /surfaceState: null/);
});
});

View File

@@ -27,7 +27,7 @@
"adr857-predicate-boundary.test.cjs": 113,
"affected-tests-lib.test.cjs": 240,
"agent-classification-parity.test.cjs": 49,
"agent-fragments-emission.install.test.cjs": 79456,
"agent-fragments-emission.install.test.cjs": 228000,
"agent-frontmatter.test.cjs": 1076,
"agent-install-check.test.cjs": 274,
"agent-install-validation.test.cjs": 12405,
@@ -282,7 +282,7 @@
"fixture-builder.test.cjs": 324,
"forensics.test.cjs": 164,
"format-github-release-notes.test.cjs": 69,
"fragment-single-edit-propagation.install.test.cjs": 229914,
"fragment-single-edit-propagation.install.test.cjs": 575000,
"frontmatter-cli.test.cjs": 25728,
"frontmatter.property.test.cjs": 2551,
"frontmatter.test.cjs": 10565,