2061 Commits

Author SHA1 Message Date
Nicolas Le Cam 0924356b4c Merge pull request #3728 from esidorenko-sl/fix/windows-msys-child-arg-quoting
fix(core): quote child arguments so MSYS children receive them intact
dev-0.50.0-rc.444
2026-09-19 01:11:20 +02:00
Nicolas Le Cam 0022842eb2 Merge pull request #3008 from deqingLv/feat/trae-hook-integration
feat(hooks): add Trae IDE integration
dev-0.50.0-rc.443
2026-09-19 00:31:35 +02:00
Nicolas Le Cam 64a7010b21 fix(hooks): identify Trae registrations by where they fire, not just by command
Matching the RTK command alone settled the round-1 defect, where a matcher or
timeout the user had edited made uninstall report "nothing to remove" and a
reinstall append a duplicate. It also went one step too far in both directions,
and this restores the two distinctions that were lost with it.

Presence now only counts a registration that would run for the tool RTK serves:
a group with no matcher, or one naming RunCommand among its `|`-separated
tools. Anything unrecognised counts as not covering RunCommand, so an install
adds an entry that fires rather than skipping one that never would. Removal
stays matcher-blind, which is what round 1 asked for, but skips an entry whose
explicit type is not `command`: a `prompt` entry is by construction the user's,
and deleting it also took the group and its `matcher` and `description` keys.

The "Already updated" list was also per-run, so the rerun the documentation
recommends after a write failure reported "none" while a target was fully
installed. It is now seeded from the preflight, and the uninstall path — which
has the same two-target failure mode — reports it too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-19 00:19:19 +02:00
Egor Sidorenko eb11789de9 fix(core): quote child arguments so MSYS children receive them intact
std::process::Command wraps an argument in quotes only when it contains a
space or a tab, so an argument like a"b reaches the raw command line bare.
MSVCRT and UCRT parse that back correctly, Cygwin and MSYS do not, which is
why `rtk grep -c '"type"'` silently matched nothing (#3727). Re-encode with
libuv's quote_cmd_arg rules, and only when the argument contains a quote, so
every argument that works today keeps its exact bytes. Batch programs stay
on the old path: raw_arg would bypass std's CVE-2024-24576 mitigation, and
gradlew.bat and mvnw.cmd both reach run_passthrough.

tree forwards the user's own arguments the same way (#4101). MSYS2 ships an
MSYS-linked tree, so it belongs with ls, wc and find rather than with the
native-only spawn sites, which are deliberately left alone.
2026-09-18 22:35:23 +05:00
lvdeqing ceae215ff7 test(hooks): scope Trae audit assertion to Unix as reviewed 2026-09-18 15:23:56 +08:00
lvdeqing 0184ba2425 fix(hooks): address Trae portability and partial install diagnostics 2026-09-18 15:08:49 +08:00
lvdeqing 651441cb52 chore: merge latest develop into Trae hook integration 2026-09-18 14:47:34 +08:00
lvdeqing e988098e22 fix(hooks): identify Trae registrations by command alone 2026-09-18 14:32:36 +08:00
lvdeqing dbecb980f9 fix(hooks): honor audit directory override for portable Trae tests 2026-09-18 14:26:58 +08:00
Nicolas Le Cam 6d104308c5 Merge pull request #776 from mvanhorn/osc/682-suppress-hook-warning-config
feat(config): add suppress_hook_warning option
dev-0.50.0-rc.442
2026-09-18 02:24:05 +02:00
Nicolas Le Cam d2e906a0fe fix(gain): honour suppress_hook_warning, and pin the env/config composition
`rtk gain` printed its own missing-hook line from a bare `status()` match,
outside `maybe_warn`, so neither `hooks.suppress_hook_warning` nor
`RTK_SUPPRESS_HOOK_WARNING` reached it — on the report the no-hook audience
reads most. Gate that arm on the same helper; the outdated-hook prompt stays
visible, as it does everywhere else.

The new unit tests exercise the parser alone, so folding env and config
together with `||` — which drops the falsy force-off — left the whole suite
green. Drive the composition through the binary instead, and give the env
table the `=0` row that overrides the config flag.

The suite pins `XDG_CONFIG_HOME`/`XDG_DATA_HOME` to the temporary home and
seeds the config in both the XDG and the macOS location, so the loader cannot
resolve past it: `dirs::config_dir` is `~/.config` on Linux but
`~/Library/Application Support` on macOS, and a runner that exports either
`XDG_*` reached the developer's own config before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 02:16:12 +02:00
Nicolas Le Cam 0a71fcf3b6 Merge pull request #4048 from TechWizard9999/fix/4037-flaky-dotnet-trx-mtime
fix(tests): make dotnet_trx mtime-dependent tests deterministic
dev-0.50.0-rc.441
2026-09-18 01:31:23 +02:00
Nicolas Le Cam 8495f63bf7 Merge pull request #3275 from breisnerlopez/fix/pnpm-strip-global-opts
fix(pnpm): rewrite pnpm commands with global flags before the subcommand
2026-09-18 01:24:17 +02:00
Nicolas Le Cam 1281273e6e fix(tests): set trx mtimes via std instead of a new dev-dependency
std::fs::File::set_modified has covered this since Rust 1.75, well under
the crate's 1.91 rust-version, so the filetime dev-dependency buys nothing.
Dropping it also drops the Cargo.toml hunk, which added a second
[dev-dependencies] table and made the manifest a duplicate key once develop
grew its own.

Extend the same treatment to the remaining sleep-ordered mtime test,
merge_test_summary_from_trx_ignores_stale_fallback_file, whose 5 ms sleep
left the stale/fresh distinction to filesystem mtime granularity.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 01:18:36 +02:00
Matt Van Horn 4e53f760fe fix: scope suppress_hook_warning to missing hooks and parse the env override
Parse RTK_SUPPRESS_HOOK_WARNING as a truthy/falsy override that falls
back to config when unset or unrecognised, keep the HookStatus::Ok fast
path free of config loading, and suppress only the missing-hook warning
so the outdated-hook upgrade prompt stays visible.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CNmJZVV9u6pBhcwVhwkPp6
2026-09-16 07:46:02 -07:00
Matt Van Horn 0e7a41eb52 feat(config): add suppress_hook_warning option
Add hooks.suppress_hook_warning config option and RTK_SUPPRESS_HOOK_WARNING
env var to disable "No hook installed" and "Hook outdated" warnings.

Users running rtk via CLAUDE.md instructions instead of hooks, or with
tools like OpenCode, get these warnings on every command. The warnings
waste tokens and confuse AI agents since rtk is working correctly.

RTK_SUPPRESS_HOOK_WARNING=1 suppresses; any other value forces the warning
on; unset falls back to the config file. Both default to false so existing
behavior is unchanged. The env parse follows the repo's
as_deref() == Ok("1") convention.

The suppression check runs before status() so the suppressed path does not
pay for the hook probe.

Documented in configuration.md (the hooks block and the env var table) and
README.md.

Fixes #682

Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
2026-09-16 07:27:24 -07:00
lvdeqing ca24862484 chore: merge latest develop into Trae hook integration 2026-09-15 20:24:01 +08:00
Nicolas Le Cam 5e0f92cd10 Merge pull request #3782 from KuSh/chore/rust-edition-2024
chore: migrate to Rust edition 2024 and adopt let-chains
dev-0.50.0-rc.439
2026-09-14 20:21:46 +02:00
TechWizard9999 9082031924 fix(tests): make dotnet_trx mtime-dependent tests deterministic
test_parse_trx_files_in_dir_since_ignores_older_files flaked when
filesystem mtime granularity quantized new.trx's mtime at or below
the 'since' threshold, leaving zero summaries and panicking on
.expect("merged summary") (fixes #4037).

Set explicit mtimes (now-10s / now+10s) via the filetime dev crate
instead of deriving them from write order, and apply the same fix to
test_find_recent_trx_in_dir_picks_newest_trx, which relied on a 5ms
sleep plus max_by_key over unspecified read_dir order.
2026-09-14 16:35:33 +05:30
breisnerlopez 6c84b82388 fix(pnpm): gate global-opt strip to the rtk pnpm rule (review round 1)
The strip ran in classify_command but the rewrite matches rewrite_prefixes
against the original flag-first text. For the tool rules reachable via
`pnpm exec`/`pnpm run` (`pnpm -r exec vitest`, `pnpm -r lint`, ...) the
stripped form matched a tool rule, so classify returned Supported while the
rewrite never fired — discover/session then reported savings the hook cannot
deliver.

Only adopt the stripped form when it routes to the `rtk pnpm` rule
(matches_pnpm_rule); every form the PR targets (install/list/ls/i/outdated/run)
is that rule, so nothing it claims is lost, and the tool rules classify exactly
as on develop.

Also fold the two optional items from the review:
- assert `pnpm -x install` -> None, making the fixed-set guard load-bearing.
- tolerate extra spaces before the flag (`pnpm  -r  install`) via trim_start,
  while keeping the single-ASCII-space boundary that strip_word_prefix requires
  so classify and rewrite never diverge on a tab/other whitespace separator.
2026-09-14 07:08:19 +02:00
Nicolas Le Cam bf2f7c7c12 chore: ignore the style-edition reformat in git blame
The style-edition reformat touched 69 files without changing behaviour,
which buries the real authorship of those lines. GitHub's web blame applies
.git-blame-ignore-revs automatically; locally it needs blame.ignoreRevsFile
set, so CONTRIBUTING now says so where contributors first clone.

Only the reformat is listed. The let-chain commit also touches many files
but changes control flow and drops a crate-wide lint allow, so its
authorship is real and should stay visible in blame.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 01:27:25 +02:00
Nicolas Le Cam 75b30a442c fix(hooks): don't abort init --status on an unreadable Cursor hook
show_claude_config read the Cursor hook file only to compute _is_thin, which
nothing reads. The `?` on that read meant an unreadable hook file aborted
`rtk init --status` before it printed the rest of the report -- a status
command failing on the thing it is meant to report about. The executable-bit
check above it is what the branch actually uses.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 01:27:25 +02:00
Nicolas Le Cam d00c514edd refactor: adopt let-chains
Let-chains are edition 2024 syntax, so clippy::collapsible_if now fires on
every nested `if let` / `if` pair, and with warnings = "deny" they are build
errors rather than suggestions. Applied with cargo clippy --fix, which
handles all of them in one pass, then cargo fmt to re-indent the collapsed
bodies.

The deepest cases flatten four levels of nesting into one condition:

    if let Some(cutoff_time) = cutoff
        && let Ok(meta) = fs::metadata(file_path)
        && let Ok(mtime) = meta.modified()
        && mtime < cutoff_time
    {
        continue;
    }

Drops the crate-wide clippy::collapsible_if allow added in the previous
commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 01:27:25 +02:00
Nicolas Le Cam 7c18567155 chore: migrate to Rust edition 2024
Bump edition 2021 -> 2024. rust-version stays at 1.91, already well above
the 1.85 floor the edition needs; docs/guide/resources/troubleshooting.md
still claimed 1.70+, which is where a failed `cargo install --git` lands.

Four things the edition forces:

- std::env::{set_var,remove_var} are unsafe in 2024 with no safe std
  replacement. Rather than wrap the test call sites in unsafe -- which the
  crate denies and .semgrep.yml flags -- route them through temp-env, a
  dev-only dependency whose closure API is safe and which restores the
  previous value even when the body panics. The hand-rolled CLAUDE_DIR_LOCK
  and PI_DIR_LOCK guards existed only to serialise those mutations and are
  now redundant; CWD_LOCK and TEST_ENV_LOCK stay, they order more than the
  env var itself.

- unsafe_op_in_unsafe_fn is on by default, so the libc calls in the proxy
  signal handler and in stream.rs's relay handler need explicit unsafe
  blocks, scoped to the libc calls themselves.

- `gen` is a reserved keyword, so the closure by that name in diff_cmd.rs
  becomes make_lines.

- Tightened tail-expression temporary scopes let clippy prove the binding in
  setup_test_env is inlinable, so let_and_return now fires there.

if_let_rescope changes when the scrutinee temporary drops in an if let/else.
The two sites in show_claude_config take cargo fix --edition's match rewrite,
which keeps the 2021 drop timing.

rustfmt.toml is kept rather than dropped: cargo fmt passes --edition from
Cargo.toml, but a bare rustfmt invocation has no crate context and falls
back to edition 2015, which cannot parse the let-chains the next commit
introduces. Pinning it there keeps format-on-save and pre-commit hooks in
agreement with CI.

clippy::collapsible_if is allowed crate-wide for now; the follow-up commit
adopts let-chains and removes the allow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 01:26:43 +02:00
Nicolas Le Cam 70ec493d0d chore: list command modules explicitly instead of via automod
Every ecosystem mod.rs under src/cmds/ generated its module list with
automod::dir!(). rustfmt only follows literal `mod` items and cannot expand
macros, so `cargo fmt` never reached any of those files -- and neither did
CI's `cargo fmt --all -- --check` gate, which has been silently passing
over half the crate.

Demonstrated by appending `fn   __probe( )->u8{let    x=1;x}` to a file
under src/cmds/: with automod, `cargo fmt --all -- --check` reports no
diff; with an explicit `pub mod`, it reports the diff and `cargo fmt --all`
fixes it. The preceding commit had to invoke rustfmt directly for the same
reason; from here `cargo fmt` covers the crate on its own.

Listing modules by hand trades one failure mode for another, so build.rs
now guards the new one: automod compiled any stray .rs file, whereas an
explicit list silently drops a file whose `pub mod` line is forgotten --
never compiled, never linted, tests never run, and check-test-presence.sh
still reporting PASS because it only greps the file for #[cfg(test)]. The
build now fails with the missing declaration named.

Declaring the modules explicitly also exposed clippy::module_inception on
cmds::git::git, which clippy skips inside macro-generated code. git.rs is
renamed to git_cmd.rs, which resolves the lint and matches the convention
its siblings already follow -- diff_cmd, gh_cmd, glab_cmd, gt_cmd. Docs
that point at the module are updated; sample command output that merely
shows a "git.rs" path is left alone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 01:26:43 +02:00
Nicolas Le Cam ad63139576 chore: reformat under rustfmt style edition 2024
Pin style_edition = "2024" in rustfmt.toml and reformat, ahead of the
edition 2024 bump. Setting style_edition explicitly decouples the reformat
from the crate edition, so this lands on edition 2021 and CI's
`cargo fmt --all -- --check` still passes.

Run through rustfmt directly rather than `cargo fmt`. Every module under
src/cmds/ is currently declared by automod::dir!, and rustfmt only follows
literal `mod` items, so `cargo fmt` cannot see those files -- the next
commit makes them reachable. Roughly two thirds of the diff is therefore in
src/cmds/, mostly the version-sorted imports style edition 2024 introduces.

No logic changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 01:26:21 +02:00
Nicolas Le Cam d402152ffa Merge pull request #1422 from JackDanger/fix/suppress-hook-warn-during-init
fix: suppress hook warning during rtk init and verify
dev-0.50.0-rc.438
2026-09-14 01:20:47 +02:00
Nicolas Le Cam 06d538728c test: cover which commands get the daily hook reminder
Pins both directions: the commands that report hook state themselves stay
quiet, and the filtered commands still warn. Also pins the reason the
suppression is worth having — `maybe_warn` touches the once-a-day marker, so
warning on a meta command would leave the next filtered command silent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 01:01:14 +02:00
Nicolas Le Cam cfe248c1f6 Merge pull request #3941 from iliaal/fix/faithful-head-tail-windows
fix(read): make head/tail rewrites faithful to the native commands
dev-0.50.0-rc.437
2026-09-14 00:59:57 +02:00
Nicolas Le Cam 784d347011 test(read): isolate the rewrite test from the developer's rtk config
`rewritten_head_spellings_match_native_on_non_utf8_files` isolates
`CLAUDE_CONFIG_DIR` but reads the ambient `XDG_CONFIG_HOME`, so a config
carrying `exclude_commands = ["head", "tail"]` suppresses the rewrite and
the exit-code-3 assertion fails. Clean runners have no such config, so the
test passes in CI and fails only for the developers most likely to have
opted out of these very rewrites.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 00:45:35 +02:00
Nicolas Le Cam e224b159af docs(read): point the head/tail rewrite docs at --head-lines
The pipeline diagram, the discover walkthrough and the `rtk read` option
table still described the `--max-lines` mapping this branch replaced, and
the repo's own suggest hook still proposed `--max-lines N` for `head -N`
— the mapping this branch exists to correct.

Drop the `head -` disjunct in the rewrite guard: every string with that
prefix also has the `head ` prefix that sits next to it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-14 00:45:35 +02:00
Nicolas Le Cam 2ff2f71711 Merge pull request #1298 from rtk-ai/fix/tracking-weighted-aggregations
fix(tracking): weighted savings rate in low_savings_commands and avg_savings_per_command
dev-0.50.0-rc.436
2026-09-14 00:37:18 +02:00
Nicolas Le Cam cb5e5994e1 fix(tracking): align the telemetry rates with rtk gain and pin them in memory
`get_by_command` moved to the volume-weighted rate while this branch was
open (#891), summing every call and guarding the division at group level.
The two telemetry queries now use the same shape: the row-level
`WHERE input_tokens > 0` is gone, so a call with no input that still
printed something counts against its command exactly as it does in the
By Command table, and `HAVING SUM(input_tokens) > 0` keeps commands that
never had any input out of both, as before.

`low_savings_commands` lists net-regressing commands: `sav > 0.0` became
`sav <> 0.0`, so only exact 0% stays with `passthrough_top`. A command
that emits more than it saves is the filter to fix first, and with the
weighted rate the old bound also dropped commands the unweighted query
used to list.

The two regression tests opened the on-disk tracker, so every `cargo test`
wrote ten synthetic rows (one at 100k input tokens) into whichever history
database `Tracker::new()` resolves to, on a developer machine the real one.
They now use `Tracker::new_in_memory()` like the rest of the module, and
`test_avg_savings_per_command_inner_weighted` only asserted a `0..=100`
range that the unweighted query also satisfied. Both tests now assert the
exact weighted figures, check each listed rate against `get_summary()`,
and fail when either query goes back to `AVG`, to the row filter, or to
the positive bound.

Tests are numbered 18 and 19 after the ones develop already carries as
14-17. The `low_savings_commands` doc no longer points at a PR, and both
telemetry field tables describe the new semantics.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 21:05:32 +02:00
Nicolas Le Cam 4b6c0f00ef Merge remote-tracking branch 'upstream/develop' into pr-1298-merge 2026-09-13 20:35:13 +02:00
Nicolas Le Cam b6a171242c Merge pull request #891 from rtk-ai/fix/gain-weighted-avg
fix(gain): use weighted savings rate in per-command stats
dev-0.50.0-rc.435
2026-09-13 20:30:32 +02:00
Ilia Alshanetsky 23a1be622f test(read): isolate rewrite permission settings 2026-09-13 12:35:05 -04:00
Ilia Alshanetsky 6f4913b37b fix(read): preserve non-UTF-8 head and tail windows 2026-09-13 12:27:47 -04:00
Nicolas Le Cam 9573488935 test(tracking): cover the weighted rate with isolated in-memory cases
Move the weighted-rate regression test off the real tracking database, which
it wrote two rows into on every run, and onto an in-memory tracker. Add the
long-tailed pair that pins the weighted rate against the mean of percentages,
the same assertion through get_summary(), and a zero-input group: without the
CASE guard that last one fails on a NULL rate, and no other test covers it.

Name the 4th field of GainSummary::by_command for what it now holds, and state
the rate formula on the CommandStats warning in percentage order, with the zero
guard, so that following it verbatim cannot reintroduce the NULL.

Head the column Total% rather than Rate, keeping the shape of the Avg% it
replaces and naming the total the figure is now taken over.

Drop the hand-written CHANGELOG entry: release-please generates it from the
commit subject, and CONTRIBUTING.md asks for that file to be left alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-13 17:51:27 +02:00
Nicolas Le Cam 86668b065a Merge remote-tracking branch 'upstream/develop' into pr-891 2026-09-13 17:25:52 +02:00
Nicolas Le Cam d0c2985155 Merge pull request #1122 from carlosdagos/fix/gh-pr-no-early-exit
fix(gh): don't early exit on failure for "pr checks"
dev-0.50.0-rc.434
2026-09-13 15:17:12 +02:00
Nicolas Le Cam d105227193 fix(gh): account for every check bucket in the pr checks summary
Filtering a failing `gh pr checks` makes the summary the only thing the user
sees, so a bucket it does not count disappears. `parse_pr_check_line` dropped
every row that was not pass/fail/pending, which turned a cancelled run -- the
usual outcome when a new push supersedes CI -- into "Passed: 0, Failed: 0",
and left 5 of PR 3982's 15 checks out of the totals.

Count the remaining buckets and report them, so the summary always adds up to
the checks gh listed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 15:04:33 +02:00
Nicolas Le Cam 83b1957cca Merge remote-tracking branch 'upstream/develop' into pr-1122-clean 2026-09-13 15:04:33 +02:00
Nicolas Le Cam 0cd3eba80b Merge pull request #3542 from uuzzrm/fix/gh-checks-watch-deduplicate
fix(gh): deduplicate watched PR checks
dev-0.50.0-rc.433
2026-09-13 14:47:27 +02:00
Nicolas Le Cam 718c18530d Merge pull request #3857 from Micaso/feat/ast-grep-support
feat(ast-grep): add ast-grep filter (rtk ast-grep)
dev-0.50.0-rc.432
2026-09-13 14:37:39 +02:00
Nicolas Le Cam 83f87f92f3 test(gh): use gh's real row shape in the pr checks tests
`gh pr checks` spells a pending bucket `pending`, never `*`, and prints five
tab-separated fields with the description last. The transition test used a
shape gh does not emit; the new case carries the trailing description column
and a pending row that resolves across polls.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 12:33:46 +02:00
Nicolas Le Cam 3d2d244406 fix(ast-grep): account for every dropped line and stop wrecking scan output
Two defects in `filter_ast_grep`, both verified against ast-grep 0.45.3.

`ast-grep scan` diagnostics parse only on their locator line, so filtering
line by line kept `  ┌─ a.rs:2:13` and dropped the rule id, severity,
message and source line — at exit code 0, so it read as success. The
whole-output fallback never fired because `order` was not empty.
`unparsed_signal()` now passes any shape through untouched when a single
non-blank line fails to parse, which is what `search.rs` already does for
grep/rg. This also covers `--heading` mode and Windows drive-letter paths,
where `[^:]+` cannot match `C:\src\a.rs`.

The per-file overflow hint was computed as `entries.len() - max_per_file`,
which ignores `max_total` cutting a file short: a file under its own cap
lost its remainder with no hint at all, and a file over it under-reported
the drop. Both now count against what was actually printed.

The hint said "matches" while counting lines. ast-grep prints one line per
matched source line and a structural match spans several, so a repo search
reported "19 more matches" where five matches remained.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-13 12:16:33 +02:00
Nicolas Le Cam f64d1d4808 fix(ast-grep): adopt PipelineSafety after merging develop
`RtkRule::pipeline_final_safe` was replaced by the `PipelineSafety` enum
on develop (#3171). The ast-grep rule still set the old field, so the
branch merged cleanly but failed to compile (E0560).

`ProducerOnly` keeps the rule's original intent: safe as a pipeline's
first stage, never as its final stage, since run() execs with stdin null.
Adding a producer-safe rule also requires listing it in
`test_pipeline_producer_safe_rule_set`, which pins the exact set.

`savings_pct` was left at the 60.0 default; the repo-wide measurement is
84.6%, which is what README and what-rtk-covers.md already claim.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-13 12:11:52 +02:00
Nicolas Le Cam 8b4c445815 Merge branch 'develop' into feat/ast-grep-support 2026-09-13 12:11:52 +02:00
Nicolas Le Cam 5626e94a63 Merge pull request #3552 from yeahjack/feat/codex-direct-hook
feat(hooks): add direct Codex command rewriting
dev-0.50.0-rc.431
2026-09-13 12:01:14 +02:00
Nicolas Le Cam ce6e277cce refactor(permissions): group rule-less hosts into one match arm
Codex and Vibe both return empty rule vectors; keeping them as separate
arms multiplies branches that have to stay in sync. Group them, sorted,
with one comment covering both.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-13 11:42:31 +02:00