@@ -4,6 +4,7 @@ import { join } from "node:path";
44import { fileURLToPath } from "node:url" ;
55import {
66 app ,
7+ autoUpdater as nativeAutoUpdater ,
78 BrowserWindow ,
89 dialog ,
910 ipcMain ,
@@ -806,17 +807,11 @@ const registerIpcHandlers = () => {
806807 // Outside a packaged build there is no real bundle to swap, and quitting
807808 // would tear down the e2e harness — reflect "installing" so the renderer
808809 // can prove the wiring instead.
809- if ( ! app . isPackaged ) {
810- setUpdateStatus ( { state : "installing" , version } ) ;
811- return ;
812- }
813- // Stop the sidecar cleanly before Squirrel.Mac swaps the bundle, matching
814- // the native dialog's restart path.
815- stopSupervisedMonitor ( ) ;
816- if ( connection ) {
817- await stopConnection ( connection ) ;
818- connection = null ;
819- }
810+ setUpdateStatus ( { state : "installing" , version } ) ;
811+ if ( ! app . isPackaged ) return ;
812+ // Squirrel.Mac only validates the staged bundle now; the sidecar is torn
813+ // down in 'before-quit-for-update' once it has accepted the update, so a
814+ // rejected zip leaves the app usable and surfaces via the 'error' handler.
820815 autoUpdater . quitAndInstall ( false , true ) ;
821816 } ) ;
822817 // Crash-screen last resort for damaged state: confirm, move the data dir
@@ -937,13 +932,7 @@ const promptInstallUpdate = async (version: string) => {
937932 cancelId : 1 ,
938933 } ) ;
939934 if ( response . response === 0 ) {
940- // Stop the sidecar cleanly before Squirrel.Mac swaps the bundle. A
941- // supervised daemon is left running — it's independent of this bundle.
942- stopSupervisedMonitor ( ) ;
943- if ( connection ) {
944- await stopConnection ( connection ) ;
945- connection = null ;
946- }
935+ setUpdateStatus ( { state : "installing" , version } ) ;
947936 autoUpdater . quitAndInstall ( false , true ) ;
948937 return ;
949938 }
@@ -963,6 +952,18 @@ const setupAutoUpdater = () => {
963952 autoUpdater . logger = log ;
964953 autoUpdater . autoDownload = true ;
965954 autoUpdater . autoInstallOnAppQuit = false ;
955+ // Fired by Electron's native updater once Squirrel.Mac has downloaded and
956+ // validated the bundle and is about to quit for the swap. Stop a spawned
957+ // sidecar here rather than before quitAndInstall: if Squirrel rejects the
958+ // update (bad signature, corrupt zip) nothing has been torn down. A
959+ // supervised daemon is left running — it's independent of this bundle.
960+ nativeAutoUpdater . on ( "before-quit-for-update" , ( ) => {
961+ stopSupervisedMonitor ( ) ;
962+ if ( connection ) {
963+ void stopConnection ( connection ) ;
964+ connection = null ;
965+ }
966+ } ) ;
966967
967968 autoUpdater . on ( "update-available" , ( info : UpdateInfo ) => {
968969 pendingUpdateVersion = info . version ;
0 commit comments