@mono-agent/agent-runtime 0.20.11 → 0.21.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/ARCHITECTURE.md +50 -11
- package/MIGRATION.md +288 -26
- package/README.md +352 -477
- package/package.json +13 -44
- package/src/agent/tool-bloat.js +145 -9
- package/src/agent/tools/agent-tool.js +108 -9
- package/src/agent/tools/bash.js +11 -26
- package/src/agent/tools/codex-subscription-search.js +123 -29
- package/src/agent/tools/exec.js +10 -2
- package/src/agent/tools/index.js +7 -0
- package/src/agent/tools/monitor.js +149 -0
- package/src/agent/tools/pi-bridge.js +123 -19
- package/src/agent/tools/shared/bash-environment.js +31 -0
- package/src/agent/tools/shared/monitors.js +293 -0
- package/src/agent/tools/shared/path-resolver.js +25 -6
- package/src/agent/tools/shared/process-jobs.js +6 -1
- package/src/agent/tools/shared/process-runner.js +26 -6
- package/src/agent/tools/shared/tool-context.js +8 -0
- package/src/agent/tools/web-access-interstitial.js +70 -0
- package/src/agent/tools/web-browser-render.js +83 -58
- package/src/agent/tools/web-controller.js +112 -21
- package/src/agent/tools/web-document-extractor.js +379 -0
- package/src/agent/tools/web-fetch.js +271 -243
- package/src/agent/tools/web-request.js +65 -0
- package/src/agent/tools/web-search-output.js +165 -0
- package/src/agent/tools/web-search-state.js +75 -0
- package/src/agent/tools/web-search.js +532 -71
- package/src/ai/cost.js +13 -68
- package/src/ai/failure.js +3 -3
- package/src/ai/index.js +5 -17
- package/src/ai/observer.js +8 -0
- package/src/ai/pi-interop.js +221 -1
- package/src/ai/pi-oauth-compat.js +1 -1
- package/src/ai/provider-check.js +131 -0
- package/src/ai/providers/codex/app-server-client.js +592 -0
- package/src/ai/providers/pi-models.js +18 -10
- package/src/ai/providers/pi-native/compaction-driver.js +94 -42
- package/src/ai/providers/pi-native/compaction-summary.js +140 -0
- package/src/ai/providers/pi-native/harness-adapter.js +376 -0
- package/src/ai/providers/pi-native/prompt-cache-diagnostics.js +103 -0
- package/src/ai/providers/pi-native/provider-attribution.js +102 -0
- package/src/ai/providers/pi-native/result-builder.js +38 -14
- package/src/ai/providers/pi-native/session-lifecycle.js +253 -55
- package/src/ai/providers/pi-native/stream-subscriber.js +52 -6
- package/src/ai/providers/pi-native/terminal-recovery.js +40 -0
- package/src/ai/providers/pi-native/turn-runner.js +279 -28
- package/src/ai/providers/pi-native.js +206 -61
- package/src/ai/runtime/capabilities.js +11 -56
- package/src/ai/runtime/live-input-events.js +250 -54
- package/src/ai/runtime/model-refs.js +118 -153
- package/src/ai/runtime/registry.js +22 -56
- package/src/ai/runtime/router.js +76 -417
- package/src/ai/runtime/session-liveness.js +3 -4
- package/src/ai/runtime/sessions.js +4 -5
- package/src/ai/runtime/tool-policy.js +0 -2
- package/src/ai/tool-lifecycle.js +32 -18
- package/src/ai/types.js +37 -112
- package/src/index.js +0 -6
- package/src/runtime.js +29 -16
- package/types/agent/tool-bloat.d.ts +1 -1
- package/types/agent/tools/agent-tool.d.ts +4 -2
- package/types/agent/tools/bash.d.ts +5 -3
- package/types/agent/tools/codex-subscription-search.d.ts +7 -3
- package/types/agent/tools/exec.d.ts +5 -3
- package/types/agent/tools/index.d.ts +1 -0
- package/types/agent/tools/monitor.d.ts +47 -0
- package/types/agent/tools/pi-bridge.d.ts +7 -4
- package/types/agent/tools/shared/bash-environment.d.ts +4 -0
- package/types/agent/tools/shared/monitors.d.ts +98 -0
- package/types/agent/tools/shared/process-jobs.d.ts +5 -1
- package/types/agent/tools/shared/process-runner.d.ts +14 -4
- package/types/agent/tools/shared/tool-context.d.ts +2 -0
- package/types/agent/tools/web-access-interstitial.d.ts +23 -0
- package/types/agent/tools/web-browser-render.d.ts +4 -1
- package/types/agent/tools/web-controller.d.ts +4 -2
- package/types/agent/tools/web-document-extractor.d.ts +27 -0
- package/types/agent/tools/web-fetch.d.ts +19 -24
- package/types/agent/tools/web-request.d.ts +20 -0
- package/types/agent/tools/web-search-output.d.ts +31 -0
- package/types/agent/tools/web-search-state.d.ts +21 -0
- package/types/agent/tools/web-search.d.ts +10 -45
- package/types/ai/cost.d.ts +1 -2
- package/types/ai/index.d.ts +2 -4
- package/types/ai/observer.d.ts +6 -0
- package/types/ai/pi-interop.d.ts +81 -0
- package/types/ai/provider-check.d.ts +53 -0
- package/types/ai/providers/codex/app-server-client.d.ts +37 -0
- package/types/ai/providers/pi-native/compaction-driver.d.ts +2 -1
- package/types/ai/providers/pi-native/compaction-summary.d.ts +19 -0
- package/types/ai/providers/pi-native/harness-adapter.d.ts +58 -0
- package/types/ai/providers/pi-native/prompt-cache-diagnostics.d.ts +3 -0
- package/types/ai/providers/pi-native/provider-attribution.d.ts +26 -0
- package/types/ai/providers/pi-native/result-builder.d.ts +14 -4
- package/types/ai/providers/pi-native/session-lifecycle.d.ts +25 -6
- package/types/ai/providers/pi-native/stream-subscriber.d.ts +2 -2
- package/types/ai/providers/pi-native/terminal-recovery.d.ts +2 -0
- package/types/ai/providers/pi-native/turn-runner.d.ts +68 -10
- package/types/ai/providers/pi-native.d.ts +21 -4
- package/types/ai/runtime/capabilities.d.ts +21 -70
- package/types/ai/runtime/live-input-events.d.ts +32 -8
- package/types/ai/runtime/model-refs.d.ts +0 -24
- package/types/ai/runtime/router.d.ts +3 -10
- package/types/ai/runtime/tool-policy.d.ts +0 -2
- package/types/ai/tool-lifecycle.d.ts +4 -3
- package/types/ai/types.d.ts +162 -256
- package/types/index.d.ts +0 -1
- package/src/ai/providers/acp-client.js +0 -1149
- package/src/ai/providers/acp-privacy.js +0 -124
- package/src/ai/providers/acp-public.js +0 -21
- package/src/ai/providers/acp-session-tokens.js +0 -282
- package/src/ai/providers/acp-transport.js +0 -356
- package/src/ai/providers/acp.js +0 -543
- package/src/ai/providers/claude-cli.js +0 -883
- package/src/ai/providers/claude-sandbox.js +0 -71
- package/src/ai/providers/claude-sdk-discovery-worker.js +0 -53
- package/src/ai/providers/claude-sdk-discovery.js +0 -352
- package/src/ai/providers/claude-sdk.js +0 -1127
- package/src/ai/providers/claude-subagent-activity.js +0 -719
- package/src/ai/providers/claude-subagents.js +0 -88
- package/src/ai/providers/codex-app.js +0 -2946
- package/src/ai/providers/opencode-app.js +0 -1109
- package/src/ai/providers/opencode-discovery.js +0 -39
- package/src/ai/providers/opencode-server.js +0 -508
- package/src/ai/runtime/context-windows.js +0 -46
- package/src/ai/runtime/fast-mode.js +0 -8
- package/src/ai/streaming/codex-events.js +0 -146
- package/src/ai/streaming/opencode-events.js +0 -59
- package/types/ai/providers/acp-client.d.ts +0 -227
- package/types/ai/providers/acp-privacy.d.ts +0 -25
- package/types/ai/providers/acp-public.d.ts +0 -7
- package/types/ai/providers/acp-session-tokens.d.ts +0 -41
- package/types/ai/providers/acp-transport.d.ts +0 -45
- package/types/ai/providers/acp.d.ts +0 -93
- package/types/ai/providers/claude-cli.d.ts +0 -305
- package/types/ai/providers/claude-sandbox.d.ts +0 -79
- package/types/ai/providers/claude-sdk-discovery-worker.d.ts +0 -1
- package/types/ai/providers/claude-sdk-discovery.d.ts +0 -97
- package/types/ai/providers/claude-sdk.d.ts +0 -138
- package/types/ai/providers/claude-subagent-activity.d.ts +0 -53
- package/types/ai/providers/claude-subagents.d.ts +0 -18
- package/types/ai/providers/codex-app.d.ts +0 -151
- package/types/ai/providers/opencode-app.d.ts +0 -96
- package/types/ai/providers/opencode-discovery.d.ts +0 -4
- package/types/ai/providers/opencode-server.d.ts +0 -20
- package/types/ai/runtime/context-windows.d.ts +0 -9
- package/types/ai/runtime/fast-mode.d.ts +0 -2
- package/types/ai/streaming/codex-events.d.ts +0 -40
- package/types/ai/streaming/opencode-events.d.ts +0 -42
|
@@ -1,356 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
|
-
|
|
5
|
-
// Strict, bounded ACP v1 newline transport for an owned stdio child process.
|
|
6
|
-
// The SDK's stock ndJsonStream intentionally tolerates malformed input and its
|
|
7
|
-
// line buffer is unbounded, which is a poor fit for a long-lived host boundary.
|
|
8
|
-
|
|
9
|
-
const DEFAULT_MAX_LINE_BYTES = 1024 * 1024;
|
|
10
|
-
const MAX_MAX_LINE_BYTES = 16 * 1024 * 1024;
|
|
11
|
-
|
|
12
|
-
// @agentclientprotocol/sdk 1.3.0 sends the trailing arguments of these
|
|
13
|
-
// diagnostics directly to console. Those values include raw JSON-RPC payloads
|
|
14
|
-
// (and, for malformed notifications, Zod error details derived from them).
|
|
15
|
-
// Preserve the useful classification while dropping payload-bearing details.
|
|
16
|
-
const ACP_SDK_PAYLOAD_DIAGNOSTICS = Object.freeze({
|
|
17
|
-
error: new Set([
|
|
18
|
-
"Invalid message",
|
|
19
|
-
"Error handling notification",
|
|
20
|
-
"Got response to unknown request",
|
|
21
|
-
"Failed to parse JSON message:",
|
|
22
|
-
"ACP connection router stopped unexpectedly:",
|
|
23
|
-
]),
|
|
24
|
-
warn: new Set([
|
|
25
|
-
"Skipping JSON line that is not an object:",
|
|
26
|
-
]),
|
|
27
|
-
});
|
|
28
|
-
const acpSdkDiagnosticScope = new AsyncLocalStorage();
|
|
29
|
-
let activeAcpSdkDiagnosticGuards = 0;
|
|
30
|
-
/** @type {null|{
|
|
31
|
-
* originalError: typeof console.error,
|
|
32
|
-
* originalWarn: typeof console.warn,
|
|
33
|
-
* guardedError: typeof console.error,
|
|
34
|
-
* guardedWarn: typeof console.warn,
|
|
35
|
-
* }} */
|
|
36
|
-
let acpSdkConsoleGuard = null;
|
|
37
|
-
|
|
38
|
-
function installAcpSdkConsoleGuard() {
|
|
39
|
-
activeAcpSdkDiagnosticGuards += 1;
|
|
40
|
-
if (acpSdkConsoleGuard) return;
|
|
41
|
-
|
|
42
|
-
const originalError = console.error;
|
|
43
|
-
const originalWarn = console.warn;
|
|
44
|
-
/** @type {typeof console.error} */
|
|
45
|
-
const guardedError = (...args) => {
|
|
46
|
-
const contentFree = args[0];
|
|
47
|
-
if (acpSdkDiagnosticScope.getStore() === true
|
|
48
|
-
&& typeof contentFree === "string"
|
|
49
|
-
&& ACP_SDK_PAYLOAD_DIAGNOSTICS.error.has(contentFree)) {
|
|
50
|
-
Reflect.apply(originalError, console, [contentFree]);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
Reflect.apply(originalError, console, args);
|
|
54
|
-
};
|
|
55
|
-
/** @type {typeof console.warn} */
|
|
56
|
-
const guardedWarn = (...args) => {
|
|
57
|
-
const contentFree = args[0];
|
|
58
|
-
if (acpSdkDiagnosticScope.getStore() === true
|
|
59
|
-
&& typeof contentFree === "string"
|
|
60
|
-
&& ACP_SDK_PAYLOAD_DIAGNOSTICS.warn.has(contentFree)) {
|
|
61
|
-
Reflect.apply(originalWarn, console, [contentFree]);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
Reflect.apply(originalWarn, console, args);
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
acpSdkConsoleGuard = { originalError, originalWarn, guardedError, guardedWarn };
|
|
68
|
-
console.error = guardedError;
|
|
69
|
-
console.warn = guardedWarn;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function releaseAcpSdkConsoleGuard() {
|
|
73
|
-
activeAcpSdkDiagnosticGuards = Math.max(0, activeAcpSdkDiagnosticGuards - 1);
|
|
74
|
-
if (activeAcpSdkDiagnosticGuards !== 0 || !acpSdkConsoleGuard) return;
|
|
75
|
-
const guard = acpSdkConsoleGuard;
|
|
76
|
-
acpSdkConsoleGuard = null;
|
|
77
|
-
if (console.error === guard.guardedError) console.error = guard.originalError;
|
|
78
|
-
if (console.warn === guard.guardedWarn) console.warn = guard.originalWarn;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Open one SDK connection inside an async context that strips payload-bearing
|
|
83
|
-
* SDK console arguments. The SDK starts its detached receive loop during
|
|
84
|
-
* `connect`, so descendants retain this scope without muting concurrent host
|
|
85
|
-
* work or other ACP connections.
|
|
86
|
-
*
|
|
87
|
-
* @template {{closed: Promise<unknown>}} T
|
|
88
|
-
* @param {() => T} connect
|
|
89
|
-
* @returns {T}
|
|
90
|
-
*/
|
|
91
|
-
export function connectWithSafeAcpSdkDiagnostics(connect) {
|
|
92
|
-
installAcpSdkConsoleGuard();
|
|
93
|
-
let connection;
|
|
94
|
-
try {
|
|
95
|
-
connection = acpSdkDiagnosticScope.run(true, connect);
|
|
96
|
-
} catch (error) {
|
|
97
|
-
releaseAcpSdkConsoleGuard();
|
|
98
|
-
throw error;
|
|
99
|
-
}
|
|
100
|
-
void Promise.resolve(connection.closed).then(
|
|
101
|
-
releaseAcpSdkConsoleGuard,
|
|
102
|
-
releaseAcpSdkConsoleGuard,
|
|
103
|
-
);
|
|
104
|
-
return connection;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export class AcpTransportError extends Error {
|
|
108
|
-
/**
|
|
109
|
-
* @param {string} code
|
|
110
|
-
* @param {string} message
|
|
111
|
-
*/
|
|
112
|
-
constructor(code, message) {
|
|
113
|
-
super(message);
|
|
114
|
-
this.name = "AcpTransportError";
|
|
115
|
-
this.code = code;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* @param {unknown} value
|
|
121
|
-
* @param {number} [fallback]
|
|
122
|
-
* @returns {number}
|
|
123
|
-
*/
|
|
124
|
-
export function normalizeAcpMaxLineBytes(value, fallback = DEFAULT_MAX_LINE_BYTES) {
|
|
125
|
-
if (value === undefined) return fallback;
|
|
126
|
-
if (!Number.isInteger(value) || Number(value) < 1024 || Number(value) > MAX_MAX_LINE_BYTES) {
|
|
127
|
-
throw new AcpTransportError(
|
|
128
|
-
"invalid_transport_policy",
|
|
129
|
-
`ACP maxLineBytes must be an integer between 1024 and ${MAX_MAX_LINE_BYTES}.`,
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
return Number(value);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* The transport only accepts individual JSON-RPC 2.0 objects. Batches are not
|
|
137
|
-
* part of ACP v1 and are rejected before the SDK sees them.
|
|
138
|
-
* @param {unknown} value
|
|
139
|
-
* @returns {value is Record<string, unknown>}
|
|
140
|
-
*/
|
|
141
|
-
function isIndividualJsonRpcMessage(value) {
|
|
142
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
143
|
-
const record = /** @type {Record<string, unknown>} */ (value);
|
|
144
|
-
if (record.jsonrpc !== "2.0") return false;
|
|
145
|
-
|
|
146
|
-
const hasId = Object.hasOwn(record, "id");
|
|
147
|
-
const hasMethod = Object.hasOwn(record, "method");
|
|
148
|
-
const hasParams = Object.hasOwn(record, "params");
|
|
149
|
-
const hasResult = Object.hasOwn(record, "result");
|
|
150
|
-
const hasError = Object.hasOwn(record, "error");
|
|
151
|
-
|
|
152
|
-
const validId = !hasId
|
|
153
|
-
|| record.id === null
|
|
154
|
-
|| typeof record.id === "string"
|
|
155
|
-
|| (typeof record.id === "number" && Number.isFinite(record.id));
|
|
156
|
-
if (!validId) return false;
|
|
157
|
-
|
|
158
|
-
if (hasMethod) {
|
|
159
|
-
if (typeof record.method !== "string" || record.method.length === 0) return false;
|
|
160
|
-
if (hasParams) {
|
|
161
|
-
const params = record.params;
|
|
162
|
-
if (!params || typeof params !== "object") return false;
|
|
163
|
-
}
|
|
164
|
-
return !hasResult && !hasError;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (!hasId || hasParams || hasResult === hasError) return false;
|
|
168
|
-
if (!hasError) return true;
|
|
169
|
-
if (!record.error || typeof record.error !== "object" || Array.isArray(record.error)) return false;
|
|
170
|
-
const error = /** @type {Record<string, unknown>} */ (record.error);
|
|
171
|
-
return Number.isInteger(error.code) && typeof error.message === "string";
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* @param {Buffer} line
|
|
176
|
-
* @returns {Record<string, unknown>}
|
|
177
|
-
*/
|
|
178
|
-
function decodeLine(line) {
|
|
179
|
-
if (line.length === 0) {
|
|
180
|
-
throw new AcpTransportError("invalid_jsonrpc", "ACP peer emitted an empty NDJSON line.");
|
|
181
|
-
}
|
|
182
|
-
let text;
|
|
183
|
-
try {
|
|
184
|
-
text = new TextDecoder("utf-8", { fatal: true }).decode(line);
|
|
185
|
-
} catch {
|
|
186
|
-
throw new AcpTransportError("invalid_utf8", "ACP peer emitted invalid UTF-8.");
|
|
187
|
-
}
|
|
188
|
-
let parsed;
|
|
189
|
-
try {
|
|
190
|
-
parsed = JSON.parse(text);
|
|
191
|
-
} catch {
|
|
192
|
-
throw new AcpTransportError("invalid_jsonrpc", "ACP peer emitted malformed JSON.");
|
|
193
|
-
}
|
|
194
|
-
if (!isIndividualJsonRpcMessage(parsed)) {
|
|
195
|
-
throw new AcpTransportError("invalid_jsonrpc", "ACP peer emitted a non-ACP JSON-RPC message.");
|
|
196
|
-
}
|
|
197
|
-
return parsed;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Build the Stream shape consumed by @agentclientprotocol/sdk from a child
|
|
202
|
-
* process's stdin/stdout. Both inbound and outbound payloads are capped.
|
|
203
|
-
*
|
|
204
|
-
* @param {{stdin: import('node:stream').Writable|null, stdout: import('node:stream').Readable|null}} child
|
|
205
|
-
* @param {{maxLineBytes?: number}} [options]
|
|
206
|
-
* @returns {{readable: ReadableStream<any>, writable: WritableStream<any>}}
|
|
207
|
-
*/
|
|
208
|
-
export function createBoundedAcpStdioStream(child, options = {}) {
|
|
209
|
-
const maxLineBytes = normalizeAcpMaxLineBytes(options.maxLineBytes);
|
|
210
|
-
if (!child.stdin || !child.stdout) {
|
|
211
|
-
throw new AcpTransportError("stdio_unavailable", "ACP child stdio is unavailable.");
|
|
212
|
-
}
|
|
213
|
-
const input = child.stdout;
|
|
214
|
-
const output = child.stdin;
|
|
215
|
-
|
|
216
|
-
let pending = Buffer.alloc(0);
|
|
217
|
-
let settled = false;
|
|
218
|
-
let inputEnded = false;
|
|
219
|
-
/** @type {ReadableStreamDefaultController<any>|null} */
|
|
220
|
-
let readableController = null;
|
|
221
|
-
|
|
222
|
-
const cleanupReadable = () => {
|
|
223
|
-
input.off("data", onData);
|
|
224
|
-
input.off("end", onEnd);
|
|
225
|
-
input.off("error", onError);
|
|
226
|
-
};
|
|
227
|
-
const failReadable = (error) => {
|
|
228
|
-
if (settled) return;
|
|
229
|
-
settled = true;
|
|
230
|
-
input.pause();
|
|
231
|
-
cleanupReadable();
|
|
232
|
-
readableController?.error(error instanceof Error
|
|
233
|
-
? error
|
|
234
|
-
: new AcpTransportError("transport_failed", "ACP stdout failed."));
|
|
235
|
-
};
|
|
236
|
-
const firstPendingLineIsTooLarge = () => {
|
|
237
|
-
const newline = pending.indexOf(0x0a);
|
|
238
|
-
if (newline !== -1) {
|
|
239
|
-
const contentBytes = newline > 0 && pending[newline - 1] === 0x0d ? newline - 1 : newline;
|
|
240
|
-
return contentBytes > maxLineBytes;
|
|
241
|
-
}
|
|
242
|
-
if (pending.length <= maxLineBytes) return false;
|
|
243
|
-
return pending.length > maxLineBytes + 1 || pending[pending.length - 1] !== 0x0d;
|
|
244
|
-
};
|
|
245
|
-
const finishReadableIfEnded = () => {
|
|
246
|
-
if (!inputEnded || settled || !readableController) return false;
|
|
247
|
-
if (pending.length === 0) {
|
|
248
|
-
settled = true;
|
|
249
|
-
cleanupReadable();
|
|
250
|
-
readableController.close();
|
|
251
|
-
return true;
|
|
252
|
-
}
|
|
253
|
-
if (pending.indexOf(0x0a) === -1) {
|
|
254
|
-
failReadable(new AcpTransportError(
|
|
255
|
-
"unterminated_line",
|
|
256
|
-
"ACP peer closed stdout with an unterminated JSON-RPC line.",
|
|
257
|
-
));
|
|
258
|
-
return true;
|
|
259
|
-
}
|
|
260
|
-
return false;
|
|
261
|
-
};
|
|
262
|
-
const drainPending = () => {
|
|
263
|
-
if (settled || !readableController) return;
|
|
264
|
-
while (readableController.desiredSize !== null && readableController.desiredSize > 0) {
|
|
265
|
-
const newline = pending.indexOf(0x0a);
|
|
266
|
-
if (newline === -1) break;
|
|
267
|
-
let line = pending.subarray(0, newline);
|
|
268
|
-
pending = pending.subarray(newline + 1);
|
|
269
|
-
if (line.length > 0 && line[line.length - 1] === 0x0d) line = line.subarray(0, line.length - 1);
|
|
270
|
-
if (line.length > maxLineBytes) {
|
|
271
|
-
failReadable(new AcpTransportError("line_too_large", "ACP peer exceeded the inbound line limit."));
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
try {
|
|
275
|
-
readableController.enqueue(decodeLine(line));
|
|
276
|
-
} catch (error) {
|
|
277
|
-
failReadable(error);
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
if (firstPendingLineIsTooLarge()) {
|
|
282
|
-
failReadable(new AcpTransportError("line_too_large", "ACP peer exceeded the inbound line limit."));
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
if (finishReadableIfEnded()) return;
|
|
286
|
-
if (readableController.desiredSize !== null
|
|
287
|
-
&& readableController.desiredSize > 0
|
|
288
|
-
&& pending.indexOf(0x0a) === -1) {
|
|
289
|
-
input.resume();
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
const onData = (chunk) => {
|
|
293
|
-
if (settled) return;
|
|
294
|
-
input.pause();
|
|
295
|
-
const next = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
296
|
-
pending = pending.length === 0 ? next : Buffer.concat([pending, next]);
|
|
297
|
-
drainPending();
|
|
298
|
-
};
|
|
299
|
-
const onEnd = () => {
|
|
300
|
-
if (settled) return;
|
|
301
|
-
inputEnded = true;
|
|
302
|
-
drainPending();
|
|
303
|
-
};
|
|
304
|
-
const onError = () => failReadable(new AcpTransportError("transport_failed", "ACP stdout failed."));
|
|
305
|
-
|
|
306
|
-
const readable = new ReadableStream({
|
|
307
|
-
start(controller) {
|
|
308
|
-
readableController = controller;
|
|
309
|
-
input.pause();
|
|
310
|
-
input.on("data", onData);
|
|
311
|
-
input.once("end", onEnd);
|
|
312
|
-
input.once("error", onError);
|
|
313
|
-
drainPending();
|
|
314
|
-
},
|
|
315
|
-
pull() {
|
|
316
|
-
drainPending();
|
|
317
|
-
},
|
|
318
|
-
cancel() {
|
|
319
|
-
if (!settled) {
|
|
320
|
-
settled = true;
|
|
321
|
-
cleanupReadable();
|
|
322
|
-
}
|
|
323
|
-
input.destroy();
|
|
324
|
-
},
|
|
325
|
-
}, { highWaterMark: 1 });
|
|
326
|
-
|
|
327
|
-
const writable = new WritableStream({
|
|
328
|
-
async write(message) {
|
|
329
|
-
let json;
|
|
330
|
-
try {
|
|
331
|
-
json = JSON.stringify(message);
|
|
332
|
-
} catch {
|
|
333
|
-
throw new AcpTransportError("invalid_outbound_json", "ACP outbound message is not JSON serializable.");
|
|
334
|
-
}
|
|
335
|
-
if (typeof json !== "string" || Buffer.byteLength(json, "utf8") > maxLineBytes) {
|
|
336
|
-
throw new AcpTransportError("line_too_large", "ACP outbound message exceeded the line limit.");
|
|
337
|
-
}
|
|
338
|
-
if (output.destroyed || output.writableEnded) {
|
|
339
|
-
throw new AcpTransportError("transport_closed", "ACP stdin is closed.");
|
|
340
|
-
}
|
|
341
|
-
await new Promise((resolve, reject) => {
|
|
342
|
-
output.write(`${json}\n`, (error) => error ? reject(error) : resolve(undefined));
|
|
343
|
-
});
|
|
344
|
-
},
|
|
345
|
-
close() {
|
|
346
|
-
if (!output.destroyed && !output.writableEnded) output.end();
|
|
347
|
-
},
|
|
348
|
-
abort() {
|
|
349
|
-
output.destroy();
|
|
350
|
-
},
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
return { readable, writable };
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
export const ACP_DEFAULT_MAX_LINE_BYTES = DEFAULT_MAX_LINE_BYTES;
|