Repository navigation
Next Release - #4576
Open
rtk-release-bot[bot] wants to merge 103 commits into
Open
Next Release#4576rtk-release-bot[bot] wants to merge 103 commits into
rtk-release-bot[bot] wants to merge 103 commits into
Conversation
The Windows stack-size reservation had two problems that only surface off
the MSVC toolchain.
`#[cfg(windows)]` in a build script describes the machine running the
build, not the machine the binary is for, so cross-compiling to Windows
from Linux silently skipped the flag while a Linux-targeted build on a
Windows host wrongly emitted it. Key the check off CARGO_CFG_TARGET_OS
instead, which is the target.
The flag itself is also toolchain-specific. `link.exe` understands
`/STACK:`, but the MinGW `ld` behind `x86_64-pc-windows-gnu` does not --
it reads the argument as a filename and fails the link with:
ld.exe: cannot find /STACK:8388608: No such file or directory
Select `-Wl,--stack,<bytes>` when CARGO_CFG_TARGET_ENV is `gnu` and keep
`/STACK:` otherwise. CI never caught this because windows-latest defaults
to MSVC.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: AxelRay <110029405+axelray-dev@users.noreply.github.com>
Agents gate on exit status, and hooks replace a command with whatever `rtk rewrite` returns, so the rewrite must exit with the raw command's code. Run a matrix of rewritten commands (git, ls, grep, wc, cat/head -> read, find, plus `&&`/`;` chains and python3 one-liners when available) raw and rewritten in a sandboxed repo and require identical exit codes. A second test fails if the cases stop exercising the rewrite path, so the check cannot silently degrade into comparing `sh` with itself. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WcTsSr2cKxstnvgXk2bP88
…parsed A Claude Code settings file that exists but cannot be read or parsed adds a catch-all Ask rule and a warning instead of being skipped. Refs #4282.
Clap adds -h/--help and a help subcommand to every subcommand it builds. On a subcommand that exists only to compress another tool's output those tokens are not RTK's to answer: grep -h is --no-filename, ls -h and tree -h are --human-readable, and git help log is a real subcommand. RTK replied with its own usage on stdout at exit 0, so an agent that only ever typed grep -h (the hook adds the prefix) read RTK's help as grep's matches. Only psql and ctest had opted out, one bug report at a time. release_meta_flags now walks the clap tree and releases those flags on every subcommand that forwards to a native tool, detected structurally rather than from a list. RTK's own commands keep their help, and rtk help <cmd> still reaches RTK's usage for a wrapper. Forwarding the flag exposed a second half: filters that summarise found no diagnostics in a help page and printed their empty summary instead, so cargo test --help returned nothing at all. args_utils::asks_tool_for_help guards those entry points and defers to runner::run_passthrough. Fixes #4198
Drops the docs and awareness-text changes: rewording the "always safe" claim in the agent instructions is a separate concern from the flag collision, and the README and TECHNICAL edits were not needed to ship the fix. release_meta_flags no longer recurses. disable_help_flag, disable_version_flag and disable_help_subcommand are all global settings in clap, so one call already covers the whole subtree. asks_tool_for_help now reads -h as a help request. It only read the long spellings before, so cargo build -h still reached the build filter and came back as "cargo build (0 crates compiled)". ls and tree use the long-only form, since their -h is --human-readable.
The guard was repeated at 41 filter entry points. 38 of those modules already run their child through runner::run, which holds the built Command and so can answer the question itself: requests_help reads the program name and the argv before the boundary, and swaps the mode to Passthrough. That leaves explicit guards only where the filter runs the child itself rather than through the runner: git, find, pip, uv and dotnet. requests_help_args is the same rule for those callers, so there is one definition of what a help request is. -h is a request everywhere except psql, ls, tree and grep, which spell something else with it. RTK's own package-runner prefix (pnpm exec --, npx --) is skipped so the -- it ends with is not read as the caller's boundary.
Two layers, mirroring the two halves of the bug. Over the clap tree: every wrapper path crossed with -h, --help, -V, --version and help, dropped at every position of nine argv shapes, asserting RTK never answers with its own usage and that the token still reaches the leaf. Roughly 14k parses, read off the built tree so a new subcommand joins on its own. The inverse is pinned too, or releasing everything would satisfy it. Over real binaries: rtk <tool> --help spawned against the tool itself for 24 pairs, comparing exit code and asserting the page was not collapsed to a summary. Tools that are not installed are skipped, and commands are spawned directly so a grep shell function cannot stand in for the binary. Both were mutation-checked. Removing release_meta_flags fails the first with "RTK answered `rtk ls -h` itself"; removing the runner guard fails the second with "rtk cargo build -h returned 32 bytes of the tool's 3241"; dropping tree from DASH_H_IS_NOT_HELP fails the filtering check.
Three fixes to the tests added in the previous commit, all found by CI. semgrep's dynamic-command-execution rule forbids Command::new(<variable>) anywhere under src/, test modules included. The runner tests built a Command only to feed requests_help, so they now exercise requests_help_args, which takes the tool name as a string, and one adapter test keeps a literal program. Windows names the binary rtk.exe, so the "Usage: rtk " marker never matched. That failed the positive assertion and, worse, made the negative one pass for the wrong reason. The marker now stops at the stem. on_path joined PATH entries with a bare name, which on Windows finds the extensionless npm script rather than npm.cmd and fails the spawn with error 193. It now walks PATHEXT there. The cases whose Windows namesake is an unrelated program (find, tree) or needs a Unix toolchain (grep, ls, wc) are skipped, and the two tests asserting GNU/BSD flag semantics are unix-only.
pytest format_session_duration appends " (H:MM:SS)" once a run exceeds a minute. Allow that optional clock so long suites are still parsed.
Signed-off-by: tayfuryldz <yildiztayfur668@gmail.com>
Signed-off-by: tayfuryldz <yildiztayfur668@gmail.com>
Signed-off-by: tayfuryldzz <yildiztayfur668@gmail.com>
`bun test --coverage` prints its table and `--bail` prints "Bailed out after N failures", and neither survived the summary extractor. The bail case is the costly one: bun prints no count lines when it aborts, so the summary read as a complete run of however many tests happened to execute before the abort. The table is tracked from its header to the next blank line rather than by counting column separators, so a source frame holding `a || b` is not mistaken for a row, and its rows are capped at CAP_LIST: one row per file makes it the only part of the summary that grows with the repo. Fixtures are real bun 1.3.14 runs.
Two shapes the bun fixtures did not reach. A run killed by SIGKILL prints the banner and nothing else, so the raw-tail fallback is all that stands between an aborted run and a summary that reads clean. And 40 failures in one run exercise MAX_RUNNER_FAILURES, which no bun fixture was large enough to reach. Both are real bun 1.3.14 captures. No behaviour change.
Bun sorts the coverage table by path, so capping it by a plain head kept whichever files came first alphabetically and dropped the ones with a gap, which is what the flag was passed for. On a 41 file project the only row below 100% was last in the sort, so it never appeared and could not be retrieved. The table is buffered now and filled in priority order: its structure, then the rows reporting a gap, then whatever still fits, each in bun's own order. What the cap drops is announced as files, not table lines, and written out through force_tee_tail_hint, so a capped run is recoverable like the other capped lists in the tree. The cap is pinned against real output over it: exactly the cap is shown, the notice appears once and accounts for every dropped line, and a table of exactly the cap announces nothing.
Resolves the test-import conflict in src/main.rs by keeping develop's test_isolation import and dropping clap::Parser, which this branch no longer needs. The help fuzz now spawns through common::rtk_command() rather than naming CARGO_BIN_EXE_rtk, so the child writes to the test's scratch data directory instead of the contributor's own. core::test_isolation fails the suite on a spawn that skips it (#3758), which is what turned the merged branch red.
…n capture too Review round 1 on #4348. Blocker 1(a): a help request still reached filters that run the child through exec_capture rather than runner::run, and several answered with a plausible result: jest returned 2161 bytes of its 26881, pnpm outdated reported "48 outdated packages" parsed out of a help page, wget reported a download. The guard now also sits in stream::capture, which every exec_capture caller passes through. exec_capture_probe is the way out for a command RTK issues itself: a version probe asks --version to read the answer, not to show it, and golangci runs one. Blocker 1(b) and 1(c): asks_for_usage goes through arg_tokenizer instead of comparing raw strings, per rule 6 in rust-patterns.md. A per-tool spelling picks the dialect, so dotnet's -? and /? and Go's -help are read as the atomic names they are; a flag carrying a value no longer counts, so `cargo install x --version 1.2.3` stays filtered; and a tool that forwards past -- gets that region scanned as the argv it is, so `cargo test -- --help` is libtest's usage while `grep -- --help` is still a pattern. git and dotnet keep their own guards rather than relying on capture: by then RTK has injected its globals, and git's --no-pager turns the man page into a one-screen usage. pip's guard goes, covered by capture. kubectl/oc `extra` now carries only a usage request. Anything else runs as the caller typed it, matching kubectl's own "unknown command" rather than silently reaching a `get` pinned to -o json. Blocker 2: pins for what the mutations survived. The forwarded git argv including globals and the stash subcommand, every git_name arm, forwarded_dotnet_args, the dotnet spellings, the k8s alias split, RTK's own help on the commands that wrap nothing (read, diff, log, env), the forwarded boundary and the value forms. The integration check compares the tool's own first line rather than a length, so a page from the wrong subcommand fails.
Moving the scan onto the tokenizer brought short-flag clustering with it, and that read the h inside another flag as a request: `find -maxdepth 2` came back as raw find output instead of the compressed listing, and `mvn -Dhttp.proxyHost=…` and `gradlew -Dhttp.x=1` carry one the same way. A clustered h is almost never the flag, so it counts only when the argument is exactly `-h`. The cost is `cargo -qh`, which no longer registers; the tools that spell help with a single-dash long name (`go -help`, `dotnet -?`) are unaffected, since they are read in the MSBuild dialect where the name is atomic.
On Windows this harness reaches pip.EXE where rtk reaches pip, so the usage line the two print differs by that spelling while the page is the same. The anchor is compared with it removed. The check still fails on a page from the wrong subcommand, which is what it is for.
content_hash() kept 12 hex characters (48 bits) of SHA-256, and the store upserts on the hash, so two outputs sharing that prefix overwrote each other. Keep 16 hex characters. Existing 12-character rows still resolve by exact match, and shorter prefixes still resolve. Closes #3948
A run with fixture, teardown or collection errors ended "1 passed, 1 error" (exit 1) but rtk printed "Pytest: 1 passed": the summary parser had no arm for error(s) and the ERRORS section was skipped. Count errors, keep the run off the all-green line, and render the ERRORS blocks and ERROR short-summary lines as [ERROR] entries. Fixes #4426
…ight `walk_exceeds_limit` asks git whether `rtk git log`'s ten-commit cap actually cut anything. It was wrong in both directions: silent on walks the cap had gutted, and loud on walks it never touched. Two kinds of walk, two questions. Without a diff-based filter (`-S`, `-G`, `--diff-filter`, `--find-object`) the probe skips past the limit and asks whether anything is left. With one it has to count instead, because git applies `--skip` before such a filter and `--max-count` after it. Most of what follows is the counting branch getting an honest count, and the notice being owed at all. What the probe forwards. It may drop what only decides how git prints, and must keep what decides which commits come back -- a distinction the flags do not respect. `--line-prefix` and `--graph` are dropped because both put something in front of every record, and `--graph` draws its rail with the characters a patch begins its lines with (`|` before a diff body, `-` before a removed line), so no trimming rule serves both. But `--graph` also turns on parent rewriting, which decides which commits come back: one path here holds a single commit without it and fifteen with it, so the probe asks for `--parents` instead, which turns on the same rewriting and prints nothing beside a `%H` record. `--reverse` is dropped because it moves `--max-count`: git drains the whole walk before showing anything, so the count bounds the walk rather than what came through the filter, and eleven records became six against a selection of 836. `--check` joins `--exit-code`, whose non-zero exit reports on the diff rather than on the command. And `-c`/`--cc`/`--remerge-diff` and every `--diff-merges` format but `off` are kept whenever the walk selects by diff: they give merge commits a diff, and a diff-based filter selects on the diffs the walk produces. On a repository whose merges carry content from neither parent, `git log -S evil` selects nothing where `git log -c -S evil` selects 14. Off such a walk they are still dropped, which spares a configured `diff.external` the eleventh run of a ten-commit window. The user's own `--skip` is now reproduced in the counting branch too. RTK's has to win, so the user's is stripped and re-applied -- but only the other branch re-applied it, and the count covered commits they had already skipped past: `--skip=20 -S NEEDLE` leaves five commits and announced a cap of ten. What counts as a commit in the answer. Records are split on NUL as well as newline, because `-z` terminates them that way and the whole walk had been read as one line matching nothing. A record is a commit only at an object name's exact length -- `%H` does not abbreviate, for neither `--abbrev-commit` nor `core.abbrev` -- which keeps out the paths `--name-only -z` puts in a record of their own, where a file called `cafebabe01` had counted as a commit. And only at column 0, which keeps out the diff context of a probe that kept a merge-diff flag, in the case where that context is itself full-length hex: a file of checksums. Last, the notice is gated on git not having refused. The probe prunes `--pretty`/`--format`/`--output`, so it can succeed on arguments git rejected outright, and the notice landed under git's own `fatal:` line. Failure is not that test: git refuses with 128, 129 or 128 + n and keeps the small codes for what the diff machinery found in a walk it ran and printed in full -- 1 for `--exit-code`, 2 for `--check`. The strip these go through is the one the `diff`/`show` header already used, lifted behind a predicate so the probe can widen it without widening that header's own idea of patch shape. Going through it is what lets `-c` be dropped at all: a short flag shares its argument with whatever was clustered onto it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…it-code-regression-test
run_cli moved from src/main.rs to src/lib.rs on develop, which also skips the hook-status warning for Commands::Hook already; the telemetry reorder is carried over to its new home. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
maybe_ping is inert in any build without RTK_TELEMETRY_URL, test builds included, so no test could tell whether a hook command pings. The decision now lives in pings_telemetry, taken on the parse result, with one call site; the tests cover parsed hook commands and the invocations clap rejects (help, version, passthrough, a hook with a bad flag). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(hook): skip background checks in hook commands
…s base URL on uninstall
Port the seven missing operational-command entries and regression coverage to current develop without importing unrelated commit history.
Claude Code's worktree-isolation guard evaluates the command after the PreToolUse hook has rewritten it, and it can only verify git when it is spelled plainly. Every `rtk git …` the hook emitted was therefore refused as "cannot be shown not to be git", so no git command could run from a worktree-isolated session. The payload carries no isolation flag, but managed worktrees always live at `<repo>/.claude/worktrees/<name>`. When the payload cwd has that shape, the Claude hook adds `git` to the exclude list so it passes through untouched while the rest of the chain is still rewritten. Other hosts pass no cwd and are unchanged. Fixes #3864 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Pin the worktree exclusion: another git verb, a non-worktree .claude directory, and the user's own exclude_commands kept alongside it. The doc comment now says a worktree placed outside .claude/worktrees is not detected, and the path check uses CLAUDE_DIR. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(hooks): leave git unrewritten in Claude Code managed worktrees
`rtk gain` summed `exec_time_ms` over every tracked row. Rows recorded through the passthrough/fallback path carry no input (`input_tokens = 0`) and their duration is the wrapped process's whole lifetime, so a single interactive TUI launched as `rtk claude` adds hours of wall-clock time. On the reporter's install 131 such rows were 99.7% of `Total exec time` and inflated the average 865x (9m5s reported vs 1.15s of real filtering). Only rows with captured input now count toward the exec-time total and its average, in the summary and in the daily/weekly/monthly breakdowns (text, JSON and CSV), including the TOTAL row of the period tables. Command counts, token totals and savings percentages are unchanged. Closes #4003 Signed-off-by: Raymond Riter <rpr2998@gmail.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: jaideeppyne <jaideeppyne1997@gmail.com>
A closing marker the user quotes after the RTK block must not extend the removal over their prose. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… parse failure The read-failure warning and the delegate exit code are checked end to end through `rtk rewrite` with `RTK_REWRITE_HOST=openclaw`, for a settings file that cannot be read and one that cannot be parsed. A unit test checks that deny rules from the other settings files still apply after an unparseable one, as they already did after an unreadable one. The new test helpers say why they would panic. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(init): preserve user prose during uninstall
…ettings fix(permissions): fail closed when a settings file cannot be read or parsed
Replay real `ruff analyze graph` and `ruff rule E501` output (ruff 0.16.6) through `rtk ruff`: the graph comes back whole and valid JSON, other passthrough subcommands keep the cap. The unit tests now use the same captured graph instead of a hand-built one, and pin which invocations the classifier exempts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-3929 fix(ruff): preserve analyze graph JSON output
…available, name the removed base URL
fix(init): only offer the proxy when rtk-proxy can run, and remove its base URL on uninstall
fix(pytest): validate trailing summary line
fix(pytest): report setup errors in the summary
…time fix(gain): exclude zero-input rows from exec time totals
…ntegrity fix: check hook integrity for rewritten commands
The collision test now asserts both stored keys, so a key length other than 16 fails it. A new test stores an output under a 12-char key, as the previous release did, stores it again under the 16-char key, and checks that each hint returns its own row instead of an ambiguous-prefix error. The getting-started guide's example hint uses the 16-char form. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e-bail fix(js): handle bun test --coverage and --bail
fix(recall): widen content hash to 64 bits so colliding outputs are kept
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.
Feats
Fix
Other