From bf60b53f515b284d10ab6974018d961c15c6ee5a Mon Sep 17 00:00:00 2001 From: Owen <33508519+lxxonx@users.noreply.github.com> Date: Fri, 16 Jan 2026 18:20:40 +0900 Subject: [PATCH 1/2] fix(tui): show warning when opening WebUI without server mode When OpenCode runs without --port flag, it uses internal RPC communication with 'opencode.internal' as a placeholder URL. The 'Open WebUI' command was trying to open this non-resolvable URL in the browser, which fails silently. This change adds a check for the internal URL and shows a helpful warning toast explaining how to enable server mode instead. --- packages/opencode/src/cli/cmd/tui/app.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 1fea3f4b305..d145547239a 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -465,6 +465,15 @@ function App() { title: "Open WebUI", value: "webui.open", onSelect: () => { + if (sdk.url.includes("opencode.internal")) { + toast.show({ + variant: "warning", + message: "WebUI requires server mode. Restart with: opencode --port 4096", + duration: 5000, + }) + dialog.clear() + return + } open(sdk.url).catch(() => {}) dialog.clear() }, From 4b8ae9298e4c9fc093596ec1bcd6ffb27268afd8 Mon Sep 17 00:00:00 2001 From: lxxonx Date: Sat, 17 Jan 2026 12:26:21 +0900 Subject: [PATCH 2/2] feat(tui): start server on-demand when opening WebUI Instead of showing a warning when WebUI is requested without server mode, automatically start the server and open the actual WebUI page. --- packages/opencode/src/cli/cmd/tui/app.tsx | 35 +++++++++++++++---- .../opencode/src/cli/cmd/tui/context/sdk.tsx | 10 ++++-- packages/opencode/src/cli/cmd/tui/thread.ts | 6 ++++ 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index d145547239a..ee389a0525a 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -105,6 +105,7 @@ export function tui(input: { directory?: string fetch?: typeof fetch events?: EventSource + startServer?: () => Promise onExit?: () => Promise }) { // promise to prevent immediate exit @@ -131,6 +132,7 @@ export function tui(input: { directory={input.directory} fetch={input.fetch} events={input.events} + startServer={input.startServer} > @@ -464,17 +466,36 @@ function App() { { title: "Open WebUI", value: "webui.open", - onSelect: () => { + onSelect: async () => { + let url = sdk.url if (sdk.url.includes("opencode.internal")) { + if (!sdk.startServer) { + toast.show({ + variant: "warning", + message: "WebUI requires server mode. Restart with: opencode --port 4096", + duration: 5000, + }) + dialog.clear() + return + } toast.show({ - variant: "warning", - message: "WebUI requires server mode. Restart with: opencode --port 4096", - duration: 5000, + variant: "info", + message: "Starting server...", + duration: 2000, }) - dialog.clear() - return + try { + url = await sdk.startServer() + } catch (e) { + toast.show({ + variant: "error", + message: "Failed to start server", + duration: 3000, + }) + dialog.clear() + return + } } - open(sdk.url).catch(() => {}) + open(url).catch(() => {}) dialog.clear() }, category: "System", diff --git a/packages/opencode/src/cli/cmd/tui/context/sdk.tsx b/packages/opencode/src/cli/cmd/tui/context/sdk.tsx index 3339e7b00d2..549fd336678 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sdk.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sdk.tsx @@ -9,7 +9,13 @@ export type EventSource = { export const { use: useSDK, provider: SDKProvider } = createSimpleContext({ name: "SDK", - init: (props: { url: string; directory?: string; fetch?: typeof fetch; events?: EventSource }) => { + init: (props: { + url: string + directory?: string + fetch?: typeof fetch + events?: EventSource + startServer?: () => Promise + }) => { const abort = new AbortController() const sdk = createOpencodeClient({ baseUrl: props.url, @@ -89,6 +95,6 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({ if (timer) clearTimeout(timer) }) - return { client: sdk, event: emitter, url: props.url } + return { client: sdk, event: emitter, url: props.url, startServer: props.startServer } }, }) diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index 05714268545..3e51f391f28 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -151,6 +151,12 @@ export const TuiThreadCommand = cmd({ model: args.model, prompt, }, + startServer: shouldStartServer + ? undefined + : async () => { + const server = await client.call("server", networkOpts) + return server.url + }, onExit: async () => { await client.call("shutdown", undefined) },