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,5 +1,5 @@
|
||||
// allow-test-rule: source-text-is-the-product
|
||||
// commands/gsd/*.md files ARE the deployed skill surface. Testing their
|
||||
// commands/msd/*.md files ARE the deployed skill surface. Testing their
|
||||
// contract tests the runtime behaviour.
|
||||
|
||||
'use strict';
|
||||
@@ -7,12 +7,12 @@
|
||||
/**
|
||||
* Command Contract tests (ADR-0002)
|
||||
*
|
||||
* Authoritative behavioral contract for every commands/gsd/*.md file.
|
||||
* Authoritative behavioral contract for every commands/msd/*.md file.
|
||||
* Replaces scattered coverage in enh-2790-skill-consolidation and
|
||||
* bug-3135-capture-backlog-workflow for the full-surface contract checks.
|
||||
*
|
||||
* Contract:
|
||||
* 1. name: present, non-empty, starts with gsd: or gsd-
|
||||
* 1. name: present, non-empty, starts with msd: or msd-
|
||||
* 2. description: present, non-empty
|
||||
* 3. allowed-tools: present, non-empty, all entries from CANONICAL_TOOLS
|
||||
* 4. execution_context @-refs: every reference resolves to an existing file
|
||||
@@ -25,8 +25,8 @@ const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const COMMANDS_DIR = path.join(ROOT, 'commands', 'gsd');
|
||||
const GSD_ROOT = path.join(ROOT, 'gsd-core');
|
||||
const COMMANDS_DIR = path.join(ROOT, 'commands', 'msd');
|
||||
const MSD_ROOT = path.join(ROOT, 'msd-core');
|
||||
|
||||
const {
|
||||
CANONICAL_TOOLS,
|
||||
@@ -51,12 +51,12 @@ const commandFiles = fs
|
||||
|
||||
describe('command contract: name field (ADR-0002)', () => {
|
||||
for (const { name, full } of commandFiles) {
|
||||
test(`${name}: name: present and starts with gsd: or gsd-`, () => {
|
||||
test(`${name}: name: present and starts with msd: or msd-`, () => {
|
||||
const fm = parseFrontmatter(fs.readFileSync(full, 'utf-8'));
|
||||
assert.ok(fm.name && fm.name.trim(), `${name}: name: field missing or empty`);
|
||||
assert.ok(
|
||||
/^gsd[:-]/.test(fm.name.trim()),
|
||||
`${name}: name: must start with "gsd:" or "gsd-", got "${fm.name.trim()}"`,
|
||||
/^msd[:-]/.test(fm.name.trim()),
|
||||
`${name}: name: must start with "msd:" or "msd-", got "${fm.name.trim()}"`,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -99,7 +99,7 @@ describe('command contract: execution_context @-refs resolve (ADR-0002)', () =>
|
||||
const refs = executionContextRefs(fs.readFileSync(full, 'utf-8'));
|
||||
for (const { normalized } of refs) {
|
||||
assert.ok(
|
||||
fs.existsSync(path.join(GSD_ROOT, normalized)),
|
||||
fs.existsSync(path.join(MSD_ROOT, normalized)),
|
||||
`${name}: execution_context @-ref "${normalized}" does not exist — ` +
|
||||
'create the file or remove the reference',
|
||||
);
|
||||
@@ -125,21 +125,21 @@ describe('command contract: execution_context @-refs on own line (ADR-0002)', ()
|
||||
describe('#3561 — workflowPathRefs resolver', () => {
|
||||
test('eager @-include', () => {
|
||||
assert.deepEqual(
|
||||
workflowPathRefs('@~/.claude/gsd-core/workflows/x.md'),
|
||||
workflowPathRefs('@~/.claude/msd-core/workflows/x.md'),
|
||||
['workflows/x.md'],
|
||||
);
|
||||
});
|
||||
|
||||
test('lazy tilde path', () => {
|
||||
assert.deepEqual(
|
||||
workflowPathRefs('read `~/.claude/gsd-core/workflows/x.md` now'),
|
||||
workflowPathRefs('read `~/.claude/msd-core/workflows/x.md` now'),
|
||||
['workflows/x.md'],
|
||||
);
|
||||
});
|
||||
|
||||
test('repo-relative path', () => {
|
||||
assert.deepEqual(
|
||||
workflowPathRefs('see gsd-core/workflows/x.md'),
|
||||
workflowPathRefs('see msd-core/workflows/x.md'),
|
||||
['workflows/x.md'],
|
||||
);
|
||||
});
|
||||
@@ -234,7 +234,7 @@ describe('#3561 — workflowPathRefs resolver', () => {
|
||||
test('binds to the --fast line, not the whole file', () => {
|
||||
const syntheticFile = [
|
||||
'- If it is `--fast`: strip the flag, run the scan workflow.',
|
||||
'<!-- see gsd-core/workflows/scan.md -->',
|
||||
'<!-- see msd-core/workflows/scan.md -->',
|
||||
].join('\n');
|
||||
const fastLine = syntheticFile
|
||||
.split(/\r?\n/)
|
||||
@@ -248,7 +248,7 @@ describe('#3561 — workflowPathRefs resolver', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#3561 — /gsd-map-codebase --fast routes to a loadable workflow', () => {
|
||||
describe('#3561 — /msd-map-codebase --fast routes to a loadable workflow', () => {
|
||||
const mapCodebasePath = path.join(COMMANDS_DIR, 'map-codebase.md');
|
||||
const mapCodebaseContent = fs.readFileSync(mapCodebasePath, 'utf-8');
|
||||
|
||||
@@ -258,7 +258,7 @@ describe('#3561 — /gsd-map-codebase --fast routes to a loadable workflow', ()
|
||||
.find(line => /^-\s*If it is\s*`--fast`/.test(line));
|
||||
assert.ok(
|
||||
fastLine,
|
||||
'#3561: commands/gsd/map-codebase.md has no "--fast" routing bullet ' +
|
||||
'#3561: commands/msd/map-codebase.md has no "--fast" routing bullet ' +
|
||||
'(expected a line matching /^-\\s*If it is\\s*`--fast`/) — the routing logic is missing entirely',
|
||||
);
|
||||
const refs = workflowPathRefs(fastLine);
|
||||
@@ -282,8 +282,8 @@ describe('#3561 — every workflow path referenced by a command exists on disk',
|
||||
const refs = workflowPathRefs(fs.readFileSync(full, 'utf-8'));
|
||||
for (const ref of refs) {
|
||||
assert.ok(
|
||||
fs.existsSync(path.join(GSD_ROOT, ref)),
|
||||
`${name}: referenced workflow path "${ref}" does not exist under ${GSD_ROOT}`,
|
||||
fs.existsSync(path.join(MSD_ROOT, ref)),
|
||||
`${name}: referenced workflow path "${ref}" does not exist under ${MSD_ROOT}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -294,60 +294,60 @@ describe('#3561 — every workflow path referenced by a command exists on disk',
|
||||
describe('#3560 — unreachableWorkflows closure', () => {
|
||||
test('a planted orphan is reported', () => {
|
||||
const loaderContents = ['load workflows/live.md'];
|
||||
const gsdFiles = new Map();
|
||||
const msdFiles = new Map();
|
||||
const workflowPaths = ['workflows/live.md', 'workflows/orphan.md'];
|
||||
assert.deepEqual(
|
||||
unreachableWorkflows(loaderContents, gsdFiles, workflowPaths),
|
||||
unreachableWorkflows(loaderContents, msdFiles, workflowPaths),
|
||||
['workflows/orphan.md'],
|
||||
);
|
||||
});
|
||||
|
||||
test('eager include reaches', () => {
|
||||
const loaderContents = ['@~/.claude/gsd-core/workflows/a.md'];
|
||||
const gsdFiles = new Map();
|
||||
const loaderContents = ['@~/.claude/msd-core/workflows/a.md'];
|
||||
const msdFiles = new Map();
|
||||
const workflowPaths = ['workflows/a.md'];
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, gsdFiles, workflowPaths), []);
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, msdFiles, workflowPaths), []);
|
||||
});
|
||||
|
||||
test('lazy path reaches', () => {
|
||||
const loaderContents = ['read `gsd-core/workflows/a.md`'];
|
||||
const gsdFiles = new Map();
|
||||
const loaderContents = ['read `msd-core/workflows/a.md`'];
|
||||
const msdFiles = new Map();
|
||||
const workflowPaths = ['workflows/a.md'];
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, gsdFiles, workflowPaths), []);
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, msdFiles, workflowPaths), []);
|
||||
});
|
||||
|
||||
test('parent-relative reaches', () => {
|
||||
const loaderContents = ['run execute-phase/steps/s.md'];
|
||||
const gsdFiles = new Map();
|
||||
const msdFiles = new Map();
|
||||
const workflowPaths = ['workflows/execute-phase/steps/s.md'];
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, gsdFiles, workflowPaths), []);
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, msdFiles, workflowPaths), []);
|
||||
});
|
||||
|
||||
test('reaches transitively', () => {
|
||||
const loaderContents = ['see workflows/a.md'];
|
||||
const gsdFiles = new Map([['workflows/a.md', 'see workflows/b.md']]);
|
||||
const msdFiles = new Map([['workflows/a.md', 'see workflows/b.md']]);
|
||||
const workflowPaths = ['workflows/a.md', 'workflows/b.md'];
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, gsdFiles, workflowPaths), []);
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, msdFiles, workflowPaths), []);
|
||||
});
|
||||
|
||||
test('reaches at depth three', () => {
|
||||
const loaderContents = ['see workflows/a.md'];
|
||||
const gsdFiles = new Map([
|
||||
const msdFiles = new Map([
|
||||
['workflows/a.md', 'see workflows/b.md'],
|
||||
['workflows/b.md', 'see workflows/c.md'],
|
||||
]);
|
||||
const workflowPaths = ['workflows/a.md', 'workflows/b.md', 'workflows/c.md'];
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, gsdFiles, workflowPaths), []);
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, msdFiles, workflowPaths), []);
|
||||
});
|
||||
|
||||
test('a self-reference does not reach', () => {
|
||||
// Nothing in loaderContents mentions self.md; the fact that self.md's
|
||||
// own body references itself must not count as reachability.
|
||||
const loaderContents = [];
|
||||
const gsdFiles = new Map([['workflows/self.md', 'see workflows/self.md']]);
|
||||
const msdFiles = new Map([['workflows/self.md', 'see workflows/self.md']]);
|
||||
const workflowPaths = ['workflows/self.md'];
|
||||
assert.deepEqual(
|
||||
unreachableWorkflows(loaderContents, gsdFiles, workflowPaths),
|
||||
unreachableWorkflows(loaderContents, msdFiles, workflowPaths),
|
||||
['workflows/self.md'],
|
||||
);
|
||||
});
|
||||
@@ -356,13 +356,13 @@ describe('#3560 — unreachableWorkflows closure', () => {
|
||||
// x and y point only at each other; no loader points at either. The
|
||||
// island looks connected from the inside but no runtime ever opens it.
|
||||
const loaderContents = [];
|
||||
const gsdFiles = new Map([
|
||||
const msdFiles = new Map([
|
||||
['workflows/x.md', 'see workflows/y.md'],
|
||||
['workflows/y.md', 'see workflows/x.md'],
|
||||
]);
|
||||
const workflowPaths = ['workflows/x.md', 'workflows/y.md'];
|
||||
assert.deepEqual(
|
||||
unreachableWorkflows(loaderContents, gsdFiles, workflowPaths),
|
||||
unreachableWorkflows(loaderContents, msdFiles, workflowPaths),
|
||||
['workflows/x.md', 'workflows/y.md'],
|
||||
);
|
||||
});
|
||||
@@ -371,70 +371,70 @@ describe('#3560 — unreachableWorkflows closure', () => {
|
||||
// a -> b -> c -> a. All three are reachable from the loader; the walk
|
||||
// must still terminate rather than looping forever on the cycle.
|
||||
const loaderContents = ['see workflows/a.md'];
|
||||
const gsdFiles = new Map([
|
||||
const msdFiles = new Map([
|
||||
['workflows/a.md', 'see workflows/b.md'],
|
||||
['workflows/b.md', 'see workflows/c.md'],
|
||||
['workflows/c.md', 'see workflows/a.md'],
|
||||
]);
|
||||
const workflowPaths = ['workflows/a.md', 'workflows/b.md', 'workflows/c.md'];
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, gsdFiles, workflowPaths), []);
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, msdFiles, workflowPaths), []);
|
||||
});
|
||||
|
||||
test('a docs-only mention does not reach (Goodhart guard: mentioning a path is not the same as loading it)', () => {
|
||||
// Simulates a hypothetical prose/docs file that names orphan.md — that
|
||||
// string is simply never included in loaderContents (or gsdFiles), which
|
||||
// string is simply never included in loaderContents (or msdFiles), which
|
||||
// is exactly what "a docs mention" looks like to this function: absent.
|
||||
const loaderContents = [];
|
||||
const gsdFiles = new Map();
|
||||
const msdFiles = new Map();
|
||||
const workflowPaths = ['workflows/orphan.md'];
|
||||
assert.deepEqual(
|
||||
unreachableWorkflows(loaderContents, gsdFiles, workflowPaths),
|
||||
unreachableWorkflows(loaderContents, msdFiles, workflowPaths),
|
||||
['workflows/orphan.md'],
|
||||
);
|
||||
});
|
||||
|
||||
test('a dangling reference reaches nothing', () => {
|
||||
const loaderContents = ['see workflows/missing.md'];
|
||||
const gsdFiles = new Map();
|
||||
const msdFiles = new Map();
|
||||
const workflowPaths = ['workflows/real-orphan.md'];
|
||||
assert.doesNotThrow(() => unreachableWorkflows(loaderContents, gsdFiles, workflowPaths));
|
||||
assert.doesNotThrow(() => unreachableWorkflows(loaderContents, msdFiles, workflowPaths));
|
||||
assert.deepEqual(
|
||||
unreachableWorkflows(loaderContents, gsdFiles, workflowPaths),
|
||||
unreachableWorkflows(loaderContents, msdFiles, workflowPaths),
|
||||
['workflows/real-orphan.md'],
|
||||
);
|
||||
});
|
||||
|
||||
test('empty workflow set', () => {
|
||||
const loaderContents = ['see workflows/a.md'];
|
||||
const gsdFiles = new Map();
|
||||
const msdFiles = new Map();
|
||||
const workflowPaths = [];
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, gsdFiles, workflowPaths), []);
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, msdFiles, workflowPaths), []);
|
||||
});
|
||||
|
||||
test('no loaders means nothing is reached', () => {
|
||||
const loaderContents = [];
|
||||
const gsdFiles = new Map();
|
||||
const msdFiles = new Map();
|
||||
const workflowPaths = ['workflows/a.md'];
|
||||
assert.deepEqual(
|
||||
unreachableWorkflows(loaderContents, gsdFiles, workflowPaths),
|
||||
unreachableWorkflows(loaderContents, msdFiles, workflowPaths),
|
||||
['workflows/a.md'],
|
||||
);
|
||||
});
|
||||
|
||||
test('CRLF-tolerant', () => {
|
||||
const loaderContents = ['workflows/a.md\r\nworkflows/b.md'];
|
||||
const gsdFiles = new Map();
|
||||
const msdFiles = new Map();
|
||||
const workflowPaths = ['workflows/a.md', 'workflows/b.md'];
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, gsdFiles, workflowPaths), []);
|
||||
assert.deepEqual(unreachableWorkflows(loaderContents, msdFiles, workflowPaths), []);
|
||||
});
|
||||
|
||||
test('reports exactly the orphan among many', () => {
|
||||
const reachable = Array.from({ length: 152 }, (_, i) => `workflows/gen-${i}.md`);
|
||||
const loaderContents = reachable.slice();
|
||||
const gsdFiles = new Map();
|
||||
const msdFiles = new Map();
|
||||
const orphan = 'workflows/orphan-152.md';
|
||||
const workflowPaths = [...reachable, orphan];
|
||||
const result = unreachableWorkflows(loaderContents, gsdFiles, workflowPaths);
|
||||
const result = unreachableWorkflows(loaderContents, msdFiles, workflowPaths);
|
||||
assert.equal(result.length, 1);
|
||||
assert.deepEqual(result, [orphan]);
|
||||
});
|
||||
@@ -446,16 +446,16 @@ describe('#3560 — rule 6 fails the build on a real orphan', () => {
|
||||
// `extra` lets each test layer on exactly the additional state it needs
|
||||
// without coupling test execution order to shared mutable fixture state.
|
||||
function buildBaseFixture(dir) {
|
||||
fs.mkdirSync(path.join(dir, 'commands', 'gsd'), { recursive: true });
|
||||
fs.mkdirSync(path.join(dir, 'gsd-core', 'workflows'), { recursive: true });
|
||||
fs.mkdirSync(path.join(dir, 'commands', 'msd'), { recursive: true });
|
||||
fs.mkdirSync(path.join(dir, 'msd-core', 'workflows'), { recursive: true });
|
||||
fs.mkdirSync(path.join(dir, 'agents'), { recursive: true });
|
||||
fs.mkdirSync(path.join(dir, 'skills'), { recursive: true });
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(dir, 'commands', 'gsd', 'fixture-command.md'),
|
||||
path.join(dir, 'commands', 'msd', 'fixture-command.md'),
|
||||
[
|
||||
'---',
|
||||
'name: gsd:fixture-command',
|
||||
'name: msd:fixture-command',
|
||||
'description: Fixture command for the #3560 rule-6 regression tests.',
|
||||
'allowed-tools:',
|
||||
' - Read',
|
||||
@@ -463,14 +463,14 @@ describe('#3560 — rule 6 fails the build on a real orphan', () => {
|
||||
'---',
|
||||
'',
|
||||
'<execution_context>',
|
||||
'@~/.claude/gsd-core/workflows/live.md',
|
||||
'@~/.claude/msd-core/workflows/live.md',
|
||||
'</execution_context>',
|
||||
'',
|
||||
].join('\n'),
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(dir, 'gsd-core', 'workflows', 'live.md'),
|
||||
path.join(dir, 'msd-core', 'workflows', 'live.md'),
|
||||
'# live workflow\n\nNothing special here.\n',
|
||||
);
|
||||
}
|
||||
@@ -480,7 +480,7 @@ describe('#3560 — rule 6 fails the build on a real orphan', () => {
|
||||
}
|
||||
|
||||
test('clean fixture passes', (t) => {
|
||||
const dir = createTempDir('gsd-3560-clean-');
|
||||
const dir = createTempDir('msd-3560-clean-');
|
||||
t.after(() => cleanup(dir));
|
||||
buildBaseFixture(dir);
|
||||
|
||||
@@ -490,11 +490,11 @@ describe('#3560 — rule 6 fails the build on a real orphan', () => {
|
||||
});
|
||||
|
||||
test('a planted orphan fails the build', (t) => {
|
||||
const dir = createTempDir('gsd-3560-orphan-');
|
||||
const dir = createTempDir('msd-3560-orphan-');
|
||||
t.after(() => cleanup(dir));
|
||||
buildBaseFixture(dir);
|
||||
fs.writeFileSync(
|
||||
path.join(dir, 'gsd-core', 'workflows', 'orphan.md'),
|
||||
path.join(dir, 'msd-core', 'workflows', 'orphan.md'),
|
||||
'# orphan workflow\n\nNo loader references this file.\n',
|
||||
);
|
||||
|
||||
@@ -502,23 +502,23 @@ describe('#3560 — rule 6 fails the build on a real orphan', () => {
|
||||
assert.equal(result.outcome, OUTCOME.EXITED);
|
||||
assert.equal(result.exitCode, 1);
|
||||
assert.ok(
|
||||
(result.stdout + result.stderr).includes('gsd-core/workflows/orphan.md'),
|
||||
(result.stdout + result.stderr).includes('msd-core/workflows/orphan.md'),
|
||||
'diagnostic output must name the orphaned file path',
|
||||
);
|
||||
});
|
||||
|
||||
test('an orphan referenced only from docs/ still fails', (t) => {
|
||||
const dir = createTempDir('gsd-3560-docs-only-');
|
||||
const dir = createTempDir('msd-3560-docs-only-');
|
||||
t.after(() => cleanup(dir));
|
||||
buildBaseFixture(dir);
|
||||
fs.writeFileSync(
|
||||
path.join(dir, 'gsd-core', 'workflows', 'orphan.md'),
|
||||
path.join(dir, 'msd-core', 'workflows', 'orphan.md'),
|
||||
'# orphan workflow\n\nNo loader references this file.\n',
|
||||
);
|
||||
fs.mkdirSync(path.join(dir, 'docs'), { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(dir, 'docs', 'SOMETHING.md'),
|
||||
'See gsd-core/workflows/orphan.md for details.\n',
|
||||
'See msd-core/workflows/orphan.md for details.\n',
|
||||
);
|
||||
|
||||
const result = runLint(dir);
|
||||
@@ -527,17 +527,17 @@ describe('#3560 — rule 6 fails the build on a real orphan', () => {
|
||||
});
|
||||
|
||||
test('an orphan reachable only transitively passes', (t) => {
|
||||
const dir = createTempDir('gsd-3560-transitive-');
|
||||
const dir = createTempDir('msd-3560-transitive-');
|
||||
t.after(() => cleanup(dir));
|
||||
buildBaseFixture(dir);
|
||||
fs.writeFileSync(
|
||||
path.join(dir, 'gsd-core', 'workflows', 'orphan.md'),
|
||||
path.join(dir, 'msd-core', 'workflows', 'orphan.md'),
|
||||
'# orphan workflow\n\nReachable transitively via live.md.\n',
|
||||
);
|
||||
// live.md itself now names orphan.md; live.md is eagerly loaded by the
|
||||
// fixture command, so orphan.md becomes reachable one hop out.
|
||||
fs.writeFileSync(
|
||||
path.join(dir, 'gsd-core', 'workflows', 'live.md'),
|
||||
path.join(dir, 'msd-core', 'workflows', 'live.md'),
|
||||
'# live workflow\n\nSee workflows/orphan.md for the follow-up.\n',
|
||||
);
|
||||
|
||||
@@ -551,10 +551,10 @@ describe('#3560 — deleted orphan workflows do not ship', () => {
|
||||
const deletedBasenames = ['discovery-phase.md', 'plan-milestone-gaps.md'];
|
||||
|
||||
for (const basename of deletedBasenames) {
|
||||
test(`${basename}: does not exist under gsd-core/workflows/`, () => {
|
||||
test(`${basename}: does not exist under msd-core/workflows/`, () => {
|
||||
assert.ok(
|
||||
!fs.existsSync(path.join(GSD_ROOT, 'workflows', basename)),
|
||||
`${basename}: expected file to be deleted from gsd-core/workflows/, but it still exists`,
|
||||
!fs.existsSync(path.join(MSD_ROOT, 'workflows', basename)),
|
||||
`${basename}: expected file to be deleted from msd-core/workflows/, but it still exists`,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -566,10 +566,10 @@ describe('#3560 — deleted orphan workflows do not ship', () => {
|
||||
test(`${fixtureFile}: install-tree manifest contains no entry for a deleted workflow`, () => {
|
||||
const manifest = JSON.parse(fs.readFileSync(path.join(fixturesDir, fixtureFile), 'utf-8'));
|
||||
for (const basename of deletedBasenames) {
|
||||
const gsdRelative = `gsd-core/workflows/${basename}`;
|
||||
const msdRelative = `msd-core/workflows/${basename}`;
|
||||
assert.ok(
|
||||
!manifest.includes(gsdRelative),
|
||||
`${fixtureFile}: manifest still lists ${gsdRelative}`,
|
||||
!manifest.includes(msdRelative),
|
||||
`${fixtureFile}: manifest still lists ${msdRelative}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -577,8 +577,8 @@ describe('#3560 — deleted orphan workflows do not ship', () => {
|
||||
|
||||
test('scan.md is untouched by this PR', () => {
|
||||
assert.ok(
|
||||
fs.existsSync(path.join(GSD_ROOT, 'workflows', 'scan.md')),
|
||||
'gsd-core/workflows/scan.md is expected to still exist — this PR only deletes ' +
|
||||
fs.existsSync(path.join(MSD_ROOT, 'workflows', 'scan.md')),
|
||||
'msd-core/workflows/scan.md is expected to still exist — this PR only deletes ' +
|
||||
'discovery-phase.md and plan-milestone-gaps.md',
|
||||
);
|
||||
});
|
||||
@@ -611,7 +611,7 @@ describe('#3560 — INVENTORY carries no row for a deleted workflow', () => {
|
||||
'use strict';
|
||||
|
||||
// allow-test-rule: source-text-is-the-product (see #3168)
|
||||
// commands/gsd/*.md, gsd-core/workflows/*.md, and agents/gsd-*.md are
|
||||
// commands/msd/*.md, msd-core/workflows/*.md, and agents/msd-*.md are
|
||||
// deployed product files. Checking their text IS checking the runtime contract.
|
||||
|
||||
/**
|
||||
@@ -619,7 +619,7 @@ describe('#3560 — INVENTORY carries no row for a deleted workflow', () => {
|
||||
*
|
||||
* The Claude Code subagent-dispatcher tool is named `Agent`. The `Task*` namespace
|
||||
* (TaskCreate, TaskList, TaskGet, TaskUpdate, TaskOutput, TaskStop) is the task
|
||||
* tracker — a distinct tool set. GSD workflows were partially migrated and still
|
||||
* tracker — a distinct tool set. MSD workflows were partially migrated and still
|
||||
* reference `Task(` and `- Task` in allowed-tools/tools frontmatter in most files.
|
||||
*/
|
||||
|
||||
@@ -629,8 +629,8 @@ const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const COMMANDS_DIR = path.join(ROOT, 'commands', 'gsd');
|
||||
const WORKFLOWS_DIR = path.join(ROOT, 'gsd-core', 'workflows');
|
||||
const COMMANDS_DIR = path.join(ROOT, 'commands', 'msd');
|
||||
const WORKFLOWS_DIR = path.join(ROOT, 'msd-core', 'workflows');
|
||||
const AGENTS_DIR = path.join(ROOT, 'agents');
|
||||
|
||||
// Task tracker names — these must NOT be renamed
|
||||
@@ -657,7 +657,7 @@ function extractFrontmatterTools(content) {
|
||||
return toolsBlock.split(',').map(t => t.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
describe('#3168 — commands/gsd: allowed-tools must use Agent not Task', () => {
|
||||
describe('#3168 — commands/msd: allowed-tools must use Agent not Task', () => {
|
||||
const commands = readMdFiles(COMMANDS_DIR);
|
||||
|
||||
for (const cmd of commands) {
|
||||
@@ -710,7 +710,7 @@ describe('#3168 — workflows: prose must use Agent( not Task( for dispatcher ca
|
||||
});
|
||||
|
||||
describe('#3168 — agents: tools frontmatter must use Agent not Task', () => {
|
||||
const agents = readMdFiles(AGENTS_DIR, 'gsd-');
|
||||
const agents = readMdFiles(AGENTS_DIR, 'msd-');
|
||||
|
||||
for (const agent of agents) {
|
||||
test(`${agent.name}: tools must not list Task`, () => {
|
||||
|
||||
Reference in New Issue
Block a user