refactor: hard-fork GSD -> MSD (Make Software Done)
Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD across contents and paths, upstream package/repo coordinates -> @golem15/msd-core and golem15com/msd-core. Deep links into upstream history, sibling upstream packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is. Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line, package/plugin identity, regenerated lockfile, install-tree fixtures, derived registries and benchmark baseline; migration checksum baseline re-locked (MSD keeps its own install state, so no install had applied the old sums); sort-order and regex-escaped expectations in tests adjusted.
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* Tests for gsd-core/bin/lib/intel.cjs
|
||||
* Tests for msd-core/bin/lib/intel.cjs
|
||||
*
|
||||
* Covers: query, status, diff, validate, snapshot, patch-meta,
|
||||
* extract-exports, enabled/disabled gating, and CLI routing via gsd-tools.
|
||||
* extract-exports, enabled/disabled gating, and CLI routing via msd-tools.
|
||||
*/
|
||||
// allow-test-rule: source-text-is-the-product
|
||||
// readFileSync assertions target API-SURFACE.md, which is the generated product of intelApiSurface; asserting on its text content is the only way to verify correct generation.
|
||||
@@ -13,7 +13,7 @@ const { describe, test, beforeEach, afterEach } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { createTempProject, createTempDir, cleanup, runGsdTools } = require('./helpers.cjs');
|
||||
const { createTempProject, createTempDir, cleanup, runMsdTools } = require('./helpers.cjs');
|
||||
|
||||
const {
|
||||
intelQuery,
|
||||
@@ -27,9 +27,9 @@ const {
|
||||
ensureIntelDir,
|
||||
isIntelCapabilityActive,
|
||||
INTEL_FILES,
|
||||
} = require('../gsd-core/bin/lib/intel.cjs');
|
||||
} = require('../msd-core/bin/lib/intel.cjs');
|
||||
|
||||
const { isCapabilityActive } = require('../gsd-core/bin/lib/capability-state.cjs');
|
||||
const { isCapabilityActive } = require('../msd-core/bin/lib/capability-state.cjs');
|
||||
|
||||
// ─── Helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -66,15 +66,15 @@ function _writeIntelMd(planningDir, filename, content) {
|
||||
// where intel is surfaced in the real ~/.claude).
|
||||
//
|
||||
// Fix: point CLAUDE_CONFIG_DIR at a tmp dir containing a full-profile
|
||||
// .gsd-surface.json (no disabled clusters) so intel is surfaced deterministically.
|
||||
// .msd-surface.json (no disabled clusters) so intel is surfaced deterministically.
|
||||
// An EMPTY tmp config dir also works (defaults to 'full' profile → all surfaced)
|
||||
// but we write the file explicitly for visible intent.
|
||||
|
||||
/** Create a tmp config dir with intel (and all caps) surfaced — full profile. */
|
||||
function makeSurfacedConfigDir() {
|
||||
const dir = createTempDir('gsd-intel-surface-cfg-');
|
||||
const dir = createTempDir('msd-intel-surface-cfg-');
|
||||
fs.writeFileSync(
|
||||
path.join(dir, '.gsd-surface.json'),
|
||||
path.join(dir, '.msd-surface.json'),
|
||||
JSON.stringify({ baseProfile: 'full', disabledClusters: [], explicitAdds: [], explicitRemoves: [] }, null, 2) + '\n',
|
||||
'utf8',
|
||||
);
|
||||
@@ -84,21 +84,21 @@ function makeSurfacedConfigDir() {
|
||||
/** Save env vars touched by the surfaced-config fixture; returns .restore(). */
|
||||
function saveSurfacedEnv() {
|
||||
const saved = {
|
||||
GSD_RUNTIME: process.env.GSD_RUNTIME,
|
||||
MSD_RUNTIME: process.env.MSD_RUNTIME,
|
||||
CLAUDE_CONFIG_DIR: process.env.CLAUDE_CONFIG_DIR,
|
||||
GSD_WORKSTREAM: process.env.GSD_WORKSTREAM,
|
||||
GSD_PROJECT: process.env.GSD_PROJECT,
|
||||
MSD_WORKSTREAM: process.env.MSD_WORKSTREAM,
|
||||
MSD_PROJECT: process.env.MSD_PROJECT,
|
||||
};
|
||||
return {
|
||||
restore() {
|
||||
if (saved.GSD_RUNTIME === undefined) delete process.env.GSD_RUNTIME;
|
||||
else process.env.GSD_RUNTIME = saved.GSD_RUNTIME;
|
||||
if (saved.MSD_RUNTIME === undefined) delete process.env.MSD_RUNTIME;
|
||||
else process.env.MSD_RUNTIME = saved.MSD_RUNTIME;
|
||||
if (saved.CLAUDE_CONFIG_DIR === undefined) delete process.env.CLAUDE_CONFIG_DIR;
|
||||
else process.env.CLAUDE_CONFIG_DIR = saved.CLAUDE_CONFIG_DIR;
|
||||
if (saved.GSD_WORKSTREAM === undefined) delete process.env.GSD_WORKSTREAM;
|
||||
else process.env.GSD_WORKSTREAM = saved.GSD_WORKSTREAM;
|
||||
if (saved.GSD_PROJECT === undefined) delete process.env.GSD_PROJECT;
|
||||
else process.env.GSD_PROJECT = saved.GSD_PROJECT;
|
||||
if (saved.MSD_WORKSTREAM === undefined) delete process.env.MSD_WORKSTREAM;
|
||||
else process.env.MSD_WORKSTREAM = saved.MSD_WORKSTREAM;
|
||||
if (saved.MSD_PROJECT === undefined) delete process.env.MSD_PROJECT;
|
||||
else process.env.MSD_PROJECT = saved.MSD_PROJECT;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -214,31 +214,31 @@ describe('intel tri-state gate hermetic regression (isCapabilityActive cutover)'
|
||||
let tmpConfigDir;
|
||||
let tmpProjectDir;
|
||||
let prevClaudeConfigDir;
|
||||
let prevGsdWorkstream;
|
||||
let prevGsdProject;
|
||||
let prevMsdWorkstream;
|
||||
let prevMsdProject;
|
||||
|
||||
beforeEach(() => {
|
||||
tmpConfigDir = createTempDir('gsd-intel-tristate-cfg-');
|
||||
tmpProjectDir = createTempProject('gsd-intel-tristate-proj-');
|
||||
tmpConfigDir = createTempDir('msd-intel-tristate-cfg-');
|
||||
tmpProjectDir = createTempProject('msd-intel-tristate-proj-');
|
||||
|
||||
prevClaudeConfigDir = process.env.CLAUDE_CONFIG_DIR;
|
||||
prevGsdWorkstream = process.env.GSD_WORKSTREAM;
|
||||
prevGsdProject = process.env.GSD_PROJECT;
|
||||
// Empty CLAUDE_CONFIG_DIR (no .gsd-surface.json) → defaults to 'full' profile.
|
||||
prevMsdWorkstream = process.env.MSD_WORKSTREAM;
|
||||
prevMsdProject = process.env.MSD_PROJECT;
|
||||
// Empty CLAUDE_CONFIG_DIR (no .msd-surface.json) → defaults to 'full' profile.
|
||||
// Intel has skills:[] so it is vacuously installed+surfaced+enabled.
|
||||
// Active = configActivation = intel.enabled in config.
|
||||
process.env.CLAUDE_CONFIG_DIR = tmpConfigDir;
|
||||
delete process.env.GSD_WORKSTREAM;
|
||||
delete process.env.GSD_PROJECT;
|
||||
delete process.env.MSD_WORKSTREAM;
|
||||
delete process.env.MSD_PROJECT;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (prevClaudeConfigDir === undefined) delete process.env.CLAUDE_CONFIG_DIR;
|
||||
else process.env.CLAUDE_CONFIG_DIR = prevClaudeConfigDir;
|
||||
if (prevGsdWorkstream === undefined) delete process.env.GSD_WORKSTREAM;
|
||||
else process.env.GSD_WORKSTREAM = prevGsdWorkstream;
|
||||
if (prevGsdProject === undefined) delete process.env.GSD_PROJECT;
|
||||
else process.env.GSD_PROJECT = prevGsdProject;
|
||||
if (prevMsdWorkstream === undefined) delete process.env.MSD_WORKSTREAM;
|
||||
else process.env.MSD_WORKSTREAM = prevMsdWorkstream;
|
||||
if (prevMsdProject === undefined) delete process.env.MSD_PROJECT;
|
||||
else process.env.MSD_PROJECT = prevMsdProject;
|
||||
|
||||
cleanup(tmpConfigDir);
|
||||
cleanup(tmpProjectDir);
|
||||
@@ -339,10 +339,10 @@ describe('intelQuery', () => {
|
||||
// Empty CLAUDE_CONFIG_DIR defaults to 'full' profile → all caps surfaced.
|
||||
surfacedConfigDir = makeSurfacedConfigDir();
|
||||
savedEnv = saveSurfacedEnv();
|
||||
delete process.env.GSD_RUNTIME;
|
||||
delete process.env.MSD_RUNTIME;
|
||||
process.env.CLAUDE_CONFIG_DIR = surfacedConfigDir;
|
||||
delete process.env.GSD_WORKSTREAM;
|
||||
delete process.env.GSD_PROJECT;
|
||||
delete process.env.MSD_WORKSTREAM;
|
||||
delete process.env.MSD_PROJECT;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -454,10 +454,10 @@ describe('#3885 (ADR-3473 §8.5): intel query recursion bound + truncation signa
|
||||
enableIntel(planningDir);
|
||||
surfacedConfigDir = makeSurfacedConfigDir();
|
||||
savedEnv = saveSurfacedEnv();
|
||||
delete process.env.GSD_RUNTIME;
|
||||
delete process.env.MSD_RUNTIME;
|
||||
process.env.CLAUDE_CONFIG_DIR = surfacedConfigDir;
|
||||
delete process.env.GSD_WORKSTREAM;
|
||||
delete process.env.GSD_PROJECT;
|
||||
delete process.env.MSD_WORKSTREAM;
|
||||
delete process.env.MSD_PROJECT;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -521,7 +521,7 @@ describe('#3885 (ADR-3473 §8.5): intel query recursion bound + truncation signa
|
||||
// never appear.
|
||||
test('T4: deeplyNestedIntelDoesNotOverflowTheStack', () => {
|
||||
writeNestedFixtureText(12000);
|
||||
const result = runGsdTools(['intel', 'query', 'needle-here'], tmpDir);
|
||||
const result = runMsdTools(['intel', 'query', 'needle-here'], tmpDir);
|
||||
assert.strictEqual(result.success, true, `must exit 0 (no stack overflow), got: ${result.error}`);
|
||||
assert.ok(
|
||||
!/Maximum call stack size exceeded/.test(result.error || ''),
|
||||
@@ -580,10 +580,10 @@ describe('#3885 (ADR-3473 §8.5): safeReadJson distinguishes absent from unreada
|
||||
enableIntel(planningDir);
|
||||
surfacedConfigDir = makeSurfacedConfigDir();
|
||||
savedEnv = saveSurfacedEnv();
|
||||
delete process.env.GSD_RUNTIME;
|
||||
delete process.env.MSD_RUNTIME;
|
||||
process.env.CLAUDE_CONFIG_DIR = surfacedConfigDir;
|
||||
delete process.env.GSD_WORKSTREAM;
|
||||
delete process.env.GSD_PROJECT;
|
||||
delete process.env.MSD_WORKSTREAM;
|
||||
delete process.env.MSD_PROJECT;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -685,10 +685,10 @@ describe('intelStatus', () => {
|
||||
enableIntel(planningDir);
|
||||
surfacedConfigDir = makeSurfacedConfigDir();
|
||||
savedEnv = saveSurfacedEnv();
|
||||
delete process.env.GSD_RUNTIME;
|
||||
delete process.env.MSD_RUNTIME;
|
||||
process.env.CLAUDE_CONFIG_DIR = surfacedConfigDir;
|
||||
delete process.env.GSD_WORKSTREAM;
|
||||
delete process.env.GSD_PROJECT;
|
||||
delete process.env.MSD_WORKSTREAM;
|
||||
delete process.env.MSD_PROJECT;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -750,10 +750,10 @@ describe('#3885 (ADR-3473 §8.5): intelStatus read_error field', () => {
|
||||
enableIntel(planningDir);
|
||||
surfacedConfigDir = makeSurfacedConfigDir();
|
||||
savedEnv = saveSurfacedEnv();
|
||||
delete process.env.GSD_RUNTIME;
|
||||
delete process.env.MSD_RUNTIME;
|
||||
process.env.CLAUDE_CONFIG_DIR = surfacedConfigDir;
|
||||
delete process.env.GSD_WORKSTREAM;
|
||||
delete process.env.GSD_PROJECT;
|
||||
delete process.env.MSD_WORKSTREAM;
|
||||
delete process.env.MSD_PROJECT;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -828,10 +828,10 @@ describe('intelDiff', () => {
|
||||
enableIntel(planningDir);
|
||||
surfacedConfigDir = makeSurfacedConfigDir();
|
||||
savedEnv = saveSurfacedEnv();
|
||||
delete process.env.GSD_RUNTIME;
|
||||
delete process.env.MSD_RUNTIME;
|
||||
process.env.CLAUDE_CONFIG_DIR = surfacedConfigDir;
|
||||
delete process.env.GSD_WORKSTREAM;
|
||||
delete process.env.GSD_PROJECT;
|
||||
delete process.env.MSD_WORKSTREAM;
|
||||
delete process.env.MSD_PROJECT;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -899,10 +899,10 @@ describe('#3885 (ADR-3473 §8.5): intelDiff read_error / no_baseline false-verdi
|
||||
enableIntel(planningDir);
|
||||
surfacedConfigDir = makeSurfacedConfigDir();
|
||||
savedEnv = saveSurfacedEnv();
|
||||
delete process.env.GSD_RUNTIME;
|
||||
delete process.env.MSD_RUNTIME;
|
||||
process.env.CLAUDE_CONFIG_DIR = surfacedConfigDir;
|
||||
delete process.env.GSD_WORKSTREAM;
|
||||
delete process.env.GSD_PROJECT;
|
||||
delete process.env.MSD_WORKSTREAM;
|
||||
delete process.env.MSD_PROJECT;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -1015,10 +1015,10 @@ describe('intelSnapshot', () => {
|
||||
enableIntel(planningDir);
|
||||
surfacedConfigDir = makeSurfacedConfigDir();
|
||||
savedEnv = saveSurfacedEnv();
|
||||
delete process.env.GSD_RUNTIME;
|
||||
delete process.env.MSD_RUNTIME;
|
||||
process.env.CLAUDE_CONFIG_DIR = surfacedConfigDir;
|
||||
delete process.env.GSD_WORKSTREAM;
|
||||
delete process.env.GSD_PROJECT;
|
||||
delete process.env.MSD_WORKSTREAM;
|
||||
delete process.env.MSD_PROJECT;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -1056,10 +1056,10 @@ describe('intelValidate', () => {
|
||||
enableIntel(planningDir);
|
||||
surfacedConfigDir = makeSurfacedConfigDir();
|
||||
savedEnv = saveSurfacedEnv();
|
||||
delete process.env.GSD_RUNTIME;
|
||||
delete process.env.MSD_RUNTIME;
|
||||
process.env.CLAUDE_CONFIG_DIR = surfacedConfigDir;
|
||||
delete process.env.GSD_WORKSTREAM;
|
||||
delete process.env.GSD_PROJECT;
|
||||
delete process.env.MSD_WORKSTREAM;
|
||||
delete process.env.MSD_PROJECT;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -1355,9 +1355,9 @@ describe('intelExtractExports', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ─── CLI routing via gsd-tools ──────────────────────────────────────────────
|
||||
// ─── CLI routing via msd-tools ──────────────────────────────────────────────
|
||||
|
||||
describe('gsd-tools intel subcommands', () => {
|
||||
describe('msd-tools intel subcommands', () => {
|
||||
let tmpDir;
|
||||
let surfacedConfigDir;
|
||||
let savedEnv;
|
||||
@@ -1368,10 +1368,10 @@ describe('gsd-tools intel subcommands', () => {
|
||||
// Negative-path tests (disabled) still work because intel.enabled is not set by default.
|
||||
surfacedConfigDir = makeSurfacedConfigDir();
|
||||
savedEnv = saveSurfacedEnv();
|
||||
delete process.env.GSD_RUNTIME;
|
||||
delete process.env.MSD_RUNTIME;
|
||||
process.env.CLAUDE_CONFIG_DIR = surfacedConfigDir;
|
||||
delete process.env.GSD_WORKSTREAM;
|
||||
delete process.env.GSD_PROJECT;
|
||||
delete process.env.MSD_WORKSTREAM;
|
||||
delete process.env.MSD_PROJECT;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -1381,14 +1381,14 @@ describe('gsd-tools intel subcommands', () => {
|
||||
});
|
||||
|
||||
test('intel status returns disabled message when not enabled', () => {
|
||||
const result = runGsdTools(['intel', 'status'], tmpDir);
|
||||
const result = runMsdTools(['intel', 'status'], tmpDir);
|
||||
assert.strictEqual(result.success, true);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.strictEqual(output.disabled, true);
|
||||
});
|
||||
|
||||
test('intel query returns disabled message when not enabled', () => {
|
||||
const result = runGsdTools(['intel', 'query', 'test'], tmpDir);
|
||||
const result = runMsdTools(['intel', 'query', 'test'], tmpDir);
|
||||
assert.strictEqual(result.success, true);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.strictEqual(output.disabled, true);
|
||||
@@ -1396,7 +1396,7 @@ describe('gsd-tools intel subcommands', () => {
|
||||
|
||||
test('intel status returns file status when enabled', () => {
|
||||
enableIntel(path.join(tmpDir, '.planning'));
|
||||
const result = runGsdTools(['intel', 'status'], tmpDir);
|
||||
const result = runMsdTools(['intel', 'status'], tmpDir);
|
||||
assert.strictEqual(result.success, true);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.ok(output.files);
|
||||
@@ -1405,7 +1405,7 @@ describe('gsd-tools intel subcommands', () => {
|
||||
|
||||
test('intel validate reports errors for missing files when enabled', () => {
|
||||
enableIntel(path.join(tmpDir, '.planning'));
|
||||
const result = runGsdTools(['intel', 'validate'], tmpDir);
|
||||
const result = runMsdTools(['intel', 'validate'], tmpDir);
|
||||
assert.strictEqual(result.success, true);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.strictEqual(output.valid, false);
|
||||
@@ -1413,21 +1413,21 @@ describe('gsd-tools intel subcommands', () => {
|
||||
});
|
||||
|
||||
test('unknown intel subcommand error lists api-surface', () => {
|
||||
const result = runGsdTools(['intel', 'nonexistent-subcmd'], tmpDir);
|
||||
const result = runMsdTools(['intel', 'nonexistent-subcmd'], tmpDir);
|
||||
assert.strictEqual(result.success, false);
|
||||
const errorText = result.error || '';
|
||||
assert.ok(errorText.includes('api-surface'), 'error message must list api-surface');
|
||||
});
|
||||
|
||||
test('flag-looking intel subcommand treated as unknown, not crash', () => {
|
||||
const result = runGsdTools(['intel', '--api-surface'], tmpDir);
|
||||
const result = runMsdTools(['intel', '--api-surface'], tmpDir);
|
||||
assert.strictEqual(result.success, false);
|
||||
const errorText = result.error || '';
|
||||
assert.ok(errorText.includes('Unknown intel subcommand'), 'must emit typed unknown-subcommand error');
|
||||
});
|
||||
|
||||
test('intel api-surface returns disabled message when not enabled', () => {
|
||||
const result = runGsdTools(['intel', 'api-surface'], tmpDir);
|
||||
const result = runMsdTools(['intel', 'api-surface'], tmpDir);
|
||||
assert.strictEqual(result.success, true);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.strictEqual(output.disabled, true);
|
||||
@@ -1443,7 +1443,7 @@ describe('gsd-tools intel subcommands', () => {
|
||||
'intelStatus': { method: 'function', handler: 'intelStatus', role: 'report freshness' },
|
||||
},
|
||||
});
|
||||
const result = runGsdTools(['intel', 'api-surface'], tmpDir);
|
||||
const result = runMsdTools(['intel', 'api-surface'], tmpDir);
|
||||
assert.strictEqual(result.success, true);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.ok(output.written, 'result must include written path');
|
||||
@@ -1467,10 +1467,10 @@ describe('intelApiSurface', () => {
|
||||
planningDir = path.join(tmpDir, '.planning');
|
||||
surfacedConfigDir = makeSurfacedConfigDir();
|
||||
savedEnv = saveSurfacedEnv();
|
||||
delete process.env.GSD_RUNTIME;
|
||||
delete process.env.MSD_RUNTIME;
|
||||
process.env.CLAUDE_CONFIG_DIR = surfacedConfigDir;
|
||||
delete process.env.GSD_WORKSTREAM;
|
||||
delete process.env.GSD_PROJECT;
|
||||
delete process.env.MSD_WORKSTREAM;
|
||||
delete process.env.MSD_PROJECT;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -1585,10 +1585,10 @@ describe('#3885 (ADR-3473 §8.5): intelApiSurface read_error + Incomplete banner
|
||||
enableIntel(planningDir);
|
||||
surfacedConfigDir = makeSurfacedConfigDir();
|
||||
savedEnv = saveSurfacedEnv();
|
||||
delete process.env.GSD_RUNTIME;
|
||||
delete process.env.MSD_RUNTIME;
|
||||
process.env.CLAUDE_CONFIG_DIR = surfacedConfigDir;
|
||||
delete process.env.GSD_WORKSTREAM;
|
||||
delete process.env.GSD_PROJECT;
|
||||
delete process.env.MSD_WORKSTREAM;
|
||||
delete process.env.MSD_PROJECT;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -1671,18 +1671,18 @@ describe('#3885 (ADR-3473 §8.5): intelApiSurface read_error + Incomplete banner
|
||||
});
|
||||
});
|
||||
|
||||
describe('#1000 regression: gsd-intel-updater emits canonical intel filenames', () => {
|
||||
describe('#1000 regression: msd-intel-updater emits canonical intel filenames', () => {
|
||||
// allow-test-rule: source-text-is-the-product
|
||||
// agents/gsd-intel-updater.md IS the system prompt the intel-updater agent runs under; asserting its filename references
|
||||
// agents/msd-intel-updater.md IS the system prompt the intel-updater agent runs under; asserting its filename references
|
||||
// verifies the deployed agent surface contract matches the INTEL_FILES the CLI reads.
|
||||
const agentPromptPath = path.join(__dirname, '..', 'agents', 'gsd-intel-updater.md');
|
||||
const agentPromptPath = path.join(__dirname, '..', 'agents', 'msd-intel-updater.md');
|
||||
const agentPrompt = fs.readFileSync(agentPromptPath, 'utf8');
|
||||
|
||||
test('references every canonical INTEL_FILES name', () => {
|
||||
for (const filename of Object.values(INTEL_FILES)) {
|
||||
assert.ok(
|
||||
agentPrompt.includes(filename),
|
||||
`gsd-intel-updater.md must instruct writing the canonical intel file "${filename}" (from INTEL_FILES) that the gsd-tools intel CLI reads; it was missing.`,
|
||||
`msd-intel-updater.md must instruct writing the canonical intel file "${filename}" (from INTEL_FILES) that the msd-tools intel CLI reads; it was missing.`,
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -1704,7 +1704,7 @@ describe('#1000 regression: gsd-intel-updater emits canonical intel filenames',
|
||||
assert.strictEqual(
|
||||
offendingLines.length,
|
||||
0,
|
||||
`gsd-intel-updater.md must not reference orphaned short name "${shortName}" the intel CLI never reads. Offending line(s):\n${offendingLines.join('\n')}`,
|
||||
`msd-intel-updater.md must not reference orphaned short name "${shortName}" the intel CLI never reads. Offending line(s):\n${offendingLines.join('\n')}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -1712,11 +1712,11 @@ describe('#1000 regression: gsd-intel-updater emits canonical intel filenames',
|
||||
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
// Folded from tests/bug-3258-no-stale-gsd-intel-references.test.cjs — consolidation epic #1969 (B3 #1972)
|
||||
// Folded from tests/bug-3258-no-stale-msd-intel-references.test.cjs — consolidation epic #1969 (B3 #1972)
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
{
|
||||
const { describe: __foldDescribe } = require('node:test');
|
||||
__foldDescribe("folded:bug-3258-no-stale-gsd-intel-references (consolidation epic #1969 B3 #1972)", () => {
|
||||
__foldDescribe("folded:bug-3258-no-stale-msd-intel-references (consolidation epic #1969 B3 #1972)", () => {
|
||||
// allow-test-rule: source-text-is-the-product — workflow, reference, and docs .md files (see #3258)
|
||||
// ARE what the runtime loads and what users read; asserting their text content
|
||||
// tests the deployed skill surface contract, not implementation internals.
|
||||
@@ -1725,26 +1725,26 @@ describe('#1000 regression: gsd-intel-updater emits canonical intel filenames',
|
||||
|
||||
// Regression tests for bug #3258.
|
||||
//
|
||||
// PR #2790 folded `/gsd-intel` into `/gsd-map-codebase --query`. After that
|
||||
// PR #2790 folded `/msd-intel` into `/msd-map-codebase --query`. After that
|
||||
// consolidation, five prose occurrences in two source files continued to
|
||||
// reference the retired `/gsd-intel` slash command. Users invoking the wizard
|
||||
// reference the retired `/msd-intel` slash command. Users invoking the wizard
|
||||
// were directed to a command that no longer exists.
|
||||
//
|
||||
// Fix: replace each `/gsd-intel` (the retired user-facing slash command) with
|
||||
// `/gsd-map-codebase --query` in:
|
||||
// - gsd-core/references/planning-config.md
|
||||
// - gsd-core/workflows/settings.md
|
||||
// Fix: replace each `/msd-intel` (the retired user-facing slash command) with
|
||||
// `/msd-map-codebase --query` in:
|
||||
// - msd-core/references/planning-config.md
|
||||
// - msd-core/workflows/settings.md
|
||||
// - docs/INVENTORY.md
|
||||
// - docs/USER-GUIDE.md
|
||||
// - docs/FEATURES.md
|
||||
//
|
||||
// Allowed: `gsd-intel-updater` (still-valid agent name, no leading slash),
|
||||
// Allowed: `msd-intel-updater` (still-valid agent name, no leading slash),
|
||||
// `intel.cjs` / `intel.enabled` / `intel.*` (internal backend, not user command),
|
||||
// CHANGELOG.md (historical record), test files themselves.
|
||||
//
|
||||
// This test distinguishes `/gsd-intel` (the retired slash command, leading slash)
|
||||
// from `gsd-intel-updater` (still-valid agent) by grepping for the literal
|
||||
// string `/gsd-intel` and then asserting no match survives after excluding
|
||||
// This test distinguishes `/msd-intel` (the retired slash command, leading slash)
|
||||
// from `msd-intel-updater` (still-valid agent) by grepping for the literal
|
||||
// string `/msd-intel` and then asserting no match survives after excluding
|
||||
// the `-updater` suffix.
|
||||
|
||||
const { describe, test } = require('node:test');
|
||||
@@ -1770,40 +1770,40 @@ function walkMd(dir) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all lines in `src` that contain `/gsd-intel` (the retired slash
|
||||
* command) but are NOT the agent name `gsd-intel-updater`.
|
||||
* We match the literal substring `/gsd-intel` (with leading slash) and then
|
||||
* Return all lines in `src` that contain `/msd-intel` (the retired slash
|
||||
* command) but are NOT the agent name `msd-intel-updater`.
|
||||
* We match the literal substring `/msd-intel` (with leading slash) and then
|
||||
* exclude any line where the match is immediately followed by `-updater`.
|
||||
*/
|
||||
function staleLinesIn(src) {
|
||||
return src.split('\n').filter((line) => {
|
||||
if (!line.includes('/gsd-intel')) return false;
|
||||
if (!line.includes('/msd-intel')) return false;
|
||||
// Remove all occurrences of the valid agent name; if nothing remains, skip.
|
||||
const stripped = line.replace(/\/gsd-intel-updater/g, '');
|
||||
return stripped.includes('/gsd-intel');
|
||||
const stripped = line.replace(/\/msd-intel-updater/g, '');
|
||||
return stripped.includes('/msd-intel');
|
||||
});
|
||||
}
|
||||
|
||||
const SOURCE_DIRS = [
|
||||
path.join(ROOT, 'commands', 'gsd'),
|
||||
path.join(ROOT, 'gsd-core', 'workflows'),
|
||||
path.join(ROOT, 'gsd-core', 'references'),
|
||||
path.join(ROOT, 'commands', 'msd'),
|
||||
path.join(ROOT, 'msd-core', 'workflows'),
|
||||
path.join(ROOT, 'msd-core', 'references'),
|
||||
path.join(ROOT, 'agents'),
|
||||
path.join(ROOT, 'docs'),
|
||||
];
|
||||
|
||||
describe('#3258: no stale /gsd-intel slash-command references in product source dirs', () => {
|
||||
describe('#3258: no stale /msd-intel slash-command references in product source dirs', () => {
|
||||
for (const dir of SOURCE_DIRS) {
|
||||
const files = walkMd(dir);
|
||||
for (const file of files) {
|
||||
const rel = path.relative(ROOT, file);
|
||||
|
||||
// Allowed exclusions:
|
||||
// - CHANGELOG.md is a historical record; /gsd-intel appears in release notes
|
||||
// - CHANGELOG.md is a historical record; /msd-intel appears in release notes
|
||||
// - test files (under tests/) are excluded automatically by SOURCE_DIRS scope
|
||||
if (rel === 'CHANGELOG.md') continue;
|
||||
|
||||
test(`${rel} has no stale /gsd-intel references`, () => {
|
||||
test(`${rel} has no stale /msd-intel references`, () => {
|
||||
let src;
|
||||
try {
|
||||
src = fs.readFileSync(file, 'utf8');
|
||||
@@ -1816,8 +1816,8 @@ describe('#3258: no stale /gsd-intel slash-command references in product source
|
||||
staleLines.length,
|
||||
0,
|
||||
[
|
||||
`${rel} contains ${staleLines.length} stale /gsd-intel reference(s).`,
|
||||
'Replace with /gsd-map-codebase --query (retired by PR #2790).',
|
||||
`${rel} contains ${staleLines.length} stale /msd-intel reference(s).`,
|
||||
'Replace with /msd-map-codebase --query (retired by PR #2790).',
|
||||
'Stale lines:',
|
||||
...staleLines.map((l) => ` ${l.trim()}`),
|
||||
].join('\n'),
|
||||
@@ -1838,10 +1838,10 @@ describe('#3258: no stale /gsd-intel slash-command references in product source
|
||||
/**
|
||||
* Regression test for bug #2351
|
||||
*
|
||||
* gsd-intel-updater used hardcoded canonical paths (`agents/*.md`,
|
||||
* `commands/gsd/*.md`, `hooks/*.js`, etc.) that assumed the standard
|
||||
* msd-intel-updater used hardcoded canonical paths (`agents/*.md`,
|
||||
* `commands/msd/*.md`, `hooks/*.js`, etc.) that assumed the standard
|
||||
* `.claude/` runtime layout. Under a `.kilo` install, the runtime root is
|
||||
* `.kilo/`, and the command directory is `command/` (not `commands/gsd/`).
|
||||
* `.kilo/`, and the command directory is `command/` (not `commands/msd/`).
|
||||
* Globs against the old paths returned no results, producing semantically
|
||||
* empty intel files (`"entries": {}`).
|
||||
*
|
||||
@@ -1856,13 +1856,13 @@ const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const AGENT_PATH = path.join(__dirname, '..', 'agents', 'gsd-intel-updater.md');
|
||||
const AGENT_PATH = path.join(__dirname, '..', 'agents', 'msd-intel-updater.md');
|
||||
|
||||
describe('bug #2351: intel updater kilo layout support', () => {
|
||||
let content;
|
||||
|
||||
test('agent file exists', () => {
|
||||
assert.ok(fs.existsSync(AGENT_PATH), 'agents/gsd-intel-updater.md must exist');
|
||||
assert.ok(fs.existsSync(AGENT_PATH), 'agents/msd-intel-updater.md must exist');
|
||||
content = fs.readFileSync(AGENT_PATH, 'utf-8');
|
||||
});
|
||||
|
||||
@@ -1875,7 +1875,7 @@ describe('bug #2351: intel updater kilo layout support', () => {
|
||||
content.includes('layout detection');
|
||||
assert.ok(
|
||||
hasDetection,
|
||||
'gsd-intel-updater.md must instruct the agent to detect the runtime layout ' +
|
||||
'msd-intel-updater.md must instruct the agent to detect the runtime layout ' +
|
||||
'(.kilo vs .claude) before resolving canonical paths (#2351)'
|
||||
);
|
||||
});
|
||||
@@ -1888,11 +1888,11 @@ describe('bug #2351: intel updater kilo layout support', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('scope section maps .kilo/command path (not commands/gsd)', () => {
|
||||
test('scope section maps .kilo/command path (not commands/msd)', () => {
|
||||
content = content || fs.readFileSync(AGENT_PATH, 'utf-8');
|
||||
assert.ok(
|
||||
content.includes('.kilo/command'),
|
||||
'scope section must include .kilo/command path — kilo uses "command/" not "commands/gsd/"'
|
||||
'scope section must include .kilo/command path — kilo uses "command/" not "commands/msd/"'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1923,7 +1923,7 @@ describe('bug #2351: intel updater kilo layout support', () => {
|
||||
const { describe: __foldDescribe } = require('node:test');
|
||||
__foldDescribe("folded:bug-3290-intel-updater-layout-block (consolidation epic #1969 B7 #1976)", () => {
|
||||
// allow-test-rule: source-text-is-the-product (see #3290)
|
||||
// agents/gsd-intel-updater.md IS the deployed agent instruction set. Asserting
|
||||
// agents/msd-intel-updater.md IS the deployed agent instruction set. Asserting
|
||||
// its text content tests the deployed behaviour contract, not internal implementation.
|
||||
|
||||
'use strict';
|
||||
@@ -1931,18 +1931,18 @@ describe('bug #2351: intel updater kilo layout support', () => {
|
||||
/**
|
||||
* Regression tests for bug #3290.
|
||||
*
|
||||
* The "Runtime layout detection" block in gsd-intel-updater.md ran
|
||||
* The "Runtime layout detection" block in msd-intel-updater.md ran
|
||||
* unconditionally on every project analysed, emitting:
|
||||
*
|
||||
* Layout detection returned "unknown" — this project is not a GSD-system
|
||||
* installation (no `.claude/gsd-core/` or `.kilo/` runtime root).
|
||||
* Layout detection returned "unknown" — this project is not a MSD-system
|
||||
* installation (no `.claude/msd-core/` or `.kilo/` runtime root).
|
||||
*
|
||||
* for every ordinary (non-GSD-framework) user project. The verdict was already
|
||||
* ignored by Steps 2-6 on non-GSD projects. The block was dead-but-noisy.
|
||||
* for every ordinary (non-MSD-framework) user project. The verdict was already
|
||||
* ignored by Steps 2-6 on non-MSD projects. The block was dead-but-noisy.
|
||||
*
|
||||
* Fix: gate the runtime bash detection on a positive "is-this-the-framework-
|
||||
* repo" check (package.json name === "@opengsd/gsd-core") so it runs ONLY when
|
||||
* analysing the GSD framework's own repo, OR remove the block entirely if no
|
||||
* repo" check (package.json name === "@golem15/msd-core") so it runs ONLY when
|
||||
* analysing the MSD framework's own repo, OR remove the block entirely if no
|
||||
* downstream consumers exist.
|
||||
*
|
||||
* Group A — gating contract:
|
||||
@@ -1961,7 +1961,7 @@ const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const AGENT_PATH = path.join(ROOT, 'agents', 'gsd-intel-updater.md');
|
||||
const AGENT_PATH = path.join(ROOT, 'agents', 'msd-intel-updater.md');
|
||||
|
||||
// ─── helpers ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -1986,7 +1986,7 @@ describe('bug #3290 — Group A: layout-detection block must be gated or absent'
|
||||
let content;
|
||||
|
||||
test('agent file exists', () => {
|
||||
assert.ok(fs.existsSync(AGENT_PATH), 'agents/gsd-intel-updater.md must exist');
|
||||
assert.ok(fs.existsSync(AGENT_PATH), 'agents/msd-intel-updater.md must exist');
|
||||
content = fs.readFileSync(AGENT_PATH, 'utf-8');
|
||||
});
|
||||
|
||||
@@ -2010,23 +2010,23 @@ describe('bug #3290 — Group A: layout-detection block must be gated or absent'
|
||||
|
||||
// Block is still present. Verify it is surrounded by a framework-repo gate.
|
||||
// A valid gate checks package.json name or an equivalent positive signal
|
||||
// that the current project IS the GSD framework's own repo.
|
||||
// that the current project IS the MSD framework's own repo.
|
||||
const hasFrameworkGate =
|
||||
content.includes('@opengsd/gsd-core') ||
|
||||
content.includes('@golem15/msd-core') ||
|
||||
content.includes('is-this-the-framework') ||
|
||||
content.includes('framework repo') ||
|
||||
content.includes('Only run') ||
|
||||
/if.*package\.json.*gsd-core/i.test(content) ||
|
||||
/Only.*layout detection.*GSD framework/i.test(content) ||
|
||||
/if.*package\.json.*msd-core/i.test(content) ||
|
||||
/Only.*layout detection.*MSD framework/i.test(content) ||
|
||||
/Only.*layout detection.*framework/i.test(content);
|
||||
|
||||
assert.ok(
|
||||
hasFrameworkGate,
|
||||
'agents/gsd-intel-updater.md contains a bare unconditional layout-detection ' +
|
||||
'agents/msd-intel-updater.md contains a bare unconditional layout-detection ' +
|
||||
'bash block (`ls -d .kilo ... || echo unknown`) with no surrounding ' +
|
||||
'framework-repo gate (#3290). ' +
|
||||
'Either remove the block entirely, or wrap it in a check like:\n' +
|
||||
' if [[ "$(jq -r \'.name // ""\' package.json 2>/dev/null)" == "@opengsd/gsd-core" ]]; then\n' +
|
||||
' if [[ "$(jq -r \'.name // ""\' package.json 2>/dev/null)" == "@golem15/msd-core" ]]; then\n' +
|
||||
' # ... detection block ...\n' +
|
||||
' fi'
|
||||
);
|
||||
@@ -2039,14 +2039,14 @@ describe('bug #3290 — Group A: layout-detection block must be gated or absent'
|
||||
describe('bug #3290 — Group B: layout-detection verdict has no downstream consumers', () => {
|
||||
const SOURCE_DIRS = [
|
||||
path.join(ROOT, 'agents'),
|
||||
path.join(ROOT, 'commands', 'gsd'),
|
||||
path.join(ROOT, 'gsd-core', 'workflows'),
|
||||
path.join(ROOT, 'commands', 'msd'),
|
||||
path.join(ROOT, 'msd-core', 'workflows'),
|
||||
];
|
||||
|
||||
/**
|
||||
* Lines that reference the three possible verdict values emitted by the
|
||||
* detection block: "claude", "kilo", "unknown" — ONLY as the verdict output
|
||||
* of the gsd-intel-updater layout detection (not general runtime references).
|
||||
* of the msd-intel-updater layout detection (not general runtime references).
|
||||
*
|
||||
* We look for the specific phrase "Layout detection returned" which is the
|
||||
* sentinel the noisy output line uses.
|
||||
@@ -2073,7 +2073,7 @@ describe('bug #3290 — Group B: layout-detection verdict has no downstream cons
|
||||
matches.length,
|
||||
0,
|
||||
'Expected zero files to contain "Layout detection returned" (the noisy verdict ' +
|
||||
'phrase from the gsd-intel-updater layout-detection block). Found:\n' +
|
||||
'phrase from the msd-intel-updater layout-detection block). Found:\n' +
|
||||
matches.map(({ rel, lines }) =>
|
||||
` ${rel}:\n${lines.map(({ n, line }) => ` L${n}: ${line.trim()}`).join('\n')}`
|
||||
).join('\n')
|
||||
@@ -2084,7 +2084,7 @@ describe('bug #3290 — Group B: layout-detection verdict has no downstream cons
|
||||
// The verdict was: echo "kilo" | echo "claude" | echo "unknown"
|
||||
// If any file references "Layout detection returned unknown" as an instruction
|
||||
// to consume, that would be a consumer. We verify none exist outside of
|
||||
// the producing file (gsd-intel-updater.md).
|
||||
// the producing file (msd-intel-updater.md).
|
||||
const verdictConsumerPattern = /Layout detection returned.*(unknown|claude|kilo)/i;
|
||||
const consumers = [];
|
||||
|
||||
@@ -2092,7 +2092,7 @@ describe('bug #3290 — Group B: layout-detection verdict has no downstream cons
|
||||
const files = walkMd(dir);
|
||||
for (const file of files) {
|
||||
// Exclude the producer itself — it defines the message, not consumes it
|
||||
if (path.basename(file) === 'gsd-intel-updater.md') continue;
|
||||
if (path.basename(file) === 'msd-intel-updater.md') continue;
|
||||
const src = fs.readFileSync(file, 'utf-8');
|
||||
if (verdictConsumerPattern.test(src)) {
|
||||
consumers.push(path.relative(ROOT, file));
|
||||
|
||||
Reference in New Issue
Block a user