From 66ad2b2c30f42354681d19a3992344f525ac566f Mon Sep 17 00:00:00 2001 From: Side Quest Studios Date: Fri, 24 Jul 2026 13:50:36 -0400 Subject: [PATCH] fix: wait for the relaunch spawn to hand off before app.exit() Verified directly: PR #11's fix (spawn 'open' + immediately call app.exit()) could silently drop the relaunch entirely - the app quit and never came back, no error, nothing. Reproduced in isolation that the same spawn+exit pattern works fine as a plain Node script, so this is specific to app.exit(): it tears the process down harder and faster than a normal quit, and was winning the race against `open` finishing its handoff to launchd. Give the spawned process a brief moment to actually launch before tearing this one down. Also use the absolute /usr/bin/open path instead of relying on PATH resolution, removing one more variable. --- electron/ipc/register/permissions.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/electron/ipc/register/permissions.ts b/electron/ipc/register/permissions.ts index e82e09e98..d5dd34132 100644 --- a/electron/ipc/register/permissions.ts +++ b/electron/ipc/register/permissions.ts @@ -4,7 +4,7 @@ import { app, ipcMain, shell, systemPreferences } from "electron"; import { getMacPrivacySettingsUrl } from "../utils"; export function registerPermissionHandlers() { - ipcMain.handle('relaunch-app', () => { + ipcMain.handle('relaunch-app', async () => { // macOS caches permission-check results (getMediaAccessStatus, etc.) for // the life of the process, so a grant made in System Settings is invisible // until the app actually restarts - closing the window isn't enough on @@ -21,7 +21,12 @@ export function registerPermissionHandlers() { // lineage as double-clicking it in Finder/Dock actually has. if (process.platform === "darwin") { const appBundlePath = path.dirname(path.dirname(path.dirname(process.execPath))); - spawn("open", [appBundlePath], { detached: true, stdio: "ignore" }).unref(); + spawn("/usr/bin/open", [appBundlePath], { detached: true, stdio: "ignore" }).unref(); + // app.exit() tears the process down harder/faster than a normal quit - + // verified directly that calling it immediately after spawn() could + // kill this process before `open` finished handing off to launchd, + // silently dropping the relaunch entirely. Give it a moment first. + await new Promise((resolve) => setTimeout(resolve, 500)); app.exit(0); } else { app.relaunch();