"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.pluginManager = exports.PluginManager = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const isolated_vm_1 = __importDefault(require("isolated-vm"));
class PluginManager {
    skills = new Map();
    async loadPlugins() {
        const pluginsDir = path_1.default.join(process.cwd(), 'src', 'external_skills');
        if (!fs_1.default.existsSync(pluginsDir)) {
            fs_1.default.mkdirSync(pluginsDir, { recursive: true });
            return;
        }
        const files = fs_1.default.readdirSync(pluginsDir);
        for (const file of files) {
            if (file.endsWith('.js') || file.endsWith('.ts')) {
                try {
                    const absolutePath = path_1.default.resolve(pluginsDir, file);
                    const code = fs_1.default.readFileSync(absolutePath, 'utf8');
                    const isolate = new isolated_vm_1.default.Isolate({ memoryLimit: 128 });
                    const context = isolate.createContextSync();
                    const jail = context.global;
                    jail.setSync('global', jail.derefInto());
                    // Inject a safe fetch
                    const safeFetch = new isolated_vm_1.default.Reference(async (url, options) => {
                        if (url.includes('127.0.0.1') || url.includes('localhost') || url.includes('::1')) {
                            throw new Error("SSRF Protection: Access to localhost is blocked.");
                        }
                        const res = await fetch(url, options);
                        const text = await res.text();
                        return text; // Only return text to avoid passing complex Response objects
                    });
                    jail.setSync('fetchText', safeFetch);
                    // Inject console
                    const logCallback = new isolated_vm_1.default.Reference((...args) => console.log('[Plugin]', ...args));
                    jail.setSync('log', logCallback);
                    const scriptCode = `
             const console = { log: (...args) => log(...args) };
             const fetch = async (url, options) => {
                const text = await fetchText.apply(undefined, [url, options], { arguments: { copy: true }, result: { promise: true } });
                return { text: async () => text, json: async () => JSON.parse(text) };
             };
             const module = { exports: {} };
             const exports = module.exports;
             ${code}
             module.exports;
          `;
                    const script = isolate.compileScriptSync(scriptCode, { filename: file });
                    const moduleExportsRef = script.runSync(context);
                    const toolDefinition = moduleExportsRef.getSync('toolDefinition');
                    const executeRef = moduleExportsRef.getSync('execute');
                    if (toolDefinition && executeRef && typeof executeRef === 'object') {
                        const toolName = toolDefinition.function.name;
                        const safeExecute = async (args) => {
                            const result = await executeRef.apply(undefined, [args], { arguments: { copy: true }, result: { promise: true, copy: true } });
                            return result;
                        };
                        this.skills.set(toolName, { toolDefinition, execute: safeExecute });
                        console.log(`[PluginManager] Loaded sandboxed external skill: ${toolName}`);
                    }
                    moduleExportsRef.release();
                }
                catch (error) {
                    console.error(`[PluginManager] Failed to load sandboxed plugin ${file}:`, error.message);
                }
            }
        }
    }
    getToolDefinitions() {
        return Array.from(this.skills.values()).map(skill => skill.toolDefinition);
    }
    async executeTool(toolName, args) {
        const skill = this.skills.get(toolName);
        if (skill) {
            try {
                return await skill.execute(args);
            }
            catch (error) {
                return `External skill ${toolName} failed: ${error.message}`;
            }
        }
        return null; // Tool not found in external skills
    }
}
exports.PluginManager = PluginManager;
exports.pluginManager = new PluginManager();
