Skip to content

Commit b363c2d

Browse files
Bryan Soaresclaude
andcommitted
fix(init): warn when jq is missing during hook installation
The shell-based hook (rtk-rewrite.sh) requires jq to parse JSON from Claude Code / Cursor. When jq is not installed the hook exits silently (exit 0, no output), causing every command to fall through without RTK rewriting — resulting in zero token savings with no visible error. Add a soft check during `rtk init -g` that warns the user if jq is not found on PATH, with install instructions for common platforms. This is a stopgap until the hook is replaced by a native Rust subcommand (see rtk-ai#785). Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent a00560a commit b363c2d

File tree

1 file changed

+52
-0
lines changed

1 file changed

+52
-0
lines changed

src/init.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,42 @@ pub fn run(
287287
Ok(())
288288
}
289289

290+
/// Check whether `jq` is available on PATH and warn if not.
291+
///
292+
/// The shell-based hook (`rtk-rewrite.sh`) requires `jq` to parse the JSON
293+
/// payload from Claude Code. When `jq` is missing the hook exits silently
294+
/// (exit 0, no output) which means **every** command falls through without
295+
/// RTK rewriting — resulting in zero token savings with no visible error.
296+
///
297+
/// This is a soft check: it prints a prominent warning but does **not** fail
298+
/// the init, so the rest of the setup can still complete.
299+
fn check_jq_available() {
300+
use std::process::Command;
301+
302+
let jq_found = Command::new("jq")
303+
.arg("--version")
304+
.stdout(std::process::Stdio::null())
305+
.stderr(std::process::Stdio::null())
306+
.status()
307+
.map(|s| s.success())
308+
.unwrap_or(false);
309+
310+
if !jq_found {
311+
eprintln!();
312+
eprintln!(" [WARNING] jq is not installed.");
313+
eprintln!(" The RTK hook requires jq to rewrite commands.");
314+
eprintln!(" Without it the hook will silently do nothing — zero token savings.");
315+
eprintln!();
316+
eprintln!(" Install jq:");
317+
eprintln!(" macOS: brew install jq");
318+
eprintln!(" Ubuntu: sudo apt-get install -y jq");
319+
eprintln!(" Fedora: sudo dnf install -y jq");
320+
eprintln!(" Arch: sudo pacman -S jq");
321+
eprintln!(" Other: https://jqlang.github.io/jq/download/");
322+
eprintln!();
323+
}
324+
}
325+
290326
/// Prepare hook directory and return paths (hook_dir, hook_path)
291327
fn prepare_hook_paths() -> Result<(PathBuf, PathBuf)> {
292328
let claude_dir = resolve_claude_dir()?;
@@ -897,6 +933,12 @@ fn run_default_mode(
897933
let (_hook_dir, hook_path) = prepare_hook_paths()?;
898934
let hook_changed = ensure_hook_installed(&hook_path, verbose)?;
899935

936+
// 1b. Warn if jq is not installed — the hook script requires it to parse JSON.
937+
// Without jq the hook exits silently, causing zero token savings.
938+
// This check will become unnecessary once the hook is replaced by a native
939+
// Rust subcommand (see https://github.com/rtk-ai/rtk/pull/785).
940+
check_jq_available();
941+
900942
// 2. Write RTK.md
901943
write_if_changed(&rtk_md_path, RTK_SLIM, "RTK.md", verbose)?;
902944

@@ -1608,6 +1650,9 @@ fn install_cursor_hooks(verbose: u8) -> Result<()> {
16081650
})?;
16091651
}
16101652

1653+
// 1b. Warn if jq is missing (same issue as Claude Code hook)
1654+
check_jq_available();
1655+
16111656
// 2. Create or patch hooks.json
16121657
let hooks_json_path = cursor_dir.join("hooks.json");
16131658
let patched = patch_cursor_hooks_json(&hooks_json_path, verbose)?;
@@ -2346,6 +2391,13 @@ mod tests {
23462391
);
23472392
}
23482393

2394+
#[test]
2395+
fn test_check_jq_available_does_not_panic() {
2396+
// check_jq_available is a soft check — it must never panic or fail,
2397+
// regardless of whether jq is installed. It only prints a warning.
2398+
check_jq_available();
2399+
}
2400+
23492401
#[test]
23502402
fn test_hook_has_guards() {
23512403
assert!(REWRITE_HOOK.contains("command -v rtk"));

0 commit comments

Comments
 (0)