Skip to content

fix: skip init prompts when stdin is not a TTY - #16

Merged
manish-wekan merged 2 commits into
developfrom
fix/cli-skip-init-prompts-non-tty
Nov 5, 2026
Merged

manish-wekan merged 2 commits into
developfrom
fix/cli-skip-init-prompts-non-tty

Conversation

@manish-wekan

@manish-wekan manish-wekan commented Sep 7, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

nitrostack-py init blocked on readline() when stdin is inherited but never written (NitroStudio generate step 4 of 5, CI). Every prompt now answers with its default when stdin is not a TTY.

 _prompt(message, default)
+  if not _stdin_is_interactive():
+    echo default; return default
   readline()

 _prompt_yes_no(message, default_yes)
+  if not _stdin_is_interactive():
+    echo yes/no; return default_yes
   readline()

 init_project
   name      = arg or _prompt("Project name")        # now non-blocking
   overwrite = existing dir and not TTY -> exit 1    # no prompt
   template  = arg or _prompt_template()             # now non-blocking
   description, author = _prompt(...)                # non-blocking
   install   = skip_install or _prompt_yes_no(...)   # now non-blocking

Tests that script answers through io.StringIO now use a stdin that reports a TTY.

Evidence

  • Before (first commit only): init --skip-install with no name/template on an open, unused stdin → TimeoutError: CLI hung for 20.0s; test_prompts_return_defaults_without_tty fails; 9 existing test_cli.py init tests fail.
  • After: tests/test_cli_studio_noninteractive.py (3 subprocess cases, stdin PIPE never written) and test_prompts_return_defaults_without_tty pass; full suite 1342 passed locally.

Merge Danger

Door: two-way

Blast Radius: CLI

Off-TTY, init without --skip-install now installs dependencies (the prompt's default is Yes) instead of hanging. Studio already passes --skip-install. Interactive terminals are unchanged.

🤖 Generated with Claude Code

@manish-wekan
manish-wekan added this pull request to stack #32 September 10, 2026 12:33
Base automatically changed from develop to main September 10, 2026 12:35
@manish-wekan
manish-wekan force-pushed the fix/cli-skip-init-prompts-non-tty branch from 88d4de1 to b61b84f Compare September 10, 2026 12:35
@manish-wekan
manish-wekan force-pushed the fix/cli-skip-init-prompts-non-tty branch from b61b84f to 3193004 Compare November 3, 2026 11:50
@manish-wekan

Copy link
Copy Markdown
Collaborator Author

Review — not ready to merge yet.

1. Retarget to develop. This targets main, but develop doesn't have the fix either. It applies cleanly on top of develop @ 0d51ee4.

2. CI fails — existing init tests break. 7 failures on main, 9 when applied to develop:

tests/test_cli.py::test_init_with_name_and_explicit_template
tests/test_cli.py::test_init_install_dependencies_prompt_no
tests/test_cli.py::test_init_project_rejects_blank_name_and_overwrite_cancel
tests/test_cli.py::test_init_project_overwrite_and_install_yes_calls_npm
tests/test_cli.py::test_init_rewrites_pyproject_identity_and_copies_uv_files[*]  (5 templates)

These tests type answers through a fake StringIO stdin, which isn't a TTY, so the new guards skip the prompts and the scripted answers end up feeding the wrong prompt (or the overwrite path exits 1). They need sys.stdin.isatty patched to return True (e.g. a small TtyStringIO(io.StringIO) with isatty = lambda self: True, or monkeypatch.setattr(sys.stdin, "isatty", lambda: True) after swapping stdin).

3. Non-TTY coverage is incomplete. Only Description/Author and the overwrite prompt are guarded. With stdin not a TTY and the args omitted, these still block on readline():

  • init_project → _prompt("Project name", ...) when no name is passed
  • _prompt_template() when --template is omitted (also loops forever on EOF/invalid input)
  • _prompt_yes_no("Install dependencies", ...) when --skip-install isn't passed — the one flagged in the first review

Simplest fix: guard inside _prompt / _prompt_yes_no themselves (return the default when not sys.stdin.isatty()), so every current and future prompt is covered, and keep the explicit overwrite → exit 1 behaviour. Then extend tests/test_cli_studio_noninteractive.py to run init with no args and open stdin and assert it finishes.

~sent from claude-code

manish-wekan and others added 2 commits November 5, 2026 13:43
Studio and CI inherit an open stdin that never writes, so Description/Author readline hung generate. Use defaults off-TTY and refuse overwrite without a prompt.
The first fix only covered Description/Author and the overwrite prompt.
Project name, template choice and "Install dependencies" still blocked on
the inherited stdin Studio and CI pass. Move the TTY check into _prompt and
_prompt_yes_no so every prompt answers with its default off-TTY, and echo
the default so the log shows what was chosen. Overwrite still exits 1.

Tests that script answers through StringIO now use a stdin that reports a
TTY, and new tests cover init with no arguments on an open, unused stdin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@manish-wekan
manish-wekan force-pushed the fix/cli-skip-init-prompts-non-tty branch from 3193004 to 35fa72b Compare November 5, 2026 08:21
@manish-wekan
manish-wekan removed this pull request from stack #32 November 5, 2026 08:30
@manish-wekan
manish-wekan changed the base branch from main to develop November 5, 2026 08:30
@manish-wekan manish-wekan reopened this Nov 5, 2026
@manish-wekan
manish-wekan merged commit 12e65b1 into develop Nov 5, 2026
3 checks passed
@manish-wekan
manish-wekan deleted the fix/cli-skip-init-prompts-non-tty branch November 5, 2026 12:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant