@opencode-ai/client 0.0.0-next-17255 → 0.0.0-next-17268
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/service.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { ServiceStatus } from "@opencode-ai/protocol/groups/health";
|
|
2
2
|
import { Effect, FileSystem, Option, Schedule, Schema } from "effect";
|
|
3
|
-
import { spawn } from "node:child_process";
|
|
4
3
|
import { homedir } from "node:os";
|
|
5
4
|
import { join } from "node:path";
|
|
5
|
+
import { contenderFailure, contenderFinished, spawnServiceContender, } from "../service-contender.js";
|
|
6
6
|
import { defaultEnsureTiming, ensureTiming } from "../service-timing.js";
|
|
7
7
|
export * from "../service.js";
|
|
8
|
+
// Find, start, and stop the local opencode background service.
|
|
9
|
+
//
|
|
10
|
+
// The service daemon advertises itself through a registration file in the
|
|
11
|
+
// user's state directory: url, pid, version, and the private password, with
|
|
12
|
+
// 0600 permissions. That file is the complete discovery contract — reading it
|
|
13
|
+
// is all a client needs to connect. The daemon's own configuration (port,
|
|
14
|
+
// persisted password) is CLI-owned and never read here.
|
|
8
15
|
// Read-only lookup: registration file plus health check and version gate.
|
|
9
16
|
// Never spawns; escalation to ensure() is the caller's policy.
|
|
10
17
|
/** Discover a healthy, compatible local service without starting one. */
|
|
@@ -52,13 +59,7 @@ export const ensure = Effect.fn("service.ensure")(function* (options = {}) {
|
|
|
52
59
|
return yield* Effect.fail(new Error("Missing service command"));
|
|
53
60
|
return yield* Effect.try({
|
|
54
61
|
try: () => {
|
|
55
|
-
|
|
56
|
-
let error;
|
|
57
|
-
child.once("error", (cause) => {
|
|
58
|
-
error = new Error("Failed to start server", { cause });
|
|
59
|
-
});
|
|
60
|
-
child.unref();
|
|
61
|
-
return { child, error: () => error };
|
|
62
|
+
return spawnServiceContender(command, args);
|
|
62
63
|
},
|
|
63
64
|
catch: (cause) => new Error("Failed to start server", { cause }),
|
|
64
65
|
});
|
|
@@ -115,24 +116,11 @@ export const ensure = Effect.fn("service.ensure")(function* (options = {}) {
|
|
|
115
116
|
}).pipe(Effect.repeat({
|
|
116
117
|
until: Option.isSome,
|
|
117
118
|
schedule: Schedule.max([Schedule.spaced(timing.pollInterval), Schedule.recurs(timing.attempts)]),
|
|
118
|
-
}));
|
|
119
|
+
}), Effect.ensuring(Effect.sync(() => contenders.forEach((contender) => contender.release()))));
|
|
119
120
|
if (Option.isNone(found))
|
|
120
121
|
return yield* Effect.fail(new Error("Timed out waiting for the background service to start"));
|
|
121
122
|
return found.value.endpoint;
|
|
122
123
|
});
|
|
123
|
-
function contenderFailure(contender) {
|
|
124
|
-
const error = contender.error();
|
|
125
|
-
if (error !== undefined)
|
|
126
|
-
return error;
|
|
127
|
-
if (contender.child.exitCode !== null && contender.child.exitCode !== 0)
|
|
128
|
-
return new Error(`Server process exited with code ${contender.child.exitCode}`);
|
|
129
|
-
if (contender.child.signalCode !== null)
|
|
130
|
-
return new Error(`Server process terminated by ${contender.child.signalCode}`);
|
|
131
|
-
return undefined;
|
|
132
|
-
}
|
|
133
|
-
function contenderFinished(contender) {
|
|
134
|
-
return contender.error() !== undefined || contender.child.exitCode !== null || contender.child.signalCode !== null;
|
|
135
|
-
}
|
|
136
124
|
/** Stop the registered local service. */
|
|
137
125
|
export const stop = Effect.fn("service.stop")(function* (options = {}) {
|
|
138
126
|
const existing = yield* find(options);
|
|
@@ -73,7 +73,7 @@ export declare function make(options: ClientOptions): {
|
|
|
73
73
|
log: (input: SessionLogInput, requestOptions?: RequestOptions) => AsyncIterable<SessionLogOutput>;
|
|
74
74
|
interrupt: (input: SessionInterruptInput, requestOptions?: RequestOptions) => Promise<void>;
|
|
75
75
|
background: (input: SessionBackgroundInput, requestOptions?: RequestOptions) => Promise<void>;
|
|
76
|
-
message: (input: SessionMessageInput, requestOptions?: RequestOptions) => Promise<import("./types.js").SessionMessageAgentSelected | import("./types.js").SessionMessageSynthetic | import("./types.js").SessionMessageSystem | import("./types.js").SessionMessageSkill | import("./types.js").SessionMessageShell | import("./types.js").SessionMessageCompactionRunning | import("./types.js").SessionMessageCompactionCompleted | import("./types.js").SessionMessageModelSelected | import("./types.js").SessionMessageCompactionFailed | import("./types.js").SessionMessageUser | import("./types.js").SessionMessageAssistant>;
|
|
76
|
+
message: (input: SessionMessageInput, requestOptions?: RequestOptions) => Promise<import("./types.js").SessionMessageAgentSelected | import("./types.js").SessionMessageSynthetic | import("./types.js").SessionMessageSystem | import("./types.js").SessionMessageSkill | import("./types.js").SessionMessageShell | import("./types.js").SessionMessageCompactionRunning | import("./types.js").SessionMessageCompactionCompleted | import("./types.js").SessionMessageModelSelected | import("./types.js").SessionMessageLocationSwitched | import("./types.js").SessionMessageCompactionFailed | import("./types.js").SessionMessageUser | import("./types.js").SessionMessageAssistant>;
|
|
77
77
|
};
|
|
78
78
|
message: {
|
|
79
79
|
list: (input: MessageListInput, requestOptions?: RequestOptions) => Promise<import("./types.js").SessionMessagesResponse>;
|
|
@@ -96,6 +96,7 @@ export type SessionMessageSystem = {
|
|
|
96
96
|
};
|
|
97
97
|
type: "system";
|
|
98
98
|
text: string;
|
|
99
|
+
description?: string;
|
|
99
100
|
};
|
|
100
101
|
export type SessionMessageSkill = {
|
|
101
102
|
id: string;
|
|
@@ -618,6 +619,24 @@ export type PermissionRule = {
|
|
|
618
619
|
resource: string;
|
|
619
620
|
effect: PermissionEffect;
|
|
620
621
|
};
|
|
622
|
+
export type SessionMessageLocationSwitched = {
|
|
623
|
+
id: string;
|
|
624
|
+
metadata?: {
|
|
625
|
+
[x: string]: JsonValue;
|
|
626
|
+
};
|
|
627
|
+
time: {
|
|
628
|
+
created: number;
|
|
629
|
+
};
|
|
630
|
+
type: "location-switched";
|
|
631
|
+
location: LocationRef;
|
|
632
|
+
projectID?: string;
|
|
633
|
+
subpath?: string;
|
|
634
|
+
previous?: {
|
|
635
|
+
location: LocationRef;
|
|
636
|
+
projectID?: string;
|
|
637
|
+
subpath?: string;
|
|
638
|
+
};
|
|
639
|
+
};
|
|
621
640
|
export type SessionCreated = {
|
|
622
641
|
id: string;
|
|
623
642
|
created: number;
|
|
@@ -2797,7 +2816,7 @@ export type SessionInputAdmitted = {
|
|
|
2797
2816
|
input: SessionPendingMessage;
|
|
2798
2817
|
};
|
|
2799
2818
|
};
|
|
2800
|
-
export type SessionMessageInfo = SessionMessageAgentSelected | SessionMessageModelSelected | SessionMessageUser | SessionMessageSynthetic | SessionMessageSystem | SessionMessageSkill | SessionMessageShell | SessionMessageAssistant | SessionMessageCompaction;
|
|
2819
|
+
export type SessionMessageInfo = SessionMessageAgentSelected | SessionMessageModelSelected | SessionMessageLocationSwitched | SessionMessageUser | SessionMessageSynthetic | SessionMessageSystem | SessionMessageSkill | SessionMessageShell | SessionMessageAssistant | SessionMessageCompaction;
|
|
2801
2820
|
export type IntegrationMethod = IntegrationOAuthMethod | IntegrationCommandMethod | IntegrationKeyMethod | IntegrationEnvMethod;
|
|
2802
2821
|
export type FormCreated = {
|
|
2803
2822
|
id: string;
|
|
@@ -3331,6 +3350,29 @@ export type SessionImportInput = {
|
|
|
3331
3350
|
readonly providerID: string;
|
|
3332
3351
|
readonly variant?: string;
|
|
3333
3352
|
};
|
|
3353
|
+
} | {
|
|
3354
|
+
readonly id: string;
|
|
3355
|
+
readonly metadata?: {
|
|
3356
|
+
readonly [x: string]: JsonValue;
|
|
3357
|
+
};
|
|
3358
|
+
readonly time: {
|
|
3359
|
+
readonly created: number;
|
|
3360
|
+
};
|
|
3361
|
+
readonly type: "location-switched";
|
|
3362
|
+
readonly location: {
|
|
3363
|
+
readonly directory: string;
|
|
3364
|
+
readonly workspaceID?: string;
|
|
3365
|
+
};
|
|
3366
|
+
readonly projectID?: string;
|
|
3367
|
+
readonly subpath?: string;
|
|
3368
|
+
readonly previous?: {
|
|
3369
|
+
readonly location: {
|
|
3370
|
+
readonly directory: string;
|
|
3371
|
+
readonly workspaceID?: string;
|
|
3372
|
+
};
|
|
3373
|
+
readonly projectID?: string;
|
|
3374
|
+
readonly subpath?: string;
|
|
3375
|
+
};
|
|
3334
3376
|
} | {
|
|
3335
3377
|
readonly id: string;
|
|
3336
3378
|
readonly metadata?: {
|
|
@@ -3397,6 +3439,7 @@ export type SessionImportInput = {
|
|
|
3397
3439
|
};
|
|
3398
3440
|
readonly type: "system";
|
|
3399
3441
|
readonly text: string;
|
|
3442
|
+
readonly description?: string;
|
|
3400
3443
|
} | {
|
|
3401
3444
|
readonly id: string;
|
|
3402
3445
|
readonly metadata?: {
|
|
@@ -3714,6 +3757,29 @@ export type SessionImportInput = {
|
|
|
3714
3757
|
readonly providerID: string;
|
|
3715
3758
|
readonly variant?: string;
|
|
3716
3759
|
};
|
|
3760
|
+
} | {
|
|
3761
|
+
readonly id: string;
|
|
3762
|
+
readonly metadata?: {
|
|
3763
|
+
readonly [x: string]: JsonValue;
|
|
3764
|
+
};
|
|
3765
|
+
readonly time: {
|
|
3766
|
+
readonly created: number;
|
|
3767
|
+
};
|
|
3768
|
+
readonly type: "location-switched";
|
|
3769
|
+
readonly location: {
|
|
3770
|
+
readonly directory: string;
|
|
3771
|
+
readonly workspaceID?: string;
|
|
3772
|
+
};
|
|
3773
|
+
readonly projectID?: string;
|
|
3774
|
+
readonly subpath?: string;
|
|
3775
|
+
readonly previous?: {
|
|
3776
|
+
readonly location: {
|
|
3777
|
+
readonly directory: string;
|
|
3778
|
+
readonly workspaceID?: string;
|
|
3779
|
+
};
|
|
3780
|
+
readonly projectID?: string;
|
|
3781
|
+
readonly subpath?: string;
|
|
3782
|
+
};
|
|
3717
3783
|
} | {
|
|
3718
3784
|
readonly id: string;
|
|
3719
3785
|
readonly metadata?: {
|
|
@@ -3780,6 +3846,7 @@ export type SessionImportInput = {
|
|
|
3780
3846
|
};
|
|
3781
3847
|
readonly type: "system";
|
|
3782
3848
|
readonly text: string;
|
|
3849
|
+
readonly description?: string;
|
|
3783
3850
|
} | {
|
|
3784
3851
|
readonly id: string;
|
|
3785
3852
|
readonly metadata?: {
|
|
@@ -4097,6 +4164,29 @@ export type SessionImportInput = {
|
|
|
4097
4164
|
readonly providerID: string;
|
|
4098
4165
|
readonly variant?: string;
|
|
4099
4166
|
};
|
|
4167
|
+
} | {
|
|
4168
|
+
readonly id: string;
|
|
4169
|
+
readonly metadata?: {
|
|
4170
|
+
readonly [x: string]: JsonValue;
|
|
4171
|
+
};
|
|
4172
|
+
readonly time: {
|
|
4173
|
+
readonly created: number;
|
|
4174
|
+
};
|
|
4175
|
+
readonly type: "location-switched";
|
|
4176
|
+
readonly location: {
|
|
4177
|
+
readonly directory: string;
|
|
4178
|
+
readonly workspaceID?: string;
|
|
4179
|
+
};
|
|
4180
|
+
readonly projectID?: string;
|
|
4181
|
+
readonly subpath?: string;
|
|
4182
|
+
readonly previous?: {
|
|
4183
|
+
readonly location: {
|
|
4184
|
+
readonly directory: string;
|
|
4185
|
+
readonly workspaceID?: string;
|
|
4186
|
+
};
|
|
4187
|
+
readonly projectID?: string;
|
|
4188
|
+
readonly subpath?: string;
|
|
4189
|
+
};
|
|
4100
4190
|
} | {
|
|
4101
4191
|
readonly id: string;
|
|
4102
4192
|
readonly metadata?: {
|
|
@@ -4163,6 +4253,7 @@ export type SessionImportInput = {
|
|
|
4163
4253
|
};
|
|
4164
4254
|
readonly type: "system";
|
|
4165
4255
|
readonly text: string;
|
|
4256
|
+
readonly description?: string;
|
|
4166
4257
|
} | {
|
|
4167
4258
|
readonly id: string;
|
|
4168
4259
|
readonly metadata?: {
|
package/dist/promise/service.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
3
2
|
import { homedir } from "node:os";
|
|
4
3
|
import { join } from "node:path";
|
|
4
|
+
import { contenderFailure, contenderFinished, spawnServiceContender, } from "../service-contender.js";
|
|
5
5
|
import { defaultEnsureTiming, ensureTiming } from "../service-timing.js";
|
|
6
6
|
export * from "../service.js";
|
|
7
|
+
// Find, start, and stop the local opencode background service.
|
|
8
|
+
//
|
|
9
|
+
// The registration file is the complete discovery contract. This module is
|
|
10
|
+
// intentionally implemented with Node APIs so Promise clients do not need
|
|
11
|
+
// Effect or @effect/platform-node at runtime.
|
|
7
12
|
/** Discover a healthy, compatible local service without starting one. */
|
|
8
13
|
export async function discover(options = {}) {
|
|
9
14
|
return (await discoverLocal(options))?.endpoint;
|
|
@@ -36,83 +41,69 @@ export async function ensure(options = {}) {
|
|
|
36
41
|
if (command === undefined)
|
|
37
42
|
throw new Error("Missing service command");
|
|
38
43
|
try {
|
|
39
|
-
|
|
40
|
-
let error;
|
|
41
|
-
child.once("error", (cause) => {
|
|
42
|
-
error = new Error("Failed to start server", { cause });
|
|
43
|
-
});
|
|
44
|
-
child.unref();
|
|
45
|
-
return { child, error: () => error };
|
|
44
|
+
return spawnServiceContender(command, args);
|
|
46
45
|
}
|
|
47
46
|
catch (cause) {
|
|
48
47
|
throw new Error("Failed to start server", { cause });
|
|
49
48
|
}
|
|
50
49
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
else
|
|
68
|
-
timeouts = undefined;
|
|
69
|
-
if (registration.service !== undefined) {
|
|
70
|
-
spawnDelay = timing.spawnDelay;
|
|
71
|
-
const service = registration.service;
|
|
72
|
-
const compatible = !service.legacy && (options.version === undefined || service.version === options.version);
|
|
73
|
-
if (compatible && service.state === "ready")
|
|
74
|
-
return service.endpoint;
|
|
75
|
-
if (compatible && service.state === "failed")
|
|
76
|
-
throw new Error("Background service failed to start");
|
|
77
|
-
if (!compatible) {
|
|
78
|
-
announce("version-mismatch", service.version);
|
|
79
|
-
await kill(service, options, timing).catch(() => undefined);
|
|
80
|
-
lastSpawn = 0;
|
|
50
|
+
try {
|
|
51
|
+
while (true) {
|
|
52
|
+
if (Date.now() >= deadline)
|
|
53
|
+
throw new Error("Timed out waiting for the background service to start");
|
|
54
|
+
const registration = await registered(options.file, true, timing.requestTimeout);
|
|
55
|
+
if (registration.timedOut && registration.info !== undefined) {
|
|
56
|
+
timeouts = {
|
|
57
|
+
info: registration.info,
|
|
58
|
+
count: timeouts !== undefined && same(timeouts.info, registration.info) ? timeouts.count + 1 : 1,
|
|
59
|
+
};
|
|
60
|
+
if (timeouts.count >= 3) {
|
|
61
|
+
announce("missing");
|
|
62
|
+
await evict(registration.info, options, timing);
|
|
63
|
+
timeouts = undefined;
|
|
64
|
+
lastSpawn = Date.now() - spawnDelay;
|
|
65
|
+
}
|
|
81
66
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
67
|
+
else
|
|
68
|
+
timeouts = undefined;
|
|
69
|
+
if (registration.service !== undefined) {
|
|
70
|
+
spawnDelay = timing.spawnDelay;
|
|
71
|
+
const service = registration.service;
|
|
72
|
+
const compatible = !service.legacy && (options.version === undefined || service.version === options.version);
|
|
73
|
+
if (compatible && service.state === "ready")
|
|
74
|
+
return service.endpoint;
|
|
75
|
+
if (compatible && service.state === "failed")
|
|
76
|
+
throw new Error("Background service failed to start");
|
|
77
|
+
if (!compatible) {
|
|
78
|
+
announce("version-mismatch", service.version);
|
|
79
|
+
await kill(service, options, timing).catch(() => undefined);
|
|
80
|
+
lastSpawn = 0;
|
|
81
|
+
}
|
|
90
82
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
83
|
+
else {
|
|
84
|
+
if (lastSpawn === 0 && registration.info !== undefined)
|
|
85
|
+
lastSpawn = Date.now();
|
|
86
|
+
const finished = [...contenders].filter(contenderFinished);
|
|
87
|
+
const failure = finished.map(contenderFailure).find((error) => error !== undefined);
|
|
88
|
+
if (finished.some((item) => item.child.exitCode === 0)) {
|
|
89
|
+
spawnDelay = Math.min(spawnDelay * 2, timing.maxSpawnDelay);
|
|
90
|
+
}
|
|
91
|
+
finished.forEach((item) => contenders.delete(item));
|
|
92
|
+
if (failure !== undefined && contenders.size === 0)
|
|
93
|
+
throw failure;
|
|
94
|
+
// Keep one candidate plus one lock probe so a pre-lock stall cannot block recovery.
|
|
95
|
+
if (contenders.size < 2 && Date.now() - lastSpawn >= spawnDelay) {
|
|
96
|
+
announce("missing");
|
|
97
|
+
contenders.add(spawnContender());
|
|
98
|
+
lastSpawn = Date.now();
|
|
99
|
+
}
|
|
99
100
|
}
|
|
101
|
+
await delay(timing.pollInterval);
|
|
100
102
|
}
|
|
101
|
-
await delay(timing.pollInterval);
|
|
102
103
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (error !== undefined)
|
|
107
|
-
return error;
|
|
108
|
-
if (contender.child.exitCode !== null && contender.child.exitCode !== 0)
|
|
109
|
-
return new Error(`Server process exited with code ${contender.child.exitCode}`);
|
|
110
|
-
if (contender.child.signalCode !== null)
|
|
111
|
-
return new Error(`Server process terminated by ${contender.child.signalCode}`);
|
|
112
|
-
return undefined;
|
|
113
|
-
}
|
|
114
|
-
function contenderFinished(contender) {
|
|
115
|
-
return contender.error() !== undefined || contender.child.exitCode !== null || contender.child.signalCode !== null;
|
|
104
|
+
finally {
|
|
105
|
+
contenders.forEach((contender) => contender.release());
|
|
106
|
+
}
|
|
116
107
|
}
|
|
117
108
|
/** Stop the registered local service. */
|
|
118
109
|
export async function stop(options = {}) {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ChildProcess } from "node:child_process";
|
|
2
|
+
export type ServiceContender = {
|
|
3
|
+
readonly child: ChildProcess;
|
|
4
|
+
readonly error: () => Error | undefined;
|
|
5
|
+
readonly closed: () => boolean;
|
|
6
|
+
readonly stderr: () => string;
|
|
7
|
+
readonly release: () => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function spawnServiceContender(command: string, args: ReadonlyArray<string>): ServiceContender;
|
|
10
|
+
export declare function contenderFailure(contender: ServiceContender): Error | undefined;
|
|
11
|
+
export declare function contenderFinished(contender: ServiceContender): boolean;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
const stderrLimit = 8 * 1024;
|
|
3
|
+
export function spawnServiceContender(command, args) {
|
|
4
|
+
const child = spawn(command, args, { detached: true, stdio: ["ignore", "ignore", "pipe"] });
|
|
5
|
+
let error;
|
|
6
|
+
let closed = false;
|
|
7
|
+
let stderr = Buffer.alloc(0);
|
|
8
|
+
const onStderr = (chunk) => {
|
|
9
|
+
const tail = chunk.subarray(-stderrLimit);
|
|
10
|
+
stderr =
|
|
11
|
+
tail.length === stderrLimit
|
|
12
|
+
? Buffer.from(tail)
|
|
13
|
+
: Buffer.concat([stderr.subarray(-(stderrLimit - tail.length)), tail]);
|
|
14
|
+
};
|
|
15
|
+
child.stderr?.on("data", onStderr);
|
|
16
|
+
if (child.stderr !== null && "unref" in child.stderr && typeof child.stderr.unref === "function")
|
|
17
|
+
child.stderr.unref();
|
|
18
|
+
child.once("error", (cause) => {
|
|
19
|
+
error = new Error("Failed to start server", { cause });
|
|
20
|
+
});
|
|
21
|
+
child.once("close", () => {
|
|
22
|
+
closed = true;
|
|
23
|
+
});
|
|
24
|
+
child.unref();
|
|
25
|
+
return {
|
|
26
|
+
child,
|
|
27
|
+
error: () => error,
|
|
28
|
+
closed: () => closed,
|
|
29
|
+
stderr: () => stderr.toString("utf8").trim(),
|
|
30
|
+
release: () => {
|
|
31
|
+
child.stderr?.off("data", onStderr);
|
|
32
|
+
child.stderr?.resume();
|
|
33
|
+
stderr = Buffer.alloc(0);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function contenderFailure(contender) {
|
|
38
|
+
const error = contender.error();
|
|
39
|
+
if (error !== undefined)
|
|
40
|
+
return error;
|
|
41
|
+
if (contender.child.exitCode !== null && contender.child.exitCode !== 0)
|
|
42
|
+
return startupError(`Server process exited with code ${contender.child.exitCode}`, contender.stderr());
|
|
43
|
+
if (contender.child.signalCode !== null)
|
|
44
|
+
return startupError(`Server process terminated by ${contender.child.signalCode}`, contender.stderr());
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
export function contenderFinished(contender) {
|
|
48
|
+
return contender.error() !== undefined || contender.closed();
|
|
49
|
+
}
|
|
50
|
+
function startupError(message, stderr) {
|
|
51
|
+
return new Error(stderr ? `${message}\n${stderr}` : message);
|
|
52
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@opencode-ai/client",
|
|
4
|
-
"version": "0.0.0-next-
|
|
4
|
+
"version": "0.0.0-next-17268",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
"typecheck": "tsgo --noEmit"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@opencode-ai/schema": "0.0.0-next-
|
|
57
|
-
"@opencode-ai/protocol": "0.0.0-next-
|
|
56
|
+
"@opencode-ai/schema": "0.0.0-next-17268",
|
|
57
|
+
"@opencode-ai/protocol": "0.0.0-next-17268"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"effect": "4.0.0-beta.101"
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@effect/platform-node": "4.0.0-beta.101",
|
|
69
|
-
"@opencode-ai/httpapi-codegen": "0.0.0-next-
|
|
69
|
+
"@opencode-ai/httpapi-codegen": "0.0.0-next-17268",
|
|
70
70
|
"@tsconfig/bun": "1.0.9",
|
|
71
71
|
"@types/bun": "1.3.13",
|
|
72
72
|
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|