fix: bound /dev/tty write so hooks can't hang when Warp UI is unresponsive#37
Open
tebayoso wants to merge 1 commit into
Open
Conversation
…nsive The OSC 777 notification write in warp-notify.sh blocks indefinitely if the slave PTY's output buffer fills up and stops draining — for example, when Warp's UI is hung and not reading from the master PTY. The block propagates back up the hook chain (warp-notify.sh -> on-*.sh -> claude), freezing the calling Claude Code session until Warp recovers. Observed in production as a 36-minute session lockup. Wrap the printf in a pure-bash watchdog: spawn the writer in the background, force-kill it after WARP_NOTIFY_TIMEOUT_SEC seconds (default 2) if the syscall hasn't returned. The script stays best-effort and always exits 0. A new WARP_NOTIFY_TARGET env var lets tests redirect output away from /dev/tty. Adds plugins/warp/tests/test-warp-notify.sh which simulates the failure mode via a FIFO with no reader (kernel-level identical to a slave PTY whose master isn't reading) and verifies the watchdog fires within the configured timeout. CI's globstar pattern picks up the new file automatically. Same patch applied to scripts/legacy/warp-notify.sh.
3 tasks
skspade
added a commit
to skspade/claude-code-warp
that referenced
this pull request
May 13, 2026
… Warp UI is unresponsive Resolution: hybrid of warpdotdev#44's tty walker and warpdotdev#37's timeout watchdog. Each candidate tty is now tried with a TIMEOUT_SEC watchdog (default 2s) so a hung Warp UI on one tty falls through to the next ancestor instead of blocking forever.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
warp-notify.shwrites the OSC 777 notification with no timeout:If the slave PTY's output buffer fills up and stops draining — for example, when Warp's UI is hung and not reading from the master side — this
printfblocks indefinitely on the kernelwrite(). The block then propagates back up the hook chain (warp-notify.sh→on-prompt-submit.sh/on-stop.sh/ etc. → the Claude Code session), freezing the whole CLI agent until Warp's renderer recovers.The trailing
|| trueshows the original author intended this to be best-effort; the gap is that "best-effort" was never bounded in time.Reproducer
osascript -e 'tell application \"Warp\" to activate'recovered it).warp-notify.sh.The hook subprocess parks in
printf > /dev/ttyand the Claude Code session is frozen until Warp drains the buffer. Observed in production as a 36-minute lockup; the only way to recover withoutkillwas to wake Warp's UI from outside.Diagnosed via
lsof -p <hook_pid>(FD 1 →/dev/ttys000, blocked) and confirmed by writing one byte to the same TTY from a different shell — also blocked, ruling out anything specific to the hook process.Fix
Wrap the
printfin a pure-bash watchdog: spawn the writer as a backgrounded subshell, force-kill it afterWARP_NOTIFY_TIMEOUT_SECseconds (default2) if it hasn't completed. The script stays best-effort (always exits0). No externaltimeout(1)dependency, so it works the same on macOS bash 3.2 and Linux bash 5.{ printf '%s' "$SEQ" > "$TARGET" 2>/dev/null; } & writer_pid=$! { sleep "$TIMEOUT_SEC" 2>/dev/null; kill -KILL "$writer_pid" 2>/dev/null; } & watchdog_pid=$! wait "$writer_pid" 2>/dev/null kill -KILL "$watchdog_pid" 2>/dev/null; wait "$watchdog_pid" 2>/dev/null exit 0Worst case impact: a hook adds at most ~2s instead of hanging the session forever. Same patch applied to the legacy variant.
A new
WARP_NOTIFY_TARGETenv var (default/dev/tty) lets tests redirect output without touching/dev/ttydirectly — needed because CI has no TTY.Tests
Adds
plugins/warp/tests/test-warp-notify.sh, picked up automatically by the existing globstar pattern in.github/workflows/test.yml.Three scenarios per variant:
WARP_NOTIFY_TARGETat a FIFO with no reader. The kernel blocksopen()/write()on such a FIFO the same way it blocks writes to a slave PTY whose master isn't reading, which is the exact failure mode reproduced in production. Verifies the watchdog kicks in within the configured timeout and the script still exits 0.WARP_NOTIFY_TIMEOUT_SEC, blocked writes still cap at the 2s default.Runs locally on macOS and on Ubuntu (the CI runner). All 39 existing tests still pass.
Notes