-
Notifications
You must be signed in to change notification settings - Fork 73
Description
Description
When using the fzf interactive picker (gtr cd → ctrl-a) to launch Claude Code, it crashes with a Bun kqueue error:
Bun v1.3.11 (macOS arm64)
239 | throw @makeErrorWithCode(118, "options.flush", "boolean", flush);
240 | this.flush = flush;
241 | }
242 | if (this.start = start, this.pos = @undefined, this.bytesWritten = 0, start !== @undefined)
243 | validateInteger(start, "start", 0), this.pos = start;
244 | this[kWriteStreamFastPath] = fd ? Bun.file(fd).writer() : !0, this._write = underscoreWriteFast, this._writev = @undefined, this.write = writeFast;
^
error: EINVAL: invalid argument, kqueue
Environment
- macOS arm64 (Darwin 24.6.0)
- Claude Code 2.1.72 (bundles Bun v1.3.11)
- git-gtr 2.4.0
- fzf 0.70.0
Root Cause
fzf's execute() action runs the command with stdout/stderr connected through pipes rather than the terminal. Claude Code is built on Bun, which uses macOS kqueue to watch file descriptors. When Bun's WriteStream tries to register fzf's pipe FDs with kqueue, it fails with EINVAL.
Running gtr ai <branch> directly from the shell works fine — the issue only occurs when launched through fzf's execute() binding in the shell integration (init.sh).
Workaround
Wrapping the claude command with script -q /dev/null in adapters/ai/claude.sh fixes the issue by allocating a proper pseudo-terminal:
- (cd "$path" && "$claude_cmd" "$@")
+ # Use 'script' to allocate a proper PTY for Claude/Bun,
+ # preventing kqueue EINVAL errors when launched from fzf execute()
+ (cd "$path" && script -q /dev/null "$claude_cmd" "$@")script gives Claude/Bun real TTY file descriptors for stdin/stdout/stderr, bypassing the pipe FDs that kqueue can't handle.
Notes
- This likely affects any Bun-based AI tool launched via the fzf
ctrl-abinding - Other approaches tried that did not work:
- Increasing
ulimit -n - Closing inherited FDs (3-9 or all above stderr)
- Redirecting stdin/stdout/stderr to
/dev/tty(causesTypeError: undefined is not an object (evaluating 'process.stderr.fd')) - Using fzf's
become()instead ofexecute()
- Increasing
- The
scriptwrapper may also be useful as a general pattern for other terminal-based AI tools in the adapter system