diff --git a/hooks/.rtk-hook.sha256 b/hooks/.rtk-hook.sha256 index 79741f9..2305033 100644 --- a/hooks/.rtk-hook.sha256 +++ b/hooks/.rtk-hook.sha256 @@ -1 +1 @@ -ef0d630994fd7ef5f2b84fb66cd6249c493bb8736bcacd4734d7c798125018fb rtk-rewrite.sh +0f43229d17d03342d27c0b836b9b70f25f98dfb80a35ffc8dc2488034cb8719c rtk-rewrite.sh diff --git a/hooks/rtk-rewrite.sh b/hooks/rtk-rewrite.sh index f7a42b5..faaf089 100755 --- a/hooks/rtk-rewrite.sh +++ b/hooks/rtk-rewrite.sh @@ -7,6 +7,10 @@ # which is the single source of truth (src/discover/registry.rs). # To add or change rewrite rules, edit the Rust registry — not this file. # +# INTEGRITY PIN: the rtk binary verifies this file against +# hooks/.rtk-hook.sha256 at execution time and refuses to run on mismatch. +# ANY edit here must re-pin: (cd hooks && sha256sum rtk-rewrite.sh > .rtk-hook.sha256) +# # Exit code protocol for `rtk rewrite`: # 0 + stdout Rewrite found, no deny/ask rule matched → auto-allow # 1 No RTK equivalent → pass through unchanged @@ -18,14 +22,27 @@ if ! command -v jq &>/dev/null; then exit 0 fi -if ! command -v rtk &>/dev/null; then +# PATH heal: hook/tool-shell PATH may lack the cargo bin dir (hand-managed +# ~/.bashrc can lose the cargo line — LRN-036 class). Resolve the ABSOLUTE +# binary path: the rewritten command executes in the tool shell, whose PATH +# the hook cannot fix — a bare `rtk …` rewrite would exit 127 there. +RTK_BIN="$(command -v rtk 2>/dev/null || true)" +RTK_ON_PATH=1 +if [ -z "$RTK_BIN" ]; then + RTK_ON_PATH=0 + for _d in "$HOME/.cargo/bin" "$HOME/.local/bin"; do + if [ -x "$_d/rtk" ]; then RTK_BIN="$_d/rtk"; break; fi + done +fi + +if [ -z "$RTK_BIN" ]; then echo "[rtk] WARNING: rtk is not installed or not in PATH. Hook cannot rewrite commands. Install: https://github.com/rtk-ai/rtk#installation" >&2 exit 0 fi # Version guard: rtk rewrite was added in 0.23.0. # Older binaries: warn once and exit cleanly (no silent failure). -RTK_VERSION=$(rtk --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) +RTK_VERSION=$("$RTK_BIN" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) if [ -n "$RTK_VERSION" ]; then MAJOR=$(echo "$RTK_VERSION" | cut -d. -f1) MINOR=$(echo "$RTK_VERSION" | cut -d. -f2) @@ -44,7 +61,7 @@ if [ -z "$CMD" ]; then fi # Delegate all rewrite + permission logic to the Rust binary. -REWRITTEN=$(rtk rewrite "$CMD" 2>/dev/null) +REWRITTEN=$("$RTK_BIN" rewrite "$CMD" 2>/dev/null) EXIT_CODE=$? case $EXIT_CODE in @@ -70,6 +87,22 @@ case $EXIT_CODE in ;; esac +# When rtk is NOT on PATH, a bare `rtk …` rewrite exits 127 in the tool +# shell (whose PATH the hook cannot fix). Substitute the absolute path at +# the string head — the only position safe to rewrite. Compound commands +# (`a && b`) can carry further bare rtk segments we canNOT substitute +# safely (quoted text, e.g. commit messages, may contain the same +# pattern): if any remain at a command position, pass through unrewritten +# — lose the compression, never emit a command that 127s. +if [ "$RTK_ON_PATH" -eq 0 ]; then + case "$REWRITTEN" in + rtk\ *) REWRITTEN="$RTK_BIN ${REWRITTEN#rtk }" ;; + esac + if printf '%s' "$REWRITTEN" | grep -Eq '(^|[;&|][[:space:]]*)rtk[[:space:]]'; then + exit 0 + fi +fi + ORIGINAL_INPUT=$(echo "$INPUT" | jq -c '.tool_input') UPDATED_INPUT=$(echo "$ORIGINAL_INPUT" | jq --arg cmd "$REWRITTEN" '.command = $cmd') diff --git a/lib/detect-plugins.sh b/lib/detect-plugins.sh index 7f0da36..4635306 100644 --- a/lib/detect-plugins.sh +++ b/lib/detect-plugins.sh @@ -10,7 +10,9 @@ # --- Always-on plugins --- detect_rtk() { - command -v rtk &>/dev/null + command -v rtk &>/dev/null && return 0 + # PATH heal: hook/session PATH may lack the cargo bin dir (LRN-036 class) + [ -x "$HOME/.cargo/bin/rtk" ] || [ -x "$HOME/.local/bin/rtk" ] } detect_superpowers() {