/**
 * Tool Permissions System
 *
 * Inspired by mistral-vibe's tool permission system that allows:
 * - ALWAYS: Auto-execute without prompting
 * - ASK: Request user confirmation before running
 * - NEVER: Block execution entirely
 *
 * Supports:
 * - Exact tool name matching
 * - Glob patterns (e.g., "read_*", "git*")
 * - Regex patterns with "re:" prefix (e.g., "re:^file_.*")
 */
import fs from 'fs-extra';
import path from 'path';
import os from 'os';
import { logger } from '../utils/logger.js';
// ============================================================================
// Types
// ============================================================================
export var ToolPermission;
(function (ToolPermission) {
    ToolPermission["ALWAYS"] = "always";
    ToolPermission["ASK"] = "ask";
    ToolPermission["NEVER"] = "never";
})(ToolPermission || (ToolPermission = {}));
// ============================================================================
// Default Configuration (like mistral-vibe)
// ============================================================================
const DEFAULT_CONFIG = {
    default: ToolPermission.ASK,
    rules: [
        // Read-only operations are always allowed
        { pattern: 'read_file', permission: ToolPermission.ALWAYS },
        { pattern: 'view_file', permission: ToolPermission.ALWAYS },
        { pattern: 'list_files', permission: ToolPermission.ALWAYS },
        { pattern: 'search_files', permission: ToolPermission.ALWAYS },
        { pattern: 'grep', permission: ToolPermission.ALWAYS },
        { pattern: 'rg', permission: ToolPermission.ALWAYS },
        { pattern: 'find_files', permission: ToolPermission.ALWAYS },
        { pattern: 'glob', permission: ToolPermission.ALWAYS },
        { pattern: 'git_status', permission: ToolPermission.ALWAYS },
        { pattern: 'git_log', permission: ToolPermission.ALWAYS },
        { pattern: 'git_diff', permission: ToolPermission.ALWAYS },
        // Todo operations are always allowed
        { pattern: 'todo_*', permission: ToolPermission.ALWAYS },
        // Write operations require confirmation
        { pattern: 'write_file', permission: ToolPermission.ASK },
        { pattern: 'edit_file', permission: ToolPermission.ASK },
        { pattern: 'create_file', permission: ToolPermission.ASK },
        { pattern: 'delete_file', permission: ToolPermission.ASK },
        { pattern: 'str_replace', permission: ToolPermission.ASK },
        // Shell commands require confirmation
        { pattern: 'bash', permission: ToolPermission.ASK },
        { pattern: 'shell', permission: ToolPermission.ASK },
        { pattern: 'execute', permission: ToolPermission.ASK },
        // Git write operations require confirmation
        { pattern: 'git_commit', permission: ToolPermission.ASK },
        { pattern: 'git_push', permission: ToolPermission.ASK },
        { pattern: 'git_checkout', permission: ToolPermission.ASK },
    ],
    allowlist: [
        // Safe bash commands (like mistral-vibe)
        'echo *',
        'ls *',
        'cat *',
        'head *',
        'tail *',
        'find *',
        'git log *',
        'git status *',
        'git diff *',
        'npm run test*',
        'npm run build*',
        'npm run lint*',
    ],
    denylist: [
        // Interactive commands that can't work in non-TTY
        'vim *',
        'nano *',
        'emacs *',
        'less *',
        'more *',
        'bash -i*',
        'python',
        'node',
        // Dangerous commands
        'rm -rf /*',
        'rm -rf ~*',
        'sudo *',
    ],
};
// ============================================================================
// Pattern Matching
// ============================================================================
/**
 * Check if a string matches a pattern (glob or regex)
 */
function matchesPattern(input, pattern) {
    // Regex pattern (with "re:" prefix)
    if (pattern.startsWith('re:')) {
        try {
            const regex = new RegExp(pattern.slice(3));
            return regex.test(input);
        }
        catch {
            return false;
        }
    }
    // Glob pattern (convert to regex)
    const regexPattern = pattern
        .replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape special chars
        .replace(/\*/g, '.*') // * -> .*
        .replace(/\?/g, '.'); // ? -> .
    const regex = new RegExp(`^${regexPattern}$`, 'i');
    return regex.test(input);
}
// ============================================================================
// Tool Permission Manager
// ============================================================================
export class ToolPermissionManager {
    config;
    configPath;
    constructor(configPath) {
        this.configPath = configPath || path.join(os.homedir(), '.codebuddy', 'tool-permissions.json');
        this.config = this.loadConfig();
    }
    /**
     * Load configuration from file or use defaults
     */
    loadConfig() {
        try {
            if (fs.existsSync(this.configPath)) {
                const data = fs.readFileSync(this.configPath, 'utf-8');
                const loaded = JSON.parse(data);
                // Merge with defaults
                return {
                    default: loaded.default || DEFAULT_CONFIG.default,
                    rules: [...DEFAULT_CONFIG.rules, ...(loaded.rules || [])],
                    allowlist: [...DEFAULT_CONFIG.allowlist, ...(loaded.allowlist || [])],
                    denylist: [...DEFAULT_CONFIG.denylist, ...(loaded.denylist || [])],
                };
            }
        }
        catch (error) {
            logger.warn(`Failed to load tool permissions config: ${error instanceof Error ? error.message : String(error)}`);
        }
        return { ...DEFAULT_CONFIG };
    }
    /**
     * Save configuration to file
     */
    saveConfig() {
        try {
            const dir = path.dirname(this.configPath);
            fs.ensureDirSync(dir);
            fs.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2));
        }
        catch (error) {
            logger.warn(`Failed to save tool permissions config: ${error instanceof Error ? error.message : String(error)}`);
        }
    }
    /**
     * Get permission for a tool
     *
     * @param toolName - Name of the tool
     * @param commandArgs - Optional command arguments (for bash/shell tools)
     * @returns Permission level and optional reason
     */
    getPermission(toolName, commandArgs) {
        const fullCommand = commandArgs ? `${toolName} ${commandArgs}` : toolName;
        // Check denylist first (highest priority)
        for (const pattern of this.config.denylist) {
            if (matchesPattern(fullCommand, pattern) || matchesPattern(toolName, pattern)) {
                return {
                    permission: ToolPermission.NEVER,
                    reason: `Blocked by denylist pattern: ${pattern}`,
                };
            }
        }
        // Check allowlist (for bash commands with arguments)
        if (commandArgs) {
            for (const pattern of this.config.allowlist) {
                if (matchesPattern(fullCommand, pattern)) {
                    return {
                        permission: ToolPermission.ALWAYS,
                        reason: `Allowed by allowlist pattern: ${pattern}`,
                    };
                }
            }
        }
        // Check specific rules
        for (const rule of this.config.rules) {
            if (matchesPattern(toolName, rule.pattern)) {
                return {
                    permission: rule.permission,
                    reason: rule.reason || `Matched rule: ${rule.pattern}`,
                };
            }
        }
        // Return default
        return {
            permission: this.config.default,
            reason: 'Using default permission',
        };
    }
    /**
     * Check if a tool should be auto-approved
     */
    shouldAutoApprove(toolName, commandArgs) {
        const { permission } = this.getPermission(toolName, commandArgs);
        return permission === ToolPermission.ALWAYS;
    }
    /**
     * Check if a tool should be blocked
     */
    shouldBlock(toolName, commandArgs) {
        const { permission } = this.getPermission(toolName, commandArgs);
        return permission === ToolPermission.NEVER;
    }
    /**
     * Add a rule
     */
    addRule(rule) {
        this.config.rules.push(rule);
        this.saveConfig();
    }
    /**
     * Remove a rule by pattern
     */
    removeRule(pattern) {
        const initialLength = this.config.rules.length;
        this.config.rules = this.config.rules.filter(r => r.pattern !== pattern);
        if (this.config.rules.length !== initialLength) {
            this.saveConfig();
            return true;
        }
        return false;
    }
    /**
     * Add to allowlist
     */
    addToAllowlist(pattern) {
        if (!this.config.allowlist.includes(pattern)) {
            this.config.allowlist.push(pattern);
            this.saveConfig();
        }
    }
    /**
     * Add to denylist
     */
    addToDenylist(pattern) {
        if (!this.config.denylist.includes(pattern)) {
            this.config.denylist.push(pattern);
            this.saveConfig();
        }
    }
    /**
     * Get all rules
     */
    getRules() {
        return [...this.config.rules];
    }
    /**
     * Get configuration
     */
    getConfig() {
        return { ...this.config };
    }
    /**
     * Reset to defaults
     */
    resetToDefaults() {
        this.config = { ...DEFAULT_CONFIG };
        this.saveConfig();
    }
    /**
     * Format rules for display
     */
    formatRules() {
        const lines = [
            'Tool Permissions Configuration',
            '═'.repeat(50),
            '',
            `Default: ${this.config.default.toUpperCase()}`,
            '',
            '📋 Rules:',
        ];
        const permissionIcons = {
            [ToolPermission.ALWAYS]: '✅',
            [ToolPermission.ASK]: '❓',
            [ToolPermission.NEVER]: '🚫',
        };
        for (const rule of this.config.rules) {
            const icon = permissionIcons[rule.permission];
            lines.push(`  ${icon} ${rule.pattern} → ${rule.permission}`);
        }
        lines.push('');
        lines.push('✅ Allowlist:');
        for (const pattern of this.config.allowlist.slice(0, 10)) {
            lines.push(`  • ${pattern}`);
        }
        if (this.config.allowlist.length > 10) {
            lines.push(`  ... and ${this.config.allowlist.length - 10} more`);
        }
        lines.push('');
        lines.push('🚫 Denylist:');
        for (const pattern of this.config.denylist.slice(0, 10)) {
            lines.push(`  • ${pattern}`);
        }
        if (this.config.denylist.length > 10) {
            lines.push(`  ... and ${this.config.denylist.length - 10} more`);
        }
        return lines.join('\n');
    }
}
// ============================================================================
// Singleton Instance
// ============================================================================
let instance = null;
export function getToolPermissionManager() {
    if (!instance) {
        instance = new ToolPermissionManager();
    }
    return instance;
}
export function resetToolPermissionManager() {
    instance = null;
}
//# sourceMappingURL=tool-permissions.js.map