Files
patrick 83b5505fc8 fix(toml-filter): skip filtering when stdout is piped (#1060)
`rtk ps aux | wc -l` returned 31 lines instead of the host's ~374
processes because the TOML filter for `ps` (`max_lines = 30`,
`truncate_lines_at = 120`) fired unconditionally, even when stdout was
piped or redirected to another program. Downstream consumers like
`grep`, `wc`, `jq` or shell scripts then saw a truncated view and
silently lost data.

This was the same shape on every truncating TOML filter (top, lsof,
df, netstat, ...), but the dispatcher in `main.rs` never checked
`stdout().is_terminal()` before applying the filter — unlike the
hand-rolled Rust filters in `curl_cmd` and `ls` which already gate on
TTY (PR #1602, PR #503).

Fix:
- Extract the dispatch decision into a pure `should_apply_toml_filter`
  helper that takes (env_disabled, stdout_is_tty) and bypasses the
  filter when stdout is not a terminal.
- Wire `std::io::stdout().is_terminal()` into the dispatcher.

Tests:
- Unit matrix `test_toml_filter_*` covers the four
  (env_disabled, stdout_is_tty) combinations and pins the new
  pipe-bypass behaviour.
- `test_multiple_toml_filters_are_registered` documents that the
  bypass protects more than just `ps` (top, lsof, df, netstat, ...).
- New integration test `rtk_ps_aux_piped_preserves_raw_line_count`
  spawns the rtk binary with `Stdio::piped()` (the exact shape of
  `rtk ps aux | ...`) and asserts the line count is close to raw
  `ps aux`. Skips gracefully on hosts with fewer than 35 processes
  (small containers) and when `ps` is unavailable.

End-to-end verification on the release build:
  $ /usr/bin/ps aux | wc -l                              # 374
  $ target/release/rtk ps aux | wc -l                    # 375  ✓
  $ RTK_NO_TOML=1 target/release/rtk ps aux | wc -l      # 375  ✓
Before this commit `rtk ps aux | wc -l` returned 31.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 21:07:58 +02:00
..