Skip to content

feat: binary hook engine with lexer, streaming, and rewrite_compound integration#536

Open
ahundt wants to merge 294 commits intortk-ai:developfrom
ahundt:feat/rust-hooks-v2-develop
Open

feat: binary hook engine with lexer, streaming, and rewrite_compound integration#536
ahundt wants to merge 294 commits intortk-ai:developfrom
ahundt:feat/rust-hooks-v2-develop

Conversation

@ahundt
Copy link

@ahundt ahundt commented Mar 12, 2026

Summary

This PR #536 integrates the hooks-v2 engine (from PR #156) with the develop branch (note that #537 is the same code as 536 and 156 but it is stripped of tests for easier reviewing), and #361 describes the bug fixes in this pr, this pr #536 demonstrates that:

  1. The lexer is a drop-in replacement for rewrite_compound()'s inline byte scanner — all 155 existing rewrite tests pass unchanged
  2. The binary hook path (rtk hook claude) works alongside the shell hook path (rtk rewrite)
  3. The streaming infrastructure (stream.rs) enables bidirectional process shims with exit code transparency

Key components

  • src/cmd/lexer.rs — Shell-aware tokenizer (56 tests): handles quoting, escapes, $(), backticks, globs, redirects, 2>&1
  • src/cmd/analysis.rs — Command chain parser (61+ tests): needs_shell() detection, parse_chain() for &&/||/; chains
  • src/cmd/hook/mod.rs — Binary hook engine (98 tests): conservative hook_lookup() whitelist, Claude Code JSON protocol, safe suffix handling
  • src/cmd/exec.rs — Native command executor: runs simple chains natively, delegates complex shell to /bin/sh
  • src/stream.rs — Streaming process execution (39 tests): StreamFilter trait, StdinMode::Inherit for pipe support, SIGPIPE handling, 1 MiB raw cap
  • src/pipe_cmd.rsrtk pipe --filter dispatch for grep/rg/find/fd output filtering
  • src/discover/registry.rsrewrite_compound() replaced: lexer-based splitting instead of 130-line inline byte scanner

Lexer integration in rewrite_compound()

The byte-level quote tracker in rewrite_compound() (~130 lines) is replaced with lexer::tokenize() calls (~80 lines). The lexer adds:

  • Escape sequence handling (\\)
  • $() and backtick detection (Shellism tokens)
  • Glob detection (*, ? → Shellism)
  • Redirect parsing — not confused with && operator (2>&1, &>/dev/null)

Token byte offsets (ParsedToken.offset) enable extracting original substrings from the command string, so rewrite_segment() receives exact original text — no reconstruction fidelity issues.

Binary hook architecture

Two complementary routing paths:

  • Shell hook: rtk rewriteregistry::rewrite_command()rewrite_compound()rewrite_segment() (TOML filters + RULES table)
  • Binary hook: rtk hook claudecheck_for_hook()lexer::tokenize()analysis::parse_chain()hook_lookup()route_native_command() (conservative whitelist)

The binary hook uses a strict whitelist (hook_lookup()) that only routes subcommands RTK optimizes well (e.g., git status but not git rebase, cargo test but not cargo publish).

Init system (src/init.rs)

  • --hook-type binary|script flag to select hook mode
  • Plugin cache patching: removes Bash from plugin matchers, writes manifest
  • Manifest-based handler dispatch for both NoOpinion and Allow paths
  • backup_file_once() + atomic_write() for safe file operations
  • OpenCode plugin support (develop's --install-opencode flag preserved)

Test plan

  • cargo test — 1309 passed, 0 failed, 6 ignored
  • cargo fmt --all — clean
  • cargo clippy --all-targets — clean
  • All 155 registry rewrite tests pass (including develop's TOML rule tests)
  • All 56 lexer tests pass
  • All 98 hook tests pass
  • All 39 streaming tests pass
  • Manual: rtk rewrite "cargo test && git status" produces rtk cargo test && rtk git status
  • Manual: rtk rewrite "cargo test | grep FAIL" produces rtk cargo test | grep FAIL
  • Manual: rtk rewrite "cargo test 2>&1" produces rtk cargo test 2>&1

Stats

46 files changed, ~9500 insertions, ~450 deletions

Fixes #222

pszymkowiak and others added 30 commits January 30, 2026 14:24
…s--master--components--rtk

chore(master): release 0.5.0
1. CRITICAL: Fix 'latest' tag creation after releases
   - Move update-latest-tag job from release.yml to release-please.yml
   - release-please creates tags via API (no push event) → must run in same workflow
   - Job now conditional on release_created output

2. IMPORTANT: Add npx fallback for ccusage + improve message
   - Check binary in PATH first, fallback to 'npx ccusage'
   - Updated message: "npm i -g ccusage (or use npx ccusage)"
   - Consistent with other JS tooling (next_cmd, tsc_cmd, prettier_cmd)

3. PROCESS: Slow down version bumps with release-please config
   - Add release-please-config.json with bump-patch-for-minor-pre-major
   - In 0.x versions: feat: → patch bump instead of minor
   - Prevents rapid version inflation (0.3.1 → 0.5.0 in 21h)

Fixes issues raised by Patrick after PR rtk-ai#21 merge.

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
fix: 3 issues (latest tag, ccusage fallback, versioning)
…s--master--components--rtk

chore(master): release 0.5.1
Patrick reported 2 critical issues post-merge PR rtk-ai#23:

1. **release.yml never triggers**: release-please creates tags via GitHub API
   → no push event generated → build workflow never runs
   → v0.5.1 released without binaries

2. **README install URLs 404**: DEB/RPM URLs hardcode version 0.3.1
   → /releases/latest/download/ serves different filenames
   → all releases > 0.3.1 break installation instructions

Root cause analysis:
- release-please creates GitHub Releases (triggers `release.published` event)
- release.yml only listens to `on: push: tags` (doesn't fire for API-created tags)
- Standard pattern: release-please + binary builds = `on: release.published`

Fixes:
1. release.yml trigger:
   - Add `on: release: types: [published]` (standard release-please pattern)
   - Remove `on: push: tags: ['v*']` (dead code with release-please)
   - Update version extraction to handle `release` event
   - Split release job: upload assets (release event) vs create release (workflow_dispatch)

2. Version-agnostic package naming:
   - Create copies: rtk_0.5.0-1_amd64.deb → rtk_amd64.deb
   - Create copies: rtk-0.5.0-1.x86_64.rpm → rtk.x86_64.rpm
   - Update README URLs to use version-agnostic names
   - /releases/latest/download/ now serves stable filenames

Impact:
- release-please releases now auto-trigger binary builds
- Installation URLs work for all future releases
- No manual workflow_dispatch needed for new versions

Manual action required:
Patrick needs to re-run build for v0.5.1 via workflow_dispatch
(or create v0.5.2 with a trivial fix commit)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
fix: release pipeline trigger and version-agnostic package URLs
…s--master--components--rtk

chore(master): release 0.5.2
- Make compact_diff pub(crate) in git.rs for cross-module use
- Extract filter_json_string() from json_cmd.rs for reuse
- Add ok_confirmation() to utils.rs for write operation confirmations
- Add detect_package_manager() and package_manager_exec() to utils.rs

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- cargo build: strip Compiling/Downloading lines, show errors + summary
- cargo test: show failures only + summary line
- cargo clippy: group warnings by lint rule with locations

New module: src/cargo_cmd.rs with 6 unit tests

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- git branch: compact listing (current/local/remote-only)
- git fetch: "ok fetched (N new refs)" confirmation
- git stash: list/show/pop/apply/drop with compact output
- git worktree: compact listing with home dir abbreviation

4 new tests in git.rs

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- gh pr create: capture URL + number, "ok created #N url"
- gh pr merge: "ok merged #N" confirmation
- gh pr diff: reuse compact_diff() for condensed output
- gh pr comment/edit: generic "ok {action} #N" confirmations
- gh api: auto-detect JSON, pipe through filter_json_string()

5 new tests in gh_cmd.rs

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- npm run: filter boilerplate (> script, npm WARN, progress)
- npx: intelligent routing to specialized filters
  (tsc, eslint, prisma, next, prettier, playwright)
- pnpm build: delegates to next_cmd filter
- pnpm typecheck: delegates to tsc_cmd filter
- --skip-env global flag: propagates SKIP_ENV_VALIDATION=1

New module: src/npm_cmd.rs with 2 unit tests

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Execute curl -s, auto-detect JSON responses
- JSON output piped through filter_json_string() for schema view
- Non-JSON output truncated to 30 lines with byte count

New module: src/curl_cmd.rs with 4 unit tests

Co-Authored-By: Claude Opus 4.5 <[email protected]>
feat: shared infrastructure for new commands
- Fix test_analyze_logs: use normalizable paths instead of distinct IPs
- Fix test_filter_outdated: match real pnpm outdated output format
- Fix test_filter_ansi_colors: add missing Tests line for stats parsing
- Add .claude/skills/rtk-tdd/ with Red-Green-Refactor workflow
- Add testing-patterns.md reference with untested modules backlog
- Update CLAUDE.md Testing Strategy with TDD mandate and pre-commit gate
- Add 17 tests to diff_cmd.rs (similarity, truncate, compute_diff, condense)
- Test suite: 102/105 → 122/122

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- New `rtk discover` command scans Claude Code JSONL session history to
  identify missed RTK savings and suggest unhandled commands for issues.
  Modular architecture: registry (RegexSet classification), provider
  (SessionProvider trait + ClaudeProvider), report (text/json formatting).

- New PreToolUse auto-rewrite hook transparently intercepts Bash commands
  and rewrites them to rtk equivalents before execution, ensuring 100%
  adoption across all conversations including subagents.

- New `rtk git show` command with compact output: one-line commit summary
  + stat + compacted diff (reuses compact_diff from git diff).

Co-Authored-By: Claude Opus 4.5 <[email protected]>
rtk git push and rtk git pull now accept trailing arguments and forward
them to git. Fixes the auto-rewrite hook failing on commands like
`git push -u origin feat/branch`.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
feat: discover command, auto-rewrite hook, git show
…s--master--components--rtk

chore(master): release 0.7.0
# Conflicts:
#	src/git.rs
#	src/grep_cmd.rs
ahundt added a commit to ahundt/rtk that referenced this pull request Mar 13, 2026
Address PR rtk-ai#536 review comments from KuSh:
- get_summary() delegates to get_summary_filtered(None), so the match
  on project_scope was unnecessary — call get_summary_filtered() directly
- Same simplification for get_recent_filtered()

src/gain.rs: 2 match blocks replaced with direct .as_deref() calls
@ahundt
Copy link
Author

ahundt commented Mar 13, 2026

@KuSh @pszymkowiak everything that is outstanding should be addressed including the comments above! There are also no conflicts with the base branch and it is ready to be merged w.r.t. git conflicts at the time of writing.

@ahundt ahundt requested a review from KuSh March 13, 2026 22:18
ahundt and others added 22 commits March 14, 2026 04:47
Previously split_safe_suffix only stripped one suffix per call, so
compound patterns like "cargo test 2>&1 | tail -50" would only strip
"| tail -50" leaving "2>&1" in the core, causing needs_shell to force
passthrough.

Now split_safe_suffix loops, stripping suffixes right-to-left until no
more match. Uses Vec::truncate for zero-allocation per iteration and
Vec<String> with reverse+join to preserve left-to-right suffix order.

Adds 6 TDD tests for compound suffix patterns:
- 2>&1 | tail -50 (the rtk-ai#1 missed compound pattern)
- > /dev/null 2>&1
- 2>&1 | tee /tmp/log
- >> /tmp/log 2>&1 | tail -5 (triple compound)
- | grep FAILED 2>&1 (unsafe pipe correctly NOT stripped)
- > /dev/null & (redirect + background)

All 67 analysis tests pass. All 1348 project tests pass.
Clap rejected grep flags like -A 5 before reaching trailing_var_arg.
Add after_context, before_context, grep_context, ignore_case, and
word_regexp as named Clap args. Convert to extra_args at dispatch
site — no changes to grep_cmd.rs function signature.

Includes 3 TDD tests verifying Clap accepts the new flags.
Both subcommands have dedicated handlers in git.rs with write-detection,
compact output, and exit code propagation. Adding to hook_lookup routes
them through RTK filters instead of raw passthrough.

Includes 4 TDD tests verifying lookup and end-to-end routing.
Remove after_context, before_context, grep_context Clap args and their
dispatch logic. These flags correctly reached rg but RTK's output parser
at grep_cmd.rs:77-88 uses splitn(3, ':') which misparses rg context
lines (dash-separated format) as filenames, producing garbled output.

Keep working -i (ignore-case) and -w (word-regexp) flags which only
affect matching, not output format.

Discovered via post-implementation audit: rtk grep -A 2 "fn run_branch"
src/git.rs showed context lines misidentified as separate files.
filter_branch_output() hardcoded "remotes/origin/" prefix check at
git.rs:1111, causing branches from other remotes (upstream, fork, etc.)
to be dumped verbatim into the local section. On multi-remote repos
this yielded only 2.7% savings instead of expected 40-70%.

Fix: match any "remotes/*/" prefix using strip_prefix + find('/').
Deduplicate across remotes using HashSet before filtering against
local branches.

Add TDD tests: multi-remote correctness (3 remotes, dedup, HEAD skip)
and multi-remote savings assertion (>=40% on 3x9 remote branches).
* fix: P1 exit codes, grep regex perf, SQLite concurrency

Exit code propagation (same pattern as existing modules):
- wget_cmd: run() and run_stdout() now exit on failure
- container: docker_logs, kubectl_pods/services/logs now check
  status before parsing JSON (was showing "No pods found" on error)
- pnpm_cmd: replace bail!() with eprint + process::exit in
  run_list and run_install

Performance:
- grep_cmd: compile context regex once before loop instead of
  per-line in clean_line() (was N compilations per grep call)

Data integrity:
- tracking: add PRAGMA journal_mode=WAL and busy_timeout=5000
  to prevent SQLite corruption with concurrent Claude Code instances

Signed-off-by: Patrick <[email protected]>
Signed-off-by: Patrick szymkowiak <[email protected]>

* fix: address review findings on P1 fixes

- tracking: WAL pragma non-fatal (NFS/read-only compat)
- wget: forward raw stderr on failure, track raw==raw (no fake savings)
- container: remove stderr shadow in docker_logs, add empty-stderr
  guard on all 4 new exit code paths for consistency with prisma pattern

Signed-off-by: Patrick <[email protected]>
Signed-off-by: Patrick szymkowiak <[email protected]>

---------

Signed-off-by: Patrick <[email protected]>
Signed-off-by: Patrick szymkowiak <[email protected]>
… (rtk-ai#630)

* fix: raise output caps for grep, git status, and parser fallback (rtk-ai#617, rtk-ai#618, rtk-ai#620)

- grep: per-file match cap 10 → 25, global max 50 → 200
- git status: file list caps 5/5/3 → 15/15/10
- parser fallback: truncate 500 → 2000 chars across all modules

These P0 bugs caused LLM retry loops when RTK returned less signal
than the raw command, making RTK worse than not using it.

Fixes rtk-ai#617, rtk-ai#618, rtk-ai#620

Signed-off-by: Patrick <[email protected]>
Signed-off-by: Patrick szymkowiak <[email protected]>

* fix: update README example and add truncation tests for modified/untracked

- parser/README.md: update example from 500 → 2000 to match code
- git.rs: add test_format_status_modified_truncation (cap 15)
- git.rs: add test_format_status_untracked_truncation (cap 10)

Signed-off-by: Patrick <[email protected]>
Signed-off-by: Patrick szymkowiak <[email protected]>

* refactor: extract output caps into [limits] config section

Move hardcoded caps into config.toml so users can tune them:

  [limits]
  grep_max_results = 200      # global grep match limit
  grep_max_per_file = 25      # per-file match limit
  status_max_files = 15       # staged/modified file list cap
  status_max_untracked = 10   # untracked file list cap
  passthrough_max_chars = 2000 # parser fallback truncation

All 8 modules now read from config::limits() instead of hardcoded
values. Defaults unchanged from previous commit.

Signed-off-by: Patrick <[email protected]>
Signed-off-by: Patrick szymkowiak <[email protected]>

---------

Signed-off-by: Patrick <[email protected]>
Signed-off-by: Patrick szymkowiak <[email protected]>
…es (rtk-ai#662)

* feat(.claude): add /rtk-triage skill — orchestrated PR+issue cross-analysis

New skill that runs issue-triage + pr-triage in parallel then produces
a cross-analysis layer that neither skill can do individually:

- Double coverage detection: identifies when 2+ PRs target the same issue
  (via body scan + file overlap), recommends which to keep/close
- Security gap detection: for security review issues, maps each finding
  to a PR (or flags it as uncovered)
- P0/P1 bugs without PR: groups by pattern to suggest sprint batching
- Our dirty PRs: identifies probable cause (conflict with sibling PR,
  needs rebase, missing linked issue)

Output is saved automatically to claudedocs/RTK-YYYY-MM-DD.md.

Usage: /rtk-triage           (French, auto-save)
       /rtk-triage en        (English output)

Signed-off-by: Florian Bruniaux <[email protected]>
Signed-off-by: Florian BRUNIAUX <[email protected]>

* docs(architecture): update module count to 66

Sync ARCHITECTURE.md with current main.rs state.
Previous count (60) was stale since several modules were added
(dotnet_cmd, dotnet_format_report, dotnet_trx, npm_cmd, gt_cmd, etc.).

Signed-off-by: Florian Bruniaux <[email protected]>
Signed-off-by: Florian BRUNIAUX <[email protected]>

---------

Signed-off-by: Florian Bruniaux <[email protected]>
Signed-off-by: Florian BRUNIAUX <[email protected]>
…tk-ai#601)

- git stash: pass unknown subcommands (save, branch, clear) through
  instead of silently falling back to git stash push
- git branch: add --show-current, --set-upstream-to, --format, --sort
  to flag detection so they don't get overridden by -a injection
- pip: replace bail!() with passthrough for unknown subcommands
  (freeze, download, wheel, etc.)

Fixes rtk-ai#600

Signed-off-by: Patrick szymkowiak <[email protected]>
cargo fmt diffs in config.rs, git.rs, playwright_cmd.rs were failing
the fmt CI check, which cascaded to block clippy/test/security on
PRs rtk-ai#632, rtk-ai#635, rtk-ai#638. Also fixes all clippy warnings: dead code
annotations, iterator simplifications, assert patterns, and
unnecessary allocations.

Signed-off-by: Patrick Szymkowiak <[email protected]>
Signed-off-by: Patrick szymkowiak <[email protected]>
…#163) (rtk-ai#518)

* fix: discover classifies absolute paths like /usr/bin/grep (rtk-ai#485)

Normalize absolute binary paths before classification:
/usr/bin/grep → grep, /bin/ls → ls, /usr/local/bin/git → git

Adds strip_absolute_path() helper + 5 tests.

Signed-off-by: Patrick szymkowiak <[email protected]>

* fix: discover and rewrite support git global options -C, --no-pager, etc. (rtk-ai#163)

Strip git global options (-C <path>, -c <key=val>, --git-dir, --work-tree,
--no-pager, --no-optional-locks, --bare, --literal-pathspecs) before
classification so git -C /tmp status is recognized as rtk git.

Rewrite preserves global options: git -C /tmp status → rtk git -C /tmp status

Adds GIT_GLOBAL_OPT lazy_static regex + strip_git_global_opts() helper + 6 tests.

Signed-off-by: Patrick szymkowiak <[email protected]>

---------

Signed-off-by: Patrick szymkowiak <[email protected]>
…-ai#519)

When running `rtk cargo clippy -p my-crate -- -D warnings`, Clap with
`trailing_var_arg = true` preserves the `--` in parsed args when flags
precede it. `restore_double_dash()` then added a second `--`, producing
`cargo clippy -p my-crate -- -- -D warnings`. This caused rustc to
interpret `-D` as a filename instead of a lint flag.

Fix: skip restoration when args already contain `--` (Clap preserved it).

Fixes rtk-ai#496

Signed-off-by: Ousama Ben Younes <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
- PR template reminds contributors to target develop
- CI workflow labels PRs targeting master with 'wrong-base' and posts a comment
- Excludes develop→master PRs (maintainer releases)

Signed-off-by: Patrick <[email protected]>
Signed-off-by: Patrick szymkowiak <[email protected]>
Add Language::Data variant for data formats (JSON, YAML, TOML, XML, CSV, etc.)
with empty comment patterns to prevent comment stripping. AggressiveFilter
falls back to MinimalFilter for data files.

Fixes rtk-ai#464

Signed-off-by: Ousama Ben Younes <[email protected]>
Co-authored-by: Claude Opus 4.6 <[email protected]>
…tk-ai#439) (rtk-ai#563)

rtk find outputs a grouped format incompatible with pipe consumers
like xargs, grep, wc, sort. Skip rewrite when find/fd is followed
by a pipe, preserving native one-per-line output.

Signed-off-by: Patrick szymkowiak <[email protected]>
…gh (rtk-ai#427) (rtk-ai#564)

When compact_diff truncates output, append a hint line so Claude knows
how to get the full diff: [full diff: rtk git diff --no-compact]

Also fix --no-compact flag being passed to git (causing usage error)
and remove decorative emoji from compact_diff output.

Signed-off-by: Patrick szymkowiak <[email protected]>
rtk-ai#632)

4 P1 bugs where git exit codes were swallowed:
- git diff: failure silently printed empty stat output
- git status (with args): failure was filtered instead of propagated
- git commit: failure printed "FAILED" but returned Ok(()) breaking pre-commit hooks
- git branch (list mode): failure was silently ignored

All now follow the established pattern: eprint stderr, track raw==raw, process::exit(code).

Signed-off-by: Patrick szymkowiak <[email protected]>
…tk-ai#635)

* feat: add 5 new TOML built-in filters (ollama, nx, gradle, spring-boot, jira)

New filters for commands not covered by Rust modules:
- ollama: strip ANSI spinners, keep final text response (rtk-ai#624)
- nx: strip Nx monorepo noise, keep build results (rtk-ai#444)
- gradle/gradlew: strip UP-TO-DATE tasks, keep build summary (rtk-ai#147)
- spring-boot: strip banner and verbose logs, keep startup/errors (rtk-ai#147)
- jira: strip blanks, truncate wide columns (rtk-ai#524)

All 5 filters pass inline tests via rtk verify (123/123).
Updated builtin filter count: 47 -> 52.

Signed-off-by: Patrick szymkowiak <[email protected]>

* feat: add 5 more TOML filters (turbo, mise, just, task, yadm)

New filters for task runners and git wrapper:
- turbo: strip cache/Tasks/Duration noise, keep task output (rtk-ai#531)
- mise: strip install/download progress, keep task results (rtk-ai#607)
- just: strip blanks and recipe headers, keep output (rtk-ai#607)
- task: strip task headers and up-to-date lines, keep results (rtk-ai#607)
- yadm: strip hint lines, compact git-like output (rtk-ai#567)

All verified with fake binaries through catch-all TOML engine.
137/137 TOML tests pass, 934 Rust tests pass.
Updated builtin filter count: 52 -> 57.

Signed-off-by: Patrick szymkowiak <[email protected]>

---------

Signed-off-by: Patrick szymkowiak <[email protected]>
…rtk-ai#638)

Git status output used emojis (📌, 📝, ❓, ✅, ⚠️) that confuse
non-Claude LLMs (GPT, etc.) causing retry loops. Replace with plain
text labels (branch:, modified:, staged:, untracked:, conflicts:).

Also add "clean — nothing to commit" when working tree is clean,
so LLMs understand the repo state without ambiguity.

Before: 📌 master
After:  branch: master
        clean — nothing to commit

Fixes rtk-ai#603

Signed-off-by: Patrick szymkowiak <[email protected]>
…ooks

When Claude Code updates a plugin, both old and new version directories
remain on disk. patch_plugin_caches() previously processed ALL versions,
creating manifest entries for each. This caused double-execution: the
active version's hook ran via direct match AND via fallthrough from the
old version's manifest entry.

Fix: collect version directories, sort by semver (descending via
parse_semver()), process only the highest (active) version. Remove
manifest entries for non-active versions of the same plugin using
retain() with plugin_prefix/active_prefix path matching.

Add parse_semver() helper (major.minor.patch tuple comparison).
Add TDD tests: test_parse_semver, test_version_dedup_removes_older_entries,
test_catch_all_not_registered_as_fallthrough.
Cargo.toml: add [profile.dev.package."*"] with debug=0, opt-level=1
to reduce target/ size (8.2GB → 0.73GB measured) and speed up dep builds.

CLAUDE.md: add Debug & Profiling Builds section documenting debugging/
profiling named profiles. Append RTK command reference (rtk-instructions
v2) with full command list organized by workflow category.
Merge 34 upstream commits (develop) including:
- src/trust.rs: trust boundary for project-local TOML filters
- src/git.rs: git log --oneline regression fix (user_format 4th param)
- src/git.rs: nothing-to-commit detection in commit handler
- 6 critical bug fixes: exit codes, unwrap, lazy regex (rtk-ai#626)
- src/discover/registry.rs: find/fd pipe-skip ported to token-based lexer
- cargo fmt + 54 clippy warnings fix (rtk-ai#663)
- subcommand routing fix (rtk-ai#600), output cap raise (rtk-ai#617-620)
- SQLite WAL, grep regex perf (rtk-ai#631)

Conflict resolution (6 files, 11 hunks):
- src/main.rs: kept Pipe (ours) + Trust/Untrust (upstream)
- src/git.rs: pub(crate) (ours) + user_format param (upstream)
- src/grep_cmd.rs: filter_grep_raw (ours) + context_re (upstream)
- src/init.rs: remove-then-insert upgrade path (ours)
- src/tracking.rs: merged doc comments
- src/discover/registry.rs: token-based lexer (ours) + find/fd skip (upstream)
- src/tee.rs: removed duplicate derive(Default)
- src/pipe_cmd.rs: added user_format=false 4th arg

Tests: 1388 passed (was 1358), 0 failures, 6 ignored
@ahundt
Copy link
Author

ahundt commented Mar 18, 2026

I updated again to match upstream, it is ready to merge to the best of my knowledge! Additionally this pr fixes the multi-hook conflict bug that is now independently confirmed by #361 (comment)

…s-v2-develop

Merge 15 new upstream commits after force-push rebase including:
- v0.31.0 release
- Cline/Roo Code, Windsurf, Cursor Agent, Copilot, Codex CLI support
- Gemini CLI support via rtk init --gemini
- OpenClaw plugin for transparent exec rewriting
- Emoji removal from all CLI output (rtk-ai#687)

Conflict resolution (9 files, 29 hunks):
- src/git.rs: accepted upstream plain-text labels, updated 8 test assertions
- src/main.rs: merged Hook enum (Claude+Gemini+Copilot), kept Pipe + Init fields
- src/init.rs: kept remove-then-insert + Result<()>, added HookType to new tests
- src/discover/registry.rs: kept token-based lexer
- src/grep_cmd.rs: kept filter_grep_raw/find_output, emoji removal
- src/gh_cmd.rs, log_cmd.rs, wget_cmd.rs: accepted upstream changes
- src/tracking.rs: kept doc comments
- src/cargo_cmd.rs, pytest_cmd.rs: fixed stale emoji assertions in stream tests

Caller/callee verification: 10/10 critical functions verified correct
Tests: 1417 passed (was 1388), 0 failures, 6 ignored
ahundt added a commit to ahundt/rtk that referenced this pull request Mar 19, 2026
Quantitative benchmark comparing PR rtk-ai#536 capabilities vs upstream develop.
Measures token savings across 10 operations using live command output:

- 5 shared e2e commands (both branches: 72-91% savings)
- 5 pipe mode commands (PR rtk-ai#536 only: 78-97% savings, develop: 0%)
- Token-based lexer correctness (background & operator: 2/2)

Combined: develop 44.2% vs PR rtk-ai#536 93.0% (+48.7pp improvement)

Run: cargo test --test pipe_and_hook_savings_benchmark -- --nocapture --include-ignored
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.