#!/usr/bin/env bash
# AY Framework -- PostToolUse(Bash) hook: bash tool-abuse lint (task 67)
#
# Warns when a Bash command performs a file operation that has a dedicated
# Claude Code tool (Read / Write / Edit / Glob / Grep). Using the dedicated tool
# is cheaper on tokens, safer, and keeps file state tracked by the harness.
#
# ADVISORY ONLY: this hook never blocks. It writes a note to stderr and always
# exits 0. If it cannot find a JSON parser or the input is unparseable, it stays
# silent rather than interrupting the session.
#
# Wire-up (PostToolUse, matcher "Bash") in .claude/settings.json:
#   {"hooks":{"PostToolUse":[{"matcher":"Bash",
#     "hooks":[{"type":"command","command":"bash hooks/bash-lint.sh"}]}]}}
#
# Works on Mac, Linux, Windows (Git Bash).

set -uo pipefail

# --- read the PostToolUse event JSON from stdin ------------------------------
INPUT="$(cat 2>/dev/null || true)"
[ -n "$INPUT" ] || exit 0

# --- extract tool_input.command (prefer jq, fall back to python3) ------------
CMD=""
if command -v jq >/dev/null 2>&1; then
  CMD="$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null || true)"
elif command -v python3 >/dev/null 2>&1; then
  CMD="$(printf '%s' "$INPUT" | python3 -c 'import sys,json
try:
    d=json.load(sys.stdin)
    print(d.get("tool_input",{}).get("command","") or "")
except Exception:
    pass' 2>/dev/null || true)"
fi
[ -n "$CMD" ] || exit 0

# --- pattern checks ----------------------------------------------------------
# Each rule: if the command matches an "abuse" pattern, record a suggestion.
# Patterns are deliberately conservative to avoid false positives on legitimate
# pipeline usage (e.g. `... | grep`, `cat <<EOF` heredocs, `echo x >&2`).
warnings=()
add() { warnings+=("$1"); }

# Strip single/double-quoted spans so redirects inside string literals don't trip
# the redirect rules (best-effort; keeps the common cases clean).
STRIPPED="$(printf '%s' "$CMD" | sed "s/'[^']*'//g; s/\"[^\"]*\"//g")"

# 1) cat <file>  -> Read.  Skip heredocs (cat <<EOF) and pipe-into-cat (| cat).
if printf '%s' "$CMD" | grep -qE '(^|[;&|]|&&|\|\|)[[:space:]]*cat[[:space:]]+[^-<|&]' \
   && ! printf '%s' "$CMD" | grep -qE 'cat[[:space:]]+<'; then
  add 'cat <file> — use the Read tool to view files (cheaper, tracked).'
fi

# 2) head/tail <file>  -> Read (with offset/limit).  Skip pipe-fed head/tail.
# Allow numeric/letter flags (e.g. `head -20 f`, `tail -n 50 f`) before the path.
if printf '%s' "$CMD" | grep -qE '(^|[;&|]|&&|\|\|)[[:space:]]*(head|tail)[[:space:]]+(-[A-Za-z0-9]+[[:space:]]+)*[^-|&]' \
   && ! printf '%s' "$CMD" | grep -qE '\|[[:space:]]*(head|tail)'; then
  add 'head/tail <file> — use the Read tool with offset/limit for partial reads.'
fi

# 3) echo/printf ... > file  (or >>)  -> Write/Edit.  Skip >&fd and /dev/*.
if printf '%s' "$STRIPPED" | grep -qE '(^|[;&|]|&&|\|\|)[[:space:]]*(echo|printf)[[:space:]].*>>?[[:space:]]*[^&/[:space:]]' \
   && ! printf '%s' "$STRIPPED" | grep -qE '>>?[[:space:]]*/dev/'; then
  add 'echo/printf > file — use the Write tool (new file) or Edit tool (change).'
fi

# 4) sed -i  (in-place edit)  -> Edit.
if printf '%s' "$CMD" | grep -qE '(^|[;&|]|&&|\|\|)[[:space:]]*sed[[:space:]]+([^|]*[[:space:]])?-i'; then
  add 'sed -i — use the Edit tool for in-place file edits.'
fi

# 5) awk ... > file  -> Write.  (The awk program is usually quoted and stripped
#    above, so match on awk + an output redirect to a real file, not just print.)
if printf '%s' "$STRIPPED" | grep -qE 'awk[[:space:]].*>>?[[:space:]]*[^&/[:space:]]' \
   && ! printf '%s' "$STRIPPED" | grep -qE '>>?[[:space:]]*/dev/'; then
  add 'awk ... > file — use the Write tool to produce files.'
fi

# 6) tee <file>  -> Write (unless writing to /dev/*).  Skip `tee /dev/null`.
if printf '%s' "$STRIPPED" | grep -qE '(^|\|)[[:space:]]*tee[[:space:]]+(-a[[:space:]]+)?[^-/&[:space:]]'; then
  add 'tee <file> — use the Write/Edit tool instead of piping through tee.'
fi

# --- emit (advisory, stderr only) --------------------------------------------
if [ "${#warnings[@]}" -gt 0 ]; then
  {
    echo "[ayf bash-lint] File-op patterns detected — a dedicated tool is usually better:"
    for w in "${warnings[@]}"; do
      echo "  • $w"
    done
    echo "  (advisory only — this did not block the command)"
  } >&2
fi

exit 0
