You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(cli): add -q/--quiet to print only the result or the error - #2576
Adds -q / --quiet to the CLI. With it, a run prints only the result payload on stdout, or on failure only the single-line error envelope on stderr.
What the CLI actually emitted, and what --quiet does with each
Output
Where
Under --quiet
A stdio server's own stderr (banners, logs): inherited by the child, so it landed in the CLI's stderr
cli.ts (InspectorClient)
Dropped.pipeStderr: true. InspectorClient drains the pipe into its stderrLog event, which nothing subscribes to, so the child never blocks on a full pipe. No core/ change.
Schema portability: … Re-run with --strict for details.
schema-lint-report.ts
Dropped
--verify one-line summary
consume-outcome.ts
Dropped. A failing run's envelope carries the same text as its message.
Warning: could not revoke the OAuth grant … (--relogin)
cli.ts
Dropped. The relogin and the revocation attempt still happen.
--strict report
schema-lint-report.ts
Kept. The caller asked for it explicitly, and it is the detail behind exit 6, which the envelope only counts.
OAuth authorization URL, the step-up [y/N], and "open it by hand"
cli-oauth-navigation.ts, cliOAuth.ts
Kept. Interactive login can't finish without them. For runs that must never prompt, use --quiet --stored-auth-only.
Error envelope
error-handler.ts
Kept
Decisions I made without asking:
--quiet is independent of --format: --format shapes stdout, and --quiet empties stderr.
Dropping the server's stderr also drops its own explanation when it fails to start. The README says so and suggests re-running without --quiet.
The flag is documented in clients/cli/README.md (options table, plus a new "Quiet output (--quiet)" section).
Tests
cli.test.ts: -q and --quiet against the stdio test server: valid JSON on stdout, empty stderr.
e2e.test.ts (built binary, out of process): a --import preload makes the real test server write a line to stderr before it starts. The line passes through without -q and is absent with -q. This half can't be asserted in-process, because the child's inherited fd 2 bypasses the patched process.stderr.write.
cliOAuth.test.ts: no status lines in quiet mode on both retry branches and on connect, and the step-up prompt still prints.
schema-lint-report.test.ts, skills-verify-cli.test.ts, relogin-revocation.test.ts: the hint, summary and warning are suppressed, and the --strict report and the exit code / envelope message are kept.
Gate
Run with the sandbox proxy env unset (env -u HTTP_PROXY -u HTTPS_PROXY …). With an ambient proxy set, relogin-revocation.test.ts fails both on v2/main and on this branch.
local:validate and verify:skills:cli: pass.
coverage:web: 1 environmental failure, unrelated to this change. secret-store-selection.test.ts > isOnMountPoint > is false when the path itself can't be resolved fails in this sandbox on its own, because the worktree sits on a mounted volume, so a relative path that can't be resolved still lands on a mount. This PR touches only clients/cli.
coverage:cli (459 tests, every file ≥ 90 on all four dimensions), coverage:tui, coverage:launcher, verify:build-gate, verify:bundle-externals: pass.
smoke, smoke:web:firefox, local:storybook: still queued behind the machine-wide gate lease (about 20 gates deep). I'll post their result as a comment.
`--quiet` drops the CLI's non-essential output so a scripted caller gets the
result payload on stdout and, on failure, only the error envelope on stderr:
- a stdio server's own stderr (piped and drained instead of inherited)
- the non-strict schema-portability hint on tools/list
- the --verify one-line summary (a failing run's envelope carries it)
- "Authorization complete." / "Authorization complete. Retrying…"
- the --relogin revocation-failure warning
Kept on purpose: the --strict report (explicitly requested; the detail
behind exit 6), and everything a human must act on for interactive OAuth
(authorization URL, step-up [y/N], "open it by hand").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
A usage error made Commander write its own error line during parse(),
before the envelope, so --quiet stderr was two lines. The error is still
thrown and reaches the envelope with the same message.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Quiet mode leaks secret-store warnings on HTTP/SSE runs
clients/cli/src/cli.ts:188
--quiet still leaks core secret-store warnings on HTTP/SSE runs. During InspectorClient.connect(), isOAuthAuthorized() reads NodeOAuthStorage; when the keychain is unavailable (or MCP_INSPECTOR_SECRET_STORE=memory is configured), resolveSecretStore() calls warnAboutSecretStorage() via console.warn, bypassing every new quiet check. A successful quiet invocation therefore has non-empty stderr. Route these diagnostics through a quiet-aware sink while preserving the intentional OAuth prompts/strict report, and cover an HTTP quiet run with the memory store selected.
This says --quiet empties stderr, but the table immediately below documents intentional stderr output for --strict and interactive OAuth. Describe it as suppressing non-essential stderr instead so the user-facing contract is not contradictory.
…2435)
resolveSecretStore() announces a keychain fallback or a store caveat
(e.g. memory) with console.warn on first use, so an HTTP/SSE --quiet run
on a box without a keychain still printed it. Core caches the resolution,
so the CLI now settles it once at parse time with console.warn muted; no
core change, and the selected store is unaffected.
Also reword the README so it no longer says --quiet empties stderr, since
the table below lists what it deliberately keeps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Quiet mode leaks Commander parse diagnostics to stderr: fixed in 1851809 (answered in its thread).
Round 2 had no inline comments. Its two findings were in the body's "Previously missed" block, so they are answered here:
Quiet mode leaks secret-store warnings on HTTP/SSE runs: fixed in 37452a9. Core's resolveSecretStore() prints the keychain-fallback / memory caveat with console.warn on first use, and it caches the resolution. Under --quiet, parseArgs now settles it once with console.warn muted (clients/cli/src/quiet-secret-store.ts). No core/ change, and the selected store is unchanged. The test is out of process in e2e.test.ts (--relogin against a refused port, with the inherited MCP_INSPECTOR_SECRET_STORE=memory): the notice is present without -q, and with -q stderr is the envelope alone. The in-process runner can't observe this, because Vitest replaces console. I confirmed the -q case fails with the fix disabled.
Clarify quiet mode suppresses non-essential stderr: fixed in 37452a9. The README now says --quiet strips stderr of everything non-essential and points at the table of exceptions. The table also gained a row for the secret-store notice.
Core reports advisories with console.warn from many places the CLI
reaches (cleanRoots, OAuth endpoint overrides, oauth-persist, file-lock,
secret-store selection), so muting only the secret-store resolution left
the rest leaking. parseArgs now swaps console.warn for a no-op when -q is
in argv, and runCli restores it in finally so a module caller (the
launcher, the test runner) never inherits the mute. Replaces the narrower
quiet-secret-store helper. Everything --quiet keeps is written to the
streams directly, never through console.warn.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Commander accepts -qe KEY=V, which enabled quiet without the pre-parse
handling (Commander's writeErr and the console.warn mute). Read clusters
the way Commander does: q is the flag, and e takes a value, so anything
after it in the token is that value.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
…can (#2435)
A -q that is another option's value (--client-secret -q) was taken for the
flag. Commander's error output is now buffered and written from
exitOverride unless opts().quiet is already set, and the console.warn mute
moves to just after parse(). Combined -qe still counts because Commander
parses it natively; argvRequestsQuiet is gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Gate follow-up. The stages that were still queued on the lease have now passed: smoke (launcher, cli, tui, web, web:browser/app/elicit/tabs on chromium), smoke:web:firefox and local:storybook (123 files / 528 tests). Every local:gate stage has now passed except the one environmental coverage:web test noted in the description (isOnMountPoint, which fails in this sandbox because the worktree sits on a mounted volume, and is unrelated to clients/cli). After each later review fix, the clients/cli check plus test:coverage were re-run green.
Copilot review loop closed: round 6 was clean (no inline comments, no suppressed or previously-missed findings, and the headline is "Approval recommended"), which is the stop exit.
Rounds 3 to 5 (each answered in its own thread):
r3, apply quiet warning suppression across the full invocation: fixed in f003441. console.warn is muted for the whole run and restored in runCli's finally. This replaced the narrower secret-store helper.
r4, detect -q in combined short options: fixed in 7f616de. That fix was then superseded by r5.
r5, don't treat a dash-prefixed option value as the flag: fixed in 0a1c0d4. Quiet is now decided from Commander's parsed state (buffered writeErr and an exitOverride check), not an argv scan.
Nothing was declined, and no follow-up issues were filed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2435
Adds
-q/--quietto the CLI. With it, a run prints only the result payload on stdout, or on failure only the single-line error envelope on stderr.What the CLI actually emitted, and what
--quietdoes with each--quietcli.ts(InspectorClient)pipeStderr: true. InspectorClient drains the pipe into itsstderrLogevent, which nothing subscribes to, so the child never blocks on a full pipe. Nocore/change.Schema portability: … Re-run with --strict for details.schema-lint-report.ts--verifyone-line summaryconsume-outcome.tsAuthorization complete./Authorization complete. Retrying…cliOAuth.tsWarning: could not revoke the OAuth grant …(--relogin)cli.ts--strictreportschema-lint-report.ts[y/N], and "open it by hand"cli-oauth-navigation.ts,cliOAuth.ts--quiet --stored-auth-only.error-handler.tsDecisions I made without asking:
--quietis independent of--format:--formatshapes stdout, and--quietempties stderr.--quiet.The flag is documented in
clients/cli/README.md(options table, plus a new "Quiet output (--quiet)" section).Tests
cli.test.ts:-qand--quietagainst the stdio test server: valid JSON on stdout, empty stderr.e2e.test.ts(built binary, out of process): a--importpreload makes the real test server write a line to stderr before it starts. The line passes through without-qand is absent with-q. This half can't be asserted in-process, because the child's inherited fd 2 bypasses the patchedprocess.stderr.write.cliOAuth.test.ts: no status lines in quiet mode on both retry branches and on connect, and the step-up prompt still prints.schema-lint-report.test.ts,skills-verify-cli.test.ts,relogin-revocation.test.ts: the hint, summary and warning are suppressed, and the--strictreport and the exit code / envelope message are kept.Gate
Run with the sandbox proxy env unset (
env -u HTTP_PROXY -u HTTPS_PROXY …). With an ambient proxy set,relogin-revocation.test.tsfails both onv2/mainand on this branch.local:validateandverify:skills:cli: pass.coverage:web: 1 environmental failure, unrelated to this change.secret-store-selection.test.ts > isOnMountPoint > is false when the path itself can't be resolvedfails in this sandbox on its own, because the worktree sits on a mounted volume, so a relative path that can't be resolved still lands on a mount. This PR touches onlyclients/cli.coverage:cli(459 tests, every file ≥ 90 on all four dimensions),coverage:tui,coverage:launcher,verify:build-gate,verify:bundle-externals: pass.smoke,smoke:web:firefox,local:storybook: still queued behind the machine-wide gate lease (about 20 gates deep). I'll post their result as a comment.🤖 Generated with Claude Code