import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Box, Text } from 'ink';
import BashProgress from '../components/bash-progress.js';
import { isNanocoderToolAlwaysAllowed } from '../config/nanocoder-tools-config.js';
import { TRUNCATION_OUTPUT_LIMIT } from '../constants.js';
import { useTheme } from '../hooks/useTheme.js';
import { bashExecutor } from '../services/bash-executor.js';
import { jsonSchema, tool } from '../types/core.js';
/**
 * Execute a bash command using the bash executor service.
 * This is the internal implementation used by both the tool and direct !command mode.
 *
 * @param command - The bash command to execute
 * @returns Object containing executionId and promise for the result
 */
export function executeBashCommand(command) {
    return bashExecutor.execute(command);
}
/**
 * Format bash execution result for LLM context
 */
export function formatBashResultForLLM(result) {
    let fullOutput = '';
    const exitCodeInfo = result.exitCode !== null ? `EXIT_CODE: ${result.exitCode}\n` : '';
    if (result.stderr) {
        fullOutput = `${exitCodeInfo}STDERR:\n${result.stderr}\nSTDOUT:\n${result.fullOutput}`;
    }
    else {
        fullOutput = `${exitCodeInfo}${result.fullOutput}`;
    }
    // Handle errors
    if (result.error) {
        fullOutput = `Error: ${result.error}\n${fullOutput}`;
    }
    // Limit the context for LLM to prevent overwhelming the model
    const llmContext = fullOutput.length > TRUNCATION_OUTPUT_LIMIT
        ? fullOutput.substring(0, TRUNCATION_OUTPUT_LIMIT) +
            '\n... [Output truncated. Use more specific commands to see full output]'
        : fullOutput;
    return llmContext;
}
/**
 * Tool execute function - called by the tool system
 * Note: For streaming tools, the tool handler will use executeBashCommand directly
 * and this function serves as a fallback/compatibility layer
 */
const executeExecuteBash = async (args) => {
    const { promise } = bashExecutor.execute(args.command);
    const result = await promise;
    return formatBashResultForLLM(result);
};
const executeBashCoreTool = tool({
    description: 'Execute a bash command and return the output (use for running commands)',
    inputSchema: jsonSchema({
        type: 'object',
        properties: {
            command: {
                type: 'string',
                description: 'The bash command to execute.',
            },
        },
        required: ['command'],
    }),
    // High risk: bash commands require approval unless explicitly configured in nanocoderTools.alwaysAllow
    needsApproval: () => {
        // Check if this tool is configured to always be allowed
        if (isNanocoderToolAlwaysAllowed('execute_bash')) {
            return false;
        }
        // Even in auto-accept mode, bash commands should require approval for security
        return true;
    },
    execute: async (args, _options) => {
        return await executeExecuteBash(args);
    },
});
/**
 * Formatter component - used for tool confirmation preview
 */
function ExecuteBashFormatterComponent({ command, }) {
    const { colors } = useTheme();
    return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.tool, children: "\u2692 execute_bash" }), _jsxs(Box, { children: [_jsx(Text, { color: colors.secondary, children: "Command: " }), _jsx(Box, { marginLeft: 1, children: _jsx(Text, { color: colors.primary, children: command }) })] })] }));
}
/**
 * Regular formatter - called for tool confirmation preview
 * Shows the command that will be executed
 */
const executeBashFormatter = (args) => {
    return _jsx(ExecuteBashFormatterComponent, { command: args.command });
};
/**
 * Streaming formatter - called BEFORE execution to set up progress component
 * The component subscribes to bash executor events and updates itself
 */
const executeBashStreamingFormatter = (args, executionId) => {
    return _jsx(BashProgress, { executionId: executionId, command: args.command });
};
const executeBashValidator = (args) => {
    const command = args.command?.trim();
    // Check if command is empty
    if (!command) {
        return Promise.resolve({
            valid: false,
            error: '⚒ Command cannot be empty',
        });
    }
    // Check for extremely dangerous commands
    const dangerousPatterns = [
        /rm\s+-rf\s+\/(?!\w)/i, // rm -rf / (but allow /path)
        /mkfs/i, // Format filesystem
        /dd\s+if=/i, // Direct disk write
        /:(){:|:&};:/i, // Fork bomb
        />\s*\/dev\/sd[a-z]/i, // Writing to raw disk devices
        /chmod\s+-R\s+000/i, // Remove all permissions recursively
    ];
    for (const pattern of dangerousPatterns) {
        if (pattern.test(command)) {
            return Promise.resolve({
                valid: false,
                error: `⚒ Command contains potentially destructive operation: "${command}". This command is blocked for safety.`,
            });
        }
    }
    return Promise.resolve({ valid: true });
};
export const executeBashTool = {
    name: 'execute_bash',
    tool: executeBashCoreTool,
    formatter: executeBashFormatter,
    streamingFormatter: executeBashStreamingFormatter,
    validator: executeBashValidator,
};
//# sourceMappingURL=execute-bash.js.map