Skip to content

Release v0.6.4-alpha.1: fix PostToolUse hooks hanging - #81

Merged
alokwhitewolf merged 2 commits into
mainfrom
release/0.6.4
Jul 1, 2026
Merged

Release v0.6.4-alpha.1: fix PostToolUse hooks hanging#81
alokwhitewolf merged 2 commits into
mainfrom
release/0.6.4

Conversation

@alokwhitewolf

Copy link
Copy Markdown
Collaborator

The 0.6.2 migration wrapped every hook command in a node -e launcher that
calls spawnSync(helper, {input}) with no timeout. The helper
(evo-hook-drain) hands off to the Python evo-drain, which inherits the
helper's stdout/stderr. spawnSync does not return until those captured pipes
reach EOF, i.e. until every descendant holding them exits. A lingering
descendant blocks the launcher forever, so the host shows the PostToolUse hook
"running" with a spinner and stuck node processes pile up. The host times the
hook out, so agent progress is never blocked, but the orphaned launcher keeps
spinning.

Fix

  • spawnSync passes timeout:2000 + killSignal:'SIGKILL', so a leaked
    descendant can no longer hang the hook. 2s is well under the host's 60s hook
    timeout and comfortably above a real sub-second drain.
  • stdin is read only when fd 0 is a real pipe (!tty.isatty(0)), so an
    interactive terminal never blocks readFileSync(0).

Applied to both launcher sources: plugins/evo/hooks/hooks.json (Claude Code)
and the Codex _stable_hook_command() generator. Adds a regression test that
spawns a helper whose grandchild outlives it on the inherited stdio and asserts
the hook still returns and fails open.

Release

Versioned 0.6.4-alpha.1 (alpha pre-release). All 9 version pins bumped via
scripts/bump-version.py; npm/ synced.

Verification

  • The hang reproduces on v0.6.3: the unbounded launcher blocks until the
    lingering descendant dies (capped only by the host's hook timeout).
  • Regression test passes in ~2s on this branch; against v0.6.3 it raises
    TimeoutExpired.

claude and others added 2 commits June 30, 2026 09:11
The 0.6.2 migration wrapped every hook command in a `node -e` launcher
that calls `spawnSync(helper, {input})` with no timeout. The helper
(`evo-hook-drain`) hands off to the Python `evo-drain`, which inherits
the helper's stdout/stderr (`Stdio::inherit()`). node's `spawnSync` does
not return until those captured pipes reach EOF, i.e. until every
descendant holding them exits. If any descendant lingers, the launcher
blocks forever, so the host shows the PostToolUse hook "running" with a
spinner and the stuck node processes pile up (the reported "6 PostToolUse
hooks with loading animations"). It never blocks agent progress because
the host times the hook out, but the orphaned launcher keeps spinning.

The launcher's own contract is to "fail open", but failing open requires
bounding every blocking call. Fix:

- `spawnSync` now passes `timeout:2000` + `killSignal:'SIGKILL'`, so a
  lingering/leaked descendant can no longer hang the hook. 2s is well
  under the host's 60s hook timeout and comfortably above a real
  sub-second drain.
- stdin is read only when fd 0 is a real pipe (`!tty.isatty(0)`), so an
  interactive terminal never blocks `readFileSync(0)`.

Applied to both launcher sources: the shared `plugins/evo/hooks/hooks.json`
(Claude Code) and the Codex `_stable_hook_command()` generator. Adds a
regression test that spawns a helper whose grandchild outlives it on the
inherited stdio and asserts the hook still returns and fails open.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VpudqCLoPU7Y29rAKLw3Eg
Alpha patch carrying the PostToolUse hook hang fix (bounded spawnSync
+ stdin tty-guard so the node launcher fails open instead of spinning
indefinitely). spawnSync timeout set to 2s.

Bumps all version pins via scripts/bump-version.py and syncs npm/.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@alokwhitewolf
alokwhitewolf merged commit 884031c into main Jul 1, 2026
43 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants