git -C <path> and other global options were rejected because Clap
expected a subcommand immediately after `git`. Add these options to
the Git command variant and thread them through all git subcommand
handlers via a git_cmd() helper that prepends global args before
the subcommand.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(gain): add per-project token savings with -p flag
Record project_path (cwd) in tracking database and add filtered query
methods. `rtk gain -p` shows savings scoped to the current project
directory instead of global aggregates.
- tracking.rs: Add project_path column with auto-migration, index,
and filtered variants for all query methods (summary, daily, weekly,
monthly, recent)
- gain.rs: Add resolve_project_scope(), shorten_path(), scope-aware
header, pass project filter to all queries and exports
- main.rs: Add --project/-p flag to Gain command
Backward-compatible: existing rows get empty project_path, unfiltered
queries delegate to filtered(None) which returns all data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(tracking): use GLOB instead of LIKE for project path filtering
Address reviewer feedback on PR #128:
1. Replace SQL LIKE with GLOB in all project-scoped queries to prevent
`_` and `%` characters in path names from being interpreted as
wildcards (e.g., `my_project` matching `myXproject`). GLOB uses `*`
for wildcard matching which is safer for file system paths.
2. Guard the startup `UPDATE commands SET project_path = ''` migration
with an `EXISTS` check so it only runs when NULL rows actually exist,
avoiding a no-op UPDATE on every startup after the first migration.
3. Add `DEFAULT ''` to the ALTER TABLE migration so new installs never
create NULL project_path values.
4. Add 3 new unit tests for project_filter_params GLOB behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add mypy command with grouped error output (80% token reduction)
Add rtk mypy module that parses mypy type checker output, groups errors
by file and error code, and produces compact summaries. Includes
discovery registry pattern, hook rewrites, and 11 new tests (324 total).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address review - remove specs/ and clean CLAUDE.md
Remove process docs (spec, plan, tasks, research, checklists) from
specs/001-mypy-cmd/ and strip "Active Technologies" / "Recent Changes"
sections from CLAUDE.md per PR #109 review feedback.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address review - deduplicate mypy handler, delegate from lint_cmd
Make lint_cmd.rs delegate to mypy_cmd::filter_mypy_output() instead of
maintaining a separate, less capable implementation. The mypy_cmd version
handles column numbers, note continuations, file-less errors, and shows
full error details. Removes 145 lines of duplicate code + 2 redundant tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Robert Mohid <rmohid@Roberts-Mini.ht.home>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
`go test -json` emits build failures as `build-output`/`build-fail`
actions with `ImportPath` (not `Package`/`Test`), followed by a
package-level `fail` with a `FailedBuild` field. The JSON parser
only counted failures when `event.test.is_some()`, so build errors
were silently dropped from the summary — showing "891 passed" when
a package failed to compile.
Now parses `build-output`, `build-fail`, and `FailedBuild` fields.
Build failures count toward the total and display with `[build failed]`
plus the compiler error lines.
Before:
✓ Go test: 891 passed in 74 packages
After:
Go test: 891 passed, 1 failed in 74 packages
═══════════════════════════════════════
📦 stream [build failed]
handler_test.go:64:9: undefined: undefinedVariable
Co-authored-by: Ricardo Liberato <ricardo@liberato.pt>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The hook was rewriting all `docker compose` commands to `rtk docker
compose`, but rtk only supports ps, logs, and build. Unsupported
subcommands (up, down, exec, restart...) and compose-level flags
(-f, --project-name) caused hard failures.
Now matches the approach used by the regular docker branch: only
rewrite when the subcommand is known to be supported.
Fixes#244
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The shell keyword "fi" was listed as a bare prefix in IGNORED_PREFIXES,
causing classify_command("find ...") to return Ignored because
"find".starts_with("fi") is true. This prevented find commands from
being rewritten by rtk rewrite and the hook system.
Move "fi" and "done" from IGNORED_PREFIXES to IGNORED_EXACT so they
only match as exact standalone keywords, not as prefixes of other
commands.
Fixes#170, #204, #236 (partially — find classification was the root
blocker for rtk rewrite).
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The current x86_64-unknown-linux-gnu release binary dynamically links against glibc, which causes failures on systems with an older glibc version:
rtk: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.39' not found (required by rtk)
Replace the x86_64-unknown-linux-gnu build target with x86_64-unknown-linux-musl, producing a fully statically-linked binary with no libc dependency.
Fixesrtk-ai/rtk#265 - binary fails on systems with old glibc.
Remove `methode-aristote/app` project name from the JS/TS tooling
section. Project-specific CLAUDE.md should not reference personal
projects or contributor-specific context.
Follow-up to #242.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Project CLAUDE.md is loaded for every contributor using Claude Code.
It should contain project documentation, not personal preferences.
Removed:
- Hardcoded home directory path (/Users/florianbruniaux/...)
- Sibling project references (ccboard, cc-economics)
- French language preference and communication style
These belong in the author's personal ~/.claude/CLAUDE.md, not in
the repo where they get imposed on every fork and contributor.
Three bugs fixed:
1. JSON struct mismatch: The parser expected `suites[].tests[]` but
Playwright's JSON reporter outputs `suites[].specs[].tests[]`.
Added PlaywrightSpec layer, use `spec.ok` for failure detection,
and `errors: Vec<PlaywrightError>` (array, not Option).
2. Float duration: Playwright emits `duration` as f64, not u64.
Changed struct field type to avoid deserialization failures.
3. pyenv shim collision: `which playwright` can resolve to a pyenv
shim (Python's playwright) which lacks a `test` subcommand.
Bypass `which` entirely and resolve through the detected package
manager (npx/pnpm/yarn).
Also strips user-supplied `--reporter` flags to avoid conflicts with
the forced `--reporter=json`.
rtk grep previously returned exit 0 for all failure modes (no match,
invalid regex, missing file) where rg returns non-zero. This broke
shell workflows relying on exit code semantics.
Now propagates rg exit codes: 1 (no match), 2 (error) and surfaces
stderr for error cases so users see why the command failed.
Fixes#162
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
`rtk git branch <name>` fell into the listing code path which injected
`-a --no-color`, turning the creation into a pattern-filtered listing
(silent no-op with exit 0). Detect positional args without list-mode
flags and route them to direct passthrough so branch creation, including
`git branch <name> <start-point>`, works correctly.
Adds regression integration tests for both cases.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Two bugs when passing grep-idiom arguments to rtk grep:
1. Pattern alternation `\|` (BRE syntax) returns 0 results because rg
uses PCRE-style `|`, not BRE `\|`. Users coming from grep/awk muscle
memory naturally write `rtk grep "fn foo\|fn bar" src/` and get
empty output with no error.
Fix: translate `\|` → `|` in pattern before passing to rg.
2. `-r`/`--recursive` flag (grep idiom) silently breaks the search.
In rg, `-r` means `--replace` and requires an argument — passing it
alone causes rg to exit with an error. The `.or_else(|_| ...)` fallback
only catches IO errors (command not found), so the grep fallback never
triggers; stdout is empty and rtk reports "0 for '<pattern>'".
Fix: filter out `-r`/`--recursive` from extra_args before building
the rg command (rg is recursive by default, flag is a no-op).
Adds two regression tests documenting both behaviours.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
rtk lint was always returning exit code 0 regardless of the underlying
linter's exit status, causing false-green CI behavior when lint should fail.
Uses !output.status.success() pattern consistent with all other RTK modules,
which correctly handles both non-zero exit codes and signal termination.
Fixes#185
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Adds a new `wc` subcommand that compresses wc output by:
- Stripping alignment padding: ` 30 96 978 file.py` → `30L 96W 978B`
- Removing common path prefixes in multi-file output
- Returning bare numbers for single-flag modes (-l, -w, -c, -m)
- Showing Σ totals instead of verbose "total" lines
Includes 15 unit tests covering single/multi-file, stdin, all flag
modes, and common prefix detection.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
view_run() only passed the run ID to `gh run view`, silently
dropping all subsequent args. This made it impossible to inspect
CI failure logs when the rtk-rewrite hook was active.
Add should_passthrough_run_view() to detect flags that produce
output incompatible with the summary filter, and pass through
to gh directly when found.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat(docker): add docker compose support with compact output
Add token-optimized output for docker compose commands:
- `docker compose ps`: compact service listing with status and ports
- `docker compose logs`: deduplicated log output via existing log engine
- `docker compose build`: summary with build time, services, and step count
- Unsupported compose subcommands pass through directly
Includes 11 tests (8 compose format tests + 3 for existing compact_ports).
Fixes#101
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR #110 review — use --format for compose ps, fix bytes/chars bugs
- Switch format_compose_ps to parse structured --format tab output
instead of fragile human-readable table (eliminates contains("Up")
false positives and byte/char confusion)
- Fix find('[') byte offset used with chars().skip() in build parsing
- Use .next_back() instead of .last() on DoubleEndedIterator
- Consistent error handling with .context()? in run_compose_ps
- Strengthen test assertion for compose logs
- Add tests for no-ports and long-image-path cases
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: propagate exit codes on compose failures + remove Vec allocation
Address PR #110 review feedback from pszymkowiak:
- Check output.status.success() after .output() in run_compose_ps,
run_compose_logs, and run_compose_build to prevent silent failures
when Docker daemon is not running
- Replace .collect::<Vec<&str>>().len() with .count() in
format_compose_build step counting to avoid unnecessary allocation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: update version references to 0.20.1 after upstream rebase
Sync documentation version strings with Cargo.toml after rebasing
on upstream master. Fixes CI validate-docs check.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: drop upstream workflow file from feature branch
This workflow was pulled in during rebase on upstream master.
Not part of the docker compose feature — let upstream manage it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: restore validate-docs workflow from upstream
Workflow was unintentionally removed while resolving a push
permission issue. Restored to match upstream master.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Remove sudo requirement by defaulting to $HOME/.local/bin (XDG standard).
Supports RTK_INSTALL_DIR env var for custom install path.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add opt-in audit logging to the RTK rewrite hook and a new `rtk hook-audit`
command to analyze the collected metrics. This provides verifiable data on
hook reliability (rewrite rate, skip reasons, top commands) instead of
relying on anecdotal claims.
- Add `_rtk_audit_log()` function to rtk-rewrite.sh (opt-in via RTK_HOOK_AUDIT=1)
- Log each invocation: timestamp | action | original_cmd | rewritten_cmd
- Actions: rewrite, skip:already_rtk, skip:heredoc, skip:no_match, skip:no_deps, skip:empty
- New `src/hook_audit_cmd.rs` module with log parser and stats display
- New `rtk hook-audit --since N` subcommand (default: last 7 days)
- 8 Rust unit tests + 7 hook bash tests for audit mode
- Make HOOK var overridable in test suite for repo-local testing
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: tee raw output to file for LLM re-read without re-run (#86)
When RTK filters command output, LLM agents lose failure details
(stack traces, assertions) and re-run the same command 2-3x. The tee
feature saves raw output to ~/.local/share/rtk/tee/ on failure and
prints a one-line hint so the agent can read the file instead.
- Add src/tee.rs: core module with tee_raw(), tee_and_hint(), rotation
- Add TeeConfig to config.rs: enabled, mode, max_files, max_file_size
- Integrate in 7 modules: cargo, runner, vitest, pytest, lint, tsc, go
- Default: failures only, skip <500 chars, 20 file rotation, 1MB cap
- Env overrides: RTK_TEE=0 (disable), RTK_TEE_DIR (custom directory)
- 14 unit tests, 352 total tests passing, zero regressions
Closes#86
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add tee.rs to ARCHITECTURE.md module count (47 modules)
CI validate-docs requires main.rs module count == ARCHITECTURE.md count.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Generates structured repo recap with:
- Open PRs categorized (ours/reviewable/problematic)
- Open issues with priority classification
- Recent releases
- Executive summary with risks and quick wins
- Auto-copy to clipboard
- FR/EN language support via argument
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
`rtk grep -n "pattern" path` failed with "unexpected argument '-n'"
because clap didn't recognize -n before the positional arguments.
Users naturally place -n before the pattern (muscle memory from
grep/rg). The flag is a no-op since grep_cmd::run() already passes
-n to ripgrep unconditionally, but clap must accept it.
Adds -n/--line-numbers as an explicit bool field to the Grep command
and ignores it in the match arm. Test added in grep_cmd::tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>