/**
 * Consent-Aware Tool Executor — Sprint 4.7
 *
 * Wraps ToolRegistry.execute() with consent checking. When a tool requires
 * consent (based on permissions + trust level), execution is paused and a
 * consent request is created. The tool only runs after approval.
 *
 * In dry-run mode, the executor returns the plan (what would happen)
 * without executing anything, regardless of consent level.
 */
import { requiresConsent, isCommandAllowed, resolveToolPermission } from "./tool-permissions.js";
const COMMAND_TOOL_NAMES = new Set(["terminal.run", "terminal.stream", "execute", "jait.terminal"]);
export class ConsentAwareExecutor {
    toolRegistry;
    consentManager;
    trustEngine;
    audit;
    permissions;
    sessionApprovals;
    profileName;
    delegate;
    constructor(opts) {
        this.toolRegistry = opts.toolRegistry;
        this.consentManager = opts.consentManager;
        this.trustEngine = opts.trustEngine;
        this.audit = opts.audit;
        this.permissions = opts.permissions;
        this.sessionApprovals = opts.sessionApprovals;
        this.profileName = opts.profileName;
        this.delegate = opts.delegate;
    }
    /** Execute a tool, routing through the delegate when one is configured. */
    runTool(toolName, input, context) {
        if (this.delegate) {
            return this.delegate(toolName, input, context, this.audit);
        }
        return this.toolRegistry.execute(toolName, input, context, this.audit);
    }
    /**
     * Execute a tool with consent checking and trust-level awareness.
     */
    async execute(toolName, input, context, options = {}) {
        const permission = resolveToolPermission(toolName, this.permissions);
        const trustLevel = this.trustEngine.getLevel(toolName);
        // Build a summary for the consent card
        const summary = this.buildSummary(toolName, input);
        const preview = this.buildPreview(toolName, input);
        // ── Dry-run mode: return plan without executing ──
        if (options.dryRun) {
            const needsConsent = requiresConsent(permission, trustLevel, this.sessionApprovals);
            return {
                ok: true,
                message: "Dry-run: showing plan without executing",
                data: {
                    dryRun: true,
                    toolName,
                    input,
                    summary,
                    preview,
                    requiresConsent: needsConsent,
                    trustLevel,
                    risk: permission.risk,
                    policy: {
                        profileName: this.profileName ?? null,
                        consentLevel: permission.consentLevel,
                        description: permission.description,
                        knownTool: permission.knownTool,
                        source: permission.source,
                    },
                },
            };
        }
        // ── Command allow/deny check (for terminal tools) ──
        if (COMMAND_TOOL_NAMES.has(toolName)) {
            const command = input?.command;
            if (typeof command === "string") {
                const commandPermission = toolName === "execute" || toolName === "jait.terminal"
                    ? (this.permissions.get("terminal.run") ?? permission)
                    : permission;
                const cmdCheck = isCommandAllowed(command, commandPermission);
                if (!cmdCheck.allowed) {
                    return {
                        ok: false,
                        message: `Command blocked: ${cmdCheck.reason}`,
                    };
                }
            }
        }
        // ── Auto-execute if no consent required ──
        const needsConsent = requiresConsent(permission, trustLevel, this.sessionApprovals);
        const approveAllEnabled = this.consentManager.isApproveAllEnabledForSession(context.sessionId);
        const isScheduler = context.requestedBy === "scheduler";
        const isVoiceAssistant = context.requestedBy === "voice-assistant";
        if (!needsConsent || approveAllEnabled || isScheduler || isVoiceAssistant) {
            const result = await this.runTool(toolName, input, context);
            // Record successful approval for trust progression
            if (result.ok) {
                this.trustEngine.recordApproval(toolName);
            }
            return result;
        }
        // ── Consent required: create request and wait ──
        const decision = await this.consentManager.requestConsent({
            actionId: context.actionId,
            toolName,
            summary,
            preview,
            risk: permission.risk,
            policy: {
                consentLevel: permission.consentLevel,
                description: permission.description,
                knownTool: permission.knownTool,
                source: permission.source,
            },
            sessionId: context.sessionId,
            timeoutMs: options.consentTimeoutMs,
        });
        if (!decision.approved) {
            return {
                ok: false,
                message: decision.decidedVia === "timeout"
                    ? `Consent timed out for ${toolName}`
                    : `User rejected ${toolName}: ${decision.reason ?? "no reason given"}`,
                data: { consentRejected: true, decidedVia: decision.decidedVia },
            };
        }
        // ── Approved: execute the tool ──
        const result = await this.runTool(toolName, input, context);
        // Record for trust progression
        if (result.ok) {
            this.trustEngine.recordApproval(toolName);
            // Mark as session-approved for "once" consent level
            if (permission.consentLevel === "once") {
                this.sessionApprovals.add(toolName);
            }
        }
        return result;
    }
    // ── Helpers ────────────────────────────────────────────────────────
    buildSummary(toolName, input) {
        const inp = input;
        switch (toolName) {
            case "terminal.run":
            case "execute":
            case "jait.terminal":
                return `Run command: ${inp?.command ?? "(unknown)"}`;
            case "terminal.stream":
                return "Open a new terminal session";
            case "file.write":
                return `Write to file: ${inp?.path ?? "(unknown)"}`;
            case "file.patch":
                return `Patch file: ${inp?.path ?? "(unknown)"}`;
            case "file.read":
                return `Read file: ${inp?.path ?? "(unknown)"}`;
            case "os.install":
                return `Install package: ${inp?.package ?? "(unknown)"}`;
            case "os.query":
                return `Query OS: ${inp?.type ?? "(unknown)"}`;
            case "surfaces.start":
                return `Start surface: ${inp?.type ?? "(unknown)"}`;
            case "surfaces.stop":
                return `Stop surface: ${inp?.id ?? "(unknown)"}`;
            default:
                return `Execute tool: ${toolName}`;
        }
    }
    buildPreview(toolName, input) {
        const inp = input;
        switch (toolName) {
            case "terminal.run":
            case "execute":
            case "jait.terminal":
                return { command: inp?.command, timeout: inp?.timeout };
            case "file.write":
                return {
                    path: inp?.path,
                    content: typeof inp?.content === "string"
                        ? inp.content.slice(0, 500)
                        : undefined,
                };
            case "file.patch":
                return { path: inp?.path, search: inp?.search, replace: inp?.replace };
            case "os.install":
                return { package: inp?.package };
            default:
                return inp ?? {};
        }
    }
}
//# sourceMappingURL=consent-executor.js.map