#!/bin/sh
# Git post-commit hook: record code -> config edges in the brain-dump graph.
#
# Invoked by git through core.hooksPath (/etc/git-hooks, set system-wide at
# image build), so this file is shared by every clone and worktree in the
# container and is mounted read-only.
#
# Three rules, in order of importance:
#
# 1. Exit 0, always. A commit that has already been created cannot be failed by
#    a post-commit hook in git's model, but a non-zero exit still shows up as an
#    error in every git client and in scripts that check `git commit`'s status.
#    A hook that can fail a workflow gets deleted by whoever hits it first, so
#    this one has no failure path at all.
# 2. Never add latency. The bridge is launched in a detached background
#    subshell; the developer's commit returns as soon as git finishes, whether
#    or not the MCP server is reachable.
# 3. Changed files only. `git diff-tree --no-commit-id --name-only -r HEAD`
#    lists what this commit touched, so a commit that only edits a README does
#    not trigger a scan of the tree.
#
# NUL separation (-z) is used so paths with spaces survive, and the names are
# handed to the bridge on stdin rather than as shell-expanded arguments.
#
# POSIX sh, ASCII only, LF only.

# --- locate the bridge next to this hook -----------------------------------
# CDPATH is cleared so `cd` cannot print a resolved path to stdout, and it is
# spelled with an explicit empty value rather than a bare `CDPATH=` prefix:
# the bare form is correct POSIX but trips shellcheck SC1007.
hook_dir=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd) || exit 0
bridge="${hook_dir}/sync_config_edges.py"
[ -f "$bridge" ] || exit 0
command -v python3 >/dev/null 2>&1 || exit 0

# --- log destination --------------------------------------------------------
log_dir="${SYNC_CONFIG_EDGES_LOG_DIR:-/workspace/.hooks}"
# Best effort: an unwritable log must not stop the hook from exiting 0.
mkdir -p "$log_dir" 2>/dev/null || :
log_file="${log_dir}/sync_config_edges.log"

# --- repository root --------------------------------------------------------
repo=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0
[ -n "$repo" ] || exit 0

commit=$(git rev-parse --short HEAD 2>/dev/null) || commit=unknown

# --- launch detached --------------------------------------------------------
# The whole pipeline lives in a subshell that is immediately backgrounded. It
# gets /dev/null as stdin so it can never read the terminal, and its own stdout
# and stderr both go to the log. Nothing here is waited on.
(
    exec </dev/null
    git diff-tree --no-commit-id --name-only -r -z HEAD 2>/dev/null |
        python3 "$bridge" --repo "$repo" --commit "$commit" --stdin-nul \
            >>"$log_file" 2>&1
) &

exit 0
