@wrongstack/acp 1.0.28 → 1.0.32
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/agent.js +54 -24
- package/dist/client/acp-session-messages.d.ts +24 -0
- package/dist/client/acp-session.d.ts +1 -0
- package/dist/client.js +258 -187
- package/dist/index.js +287 -191
- package/dist/wrongstack-acp-agent.js +24 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -239,6 +239,10 @@ async function handleSessionNewOp(ctx, id, params) {
|
|
|
239
239
|
}
|
|
240
240
|
const skipped = [];
|
|
241
241
|
const mcpServers = parseMcpServers(p.mcpServers, (reason) => skipped.push(reason));
|
|
242
|
+
if (ctx.sessions.size >= ctx.maxSessions) {
|
|
243
|
+
await ctx.sendError(id, -32e3, `active session limit reached (${ctx.maxSessions})`);
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
242
246
|
const sessionId = `sess_${ctx.allocId()}`;
|
|
243
247
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
244
248
|
const state = {
|
|
@@ -289,6 +293,9 @@ async function handleSessionLoadOp(ctx, id, params, replayHistory = true) {
|
|
|
289
293
|
if (!existing && sessionId && ctx.store) {
|
|
290
294
|
const persisted = await ctx.store.load(sessionId);
|
|
291
295
|
if (persisted) {
|
|
296
|
+
if (ctx.sessions.has(sessionId)) {
|
|
297
|
+
return handleSessionLoadOp(ctx, id, params, replayHistory);
|
|
298
|
+
}
|
|
292
299
|
if (ctx.sessions.size >= ctx.maxSessions) {
|
|
293
300
|
await ctx.sendError(id, -32e3, `active session limit reached (${ctx.maxSessions})`);
|
|
294
301
|
return false;
|
|
@@ -297,8 +304,15 @@ async function handleSessionLoadOp(ctx, id, params, replayHistory = true) {
|
|
|
297
304
|
await ctx.sendError(id, -32602, `cwd must be an absolute path to an existing directory`);
|
|
298
305
|
return false;
|
|
299
306
|
}
|
|
300
|
-
const candidateCwd = persisted.cwd ??
|
|
307
|
+
const candidateCwd = loadCwd ?? persisted.cwd ?? ctx.defaultCwd;
|
|
301
308
|
const restoredCwd = await resolveSessionCwd(candidateCwd) ?? ctx.defaultCwd;
|
|
309
|
+
if (ctx.sessions.has(sessionId)) {
|
|
310
|
+
return handleSessionLoadOp(ctx, id, params, replayHistory);
|
|
311
|
+
}
|
|
312
|
+
if (ctx.sessions.size >= ctx.maxSessions) {
|
|
313
|
+
await ctx.sendError(id, -32e3, `active session limit reached (${ctx.maxSessions})`);
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
302
316
|
const restored = {
|
|
303
317
|
id: sessionId,
|
|
304
318
|
cwd: restoredCwd,
|
|
@@ -402,9 +416,17 @@ async function handleSessionForkOp(ctx, id, params) {
|
|
|
402
416
|
}
|
|
403
417
|
forkCwd = resolved;
|
|
404
418
|
}
|
|
419
|
+
if (ctx.sessions.get(sourceId) !== source) {
|
|
420
|
+
await ctx.sendError(id, -32e3, `session not found: ${sourceId}`);
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
405
423
|
const forkSkipped = [];
|
|
406
424
|
const forkRequested = parseMcpServers(p.mcpServers, (reason) => forkSkipped.push(reason));
|
|
407
425
|
const forkMcpServers = forkRequested.length > 0 ? forkRequested : source.mcpServers;
|
|
426
|
+
if (ctx.sessions.size >= ctx.maxSessions) {
|
|
427
|
+
await ctx.sendError(id, -32e3, `active session limit reached (${ctx.maxSessions})`);
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
408
430
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
409
431
|
const sessionId = `sess_${ctx.allocId()}`;
|
|
410
432
|
const forked = {
|
|
@@ -478,6 +500,7 @@ async function handleSessionPromptOp(ctx, id, params) {
|
|
|
478
500
|
let result;
|
|
479
501
|
const pendingNotifications = [];
|
|
480
502
|
const emit = (update) => {
|
|
503
|
+
if (ctx.sessions.get(sessionId) !== session) return;
|
|
481
504
|
const notifPromise = ctx.sendNotification({ sessionId, update });
|
|
482
505
|
pendingNotifications.push(notifPromise.catch(() => {
|
|
483
506
|
}));
|
|
@@ -1516,7 +1539,7 @@ function toACPInputSchema(src) {
|
|
|
1516
1539
|
if (typeof s.maximum === "number") out.maximum = s.maximum;
|
|
1517
1540
|
if (s.items) out.items = toACPInputSchema(s.items);
|
|
1518
1541
|
if (s.properties && typeof s.properties === "object") {
|
|
1519
|
-
const props =
|
|
1542
|
+
const props = /* @__PURE__ */ Object.create(null);
|
|
1520
1543
|
for (const [k, v] of Object.entries(s.properties)) {
|
|
1521
1544
|
props[k] = toACPInputSchema(v);
|
|
1522
1545
|
}
|
|
@@ -1842,8 +1865,8 @@ function cancelLateAcpSession(transport, createPromise) {
|
|
|
1842
1865
|
const timer = setTimeout(() => {
|
|
1843
1866
|
reject(new Error("late session/cancel send timed out"));
|
|
1844
1867
|
}, LATE_CANCEL_SEND_TIMEOUT_MS);
|
|
1845
|
-
Promise.resolve(
|
|
1846
|
-
transport.send({
|
|
1868
|
+
Promise.resolve().then(
|
|
1869
|
+
() => transport.send({
|
|
1847
1870
|
jsonrpc: "2.0",
|
|
1848
1871
|
method: "session/cancel",
|
|
1849
1872
|
params: { sessionId: lateId }
|
|
@@ -1882,11 +1905,6 @@ function cancelLateAcpSession(transport, createPromise) {
|
|
|
1882
1905
|
});
|
|
1883
1906
|
}
|
|
1884
1907
|
|
|
1885
|
-
// src/client/acp-message-routing.ts
|
|
1886
|
-
function isBestEffortAckMethod(method) {
|
|
1887
|
-
return method === "mcp/connect" || method === "mcp/message" || method === "mcp/disconnect" || method === "elicitation/create" || method === "elicitation/complete";
|
|
1888
|
-
}
|
|
1889
|
-
|
|
1890
1908
|
// src/client/acp-session-errors.ts
|
|
1891
1909
|
var ACPSessionError = class extends Error {
|
|
1892
1910
|
kind;
|
|
@@ -1899,7 +1917,7 @@ var ACPSessionError = class extends Error {
|
|
|
1899
1917
|
}
|
|
1900
1918
|
};
|
|
1901
1919
|
function isJsonRpcError(v) {
|
|
1902
|
-
return typeof v === "object" && v !== null &&
|
|
1920
|
+
return typeof v === "object" && v !== null && Number.isSafeInteger(v.code) && typeof v.message === "string";
|
|
1903
1921
|
}
|
|
1904
1922
|
function isAuthRequiredError(err) {
|
|
1905
1923
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -1947,6 +1965,7 @@ async function executeLoadSession(ctx, sessionId, mcpServers, cwd) {
|
|
|
1947
1965
|
if (ctx.sessionId && ctx.sessionId !== sessionId) {
|
|
1948
1966
|
await ctx.closeSession();
|
|
1949
1967
|
}
|
|
1968
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1950
1969
|
ctx.resetScratch();
|
|
1951
1970
|
const servers = filterMcpServers(ctx.agentCapabilities, mcpServers ?? ctx.opts.mcpServers);
|
|
1952
1971
|
const id = ctx.allocId();
|
|
@@ -1958,6 +1977,7 @@ async function executeLoadSession(ctx, sessionId, mcpServers, cwd) {
|
|
|
1958
1977
|
if (isJsonRpcError(result)) {
|
|
1959
1978
|
throw new ACPSessionError("prompt_failed", `session/load failed: ${result.message}`, result);
|
|
1960
1979
|
}
|
|
1980
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1961
1981
|
ctx.setSessionId(sessionId);
|
|
1962
1982
|
}
|
|
1963
1983
|
async function executeResumeSession(ctx, sessionId, mcpServers, cwd) {
|
|
@@ -1971,6 +1991,7 @@ async function executeResumeSession(ctx, sessionId, mcpServers, cwd) {
|
|
|
1971
1991
|
if (ctx.sessionId && ctx.sessionId !== sessionId) {
|
|
1972
1992
|
await ctx.closeSession();
|
|
1973
1993
|
}
|
|
1994
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1974
1995
|
const servers = filterMcpServers(ctx.agentCapabilities, mcpServers ?? ctx.opts.mcpServers);
|
|
1975
1996
|
const id = ctx.allocId();
|
|
1976
1997
|
const result = await ctx.sendRequest(id, "session/resume", {
|
|
@@ -1981,6 +2002,7 @@ async function executeResumeSession(ctx, sessionId, mcpServers, cwd) {
|
|
|
1981
2002
|
if (isJsonRpcError(result)) {
|
|
1982
2003
|
throw new ACPSessionError("prompt_failed", `session/resume failed: ${result.message}`, result);
|
|
1983
2004
|
}
|
|
2005
|
+
if (ctx.closed) throw new ACPSessionError("closed", "session is closed");
|
|
1984
2006
|
ctx.setSessionId(sessionId);
|
|
1985
2007
|
}
|
|
1986
2008
|
async function executeListSessions(ctx, cursor, cwd) {
|
|
@@ -2129,10 +2151,11 @@ async function executeCreateSession(ctx) {
|
|
|
2129
2151
|
}
|
|
2130
2152
|
|
|
2131
2153
|
// src/client/acp-session-auth.ts
|
|
2154
|
+
function ensureOpen(host) {
|
|
2155
|
+
if (host.state === "closed") throw new ACPSessionError("closed", "session is closed");
|
|
2156
|
+
}
|
|
2132
2157
|
async function authenticate(host, methodId) {
|
|
2133
|
-
|
|
2134
|
-
throw new ACPSessionError("closed", "session is closed");
|
|
2135
|
-
}
|
|
2158
|
+
ensureOpen(host);
|
|
2136
2159
|
if (host.state !== "ready" && host.state !== "authenticated") {
|
|
2137
2160
|
throw new ACPSessionError(
|
|
2138
2161
|
"protocol_error",
|
|
@@ -2157,12 +2180,11 @@ async function authenticate(host, methodId) {
|
|
|
2157
2180
|
if (isJsonRpcError(result)) {
|
|
2158
2181
|
throw new ACPSessionError("auth_failed", `authenticate failed: ${result.message}`, result);
|
|
2159
2182
|
}
|
|
2183
|
+
ensureOpen(host);
|
|
2160
2184
|
host.state = "authenticated";
|
|
2161
2185
|
}
|
|
2162
2186
|
async function logout(host) {
|
|
2163
|
-
|
|
2164
|
-
throw new ACPSessionError("closed", "session is closed");
|
|
2165
|
-
}
|
|
2187
|
+
ensureOpen(host);
|
|
2166
2188
|
if (!host.agentCapabilities.auth?.logout) {
|
|
2167
2189
|
throw new ACPSessionError(
|
|
2168
2190
|
"unsupported_capability",
|
|
@@ -2174,6 +2196,7 @@ async function logout(host) {
|
|
|
2174
2196
|
if (isJsonRpcError(result)) {
|
|
2175
2197
|
throw new ACPSessionError("logout_failed", `logout failed: ${result.message}`, result);
|
|
2176
2198
|
}
|
|
2199
|
+
ensureOpen(host);
|
|
2177
2200
|
host.state = "ready";
|
|
2178
2201
|
}
|
|
2179
2202
|
async function createSessionWithAuth(host) {
|
|
@@ -2215,6 +2238,44 @@ async function ensureAuthenticated(host) {
|
|
|
2215
2238
|
);
|
|
2216
2239
|
}
|
|
2217
2240
|
|
|
2241
|
+
// src/client/acp-session-content.ts
|
|
2242
|
+
function textContent(text) {
|
|
2243
|
+
return { type: "text", text };
|
|
2244
|
+
}
|
|
2245
|
+
function imageContent(mimeType, data) {
|
|
2246
|
+
return { type: "image", mimeType, data };
|
|
2247
|
+
}
|
|
2248
|
+
function audioContent(mimeType, data) {
|
|
2249
|
+
return { type: "audio", mimeType, data };
|
|
2250
|
+
}
|
|
2251
|
+
function extractText(block) {
|
|
2252
|
+
if (typeof block !== "object" || block === null) return "";
|
|
2253
|
+
const b = block;
|
|
2254
|
+
if (b.type === "text" && typeof b.text === "string") return b.text;
|
|
2255
|
+
if (b.type === "resource" && b.resource && typeof b.resource === "object" && typeof b.resource.text === "string") {
|
|
2256
|
+
return b.resource.text;
|
|
2257
|
+
}
|
|
2258
|
+
return "";
|
|
2259
|
+
}
|
|
2260
|
+
function isRecord(v) {
|
|
2261
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2262
|
+
}
|
|
2263
|
+
function emptyRunResult(stopReason) {
|
|
2264
|
+
return {
|
|
2265
|
+
text: "",
|
|
2266
|
+
stopReason,
|
|
2267
|
+
hasText: false,
|
|
2268
|
+
toolCalls: [],
|
|
2269
|
+
diffs: [],
|
|
2270
|
+
thoughts: ""
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
// src/client/acp-message-routing.ts
|
|
2275
|
+
function isBestEffortAckMethod(method) {
|
|
2276
|
+
return method === "mcp/connect" || method === "mcp/message" || method === "mcp/disconnect" || method === "elicitation/create" || method === "elicitation/complete";
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2218
2279
|
// src/client/file-server.ts
|
|
2219
2280
|
import { randomBytes } from "node:crypto";
|
|
2220
2281
|
import { realpathSync } from "node:fs";
|
|
@@ -2271,6 +2332,9 @@ var FileServer = class {
|
|
|
2271
2332
|
const stat3 = await this.operations.stat(safe).catch((err) => {
|
|
2272
2333
|
throw mapFsError(err, safe);
|
|
2273
2334
|
});
|
|
2335
|
+
if (controller.signal.aborted) {
|
|
2336
|
+
throw new FsError("TIMEOUT", safe, `readTextFile timed out after ${this.timeoutMs}ms`);
|
|
2337
|
+
}
|
|
2274
2338
|
if (stat3.size > this.maxReadBytes) {
|
|
2275
2339
|
throw new FsError(
|
|
2276
2340
|
"TOO_LARGE",
|
|
@@ -2282,6 +2346,17 @@ var FileServer = class {
|
|
|
2282
2346
|
encoding: "utf8",
|
|
2283
2347
|
signal: controller.signal
|
|
2284
2348
|
});
|
|
2349
|
+
if (controller.signal.aborted) {
|
|
2350
|
+
throw new FsError("TIMEOUT", safe, `readTextFile timed out after ${this.timeoutMs}ms`);
|
|
2351
|
+
}
|
|
2352
|
+
const actualSize = Buffer.byteLength(content, "utf8");
|
|
2353
|
+
if (actualSize > this.maxReadBytes) {
|
|
2354
|
+
throw new FsError(
|
|
2355
|
+
"TOO_LARGE",
|
|
2356
|
+
safe,
|
|
2357
|
+
`file is ${actualSize} bytes after read, max read is ${this.maxReadBytes} bytes`
|
|
2358
|
+
);
|
|
2359
|
+
}
|
|
2285
2360
|
if (params.line == null && params.limit == null) return { content };
|
|
2286
2361
|
const lines = content.match(/[^\n]*\n|[^\n]+$/g) ?? [];
|
|
2287
2362
|
const start = (params.line ?? 1) - 1;
|
|
@@ -2320,9 +2395,21 @@ var FileServer = class {
|
|
|
2320
2395
|
encoding: "utf8",
|
|
2321
2396
|
signal: controller.signal
|
|
2322
2397
|
});
|
|
2398
|
+
if (controller.signal.aborted) {
|
|
2399
|
+
throw new FsError("TIMEOUT", safe, `writeTextFile timed out after ${this.timeoutMs}ms`);
|
|
2400
|
+
}
|
|
2323
2401
|
await this.assertRealInside(tmp);
|
|
2402
|
+
if (controller.signal.aborted) {
|
|
2403
|
+
throw new FsError("TIMEOUT", safe, `writeTextFile timed out after ${this.timeoutMs}ms`);
|
|
2404
|
+
}
|
|
2324
2405
|
await this.assertRealInside(path2.dirname(safe));
|
|
2406
|
+
if (controller.signal.aborted) {
|
|
2407
|
+
throw new FsError("TIMEOUT", safe, `writeTextFile timed out after ${this.timeoutMs}ms`);
|
|
2408
|
+
}
|
|
2325
2409
|
await this.operations.rename(tmp, safe);
|
|
2410
|
+
if (controller.signal.aborted) {
|
|
2411
|
+
throw new FsError("TIMEOUT", safe, `writeTextFile timed out after ${this.timeoutMs}ms`);
|
|
2412
|
+
}
|
|
2326
2413
|
} catch (err) {
|
|
2327
2414
|
if (err instanceof FsError) {
|
|
2328
2415
|
await this.operations.unlink(tmp).catch(() => void 0);
|
|
@@ -2421,7 +2508,7 @@ function safeRealpathSync(p) {
|
|
|
2421
2508
|
|
|
2422
2509
|
// src/client/acp-session-callbacks.ts
|
|
2423
2510
|
var DEFAULT_PERMISSION_TIMEOUT_MS = 6e4;
|
|
2424
|
-
async function handleAcpPermissionRequest(msg, permissionPolicy, sender,
|
|
2511
|
+
async function handleAcpPermissionRequest(msg, permissionPolicy, sender, callbackOptions2 = {}) {
|
|
2425
2512
|
const id = msg.id;
|
|
2426
2513
|
if (id === void 0) return;
|
|
2427
2514
|
const params = msg.params;
|
|
@@ -2438,7 +2525,7 @@ async function handleAcpPermissionRequest(msg, permissionPolicy, sender, callbac
|
|
|
2438
2525
|
toolCall,
|
|
2439
2526
|
options: permissionOptions
|
|
2440
2527
|
},
|
|
2441
|
-
|
|
2528
|
+
callbackOptions2
|
|
2442
2529
|
);
|
|
2443
2530
|
await sender.sendResult(id, { outcome });
|
|
2444
2531
|
} catch (err) {
|
|
@@ -2450,7 +2537,7 @@ async function handleAcpPermissionRequest(msg, permissionPolicy, sender, callbac
|
|
|
2450
2537
|
await sender.sendErrorResponse(id, -32603, `permission policy failed: ${message}`);
|
|
2451
2538
|
}
|
|
2452
2539
|
}
|
|
2453
|
-
async function handleAcpFsRequest(msg, fileServer, permissionPolicy, sender,
|
|
2540
|
+
async function handleAcpFsRequest(msg, fileServer, permissionPolicy, sender, callbackOptions2 = {}) {
|
|
2454
2541
|
const id = msg.id;
|
|
2455
2542
|
if (id === void 0) return;
|
|
2456
2543
|
const params = msg.params;
|
|
@@ -2467,7 +2554,7 @@ async function handleAcpFsRequest(msg, fileServer, permissionPolicy, sender, cal
|
|
|
2467
2554
|
kind: "edit",
|
|
2468
2555
|
rawInput: { path: params.path, sessionId: params.sessionId }
|
|
2469
2556
|
},
|
|
2470
|
-
|
|
2557
|
+
callbackOptions2
|
|
2471
2558
|
);
|
|
2472
2559
|
if (authorization !== "allowed") {
|
|
2473
2560
|
const isCancelled = authorization === "cancelled";
|
|
@@ -2502,7 +2589,7 @@ async function handleAcpFsRequest(msg, fileServer, permissionPolicy, sender, cal
|
|
|
2502
2589
|
await sender.sendErrorResponse(id, code, message);
|
|
2503
2590
|
}
|
|
2504
2591
|
}
|
|
2505
|
-
async function handleAcpTerminalRequest(msg, terminalServer, permissionPolicy, sender,
|
|
2592
|
+
async function handleAcpTerminalRequest(msg, terminalServer, permissionPolicy, sender, callbackOptions2 = {}) {
|
|
2506
2593
|
const id = msg.id;
|
|
2507
2594
|
if (id === void 0) return;
|
|
2508
2595
|
const params = msg.params ?? {};
|
|
@@ -2522,7 +2609,7 @@ async function handleAcpTerminalRequest(msg, terminalServer, permissionPolicy, s
|
|
|
2522
2609
|
sessionId: params.sessionId
|
|
2523
2610
|
}
|
|
2524
2611
|
},
|
|
2525
|
-
|
|
2612
|
+
callbackOptions2
|
|
2526
2613
|
);
|
|
2527
2614
|
if (authorization !== "allowed") {
|
|
2528
2615
|
const isCancelled = authorization === "cancelled";
|
|
@@ -2583,7 +2670,7 @@ async function handleAcpTerminalRequest(msg, terminalServer, permissionPolicy, s
|
|
|
2583
2670
|
await sender.sendErrorResponse(id, -32603, message);
|
|
2584
2671
|
}
|
|
2585
2672
|
}
|
|
2586
|
-
async function authorizeAcpCallback(permissionPolicy, partial,
|
|
2673
|
+
async function authorizeAcpCallback(permissionPolicy, partial, callbackOptions2) {
|
|
2587
2674
|
try {
|
|
2588
2675
|
const outcome = await runPermissionWithDeadline(
|
|
2589
2676
|
permissionPolicy,
|
|
@@ -2601,25 +2688,25 @@ async function authorizeAcpCallback(permissionPolicy, partial, callbackOptions)
|
|
|
2601
2688
|
{ optionId: "reject", name: "Reject", kind: "reject_once" }
|
|
2602
2689
|
]
|
|
2603
2690
|
},
|
|
2604
|
-
|
|
2691
|
+
callbackOptions2
|
|
2605
2692
|
);
|
|
2606
2693
|
return outcome.outcome === "selected" && outcome.optionId !== "reject" && outcome.optionId !== "reject_once" && outcome.optionId !== "reject_always" ? "allowed" : "denied";
|
|
2607
2694
|
} catch (err) {
|
|
2608
2695
|
return isAbortLikeError(err) ? "cancelled" : "denied";
|
|
2609
2696
|
}
|
|
2610
2697
|
}
|
|
2611
|
-
async function runPermissionWithDeadline(permissionPolicy, call,
|
|
2612
|
-
const timeoutMs = resolvePermissionDeadline(
|
|
2698
|
+
async function runPermissionWithDeadline(permissionPolicy, call, callbackOptions2) {
|
|
2699
|
+
const timeoutMs = resolvePermissionDeadline(callbackOptions2.permissionTimeoutMs);
|
|
2613
2700
|
const controller = new AbortController();
|
|
2614
2701
|
const abort = () => controller.abort();
|
|
2615
2702
|
const timer = timeoutMs === null ? null : setTimeout(abort, timeoutMs);
|
|
2616
2703
|
let removeAbort;
|
|
2617
|
-
if (
|
|
2618
|
-
if (
|
|
2704
|
+
if (callbackOptions2.signal) {
|
|
2705
|
+
if (callbackOptions2.signal.aborted) {
|
|
2619
2706
|
abort();
|
|
2620
2707
|
} else {
|
|
2621
|
-
|
|
2622
|
-
removeAbort = () =>
|
|
2708
|
+
callbackOptions2.signal.addEventListener("abort", abort, { once: true });
|
|
2709
|
+
removeAbort = () => callbackOptions2.signal?.removeEventListener("abort", abort);
|
|
2623
2710
|
}
|
|
2624
2711
|
}
|
|
2625
2712
|
try {
|
|
@@ -2655,54 +2742,21 @@ function resolvePermissionDeadline(value) {
|
|
|
2655
2742
|
return DEFAULT_PERMISSION_TIMEOUT_MS;
|
|
2656
2743
|
}
|
|
2657
2744
|
|
|
2658
|
-
// src/client/acp-session-content.ts
|
|
2659
|
-
function textContent(text) {
|
|
2660
|
-
return { type: "text", text };
|
|
2661
|
-
}
|
|
2662
|
-
function imageContent(mimeType, data) {
|
|
2663
|
-
return { type: "image", mimeType, data };
|
|
2664
|
-
}
|
|
2665
|
-
function audioContent(mimeType, data) {
|
|
2666
|
-
return { type: "audio", mimeType, data };
|
|
2667
|
-
}
|
|
2668
|
-
function extractText(block) {
|
|
2669
|
-
if (typeof block !== "object" || block === null) return "";
|
|
2670
|
-
const b = block;
|
|
2671
|
-
if (b.type === "text" && typeof b.text === "string") return b.text;
|
|
2672
|
-
if (b.type === "resource" && b.resource && typeof b.resource === "object" && typeof b.resource.text === "string") {
|
|
2673
|
-
return b.resource.text;
|
|
2674
|
-
}
|
|
2675
|
-
return "";
|
|
2676
|
-
}
|
|
2677
|
-
function isRecord(v) {
|
|
2678
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2679
|
-
}
|
|
2680
|
-
function emptyRunResult(stopReason) {
|
|
2681
|
-
return {
|
|
2682
|
-
text: "",
|
|
2683
|
-
stopReason,
|
|
2684
|
-
hasText: false,
|
|
2685
|
-
toolCalls: [],
|
|
2686
|
-
diffs: [],
|
|
2687
|
-
thoughts: ""
|
|
2688
|
-
};
|
|
2689
|
-
}
|
|
2690
|
-
|
|
2691
2745
|
// src/client/acp-session-updates.ts
|
|
2692
2746
|
function createSessionScratch() {
|
|
2693
2747
|
return { text: "", thoughts: "", toolCalls: /* @__PURE__ */ new Map(), diffs: [] };
|
|
2694
2748
|
}
|
|
2695
|
-
function handleAcpSessionUpdate(msg, scratch,
|
|
2749
|
+
function handleAcpSessionUpdate(msg, scratch, emitProgress2) {
|
|
2696
2750
|
const update = msg.params?.update;
|
|
2697
2751
|
if (typeof update !== "object" || update === null) return;
|
|
2698
2752
|
const u = update;
|
|
2699
|
-
|
|
2753
|
+
emitProgress2({ type: "raw", update: u });
|
|
2700
2754
|
switch (u.sessionUpdate) {
|
|
2701
2755
|
case "agent_message_chunk": {
|
|
2702
2756
|
const text = extractText(u.content);
|
|
2703
2757
|
if (text) {
|
|
2704
2758
|
scratch.text += text;
|
|
2705
|
-
|
|
2759
|
+
emitProgress2({ type: "message", text });
|
|
2706
2760
|
}
|
|
2707
2761
|
return;
|
|
2708
2762
|
}
|
|
@@ -2711,29 +2765,29 @@ function handleAcpSessionUpdate(msg, scratch, emitProgress) {
|
|
|
2711
2765
|
const text = extractText(u.content);
|
|
2712
2766
|
if (text) {
|
|
2713
2767
|
scratch.thoughts += text;
|
|
2714
|
-
|
|
2768
|
+
emitProgress2({ type: "thought", text });
|
|
2715
2769
|
}
|
|
2716
2770
|
return;
|
|
2717
2771
|
}
|
|
2718
2772
|
case "tool_call":
|
|
2719
2773
|
case "tool_call_update":
|
|
2720
|
-
captureToolCall(u, u.sessionUpdate === "tool_call", scratch,
|
|
2774
|
+
captureToolCall(u, u.sessionUpdate === "tool_call", scratch, emitProgress2);
|
|
2721
2775
|
return;
|
|
2722
2776
|
case "plan":
|
|
2723
2777
|
if (Array.isArray(u.entries)) {
|
|
2724
2778
|
scratch.plan = u.entries;
|
|
2725
|
-
|
|
2779
|
+
emitProgress2({ type: "plan", entries: u.entries });
|
|
2726
2780
|
}
|
|
2727
2781
|
return;
|
|
2728
2782
|
case "usage_update":
|
|
2729
|
-
if (typeof u.used === "number" && typeof u.size === "number") {
|
|
2783
|
+
if (typeof u.used === "number" && Number.isFinite(u.used) && u.used >= 0 && typeof u.size === "number" && Number.isFinite(u.size) && u.size >= 0) {
|
|
2730
2784
|
const usage = {
|
|
2731
2785
|
used: u.used,
|
|
2732
2786
|
size: u.size,
|
|
2733
2787
|
...typeof u.cost === "object" && u.cost !== null ? { cost: u.cost } : {}
|
|
2734
2788
|
};
|
|
2735
2789
|
scratch.usage = usage;
|
|
2736
|
-
|
|
2790
|
+
emitProgress2({ type: "usage", usage });
|
|
2737
2791
|
}
|
|
2738
2792
|
return;
|
|
2739
2793
|
case "available_commands_update":
|
|
@@ -2748,7 +2802,7 @@ function handleAcpSessionUpdate(msg, scratch, emitProgress) {
|
|
|
2748
2802
|
return;
|
|
2749
2803
|
}
|
|
2750
2804
|
}
|
|
2751
|
-
function captureToolCall(u, isNew, scratch,
|
|
2805
|
+
function captureToolCall(u, isNew, scratch, emitProgress2) {
|
|
2752
2806
|
const toolCallId = typeof u.toolCallId === "string" ? u.toolCallId : "";
|
|
2753
2807
|
if (!toolCallId) return;
|
|
2754
2808
|
const prev = scratch.toolCalls.get(toolCallId);
|
|
@@ -2770,16 +2824,119 @@ function captureToolCall(u, isNew, scratch, emitProgress) {
|
|
|
2770
2824
|
newText: c.newText
|
|
2771
2825
|
};
|
|
2772
2826
|
scratch.diffs.push(diff);
|
|
2773
|
-
|
|
2827
|
+
emitProgress2({ type: "diff", diff });
|
|
2774
2828
|
}
|
|
2775
2829
|
}
|
|
2776
2830
|
}
|
|
2777
|
-
|
|
2831
|
+
emitProgress2({
|
|
2778
2832
|
type: isNew ? "tool_call" : "tool_call_update",
|
|
2779
2833
|
toolCall: record
|
|
2780
2834
|
});
|
|
2781
2835
|
}
|
|
2782
2836
|
|
|
2837
|
+
// src/client/acp-session-messages.ts
|
|
2838
|
+
function responseSender() {
|
|
2839
|
+
return {
|
|
2840
|
+
sendResult: (id, result) => this.sendResult(id, result),
|
|
2841
|
+
sendErrorResponse: (id, code, message) => this.sendErrorResponse(id, code, message)
|
|
2842
|
+
};
|
|
2843
|
+
}
|
|
2844
|
+
function callbackOptions() {
|
|
2845
|
+
const promptSignal = this.promptCallbackAbort?.signal;
|
|
2846
|
+
const signal = promptSignal ? AbortSignal.any([this.callbackAbort.signal, promptSignal]) : this.callbackAbort.signal;
|
|
2847
|
+
return { signal, permissionTimeoutMs: Number.POSITIVE_INFINITY };
|
|
2848
|
+
}
|
|
2849
|
+
function handleMessage(msg) {
|
|
2850
|
+
if (msg.id !== void 0 && (msg.result !== void 0 || msg.error !== void 0)) {
|
|
2851
|
+
const pending = this.pending.get(msg.id);
|
|
2852
|
+
if (!pending) return;
|
|
2853
|
+
clearTimeout(pending.timeoutHandle);
|
|
2854
|
+
this.pending.delete(msg.id);
|
|
2855
|
+
if (msg.error !== void 0) {
|
|
2856
|
+
const method = pending.method;
|
|
2857
|
+
const kind = method === "session/new" ? "session_create_failed" : method === "authenticate" ? "auth_failed" : "protocol_error";
|
|
2858
|
+
pending.reject(
|
|
2859
|
+
new ACPSessionError(kind, msg.error.message ?? "unknown JSON-RPC error", msg.error)
|
|
2860
|
+
);
|
|
2861
|
+
} else {
|
|
2862
|
+
pending.resolve(msg.result);
|
|
2863
|
+
}
|
|
2864
|
+
return;
|
|
2865
|
+
}
|
|
2866
|
+
if (msg.method === "session/update") {
|
|
2867
|
+
const updateSessionId = msg.params?.sessionId;
|
|
2868
|
+
if (typeof updateSessionId === "string" && updateSessionId !== this.sessionId) return;
|
|
2869
|
+
handleAcpSessionUpdate(msg, this.scratch, (event) => this.emitProgress(event));
|
|
2870
|
+
return;
|
|
2871
|
+
}
|
|
2872
|
+
if (msg.method === "session/request_permission") {
|
|
2873
|
+
handleAcpPermissionRequest(
|
|
2874
|
+
msg,
|
|
2875
|
+
this.permissionPolicy,
|
|
2876
|
+
this.responseSender(),
|
|
2877
|
+
this.callbackOptions()
|
|
2878
|
+
).catch(() => {
|
|
2879
|
+
});
|
|
2880
|
+
return;
|
|
2881
|
+
}
|
|
2882
|
+
if (msg.method === "fs/read_text_file" || msg.method === "fs/write_text_file") {
|
|
2883
|
+
handleAcpFsRequest(
|
|
2884
|
+
msg,
|
|
2885
|
+
this.fileServer,
|
|
2886
|
+
this.permissionPolicy,
|
|
2887
|
+
this.responseSender(),
|
|
2888
|
+
this.callbackOptions()
|
|
2889
|
+
).catch(() => {
|
|
2890
|
+
});
|
|
2891
|
+
return;
|
|
2892
|
+
}
|
|
2893
|
+
if (msg.method?.startsWith("terminal/")) {
|
|
2894
|
+
handleAcpTerminalRequest(
|
|
2895
|
+
msg,
|
|
2896
|
+
this.terminalServer,
|
|
2897
|
+
this.permissionPolicy,
|
|
2898
|
+
this.responseSender(),
|
|
2899
|
+
this.callbackOptions()
|
|
2900
|
+
).catch(() => {
|
|
2901
|
+
});
|
|
2902
|
+
return;
|
|
2903
|
+
}
|
|
2904
|
+
if (isBestEffortAckMethod(msg.method)) {
|
|
2905
|
+
if (msg.id !== void 0) {
|
|
2906
|
+
this.sendErrorResponse(msg.id, -32601, `Unsupported method: ${msg.method}`).catch(() => {
|
|
2907
|
+
});
|
|
2908
|
+
}
|
|
2909
|
+
return;
|
|
2910
|
+
}
|
|
2911
|
+
if (msg.method === "$/cancel_request") {
|
|
2912
|
+
return;
|
|
2913
|
+
}
|
|
2914
|
+
if (msg.method) {
|
|
2915
|
+
if (msg.id !== void 0) {
|
|
2916
|
+
void this.sendErrorResponse(msg.id, -32601, `Unsupported method: ${msg.method}`).catch(
|
|
2917
|
+
() => {
|
|
2918
|
+
}
|
|
2919
|
+
);
|
|
2920
|
+
return;
|
|
2921
|
+
}
|
|
2922
|
+
console.warn(
|
|
2923
|
+
JSON.stringify({
|
|
2924
|
+
level: "warn",
|
|
2925
|
+
event: "acp_session.unhandled_method",
|
|
2926
|
+
method: msg.method,
|
|
2927
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2928
|
+
})
|
|
2929
|
+
);
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
function emitProgress(event) {
|
|
2933
|
+
if (!this.progressHandler) return;
|
|
2934
|
+
try {
|
|
2935
|
+
this.progressHandler(event);
|
|
2936
|
+
} catch {
|
|
2937
|
+
}
|
|
2938
|
+
}
|
|
2939
|
+
|
|
2783
2940
|
// src/client/permission.ts
|
|
2784
2941
|
function pickAllow(options) {
|
|
2785
2942
|
const ranked = [...options].sort((a, b) => {
|
|
@@ -2818,6 +2975,7 @@ function makePermissionPolicy(decide) {
|
|
|
2818
2975
|
return async (req) => {
|
|
2819
2976
|
if (req.signal.aborted) return { outcome: "cancelled" };
|
|
2820
2977
|
const allow = await decide(req);
|
|
2978
|
+
if (req.signal.aborted) return { outcome: "cancelled" };
|
|
2821
2979
|
return allow ? pickAllow(req.options) : pickReject(req.options);
|
|
2822
2980
|
};
|
|
2823
2981
|
}
|
|
@@ -2870,8 +3028,8 @@ var TerminalServer = class {
|
|
|
2870
3028
|
constructor(opts) {
|
|
2871
3029
|
this.projectRoot = path3.resolve(opts.projectRoot);
|
|
2872
3030
|
this.commandTimeoutMs = opts.commandTimeoutMs ?? 5 * 6e4;
|
|
2873
|
-
this.outputByteLimit = opts.outputByteLimit
|
|
2874
|
-
this.maxOutputByteLimit = opts.maxOutputByteLimit
|
|
3031
|
+
this.outputByteLimit = this.clampFiniteInt(opts.outputByteLimit, 1024 * 1024);
|
|
3032
|
+
this.maxOutputByteLimit = this.clampFiniteInt(opts.maxOutputByteLimit, 16 * 1024 * 1024);
|
|
2875
3033
|
this.instanceId = `term_srv_${randomBytes2(4).toString("hex")}`;
|
|
2876
3034
|
this.maxTerminals = this.clampFiniteInt(opts.maxTerminals, 32);
|
|
2877
3035
|
this.abortSignal = opts.signal;
|
|
@@ -2932,7 +3090,7 @@ var TerminalServer = class {
|
|
|
2932
3090
|
clearTimeout(state.timeoutHandle);
|
|
2933
3091
|
state.timeoutHandle = null;
|
|
2934
3092
|
}
|
|
2935
|
-
const exitStatus = {
|
|
3093
|
+
const exitStatus = state.exitStatus ?? {
|
|
2936
3094
|
exitCode: typeof code === "number" ? code : null,
|
|
2937
3095
|
signal: typeof signalName === "string" ? signalName : null
|
|
2938
3096
|
};
|
|
@@ -3132,7 +3290,7 @@ var TerminalServer = class {
|
|
|
3132
3290
|
* unbounded memory growth.
|
|
3133
3291
|
*/
|
|
3134
3292
|
clampFiniteInt(value, defaultValue) {
|
|
3135
|
-
if (value === void 0 || !Number.isFinite(value) || value < 1) {
|
|
3293
|
+
if (value === void 0 || !Number.isFinite(value) || value < 1 || !Number.isSafeInteger(Math.trunc(value))) {
|
|
3136
3294
|
return defaultValue;
|
|
3137
3295
|
}
|
|
3138
3296
|
return Math.trunc(value);
|
|
@@ -3263,7 +3421,7 @@ var WebSocketClientTransport = class {
|
|
|
3263
3421
|
)
|
|
3264
3422
|
);
|
|
3265
3423
|
}
|
|
3266
|
-
const timeoutMs = this.opts.handshakeTimeoutMs
|
|
3424
|
+
const timeoutMs = finitePositiveLimit(this.opts.handshakeTimeoutMs, 3e4);
|
|
3267
3425
|
return new Promise((resolve5, reject) => {
|
|
3268
3426
|
const ws = new WS(this.opts.url, this.opts.protocols);
|
|
3269
3427
|
ws.binaryType = "arraybuffer";
|
|
@@ -3409,7 +3567,9 @@ var WebSocketClientTransport = class {
|
|
|
3409
3567
|
}
|
|
3410
3568
|
};
|
|
3411
3569
|
function finitePositiveLimit(value, fallback) {
|
|
3412
|
-
|
|
3570
|
+
if (value === void 0 || !Number.isFinite(value)) return fallback;
|
|
3571
|
+
const normalized = Math.floor(value);
|
|
3572
|
+
return Number.isSafeInteger(normalized) && normalized >= 1 ? normalized : fallback;
|
|
3413
3573
|
}
|
|
3414
3574
|
|
|
3415
3575
|
// src/client/acp-session.ts
|
|
@@ -3621,7 +3781,9 @@ var ACPSession = class _ACPSession {
|
|
|
3621
3781
|
opContext() {
|
|
3622
3782
|
const self = this;
|
|
3623
3783
|
return {
|
|
3624
|
-
closed
|
|
3784
|
+
get closed() {
|
|
3785
|
+
return self.closed;
|
|
3786
|
+
},
|
|
3625
3787
|
get sessionId() {
|
|
3626
3788
|
return self.sessionId;
|
|
3627
3789
|
},
|
|
@@ -3723,10 +3885,6 @@ var ACPSession = class _ACPSession {
|
|
|
3723
3885
|
createPromise,
|
|
3724
3886
|
new Promise((_, reject) => {
|
|
3725
3887
|
rejectCreate = reject;
|
|
3726
|
-
if (signal.aborted) {
|
|
3727
|
-
reject(new ACPSessionError("aborted", "prompt was aborted by the parent"));
|
|
3728
|
-
return;
|
|
3729
|
-
}
|
|
3730
3888
|
signal.addEventListener("abort", onCreateAbort, { once: true });
|
|
3731
3889
|
})
|
|
3732
3890
|
]);
|
|
@@ -3744,12 +3902,6 @@ var ACPSession = class _ACPSession {
|
|
|
3744
3902
|
}
|
|
3745
3903
|
signal.removeEventListener("abort", onCreateAbort);
|
|
3746
3904
|
rejectCreate = void 0;
|
|
3747
|
-
if (typeof sessionId !== "string" || sessionId.length === 0) {
|
|
3748
|
-
signal.removeEventListener("abort", onAbort);
|
|
3749
|
-
this.promptCallbackAbort?.abort();
|
|
3750
|
-
this.promptCallbackAbort = null;
|
|
3751
|
-
throw new ACPSessionError("protocol_error", "session/new returned no session id");
|
|
3752
|
-
}
|
|
3753
3905
|
this.sessionId = sessionId;
|
|
3754
3906
|
}
|
|
3755
3907
|
if (signal.aborted) {
|
|
@@ -3932,103 +4084,16 @@ var ACPSession = class _ACPSession {
|
|
|
3932
4084
|
});
|
|
3933
4085
|
}
|
|
3934
4086
|
responseSender() {
|
|
3935
|
-
return
|
|
3936
|
-
sendResult: (id, result) => this.sendResult(id, result),
|
|
3937
|
-
sendErrorResponse: (id, code, message) => this.sendErrorResponse(id, code, message)
|
|
3938
|
-
};
|
|
4087
|
+
return responseSender.call(this.acpSessionMessagesHost());
|
|
3939
4088
|
}
|
|
3940
4089
|
callbackOptions() {
|
|
3941
|
-
|
|
3942
|
-
const signal = promptSignal ? AbortSignal.any([this.callbackAbort.signal, promptSignal]) : this.callbackAbort.signal;
|
|
3943
|
-
return { signal, permissionTimeoutMs: Number.POSITIVE_INFINITY };
|
|
4090
|
+
return callbackOptions.call(this.acpSessionMessagesHost());
|
|
3944
4091
|
}
|
|
3945
4092
|
handleMessage(msg) {
|
|
3946
|
-
|
|
3947
|
-
const pending = this.pending.get(msg.id);
|
|
3948
|
-
if (!pending) return;
|
|
3949
|
-
clearTimeout(pending.timeoutHandle);
|
|
3950
|
-
this.pending.delete(msg.id);
|
|
3951
|
-
if (msg.error !== void 0) {
|
|
3952
|
-
const method = pending.method;
|
|
3953
|
-
const kind = method === "session/new" ? "session_create_failed" : method === "authenticate" ? "auth_failed" : "protocol_error";
|
|
3954
|
-
pending.reject(
|
|
3955
|
-
new ACPSessionError(kind, msg.error.message ?? "unknown JSON-RPC error", msg.error)
|
|
3956
|
-
);
|
|
3957
|
-
} else {
|
|
3958
|
-
pending.resolve(msg.result);
|
|
3959
|
-
}
|
|
3960
|
-
return;
|
|
3961
|
-
}
|
|
3962
|
-
if (msg.method === "session/update") {
|
|
3963
|
-
handleAcpSessionUpdate(msg, this.scratch, (event) => this.emitProgress(event));
|
|
3964
|
-
return;
|
|
3965
|
-
}
|
|
3966
|
-
if (msg.method === "session/request_permission") {
|
|
3967
|
-
handleAcpPermissionRequest(
|
|
3968
|
-
msg,
|
|
3969
|
-
this.permissionPolicy,
|
|
3970
|
-
this.responseSender(),
|
|
3971
|
-
this.callbackOptions()
|
|
3972
|
-
).catch(() => {
|
|
3973
|
-
});
|
|
3974
|
-
return;
|
|
3975
|
-
}
|
|
3976
|
-
if (msg.method === "fs/read_text_file" || msg.method === "fs/write_text_file") {
|
|
3977
|
-
handleAcpFsRequest(
|
|
3978
|
-
msg,
|
|
3979
|
-
this.fileServer,
|
|
3980
|
-
this.permissionPolicy,
|
|
3981
|
-
this.responseSender(),
|
|
3982
|
-
this.callbackOptions()
|
|
3983
|
-
).catch(() => {
|
|
3984
|
-
});
|
|
3985
|
-
return;
|
|
3986
|
-
}
|
|
3987
|
-
if (msg.method?.startsWith("terminal/")) {
|
|
3988
|
-
handleAcpTerminalRequest(
|
|
3989
|
-
msg,
|
|
3990
|
-
this.terminalServer,
|
|
3991
|
-
this.permissionPolicy,
|
|
3992
|
-
this.responseSender(),
|
|
3993
|
-
this.callbackOptions()
|
|
3994
|
-
).catch(() => {
|
|
3995
|
-
});
|
|
3996
|
-
return;
|
|
3997
|
-
}
|
|
3998
|
-
if (isBestEffortAckMethod(msg.method)) {
|
|
3999
|
-
if (msg.id !== void 0) {
|
|
4000
|
-
this.sendErrorResponse(msg.id, -32601, `Unsupported method: ${msg.method}`).catch(() => {
|
|
4001
|
-
});
|
|
4002
|
-
}
|
|
4003
|
-
return;
|
|
4004
|
-
}
|
|
4005
|
-
if (msg.method === "$/cancel_request") {
|
|
4006
|
-
return;
|
|
4007
|
-
}
|
|
4008
|
-
if (msg.method) {
|
|
4009
|
-
if (msg.id !== void 0) {
|
|
4010
|
-
void this.sendErrorResponse(msg.id, -32601, `Unsupported method: ${msg.method}`).catch(
|
|
4011
|
-
() => {
|
|
4012
|
-
}
|
|
4013
|
-
);
|
|
4014
|
-
return;
|
|
4015
|
-
}
|
|
4016
|
-
console.warn(
|
|
4017
|
-
JSON.stringify({
|
|
4018
|
-
level: "warn",
|
|
4019
|
-
event: "acp_session.unhandled_method",
|
|
4020
|
-
method: msg.method,
|
|
4021
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
4022
|
-
})
|
|
4023
|
-
);
|
|
4024
|
-
}
|
|
4093
|
+
handleMessage.call(this.acpSessionMessagesHost(), msg);
|
|
4025
4094
|
}
|
|
4026
4095
|
emitProgress(event) {
|
|
4027
|
-
|
|
4028
|
-
try {
|
|
4029
|
-
this.progressHandler(event);
|
|
4030
|
-
} catch {
|
|
4031
|
-
}
|
|
4096
|
+
emitProgress.call(this.acpSessionMessagesHost(), event);
|
|
4032
4097
|
}
|
|
4033
4098
|
progressHandler = null;
|
|
4034
4099
|
scratch = createSessionScratch();
|
|
@@ -4058,6 +4123,23 @@ var ACPSession = class _ACPSession {
|
|
|
4058
4123
|
opts: this.opts
|
|
4059
4124
|
};
|
|
4060
4125
|
}
|
|
4126
|
+
acpSessionMessagesHost() {
|
|
4127
|
+
void this.sendResult;
|
|
4128
|
+
void this.sendErrorResponse;
|
|
4129
|
+
void this.promptCallbackAbort;
|
|
4130
|
+
void this.callbackAbort;
|
|
4131
|
+
void this.pending;
|
|
4132
|
+
void this.sessionId;
|
|
4133
|
+
void this.scratch;
|
|
4134
|
+
void this.emitProgress;
|
|
4135
|
+
void this.permissionPolicy;
|
|
4136
|
+
void this.responseSender;
|
|
4137
|
+
void this.callbackOptions;
|
|
4138
|
+
void this.fileServer;
|
|
4139
|
+
void this.terminalServer;
|
|
4140
|
+
void this.progressHandler;
|
|
4141
|
+
return this;
|
|
4142
|
+
}
|
|
4061
4143
|
};
|
|
4062
4144
|
|
|
4063
4145
|
// src/client/tool-translator.ts
|
|
@@ -4103,18 +4185,30 @@ var ToolTranslator = class {
|
|
|
4103
4185
|
* response arrives.
|
|
4104
4186
|
*/
|
|
4105
4187
|
async callTool(transport, name, args, callId = crypto.randomUUID()) {
|
|
4106
|
-
|
|
4107
|
-
jsonrpc: "2.0",
|
|
4108
|
-
method: "tools/call",
|
|
4109
|
-
id: callId,
|
|
4110
|
-
params: { name, arguments: args }
|
|
4111
|
-
});
|
|
4188
|
+
if (this.pending.has(callId)) throw new Error(`Tool call id ${callId} is already pending`);
|
|
4112
4189
|
return new Promise((resolve5, reject) => {
|
|
4113
4190
|
const timeout = setTimeout(() => {
|
|
4114
4191
|
this.pending.delete(callId);
|
|
4115
4192
|
reject(new Error(`Tool call ${name} timed out after ${this.opts.totalTimeoutMs}ms`));
|
|
4116
4193
|
}, this.opts.totalTimeoutMs);
|
|
4117
|
-
|
|
4194
|
+
const pending = { resolve: resolve5, reject, timeout };
|
|
4195
|
+
this.pending.set(callId, pending);
|
|
4196
|
+
const failSend = (err) => {
|
|
4197
|
+
if (this.pending.get(callId) !== pending) return;
|
|
4198
|
+
clearTimeout(timeout);
|
|
4199
|
+
this.pending.delete(callId);
|
|
4200
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
4201
|
+
};
|
|
4202
|
+
try {
|
|
4203
|
+
transport.send({
|
|
4204
|
+
jsonrpc: "2.0",
|
|
4205
|
+
method: "tools/call",
|
|
4206
|
+
id: callId,
|
|
4207
|
+
params: { name, arguments: args }
|
|
4208
|
+
}).catch(failSend);
|
|
4209
|
+
} catch (err) {
|
|
4210
|
+
failSend(err);
|
|
4211
|
+
}
|
|
4118
4212
|
});
|
|
4119
4213
|
}
|
|
4120
4214
|
cancelAll() {
|
|
@@ -4248,7 +4342,8 @@ async function runAcpBench(opts) {
|
|
|
4248
4342
|
const timeoutMs = opts.timeoutMs ?? 6e4;
|
|
4249
4343
|
const checkFs = opts.checkFs ?? false;
|
|
4250
4344
|
const marker = opts.marker ?? randomMarker();
|
|
4251
|
-
const
|
|
4345
|
+
const requestedConcurrency = opts.concurrency ?? 2;
|
|
4346
|
+
const concurrency = Number.isNaN(requestedConcurrency) ? 2 : Math.max(1, Math.floor(requestedConcurrency));
|
|
4252
4347
|
const seen = /* @__PURE__ */ new Set();
|
|
4253
4348
|
const ids = [];
|
|
4254
4349
|
for (const raw of opts.agentIds) {
|
|
@@ -5088,7 +5183,8 @@ var DEFAULT_MAX_CONCURRENCY = 4;
|
|
|
5088
5183
|
async function mapBound(items, worker, limit) {
|
|
5089
5184
|
const results = new Array(items.length);
|
|
5090
5185
|
if (items.length === 0) return results;
|
|
5091
|
-
const
|
|
5186
|
+
const normalizedLimit = Number.isNaN(limit) ? DEFAULT_MAX_CONCURRENCY : Math.floor(limit);
|
|
5187
|
+
const safeLimit = Math.max(1, Math.min(normalizedLimit, items.length));
|
|
5092
5188
|
let nextIndex = 0;
|
|
5093
5189
|
const workerCount = Math.min(safeLimit, items.length);
|
|
5094
5190
|
const runners = [];
|