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