Skip to content

fix: don't hang on prompts when no terminal is attached - #471

Open
Lyokone wants to merge 1 commit into
mainfrom
fix/non-interactive-no-tty
Open

Lyokone wants to merge 1 commit into
mainfrom
fix/non-interactive-no-tty

Conversation

@Lyokone

@Lyokone Lyokone commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Description

The CLI only skipped its prompts on CI. Run by a script or an AI coding agent without a terminal (and without CI set), the first prompt waited forever: flutterfire configure and flutterfire install latest with stdin from /dev/null both hung until killed.

The CLI is now non-interactive on CI or when stdin is not a terminal (isNonInteractive in common/utils.dart). stdin.hasTerminal alone is not enough: it is also true for other character devices such as /dev/null, which many tools use as stdin, so stdin's echo mode is read as well (it throws unless stdin is a real terminal).

When non-interactive, each prompt either uses the value given by the flags or exits 1 with an error naming the flag to pass, for example:

NonInteractiveException: Cannot ask which Firebase plugins to install without a terminal attached to stdin. Please re-run the command with the `--plugins` flag, e.g. `--plugins=firebase_core,firebase_auth`, or with the `--only-pubspec-plugins` flag to install the plugins already in your `pubspec.yaml`.
  • Every isCI check guarding a prompt now uses isNonInteractive, and the messages name the flag (--platforms, --out, --android-out, --ios-build-config/--ios-target, --overwrite-firebase-options, ...).
  • New checks where there were none: install's plugin choice, platform choice, the "reuse firebase.json?" question, an invalid --out, the Apple service file path, and overwriting an existing firebase_options.dart.
  • The prompt helpers throw a new NonInteractiveException instead of calling interact as a safety net for any other call site.
  • If fetching projects fails, the error is rethrown instead of asking whether to create a project.
  • --version skips the update check without a terminal, as it already did on CI.
  • README: new "Running without a terminal" section.

Behavior in a terminal is unchanged (checked with a pty). On CI it is unchanged too, except that prompts that used to hang there now fail with an error. Piping answers in (yes | flutterfire ...) never worked with interact and now fails fast instead of hanging.

Testing

  • New offline test/non_interactive_test.dart (21 tests): fake stdin through IOOverrides (pipe, /dev/null, terminal), plus the real CLI as a subprocess with stdin piped and from /dev/null. With the fix reverted, 15 of them fail.
  • dart analyze --fatal-infos clean, all offline tests pass (89).
  • Not run locally: the e2e tests that need FIREBASE_TOKEN, and Windows.

Type of Change

  • ✨ feat -- New feature (non-breaking change which adds functionality)
  • 🛠️ fix -- Bug fix (non-breaking change which fixes an issue)
  • ❌ ! -- Breaking change (fix or feature that would cause existing functionality to change)
  • 🧹 refactor -- Code refactor
  • ✅ ci -- Build configuration change
  • 📝 docs -- Documentation
  • 🗑️ chore -- Chore

@Lyokone
Lyokone deployed to CI Environment October 20, 2026 15:17 — with GitHub Actions Active
@Lyokone
Lyokone deployed to CI Environment October 20, 2026 15:17 — with GitHub Actions Active
The CLI only skipped its prompts on CI. When a script or an AI coding
agent ran it without a terminal and without `CI` set, the first prompt
waited forever for an answer that could never come.

The CLI is now non-interactive on CI or when stdin is not a terminal.
`stdin.hasTerminal` alone is not enough: it is also true for other
character devices such as `/dev/null`, the stdin many tools run
commands with, so stdin's echo mode is read as well.

When non-interactive, each prompt either uses the value given by the
flags, or exits with an error naming the flag to pass (`--platforms`,
`--plugins`, `--out`, `--overwrite-firebase-options`, ...). The prompt
helpers throw a `NonInteractiveException` as a safety net for any call
site that does not. Behavior in a terminal and on CI is unchanged,
apart from prompts that used to hang on CI now failing with an error.
@Lyokone
Lyokone force-pushed the fix/non-interactive-no-tty branch from 72cc57e to 69cfc6e Compare October 21, 2026 07:16
@Lyokone
Lyokone deployed to CI Environment October 21, 2026 07:16 — with GitHub Actions Active
@Lyokone
Lyokone deployed to CI Environment October 21, 2026 07:16 — with GitHub Actions Active
@Lyokone
Lyokone deployed to CI Environment October 21, 2026 07:16 — with GitHub Actions Active

This branch was successfully deployed

1 active deployment
CI Environment — 69cfc6e9 Deployed Oct 21, 2026 by Lyokone via test_macos #120
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.

2 participants