Skip to content

fix(git): preserve full status paths and untracked files#991

Merged
aeppling merged 1 commit into
rtk-ai:developfrom
em0t:fix/git-completeness
May 14, 2026
Merged

fix(git): preserve full status paths and untracked files#991
aeppling merged 1 commit into
rtk-ai:developfrom
em0t:fix/git-completeness

Conversation

@em0t

@em0t em0t commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • switch default rtk git status to --porcelain -b -uall so dirty paths are no longer hidden behind grouped summaries, overflow markers, or directory-level collapse
  • preserve RTK's status framing (* branch, clean — nothing to commit) while keeping every dirty path visible
  • keep branch-oriented explicit status flags (-b, --branch, -sb, --short --branch) on the same compact path so rtk git status -b still gains tokens without hiding files
  • add focused regression coverage for default status behavior, branch-flag routing, rename/conflict preservation, and untracked directory expansion

Minimal Cases

rtk git status Hidden Dirty Paths

Raw

On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   src/file01.rs
	modified:   src/file02.rs
	modified:   src/file03.rs
	modified:   src/file04.rs
	modified:   src/file05.rs
	modified:   src/file06.rs
	modified:   src/file07.rs
	modified:   src/file08.rs
	modified:   src/file09.rs
	modified:   src/file10.rs
	modified:   src/file11.rs
	modified:   src/file12.rs
	modified:   src/file13.rs
	modified:   src/file14.rs
	modified:   src/file15.rs
	modified:   src/file16.rs
	modified:   src/file17.rs

no changes added to commit (use "git add" and/or "git commit -a")

Previous RTK (develop)

* main
~ Modified: 17 files
   src/file01.rs
   src/file02.rs
   src/file03.rs
   src/file04.rs
   src/file05.rs
   src/file06.rs
   src/file07.rs
   src/file08.rs
   src/file09.rs
   src/file10.rs
   src/file11.rs
   src/file12.rs
   src/file13.rs
   src/file14.rs
   src/file15.rs
   ... +2 more

This PR

* main
 M src/file01.rs
 M src/file02.rs
 M src/file03.rs
 M src/file04.rs
 M src/file05.rs
 M src/file06.rs
 M src/file07.rs
 M src/file08.rs
 M src/file09.rs
 M src/file10.rs
 M src/file11.rs
 M src/file12.rs
 M src/file13.rs
 M src/file14.rs
 M src/file15.rs
 M src/file16.rs
 M src/file17.rs

Untracked Directory Expansion

Raw

On branch main
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	tmp/

nothing added to commit but untracked files present (use "git add" to track)

Previous RTK (develop)

* main
? Untracked: 1 files
   tmp/

This PR

* main
?? tmp/c.txt
?? tmp/nested/d.txt

Branch-Oriented Explicit Flags Stay Compact

Raw

On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   tracked.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	tmp/

no changes added to commit (use "git add" and/or "git commit -a")

Previous RTK (develop)

On branch main
Changes not staged for commit:
	modified:   tracked.txt
Untracked files:
	tmp/

This PR

* main
 M tracked.txt
?? tmp/c.txt
?? tmp/nested/d.txt

Scope note: this PR keeps the explicit-flag support intentionally narrow. Only branch-oriented status flags (-b, --branch, -sb, --short --branch) reuse the compact path here; other explicit args stay on their existing path so we do not change semantics like -s alone gaining a branch line or -uno being overridden to -uall.

Testing

  • cargo fmt --all --check
  • cargo clippy --all-targets
  • cargo test --all

@CLAassistant

CLAassistant commented Apr 3, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@em0t em0t force-pushed the fix/git-completeness branch from 1b1f947 to 359daa5 Compare April 3, 2026 09:36
@em0t em0t changed the base branch from master to develop April 3, 2026 09:36
@em0t em0t force-pushed the fix/git-completeness branch 2 times, most recently from 2b61126 to 481103d Compare April 3, 2026 10:09
@em0t

em0t commented Apr 3, 2026

Copy link
Copy Markdown
Contributor Author

Could a maintainer please approve and run workflows so CI can start for review?

@aeppling aeppling self-assigned this Apr 3, 2026
@aeppling aeppling added the filter-quality Filter produces incorrect/truncated signal label Apr 3, 2026
@aeppling

aeppling commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Hello @em0t

Thanks for those contributions !

I'll review this today , currently focusing on bugs and filters quality.

Did you check if there was any issues related to your 4 PRs ?

@em0t

em0t commented Apr 3, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @aeppling. I didn’t find existing upstream issues specifically tracking these 4 cases.

These 4 PRs came from an internal local A/B evaluation we ran while assessing RTK for rollout in our team. We used Claude Code + Codex, wrote up a report, and these were the main issues we found. I split them into 4 small PRs by issue category to keep review clearer and each fix easier to reason about.

Also yes, all 4 PRs include automated regression tests for the behavior they change, and I ran cargo fmt --all, cargo clippy --all-targets, and cargo test --all locally on each branch.

To be transparent, I haven’t manually reproduced every case end-to-end by hand yet.

@aeppling

aeppling commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Ok thanks, passing by this i see the output of git status is :

Modified files:
  src/a.rs
  src/b.rs
Untracked files:
  tmp/c.txt

But actually, isn't "modified" and "untracked" enough for LLM to understand and compress a bit more ?
Since we are removing some filters part, would be interesting to add this if it make sense for you so we still get nice compression globally on git commands

@em0t

em0t commented Apr 3, 2026

Copy link
Copy Markdown
Contributor Author

Yes, that makes sense. I’ll follow up with a smaller optimization for the git status formatting afterwards.

@aeppling

aeppling commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Thank you !

@em0t

em0t commented Apr 3, 2026

Copy link
Copy Markdown
Contributor Author

@aeppling Follow-up pushed in this PR. Default git status now keeps every dirty path visible but switches the default output to porcelain-like status lines (##, M , ??) instead of grouped labels, so it compresses better without hiding files. I also removed the now-dead status limit config/docs and re-ran cargo fmt --all --check, cargo clippy --all-targets, and cargo test --all locally; clippy still shows the same pre-existing warnings outside this diff.

@em0t

em0t commented Apr 3, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review. I narrowed this PR further to keep the scope as small as possible.

Changes since the last round:

  • kept the scope in src/cmds/git/* only; no core config changes
  • preserved the existing RTK status framing (* branch, clean — nothing to commit)
  • kept only the behavior fixes:
    • default rtk git log no longer hides merge commits
    • default rtk git status no longer hides dirty paths and now expands untracked directories via -uall
  • reduced the regression coverage to the focused cases for these behaviors
  • updated the PR description to match the current behavior

Would appreciate another look when you have a moment. If anything still feels broader than it should be, I can trim it further.

@em0t em0t changed the title fix(git): preserve merge commits and full status paths fix(git): preserve full status paths and untracked files Apr 4, 2026
@em0t

em0t commented Apr 4, 2026

Copy link
Copy Markdown
Contributor Author

@aeppling I thought about it more and removed the git log merge-commit change from this PR.

What’s left is just the two git status correctness fixes: preserving all dirty paths and expanding untracked directories.

Would appreciate another review when you have a chance.

@aeppling

aeppling commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Hey @em0t

Additional thoughts , you bypass the porcelain flag addition when user run a "git status" cmd without arguments.
But in case user run "git branch -b", we could also catch to still gain token (if git status -b for eg.) Since we add -b in flags that could make sense to catch as well for compress.

@em0t

em0t commented Apr 14, 2026

Copy link
Copy Markdown
Contributor Author

@aeppling I pushed a follow-up for your last comment.

rtk git status -b now keeps the compact porcelain-style output without hiding dirty paths. Tests are updated and all checks are passing.

Would appreciate another look when you have time.

@aeppling

Copy link
Copy Markdown
Contributor

Hey @em0t Sorry for the response time, yes this is clean, you just got conflicts i think because we now use exec_capture, could you resolve please ? i'll come back to this during the week end

@em0t em0t force-pushed the fix/git-completeness branch from 92cd49e to 6ebde6d Compare May 9, 2026 03:32
@em0t

em0t commented May 9, 2026

Copy link
Copy Markdown
Contributor Author

@aeppling Sorry for the delay, I was away for a long holiday.

I’ve updated the PR based on your request and resolved the conflicts against the latest develop, including the exec_capture changes. When you have time, could you please take another look?

@aeppling

Copy link
Copy Markdown
Contributor

Hey @em0t

No problem, LGTM

Thanks again for contributing to RTK :)

@aeppling aeppling merged commit 3ba1634 into rtk-ai:develop May 14, 2026
11 checks passed
@aeppling aeppling mentioned this pull request May 14, 2026
Fungraphic pushed a commit to Fungraphic/rtk that referenced this pull request May 19, 2026
fix(git): preserve full status paths and untracked files
pull Bot pushed a commit to oXoi/rtk that referenced this pull request May 22, 2026
The compact `git status` path ran `git status --porcelain -b -uall`. The
`-uall` flag expands fully-untracked directories into every file, while raw
`git status` collapses them (e.g. `node_modules/`). This made rtk output
larger than raw — measured ~29x on a 200-file untracked dir (5500B vs 191B) —
violating RTK's compress-or-match-raw invariant and inflating tokens.

Remove `-uall` so untracked directories collapse exactly like raw. This keeps
rtk-ai#991's actual fix intact: all modified/staged/renamed/conflict paths are still
shown with no grouped summaries or `... +N more` overflow markers (`-uall`
never affected those lines). Untracked files in partially-tracked dirs and any
paths git itself expands are still preserved by the formatter.

Measured (rtk vs raw git status):
- node_modules/ (200 files): 5500B (-2780%) -> 25B (+87% savings)
- normal (8 mod + 2 untracked): +71% -> +76%
- 17 modified (rtk-ai#991 case): unchanged at +58%, all 17 shown, 0 overflow markers

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Olyno pushed a commit to Olyno/rtk that referenced this pull request May 24, 2026
The compact `git status` path ran `git status --porcelain -b -uall`. The
`-uall` flag expands fully-untracked directories into every file, while raw
`git status` collapses them (e.g. `node_modules/`). This made rtk output
larger than raw — measured ~29x on a 200-file untracked dir (5500B vs 191B) —
violating RTK's compress-or-match-raw invariant and inflating tokens.

Remove `-uall` so untracked directories collapse exactly like raw. This keeps
rtk-ai#991's actual fix intact: all modified/staged/renamed/conflict paths are still
shown with no grouped summaries or `... +N more` overflow markers (`-uall`
never affected those lines). Untracked files in partially-tracked dirs and any
paths git itself expands are still preserved by the formatter.

Measured (rtk vs raw git status):
- node_modules/ (200 files): 5500B (-2780%) -> 25B (+87% savings)
- normal (8 mod + 2 untracked): +71% -> +76%
- 17 modified (rtk-ai#991 case): unchanged at +58%, all 17 shown, 0 overflow markers

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ryanmurf added a commit to murphytek/rtk that referenced this pull request May 30, 2026
* fix(uninstall): uninstall removes --claude-md artifacts on Windows

  Core fix (src/init.rs — uninstall()):
  - Added step 3b after existing @RTK.md removal: checks for <!-- rtk-instructions marker in CLAUDE.md and removes the block
  using the existing remove_rtk_block() helper
  - Handles both artifacts in a single pass (covers edge case where both @RTK.md and the instructions block exist, e.g. after
  running both rtk init -g and rtk init -g --claude-md)
  - If CLAUDE.md becomes empty after cleanup, deletes the file

  Hardening:
  - Extracted RTK_BLOCK_START and RTK_BLOCK_END constants — all marker matching across uninstall(), upsert_rtk_block(),
  remove_rtk_block(), patch_claude_md(), and show_config() now uses these instead of duplicated string literals
  - When uninstall finds nothing to remove, prints which paths were checked to help users diagnose path issues
  - resolve_claude_dir() error message now shows %USERPROFILE% on Windows instead of $HOME

Signed-off-by: Adrien Eppling <adrien.eppling@supinfo.com>

* fix(init-uninstall): trailing newline, test refactor, changelog

Signed-off-by: aesoft <43991222+aeppling@users.noreply.github.com>

* fix(pnpm): install don't take a list of packages

Signed-off-by: Nicolas Le Cam <niko.lecam@gmail.com>

* fix(ls): add LC_ALL=C and fallback to raw on unrecognized locale

- Force LC_ALL=C so ls always outputs English month names regardless of system locale
- When no lines are parsed (e.g., non-English locale where regex fails to match),
  fall back to raw output instead of returning '(empty)'
- This prevents silent data loss for users in zh_CN/ja/ko/etc. locales
- Fixes rtk-ai#1276

* chore(master): release 0.37.0

* fix(install): reject archive with path traversal before extraction (rtk-ai#1250)

The installer previously ran `tar -xzf` on the downloaded archive with no
pre-extraction verification. A malicious mirror could ship a tarball with
`../` components or absolute paths and write files anywhere on the user's
filesystem (CWE-22).

Add a pre-extraction check that lists archive contents with `tar -tzf`
and rejects any entry whose name starts with `/` or contains a `..` path
component. The check is POSIX-compliant and adds negligible overhead for
the single-binary RTK release tarball.

Covered by scripts/test-install.sh, which exercises one safe archive
and four crafted malicious archives (leading `..`, absolute path,
mid-path `..`, trailing `..`) plus a regression guard that ensures the
check remains in install.sh.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(discover): skip head/tail rewrite when multiple files are passed (rtk-ai#1362)

`head -N file1 file2 ...` was rewritten to
`rtk read file1 file2 ... --max-lines N`. The capture regex was greedy
(`(.+)$`), so every file argument was folded into a single string. `rtk
read` then silently mis-handled the shape and fell through to the system
`read` builtin (`/usr/bin/read`) which rejects paths starting with `/` as
"not a valid identifier".

Tighten each head/tail regex to a single non-whitespace file argument
(`\S+$`). When >1 file is provided the regex misses, `rewrite_line_range`
returns `None`, and the command falls through to the native `head` / `tail`
binary — which already handles multi-file input with the expected
`==> name <==` banners. Same class as the cat multi-file fix in rtk-ai#989.

Added six regression tests covering the `-N`, `--lines=N`, `-n N`, and
`--lines N` variants for both `head` and `tail`.

* fix(ls): distinguish empty dir from unparseable locale content

- Move . and .. detection before date parsing (is_dotdir) for non-English locale compatibility
- Add dotdirs counter to distinguish empty dir (only . and ..) from real content that failed to parse
- Fix test_compact_empty to use real ls -la output (includes . and ..)
- Add test_compact_empty_chinese_locale for Chinese locale empty dir case
- Closes regression where fallback falsely triggered on empty directories

* refactor(ls): remove unused parse_failed variable

* chore(master): release 0.37.1

* feat(init): add --dry-run flag to preview changes without writing

Rebased onto current develop (binary-command era). Threads dry_run
through patch_settings_json_command, migrate_old_hook_script,
install_cursor_hooks, run_kilocode_mode, run_antigravity_mode,
run_gemini, run_copilot, and uninstall.

Fixes from PR rtk-ai#1032 review:
- --uninstall --dry-run no longer deletes files (uninstall() now takes
  dry_run, every fs::remove_file / fs::write / atomic_write guarded)
- Success messages ("installed", "configured", "Restart ...") gated on
  !dry_run in run_default_mode, run_hook_only_mode, run_codex_mode,
  run_copilot, install_cursor_hooks, run_gemini
- prompt_telemetry_consent() skipped in dry-run
- integrity::store_hash() in run_gemini guarded
- KiloCode and Antigravity modes now accept dry_run
- PatchResult::WouldPatch variant added for patch_settings_json_command
- [dry-run] Nothing written. footer printed by every sub-mode
- write_if_changed uses atomic_write (not fs::write)

Added integrity::hash_path_for() public wrapper so dry-run can check
sidecar existence without the destructive remove_hash.

Tests: write_if_changed(dry_run=true) creates nothing;
run_codex_mode_with_paths(dry_run=true) creates neither RTK.md nor
AGENTS.md. 1596 tests pass, clippy clean.

* chore(master): release 0.37.2

* fix(tests): update init.rs test calls for dry_run parameter

* feat(cicd): add auto next release parser

Create Next Release PR and set up the description with fix / feat PRs and issues to be closed

* fix(ls): LC_ALL=C + fallback to raw on unrecognized locale

- Force LC_ALL=C so ls always outputs English month names
- When zero lines parsed but directory has content, fallback to raw output
- Add is_dotdir() to distinguish empty dirs (only . and ..) from unparseable content
- Fix empty directory regression for both English and non-English locales
- Closes rtk-ai#1276

* chore(init): suppress semgrep filesystem-deletion on dry-run-wrapped removals

The two remove_file calls flagged by semgrep already existed pre-PR.
Wrapping them in if dry_run { print } else { remove_file } shifted
their context enough that --baseline-commit re-attributed them as new.
The rule's own message says deletion is expected in hooks/init cleanup.

* test(dotnet): try to lessen test flakiness

Fix seems counter intuitive but it helps a lot on my machine.
Before, I had 234 errors (23%) out of 1,000 tests run; now, I only have one (0.1%)

It's not totaly fixed but it reduce error a lot and avoids having one almost every time I test a PR.

Another way to completly fix it would be to use std::fs::set_times on old.trx to set each time in the past, but it requires unstable fs_set_times feature, so I'm not sure you'll agree with that

Signed-off-by: Nicolas Le Cam <niko.lecam@gmail.com>

* fix(grep): adjust the command to fall through if the output would already be as small as possible

* refactor(init): introduce InitContext and centralize dry-run footer

Addresses three review items from PR rtk-ai#1032:

- Bundle verbose+dry_run into a Clone+Copy InitContext struct (mirrors
  RunOptions in src/core/runner.rs). Collapses 25+ function signatures
  that already carried both fields and makes future flags one struct
  field instead of N signature changes.
- Emit "[dry-run] Nothing written." exactly once from the top-level
  run() and uninstall() exit points instead of from every sub-mode.
  Fixes the double footer when --agent cursor combined with default
  mode.
- Reject --show with --dry-run via clap conflicts_with rather than
  silently ignoring --dry-run.
- Add regression tests for run_default_mode and uninstall dry-run paths
  using the existing with_claude_dir_override scaffolding.

* docs(init): document --dry-run in quick-start guide

Adds a "Preview without writing" subsection under Step 1 covering the
--dry-run flag, -v interaction for content preview, that telemetry
consent is skipped, and the --show conflict. Required by CONTRIBUTING.md
section 4 (new features need documentation).

* fix(stream): route to respective fd

* fix(benchmark): capture all fd for stream cmd benchmark

* fix(benchmark): benchmark capture all fd only stream

* refactor(git): Fix stash status detection for all cases

Consolidate stash default handlers to ensure "no local changes"
is properly detected across all stash operations, not just the
default push case.

Signed-off-by: Nicolas Le Cam <niko.lecam@gmail.com>

* fix(stream): add semgrep flag for sh tests

* hotfix(cicd): add git app token for release please

* Update cd.yml

* hotfix(cicd): authorize dispatch for release please + git app for bump

* hotfix(cicd): git app token for artefact

* chore(master): release 0.38.0

* fix(git): surface in-progress state in compact `rtk git status`

Default `rtk git status` runs `git status --porcelain -b` to build its
compact view, but porcelain v1 omits the state header git prints when a
rebase, merge, cherry-pick, revert, bisect, am, or sparse checkout is in
progress. That header is correctness-critical — hiding "You are currently
editing a commit while rebasing..." leaves the user thinking the repo is
clean when it isn't.

`run_status` already captures plain `git status` output as `raw_output`
for tracking, so this fix adds `extract_state_header` to pull the state
block out of it and prepends the block to the compact output. Returns
`None` when nothing is in progress so clean repos are unchanged.

Covered states: interactive / regular rebase, merge-with-unmerged-paths,
"still merging after conflicts fixed", cherry-pick, revert, bisect, am,
sparse checkout. Preserves the directive hints git prints alongside
(`git rebase --continue`, `git commit --amend`, `git bisect reset`,
etc.), while still filtering generic `(use "git add")` / `(use "git
restore")` noise.

Design principle: Correctness vs Token Savings — never hide information
that changes the user's understanding of repo state.

* fix(git): compact in-progress status state

* fix(git): address review feedback on status state surfacing

- Drop redundant LANG=C env (LC_ALL=C is sufficient).
- Replace nested if/else chains in detect_status_state and
  extract_state_hint with const slices + iter for readability.
- Drop the 2-space indent prefix on hint lines — adds nothing for
  machine consumption.

* fix(git): drop state-hint extraction in compact status

KuSh: the in-progress state line ("rebase in progress", "merge in
progress. unresolved conflicts", etc.) is enough — LLMs know which git
commands resolve each state, so the per-state hint list was noise.

Removes STATE_HINTS and extract_state_hint, and reduces extract_state_header
to a short walk that returns the first detected state summary or None.
Existing per-state tests now assert the exact compact summary.

* chore: fix clippy warnings

- **Path Centralization:** Hardcoded directory and file paths across all hook logic () are replaced with dedicated, exported constants in . This prevents magic strings and simplifies maintenance when system directories change.
- **Code Cleanup:** Move all code only used by tests behind cfg(test) attribute
- **Refactoring:** Apply Clippy fixes and address remaining warnings

Signed-off-by: Nicolas Le Cam <niko.lecam@gmail.com>

* build(deps): bump rustls-webpki from 0.103.9 to 0.103.13

Bumps [rustls-webpki](https://github.com/rustls/webpki) from 0.103.9 to 0.103.13.
- [Release notes](https://github.com/rustls/webpki/releases)
- [Commits](rustls/webpki@v/0.103.9...v/0.103.13)

---
updated-dependencies:
- dependency-name: rustls-webpki
  dependency-version: 0.103.13
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(json): use char boundary when truncating long string values

* fix(json): expand char boundary truncation test

* test(json): assert truncated value byte length for multibyte strings

* feat(cicd): target develop branch

* fix(curl): JSON passthrough + IsTerminal gate to prevent invalid JSON output

`rtk curl` was unconditionally truncating any response >=500 bytes when a
tee hint was available, inserting the literal `... (N bytes total)` marker
mid-stream. For JSON bodies this produces invalid, unparseable output and
silently breaks every downstream `jq`, `python -m json.tool`, or agent
pipeline that consumes `rtk curl`.

Two changes in `filter_curl_output`:

1. JSON heuristic passthrough — if the trimmed body starts/ends with
   matching JSON brackets, return it unchanged. The body is already
   buffered in memory so the check is essentially free.

2. `is_terminal()` gate — only truncate non-JSON output when stdout is
   a TTY. Pipes and shell redirects (`> file`, `| jq`) now receive the
   full body, matching what `curl -o file` already does and closing
   the silent-data-loss path described in rtk-ai#1282.

The tee file is still written for inspection, but the hint line is
suppressed in the passthrough cases so it never leaks into pipes.

Tests: existing 5 cases updated to pass `is_tty=true` (preserve TTY-mode
assertions); 4 new cases cover JSON object/array passthrough at
>500 bytes and pipe-mode (non-TTY) full-body delivery.

Verified end-to-end against the public repro from the issue:
`rtk curl -s https://jsonplaceholder.typicode.com/posts | python3 -c
'import sys,json; print(len(json.load(sys.stdin)))'` now returns 100.

Closes rtk-ai#1536
Refs rtk-ai#1282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(curl): gate force_tee_hint, extend JSON heuristic, avoid full-body alloc

Follow-up to the initial rtk-ai#1536 fix after a deeper review pass.

- force_tee_hint() is no longer called on the passthrough path. Previously
  every non-TTY pipe invocation (curl | jq, curl | python -m json.tool —
  the exact scenarios this PR fixes) was still writing a tee log file as a
  side effect, which is wasteful: the tee file's purpose is to give the
  LLM a recovery path when output is truncated, and we are no longer
  truncating in those cases.

- looks_like_json now also matches bare top-level JSON strings (e.g.
  /api/token endpoints returning a long quoted token). Previously a
  >500-byte bare JSON string on a TTY would still get truncated mid-stream
  and produce invalid output.

- FilterResult.content is now Cow<'_, str> so the passthrough path no
  longer copies the whole body. For multi-MB curl responses piped through
  rtk this eliminates a full-size allocation.

- Exit code from curl is propagated via Ok(result.exit_code) instead of
  the previously hardcoded Ok(0). On the success path the value is 0
  anyway, but the inconsistency with the early-exit branch above made the
  intent unclear.

Tests: 9 -> 11 (added bare-JSON-string passthrough and a Cow::Borrowed
assertion verifying the passthrough paths don't allocate). cargo test
--all: 1693 passed, 6 ignored.

Verified end-to-end against jsonplaceholder.typicode.com/posts (~27 KB,
100 entries, parseable) and a randomly-generated 100-entry / 52 KB / 1450-line
JSON served from a local http.server (rtk output byte-identical to source
modulo the trailing newline added by println!).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(ls): handle device files (block, char, pipe, socket) in ls filter

Character devices (c), block devices (b), pipes (p), and sockets (s)
were silently dropped by compact_ls because only regular files (-),
symlinks (l), and directories (d) were handled. This caused
`rtk ls /dev/ttyACM*` to return "(empty)".

Closes rtk-ai#844

* fix(cicd): match ":" for body prefix to catch

Co-authored-by: Nicolas Le Cam <niko.lecam@gmail.com>

* fix(cicd): match allowed repo list in pr bodies

for next release body auto write

create a regex with pipes of list of allowed repo to be matched

added allowed_repos in cicd env

* feat(gradlew): add Gradle/gradlew support with streaming filters

Adds rtk gradlew command for build, test, lint, and dependency
operations on Gradle projects. Filters task progress noise, preserves
build scan URLs, test failures, lint violations, and compiler warnings.

Recognises ./gradlew, gradlew, gradlew.bat, and gradle invocations.
Surfaces unit-test report paths and shows a progress indicator for
long-running tasks.

Targets 75% savings (90% on test, 80% on build).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(hooks): add Pi coding agent integration

* refactor: handling of uninstallation

* test(cli): add init parse coverage for --pi, --agent pi, and --uninstall --pi

* fix(gradlew): satisfy semgrep dynamic-command-execution rule

Extract a new_gradle_command() helper that uses string literals in
every Command::new() branch. The .semgrep.yml dynamic-command-execution
rule rejects Command::new(var) — semgrep needs to statically audit
the executable set.

Same runtime behaviour: prefer ./gradlew (or gradlew.bat on Windows),
fall back to gradle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(gradlew): align with shared runner pattern

Replaces custom run_streaming / run_batch / run_passthrough / ProgressIndicator
with the shared runner helpers used by cargo and other commands:

- Build → runner::run_streamed with a BuildLineFilter implementing StreamFilter
- Test/Lint/Connected/Deps → runner::run_filtered with the existing filter_*
  closures (filter_test, filter_connected, filter_lint, filter_dependencies)
- Other / verbose flags → runner::run_passthrough(tool, args, verbose)

Benefits inherited from runner.rs: ChildGuard zombie prevention, 10 MiB output
cap, broken pipe handling, proper Result<i32> exit-code propagation.

run() now returns Result<i32> like cargo_cmd / golangci_cmd. main.rs updated
to forward the exit code with `?` directly (no manual `0` wrapper).

All Command::new() invocations remain string literals (semgrep
dynamic-command-execution rule).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(master): release 0.39.0

* fix(gradlew): use resolved_command for system gradle fallback

new_gradle_command() now uses resolved_command("gradle") for the two
fallback branches (Windows + Unix when no local wrapper is present),
matching how cargo / golangci-lint / etc. resolve system binaries.

Local wrappers (./gradlew, gradlew.bat) stay as string literals — they
are relative paths, not on PATH, and semgrep's dynamic-command-execution
rule needs literals here.

Net effect: PATHEXT-aware resolution on Windows (.CMD/.BAT shims work),
no behavioural change on Unix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: rm rtk awareness injection

* chore: docs cleanup

* Update telemetry documentation link to use 'master' branch

* fix(dotnet): move build/test/restore status line to the bottom

The `ok` / `fail` verdict line was emitted at the top of the filtered
output, before errors and warnings. Consumers reading the tail of the
stream — `| tail -N`, IDE log followers, agent watch/monitor loops,
bounded-context-window readers — saw error noise followed by EOF with
no verdict anywhere near the end, silently breaking any agent loop that
gates the next step on build success.

Reorder `format_build_output`, `format_test_output`, and
`format_restore_output` to emit the body first, then the separator
(only when the body is non-empty), then the verdict header last,
matching native `dotnet` which ends with `Build succeeded.` or
`Build FAILED.`.

Add three regression tests using strict `output.lines().last()` plus a
`tail -5` inclusion assertion so future regressions that append a
trailing context line get caught.

Closes rtk-ai#1574

Signed-off-by: Artiom Tofan <arto@queue-it.com>

* fix(dotnet): 🐛 format build/test/restore output sections

- Separate warnings and errors into distinct sections.
- Ensure status line is emitted last for clarity.
- Maintain consistency with native `dotnet` output behavior.

* fix(dotnet): 🐛 format build/test/restore output summaries

- Improve formatting of output summaries for build, test, and restore commands.
- Ensure status lines are emitted last for better stream consumption.

* fix(dotnet): 🐛 format warnings section in build/test/restore outputs

- Refactor warning formatting to improve consistency across output sections.
- Ensure warnings are displayed correctly in all relevant output formats.

* fix: correct ARCHITECTURE.md path in README links

The file lives at docs/contributing/ARCHITECTURE.md, not at the repo
root — both the nav header and Documentation section pointed to the
wrong location.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(init): make --pi route to Pi-only mode and skip CLAUDE.md injection

* chore: update hooks/pi/rtk.ts to reflect new package name

Co-authored-by: Jean du Plessis <jeandp@gmail.com>

* feat(hooks): add transparent_prefixes config for wrapper commands

Command wrappers like shadowenv (https://github.com/Shopify/shadowenv),
`direnv exec .`, `nix develop --command`, `docker exec <container>`,
`poetry run`, and `bundle exec` sit in front of every command in their
respective project layouts. When rtk is driving a Claude Code / Gemini /
Copilot / opencode hook, these wrappers defeat the rewrite — `rtk
rewrite "shadowenv exec -- git status"` returns exit 1 (no rewrite)
because the registry can't see past the wrapper to the inner `git
status`. Every build tool, test runner, linter, and `git` invocation
in such a layout stays uncompressed.

rtk already solves exactly this shape for shell builtins via
SHELL_PREFIX_BUILTINS (`noglob`, `command`, `builtin`, `exec`,
`nocorrect`): strip the prefix, recurse on the inner command, re-prepend
the prefix to the rewrite. This commit extends that pattern with a new
[hooks].transparent_prefixes config field so users can register
multi-word wrappers that don't change what runs, only how.

  [hooks]
  transparent_prefixes = ["shadowenv exec --", "direnv exec ."]

With that config, `rtk rewrite "shadowenv exec -- cargo test"` becomes
`shadowenv exec -- rtk cargo test` and exits 3 (ask, matching the
existing ask semantics for inner commands).

Implementation:

- New `rewrite_command_with_prefixes(cmd, excluded, transparent_prefixes)`
  public entry. The original `rewrite_command(cmd, excluded)` is kept as
  a thin back-compat wrapper that passes an empty prefix slice, so the
  ~150 existing unit-test call sites don't need updating.
- `transparent_prefixes: &[String]` threaded through `rewrite_compound`,
  `rewrite_segment`, `rewrite_segment_inner`.
- In `rewrite_segment_inner`, a second strip loop runs after the
  SHELL_PREFIX_BUILTINS loop, with identical strip-recurse-reprepend
  semantics. Matching is whole-word via the existing `strip_word_prefix`
  helper (multi-word prefixes like `"shadowenv exec --"` are handled
  by-value — byte-level `starts_with` plus a space check).
- Recursion is bounded by the existing MAX_PREFIX_DEPTH so pathological
  or self-referential configs cannot stack-overflow.
- Production callers (`hooks/rewrite_cmd.rs`, `hooks/hook_cmd.rs`,
  `main.rs`) now load both `exclude_commands` and `transparent_prefixes`
  from config in the same `Config::load()` call — no new I/O.

Tests (14 new):

- config: 3 TOML roundtrip tests (present, missing, mixed with older
  fields).
- registry: 11 behavior tests — strip/reprepend, unknown inner returns
  None, unmatched passthrough, composed with shell builtin, multiple
  prefixes configured, whole-word matching, empty-rest None, blank-entry
  skip, compound `&&` with prefix on both segments, excluded-inner
  returns None, recursion bounded.

Design principles (from CONTRIBUTING.md):
- Extensibility: extends an existing, documented pattern.
- Zero Overhead: config load already happens on every hook invocation;
  this reads one additional vec. Empty `transparent_prefixes` is the
  default and adds one cheap loop-over-zero-elements on the hot path.
- Correctness vs Token Savings: without this, hook rewrites silently
  miss every command run through a wrapper — exactly the kind of
  correctness gap the principle warns against.

* fix(hooks): compose env and transparent prefixes

* fix(hooks): address transparent prefix review

* fix(hooks): address transparent prefix review comments

* fix: minor code cleanup, avoid duplicating logic

* fix: new rewite_command test call after rebase

* fix: don't inject -json for go test -bench runs

When -bench is present, benchmark output is already compact and useful.
Injecting -json causes the filter to discard benchmark results since they
don't produce pass/fail events the JSON parser expects.

Fixes rtk-ai#1609

* refactor(warn): src/core/utils.rs has an unused error warning at compilation

* fix(cicd): pr-target clean msg + git app token

inform user how to solve CI pr-target failing check

* fix(git): resolve status completeness conflicts

* fix(hooks): make Cursor preToolUse rewrites work and stay visible

Three related issues prevented RTK from working with the Cursor
preToolUse hook on Windows. Each one alone produced the same
user-visible symptom (`Output: {}` and the original command running
unmodified), so they're fixed together:

1. Cursor preToolUse only enforces allow/deny — `permission: "ask"` is
   accepted by the schema but ignored at runtime, so `updated_input`
   rewrites could silently be dropped. Always return `allow` for
   rewritten commands (deny rules still take precedence and are
   evaluated before this point).

2. Cursor's preToolUse panel renders the JSON returned by the hook.
   Without a `continue: true` field the panel collapses to
   `Output: {}` even when the rewrite ran successfully, which makes
   the hook look broken from the user's perspective. Every other
   Cursor hook (`afterShellExecution`, `beforeSubmitPrompt`, `stop`,
   ...) returns `continue: true`; mirror that shape here so the panel
   surfaces the actual `permission` and `updated_input` payload.

3. Cursor on Windows prepends one or two UTF-8 BOMs (`EF BB BF`,
   sometimes doubled) to the JSON it pipes into the hook process.
   serde_json refuses to parse BOM-prefixed input, so `run_cursor`
   bailed out into the "no command" branch and returned `{}` for
   every invocation. Strip leading BOMs before parsing. This was the
   root cause of the long-standing "RTK silently no-ops in Cursor"
   reports — the rewrite path was never reached.

Tests cover the flat allow output, `continue: true` on both single
and compound (`cd ... && git status`) rewrites, the BOM-strip on
double-BOM payloads matching what Cursor actually sends, and assert
that the legacy hookSpecificOutput envelope is not emitted.

Verified end to end on Windows by tracing real Cursor stdin payloads:
the hook now returns `{"continue":true,"permission":"allow",
"updated_input":{"command":"rtk git status"}}` for `git status` and
the panel renders it instead of `Output: {}`.

* fix: resolve merge conflict artifacts in init.rs

* chore: fix clippy 0.1.95 warnings

* chore(ci): deny warnings and make clippy pass mandatory in ci

* feat(hermes): add rtk integration

Signed-off-by: Kayphoon <109347466+Kayphoon@users.noreply.github.com>

* style(hooks): format BOM helper assertion

* feat(init): remove --pi flag, canonicalize Pi install to --agent pi
chore: sync the codebase after mergew

* fix(security): replace insecure tmp, lock git workflow perm

* fix(security): pin workflow actions to SHA, clean up tempfile on failure

* Update pr-target-check.yml

* fix(cicd): set release-please target-branch to master [skip ci]

* chore(master): release 0.40.0

* fix(docker): forward --tail flag in compose logs

Previously `rtk docker compose logs --tail=20 web` would fall through to
the passthrough handler because clap had no `--tail` field on the `Logs`
subcommand, resulting in 0% token savings. Additionally, `run_compose_logs`
always fetched 100 lines regardless of user input.

- Add `#[arg(long, default_value_t = 100)] tail: u32` to `ComposeCommands::Logs`
- Thread the value through to the docker invocation
- Default unchanged (100 lines), so bare `rtk docker compose logs` behaves as before

Ports the core fix from rtk-ai#580, retargeted onto current develop layout
(`src/cmds/cloud/container.rs`). Relates to rtk-ai#578.

Co-authored-by: Mihir Dash <137862945+slice-mihird@users.noreply.github.com>

* fix(filters): address adversarial test-suite findings on aggressive filtering

Several filters dropped or rewrote information an agent needs, producing
output that was misleading rather than merely compressed. This fixes the
clear-cut cases surfaced by the TheDecipherist/rtk-test suite:

- ls: stop hiding the `.env` file (removed `.env`/`env` from NOISE_DIRS).
- git status: restore the explicit "HEAD detached at <sha>" line instead of
  the opaque "* HEAD (no branch)".
- log/docker logs: recognise CRITICAL/FATAL/ALERT/EMERGENCY/SEVERE (and
  NOTICE) as severities so those lines are no longer silently filtered;
  expose `log` as a `rtk pipe` filter and accept a positional filter name.
- wc: forward stdin to the child so `cat file | rtk wc` counts the pipe
  instead of reporting 0 (new RunOptions::inherit_stdin).
- jest/vitest: include skipped/pending test count in the compact summary.
- pytest: surface xfailed/xpassed counts and list XFAIL/XPASS entries with
  their reasons (adds `-rxX`).
- ruff/eslint: list individual violations with file:line:col, not just
  rule/file group counts.
- pnpm/npm list: render the actual package list instead of the false-positive
  "All packages up-to-date" when there's no upgrade info.
- git add: stay silent on a no-op instead of printing an ambiguous "ok".
- git stash: pass git's own message through instead of collapsing to "ok".
- docker ps: keep the Status column (health/restart info) and list
  stopped/exited containers; docker images: show all images with full names;
  docker compose ps: use `-a` so crashed services stay visible.

All 1870 unit tests pass; cargo fmt + clippy clean.

* chore(filters): remove filter-level annotations and restore compose logs tail arg

* fix(filters): add test for aggressive filter batch fix

* fix(git): stream push output via FilterMode::Streaming (rtk-ai#963)

## Problem (rtk-ai#963)

`rtk git push` reportedly times out: users see
`bash tool terminated command after exceeding timeout 30000 ms` while
plain `git push` to the same remote completes fine. P1-critical because
every Claude Code git push goes through rtk.

## Root cause

`run_push` used `cmd.stdin(Stdio::inherit()).output()`. `Command::output()`
captures both stdout and stderr until the child exits. Git push prints
its progress (`Counting objects` / `Compressing objects` / `Writing
objects`) to stderr and may prompt for SSH passphrases or HTTPS
credentials. With stderr captured, Claude Code's bash tool saw zero
output for 30+ seconds and killed the command — exactly the 30000 ms
message in the issue.

## Fix

Rewrite `run_push` on top of the streaming infrastructure that already
exists for this exact purpose (`stream::run_streaming` +
`FilterMode::Streaming`, added in 0.37.0).

Add a counterpart to `BlockStreamFilter<H: BlockHandler>` in
`src/core/stream.rs`: `LineStreamFilter<H: LineHandler>`. Where
`BlockStreamFilter` defaults to DROP and emits only collected blocks,
`LineStreamFilter` defaults to KEEP and lets handlers opt into dropping
noise. Trait surface mirrors `BlockHandler`:

- `should_skip(&mut self, line: &str) -> bool` — default false
- `observe_line(&mut self, line: &str)` — default no-op
- `format_summary(&self, exit_code, raw) -> Option<String>`

This lets future streaming commands reuse the line-oriented pattern.

`GitPushLineHandler` then becomes a tiny `LineHandler` impl:

- `should_skip` drops the high-volume progress phases (Enumerating /
  Counting / Compressing / Writing objects, Delta compression, Total)
  and blank lines.
- `observe_line` captures the up-to-date sentinel and the first ref
  update target (e.g. `master`) for the summary.
- `format_summary` emits `ok <ref>` / `ok (up-to-date)` / `ok` on
  success; nothing on failure (raw error lines already flowed through).

Stdin is inherited (`StdinMode::Inherit`) so SSH passphrase and HTTPS
credential prompts still reach the user. Tracking now records the real
raw output and the filtered output.

## Test plan

- [x] `cargo fmt --all -- --check`
- [x] `cargo clippy --all-targets -- -D warnings` — clean
- [x] `cargo test --all` — 1880 passed, 0 failed, 6 ignored
- Six unit tests cover the push handler: progress-prefix drop,
  up-to-date summary, remote message passthrough, no-summary-on-failure,
  first-ref-wins, and token-savings (>=60% on a representative payload).
- Four unit tests cover the new `LineStreamFilter` trait:
  default-keep-all, skip-drops-matching, summary-propagates-exit-code,
  observe-only-called-for-kept-lines.

## Notes

- Behaviour change: users now see git's native output line-by-line
  (with progress phases stripped) plus a final `ok <ref>` summary,
  instead of just the compact summary. This matches plain `git push`
  more closely and is what the issue reporter expects.
- No regression for other filters: `run_pull`, `run_fetch`, `run_clone`
  are untouched; only `run_push` is modified.

Closes rtk-ai#963

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---
_Vibe Coded by Ousama Ben Younes_
_Developed With Ora Studio (Claude Code)_

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(hints): add tail hints for tee & hints + address reviews

- fix signal truncation gaps + kush reviews
- added a new tee and hints function to give an hint with tail (avoid re-ingest of the head)
- extracted patterns in constants

* fix: re-add env python as noisy dir

* fix: '...' ascii to unicode, remove some comments

* fix(kubectl): compact get pods and services aliases

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(filters): split docker ps/-a paths, cap ruff violations at 50

- docker ps reverts to plain (no -a augmentation)
- docker ps -a / compose ps -a wired to the running/stopped split filter
- ruff Violations: capped at 50 + force_tee_tail_hint recovery
- tests for the ruff and pytest xfail caps

* fix(init): honor dry-run for Pi install and uninstall paths

* fix(tee): safe truncation caps and compose-ps tee content fix

Replace all bare magic offset literals (e.g. 21 for cap=20) with named
constants (MAX_XXX + 1) so offsets stay in sync if caps change.
Fix compose_ps to tee pre-formatted lines instead of raw tab-separated
input, so tail -n +N gives the agent readable content.
All 13 affected modules updated: container, dotnet, gh, glab, go, lint,
pnpm, pytest, rubocop, cargo, aws. 1884 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(rust): multi-line blocks used with tail hint

* docs(cmds): truncations hints and recovery guidelines

* test(hooks/init): add red test for copilot-instructions preservation

Adds a TDD red test that asserts pre-existing user content in
.github/copilot-instructions.md must survive 'rtk init --copilot'.
Currently fails because run_copilot() uses write_if_changed() which
truncates the file.

Refs rtk-ai#1964

* fix(hooks/init): preserve user content in copilot-instructions.md

run_copilot() previously called write_if_changed() which truncated any
pre-existing .github/copilot-instructions.md, destroying user-authored
Copilot rules.

This routes copilot-instructions.md through upsert_rtk_block() (the
same idempotent marker-block helper already used for CLAUDE.md and
AGENTS.md). The COPILOT_INSTRUCTIONS constant is wrapped in
<!-- rtk-instructions v2 --> ... <!-- /rtk-instructions --> markers
so subsequent inits replace only RTK-owned content; the rest of the
file is preserved verbatim. Malformed pre-existing blocks (opening
marker without closing) are refused with a remediation message
rather than silently rewritten.

Fixes rtk-ai#1964, rtk-ai#1891

* test(hooks/init): cover idempotency, stale-block, dry-run, fresh, malformed paths

Adds five additional tests around copilot-instructions.md upsert:
- idempotent re-init (no duplicated blocks, identical content)
- stale RTK block in-place update with surrounding user content preserved
- dry-run never creates or modifies the file
- fresh install creates file with RTK marker block when no file exists
- malformed pre-existing block (opening marker without closing) is
  refused with a clear error rather than silently rewritten

Refs rtk-ai#1964

* refactor(hooks/init): extract run_copilot_at for parallel-safe tests

run_copilot(ctx) is now a thin wrapper around run_copilot_at(base, ctx);
tests pass a TempDir path so they no longer mutate process-global cwd.
This eliminates flakes when cargo test runs in parallel (the default).

The public API is unchanged; only the internal seam moves.

Refs rtk-ai#1964

* docs(readme): fix license references to match LICENSE (Apache-2.0)

The README badge and footer claimed MIT, but the LICENSE file is
Apache License 2.0. Updates both references so the README matches
the authoritative LICENSE file.

Closes rtk-ai#1996

Co-Authored-By: Claude <noreply@anthropic.com>

* refacto(truncations): Set global CAPS for truncation

Following tee and hint refacto
Add global CAP constant to be inherited , to enable easier global configuration later

* refactor(hooks/init): share write_rtk_block, unify malformed handling

Address review feedback on rtk-ai#1976:

- Extract write_rtk_block() shared dispatcher: eliminates the duplicated
  4-arm RtkBlockUpsert match between run_claude_md_mode and the former
  upsert_copilot_instructions (now inlined). Both callers stay under the
  ~60-line guideline.
- Unify malformed handling: both paths now bail!() with a diagnostic and
  the exact recovery command. CLAUDE.md previously warned and exited 0,
  silently skipping the OpenCode plugin step; behaviour is now consistent.
- Reorder run_copilot_at: upsert copilot-instructions.md BEFORE writing
  the hook config so a malformed file aborts the install without leaving
  a stale .github/hooks/rtk-rewrite.json on disk.

Regression coverage:
- test_claude_md_mode_refuses_malformed_block mirrors the existing
  copilot malformed test against the shared dispatcher contract.
- test_copilot_init_malformed_leaves_no_hook_on_disk pins the new write
  order so a future re-order regression is caught.

cargo fmt / clippy --all-targets / test --bin rtk: clean (1909 passed).

* fix(truncate): global caps reduce (avoid underflow and 0 results)

- Avoid underflow + 0 results caused by overwrite of global constant CAPS
- Soon user will be able to apply global configuration, this will change global CAPS and should not cause any underflow or 0 results, if overwrite sub >= CAPS -> use CAPS.

* fix: honor explicit -n N limit for git log on merge commits

When user runs 'git log -1 --format='%H' HEAD' where HEAD is a merge
commit, rtk was adding --no-merges which filtered out the merge commit
itself and returned the second parent instead. This made 'git log -1'
return wrong SHAs for merge commits.

Fix: don't add --no-merges when user explicitly passes -n N or
--max-count=N. When a user specifies an exact count they expect exactly
that many commits, not filtered results. Also skip --no-merges if user
already passed --merges or --no-merges explicitly.

Fixes rtk-ai#2009.

* chore: regroup agent init tests by agent section

* fix(git): drop -uall from compact status so output never exceeds raw

The compact `git status` path ran `git status --porcelain -b -uall`. The
`-uall` flag expands fully-untracked directories into every file, while raw
`git status` collapses them (e.g. `node_modules/`). This made rtk output
larger than raw — measured ~29x on a 200-file untracked dir (5500B vs 191B) —
violating RTK's compress-or-match-raw invariant and inflating tokens.

Remove `-uall` so untracked directories collapse exactly like raw. This keeps
rtk-ai#991's actual fix intact: all modified/staged/renamed/conflict paths are still
shown with no grouped summaries or `... +N more` overflow markers (`-uall`
never affected those lines). Untracked files in partially-tracked dirs and any
paths git itself expands are still preserved by the formatter.

Measured (rtk vs raw git status):
- node_modules/ (200 files): 5500B (-2780%) -> 25B (+87% savings)
- normal (8 mod + 2 untracked): +71% -> +76%
- 17 modified (rtk-ai#991 case): unchanged at +58%, all 17 shown, 0 overflow markers

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Update git.rs

* docs(git): sync status README with --porcelain -b (drop -uall)

* chore(master): release 0.41.0

* feat: address pr suggestions

* chore: sync with pi api

* chore: minor cleanup

* chore(master): release 0.42.0

* fix(clippy): factor mvn version-cache triple into type alias

Pre-existing clippy::type_complexity on the probe_mvn_version CACHE static
(deny-warnings in CI's `cargo clippy --all-targets` gate). Extract the
(u32,u32,u32) into a VersionTriple alias per clippy's own suggestion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Signed-off-by: Adrien Eppling <adrien.eppling@supinfo.com>
Signed-off-by: aesoft <43991222+aeppling@users.noreply.github.com>
Signed-off-by: Nicolas Le Cam <niko.lecam@gmail.com>
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Artiom Tofan <arto@queue-it.com>
Signed-off-by: Kayphoon <109347466+Kayphoon@users.noreply.github.com>
Co-authored-by: aesoft <43991222+aeppling@users.noreply.github.com>
Co-authored-by: Nicolas Le Cam <niko.lecam@gmail.com>
Co-authored-by: Lumin Cui <vincenthcui@qq.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Ousama Ben Younes <benyounes.ousama@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: hed0rah <18272116+hed0rah@users.noreply.github.com>
Co-authored-by: Joshua <joshua.french@hey.com>
Co-authored-by: rtk-release-bot[bot] <280461666+rtk-release-bot[bot]@users.noreply.github.com>
Co-authored-by: Victor Sumner <victor.sumner@shopify.com>
Co-authored-by: Victor Sumner <vsumner@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: swithek <52840391+swithek@users.noreply.github.com>
Co-authored-by: patrick <patrick@rtk-ai.app>
Co-authored-by: Maxence Bombeeck <maxence.bombeeck@supinfo.com>
Co-authored-by: Adrien Eppling <adrien.eppling@supinfo.com>
Co-authored-by: Kevin <kevin.herembourg@gmail.com>
Co-authored-by: gitbluf <gh+git@gitbluf.xyz>
Co-authored-by: gitbluf <git+gh@gitbluf.xyz>
Co-authored-by: SADIK KUZU <sadikkuzu@hotmail.com>
Co-authored-by: Artiom Tofan <arto@queue-it.com>
Co-authored-by: Sam Severance <swseverance@gmail.com>
Co-authored-by: Marko Petrovic <22802784+gitbluf@users.noreply.github.com>
Co-authored-by: Jean du Plessis <jeandp@gmail.com>
Co-authored-by: Yaniv Michael Kaul <yaniv.kaul@scylladb.com>
Co-authored-by: xdm67x <m-ozkan@outlook.fr>
Co-authored-by: em0t <10153971+em0t@users.noreply.github.com>
Co-authored-by: kamilkaczmareksolutions <kamil.kaczmarek.us@gmail.com>
Co-authored-by: patrick szymkowiak <52030887+pszymkowiak@users.noreply.github.com>
Co-authored-by: Kayphoon <109347466+Kayphoon@users.noreply.github.com>
Co-authored-by: Mihir Dash <137862945+slice-mihird@users.noreply.github.com>
Co-authored-by: pagarsky <opaharskyi@chartbeat.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: 李冠辰 <liguanchen@xiaomi.com>
Co-authored-by: Tylere Zimmerman <tylere.zimmerman@delinea.com>
Co-authored-by: okwn <root@okwn.cc>
Co-authored-by: tron-coord <coord@murphytek.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

filter-quality Filter produces incorrect/truncated signal

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants