@opencode/server 2.0.8 → 2.0.10

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/auth-0ar9gf7q.js +55 -0
  5. package/dist/chunks/auth-0qzy9yxk.js +163 -0
  6. package/dist/chunks/auth-1wj0ectp.js +22 -0
  7. package/dist/chunks/auth-23w8t84j.js +26 -0
  8. package/dist/chunks/auth-34e6wr3b.js +13 -0
  9. package/dist/chunks/auth-3582t7j8.js +139 -0
  10. package/dist/chunks/auth-40g8rvw4.js +59 -0
  11. package/dist/chunks/auth-5p62ed52.js +36 -0
  12. package/dist/chunks/auth-6aya8ky6.js +39 -0
  13. package/dist/chunks/auth-760vtqy2.js +29 -0
  14. package/dist/chunks/auth-7bj707s9.js +99 -0
  15. package/dist/chunks/auth-7qtja2kq.js +15 -0
  16. package/dist/chunks/auth-8e21y1bd.js +20 -0
  17. package/dist/chunks/auth-8nbs1vvt.js +34 -0
  18. package/dist/chunks/auth-8ygjd1s8.js +40 -0
  19. package/dist/chunks/auth-9rqn6x4v.js +16 -0
  20. package/dist/chunks/auth-b4atwt7w.js +37 -0
  21. package/dist/chunks/auth-bgzrbsek.js +13 -0
  22. package/dist/chunks/auth-bkb1xk38.js +42 -0
  23. package/dist/chunks/auth-bkk2wfbz.js +23 -0
  24. package/dist/chunks/auth-byzd2nk7.js +21 -0
  25. package/dist/chunks/auth-cm8xmqjn.js +13 -0
  26. package/dist/chunks/auth-d2g7egyw.js +25 -0
  27. package/dist/chunks/auth-e09mshwt.js +23 -0
  28. package/dist/chunks/auth-erwrh284.js +156 -0
  29. package/dist/chunks/auth-frv6gfy7.js +33 -0
  30. package/dist/chunks/auth-fyjxk8m3.js +22 -0
  31. package/dist/chunks/auth-gsks0nj8.js +149 -0
  32. package/dist/chunks/auth-hezj1jdf.js +7 -0
  33. package/dist/chunks/auth-kv6ycdgm.js +77 -0
  34. package/dist/chunks/auth-m6wvgbfq.js +60 -0
  35. package/dist/chunks/auth-p5hgn93y.js +26 -0
  36. package/dist/chunks/auth-pd1pbg0v.js +17 -0
  37. package/dist/chunks/auth-q4bn6dy8.js +39 -0
  38. package/dist/chunks/auth-r4dhhtgz.js +346 -0
  39. package/dist/chunks/auth-rjpqaa8h.js +83 -0
  40. package/dist/chunks/auth-smaf4a18.js +28 -0
  41. package/dist/chunks/auth-t8yzmczr.js +18 -0
  42. package/dist/chunks/auth-tk6nqkmh.js +22 -0
  43. package/dist/chunks/auth-txhx6f1m.js +13 -0
  44. package/dist/chunks/auth-vgxn80m1.js +61 -0
  45. package/dist/chunks/auth-xpxp1sqb.js +22 -0
  46. package/dist/chunks/auth-xsrtpxyd.js +23 -0
  47. package/dist/chunks/auth-yc7nft6q.js +5 -0
  48. package/dist/chunks/auth-z3nth2hg.js +35 -0
  49. package/dist/chunks/auth-z6kg9h7e.js +19 -0
  50. package/dist/chunks/auth-zw9j8b8g.js +32 -0
  51. package/dist/chunks/auth-zxvt7wd3.js +25 -0
  52. package/dist/chunks/auth-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,346 @@
1
+ import {
2
+ missingSession2,
3
+ missingMessage2,
4
+ failedMessageDecode2,
5
+ failedSnapshot2
6
+ } from "./auth-smaf4a18.js";
7
+ import {
8
+ Api2
9
+ } from "./auth-z6kg9h7e.js";
10
+
11
+ // src/handlers/session.ts
12
+ import { Session } from "@opencode/core/session";
13
+ import { SessionStats } from "@opencode/core/session/stats";
14
+ import { SessionTitle } from "@opencode/core/session/title";
15
+ import { SessionTransfer } from "@opencode/core/session/transfer";
16
+ import { InstructionEntry } from "@opencode/core/session/instruction-entry";
17
+ import { Form } from "@opencode/core/form";
18
+ import { DateTime, Effect, Stream } from "effect";
19
+ import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
20
+ import { SessionsCursor } from "@opencode/protocol/groups/session";
21
+ import {
22
+ ConflictError,
23
+ CommandExecutionError,
24
+ CommandNotFoundError,
25
+ FormAlreadySettledError,
26
+ FormInvalidAnswerError,
27
+ FormNotFoundError,
28
+ InvalidRequestError,
29
+ InvalidCursorError,
30
+ MessageNotFoundError,
31
+ ServiceUnavailableError,
32
+ SessionBusyError,
33
+ SkillNotFoundError
34
+ } from "@opencode/protocol/errors";
35
+ import { AbsolutePath } from "@opencode/core/schema";
36
+ var DefaultSessionsLimit = 50;
37
+ function missingForm(id) {
38
+ return new FormNotFoundError({ id, message: `Form not found: ${id}` });
39
+ }
40
+ var SessionHandler2 = HttpApiBuilder.group(Api2, "server.session", (handlers) => Effect.gen(function* () {
41
+ const session = yield* Session.Service;
42
+ const transfer = yield* SessionTransfer.Service;
43
+ const requireOwnedForm = Effect.fnUntraced(function* (sessionID, formID) {
44
+ const form = yield* Form.Service;
45
+ const info = yield* form.get(formID).pipe(Effect.catchTag("Form.NotFoundError", () => missingForm(formID)));
46
+ if (info.sessionID !== sessionID)
47
+ return yield* missingForm(formID);
48
+ return { form, info };
49
+ });
50
+ const busySession = (error) => new SessionBusyError({
51
+ sessionID: error.sessionID,
52
+ message: `Session is busy: ${error.sessionID}`
53
+ });
54
+ const pendingMutation = (effect, conflict) => effect.pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.InboxConflictError", (error) => new ConflictError({ resource: error.inboxID, message: `${conflict}: ${error.inboxID}` })), Effect.as(HttpApiSchema.NoContent.make()));
55
+ return handlers.handle("session.list", Effect.fn(function* (ctx) {
56
+ const query = ctx.query.cursor !== undefined ? yield* SessionsCursor.parse(ctx.query.cursor).pipe(Effect.mapError(() => new InvalidCursorError({ message: "Invalid cursor" }))) : ctx.query;
57
+ const page = yield* session.list({
58
+ ...query,
59
+ limit: ctx.query.limit ?? DefaultSessionsLimit
60
+ });
61
+ const sessions = page.data;
62
+ const first = sessions[0];
63
+ const last = sessions.at(-1);
64
+ return {
65
+ data: sessions,
66
+ cursor: {
67
+ previous: first ? SessionsCursor.make({
68
+ ...query,
69
+ anchor: {
70
+ id: first.id,
71
+ time: DateTime.toEpochMillis(first.time.updated),
72
+ direction: "previous"
73
+ }
74
+ }) : undefined,
75
+ next: last ? SessionsCursor.make({
76
+ ...query,
77
+ anchor: {
78
+ id: last.id,
79
+ time: DateTime.toEpochMillis(last.time.updated),
80
+ direction: "next"
81
+ }
82
+ }) : undefined
83
+ }
84
+ };
85
+ })).handle("session.stats", Effect.fn(function* (ctx) {
86
+ const timezone = ctx.query.timezone ?? "UTC";
87
+ yield* Effect.try({
88
+ try: () => new Intl.DateTimeFormat("en-US", { timeZone: timezone }),
89
+ catch: () => new InvalidRequestError({ message: `Invalid time zone: ${timezone}` })
90
+ });
91
+ return {
92
+ data: yield* SessionStats.get({
93
+ from: ctx.query.from,
94
+ to: ctx.query.to,
95
+ projectID: ctx.query.project,
96
+ timezone,
97
+ tools: ctx.query.tools
98
+ }).pipe(Effect.mapError(() => new InvalidRequestError({ message: "Stats range must end after it starts" })))
99
+ };
100
+ })).handle("session.create", Effect.fn(function* (ctx) {
101
+ return {
102
+ data: yield* session.create({
103
+ id: ctx.payload.id,
104
+ title: ctx.payload.title,
105
+ agent: ctx.payload.agent,
106
+ model: ctx.payload.model,
107
+ metadata: ctx.payload.metadata,
108
+ permissions: ctx.payload.permissions,
109
+ location: ctx.payload.location ?? { directory: AbsolutePath.make(process.cwd()) }
110
+ }).pipe(Effect.orDie)
111
+ };
112
+ })).handle("session.import", Effect.fn(function* (ctx) {
113
+ return {
114
+ data: yield* transfer.import({
115
+ data: { info: ctx.payload.info, messages: ctx.payload.messages },
116
+ location: ctx.payload.location ?? { directory: AbsolutePath.make(process.cwd()) }
117
+ }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("SessionTransfer.ImportConflictError", (error) => new ConflictError({
118
+ message: `Session already exists: ${error.sessionID}`,
119
+ resource: error.sessionID
120
+ })))
121
+ };
122
+ })).handle("session.export", Effect.fn(function* (ctx) {
123
+ return {
124
+ data: yield* transfer.export({ sessionID: ctx.params.sessionID, sanitize: ctx.query.sanitize }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.MessageDecodeError", failedMessageDecode2))
125
+ };
126
+ })).handle("session.active", Effect.fn(function* () {
127
+ const active = yield* session.active;
128
+ return {
129
+ data: Object.fromEntries(Array.from(active, (sessionID) => [sessionID, { type: "running" }]))
130
+ };
131
+ })).handle("session.get", Effect.fn(function* (ctx) {
132
+ return {
133
+ data: yield* session.get(ctx.params.sessionID).pipe(Effect.catchTag("Session.NotFoundError", missingSession2))
134
+ };
135
+ })).handle("session.view", Effect.fn(function* (ctx) {
136
+ yield* session.view({ sessionID: ctx.params.sessionID, idle: DateTime.toEpochMillis(ctx.payload.idle) }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
137
+ return HttpApiSchema.NoContent.make();
138
+ })).handle("session.remove", Effect.fn(function* (ctx) {
139
+ yield* session.remove(ctx.params.sessionID).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
140
+ return HttpApiSchema.NoContent.make();
141
+ })).handle("session.environment", Effect.fn(function* (ctx) {
142
+ yield* session.environment({ sessionID: ctx.params.sessionID, variables: ctx.payload.variables }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
143
+ return HttpApiSchema.NoContent.make();
144
+ })).handle("session.fork", Effect.fn(function* (ctx) {
145
+ return {
146
+ data: yield* session.fork({ sessionID: ctx.params.sessionID, before: ctx.payload.before }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.MessageNotFoundError", missingMessage2), Effect.catchTag("Session.ForkEmptyError", (error) => new InvalidRequestError({ message: error.message, kind: "empty_session" })))
147
+ };
148
+ })).handle("session.switchAgent", Effect.fn(function* (ctx) {
149
+ yield* session.switchAgent({ sessionID: ctx.params.sessionID, agent: ctx.payload.agent }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
150
+ return HttpApiSchema.NoContent.make();
151
+ })).handle("session.switchModel", Effect.fn(function* (ctx) {
152
+ yield* session.switchModel({ sessionID: ctx.params.sessionID, model: ctx.payload.model }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
153
+ return HttpApiSchema.NoContent.make();
154
+ })).handle("session.update", Effect.fn(function* (ctx) {
155
+ yield* session.get(ctx.params.sessionID).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
156
+ if (ctx.payload.title !== undefined) {
157
+ if (ctx.payload.title) {
158
+ yield* session.rename({ sessionID: ctx.params.sessionID, title: ctx.payload.title }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
159
+ } else {
160
+ const title = yield* SessionTitle.Service;
161
+ yield* title.generate(ctx.params.sessionID);
162
+ }
163
+ }
164
+ if (ctx.payload.permissions !== undefined)
165
+ yield* session.setPermissions({ sessionID: ctx.params.sessionID, permissions: ctx.payload.permissions }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
166
+ return HttpApiSchema.NoContent.make();
167
+ })).handle("session.move", Effect.fn(function* (ctx) {
168
+ yield* session.move({
169
+ sessionID: ctx.params.sessionID,
170
+ directory: ctx.payload.directory,
171
+ delivery: ctx.payload.delivery
172
+ }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.DestinationNotFoundError", (error) => Effect.fail(new InvalidRequestError({ message: `Directory does not exist: ${error.directory}` }))), Effect.catchTag("Session.DestinationNotDirectoryError", (error) => Effect.fail(new InvalidRequestError({ message: `Not a directory: ${error.directory}` }))), Effect.catchTag("Session.DestinationUnavailableError", (error) => Effect.fail(new InvalidRequestError({ message: `Directory is unavailable: ${error.directory}` }))));
173
+ return HttpApiSchema.NoContent.make();
174
+ })).handle("session.prompt", Effect.fn(function* (ctx) {
175
+ return {
176
+ data: yield* session.prompt({
177
+ sessionID: ctx.params.sessionID,
178
+ id: ctx.payload.id,
179
+ text: ctx.payload.text,
180
+ files: ctx.payload.files,
181
+ agents: ctx.payload.agents,
182
+ skills: ctx.payload.skills,
183
+ metadata: ctx.payload.metadata,
184
+ delivery: ctx.payload.delivery,
185
+ resume: ctx.payload.resume
186
+ }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.PromptConflictError", (error) => Effect.fail(new ConflictError({
187
+ message: `Prompt message ID conflicts with an existing durable record: ${error.messageID}`,
188
+ resource: error.messageID
189
+ }))), Effect.catchTag("Session.AttachmentError", (error) => Effect.fail(new InvalidRequestError({ message: error.message, field: "files" }))), Effect.catchTag("Session.SkillNotFoundError", (error) => Effect.fail(new InvalidRequestError({ message: `Skill not found: ${error.skill}`, field: "skills" }))))
190
+ };
191
+ })).handle("session.command", Effect.fn(function* (ctx) {
192
+ yield* session.command({
193
+ sessionID: ctx.params.sessionID,
194
+ command: ctx.payload.name,
195
+ text: ctx.payload.text,
196
+ files: ctx.payload.files,
197
+ agents: ctx.payload.agents,
198
+ skills: ctx.payload.skills,
199
+ delivery: ctx.payload.delivery
200
+ }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Command.NotFoundError", (error) => Effect.fail(new CommandNotFoundError({
201
+ command: error.command,
202
+ message: error.message
203
+ }))), Effect.catchTag("Command.ExecutionError", (error) => Effect.fail(new CommandExecutionError({
204
+ command: error.command,
205
+ message: error.message
206
+ }))));
207
+ return HttpApiSchema.NoContent.make();
208
+ })).handle("session.skill", Effect.fn(function* (ctx) {
209
+ yield* session.skill({
210
+ sessionID: ctx.params.sessionID,
211
+ skill: ctx.payload.id,
212
+ resume: ctx.payload.resume
213
+ }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.SkillNotFoundError", (error) => Effect.fail(new SkillNotFoundError({ skill: error.skill, message: `Skill not found: ${error.skill}` }))));
214
+ return HttpApiSchema.NoContent.make();
215
+ })).handle("session.synthetic", Effect.fn(function* (ctx) {
216
+ const data = yield* session.synthetic({
217
+ id: ctx.payload.id,
218
+ sessionID: ctx.params.sessionID,
219
+ text: ctx.payload.text,
220
+ description: ctx.payload.description,
221
+ metadata: ctx.payload.metadata,
222
+ delivery: ctx.payload.delivery,
223
+ resume: ctx.payload.resume
224
+ }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.SyntheticConflictError", (error) => Effect.fail(new ConflictError({
225
+ message: `Synthetic input ID conflicts with an existing durable record: ${error.inputID}`,
226
+ resource: error.inputID
227
+ }))));
228
+ return { data };
229
+ })).handle("session.shell", Effect.fn(function* (ctx) {
230
+ yield* session.shell({ sessionID: ctx.params.sessionID, id: ctx.payload.id, command: ctx.payload.command }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
231
+ return HttpApiSchema.NoContent.make();
232
+ })).handle("session.compact", Effect.fn(function* (ctx) {
233
+ return {
234
+ data: yield* session.compact({ sessionID: ctx.params.sessionID, id: ctx.payload.id, delivery: ctx.payload.delivery }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.CompactionConflictError", (error) => Effect.fail(new ConflictError({
235
+ message: `Compaction input ID conflicts with an existing durable record: ${error.inputID}`,
236
+ resource: error.inputID
237
+ }))))
238
+ };
239
+ })).handle("session.wait", Effect.fn(function* (ctx) {
240
+ yield* session.wait(ctx.params.sessionID).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
241
+ return HttpApiSchema.NoContent.make();
242
+ })).handle("session.revert.stage", Effect.fn(function* (ctx) {
243
+ yield* Effect.log("session.revert.stage", {
244
+ sessionID: ctx.params.sessionID,
245
+ messageID: ctx.payload.messageID,
246
+ files: ctx.payload.files
247
+ });
248
+ return {
249
+ data: yield* session.revert.stage({ ...ctx.params, ...ctx.payload }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.MessageNotFoundError", missingMessage2), Effect.catchTag("Session.BusyError", busySession), Effect.catchTag("Snapshot.Error", failedSnapshot2("stage session revert", ctx.params.sessionID)))
250
+ };
251
+ })).handle("session.revert.clear", Effect.fn(function* (ctx) {
252
+ yield* Effect.log("session.revert.clear", { sessionID: ctx.params.sessionID });
253
+ yield* session.revert.clear(ctx.params.sessionID).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.BusyError", busySession), Effect.catchTag("Snapshot.Error", failedSnapshot2("clear session revert", ctx.params.sessionID)));
254
+ return HttpApiSchema.NoContent.make();
255
+ })).handle("session.revert.commit", Effect.fn(function* (ctx) {
256
+ yield* Effect.log("session.revert.commit", { sessionID: ctx.params.sessionID });
257
+ yield* session.revert.commit(ctx.params.sessionID).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.BusyError", busySession));
258
+ return HttpApiSchema.NoContent.make();
259
+ })).handle("session.context", Effect.fn(function* (ctx) {
260
+ return {
261
+ data: yield* session.context(ctx.params.sessionID).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.MessageDecodeError", failedMessageDecode2))
262
+ };
263
+ })).handle("session.diff", Effect.fn(function* (ctx) {
264
+ return {
265
+ data: yield* session.diff({ sessionID: ctx.params.sessionID, ...ctx.query }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.MessageNotFoundError", missingMessage2), Effect.catchTag("Session.TurnRangeError", (error) => new InvalidRequestError({ message: error.message, field: error.field })), Effect.catchTag("Snapshot.Error", failedSnapshot2("diff session turn", ctx.params.sessionID)))
266
+ };
267
+ })).handle("session.inbox.list", Effect.fn(function* (ctx) {
268
+ return {
269
+ data: yield* session.inbox(ctx.params.sessionID).pipe(Effect.catchTag("Session.NotFoundError", missingSession2))
270
+ };
271
+ })).handle("session.inbox.cancel", Effect.fn(function* (ctx) {
272
+ yield* session.cancelInbox({ sessionID: ctx.params.sessionID, inboxID: ctx.params.inboxID }).pipe(Effect.catchTag("Session.NotFoundError", missingSession2), Effect.catchTag("Session.InboxConflictError", () => Effect.void));
273
+ return HttpApiSchema.NoContent.make();
274
+ })).handle("session.inbox.update", Effect.fn(function* (ctx) {
275
+ return yield* pendingMutation(ctx.payload.delivery === "steer" ? session.steerInbox({ sessionID: ctx.params.sessionID, inboxID: ctx.params.inboxID }) : session.queueInbox({ sessionID: ctx.params.sessionID, inboxID: ctx.params.inboxID }), `Pending input cannot change to ${ctx.payload.delivery}`);
276
+ })).handle("session.instructions.entry.list", Effect.fn(function* (ctx) {
277
+ const instructions = yield* InstructionEntry.Service;
278
+ return { data: yield* instructions.list(ctx.params.sessionID) };
279
+ })).handle("session.instructions.entry.put", Effect.fn(function* (ctx) {
280
+ const instructions = yield* InstructionEntry.Service;
281
+ yield* instructions.put({ sessionID: ctx.params.sessionID, key: ctx.params.key, value: ctx.payload.value });
282
+ return HttpApiSchema.NoContent.make();
283
+ })).handle("session.instructions.entry.remove", Effect.fn(function* (ctx) {
284
+ const instructions = yield* InstructionEntry.Service;
285
+ yield* instructions.remove({ sessionID: ctx.params.sessionID, key: ctx.params.key });
286
+ return HttpApiSchema.NoContent.make();
287
+ })).handle("session.generate", Effect.fn(function* (ctx) {
288
+ const text = yield* session.generate({ sessionID: ctx.params.sessionID, prompt: ctx.payload.prompt }).pipe(Effect.mapError((error) => error._tag === "Session.NotFoundError" ? missingSession2(error) : new ServiceUnavailableError({ message: error.message, service: "session generation" })));
289
+ return { data: { text } };
290
+ })).handle("session.log", Effect.fn(function* (ctx) {
291
+ yield* session.get(ctx.params.sessionID).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
292
+ return session.log({ sessionID: ctx.params.sessionID, after: ctx.query.after, follow: ctx.query.follow }).pipe(Stream.orDie);
293
+ })).handle("session.interrupt", Effect.fn(function* (ctx) {
294
+ return { interrupted: yield* session.interrupt(ctx.params.sessionID, { resume: ctx.query.resume }) };
295
+ })).handle("session.background", Effect.fn(function* (ctx) {
296
+ yield* session.background(ctx.params.sessionID).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
297
+ return HttpApiSchema.NoContent.make();
298
+ })).handle("session.message", Effect.fn(function* (ctx) {
299
+ yield* session.get(ctx.params.sessionID).pipe(Effect.catchTag("Session.NotFoundError", missingSession2));
300
+ const message = yield* session.message(ctx.params);
301
+ if (message)
302
+ return { data: message };
303
+ return yield* new MessageNotFoundError({
304
+ sessionID: ctx.params.sessionID,
305
+ messageID: ctx.params.messageID,
306
+ message: `Message not found: ${ctx.params.messageID}`
307
+ });
308
+ })).handle("session.form.list", Effect.fn(function* (ctx) {
309
+ const form = yield* Form.Service;
310
+ return { data: yield* form.list({ sessionID: ctx.params.sessionID }) };
311
+ })).handle("session.form.create", Effect.fn(function* (ctx) {
312
+ const form = yield* Form.Service;
313
+ const created = yield* form.create({
314
+ id: ctx.payload.id,
315
+ sessionID: ctx.params.sessionID,
316
+ title: ctx.payload.title,
317
+ metadata: ctx.payload.metadata,
318
+ fields: ctx.payload.fields
319
+ }).pipe(Effect.catchTags({
320
+ "Form.AlreadyExistsError": (error) => new ConflictError({ resource: error.id, message: error.message }),
321
+ "Form.InvalidFormError": (error) => new InvalidRequestError({ message: error.message, field: "fields" })
322
+ }));
323
+ return { data: created };
324
+ })).handle("session.form.get", Effect.fn(function* (ctx) {
325
+ const owned = yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID);
326
+ const state = yield* owned.form.state(ctx.params.formID).pipe(Effect.catchTag("Form.NotFoundError", () => missingForm(ctx.params.formID)));
327
+ return { data: { ...owned.info, state } };
328
+ })).handle("session.form.reply", Effect.fn(function* (ctx) {
329
+ const owned = yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID);
330
+ yield* owned.form.reply({ id: ctx.params.formID, answer: ctx.payload.answer }).pipe(Effect.catchTags({
331
+ "Form.AlreadySettledError": (error) => new FormAlreadySettledError({ id: error.id, message: error.message }),
332
+ "Form.InvalidAnswerError": (error) => new FormInvalidAnswerError({ id: error.id, message: error.message }),
333
+ "Form.NotFoundError": () => missingForm(ctx.params.formID)
334
+ }));
335
+ return HttpApiSchema.NoContent.make();
336
+ })).handle("session.form.cancel", Effect.fn(function* (ctx) {
337
+ const owned = yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID);
338
+ yield* owned.form.cancel(ctx.params.formID).pipe(Effect.catchTags({
339
+ "Form.AlreadySettledError": (error) => new FormAlreadySettledError({ id: error.id, message: error.message }),
340
+ "Form.NotFoundError": () => missingForm(ctx.params.formID)
341
+ }));
342
+ return HttpApiSchema.NoContent.make();
343
+ }));
344
+ }));
345
+
346
+ export { SessionHandler2 };
@@ -0,0 +1,83 @@
1
+ import {
2
+ __export
3
+ } from "./auth-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: () => layer3,
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 layer3 = 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, layer3, exports_event_feed };
@@ -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,22 @@
1
+ import {
2
+ Api2
3
+ } from "./auth-z6kg9h7e.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,13 @@
1
+ import {
2
+ Api2
3
+ } from "./auth-z6kg9h7e.js";
4
+
5
+ // src/handlers/migration.ts
6
+ import { V1Migration } from "@opencode/core/database/v1-migration";
7
+ import { HttpApiBuilder } from "effect/unstable/httpapi";
8
+ import { Effect } from "effect";
9
+ var MigrationHandler2 = HttpApiBuilder.group(Api2, "server.migration", (handlers) => handlers.handle("migration.v1.status", Effect.fn(function* () {
10
+ return yield* V1Migration.status();
11
+ })));
12
+
13
+ export { MigrationHandler2 };
@@ -0,0 +1,61 @@
1
+ import {
2
+ response2
3
+ } from "./auth-0ar9gf7q.js";
4
+ import {
5
+ Api2
6
+ } from "./auth-z6kg9h7e.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,22 @@
1
+ import {
2
+ Api2
3
+ } from "./auth-z6kg9h7e.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,23 @@
1
+ import {
2
+ __export
3
+ } from "./auth-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 };