diff --git a/bot_bottle/cli/start.py b/bot_bottle/cli/start.py index afe78a8..27bcf3a 100644 --- a/bot_bottle/cli/start.py +++ b/bot_bottle/cli/start.py @@ -14,6 +14,7 @@ the private orchestrator `_launch_bottle`. from __future__ import annotations import argparse +import io import os import shutil import sys @@ -195,7 +196,11 @@ def _start_headless( path, so the agent still execs on the inherited stdio/PTY — an orchestrator allocates that PTY and relays it to its desktop/mobile clients.""" - if not os.isatty(sys.stdin.fileno()): + try: + stdin_fd = sys.stdin.fileno() + except io.UnsupportedOperation: + stdin_fd = -1 + if not os.isatty(stdin_fd): die( "--headless requires a PTY on stdin; run via:\n" " script -q /dev/null ./cli.py start ..." diff --git a/tests/unit/test_cli_start_headless.py b/tests/unit/test_cli_start_headless.py index 48bc274..092b26c 100644 --- a/tests/unit/test_cli_start_headless.py +++ b/tests/unit/test_cli_start_headless.py @@ -69,6 +69,9 @@ class TestCmdStartHeadless(unittest.TestCase): self._modal = patch.object(tui_mod, "name_color_modal").start() patch.dict(os.environ, {}, clear=False).start() os.environ.pop("BOT_BOTTLE_BACKEND", None) + # PTY check uses os.isatty(sys.stdin.fileno()); stub both so + # headless unit tests aren't blocked on a real TTY. + patch("bot_bottle.cli.start.os.isatty", return_value=True).start() self.addCleanup(patch.stopall) def _spec(self):