fix(agent-setup): stop agent wrappers from resolving to themselves
What & why
The agent wrappers in ~/.paradev/bin can resolve to themselves and recurse forever. find_real_binary skips the wrapper's own bin dir only through the case patterns, and every pattern except getBinDir() is built from $HOME. So the wrapper finds itself again when:
- a process runs with a different
HOME(test runners and sandboxes routinely set one), or - the bin dir is on
PATHunder another spelling. After the Superset to Paradev rename,~/.supersetis a symlink to~/.paradev, andPATHstill lists~/.superset/bin.
In either case REAL_BIN is the wrapper. It runs itself with --enable hooks added, the copy does the same, and so on until the process table is full.
On my machine a single codex --version from a test suite with a temporary HOME grew to about 3,500 processes in under an hour. With a fake HOME, 175 copies spawned within 3 seconds.
The fix adds two checks in find_real_binary, after a candidate passes the executable test:
[ "$dir/$name" -ef "${BASH_SOURCE[0]}" ]: skip the running wrapper itself, however its path is spelled (same device and inode).- Skip any file whose first lines carry
WRAPPER_MARKER, so another profile's wrapper (~/.paradev-*/bin) is never treated as the real binary either.
The existing case patterns stay as they are.
How I tested it
- New test:
never resolves to itself when its bin dir is on PATH under another spelling. It reaches the wrapper through a symlinked bin dir withHOMEpointing elsewhere. Without the fix it times out at 5 s; with the fix it prints the real binary's output. The test starts the wrapper in its own process group and kills the group on timeout, so a failure can't leak the recursion into the test machine. I checked the process count before and after a failing run. bun test src/agent-wrappers.test.tsinpackages/agent-setup: 96 pass, 0 fail.bun run typecheckinpackages/agent-setuppasses, andbiome checkon both changed files is clean.- I applied the same change by hand to all 16 installed wrappers on macOS and ran each with
--version, with my realHOMEand with a fake one. None recursed. Tools that are installed printed their version, and the missing ones gave the usual "not found" exit 127.
Not run: the full monorepo bun run lint / bun run test, and Linux.
Checklist
- PR title follows conventional commits (
type(scope): subject) -
bun run typecheckpasses forpackages/agent-setup;biome checkis clean on the changed files (fullbun run lintnot run) - "Allow edits from maintainers" is checked on fork PRs
- I have signed the CLA (the bot asks on your first PR)
🤖 Generated with Claude Code
Summary by cubic
Fixes agent wrappers resolving to themselves and recursing until the process table fills when the wrapper runs with a different HOME or the bin dir is on PATH under another spelling (the ~/.superset symlink to ~/.paradev).
find_real_binarynow skips candidates that are the same file as the running wrapper and candidates carrying the managed-wrapper marker.- Adds a regression test that reaches the wrapper through a symlinked bin dir with
HOMEset elsewhere; it times out on the old behavior and kills the process group.
Summary by CodeRabbit
- Bug Fixes
- Fixed a case where Copilot could fail to launch its real executable when the wrapper was reached through a symlink and the home directory differed. Copilot now correctly starts the real executable in this setup and displays its output, improving reliability for users whose
PATHincludes a symlink to the wrapper.
- Fixed a case where Copilot could fail to launch its real executable when the wrapper was reached through a symlink and the home directory differed. Copilot now correctly starts the real executable in this setup and displays its output, improving reliability for users whose