Skip to content

chore: sync fork with upstream rtk-ai/rtk v0.43.0 - #22

Merged
ryanmurf merged 383 commits into
masterfrom
chore/sync-upstream-v0.43.0
Jul 25, 2026
Merged

ryanmurf merged 383 commits into
masterfrom
chore/sync-upstream-v0.43.0

Conversation

@ryanmurf

@ryanmurf ryanmurf commented Jul 25, 2026 •

Copy link
Copy Markdown

Summary

Syncs the fork with upstream rtk-ai/rtk v0.43.0 — 381 upstream commits, v0.42.0 → v0.43.0.

Done as a true merge (2 parents, 65c3ce9), matching the precedent set by the last sync (152f4e3). No history was rewritten and nothing was force-pushed.

Why there were so many conflicts

The previous sync (152f4e3) was squash-merged, so the merge base with upstream is still 323cc3d — it predates that sync. Git therefore saw the flattened upstream content on our side as "ours" and reported it as conflicting against the same content upstream. 21 of the 37 conflicted files were pure noise of this kind. Each was proved byte-identical to tag v0.42.0 on our side before taking upstream's version, so "take upstream" there is provably lossless rather than an assumption.

The remaining 16 were resolved by hand and are listed below.


Local carry — KEPT

Each of these was checked against upstream v0.43.0 source directly (not inferred from commit messages). None had been absorbed upstream.

Commit Fix Evidence it is still needed
690dc16 fix(ls): entries whose names end in . were dropped upstream still uses ends_with('.') to detect ./..
95d20f1 fix(read): --tail-lines renumbered the gutter from 1 upstream format_with_line_numbers(content: &str) has no offset parameter
54b1216 fix(wc): filenames containing spaces split_counts_and_name absent upstream
d898926 fix(tree): summary-line detection is_tree_summary absent upstream
eb70ed9 fix(find): UTF-8-safe dir abbreviation abbreviate_dir absent upstream
d546a9a fix(log): truncate by chars, not bytes truncate_message absent upstream
59e592d fix(gain): char-safe truncation absent upstream
d738b7b, aa3f157, b031884 rtk gradle / rtk ant commands, gradle.toml / ant.toml, line_dedup / stack_dedup / stack_trim, RTK_NO_INJECT_FLAGS fork-only features; upstream has no Gradle/Ant command
0a9f47a ci: fall back to GITHUB_TOKEN when GitHub App secrets are absent fork-specific; the App secrets do not exist here
3079701 chore(release): Discord notify + Homebrew formula steps stay removed fork-specific
8c4e26d docs: README points at murphytek/rtk fork-specific (11 murphytek refs preserved)

Kept carry that had no test coverage now has one: RTK_NO_INJECT_FLAGS gained test_injection_disabled_truth_table in src/cmds/jvm/gradle_cmd.rs — a mutex-serialised env test pinning the full truth table (unset / 1 / true / yes / arbitrary value → disabled; "" and 0 → enabled). Every other kept fix already had a regression test, and those tests were re-applied on top of upstream's rewritten files and still pass.

Local carry — DROPPED as genuinely superseded upstream

f30963e fix(grep): treat bare | as a literal pipe (BRE), not rg alternation.
Upstream rewrote grep_cmd.rs into search.rs, which now runs the real grep binary verbatim and never substitutes rg for it. main.rs routes rtk grep → search::Engine::Grep, and upstream pins the exact behaviour our fix added in tests/search_faithful_test.rs:69 ("a bare | is a literal pipe … proving no rg substitution"). Verified against the built binary:

$ rtk grep -n 'alpha|beta' bre.txt      →  1:alpha|beta
$ grep    -n 'alpha|beta' bre.txt       →  1:alpha|beta

Our translate_bre_pipes helper and grep_cmd.rs were removed with the rename.

1b44030 feat(jvm): Maven command + mvn-build.toml filter.
Superseded — but by independent upstream work, not by our commit being upstreamed. Upstream 6c4950e (feat(mvn)!: Rust module replacing TOML filter) ships a 2112-line maintained module covering the full Maven lifecycle with stateful Surefire collapse, plus ~15 follow-up commits. Keeping our TOML filter alongside it would mean maintaining a strictly worse duplicate, so upstream's module won.


⚠️ User-visible behaviour changes (judgement calls — flagged per brief)

  1. rtk mvn build no longer exists. Our fork exposed rtk mvn <subcommand> with a build alias mapping to compile. Upstream's rtk mvn passes goals straight through to Maven, so rtk mvn build is now rtk mvn compile (or whatever goal you actually want). This is the one place where taking upstream changes behaviour for users, and it is the trade I made deliberately: upstream's module is materially better and actively maintained.
  2. RTK_NO_INJECT_FLAGS no longer applies to mvn. It was ours, wired into our mvn module. It still governs Gradle/Ant, which is where it matters on this host.
  3. The fork's Maven integration tests were removed (tests/jvm_filter_integration.rs Maven sections + 2 fixtures + filter_mvn_build/filter_mvn_test in tests/common/mod.rs). They re-implemented the filter inside the test file instead of calling production code, so after the swap they asserted only against themselves — vacuous, not coverage. Upstream's mvn module ships its own fixtures and unit tests. Gradle and Ant sections remain (6 tests).

External review (codex / gpt-5.5) — REQUEST_CHANGES, addressed in 40b3b0c

The mandatory pre-merge review returned REQUEST_CHANGES with 5 bug findings. I reproduced every
one against the built binary rather than taking them on trust; 4 of 5 were real, and one was
wrong.
Fixes are in a separate commit, 40b3b0c.

# Finding Verified Introduced by this merge? Action
1 pytest xfail/xpass block emitted twice ✅ real YES — my conflict resolution fixed
2 ls silently deletes symlinks pointing at ./.. ✅ real no — 0.42.1 identical fixed
3 read -n renumbers relative to filtered content ✅ real no — 0.42.1 identical flagged, not fixed
4 wc mixed mode eats a numeric leading filename token ✅ real no — 0.42.1 identical fixed
5 search.rs grep-fidelity gaps (--, --regexp=, -f) upstream's no flagged upstream

Finding 1 was a genuine regression in this merge and the most valuable catch. The xfail rendering
block was duplicated verbatim during conflict resolution — both parents contain exactly one copy
(5a7880d=1, 5787829=1), the merge commit contained two — so every pytest run with an XFAIL/XPASS
summary printed each outcome twice. 2362 passing tests and a fully green CI both missed it,
because the existing assertion used .contains, which cannot detect duplication. The test now
asserts exact match counts.

Finding 4 initially did not reproduce for me; my first attempt used a path-prefixed filename
(wctest/123 report.txt), which changes the tokenization. With the bare name the bug is real:
rtk wc -lw "123 report.txt" printed 2 2 123 instead of 2 2. Retesting rather than trusting my
first negative result is what caught it.

Not fixed here, deliberately:

  • Finding 3 (read -n under a filter level that drops lines: --tail-lines 2 on a 4-line file
    labels lines 3–4 as 2–3). Real and confirmed pre-existing in 0.42.1, so not a sync regression.
    A correct fix requires threading a line map through the filter pipeline so filtered output can be
    attributed back to true file offsets — a design change that does not belong in a sync PR and needs
    its own tests. Reproduction is recorded above; worth a follow-up issue.
  • Finding 5 is upstream v0.43.0's, not part of the carry diff.

Reviewer note: codex was explicitly forbidden from building or running tests on this host, so its
verification is static-analysis only and it could not confirm the test counts or the rustc-1.97
claim itself.

Hook-rewrite behaviour change (investigated on request — matters on tron)

rtk is wired as a Claude Code hook on this host, so it rewrites every agent Bash command. A
coordinator reported live command mangling on pre-0.43 and flagged this PR as a rewrite-regression
risk, so I probed the installed 0.42.1 against this build directly (rtk rewrite and the real
rtk hook claude JSON path, plus a fake-binary argv probe). Result: v0.43.0 is strictly safer
here, and this PR does not change the rewriter itself
— src/discover/registry.rs was not a
conflicted file; the improvement is upstream's.

  • Rewrite decisions are byte-identical between 0.42.1 and 0.43.0 for plain commands,
    compound &&, ;, pipes, env prefixes, quoted args, heredocs and nested quotes.
  • Upstream added discover::lexer::contains_unattestable_construct (its tests are tagged cve):
    a command containing command substitution ($(…), backticks, <(/>() or a redirect with a
    file target
    is now passed through unrewritten instead of being rewritten. So
    git diff > out.diff went from rtk git diff > out.diff (the file receives compressed bytes)
    to no rewrite at all. This eliminates a silent file-corruption class — I hit it in this very task:
    a redirected git diff produced a 24,458-byte file where the real diff is 158,724 bytes.
    fd-dup 2>&1 correctly still rewrites.
  • Quoting is not corrupted by the rewriter in either version; argv survives intact
    (<app in (a, b)>, <fix: a b c>).

The command-substitution half of that guard fixes a confirmed real-world failure, independently
reproduced on this host by another agent after the rollout. On 0.42.1:

POD=$(microk8s kubectl get pods -n <ns> --no-headers | grep '^hd-api' | awk '{print $1}' | head -1)
# 0.42.1 -> POD is EMPTY; the same pipeline run directly prints the pod fine
# 0.43.0 -> POD=hd-api-7d6ff56b49-4pvbb

rtk rewrote the pipeline inside $( … ), so grep/awk were fed the compressed stream, matched
nothing, and the variable came back empty — after which the next command failed with an unrelated-
looking usage error. No error was ever surfaced for the actual cause. 0.43.0 passes the whole
substitution through untouched. This is the same silent-wrong-value class as the redirect case, via
a different path.

Still exposed after this upgrade (pre-existing, not introduced here): piped stdout is still
rewritten, so the pipe carries the compressed stream — git diff | wc -c reports 22,340 bytes
against 125,599 real (17%), and | tee file writes those compressed bytes to disk. This is now the
main residual risk of this class: it fails silently with a plausible-looking wrong value rather than
an error. Worth a follow-up upstream; out of scope for a sync PR.

One non-fork-specific fix carried in this PR

cargo test failed on constant FILTERS_TOML is never used and associated function load is never used, denied by [lints.rust] warnings = "deny". Verified reproducible on pristine upstream v0.43.0 in a separate worktree — it is pre-existing, caused by rustc 1.97.0 (2026-07-07) tightening dead-code analysis after upstream's last green CI run (2026-06-28). Both items are live in production via the REGISTRY singleton but invisible to the bin's --test dead-code roots (the harness replaces main). Fixed with a targeted #[cfg_attr(test, allow(dead_code))] and an explanatory comment on each, rather than by weakening the lint config.


Conflicts resolved by hand (16)

File Resolution
src/main.rs keep both JVM import blocks; drop our Mvn { command } variant, MvnCommands enum and routing arm; keep upstream's Commands::Mvn { args } wiring; add gradle/ant to the test PASSTHROUGH const (they wrap real binaries)
src/discover/rules.rs take upstream wholesale (richer mvn pattern), then re-append our rtk ant rule — a post-resolution grep caught that taking upstream silently dropped it
src/cmds/jvm/mvn_cmd.rs upstream's module
src/filters/mvn-build.toml deleted (superseded)
src/cmds/system/grep_cmd.rs deleted (upstream renamed to search.rs)
src/cmds/system/read.rs upstream's file + our line-offset fix re-applied at both run and run_stdin
src/cmds/system/ls.rs upstream's rewritten file + our is_dotdir fix and 3 tests re-applied against the new signature
src/core/toml_filter.rs filter-count assertions 63 → 64/65 (upstream built-ins + our ant.toml); dead-code annotation
src/core/constants.rs dead-code annotation
.github/workflows/cd.yml, release.yml, pr-target-check.yml ours at every conflict (App token + GITHUB_TOKEN fallback, pull-requests: write, no Discord/Homebrew); YAML validated
README.md murphytek URLs kept; adopted upstream's Apache-2.0 badge — LICENSE here has been Apache 2.0 all along, our MIT badge was simply stale; took upstream's Pi-agent / 14-tools additions
CHANGELOG.md rebuilt as a union: header + our fork-only 0.42.1 block + upstream's full body from 0.43.0 down
Cargo.toml, .release-please-manifest.json 0.43.0
Cargo.lock upstream's, regenerated by the build
tests/jvm_filter_integration.rs, tests/common/mod.rs, tests/fixtures/jvm/mvn_* Maven sections pruned (see above)

Test results

Gate Result
cargo fmt --all --check clean
cargo clippy --all-targets clean, no warnings
cargo test 2367 passed, 0 failed, 8 ignored (8 suites)
cargo build --release ok → rtk 0.43.0
test_injection_disabled_truth_table passes (new)
tests/jvm_filter_integration.rs 6 passed (3 gradle + 3 ant)

Binary smoke test on the release build:

rtk --version   → rtk 0.43.0
rtk gain        → renders global savings table
rtk git status  → * chore/sync-upstream-v0.43.0 / clean — nothing to commit
rtk ls          → compact directory listing
rtk grep        → matches real grep byte-for-byte, incl. bare `|` as a literal

scripts/test-all.sh — 0 regressions

scripts/test-all.sh does not run clean on this host, so rather than report a bare failure count I built pristine upstream v0.43.0 in a separate worktree and ran the same script against it for a baseline:

passed failed skipped
this branch 101 14 7
pristine upstream v0.43.0 100 15 7

Set difference: zero failures are unique to this branch. All 14 reproduce on unmodified upstream; upstream additionally fails rtk cargo test. The failures are environmental, not functional — network-dependent checks (curl/wget against httpbin, cc-economics fetching ccusage via npx), pnpm needing a package.json, and a cluster of rewrite/-u assertions where the harness compares exact strings but rtk prepends [rtk] WARNING: untrusted project filters (.rtk/filters.toml) in a fresh clone (note several of them read expected: 'rtk git status' / got: rtk git status).

aeppling and others added 30 commits May 13, 2026 15:42
…tmp-lock-workflow

fix(security): replace insecure tmp, lock git perm, set sha for actions
…master--components--rtk

chore(master): release 0.40.0
fix(install): reject archive with path traversal before extraction (rtk-ai#1250)
fix(git): preserve full status paths and untracked files
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(docker): forward --tail flag in compose logs
…iltering

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.
## 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>
- 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
Co-authored-by: Cursor <cursoragent@cursor.com>
fix(kubectl): compact get pods and services aliases
fix(git): stream push output to avoid spurious 30s timeout (rtk-ai#963)
Replaces the stateless src/filters/mvn-build.toml (4 phases, 50-line cap) with
a Rust module under src/cmds/jvm/mvn_cmd.rs handling all common Maven lifecycle
phases with stateful Surefire/Failsafe block collapse.

Why TOML couldn't do this: the dominant noise on a healthy Maven project is
expected-exception stack traces inside passing tests (assertThrows). Collapsing
these requires deciding to drop a block based on its closing
`Tests run: N, Failures: 0, Errors: 0` line — a stateful decision the TOML DSL
cannot express.

Measured savings on synthetic full-shape fixtures (~1100 lines each, gzipped):
- mvn test:    3 422 tok → 36 tok (98.9% savings)
- mvn install: 3 460 tok → 85 tok (97.5% savings)

Coverage:

| Phase                              | Filter                                 |
|------------------------------------|----------------------------------------|
| test, integration-test             | filter_surefire (block collapse)       |
| compile, test-compile              | filter_compile (ERROR + indent + dedup)|
| package, install, verify, deploy   | filter_package (compile + surefire)    |
| clean, site, plugin goals, version | passthrough                            |

Key behaviours:
- ANSI strip first in every filter (real Maven output contains colour escapes).
- English-footer guard: if no `BUILD SUCCESS`/`BUILD FAILURE` line is present,
  return ANSI-stripped raw input unchanged — protects non-English locales.
- Verbose bypass: `-X`, `--debug`, `-e`, `--errors` skip filtering.
- Stack-frame deny-list strips framework frames (`at org.junit.`, `at java.util.`,
  `at sun.reflect.`, etc.); user-code frames (any other prefix) preserved.
- Duration normalisation (`Time elapsed: 2.341 s` → `Time elapsed: T s`) for
  deterministic test output.
- Wrapper detection: `./mvnw` / `mvnw.cmd` via string-literal `Command::new`
  (semgrep-safe); falls back to `resolved_command("mvn")`.

Hook regex changes (src/discover/rules.rs):
- Adds wrapper prefixes (./mvnw, mvnw.cmd, mvnw).
- Adds test, integration-test, verify, deploy to the alternation.
- Drops clean + site so bare invocations bypass RTK entirely (0 overhead).
- Lazy quantifier skips flags before the goal (`mvn -B clean install` now
  rewrites correctly; previously failed because the regex required the goal
  as the first token after `mvn`).
- Drops subcmd_savings (lazy match captures first phase, which would mis-tier
  `clean install` to clean); uses flat 82.0.

Tests:
- 33 unit tests in mvn_cmd.rs (phase detection, footer guard, framework deny,
  duration normalisation, ERROR continuation, WARNING dedup, install/jar lines).
- 2 inline savings assertions on gzipped synthetic full fixtures (~3 KB each)
  using flate2 already in Cargo.toml. Run as part of standard `cargo test --all`.
- 12 classifier/rewrite tests in src/discover/registry.rs under new Maven
  section.

Files changed:
- ADD src/cmds/jvm/mvn_cmd.rs (~810 LoC incl. tests)
- ADD src/cmds/jvm/README.md (documents whitelist omission decision)
- ADD tests/fixtures/mvn_*_raw.txt (6 inline) + 2 .gz synthetic full fixtures
- MOD src/main.rs (1 use, 1 Commands variant, 1 dispatch arm)
- MOD src/discover/rules.rs (replace mvn entry)
- MOD src/discover/registry.rs (12 classifier tests)
- MOD src/core/toml_filter.rs (drop mvn-build from expected-filters list,
  adjust the 2 count assertions)
- DEL src/filters/mvn-build.toml

Fixtures are entirely synthetic — generic `com.example.app.*` package names and
`com.example:myapp` Maven coordinates. Same SHAPE as real Maven output (block
structure, ANSI codes, framework stack frames, BUILD footer, plugin banners)
without any project-identifying content.

Integrity-check whitelist: Commands::Mvn is intentionally omitted from
is_operational_command at src/main.rs:2455-2501, matching the gradle precedent
(Commands::Gradlew also omitted). The whitelist is opt-in by design per the
comment at L2452-2454 — filter modules invoked through an already-verified
hook do not need a second integrity check on their own dispatch path.
Documented in src/cmds/jvm/README.md.

Out-of-scope (follow-ups noted in module + README):
- Parallel mode `-T2C` (interleaved blocks across threads).
- Plugin goals (`mvn dependency:tree`, `mvn versions:*`).
- `mvnw.bat` legacy wrapper (Maven Wrapper 3.x emits `.cmd`).

BREAKING CHANGE: `rtk mvn <args>` output format changed. Previously: TOML
filter strips INFO/Downloading lines and caps at 50 lines. Now: state-machine
filter with Surefire block collapse + locale guard + verbose bypass. Different
output shape; significantly better savings tier; behaviour is otherwise a
superset (all previously-handled cases still handled, plus test/verify/etc.).
- 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
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>
hgunduzoglu and others added 20 commits June 26, 2026 11:35
Per review (rtk-ai#2498): self-explanatory guard; remove comment to avoid noise.
…t-exit-code

fix(git): propagate exit code on git status failure in compact path
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 (rtk-ai#2497) can't creep back.
…ow-exit-code

test(git): cover exit-code propagation for git stash list/show failure
…success

fix(git): propagate exit code when commit fails instead of reporting ok
…-exit-code

fix(git): propagate exit code on git worktree list failure
- grep runs grep, rg runs rg: drop the substitution, forced --no-ignore-vcs, and BRE-to-rg translation
- add `rtk rg` command (native ripgrep, sharing the same output filter)
- split rewrite rule: grep to rtk grep, rg to rtk rg
- record the agent's real command in tracking (was synthesized as "grep -rn")
- emit nothing on a clean no-match (never-worse parity with the shared guard)
- rename grep_cmd.rs to search.rs, now hosting both engines
- cover engine faithfulness, ignore semantics, and rg savings with issue-referenced tests
- benchmark the grep and rg paths
- line number always (the openable position); filename only when grep/rg prints one (multi-file, dir, -r, -H)
- single file and stdin equal `grep -n` byte-for-byte: no synthetic filename, header, or lossy truncation
- read piped stdin instead of injecting `.`; rg no longer searches the cwd on a pipe
- pattern-less and format-flag commands run verbatim (rg --type-list, --files, grep -c/-o)
- grouped/capped form only when capping actually shrinks the output
- byte-for-byte tests vs grep -n across flags, pipes and edge cases (incl rtk-ai#1436)
- leading ^ anchor must stay scoped to the path (tenequm)
- line ending in `:` keeps full content (BTCAlchemist)
- rg surfaces a regex parse error as exit 2, not a silent 0 (jhagberg)
- grep_compress_test.rs -> search_compress_test.rs (tests the shared grep/rg filter)
- binary match skipped as noise by default, -a opts back in
- fix parse_flags doc: -I is an intentional binary skip, not a no-op
- drop the synthetic "search failed with exit code N" line (an rtk addition)
- surface the engine stderr verbatim in every path, incl. partial match + error
- remove the now-vestigial is_grep_error_exit (the "0 matches" it guarded is gone)
- error/exit matrix tests vs real grep/rg (rtk-ai#2465: an error is never a silent no-match)
refacto(search): run the invoked engine instead of substituting rg for grep
…master--components--rtk

chore(master): release 0.43.0
Merge upstream/master (381 commits, v0.42.0 -> v0.43.0) into murphytek/rtk.

Local carry KEPT (verified absent upstream, per-fix):
- fix(ls): trailing-dot dirs no longer treated as . / ..  (is_dotdir)
- fix(read): --tail-lines keeps true file offset in the gutter
- fix(wc): filenames containing spaces
- fix(tree): summary-line detection
- fix(find): UTF-8 safe directory abbreviation
- fix(log): char-safe commit message truncation
- fix(gain): char-safe truncation
- feat(jvm): `rtk gradle` + `rtk ant` commands, gradle.toml / ant.toml filters
- feat: line_dedup / stack_dedup / stack_trim filter primitives
- feat: RTK_NO_INJECT_FLAGS kill switch (regression test added)
- ci: GitHub App token with GITHUB_TOKEN fallback; no Discord/Homebrew jobs
- docs: murphytek fork URLs in README

Local carry DROPPED (superseded upstream, verified):
- fix(grep): bare `|` literal handling — upstream rewrote grep_cmd.rs into
  search.rs, which runs the real grep verbatim; pinned by upstream's
  tests/search_faithful_test.rs.
- feat(mvn): murphytek mvn-build.toml filter + `rtk mvn <subcommand>` CLI —
  upstream 6c4950e replaced it with a maintained Rust module covering the
  full Maven lifecycle. BEHAVIOR CHANGE: `rtk mvn build` alias is gone
  (goals now pass through), and RTK_NO_INJECT_FLAGS no longer applies to mvn.
  The fork's mvn integration tests re-implemented the filter in
  tests/common/mod.rs rather than calling production code, so they were
  vacuous after the swap and have been removed along with their fixtures.

Also carries a small fix that is NOT fork-specific: rustc 1.97 tightened
dead-code analysis, so `cargo test` now denies core::constants::FILTERS_TOML
and TomlFilterRegistry::load as unused in the bin's --test build. Verified
reproducible on pristine upstream v0.43.0; annotated with
#[cfg_attr(test, allow(dead_code))].

Tests: cargo fmt --check clean, cargo clippy --all-targets clean,
cargo test 2362 passed / 0 failed (8 suites), cargo build --release ok.
@github-actions

Copy link
Copy Markdown

Automatic message from CI checks : It seems like this branch is targeting the wrong branch, any contribution should target develop branch.

See CONTRIBUTING.md for details.

@ryanmurf

Copy link
Copy Markdown
Author

Advisory review: hook rewrite path (automated review — not a merge gate)

Context: on this fleet rtk is wired into Claude Code as the PreToolUse hook (rtk hook claude in settings.json), so every Bash command from every agent flows through rewrite_command. The PR's cargo test/clippy evidence is unit-level; this review focused specifically on whether the sync changes hook/rewrite behavior vs. the deployed 0.42.1. I built this branch's binary and diffed it empirically against the deployed one.

1. The rewrite path IS heavily touched — but cleanly, and it got safer

Upstream changes landing via this sync: src/hooks/hook_cmd.rs (~645 changed lines), rewrite_cmd.rs, permissions.rs (+312), new src/discover/lexer.rs module (+274), registry.rs (+289). Two behavior-relevant additions:

  • contains_unattestable_construct gate (lexer.rs): commands containing command/process substitution (`, $(, <() or a file-target redirect now pass through un-rewritten (fd-dups like 2>&1 and /dev/null exempt). Deployed 0.42.1 rewrites these. This is upstream security hardening; it trades a little token savings for not touching complex commands. Wired into both rtk rewrite (evaluate) and the deployed-here rtk hook claude path (decide_from_verdict) — verified in source on this branch.
  • Bash line-continuation collapse (upstream Hook matcher: leading backslash-newline defeats command rewrite rtk-ai/rtk#1564) in rewrite_command.

Critically, rewrite_compound — the segment re-serializer — is byte-identical between master and this branch (extracted both and diffed).

2. Empirical diff: branch binary vs deployed 0.42.1

Built target/release/rtk (0.43.0) from this branch and fed identical inputs to both binaries:

  • 30-command battery via rtk rewrite (git/gh/cargo/grep/find/pipes/compounds/quoted strings/bracket patterns/2>&1): zero divergence in output or exit codes.
  • PreToolUse JSON battery via rtk hook claude: identical except two intentional changes — git log --oneline > /tmp/out.txt and git status $(echo x) now pass through untouched (deployed rewrites them). Both are the new gate working as designed.
  • Heredoc payloads: passthrough on both.
  • command git status → command rtk git status on both binaries — command is a transparent prefix on both, so no regression here, but note the fleet's command git convention is not actually a rewrite bypass for simple commands on either version.

3. The live quoting-corruption bug: reproduces identically on BOTH — pre-existing, not from this PR

Observed in live sessions on 2026-07-24 (deployed 0.42.1): quoted case statements get mangled. Reproducer, via rtk hook claude:

IN : PAT='x -p'; c="hello x -p"; case "$c" in *"$PAT"*|*"x -p"*) echo match;; *) echo no;; esac; git status
OUT: PAT='x -p'; c="hello x -p"; case "$c" in *"$PAT"* |*"x -p"*) echo match; ; *) echo no; ; esac; rtk git status

Two corruptions: the | inside the case pattern is treated as a shell pipe (stray space injected), and ;; is re-serialized as ; ; → syntax error near unexpected token ';'. Byte-identical output from deployed 0.42.1 and this branch. Mechanism: rewrite_compound tokenizes with a shell-naive lexer (no case/esac keyword awareness), trims segments, and re-joins with normalized spacing; the corrupted whole string is emitted whenever any segment rewrites (here the trailing git status). The new unattestable-construct gate does not catch this class (no substitution/redirect present).

So: this PR neither fixes nor worsens the corruption — it is inherited from upstream and unchanged. Not a blocker for the sync, but it remains live after merge.

4. Conflict resolutions vs the rewrite path

None of the 16 hand-resolved files are in the core rewrite path (registry.rs, lexer.rs, hook_cmd.rs, rewrite_cmd.rs, permissions.rs all came in clean from upstream). Verified: the fork has zero local commits touching src/hooks/ or src/discover/ since the last sync (git log 152f4e3..master -- src/hooks src/discover is empty), so no local rewrite-path customization existed to be dropped. Closest touched files are main.rs (routing) and discover/rules.rs (discover suggestions; the rtk ant rule re-append is accounted for in the PR body).

5. Coverage gap + suggested follow-ups

Current hook coverage: run_claude_inner unit tests (full PreToolUse JSON through the real processing fn, in-process) + ~10 simple rtk rewrite assertions in scripts/test-all.sh. Nothing exercises the corruption class (case/;;/|-in-glob) and nothing invokes rtk hook claude the way settings.json actually does.

Suggested (advisory):

  1. Pre-deploy smoke (essentially what this review ran): feed a battery of representative commands — quoted case statement, command git, bracketed grep patterns, heredoc, pipes, && compounds — through both the deployed binary and the new one via rtk hook claude JSON, and diff. Expected result for this PR: identical except substitution/file-redirect passthroughs.
  2. Fork carry candidate (or upstream PR): make rewrite_command bail early on shell keywords it can't re-serialize — e.g. treat a ;; token or case /esac as unattestable, alongside the existing has_heredoc early-out. That kills the observed fleet corruption class at the gate for the cost of a few lost rewrites. A regression test pinning rewrite_command(...case...;;...esac...) == None would prevent reintroduction.

Verdict

Merge risk to the hook path: LOW. Empirically byte-identical to deployed on everything tested except two intentional safety passthroughs; the one known corruption bug predates the PR and is unchanged; conflict resolutions don't touch the rewrite core; fork carries (gradle/ant/RTK_NO_INJECT_FLAGS) verified present in the built binary. The follow-ups above are about the pre-existing bug, not this sync.

@github-actions

Copy link
Copy Markdown

Automatic message from CI checks : It seems like this branch is targeting the wrong branch, any contribution should target develop branch.

See CONTRIBUTING.md for details.

Three confirmed defects, each reproduced against the built binary before and
after the fix. One is a regression this merge introduced; two are latent bugs
in fork carry fixes that this merge re-applied.

1. pytest: xfail/xpass block emitted twice (MERGE REGRESSION)
   The rendering block was duplicated verbatim during conflict resolution.
   Proof it came from the merge: both parents contain exactly one copy
   (5a7880d=1, 5787829=1), the merge commit contained two. Any pytest run with
   an XFAIL/XPASS summary printed the heading and every outcome twice. The
   existing test used `.contains`, which cannot see a duplicate, so 2362 green
   tests and a green CI both missed it. Now asserted with exact match counts.

2. ls: symlinks pointing at `.` or `..` were silently deleted
   `is_dotdir` compared the last whitespace token, but `ls -l` renders a symlink
   as `<name> -> <target>`, so for `current -> .` the last token is the target.
   Both `current -> .` and `parent -> ..` vanished from `rtk ls -la` output.
   The arrow suffix is now stripped before the comparison. Pre-existing in
   0.42.1, not introduced here.

3. wc: single-file mixed mode swallowed a numeric leading filename token
   `WcMode::Mixed` discarded how many count columns were requested and peeled up
   to 4, so `wc -lw "123 report.txt"` (raw `2 2 123 report.txt`) printed
   `2 2 123` instead of `2 2`. Mixed now carries the exact flag count.
   Pre-existing in 0.42.1, not introduced here.

Regression tests added for all three, including the exact reproductions.

Reported but NOT fixed here, with reasons (see PR body):
- read.rs `-n` renumbers relative to filtered content, so a tail window under
  `--level minimal` mislabels lines. Confirmed real and confirmed pre-existing
  in 0.42.1. A correct fix needs a line map threaded through the filter
  pipeline — a design change that does not belong in a sync PR.
- search.rs grep-fidelity gaps (`--`, `--regexp=`, `-f`) are upstream v0.43.0
  defects, not carry-diff additions.

Tests: fmt clean, clippy clean, 2367 passed / 0 failed (was 2362, +5).
@github-actions

Copy link
Copy Markdown

Automatic message from CI checks : It seems like this branch is targeting the wrong branch, any contribution should target develop branch.

See CONTRIBUTING.md for details.

@ryanmurf
ryanmurf merged commit d94c333 into master Jul 25, 2026
17 checks passed
@ryanmurf
ryanmurf deleted the chore/sync-upstream-v0.43.0 branch July 25, 2026 00:36
@github-actions

Copy link
Copy Markdown

Automatic message from CI checks : It seems like this branch is targeting the wrong branch, any contribution should target develop branch.

See CONTRIBUTING.md for details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.