Merge pull request #2743 from gsd-build/fix/2714-workstream-config-inheritance

feat(config): workstream config.json inherits from root .planning/config.json
This commit is contained in:
Tom Boucher
2026-04-26 11:49:30 -04:00
committed by GitHub
4 changed files with 206 additions and 23 deletions

View File

@@ -226,6 +226,44 @@ describe('replaceInCurrentMilestone', () => {
// v1.18 old plans line should remain untouched
expect(result).toContain('**Plans:** 1/1 plans');
});
it('replaces inside active <details> even when footer text exists after </details>', async () => {
const { replaceInCurrentMilestone } = await import('./phase-lifecycle.js');
// Scenario: active milestone is the last <details> block, but a footer
// (e.g. "---\n*Last updated*") follows it. The fast-path sees after.trim()
// non-empty and replaces in the footer instead of inside the active block.
const content = [
'# Roadmap',
'',
'<details>',
'<summary>v1.0 (Archived)</summary>',
'',
'**Plans:** 1/1 plans',
'',
'</details>',
'',
'<details>',
'<summary>v2.0 (Active)</summary>',
'',
'**Plans:** 1/2 plans',
'',
'</details>',
'',
'---',
'*Last updated: 2026-01-01*',
].join('\n');
const pattern = /\*\*Plans:\*\* [^\n]+/g;
const result = replaceInCurrentMilestone(content, pattern, '**Plans:** 2/2 plans complete');
// Active milestone inside last <details> should be updated
expect(result).toContain('**Plans:** 2/2 plans complete');
// Archived milestone should remain untouched
expect(result).toContain('**Plans:** 1/1 plans');
// Footer should be preserved verbatim
expect(result).toContain('---');
expect(result).toContain('*Last updated: 2026-01-01*');
});
});
// ─── readModifyWriteRoadmapMd ───────────────────────────────────────────

View File

@@ -111,8 +111,9 @@ export function replaceInCurrentMilestone(
// Fast path: the current milestone is not inside a <details> block — the
// pattern lives in the plain text after the last </details>.
if (after.trim().length > 0) {
return before + after.replace(pattern, replacement);
const replacedAfter = after.replace(pattern, replacement);
if (replacedAfter !== after) {
return before + replacedAfter;
}
// Slow path: the active milestone is inside the last <details> block.