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:
@@ -40,9 +40,9 @@ const { loadScenario, runScenario, assertWiringIsLive } = require('./qa/scenario
|
||||
const { buildReport } = require('./qa/report.cjs');
|
||||
const { resolveRef } = require('./qa/fixtures/index.cjs');
|
||||
const { resolveWithin, resolveForCompare, isUnderProjectDir } = require('./qa/paths.cjs');
|
||||
const { LOOP_HOST_CONTRACT } = require('../gsd-core/bin/lib/loop-host-contract.cjs');
|
||||
const { extractFrontmatter } = require('../gsd-core/bin/lib/frontmatter.cjs');
|
||||
const { evaluateUatPassed } = require('../gsd-core/bin/lib/uat-predicate.cjs');
|
||||
const { LOOP_HOST_CONTRACT } = require('../msd-core/bin/lib/loop-host-contract.cjs');
|
||||
const { extractFrontmatter } = require('../msd-core/bin/lib/frontmatter.cjs');
|
||||
const { evaluateUatPassed } = require('../msd-core/bin/lib/uat-predicate.cjs');
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
@@ -73,7 +73,7 @@ function collectFixtureMarkdownFiles(dir, out = []) {
|
||||
* WHY skip leading comments/blanks rather than requiring byte-0 `---`: the whole
|
||||
* point of this predicate is to catch DEFECT 1's shape — a provenance comment
|
||||
* placed BEFORE the frontmatter fence, which makes `extractFrontmatter` (which
|
||||
* only recognizes `---` at byte 0, `gsd-core/bin/lib/frontmatter.cjs`) silently
|
||||
* only recognizes `---` at byte 0, `msd-core/bin/lib/frontmatter.cjs`) silently
|
||||
* return `{}`. A predicate that itself required byte-0 `---` would only ever
|
||||
* fire on already-correct fixtures and could never catch this regression class —
|
||||
* it would be exactly as vacuous as the bug it exists to guard against.
|
||||
@@ -142,7 +142,7 @@ describe('RunResult classification', () => {
|
||||
|
||||
test('classifies exit 1 with a warning line before the JSON envelope as STRUCTURED_ERROR', () => {
|
||||
const stderr = [
|
||||
'gsd-tools: warning: unknown config key(s) in .planning/config.json: foo',
|
||||
'msd-tools: warning: unknown config key(s) in .planning/config.json: foo',
|
||||
JSON.stringify({ ok: false, reason: 'bad-config', message: 'config invalid' }),
|
||||
].join('\n');
|
||||
const raw = { exitCode: 1, stdout: '', stderr, argv: ['review-lane'] };
|
||||
@@ -219,7 +219,7 @@ describe('RunResult classification', () => {
|
||||
});
|
||||
|
||||
test('an @file: pointer is followed and its JSON payload parsed', (t) => {
|
||||
const dir = createTempDir('gsd-runresult-pointer-');
|
||||
const dir = createTempDir('msd-runresult-pointer-');
|
||||
t.after(() => cleanup(dir));
|
||||
const payloadPath = path.join(dir, 'payload.json');
|
||||
fs.writeFileSync(payloadPath, JSON.stringify({ ok: true, phases: 4 }), 'utf-8');
|
||||
@@ -301,8 +301,8 @@ describe('oracle self-tests', () => {
|
||||
});
|
||||
|
||||
test('value-hygiene SMELL (not a violation) on an absolute path outside ctx.projectDir', (t) => {
|
||||
const projectDir = createTempDir('gsd-hygiene-outside-');
|
||||
const outsideDir = createTempDir('gsd-hygiene-outside-sibling-');
|
||||
const projectDir = createTempDir('msd-hygiene-outside-');
|
||||
const outsideDir = createTempDir('msd-hygiene-outside-sibling-');
|
||||
t.after(() => {
|
||||
cleanup(projectDir);
|
||||
cleanup(outsideDir);
|
||||
@@ -322,7 +322,7 @@ describe('oracle self-tests', () => {
|
||||
});
|
||||
|
||||
test('value-hygiene has no finding for an in-project path, including one that does not exist yet', (t) => {
|
||||
const projectDir = createTempDir('gsd-hygiene-inproject-');
|
||||
const projectDir = createTempDir('msd-hygiene-inproject-');
|
||||
t.after(() => cleanup(projectDir));
|
||||
// `init` returns paths for files the agent has not written yet — realpath
|
||||
// throws ENOENT on those, and the oracle must not crash or false-positive.
|
||||
@@ -340,8 +340,8 @@ describe('oracle self-tests', () => {
|
||||
});
|
||||
|
||||
test('value-hygiene has no finding (not even a SMELL) for an allowlisted external-path key like agents_dir', (t) => {
|
||||
const projectDir = createTempDir('gsd-hygiene-allowlist-');
|
||||
const outsideDir = createTempDir('gsd-hygiene-allowlist-outside-');
|
||||
const projectDir = createTempDir('msd-hygiene-allowlist-');
|
||||
const outsideDir = createTempDir('msd-hygiene-allowlist-outside-');
|
||||
t.after(() => {
|
||||
cleanup(projectDir);
|
||||
cleanup(outsideDir);
|
||||
@@ -360,8 +360,8 @@ describe('oracle self-tests', () => {
|
||||
});
|
||||
|
||||
test('value-hygiene still SMELLs on a non-allowlisted out-of-project key even when agents_dir is also present', (t) => {
|
||||
const projectDir = createTempDir('gsd-hygiene-mixed-');
|
||||
const outsideDir = createTempDir('gsd-hygiene-mixed-outside-');
|
||||
const projectDir = createTempDir('msd-hygiene-mixed-');
|
||||
const outsideDir = createTempDir('msd-hygiene-mixed-outside-');
|
||||
t.after(() => {
|
||||
cleanup(projectDir);
|
||||
cleanup(outsideDir);
|
||||
@@ -381,7 +381,7 @@ describe('oracle self-tests', () => {
|
||||
});
|
||||
|
||||
test('value-hygiene SMELLs on a sibling-prefix path (containment is path-segment, not string-prefix)', (t) => {
|
||||
const projectDir = createTempDir('gsd-hygiene-sibling-');
|
||||
const projectDir = createTempDir('msd-hygiene-sibling-');
|
||||
t.after(() => cleanup(projectDir));
|
||||
// `${projectDir}-evil` starts with the exact same characters as `projectDir`,
|
||||
// so a naive string-prefix/`.startsWith()` containment check would (wrongly)
|
||||
@@ -393,17 +393,17 @@ describe('oracle self-tests', () => {
|
||||
});
|
||||
|
||||
test('value-hygiene has no finding for a live-command TOKEN under actions[].command (regression guard — FAILS pre-fix, measured)', (t) => {
|
||||
const projectDir = createTempDir('gsd-hygiene-command-token-');
|
||||
const projectDir = createTempDir('msd-hygiene-command-token-');
|
||||
t.after(() => cleanup(projectDir));
|
||||
const outcome = getOracle('value-hygiene').check({
|
||||
result: { json: { actions: [{ id: 'a', command: '/gsd:progress' }] } },
|
||||
result: { json: { actions: [{ id: 'a', command: '/msd:progress' }] } },
|
||||
projectDir,
|
||||
});
|
||||
assert.strictEqual(outcome.ok, true);
|
||||
});
|
||||
|
||||
test('value-hygiene SMELLs on a genuine absolute-path leak stored under a key named "command"', (t) => {
|
||||
const projectDir = createTempDir('gsd-hygiene-command-path-leak-');
|
||||
const projectDir = createTempDir('msd-hygiene-command-path-leak-');
|
||||
t.after(() => cleanup(projectDir));
|
||||
const outcome = getOracle('value-hygiene').check({
|
||||
result: { json: { actions: [{ id: 'a', command: '/Users/someone/elsewhere/bin/tool' }] } },
|
||||
@@ -420,43 +420,43 @@ describe('oracle self-tests', () => {
|
||||
// token prefix. Fixed by requiring the string's first whitespace-delimited
|
||||
// word to be an EXACT member of getLiveCommandTokens().
|
||||
|
||||
test('F1a: a leaked path sharing a prefix with a real token ("/gsd-x/../../../Users/someone/.ssh/id_rsa") IS a SMELL (failing-first against the pre-fix startsWith exemption)', (t) => {
|
||||
const projectDir = createTempDir('gsd-hygiene-sec1-traversal-');
|
||||
test('F1a: a leaked path sharing a prefix with a real token ("/msd-x/../../../Users/someone/.ssh/id_rsa") IS a SMELL (failing-first against the pre-fix startsWith exemption)', (t) => {
|
||||
const projectDir = createTempDir('msd-hygiene-sec1-traversal-');
|
||||
t.after(() => cleanup(projectDir));
|
||||
const outcome = getOracle('value-hygiene').check({
|
||||
result: { json: { command: '/gsd-x/../../../Users/someone/.ssh/id_rsa' } },
|
||||
result: { json: { command: '/msd-x/../../../Users/someone/.ssh/id_rsa' } },
|
||||
projectDir,
|
||||
});
|
||||
assert.strictEqual(outcome.ok, false);
|
||||
assert.strictEqual(outcome.severity, SEVERITY.SMELL);
|
||||
});
|
||||
|
||||
test('F1b: a leaked path sharing a colon-style prefix ("/gsd:/etc/passwd") IS a SMELL', (t) => {
|
||||
const projectDir = createTempDir('gsd-hygiene-sec1-colon-');
|
||||
test('F1b: a leaked path sharing a colon-style prefix ("/msd:/etc/passwd") IS a SMELL', (t) => {
|
||||
const projectDir = createTempDir('msd-hygiene-sec1-colon-');
|
||||
t.after(() => cleanup(projectDir));
|
||||
const outcome = getOracle('value-hygiene').check({
|
||||
result: { json: { command: '/gsd:/etc/passwd' } },
|
||||
result: { json: { command: '/msd:/etc/passwd' } },
|
||||
projectDir,
|
||||
});
|
||||
assert.strictEqual(outcome.ok, false);
|
||||
assert.strictEqual(outcome.severity, SEVERITY.SMELL);
|
||||
});
|
||||
|
||||
test('F1c: an exact live-command token ("/gsd-progress") is exempt (regression guard)', (t) => {
|
||||
const projectDir = createTempDir('gsd-hygiene-sec1-exact-');
|
||||
test('F1c: an exact live-command token ("/msd-progress") is exempt (regression guard)', (t) => {
|
||||
const projectDir = createTempDir('msd-hygiene-sec1-exact-');
|
||||
t.after(() => cleanup(projectDir));
|
||||
const outcome = getOracle('value-hygiene').check({
|
||||
result: { json: { command: '/gsd-progress' } },
|
||||
result: { json: { command: '/msd-progress' } },
|
||||
projectDir,
|
||||
});
|
||||
assert.strictEqual(outcome.ok, true);
|
||||
});
|
||||
|
||||
test('F1d: a live-command token carrying trailing arguments ("/gsd-plan-phase 2") is exempt (the case a naive exact-match-on-the-whole-string breaks)', (t) => {
|
||||
const projectDir = createTempDir('gsd-hygiene-sec1-args-');
|
||||
test('F1d: a live-command token carrying trailing arguments ("/msd-plan-phase 2") is exempt (the case a naive exact-match-on-the-whole-string breaks)', (t) => {
|
||||
const projectDir = createTempDir('msd-hygiene-sec1-args-');
|
||||
t.after(() => cleanup(projectDir));
|
||||
const outcome = getOracle('value-hygiene').check({
|
||||
result: { json: { command: '/gsd-plan-phase 2' } },
|
||||
result: { json: { command: '/msd-plan-phase 2' } },
|
||||
projectDir,
|
||||
});
|
||||
assert.strictEqual(outcome.ok, true);
|
||||
@@ -469,7 +469,7 @@ describe('oracle self-tests', () => {
|
||||
// change that starts false-positiving on ordinary non-path, non-token
|
||||
// command values.
|
||||
test('forward guard: value-hygiene is unaffected by a "command" value that is neither a live-command token nor an absolute path', (t) => {
|
||||
const projectDir = createTempDir('gsd-hygiene-command-plain-');
|
||||
const projectDir = createTempDir('msd-hygiene-command-plain-');
|
||||
t.after(() => cleanup(projectDir));
|
||||
const outcome = getOracle('value-hygiene').check({
|
||||
result: { json: { actions: [{ id: 'a', command: 'progress' }] } },
|
||||
@@ -660,10 +660,10 @@ describe('oracle self-tests', () => {
|
||||
result: {
|
||||
json: {
|
||||
recommended: 'discuss-phase',
|
||||
actions: [{ id: 'discuss-phase', label: 'Discuss', command: '/gsd:discuss-phase', recommended: true }],
|
||||
actions: [{ id: 'discuss-phase', label: 'Discuss', command: '/msd:discuss-phase', recommended: true }],
|
||||
},
|
||||
},
|
||||
liveCommands: ['/gsd:discuss-phase'],
|
||||
liveCommands: ['/msd:discuss-phase'],
|
||||
});
|
||||
assert.strictEqual(outcome.ok, true);
|
||||
});
|
||||
@@ -675,16 +675,16 @@ describe('oracle self-tests', () => {
|
||||
result: {
|
||||
json: {
|
||||
recommended: 'discuss-phase',
|
||||
actions: [{ id: 'discuss-phase', label: 'Discuss', command: '/gsd:not-a-live-command', recommended: true }],
|
||||
actions: [{ id: 'discuss-phase', label: 'Discuss', command: '/msd:not-a-live-command', recommended: true }],
|
||||
},
|
||||
},
|
||||
liveCommands: ['/gsd:discuss-phase'],
|
||||
liveCommands: ['/msd:discuss-phase'],
|
||||
});
|
||||
assert.strictEqual(outcome.ok, false);
|
||||
assert.strictEqual(outcome.severity, SEVERITY.VIOLATION);
|
||||
assert.strictEqual(typeof outcome.detail, 'string');
|
||||
assert.ok(outcome.detail.length > 0);
|
||||
assert.strictEqual(outcome.subject.value, '/gsd:not-a-live-command');
|
||||
assert.strictEqual(outcome.subject.value, '/msd:not-a-live-command');
|
||||
});
|
||||
|
||||
// Forward guard, not a regression test: a payload with nothing for the
|
||||
@@ -694,15 +694,15 @@ describe('oracle self-tests', () => {
|
||||
test('forward guard — A4: a payload with no recommended and no actions/next.command is not engaged (ok)', () => {
|
||||
const outcome = getOracle('routing-validity').check({
|
||||
result: { json: { situation: 'complete', summary: 'done' } },
|
||||
liveCommands: ['/gsd:discuss-phase'],
|
||||
liveCommands: ['/msd:discuss-phase'],
|
||||
});
|
||||
assert.strictEqual(outcome.ok, true);
|
||||
});
|
||||
|
||||
test('routing-validity also validates next.command (state-contract shape)', () => {
|
||||
const outcome = getOracle('routing-validity').check({
|
||||
result: { json: { next: { command: '/gsd:not-live', label: 'x', reason: 'y' } } },
|
||||
liveCommands: ['/gsd:discuss-phase'],
|
||||
result: { json: { next: { command: '/msd:not-live', label: 'x', reason: 'y' } } },
|
||||
liveCommands: ['/msd:discuss-phase'],
|
||||
});
|
||||
assert.strictEqual(outcome.ok, false);
|
||||
assert.strictEqual(outcome.severity, SEVERITY.VIOLATION);
|
||||
@@ -715,44 +715,44 @@ describe('oracle self-tests', () => {
|
||||
// first word matches the live-command prefix set. Each F2a case is
|
||||
// failing-first against the pre-fix two-field-path version.
|
||||
|
||||
const F2A_LIVE_COMMANDS = ['/gsd-progress'];
|
||||
const F2A_LIVE_COMMANDS = ['/msd-progress'];
|
||||
|
||||
test('F2a: a non-live token in recommended_command is a VIOLATION', () => {
|
||||
const outcome = getOracle('routing-validity').check({
|
||||
result: { json: { recommended_command: '/gsd-nope' } },
|
||||
result: { json: { recommended_command: '/msd-nope' } },
|
||||
liveCommands: F2A_LIVE_COMMANDS,
|
||||
});
|
||||
assert.strictEqual(outcome.ok, false);
|
||||
assert.strictEqual(outcome.severity, SEVERITY.VIOLATION);
|
||||
assert.strictEqual(outcome.subject.value, '/gsd-nope');
|
||||
assert.strictEqual(outcome.subject.value, '/msd-nope');
|
||||
});
|
||||
|
||||
test('F2a: a non-live token as a bare STRING next is a VIOLATION', () => {
|
||||
const outcome = getOracle('routing-validity').check({
|
||||
result: { json: { next: '/gsd-nope' } },
|
||||
result: { json: { next: '/msd-nope' } },
|
||||
liveCommands: F2A_LIVE_COMMANDS,
|
||||
});
|
||||
assert.strictEqual(outcome.ok, false);
|
||||
assert.strictEqual(outcome.severity, SEVERITY.VIOLATION);
|
||||
assert.strictEqual(outcome.subject.value, '/gsd-nope');
|
||||
assert.strictEqual(outcome.subject.value, '/msd-nope');
|
||||
});
|
||||
|
||||
test('F2a: a non-live token in steps[].command is a VIOLATION', () => {
|
||||
const outcome = getOracle('routing-validity').check({
|
||||
result: { json: { steps: [{ command: '/gsd-nope' }] } },
|
||||
result: { json: { steps: [{ command: '/msd-nope' }] } },
|
||||
liveCommands: F2A_LIVE_COMMANDS,
|
||||
});
|
||||
assert.strictEqual(outcome.ok, false);
|
||||
assert.strictEqual(outcome.severity, SEVERITY.VIOLATION);
|
||||
assert.strictEqual(outcome.subject.key, 'steps[0].command');
|
||||
assert.strictEqual(outcome.subject.value, '/gsd-nope');
|
||||
assert.strictEqual(outcome.subject.value, '/msd-nope');
|
||||
});
|
||||
|
||||
test('F2b: a LIVE token in recommended_command, string next, and steps[].command each PASS', () => {
|
||||
for (const json of [
|
||||
{ recommended_command: '/gsd-progress' },
|
||||
{ next: '/gsd-progress' },
|
||||
{ steps: [{ command: '/gsd-progress' }] },
|
||||
{ recommended_command: '/msd-progress' },
|
||||
{ next: '/msd-progress' },
|
||||
{ steps: [{ command: '/msd-progress' }] },
|
||||
]) {
|
||||
const outcome = getOracle('routing-validity').check({ result: { json }, liveCommands: F2A_LIVE_COMMANDS });
|
||||
assert.strictEqual(outcome.ok, true, `expected ok for ${JSON.stringify(json)}`);
|
||||
@@ -761,7 +761,7 @@ describe('oracle self-tests', () => {
|
||||
|
||||
test('F2: a non-live token surfaces through next as an array of {command} entries', () => {
|
||||
const outcome = getOracle('routing-validity').check({
|
||||
result: { json: { next: [{ command: '/gsd-nope' }] } },
|
||||
result: { json: { next: [{ command: '/msd-nope' }] } },
|
||||
liveCommands: F2A_LIVE_COMMANDS,
|
||||
});
|
||||
assert.strictEqual(outcome.ok, false);
|
||||
@@ -770,7 +770,7 @@ describe('oracle self-tests', () => {
|
||||
|
||||
test('F2: a non-live token surfaces when actions is an object map instead of an array', () => {
|
||||
const outcome = getOracle('routing-validity').check({
|
||||
result: { json: { actions: { a: { command: '/gsd-nope' } } } },
|
||||
result: { json: { actions: { a: { command: '/msd-nope' } } } },
|
||||
liveCommands: F2A_LIVE_COMMANDS,
|
||||
});
|
||||
assert.strictEqual(outcome.ok, false);
|
||||
@@ -779,7 +779,7 @@ describe('oracle self-tests', () => {
|
||||
|
||||
test('F2: a non-live token surfaces via actions[].next.command', () => {
|
||||
const outcome = getOracle('routing-validity').check({
|
||||
result: { json: { actions: [{ next: { command: '/gsd-nope' } }] } },
|
||||
result: { json: { actions: [{ next: { command: '/msd-nope' } }] } },
|
||||
liveCommands: F2A_LIVE_COMMANDS,
|
||||
});
|
||||
assert.strictEqual(outcome.ok, false);
|
||||
@@ -787,15 +787,15 @@ describe('oracle self-tests', () => {
|
||||
});
|
||||
|
||||
test('shared predicate: a live token routing-validity vouches for is exactly what value-hygiene exempts', (t) => {
|
||||
const projectDir = createTempDir('gsd-shared-predicate-');
|
||||
const projectDir = createTempDir('msd-shared-predicate-');
|
||||
t.after(() => cleanup(projectDir));
|
||||
const routing = getOracle('routing-validity').check({
|
||||
result: { json: { recommended_command: '/gsd-progress' } },
|
||||
result: { json: { recommended_command: '/msd-progress' } },
|
||||
liveCommands: F2A_LIVE_COMMANDS,
|
||||
});
|
||||
assert.strictEqual(routing.ok, true);
|
||||
const hygiene = getOracle('value-hygiene').check({
|
||||
result: { json: { command: '/gsd-progress' } },
|
||||
result: { json: { command: '/msd-progress' } },
|
||||
projectDir,
|
||||
});
|
||||
assert.strictEqual(hygiene.ok, true);
|
||||
@@ -930,7 +930,7 @@ describe('scenario DSL validation', () => {
|
||||
});
|
||||
|
||||
function writeScenarioFile(t, obj) {
|
||||
const dir = createTempDir('gsd-scenario-dsl-');
|
||||
const dir = createTempDir('msd-scenario-dsl-');
|
||||
t.after(() => cleanup(dir));
|
||||
const file = path.join(dir, 'scenario.json');
|
||||
fs.writeFileSync(file, JSON.stringify(obj), 'utf-8');
|
||||
@@ -1129,7 +1129,7 @@ describe('mutations', () => {
|
||||
let mutDir;
|
||||
|
||||
beforeEach(() => {
|
||||
mutDir = createTempDir('gsd-mutations-file-');
|
||||
mutDir = createTempDir('msd-mutations-file-');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -1159,7 +1159,7 @@ describe('mutations', () => {
|
||||
|
||||
describe('path containment', () => {
|
||||
test('resolveWithin rejects a traversing relPath, naming it and the base', (t) => {
|
||||
const dir = createTempDir('gsd-pathguard-');
|
||||
const dir = createTempDir('msd-pathguard-');
|
||||
t.after(() => cleanup(dir));
|
||||
assert.throws(() => resolveWithin(dir, '../../etc/hosts'), (err) => {
|
||||
assert.ok(err instanceof Error);
|
||||
@@ -1171,7 +1171,7 @@ describe('path containment', () => {
|
||||
});
|
||||
|
||||
test('resolveWithin rejects an absolute relPath', (t) => {
|
||||
const dir = createTempDir('gsd-pathguard-abs-');
|
||||
const dir = createTempDir('msd-pathguard-abs-');
|
||||
t.after(() => cleanup(dir));
|
||||
assert.throws(() => resolveWithin(dir, '/etc/hosts'), (err) => {
|
||||
assert.strictEqual(err.code, 'EPATHESCAPE');
|
||||
@@ -1182,13 +1182,13 @@ describe('path containment', () => {
|
||||
});
|
||||
|
||||
test('resolveWithin rejects a sibling-prefix escape (path-segment, not string-prefix, containment)', (t) => {
|
||||
const dir = createTempDir('gsd-pathguard-sibling-');
|
||||
const dir = createTempDir('msd-pathguard-sibling-');
|
||||
t.after(() => cleanup(dir));
|
||||
assert.throws(() => resolveWithin(dir, `../${path.basename(dir)}-evil/x`), /escapes/);
|
||||
});
|
||||
|
||||
test('resolveWithin accepts an in-project path that does not exist yet', (t) => {
|
||||
const dir = createTempDir('gsd-pathguard-notyet-');
|
||||
const dir = createTempDir('msd-pathguard-notyet-');
|
||||
t.after(() => cleanup(dir));
|
||||
const resolved = resolveWithin(dir, 'deep/not/created/yet.md');
|
||||
assert.strictEqual(typeof resolved, 'string');
|
||||
@@ -1196,14 +1196,14 @@ describe('path containment', () => {
|
||||
});
|
||||
|
||||
test('LoopWalk#writeArtifact rejects a traversing relPath', (t) => {
|
||||
const walk = LoopWalk.create({ fixture: 'greenfield', prefix: 'gsd-pathguard-write-' });
|
||||
const walk = LoopWalk.create({ fixture: 'greenfield', prefix: 'msd-pathguard-write-' });
|
||||
t.after(() => walk.cleanup());
|
||||
assert.throws(() => walk.writeArtifact('../../escaped.md', 'x'), /escapes|absolute/);
|
||||
assert.strictEqual(fs.existsSync(path.join(path.dirname(walk.dir), 'escaped.md')), false);
|
||||
});
|
||||
|
||||
test('LoopWalk#writeArtifact still writes a legitimate in-project path after the guard', (t) => {
|
||||
const walk = LoopWalk.create({ fixture: 'greenfield', prefix: 'gsd-pathguard-write-ok-' });
|
||||
const walk = LoopWalk.create({ fixture: 'greenfield', prefix: 'msd-pathguard-write-ok-' });
|
||||
t.after(() => walk.cleanup());
|
||||
walk.writeArtifact('.planning/PROJECT.md', '# ok\n');
|
||||
assert.strictEqual(fs.existsSync(path.join(walk.dir, '.planning', 'PROJECT.md')), true);
|
||||
@@ -1217,8 +1217,8 @@ describe('path containment', () => {
|
||||
// `fs.realpathSync.native` performs that expansion; plain `fs.realpathSync` does not, which
|
||||
// was the root cause. Injected here (rather than skipped on non-Windows) via the
|
||||
// `realpathFn` seam so this regression is caught on every platform, not just Windows.
|
||||
const shortForm = 'C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\gsd-loop-walk-GP8Q6U';
|
||||
const longForm = 'C:/Users/runneradmin/AppData/Local/Temp/gsd-loop-walk-GP8Q6U';
|
||||
const shortForm = 'C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\msd-loop-walk-GP8Q6U';
|
||||
const longForm = 'C:/Users/runneradmin/AppData/Local/Temp/msd-loop-walk-GP8Q6U';
|
||||
const fakeNativeRealpath = (p) => (p === shortForm ? longForm : p);
|
||||
|
||||
const resolvedProjectDir = resolveForCompare(shortForm, fakeNativeRealpath);
|
||||
@@ -1230,8 +1230,8 @@ describe('path containment', () => {
|
||||
});
|
||||
|
||||
test('isUnderProjectDir positive control: a genuinely outside path is still reported as outside, even through the injected realpathFn seam', () => {
|
||||
const projectDir = 'C:/Users/runneradmin/AppData/Local/Temp/gsd-loop-walk-GP8Q6U';
|
||||
const outsideDir = 'C:/Users/runneradmin/AppData/Local/Temp/gsd-loop-walk-OTHER';
|
||||
const projectDir = 'C:/Users/runneradmin/AppData/Local/Temp/msd-loop-walk-GP8Q6U';
|
||||
const outsideDir = 'C:/Users/runneradmin/AppData/Local/Temp/msd-loop-walk-OTHER';
|
||||
const identityRealpath = (p) => p;
|
||||
|
||||
const resolvedProjectDir = resolveForCompare(projectDir, identityRealpath);
|
||||
@@ -1241,19 +1241,19 @@ describe('path containment', () => {
|
||||
});
|
||||
|
||||
test('mutations apply("delete", ...) rejects a traversing relPath', (t) => {
|
||||
const mutDir = createTempDir('gsd-pathguard-delete-');
|
||||
const mutDir = createTempDir('msd-pathguard-delete-');
|
||||
t.after(() => cleanup(mutDir));
|
||||
assert.throws(() => apply('delete', { dir: mutDir, relPath: '../../../../etc/hosts' }), /escapes|absolute/);
|
||||
});
|
||||
|
||||
test('mutations apply("symlink", ...) rejects a traversing relPath', (t) => {
|
||||
const mutDir = createTempDir('gsd-pathguard-symlink-');
|
||||
const mutDir = createTempDir('msd-pathguard-symlink-');
|
||||
t.after(() => cleanup(mutDir));
|
||||
assert.throws(() => apply('symlink', { dir: mutDir, relPath: '../../../../etc/hosts' }), /escapes|absolute/);
|
||||
});
|
||||
|
||||
test('loadScenario rejects a mutate.target that traverses out of the project, at load time', (t) => {
|
||||
const dir = createTempDir('gsd-pathguard-scenario-mutate-');
|
||||
const dir = createTempDir('msd-pathguard-scenario-mutate-');
|
||||
t.after(() => cleanup(dir));
|
||||
const file = path.join(dir, 's.json');
|
||||
fs.writeFileSync(file, JSON.stringify({
|
||||
@@ -1265,7 +1265,7 @@ describe('path containment', () => {
|
||||
});
|
||||
|
||||
test('loadScenario rejects an absolute mutate.target, at load time', (t) => {
|
||||
const dir = createTempDir('gsd-pathguard-scenario-mutate-abs-');
|
||||
const dir = createTempDir('msd-pathguard-scenario-mutate-abs-');
|
||||
t.after(() => cleanup(dir));
|
||||
const file = path.join(dir, 's.json');
|
||||
fs.writeFileSync(file, JSON.stringify({
|
||||
@@ -1277,7 +1277,7 @@ describe('path containment', () => {
|
||||
});
|
||||
|
||||
test('loadScenario rejects an agent.write key that traverses out of the project, at load time', (t) => {
|
||||
const dir = createTempDir('gsd-pathguard-scenario-write-');
|
||||
const dir = createTempDir('msd-pathguard-scenario-write-');
|
||||
t.after(() => cleanup(dir));
|
||||
const file = path.join(dir, 's.json');
|
||||
fs.writeFileSync(file, JSON.stringify({
|
||||
@@ -1289,7 +1289,7 @@ describe('path containment', () => {
|
||||
});
|
||||
|
||||
test('loadScenario rejects an absolute agent.write key, at load time', (t) => {
|
||||
const dir = createTempDir('gsd-pathguard-scenario-write-abs-');
|
||||
const dir = createTempDir('msd-pathguard-scenario-write-abs-');
|
||||
t.after(() => cleanup(dir));
|
||||
const file = path.join(dir, 's.json');
|
||||
fs.writeFileSync(file, JSON.stringify({
|
||||
@@ -1307,7 +1307,7 @@ describe('greenfield walk (end-to-end)', () => {
|
||||
before(() => {
|
||||
// tests/helpers/live-command-registry.cjs's real API: getLiveCommandTokens()
|
||||
// returns a memoized Set<string> of every live slash-command token derived
|
||||
// from commands/gsd/*.md frontmatter (e.g. "/gsd-plan-phase"). The
|
||||
// from commands/msd/*.md frontmatter (e.g. "/msd-plan-phase"). The
|
||||
// routing-validity oracle (#3913) checks command tokens carried by
|
||||
// result.json.actions[].command / result.json.next.command against this
|
||||
// set — never the bare result.json.recommended action id.
|
||||
@@ -1495,7 +1495,7 @@ describe('fixture integrity', () => {
|
||||
* WHY module-content, not module-frontmatter: this guards against defect classes
|
||||
* where a provenance comment (or any other byte-0 preamble) silently defeats
|
||||
* `extractFrontmatter`, which only recognizes a frontmatter block that starts at
|
||||
* byte 0 of the file (`gsd-core/bin/lib/frontmatter.cjs` — `content.startsWith('---\n')`).
|
||||
* byte 0 of the file (`msd-core/bin/lib/frontmatter.cjs` — `content.startsWith('---\n')`).
|
||||
*/
|
||||
const fixtureFiles = collectFixtureMarkdownFiles(FIXTURES_ROOT);
|
||||
|
||||
@@ -1540,7 +1540,7 @@ describe('fixture integrity', () => {
|
||||
let dir;
|
||||
|
||||
beforeEach(() => {
|
||||
dir = createTempDir('gsd-uat-fixture-integrity-');
|
||||
dir = createTempDir('msd-uat-fixture-integrity-');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -1569,8 +1569,8 @@ describe('fixture integrity', () => {
|
||||
|
||||
describe('walk isolation', () => {
|
||||
test('two LoopWalk instances never share a project directory', (t) => {
|
||||
const walkA = LoopWalk.create({ fixture: 'greenfield', prefix: 'gsd-walk-isolation-a-' });
|
||||
const walkB = LoopWalk.create({ fixture: 'greenfield', prefix: 'gsd-walk-isolation-b-' });
|
||||
const walkA = LoopWalk.create({ fixture: 'greenfield', prefix: 'msd-walk-isolation-a-' });
|
||||
const walkB = LoopWalk.create({ fixture: 'greenfield', prefix: 'msd-walk-isolation-b-' });
|
||||
t.after(() => {
|
||||
walkA.cleanup();
|
||||
walkB.cleanup();
|
||||
@@ -1579,7 +1579,7 @@ describe('walk isolation', () => {
|
||||
});
|
||||
|
||||
test('a read-only command does not change the stat snapshot', (t) => {
|
||||
const walk = LoopWalk.create({ fixture: 'greenfield', prefix: 'gsd-walk-isolation-readonly-' });
|
||||
const walk = LoopWalk.create({ fixture: 'greenfield', prefix: 'msd-walk-isolation-readonly-' });
|
||||
t.after(() => walk.cleanup());
|
||||
const statsBefore = walk.statSnapshot();
|
||||
walk.run('progress');
|
||||
@@ -1595,7 +1595,7 @@ describe('worktree-concurrency (dedicated — trajectory 9 is not expressible as
|
||||
* `scenario.cjs#runScenario` drives exactly one `LoopWalk` through a
|
||||
* strictly sequential `steps` array — `LoopWalk#run` itself is built on
|
||||
* `execFileSync` (see `loop-walk.cjs`), so within the DSL there is no way to
|
||||
* have two `gsd-tools` invocations genuinely in flight at the same wall-clock
|
||||
* have two `msd-tools` invocations genuinely in flight at the same wall-clock
|
||||
* moment. "Two LoopWalk instances driving simultaneously" (issue #2966's
|
||||
* ninth trajectory) is therefore implemented here directly against
|
||||
* `child_process.execFile` (async) so both subprocesses are launched before
|
||||
@@ -1603,12 +1603,12 @@ describe('worktree-concurrency (dedicated — trajectory 9 is not expressible as
|
||||
* up as one.
|
||||
*/
|
||||
|
||||
/** Absolute path to the gsd-tools entry point, mirrored from `helpers.cjs`'s `TOOLS_PATH`. */
|
||||
const TOOLS_PATH = path.join(__dirname, '..', 'gsd-core', 'bin', 'gsd-tools.cjs');
|
||||
/** Absolute path to the msd-tools entry point, mirrored from `helpers.cjs`'s `TOOLS_PATH`. */
|
||||
const TOOLS_PATH = path.join(__dirname, '..', 'msd-core', 'bin', 'msd-tools.cjs');
|
||||
|
||||
/**
|
||||
* Runs a single `gsd-tools --json-errors <argv>` invocation asynchronously
|
||||
* against `dir`, sanitizing ambient `GSD_*` env vars exactly as
|
||||
* Runs a single `msd-tools --json-errors <argv>` invocation asynchronously
|
||||
* against `dir`, sanitizing ambient `MSD_*` env vars exactly as
|
||||
* `LoopWalk#run` does (see that method's header for why), and pinning the
|
||||
* clock so both concurrent invocations are reproducible.
|
||||
*
|
||||
@@ -1620,9 +1620,9 @@ describe('worktree-concurrency (dedicated — trajectory 9 is not expressible as
|
||||
/** @type {Record<string, string|undefined>} */
|
||||
const sanitize = {};
|
||||
for (const key of Object.keys(process.env)) {
|
||||
if (key.startsWith('GSD_')) sanitize[key] = undefined;
|
||||
if (key.startsWith('MSD_')) sanitize[key] = undefined;
|
||||
}
|
||||
const env = { ...sanitize, GSD_TEST_MODE: '1', GSD_NOW_MS: '1767225600000' };
|
||||
const env = { ...sanitize, MSD_TEST_MODE: '1', MSD_NOW_MS: '1767225600000' };
|
||||
const startedAtMs = Date.now();
|
||||
const { stdout } = await execFileAsync(
|
||||
process.execPath,
|
||||
@@ -1633,8 +1633,8 @@ describe('worktree-concurrency (dedicated — trajectory 9 is not expressible as
|
||||
}
|
||||
|
||||
test('two LoopWalk projects driven via genuinely concurrent async subprocesses stay isolated', async (t) => {
|
||||
const walkA = LoopWalk.create({ fixture: 'greenfield', prefix: 'gsd-concurrency-a-' });
|
||||
const walkB = LoopWalk.create({ fixture: 'greenfield', prefix: 'gsd-concurrency-b-' });
|
||||
const walkA = LoopWalk.create({ fixture: 'greenfield', prefix: 'msd-concurrency-a-' });
|
||||
const walkB = LoopWalk.create({ fixture: 'greenfield', prefix: 'msd-concurrency-b-' });
|
||||
t.after(() => {
|
||||
walkA.cleanup();
|
||||
walkB.cleanup();
|
||||
@@ -1703,7 +1703,7 @@ describe('qa-smell-ratchet gate (#3597)', () => {
|
||||
mutation: null,
|
||||
mutationNoop: false,
|
||||
mutationObserved: false,
|
||||
repro: 'cd /tmp/x && node gsd-core/bin/gsd-tools.cjs --ws alpha progress',
|
||||
repro: 'cd /tmp/x && node msd-core/bin/msd-tools.cjs --ws alpha progress',
|
||||
};
|
||||
return {
|
||||
reportVersion: 1,
|
||||
@@ -1749,7 +1749,7 @@ describe('qa-smell-ratchet gate (#3597)', () => {
|
||||
mutation: null,
|
||||
mutationNoop: false,
|
||||
mutationObserved: false,
|
||||
repro: 'cd /tmp/x && node gsd-core/bin/gsd-tools.cjs --ws alpha progress',
|
||||
repro: 'cd /tmp/x && node msd-core/bin/msd-tools.cjs --ws alpha progress',
|
||||
};
|
||||
if (fields.expectFailures !== undefined) step.expectFailures = fields.expectFailures;
|
||||
if (fields.violations !== undefined) step.violations = fields.violations;
|
||||
|
||||
Reference in New Issue
Block a user