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
This commit is contained in:
Dax Raad
2026-01-31 14:42:36 -05:00
parent da7c874808
commit e70d984320
3 changed files with 27 additions and 5 deletions

View File

@@ -104,6 +104,7 @@ export function tui(input: {
args: Args args: Args
directory?: string directory?: string
fetch?: typeof fetch fetch?: typeof fetch
headers?: RequestInit["headers"]
events?: EventSource events?: EventSource
onExit?: () => Promise<void> onExit?: () => Promise<void>
}) { }) {
@@ -130,6 +131,7 @@ export function tui(input: {
url={input.url} url={input.url}
directory={input.directory} directory={input.directory}
fetch={input.fetch} fetch={input.fetch}
headers={input.headers}
events={input.events} events={input.events}
> >
<SyncProvider> <SyncProvider>

View File

@@ -19,21 +19,34 @@ export const AttachCommand = cmd({
alias: ["s"], alias: ["s"],
type: "string", type: "string",
describe: "session id to continue", describe: "session id to continue",
})
.option("password", {
alias: ["p"],
type: "string",
describe: "basic auth password (defaults to OPENCODE_SERVER_PASSWORD)",
}), }),
handler: async (args) => { handler: async (args) => {
let directory = args.dir const directory = (() => {
if (args.dir) { if (!args.dir) return undefined
try { try {
process.chdir(args.dir) process.chdir(args.dir)
directory = process.cwd() return process.cwd()
} catch { } catch {
// If the directory doesn't exist locally (remote attach), pass it through. // 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({ await tui({
url: args.url, url: args.url,
args: { sessionID: args.session }, args: { sessionID: args.session },
directory, directory,
headers,
}) })
}, },
}) })

View File

@@ -9,13 +9,20 @@ export type EventSource = {
export const { use: useSDK, provider: SDKProvider } = createSimpleContext({ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
name: "SDK", 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 abort = new AbortController()
const sdk = createOpencodeClient({ const sdk = createOpencodeClient({
baseUrl: props.url, baseUrl: props.url,
signal: abort.signal, signal: abort.signal,
directory: props.directory, directory: props.directory,
fetch: props.fetch, fetch: props.fetch,
headers: props.headers,
}) })
const emitter = createGlobalEmitter<{ const emitter = createGlobalEmitter<{