@opencode-ai/server 0.0.0-dev-18303 → 0.0.0-dev-18308
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/handlers/persistent-pty.js +46 -41
- package/package.json +6 -6
|
@@ -48,8 +48,6 @@ export const PersistentPtyHandler = HttpApiBuilder.group(Api, "server.experiment
|
|
|
48
48
|
yield* pty.get(ctx.params.ptyID).pipe(mapTerminalError);
|
|
49
49
|
return { data: yield* tickets.issue({ ptyID: ctx.params.ptyID }) };
|
|
50
50
|
})).handleRaw("persistentPty.connect", Effect.fn("PersistentPtyHandler.connect")(function* (ctx) {
|
|
51
|
-
if (!(yield* pty.get(ctx.params.ptyID).pipe(Effect.as(!0), Effect.catchTag("PersistentPty.NotFoundError", () => Effect.succeed(!1)), Effect.catchTag("PersistentPty.UnavailableError", () => Effect.succeed(!1)))))
|
|
52
|
-
return HttpServerResponse.empty({ status: 404 });
|
|
53
51
|
const url = new URL(ctx.request.url, "http://localhost"), ticket = url.searchParams.get(PTY_CONNECT_TICKET_QUERY);
|
|
54
52
|
if (ticket) {
|
|
55
53
|
if (!(isAllowedRequestOrigin(ctx.request.headers.origin, ctx.request.headers.host, cors) ? yield* tickets.consume({ ticket, ptyID: ctx.params.ptyID }) : !1))
|
|
@@ -58,45 +56,50 @@ export const PersistentPtyHandler = HttpApiBuilder.group(Api, "server.experiment
|
|
|
58
56
|
const cursor = Number(url.searchParams.get("cursor") ?? "0"), role = url.searchParams.get("role") === "observer" ? "observer" : "controller", framedInput = url.searchParams.get("input_protocol") === "1", attachmentID = url.searchParams.get("attachment_id") ?? crypto.randomUUID();
|
|
59
57
|
if (!Number.isSafeInteger(cursor) || cursor < 0)
|
|
60
58
|
return HttpServerResponse.empty({ status: 400 });
|
|
61
|
-
const socket = yield* Effect.orDie(ctx.request.upgrade), write = yield* socket.writer, outbox = yield* Queue.unbounded(), input = yield* Semaphore.make(1)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
info: attachment.info,
|
|
86
|
-
role: attachment.role,
|
|
87
|
-
generation: attachment.generation,
|
|
88
|
-
replay: {
|
|
89
|
-
requestedOffset: attachment.replay.requestedOffset,
|
|
90
|
-
availableOffset: attachment.replay.availableOffset,
|
|
91
|
-
endOffset: attachment.replay.endOffset,
|
|
92
|
-
truncated: attachment.replay.truncated
|
|
59
|
+
const socket = yield* Effect.orDie(ctx.request.upgrade), write = yield* socket.writer, outbox = yield* Queue.unbounded(), input = yield* Semaphore.make(1);
|
|
60
|
+
let attachment;
|
|
61
|
+
const onOpen = Effect.gen(function* () {
|
|
62
|
+
attachment = yield* pty.attach(ctx.params.ptyID, {
|
|
63
|
+
cursor,
|
|
64
|
+
attachmentID,
|
|
65
|
+
role,
|
|
66
|
+
takeover: url.searchParams.get("takeover") === "true",
|
|
67
|
+
onEvent: (event) => {
|
|
68
|
+
if (event.type === "output")
|
|
69
|
+
Queue.offerUnsafe(outbox, event.data);
|
|
70
|
+
if (event.type === "resized")
|
|
71
|
+
Queue.offerUnsafe(outbox, JSON.stringify({ ...event, checkpoint: Buffer.from(event.checkpoint).toString("base64") }));
|
|
72
|
+
if (event.type !== "output" && event.type !== "resized")
|
|
73
|
+
Queue.offerUnsafe(outbox, JSON.stringify(event));
|
|
74
|
+
},
|
|
75
|
+
onEnd: () => Queue.offerUnsafe(outbox, new Socket.CloseEvent(1000))
|
|
76
|
+
}).pipe(Effect.catchTags({
|
|
77
|
+
"PersistentPty.NotFoundError": () => Effect.succeed(void 0),
|
|
78
|
+
"PersistentPty.UnavailableError": () => Effect.succeed(void 0)
|
|
79
|
+
}));
|
|
80
|
+
if (!attachment) {
|
|
81
|
+
Queue.offerUnsafe(outbox, new Socket.CloseEvent(4404, "terminal unavailable"));
|
|
82
|
+
return;
|
|
93
83
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
84
|
+
Queue.offerUnsafe(outbox, JSON.stringify({
|
|
85
|
+
type: "attached",
|
|
86
|
+
attachmentID,
|
|
87
|
+
inputProtocol: framedInput ? 1 : 0,
|
|
88
|
+
info: attachment.info,
|
|
89
|
+
role: attachment.role,
|
|
90
|
+
generation: attachment.generation,
|
|
91
|
+
replay: {
|
|
92
|
+
requestedOffset: attachment.replay.requestedOffset,
|
|
93
|
+
availableOffset: attachment.replay.availableOffset,
|
|
94
|
+
endOffset: attachment.replay.endOffset,
|
|
95
|
+
truncated: attachment.replay.truncated
|
|
96
|
+
}
|
|
97
|
+
}));
|
|
98
|
+
if (attachment.replay.data.length > 0)
|
|
99
|
+
Queue.offerUnsafe(outbox, attachment.replay.data);
|
|
100
|
+
Queue.offerUnsafe(outbox, JSON.stringify({ type: "replay_complete", endOffset: attachment.replay.endOffset }));
|
|
101
|
+
attachment.activate();
|
|
102
|
+
}), drain = Effect.gen(function* () {
|
|
100
103
|
while (!0) {
|
|
101
104
|
const item = yield* Queue.take(outbox);
|
|
102
105
|
yield* write(item);
|
|
@@ -105,6 +108,8 @@ export const PersistentPtyHandler = HttpApiBuilder.group(Api, "server.experiment
|
|
|
105
108
|
}
|
|
106
109
|
});
|
|
107
110
|
yield* Effect.race(drain, socket.runRaw((message) => input.withPermit(Effect.suspend(() => {
|
|
111
|
+
if (!attachment)
|
|
112
|
+
return Effect.void;
|
|
108
113
|
const data = typeof message === "string" ? Buffer.from(message) : message;
|
|
109
114
|
if (!framedInput)
|
|
110
115
|
return pty.input(ctx.params.ptyID, attachmentID, attachment.info.size.cols, attachment.info.size.rows, data).pipe(Effect.ignore);
|
|
@@ -116,7 +121,7 @@ export const PersistentPtyHandler = HttpApiBuilder.group(Api, "server.experiment
|
|
|
116
121
|
if (type === 0)
|
|
117
122
|
return pty.control(ctx.params.ptyID, attachmentID, cols, rows).pipe(Effect.ignore);
|
|
118
123
|
return pty.input(ctx.params.ptyID, attachmentID, cols, rows, data.subarray(5)).pipe(Effect.ignore);
|
|
119
|
-
})))).pipe(Effect.catchReason("SocketError", "SocketCloseError", () => Effect.void), Effect.ensuring(Effect.sync(() => attachment
|
|
124
|
+
})), { onOpen })).pipe(Effect.catchReason("SocketError", "SocketCloseError", () => Effect.void), Effect.ensuring(Effect.sync(() => attachment?.detach())), Effect.orDie);
|
|
120
125
|
return HttpServerResponse.empty();
|
|
121
126
|
}));
|
|
122
127
|
}));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@opencode-ai/server",
|
|
4
|
-
"version": "0.0.0-dev-
|
|
4
|
+
"version": "0.0.0-dev-18308",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@effect/platform-node": "4.0.0-rc.111",
|
|
32
32
|
"@effect/platform-node-shared": "4.0.0-rc.111",
|
|
33
|
-
"@opencode-ai/core": "0.0.0-dev-
|
|
34
|
-
"@opencode-ai/protocol": "0.0.0-dev-
|
|
35
|
-
"@opencode-ai/schema": "0.0.0-dev-
|
|
36
|
-
"@opencode-ai/simulation": "0.0.0-dev-
|
|
37
|
-
"@opencode-ai/util": "0.0.0-dev-
|
|
33
|
+
"@opencode-ai/core": "0.0.0-dev-18308",
|
|
34
|
+
"@opencode-ai/protocol": "0.0.0-dev-18308",
|
|
35
|
+
"@opencode-ai/schema": "0.0.0-dev-18308",
|
|
36
|
+
"@opencode-ai/simulation": "0.0.0-dev-18308",
|
|
37
|
+
"@opencode-ai/util": "0.0.0-dev-18308",
|
|
38
38
|
"drizzle-orm": "1.0.0-rc.5-169397b",
|
|
39
39
|
"effect": "4.0.0-rc.111"
|
|
40
40
|
},
|