From e70d984320571597f89421d85c2f74009951027c Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Sat, 31 Jan 2026 14:42:36 -0500 Subject: [PATCH] tui: enable password authentication for remote session attachment Allow users to authenticate when attaching to a remote OpenCode session by supporting basic auth via a password flag or OPENCODE_SERVER_PASSWORD environment variable --- packages/opencode/src/cli/cmd/tui/app.tsx | 2 ++ packages/opencode/src/cli/cmd/tui/attach.ts | 21 +++++++++++++++---- .../opencode/src/cli/cmd/tui/context/sdk.tsx | 9 +++++++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 10d7a25f8..713def2e5 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -104,6 +104,7 @@ export function tui(input: { args: Args directory?: string fetch?: typeof fetch + headers?: RequestInit["headers"] events?: EventSource onExit?: () => Promise }) { @@ -130,6 +131,7 @@ export function tui(input: { url={input.url} directory={input.directory} fetch={input.fetch} + headers={input.headers} events={input.events} > diff --git a/packages/opencode/src/cli/cmd/tui/attach.ts b/packages/opencode/src/cli/cmd/tui/attach.ts index f641ff098..e852cb73d 100644 --- a/packages/opencode/src/cli/cmd/tui/attach.ts +++ b/packages/opencode/src/cli/cmd/tui/attach.ts @@ -19,21 +19,34 @@ export const AttachCommand = cmd({ alias: ["s"], type: "string", describe: "session id to continue", + }) + .option("password", { + alias: ["p"], + type: "string", + describe: "basic auth password (defaults to OPENCODE_SERVER_PASSWORD)", }), handler: async (args) => { - let directory = args.dir - if (args.dir) { + const directory = (() => { + if (!args.dir) return undefined try { process.chdir(args.dir) - directory = process.cwd() + return process.cwd() } catch { // If the directory doesn't exist locally (remote attach), pass it through. + return args.dir } - } + })() + const headers = (() => { + const password = args.password ?? process.env.OPENCODE_SERVER_PASSWORD + if (!password) return undefined + const auth = `Basic ${Buffer.from(`opencode:${password}`).toString("base64")}` + return { Authorization: auth } + })() await tui({ url: args.url, args: { sessionID: args.session }, directory, + headers, }) }, }) diff --git a/packages/opencode/src/cli/cmd/tui/context/sdk.tsx b/packages/opencode/src/cli/cmd/tui/context/sdk.tsx index 3339e7b00..7fa7e05c3 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sdk.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sdk.tsx @@ -9,13 +9,20 @@ 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 + headers?: RequestInit["headers"] + events?: EventSource + }) => { const abort = new AbortController() const sdk = createOpencodeClient({ baseUrl: props.url, signal: abort.signal, directory: props.directory, fetch: props.fetch, + headers: props.headers, }) const emitter = createGlobalEmitter<{