103 lines
3.1 KiB
TypeScript
103 lines
3.1 KiB
TypeScript
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<string, unknown>, 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<string, unknown>) {
|
|
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);
|
|
}
|