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.
93 lines
3.2 KiB
JavaScript
93 lines
3.2 KiB
JavaScript
/**
|
|
* /msd mvp-phase command — frontmatter contract test
|
|
* Verifies the command exists, has required frontmatter fields, and
|
|
* points to the workflow file.
|
|
*/
|
|
const { test, describe } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const CMD = path.join(__dirname, '..', 'commands', 'msd', 'mvp-phase.md');
|
|
|
|
function parseCommandContract(content) {
|
|
const lines = content.split(/\r?\n/);
|
|
const firstFence = lines.indexOf('---');
|
|
const secondFence = lines.indexOf('---', firstFence + 1);
|
|
assert.ok(firstFence === 0 && secondFence > 0, 'command must start with YAML frontmatter');
|
|
|
|
const frontmatterLines = lines.slice(firstFence + 1, secondFence);
|
|
const frontmatter = {};
|
|
const allowedTools = [];
|
|
let inAllowedTools = false;
|
|
|
|
for (const raw of frontmatterLines) {
|
|
const line = raw.trim();
|
|
if (line === 'allowed-tools:') {
|
|
inAllowedTools = true;
|
|
continue;
|
|
}
|
|
if (inAllowedTools) {
|
|
if (line.startsWith('- ')) {
|
|
allowedTools.push(line.slice(2).trim());
|
|
continue;
|
|
}
|
|
inAllowedTools = false;
|
|
}
|
|
const sep = line.indexOf(':');
|
|
if (sep > 0) {
|
|
frontmatter[line.slice(0, sep).trim()] = line.slice(sep + 1).trim();
|
|
}
|
|
}
|
|
|
|
const executionContextStart = lines.findIndex(line => line.trim() === '<execution_context>');
|
|
const executionContextEnd = lines.findIndex(
|
|
(line, idx) => idx > executionContextStart && line.trim() === '</execution_context>'
|
|
);
|
|
const executionContextRefs = executionContextStart >= 0 && executionContextEnd > executionContextStart
|
|
? lines.slice(executionContextStart + 1, executionContextEnd).map(line => line.trim()).filter(Boolean)
|
|
: [];
|
|
|
|
return {
|
|
name: frontmatter.name || '',
|
|
argumentHint: frontmatter['argument-hint'] || '',
|
|
executionContextRefs,
|
|
allowedTools,
|
|
};
|
|
}
|
|
|
|
describe('/msd mvp-phase command frontmatter', () => {
|
|
test('command file exists', () => {
|
|
assert.ok(fs.existsSync(CMD), `${CMD} must exist`);
|
|
});
|
|
|
|
test('frontmatter declares correct command name', () => {
|
|
const contract = parseCommandContract(fs.readFileSync(CMD, 'utf-8'));
|
|
assert.equal(contract.name, 'msd:mvp-phase');
|
|
});
|
|
|
|
test('argument-hint mentions phase number', () => {
|
|
const contract = parseCommandContract(fs.readFileSync(CMD, 'utf-8'));
|
|
assert.ok(contract.argumentHint.toLowerCase().includes('phase'));
|
|
});
|
|
|
|
test('allowed-tools includes Read, Write, Bash, (Task or Agent), AskUserQuestion', () => {
|
|
const contract = parseCommandContract(fs.readFileSync(CMD, 'utf-8'));
|
|
for (const tool of ['Read', 'Write', 'Bash', 'AskUserQuestion']) {
|
|
assert.ok(contract.allowedTools.includes(tool), `allowed-tools must include ${tool}`);
|
|
}
|
|
assert.ok(
|
|
contract.allowedTools.includes('Task') || contract.allowedTools.includes('Agent'),
|
|
'allowed-tools must include Task or Agent for delegation'
|
|
);
|
|
});
|
|
|
|
test('execution_context points to the workflow file', () => {
|
|
const contract = parseCommandContract(fs.readFileSync(CMD, 'utf-8'));
|
|
assert.ok(
|
|
contract.executionContextRefs.some(ref => ref.endsWith('workflows/mvp-phase.md')),
|
|
'execution_context must include workflows/mvp-phase.md'
|
|
);
|
|
});
|
|
});
|