diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index 7230dae16ae4..9176d606517b 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -3,6 +3,7 @@ import { Rpc } from "@/util/rpc" import { type rpc } from "./worker" import path from "path" import { fileURLToPath } from "url" +import { spawn } from "child_process" import { UI } from "@/cli/ui" import * as Log from "@opencode-ai/core/util/log" import { errorMessage } from "@/util/error" @@ -224,7 +225,17 @@ export const TuiThreadCommand = cmd({ } setTimeout(() => { - client.call("checkUpgrade", { directory: cwd }).catch(() => {}) + client.call("checkUpgrade", { directory: cwd }).then((upgraded: unknown) => { + if (upgraded) { + console.log("Update installed. Restarting...") + const child = spawn(process.execPath, process.argv.slice(1), { + stdio: "inherit", + env: process.env, + }) + child.unref() + process.exit(0) + } + }).catch(() => {}) }, 1000).unref?.() try { diff --git a/packages/opencode/src/cli/cmd/tui/worker.ts b/packages/opencode/src/cli/cmd/tui/worker.ts index 31ead18cf84f..734dc77e5232 100644 --- a/packages/opencode/src/cli/cmd/tui/worker.ts +++ b/packages/opencode/src/cli/cmd/tui/worker.ts @@ -77,7 +77,12 @@ export const rpc = { }, async checkUpgrade(input: { directory: string }) { await InstanceRuntime.load({ directory: input.directory }) - await upgrade().catch(() => {}) + const upgraded = await upgrade().catch(() => false) + if (upgraded) { + await InstanceRuntime.disposeAllInstances().catch(() => {}) + if (server) await server.stop(true).catch(() => {}) + } + return upgraded }, async reload() { await AppRuntime.runPromise( diff --git a/packages/opencode/src/cli/upgrade.ts b/packages/opencode/src/cli/upgrade.ts index 62b230a63364..62634e677574 100644 --- a/packages/opencode/src/cli/upgrade.ts +++ b/packages/opencode/src/cli/upgrade.ts @@ -5,12 +5,12 @@ import { Installation } from "@/installation" import { InstallationVersion } from "@opencode-ai/core/installation/version" import { GlobalBus } from "@/bus/global" -export async function upgrade() { +export async function upgrade(): Promise { const config = await AppRuntime.runPromise(Config.Service.use((cfg) => cfg.getGlobal())) - if (config.autoupdate === false || Flag.OPENCODE_DISABLE_AUTOUPDATE) return + if (config.autoupdate === false || Flag.OPENCODE_DISABLE_AUTOUPDATE) return false const method = await Installation.method() - const latest = await Installation.latest(method).catch(() => {}) - if (!latest) return + const latest = await Installation.latest(method).catch(() => undefined) + if (!latest) return false if (Flag.OPENCODE_ALWAYS_NOTIFY_UPDATE) { GlobalBus.emit("event", { @@ -20,10 +20,10 @@ export async function upgrade() { properties: { version: latest }, }, }) - return + return false } - if (InstallationVersion === latest) return + if (InstallationVersion === latest) return false const kind = Installation.getReleaseType(InstallationVersion, latest) @@ -35,19 +35,21 @@ export async function upgrade() { properties: { version: latest }, }, }) - return + return false } - if (method === "unknown") return - await Installation.upgrade(method, latest) - .then(() => + if (method === "unknown") return false + const upgraded = await Installation.upgrade(method, latest) + .then(() => { GlobalBus.emit("event", { directory: "global", payload: { type: Installation.Event.Updated.type, properties: { version: latest }, }, - }), - ) - .catch(() => {}) + }) + return true + }) + .catch(() => false) + return upgraded } diff --git a/packages/opencode/test/cli/upgrade.test.ts b/packages/opencode/test/cli/upgrade.test.ts new file mode 100644 index 000000000000..c163c4d39a80 --- /dev/null +++ b/packages/opencode/test/cli/upgrade.test.ts @@ -0,0 +1,12 @@ +import { describe, expect, test } from "bun:test" +import { Installation } from "@/installation" + +describe("upgrade", () => { + test("Installation.Event.Updated type matches expected value", () => { + expect(Installation.Event.Updated.type).toBe("installation.updated") + }) + + test("Installation.Event.UpdateAvailable type matches expected value", () => { + expect(Installation.Event.UpdateAvailable.type).toBe("installation.update-available") + }) +})