backeer-opencode 0.3.2 → 0.5.1
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/CHANGELOG.md +42 -0
- package/README.md +91 -17
- package/bin/backeer-opencode-mcp.js +9 -0
- package/dist/backeer-permission.js +3251 -88
- package/docs/live-control.md +80 -0
- package/package.json +12 -5
- package/src/config.js +4 -0
- package/src/index.js +6 -1
- package/src/live-bridge-client.js +52 -0
- package/src/live-bridge-config.js +48 -0
- package/src/live-bridge-events.js +80 -0
- package/src/live-bridge.js +273 -0
- package/src/live-connection.js +50 -0
- package/src/live-control-client.js +361 -0
- package/src/live-control-mcp.js +79 -0
- package/src/opencode-v2-client.js +147 -0
- package/src/opencode-v2-forms.js +24 -0
- package/src/opencode-v2.js +105 -0
- package/src/plugin.js +57 -49
- package/src/updates.js +4 -2
|
@@ -1,7 +1,1863 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res, err) => function __init() {
|
|
4
|
+
if (err) throw err[0];
|
|
5
|
+
try {
|
|
6
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
+
} catch (e) {
|
|
8
|
+
throw err = [e], e;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// node_modules/@opencode/client/dist/chunks/service-timing-9rqn6x4v.js
|
|
17
|
+
function __exportSetter(name, newValue) {
|
|
18
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
19
|
+
}
|
|
20
|
+
var __defProp2, __returnValue, __export2;
|
|
21
|
+
var init_service_timing_9rqn6x4v = __esm({
|
|
22
|
+
"node_modules/@opencode/client/dist/chunks/service-timing-9rqn6x4v.js"() {
|
|
23
|
+
__defProp2 = Object.defineProperty;
|
|
24
|
+
__returnValue = (v) => v;
|
|
25
|
+
__export2 = (target, all) => {
|
|
26
|
+
for (var name in all)
|
|
27
|
+
__defProp2(target, name, {
|
|
28
|
+
get: all[name],
|
|
29
|
+
enumerable: true,
|
|
30
|
+
configurable: true,
|
|
31
|
+
set: __exportSetter.bind(all, name)
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// node_modules/@opencode/client/dist/chunks/service-timing-frbwqjmf.js
|
|
38
|
+
function make7(connect) {
|
|
39
|
+
let current;
|
|
40
|
+
const capacity = 4096;
|
|
41
|
+
function stop2(connection) {
|
|
42
|
+
connection.connected = void 0;
|
|
43
|
+
connection.controller.abort();
|
|
44
|
+
if (current === connection)
|
|
45
|
+
current = void 0;
|
|
46
|
+
}
|
|
47
|
+
async function run(connection) {
|
|
48
|
+
let iterator;
|
|
49
|
+
let completion = {};
|
|
50
|
+
try {
|
|
51
|
+
if (connection.controller.signal.aborted)
|
|
52
|
+
return;
|
|
53
|
+
iterator = connect(connection.controller.signal, () => {
|
|
54
|
+
connection.subscribers.forEach((subscriber) => subscriber.activity?.());
|
|
55
|
+
})[Symbol.asyncIterator]();
|
|
56
|
+
while (!connection.controller.signal.aborted) {
|
|
57
|
+
const item = await iterator.next();
|
|
58
|
+
if (item.done || connection.controller.signal.aborted)
|
|
59
|
+
break;
|
|
60
|
+
if (item.value.type === "server.connected")
|
|
61
|
+
connection.connected = item.value;
|
|
62
|
+
connection.subscribers.forEach((subscriber) => subscriber.push(item.value));
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
completion = { error };
|
|
66
|
+
} finally {
|
|
67
|
+
stop2(connection);
|
|
68
|
+
try {
|
|
69
|
+
await iterator?.return?.();
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (!("error" in completion))
|
|
72
|
+
completion = { error };
|
|
73
|
+
}
|
|
74
|
+
connection.subscribers.forEach((subscriber) => subscriber.finish(completion));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
subscribe(options) {
|
|
79
|
+
return {
|
|
80
|
+
[Symbol.asyncIterator]() {
|
|
81
|
+
const pending = [];
|
|
82
|
+
const queued = [];
|
|
83
|
+
let started = false;
|
|
84
|
+
let completion;
|
|
85
|
+
let connection;
|
|
86
|
+
function finish(result, discard = true) {
|
|
87
|
+
completion = result;
|
|
88
|
+
if (discard)
|
|
89
|
+
queued.length = 0;
|
|
90
|
+
options?.signal?.removeEventListener("abort", abort);
|
|
91
|
+
if (connection?.subscribers.delete(subscriber) && !connection.subscribers.size)
|
|
92
|
+
stop2(connection);
|
|
93
|
+
pending.splice(0).forEach((request) => {
|
|
94
|
+
if ("error" in result)
|
|
95
|
+
request.reject(result.error);
|
|
96
|
+
else
|
|
97
|
+
request.resolve({ done: true, value: void 0 });
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function abort() {
|
|
101
|
+
finish({});
|
|
102
|
+
}
|
|
103
|
+
const subscriber = {
|
|
104
|
+
activity: options?.onActivity,
|
|
105
|
+
finish(result) {
|
|
106
|
+
finish(result, false);
|
|
107
|
+
},
|
|
108
|
+
push(value) {
|
|
109
|
+
if (completion)
|
|
110
|
+
return;
|
|
111
|
+
const request = pending.shift();
|
|
112
|
+
if (request) {
|
|
113
|
+
request.resolve({ done: false, value });
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (queued.length === capacity) {
|
|
117
|
+
finish({ error: new Error(`Event subscriber exceeded its ${capacity}-event capacity`) });
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
queued.push(value);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
function start() {
|
|
124
|
+
if (completion)
|
|
125
|
+
return;
|
|
126
|
+
const fresh = !current;
|
|
127
|
+
connection = current ?? {
|
|
128
|
+
controller: new AbortController(),
|
|
129
|
+
subscribers: /* @__PURE__ */ new Set()
|
|
130
|
+
};
|
|
131
|
+
current = connection;
|
|
132
|
+
connection.subscribers.add(subscriber);
|
|
133
|
+
if (connection.connected)
|
|
134
|
+
subscriber.push(connection.connected);
|
|
135
|
+
if (fresh)
|
|
136
|
+
run(connection);
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
next() {
|
|
140
|
+
const value = queued.shift();
|
|
141
|
+
if (value)
|
|
142
|
+
return Promise.resolve({ done: false, value });
|
|
143
|
+
if (completion) {
|
|
144
|
+
if ("error" in completion)
|
|
145
|
+
return Promise.reject(completion.error);
|
|
146
|
+
return Promise.resolve({ done: true, value: void 0 });
|
|
147
|
+
}
|
|
148
|
+
if (options?.signal?.aborted) {
|
|
149
|
+
abort();
|
|
150
|
+
return Promise.resolve({ done: true, value: void 0 });
|
|
151
|
+
}
|
|
152
|
+
const request = Promise.withResolvers();
|
|
153
|
+
pending.push(request);
|
|
154
|
+
if (!started) {
|
|
155
|
+
started = true;
|
|
156
|
+
options?.signal?.addEventListener("abort", abort, { once: true });
|
|
157
|
+
start();
|
|
158
|
+
}
|
|
159
|
+
return request.promise;
|
|
160
|
+
},
|
|
161
|
+
return() {
|
|
162
|
+
finish({});
|
|
163
|
+
return Promise.resolve({ done: true, value: void 0 });
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
var exports_shared_events;
|
|
172
|
+
var init_service_timing_frbwqjmf = __esm({
|
|
173
|
+
"node_modules/@opencode/client/dist/chunks/service-timing-frbwqjmf.js"() {
|
|
174
|
+
init_service_timing_9rqn6x4v();
|
|
175
|
+
exports_shared_events = {};
|
|
176
|
+
__export2(exports_shared_events, {
|
|
177
|
+
SharedEvents: () => exports_shared_events,
|
|
178
|
+
make: () => make7
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// node_modules/@opencode/client/dist/chunks/service-timing-js54wxgp.js
|
|
184
|
+
var ClientError2;
|
|
185
|
+
var init_service_timing_js54wxgp = __esm({
|
|
186
|
+
"node_modules/@opencode/client/dist/chunks/service-timing-js54wxgp.js"() {
|
|
187
|
+
ClientError2 = class extends Error {
|
|
188
|
+
reason;
|
|
189
|
+
name = "ClientError";
|
|
190
|
+
constructor(reason, options) {
|
|
191
|
+
const detail = options?.detail ?? (options?.cause instanceof Error ? options.cause.message : void 0);
|
|
192
|
+
super(detail ? `${reason}: ${detail}` : reason, options);
|
|
193
|
+
this.reason = reason;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// node_modules/@opencode/client/dist/chunks/service-timing-tbh3h57v.js
|
|
200
|
+
function make3(options) {
|
|
201
|
+
const fetch2 = options.fetch ?? globalThis.fetch;
|
|
202
|
+
const prepare = (descriptor, requestOptions) => {
|
|
203
|
+
const baseUrl = new URL(options.baseUrl);
|
|
204
|
+
if (!baseUrl.pathname.endsWith("/"))
|
|
205
|
+
baseUrl.pathname += "/";
|
|
206
|
+
const url = new URL(descriptor.path.slice(1), baseUrl);
|
|
207
|
+
for (const [key, value] of Object.entries(descriptor.query ?? {}))
|
|
208
|
+
appendQuery(url.searchParams, key, value);
|
|
209
|
+
const headers = new Headers(options.headers);
|
|
210
|
+
for (const [key, value] of Object.entries(descriptor.headers ?? {})) {
|
|
211
|
+
if (value !== void 0 && value !== null)
|
|
212
|
+
headers.set(key, String(value));
|
|
213
|
+
}
|
|
214
|
+
for (const [key, value] of new Headers(requestOptions?.headers))
|
|
215
|
+
headers.set(key, value);
|
|
216
|
+
if (descriptor.body !== void 0 && !headers.has("content-type"))
|
|
217
|
+
headers.set("content-type", descriptor.binaryBody ? "application/octet-stream" : "application/json");
|
|
218
|
+
return {
|
|
219
|
+
url,
|
|
220
|
+
init: {
|
|
221
|
+
method: descriptor.method,
|
|
222
|
+
signal: requestOptions?.signal,
|
|
223
|
+
headers,
|
|
224
|
+
body: descriptor.body === void 0 ? void 0 : descriptor.binaryBody ? descriptor.body : JSON.stringify(descriptor.body)
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
};
|
|
228
|
+
const execute = async (descriptor, requestOptions) => {
|
|
229
|
+
try {
|
|
230
|
+
const prepared = prepare(descriptor, requestOptions);
|
|
231
|
+
return await fetch2(prepared.url, prepared.init);
|
|
232
|
+
} catch (cause) {
|
|
233
|
+
throw new ClientError2("Transport", { cause });
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
const responseError = async (response, descriptor) => {
|
|
237
|
+
if (descriptor.declaredStatuses.includes(response.status))
|
|
238
|
+
throw declared(await json2(response));
|
|
239
|
+
try {
|
|
240
|
+
await response.body?.cancel();
|
|
241
|
+
} catch {
|
|
242
|
+
}
|
|
243
|
+
throw new ClientError2("UnexpectedStatus", { cause: { status: response.status }, detail: String(response.status) });
|
|
244
|
+
};
|
|
245
|
+
const request = async (descriptor, requestOptions) => {
|
|
246
|
+
const response = await execute(descriptor, requestOptions);
|
|
247
|
+
if (response.status !== descriptor.successStatus)
|
|
248
|
+
return responseError(response, descriptor);
|
|
249
|
+
if (descriptor.binary)
|
|
250
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
251
|
+
if (descriptor.empty) {
|
|
252
|
+
try {
|
|
253
|
+
await response.body?.cancel();
|
|
254
|
+
} catch {
|
|
255
|
+
}
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
return await json2(response);
|
|
259
|
+
};
|
|
260
|
+
const sse = (descriptor, requestOptions) => ({
|
|
261
|
+
async *[Symbol.asyncIterator]() {
|
|
262
|
+
const response = await execute(descriptor, requestOptions);
|
|
263
|
+
if (response.status !== descriptor.successStatus)
|
|
264
|
+
await responseError(response, descriptor);
|
|
265
|
+
if (!isContentType(response, "text/event-stream")) {
|
|
266
|
+
try {
|
|
267
|
+
await response.body?.cancel();
|
|
268
|
+
} catch {
|
|
269
|
+
}
|
|
270
|
+
throw new ClientError2("UnsupportedContentType", { detail: response.headers.get("content-type") });
|
|
271
|
+
}
|
|
272
|
+
if (response.body === null)
|
|
273
|
+
throw new ClientError2("MalformedResponse");
|
|
274
|
+
const reader = response.body.getReader();
|
|
275
|
+
const decoder = new TextDecoder();
|
|
276
|
+
let buffer = "";
|
|
277
|
+
try {
|
|
278
|
+
while (true) {
|
|
279
|
+
let next;
|
|
280
|
+
try {
|
|
281
|
+
next = await reader.read();
|
|
282
|
+
} catch (cause) {
|
|
283
|
+
throw new ClientError2("Transport", { cause });
|
|
284
|
+
}
|
|
285
|
+
if (!next.done)
|
|
286
|
+
requestOptions?.onActivity?.();
|
|
287
|
+
buffer += decoder.decode(next.value, { stream: !next.done });
|
|
288
|
+
if (buffer.length > maxSseEventBytes)
|
|
289
|
+
throw new ClientError2("SseEventTooLarge");
|
|
290
|
+
const trailingCarriageReturn = !next.done && buffer.endsWith("\r");
|
|
291
|
+
if (trailingCarriageReturn)
|
|
292
|
+
buffer = buffer.slice(0, -1);
|
|
293
|
+
buffer = buffer.replaceAll(`\r
|
|
294
|
+
`, `
|
|
295
|
+
`).replaceAll("\r", `
|
|
296
|
+
`);
|
|
297
|
+
if (trailingCarriageReturn)
|
|
298
|
+
buffer += "\r";
|
|
299
|
+
if (next.done && buffer !== "")
|
|
300
|
+
buffer += `
|
|
301
|
+
|
|
302
|
+
`;
|
|
303
|
+
let boundary = buffer.indexOf(`
|
|
304
|
+
|
|
305
|
+
`);
|
|
306
|
+
while (boundary >= 0) {
|
|
307
|
+
const block = buffer.slice(0, boundary);
|
|
308
|
+
buffer = buffer.slice(boundary + 2);
|
|
309
|
+
const data = block.split(`
|
|
310
|
+
`).flatMap((line) => line.startsWith("data:") ? [line.slice(5).trimStart()] : []).join(`
|
|
311
|
+
`);
|
|
312
|
+
if (data !== "") {
|
|
313
|
+
try {
|
|
314
|
+
yield JSON.parse(data);
|
|
315
|
+
} catch (cause) {
|
|
316
|
+
throw new ClientError2("MalformedResponse", { cause });
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
boundary = buffer.indexOf(`
|
|
320
|
+
|
|
321
|
+
`);
|
|
322
|
+
}
|
|
323
|
+
if (next.done)
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
} finally {
|
|
327
|
+
try {
|
|
328
|
+
await reader.cancel();
|
|
329
|
+
} catch {
|
|
330
|
+
}
|
|
331
|
+
reader.releaseLock();
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
return {
|
|
336
|
+
server: {
|
|
337
|
+
info: (requestOptions) => request({ method: "GET", path: `/api/info`, successStatus: 200, declaredStatuses: [400, 401], empty: false }, requestOptions),
|
|
338
|
+
pair: (requestOptions) => request({ method: "POST", path: `/api/pair`, successStatus: 200, declaredStatuses: [400, 401], empty: false }, requestOptions),
|
|
339
|
+
connect: (input, requestOptions) => request({
|
|
340
|
+
method: "GET",
|
|
341
|
+
path: `/auth/connect/${encodeURIComponent(input.code)}`,
|
|
342
|
+
successStatus: 200,
|
|
343
|
+
declaredStatuses: [400, 401],
|
|
344
|
+
empty: false
|
|
345
|
+
}, requestOptions)
|
|
346
|
+
},
|
|
347
|
+
location: {
|
|
348
|
+
get: (input, requestOptions) => request({
|
|
349
|
+
method: "GET",
|
|
350
|
+
path: `/api/location`,
|
|
351
|
+
query: { location: input?.["location"] },
|
|
352
|
+
successStatus: 200,
|
|
353
|
+
declaredStatuses: [400, 401, 404],
|
|
354
|
+
empty: false
|
|
355
|
+
}, requestOptions),
|
|
356
|
+
reload: (requestOptions) => request({
|
|
357
|
+
method: "POST",
|
|
358
|
+
path: `/api/location/reload`,
|
|
359
|
+
successStatus: 204,
|
|
360
|
+
declaredStatuses: [400, 401, 503],
|
|
361
|
+
empty: true
|
|
362
|
+
}, requestOptions)
|
|
363
|
+
},
|
|
364
|
+
agent: {
|
|
365
|
+
list: (input, requestOptions) => request({
|
|
366
|
+
method: "GET",
|
|
367
|
+
path: `/api/agent`,
|
|
368
|
+
query: { location: input?.["location"] },
|
|
369
|
+
successStatus: 200,
|
|
370
|
+
declaredStatuses: [400, 401, 404],
|
|
371
|
+
empty: false
|
|
372
|
+
}, requestOptions),
|
|
373
|
+
get: (input, requestOptions) => request({
|
|
374
|
+
method: "GET",
|
|
375
|
+
path: `/api/agent/${encodeURIComponent(input.agentID)}`,
|
|
376
|
+
query: { location: input["location"] },
|
|
377
|
+
successStatus: 200,
|
|
378
|
+
declaredStatuses: [400, 401, 404],
|
|
379
|
+
empty: false
|
|
380
|
+
}, requestOptions)
|
|
381
|
+
},
|
|
382
|
+
plugin: {
|
|
383
|
+
list: (input, requestOptions) => request({
|
|
384
|
+
method: "GET",
|
|
385
|
+
path: `/api/plugin`,
|
|
386
|
+
query: { location: input?.["location"] },
|
|
387
|
+
successStatus: 200,
|
|
388
|
+
declaredStatuses: [400, 401, 404],
|
|
389
|
+
empty: false
|
|
390
|
+
}, requestOptions),
|
|
391
|
+
check: (input, requestOptions) => request({
|
|
392
|
+
method: "POST",
|
|
393
|
+
path: `/api/plugin/check`,
|
|
394
|
+
query: { location: input?.["location"] },
|
|
395
|
+
body: { target: input?.["target"] },
|
|
396
|
+
successStatus: 200,
|
|
397
|
+
declaredStatuses: [400, 401, 404],
|
|
398
|
+
empty: false
|
|
399
|
+
}, requestOptions),
|
|
400
|
+
update: (input, requestOptions) => request({
|
|
401
|
+
method: "POST",
|
|
402
|
+
path: `/api/plugin/update`,
|
|
403
|
+
query: { location: input["location"] },
|
|
404
|
+
body: { targets: input["targets"] },
|
|
405
|
+
successStatus: 204,
|
|
406
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
407
|
+
empty: true
|
|
408
|
+
}, requestOptions)
|
|
409
|
+
},
|
|
410
|
+
session: {
|
|
411
|
+
list: (input, requestOptions) => request({
|
|
412
|
+
method: "GET",
|
|
413
|
+
path: `/api/session`,
|
|
414
|
+
query: {
|
|
415
|
+
limit: input?.["limit"],
|
|
416
|
+
order: input?.["order"],
|
|
417
|
+
search: input?.["search"],
|
|
418
|
+
parentID: input?.["parentID"],
|
|
419
|
+
directory: input?.["directory"],
|
|
420
|
+
project: input?.["project"],
|
|
421
|
+
subpath: input?.["subpath"],
|
|
422
|
+
cursor: input?.["cursor"]
|
|
423
|
+
},
|
|
424
|
+
successStatus: 200,
|
|
425
|
+
declaredStatuses: [400, 401],
|
|
426
|
+
empty: false
|
|
427
|
+
}, requestOptions),
|
|
428
|
+
stats: (input, requestOptions) => request({
|
|
429
|
+
method: "GET",
|
|
430
|
+
path: `/api/experimental/session/stats`,
|
|
431
|
+
query: {
|
|
432
|
+
from: input?.["from"],
|
|
433
|
+
to: input?.["to"],
|
|
434
|
+
project: input?.["project"],
|
|
435
|
+
timezone: input?.["timezone"],
|
|
436
|
+
tools: input?.["tools"]
|
|
437
|
+
},
|
|
438
|
+
successStatus: 200,
|
|
439
|
+
declaredStatuses: [400, 401],
|
|
440
|
+
empty: false
|
|
441
|
+
}, requestOptions).then((value) => value.data),
|
|
442
|
+
create: (input, requestOptions) => request({
|
|
443
|
+
method: "POST",
|
|
444
|
+
path: `/api/session`,
|
|
445
|
+
body: {
|
|
446
|
+
id: input?.["id"],
|
|
447
|
+
parentID: input?.["parentID"],
|
|
448
|
+
title: input?.["title"],
|
|
449
|
+
agent: input?.["agent"],
|
|
450
|
+
model: input?.["model"],
|
|
451
|
+
location: input?.["location"],
|
|
452
|
+
metadata: input?.["metadata"],
|
|
453
|
+
permissions: input?.["permissions"]
|
|
454
|
+
},
|
|
455
|
+
successStatus: 200,
|
|
456
|
+
declaredStatuses: [400, 401, 404],
|
|
457
|
+
empty: false
|
|
458
|
+
}, requestOptions).then((value) => value.data),
|
|
459
|
+
import: (input, requestOptions) => request({
|
|
460
|
+
method: "POST",
|
|
461
|
+
path: `/api/experimental/session/import`,
|
|
462
|
+
body: { info: input["info"], messages: input["messages"], location: input["location"] },
|
|
463
|
+
successStatus: 200,
|
|
464
|
+
declaredStatuses: [400, 401, 404, 409],
|
|
465
|
+
empty: false
|
|
466
|
+
}, requestOptions).then((value) => value.data),
|
|
467
|
+
export: (input, requestOptions) => request({
|
|
468
|
+
method: "GET",
|
|
469
|
+
path: `/api/experimental/session/${encodeURIComponent(input.sessionID)}/export`,
|
|
470
|
+
query: { sanitize: input["sanitize"] },
|
|
471
|
+
successStatus: 200,
|
|
472
|
+
declaredStatuses: [400, 401, 404, 500],
|
|
473
|
+
empty: false
|
|
474
|
+
}, requestOptions).then((value) => value.data),
|
|
475
|
+
active: (requestOptions) => request({
|
|
476
|
+
method: "GET",
|
|
477
|
+
path: `/api/session/active`,
|
|
478
|
+
successStatus: 200,
|
|
479
|
+
declaredStatuses: [400, 401],
|
|
480
|
+
empty: false
|
|
481
|
+
}, requestOptions).then((value) => value.data),
|
|
482
|
+
get: (input, requestOptions) => request({
|
|
483
|
+
method: "GET",
|
|
484
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}`,
|
|
485
|
+
successStatus: 200,
|
|
486
|
+
declaredStatuses: [400, 401, 404],
|
|
487
|
+
empty: false
|
|
488
|
+
}, requestOptions).then((value) => value.data),
|
|
489
|
+
remove: (input, requestOptions) => request({
|
|
490
|
+
method: "DELETE",
|
|
491
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}`,
|
|
492
|
+
successStatus: 204,
|
|
493
|
+
declaredStatuses: [400, 401, 404],
|
|
494
|
+
empty: true
|
|
495
|
+
}, requestOptions),
|
|
496
|
+
fork: (input, requestOptions) => request({
|
|
497
|
+
method: "POST",
|
|
498
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/fork`,
|
|
499
|
+
body: { before: input["before"] },
|
|
500
|
+
successStatus: 200,
|
|
501
|
+
declaredStatuses: [400, 401, 404],
|
|
502
|
+
empty: false
|
|
503
|
+
}, requestOptions).then((value) => value.data),
|
|
504
|
+
switchAgent: (input, requestOptions) => request({
|
|
505
|
+
method: "POST",
|
|
506
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/agent`,
|
|
507
|
+
body: { agent: input["agent"] },
|
|
508
|
+
successStatus: 204,
|
|
509
|
+
declaredStatuses: [400, 401, 404],
|
|
510
|
+
empty: true
|
|
511
|
+
}, requestOptions),
|
|
512
|
+
switchModel: (input, requestOptions) => request({
|
|
513
|
+
method: "POST",
|
|
514
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/model`,
|
|
515
|
+
body: { model: input["model"] },
|
|
516
|
+
successStatus: 204,
|
|
517
|
+
declaredStatuses: [400, 401, 404],
|
|
518
|
+
empty: true
|
|
519
|
+
}, requestOptions),
|
|
520
|
+
update: (input, requestOptions) => request({
|
|
521
|
+
method: "PATCH",
|
|
522
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}`,
|
|
523
|
+
body: { title: input["title"], metadata: input["metadata"], permissions: input["permissions"] },
|
|
524
|
+
successStatus: 204,
|
|
525
|
+
declaredStatuses: [400, 401, 404],
|
|
526
|
+
empty: true
|
|
527
|
+
}, requestOptions),
|
|
528
|
+
move: (input, requestOptions) => request({
|
|
529
|
+
method: "POST",
|
|
530
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/move`,
|
|
531
|
+
body: { directory: input["directory"], delivery: input["delivery"] },
|
|
532
|
+
successStatus: 204,
|
|
533
|
+
declaredStatuses: [400, 401, 404],
|
|
534
|
+
empty: true
|
|
535
|
+
}, requestOptions),
|
|
536
|
+
prompt: (input, requestOptions) => request({
|
|
537
|
+
method: "POST",
|
|
538
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/prompt`,
|
|
539
|
+
body: {
|
|
540
|
+
id: input["id"],
|
|
541
|
+
text: input["text"],
|
|
542
|
+
files: input["files"],
|
|
543
|
+
agents: input["agents"],
|
|
544
|
+
skills: input["skills"],
|
|
545
|
+
metadata: input["metadata"],
|
|
546
|
+
delivery: input["delivery"],
|
|
547
|
+
resume: input["resume"]
|
|
548
|
+
},
|
|
549
|
+
successStatus: 200,
|
|
550
|
+
declaredStatuses: [400, 401, 404, 409],
|
|
551
|
+
empty: false
|
|
552
|
+
}, requestOptions).then((value) => value.data),
|
|
553
|
+
command: (input, requestOptions) => request({
|
|
554
|
+
method: "POST",
|
|
555
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/command`,
|
|
556
|
+
body: {
|
|
557
|
+
name: input["name"],
|
|
558
|
+
text: input["text"],
|
|
559
|
+
files: input["files"],
|
|
560
|
+
agents: input["agents"],
|
|
561
|
+
skills: input["skills"],
|
|
562
|
+
delivery: input["delivery"]
|
|
563
|
+
},
|
|
564
|
+
successStatus: 204,
|
|
565
|
+
declaredStatuses: [400, 401, 404, 500],
|
|
566
|
+
empty: true
|
|
567
|
+
}, requestOptions),
|
|
568
|
+
skill: (input, requestOptions) => request({
|
|
569
|
+
method: "POST",
|
|
570
|
+
path: `/api/experimental/session/${encodeURIComponent(input.sessionID)}/skill`,
|
|
571
|
+
body: { id: input["id"], resume: input["resume"] },
|
|
572
|
+
successStatus: 204,
|
|
573
|
+
declaredStatuses: [400, 401, 404],
|
|
574
|
+
empty: true
|
|
575
|
+
}, requestOptions),
|
|
576
|
+
synthetic: (input, requestOptions) => request({
|
|
577
|
+
method: "POST",
|
|
578
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/synthetic`,
|
|
579
|
+
body: {
|
|
580
|
+
id: input["id"],
|
|
581
|
+
text: input["text"],
|
|
582
|
+
description: input["description"],
|
|
583
|
+
metadata: input["metadata"],
|
|
584
|
+
delivery: input["delivery"],
|
|
585
|
+
resume: input["resume"]
|
|
586
|
+
},
|
|
587
|
+
successStatus: 200,
|
|
588
|
+
declaredStatuses: [400, 401, 404, 409],
|
|
589
|
+
empty: false
|
|
590
|
+
}, requestOptions).then((value) => value.data),
|
|
591
|
+
shell: (input, requestOptions) => request({
|
|
592
|
+
method: "POST",
|
|
593
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/shell`,
|
|
594
|
+
body: { id: input["id"], command: input["command"] },
|
|
595
|
+
successStatus: 204,
|
|
596
|
+
declaredStatuses: [400, 401, 404],
|
|
597
|
+
empty: true
|
|
598
|
+
}, requestOptions),
|
|
599
|
+
compact: (input, requestOptions) => request({
|
|
600
|
+
method: "POST",
|
|
601
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/compact`,
|
|
602
|
+
body: { id: input["id"], delivery: input["delivery"] },
|
|
603
|
+
successStatus: 200,
|
|
604
|
+
declaredStatuses: [400, 401, 404, 409],
|
|
605
|
+
empty: false
|
|
606
|
+
}, requestOptions).then((value) => value.data),
|
|
607
|
+
wait: (input, requestOptions) => request({
|
|
608
|
+
method: "POST",
|
|
609
|
+
path: `/api/experimental/session/${encodeURIComponent(input.sessionID)}/wait`,
|
|
610
|
+
successStatus: 204,
|
|
611
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
612
|
+
empty: true
|
|
613
|
+
}, requestOptions),
|
|
614
|
+
revert: {
|
|
615
|
+
stage: (input, requestOptions) => request({
|
|
616
|
+
method: "POST",
|
|
617
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/revert/stage`,
|
|
618
|
+
body: { messageID: input["messageID"], files: input["files"] },
|
|
619
|
+
successStatus: 200,
|
|
620
|
+
declaredStatuses: [400, 401, 404, 409, 500],
|
|
621
|
+
empty: false
|
|
622
|
+
}, requestOptions).then((value) => value.data),
|
|
623
|
+
clear: (input, requestOptions) => request({
|
|
624
|
+
method: "DELETE",
|
|
625
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/revert`,
|
|
626
|
+
successStatus: 204,
|
|
627
|
+
declaredStatuses: [400, 401, 404, 409, 500],
|
|
628
|
+
empty: true
|
|
629
|
+
}, requestOptions),
|
|
630
|
+
commit: (input, requestOptions) => request({
|
|
631
|
+
method: "POST",
|
|
632
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/revert/commit`,
|
|
633
|
+
successStatus: 204,
|
|
634
|
+
declaredStatuses: [400, 401, 404, 409],
|
|
635
|
+
empty: true
|
|
636
|
+
}, requestOptions)
|
|
637
|
+
},
|
|
638
|
+
context: (input, requestOptions) => request({
|
|
639
|
+
method: "GET",
|
|
640
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/context`,
|
|
641
|
+
successStatus: 200,
|
|
642
|
+
declaredStatuses: [400, 401, 404, 500],
|
|
643
|
+
empty: false
|
|
644
|
+
}, requestOptions).then((value) => value.data),
|
|
645
|
+
diff: (input, requestOptions) => request({
|
|
646
|
+
method: "GET",
|
|
647
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/diff`,
|
|
648
|
+
query: { from: input["from"], to: input["to"], context: input["context"] },
|
|
649
|
+
successStatus: 200,
|
|
650
|
+
declaredStatuses: [400, 401, 404, 500],
|
|
651
|
+
empty: false
|
|
652
|
+
}, requestOptions).then((value) => value.data),
|
|
653
|
+
inbox: {
|
|
654
|
+
list: (input, requestOptions) => request({
|
|
655
|
+
method: "GET",
|
|
656
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/inbox`,
|
|
657
|
+
successStatus: 200,
|
|
658
|
+
declaredStatuses: [400, 401, 404],
|
|
659
|
+
empty: false
|
|
660
|
+
}, requestOptions).then((value) => value.data),
|
|
661
|
+
cancel: (input, requestOptions) => request({
|
|
662
|
+
method: "DELETE",
|
|
663
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/inbox/${encodeURIComponent(input.inboxID)}`,
|
|
664
|
+
successStatus: 204,
|
|
665
|
+
declaredStatuses: [400, 401, 404],
|
|
666
|
+
empty: true
|
|
667
|
+
}, requestOptions),
|
|
668
|
+
update: (input, requestOptions) => request({
|
|
669
|
+
method: "PATCH",
|
|
670
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/inbox/${encodeURIComponent(input.inboxID)}`,
|
|
671
|
+
body: { delivery: input["delivery"] },
|
|
672
|
+
successStatus: 204,
|
|
673
|
+
declaredStatuses: [400, 401, 404, 409],
|
|
674
|
+
empty: true
|
|
675
|
+
}, requestOptions)
|
|
676
|
+
},
|
|
677
|
+
instructions: {
|
|
678
|
+
entry: {
|
|
679
|
+
list: (input, requestOptions) => request({
|
|
680
|
+
method: "GET",
|
|
681
|
+
path: `/api/experimental/session/${encodeURIComponent(input.sessionID)}/instructions/entries`,
|
|
682
|
+
successStatus: 200,
|
|
683
|
+
declaredStatuses: [400, 401, 404],
|
|
684
|
+
empty: false
|
|
685
|
+
}, requestOptions).then((value) => value.data),
|
|
686
|
+
put: (input, requestOptions) => request({
|
|
687
|
+
method: "PUT",
|
|
688
|
+
path: `/api/experimental/session/${encodeURIComponent(input.sessionID)}/instructions/entries/${encodeURIComponent(input.key)}`,
|
|
689
|
+
body: { value: input["value"] },
|
|
690
|
+
successStatus: 204,
|
|
691
|
+
declaredStatuses: [400, 401, 404, 413],
|
|
692
|
+
empty: true
|
|
693
|
+
}, requestOptions),
|
|
694
|
+
remove: (input, requestOptions) => request({
|
|
695
|
+
method: "DELETE",
|
|
696
|
+
path: `/api/experimental/session/${encodeURIComponent(input.sessionID)}/instructions/entries/${encodeURIComponent(input.key)}`,
|
|
697
|
+
successStatus: 204,
|
|
698
|
+
declaredStatuses: [400, 401, 404],
|
|
699
|
+
empty: true
|
|
700
|
+
}, requestOptions)
|
|
701
|
+
}
|
|
702
|
+
},
|
|
703
|
+
generate: (input, requestOptions) => request({
|
|
704
|
+
method: "POST",
|
|
705
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/generate`,
|
|
706
|
+
body: { prompt: input["prompt"] },
|
|
707
|
+
successStatus: 200,
|
|
708
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
709
|
+
empty: false
|
|
710
|
+
}, requestOptions).then((value) => value.data),
|
|
711
|
+
log: (input, requestOptions) => sse({
|
|
712
|
+
method: "GET",
|
|
713
|
+
path: `/api/experimental/session/${encodeURIComponent(input.sessionID)}/log`,
|
|
714
|
+
query: { after: input["after"], follow: input["follow"] },
|
|
715
|
+
successStatus: 200,
|
|
716
|
+
declaredStatuses: [400, 401, 404],
|
|
717
|
+
empty: false
|
|
718
|
+
}, requestOptions),
|
|
719
|
+
interrupt: (input, requestOptions) => request({
|
|
720
|
+
method: "POST",
|
|
721
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/interrupt`,
|
|
722
|
+
query: { resume: input["resume"] },
|
|
723
|
+
successStatus: 200,
|
|
724
|
+
declaredStatuses: [400, 401, 404],
|
|
725
|
+
empty: false
|
|
726
|
+
}, requestOptions),
|
|
727
|
+
background: (input, requestOptions) => request({
|
|
728
|
+
method: "POST",
|
|
729
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/background`,
|
|
730
|
+
successStatus: 204,
|
|
731
|
+
declaredStatuses: [400, 401, 404],
|
|
732
|
+
empty: true
|
|
733
|
+
}, requestOptions),
|
|
734
|
+
message: {
|
|
735
|
+
get: (input, requestOptions) => request({
|
|
736
|
+
method: "GET",
|
|
737
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/message/${encodeURIComponent(input.messageID)}`,
|
|
738
|
+
successStatus: 200,
|
|
739
|
+
declaredStatuses: [400, 401, 404],
|
|
740
|
+
empty: false
|
|
741
|
+
}, requestOptions).then((value) => value.data)
|
|
742
|
+
},
|
|
743
|
+
form: {
|
|
744
|
+
list: (input, requestOptions) => request({
|
|
745
|
+
method: "GET",
|
|
746
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/form`,
|
|
747
|
+
successStatus: 200,
|
|
748
|
+
declaredStatuses: [400, 401, 404],
|
|
749
|
+
empty: false
|
|
750
|
+
}, requestOptions).then((value) => value.data),
|
|
751
|
+
create: (input, requestOptions) => request({
|
|
752
|
+
method: "POST",
|
|
753
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/form`,
|
|
754
|
+
body: { id: input["id"], title: input["title"], metadata: input["metadata"], fields: input["fields"] },
|
|
755
|
+
successStatus: 200,
|
|
756
|
+
declaredStatuses: [400, 401, 404, 409],
|
|
757
|
+
empty: false
|
|
758
|
+
}, requestOptions).then((value) => value.data),
|
|
759
|
+
get: (input, requestOptions) => request({
|
|
760
|
+
method: "GET",
|
|
761
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/form/${encodeURIComponent(input.formID)}`,
|
|
762
|
+
successStatus: 200,
|
|
763
|
+
declaredStatuses: [400, 401, 404],
|
|
764
|
+
empty: false
|
|
765
|
+
}, requestOptions).then((value) => value.data),
|
|
766
|
+
reply: (input, requestOptions) => request({
|
|
767
|
+
method: "POST",
|
|
768
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/form/${encodeURIComponent(input.formID)}/reply`,
|
|
769
|
+
body: { answer: input["answer"] },
|
|
770
|
+
successStatus: 204,
|
|
771
|
+
declaredStatuses: [400, 401, 404, 409],
|
|
772
|
+
empty: true
|
|
773
|
+
}, requestOptions),
|
|
774
|
+
cancel: (input, requestOptions) => request({
|
|
775
|
+
method: "DELETE",
|
|
776
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/form/${encodeURIComponent(input.formID)}`,
|
|
777
|
+
query: { message: input["message"] },
|
|
778
|
+
successStatus: 204,
|
|
779
|
+
declaredStatuses: [400, 401, 404, 409],
|
|
780
|
+
empty: true
|
|
781
|
+
}, requestOptions)
|
|
782
|
+
},
|
|
783
|
+
environment: (input, requestOptions) => request({
|
|
784
|
+
method: "PUT",
|
|
785
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/environment`,
|
|
786
|
+
body: { variables: input["variables"] },
|
|
787
|
+
successStatus: 204,
|
|
788
|
+
declaredStatuses: [400, 401, 404],
|
|
789
|
+
empty: true
|
|
790
|
+
}, requestOptions),
|
|
791
|
+
view: (input, requestOptions) => request({
|
|
792
|
+
method: "POST",
|
|
793
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/view`,
|
|
794
|
+
body: { idle: input["idle"] },
|
|
795
|
+
successStatus: 204,
|
|
796
|
+
declaredStatuses: [400, 401, 404],
|
|
797
|
+
empty: true
|
|
798
|
+
}, requestOptions)
|
|
799
|
+
},
|
|
800
|
+
message: {
|
|
801
|
+
list: (input, requestOptions) => request({
|
|
802
|
+
method: "GET",
|
|
803
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/message`,
|
|
804
|
+
query: { limit: input["limit"], order: input["order"], cursor: input["cursor"], type: input["type"] },
|
|
805
|
+
successStatus: 200,
|
|
806
|
+
declaredStatuses: [400, 401, 404, 500],
|
|
807
|
+
empty: false
|
|
808
|
+
}, requestOptions)
|
|
809
|
+
},
|
|
810
|
+
model: {
|
|
811
|
+
list: (input, requestOptions) => request({
|
|
812
|
+
method: "GET",
|
|
813
|
+
path: `/api/model`,
|
|
814
|
+
query: { location: input?.["location"] },
|
|
815
|
+
successStatus: 200,
|
|
816
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
817
|
+
empty: false
|
|
818
|
+
}, requestOptions),
|
|
819
|
+
default: (input, requestOptions) => request({
|
|
820
|
+
method: "GET",
|
|
821
|
+
path: `/api/model/default`,
|
|
822
|
+
query: { location: input?.["location"] },
|
|
823
|
+
successStatus: 200,
|
|
824
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
825
|
+
empty: false
|
|
826
|
+
}, requestOptions)
|
|
827
|
+
},
|
|
828
|
+
generate: {
|
|
829
|
+
text: (input, requestOptions) => request({
|
|
830
|
+
method: "POST",
|
|
831
|
+
path: `/api/experimental/generate`,
|
|
832
|
+
body: { prompt: input["prompt"], model: input["model"] },
|
|
833
|
+
successStatus: 200,
|
|
834
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
835
|
+
empty: false
|
|
836
|
+
}, requestOptions).then((value) => value.data)
|
|
837
|
+
},
|
|
838
|
+
provider: {
|
|
839
|
+
list: (input, requestOptions) => request({
|
|
840
|
+
method: "GET",
|
|
841
|
+
path: `/api/provider`,
|
|
842
|
+
query: { location: input?.["location"] },
|
|
843
|
+
successStatus: 200,
|
|
844
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
845
|
+
empty: false
|
|
846
|
+
}, requestOptions),
|
|
847
|
+
get: (input, requestOptions) => request({
|
|
848
|
+
method: "GET",
|
|
849
|
+
path: `/api/provider/${encodeURIComponent(input.providerID)}`,
|
|
850
|
+
query: { location: input["location"] },
|
|
851
|
+
successStatus: 200,
|
|
852
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
853
|
+
empty: false
|
|
854
|
+
}, requestOptions)
|
|
855
|
+
},
|
|
856
|
+
integration: {
|
|
857
|
+
list: (input, requestOptions) => request({
|
|
858
|
+
method: "GET",
|
|
859
|
+
path: `/api/integration`,
|
|
860
|
+
query: { location: input?.["location"] },
|
|
861
|
+
successStatus: 200,
|
|
862
|
+
declaredStatuses: [400, 401, 404],
|
|
863
|
+
empty: false
|
|
864
|
+
}, requestOptions),
|
|
865
|
+
get: (input, requestOptions) => request({
|
|
866
|
+
method: "GET",
|
|
867
|
+
path: `/api/integration/${encodeURIComponent(input.integrationID)}`,
|
|
868
|
+
query: { location: input["location"] },
|
|
869
|
+
successStatus: 200,
|
|
870
|
+
declaredStatuses: [400, 401, 404],
|
|
871
|
+
empty: false
|
|
872
|
+
}, requestOptions),
|
|
873
|
+
wellknown: {
|
|
874
|
+
add: (input, requestOptions) => request({
|
|
875
|
+
method: "POST",
|
|
876
|
+
path: `/api/experimental/integration/wellknown`,
|
|
877
|
+
query: { location: input["location"] },
|
|
878
|
+
body: { url: input["url"] },
|
|
879
|
+
successStatus: 204,
|
|
880
|
+
declaredStatuses: [400, 401, 404],
|
|
881
|
+
empty: true
|
|
882
|
+
}, requestOptions)
|
|
883
|
+
},
|
|
884
|
+
connect: {
|
|
885
|
+
key: (input, requestOptions) => request({
|
|
886
|
+
method: "POST",
|
|
887
|
+
path: `/api/integration/${encodeURIComponent(input.integrationID)}/connect/key`,
|
|
888
|
+
query: { location: input["location"] },
|
|
889
|
+
body: { key: input["key"], answer: input["answer"], label: input["label"] },
|
|
890
|
+
successStatus: 204,
|
|
891
|
+
declaredStatuses: [400, 401, 404],
|
|
892
|
+
empty: true
|
|
893
|
+
}, requestOptions),
|
|
894
|
+
external: (input, requestOptions) => request({
|
|
895
|
+
method: "POST",
|
|
896
|
+
path: `/api/integration/${encodeURIComponent(input.integrationID)}/connect/external`,
|
|
897
|
+
query: { location: input["location"] },
|
|
898
|
+
body: { methodID: input["methodID"], answer: input["answer"], label: input["label"] },
|
|
899
|
+
successStatus: 204,
|
|
900
|
+
declaredStatuses: [400, 401, 404],
|
|
901
|
+
empty: true
|
|
902
|
+
}, requestOptions)
|
|
903
|
+
},
|
|
904
|
+
oauth: {
|
|
905
|
+
connect: (input, requestOptions) => request({
|
|
906
|
+
method: "POST",
|
|
907
|
+
path: `/api/integration/${encodeURIComponent(input.integrationID)}/connect/oauth`,
|
|
908
|
+
query: { location: input["location"] },
|
|
909
|
+
body: { methodID: input["methodID"], answer: input["answer"], label: input["label"] },
|
|
910
|
+
successStatus: 200,
|
|
911
|
+
declaredStatuses: [400, 401, 404],
|
|
912
|
+
empty: false
|
|
913
|
+
}, requestOptions),
|
|
914
|
+
status: (input, requestOptions) => request({
|
|
915
|
+
method: "GET",
|
|
916
|
+
path: `/api/integration/${encodeURIComponent(input.integrationID)}/connect/oauth/${encodeURIComponent(input.attemptID)}`,
|
|
917
|
+
query: { location: input["location"] },
|
|
918
|
+
successStatus: 200,
|
|
919
|
+
declaredStatuses: [400, 401, 404],
|
|
920
|
+
empty: false
|
|
921
|
+
}, requestOptions),
|
|
922
|
+
complete: (input, requestOptions) => request({
|
|
923
|
+
method: "POST",
|
|
924
|
+
path: `/api/integration/${encodeURIComponent(input.integrationID)}/connect/oauth/${encodeURIComponent(input.attemptID)}/complete`,
|
|
925
|
+
query: { location: input["location"] },
|
|
926
|
+
body: { code: input["code"] },
|
|
927
|
+
successStatus: 204,
|
|
928
|
+
declaredStatuses: [400, 401, 404],
|
|
929
|
+
empty: true
|
|
930
|
+
}, requestOptions),
|
|
931
|
+
cancel: (input, requestOptions) => request({
|
|
932
|
+
method: "DELETE",
|
|
933
|
+
path: `/api/integration/${encodeURIComponent(input.integrationID)}/connect/oauth/${encodeURIComponent(input.attemptID)}`,
|
|
934
|
+
query: { location: input["location"] },
|
|
935
|
+
successStatus: 204,
|
|
936
|
+
declaredStatuses: [400, 401, 404],
|
|
937
|
+
empty: true
|
|
938
|
+
}, requestOptions)
|
|
939
|
+
},
|
|
940
|
+
command: {
|
|
941
|
+
connect: (input, requestOptions) => request({
|
|
942
|
+
method: "POST",
|
|
943
|
+
path: `/api/integration/${encodeURIComponent(input.integrationID)}/connect/command`,
|
|
944
|
+
query: { location: input["location"] },
|
|
945
|
+
body: { methodID: input["methodID"], label: input["label"] },
|
|
946
|
+
successStatus: 200,
|
|
947
|
+
declaredStatuses: [400, 401, 404],
|
|
948
|
+
empty: false
|
|
949
|
+
}, requestOptions),
|
|
950
|
+
status: (input, requestOptions) => request({
|
|
951
|
+
method: "GET",
|
|
952
|
+
path: `/api/integration/${encodeURIComponent(input.integrationID)}/connect/command/${encodeURIComponent(input.attemptID)}`,
|
|
953
|
+
query: { location: input["location"] },
|
|
954
|
+
successStatus: 200,
|
|
955
|
+
declaredStatuses: [400, 401, 404],
|
|
956
|
+
empty: false
|
|
957
|
+
}, requestOptions),
|
|
958
|
+
cancel: (input, requestOptions) => request({
|
|
959
|
+
method: "DELETE",
|
|
960
|
+
path: `/api/integration/${encodeURIComponent(input.integrationID)}/connect/command/${encodeURIComponent(input.attemptID)}`,
|
|
961
|
+
query: { location: input["location"] },
|
|
962
|
+
successStatus: 204,
|
|
963
|
+
declaredStatuses: [400, 401, 404],
|
|
964
|
+
empty: true
|
|
965
|
+
}, requestOptions)
|
|
966
|
+
}
|
|
967
|
+
},
|
|
968
|
+
mcp: {
|
|
969
|
+
list: (input, requestOptions) => request({
|
|
970
|
+
method: "GET",
|
|
971
|
+
path: `/api/mcp`,
|
|
972
|
+
query: { location: input?.["location"] },
|
|
973
|
+
successStatus: 200,
|
|
974
|
+
declaredStatuses: [400, 401, 404],
|
|
975
|
+
empty: false
|
|
976
|
+
}, requestOptions),
|
|
977
|
+
add: (input, requestOptions) => request({
|
|
978
|
+
method: "PUT",
|
|
979
|
+
path: `/api/experimental/mcp/${encodeURIComponent(input.server)}`,
|
|
980
|
+
query: { location: input["location"] },
|
|
981
|
+
body: { config: input["config"] },
|
|
982
|
+
successStatus: 204,
|
|
983
|
+
declaredStatuses: [400, 401, 404],
|
|
984
|
+
empty: true
|
|
985
|
+
}, requestOptions),
|
|
986
|
+
remove: (input, requestOptions) => request({
|
|
987
|
+
method: "DELETE",
|
|
988
|
+
path: `/api/experimental/mcp/${encodeURIComponent(input.server)}`,
|
|
989
|
+
query: { location: input["location"] },
|
|
990
|
+
successStatus: 204,
|
|
991
|
+
declaredStatuses: [400, 401, 404],
|
|
992
|
+
empty: true
|
|
993
|
+
}, requestOptions),
|
|
994
|
+
connect: (input, requestOptions) => request({
|
|
995
|
+
method: "POST",
|
|
996
|
+
path: `/api/experimental/mcp/${encodeURIComponent(input.server)}/connect`,
|
|
997
|
+
query: { location: input["location"] },
|
|
998
|
+
successStatus: 204,
|
|
999
|
+
declaredStatuses: [400, 401, 404],
|
|
1000
|
+
empty: true
|
|
1001
|
+
}, requestOptions),
|
|
1002
|
+
disconnect: (input, requestOptions) => request({
|
|
1003
|
+
method: "POST",
|
|
1004
|
+
path: `/api/experimental/mcp/${encodeURIComponent(input.server)}/disconnect`,
|
|
1005
|
+
query: { location: input["location"] },
|
|
1006
|
+
successStatus: 204,
|
|
1007
|
+
declaredStatuses: [400, 401, 404],
|
|
1008
|
+
empty: true
|
|
1009
|
+
}, requestOptions),
|
|
1010
|
+
resource: {
|
|
1011
|
+
catalog: (input, requestOptions) => request({
|
|
1012
|
+
method: "GET",
|
|
1013
|
+
path: `/api/mcp/resource`,
|
|
1014
|
+
query: { location: input?.["location"] },
|
|
1015
|
+
successStatus: 200,
|
|
1016
|
+
declaredStatuses: [400, 401, 404],
|
|
1017
|
+
empty: false
|
|
1018
|
+
}, requestOptions)
|
|
1019
|
+
}
|
|
1020
|
+
},
|
|
1021
|
+
credential: {
|
|
1022
|
+
list: (requestOptions) => request({ method: "GET", path: `/api/credential`, successStatus: 200, declaredStatuses: [400, 401], empty: false }, requestOptions).then((value) => value.data),
|
|
1023
|
+
create: (input, requestOptions) => request({
|
|
1024
|
+
method: "POST",
|
|
1025
|
+
path: `/api/credential`,
|
|
1026
|
+
body: {
|
|
1027
|
+
id: input["id"],
|
|
1028
|
+
integrationID: input["integrationID"],
|
|
1029
|
+
label: input["label"],
|
|
1030
|
+
value: input["value"],
|
|
1031
|
+
activate: input["activate"]
|
|
1032
|
+
},
|
|
1033
|
+
successStatus: 200,
|
|
1034
|
+
declaredStatuses: [400, 401, 409],
|
|
1035
|
+
empty: false
|
|
1036
|
+
}, requestOptions).then((value) => value.data),
|
|
1037
|
+
update: (input, requestOptions) => request({
|
|
1038
|
+
method: "PATCH",
|
|
1039
|
+
path: `/api/credential/${encodeURIComponent(input.credentialID)}`,
|
|
1040
|
+
body: { label: input["label"] },
|
|
1041
|
+
successStatus: 204,
|
|
1042
|
+
declaredStatuses: [400, 401],
|
|
1043
|
+
empty: true
|
|
1044
|
+
}, requestOptions),
|
|
1045
|
+
activate: (input, requestOptions) => request({
|
|
1046
|
+
method: "POST",
|
|
1047
|
+
path: `/api/credential/${encodeURIComponent(input.credentialID)}/activate`,
|
|
1048
|
+
successStatus: 204,
|
|
1049
|
+
declaredStatuses: [400, 401],
|
|
1050
|
+
empty: true
|
|
1051
|
+
}, requestOptions),
|
|
1052
|
+
remove: (input, requestOptions) => request({
|
|
1053
|
+
method: "DELETE",
|
|
1054
|
+
path: `/api/credential/${encodeURIComponent(input.credentialID)}`,
|
|
1055
|
+
successStatus: 204,
|
|
1056
|
+
declaredStatuses: [400, 401],
|
|
1057
|
+
empty: true
|
|
1058
|
+
}, requestOptions)
|
|
1059
|
+
},
|
|
1060
|
+
project: {
|
|
1061
|
+
list: (requestOptions) => request({ method: "GET", path: `/api/project`, successStatus: 200, declaredStatuses: [400, 401, 404], empty: false }, requestOptions),
|
|
1062
|
+
update: (input, requestOptions) => request({
|
|
1063
|
+
method: "PATCH",
|
|
1064
|
+
path: `/api/project/${encodeURIComponent(input.projectID)}`,
|
|
1065
|
+
body: {
|
|
1066
|
+
canonical: input["canonical"],
|
|
1067
|
+
name: input["name"],
|
|
1068
|
+
icon: input["icon"],
|
|
1069
|
+
commands: input["commands"]
|
|
1070
|
+
},
|
|
1071
|
+
successStatus: 200,
|
|
1072
|
+
declaredStatuses: [400, 401, 404],
|
|
1073
|
+
empty: false
|
|
1074
|
+
}, requestOptions)
|
|
1075
|
+
},
|
|
1076
|
+
form: {
|
|
1077
|
+
list: (input, requestOptions) => request({
|
|
1078
|
+
method: "GET",
|
|
1079
|
+
path: `/api/form`,
|
|
1080
|
+
query: { location: input?.["location"] },
|
|
1081
|
+
successStatus: 200,
|
|
1082
|
+
declaredStatuses: [400, 401, 404],
|
|
1083
|
+
empty: false
|
|
1084
|
+
}, requestOptions)
|
|
1085
|
+
},
|
|
1086
|
+
permission: {
|
|
1087
|
+
request: {
|
|
1088
|
+
list: (input, requestOptions) => request({
|
|
1089
|
+
method: "GET",
|
|
1090
|
+
path: `/api/permission/request`,
|
|
1091
|
+
query: { location: input?.["location"] },
|
|
1092
|
+
successStatus: 200,
|
|
1093
|
+
declaredStatuses: [400, 401, 404],
|
|
1094
|
+
empty: false
|
|
1095
|
+
}, requestOptions)
|
|
1096
|
+
},
|
|
1097
|
+
saved: {
|
|
1098
|
+
list: (input, requestOptions) => request({
|
|
1099
|
+
method: "GET",
|
|
1100
|
+
path: `/api/permission/saved`,
|
|
1101
|
+
query: { projectID: input?.["projectID"] },
|
|
1102
|
+
successStatus: 200,
|
|
1103
|
+
declaredStatuses: [400, 401, 404],
|
|
1104
|
+
empty: false
|
|
1105
|
+
}, requestOptions).then((value) => value.data),
|
|
1106
|
+
remove: (input, requestOptions) => request({
|
|
1107
|
+
method: "DELETE",
|
|
1108
|
+
path: `/api/permission/saved/${encodeURIComponent(input.id)}`,
|
|
1109
|
+
successStatus: 204,
|
|
1110
|
+
declaredStatuses: [400, 401, 404],
|
|
1111
|
+
empty: true
|
|
1112
|
+
}, requestOptions)
|
|
1113
|
+
},
|
|
1114
|
+
create: (input, requestOptions) => request({
|
|
1115
|
+
method: "POST",
|
|
1116
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/permission`,
|
|
1117
|
+
body: {
|
|
1118
|
+
id: input["id"],
|
|
1119
|
+
action: input["action"],
|
|
1120
|
+
resources: input["resources"],
|
|
1121
|
+
save: input["save"],
|
|
1122
|
+
metadata: input["metadata"],
|
|
1123
|
+
source: input["source"],
|
|
1124
|
+
agent: input["agent"]
|
|
1125
|
+
},
|
|
1126
|
+
successStatus: 200,
|
|
1127
|
+
declaredStatuses: [400, 401, 404],
|
|
1128
|
+
empty: false
|
|
1129
|
+
}, requestOptions).then((value) => value.data),
|
|
1130
|
+
list: (input, requestOptions) => request({
|
|
1131
|
+
method: "GET",
|
|
1132
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/permission`,
|
|
1133
|
+
successStatus: 200,
|
|
1134
|
+
declaredStatuses: [400, 401, 404],
|
|
1135
|
+
empty: false
|
|
1136
|
+
}, requestOptions).then((value) => value.data),
|
|
1137
|
+
get: (input, requestOptions) => request({
|
|
1138
|
+
method: "GET",
|
|
1139
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/permission/${encodeURIComponent(input.requestID)}`,
|
|
1140
|
+
successStatus: 200,
|
|
1141
|
+
declaredStatuses: [400, 401, 404],
|
|
1142
|
+
empty: false
|
|
1143
|
+
}, requestOptions).then((value) => value.data),
|
|
1144
|
+
reply: (input, requestOptions) => request({
|
|
1145
|
+
method: "POST",
|
|
1146
|
+
path: `/api/session/${encodeURIComponent(input.sessionID)}/permission/${encodeURIComponent(input.requestID)}/reply`,
|
|
1147
|
+
body: { decision: input["decision"], message: input["message"] },
|
|
1148
|
+
successStatus: 204,
|
|
1149
|
+
declaredStatuses: [400, 401, 404],
|
|
1150
|
+
empty: true
|
|
1151
|
+
}, requestOptions)
|
|
1152
|
+
},
|
|
1153
|
+
file: {
|
|
1154
|
+
read: (input, requestOptions) => request({
|
|
1155
|
+
method: "GET",
|
|
1156
|
+
path: `/api/fs/read/${encodePath(input.path)}`,
|
|
1157
|
+
query: { location: input["location"] },
|
|
1158
|
+
successStatus: 200,
|
|
1159
|
+
declaredStatuses: [400, 401, 404],
|
|
1160
|
+
empty: false,
|
|
1161
|
+
binary: true
|
|
1162
|
+
}, requestOptions),
|
|
1163
|
+
list: (input, requestOptions) => request({
|
|
1164
|
+
method: "GET",
|
|
1165
|
+
path: `/api/fs/list`,
|
|
1166
|
+
query: { location: input?.["location"], path: input?.["path"] },
|
|
1167
|
+
successStatus: 200,
|
|
1168
|
+
declaredStatuses: [400, 401, 404],
|
|
1169
|
+
empty: false
|
|
1170
|
+
}, requestOptions),
|
|
1171
|
+
find: (input, requestOptions) => request({
|
|
1172
|
+
method: "GET",
|
|
1173
|
+
path: `/api/fs/find`,
|
|
1174
|
+
query: { location: input["location"], query: input["query"], type: input["type"], limit: input["limit"] },
|
|
1175
|
+
successStatus: 200,
|
|
1176
|
+
declaredStatuses: [400, 401, 404],
|
|
1177
|
+
empty: false
|
|
1178
|
+
}, requestOptions),
|
|
1179
|
+
write: (input, requestOptions) => request({
|
|
1180
|
+
method: "POST",
|
|
1181
|
+
path: `/api/experimental/fs/write`,
|
|
1182
|
+
query: { location: input["location"], path: input["path"] },
|
|
1183
|
+
body: input["payload"],
|
|
1184
|
+
successStatus: 200,
|
|
1185
|
+
declaredStatuses: [400, 401, 404],
|
|
1186
|
+
empty: false,
|
|
1187
|
+
binaryBody: true
|
|
1188
|
+
}, requestOptions)
|
|
1189
|
+
},
|
|
1190
|
+
command: {
|
|
1191
|
+
list: (input, requestOptions) => request({
|
|
1192
|
+
method: "GET",
|
|
1193
|
+
path: `/api/command`,
|
|
1194
|
+
query: { location: input?.["location"] },
|
|
1195
|
+
successStatus: 200,
|
|
1196
|
+
declaredStatuses: [400, 401, 404],
|
|
1197
|
+
empty: false
|
|
1198
|
+
}, requestOptions)
|
|
1199
|
+
},
|
|
1200
|
+
skill: {
|
|
1201
|
+
list: (input, requestOptions) => request({
|
|
1202
|
+
method: "GET",
|
|
1203
|
+
path: `/api/skill`,
|
|
1204
|
+
query: { location: input?.["location"] },
|
|
1205
|
+
successStatus: 200,
|
|
1206
|
+
declaredStatuses: [400, 401, 404],
|
|
1207
|
+
empty: false
|
|
1208
|
+
}, requestOptions)
|
|
1209
|
+
},
|
|
1210
|
+
rpc: {
|
|
1211
|
+
call: (input, requestOptions) => request({
|
|
1212
|
+
method: "POST",
|
|
1213
|
+
path: `/api/rpc/${encodeURIComponent(input.rpcID)}/${encodeURIComponent(input.method)}`,
|
|
1214
|
+
query: { location: input["location"] },
|
|
1215
|
+
body: { input: input["input"] },
|
|
1216
|
+
successStatus: 200,
|
|
1217
|
+
declaredStatuses: [400, 401, 404, 500],
|
|
1218
|
+
empty: false
|
|
1219
|
+
}, requestOptions)
|
|
1220
|
+
},
|
|
1221
|
+
event: {
|
|
1222
|
+
subscribe: (requestOptions) => sse({ method: "GET", path: `/api/event`, successStatus: 200, declaredStatuses: [400, 401], empty: false }, requestOptions)
|
|
1223
|
+
},
|
|
1224
|
+
pty: {
|
|
1225
|
+
list: (input, requestOptions) => request({
|
|
1226
|
+
method: "GET",
|
|
1227
|
+
path: `/api/pty`,
|
|
1228
|
+
query: { location: input?.["location"] },
|
|
1229
|
+
successStatus: 200,
|
|
1230
|
+
declaredStatuses: [400, 401, 404],
|
|
1231
|
+
empty: false
|
|
1232
|
+
}, requestOptions),
|
|
1233
|
+
create: (input, requestOptions) => request({
|
|
1234
|
+
method: "POST",
|
|
1235
|
+
path: `/api/pty`,
|
|
1236
|
+
query: { location: input?.["location"] },
|
|
1237
|
+
body: {
|
|
1238
|
+
command: input?.["command"],
|
|
1239
|
+
args: input?.["args"],
|
|
1240
|
+
cwd: input?.["cwd"],
|
|
1241
|
+
title: input?.["title"],
|
|
1242
|
+
env: input?.["env"]
|
|
1243
|
+
},
|
|
1244
|
+
successStatus: 200,
|
|
1245
|
+
declaredStatuses: [400, 401, 404],
|
|
1246
|
+
empty: false
|
|
1247
|
+
}, requestOptions),
|
|
1248
|
+
get: (input, requestOptions) => request({
|
|
1249
|
+
method: "GET",
|
|
1250
|
+
path: `/api/pty/${encodeURIComponent(input.ptyID)}`,
|
|
1251
|
+
query: { location: input["location"] },
|
|
1252
|
+
successStatus: 200,
|
|
1253
|
+
declaredStatuses: [400, 401, 404],
|
|
1254
|
+
empty: false
|
|
1255
|
+
}, requestOptions),
|
|
1256
|
+
update: (input, requestOptions) => request({
|
|
1257
|
+
method: "PUT",
|
|
1258
|
+
path: `/api/pty/${encodeURIComponent(input.ptyID)}`,
|
|
1259
|
+
query: { location: input["location"] },
|
|
1260
|
+
body: { title: input["title"], size: input["size"] },
|
|
1261
|
+
successStatus: 200,
|
|
1262
|
+
declaredStatuses: [400, 401, 404],
|
|
1263
|
+
empty: false
|
|
1264
|
+
}, requestOptions),
|
|
1265
|
+
remove: (input, requestOptions) => request({
|
|
1266
|
+
method: "DELETE",
|
|
1267
|
+
path: `/api/pty/${encodeURIComponent(input.ptyID)}`,
|
|
1268
|
+
query: { location: input["location"] },
|
|
1269
|
+
successStatus: 204,
|
|
1270
|
+
declaredStatuses: [400, 401, 404],
|
|
1271
|
+
empty: true
|
|
1272
|
+
}, requestOptions),
|
|
1273
|
+
connect: {
|
|
1274
|
+
token: (input, requestOptions) => request({
|
|
1275
|
+
method: "POST",
|
|
1276
|
+
path: `/api/pty/${encodeURIComponent(input.ptyID)}/connect-token`,
|
|
1277
|
+
query: { location: input["location"] },
|
|
1278
|
+
headers: { "x-opencode-ticket": input["x-opencode-ticket"] },
|
|
1279
|
+
successStatus: 200,
|
|
1280
|
+
declaredStatuses: [400, 401, 403, 404],
|
|
1281
|
+
empty: false
|
|
1282
|
+
}, requestOptions)
|
|
1283
|
+
}
|
|
1284
|
+
},
|
|
1285
|
+
experimental: {
|
|
1286
|
+
persistentPty: {
|
|
1287
|
+
read: (input, requestOptions) => request({
|
|
1288
|
+
method: "GET",
|
|
1289
|
+
path: `/api/experimental/session/${encodeURIComponent(input.sessionID)}/terminal/read`,
|
|
1290
|
+
query: { lines: input["lines"] },
|
|
1291
|
+
successStatus: 200,
|
|
1292
|
+
declaredStatuses: [400, 401, 503],
|
|
1293
|
+
empty: false
|
|
1294
|
+
}, requestOptions).then((value) => value.data),
|
|
1295
|
+
list: (input, requestOptions) => request({
|
|
1296
|
+
method: "GET",
|
|
1297
|
+
path: `/api/experimental/session/${encodeURIComponent(input.sessionID)}/terminal`,
|
|
1298
|
+
successStatus: 200,
|
|
1299
|
+
declaredStatuses: [400, 401, 503],
|
|
1300
|
+
empty: false
|
|
1301
|
+
}, requestOptions).then((value) => value.data),
|
|
1302
|
+
create: (input, requestOptions) => request({
|
|
1303
|
+
method: "POST",
|
|
1304
|
+
path: `/api/experimental/session/${encodeURIComponent(input.sessionID)}/terminal`,
|
|
1305
|
+
body: {
|
|
1306
|
+
command: input["command"],
|
|
1307
|
+
args: input["args"],
|
|
1308
|
+
cwd: input["cwd"],
|
|
1309
|
+
title: input["title"],
|
|
1310
|
+
env: input["env"],
|
|
1311
|
+
size: input["size"]
|
|
1312
|
+
},
|
|
1313
|
+
successStatus: 200,
|
|
1314
|
+
declaredStatuses: [400, 401, 503],
|
|
1315
|
+
empty: false
|
|
1316
|
+
}, requestOptions).then((value) => value.data),
|
|
1317
|
+
shutdown: (requestOptions) => request({
|
|
1318
|
+
method: "POST",
|
|
1319
|
+
path: `/api/experimental/persistent-pty/shutdown`,
|
|
1320
|
+
successStatus: 204,
|
|
1321
|
+
declaredStatuses: [400, 401, 503],
|
|
1322
|
+
empty: true
|
|
1323
|
+
}, requestOptions),
|
|
1324
|
+
handoff: (requestOptions) => request({
|
|
1325
|
+
method: "POST",
|
|
1326
|
+
path: `/api/experimental/persistent-pty/handoff`,
|
|
1327
|
+
successStatus: 200,
|
|
1328
|
+
declaredStatuses: [400, 401, 503],
|
|
1329
|
+
empty: false
|
|
1330
|
+
}, requestOptions),
|
|
1331
|
+
get: (input, requestOptions) => request({
|
|
1332
|
+
method: "GET",
|
|
1333
|
+
path: `/api/experimental/persistent-pty/${encodeURIComponent(input.ptyID)}`,
|
|
1334
|
+
successStatus: 200,
|
|
1335
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
1336
|
+
empty: false
|
|
1337
|
+
}, requestOptions).then((value) => value.data),
|
|
1338
|
+
update: (input, requestOptions) => request({
|
|
1339
|
+
method: "PUT",
|
|
1340
|
+
path: `/api/experimental/persistent-pty/${encodeURIComponent(input.ptyID)}`,
|
|
1341
|
+
body: { attachmentID: input["attachmentID"], size: input["size"] },
|
|
1342
|
+
successStatus: 200,
|
|
1343
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
1344
|
+
empty: false
|
|
1345
|
+
}, requestOptions).then((value) => value.data),
|
|
1346
|
+
snapshot: (input, requestOptions) => request({
|
|
1347
|
+
method: "GET",
|
|
1348
|
+
path: `/api/experimental/persistent-pty/${encodeURIComponent(input.ptyID)}/snapshot`,
|
|
1349
|
+
successStatus: 200,
|
|
1350
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
1351
|
+
empty: false
|
|
1352
|
+
}, requestOptions).then((value) => value.data),
|
|
1353
|
+
remove: (input, requestOptions) => request({
|
|
1354
|
+
method: "DELETE",
|
|
1355
|
+
path: `/api/experimental/persistent-pty/${encodeURIComponent(input.ptyID)}`,
|
|
1356
|
+
successStatus: 204,
|
|
1357
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
1358
|
+
empty: true
|
|
1359
|
+
}, requestOptions),
|
|
1360
|
+
connectToken: (input, requestOptions) => request({
|
|
1361
|
+
method: "POST",
|
|
1362
|
+
path: `/api/experimental/persistent-pty/${encodeURIComponent(input.ptyID)}/connect-token`,
|
|
1363
|
+
headers: { "x-opencode-ticket": input["x-opencode-ticket"] },
|
|
1364
|
+
successStatus: 200,
|
|
1365
|
+
declaredStatuses: [400, 401, 403, 404, 503],
|
|
1366
|
+
empty: false
|
|
1367
|
+
}, requestOptions).then((value) => value.data)
|
|
1368
|
+
}
|
|
1369
|
+
},
|
|
1370
|
+
shell: {
|
|
1371
|
+
list: (input, requestOptions) => request({
|
|
1372
|
+
method: "GET",
|
|
1373
|
+
path: `/api/shell`,
|
|
1374
|
+
query: { location: input?.["location"] },
|
|
1375
|
+
successStatus: 200,
|
|
1376
|
+
declaredStatuses: [400, 401, 404],
|
|
1377
|
+
empty: false
|
|
1378
|
+
}, requestOptions),
|
|
1379
|
+
create: (input, requestOptions) => request({
|
|
1380
|
+
method: "POST",
|
|
1381
|
+
path: `/api/shell`,
|
|
1382
|
+
query: { location: input["location"] },
|
|
1383
|
+
body: {
|
|
1384
|
+
command: input["command"],
|
|
1385
|
+
cwd: input["cwd"],
|
|
1386
|
+
timeout: input["timeout"],
|
|
1387
|
+
metadata: input["metadata"]
|
|
1388
|
+
},
|
|
1389
|
+
successStatus: 200,
|
|
1390
|
+
declaredStatuses: [400, 401, 404],
|
|
1391
|
+
empty: false
|
|
1392
|
+
}, requestOptions),
|
|
1393
|
+
get: (input, requestOptions) => request({
|
|
1394
|
+
method: "GET",
|
|
1395
|
+
path: `/api/shell/${encodeURIComponent(input.id)}`,
|
|
1396
|
+
query: { location: input["location"] },
|
|
1397
|
+
successStatus: 200,
|
|
1398
|
+
declaredStatuses: [400, 401, 404],
|
|
1399
|
+
empty: false
|
|
1400
|
+
}, requestOptions),
|
|
1401
|
+
output: (input, requestOptions) => request({
|
|
1402
|
+
method: "GET",
|
|
1403
|
+
path: `/api/shell/${encodeURIComponent(input.id)}/output`,
|
|
1404
|
+
query: { location: input["location"], cursor: input["cursor"], limit: input["limit"] },
|
|
1405
|
+
successStatus: 200,
|
|
1406
|
+
declaredStatuses: [400, 401, 404],
|
|
1407
|
+
empty: false
|
|
1408
|
+
}, requestOptions),
|
|
1409
|
+
remove: (input, requestOptions) => request({
|
|
1410
|
+
method: "DELETE",
|
|
1411
|
+
path: `/api/shell/${encodeURIComponent(input.id)}`,
|
|
1412
|
+
query: { location: input["location"] },
|
|
1413
|
+
successStatus: 204,
|
|
1414
|
+
declaredStatuses: [400, 401, 404],
|
|
1415
|
+
empty: true
|
|
1416
|
+
}, requestOptions)
|
|
1417
|
+
},
|
|
1418
|
+
reference: {
|
|
1419
|
+
list: (input, requestOptions) => request({
|
|
1420
|
+
method: "GET",
|
|
1421
|
+
path: `/api/reference`,
|
|
1422
|
+
query: { location: input?.["location"] },
|
|
1423
|
+
successStatus: 200,
|
|
1424
|
+
declaredStatuses: [400, 401, 404],
|
|
1425
|
+
empty: false
|
|
1426
|
+
}, requestOptions)
|
|
1427
|
+
},
|
|
1428
|
+
worktree: {
|
|
1429
|
+
list: (input, requestOptions) => request({
|
|
1430
|
+
method: "GET",
|
|
1431
|
+
path: `/api/worktree`,
|
|
1432
|
+
query: { projectID: input["projectID"] },
|
|
1433
|
+
successStatus: 200,
|
|
1434
|
+
declaredStatuses: [400, 401, 404],
|
|
1435
|
+
empty: false
|
|
1436
|
+
}, requestOptions),
|
|
1437
|
+
create: (input, requestOptions) => request({
|
|
1438
|
+
method: "POST",
|
|
1439
|
+
path: `/api/worktree`,
|
|
1440
|
+
body: {
|
|
1441
|
+
projectID: input["projectID"],
|
|
1442
|
+
from: input["from"],
|
|
1443
|
+
branch: input["branch"],
|
|
1444
|
+
directory: input["directory"],
|
|
1445
|
+
name: input["name"]
|
|
1446
|
+
},
|
|
1447
|
+
successStatus: 200,
|
|
1448
|
+
declaredStatuses: [400, 401, 404],
|
|
1449
|
+
empty: false
|
|
1450
|
+
}, requestOptions),
|
|
1451
|
+
remove: (input, requestOptions) => request({
|
|
1452
|
+
method: "DELETE",
|
|
1453
|
+
path: `/api/worktree`,
|
|
1454
|
+
body: { projectID: input["projectID"], directory: input["directory"], force: input["force"] },
|
|
1455
|
+
successStatus: 204,
|
|
1456
|
+
declaredStatuses: [400, 401, 404],
|
|
1457
|
+
empty: true
|
|
1458
|
+
}, requestOptions),
|
|
1459
|
+
refresh: (input, requestOptions) => request({
|
|
1460
|
+
method: "POST",
|
|
1461
|
+
path: `/api/worktree/refresh`,
|
|
1462
|
+
body: { projectID: input["projectID"] },
|
|
1463
|
+
successStatus: 204,
|
|
1464
|
+
declaredStatuses: [400, 401, 404],
|
|
1465
|
+
empty: true
|
|
1466
|
+
}, requestOptions)
|
|
1467
|
+
},
|
|
1468
|
+
vcs: {
|
|
1469
|
+
init: (input, requestOptions) => request({
|
|
1470
|
+
method: "POST",
|
|
1471
|
+
path: `/api/vcs/init`,
|
|
1472
|
+
query: { location: input?.["location"], provider: input?.["provider"] },
|
|
1473
|
+
successStatus: 204,
|
|
1474
|
+
declaredStatuses: [400, 401, 404, 409, 501, 503],
|
|
1475
|
+
empty: true
|
|
1476
|
+
}, requestOptions),
|
|
1477
|
+
get: (input, requestOptions) => request({
|
|
1478
|
+
method: "GET",
|
|
1479
|
+
path: `/api/vcs`,
|
|
1480
|
+
query: { location: input?.["location"] },
|
|
1481
|
+
successStatus: 200,
|
|
1482
|
+
declaredStatuses: [400, 401, 404],
|
|
1483
|
+
empty: false
|
|
1484
|
+
}, requestOptions),
|
|
1485
|
+
base: (input, requestOptions) => request({
|
|
1486
|
+
method: "GET",
|
|
1487
|
+
path: `/api/vcs/base`,
|
|
1488
|
+
query: { location: input?.["location"] },
|
|
1489
|
+
successStatus: 200,
|
|
1490
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
1491
|
+
empty: false
|
|
1492
|
+
}, requestOptions),
|
|
1493
|
+
status: (input, requestOptions) => request({
|
|
1494
|
+
method: "GET",
|
|
1495
|
+
path: `/api/vcs/status`,
|
|
1496
|
+
query: { location: input?.["location"] },
|
|
1497
|
+
successStatus: 200,
|
|
1498
|
+
declaredStatuses: [400, 401, 404],
|
|
1499
|
+
empty: false
|
|
1500
|
+
}, requestOptions),
|
|
1501
|
+
branch: {
|
|
1502
|
+
list: (input, requestOptions) => request({
|
|
1503
|
+
method: "GET",
|
|
1504
|
+
path: `/api/vcs/branch`,
|
|
1505
|
+
query: { location: input?.["location"], search: input?.["search"], limit: input?.["limit"] },
|
|
1506
|
+
successStatus: 200,
|
|
1507
|
+
declaredStatuses: [400, 401, 404],
|
|
1508
|
+
empty: false
|
|
1509
|
+
}, requestOptions)
|
|
1510
|
+
},
|
|
1511
|
+
diff: (input, requestOptions) => request({
|
|
1512
|
+
method: "GET",
|
|
1513
|
+
path: `/api/vcs/diff`,
|
|
1514
|
+
query: { location: input["location"], mode: input["mode"], base: input["base"], context: input["context"] },
|
|
1515
|
+
successStatus: 200,
|
|
1516
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
1517
|
+
empty: false
|
|
1518
|
+
}, requestOptions)
|
|
1519
|
+
},
|
|
1520
|
+
debug: {
|
|
1521
|
+
location: {
|
|
1522
|
+
list: (requestOptions) => request({
|
|
1523
|
+
method: "GET",
|
|
1524
|
+
path: `/api/debug/location`,
|
|
1525
|
+
successStatus: 200,
|
|
1526
|
+
declaredStatuses: [400, 401],
|
|
1527
|
+
empty: false
|
|
1528
|
+
}, requestOptions),
|
|
1529
|
+
evict: (input, requestOptions) => request({
|
|
1530
|
+
method: "DELETE",
|
|
1531
|
+
path: `/api/debug/location`,
|
|
1532
|
+
query: { location: input?.["location"] },
|
|
1533
|
+
successStatus: 204,
|
|
1534
|
+
declaredStatuses: [400, 401],
|
|
1535
|
+
empty: true
|
|
1536
|
+
}, requestOptions)
|
|
1537
|
+
}
|
|
1538
|
+
},
|
|
1539
|
+
migration: {
|
|
1540
|
+
v1: {
|
|
1541
|
+
status: (requestOptions) => request({
|
|
1542
|
+
method: "GET",
|
|
1543
|
+
path: `/api/experimental/migration/v1`,
|
|
1544
|
+
successStatus: 200,
|
|
1545
|
+
declaredStatuses: [400, 401],
|
|
1546
|
+
empty: false
|
|
1547
|
+
}, requestOptions)
|
|
1548
|
+
}
|
|
1549
|
+
},
|
|
1550
|
+
websearch: {
|
|
1551
|
+
providers: (input, requestOptions) => request({
|
|
1552
|
+
method: "GET",
|
|
1553
|
+
path: `/api/websearch/provider`,
|
|
1554
|
+
query: { location: input?.["location"] },
|
|
1555
|
+
successStatus: 200,
|
|
1556
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
1557
|
+
empty: false
|
|
1558
|
+
}, requestOptions),
|
|
1559
|
+
query: (input, requestOptions) => request({
|
|
1560
|
+
method: "POST",
|
|
1561
|
+
path: `/api/websearch`,
|
|
1562
|
+
query: { location: input["location"] },
|
|
1563
|
+
body: { query: input["query"], providerID: input["providerID"] },
|
|
1564
|
+
successStatus: 200,
|
|
1565
|
+
declaredStatuses: [400, 401, 404, 503],
|
|
1566
|
+
empty: false
|
|
1567
|
+
}, requestOptions)
|
|
1568
|
+
},
|
|
1569
|
+
config: {
|
|
1570
|
+
get: (input, requestOptions) => request({
|
|
1571
|
+
method: "GET",
|
|
1572
|
+
path: `/api/config`,
|
|
1573
|
+
query: { location: input?.["location"] },
|
|
1574
|
+
successStatus: 200,
|
|
1575
|
+
declaredStatuses: [400, 401, 404],
|
|
1576
|
+
empty: false
|
|
1577
|
+
}, requestOptions),
|
|
1578
|
+
shells: (requestOptions) => request({
|
|
1579
|
+
method: "GET",
|
|
1580
|
+
path: `/api/config/shell`,
|
|
1581
|
+
successStatus: 200,
|
|
1582
|
+
declaredStatuses: [400, 401, 404],
|
|
1583
|
+
empty: false
|
|
1584
|
+
}, requestOptions),
|
|
1585
|
+
update: (input, requestOptions) => request({
|
|
1586
|
+
method: "PATCH",
|
|
1587
|
+
path: `/api/experimental/config`,
|
|
1588
|
+
body: { shell: input["shell"] },
|
|
1589
|
+
successStatus: 204,
|
|
1590
|
+
declaredStatuses: [400, 401, 404],
|
|
1591
|
+
empty: true
|
|
1592
|
+
}, requestOptions)
|
|
1593
|
+
}
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1596
|
+
function encodePath(value) {
|
|
1597
|
+
return value.split("/").map(encodeURIComponent).join("/");
|
|
1598
|
+
}
|
|
1599
|
+
function appendQuery(params, key, value) {
|
|
1600
|
+
if (value === void 0)
|
|
1601
|
+
return;
|
|
1602
|
+
if (value === null) {
|
|
1603
|
+
params.append(key, "null");
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1606
|
+
if (Array.isArray(value)) {
|
|
1607
|
+
for (const item of value)
|
|
1608
|
+
appendQuery(params, key, item);
|
|
1609
|
+
return;
|
|
1610
|
+
}
|
|
1611
|
+
if (typeof value === "object") {
|
|
1612
|
+
for (const [child, item] of Object.entries(value))
|
|
1613
|
+
appendQuery(params, `${key}[${child}]`, item);
|
|
1614
|
+
return;
|
|
1615
|
+
}
|
|
1616
|
+
params.append(key, String(value));
|
|
1617
|
+
}
|
|
1618
|
+
async function json2(response) {
|
|
1619
|
+
if (!isContentType(response, "application/json") && !response.headers.get("content-type")?.includes("+json")) {
|
|
1620
|
+
try {
|
|
1621
|
+
await response.body?.cancel();
|
|
1622
|
+
} catch {
|
|
1623
|
+
}
|
|
1624
|
+
throw new ClientError2("UnsupportedContentType", { detail: response.headers.get("content-type") });
|
|
1625
|
+
}
|
|
1626
|
+
let text;
|
|
1627
|
+
try {
|
|
1628
|
+
text = await response.text();
|
|
1629
|
+
} catch (cause) {
|
|
1630
|
+
throw new ClientError2("Transport", { cause });
|
|
1631
|
+
}
|
|
1632
|
+
if (text === "")
|
|
1633
|
+
throw new ClientError2("MalformedResponse");
|
|
1634
|
+
try {
|
|
1635
|
+
return JSON.parse(text);
|
|
1636
|
+
} catch (cause) {
|
|
1637
|
+
throw new ClientError2("MalformedResponse", { cause });
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
function declared(body) {
|
|
1641
|
+
const error = Object.assign(new Error(body.message ?? body.data?.message), body);
|
|
1642
|
+
if (body._tag)
|
|
1643
|
+
error.name = body._tag;
|
|
1644
|
+
return error;
|
|
1645
|
+
}
|
|
1646
|
+
function isContentType(response, expected) {
|
|
1647
|
+
return response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() === expected;
|
|
1648
|
+
}
|
|
1649
|
+
var exports_client2, maxSseEventBytes;
|
|
1650
|
+
var init_service_timing_tbh3h57v = __esm({
|
|
1651
|
+
"node_modules/@opencode/client/dist/chunks/service-timing-tbh3h57v.js"() {
|
|
1652
|
+
init_service_timing_js54wxgp();
|
|
1653
|
+
init_service_timing_9rqn6x4v();
|
|
1654
|
+
exports_client2 = {};
|
|
1655
|
+
__export2(exports_client2, {
|
|
1656
|
+
make: () => make3
|
|
1657
|
+
});
|
|
1658
|
+
maxSseEventBytes = 16 * 1024 * 1024;
|
|
1659
|
+
}
|
|
1660
|
+
});
|
|
1661
|
+
|
|
1662
|
+
// node_modules/@opencode/client/dist/chunks/service-timing-vt9jbch8.js
|
|
1663
|
+
var isInvalidRequestError2, isUnauthorizedError2, isLocationNotFoundError2, isServiceUnavailableError2, isAgentNotFoundError2, isInvalidCursorError2, isSessionNotFoundError2, isConflictError2, isUnknownError2, isMessageNotFoundError2, isCommandNotFoundError2, isCommandExecutionError2, isSkillNotFoundError2, isSessionBusyError2, isInstructionEntryValueTooLargeError2, isFormNotFoundError2, isFormInvalidAnswerError2, isFormAlreadySettledError2, isProviderNotFoundError2, isIntegrationNotFoundError2, isIntegrationAttemptNotFoundError2, isIntegrationMethodNotFoundError2, isMcpServerNotFoundError2, isProjectNotFoundError2, isPermissionNotFoundError2, isFileNotFoundError2, isRpcError2, isRpcInternalError2, isPtyNotFoundError2, isForbiddenError2, isShellNotFoundError2, isWorktreeError2, isVcsInitNotSupportedError2;
|
|
1664
|
+
var init_service_timing_vt9jbch8 = __esm({
|
|
1665
|
+
"node_modules/@opencode/client/dist/chunks/service-timing-vt9jbch8.js"() {
|
|
1666
|
+
isInvalidRequestError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "InvalidRequestError";
|
|
1667
|
+
isUnauthorizedError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "UnauthorizedError";
|
|
1668
|
+
isLocationNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "LocationNotFoundError";
|
|
1669
|
+
isServiceUnavailableError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ServiceUnavailableError";
|
|
1670
|
+
isAgentNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "AgentNotFoundError";
|
|
1671
|
+
isInvalidCursorError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "InvalidCursorError";
|
|
1672
|
+
isSessionNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "SessionNotFoundError";
|
|
1673
|
+
isConflictError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ConflictError";
|
|
1674
|
+
isUnknownError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "UnknownError";
|
|
1675
|
+
isMessageNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "MessageNotFoundError";
|
|
1676
|
+
isCommandNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "CommandNotFoundError";
|
|
1677
|
+
isCommandExecutionError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "CommandExecutionError";
|
|
1678
|
+
isSkillNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "SkillNotFoundError";
|
|
1679
|
+
isSessionBusyError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "SessionBusyError";
|
|
1680
|
+
isInstructionEntryValueTooLargeError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "InstructionEntryValueTooLargeError";
|
|
1681
|
+
isFormNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "FormNotFoundError";
|
|
1682
|
+
isFormInvalidAnswerError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "FormInvalidAnswerError";
|
|
1683
|
+
isFormAlreadySettledError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "FormAlreadySettledError";
|
|
1684
|
+
isProviderNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ProviderNotFoundError";
|
|
1685
|
+
isIntegrationNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "IntegrationNotFoundError";
|
|
1686
|
+
isIntegrationAttemptNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "IntegrationAttemptNotFoundError";
|
|
1687
|
+
isIntegrationMethodNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "IntegrationMethodNotFoundError";
|
|
1688
|
+
isMcpServerNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "McpServerNotFoundError";
|
|
1689
|
+
isProjectNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ProjectNotFoundError";
|
|
1690
|
+
isPermissionNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "PermissionNotFoundError";
|
|
1691
|
+
isFileNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "FileNotFoundError";
|
|
1692
|
+
isRpcError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "RpcError";
|
|
1693
|
+
isRpcInternalError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "RpcInternalError";
|
|
1694
|
+
isPtyNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "PtyNotFoundError";
|
|
1695
|
+
isForbiddenError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ForbiddenError";
|
|
1696
|
+
isShellNotFoundError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "ShellNotFoundError";
|
|
1697
|
+
isWorktreeError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "WorktreeError";
|
|
1698
|
+
isVcsInitNotSupportedError2 = (value) => typeof value === "object" && value !== null && "_tag" in value && value["_tag"] === "VcsInitNotSupportedError";
|
|
1699
|
+
}
|
|
1700
|
+
});
|
|
1701
|
+
|
|
1702
|
+
// node_modules/@opencode/client/dist/chunks/service-timing-1y4a697q.js
|
|
1703
|
+
function makeRpc2(raw, events) {
|
|
1704
|
+
return (definition) => {
|
|
1705
|
+
const subscribe = (name, options) => {
|
|
1706
|
+
if (!Object.hasOwn(definition.events, name))
|
|
1707
|
+
throw new Error(`Unknown RPC event: ${definition.id}.${name}`);
|
|
1708
|
+
const type = eventType(definition, name);
|
|
1709
|
+
return {
|
|
1710
|
+
[Symbol.asyncIterator]() {
|
|
1711
|
+
const controller = new AbortController();
|
|
1712
|
+
const signal2 = options?.signal ? AbortSignal.any([controller.signal, options.signal]) : controller.signal;
|
|
1713
|
+
const iterator = (async function* () {
|
|
1714
|
+
try {
|
|
1715
|
+
for await (const published of events.subscribe({ signal: signal2 })) {
|
|
1716
|
+
if (signal2.aborted)
|
|
1717
|
+
return;
|
|
1718
|
+
if (published.type !== type)
|
|
1719
|
+
continue;
|
|
1720
|
+
yield published;
|
|
1721
|
+
}
|
|
1722
|
+
} catch (error) {
|
|
1723
|
+
if (!signal2.aborted)
|
|
1724
|
+
throw error;
|
|
1725
|
+
} finally {
|
|
1726
|
+
controller.abort();
|
|
1727
|
+
}
|
|
1728
|
+
})();
|
|
1729
|
+
return {
|
|
1730
|
+
next: () => iterator.next(),
|
|
1731
|
+
return: () => {
|
|
1732
|
+
controller.abort();
|
|
1733
|
+
return iterator.return();
|
|
1734
|
+
}
|
|
1735
|
+
};
|
|
1736
|
+
}
|
|
1737
|
+
};
|
|
1738
|
+
};
|
|
1739
|
+
return Object.assign(Object.fromEntries(Object.keys(definition.methods).map((name) => [
|
|
1740
|
+
name,
|
|
1741
|
+
async (input, options) => {
|
|
1742
|
+
try {
|
|
1743
|
+
const result = await raw.rpc.call({
|
|
1744
|
+
rpcID: definition.id,
|
|
1745
|
+
method: name,
|
|
1746
|
+
input,
|
|
1747
|
+
location: options?.location
|
|
1748
|
+
}, { signal: options?.signal, headers: options?.headers });
|
|
1749
|
+
return result.output;
|
|
1750
|
+
} catch (error) {
|
|
1751
|
+
if (!isRpcError2(error) && !isRpcInternalError2(error))
|
|
1752
|
+
throw error;
|
|
1753
|
+
throw error.data === void 0 ? { type: error.type, message: error.message } : { type: error.type, message: error.message, data: error.data };
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
])), {
|
|
1757
|
+
events: {
|
|
1758
|
+
subscribe,
|
|
1759
|
+
on: (name, handler, options) => {
|
|
1760
|
+
const controller = new AbortController();
|
|
1761
|
+
const signal2 = options?.signal ? AbortSignal.any([controller.signal, options.signal]) : controller.signal;
|
|
1762
|
+
const source = subscribe(name, { signal: signal2 });
|
|
1763
|
+
(async () => {
|
|
1764
|
+
for await (const event of source)
|
|
1765
|
+
await handler(event);
|
|
1766
|
+
})().catch((error) => console.error(error));
|
|
1767
|
+
return () => controller.abort();
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
});
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
function eventType(definition, name) {
|
|
1774
|
+
return `rpc.${definition.id}.${name}`;
|
|
1775
|
+
}
|
|
1776
|
+
var init_service_timing_1y4a697q = __esm({
|
|
1777
|
+
"node_modules/@opencode/client/dist/chunks/service-timing-1y4a697q.js"() {
|
|
1778
|
+
init_service_timing_vt9jbch8();
|
|
1779
|
+
}
|
|
1780
|
+
});
|
|
1781
|
+
|
|
1782
|
+
// node_modules/@opencode/client/dist/chunks/service-timing-e4sc9kq6.js
|
|
1783
|
+
function make2(options) {
|
|
1784
|
+
const raw = make3(options);
|
|
1785
|
+
const events = make7((signal2, onActivity) => raw.event.subscribe({ signal: signal2, onActivity }));
|
|
1786
|
+
return {
|
|
1787
|
+
...raw,
|
|
1788
|
+
rpc: Object.assign(makeRpc2(raw, events), raw.rpc),
|
|
1789
|
+
event: events
|
|
1790
|
+
};
|
|
1791
|
+
}
|
|
1792
|
+
var exports_client;
|
|
1793
|
+
var init_service_timing_e4sc9kq6 = __esm({
|
|
1794
|
+
"node_modules/@opencode/client/dist/chunks/service-timing-e4sc9kq6.js"() {
|
|
1795
|
+
init_service_timing_frbwqjmf();
|
|
1796
|
+
init_service_timing_tbh3h57v();
|
|
1797
|
+
init_service_timing_1y4a697q();
|
|
1798
|
+
init_service_timing_9rqn6x4v();
|
|
1799
|
+
exports_client = {};
|
|
1800
|
+
__export2(exports_client, {
|
|
1801
|
+
OpenCode: () => exports_client,
|
|
1802
|
+
make: () => make2
|
|
1803
|
+
});
|
|
1804
|
+
}
|
|
1805
|
+
});
|
|
1806
|
+
|
|
1807
|
+
// node_modules/@opencode/client/dist/promise/index.js
|
|
1808
|
+
var promise_exports = {};
|
|
1809
|
+
__export(promise_exports, {
|
|
1810
|
+
ClientError: () => ClientError2,
|
|
1811
|
+
OpenCode: () => exports_client,
|
|
1812
|
+
isAgentNotFoundError: () => isAgentNotFoundError2,
|
|
1813
|
+
isCommandExecutionError: () => isCommandExecutionError2,
|
|
1814
|
+
isCommandNotFoundError: () => isCommandNotFoundError2,
|
|
1815
|
+
isConflictError: () => isConflictError2,
|
|
1816
|
+
isFileNotFoundError: () => isFileNotFoundError2,
|
|
1817
|
+
isForbiddenError: () => isForbiddenError2,
|
|
1818
|
+
isFormAlreadySettledError: () => isFormAlreadySettledError2,
|
|
1819
|
+
isFormInvalidAnswerError: () => isFormInvalidAnswerError2,
|
|
1820
|
+
isFormNotFoundError: () => isFormNotFoundError2,
|
|
1821
|
+
isInstructionEntryValueTooLargeError: () => isInstructionEntryValueTooLargeError2,
|
|
1822
|
+
isIntegrationAttemptNotFoundError: () => isIntegrationAttemptNotFoundError2,
|
|
1823
|
+
isIntegrationMethodNotFoundError: () => isIntegrationMethodNotFoundError2,
|
|
1824
|
+
isIntegrationNotFoundError: () => isIntegrationNotFoundError2,
|
|
1825
|
+
isInvalidCursorError: () => isInvalidCursorError2,
|
|
1826
|
+
isInvalidRequestError: () => isInvalidRequestError2,
|
|
1827
|
+
isLocationNotFoundError: () => isLocationNotFoundError2,
|
|
1828
|
+
isMcpServerNotFoundError: () => isMcpServerNotFoundError2,
|
|
1829
|
+
isMessageNotFoundError: () => isMessageNotFoundError2,
|
|
1830
|
+
isPermissionNotFoundError: () => isPermissionNotFoundError2,
|
|
1831
|
+
isProjectNotFoundError: () => isProjectNotFoundError2,
|
|
1832
|
+
isProviderNotFoundError: () => isProviderNotFoundError2,
|
|
1833
|
+
isPtyNotFoundError: () => isPtyNotFoundError2,
|
|
1834
|
+
isRpcError: () => isRpcError2,
|
|
1835
|
+
isRpcInternalError: () => isRpcInternalError2,
|
|
1836
|
+
isServiceUnavailableError: () => isServiceUnavailableError2,
|
|
1837
|
+
isSessionBusyError: () => isSessionBusyError2,
|
|
1838
|
+
isSessionNotFoundError: () => isSessionNotFoundError2,
|
|
1839
|
+
isShellNotFoundError: () => isShellNotFoundError2,
|
|
1840
|
+
isSkillNotFoundError: () => isSkillNotFoundError2,
|
|
1841
|
+
isUnauthorizedError: () => isUnauthorizedError2,
|
|
1842
|
+
isUnknownError: () => isUnknownError2,
|
|
1843
|
+
isVcsInitNotSupportedError: () => isVcsInitNotSupportedError2,
|
|
1844
|
+
isWorktreeError: () => isWorktreeError2
|
|
1845
|
+
});
|
|
1846
|
+
var init_promise = __esm({
|
|
1847
|
+
"node_modules/@opencode/client/dist/promise/index.js"() {
|
|
1848
|
+
init_service_timing_e4sc9kq6();
|
|
1849
|
+
init_service_timing_tbh3h57v();
|
|
1850
|
+
init_service_timing_js54wxgp();
|
|
1851
|
+
init_service_timing_1y4a697q();
|
|
1852
|
+
init_service_timing_vt9jbch8();
|
|
1853
|
+
init_service_timing_frbwqjmf();
|
|
1854
|
+
}
|
|
1855
|
+
});
|
|
1856
|
+
|
|
1
1857
|
// src/config.js
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
1858
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
3
1859
|
import { homedir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
1860
|
+
import { join as join2 } from "node:path";
|
|
5
1861
|
|
|
6
1862
|
// src/utilities.js
|
|
7
1863
|
var MAX_TRACKED_ITEMS = 500;
|
|
@@ -74,6 +1930,48 @@ function rememberRecent(map, key, value) {
|
|
|
74
1930
|
while (map.size > 100) map.delete(map.keys().next().value);
|
|
75
1931
|
}
|
|
76
1932
|
|
|
1933
|
+
// src/live-bridge-config.js
|
|
1934
|
+
import { constants, closeSync, fstatSync, openSync, readFileSync } from "node:fs";
|
|
1935
|
+
import { isAbsolute, join } from "node:path";
|
|
1936
|
+
function readCredential(file) {
|
|
1937
|
+
if (typeof file !== "string" || !isAbsolute(file)) {
|
|
1938
|
+
throw new Error("Live control requires an absolute credential-file path");
|
|
1939
|
+
}
|
|
1940
|
+
let descriptor;
|
|
1941
|
+
try {
|
|
1942
|
+
descriptor = openSync(file, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
|
|
1943
|
+
const stat = fstatSync(descriptor);
|
|
1944
|
+
if (!stat.isFile() || stat.size > 4096 || process.platform !== "win32" && ((stat.mode & 63) !== 0 || stat.uid !== process.getuid())) {
|
|
1945
|
+
throw new Error("invalid_file");
|
|
1946
|
+
}
|
|
1947
|
+
const token = readFileSync(descriptor, "utf8").trim();
|
|
1948
|
+
if (!/^[A-Za-z0-9_-]{32,256}$/.test(token)) throw new Error("invalid_token");
|
|
1949
|
+
return token;
|
|
1950
|
+
} catch {
|
|
1951
|
+
throw new Error("Live control credential must be an owner-only regular file containing a 32\u2013256 character token");
|
|
1952
|
+
} finally {
|
|
1953
|
+
if (descriptor !== void 0) closeSync(descriptor);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
function loadLiveBridgeConfig(option, { configDirectory, ingestToken } = {}) {
|
|
1957
|
+
const values = option && typeof option === "object" ? option : {};
|
|
1958
|
+
const enabled2 = (typeof option === "boolean" ? option : values.enabled) ?? process.env.BACKEER_LIVE_ENABLED;
|
|
1959
|
+
if (enabled2 !== true && enabled2 !== "true" && enabled2 !== "1") return { enabled: false };
|
|
1960
|
+
try {
|
|
1961
|
+
const rawPort = values.port ?? process.env.BACKEER_LIVE_PORT ?? 43871;
|
|
1962
|
+
const port = Number(rawPort);
|
|
1963
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
1964
|
+
throw new Error("Live control port must be an integer between 1 and 65535");
|
|
1965
|
+
}
|
|
1966
|
+
const tokenFile = values.tokenFile ?? process.env.BACKEER_LIVE_TOKEN_FILE ?? join(configDirectory, "secrets", "backeer-live-token");
|
|
1967
|
+
const token = readCredential(tokenFile);
|
|
1968
|
+
if (token === ingestToken) throw new Error("Live control requires a credential distinct from the Backeer ingest token");
|
|
1969
|
+
return { enabled: true, token, tokenFile, port };
|
|
1970
|
+
} catch (error) {
|
|
1971
|
+
return { enabled: false, error: error.message };
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
|
|
77
1975
|
// src/config.js
|
|
78
1976
|
var DEFAULT_ORIGIN = "https://external-gateway.backeer.com";
|
|
79
1977
|
function integer(value, fallback, { minimum = 0, maximum = 86400 } = {}) {
|
|
@@ -115,13 +2013,13 @@ function loadLifecycleConfig(option) {
|
|
|
115
2013
|
}
|
|
116
2014
|
function defaultConfigDirectory() {
|
|
117
2015
|
const base = process.env.XDG_CONFIG_HOME?.trim();
|
|
118
|
-
return base ?
|
|
2016
|
+
return base ? join2(base, "opencode") : join2(homedir(), ".config", "opencode");
|
|
119
2017
|
}
|
|
120
2018
|
function loadToken(tokenFile) {
|
|
121
2019
|
const environmentToken = process.env.BACKEER_INGEST_TOKEN?.trim();
|
|
122
2020
|
if (environmentToken) return { token: environmentToken, source: "environment" };
|
|
123
2021
|
try {
|
|
124
|
-
const token =
|
|
2022
|
+
const token = readFileSync2(tokenFile, "utf8").trim();
|
|
125
2023
|
return { token, source: token ? "file" : "missing" };
|
|
126
2024
|
} catch {
|
|
127
2025
|
return { token: "", source: "missing" };
|
|
@@ -134,7 +2032,7 @@ function loadConfig(options = {}) {
|
|
|
134
2032
|
if (origin.protocol !== "https:") {
|
|
135
2033
|
throw new Error("Backeer origin must use HTTPS");
|
|
136
2034
|
}
|
|
137
|
-
const tokenFile = options.tokenFile ?? process.env.BACKEER_TOKEN_FILE ??
|
|
2035
|
+
const tokenFile = options.tokenFile ?? process.env.BACKEER_TOKEN_FILE ?? join2(defaultConfigDirectory(), "secrets", "backeer-ingest-token");
|
|
138
2036
|
const loadedToken = loadToken(tokenFile);
|
|
139
2037
|
return {
|
|
140
2038
|
origin,
|
|
@@ -144,6 +2042,10 @@ function loadConfig(options = {}) {
|
|
|
144
2042
|
token: loadedToken.token,
|
|
145
2043
|
tokenSource: loadedToken.source,
|
|
146
2044
|
tokenFile,
|
|
2045
|
+
liveBridge: loadLiveBridgeConfig(options.liveBridge, {
|
|
2046
|
+
configDirectory: defaultConfigDirectory(),
|
|
2047
|
+
ingestToken: loadedToken.token
|
|
2048
|
+
}),
|
|
147
2049
|
permissions: enabled(
|
|
148
2050
|
options.permissions ?? process.env.BACKEER_NOTIFY_PERMISSIONS
|
|
149
2051
|
),
|
|
@@ -238,19 +2140,19 @@ function isRetryable(status) {
|
|
|
238
2140
|
function isAbortError(error) {
|
|
239
2141
|
return error instanceof Error && error.name === "AbortError";
|
|
240
2142
|
}
|
|
241
|
-
function sleep(milliseconds,
|
|
2143
|
+
function sleep(milliseconds, signal2) {
|
|
242
2144
|
return new Promise((resolve2) => {
|
|
243
|
-
if (
|
|
2145
|
+
if (signal2?.aborted) {
|
|
244
2146
|
resolve2();
|
|
245
2147
|
return;
|
|
246
2148
|
}
|
|
247
2149
|
const timeout = setTimeout(done, milliseconds);
|
|
248
2150
|
function done() {
|
|
249
2151
|
clearTimeout(timeout);
|
|
250
|
-
|
|
2152
|
+
signal2?.removeEventListener("abort", done);
|
|
251
2153
|
resolve2();
|
|
252
2154
|
}
|
|
253
|
-
|
|
2155
|
+
signal2?.addEventListener("abort", done, { once: true });
|
|
254
2156
|
});
|
|
255
2157
|
}
|
|
256
2158
|
async function postJsonWithRetry(config, url, body, options = {}) {
|
|
@@ -481,7 +2383,7 @@ async function publishTodoCompletion(config, reporter, request, eventID, client,
|
|
|
481
2383
|
import {
|
|
482
2384
|
chmodSync,
|
|
483
2385
|
mkdirSync,
|
|
484
|
-
readFileSync as
|
|
2386
|
+
readFileSync as readFileSync3,
|
|
485
2387
|
renameSync,
|
|
486
2388
|
statSync as statSync2,
|
|
487
2389
|
writeFileSync
|
|
@@ -493,7 +2395,7 @@ import { randomUUID } from "node:crypto";
|
|
|
493
2395
|
import { statSync } from "node:fs";
|
|
494
2396
|
|
|
495
2397
|
// src/updates.js
|
|
496
|
-
var PLUGIN_VERSION = "0.
|
|
2398
|
+
var PLUGIN_VERSION = "0.5.1";
|
|
497
2399
|
var PACKAGE_NAME = "backeer-opencode";
|
|
498
2400
|
var NPM_REGISTRY_URL = "https://registry.npmjs.org";
|
|
499
2401
|
var CHECK_TIMEOUT_MS = 3e3;
|
|
@@ -524,7 +2426,8 @@ function isVersionNewer(latestValue, currentValue) {
|
|
|
524
2426
|
}
|
|
525
2427
|
function createUpdateChecker({
|
|
526
2428
|
fetchImplementation = globalThis.fetch,
|
|
527
|
-
now = () => Date.now()
|
|
2429
|
+
now = () => Date.now(),
|
|
2430
|
+
v2 = false
|
|
528
2431
|
} = {}) {
|
|
529
2432
|
let checkedAt = 0;
|
|
530
2433
|
let cachedResult;
|
|
@@ -554,7 +2457,7 @@ function createUpdateChecker({
|
|
|
554
2457
|
state: "available",
|
|
555
2458
|
currentVersion: PLUGIN_VERSION,
|
|
556
2459
|
latestVersion,
|
|
557
|
-
updateCommand: `opencode plugin ${PACKAGE_NAME}@${latestVersion} -g --force`
|
|
2460
|
+
updateCommand: v2 ? `opencode plugin add ${PACKAGE_NAME}@${latestVersion}` : `opencode plugin ${PACKAGE_NAME}@${latestVersion} -g --force`
|
|
558
2461
|
};
|
|
559
2462
|
} catch {
|
|
560
2463
|
return { state: "unavailable", currentVersion: PLUGIN_VERSION };
|
|
@@ -983,7 +2886,7 @@ function rotateTokenFromFile(config, sourcePathValue) {
|
|
|
983
2886
|
if ((sourceStats.mode & 63) !== 0) {
|
|
984
2887
|
throw new Error("The token source must not be readable by group or other users");
|
|
985
2888
|
}
|
|
986
|
-
const token =
|
|
2889
|
+
const token = readFileSync3(sourcePath, "utf8").trim();
|
|
987
2890
|
if (!token || /\s/.test(token)) {
|
|
988
2891
|
throw new Error("The token source must contain exactly one non-empty token");
|
|
989
2892
|
}
|
|
@@ -1510,35 +3413,546 @@ function createLifecycleController({
|
|
|
1510
3413
|
};
|
|
1511
3414
|
}
|
|
1512
3415
|
|
|
1513
|
-
// src/
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
}
|
|
1528
|
-
const expiresAt = Date.parse(command.expiresAt);
|
|
1529
|
-
if (!Number.isFinite(expiresAt) || expiresAt <= now) {
|
|
1530
|
-
return { status: "expired", decision: command.decision };
|
|
1531
|
-
}
|
|
1532
|
-
if (command.decision === "always" && command.confirmed !== true) {
|
|
1533
|
-
return {
|
|
1534
|
-
status: "rejected",
|
|
1535
|
-
decision: command.decision,
|
|
1536
|
-
errorCode: "confirmation_required"
|
|
1537
|
-
};
|
|
3416
|
+
// src/live-bridge.js
|
|
3417
|
+
import { createServer } from "node:http";
|
|
3418
|
+
import { randomUUID as randomUUID3, timingSafeEqual } from "node:crypto";
|
|
3419
|
+
|
|
3420
|
+
// src/live-bridge-client.js
|
|
3421
|
+
function createV2LiveClient(ctx) {
|
|
3422
|
+
const known = /* @__PURE__ */ new Map();
|
|
3423
|
+
let disposed = false;
|
|
3424
|
+
async function get(id) {
|
|
3425
|
+
const info = await ctx.session.get({ sessionID: id });
|
|
3426
|
+
if (disposed) return info;
|
|
3427
|
+
known.set(id, info);
|
|
3428
|
+
if (known.size > 100) known.delete(known.keys().next().value);
|
|
3429
|
+
return info;
|
|
1538
3430
|
}
|
|
3431
|
+
return {
|
|
3432
|
+
async list() {
|
|
3433
|
+
if (typeof ctx.session.list === "function") {
|
|
3434
|
+
return ctx.session.list({ directory: ctx.location.directory, limit: 100, order: "desc" });
|
|
3435
|
+
}
|
|
3436
|
+
const refreshed = [];
|
|
3437
|
+
for (const id of known.keys()) {
|
|
3438
|
+
try {
|
|
3439
|
+
refreshed.push(await get(id));
|
|
3440
|
+
} catch {
|
|
3441
|
+
known.delete(id);
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
return refreshed;
|
|
3445
|
+
},
|
|
3446
|
+
get,
|
|
3447
|
+
prompt: (id, text) => ctx.session.prompt({ sessionID: id, text, delivery: "queue" }),
|
|
3448
|
+
dispose: () => {
|
|
3449
|
+
disposed = true;
|
|
3450
|
+
known.clear();
|
|
3451
|
+
}
|
|
3452
|
+
};
|
|
1539
3453
|
}
|
|
1540
|
-
function
|
|
1541
|
-
|
|
3454
|
+
function unwrap(value) {
|
|
3455
|
+
if (value?.error) throw new Error("OpenCode request failed");
|
|
3456
|
+
return value?.data ?? value;
|
|
3457
|
+
}
|
|
3458
|
+
function createV1LiveClient(client, directory) {
|
|
3459
|
+
return {
|
|
3460
|
+
list: async () => unwrap(await client.session.list({ query: { directory }, throwOnError: true })),
|
|
3461
|
+
get: async (id) => unwrap(await client.session.get({ path: { id }, query: { directory }, throwOnError: true })),
|
|
3462
|
+
async prompt(id, text) {
|
|
3463
|
+
if (typeof client.session.promptAsync !== "function") {
|
|
3464
|
+
throw Object.assign(new Error("OpenCode asynchronous prompts are unavailable"), { status: 501 });
|
|
3465
|
+
}
|
|
3466
|
+
return unwrap(await client.session.promptAsync({
|
|
3467
|
+
path: { id },
|
|
3468
|
+
query: { directory },
|
|
3469
|
+
body: { parts: [{ type: "text", text }] },
|
|
3470
|
+
throwOnError: true
|
|
3471
|
+
}));
|
|
3472
|
+
}
|
|
3473
|
+
};
|
|
3474
|
+
}
|
|
3475
|
+
|
|
3476
|
+
// src/live-connection.js
|
|
3477
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
3478
|
+
var LIVE_RECONNECT_MS = 3e3;
|
|
3479
|
+
var LIVE_HEARTBEAT_MS = 15e3;
|
|
3480
|
+
function createLiveConnectionNotifier(config, reporter) {
|
|
3481
|
+
const epoch = randomUUID2();
|
|
3482
|
+
const controller = new AbortController();
|
|
3483
|
+
let last, sequence = 0, pending, task;
|
|
3484
|
+
async function drain() {
|
|
3485
|
+
while (pending && !controller.signal.aborted) {
|
|
3486
|
+
const event = pending;
|
|
3487
|
+
pending = void 0;
|
|
3488
|
+
try {
|
|
3489
|
+
await postJsonWithRetry(config, config.eventsEndpoint, event, { signal: controller.signal });
|
|
3490
|
+
} catch {
|
|
3491
|
+
if (!controller.signal.aborted) reporter?.error("Live connection notification could not be sent");
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
}
|
|
3495
|
+
return {
|
|
3496
|
+
update(connected) {
|
|
3497
|
+
if (controller.signal.aborted || connected === last) return;
|
|
3498
|
+
const initial = last === void 0;
|
|
3499
|
+
last = connected;
|
|
3500
|
+
if (initial || !config.token || !config.eventsEndpoint) return;
|
|
3501
|
+
pending = {
|
|
3502
|
+
type: "application",
|
|
3503
|
+
severity: connected ? "info" : "warning",
|
|
3504
|
+
title: connected ? "OpenCode ba\u011Flant\u0131s\u0131 yeniden kuruldu" : "OpenCode ba\u011Flant\u0131s\u0131 kesildi",
|
|
3505
|
+
body: connected ? "Canl\u0131 takip yeniden ba\u011Fland\u0131. Sunucudaki g\xF6rev otomatik olarak yeniden ba\u015Flat\u0131lmad\u0131." : "Canl\u0131 takip ba\u011Flant\u0131s\u0131 kesildi. Yeniden ba\u011Flanma her 3 saniyede denenecek; sunucudaki g\xF6rev durdurulmad\u0131.",
|
|
3506
|
+
payload: [{ key: "Connection", value: connected ? "reconnected" : "disconnected" }],
|
|
3507
|
+
externalId: `opencode:live:${epoch}:${++sequence}`,
|
|
3508
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3509
|
+
notify: true,
|
|
3510
|
+
direction: "in"
|
|
3511
|
+
};
|
|
3512
|
+
task ??= drain().finally(() => {
|
|
3513
|
+
task = void 0;
|
|
3514
|
+
});
|
|
3515
|
+
},
|
|
3516
|
+
async dispose() {
|
|
3517
|
+
controller.abort();
|
|
3518
|
+
pending = void 0;
|
|
3519
|
+
await task;
|
|
3520
|
+
}
|
|
3521
|
+
};
|
|
3522
|
+
}
|
|
3523
|
+
|
|
3524
|
+
// src/live-bridge-events.js
|
|
3525
|
+
var ID = /^[A-Za-z0-9_-]{1,160}$/;
|
|
3526
|
+
var validBridgeID = (value) => typeof value === "string" && ID.test(value);
|
|
3527
|
+
function createBridgeSanitizer(secrets = []) {
|
|
3528
|
+
const known = secrets.filter((value) => typeof value === "string" && value.length > 0);
|
|
3529
|
+
const assistants = /* @__PURE__ */ new Map();
|
|
3530
|
+
function clipped(value, max = 12e3) {
|
|
3531
|
+
if (typeof value !== "string") return { value: "", truncated: false };
|
|
3532
|
+
let result = value.slice(0, 64e3);
|
|
3533
|
+
for (const secret of known) result = result.split(secret).join("[REDACTED]");
|
|
3534
|
+
result = result.replace(/-----BEGIN [^-]*PRIVATE KEY-----[\s\S]*?(?:-----END [^-]*PRIVATE KEY-----|$)/g, "[REDACTED PRIVATE KEY]").replace(/\bBearer\s+[^\s"'<>]+/gi, "Bearer [REDACTED]").replace(/\b(?:sk|bgi)_[A-Za-z0-9_-]{12,}|\bsk-[A-Za-z0-9_-]{12,}/g, "[REDACTED]").replace(/((?:api[_-]?key|access[_-]?token|secret|password|authorization)\s*[=:]\s*)[^\s,;]+/gi, "$1[REDACTED]");
|
|
3535
|
+
return { value: result.slice(0, max), truncated: value.length > 64e3 || result.length > max };
|
|
3536
|
+
}
|
|
3537
|
+
function text(value, max) {
|
|
3538
|
+
return clipped(value, max).value;
|
|
3539
|
+
}
|
|
3540
|
+
function content(key, value) {
|
|
3541
|
+
const result = clipped(value);
|
|
3542
|
+
return { [key]: result.value, ...result.truncated ? { truncated: true } : {} };
|
|
3543
|
+
}
|
|
3544
|
+
function sanitize(event) {
|
|
3545
|
+
const p = event?.properties ?? event?.data ?? {};
|
|
3546
|
+
const sessionID = p.sessionID ?? p.info?.sessionID ?? p.part?.sessionID;
|
|
3547
|
+
if (!validBridgeID(sessionID) || sessionID === "global") return void 0;
|
|
3548
|
+
const base = { type: event.type, sessionID, data: {} };
|
|
3549
|
+
if (event.type === "message.updated") {
|
|
3550
|
+
const info = p.info;
|
|
3551
|
+
if (!validBridgeID(info?.id)) return void 0;
|
|
3552
|
+
if (info.role === "assistant") {
|
|
3553
|
+
assistants.set(info.id, sessionID);
|
|
3554
|
+
if (assistants.size > 256) assistants.delete(assistants.keys().next().value);
|
|
3555
|
+
}
|
|
3556
|
+
return info.role === "assistant" ? { ...base, data: {
|
|
3557
|
+
messageID: info.id,
|
|
3558
|
+
completed: !!info.time?.completed,
|
|
3559
|
+
failed: !!info.error
|
|
3560
|
+
} } : void 0;
|
|
3561
|
+
}
|
|
3562
|
+
if (event.type === "message.part.updated") {
|
|
3563
|
+
const part = p.part;
|
|
3564
|
+
if (assistants.get(part?.messageID) !== sessionID) return void 0;
|
|
3565
|
+
if (part.type === "text") return { ...base, type: "assistant.text", data: {
|
|
3566
|
+
messageID: part.messageID,
|
|
3567
|
+
...content("text", part.text),
|
|
3568
|
+
replace: true
|
|
3569
|
+
} };
|
|
3570
|
+
if (part.type !== "tool") return void 0;
|
|
3571
|
+
const state = part.state ?? {};
|
|
3572
|
+
return { ...base, type: "tool.status", data: {
|
|
3573
|
+
tool: text(part.tool, 80),
|
|
3574
|
+
status: text(state.status, 40),
|
|
3575
|
+
...state.status === "completed" ? content("output", state.output) : {},
|
|
3576
|
+
...state.status === "error" ? { failed: true } : {}
|
|
3577
|
+
} };
|
|
3578
|
+
}
|
|
3579
|
+
if (event.type === "session.text.ended") return { ...base, type: "assistant.text", data: {
|
|
3580
|
+
messageID: validBridgeID(p.assistantMessageID) ? p.assistantMessageID : void 0,
|
|
3581
|
+
...content("text", p.text),
|
|
3582
|
+
replace: true
|
|
3583
|
+
} };
|
|
3584
|
+
if (["session.tool.called", "session.tool.success", "session.tool.failed"].includes(event.type)) {
|
|
3585
|
+
return { ...base, type: "tool.status", data: {
|
|
3586
|
+
status: event.type.split(".").at(-1),
|
|
3587
|
+
...event.type === "session.tool.success" ? content(
|
|
3588
|
+
"output",
|
|
3589
|
+
(p.content ?? []).filter((item) => item?.type === "text").map((item) => item.text).join("\n")
|
|
3590
|
+
) : {}
|
|
3591
|
+
} };
|
|
3592
|
+
}
|
|
3593
|
+
if (["permission.asked", "question.asked", "question.v2.asked"].includes(event.type)) {
|
|
3594
|
+
return { ...base, type: "approval.waiting", data: { kind: event.type.split(".")[0] } };
|
|
3595
|
+
}
|
|
3596
|
+
if (["permission.replied", "question.replied", "question.v2.replied", "question.rejected", "question.v2.rejected"].includes(event.type)) {
|
|
3597
|
+
return { ...base, type: "approval.settled", data: { kind: event.type.split(".")[0] } };
|
|
3598
|
+
}
|
|
3599
|
+
if (event.type === "session.status") return { ...base, data: {
|
|
3600
|
+
status: ["idle", "busy", "retry"].includes(p.status?.type) ? p.status.type : "unknown"
|
|
3601
|
+
} };
|
|
3602
|
+
if (["session.idle", "session.error", "session.deleted"].includes(event.type)) return base;
|
|
3603
|
+
return void 0;
|
|
3604
|
+
}
|
|
3605
|
+
return { sanitize, text, clear: () => assistants.clear() };
|
|
3606
|
+
}
|
|
3607
|
+
|
|
3608
|
+
// src/live-bridge.js
|
|
3609
|
+
var LIMITS = { events: 256, bytes: 2e6, clients: 8, commands: 1024, commandTTL: 864e5, body: 32768, requests: 16 };
|
|
3610
|
+
function failure(status, code) {
|
|
3611
|
+
return Object.assign(new Error(code), { status, code });
|
|
3612
|
+
}
|
|
3613
|
+
function json(response, status, value) {
|
|
3614
|
+
if (!response.destroyed && !response.headersSent) {
|
|
3615
|
+
response.writeHead(status, { "content-type": "application/json", "cache-control": "no-store" });
|
|
3616
|
+
response.end(JSON.stringify(value));
|
|
3617
|
+
}
|
|
3618
|
+
}
|
|
3619
|
+
async function readBody(request) {
|
|
3620
|
+
const chunks = [];
|
|
3621
|
+
let bytes = 0;
|
|
3622
|
+
for await (const chunk of request) {
|
|
3623
|
+
bytes += chunk.length;
|
|
3624
|
+
if (bytes > LIMITS.body) throw failure(413, "body_too_large");
|
|
3625
|
+
chunks.push(chunk);
|
|
3626
|
+
}
|
|
3627
|
+
try {
|
|
3628
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
3629
|
+
} catch {
|
|
3630
|
+
throw failure(400, "invalid_json");
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3633
|
+
async function createLiveBridge({ config, client, directory, reporter }) {
|
|
3634
|
+
const options = config.liveBridge;
|
|
3635
|
+
if (!options?.enabled) return { handle() {
|
|
3636
|
+
}, async dispose() {
|
|
3637
|
+
}, address: void 0 };
|
|
3638
|
+
const token = options.token;
|
|
3639
|
+
if (typeof token !== "string" || token.length < 32 || token === config.token) {
|
|
3640
|
+
throw new Error("Live bridge requires a separate credential of at least 32 characters");
|
|
3641
|
+
}
|
|
3642
|
+
const api = client.liveBridge ?? createV1LiveClient(client, directory);
|
|
3643
|
+
const connectionNotifications = createLiveConnectionNotifier(config, reporter);
|
|
3644
|
+
const sanitizer = createBridgeSanitizer([token, config.token]);
|
|
3645
|
+
const epoch = randomUUID3();
|
|
3646
|
+
const events = [], streams = /* @__PURE__ */ new Set(), commands = /* @__PURE__ */ new Map(), states = /* @__PURE__ */ new Map();
|
|
3647
|
+
let sequence = 0, bytes = 0, active = 0, disposed = false, disposeTask;
|
|
3648
|
+
let lookups = 0;
|
|
3649
|
+
const lookupWaiters = /* @__PURE__ */ new Set();
|
|
3650
|
+
const cursor = () => `${epoch}:${sequence}`;
|
|
3651
|
+
function lookup(id) {
|
|
3652
|
+
if (disposed) return Promise.reject(failure(503, "bridge_closed"));
|
|
3653
|
+
if (lookups >= 16) return Promise.reject(failure(429, "session_lookup_busy"));
|
|
3654
|
+
lookups++;
|
|
3655
|
+
return new Promise((resolve2, reject) => {
|
|
3656
|
+
let finished = false;
|
|
3657
|
+
const finish = (complete, value) => {
|
|
3658
|
+
if (finished) return;
|
|
3659
|
+
finished = true;
|
|
3660
|
+
clearTimeout(timer);
|
|
3661
|
+
lookupWaiters.delete(cancel);
|
|
3662
|
+
complete(value);
|
|
3663
|
+
};
|
|
3664
|
+
const cancel = () => finish(reject, failure(503, "bridge_closed"));
|
|
3665
|
+
const timer = setTimeout(() => finish(reject, failure(504, "session_lookup_timed_out")), 1e3);
|
|
3666
|
+
lookupWaiters.add(cancel);
|
|
3667
|
+
Promise.resolve().then(() => api.get(id)).then(
|
|
3668
|
+
(value) => {
|
|
3669
|
+
lookups--;
|
|
3670
|
+
finish(resolve2, value);
|
|
3671
|
+
},
|
|
3672
|
+
(error) => {
|
|
3673
|
+
lookups--;
|
|
3674
|
+
finish(reject, error);
|
|
3675
|
+
}
|
|
3676
|
+
);
|
|
3677
|
+
});
|
|
3678
|
+
}
|
|
3679
|
+
async function session(id) {
|
|
3680
|
+
if (!validBridgeID(id) || id === "global") throw failure(400, "invalid_session");
|
|
3681
|
+
let info;
|
|
3682
|
+
try {
|
|
3683
|
+
info = await lookup(id);
|
|
3684
|
+
} catch (error) {
|
|
3685
|
+
if (["session_lookup_busy", "session_lookup_timed_out", "bridge_closed"].includes(error.code)) throw error;
|
|
3686
|
+
throw failure(404, "session_not_found");
|
|
3687
|
+
}
|
|
3688
|
+
if (info?.id !== id || (info.location?.directory ?? info.directory) !== directory) {
|
|
3689
|
+
throw failure(404, "session_not_found");
|
|
3690
|
+
}
|
|
3691
|
+
return {
|
|
3692
|
+
id,
|
|
3693
|
+
title: sanitizer.text(info.title, 240),
|
|
3694
|
+
...validBridgeID(info.parentID) ? { parentID: info.parentID } : {},
|
|
3695
|
+
status: states.get(id) ?? "unknown"
|
|
3696
|
+
};
|
|
3697
|
+
}
|
|
3698
|
+
function removeStream(stream) {
|
|
3699
|
+
const removed = streams.delete(stream);
|
|
3700
|
+
clearInterval(stream.heartbeat);
|
|
3701
|
+
stream.queue.length = 0;
|
|
3702
|
+
stream.queuedBytes = 0;
|
|
3703
|
+
if (removed && !streams.size && !disposed) connectionNotifications.update(false);
|
|
3704
|
+
}
|
|
3705
|
+
function write(stream, value) {
|
|
3706
|
+
if (!streams.has(stream)) return;
|
|
3707
|
+
if (stream.blocked) {
|
|
3708
|
+
stream.queue.push(value);
|
|
3709
|
+
stream.queuedBytes += Buffer.byteLength(value);
|
|
3710
|
+
if (stream.queuedBytes > LIMITS.bytes) {
|
|
3711
|
+
removeStream(stream);
|
|
3712
|
+
stream.response.destroy();
|
|
3713
|
+
}
|
|
3714
|
+
return;
|
|
3715
|
+
}
|
|
3716
|
+
if (!stream.response.write(value)) {
|
|
3717
|
+
stream.blocked = true;
|
|
3718
|
+
}
|
|
3719
|
+
}
|
|
3720
|
+
async function handle(event) {
|
|
3721
|
+
if (disposed) return;
|
|
3722
|
+
const safe = sanitizer.sanitize(event);
|
|
3723
|
+
if (!safe) return;
|
|
3724
|
+
try {
|
|
3725
|
+
await session(safe.sessionID);
|
|
3726
|
+
} catch {
|
|
3727
|
+
return;
|
|
3728
|
+
}
|
|
3729
|
+
if (disposed) return;
|
|
3730
|
+
if (safe.type === "session.status") states.set(safe.sessionID, safe.data.status);
|
|
3731
|
+
if (safe.type === "session.idle") states.set(safe.sessionID, "idle");
|
|
3732
|
+
if (safe.type === "session.deleted") states.delete(safe.sessionID);
|
|
3733
|
+
if (states.size > 256) states.delete(states.keys().next().value);
|
|
3734
|
+
const record = { id: `${epoch}:${++sequence}`, ...safe, timestamp: Date.now() };
|
|
3735
|
+
let frame = `id: ${record.id}
|
|
3736
|
+
event: backeer.event
|
|
3737
|
+
data: ${JSON.stringify(record)}
|
|
3738
|
+
|
|
3739
|
+
`;
|
|
3740
|
+
if (Buffer.byteLength(frame) > 32768) {
|
|
3741
|
+
record.data = { truncated: true };
|
|
3742
|
+
frame = `id: ${record.id}
|
|
3743
|
+
event: backeer.event
|
|
3744
|
+
data: ${JSON.stringify(record)}
|
|
3745
|
+
|
|
3746
|
+
`;
|
|
3747
|
+
}
|
|
3748
|
+
const size = Buffer.byteLength(frame);
|
|
3749
|
+
events.push({ sequence, sessionID: record.sessionID, frame, size });
|
|
3750
|
+
bytes += size;
|
|
3751
|
+
while (events.length > LIMITS.events || bytes > LIMITS.bytes) bytes -= events.shift().size;
|
|
3752
|
+
for (const stream of streams) if (!stream.sessionID || stream.sessionID === record.sessionID) write(stream, frame);
|
|
3753
|
+
}
|
|
3754
|
+
function authorized(request) {
|
|
3755
|
+
if (request.headers.origin || request.headers["sec-fetch-site"]) return false;
|
|
3756
|
+
const expected = Buffer.from(`Bearer ${token}`);
|
|
3757
|
+
const actual = Buffer.from(request.headers.authorization ?? "");
|
|
3758
|
+
return actual.length === expected.length && timingSafeEqual(actual, expected);
|
|
3759
|
+
}
|
|
3760
|
+
function parseCursor(value) {
|
|
3761
|
+
if (!value) return { after: 0 };
|
|
3762
|
+
const match = /^([a-f0-9-]{36}):(\d{1,16})$/.exec(value);
|
|
3763
|
+
if (!match) throw failure(400, "invalid_cursor");
|
|
3764
|
+
if (match[1] !== epoch) return { gap: "stream_restarted" };
|
|
3765
|
+
const after = Number(match[2]);
|
|
3766
|
+
if (!Number.isSafeInteger(after) || after > sequence) throw failure(400, "invalid_cursor");
|
|
3767
|
+
if (events.length && after < events[0].sequence - 1) return { gap: "cursor_expired" };
|
|
3768
|
+
return { after };
|
|
3769
|
+
}
|
|
3770
|
+
async function route(request, response) {
|
|
3771
|
+
if (!authorized(request)) return json(response, 401, { error: "unauthorized" });
|
|
3772
|
+
if (active >= LIMITS.requests) return json(response, 429, { error: "bridge_busy" });
|
|
3773
|
+
active++;
|
|
3774
|
+
const timeout = setTimeout(() => json(response, 504, { error: "request_timed_out" }), 15e3);
|
|
3775
|
+
timeout.unref();
|
|
3776
|
+
try {
|
|
3777
|
+
const url = new URL(request.url, "http://127.0.0.1");
|
|
3778
|
+
if (url.username || url.password) throw failure(400, "invalid_url");
|
|
3779
|
+
if (request.method === "GET" && url.pathname === "/v1/sessions") {
|
|
3780
|
+
const result = await api.list();
|
|
3781
|
+
const values = Array.isArray(result) ? result : result?.data;
|
|
3782
|
+
if (!Array.isArray(values)) throw failure(502, "invalid_session_list");
|
|
3783
|
+
const own = values.slice(0, 100).filter((info) => validBridgeID(info?.id) && (info.location?.directory ?? info.directory) === directory);
|
|
3784
|
+
return json(response, 200, { sessions: own.map((info) => ({
|
|
3785
|
+
id: info.id,
|
|
3786
|
+
title: sanitizer.text(info.title, 240),
|
|
3787
|
+
status: states.get(info.id) ?? "unknown",
|
|
3788
|
+
...validBridgeID(info.parentID) ? { parentID: info.parentID } : {}
|
|
3789
|
+
})), cursor: cursor() });
|
|
3790
|
+
}
|
|
3791
|
+
if (request.method === "GET" && url.pathname === "/v1/events") {
|
|
3792
|
+
const selected = url.searchParams.get("sessionID") || void 0;
|
|
3793
|
+
if (selected) await session(selected);
|
|
3794
|
+
const parsed = parseCursor(url.searchParams.get("after") ?? request.headers["last-event-id"]);
|
|
3795
|
+
if (response.headersSent) return;
|
|
3796
|
+
if (streams.size >= LIMITS.clients) throw failure(429, "too_many_streams");
|
|
3797
|
+
clearTimeout(timeout);
|
|
3798
|
+
response.writeHead(200, {
|
|
3799
|
+
"content-type": "text/event-stream",
|
|
3800
|
+
"cache-control": "no-cache, no-transform",
|
|
3801
|
+
"x-accel-buffering": "no",
|
|
3802
|
+
connection: "keep-alive"
|
|
3803
|
+
});
|
|
3804
|
+
if (parsed.gap) {
|
|
3805
|
+
response.end(`event: backeer.gap
|
|
3806
|
+
data: ${JSON.stringify({ reason: parsed.gap, cursor: cursor() })}
|
|
3807
|
+
|
|
3808
|
+
`);
|
|
3809
|
+
return;
|
|
3810
|
+
}
|
|
3811
|
+
const stream = {
|
|
3812
|
+
response,
|
|
3813
|
+
sessionID: selected,
|
|
3814
|
+
heartbeat: void 0,
|
|
3815
|
+
blocked: false,
|
|
3816
|
+
queue: [],
|
|
3817
|
+
queuedBytes: 0
|
|
3818
|
+
};
|
|
3819
|
+
streams.add(stream);
|
|
3820
|
+
connectionNotifications.update(true);
|
|
3821
|
+
request.socket.setTimeout(0);
|
|
3822
|
+
request.socket.setKeepAlive(true, LIVE_HEARTBEAT_MS);
|
|
3823
|
+
response.on("close", () => removeStream(stream));
|
|
3824
|
+
response.on("drain", () => {
|
|
3825
|
+
stream.blocked = false;
|
|
3826
|
+
while (streams.has(stream) && !stream.blocked && stream.queue.length) {
|
|
3827
|
+
const next = stream.queue.shift();
|
|
3828
|
+
stream.queuedBytes -= Buffer.byteLength(next);
|
|
3829
|
+
write(stream, next);
|
|
3830
|
+
}
|
|
3831
|
+
});
|
|
3832
|
+
write(stream, `: connected
|
|
3833
|
+
retry: ${LIVE_RECONNECT_MS}
|
|
3834
|
+
|
|
3835
|
+
`);
|
|
3836
|
+
for (const item of events) {
|
|
3837
|
+
if (!streams.has(stream)) break;
|
|
3838
|
+
if (item.sequence > parsed.after && (!selected || selected === item.sessionID)) write(stream, item.frame);
|
|
3839
|
+
}
|
|
3840
|
+
if (streams.has(stream)) {
|
|
3841
|
+
stream.heartbeat = setInterval(() => write(stream, ": heartbeat\n\n"), LIVE_HEARTBEAT_MS);
|
|
3842
|
+
stream.heartbeat.unref();
|
|
3843
|
+
}
|
|
3844
|
+
return;
|
|
3845
|
+
}
|
|
3846
|
+
const match = /^\/v1\/sessions\/([A-Za-z0-9_-]{1,160})(\/instructions)?$/.exec(url.pathname);
|
|
3847
|
+
if (!match) throw failure(404, "route_not_found");
|
|
3848
|
+
if (request.method === "GET" && !match[2]) return json(response, 200, await session(match[1]));
|
|
3849
|
+
if (request.method !== "POST" || !match[2]) throw failure(405, "method_not_allowed");
|
|
3850
|
+
if (!/^application\/json(?:;|$)/i.test(request.headers["content-type"] ?? "")) throw failure(415, "json_required");
|
|
3851
|
+
const body = await readBody(request);
|
|
3852
|
+
if (!body || !validBridgeID(body.requestId) || typeof body.prompt !== "string" || !body.prompt.trim() || body.prompt.length > 16e3 || Object.keys(body).some((key) => !["requestId", "prompt"].includes(key))) throw failure(400, "invalid_instruction");
|
|
3853
|
+
await session(match[1]);
|
|
3854
|
+
if (response.headersSent || disposed) return;
|
|
3855
|
+
for (const [id, command2] of commands) {
|
|
3856
|
+
if (command2.settled && Date.now() - command2.created >= LIMITS.commandTTL) commands.delete(id);
|
|
3857
|
+
}
|
|
3858
|
+
const existing = commands.get(body.requestId);
|
|
3859
|
+
if (existing) {
|
|
3860
|
+
if (existing.sessionID !== match[1] || existing.prompt !== body.prompt) throw failure(409, "request_id_conflict");
|
|
3861
|
+
await existing.task;
|
|
3862
|
+
return json(response, 200, existing.result);
|
|
3863
|
+
}
|
|
3864
|
+
if (commands.size >= LIMITS.commands) throw failure(429, "command_window_full");
|
|
3865
|
+
const command = {
|
|
3866
|
+
sessionID: match[1],
|
|
3867
|
+
prompt: body.prompt,
|
|
3868
|
+
created: Date.now(),
|
|
3869
|
+
settled: false,
|
|
3870
|
+
result: { requestId: body.requestId, sessionID: match[1], status: "accepted" },
|
|
3871
|
+
task: void 0
|
|
3872
|
+
};
|
|
3873
|
+
commands.set(body.requestId, command);
|
|
3874
|
+
command.task = Promise.resolve().then(() => api.prompt(match[1], body.prompt)).finally(() => {
|
|
3875
|
+
command.settled = true;
|
|
3876
|
+
});
|
|
3877
|
+
await command.task;
|
|
3878
|
+
return json(response, 202, command.result);
|
|
3879
|
+
} catch (error) {
|
|
3880
|
+
json(response, error.status ?? 502, { error: error.code ?? "opencode_request_failed" });
|
|
3881
|
+
} finally {
|
|
3882
|
+
active--;
|
|
3883
|
+
clearTimeout(timeout);
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3886
|
+
const server = createServer((request, response) => {
|
|
3887
|
+
void route(request, response);
|
|
3888
|
+
});
|
|
3889
|
+
server.requestTimeout = 15e3;
|
|
3890
|
+
server.headersTimeout = 1e4;
|
|
3891
|
+
server.keepAliveTimeout = 5e3;
|
|
3892
|
+
await new Promise((resolve2, reject) => {
|
|
3893
|
+
server.once("error", reject);
|
|
3894
|
+
server.listen(options.port ?? 43871, "127.0.0.1", () => {
|
|
3895
|
+
server.off("error", reject);
|
|
3896
|
+
resolve2();
|
|
3897
|
+
});
|
|
3898
|
+
});
|
|
3899
|
+
server.on("error", () => {
|
|
3900
|
+
});
|
|
3901
|
+
return {
|
|
3902
|
+
handle,
|
|
3903
|
+
address: server.address(),
|
|
3904
|
+
dispose() {
|
|
3905
|
+
disposeTask ??= new Promise((resolve2) => {
|
|
3906
|
+
disposed = true;
|
|
3907
|
+
for (const cancel of lookupWaiters) cancel();
|
|
3908
|
+
for (const stream of streams) {
|
|
3909
|
+
removeStream(stream);
|
|
3910
|
+
stream.response.destroy();
|
|
3911
|
+
}
|
|
3912
|
+
server.close(() => {
|
|
3913
|
+
void connectionNotifications.dispose().then(resolve2);
|
|
3914
|
+
});
|
|
3915
|
+
server.closeAllConnections?.();
|
|
3916
|
+
events.length = 0;
|
|
3917
|
+
states.clear();
|
|
3918
|
+
commands.clear();
|
|
3919
|
+
sanitizer.clear();
|
|
3920
|
+
api.dispose?.();
|
|
3921
|
+
});
|
|
3922
|
+
return disposeTask;
|
|
3923
|
+
}
|
|
3924
|
+
};
|
|
3925
|
+
}
|
|
3926
|
+
|
|
3927
|
+
// src/permission-command.js
|
|
3928
|
+
var ALLOWED_DECISIONS = /* @__PURE__ */ new Set(["once", "always", "reject"]);
|
|
3929
|
+
var DECISION_LABELS = {
|
|
3930
|
+
once: "Allow once",
|
|
3931
|
+
always: "Always allow",
|
|
3932
|
+
reject: "Reject"
|
|
3933
|
+
};
|
|
3934
|
+
function validatePermissionCommand(command, now = Date.now()) {
|
|
3935
|
+
if (!ALLOWED_DECISIONS.has(command.decision)) {
|
|
3936
|
+
return {
|
|
3937
|
+
status: "rejected",
|
|
3938
|
+
decision: command.decision,
|
|
3939
|
+
errorCode: "invalid_decision"
|
|
3940
|
+
};
|
|
3941
|
+
}
|
|
3942
|
+
const expiresAt = Date.parse(command.expiresAt);
|
|
3943
|
+
if (!Number.isFinite(expiresAt) || expiresAt <= now) {
|
|
3944
|
+
return { status: "expired", decision: command.decision };
|
|
3945
|
+
}
|
|
3946
|
+
if (command.decision === "always" && command.confirmed !== true) {
|
|
3947
|
+
return {
|
|
3948
|
+
status: "rejected",
|
|
3949
|
+
decision: command.decision,
|
|
3950
|
+
errorCode: "confirmation_required"
|
|
3951
|
+
};
|
|
3952
|
+
}
|
|
3953
|
+
}
|
|
3954
|
+
function failureAcknowledgement(command, error) {
|
|
3955
|
+
const stale = error instanceof HttpError && error.status === 404;
|
|
1542
3956
|
return {
|
|
1543
3957
|
status: stale ? "stale" : "failed",
|
|
1544
3958
|
decision: command.decision,
|
|
@@ -1651,13 +4065,13 @@ function nextSseFrame(buffer) {
|
|
|
1651
4065
|
}
|
|
1652
4066
|
return { frame: buffer.slice(0, lfIndex), rest: buffer.slice(lfIndex + 2) };
|
|
1653
4067
|
}
|
|
1654
|
-
async function consumeSse(response, state, onCommand,
|
|
4068
|
+
async function consumeSse(response, state, onCommand, signal2, reporter) {
|
|
1655
4069
|
if (!response.body) throw new Error("Backeer command stream has no body");
|
|
1656
4070
|
const reader = response.body.getReader();
|
|
1657
4071
|
const decoder = new TextDecoder();
|
|
1658
4072
|
let buffer = "";
|
|
1659
4073
|
try {
|
|
1660
|
-
while (!
|
|
4074
|
+
while (!signal2.aborted) {
|
|
1661
4075
|
const item = await reader.read();
|
|
1662
4076
|
if (item.done) break;
|
|
1663
4077
|
buffer += decoder.decode(item.value, { stream: true });
|
|
@@ -1686,7 +4100,7 @@ async function consumeSse(response, state, onCommand, signal, reporter) {
|
|
|
1686
4100
|
});
|
|
1687
4101
|
}
|
|
1688
4102
|
}
|
|
1689
|
-
async function openCommandStream(config, state,
|
|
4103
|
+
async function openCommandStream(config, state, signal2, fetchImplementation) {
|
|
1690
4104
|
const headers = {
|
|
1691
4105
|
Accept: "text/event-stream",
|
|
1692
4106
|
Authorization: `Bearer ${config.token}`
|
|
@@ -1694,7 +4108,7 @@ async function openCommandStream(config, state, signal, fetchImplementation) {
|
|
|
1694
4108
|
if (state.lastEventID) headers["Last-Event-ID"] = state.lastEventID;
|
|
1695
4109
|
const response = await fetchImplementation(config.commandStreamEndpoint, {
|
|
1696
4110
|
headers,
|
|
1697
|
-
signal
|
|
4111
|
+
signal: signal2
|
|
1698
4112
|
});
|
|
1699
4113
|
if (!response.ok) {
|
|
1700
4114
|
const responseBody = limit(await response.text(), 500);
|
|
@@ -1713,7 +4127,7 @@ async function consumeConnection({
|
|
|
1713
4127
|
response,
|
|
1714
4128
|
state,
|
|
1715
4129
|
onCommand,
|
|
1716
|
-
signal,
|
|
4130
|
+
signal: signal2,
|
|
1717
4131
|
reporter,
|
|
1718
4132
|
now,
|
|
1719
4133
|
stableConnectionMs,
|
|
@@ -1722,7 +4136,7 @@ async function consumeConnection({
|
|
|
1722
4136
|
const connectedAt = now();
|
|
1723
4137
|
const framesBeforeConnection = state.framesReceived;
|
|
1724
4138
|
try {
|
|
1725
|
-
await consumeSse(response, state, onCommand,
|
|
4139
|
+
await consumeSse(response, state, onCommand, signal2, reporter);
|
|
1726
4140
|
} finally {
|
|
1727
4141
|
const receivedFrame = state.framesReceived > framesBeforeConnection;
|
|
1728
4142
|
if (receivedFrame || now() - connectedAt >= stableConnectionMs) onStable();
|
|
@@ -1743,7 +4157,7 @@ function streamErrorState(error, lastLoggedError, reconnectDelay, reporter) {
|
|
|
1743
4157
|
};
|
|
1744
4158
|
}
|
|
1745
4159
|
async function runCommandStream(config, reporter, {
|
|
1746
|
-
signal,
|
|
4160
|
+
signal: signal2,
|
|
1747
4161
|
hasPending,
|
|
1748
4162
|
onCommand,
|
|
1749
4163
|
fetchImplementation = fetch,
|
|
@@ -1754,19 +4168,19 @@ async function runCommandStream(config, reporter, {
|
|
|
1754
4168
|
const state = { lastEventID: "", framesReceived: 0 };
|
|
1755
4169
|
let reconnectDelay = 1e3;
|
|
1756
4170
|
let lastLoggedError = "";
|
|
1757
|
-
while (!
|
|
4171
|
+
while (!signal2.aborted && hasPending()) {
|
|
1758
4172
|
try {
|
|
1759
4173
|
const response = await openCommandStream(
|
|
1760
4174
|
config,
|
|
1761
4175
|
state,
|
|
1762
|
-
|
|
4176
|
+
signal2,
|
|
1763
4177
|
fetchImplementation
|
|
1764
4178
|
);
|
|
1765
4179
|
await consumeConnection({
|
|
1766
4180
|
response,
|
|
1767
4181
|
state,
|
|
1768
4182
|
onCommand,
|
|
1769
|
-
signal,
|
|
4183
|
+
signal: signal2,
|
|
1770
4184
|
reporter,
|
|
1771
4185
|
now,
|
|
1772
4186
|
stableConnectionMs,
|
|
@@ -1776,13 +4190,13 @@ async function runCommandStream(config, reporter, {
|
|
|
1776
4190
|
}
|
|
1777
4191
|
});
|
|
1778
4192
|
} catch (error) {
|
|
1779
|
-
if (
|
|
4193
|
+
if (signal2.aborted || isAbortError(error)) return;
|
|
1780
4194
|
const next = streamErrorState(error, lastLoggedError, reconnectDelay, reporter);
|
|
1781
4195
|
reconnectDelay = next.reconnectDelay;
|
|
1782
4196
|
lastLoggedError = next.lastLoggedError;
|
|
1783
4197
|
}
|
|
1784
|
-
if (!
|
|
1785
|
-
await sleepImplementation(reconnectDelay,
|
|
4198
|
+
if (!signal2.aborted && hasPending()) {
|
|
4199
|
+
await sleepImplementation(reconnectDelay, signal2);
|
|
1786
4200
|
reconnectDelay = Math.min(reconnectDelay * 2, 6e4);
|
|
1787
4201
|
}
|
|
1788
4202
|
}
|
|
@@ -2070,7 +4484,7 @@ function createPermissionController({
|
|
|
2070
4484
|
}
|
|
2071
4485
|
|
|
2072
4486
|
// src/plugin.js
|
|
2073
|
-
async function BackeerPlugin({ client, directory }, options = {}) {
|
|
4487
|
+
async function BackeerPlugin({ client, directory, feedback, v2 = false }, options = {}) {
|
|
2074
4488
|
const bootstrapReporter = createOpenCodeReporter(
|
|
2075
4489
|
client,
|
|
2076
4490
|
options.logLevel ?? process.env.BACKEER_LOG_LEVEL
|
|
@@ -2083,7 +4497,14 @@ async function BackeerPlugin({ client, directory }, options = {}) {
|
|
|
2083
4497
|
return {};
|
|
2084
4498
|
}
|
|
2085
4499
|
const reporter = createOpenCodeReporter(client, config.logLevel);
|
|
2086
|
-
const conversation = createConversationFeedback({ client, reporter });
|
|
4500
|
+
const conversation = feedback ?? createConversationFeedback({ client, reporter });
|
|
4501
|
+
if (config.liveBridge.error) reporter.error("Live control disabled", config.liveBridge.error);
|
|
4502
|
+
const liveBridge = await createLiveBridge({ config, client, directory, reporter }).catch((error) => {
|
|
4503
|
+
reporter.error("Live control unavailable", error);
|
|
4504
|
+
return { async handle() {
|
|
4505
|
+
}, async dispose() {
|
|
4506
|
+
} };
|
|
4507
|
+
});
|
|
2087
4508
|
const permissionController = createPermissionController({
|
|
2088
4509
|
config,
|
|
2089
4510
|
reporter,
|
|
@@ -2101,7 +4522,7 @@ async function BackeerPlugin({ client, directory }, options = {}) {
|
|
|
2101
4522
|
const permissionPublications = createDeliveryTracker();
|
|
2102
4523
|
const questionPublications = createDeliveryTracker();
|
|
2103
4524
|
const todoCompletions = createCompletionTracker();
|
|
2104
|
-
const updateChecker = createUpdateChecker();
|
|
4525
|
+
const updateChecker = createUpdateChecker({ v2 });
|
|
2105
4526
|
const handleBackeerCommand = createBackeerCommandHandler({
|
|
2106
4527
|
client,
|
|
2107
4528
|
config,
|
|
@@ -2191,6 +4612,38 @@ async function BackeerPlugin({ client, directory }, options = {}) {
|
|
|
2191
4612
|
conversation.error(identity.sessionID, "Question could not be sent");
|
|
2192
4613
|
});
|
|
2193
4614
|
}
|
|
4615
|
+
async function handleNotificationEvent(event) {
|
|
4616
|
+
if (!config.token) return;
|
|
4617
|
+
conversation.handle(event);
|
|
4618
|
+
lifecycleController.handle(event);
|
|
4619
|
+
if (config.permissions && event.type === "permission.asked") {
|
|
4620
|
+
await handlePermissionAsked(event);
|
|
4621
|
+
return;
|
|
4622
|
+
}
|
|
4623
|
+
if (config.permissions && event.type === "permission.replied") {
|
|
4624
|
+
permissionController.resolveLocally(
|
|
4625
|
+
event.properties.requestID ?? event.properties.id
|
|
4626
|
+
);
|
|
4627
|
+
return;
|
|
4628
|
+
}
|
|
4629
|
+
if (config.todos && event.type === "todo.updated") {
|
|
4630
|
+
await handleTodoUpdated(event);
|
|
4631
|
+
return;
|
|
4632
|
+
}
|
|
4633
|
+
if (config.questions && (event.type === "question.asked" || event.type === "question.v2.asked")) {
|
|
4634
|
+
await handleQuestionAsked(event);
|
|
4635
|
+
return;
|
|
4636
|
+
}
|
|
4637
|
+
if (config.questions && ["question.replied", "question.v2.replied", "question.rejected", "question.v2.rejected"].includes(event.type)) {
|
|
4638
|
+
const requestID = event.properties.requestID ?? event.properties.id;
|
|
4639
|
+
if (typeof requestID === "string") {
|
|
4640
|
+
permissionController.resolveQuestionLocally(
|
|
4641
|
+
requestID,
|
|
4642
|
+
event.type.endsWith("rejected") ? "rejected" : "answered"
|
|
4643
|
+
);
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
2194
4647
|
return {
|
|
2195
4648
|
config: async (opencodeConfig) => {
|
|
2196
4649
|
registerBackeerCommand(opencodeConfig);
|
|
@@ -2198,38 +4651,10 @@ async function BackeerPlugin({ client, directory }, options = {}) {
|
|
|
2198
4651
|
"command.execute.before": handleBackeerCommand,
|
|
2199
4652
|
"chat.message": handleUpdateNotice,
|
|
2200
4653
|
event: async ({ event }) => {
|
|
2201
|
-
|
|
2202
|
-
conversation.handle(event);
|
|
2203
|
-
lifecycleController.handle(event);
|
|
2204
|
-
if (config.permissions && event.type === "permission.asked") {
|
|
2205
|
-
await handlePermissionAsked(event);
|
|
2206
|
-
return;
|
|
2207
|
-
}
|
|
2208
|
-
if (config.permissions && event.type === "permission.replied") {
|
|
2209
|
-
permissionController.resolveLocally(
|
|
2210
|
-
event.properties.requestID ?? event.properties.id
|
|
2211
|
-
);
|
|
2212
|
-
return;
|
|
2213
|
-
}
|
|
2214
|
-
if (config.todos && event.type === "todo.updated") {
|
|
2215
|
-
await handleTodoUpdated(event);
|
|
2216
|
-
return;
|
|
2217
|
-
}
|
|
2218
|
-
if (config.questions && (event.type === "question.asked" || event.type === "question.v2.asked")) {
|
|
2219
|
-
await handleQuestionAsked(event);
|
|
2220
|
-
return;
|
|
2221
|
-
}
|
|
2222
|
-
if (config.questions && ["question.replied", "question.v2.replied", "question.rejected", "question.v2.rejected"].includes(event.type)) {
|
|
2223
|
-
const requestID = event.properties.requestID ?? event.properties.id;
|
|
2224
|
-
if (typeof requestID === "string") {
|
|
2225
|
-
permissionController.resolveQuestionLocally(
|
|
2226
|
-
requestID,
|
|
2227
|
-
event.type.endsWith("rejected") ? "rejected" : "answered"
|
|
2228
|
-
);
|
|
2229
|
-
}
|
|
2230
|
-
}
|
|
4654
|
+
await Promise.all([handleNotificationEvent(event), liveBridge.handle(event)]);
|
|
2231
4655
|
},
|
|
2232
4656
|
dispose: async () => {
|
|
4657
|
+
await liveBridge.dispose();
|
|
2233
4658
|
await permissionController.dispose();
|
|
2234
4659
|
lifecycleController.dispose();
|
|
2235
4660
|
permissionPublications.clear();
|
|
@@ -2239,6 +4664,744 @@ async function BackeerPlugin({ client, directory }, options = {}) {
|
|
|
2239
4664
|
}
|
|
2240
4665
|
};
|
|
2241
4666
|
}
|
|
4667
|
+
|
|
4668
|
+
// src/opencode-v2-forms.js
|
|
4669
|
+
init_promise();
|
|
4670
|
+
|
|
4671
|
+
// node_modules/@opencode/client/dist/chunks/service-timing-ve4aws36.js
|
|
4672
|
+
import { spawn } from "node:child_process";
|
|
4673
|
+
var stderrLimit = 8 * 1024;
|
|
4674
|
+
function spawnServiceContender2(command, args, env) {
|
|
4675
|
+
const child = spawn(command, args, {
|
|
4676
|
+
detached: true,
|
|
4677
|
+
windowsHide: true,
|
|
4678
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
4679
|
+
env: { ...process.env, ...env }
|
|
4680
|
+
});
|
|
4681
|
+
let error;
|
|
4682
|
+
let closed = false;
|
|
4683
|
+
let stderr = Buffer.alloc(0);
|
|
4684
|
+
const onStderr = (chunk) => {
|
|
4685
|
+
const tail = chunk.subarray(-stderrLimit);
|
|
4686
|
+
stderr = tail.length === stderrLimit ? Buffer.from(tail) : Buffer.concat([stderr.subarray(-(stderrLimit - tail.length)), tail]);
|
|
4687
|
+
};
|
|
4688
|
+
child.stderr?.on("data", onStderr);
|
|
4689
|
+
if (child.stderr !== null && "unref" in child.stderr && typeof child.stderr.unref === "function")
|
|
4690
|
+
child.stderr.unref();
|
|
4691
|
+
child.once("error", (cause) => {
|
|
4692
|
+
error = new Error("Failed to start server", { cause });
|
|
4693
|
+
});
|
|
4694
|
+
child.once("close", () => {
|
|
4695
|
+
closed = true;
|
|
4696
|
+
});
|
|
4697
|
+
child.unref();
|
|
4698
|
+
return {
|
|
4699
|
+
child,
|
|
4700
|
+
error: () => error,
|
|
4701
|
+
closed: () => closed,
|
|
4702
|
+
stderr: () => stderr.toString("utf8").trim(),
|
|
4703
|
+
release: () => {
|
|
4704
|
+
child.stderr?.off("data", onStderr);
|
|
4705
|
+
child.stderr?.resume();
|
|
4706
|
+
stderr = Buffer.alloc(0);
|
|
4707
|
+
}
|
|
4708
|
+
};
|
|
4709
|
+
}
|
|
4710
|
+
function contenderPool2(timing) {
|
|
4711
|
+
const contenders = /* @__PURE__ */ new Set();
|
|
4712
|
+
let failure2;
|
|
4713
|
+
let spawnDelay = timing.spawnDelay;
|
|
4714
|
+
let lastSpawn = 0;
|
|
4715
|
+
return {
|
|
4716
|
+
failure: () => failure2,
|
|
4717
|
+
serviceAnswered() {
|
|
4718
|
+
spawnDelay = timing.spawnDelay;
|
|
4719
|
+
},
|
|
4720
|
+
evict(pid) {
|
|
4721
|
+
for (const item of contenders) {
|
|
4722
|
+
if (item.child.pid === pid || contenderFinished2(item)) {
|
|
4723
|
+
item.release();
|
|
4724
|
+
contenders.delete(item);
|
|
4725
|
+
}
|
|
4726
|
+
}
|
|
4727
|
+
failure2 = void 0;
|
|
4728
|
+
lastSpawn = 0;
|
|
4729
|
+
},
|
|
4730
|
+
recruitNow() {
|
|
4731
|
+
lastSpawn = Date.now() - spawnDelay;
|
|
4732
|
+
},
|
|
4733
|
+
reap() {
|
|
4734
|
+
const finished = [...contenders].filter(contenderFinished2);
|
|
4735
|
+
failure2 ??= finished.map(contenderFailure).find((error) => error !== void 0);
|
|
4736
|
+
if (finished.some((item) => item.child.exitCode === 0))
|
|
4737
|
+
spawnDelay = Math.min(spawnDelay * 2, timing.maxSpawnDelay);
|
|
4738
|
+
finished.forEach((item) => contenders.delete(item));
|
|
4739
|
+
return contenders.size === 0 ? failure2 : void 0;
|
|
4740
|
+
},
|
|
4741
|
+
shouldRecruit(registered2) {
|
|
4742
|
+
if (lastSpawn === 0 && registered2)
|
|
4743
|
+
lastSpawn = Date.now();
|
|
4744
|
+
return failure2 === void 0 && contenders.size < 2 && Date.now() - lastSpawn >= spawnDelay;
|
|
4745
|
+
},
|
|
4746
|
+
add(contender) {
|
|
4747
|
+
contenders.add(contender);
|
|
4748
|
+
lastSpawn = Date.now();
|
|
4749
|
+
},
|
|
4750
|
+
releaseAll() {
|
|
4751
|
+
contenders.forEach((contender) => contender.release());
|
|
4752
|
+
}
|
|
4753
|
+
};
|
|
4754
|
+
}
|
|
4755
|
+
function contenderFailure(contender) {
|
|
4756
|
+
const error = contender.error();
|
|
4757
|
+
if (error !== void 0)
|
|
4758
|
+
return error;
|
|
4759
|
+
if (contender.child.exitCode !== null && contender.child.exitCode !== 0)
|
|
4760
|
+
return startupError(`Server process exited with code ${contender.child.exitCode}`, contender.stderr());
|
|
4761
|
+
if (contender.child.signalCode !== null)
|
|
4762
|
+
return startupError(`Server process terminated by ${contender.child.signalCode}`, contender.stderr());
|
|
4763
|
+
return;
|
|
4764
|
+
}
|
|
4765
|
+
function contenderFinished2(contender) {
|
|
4766
|
+
return contender.error() !== void 0 || contender.closed();
|
|
4767
|
+
}
|
|
4768
|
+
function startupError(message, stderr) {
|
|
4769
|
+
return new Error(stderr ? `${message}
|
|
4770
|
+
${stderr}` : message);
|
|
4771
|
+
}
|
|
4772
|
+
|
|
4773
|
+
// node_modules/@opencode/client/dist/chunks/service-timing-xgnj2w4v.js
|
|
4774
|
+
var timings = /* @__PURE__ */ new WeakMap();
|
|
4775
|
+
var defaultEnsureTiming2 = {
|
|
4776
|
+
pollInterval: 25,
|
|
4777
|
+
requestTimeout: 2e3,
|
|
4778
|
+
spawnDelay: 5e3,
|
|
4779
|
+
maxSpawnDelay: 3e4,
|
|
4780
|
+
promiseTimeout: 12e4,
|
|
4781
|
+
stopPollInterval: 50,
|
|
4782
|
+
stopPollAttempts: 100
|
|
4783
|
+
};
|
|
4784
|
+
function ensureTiming2(options) {
|
|
4785
|
+
return timings.get(options) ?? defaultEnsureTiming2;
|
|
4786
|
+
}
|
|
4787
|
+
|
|
4788
|
+
// node_modules/@opencode/client/dist/chunks/service-timing-sxt88q69.js
|
|
4789
|
+
function matchesVersion2(version, options) {
|
|
4790
|
+
if (options.version === void 0)
|
|
4791
|
+
return true;
|
|
4792
|
+
if (version === void 0)
|
|
4793
|
+
return false;
|
|
4794
|
+
if (typeof options.version === "function")
|
|
4795
|
+
return options.version(version);
|
|
4796
|
+
return version === options.version;
|
|
4797
|
+
}
|
|
4798
|
+
|
|
4799
|
+
// node_modules/@opencode/client/dist/chunks/service-timing-0rcx1gca.js
|
|
4800
|
+
init_service_timing_9rqn6x4v();
|
|
4801
|
+
import { readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
4802
|
+
var exports_pty_handoff = {};
|
|
4803
|
+
__export2(exports_pty_handoff, {
|
|
4804
|
+
PtyHandoff: () => exports_pty_handoff,
|
|
4805
|
+
clear: () => clear2,
|
|
4806
|
+
complete: () => complete2,
|
|
4807
|
+
environment: () => environment2,
|
|
4808
|
+
prepare: () => prepare2
|
|
4809
|
+
});
|
|
4810
|
+
async function prepare2(file, info, timeout) {
|
|
4811
|
+
const existing = await read(file);
|
|
4812
|
+
if (existing !== void 0 && existing.expiresAt > Date.now() && same(existing.source, info))
|
|
4813
|
+
return;
|
|
4814
|
+
const { OpenCode } = await Promise.resolve().then(() => (init_promise(), promise_exports));
|
|
4815
|
+
const client = OpenCode.make({
|
|
4816
|
+
baseUrl: info.url,
|
|
4817
|
+
headers: info.password === void 0 ? void 0 : { authorization: "Basic " + Buffer.from(`opencode:${info.password}`).toString("base64") }
|
|
4818
|
+
});
|
|
4819
|
+
const handoff = await client.experimental.persistentPty.handoff({ signal: AbortSignal.timeout(timeout) }).then(parse).catch(async (cause) => {
|
|
4820
|
+
const concurrent = await read(file);
|
|
4821
|
+
if (concurrent !== void 0 && concurrent.expiresAt > Date.now() && same(concurrent.source, info))
|
|
4822
|
+
return;
|
|
4823
|
+
console.warn("Background service cannot hand off persistent terminals; shutting them down before replacement", cause);
|
|
4824
|
+
await client.experimental.persistentPty.shutdown({ signal: AbortSignal.timeout(timeout) }).catch(() => {
|
|
4825
|
+
});
|
|
4826
|
+
return null;
|
|
4827
|
+
});
|
|
4828
|
+
if (handoff === void 0)
|
|
4829
|
+
return;
|
|
4830
|
+
await publish2(file, info, handoff).catch((cause) => console.warn("Failed to publish persistent terminal handoff", cause));
|
|
4831
|
+
}
|
|
4832
|
+
function parse(body) {
|
|
4833
|
+
if (typeof body !== "object" || body === null || !("handoff" in body))
|
|
4834
|
+
throw new Error("Invalid persistent terminal handoff response");
|
|
4835
|
+
if (body.handoff === null)
|
|
4836
|
+
return null;
|
|
4837
|
+
if (!isHandoff(body.handoff) || body.handoff.expiresAt <= Date.now())
|
|
4838
|
+
throw new Error("Invalid or expired persistent terminal handoff");
|
|
4839
|
+
return body.handoff;
|
|
4840
|
+
}
|
|
4841
|
+
async function publish2(file, info, handoff) {
|
|
4842
|
+
const temporary = `${file}.pty-handoff.${crypto.randomUUID()}.tmp`;
|
|
4843
|
+
await writeFile(temporary, JSON.stringify({
|
|
4844
|
+
source: { id: info.id, pid: info.pid, url: info.url },
|
|
4845
|
+
handoff,
|
|
4846
|
+
expiresAt: handoff?.expiresAt ?? Date.now() + 3e4
|
|
4847
|
+
}), { mode: 384, flag: "wx" });
|
|
4848
|
+
await rename(temporary, file + ".pty-handoff").finally(() => rm(temporary, { force: true }));
|
|
4849
|
+
}
|
|
4850
|
+
async function environment2(file, env) {
|
|
4851
|
+
const record = await read(file);
|
|
4852
|
+
const current = await readFile(file, "utf8").then((text) => JSON.parse(text)).catch(() => {
|
|
4853
|
+
return;
|
|
4854
|
+
});
|
|
4855
|
+
const handoff = record !== void 0 && record.expiresAt > Date.now() && (current === void 0 || same(record.source, current)) ? record.handoff : void 0;
|
|
4856
|
+
return { ...env, OPENCODE_PTY_HANDOFF: handoff == null ? void 0 : JSON.stringify(handoff) };
|
|
4857
|
+
}
|
|
4858
|
+
async function complete2(file, info) {
|
|
4859
|
+
const record = await read(file);
|
|
4860
|
+
if (record !== void 0 && !same(record.source, info))
|
|
4861
|
+
await clear2(file);
|
|
4862
|
+
}
|
|
4863
|
+
async function clear2(file) {
|
|
4864
|
+
await rm(file + ".pty-handoff", { force: true });
|
|
4865
|
+
}
|
|
4866
|
+
async function read(file) {
|
|
4867
|
+
const value = await readFile(file + ".pty-handoff", "utf8").then((text) => JSON.parse(text)).catch(() => {
|
|
4868
|
+
return;
|
|
4869
|
+
});
|
|
4870
|
+
if (typeof value !== "object" || value === null || !("source" in value) || !("handoff" in value))
|
|
4871
|
+
return;
|
|
4872
|
+
if (typeof value.source !== "object" || value.source === null)
|
|
4873
|
+
return;
|
|
4874
|
+
if (!("pid" in value.source) || typeof value.source.pid !== "number")
|
|
4875
|
+
return;
|
|
4876
|
+
if (!("url" in value.source) || typeof value.source.url !== "string")
|
|
4877
|
+
return;
|
|
4878
|
+
if ("id" in value.source && typeof value.source.id !== "string")
|
|
4879
|
+
return;
|
|
4880
|
+
if (value.handoff !== null && !isHandoff(value.handoff))
|
|
4881
|
+
return;
|
|
4882
|
+
if (!("expiresAt" in value) || typeof value.expiresAt !== "number" || !Number.isFinite(value.expiresAt))
|
|
4883
|
+
return;
|
|
4884
|
+
return {
|
|
4885
|
+
source: {
|
|
4886
|
+
id: "id" in value.source && typeof value.source.id === "string" ? value.source.id : void 0,
|
|
4887
|
+
pid: value.source.pid,
|
|
4888
|
+
url: value.source.url
|
|
4889
|
+
},
|
|
4890
|
+
handoff: value.handoff,
|
|
4891
|
+
expiresAt: value.expiresAt
|
|
4892
|
+
};
|
|
4893
|
+
}
|
|
4894
|
+
function same(left, right) {
|
|
4895
|
+
return left.id === right.id && left.pid === right.pid && left.url === right.url;
|
|
4896
|
+
}
|
|
4897
|
+
function isHandoff(value) {
|
|
4898
|
+
return typeof value === "object" && value !== null && "directory" in value && typeof value.directory === "string" && "instanceID" in value && typeof value.instanceID === "string" && "ticket" in value && typeof value.ticket === "string" && "expiresAt" in value && typeof value.expiresAt === "number" && Number.isFinite(value.expiresAt);
|
|
4899
|
+
}
|
|
4900
|
+
|
|
4901
|
+
// node_modules/@opencode/client/dist/chunks/service-timing-8ye1ye6f.js
|
|
4902
|
+
import { homedir as homedir2 } from "node:os";
|
|
4903
|
+
import { join as join3 } from "node:path";
|
|
4904
|
+
function decide2(service, options) {
|
|
4905
|
+
if (!matchesVersion2(service.version, options))
|
|
4906
|
+
return { _tag: "replace", pty: service.state === "ready" ? "handoff" : "clear" };
|
|
4907
|
+
if (!service.compatible)
|
|
4908
|
+
return fail("Background service uses an incompatible health protocol. Update this client or explicitly restart the service.");
|
|
4909
|
+
if (service.state === "ready")
|
|
4910
|
+
return { _tag: "reuse" };
|
|
4911
|
+
if (service.state === "failed")
|
|
4912
|
+
return fail("Background service failed to start");
|
|
4913
|
+
return { _tag: "wait" };
|
|
4914
|
+
}
|
|
4915
|
+
function fail(message) {
|
|
4916
|
+
return { _tag: "fail", error: new Error(message) };
|
|
4917
|
+
}
|
|
4918
|
+
function fallback2() {
|
|
4919
|
+
return join3(process.env["XDG_STATE_HOME"] ?? join3(homedir2(), ".local", "state"), "opencode", "service.json");
|
|
4920
|
+
}
|
|
4921
|
+
function same2(left, right) {
|
|
4922
|
+
return left.id === right.id && left.version === right.version && left.url === right.url && left.pid === right.pid;
|
|
4923
|
+
}
|
|
4924
|
+
async function probeResult2(info, timeout = defaultEnsureTiming2.requestTimeout) {
|
|
4925
|
+
const endpoint = {
|
|
4926
|
+
url: info.url,
|
|
4927
|
+
auth: info.password === void 0 ? void 0 : { type: "basic", username: "opencode", password: info.password }
|
|
4928
|
+
};
|
|
4929
|
+
const signal2 = AbortSignal.timeout(timeout);
|
|
4930
|
+
const result = await fetch(new URL("/api/info", info.url), { headers: headers2(endpoint), signal: signal2 }).then(async (response2) => ({
|
|
4931
|
+
response: response2,
|
|
4932
|
+
body: response2.status === 404 ? void 0 : await response2.json()
|
|
4933
|
+
})).catch(() => {
|
|
4934
|
+
return;
|
|
4935
|
+
});
|
|
4936
|
+
if (result === void 0)
|
|
4937
|
+
return { service: void 0, timedOut: signal2.aborted };
|
|
4938
|
+
const response = result.response;
|
|
4939
|
+
if (response.status === 404)
|
|
4940
|
+
return {
|
|
4941
|
+
service: {
|
|
4942
|
+
info,
|
|
4943
|
+
endpoint,
|
|
4944
|
+
version: info.version,
|
|
4945
|
+
state: "ready",
|
|
4946
|
+
compatible: false
|
|
4947
|
+
},
|
|
4948
|
+
timedOut: false
|
|
4949
|
+
};
|
|
4950
|
+
const serverInfo = decodeInfo(result.body);
|
|
4951
|
+
if (serverInfo === void 0)
|
|
4952
|
+
return { service: void 0, timedOut: false };
|
|
4953
|
+
if (serverInfo.pid !== info.pid)
|
|
4954
|
+
return { service: void 0, timedOut: false };
|
|
4955
|
+
if (info.version !== void 0 && serverInfo.version !== info.version)
|
|
4956
|
+
return { service: void 0, timedOut: false };
|
|
4957
|
+
return {
|
|
4958
|
+
service: {
|
|
4959
|
+
info,
|
|
4960
|
+
endpoint,
|
|
4961
|
+
version: serverInfo.version,
|
|
4962
|
+
state: response.ok ? "ready" : response.status === 500 ? "failed" : "waiting",
|
|
4963
|
+
compatible: true
|
|
4964
|
+
},
|
|
4965
|
+
timedOut: false
|
|
4966
|
+
};
|
|
4967
|
+
}
|
|
4968
|
+
function headers2(endpoint) {
|
|
4969
|
+
if (endpoint.auth === void 0)
|
|
4970
|
+
return;
|
|
4971
|
+
return {
|
|
4972
|
+
authorization: "Basic " + Buffer.from(endpoint.auth.username + ":" + endpoint.auth.password).toString("base64")
|
|
4973
|
+
};
|
|
4974
|
+
}
|
|
4975
|
+
function decodeInfo(input) {
|
|
4976
|
+
if (typeof input !== "object" || input === null)
|
|
4977
|
+
return;
|
|
4978
|
+
if (!("version" in input) || typeof input.version !== "string")
|
|
4979
|
+
return;
|
|
4980
|
+
if (!("pid" in input) || typeof input.pid !== "number" || !Number.isInteger(input.pid) || input.pid < 0)
|
|
4981
|
+
return;
|
|
4982
|
+
return { version: input.version, pid: input.pid };
|
|
4983
|
+
}
|
|
4984
|
+
|
|
4985
|
+
// node_modules/@opencode/client/dist/promise/service.js
|
|
4986
|
+
import { readFile as readFile2, rm as rm2 } from "node:fs/promises";
|
|
4987
|
+
async function discover(options = {}) {
|
|
4988
|
+
const found = (await registered(options.file)).service;
|
|
4989
|
+
if (found?.state !== "ready")
|
|
4990
|
+
return;
|
|
4991
|
+
if (!found.compatible)
|
|
4992
|
+
return;
|
|
4993
|
+
if (!matchesVersion2(found.version, options))
|
|
4994
|
+
return;
|
|
4995
|
+
return found.endpoint;
|
|
4996
|
+
}
|
|
4997
|
+
async function ensure(options = {}) {
|
|
4998
|
+
const timing = ensureTiming2(options);
|
|
4999
|
+
const deadline = Date.now() + timing.promiseTimeout;
|
|
5000
|
+
const pool = contenderPool2(timing);
|
|
5001
|
+
let timeouts;
|
|
5002
|
+
let announced = false;
|
|
5003
|
+
const announce = (reason, previousVersion) => {
|
|
5004
|
+
if (announced)
|
|
5005
|
+
return;
|
|
5006
|
+
announced = true;
|
|
5007
|
+
options.onStart?.(reason, previousVersion);
|
|
5008
|
+
};
|
|
5009
|
+
const spawnContender = async () => {
|
|
5010
|
+
const [command, ...args] = options.command ?? ["opencode", "serve", "--service"];
|
|
5011
|
+
if (command === void 0)
|
|
5012
|
+
throw new Error("Missing service command");
|
|
5013
|
+
try {
|
|
5014
|
+
return spawnServiceContender2(command, args, await environment2(options.file ?? fallback2(), options.env));
|
|
5015
|
+
} catch (cause) {
|
|
5016
|
+
throw new Error("Failed to start server", { cause });
|
|
5017
|
+
}
|
|
5018
|
+
};
|
|
5019
|
+
try {
|
|
5020
|
+
while (true) {
|
|
5021
|
+
if (Date.now() >= deadline)
|
|
5022
|
+
throw pool.failure() ?? new Error("Timed out waiting for the background service to start");
|
|
5023
|
+
const registration = await registered(options.file, timing.requestTimeout);
|
|
5024
|
+
if (registration.timedOut && registration.info !== void 0) {
|
|
5025
|
+
timeouts = {
|
|
5026
|
+
info: registration.info,
|
|
5027
|
+
count: timeouts !== void 0 && same2(timeouts.info, registration.info) ? timeouts.count + 1 : 1
|
|
5028
|
+
};
|
|
5029
|
+
if (timeouts.count >= 3) {
|
|
5030
|
+
announce("missing");
|
|
5031
|
+
console.warn("Background service is unresponsive; recovery cannot preserve persistent terminals");
|
|
5032
|
+
await clear2(options.file ?? fallback2());
|
|
5033
|
+
await terminate(registration.info, options, timing);
|
|
5034
|
+
pool.evict(registration.info.pid);
|
|
5035
|
+
pool.recruitNow();
|
|
5036
|
+
timeouts = void 0;
|
|
5037
|
+
}
|
|
5038
|
+
} else
|
|
5039
|
+
timeouts = void 0;
|
|
5040
|
+
if (registration.service !== void 0) {
|
|
5041
|
+
pool.serviceAnswered();
|
|
5042
|
+
const service2 = registration.service;
|
|
5043
|
+
const decision = decide2(service2, options);
|
|
5044
|
+
if (decision._tag === "fail")
|
|
5045
|
+
throw decision.error;
|
|
5046
|
+
if (decision._tag === "reuse") {
|
|
5047
|
+
await complete2(options.file ?? fallback2(), service2.info);
|
|
5048
|
+
return service2.endpoint;
|
|
5049
|
+
}
|
|
5050
|
+
if (decision._tag === "replace") {
|
|
5051
|
+
announce("version-mismatch", service2.version);
|
|
5052
|
+
if (service2.state !== "ready")
|
|
5053
|
+
console.warn("Background service is not ready; replacement cannot preserve persistent terminals");
|
|
5054
|
+
await stop({ file: options.file, pty: decision.pty }).catch(() => {
|
|
5055
|
+
return;
|
|
5056
|
+
});
|
|
5057
|
+
pool.evict(service2.info.pid);
|
|
5058
|
+
}
|
|
5059
|
+
} else {
|
|
5060
|
+
const failed = pool.reap();
|
|
5061
|
+
if (failed !== void 0)
|
|
5062
|
+
throw failed;
|
|
5063
|
+
if (pool.shouldRecruit(registration.info !== void 0)) {
|
|
5064
|
+
announce("missing");
|
|
5065
|
+
pool.add(await spawnContender());
|
|
5066
|
+
}
|
|
5067
|
+
}
|
|
5068
|
+
await delay(timing.pollInterval);
|
|
5069
|
+
}
|
|
5070
|
+
} finally {
|
|
5071
|
+
pool.releaseAll();
|
|
5072
|
+
}
|
|
5073
|
+
}
|
|
5074
|
+
async function stop(options = {}) {
|
|
5075
|
+
const info = await read2(options.file);
|
|
5076
|
+
await (options.pty === "handoff" && info !== void 0 ? prepare2(options.file ?? fallback2(), info, defaultEnsureTiming2.requestTimeout) : clear2(options.file ?? fallback2())).catch((cause) => console.warn("Failed to prepare persistent terminals for replacement", cause));
|
|
5077
|
+
if (info !== void 0)
|
|
5078
|
+
await terminate(info, options, ensureTiming2(options));
|
|
5079
|
+
}
|
|
5080
|
+
async function read2(file) {
|
|
5081
|
+
const text = await readFile2(file ?? fallback2(), "utf8").catch(() => {
|
|
5082
|
+
return;
|
|
5083
|
+
});
|
|
5084
|
+
if (text === void 0)
|
|
5085
|
+
return;
|
|
5086
|
+
try {
|
|
5087
|
+
return JSON.parse(text);
|
|
5088
|
+
} catch {
|
|
5089
|
+
return;
|
|
5090
|
+
}
|
|
5091
|
+
}
|
|
5092
|
+
async function registered(file, timeout) {
|
|
5093
|
+
const info = await read2(file);
|
|
5094
|
+
if (info === void 0)
|
|
5095
|
+
return { info: void 0, service: void 0, timedOut: false };
|
|
5096
|
+
return { info, ...await probeResult2(info, timeout) };
|
|
5097
|
+
}
|
|
5098
|
+
function signal(pid, name) {
|
|
5099
|
+
try {
|
|
5100
|
+
process.kill(pid, name);
|
|
5101
|
+
} catch {
|
|
5102
|
+
}
|
|
5103
|
+
}
|
|
5104
|
+
function stopped(pid) {
|
|
5105
|
+
try {
|
|
5106
|
+
process.kill(pid, 0);
|
|
5107
|
+
return false;
|
|
5108
|
+
} catch {
|
|
5109
|
+
return true;
|
|
5110
|
+
}
|
|
5111
|
+
}
|
|
5112
|
+
async function waitUntilStopped(pid, timing) {
|
|
5113
|
+
for (let attempt = 0; attempt <= timing.stopPollAttempts; attempt++) {
|
|
5114
|
+
if (stopped(pid))
|
|
5115
|
+
return true;
|
|
5116
|
+
if (attempt < timing.stopPollAttempts)
|
|
5117
|
+
await delay(timing.stopPollInterval);
|
|
5118
|
+
}
|
|
5119
|
+
return false;
|
|
5120
|
+
}
|
|
5121
|
+
async function terminate(info, options, timing) {
|
|
5122
|
+
const current = await read2(options.file);
|
|
5123
|
+
if (current === void 0 || !same2(current, info))
|
|
5124
|
+
return;
|
|
5125
|
+
signal(info.pid, "SIGTERM");
|
|
5126
|
+
if (!await waitUntilStopped(info.pid, timing)) {
|
|
5127
|
+
signal(info.pid, "SIGKILL");
|
|
5128
|
+
if (!await waitUntilStopped(info.pid, timing))
|
|
5129
|
+
throw new Error(`Server process ${info.pid} is still running`);
|
|
5130
|
+
}
|
|
5131
|
+
const latest = await read2(options.file);
|
|
5132
|
+
if (latest === void 0 || !same2(latest, info))
|
|
5133
|
+
return;
|
|
5134
|
+
await rm2(options.file ?? fallback2(), { force: true });
|
|
5135
|
+
}
|
|
5136
|
+
function delay(milliseconds) {
|
|
5137
|
+
return new Promise((resolve2) => setTimeout(resolve2, milliseconds));
|
|
5138
|
+
}
|
|
5139
|
+
var Service = { discover, ensure, stop, headers: headers2 };
|
|
5140
|
+
|
|
5141
|
+
// src/opencode-v2-forms.js
|
|
5142
|
+
async function getFormApi(ctx, sessionID, { makeClient = exports_client.make } = {}) {
|
|
5143
|
+
const endpoint = await Service.discover({ version: ctx.app.version });
|
|
5144
|
+
if (!endpoint) {
|
|
5145
|
+
throw new HttpError("Remote question replies require the OpenCode V2 shared service", 501);
|
|
5146
|
+
}
|
|
5147
|
+
const client = makeClient({ baseUrl: endpoint.url, headers: Service.headers(endpoint) });
|
|
5148
|
+
let session;
|
|
5149
|
+
try {
|
|
5150
|
+
session = await client.session.get({ sessionID });
|
|
5151
|
+
} catch {
|
|
5152
|
+
throw new HttpError("The question session is not owned by the shared OpenCode service", 501);
|
|
5153
|
+
}
|
|
5154
|
+
if (session.location.directory !== ctx.location.directory) {
|
|
5155
|
+
throw new HttpError("The question session belongs to another OpenCode location", 403);
|
|
5156
|
+
}
|
|
5157
|
+
return client.session.form;
|
|
5158
|
+
}
|
|
5159
|
+
|
|
5160
|
+
// src/opencode-v2-client.js
|
|
5161
|
+
async function nativeReply(operation) {
|
|
5162
|
+
try {
|
|
5163
|
+
return await operation();
|
|
5164
|
+
} catch (error) {
|
|
5165
|
+
const statuses = {
|
|
5166
|
+
PermissionNotFoundError: 404,
|
|
5167
|
+
SessionNotFoundError: 404,
|
|
5168
|
+
FormNotFoundError: 404,
|
|
5169
|
+
FormAlreadySettledError: 409,
|
|
5170
|
+
FormInvalidAnswerError: 422
|
|
5171
|
+
};
|
|
5172
|
+
const status = statuses[error?._tag];
|
|
5173
|
+
if (status) throw new HttpError(error.message || error._tag, status);
|
|
5174
|
+
throw error;
|
|
5175
|
+
}
|
|
5176
|
+
}
|
|
5177
|
+
function questionForm(form) {
|
|
5178
|
+
return form?.metadata?.kind === "question" && typeof form.sessionID === "string" && form.sessionID !== "global" && Array.isArray(form.fields) && form.fields.length > 0 && form.fields.every(
|
|
5179
|
+
(field) => ["string", "multiselect"].includes(field.type) && !field.hidden && !field.when?.length
|
|
5180
|
+
);
|
|
5181
|
+
}
|
|
5182
|
+
function normalizeV2Event(event) {
|
|
5183
|
+
const properties = event.data ?? {};
|
|
5184
|
+
const normalized = { ...event, properties };
|
|
5185
|
+
if (event.type === "form.created") {
|
|
5186
|
+
const form = properties.form;
|
|
5187
|
+
if (!questionForm(form)) return [];
|
|
5188
|
+
return [{ ...normalized, type: "question.v2.asked", properties: {
|
|
5189
|
+
id: form.id,
|
|
5190
|
+
sessionID: form.sessionID,
|
|
5191
|
+
questions: form.fields.map((field) => ({
|
|
5192
|
+
header: field.title ?? form.title,
|
|
5193
|
+
question: field.description ?? field.title ?? form.title,
|
|
5194
|
+
options: (field.options ?? []).map((option) => ({
|
|
5195
|
+
label: option.label,
|
|
5196
|
+
description: option.description ?? ""
|
|
5197
|
+
})),
|
|
5198
|
+
multiple: field.type === "multiselect",
|
|
5199
|
+
custom: field.custom === true || !field.options?.length
|
|
5200
|
+
}))
|
|
5201
|
+
} }];
|
|
5202
|
+
}
|
|
5203
|
+
if (event.type === "form.replied" || event.type === "form.cancelled") {
|
|
5204
|
+
return [{ ...normalized, type: event.type === "form.replied" ? "question.v2.replied" : "question.v2.rejected" }];
|
|
5205
|
+
}
|
|
5206
|
+
if (event.type === "session.execution.started") {
|
|
5207
|
+
return [{ ...normalized, type: "session.status", properties: {
|
|
5208
|
+
...properties,
|
|
5209
|
+
status: { type: "busy" }
|
|
5210
|
+
} }];
|
|
5211
|
+
}
|
|
5212
|
+
if (["session.execution.succeeded", "session.execution.interrupted"].includes(event.type)) {
|
|
5213
|
+
return [
|
|
5214
|
+
{ ...normalized, type: "message.updated", properties: { info: {
|
|
5215
|
+
role: "assistant",
|
|
5216
|
+
sessionID: properties.sessionID,
|
|
5217
|
+
id: event.id,
|
|
5218
|
+
time: { completed: event.created },
|
|
5219
|
+
error: event.type === "session.execution.interrupted"
|
|
5220
|
+
} } },
|
|
5221
|
+
{ ...normalized, type: "session.idle" }
|
|
5222
|
+
];
|
|
5223
|
+
}
|
|
5224
|
+
if (event.type === "session.execution.failed") {
|
|
5225
|
+
return [{ ...normalized, type: "session.error" }, { ...normalized, type: "session.idle" }];
|
|
5226
|
+
}
|
|
5227
|
+
if (event.type === "session.idle" || event.type === "session.status" && properties.status?.type === "idle") {
|
|
5228
|
+
return [];
|
|
5229
|
+
}
|
|
5230
|
+
return [normalized];
|
|
5231
|
+
}
|
|
5232
|
+
function createV2Client(ctx, resolveFormApi = (sessionID) => getFormApi(ctx, sessionID)) {
|
|
5233
|
+
return {
|
|
5234
|
+
liveBridge: createV2LiveClient(ctx),
|
|
5235
|
+
app: {
|
|
5236
|
+
async log({ body }) {
|
|
5237
|
+
console.error(JSON.stringify(body));
|
|
5238
|
+
}
|
|
5239
|
+
},
|
|
5240
|
+
session: {
|
|
5241
|
+
get: ({ path }) => ctx.session.get({ sessionID: path.id }),
|
|
5242
|
+
prompt: ({ path, body }) => ctx.session.synthetic({
|
|
5243
|
+
sessionID: path.id,
|
|
5244
|
+
text: body.parts.map((part) => part.text).join("\n"),
|
|
5245
|
+
resume: false
|
|
5246
|
+
})
|
|
5247
|
+
},
|
|
5248
|
+
postSessionIdPermissionsPermissionId: ({ path, body }) => nativeReply(() => ctx.permission.reply({
|
|
5249
|
+
sessionID: path.id,
|
|
5250
|
+
requestID: path.permissionID,
|
|
5251
|
+
decision: body.response
|
|
5252
|
+
})),
|
|
5253
|
+
v2: { session: { question: {
|
|
5254
|
+
async reply({ sessionID, requestID, questionV2Reply }) {
|
|
5255
|
+
const api = await resolveFormApi(sessionID);
|
|
5256
|
+
const form = await nativeReply(() => api.get({ sessionID, formID: requestID }));
|
|
5257
|
+
if (!questionForm(form)) throw new HttpError("Unsupported OpenCode question form", 422);
|
|
5258
|
+
const answers = questionV2Reply.answers;
|
|
5259
|
+
if (!Array.isArray(answers) || answers.length !== form.fields.length) {
|
|
5260
|
+
throw new HttpError("Question answer count does not match the form", 422);
|
|
5261
|
+
}
|
|
5262
|
+
const answer = {};
|
|
5263
|
+
form.fields.forEach((field, index) => {
|
|
5264
|
+
const selections = answers[index];
|
|
5265
|
+
if (!Array.isArray(selections) || selections.some((value) => typeof value !== "string")) {
|
|
5266
|
+
throw new HttpError("Invalid question answer", 422);
|
|
5267
|
+
}
|
|
5268
|
+
const values = selections.map(
|
|
5269
|
+
(label) => field.options?.find((option) => option.label === label)?.value ?? label
|
|
5270
|
+
);
|
|
5271
|
+
if (field.type === "multiselect") answer[field.key] = values;
|
|
5272
|
+
else if (values.length === 1) answer[field.key] = values[0];
|
|
5273
|
+
else if (values.length > 1) throw new HttpError("Single-choice question has multiple answers", 422);
|
|
5274
|
+
});
|
|
5275
|
+
return nativeReply(() => api.reply({ sessionID, formID: requestID, answer }));
|
|
5276
|
+
},
|
|
5277
|
+
async reject({ sessionID, requestID }) {
|
|
5278
|
+
const api = await resolveFormApi(sessionID);
|
|
5279
|
+
const form = await nativeReply(() => api.get({ sessionID, formID: requestID }));
|
|
5280
|
+
if (!questionForm(form)) throw new HttpError("Unsupported OpenCode question form", 422);
|
|
5281
|
+
return nativeReply(() => api.cancel({ sessionID, formID: requestID }));
|
|
5282
|
+
}
|
|
5283
|
+
} } },
|
|
5284
|
+
async ownsEvent(event) {
|
|
5285
|
+
if (event.location?.directory) return event.location.directory === ctx.location.directory;
|
|
5286
|
+
const sessionID = event.data?.sessionID ?? event.data?.form?.sessionID;
|
|
5287
|
+
if (!sessionID) return event.type === "installation.update-available";
|
|
5288
|
+
if (sessionID === "global") return false;
|
|
5289
|
+
try {
|
|
5290
|
+
const session = await ctx.session.get({ sessionID });
|
|
5291
|
+
return session.location?.directory === ctx.location.directory;
|
|
5292
|
+
} catch {
|
|
5293
|
+
return false;
|
|
5294
|
+
}
|
|
5295
|
+
}
|
|
5296
|
+
};
|
|
5297
|
+
}
|
|
5298
|
+
|
|
5299
|
+
// src/opencode-v2.js
|
|
5300
|
+
function waitForReconnect(signal2, delay2) {
|
|
5301
|
+
return new Promise((resolve2) => {
|
|
5302
|
+
const finish = () => {
|
|
5303
|
+
clearTimeout(timer);
|
|
5304
|
+
signal2.removeEventListener("abort", finish);
|
|
5305
|
+
resolve2();
|
|
5306
|
+
};
|
|
5307
|
+
const timer = setTimeout(finish, delay2);
|
|
5308
|
+
signal2.addEventListener("abort", finish, { once: true });
|
|
5309
|
+
if (signal2.aborted) finish();
|
|
5310
|
+
});
|
|
5311
|
+
}
|
|
5312
|
+
async function setup(ctx) {
|
|
5313
|
+
const client = createV2Client(ctx);
|
|
5314
|
+
const reporter = createOpenCodeReporter(client, ctx.options?.logLevel ?? process.env.BACKEER_LOG_LEVEL);
|
|
5315
|
+
const feedback = Object.fromEntries(
|
|
5316
|
+
["info", "success", "applied", "warning", "error"].map((kind) => [
|
|
5317
|
+
kind,
|
|
5318
|
+
() => {
|
|
5319
|
+
}
|
|
5320
|
+
])
|
|
5321
|
+
);
|
|
5322
|
+
feedback.handle = () => {
|
|
5323
|
+
};
|
|
5324
|
+
feedback.dispose = () => {
|
|
5325
|
+
};
|
|
5326
|
+
const hooks = await BackeerPlugin({
|
|
5327
|
+
client,
|
|
5328
|
+
directory: ctx.location.directory,
|
|
5329
|
+
feedback,
|
|
5330
|
+
v2: true
|
|
5331
|
+
}, { ...ctx.options, todos: false });
|
|
5332
|
+
if (!hooks.event) return;
|
|
5333
|
+
const controller = new AbortController();
|
|
5334
|
+
let streamTask;
|
|
5335
|
+
let cleanupTask;
|
|
5336
|
+
const registrations = [];
|
|
5337
|
+
function cleanup() {
|
|
5338
|
+
cleanupTask ??= (async () => {
|
|
5339
|
+
controller.abort();
|
|
5340
|
+
await streamTask?.catch(() => {
|
|
5341
|
+
});
|
|
5342
|
+
await hooks.dispose();
|
|
5343
|
+
await Promise.all(registrations.map((registration) => registration.dispose()));
|
|
5344
|
+
})();
|
|
5345
|
+
return cleanupTask;
|
|
5346
|
+
}
|
|
5347
|
+
try {
|
|
5348
|
+
await ctx.command.transform((editor) => {
|
|
5349
|
+
editor.add({
|
|
5350
|
+
name: "backeer",
|
|
5351
|
+
description: "Check, test, update, or manage Backeer",
|
|
5352
|
+
async execute({ sessionID, prompt, delivery }) {
|
|
5353
|
+
const output = { parts: [] };
|
|
5354
|
+
await hooks["command.execute.before"]({
|
|
5355
|
+
command: "backeer",
|
|
5356
|
+
sessionID,
|
|
5357
|
+
arguments: prompt.text
|
|
5358
|
+
}, output);
|
|
5359
|
+
if (output.parts.length) {
|
|
5360
|
+
await ctx.session.prompt({
|
|
5361
|
+
sessionID,
|
|
5362
|
+
text: output.parts.map((part) => part.text).join("\n"),
|
|
5363
|
+
delivery
|
|
5364
|
+
});
|
|
5365
|
+
}
|
|
5366
|
+
}
|
|
5367
|
+
});
|
|
5368
|
+
}).then((registration) => registrations.push(registration));
|
|
5369
|
+
registrations.push(await ctx.session.hook("prompt", async (event) => {
|
|
5370
|
+
const output = { message: { id: event.messageID }, parts: [] };
|
|
5371
|
+
await hooks["chat.message"]({ sessionID: event.sessionID }, output);
|
|
5372
|
+
if (output.parts.length) {
|
|
5373
|
+
event.prompt.text += `
|
|
5374
|
+
|
|
5375
|
+
${output.parts.map((part) => part.text).join("\n")}`;
|
|
5376
|
+
}
|
|
5377
|
+
}));
|
|
5378
|
+
streamTask = (async () => {
|
|
5379
|
+
while (!controller.signal.aborted) {
|
|
5380
|
+
try {
|
|
5381
|
+
for await (const event of ctx.event.subscribe({ signal: controller.signal })) {
|
|
5382
|
+
if (controller.signal.aborted) break;
|
|
5383
|
+
if (!await client.ownsEvent(event)) continue;
|
|
5384
|
+
for (const normalized of normalizeV2Event(event)) {
|
|
5385
|
+
await hooks.event({ event: normalized });
|
|
5386
|
+
}
|
|
5387
|
+
}
|
|
5388
|
+
} catch (error) {
|
|
5389
|
+
if (!controller.signal.aborted) reporter.error("OpenCode event stream disconnected", error);
|
|
5390
|
+
}
|
|
5391
|
+
if (!controller.signal.aborted) {
|
|
5392
|
+
await waitForReconnect(controller.signal, LIVE_RECONNECT_MS);
|
|
5393
|
+
}
|
|
5394
|
+
}
|
|
5395
|
+
})();
|
|
5396
|
+
return cleanup;
|
|
5397
|
+
} catch (error) {
|
|
5398
|
+
await cleanup();
|
|
5399
|
+
throw error;
|
|
5400
|
+
}
|
|
5401
|
+
}
|
|
5402
|
+
|
|
5403
|
+
// src/index.js
|
|
5404
|
+
var index_default = { id: "backeer-opencode", setup, server: BackeerPlugin };
|
|
2242
5405
|
export {
|
|
2243
|
-
|
|
5406
|
+
index_default as default
|
|
2244
5407
|
};
|