@opencode/server 2.0.8 → 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,59 @@
1
+ import {
2
+ missingSession2,
3
+ failedMessageDecode2
4
+ } from "./fetch-smaf4a18.js";
5
+ import {
6
+ Api2
7
+ } from "./fetch-z5shrcz9.js";
8
+
9
+ // src/handlers/message.ts
10
+ import { SessionMessage } from "@opencode/core/session/message";
11
+ import { Session } from "@opencode/core/session";
12
+ import { Effect, Schema } from "effect";
13
+ import { HttpApiBuilder } from "effect/unstable/httpapi";
14
+ import { InvalidCursorError } from "@opencode/protocol/errors";
15
+ var DefaultMessagesLimit = 50;
16
+ var Cursor = Schema.Struct({
17
+ id: SessionMessage.ID,
18
+ order: Schema.Union([Schema.Literal("asc"), Schema.Literal("desc")]),
19
+ direction: Schema.Union([Schema.Literal("previous"), Schema.Literal("next")])
20
+ });
21
+ var decodeCursor = Schema.decodeUnknownSync(Cursor);
22
+ var cursor = {
23
+ encode(message, order, direction) {
24
+ return Buffer.from(JSON.stringify({ id: message.id, order, direction })).toString("base64url");
25
+ },
26
+ decode(input) {
27
+ return decodeCursor(JSON.parse(Buffer.from(input, "base64url").toString("utf8")));
28
+ }
29
+ };
30
+ var MessageHandler2 = HttpApiBuilder.group(Api2, "server.message", (handlers) => Effect.gen(function* () {
31
+ const session = yield* Session.Service;
32
+ return handlers.handle("session.messages", Effect.fn(function* (ctx) {
33
+ if (ctx.query.cursor && ctx.query.order !== undefined)
34
+ return yield* new InvalidCursorError({ message: "Cursor cannot be combined with order" });
35
+ const decoded = yield* Effect.try({
36
+ try: () => ctx.query.cursor ? cursor.decode(ctx.query.cursor) : undefined,
37
+ catch: () => new InvalidCursorError({ message: "Invalid cursor" })
38
+ });
39
+ const order = decoded?.order ?? ctx.query.order ?? "desc";
40
+ const messages = yield* session.messages({
41
+ sessionID: ctx.params.sessionID,
42
+ limit: ctx.query.limit ?? DefaultMessagesLimit,
43
+ order,
44
+ type: ctx.query.type,
45
+ cursor: decoded ? { id: decoded.id, direction: decoded.direction } : undefined
46
+ }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.MessageDecodeError", failedMessageDecode2));
47
+ const first = messages[0];
48
+ const last = messages.at(-1);
49
+ return {
50
+ data: messages,
51
+ cursor: {
52
+ previous: first ? cursor.encode(first, order, "previous") : undefined,
53
+ next: last ? cursor.encode(last, order, "next") : undefined
54
+ }
55
+ };
56
+ }));
57
+ }));
58
+
59
+ export { MessageHandler2 };
@@ -0,0 +1,22 @@
1
+ import {
2
+ Api2
3
+ } from "./fetch-z5shrcz9.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,36 @@
1
+ import {
2
+ __export
3
+ } from "./fetch-9rqn6x4v.js";
4
+
5
+ // src/server-info.ts
6
+ var exports_server_info = {};
7
+ __export(exports_server_info, {
8
+ ServerInfo: () => exports_server_info,
9
+ Service: () => Service2,
10
+ connectionURLs: () => connectionURLs2,
11
+ layer: () => layer2
12
+ });
13
+ import { Context, Layer } from "effect";
14
+ import { networkInterfaces } from "node:os";
15
+
16
+ class Service2 extends Context.Service()("@opencode/server/ServerInfo") {
17
+ }
18
+ function layer2(urls, tmp, app = {}) {
19
+ return Layer.succeed(Service2, Service2.of({ urls, app, paths: { tmp } }));
20
+ }
21
+ function connectionURLs2(value, requestedHostname) {
22
+ const url = new URL(value);
23
+ const hostname = requestedHostname ?? url.hostname;
24
+ const family = hostname === "0.0.0.0" ? "IPv4" : hostname === "::" || hostname === "[::]" ? "IPv6" : undefined;
25
+ if (family === undefined)
26
+ return [value];
27
+ return [
28
+ ...new Set(Object.values(networkInterfaces()).flatMap((entries) => entries ?? []).filter((entry) => !entry.internal && entry.family === family).map((entry) => {
29
+ const result = new URL(value);
30
+ result.hostname = family === "IPv6" ? `[${entry.address}]` : entry.address;
31
+ return result.toString().replace(/\/$/, "");
32
+ }))
33
+ ];
34
+ }
35
+
36
+ export { Service2, layer2, connectionURLs2, exports_server_info };
@@ -0,0 +1,28 @@
1
+ // src/handlers/session-error.ts
2
+ import { MessageNotFoundError, SessionNotFoundError, UnknownError } from "@opencode/protocol/errors";
3
+ import { Effect } from "effect";
4
+ function missingSession2(error) {
5
+ return new SessionNotFoundError({
6
+ sessionID: error.sessionID,
7
+ message: `Session not found: ${error.sessionID}`
8
+ });
9
+ }
10
+ function missingMessage2(error) {
11
+ return new MessageNotFoundError({
12
+ sessionID: error.sessionID,
13
+ messageID: error.messageID,
14
+ message: `Message not found: ${error.messageID}`
15
+ });
16
+ }
17
+ function failedMessageDecode2(error) {
18
+ const ref = `err_${crypto.randomUUID().slice(0, 8)}`;
19
+ return Effect.logError("failed to decode session message").pipe(Effect.annotateLogs({ ref, sessionID: error.sessionID, messageID: error.messageID }), Effect.andThen(Effect.fail(new UnknownError({ message: "Unexpected server error. Check server logs for details.", ref }))));
20
+ }
21
+ function failedSnapshot2(operation, sessionID) {
22
+ return (error) => {
23
+ const ref = `err_${crypto.randomUUID().slice(0, 8)}`;
24
+ return Effect.logError(`failed to ${operation}`, { cause: error }).pipe(Effect.annotateLogs({ ref, sessionID }), Effect.andThen(Effect.fail(new UnknownError({ message: "Unexpected server error. Check server logs for details.", ref }))));
25
+ };
26
+ }
27
+
28
+ export { missingSession2, missingMessage2, failedMessageDecode2, failedSnapshot2 };
@@ -0,0 +1,18 @@
1
+ // src/middleware/schema-error.ts
2
+ import { Effect } from "effect";
3
+ import { HttpApiMiddleware } from "effect/unstable/httpapi";
4
+ import { InvalidRequestError } from "@opencode/protocol/errors";
5
+ import { SchemaErrorMiddleware } from "@opencode/protocol/middleware/schema-error";
6
+ import { SchemaErrorMiddleware as SchemaErrorMiddleware2 } from "@opencode/protocol/middleware/schema-error";
7
+ var REASON_LIMIT = 1024;
8
+ function truncateReason(reason) {
9
+ if (reason.length <= REASON_LIMIT)
10
+ return reason;
11
+ return reason.slice(0, REASON_LIMIT) + `... (${reason.length - REASON_LIMIT} more chars)`;
12
+ }
13
+ var schemaErrorLayer2 = HttpApiMiddleware.layerSchemaErrorTransform(SchemaErrorMiddleware, (error) => {
14
+ const reason = truncateReason(error.cause.message);
15
+ return Effect.logWarning("schema rejection").pipe(Effect.annotateLogs({ kind: error.kind, reason }), Effect.andThen(Effect.fail(new InvalidRequestError({ message: reason, kind: error.kind }))));
16
+ });
17
+
18
+ export { schemaErrorLayer2, SchemaErrorMiddleware2 };
@@ -0,0 +1,149 @@
1
+ import {
2
+ layer4
3
+ } from "./fetch-6gkz39ey.js";
4
+ import {
5
+ formLocationLayer2
6
+ } from "./fetch-5rwqcaw2.js";
7
+ import {
8
+ sessionLocationLayer2
9
+ } from "./fetch-3kzx88w9.js";
10
+ import {
11
+ Api2
12
+ } from "./fetch-z5shrcz9.js";
13
+ import {
14
+ Config2
15
+ } from "./fetch-zyv89x5n.js";
16
+ import {
17
+ CorsConfig2
18
+ } from "./fetch-q4bn6dy8.js";
19
+ import {
20
+ layer2
21
+ } from "./fetch-s4aja1df.js";
22
+ import {
23
+ node2
24
+ } from "./fetch-0d9kah4z.js";
25
+ import {
26
+ handlers2
27
+ } from "./fetch-csspsf0t.js";
28
+ import {
29
+ authorizationLayer2
30
+ } from "./fetch-m6wvgbfq.js";
31
+ import {
32
+ schemaErrorLayer2
33
+ } from "./fetch-t8yzmczr.js";
34
+
35
+ // src/routes.ts
36
+ import { Database } from "@opencode/core/database/database";
37
+ import { V1Migration } from "@opencode/core/database/v1-migration";
38
+ import { App } from "@opencode/core/app";
39
+ import { LayerNode } from "@opencode/util/effect/layer-node";
40
+ import { httpClient } from "@opencode/util/effect/app-node-platform";
41
+ import { AppNodeBuilder } from "@opencode/core/effect/app-node-builder";
42
+ import { Bus } from "@opencode/core/bus";
43
+ import { EventLogger } from "@opencode/core/event-logger";
44
+ import { FileSystemSearch } from "@opencode/core/filesystem/search";
45
+ import { Credential } from "@opencode/core/credential";
46
+ import { Config } from "@opencode/core/config";
47
+ import { PermissionSaved } from "@opencode/core/permission/saved";
48
+ import { PtyTicket } from "@opencode/core/pty/ticket";
49
+ import { PersistentPty } from "@opencode/core/persistent-pty";
50
+ import { Project } from "@opencode/core/project";
51
+ import { Worktree } from "@opencode/core/worktree";
52
+ import { Session } from "@opencode/core/session";
53
+ import { Instance } from "@opencode/core/instance/service";
54
+ import { SessionTransfer } from "@opencode/core/session/transfer";
55
+ import { ShellSelect } from "@opencode/core/shell/select";
56
+ import { Job } from "@opencode/core/job";
57
+ import { Mcp } from "@opencode/core/mcp/index";
58
+ import { Global } from "@opencode/util/global";
59
+ import { InstructionDiscovery } from "@opencode/core/instruction-discovery";
60
+ import { LocationServiceMap } from "@opencode/core/location-service-map";
61
+ import { LocationActivity } from "@opencode/core/location-activity";
62
+ import { ModelsDev } from "@opencode/core/models-dev";
63
+ import { SessionRestart } from "@opencode/core/session/execution/restart";
64
+ import { PluginUpdate } from "@opencode/core/plugin/update";
65
+ import { SdkPlugins } from "@opencode/core/plugin/sdk";
66
+ import { WellKnown } from "@opencode/core/wellknown";
67
+ import { Workspace } from "@opencode/core/workspace";
68
+ import { Watcher } from "@opencode/core/filesystem/watcher";
69
+ import { HttpRouter } from "effect/unstable/http";
70
+ import { HttpApiBuilder } from "effect/unstable/httpapi";
71
+ import { Context, Effect, Layer, Option } from "effect";
72
+ var applicationServiceNodes = [
73
+ Global.node,
74
+ Database.node,
75
+ Bus.node,
76
+ EventLogger.node,
77
+ httpClient,
78
+ Job.node,
79
+ Project.node,
80
+ Worktree.node,
81
+ Session.node,
82
+ Instance.node,
83
+ SessionTransfer.node,
84
+ SdkPlugins.node,
85
+ PluginUpdate.node,
86
+ PermissionSaved.node,
87
+ PtyTicket.node,
88
+ PersistentPty.node,
89
+ Credential.node,
90
+ WellKnown.node,
91
+ node2,
92
+ LocationServiceMap.node,
93
+ LocationActivity.node,
94
+ SessionRestart.node,
95
+ Workspace.node
96
+ ];
97
+ var applicationServices = LayerNode.group(applicationServiceNodes);
98
+ function createRoutes2(options = {}, serviceURLs = () => [], overrides = []) {
99
+ return makeRoutes(options.password ? Config2.configLayer({ password: Option.some(options.password) }) : Config2.layer, options, serviceURLs, overrides);
100
+ }
101
+ function createEmbeddedRoutes2(options = {}, overrides = [], instances) {
102
+ return makeRoutes(Config2.configLayer({ password: Option.none() }), options, () => [], overrides, instances);
103
+ }
104
+ function makeRoutes(auth, options, serviceURLs, overrides, instances) {
105
+ const standard = [
106
+ Database.node.replace(Database.configured(options.database)),
107
+ PersistentPty.node.replace(PersistentPty.configured(options.pty)),
108
+ Bus.node.replace(Bus.configured({ persist: options.events?.persist })),
109
+ App.node.replace(App.configured(options.app)),
110
+ ModelsDev.node.replace(ModelsDev.configured(options.models)),
111
+ Watcher.node.replace(Watcher.configured({ enabled: options.fs?.filewatcher })),
112
+ FileSystemSearch.node.replace(FileSystemSearch.configured({ fff: options.fs?.fff })),
113
+ Global.node.replace(Global.layerWith(options.config?.directory ? { config: options.config.directory } : {})),
114
+ Config.node.replace(Config.configured({
115
+ project: options.config?.project,
116
+ file: options.config?.file,
117
+ content: options.config?.content
118
+ })),
119
+ InstructionDiscovery.node.replace(InstructionDiscovery.configured({ project: options.config?.project })),
120
+ ShellSelect.node.replace(ShellSelect.configured({ gitbash: options.windows?.gitbash })),
121
+ Mcp.node.replace(Mcp.configured({
122
+ clientInfo: {
123
+ name: options.app?.name ?? "opencode",
124
+ version: options.app?.version ?? "unknown"
125
+ }
126
+ }))
127
+ ];
128
+ const build = (overrides) => {
129
+ const replacements = [
130
+ ...standard,
131
+ ...instances ? [Instance.node.replace(instances(() => replacements))] : [],
132
+ ...overrides
133
+ ];
134
+ return AppNodeBuilder.build(applicationServices, replacements);
135
+ };
136
+ const serviceLayer = options.simulation ? Layer.unwrap(Effect.gen(function* () {
137
+ const { simulationReplacements } = yield* Effect.promise(() => import("@opencode/simulation/backend"));
138
+ const simulation = yield* simulationReplacements({ version: App.make(options.app).version });
139
+ return build([...overrides, ...simulation]);
140
+ })) : build(overrides);
141
+ return serviceLayer.pipe(Layer.flatMap((context) => {
142
+ const services = Layer.succeedContext(context);
143
+ const requestServices = Layer.merge(Layer.succeedContext(Context.pick(Database.Service, Credential.Service, PermissionSaved.Service, PluginUpdate.Service, Project.Service, WellKnown.Service)(context)), layer2(serviceURLs, Context.get(context, Global.Service).tmp, options.app));
144
+ const api = HttpApiBuilder.layer(Api2, { openapiPath: "/openapi.json" }).pipe(Layer.provide(handlers2.pipe(Layer.provide(services), Layer.provide(Layer.succeed(CorsConfig2, options)))), Layer.provide(formLocationLayer2), Layer.provide(sessionLocationLayer2), Layer.provide(layer4), Layer.provide(authorizationLayer2), Layer.provide(schemaErrorLayer2), Layer.provide(auth), HttpRouter.provideRequest(requestServices), Layer.provideMerge(services), Layer.provideMerge(HttpRouter.layer));
145
+ return Layer.merge(api, V1Migration.layer.pipe(Layer.provide(services)));
146
+ }));
147
+ }
148
+
149
+ export { createRoutes2, createEmbeddedRoutes2 };
@@ -0,0 +1,23 @@
1
+ import {
2
+ __export
3
+ } from "./fetch-9rqn6x4v.js";
4
+
5
+ // src/service-status.ts
6
+ var exports_service_status = {};
7
+ __export(exports_service_status, {
8
+ Status: () => exports_service_status,
9
+ make: () => make2
10
+ });
11
+ import { Effect, Ref } from "effect";
12
+ var make2 = Effect.fnUntraced(function* (options = {}) {
13
+ const current = yield* Ref.make(options.initial ?? { type: "starting" });
14
+ const beginStopping = Ref.update(current, (status) => status.type === "stopping" ? status : { type: "stopping" });
15
+ return {
16
+ current: Ref.get(current),
17
+ ready: Ref.update(current, (status) => status.type === "starting" ? { type: "ready" } : status),
18
+ fail: Ref.update(current, (status) => status.type === "starting" ? { type: "failed" } : status),
19
+ beginStopping
20
+ };
21
+ });
22
+
23
+ export { make2, exports_service_status };
@@ -0,0 +1,5 @@
1
+ // src/request-tracing.ts
2
+ import { Context, Effect, Tracer } from "effect";
3
+ var withoutParentSpan2 = (effect) => effect.pipe(Effect.updateContext((context) => Context.omit(Tracer.ParentSpan)(context)));
4
+
5
+ export { withoutParentSpan2 };
@@ -0,0 +1,139 @@
1
+ import {
2
+ response2
3
+ } from "./fetch-6gkz39ey.js";
4
+ import {
5
+ Api2
6
+ } from "./fetch-z5shrcz9.js";
7
+ import {
8
+ CorsConfig2,
9
+ isAllowedRequestOrigin2
10
+ } from "./fetch-q4bn6dy8.js";
11
+ import {
12
+ Service3
13
+ } from "./fetch-0d9kah4z.js";
14
+ import {
15
+ runPtySocket2
16
+ } from "./fetch-hezj1jdf.js";
17
+
18
+ // src/handlers/pty.ts
19
+ import { Pty } from "@opencode/core/pty";
20
+ import { PtyProtocol } from "@opencode/core/pty/protocol";
21
+ import { PtyTicket } from "@opencode/core/pty/ticket";
22
+ import { Location } from "@opencode/core/location";
23
+ import { Effect, Queue } from "effect";
24
+ import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
25
+ import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
26
+ import { Socket } from "effect/unstable/socket";
27
+ import { ForbiddenError, PtyNotFoundError } from "@opencode/protocol/errors";
28
+ import {
29
+ PTY_CONNECT_TICKET_QUERY,
30
+ PTY_CONNECT_TOKEN_HEADER,
31
+ PTY_CONNECT_TOKEN_HEADER_VALUE
32
+ } from "@opencode/protocol/groups/pty";
33
+ var ticketScope = Effect.gen(function* () {
34
+ const location = yield* Location.Service;
35
+ return { directory: location.directory, workspaceID: location.workspaceID };
36
+ });
37
+ var PtyHandler2 = HttpApiBuilder.group(Api2, "server.pty", (handlers) => Effect.gen(function* () {
38
+ const tickets = yield* PtyTicket.Service;
39
+ const cors = yield* CorsConfig2;
40
+ const environment = yield* Service3;
41
+ return handlers.handle("pty.list", Effect.fn(function* () {
42
+ const pty = yield* Pty.Service;
43
+ return yield* response2(pty.list());
44
+ })).handle("pty.create", Effect.fn(function* (ctx) {
45
+ const pty = yield* Pty.Service;
46
+ const location = yield* Location.Service;
47
+ const cwd = ctx.payload.cwd || location.directory;
48
+ return yield* response2(pty.create({
49
+ ...ctx.payload,
50
+ args: ctx.payload.args ? [...ctx.payload.args] : undefined,
51
+ cwd,
52
+ env: {
53
+ ...ctx.payload.env,
54
+ ...yield* environment.get({ directory: location.directory, cwd })
55
+ }
56
+ }));
57
+ })).handle("pty.get", Effect.fn(function* (ctx) {
58
+ const pty = yield* Pty.Service;
59
+ return yield* response2(pty.get(ctx.params.ptyID).pipe(Effect.catchTag("Pty.NotFoundError", () => new PtyNotFoundError({
60
+ ptyID: ctx.params.ptyID,
61
+ message: `PTY session not found: ${ctx.params.ptyID}`
62
+ }))));
63
+ })).handle("pty.update", Effect.fn(function* (ctx) {
64
+ const pty = yield* Pty.Service;
65
+ return yield* response2(pty.update(ctx.params.ptyID, {
66
+ ...ctx.payload,
67
+ size: ctx.payload.size ? { ...ctx.payload.size } : undefined
68
+ }).pipe(Effect.catchTag("Pty.NotFoundError", () => new PtyNotFoundError({
69
+ ptyID: ctx.params.ptyID,
70
+ message: `PTY session not found: ${ctx.params.ptyID}`
71
+ }))));
72
+ })).handle("pty.remove", Effect.fn(function* (ctx) {
73
+ const pty = yield* Pty.Service;
74
+ yield* pty.remove(ctx.params.ptyID).pipe(Effect.catchTag("Pty.NotFoundError", () => new PtyNotFoundError({
75
+ ptyID: ctx.params.ptyID,
76
+ message: `PTY session not found: ${ctx.params.ptyID}`
77
+ })));
78
+ return HttpApiSchema.NoContent.make();
79
+ })).handle("pty.connectToken", Effect.fn(function* (ctx) {
80
+ const request = yield* HttpServerRequest.HttpServerRequest;
81
+ if (request.headers[PTY_CONNECT_TOKEN_HEADER] !== PTY_CONNECT_TOKEN_HEADER_VALUE || !isAllowedRequestOrigin2(request.headers.origin, request.headers.host, cors))
82
+ return yield* new ForbiddenError({ message: "Invalid PTY connect token request" });
83
+ const pty = yield* Pty.Service;
84
+ yield* pty.get(ctx.params.ptyID).pipe(Effect.catchTag("Pty.NotFoundError", () => new PtyNotFoundError({
85
+ ptyID: ctx.params.ptyID,
86
+ message: `PTY session not found: ${ctx.params.ptyID}`
87
+ })));
88
+ return yield* response2(tickets.issue({ ptyID: ctx.params.ptyID, ...yield* ticketScope }));
89
+ })).handleRaw("pty.connect", Effect.fn("PtyHandler.connect")(function* (ctx) {
90
+ const pty = yield* Pty.Service;
91
+ const exists = yield* pty.get(ctx.params.ptyID).pipe(Effect.as(true), Effect.catchTag("Pty.NotFoundError", () => Effect.succeed(false)));
92
+ if (!exists)
93
+ return HttpServerResponse.empty({ status: 404 });
94
+ const url = new URL(ctx.request.url, "http://localhost");
95
+ const ticket = url.searchParams.get(PTY_CONNECT_TICKET_QUERY);
96
+ if (ticket) {
97
+ const valid = isAllowedRequestOrigin2(ctx.request.headers.origin, ctx.request.headers.host, cors) ? yield* tickets.consume({ ticket, ptyID: ctx.params.ptyID, ...yield* ticketScope }) : false;
98
+ if (!valid)
99
+ return HttpServerResponse.empty({ status: 403 });
100
+ }
101
+ const parsedCursor = url.searchParams.get("cursor");
102
+ const cursorNumber = parsedCursor === null ? undefined : Number(parsedCursor);
103
+ const cursor = cursorNumber !== undefined && Number.isSafeInteger(cursorNumber) && cursorNumber >= -1 ? cursorNumber : undefined;
104
+ const socket = yield* Effect.orDie(ctx.request.upgrade);
105
+ const write = yield* socket.writer;
106
+ const closeAccepted = (event) => socket.runRaw(() => Effect.void, { onOpen: write(event).pipe(Effect.catch(() => Effect.void)) }).pipe(Effect.timeout("1 second"), Effect.catchReason("SocketError", "SocketCloseError", () => Effect.void), Effect.catch(() => Effect.void));
107
+ const outbox = yield* Queue.unbounded();
108
+ const attachment = yield* pty.attach(ctx.params.ptyID, {
109
+ cursor,
110
+ onData: (chunk) => Queue.offerUnsafe(outbox, chunk),
111
+ onEnd: () => Queue.offerUnsafe(outbox, new Socket.CloseEvent(1000))
112
+ }).pipe(Effect.catchTags({
113
+ "Pty.NotFoundError": () => closeAccepted(new Socket.CloseEvent(4404, "session not found")).pipe(Effect.as(undefined)),
114
+ "Pty.ExitedError": () => closeAccepted(new Socket.CloseEvent(4404, "session exited")).pipe(Effect.as(undefined))
115
+ }));
116
+ if (!attachment)
117
+ return HttpServerResponse.empty();
118
+ for (const chunk of PtyProtocol.chunks(attachment.replay))
119
+ Queue.offerUnsafe(outbox, chunk);
120
+ Queue.offerUnsafe(outbox, PtyProtocol.metaFrame(attachment.cursor));
121
+ attachment.activate();
122
+ const drain = Effect.gen(function* () {
123
+ while (true) {
124
+ const item = yield* Queue.take(outbox);
125
+ yield* write(item);
126
+ if (item instanceof Socket.CloseEvent)
127
+ return;
128
+ }
129
+ });
130
+ yield* runPtySocket2(drain, socket.runRaw((message) => {
131
+ const decoded = PtyProtocol.decodeInput(message);
132
+ if (decoded !== undefined)
133
+ attachment.write(decoded);
134
+ }), attachment.detach).pipe(Effect.catchReason("SocketError", "SocketCloseError", () => Effect.void), Effect.orDie);
135
+ return HttpServerResponse.empty();
136
+ }));
137
+ }));
138
+
139
+ export { PtyHandler2 };
@@ -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/reference.ts
9
+ import { Reference } from "@opencode/core/reference";
10
+ import { HttpApiBuilder } from "effect/unstable/httpapi";
11
+ var ReferenceHandler2 = HttpApiBuilder.group(Api2, "server.reference", (handlers) => handlers.handle("reference.list", () => response2(Reference.Service.use((reference) => reference.list()))));
12
+
13
+ export { ReferenceHandler2 };
@@ -0,0 +1,19 @@
1
+ import {
2
+ LocationMiddleware2
3
+ } from "./fetch-6gkz39ey.js";
4
+ import {
5
+ FormLocationMiddleware2
6
+ } from "./fetch-5rwqcaw2.js";
7
+ import {
8
+ SessionLocationMiddleware2
9
+ } from "./fetch-3kzx88w9.js";
10
+
11
+ // src/api.ts
12
+ import { makeDefaultApi } from "@opencode/protocol/api";
13
+ var Api2 = makeDefaultApi({
14
+ locationMiddleware: LocationMiddleware2,
15
+ formLocationMiddleware: FormLocationMiddleware2,
16
+ sessionLocationMiddleware: SessionLocationMiddleware2
17
+ });
18
+
19
+ export { Api2 };
@@ -0,0 +1,15 @@
1
+ import {
2
+ Api2
3
+ } from "./fetch-z5shrcz9.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,30 @@
1
+ import {
2
+ __export
3
+ } from "./fetch-9rqn6x4v.js";
4
+
5
+ // src/auth.ts
6
+ var exports_auth = {};
7
+ __export(exports_auth, {
8
+ Config: () => Config2,
9
+ ServerAuth: () => exports_auth,
10
+ authorized: () => authorized2,
11
+ required: () => required2
12
+ });
13
+ import { Context, Layer, Option, Redacted } from "effect";
14
+
15
+ class Config2 extends Context.Service()("@opencode/ServerAuthConfig") {
16
+ static configLayer(input) {
17
+ return Layer.succeed(this, this.of({ ...input, username: "opencode" }));
18
+ }
19
+ static get layer() {
20
+ return this.configLayer({ password: Option.none() });
21
+ }
22
+ }
23
+ function required2(config) {
24
+ return Option.isSome(config.password) && config.password.value !== "";
25
+ }
26
+ function authorized2(credentials, config) {
27
+ return Option.isSome(config.password) && credentials.username === config.username && Redacted.value(credentials.password) === config.password.value;
28
+ }
29
+
30
+ export { Config2, required2, authorized2, exports_auth };
package/dist/cors.js CHANGED
@@ -1,36 +1,10 @@
1
- import { Context } from "effect";
2
- const opencodeOrigin = /^https:\/\/([a-z0-9-]+\.)*opencode\.ai$/;
3
- export const CorsConfig = Context.Reference("@opencode/ServerCorsConfig", {
4
- defaultValue: () => {
5
- return;
6
- }
7
- });
8
- export function isAllowedCorsOrigin(input, opts) {
9
- if (!input)
10
- return !0;
11
- if (input.startsWith("http://localhost:"))
12
- return !0;
13
- if (input.startsWith("http://127.0.0.1:"))
14
- return !0;
15
- if (input.startsWith("oc://renderer"))
16
- return !0;
17
- if (input === "tauri://localhost" || input === "http://tauri.localhost" || input === "https://tauri.localhost")
18
- return !0;
19
- if (opencodeOrigin.test(input))
20
- return !0;
21
- return opts?.cors?.includes(input) ?? !1;
22
- }
23
- export function isAllowedRequestOrigin(input, host, opts) {
24
- if (!input)
25
- return !0;
26
- if (host && sameHost(input, host))
27
- return !0;
28
- return isAllowedCorsOrigin(input, opts);
29
- }
30
- function sameHost(origin, host) {
31
- try {
32
- return new URL(origin).host === host;
33
- } catch {
34
- return !1;
35
- }
36
- }
1
+ import {
2
+ CorsConfig2,
3
+ isAllowedCorsOrigin2,
4
+ isAllowedRequestOrigin2
5
+ } from "./chunks/fetch-q4bn6dy8.js";
6
+ export {
7
+ CorsConfig2 as CorsConfig,
8
+ isAllowedCorsOrigin2 as isAllowedCorsOrigin,
9
+ isAllowedRequestOrigin2 as isAllowedRequestOrigin
10
+ };