Repository navigation
fix: handle EAGAIN in hook scripts readHookInput (#120) - #150
D2758695161 wants to merge 3 commits into
Conversation
Fixes openai#120 - Catch EAGAIN when reading non-blocking stdin in hooks
Fixes openai#120 - Catch EAGAIN when reading non-blocking stdin in hooks
|
👋 Following up — ready for review! — 一筒 🦀 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2d542f8521
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const { options, positionals } = parseCommandInput(argv, { | ||
| valueOptions: ["model", "effort", "cwd", "prompt-file"], | ||
| booleanOptions: ["json", "write", "resume-last", "resume", "fresh", "background"], | ||
| booleanOptions: ["json", "write", "full-access", "resume-last", "resume", "fresh", "background"], |
There was a problem hiding this comment.
Wire --full-access through task execution
handleTask now advertises --full-access, but the parsed value is never read or passed into the task request, so executeTaskRun always sees request.fullAccess as falsy and falls back to workspace-write/read-only. In practice, running task --full-access ... is a no-op for both foreground and background runs, which breaks the new CLI contract and can cause tasks requiring full sandbox access to fail unexpectedly.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2d542f8521
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const { options, positionals } = parseCommandInput(argv, { | ||
| valueOptions: ["model", "effort", "cwd", "prompt-file"], | ||
| booleanOptions: ["json", "write", "resume-last", "resume", "fresh", "background"], | ||
| booleanOptions: ["json", "write", "full-access", "resume-last", "resume", "fresh", "background"], |
There was a problem hiding this comment.
Wire --full-access through task execution
handleTask now advertises --full-access, but the parsed value is never read or passed into the task request, so executeTaskRun always sees request.fullAccess as falsy and falls back to workspace-write/read-only. In practice, running task --full-access ... is a no-op for both foreground and background runs, which breaks the new CLI contract and can cause tasks requiring full sandbox access to fail unexpectedly.
Useful? React with 👍 / 👎.
|
👋 Checking in — still ready for review. Happy to address any feedback! — 一筒 🦀 |
…eview prompt via stdin New lib/hook-input.mjs readHookInput(): streams stdin with a deadline (2 s default, CODEX_HOOK_STDIN_TIMEOUT_MS for tests), a 1 MiB byte limit and a StringDecoder across chunk boundaries. EOF parses the whole input; at the deadline a buffer that is already a complete JSON object is accepted (only the EOF was late), anything else is `timeout`; over the limit is `overflow` without parsing; bad JSON is `invalid-json`. Listeners and the timer are removed and stdin destroyed, so the hook exits right after deciding. Stop hook: any read error blocks as before (fail-closed), except a timeout with nothing received while the workspace gate (CLAUDE_PROJECT_DIR / cwd) is off, which allows (openai#530/openai#544). With the gate on, a timeout blocks naming "hook input did not arrive". The review prompt now reaches the companion via `task --prompt-stdin`, not argv, lifting the Windows/Linux argv limits. SessionStart/SessionEnd hook: reads with a 1 s deadline before the 12 s SessionEnd budget starts; on any read error it prints one stderr line and returns without cleanup. The hooks.json timeout test now asserts 15 s > budget + read. readStdinIfPiped (companion): readSync loop that keeps accumulated bytes across EAGAIN on a non-blocking stdin (up to 50 x 20 ms consecutive) and throws on exhaustion instead of returning a partial prompt (openai#120/openai#247/openai#123/openai#150/openai#165). Co-authored-by: stantheman0128 <[email protected]> Co-authored-by: tmchow <[email protected]> Co-Authored-By: Claude Fable 5.1 <[email protected]>
Summary
Fixes #120: Hook scripts crash with
EAGAIN: resource temporarily unavailablewhen reading non-blocking stdin.Problem
readHookInput()usesfs.readFileSync(0, "utf8")to read stdin. When Claude Code invokes hooks with stdin as a non-blocking pipe, the kernel returnsEAGAINinstead of blocking, causing Node.js to throw.Solution
Wrap
readFileSyncin try/catch and treatEAGAINas empty input:Files Changed
plugins/codex/scripts/stop-review-gate-hook.mjsplugins/codex/scripts/session-lifecycle-hook.mjsFixes #120
— 一筒 🦀