From 2f40bd2c6233bbdc3fba254fde1e2e3ab4d027bf Mon Sep 17 00:00:00 2001 From: 7418 <7418@openclaw.ai> Date: Fri, 6 Feb 2026 21:33:27 +0800 Subject: [PATCH] fix: use spawn with ELECTRON_RUN_AS_NODE for packaged server - Replace fork() with spawn() + ELECTRON_RUN_AS_NODE=1 so the standalone server runs correctly inside the packaged app - Set cwd to standalone directory for proper dependency resolution - Show error dialog on startup failure instead of silent quit - Add Chinese README (README_CN.md) Co-Authored-By: Claude Opus 4.6 --- electron/main.ts | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/electron/main.ts b/electron/main.ts index e8a65b6..17195e3 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -1,10 +1,11 @@ -import { app, BrowserWindow, nativeImage } from 'electron'; +import { app, BrowserWindow, nativeImage, dialog } from 'electron'; import path from 'path'; -import { fork, ChildProcess } from 'child_process'; +import { spawn, ChildProcess } from 'child_process'; import net from 'net'; let mainWindow: BrowserWindow | null = null; let serverProcess: ChildProcess | null = null; +let serverPort: number | null = null; const isDev = !app.isPackaged; @@ -51,14 +52,20 @@ async function waitForServer(port: number, timeout = 30000): Promise { function startServer(port: number): ChildProcess { const serverPath = path.join(process.resourcesPath, 'standalone', 'server.js'); - const child = fork(serverPath, [], { + // Use the bundled Node.js from Electron's helper + const nodePath = process.execPath; + + const child = spawn(nodePath, [serverPath], { env: { ...process.env, PORT: String(port), HOSTNAME: '127.0.0.1', CLAUDE_GUI_DATA_DIR: app.getPath('userData'), + // Tell Electron's Node not to load the Electron module + ELECTRON_RUN_AS_NODE: '1', }, stdio: 'pipe', + cwd: path.join(process.resourcesPath, 'standalone'), }); child.stdout?.on('data', (data: Buffer) => { @@ -131,9 +138,14 @@ app.whenReady().then(async () => { console.log('Server is ready'); } + serverPort = port; createWindow(port); } catch (err) { console.error('Failed to start:', err); + dialog.showErrorBox( + 'CodePilot - Failed to Start', + `The internal server could not start.\n\n${err instanceof Error ? err.message : String(err)}\n\nPlease try restarting the application.` + ); app.quit(); } }); @@ -150,12 +162,17 @@ app.on('window-all-closed', () => { app.on('activate', async () => { if (BrowserWindow.getAllWindows().length === 0) { - const port = isDev ? 3000 : await getPort(); - if (!isDev && !serverProcess) { - serverProcess = startServer(port); - await waitForServer(port); + try { + if (!isDev && !serverProcess) { + const port = await getPort(); + serverProcess = startServer(port); + await waitForServer(port); + serverPort = port; + } + createWindow(serverPort || 3000); + } catch (err) { + console.error('Failed to restart server:', err); } - createWindow(port); } });