@opencode/server 2.0.2 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.d.ts CHANGED
@@ -145,7 +145,7 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
145
145
  };
146
146
  readonly created: import("effect/Schema").Finite;
147
147
  readonly metadata: import("effect/Schema").decodeTo<import("effect/Schema").optional<import("effect/Schema").toType<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Unknown>>>, import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Unknown>>, never, never>;
148
- readonly type: import("effect/Schema").Literal<"catalog.updated">;
148
+ readonly type: import("effect/Schema").Literal<"provider.updated">;
149
149
  readonly location: import("effect/Schema").decodeTo<import("effect/Schema").optional<import("effect/Schema").toType<import("effect/Schema").Struct<{
150
150
  readonly directory: import("effect/Schema").brand<import("effect/Schema").String, "AbsolutePath">;
151
151
  readonly workspaceID: import("effect/Schema").decodeTo<import("effect/Schema").optional<import("effect/Schema").toType<import("effect/Schema").brand<import("effect/Schema").String, "Workspace.ID"> & {
@@ -167,7 +167,39 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
167
167
  }>>, never, never>;
168
168
  readonly data: import("effect/Schema").Struct<{}>;
169
169
  }> & {
170
- type: "catalog.updated";
170
+ type: "provider.updated";
171
+ durability: "ephemeral";
172
+ durable: undefined;
173
+ data: import("effect/Schema").Struct<{}>;
174
+ }, import("effect/Schema").Struct<{
175
+ readonly id: import("effect/Schema").brand<import("effect/Schema").String, "Event.ID"> & {
176
+ create: () => string & import("effect/Brand").Brand<"Event.ID">;
177
+ };
178
+ readonly created: import("effect/Schema").Finite;
179
+ readonly metadata: import("effect/Schema").decodeTo<import("effect/Schema").optional<import("effect/Schema").toType<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Unknown>>>, import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Unknown>>, never, never>;
180
+ readonly type: import("effect/Schema").Literal<"model.updated">;
181
+ readonly location: import("effect/Schema").decodeTo<import("effect/Schema").optional<import("effect/Schema").toType<import("effect/Schema").Struct<{
182
+ readonly directory: import("effect/Schema").brand<import("effect/Schema").String, "AbsolutePath">;
183
+ readonly workspaceID: import("effect/Schema").decodeTo<import("effect/Schema").optional<import("effect/Schema").toType<import("effect/Schema").brand<import("effect/Schema").String, "Workspace.ID"> & {
184
+ ascending: (id?: string) => string & import("effect/Brand").Brand<"Workspace.ID">;
185
+ create: () => string & import("effect/Brand").Brand<"Workspace.ID">;
186
+ }>>, import("effect/Schema").optionalKey<import("effect/Schema").brand<import("effect/Schema").String, "Workspace.ID"> & {
187
+ ascending: (id?: string) => string & import("effect/Brand").Brand<"Workspace.ID">;
188
+ create: () => string & import("effect/Brand").Brand<"Workspace.ID">;
189
+ }>, never, never>;
190
+ }>>>, import("effect/Schema").optionalKey<import("effect/Schema").Struct<{
191
+ readonly directory: import("effect/Schema").brand<import("effect/Schema").String, "AbsolutePath">;
192
+ readonly workspaceID: import("effect/Schema").decodeTo<import("effect/Schema").optional<import("effect/Schema").toType<import("effect/Schema").brand<import("effect/Schema").String, "Workspace.ID"> & {
193
+ ascending: (id?: string) => string & import("effect/Brand").Brand<"Workspace.ID">;
194
+ create: () => string & import("effect/Brand").Brand<"Workspace.ID">;
195
+ }>>, import("effect/Schema").optionalKey<import("effect/Schema").brand<import("effect/Schema").String, "Workspace.ID"> & {
196
+ ascending: (id?: string) => string & import("effect/Brand").Brand<"Workspace.ID">;
197
+ create: () => string & import("effect/Brand").Brand<"Workspace.ID">;
198
+ }>, never, never>;
199
+ }>>, never, never>;
200
+ readonly data: import("effect/Schema").Struct<{}>;
201
+ }> & {
202
+ type: "model.updated";
171
203
  durability: "ephemeral";
172
204
  durable: undefined;
173
205
  data: import("effect/Schema").Struct<{}>;
@@ -789,7 +821,7 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
789
821
  };
790
822
  readonly created: import("effect/Schema").Finite;
791
823
  readonly metadata: import("effect/Schema").decodeTo<import("effect/Schema").optional<import("effect/Schema").toType<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Unknown>>>, import("effect/Schema").optionalKey<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Unknown>>, never, never>;
792
- readonly type: import("effect/Schema").Literal<"session.permissions.updated">;
824
+ readonly type: import("effect/Schema").Literal<"session.permissions">;
793
825
  readonly durable: import("effect/Schema").Struct<{
794
826
  readonly aggregateID: import("effect/Schema").String;
795
827
  readonly seq: import("effect/Schema").brand<import("effect/Schema").Int, "Event.Seq">;
@@ -826,7 +858,7 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
826
858
  };
827
859
  }>;
828
860
  }> & {
829
- type: "session.permissions.updated";
861
+ type: "session.permissions";
830
862
  durability: "durable";
831
863
  durable: {
832
864
  readonly version: number;
@@ -4541,7 +4573,6 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
4541
4573
  readonly time: import("effect/Schema").Struct<{
4542
4574
  readonly created: import("effect/Schema").Int;
4543
4575
  readonly updated: import("effect/Schema").Int;
4544
- readonly initialized: import("effect/Schema").decodeTo<import("effect/Schema").optional<import("effect/Schema").toType<import("effect/Schema").Int>>, import("effect/Schema").optionalKey<import("effect/Schema").Int>, never, never>;
4545
4576
  }>;
4546
4577
  readonly sandboxes: import("effect/Schema").$Array<import("effect/Schema").String>;
4547
4578
  }>;
@@ -4573,7 +4604,6 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
4573
4604
  readonly time: import("effect/Schema").Struct<{
4574
4605
  readonly created: import("effect/Schema").Int;
4575
4606
  readonly updated: import("effect/Schema").Int;
4576
- readonly initialized: import("effect/Schema").decodeTo<import("effect/Schema").optional<import("effect/Schema").toType<import("effect/Schema").Int>>, import("effect/Schema").optionalKey<import("effect/Schema").Int>, never, never>;
4577
4607
  }>;
4578
4608
  readonly sandboxes: import("effect/Schema").$Array<import("effect/Schema").String>;
4579
4609
  }>;
@@ -6156,13 +6186,6 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
6156
6186
  readonly type: import("effect/Schema").TemplateLiteral<readonly ["rpc.", import("effect/Schema").String]>;
6157
6187
  readonly location: import("effect/Schema").Struct<{
6158
6188
  readonly directory: import("effect/Schema").brand<import("effect/Schema").String, "AbsolutePath">;
6159
- readonly workspaceID: import("effect/Schema").decodeTo<import("effect/Schema").optional<import("effect/Schema").toType<import("effect/Schema").brand<import("effect/Schema").String, "Workspace.ID"> & {
6160
- ascending: (id?: string) => string & import("effect/Brand").Brand<"Workspace.ID">;
6161
- create: () => string & import("effect/Brand").Brand<"Workspace.ID">;
6162
- }>>, import("effect/Schema").optionalKey<import("effect/Schema").brand<import("effect/Schema").String, "Workspace.ID"> & {
6163
- ascending: (id?: string) => string & import("effect/Brand").Brand<"Workspace.ID">;
6164
- create: () => string & import("effect/Brand").Brand<"Workspace.ID">;
6165
- }>, never, never>;
6166
6189
  }>;
6167
6190
  readonly data: import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Unknown>;
6168
6191
  }>, ...import("effect/Schema").Struct<{
@@ -6174,13 +6197,6 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
6174
6197
  readonly metadata: import("effect/Schema").optional<import("effect/Schema").$Record<import("effect/Schema").String, import("effect/Schema").Unknown>>;
6175
6198
  readonly location: import("effect/Schema").optional<import("effect/Schema").Struct<{
6176
6199
  readonly directory: import("effect/Schema").brand<import("effect/Schema").String, "AbsolutePath">;
6177
- readonly workspaceID: import("effect/Schema").decodeTo<import("effect/Schema").optional<import("effect/Schema").toType<import("effect/Schema").brand<import("effect/Schema").String, "Workspace.ID"> & {
6178
- ascending: (id?: string) => string & import("effect/Brand").Brand<"Workspace.ID">;
6179
- create: () => string & import("effect/Brand").Brand<"Workspace.ID">;
6180
- }>>, import("effect/Schema").optionalKey<import("effect/Schema").brand<import("effect/Schema").String, "Workspace.ID"> & {
6181
- ascending: (id?: string) => string & import("effect/Brand").Brand<"Workspace.ID">;
6182
- create: () => string & import("effect/Brand").Brand<"Workspace.ID">;
6183
- }>, never, never>;
6184
6200
  }>>;
6185
6201
  }>[]]>>, import("effect/Schema").Never, {
6186
6202
  readonly id: string & import("effect/Brand").Brand<"Event.ID">;
@@ -6199,8 +6215,6 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
6199
6215
  readonly data: {
6200
6216
  readonly form: {
6201
6217
  readonly id: string & import("effect/Brand").Brand<"Form.ID">;
6202
- readonly sessionID: string;
6203
- readonly title: string;
6204
6218
  readonly fields: readonly [{
6205
6219
  readonly type: "string";
6206
6220
  readonly key: string;
@@ -6380,6 +6394,8 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
6380
6394
  readonly description?: string | undefined;
6381
6395
  readonly title?: string | undefined;
6382
6396
  })[]];
6397
+ readonly sessionID: string;
6398
+ readonly title: string;
6383
6399
  readonly metadata?: {
6384
6400
  readonly [x: string]: unknown;
6385
6401
  } | undefined;
@@ -6466,6 +6482,30 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
6466
6482
  readonly metadata?: {
6467
6483
  readonly [x: string]: unknown;
6468
6484
  } | undefined;
6485
+ } | {
6486
+ readonly id: string & import("effect/Brand").Brand<"Event.ID">;
6487
+ readonly data: {};
6488
+ readonly type: "provider.updated";
6489
+ readonly created: number;
6490
+ readonly location?: {
6491
+ readonly directory: string & import("effect/Brand").Brand<"AbsolutePath">;
6492
+ readonly workspaceID?: (string & import("effect/Brand").Brand<"Workspace.ID">) | undefined;
6493
+ } | undefined;
6494
+ readonly metadata?: {
6495
+ readonly [x: string]: unknown;
6496
+ } | undefined;
6497
+ } | {
6498
+ readonly id: string & import("effect/Brand").Brand<"Event.ID">;
6499
+ readonly data: {};
6500
+ readonly type: "model.updated";
6501
+ readonly created: number;
6502
+ readonly location?: {
6503
+ readonly directory: string & import("effect/Brand").Brand<"AbsolutePath">;
6504
+ readonly workspaceID?: (string & import("effect/Brand").Brand<"Workspace.ID">) | undefined;
6505
+ } | undefined;
6506
+ readonly metadata?: {
6507
+ readonly [x: string]: unknown;
6508
+ } | undefined;
6469
6509
  } | {
6470
6510
  readonly id: string & import("effect/Brand").Brand<"Event.ID">;
6471
6511
  readonly data: {
@@ -6529,7 +6569,6 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
6529
6569
  readonly time: {
6530
6570
  readonly created: number;
6531
6571
  readonly updated: number;
6532
- readonly initialized?: number | undefined;
6533
6572
  };
6534
6573
  readonly sandboxes: readonly string[];
6535
6574
  readonly name?: string | undefined;
@@ -6765,7 +6804,7 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
6765
6804
  readonly seq: number & import("effect/Brand").Brand<"Event.Seq">;
6766
6805
  readonly version: number & import("effect/Brand").Brand<"Event.Version">;
6767
6806
  };
6768
- readonly type: "session.permissions.updated";
6807
+ readonly type: "session.permissions";
6769
6808
  readonly created: number;
6770
6809
  readonly location?: {
6771
6810
  readonly directory: string & import("effect/Brand").Brand<"AbsolutePath">;
@@ -7959,18 +7998,6 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
7959
7998
  readonly metadata?: {
7960
7999
  readonly [x: string]: unknown;
7961
8000
  } | undefined;
7962
- } | {
7963
- readonly id: string & import("effect/Brand").Brand<"Event.ID">;
7964
- readonly data: {};
7965
- readonly type: "catalog.updated";
7966
- readonly created: number;
7967
- readonly location?: {
7968
- readonly directory: string & import("effect/Brand").Brand<"AbsolutePath">;
7969
- readonly workspaceID?: (string & import("effect/Brand").Brand<"Workspace.ID">) | undefined;
7970
- } | undefined;
7971
- readonly metadata?: {
7972
- readonly [x: string]: unknown;
7973
- } | undefined;
7974
8001
  } | {
7975
8002
  readonly id: string & import("effect/Brand").Brand<"Event.ID">;
7976
8003
  readonly data: {};
@@ -8370,7 +8397,6 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
8370
8397
  readonly id: string & import("effect/Brand").Brand<"Event.ID">;
8371
8398
  readonly location: {
8372
8399
  readonly directory: string & import("effect/Brand").Brand<"AbsolutePath">;
8373
- readonly workspaceID?: (string & import("effect/Brand").Brand<"Workspace.ID">) | undefined;
8374
8400
  };
8375
8401
  readonly data: {
8376
8402
  readonly [x: string]: unknown;
@@ -8386,7 +8412,6 @@ export declare const Api: import("@opencode/protocol/api").Api<LocationMiddlewar
8386
8412
  readonly type: "server.connected";
8387
8413
  readonly location?: {
8388
8414
  readonly directory: string & import("effect/Brand").Brand<"AbsolutePath">;
8389
- readonly workspaceID?: (string & import("effect/Brand").Brand<"Workspace.ID">) | undefined;
8390
8415
  } | undefined;
8391
8416
  readonly metadata?: {
8392
8417
  readonly [x: string]: unknown;
@@ -3,16 +3,11 @@ import { ShellSelect } from "@opencode/core/shell/select";
3
3
  import { Effect } from "effect";
4
4
  import { HttpApiBuilder } from "effect/unstable/httpapi";
5
5
  import { Api } from "../api";
6
- export const ConfigHandler = HttpApiBuilder.group(Api, "server.config", (handlers) => handlers.handle("config.get", () => Config.Service.use((config) => config.entries())).handle("config.preferences", Effect.fn(function* () {
6
+ export const ConfigHandler = HttpApiBuilder.group(Api, "server.config", (handlers) => handlers.handle("config.get", () => Config.Service.use((config) => config.entries())).handle("config.update", Effect.fn(function* (ctx) {
7
7
  const config = yield* Config.Service;
8
- if (!config.preferences)
9
- return yield* Effect.die(Error("Config preferences are unavailable"));
10
- return yield* config.preferences().pipe(Effect.orDie);
11
- })).handle("config.updatePreferences", Effect.fn(function* (ctx) {
12
- const config = yield* Config.Service;
13
- if (!config.updatePreferences)
14
- return yield* Effect.die(Error("Config preference updates are unavailable"));
15
- return yield* config.updatePreferences(ctx.payload).pipe(Effect.orDie);
8
+ if (!config.update)
9
+ return yield* Effect.die(Error("Config updates are unavailable"));
10
+ return yield* config.update(ctx.payload).pipe(Effect.orDie);
16
11
  })).handle("config.shells", Effect.fn(function* () {
17
12
  const shell = yield* ShellSelect.Service;
18
13
  if (!shell.list)
@@ -1 +1,2 @@
1
- export declare const CredentialHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.credential">, never, import("@opencode/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware>;
1
+ import { Credential } from "@opencode/core/credential";
2
+ export declare const CredentialHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.credential">, never, import("@opencode/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode/protocol/middleware/authorization").Authorization | import("effect/unstable/http/HttpRouter").Request<"Requires", Credential.Service>>;
@@ -1,14 +1,14 @@
1
- import { Integration } from "@opencode/core/integration";
1
+ import { Credential } from "@opencode/core/credential";
2
2
  import { Effect } from "effect";
3
3
  import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
4
4
  import { Api } from "../api";
5
5
  export const CredentialHandler = HttpApiBuilder.group(Api, "server.credential", (handlers) => handlers.handle("credential.update", Effect.fn(function* (ctx) {
6
- yield* (yield* Integration.Service).connection.update(ctx.params.credentialID, { label: ctx.payload.label });
6
+ yield* (yield* Credential.Service).update(ctx.params.credentialID, { label: ctx.payload.label });
7
7
  return HttpApiSchema.NoContent.make();
8
8
  })).handle("credential.activate", Effect.fn(function* (ctx) {
9
- yield* (yield* Integration.Service).connection.activate(ctx.params.credentialID);
9
+ yield* (yield* Credential.Service).activate(ctx.params.credentialID);
10
10
  return HttpApiSchema.NoContent.make();
11
11
  })).handle("credential.remove", Effect.fn(function* (ctx) {
12
- yield* (yield* Integration.Service).connection.remove(ctx.params.credentialID);
12
+ yield* (yield* Credential.Service).remove(ctx.params.credentialID);
13
13
  return HttpApiSchema.NoContent.make();
14
14
  })));
@@ -1,4 +1 @@
1
- import { Instance } from "@opencode/core/instance/service";
2
- import { LocationServiceMap } from "@opencode/core/location-services";
3
- import { Session } from "@opencode/core/session";
4
- export declare const FormHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.form">, never, LocationServiceMap.Service | Session.Service | Instance.Service | import("../location").LocationMiddleware | (import("@opencode/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode/protocol/middleware/authorization").Authorization | import("../middleware/form-location").FormLocationMiddleware)>;
1
+ export declare const FormHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.form">, never, import("@opencode/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware>;
@@ -1,61 +1,9 @@
1
1
  import { Form } from "@opencode/core/form";
2
- import { Instance } from "@opencode/core/instance/service";
3
- import { LocationServiceMap } from "@opencode/core/location-services";
4
- import { Session } from "@opencode/core/session";
5
- import {
6
- ConflictError,
7
- FormAlreadySettledError,
8
- FormInvalidAnswerError,
9
- FormNotFoundError,
10
- InvalidRequestError
11
- } from "@opencode/protocol/errors";
12
2
  import { Effect } from "effect";
13
- import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
3
+ import { HttpApiBuilder } from "effect/unstable/httpapi";
14
4
  import { Api } from "../api";
15
- import { requestRef, response, sessionInfo } from "../location";
16
- function missingForm(id) {
17
- return new FormNotFoundError({ id, message: `Form not found: ${id}` });
18
- }
19
- export const FormHandler = HttpApiBuilder.group(Api, "server.form", (handlers) => Effect.gen(function* () {
20
- const locations = yield* LocationServiceMap.Service, instances = yield* Instance.Service, sessions = yield* Session.Service, requireOwnedForm = Effect.fnUntraced(function* (sessionID, formID) {
21
- const form = yield* Form.Service, info = yield* form.get(formID).pipe(Effect.catchTag("Form.NotFoundError", () => missingForm(formID)));
22
- if (info.sessionID !== sessionID)
23
- return yield* missingForm(formID);
24
- return { form, info };
25
- });
26
- return handlers.handle("form.request.list", Effect.fn(function* () {
27
- const form = yield* Form.Service;
28
- return yield* response(form.list());
29
- })).handle("session.form.list", Effect.fn(function* (ctx) {
30
- const session = ctx.params.sessionID === "global" ? void 0 : yield* sessionInfo(sessions, ctx.params.sessionID), read = Form.Service.use((form) => form.list({ sessionID: ctx.params.sessionID }));
31
- return { data: yield* session ? read.pipe(instances.provide(session)) : read.pipe(Effect.provide(locations.get(requestRef(ctx.request)))) };
32
- })).handle("session.form.create", Effect.fn(function* (ctx) {
33
- return { data: yield* (yield* Form.Service).create({
34
- id: ctx.payload.id,
35
- sessionID: ctx.params.sessionID,
36
- title: ctx.payload.title,
37
- metadata: ctx.payload.metadata,
38
- fields: ctx.payload.fields
39
- }).pipe(Effect.catchTags({
40
- "Form.AlreadyExistsError": (error) => new ConflictError({ resource: error.id, message: error.message }),
41
- "Form.InvalidFormError": (error) => new InvalidRequestError({ message: error.message, field: "fields" })
42
- })) };
43
- })).handle("session.form.get", Effect.fn(function* (ctx) {
44
- return { data: (yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID)).info };
45
- })).handle("session.form.state", Effect.fn(function* (ctx) {
46
- return { data: yield* (yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID)).form.state(ctx.params.formID).pipe(Effect.catchTag("Form.NotFoundError", () => missingForm(ctx.params.formID))) };
47
- })).handle("session.form.reply", Effect.fn(function* (ctx) {
48
- yield* (yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID)).form.reply({ id: ctx.params.formID, answer: ctx.payload.answer }).pipe(Effect.catchTags({
49
- "Form.AlreadySettledError": (error) => new FormAlreadySettledError({ id: error.id, message: error.message }),
50
- "Form.InvalidAnswerError": (error) => new FormInvalidAnswerError({ id: error.id, message: error.message }),
51
- "Form.NotFoundError": () => missingForm(ctx.params.formID)
52
- }));
53
- return HttpApiSchema.NoContent.make();
54
- })).handle("session.form.cancel", Effect.fn(function* (ctx) {
55
- yield* (yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID)).form.cancel(ctx.params.formID).pipe(Effect.catchTags({
56
- "Form.AlreadySettledError": (error) => new FormAlreadySettledError({ id: error.id, message: error.message }),
57
- "Form.NotFoundError": () => missingForm(ctx.params.formID)
58
- }));
59
- return HttpApiSchema.NoContent.make();
60
- }));
61
- }));
5
+ import { response } from "../location";
6
+ export const FormHandler = HttpApiBuilder.group(Api, "server.form", (handlers) => handlers.handle("form.list", Effect.fn(function* () {
7
+ const form = yield* Form.Service;
8
+ return yield* response(form.list());
9
+ })));
@@ -2,7 +2,12 @@ import { Integration } from "@opencode/core/integration";
2
2
  import { Effect } from "effect";
3
3
  import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
4
4
  import { Api } from "../api";
5
- import { InvalidRequestError } from "@opencode/protocol/errors";
5
+ import {
6
+ IntegrationAttemptNotFoundError,
7
+ IntegrationMethodNotFoundError,
8
+ IntegrationNotFoundError,
9
+ InvalidRequestError
10
+ } from "@opencode/protocol/errors";
6
11
  import { response } from "../location";
7
12
  import { WellKnown } from "@opencode/core/wellknown";
8
13
  const authorize = (effect) => effect.pipe(Effect.mapError((error) => new InvalidRequestError({
@@ -14,8 +19,13 @@ export const IntegrationHandler = HttpApiBuilder.group(Api, "server.integration"
14
19
  const service = yield* Integration.Service;
15
20
  return yield* response(service.list());
16
21
  })).handle("integration.get", Effect.fn(function* (ctx) {
17
- const service = yield* Integration.Service;
18
- return yield* response(service.get(ctx.params.integrationID));
22
+ const integration = yield* (yield* Integration.Service).get(ctx.params.integrationID);
23
+ if (!integration)
24
+ return yield* new IntegrationNotFoundError({
25
+ integrationID: ctx.params.integrationID,
26
+ message: `Integration not found: ${ctx.params.integrationID}`
27
+ });
28
+ return yield* response(Effect.succeed(integration));
19
29
  })).handle("integration.wellknown.add", Effect.fn(function* (ctx) {
20
30
  const wellknown = yield* WellKnown.Service, integration = yield* Integration.Service;
21
31
  yield* wellknown.add(ctx.payload.url).pipe(Effect.mapError((error) => new InvalidRequestError({ message: error.message, kind: "well_known_discovery" })));
@@ -23,6 +33,11 @@ export const IntegrationHandler = HttpApiBuilder.group(Api, "server.integration"
23
33
  return HttpApiSchema.NoContent.make();
24
34
  })).handle("integration.connect.key", Effect.fn(function* (ctx) {
25
35
  const service = yield* Integration.Service;
36
+ if (!(yield* service.get(ctx.params.integrationID)))
37
+ return yield* new IntegrationNotFoundError({
38
+ integrationID: ctx.params.integrationID,
39
+ message: `Integration not found: ${ctx.params.integrationID}`
40
+ });
26
41
  yield* authorize(service.connection.key({
27
42
  integrationID: ctx.params.integrationID,
28
43
  key: ctx.payload.key,
@@ -40,19 +55,42 @@ export const IntegrationHandler = HttpApiBuilder.group(Api, "server.integration"
40
55
  })));
41
56
  })).handle("integration.oauth.status", Effect.fn(function* (ctx) {
42
57
  const service = yield* Integration.Service;
58
+ if (!(yield* service.get(ctx.params.integrationID)))
59
+ return yield* new IntegrationNotFoundError({
60
+ integrationID: ctx.params.integrationID,
61
+ message: `Integration not found: ${ctx.params.integrationID}`
62
+ });
43
63
  return yield* response(service.oauth.status({
44
64
  integrationID: ctx.params.integrationID,
45
65
  attemptID: ctx.params.attemptID
46
- }));
66
+ }).pipe(Effect.mapError((error) => new IntegrationAttemptNotFoundError({
67
+ integrationID: error.integrationID,
68
+ attemptID: error.attemptID,
69
+ message: `OAuth attempt not found: ${error.attemptID}`
70
+ }))));
47
71
  })).handle("integration.oauth.complete", Effect.fn(function* (ctx) {
48
- yield* (yield* Integration.Service).oauth.complete({
72
+ const service = yield* Integration.Service;
73
+ if (!(yield* service.get(ctx.params.integrationID)))
74
+ return yield* new IntegrationNotFoundError({
75
+ integrationID: ctx.params.integrationID,
76
+ message: `Integration not found: ${ctx.params.integrationID}`
77
+ });
78
+ yield* service.oauth.complete({
49
79
  integrationID: ctx.params.integrationID,
50
80
  attemptID: ctx.params.attemptID,
51
81
  code: ctx.payload.code
52
- }).pipe(Effect.mapError((error) => new InvalidRequestError({
53
- message: error._tag === "Integration.CodeRequired" ? "Authorization code is required" : "Authentication failed",
54
- kind: error._tag === "Integration.CodeRequired" ? "integration_code_required" : "integration_authorization"
55
- })));
82
+ }).pipe(Effect.mapError((error) => {
83
+ if (error._tag === "Integration.AttemptNotFound")
84
+ return new IntegrationAttemptNotFoundError({
85
+ integrationID: error.integrationID,
86
+ attemptID: error.attemptID,
87
+ message: `OAuth attempt not found: ${error.attemptID}`
88
+ });
89
+ return new InvalidRequestError({
90
+ message: error._tag === "Integration.CodeRequired" ? "Authorization code is required" : "Authentication failed",
91
+ kind: error._tag === "Integration.CodeRequired" ? "integration_code_required" : "integration_authorization"
92
+ });
93
+ }));
56
94
  return HttpApiSchema.NoContent.make();
57
95
  })).handle("integration.oauth.cancel", Effect.fn(function* (ctx) {
58
96
  yield* (yield* Integration.Service).oauth.cancel({
@@ -61,7 +99,18 @@ export const IntegrationHandler = HttpApiBuilder.group(Api, "server.integration"
61
99
  });
62
100
  return HttpApiSchema.NoContent.make();
63
101
  })).handle("integration.command.connect", Effect.fn(function* (ctx) {
64
- const service = yield* Integration.Service;
102
+ const service = yield* Integration.Service, integration = yield* service.get(ctx.params.integrationID);
103
+ if (!integration)
104
+ return yield* new IntegrationNotFoundError({
105
+ integrationID: ctx.params.integrationID,
106
+ message: `Integration not found: ${ctx.params.integrationID}`
107
+ });
108
+ if (!integration.methods.some((method) => method.type === "command" && method.id === ctx.payload.methodID))
109
+ return yield* new IntegrationMethodNotFoundError({
110
+ integrationID: ctx.params.integrationID,
111
+ methodID: ctx.payload.methodID,
112
+ message: `Integration method not found: ${ctx.payload.methodID}`
113
+ });
65
114
  return yield* response(authorize(service.command.connect({
66
115
  integrationID: ctx.params.integrationID,
67
116
  methodID: ctx.payload.methodID,
@@ -69,10 +118,19 @@ export const IntegrationHandler = HttpApiBuilder.group(Api, "server.integration"
69
118
  })));
70
119
  })).handle("integration.command.status", Effect.fn(function* (ctx) {
71
120
  const service = yield* Integration.Service;
121
+ if (!(yield* service.get(ctx.params.integrationID)))
122
+ return yield* new IntegrationNotFoundError({
123
+ integrationID: ctx.params.integrationID,
124
+ message: `Integration not found: ${ctx.params.integrationID}`
125
+ });
72
126
  return yield* response(service.command.status({
73
127
  integrationID: ctx.params.integrationID,
74
128
  attemptID: ctx.params.attemptID
75
- }));
129
+ }).pipe(Effect.mapError((error) => new IntegrationAttemptNotFoundError({
130
+ integrationID: error.integrationID,
131
+ attemptID: error.attemptID,
132
+ message: `Command attempt not found: ${error.attemptID}`
133
+ }))));
76
134
  })).handle("integration.command.cancel", Effect.fn(function* (ctx) {
77
135
  yield* (yield* Integration.Service).command.cancel({
78
136
  integrationID: ctx.params.integrationID,
@@ -6,7 +6,6 @@ export const LocationHandler = HttpApiBuilder.group(Api, "server.location", (han
6
6
  const location = yield* Location.Service;
7
7
  return new Location.Info({
8
8
  directory: location.directory,
9
- workspaceID: location.workspaceID,
10
9
  project: location.project
11
10
  });
12
11
  })));
@@ -1,14 +1,14 @@
1
- import { Catalog } from "@opencode/core/catalog";
1
+ import { Model } from "@opencode/core/model";
2
2
  import { Effect } from "effect";
3
3
  import { HttpApiBuilder } from "effect/unstable/httpapi";
4
4
  import { Api } from "../api";
5
5
  import { response } from "../location";
6
6
  export const ModelHandler = HttpApiBuilder.group(Api, "server.model", (handlers) => Effect.gen(function* () {
7
7
  return handlers.handle("model.list", Effect.fn(function* () {
8
- const catalog = yield* Catalog.Service;
9
- return yield* response(catalog.model.available());
8
+ const models = yield* Model.Service;
9
+ return yield* response(models.available());
10
10
  })).handle("model.default", Effect.fn(function* () {
11
- const catalog = yield* Catalog.Service;
12
- return yield* response(catalog.model.default());
11
+ const models = yield* Model.Service;
12
+ return yield* response(models.default());
13
13
  }));
14
14
  }));
@@ -1,4 +1,4 @@
1
1
  import { Instance } from "@opencode/core/instance/service";
2
2
  import { PermissionSaved } from "@opencode/core/permission/saved";
3
3
  import { Session } from "@opencode/core/session";
4
- export declare const PermissionHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.permission">, never, import("@opencode/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode/protocol/middleware/authorization").Authorization | Session.Service | Instance.Service | import("../location").LocationMiddleware | import("../middleware/session-location").SessionLocationMiddleware | import("effect/unstable/http/HttpRouter").Request<"Requires", PermissionSaved.Service>>;
4
+ export declare const PermissionHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.permission">, never, Session.Service | Instance.Service | import("../middleware/session-location").SessionLocationMiddleware | (import("@opencode/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware | import("effect/unstable/http/HttpRouter").Request<"Requires", PermissionSaved.Service>)>;
@@ -41,10 +41,7 @@ export const PermissionHandler = HttpApiBuilder.group(Api, "server.permission",
41
41
  })).handle("session.permission.get", Effect.fn(function* (ctx) {
42
42
  return { data: (yield* requireOwnedRequest(ctx.params.sessionID, ctx.params.requestID)).request };
43
43
  })).handle("session.permission.reply", Effect.fn(function* (ctx) {
44
- yield* (yield* requireOwnedRequest(ctx.params.sessionID, ctx.params.requestID)).permission.reply({ requestID: ctx.params.requestID, reply: ctx.payload.reply, message: ctx.payload.message }).pipe(Effect.catchTag("Permission.NotFoundError", () => missingRequest(ctx.params.requestID)));
45
- return HttpApiSchema.NoContent.make();
46
- })).handle("session.permission.rules", Effect.fn(function* (ctx) {
47
- yield* sessions.setPermissions({ sessionID: ctx.params.sessionID, permissions: ctx.payload.permissions }).pipe(Effect.catchTag("Session.NotFoundError", missingSession));
44
+ yield* (yield* requireOwnedRequest(ctx.params.sessionID, ctx.params.requestID)).permission.reply({ requestID: ctx.params.requestID, reply: ctx.payload.decision, message: ctx.payload.message }).pipe(Effect.catchTag("Permission.NotFoundError", () => missingRequest(ctx.params.requestID)));
48
45
  return HttpApiSchema.NoContent.make();
49
46
  })).handle("permission.saved.list", Effect.fn(function* (ctx) {
50
47
  const location = yield* Location.Service;
@@ -7,10 +7,8 @@ import { Api } from "../api";
7
7
  import { response } from "../location";
8
8
  export const PluginHandler = HttpApiBuilder.group(Api, "server.plugin", (handlers) => handlers.handle("plugin.list", () => Effect.gen(function* () {
9
9
  return yield* response(Plugin.Service.use((plugin) => plugin.list()));
10
- })).handle("plugin.awaitActivation", () => Plugin.awaitActivation).handle("plugin.check", (ctx) => Effect.gen(function* () {
11
- const plugins = yield* Plugin.Service;
12
- yield* plugins.awaitActivation;
13
- const inventory = yield* plugins.list(), targets = [
10
+ })).handle("plugin.check", (ctx) => Effect.gen(function* () {
11
+ const inventory = yield* (yield* Plugin.Service).list(), targets = [
14
12
  ...new Set(inventory.flatMap((plugin) => plugin.source.type === "package" ? [plugin.source.target] : []))
15
13
  ].filter((target) => ctx.payload.target === void 0 || target === ctx.payload.target);
16
14
  if (ctx.payload.target !== void 0 && !targets.length)
@@ -34,9 +32,7 @@ export const PluginHandler = HttpApiBuilder.group(Api, "server.plugin", (handler
34
32
  };
35
33
  })));
36
34
  })).handle("plugin.update", (ctx) => Effect.gen(function* () {
37
- const plugins = yield* Plugin.Service;
38
- yield* plugins.awaitActivation;
39
- const inventory = new Set((yield* plugins.list()).flatMap((plugin) => plugin.source.type === "package" ? [plugin.source.target] : [])), unknown = ctx.payload.targets.filter((target) => !inventory.has(target));
35
+ const plugins = yield* Plugin.Service, inventory = new Set((yield* plugins.list()).flatMap((plugin) => plugin.source.type === "package" ? [plugin.source.target] : [])), unknown = ctx.payload.targets.filter((target) => !inventory.has(target));
40
36
  if (unknown.length)
41
37
  return yield* new InvalidRequestError({
42
38
  message: `Plugin packages are not in the current server inventory: ${unknown.join(", ")}`,
@@ -1,2 +1,2 @@
1
1
  import { Project } from "@opencode/core/project";
2
- export declare const ProjectHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.project">, never, import("effect/unstable/http/HttpRouter").Request<"Requires", Project.Service> | (import("@opencode/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware)>;
2
+ export declare const ProjectHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.project">, never, import("@opencode/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware | import("effect/unstable/http/HttpRouter").Request<"Requires", Project.Service>>;
@@ -1,4 +1,3 @@
1
- import { Location } from "@opencode/core/location";
2
1
  import { Project } from "@opencode/core/project";
3
2
  import { Effect } from "effect";
4
3
  import { HttpApiBuilder } from "effect/unstable/httpapi";
@@ -7,8 +6,4 @@ import { ProjectNotFoundError } from "@opencode/protocol/errors";
7
6
  export const ProjectHandler = HttpApiBuilder.group(Api, "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({
8
7
  projectID: ctx.params.projectID,
9
8
  message: `Project not found: ${ctx.params.projectID}`
10
- }))))).handle("project.current", () => Location.Service.use((location) => Effect.succeed({
11
- id: location.project.id,
12
- directory: location.project.directory,
13
- canonical: location.project.canonical
14
- }))));
9
+ }))))));
@@ -1,4 +1,4 @@
1
- import { Catalog } from "@opencode/core/catalog";
1
+ import { Provider } from "@opencode/core/provider";
2
2
  import { ProviderNotFoundError } from "@opencode/protocol/errors";
3
3
  import { Effect } from "effect";
4
4
  import { HttpApiBuilder } from "effect/unstable/httpapi";
@@ -6,10 +6,10 @@ import { Api } from "../api";
6
6
  import { response } from "../location";
7
7
  export const ProviderHandler = HttpApiBuilder.group(Api, "server.provider", (handlers) => Effect.gen(function* () {
8
8
  return handlers.handle("provider.list", Effect.fn(function* () {
9
- const catalog = yield* Catalog.Service;
10
- return yield* response(catalog.provider.available());
9
+ const providers = yield* Provider.Service;
10
+ return yield* response(providers.available());
11
11
  })).handle("provider.get", Effect.fn(function* (ctx) {
12
- const provider = yield* (yield* Catalog.Service).provider.get(ctx.params.providerID);
12
+ const provider = yield* (yield* Provider.Service).get(ctx.params.providerID);
13
13
  if (!provider)
14
14
  return yield* new ProviderNotFoundError({
15
15
  providerID: ctx.params.providerID,
@@ -2,6 +2,11 @@ import { Effect } from "effect";
2
2
  import { HttpApiBuilder } from "effect/unstable/httpapi";
3
3
  import { Api } from "../api";
4
4
  import { ServerInfo } from "../server-info";
5
- export const ServerHandler = HttpApiBuilder.group(Api, "server.server", (handlers) => handlers.handle("server.get", () => Effect.gen(function* () {
6
- return { urls: (yield* ServerInfo.Service).urls() };
5
+ export const ServerHandler = HttpApiBuilder.group(Api, "server.server", (handlers) => handlers.handle("server.status", () => Effect.gen(function* () {
6
+ const info = yield* ServerInfo.Service;
7
+ return {
8
+ version: info.app.version ?? "unknown",
9
+ pid: process.pid ?? 0,
10
+ urls: info.urls()
11
+ };
7
12
  })));
@@ -1,5 +1,9 @@
1
1
  import { Session } from "@opencode/core/session";
2
- import { SessionNotFoundError, UnknownError } from "@opencode/protocol/errors";
2
+ import type { Snapshot } from "@opencode/core/snapshot";
3
+ import { MessageNotFoundError, SessionNotFoundError, UnknownError } from "@opencode/protocol/errors";
3
4
  import { Effect } from "effect";
4
5
  export declare function missingSession(error: Session.NotFoundError): SessionNotFoundError;
6
+ export declare function missingMessage(error: Session.MessageNotFoundError): MessageNotFoundError;
5
7
  export declare function failedMessageDecode(error: Session.MessageDecodeError): Effect.Effect<never, UnknownError, never>;
8
+ /** Snapshot repositories are host state clients cannot repair, so surface only a log reference. */
9
+ export declare function failedSnapshot(operation: string, sessionID: Session.ID): (error: Snapshot.Error) => Effect.Effect<never, UnknownError, never>;