- Analysis: parameter sweep scripts, adversarial testing, 2D frontier maps - Research: KRAIKEN_RESEARCH_REPORT, SECURITY_REVIEW, STORAGE_LAYOUT - FuzzingBase: consolidated fuzzing helper, BackgroundLP simulation - Sweep results: CSV data for full 4D sweep (1050 combos), bull-bear, AS sweep, VWAP fix validation - Code quality: .gitignore for fuzz CSVs, gas snapshot, updated docs - Remove dead analysis helpers (CSVHelper, CSVManager, ScenarioRecorder) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
71 lines
2.4 KiB
Bash
Executable file
71 lines
2.4 KiB
Bash
Executable file
#!/bin/bash
|
||
# Claude Code Stop hook — fires when the agent finishes responding.
|
||
#
|
||
# Option D: bash pre-filter first, LLM triage only for ambiguous cases.
|
||
#
|
||
# Known Stop event fields:
|
||
# session_id, transcript_path, cwd, permission_mode,
|
||
# hook_event_name ("Stop"), stop_hook_active
|
||
#
|
||
# Note: stop_reason is NOT provided in the Stop event JSON.
|
||
# We detect state by inspecting the tmux pane instead.
|
||
|
||
set -euo pipefail
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
SUPERVISOR_DIR="${SCRIPT_DIR%/hooks}"
|
||
|
||
INPUT=$(cat)
|
||
|
||
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
|
||
CWD=$(echo "$INPUT" | jq -r '.cwd // "unknown"')
|
||
|
||
# Find matching supervised session
|
||
STATE_FILE="${CCS_STATE_FILE:-${HOME}/.openclaw/workspace/supervisor-state.json}"
|
||
if [ ! -f "$STATE_FILE" ]; then
|
||
exit 0 # No supervised sessions
|
||
fi
|
||
|
||
SOCKET=$(jq -r --arg cwd "$CWD" '
|
||
.sessions | to_entries[] | select(.value.projectDir == $cwd and .value.status == "running") | .value.socket
|
||
' "$STATE_FILE" 2>/dev/null || echo "")
|
||
|
||
TMUX_SESSION=$(jq -r --arg cwd "$CWD" '
|
||
.sessions | to_entries[] | select(.value.projectDir == $cwd and .value.status == "running") | .value.tmuxSession
|
||
' "$STATE_FILE" 2>/dev/null || echo "")
|
||
|
||
# No matching supervised session for this project
|
||
if [ -z "$SOCKET" ] || [ -z "$TMUX_SESSION" ]; then
|
||
exit 0
|
||
fi
|
||
|
||
# Can we reach the tmux session?
|
||
if [ ! -S "$SOCKET" ] || ! tmux -S "$SOCKET" has-session -t "$TMUX_SESSION" 2>/dev/null; then
|
||
exit 0
|
||
fi
|
||
|
||
PANE_OUTPUT=$(tmux -S "$SOCKET" capture-pane -p -J -t "$TMUX_SESSION" -S -30 2>/dev/null || echo "")
|
||
|
||
# Bash pre-filter: check the last few lines for patterns
|
||
|
||
# Check for API errors (transient — always triage)
|
||
if echo "$PANE_OUTPUT" | tail -10 | grep -qiE "API Error: 5[0-9][0-9]|internal.server.error|api_error"; then
|
||
"$SUPERVISOR_DIR/triage.sh" "stopped:api_error" "$CWD" "$PANE_OUTPUT" &
|
||
exit 0
|
||
fi
|
||
|
||
# Check for rate limiting
|
||
if echo "$PANE_OUTPUT" | tail -10 | grep -qiE "429|rate.limit"; then
|
||
echo "[$(date -u +%FT%TZ)] RATE_LIMITED | stop | $CWD" >> "${CCS_LOG_FILE:-/tmp/ccs-triage.log}"
|
||
exit 0
|
||
fi
|
||
|
||
# Check if shell prompt is back (Claude Code exited)
|
||
if echo "$PANE_OUTPUT" | tail -5 | grep -qE '^\$ |^❯ [^/]|^% |^[a-z]+@.*\$ '; then
|
||
# Prompt returned — agent might be done or crashed. Triage it.
|
||
"$SUPERVISOR_DIR/triage.sh" "stopped:prompt_back" "$CWD" "$PANE_OUTPUT" &
|
||
exit 0
|
||
fi
|
||
|
||
# No prompt back, no errors — agent is likely mid-conversation. Skip silently.
|
||
exit 0
|