@opencode/server 2.0.7 → 2.0.9

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.
Files changed (104) hide show
  1. package/dist/api.d.ts +4 -4
  2. package/dist/api.js +10 -9
  3. package/dist/auth.js +12 -17
  4. package/dist/chunks/fetch-00nn3k4b.js +20 -0
  5. package/dist/chunks/fetch-04xw3v55.js +23 -0
  6. package/dist/chunks/fetch-0d9kah4z.js +23 -0
  7. package/dist/chunks/fetch-19c9ysa1.js +61 -0
  8. package/dist/chunks/fetch-1c4qas2w.js +346 -0
  9. package/dist/chunks/fetch-254zvkj6.js +22 -0
  10. package/dist/chunks/fetch-3kzx88w9.js +26 -0
  11. package/dist/chunks/fetch-4cf3x1kw.js +21 -0
  12. package/dist/chunks/fetch-4g0fa6m0.js +32 -0
  13. package/dist/chunks/fetch-4vn5bvkr.js +25 -0
  14. package/dist/chunks/fetch-5rwqcaw2.js +33 -0
  15. package/dist/chunks/fetch-6gkz39ey.js +55 -0
  16. package/dist/chunks/fetch-6nvan4e0.js +17 -0
  17. package/dist/chunks/fetch-7rzt3wm8.js +13 -0
  18. package/dist/chunks/fetch-8bajbwjh.js +40 -0
  19. package/dist/chunks/fetch-99sfd1j8.js +83 -0
  20. package/dist/chunks/fetch-9rqn6x4v.js +16 -0
  21. package/dist/chunks/fetch-a6yp8301.js +156 -0
  22. package/dist/chunks/fetch-arj41x43.js +77 -0
  23. package/dist/chunks/fetch-b0b71rwa.js +39 -0
  24. package/dist/chunks/fetch-bjrwanme.js +22 -0
  25. package/dist/chunks/fetch-br99j6q1.js +35 -0
  26. package/dist/chunks/fetch-ceh2h0m9.js +25 -0
  27. package/dist/chunks/fetch-csspsf0t.js +99 -0
  28. package/dist/chunks/fetch-d4bshj6j.js +37 -0
  29. package/dist/chunks/fetch-hezj1jdf.js +7 -0
  30. package/dist/chunks/fetch-hjnxtxmk.js +34 -0
  31. package/dist/chunks/fetch-j2pfq4q6.js +42 -0
  32. package/dist/chunks/fetch-m6wvgbfq.js +60 -0
  33. package/dist/chunks/fetch-n0er2m55.js +163 -0
  34. package/dist/chunks/fetch-pnqq1zxv.js +29 -0
  35. package/dist/chunks/fetch-q0ycym90.js +13 -0
  36. package/dist/chunks/fetch-q4bn6dy8.js +39 -0
  37. package/dist/chunks/fetch-qm92ga5h.js +26 -0
  38. package/dist/chunks/fetch-qnwpcgp7.js +22 -0
  39. package/dist/chunks/fetch-r7e9r02j.js +13 -0
  40. package/dist/chunks/fetch-rcg4y18n.js +59 -0
  41. package/dist/chunks/fetch-req22b70.js +22 -0
  42. package/dist/chunks/fetch-s4aja1df.js +36 -0
  43. package/dist/chunks/fetch-smaf4a18.js +28 -0
  44. package/dist/chunks/fetch-t8yzmczr.js +18 -0
  45. package/dist/chunks/fetch-vgpejxxy.js +149 -0
  46. package/dist/chunks/fetch-xsrtpxyd.js +23 -0
  47. package/dist/chunks/fetch-yc7nft6q.js +5 -0
  48. package/dist/chunks/fetch-ychamt23.js +139 -0
  49. package/dist/chunks/fetch-ysabas57.js +13 -0
  50. package/dist/chunks/fetch-z5shrcz9.js +19 -0
  51. package/dist/chunks/fetch-zp2jm6dt.js +15 -0
  52. package/dist/chunks/fetch-zyv89x5n.js +30 -0
  53. package/dist/cors.js +10 -36
  54. package/dist/event-feed.js +20 -60
  55. package/dist/fetch.js +53 -11
  56. package/dist/handlers/agent.js +11 -17
  57. package/dist/handlers/command.js +11 -5
  58. package/dist/handlers/config.js +11 -16
  59. package/dist/handlers/credential.js +11 -14
  60. package/dist/handlers/debug.js +11 -11
  61. package/dist/handlers/event.js +12 -27
  62. package/dist/handlers/form.js +11 -9
  63. package/dist/handlers/fs.js +11 -22
  64. package/dist/handlers/generate.js +11 -15
  65. package/dist/handlers/integration.js +10 -142
  66. package/dist/handlers/location.js +11 -16
  67. package/dist/handlers/mcp.js +11 -31
  68. package/dist/handlers/message.js +10 -42
  69. package/dist/handlers/migration.js +11 -7
  70. package/dist/handlers/model.js +11 -14
  71. package/dist/handlers/permission.js +11 -57
  72. package/dist/handlers/persistent-pty.js +12 -135
  73. package/dist/handlers/plugin.js +11 -47
  74. package/dist/handlers/project.js +11 -9
  75. package/dist/handlers/provider.js +11 -20
  76. package/dist/handlers/pty-socket.js +6 -4
  77. package/dist/handlers/pty.js +13 -107
  78. package/dist/handlers/reference.js +11 -5
  79. package/dist/handlers/rpc.js +11 -15
  80. package/dist/handlers/server.js +12 -13
  81. package/dist/handlers/session-error.js +12 -26
  82. package/dist/handlers/session.js +10 -311
  83. package/dist/handlers/shell.js +11 -25
  84. package/dist/handlers/skill.js +11 -5
  85. package/dist/handlers/vcs.js +11 -19
  86. package/dist/handlers/websearch.js +11 -31
  87. package/dist/handlers/worktree.js +11 -37
  88. package/dist/handlers.d.ts +1 -1
  89. package/dist/handlers.js +46 -33
  90. package/dist/location.js +15 -49
  91. package/dist/middleware/authorization.js +11 -49
  92. package/dist/middleware/form-location.js +10 -25
  93. package/dist/middleware/schema-error.js +8 -15
  94. package/dist/middleware/session-location.js +10 -19
  95. package/dist/options.js +5 -1
  96. package/dist/process.js +108 -28
  97. package/dist/pty-environment.js +12 -9
  98. package/dist/request-tracing.js +6 -2
  99. package/dist/routes.d.ts +2 -2
  100. package/dist/routes.js +52 -118
  101. package/dist/server-info.js +12 -22
  102. package/dist/service-status.js +8 -11
  103. package/dist/workerd.js +80 -12
  104. package/package.json +8 -8
@@ -0,0 +1,25 @@
1
+ import {
2
+ response2
3
+ } from "./fetch-6gkz39ey.js";
4
+ import {
5
+ Api2
6
+ } from "./fetch-z5shrcz9.js";
7
+
8
+ // src/handlers/agent.ts
9
+ import { Agent } from "@opencode/core/agent";
10
+ import { Effect } from "effect";
11
+ import { HttpApiBuilder } from "effect/unstable/httpapi";
12
+ import { AgentNotFoundError } from "@opencode/protocol/errors";
13
+ var AgentHandler2 = HttpApiBuilder.group(Api2, "server.agent", (handlers) => handlers.handle("agent.list", () => Effect.gen(function* () {
14
+ return yield* response2(Agent.Service.use((agent) => agent.list()));
15
+ })).handle("agent.get", Effect.fn(function* (ctx) {
16
+ const agent = yield* Agent.Service.use((service) => service.get(ctx.params.agentID));
17
+ if (!agent)
18
+ return yield* new AgentNotFoundError({
19
+ agentID: ctx.params.agentID,
20
+ message: `Agent not found: ${ctx.params.agentID}`
21
+ });
22
+ return yield* response2(Effect.succeed(agent));
23
+ })));
24
+
25
+ export { AgentHandler2 };
@@ -0,0 +1,99 @@
1
+ import {
2
+ GenerateHandler2
3
+ } from "./fetch-4vn5bvkr.js";
4
+ import {
5
+ MessageHandler2
6
+ } from "./fetch-rcg4y18n.js";
7
+ import {
8
+ ModelHandler2
9
+ } from "./fetch-254zvkj6.js";
10
+ import {
11
+ ProviderHandler2
12
+ } from "./fetch-pnqq1zxv.js";
13
+ import {
14
+ SessionHandler2
15
+ } from "./fetch-1c4qas2w.js";
16
+ import {
17
+ PermissionHandler2
18
+ } from "./fetch-arj41x43.js";
19
+ import {
20
+ FileSystemHandler2
21
+ } from "./fetch-hjnxtxmk.js";
22
+ import {
23
+ FormHandler2
24
+ } from "./fetch-6nvan4e0.js";
25
+ import {
26
+ CommandHandler2
27
+ } from "./fetch-r7e9r02j.js";
28
+ import {
29
+ SkillHandler2
30
+ } from "./fetch-q0ycym90.js";
31
+ import {
32
+ RpcHandler2
33
+ } from "./fetch-bjrwanme.js";
34
+ import {
35
+ layer5
36
+ } from "./fetch-99sfd1j8.js";
37
+ import {
38
+ EventHandler2
39
+ } from "./fetch-d4bshj6j.js";
40
+ import {
41
+ AgentHandler2
42
+ } from "./fetch-ceh2h0m9.js";
43
+ import {
44
+ PluginHandler2
45
+ } from "./fetch-19c9ysa1.js";
46
+ import {
47
+ ServerHandler2
48
+ } from "./fetch-4cf3x1kw.js";
49
+ import {
50
+ DebugHandler2
51
+ } from "./fetch-00nn3k4b.js";
52
+ import {
53
+ PtyHandler2
54
+ } from "./fetch-ychamt23.js";
55
+ import {
56
+ PersistentPtyHandler2
57
+ } from "./fetch-n0er2m55.js";
58
+ import {
59
+ ShellHandler2
60
+ } from "./fetch-br99j6q1.js";
61
+ import {
62
+ ReferenceHandler2
63
+ } from "./fetch-ysabas57.js";
64
+ import {
65
+ LocationHandler2
66
+ } from "./fetch-req22b70.js";
67
+ import {
68
+ IntegrationHandler2
69
+ } from "./fetch-a6yp8301.js";
70
+ import {
71
+ WebSearchHandler2
72
+ } from "./fetch-b0b71rwa.js";
73
+ import {
74
+ McpHandler2
75
+ } from "./fetch-8bajbwjh.js";
76
+ import {
77
+ CredentialHandler2
78
+ } from "./fetch-04xw3v55.js";
79
+ import {
80
+ ProjectHandler2
81
+ } from "./fetch-zp2jm6dt.js";
82
+ import {
83
+ WorktreeHandler2
84
+ } from "./fetch-j2pfq4q6.js";
85
+ import {
86
+ VcsHandler2
87
+ } from "./fetch-4g0fa6m0.js";
88
+ import {
89
+ MigrationHandler2
90
+ } from "./fetch-7rzt3wm8.js";
91
+ import {
92
+ ConfigHandler2
93
+ } from "./fetch-qnwpcgp7.js";
94
+
95
+ // src/handlers.ts
96
+ import { Layer } from "effect";
97
+ var handlers2 = Layer.mergeAll(ServerHandler2, DebugHandler2, MigrationHandler2, LocationHandler2, AgentHandler2, PluginHandler2, SessionHandler2, MessageHandler2, ModelHandler2, GenerateHandler2, ProviderHandler2, IntegrationHandler2, WebSearchHandler2, McpHandler2, CredentialHandler2, ProjectHandler2, FormHandler2, PermissionHandler2, FileSystemHandler2, CommandHandler2, SkillHandler2, RpcHandler2, EventHandler2.pipe(Layer.provide(layer5)), PtyHandler2, PersistentPtyHandler2, ShellHandler2, ReferenceHandler2, WorktreeHandler2, VcsHandler2, ConfigHandler2);
98
+
99
+ export { handlers2 };
@@ -0,0 +1,37 @@
1
+ import {
2
+ Api2
3
+ } from "./fetch-z5shrcz9.js";
4
+ import {
5
+ Service4,
6
+ frame2
7
+ } from "./fetch-99sfd1j8.js";
8
+
9
+ // src/handlers/event.ts
10
+ import { Event } from "@opencode/schema/event";
11
+ import { Effect, Stream } from "effect";
12
+ import { HttpServerResponse } from "effect/unstable/http";
13
+ import { HttpApiBuilder } from "effect/unstable/httpapi";
14
+ var EventHandler2 = HttpApiBuilder.group(Api2, "server.event", (handlers) => Effect.gen(function* () {
15
+ const feed = yield* Service4;
16
+ return handlers.handleRaw("event.subscribe", () => Effect.gen(function* () {
17
+ const connected = {
18
+ id: Event.ID.create(),
19
+ type: "server.connected",
20
+ data: {}
21
+ };
22
+ const output = Stream.unwrap(feed.subscribe.pipe(Effect.map((live) => Stream.make(frame2(connected)).pipe(Stream.concat(live)))));
23
+ const heartbeat = Stream.tick("15 seconds").pipe(Stream.map(() => `: heartbeat
24
+
25
+ `));
26
+ return HttpServerResponse.stream(output.pipe(Stream.merge(heartbeat, { haltStrategy: "left" }), Stream.encodeText), {
27
+ contentType: "text/event-stream",
28
+ headers: {
29
+ "Cache-Control": "no-cache, no-transform",
30
+ "X-Accel-Buffering": "no",
31
+ "X-Content-Type-Options": "nosniff"
32
+ }
33
+ });
34
+ }));
35
+ }));
36
+
37
+ export { EventHandler2 };
@@ -0,0 +1,7 @@
1
+ // src/handlers/pty-socket.ts
2
+ import { Effect } from "effect";
3
+ function runPtySocket2(drain, socket, detach) {
4
+ return Effect.raceFirst(drain, socket).pipe(Effect.ensuring(Effect.sync(detach)));
5
+ }
6
+
7
+ export { runPtySocket2 };
@@ -0,0 +1,34 @@
1
+ import {
2
+ response2
3
+ } from "./fetch-6gkz39ey.js";
4
+ import {
5
+ Api2
6
+ } from "./fetch-z5shrcz9.js";
7
+
8
+ // src/handlers/fs.ts
9
+ import { FileSystem } from "@opencode/core/filesystem";
10
+ import { RelativePath } from "@opencode/core/schema";
11
+ import { FileNotFoundError } from "@opencode/protocol/errors";
12
+ import { Effect } from "effect";
13
+ import { HttpServerResponse } from "effect/unstable/http";
14
+ import { HttpApiBuilder } from "effect/unstable/httpapi";
15
+ var FileSystemHandler2 = HttpApiBuilder.group(Api2, "server.fs", (handlers) => Effect.gen(function* () {
16
+ return handlers.handleRaw("fs.read", (ctx) => Effect.gen(function* () {
17
+ const fs = yield* FileSystem.Service;
18
+ const file = yield* fs.read({
19
+ path: RelativePath.make(decodeURIComponent(new URL(ctx.request.url, "http://localhost").pathname.slice(13)))
20
+ }).pipe(Effect.mapError((error) => new FileNotFoundError({ path: error.path, message: `File not found: ${error.path}` })));
21
+ return HttpServerResponse.uint8Array(file.content, { contentType: file.mime });
22
+ })).handle("fs.list", (ctx) => response2(Effect.gen(function* () {
23
+ const fs = yield* FileSystem.Service;
24
+ return yield* fs.list(ctx.query);
25
+ }))).handle("fs.find", (ctx) => response2(Effect.gen(function* () {
26
+ const fs = yield* FileSystem.Service;
27
+ return yield* fs.find(ctx.query);
28
+ }))).handle("fs.write", (ctx) => response2(Effect.gen(function* () {
29
+ const fs = yield* FileSystem.Service;
30
+ return yield* fs.write({ path: ctx.query.path, data: ctx.payload });
31
+ })));
32
+ }));
33
+
34
+ export { FileSystemHandler2 };
@@ -0,0 +1,42 @@
1
+ import {
2
+ Api2
3
+ } from "./fetch-z5shrcz9.js";
4
+
5
+ // src/handlers/worktree.ts
6
+ import { Git } from "@opencode/core/git";
7
+ import { Worktree } from "@opencode/core/worktree";
8
+ import { ProjectNotFoundError } from "@opencode/protocol/errors";
9
+ import { WorktreeError } from "@opencode/protocol/groups/worktree";
10
+ import { Effect } from "effect";
11
+ import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
12
+ var WorktreeHandler2 = HttpApiBuilder.group(Api2, "server.worktree", (handlers) => Effect.gen(function* () {
13
+ const worktrees = yield* Worktree.Service;
14
+ return handlers.handle("worktree.list", (ctx) => worktrees.list(ctx.query).pipe(Effect.catchTag("Project.NotFoundError", missingProject))).handle("worktree.create", (ctx) => worktrees.create(ctx.payload).pipe(badRequest)).handle("worktree.remove", (ctx) => worktrees.remove(ctx.payload).pipe(badRequest, Effect.as(HttpApiSchema.NoContent.make()))).handle("worktree.refresh", (ctx) => worktrees.refresh(ctx.payload).pipe(badRequest, Effect.as(HttpApiSchema.NoContent.make())));
15
+ }));
16
+ function badRequest(effect) {
17
+ return effect.pipe(Effect.catchTag("Project.NotFoundError", missingProject), Effect.mapError((error) => error instanceof ProjectNotFoundError ? error : new WorktreeError({
18
+ name: "WorktreeError",
19
+ data: {
20
+ message: message(error),
21
+ forceRequired: error instanceof Git.WorktreeError || error instanceof Worktree.OperationError ? error.forceRequired : undefined
22
+ }
23
+ })));
24
+ }
25
+ function missingProject(error) {
26
+ return Effect.fail(new ProjectNotFoundError({ projectID: error.projectID, message: `Project not found: ${error.projectID}` }));
27
+ }
28
+ function message(error) {
29
+ if (error instanceof Worktree.SourceDirectoryNotFoundError)
30
+ return error.directory ? `Worktree source not found: ${error.directory}` : `Worktree source not found for project: ${error.projectID}`;
31
+ if (error instanceof Worktree.DestinationExistsError)
32
+ return `Worktree destination already exists: ${error.directory}`;
33
+ if (error instanceof Worktree.DirectoryUnavailableError)
34
+ return `Worktree directory unavailable: ${error.directory}`;
35
+ if (error instanceof Worktree.InvalidDirectoryError)
36
+ return `Invalid worktree directory: ${error.directory}`;
37
+ if (error instanceof Worktree.StrategyUnavailableError)
38
+ return `Worktree strategy unavailable: ${error.strategy}`;
39
+ return error.message;
40
+ }
41
+
42
+ export { WorktreeHandler2 };
@@ -0,0 +1,60 @@
1
+ import {
2
+ Config2,
3
+ required2,
4
+ authorized2
5
+ } from "./fetch-zyv89x5n.js";
6
+
7
+ // src/middleware/authorization.ts
8
+ import { UnauthorizedError } from "@opencode/protocol/errors";
9
+ import { Authorization } from "@opencode/protocol/middleware/authorization";
10
+ import { Authorization as Authorization2 } from "@opencode/protocol/middleware/authorization";
11
+ import { hasPtyConnectTicketURL } from "@opencode/protocol/groups/pty";
12
+ import { hasPersistentPtyConnectTicketURL } from "@opencode/protocol/groups/persistent-pty";
13
+ import { Effect, Encoding, Layer, Redacted } from "effect";
14
+ import { HttpEffect, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
15
+ var AUTH_TOKEN_QUERY = "auth_token";
16
+ var WWW_AUTHENTICATE = 'Basic realm="Secure Area"';
17
+ function emptyCredential() {
18
+ return { username: "", password: Redacted.make("") };
19
+ }
20
+ function decodeCredential(input) {
21
+ return Effect.fromResult(Encoding.decodeBase64String(input)).pipe(Effect.match({
22
+ onFailure: emptyCredential,
23
+ onSuccess: (header) => {
24
+ const separator = header.indexOf(":");
25
+ if (separator === -1)
26
+ return emptyCredential();
27
+ return { username: header.slice(0, separator), password: Redacted.make(header.slice(separator + 1)) };
28
+ }
29
+ }));
30
+ }
31
+ function credentialFromRequest(request) {
32
+ const url = new URL(request.url, "http://localhost");
33
+ const token = url.searchParams.get(AUTH_TOKEN_QUERY);
34
+ if (token)
35
+ return decodeCredential(token);
36
+ const match = /^Basic\s+(.+)$/i.exec(request.headers.authorization ?? "");
37
+ if (match)
38
+ return decodeCredential(match[1]);
39
+ return Effect.succeed(emptyCredential());
40
+ }
41
+ function authorizedRequest2(request, config) {
42
+ return credentialFromRequest(request).pipe(Effect.map((credential) => authorized2(credential, config)));
43
+ }
44
+ var authorizationLayer2 = Layer.effect(Authorization, Effect.gen(function* () {
45
+ const config = yield* Config2;
46
+ if (!required2(config))
47
+ return Authorization.of((effect) => effect);
48
+ return Authorization.of((effect) => Effect.gen(function* () {
49
+ const request = yield* HttpServerRequest.HttpServerRequest;
50
+ const url = new URL(request.url, "http://localhost");
51
+ if (hasPtyConnectTicketURL(url) || hasPersistentPtyConnectTicketURL(url))
52
+ return yield* effect;
53
+ if (yield* authorizedRequest2(request, config))
54
+ return yield* effect;
55
+ yield* HttpEffect.appendPreResponseHandler((_request, response) => Effect.succeed(HttpServerResponse.setHeader(response, "www-authenticate", WWW_AUTHENTICATE)));
56
+ return yield* new UnauthorizedError({ message: "Authentication required" });
57
+ }));
58
+ }));
59
+
60
+ export { authorizedRequest2, authorizationLayer2, Authorization2 };
@@ -0,0 +1,163 @@
1
+ import {
2
+ Api2
3
+ } from "./fetch-z5shrcz9.js";
4
+ import {
5
+ CorsConfig2,
6
+ isAllowedRequestOrigin2
7
+ } from "./fetch-q4bn6dy8.js";
8
+ import {
9
+ runPtySocket2
10
+ } from "./fetch-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,29 @@
1
+ import {
2
+ response2
3
+ } from "./fetch-6gkz39ey.js";
4
+ import {
5
+ Api2
6
+ } from "./fetch-z5shrcz9.js";
7
+
8
+ // src/handlers/provider.ts
9
+ import { Provider } from "@opencode/core/provider";
10
+ import { ProviderNotFoundError } from "@opencode/protocol/errors";
11
+ import { Effect } from "effect";
12
+ import { HttpApiBuilder } from "effect/unstable/httpapi";
13
+ var ProviderHandler2 = HttpApiBuilder.group(Api2, "server.provider", (handlers) => Effect.gen(function* () {
14
+ return handlers.handle("provider.list", Effect.fn(function* () {
15
+ const providers = yield* Provider.Service;
16
+ return yield* response2(providers.available());
17
+ })).handle("provider.get", Effect.fn(function* (ctx) {
18
+ const providers = yield* Provider.Service;
19
+ const provider = yield* providers.get(ctx.params.providerID);
20
+ if (!provider)
21
+ return yield* new ProviderNotFoundError({
22
+ providerID: ctx.params.providerID,
23
+ message: `Provider not found: ${ctx.params.providerID}`
24
+ });
25
+ return yield* response2(Effect.succeed(provider));
26
+ }));
27
+ }));
28
+
29
+ export { ProviderHandler2 };
@@ -0,0 +1,13 @@
1
+ import {
2
+ response2
3
+ } from "./fetch-6gkz39ey.js";
4
+ import {
5
+ Api2
6
+ } from "./fetch-z5shrcz9.js";
7
+
8
+ // src/handlers/skill.ts
9
+ import { Skill } from "@opencode/core/skill";
10
+ import { HttpApiBuilder } from "effect/unstable/httpapi";
11
+ var SkillHandler2 = HttpApiBuilder.group(Api2, "server.skill", (handlers) => handlers.handle("skill.list", () => response2(Skill.Service.use((skill) => skill.list()))));
12
+
13
+ export { SkillHandler2 };
@@ -0,0 +1,39 @@
1
+ // src/cors.ts
2
+ import { Context } from "effect";
3
+ var opencodeOrigin = /^https:\/\/([a-z0-9-]+\.)*opencode\.ai$/;
4
+ var CorsConfig2 = Context.Reference("@opencode/ServerCorsConfig", {
5
+ defaultValue: () => {
6
+ return;
7
+ }
8
+ });
9
+ function isAllowedCorsOrigin2(input, opts) {
10
+ if (!input)
11
+ return true;
12
+ if (input.startsWith("http://localhost:"))
13
+ return true;
14
+ if (input.startsWith("http://127.0.0.1:"))
15
+ return true;
16
+ if (input.startsWith("oc://renderer"))
17
+ return true;
18
+ if (input === "tauri://localhost" || input === "http://tauri.localhost" || input === "https://tauri.localhost")
19
+ return true;
20
+ if (opencodeOrigin.test(input))
21
+ return true;
22
+ return opts?.cors?.includes(input) ?? false;
23
+ }
24
+ function isAllowedRequestOrigin2(input, host, opts) {
25
+ if (!input)
26
+ return true;
27
+ if (host && sameHost(input, host))
28
+ return true;
29
+ return isAllowedCorsOrigin2(input, opts);
30
+ }
31
+ function sameHost(origin, host) {
32
+ try {
33
+ return new URL(origin).host === host;
34
+ } catch {
35
+ return false;
36
+ }
37
+ }
38
+
39
+ export { CorsConfig2, isAllowedCorsOrigin2, isAllowedRequestOrigin2 };
@@ -0,0 +1,26 @@
1
+ import {
2
+ isAllowedCorsOrigin2
3
+ } from "./fetch-q4bn6dy8.js";
4
+ import {
5
+ createRoutes2
6
+ } from "./fetch-vgpejxxy.js";
7
+ import {
8
+ __export
9
+ } from "./fetch-9rqn6x4v.js";
10
+
11
+ // src/fetch.ts
12
+ var exports_fetch = {};
13
+ __export(exports_fetch, {
14
+ ServerFetch: () => exports_fetch,
15
+ make: () => make3
16
+ });
17
+ import { Context, Effect, Layer } from "effect";
18
+ import { HttpEffect, HttpMiddleware, HttpRouter, HttpServer } from "effect/unstable/http";
19
+ import { SessionRestart } from "@opencode/core/session/execution/restart";
20
+ var make3 = Effect.fn("ServerFetch.make")(function* (options = {}, boot = {}) {
21
+ const context = yield* Layer.build(createRoutes2(options, () => [], boot.overrides ?? []).pipe(Layer.provide(HttpServer.layerServices)));
22
+ yield* Effect.forkDetach(Context.get(context, SessionRestart.Service).resumeSuspendedSessions);
23
+ return Context.get(context, HttpRouter.HttpRouter).asHttpEffect().pipe(HttpMiddleware.cors({ allowedOrigins: (origin) => isAllowedCorsOrigin2(origin, options), maxAge: 86400 }), HttpEffect.toWebHandlerWith(context));
24
+ });
25
+
26
+ export { make3, exports_fetch };
@@ -0,0 +1,22 @@
1
+ import {
2
+ Api2
3
+ } from "./fetch-z5shrcz9.js";
4
+
5
+ // src/handlers/config.ts
6
+ import { Config } from "@opencode/core/config";
7
+ import { ShellSelect } from "@opencode/core/shell/select";
8
+ import { Effect } from "effect";
9
+ import { HttpApiBuilder } from "effect/unstable/httpapi";
10
+ var ConfigHandler2 = HttpApiBuilder.group(Api2, "server.config", (handlers) => handlers.handle("config.get", () => Config.Service.use((config) => config.entries())).handle("config.update", Effect.fn(function* (ctx) {
11
+ const config = yield* Config.Service;
12
+ if (!config.update)
13
+ return yield* Effect.die(new Error("Config updates are unavailable"));
14
+ return yield* config.update(ctx.payload).pipe(Effect.orDie);
15
+ })).handle("config.shells", Effect.fn(function* () {
16
+ const shell = yield* ShellSelect.Service;
17
+ if (!shell.list)
18
+ return yield* Effect.die(new Error("Shell discovery is unavailable"));
19
+ return yield* shell.list();
20
+ })));
21
+
22
+ export { ConfigHandler2 };
@@ -0,0 +1,13 @@
1
+ import {
2
+ response2
3
+ } from "./fetch-6gkz39ey.js";
4
+ import {
5
+ Api2
6
+ } from "./fetch-z5shrcz9.js";
7
+
8
+ // src/handlers/command.ts
9
+ import { Command } from "@opencode/core/command";
10
+ import { HttpApiBuilder } from "effect/unstable/httpapi";
11
+ var CommandHandler2 = HttpApiBuilder.group(Api2, "server.command", (handlers) => handlers.handle("command.list", () => response2(Command.Service.use((command) => command.list()))));
12
+
13
+ export { CommandHandler2 };