#!/usr/bin/env bash
#
# capture-detect.sh — BALDART proactive capture hook (event: Stop)
#
# Runs at the end of every Claude Code session. When the just-finished
# session contains cross-document reasoning (the user has been weaving
# together facts from multiple docs/references files), this hook drops a
# *candidate* file into `.claude/capture-queue/` so the next `/capture`
# invocation can surface it and offer to distill the synthesis into a
# durable wiki page.
#
# This hook NEVER spawns Claude itself — it only writes a small JSON
# candidate. The actual synthesis is always a human-approved manual step
# via the `capture` skill.
#
# Stdin: Claude Code passes a JSON envelope; we read `transcript_path`,
#        `session_id`, `cwd` (best-effort — falls back if jq is unavailable).
#
# Exit: always 0. Failure isolation — a non-zero exit on a Stop hook can
#       be ignored by the runtime, but as a matter of hygiene we never
#       propagate errors out of an instrumentation hook.

set -u
exec 2>/dev/null  # silence stderr; we are not user-visible

# --- read envelope --------------------------------------------------------

INPUT=""
if [ ! -t 0 ]; then
  INPUT="$(cat)"
fi

# Try jq first, fall back to grep/sed extraction.
get_field() {
  local field="$1"
  if command -v jq >/dev/null 2>&1; then
    printf '%s' "$INPUT" | jq -r ".$field // empty" 2>/dev/null
  else
    printf '%s' "$INPUT" | sed -n "s/.*\"$field\"[[:space:]]*:[[:space:]]*\"\\([^\"]*\\)\".*/\\1/p" | head -1
  fi
}

TRANSCRIPT_PATH="$(get_field transcript_path)"
SESSION_ID="$(get_field session_id)"
CWD_FROM_ENV="$(get_field cwd)"
CWD="${CWD_FROM_ENV:-$PWD}"

[ -n "$TRANSCRIPT_PATH" ] || exit 0
[ -f "$TRANSCRIPT_PATH" ] || exit 0

cd "$CWD" 2>/dev/null || exit 0

# --- gate on features.has_wiki_overlay -----------------------------------

CONFIG="baldart.config.yml"
[ -f "$CONFIG" ] || exit 0
# Coarse check: look for `has_wiki_overlay: true` (whitespace-tolerant).
if ! grep -E '^\s*has_wiki_overlay\s*:\s*true\b' "$CONFIG" >/dev/null 2>&1; then
  exit 0
fi

# --- gates: kill switch + anti-spam --------------------------------------

QUEUE_DIR=".claude/capture-queue"
mkdir -p "$QUEUE_DIR" || exit 0

[ -f "$QUEUE_DIR/.disabled" ] && exit 0

# Anti-spam: refuse when ≥10 unprocessed candidates already queued.
EXISTING="$(find "$QUEUE_DIR" -maxdepth 1 -type f -name '*.json' 2>/dev/null | wc -l | tr -d ' ')"
[ "${EXISTING:-0}" -ge 10 ] && exit 0

# --- heuristic: is this session worth flagging? --------------------------
#
# We treat "≥3 distinct docs/references-style paths mentioned across the
# session" as a weak signal of cross-document reasoning. False positives
# are acceptable here — the user reviews every candidate in /capture and
# can reject. False negatives are also fine — the user can always invoke
# /capture manually.

REFS="$(grep -ohE '(\./|/|\b)((docs|wiki|references|backlog|prd)/[A-Za-z0-9._/-]+\.(md|yml|yaml|json))' "$TRANSCRIPT_PATH" 2>/dev/null \
  | sort -u | head -10)"

REF_COUNT="$(printf '%s\n' "$REFS" | grep -c . || true)"
[ "${REF_COUNT:-0}" -lt 3 ] && exit 0

# --- write candidate ------------------------------------------------------

TS_FILE="$(date -u +%Y%m%dT%H%M%SZ)"
TS_HUMAN="$(date -u +'%Y-%m-%d %H:%M UTC')"
OUT="$QUEUE_DIR/${TS_FILE}-${SESSION_ID:-unknown}.json"

# JSON-escape with awk (no jq required for emit either).
escape_json() {
  printf '%s' "$1" | awk 'BEGIN{ORS=""} {gsub(/\\/,"\\\\"); gsub(/"/,"\\\""); gsub(/\r/,""); gsub(/\n/,"\\n"); print}'
}

REFS_JSON="["
first=1
while IFS= read -r r; do
  [ -z "$r" ] && continue
  if [ $first -eq 1 ]; then first=0; else REFS_JSON="$REFS_JSON,"; fi
  REFS_JSON="$REFS_JSON\"$(escape_json "$r")\""
done <<EOF
$REFS
EOF
REFS_JSON="$REFS_JSON]"

cat > "$OUT" <<JSON
{
  "trigger": "cross_doc_refs",
  "detected_at": "$TS_HUMAN",
  "session_id": "$(escape_json "${SESSION_ID:-unknown}")",
  "transcript_path": "$(escape_json "$TRANSCRIPT_PATH")",
  "refs_mentioned": $REFS_JSON,
  "excerpt": "Session referenced ${REF_COUNT} distinct doc paths — possible cross-document synthesis worth capturing.",
  "hint": "Run /capture to review this candidate."
}
JSON

exit 0
