/**
 * Safe Binaries System
 *
 * Maintains a list of commands that are safe to execute without
 * user approval. These are read-only or informational commands
 * that cannot modify the filesystem or system state.
 */
import { logger } from '../utils/logger.js';
// ============================================================================
// Safe Binaries List
// ============================================================================
export const SAFE_BINARIES = [
    'ls', 'cat', 'head', 'tail', 'wc', 'grep', 'rg', 'find',
    'which', 'whoami', 'pwd', 'echo', 'date', 'uname', 'hostname',
    'env', 'printenv', 'file', 'stat', 'du', 'df', 'free', 'uptime',
    'id', 'groups', 'locale', 'tty', 'stty', 'basename', 'dirname',
    'realpath', 'readlink', 'md5sum', 'sha256sum', 'sort', 'uniq',
    'tr', 'cut', 'paste', 'diff', 'comm', 'tee', 'xargs', 'seq',
    'yes', 'true', 'false', 'test', 'expr',
];
// ============================================================================
// SafeBinariesChecker
// ============================================================================
export class SafeBinariesChecker {
    static instance = null;
    safeBinaries;
    customized = false;
    constructor() {
        this.safeBinaries = new Set(SAFE_BINARIES);
    }
    static getInstance() {
        if (!SafeBinariesChecker.instance) {
            SafeBinariesChecker.instance = new SafeBinariesChecker();
        }
        return SafeBinariesChecker.instance;
    }
    static resetInstance() {
        SafeBinariesChecker.instance = null;
    }
    isSafe(command) {
        const trimmed = command.trim();
        if (!trimmed)
            return false;
        const firstWord = this.extractFirstWord(trimmed);
        return this.safeBinaries.has(firstWord);
    }
    isSafeChain(command) {
        const trimmed = command.trim();
        if (!trimmed)
            return false;
        // Split on pipes, &&, ||, and ;
        const parts = trimmed.split(/\s*(?:\|{1,2}|&&|;)\s*/);
        for (const part of parts) {
            const cleaned = part.trim();
            if (!cleaned)
                continue;
            if (!this.isSafe(cleaned)) {
                return false;
            }
        }
        return true;
    }
    getSafeBinaries() {
        return Array.from(this.safeBinaries).sort();
    }
    addSafeBinary(name) {
        this.safeBinaries.add(name);
        this.customized = true;
        logger.debug('Added safe binary', { name });
    }
    removeSafeBinary(name) {
        this.safeBinaries.delete(name);
        this.customized = true;
        logger.debug('Removed safe binary', { name });
    }
    isCustomized() {
        return this.customized;
    }
    extractFirstWord(command) {
        // Handle env var prefixes like FOO=bar cmd
        let cmd = command;
        while (/^\w+=\S*\s+/.test(cmd)) {
            cmd = cmd.replace(/^\w+=\S*\s+/, '');
        }
        // Handle sudo/command prefixes
        const prefixes = ['sudo', 'command', 'builtin'];
        let firstWord = cmd.split(/\s+/)[0];
        if (prefixes.includes(firstWord) && cmd.split(/\s+/).length > 1) {
            firstWord = cmd.split(/\s+/)[1];
        }
        // Strip path prefix (e.g., /usr/bin/ls -> ls)
        const basename = firstWord.split('/').pop() || firstWord;
        return basename;
    }
}
//# sourceMappingURL=safe-binaries.js.map