From 1ba44198c1b8ca1ce63e4cb470f5ffb964d301df Mon Sep 17 00:00:00 2001 From: David Raitzyk Date: Thu, 16 Jul 2026 10:31:26 -0400 Subject: [PATCH] fix(session-end): remove .unref() so setTimeout force-exits after 1500ms Pending fetch() calls keep the Node.js event loop alive until their AbortSignal timeouts fire (30s normally, up to 120s with CONSOLIDATION_ENABLED). With .unref(), the setTimeout becomes passive and never fires while those fetches are in flight, so the hook process outlives Claude Code's hook timeout and gets killed with 'Hook cancelled'. Removing .unref() makes the timer active: the process exits after 1500ms regardless of in-flight fetches. The fetches are fire-and-forget to the local daemon anyway, so exiting before they settle is correct behavior. --- plugin/scripts/session-end.mjs | 2 +- src/hooks/session-end.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/plugin/scripts/session-end.mjs b/plugin/scripts/session-end.mjs index 019149c30..de2f6d53f 100755 --- a/plugin/scripts/session-end.mjs +++ b/plugin/scripts/session-end.mjs @@ -51,7 +51,7 @@ async function main() { headers: authHeaders(), signal: AbortSignal.timeout(3e4) }).catch(() => {}); - setTimeout(() => process.exit(0), 1500).unref(); + setTimeout(() => process.exit(0), 1500); } main(); diff --git a/src/hooks/session-end.ts b/src/hooks/session-end.ts index 6a9fc429c..1ce7773fe 100644 --- a/src/hooks/session-end.ts +++ b/src/hooks/session-end.ts @@ -63,7 +63,11 @@ async function main() { }).catch(() => {}); } - setTimeout(() => process.exit(0), 1500).unref(); + // Force-exit after 1500ms regardless of in-flight fetches. Without this, + // .unref() makes the timer passive and pending fetch() calls keep the event + // loop alive until their AbortSignal timeouts fire (up to 120s), causing + // Claude Code to cancel the hook with "Hook cancelled". + setTimeout(() => process.exit(0), 1500); } main();