@opencode-ai/client
Advanced tools
@@ -15,2 +15,16 @@ import { Effect, FileSystem, Schema } from "effect"; | ||
| } | undefined, never, FileSystem.FileSystem>; | ||
| /** Recognize an authenticated compatible service bound to an expected URL, including while it starts or fails. */ | ||
| export declare const incumbent: (options: DiscoverOptions & { | ||
| readonly url: string; | ||
| }) => Effect.Effect<{ | ||
| endpoint: { | ||
| url: string; | ||
| auth: { | ||
| type: "basic"; | ||
| username: string; | ||
| password: string; | ||
| } | undefined; | ||
| }; | ||
| state: "failed" | "ready" | "waiting"; | ||
| } | undefined, never, FileSystem.FileSystem>; | ||
| /** Ensure a healthy, compatible local service is running. */ | ||
@@ -31,2 +45,3 @@ export declare const ensure: (options?: EnsureOptions | undefined) => Effect.Effect<Endpoint, Error, FileSystem.FileSystem>; | ||
| readonly password: Schema.optional<Schema.String>; | ||
| readonly startedAt: Schema.optional<Schema.Int>; | ||
| }>; | ||
@@ -43,2 +58,15 @@ /** Effect-based local service lifecycle operations. */ | ||
| } | undefined, never, FileSystem.FileSystem>; | ||
| incumbent: (options: DiscoverOptions & { | ||
| readonly url: string; | ||
| }) => Effect.Effect<{ | ||
| endpoint: { | ||
| url: string; | ||
| auth: { | ||
| type: "basic"; | ||
| username: string; | ||
| password: string; | ||
| } | undefined; | ||
| }; | ||
| state: "failed" | "ready" | "waiting"; | ||
| } | undefined, never, FileSystem.FileSystem>; | ||
| ensure: (options?: EnsureOptions | undefined) => Effect.Effect<Endpoint, Error, FileSystem.FileSystem>; | ||
@@ -53,3 +81,4 @@ stop: (options?: StopOptions | undefined) => Effect.Effect<void, Error, FileSystem.FileSystem>; | ||
| readonly password: Schema.optional<Schema.String>; | ||
| readonly startedAt: Schema.optional<Schema.Int>; | ||
| }>; | ||
| }; |
@@ -13,2 +13,12 @@ import { ServiceStatus } from "@opencode-ai/protocol/groups/health"; | ||
| }); | ||
| /** Recognize an authenticated compatible service bound to an expected URL, including while it starts or fails. */ | ||
| export const incumbent = Effect.fn("service.incumbent")(function* (options) { | ||
| const info = yield* read(options.file); | ||
| const found = info === undefined ? undefined : yield* probe({ ...info, url: options.url }); | ||
| if (found === undefined || found.legacy) | ||
| return undefined; | ||
| if (options.version !== undefined && found.version !== options.version) | ||
| return undefined; | ||
| return { endpoint: found.endpoint, state: found.state }; | ||
| }); | ||
| const discoverLocal = Effect.fnUntraced(function* (options) { | ||
@@ -92,4 +102,9 @@ const found = (yield* registered(options.file)).service; | ||
| return Option.none(); | ||
| }).pipe(Effect.repeat({ until: Option.isSome, schedule: Schedule.spaced("1 second") })); | ||
| return Option.getOrThrow(found).endpoint; | ||
| }).pipe(Effect.repeat({ | ||
| until: Option.isSome, | ||
| schedule: Schedule.max([Schedule.spaced("1 second"), Schedule.recurs(120)]), | ||
| })); | ||
| if (Option.isNone(found)) | ||
| return yield* Effect.fail(new Error("Timed out waiting for the background service to start")); | ||
| return found.value.endpoint; | ||
| }); | ||
@@ -132,2 +147,3 @@ function contenderFailure(contender) { | ||
| password: Schema.optional(Schema.String), | ||
| startedAt: Schema.optional(Schema.Int.check(Schema.isGreaterThan(0))), | ||
| }); | ||
@@ -244,2 +260,2 @@ const decode = Schema.decodeUnknownEffect(Schema.fromJsonString(Info)); | ||
| /** Effect-based local service lifecycle operations. */ | ||
| export const Service = { discover, ensure, stop, headers, Info }; | ||
| export const Service = { discover, incumbent, ensure, stop, headers, Info }; |
@@ -20,2 +20,3 @@ import { readFile } from "node:fs/promises"; | ||
| export async function ensure(options = {}) { | ||
| const deadline = Date.now() + 120_000; | ||
| const contenders = new Set(); | ||
@@ -50,2 +51,4 @@ let announced = false; | ||
| while (true) { | ||
| if (Date.now() >= deadline) | ||
| throw new Error("Timed out waiting for the background service to start"); | ||
| const registration = await registered(options.file, true); | ||
@@ -115,3 +118,5 @@ if (registration.service !== undefined) { | ||
| return undefined; | ||
| return { authorization: "Basic " + Buffer.from(endpoint.auth.username + ":" + endpoint.auth.password).toString("base64") }; | ||
| return { | ||
| authorization: "Basic " + Buffer.from(endpoint.auth.username + ":" + endpoint.auth.password).toString("base64"), | ||
| }; | ||
| } | ||
@@ -118,0 +123,0 @@ async function read(file) { |
@@ -48,2 +48,4 @@ /** Connection details for a local OpenCode service. */ | ||
| readonly password?: string; | ||
| /** Registration generation used to resolve owner write races. */ | ||
| readonly startedAt?: number; | ||
| }; |
+4
-4
| { | ||
| "$schema": "https://json.schemastore.org/package.json", | ||
| "name": "@opencode-ai/client", | ||
| "version": "0.0.0-next-15772", | ||
| "version": "0.0.0-next-15778", | ||
| "type": "module", | ||
@@ -56,4 +56,4 @@ "license": "MIT", | ||
| "dependencies": { | ||
| "@opencode-ai/schema": "0.0.0-next-15772", | ||
| "@opencode-ai/protocol": "0.0.0-next-15772" | ||
| "@opencode-ai/schema": "0.0.0-next-15778", | ||
| "@opencode-ai/protocol": "0.0.0-next-15778" | ||
| }, | ||
@@ -70,3 +70,3 @@ "peerDependencies": { | ||
| "@effect/platform-node": "4.0.0-beta.98", | ||
| "@opencode-ai/httpapi-codegen": "0.0.0-next-15772", | ||
| "@opencode-ai/httpapi-codegen": "0.0.0-next-15778", | ||
| "@tsconfig/bun": "1.0.9", | ||
@@ -73,0 +73,0 @@ "@types/bun": "1.3.13", |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
977915
0.22%19057
0.27%+ Added
+ Added
- Removed
- Removed