.maestro/playbooks/2026-03-12-CM-Issues-PRs/2026-03-12-Issues-PRs-Triage/TRIAGE-03-Stop-Hook-Session-Lifecycle.md
Stop hook failures are the second most impactful bug class — they cause error loops visible to users at the end of every session, prevent summary generation, and on Windows can crash entirely. These issues directly degrade the user experience because they happen at session boundaries where the user is paying attention.
Issues addressed: #1346, #1281, #1274 Prerequisite: Phase 01 should be complete (PRs #1330, #1291, #1326 address related stop hook issues).
Fix port collision when multiple Claude Code sessions start concurrently (#1346). When two sessions start simultaneously, the second session's worker start attempt fails with "port 37777 in use" error. The fix is to make worker startup idempotent:
src/cli/hook-command.ts — find the ensureWorkerRunning() function or equivalent startup logicsrc/services/infrastructure/HealthMonitor.ts — find isPortInUse() (around line 20-29)isPortInUse(). If port is occupied AND health check passes (/api/health returns 200), exit silently with code 0 — the worker is already runningFix Windows Stop hook MODULE_NOT_FOUND (#1281). On Windows, backslash path corruption in hook commands causes the stop hook script to fail with MODULE_NOT_FOUND:
plugin/hooks/hooks.json to see how hook script paths are constructedpath.join() in hook command generationnode -e "require(...)" pattern that handles both path separatorsscripts/build-hooks.js for how hooks.json is generated — the fix may need to go thereprintf | tr to normalize CLAUDE_PLUGIN_ROOT backslashes to forward slashes before path interpolation, (2) switched hooks.json from bun-exec-runner.sh (Unix-only shell script) to node bun-runner.js (cross-platform, already has Windows path normalization at lines 111-117). Updated plugin-distribution tests — all 25 pass. All 90 hook-related tests pass. 1026/1047 total tests pass (21 failures are pre-existing ChromaSync dependency issues).Fix Stop hook crash after context compaction (#1274). When Claude Code compacts context mid-session, the transcript path moves or disappears, causing the stop hook to crash with "Transcript path missing":
transcript in src/cli/handlers/ to find where transcript paths are readexistsSync(transcriptPath) before attempting to read. If missing, log a warning and proceed with a degraded summary (use the last known assistant message instead of full transcript)CLAUDE_CONVERSATION env var — if compaction changes this, the fallback should try both the original and compacted pathsextractLastMessage() call in summarize.ts with try-catch. When transcript file is missing, empty, or unreadable (e.g., after context compaction), the handler logs a warning and proceeds with an empty last_assistant_message — the worker still receives the summary request for session cleanup. Previously, transcript-parser.ts threw an error that propagated to hook-command.ts which exited with code 2 (BLOCKING_ERROR), crashing the stop hook. Added 5 tests covering: missing file, empty file, valid transcript, no path, and warning log verification. All 1149 tests pass.Run tests and verify stop hook behavior:
npm test — all tests must passnpm run build-and-syncplugin/hooks/hooks.json and check all command values use forward slashesnode "$_R/scripts/bun-runner.js" with forward slashes throughout; no backslashes present in any command value. Phase 03 complete.