#!/usr/bin/env bash
# _git-guard-shim.sh — PATH shim for `git`. Blocks the SAME destructive verbs as
# main-checkout-guard.sh (git restore / checkout -- / checkout . / stash push,pop,
# drop,clear / clean -f* / reset --hard) when they target the SHARED main checkout
# of a repo that has opted into worktree isolation (a <main_root>/.worktrees dir).
#
# WHY A PATH SHIM, NOT JUST A CLAUDE HOOK: Claude Code's PreToolUse hook
# (main-checkout-guard.sh) covers only Claude's own Bash tool. codex (`cdx exec`,
# used by /ask-codex) and cursor-agent run their own internal git calls with no
# equivalent hook. PATH is inherited across every exec boundary — the same
# rationale _tmpjail-shim.sh documents for wrapping claude/codex/cursor-agent
# themselves — so wrapping `git` here catches all three runtimes, and anything
# else spawned underneath them, without depending on per-runtime cooperation.
#
# WHY GATED ON AGENT_BUILD_SCOPE_ACTIVE: that var is exported unconditionally by
# _agent-build-scope for every launch of the wrapped claude/codex/cursor-agent
# CLIs, and inherited by every process they spawn. A human's own interactive
# shell never sets it, so a person typing `git restore` by hand is never
# affected — only git commands running inside an agent-launched process tree are.
set -e

name="$(basename -- "$0")"
SHIM_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Resolve the REAL git binary first, unconditionally. The classification below
# calls git itself (rev-parse) — it MUST use this resolved path (WT_GIT_BIN),
# never bare `git`, or it would resolve back through PATH into this same shim
# and recurse.
real=""
IFS=':' read -ra _parts <<< "$PATH"
for _d in "${_parts[@]}"; do
  [[ "$_d" == "$SHIM_DIR" ]] && continue
  if [[ -x "$_d/$name" && ! -d "$_d/$name" ]]; then
    real="$_d/$name"
    break
  fi
done

if [[ -z "$real" ]]; then
  echo "$name: command not found (git-guard shim found no real binary outside $SHIM_DIR)" >&2
  exit 127
fi

if [[ "${AGENT_BUILD_SCOPE_ACTIVE:-}" == "1" ]]; then
  LIB="$SHIM_DIR/../hooks/lib/worktree-guard-lib.sh"
  if [[ -r "$LIB" ]]; then
    # shellcheck source=../hooks/lib/worktree-guard-lib.sh
    source "$LIB"
    export WT_GIT_BIN="$real"

    EFFECTIVE_DIR="$PWD"
    _args=("$@")
    _i=0
    while [[ $_i -lt ${#_args[@]} ]]; do
      case "${_args[$_i]}" in
        -C)
          _next="${_args[$((_i + 1))]:-}"
          if [[ -n "$_next" ]]; then
            _resolved=$(cd "$EFFECTIVE_DIR" 2>/dev/null && cd "$_next" 2>/dev/null && pwd) || _resolved=""
            [[ -n "$_resolved" ]] && EFFECTIVE_DIR="$_resolved"
          fi
          _i=$((_i + 2))
          ;;
        -c | --git-dir | --work-tree | --namespace)
          _i=$((_i + 2))
          ;;
        -*)
          _i=$((_i + 1))
          ;;
        *)
          break
          ;;
      esac
    done

    if MAIN_ROOT=$(wt_main_root "$EFFECTIVE_DIR") \
      && [[ -d "$MAIN_ROOT/.worktrees" ]] \
      && wt_is_main_checkout_path "$EFFECTIVE_DIR" "$MAIN_ROOT" \
      && wt_has_destructive_git "git $*"; then
      cat >&2 <<MSG
git-guard: this command discards/overwrites working-tree state in the SHARED main
checkout ($MAIN_ROOT) — it can silently destroy another agent session's uncommitted
edits. Work in a claimed worktree instead:
  ~/.claude/bin/od-worktree add <slug>
  cd $MAIN_ROOT/.worktrees/<slug>
MSG
      exit 77
    fi
  fi
fi

exec "$real" "$@"
