feat(desktop): make updates persistent and responsive (#31191)

This commit is contained in:
Luke Parker 2026-06-07 15:20:56 +10:00 committed by GitHub
commit 9b4d5b0395
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 509 additions and 396 deletions

View file

@ -1,5 +1,14 @@
import { contextBridge, ipcRenderer } from "electron"
import type { ElectronAPI, WslServersEvent } from "./types"
import type { UpdaterState } from "@opencode-ai/app/updater"
const updaterCallbacks = new Set<(state: UpdaterState) => void>()
let updaterState: UpdaterState | undefined
let updaterSubscription: Promise<void> | undefined
const updaterHandler = (_: unknown, state: UpdaterState) => {
updaterState = state
updaterCallbacks.forEach((callback) => callback(state))
}
const api: ElectronAPI = {
killSidecar: () => ipcRenderer.invoke("kill-sidecar"),
@ -28,7 +37,26 @@ const api: ElectronAPI = {
removeServer: (id) => ipcRenderer.invoke("wsl-servers-remove", id),
startServer: (id) => ipcRenderer.invoke("wsl-servers-start", id),
},
getWindowConfig: () => ipcRenderer.invoke("get-window-config"),
updater: {
subscribe: async (cb) => {
updaterCallbacks.add(cb)
if (updaterState) cb(updaterState)
if (!updaterSubscription) {
ipcRenderer.on("updater-state", updaterHandler)
updaterSubscription = ipcRenderer.invoke("updater-subscribe")
}
await updaterSubscription
return () => {
updaterCallbacks.delete(cb)
if (updaterCallbacks.size > 0) return
ipcRenderer.removeListener("updater-state", updaterHandler)
updaterSubscription = undefined
void ipcRenderer.invoke("updater-unsubscribe")
}
},
check: () => ipcRenderer.invoke("updater-check"),
install: () => ipcRenderer.invoke("updater-install"),
},
consumeInitialDeepLinks: () => ipcRenderer.invoke("consume-initial-deep-links"),
getDefaultServerUrl: () => ipcRenderer.invoke("get-default-server-url"),
setDefaultServerUrl: (url) => ipcRenderer.invoke("set-default-server-url", url),
@ -83,9 +111,6 @@ const api: ElectronAPI = {
},
setTitlebar: (theme) => ipcRenderer.invoke("set-titlebar", theme),
runDesktopMenuAction: (action) => ipcRenderer.invoke("run-desktop-menu-action", action),
runUpdater: (alertOnFail) => ipcRenderer.invoke("run-updater", alertOnFail),
checkUpdate: () => ipcRenderer.invoke("check-update"),
installUpdate: () => ipcRenderer.invoke("install-update"),
setBackgroundColor: (color: string) => ipcRenderer.invoke("set-background-color", color),
exportDebugLogs: () => ipcRenderer.invoke("export-debug-logs"),
recordFatalRendererError: (error) => ipcRenderer.invoke("record-fatal-renderer-error", error),

View file

@ -1,5 +1,6 @@
import type { DesktopMenuAction } from "@opencode-ai/app/desktop-menu"
import type { WslServersPlatform } from "@opencode-ai/app/wsl/types"
import type { UpdaterState } from "@opencode-ai/app/updater"
export type {
WslDistroProbe,
WslInstalledDistro,
@ -21,15 +22,16 @@ export type ServerReadyData = {
}
export type WslServersAPI = WslServersPlatform
export type UpdaterAPI = {
subscribe: (cb: (state: UpdaterState) => void) => Promise<() => void>
check: () => Promise<UpdaterState>
install: () => Promise<void>
}
export type LinuxDisplayBackend = "wayland" | "auto"
export type TitlebarTheme = {
mode: "light" | "dark"
}
export type WindowConfig = {
updaterEnabled: boolean
}
export type FatalRendererError = {
error: string
url: string
@ -43,7 +45,7 @@ export type ElectronAPI = {
installCli: () => Promise<string>
awaitInitialization: () => Promise<ServerReadyData>
wslServers: WslServersAPI
getWindowConfig: () => Promise<WindowConfig>
updater: UpdaterAPI
consumeInitialDeepLinks: () => Promise<string[]>
getDefaultServerUrl: () => Promise<string | null>
setDefaultServerUrl: (url: string | null) => Promise<void>
@ -92,9 +94,6 @@ export type ElectronAPI = {
onZoomFactorChanged: (cb: (factor: number) => void) => () => void
setTitlebar: (theme: TitlebarTheme) => Promise<void>
runDesktopMenuAction: (action: DesktopMenuAction) => Promise<void>
runUpdater: (alertOnFail: boolean) => Promise<void>
checkUpdate: () => Promise<{ updateAvailable: boolean; version?: string }>
installUpdate: () => Promise<void>
setBackgroundColor: (color: string) => Promise<void>
exportDebugLogs: () => Promise<string>
recordFatalRendererError: (error: FatalRendererError) => Promise<void>