#!/usr/bin/env bash
set -euo pipefail

# ─────────────────────────────────────────────────────────────
# Eagle Skills — CLI installer, updater, and manager
# https://github.com/eagleisbatman/eagle-skills
# ─────────────────────────────────────────────────────────────

VERSION="3.3.0"
REPO_URL="https://github.com/eagleisbatman/eagle-skills.git"
SOURCE_FILE="${BASH_SOURCE[0]}"
while [ -L "$SOURCE_FILE" ]; do
  SOURCE_PARENT="$(cd -P "$(dirname "$SOURCE_FILE")" && pwd)"
  SOURCE_FILE="$(readlink "$SOURCE_FILE")"
  [[ "$SOURCE_FILE" != /* ]] && SOURCE_FILE="$SOURCE_PARENT/$SOURCE_FILE"
done
SOURCE_DIR="${EAGLE_SKILLS_SOURCE_DIR:-$(cd "$(dirname "$SOURCE_FILE")/.." && pwd)}"
INSTALL_DIR="${EAGLE_SKILLS_DIR:-$HOME/.eagle-skills}"
TARGET_SELECTION="${EAGLE_SKILLS_TARGET:-claude}"

# ─── Available skills (directory → display) ─────────────────
declare -a SKILL_DIRS=("eagle-ux-review" "eagle-product-diagnostics" "eagle-ad-review" "eagle-anti-slop" "eagle-human-writing" "eagle-clean-doc" "eagle-clean-sheet" "eagle-multi-stack-scaffolder" "eagle-claude-md" "eagle-bootstrap" "eagle-governance" "eagle-feature-flow" "eagle-spectral-review" "eagle-compact-add" "eagle-tracker")
declare -a SKILL_NAMES=("Eagle UX Review" "Eagle Product Diagnostics" "Eagle Ad Review" "Eagle Anti-Slop" "Eagle Human Writing" "Eagle Clean Doc" "Eagle Clean Sheet" "Eagle Multi-Stack Scaffolder" "Eagle CLAUDE.md" "Eagle Bootstrap" "Eagle Governance" "Eagle Feature Flow" "Eagle Spectral Review" "Eagle Compact Add" "Eagle Tracker")
declare -a SKILL_DESCS=(
  "Expert-level UX audits grounded in 65+ UX laws"
  "Three-layer data validation: design intent + behavior + outcomes"
  "Strategy-first ad creative review across any medium"
  "Detect and eliminate AI-generated slop in code, text, and design"
  "Natural prose rewrites that remove AI voice and corporate filler"
  "Modern Word document generation — Helvetica, monochrome, clean"
  "Modern Excel spreadsheet generation — clean tables, monochrome"
  "Research-driven project scaffolding for 13+ technology stacks"
  "Full project onboarding — lean CLAUDE.md, LLM Wiki, Obsidian vault, eagle-skills install"
  "One-time global environment setup — behavioral rules, hooks, vault, plugin checks"
  "Hook-based engineering governance — policy gates, context handoff, instruction shims"
  "Structured dev workflow — plan, build, test, spectral review, anti-slop, commit"
  "Routes Spectral review requests to the right specialist agents"
  "Add new rules to compact-rules.json for verbose commands"
  "Project trackers + Gantt charts as .xlsx that open in Excel and import to Google Sheets"
)
declare -a SKILL_COMMANDS=("/eagle-ux-review" "/eagle-product-diagnostics" "/eagle-ad-review" "/eagle-anti-slop" "/eagle-human-writing" "/eagle-clean-doc" "/eagle-clean-sheet" "/eagle-multi-stack-scaffolder" "/eagle-claude-md" "/eagle-bootstrap" "/eagle-governance" "/eagle-feature-flow" "/eagle-spectral-review" "/eagle-compact-add" "/eagle-tracker")
declare -a SKILL_TRIGGERS=(
  "ux review, ux audit, usability review, heuristic evaluation, critique this design, what's wrong with this UI"
  "validate these findings, product diagnostics, funnel analysis, why isn't this metric moving, triangulate UX and data"
  "review these ads, ad creative review, audit my ads, critique these creatives, ad teardown"
  "slop, anti-slop, clean up AI code, review for slop, detect slop, LLM-generated, over-abstracted, too many comments"
  "human writing, make it sound human, less AI, no AI voice, ghost mode, no corporate tone, degpt"
  "word doc, docx, create a document, write a report, generate a Word file"
  "spreadsheet, excel, xlsx, create a spreadsheet, export to Excel"
  "scaffold, new project, create app, bootstrap, set up project, initialize codebase, start new application, project structure"
  "init claude, setup claude md, create claude.md, project init, eagle init, onboard this project, add claude.md"
  "eagle bootstrap, setup my environment, first time setup, configure claude globally, install eagle environment"
  "govern this project, install governance hooks, agent governance, context bloat guard, hook-based engineering governance"
  "feature flow, build this feature, implement this, dev workflow, eagle flow, start feature, build and ship, full dev cycle, plan and build"
  "spectral agents, spectral review, full spectrum review, run review specialists, triage review agents"
  "compact-add, add compact rules, this command is too verbose, compact this command"
  "project tracker, task tracker, gantt chart, project plan, roadmap, timeline, sprint board, raid log, track tasks with owners and dates"
)
declare -a SKILL_INPUTS=(
  "North star metric|Target user profile (demographics, tech literacy, device/connectivity)|2-3 reference apps the target user opens daily|App identity (chat, marketplace, tool, social, etc.)|Output format: HTML, Word, or both|Screen recording (video) or a folder of screenshots|Optional: PRD or hypothesis document|Optional: User personas, analytics data, competitive screenshots"
  "Goal definitions (success metrics per feature)|Event taxonomy (analytics events mapped to screens and funnels)|Database outcomes (actual vs. target metrics)|Output format: HTML, Word, Excel, or a combination|Optional: UX review report from Eagle UX Review"
  "Campaign strategy (objective, funnel stage, audience, medium/channels, KPI)|Brand context (value proposition, positioning, competitive landscape)|Output format: HTML, Word, or both|Creative files — images, video, audio, PDFs, scripts (any format, any medium)"
  "Code, text, or design files to review|Optional: --aggressive flag for stricter cleanup"
  "Draft prose, README copy, article, report, email, social post, or rewrite request|Optional: target voice, audience, and register"
  "Content for the document (text, data, or instructions)|Optional: document type (report, memo, letter, spec)"
  "Data to populate the spreadsheet (text, CSV, JSON, or instructions)|Optional: sheet structure preferences"
  "What you're building (app type, features, platforms)|Optional: technology preferences|Optional: existing backend/services to integrate with"
  "A project directory (runs in current directory by default)|Optional: Obsidian vault path (auto-detected if configured)"
  "No inputs required (auto-detects what's already configured)"
  "A project directory|Optional: target agents with --target|Optional: enforcement mode warn, block-risky, or strict"
  "Feature description (what to build and why)|Project must have a test suite or instructions to create one"
  "Review scope: changed files, whole project, a PR, or specific paths|Optional: focus area such as security, API, UX, accessibility, database, data integrity, performance, architecture, or quality"
  "Command to compact, or describe which commands are too verbose"
  "A list of tasks with owners, start/end dates, and status (prose, CSV, JSON, or a JSON spec)|Optional: timescale (day/week/month)"
)
declare -a SKILL_OUTPUTS=(
  "HTML and/or Word report with severity-rated findings, embedded evidence, before/after mockups, priority matrix, UX law citations"
  "HTML and/or Word report with goal scorecard, funnel visualizations, three-layer diagnosis. Optional Excel export with structured data"
  "HTML and/or Word report with 10-dimension scoring, per-creative breakdowns, platform compliance audit, creative brief"
  "Cleaned files with slop removed, scored reports for text, refactored code in-place"
  "Rewritten prose with AI fingerprints removed and stronger voice"
  "Professional .docx file with Helvetica/Courier New, monochrome palette, clean tables and code blocks"
  "Professional .xlsx file with clean styling, frozen headers, auto-sized columns"
  "Scaffolded project with docs (RESEARCH.md, DEPENDENCIES.md, STRUCTURE.md, SETUP.md), config files, and boilerplate code"
  "Lean CLAUDE.md, raw/ and wiki/ directories, Obsidian vault symlink"
  "Enriched global CLAUDE.md, compact.sh hook, Obsidian vault config, plugin/agent verification report"
  "Project-local governance hooks, policy config, instruction shims, and PM-readable status"
  "Committed, tested, reviewed code with clean git history"
  "A routed review plan naming the exact Spectral specialists to run"
  "New rules appended to compact-rules.json"
  "A styled .xlsx with Tracker (status dropdowns, % data bars), a conditional-formatting Gantt with today marker, and a dashboard — opens in Excel and imports to Google Sheets"
)
declare -a SKILL_EXAMPLES=(
  "UX review this app — here's a screen recording of the onboarding flow"
  "Why isn't our retention improving? Here's our Firebase events and DB metrics"
  "Review these ad creatives — folder is ./ads/. Campaign is awareness on Meta and radio"
  "Review this file for slop"
  "Rewrite this README so it sounds human and less corporate"
  "Create a Word doc summarizing these API endpoints"
  "Export this data to a clean Excel spreadsheet"
  "Scaffold a fitness tracking app for iOS and Android with a Python backend"
  "Set up this project for Claude — create a CLAUDE.md and wiki structure"
  "Run eagle bootstrap to set up my global Claude environment"
  "Govern this project with hooks so agents cannot skip DB, dependency, test, or context gates"
  "Build a rate-limiting middleware for the auth routes"
  "Use Spectral Agents to review this PR and pick the right specialists"
  "That terraform plan output was way too long, compact it"
  "Turn this list of tasks, owners, and dates into a project tracker with a Gantt chart for Google Sheets"
)

# ─── Available agents (filename without .md → display) ──────
declare -a AGENT_FILES=(
  "eagle-spectral-triage"
  "eagle-spectral-plan"
  "eagle-spectral-investigate"
  "eagle-spectral-ship"
  "eagle-security-audit"
  "eagle-architecture-review"
  "eagle-performance-review"
  "eagle-code-quality"
  "eagle-ux-code-review"
  "eagle-accessibility-review"
  "eagle-api-review"
  "eagle-data-integrity"
  "eagle-database-review"
)
declare -a AGENT_NAMES=(
  "Eagle Spectral Triage"
  "Eagle Spectral Plan"
  "Eagle Spectral Investigate"
  "Eagle Spectral Ship"
  "Eagle Security Audit"
  "Eagle Architecture Review"
  "Eagle Performance Review"
  "Eagle Code Quality"
  "Eagle UX Code Review"
  "Eagle Accessibility Review"
  "Eagle API Review"
  "Eagle Data Integrity"
  "Eagle Database Review"
)
declare -a AGENT_DESCS=(
  "Review router — selects the right Spectral specialists for a scope"
  "Planning and architecture design — scopes features, evaluates approaches"
  "Root-cause debugging — traces code paths, tests hypotheses, applies fixes"
  "Pre-ship pipeline and PR creation — runs gates, cleans diff, creates PR"
  "Deep vulnerability hunting — injection, auth flaws, data exposure, supply chain"
  "Structural health — dependency management, coupling, cohesion, design patterns"
  "Bottleneck and resource usage analysis — memory leaks, N+1 queries, bundle bloat"
  "Readability, dead code, duplication, convention violations, test gaps"
  "Frontend code UX patterns — loading states, error handling, form validation, responsive design"
  "WCAG 2.1 AA compliance — semantic HTML, ARIA, keyboard nav, color contrast"
  "API design consistency — endpoints, contracts, error handling, versioning, pagination"
  "Data corruption and loss vectors — race conditions, partial writes, missing transactions"
  "Schema design, query performance, migrations, indexes, ORM usage"
)
declare -a AGENT_CATEGORIES=(
  "orchestrator"
  "lifecycle"
  "lifecycle"
  "lifecycle"
  "review"
  "review"
  "review"
  "review"
  "review"
  "review"
  "review"
  "review"
  "review"
)

# ─── Colors ──────────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
BOLD='\033[1m'
DIM='\033[2m'
RESET='\033[0m'

# ─── Helpers ─────────────────────────────────────────────────
info()    { echo -e "${BLUE}info${RESET}  $1"; }
ok()      { echo -e "${GREEN}  ok${RESET}  $1"; }
warn()    { echo -e "${YELLOW}warn${RESET}  $1"; }
err()     { echo -e "${RED} err${RESET}  $1"; }
header()  { echo -e "\n${BOLD}${MAGENTA}$1${RESET}\n"; }

banner() {
  echo -e "${BOLD}"
  cat << 'BANNER'
███████╗░█████╗░░██████╗░██╗░░░░░███████╗  ░██████╗██╗░░██╗██╗██╗░░░░░██╗░░░░░░██████╗
██╔════╝██╔══██╗██╔════╝░██║░░░░░██╔════╝  ██╔════╝██║░██╔╝██║██║░░░░░██║░░░░░██╔════╝
█████╗░░███████║██║░░██╗░██║░░░░░█████╗░░  ╚█████╗░█████═╝░██║██║░░░░░██║░░░░░╚█████╗░
██╔══╝░░██╔══██║██║░░╚██╗██║░░░░░██╔══╝░░  ░╚═══██╗██╔═██╗░██║██║░░░░░██║░░░░░░╚═══██╗
███████╗██║░░██║╚██████╔╝███████╗███████╗  ██████╔╝██║░╚██╗██║███████╗███████╗██████╔╝
╚══════╝╚═╝░░╚═╝░╚═════╝░╚══════╝╚══════╝  ╚═════╝░╚═╝░░╚═╝╚═╝╚══════╝╚══════╝╚═════╝
BANNER
  echo -e "${RESET}"
}

check_git() {
  if ! command -v git &>/dev/null; then
    err "git is required but not installed."
    exit 1
  fi
}

target_display_name() {
  case "$1" in
    claude) echo "Claude Code" ;;
    codex) echo "Codex" ;;
    grok) echo "Grok Build" ;;
    antigravity) echo "Google Antigravity" ;;
    *) echo "$1" ;;
  esac
}

normalize_targets() {
  local raw="${1:-claude}"
  local -a normalized=()
  IFS=',' read -ra requested <<< "$raw"
  for target in "${requested[@]}"; do
    target=$(echo "$target" | tr '[:upper:]' '[:lower:]' | tr -d ' ')
    case "$target" in
      all)
        normalized+=("claude" "codex" "grok" "antigravity")
        ;;
      claude|claude-code)
        normalized+=("claude")
        ;;
      codex|openai-codex)
        normalized+=("codex")
        ;;
      grok|grog|grok-build|grogbuild)
        normalized+=("grok")
        ;;
      antigravity|anti-gravity|google-antigravity)
        normalized+=("antigravity")
        ;;
      "")
        ;;
      *)
        err "Unknown target: $target"
        echo "  Valid targets: claude, codex, grok, antigravity, all"
        exit 1
        ;;
    esac
  done

  TARGETS=()
  local seen=" "
  for target in "${normalized[@]}"; do
    if [[ "$seen" != *" $target "* ]]; then
      TARGETS+=("$target")
      seen+="$target "
    fi
  done

  if [ ${#TARGETS[@]} -eq 0 ]; then
    TARGETS=("claude")
  fi
}

parse_target_args() {
  POSITIONAL_ARGS=()
  while [ "$#" -gt 0 ]; do
    case "$1" in
      --target|-t)
        if [ $# -lt 2 ]; then
          err "--target requires a value"
          exit 1
        fi
        TARGET_SELECTION="$2"
        shift 2
        ;;
      --target=*)
        TARGET_SELECTION="${1#--target=}"
        shift
        ;;
      --all-targets)
        TARGET_SELECTION="all"
        shift
        ;;
      *)
        POSITIONAL_ARGS+=("$1")
        shift
        ;;
    esac
  done
  normalize_targets "$TARGET_SELECTION"
}

target_skill_dirs() {
  case "$1" in
    claude)
      echo "$HOME/.claude/skills"
      ;;
    codex)
      echo "$HOME/.codex/skills"
      ;;
    grok)
      echo "$HOME/.grok/skills"
      ;;
    antigravity)
      echo "$HOME/.gemini/config/skills"
      echo "$HOME/.gemini/antigravity-ide/skills"
      ;;
  esac
}

target_agent_dirs() {
  case "$1" in
    claude)
      echo "$HOME/.claude/agents"
      ;;
    grok)
      # Grok Build discovers Claude-compatible agent definitions today.
      echo "$HOME/.claude/agents"
      ;;
  esac
}

target_supports_agents() {
  case "$1" in
    claude|grok) return 0 ;;
    *) return 1 ;;
  esac
}

ensure_target_dirs() {
  local target="$1"
  while IFS= read -r dir; do
    [ -z "$dir" ] && continue
    mkdir -p "$dir"
  done < <(target_skill_dirs "$target")

  while IFS= read -r dir; do
    [ -z "$dir" ] && continue
    mkdir -p "$dir"
  done < <(target_agent_dirs "$target")
}

print_targets() {
  local names=()
  for target in "${TARGETS[@]}"; do
    names+=("$(target_display_name "$target")")
  done
  local IFS=", "
  echo "${names[*]}"
}

# ─── Selection menu ──────────────────────────────────────────
select_items() {
  local -a selected_skills=()
  local -a selected_agents=()
  local skill_count=${#SKILL_DIRS[@]}
  local agent_count=${#AGENT_FILES[@]}
  local total=$((skill_count + agent_count))

  banner
  echo -e "  ${DIM}Select skills and agents to install${RESET}"
  echo ""

  echo -e "  ${BOLD}Skills${RESET} ${DIM}(installed for $(print_targets))${RESET}"
  echo ""
  for i in "${!SKILL_DIRS[@]}"; do
    local num=$((i + 1))
    echo -e "    ${CYAN}${num}${RESET}  ${BOLD}${SKILL_NAMES[$i]}${RESET}"
    echo -e "       ${DIM}${SKILL_DESCS[$i]}${RESET}"
    echo ""
  done

  echo -e "  ${BOLD}Agents${RESET} ${DIM}(Claude Code and Grok Build targets only)${RESET}"
  echo ""
  for i in "${!AGENT_FILES[@]}"; do
    local num=$((skill_count + i + 1))
    local category="${AGENT_CATEGORIES[$i]}"
    local tag=""
    case "$category" in
      orchestrator) tag="${MAGENTA}orchestrator${RESET}" ;;
      lifecycle)    tag="${BLUE}lifecycle${RESET}" ;;
      review)       tag="${GREEN}review${RESET}" ;;
    esac
    echo -e "    ${CYAN}${num}${RESET}  ${BOLD}${AGENT_NAMES[$i]}${RESET}  ${DIM}[${tag}${DIM}]${RESET}"
    echo -e "       ${DIM}${AGENT_DESCS[$i]}${RESET}"
    echo ""
  done

  echo -e "    ${CYAN}a${RESET}  ${BOLD}All skills and agents${RESET}"
  echo ""

  read -rp "  Select items to install (e.g. 1,3,8 or a for all): " choice

  if [[ "$choice" =~ ^[Aa]$ ]]; then
    selected_skills=("${SKILL_DIRS[@]}")
    selected_agents=("${AGENT_FILES[@]}")
  else
    IFS=',' read -ra nums <<< "$choice"
    for num in "${nums[@]}"; do
      num=$(echo "$num" | tr -d ' ')
      if [[ "$num" =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le "$total" ]; then
        if [ "$num" -le "$skill_count" ]; then
          selected_skills+=("${SKILL_DIRS[$((num - 1))]}")
        else
          local agent_idx=$((num - skill_count - 1))
          selected_agents+=("${AGENT_FILES[$agent_idx]}")
        fi
      else
        warn "Skipping invalid selection: $num"
      fi
    done
  fi

  if [ ${#selected_skills[@]} -eq 0 ] && [ ${#selected_agents[@]} -eq 0 ]; then
    err "No items selected."
    exit 1
  fi

  SELECTED_SKILLS=("${selected_skills[@]+"${selected_skills[@]}"}")
  SELECTED_AGENTS=("${selected_agents[@]+"${selected_agents[@]}"}")
}

# ─── Commands ────────────────────────────────────────────────

install_skill_to_dir() {
  local skill="$1"
  local dst_root="$2"
  local src="$INSTALL_DIR/$skill"
  local dst="$dst_root/$skill"

  if [ ! -d "$src" ]; then
    warn "Skill directory not found: $src (skipping)"
    return 1
  fi

  if [ -L "$dst" ]; then
    rm "$dst"
  elif [ -d "$dst" ]; then
    warn "$dst exists and is not a symlink. Overwrite? [y/N]"
    read -rp "  " answer
    if [[ "$answer" =~ ^[Yy]$ ]]; then
      rm -rf "$dst"
    else
      warn "Skipping $skill"
      return 1
    fi
  fi

  ln -sf "$src" "$dst"
  return 0
}

install_agent_to_dir() {
  local agent="$1"
  local dst_root="$2"
  local src="$INSTALL_DIR/agents/${agent}.md"
  local dst="$dst_root/${agent}.md"

  if [ ! -f "$src" ]; then
    warn "Agent file not found: $src (skipping)"
    return 1
  fi

  if [ -L "$dst" ]; then
    rm "$dst"
  elif [ -f "$dst" ]; then
    warn "$dst exists and is not a symlink. Overwrite? [y/N]"
    read -rp "  " answer
    if [[ "$answer" =~ ^[Yy]$ ]]; then
      rm -f "$dst"
    else
      warn "Skipping $agent"
      return 1
    fi
  fi

  ln -sf "$src" "$dst"
  return 0
}

cmd_install() {
  check_git

  for target in "${TARGETS[@]}"; do
    ensure_target_dirs "$target"
  done

  select_items

  echo ""

  # Clone or update the repo
  if [ -d "$INSTALL_DIR/.git" ]; then
    info "Updating existing clone at $INSTALL_DIR"
    git -C "$INSTALL_DIR" pull --quiet
    ok "Repository updated"
  else
    info "Cloning eagle-skills to $INSTALL_DIR"
    git clone --quiet "$REPO_URL" "$INSTALL_DIR"
    ok "Repository cloned"
  fi

  local count=0

  for target in "${TARGETS[@]}"; do
    header "Installing for $(target_display_name "$target")"

    while IFS= read -r skills_dir; do
      [ -z "$skills_dir" ] && continue
      for skill in "${SELECTED_SKILLS[@]+"${SELECTED_SKILLS[@]}"}"; do
        [ -z "$skill" ] && continue
        if install_skill_to_dir "$skill" "$skills_dir"; then
          ok "Installed skill ${BOLD}$(skill_display_name "$skill")${RESET} -> $skills_dir"
          count=$((count + 1))
        fi
      done
    done < <(target_skill_dirs "$target")

    if target_supports_agents "$target"; then
      while IFS= read -r agents_dir; do
        [ -z "$agents_dir" ] && continue
        for agent in "${SELECTED_AGENTS[@]+"${SELECTED_AGENTS[@]}"}"; do
          [ -z "$agent" ] && continue
          if install_agent_to_dir "$agent" "$agents_dir"; then
            ok "Installed agent ${BOLD}$(agent_display_name "$agent")${RESET} -> $agents_dir"
            count=$((count + 1))
          fi
        done
      done < <(target_agent_dirs "$target")
    elif [ ${#SELECTED_AGENTS[@]} -gt 0 ]; then
      warn "$(target_display_name "$target") does not support Eagle agent files yet; skills were installed."
    fi
  done

  echo ""
  if [ "$count" -gt 0 ]; then
    echo -e "  ${GREEN}${BOLD}$count item(s) installed.${RESET}"
    echo -e "  ${DIM}Items are symlinked — run ${RESET}eagle-skills update${DIM} to get the latest.${RESET}"
  else
    warn "No items were installed."
  fi
  echo ""
}

cmd_update() {
  if [ ! -d "$INSTALL_DIR/.git" ]; then
    err "Eagle Skills not found at $INSTALL_DIR"
    echo -e "  ${DIM}Run ${RESET}eagle-skills install${DIM} first.${RESET}"
    exit 1
  fi

  header "Updating Eagle Skills"

  local before
  before=$(git -C "$INSTALL_DIR" rev-parse HEAD)
  git -C "$INSTALL_DIR" pull --quiet
  local after
  after=$(git -C "$INSTALL_DIR" rev-parse HEAD)

  if [ "$before" = "$after" ]; then
    ok "Already up to date."
  else
    local changes
    changes=$(git -C "$INSTALL_DIR" log --oneline "$before..$after" | wc -l | tr -d ' ')
    ok "Updated ($changes new commit(s))"
    echo ""
    echo -e "  ${DIM}Recent changes:${RESET}"
    git -C "$INSTALL_DIR" log --oneline "$before..$after" | head -10 | while read -r line; do
      echo -e "    ${DIM}$line${RESET}"
    done
  fi

  # Verify symlinks still work for selected targets
  echo ""
  local broken=0
  for target in "${TARGETS[@]}"; do
    echo -e "  ${BOLD}$(target_display_name "$target")${RESET}"
    while IFS= read -r skills_dir; do
      [ -z "$skills_dir" ] && continue
      for skill in "${SKILL_DIRS[@]}"; do
        local dst="$skills_dir/$skill"
        if [ -L "$dst" ]; then
          if [ -d "$dst" ]; then
            ok "$skill"
          else
            err "$skill — broken symlink"
            broken=$((broken + 1))
          fi
        fi
      done
    done < <(target_skill_dirs "$target")

    while IFS= read -r agents_dir; do
      [ -z "$agents_dir" ] && continue
      for agent in "${AGENT_FILES[@]}"; do
        local dst="$agents_dir/${agent}.md"
        if [ -L "$dst" ]; then
          if [ -f "$dst" ]; then
            ok "$agent"
          else
            err "$agent — broken symlink"
            broken=$((broken + 1))
          fi
        fi
      done
    done < <(target_agent_dirs "$target")
  done

  if [ "$broken" -gt 0 ]; then
    warn "$broken broken symlink(s). Run ${RESET}eagle-skills install${DIM} to fix.${RESET}"
  fi
  echo ""
}

cmd_status() {
  header "Eagle Skills — Status"

  # Check install directory
  if [ -d "$INSTALL_DIR/.git" ]; then
    local commit
    commit=$(git -C "$INSTALL_DIR" log --oneline -1)
    ok "Repo: $INSTALL_DIR"
    echo -e "     ${DIM}$commit${RESET}"

    # Check for updates
    git -C "$INSTALL_DIR" fetch --quiet 2>/dev/null || true
    local local_rev remote_rev
    local_rev=$(git -C "$INSTALL_DIR" rev-parse HEAD)
    remote_rev=$(git -C "$INSTALL_DIR" rev-parse '@{u}' 2>/dev/null || echo "$local_rev")
    if [ "$local_rev" != "$remote_rev" ]; then
      local behind
      behind=$(git -C "$INSTALL_DIR" rev-list --count HEAD..'@{u}' 2>/dev/null || echo "?")
      warn "Update available ($behind commit(s) behind)"
    fi
  else
    warn "Not installed. Run: eagle-skills install"
    return
  fi

  echo ""

  for target in "${TARGETS[@]}"; do
    echo -e "  ${BOLD}$(target_display_name "$target")${RESET}"
    echo ""

    local installed_skills=0
    local skill_slots=0
    echo -e "    ${BOLD}Skills:${RESET}"
    while IFS= read -r skills_dir; do
      [ -z "$skills_dir" ] && continue
      echo -e "      ${DIM}$skills_dir${RESET}"
      for i in "${!SKILL_DIRS[@]}"; do
        local skill="${SKILL_DIRS[$i]}"
        local dst="$skills_dir/$skill"
        skill_slots=$((skill_slots + 1))
        if [ -L "$dst" ] && [ -d "$dst" ]; then
          echo -e "        ${GREEN}*${RESET} ${BOLD}${SKILL_NAMES[$i]}${RESET}"
          echo -e "          ${DIM}-> $(readlink "$dst")${RESET}"
          installed_skills=$((installed_skills + 1))
        elif [ -L "$dst" ]; then
          echo -e "        ${RED}!${RESET} ${BOLD}${SKILL_NAMES[$i]}${RESET} ${RED}(broken symlink)${RESET}"
        elif [ -d "$dst" ]; then
          echo -e "        ${YELLOW}~${RESET} ${BOLD}${SKILL_NAMES[$i]}${RESET} ${YELLOW}(copied, not symlinked)${RESET}"
          installed_skills=$((installed_skills + 1))
        else
          echo -e "        ${DIM}-${RESET} ${DIM}${SKILL_NAMES[$i]}${RESET} ${DIM}(not installed)${RESET}"
        fi
      done
    done < <(target_skill_dirs "$target")
    echo -e "      ${DIM}$installed_skills of $skill_slots skill slots installed${RESET}"

    local installed_agents=0
    local agent_slots=0
    if target_supports_agents "$target"; then
      echo ""
      echo -e "    ${BOLD}Agents:${RESET}"
      while IFS= read -r agents_dir; do
        [ -z "$agents_dir" ] && continue
        echo -e "      ${DIM}$agents_dir${RESET}"
        for i in "${!AGENT_FILES[@]}"; do
          local agent="${AGENT_FILES[$i]}"
          local dst="$agents_dir/${agent}.md"
          agent_slots=$((agent_slots + 1))
          if [ -L "$dst" ] && [ -f "$dst" ]; then
            echo -e "        ${GREEN}*${RESET} ${BOLD}${AGENT_NAMES[$i]}${RESET}"
            echo -e "          ${DIM}-> $(readlink "$dst")${RESET}"
            installed_agents=$((installed_agents + 1))
          elif [ -L "$dst" ]; then
            echo -e "        ${RED}!${RESET} ${BOLD}${AGENT_NAMES[$i]}${RESET} ${RED}(broken symlink)${RESET}"
          elif [ -f "$dst" ]; then
            echo -e "        ${YELLOW}~${RESET} ${BOLD}${AGENT_NAMES[$i]}${RESET} ${YELLOW}(copied, not symlinked)${RESET}"
            installed_agents=$((installed_agents + 1))
          else
            echo -e "        ${DIM}-${RESET} ${DIM}${AGENT_NAMES[$i]}${RESET} ${DIM}(not installed)${RESET}"
          fi
        done
      done < <(target_agent_dirs "$target")
      echo -e "      ${DIM}$installed_agents of $agent_slots agent slots installed${RESET}"
    else
      echo ""
      echo -e "    ${DIM}Agent files are not supported for this target; install Eagle Spectral Review as a skill.${RESET}"
    fi
    echo ""
  done
  echo ""
}

cmd_uninstall() {
  header "Uninstall Eagle Skills"

  local removed=0

  for target in "${TARGETS[@]}"; do
    header "Removing from $(target_display_name "$target")"

    while IFS= read -r skills_dir; do
      [ -z "$skills_dir" ] && continue
      for i in "${!SKILL_DIRS[@]}"; do
        local skill="${SKILL_DIRS[$i]}"
        local dst="$skills_dir/$skill"
        if [ -L "$dst" ]; then
          rm "$dst"
          ok "Removed skill ${SKILL_NAMES[$i]} from $skills_dir"
          removed=$((removed + 1))
        elif [ -d "$dst" ]; then
          read -rp "  Remove ${SKILL_NAMES[$i]} from $skills_dir (not a symlink — will delete)? [y/N] " answer
          if [[ "$answer" =~ ^[Yy]$ ]]; then
            rm -rf "$dst"
            ok "Removed skill ${SKILL_NAMES[$i]} from $skills_dir"
            removed=$((removed + 1))
          fi
        fi
      done
    done < <(target_skill_dirs "$target")

    while IFS= read -r agents_dir; do
      [ -z "$agents_dir" ] && continue
      for i in "${!AGENT_FILES[@]}"; do
        local agent="${AGENT_FILES[$i]}"
        local dst="$agents_dir/${agent}.md"
        if [ -L "$dst" ]; then
          rm "$dst"
          ok "Removed agent ${AGENT_NAMES[$i]} from $agents_dir"
          removed=$((removed + 1))
        elif [ -f "$dst" ]; then
          read -rp "  Remove ${AGENT_NAMES[$i]} from $agents_dir (not a symlink — will delete)? [y/N] " answer
          if [[ "$answer" =~ ^[Yy]$ ]]; then
            rm -f "$dst"
            ok "Removed agent ${AGENT_NAMES[$i]} from $agents_dir"
            removed=$((removed + 1))
          fi
        fi
      done
    done < <(target_agent_dirs "$target")
  done

  if [ "$removed" -eq 0 ]; then
    info "No items were installed."
  else
    ok "$removed item(s) removed."
  fi

  # Optionally remove the clone
  if [ -d "$INSTALL_DIR" ]; then
    echo ""
    read -rp "  Also remove the cloned repo at $INSTALL_DIR? [y/N] " answer
    if [[ "$answer" =~ ^[Yy]$ ]]; then
      rm -rf "$INSTALL_DIR"
      ok "Repo removed."
    fi
  fi
  echo ""
}

skill_display_name() {
  local dir="$1"
  for i in "${!SKILL_DIRS[@]}"; do
    if [ "${SKILL_DIRS[$i]}" = "$dir" ]; then
      echo "${SKILL_NAMES[$i]}"
      return
    fi
  done
  echo "$dir"
}

agent_display_name() {
  local file="$1"
  for i in "${!AGENT_FILES[@]}"; do
    if [ "${AGENT_FILES[$i]}" = "$file" ]; then
      echo "${AGENT_NAMES[$i]}"
      return
    fi
  done
  echo "$file"
}

# ─── Usage command ──────────────────────────────────────────

print_skill_usage() {
  local i="$1"
  echo -e "  ${BOLD}${MAGENTA}${SKILL_NAMES[$i]}${RESET}"
  echo ""
  echo -e "    ${BOLD}Slash command:${RESET}  ${CYAN}${SKILL_COMMANDS[$i]}${RESET}"
  echo -e "    ${BOLD}Trigger with:${RESET}   ${DIM}${SKILL_TRIGGERS[$i]}${RESET}"
  echo ""
  echo -e "    ${BOLD}Required inputs:${RESET}"
  local shown_optional=false
  IFS='|' read -ra items <<< "${SKILL_INPUTS[$i]}"
  for item in "${items[@]}"; do
    item=$(echo "$item" | sed 's/^ *//')
    if [[ "$item" == Optional:* ]]; then
      if [ "$shown_optional" = false ]; then
        echo ""
        echo -e "    ${BOLD}Optional inputs:${RESET}"
        shown_optional=true
      fi
      item="${item#Optional: }"
      echo -e "      ${DIM}-${RESET} $item"
    else
      echo -e "      ${DIM}-${RESET} $item"
    fi
  done
  echo ""
  echo -e "    ${BOLD}Output:${RESET}"
  echo -e "      ${SKILL_OUTPUTS[$i]}"
  echo ""
  echo -e "    ${BOLD}Example:${RESET}"
  echo -e "      ${DIM}You:${RESET} ${SKILL_EXAMPLES[$i]}"
  echo ""
}

print_agent_usage() {
  local i="$1"
  local category="${AGENT_CATEGORIES[$i]}"
  local tag=""
  case "$category" in
    orchestrator) tag="${MAGENTA}orchestrator${RESET}" ;;
    lifecycle)    tag="${BLUE}lifecycle${RESET}" ;;
    review)       tag="${GREEN}review${RESET}" ;;
  esac
  echo -e "  ${BOLD}${MAGENTA}${AGENT_NAMES[$i]}${RESET}  ${DIM}[${tag}${DIM}]${RESET}"
  echo ""
  echo -e "    ${BOLD}Agent name:${RESET}  ${CYAN}${AGENT_FILES[$i]}${RESET}"
  echo -e "    ${BOLD}Category:${RESET}    ${DIM}${category}${RESET}"
  echo ""
  echo -e "    ${BOLD}Description:${RESET}"
  echo -e "      ${AGENT_DESCS[$i]}"
  echo ""
  echo -e "    ${BOLD}Invoke:${RESET}"
  echo -e "      ${DIM}Claude Code and Grok Build can dispatch this agent by name,${RESET}"
  echo -e "      ${DIM}or you can ask: \"run ${AGENT_FILES[$i]}\"${RESET}"
  echo ""
}

cmd_usage() {
  local filter="${1:-}"

  header "Eagle Skills — How to Use"

  # Determine which items to show
  local -a show_skill_indices=()
  local -a show_agent_indices=()
  local has_installed=false

  if [ -n "$filter" ]; then
    local found=false
    for i in "${!SKILL_DIRS[@]}"; do
      if [ "${SKILL_DIRS[$i]}" = "$filter" ] || [ "${SKILL_COMMANDS[$i]}" = "/$filter" ] || [ "${SKILL_COMMANDS[$i]}" = "$filter" ]; then
        show_skill_indices+=("$i")
        found=true
        break
      fi
    done
    if [ "$found" = false ]; then
      for i in "${!AGENT_FILES[@]}"; do
        if [ "${AGENT_FILES[$i]}" = "$filter" ]; then
          show_agent_indices+=("$i")
          found=true
          break
        fi
      done
    fi
    if [ "$found" = false ]; then
      err "Unknown skill or agent: $filter"
      echo -e "  ${DIM}Skills: ${SKILL_DIRS[*]}${RESET}"
      echo -e "  ${DIM}Agents: ${AGENT_FILES[*]}${RESET}"
      echo ""
      return 1
    fi
  else
    local seen_skills=" "
    local seen_agents=" "
    for target in "${TARGETS[@]}"; do
      while IFS= read -r skills_dir; do
        [ -z "$skills_dir" ] && continue
        for i in "${!SKILL_DIRS[@]}"; do
          local dst="$skills_dir/${SKILL_DIRS[$i]}"
          if { [ -L "$dst" ] && [ -d "$dst" ]; } || [ -d "$dst" ]; then
            if [[ "$seen_skills" != *" $i "* ]]; then
              show_skill_indices+=("$i")
              seen_skills+="$i "
            fi
            has_installed=true
          fi
        done
      done < <(target_skill_dirs "$target")

      while IFS= read -r agents_dir; do
        [ -z "$agents_dir" ] && continue
        for i in "${!AGENT_FILES[@]}"; do
          local dst="$agents_dir/${AGENT_FILES[$i]}.md"
          if { [ -L "$dst" ] && [ -f "$dst" ]; } || [ -f "$dst" ]; then
            if [[ "$seen_agents" != *" $i "* ]]; then
              show_agent_indices+=("$i")
              seen_agents+="$i "
            fi
            has_installed=true
          fi
        done
      done < <(target_agent_dirs "$target")
    done

    if [ ${#show_skill_indices[@]} -eq 0 ] && [ ${#show_agent_indices[@]} -eq 0 ]; then
      echo -e "  ${DIM}Nothing installed. Showing all available items.${RESET}"
      echo -e "  ${DIM}Run ${RESET}eagle-skills install${DIM} to get started.${RESET}"
      echo ""
      for i in "${!SKILL_DIRS[@]}"; do show_skill_indices+=("$i"); done
      for i in "${!AGENT_FILES[@]}"; do show_agent_indices+=("$i"); done
    else
      local total=$(( ${#show_skill_indices[@]} + ${#show_agent_indices[@]} ))
      echo -e "  ${DIM}Showing $total installed item(s) for $(print_targets). Run ${RESET}eagle-skills usage <name>${DIM} for details on one.${RESET}"
      echo ""
    fi
  fi

  if [ ${#show_skill_indices[@]} -gt 0 ]; then
    echo -e "  ${BOLD}${CYAN}── Skills ──${RESET}"
    echo ""
    for i in "${show_skill_indices[@]}"; do
      print_skill_usage "$i"
    done
  fi

  if [ ${#show_agent_indices[@]} -gt 0 ]; then
    echo -e "  ${BOLD}${CYAN}── Agents ──${RESET}"
    echo ""
    for i in "${show_agent_indices[@]}"; do
      print_agent_usage "$i"
    done
  fi

  echo -e "  ${DIM}────────────────────────────────────────────────${RESET}"
  echo ""
  echo -e "  ${BOLD}Tips:${RESET}"
  echo -e "    ${DIM}-${RESET} Skills activate when an agent detects matching intent, or invoke with slash commands"
  echo -e "    ${DIM}-${RESET} Agent files work in Claude Code and Grok Build — ask the agent to run one by name"
  echo -e "    ${DIM}-${RESET} Ask for specific review agents by name, or describe what you need"
  echo ""
}

cmd_govern() {
  local targets
  local IFS=","
  targets="${TARGETS[*]}"
  EAGLE_SKILLS_SOURCE_DIR="$SOURCE_DIR" EAGLE_SKILLS_TARGETS="$targets" bash "$SOURCE_DIR/scripts/govern.sh" "${POSITIONAL_ARGS[@]+"${POSITIONAL_ARGS[@]}"}"
}

cmd_help() {
  banner
  echo -e "  ${BOLD}Eagle Skills${RESET} v${VERSION}"
  echo -e "  ${DIM}Skills and agents for Claude Code, Codex, Grok Build, and Antigravity${RESET}"
  echo ""
  echo -e "${BOLD}Usage:${RESET}"
  echo "  eagle-skills <command> [--target claude|codex|grok|antigravity|all]"
  echo ""
  echo -e "${BOLD}Commands:${RESET}"
  echo "  install     Select and install skills and agents"
  echo "  update      Pull latest changes (symlinked items update automatically)"
  echo "  status      Show installed skills/agents and check for updates"
  echo "  usage       Show how to use installed items (inputs, outputs, examples)"
  echo "  uninstall   Remove installed skills and agents"
  echo "  govern      Install and verify hook-based project governance"
  echo "  help        Show this help message"
  echo ""
  echo -e "${BOLD}Quick start:${RESET}"
  echo "  npx eagle-skills install"
  echo "  npx eagle-skills install --target all"
  echo "  npx eagle-skills govern apply --target all --mode warn"
  echo ""
  echo -e "${BOLD}Alternative (without npm):${RESET}"
  echo "  curl -fsSL https://raw.githubusercontent.com/eagleisbatman/eagle-skills/main/install.sh | bash"
  echo ""

  echo -e "${BOLD}Skills${RESET} ${DIM}(${#SKILL_DIRS[@]} — invoked via slash commands)${RESET}"
  echo ""
  for i in "${!SKILL_DIRS[@]}"; do
    echo -e "  ${BOLD}$((i + 1)).${RESET} ${CYAN}${SKILL_COMMANDS[$i]}${RESET}"
    echo -e "     ${DIM}${SKILL_DESCS[$i]}${RESET}"
  done
  echo ""

  echo -e "${BOLD}Agents${RESET} ${DIM}(${#AGENT_FILES[@]} — dispatched by Claude Code and Grok Build)${RESET}"
  echo ""
  for i in "${!AGENT_FILES[@]}"; do
    echo -e "  ${BOLD}$((i + 1)).${RESET} ${CYAN}${AGENT_FILES[$i]}${RESET}"
    echo -e "     ${DIM}${AGENT_DESCS[$i]}${RESET}"
  done
  echo ""
}

# ─── Main ────────────────────────────────────────────────────
main() {
  local cmd="${1:-help}"
  if [ "$#" -gt 0 ]; then
    shift
  fi

  parse_target_args "$@"

  case "$cmd" in
    install)   cmd_install ;;
    update)    cmd_update ;;
    status)    cmd_status ;;
    usage)     cmd_usage "${POSITIONAL_ARGS[0]:-}" ;;
    uninstall) cmd_uninstall ;;
    govern)    cmd_govern ;;
    help|--help|-h) cmd_help ;;
    version|--version|-v) echo "eagle-skills v${VERSION}" ;;
    *)
      err "Unknown command: $cmd"
      cmd_help
      exit 1
      ;;
  esac
}

main "$@"
