From 84bbced08b6843d89ce89fa48050b02d71369f15 Mon Sep 17 00:00:00 2001 From: ANGELES00004 Date: Fri, 29 May 2026 23:53:41 -0600 Subject: [PATCH] fix(plugin): detach daemon from job control + bound hook curls with --max-time The SessionStart hook starts `engram serve` with a bare `&`, leaving the daemon in the parent shell's process group and attached to its controlling terminal. On Linux/WSL2 a Ctrl-Z (SIGTSTP) or terminal close can suspend the daemon into state T: it keeps port 7437 bound but stops answering. Since the Stop hook's curl has no --max-time, every session close then hangs forever and leaks a bash+curl process, accumulating one per stop. - session-start.sh: launch the daemon via setsid (fallback nohup) in its own session with no controlling terminal, immune to SIGTSTP/SIGHUP. - session-stop.sh, session-start.sh, post-compaction.sh: add --max-time 3 to the remaining hook curls so an unresponsive daemon fails fast instead of hanging and leaking processes. --- plugin/claude-code/scripts/post-compaction.sh | 2 +- plugin/claude-code/scripts/session-start.sh | 16 ++++++++++++---- plugin/claude-code/scripts/session-stop.sh | 4 +++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/plugin/claude-code/scripts/post-compaction.sh b/plugin/claude-code/scripts/post-compaction.sh index 7905af9f..cb61aac1 100755 --- a/plugin/claude-code/scripts/post-compaction.sh +++ b/plugin/claude-code/scripts/post-compaction.sh @@ -19,7 +19,7 @@ PROJECT=$(detect_project "$CWD") # Ensure session exists if [ -n "$SESSION_ID" ] && [ -n "$PROJECT" ]; then - curl -sf "${ENGRAM_URL}/sessions" \ + curl -sf --max-time 3 "${ENGRAM_URL}/sessions" \ -X POST \ -H "Content-Type: application/json" \ -d "$(jq -n --arg id "$SESSION_ID" --arg project "$PROJECT" --arg dir "$CWD" \ diff --git a/plugin/claude-code/scripts/session-start.sh b/plugin/claude-code/scripts/session-start.sh index d077638a..9fd4337d 100755 --- a/plugin/claude-code/scripts/session-start.sh +++ b/plugin/claude-code/scripts/session-start.sh @@ -23,15 +23,23 @@ CWD=$(echo "$INPUT" | jq -r '.cwd // empty') OLD_PROJECT=$(basename "$CWD" | tr '[:upper:]' '[:lower:]') PROJECT=$(detect_project "$CWD") -# Ensure engram server is running +# Ensure engram server is running. +# Detach the daemon from the parent shell's job control: start it in a new +# session with no controlling terminal so a Ctrl-Z (SIGTSTP) or SIGHUP on the +# terminal can't suspend it. A suspended daemon keeps the port bound but stops +# answering, which hangs every later hook curl and leaks processes over time. if ! curl -sf "${ENGRAM_URL}/health" --max-time 1 > /dev/null 2>&1; then - engram serve &>/dev/null & + if command -v setsid > /dev/null 2>&1; then + setsid engram serve < /dev/null > /dev/null 2>&1 & + else + nohup engram serve < /dev/null > /dev/null 2>&1 & + fi sleep 0.5 fi # Migrate project name if it changed (one-time, idempotent) if [ "$OLD_PROJECT" != "$PROJECT" ] && [ -n "$OLD_PROJECT" ] && [ -n "$PROJECT" ]; then - curl -sf "${ENGRAM_URL}/projects/migrate" \ + curl -sf --max-time 3 "${ENGRAM_URL}/projects/migrate" \ -X POST \ -H "Content-Type: application/json" \ -d "$(jq -n --arg old "$OLD_PROJECT" --arg new "$PROJECT" \ @@ -41,7 +49,7 @@ fi # Create session if [ -n "$SESSION_ID" ] && [ -n "$PROJECT" ]; then - curl -sf "${ENGRAM_URL}/sessions" \ + curl -sf --max-time 3 "${ENGRAM_URL}/sessions" \ -X POST \ -H "Content-Type: application/json" \ -d "$(jq -n --arg id "$SESSION_ID" --arg project "$PROJECT" --arg dir "$CWD" \ diff --git a/plugin/claude-code/scripts/session-stop.sh b/plugin/claude-code/scripts/session-stop.sh index a05d57a1..a958c0a4 100755 --- a/plugin/claude-code/scripts/session-stop.sh +++ b/plugin/claude-code/scripts/session-stop.sh @@ -14,7 +14,9 @@ if [ -z "$SESSION_ID" ]; then exit 0 fi -curl -sf "${ENGRAM_URL}/sessions/${SESSION_ID}/end" \ +# --max-time bounds the request: if the daemon is unreachable or unresponsive +# the curl fails fast instead of hanging forever and leaking a process per stop. +curl -sf --max-time 3 "${ENGRAM_URL}/sessions/${SESSION_ID}/end" \ -X POST \ -H "Content-Type: application/json" \ -d '{}' \