From f4be4fd4318c203fb7e4d7fbd3c4080325fe0ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Thu, 6 Aug 2026 22:49:32 +0000 Subject: [PATCH] write the claude session id through instead of debouncing it the sessionKey to claude uuid map is what --resume needs to reattach a conversation after the agent sidecar dies, so a 30s debounce put exactly the wrong state behind a window. flushAndSave on SIGTERM covers a pm2 restart but not a crash or SIGKILL, which is the case resume exists for. an equality guard keeps onSessionId from thrashing the file. Co-Authored-By: Claude Opus 5 --- src/servers/sidecar/claude/state.ts | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/servers/sidecar/claude/state.ts b/src/servers/sidecar/claude/state.ts index b55e63ec..59dfd5fc 100644 --- a/src/servers/sidecar/claude/state.ts +++ b/src/servers/sidecar/claude/state.ts @@ -71,14 +71,34 @@ export function updateState(patch: Partial): void { scheduleSave(); } +/** + * Both of these write through instead of debouncing. + * + * This map is the only thing that lets a conversation be reattached with `--resume` after the agent + * sidecar dies, so it is precisely the state that must not be in a 30s window when the process is + * killed rather than asked to stop — `flushAndSave` on SIGTERM covers a `pm2 restart`, but not a + * crash or a SIGKILL, which is the case the resume path exists for. Losing it silently starts the + * next turn as a fresh Claude session and orphans the transcript on disk. + * + * There is nothing to debounce: `onSessionId` fires on every message but with the same id, so the + * equality guard collapses it to one write per session, and clearing happens once. + */ export function setClaudeSession(sessionKey: string, sessionId: string): void { + if (currentState.claudeSessions[sessionKey] === sessionId) return; currentState.claudeSessions[sessionKey] = sessionId; - scheduleSave(); + writeThrough(); } export function clearClaudeSession(sessionKey: string): void { + if (!(sessionKey in currentState.claudeSessions)) return; delete currentState.claudeSessions[sessionKey]; - scheduleSave(); + writeThrough(); +} + +function writeThrough(): void { + void flushAndSave().catch((err) => { + console.error('[claude-state] save failed:', err instanceof Error ? err.message : err); + }); } export function getClaudeSession(sessionKey: string): string | undefined {