harness-dispatch 0.5.0 → 0.6.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 +152 -0
- package/README.md +5 -2
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +1 -175
- package/dist/bin.js.map +1 -1
- package/dist/config/route-fields.d.ts +72 -0
- package/dist/config/route-fields.d.ts.map +1 -0
- package/dist/config/route-fields.js +128 -0
- package/dist/config/route-fields.js.map +1 -0
- package/dist/config/validation.js +1 -1
- package/dist/config/validation.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +32 -171
- package/dist/config.js.map +1 -1
- package/dist/configure-yaml.d.ts +23 -0
- package/dist/configure-yaml.d.ts.map +1 -0
- package/dist/configure-yaml.js +193 -0
- package/dist/configure-yaml.js.map +1 -0
- package/dist/dispatchers/base.d.ts +3 -0
- package/dist/dispatchers/base.d.ts.map +1 -1
- package/dist/dispatchers/base.js.map +1 -1
- package/dist/dispatchers/generic-cli.d.ts.map +1 -1
- package/dist/dispatchers/generic-cli.js +4 -0
- package/dist/dispatchers/generic-cli.js.map +1 -1
- package/dist/dispatchers/openai-compatible.d.ts.map +1 -1
- package/dist/dispatchers/openai-compatible.js +18 -0
- package/dist/dispatchers/openai-compatible.js.map +1 -1
- package/dist/dispatchers/shared/stream-subprocess.d.ts +11 -0
- package/dist/dispatchers/shared/stream-subprocess.d.ts.map +1 -1
- package/dist/dispatchers/shared/stream-subprocess.js +57 -35
- package/dist/dispatchers/shared/stream-subprocess.js.map +1 -1
- package/dist/http/parse.d.ts +64 -0
- package/dist/http/parse.d.ts.map +1 -0
- package/dist/http/parse.js +230 -0
- package/dist/http/parse.js.map +1 -0
- package/dist/http/server.d.ts +2 -11
- package/dist/http/server.d.ts.map +1 -1
- package/dist/http/server.js +26 -232
- package/dist/http/server.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/jobs/context.d.ts +17 -0
- package/dist/jobs/context.d.ts.map +1 -0
- package/dist/jobs/context.js +84 -0
- package/dist/jobs/context.js.map +1 -0
- package/dist/jobs/store.d.ts +80 -0
- package/dist/jobs/store.d.ts.map +1 -0
- package/dist/jobs/store.js +279 -0
- package/dist/jobs/store.js.map +1 -0
- package/dist/jobs/types.d.ts +135 -0
- package/dist/jobs/types.d.ts.map +1 -0
- package/dist/jobs/types.js +11 -0
- package/dist/jobs/types.js.map +1 -0
- package/dist/jobs.d.ts +113 -123
- package/dist/jobs.d.ts.map +1 -1
- package/dist/jobs.js +314 -309
- package/dist/jobs.js.map +1 -1
- package/dist/mcp/tool-schemas.d.ts +194 -0
- package/dist/mcp/tool-schemas.d.ts.map +1 -0
- package/dist/mcp/tool-schemas.js +311 -0
- package/dist/mcp/tool-schemas.js.map +1 -0
- package/dist/mcp/tools.d.ts +15 -59
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +63 -239
- package/dist/mcp/tools.js.map +1 -1
- package/dist/quota.d.ts +19 -1
- package/dist/quota.d.ts.map +1 -1
- package/dist/quota.js +39 -4
- package/dist/quota.js.map +1 -1
- package/dist/router.d.ts +4 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +8 -0
- package/dist/router.js.map +1 -1
- package/dist/status.d.ts +13 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +6 -0
- package/dist/status.js.map +1 -1
- package/dist/types.d.ts +24 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/workspace-resolve.d.ts +98 -0
- package/dist/workspace-resolve.d.ts.map +1 -0
- package/dist/workspace-resolve.js +382 -0
- package/dist/workspace-resolve.js.map +1 -0
- package/dist/workspaces.d.ts +1 -0
- package/dist/workspaces.d.ts.map +1 -1
- package/dist/workspaces.js +67 -15
- package/dist/workspaces.js.map +1 -1
- package/package.json +5 -4
- package/dist/dashboard/live.d.ts +0 -49
- package/dist/dashboard/live.d.ts.map +0 -1
- package/dist/dashboard/live.js +0 -149
- package/dist/dashboard/live.js.map +0 -1
|
@@ -148,6 +148,12 @@ function realStreamSubprocess(command, args, opts) {
|
|
|
148
148
|
terminateChild("SIGTERM");
|
|
149
149
|
}, timeoutMs);
|
|
150
150
|
timer.unref();
|
|
151
|
+
if (opts.signal) {
|
|
152
|
+
if (opts.signal.aborted)
|
|
153
|
+
terminateChild("SIGTERM");
|
|
154
|
+
else
|
|
155
|
+
opts.signal.addEventListener("abort", () => terminateChild("SIGTERM"), { once: true });
|
|
156
|
+
}
|
|
151
157
|
child.stdout?.on("data", (buf) => {
|
|
152
158
|
if (truncated)
|
|
153
159
|
return;
|
|
@@ -205,43 +211,59 @@ function realStreamSubprocess(command, args, opts) {
|
|
|
205
211
|
});
|
|
206
212
|
finish();
|
|
207
213
|
});
|
|
214
|
+
// The three iterator methods, named rather than written inline.
|
|
215
|
+
//
|
|
216
|
+
// They used to sit three object/function literals deep inside
|
|
217
|
+
// buildIterable, which put the ordinary queue check at brace depth 8 — the
|
|
218
|
+
// deepest point in the codebase, for logic that is not complicated. None of
|
|
219
|
+
// them uses `this`, so they lift straight out and the nesting was pure
|
|
220
|
+
// syntax.
|
|
221
|
+
/** Next buffered event, the terminal state, or a promise a writer resolves. */
|
|
222
|
+
function nextEvent() {
|
|
223
|
+
if (queue.length > 0) {
|
|
224
|
+
const evt = queue.shift();
|
|
225
|
+
return Promise.resolve({ value: evt, done: false });
|
|
226
|
+
}
|
|
227
|
+
if (done) {
|
|
228
|
+
if (errored)
|
|
229
|
+
return Promise.reject(errored);
|
|
230
|
+
return Promise.resolve({ value: undefined, done: true });
|
|
231
|
+
}
|
|
232
|
+
return new Promise((resolve, reject) => {
|
|
233
|
+
waiters.push({ resolve, reject });
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Consumer abandoned the stream (a `break` in a for-await). Kill the child
|
|
238
|
+
* and release every waiter — leaving one pending would hang the caller.
|
|
239
|
+
*/
|
|
240
|
+
function stopIteration() {
|
|
241
|
+
if (!settled)
|
|
242
|
+
terminateChild("SIGTERM");
|
|
243
|
+
done = true;
|
|
244
|
+
while (waiters.length > 0) {
|
|
245
|
+
const w = waiters.shift();
|
|
246
|
+
if (w)
|
|
247
|
+
w.resolve({ value: undefined, done: true });
|
|
248
|
+
}
|
|
249
|
+
return Promise.resolve({ value: undefined, done: true });
|
|
250
|
+
}
|
|
251
|
+
/** Consumer threw into the stream: same teardown, propagate the error. */
|
|
252
|
+
function failIteration(err) {
|
|
253
|
+
if (!settled)
|
|
254
|
+
terminateChild("SIGTERM");
|
|
255
|
+
done = true;
|
|
256
|
+
return Promise.reject(err);
|
|
257
|
+
}
|
|
208
258
|
function buildIterable() {
|
|
259
|
+
// A fresh iterator object per call, as before — they share the one queue
|
|
260
|
+
// either way, so this stream has always been single-consumer.
|
|
209
261
|
return {
|
|
210
|
-
[Symbol.asyncIterator]() {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
return Promise.resolve({ value: evt, done: false });
|
|
216
|
-
}
|
|
217
|
-
if (done) {
|
|
218
|
-
if (errored)
|
|
219
|
-
return Promise.reject(errored);
|
|
220
|
-
return Promise.resolve({ value: undefined, done: true });
|
|
221
|
-
}
|
|
222
|
-
return new Promise((resolve, reject) => {
|
|
223
|
-
waiters.push({ resolve, reject });
|
|
224
|
-
});
|
|
225
|
-
},
|
|
226
|
-
return() {
|
|
227
|
-
if (!settled)
|
|
228
|
-
terminateChild("SIGTERM");
|
|
229
|
-
done = true;
|
|
230
|
-
while (waiters.length > 0) {
|
|
231
|
-
const w = waiters.shift();
|
|
232
|
-
if (w)
|
|
233
|
-
w.resolve({ value: undefined, done: true });
|
|
234
|
-
}
|
|
235
|
-
return Promise.resolve({ value: undefined, done: true });
|
|
236
|
-
},
|
|
237
|
-
throw(err) {
|
|
238
|
-
if (!settled)
|
|
239
|
-
terminateChild("SIGTERM");
|
|
240
|
-
done = true;
|
|
241
|
-
return Promise.reject(err);
|
|
242
|
-
},
|
|
243
|
-
};
|
|
244
|
-
},
|
|
262
|
+
[Symbol.asyncIterator]: () => ({
|
|
263
|
+
next: nextEvent,
|
|
264
|
+
return: stopIteration,
|
|
265
|
+
throw: failIteration,
|
|
266
|
+
}),
|
|
245
267
|
};
|
|
246
268
|
}
|
|
247
269
|
return buildIterable();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream-subprocess.js","sourceRoot":"","sources":["../../../src/dispatchers/shared/stream-subprocess.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,MAAM,aAAa,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAyB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"stream-subprocess.js","sourceRoot":"","sources":["../../../src/dispatchers/shared/stream-subprocess.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsing an OpenAI-style request into something the router can act on.
|
|
3
|
+
*
|
|
4
|
+
* Split out of http/server.ts, which mixed this with transport wiring. The
|
|
5
|
+
* separation is worth making because this file is the HTTP surface's half of
|
|
6
|
+
* the safety boundary, and it has repeatedly been the half that drifted: the
|
|
7
|
+
* MCP tool rejected an unknown fanout target by name while this one silently
|
|
8
|
+
* returned fewer arms, capped context files while this one accepted an
|
|
9
|
+
* unbounded list, and rejected misplaced hint keys while this one ignored
|
|
10
|
+
* them. Every one of those was found as "same input, two answers".
|
|
11
|
+
*
|
|
12
|
+
* Anything rejected here must be rejected the same way the MCP schema
|
|
13
|
+
* rejects it (see mcp/tool-schemas.ts). BadRequestError is what maps a
|
|
14
|
+
* refusal to HTTP 400 rather than letting it fail later as a 500.
|
|
15
|
+
*/
|
|
16
|
+
import type { IncomingMessage } from "node:http";
|
|
17
|
+
import type { RouteHints } from "../types.js";
|
|
18
|
+
/** Raised for anything the caller can fix; mapped to HTTP 400 by the server. */
|
|
19
|
+
export declare class PayloadTooLargeError extends Error {
|
|
20
|
+
}
|
|
21
|
+
export interface ChatMessage {
|
|
22
|
+
role?: unknown;
|
|
23
|
+
content?: unknown;
|
|
24
|
+
}
|
|
25
|
+
export interface ChatRequest {
|
|
26
|
+
model?: unknown;
|
|
27
|
+
messages?: unknown;
|
|
28
|
+
prompt?: unknown;
|
|
29
|
+
stream?: unknown;
|
|
30
|
+
workingDir?: unknown;
|
|
31
|
+
files?: unknown;
|
|
32
|
+
mode?: unknown;
|
|
33
|
+
models?: unknown;
|
|
34
|
+
hints?: unknown;
|
|
35
|
+
safetyProfile?: unknown;
|
|
36
|
+
workspacePolicy?: unknown;
|
|
37
|
+
}
|
|
38
|
+
export declare const MAX_REQUEST_BODY_BYTES: number;
|
|
39
|
+
/**
|
|
40
|
+
* A request the CALLER can fix — malformed JSON, a missing required field, a
|
|
41
|
+
* working directory that does not exist.
|
|
42
|
+
*
|
|
43
|
+
* Everything except the 413 was returned as 500. PRODUCT.md names CI and cron
|
|
44
|
+
* as consumers of this surface, and retry-on-5xx will happily retry a request
|
|
45
|
+
* that can never succeed. A 4xx says "stop and fix the request", which is the
|
|
46
|
+
* true statement.
|
|
47
|
+
*/
|
|
48
|
+
export declare class BadRequestError extends Error {
|
|
49
|
+
}
|
|
50
|
+
/** Mirrors MAX_CONTEXT_FILES in mcp/tools.ts — the two surfaces must agree. */
|
|
51
|
+
export declare const MAX_CONTEXT_FILES_HTTP = 64;
|
|
52
|
+
export declare function readJson(req: IncomingMessage, maxBytes?: number): Promise<unknown>;
|
|
53
|
+
export declare function parseChatRequest(raw: unknown): {
|
|
54
|
+
prompt: string;
|
|
55
|
+
files: string[];
|
|
56
|
+
workingDir: string;
|
|
57
|
+
workingDirWarning?: string;
|
|
58
|
+
stream: boolean;
|
|
59
|
+
mode: "single" | "fanout";
|
|
60
|
+
models: string[];
|
|
61
|
+
hints: RouteHints;
|
|
62
|
+
};
|
|
63
|
+
export declare function completionEnvelope(content: string, model: string, extra: Record<string, unknown>): Record<string, unknown>;
|
|
64
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/http/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAGjD,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,aAAa,CAAC;AAG/D,gFAAgF;AAChF,qBAAa,oBAAqB,SAAQ,KAAK;CAAG;AAElD,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAKD,eAAO,MAAM,sBAAsB,QAAmB,CAAC;AAEvD;;;;;;;;GAQG;AACH,qBAAa,eAAgB,SAAQ,KAAK;CAAG;AAE7C,+EAA+E;AAC/E,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,eAAe,EACpB,QAAQ,GAAE,MAA+B,GACxC,OAAO,CAAC,OAAO,CAAC,CAwBlB;AAsHD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,UAAU,CAAC;CACnB,CAmDA;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAezB"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsing an OpenAI-style request into something the router can act on.
|
|
3
|
+
*
|
|
4
|
+
* Split out of http/server.ts, which mixed this with transport wiring. The
|
|
5
|
+
* separation is worth making because this file is the HTTP surface's half of
|
|
6
|
+
* the safety boundary, and it has repeatedly been the half that drifted: the
|
|
7
|
+
* MCP tool rejected an unknown fanout target by name while this one silently
|
|
8
|
+
* returned fewer arms, capped context files while this one accepted an
|
|
9
|
+
* unbounded list, and rejected misplaced hint keys while this one ignored
|
|
10
|
+
* them. Every one of those was found as "same input, two answers".
|
|
11
|
+
*
|
|
12
|
+
* Anything rejected here must be rejected the same way the MCP schema
|
|
13
|
+
* rejects it (see mcp/tool-schemas.ts). BadRequestError is what maps a
|
|
14
|
+
* refusal to HTTP 400 rather than letting it fail later as a 500.
|
|
15
|
+
*/
|
|
16
|
+
import { randomUUID } from "node:crypto";
|
|
17
|
+
import { resolveWorkingDir, validateWorkingDir, workingDirWarning } from "../working-dir.js";
|
|
18
|
+
/** Raised for anything the caller can fix; mapped to HTTP 400 by the server. */
|
|
19
|
+
export class PayloadTooLargeError extends Error {
|
|
20
|
+
}
|
|
21
|
+
// Local-only server, but still worth bounding: an unbounded body read lets
|
|
22
|
+
// any authorized (or, if --host is opened beyond loopback, network-adjacent)
|
|
23
|
+
// caller exhaust process memory with one oversized POST.
|
|
24
|
+
export const MAX_REQUEST_BODY_BYTES = 10 * 1024 * 1024;
|
|
25
|
+
/**
|
|
26
|
+
* A request the CALLER can fix — malformed JSON, a missing required field, a
|
|
27
|
+
* working directory that does not exist.
|
|
28
|
+
*
|
|
29
|
+
* Everything except the 413 was returned as 500. PRODUCT.md names CI and cron
|
|
30
|
+
* as consumers of this surface, and retry-on-5xx will happily retry a request
|
|
31
|
+
* that can never succeed. A 4xx says "stop and fix the request", which is the
|
|
32
|
+
* true statement.
|
|
33
|
+
*/
|
|
34
|
+
export class BadRequestError extends Error {
|
|
35
|
+
}
|
|
36
|
+
/** Mirrors MAX_CONTEXT_FILES in mcp/tools.ts — the two surfaces must agree. */
|
|
37
|
+
export const MAX_CONTEXT_FILES_HTTP = 64;
|
|
38
|
+
export async function readJson(req, maxBytes = MAX_REQUEST_BODY_BYTES) {
|
|
39
|
+
const chunks = [];
|
|
40
|
+
let total = 0;
|
|
41
|
+
for await (const chunk of req) {
|
|
42
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
43
|
+
total += buf.length;
|
|
44
|
+
if (total > maxBytes) {
|
|
45
|
+
// Don't destroy() the socket here — that races with the 413 response
|
|
46
|
+
// write and the client sees a connection reset instead of a clean
|
|
47
|
+
// status code. Just stop buffering (the memory-exhaustion risk this
|
|
48
|
+
// guards against) and let the normal response path write the 413.
|
|
49
|
+
throw new PayloadTooLargeError(`request body exceeds ${maxBytes} bytes`);
|
|
50
|
+
}
|
|
51
|
+
chunks.push(buf);
|
|
52
|
+
}
|
|
53
|
+
const text = Buffer.concat(chunks).toString("utf-8");
|
|
54
|
+
if (!text.trim())
|
|
55
|
+
return {};
|
|
56
|
+
try {
|
|
57
|
+
return JSON.parse(text);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
throw new BadRequestError(`request body is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function contentToText(content) {
|
|
64
|
+
if (typeof content === "string")
|
|
65
|
+
return content;
|
|
66
|
+
if (Array.isArray(content)) {
|
|
67
|
+
return content
|
|
68
|
+
.map((part) => {
|
|
69
|
+
if (typeof part === "string")
|
|
70
|
+
return part;
|
|
71
|
+
if (part && typeof part === "object" && "text" in part) {
|
|
72
|
+
const text = part.text;
|
|
73
|
+
return typeof text === "string" ? text : "";
|
|
74
|
+
}
|
|
75
|
+
return "";
|
|
76
|
+
})
|
|
77
|
+
.filter(Boolean)
|
|
78
|
+
.join("\n");
|
|
79
|
+
}
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
function messagesToPrompt(messages) {
|
|
83
|
+
if (!Array.isArray(messages))
|
|
84
|
+
return "";
|
|
85
|
+
return messages
|
|
86
|
+
.map((message) => {
|
|
87
|
+
const role = typeof message.role === "string" ? message.role : "user";
|
|
88
|
+
const text = contentToText(message.content);
|
|
89
|
+
return text ? `${role}: ${text}` : "";
|
|
90
|
+
})
|
|
91
|
+
.filter(Boolean)
|
|
92
|
+
.join("\n\n");
|
|
93
|
+
}
|
|
94
|
+
function parseHints(body) {
|
|
95
|
+
const hints = {};
|
|
96
|
+
if (typeof body.model === "string" && body.model !== "")
|
|
97
|
+
hints.model = body.model;
|
|
98
|
+
if (body.safetyProfile === "read_only" ||
|
|
99
|
+
body.safetyProfile === "workspace_edit" ||
|
|
100
|
+
body.safetyProfile === "full_auto") {
|
|
101
|
+
hints.safetyProfile = body.safetyProfile;
|
|
102
|
+
}
|
|
103
|
+
if (body.hints && typeof body.hints === "object") {
|
|
104
|
+
const raw = body.hints;
|
|
105
|
+
if (typeof raw.model === "string")
|
|
106
|
+
hints.model = raw.model;
|
|
107
|
+
if (raw.taskType === "execute" ||
|
|
108
|
+
raw.taskType === "plan" ||
|
|
109
|
+
raw.taskType === "review" ||
|
|
110
|
+
raw.taskType === "local") {
|
|
111
|
+
hints.taskType = raw.taskType;
|
|
112
|
+
}
|
|
113
|
+
if (typeof raw.preferLargeContext === "boolean") {
|
|
114
|
+
hints.preferLargeContext = raw.preferLargeContext;
|
|
115
|
+
}
|
|
116
|
+
if (raw.safetyProfile === "read_only" ||
|
|
117
|
+
raw.safetyProfile === "workspace_edit" ||
|
|
118
|
+
raw.safetyProfile === "full_auto") {
|
|
119
|
+
hints.safetyProfile = raw.safetyProfile;
|
|
120
|
+
}
|
|
121
|
+
if (raw.workspacePolicy === "shared" ||
|
|
122
|
+
raw.workspacePolicy === "shared_locked" ||
|
|
123
|
+
raw.workspacePolicy === "copy" ||
|
|
124
|
+
raw.workspacePolicy === "git_worktree") {
|
|
125
|
+
hints.workspacePolicy = raw.workspacePolicy;
|
|
126
|
+
}
|
|
127
|
+
// routePolicy was never read here at all. evaluateRoutePolicy implements
|
|
128
|
+
// local_only, approval_required and blocked in full, and on this surface
|
|
129
|
+
// they were wired to nothing: POST {"hints":{"routePolicy":"blocked"}}
|
|
130
|
+
// returned 200 and dispatched. PRODUCT.md names CI and cron as this
|
|
131
|
+
// surface's consumers, and calls a guarantee that reads correctly and does
|
|
132
|
+
// nothing at runtime its own counter-signal.
|
|
133
|
+
if (raw.routePolicy === "local_only" ||
|
|
134
|
+
raw.routePolicy === "approval_required" ||
|
|
135
|
+
raw.routePolicy === "blocked") {
|
|
136
|
+
hints.routePolicy = raw.routePolicy;
|
|
137
|
+
}
|
|
138
|
+
if (typeof raw.timeoutMs === "number" && Number.isFinite(raw.timeoutMs)) {
|
|
139
|
+
hints.timeoutMs = raw.timeoutMs;
|
|
140
|
+
}
|
|
141
|
+
// Unknown keys are REJECTED, matching the MCP surface. The whole point of
|
|
142
|
+
// making hints strict there was that `safety_profile` (the config
|
|
143
|
+
// spelling) silently disabled a safety limit; accepting it here left the
|
|
144
|
+
// identical typo failing open on the other surface.
|
|
145
|
+
const known = new Set([
|
|
146
|
+
"model",
|
|
147
|
+
"taskType",
|
|
148
|
+
"preferLargeContext",
|
|
149
|
+
"safetyProfile",
|
|
150
|
+
"workspacePolicy",
|
|
151
|
+
"routePolicy",
|
|
152
|
+
"timeoutMs",
|
|
153
|
+
]);
|
|
154
|
+
const unknown = Object.keys(raw).filter((k) => !known.has(k));
|
|
155
|
+
if (unknown.length > 0) {
|
|
156
|
+
throw new BadRequestError(`unknown hints key(s): ${unknown.join(", ")}. Valid: ${[...known].join(", ")}.`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (body.workspacePolicy === "shared" ||
|
|
160
|
+
body.workspacePolicy === "shared_locked" ||
|
|
161
|
+
body.workspacePolicy === "copy" ||
|
|
162
|
+
body.workspacePolicy === "git_worktree") {
|
|
163
|
+
hints.workspacePolicy = body.workspacePolicy;
|
|
164
|
+
}
|
|
165
|
+
return hints;
|
|
166
|
+
}
|
|
167
|
+
export function parseChatRequest(raw) {
|
|
168
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
169
|
+
// Was a plain Error, so `null`, `"hello"` and `42` all returned 500. The
|
|
170
|
+
// BadRequestError mapping was added for JSON PARSE failures only — same
|
|
171
|
+
// fix, one of two paths, which is the pattern this file keeps repeating.
|
|
172
|
+
throw new BadRequestError("request body must be a JSON object");
|
|
173
|
+
}
|
|
174
|
+
const body = raw;
|
|
175
|
+
const prompt = typeof body.prompt === "string" && body.prompt.trim()
|
|
176
|
+
? body.prompt
|
|
177
|
+
: messagesToPrompt(body.messages);
|
|
178
|
+
if (!prompt.trim())
|
|
179
|
+
throw new BadRequestError("messages or prompt is required");
|
|
180
|
+
// MCP validates this; HTTP did not, so `workingDir: "Z:/nope"` surfaced as
|
|
181
|
+
// `spawn node.EXE ENOENT` — verbatim the wrong-cause error working-dir.ts
|
|
182
|
+
// exists to prevent, on the surface CI uses.
|
|
183
|
+
const workingDirError = validateWorkingDir(typeof body.workingDir === "string"
|
|
184
|
+
? body.workingDir
|
|
185
|
+
: undefined);
|
|
186
|
+
if (workingDirError !== undefined)
|
|
187
|
+
throw new BadRequestError(workingDirError);
|
|
188
|
+
// Same cap as the MCP surface, and for the same reason: each file's parent
|
|
189
|
+
// directory becomes an --add-dir grant on CLI routes, so an unbounded list
|
|
190
|
+
// is an unbounded set of directories handed to a coding agent. The cap was
|
|
191
|
+
// added at the MCP boundary only; this surface accepted 500.
|
|
192
|
+
if (Array.isArray(body.files) && body.files.length > MAX_CONTEXT_FILES_HTTP) {
|
|
193
|
+
throw new BadRequestError(`files: ${body.files.length} entries exceeds the maximum of ${MAX_CONTEXT_FILES_HTTP}.`);
|
|
194
|
+
}
|
|
195
|
+
const files = Array.isArray(body.files)
|
|
196
|
+
? body.files.filter((v) => typeof v === "string")
|
|
197
|
+
: [];
|
|
198
|
+
const models = Array.isArray(body.models)
|
|
199
|
+
? body.models.filter((v) => typeof v === "string")
|
|
200
|
+
: [];
|
|
201
|
+
const resolvedWorkingDir = resolveWorkingDir(typeof body.workingDir === "string" ? body.workingDir : undefined);
|
|
202
|
+
const warning = workingDirWarning(resolvedWorkingDir);
|
|
203
|
+
return {
|
|
204
|
+
prompt,
|
|
205
|
+
files,
|
|
206
|
+
workingDir: resolvedWorkingDir.workingDir,
|
|
207
|
+
...(warning !== undefined ? { workingDirWarning: warning } : {}),
|
|
208
|
+
stream: body.stream === true,
|
|
209
|
+
mode: body.mode === "fanout" ? "fanout" : "single",
|
|
210
|
+
models,
|
|
211
|
+
hints: parseHints(body),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
export function completionEnvelope(content, model, extra) {
|
|
215
|
+
return {
|
|
216
|
+
id: `chatcmpl-${randomUUID()}`,
|
|
217
|
+
object: "chat.completion",
|
|
218
|
+
created: Math.floor(Date.now() / 1000),
|
|
219
|
+
model,
|
|
220
|
+
choices: [
|
|
221
|
+
{
|
|
222
|
+
index: 0,
|
|
223
|
+
message: { role: "assistant", content },
|
|
224
|
+
finish_reason: "stop",
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
...extra,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/http/parse.ts"],"names":[],"mappings":"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"}
|
package/dist/http/server.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type BuildMcpOptions, type McpHandle } from "../mcp/server.js";
|
|
2
|
+
import { BadRequestError } from "./parse.js";
|
|
3
|
+
export { BadRequestError };
|
|
2
4
|
export interface HttpServerHandle extends McpHandle {
|
|
3
5
|
port: number;
|
|
4
6
|
host: string;
|
|
@@ -10,17 +12,6 @@ export interface StartHttpOptions extends BuildMcpOptions {
|
|
|
10
12
|
mcpRoute?: string;
|
|
11
13
|
token?: string | null;
|
|
12
14
|
}
|
|
13
|
-
/**
|
|
14
|
-
* A request the CALLER can fix — malformed JSON, a missing required field, a
|
|
15
|
-
* working directory that does not exist.
|
|
16
|
-
*
|
|
17
|
-
* Everything except the 413 was returned as 500. PRODUCT.md names CI and cron
|
|
18
|
-
* as consumers of this surface, and retry-on-5xx will happily retry a request
|
|
19
|
-
* that can never succeed. A 4xx says "stop and fix the request", which is the
|
|
20
|
-
* true statement.
|
|
21
|
-
*/
|
|
22
|
-
export declare class BadRequestError extends Error {
|
|
23
|
-
}
|
|
24
15
|
export declare function startHttpServer(opts?: StartHttpOptions): Promise<HttpServerHandle>;
|
|
25
16
|
export declare const startMcpHttpServer: typeof startHttpServer;
|
|
26
17
|
//# sourceMappingURL=server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/http/server.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/http/server.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAC;AAQ1B,OAAO,EACL,eAAe,EAKhB,MAAM,YAAY,CAAC;AAKpB,OAAO,EAAE,eAAe,EAAE,CAAC;AAG3B,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AA4UD,wBAAsB,eAAe,CAAC,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgN5F;AAED,eAAO,MAAM,kBAAkB,wBAAkB,CAAC"}
|