import { createRequire } from 'node:module'; import * as os from 'node:os'; import * as path from 'node:path'; import { MacpRuntime } from './macp-runtime.js'; // Resolve OC plugin SDK dynamically — works on any machine with openclaw installed globally const ocRequire = createRequire(import.meta.url); const sdkRoot = path.dirname(ocRequire.resolve('openclaw/dist/plugin-sdk/index.js')); // Dynamic imports for runtime SDK functions const { registerAcpRuntimeBackend, unregisterAcpRuntimeBackend } = (await import( `${sdkRoot}/acp-runtime.js` )) as { registerAcpRuntimeBackend: (backend: { id: string; runtime: any; healthy: () => boolean; }) => void; unregisterAcpRuntimeBackend: (id: string) => void; }; type PluginConfig = { defaultModel?: string; systemPrompt?: string; timeoutMs?: number; logDir?: string; repoRoot?: string; orchDir?: string; defaultDispatch?: string; defaultRuntime?: string; }; function expandHome(rawPath: string): string { if (rawPath === '~') { return os.homedir(); } if (rawPath.startsWith('~/')) { return path.join(os.homedir(), rawPath.slice(2)); } return rawPath; } function resolveConfig(pluginConfig?: Record, stateDir?: string) { const config = (pluginConfig ?? {}) as PluginConfig; const repoRoot = config.repoRoot?.trim() ? path.resolve(expandHome(config.repoRoot)) : path.resolve(os.homedir(), 'src', 'mosaic-stack'); return { defaultModel: config.defaultModel?.trim() || 'openai/gpt-5-mini', systemPrompt: config.systemPrompt ?? '', timeoutMs: typeof config.timeoutMs === 'number' && Number.isFinite(config.timeoutMs) && config.timeoutMs > 0 ? config.timeoutMs : 300_000, stateDir: config.logDir?.trim() ? path.resolve(expandHome(config.logDir)) : (stateDir ?? process.cwd()), repoRoot, orchDir: config.orchDir?.trim() ? path.resolve(expandHome(config.orchDir)) : path.join(repoRoot, '.mosaic', 'orchestrator'), defaultDispatch: config.defaultDispatch?.trim() || 'yolo', defaultRuntime: config.defaultRuntime?.trim() || 'codex', }; } function createMacpRuntimeService(pluginConfig?: Record) { let runtime: MacpRuntime | null = null; return { id: 'macp-runtime', async start(ctx: { stateDir: string; logger: { info: (msg: string) => void } }) { const resolved = resolveConfig(pluginConfig, ctx.stateDir); runtime = new MacpRuntime({ ...resolved, logger: ctx.logger, }); registerAcpRuntimeBackend({ id: 'macp', runtime, healthy: () => runtime !== null, }); ctx.logger.info( `macp runtime backend registered (defaultRuntime: ${resolved.defaultRuntime}, defaultDispatch: ${resolved.defaultDispatch}, timeoutMs: ${resolved.timeoutMs})`, ); }, async stop() { if (runtime) { unregisterAcpRuntimeBackend('macp'); runtime = null; } }, }; } export default function register(api: any) { const service = createMacpRuntimeService(api.pluginConfig); api.registerService(service); }