feat: binary hook engine with lexer, streaming, and rewrite_compound integration#536
Open
ahundt wants to merge 279 commits intortk-ai:developfrom
Open
feat: binary hook engine with lexer, streaming, and rewrite_compound integration#536ahundt wants to merge 279 commits intortk-ai:developfrom
ahundt wants to merge 279 commits intortk-ai:developfrom
Conversation
## Overview Complete architectural documentation (1133 lines) covering all 30 modules, design patterns, and extensibility guidelines. ## Critical Fixes (🔴) - ✅ Module count: 30 documented (not 27) - added deps, env_cmd, find_cmd, local_llm, summary, wget_cmd - ✅ Language: Fully translated to English for consistency with README.md - ✅ Shared Infrastructure: New section documenting utils.rs and package manager detection - ✅ Exit codes: Correct documentation (git.rs preserves exit codes for CI/CD) - ✅ Database: Correct path ~/.local/share/rtk/history.db (not tracking.db) ## Important Additions (🟡) - ✅ Global Flags Architecture: Verbosity (-v/-vv/-vvv) and ultra-compact (-u) - ✅ Complete patterns: Package manager detection, exit code preservation, lazy static regex - ✅ Config system: TOML format documented - ✅ Performance: Verified binary size (4.1 MB) and estimated overhead - ✅ Filter levels: Before/after examples with Rust code ## Bonus Improvements (🟢) - ✅ Table of Contents (12 sections) - ✅ Extensibility Guide (7-step process for adding commands) - ✅ Architecture Decision Records (Why Rust? Why SQLite?) - ✅ Glossary (7 technical terms) - ✅ Module Development Pattern (template + 3 common patterns) - ✅ 15+ ASCII diagrams for visual clarity ## Stats - Lines: 1133 (+118% vs original 520) - Sections: 12 main + subsections - Code examples: 10+ Rust/bash snippets - Accuracy: 100% verified against source code Production-ready for new contributors, experienced developers, and LLM teams. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
docs: add comprehensive ARCHITECTURE.md v2.0
Updates documentation to reflect all features added in recent PRs: **Version Updates** - Update installation commands to v0.3.1 (DEB/RPM packages) **New Sections** - Add Global Flags section (-u/--ultra-compact, -v/--verbose) - Add JavaScript/TypeScript Stack section (10 new commands) **New Commands Documented** - Files: `rtk smart` (heuristic code summary) - Commands: `rtk gh` (GitHub CLI), `rtk wget`, `rtk config` - Data: `rtk gain --quota` and `--tier` flags - Containers: `rtk kubectl services` - JS/TS Stack: lint, tsc, next, prettier, vitest, playwright, prisma **Features Coverage** This update documents functionality from: - PR rtk-ai#5: Git argument parsing improvements - PR rtk-ai#6: pnpm support - PR rtk-ai#9: Modern JavaScript/TypeScript stack support - PR rtk-ai#10: GitHub CLI integration - PR rtk-ai#11: Quota analysis features - PR rtk-ai#14: Additional command improvements All commands documented are available in v0.3.1. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…update docs: comprehensive documentation update for v0.3.1
Add automated workflow step to update the 'latest' tag after each successful release. This ensures 'latest' always points to the most recent stable version without manual intervention. The new job: - Runs after successful release completion - Updates 'latest' tag to point to the new semver tag - Uses force push to move the tag reference - Includes version info in tag annotation message Benefits: - Install scripts can reliably use /releases/latest/download/ - No manual tag management needed - Consistent reference for "current stable" across platforms Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…-tag ci: automate 'latest' tag update on releases
…tics Implement day-by-day, week-by-week, and monthly breakdowns with JSON/CSV export capabilities for in-depth token savings analysis and reporting. New Features: - Daily breakdown (--daily): Complete day-by-day statistics without 30-day limit - Weekly breakdown (--weekly): Sunday-to-Saturday week aggregations with date ranges - Monthly breakdown (--monthly): Calendar month aggregations (YYYY-MM format) - Combined view (--all): All temporal breakdowns in single output - JSON export (--format json): Structured data for APIs, dashboards, scripts - CSV export (--format csv): Tabular data for Excel, Google Sheets, data science Technical Implementation: - src/tracking.rs: Add DayStats, WeekStats, MonthStats structures with Serialize - src/tracking.rs: Implement get_all_days(), get_by_week(), get_by_month() SQL queries - src/main.rs: Extend Commands::Gain with --daily, --weekly, --monthly, --all, --format flags - src/gain.rs: Add print_daily_full(), print_weekly(), print_monthly() display functions - src/gain.rs: Implement export_json() and export_csv() for data export Documentation: - docs/AUDIT_GUIDE.md: Comprehensive guide with examples, workflows, integrations - README.md: Update Data section with new audit commands and export formats - claudedocs/audit-feature-summary.md: Technical summary and implementation details Database Scope: - Global machine storage: ~/.local/share/rtk/history.db - Shared across all projects, worktrees, and Claude sessions - 90-day retention policy with automatic cleanup - SQLite with indexed timestamp for fast aggregations Use Cases: - Trend analysis: identify daily/weekly patterns in token usage - Cost reporting: monthly savings reports for budget tracking - Data science: export CSV/JSON for pandas, R, Excel analysis - Dashboards: integrate JSON export with Chart.js, D3.js, Grafana - CI/CD: automated weekly/monthly savings reports via GitHub Actions Examples: rtk gain --daily # Day-by-day breakdown rtk gain --weekly # Weekly aggregations rtk gain --all # All breakdowns combined rtk gain --all --format json | jq . # JSON export with jq rtk gain --all --format csv # CSV for Excel/analysis Backwards Compatibility: - All existing flags (--graph, --history, --quota) preserved - Default behavior unchanged (summary view) - No database migration required - Zero breaking changes Performance: - Efficient SQL aggregations with timestamp index - No impact on rtk command execution speed - Instant queries even with 90 days of data Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…dit-system feat: Comprehensive Temporal Audit System for Token Savings Analytics
…s--master--components--rtk chore(master): release 0.4.0
Implement `rtk cc-economics` command combining ccusage spending data with rtk savings analytics for economic impact reporting. Features: - Dual metric system (active vs blended cost-per-token) - Daily/weekly/monthly granularity with ISO-8601 week alignment - JSON/CSV export support for data analysis - Graceful degradation when ccusage unavailable - Real-time data merge with O(n+m) HashMap performance Architecture: - src/ccusage.rs: Isolated ccusage CLI interface (7 tests) - src/cc_economics.rs: Business logic + display (10 tests) - src/utils.rs: Shared formatting utilities (8 tests) - Refactored gain.rs to use shared format_tokens() Test coverage: 17 new tests, all passing Validated with real-world data (2 months, $3.4K spent, 1.2M saved) Addresses: #economics-integration Impact: 24.4% cost savings identified ($830.91 active pricing) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Apply systematic quality fixes identified in code audit: Phase 1: Remove dead code (4 warnings → 0) - Remove unused run_compact() function in gain.rs - Remove unused track_tokens() function in tracking.rs - Remove unused TRACKER singleton (Mutex) - Clean up CommandRecord struct (remove unused fields) Phase 2: Add error context and quality fixes - Add .context() to all ? operators in cc_economics.rs (15+ callsites) - Add .context() to all ? operators in gain.rs (10+ callsites) - Fix bounds check panic risk in gain.rs:252 (week_start slice) - Reduce visibility: estimate_tokens pub → private - Replace 6 manual loops with idiomatic .collect::<Result<Vec<_>, _>>()? - Remove residual dev comment (// psk:) - Remove unnecessary .clone() in main.rs Phase 3: Refactor duplication (132 lines eliminated) - Create display_helpers.rs module with PeriodStats trait - Unify print_daily_full/weekly/monthly in gain.rs (152 lines → 9 lines) - Implement trait for DayStats, WeekStats, MonthStats - Zero-overhead compile-time dispatch (monomorphization) - Output bit-identical, all tests passing Impact: - Dead code: -20 lines - Error context: Errors now actionable instead of opaque - Duplication: -132 lines of pure duplication - Safety: Bounds check prevents potential panic - Idiomaticity: .collect() over manual loops Metrics: - Build: 0 errors, 1 warning (pre-existing cache_* fields) - Tests: 79/82 passing (3 pre-existing failures) - Clippy: 13 warnings (all pre-existing) - Functional: rtk gain --daily, rtk cc-economics validated Addresses code audit feedback from parallel session Detailed report: claudedocs/refactoring-report.md Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Applies targeted code quality improvements: Issue rtk-ai#5: Reduce clones in HashMap merge - Destructure CcusagePeriod to avoid cloning key - Use .or_insert_with_key() for ccusage data merging - Keep necessary clones for rtk data (HashMap ownership requirement) - Affects: merge_daily, merge_weekly, merge_monthly Issue rtk-ai#7: Replace magic number with named constant - Add const BILLION: f64 = 1e9 - Improves readability in cache token calculation Issue rtk-ai#8: Add NaN/Infinity safety check - Guard format_usd() against invalid float values - Return "$0.00" for non-finite inputs Build: Clean (1 pre-existing warning) Tests: 79/82 passing (3 pre-existing failures) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…dit-system feat: comprehensive economics analysis and code quality improvements
…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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
- 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 <noreply@anthropic.com>
- 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 <noreply@anthropic.com>
- 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 <noreply@anthropic.com>
- 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 <noreply@anthropic.com>
- 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 <noreply@anthropic.com>
Merge upstream/develop (4 commits: dotnet support, TOML rules,
OpenCode plugin, git log improvements) into hooks-v2.
Conflict resolution (4 files):
- src/discover/rules.rs: Keep both HEAD's wc rule and develop's
32 TOML-filtered command rules (ansible, brew, composer, df, etc.)
- src/git.rs: Take develop's improved has_limit_flag detection
(-n, --max-count), parse_user_limit(), and 3-arg filter_log_output
with user_set_limit support. Use is_some_and() (rustonic) instead
of map_or(false, ...). Keep pub(crate) visibility for pipe_cmd.
- src/init.rs: Merge both hook_type (HookType::Script|Binary from
HEAD) and install_claude/install_opencode (OpenCode plugin from
develop) into all function signatures: run(), patch_settings_json(),
run_default_mode(), run_hook_only_mode().
- src/main.rs: Keep HEAD's Run/Pipe/Hook command handlers, use
develop's Rewrite { args } destructuring with args.join(" ").
Pass both hook_type and install_claude/install_opencode to init::run().
- src/pipe_cmd.rs: Update filter_log_output call from 2-arg to
3-arg form (input, 50, false) matching develop's new signature.
All 1309 tests pass (up from 1002 on hooks-v2 alone).
registry.rs rewrite_compound() now uses cmd::lexer::tokenize() to split compound commands instead of a 130-line inline byte scanner. Previous behavior: rewrite_compound() manually tracked in_single/ in_double quote state, byte-by-byte, splitting on &&, ||, ;, |, &. Redirect detection (2>&1, &>/dev/null) used byte-neighbor checks. What changed: - src/cmd/lexer.rs: Add offset: usize field to ParsedToken for byte position tracking. tokenize() now tracks byte_pos through char iteration. flush_arg() adjusts offset for trimmed whitespace. - src/discover/registry.rs: Replace rewrite_compound() body with lexer-based implementation (~80 lines vs ~130 lines). Uses token offsets to extract original substrings from cmd (preserving exact spacing, quotes, redirects). Background & detection checks both prev_kind==Redirect (2>&1) and next token==Redirect (&>/dev/null). Why: The lexer additionally handles edge cases the byte scanner missed: escape sequences (\), $() and backtick detection, glob detection (*, ?), and proper classification of all redirect forms. rewrite_segment() unchanged — still uses classify_command() + RULES table + TOML filters for per-segment rewriting. All 1309 tests pass (155 registry tests, 56 lexer tests).
ahundt
added a commit
to ahundt/rtk
that referenced
this pull request
Mar 12, 2026
This commit removes 423 test functions added by PR rtk-ai#536 to make the core production code easier to review. Tests are NOT deleted — they exist in full on the feat/rust-hooks-v2-develop branch and PR rtk-ai#536. DO NOT MERGE this branch. Use feat/rust-hooks-v2-develop (PR rtk-ai#536) for the complete, tested version. Files affected (test blocks removed from 13 new files, new test functions removed from 7 modified files): - src/cmd/analysis.rs, builtins.rs, exec.rs, filters.rs, predicates.rs, trash.rs - src/cmd/hook/mod.rs, claude.rs - src/cmd/lexer.rs - src/pipe_cmd.rs, stream.rs - src/cargo_cmd.rs, discover/registry.rs, git.rs, grep_cmd.rs - src/init.rs, pytest_cmd.rs, main.rs 886 tests pass (develop's existing tests preserved).
This was referenced Mar 12, 2026
This was referenced Mar 12, 2026
Closed
1. grep_cmd.rs: restore 3 lost behaviors from develop
- Exit code propagation (was always 0, breaks CI pipelines)
- BRE \| → | translation for rg (grep users expect this)
- -r/--recursive stripping (rg interprets -r as --replace)
- Add 3 tests from develop: BRE translation, recursive stripping, rg -n
2. hooks/rtk-rewrite.sh: fix exit code collection
- Remove `|| true` from `wait "$pid"` so $? captures the
actual handler exit code instead of always 0
3. src/cmd/trash.rs: remove orphaned file
- Was commented out in mod.rs, never compiled or wired into main.rs
- Remove file and dead comment
1312 tests pass (1309 + 3 restored develop tests).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. grep_cmd.rs: restore 3 lost behaviors from develop
- Exit code propagation (was always 0, breaks CI pipelines)
- BRE \| → | translation for rg (grep users expect this)
- -r/--recursive stripping (rg interprets -r as --replace)
- Add 3 tests from develop: BRE translation, recursive stripping, rg -n
2. hooks/rtk-rewrite.sh: fix exit code collection
- Remove `|| true` from `wait "$pid"` so $? captures the
actual handler exit code instead of always 0
3. src/cmd/trash.rs: remove orphaned file
- Was commented out in mod.rs, never compiled or wired into main.rs
- Remove file and dead comment
1312 tests pass (1309 + 3 restored develop tests).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ks-v2-develop Merges 3 upstream commits: - fix: resolve Windows command wrapper execution (rtk-ai#269) — adds `which` crate, `resolved_command()`, `tool_exists()` for PATHEXT-aware binary resolution - fix: remove version check from validate-docs CI (rtk-ai#476) - fix: test-all.sh aborts when gt not installed (rtk-ai#500) Conflict resolution: - src/utils.rs: removed our `command_in_path`/`which_command` (replaced by upstream's `resolved_command`/`tool_exists` using `which` crate) - src/{ccusage,next,prisma,tsc,tree}.rs: `command_in_path()` → `tool_exists()` - src/{mypy,pip,pytest}_cmd.rs: removed dead `which_command()` wrappers - src/grep_cmd.rs: kept our superset (BRE translation, -r stripping, exit codes, filter_grep_raw, filter_find_output) + adopted `resolved_command("rg")` - src/cargo_cmd.rs: added `truncate` import, `resolved_command("cargo")` - src/git.rs: fixed test to accept resolved full path from `resolved_command` - Cargo.toml: deduplicated `which` dep (kept v8) 1320 tests pass, 0 failures. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
KuSh
reviewed
Mar 12, 2026
src/gain.rs
Outdated
| let summary = tracker | ||
| .get_summary_filtered(project_scope.as_deref()) // changed: use filtered variant | ||
| .context("Failed to load token savings summary from database")?; | ||
| let summary = match project_scope.as_deref() { |
There was a problem hiding this comment.
Suggested change
| let summary = match project_scope.as_deref() { | |
| let summary = match project_scope { |
src/gain.rs
Outdated
|
|
||
| if history { | ||
| let recent = tracker.get_recent_filtered(10, project_scope.as_deref())?; // changed: filtered | ||
| let recent = match project_scope.as_deref() { |
There was a problem hiding this comment.
Suggested change
| let recent = match project_scope.as_deref() { | |
| let recent = match project_scope { |
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
…imit parsing)
Resolve 15 merge conflicts:
- src/utils.rs: remove command_in_path()/which_command(), use tool_exists()/resolved_command()
- src/mypy_cmd.rs, src/pip_cmd.rs: remove dead which_command() wrappers
- src/pytest_cmd.rs: keep pub(crate) filter_pytest_output using PyTestStreamFilter
- src/next_cmd.rs, src/tsc_cmd.rs, src/tree.rs, src/prisma_cmd.rs, src/ccusage.rs: command_in_path -> tool_exists
- src/grep_cmd.rs: use resolved_command("rg") in test
- src/cargo_cmd.rs: Command::new("cargo") -> resolved_command("cargo")
- src/git.rs: take upstream's improved limit parsing (parse_user_limit), filter_log_output(3-arg)
- src/main.rs: keep our Run/Pipe/Hook commands, add session_cmd + stream modules, fix Rewrite args
- src/init.rs: merge hook_type + install_opencode params into all mode functions
- src/discover/rules.rs: keep wc rule, add upstream TOML-filtered command rules
- Cargo.toml: keep which = "8" only
- Cargo.lock: regenerated from upstream + our deps
1342 tests pass, 0 failures.
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
…based version Replace the 129-line byte-scanner rewrite_compound() with the 107-line lexer-based version that uses cmd::lexer::tokenize() for quote-aware operator detection and byte-offset segment extraction. Changes: - Add byte offset tracking to ParsedToken and tokenize() in lexer.rs - Import tokenize/TokenKind in discover/registry.rs - Replace rewrite_compound with lexer-based version Improvements over old byte scanner: - Handles escape sequences (\", \\) - Detects $() subshells, backticks, globs as shellisms - Uses TokenKind::Redirect context for 2>&1 vs && disambiguation - Supports unicode via chars() iterator - 22 lines shorter, shares lexer with binary hook path All existing rewrite_compound + lexer tests pass unchanged.
# 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
Author
|
@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. |
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).
…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
Author
|
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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR #536 integrates the hooks-v2 engine (from PR #156) with the
developbranch (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:rewrite_compound()'s inline byte scanner — all 155 existing rewrite tests pass unchangedrtk hook claude) works alongside the shell hook path (rtk rewrite)stream.rs) enables bidirectional process shims with exit code transparencyKey components
src/cmd/lexer.rs— Shell-aware tokenizer (56 tests): handles quoting, escapes,$(), backticks, globs, redirects,2>&1src/cmd/analysis.rs— Command chain parser (61+ tests):needs_shell()detection,parse_chain()for&&/||/;chainssrc/cmd/hook/mod.rs— Binary hook engine (98 tests): conservativehook_lookup()whitelist, Claude Code JSON protocol, safe suffix handlingsrc/cmd/exec.rs— Native command executor: runs simple chains natively, delegates complex shell to/bin/shsrc/stream.rs— Streaming process execution (39 tests):StreamFiltertrait,StdinMode::Inheritfor pipe support, SIGPIPE handling, 1 MiB raw capsrc/pipe_cmd.rs—rtk pipe --filterdispatch for grep/rg/find/fd output filteringsrc/discover/registry.rs—rewrite_compound()replaced: lexer-based splitting instead of 130-line inline byte scannerLexer integration in
rewrite_compound()The byte-level quote tracker in
rewrite_compound()(~130 lines) is replaced withlexer::tokenize()calls (~80 lines). The lexer adds:\\)$()and backtick detection (Shellism tokens)*,?→ Shellism)&&operator (2>&1,&>/dev/null)Token byte offsets (
ParsedToken.offset) enable extracting original substrings from the command string, sorewrite_segment()receives exact original text — no reconstruction fidelity issues.Binary hook architecture
Two complementary routing paths:
rtk rewrite→registry::rewrite_command()→rewrite_compound()→rewrite_segment()(TOML filters + RULES table)rtk hook claude→check_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 statusbut notgit rebase,cargo testbut notcargo publish).Init system (
src/init.rs)--hook-type binary|scriptflag to select hook modeBashfrom plugin matchers, writes manifestNoOpinionandAllowpathsbackup_file_once()+atomic_write()for safe file operations--install-opencodeflag preserved)Test plan
cargo test— 1309 passed, 0 failed, 6 ignoredcargo fmt --all— cleancargo clippy --all-targets— cleanrtk rewrite "cargo test && git status"producesrtk cargo test && rtk git statusrtk rewrite "cargo test | grep FAIL"producesrtk cargo test | grep FAILrtk rewrite "cargo test 2>&1"producesrtk cargo test 2>&1Stats
46 files changed, ~9500 insertions, ~450 deletions
Fixes #222