Skip to content
Merged
9 changes: 9 additions & 0 deletions packages/opencode/src/cli/cmd/tui/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<box
width={dimensions().width}
Expand Down
9 changes: 8 additions & 1 deletion packages/opencode/src/cli/cmd/tui/thread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ export const TuiThreadCommand = cmd({
if (!args.prompt) return piped
return piped ? piped + "\n" + args.prompt : args.prompt
})
await tui({

const tuiPromise = tui({
url: server.url,
args: {
continue: args.continue,
Expand All @@ -112,5 +113,11 @@ export const TuiThreadCommand = cmd({
await client.call("shutdown", undefined)
},
})

setTimeout(() => {
client.call("checkUpgrade", { directory: cwd }).catch(() => {})
}, 1000)

await tuiPromise
},
})
10 changes: 8 additions & 2 deletions packages/opencode/src/cli/cmd/tui/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ process.on("uncaughtException", (e) => {
})
})

upgrade()

let server: Bun.Server<undefined>
export const rpc = {
async server(input: { port: number; hostname: string }) {
Expand All @@ -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()
Expand Down
7 changes: 6 additions & 1 deletion packages/opencode/src/cli/upgrade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions packages/opencode/src/installation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions packages/sdk/js/src/gen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -642,6 +649,7 @@ export type EventFileWatcherUpdated = {

export type Event =
| EventInstallationUpdated
| EventInstallationUpdateAvailable
| EventLspClientDiagnostics
| EventLspUpdated
| EventMessageUpdated
Expand Down