From 8ee6bdcd0e09da6d72be1a18708a08efd8260aa3 Mon Sep 17 00:00:00 2001 From: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Date: Thu, 20 Aug 2026 03:27:08 -0700 Subject: [PATCH] fix(agent-status): rollback rejected Claude cache mutations --- .../server-hook-http-ingest.test.ts | 4 ++ src/main/agent-hooks/server.ts | 39 ++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/main/agent-hooks/server-hook-http-ingest.test.ts b/src/main/agent-hooks/server-hook-http-ingest.test.ts index b7ae5981d6b..3791ca7a489 100644 --- a/src/main/agent-hooks/server-hook-http-ingest.test.ts +++ b/src/main/agent-hooks/server-hook-http-ingest.test.ts @@ -165,6 +165,8 @@ describe('AgentHookServer listener replay', () => { }) const parent = server.getStatusSnapshot()[0] const state = server._getStateForTests() + const parentPrompt = state.lastPromptByPaneKey.get(PANE) + const parentTool = state.lastToolByPaneKey.get(PANE) state.claudeSubagentRosterByPaneKey.set( PANE, new Map([['agent-1', { state: 'working', startedAt: 1 }]]) @@ -197,6 +199,8 @@ describe('AgentHookServer listener replay', () => { server._getStateForTests().claudeSubagentRosterByPaneKey.get(PANE)?.has('agent-1') ).toBe(true) expect(server._getStateForTests().claudeLeadStateByPaneKey.has(PANE)).toBe(false) + expect(server._getStateForTests().lastPromptByPaneKey.get(PANE)).toBe(parentPrompt) + expect(server._getStateForTests().lastToolByPaneKey.get(PANE)).toEqual(parentTool) } finally { server.stop() rmSync(dir, { recursive: true, force: true }) diff --git a/src/main/agent-hooks/server.ts b/src/main/agent-hooks/server.ts index 1fc36a1d2ed..67eac3b4192 100644 --- a/src/main/agent-hooks/server.ts +++ b/src/main/agent-hooks/server.ts @@ -40,7 +40,8 @@ import { writeEndpointFile, type AgentHookEventPayload, type ClaudeLeadTurnState, - type HookListenerState + type HookListenerState, + type ToolSnapshot } from '../../shared/agent-hook-listener' import { createHookTransportInterferenceTracker, @@ -2055,6 +2056,9 @@ export class AgentHookServer { this.state.claudeSubagentRosterByPaneKey.get(paneKey) ) const previousLeadState = this.cloneClaudeLeadState(paneKey) + const previousPrompt = this.state.lastPromptByPaneKey.get(paneKey) + const previousTool = this.cloneClaudeToolState(paneKey) + const previousUnconfirmed = this.state.claudeUnconfirmedRestoredStatusPaneKeys.has(paneKey) const event = normalizeHookPayload(this.state, source, body, this.env) const nextRunningTask = this.state.claudeRunningNonAgentTaskPaneKeys.has(paneKey) const nextTaskObservations = new Map( @@ -2067,6 +2071,9 @@ export class AgentHookServer { this.state.claudeSubagentRosterByPaneKey.get(paneKey) ) const nextLeadState = this.cloneClaudeLeadState(paneKey) + const nextPrompt = this.state.lastPromptByPaneKey.get(paneKey) + const nextTool = this.cloneClaudeToolState(paneKey) + const nextUnconfirmed = this.state.claudeUnconfirmedRestoredStatusPaneKeys.has(paneKey) this.setClaudeBackgroundEvidence( paneKey, previousRunningTask, @@ -2076,6 +2083,7 @@ export class AgentHookServer { ) this.setClaudeSubagentRoster(paneKey, previousSubagentRoster) this.setClaudeLeadState(paneKey, previousLeadState) + this.setClaudeNormalizationCache(paneKey, previousPrompt, previousTool, previousUnconfirmed) if (!event || event.paneKey !== paneKey) { return { event } } @@ -2092,6 +2100,7 @@ export class AgentHookServer { ) this.setClaudeSubagentRoster(paneKey, nextSubagentRoster) this.setClaudeLeadState(paneKey, nextLeadState) + this.setClaudeNormalizationCache(paneKey, nextPrompt, nextTool, nextUnconfirmed) } } } @@ -2122,6 +2131,34 @@ export class AgentHookServer { } } + private cloneClaudeToolState(paneKey: string): ToolSnapshot | undefined { + const tool = this.state.lastToolByPaneKey.get(paneKey) + return tool ? { ...tool } : undefined + } + + private setClaudeNormalizationCache( + paneKey: string, + prompt: string | undefined, + tool: ToolSnapshot | undefined, + restoredUnconfirmed: boolean + ): void { + if (prompt === undefined) { + this.state.lastPromptByPaneKey.delete(paneKey) + } else { + this.state.lastPromptByPaneKey.set(paneKey, prompt) + } + if (tool === undefined) { + this.state.lastToolByPaneKey.delete(paneKey) + } else { + this.state.lastToolByPaneKey.set(paneKey, tool) + } + if (restoredUnconfirmed) { + this.state.claudeUnconfirmedRestoredStatusPaneKeys.add(paneKey) + } else { + this.state.claudeUnconfirmedRestoredStatusPaneKeys.delete(paneKey) + } + } + private setClaudeBackgroundEvidence( paneKey: string, hasRunningTask: boolean,