Commit Graph

55 Commits

Author SHA1 Message Date
Adrien Eppling b619ecfb24 test(git): update stash summary tests for comma-free format 2026-07-03 14:57:47 +02:00
aesoft 6c3d81f970 no commas 2026-07-03 14:06:23 +02:00
Adrien Eppling 0ac5f5c311 fix(git): compress git stash show summary line
Shorten "N files changed, X insertions(+), Y deletions(-)" to "N changed, X +, Y -"; numbers preserved, no signal loss.
2026-07-03 13:39:50 +02:00
Adrien Eppling add35e0928 fix(git): compact git stash show instead of forcing -p
Strip the diffstat decorations and cap the file list; savings are measured against the real command, not an inflated -p patch.
2026-07-03 12:14:01 +02:00
aesoft 9a52647f65 Merge pull request #2499 from hgunduzoglu/fix/git-worktree-list-exit-code
fix(git): propagate exit code on git worktree list failure
2026-06-26 13:58:31 +02:00
aesoft 29272484de Merge pull request #2496 from hgunduzoglu/fix/git-commit-false-success
fix(git): propagate exit code when commit fails instead of reporting ok
2026-06-26 13:24:34 +02:00
aesoft a9b2ef5b3c Update git.rs 2026-06-26 13:16:32 +02:00
aesoft adaf2b259c Update git.rs 2026-06-26 13:13:37 +02:00
Husam c04dec1fe1 test(git): cover exit-code propagation for git stash list/show failure
develop already propagates the exit code for failed git stash list/show
(via the empty-stdout guard). Add regression tests so the masking-failure
behavior (#2497) can't creep back.
2026-06-26 13:16:24 +03:00
aesoft d86f0073ec Merge pull request #2498 from hgunduzoglu/fix/git-status-compact-exit-code
fix(git): propagate exit code on git status failure in compact path
2026-06-26 11:49:23 +02:00
Husam 8ef08cf6f0 refactor(git): trim verbose comments on commit outcome to a concise note 2026-06-26 12:04:25 +03:00
Husam d8e1428110 refactor(git): drop explanatory comment on worktree list failure guard
Per review (#2498): self-explanatory guard; remove comment to avoid noise.
2026-06-26 11:35:37 +03:00
Husam ee5a675f40 refactor(git): drop explanatory comment on status failure guard
Per review (#2498): the guard is self-explanatory; remove the comment
to avoid noise.
2026-06-26 11:35:00 +03:00
Adrien Eppling 861a46dee5 fix(core): never-worse output guard so RTK never exceeds the raw command
RTK could emit more tokens than the underlying command on small inputs:
filters that add headers, summaries, re-indentation, or a tee hint, plus
synthetic no-result messages ("0 matches", "No stashes", "[docker] 0
containers") printed where the raw command emitted nothing. Both break the
Transparency principle and inflate tokens instead of saving them.

- core::guard::never_worse(raw, filtered) returns raw when the filtered form
  has more tokens (reuses tracking::estimate_tokens), so RTK output is never
  larger than the real command.
- runner::emit_guarded(filtered, hint, raw) composes body + tee hint, guards
  the whole, prints, and returns what was shown so printed == tracked.
- run_captured_filter guards the run_filtered* family centrally; per-site
  guards cover the remaining single-string filters.
- On empty raw, emit empty and preserve the exit code instead of a synthetic
  no-result message (the messages were cosmetic with no dependents; #2461
  reports the grep one as actively harmful).
- git stash show now propagates its exit code instead of masking a real
  failure as Ok(0).

Resolves #2551.
2026-06-23 21:53:35 +02:00
Husam ebaaf8db58 fix(git): propagate exit code on git worktree list failure
run_worktree list mode never checked result.success() — a failed
`git worktree list` (e.g. run outside a repo) was flattened to empty
output + exit 0. The has_action branch already guards on success; apply
the same guard to list mode and surface git's error with its exit code.

Part of #2497
2026-06-18 22:55:50 +03:00
Husam 756c2a4ce8 fix(git): propagate exit code on git status failure in compact path
The compact status path only caught the "not a git repository" error and
let every other failure (corrupt index, lock contention, broken refs)
fall through to a formatted "Clean working tree" + Ok(0), masking a real
git error. The non-compact path already guards on result.success(); apply
the same guard to the compact path, keeping the friendly not-a-repo
message and propagating git's real exit code otherwise.

Part of #2497
2026-06-18 22:53:49 +03:00
Husam e36dd8cbe7 fix(git): propagate exit code when commit fails instead of reporting ok
run_commit had a branch that printed 'ok (nothing to commit)' and fell
through to Ok(0) whenever git exited non-zero with a 'nothing to commit'
message — so a no-op or hook-aborted commit was reported as success with
exit 0. Gate strictly on output.status.success() via a CommitOutcome
helper: any failure surfaces git's message and propagates the real exit
code, matching native git. Same bug class as #1581 (push) and #1535
(stash).

Fixes #2494
2026-06-18 22:22:36 +03:00
aesoft 0a630fe9ac Merge pull request #2289 from rtk-ai/refacto/strip-output-decorators
refacto(cmds): strip decorator noise from filter output
2026-06-05 18:31:39 +02:00
Adrien Eppling 16d6599b4c refacto(cmds): strip decorator noise from filter output
Separator lines (═══, ---) and an emoji status marker cost tokens
without adding signal for the LLM — RTK output must never add noise
over raw. Semantic labels are kept; the emoji is swapped for plain
monochrome unicode.
2026-06-05 17:41:53 +02:00
aesoft 4f4a6a02ae Merge pull request #1266 from shalk/fix/commit-multibyte-panic-rebased
fix(git): fix panic on multibyte chars in commit output
2026-06-03 17:20:40 +02:00
Nicolas Le Cam 83cd93e7d7 chore(args): introduce a more generic solution for restoring double dashes in args
Fixes #1669
2026-05-31 17:06:26 +02:00
aesoft 26c88907d9 Merge pull request #2015 from okwn/contrib/rtk/git-log-merge-fix
fix: honor explicit -n N limit for git log on merge commits
2026-05-23 10:11:11 +02:00
aesoft f431fb9521 Update git.rs 2026-05-22 15:30:14 +02:00
Adrien Eppling 7753e487b3 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
#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 (#991 case): unchanged at +58%, all 17 shown, 0 overflow markers

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 10:13:00 +02:00
okwn b3adcb18ef 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/rtk#2009.
2026-05-21 10:16:09 +00:00
aesoft 9c80934dab Merge branch 'develop' into fix/tee-hint-trunc-quality 2026-05-21 10:27:00 +02:00
aesoft b6054a5fef 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
2026-05-20 17:29:14 +02:00
aesoft 90c285c380 Merge pull request #1895 from rtk-ai/fix/aggressive-filters-batch
fix(filters): aggresivity batch fix
2026-05-19 09:15:39 +02:00
aesoft 3571d5293d fix: '...' ascii to unicode, remove some comments 2026-05-16 15:23:06 +02:00
aesoft 46fe7c4729 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
2026-05-16 15:00:11 +02:00
Ousama Ben Younes be5178377f fix(git): stream push output via FilterMode::Streaming (#963)
## Problem (#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 #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>
2026-05-15 22:13:59 +00:00
aesoft f6b28c292b fix(filters): add test for aggressive filter batch fix 2026-05-15 19:14:37 +02:00
aesoft 16803a6cce chore(filters): remove filter-level annotations and restore compose logs tail arg 2026-05-15 19:14:36 +02:00
Adrien Eppling 62fc0e0d21 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.
2026-05-15 19:12:05 +02:00
em0t 6ebde6d2c2 fix(git): resolve status completeness conflicts 2026-05-09 11:32:00 +08:00
aesoft b5500bb6bf Merge pull request #1586 from KuSh/git-stash-nothing
refactor(git): Fix stash status detection for all cases
2026-05-04 22:12:36 +02:00
Victor Sumner e91dee568b 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.
2026-05-01 05:54:24 +02:00
Victor Sumner 316e65ef5b 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.
2026-05-01 05:54:24 +02:00
Victor Sumner cff391e50b fix(git): compact in-progress status state 2026-05-01 05:54:24 +02:00
Victor Sumner 017d0f9ee6 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.
2026-05-01 05:54:24 +02:00
Nicolas Le Cam b8558910cd 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>
2026-04-28 22:10:34 +02:00
binsee 13188a88b2 fix(git): fix empty output when branch name contains '/' in git diff
Branch names containing '/' (e.g. feature/user-auth, main...feature/auth)
were incorrectly treated as file paths by the string heuristic in
normalize_diff_args, causing '--' to be injected before them and making
git treat them as pathspecs — resulting in silent empty output (exit 0).

Replace looks_like_path() with a three-tier detection strategy:
- Explicit path prefixes (. ~) → always a path, no filesystem check needed
- Contains path separator (/ \) → use filesystem existence to distinguish
  branch names (feature/auth, not on disk) from real paths (src/main.rs)
- Bare word with no separator → never inject '--', regardless of filesystem
  state (avoids misfire when a file shares a name with a branch/ref)

Introduce normalize_diff_args_impl with injectable path-checker for
testability. Update all existing tests to use mock existence checks.
Add three regression tests: branch-with-slash, range-with-slash, and
bare-word-that-exists-on-disk.

Fixes: #1431

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 00:24:32 +08:00
aesoft 906dedd75a Merge remote-tracking branch 'origin/develop' into feat-hook-engine 2026-04-13 21:14:55 +02:00
shalk(xiao kun) ab4fa7b539 test(git): add regression tests for commit output parsing with multibyte branch names
Extracts parse_commit_output into a testable helper function and adds 7 comprehensive unit tests covering:
- Normal branch names
- Root-commit annotations
- Multibyte branch names (Chinese, Thai) — regression test for the panic fix
- Edge cases (no bracket, short hash, empty input)

Tests verify the fix handles UTF-8 safely by anchoring on ']' and using char-safe slicing.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-13 19:49:29 +08:00
shalk(xiao kun) c5ec92fac8 fix(git): fix panic on multibyte chars in commit output
git commit on an initial commit under a Chinese locale outputs:
  [master(根提交) fb597ec] Initial commit

The old code found the first space and sliced line[1..hash_start],
yielding "master(根提交)" (21 bytes).  hash.len() >= 7 was true,
so it tried &hash[..7] — but byte 7 falls inside the 3-byte '('
character, causing a panic.

Two bugs were present:
1. Logic: the code grabbed the token *before* the first space
   (branch name), not the commit hash.  The hash is always the last
   whitespace-separated token inside the [...] brackets.
2. Safety: raw byte slicing on a potentially non-ASCII string.

Fix: find ']', extract the bracket content, split_whitespace() and
take next_back() to get the hash.  Use chars().take(7) for the
short-hash slice so it is always char-boundary-safe.
2026-04-13 17:30:47 +08:00
Ousama Ben Younes 9979c69930 fix(git): re-insert -- separator when clap consumes it from git diff args (#1215)
clap's trailing_var_arg=true silently drops -- when it appears as the first
positional argument. This caused `rtk git diff -- <path>` to arrive in
run_diff without the separator, making git treat the path as a revision and
emit "fatal: ambiguous argument". Adds normalize_diff_args() which re-inserts
-- before the first path-like argument (contains /, \, starts with . or ~)
when -- is absent from the args vec. The fix is a no-op when -- is already
present (e.g. rtk git diff HEAD -- file preserves the separator correctly).

Generated by Claude Code
Vibe coded by ousamabenyounes

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-11 10:27:12 +00:00
Adrien Eppling 52643791bc Merge origin/develop into feat/refacto-stream-binary
Integrates ~30 develop commits (PR #997): AWS expansion (8→25 cmds),
SSH signing for git commit/push, go test context, grep stdin leak fix,
default-to-ask permissions, gh pr merge passthrough.

Conflict resolution (4 files):
- git.rs: kept .output()+stdin(inherit) for commit/push (SSH/GPG signing)
- go_cmd.rs: accepted incoming + added pub(crate) visibility
- hook_check.rs: merged binary_hook_registered + other_integration_installed
- hook_cmd.rs: fixed permissions path, println→writeln for Gemini deny

Verified: 1445 tests pass, 0 clippy errors, all manual integration tests pass.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-04 21:21:01 +02:00
aesoft a2312df5f2 feat(stream): standardize command execution with exec_capture() 2026-04-04 20:38:43 +02:00
Nicolas Le Cam c6f35c9771 fix: apply clippy suggestions
Signed-off-by: Nicolas Le Cam <niko.lecam@gmail.com>
2026-04-04 01:25:16 +02:00
em0t 09b3ff9424 fix(git): preserve full diff hunk headers
Signed-off-by: em0t <10153971+em0t@users.noreply.github.com>
2026-04-03 18:09:20 +08:00