fix(milestone-archive): expose searched roots and parse canonical STATE milestone
This commit is contained in:
@@ -214,7 +214,7 @@ function cmdFindPhase(cwd, phase, raw) {
|
||||
|
||||
const planBase = planningDir(cwd);
|
||||
const normalized = normalizePhaseName(phase);
|
||||
const notFound = { found: false, directory: null, phase_number: null, phase_name: null, plans: [], summaries: [] };
|
||||
const notFound = { found: false, directory: null, phase_number: null, phase_name: null, plans: [], summaries: [], searched_directories: [] };
|
||||
|
||||
// Build candidate search dirs: flat layout first, then milestone-archive layout.
|
||||
const searchDirs = [];
|
||||
@@ -230,6 +230,9 @@ function cmdFindPhase(cwd, phase, raw) {
|
||||
}
|
||||
} catch { /* no milestones dir */ }
|
||||
|
||||
notFound.searched_directories = searchDirs.map((searchDir) =>
|
||||
toPosixPath(path.join(path.relative(cwd, planBase), path.relative(planBase, searchDir))));
|
||||
|
||||
for (const searchDir of searchDirs) {
|
||||
try {
|
||||
const entries = fs.readdirSync(searchDir, { withFileTypes: true });
|
||||
|
||||
@@ -420,7 +420,7 @@ function getActiveMilestoneArchiveDir(planBase) {
|
||||
const statePath = path.join(planBase, 'STATE.md');
|
||||
if (fs.existsSync(statePath)) {
|
||||
const state = fs.readFileSync(statePath, 'utf-8');
|
||||
const m = state.match(/^\s*milestone:\s*([^\r\n#]+)\s*$/mi);
|
||||
const m = state.match(/^\s*(?:\*\*)?milestone(?:\*\*)?:\s*([^\s\r\n#]+).*$/mi);
|
||||
if (m && m[1]) {
|
||||
const milestone = m[1].trim();
|
||||
const candidate = path.join(planBase, 'milestones', `${milestone}-phases`);
|
||||
|
||||
@@ -139,7 +139,7 @@ describe('#3164 — validate consistency: milestone-archive layout', () => {
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, '.planning', 'STATE.md'),
|
||||
'milestone: v1.7\n# Session State\n\nPhase: 65\n'
|
||||
'# Session State\n\n**Milestone:** v1.7 Current Milestone\nPhase: 65\n'
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, '.planning', 'ROADMAP.md'),
|
||||
@@ -240,4 +240,23 @@ describe('#3164 — find-phase: milestone-archive layout', () => {
|
||||
`Expected deterministic archive ordering (v1.2 before v1.10), got directory: ${out.directory}`
|
||||
);
|
||||
});
|
||||
|
||||
test('find-phase not-found payload includes searched_directories', () => {
|
||||
setupMilestoneArchiveProject(tmpDir, {
|
||||
milestone: 'v1.7',
|
||||
phases: ['64-secondary-grader-fix'],
|
||||
roadmapPhases: ['64'],
|
||||
});
|
||||
|
||||
const result = runGsdTools('find-phase 999', tmpDir);
|
||||
assert.ok(result.success, `find-phase should succeed with found:false payload: ${result.error}`);
|
||||
|
||||
const out = JSON.parse(result.output);
|
||||
assert.strictEqual(out.found, false, `find-phase 999 should return found:false, got: ${JSON.stringify(out)}`);
|
||||
assert.ok(Array.isArray(out.searched_directories), 'searched_directories should be an array on not-found payload');
|
||||
assert.ok(
|
||||
out.searched_directories.includes('.planning/milestones/v1.7-phases'),
|
||||
`searched_directories should include active archive dir, got: ${JSON.stringify(out.searched_directories)}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user