import { utilityProcess } from 'electron'; import logManager from '@electron/service/logger'; export interface OpenClawGatewayLaunchContext { port: number; token: string; openclawDir: string; entryScript: string; } export async function launchGatewayProcess( context: OpenClawGatewayLaunchContext, ): Promise { const gatewayArgs = [ 'gateway', '--port', String(context.port), '--token', context.token, '--allow-unconfigured', ]; const env: NodeJS.ProcessEnv = { ...process.env, OPENCLAW_GATEWAY_TOKEN: context.token, OPENCLAW_SKIP_CHANNELS: '1', OPENCLAW_NO_RESPAWN: '1', }; logManager.info('Starting OpenClaw Gateway process', { port: context.port, entryScript: context.entryScript, cwd: context.openclawDir, args: gatewayArgs, }); return await new Promise((resolve, reject) => { const child = utilityProcess.fork(context.entryScript, gatewayArgs, { cwd: context.openclawDir, stdio: 'pipe', env, serviceName: 'OpenClaw Gateway', }); let settled = false; const resolveOnce = () => { if (settled) return; settled = true; resolve(child); }; const rejectOnce = (error: Error) => { if (settled) return; settled = true; reject(error); }; child.once('spawn', () => { logManager.info('OpenClaw Gateway process spawned', { pid: child.pid }); resolveOnce(); }); child.once('error', (error) => { logManager.error('OpenClaw Gateway process spawn error:', error); rejectOnce(error); }); child.once('exit', (code) => { if (!settled) { rejectOnce(new Error(`OpenClaw Gateway exited before spawn completed (code=${code ?? 'unknown'})`)); } }); child.stderr?.on('data', (data) => { const raw = data.toString(); for (const line of raw.split(/\r?\n/)) { const trimmed = line.trim(); if (trimmed) { logManager.warn(`[OpenClaw] ${trimmed}`); } } }); }); }