acpx 0.18.0 → 0.19.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/dist/{agent-registry-DdKB-zia.js → agent-registry-Ct2yWPW7.js} +3 -2
- package/dist/agent-registry-Ct2yWPW7.js.map +1 -0
- package/dist/agent-registry.js +1 -1
- package/dist/{cli-8mVHeUXh.js → cli-Bmki9cj5.js} +5 -5
- package/dist/{cli-8mVHeUXh.js.map → cli-Bmki9cj5.js.map} +1 -1
- package/dist/cli.js +55 -47
- package/dist/cli.js.map +1 -1
- package/dist/{client-DeNKZZcu.d.ts → client-DzaUKazo.d.ts} +10 -4
- package/dist/client-DzaUKazo.d.ts.map +1 -0
- package/dist/{flows-WOQNzCMC.js → flows--Ewxn_fQ.js} +665 -460
- package/dist/flows--Ewxn_fQ.js.map +1 -0
- package/dist/flows.d.ts +19 -7
- package/dist/flows.d.ts.map +1 -1
- package/dist/flows.js +1 -1
- package/dist/{invocation-options-B6d7TI-y.js → invocation-options-DRzxHZmr.js} +32 -11
- package/dist/invocation-options-DRzxHZmr.js.map +1 -0
- package/dist/{ipc-BJrvfNXr.js → ipc-fMgj5vrO.js} +540 -241
- package/dist/ipc-fMgj5vrO.js.map +1 -0
- package/dist/{output-CL18YmsG.js → output-D6kDs8BN.js} +24 -11
- package/dist/output-D6kDs8BN.js.map +1 -0
- package/dist/{queue-owner-runtime-Cr0dWJuL.js → queue-owner-runtime-CLwjMYNL.js} +549 -337
- package/dist/queue-owner-runtime-CLwjMYNL.js.map +1 -0
- package/dist/runtime.d.ts +19 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +47 -28
- package/dist/runtime.js.map +1 -1
- package/dist/session-options-Dp6mzNSy.d.ts.map +1 -1
- package/dist/{session-watch-B8Q_TsGf.js → session-watch-BfdIo-n4.js} +5 -5
- package/dist/session-watch-BfdIo-n4.js.map +1 -0
- package/dist/{watch-Dp73ph8h.js → watch-DH-zXQH2.js} +2 -2
- package/dist/{watch-Dp73ph8h.js.map → watch-DH-zXQH2.js.map} +1 -1
- package/package.json +1 -1
- package/skills/acpx/SKILL.md +43 -23
- package/dist/agent-registry-DdKB-zia.js.map +0 -1
- package/dist/client-DeNKZZcu.d.ts.map +0 -1
- package/dist/flows-WOQNzCMC.js.map +0 -1
- package/dist/invocation-options-B6d7TI-y.js.map +0 -1
- package/dist/ipc-BJrvfNXr.js.map +0 -1
- package/dist/output-CL18YmsG.js.map +0 -1
- package/dist/queue-owner-runtime-Cr0dWJuL.js.map +0 -1
- package/dist/session-watch-B8Q_TsGf.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import { A as resolveAgentCommandParts, C as asAbsoluteCwd, E as isoNow$2, F as waitForSpawn, M as runTimedExecFile, N as splitCommandLine, P as waitForChildExit, S as PROCESS_HELPER_TIMEOUT_MS, T as isChildProcessRunning, _ as buildSpawnCommandOptions, b as readWindowsEnvValue, f as resolveBuiltInAgentLaunch, g as buildAgentSpawnCommand, j as resolveAgentSessionCwd, k as requireAgentStdio, v as buildTerminalShellSpawnCommand, w as basenameToken, x as resolveWindowsExecutablePath, y as buildTerminalSpawnCommand } from "./agent-registry-
|
|
1
|
+
import { $ as measurePerf, A as findGitRepositoryRoot, B as writeSessionRecord, Bt as PermissionDeniedError, C as getUnsupportedPromptContentMessage, D as textPrompt, Dt as OUTPUT_ERROR_ORIGINS, E as promptToDisplayText, Et as OUTPUT_ERROR_CODES, Ft as AgentStartupError, G as normalizeAgentSessionId, Gt as SessionModelReplayError, Ht as QueueConnectionError, I as normalizeName, It as AuthPolicyError, Jt as UnsupportedPromptContentError, K as SESSION_JOURNAL_SCHEMA, Lt as ClaudeAcpSessionCreateTimeoutError, M as findSessionByDirectoryWalk, Mt as AcpxOperationalError, N as isoNow$1, Nt as AgentDisconnectedError, Pt as AgentSpawnError, Q as incrementPerfCounter, Rt as CopilotAcpUnsupportedError, St as isAcpResourceNotFoundError, Ut as SessionConfigOptionReplayError, Vt as PermissionPromptUnavailableError, W as extractAgentSessionId, Wt as SessionModeReplayError, X as formatPerfMetric, Z as getPerfMetricsSnapshot, _ as waitMs$1, a as trySetModelOnRunningOwner, at as isAcpJsonRpcMessage, b as lockOwnerPid, bt as extractAcpError, c as queueRequestExceedsLimit, et as recordPerfDuration, f as refreshQueueOwnerLease, ft as defaultSessionEventLog, g as tryAcquireQueueOwnerLease, gt as sessionEventSegmentPath, h as terminateQueueOwnerForSession, ht as sessionEventLockPath, i as trySetModeOnRunningOwner, k as absolutePath, l as parseQueueRequest, m as terminateProcess, mt as sessionEventActivePath, n as tryCloseSessionOnRunningOwner, nt as setPerfGauge, o as trySubmitToRunningOwner, ot as isAcpMessageObject, p as releaseQueueOwnerLease, pt as sessionBaseDir, q as SessionJournalReader, qt as SessionResumeRequiredError, r as trySetConfigOptionOnRunningOwner, rt as startPerfTimer, s as queueRequestByteLimit, st as isSessionUpdateNotification, t as tryCancelOnRunningOwner, tt as resetPerfMetrics, v as QueueLeaseGuardSettlementError, wt as EXIT_CODES, x as readProcessTable, xt as formatUnknownErrorMessage, y as createLockOwner, yt as isProcessAlive, z as resolveSessionRecord, zt as GeminiAcpStartupTimeoutError } from "./ipc-fMgj5vrO.js";
|
|
2
|
+
import { A as resolveAgentCommandParts, C as asAbsoluteCwd, E as isoNow$2, F as waitForSpawn, M as runTimedExecFile, N as splitCommandLine, P as waitForChildExit, S as PROCESS_HELPER_TIMEOUT_MS, T as isChildProcessRunning, _ as buildSpawnCommandOptions, b as readWindowsEnvValue, f as resolveBuiltInAgentLaunch, g as buildAgentSpawnCommand, j as resolveAgentSessionCwd, k as requireAgentStdio, v as buildTerminalShellSpawnCommand, w as basenameToken, x as resolveWindowsExecutablePath, y as buildTerminalSpawnCommand } from "./agent-registry-Ct2yWPW7.js";
|
|
3
3
|
import fs, { readFileSync, realpathSync } from "node:fs";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
5
|
import path from "node:path";
|
|
@@ -485,6 +485,17 @@ function normalizeQueueOwnerTtlMs(ttlMs) {
|
|
|
485
485
|
return Math.round(ttlMs);
|
|
486
486
|
}
|
|
487
487
|
//#endregion
|
|
488
|
+
//#region src/file-read-window.ts
|
|
489
|
+
function sliceReadWindow(content, line, limit) {
|
|
490
|
+
if (line == null && limit == null) return content;
|
|
491
|
+
const lines = content.split("\n");
|
|
492
|
+
const startIndex = Math.max(0, (line == null ? 1 : Math.max(1, Math.trunc(line))) - 1);
|
|
493
|
+
const maxLines = limit == null ? void 0 : Math.max(0, Math.trunc(limit));
|
|
494
|
+
if (maxLines === 0) return "";
|
|
495
|
+
const endIndex = maxLines == null ? lines.length : Math.min(lines.length, startIndex + maxLines);
|
|
496
|
+
return lines.slice(startIndex, endIndex).join("\n");
|
|
497
|
+
}
|
|
498
|
+
//#endregion
|
|
488
499
|
//#region src/permission-prompt.ts
|
|
489
500
|
let promptQueue = Promise.resolve();
|
|
490
501
|
async function promptForPermission(options) {
|
|
@@ -598,7 +609,7 @@ var FileSystemHandlers = class {
|
|
|
598
609
|
if (this.permissionMode === "deny-all") throw new PermissionDeniedError("Permission denied for fs/read_text_file (--deny-all)");
|
|
599
610
|
const content = await (await this.getWorkspace()).readText(filePath);
|
|
600
611
|
assertControlAuthority(authority);
|
|
601
|
-
const sliced =
|
|
612
|
+
const sliced = sliceReadWindow(content, params.line, params.limit);
|
|
602
613
|
this.emitOperation({
|
|
603
614
|
method: "fs/read_text_file",
|
|
604
615
|
status: "completed",
|
|
@@ -686,15 +697,6 @@ var FileSystemHandlers = class {
|
|
|
686
697
|
maxBytes: Infinity
|
|
687
698
|
});
|
|
688
699
|
}
|
|
689
|
-
sliceContent(content, line, limit) {
|
|
690
|
-
if (line == null && limit == null) return content;
|
|
691
|
-
const lines = content.split("\n");
|
|
692
|
-
const startIndex = Math.max(0, (line == null ? 1 : Math.max(1, Math.trunc(line))) - 1);
|
|
693
|
-
const maxLines = limit == null ? void 0 : Math.max(0, Math.trunc(limit));
|
|
694
|
-
if (maxLines === 0) return "";
|
|
695
|
-
const endIndex = maxLines == null ? lines.length : Math.min(lines.length, startIndex + maxLines);
|
|
696
|
-
return lines.slice(startIndex, endIndex).join("\n");
|
|
697
|
-
}
|
|
698
700
|
readWindowDetails(line, limit) {
|
|
699
701
|
if (line == null && limit == null) return;
|
|
700
702
|
return `line=${line == null ? 1 : Math.max(1, Math.trunc(line))}, limit=${limit == null ? "all" : Math.max(0, Math.trunc(limit))}`;
|
|
@@ -1556,15 +1558,22 @@ function enqueueNdJsonLine(agentCommand, line, controller) {
|
|
|
1556
1558
|
console.error("Failed to parse JSON message:", trimmedLine, err);
|
|
1557
1559
|
}
|
|
1558
1560
|
}
|
|
1559
|
-
function
|
|
1561
|
+
function enqueueNdJsonChunk(agentCommand, chunk, fragments, controller) {
|
|
1562
|
+
const lines = chunk.split("\n");
|
|
1563
|
+
const suffix = lines.pop() || "";
|
|
1564
|
+
if (lines.length > 0 && fragments.length > 0) {
|
|
1565
|
+
lines[0] = fragments.join("") + lines[0];
|
|
1566
|
+
fragments.length = 0;
|
|
1567
|
+
}
|
|
1560
1568
|
for (const line of lines) enqueueNdJsonLine(agentCommand, line, controller);
|
|
1569
|
+
if (suffix) fragments.push(suffix);
|
|
1561
1570
|
}
|
|
1562
1571
|
function createNdJsonMessageStream(agentCommand, output, input, maxMessageBytes, onReadError) {
|
|
1563
1572
|
const textEncoder = new TextEncoder();
|
|
1564
1573
|
const textDecoder = new TextDecoder();
|
|
1565
1574
|
return {
|
|
1566
1575
|
readable: new ReadableStream({ async start(controller) {
|
|
1567
|
-
|
|
1576
|
+
const fragments = [];
|
|
1568
1577
|
let retainedBytes = 0;
|
|
1569
1578
|
const reader = input.getReader();
|
|
1570
1579
|
try {
|
|
@@ -1572,10 +1581,7 @@ function createNdJsonMessageStream(agentCommand, output, input, maxMessageBytes,
|
|
|
1572
1581
|
const { value, done } = await reader.read();
|
|
1573
1582
|
if (done) break;
|
|
1574
1583
|
if (maxMessageBytes !== void 0) retainedBytes = countLineBytes(value, retainedBytes, maxMessageBytes);
|
|
1575
|
-
|
|
1576
|
-
const lines = content.split("\n");
|
|
1577
|
-
content = lines.pop() || "";
|
|
1578
|
-
enqueueNdJsonLines(agentCommand, lines, controller);
|
|
1584
|
+
enqueueNdJsonChunk(agentCommand, textDecoder.decode(value, { stream: true }), fragments, controller);
|
|
1579
1585
|
}
|
|
1580
1586
|
controller.close();
|
|
1581
1587
|
} catch (err) {
|
|
@@ -1667,65 +1673,88 @@ function promptRequestOwner(message) {
|
|
|
1667
1673
|
}
|
|
1668
1674
|
//#endregion
|
|
1669
1675
|
//#region src/acp/process-descendants.ts
|
|
1670
|
-
function parseProcessTable(output) {
|
|
1671
|
-
const table = /* @__PURE__ */ new Map();
|
|
1672
|
-
for (const line of output.split("\n")) {
|
|
1673
|
-
const match = /^\s*(\d+)\s+(\d+)\s+(\S+)\s+(.+?)\s*$/.exec(line);
|
|
1674
|
-
if (match && !match[3].startsWith("Z")) {
|
|
1675
|
-
const pid = Number(match[1]);
|
|
1676
|
-
if (Number.isSafeInteger(pid) && pid > 1 && pid !== process.pid) table.set(pid, {
|
|
1677
|
-
pid,
|
|
1678
|
-
parentPid: Number(match[2]),
|
|
1679
|
-
birth: match[4]
|
|
1680
|
-
});
|
|
1681
|
-
}
|
|
1682
|
-
}
|
|
1683
|
-
return table;
|
|
1684
|
-
}
|
|
1685
1676
|
function includeDescendants(table, owned) {
|
|
1686
1677
|
let expanded;
|
|
1687
1678
|
do {
|
|
1688
1679
|
expanded = false;
|
|
1689
|
-
for (const identity of table.values())
|
|
1690
|
-
|
|
1691
|
-
|
|
1680
|
+
for (const identity of table.values()) {
|
|
1681
|
+
const parent = table.get(identity.parentPid);
|
|
1682
|
+
if (process.platform === "win32" && (!parent || parent.birth > identity.birth)) continue;
|
|
1683
|
+
if (owned.has(identity.parentPid) && !owned.has(identity.pid)) {
|
|
1684
|
+
owned.add(identity.pid);
|
|
1685
|
+
expanded = true;
|
|
1686
|
+
}
|
|
1692
1687
|
}
|
|
1693
1688
|
} while (expanded);
|
|
1694
1689
|
}
|
|
1695
|
-
/** Best-effort
|
|
1690
|
+
/** Best-effort cleanup for descendants witnessed during this child launch. */
|
|
1696
1691
|
var ProcessDescendants = class {
|
|
1697
1692
|
child;
|
|
1698
1693
|
identities = /* @__PURE__ */ new Map();
|
|
1694
|
+
rootBirth;
|
|
1699
1695
|
pending;
|
|
1700
1696
|
retired = false;
|
|
1701
|
-
|
|
1697
|
+
ownProcessGroup;
|
|
1698
|
+
captureGroupAfterExit;
|
|
1699
|
+
groupExitedAt;
|
|
1700
|
+
onRootExit = () => {
|
|
1701
|
+
this.groupExitedAt = Date.now();
|
|
1702
|
+
};
|
|
1703
|
+
constructor(child, options = {}) {
|
|
1702
1704
|
this.child = child;
|
|
1705
|
+
this.ownProcessGroup = process.platform !== "win32" && Boolean(options.ownProcessGroup);
|
|
1706
|
+
this.captureGroupAfterExit = this.ownProcessGroup && isChildProcessRunning(child);
|
|
1707
|
+
if (this.ownProcessGroup) child.once("exit", this.onRootExit);
|
|
1703
1708
|
}
|
|
1704
1709
|
capture(timeoutMs = PROCESS_HELPER_TIMEOUT_MS) {
|
|
1705
|
-
if (this.retired
|
|
1710
|
+
if (this.retired) return Promise.resolve(true);
|
|
1706
1711
|
this.pending ??= this.readSnapshot(timeoutMs).finally(() => {
|
|
1707
1712
|
this.pending = void 0;
|
|
1708
1713
|
});
|
|
1709
1714
|
return this.pending;
|
|
1710
1715
|
}
|
|
1711
1716
|
async readSnapshot(timeoutMs) {
|
|
1717
|
+
const deadline = performance.now() + timeoutMs;
|
|
1718
|
+
const rootWasRunning = isChildProcessRunning(this.child);
|
|
1719
|
+
const captureRootGroup = rootWasRunning || this.captureGroupAfterExit;
|
|
1720
|
+
if (!rootWasRunning) this.captureGroupAfterExit = false;
|
|
1712
1721
|
try {
|
|
1713
|
-
const
|
|
1714
|
-
if (!this.retired)
|
|
1722
|
+
const table = await readProcessTable(timeoutMs);
|
|
1723
|
+
if (!this.retired) {
|
|
1724
|
+
table.delete(1);
|
|
1725
|
+
table.delete(process.pid);
|
|
1726
|
+
this.refresh(table, captureRootGroup);
|
|
1727
|
+
if (this.captureGroupAfterExit && !isChildProcessRunning(this.child)) return await this.readSnapshot(Math.max(1, deadline - performance.now()));
|
|
1728
|
+
}
|
|
1715
1729
|
return true;
|
|
1716
1730
|
} catch {
|
|
1731
|
+
if (!isChildProcessRunning(this.child)) this.captureGroupAfterExit = false;
|
|
1717
1732
|
return false;
|
|
1718
1733
|
}
|
|
1719
1734
|
}
|
|
1720
|
-
refresh(table) {
|
|
1735
|
+
refresh(table, rootWasRunning) {
|
|
1721
1736
|
const owned = /* @__PURE__ */ new Set();
|
|
1722
1737
|
for (const [pid, identity] of this.identities) if (table.get(pid)?.birth === identity.birth) owned.add(pid);
|
|
1723
|
-
|
|
1724
|
-
if (
|
|
1738
|
+
this.includeRoot(table, owned);
|
|
1739
|
+
if (this.ownProcessGroup) this.includeProcessGroup(table, owned, rootWasRunning);
|
|
1725
1740
|
includeDescendants(table, owned);
|
|
1726
|
-
owned.delete(
|
|
1741
|
+
owned.delete(this.child.pid ?? 0);
|
|
1727
1742
|
this.identities = new Map([...table].filter(([pid]) => owned.has(pid)));
|
|
1728
1743
|
}
|
|
1744
|
+
includeRoot(table, owned) {
|
|
1745
|
+
const root = this.child.pid;
|
|
1746
|
+
const rootIdentity = root && table.get(root);
|
|
1747
|
+
if (rootIdentity && isChildProcessRunning(this.child)) {
|
|
1748
|
+
this.rootBirth ??= rootIdentity.birth;
|
|
1749
|
+
if (rootIdentity.birth === this.rootBirth) owned.add(rootIdentity.pid);
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
includeProcessGroup(table, owned, rootWasRunning) {
|
|
1753
|
+
const root = this.child.pid;
|
|
1754
|
+
if (root && (rootWasRunning || [...owned].some((pid) => table.get(pid)?.groupPid === root))) {
|
|
1755
|
+
for (const identity of table.values()) if (identity.groupPid === root && (this.groupExitedAt === void 0 || Date.parse(identity.birth) <= this.groupExitedAt)) owned.add(identity.pid);
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1729
1758
|
async signal(signal, timeoutMs) {
|
|
1730
1759
|
if (!await this.capture(timeoutMs) || this.retired) return;
|
|
1731
1760
|
for (const pid of this.identities.keys()) try {
|
|
@@ -1734,6 +1763,9 @@ var ProcessDescendants = class {
|
|
|
1734
1763
|
this.identities.delete(pid);
|
|
1735
1764
|
}
|
|
1736
1765
|
}
|
|
1766
|
+
hasTrackedProcesses() {
|
|
1767
|
+
return this.identities.size > 0;
|
|
1768
|
+
}
|
|
1737
1769
|
async waitForExit(timeoutMs) {
|
|
1738
1770
|
const deadline = Date.now() + timeoutMs;
|
|
1739
1771
|
do {
|
|
@@ -1745,6 +1777,7 @@ var ProcessDescendants = class {
|
|
|
1745
1777
|
}
|
|
1746
1778
|
retire() {
|
|
1747
1779
|
this.retired = true;
|
|
1780
|
+
this.child.off("exit", this.onRootExit);
|
|
1748
1781
|
this.identities.clear();
|
|
1749
1782
|
}
|
|
1750
1783
|
};
|
|
@@ -1812,12 +1845,20 @@ function readTerminalOutputCeiling() {
|
|
|
1812
1845
|
if (!/^\d+$/.test(raw) || !Number.isSafeInteger(bytes)) throw new Error("ACPX_TERMINAL_MAX_OUTPUT_BYTES must be a non-negative safe integer; zero disables the host ceiling");
|
|
1813
1846
|
return bytes === 0 ? void 0 : bytes;
|
|
1814
1847
|
}
|
|
1848
|
+
function resolveTerminalOutputLimit(requested, ceiling) {
|
|
1849
|
+
return Math.min(Math.max(0, Math.round(requested ?? DEFAULT_TERMINAL_OUTPUT_LIMIT_BYTES)), ceiling ?? Number.POSITIVE_INFINITY);
|
|
1850
|
+
}
|
|
1851
|
+
function tracksTerminalDescendants(terminal) {
|
|
1852
|
+
return terminal.killProcessGroup || terminal.descendants !== void 0;
|
|
1853
|
+
}
|
|
1854
|
+
function createTerminalDescendants(proc, killProcessGroup) {
|
|
1855
|
+
return process.platform === "win32" && killProcessGroup ? void 0 : new ProcessDescendants(proc, { ownProcessGroup: true });
|
|
1856
|
+
}
|
|
1815
1857
|
function trimToUtf8Boundary(buffer, limit) {
|
|
1816
1858
|
if (limit <= 0) return Buffer.alloc(0);
|
|
1817
|
-
|
|
1818
|
-
let start = buffer.length - limit;
|
|
1859
|
+
let start = Math.max(0, buffer.length - limit);
|
|
1819
1860
|
while (start < buffer.length && (buffer[start] & 192) === 128) start += 1;
|
|
1820
|
-
if (start >= buffer.length)
|
|
1861
|
+
if (start >= buffer.length) return Buffer.alloc(0);
|
|
1821
1862
|
return buffer.subarray(start);
|
|
1822
1863
|
}
|
|
1823
1864
|
async function defaultConfirmExecute(commandLine, signal) {
|
|
@@ -1854,7 +1895,8 @@ var TerminalManager = class {
|
|
|
1854
1895
|
this.onOperation = options.onOperation;
|
|
1855
1896
|
this.usesDefaultConfirmExecute = options.confirmExecute == null;
|
|
1856
1897
|
this.confirmExecute = options.confirmExecute ?? defaultConfirmExecute;
|
|
1857
|
-
|
|
1898
|
+
const killGraceMs = Math.max(0, Math.round(options.killGraceMs ?? DEFAULT_KILL_GRACE_MS));
|
|
1899
|
+
this.killGraceMs = Number.isFinite(killGraceMs) && killGraceMs <= 2147483647 ? killGraceMs : 1;
|
|
1858
1900
|
this.processHelperTimeoutMs = Math.max(1, Math.round(options.processHelperTimeoutMs ?? 8e3));
|
|
1859
1901
|
}
|
|
1860
1902
|
updatePermissionPolicy(permissionMode, nonInteractivePermissions) {
|
|
@@ -1875,8 +1917,7 @@ var TerminalManager = class {
|
|
|
1875
1917
|
const approved = await this.isExecuteApproved(commandLine, authority?.signal);
|
|
1876
1918
|
assertControlAuthority(authority);
|
|
1877
1919
|
if (!approved) throw new PermissionDeniedError("Permission denied for terminal/create");
|
|
1878
|
-
const
|
|
1879
|
-
const outputByteLimit = Math.min(requestedLimit, this.outputCeilingBytes ?? Number.POSITIVE_INFINITY);
|
|
1920
|
+
const outputByteLimit = resolveTerminalOutputLimit(params.outputByteLimit, this.outputCeilingBytes);
|
|
1880
1921
|
const { proc, spawnCommand } = await spawnTerminalProcess(params, this.cwd, authority);
|
|
1881
1922
|
let resolveExit = () => {};
|
|
1882
1923
|
const exitPromise = new Promise((resolve) => {
|
|
@@ -1886,6 +1927,7 @@ var TerminalManager = class {
|
|
|
1886
1927
|
process: proc,
|
|
1887
1928
|
killProcessGroup: spawnCommand.killProcessGroup,
|
|
1888
1929
|
descendantPids: /* @__PURE__ */ new Set(),
|
|
1930
|
+
descendants: createTerminalDescendants(proc, spawnCommand.killProcessGroup),
|
|
1889
1931
|
processHelperTimeoutMs: this.processHelperTimeoutMs,
|
|
1890
1932
|
output: Buffer.alloc(0),
|
|
1891
1933
|
truncated: false,
|
|
@@ -1899,10 +1941,8 @@ var TerminalManager = class {
|
|
|
1899
1941
|
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
1900
1942
|
if (bytes.length === 0) return;
|
|
1901
1943
|
terminal.output = Buffer.concat([terminal.output, bytes]);
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
terminal.truncated = true;
|
|
1905
|
-
}
|
|
1944
|
+
terminal.truncated ||= terminal.output.length > terminal.outputByteLimit;
|
|
1945
|
+
if (terminal.truncated) terminal.output = trimToUtf8Boundary(terminal.output, terminal.outputByteLimit);
|
|
1906
1946
|
};
|
|
1907
1947
|
proc.stdout.on("data", appendOutput);
|
|
1908
1948
|
proc.stderr.on("data", appendOutput);
|
|
@@ -1911,9 +1951,10 @@ var TerminalManager = class {
|
|
|
1911
1951
|
proc.once("exit", (exitCode, signal) => {
|
|
1912
1952
|
terminal.exitCode = exitCode;
|
|
1913
1953
|
terminal.signal = signal;
|
|
1914
|
-
terminal.processGroupSnapshotPromise = rememberProcessGroupPids(terminal);
|
|
1954
|
+
terminal.processGroupSnapshotPromise = terminal.descendants ? terminal.descendants.capture(terminal.processHelperTimeoutMs).then(() => {}) : rememberProcessGroupPids(terminal);
|
|
1915
1955
|
(async () => {
|
|
1916
1956
|
await terminal.processGroupSnapshotPromise;
|
|
1957
|
+
terminal.processGroupSnapshotPromise = void 0;
|
|
1917
1958
|
terminal.resolveExit({
|
|
1918
1959
|
exitCode: exitCode ?? null,
|
|
1919
1960
|
signal: signal ?? null
|
|
@@ -1923,6 +1964,7 @@ var TerminalManager = class {
|
|
|
1923
1964
|
const terminalId = randomUUID();
|
|
1924
1965
|
this.terminals.set(terminalId, terminal);
|
|
1925
1966
|
try {
|
|
1967
|
+
await terminal.descendants?.capture(terminal.processHelperTimeoutMs);
|
|
1926
1968
|
assertControlAuthority(authority);
|
|
1927
1969
|
} catch (error) {
|
|
1928
1970
|
await this.releaseTerminal({
|
|
@@ -2036,6 +2078,9 @@ var TerminalManager = class {
|
|
|
2036
2078
|
try {
|
|
2037
2079
|
await this.killProcess(terminal);
|
|
2038
2080
|
await terminal.exitPromise.catch(() => {});
|
|
2081
|
+
terminal.descendants?.retire();
|
|
2082
|
+
terminal.process.stdout.destroy();
|
|
2083
|
+
terminal.process.stderr.destroy();
|
|
2039
2084
|
terminal.output = Buffer.alloc(0);
|
|
2040
2085
|
this.terminals.delete(params.terminalId);
|
|
2041
2086
|
this.emitOperation({
|
|
@@ -2058,10 +2103,13 @@ var TerminalManager = class {
|
|
|
2058
2103
|
}
|
|
2059
2104
|
}
|
|
2060
2105
|
async shutdown() {
|
|
2061
|
-
|
|
2106
|
+
const results = await Promise.allSettled(Array.from(this.terminals.keys(), (terminalId) => this.releaseTerminal({
|
|
2062
2107
|
terminalId,
|
|
2063
2108
|
sessionId: "shutdown"
|
|
2064
|
-
});
|
|
2109
|
+
})));
|
|
2110
|
+
const failures = [];
|
|
2111
|
+
for (const result of results) if (result.status === "rejected") failures.push(result.reason);
|
|
2112
|
+
if (failures.length > 0) throw new AggregateError(failures, "Terminal shutdown failed", { cause: failures[0] });
|
|
2065
2113
|
}
|
|
2066
2114
|
getTerminal(terminalId) {
|
|
2067
2115
|
return this.terminals.get(terminalId);
|
|
@@ -2079,13 +2127,13 @@ var TerminalManager = class {
|
|
|
2079
2127
|
return terminal.exitCode === void 0 && terminal.signal === void 0;
|
|
2080
2128
|
}
|
|
2081
2129
|
async killProcess(terminal) {
|
|
2082
|
-
if (!this.isRunning(terminal) && !terminal
|
|
2130
|
+
if (!this.isRunning(terminal) && !tracksTerminalDescendants(terminal)) return;
|
|
2083
2131
|
try {
|
|
2084
2132
|
await this.signalProcess(terminal, "SIGTERM");
|
|
2085
2133
|
} catch {
|
|
2086
2134
|
return;
|
|
2087
2135
|
}
|
|
2088
|
-
if (await this.waitForCleanupAfterSignal(terminal) && !terminal.killProcessGroup) return;
|
|
2136
|
+
if (await this.waitForCleanupAfterSignal(terminal) && (!terminal.killProcessGroup || terminal.descendants)) return;
|
|
2089
2137
|
try {
|
|
2090
2138
|
await this.signalProcess(terminal, "SIGKILL");
|
|
2091
2139
|
} catch {
|
|
@@ -2094,15 +2142,16 @@ var TerminalManager = class {
|
|
|
2094
2142
|
await this.waitForFinalCleanup(terminal);
|
|
2095
2143
|
}
|
|
2096
2144
|
async signalProcess(terminal, signal) {
|
|
2145
|
+
if (terminal.descendants) {
|
|
2146
|
+
await terminal.descendants.signal(signal, terminal.processHelperTimeoutMs);
|
|
2147
|
+
if (this.isRunning(terminal)) terminal.process.kill(signal);
|
|
2148
|
+
return;
|
|
2149
|
+
}
|
|
2097
2150
|
const pid = terminal.process.pid;
|
|
2098
2151
|
if (terminal.killProcessGroup && pid && process.platform === "win32") {
|
|
2099
2152
|
await this.signalWindowsProcessGroup(terminal, pid, signal);
|
|
2100
2153
|
return;
|
|
2101
2154
|
}
|
|
2102
|
-
if (terminal.killProcessGroup && pid) {
|
|
2103
|
-
await this.signalPosixProcessGroup(terminal, pid, signal);
|
|
2104
|
-
return;
|
|
2105
|
-
}
|
|
2106
2155
|
terminal.process.kill(signal);
|
|
2107
2156
|
}
|
|
2108
2157
|
async signalWindowsProcessGroup(terminal, pid, signal) {
|
|
@@ -2113,14 +2162,6 @@ var TerminalManager = class {
|
|
|
2113
2162
|
}
|
|
2114
2163
|
for (const descendantPid of terminal.descendantPids) await killWindowsProcessTree(descendantPid, signal, terminal.processHelperTimeoutMs);
|
|
2115
2164
|
}
|
|
2116
|
-
async signalPosixProcessGroup(terminal, pid, signal) {
|
|
2117
|
-
await this.captureDescendantPids(terminal, pid);
|
|
2118
|
-
if (hasLiveProcessGroup(pid)) {
|
|
2119
|
-
sendSignal(-pid, signal);
|
|
2120
|
-
return;
|
|
2121
|
-
}
|
|
2122
|
-
for (const descendantPid of terminal.descendantPids) sendSignal(descendantPid, signal);
|
|
2123
|
-
}
|
|
2124
2165
|
async captureDescendantPids(terminal, pid) {
|
|
2125
2166
|
if (!this.isRunning(terminal)) await terminal.processGroupSnapshotPromise?.catch(() => {});
|
|
2126
2167
|
for (const descendantPid of await listDescendantPids(pid, terminal.processHelperTimeoutMs)) terminal.descendantPids.add(descendantPid);
|
|
@@ -2129,12 +2170,13 @@ var TerminalManager = class {
|
|
|
2129
2170
|
if (!await this.waitForCleanupAfterSignal(terminal) && process.platform === "win32") throw new Error("Terminal process cleanup did not finish after SIGKILL");
|
|
2130
2171
|
}
|
|
2131
2172
|
async waitForCleanupAfterSignal(terminal) {
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2173
|
+
const deadline = performance.now() + this.killGraceMs;
|
|
2174
|
+
while (this.isRunning(terminal) || terminal.processGroupSnapshotPromise || await hasLiveTerminalDescendants(terminal, deadline - performance.now()) || hasLivePid(terminal.descendantPids)) {
|
|
2175
|
+
const remaining = deadline - performance.now();
|
|
2176
|
+
if (remaining <= 0) return false;
|
|
2177
|
+
await waitMs(Math.min(25, remaining));
|
|
2178
|
+
}
|
|
2179
|
+
return true;
|
|
2138
2180
|
}
|
|
2139
2181
|
};
|
|
2140
2182
|
async function spawnTerminalProcess(params, defaultCwd, authority) {
|
|
@@ -2155,7 +2197,7 @@ async function spawnTerminalProcess(params, defaultCwd, authority) {
|
|
|
2155
2197
|
}
|
|
2156
2198
|
async function spawnAndWait(spawnCommand, params, defaultCwd, authority) {
|
|
2157
2199
|
const spawnOptions = buildTerminalSpawnOptions(spawnCommand.command, params.cwd ?? defaultCwd, params.env);
|
|
2158
|
-
if (spawnCommand.killProcessGroup) spawnOptions.detached = true;
|
|
2200
|
+
if (spawnCommand.killProcessGroup || process.platform !== "win32") spawnOptions.detached = true;
|
|
2159
2201
|
assertControlAuthority(authority);
|
|
2160
2202
|
const proc = spawn(spawnCommand.command, spawnCommand.args, spawnOptions);
|
|
2161
2203
|
await waitForSpawn(proc);
|
|
@@ -2183,7 +2225,7 @@ function commandPathExists(command, cwd) {
|
|
|
2183
2225
|
async function listDescendantPids(rootPid, timeoutMs) {
|
|
2184
2226
|
let output;
|
|
2185
2227
|
try {
|
|
2186
|
-
output = await
|
|
2228
|
+
output = await runWindowsProcessListCommand(timeoutMs);
|
|
2187
2229
|
} catch {
|
|
2188
2230
|
return [];
|
|
2189
2231
|
}
|
|
@@ -2216,38 +2258,10 @@ function parseProcessListLine(line) {
|
|
|
2216
2258
|
parentPid
|
|
2217
2259
|
};
|
|
2218
2260
|
}
|
|
2219
|
-
async function runProcessListCommand(timeoutMs) {
|
|
2220
|
-
if (process.platform === "win32") return await runWindowsProcessListCommand(timeoutMs);
|
|
2221
|
-
return await runTimedExecFile("ps", ["-eo", "pid=,ppid="], { timeoutMs });
|
|
2222
|
-
}
|
|
2223
2261
|
async function rememberProcessGroupPids(terminal) {
|
|
2224
2262
|
const processGroupId = terminal.process.pid;
|
|
2225
2263
|
if (!terminal.killProcessGroup || !processGroupId) return;
|
|
2226
|
-
|
|
2227
|
-
for (const pid of await listDescendantPids(processGroupId, terminal.processHelperTimeoutMs)) terminal.descendantPids.add(pid);
|
|
2228
|
-
return;
|
|
2229
|
-
}
|
|
2230
|
-
for (const pid of await listProcessGroupPids(processGroupId, terminal.processHelperTimeoutMs)) if (pid !== processGroupId) terminal.descendantPids.add(pid);
|
|
2231
|
-
}
|
|
2232
|
-
async function listProcessGroupPids(processGroupId, timeoutMs) {
|
|
2233
|
-
let output;
|
|
2234
|
-
try {
|
|
2235
|
-
output = await runProcessGroupListCommand(timeoutMs);
|
|
2236
|
-
} catch {
|
|
2237
|
-
return [];
|
|
2238
|
-
}
|
|
2239
|
-
const pids = [];
|
|
2240
|
-
for (const line of output.split("\n")) {
|
|
2241
|
-
const match = line.trim().match(/^(\d+)\s+(\d+)$/);
|
|
2242
|
-
if (!match) continue;
|
|
2243
|
-
const pid = Number(match[1]);
|
|
2244
|
-
const pgid = Number(match[2]);
|
|
2245
|
-
if (Number.isInteger(pid) && Number.isInteger(pgid) && pid > 0 && pgid === processGroupId) pids.push(pid);
|
|
2246
|
-
}
|
|
2247
|
-
return pids;
|
|
2248
|
-
}
|
|
2249
|
-
async function runProcessGroupListCommand(timeoutMs) {
|
|
2250
|
-
return await runTimedExecFile("ps", ["-eo", "pid=,pgid="], { timeoutMs });
|
|
2264
|
+
for (const pid of await listDescendantPids(processGroupId, terminal.processHelperTimeoutMs)) terminal.descendantPids.add(pid);
|
|
2251
2265
|
}
|
|
2252
2266
|
async function runWindowsProcessListCommand(timeoutMs) {
|
|
2253
2267
|
const command = ["Get-CimInstance Win32_Process |", "ForEach-Object { \"$($_.ProcessId) $($_.ParentProcessId)\" }"].join(" ");
|
|
@@ -2275,22 +2289,11 @@ async function killWindowsProcessTree(pid, signal, timeoutMs = PROCESS_HELPER_TI
|
|
|
2275
2289
|
});
|
|
2276
2290
|
} catch {}
|
|
2277
2291
|
}
|
|
2278
|
-
function
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
function hasLiveProcessGroup(processGroupId) {
|
|
2284
|
-
try {
|
|
2285
|
-
process.kill(-processGroupId, 0);
|
|
2286
|
-
return true;
|
|
2287
|
-
} catch {
|
|
2288
|
-
return false;
|
|
2289
|
-
}
|
|
2290
|
-
}
|
|
2291
|
-
function hasLiveTerminalProcessGroup(terminal) {
|
|
2292
|
-
const pid = terminal.process.pid;
|
|
2293
|
-
return Boolean(terminal.killProcessGroup && pid && process.platform !== "win32" && hasLiveProcessGroup(pid));
|
|
2292
|
+
async function hasLiveTerminalDescendants(terminal, timeoutMs) {
|
|
2293
|
+
const descendants = terminal.descendants;
|
|
2294
|
+
if (!descendants) return false;
|
|
2295
|
+
if (timeoutMs > 0) await descendants.capture(Math.min(terminal.processHelperTimeoutMs, timeoutMs));
|
|
2296
|
+
return descendants.hasTrackedProcesses();
|
|
2294
2297
|
}
|
|
2295
2298
|
function hasLivePid(pids) {
|
|
2296
2299
|
for (const pid of pids) try {
|
|
@@ -2441,6 +2444,7 @@ var AcpClient = class {
|
|
|
2441
2444
|
cancellingSessionIds = /* @__PURE__ */ new Set();
|
|
2442
2445
|
permissionAbortControllers = /* @__PURE__ */ new Map();
|
|
2443
2446
|
closing = false;
|
|
2447
|
+
closeTask;
|
|
2444
2448
|
closeEpoch = 0;
|
|
2445
2449
|
agentStartedAt;
|
|
2446
2450
|
lastAgentExit;
|
|
@@ -2537,7 +2541,7 @@ var AcpClient = class {
|
|
|
2537
2541
|
this.terminalManager.updatePermissionPolicy(this.options.permissionMode, this.options.nonInteractivePermissions);
|
|
2538
2542
|
}
|
|
2539
2543
|
hasLiveConnection() {
|
|
2540
|
-
return this.connection != null && !this.connection.signal.aborted && this.agent != null && isChildProcessRunning(this.agent);
|
|
2544
|
+
return !this.closing && this.connection != null && !this.connection.signal.aborted && this.agent != null && isChildProcessRunning(this.agent);
|
|
2541
2545
|
}
|
|
2542
2546
|
hasReusableSession(sessionId) {
|
|
2543
2547
|
return this.hasLiveConnection() && this.loadedSessionId === sessionId;
|
|
@@ -2560,15 +2564,17 @@ var AcpClient = class {
|
|
|
2560
2564
|
}
|
|
2561
2565
|
fallback?.abort();
|
|
2562
2566
|
}
|
|
2563
|
-
async start() {
|
|
2567
|
+
async start(authority) {
|
|
2568
|
+
assertControlAuthority(authority);
|
|
2564
2569
|
if (this.hasLiveConnection()) return;
|
|
2565
|
-
|
|
2566
|
-
const epoch = this.closeEpoch;
|
|
2570
|
+
const epoch = await this.waitForPreviousClose();
|
|
2567
2571
|
const maxMessageBytes = readMaxAcpMessageBytes();
|
|
2568
2572
|
const launch = await this.resolveAgentLaunchPlan();
|
|
2573
|
+
assertControlAuthority(authority);
|
|
2569
2574
|
this.logAgentLaunch(launch);
|
|
2570
2575
|
await this.ensureLaunchSupport(launch);
|
|
2571
|
-
|
|
2576
|
+
assertControlAuthority(authority);
|
|
2577
|
+
const { child, process: startedProcess } = await this.spawnAgentProcess(launch, authority);
|
|
2572
2578
|
if (this.closeEpoch === epoch) {
|
|
2573
2579
|
this.agent = child;
|
|
2574
2580
|
this.closing = false;
|
|
@@ -2591,7 +2597,7 @@ var AcpClient = class {
|
|
|
2591
2597
|
startupFailure.dispose();
|
|
2592
2598
|
throw error;
|
|
2593
2599
|
}
|
|
2594
|
-
await this.stopIfClosedDuringLaunch(epoch, child, startupFailure);
|
|
2600
|
+
await this.stopIfClosedDuringLaunch(epoch, child, startupFailure, authority);
|
|
2595
2601
|
const input = Writable.toWeb(child.stdin);
|
|
2596
2602
|
const output = Readable.toWeb(child.stdout);
|
|
2597
2603
|
let connection;
|
|
@@ -2606,9 +2612,10 @@ var AcpClient = class {
|
|
|
2606
2612
|
elicitationModes: this.options.elicitationModes
|
|
2607
2613
|
});
|
|
2608
2614
|
connection = this.createConnection(stream, launch, capabilities);
|
|
2609
|
-
|
|
2610
|
-
this.
|
|
2611
|
-
}
|
|
2615
|
+
const onConnectionClose = () => {
|
|
2616
|
+
this.handleAgentDisconnect(child, "connection_close", child.exitCode ?? null, child.signalCode ?? null);
|
|
2617
|
+
};
|
|
2618
|
+
connection.signal.addEventListener("abort", onConnectionClose, { once: true });
|
|
2612
2619
|
await this.initializeAgentConnection({
|
|
2613
2620
|
child,
|
|
2614
2621
|
connection,
|
|
@@ -2617,6 +2624,14 @@ var AcpClient = class {
|
|
|
2617
2624
|
launch,
|
|
2618
2625
|
capabilities
|
|
2619
2626
|
});
|
|
2627
|
+
if (connection.signal.aborted) onConnectionClose();
|
|
2628
|
+
}
|
|
2629
|
+
async waitForPreviousClose() {
|
|
2630
|
+
const cleanup = this.closeTask ?? (this.connection || this.agent ? this.close() : void 0);
|
|
2631
|
+
const epoch = this.closeEpoch;
|
|
2632
|
+
await cleanup;
|
|
2633
|
+
if (this.closeEpoch !== epoch) throw new Error("ACP client was closed while the agent was starting");
|
|
2634
|
+
return epoch;
|
|
2620
2635
|
}
|
|
2621
2636
|
async resolveAgentLaunchPlan() {
|
|
2622
2637
|
const configuredCommand = resolveAgentCommandParts(this.options.agentCommand, this.options.agentArgv);
|
|
@@ -2657,7 +2672,7 @@ var AcpClient = class {
|
|
|
2657
2672
|
this.log(`resolved system Claude Code executable: ${claudeExe}`);
|
|
2658
2673
|
}
|
|
2659
2674
|
}
|
|
2660
|
-
async spawnAgentProcess(plan) {
|
|
2675
|
+
async spawnAgentProcess(plan, authority) {
|
|
2661
2676
|
const spawnCommand = buildAgentSpawnCommand(plan.spawnCommand, plan.args, process.platform, plan.spawnOptions.env);
|
|
2662
2677
|
const launch = Object.freeze({
|
|
2663
2678
|
launchId: randomUUID(),
|
|
@@ -2667,6 +2682,7 @@ var AcpClient = class {
|
|
|
2667
2682
|
cwd: this.options.cwd
|
|
2668
2683
|
});
|
|
2669
2684
|
await this.options.processLifecycle?.onBeforeSpawn?.(launch);
|
|
2685
|
+
assertControlAuthority(authority);
|
|
2670
2686
|
let spawnedChild;
|
|
2671
2687
|
try {
|
|
2672
2688
|
spawnedChild = spawn(spawnCommand.command, spawnCommand.args, {
|
|
@@ -2788,7 +2804,8 @@ var AcpClient = class {
|
|
|
2788
2804
|
onPromptRequestWritten: (active, owner) => this.onPromptRequestWritten(active, owner)
|
|
2789
2805
|
});
|
|
2790
2806
|
}
|
|
2791
|
-
async createSession(cwd = this.options.cwd) {
|
|
2807
|
+
async createSession(cwd = this.options.cwd, authority) {
|
|
2808
|
+
assertControlAuthority(authority);
|
|
2792
2809
|
const connection = this.getConnection();
|
|
2793
2810
|
const { command, args } = resolveAgentCommandParts(this.options.agentCommand, this.options.agentArgv);
|
|
2794
2811
|
const claudeAcp = isClaudeAcpCommand(command, args);
|
|
@@ -2799,7 +2816,7 @@ var AcpClient = class {
|
|
|
2799
2816
|
cwd: sessionCwd,
|
|
2800
2817
|
mcpServers: this.options.mcpServers ?? [],
|
|
2801
2818
|
_meta: buildClaudeCodeOptionsMeta(this.options.sessionOptions, claudeAcp)
|
|
2802
|
-
}));
|
|
2819
|
+
}), authority);
|
|
2803
2820
|
result = claudeAcp ? await withTimeout(createPromise, resolveClaudeAcpSessionCreateTimeoutMs()) : await createPromise;
|
|
2804
2821
|
} catch (error) {
|
|
2805
2822
|
if (claudeAcp && error instanceof TimeoutError) throw new ClaudeAcpSessionCreateTimeoutError(buildClaudeAcpSessionCreateTimeoutMessage(), {
|
|
@@ -2831,6 +2848,7 @@ var AcpClient = class {
|
|
|
2831
2848
|
async loadSessionWithOptions(sessionId, cwd = this.options.cwd, options = {}) {
|
|
2832
2849
|
const connection = this.getConnection();
|
|
2833
2850
|
const sessionCwd = await resolveAgentSessionCwd(cwd, this.options.agentCommand);
|
|
2851
|
+
assertControlAuthority(options.authority);
|
|
2834
2852
|
const previousSuppression = this.applySessionUpdateSuppression(Boolean(options.suppressReplayUpdates));
|
|
2835
2853
|
let response;
|
|
2836
2854
|
try {
|
|
@@ -2838,7 +2856,7 @@ var AcpClient = class {
|
|
|
2838
2856
|
sessionId,
|
|
2839
2857
|
cwd: sessionCwd,
|
|
2840
2858
|
mcpServers: this.options.mcpServers ?? []
|
|
2841
|
-
}));
|
|
2859
|
+
}), options.authority);
|
|
2842
2860
|
await this.waitForSessionUpdateDrain(options.replayIdleMs ?? REPLAY_IDLE_MS, options.replayDrainTimeoutMs ?? REPLAY_DRAIN_TIMEOUT_MS);
|
|
2843
2861
|
} finally {
|
|
2844
2862
|
this.restoreSessionUpdateSuppression(previousSuppression);
|
|
@@ -2848,14 +2866,15 @@ var AcpClient = class {
|
|
|
2848
2866
|
await this.captureAgentDescendants(this.agent);
|
|
2849
2867
|
return result;
|
|
2850
2868
|
}
|
|
2851
|
-
async resumeSession(sessionId, cwd = this.options.cwd) {
|
|
2869
|
+
async resumeSession(sessionId, cwd = this.options.cwd, authority) {
|
|
2870
|
+
assertControlAuthority(authority);
|
|
2852
2871
|
const connection = this.getConnection();
|
|
2853
2872
|
const sessionCwd = await resolveAgentSessionCwd(cwd, this.options.agentCommand);
|
|
2854
2873
|
const response = await this.runConnectionRequest(() => connection.agent.request(methods.agent.session.resume, {
|
|
2855
2874
|
sessionId,
|
|
2856
2875
|
cwd: sessionCwd,
|
|
2857
2876
|
mcpServers: this.options.mcpServers ?? []
|
|
2858
|
-
}));
|
|
2877
|
+
}), authority);
|
|
2859
2878
|
this.loadedSessionId = sessionId;
|
|
2860
2879
|
const result = toReconnectedSessionResult(response);
|
|
2861
2880
|
await this.captureAgentDescendants(this.agent);
|
|
@@ -3080,20 +3099,23 @@ var AcpClient = class {
|
|
|
3080
3099
|
if (timer) clearTimeout(timer);
|
|
3081
3100
|
}
|
|
3082
3101
|
}
|
|
3083
|
-
|
|
3102
|
+
close() {
|
|
3084
3103
|
this.closing = true;
|
|
3085
3104
|
this.closeEpoch += 1;
|
|
3105
|
+
if (this.closeTask) return this.closeTask;
|
|
3106
|
+
this.closeTask = Promise.resolve().then(() => this.finishClose()).finally(() => {
|
|
3107
|
+
this.closeTask = void 0;
|
|
3108
|
+
});
|
|
3109
|
+
return this.closeTask;
|
|
3110
|
+
}
|
|
3111
|
+
async finishClose() {
|
|
3086
3112
|
const permissionControllers = [...this.permissionAbortControllers.values()];
|
|
3087
3113
|
this.permissionAbortControllers.clear();
|
|
3088
3114
|
const owners = [...this.pendingPromptOwners];
|
|
3089
3115
|
this.abortActiveElicitation();
|
|
3090
3116
|
for (const owner of owners) owner.requestController.abort();
|
|
3091
3117
|
for (const controller of permissionControllers) controller.abort();
|
|
3092
|
-
await this.
|
|
3093
|
-
const agent = this.agent;
|
|
3094
|
-
if (agent) await this.terminateAgentProcess(agent);
|
|
3095
|
-
this.closeConnection();
|
|
3096
|
-
if (this.pendingConnectionRequests.size > 0) this.rejectPendingConnectionRequests(this.lastAgentExit ? new AgentDisconnectedError(this.lastAgentExit.reason, this.lastAgentExit.exitCode, this.lastAgentExit.signal, { outputAlreadyEmitted: Boolean(this.activePrompt) }) : new AgentDisconnectedError("connection_close", null, null, { outputAlreadyEmitted: Boolean(this.activePrompt) }));
|
|
3118
|
+
await this.retireNativeResources();
|
|
3097
3119
|
this.sessionUpdateChain = Promise.resolve();
|
|
3098
3120
|
this.observedSessionUpdates = 0;
|
|
3099
3121
|
this.processedSessionUpdates = 0;
|
|
@@ -3110,10 +3132,31 @@ var AcpClient = class {
|
|
|
3110
3132
|
this.connection = void 0;
|
|
3111
3133
|
this.agent = void 0;
|
|
3112
3134
|
}
|
|
3113
|
-
async
|
|
3135
|
+
async retireNativeResources() {
|
|
3136
|
+
const agent = this.agent;
|
|
3137
|
+
const failures = [];
|
|
3138
|
+
try {
|
|
3139
|
+
await this.terminalManager.shutdown();
|
|
3140
|
+
} catch (error) {
|
|
3141
|
+
failures.push(error);
|
|
3142
|
+
}
|
|
3143
|
+
try {
|
|
3144
|
+
if (agent) await this.terminateAgentProcess(agent);
|
|
3145
|
+
} catch (error) {
|
|
3146
|
+
failures.push(error);
|
|
3147
|
+
}
|
|
3148
|
+
try {
|
|
3149
|
+
this.closeConnection();
|
|
3150
|
+
} finally {
|
|
3151
|
+
this.rejectPendingConnectionRequests(this.lastAgentExit ? new AgentDisconnectedError(this.lastAgentExit.reason, this.lastAgentExit.exitCode, this.lastAgentExit.signal, { outputAlreadyEmitted: Boolean(this.activePrompt) }) : new AgentDisconnectedError("connection_close", null, null, { outputAlreadyEmitted: Boolean(this.activePrompt) }));
|
|
3152
|
+
}
|
|
3153
|
+
if (failures.length > 0) throw new AggregateError(failures, "ACP client cleanup failed", { cause: failures[0] });
|
|
3154
|
+
}
|
|
3155
|
+
async stopIfClosedDuringLaunch(epoch, child, startupFailure, authority) {
|
|
3114
3156
|
if (this.closeEpoch === epoch) return;
|
|
3115
3157
|
startupFailure.dispose();
|
|
3116
3158
|
await this.terminateAgentProcess(child);
|
|
3159
|
+
assertControlAuthority(authority);
|
|
3117
3160
|
throw new Error("ACP client was closed while the agent was starting");
|
|
3118
3161
|
}
|
|
3119
3162
|
abortActiveElicitation() {
|
|
@@ -3475,7 +3518,7 @@ var AcpClient = class {
|
|
|
3475
3518
|
attachAgentLifecycleObservers(child, startedProcess, exitNotificationBarrier) {
|
|
3476
3519
|
const onExit = (exitCode, signal) => {
|
|
3477
3520
|
const exitedAt = isoNow$2();
|
|
3478
|
-
this.
|
|
3521
|
+
this.handleAgentDisconnect(child, "process_exit", exitCode, signal);
|
|
3479
3522
|
this.terminateAgentProcess(child);
|
|
3480
3523
|
exitNotificationBarrier.then(() => {
|
|
3481
3524
|
this.notifyProcessExit(startedProcess, exitCode, signal, exitedAt);
|
|
@@ -3487,10 +3530,17 @@ var AcpClient = class {
|
|
|
3487
3530
|
onExit(child.exitCode, child.signalCode);
|
|
3488
3531
|
}
|
|
3489
3532
|
child.once("close", (exitCode, signal) => {
|
|
3490
|
-
this.
|
|
3533
|
+
this.handleAgentDisconnect(child, "process_close", exitCode, signal);
|
|
3491
3534
|
});
|
|
3492
3535
|
child.stdout.once("close", () => {
|
|
3493
|
-
this.
|
|
3536
|
+
this.handleAgentDisconnect(child, "pipe_close", child.exitCode ?? null, child.signalCode ?? null);
|
|
3537
|
+
});
|
|
3538
|
+
}
|
|
3539
|
+
handleAgentDisconnect(child, reason, exitCode, signal) {
|
|
3540
|
+
this.recordAgentExit(child, reason, exitCode, signal);
|
|
3541
|
+
if (this.agent !== child || this.closing || !this.connection) return;
|
|
3542
|
+
this.close().catch((error) => {
|
|
3543
|
+
this.log(`disconnected agent cleanup failed: ${String(error)}`);
|
|
3494
3544
|
});
|
|
3495
3545
|
}
|
|
3496
3546
|
notifyProcessSpawnFailure(launch, error) {
|
|
@@ -3854,7 +3904,6 @@ function ensureAgentMessage(conversation) {
|
|
|
3854
3904
|
return created;
|
|
3855
3905
|
}
|
|
3856
3906
|
function appendAgentText(agent, text) {
|
|
3857
|
-
if (!text.trim()) return;
|
|
3858
3907
|
const last = agent.content.at(-1);
|
|
3859
3908
|
if (last && isAgentTextContent(last)) {
|
|
3860
3909
|
last.Text = trimRuntimeText(`${last.Text}${text}`, MAX_RUNTIME_AGENT_TEXT_CHARS);
|
|
@@ -3864,7 +3913,6 @@ function appendAgentText(agent, text) {
|
|
|
3864
3913
|
agent.content.push(next);
|
|
3865
3914
|
}
|
|
3866
3915
|
function appendAgentThinking(agent, text) {
|
|
3867
|
-
if (!text.trim()) return;
|
|
3868
3916
|
const last = agent.content.at(-1);
|
|
3869
3917
|
if (last && isAgentThinkingContent(last)) {
|
|
3870
3918
|
last.Thinking.text = trimRuntimeText(`${last.Thinking.text}${text}`, MAX_RUNTIME_THINKING_CHARS);
|
|
@@ -3921,8 +3969,7 @@ function ensureToolUseContent(agent, toolCallId) {
|
|
|
3921
3969
|
return created;
|
|
3922
3970
|
}
|
|
3923
3971
|
function upsertToolResult(agent, toolCallId, patch) {
|
|
3924
|
-
const
|
|
3925
|
-
const fallback = existingToolResultValues(existing);
|
|
3972
|
+
const fallback = existingToolResultValues(hasOwn(agent.tool_results, toolCallId) ? agent.tool_results[toolCallId] : void 0);
|
|
3926
3973
|
const next = {
|
|
3927
3974
|
tool_use_id: toolCallId,
|
|
3928
3975
|
tool_name: patch.tool_name ?? fallback.tool_name,
|
|
@@ -3930,7 +3977,12 @@ function upsertToolResult(agent, toolCallId, patch) {
|
|
|
3930
3977
|
content: patch.content ?? fallback.content,
|
|
3931
3978
|
output: patch.output ?? fallback.output
|
|
3932
3979
|
};
|
|
3933
|
-
agent.tool_results
|
|
3980
|
+
Object.defineProperty(agent.tool_results, toolCallId, {
|
|
3981
|
+
value: next,
|
|
3982
|
+
writable: true,
|
|
3983
|
+
enumerable: true,
|
|
3984
|
+
configurable: true
|
|
3985
|
+
});
|
|
3934
3986
|
}
|
|
3935
3987
|
function existingToolResultValues(existing) {
|
|
3936
3988
|
if (existing) return existing;
|
|
@@ -3971,7 +4023,7 @@ function applyToolResultUpdate(agent, tool, update) {
|
|
|
3971
4023
|
const output = hasOwn(update, "rawOutput") ? deepClone(update.rawOutput) : void 0;
|
|
3972
4024
|
upsertToolResult(agent, update.toolCallId, {
|
|
3973
4025
|
tool_name: tool.name,
|
|
3974
|
-
is_error: statusIndicatesError(status),
|
|
4026
|
+
is_error: status === void 0 ? void 0 : statusIndicatesError(status),
|
|
3975
4027
|
content: output === void 0 ? void 0 : toToolResultContent(output),
|
|
3976
4028
|
output
|
|
3977
4029
|
});
|
|
@@ -4397,10 +4449,7 @@ function getDesiredModeId(state) {
|
|
|
4397
4449
|
function getDesiredConfigOptions(state) {
|
|
4398
4450
|
const desired = state?.desired_config_options;
|
|
4399
4451
|
if (!desired) return {};
|
|
4400
|
-
return Object.fromEntries(Object.entries(desired).
|
|
4401
|
-
const normalizedConfigId = normalizeModeId(configId);
|
|
4402
|
-
return normalizedConfigId && typeof value === "string" ? [[normalizedConfigId, value]] : [];
|
|
4403
|
-
}));
|
|
4452
|
+
return Object.fromEntries(Object.entries(desired).filter(([, value]) => typeof value === "string"));
|
|
4404
4453
|
}
|
|
4405
4454
|
function setDesiredModeId(record, modeId) {
|
|
4406
4455
|
const acpx = ensureAcpxState(record.acpx);
|
|
@@ -4410,10 +4459,9 @@ function setDesiredModeId(record, modeId) {
|
|
|
4410
4459
|
record.acpx = acpx;
|
|
4411
4460
|
}
|
|
4412
4461
|
function clearDesiredConfigOption(state, configId) {
|
|
4413
|
-
|
|
4414
|
-
if (!normalizedConfigId || !state.desired_config_options) return;
|
|
4462
|
+
if (typeof configId !== "string" || !state.desired_config_options) return;
|
|
4415
4463
|
const desired = { ...state.desired_config_options };
|
|
4416
|
-
delete desired[
|
|
4464
|
+
delete desired[configId];
|
|
4417
4465
|
if (Object.keys(desired).length > 0) state.desired_config_options = desired;
|
|
4418
4466
|
else delete state.desired_config_options;
|
|
4419
4467
|
}
|
|
@@ -4452,7 +4500,7 @@ async function applyRequestedModelIfAdvertised(params) {
|
|
|
4452
4500
|
if (params.models.currentModelId === requestedModel) return { applied: true };
|
|
4453
4501
|
return {
|
|
4454
4502
|
applied: true,
|
|
4455
|
-
response: await withTimeout(params.client.setSessionModel(params.sessionId, requestedModel, params.models), params.timeoutMs)
|
|
4503
|
+
response: await withTimeout(params.client.setSessionModel(params.sessionId, requestedModel, params.models, params.authority), params.timeoutMs)
|
|
4456
4504
|
};
|
|
4457
4505
|
}
|
|
4458
4506
|
//#endregion
|
|
@@ -4477,9 +4525,9 @@ function applyAcceptedConfigOptions(state, response) {
|
|
|
4477
4525
|
if (!response) return next;
|
|
4478
4526
|
applyConfigOptionsModelState(next, response.configOptions);
|
|
4479
4527
|
if (!next.desired_config_options) return next;
|
|
4480
|
-
const
|
|
4481
|
-
for (const option of response.configOptions) if (typeof option.currentValue === "string" && Object.hasOwn(next.desired_config_options, option.id))
|
|
4482
|
-
if (
|
|
4528
|
+
const desiredEntries = [];
|
|
4529
|
+
for (const option of response.configOptions) if (typeof option.currentValue === "string" && Object.hasOwn(next.desired_config_options, option.id)) desiredEntries.push([option.id, option.currentValue]);
|
|
4530
|
+
if (desiredEntries.length > 0) next.desired_config_options = Object.fromEntries(desiredEntries);
|
|
4483
4531
|
else delete next.desired_config_options;
|
|
4484
4532
|
return next;
|
|
4485
4533
|
}
|
|
@@ -4497,8 +4545,7 @@ function applyModelSelection(state, modelId, response) {
|
|
|
4497
4545
|
function applyConfigOptionSelection(state, configId, value, response, modelConfigId = advertisedModelState(state)?.configId) {
|
|
4498
4546
|
if (configId === modelConfigId || configId === modelStateFromConfigOptions(response.configOptions)?.configId) return applyModelSelection(state, value, response);
|
|
4499
4547
|
const next = cloneSessionAcpxState(state) ?? {};
|
|
4500
|
-
|
|
4501
|
-
else next.desired_config_options = {
|
|
4548
|
+
next.desired_config_options = {
|
|
4502
4549
|
...next.desired_config_options,
|
|
4503
4550
|
[configId]: value
|
|
4504
4551
|
};
|
|
@@ -4509,6 +4556,7 @@ function applyConfigOptionSelection(state, configId, value, response, modelConfi
|
|
|
4509
4556
|
const LOCK_RETRY_MS = 15;
|
|
4510
4557
|
const INCOMPLETE_RESERVATION_GRACE_MS = 15e3;
|
|
4511
4558
|
let lastCreatedAt = 0;
|
|
4559
|
+
const localTurns = /* @__PURE__ */ new Map();
|
|
4512
4560
|
async function readLock(filePath) {
|
|
4513
4561
|
try {
|
|
4514
4562
|
const stat = await fs$1.lstat(filePath, { bigint: true });
|
|
@@ -4522,11 +4570,6 @@ async function readLock(filePath) {
|
|
|
4522
4570
|
throw error;
|
|
4523
4571
|
}
|
|
4524
4572
|
}
|
|
4525
|
-
function lockPid(value) {
|
|
4526
|
-
if (!value || typeof value !== "object" || !("pid" in value)) return;
|
|
4527
|
-
const pid = value.pid;
|
|
4528
|
-
return typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0 ? pid : void 0;
|
|
4529
|
-
}
|
|
4530
4573
|
function parseLock(payload) {
|
|
4531
4574
|
try {
|
|
4532
4575
|
return JSON.parse(payload);
|
|
@@ -4534,7 +4577,7 @@ function parseLock(payload) {
|
|
|
4534
4577
|
return;
|
|
4535
4578
|
}
|
|
4536
4579
|
}
|
|
4537
|
-
async function tryAcquireGuard(filePath) {
|
|
4580
|
+
async function tryAcquireGuard(filePath, owner, signal) {
|
|
4538
4581
|
try {
|
|
4539
4582
|
return await acquireFileLock(filePath, {
|
|
4540
4583
|
managerKey: "acpx.session-turn",
|
|
@@ -4549,9 +4592,9 @@ async function tryAcquireGuard(filePath) {
|
|
|
4549
4592
|
randomize: false
|
|
4550
4593
|
},
|
|
4551
4594
|
staleRecovery: "remove-if-unchanged",
|
|
4552
|
-
payload: () =>
|
|
4553
|
-
shouldReclaim: ({ payload }) =>
|
|
4554
|
-
shouldRemoveStaleLock: ({ payload }) =>
|
|
4595
|
+
payload: () => owner.payload,
|
|
4596
|
+
shouldReclaim: ({ payload }) => owner.hasExited(payload, false, signal),
|
|
4597
|
+
shouldRemoveStaleLock: ({ payload }) => owner.hasExited(payload, true, signal)
|
|
4555
4598
|
});
|
|
4556
4599
|
} catch (error) {
|
|
4557
4600
|
if (error.code === "file_lock_timeout") return;
|
|
@@ -4567,11 +4610,12 @@ async function removeObservedLock(filePath, observed) {
|
|
|
4567
4610
|
});
|
|
4568
4611
|
return true;
|
|
4569
4612
|
}
|
|
4570
|
-
async function recoverAbandonedLock(filePath) {
|
|
4613
|
+
async function recoverAbandonedLock(filePath, owner, signal) {
|
|
4571
4614
|
const observed = await readLock(filePath);
|
|
4572
4615
|
if (!observed) return true;
|
|
4573
|
-
const
|
|
4574
|
-
|
|
4616
|
+
const payload = parseLock(observed.payload);
|
|
4617
|
+
const pid = lockOwnerPid(payload);
|
|
4618
|
+
if (pid && (!await owner.hasExited(payload, false, signal) || !await owner.hasExited(payload, true, signal))) return false;
|
|
4575
4619
|
if (!pid && Date.now() - Number(observed.stat.mtimeMs) <= INCOMPLETE_RESERVATION_GRACE_MS) return false;
|
|
4576
4620
|
if (await removeObservedLock(filePath, observed)) {
|
|
4577
4621
|
incrementPerfCounter("session.events.stale_lock_recovered");
|
|
@@ -4607,58 +4651,112 @@ async function removePublishedLock(filePath, payload) {
|
|
|
4607
4651
|
const current = await readLock(filePath);
|
|
4608
4652
|
if (current?.payload === payload) await removeObservedLock(filePath, current);
|
|
4609
4653
|
}
|
|
4610
|
-
async function rejectAcquisition(filePath,
|
|
4654
|
+
async function rejectAcquisition(filePath, receipt, error) {
|
|
4611
4655
|
const failures = [error];
|
|
4612
|
-
await
|
|
4613
|
-
failures.push(cleanupError);
|
|
4614
|
-
});
|
|
4615
|
-
await guard.release().catch((releaseError) => {
|
|
4616
|
-
failures.push(releaseError);
|
|
4656
|
+
await disposeTurn(filePath, receipt).catch((cleanupError) => {
|
|
4657
|
+
failures.push(...cleanupError instanceof AggregateError ? cleanupError.errors : [cleanupError]);
|
|
4617
4658
|
});
|
|
4618
4659
|
if (failures.length > 1) throw new AggregateError(failures, "Session turn acquisition and cleanup failed");
|
|
4619
4660
|
throw error;
|
|
4620
4661
|
}
|
|
4621
|
-
function
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4662
|
+
async function releaseTurnGuard(receipt) {
|
|
4663
|
+
await receipt.guard?.release();
|
|
4664
|
+
receipt.guard = void 0;
|
|
4665
|
+
}
|
|
4666
|
+
async function removeTurnMarker(filePath, receipt) {
|
|
4667
|
+
if (!receipt.removeMarker) return true;
|
|
4668
|
+
if (receipt.guard && !await receipt.guard.verifyStillHeld()) await releaseTurnGuard(receipt);
|
|
4669
|
+
receipt.guard ??= await tryAcquireGuard(filePath, receipt.owner);
|
|
4670
|
+
if (!receipt.guard) return false;
|
|
4671
|
+
await receipt.removeMarker();
|
|
4672
|
+
receipt.removeMarker = void 0;
|
|
4673
|
+
return true;
|
|
4674
|
+
}
|
|
4675
|
+
async function settleTurn(filePath, receipt) {
|
|
4676
|
+
if (receipt.settled) return true;
|
|
4677
|
+
const pending = receipt.pending ??= (async () => {
|
|
4678
|
+
receipt.failed = false;
|
|
4679
|
+
const failures = [];
|
|
4631
4680
|
try {
|
|
4632
|
-
await
|
|
4633
|
-
}
|
|
4634
|
-
|
|
4681
|
+
if (!await removeTurnMarker(filePath, receipt)) return false;
|
|
4682
|
+
} catch (error) {
|
|
4683
|
+
failures.push(error);
|
|
4635
4684
|
}
|
|
4636
|
-
|
|
4685
|
+
if (failures.length === 0 || !receipt.admitted) try {
|
|
4686
|
+
await releaseTurnGuard(receipt);
|
|
4687
|
+
} catch (error) {
|
|
4688
|
+
failures.push(error);
|
|
4689
|
+
}
|
|
4690
|
+
if (failures.length > 1) throw new AggregateError(failures, "Session turn cleanup failed");
|
|
4691
|
+
if (failures.length === 1) throw failures[0];
|
|
4692
|
+
receipt.settled = true;
|
|
4693
|
+
localTurns.delete(filePath);
|
|
4694
|
+
return true;
|
|
4695
|
+
})();
|
|
4696
|
+
try {
|
|
4697
|
+
return await pending;
|
|
4698
|
+
} finally {
|
|
4699
|
+
if (receipt.pending === pending) {
|
|
4700
|
+
receipt.pending = void 0;
|
|
4701
|
+
receipt.failed = !receipt.settled;
|
|
4702
|
+
}
|
|
4703
|
+
}
|
|
4704
|
+
}
|
|
4705
|
+
async function disposeTurn(filePath, receipt) {
|
|
4706
|
+
if (!await settleTurn(filePath, receipt)) throw new Error(`Session turn cleanup is waiting for its guard: ${filePath}`);
|
|
4637
4707
|
}
|
|
4638
|
-
async function tryPublishLock(filePath, payload, signal) {
|
|
4708
|
+
async function tryPublishLock(filePath, payload, owner, signal) {
|
|
4639
4709
|
for (;;) try {
|
|
4640
4710
|
await publishLock(filePath, payload, signal);
|
|
4641
4711
|
return true;
|
|
4642
4712
|
} catch (error) {
|
|
4643
4713
|
if (error.code !== "EEXIST") throw error;
|
|
4644
|
-
if (!await recoverAbandonedLock(filePath)) return false;
|
|
4714
|
+
if (!await recoverAbandonedLock(filePath, owner, signal)) return false;
|
|
4645
4715
|
}
|
|
4646
4716
|
}
|
|
4647
|
-
async function
|
|
4648
|
-
const
|
|
4649
|
-
if (
|
|
4717
|
+
async function tryAcquireTurnCleanup(filePath, payload, owner, signal) {
|
|
4718
|
+
const previous = localTurns.get(filePath);
|
|
4719
|
+
if (previous) {
|
|
4720
|
+
if (previous.failed) await settleTurn(filePath, previous);
|
|
4721
|
+
return;
|
|
4722
|
+
}
|
|
4723
|
+
const receipt = {
|
|
4724
|
+
owner,
|
|
4725
|
+
removeMarker: async () => await removePublishedLock(filePath, payload),
|
|
4726
|
+
admitted: false,
|
|
4727
|
+
failed: false,
|
|
4728
|
+
settled: false
|
|
4729
|
+
};
|
|
4730
|
+
localTurns.set(filePath, receipt);
|
|
4731
|
+
try {
|
|
4732
|
+
receipt.guard = await tryAcquireGuard(filePath, owner, signal);
|
|
4733
|
+
} catch (error) {
|
|
4734
|
+
localTurns.delete(filePath);
|
|
4735
|
+
throw error;
|
|
4736
|
+
}
|
|
4737
|
+
if (!receipt.guard) {
|
|
4738
|
+
localTurns.delete(filePath);
|
|
4739
|
+
return;
|
|
4740
|
+
}
|
|
4741
|
+
return receipt;
|
|
4742
|
+
}
|
|
4743
|
+
async function tryAcquireTurn(filePath, payload, owner, signal) {
|
|
4744
|
+
const receipt = await tryAcquireTurnCleanup(filePath, payload, owner, signal);
|
|
4745
|
+
if (!receipt) return;
|
|
4650
4746
|
try {
|
|
4651
4747
|
signal?.throwIfAborted();
|
|
4652
|
-
if (!await tryPublishLock(filePath, payload, signal)) {
|
|
4653
|
-
await
|
|
4748
|
+
if (!await tryPublishLock(filePath, payload, owner, signal)) {
|
|
4749
|
+
await disposeTurn(filePath, receipt);
|
|
4654
4750
|
return;
|
|
4655
4751
|
}
|
|
4656
4752
|
const observed = await readLock(filePath);
|
|
4657
4753
|
if (observed?.payload !== payload) throw new Error(`Session turn ownership changed before admission: ${filePath}`);
|
|
4658
4754
|
signal?.throwIfAborted();
|
|
4659
|
-
|
|
4755
|
+
receipt.admitted = true;
|
|
4756
|
+
receipt.removeMarker = async () => await removeObservedLock(filePath, observed);
|
|
4757
|
+
return { [Symbol.asyncDispose]: async () => await disposeTurn(filePath, receipt) };
|
|
4660
4758
|
} catch (error) {
|
|
4661
|
-
return await rejectAcquisition(filePath,
|
|
4759
|
+
return await rejectAcquisition(filePath, receipt, error);
|
|
4662
4760
|
}
|
|
4663
4761
|
}
|
|
4664
4762
|
async function acquireSessionTurn(recordId, signal) {
|
|
@@ -4668,19 +4766,44 @@ async function acquireSessionTurn(recordId, signal) {
|
|
|
4668
4766
|
mode: 448
|
|
4669
4767
|
});
|
|
4670
4768
|
const filePath = path.join(await fs$1.realpath(path.dirname(requestedPath)), path.basename(requestedPath));
|
|
4769
|
+
const owner = await createLockOwner({ signal });
|
|
4671
4770
|
lastCreatedAt = Math.max(Date.now(), lastCreatedAt + 1);
|
|
4672
4771
|
const payload = `${JSON.stringify({
|
|
4673
|
-
|
|
4772
|
+
...owner.payload,
|
|
4674
4773
|
created_at: new Date(lastCreatedAt).toISOString()
|
|
4675
4774
|
}, null, 2)}\n`;
|
|
4676
4775
|
for (;;) {
|
|
4677
4776
|
signal?.throwIfAborted();
|
|
4678
|
-
const turn = await tryAcquireTurn(filePath, payload, signal);
|
|
4777
|
+
const turn = await tryAcquireTurn(filePath, payload, owner, signal);
|
|
4679
4778
|
if (turn) return turn;
|
|
4680
4779
|
await setTimeout$1(LOCK_RETRY_MS, void 0, { signal });
|
|
4681
4780
|
}
|
|
4682
4781
|
}
|
|
4683
4782
|
//#endregion
|
|
4783
|
+
//#region src/session/execution/direct-lifetime.ts
|
|
4784
|
+
function ownDirectClient(client, signal) {
|
|
4785
|
+
let closing;
|
|
4786
|
+
const cancel = async () => {
|
|
4787
|
+
await withTimeout(client.cancelActivePrompt(2500), 2500).catch(() => {});
|
|
4788
|
+
await client.close();
|
|
4789
|
+
};
|
|
4790
|
+
const onAbort = () => {
|
|
4791
|
+
closing ??= cancel();
|
|
4792
|
+
closing.catch(() => {});
|
|
4793
|
+
};
|
|
4794
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
4795
|
+
if (signal?.aborted) onAbort();
|
|
4796
|
+
const release = () => signal?.removeEventListener("abort", onAbort);
|
|
4797
|
+
return Object.assign(() => {
|
|
4798
|
+
release();
|
|
4799
|
+
closing ??= client.close();
|
|
4800
|
+
return closing;
|
|
4801
|
+
}, { release });
|
|
4802
|
+
}
|
|
4803
|
+
function directExecutionError(error, signal) {
|
|
4804
|
+
return signal?.aborted && error instanceof AgentDisconnectedError ? signal.reason : error;
|
|
4805
|
+
}
|
|
4806
|
+
//#endregion
|
|
4684
4807
|
//#region src/session/queue/ipc-server.ts
|
|
4685
4808
|
const QUEUE_SOCKET_DRAIN_TIMEOUT_MS = 1e3;
|
|
4686
4809
|
function makeQueueOwnerError(requestId, message, detailCode, options = {}) {
|
|
@@ -4713,9 +4836,12 @@ function makeQueueOwnerErrorFromUnknown(requestId, error, detailCode, options =
|
|
|
4713
4836
|
acp: normalized.acp
|
|
4714
4837
|
};
|
|
4715
4838
|
}
|
|
4839
|
+
function armSocketDrainTimeout(socket) {
|
|
4840
|
+
if (process.platform !== "win32") socket.setTimeout(QUEUE_SOCKET_DRAIN_TIMEOUT_MS);
|
|
4841
|
+
}
|
|
4716
4842
|
function writeQueueMessage(socket, message) {
|
|
4717
4843
|
if (socket.destroyed || !socket.writable) return;
|
|
4718
|
-
socket.write(`${JSON.stringify(message)}\n`);
|
|
4844
|
+
if (!socket.write(`${JSON.stringify(message)}\n`) && !socket.timeout) armSocketDrainTimeout(socket);
|
|
4719
4845
|
}
|
|
4720
4846
|
var SessionQueueOwner = class SessionQueueOwner {
|
|
4721
4847
|
server;
|
|
@@ -4883,6 +5009,7 @@ var SessionQueueOwner = class SessionQueueOwner {
|
|
|
4883
5009
|
if (socket.destroyed || this.drainingSockets.has(socket)) return;
|
|
4884
5010
|
this.taskSockets.delete(socket);
|
|
4885
5011
|
this.drainingSockets.add(socket);
|
|
5012
|
+
armSocketDrainTimeout(socket);
|
|
4886
5013
|
socket.end(() => {
|
|
4887
5014
|
this.drainingSockets.delete(socket);
|
|
4888
5015
|
socket.destroy();
|
|
@@ -5032,6 +5159,10 @@ var SessionQueueOwner = class SessionQueueOwner {
|
|
|
5032
5159
|
handleConnection(socket) {
|
|
5033
5160
|
this.sockets.add(socket);
|
|
5034
5161
|
socket.setEncoding("utf8");
|
|
5162
|
+
socket.on("timeout", () => socket.destroy());
|
|
5163
|
+
socket.on("drain", () => {
|
|
5164
|
+
if (!socket.writableEnded) socket.setTimeout(0);
|
|
5165
|
+
});
|
|
5035
5166
|
socket.once("close", () => {
|
|
5036
5167
|
this.sockets.delete(socket);
|
|
5037
5168
|
this.taskSockets.delete(socket);
|
|
@@ -5120,6 +5251,10 @@ async function replayDesiredMode(params) {
|
|
|
5120
5251
|
await withTimeout(params.client.setSessionMode(params.sessionId, params.desiredModeId, params.replay.authority), params.timeoutMs);
|
|
5121
5252
|
params.replay.acknowledged = true;
|
|
5122
5253
|
if (params.verbose) process.stderr.write(`[acpx] replayed desired mode ${params.desiredModeId} on fresh ACP session ${params.sessionId} (previous ${params.previousSessionId})\n`);
|
|
5254
|
+
return {
|
|
5255
|
+
models: advertisedModelState(params.record.acpx),
|
|
5256
|
+
configOptionsPresent: params.record.acpx?.config_options !== void 0
|
|
5257
|
+
};
|
|
5123
5258
|
} catch (error) {
|
|
5124
5259
|
rethrowAuthorityFailure(params.replay, error);
|
|
5125
5260
|
throw new SessionModeReplayError(`Failed to replay saved session mode ${params.desiredModeId} on fresh ACP session ${params.sessionId}: ${formatErrorMessage(error)}`, {
|
|
@@ -5198,18 +5333,20 @@ function restoreOriginalSessionState(params) {
|
|
|
5198
5333
|
async function connectAndLoadSession(options) {
|
|
5199
5334
|
const record = options.record;
|
|
5200
5335
|
const client = options.client;
|
|
5336
|
+
assertControlAuthority(options.authority);
|
|
5201
5337
|
const sameSessionOnly = requiresSameSession(options.resumePolicy) || Boolean(record.importedFrom);
|
|
5202
5338
|
const originalSessionId = record.acpSessionId;
|
|
5203
5339
|
const originalAgentSessionId = record.agentSessionId;
|
|
5204
5340
|
const originalAcpx = cloneSessionAcpxState(record.acpx);
|
|
5205
|
-
const desiredModeId = getDesiredModeId(record.acpx);
|
|
5341
|
+
const desiredModeId = options.replacingMode ? void 0 : getDesiredModeId(record.acpx);
|
|
5206
5342
|
const desiredModelId = getDesiredModelId(record.acpx);
|
|
5207
5343
|
const desiredConfigOptions = getDesiredConfigOptions(record.acpx);
|
|
5208
5344
|
const storedProcessAlive = isProcessAlive(record.pid);
|
|
5209
5345
|
logReconnectAttempt(record, storedProcessAlive, Boolean(record.pid) && !storedProcessAlive, options.verbose);
|
|
5210
5346
|
const reusingLoadedSession = client.hasReusableSession(record.acpSessionId);
|
|
5211
5347
|
if (reusingLoadedSession) incrementPerfCounter("runtime.connect_and_load.reused_session");
|
|
5212
|
-
else await withTimeout(client.start(), options.timeoutMs);
|
|
5348
|
+
else await withTimeout(client.start(options.authority), options.timeoutMs);
|
|
5349
|
+
assertControlAuthority(options.authority);
|
|
5213
5350
|
options.onClientAvailable?.(options.activeController);
|
|
5214
5351
|
applyLifecycleSnapshotToRecord(record, client.getAgentLifecycleSnapshot());
|
|
5215
5352
|
record.closed = false;
|
|
@@ -5220,7 +5357,8 @@ async function connectAndLoadSession(options) {
|
|
|
5220
5357
|
record,
|
|
5221
5358
|
reusingLoadedSession,
|
|
5222
5359
|
sameSessionOnly,
|
|
5223
|
-
timeoutMs: options.timeoutMs
|
|
5360
|
+
timeoutMs: options.timeoutMs,
|
|
5361
|
+
authority: options.authority
|
|
5224
5362
|
});
|
|
5225
5363
|
const { resumed, loadError, sessionId, createdFreshSession, pendingAgentSessionId, sessionModels } = loadState;
|
|
5226
5364
|
applyReconnectedModelState(record, sessionModels, loadState.configOptionsPresent, loadState.legacyModelMetadataPresent, createdFreshSession);
|
|
@@ -5254,14 +5392,18 @@ async function connectAndLoadSession(options) {
|
|
|
5254
5392
|
};
|
|
5255
5393
|
}
|
|
5256
5394
|
function resolveModelsAfterReplay(replay, initialModels) {
|
|
5257
|
-
|
|
5258
|
-
return replay.modelReplay.replayed ? replay.modelReplay.models :
|
|
5395
|
+
const models = resolveModeReplayModels(replay.modeMetadata, initialModels);
|
|
5396
|
+
if (replay.configReplay.replayed) return replay.configReplay.models ?? preserveLegacyModels(replay.modelReplay.replayed ? replay.modelReplay.models : models);
|
|
5397
|
+
return replay.modelReplay.replayed ? replay.modelReplay.models : models;
|
|
5398
|
+
}
|
|
5399
|
+
function resolveModeReplayModels(modeMetadata, initialModels) {
|
|
5400
|
+
return modeMetadata ? modeMetadata.models : initialModels;
|
|
5259
5401
|
}
|
|
5260
5402
|
function preserveLegacyModels(models) {
|
|
5261
5403
|
return models && !models.configId ? models : void 0;
|
|
5262
5404
|
}
|
|
5263
5405
|
function resolveConfigOptionsPresenceAfterReplay(replay, initiallyPresent) {
|
|
5264
|
-
return initiallyPresent || replay.configReplay.replayed || replay.modelReplay.configOptions !== void 0;
|
|
5406
|
+
return initiallyPresent || replay.modeMetadata?.configOptionsPresent === true || replay.configReplay.replayed || replay.modelReplay.configOptions !== void 0;
|
|
5265
5407
|
}
|
|
5266
5408
|
function applyReconnectedModelState(record, sessionModels, configOptionsPresent, legacyModelMetadataPresent, createdFreshSession) {
|
|
5267
5409
|
clearOmittedFreshSessionConfigOptions(record, createdFreshSession, configOptionsPresent);
|
|
@@ -5302,12 +5444,13 @@ async function replaySessionPreferences(params) {
|
|
|
5302
5444
|
};
|
|
5303
5445
|
let modelReplay = { replayed: false };
|
|
5304
5446
|
let configReplay = { replayed: false };
|
|
5447
|
+
let modeMetadata;
|
|
5305
5448
|
const replay = createReplayState(params.authority);
|
|
5306
|
-
const replacingModel = replacesModel(params.replacingConfigOption, params.sessionModels, params.originalAcpx);
|
|
5307
5449
|
try {
|
|
5308
5450
|
assertControlAuthority(replay.authority);
|
|
5309
|
-
await replayDesiredMode({
|
|
5451
|
+
modeMetadata = await replayDesiredMode({
|
|
5310
5452
|
client: params.client,
|
|
5453
|
+
record: params.record,
|
|
5311
5454
|
sessionId: params.sessionId,
|
|
5312
5455
|
desiredModeId: params.createdFreshSession ? params.desiredModeId : void 0,
|
|
5313
5456
|
replay,
|
|
@@ -5315,6 +5458,8 @@ async function replaySessionPreferences(params) {
|
|
|
5315
5458
|
timeoutMs: params.timeoutMs,
|
|
5316
5459
|
verbose: params.verbose
|
|
5317
5460
|
});
|
|
5461
|
+
const effectiveModels = resolveModeReplayModels(modeMetadata, params.sessionModels);
|
|
5462
|
+
const replacingModel = replacesModel(params.replacingConfigOption, effectiveModels, params.originalAcpx);
|
|
5318
5463
|
modelReplay = await replayDesiredModel({
|
|
5319
5464
|
client: params.client,
|
|
5320
5465
|
sessionId: params.sessionId,
|
|
@@ -5322,7 +5467,7 @@ async function replaySessionPreferences(params) {
|
|
|
5322
5467
|
replay,
|
|
5323
5468
|
previousSessionId: params.originalSessionId,
|
|
5324
5469
|
record: params.record,
|
|
5325
|
-
models:
|
|
5470
|
+
models: effectiveModels,
|
|
5326
5471
|
createdFreshSession: params.createdFreshSession,
|
|
5327
5472
|
timeoutMs: params.timeoutMs,
|
|
5328
5473
|
verbose: params.verbose,
|
|
@@ -5349,7 +5494,8 @@ async function replaySessionPreferences(params) {
|
|
|
5349
5494
|
reconcileAgentSessionId(params.record, params.pendingAgentSessionId);
|
|
5350
5495
|
return {
|
|
5351
5496
|
modelReplay,
|
|
5352
|
-
configReplay
|
|
5497
|
+
configReplay,
|
|
5498
|
+
modeMetadata
|
|
5353
5499
|
};
|
|
5354
5500
|
}
|
|
5355
5501
|
function settleFailedReplay(params, replay, error) {
|
|
@@ -5381,11 +5527,14 @@ async function loadOrCreateRuntimeSession(params) {
|
|
|
5381
5527
|
record: params.record,
|
|
5382
5528
|
reason: "agent does not support session/resume or session/load"
|
|
5383
5529
|
});
|
|
5384
|
-
return await createFreshRuntimeSession(params.client, params.record, params.timeoutMs);
|
|
5530
|
+
return await createFreshRuntimeSession(params.client, params.record, params.timeoutMs, params.authority);
|
|
5385
5531
|
}
|
|
5386
5532
|
async function loadRuntimeSession(params, resume) {
|
|
5387
5533
|
try {
|
|
5388
|
-
const loadResult = await withTimeout(resume ? params.client.resumeSession(params.record.acpSessionId, params.record.cwd) : params.client.loadSessionWithOptions(params.record.acpSessionId, params.record.cwd, {
|
|
5534
|
+
const loadResult = await withTimeout(resume ? params.client.resumeSession(params.record.acpSessionId, params.record.cwd, params.authority) : params.client.loadSessionWithOptions(params.record.acpSessionId, params.record.cwd, {
|
|
5535
|
+
suppressReplayUpdates: true,
|
|
5536
|
+
...params.authority ? { authority: params.authority } : {}
|
|
5537
|
+
}), params.timeoutMs);
|
|
5389
5538
|
reconcileAgentSessionId(params.record, loadResult.agentSessionId);
|
|
5390
5539
|
applyConfigOptionsToRecord(params.record, loadResult);
|
|
5391
5540
|
return {
|
|
@@ -5398,9 +5547,14 @@ async function loadRuntimeSession(params, resume) {
|
|
|
5398
5547
|
createdFreshSession: false
|
|
5399
5548
|
};
|
|
5400
5549
|
} catch (error) {
|
|
5550
|
+
rethrowCancelledLoad(error, params.authority);
|
|
5401
5551
|
return await recoverRuntimeSessionLoadFailure(params, error);
|
|
5402
5552
|
}
|
|
5403
5553
|
}
|
|
5554
|
+
function rethrowCancelledLoad(error, authority) {
|
|
5555
|
+
const signal = authority?.signal;
|
|
5556
|
+
if (signal?.aborted && (error instanceof AgentDisconnectedError || error === signal.reason)) throw signal.reason;
|
|
5557
|
+
}
|
|
5404
5558
|
async function recoverRuntimeSessionLoadFailure(params, error) {
|
|
5405
5559
|
const loadError = formatErrorMessage(error);
|
|
5406
5560
|
if (params.sameSessionOnly) throw makeSessionResumeRequiredError({
|
|
@@ -5410,12 +5564,12 @@ async function recoverRuntimeSessionLoadFailure(params, error) {
|
|
|
5410
5564
|
});
|
|
5411
5565
|
if (!shouldFallbackToNewSession(error, params.record)) throw error;
|
|
5412
5566
|
return {
|
|
5413
|
-
...await createFreshRuntimeSession(params.client, params.record, params.timeoutMs),
|
|
5567
|
+
...await createFreshRuntimeSession(params.client, params.record, params.timeoutMs, params.authority),
|
|
5414
5568
|
loadError
|
|
5415
5569
|
};
|
|
5416
5570
|
}
|
|
5417
|
-
async function createFreshRuntimeSession(client, record, timeoutMs) {
|
|
5418
|
-
const createdSession = await withTimeout(client.createSession(record.cwd), timeoutMs);
|
|
5571
|
+
async function createFreshRuntimeSession(client, record, timeoutMs, authority) {
|
|
5572
|
+
const createdSession = await withTimeout(client.createSession(record.cwd, authority), timeoutMs);
|
|
5419
5573
|
applyConfigOptionsToRecord(record, createdSession);
|
|
5420
5574
|
return {
|
|
5421
5575
|
sessionId: createdSession.sessionId,
|
|
@@ -5482,6 +5636,7 @@ async function withConnectedSession(options) {
|
|
|
5482
5636
|
client,
|
|
5483
5637
|
record,
|
|
5484
5638
|
resumePolicy: options.resumePolicy,
|
|
5639
|
+
replacingMode: options.replacingMode,
|
|
5485
5640
|
replacingConfigOption: options.replacingConfigOption,
|
|
5486
5641
|
authority: options.authority,
|
|
5487
5642
|
timeoutMs: options.timeoutMs,
|
|
@@ -5542,6 +5697,7 @@ async function withConnectedSession(options) {
|
|
|
5542
5697
|
function buildDirectConnectedSessionOptions(options, run) {
|
|
5543
5698
|
return {
|
|
5544
5699
|
sessionRecordId: options.sessionRecordId,
|
|
5700
|
+
replacingMode: options.replacingMode,
|
|
5545
5701
|
replacingConfigOption: options.replacingConfigOption,
|
|
5546
5702
|
loadRecord: resolveSessionRecord,
|
|
5547
5703
|
saveRecord: writeSessionRecord,
|
|
@@ -5592,7 +5748,10 @@ async function withOwnedDirectSession(options) {
|
|
|
5592
5748
|
}
|
|
5593
5749
|
}
|
|
5594
5750
|
async function runSessionSetModeDirect(options) {
|
|
5595
|
-
return toSessionMutationResult(await withOwnedDirectSession(buildDirectConnectedSessionOptions(
|
|
5751
|
+
return toSessionMutationResult(await withOwnedDirectSession(buildDirectConnectedSessionOptions({
|
|
5752
|
+
...options,
|
|
5753
|
+
replacingMode: true
|
|
5754
|
+
}, async ({ client, sessionId, record }) => {
|
|
5596
5755
|
await withTimeout(client.setSessionMode(sessionId, options.modeId), options.timeoutMs);
|
|
5597
5756
|
setDesiredModeId(record, options.modeId);
|
|
5598
5757
|
})));
|
|
@@ -5806,8 +5965,14 @@ const sessionControlTestInternals = {
|
|
|
5806
5965
|
};
|
|
5807
5966
|
async function closeSession(sessionId) {
|
|
5808
5967
|
const record = await resolveSessionRecord(sessionId);
|
|
5809
|
-
|
|
5810
|
-
await
|
|
5968
|
+
let selectedOwner;
|
|
5969
|
+
await tryCloseSessionOnRunningOwner({
|
|
5970
|
+
sessionId: record.acpxRecordId,
|
|
5971
|
+
onOwnerSelected: (owner) => {
|
|
5972
|
+
selectedOwner = owner;
|
|
5973
|
+
}
|
|
5974
|
+
}).catch(() => {});
|
|
5975
|
+
if (selectedOwner) await terminateQueueOwnerForSession(record.acpxRecordId, selectedOwner);
|
|
5811
5976
|
if (record.pid != null && isProcessAlive(record.pid) && await isLikelyMatchingProcess(record.pid, record.agentCommand)) await terminateProcess(record.pid);
|
|
5812
5977
|
const ownership = await acquireSessionTurn(record.acpxRecordId);
|
|
5813
5978
|
try {
|
|
@@ -5825,9 +5990,11 @@ async function closeSession(sessionId) {
|
|
|
5825
5990
|
//#region src/session/execution/session-management.ts
|
|
5826
5991
|
async function createSessionRecordWithClient(client, options) {
|
|
5827
5992
|
const cwd = absolutePath(options.cwd);
|
|
5828
|
-
await withTimeout(client.start(), options.timeoutMs);
|
|
5993
|
+
await withTimeout(client.start({ signal: options.signal }), options.timeoutMs);
|
|
5994
|
+
assertControlAuthority({ signal: options.signal });
|
|
5829
5995
|
const createdState = options.resumeSessionId ? await resumeSessionRecordWithClient(client, options, cwd) : await createFreshSessionState(client, options, cwd);
|
|
5830
5996
|
const { sessionId, agentSessionId } = createdState;
|
|
5997
|
+
assertControlAuthority({ signal: options.signal });
|
|
5831
5998
|
const lifecycle = client.getAgentLifecycleSnapshot();
|
|
5832
5999
|
const record = {
|
|
5833
6000
|
...createInitialSessionRecord({
|
|
@@ -5849,10 +6016,12 @@ async function createSessionRecordWithClient(client, options) {
|
|
|
5849
6016
|
applyConfigOptionsToRecord(record, createdState.sessionResult);
|
|
5850
6017
|
applyInitialModelSelection(record, createdState.sessionResult.models, options.sessionOptions?.model, createdState.modelApplication);
|
|
5851
6018
|
await writeSessionRecord(record);
|
|
6019
|
+
assertControlAuthority({ signal: options.signal });
|
|
5852
6020
|
return record;
|
|
5853
6021
|
}
|
|
5854
6022
|
async function createFreshSessionState(client, options, cwd) {
|
|
5855
|
-
const createdSession = await withTimeout(client.createSession(cwd), options.timeoutMs);
|
|
6023
|
+
const createdSession = await withTimeout(client.createSession(cwd, { signal: options.signal }), options.timeoutMs);
|
|
6024
|
+
assertControlAuthority({ signal: options.signal });
|
|
5856
6025
|
const modelApplication = await applyRequestedModelIfAdvertised({
|
|
5857
6026
|
client,
|
|
5858
6027
|
sessionId: createdSession.sessionId,
|
|
@@ -5860,7 +6029,8 @@ async function createFreshSessionState(client, options, cwd) {
|
|
|
5860
6029
|
models: createdSession.models,
|
|
5861
6030
|
agentCommand: options.agentCommand,
|
|
5862
6031
|
timeoutMs: options.timeoutMs,
|
|
5863
|
-
onWarning: options.onModelWarning
|
|
6032
|
+
onWarning: options.onModelWarning,
|
|
6033
|
+
authority: { signal: options.signal }
|
|
5864
6034
|
});
|
|
5865
6035
|
return {
|
|
5866
6036
|
sessionId: createdSession.sessionId,
|
|
@@ -5874,8 +6044,9 @@ async function resumeSessionRecordWithClient(client, options, cwd) {
|
|
|
5874
6044
|
const resumeMethod = client.supportsResumeSession() ? "session/resume" : client.supportsLoadSession() ? "session/load" : void 0;
|
|
5875
6045
|
if (!resumeMethod) throw new Error(`Agent command "${options.agentCommand}" does not support session/resume or session/load; cannot resume session ${options.resumeSessionId}`);
|
|
5876
6046
|
try {
|
|
5877
|
-
const resumedSession = await withTimeout(resumeMethod === "session/resume" ? client.resumeSession(options.resumeSessionId, cwd) : client.
|
|
6047
|
+
const resumedSession = await withTimeout(resumeMethod === "session/resume" ? client.resumeSession(options.resumeSessionId, cwd, { signal: options.signal }) : client.loadSessionWithOptions(options.resumeSessionId, cwd, { authority: { signal: options.signal } }), options.timeoutMs);
|
|
5878
6048
|
const sessionModels = resumedSession.models;
|
|
6049
|
+
assertControlAuthority({ signal: options.signal });
|
|
5879
6050
|
const modelApplication = await applyRequestedModelIfAdvertised({
|
|
5880
6051
|
client,
|
|
5881
6052
|
sessionId: options.resumeSessionId,
|
|
@@ -5883,7 +6054,8 @@ async function resumeSessionRecordWithClient(client, options, cwd) {
|
|
|
5883
6054
|
models: sessionModels,
|
|
5884
6055
|
agentCommand: options.agentCommand,
|
|
5885
6056
|
timeoutMs: options.timeoutMs,
|
|
5886
|
-
onWarning: options.onModelWarning
|
|
6057
|
+
onWarning: options.onModelWarning,
|
|
6058
|
+
authority: { signal: options.signal }
|
|
5887
6059
|
});
|
|
5888
6060
|
return {
|
|
5889
6061
|
sessionId: options.resumeSessionId,
|
|
@@ -5896,7 +6068,7 @@ async function resumeSessionRecordWithClient(client, options, cwd) {
|
|
|
5896
6068
|
}
|
|
5897
6069
|
}
|
|
5898
6070
|
async function createSessionWithClient(options) {
|
|
5899
|
-
options.signal
|
|
6071
|
+
assertControlAuthority({ signal: options.signal });
|
|
5900
6072
|
const client = new AcpClient({
|
|
5901
6073
|
agentCommand: options.agentCommand,
|
|
5902
6074
|
agentArgv: options.agentArgv,
|
|
@@ -5912,28 +6084,25 @@ async function createSessionWithClient(options) {
|
|
|
5912
6084
|
verbose: options.verbose,
|
|
5913
6085
|
sessionOptions: options.sessionOptions
|
|
5914
6086
|
});
|
|
5915
|
-
const
|
|
5916
|
-
client.close().catch(() => {});
|
|
5917
|
-
};
|
|
5918
|
-
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
6087
|
+
const closeOwnedClient = ownDirectClient(client, options.signal);
|
|
5919
6088
|
try {
|
|
5920
6089
|
const create = async () => {
|
|
5921
|
-
options.signal
|
|
6090
|
+
assertControlAuthority({ signal: options.signal });
|
|
5922
6091
|
const record = await createSessionRecordWithClient(client, options);
|
|
5923
|
-
options.signal
|
|
6092
|
+
assertControlAuthority({ signal: options.signal });
|
|
5924
6093
|
return record;
|
|
5925
6094
|
};
|
|
5926
6095
|
return {
|
|
5927
6096
|
record: options.handleProcessInterrupts === false ? await create() : await withInterrupt(create, async () => {
|
|
5928
|
-
await
|
|
6097
|
+
await closeOwnedClient();
|
|
5929
6098
|
}),
|
|
5930
6099
|
client
|
|
5931
6100
|
};
|
|
5932
6101
|
} catch (error) {
|
|
5933
|
-
await
|
|
5934
|
-
throw error;
|
|
6102
|
+
await closeOwnedClient();
|
|
6103
|
+
throw directExecutionError(error, options.signal);
|
|
5935
6104
|
} finally {
|
|
5936
|
-
|
|
6105
|
+
closeOwnedClient.release();
|
|
5937
6106
|
}
|
|
5938
6107
|
}
|
|
5939
6108
|
async function createSession(options) {
|
|
@@ -5999,7 +6168,7 @@ async function ensureSession(options) {
|
|
|
5999
6168
|
}
|
|
6000
6169
|
}
|
|
6001
6170
|
async function ensureSessionWithOwnership(options, cwd) {
|
|
6002
|
-
options.signal
|
|
6171
|
+
assertControlAuthority({ signal: options.signal });
|
|
6003
6172
|
const gitRoot = findGitRepositoryRoot(cwd);
|
|
6004
6173
|
const walkBoundary = options.walkBoundary ?? gitRoot ?? cwd;
|
|
6005
6174
|
const existing = await findSessionByDirectoryWalk({
|
|
@@ -6509,27 +6678,27 @@ const NODE_TEST_FLAGS_WITH_VALUE = /* @__PURE__ */ new Set([
|
|
|
6509
6678
|
"--test-reporter",
|
|
6510
6679
|
"--test-reporter-destination"
|
|
6511
6680
|
]);
|
|
6512
|
-
const
|
|
6681
|
+
const INSPECTOR_FLAGS = /* @__PURE__ */ new Set([
|
|
6513
6682
|
"--inspect",
|
|
6514
6683
|
"--inspect-brk",
|
|
6684
|
+
"--inspect-wait"
|
|
6685
|
+
]);
|
|
6686
|
+
const INSPECTOR_FLAGS_WITH_VALUE = /* @__PURE__ */ new Set([
|
|
6515
6687
|
"--inspect-port",
|
|
6516
6688
|
"--inspect-publish-uid",
|
|
6517
6689
|
"--debug-port"
|
|
6518
6690
|
]);
|
|
6519
|
-
const INSPECTOR_FLAG_PREFIXES = [
|
|
6520
|
-
"--inspect=",
|
|
6521
|
-
"--inspect-brk=",
|
|
6522
|
-
"--inspect-port=",
|
|
6523
|
-
"--inspect-publish-uid=",
|
|
6524
|
-
"--debug-port="
|
|
6525
|
-
];
|
|
6526
6691
|
function classifyExecArgv(value) {
|
|
6527
|
-
if (value
|
|
6528
|
-
if (
|
|
6529
|
-
return
|
|
6692
|
+
if (NODE_TEST_FLAGS_WITH_VALUE.has(value)) return "drop-with-value";
|
|
6693
|
+
if (NODE_TEST_FLAGS.has(value) || value.startsWith("--test-")) return "drop";
|
|
6694
|
+
return classifyInspectorArgv(value);
|
|
6530
6695
|
}
|
|
6531
|
-
function
|
|
6532
|
-
|
|
6696
|
+
function classifyInspectorArgv(value) {
|
|
6697
|
+
const [name] = value.split("=", 1);
|
|
6698
|
+
if (!name?.startsWith("--")) return "keep";
|
|
6699
|
+
const flag = name.replaceAll("_", "-");
|
|
6700
|
+
if (INSPECTOR_FLAGS_WITH_VALUE.has(flag)) return value.includes("=") ? "drop" : "drop-with-value";
|
|
6701
|
+
return INSPECTOR_FLAGS.has(flag) ? "drop" : "keep";
|
|
6533
6702
|
}
|
|
6534
6703
|
function sanitizeQueueOwnerExecArgv(execArgv = process.execArgv) {
|
|
6535
6704
|
const sanitized = [];
|
|
@@ -6889,6 +7058,7 @@ async function applyPromptModelIfAdvertised(params) {
|
|
|
6889
7058
|
models: advertisedModelState(params.record.acpx),
|
|
6890
7059
|
agentCommand: params.record.agentCommand,
|
|
6891
7060
|
timeoutMs: params.timeoutMs,
|
|
7061
|
+
authority: { signal: params.signal },
|
|
6892
7062
|
onWarning: params.suppressWarnings ? void 0 : (message) => process.stderr.write(`[acpx] warning: ${message}\n`)
|
|
6893
7063
|
});
|
|
6894
7064
|
if (result.applied) params.record.acpx = applyModelSelection(params.record.acpx, requestedModel, result.response);
|
|
@@ -7073,7 +7243,7 @@ async function waitForSessionTurn(options) {
|
|
|
7073
7243
|
"SIGTERM",
|
|
7074
7244
|
"SIGHUP"
|
|
7075
7245
|
];
|
|
7076
|
-
for (const signal of signals) process.once(signal, onInterrupt);
|
|
7246
|
+
if (options.handleProcessInterrupts !== false) for (const signal of signals) process.once(signal, onInterrupt);
|
|
7077
7247
|
const timeoutMs = options.timeoutMs;
|
|
7078
7248
|
const timeout = timeoutMs != null && timeoutMs > 0 ? setTimeout(() => waiting.abort(new TimeoutError(timeoutMs)), timeoutMs) : void 0;
|
|
7079
7249
|
const signal = options.waitSignal ? AbortSignal.any([waiting.signal, options.waitSignal]) : waiting.signal;
|
|
@@ -7084,18 +7254,22 @@ async function waitForSessionTurn(options) {
|
|
|
7084
7254
|
ownership: await acquireSessionTurn(acpxRecordId, signal)
|
|
7085
7255
|
};
|
|
7086
7256
|
} catch (error) {
|
|
7087
|
-
signal
|
|
7088
|
-
throw error;
|
|
7257
|
+
return throwTurnAcquisitionError(error, signal);
|
|
7089
7258
|
} finally {
|
|
7090
7259
|
clearTimeout(timeout);
|
|
7091
7260
|
for (const signal of signals) process.off(signal, onInterrupt);
|
|
7092
7261
|
}
|
|
7093
7262
|
}
|
|
7263
|
+
function throwTurnAcquisitionError(error, signal) {
|
|
7264
|
+
if (signal.aborted && error instanceof Error && error.name === "AbortError" && error.cause === signal.reason) throw signal.reason;
|
|
7265
|
+
throw error;
|
|
7266
|
+
}
|
|
7094
7267
|
async function runSessionPrompt(options) {
|
|
7095
7268
|
let turn;
|
|
7096
7269
|
try {
|
|
7097
7270
|
turn = await waitForSessionTurn(options);
|
|
7098
7271
|
} catch (error) {
|
|
7272
|
+
if (options.ownedSignal) throw error;
|
|
7099
7273
|
if (options.waitSignal?.aborted && error === options.waitSignal.reason) {
|
|
7100
7274
|
const record = await resolveSessionRecord(options.sessionRecordId);
|
|
7101
7275
|
return {
|
|
@@ -7215,8 +7389,10 @@ async function runOwnedSessionPrompt(options) {
|
|
|
7215
7389
|
const record = await measurePerf("session.resolve_prompt_record", async () => {
|
|
7216
7390
|
return await resolveSessionRecord(options.sessionRecordId);
|
|
7217
7391
|
});
|
|
7392
|
+
options.ownedSignal?.throwIfAborted();
|
|
7218
7393
|
const { conversation, promptMessageId } = preparePromptConversation(record, options);
|
|
7219
7394
|
await writeSessionRecord(record);
|
|
7395
|
+
options.ownedSignal?.throwIfAborted();
|
|
7220
7396
|
output.setContext({ sessionId: record.acpxRecordId });
|
|
7221
7397
|
const eventWriter = await measurePerf("session.events.open", async () => {
|
|
7222
7398
|
return await SessionEventWriter.open(record);
|
|
@@ -7259,7 +7435,7 @@ async function runOwnedSessionPrompt(options) {
|
|
|
7259
7435
|
if (options.verbose) process.stderr.write("[acpx] live session checkpoint failed: " + formatErrorMessage(error) + "\n");
|
|
7260
7436
|
}
|
|
7261
7437
|
});
|
|
7262
|
-
let closeClientOnExit = options.client == null;
|
|
7438
|
+
let closeClientOnExit = options.client == null || options.ownedSignal !== void 0;
|
|
7263
7439
|
const client = options.client ?? new AcpClient({
|
|
7264
7440
|
agentCommand: record.agentCommand,
|
|
7265
7441
|
agentArgv: record.agentArgv,
|
|
@@ -7285,6 +7461,7 @@ async function runOwnedSessionPrompt(options) {
|
|
|
7285
7461
|
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
7286
7462
|
verbose: options.verbose
|
|
7287
7463
|
});
|
|
7464
|
+
const closeOwnedClient = options.closeProvidedClient ?? ownDirectClient(client, options.ownedSignal);
|
|
7288
7465
|
client.setEventHandlers({
|
|
7289
7466
|
onAcpMessage: (direction, message) => {
|
|
7290
7467
|
pendingMessages.push(message);
|
|
@@ -7358,6 +7535,7 @@ async function runOwnedSessionPrompt(options) {
|
|
|
7358
7535
|
verbose: options.verbose,
|
|
7359
7536
|
suppressWarnings: options.suppressSdkConsoleErrors,
|
|
7360
7537
|
activeController,
|
|
7538
|
+
authority: { signal: options.ownedSignal },
|
|
7361
7539
|
onClientAvailable: (controller) => {
|
|
7362
7540
|
options.onClientAvailable?.(controller);
|
|
7363
7541
|
notifiedClientAvailable = true;
|
|
@@ -7464,15 +7642,19 @@ async function runOwnedSessionPrompt(options) {
|
|
|
7464
7642
|
return response;
|
|
7465
7643
|
};
|
|
7466
7644
|
const runPrompt = async () => {
|
|
7645
|
+
options.ownedSignal?.throwIfAborted();
|
|
7467
7646
|
const { sessionId: activeSessionId, resumed, loadError } = await connectForPrompt();
|
|
7647
|
+
options.ownedSignal?.throwIfAborted();
|
|
7468
7648
|
await applyPromptModelIfAdvertised({
|
|
7469
7649
|
client,
|
|
7470
7650
|
sessionId: activeSessionId,
|
|
7471
7651
|
requestedModel: options.sessionOptions?.model,
|
|
7472
7652
|
record,
|
|
7473
7653
|
timeoutMs: options.timeoutMs,
|
|
7474
|
-
suppressWarnings: options.suppressSdkConsoleErrors
|
|
7654
|
+
suppressWarnings: options.suppressSdkConsoleErrors,
|
|
7655
|
+
signal: options.ownedSignal
|
|
7475
7656
|
});
|
|
7657
|
+
options.ownedSignal?.throwIfAborted();
|
|
7476
7658
|
output.setContext({ sessionId: record.acpxRecordId });
|
|
7477
7659
|
await liveCheckpoint.checkpoint();
|
|
7478
7660
|
const response = await savePromptSuccess(await runPromptWithRetries(activeSessionId));
|
|
@@ -7490,20 +7672,23 @@ async function runOwnedSessionPrompt(options) {
|
|
|
7490
7672
|
record.lastUsedAt = isoNow$1();
|
|
7491
7673
|
applyConversation(record, conversation);
|
|
7492
7674
|
await flushPendingMessages(false).catch(() => {});
|
|
7493
|
-
if (closeClientOnExit) await
|
|
7675
|
+
if (closeClientOnExit) await closeOwnedClient();
|
|
7494
7676
|
};
|
|
7495
7677
|
const runObservedPrompt = async () => {
|
|
7496
7678
|
try {
|
|
7497
|
-
|
|
7679
|
+
const result = await runWithOptionalInterrupt({
|
|
7498
7680
|
handleProcessInterrupts: options.handleProcessInterrupts,
|
|
7499
7681
|
run: runPrompt,
|
|
7500
7682
|
handleInterrupt
|
|
7501
7683
|
});
|
|
7684
|
+
options.ownedSignal?.throwIfAborted();
|
|
7685
|
+
return result;
|
|
7502
7686
|
} catch (error) {
|
|
7503
|
-
const
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7687
|
+
const failure = directExecutionError(error, options.ownedSignal);
|
|
7688
|
+
const matchedAcpError = acpErrors.match(failure);
|
|
7689
|
+
attachAcpErrorPayload(failure, matchedAcpError);
|
|
7690
|
+
markOutputAlreadyEmitted(failure, matchedAcpError !== void 0 && shouldMarkAcpErrorsEmitted);
|
|
7691
|
+
throw failure;
|
|
7507
7692
|
}
|
|
7508
7693
|
};
|
|
7509
7694
|
const cleanupPrompt = async (attempt) => {
|
|
@@ -7516,7 +7701,7 @@ async function runOwnedSessionPrompt(options) {
|
|
|
7516
7701
|
async () => {
|
|
7517
7702
|
const journalFailed = attempt.status === "rejected" && attempt.error instanceof AcpxOperationalError && attempt.error.detailCode === "SESSION_JOURNAL_WRITE_FAILED";
|
|
7518
7703
|
if (unresolvedPrompt || closeClientOnExit || journalFailed) try {
|
|
7519
|
-
await
|
|
7704
|
+
await closeOwnedClient();
|
|
7520
7705
|
} catch (error) {
|
|
7521
7706
|
options.onClientCloseFailure?.();
|
|
7522
7707
|
throw error;
|
|
@@ -7554,7 +7739,8 @@ async function runOwnedSessionPrompt(options) {
|
|
|
7554
7739
|
cleanup: cleanupPrompt
|
|
7555
7740
|
});
|
|
7556
7741
|
}
|
|
7557
|
-
async function runOnce(options) {
|
|
7742
|
+
async function runOnce(options, control) {
|
|
7743
|
+
const authority = { signal: control?.signal };
|
|
7558
7744
|
const output = options.outputFormatter;
|
|
7559
7745
|
const shouldMarkAcpErrorsEmitted = rendersAcpErrors(options.errorEmissionPolicy);
|
|
7560
7746
|
let promptTurnActive = false;
|
|
@@ -7594,10 +7780,12 @@ async function runOnce(options) {
|
|
|
7594
7780
|
},
|
|
7595
7781
|
sessionOptions: options.sessionOptions
|
|
7596
7782
|
});
|
|
7783
|
+
const closeOwnedClient = ownDirectClient(client, control?.signal);
|
|
7597
7784
|
const runExecPromptAttempt = async (sessionId) => {
|
|
7785
|
+
assertControlAuthority(authority);
|
|
7598
7786
|
acpErrors.reset();
|
|
7599
7787
|
return await measurePerf("runtime.exec.prompt", async () => {
|
|
7600
|
-
return await withTimeout(client.prompt(sessionId, options.prompt), options.timeoutMs);
|
|
7788
|
+
return await withTimeout(client.prompt(sessionId, options.prompt, void 0, void 0, void 0, { signal: control?.signal }), options.timeoutMs);
|
|
7601
7789
|
});
|
|
7602
7790
|
};
|
|
7603
7791
|
const runExecPromptWithRetries = async (sessionId) => {
|
|
@@ -7606,78 +7794,102 @@ async function runOnce(options) {
|
|
|
7606
7794
|
for (let attempt = 0;; attempt++) try {
|
|
7607
7795
|
return await runExecPromptAttempt(sessionId);
|
|
7608
7796
|
} catch (error) {
|
|
7609
|
-
if (await preparePromptRetry(error, attempt, maxRetries, () => promptTurnHadSideEffects, options.suppressSdkConsoleErrors)) continue;
|
|
7797
|
+
if (await preparePromptRetry(error, attempt, maxRetries, () => promptTurnHadSideEffects, options.suppressSdkConsoleErrors, control?.signal)) continue;
|
|
7610
7798
|
promptTurnActive = false;
|
|
7611
7799
|
throw error;
|
|
7612
7800
|
}
|
|
7613
7801
|
};
|
|
7614
7802
|
try {
|
|
7615
|
-
return await
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
sessionId
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7803
|
+
return await runWithOptionalInterrupt({
|
|
7804
|
+
handleProcessInterrupts: control?.handleProcessInterrupts,
|
|
7805
|
+
run: async () => {
|
|
7806
|
+
assertControlAuthority(authority);
|
|
7807
|
+
await measurePerf("runtime.exec.start", async () => {
|
|
7808
|
+
await withTimeout(client.start(authority), options.timeoutMs);
|
|
7809
|
+
});
|
|
7810
|
+
assertControlAuthority(authority);
|
|
7811
|
+
const createdSession = await measurePerf("runtime.exec.create_session", async () => {
|
|
7812
|
+
return await withTimeout(client.createSession(absolutePath(options.cwd), authority), options.timeoutMs);
|
|
7813
|
+
});
|
|
7814
|
+
assertControlAuthority(authority);
|
|
7815
|
+
const sessionId = createdSession.sessionId;
|
|
7816
|
+
if (createdSession.models) applyAdvertisedModelState(controlState, createdSession.models);
|
|
7817
|
+
controlState = applyConfigOptionsToState(controlState, createdSession.configOptions ?? []);
|
|
7818
|
+
const modelApplication = await applyRequestedModelIfAdvertised({
|
|
7819
|
+
client,
|
|
7820
|
+
sessionId,
|
|
7821
|
+
requestedModel: options.sessionOptions?.model,
|
|
7822
|
+
models: createdSession.models,
|
|
7823
|
+
agentCommand: options.agentCommand,
|
|
7824
|
+
timeoutMs: options.timeoutMs,
|
|
7825
|
+
authority,
|
|
7826
|
+
onWarning: options.suppressSdkConsoleErrors ? void 0 : (message) => process.stderr.write(`[acpx] warning: ${message}\n`)
|
|
7827
|
+
});
|
|
7828
|
+
if (modelApplication.response) controlState = applyConfigOptionsToState(controlState, modelApplication.response.configOptions);
|
|
7829
|
+
for (const configOption of options.configOptions ?? []) {
|
|
7830
|
+
assertControlAuthority(authority);
|
|
7831
|
+
const response = await withTimeout(client.setSessionConfigOption(sessionId, configOption.configId, configOption.value, advertisedModelState(controlState), authority), options.timeoutMs);
|
|
7832
|
+
controlState = applyConfigOptionsToState(controlState, response.configOptions);
|
|
7833
|
+
}
|
|
7834
|
+
assertControlAuthority(authority);
|
|
7835
|
+
output.setContext({ sessionId });
|
|
7836
|
+
const response = await runExecPromptWithRetries(sessionId);
|
|
7837
|
+
promptTurnActive = false;
|
|
7838
|
+
return toPromptResult(response.stopReason, sessionId, client, response._meta);
|
|
7839
|
+
},
|
|
7840
|
+
handleInterrupt: async () => {
|
|
7841
|
+
await client.cancelActivePrompt(INTERRUPT_CANCEL_WAIT_MS);
|
|
7842
|
+
await closeOwnedClient();
|
|
7638
7843
|
}
|
|
7639
|
-
output.setContext({ sessionId });
|
|
7640
|
-
const response = await runExecPromptWithRetries(sessionId);
|
|
7641
|
-
promptTurnActive = false;
|
|
7642
|
-
output.flush();
|
|
7643
|
-
return toPromptResult(response.stopReason, sessionId, client, response._meta);
|
|
7644
|
-
}, async () => {
|
|
7645
|
-
await client.cancelActivePrompt(INTERRUPT_CANCEL_WAIT_MS);
|
|
7646
|
-
await client.close();
|
|
7647
7844
|
});
|
|
7648
7845
|
} catch (error) {
|
|
7649
|
-
const
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7846
|
+
const failure = directExecutionError(error, authority.signal);
|
|
7847
|
+
const matchedAcpError = acpErrors.match(failure);
|
|
7848
|
+
attachAcpErrorPayload(failure, matchedAcpError);
|
|
7849
|
+
markOutputAlreadyEmitted(failure, matchedAcpError !== void 0 && shouldMarkAcpErrorsEmitted);
|
|
7850
|
+
throw failure;
|
|
7653
7851
|
} finally {
|
|
7654
|
-
|
|
7852
|
+
try {
|
|
7853
|
+
await closeOwnedClient();
|
|
7854
|
+
} finally {
|
|
7855
|
+
output.flush();
|
|
7856
|
+
}
|
|
7655
7857
|
}
|
|
7656
7858
|
}
|
|
7657
|
-
async function sendSessionDirect(options) {
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
7662
|
-
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
|
|
7673
|
-
|
|
7674
|
-
|
|
7675
|
-
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
|
|
7679
|
-
|
|
7680
|
-
|
|
7859
|
+
async function sendSessionDirect(options, control) {
|
|
7860
|
+
const closeProvidedClient = control && options.client ? ownDirectClient(options.client, control.signal) : void 0;
|
|
7861
|
+
try {
|
|
7862
|
+
control?.signal.throwIfAborted();
|
|
7863
|
+
return await runSessionPrompt({
|
|
7864
|
+
ownedSignal: control?.signal,
|
|
7865
|
+
closeProvidedClient,
|
|
7866
|
+
waitSignal: control?.signal,
|
|
7867
|
+
handleProcessInterrupts: control?.handleProcessInterrupts,
|
|
7868
|
+
sessionRecordId: options.sessionId,
|
|
7869
|
+
prompt: options.prompt,
|
|
7870
|
+
mcpServers: options.mcpServers,
|
|
7871
|
+
permissionMode: options.permissionMode,
|
|
7872
|
+
resumePolicy: options.resumePolicy,
|
|
7873
|
+
nonInteractivePermissions: options.nonInteractivePermissions,
|
|
7874
|
+
permissionPolicy: options.permissionPolicy,
|
|
7875
|
+
authCredentials: options.authCredentials,
|
|
7876
|
+
authPolicy: options.authPolicy,
|
|
7877
|
+
fs: options.fs,
|
|
7878
|
+
terminal: options.terminal,
|
|
7879
|
+
outputFormatter: options.outputFormatter,
|
|
7880
|
+
errorEmissionPolicy: options.errorEmissionPolicy,
|
|
7881
|
+
onAcpMessage: options.onAcpMessage,
|
|
7882
|
+
onSessionUpdate: options.onSessionUpdate,
|
|
7883
|
+
onClientOperation: options.onClientOperation,
|
|
7884
|
+
onPermissionEscalation: options.onPermissionEscalation,
|
|
7885
|
+
timeoutMs: options.timeoutMs,
|
|
7886
|
+
suppressSdkConsoleErrors: options.suppressSdkConsoleErrors,
|
|
7887
|
+
verbose: options.verbose,
|
|
7888
|
+
client: options.client
|
|
7889
|
+
});
|
|
7890
|
+
} finally {
|
|
7891
|
+
await closeProvidedClient?.();
|
|
7892
|
+
}
|
|
7681
7893
|
}
|
|
7682
7894
|
//#endregion
|
|
7683
7895
|
//#region src/session/execution/queue-owner-runtime.ts
|
|
@@ -8081,4 +8293,4 @@ const queueOwnerRuntimeTestInternals = { queueOwnerExitIsFatal };
|
|
|
8081
8293
|
//#endregion
|
|
8082
8294
|
export { getAcpxVersion as $, applyInitialModelSelection as A, cloneSessionAcpxState as B, setSessionModeOnOwner as C, connectAndLoadSession as D, withConnectedSession as E, sessionOptionsFromRecord as F, recordSessionUpdate as G, createSessionConversation as H, applyConversation as I, AcpClient as J, trimConversationForRuntime as K, applyLifecycleSnapshotToRecord as L, applyRequestedModelIfAdvertised as M, setDesiredModeId as N, applyConfigOptionSelection as O, persistSessionOptions as P, isRequestedModelUnsupportedError as Q, createInitialSessionRecord as R, setSessionMode as S, setSessionModelOnOwner as T, recordClientOperation as U, cloneSessionConversation as V, recordPromptSubmission as W, REQUESTED_MODEL_UNSUPPORTED_REASONS as X, REQUESTED_MODEL_UNSUPPORTED_ERROR_CODE as Y, RequestedModelUnsupportedError as Z, cancelSessionPrompt as _, runQueuedTask as a, InterruptedError as at, setSessionConfigOption as b, LiveSessionCheckpoint as c, withInterrupt as ct, flushPerfMetricsCapture as d, normalizeOutputError as dt, permissionModeSatisfies as et, installPerfMetricsCapture as f, listAgentSessions as g, ensureSession as h, runOnce as i, isLegacyZedCodexAcpInvocation as it, applyModelSelection as j, applyConfigOptionsToRecord as k, runPromptTurn as l, withTimeout as lt, createSessionWithClient as m, runSessionQueueOwner as n, normalizeQueueOwnerTtlMs as nt, sendSessionDirect as o, TimeoutError as ot, createSession as p, advertisedModelState as q, sendSession as r, listSessionEvents as rt, DISCARD_OUTPUT_FORMATTER as s, assertControlAuthority as st, queueOwnerRuntimeTestInternals as t, DEFAULT_QUEUE_OWNER_TTL_MS as tt, buildQueueOwnerArgOverride as u, exitCodeForOutputErrorCode as ut, closeSession as v, setSessionModel as w, setSessionConfigOptionOnOwner as x, sessionControlTestInternals as y, reconcileAgentSessionId as z };
|
|
8083
8295
|
|
|
8084
|
-
//# sourceMappingURL=queue-owner-runtime-
|
|
8296
|
+
//# sourceMappingURL=queue-owner-runtime-CLwjMYNL.js.map
|