fix(gsd): persist autoStartTime across session resume so elapsed timer survives /exit

autoStartTime was never saved to paused-session.json, so cross-session
resume always started with autoStartTime=0 and the widget showed no
elapsed timer. Now saved on pause, restored on resume with Date.now()
fallback for old files.

Also fixes widget layout: elapsed/ETA stays on the header line above
the milestone/branch info line.
This commit is contained in:
Jeremy 2026-04-05 21:04:05 -05:00
parent 24e0856950
commit a0a20599a0
2 changed files with 9 additions and 4 deletions

View file

@ -585,10 +585,11 @@ export function updateProgressWidget(
lines.push(rightAlign(headerLeft, headerRight, width));
// Worktree/branch right-aligned below header
if (worktreeName && cachedBranch) {
lines.push(rightAlign("", theme.fg("dim", `${worktreeName} (${cachedBranch})`), width));
} else if (cachedBranch) {
lines.push(rightAlign("", theme.fg("dim", cachedBranch), width));
const branchLabel = worktreeName && cachedBranch
? `${worktreeName} (${cachedBranch})`
: cachedBranch ?? "";
if (branchLabel) {
lines.push(rightAlign("", theme.fg("dim", branchLabel), width));
}
// Show health signal details when degraded (yellow/red)

View file

@ -895,6 +895,7 @@ export async function pauseAuto(
sessionFile: s.pausedSessionFile,
activeEngineId: s.activeEngineId,
activeRunDir: s.activeRunDir,
autoStartTime: s.autoStartTime,
};
const runtimeDir = join(gsdRoot(s.originalBasePath || s.basePath), "runtime");
mkdirSync(runtimeDir, { recursive: true });
@ -1137,6 +1138,7 @@ export async function startAuto(
s.activeRunDir = meta.activeRunDir ?? null;
s.originalBasePath = meta.originalBasePath || base;
s.stepMode = meta.stepMode ?? requestedStepMode;
s.autoStartTime = meta.autoStartTime || Date.now();
s.paused = true;
try { unlinkSync(pausedPath); } catch (err) { /* non-fatal */
logWarning("session", `pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
@ -1162,6 +1164,7 @@ export async function startAuto(
s.currentMilestoneId = meta.milestoneId;
s.originalBasePath = meta.originalBasePath || base;
s.stepMode = meta.stepMode ?? requestedStepMode;
s.autoStartTime = meta.autoStartTime || Date.now();
s.paused = true;
// Clean up the persisted file — we're consuming it
try { unlinkSync(pausedPath); } catch (err) { /* non-fatal */
@ -1194,6 +1197,7 @@ export async function startAuto(
s.cmdCtx = ctx;
s.basePath = base;
setLogBasePath(base);
if (!s.autoStartTime || s.autoStartTime <= 0) s.autoStartTime = Date.now();
s.unitDispatchCount.clear();
s.unitLifetimeDispatches.clear();
if (!getLedger()) initMetrics(base);