From 34a4b3dad3c5203e1c634f07a7b9d14294be124a Mon Sep 17 00:00:00 2001 From: liuzhq Date: Wed, 18 Mar 2026 15:14:58 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0openclaw=20gatewa?= =?UTF-8?q?y=20=E5=90=AF=E5=8A=A8=E5=A4=B1=E8=B4=A5=E5=90=8E=E9=87=8D?= =?UTF-8?q?=E5=90=AF=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/main.ts | 26 ++++++++++ src/main/preload.ts | 1 + src/renderer/components/cowork/CoworkView.tsx | 47 ++++++++++--------- src/renderer/services/cowork.ts | 13 +++++ src/renderer/services/i18n.ts | 2 + src/renderer/types/electron.d.ts | 1 + 6 files changed, 69 insertions(+), 21 deletions(-) diff --git a/src/main/main.ts b/src/main/main.ts index 7e666a1..6ad7347 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -1730,6 +1730,32 @@ if (!gotTheLock) { } }); + let restartGatewayPromise: Promise | null = null; + ipcMain.handle('openclaw:engine:restartGateway', async () => { + if (restartGatewayPromise) { + const status = await restartGatewayPromise; + return { success: status.phase === 'running' || status.phase === 'ready', status }; + } + try { + const manager = getOpenClawEngineManager(); + restartGatewayPromise = manager.restartGateway(); + const status = await restartGatewayPromise; + return { + success: status.phase === 'running' || status.phase === 'ready', + status, + }; + } catch (error) { + const manager = getOpenClawEngineManager(); + return { + success: false, + status: manager.getStatus(), + error: error instanceof Error ? error.message : 'Failed to restart OpenClaw gateway', + }; + } finally { + restartGatewayPromise = null; + } + }); + // MCP Server IPC handlers ipcMain.handle('mcp:list', () => { try { diff --git a/src/main/preload.ts b/src/main/preload.ts index d8ee958..f28e75b 100644 --- a/src/main/preload.ts +++ b/src/main/preload.ts @@ -123,6 +123,7 @@ contextBridge.exposeInMainWorld('electron', { getStatus: () => ipcRenderer.invoke('openclaw:engine:getStatus'), install: () => ipcRenderer.invoke('openclaw:engine:install'), retryInstall: () => ipcRenderer.invoke('openclaw:engine:retryInstall'), + restartGateway: () => ipcRenderer.invoke('openclaw:engine:restartGateway'), onProgress: (callback: (status: any) => void) => { const handler = (_event: any, status: any) => callback(status); ipcRenderer.on('openclaw:engine:onProgress', handler); diff --git a/src/renderer/components/cowork/CoworkView.tsx b/src/renderer/components/cowork/CoworkView.tsx index ecc5c4e..dd783d5 100644 --- a/src/renderer/components/cowork/CoworkView.tsx +++ b/src/renderer/components/cowork/CoworkView.tsx @@ -33,6 +33,7 @@ const CoworkView: React.FC = ({ onRequestAppSettings, onShowSki const isMac = window.electron.platform === 'darwin'; const [isInitialized, setIsInitialized] = useState(false); const [openClawStatus, setOpenClawStatus] = useState(null); + const [isRestartingGateway, setIsRestartingGateway] = useState(false); // Track if we're starting a session to prevent duplicate submissions const isStartingRef = useRef(false); // Track pending start request so stop can cancel delayed startup. @@ -69,9 +70,6 @@ const CoworkView: React.FC = ({ onRequestAppSettings, onShowSki }; const resolveEngineStatusText = (status: OpenClawEngineStatus): string => { - if (status.message?.trim()) { - return status.message.trim(); - } switch (status.phase) { case 'not_installed': return i18nService.t('coworkOpenClawNotInstalledNotice'); @@ -94,6 +92,18 @@ const CoworkView: React.FC = ({ onRequestAppSettings, onShowSki return status.phase === 'running' || status.phase === 'ready'; }; + const handleRestartGateway = async () => { + if (isRestartingGateway) return; + setIsRestartingGateway(true); + try { + await coworkService.restartOpenClawGateway(); + } catch (error) { + console.error('[CoworkView] Failed to restart gateway:', error); + } finally { + setIsRestartingGateway(false); + } + }; + useEffect(() => { const init = async () => { await coworkService.init(); @@ -390,11 +400,6 @@ const CoworkView: React.FC = ({ onRequestAppSettings, onShowSki const shouldShowEngineStatus = Boolean(isOpenClawEngine && openClawStatus && openClawStatus.phase !== 'running'); const isEngineError = openClawStatus?.phase === 'error'; - const shouldShowGoToSettingsInstall = openClawStatus - ? (openClawStatus.phase === 'not_installed' - || openClawStatus.phase === 'installing' - || openClawStatus.phase === 'error') - : false; const isEngineReady = isOpenClawEngine ? isOpenClawReadyForSession(openClawStatus) : true; @@ -480,10 +485,11 @@ const CoworkView: React.FC = ({ onRequestAppSettings, onShowSki )} @@ -528,17 +534,16 @@ const CoworkView: React.FC = ({ onRequestAppSettings, onShowSki )} - {shouldShowGoToSettingsInstall && ( - - )} )} diff --git a/src/renderer/services/cowork.ts b/src/renderer/services/cowork.ts index 23e06ca..896a170 100644 --- a/src/renderer/services/cowork.ts +++ b/src/renderer/services/cowork.ts @@ -582,6 +582,19 @@ class CoworkService { return this.openClawStatus; } + async restartOpenClawGateway(): Promise { + const engineApi = window.electron?.openclaw?.engine; + if (!engineApi?.restartGateway) { + return null; + } + const result = await engineApi.restartGateway(); + if (result?.status) { + this.notifyOpenClawStatus(result.status); + return result.status; + } + return this.openClawStatus; + } + async generateSessionTitle(prompt: string | null): Promise { if (!window.electron?.generateSessionTitle) { return null; diff --git a/src/renderer/services/i18n.ts b/src/renderer/services/i18n.ts index ad88f36..9c18e1b 100644 --- a/src/renderer/services/i18n.ts +++ b/src/renderer/services/i18n.ts @@ -253,6 +253,7 @@ const translations: Record> = { coworkOpenClawInstalling: '正在启动 OpenClaw...', coworkOpenClawInstallHint: 'OpenClaw 运行时已内置。切换到该引擎或启动任务时会自动拉起网关。', coworkOpenClawGoToSettingsInstall: '查看引擎设置', + coworkOpenClawRestartGateway: '重新启动网关', coworkOpenClawNotInstalledNotice: '未检测到内置 OpenClaw runtime(cfmind),请先执行打包前构建脚本。', coworkOpenClawReadyNotice: 'OpenClaw runtime 已就绪。开始任务时会自动启动网关。', coworkOpenClawStarting: 'AI 引擎正在启动网关...', @@ -1167,6 +1168,7 @@ const translations: Record> = { coworkOpenClawInstalling: 'Starting OpenClaw...', coworkOpenClawInstallHint: 'OpenClaw runtime is bundled. Switching to this engine or starting a task will auto-start the gateway.', coworkOpenClawGoToSettingsInstall: 'View Engine Settings', + coworkOpenClawRestartGateway: 'Restart Gateway', coworkOpenClawNotInstalledNotice: 'Bundled OpenClaw runtime (cfmind) was not found. Build the runtime before packaging.', coworkOpenClawReadyNotice: 'OpenClaw runtime is ready. The gateway will auto-start when you run a task.', coworkOpenClawStarting: 'AI engine is starting the gateway...', diff --git a/src/renderer/types/electron.d.ts b/src/renderer/types/electron.d.ts index 7c7bcac..0e33530 100644 --- a/src/renderer/types/electron.d.ts +++ b/src/renderer/types/electron.d.ts @@ -276,6 +276,7 @@ interface IElectronAPI { getStatus: () => Promise<{ success: boolean; status?: OpenClawEngineStatus; error?: string }>; install: () => Promise<{ success: boolean; status?: OpenClawEngineStatus; error?: string }>; retryInstall: () => Promise<{ success: boolean; status?: OpenClawEngineStatus; error?: string }>; + restartGateway: () => Promise<{ success: boolean; status?: OpenClawEngineStatus; error?: string }>; onProgress: (callback: (status: OpenClawEngineStatus) => void) => () => void; }; }; From 3d82758c4131dc5653ec432bf328787ad395cd5e Mon Sep 17 00:00:00 2001 From: liuzhq Date: Wed, 18 Mar 2026 15:32:21 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E7=BD=91=E5=85=B3=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E5=A4=B1=E8=B4=A5=E6=97=B6=E6=98=BE=E7=A4=BA=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E5=90=AF=E5=8A=A8=E7=BD=91=E5=85=B3=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E5=B9=B6=E5=9B=BD=E9=99=85=E5=8C=96=E7=8A=B6=E6=80=81=E6=96=87?= =?UTF-8?q?=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/services/i18n.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/services/i18n.ts b/src/renderer/services/i18n.ts index 9c18e1b..1ced470 100644 --- a/src/renderer/services/i18n.ts +++ b/src/renderer/services/i18n.ts @@ -258,7 +258,7 @@ const translations: Record> = { coworkOpenClawReadyNotice: 'OpenClaw runtime 已就绪。开始任务时会自动启动网关。', coworkOpenClawStarting: 'AI 引擎正在启动网关...', coworkOpenClawRunning: 'AI 引擎已就绪。', - coworkOpenClawError: 'AI 引擎初始化失败,请前往设置页检查运行时配置。', + coworkOpenClawError: 'OpenClaw 网关未能在规定时间内启动成功。', coworkMemoryTitle: '记忆', coworkAgentTab: 'Agent', coworkBootstrapAgentSectionTitle: 'Agent 设定', @@ -1173,7 +1173,7 @@ const translations: Record> = { coworkOpenClawReadyNotice: 'OpenClaw runtime is ready. The gateway will auto-start when you run a task.', coworkOpenClawStarting: 'AI engine is starting the gateway...', coworkOpenClawRunning: 'AI engine is ready.', - coworkOpenClawError: 'AI engine initialization failed. Please check the runtime configuration in Settings.', + coworkOpenClawError: 'OpenClaw gateway failed to become healthy in time.', coworkMemoryTitle: 'Memory', coworkAgentTab: 'Agent', coworkBootstrapAgentSectionTitle: 'Agent Settings',