#!/usr/bin/env node
/**
 * ef-guard.cjs — PreToolUse hook (matcher: Bash).
 *
 * Blocks RAW EF Core WRITE commands issued by Claude Code via the Bash tool:
 * `dotnet ef migrations add|remove` and `dotnet ef database update|drop`. These
 * are the operations governed by the SmartStack 3-tier migration policy
 * (migration-policy.ts) — they must go through `/efcore` (create / apply), whose
 * CLI classifies the branch + the target database and gates the 🔴 irreversible
 * cases. A raw `dotnet ef` typed at the shell bypasses that gate, so it is blocked.
 *
 * Read-only EF stays allowed: `migrations list`, `migrations script`,
 * `migrations has-pending-model-changes`, `dbcontext info/list`.
 *
 * NOTE — this does NOT block the sanctioned path: the efcore CLI runs `dotnet ef`
 * via `execFile` INSIDE its tsx process, not as a Bash tool call, so a PreToolUse
 * Bash hook never sees it (same way the gitflow commit CLI bypasses git-guard).
 *
 * Mechanism — PreToolUse exit code 2 BLOCKS the call and feeds the message back to
 * Claude (exit 1 only warns and lets it through — the classic trap). Pure Node — no
 * jq, no bash — identical on Windows / WSL / Git Bash / macOS / Linux. Deployed to
 * ~/.claude/hooks/ef-guard.cjs and registered in settings.json by `ss install`.
 *
 * Manual override — set EF_GUARD_OFF=1 in the environment (or settings.json "env").
 * USER-only: a value set inside a Claude Bash call lives in that child shell and
 * does NOT reach this hook's parent process, so Claude cannot self-bypass.
 */
'use strict';

// User-only kill switch (see header). Off by default.
const off = process.env.EF_GUARD_OFF;
if (off && off !== '0' && off.toLowerCase() !== 'false') process.exit(0);

function readStdin() {
  try {
    return require('fs').readFileSync(0, 'utf8');
  } catch {
    return '';
  }
}

let cmd = '';
try {
  const input = JSON.parse(readStdin());
  cmd = (input && input.tool_input && input.tool_input.command) || '';
} catch {
  // Not JSON / nothing to inspect — allow.
  process.exit(0);
}

if (!cmd) process.exit(0);

// EF write verbs requiring the policy CLI. Matches both `dotnet ef …` and the
// `dotnet-ef …` global-tool form. `migrations list|script|has-pending-model-changes`
// and `dbcontext …` are read-only and deliberately NOT matched. The `(^|[;&|\s])`
// prefix catches chained lines (e.g. `cd x && dotnet ef database update`).
const WRITE_RE =
  /(^|[;&|\s])dotnet(?:-ef|\s+ef)\s+(?:migrations\s+(?:add|remove)|database\s+(?:update|drop))\b/i;

if (!WRITE_RE.test(cmd)) process.exit(0);

const reason =
  '🚫 Commande EF Core d’écriture bloquée par ef-guard (PreToolUse). ' +
  'Les migrations suivent la politique 3 paliers : passe par /efcore (create / apply), ' +
  'qui classe la branche + la base cible et gère le palier 🔴 irréversible. ' +
  'Un 🟢 (apply local sur feature/develop) y est autonome ; un 🔴 (base distante, ' +
  'branche protégée, ou réécriture d’historique) requiert ton accord explicite.';

process.stdout.write(
  JSON.stringify({
    continue: true,
    hookSpecificOutput: {
      hookEventName: 'PreToolUse',
      permissionDecision: 'block',
      permissionDecisionReason: reason,
    },
  }),
);
process.stderr.write(reason + '\n');
process.exit(2);
