Codex, Antigravity, and Devin launch their agent-hook `command` as a program
(argv[0]), not through cmd.exe. PR #8430 changed wrapWindowsCmdHookCommand to
emit an `if exist "path\." (drain) else if exist "path" (call "path") else
(drain)` compound whose argv[0] is the cmd builtin `if` — unspawnable — so every
Codex/Antigravity/Devin hook (SessionStart, UserPromptSubmit, Stop, ...) failed
with "hook exited with code 1" on Windows starting in v1.4.138.
Revert the cmd-safe fast path to the bare, directly-spawnable .cmd path (the
proven pre-#8430 form). A cmd-builtin drain and direct-spawnability are mutually
exclusive, and nesting cmd.exe /d /c breaks large-payload draining; the
missing-script stdin drain stays on the encoded-PowerShell fallback (used for
spaced/non-ASCII paths). Upgrades self-heal on first launch: startup install()
unconditionally rewrites the command and Codex trust entry, sweeping the old
compound form.
Add a platform-independent regression guard (launcher must resolve to a real
file, never a cmd-builtin fragment), update the lifecycle test + docs, and fix a
stale Devin comment.
* Fix hook scripts to drain stdin before any early-exit path
Generated agent hook scripts and missing-script launchers could exit
successfully before consuming the payload written to their stdin,
leaving the writer with a broken pipe (EPIPE/ERROR_BROKEN_PIPE) once
the reader closed early. Capture stdin (or drain it via a shared
epilogue/fast-path guard) before any whole-script success exit across
all POSIX, batch, PowerShell, and Git Bash launcher variants, and add
a cross-agent lifecycle test suite plus a live Electron verification
script to guard the contract going forward.
* Harden hook scripts against unreadable managed scripts and add a Claude/
- Extend the POSIX launcher guard to also require `[ -r ]`, not just `-f`/`-x`,
so an executable-but-unreadable managed script still drains stdin instead of
erroring or silently misbehaving.
- Add a verifier case (`verifyClaudeDevinSkip`) that spins up a local HTTP
server and confirms the Claude hook never forwards a request that Devin
already imported, catching accidental double-forwarding.
- Update installer-utils tests and stdin-lifecycle docs to match the new
readable-file guard and the added verification case.
* Fix hook-launcher verification to derive script paths from the installed
Extract the quoted path from the launcher's `if [ -f '...'` clause instead of
reconstructing it via join(home, ...), so missing/failing-script test cases
can't silently fall through to the real script if the install layout changes.
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>