From 2c5bde5a9d745a4f72319d7f1cdf9bd71ed228e0 Mon Sep 17 00:00:00 2001 From: Patrick Lee Date: Sat, 22 Aug 2026 22:30:18 -0400 Subject: [PATCH 1/3] Hold a downloaded desktop update against re-checks that tear down its staging Every update check (Settings page visits, the 15-minute activity check, and the hourly timer) made Squirrel replace its finished update. staging directory with a fresh partial extraction while the UI still offered Relaunch. Clicking Relaunch then handed ShipIt a directory without bb Nightly.app, ShipIt aborted after three retries, and the old build relaunched - so nightly updates never applied. Once electron-updater reports an update downloaded, skip further checks until that install is applied. --- apps/desktop/src/desktop-auto-update.ts | 8 ++++ apps/desktop/test/desktop-auto-update.test.ts | 38 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/apps/desktop/src/desktop-auto-update.ts b/apps/desktop/src/desktop-auto-update.ts index 1dd05a9355..572c576e8e 100644 --- a/apps/desktop/src/desktop-auto-update.ts +++ b/apps/desktop/src/desktop-auto-update.ts @@ -306,6 +306,14 @@ export function createDesktopAutoUpdateService( if (!args.enabled) { return currentInfo; } + // A downloaded update is a staged ShipIt install. Re-checking tears that + // staging down (Squirrel replaces update. with a fresh partial + // extraction), so a Relaunch issued afterwards installs a directory + // without the app bundle and ShipIt aborts three times, leaving the user + // on the old version. Hold the staged install until it is applied. + if (currentInfo.updateDownloaded) { + return currentInfo; + } if (inflight !== null) { return inflight; } diff --git a/apps/desktop/test/desktop-auto-update.test.ts b/apps/desktop/test/desktop-auto-update.test.ts index 62edde773b..4f39292bf0 100644 --- a/apps/desktop/test/desktop-auto-update.test.ts +++ b/apps/desktop/test/desktop-auto-update.test.ts @@ -367,6 +367,44 @@ describe("desktop auto-update service", () => { }); }); + it("holds a downloaded update by skipping re-checks that would tear down its staging", async () => { + const updater = new DesktopAutoUpdaterAdapterStub(); + updater.updateCheckResult = createUpdateCheckResult("0.0.2"); + let currentTime = Date.parse(checkedAt); + const service = createDesktopAutoUpdateService({ + currentVersion: "0.0.1", + enabled: true, + forceDevUpdateConfig: false, + logger: createLogger(createLoggerMessages()), + now: () => currentTime, + platform: "macos", + updater, + }); + + await service.checkForUpdates(); + expect(updater.checkForUpdatesCalls).toBe(1); + + updater.emitUpdateDownloaded(createDownloadedEvent("0.0.2")); + await service.checkForUpdates(); + // Advance past the active-check throttle so this reaches checkForUpdates. + currentTime += 16 * 60 * 1000; + await service.checkAfterActive(); + + // The staged ShipIt install stays untouched: no further checks run and + // the info keeps reporting the downloaded update. + expect(updater.checkForUpdatesCalls).toBe(1); + expect(service.getInfo()).toEqual({ + downloadState: "downloaded", + lastCheckedAt: checkedAt, + latestVersion: "0.0.2", + pendingVersion: "0.0.2", + platform: "macos", + updateAvailable: true, + updateDownloaded: true, + version: "0.0.1", + }); + }); + it("does not initialize electron-updater in dev mode without the override", async () => { const updater = new DesktopAutoUpdaterAdapterStub(); const enabled = shouldEnableDesktopAutoUpdate({ From 6e1bafc9ebcda9bf3fec6c0f7b97c52b9e92a9fb Mon Sep 17 00:00:00 2001 From: Patrick Lee Date: Sat, 22 Aug 2026 22:44:27 -0400 Subject: [PATCH 2/3] Check for desktop updates every 6 hours instead of hourly --- apps/desktop/src/desktop-update-check.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/src/desktop-update-check.ts b/apps/desktop/src/desktop-update-check.ts index e067c9d5c2..05964890ba 100644 --- a/apps/desktop/src/desktop-update-check.ts +++ b/apps/desktop/src/desktop-update-check.ts @@ -8,7 +8,7 @@ import { } from "@bb/desktop-contract"; export { createDesktopUpdateFeedUrl } from "./desktop-update-provider.js"; -export const DESKTOP_UPDATE_CHECK_INTERVAL_MS = 60 * 60 * 1000; +export const DESKTOP_UPDATE_CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000; export const DESKTOP_UPDATE_CHECK_TIMEOUT_MS = 5_000; export const DESKTOP_UPDATE_ACTIVE_MIN_INTERVAL_MS = 15 * 60 * 1000; From b308db12e230e33fdeeaafd0ad68794dd26fc008 Mon Sep 17 00:00:00 2001 From: Patrick Lee Date: Sat, 22 Aug 2026 22:45:47 -0400 Subject: [PATCH 3/3] Revert "Check for desktop updates every 6 hours instead of hourly" This reverts commit 6e1bafc9ebcda9bf3fec6c0f7b97c52b9e92a9fb. --- apps/desktop/src/desktop-update-check.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/src/desktop-update-check.ts b/apps/desktop/src/desktop-update-check.ts index 05964890ba..e067c9d5c2 100644 --- a/apps/desktop/src/desktop-update-check.ts +++ b/apps/desktop/src/desktop-update-check.ts @@ -8,7 +8,7 @@ import { } from "@bb/desktop-contract"; export { createDesktopUpdateFeedUrl } from "./desktop-update-provider.js"; -export const DESKTOP_UPDATE_CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000; +export const DESKTOP_UPDATE_CHECK_INTERVAL_MS = 60 * 60 * 1000; export const DESKTOP_UPDATE_CHECK_TIMEOUT_MS = 5_000; export const DESKTOP_UPDATE_ACTIVE_MIN_INTERVAL_MS = 15 * 60 * 1000;