refactor(cli): single password config with legacy fallback

This commit is contained in:
Dax Raad
2026-07-03 13:41:15 -04:00
parent 24d26365e6
commit 08293e74a0
4 changed files with 13 additions and 11 deletions
@@ -19,7 +19,7 @@ export default Runtime.handler(Commands, (input) =>
return yield* Effect.fail(new Error("--server and --standalone cannot be combined"))
const transport = yield* Effect.gen(function* () {
if (server !== undefined) {
const password = Option.getOrUndefined(yield* Env.password)
const password = yield* Env.password
const explicit = {
url: server,
headers: password
+5 -2
View File
@@ -27,10 +27,13 @@ export default Runtime.handler(
if (input.service) yield* Effect.sync(() => process.chdir(Global.Path.home))
return yield* Effect.scoped(
Effect.gen(function* () {
const standalonePassword = Option.getOrUndefined(yield* Env.serverPassword)
const standalonePassword = yield* Env.password
// Keep the lease credential out of the environment inherited by any
// process this server spawns.
if (input.stdio) delete process.env.OPENCODE_SERVER_PASSWORD
if (input.stdio) {
delete process.env.OPENCODE_PASSWORD
delete process.env.OPENCODE_SERVER_PASSWORD
}
const config = input.service ? yield* ServiceConfig.read() : {}
const password = input.service
? yield* ServiceConfig.password()
+4 -7
View File
@@ -4,15 +4,12 @@ import { Config } from "effect"
// these instead of touching process.env so the full surface stays visible,
// typed, and redacted where secret.
// Client-side password for an explicit --server target. The legacy name is
// still honored; it also remains the variable a standalone child inherits.
// The opencode server password: sent by clients connecting to an explicit
// --server, and adopted by a manually run or standalone server. The legacy
// name is still honored.
export const password = Config.redacted("OPENCODE_PASSWORD").pipe(
Config.orElse(() => Config.redacted("OPENCODE_SERVER_PASSWORD")),
Config.option,
Config.withDefault(undefined),
)
// Server-side lease password: set by the standalone spawner for its child,
// or preset for a manually managed `opencode serve`.
export const serverPassword = Config.redacted("OPENCODE_SERVER_PASSWORD").pipe(Config.option)
export * as Env from "./env"
+3 -1
View File
@@ -15,7 +15,9 @@ function command(password: string) {
if (!compiled && entrypoint.length === 0) throw new Error("Failed to resolve CLI entrypoint")
return ChildProcess.make(process.execPath, [...entrypoint, "serve", "--stdio", "--port", "0"], {
cwd: process.cwd(),
env: { OPENCODE_SERVER_PASSWORD: password },
// Explicit entry wins over anything inherited, so a user-exported
// OPENCODE_PASSWORD cannot shadow the child's lease credential.
env: { OPENCODE_PASSWORD: password },
extendEnv: true,
// The server treats EOF on this pipe as the end of its ownership lease.
// The OS closes it even when the TUI is killed before Effect finalizers run.