diff --git a/src/features/boulder-state/storage.ts b/src/features/boulder-state/storage.ts index c42fc881..2b0d1bde 100644 --- a/src/features/boulder-state/storage.ts +++ b/src/features/boulder-state/storage.ts @@ -22,7 +22,14 @@ export function readBoulderState(directory: string): BoulderState | null { try { const content = readFileSync(filePath, "utf-8") - return JSON.parse(content) as BoulderState + const parsed = JSON.parse(content) + if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) { + return null + } + if (!Array.isArray(parsed.session_ids)) { + parsed.session_ids = [] + } + return parsed as BoulderState } catch { return null } @@ -48,7 +55,10 @@ export function appendSessionId(directory: string, sessionId: string): BoulderSt const state = readBoulderState(directory) if (!state) return null - if (!state.session_ids.includes(sessionId)) { + if (!state.session_ids?.includes(sessionId)) { + if (!Array.isArray(state.session_ids)) { + state.session_ids = [] + } state.session_ids.push(sessionId) if (writeBoulderState(directory, state)) { return state diff --git a/src/hooks/atlas/event-handler.ts b/src/hooks/atlas/event-handler.ts index 4d33b7da..0857c3db 100644 --- a/src/hooks/atlas/event-handler.ts +++ b/src/hooks/atlas/event-handler.ts @@ -41,7 +41,7 @@ export function createAtlasEventHandler(input: { // Read boulder state FIRST to check if this session is part of an active boulder const boulderState = readBoulderState(ctx.directory) - const isBoulderSession = boulderState?.session_ids.includes(sessionID) ?? false + const isBoulderSession = boulderState?.session_ids?.includes(sessionID) ?? false const isBackgroundTaskSession = subagentSessions.has(sessionID) diff --git a/src/hooks/atlas/tool-execute-after.ts b/src/hooks/atlas/tool-execute-after.ts index a922e422..f82f3e49 100644 --- a/src/hooks/atlas/tool-execute-after.ts +++ b/src/hooks/atlas/tool-execute-after.ts @@ -65,7 +65,7 @@ export function createToolExecuteAfterHandler(input: { if (boulderState) { const progress = getPlanProgress(boulderState.active_plan) - if (toolInput.sessionID && !boulderState.session_ids.includes(toolInput.sessionID)) { + if (toolInput.sessionID && !boulderState.session_ids?.includes(toolInput.sessionID)) { appendSessionId(ctx.directory, toolInput.sessionID) log(`[${HOOK_NAME}] Appended session to boulder`, { sessionID: toolInput.sessionID, diff --git a/src/hooks/prometheus-md-only/agent-resolution.ts b/src/hooks/prometheus-md-only/agent-resolution.ts index 6035209b..b59c5a3a 100644 --- a/src/hooks/prometheus-md-only/agent-resolution.ts +++ b/src/hooks/prometheus-md-only/agent-resolution.ts @@ -43,7 +43,7 @@ export function getAgentFromSession(sessionID: string, directory: string): strin // Check boulder state (persisted across restarts) - fixes #927 const boulderState = readBoulderState(directory) - if (boulderState?.session_ids.includes(sessionID) && boulderState.agent) { + if (boulderState?.session_ids?.includes(sessionID) && boulderState.agent) { return boulderState.agent }