mirror of
https://github.com/oven-sh/bun
synced 2026-02-10 02:48:50 +00:00
## Summary - Fixes ENXIO error when reopening `/dev/tty` after stdin reaches EOF - Fixes ESPIPE error when reading from reopened TTY streams - Adds ref/unref methods to tty.ReadStream for socket-like behavior - Enables TUI applications that read piped input then switch to interactive TTY mode ## The Problem TUI applications and interactive CLI tools have a pattern where they: 1. Read piped input as initial data: `echo "data" | tui-app` 2. After stdin ends, reopen `/dev/tty` for interactive session 3. Use the TTY for interactive input/output This didn't work in Bun due to missing functionality: - **ESPIPE error**: TTY ReadStreams incorrectly had `pos=0` causing `pread()` syscall usage which fails on character devices - **Missing methods**: tty.ReadStream lacked ref/unref methods that TUI apps expect for socket-like behavior - **Hardcoded isTTY**: tty.ReadStream always set `isTTY = true` even for non-TTY file descriptors ## The Solution 1. **Fix ReadStream position**: For fd-based streams (like TTY), don't default `start` to 0. This keeps `pos` undefined, ensuring `read()` syscall is used instead of `pread()`. 2. **Add ref/unref methods**: Implement ref/unref on tty.ReadStream prototype to match Node.js socket-like behavior, allowing TUI apps to control event loop behavior. 3. **Dynamic isTTY check**: Use `isatty(fd)` to properly detect if the file descriptor is actually a TTY. ## Test Results ```bash $ bun test test/regression/issue/tty-reopen-after-stdin-eof.test.ts ✓ can reopen /dev/tty after stdin EOF for interactive session ✓ TTY ReadStream should not set position for character devices $ bun test test/regression/issue/tty-readstream-ref-unref.test.ts ✓ tty.ReadStream should have ref/unref methods when opened on /dev/tty ✓ tty.ReadStream ref/unref should behave like Node.js $ bun test test/regression/issue/tui-app-tty-pattern.test.ts ✓ TUI app pattern: read piped stdin then reopen /dev/tty ✓ tty.ReadStream handles non-TTY file descriptors correctly ``` ## Compatibility Tested against Node.js v24.3.0 - our behavior now matches: - ✅ Can reopen `/dev/tty` after stdin EOF - ✅ TTY ReadStream has `pos: undefined` and `start: undefined` - ✅ tty.ReadStream has ref/unref methods for socket-like behavior - ✅ `isTTY` is properly determined using `isatty(fd)` --------- Co-authored-by: Claude Bot <claude-bot@bun.sh> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>