#!/bin/bash
set -euo pipefail

trap 'echo "at line $LINENO, exit code $? from $BASH_COMMAND" >&2; exit 1' ERR

# This script is intended to be invoked as a Claude Code hook. Like this, in ~/.claude/settings.json,
# or installed via /hooks
#  "hooks": {
#    "PreToolUse": [{"hooks": [{"type": "command", "command": "~/log-hook.sh"}]}],
#    "PostToolUse": [{"hooks": [{"type": "command", "command": "~/log-hook.sh"}]}],
#    "Notification": [{"hooks": [{"type": "command", "command": "~/log-hook.sh"}]}],
#    "Stop": [{"hooks": [{"type": "command", "command": "~/log-hook.sh"}]}],
#    "SubagentStop": [{"hooks": [{"type": "command", "command": "~/log-hook.sh"}]}],
#    "PreCompact": [{"hooks": [{"type": "command", "command": "~/log-hook.sh"}]}],
#    "UserPromptSubmit": [{"hooks": [{"type": "command", "command": "~/log-hook.sh"}]}],#  }
#
# The purpose of this script is to append to ~/claude-log.jsonl with every update that's been
# made to the transcript file (whose filename we discover from reading stdin), with logEvent:TRANSCRIPT_ITEM
# To be able to tell what's new in the transcript file, it keeps a full copy of the previous
# contents+filename of the transcript when this script was last called.
# If lines get removed, they're marked with logEvent:TRANSCRIPT_PRUNE.
# If the transcript file has been replaced, that's marked with logEvent:TRANSCRIPT_RENEW.
# This script also appends to ~/claude-log.jsonl with the content of stdin from this script's
# own invocation, with logEvent:HOOK.

logTimestamp=$(date +%s)
logDate=$(date)
stdin=$(cat)

# This is a way to do atomic locks that's portable across mac and linux
LOCKDIR="${TMPDIR:-/tmp}/claude-log.lock"
while ! mkdir "$LOCKDIR" 2>/dev/null; do
    sleep 0.2
done
trap 'rmdir "$LOCKDIR" 2>/dev/null' EXIT

# Assumption: content of transcript_path doesn't change during script execution
transcript_path=$(echo "$stdin" | jq -r ".transcript_path")
# logEvent: TRANSCRIPT_RENEW if it's a new transcript file (and if so, reset our transcript copy)
if [[ ! -f ~/claude-log.transcript_path.txt ]] || [[ $(< ~/claude-log.transcript_path.txt) != "$transcript_path" ]]; then
    jq -nc --argjson logTimestamp "$logTimestamp" --arg logDate "$logDate" '{logEvent: "TRANSCRIPT_RENEW", $logTimestamp, $logDate}' >> ~/claude-log.jsonl
    > ~/claude-log.transcript.jsonl # reset our transcript copy.
fi

[[ -f ~/claude-log.transcript.jsonl ]] || touch ~/claude-log.transcript.jsonl
echo "$transcript_path" > ~/claude-log.transcript_path.txt
diff_output=$(diff ~/claude-log.transcript.jsonl "$transcript_path" 2>/dev/null || true)
cp "$transcript_path" ~/claude-log.transcript.jsonl

# logEvent: TRANSCRIPT_PRUNE
logRemovals=$(echo "$diff_output" | grep -c '^< ' || echo "0")
[[ $logRemovals -gt 0 ]] && jq -nc --argjson logTimestamp "$logTimestamp" --arg logDate "$logDate" --argjson logRemovals "$logRemovals" '{logEvent: "TRANSCRIPT_PRUNE", $logRemovals, $logTimestamp, $logDate}' >> ~/claude-log.jsonl

# logEvent: TRANSCRIPT_ITEM
logAdditions=$(echo "$diff_output" | grep '^> ' | sed 's/^> //' || true)
[[ -n "$logAdditions" ]] && echo "$logAdditions" | jq -c --argjson logTimestamp "$logTimestamp" --arg logDate "$logDate" '{logEvent: "TRANSCRIPT_ITEM", $logTimestamp, $logDate} + .' >> ~/claude-log.jsonl

# logEvent: HOOK
echo "$stdin" | jq -c --argjson logTimestamp "$logTimestamp" --arg logDate "$logDate" '{logEvent: "HOOK", $logTimestamp, $logDate} + .' >> ~/claude-log.jsonl

exit 0
