From 9b6da6d5853ef05836886434975fa7abf2f5717f Mon Sep 17 00:00:00 2001 From: Andrew Mikofalvy <5668128+amikofalvy@users.noreply.github.com> Date: Tue, 30 Jun 2026 12:32:43 -0700 Subject: [PATCH] fix(open-knowledge): suppress update notices in dev builds (#2296) Dev desktop builds never download or install updates, but boot-time update state (attemptedInstall / versionPendingInstall / lastSeenVersion) could still surface the 'Update to X didn't install' banner, the staged-update relaunch banner, and the 'what's new' toast from stale local state. Gate every user-visible update notice on the same isPackaged || forceDevBypass signal that already gates update checks: the boot-time failed-install and what's-new emits in auto-updater.ts, and the late-window re-broadcast in index.ts. OK_UPDATER_FORCE_DEV stays as the escape hatch so the manual update smoke can still observe the toasts in a dev build. GitOrigin-RevId: 3e39659a329cdceaca428611fe3caac67b412a21 --- .changeset/dev-suppress-update-notices.md | 5 +++ packages/desktop/src/main/auto-updater.ts | 8 ++-- packages/desktop/src/main/index.ts | 1 + .../tests/integration/auto-updater.test.ts | 44 +++++++++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 .changeset/dev-suppress-update-notices.md diff --git a/.changeset/dev-suppress-update-notices.md b/.changeset/dev-suppress-update-notices.md new file mode 100644 index 000000000..a76be285a --- /dev/null +++ b/.changeset/dev-suppress-update-notices.md @@ -0,0 +1,5 @@ +--- +"@inkeep/open-knowledge-desktop": patch +--- + +Stop showing auto-update notices in unpackaged dev builds. A dev desktop app never downloads or installs updates, so the boot-time "Update to X didn't install" banner, the staged-update relaunch banner, and the "what's new" toast were all noise driven by stale local state. They're now gated on the same signal that gates update checks (`app.isPackaged`), with the `OK_UPDATER_FORCE_DEV` escape hatch preserved for the manual update smoke. diff --git a/packages/desktop/src/main/auto-updater.ts b/packages/desktop/src/main/auto-updater.ts index 01b69453b..13580b473 100644 --- a/packages/desktop/src/main/auto-updater.ts +++ b/packages/desktop/src/main/auto-updater.ts @@ -270,6 +270,8 @@ export function startAutoUpdater(opts: StartAutoUpdaterOpts): StartAutoUpdaterHa }); } + const updatesEnabled = isPackaged || forceDevBypass; + const revertToGithubFeed = (cause: string): void => { if (!usingProxyFeed || proxyFallbackTried) return; proxyFallbackTried = true; @@ -667,7 +669,7 @@ export function startAutoUpdater(opts: StartAutoUpdaterOpts): StartAutoUpdaterHa running: currentVersion, }); } - } else { + } else if (updatesEnabled) { const next = { ...state, versionPendingInstall: attempted }; if (persistSafely(next, 'install-failed-on-boot')) { state = next; @@ -697,7 +699,7 @@ export function startAutoUpdater(opts: StartAutoUpdaterOpts): StartAutoUpdaterHa { ...state, lastSeenVersion: currentVersion }, 'lastSeenVersion-advance', ); - if (advanced && shouldShowVersionNotice) { + if (advanced && shouldShowVersionNotice && updatesEnabled) { const fireToastB = (): void => { const releaseUrl = releaseUrlFor(currentVersion); activeWhatsNew = { version: currentVersion, releaseUrl, firedAt: now().getTime() }; @@ -740,7 +742,7 @@ export function startAutoUpdater(opts: StartAutoUpdaterOpts): StartAutoUpdaterHa scheduleNextCheck(); }; - if (isPackaged || forceDevBypass) { + if (updatesEnabled) { void updater .checkForUpdates() .then(() => { diff --git a/packages/desktop/src/main/index.ts b/packages/desktop/src/main/index.ts index 8116f5f97..f8f4a2142 100644 --- a/packages/desktop/src/main/index.ts +++ b/packages/desktop/src/main/index.ts @@ -2665,6 +2665,7 @@ function bootPrimaryInstance(): void { app.on('browser-window-created', (_event, win) => { win.webContents.once('did-finish-load', () => { + if (!(app.isPackaged || process.env.OK_UPDATER_FORCE_DEV === '1')) return; const pending = appState.versionPendingInstall; if (pending) { sendToRenderer(win.webContents, 'ok:update:downloaded', { version: pending }); diff --git a/packages/desktop/tests/integration/auto-updater.test.ts b/packages/desktop/tests/integration/auto-updater.test.ts index 9ec2178f2..da7f8ef39 100644 --- a/packages/desktop/tests/integration/auto-updater.test.ts +++ b/packages/desktop/tests/integration/auto-updater.test.ts @@ -1976,6 +1976,50 @@ describe('dev-mode guard (isPackaged=false)', () => { const toastA = rig.captured.filter((c) => c.channel === 'ok:update:downloaded'); expect(toastA).toHaveLength(1); }); + + test('boot-time failed-install notice suppressed when isPackaged=false', () => { + const { rig } = makeRig({ + isPackaged: false, + attemptedInstall: '0.5.0', + appVersion: '0.4.0', + }); + expect(rig.captured.filter((c) => c.channel === 'ok:update:relaunch-failed')).toHaveLength(0); + expect(rig.dispatches).not.toContain('install-failed-on-boot' as DispatchKind); + }); + + test('boot-time whats-new toast suppressed when isPackaged=false (lastSeenVersion still advances)', () => { + const { rig } = makeRig({ + isPackaged: false, + lastSeenVersion: '0.3.0', + appVersion: '0.3.1', + }); + expect(rig.captured.filter((c) => c.channel === 'ok:update:whats-new')).toHaveLength(0); + expect(rig.dispatches).not.toContain('whats-new-toast-b' as DispatchKind); + expect(rig.state.lastSeenVersion).toBe('0.3.1'); + }); + + test('forceDevBypass=true re-enables the boot-time failed-install notice', () => { + const { rig } = makeRig({ + isPackaged: false, + forceDevBypass: true, + attemptedInstall: '0.5.0', + appVersion: '0.4.0', + }); + const failed = rig.captured.filter((c) => c.channel === 'ok:update:relaunch-failed'); + expect(failed).toHaveLength(1); + expect(rig.dispatches).toContain('install-failed-on-boot' as DispatchKind); + }); + + test('forceDevBypass=true re-enables the boot-time whats-new toast', () => { + const { rig } = makeRig({ + isPackaged: false, + forceDevBypass: true, + lastSeenVersion: '0.3.0', + appVersion: '0.3.1', + }); + expect(rig.captured.filter((c) => c.channel === 'ok:update:whats-new')).toHaveLength(1); + expect(rig.dispatches).toContain('whats-new-toast-b' as DispatchKind); + }); }); describe('download-progress (log-only, no UI surface)', () => {