Skip to content

Instantly share code, notes, and snippets.

@pybe
Last active January 8, 2026 17:06
Show Gist options
  • Select an option

  • Save pybe/1b7f7d97097a20b0101a22e9cefbe5b7 to your computer and use it in GitHub Desktop.

Select an option

Save pybe/1b7f7d97097a20b0101a22e9cefbe5b7 to your computer and use it in GitHub Desktop.
Patch Claude Code cli.js to enable hooks on Termux/Android (PARTIAL FIX - PreToolUse known issue)
#!/usr/bin/env bash
# Claude Code Termux/Android Patch Script
# Fixes hooks not firing on Android by patching platform detection and temp paths
#
# Usage:
# patch-termux-hooks # Apply all patches (recommended)
# patch-termux-hooks --platform-only # Only platform detection patch
# patch-termux-hooks --tmp-only # Only /tmp path patch
# patch-termux-hooks --rollback # Restore from backup
# patch-termux-hooks --help # Show this help
#
# Repository: https://github.com/anthropics/claude-code/issues/16615
# Gist: https://gist.github.com/1b7f7d97097a20b0101a22e9cefbe5b7
#
# ⚠️ KNOWN LIMITATION (Session 12 Deep Investigation - 2026-01-08):
#
# PreToolUse and PostToolUse hooks DO NOT FIRE during live tool execution,
# even with all patches applied. This is NOT a configuration issue - it's
# a deeper code path problem that requires an upstream fix.
#
# What works:
# ✅ SessionStart hooks
# ✅ Stop hooks
# ✅ SubagentStop hooks
#
# What doesn't work:
# ❌ PreToolUse hooks (never invoked during tool calls)
# ❌ PostToolUse hooks (never invoked during tool calls)
#
# Technical Investigation Findings:
#
# The code path for PreToolUse exists in cli.js:
# ZZ7 (tool execution)
# → XZ7 (pre-tool hook wrapper)
# → XM0 (executePreToolHooks)
# → Ot (main hook generator)
# → OM0 (getMatchingHooks)
# → Debug: "Getting matching hook commands for PreToolUse"
#
# Debug logs show "Getting matching hook commands for X" for working hooks
# (SessionStart, Stop, SubagentStop), but ZERO entries for PreToolUse.
# The hook execution system simply never reaches the PreToolUse code path.
#
# Potential causes under investigation:
# 1. Feature flag "tengu_streaming_tool_execution2" may route Android differently
# 2. Async generator (XZ7) may not be properly consumed on Android
# 3. Silent exception in tool execution path
#
# See GitHub issue #16615 for upstream tracking.
#
# What this script DOES fix:
# 1. Platform detection (android → recognized as valid platform)
# 2. Temp directory paths (/tmp → $PREFIX/tmp)
# 3. Enables SessionStart/Stop/SubagentStop hooks
#
# ------------------------------------------------------------------------------
set -e
CLI_PATH="/data/data/com.termux/files/usr/lib/node_modules/@anthropic-ai/claude-code/cli.js"
BACKUP_PATH="${CLI_PATH}.backup"
TERMUX_TMP="/data/data/com.termux/files/usr/tmp"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
show_help() {
head -35 "$0" | tail -33
exit 0
}
check_prerequisites() {
if [[ ! -f "$CLI_PATH" ]]; then
echo -e "${RED}Error: Claude Code CLI not found at $CLI_PATH${NC}"
echo "Make sure Claude Code is installed: npm install -g @anthropic-ai/claude-code"
exit 1
fi
if [[ ! -d "$TERMUX_TMP" ]]; then
echo -e "${YELLOW}Creating Termux tmp directory...${NC}"
mkdir -p "$TERMUX_TMP"
fi
}
create_backup() {
if [[ ! -f "$BACKUP_PATH" ]]; then
echo -e "${BLUE}Creating backup at $BACKUP_PATH${NC}"
cp "$CLI_PATH" "$BACKUP_PATH"
else
echo -e "${YELLOW}Backup already exists${NC}"
fi
}
apply_platform_patch() {
echo -e "${BLUE}Applying platform detection patch...${NC}"
# Count existing android patches
local before=$(grep -c '==="android"' "$CLI_PATH" 2>/dev/null || echo "0")
if [[ "$before" -ge 10 ]]; then
echo -e "${GREEN}Platform patch already applied ($before occurrences)${NC}"
return 0
fi
# Patch patterns - add android to platform checks
# Pattern 1: process.platform==="darwin"||process.platform==="linux"
sed -i 's/process\.platform==="darwin"||process\.platform==="linux"/process.platform==="darwin"||process.platform==="linux"||process.platform==="android"/g' "$CLI_PATH"
# Pattern 2: "darwin"===process.platform||"linux"===process.platform
sed -i 's/"darwin"===process\.platform||"linux"===process\.platform/"darwin"===process.platform||"linux"===process.platform||"android"===process.platform/g' "$CLI_PATH"
# Pattern 3: Variations with spaces
sed -i 's/process\.platform === "darwin" || process\.platform === "linux"/process.platform === "darwin" || process.platform === "linux" || process.platform === "android"/g' "$CLI_PATH"
local after=$(grep -c '==="android"\|=== "android"' "$CLI_PATH" 2>/dev/null || echo "0")
echo -e "${GREEN}Platform patch applied ($after occurrences)${NC}"
}
apply_tmp_patch() {
echo -e "${BLUE}Applying /tmp path patch...${NC}"
# Count existing hardcoded /tmp paths
local before=$(grep -c '"/tmp' "$CLI_PATH" 2>/dev/null || echo "0")
if [[ "$before" -le 1 ]]; then
echo -e "${GREEN}/tmp patch already applied or not needed${NC}"
return 0
fi
# Replace /tmp/claude with Termux path
sed -i "s|\"/tmp/claude|\"$TERMUX_TMP/claude|g" "$CLI_PATH"
# Replace /tmp/workspace with Termux path
sed -i "s|\"/tmp/workspace|\"$TERMUX_TMP/workspace|g" "$CLI_PATH"
# Replace remaining /tmp references (be careful not to break legitimate paths)
sed -i "s|TMPDIR=/tmp|TMPDIR=$TERMUX_TMP|g" "$CLI_PATH"
local after=$(grep -c '"/tmp' "$CLI_PATH" 2>/dev/null || echo "0")
echo -e "${GREEN}/tmp patch applied (remaining /tmp refs: $after)${NC}"
}
rollback() {
if [[ -f "$BACKUP_PATH" ]]; then
echo -e "${BLUE}Restoring from backup...${NC}"
cp "$BACKUP_PATH" "$CLI_PATH"
echo -e "${GREEN}Rollback complete${NC}"
else
echo -e "${RED}No backup found at $BACKUP_PATH${NC}"
exit 1
fi
}
show_status() {
echo -e "\n${BLUE}=== Patch Status ===${NC}"
local platform_count=$(grep -c '==="android"\|=== "android"' "$CLI_PATH" 2>/dev/null || echo "0")
local tmp_count=$(grep -c '"/tmp' "$CLI_PATH" 2>/dev/null || echo "0")
if [[ "$platform_count" -ge 10 ]]; then
echo -e "Platform patch: ${GREEN}✓ Applied ($platform_count occurrences)${NC}"
else
echo -e "Platform patch: ${RED}✗ Not applied${NC}"
fi
if [[ "$tmp_count" -le 1 ]]; then
echo -e "/tmp patch: ${GREEN}✓ Applied${NC}"
else
echo -e "/tmp patch: ${RED}✗ $tmp_count hardcoded /tmp paths remain${NC}"
fi
if [[ -f "$BACKUP_PATH" ]]; then
echo -e "Backup: ${GREEN}✓ Available${NC}"
else
echo -e "Backup: ${YELLOW}○ Not created${NC}"
fi
echo -e "\n${YELLOW}⚠️ Note: PreToolUse/PostToolUse hooks require upstream fix${NC}"
echo -e "${YELLOW} See: https://github.com/anthropics/claude-code/issues/16615${NC}"
}
# Main
case "${1:-}" in
--help|-h)
show_help
;;
--rollback)
rollback
;;
--platform-only)
check_prerequisites
create_backup
apply_platform_patch
show_status
;;
--tmp-only)
check_prerequisites
create_backup
apply_tmp_patch
show_status
;;
*)
check_prerequisites
create_backup
apply_platform_patch
apply_tmp_patch
show_status
echo -e "\n${GREEN}All patches applied. Restart Claude Code to take effect.${NC}"
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment