@opencode-ai/server 0.0.0-dev-17880
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 +7528 -0
- package/dist/api.js +9 -0
- package/dist/auth.d.ts +17 -0
- package/dist/auth.js +17 -0
- package/dist/cors.d.ts +7 -0
- package/dist/cors.js +36 -0
- package/dist/event-feed.d.ts +32 -0
- package/dist/event-feed.js +60 -0
- package/dist/fetch.d.ts +68 -0
- package/dist/fetch.js +11 -0
- package/dist/handlers/agent.d.ts +1 -0
- package/dist/handlers/agent.js +17 -0
- package/dist/handlers/command.d.ts +1 -0
- package/dist/handlers/command.js +5 -0
- package/dist/handlers/config.d.ts +1 -0
- package/dist/handlers/config.js +4 -0
- package/dist/handlers/credential.d.ts +1 -0
- package/dist/handlers/credential.js +11 -0
- package/dist/handlers/debug.d.ts +1 -0
- package/dist/handlers/debug.js +11 -0
- package/dist/handlers/event.d.ts +2 -0
- package/dist/handlers/event.js +27 -0
- package/dist/handlers/form.d.ts +1 -0
- package/dist/handlers/form.js +57 -0
- package/dist/handlers/fs.d.ts +1 -0
- package/dist/handlers/fs.js +19 -0
- package/dist/handlers/generate.d.ts +1 -0
- package/dist/handlers/generate.js +10 -0
- package/dist/handlers/health.d.ts +2 -0
- package/dist/handlers/health.js +11 -0
- package/dist/handlers/integration.d.ts +2 -0
- package/dist/handlers/integration.js +83 -0
- package/dist/handlers/location.d.ts +1 -0
- package/dist/handlers/location.js +12 -0
- package/dist/handlers/mcp.d.ts +1 -0
- package/dist/handlers/mcp.js +31 -0
- package/dist/handlers/message.d.ts +2 -0
- package/dist/handlers/message.js +42 -0
- package/dist/handlers/migration.d.ts +1 -0
- package/dist/handlers/migration.js +7 -0
- package/dist/handlers/model.d.ts +1 -0
- package/dist/handlers/model.js +22 -0
- package/dist/handlers/permission.d.ts +2 -0
- package/dist/handlers/permission.js +56 -0
- package/dist/handlers/plugin-readiness.d.ts +4 -0
- package/dist/handlers/plugin-readiness.js +9 -0
- package/dist/handlers/plugin.d.ts +1 -0
- package/dist/handlers/plugin.js +8 -0
- package/dist/handlers/project.d.ts +2 -0
- package/dist/handlers/project.js +10 -0
- package/dist/handlers/provider.d.ts +1 -0
- package/dist/handlers/provider.js +20 -0
- package/dist/handlers/pty.d.ts +3 -0
- package/dist/handlers/pty.js +109 -0
- package/dist/handlers/reference.d.ts +1 -0
- package/dist/handlers/reference.js +5 -0
- package/dist/handlers/server.d.ts +2 -0
- package/dist/handlers/server.js +7 -0
- package/dist/handlers/session-error.d.ts +5 -0
- package/dist/handlers/session-error.js +13 -0
- package/dist/handlers/session.d.ts +3 -0
- package/dist/handlers/session.js +275 -0
- package/dist/handlers/shell.d.ts +1 -0
- package/dist/handlers/shell.js +30 -0
- package/dist/handlers/skill.d.ts +1 -0
- package/dist/handlers/skill.js +5 -0
- package/dist/handlers/vcs.d.ts +1 -0
- package/dist/handlers/vcs.js +14 -0
- package/dist/handlers/websearch.d.ts +1 -0
- package/dist/handlers/websearch.js +38 -0
- package/dist/handlers/worktree.d.ts +2 -0
- package/dist/handlers/worktree.js +32 -0
- package/dist/handlers.d.ts +2 -0
- package/dist/handlers.js +32 -0
- package/dist/location.d.ts +23 -0
- package/dist/location.js +44 -0
- package/dist/middleware/authorization.d.ts +7 -0
- package/dist/middleware/authorization.js +48 -0
- package/dist/middleware/form-location.d.ts +18 -0
- package/dist/middleware/form-location.js +42 -0
- package/dist/middleware/schema-error.d.ts +3 -0
- package/dist/middleware/schema-error.js +15 -0
- package/dist/middleware/session-location.d.ts +18 -0
- package/dist/middleware/session-location.js +36 -0
- package/dist/options.d.ts +38 -0
- package/dist/options.js +32 -0
- package/dist/process.d.ts +47 -0
- package/dist/process.js +115 -0
- package/dist/pty-environment.d.ts +13 -0
- package/dist/pty-environment.js +9 -0
- package/dist/request-tracing.d.ts +2 -0
- package/dist/request-tracing.js +2 -0
- package/dist/routes.d.ts +23 -0
- package/dist/routes.js +112 -0
- package/dist/server-info.d.ts +11 -0
- package/dist/server-info.js +22 -0
- package/dist/service-status.d.ts +25 -0
- package/dist/service-status.js +11 -0
- package/dist/workerd.d.ts +45 -0
- package/dist/workerd.js +57 -0
- package/package.json +45 -0
package/dist/api.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { makeDefaultApi } from "@opencode-ai/protocol/api";
|
|
2
|
+
import { LocationMiddleware } from "./location";
|
|
3
|
+
import { FormLocationMiddleware } from "./middleware/form-location";
|
|
4
|
+
import { SessionLocationMiddleware } from "./middleware/session-location";
|
|
5
|
+
export const Api = makeDefaultApi({
|
|
6
|
+
locationMiddleware: LocationMiddleware,
|
|
7
|
+
formLocationMiddleware: FormLocationMiddleware,
|
|
8
|
+
sessionLocationMiddleware: SessionLocationMiddleware
|
|
9
|
+
});
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * as ServerAuth from "./auth";
|
|
2
|
+
import { Context, Layer, Option, Redacted } from "effect";
|
|
3
|
+
export type DecodedCredentials = {
|
|
4
|
+
readonly username: string;
|
|
5
|
+
readonly password: Redacted.Redacted;
|
|
6
|
+
};
|
|
7
|
+
export type Info = {
|
|
8
|
+
readonly password: Option.Option<string>;
|
|
9
|
+
readonly username: string;
|
|
10
|
+
};
|
|
11
|
+
declare const Config_base: Context.ServiceClass<Config, "@opencode/ServerAuthConfig", Info>;
|
|
12
|
+
export declare class Config extends Config_base {
|
|
13
|
+
static configLayer(input: Pick<Info, "password">): Layer.Layer<Config, never, never>;
|
|
14
|
+
static get layer(): Layer.Layer<Config, never, never>;
|
|
15
|
+
}
|
|
16
|
+
export declare function required(config: Info): boolean;
|
|
17
|
+
export declare function authorized(credentials: DecodedCredentials, config: Info): boolean;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * as ServerAuth from "./auth";
|
|
2
|
+
import { Context, Layer, Option, Redacted } from "effect";
|
|
3
|
+
|
|
4
|
+
export class Config extends Context.Service()("@opencode/ServerAuthConfig") {
|
|
5
|
+
static configLayer(input) {
|
|
6
|
+
return Layer.succeed(this, this.of({ ...input, username: "opencode" }));
|
|
7
|
+
}
|
|
8
|
+
static get layer() {
|
|
9
|
+
return this.configLayer({ password: Option.none() });
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function required(config) {
|
|
13
|
+
return Option.isSome(config.password) && config.password.value !== "";
|
|
14
|
+
}
|
|
15
|
+
export function authorized(credentials, config) {
|
|
16
|
+
return Option.isSome(config.password) && credentials.username === config.username && Redacted.value(credentials.password) === config.password.value;
|
|
17
|
+
}
|
package/dist/cors.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
export type CorsOptions = {
|
|
3
|
+
readonly cors?: ReadonlyArray<string>;
|
|
4
|
+
};
|
|
5
|
+
export declare const CorsConfig: Context.Reference<CorsOptions | undefined>;
|
|
6
|
+
export declare function isAllowedCorsOrigin(input: string | undefined, opts?: CorsOptions): boolean;
|
|
7
|
+
export declare function isAllowedRequestOrigin(input: string | undefined, host: string | undefined, opts?: CorsOptions): boolean;
|
package/dist/cors.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export * as EventFeed from "./event-feed";
|
|
2
|
+
import { Bus } from "@opencode-ai/core/bus";
|
|
3
|
+
import { type OpenCodeEvent } from "@opencode-ai/protocol/groups/event";
|
|
4
|
+
import { Cause, Context, Effect, Layer, Schema, Scope, Stream } from "effect";
|
|
5
|
+
export declare const SubscriberCapacity = 4096;
|
|
6
|
+
declare const SubscriberOverflowError_base: Schema.Class<SubscriberOverflowError, Schema.TaggedStruct<"EventFeed.SubscriberOverflow", {
|
|
7
|
+
readonly capacity: Schema.Int;
|
|
8
|
+
}>, Cause.YieldableError>;
|
|
9
|
+
export declare class SubscriberOverflowError extends SubscriberOverflowError_base {
|
|
10
|
+
}
|
|
11
|
+
declare const EncodingError_base: Schema.Class<EncodingError, Schema.TaggedStruct<"EventFeed.EncodingError", {
|
|
12
|
+
readonly eventID: Schema.brand<Schema.String, "Event.ID"> & {
|
|
13
|
+
create: () => string & import("effect/Brand").Brand<"Event.ID">;
|
|
14
|
+
};
|
|
15
|
+
readonly eventType: Schema.String;
|
|
16
|
+
readonly cause: Schema.Defect;
|
|
17
|
+
}>, Cause.YieldableError>;
|
|
18
|
+
export declare class EncodingError extends EncodingError_base {
|
|
19
|
+
}
|
|
20
|
+
export type Error = SubscriberOverflowError | EncodingError;
|
|
21
|
+
export interface Interface {
|
|
22
|
+
readonly subscribe: Effect.Effect<Stream.Stream<string, Error>, never, Scope.Scope>;
|
|
23
|
+
}
|
|
24
|
+
declare const Service_base: Context.ServiceClass<Service, "@opencode/server/EventFeed", Interface>;
|
|
25
|
+
export declare class Service extends Service_base {
|
|
26
|
+
}
|
|
27
|
+
export declare function frame(event: OpenCodeEvent): string;
|
|
28
|
+
export declare const make: (observe: (subscriber: Bus.Subscriber) => Effect.Effect<Bus.Unsubscribe>, options?: {
|
|
29
|
+
readonly capacity?: number;
|
|
30
|
+
readonly encode?: (event: OpenCodeEvent) => string;
|
|
31
|
+
} | undefined) => Effect.Effect<Interface, never, Scope.Scope>;
|
|
32
|
+
export declare const layer: Layer.Layer<Service, never, Bus.Service>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export * as EventFeed from "./event-feed";
|
|
2
|
+
import { Bus } from "@opencode-ai/core/bus";
|
|
3
|
+
import { Event } from "@opencode-ai/schema/event";
|
|
4
|
+
import { isOpenCodeEvent } from "@opencode-ai/protocol/groups/event";
|
|
5
|
+
import { Cause, Context, Effect, Layer, Queue, Schema, Scope, Stream } from "effect";
|
|
6
|
+
export const SubscriberCapacity = 4096;
|
|
7
|
+
|
|
8
|
+
export class SubscriberOverflowError extends Schema.TaggedError()("EventFeed.SubscriberOverflow", { capacity: Schema.Int }) {
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class EncodingError extends Schema.TaggedError()("EventFeed.EncodingError", {
|
|
12
|
+
eventID: Event.ID,
|
|
13
|
+
eventType: Schema.String,
|
|
14
|
+
cause: Schema.Defect()
|
|
15
|
+
}) {
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class Service extends Context.Service()("@opencode/server/EventFeed") {
|
|
19
|
+
}
|
|
20
|
+
export function frame(event) {
|
|
21
|
+
return `data: ${JSON.stringify(event)}
|
|
22
|
+
|
|
23
|
+
`;
|
|
24
|
+
}
|
|
25
|
+
export const make = Effect.fn("EventFeed.make")(function* (observe, options) {
|
|
26
|
+
const capacity = options?.capacity ?? SubscriberCapacity, render = options?.encode ?? frame, subscribers = new Set, fail = (error) => Effect.sync(() => {
|
|
27
|
+
const current = Array.from(subscribers);
|
|
28
|
+
subscribers.clear();
|
|
29
|
+
for (const subscriber of current)
|
|
30
|
+
Queue.failCauseUnsafe(subscriber, Cause.fail(error));
|
|
31
|
+
}), publish = Effect.fnUntraced(function* (event) {
|
|
32
|
+
if (!isOpenCodeEvent(event))
|
|
33
|
+
return;
|
|
34
|
+
if (subscribers.size === 0)
|
|
35
|
+
return;
|
|
36
|
+
const encoded = yield* Effect.try({
|
|
37
|
+
try: () => render(event),
|
|
38
|
+
catch: (cause) => new EncodingError({ eventID: event.id, eventType: event.type, cause })
|
|
39
|
+
}).pipe(Effect.catch((error) => Effect.logError("Failed to encode public event", {
|
|
40
|
+
eventID: error.eventID,
|
|
41
|
+
eventType: error.eventType,
|
|
42
|
+
cause: error.cause
|
|
43
|
+
}).pipe(Effect.andThen(fail(error)), Effect.as(void 0))));
|
|
44
|
+
if (encoded === void 0)
|
|
45
|
+
return;
|
|
46
|
+
for (const subscriber of subscribers) {
|
|
47
|
+
if (Queue.offerUnsafe(subscriber, encoded))
|
|
48
|
+
continue;
|
|
49
|
+
subscribers.delete(subscriber);
|
|
50
|
+
Queue.failCauseUnsafe(subscriber, Cause.fail(new SubscriberOverflowError({ capacity })));
|
|
51
|
+
}
|
|
52
|
+
}), unsubscribe = yield* observe(publish);
|
|
53
|
+
yield* Effect.addFinalizer(() => unsubscribe);
|
|
54
|
+
return Service.of({
|
|
55
|
+
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))
|
|
56
|
+
});
|
|
57
|
+
}), layer = Layer.effect(Service, Effect.gen(function* () {
|
|
58
|
+
const bus = yield* Bus.Service;
|
|
59
|
+
return yield* make(bus.listen);
|
|
60
|
+
}));
|
package/dist/fetch.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export * as ServerFetch from "./fetch";
|
|
2
|
+
import { Context, Effect } from "effect";
|
|
3
|
+
import type { LayerNode } from "@opencode-ai/util/effect/layer-node";
|
|
4
|
+
export interface BootOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Runtime-profile service replacements, applied after the standard set so later entries
|
|
7
|
+
* win — swaps services the standard graph assumes are local. See `ServerWorkerd.replacements`.
|
|
8
|
+
*/
|
|
9
|
+
readonly overrides?: LayerNode.Replacements;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Builds a web-standard fetch handler — `(request: Request) => Promise<Response>` — serving the
|
|
13
|
+
* same HttpApi routes as the Node server process without binding a port, owning a listener, or
|
|
14
|
+
* installing signal handlers. This is the entry for runtimes that hand requests to the embedder
|
|
15
|
+
* instead of letting it listen: workerd (Workers and Durable Objects), Deno.serve, Bun.serve, or
|
|
16
|
+
* a test harness.
|
|
17
|
+
*
|
|
18
|
+
* The application layer builds EAGERLY, inside the caller's `Scope`, before the handler is
|
|
19
|
+
* returned. Do not convert this to a lazy first-request build: on workerd, a first request that
|
|
20
|
+
* aborts mid-build interrupts the layer construction and wedges every subsequent request
|
|
21
|
+
* (Effect-TS/effect#6319 class). The embedder owns the lifecycle — closing the scope releases
|
|
22
|
+
* the application layer.
|
|
23
|
+
*
|
|
24
|
+
* Auth follows `createRoutes` semantics: `options.password` enforces Basic auth; omitting it
|
|
25
|
+
* serves unauthenticated, so an embedder without a password must front the handler with its own
|
|
26
|
+
* access control.
|
|
27
|
+
*
|
|
28
|
+
* Sessions whose execution claim was never released resume once the layer is built, exactly as
|
|
29
|
+
* the Node server process does: a runtime that dies without teardown — an evicted Durable
|
|
30
|
+
* Object leaves the same durable signature as a killed process — replays orphaned turns on the
|
|
31
|
+
* next boot, and the sweep is a no-op when nothing is suspended.
|
|
32
|
+
*/
|
|
33
|
+
export declare const make: (options?: {
|
|
34
|
+
readonly events?: {
|
|
35
|
+
readonly persist?: boolean | undefined;
|
|
36
|
+
} | undefined;
|
|
37
|
+
readonly models?: {
|
|
38
|
+
readonly url?: string | undefined;
|
|
39
|
+
readonly file?: string | undefined;
|
|
40
|
+
readonly snapshot?: boolean | undefined;
|
|
41
|
+
readonly fetch?: boolean | undefined;
|
|
42
|
+
} | undefined;
|
|
43
|
+
readonly config?: {
|
|
44
|
+
readonly directory?: string | undefined;
|
|
45
|
+
readonly project?: boolean | undefined;
|
|
46
|
+
readonly content?: string | undefined;
|
|
47
|
+
readonly file?: string | undefined;
|
|
48
|
+
} | undefined;
|
|
49
|
+
readonly hostname?: string | undefined;
|
|
50
|
+
readonly windows?: {
|
|
51
|
+
readonly gitbash?: string | undefined;
|
|
52
|
+
} | undefined;
|
|
53
|
+
readonly port?: number | undefined;
|
|
54
|
+
readonly app?: {
|
|
55
|
+
readonly version?: string | undefined;
|
|
56
|
+
readonly name?: string | undefined;
|
|
57
|
+
readonly channel?: string | undefined;
|
|
58
|
+
} | undefined;
|
|
59
|
+
readonly fs?: {
|
|
60
|
+
readonly fff?: boolean | undefined;
|
|
61
|
+
readonly filewatcher?: boolean | undefined;
|
|
62
|
+
} | undefined;
|
|
63
|
+
readonly password?: string | undefined;
|
|
64
|
+
readonly simulation?: boolean | undefined;
|
|
65
|
+
readonly database?: {
|
|
66
|
+
readonly path?: string | undefined;
|
|
67
|
+
} | undefined;
|
|
68
|
+
} | undefined, boot?: BootOptions | undefined) => Effect.Effect<(request: Request, context?: Context.Context<never> | undefined) => Promise<globalThis.Response>, Error, import("effect/Scope").Scope>;
|
package/dist/fetch.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * as ServerFetch from "./fetch";
|
|
2
|
+
import { Context, Effect, Layer } from "effect";
|
|
3
|
+
import { HttpEffect, HttpMiddleware, HttpRouter, HttpServer } from "effect/unstable/http";
|
|
4
|
+
import { SessionRestart } from "@opencode-ai/core/session/execution/restart";
|
|
5
|
+
import { isAllowedCorsOrigin } from "./cors";
|
|
6
|
+
import { createRoutes } from "./routes";
|
|
7
|
+
export const make = Effect.fn("ServerFetch.make")(function* (options = {}, boot = {}) {
|
|
8
|
+
const context = yield* Layer.build(createRoutes(options, () => [], boot.overrides ?? []).pipe(Layer.provide(HttpServer.layerServices)));
|
|
9
|
+
yield* Effect.forkDetach(Context.get(context, SessionRestart.Service).resumeSuspendedSessions);
|
|
10
|
+
return Context.get(context, HttpRouter.HttpRouter).asHttpEffect().pipe(HttpMiddleware.cors({ allowedOrigins: isAllowedCorsOrigin, maxAge: 86400 }), HttpEffect.toWebHandlerWith(context));
|
|
11
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const AgentHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.agent">, never, import("@opencode-ai/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode-ai/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Agent } from "@opencode-ai/core/agent";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
4
|
+
import { Api } from "../api";
|
|
5
|
+
import { response } from "../location";
|
|
6
|
+
import { AgentNotFoundError } from "@opencode-ai/protocol/errors";
|
|
7
|
+
export const AgentHandler = HttpApiBuilder.group(Api, "server.agent", (handlers) => handlers.handle("agent.list", () => Effect.gen(function* () {
|
|
8
|
+
return yield* response(Agent.Service.use((agent) => agent.list()));
|
|
9
|
+
})).handle("agent.get", Effect.fn(function* (ctx) {
|
|
10
|
+
const agent = yield* Agent.Service.use((service) => service.get(ctx.params.agentID));
|
|
11
|
+
if (!agent)
|
|
12
|
+
return yield* new AgentNotFoundError({
|
|
13
|
+
agentID: ctx.params.agentID,
|
|
14
|
+
message: `Agent not found: ${ctx.params.agentID}`
|
|
15
|
+
});
|
|
16
|
+
return yield* response(Effect.succeed(agent));
|
|
17
|
+
})));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const CommandHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.command">, never, import("@opencode-ai/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode-ai/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware>;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Command } from "@opencode-ai/core/command";
|
|
2
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
3
|
+
import { Api } from "../api";
|
|
4
|
+
import { response } from "../location";
|
|
5
|
+
export const CommandHandler = HttpApiBuilder.group(Api, "server.command", (handlers) => handlers.handle("command.list", () => response(Command.Service.use((command) => command.list()))));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ConfigHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.config">, never, import("@opencode-ai/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode-ai/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Config } from "@opencode-ai/core/config";
|
|
2
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
3
|
+
import { Api } from "../api";
|
|
4
|
+
export const ConfigHandler = HttpApiBuilder.group(Api, "server.config", (handlers) => handlers.handle("config.get", () => Config.Service.use((config) => config.entries())));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const CredentialHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.credential">, never, import("@opencode-ai/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode-ai/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Integration } from "@opencode-ai/core/integration";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
|
|
4
|
+
import { Api } from "../api";
|
|
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 });
|
|
7
|
+
return HttpApiSchema.NoContent.make();
|
|
8
|
+
})).handle("credential.remove", Effect.fn(function* (ctx) {
|
|
9
|
+
yield* (yield* Integration.Service).connection.remove(ctx.params.credentialID);
|
|
10
|
+
return HttpApiSchema.NoContent.make();
|
|
11
|
+
})));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const DebugHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.debug">, never, import("@opencode-ai/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode-ai/protocol/middleware/authorization").Authorization>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { LocationServiceMap } from "@opencode-ai/core/location-service-map";
|
|
2
|
+
import { Effect, Option, RcMap } from "effect";
|
|
3
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
4
|
+
import { Api } from "../api";
|
|
5
|
+
import { requestRef } from "../location";
|
|
6
|
+
export const DebugHandler = HttpApiBuilder.group(Api, "server.debug", (handlers) => handlers.handle("debug.location", Effect.fn(function* () {
|
|
7
|
+
const locations = Option.getOrThrow(yield* Effect.serviceOption(LocationServiceMap.Service));
|
|
8
|
+
return Array.from(yield* RcMap.keys(locations.rcMap));
|
|
9
|
+
})).handle("debug.location.evict", Effect.fn(function* (ctx) {
|
|
10
|
+
yield* Option.getOrThrow(yield* Effect.serviceOption(LocationServiceMap.Service)).invalidate(requestRef(ctx.request));
|
|
11
|
+
})));
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { EventFeed } from "../event-feed";
|
|
2
|
+
export declare const EventHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.event">, never, EventFeed.Service | (import("@opencode-ai/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode-ai/protocol/middleware/authorization").Authorization)>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Bus } from "@opencode-ai/core/bus";
|
|
2
|
+
import { Event } from "@opencode-ai/schema/event";
|
|
3
|
+
import { Effect, Stream } from "effect";
|
|
4
|
+
import { HttpServerResponse } from "effect/unstable/http";
|
|
5
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
6
|
+
import { Api } from "../api";
|
|
7
|
+
import { EventFeed } from "../event-feed";
|
|
8
|
+
export const EventHandler = HttpApiBuilder.group(Api, "server.event", (handlers) => Effect.gen(function* () {
|
|
9
|
+
const feed = yield* EventFeed.Service;
|
|
10
|
+
return handlers.handleRaw("event.subscribe", () => Effect.gen(function* () {
|
|
11
|
+
const connected = {
|
|
12
|
+
id: Event.ID.create(),
|
|
13
|
+
type: "server.connected",
|
|
14
|
+
data: {}
|
|
15
|
+
}, output = Stream.unwrap(feed.subscribe.pipe(Effect.map((live) => Stream.make(EventFeed.frame(connected)).pipe(Stream.concat(live))))), heartbeat = Stream.tick("15 seconds").pipe(Stream.map(() => `: heartbeat
|
|
16
|
+
|
|
17
|
+
`));
|
|
18
|
+
return HttpServerResponse.stream(output.pipe(Stream.merge(heartbeat, { haltStrategy: "left" }), Stream.encodeText), {
|
|
19
|
+
contentType: "text/event-stream",
|
|
20
|
+
headers: {
|
|
21
|
+
"Cache-Control": "no-cache, no-transform",
|
|
22
|
+
"X-Accel-Buffering": "no",
|
|
23
|
+
"X-Content-Type-Options": "nosniff"
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}));
|
|
27
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const FormHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.form">, never, import("../location").LocationMiddleware | (import("@opencode-ai/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode-ai/protocol/middleware/authorization").Authorization | import("../middleware/form-location").FormLocationMiddleware)>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Form } from "@opencode-ai/core/form";
|
|
2
|
+
import {
|
|
3
|
+
ConflictError,
|
|
4
|
+
FormAlreadySettledError,
|
|
5
|
+
FormInvalidAnswerError,
|
|
6
|
+
FormNotFoundError,
|
|
7
|
+
InvalidRequestError
|
|
8
|
+
} from "@opencode-ai/protocol/errors";
|
|
9
|
+
import { Effect } from "effect";
|
|
10
|
+
import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
|
|
11
|
+
import { Api } from "../api";
|
|
12
|
+
import { response } from "../location";
|
|
13
|
+
function missingForm(id) {
|
|
14
|
+
return new FormNotFoundError({ id, message: `Form not found: ${id}` });
|
|
15
|
+
}
|
|
16
|
+
export const FormHandler = HttpApiBuilder.group(Api, "server.form", (handlers) => Effect.gen(function* () {
|
|
17
|
+
const requireOwnedForm = Effect.fnUntraced(function* (sessionID, formID) {
|
|
18
|
+
const form = yield* Form.Service, info = yield* form.get(formID).pipe(Effect.catchTag("Form.NotFoundError", () => missingForm(formID)));
|
|
19
|
+
if (info.sessionID !== sessionID)
|
|
20
|
+
return yield* missingForm(formID);
|
|
21
|
+
return { form, info };
|
|
22
|
+
});
|
|
23
|
+
return handlers.handle("form.request.list", Effect.fn(function* () {
|
|
24
|
+
const form = yield* Form.Service;
|
|
25
|
+
return yield* response(form.list());
|
|
26
|
+
})).handle("session.form.list", Effect.fn(function* (ctx) {
|
|
27
|
+
return { data: yield* (yield* Form.Service).list({ sessionID: ctx.params.sessionID }) };
|
|
28
|
+
})).handle("session.form.create", Effect.fn(function* (ctx) {
|
|
29
|
+
return { data: yield* (yield* Form.Service).create({
|
|
30
|
+
id: ctx.payload.id,
|
|
31
|
+
sessionID: ctx.params.sessionID,
|
|
32
|
+
title: ctx.payload.title,
|
|
33
|
+
metadata: ctx.payload.metadata,
|
|
34
|
+
fields: ctx.payload.fields
|
|
35
|
+
}).pipe(Effect.catchTags({
|
|
36
|
+
"Form.AlreadyExistsError": (error) => new ConflictError({ resource: error.id, message: error.message }),
|
|
37
|
+
"Form.InvalidFormError": (error) => new InvalidRequestError({ message: error.message, field: "fields" })
|
|
38
|
+
})) };
|
|
39
|
+
})).handle("session.form.get", Effect.fn(function* (ctx) {
|
|
40
|
+
return { data: (yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID)).info };
|
|
41
|
+
})).handle("session.form.state", Effect.fn(function* (ctx) {
|
|
42
|
+
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))) };
|
|
43
|
+
})).handle("session.form.reply", Effect.fn(function* (ctx) {
|
|
44
|
+
yield* (yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID)).form.reply({ id: ctx.params.formID, answer: ctx.payload.answer }).pipe(Effect.catchTags({
|
|
45
|
+
"Form.AlreadySettledError": (error) => new FormAlreadySettledError({ id: error.id, message: error.message }),
|
|
46
|
+
"Form.InvalidAnswerError": (error) => new FormInvalidAnswerError({ id: error.id, message: error.message }),
|
|
47
|
+
"Form.NotFoundError": () => missingForm(ctx.params.formID)
|
|
48
|
+
}));
|
|
49
|
+
return HttpApiSchema.NoContent.make();
|
|
50
|
+
})).handle("session.form.cancel", Effect.fn(function* (ctx) {
|
|
51
|
+
yield* (yield* requireOwnedForm(ctx.params.sessionID, ctx.params.formID)).form.cancel(ctx.params.formID).pipe(Effect.catchTags({
|
|
52
|
+
"Form.AlreadySettledError": (error) => new FormAlreadySettledError({ id: error.id, message: error.message }),
|
|
53
|
+
"Form.NotFoundError": () => missingForm(ctx.params.formID)
|
|
54
|
+
}));
|
|
55
|
+
return HttpApiSchema.NoContent.make();
|
|
56
|
+
}));
|
|
57
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const FileSystemHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.fs">, never, import("@opencode-ai/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode-ai/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FileSystem } from "@opencode-ai/core/filesystem";
|
|
2
|
+
import { RelativePath } from "@opencode-ai/core/schema";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
import { HttpServerResponse } from "effect/unstable/http";
|
|
5
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
6
|
+
import { Api } from "../api";
|
|
7
|
+
import { response } from "../location";
|
|
8
|
+
export const FileSystemHandler = HttpApiBuilder.group(Api, "server.fs", (handlers) => Effect.gen(function* () {
|
|
9
|
+
return handlers.handleRaw("fs.read", (ctx) => Effect.gen(function* () {
|
|
10
|
+
const file = yield* (yield* FileSystem.Service).read({
|
|
11
|
+
path: RelativePath.make(decodeURIComponent(new URL(ctx.request.url, "http://localhost").pathname.slice(13)))
|
|
12
|
+
});
|
|
13
|
+
return HttpServerResponse.uint8Array(file.content, { contentType: file.mime });
|
|
14
|
+
})).handle("fs.list", (ctx) => response(Effect.gen(function* () {
|
|
15
|
+
return yield* (yield* FileSystem.Service).list(ctx.query);
|
|
16
|
+
}))).handle("fs.find", (ctx) => response(Effect.gen(function* () {
|
|
17
|
+
return yield* (yield* FileSystem.Service).find(ctx.query);
|
|
18
|
+
})));
|
|
19
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const GenerateHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.generate">, never, import("@opencode-ai/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode-ai/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Generate } from "@opencode-ai/core/generate";
|
|
2
|
+
import { InvalidRequestError, ServiceUnavailableError } from "@opencode-ai/protocol/errors";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
5
|
+
import { Api } from "../api";
|
|
6
|
+
export const GenerateHandler = HttpApiBuilder.group(Api, "server.generate", (handlers) => Effect.gen(function* () {
|
|
7
|
+
return handlers.handle("generate.text", Effect.fn("server.generate.text")(function* (request) {
|
|
8
|
+
return { data: { text: yield* (yield* Generate.Service).text(request.payload).pipe(Effect.mapError((error) => error._tag === "Generate.ModelSelectionError" ? new InvalidRequestError({ message: error.message }) : new ServiceUnavailableError({ message: error.message, service: error.service }))) } };
|
|
9
|
+
}));
|
|
10
|
+
}));
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { ServerInfo } from "../server-info";
|
|
2
|
+
export declare const HealthHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.health">, never, import("@opencode-ai/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode-ai/protocol/middleware/authorization").Authorization | import("effect/unstable/http/HttpRouter").Request<"Requires", ServerInfo.Service>>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
3
|
+
import { Api } from "../api";
|
|
4
|
+
import { ServerInfo } from "../server-info";
|
|
5
|
+
export const HealthHandler = HttpApiBuilder.group(Api, "server.health", (handlers) => handlers.handle("health.get", () => Effect.gen(function* () {
|
|
6
|
+
return {
|
|
7
|
+
healthy: !0,
|
|
8
|
+
version: (yield* ServerInfo.Service).app.version ?? "unknown",
|
|
9
|
+
pid: process.pid ?? 0
|
|
10
|
+
};
|
|
11
|
+
})));
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { WellKnown } from "@opencode-ai/core/wellknown";
|
|
2
|
+
export declare const IntegrationHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.integration">, never, import("effect/unstable/http/HttpRouter").Request<"Requires", WellKnown.Service> | (import("@opencode-ai/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode-ai/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware)>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Integration } from "@opencode-ai/core/integration";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi";
|
|
4
|
+
import { Api } from "../api";
|
|
5
|
+
import { InvalidRequestError } from "@opencode-ai/protocol/errors";
|
|
6
|
+
import { response } from "../location";
|
|
7
|
+
import { WellKnown } from "@opencode-ai/core/wellknown";
|
|
8
|
+
const authorize = (effect) => effect.pipe(Effect.mapError(() => new InvalidRequestError({
|
|
9
|
+
message: "Authentication failed",
|
|
10
|
+
kind: "integration_authorization"
|
|
11
|
+
})));
|
|
12
|
+
export const IntegrationHandler = HttpApiBuilder.group(Api, "server.integration", (handlers) => Effect.gen(function* () {
|
|
13
|
+
return handlers.handle("integration.list", Effect.fn(function* () {
|
|
14
|
+
const service = yield* Integration.Service;
|
|
15
|
+
return yield* response(service.list());
|
|
16
|
+
})).handle("integration.get", Effect.fn(function* (ctx) {
|
|
17
|
+
const service = yield* Integration.Service;
|
|
18
|
+
return yield* response(service.get(ctx.params.integrationID));
|
|
19
|
+
})).handle("integration.wellknown.add", Effect.fn(function* (ctx) {
|
|
20
|
+
const wellknown = yield* WellKnown.Service, integration = yield* Integration.Service;
|
|
21
|
+
yield* wellknown.add(ctx.payload.url).pipe(Effect.mapError((error) => new InvalidRequestError({ message: error.message, kind: "well_known_discovery" })));
|
|
22
|
+
yield* integration.reload();
|
|
23
|
+
return HttpApiSchema.NoContent.make();
|
|
24
|
+
})).handle("integration.connect.key", Effect.fn(function* (ctx) {
|
|
25
|
+
const service = yield* Integration.Service;
|
|
26
|
+
yield* authorize(service.connection.key({
|
|
27
|
+
integrationID: ctx.params.integrationID,
|
|
28
|
+
key: ctx.payload.key,
|
|
29
|
+
answer: ctx.payload.answer,
|
|
30
|
+
label: ctx.payload.label
|
|
31
|
+
}));
|
|
32
|
+
return HttpApiSchema.NoContent.make();
|
|
33
|
+
})).handle("integration.oauth.connect", Effect.fn(function* (ctx) {
|
|
34
|
+
const service = yield* Integration.Service;
|
|
35
|
+
return yield* response(authorize(service.oauth.connect({
|
|
36
|
+
integrationID: ctx.params.integrationID,
|
|
37
|
+
methodID: ctx.payload.methodID,
|
|
38
|
+
answer: ctx.payload.answer,
|
|
39
|
+
label: ctx.payload.label
|
|
40
|
+
})));
|
|
41
|
+
})).handle("integration.oauth.status", Effect.fn(function* (ctx) {
|
|
42
|
+
const service = yield* Integration.Service;
|
|
43
|
+
return yield* response(service.oauth.status({
|
|
44
|
+
integrationID: ctx.params.integrationID,
|
|
45
|
+
attemptID: ctx.params.attemptID
|
|
46
|
+
}));
|
|
47
|
+
})).handle("integration.oauth.complete", Effect.fn(function* (ctx) {
|
|
48
|
+
yield* (yield* Integration.Service).oauth.complete({
|
|
49
|
+
integrationID: ctx.params.integrationID,
|
|
50
|
+
attemptID: ctx.params.attemptID,
|
|
51
|
+
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
|
+
})));
|
|
56
|
+
return HttpApiSchema.NoContent.make();
|
|
57
|
+
})).handle("integration.oauth.cancel", Effect.fn(function* (ctx) {
|
|
58
|
+
yield* (yield* Integration.Service).oauth.cancel({
|
|
59
|
+
integrationID: ctx.params.integrationID,
|
|
60
|
+
attemptID: ctx.params.attemptID
|
|
61
|
+
});
|
|
62
|
+
return HttpApiSchema.NoContent.make();
|
|
63
|
+
})).handle("integration.command.connect", Effect.fn(function* (ctx) {
|
|
64
|
+
const service = yield* Integration.Service;
|
|
65
|
+
return yield* response(authorize(service.command.connect({
|
|
66
|
+
integrationID: ctx.params.integrationID,
|
|
67
|
+
methodID: ctx.payload.methodID,
|
|
68
|
+
label: ctx.payload.label
|
|
69
|
+
})));
|
|
70
|
+
})).handle("integration.command.status", Effect.fn(function* (ctx) {
|
|
71
|
+
const service = yield* Integration.Service;
|
|
72
|
+
return yield* response(service.command.status({
|
|
73
|
+
integrationID: ctx.params.integrationID,
|
|
74
|
+
attemptID: ctx.params.attemptID
|
|
75
|
+
}));
|
|
76
|
+
})).handle("integration.command.cancel", Effect.fn(function* (ctx) {
|
|
77
|
+
yield* (yield* Integration.Service).command.cancel({
|
|
78
|
+
integrationID: ctx.params.integrationID,
|
|
79
|
+
attemptID: ctx.params.attemptID
|
|
80
|
+
});
|
|
81
|
+
return HttpApiSchema.NoContent.make();
|
|
82
|
+
}));
|
|
83
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const LocationHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.location">, never, import("@opencode-ai/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode-ai/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Location } from "@opencode-ai/core/location";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { HttpApiBuilder } from "effect/unstable/httpapi";
|
|
4
|
+
import { Api } from "../api";
|
|
5
|
+
export const LocationHandler = HttpApiBuilder.group(Api, "server.location", (handlers) => handlers.handle("location.get", Effect.fn(function* () {
|
|
6
|
+
const location = yield* Location.Service;
|
|
7
|
+
return new Location.Info({
|
|
8
|
+
directory: location.directory,
|
|
9
|
+
workspaceID: location.workspaceID,
|
|
10
|
+
project: location.project
|
|
11
|
+
});
|
|
12
|
+
})));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const McpHandler: import("effect/Layer").Layer<import("effect/unstable/httpapi/HttpApiGroup").Service<"server", "server.mcp">, never, import("@opencode-ai/protocol/middleware/schema-error").SchemaErrorMiddleware | import("@opencode-ai/protocol/middleware/authorization").Authorization | import("../location").LocationMiddleware>;
|