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.
84 lines
3.8 KiB
JavaScript
84 lines
3.8 KiB
JavaScript
/**
|
|
* plan-phase workflow — --mvp flag parsing and MVP_MODE resolution
|
|
* Contract test: verifies the workflow markdown documents the agreed
|
|
* resolution order (CLI flag → roadmap mode → config → default false).
|
|
*/
|
|
const { test, describe, beforeEach, afterEach } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const { runMsdTools, createTempProject, cleanup } = require('./helpers.cjs');
|
|
|
|
const WORKFLOW = path.join(__dirname, '..', 'msd-core', 'workflows', 'plan-phase.md');
|
|
|
|
function parseWorkflowContract(content) {
|
|
const lines = content.split(/\r?\n/).map(line => line.trim());
|
|
const argExtractionLine = lines.find(line => line.includes('Extract from $ARGUMENTS:')) || '';
|
|
const hasMvpModeVariable = lines.some(line => line.includes('MVP_MODE'));
|
|
const hasWorkflowConfigRead = lines.some(line => line.includes('workflow.mvp_mode'));
|
|
const hasRoadmapModeRead = lines.some(line => line.includes('phase.mvp-mode') || line.includes('roadmap'));
|
|
const hasSkeletonReference = lines.some(line => line.includes('SKELETON.md'));
|
|
const hasWalkingSkeletonLabel = lines.some(line => line.toLowerCase().includes('walking skeleton'));
|
|
const plannerLines = lines.filter(line => line.includes('planner') || line.includes('msd-planner'));
|
|
const plannerUsesMvpMode = plannerLines.some(line => line.includes('MVP_MODE')) || lines.some(line => line.includes('MVP_MODE') && line.includes('planner'));
|
|
return {
|
|
argExtractionLine,
|
|
hasMvpModeVariable,
|
|
hasWorkflowConfigRead,
|
|
hasRoadmapModeRead,
|
|
hasSkeletonReference,
|
|
hasWalkingSkeletonLabel,
|
|
plannerUsesMvpMode,
|
|
};
|
|
}
|
|
|
|
describe('plan-phase workflow — --mvp flag', () => {
|
|
const contract = parseWorkflowContract(fs.readFileSync(WORKFLOW, 'utf-8'));
|
|
|
|
test('argument list documents --mvp flag', () => {
|
|
assert.ok(contract.argExtractionLine.length > 0, 'Step 2 arg-extraction line not found');
|
|
assert.ok(contract.argExtractionLine.includes('--mvp'), 'argument list must mention --mvp');
|
|
});
|
|
|
|
test('workflow defines MVP_MODE resolution block', () => {
|
|
assert.ok(contract.hasMvpModeVariable, 'workflow must declare MVP_MODE');
|
|
assert.ok(contract.hasWorkflowConfigRead, 'must read workflow.mvp_mode config');
|
|
assert.ok(contract.hasRoadmapModeRead, 'must consult phase mode from roadmap/phase.mvp-mode');
|
|
});
|
|
|
|
test('Walking Skeleton gate references new-project + Phase 1', () => {
|
|
assert.ok(contract.hasSkeletonReference, 'workflow must mention SKELETON.md');
|
|
assert.ok(contract.hasWalkingSkeletonLabel, 'workflow must label the gate as Walking Skeleton');
|
|
});
|
|
|
|
test('planner spawn passes MVP_MODE to msd-planner', () => {
|
|
assert.ok(contract.plannerUsesMvpMode, 'workflow must wire MVP_MODE into the planner subagent prompt');
|
|
});
|
|
});
|
|
|
|
describe('plan-phase --mvp — resolution chain integration', () => {
|
|
let tmpDir;
|
|
beforeEach(() => { tmpDir = createTempProject(); });
|
|
afterEach(() => { cleanup(tmpDir); });
|
|
|
|
test('roadmap.get-phase reports mode=mvp when set in roadmap', () => {
|
|
fs.writeFileSync(
|
|
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
|
`# Roadmap\n\n## v1.0.0\n\n### Phase 1: Auth\n**Goal:** Users can log in\n**Mode:** mvp\n`
|
|
);
|
|
const result = runMsdTools('roadmap get-phase 1 --pick mode', tmpDir);
|
|
assert.ok(result.success);
|
|
assert.strictEqual(result.output.trim(), 'mvp');
|
|
});
|
|
|
|
test('config-get workflow.mvp_mode default is empty/unset', () => {
|
|
const result = runMsdTools('config-get workflow.mvp_mode', tmpDir);
|
|
// Either success with empty output OR a non-zero exit; both are fine.
|
|
// Real assertion: the key isn't accidentally set to "true" in tmp project.
|
|
if (result.success) {
|
|
assert.notStrictEqual(result.output.trim(), 'true');
|
|
}
|
|
});
|
|
});
|