/**
 * OwlCoda Plugin Loader — discovers and loads plugins from ~/.owlcoda/plugins/
 */
import { readdirSync, existsSync, statSync } from 'node:fs';
import path from 'node:path';
import { homedir } from 'node:os';
import { pathToFileURL } from 'node:url';
const HOOK_NAMES = ['onRequest', 'onResponse', 'onToolCall', 'onError'];
let loadedPlugins = [];
function getPluginDir() {
    const owlcodaHome = process.env['OWLCODA_HOME'] || path.join(homedir(), '.owlcoda');
    return path.join(owlcodaHome, 'plugins');
}
function validatePlugin(obj, pluginPath) {
    if (!obj || typeof obj !== 'object')
        return null;
    const candidate = obj;
    if (!candidate.metadata || typeof candidate.metadata !== 'object') {
        console.error(`[plugins] ${pluginPath}: missing metadata`);
        return null;
    }
    const meta = candidate.metadata;
    if (typeof meta.name !== 'string' || typeof meta.version !== 'string') {
        console.error(`[plugins] ${pluginPath}: metadata.name and metadata.version must be strings`);
        return null;
    }
    return candidate;
}
function countHooks(plugin) {
    return HOOK_NAMES.filter(h => typeof plugin[h] === 'function').length;
}
export async function loadPlugins() {
    const dir = getPluginDir();
    if (!existsSync(dir)) {
        loadedPlugins = [];
        return loadedPlugins;
    }
    const entries = readdirSync(dir).sort();
    const plugins = [];
    for (const entry of entries) {
        const pluginPath = path.join(dir, entry);
        if (!statSync(pluginPath).isDirectory())
            continue;
        const indexPath = path.join(pluginPath, 'index.js');
        if (!existsSync(indexPath)) {
            console.error(`[plugins] ${entry}: no index.js found, skipping`);
            continue;
        }
        try {
            const mod = await import(/* @vite-ignore */ pathToFileURL(indexPath).href);
            const exported = mod.default ?? mod;
            const plugin = validatePlugin(exported, entry);
            if (!plugin)
                continue;
            if (typeof plugin.onLoad === 'function') {
                await plugin.onLoad();
            }
            plugins.push({
                plugin,
                path: pluginPath,
                hookCount: countHooks(plugin),
            });
            console.error(`[plugins] Loaded: ${plugin.metadata.name} v${plugin.metadata.version} (${countHooks(plugin)} hooks)`);
        }
        catch (err) {
            console.error(`[plugins] Failed to load ${entry}: ${err}`);
        }
    }
    loadedPlugins = plugins;
    return plugins;
}
export function getLoadedPlugins() {
    return loadedPlugins;
}
export async function runRequestHooks(ctx) {
    for (const { plugin } of loadedPlugins) {
        if (typeof plugin.onRequest === 'function') {
            try {
                await plugin.onRequest(ctx);
            }
            catch (err) {
                console.error(`[plugins] ${plugin.metadata.name}.onRequest error: ${err}`);
            }
        }
    }
}
export async function runResponseHooks(ctx) {
    for (const { plugin } of loadedPlugins) {
        if (typeof plugin.onResponse === 'function') {
            try {
                await plugin.onResponse(ctx);
            }
            catch (err) {
                console.error(`[plugins] ${plugin.metadata.name}.onResponse error: ${err}`);
            }
        }
    }
}
export async function runToolCallHooks(ctx) {
    for (const { plugin } of loadedPlugins) {
        if (typeof plugin.onToolCall === 'function') {
            try {
                await plugin.onToolCall(ctx);
            }
            catch (err) {
                console.error(`[plugins] ${plugin.metadata.name}.onToolCall error: ${err}`);
            }
        }
    }
}
export async function runErrorHooks(ctx) {
    for (const { plugin } of loadedPlugins) {
        if (typeof plugin.onError === 'function') {
            try {
                await plugin.onError(ctx);
            }
            catch (err) {
                console.error(`[plugins] ${plugin.metadata.name}.onError error: ${err}`);
            }
        }
    }
}
export async function unloadPlugins() {
    for (const { plugin } of loadedPlugins) {
        if (typeof plugin.onUnload === 'function') {
            try {
                await plugin.onUnload();
            }
            catch (err) {
                console.error(`[plugins] ${plugin.metadata.name}.onUnload error: ${err}`);
            }
        }
    }
    loadedPlugins = [];
}
//# sourceMappingURL=loader.js.map