cloudaxe-opencode/packages/opencode/src/cli/cmd/serve.ts
2026-05-15 20:25:59 -04:00

42 lines
1.6 KiB
TypeScript

import { Effect } from "effect"
import { Server } from "../../server/server"
import { ServerDiscovery } from "@/server/discovery"
import { effectCmd } from "../effect-cmd"
import { withNetworkOptions, resolveNetworkOptions } from "../network"
import { Flag } from "@opencode-ai/core/flag/flag"
export const ServeCommand = effectCmd({
command: "serve",
builder: (yargs) =>
withNetworkOptions(yargs).option("discoverable", {
type: "boolean",
describe: "write this server to the local discovery file for default TUI startup",
default: false,
}),
describe: "starts a headless opencode server",
// Server loads instances per-request via x-opencode-directory header — no
// need for an ambient project InstanceContext at startup.
instance: false,
handler: Effect.fn("Cli.serve")(function* (args) {
if (!Flag.OPENCODE_SERVER_PASSWORD) {
console.log("Warning: OPENCODE_SERVER_PASSWORD is not set; server is unsecured.")
}
const opts = yield* resolveNetworkOptions(args)
const server = yield* Effect.promise(() => Server.listen(opts))
if (args.discoverable) {
yield* ServerDiscovery.Service.use((discovery) => discovery.write(server.url))
process.on("exit", ServerDiscovery.removeSync)
}
console.log(`opencode server listening on http://${server.hostname}:${server.port}`)
yield* Effect.never.pipe(
Effect.ensuring(
args.discoverable
? ServerDiscovery.Service.use((discovery) => discovery.remove()).pipe(
Effect.ensuring(Effect.sync(() => process.off("exit", ServerDiscovery.removeSync))),
)
: Effect.void,
),
)
}),
})