Skip to content

Commit 3f96a0b

Browse files
j2h4uclaude
andcommitted
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 <noreply@anthropic.com>
1 parent 2eaed7a commit 3f96a0b

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
66

77
## [Unreleased]
88

9+
### Fixed
10+
- `roadmap update-plan-progress` now marks individual plan checkboxes (e.g. `- [ ] 50-01-PLAN.md`) as complete when their summary exists
11+
912
## [1.22.4] - 2026-03-03
1013

1114
### Added

get-shit-done/bin/lib/roadmap.cjs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,18 @@ function cmdRoadmapUpdatePlanProgress(cwd, phaseNum, raw) {
279279
roadmapContent = roadmapContent.replace(checkboxPattern, `$1x$2 (completed ${today})`);
280280
}
281281

282+
// Mark completed plan checkboxes (e.g. "- [ ] 50-01-PLAN.md" or "- [ ] 50-01:")
283+
for (const summaryFile of phaseInfo.summaries) {
284+
const planId = summaryFile.replace('-SUMMARY.md', '').replace('SUMMARY.md', '');
285+
if (!planId) continue;
286+
const planEscaped = escapeRegex(planId);
287+
const planCheckboxPattern = new RegExp(
288+
`(-\\s*\\[) (\\]\\s*${planEscaped})`,
289+
'i'
290+
);
291+
roadmapContent = roadmapContent.replace(planCheckboxPattern, '$1x$2');
292+
}
293+
282294
fs.writeFileSync(roadmapPath, roadmapContent, 'utf-8');
283295

284296
output({

tests/roadmap.test.cjs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,42 @@ describe('roadmap update-plan-progress command', () => {
662662
assert.strictEqual(output.updated, false, 'should not update');
663663
assert.ok(output.reason.includes('ROADMAP.md not found'), 'reason should mention missing ROADMAP.md');
664664
});
665+
666+
test('marks completed plan checkboxes', () => {
667+
const roadmapContent = `# Roadmap
668+
669+
- [ ] Phase 50: Build
670+
- [ ] 50-01-PLAN.md
671+
- [ ] 50-02-PLAN.md
672+
673+
### Phase 50: Build
674+
**Goal:** Build stuff
675+
**Plans:** 2 plans
676+
677+
## Progress
678+
679+
| Phase | Plans Complete | Status | Completed |
680+
|-------|---------------|--------|-----------|
681+
| 50. Build | 0/2 | Planned | |
682+
`;
683+
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), roadmapContent);
684+
685+
const p50 = path.join(tmpDir, '.planning', 'phases', '50-build');
686+
fs.mkdirSync(p50, { recursive: true });
687+
fs.writeFileSync(path.join(p50, '50-01-PLAN.md'), '# Plan 1');
688+
fs.writeFileSync(path.join(p50, '50-02-PLAN.md'), '# Plan 2');
689+
// Only plan 1 has a summary (completed)
690+
fs.writeFileSync(path.join(p50, '50-01-SUMMARY.md'), '# Summary 1');
691+
692+
const result = runGsdTools('roadmap update-plan-progress 50', tmpDir);
693+
assert.ok(result.success, `Command failed: ${result.error}`);
694+
695+
const roadmap = fs.readFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), 'utf-8');
696+
assert.ok(roadmap.includes('[x] 50-01-PLAN.md') || roadmap.includes('[x] 50-01'),
697+
'completed plan checkbox should be marked');
698+
assert.ok(roadmap.includes('[ ] 50-02-PLAN.md') || roadmap.includes('[ ] 50-02'),
699+
'incomplete plan checkbox should remain unchecked');
700+
});
665701
});
666702

667703
// ─────────────────────────────────────────────────────────────────────────────

0 commit comments

Comments
 (0)