#!/bin/bash
# PostToolUse telemetry hook: logs every Skill and Task (subagent-dispatch) call.
# Captures which skills were loaded and which agents were dispatched
# for benchmarking harness compliance.
#
# Output: .forge/state/telemetry.jsonl (one JSON object per line)
#
# Each record now includes work_id when there's an in-progress manifest.
# gate-enforcer.sh filters by work_id so a stale invocation from another work
# item no longer satisfies a fresh gate (closes the cross-work-item bypass
# vector where a previous skill invocation could mask the current one).
# Records with no in-progress work omit the work_id field (null on the
# consuming side).
#
# Note: the subagent-dispatch tool was renamed `Agent` → `Task` (canonical name
# in current Claude Code releases). Both names are accepted here for backward
# compatibility with existing telemetry written before the rename; `Task` is
# the dispatch path going forward and the matcher in hooks.json fires on it.

set -euo pipefail

PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
STATE_DIR="$PROJECT_ROOT/.forge/state"
TELEMETRY_FILE="$STATE_DIR/telemetry.jsonl"

mkdir -p "$STATE_DIR"

# Read hook input from stdin
INPUT=$(cat)

TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // "unknown"')
TIMESTAMP=$(date -u '+%Y-%m-%dT%H:%M:%SZ')

# Locate the in-progress work item (if any). Same scan pattern used by
# pre-compact.sh and session-start.sh. Cost is sub-millisecond — a small
# loop over a handful of manifest files — well within PostToolUse overhead.
ACTIVE_WORK=""
if [ -d "$PROJECT_ROOT/.forge/work" ]; then
    for manifest in "$PROJECT_ROOT/.forge/work"/*/*/manifest.yaml; do
        if [ -f "$manifest" ] && grep -q 'status: in-progress' "$manifest" 2>/dev/null; then
            WORK_NAME="$(basename "$(dirname "$manifest")")"
            WORK_TYPE="$(basename "$(dirname "$(dirname "$manifest")")")"
            ACTIVE_WORK="$WORK_TYPE/$WORK_NAME"
            break
        fi
    done
fi

# work_id field — emitted only when we resolved an in-progress manifest.
# Records without work_id naturally fail the enforcer's per-work-id filter,
# which is the desired behavior (an invocation that happened with no
# work-in-progress context cannot satisfy a gate on a specific work item).
WORK_FIELD=""
if [ -n "$ACTIVE_WORK" ]; then
    WORK_FIELD=",\"work_id\":\"$ACTIVE_WORK\""
fi

# Extract relevant fields based on tool type.
# Task and Agent share input shape (subagent_type + description); accept either.
case "$TOOL_NAME" in
  Skill)
    SKILL_NAME=$(echo "$INPUT" | jq -r '.tool_input.skill // "unknown"')
    echo "{\"timestamp\":\"$TIMESTAMP\",\"type\":\"skill\",\"name\":\"$SKILL_NAME\"$WORK_FIELD}" >> "$TELEMETRY_FILE"
    ;;
  Task|Agent)
    AGENT_TYPE=$(echo "$INPUT" | jq -r '.tool_input.subagent_type // "unknown"')
    DESCRIPTION=$(echo "$INPUT" | jq -r '.tool_input.description // ""')
    echo "{\"timestamp\":\"$TIMESTAMP\",\"type\":\"agent\",\"name\":\"$AGENT_TYPE\",\"description\":\"$DESCRIPTION\"$WORK_FIELD}" >> "$TELEMETRY_FILE"
    ;;
esac

exit 0
