"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveMode = resolveMode;
exports.evaluateWriteGate = evaluateWriteGate;
/**
 * Resolve the effective execution mode, output preferences, and capability
 * grants.
 *
 * Precedence for output format:
 *   --human           → force human output (overrides auto-detect)
 *   --json / --agent  → force structured JSON
 *   !isTTY            → auto-detect to JSON (piped to another program)
 *   default           → human
 *
 * Capability grants (additive, lowest to highest):
 *   --auto-approve    → autoApprove
 *   --yes / --ci      → autoApprove + allowWrites
 *   --force           → autoApprove + allowWrites + allowDestructive
 *   --agent (alone)   → autoApprove + allowWrites (unless `requireExplicitWrites`)
 *
 * `--json` produces machine-readable output WITHOUT any capability grants.
 * Use `--agent` when you also want auto-approval of prompts.
 */
function resolveMode(opts) {
    const isAgent = Boolean(opts.agent);
    const requireExplicitWrites = Boolean(opts.requireExplicitWrites);
    // Build capability grants additively from each flag.
    let autoApprove = false;
    let allowWrites = false;
    let allowDestructive = false;
    if (opts.autoApprove)
        autoApprove = true;
    if (opts.yes) {
        autoApprove = true;
        allowWrites = true;
    }
    if (opts.ci) {
        autoApprove = true;
        allowWrites = true;
    }
    if (opts.force) {
        autoApprove = true;
        allowWrites = true;
        allowDestructive = true;
    }
    // Back-compat: today's `--agent` (with no other capability flags) implies
    // auto-approve and writes. New scoped commands (`apply`, `verify`) opt
    // out via `requireExplicitWrites: true`.
    //
    // Critically, the back-compat ONLY fires when no explicit capability
    // flag was passed. Otherwise `--auto-approve --agent` would silently
    // grant writes despite `--auto-approve`'s documented "no writes"
    // contract — a real risk because bin.ts auto-detects `--agent` in
    // non-TTY contexts. (Bugbot finding.)
    const hasExplicitCapabilityFlag = Boolean(opts.autoApprove) ||
        Boolean(opts.yes) ||
        Boolean(opts.ci) ||
        Boolean(opts.force);
    if (isAgent && !requireExplicitWrites && !hasExplicitCapabilityFlag) {
        autoApprove = true;
        allowWrites = true;
    }
    const isInteractive = !autoApprove && opts.isTTY;
    const jsonOutput = opts.human
        ? false
        : Boolean(opts.json) || isAgent || !opts.isTTY;
    return {
        mode: isAgent ? 'agent' : isInteractive ? 'interactive' : 'ci',
        autoApprove,
        allowWrites,
        allowDestructive,
        jsonOutput,
        quiet: !opts.isTTY,
    };
}
// ── Write-gate helper ─────────────────────────────────────────────────
//
// The PreToolUse hook calls `evaluateWriteGate` for every tool the inner
// Claude agent attempts. The gate answers a single question: should this
// tool call be allowed under the current capability grants? When denied,
// the hook returns a structured deny response and the wizard exits
// `WRITE_REFUSED` (13) so outer agents can re-invoke with `--yes`.
const WRITE_TOOLS = new Set(['Edit', 'Write', 'MultiEdit', 'NotebookEdit']);
const DESTRUCTIVE_BASH_PATTERNS = [
    // rm -rf, rm -r, rm -f at start or after a chain operator. The previous
    // `\brm\s+-` matched ANY `rm` after a word boundary, so package-manager
    // uninstalls like `pnpm rm -D foo` were flagged as destructive
    // filesystem ops. Anchor to start-of-string or chain operators so
    // standalone `rm` is caught but `pnpm rm` / `npm rm` / `yarn rm` /
    // `bun rm` aren't.
    /(?:^|[;&|]\s*)rm\s+-/i,
    /\bgit\s+reset\s+--hard\b/i,
    /\bgit\s+checkout\s+--\s/i,
    /\bgit\s+clean\s+-/i,
    /\bgit\s+restore\s+\./i,
    // Match `--force` but exclude `--force-with-lease` (the explicitly safer
    // push variant — flagging it as destructive would push users toward the
    // broader CLI `--force` flag as a workaround).
    /\bgit\s+push\s+.*--force(?!-)/i,
    /\bdrop\s+(table|database)\b/i,
    /\btruncate\s+table\b/i,
];
/**
 * Decide whether a tool call should be permitted under the current
 * capability grants. Pure function — no I/O, easy to unit test.
 *
 *   - Write tools (Edit/Write/MultiEdit/NotebookEdit) require `allowWrites`.
 *   - Write tools targeting an existing file also require `allowDestructive`.
 *   - Bash commands matching destructive patterns require `allowDestructive`.
 *   - Everything else is allowed.
 *
 * The caller (PreToolUse hook) is responsible for checking the filesystem
 * and passing `context.targetFileExists` so this function can enforce the
 * `allowDestructive` contract without performing I/O itself.
 */
function evaluateWriteGate(toolName, toolInput, caps, context) {
    if (WRITE_TOOLS.has(toolName)) {
        if (!caps.allowWrites) {
            return {
                kind: 'deny',
                reason: `Tool "${toolName}" is a write tool and --yes was not provided.`,
                resumeFlag: '--yes',
            };
        }
        if (!caps.allowDestructive && context?.targetFileExists) {
            return {
                kind: 'deny',
                reason: `Tool "${toolName}" would overwrite an existing file and --force was not provided.`,
                resumeFlag: '--force',
            };
        }
        return { kind: 'allow' };
    }
    if (toolName === 'Bash') {
        const command = typeof toolInput === 'object' &&
            toolInput !== null &&
            'command' in toolInput &&
            typeof toolInput.command === 'string'
            ? toolInput.command
            : '';
        if (command &&
            DESTRUCTIVE_BASH_PATTERNS.some((re) => re.test(command)) &&
            !caps.allowDestructive) {
            return {
                kind: 'deny',
                reason: `Bash command matches a destructive pattern and --force was not provided: ${command.slice(0, 100)}`,
                resumeFlag: '--force',
            };
        }
        // Non-destructive Bash: still requires allowWrites (any shell command
        // can mutate state). We err on the side of usability here — `apply`
        // grants allowWrites, which is what the inner agent needs.
        if (!caps.allowWrites) {
            return {
                kind: 'deny',
                reason: `Tool "Bash" can mutate state and --yes was not provided.`,
                resumeFlag: '--yes',
            };
        }
        return { kind: 'allow' };
    }
    return { kind: 'allow' };
}
