Skip to content

fix(cli): route interactive prompts and prelude to stderr (keep stdout pure)#31

Open
Davidson3556 wants to merge 1 commit into
TestSprite:mainfrom
Davidson3556:fix/interactive-output-to-stderr
Open

fix(cli): route interactive prompts and prelude to stderr (keep stdout pure)#31
Davidson3556 wants to merge 1 commit into
TestSprite:mainfrom
Davidson3556:fix/interactive-output-to-stderr

Conversation

@Davidson3556

@Davidson3556 Davidson3556 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Fixes #30

Describe the changes you have made in this PR -

Interactive prompts wrote to stdout, polluting the result stream:

  • prompt.ts (promptText / promptSecret) defaulted the question + masking to stdout — used by the API-key prompt in setup/auth configure and the target prompt in agent install.
  • the Configuring profile … prelude in auth.ts defaulted to stdout.

On any interactive path this mixes UI text into stdout, and under --output json it breaks the contract that stdout is a single JSON document (a consumer doing JSON.parse(stdout) fails on the prompt text). The repo already enforces stdout purity elsewhere (the stdoutPurity helper, §8.1) — the interactive prompt path was the gap.

Change: default both to stderr. Prompts and informational preludes are interactive UI, not result data; stderr is still the user's TTY so they stay visible, and the secret is still never echoed. Callers that inject explicit streams are unaffected.

Demo/Screenshot for feature changes and bug fixes -

The cleanest reproduction uses agent install with no --target (it prompts, and is fully local — no key/network). Redirect stdout to a file; the prompt should appear on your terminal (stderr) and the file should hold only the result.

image

Code Understanding and AI Usage

Did you use AI assistance (ChatGPT, Claude, Copilot, etc.) to write any part of this code?

  • No, I wrote all the code myself
  • Yes, I used AI assistance (continue below)

If you used AI assistance:

  • I have reviewed every single line of the AI-generated code
  • I can explain the purpose and logic of each function/component I added
  • I have tested edge cases and understand how the code handles them
  • I have modified the AI output to follow this project's coding standards and conventions

Explain your implementation approach:

Problem: the repo treats stdout as a pure result stream (so --output json yields one parseable document and text-mode stdout is script-clean), but interactive prompts and the configure prelude wrote to stdout, violating that on the interactive path.

Approach: prompts are UI, not data, so the fix is to default their output stream to stderr. prompt.ts already accepts an injectable output stream; I only changed the default (process.stdoutprocess.stderr) in promptText/promptSecret, and changed the auth.ts prelude's default writer the same way. stderr is the controlling terminal in an interactive session, so the prompt stays visible; nothing about masking or the "never echo the secret" behavior changes.

Alternatives considered: (1) gate the stream on --output json only — rejected, because text-mode stdout should be clean too (e.g. KEY=$(testsprite … )), and a mode-dependent stream is more surprising than "prompts always go to stderr," which is the conventional behavior for CLIs. (2) Strip the prompt from stdout after the fact — not possible/clean.

Edge cases handled/tested: a promptText regression test confirms the question goes to stderr (not stdout) when no stream is injected; an auth regression test confirms the Configuring profile … prelude lands on stderr while the result stays on stdout. Existing prompt tests (which inject an explicit output stream) are unaffected, and the secret-not-echoed test still passes.

Note on the tests: I swap the global process.stderr/process.stdout writers manually (save/restore) rather than vi.spyOn, because vi.spyOn(process.stderr, 'write') did not intercept the writes in this setup — the manual override is reliable since the code reads process.stderr at call time.


Checklist before requesting a review

  • I have added proper PR title and linked to the issue
  • I have performed a self-review of my code
  • I can explain the purpose of every function, class, and logic block I added
  • I understand why my changes work and have tested them thoroughly
  • I have considered potential edge cases and how my code handles them
  • If it is a core feature, I have added thorough tests
  • My code follows the project's style guidelines and conventions

Note: Please check Allow edits from maintainers if you would like us to assist in the PR.

…t pure)

Interactive prompts (`prompt.ts` — the API-key prompt during `setup`/`auth
configure`, the target prompt during `agent install`) wrote the question and
masking to STDOUT, and the "Configuring profile …" prelude defaulted to
stdout too. On the interactive path that mixes UI text into stdout — and
under `--output json` it breaks the contract that stdout is a single JSON
document, so a consumer doing `JSON.parse(stdout)` fails.

Default both to stderr: prompts and informational preludes are interactive
UI, not result data. stdout now carries only the command's result (the §8.1
stdout-purity principle the repo already enforces elsewhere). stderr is still
the user's TTY, so prompts remain visible; the secret is still never echoed.
Callers that inject explicit streams are unaffected.

Adds regression tests: promptText writes the question to stderr by default,
and the configure prelude lands on stderr (not the result stdout).
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.

Interactive prompts and the configure prelude write to stdout, breaking --output json purity

1 participant