cli-parser: return empty on socket stdin to unblock Claude Code Bash tool#188
Open
SevenX77 wants to merge 1 commit intobfly123:mainfrom
Open
cli-parser: return empty on socket stdin to unblock Claude Code Bash tool#188SevenX77 wants to merge 1 commit intobfly123:mainfrom
SevenX77 wants to merge 1 commit intobfly123:mainfrom
Conversation
…Bash tool CCB CLI `ask` hangs 100% under Claude Code's Bash tool because `_read_optional_stdin` checks only `isatty()` before blocking-reading stdin. Claude Code gives child processes a Unix socket stdin (not TTY, not pipe) that never closes — so the read never returns. Add `stat.S_ISSOCK` early-exit on fd 0. Other stdin types (FIFO, regular file, TTY) keep their original behavior. On fstat OSError, fall through to `read_stdin_text()` per AC5 (no regression). Refs: TD-007
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
ccb ask(and other commands that call_read_optional_stdin) hangs indefinitely when invoked from Claude Code's Bash tool, because the tool passes a Unix-domain socket as child stdin:sys.stdin.isatty()returnsFalse(socket is not a TTY)_read_optional_stdinunconditionally falls intoread_stdin_text(), which blocks onread()until EOFThe workaround users have been living with is appending
< /dev/nullto everyccb askinvocation from Bash tool contexts. This is easy to forget and propagates through docs and agent scripts.Fix
Add a
stat.S_ISSOCKearly-exit check usingos.fstat(0)before enteringread_stdin_text(). Other stdin types (TTY, pipe/FIFO, regular file) keep their original behavior. OnfstatOSError, fall through toread_stdin_text()so the original code path is preserved (no regression when fd 0 is closed).Code change: +8 lines in
lib/cli/parser.py, one function touched.Why
S_ISSOCK?Only
fstat+S_ISSOCKcan distinguish a Unix socket from a FIFO/pipe;fcntl(F_GETFL)exposes only flags (O_NONBLOCKetc.), not the underlying file type. Pipe/FIFO stdin (e.g.cat file | ccb ask ...) must continue to be read, so a coarser check (e.g. "any non-TTY non-regular-file") would break valid usage.Tests
5 unit tests in
test/test_cli_parser.pycovering:read_stdin_textfstat(priority check)fstatraisingOSError→ falls back toread_stdin_text(no regression)All 5 pass locally. E2E verified from Claude Code Bash tool:
ccb ask --wait a2 "ping"(no< /dev/null) returns a normal reply in 15s instead of hanging.Risk
Minimal. The only scenario that behaves differently is stdin-is-Unix-socket — previously that hung forever, now it returns
''(treated as "no stdin content supplied"). No known legitimate use case whereccb askis fed meaningful data via a Unix socket stdin; the normal transports (pipe, file redirect, interactive TTY) are unaffected.Rollback
Single commit, revert with
git revertif needed.