fix(guided-flow): add self-heal for stale runtime records on wizard start (#436)
auto.ts has selfHealRuntimeRecords() which cleans up stale .gsd/runtime/units/ records when /gsd auto starts. However, guided-flow.ts (used by /gsd manual mode) had zero awareness of runtime records — it only checked auto.lock. This means if auto-mode crashes mid-unit, the stale runtime records persist until the next /gsd auto run. Users who alternate between manual and auto mode, or who only use manual mode after a crash, would accumulate stale records that could cause spurious re-dispatch or confusing state. Add selfHealRuntimeRecords() to guided-flow.ts that: - Clears records where the expected artifact already exists (completed but closeout didn't finish) - Clears records stuck in dispatched or timeout phase (process died mid-unit) - Notifies the user how many stale records were cleaned Called in showSmartEntry() before the crash lock check so the wizard always starts from a clean state regardless of how the previous session ended. Co-authored-by: Thomas <twilliams1234@gmail.com>
This commit is contained in:
parent
0e3284215a
commit
3c931b2e19
1 changed files with 41 additions and 0 deletions
|
|
@ -13,6 +13,8 @@ import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|||
import { deriveState } from "./state.js";
|
||||
import { startAuto } from "./auto.js";
|
||||
import { readCrashLock, clearLock, formatCrashInfo } from "./crash-recovery.js";
|
||||
import { listUnitRuntimeRecords, clearUnitRuntimeRecord } from "./unit-runtime.js";
|
||||
import { resolveExpectedArtifactPath } from "./auto.js";
|
||||
import {
|
||||
gsdRoot, milestonesDir, resolveMilestoneFile, resolveMilestonePath,
|
||||
resolveSliceFile, resolveSlicePath, resolveGsdRootFile, relGsdRootFile,
|
||||
|
|
@ -518,6 +520,42 @@ export async function showDiscuss(
|
|||
/**
|
||||
* The one wizard. Reads state, shows contextual options, dispatches into the workflow doc.
|
||||
*/
|
||||
/**
|
||||
* Self-heal: scan runtime records and clear stale ones left behind when
|
||||
* auto-mode crashed mid-unit. auto.ts has its own selfHealRuntimeRecords()
|
||||
* but guided-flow (manual /gsd mode) never called it — meaning stale records
|
||||
* persisted until the next /gsd auto run. This ensures the wizard always
|
||||
* starts from a clean state regardless of how the previous session ended.
|
||||
*/
|
||||
function selfHealRuntimeRecords(basePath: string, ctx: ExtensionContext): { cleared: number } {
|
||||
try {
|
||||
const records = listUnitRuntimeRecords(basePath);
|
||||
let cleared = 0;
|
||||
for (const record of records) {
|
||||
const { unitType, unitId, phase } = record;
|
||||
// Clear records whose expected artifact already exists (completed but not cleaned up)
|
||||
const artifactPath = resolveExpectedArtifactPath(unitType, unitId, basePath);
|
||||
if (artifactPath && existsSync(artifactPath)) {
|
||||
clearUnitRuntimeRecord(basePath, unitType, unitId);
|
||||
cleared++;
|
||||
continue;
|
||||
}
|
||||
// Clear records stuck in dispatched or timeout phase (process died mid-unit)
|
||||
if (phase === "dispatched" || phase === "timeout") {
|
||||
clearUnitRuntimeRecord(basePath, unitType, unitId);
|
||||
cleared++;
|
||||
}
|
||||
}
|
||||
if (cleared > 0) {
|
||||
ctx.ui.notify(`Self-heal: cleared ${cleared} stale runtime record(s) from a previous session.`, "info");
|
||||
}
|
||||
return { cleared };
|
||||
} catch {
|
||||
// Non-fatal — self-heal should never block the wizard
|
||||
return { cleared: 0 };
|
||||
}
|
||||
}
|
||||
|
||||
export async function showSmartEntry(
|
||||
ctx: ExtensionCommandContext,
|
||||
pi: ExtensionAPI,
|
||||
|
|
@ -556,6 +594,9 @@ export async function showSmartEntry(
|
|||
}
|
||||
}
|
||||
|
||||
// ── Self-heal stale runtime records from crashed auto-mode sessions ──
|
||||
selfHealRuntimeRecords(basePath, ctx);
|
||||
|
||||
// Check for crash from previous auto-mode session
|
||||
const crashLock = readCrashLock(basePath);
|
||||
if (crashLock) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue