Commit Graph

931 Commits

Author SHA1 Message Date
Adrien Eppling 9f47f4968f fix(hooks): use absolute path for sub agents 2026-05-10 17:03:39 +02:00
patrick szymkowiak 2d6e10a923 Merge pull request #1718 from kamilkaczmareksolutions/fix/cursor-hook-permission-ask
fix(hooks): make Cursor preToolUse rewrites work and stay visible
dev-0.40.0-rc.214
2026-05-10 16:27:18 +02:00
aesoft 107b3d3b2c Merge pull request #1776 from KuSh/fix-clippy-0.1.95
chore(ci): makes clippy pass, warnings included, mandatory
dev-0.40.0-rc.213
2026-05-10 13:41:09 +02:00
Nicolas Le Cam 70b9f385c7 chore(ci): deny warnings and make clippy pass mandatory in ci 2026-05-10 12:44:38 +02:00
Nicolas Le Cam f005dbf299 chore: fix clippy 0.1.95 warnings 2026-05-10 12:44:38 +02:00
patrick szymkowiak 858d0d9a14 Merge pull request #1764 from sadikkuzu/update-telemetry-docs-link
Update telemetry documentation link to use 'master' branch
dev-0.40.0-rc.212
2026-05-10 11:57:00 +02:00
patrick szymkowiak 0a55201ae1 Merge pull request #1791 from xdm67x/refactor/unused-error-warning-fix
refactor(warn): replace #[cfg] with cfg! macro to fix unused variable warning
2026-05-10 11:56:17 +02:00
patrick szymkowiak 2a41e03990 Merge pull request #1767 from swseverance/fix/links
fix: correct ARCHITECTURE.md path in README links
2026-05-10 11:55:40 +02:00
aesoft 172ec54580 Merge pull request #1032 from hed0rah/feat/init-dry-run
feat(init): add --dry-run flag to preview changes without writing
dev-0.40.0-rc.209
2026-05-10 00:45:39 +02:00
Adrien Eppling 4830d50f6e fix: resolve merge conflict artifacts in init.rs 2026-05-10 00:17:26 +02:00
aesoft 96aeb69842 Merge branch 'develop' into feat/init-dry-run 2026-05-10 00:00:15 +02:00
kamilkaczmareksolutions f00977aa33 fix(hooks): make Cursor preToolUse rewrites work and stay visible
Three related issues prevented RTK from working with the Cursor
preToolUse hook on Windows. Each one alone produced the same
user-visible symptom (`Output: {}` and the original command running
unmodified), so they're fixed together:

1. Cursor preToolUse only enforces allow/deny — `permission: "ask"` is
   accepted by the schema but ignored at runtime, so `updated_input`
   rewrites could silently be dropped. Always return `allow` for
   rewritten commands (deny rules still take precedence and are
   evaluated before this point).

2. Cursor's preToolUse panel renders the JSON returned by the hook.
   Without a `continue: true` field the panel collapses to
   `Output: {}` even when the rewrite ran successfully, which makes
   the hook look broken from the user's perspective. Every other
   Cursor hook (`afterShellExecution`, `beforeSubmitPrompt`, `stop`,
   ...) returns `continue: true`; mirror that shape here so the panel
   surfaces the actual `permission` and `updated_input` payload.

3. Cursor on Windows prepends one or two UTF-8 BOMs (`EF BB BF`,
   sometimes doubled) to the JSON it pipes into the hook process.
   serde_json refuses to parse BOM-prefixed input, so `run_cursor`
   bailed out into the "no command" branch and returned `{}` for
   every invocation. Strip leading BOMs before parsing. This was the
   root cause of the long-standing "RTK silently no-ops in Cursor"
   reports — the rewrite path was never reached.

Tests cover the flat allow output, `continue: true` on both single
and compound (`cd ... && git status`) rewrites, the BOM-strip on
double-BOM payloads matching what Cursor actually sends, and assert
that the legacy hookSpecificOutput envelope is not emitted.

Verified end to end on Windows by tracing real Cursor stdin payloads:
the hook now returns `{"continue":true,"permission":"allow",
"updated_input":{"command":"rtk git status"}}` for `git status` and
the panel renders it instead of `Output: {}`.
2026-05-09 11:03:29 +02:00
aesoft e4c3ed7d88 Merge pull request #1792 from rtk-ai/fix/cicd/pr-target-enhance
fix(cicd): pr-target clean msg + git app token
dev-0.40.0-rc.208
2026-05-08 11:20:30 +02:00
aesoft 4ebda52f5a fix(cicd): pr-target clean msg + git app token
inform user how to solve CI pr-target failing check
2026-05-08 11:00:50 +02:00
aesoft 380a7c9f11 Merge pull request #1610 from mykaul/fix/go-bench-no-json
fix: don't inject -json for go test -bench runs
2026-05-08 10:35:02 +02:00
xdm67x fa7020b43c refactor(warn): src/core/utils.rs has an unused error warning at compilation 2026-05-08 10:09:15 +02:00
Yaniv Michael Kaul b058c960f4 fix: don't inject -json for go test -bench runs
When -bench is present, benchmark output is already compact and useful.
Injecting -json causes the filter to discard benchmark results since they
don't produce pass/fail events the JSON parser expects.

Fixes #1609
2026-05-08 09:53:49 +03:00
Nicolas Le Cam 5cfb8e1d2b fix: new rewite_command test call after rebase 2026-05-08 01:22:08 +02:00
Nicolas Le Cam 20cac8a4e7 fix: minor code cleanup, avoid duplicating logic 2026-05-08 01:22:08 +02:00
Victor Sumner 041de2b6ba fix(hooks): address transparent prefix review comments 2026-05-08 01:22:08 +02:00
Victor Sumner fdf0ed0b59 fix(hooks): address transparent prefix review 2026-05-08 01:22:08 +02:00
Victor Sumner b234bc6db1 fix(hooks): compose env and transparent prefixes 2026-05-08 01:22:08 +02:00
Victor Sumner 998f1ee0a3 feat(hooks): add transparent_prefixes config for wrapper commands
Command wrappers like shadowenv (https://github.com/Shopify/shadowenv),
`direnv exec .`, `nix develop --command`, `docker exec <container>`,
`poetry run`, and `bundle exec` sit in front of every command in their
respective project layouts. When rtk is driving a Claude Code / Gemini /
Copilot / opencode hook, these wrappers defeat the rewrite — `rtk
rewrite "shadowenv exec -- git status"` returns exit 1 (no rewrite)
because the registry can't see past the wrapper to the inner `git
status`. Every build tool, test runner, linter, and `git` invocation
in such a layout stays uncompressed.

rtk already solves exactly this shape for shell builtins via
SHELL_PREFIX_BUILTINS (`noglob`, `command`, `builtin`, `exec`,
`nocorrect`): strip the prefix, recurse on the inner command, re-prepend
the prefix to the rewrite. This commit extends that pattern with a new
[hooks].transparent_prefixes config field so users can register
multi-word wrappers that don't change what runs, only how.

  [hooks]
  transparent_prefixes = ["shadowenv exec --", "direnv exec ."]

With that config, `rtk rewrite "shadowenv exec -- cargo test"` becomes
`shadowenv exec -- rtk cargo test` and exits 3 (ask, matching the
existing ask semantics for inner commands).

Implementation:

- New `rewrite_command_with_prefixes(cmd, excluded, transparent_prefixes)`
  public entry. The original `rewrite_command(cmd, excluded)` is kept as
  a thin back-compat wrapper that passes an empty prefix slice, so the
  ~150 existing unit-test call sites don't need updating.
- `transparent_prefixes: &[String]` threaded through `rewrite_compound`,
  `rewrite_segment`, `rewrite_segment_inner`.
- In `rewrite_segment_inner`, a second strip loop runs after the
  SHELL_PREFIX_BUILTINS loop, with identical strip-recurse-reprepend
  semantics. Matching is whole-word via the existing `strip_word_prefix`
  helper (multi-word prefixes like `"shadowenv exec --"` are handled
  by-value — byte-level `starts_with` plus a space check).
- Recursion is bounded by the existing MAX_PREFIX_DEPTH so pathological
  or self-referential configs cannot stack-overflow.
- Production callers (`hooks/rewrite_cmd.rs`, `hooks/hook_cmd.rs`,
  `main.rs`) now load both `exclude_commands` and `transparent_prefixes`
  from config in the same `Config::load()` call — no new I/O.

Tests (14 new):

- config: 3 TOML roundtrip tests (present, missing, mixed with older
  fields).
- registry: 11 behavior tests — strip/reprepend, unknown inner returns
  None, unmatched passthrough, composed with shell builtin, multiple
  prefixes configured, whole-word matching, empty-rest None, blank-entry
  skip, compound `&&` with prefix on both segments, excluded-inner
  returns None, recursion bounded.

Design principles (from CONTRIBUTING.md):
- Extensibility: extends an existing, documented pattern.
- Zero Overhead: config load already happens on every hook invocation;
  this reads one additional vec. Empty `transparent_prefixes` is the
  default and adds one cheap loop-over-zero-elements on the hot path.
- Correctness vs Token Savings: without this, hook rewrites silently
  miss every command run through a wrapper — exactly the kind of
  correctness gap the principle warns against.
2026-05-08 01:22:08 +02:00
Sam Severance f2da381ae2 fix: correct ARCHITECTURE.md path in README links
The file lives at docs/contributing/ARCHITECTURE.md, not at the repo
root — both the nav header and Documentation section pointed to the
wrong location.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 10:02:49 -04:00
Artiom Tofan c5245d74fa fix(dotnet): 🐛 format warnings section in build/test/restore outputs
- Refactor warning formatting to improve consistency across output sections.
- Ensure warnings are displayed correctly in all relevant output formats.
2026-05-07 15:54:18 +02:00
Artiom Tofan 271bc53f35 fix(dotnet): 🐛 format build/test/restore output summaries
- Improve formatting of output summaries for build, test, and restore commands.
- Ensure status lines are emitted last for better stream consumption.
2026-05-07 15:54:18 +02:00
Artiom Tofan 106305b197 fix(dotnet): 🐛 format build/test/restore output sections
- Separate warnings and errors into distinct sections.
- Ensure status line is emitted last for clarity.
- Maintain consistency with native `dotnet` output behavior.
2026-05-07 15:54:18 +02:00
Artiom Tofan ed161b0a33 fix(dotnet): move build/test/restore status line to the bottom
The `ok` / `fail` verdict line was emitted at the top of the filtered
output, before errors and warnings. Consumers reading the tail of the
stream — `| tail -N`, IDE log followers, agent watch/monitor loops,
bounded-context-window readers — saw error noise followed by EOF with
no verdict anywhere near the end, silently breaking any agent loop that
gates the next step on build success.

Reorder `format_build_output`, `format_test_output`, and
`format_restore_output` to emit the body first, then the separator
(only when the body is non-empty), then the verdict header last,
matching native `dotnet` which ends with `Build succeeded.` or
`Build FAILED.`.

Add three regression tests using strict `output.lines().last()` plus a
`tail -5` inclusion assertion so future regressions that append a
trailing context line get caught.

Closes #1574

Signed-off-by: Artiom Tofan <arto@queue-it.com>
2026-05-07 15:54:18 +02:00
SADIK KUZU f0136afde3 Update telemetry documentation link to use 'master' branch 2026-05-07 14:08:37 +03:00
aesoft 833026b893 Merge pull request #312 from kherembourg/feat/gradlew-android-support
feat(gradlew): Gradle support for Android/Kotlin developers
2026-05-06 19:41:13 +02:00
Kevin 9e3a5ae68d fix(gradlew): use resolved_command for system gradle fallback
new_gradle_command() now uses resolved_command("gradle") for the two
fallback branches (Windows + Unix when no local wrapper is present),
matching how cargo / golangci-lint / etc. resolve system binaries.

Local wrappers (./gradlew, gradlew.bat) stay as string literals — they
are relative paths, not on PATH, and semgrep's dynamic-command-execution
rule needs literals here.

Net effect: PATHEXT-aware resolution on Windows (.CMD/.BAT shims work),
no behavioural change on Unix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 18:27:34 +02:00
Kevin 024c4a674c refactor(gradlew): align with shared runner pattern
Replaces custom run_streaming / run_batch / run_passthrough / ProgressIndicator
with the shared runner helpers used by cargo and other commands:

- Build → runner::run_streamed with a BuildLineFilter implementing StreamFilter
- Test/Lint/Connected/Deps → runner::run_filtered with the existing filter_*
  closures (filter_test, filter_connected, filter_lint, filter_dependencies)
- Other / verbose flags → runner::run_passthrough(tool, args, verbose)

Benefits inherited from runner.rs: ChildGuard zombie prevention, 10 MiB output
cap, broken pipe handling, proper Result<i32> exit-code propagation.

run() now returns Result<i32> like cargo_cmd / golangci_cmd. main.rs updated
to forward the exit code with `?` directly (no manual `0` wrapper).

All Command::new() invocations remain string literals (semgrep
dynamic-command-execution rule).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 17:39:24 +02:00
Kevin 36ec02d132 fix(gradlew): satisfy semgrep dynamic-command-execution rule
Extract a new_gradle_command() helper that uses string literals in
every Command::new() branch. The .semgrep.yml dynamic-command-execution
rule rejects Command::new(var) — semgrep needs to statically audit
the executable set.

Same runtime behaviour: prefer ./gradlew (or gradlew.bat on Windows),
fall back to gradle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 17:27:24 +02:00
Kevin 71d285fc42 feat(gradlew): add Gradle/gradlew support with streaming filters
Adds rtk gradlew command for build, test, lint, and dependency
operations on Gradle projects. Filters task progress noise, preserves
build scan URLs, test failures, lint violations, and compiler warnings.

Recognises ./gradlew, gradlew, gradlew.bat, and gradle invocations.
Surfaces unit-test report paths and shows a progress indicator for
long-running tasks.

Targets 75% savings (90% on test, 80% on build).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 10:59:04 +02:00
aesoft d395f975c3 Merge pull request #392 from rtk-ai/fix/address-issue-384
fix(init-uninstall): uninstall removes --claude-md artifacts on Windows
2026-05-05 09:32:05 +02:00
aesoft bf24972e7d Merge pull request #1462 from rtk-ai/cicd-auto-next-release
feat(cicd): add auto next release parser
2026-05-05 09:28:25 +02:00
Adrien Eppling aad0db8b52 fix(init-uninstall): uninstall removes --claude-md artifacts on Windows 2026-05-05 08:58:23 +02:00
aesoft b5500bb6bf Merge pull request #1586 from KuSh/git-stash-nothing
refactor(git): Fix stash status detection for all cases
2026-05-04 22:12:36 +02:00
aesoft 42f0203aaf Merge branch 'cicd-auto-next-release' of https://github.com/rtk-ai/rtk into cicd-auto-next-release 2026-05-04 21:14:50 +02:00
aesoft b1233ab3fb fix(cicd): match allowed repo list in pr bodies
for next release body auto write

create a regex with pipes of list of allowed repo to be matched

added allowed_repos in cicd env
2026-05-04 21:11:13 +02:00
aesoft 5987333209 fix(cicd): match ":" for body prefix to catch
Co-authored-by: Nicolas Le Cam <niko.lecam@gmail.com>
2026-05-04 20:50:36 +02:00
aesoft 17ffe624d4 Merge pull request #1238 from KuSh/dotnet-flakiness
fix: dotnet cmd test flakiness
2026-05-04 20:32:09 +02:00
aesoft 7e552aeeba Merge pull request #1532 from KuSh/clippy-fixes
chore: Fix clippy warnings
2026-05-04 20:25:28 +02:00
aesoft e456be1c16 Merge pull request #1451 from MaxenceB59/fix/ls-locale-glob-issue-844
fix(ls): handle all file types (device, pipe, socket) in ls filter
2026-05-03 19:14:27 +02:00
Maxence Bombeeck cac8ce775b fix(ls): handle device files (block, char, pipe, socket) in ls filter
Character devices (c), block devices (b), pipes (p), and sockets (s)
were silently dropped by compact_ls because only regular files (-),
symlinks (l), and directories (d) were handled. This caused
`rtk ls /dev/ttyACM*` to return "(empty)".

Closes #844
2026-05-03 18:25:55 +02:00
aesoft 492aa76ed3 Merge pull request #1009 from KuSh/broken-pnpm-i
fix(pnpm): install don't take a list of packages
2026-05-03 16:46:49 +02:00
aesoft f75a10b1a2 Merge pull request #1371 from ousamabenyounes/fix/issue-1362
fix: head/tail multi-file rewrite falls back to native command (#1362)
2026-05-03 16:24:23 +02:00
aesoft bf6d4b2ea2 Merge pull request #1338 from lumincui/fix/ls-locale-fallback
fix(ls): LC_ALL=C + fallback to raw on unrecognized locale
2026-05-03 16:05:09 +02:00
patrick 2ed53c7fa2 fix(curl): gate force_tee_hint, extend JSON heuristic, avoid full-body alloc
Follow-up to the initial #1536 fix after a deeper review pass.

- force_tee_hint() is no longer called on the passthrough path. Previously
  every non-TTY pipe invocation (curl | jq, curl | python -m json.tool —
  the exact scenarios this PR fixes) was still writing a tee log file as a
  side effect, which is wasteful: the tee file's purpose is to give the
  LLM a recovery path when output is truncated, and we are no longer
  truncating in those cases.

- looks_like_json now also matches bare top-level JSON strings (e.g.
  /api/token endpoints returning a long quoted token). Previously a
  >500-byte bare JSON string on a TTY would still get truncated mid-stream
  and produce invalid output.

- FilterResult.content is now Cow<'_, str> so the passthrough path no
  longer copies the whole body. For multi-MB curl responses piped through
  rtk this eliminates a full-size allocation.

- Exit code from curl is propagated via Ok(result.exit_code) instead of
  the previously hardcoded Ok(0). On the success path the value is 0
  anyway, but the inconsistency with the early-exit branch above made the
  intent unclear.

Tests: 9 -> 11 (added bare-JSON-string passthrough and a Cow::Borrowed
assertion verifying the passthrough paths don't allocate). cargo test
--all: 1693 passed, 6 ignored.

Verified end-to-end against jsonplaceholder.typicode.com/posts (~27 KB,
100 entries, parseable) and a randomly-generated 100-entry / 52 KB / 1450-line
JSON served from a local http.server (rtk output byte-identical to source
modulo the trailing newline added by println!).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 11:12:38 +02:00
patrick 02da3d0702 fix(curl): JSON passthrough + IsTerminal gate to prevent invalid JSON output
`rtk curl` was unconditionally truncating any response >=500 bytes when a
tee hint was available, inserting the literal `... (N bytes total)` marker
mid-stream. For JSON bodies this produces invalid, unparseable output and
silently breaks every downstream `jq`, `python -m json.tool`, or agent
pipeline that consumes `rtk curl`.

Two changes in `filter_curl_output`:

1. JSON heuristic passthrough — if the trimmed body starts/ends with
   matching JSON brackets, return it unchanged. The body is already
   buffered in memory so the check is essentially free.

2. `is_terminal()` gate — only truncate non-JSON output when stdout is
   a TTY. Pipes and shell redirects (`> file`, `| jq`) now receive the
   full body, matching what `curl -o file` already does and closing
   the silent-data-loss path described in #1282.

The tee file is still written for inspection, but the hint line is
suppressed in the passthrough cases so it never leaks into pipes.

Tests: existing 5 cases updated to pass `is_tty=true` (preserve TTY-mode
assertions); 4 new cases cover JSON object/array passthrough at
>500 bytes and pipe-mode (non-TTY) full-body delivery.

Verified end-to-end against the public repro from the issue:
`rtk curl -s https://jsonplaceholder.typicode.com/posts | python3 -c
'import sys,json; print(len(json.load(sys.stdin)))'` now returns 100.

Closes #1536
Refs #1282

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 11:12:38 +02:00