diff --git a/packages/desktop-electron/src/main/cli.ts b/packages/desktop-electron/src/main/cli.ts index fba301f36..f2d918bd2 100644 --- a/packages/desktop-electron/src/main/cli.ts +++ b/packages/desktop-electron/src/main/cli.ts @@ -35,6 +35,7 @@ export type CommandEvent = export type SqliteMigrationProgress = { type: "InProgress"; value: number } | { type: "Done" } export type CommandChild = { + pid: number | undefined kill: () => void } @@ -191,7 +192,7 @@ export function spawnCommand(args: string, extraEnv: Record) { treeKill(child.pid) } - return { events, child: { kill }, exit } + return { events, child: { pid: child.pid, kill }, exit } } function handleSqliteProgress(events: EventEmitter, line: string) { diff --git a/packages/desktop-electron/src/main/index.ts b/packages/desktop-electron/src/main/index.ts index 484e4feb2..032343204 100644 --- a/packages/desktop-electron/src/main/index.ts +++ b/packages/desktop-electron/src/main/index.ts @@ -81,6 +81,17 @@ function setupApp() { killSidecar() }) + app.on("will-quit", () => { + killSidecar() + }) + + for (const signal of ["SIGINT", "SIGTERM"] as const) { + process.on(signal, () => { + killSidecar() + app.exit(0) + }) + } + void app.whenReady().then(async () => { // migrate() app.setAsDefaultProtocolClient("opencode") @@ -234,8 +245,15 @@ registerIpcHandlers({ function killSidecar() { if (!sidecar) return + const pid = sidecar.pid sidecar.kill() sidecar = null + // tree-kill is async; also send process group signal as immediate fallback + if (pid && process.platform !== "win32") { + try { + process.kill(-pid, "SIGTERM") + } catch {} + } } function ensureLoopbackNoProxy() {