@opencode/client 0.0.0-dev-19564 → 0.0.0-dev-19566
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/effect/api/api.d.ts +1 -1
- package/dist/effect/client.d.ts +1 -1
- package/dist/effect/generated/client.d.ts +1 -1
- package/dist/effect/service.js +27 -4
- package/dist/promise/generated/client.js +1 -1
- package/dist/promise/generated/types.d.ts +7 -1
- package/dist/promise/generated/types.js +1 -0
- package/dist/promise/service.js +32 -7
- package/package.json +4 -4
package/dist/effect/api/api.d.ts
CHANGED
|
@@ -1710,7 +1710,7 @@ export type IntegrationGetInput = {
|
|
|
1710
1710
|
};
|
|
1711
1711
|
export type IntegrationGetOutput = {
|
|
1712
1712
|
readonly location: Location.PublicRef;
|
|
1713
|
-
readonly data: Integration.Info
|
|
1713
|
+
readonly data: Integration.Info;
|
|
1714
1714
|
};
|
|
1715
1715
|
export type IntegrationGetOperation<E = never> = (input: IntegrationGetInput) => Effect.Effect<IntegrationGetOutput, E>;
|
|
1716
1716
|
export type IntegrationWellknownAddInput = {
|
package/dist/effect/client.d.ts
CHANGED
|
@@ -2299,7 +2299,7 @@ export declare const make: (options?: {
|
|
|
2299
2299
|
};
|
|
2300
2300
|
integration: {
|
|
2301
2301
|
list: (input?: import("./api.js").IntegrationListInput) => Effect.Effect<import("./api.js").IntegrationListOutput, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | import("effect/Schema").SchemaError | ClientError | import("effect/unstable/http/HttpClientError").HttpClientError, never>;
|
|
2302
|
-
get: (input: import("./api.js").IntegrationGetInput) => Effect.Effect<import("./api.js").IntegrationGetOutput, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | import("effect/Schema").SchemaError | ClientError | import("effect/unstable/http/HttpClientError").HttpClientError, never>;
|
|
2302
|
+
get: (input: import("./api.js").IntegrationGetInput) => Effect.Effect<import("./api.js").IntegrationGetOutput, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | import("@opencode/protocol/errors").IntegrationNotFoundError | import("effect/Schema").SchemaError | ClientError | import("effect/unstable/http/HttpClientError").HttpClientError, never>;
|
|
2303
2303
|
wellknown: {
|
|
2304
2304
|
add: (input: import("./api.js").IntegrationWellknownAddInput) => Effect.Effect<void, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | import("effect/Schema").SchemaError | ClientError | import("effect/unstable/http/HttpClientError").HttpClientError, never>;
|
|
2305
2305
|
};
|
|
@@ -86,7 +86,7 @@ export declare const make: (options?: {
|
|
|
86
86
|
};
|
|
87
87
|
integration: {
|
|
88
88
|
list: (input?: IntegrationListInput) => Effect.Effect<IntegrationListOutput, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | Schema.SchemaError | ClientError | HttpClientError.HttpClientError, never>;
|
|
89
|
-
get: (input: IntegrationGetInput) => Effect.Effect<IntegrationGetOutput, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | Schema.SchemaError | ClientError | HttpClientError.HttpClientError, never>;
|
|
89
|
+
get: (input: IntegrationGetInput) => Effect.Effect<IntegrationGetOutput, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | import("@opencode/protocol/errors").IntegrationNotFoundError | Schema.SchemaError | ClientError | HttpClientError.HttpClientError, never>;
|
|
90
90
|
wellknown: {
|
|
91
91
|
add: (input: IntegrationWellknownAddInput) => Effect.Effect<void, import("@opencode/protocol/errors").InvalidRequestError | import("@opencode/protocol/errors").UnauthorizedError | Schema.SchemaError | ClientError | HttpClientError.HttpClientError, never>;
|
|
92
92
|
};
|
package/dist/effect/service.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ServerStatus } from "@opencode/protocol/groups/server";
|
|
2
1
|
import { Effect, FileSystem, Option, Schedule, Schema } from "effect";
|
|
3
2
|
import { homedir } from "node:os";
|
|
4
3
|
import { join } from "node:path";
|
|
@@ -21,6 +20,8 @@ export const discover = Effect.fn("service.discover")(function* (options = {}) {
|
|
|
21
20
|
const found = (yield* registered(options.file)).service;
|
|
22
21
|
if (found?.state !== "ready")
|
|
23
22
|
return undefined;
|
|
23
|
+
if (!found.compatible)
|
|
24
|
+
return undefined;
|
|
24
25
|
if (!matchesVersion(found.version, options))
|
|
25
26
|
return undefined;
|
|
26
27
|
return found.endpoint;
|
|
@@ -31,6 +32,8 @@ export const incumbent = Effect.fn("service.incumbent")(function* (options) {
|
|
|
31
32
|
const found = info === undefined ? undefined : yield* probe({ ...info, url: options.url });
|
|
32
33
|
if (found === undefined)
|
|
33
34
|
return undefined;
|
|
35
|
+
if (!found.compatible)
|
|
36
|
+
return undefined;
|
|
34
37
|
if (!matchesVersion(found.version, options))
|
|
35
38
|
return undefined;
|
|
36
39
|
return { endpoint: found.endpoint, state: found.state };
|
|
@@ -86,7 +89,7 @@ export const ensure = Effect.fn("service.ensure")(function* (options = {}) {
|
|
|
86
89
|
timeouts = undefined;
|
|
87
90
|
if (service !== undefined) {
|
|
88
91
|
spawnDelay = timing.spawnDelay;
|
|
89
|
-
const compatible = matchesVersion(service.version, options);
|
|
92
|
+
const compatible = service.compatible && matchesVersion(service.version, options);
|
|
90
93
|
if (compatible && service.state === "ready") {
|
|
91
94
|
yield* Effect.tryPromise(() => PtyHandoff.complete(options.file ?? fallback(), service.info));
|
|
92
95
|
return Option.some(service);
|
|
@@ -159,7 +162,10 @@ export const Info = Schema.Struct({
|
|
|
159
162
|
password: Schema.optional(Schema.String),
|
|
160
163
|
});
|
|
161
164
|
const decode = Schema.decodeUnknownEffect(Schema.fromJsonString(Info));
|
|
162
|
-
const decodeStatus = Schema.decodeUnknownOption(
|
|
165
|
+
const decodeStatus = Schema.decodeUnknownOption(Schema.Struct({
|
|
166
|
+
version: Schema.String,
|
|
167
|
+
pid: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
|
|
168
|
+
}));
|
|
163
169
|
// A missing or corrupt file means no valid info; callers treat both
|
|
164
170
|
// the same (the registering server self-evicts, clients rediscover).
|
|
165
171
|
const read = Effect.fnUntraced(function* (file) {
|
|
@@ -181,11 +187,27 @@ const probeResult = Effect.fnUntraced(function* (info, timeout = defaultEnsureTi
|
|
|
181
187
|
};
|
|
182
188
|
const signal = AbortSignal.timeout(timeout);
|
|
183
189
|
const result = yield* Effect.promise(() => fetch(new URL("/api/status", info.url), { headers: headers(endpoint), signal })
|
|
184
|
-
.then(async (response) => ({
|
|
190
|
+
.then(async (response) => ({
|
|
191
|
+
response,
|
|
192
|
+
body: response.status === 404 ? undefined : (await response.json()),
|
|
193
|
+
}))
|
|
185
194
|
.then((value) => ({ value }), (cause) => ({ cause })));
|
|
186
195
|
if ("cause" in result)
|
|
187
196
|
return { service: undefined, timedOut: signal.aborted };
|
|
188
197
|
const response = result.value.response;
|
|
198
|
+
// The previous V2 service exposes /api/health instead. Its authenticated 404 is enough
|
|
199
|
+
// to recognize the registered daemon as incompatible and route it through replacement.
|
|
200
|
+
if (response.status === 404)
|
|
201
|
+
return {
|
|
202
|
+
service: {
|
|
203
|
+
info,
|
|
204
|
+
endpoint,
|
|
205
|
+
version: info.version,
|
|
206
|
+
state: "ready",
|
|
207
|
+
compatible: false,
|
|
208
|
+
},
|
|
209
|
+
timedOut: false,
|
|
210
|
+
};
|
|
189
211
|
const body = result.value.body;
|
|
190
212
|
const status = decodeStatus(body);
|
|
191
213
|
if (Option.isSome(status)) {
|
|
@@ -199,6 +221,7 @@ const probeResult = Effect.fnUntraced(function* (info, timeout = defaultEnsureTi
|
|
|
199
221
|
endpoint,
|
|
200
222
|
version: status.value.version,
|
|
201
223
|
state: response.ok ? "ready" : response.status === 500 ? "failed" : "waiting",
|
|
224
|
+
compatible: true,
|
|
202
225
|
},
|
|
203
226
|
timedOut: false,
|
|
204
227
|
};
|
|
@@ -611,7 +611,7 @@ export function make(options) {
|
|
|
611
611
|
path: `/api/integration/${encodeURIComponent(input.integrationID)}`,
|
|
612
612
|
query: { location: input["location"] },
|
|
613
613
|
successStatus: 200,
|
|
614
|
-
declaredStatuses: [400, 401],
|
|
614
|
+
declaredStatuses: [400, 401, 404],
|
|
615
615
|
empty: false,
|
|
616
616
|
}, requestOptions),
|
|
617
617
|
wellknown: {
|
|
@@ -3301,6 +3301,12 @@ export type ProviderNotFoundError = {
|
|
|
3301
3301
|
readonly message: string;
|
|
3302
3302
|
};
|
|
3303
3303
|
export declare const isProviderNotFoundError: (value: unknown) => value is ProviderNotFoundError;
|
|
3304
|
+
export type IntegrationNotFoundError = {
|
|
3305
|
+
readonly _tag: "IntegrationNotFoundError";
|
|
3306
|
+
readonly integrationID: string;
|
|
3307
|
+
readonly message: string;
|
|
3308
|
+
};
|
|
3309
|
+
export declare const isIntegrationNotFoundError: (value: unknown) => value is IntegrationNotFoundError;
|
|
3304
3310
|
export type McpServerNotFoundError = {
|
|
3305
3311
|
readonly _tag: "McpServerNotFoundError";
|
|
3306
3312
|
readonly server: string;
|
|
@@ -6158,7 +6164,7 @@ export type IntegrationGetInput = {
|
|
|
6158
6164
|
};
|
|
6159
6165
|
export type IntegrationGetOutput = {
|
|
6160
6166
|
location: LocationPublicRef;
|
|
6161
|
-
data: IntegrationInfo
|
|
6167
|
+
data: IntegrationInfo;
|
|
6162
6168
|
};
|
|
6163
6169
|
export type IntegrationWellknownAddInput = {
|
|
6164
6170
|
readonly location?: {
|
|
@@ -16,6 +16,7 @@ export const isInstructionEntryValueTooLargeError = (value) => typeof value ===
|
|
|
16
16
|
"_tag" in value &&
|
|
17
17
|
value["_tag"] === "InstructionEntryValueTooLargeError";
|
|
18
18
|
export const isProviderNotFoundError = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ProviderNotFoundError";
|
|
19
|
+
export const isIntegrationNotFoundError = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "IntegrationNotFoundError";
|
|
19
20
|
export const isMcpServerNotFoundError = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "McpServerNotFoundError";
|
|
20
21
|
export const isProjectNotFoundError = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ProjectNotFoundError";
|
|
21
22
|
export const isFormNotFoundError = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "FormNotFoundError";
|
package/dist/promise/service.js
CHANGED
|
@@ -16,6 +16,8 @@ export async function discover(options = {}) {
|
|
|
16
16
|
const found = (await registered(options.file)).service;
|
|
17
17
|
if (found?.state !== "ready")
|
|
18
18
|
return undefined;
|
|
19
|
+
if (!found.compatible)
|
|
20
|
+
return undefined;
|
|
19
21
|
if (!matchesVersion(found.version, options))
|
|
20
22
|
return undefined;
|
|
21
23
|
return found.endpoint;
|
|
@@ -70,7 +72,7 @@ export async function ensure(options = {}) {
|
|
|
70
72
|
if (registration.service !== undefined) {
|
|
71
73
|
spawnDelay = timing.spawnDelay;
|
|
72
74
|
const service = registration.service;
|
|
73
|
-
const compatible = matchesVersion(service.version, options);
|
|
75
|
+
const compatible = service.compatible && matchesVersion(service.version, options);
|
|
74
76
|
if (compatible && service.state === "ready") {
|
|
75
77
|
await PtyHandoff.complete(options.file ?? fallback(), service.info);
|
|
76
78
|
return service.endpoint;
|
|
@@ -156,30 +158,53 @@ async function probeResult(info, timeout = defaultEnsureTiming.requestTimeout) {
|
|
|
156
158
|
const result = await fetch(new URL("/api/status", info.url), { headers: headers(endpoint), signal })
|
|
157
159
|
.then(async (response) => ({
|
|
158
160
|
response,
|
|
159
|
-
body: (await response.json()),
|
|
161
|
+
body: response.status === 404 ? undefined : (await response.json()),
|
|
160
162
|
}))
|
|
161
163
|
.then((value) => ({ value }), (cause) => ({ cause }));
|
|
162
164
|
if ("cause" in result)
|
|
163
165
|
return { service: undefined, timedOut: signal.aborted };
|
|
164
166
|
const response = result.value.response;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
167
|
+
// The previous V2 service exposes /api/health instead. Its authenticated 404 is enough
|
|
168
|
+
// to recognize the registered daemon as incompatible and route it through replacement.
|
|
169
|
+
if (response.status === 404)
|
|
170
|
+
return {
|
|
171
|
+
service: {
|
|
172
|
+
info,
|
|
173
|
+
endpoint,
|
|
174
|
+
version: info.version,
|
|
175
|
+
state: "ready",
|
|
176
|
+
compatible: false,
|
|
177
|
+
},
|
|
178
|
+
timedOut: false,
|
|
179
|
+
};
|
|
180
|
+
const status = decodeStatus(result.value.body);
|
|
181
|
+
if (status !== undefined) {
|
|
182
|
+
if (status.pid !== info.pid)
|
|
168
183
|
return { service: undefined, timedOut: false };
|
|
169
|
-
if (info.version !== undefined &&
|
|
184
|
+
if (info.version !== undefined && status.version !== info.version)
|
|
170
185
|
return { service: undefined, timedOut: false };
|
|
171
186
|
return {
|
|
172
187
|
service: {
|
|
173
188
|
info,
|
|
174
189
|
endpoint,
|
|
175
|
-
version:
|
|
190
|
+
version: status.version,
|
|
176
191
|
state: response.ok ? "ready" : response.status === 500 ? "failed" : "waiting",
|
|
192
|
+
compatible: true,
|
|
177
193
|
},
|
|
178
194
|
timedOut: false,
|
|
179
195
|
};
|
|
180
196
|
}
|
|
181
197
|
return { service: undefined, timedOut: false };
|
|
182
198
|
}
|
|
199
|
+
function decodeStatus(input) {
|
|
200
|
+
if (typeof input !== "object" || input === null)
|
|
201
|
+
return;
|
|
202
|
+
if (!("version" in input) || typeof input.version !== "string")
|
|
203
|
+
return;
|
|
204
|
+
if (!("pid" in input) || typeof input.pid !== "number" || !Number.isInteger(input.pid) || input.pid < 0)
|
|
205
|
+
return;
|
|
206
|
+
return { version: input.version, pid: input.pid };
|
|
207
|
+
}
|
|
183
208
|
async function registered(file, timeout) {
|
|
184
209
|
const info = await read(file);
|
|
185
210
|
if (info === undefined)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@opencode/client",
|
|
4
|
-
"version": "0.0.0-dev-
|
|
4
|
+
"version": "0.0.0-dev-19566",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"typecheck": "tsgo --noEmit"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@opencode/schema": "0.0.0-dev-
|
|
61
|
-
"@opencode/protocol": "0.0.0-dev-
|
|
60
|
+
"@opencode/schema": "0.0.0-dev-19566",
|
|
61
|
+
"@opencode/protocol": "0.0.0-dev-19566"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"effect": "4.0.0-rc.112",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"@effect/platform-node": "4.0.0-rc.112",
|
|
77
|
-
"@opencode/httpapi-codegen": "0.0.0-dev-
|
|
77
|
+
"@opencode/httpapi-codegen": "0.0.0-dev-19566",
|
|
78
78
|
"@tsconfig/bun": "1.0.9",
|
|
79
79
|
"@types/bun": "1.4.0",
|
|
80
80
|
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|