mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-21 10:23:30 +00:00
refactor(cli): manage environment variables with effect config
This commit is contained in:
parent
c22793d5f6
commit
24d26365e6
3 changed files with 32 additions and 6 deletions
|
|
@ -1,8 +1,9 @@
|
|||
import { NodeFileSystem } from "@effect/platform-node"
|
||||
import { Commands } from "../commands"
|
||||
import { Runtime } from "../../framework/runtime"
|
||||
import { Effect, Option } from "effect"
|
||||
import { Effect, Option, Redacted } from "effect"
|
||||
import { Service } from "@opencode-ai/client/effect"
|
||||
import { Env } from "../../env"
|
||||
import { ServiceConfig } from "../../services/service-config"
|
||||
import { Standalone } from "../../services/standalone"
|
||||
import { Updater } from "../../services/updater"
|
||||
|
|
@ -18,10 +19,12 @@ 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 = process.env["OPENCODE_PASSWORD"]
|
||||
const password = Option.getOrUndefined(yield* Env.password)
|
||||
const explicit = {
|
||||
url: server,
|
||||
headers: password ? { authorization: "Basic " + btoa("opencode:" + password) } : undefined,
|
||||
headers: password
|
||||
? { authorization: "Basic " + btoa("opencode:" + Redacted.value(password)) }
|
||||
: undefined,
|
||||
} satisfies Service.Transport
|
||||
// Fail loudly before entering the TUI: an explicit server that is
|
||||
// unreachable or rejects auth should not present as reconnect churn.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
|||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||
import { PermissionSaved } from "@opencode-ai/core/permission/saved"
|
||||
import { Global } from "@opencode-ai/core/global"
|
||||
import { Context, FileSystem, Layer, Option, Schedule, Schema } from "effect"
|
||||
import { Context, FileSystem, Layer, Option, Redacted, Schedule, Schema } from "effect"
|
||||
import * as Effect from "effect/Effect"
|
||||
import { HttpRouter, HttpServer } from "effect/unstable/http"
|
||||
import { createServer } from "node:http"
|
||||
|
|
@ -15,6 +15,7 @@ import { createOpencodeClient } from "@opencode-ai/sdk/v2/client"
|
|||
import { Commands } from "../commands"
|
||||
import { Runtime } from "../../framework/runtime"
|
||||
import { Service } from "@opencode-ai/client/effect"
|
||||
import { Env } from "../../env"
|
||||
import { ServiceConfig } from "../../services/service-config"
|
||||
import { Updater } from "../../services/updater"
|
||||
import { randomBytes, randomUUID } from "crypto"
|
||||
|
|
@ -26,12 +27,16 @@ export default Runtime.handler(
|
|||
if (input.service) yield* Effect.sync(() => process.chdir(Global.Path.home))
|
||||
return yield* Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
const standalonePassword = process.env.OPENCODE_SERVER_PASSWORD
|
||||
const standalonePassword = Option.getOrUndefined(yield* Env.serverPassword)
|
||||
// Keep the lease credential out of the environment inherited by any
|
||||
// process this server spawns.
|
||||
if (input.stdio) delete process.env.OPENCODE_SERVER_PASSWORD
|
||||
const config = input.service ? yield* ServiceConfig.read() : {}
|
||||
const password = input.service
|
||||
? yield* ServiceConfig.password()
|
||||
: standalonePassword || randomBytes(32).toString("base64url")
|
||||
: standalonePassword
|
||||
? Redacted.value(standalonePassword)
|
||||
: randomBytes(32).toString("base64url")
|
||||
if (!password) return yield* Effect.fail(new Error("Missing server password"))
|
||||
const hostname = Option.getOrUndefined(input.hostname) ?? config.hostname ?? "127.0.0.1"
|
||||
const port = Option.isSome(input.port)
|
||||
|
|
|
|||
18
packages/cli/src/env.ts
Normal file
18
packages/cli/src/env.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { Config } from "effect"
|
||||
|
||||
// Every environment variable the CLI reads, in one place. Consumers yield
|
||||
// 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.
|
||||
export const password = Config.redacted("OPENCODE_PASSWORD").pipe(
|
||||
Config.orElse(() => Config.redacted("OPENCODE_SERVER_PASSWORD")),
|
||||
Config.option,
|
||||
)
|
||||
|
||||
// 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"
|
||||
Loading…
Add table
Add a link
Reference in a new issue