feat(command): add CommandSpec::raw_output for verbatim stdout commands - #92
Merged
Conversation
Adds `.raw_output(true)` so a command's successful string result prints byte-for-byte to stdout, bypassing --output/--json/--human/--toon and the --fields/--filter/--expr pipeline entirely. Fixes the case where a command whose only correct output is raw text (e.g. a GraphQL SDL dump) got JSON-escaped when piped to a file. --output/--fields/--filter/--expr are hidden from such a command's --help (still parse harmlessly if passed), and raw_output is guarded against pairing with streaming or pagination. DEVEX-993 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces CommandSpec::raw_output(true) to support commands whose only correct output is verbatim text, bypassing the normal output envelope/pipeline and hiding now-irrelevant formatting flags from the command’s help.
Changes:
- Add
CommandSpec::raw_output(true)and plumbraw_outputthrough command registration into middleware rendering. - Update clap help/flag behavior so
--output/--fields/--filter/--exprare hidden (but still accepted) for raw-output commands. - Add end-to-end and guardrail tests covering raw output rendering, help visibility, and invalid raw_output+pagination/streaming combinations.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| cli-engine/tests/raw_output.rs | Adds end-to-end tests asserting raw-output rendering and help flag hiding behavior. |
| cli-engine/tests/foundation.rs | Updates middleware request helpers and adds panic-guard tests for unsupported raw_output combinations. |
| cli-engine/src/output/human.rs | Adds a unit test documenting plain-string human formatting behavior relevant to raw text output expectations. |
| cli-engine/src/middleware.rs | Implements the raw-output render bypass in the middleware render path. |
| cli-engine/src/command.rs | Adds the raw_output flag to CommandSpec plus debug-assert guards for streaming constructors. |
| cli-engine/src/cli.rs | Hides irrelevant output/pipeline flags for raw-output commands and asserts pagination incompatibility at clap-tree build time. |
| cli-engine/docs/concepts.md | Documents the raw-output concept and intended behavior. |
| AGENTS.md | Updates the command authoring checklist to include raw_output(true) guidance. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The raw_output bypass unconditionally appended "\n", so a handler string that already ended in a newline (e.g. text read from a file) rendered with a doubled trailing newline, contradicting the documented "exactly one trailing newline" guarantee. Strip at most one trailing newline before appending ours.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.
Suppressed comments (2)
cli-engine/src/middleware.rs:1018
- The raw-output renderer claims to guarantee exactly one trailing newline, but
strip_suffix('\n')only removes a single newline. If the handler returns text ending in multiple newlines (e.g. a blob with a trailing blank line), the output will still end with multiple newlines, violating that contract.
let body = text.strip_suffix('\n').unwrap_or(text);
cli-engine/src/output/human.rs:1167
- This test comment says
raw_outputrelies onformat_plain_value, but theraw_outputpath renders directly fromValue::Stringin middleware (it doesn't go through the human formatter). Updating the comment will avoid future confusion about the dependency.
// No quoting/escaping — the exact convention `raw_output` bypass
// relies on to render a `CommandResult` string byte-for-byte.
qcai-godaddy
approved these changes
Aug 10, 2026
Merged
jpage-godaddy
pushed a commit
that referenced
this pull request
Aug 10, 2026
🤖 I have created a release *beep* *boop* --- <details><summary>cli-engine: 0.8.4</summary> ## [0.8.4](cli-engine-v0.8.3...cli-engine-v0.8.4) (2026-08-10) ### Features * **command:** add CommandSpec::raw_output for verbatim stdout commands ([#92](#92)) ([84b0f00](84b0f00)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
CommandSpec::raw_output(true)so a command's successful string result prints byte-for-byte to stdout, bypassing--output/--json/--human/--toonand the--fields/--filter/--exprpipeline entirely.--output/--fields/--filter/--exprare hidden from araw_outputcommand's own--help(still parse harmlessly if passed anyway — same convention as--dry-runon non-mutating commands).raw_outputwith streaming commands or.with_pagination(...)(bothdebug_assert!).Fixes the case where a command whose only correct output is verbatim text (e.g. a GraphQL SDL dump) gets JSON-escaped instead of raw text when piped to a file — see DEVEX-993.
Test plan
cargo fmt --all --checkcargo clippy --all-targets -- -D warningsRUSTDOCFLAGS='-D warnings' cargo doc --no-depscargo rustdoc --lib -- -W missing-docs(zero)cargo test --all-targets(new coverage intests/raw_output.rs, plus new panic-guard tests intests/foundation.rsand ahuman.rsunit test)cargo test --doc🤖 Generated with Claude Code