#!/usr/bin/env bash # Generic payload-dump hook: write the full JSON payload Claude Code sends on an # event to its own `.json` file, so a consumer can read the raw record later. # Reads the payload as JSON on stdin. One script serves every event it is # registered against — both the target dir and the filename are derived from the # payload, exactly as `nvim-notify.hook.sh` derives its signal. # # One file per fire (XDG state home): # $XDG_STATE_HOME/claude//.json # * is `hook_event_name` lowercased, with a trailing `failure` stripped # so PostToolUse and PostToolUseFailure share one `posttooluse` dir (the two # halves — command and result — of a Bash call's record). # * is `tool_use_id` (`toolu_…`, unique per tool call and identical # across the Pre/PostToolUse payloads, so input and output dumps pair by # basename), else `session_id` with the session-scoped suffix `source` # (SessionStart: startup/resume/clear/compact) or `reason` (SessionEnd: # clear/logout/prompt_input_exit/other) appended to keep a session's fires # distinct. A repeated id overwrites its previous dump (latest wins). # Chronological order comes from file mtime; the wall-clock time lives inside # the JSON. input=$(cat) event=$(jq --raw-output '.hook_event_name // empty' <<<"$input" 2>/dev/null) [ -n "$event" ] || exit 0 name="${event,,}" name="${name%failure}" dir="${XDG_STATE_HOME:-$HOME/.local/state}/claude/$name" mkdir --parents "$dir" 2>/dev/null id=$(jq --raw-output '.tool_use_id // empty' <<<"$input" 2>/dev/null) if [ -z "$id" ]; then id=$(jq --raw-output '.session_id // empty' <<<"$input" 2>/dev/null) suffix=$(jq --raw-output '.source // .reason // empty' <<<"$input" 2>/dev/null) [ -n "$id" ] && [ -n "$suffix" ] && id="$id-$suffix" fi [ -n "$id" ] || id="unknown_$(date +'%F_%T')" jq --sort-keys '.' <<<"$input" >"$dir/$id.json" 2>/dev/null || printf '%s\n' "$input" >"$dir/$id.json"