Skip to content

Commit d9e6aa2

Browse files
alexgreenshclaude
andcommitted
fix: bash compression hook -- missing hookEventName + hardcoded python3 (#26)
Two bugs prevented Bash compression from working since Claude Code v2.1.101 tightened hook schema validation: 1. hookSpecificOutput was missing the required hookEventName field, causing every rewrite to be rejected with a validation error. 2. The rewritten command hardcoded python3 instead of routing through python-launcher.sh, breaking Windows (Store shim) and bypassing the cross-platform interpreter discovery. Also adds an explicit anti-recursion guard: shell interpreters (bash, sh, zsh, dash, fish) are now excluded from the whitelist so the rewritten command can never trigger the hook again. Closes #26 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 1224351 commit d9e6aa2

4 files changed

Lines changed: 17 additions & 6 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"name": "token-optimizer",
1414
"source": "./",
1515
"description": "Audit, fix, and monitor Claude Code context window usage. Find the ghost tokens.",
16-
"version": "5.6.0",
16+
"version": "5.6.1",
1717
"author": {
1818
"name": "Alex Greenshpun",
1919
"url": "https://linkedin.com/in/alexgreensh"

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
},
88
"homepage": "https://github.com/alexgreensh/token-optimizer",
99
"repository": "https://github.com/alexgreensh/token-optimizer",
10-
"version": "5.6.0",
10+
"version": "5.6.1",
1111
"license": "PolyForm-Noncommercial-1.0.0",
1212
"keywords": ["token", "optimization", "context", "audit", "cost", "coach"]
1313
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
</p>
44

55
<p align="center">
6-
<a href="https://github.com/alexgreensh/token-optimizer/releases"><img src="https://img.shields.io/badge/version-5.6.0-green" alt="Version 5.6.0"></a>
6+
<a href="https://github.com/alexgreensh/token-optimizer/releases"><img src="https://img.shields.io/badge/version-5.6.1-green" alt="Version 5.6.1"></a>
77
<a href="https://github.com/alexgreensh/token-optimizer"><img src="https://img.shields.io/badge/Claude_Code-Plugin-blueviolet" alt="Claude Code Plugin"></a>
88
<a href="https://github.com/alexgreensh/token-optimizer/tree/main/openclaw"><img src="https://img.shields.io/badge/OpenClaw-v2.4.0-brightgreen" alt="OpenClaw v2.4.0"></a>
99
<a href="https://github.com/alexgreensh/token-optimizer/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-PolyForm%20Noncommercial-blue.svg" alt="License: PolyForm Noncommercial"></a>

skills/token-optimizer/scripts/bash_hook.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ def _is_whitelisted(command_str):
157157
return False
158158
return True
159159

160-
# Check for sudo/su prefix (never rewrite)
161-
if cmd in ("sudo", "su"):
160+
# Never rewrite shell interpreters or privilege-escalation wrappers (also prevents recursion on rewritten commands).
161+
if cmd in ("bash", "sh", "zsh", "dash", "fish", "sudo", "su"):
162162
return False
163163

164164
return False
@@ -201,14 +201,24 @@ def main():
201201
if not compress_path.exists():
202202
return # Wrapper missing, exit silently
203203

204+
# Route through python-launcher.sh so Windows Store shim / py launcher are handled.
205+
plugin_root = script_dir.parent.parent.parent
206+
launcher_path = plugin_root / "hooks" / "python-launcher.sh"
207+
if not launcher_path.exists():
208+
return # Launcher missing, exit silently
209+
204210
# Build rewritten command with proper quoting for each token
205211
try:
206212
original_tokens = shlex.split(command)
207213
except ValueError:
208214
return
209215

210216
# Re-quote each token to handle paths with spaces safely (ARCH-F3)
211-
rewritten = "python3 " + shlex.quote(str(compress_path)) + " " + " ".join(shlex.quote(t) for t in original_tokens)
217+
rewritten = (
218+
"bash " + shlex.quote(str(launcher_path))
219+
+ " " + shlex.quote(str(compress_path))
220+
+ " " + " ".join(shlex.quote(t) for t in original_tokens)
221+
)
212222

213223
# Log rewrite event to sidecar JSONL
214224
try:
@@ -229,6 +239,7 @@ def main():
229239
# Emit updatedInput response
230240
response = {
231241
"hookSpecificOutput": {
242+
"hookEventName": "PreToolUse",
232243
"permissionDecision": "allow",
233244
"updatedInput": {
234245
"command": rewritten,

0 commit comments

Comments
 (0)