#!/bin/sh
# Git post-checkout hook: warm the codegraph index for the new worktree.
#
# Why: the first agent turn on a fresh worktree otherwise pays for a cold
# index. The engine's one-shot mode (`--graph-only --run-tool ...`) builds the
# graph and exits, so the resident MCP server starts against a warm
# ~/.codegraph/graph.db instead of an empty one.
#
# Arguments git passes to post-checkout:
#   $1 previous HEAD, $2 new HEAD, $3 1 for a branch checkout, 0 for a file checkout
# Only the branch case is worth warming; a file checkout does not move the tree.
#
# Two guards that matter more than the warm itself:
#
# 1. Fail open and stay in the background. Like post-commit, this hook never
#    blocks and never fails. git treats a non-zero post-checkout as an error.
#
# 2. Do not race the resident engine. The engine keeps a single RocksDB at
#    $HOME/.codegraph/graph.db and RocksDB grants one writer process a LOCK.
#    While a `--serve` engine is up it owns that lock, so a one-shot run from
#    this hook would block on it or fail. If the engine socket exists the
#    engine is already indexing and we skip entirely: that is the correct
#    action, not a degraded one.
#
# POSIX sh, ASCII only, LF only.

flag="${3:-0}"
[ "$flag" = "1" ] || exit 0

engine="${CODEGRAPH_SERVER_PATH:-/opt/codegraph/bin/codegraph-server}"
[ -x "$engine" ] || exit 0

# --- log destination --------------------------------------------------------
log_dir="${SYNC_CONFIG_EDGES_LOG_DIR:-/workspace/.hooks}"
mkdir -p "$log_dir" 2>/dev/null || :
log_file="${log_dir}/post-checkout.log"

note() {
    printf '%s %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || printf 'unknown')" "$*" \
        >>"$log_file" 2>/dev/null || :
}

# --- workspace --------------------------------------------------------------
workspace="${CODEGRAPH_WORKSPACE:-}"
if [ -z "$workspace" ]; then
    workspace=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
fi
[ -n "$workspace" ] || exit 0
[ -d "$workspace" ] || exit 0

# --- resident engine guard --------------------------------------------------
socket="${CODEGRAPH_ENGINE_SOCKET:-${HOME:-/home/opencode}/.codegraph/cg-engine.sock}"
if [ -S "$socket" ]; then
    note "skipped: resident engine owns the graph at ${socket}"
    exit 0
fi

# --- warm in the background -------------------------------------------------
# The tool name and arguments are the invocation proven in
# the brain-dump knowledge base section 17: the engine indexes, runs one
# structural query, prints JSON and exits. Its stdout is discarded because the
# point is the side effect on graph.db, not the query result.
(
    exec </dev/null
    # shellcheck disable=SC2016 # the tool arguments are literal JSON, not shell
    "$engine" \
        --graph-only \
        --workspace "$workspace" \
        --exclude node_modules \
        --exclude .git \
        --run-tool codegraph_symbol_search \
        --tool-args '{"query":"warmup","limit":1}' \
        >>"$log_file" 2>&1
    printf '%s warm exit=%s workspace=%s\n' \
        "$(date -u '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || printf 'unknown')" "$?" "$workspace" \
        >>"$log_file" 2>/dev/null || :
) &

exit 0
