From 459f7f3b645b82a287a91bc4dfc8ef30a8ce517a Mon Sep 17 00:00:00 2001 From: j2h4u <39818683+j2h4u@users.noreply.github.com> Date: Wed, 4 Mar 2026 03:12:53 +0500 Subject: [PATCH] fix(roadmap): mark individual plan checkboxes when summaries exist `cmdRoadmapUpdatePlanProgress` only marked phase-level checkboxes (e.g. `- [ ] Phase 50: Build`) but skipped plan-level entries (e.g. `- [ ] 50-01-PLAN.md`). Now iterates phase summaries and marks matching plan checkboxes as complete. Co-Authored-By: Claude Opus 4.6 --- get-shit-done/bin/lib/roadmap.cjs | 12 +++++++++++ tests/roadmap.test.cjs | 36 +++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/get-shit-done/bin/lib/roadmap.cjs b/get-shit-done/bin/lib/roadmap.cjs index a2fe661a6..6dd3554c6 100644 --- a/get-shit-done/bin/lib/roadmap.cjs +++ b/get-shit-done/bin/lib/roadmap.cjs @@ -287,6 +287,18 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) { roadmapContent = replaceInCurrentMilestone(roadmapContent, checkboxPattern, `$1x$2 (completed ${today})`); } + // Mark completed plan checkboxes (e.g. "- [ ] 50-01-PLAN.md" or "- [ ] 50-01:") + for (const summaryFile of phaseInfo.summaries) { + const planId = summaryFile.replace('-SUMMARY.md', '').replace('SUMMARY.md', ''); + if (!planId) continue; + const planEscaped = escapeRegex(planId); + const planCheckboxPattern = new RegExp( + `(-\\s*\\[) (\\]\\s*${planEscaped})`, + 'i' + ); + roadmapContent = roadmapContent.replace(planCheckboxPattern, '$1x$2'); + } + fs.writeFileSync(roadmapPath, roadmapContent, 'utf-8'); output({ diff --git a/tests/roadmap.test.cjs b/tests/roadmap.test.cjs index ea5e2f538..7f41055a3 100644 --- a/tests/roadmap.test.cjs +++ b/tests/roadmap.test.cjs @@ -756,6 +756,42 @@ describe('roadmap update-plan-progress command', () => { assert.strictEqual(output.updated, false, 'should not update'); assert.ok(output.reason.includes('ROADMAP.md not found'), 'reason should mention missing ROADMAP.md'); }); + + test('marks completed plan checkboxes', () => { + const roadmapContent = `# Roadmap + +- [ ] Phase 50: Build + - [ ] 50-01-PLAN.md + - [ ] 50-02-PLAN.md + +### Phase 50: Build +**Goal:** Build stuff +**Plans:** 2 plans + +## Progress + +| Phase | Plans Complete | Status | Completed | +|-------|---------------|--------|-----------| +| 50. Build | 0/2 | Planned | | +`; + fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), roadmapContent); + + const p50 = path.join(tmpDir, '.planning', 'phases', '50-build'); + fs.mkdirSync(p50, { recursive: true }); + fs.writeFileSync(path.join(p50, '50-01-PLAN.md'), '# Plan 1'); + fs.writeFileSync(path.join(p50, '50-02-PLAN.md'), '# Plan 2'); + // Only plan 1 has a summary (completed) + fs.writeFileSync(path.join(p50, '50-01-SUMMARY.md'), '# Summary 1'); + + const result = runGsdTools('roadmap update-plan-progress 50', tmpDir); + assert.ok(result.success, `Command failed: ${result.error}`); + + const roadmap = fs.readFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8'); + assert.ok(roadmap.includes('[x] 50-01-PLAN.md') || roadmap.includes('[x] 50-01'), + 'completed plan checkbox should be marked'); + assert.ok(roadmap.includes('[ ] 50-02-PLAN.md') || roadmap.includes('[ ] 50-02'), + 'incomplete plan checkbox should remain unchecked'); + }); }); // ─────────────────────────────────────────────────────────────────────────────