Always install the newest eligible desktop update (#2149)

* Reapply "Always revalidate desktop updates before install"

This reverts commit 623c05aa4d.

* fix(desktop): make update revalidation safe on quit

Updater-triggered quits now bypass normal quit handling, and manifest revalidation gives up after five seconds without allowing a late install.

* fix(desktop): preserve fail-closed update installs

Keep cached updates deferred when quit-time validation is offline, and report validation timeouts separately from superseded releases.

* fix(desktop): preserve updater quit behavior

Automatic installs remain silent without relaunching, updater handoff is bounded, and background preparation failures remain visible without pinning manifest checks.

* fix(desktop): keep AppImage updates manual

Preserve the AppImage safety exemption by skipping ordinary quit-time installation while retaining the explicit Update now path.

* fix(desktop): serialize update preparation

* fix(desktop): recognize macOS updater quit handoff
This commit is contained in:
Mohamed Boudra
2026-07-17 10:06:32 +02:00
committed by GitHub
parent a8ebd390fa
commit 70472dc945
8 changed files with 909 additions and 328 deletions
+34 -18
View File
@@ -12,6 +12,7 @@ import { existsSync } from "node:fs";
import { execFileSync } from "node:child_process";
import {
app,
autoUpdater as electronAutoUpdater,
BrowserWindow,
clipboard,
Menu,
@@ -81,19 +82,21 @@ import {
stopDesktopDaemonViaCli,
} from "./daemon/daemon-manager.js";
import {
createBeforeQuitHandler,
createQuitLifecycle,
stopDesktopManagedDaemonOnQuitIfNeeded,
} from "./daemon/quit-lifecycle.js";
import { runDesktopStartup } from "./desktop-startup.js";
import { autoUpdateInstalledSkills } from "./integrations/skills/index.js";
import { registerBrowserAutomationIpc } from "./features/browser-automation/ipc.js";
import { BrowserKeyboard } from "./features/browser-keyboard/index.js";
import { installAppUpdateOnQuit } from "./features/auto-updater.js";
const DEV_SERVER_URL = process.env.EXPO_DEV_URL ?? "http://localhost:8081";
const APP_SCHEME = "paseo";
const PASEO_DEBUG = process.env.PASEO_DEBUG === "1";
const DISABLE_SINGLE_INSTANCE_LOCK = process.env.PASEO_DISABLE_SINGLE_INSTANCE_LOCK === "1";
const APP_NAME = process.env.PASEO_TEST_APP_NAME?.trim() || "Paseo";
const UPDATE_QUIT_DEADLINE_MS = 5_000;
const pendingBrowserWindowOpenRequests = new PendingBrowserWindowOpenRequests();
app.setName(APP_NAME);
@@ -928,23 +931,36 @@ function showDaemonShutdownDialog(): void {
}
}
app.on(
"before-quit",
createBeforeQuitHandler({
app,
closeTransportSessions: closeAllTransportSessions,
stopDesktopManagedDaemonIfNeeded: () =>
stopDesktopManagedDaemonOnQuitIfNeeded({
settingsStore: getDesktopSettingsStore(),
isDesktopManagedDaemonRunning: isDesktopManagedDaemonRunningSync,
stopDaemon: () => stopDesktopDaemonViaCli("quit"),
showShutdownFeedback: showDaemonShutdownDialog,
}),
onStopError: (error) => {
log.error("[desktop daemon] failed to stop managed daemon on quit", error);
},
}),
);
const quitLifecycle = createQuitLifecycle({
app,
closeTransportSessions: closeAllTransportSessions,
stopDesktopManagedDaemonIfNeeded: () =>
stopDesktopManagedDaemonOnQuitIfNeeded({
settingsStore: getDesktopSettingsStore(),
isDesktopManagedDaemonRunning: isDesktopManagedDaemonRunningSync,
stopDaemon: () => stopDesktopDaemonViaCli("quit"),
showShutdownFeedback: showDaemonShutdownDialog,
}),
installAppUpdateOnQuit: async (signal) => {
const settings = await getDesktopSettingsStore().get();
return installAppUpdateOnQuit({
currentVersion: app.getVersion(),
releaseChannel: settings.releaseChannel,
signal,
});
},
createUpdateDeadlineSignal: () => AbortSignal.timeout(UPDATE_QUIT_DEADLINE_MS),
onStopError: (error) => {
log.error("[desktop daemon] failed to stop managed daemon on quit", error);
},
onUpdateError: (error) => {
log.error("[auto-updater] failed to validate downloaded update on quit", error);
},
});
// electron-updater forwards this event through Electron's built-in autoUpdater.
electronAutoUpdater.on("before-quit-for-update", quitLifecycle.handleBeforeQuitForUpdate);
app.on("before-quit", quitLifecycle.handleBeforeQuit);
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {