41 lines
1.5 KiB
TypeScript
41 lines
1.5 KiB
TypeScript
export * as Status from "./service-status"
|
|
|
|
import { ServiceStatus } from "@opencode-ai/protocol/groups/health"
|
|
import { Effect, Ref } from "effect"
|
|
|
|
export type State =
|
|
| { readonly type: "starting" }
|
|
| { readonly type: "ready" }
|
|
| { readonly type: "stopping" }
|
|
| { readonly type: "failed" }
|
|
|
|
export interface Interface {
|
|
readonly current: Effect.Effect<State>
|
|
readonly ready: Effect.Effect<void>
|
|
readonly fail: Effect.Effect<void>
|
|
readonly beginStopping: Effect.Effect<void>
|
|
readonly requestStop: (request: ServiceStatus.StopRequest) => Effect.Effect<boolean>
|
|
}
|
|
|
|
export const make = Effect.fnUntraced(function* (options: {
|
|
readonly instanceID: string
|
|
readonly managed: boolean
|
|
readonly initial?: State
|
|
}) {
|
|
const current = yield* Ref.make(options.initial ?? ({ type: "starting" } satisfies State))
|
|
const beginStopping = Ref.update(current, (status) =>
|
|
status.type === "stopping" ? status : ({ type: "stopping" } satisfies State),
|
|
)
|
|
|
|
return {
|
|
current: Ref.get(current),
|
|
ready: Ref.update(current, (status) => (status.type === "starting" ? ({ type: "ready" } satisfies State) : status)),
|
|
fail: Ref.update(current, (status) => (status.type === "starting" ? ({ type: "failed" } satisfies State) : status)),
|
|
beginStopping,
|
|
requestStop: (request) => {
|
|
if (!options.managed || request.instanceID !== options.instanceID) return Effect.succeed(false)
|
|
return beginStopping.pipe(Effect.as(true))
|
|
},
|
|
} satisfies Interface
|
|
})
|