/**
 * OpenClaw compatibility adapter.
 *
 * Loads OpenClaw-format plugins (openclaw.plugin.json + index.ts using
 * definePluginEntry) and bridges them into Jait's plugin system.
 *
 * Supported:
 *  - Tool registration (registerTool) → Jait ToolDefinition
 *  - Plugin config passthrough
 *  - Scoped logging
 *
 * Unsupported registrations (channels, speech providers, CLI backends, etc.)
 * are silently captured so the plugin doesn't throw, but they are not wired
 * into Jait's runtime. They are logged at debug level.
 */
import { readdir, readFile, stat } from "node:fs/promises";
import { join, resolve } from "node:path";
function createStubApi(manifest, pluginConfig, log) {
    const collected = { tools: [], unsupported: [] };
    const noop = (method) => (...args) => {
        collected.unsupported.push({ method, args });
        log.info(`[openclaw-compat] ${manifest.id}: skipped ${method} (not supported in Jait)`);
    };
    // Build a minimal shape that satisfies OpenClawPluginApi
    const api = {
        id: manifest.id,
        name: manifest.name ?? manifest.id,
        version: manifest.version,
        description: manifest.description,
        source: `openclaw:${manifest.id}`,
        rootDir: undefined, // set later
        registrationMode: "full",
        config: {}, // OpenClaw global config — empty in Jait context
        pluginConfig,
        runtime: {}, // Empty runtime object
        logger: log,
        // ── Supported: tool registration ──────────────────────────────
        registerTool: (tool) => {
            if (typeof tool === "function") {
                // Factory pattern (OpenClawPluginToolFactory)
                try {
                    const resolved = tool();
                    collected.tools.push(resolved);
                }
                catch (err) {
                    log.warn(`[openclaw-compat] ${manifest.id}: tool factory threw: ${err}`);
                }
            }
            else if (tool && typeof tool === "object" && "name" in tool) {
                collected.tools.push(tool);
            }
        },
        // ── Unsupported — captured but not wired ──────────────────────
        registerHook: noop("registerHook"),
        registerHttpRoute: noop("registerHttpRoute"),
        registerChannel: noop("registerChannel"),
        registerGatewayMethod: noop("registerGatewayMethod"),
        registerCli: noop("registerCli"),
        registerService: noop("registerService"),
        registerCliBackend: noop("registerCliBackend"),
        registerProvider: noop("registerProvider"),
        registerSpeechProvider: noop("registerSpeechProvider"),
        registerRealtimeTranscriptionProvider: noop("registerRealtimeTranscriptionProvider"),
        registerRealtimeVoiceProvider: noop("registerRealtimeVoiceProvider"),
        registerMediaUnderstandingProvider: noop("registerMediaUnderstandingProvider"),
        registerImageGenerationProvider: noop("registerImageGenerationProvider"),
        registerWebFetchProvider: noop("registerWebFetchProvider"),
        registerWebSearchProvider: noop("registerWebSearchProvider"),
        registerInteractiveHandler: noop("registerInteractiveHandler"),
        onConversationBindingResolved: noop("onConversationBindingResolved"),
        registerCommand: noop("registerCommand"),
        registerContextEngine: noop("registerContextEngine"),
        registerMemoryPromptSection: noop("registerMemoryPromptSection"),
        registerMemoryFlushPlan: noop("registerMemoryFlushPlan"),
        registerMemoryRuntime: noop("registerMemoryRuntime"),
        registerMemoryEmbeddingProvider: noop("registerMemoryEmbeddingProvider"),
        // ── Utility stubs ─────────────────────────────────────────────
        resolvePath: (p) => p,
        on: noop("on"),
    };
    return api;
}
/* ------------------------------------------------------------------ */
/*  Convert OpenClaw tool → Jait PluginToolDeclaration                 */
/* ------------------------------------------------------------------ */
function convertTool(_pluginId, tool) {
    return {
        name: tool.name,
        description: tool.description ?? tool.label ?? tool.name,
        parameters: tool.parameters ?? {
            type: "object",
            properties: {},
        },
        tier: "external",
        category: "external",
        risk: "high",
        defaultConsentLevel: "dangerous",
        execute: async (input, _ctx) => {
            const toolCallId = `jait-${Date.now()}`;
            const params = (input && typeof input === "object" ? input : {});
            try {
                const result = await tool.execute(toolCallId, params);
                const text = typeof result === "string" ? result : JSON.stringify(result, null, 2);
                return { ok: true, message: text };
            }
            catch (err) {
                const msg = err instanceof Error ? err.message : String(err);
                return { ok: false, message: `Error: ${msg}` };
            }
        },
    };
}
/* ------------------------------------------------------------------ */
/*  Discovery — find openclaw.plugin.json in a directory               */
/* ------------------------------------------------------------------ */
export async function discoverOpenClawPlugins(extensionsDir) {
    const results = [];
    let entries;
    try {
        entries = await readdir(extensionsDir);
    }
    catch {
        return results;
    }
    for (const entry of entries) {
        const dir = join(extensionsDir, entry);
        const dirStat = await stat(dir).catch(() => null);
        if (!dirStat?.isDirectory())
            continue;
        const manifestPath = join(dir, "openclaw.plugin.json");
        try {
            const raw = JSON.parse(await readFile(manifestPath, "utf-8"));
            if (!raw.id || typeof raw.id !== "string")
                continue;
            results.push({ manifest: raw, dir });
        }
        catch {
            // No OpenClaw manifest — skip
        }
    }
    return results;
}
/* ------------------------------------------------------------------ */
/*  Convert OpenClaw manifest → Jait manifest (for UI display)         */
/* ------------------------------------------------------------------ */
export function openclawToJaitManifest(oc, _dir) {
    return {
        id: `openclaw:${oc.id}`,
        displayName: oc.name ?? oc.id,
        version: oc.version ?? "0.0.0",
        description: oc.description,
        author: "OpenClaw",
        main: "index.ts",
        categories: ["openclaw"],
        configSchema: oc.configSchema,
        contributes: {
            tools: oc.contracts?.tools?.map((name) => ({ name, description: name })),
        },
    };
}
/* ------------------------------------------------------------------ */
/*  Load a single OpenClaw plugin as a Jait PluginModule               */
/* ------------------------------------------------------------------ */
export function createOpenClawPluginModule(manifest, dir) {
    const jaitId = `openclaw:${manifest.id}`;
    let disposeCallbacks = [];
    return {
        id: jaitId,
        displayName: manifest.name ?? manifest.id,
        async setup(ctx) {
            const pluginConfig = ctx.getConfig();
            const api = createStubApi(manifest, pluginConfig, ctx.log);
            api.rootDir = dir;
            // Try to import the plugin entry
            // OpenClaw plugins use index.ts or index.js
            const candidates = ["index.ts", "index.js", "index.mjs"];
            let loaded = false;
            for (const candidate of candidates) {
                const entryPath = resolve(dir, candidate);
                try {
                    const entryStat = await stat(entryPath).catch(() => null);
                    if (!entryStat?.isFile())
                        continue;
                    const mod = await import(entryPath);
                    const definition = mod.default ?? mod.plugin ?? mod;
                    if (typeof definition === "function") {
                        // Direct function export: (api) => void
                        await definition(api);
                        loaded = true;
                        break;
                    }
                    else if (definition && typeof definition === "object") {
                        if (typeof definition.register === "function") {
                            await definition.register(api);
                            loaded = true;
                            break;
                        }
                        else if (typeof definition.activate === "function") {
                            await definition.activate(api);
                            loaded = true;
                            break;
                        }
                    }
                }
                catch (err) {
                    ctx.log.warn(`Failed to load OpenClaw plugin entry ${entryPath}: ${err}`);
                }
            }
            if (!loaded) {
                ctx.log.warn(`OpenClaw plugin ${manifest.id}: no loadable entry found in ${dir}`);
            }
            // Convert collected tools
            const tools = api.tools.map((t) => convertTool(jaitId, t));
            const unsupported = api.unsupported;
            if (unsupported.length > 0) {
                const methods = [...new Set(unsupported.map((u) => u.method))];
                ctx.log.info(`OpenClaw plugin ${manifest.id}: ${tools.length} tool(s) bridged, ` +
                    `${unsupported.length} unsupported registration(s) skipped (${methods.join(", ")})`);
            }
            else if (tools.length > 0) {
                ctx.log.info(`OpenClaw plugin ${manifest.id}: ${tools.length} tool(s) bridged`);
            }
            return { tools };
        },
        async dispose() {
            for (const cb of disposeCallbacks) {
                try {
                    await cb();
                }
                catch { /* best effort */ }
            }
            disposeCallbacks = [];
        },
    };
}
//# sourceMappingURL=openclaw-adapter.js.map