fix: use CLI argument for hook phase detection in observe.sh

The observe.sh script receives "pre" or "post" as $1 from the hook
config, but the Python code was looking for a "hook_type" field in
the stdin JSON. Claude Code does NOT include "hook_type" in the
JSON payload passed to hooks, so it always defaulted to "unknown",
causing all observations to be recorded as "tool_complete" —
PreToolUse events were never distinguished from PostToolUse.

Fix: capture $1 as HOOK_PHASE and pass it to Python via env var.
This also fixes TIMESTAMP export in the .cursor copy where inline
`VAR=val cmd` syntax didn't propagate to the python subprocess.
This commit is contained in:
tsli
2026-02-17 10:18:36 +08:00
parent c8f54481b8
commit cb4e4ca711
2 changed files with 28 additions and 12 deletions

View File

@@ -36,6 +36,9 @@
set -e
# Hook phase from CLI argument: "pre" (PreToolUse) or "post" (PostToolUse)
HOOK_PHASE="${1:-post}"
CONFIG_DIR="${HOME}/.claude/homunculus"
OBSERVATIONS_FILE="${CONFIG_DIR}/observations.jsonl"
MAX_FILE_SIZE_MB=10
@@ -57,15 +60,22 @@ if [ -z "$INPUT_JSON" ]; then
fi
# Parse using python via stdin pipe (safe for all JSON payloads)
PARSED=$(echo "$INPUT_JSON" | python3 -c '
# Pass HOOK_PHASE via env var since Claude Code does not include hook type in stdin JSON
PARSED=$(echo "$INPUT_JSON" | HOOK_PHASE="$HOOK_PHASE" python3 -c '
import json
import sys
import os
try:
data = json.load(sys.stdin)
# Determine event type from CLI argument passed via env var.
# Claude Code does NOT include a "hook_type" field in the stdin JSON,
# so we rely on the shell argument ("pre" or "post") instead.
hook_phase = os.environ.get("HOOK_PHASE", "post")
event = "tool_start" if hook_phase == "pre" else "tool_complete"
# Extract fields - Claude Code hook format
hook_type = data.get("hook_type", "unknown") # PreToolUse or PostToolUse
tool_name = data.get("tool_name", data.get("tool", "unknown"))
tool_input = data.get("tool_input", data.get("input", {}))
tool_output = data.get("tool_output", data.get("output", ""))
@@ -82,9 +92,6 @@ try:
else:
tool_output_str = str(tool_output)[:5000]
# Determine event type
event = "tool_start" if "Pre" in hook_type else "tool_complete"
print(json.dumps({
"parsed": True,
"event": event,
@@ -103,7 +110,8 @@ PARSED_OK=$(echo "$PARSED" | python3 -c "import json,sys; print(json.load(sys.st
if [ "$PARSED_OK" != "True" ]; then
# Fallback: log raw input for debugging
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
TIMESTAMP="$timestamp" echo "$INPUT_JSON" | python3 -c "
export TIMESTAMP="$timestamp"
echo "$INPUT_JSON" | python3 -c "
import json, sys, os
raw = sys.stdin.read()[:2000]
print(json.dumps({'timestamp': os.environ['TIMESTAMP'], 'event': 'parse_error', 'raw': raw}))
@@ -124,7 +132,8 @@ fi
# Build and write observation
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
TIMESTAMP="$timestamp" echo "$PARSED" | python3 -c "
export TIMESTAMP="$timestamp"
echo "$PARSED" | python3 -c "
import json, sys, os
parsed = json.load(sys.stdin)