gsd-pi 2.67.0-dev.fe39184 → 2.68.0-dev.4cf2433
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +1 -1
- package/dist/resources/extensions/gsd/auto-start.js +5 -31
- package/dist/resources/extensions/gsd/auto-worktree.js +62 -15
- package/dist/resources/extensions/gsd/auto.js +94 -59
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +7 -2
- package/dist/resources/extensions/gsd/doctor.js +8 -4
- package/dist/resources/extensions/gsd/gsd-db.js +11 -0
- package/dist/resources/extensions/gsd/guided-flow.js +40 -31
- package/dist/resources/extensions/gsd/interrupted-session.js +146 -0
- package/dist/resources/extensions/gsd/state.js +7 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +16 -16
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +16 -16
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/2826.821e01b07d92e948.js +9 -0
- package/dist/web/standalone/.next/static/chunks/app/{page-0c485498795110d6.js → page-f1e30ab6bb269149.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{webpack-42a66876b763aa26.js → webpack-6e4d7e9a4f57bed4.js} +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/contextual-tips.d.ts +43 -0
- package/packages/pi-coding-agent/dist/core/contextual-tips.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/contextual-tips.js +208 -0
- package/packages/pi-coding-agent/dist/core/contextual-tips.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/contextual-tips.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/contextual-tips.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/contextual-tips.test.js +227 -0
- package/packages/pi-coding-agent/dist/core/contextual-tips.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/index.js +1 -0
- package/packages/pi-coding-agent/dist/core/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +14 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +13 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/contextual-tips.test.ts +259 -0
- package/packages/pi-coding-agent/src/core/contextual-tips.ts +232 -0
- package/packages/pi-coding-agent/src/core/index.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +19 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +17 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +1 -1
- package/src/resources/extensions/gsd/auto-start.ts +8 -54
- package/src/resources/extensions/gsd/auto-worktree.ts +59 -15
- package/src/resources/extensions/gsd/auto.ts +104 -63
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +8 -2
- package/src/resources/extensions/gsd/doctor.ts +9 -5
- package/src/resources/extensions/gsd/gsd-db.ts +12 -0
- package/src/resources/extensions/gsd/guided-flow.ts +42 -36
- package/src/resources/extensions/gsd/interrupted-session.ts +224 -0
- package/src/resources/extensions/gsd/state.ts +7 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +668 -2
- package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +380 -2
- package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/integration/doctor-fixlevel.test.ts +52 -1
- package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +169 -0
- package/src/resources/extensions/gsd/tests/interrupted-session-auto.test.ts +146 -0
- package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +136 -0
- package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +11 -0
- package/dist/web/standalone/.next/static/chunks/6502.5dcdcf1e1432e20d.js +0 -9
- /package/dist/web/standalone/.next/static/{gbSATDX4Jt2ufxzUr5nYm → gd7sngpqfUCltp8w_pCwF}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{gbSATDX4Jt2ufxzUr5nYm → gd7sngpqfUCltp8w_pCwF}/_ssgManifest.js +0 -0
|
@@ -16,7 +16,12 @@ import { buildSkillActivationBlock } from "./auto-prompts.js";
|
|
|
16
16
|
import { deriveState } from "./state.js";
|
|
17
17
|
import { invalidateAllCaches } from "./cache.js";
|
|
18
18
|
import { startAuto } from "./auto.js";
|
|
19
|
-
import {
|
|
19
|
+
import { clearLock } from "./crash-recovery.js";
|
|
20
|
+
import {
|
|
21
|
+
assessInterruptedSession,
|
|
22
|
+
formatInterruptedSessionRunningMessage,
|
|
23
|
+
formatInterruptedSessionSummary,
|
|
24
|
+
} from "./interrupted-session.js";
|
|
20
25
|
import { listUnitRuntimeRecords, clearUnitRuntimeRecord } from "./unit-runtime.js";
|
|
21
26
|
import { resolveExpectedArtifactPath } from "./auto.js";
|
|
22
27
|
import {
|
|
@@ -215,17 +220,9 @@ export function checkAutoStartAfterDiscuss(): boolean {
|
|
|
215
220
|
|
|
216
221
|
// Gate 4: Discussion manifest process verification (multi-milestone only)
|
|
217
222
|
// The LLM writes DISCUSSION-MANIFEST.json after each Phase 3 gate decision.
|
|
218
|
-
//
|
|
219
|
-
//
|
|
223
|
+
// When it exists, validate it before auto-starting. Project history alone is
|
|
224
|
+
// not a reliable signal for the current discussion mode.
|
|
220
225
|
const manifestPath = join(gsdRoot(basePath), "DISCUSSION-MANIFEST.json");
|
|
221
|
-
const requiresManifest = projectIds.length > 1 || findMilestoneIds(basePath).length > 1;
|
|
222
|
-
if (requiresManifest && !existsSync(manifestPath)) {
|
|
223
|
-
ctx.ui.notify(
|
|
224
|
-
"Multi-milestone discussion manifest is missing. Auto-start will remain paused until the manifest is written.",
|
|
225
|
-
"warning",
|
|
226
|
-
);
|
|
227
|
-
return false;
|
|
228
|
-
}
|
|
229
226
|
if (existsSync(manifestPath)) {
|
|
230
227
|
try {
|
|
231
228
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
@@ -1322,36 +1319,45 @@ export async function showSmartEntry(
|
|
|
1322
1319
|
// ── Self-heal stale runtime records from crashed auto-mode sessions ──
|
|
1323
1320
|
selfHealRuntimeRecords(basePath, ctx);
|
|
1324
1321
|
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
clearLock(basePath);
|
|
1322
|
+
const interrupted = await assessInterruptedSession(basePath);
|
|
1323
|
+
if (interrupted.classification === "running") {
|
|
1324
|
+
ctx.ui.notify(formatInterruptedSessionRunningMessage(interrupted), "error");
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1331
1327
|
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
if (!isBootstrapCrash) {
|
|
1340
|
-
const resume = await showNextAction(ctx, {
|
|
1341
|
-
title: "GSD — Interrupted Session Detected",
|
|
1342
|
-
summary: [formatCrashInfo(crashLock)],
|
|
1343
|
-
actions: [
|
|
1344
|
-
{ id: "resume", label: "Resume with /gsd auto", description: "Pick up where it left off", recommended: true },
|
|
1345
|
-
{ id: "continue", label: "Continue manually", description: "Open the wizard as normal" },
|
|
1346
|
-
],
|
|
1347
|
-
});
|
|
1348
|
-
if (resume === "resume") {
|
|
1349
|
-
await startAuto(ctx, pi, basePath, false);
|
|
1350
|
-
return;
|
|
1328
|
+
if (interrupted.classification === "stale") {
|
|
1329
|
+
clearLock(basePath);
|
|
1330
|
+
if (interrupted.pausedSession) {
|
|
1331
|
+
try {
|
|
1332
|
+
unlinkSync(join(gsdRoot(basePath), "runtime", "paused-session.json"));
|
|
1333
|
+
} catch (e) {
|
|
1334
|
+
logWarning("guided", `stale pause file cleanup failed: ${(e as Error).message}`, { file: "guided-flow.ts" });
|
|
1351
1335
|
}
|
|
1352
1336
|
}
|
|
1337
|
+
} else if (interrupted.classification === "recoverable") {
|
|
1338
|
+
if (interrupted.lock) clearLock(basePath);
|
|
1339
|
+
const resumeLabel = interrupted.pausedSession?.stepMode
|
|
1340
|
+
? "Resume with /gsd next"
|
|
1341
|
+
: "Resume with /gsd auto";
|
|
1342
|
+
const resume = await showNextAction(ctx, {
|
|
1343
|
+
title: "GSD — Interrupted Session Detected",
|
|
1344
|
+
summary: formatInterruptedSessionSummary(interrupted),
|
|
1345
|
+
actions: [
|
|
1346
|
+
{ id: "resume", label: resumeLabel, description: "Pick up where it left off", recommended: true },
|
|
1347
|
+
{ id: "continue", label: "Continue manually", description: "Open the wizard as normal" },
|
|
1348
|
+
],
|
|
1349
|
+
});
|
|
1350
|
+
if (resume === "resume") {
|
|
1351
|
+
await startAuto(ctx, pi, basePath, false, {
|
|
1352
|
+
interrupted,
|
|
1353
|
+
step: interrupted.pausedSession?.stepMode ?? false,
|
|
1354
|
+
});
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1353
1357
|
}
|
|
1354
1358
|
|
|
1359
|
+
// Always derive from the project root — the assessment may have derived
|
|
1360
|
+
// state from a worktree path that was cleaned up in the stale branch above.
|
|
1355
1361
|
const state = await deriveState(basePath);
|
|
1356
1362
|
|
|
1357
1363
|
// Rebuild STATE.md from derived state before any dispatch (#3475).
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { verifyExpectedArtifact } from "./auto-recovery.js";
|
|
5
|
+
import {
|
|
6
|
+
formatCrashInfo,
|
|
7
|
+
isLockProcessAlive,
|
|
8
|
+
readCrashLock,
|
|
9
|
+
type LockData,
|
|
10
|
+
} from "./crash-recovery.js";
|
|
11
|
+
import { gsdRoot } from "./paths.js";
|
|
12
|
+
import {
|
|
13
|
+
synthesizeCrashRecovery,
|
|
14
|
+
type RecoveryBriefing,
|
|
15
|
+
} from "./session-forensics.js";
|
|
16
|
+
import { deriveState } from "./state.js";
|
|
17
|
+
import type { GSDState } from "./types.js";
|
|
18
|
+
|
|
19
|
+
export type InterruptedSessionClassification =
|
|
20
|
+
| "none"
|
|
21
|
+
| "running"
|
|
22
|
+
| "recoverable"
|
|
23
|
+
| "stale";
|
|
24
|
+
|
|
25
|
+
export interface PausedSessionMetadata {
|
|
26
|
+
milestoneId?: string;
|
|
27
|
+
worktreePath?: string | null;
|
|
28
|
+
originalBasePath?: string;
|
|
29
|
+
stepMode?: boolean;
|
|
30
|
+
pausedAt?: string;
|
|
31
|
+
sessionFile?: string | null;
|
|
32
|
+
unitType?: string;
|
|
33
|
+
unitId?: string;
|
|
34
|
+
activeEngineId?: string;
|
|
35
|
+
activeRunDir?: string | null;
|
|
36
|
+
autoStartTime?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface InterruptedSessionAssessment {
|
|
40
|
+
classification: InterruptedSessionClassification;
|
|
41
|
+
lock: LockData | null;
|
|
42
|
+
pausedSession: PausedSessionMetadata | null;
|
|
43
|
+
state: GSDState | null;
|
|
44
|
+
recovery: RecoveryBriefing | null;
|
|
45
|
+
recoveryPrompt: string | null;
|
|
46
|
+
recoveryToolCallCount: number;
|
|
47
|
+
artifactSatisfied: boolean;
|
|
48
|
+
hasResumableDiskState: boolean;
|
|
49
|
+
isBootstrapCrash: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function readPausedSessionMetadata(
|
|
53
|
+
basePath: string,
|
|
54
|
+
): PausedSessionMetadata | null {
|
|
55
|
+
const pausedPath = join(gsdRoot(basePath), "runtime", "paused-session.json");
|
|
56
|
+
if (!existsSync(pausedPath)) return null;
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
return JSON.parse(readFileSync(pausedPath, "utf-8")) as PausedSessionMetadata;
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function isBootstrapCrashLock(lock: LockData | null): boolean {
|
|
66
|
+
return !!(
|
|
67
|
+
lock &&
|
|
68
|
+
lock.unitType === "starting" &&
|
|
69
|
+
lock.unitId === "bootstrap"
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function hasResumableDerivedState(state: GSDState | null): boolean {
|
|
74
|
+
return !!(state?.activeMilestone && state.phase !== "complete");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function assessInterruptedSession(
|
|
78
|
+
basePath: string,
|
|
79
|
+
): Promise<InterruptedSessionAssessment> {
|
|
80
|
+
const pausedSession = readPausedSessionMetadata(basePath);
|
|
81
|
+
const worktreeExists = pausedSession?.worktreePath
|
|
82
|
+
? existsSync(pausedSession.worktreePath)
|
|
83
|
+
: false;
|
|
84
|
+
const assessmentBasePath = worktreeExists ? pausedSession!.worktreePath! : basePath;
|
|
85
|
+
const rawLock = readCrashLock(basePath);
|
|
86
|
+
const lock = rawLock && rawLock.pid !== process.pid ? rawLock : null;
|
|
87
|
+
|
|
88
|
+
if (!lock && !pausedSession) {
|
|
89
|
+
return {
|
|
90
|
+
classification: "none",
|
|
91
|
+
lock: null,
|
|
92
|
+
pausedSession: null,
|
|
93
|
+
state: null,
|
|
94
|
+
recovery: null,
|
|
95
|
+
recoveryPrompt: null,
|
|
96
|
+
recoveryToolCallCount: 0,
|
|
97
|
+
artifactSatisfied: false,
|
|
98
|
+
hasResumableDiskState: false,
|
|
99
|
+
isBootstrapCrash: false,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (lock && isLockProcessAlive(lock)) {
|
|
104
|
+
return {
|
|
105
|
+
classification: "running",
|
|
106
|
+
lock,
|
|
107
|
+
pausedSession,
|
|
108
|
+
state: null,
|
|
109
|
+
recovery: null,
|
|
110
|
+
recoveryPrompt: null,
|
|
111
|
+
recoveryToolCallCount: 0,
|
|
112
|
+
artifactSatisfied: false,
|
|
113
|
+
hasResumableDiskState: false,
|
|
114
|
+
isBootstrapCrash: false,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const isBootstrapCrash = isBootstrapCrashLock(lock);
|
|
119
|
+
const state = await deriveState(assessmentBasePath);
|
|
120
|
+
const hasResumableDiskState = hasResumableDerivedState(state);
|
|
121
|
+
const artifactSatisfied = !!(
|
|
122
|
+
lock &&
|
|
123
|
+
!isBootstrapCrash &&
|
|
124
|
+
verifyExpectedArtifact(lock.unitType, lock.unitId, assessmentBasePath)
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
let recovery: RecoveryBriefing | null = null;
|
|
128
|
+
if (lock && !isBootstrapCrash && !artifactSatisfied) {
|
|
129
|
+
recovery = synthesizeCrashRecovery(
|
|
130
|
+
assessmentBasePath,
|
|
131
|
+
lock.unitType,
|
|
132
|
+
lock.unitId,
|
|
133
|
+
lock.sessionFile,
|
|
134
|
+
join(gsdRoot(assessmentBasePath), "activity"),
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const recoveryToolCallCount = recovery?.trace.toolCallCount ?? 0;
|
|
139
|
+
const recoveryPrompt = recoveryToolCallCount > 0 ? recovery!.prompt : null;
|
|
140
|
+
|
|
141
|
+
if (isBootstrapCrash) {
|
|
142
|
+
return {
|
|
143
|
+
classification: pausedSession ? "recoverable" : "stale",
|
|
144
|
+
lock,
|
|
145
|
+
pausedSession,
|
|
146
|
+
state,
|
|
147
|
+
recovery,
|
|
148
|
+
recoveryPrompt,
|
|
149
|
+
recoveryToolCallCount,
|
|
150
|
+
artifactSatisfied,
|
|
151
|
+
hasResumableDiskState,
|
|
152
|
+
isBootstrapCrash: true,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!hasResumableDiskState && pausedSession && !lock && recoveryToolCallCount === 0) {
|
|
157
|
+
return {
|
|
158
|
+
classification: "stale",
|
|
159
|
+
lock,
|
|
160
|
+
pausedSession,
|
|
161
|
+
state,
|
|
162
|
+
recovery,
|
|
163
|
+
recoveryPrompt,
|
|
164
|
+
recoveryToolCallCount,
|
|
165
|
+
artifactSatisfied,
|
|
166
|
+
hasResumableDiskState,
|
|
167
|
+
isBootstrapCrash: false,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (lock && artifactSatisfied && !hasResumableDiskState && recoveryToolCallCount === 0) {
|
|
172
|
+
return {
|
|
173
|
+
classification: "stale",
|
|
174
|
+
lock,
|
|
175
|
+
pausedSession,
|
|
176
|
+
state,
|
|
177
|
+
recovery,
|
|
178
|
+
recoveryPrompt,
|
|
179
|
+
recoveryToolCallCount,
|
|
180
|
+
artifactSatisfied,
|
|
181
|
+
hasResumableDiskState,
|
|
182
|
+
isBootstrapCrash: false,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const hasStrongRecoverySignal =
|
|
187
|
+
hasResumableDiskState || recoveryToolCallCount > 0;
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
classification: hasStrongRecoverySignal ? "recoverable" : "stale",
|
|
191
|
+
lock,
|
|
192
|
+
pausedSession,
|
|
193
|
+
state,
|
|
194
|
+
recovery,
|
|
195
|
+
recoveryPrompt,
|
|
196
|
+
recoveryToolCallCount,
|
|
197
|
+
artifactSatisfied,
|
|
198
|
+
hasResumableDiskState,
|
|
199
|
+
isBootstrapCrash: false,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function formatInterruptedSessionSummary(
|
|
204
|
+
assessment: InterruptedSessionAssessment,
|
|
205
|
+
): string[] {
|
|
206
|
+
if (assessment.lock) return [formatCrashInfo(assessment.lock)];
|
|
207
|
+
|
|
208
|
+
if (assessment.pausedSession?.milestoneId) {
|
|
209
|
+
return [
|
|
210
|
+
`Paused auto-mode session detected for ${assessment.pausedSession.milestoneId}.`,
|
|
211
|
+
];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return ["Paused auto-mode session detected."];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export function formatInterruptedSessionRunningMessage(
|
|
218
|
+
assessment: InterruptedSessionAssessment,
|
|
219
|
+
): string {
|
|
220
|
+
const pid = assessment.lock?.pid;
|
|
221
|
+
return pid
|
|
222
|
+
? `Another auto-mode session (PID ${pid}) appears to be running.\nStop it with \`kill ${pid}\` before starting a new session.`
|
|
223
|
+
: "Another auto-mode session appears to be running.";
|
|
224
|
+
}
|
|
@@ -47,6 +47,7 @@ import { extractVerdict } from './verdict-parser.js';
|
|
|
47
47
|
|
|
48
48
|
import {
|
|
49
49
|
isDbAvailable,
|
|
50
|
+
wasDbOpenAttempted,
|
|
50
51
|
getAllMilestones,
|
|
51
52
|
getMilestone,
|
|
52
53
|
getMilestoneSlices,
|
|
@@ -271,7 +272,12 @@ export async function deriveState(basePath: string): Promise<GSDState> {
|
|
|
271
272
|
_telemetry.markdownDeriveCount++;
|
|
272
273
|
}
|
|
273
274
|
} else {
|
|
274
|
-
|
|
275
|
+
// Only warn when DB initialization was attempted and failed — not when
|
|
276
|
+
// the DB simply hasn't been opened yet (e.g. during before_agent_start
|
|
277
|
+
// context injection which runs before any tool invocation opens the DB).
|
|
278
|
+
if (wasDbOpenAttempted()) {
|
|
279
|
+
logWarning("state", "DB unavailable — using filesystem state derivation (degraded mode)");
|
|
280
|
+
}
|
|
275
281
|
result = await _deriveStateImpl(basePath);
|
|
276
282
|
_telemetry.markdownDeriveCount++;
|
|
277
283
|
}
|