fix(gsd): address QA round 3
- Set resourceVersionOnStart on paused-session resume so resource staleness detection works for resumed sessions. - Re-register setLevelChangeCallback on resume so health-level transition notifications fire after process restart. - Persist unitType/unitId in paused-session metadata and restore them on resume so recovery synthesis framing text shows the actual unit instead of "unknown"/"unknown". - Check worktreePath existence before showing "(worktree)" in resume notification to avoid misleading the user when the worktree was already torn down. - Fix showDiscuss skip_milestone to use step:false (matching discuss_draft and discuss_fresh) instead of hardcoded step:true.
This commit is contained in:
parent
364cc7dcbc
commit
690bcbd79c
5 changed files with 22 additions and 5 deletions
|
|
@ -731,6 +731,8 @@ export async function pauseAuto(
|
|||
stepMode: s.stepMode,
|
||||
pausedAt: new Date().toISOString(),
|
||||
sessionFile: s.pausedSessionFile,
|
||||
unitType: s.currentUnit?.type ?? undefined,
|
||||
unitId: s.currentUnit?.id ?? undefined,
|
||||
};
|
||||
const runtimeDir = join(gsdRoot(s.originalBasePath || s.basePath), "runtime");
|
||||
mkdirSync(runtimeDir, { recursive: true });
|
||||
|
|
@ -968,10 +970,12 @@ export async function startAuto(
|
|||
s.originalBasePath = meta.originalBasePath || base;
|
||||
s.stepMode = meta.stepMode ?? requestedStepMode;
|
||||
s.pausedSessionFile = meta.sessionFile ?? null;
|
||||
s.pausedUnitType = meta.unitType ?? null;
|
||||
s.pausedUnitId = meta.unitId ?? null;
|
||||
s.paused = true;
|
||||
try { unlinkSync(pausedPath); } catch { /* non-fatal */ }
|
||||
ctx.ui.notify(
|
||||
`Resuming paused session for ${meta.milestoneId}${meta.worktreePath ? ` (worktree)` : ""}.`,
|
||||
`Resuming paused session for ${meta.milestoneId}${meta.worktreePath && existsSync(meta.worktreePath) ? ` (worktree)` : ""}.`,
|
||||
"info",
|
||||
);
|
||||
} else if (existsSync(pausedPath)) {
|
||||
|
|
@ -1024,6 +1028,7 @@ export async function startAuto(
|
|||
s.cmdCtx = ctx;
|
||||
s.basePath = base;
|
||||
s.autoStartTime = Date.now();
|
||||
s.resourceVersionOnStart = readResourceVersion();
|
||||
s.originalModelId = ctx.model?.id ?? null;
|
||||
s.originalModelProvider = ctx.model?.provider ?? null;
|
||||
if (ctx.model) {
|
||||
|
|
@ -1034,6 +1039,12 @@ export async function startAuto(
|
|||
if (!getLedger()) initMetrics(base);
|
||||
if (s.currentMilestoneId) setActiveMilestoneId(base, s.currentMilestoneId);
|
||||
|
||||
// Re-register health level notification callback lost across process restart
|
||||
setLevelChangeCallback((_from, to, summary) => {
|
||||
const level = to === "red" ? "error" : to === "yellow" ? "warning" : "info";
|
||||
ctx.ui.notify(summary, level as "info" | "warning" | "error");
|
||||
});
|
||||
|
||||
// ── Auto-worktree: re-enter worktree on resume ──
|
||||
if (
|
||||
s.currentMilestoneId &&
|
||||
|
|
@ -1084,8 +1095,8 @@ export async function startAuto(
|
|||
const activityDir = join(gsdRoot(s.basePath), "activity");
|
||||
const recovery = synthesizeCrashRecovery(
|
||||
s.basePath,
|
||||
s.currentUnit?.type ?? "unknown",
|
||||
s.currentUnit?.id ?? "unknown",
|
||||
s.currentUnit?.type ?? s.pausedUnitType ?? "unknown",
|
||||
s.currentUnit?.id ?? s.pausedUnitId ?? "unknown",
|
||||
s.pausedSessionFile ?? undefined,
|
||||
activityDir,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -118,6 +118,8 @@ export class AutoSession {
|
|||
pendingVerificationRetry: PendingVerificationRetry | null = null;
|
||||
readonly verificationRetryCount = new Map<string, number>();
|
||||
pausedSessionFile: string | null = null;
|
||||
pausedUnitType: string | null = null;
|
||||
pausedUnitId: string | null = null;
|
||||
resourceVersionOnStart: string | null = null;
|
||||
lastStateRebuildAt = 0;
|
||||
|
||||
|
|
@ -203,6 +205,8 @@ export class AutoSession {
|
|||
this.pendingVerificationRetry = null;
|
||||
this.verificationRetryCount.clear();
|
||||
this.pausedSessionFile = null;
|
||||
this.pausedUnitType = null;
|
||||
this.pausedUnitId = null;
|
||||
this.resourceVersionOnStart = null;
|
||||
this.lastStateRebuildAt = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -558,7 +558,7 @@ export async function showDiscuss(
|
|||
const milestoneIds = findMilestoneIds(basePath);
|
||||
const uniqueMilestoneIds = !!loadEffectiveGSDPreferences()?.preferences?.unique_milestone_ids;
|
||||
const nextId = nextMilestoneId(milestoneIds, uniqueMilestoneIds);
|
||||
pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: true };
|
||||
pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: false };
|
||||
await dispatchWorkflow(pi, buildDiscussPrompt(nextId, `New milestone ${nextId}.`, basePath), "gsd-run", ctx, "plan-milestone");
|
||||
}
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ export interface PausedSessionMetadata {
|
|||
stepMode?: boolean;
|
||||
pausedAt?: string;
|
||||
sessionFile?: string | null;
|
||||
unitType?: string;
|
||||
unitId?: string;
|
||||
}
|
||||
|
||||
export interface InterruptedSessionAssessment {
|
||||
|
|
|
|||
|
|
@ -134,5 +134,5 @@ test("guided-flow source uses step-aware resume and clears stale paused metadata
|
|||
assert.ok(source.includes('step: interrupted.pausedSession?.stepMode ?? false'));
|
||||
assert.ok(source.includes('unlinkSync(join(gsdRoot(basePath), "runtime", "paused-session.json"))'));
|
||||
assert.ok(source.includes('pendingAutoStart = { ctx, pi, basePath, milestoneId: mid, step: false };'));
|
||||
assert.ok(source.includes('pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: true };'));
|
||||
assert.ok(source.includes('pendingAutoStart = { ctx, pi, basePath, milestoneId: nextId, step: false };'));
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue