Merge pull request #947 from j2h4u/fix/state-advance-plan-compound

fix(state): parse compound Plan field in advance-plan command
This commit is contained in:
Tom Boucher
2026-03-19 12:59:18 -04:00
committed by GitHub
2 changed files with 76 additions and 7 deletions

View File

@@ -206,25 +206,55 @@ function cmdStateAdvancePlan(cwd, raw) {
if (!fs.existsSync(statePath)) { output({ error: 'STATE.md not found' }, raw); return; }
let content = fs.readFileSync(statePath, 'utf-8');
const currentPlan = parseInt(stateExtractField(content, 'Current Plan'), 10);
const totalPlans = parseInt(stateExtractField(content, 'Total Plans in Phase'), 10);
const today = new Date().toISOString().split('T')[0];
// Try legacy separate fields first, then compound "Plan: X of Y" format
const legacyPlan = stateExtractField(content, 'Current Plan');
const legacyTotal = stateExtractField(content, 'Total Plans in Phase');
const planField = stateExtractField(content, 'Plan');
let currentPlan, totalPlans;
let useCompoundFormat = false;
if (legacyPlan && legacyTotal) {
currentPlan = parseInt(legacyPlan, 10);
totalPlans = parseInt(legacyTotal, 10);
} else if (planField) {
// Compound format: "2 of 6 in current phase" or "2 of 6"
currentPlan = parseInt(planField, 10);
const ofMatch = planField.match(/of\s+(\d+)/);
totalPlans = ofMatch ? parseInt(ofMatch[1], 10) : NaN;
useCompoundFormat = true;
}
if (isNaN(currentPlan) || isNaN(totalPlans)) {
output({ error: 'Cannot parse Current Plan or Total Plans in Phase from STATE.md' }, raw);
return;
}
const replaceField = (c, primary, fallback, value) => {
let r = stateReplaceField(c, primary, value);
if (r) return r;
if (fallback) { r = stateReplaceField(c, fallback, value); if (r) return r; }
return c;
};
if (currentPlan >= totalPlans) {
content = stateReplaceField(content, 'Status', 'Phase complete — ready for verification') || content;
content = stateReplaceField(content, 'Last Activity', today) || content;
content = replaceField(content, 'Status', null, 'Phase complete — ready for verification');
content = replaceField(content, 'Last Activity', 'Last activity', today);
writeStateMd(statePath, content, cwd);
output({ advanced: false, reason: 'last_plan', current_plan: currentPlan, total_plans: totalPlans, status: 'ready_for_verification' }, raw, 'false');
} else {
const newPlan = currentPlan + 1;
content = stateReplaceField(content, 'Current Plan', String(newPlan)) || content;
content = stateReplaceField(content, 'Status', 'Ready to execute') || content;
content = stateReplaceField(content, 'Last Activity', today) || content;
if (useCompoundFormat) {
// Preserve compound format: "X of Y in current phase" → replace X only
const newPlanValue = planField.replace(/^\d+/, String(newPlan));
content = stateReplaceField(content, 'Plan', newPlanValue) || content;
} else {
content = stateReplaceField(content, 'Current Plan', String(newPlan)) || content;
}
content = replaceField(content, 'Status', null, 'Ready to execute');
content = replaceField(content, 'Last Activity', 'Last activity', today);
writeStateMd(statePath, content, cwd);
output({ advanced: true, previous_plan: currentPlan, current_plan: newPlan, total_plans: totalPlans }, raw, 'true');
}