antechamber 0.0.0-stage → 0.1.0
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/CHANGELOG.md +143 -0
- package/LICENSE +22 -0
- package/README.md +316 -2
- package/bin/opencode-antechamber +18 -0
- package/bin/opencode-pi +3 -0
- package/dist/agent-dir.d.ts +6 -0
- package/dist/agent-dir.js +21 -0
- package/dist/agent-name.d.ts +24 -0
- package/dist/agent-name.js +110 -0
- package/dist/approvals.d.ts +86 -0
- package/dist/approvals.js +520 -0
- package/dist/catalog.d.ts +88 -0
- package/dist/catalog.js +118 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +86 -0
- package/dist/commands/context.d.ts +26 -0
- package/dist/commands/context.js +89 -0
- package/dist/commands/doctor.d.ts +13 -0
- package/dist/commands/doctor.js +92 -0
- package/dist/commands/help.d.ts +1 -0
- package/dist/commands/help.js +15 -0
- package/dist/commands/serve.d.ts +8 -0
- package/dist/commands/serve.js +29 -0
- package/dist/commands/setup.d.ts +14 -0
- package/dist/commands/setup.js +137 -0
- package/dist/config.d.ts +18 -0
- package/dist/config.js +40 -0
- package/dist/http.d.ts +18 -0
- package/dist/http.js +168 -0
- package/dist/lifecycle.d.ts +43 -0
- package/dist/lifecycle.js +138 -0
- package/dist/misc-routes.d.ts +8 -0
- package/dist/misc-routes.js +119 -0
- package/dist/pi-event-translation.d.ts +65 -0
- package/dist/pi-event-translation.js +545 -0
- package/dist/pi-rpc.d.ts +68 -0
- package/dist/pi-rpc.js +285 -0
- package/dist/pidfd.d.ts +2 -0
- package/dist/pidfd.js +28 -0
- package/dist/question-forms.d.ts +30 -0
- package/dist/question-forms.js +46 -0
- package/dist/route-services.d.ts +26 -0
- package/dist/route-services.js +33 -0
- package/dist/routes-v1.d.ts +4 -0
- package/dist/routes-v1.js +346 -0
- package/dist/routes-v2.d.ts +4 -0
- package/dist/routes-v2.js +477 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.js +113 -0
- package/dist/session-commands.d.ts +75 -0
- package/dist/session-commands.js +323 -0
- package/dist/session-diff.d.ts +14 -0
- package/dist/session-diff.js +152 -0
- package/dist/session-history.d.ts +35 -0
- package/dist/session-history.js +416 -0
- package/dist/session-hosts.d.ts +3 -0
- package/dist/session-hosts.js +188 -0
- package/dist/session-store.d.ts +103 -0
- package/dist/session-store.js +339 -0
- package/dist/session-tree.d.ts +59 -0
- package/dist/session-tree.js +324 -0
- package/dist/sessions.d.ts +174 -0
- package/dist/sessions.js +1141 -0
- package/dist/sse.d.ts +19 -0
- package/dist/sse.js +92 -0
- package/dist/subagents.d.ts +64 -0
- package/dist/subagents.js +621 -0
- package/dist/thinking-levels.d.ts +17 -0
- package/dist/thinking-levels.js +24 -0
- package/dist/todo-bridge.d.ts +26 -0
- package/dist/todo-bridge.js +100 -0
- package/dist/tool-map.d.ts +32 -0
- package/dist/tool-map.js +349 -0
- package/dist/types.d.ts +338 -0
- package/dist/types.js +6 -0
- package/dist/v2.d.ts +190 -0
- package/dist/v2.js +553 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +13 -0
- package/extensions/omo-dag/README.md +159 -0
- package/extensions/omo-dag/docs/DESIGN.md +105 -0
- package/extensions/omo-dag/icon.svg +1 -0
- package/extensions/omo-dag/package.json +33 -0
- package/extensions/omo-dag/panel/index.html +179 -0
- package/extensions/omo-dag/panel/main.js +176 -0
- package/extensions/omo-dag/service/main.js +378 -0
- package/package.json +77 -4
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
/** OpenCode v1 routes, using the services composed by AdapterServer. */
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { errorBody, json } from "./http.js";
|
|
5
|
+
import { miscRoute } from "./misc-routes.js";
|
|
6
|
+
import { getAgentName, getExposedAgentNames } from "./agent-name.js";
|
|
7
|
+
import { agentDefaults } from "./catalog.js";
|
|
8
|
+
import { announceSessionError, compactSession, getCommands, parseShellCommand, parseSlashCommand, runShellCommand, runSlashCommand, unsupportedShare, } from "./session-commands.js";
|
|
9
|
+
import { modelRefFromBody, OPENCODE_COMPAT_VERSION, promptAsync } from "./route-services.js";
|
|
10
|
+
/**
|
|
11
|
+
* `archived` list filter per SDK v2 (`boolean | "true" | "false"`):
|
|
12
|
+
* "true" keeps only archived sessions, "false" only live ones, absent = all.
|
|
13
|
+
*/
|
|
14
|
+
function applyArchivedFilter(sessions, archived) {
|
|
15
|
+
if (archived === "true")
|
|
16
|
+
return sessions.filter((s) => s.time.archived !== undefined);
|
|
17
|
+
if (archived === "false")
|
|
18
|
+
return sessions.filter((s) => s.time.archived === undefined);
|
|
19
|
+
return sessions;
|
|
20
|
+
}
|
|
21
|
+
export async function handleV1(services, req, res, url, path, method, directory) {
|
|
22
|
+
if (method === "GET" && path === "/global/health") {
|
|
23
|
+
json(res, 200, OPENCODE_COMPAT_VERSION === null ? { healthy: true } : { healthy: true, version: OPENCODE_COMPAT_VERSION });
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
// There is no opencode install behind this endpoint to upgrade: the adapter
|
|
27
|
+
// speaks the OpenCode API itself. Answer instead of 404 so a direct upgrade
|
|
28
|
+
// call gets a clear reason rather than a bare HTTP status.
|
|
29
|
+
if ((method === "POST" || method === "GET") && path === "/global/upgrade") {
|
|
30
|
+
json(res, 409, errorBody("UnsupportedError", "This endpoint is served by antechamber (a pi adapter), not a real opencode install — there is nothing to upgrade."));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// --- sessions ---
|
|
34
|
+
const misc = await miscRoute(method, path, url, directory);
|
|
35
|
+
if (misc !== undefined) {
|
|
36
|
+
json(res, misc.status, misc.body);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (path === "/session" && method === "POST") {
|
|
40
|
+
const body = (await services.body(req));
|
|
41
|
+
json(res, 200, await services.sessions.create(directory, body.title, body.parentID));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (path === "/session" && method === "GET") {
|
|
45
|
+
const dir = url.searchParams.get("directory") ?? undefined;
|
|
46
|
+
let sessions = services.sessions.list(dir);
|
|
47
|
+
sessions = applyArchivedFilter(sessions, url.searchParams.get("archived"));
|
|
48
|
+
json(res, 200, sessions);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (path === "/session/status" && method === "GET") {
|
|
52
|
+
json(res, 200, services.sessions.statuses());
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const sessionMatch = path.match(/^\/session\/([^/]+)(\/.*)?$/);
|
|
56
|
+
if (sessionMatch) {
|
|
57
|
+
const [, sessionId, sub] = sessionMatch;
|
|
58
|
+
if (sessionId === undefined) {
|
|
59
|
+
json(res, 404, errorBody("NotFoundError", `session not found: ${sessionId}`));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const managed = services.sessions.get(sessionId);
|
|
63
|
+
if (!managed) {
|
|
64
|
+
json(res, 404, errorBody("NotFoundError", `session not found: ${sessionId}`));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
switch (`${method} ${sub ?? ""}`) {
|
|
68
|
+
case "GET /diff":
|
|
69
|
+
json(res, 200, await services.sessions.diff(sessionId));
|
|
70
|
+
return;
|
|
71
|
+
case "GET ":
|
|
72
|
+
json(res, 200, managed.info);
|
|
73
|
+
return;
|
|
74
|
+
case "PATCH ": {
|
|
75
|
+
const body = (await services.body(req));
|
|
76
|
+
json(res, 200, services.sessions.update(sessionId, { title: body.title, archived: body.time?.archived }));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
case "DELETE ":
|
|
80
|
+
json(res, 200, await services.sessions.remove(sessionId));
|
|
81
|
+
return;
|
|
82
|
+
case "GET /message":
|
|
83
|
+
json(res, 200, services.sessions.messages(sessionId));
|
|
84
|
+
return;
|
|
85
|
+
case "GET /todo":
|
|
86
|
+
json(res, 200, services.sessions.todos(sessionId));
|
|
87
|
+
return;
|
|
88
|
+
case "POST /prompt_async": {
|
|
89
|
+
const body = (await services.body(req));
|
|
90
|
+
const text = (body.parts ?? [])
|
|
91
|
+
.filter((p) => p.type === "text" && typeof p.text === "string")
|
|
92
|
+
.map((p) => p.text ?? "")
|
|
93
|
+
.join("\n");
|
|
94
|
+
const model = modelRefFromBody(body.model ?? (body.variant !== undefined ? managed.model : undefined), body.variant);
|
|
95
|
+
promptAsync(services, managed, text, model, body.noReply, body.messageID);
|
|
96
|
+
res.writeHead(204).end();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
case "POST /message": {
|
|
100
|
+
const body = (await services.body(req));
|
|
101
|
+
const text = (body.parts ?? [])
|
|
102
|
+
.filter((p) => p.type === "text" && typeof p.text === "string")
|
|
103
|
+
.map((p) => p.text ?? "")
|
|
104
|
+
.join("\n");
|
|
105
|
+
const model = modelRefFromBody(body.model ?? (body.variant !== undefined ? managed.model : undefined), body.variant);
|
|
106
|
+
await services.sessions.prompt(sessionId, text, model, body.noReply, body.messageID);
|
|
107
|
+
const msgs = services.sessions.messages(sessionId) ?? [];
|
|
108
|
+
json(res, 200, msgs[msgs.length - 1] ?? null);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
case "POST /abort":
|
|
112
|
+
json(res, 200, await services.sessions.abort(sessionId));
|
|
113
|
+
return;
|
|
114
|
+
case "POST /fork":
|
|
115
|
+
case "POST /revert":
|
|
116
|
+
case "POST /unrevert": {
|
|
117
|
+
const body = await services.body(req);
|
|
118
|
+
const messageID = body !== null && typeof body === "object" && "messageID" in body ? body.messageID : undefined;
|
|
119
|
+
if ((sub === "/revert" && (typeof messageID !== "string" || messageID === "")) ||
|
|
120
|
+
(sub === "/fork" && messageID !== undefined && (typeof messageID !== "string" || messageID === ""))) {
|
|
121
|
+
json(res, 400, errorBody("InvalidRequest", "messageID must be a nonempty string"));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const info = sub === "/fork"
|
|
126
|
+
? await services.sessions.fork(sessionId, typeof messageID === "string" ? messageID : undefined)
|
|
127
|
+
: sub === "/revert"
|
|
128
|
+
? await services.sessions.revert(sessionId, String(messageID))
|
|
129
|
+
: await services.sessions.unrevert(sessionId);
|
|
130
|
+
json(res, 200, info);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
json(res, 400, errorBody("SessionTreeError", error instanceof Error ? error.message : String(error)));
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
case "POST /summarize": {
|
|
138
|
+
await services.body(req);
|
|
139
|
+
const result = await compactSession(services.sessions, sessionId);
|
|
140
|
+
if (result.kind === "error") {
|
|
141
|
+
announceSessionError({ sessions: services.sessions, session: managed, emit: services.broadcast }, "BadRequestError", result.message);
|
|
142
|
+
json(res, 400, errorBody("BadRequestError", result.message));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
json(res, 200, true);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
case "POST /shell": {
|
|
149
|
+
const command = parseShellCommand(await services.body(req));
|
|
150
|
+
if (command === undefined) {
|
|
151
|
+
json(res, 400, errorBody("BadRequestError", "command is required"));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const managed = services.sessions.get(sessionId);
|
|
155
|
+
if (!managed) {
|
|
156
|
+
json(res, 404, errorBody("NotFoundError", `session not found: ${sessionId}`));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (managed.status.type !== "idle") {
|
|
160
|
+
json(res, 409, errorBody("SessionBusyError", "session is busy"));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const result = await runShellCommand({
|
|
164
|
+
sessions: services.sessions,
|
|
165
|
+
session: managed,
|
|
166
|
+
command,
|
|
167
|
+
emit: services.broadcast,
|
|
168
|
+
});
|
|
169
|
+
if (result.kind === "error") {
|
|
170
|
+
json(res, 400, errorBody("BadRequestError", result.message));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
json(res, 200, result.message.info);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
case "POST /command": {
|
|
177
|
+
const input = parseSlashCommand(await services.body(req));
|
|
178
|
+
if (input === undefined) {
|
|
179
|
+
json(res, 400, errorBody("BadRequestError", "command is required"));
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const message = await runSlashCommand(services.sessions, sessionId, input);
|
|
183
|
+
json(res, 200, message === undefined ? { info: null, parts: [] } : { info: message.info, parts: message.parts });
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
case "POST /share":
|
|
187
|
+
case "DELETE /share": {
|
|
188
|
+
const session = services.sessions.get(sessionId);
|
|
189
|
+
if (session)
|
|
190
|
+
announceSessionError({ sessions: services.sessions, session, emit: services.broadcast }, unsupportedShare.name, unsupportedShare.data.message);
|
|
191
|
+
json(res, 400, errorBody(unsupportedShare.name, unsupportedShare.data.message));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
default:
|
|
195
|
+
json(res, 501, errorBody("NotImplemented", `${method} ${path} not implemented (M1)`));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// --- project / config ---
|
|
200
|
+
if (path === "/project/current" && method === "GET") {
|
|
201
|
+
json(res, 200, { id: directory, worktree: directory, time: { created: Date.now() } });
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (path === "/project" && method === "GET") {
|
|
205
|
+
json(res, 200, [{ id: directory, worktree: directory, time: { created: Date.now() } }]);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if ((path === "/config" || path === "/global/config") && method === "GET") {
|
|
209
|
+
json(res, 200, { default_agent: getAgentName() });
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
// --- model catalog (from pi) ---
|
|
213
|
+
if (path === "/provider" && method === "GET") {
|
|
214
|
+
const cat = await services.catalog();
|
|
215
|
+
json(res, 200, { all: cat.providers, default: cat.defaults, connected: cat.providers.map((p) => p.id) });
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (path === "/config/providers" && method === "GET") {
|
|
219
|
+
const cat = await services.catalog();
|
|
220
|
+
json(res, 200, { providers: cat.providers, default: cat.defaults });
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
// --- bootstrap probes OpenChamber expects to exist ---
|
|
224
|
+
if (path === "/experimental/session" && method === "GET") {
|
|
225
|
+
// OpenChamber page-loads the sidebar through this route (not /session) with
|
|
226
|
+
// ?directory=…&archived=…&roots=…&limit=…. Honor directory/roots/archived:
|
|
227
|
+
// ignoring them left the sidebar with only live sessions, so restored
|
|
228
|
+
// history never appeared after a restart. archived=false excludes archived
|
|
229
|
+
// sessions; archived=true includes them so the UI can partition both lists.
|
|
230
|
+
const directoryParam = url.searchParams.get("directory") ?? req.headers["x-opencode-directory"];
|
|
231
|
+
const rootsOnly = url.searchParams.get("roots") === "true";
|
|
232
|
+
let sessions = directoryParam !== undefined && directoryParam !== ""
|
|
233
|
+
? services.sessions.list(directoryParam)
|
|
234
|
+
: services.sessions.listAll();
|
|
235
|
+
if (rootsOnly)
|
|
236
|
+
sessions = sessions.filter((s) => s.parentID === undefined);
|
|
237
|
+
// Experimental lists use archived=true to INCLUDE archived sessions.
|
|
238
|
+
// The UI partitions this result itself; filtering to archived-only drops
|
|
239
|
+
// the current live session from the header's global metadata store.
|
|
240
|
+
if (url.searchParams.get("archived") === "false") {
|
|
241
|
+
sessions = sessions.filter((s) => s.time.archived === undefined);
|
|
242
|
+
}
|
|
243
|
+
json(res, 200, sessions);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (path === "/question" && method === "GET") {
|
|
247
|
+
json(res, 200, services.sessions.questions());
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (path === "/permission" && method === "GET") {
|
|
251
|
+
json(res, 200, services.sessions.permissions());
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const questionReply = path.match(/^\/question\/([^/]+)\/reply$/);
|
|
255
|
+
if (questionReply && method === "POST") {
|
|
256
|
+
const requestID = decodeURIComponent(questionReply[1]);
|
|
257
|
+
const body = (await services.body(req));
|
|
258
|
+
const pending = services.sessions.questions().find((question) => question.id === requestID);
|
|
259
|
+
if (!pending) {
|
|
260
|
+
json(res, 404, errorBody("QuestionNotFoundError", `question not found: ${requestID}`));
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (!(await services.sessions.replyQuestion(pending.sessionID, requestID, body.answers ?? [], body.comment))) {
|
|
264
|
+
json(res, 409, errorBody("QuestionReplyError", "native question response refused"));
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
json(res, 200, true);
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
const questionReject = path.match(/^\/question\/([^/]+)\/reject$/);
|
|
271
|
+
if (questionReject && method === "POST") {
|
|
272
|
+
const requestID = decodeURIComponent(questionReject[1]);
|
|
273
|
+
const pending = services.sessions.questions().find((question) => question.id === requestID);
|
|
274
|
+
if (!pending) {
|
|
275
|
+
json(res, 404, errorBody("QuestionNotFoundError", `question not found: ${requestID}`));
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (!(await services.sessions.rejectQuestion(pending.sessionID, requestID))) {
|
|
279
|
+
json(res, 409, errorBody("QuestionReplyError", "native question cancellation refused"));
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
json(res, 200, true);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const permissionReply = path.match(/^\/permission\/([^/]+)\/reply$/);
|
|
286
|
+
if (permissionReply && method === "POST") {
|
|
287
|
+
const requestID = decodeURIComponent(permissionReply[1]);
|
|
288
|
+
const body = (await services.body(req));
|
|
289
|
+
const pending = services.sessions.permissions().find((permission) => permission.id === requestID);
|
|
290
|
+
if (!pending ||
|
|
291
|
+
!body.reply ||
|
|
292
|
+
!services.sessions.replyPermission(pending.sessionID, requestID, body.reply, body.message)) {
|
|
293
|
+
json(res, 404, errorBody("PermissionNotFoundError", `permission not found: ${requestID}`));
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
json(res, 200, true);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (path === "/lsp" && method === "GET") {
|
|
300
|
+
json(res, 200, []);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (path === "/formatter" && method === "GET") {
|
|
304
|
+
json(res, 200, []);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (path === "/mcp" && method === "GET") {
|
|
308
|
+
json(res, 200, {});
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (path === "/command" && method === "GET") {
|
|
312
|
+
json(res, 200, await getCommands(directory));
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (path === "/path" && method === "GET") {
|
|
316
|
+
json(res, 200, { home: homedir(), state: "", config: "", worktree: directory, directory });
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (path === "/vcs" && method === "GET") {
|
|
320
|
+
execFile("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd: directory, timeout: 3000 }, (err, stdout) => {
|
|
321
|
+
const branch = err ? undefined : stdout.trim() || undefined;
|
|
322
|
+
json(res, 200, branch === undefined ? {} : { branch });
|
|
323
|
+
});
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (path === "/agent" && method === "GET") {
|
|
327
|
+
// pi has one agent; publish OpenChamber's conventional `build` primary
|
|
328
|
+
// agent next to pi's own name so the picker — and its default resolution,
|
|
329
|
+
// which looks for `build` — has a real option. Both names run the same
|
|
330
|
+
// pi agent (see getExposedAgentNames).
|
|
331
|
+
const piName = getAgentName();
|
|
332
|
+
const defaults = agentDefaults(await services.catalog());
|
|
333
|
+
json(res, 200, getExposedAgentNames().map((name) => ({
|
|
334
|
+
name,
|
|
335
|
+
description: name === piName
|
|
336
|
+
? `${piName} (pi coding agent via antechamber)`
|
|
337
|
+
: `${name} — ${piName} (pi coding agent via antechamber)`,
|
|
338
|
+
mode: "primary",
|
|
339
|
+
hidden: name === "build" && piName !== "build",
|
|
340
|
+
options: {},
|
|
341
|
+
...defaults,
|
|
342
|
+
})));
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
json(res, 404, errorBody("NotFoundError", `no route: ${method} ${path}`));
|
|
346
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** OpenCode v2 (/api/*) routes and their response adapters. */
|
|
2
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
3
|
+
import { type RouteServices } from "./route-services.js";
|
|
4
|
+
export declare function handleV2(services: RouteServices, req: IncomingMessage, res: ServerResponse, url: URL, path: string, method: string, directory: string): Promise<void>;
|