fix: execute all Stop hooks instead of returning after first non-blocking result

Previously, executeStopHooks returned immediately after the first hook
that produced valid JSON stdout, even if it was non-blocking. This
prevented subsequent hooks from executing.

This was problematic when users had multiple Stop hooks (e.g.,
check-console-log.js + task-complete-notify.sh in settings.json),
because the first hook's stdout (which echoed stdin data as JSON)
caused an early return, silently skipping all remaining hooks.

Now only explicitly blocking results (exit code 2 or decision=block)
cause an early return, matching Claude Code's behavior of executing
all Stop hooks sequentially.

Closes #1707
This commit is contained in:
raki-1203
2026-02-12 16:09:13 +09:00
parent d358e6e48e
commit 5c8d694491
2 changed files with 211 additions and 8 deletions
+11 -8
View File
@@ -99,14 +99,17 @@ export async function executeStopHooks(
stopHookActiveState.set(ctx.sessionId, output.stop_hook_active)
}
const isBlock = output.decision === "block"
// Determine inject_prompt: prefer explicit value, fallback to reason if blocking
const injectPrompt = output.inject_prompt ?? (isBlock && output.reason ? output.reason : undefined)
return {
block: isBlock,
reason: output.reason,
stopHookActive: output.stop_hook_active,
permissionMode: output.permission_mode,
injectPrompt,
// Only return early if the hook explicitly blocks - non-blocking hooks
// should not prevent subsequent hooks from executing (matches Claude Code behavior)
if (isBlock) {
const injectPrompt = output.inject_prompt ?? (output.reason || undefined)
return {
block: true,
reason: output.reason,
stopHookActive: output.stop_hook_active,
permissionMode: output.permission_mode,
injectPrompt,
}
}
} catch {
// Ignore JSON parse errors - hook may return non-JSON output