From f0b7e89468e6aeff6cf12569844ef71f951325bc Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 2 Jul 2026 14:07:22 +0200 Subject: [PATCH] =?UTF-8?q?fix(rtk):=20rtk=20resolution=20+=20absolute-pat?= =?UTF-8?q?h=20rewrite=20=E2=80=94=20compression=20was=20silently=20dead?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rtk lives at ~/.cargo/bin but the hand-managed .bashrc lost the cargo line: command -v failed in hook AND tool shell, so the hook no-op'd with a stderr warn on every Bash call — input compression silently OFF. - Resolve RTK_BIN by probing known install dirs (LRN-036 class). - Substitute the ABSOLUTE path at the rewrite head: a bare 'rtk …' exits 127 in the tool shell, whose PATH the hook cannot fix (proven). - Compound rewrites carrying further bare rtk segments pass through unrewritten: quoted text (commit messages) makes a global substitution unsafe — lose compression, never emit a command that 127s (proven: a commit chain 127'd mid-flow). - detect_rtk probes the same dirs so the banner reports capability. - Re-pinned .rtk-hook.sha256: the rtk BINARY verifies the hook against it at execution time and refuses a modified hook — the pin is live machinery, not a vestige; coupling documented in the header. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016zA3Qh2Q1QpcGXzXxKeDHR --- hooks/.rtk-hook.sha256 | 2 +- hooks/rtk-rewrite.sh | 39 ++++++++++++++++++++++++++++++++++++--- lib/detect-plugins.sh | 4 +++- 3 files changed, 40 insertions(+), 5 deletions(-) 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() {