* feat(#39): milestone-prefixed phase IDs (M-NN convention) + migration tool + validation - Add getMilestoneFromPhaseId() / getPhaseDirFromPhaseId() helpers to core.cjs - Fix isDirInMilestone to match M-NN-style dirs (02-01-setup) against M-NN ROADMAP headings - Extend heading regex to tolerate [bracket-token] scope prefix on phase headings - Add W021 validation rule for milestone prefix mismatch - Add gsd-tools roadmap validate + roadmap upgrade --convention milestone-prefixed - Add phase_id_convention config field (null default, backwards-compatible) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#39): address 4 Codex review findings in milestone-prefixed phase ID implementation - getMilestoneFromPhaseId: tighten regex to require a digit after the hyphen (rejects '1-' and '1-abc') - isDirInMilestone: use convention-aware regex — only capture M-NN segments when ROADMAP itself uses hyphenated phase IDs, preventing legacy dirs like '01-02-setup' from being misread as phase '1-02' - checkW021: add UNPREFIXED_PHASE_RE path so unprefixed headings (### Phase 1:) also fire W021 when convention is milestone-prefixed - roadmap-upgrade: remove isMigratedDirName dir-name check (false-positive for legacy dirs); config + ROADMAP heading checks at lines 194 and 212 are sufficient Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: update changeset pr reference to #565 * fix(#39): restore phaseDirNameRe 2-digit minimum; add roadmap-upgrade to inventory - validate.cjs: \d{1,} → \d{2,} to keep single-digit prefix rejection per W005 contract - docs/INVENTORY.md: 79 → 80, add roadmap-upgrade.cjs row - docs/INVENTORY-MANIFEST.json: regenerated (roadmap-upgrade.cjs entry) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
88 lines
2.4 KiB
JavaScript
88 lines
2.4 KiB
JavaScript
'use strict';
|
|
|
|
const { describe, test, before, after } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
|
|
const { routeRoadmapCommand } = require('../get-shit-done/bin/lib/roadmap-command-router.cjs');
|
|
|
|
// These tests exercise router dispatch with a deterministic runtime context.
|
|
let _prevWorkstream;
|
|
before(() => {
|
|
_prevWorkstream = process.env.GSD_WORKSTREAM;
|
|
process.env.GSD_WORKSTREAM = 'test-unit';
|
|
});
|
|
after(() => {
|
|
if (_prevWorkstream === undefined) delete process.env.GSD_WORKSTREAM;
|
|
else process.env.GSD_WORKSTREAM = _prevWorkstream;
|
|
});
|
|
|
|
describe('roadmap-command-router', () => {
|
|
test('routes roadmap analyze', () => {
|
|
const calls = [];
|
|
const roadmap = {
|
|
cmdRoadmapAnalyze: (cwd, raw) => calls.push({ cwd, raw }),
|
|
};
|
|
|
|
routeRoadmapCommand({
|
|
roadmap,
|
|
args: ['roadmap', 'analyze'],
|
|
cwd: '/tmp/proj',
|
|
raw: true,
|
|
error: (msg) => {
|
|
throw new Error(msg);
|
|
},
|
|
});
|
|
|
|
assert.equal(calls.length, 1);
|
|
assert.deepEqual(calls[0], { cwd: '/tmp/proj', raw: true });
|
|
});
|
|
|
|
test('routes roadmap get-phase and update-plan-progress with phase arg', () => {
|
|
const calls = [];
|
|
const roadmap = {
|
|
cmdRoadmapGetPhase: (cwd, phase, raw) => calls.push({ kind: 'get', cwd, phase, raw }),
|
|
cmdRoadmapUpdatePlanProgress: (cwd, phase, raw) => calls.push({ kind: 'update', cwd, phase, raw }),
|
|
};
|
|
|
|
routeRoadmapCommand({
|
|
roadmap,
|
|
args: ['roadmap', 'get-phase', '10'],
|
|
cwd: '/tmp/proj',
|
|
raw: false,
|
|
error: (msg) => {
|
|
throw new Error(msg);
|
|
},
|
|
});
|
|
|
|
routeRoadmapCommand({
|
|
roadmap,
|
|
args: ['roadmap', 'update-plan-progress', '10'],
|
|
cwd: '/tmp/proj',
|
|
raw: false,
|
|
error: (msg) => {
|
|
throw new Error(msg);
|
|
},
|
|
});
|
|
|
|
assert.deepEqual(calls, [
|
|
{ kind: 'get', cwd: '/tmp/proj', phase: '10', raw: false },
|
|
{ kind: 'update', cwd: '/tmp/proj', phase: '10', raw: false },
|
|
]);
|
|
});
|
|
|
|
test('errors on unknown roadmap subcommand', () => {
|
|
let message = null;
|
|
routeRoadmapCommand({
|
|
roadmap: {},
|
|
args: ['roadmap', 'nonsense'],
|
|
cwd: '/tmp/proj',
|
|
raw: false,
|
|
error: (msg) => {
|
|
message = msg;
|
|
},
|
|
});
|
|
|
|
assert.equal(message, 'Unknown roadmap subcommand. Available: analyze, get-phase, update-plan-progress, annotate-dependencies, validate, upgrade');
|
|
});
|
|
});
|