mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-31 05:15:32 +00:00
refactor(cli): scope server discovery to CLI
This commit is contained in:
parent
13822b9424
commit
26f64f29fb
4 changed files with 32 additions and 34 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { Effect } from "effect"
|
||||
import { Server } from "../../server/server"
|
||||
import { ServerDiscovery } from "@/server/discovery"
|
||||
import { ServerDiscovery } from "@/cli/server-discovery"
|
||||
import { effectCmd } from "../effect-cmd"
|
||||
import { withNetworkOptions, resolveNetworkOptions } from "../network"
|
||||
import { Flag } from "@opencode-ai/core/flag/flag"
|
||||
|
|
@ -17,26 +17,26 @@ export const ServeCommand = effectCmd({
|
|||
// 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}`)
|
||||
handler: (args) =>
|
||||
Effect.gen(function* () {
|
||||
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))
|
||||
const discovery = args.discoverable ? yield* ServerDiscovery.Service : undefined
|
||||
if (discovery) {
|
||||
yield* 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,
|
||||
),
|
||||
)
|
||||
}),
|
||||
yield* Effect.never.pipe(
|
||||
Effect.ensuring(
|
||||
discovery
|
||||
? discovery.remove().pipe(Effect.ensuring(Effect.sync(() => process.off("exit", ServerDiscovery.removeSync))))
|
||||
: Effect.void,
|
||||
),
|
||||
)
|
||||
}).pipe(Effect.provide(ServerDiscovery.defaultLayer)),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { withTimeout } from "@/util/timeout"
|
|||
import { withNetworkOptions, resolveNetworkOptionsNoConfig } from "@/cli/network"
|
||||
import { Filesystem } from "@/util/filesystem"
|
||||
import { ServerAuth } from "@/server/auth"
|
||||
import { ServerDiscovery } from "@/server/discovery"
|
||||
import { ServerDiscovery } from "@/cli/server-discovery"
|
||||
import type { GlobalEvent } from "@opencode-ai/sdk/v2"
|
||||
import type { EventSource } from "./context/sdk"
|
||||
import { win32DisableProcessedInput, win32InstallCtrlCGuard } from "./win32"
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
export * as ServerDiscovery from "./discovery"
|
||||
export * as ServerDiscovery from "./server-discovery"
|
||||
|
||||
import { ServerAuth } from "@/server/auth"
|
||||
import { makeRuntime } from "@/effect/run-service"
|
||||
import { ServerAuth } from "@/server/auth"
|
||||
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
||||
import { Global } from "@opencode-ai/core/global"
|
||||
import { Context, Effect, Layer, Option, Schema } from "effect"
|
||||
import path from "path"
|
||||
import { readFileSync, unlinkSync } from "fs"
|
||||
import path from "path"
|
||||
|
||||
export const file = path.join(Global.Path.state, "server.json")
|
||||
|
||||
|
|
@ -23,36 +23,36 @@ export interface Interface {
|
|||
readonly find: () => Effect.Effect<string | undefined>
|
||||
}
|
||||
|
||||
export class Service extends Context.Service<Service, Interface>()("@opencode/ServerDiscovery") {}
|
||||
export class Service extends Context.Service<Service, Interface>()("@opencode/CliServerDiscovery") {}
|
||||
|
||||
export const layer = Layer.effect(
|
||||
Service,
|
||||
Effect.gen(function* () {
|
||||
const fs = yield* AppFileSystem.Service
|
||||
|
||||
const read = Effect.fn("ServerDiscovery.read")(function* () {
|
||||
const read = Effect.fn("CliServerDiscovery.read")(function* () {
|
||||
const entry = yield* fs.readJson(file).pipe(Effect.catch(() => Effect.succeed(undefined)))
|
||||
return Option.getOrUndefined(decodeEntry(entry))
|
||||
})
|
||||
|
||||
const remove = Effect.fn("ServerDiscovery.remove")(function* () {
|
||||
const remove = Effect.fn("CliServerDiscovery.remove")(function* () {
|
||||
const entry = yield* read()
|
||||
if (entry?.pid !== process.pid) return
|
||||
yield* fs.remove(file).pipe(Effect.ignore)
|
||||
})
|
||||
|
||||
const removeStale = Effect.fn("ServerDiscovery.removeStale")(function* (entry: Entry) {
|
||||
const removeStale = Effect.fn("CliServerDiscovery.removeStale")(function* (entry: Entry) {
|
||||
const current = yield* read()
|
||||
if (current?.pid !== entry.pid || current.url !== entry.url) return
|
||||
yield* fs.remove(file).pipe(Effect.ignore)
|
||||
})
|
||||
|
||||
return Service.of({
|
||||
write: Effect.fn("ServerDiscovery.write")(function* (url) {
|
||||
write: Effect.fn("CliServerDiscovery.write")(function* (url) {
|
||||
yield* fs.writeJson(file, { url: localURL(url).toString(), pid: process.pid }, 0o600).pipe(Effect.orDie)
|
||||
}),
|
||||
remove,
|
||||
find: Effect.fn("ServerDiscovery.find")(function* () {
|
||||
find: Effect.fn("CliServerDiscovery.find")(function* () {
|
||||
const entry = yield* read()
|
||||
if (!entry) return undefined
|
||||
const url = yield* healthy(entry.url)
|
||||
|
|
@ -58,7 +58,6 @@ import { DataMigration } from "@/data-migration"
|
|||
import { BackgroundJob } from "@/background/job"
|
||||
import { EventV2Bridge } from "@/event-v2-bridge"
|
||||
import { RuntimeFlags } from "@/effect/runtime-flags"
|
||||
import { ServerDiscovery } from "@/server/discovery"
|
||||
|
||||
export const AppLayer = Layer.mergeAll(
|
||||
Npm.defaultLayer,
|
||||
|
|
@ -115,7 +114,6 @@ export const AppLayer = Layer.mergeAll(
|
|||
SyncEvent.defaultLayer,
|
||||
EventV2Bridge.defaultLayer,
|
||||
DataMigration.defaultLayer,
|
||||
ServerDiscovery.defaultLayer,
|
||||
).pipe(Layer.provideMerge(InstanceLayer.layer), Layer.provideMerge(Observability.layer))
|
||||
|
||||
const rt = ManagedRuntime.make(AppLayer, { memoMap })
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue