refactor(client): rename service start to ensure

This commit is contained in:
Dax Raad 2026-07-15 13:34:32 -04:00
commit ec8ee60e0b
17 changed files with 79 additions and 64 deletions

View file

@ -35,7 +35,7 @@ const login = Effect.fn("cli.console.login.run")(function* (timeline: TimelineHo
yield* request(() => timeline.intro("Log in"))
yield* request(() => timeline.pending("Connecting to OpenCode..."))
const endpoint = yield* Service.start(yield* ServiceConfig.options())
const endpoint = yield* Service.ensure(yield* ServiceConfig.options())
const client = OpenCode.make({ baseUrl: endpoint.url, headers: Service.headers(endpoint) })
const found = yield* request((signal) => client.integration.get({ integrationID, location }, { signal }))
const integration = yield* required(found.data, "OpenCode Console integration is unavailable")

View file

@ -11,7 +11,7 @@ export default Runtime.handler(
Effect.fn("cli.debug.agents")(function* () {
const options = yield* ServiceConfig.options()
const found = yield* Service.discover(options)
const endpoint = found ?? (yield* Service.start(options))
const endpoint = found ?? (yield* Service.ensure(options))
const client = OpenCode.make({ baseUrl: endpoint.url, headers: Service.headers(endpoint) })
const response = yield* Effect.promise(() => client.agent.list({ location: { directory: process.cwd() } }))
process.stdout.write(

View file

@ -19,7 +19,7 @@ export default Runtime.handler(
Effect.fn("cli.mcp.auth")(function* (input) {
const options = yield* ServiceConfig.options()
const found = yield* Service.discover(options)
const endpoint = found ?? (yield* Service.start(options))
const endpoint = found ?? (yield* Service.ensure(options))
const client = OpenCode.make({ baseUrl: endpoint.url, headers: Service.headers(endpoint) })
const integration = yield* resolveIntegration(client, input.name, location)

View file

@ -11,7 +11,7 @@ export default Runtime.handler(
Effect.fn("cli.mcp.list")(function* () {
const options = yield* ServiceConfig.options()
const found = yield* Service.discover(options)
const endpoint = found ?? (yield* Service.start(options))
const endpoint = found ?? (yield* Service.ensure(options))
const client = OpenCode.make({ baseUrl: endpoint.url, headers: Service.headers(endpoint) })
const response = yield* Effect.promise(() => client.mcp.list({ location: { directory: process.cwd() } }))
const servers = response.data.toSorted((a, b) => a.name.localeCompare(b.name))

View file

@ -14,7 +14,7 @@ export default Runtime.handler(
Effect.fn("cli.mcp.logout")(function* (input) {
const options = yield* ServiceConfig.options()
const found = yield* Service.discover(options)
const endpoint = found ?? (yield* Service.start(options))
const endpoint = found ?? (yield* Service.ensure(options))
const client = OpenCode.make({ baseUrl: endpoint.url, headers: Service.headers(endpoint) })
const integration = yield* resolveIntegration(client, input.name, location)

View file

@ -10,7 +10,7 @@ import { ServiceConfig } from "../../services/service-config"
export default Runtime.handler(
Commands.commands.pair,
Effect.fn("cli.pair")(function* () {
const endpoint = yield* Service.start(yield* ServiceConfig.options())
const endpoint = yield* Service.ensure(yield* ServiceConfig.options())
const password = yield* ServiceConfig.password()
const server = yield* Effect.tryPromise(() =>
OpenCode.make({ baseUrl: endpoint.url, headers: Service.headers(endpoint) }).server.get(),

View file

@ -10,7 +10,7 @@ export default Runtime.handler(
Effect.fn("cli.service.restart")(function* () {
const options = yield* ServiceConfig.options()
yield* Service.stop(options)
const transport = yield* Service.start(options)
const transport = yield* Service.ensure(options)
process.stdout.write(transport.url + EOL)
}),
)

View file

@ -8,7 +8,7 @@ import { ServiceConfig } from "../../../services/service-config"
export default Runtime.handler(
Commands.commands.service.commands.start,
Effect.fn("cli.service.start")(function* () {
const transport = yield* Service.start(yield* ServiceConfig.options())
const transport = yield* Service.ensure(yield* ServiceConfig.options())
process.stdout.write(transport.url + EOL)
}),
)

View file

@ -1,4 +1,4 @@
import { Service, type Endpoint, type StartOptions } from "@opencode-ai/client/effect/service"
import { Service, type Endpoint, type EnsureOptions } from "@opencode-ai/client/effect/service"
import { ClientError, isUnauthorizedError, OpenCode } from "@opencode-ai/client/promise"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import { Effect, Redacted } from "effect"
@ -10,7 +10,7 @@ export type Args = {
readonly server?: string
readonly standalone?: boolean
readonly mismatch?: "replace" | "ignore" | "error"
readonly onStart?: StartOptions["onStart"]
readonly onStart?: EnsureOptions["onStart"]
}
export type Resolved = {
@ -49,31 +49,31 @@ export const resolve = Effect.fn("cli.server-connection.resolve")(function* (arg
} satisfies Resolved
})
function managedService(options: StartOptions) {
function managedService(options: EnsureOptions) {
const reconnectOptions = { ...options, version: undefined }
return {
reconnect: () => Service.start(reconnectOptions),
reconnect: () => Service.ensure(reconnectOptions),
restart: () =>
Effect.gen(function* () {
yield* Service.stop(options)
yield* Service.start(options)
yield* Service.ensure(options)
}),
}
}
const resolveManaged = Effect.fnUntraced(function* (
options: StartOptions,
options: EnsureOptions,
mismatch: NonNullable<Args["mismatch"]>,
) {
if (mismatch === "replace") return yield* Service.start(options)
if (mismatch === "ignore") return yield* Service.start({ ...options, version: undefined })
if (mismatch === "replace") return yield* Service.ensure(options)
if (mismatch === "ignore") return yield* Service.ensure({ ...options, version: undefined })
const compatible = yield* Service.discover(options)
if (compatible !== undefined) return compatible
const existing = yield* Service.discover({ ...options, version: undefined })
if (existing !== undefined)
return yield* Effect.fail(new Error("Background server version does not match this client"))
return yield* Service.start(options)
return yield* Service.ensure(options)
})
function connectError(endpoint: Endpoint, cause: unknown) {

View file

@ -6,7 +6,7 @@ import { Effect, FileSystem, Option, Schema } from "effect"
import { randomBytes } from "crypto"
import path from "path"
// The CLI's service configuration file, plus the Service.StartOptions binding that
// The CLI's service configuration file, plus the Service.EnsureOptions binding that
// points the client package's service operations at this CLI: which
// registration file (by channel), which version, and how to spawn opencode.