feat(hook): native cross-platform (Windows & more) hook-rewrite command#150
feat(hook): native cross-platform (Windows & more) hook-rewrite command#150ayoub-khemissi wants to merge 6 commits intortk-ai:masterfrom
Conversation
Windows default stack is 1 MB vs 8 MB on Unix. The large Commands enum (30+ Clap variants) overflows in unoptimized debug builds. Add build.rs with /STACK linker flag for Windows only, zero runtime overhead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Keep both hook-rewrite (this PR) and hook-audit (upstream rtk-ai#151) commands. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Hello, Approved. Code is correct for me, but for futures PR please split files into respective components to avoid having 1000+ lines files. We should refactor the code structure of the project for a clean architecture that will help for easy reviewing and extensible code. |
|
Thanks for this massive PR — the native hook-rewrite is a great step forward for cross-platform support! I did an exhaustive test of 313 commands across all 12 categories, simulating the real Claude Code hook JSON format ( Test Results: 312/313 passed (99.7%)
Only issue:
|
Split the monolithic 1127-line hook_cmd.rs into 8 focused modules under src/hook/ for better maintainability and code review: - mod.rs: entry point, chain parsing, orchestrator - git.rs: git + GitHub CLI rewriters - cargo.rs: cargo rewriter - files.rs: file ops (cat, grep, ls, tree, find, diff, head) + network - js_ts.rs: JS/TS tooling (vitest, tsc, eslint, prettier, playwright, prisma, pnpm) - containers.rs: Docker + kubectl rewriters - python.rs: pytest, ruff, pip/uv rewriters - go.rs: go test/build/vet + golangci-lint rewriters - helpers.rs: shared utility functions (replace_prefix, starts_with_any) All 71 hook tests passing. No behavioral changes.
- Update version references from 0.18.1 to 0.19.0 in README.md, CLAUDE.md, and ARCHITECTURE.md - Update module count in ARCHITECTURE.md (47 → 49) - Update validate-docs workflow and script to check native hook module (src/hook/) instead of deprecated bash script (.claude/hooks/rtk-rewrite.sh)
Fixes from review feedback1. Split
|
| File | Responsibility |
|---|---|
mod.rs |
Entry point, chain parsing, orchestrator |
git.rs |
Git + GitHub CLI |
cargo.rs |
Cargo |
files.rs |
cat, grep, ls, tree, find, diff, head, curl, wget |
js_ts.rs |
vitest, tsc, eslint, prettier, playwright, prisma, pnpm |
containers.rs |
Docker + kubectl |
python.rs |
pytest, ruff, pip/uv |
go.rs |
go test/build/vet, golangci-lint |
helpers.rs |
Shared utilities (replace_prefix, starts_with_any) |
All 71 hook tests preserved and passing.
2. Fix pnpm eslint (the 1/313 missing)
Added pnpm eslint . → rtk lint . support in js_ts.rs, with 2 dedicated tests (test_pnpm_eslint, test_pnpm_eslint_bare).
→ 313/313 commands now covered.
3. Fix CI validate-docs
- Updated version
0.18.1→0.19.0in README.md, CLAUDE.md, ARCHITECTURE.md - Fixed module count
47→49in ARCHITECTURE.md - Updated workflow and
validate-docsscript to checksrc/hook/(native hook) instead of.claude/hooks/rtk-rewrite.sh(legacy bash hook)
- Take upstream version 0.20.1 for docs - Update module count to 51 (upstream additions + hook split)
Follow-up: Real Execution Testing + Migration WarningFollowing up on my earlier 313-command protocol test — I went deeper and tested every RTK filter with real toolchains (not just the JSON rewrite protocol). Also found critical issues with the auto-migration behavior. Real Execution: 98/98 passBuilt the PR branch (merged master, zero conflicts, 491 tests pass) and tested against actual projects in
All RTK filters work perfectly with real command output. Zero regressions vs master. Critical: Don't Auto-Migrate to Native Hook
This is breaking. Deeper testing (beyond the 313 protocol commands) revealed 3 P0 bugs that would silently corrupt user workflows: P0 — Must fix before making native hook default
These aren't edge cases — Suggested approach:
P1 — Should fix
P2 — Nice to have (follow-up PRs)
Roadmap: Toward an Extensible Hook EngineThis PR provides excellent rewrite coverage (hardcoded in Rust modules). Long term, we want the community to add rewrite rules without modifying Rust source code. We plan to also leverage ideas from PR #156 (Hook Engine by @ahundt) which brings:
Combined with the declarative TOML plugin system (#139), this enables: # ~/.config/rtk/plugins/terraform.toml
[filter]
command = "terraform"
subcommands = ["plan", "apply", "init"]
strategy = "strip"
patterns = ["^Acquiring", "^- Installed", "^Terraform has been"]Community contributors would add support for new tools by dropping a Why not JS hooks? (ref: closed PR #141)
Bottom LineRTK filters are rock solid (98/98 real execution). The hook architecture is clean and well-modularized. Recommendation: Merge but keep bash hook as default. Fix the 3 P0s in follow-ups, then switch. Long term, combine with PR #156's engine + TOML plugins for community-extensible rewrite rules. Happy to discuss any of these points. |
Summary
Replace the bash-based
rtk-rewrite.shhook with a native Rustrtk hook-rewritesubcommand, eliminating the bash/jq dependency and enabling cross-platform support (Windows, macOS, Linux).src/hook_cmd.rs(1126 lines): Pure Rust command rewriter that reads Claude CodePreToolUseJSON from stdin, rewrites known commands to theirrtkequivalents, and outputs updated JSON. Supports command chains (&&,;), env var prefixes, git/cargo/docker/kubectl global flags, and 30+ command patterns (git, cargo, gh, pnpm, vitest, tsc, eslint, prettier, playwright, prisma, pytest, ruff, pip, go, golangci-lint, curl, wget, cat, grep, find, ls, tree, head, diff).src/init.rs:rtk initnow installs the nativertk hook-rewritecommand instead of the bash script. Includes migration logic to clean up old.shhook files. Both old and new formats are detected during--uninstall.src/main.rs: Added hiddenhook-rewritesubcommand routing tohook_cmd::run().build.rs: Set 8 MB stack size on Windows to prevent debug build stack overflow (Windows defaults to 1 MB vs 8 MB on Unix).src/gain.rs: Formatting fix (line wrapping fortable_widthcalculation).Why native?
rtk-rewrite.sh)rtk hook-rewrite)Security review
Per SECURITY.md checklist:
Command::new("sh")— pure string rewriting, no shell spawningunsafe {}blocksreqwest::,std::net::).env("LD_PRELOAD")).unwrap()in production paths (only inlazy_static!regex compilation)exit(0)(no rewrite, original command passes through)init.rschanges reduce attack surface by removing bash script dependencyTest plan
cargo fmt --all --check && cargo clippy --all-targets && cargo test --allpassesrtk init --auto-patchinstalls native hook command insettings.jsonrtk init --uninstallremoves both old.shand new native hook entriesgit statusis rewritten tortk git statusVerification results (Windows 11, 2026-02-16)
Quality pipeline
cargo fmt --all --checkcargo clippy --all-targetscargo test --allUninstall coverage
rtk hook-rewrite) fromsettings.jsonrtk-rewrite.sh) fileRTK.md@RTK.mdreference fromCLAUDE.md.sh→ native then uninstallHook-rewrite manual verification
git statusrtk git statuscargo test -- --nocapturertk cargo test -- --nocapturecd /project && git status && cargo testcd /project && rtk git status && rtk cargo testTEST_ID=123 git statusTEST_ID=123 rtk git statuscat src/main.rsrtk read src/main.rspython -m pytest tests/rtk pytest tests/rtk git status(already prefixed)Cross-platform (Windows)
bash,sh,jq,sed,grepcalls inhook_cmd.rsbuild.rssets/STACK:8388608(8 MB) on Windows via linker flag — zero runtime overhead, matches Unix defaults🤖 Generated with Claude Code