diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 34833f5267c..33be73ca2d1 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -426,6 +426,15 @@ function App() { }) }) + event.on(Installation.Event.UpdateAvailable.type, (evt) => { + toast.show({ + variant: "info", + title: "Update Available", + message: `OpenCode v${evt.properties.version} is available. Run 'opencode upgrade' to update manually.`, + duration: 10000, + }) + }) + return ( { + client.call("checkUpgrade", { directory: cwd }).catch(() => {}) + }, 1000) + + await tuiPromise }, }) diff --git a/packages/opencode/src/cli/cmd/tui/worker.ts b/packages/opencode/src/cli/cmd/tui/worker.ts index db1eb8ecb76..50274f44200 100644 --- a/packages/opencode/src/cli/cmd/tui/worker.ts +++ b/packages/opencode/src/cli/cmd/tui/worker.ts @@ -26,8 +26,6 @@ process.on("uncaughtException", (e) => { }) }) -upgrade() - let server: Bun.Server export const rpc = { async server(input: { port: number; hostname: string }) { @@ -42,6 +40,14 @@ export const rpc = { throw e } }, + async checkUpgrade(input: { directory: string }) { + await Instance.provide({ + directory: input.directory, + fn: async () => { + await upgrade().catch(() => {}) + }, + }) + }, async shutdown() { Log.Default.info("worker shutting down") await Instance.disposeAll() diff --git a/packages/opencode/src/cli/upgrade.ts b/packages/opencode/src/cli/upgrade.ts index 73332f95528..ca5cba27c5a 100644 --- a/packages/opencode/src/cli/upgrade.ts +++ b/packages/opencode/src/cli/upgrade.ts @@ -5,10 +5,15 @@ import { Installation } from "@/installation" export async function upgrade() { const config = await Config.global() - if (config.autoupdate === false || Flag.OPENCODE_DISABLE_AUTOUPDATE) return const latest = await Installation.latest().catch(() => {}) if (!latest) return if (Installation.VERSION === latest) return + + if (config.autoupdate === false || Flag.OPENCODE_DISABLE_AUTOUPDATE) { + await Bus.publish(Installation.Event.UpdateAvailable, { version: latest }) + return + } + const method = await Installation.method() if (method === "unknown") return await Installation.upgrade(method, latest) diff --git a/packages/opencode/src/installation/index.ts b/packages/opencode/src/installation/index.ts index f4209e5b8de..cfb590013c2 100644 --- a/packages/opencode/src/installation/index.ts +++ b/packages/opencode/src/installation/index.ts @@ -22,6 +22,12 @@ export namespace Installation { version: z.string(), }), ), + UpdateAvailable: Bus.event( + "installation.update-available", + z.object({ + version: z.string(), + }), + ), } export const Info = z diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index 4c1cb33fbea..e2e611db13a 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -7,6 +7,13 @@ export type EventInstallationUpdated = { } } +export type EventInstallationUpdateAvailable = { + type: "installation.update-available" + properties: { + version: string + } +} + export type EventLspClientDiagnostics = { type: "lsp.client.diagnostics" properties: { @@ -642,6 +649,7 @@ export type EventFileWatcherUpdated = { export type Event = | EventInstallationUpdated + | EventInstallationUpdateAvailable | EventLspClientDiagnostics | EventLspUpdated | EventMessageUpdated