@opencode/server 0.0.0-dev-19795 → 0.0.0-dev-19812
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +10 -9
- package/dist/auth.js +12 -17
- package/dist/chunks/process-172x6jgf.js +139 -0
- package/dist/chunks/process-18k6g42r.js +36 -0
- package/dist/chunks/process-1crq7hen.js +13 -0
- package/dist/chunks/process-27edjygf.js +33 -0
- package/dist/chunks/process-3esm6t0a.js +156 -0
- package/dist/chunks/process-3ra48t04.js +26 -0
- package/dist/chunks/process-8j6eh3dh.js +55 -0
- package/dist/chunks/process-910kejdj.js +37 -0
- package/dist/chunks/process-9rqn6x4v.js +16 -0
- package/dist/chunks/process-b0dj656z.js +13 -0
- package/dist/chunks/process-b4s3wxap.js +23 -0
- package/dist/chunks/process-c23ng5tp.js +17 -0
- package/dist/chunks/process-d0efjmp3.js +83 -0
- package/dist/chunks/process-d5nhwenp.js +22 -0
- package/dist/chunks/process-dhcrxjg3.js +163 -0
- package/dist/chunks/process-fa3dg36p.js +15 -0
- package/dist/chunks/process-gw2hwgqh.js +20 -0
- package/dist/chunks/process-h965rd83.js +25 -0
- package/dist/chunks/process-hezj1jdf.js +7 -0
- package/dist/chunks/process-j26nh0zz.js +40 -0
- package/dist/chunks/process-ja6yvede.js +22 -0
- package/dist/chunks/process-k319q0y1.js +39 -0
- package/dist/chunks/process-k8tgqrb7.js +61 -0
- package/dist/chunks/process-kadtbwy3.js +77 -0
- package/dist/chunks/process-kb9735wh.js +26 -0
- package/dist/chunks/process-kgbwhj3q.js +149 -0
- package/dist/chunks/process-kheky2r0.js +35 -0
- package/dist/chunks/process-knez9aqv.js +13 -0
- package/dist/chunks/process-ks9pc2xc.js +19 -0
- package/dist/chunks/process-m5dqr0xs.js +21 -0
- package/dist/chunks/process-m6wvgbfq.js +60 -0
- package/dist/chunks/process-m8y6333k.js +346 -0
- package/dist/chunks/process-mx2h5aqn.js +59 -0
- package/dist/chunks/process-prrj1pgd.js +42 -0
- package/dist/chunks/process-q4bn6dy8.js +39 -0
- package/dist/chunks/process-qc2xtz00.js +34 -0
- package/dist/chunks/process-qswqf30g.js +25 -0
- package/dist/chunks/process-rkdaz036.js +32 -0
- package/dist/chunks/process-smaf4a18.js +28 -0
- package/dist/chunks/process-t7k3q1ah.js +23 -0
- package/dist/chunks/process-t8yzmczr.js +18 -0
- package/dist/chunks/process-tp6dn9dc.js +99 -0
- package/dist/chunks/process-w0mvbrhx.js +22 -0
- package/dist/chunks/process-wt4btb09.js +13 -0
- package/dist/chunks/process-xettb16v.js +22 -0
- package/dist/chunks/process-xn1y01ws.js +29 -0
- package/dist/chunks/process-xsrtpxyd.js +23 -0
- package/dist/chunks/process-yc7nft6q.js +5 -0
- package/dist/chunks/process-zyv89x5n.js +30 -0
- package/dist/cors.js +10 -36
- package/dist/event-feed.js +20 -60
- package/dist/fetch.js +53 -11
- package/dist/handlers/agent.js +11 -17
- package/dist/handlers/command.js +11 -5
- package/dist/handlers/config.js +11 -16
- package/dist/handlers/credential.js +11 -14
- package/dist/handlers/debug.js +11 -11
- package/dist/handlers/event.js +12 -27
- package/dist/handlers/form.js +11 -9
- package/dist/handlers/fs.js +11 -22
- package/dist/handlers/generate.js +11 -15
- package/dist/handlers/integration.js +10 -142
- package/dist/handlers/location.js +11 -16
- package/dist/handlers/mcp.js +11 -31
- package/dist/handlers/message.js +10 -42
- package/dist/handlers/migration.js +11 -7
- package/dist/handlers/model.js +11 -14
- package/dist/handlers/permission.js +11 -57
- package/dist/handlers/persistent-pty.js +12 -135
- package/dist/handlers/plugin.js +11 -47
- package/dist/handlers/project.js +11 -9
- package/dist/handlers/provider.js +11 -20
- package/dist/handlers/pty-socket.js +6 -4
- package/dist/handlers/pty.js +13 -107
- package/dist/handlers/reference.js +11 -5
- package/dist/handlers/rpc.js +11 -15
- package/dist/handlers/server.js +12 -13
- package/dist/handlers/session-error.js +12 -26
- package/dist/handlers/session.js +10 -311
- package/dist/handlers/shell.js +11 -25
- package/dist/handlers/skill.js +11 -5
- package/dist/handlers/vcs.js +11 -19
- package/dist/handlers/websearch.js +11 -31
- package/dist/handlers/worktree.js +11 -37
- package/dist/handlers.js +46 -33
- package/dist/location.js +15 -49
- package/dist/middleware/authorization.js +11 -49
- package/dist/middleware/form-location.js +10 -25
- package/dist/middleware/schema-error.js +8 -15
- package/dist/middleware/session-location.js +10 -19
- package/dist/options.js +5 -1
- package/dist/process.js +108 -28
- package/dist/pty-environment.js +12 -9
- package/dist/request-tracing.js +6 -2
- package/dist/routes.js +52 -118
- package/dist/server-info.js +12 -22
- package/dist/service-status.js +8 -11
- package/dist/workerd.js +80 -12
- package/package.json +8 -8
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__export
|
|
3
|
+
} from "./process-9rqn6x4v.js";
|
|
4
|
+
|
|
5
|
+
// src/event-feed.ts
|
|
6
|
+
var exports_event_feed = {};
|
|
7
|
+
__export(exports_event_feed, {
|
|
8
|
+
EncodingError: () => EncodingError2,
|
|
9
|
+
EventFeed: () => exports_event_feed,
|
|
10
|
+
Service: () => Service3,
|
|
11
|
+
SubscriberCapacity: () => SubscriberCapacity2,
|
|
12
|
+
SubscriberOverflowError: () => SubscriberOverflowError2,
|
|
13
|
+
frame: () => frame2,
|
|
14
|
+
layer: () => layer4,
|
|
15
|
+
make: () => make4
|
|
16
|
+
});
|
|
17
|
+
import { Bus } from "@opencode/core/bus";
|
|
18
|
+
import { Event } from "@opencode/schema/event";
|
|
19
|
+
import { isOpenCodeEvent } from "@opencode/protocol/groups/event";
|
|
20
|
+
import { Cause, Context, Effect, Layer, Queue, Schema, Stream } from "effect";
|
|
21
|
+
var SubscriberCapacity2 = 4096;
|
|
22
|
+
|
|
23
|
+
class SubscriberOverflowError2 extends Schema.TaggedError()("EventFeed.SubscriberOverflow", { capacity: Schema.Int }) {
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
class EncodingError2 extends Schema.TaggedError()("EventFeed.EncodingError", {
|
|
27
|
+
eventID: Event.ID,
|
|
28
|
+
eventType: Schema.String,
|
|
29
|
+
cause: Schema.Defect()
|
|
30
|
+
}) {
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class Service3 extends Context.Service()("@opencode/server/EventFeed") {
|
|
34
|
+
}
|
|
35
|
+
function frame2(event) {
|
|
36
|
+
return `data: ${JSON.stringify(event)}
|
|
37
|
+
|
|
38
|
+
`;
|
|
39
|
+
}
|
|
40
|
+
var make4 = Effect.fn("EventFeed.make")(function* (observe, options) {
|
|
41
|
+
const capacity = options?.capacity ?? SubscriberCapacity2;
|
|
42
|
+
const render = options?.encode ?? frame2;
|
|
43
|
+
const subscribers = new Set;
|
|
44
|
+
const fail = (error) => Effect.sync(() => {
|
|
45
|
+
const current = Array.from(subscribers);
|
|
46
|
+
subscribers.clear();
|
|
47
|
+
for (const subscriber of current)
|
|
48
|
+
Queue.failCauseUnsafe(subscriber, Cause.fail(error));
|
|
49
|
+
});
|
|
50
|
+
const publish = Effect.fnUntraced(function* (event) {
|
|
51
|
+
if (!isOpenCodeEvent(event))
|
|
52
|
+
return;
|
|
53
|
+
if (subscribers.size === 0)
|
|
54
|
+
return;
|
|
55
|
+
const encoded = yield* Effect.try({
|
|
56
|
+
try: () => render(event),
|
|
57
|
+
catch: (cause) => new EncodingError2({ eventID: event.id, eventType: event.type, cause })
|
|
58
|
+
}).pipe(Effect.catch((error) => Effect.logError("Failed to encode public event", {
|
|
59
|
+
eventID: error.eventID,
|
|
60
|
+
eventType: error.eventType,
|
|
61
|
+
cause: error.cause
|
|
62
|
+
}).pipe(Effect.andThen(fail(error)), Effect.as(undefined))));
|
|
63
|
+
if (encoded === undefined)
|
|
64
|
+
return;
|
|
65
|
+
for (const subscriber of subscribers) {
|
|
66
|
+
if (Queue.offerUnsafe(subscriber, encoded))
|
|
67
|
+
continue;
|
|
68
|
+
subscribers.delete(subscriber);
|
|
69
|
+
Queue.failCauseUnsafe(subscriber, Cause.fail(new SubscriberOverflowError2({ capacity })));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
const unsubscribe = yield* observe(publish);
|
|
73
|
+
yield* Effect.addFinalizer(() => unsubscribe);
|
|
74
|
+
return Service3.of({
|
|
75
|
+
subscribe: Effect.acquireRelease(Queue.dropping(capacity).pipe(Effect.tap((queue) => Effect.sync(() => subscribers.add(queue)))), (queue) => Effect.sync(() => subscribers.delete(queue)).pipe(Effect.andThen(Queue.shutdown(queue)), Effect.asVoid)).pipe(Effect.map(Stream.fromQueue))
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
var layer4 = Layer.effect(Service3, Effect.gen(function* () {
|
|
79
|
+
const bus = yield* Bus.Service;
|
|
80
|
+
return yield* make4(bus.listen);
|
|
81
|
+
}));
|
|
82
|
+
|
|
83
|
+
export { SubscriberCapacity2, SubscriberOverflowError2, EncodingError2, Service3, frame2, make4, layer4, exports_event_feed };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
response2
|
|
3
|
+
} from "./process-8j6eh3dh.js";
|
|
4
|
+
import {
|
|
5
|
+
Api2
|
|
6
|
+
} from "./process-ks9pc2xc.js";
|
|
7
|
+
|
|
8
|
+
// src/handlers/model.ts
|
|
9
|
+
import { Model } from "@opencode/core/model";
|
|
10
|
+
import { Effect } from "effect";
|
|
11
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
12
|
+
var ModelHandler2 = HttpApiBuilder.group(Api2, "server.model", (handlers) => Effect.gen(function* () {
|
|
13
|
+
return handlers.handle("model.list", Effect.fn(function* () {
|
|
14
|
+
const models = yield* Model.Service;
|
|
15
|
+
return yield* response2(models.available());
|
|
16
|
+
})).handle("model.default", Effect.fn(function* () {
|
|
17
|
+
const models = yield* Model.Service;
|
|
18
|
+
return yield* response2(models.default());
|
|
19
|
+
}));
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
export { ModelHandler2 };
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Api2
|
|
3
|
+
} from "./process-ks9pc2xc.js";
|
|
4
|
+
import {
|
|
5
|
+
CorsConfig2,
|
|
6
|
+
isAllowedRequestOrigin2
|
|
7
|
+
} from "./process-q4bn6dy8.js";
|
|
8
|
+
import {
|
|
9
|
+
runPtySocket2
|
|
10
|
+
} from "./process-hezj1jdf.js";
|
|
11
|
+
|
|
12
|
+
// src/handlers/persistent-pty.ts
|
|
13
|
+
import { PersistentPty } from "@opencode/core/persistent-pty";
|
|
14
|
+
import { PtyTicket } from "@opencode/core/pty/ticket";
|
|
15
|
+
import { ForbiddenError, PtyNotFoundError, ServiceUnavailableError } from "@opencode/protocol/errors";
|
|
16
|
+
import {
|
|
17
|
+
PTY_CONNECT_TICKET_QUERY,
|
|
18
|
+
PTY_CONNECT_TOKEN_HEADER,
|
|
19
|
+
PTY_CONNECT_TOKEN_HEADER_VALUE
|
|
20
|
+
} from "@opencode/protocol/groups/persistent-pty";
|
|
21
|
+
import { Effect, Queue, Semaphore } from "effect";
|
|
22
|
+
import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
|
|
23
|
+
import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
|
|
24
|
+
import { Socket } from "effect/unstable/socket";
|
|
25
|
+
var PersistentPtyHandler2 = HttpApiBuilder.group(Api2, "server.experimental", (handlers) => Effect.gen(function* () {
|
|
26
|
+
const tickets = yield* PtyTicket.Service;
|
|
27
|
+
const cors = yield* CorsConfig2;
|
|
28
|
+
const pty = yield* PersistentPty.Service;
|
|
29
|
+
return handlers.handle("persistentPty.read", Effect.fn(function* (ctx) {
|
|
30
|
+
return { data: yield* pty.read(ctx.params.sessionID, ctx.query.lines).pipe(mapUnavailable) };
|
|
31
|
+
})).handle("persistentPty.list", Effect.fn(function* (ctx) {
|
|
32
|
+
return { data: yield* pty.list(ctx.params.sessionID).pipe(mapUnavailable) };
|
|
33
|
+
})).handle("persistentPty.create", Effect.fn(function* (ctx) {
|
|
34
|
+
return {
|
|
35
|
+
data: yield* pty.create(ctx.params.sessionID, {
|
|
36
|
+
command: ctx.payload.command,
|
|
37
|
+
args: ctx.payload.args,
|
|
38
|
+
cwd: ctx.payload.cwd,
|
|
39
|
+
title: ctx.payload.title,
|
|
40
|
+
env: ctx.payload.env,
|
|
41
|
+
cols: ctx.payload.size?.cols,
|
|
42
|
+
rows: ctx.payload.size?.rows
|
|
43
|
+
}).pipe(Effect.catchTag("PersistentPty.UnavailableError", unavailable))
|
|
44
|
+
};
|
|
45
|
+
})).handle("persistentPty.shutdown", Effect.fn(function* () {
|
|
46
|
+
yield* pty.shutdown().pipe(mapUnavailable);
|
|
47
|
+
return HttpApiSchema.NoContent.make();
|
|
48
|
+
})).handle("persistentPty.handoff", Effect.fn(function* () {
|
|
49
|
+
return { handoff: yield* pty.handoff().pipe(mapUnavailable) };
|
|
50
|
+
})).handle("persistentPty.get", Effect.fn(function* (ctx) {
|
|
51
|
+
return { data: yield* pty.get(ctx.params.ptyID).pipe(mapTerminalError) };
|
|
52
|
+
})).handle("persistentPty.update", Effect.fn(function* (ctx) {
|
|
53
|
+
yield* pty.resize(ctx.params.ptyID, ctx.payload.size.cols, ctx.payload.size.rows, ctx.payload.attachmentID).pipe(mapTerminalError);
|
|
54
|
+
return { data: yield* pty.get(ctx.params.ptyID).pipe(mapTerminalError) };
|
|
55
|
+
})).handle("persistentPty.snapshot", Effect.fn(function* (ctx) {
|
|
56
|
+
return { data: yield* pty.snapshot(ctx.params.ptyID).pipe(mapTerminalError) };
|
|
57
|
+
})).handle("persistentPty.remove", Effect.fn(function* (ctx) {
|
|
58
|
+
yield* pty.remove(ctx.params.ptyID).pipe(mapTerminalError);
|
|
59
|
+
return HttpApiSchema.NoContent.make();
|
|
60
|
+
})).handle("persistentPty.connectToken", Effect.fn(function* (ctx) {
|
|
61
|
+
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
62
|
+
if (request.headers[PTY_CONNECT_TOKEN_HEADER] !== PTY_CONNECT_TOKEN_HEADER_VALUE || !isAllowedRequestOrigin2(request.headers.origin, request.headers.host, cors))
|
|
63
|
+
return yield* new ForbiddenError({ message: "Invalid persistent PTY connect token request" });
|
|
64
|
+
yield* pty.get(ctx.params.ptyID).pipe(mapTerminalError);
|
|
65
|
+
return { data: yield* tickets.issue({ ptyID: ctx.params.ptyID }) };
|
|
66
|
+
})).handleRaw("persistentPty.connect", Effect.fn("PersistentPtyHandler.connect")(function* (ctx) {
|
|
67
|
+
const url = new URL(ctx.request.url, "http://localhost");
|
|
68
|
+
const ticket = url.searchParams.get(PTY_CONNECT_TICKET_QUERY);
|
|
69
|
+
if (ticket) {
|
|
70
|
+
const valid = isAllowedRequestOrigin2(ctx.request.headers.origin, ctx.request.headers.host, cors) ? yield* tickets.consume({ ticket, ptyID: ctx.params.ptyID }) : false;
|
|
71
|
+
if (!valid)
|
|
72
|
+
return HttpServerResponse.empty({ status: 403 });
|
|
73
|
+
}
|
|
74
|
+
const cursor = Number(url.searchParams.get("cursor") ?? "0");
|
|
75
|
+
const role = url.searchParams.get("role") === "observer" ? "observer" : "controller";
|
|
76
|
+
const framedInput = url.searchParams.get("input_protocol") === "1";
|
|
77
|
+
const attachmentID = url.searchParams.get("attachment_id") ?? crypto.randomUUID();
|
|
78
|
+
if (!Number.isSafeInteger(cursor) || cursor < 0)
|
|
79
|
+
return HttpServerResponse.empty({ status: 400 });
|
|
80
|
+
const socket = yield* Effect.orDie(ctx.request.upgrade);
|
|
81
|
+
const write = yield* socket.writer;
|
|
82
|
+
const outbox = yield* Queue.unbounded();
|
|
83
|
+
const input = yield* Semaphore.make(1);
|
|
84
|
+
let attachment;
|
|
85
|
+
const onOpen = Effect.gen(function* () {
|
|
86
|
+
attachment = yield* pty.attach(ctx.params.ptyID, {
|
|
87
|
+
cursor,
|
|
88
|
+
attachmentID,
|
|
89
|
+
role,
|
|
90
|
+
takeover: url.searchParams.get("takeover") === "true",
|
|
91
|
+
onEvent: (event) => {
|
|
92
|
+
if (event.type === "output")
|
|
93
|
+
Queue.offerUnsafe(outbox, event.data);
|
|
94
|
+
if (event.type === "resized")
|
|
95
|
+
Queue.offerUnsafe(outbox, JSON.stringify({ ...event, checkpoint: Buffer.from(event.checkpoint).toString("base64") }));
|
|
96
|
+
if (event.type !== "output" && event.type !== "resized")
|
|
97
|
+
Queue.offerUnsafe(outbox, JSON.stringify(event));
|
|
98
|
+
},
|
|
99
|
+
onEnd: () => Queue.offerUnsafe(outbox, new Socket.CloseEvent(1000))
|
|
100
|
+
}).pipe(Effect.catchTags({
|
|
101
|
+
"PersistentPty.NotFoundError": () => Effect.succeed(undefined),
|
|
102
|
+
"PersistentPty.UnavailableError": () => Effect.succeed(undefined)
|
|
103
|
+
}));
|
|
104
|
+
if (!attachment) {
|
|
105
|
+
Queue.offerUnsafe(outbox, new Socket.CloseEvent(4404, "terminal unavailable"));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
Queue.offerUnsafe(outbox, JSON.stringify({
|
|
109
|
+
type: "attached",
|
|
110
|
+
attachmentID,
|
|
111
|
+
inputProtocol: framedInput ? 1 : 0,
|
|
112
|
+
info: attachment.info,
|
|
113
|
+
role: attachment.role,
|
|
114
|
+
generation: attachment.generation,
|
|
115
|
+
replay: {
|
|
116
|
+
requestedOffset: attachment.replay.requestedOffset,
|
|
117
|
+
availableOffset: attachment.replay.availableOffset,
|
|
118
|
+
endOffset: attachment.replay.endOffset,
|
|
119
|
+
truncated: attachment.replay.truncated
|
|
120
|
+
}
|
|
121
|
+
}));
|
|
122
|
+
if (attachment.replay.data.length > 0)
|
|
123
|
+
Queue.offerUnsafe(outbox, attachment.replay.data);
|
|
124
|
+
Queue.offerUnsafe(outbox, JSON.stringify({ type: "replay_complete", endOffset: attachment.replay.endOffset }));
|
|
125
|
+
attachment.activate();
|
|
126
|
+
});
|
|
127
|
+
const drain = Effect.gen(function* () {
|
|
128
|
+
while (true) {
|
|
129
|
+
const item = yield* Queue.take(outbox);
|
|
130
|
+
yield* write(item);
|
|
131
|
+
if (item instanceof Socket.CloseEvent)
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
yield* runPtySocket2(drain, socket.runRaw((message) => input.withPermit(Effect.suspend(() => {
|
|
136
|
+
if (!attachment)
|
|
137
|
+
return Effect.void;
|
|
138
|
+
const data = typeof message === "string" ? Buffer.from(message) : message;
|
|
139
|
+
if (!framedInput)
|
|
140
|
+
return pty.input(ctx.params.ptyID, attachmentID, attachment.info.size.cols, attachment.info.size.rows, data).pipe(Effect.ignore);
|
|
141
|
+
if (data.byteLength < 5)
|
|
142
|
+
return Effect.void;
|
|
143
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
144
|
+
const type = data[0];
|
|
145
|
+
const cols = view.getUint16(1);
|
|
146
|
+
const rows = view.getUint16(3);
|
|
147
|
+
if (type !== 0 && type !== 1 || cols === 0 || rows === 0)
|
|
148
|
+
return Effect.void;
|
|
149
|
+
if (type === 0)
|
|
150
|
+
return pty.control(ctx.params.ptyID, attachmentID, cols, rows).pipe(Effect.ignore);
|
|
151
|
+
return pty.input(ctx.params.ptyID, attachmentID, cols, rows, data.subarray(5)).pipe(Effect.ignore);
|
|
152
|
+
})), { onOpen }), () => attachment?.detach()).pipe(Effect.catchReason("SocketError", "SocketCloseError", () => Effect.void), Effect.orDie);
|
|
153
|
+
return HttpServerResponse.empty();
|
|
154
|
+
}));
|
|
155
|
+
}));
|
|
156
|
+
var mapUnavailable = (effect) => effect.pipe(Effect.catchTag("PersistentPty.UnavailableError", unavailable));
|
|
157
|
+
var mapTerminalError = (effect) => effect.pipe(Effect.catchTags({
|
|
158
|
+
"PersistentPty.NotFoundError": (error) => new PtyNotFoundError({ ptyID: error.ptyID, message: `PTY session not found: ${error.ptyID}` }),
|
|
159
|
+
"PersistentPty.UnavailableError": unavailable
|
|
160
|
+
}));
|
|
161
|
+
var unavailable = (error) => new ServiceUnavailableError({ message: error.message, service: "opencode-pty" });
|
|
162
|
+
|
|
163
|
+
export { PersistentPtyHandler2 };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Api2
|
|
3
|
+
} from "./process-ks9pc2xc.js";
|
|
4
|
+
|
|
5
|
+
// src/handlers/project.ts
|
|
6
|
+
import { Project } from "@opencode/core/project";
|
|
7
|
+
import { Effect } from "effect";
|
|
8
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
9
|
+
import { ProjectNotFoundError } from "@opencode/protocol/errors";
|
|
10
|
+
var ProjectHandler2 = HttpApiBuilder.group(Api2, "server.project", (handlers) => handlers.handle("project.list", () => Project.Service.use((project) => project.list())).handle("project.update", (ctx) => Project.Service.use((project) => project.update({ ...ctx.payload, projectID: ctx.params.projectID }).pipe(Effect.mapError(() => new ProjectNotFoundError({
|
|
11
|
+
projectID: ctx.params.projectID,
|
|
12
|
+
message: `Project not found: ${ctx.params.projectID}`
|
|
13
|
+
}))))));
|
|
14
|
+
|
|
15
|
+
export { ProjectHandler2 };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
requestRef2
|
|
3
|
+
} from "./process-8j6eh3dh.js";
|
|
4
|
+
import {
|
|
5
|
+
Api2
|
|
6
|
+
} from "./process-ks9pc2xc.js";
|
|
7
|
+
|
|
8
|
+
// src/handlers/debug.ts
|
|
9
|
+
import { LocationServiceMap } from "@opencode/core/location-service-map";
|
|
10
|
+
import { Effect, Option, RcMap } from "effect";
|
|
11
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
12
|
+
var DebugHandler2 = HttpApiBuilder.group(Api2, "server.debug", (handlers) => handlers.handle("debug.location", Effect.fn(function* () {
|
|
13
|
+
const locations = Option.getOrThrow(yield* Effect.serviceOption(LocationServiceMap.Service));
|
|
14
|
+
return Array.from(yield* RcMap.keys(locations.rcMap));
|
|
15
|
+
})).handle("debug.location.evict", Effect.fn(function* (ctx) {
|
|
16
|
+
const locations = Option.getOrThrow(yield* Effect.serviceOption(LocationServiceMap.Service));
|
|
17
|
+
yield* locations.invalidate(requestRef2(ctx.request));
|
|
18
|
+
})));
|
|
19
|
+
|
|
20
|
+
export { DebugHandler2 };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Api2
|
|
3
|
+
} from "./process-ks9pc2xc.js";
|
|
4
|
+
|
|
5
|
+
// src/handlers/generate.ts
|
|
6
|
+
import { Generate } from "@opencode/core/generate";
|
|
7
|
+
import { Location } from "@opencode/core/location";
|
|
8
|
+
import { LocationServiceMap } from "@opencode/core/location-services";
|
|
9
|
+
import { AbsolutePath } from "@opencode/core/schema";
|
|
10
|
+
import { InvalidRequestError, ServiceUnavailableError } from "@opencode/protocol/errors";
|
|
11
|
+
import { Global } from "@opencode/util/global";
|
|
12
|
+
import { Effect } from "effect";
|
|
13
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
14
|
+
var GenerateHandler2 = HttpApiBuilder.group(Api2, "server.generate", (handlers) => Effect.gen(function* () {
|
|
15
|
+
const global = yield* Global.Service;
|
|
16
|
+
const locations = yield* LocationServiceMap.Service;
|
|
17
|
+
const services = locations.get(Location.Ref.make({ directory: AbsolutePath.make(global.config) }));
|
|
18
|
+
return handlers.handle("generate.text", Effect.fn("server.generate.text")(function* (request) {
|
|
19
|
+
const generate = yield* Generate.Service;
|
|
20
|
+
const text = yield* generate.text(request.payload).pipe(Effect.mapError((error) => error._tag === "Generate.ModelSelectionError" ? new InvalidRequestError({ message: error.message }) : new ServiceUnavailableError({ message: error.message, service: error.service })));
|
|
21
|
+
return { data: { text } };
|
|
22
|
+
}, Effect.provide(services)));
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
export { GenerateHandler2 };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
response2
|
|
3
|
+
} from "./process-8j6eh3dh.js";
|
|
4
|
+
import {
|
|
5
|
+
Api2
|
|
6
|
+
} from "./process-ks9pc2xc.js";
|
|
7
|
+
|
|
8
|
+
// src/handlers/mcp.ts
|
|
9
|
+
import { Mcp } from "@opencode/core/mcp/index";
|
|
10
|
+
import { McpServerNotFoundError } from "@opencode/protocol/errors";
|
|
11
|
+
import { Effect } from "effect";
|
|
12
|
+
import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
|
|
13
|
+
var notFound = (effect) => effect.pipe(Effect.mapError((error) => new McpServerNotFoundError({ server: error.server, message: error.message })));
|
|
14
|
+
var McpHandler2 = HttpApiBuilder.group(Api2, "server.mcp", (handlers) => Effect.gen(function* () {
|
|
15
|
+
return handlers.handle("mcp.list", Effect.fn(function* () {
|
|
16
|
+
const service = yield* Mcp.Service;
|
|
17
|
+
return yield* response2(service.servers().pipe(Effect.map((servers) => servers.map((info) => ({ name: info.name, status: info.status, integrationID: info.integrationID })))));
|
|
18
|
+
})).handle("mcp.add", Effect.fn(function* (ctx) {
|
|
19
|
+
const service = yield* Mcp.Service;
|
|
20
|
+
yield* service.add(ctx.params.server, ctx.payload.config);
|
|
21
|
+
return HttpApiSchema.NoContent.make();
|
|
22
|
+
})).handle("mcp.remove", Effect.fn(function* (ctx) {
|
|
23
|
+
const service = yield* Mcp.Service;
|
|
24
|
+
yield* notFound(service.remove(ctx.params.server));
|
|
25
|
+
return HttpApiSchema.NoContent.make();
|
|
26
|
+
})).handle("mcp.connect", Effect.fn(function* (ctx) {
|
|
27
|
+
const service = yield* Mcp.Service;
|
|
28
|
+
yield* notFound(service.connect(ctx.params.server));
|
|
29
|
+
return HttpApiSchema.NoContent.make();
|
|
30
|
+
})).handle("mcp.disconnect", Effect.fn(function* (ctx) {
|
|
31
|
+
const service = yield* Mcp.Service;
|
|
32
|
+
yield* notFound(service.disconnect(ctx.params.server));
|
|
33
|
+
return HttpApiSchema.NoContent.make();
|
|
34
|
+
})).handle("mcp.resource.catalog", Effect.fn(function* () {
|
|
35
|
+
const service = yield* Mcp.Service;
|
|
36
|
+
return yield* response2(service.resourceCatalog());
|
|
37
|
+
}));
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
export { McpHandler2 };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Api2
|
|
3
|
+
} from "./process-ks9pc2xc.js";
|
|
4
|
+
|
|
5
|
+
// src/handlers/location.ts
|
|
6
|
+
import { Location } from "@opencode/core/location";
|
|
7
|
+
import { LocationServiceMap } from "@opencode/core/location-service-map";
|
|
8
|
+
import { ServiceUnavailableError } from "@opencode/protocol/errors";
|
|
9
|
+
import { Cause, Effect } from "effect";
|
|
10
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
11
|
+
var LocationHandler2 = HttpApiBuilder.group(Api2, "server.location", (handlers) => Effect.gen(function* () {
|
|
12
|
+
const locations = yield* LocationServiceMap.Service;
|
|
13
|
+
return handlers.handle("location.get", Effect.fn(function* () {
|
|
14
|
+
const location = yield* Location.Service;
|
|
15
|
+
return new Location.Info({
|
|
16
|
+
directory: location.directory,
|
|
17
|
+
project: location.project
|
|
18
|
+
});
|
|
19
|
+
})).handle("location.reload", () => LocationServiceMap.reload().pipe(Effect.provideService(LocationServiceMap.Service, locations), Effect.catchCause((cause) => Cause.hasInterruptsOnly(cause) ? Effect.failCause(cause) : Effect.fail(new ServiceUnavailableError({ message: Cause.pretty(cause), service: "location" })))));
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
export { LocationHandler2 };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {
|
|
2
|
+
response2
|
|
3
|
+
} from "./process-8j6eh3dh.js";
|
|
4
|
+
import {
|
|
5
|
+
Api2
|
|
6
|
+
} from "./process-ks9pc2xc.js";
|
|
7
|
+
|
|
8
|
+
// src/handlers/websearch.ts
|
|
9
|
+
import { WebSearch } from "@opencode/core/websearch";
|
|
10
|
+
import { InvalidRequestError, ServiceUnavailableError } from "@opencode/protocol/errors";
|
|
11
|
+
import { Effect } from "effect";
|
|
12
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
13
|
+
var WebSearchHandler2 = HttpApiBuilder.group(Api2, "server.websearch", (handlers) => Effect.gen(function* () {
|
|
14
|
+
return handlers.handle("websearch.providers", Effect.fn("server.websearch.providers")(function* () {
|
|
15
|
+
const websearch = yield* WebSearch.Service;
|
|
16
|
+
return yield* response2(websearch.providers());
|
|
17
|
+
})).handle("websearch.query", Effect.fn("server.websearch.query")(function* (request) {
|
|
18
|
+
const websearch = yield* WebSearch.Service;
|
|
19
|
+
return yield* response2(websearch.query(request.payload).pipe(Effect.catchTags({
|
|
20
|
+
"WebSearch.ProviderRequired": () => new InvalidRequestError({
|
|
21
|
+
message: "Web search provider is required",
|
|
22
|
+
kind: "websearch_provider_required",
|
|
23
|
+
field: "providerID"
|
|
24
|
+
}),
|
|
25
|
+
"WebSearch.ProviderNotFound": (error) => new InvalidRequestError({
|
|
26
|
+
message: `Web search provider not found: ${error.providerID}`,
|
|
27
|
+
kind: "websearch_provider_not_found",
|
|
28
|
+
field: "providerID"
|
|
29
|
+
}),
|
|
30
|
+
"WebSearch.Disabled": () => new InvalidRequestError({ message: "Web search is disabled", kind: "websearch_disabled" }),
|
|
31
|
+
"WebSearch.Request": (error) => new ServiceUnavailableError({
|
|
32
|
+
message: `Web search request failed: ${error.providerID}`,
|
|
33
|
+
service: error.providerID
|
|
34
|
+
})
|
|
35
|
+
})));
|
|
36
|
+
}));
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
export { WebSearchHandler2 };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {
|
|
2
|
+
response2
|
|
3
|
+
} from "./process-8j6eh3dh.js";
|
|
4
|
+
import {
|
|
5
|
+
Api2
|
|
6
|
+
} from "./process-ks9pc2xc.js";
|
|
7
|
+
|
|
8
|
+
// src/handlers/plugin.ts
|
|
9
|
+
import { Plugin } from "@opencode/core/plugin";
|
|
10
|
+
import { PluginUpdate } from "@opencode/core/plugin/update";
|
|
11
|
+
import { InvalidRequestError, ServiceUnavailableError } from "@opencode/protocol/errors";
|
|
12
|
+
import { Cause, Effect, Exit } from "effect";
|
|
13
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
14
|
+
var PluginHandler2 = HttpApiBuilder.group(Api2, "server.plugin", (handlers) => handlers.handle("plugin.list", () => Effect.gen(function* () {
|
|
15
|
+
return yield* response2(Plugin.Service.use((plugin) => plugin.list()));
|
|
16
|
+
})).handle("plugin.check", (ctx) => Effect.gen(function* () {
|
|
17
|
+
const plugins = yield* Plugin.Service;
|
|
18
|
+
const inventory = yield* plugins.list();
|
|
19
|
+
const targets = [
|
|
20
|
+
...new Set(inventory.flatMap((plugin) => plugin.source.type === "package" ? [plugin.source.target] : []))
|
|
21
|
+
].filter((target) => ctx.payload.target === undefined || target === ctx.payload.target);
|
|
22
|
+
if (ctx.payload.target !== undefined && !targets.length)
|
|
23
|
+
return yield* new InvalidRequestError({
|
|
24
|
+
message: `Plugin package is not in the current server inventory: ${ctx.payload.target}`,
|
|
25
|
+
field: "target"
|
|
26
|
+
});
|
|
27
|
+
const updates = yield* PluginUpdate.Service;
|
|
28
|
+
const outdated = new Map(yield* Effect.forEach(targets, (target) => updates.check(target, { refresh: true }).pipe(Effect.map((value) => [target, value])), { concurrency: "unbounded" }));
|
|
29
|
+
return yield* response2(Effect.succeed(inventory.map((plugin) => {
|
|
30
|
+
if (plugin.source.type !== "package" || !outdated.has(plugin.source.target))
|
|
31
|
+
return plugin;
|
|
32
|
+
return {
|
|
33
|
+
...plugin,
|
|
34
|
+
source: {
|
|
35
|
+
type: "package",
|
|
36
|
+
target: plugin.source.target,
|
|
37
|
+
...plugin.source.version ? { version: plugin.source.version } : {},
|
|
38
|
+
...outdated.get(plugin.source.target) ? { outdated: true } : {},
|
|
39
|
+
...plugin.source.updating ? { updating: true } : {}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
})));
|
|
43
|
+
})).handle("plugin.update", (ctx) => Effect.gen(function* () {
|
|
44
|
+
const plugins = yield* Plugin.Service;
|
|
45
|
+
const inventory = new Set((yield* plugins.list()).flatMap((plugin) => plugin.source.type === "package" ? [plugin.source.target] : []));
|
|
46
|
+
const unknown = ctx.payload.targets.filter((target) => !inventory.has(target));
|
|
47
|
+
if (unknown.length)
|
|
48
|
+
return yield* new InvalidRequestError({
|
|
49
|
+
message: `Plugin packages are not in the current server inventory: ${unknown.join(", ")}`,
|
|
50
|
+
field: "targets"
|
|
51
|
+
});
|
|
52
|
+
const updates = yield* PluginUpdate.Service;
|
|
53
|
+
const failures = yield* Effect.forEach(ctx.payload.targets, (target) => updates.update(target).pipe(Effect.exit, Effect.map((exit) => Exit.isFailure(exit) ? [`${target}: ${Cause.pretty(exit.cause)}`] : [])), { concurrency: "unbounded" }).pipe(Effect.map((results) => results.flat()));
|
|
54
|
+
if (failures.length)
|
|
55
|
+
return yield* new ServiceUnavailableError({
|
|
56
|
+
message: `Failed to update plugin packages: ${failures.join("; ")}`,
|
|
57
|
+
service: "plugin"
|
|
58
|
+
});
|
|
59
|
+
})));
|
|
60
|
+
|
|
61
|
+
export { PluginHandler2 };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
missingSession2
|
|
3
|
+
} from "./process-smaf4a18.js";
|
|
4
|
+
import {
|
|
5
|
+
response2,
|
|
6
|
+
sessionInfo2
|
|
7
|
+
} from "./process-8j6eh3dh.js";
|
|
8
|
+
import {
|
|
9
|
+
Api2
|
|
10
|
+
} from "./process-ks9pc2xc.js";
|
|
11
|
+
|
|
12
|
+
// src/handlers/permission.ts
|
|
13
|
+
import { Instance } from "@opencode/core/instance/service";
|
|
14
|
+
import { Location } from "@opencode/core/location";
|
|
15
|
+
import { Permission } from "@opencode/core/permission";
|
|
16
|
+
import { PermissionSaved } from "@opencode/core/permission/saved";
|
|
17
|
+
import { Session } from "@opencode/core/session";
|
|
18
|
+
import { Effect } from "effect";
|
|
19
|
+
import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
|
|
20
|
+
import { PermissionNotFoundError } from "@opencode/protocol/errors";
|
|
21
|
+
function missingRequest(id) {
|
|
22
|
+
return new PermissionNotFoundError({ requestID: id, message: `Permission request not found: ${id}` });
|
|
23
|
+
}
|
|
24
|
+
var PermissionHandler2 = HttpApiBuilder.group(Api2, "server.permission", (handlers) => Effect.gen(function* () {
|
|
25
|
+
const instances = yield* Instance.Service;
|
|
26
|
+
const sessions = yield* Session.Service;
|
|
27
|
+
const requireOwnedRequest = Effect.fnUntraced(function* (sessionID, requestID) {
|
|
28
|
+
const permission = yield* Permission.Service;
|
|
29
|
+
const request = yield* permission.get(requestID);
|
|
30
|
+
if (!request || request.sessionID !== sessionID)
|
|
31
|
+
return yield* missingRequest(requestID);
|
|
32
|
+
return { permission, request };
|
|
33
|
+
});
|
|
34
|
+
return handlers.handle("permission.request.list", Effect.fn(function* () {
|
|
35
|
+
const permission = yield* Permission.Service;
|
|
36
|
+
return yield* response2(permission.list());
|
|
37
|
+
})).handle("session.permission.create", Effect.fn(function* (ctx) {
|
|
38
|
+
const permission = yield* Permission.Service;
|
|
39
|
+
return {
|
|
40
|
+
data: yield* permission.ask({
|
|
41
|
+
id: ctx.payload.id,
|
|
42
|
+
sessionID: ctx.params.sessionID,
|
|
43
|
+
action: ctx.payload.action,
|
|
44
|
+
resources: ctx.payload.resources,
|
|
45
|
+
save: ctx.payload.save,
|
|
46
|
+
metadata: ctx.payload.metadata,
|
|
47
|
+
source: ctx.payload.source,
|
|
48
|
+
agent: ctx.payload.agent
|
|
49
|
+
}).pipe(Effect.catchTag("Session.NotFoundError", missingSession2))
|
|
50
|
+
};
|
|
51
|
+
})).handle("session.permission.list", Effect.fn(function* (ctx) {
|
|
52
|
+
const session = yield* sessionInfo2(sessions, ctx.params.sessionID);
|
|
53
|
+
const requests = yield* Permission.Service.use((permission) => permission.forSession(ctx.params.sessionID)).pipe(instances.provide(session));
|
|
54
|
+
return { data: requests };
|
|
55
|
+
})).handle("session.permission.get", Effect.fn(function* (ctx) {
|
|
56
|
+
const owned = yield* requireOwnedRequest(ctx.params.sessionID, ctx.params.requestID);
|
|
57
|
+
return { data: owned.request };
|
|
58
|
+
})).handle("session.permission.reply", Effect.fn(function* (ctx) {
|
|
59
|
+
const owned = yield* requireOwnedRequest(ctx.params.sessionID, ctx.params.requestID);
|
|
60
|
+
yield* owned.permission.reply({ requestID: ctx.params.requestID, reply: ctx.payload.decision, message: ctx.payload.message }).pipe(Effect.catchTag("Permission.NotFoundError", () => missingRequest(ctx.params.requestID)));
|
|
61
|
+
return HttpApiSchema.NoContent.make();
|
|
62
|
+
})).handle("permission.saved.list", Effect.fn(function* (ctx) {
|
|
63
|
+
const location = yield* Location.Service;
|
|
64
|
+
const saved = yield* PermissionSaved.Service;
|
|
65
|
+
return {
|
|
66
|
+
data: yield* saved.list({
|
|
67
|
+
projectID: ctx.query.projectID ?? location.project.id
|
|
68
|
+
})
|
|
69
|
+
};
|
|
70
|
+
})).handle("permission.saved.remove", Effect.fn(function* (ctx) {
|
|
71
|
+
const saved = yield* PermissionSaved.Service;
|
|
72
|
+
yield* saved.remove(ctx.params.id);
|
|
73
|
+
return HttpApiSchema.NoContent.make();
|
|
74
|
+
}));
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
export { PermissionHandler2 };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sessionInfo2
|
|
3
|
+
} from "./process-8j6eh3dh.js";
|
|
4
|
+
|
|
5
|
+
// src/middleware/session-location.ts
|
|
6
|
+
import { Instance } from "@opencode/core/instance/service";
|
|
7
|
+
import { Session } from "@opencode/core/session";
|
|
8
|
+
import { Effect, Layer } from "effect";
|
|
9
|
+
import { HttpRouter } from "effect/unstable/http";
|
|
10
|
+
import { HttpApiMiddleware } from "effect/unstable/httpapi";
|
|
11
|
+
import { InvalidRequestError, SessionNotFoundError } from "@opencode/protocol/errors";
|
|
12
|
+
class SessionLocationMiddleware2 extends HttpApiMiddleware.Service()("@opencode/HttpApiSessionLocation", {
|
|
13
|
+
error: [InvalidRequestError, SessionNotFoundError]
|
|
14
|
+
}) {
|
|
15
|
+
}
|
|
16
|
+
var sessionLocationLayer2 = Layer.effect(SessionLocationMiddleware2, Effect.gen(function* () {
|
|
17
|
+
const sessions = yield* Session.Service;
|
|
18
|
+
const instances = yield* Instance.Service;
|
|
19
|
+
return SessionLocationMiddleware2.of((effect) => Effect.gen(function* () {
|
|
20
|
+
const route = yield* HttpRouter.RouteContext;
|
|
21
|
+
const session = yield* sessionInfo2(sessions, route.params.sessionID);
|
|
22
|
+
return yield* effect.pipe(instances.provide(session));
|
|
23
|
+
}));
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
export { SessionLocationMiddleware2, sessionLocationLayer2 };
|