From a0a20599a0565638c0a52c7ca94a1b5328e42242 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Sun, 5 Apr 2026 21:04:05 -0500 Subject: [PATCH] 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. --- src/resources/extensions/gsd/auto-dashboard.ts | 9 +++++---- src/resources/extensions/gsd/auto.ts | 4 ++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/resources/extensions/gsd/auto-dashboard.ts b/src/resources/extensions/gsd/auto-dashboard.ts index a1a072dc3..e59e34146 100644 --- a/src/resources/extensions/gsd/auto-dashboard.ts +++ b/src/resources/extensions/gsd/auto-dashboard.ts @@ -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) diff --git a/src/resources/extensions/gsd/auto.ts b/src/resources/extensions/gsd/auto.ts index e7558e57c..f21f6330d 100644 --- a/src/resources/extensions/gsd/auto.ts +++ b/src/resources/extensions/gsd/auto.ts @@ -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);