#!/usr/bin/env bash
# Capture-wrapper for live adapter conformance evidence (#30, #31).
#
# This script is the value an operator points `CCD_BIN` at when they
# want to capture raw Claude Code or Codex CLI hook stdin / stdout for
# fixture sanitization. It logs the raw bytes to a per-event file in
# `$LIFELOOP_LIVE_CAPTURE_DIR` and forwards the call (stdin and argv)
# unmodified to the real CCD broker at `$LIFELOOP_LIVE_REAL_CCD`. The
# wrapper is transparent to the harness — exit code, stdout, and
# stderr all pass through.
#
# Required env:
#   LIFELOOP_LIVE_CAPTURE_DIR   absolute directory to write raw captures into
#   LIFELOOP_LIVE_REAL_CCD      absolute path to the real CCD binary
#
# Optional env:
#   LIFELOOP_LIVE_CAPTURE_LABEL extra label baked into the filename
#
# Filename shape:
#   <epoch_ns>-<event-name>[-<label>].in.json    raw stdin
#   <epoch_ns>-<event-name>[-<label>].out.json   raw stdout (broker reply)
#   <epoch_ns>-<event-name>[-<label>].argv       one argv entry per line
#   <epoch_ns>-<event-name>[-<label>].rc         exit code of the broker
#
# Per `docs/playbooks/capture-live-adapter-evidence.md`, the operator
# runs the sanitizer over `$LIFELOOP_LIVE_CAPTURE_DIR` to produce
# committable fixtures.

set -euo pipefail

if [[ -z "${LIFELOOP_LIVE_CAPTURE_DIR:-}" ]]; then
    echo "capture-live-hook.sh: LIFELOOP_LIVE_CAPTURE_DIR is unset" >&2
    exit 64
fi
if [[ -z "${LIFELOOP_LIVE_REAL_CCD:-}" ]]; then
    echo "capture-live-hook.sh: LIFELOOP_LIVE_REAL_CCD is unset" >&2
    exit 64
fi
if [[ ! -x "$LIFELOOP_LIVE_REAL_CCD" ]]; then
    echo "capture-live-hook.sh: LIFELOOP_LIVE_REAL_CCD is not executable: $LIFELOOP_LIVE_REAL_CCD" >&2
    exit 64
fi

umask 077
mkdir -p "$LIFELOOP_LIVE_CAPTURE_DIR"
chmod 700 "$LIFELOOP_LIVE_CAPTURE_DIR"

# Extract the hook event name from argv. The CCD host-hook command
# carries `--hook <name>` somewhere in its argv; we find it without
# disturbing argv ordering. Fallback to "unknown" if the convention
# changes.
event_name="unknown"
prev=""
for arg in "$@"; do
    if [[ "$prev" == "--hook" ]]; then
        event_name="$arg"
        break
    fi
    prev="$arg"
done

label="${LIFELOOP_LIVE_CAPTURE_LABEL:-}"
# Portable nanosecond timestamp. `date +%s%N` is GNU coreutils only —
# on BSD date (macOS, the documented operator platform) the literal
# `%N` passes through, which the sanitizer's filename regex rejects
# (so captures are silently dropped) and which collides at second
# resolution within a single Claude turn (rapid hook events back
# to back). Python's time_ns() is portable across the operator
# platforms documented in the playbook, and python3 is already
# required by the orchestrator script and the sanitizer.
ts="$(python3 -c 'import time; print(time.time_ns())')"
suffix=""
if [[ -n "$label" ]]; then
    safe_label="$(printf '%s' "$label" | tr -c 'A-Za-z0-9._-' '_')"
    suffix="-$safe_label"
fi
safe_event_name="$(printf '%s' "$event_name" | tr -c 'A-Za-z0-9._-' '_')"
base="${LIFELOOP_LIVE_CAPTURE_DIR}/${ts}-${safe_event_name}${suffix}"

# Write argv line-per-line so the sanitizer can replay it.
{
    for arg in "$@"; do
        printf '%s\n' "$arg"
    done
} > "${base}.argv"

# Capture stdin to a file then feed it to the broker.
cat > "${base}.in.json"

set +e
"$LIFELOOP_LIVE_REAL_CCD" "$@" < "${base}.in.json" > "${base}.out.json"
rc=$?
set -e

printf '%s\n' "$rc" > "${base}.rc"

# Forward broker stdout to the harness so the hook contract is honored.
cat "${base}.out.json"
exit "$rc"
