bug(rewrite): false positives for systemctl, make; next build drops subcommand arg
#1,714 创建于 2026年5月5日
仓库指标
- Star
- (48,085 star)
- PR 合并指标
- (平均合并 11天 1小时) (30 天内合并 45 个 PR)
描述
rtk version: 0.38.0 OS: Linux (Ubuntu, x86_64) Discovered via: rtk-hermes plugin (Hermes Agent integration)
Summary
rtk rewrite produces incorrect rewrites for 3 commands. Two are false positives (rewriting unsupported commands to broken rtk invocations), and one drops a required subcommand argument.
Bug 1: next build → rtk next (drops build arg)
$ rtk rewrite "next build"; echo "exit: $?"
rtk next
exit: 3
The build subcommand is dropped entirely. Running rtk next without build either errors or does nothing useful.
Looking at #241, the rule was intentionally written this way:
// "next build" is stripped to "rtk next" — the build subcommand is internal
rtk_cmd: "rtk next",
rewrite_prefixes: &["npx next build", "pnpm next build", "next build"],
But rtk next requires the build (or dev, etc.) subcommand — without it, clap rejects the invocation. The rewrite should be rtk next build, not rtk next.
Bug 2: systemctl status nginx → rtk systemctl status nginx (false positive)
$ rtk rewrite "systemctl status nginx"; echo "exit: $?"
rtk systemctl status nginx
exit: 3
RTK has no systemctl first-class subcommand. There is a TOML filter (systemctl-status.toml from #386) scoped to ^systemctl\s+status\b, but the rewrite registry appears to match systemctl broadly — rewriting any systemctl command to rtk systemctl, which then fails at runtime because clap has no systemctl subcommand.
This turns a working command into a broken one.
Bug 3: make build → rtk make build (false positive)
$ rtk rewrite "make build"; echo "exit: $?"
rtk make build
exit: 3
Same pattern. RTK has a TOML filter for make (#349), but no rtk make subcommand exists in clap. The rewritten command fails. The hook silently replaces a working make build with a broken rtk make build.
Impact
Bugs 2 and 3 are particularly dangerous when used with auto-rewrite hooks (Claude Code, Hermes, Cursor, etc.) — the hook transparently replaces working commands with broken ones. The LLM agent sees a confusing error instead of the expected output and has to waste tokens diagnosing the failure and retrying.
This is the same class of bug as #336/#244 (docker compose false positives).
Root cause
The rewrite registry (rules.rs) matches commands that have TOML filters but no corresponding clap subcommand. When rtk <cmd> is executed, clap rejects it because the subcommand does not exist in the CLI interface.
Two possible fixes:
- Only rewrite commands that have an actual clap subcommand — TOML-only filters should not be added to the rewrite registry unless
rtk <cmd>is also wired into clap. - Add clap passthrough for TOML-filtered commands — if a command matches a TOML filter but has no dedicated Rust handler, route it through the TOML fallback engine (similar to
rtk run).
Test cases to add
# Bug 1: next build should keep the subcommand
assert_rewrite "next build" "rtk next build"
assert_rewrite "npx next build" "rtk next build"
# Bug 2: systemctl should not be rewritten (or only systemctl status)
assert_rewrite "systemctl status nginx" "rtk systemctl status nginx" # only if rtk systemctl exists
# or: exit 1 (no rewrite) if no rtk systemctl subcommand
# Bug 3: make should not be rewritten unless rtk make subcommand exists
assert_rewrite "make build" "rtk make build" # only if rtk make exists
# or: exit 1 (no rewrite)