Skip to content

Plain CLI output drops control characters from server text - #24

Open
krishhgg wants to merge 6 commits into
t3term/first-ten-ci-greptile-maintenancefrom
t3term/cli-plain-controls
Open

krishhgg wants to merge 6 commits into
t3term/first-ten-ci-greptile-maintenancefrom
t3term/cli-plain-controls

Conversation

@krishhgg

@krishhgg krishhgg commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Plain CLI output cleans control characters from server text, displayed IDs and error messages. Streamed replies clean only new text and preserve line breaks across updates. JSON values and the IDs sent back to T3 keep their original text.

Sol passed cargo fmt --all -- --check, cargo clippy --locked --all-targets -- -D warnings and all 305 tests at d1d7e87: 277 library, 2 main, 18 CLI and 8 fake-RPC tests. Sol also ran all six new CLI regressions at the tests-only checkpoint 76cc9a0; they compiled against the old code and all six failed their assertions. Final CI passed on this commit. Greptile gave it 5/5 and found no actionable issues.

This PR is stacked above #23 and targets its branch. Merge #23 first.

Decision log

What I noticed

Fable's first-ten audit found raw terminal controls in plain read, projects, threads and streamed replies. Other human output also printed server names, request IDs and errors directly.

How I confirmed it

The six integration regressions exercise the actual binary with isolated homes and fake HTTP, WebSocket and auth endpoints. They cover prose, tool headers, lists, requests, model settings, watch failures and doctor diagnostics. They verify JSON values, exact title matching and command IDs remain unchanged. Streaming cases include repeated updates, removed multibyte controls, split CRLF and separate reply items. Unit tests compare every character-boundary split of sample replies with cleaning the whole text.

Options

Clean values at display boundaries using the existing control policy. Borrow ordinary text; clean only the newly appended reply suffix using original byte offsets. A preceding carriage return handles CRLF split across updates. Cleaning the projection would change matching and wire values; cleaning whole replies on every update would repeat work. Doctor details use the existing safe JSON serializer.

What review changed

Sol reviewed all output sinks and confirmed the new tests fail before the fix and pass afterward. Sol and macOS CI found three formatting differences. Claude corrected them; formatting, Clippy and all tests now pass on the final commit. Greptile reviewed the final commit, gave it 5/5 and found no actionable issues.

Known limits

Clap's argument-parsing errors still quote raw command-line arguments. Line breaks in one-line fields remain line breaks. Column padding counts characters rather than display width. Logout and reconnect diagnostics were inspected but lack direct integration coverage. The existing repeated description of skipped reasoning/user items is unchanged. This changes no TUI layout, and maintenance PRs do not count toward the next audit.

RetriggerConfidence Score: 5/5

The PR appears safe to merge; no actionable issue was found.

Summary

Plain CLI output now removes control characters from server text, displayed IDs, and errors.

  • Read and streamed replies show server text without terminal controls.
  • Project and thread lists show IDs and names without terminal controls.
  • Model, request, and settings views show values without terminal controls.
  • Watch, diagnostic, and error messages display server text safely.

Acknowledged limits from krishhgg: Clap errors still quote raw arguments; one-line fields retain line breaks; padding counts characters rather than screen width; logout and reconnect lack direct integration coverage; repeated descriptions of skipped reasoning/user items remain unchanged.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  T3[T3 text] --> Raw[Original values]
  Raw --> Match[Matching and commands]
  Raw --> JSON[JSON with escaped controls]
  Raw --> Clean[Remove controls for plain output]
  Clean --> Terminal[Terminal]
  Raw --> Suffix[New reply suffix]
  Suffix --> Clean
Loading

Reviews (1) · Last reviewed commit: "style: apply rustfmt layout to plain_tex..." · Reviewed by Greptile

krishhgg and others added 6 commits October 9, 2026 23:05
Six CLI tests that run against b3d3796 without new helpers and fail
there: read, projects and threads, the wait and send --wait stream,
watch, requests, approve, interrupt, models and settings, and doctor
and error reports. Each also checks that --json keeps the values as
T3 sent them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
without_controls now reads a \r as a line break at once and skips a \n
just after it, which prints the same text and lets plain_from clean a
reply from any byte offset with only the character before it. plain
borrows text with no control but \n. plain_text cleans each header and
body before it prints them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each plain sink cleans its value where it prints it: project, thread,
request, model and settings fields, read's title and id, watch's event
types and reconnect reasons, approve and interrupt ids, error reports
and logout. Columns are padded and the model column measured after the
cleaning. The wait stream prints plain_from(body, done), so done still
counts the reply's bytes as T3 sent them. Doctor prints each detail as
--json writes it. Matching, sorting and --json still read the values
as T3 sent them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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