diff --git a/electron/main.ts b/electron/main.ts index 7c48fba..0a49e3a 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -17,11 +17,20 @@ const __dirname = path.dirname(__filename); electronState.setDevelopment(!app.isPackaged); let lastClipboardText = ''; +let clipboardWatcherTimer: NodeJS.Timeout | null = null; + +function stopClipboardWatcher() { + if (clipboardWatcherTimer) { + clearInterval(clipboardWatcherTimer); + clipboardWatcherTimer = null; + log.info('[ClipboardWatcher] Stopped'); + } +} function startClipboardWatcher() { lastClipboardText = clipboard.readText(); - setInterval(() => { + clipboardWatcherTimer = setInterval(() => { try { const currentText = clipboard.readText(); if (currentText && currentText !== lastClipboardText) { @@ -447,7 +456,26 @@ app.whenReady().then(async () => { app.on('window-all-closed', () => { globalShortcut.unregisterAll(); opencodeService.stop(); + xcOpenCodeWebService.stop(); + stopClipboardWatcher(); if (process.platform !== 'darwin') { app.quit(); } }); + +let isQuitting = false; + +app.on('before-quit', async (event) => { + if (isQuitting) return; + isQuitting = true; + + log.info('[App] before-quit received, cleaning up...'); + stopClipboardWatcher(); + + await Promise.all([ + opencodeService.stop(), + xcOpenCodeWebService.stop() + ]); + + log.info('[App] All services stopped'); +}); diff --git a/electron/services/opencodeService.ts b/electron/services/opencodeService.ts index a46e06e..f28ff0e 100644 --- a/electron/services/opencodeService.ts +++ b/electron/services/opencodeService.ts @@ -1,4 +1,4 @@ -import { spawn, ChildProcess } from 'child_process'; +import { spawn, exec, ChildProcess } from 'child_process'; import log from 'electron-log'; const OPENCODE_PORT = 4096; @@ -150,21 +150,33 @@ class OpenCodeService { try { log.info('[OpenCodeService] Stopping...'); - this.process.kill('SIGTERM'); - - await new Promise((resolve) => { - setTimeout(resolve, 1000); - }); - - if (this.process && !this.process.killed) { - this.process.kill('SIGKILL'); - } - + const pid = this.process.pid; this.process = null; this._isRunning = false; - this.restartAttempts = 0; - log.info('[OpenCodeService] Stopped'); + if (pid && process.platform === 'win32') { + return new Promise((resolve) => { + exec(`taskkill /F /T /PID ${pid}`, (error) => { + if (error) { + log.warn('[OpenCodeService] taskkill failed, process may already be dead:', error.message); + } + this.restartAttempts = 0; + log.info('[OpenCodeService] Stopped'); + resolve({ success: true }); + }); + }); + } else if (pid) { + this.process?.kill('SIGTERM'); + await new Promise((resolve) => setTimeout(resolve, 1000)); + if (this.process && !this.process.killed) { + this.process.kill('SIGKILL'); + } + this.restartAttempts = 0; + log.info('[OpenCodeService] Stopped'); + return { success: true }; + } + + this.restartAttempts = 0; return { success: true }; } catch (error: any) { log.error('[OpenCodeService] Failed to stop:', error);