import { existsSync } from 'node:fs'; import { delimiter, join } from 'node:path'; import { app } from 'electron'; import { syncBrowserConfigToOpenClaw } from '@electron/utils/openclaw-auth'; import { getOpenClawEntryPath, getOpenClawResolvedDir, } from '@electron/utils/paths'; export interface GatewayLaunchContext { openclawDir: string; entryScript: string; binDir: string; gatewayArgs: string[]; forkEnv: Record; mode: 'dev' | 'packaged'; binPathExists: boolean; } export interface PrepareGatewayLaunchContextOptions { port: number; token: string; skipChannels?: boolean; } function prependPathEntry(pathValue: string | undefined, entry: string): string { if (!pathValue?.trim()) { return entry; } const segments = pathValue.split(delimiter); if (segments.includes(entry)) { return pathValue; } return `${entry}${delimiter}${pathValue}`; } function getBundledBinDir(): string { if (app.isPackaged) { return join(process.resourcesPath, 'bin'); } return join(process.cwd(), 'resources', 'bin', `${process.platform}-${process.arch}`); } export async function syncGatewayConfigBeforeLaunch(): Promise { await syncBrowserConfigToOpenClaw(); } export async function prepareGatewayLaunchContext( options: PrepareGatewayLaunchContextOptions, ): Promise { await syncGatewayConfigBeforeLaunch(); const openclawDir = getOpenClawResolvedDir(); const entryScript = getOpenClawEntryPath(); if (!existsSync(entryScript)) { throw new Error(`OpenClaw entry script not found at ${entryScript}`); } const gatewayArgs = [ 'gateway', '--port', String(options.port), '--token', options.token, '--allow-unconfigured', ]; const skipChannels = options.skipChannels ?? true; const binDir = getBundledBinDir(); const binPathExists = existsSync(binDir); const { NODE_OPTIONS: _nodeOptions, ELECTRON_RUN_AS_NODE: _electronRunAsNode, ...baseEnv } = process.env; const forkEnv: Record = { ...baseEnv, PATH: binPathExists ? prependPathEntry(baseEnv.PATH, binDir) : baseEnv.PATH, OPENCLAW_GATEWAY_TOKEN: options.token, OPENCLAW_SKIP_CHANNELS: skipChannels ? '1' : '', CLAWDBOT_SKIP_CHANNELS: skipChannels ? '1' : '', OPENCLAW_NO_RESPAWN: '1', }; return { openclawDir, entryScript, binDir, gatewayArgs, forkEnv, mode: app.isPackaged ? 'packaged' : 'dev', binPathExists, }; }