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:
@@ -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 ───────────────────────────────────────────
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user