import { resolveReadPath, resolveToCwd } from '../../shared/files/path-utils.js';
import { BASH, EDIT, EXECUTE_CODE, FIND, GREP, LS, READ, TASK, WRITE } from '../../tool-names.js';
import { withPreApproval } from '../approvals/tool-approval.js';
import { APPROVAL } from '../approvals/types.js';
import { getSubagent } from '../subagents/index.js';
import { resolveTaskQuery } from '../tools/task/query.js';
import { requirePermissionPolicy } from './require-policy.js';
import { applyFilesystemApprovalChoice, applyShellApprovalChoice, applyTaskSpawnApprovalChoice, buildFilesystemApprovalRequest, buildShellApprovalRequest, buildTaskSpawnApprovalRequest, describeFilesystemApprovalChoice, isFilesystemInvocationSafe, isShellInvocationSafe } from './runtime-approval-flow.js';
export const TOOL_GATES = {
    [READ]: {
        kind: 'filesystem',
        access: 'read',
        resolvePath: (params, cwd) => resolveReadPath(String(params.path ?? ''), cwd)
    },
    [WRITE]: {
        kind: 'filesystem',
        access: 'write',
        resolvePath: (params, cwd) => resolveToCwd(String(params.path ?? ''), cwd)
    },
    [EDIT]: {
        kind: 'filesystem',
        access: 'write',
        resolvePath: (params, cwd) => resolveToCwd(String(params.path ?? ''), cwd)
    },
    [LS]: {
        kind: 'filesystem',
        access: 'read',
        resolvePath: (params, cwd) => resolveToCwd(String(params.path ?? '.'), cwd)
    },
    [FIND]: {
        kind: 'filesystem',
        access: 'read',
        resolvePath: (params, cwd) => resolveToCwd(String(params.path ?? '.'), cwd)
    },
    [GREP]: {
        kind: 'filesystem',
        access: 'read',
        resolvePath: (params, cwd) => resolveToCwd(String(params.path ?? '.'), cwd)
    },
    [BASH]: { kind: 'shell' },
    [EXECUTE_CODE]: { kind: 'self-gated' },
    [TASK]: { kind: 'task' }
};
export const PERMISSIONED_RUNTIME_TOOL_NAMES = Object.keys(TOOL_GATES);
/** Type guard: check whether a tool name has a registered permission gate. */
function isPermissionedRuntimeToolName(name) {
    return name in TOOL_GATES;
}
/** Wrap a tool with the supplied approval gate when one is configured. */
function wrapToolWithAgentApproval(tool, options) {
    if (!options.approval) {
        return tool;
    }
    return withPreApproval(tool, options.approval, options.buildRequest, {
        isContentSafe: options.isContentSafe,
        onRequested: options.onRequested,
        onAccepted: options.onAccepted,
        onRejected: options.onRejected,
        isApprovedChoiceAllowed: options.isApprovedChoiceAllowed,
        describeApprovedChoice: options.describeApprovedChoice,
        applyApprovalContext: options.applyApprovalContext
    });
}
/** Wrap a filesystem tool with path-aware approval, observability, and grant persistence. */
function wrapFilesystemTool(tool, gate, deps) {
    if (!deps.filesystemApproval || !deps.settingsManager) {
        return tool;
    }
    return wrapToolWithAgentApproval(tool, {
        approval: deps.filesystemApproval,
        buildRequest: async (params, ctx) => {
            const policy = requirePermissionPolicy(ctx, tool.name);
            const absolutePath = gate.resolvePath(params, deps.cwd);
            const request = await buildFilesystemApprovalRequest(absolutePath, gate.access, policy.filesystem);
            return {
                ...request,
                payload: {
                    ...request.payload,
                    workspaceRoots: request.payload.workspaceRoots.length > 0
                        ? request.payload.workspaceRoots
                        : deps.workspaceRoots
                }
            };
        },
        isContentSafe: async (params, ctx) => {
            const policy = requirePermissionPolicy(ctx, tool.name);
            const absolutePath = gate.resolvePath(params, deps.cwd);
            return isFilesystemInvocationSafe(absolutePath, gate.access, policy.filesystem, ctx);
        },
        onRequested: (request) => {
            deps.observability?.info({
                module: 'tool',
                event: 'tool_approval_requested',
                data: {
                    tool_name: tool.name,
                    approval_kind: `${gate.access}_filesystem`,
                    path: request.payload.path
                }
            });
        },
        onAccepted: (request, choice) => {
            deps.observability?.info({
                module: 'tool',
                event: 'tool_approval_accepted',
                data: {
                    tool_name: tool.name,
                    approval_kind: `${gate.access}_filesystem`,
                    accept_all: choice === APPROVAL.ACCEPT_ALL,
                    path: request.payload.path
                }
            });
        },
        onRejected: (request) => {
            deps.observability?.warn({
                module: 'tool',
                event: 'tool_approval_rejected',
                data: {
                    tool_name: tool.name,
                    approval_kind: `${gate.access}_filesystem`,
                    path: request.payload.path
                }
            });
        },
        describeApprovedChoice: (request, choice) => describeFilesystemApprovalChoice(request, choice),
        applyApprovalContext: async (ctx, _params, request, choice) => applyFilesystemApprovalChoice(choice, request, gate.access, deps.settingsManager, ctx)
    });
}
/** Wrap the bash tool with command-aware approval and observability. */
function wrapShellTool(tool, deps) {
    if (!deps.shellApproval) {
        return tool;
    }
    return wrapToolWithAgentApproval(tool, {
        approval: deps.shellApproval,
        buildRequest: (params) => buildShellApprovalRequest(params, tool.name),
        isContentSafe: (params, ctx) => {
            const policy = requirePermissionPolicy(ctx, tool.name);
            return isShellInvocationSafe(policy.shell, String(params.command ?? ''));
        },
        onRequested: (request) => {
            deps.observability?.info({
                module: 'tool',
                event: 'tool_approval_requested',
                data: {
                    tool_name: tool.name,
                    approval_kind: 'pre_execution',
                    has_connections: Array.isArray(request.payload.connections)
                }
            });
        },
        onAccepted: (request, choice) => {
            deps.observability?.info({
                module: 'tool',
                event: 'tool_approval_accepted',
                data: {
                    tool_name: tool.name,
                    approval_kind: 'pre_execution',
                    accept_all: choice === APPROVAL.ACCEPT_ALL,
                    has_connections: Array.isArray(request.payload.connections)
                }
            });
        },
        onRejected: (request) => {
            deps.observability?.warn({
                module: 'tool',
                event: 'tool_approval_rejected',
                data: {
                    tool_name: tool.name,
                    approval_kind: 'pre_execution',
                    has_connections: Array.isArray(request.payload.connections)
                }
            });
        },
        isApprovedChoiceAllowed: (_request, choice) => choice === APPROVAL.ACCEPT,
        applyApprovalContext: async (ctx, params) => applyShellApprovalChoice(ctx, params)
    });
}
/** Wrap the task tool with subagent-spawn approval and observability. */
function wrapTaskTool(tool, deps) {
    if (!deps.taskApproval) {
        return tool;
    }
    return wrapToolWithAgentApproval(tool, {
        approval: deps.taskApproval,
        buildRequest: (params) => {
            const subagentType = String(params.subagent_type ?? '');
            const subagent = getSubagent(subagentType);
            return buildTaskSpawnApprovalRequest({
                subagentType: String(params.subagent_type ?? ''),
                name: String(params.name ?? ''),
                query: resolveTaskQuery(String(params.query ?? '')),
                model: typeof params.model === 'string' ? params.model : undefined,
                fullWorker: true,
                canSpawnSubagents: subagent?.tools.includes(TASK) === true,
                requestedRunInBackground: params.run_in_background === true
            });
        },
        isContentSafe: (_params, ctx) => requirePermissionPolicy(ctx, tool.name).dangerouslySkipRuntimePermissions === true,
        onRequested: (request) => {
            deps.observability?.info({
                module: 'tool',
                event: 'tool_approval_requested',
                data: {
                    tool_name: tool.name,
                    approval_kind: 'subagent_spawn',
                    subagent_type: request.payload.subagentType
                }
            });
        },
        onAccepted: (request, choice) => {
            deps.observability?.info({
                module: 'tool',
                event: 'tool_approval_accepted',
                data: {
                    tool_name: tool.name,
                    approval_kind: 'subagent_spawn',
                    accept_all: choice === APPROVAL.ACCEPT_ALL,
                    subagent_type: request.payload.subagentType
                }
            });
        },
        onRejected: (request) => {
            deps.observability?.warn({
                module: 'tool',
                event: 'tool_approval_rejected',
                data: {
                    tool_name: tool.name,
                    approval_kind: 'subagent_spawn',
                    subagent_type: request.payload.subagentType
                }
            });
        },
        isApprovedChoiceAllowed: (_request, choice) => choice === APPROVAL.ACCEPT ||
            choice === APPROVAL.RUN_FOREGROUND ||
            choice === APPROVAL.RUN_BACKGROUND,
        describeApprovedChoice: (request) => `User approved subagent spawn: ${request.payload.name} [${request.payload.subagentType}]`,
        applyApprovalContext: async (ctx, _params, request, choice) => applyTaskSpawnApprovalChoice(ctx, request, choice)
    });
}
/** Register a runtime tool with the appropriate permission/approval wrapper. */
export function registerRuntimeTool(tools, tool, deps) {
    if (!isPermissionedRuntimeToolName(tool.name)) {
        throw new Error(`registerRuntimeTool does not support non-permissioned tool "${tool.name}".`);
    }
    const permissionedTool = tool;
    const gate = TOOL_GATES[permissionedTool.name];
    switch (gate.kind) {
        case 'filesystem':
            tools.push(wrapFilesystemTool(permissionedTool, gate, deps));
            return;
        case 'shell':
            tools.push(wrapShellTool(permissionedTool, deps));
            return;
        case 'task':
            tools.push(wrapTaskTool(permissionedTool, deps));
            return;
        case 'self-gated':
            tools.push(permissionedTool);
    }
}
//# sourceMappingURL=tool-gates.js.map