From c571bc4e2394734f61999e18c9cdd04dcc7f8418 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Wed, 16 Sep 2026 18:33:35 -0700 Subject: [PATCH] fix(native-chat): satisfy lifecycle CI guards --- src/main/claude/claude-structured-dispatch.ts | 9 ++---- .../claude/claude-structured-session-state.ts | 8 +++++ .../use-structured-conversation-command.ts | 30 +++++++++++-------- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/main/claude/claude-structured-dispatch.ts b/src/main/claude/claude-structured-dispatch.ts index 33fbe673b32..3206ecf6f5b 100644 --- a/src/main/claude/claude-structured-dispatch.ts +++ b/src/main/claude/claude-structured-dispatch.ts @@ -1,11 +1,11 @@ import { randomUUID } from 'node:crypto' -import type { AgentJournalMessageItem } from '../../shared/agent-session-journal-types' import type { AgentSessionDispatchOutcome } from '../native-chat/agent-session-wire/structured-agent-session-adapter' import { claudeHasReplayContent, readClaudeMessageEnvelope } from './claude-structured-item-translation' import type { + ClaudeDispatchTurnInput, ClaudeDispatchWaiter, ClaudeLateDispatchOutcome, ClaudeSession @@ -279,12 +279,7 @@ export function retireClaudeDispatchWaiters(session: ClaudeSession): void { export async function dispatchClaudeTurn( session: ClaudeSession, - input: { - clientMessageId?: string - providerMessageUuid?: string - body: AgentJournalMessageItem - requestedAt?: number - } + input: ClaudeDispatchTurnInput ): Promise { let content: unknown[] try { diff --git a/src/main/claude/claude-structured-session-state.ts b/src/main/claude/claude-structured-session-state.ts index 055a477c74c..ad888e760b4 100644 --- a/src/main/claude/claude-structured-session-state.ts +++ b/src/main/claude/claude-structured-session-state.ts @@ -1,5 +1,6 @@ import type { AgentJournalItemIdentity, + AgentJournalMessageItem, AgentSessionJournalIdentity } from '../../shared/agent-session-journal-types' import type { StructuredAgentSessionEventSink } from '../native-chat/agent-session-wire/structured-agent-session-event-sink' @@ -72,6 +73,13 @@ export type ClaudeLateDispatchOutcome = } | { clientMessageId: string; state: 'rejected'; reason: string } +export type ClaudeDispatchTurnInput = { + clientMessageId?: string + providerMessageUuid?: string + body: AgentJournalMessageItem + requestedAt?: number +} + export type ClaudeStructuredSessionAdapterDeps = { resolveLaunch: (input: { identity: AgentSessionJournalIdentity diff --git a/src/renderer/src/components/native-chat/use-structured-conversation-command.ts b/src/renderer/src/components/native-chat/use-structured-conversation-command.ts index 26d18a76133..d69b3a25717 100644 --- a/src/renderer/src/components/native-chat/use-structured-conversation-command.ts +++ b/src/renderer/src/components/native-chat/use-structured-conversation-command.ts @@ -34,12 +34,16 @@ export function useStructuredConversationCommand(args: { retire: () => void } { const { blocked, fence, items, mutate, onReconciled, sessionId, target } = args - const claim = useRef(new StructuredConversationCommandClaim()) + const claimRef = useRef(null) + if (claimRef.current === null) { + claimRef.current = new StructuredConversationCommandClaim() + } + const claim = claimRef.current const operationIds = useRef(new Map()) const requestScope = structuredAgentSessionMutationScope(target, sessionId) useEffect(() => { - const settledOperationIds = claim.current.applyStreamSnapshot(items) + const settledOperationIds = claim.applyStreamSnapshot(items) for (const operationId of settledOperationIds) { for (const [command, candidate] of operationIds.current) { if (candidate === operationId) { @@ -48,31 +52,31 @@ export function useStructuredConversationCommand(args: { } onReconciled(operationId) } - }, [items, onReconciled]) + }, [claim, items, onReconciled]) // A restart supersedes whatever the previous fence still owed. useEffect(() => { - const current = claim.current + const current = claim const ids = operationIds.current return () => { ids.delete('compact') current.reset(true) } - }, [fence]) + }, [claim, fence]) useLayoutEffect(() => { - const current = claim.current + const current = claim const ids = operationIds.current return () => { ids.clear() current.reset() } - }, [requestScope]) + }, [claim, requestScope]) return { run: (command) => { - if (claim.current.isRunning) { - return claim.current.run({ + if (claim.isRunning) { + return claim.run({ command, operationId: '', blocked, @@ -83,7 +87,7 @@ export function useStructuredConversationCommand(args: { // this command's terminal frame. const operationId = operationIds.current.get(command) ?? structuredSessionOperationId() operationIds.current.set(command, operationId) - return claim.current + return claim .run({ command, operationId, @@ -100,7 +104,7 @@ export function useStructuredConversationCommand(args: { onReconciled(operationId) return { status: 'unresolved' } } - if (!claim.current.isOperationOutstanding(operationId)) { + if (!claim.isOperationOutstanding(operationId)) { onReconciled(operationId) } if (disposition.status === 'refused') { @@ -123,10 +127,10 @@ export function useStructuredConversationCommand(args: { return outcome }) }, - isRunning: () => claim.current.isRunning, + isRunning: () => claim.isRunning, retire: () => { operationIds.current.clear() - claim.current.reset() + claim.reset() } } }