pi-agent-browser-native 0.3.0 → 0.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +265 -0
- package/README.md +130 -54
- package/dist/extensions/agent-browser/index.js +781 -169
- package/dist/extensions/agent-browser/lib/argv-descriptor.js +35 -3
- package/dist/extensions/agent-browser/lib/argv-grammar.js +50 -2
- package/dist/extensions/agent-browser/lib/batch-lifecycle.js +71 -0
- package/dist/extensions/agent-browser/lib/command-policy.js +5 -8
- package/dist/extensions/agent-browser/lib/command-taxonomy.js +53 -12
- package/dist/extensions/agent-browser/lib/config-policy.js +25 -1
- package/dist/extensions/agent-browser/lib/config.js +1 -1
- package/dist/extensions/agent-browser/lib/input-modes/job.js +61 -13
- package/dist/extensions/agent-browser/lib/input-modes/lookups.js +2 -2
- package/dist/extensions/agent-browser/lib/input-modes/params.js +23 -24
- package/dist/extensions/agent-browser/lib/input-modes/script.js +462 -0
- package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +51 -12
- package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +26 -4
- package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +6 -139
- package/dist/extensions/agent-browser/lib/managed-session-restore.js +26 -116
- package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +2 -4
- package/dist/extensions/agent-browser/lib/managed-session-storage.js +54 -25
- package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +26 -5
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +110 -30
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +2 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +54 -48
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +71 -5
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +2 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +6 -7
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +119 -2
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +7 -6
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +152 -64
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +244 -102
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +63 -37
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +20 -21
- package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +36 -18
- package/dist/extensions/agent-browser/lib/orchestration/output-file.js +41 -21
- package/dist/extensions/agent-browser/lib/orchestration/script-mode.js +299 -0
- package/dist/extensions/agent-browser/lib/page-target-validation.js +270 -0
- package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +32 -10
- package/dist/extensions/agent-browser/lib/playbook.js +29 -25
- package/dist/extensions/agent-browser/lib/process-environment.js +14 -0
- package/dist/extensions/agent-browser/lib/process-identity.js +5 -12
- package/dist/extensions/agent-browser/lib/process.js +130 -104
- package/dist/extensions/agent-browser/lib/recording-reservations.js +116 -0
- package/dist/extensions/agent-browser/lib/results/action-recommendations.js +63 -6
- package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +62 -4
- package/dist/extensions/agent-browser/lib/results/categories.js +6 -1
- package/dist/extensions/agent-browser/lib/results/next-actions.js +19 -5
- package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +85 -38
- package/dist/extensions/agent-browser/lib/results/presentation/batch.js +86 -18
- package/dist/extensions/agent-browser/lib/results/presentation/common.js +38 -2
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +18 -17
- package/dist/extensions/agent-browser/lib/results/presentation/errors.js +2 -1
- package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +38 -20
- package/dist/extensions/agent-browser/lib/results/presentation/registry.js +60 -15
- package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +1 -10
- package/dist/extensions/agent-browser/lib/results/presentation.js +36 -6
- package/dist/extensions/agent-browser/lib/results/recovery-actions.js +3 -1
- package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +9 -0
- package/dist/extensions/agent-browser/lib/results/selector-recovery.js +54 -11
- package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +13 -7
- package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +2 -1
- package/dist/extensions/agent-browser/lib/results/snapshot.js +4 -4
- package/dist/extensions/agent-browser/lib/runtime.js +186 -108
- package/dist/extensions/agent-browser/lib/session-page-state.js +71 -10
- package/dist/extensions/agent-browser/lib/temp.js +1 -2
- package/dist/extensions/agent-browser/lib/upstream-version.js +14 -0
- package/dist/extensions/agent-browser/lib/web-search.js +108 -24
- package/dist/extensions/agent-browser/script-worker.js +169 -0
- package/dist/scripts/agent-browser-target.mjs +21 -0
- package/docs/ARCHITECTURE.md +57 -34
- package/docs/COMMAND_REFERENCE.md +255 -68
- package/docs/ELECTRON.md +2 -2
- package/docs/RELEASE.md +12 -10
- package/docs/REQUIREMENTS.md +11 -8
- package/docs/SUPPORT_MATRIX.md +36 -24
- package/docs/TOOL_CONTRACT.md +169 -95
- package/package.json +3 -1
- package/platform-smoke.config.mjs +2 -2
- package/scripts/agent-browser-capability-baseline.mjs +87 -9
- package/scripts/agent-browser-target.mjs +21 -0
- package/scripts/build.mjs +41 -0
- package/scripts/config.mjs +1 -0
- package/scripts/doctor.mjs +16 -9
- package/scripts/platform-smoke/browser-dogfood-windows.ps1 +9 -3
- package/scripts/platform-smoke/targets.mjs +12 -6
- package/dist/extensions/agent-browser/lib/managed-session-capabilities.js +0 -20
- package/dist/extensions/agent-browser/lib/managed-session-state-policy.js +0 -583
- package/dist/extensions/agent-browser/lib/navigation-policy.js +0 -78
- package/dist/extensions/agent-browser/lib/results/presentation/managed-list-filter.js +0 -37
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import { rm } from "node:fs/promises";
|
|
2
|
-
import { getAgentBrowserSessionIdentityKey } from "../../argv-grammar.js";
|
|
3
|
-
import {
|
|
2
|
+
import { getAgentBrowserSessionIdentityKey, isAgentBrowserSessionIdentityKeyInNamespace } from "../../argv-grammar.js";
|
|
3
|
+
import { batchHasSuccessfulCloseAll, getSuccessfulBatchCloseLifecycle } from "../../batch-lifecycle.js";
|
|
4
|
+
import { isCloseAllCommand, isCloseCommand, isOpenNavigationCommand, isUnverifiedPageTransitionCommand } from "../../command-taxonomy.js";
|
|
4
5
|
import { OPEN_RESULT_TAB_CORRECTION_FLAGS } from "../../launch-scoped-flags.js";
|
|
5
6
|
import { cleanupElectronLaunchResources, inspectElectronLaunchStatus } from "../../electron/cleanup.js";
|
|
6
|
-
import {
|
|
7
|
-
import { getManagedSessionResultingPageState, getObservedBrowserPageValidationError, managedSessionCommandRequiresLivePageVerification } from "../../managed-session-state-policy.js";
|
|
7
|
+
import { getResultingPageTargetState, commandRequiresLivePageVerification } from "../../page-target-validation.js";
|
|
8
8
|
import { analyzeNetworkSourceLookupResults, analyzeSourceLookupResults, redactNetworkSourceLookupAnalysis } from "../../input-modes/lookups.js";
|
|
9
|
-
import { analyzeQaPresetResults, analyzeQaPresetTimeout, buildQaCompactPassText, extractQaPageContext } from "../../input-modes/job.js";
|
|
9
|
+
import { analyzeQaPresetResults, analyzeQaPresetTimeout, buildQaCompactFailureText, buildQaCompactPassText, extractQaPageContext } from "../../input-modes/job.js";
|
|
10
10
|
import { applyNetworkRouteRecords, buildNetworkRouteDiagnostics } from "../../results/network-routes.js";
|
|
11
11
|
import { buildToolPresentation } from "../../results/presentation.js";
|
|
12
12
|
import { getAgentBrowserErrorText, parseAgentBrowserEnvelope } from "../../results/envelope.js";
|
|
13
|
+
import { omitUpstreamLifecycle } from "../../results/presentation/common.js";
|
|
13
14
|
import { getClipboardWritePayloadCandidates, redactClipboardPermissionEcho, redactClipboardPermissionErrorValue } from "../../results/presentation/errors.js";
|
|
14
15
|
import { shouldCaptureSemanticActionNavigationSummary } from "../../results/presentation/semantic-action.js";
|
|
15
|
-
import { commandExplicitlyTargetsAboutBlank, deriveSessionTabTarget, extractLatestRefSnapshotStateFromBatchResults, extractRefSnapshotFromData, extractSessionTabTargetFromBatchResults, extractSessionTabTargetFromCommandData, isAboutBlankSessionTabTarget, normalizeSessionTabTarget, } from "../../session-page-state.js";
|
|
16
|
+
import { buildPageTransitionRefSnapshotInvalidation, commandExplicitlyTargetsAboutBlank, getCommandRefSnapshotInvalidation, deriveSessionTabTarget, extractLatestRefSnapshotStateFromBatchResults, extractRefSnapshotFromData, extractSessionTabTargetFromBatchResults, extractSessionTabTargetFromCommandData, isAboutBlankSessionTabTarget, normalizeSessionTabTarget, } from "../../session-page-state.js";
|
|
16
17
|
import { isRecord } from "../../parsing.js";
|
|
17
18
|
import { pruneOwnedManagedSessionRestoreSnapshots } from "../../managed-session-restore.js";
|
|
18
19
|
import { isManagedSessionRestoreKey } from "../../managed-session-storage.js";
|
|
19
|
-
import { createFreshSessionName,
|
|
20
|
+
import { createFreshSessionName, extractUpstreamCommandTokens, resolveManagedSessionState } from "../../runtime.js";
|
|
21
|
+
import { getUpstreamEffectiveBatchSteps } from "../batch-stdin.js";
|
|
20
22
|
import { closeManagedSession, inspectManagedSessionDaemon } from "./managed-session-daemon-policy.js";
|
|
21
23
|
import { applyOpenResultTabCorrection, buildAboutBlankRecoveryHint, buildAboutBlankWarning, buildElectronPostCommandHealthDiagnostic, buildElectronRefFreshnessDiagnostic, buildElectronSessionMismatch, buildManagedSessionOutcome, collectOpenResultTabCorrection, collectSessionTabSelection, extractNavigationSummaryFromData, extractStringResultField, findElectronLaunchRecordForSession, formatElectronPostCommandHealthText, formatElectronSessionMismatchText, getSessionContextKey, getStaleRefArgs, mergeNavigationSummaryIntoData, shouldCaptureNavigationSummary, shouldCorrectSessionTabAfterCommand, shouldInspectElectronPostCommandHealth, unwrapPinnedSessionBatchEnvelope, updateTraceOwnerState, } from "./session-state.js";
|
|
22
24
|
import { collectClickDispatchDiagnostic } from "./click-dispatch.js";
|
|
@@ -61,6 +63,35 @@ function isStreamEnableAlreadyEnabledNoop(options) {
|
|
|
61
63
|
const message = (getEnvelopeErrorString(options.envelope) ?? "").trim().replace(/[.!]+$/, "").toLowerCase();
|
|
62
64
|
return message === "streaming is already enabled for this session" || message === "streaming is already enabled" || message === "stream already enabled";
|
|
63
65
|
}
|
|
66
|
+
function isPendingWebMcpMutation(command, subcommand, data) {
|
|
67
|
+
return command === "webmcp"
|
|
68
|
+
&& ["invoke", "result"].includes(subcommand ?? "")
|
|
69
|
+
&& isRecord(data)
|
|
70
|
+
&& data.status === "pending";
|
|
71
|
+
}
|
|
72
|
+
function isWebMcpSettlementCommand(command, subcommand) {
|
|
73
|
+
return command === "webmcp" && ["result", "cancel"].includes(subcommand ?? "");
|
|
74
|
+
}
|
|
75
|
+
function batchHasPendingWebMcpMutation(data) {
|
|
76
|
+
if (!Array.isArray(data))
|
|
77
|
+
return false;
|
|
78
|
+
return data.some((row) => {
|
|
79
|
+
if (!isRecord(row) || row.success === false || !Array.isArray(row.command) || !row.command.every((token) => typeof token === "string"))
|
|
80
|
+
return false;
|
|
81
|
+
const [command, subcommand] = extractUpstreamCommandTokens(row.command);
|
|
82
|
+
return isPendingWebMcpMutation(command, subcommand, row.result);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function batchHasFailedWebMcpSettlement(data) {
|
|
86
|
+
if (!Array.isArray(data))
|
|
87
|
+
return false;
|
|
88
|
+
return data.some((row) => {
|
|
89
|
+
if (!isRecord(row) || row.success !== false || !Array.isArray(row.command) || !row.command.every((token) => typeof token === "string"))
|
|
90
|
+
return false;
|
|
91
|
+
const [command, subcommand] = extractUpstreamCommandTokens(row.command);
|
|
92
|
+
return isWebMcpSettlementCommand(command, subcommand);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
64
95
|
function batchStartedManagedBrowser(data) {
|
|
65
96
|
if (!Array.isArray(data))
|
|
66
97
|
return false;
|
|
@@ -71,6 +102,15 @@ function batchStartedManagedBrowser(data) {
|
|
|
71
102
|
return command === "connect" || command === "goto" || command === "navigate" || isOpenNavigationCommand(command);
|
|
72
103
|
});
|
|
73
104
|
}
|
|
105
|
+
function withoutNamespaceEntries(entries, namespace) {
|
|
106
|
+
return new Map([...entries].filter(([key]) => !isAgentBrowserSessionIdentityKeyInNamespace(key, namespace)));
|
|
107
|
+
}
|
|
108
|
+
function deleteNamespaceEntries(entries, namespace) {
|
|
109
|
+
for (const key of entries.keys()) {
|
|
110
|
+
if (isAgentBrowserSessionIdentityKeyInNamespace(key, namespace))
|
|
111
|
+
entries.delete(key);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
74
114
|
function setNetworkRouteState(options) {
|
|
75
115
|
if (!options.sessionName)
|
|
76
116
|
return options.routesBySession;
|
|
@@ -95,7 +135,12 @@ function applyBatchNetworkRouteState(options) {
|
|
|
95
135
|
for (const item of options.data) {
|
|
96
136
|
if (!isRecord(item) || !Array.isArray(item.command) || !item.command.every((token) => typeof token === "string"))
|
|
97
137
|
continue;
|
|
98
|
-
|
|
138
|
+
const commandTokens = extractUpstreamCommandTokens(item.command);
|
|
139
|
+
const stepSucceeded = item.success !== false;
|
|
140
|
+
if (stepSucceeded && isCloseCommand(commandTokens[0]))
|
|
141
|
+
routes = undefined;
|
|
142
|
+
else
|
|
143
|
+
routes = applyNetworkRouteRecords(routes, commandTokens, stepSucceeded);
|
|
99
144
|
}
|
|
100
145
|
return setNetworkRouteState({ routes, routesBySession: options.routesBySession, sessionName: options.sessionName });
|
|
101
146
|
}
|
|
@@ -103,7 +148,6 @@ export async function processBrowserOutput(input) {
|
|
|
103
148
|
const { ctx, cwd, electronPostCommandStatusSettleMs, implicitSessionCloseTimeoutMs, sessionPageStateUpdate, signal, state } = input;
|
|
104
149
|
const { prepared, processResult } = input;
|
|
105
150
|
const { electronChildProcesses, electronLaunchRecords, sessionPageState, traceOwners } = state;
|
|
106
|
-
let allowedDomainsBySession = state.allowedDomainsBySession;
|
|
107
151
|
let artifactManifest = state.artifactManifest;
|
|
108
152
|
let freshSessionOrdinal = state.freshSessionOrdinal;
|
|
109
153
|
let managedSessionActive = state.managedSessionActive;
|
|
@@ -120,6 +164,7 @@ export async function processBrowserOutput(input) {
|
|
|
120
164
|
let parseError = parsed.parseError;
|
|
121
165
|
let presentationEnvelope = parsed.envelope;
|
|
122
166
|
let navigationSummary = undefined;
|
|
167
|
+
let failedTransitionReverification = false;
|
|
123
168
|
if (prepared.pinnedBatchUnwrapMode) {
|
|
124
169
|
const pinnedBatchResult = unwrapPinnedSessionBatchEnvelope({ envelope: parsed.envelope, includeNavigationSummary: prepared.includePinnedNavigationSummary, mode: prepared.pinnedBatchUnwrapMode });
|
|
125
170
|
parseError = pinnedBatchResult.parseError ?? parseError;
|
|
@@ -132,11 +177,22 @@ export async function processBrowserOutput(input) {
|
|
|
132
177
|
presentationEnvelope = repairedBatchScreenshots.envelope;
|
|
133
178
|
const screenshotArtifactRequest = repairedScreenshot.request;
|
|
134
179
|
const batchScreenshotArtifactRequests = repairedBatchScreenshots.requests;
|
|
180
|
+
const batchCommandSteps = prepared.executionPlan.commandInfo.command === "batch"
|
|
181
|
+
? getUpstreamEffectiveBatchSteps(prepared.commandTokens, prepared.runtimeToolStdin)
|
|
182
|
+
: [];
|
|
183
|
+
const nestedBatchClose = prepared.executionPlan.commandInfo.command === "batch"
|
|
184
|
+
? getSuccessfulBatchCloseLifecycle(presentationEnvelope?.data, batchCommandSteps)
|
|
185
|
+
: undefined;
|
|
186
|
+
const nestedBatchClosed = nestedBatchClose?.endsClosed === true;
|
|
187
|
+
const nestedBatchRemainsActive = nestedBatchClose?.endsClosed === false;
|
|
188
|
+
const nestedBatchClosesAll = prepared.executionPlan.commandInfo.command === "batch"
|
|
189
|
+
&& batchHasSuccessfulCloseAll(presentationEnvelope?.data, batchCommandSteps);
|
|
190
|
+
const directCloseAllRequested = isCloseAllCommand(extractUpstreamCommandTokens(prepared.commandTokens));
|
|
135
191
|
const rawCloseStatePath = isCloseCommand(prepared.executionPlan.commandInfo.command)
|
|
136
192
|
&& isRecord(presentationEnvelope?.data)
|
|
137
193
|
&& typeof presentationEnvelope.data.statePath === "string"
|
|
138
194
|
? presentationEnvelope.data.statePath
|
|
139
|
-
:
|
|
195
|
+
: nestedBatchClose?.statePath;
|
|
140
196
|
if (presentationEnvelope && prepared.exactSensitiveValues.length > 0)
|
|
141
197
|
presentationEnvelope = redactExactSensitiveValue(presentationEnvelope, prepared.exactSensitiveValues);
|
|
142
198
|
const parseFailureOutput = parseError && processResult.stdoutSpillPath
|
|
@@ -152,7 +208,41 @@ export async function processBrowserOutput(input) {
|
|
|
152
208
|
let succeeded = processSucceeded && parseSucceeded && envelopeSuccess;
|
|
153
209
|
const inspectionText = plainTextInspection ? processResult.stdout.trim() : undefined;
|
|
154
210
|
const sessionStateKey = getSessionContextKey(prepared.executionPlan.sessionName, prepared.executionPlan.namespace);
|
|
155
|
-
|
|
211
|
+
const closeAllApplied = nestedBatchClosesAll || (directCloseAllRequested && succeeded);
|
|
212
|
+
if (closeAllApplied) {
|
|
213
|
+
networkRoutesBySession = withoutNamespaceEntries(networkRoutesBySession, prepared.executionPlan.namespace);
|
|
214
|
+
deleteNamespaceEntries(state.attachedSessionKeys, prepared.executionPlan.namespace);
|
|
215
|
+
deleteNamespaceEntries(traceOwners, prepared.executionPlan.namespace);
|
|
216
|
+
sessionPageState.clearNamespace(prepared.executionPlan.namespace);
|
|
217
|
+
const retainedSessionKey = nestedBatchRemainsActive ? sessionStateKey : undefined;
|
|
218
|
+
for (const [key, owner] of state.ownedManagedSessions) {
|
|
219
|
+
if (!isAgentBrowserSessionIdentityKeyInNamespace(key, prepared.executionPlan.namespace) || key === retainedSessionKey)
|
|
220
|
+
continue;
|
|
221
|
+
state.closedManagedSessionNames.add(key);
|
|
222
|
+
state.managedSessionRestoreState.clear(owner.sessionName, owner.namespace);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else if (nestedBatchClose && sessionStateKey) {
|
|
226
|
+
networkRoutesBySession = new Map(networkRoutesBySession);
|
|
227
|
+
networkRoutesBySession.delete(sessionStateKey);
|
|
228
|
+
sessionPageState.clearSession(sessionStateKey);
|
|
229
|
+
}
|
|
230
|
+
if (prepared.executionPlan.commandInfo.command === "batch" && Array.isArray(presentationEnvelope?.data)) {
|
|
231
|
+
for (const [index, row] of presentationEnvelope.data.entries()) {
|
|
232
|
+
if (!isRecord(row))
|
|
233
|
+
continue;
|
|
234
|
+
const rowCommand = Array.isArray(row.command) && row.command.every((token) => typeof token === "string")
|
|
235
|
+
? row.command
|
|
236
|
+
: batchCommandSteps[index];
|
|
237
|
+
if (!rowCommand)
|
|
238
|
+
continue;
|
|
239
|
+
const [command, subcommand] = extractUpstreamCommandTokens(rowCommand);
|
|
240
|
+
updateTraceOwnerState({ command, sessionName: sessionStateKey, subcommand, succeeded: row.success === true, traceOwners });
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
updateTraceOwnerState({ command: prepared.executionPlan.commandInfo.command, sessionName: sessionStateKey, subcommand: prepared.executionPlan.commandInfo.subcommand, succeeded, traceOwners });
|
|
245
|
+
}
|
|
156
246
|
let clickDispatchDiagnostic;
|
|
157
247
|
if (succeeded && prepared.clickDispatchProbe) {
|
|
158
248
|
clickDispatchDiagnostic = await collectClickDispatchDiagnostic({ cwd, namespace: prepared.executionPlan.namespace, probe: prepared.clickDispatchProbe, sessionName: prepared.executionPlan.sessionName, signal });
|
|
@@ -161,29 +251,38 @@ export async function processBrowserOutput(input) {
|
|
|
161
251
|
presentationEnvelope = { ...(presentationEnvelope ?? {}), error: clickDispatchDiagnostic.summary, success: false };
|
|
162
252
|
}
|
|
163
253
|
}
|
|
164
|
-
const
|
|
254
|
+
const tabTransition = prepared.executionPlan.commandInfo.command === "tab" && prepared.executionPlan.commandInfo.subcommand !== undefined && !["list", "new"].includes(prepared.executionPlan.commandInfo.subcommand);
|
|
255
|
+
const resultingPageState = getResultingPageTargetState({
|
|
165
256
|
args: prepared.executionPlan.effectiveArgs,
|
|
166
257
|
currentPageUrl: prepared.priorSessionTabTarget?.url,
|
|
167
258
|
pageUrlUnknown: prepared.priorSessionTabTargetUnknown === true,
|
|
168
259
|
stdin: prepared.runtimeToolStdin,
|
|
169
260
|
trustedFirstBatchTabSelection: prepared.pinnedBatchUnwrapMode !== undefined,
|
|
170
261
|
});
|
|
171
|
-
const presentationDataRecord = isRecord(presentationEnvelope?.data) ? presentationEnvelope.data : undefined;
|
|
172
|
-
const dataClicked = typeof presentationDataRecord?.clicked === "string" ? presentationDataRecord.clicked : undefined;
|
|
173
|
-
const cssClickWithoutHref = prepared.executionPlan.commandInfo.command === "click" && dataClicked !== undefined && !dataClicked.startsWith("@") && !dataClicked.startsWith("ref=") && typeof presentationDataRecord?.href !== "string";
|
|
174
|
-
const parsedAllowedDomainsPolicy = parseAllowedDomainsPolicyFromArgs(prepared.runtimeToolArgs);
|
|
175
|
-
const sessionAllowedDomainsPolicy = sessionStateKey
|
|
176
|
-
? parsedAllowedDomainsPolicy ?? allowedDomainsBySession.get(sessionStateKey)
|
|
177
|
-
: parsedAllowedDomainsPolicy;
|
|
178
|
-
const shouldCaptureAllowedDomainNavigationSummary = sessionAllowedDomainsPolicy !== undefined && !cssClickWithoutHref && (prepared.executionPlan.commandInfo.command === "batch" || isNavigationObservableCommandName(prepared.executionPlan.commandInfo.command));
|
|
179
262
|
if (succeeded &&
|
|
180
263
|
!navigationSummary &&
|
|
181
|
-
(shouldCaptureNavigationSummary(prepared.executionPlan.commandInfo.command, presentationEnvelope?.data) ||
|
|
264
|
+
(shouldCaptureNavigationSummary(prepared.executionPlan.commandInfo.command, presentationEnvelope?.data, prepared.executionPlan.commandInfo.subcommand) ||
|
|
182
265
|
shouldCaptureSemanticActionNavigationSummary(prepared.compiledSemanticAction, presentationEnvelope?.data) ||
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
266
|
+
commandRequiresLivePageVerification(prepared.executionPlan.effectiveArgs, prepared.runtimeToolStdin) ||
|
|
267
|
+
tabTransition)) {
|
|
268
|
+
navigationSummary = await collectNavigationSummary({ cwd, namespace: prepared.executionPlan.namespace, priorTarget: prepared.priorSessionTabTarget, reusePriorTitle: !tabTransition, sessionName: prepared.executionPlan.sessionName, signal });
|
|
269
|
+
}
|
|
270
|
+
// A failed eval/back/forward/reload/state-load/tab would otherwise drop the page to unverified and force the
|
|
271
|
+
// agent through a manual get url round trip. Probe the live URL ourselves instead: an observed page
|
|
272
|
+
// stays verified, and a failed
|
|
273
|
+
// probe preserves the existing unknown-target behavior.
|
|
274
|
+
if (succeeded === false &&
|
|
275
|
+
!navigationSummary &&
|
|
276
|
+
processResult.agentBrowserStarted &&
|
|
277
|
+
!processResult.aborted &&
|
|
278
|
+
!processResult.timedOut &&
|
|
279
|
+
prepared.executionPlan.commandInfo.command !== "batch" &&
|
|
280
|
+
isUnverifiedPageTransitionCommand(prepared.executionPlan.commandInfo.command, prepared.executionPlan.commandInfo.subcommand)) {
|
|
281
|
+
navigationSummary = await collectNavigationSummary({ cwd, namespace: prepared.executionPlan.namespace, priorTarget: prepared.priorSessionTabTarget, sessionName: prepared.executionPlan.sessionName, signal });
|
|
282
|
+
// A failed transition command can still have mutated or replaced the document before throwing, so
|
|
283
|
+
// keeping the verified URL must not keep the prior snapshot refs (markTabTargetUnknown dropped
|
|
284
|
+
// them before this probe existed); invalidate so the next ref use requires a fresh snapshot.
|
|
285
|
+
failedTransitionReverification = navigationSummary !== undefined;
|
|
187
286
|
}
|
|
188
287
|
if (navigationSummary && presentationEnvelope && prepared.executionPlan.commandInfo.command !== "eval" && !Array.isArray(presentationEnvelope.data))
|
|
189
288
|
presentationEnvelope = { ...presentationEnvelope, data: mergeNavigationSummaryIntoData(presentationEnvelope.data, navigationSummary) };
|
|
@@ -198,24 +297,28 @@ export async function processBrowserOutput(input) {
|
|
|
198
297
|
}
|
|
199
298
|
const verifiesCurrentUrl = prepared.executionPlan.commandInfo.command === "get" && prepared.executionPlan.commandInfo.subcommand === "url";
|
|
200
299
|
const trustsReportedPageTarget = !resultingPageState.pageUrlUnknown || verifiesCurrentUrl;
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
300
|
+
const pendingWebMcpMutation = isPendingWebMcpMutation(prepared.executionPlan.commandInfo.command, prepared.executionPlan.commandInfo.subcommand, presentationEnvelope?.data) || (prepared.executionPlan.commandInfo.command === "batch" && batchHasPendingWebMcpMutation(presentationEnvelope?.data));
|
|
301
|
+
const failedWebMcpSettlement = prepared.priorSessionTabTargetUnknown === true && ((!succeeded && isWebMcpSettlementCommand(prepared.executionPlan.commandInfo.command, prepared.executionPlan.commandInfo.subcommand))
|
|
302
|
+
|| (prepared.executionPlan.commandInfo.command === "batch" && batchHasFailedWebMcpSettlement(presentationEnvelope?.data)));
|
|
303
|
+
const unsettledWebMcpMutation = pendingWebMcpMutation || failedWebMcpSettlement;
|
|
304
|
+
const observedSessionTabTarget = unsettledWebMcpMutation
|
|
305
|
+
? undefined
|
|
306
|
+
: normalizeSessionTabTarget(navigationSummary)
|
|
307
|
+
?? (trustsReportedPageTarget ? extractSessionTabTargetFromBatchResults(presentationEnvelope?.data) : undefined)
|
|
308
|
+
?? (succeeded && trustsReportedPageTarget ? extractSessionTabTargetFromCommandData(prepared.commandTokens, presentationEnvelope?.data) : undefined);
|
|
309
|
+
const safeObservedSessionTabTarget = observedSessionTabTarget;
|
|
310
|
+
let currentSessionTabTarget = safeObservedSessionTabTarget;
|
|
311
|
+
if (!currentSessionTabTarget && nestedBatchClose === undefined) {
|
|
312
|
+
currentSessionTabTarget = resultingPageState.pageTargetMayHaveChanged
|
|
313
|
+
? succeeded ? normalizeSessionTabTarget({ url: resultingPageState.currentPageUrl }) : undefined
|
|
314
|
+
: deriveSessionTabTarget({ command: prepared.executionPlan.commandInfo.command, data: presentationEnvelope?.data, navigationSummary, previousTarget: prepared.priorSessionTabTarget, subcommand: prepared.executionPlan.commandInfo.subcommand });
|
|
208
315
|
}
|
|
209
|
-
const safeObservedSessionTabTarget = observedPageValidationError ? normalizeSessionTabTarget({ url: observedSessionTabTarget?.url }) : observedSessionTabTarget;
|
|
210
|
-
let currentSessionTabTarget = safeObservedSessionTabTarget ?? (resultingPageState.pageTargetMayHaveChanged
|
|
211
|
-
? succeeded ? normalizeSessionTabTarget({ url: resultingPageState.currentPageUrl }) : undefined
|
|
212
|
-
: deriveSessionTabTarget({ command: prepared.executionPlan.commandInfo.command, data: presentationEnvelope?.data, navigationSummary, previousTarget: prepared.priorSessionTabTarget, subcommand: prepared.executionPlan.commandInfo.subcommand }));
|
|
213
316
|
let aboutBlankSessionMismatch;
|
|
214
317
|
let electronPostCommandHealth;
|
|
215
318
|
let electronRefFreshnessDiagnostic;
|
|
216
319
|
let electronSessionMismatch;
|
|
217
320
|
let electronStatusAfterCommand;
|
|
218
|
-
const shouldTreatAboutBlankAsMismatch = succeeded && prepared.priorSessionTabTarget !== undefined && !isAboutBlankSessionTabTarget(prepared.priorSessionTabTarget) && isAboutBlankSessionTabTarget(observedSessionTabTarget ?? currentSessionTabTarget) && !commandExplicitlyTargetsAboutBlank(prepared.commandTokens);
|
|
321
|
+
const shouldTreatAboutBlankAsMismatch = succeeded && !tabTransition && nestedBatchClose === undefined && prepared.priorSessionTabTarget !== undefined && !isAboutBlankSessionTabTarget(prepared.priorSessionTabTarget) && isAboutBlankSessionTabTarget(observedSessionTabTarget ?? currentSessionTabTarget) && !commandExplicitlyTargetsAboutBlank(prepared.commandTokens);
|
|
219
322
|
let sessionTabCorrection = prepared.sessionTabCorrection;
|
|
220
323
|
if (shouldTreatAboutBlankAsMismatch && prepared.priorSessionTabTarget) {
|
|
221
324
|
const aboutBlankObservedTarget = observedSessionTabTarget ?? currentSessionTabTarget;
|
|
@@ -228,7 +331,7 @@ export async function processBrowserOutput(input) {
|
|
|
228
331
|
else
|
|
229
332
|
currentSessionTabTarget = aboutBlankObservedTarget ?? normalizeSessionTabTarget({ url: "about:blank" });
|
|
230
333
|
aboutBlankSessionMismatch = { activeUrl: "about:blank", recoveryApplied: appliedAboutBlankRecovery !== undefined, recoveryHint: buildAboutBlankRecoveryHint(), targetTitle: prepared.priorSessionTabTarget.title, targetUrl: prepared.priorSessionTabTarget.url };
|
|
231
|
-
const electronRecord = findElectronLaunchRecordForSession(prepared.executionPlan.sessionName, electronLaunchRecords);
|
|
334
|
+
const electronRecord = findElectronLaunchRecordForSession(prepared.executionPlan.sessionName, electronLaunchRecords, prepared.executionPlan.namespace);
|
|
232
335
|
if (electronRecord && prepared.executionPlan.sessionName) {
|
|
233
336
|
electronStatusAfterCommand = await inspectElectronLaunchStatus(electronRecord);
|
|
234
337
|
electronSessionMismatch = buildElectronSessionMismatch({ managedSession: { sessionName: prepared.executionPlan.sessionName, title: aboutBlankObservedTarget?.title, url: aboutBlankObservedTarget?.url ?? "about:blank" }, record: electronRecord, statusTargets: electronStatusAfterCommand.targets });
|
|
@@ -242,19 +345,7 @@ export async function processBrowserOutput(input) {
|
|
|
242
345
|
sessionTabCorrection = appliedPostCommandCorrection;
|
|
243
346
|
}
|
|
244
347
|
}
|
|
245
|
-
|
|
246
|
-
allowedDomainsBySession = new Map(allowedDomainsBySession);
|
|
247
|
-
allowedDomainsBySession.set(sessionStateKey, parsedAllowedDomainsPolicy);
|
|
248
|
-
}
|
|
249
|
-
const allowedDomainsViolation = succeeded ? getAllowedDomainsViolation({
|
|
250
|
-
policy: sessionAllowedDomainsPolicy,
|
|
251
|
-
url: currentSessionTabTarget?.url ?? observedSessionTabTarget?.url ?? navigationSummary?.url,
|
|
252
|
-
}) : undefined;
|
|
253
|
-
if (allowedDomainsViolation) {
|
|
254
|
-
succeeded = false;
|
|
255
|
-
presentationEnvelope = { ...(presentationEnvelope ?? {}), error: allowedDomainsViolation.summary, success: false };
|
|
256
|
-
}
|
|
257
|
-
const electronRecordForCommand = findElectronLaunchRecordForSession(prepared.executionPlan.sessionName, electronLaunchRecords);
|
|
348
|
+
const electronRecordForCommand = findElectronLaunchRecordForSession(prepared.executionPlan.sessionName, electronLaunchRecords, prepared.executionPlan.namespace);
|
|
258
349
|
if (succeeded && electronRecordForCommand && shouldInspectElectronPostCommandHealth(prepared.executionPlan.commandInfo.command)) {
|
|
259
350
|
electronStatusAfterCommand ??= await inspectElectronLaunchStatus(electronRecordForCommand);
|
|
260
351
|
electronPostCommandHealth = buildElectronPostCommandHealthDiagnostic({ command: prepared.executionPlan.commandInfo.command, record: electronRecordForCommand, status: electronStatusAfterCommand, target: observedSessionTabTarget ?? currentSessionTabTarget });
|
|
@@ -288,7 +379,7 @@ export async function processBrowserOutput(input) {
|
|
|
288
379
|
if (succeeded) {
|
|
289
380
|
selectorTextVisibilityDiagnostics = await collectSelectorTextVisibilityDiagnostics({ commandInfo: prepared.executionPlan.commandInfo, commandTokens: prepared.commandTokens, cwd, data: presentationEnvelope?.data, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal });
|
|
290
381
|
if (electronRecordForCommand)
|
|
291
|
-
electronBroadGetTextScopeDiagnostics = collectElectronBroadGetTextScopeDiagnostics({ commandInfo: prepared.executionPlan.commandInfo, commandTokens: prepared.commandTokens, currentTarget: currentSessionTabTarget, data: presentationEnvelope?.data, electronLaunchRecords, priorTarget: prepared.priorSessionTabTarget, sessionName: prepared.executionPlan.sessionName });
|
|
382
|
+
electronBroadGetTextScopeDiagnostics = collectElectronBroadGetTextScopeDiagnostics({ commandInfo: prepared.executionPlan.commandInfo, commandTokens: prepared.commandTokens, currentTarget: currentSessionTabTarget, data: presentationEnvelope?.data, electronLaunchRecords, namespace: prepared.executionPlan.namespace, priorTarget: prepared.priorSessionTabTarget, sessionName: prepared.executionPlan.sessionName });
|
|
292
383
|
}
|
|
293
384
|
const activeNetworkRoutes = sessionStateKey ? networkRoutesBySession.get(sessionStateKey) : undefined;
|
|
294
385
|
const networkRouteDiagnostics = succeeded && prepared.executionPlan.commandInfo.command === "network" && prepared.executionPlan.commandInfo.subcommand === "requests" && prepared.executionPlan.sessionName
|
|
@@ -298,36 +389,65 @@ export async function processBrowserOutput(input) {
|
|
|
298
389
|
const comboboxFocusDiagnostic = succeeded ? await collectComboboxFocusDiagnostic({ command: prepared.executionPlan.commandInfo.command, commandTokens: prepared.commandTokens, cwd, namespace: prepared.executionPlan.namespace, semanticAction: prepared.compiledSemanticAction, sessionName: prepared.executionPlan.sessionName, signal }) : undefined;
|
|
299
390
|
const recordingDependencyWarning = await collectRecordingDependencyWarning({ command: prepared.executionPlan.commandInfo.command, commandTokens: prepared.commandTokens, succeeded });
|
|
300
391
|
const scrollNoopDiagnostic = succeeded && prepared.shouldProbeScrollNoop ? buildScrollNoopDiagnostic(prepared.scrollPositionBefore, await collectScrollPositionSnapshot({ cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal })) : undefined;
|
|
392
|
+
const batchRefSnapshotState = prepared.executionPlan.commandInfo.command === "batch" ? extractLatestRefSnapshotStateFromBatchResults(presentationEnvelope?.data) : undefined;
|
|
301
393
|
let currentRefSnapshot;
|
|
302
394
|
let currentRefSnapshotInvalidation;
|
|
303
|
-
const batchRefSnapshotState = prepared.executionPlan.commandInfo.command === "batch" ? extractLatestRefSnapshotStateFromBatchResults(presentationEnvelope?.data) : undefined;
|
|
304
395
|
if (sessionStateKey) {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
396
|
+
const sessionClosed = (isCloseCommand(prepared.executionPlan.commandInfo.command) && succeeded) || nestedBatchClosed;
|
|
397
|
+
if (sessionClosed) {
|
|
398
|
+
state.attachedSessionKeys.delete(sessionStateKey);
|
|
308
399
|
networkRoutesBySession = new Map(networkRoutesBySession);
|
|
309
400
|
networkRoutesBySession.delete(sessionStateKey);
|
|
310
401
|
sessionPageState.clearSession(sessionStateKey);
|
|
311
402
|
state.closedManagedSessionNames.add(sessionStateKey);
|
|
312
403
|
}
|
|
313
|
-
else if (currentSessionTabTarget) {
|
|
314
|
-
const tabUpdate = sessionPageState.applyTabTarget({ sessionName: sessionStateKey, target: currentSessionTabTarget, update: sessionPageStateUpdate });
|
|
315
|
-
if (!tabUpdate.applied && succeeded)
|
|
316
|
-
sessionPageState.markPinning(sessionStateKey, "drift");
|
|
317
|
-
}
|
|
318
|
-
else if (processResult.agentBrowserStarted && (resultingPageState.pageUrlUnknown || resultingPageState.pageTargetMayHaveChanged)) {
|
|
319
|
-
sessionPageState.markTabTargetUnknown({ sessionName: sessionStateKey, update: sessionPageStateUpdate });
|
|
320
|
-
}
|
|
321
|
-
const refSnapshot = prepared.executionPlan.commandInfo.command === "batch" ? batchRefSnapshotState?.snapshot : succeeded ? prepared.executionPlan.commandInfo.command === "snapshot" ? extractRefSnapshotFromData(presentationEnvelope?.data) : prepared.resolvedSemanticActionRefSnapshot ?? overlayBlockerDiagnostic?.snapshot : undefined;
|
|
322
|
-
if (refSnapshot) {
|
|
323
|
-
const refUpdate = sessionPageState.applyRefSnapshot({ fallbackTarget: currentSessionTabTarget, sessionName: sessionStateKey, snapshot: refSnapshot, update: sessionPageStateUpdate });
|
|
324
|
-
currentRefSnapshot = refUpdate.refSnapshot;
|
|
325
|
-
currentRefSnapshotInvalidation = refUpdate.refSnapshotInvalidation;
|
|
326
|
-
}
|
|
327
404
|
else {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
405
|
+
// A batch that times out or returns unparseable output yields no result rows, but the daemon
|
|
406
|
+
// may already have executed a recording swap or page-provided WebMCP tool; fall back to the
|
|
407
|
+
// planned steps then. This can over-invalidate by one snapshot, but never under-invalidates.
|
|
408
|
+
const directTransitionInvalidation = getCommandRefSnapshotInvalidation(prepared.commandTokens);
|
|
409
|
+
const plannedBatchTransitionInvalidation = !Array.isArray(presentationEnvelope?.data)
|
|
410
|
+
? batchCommandSteps.map(getCommandRefSnapshotInvalidation).find((invalidation) => invalidation !== undefined)
|
|
411
|
+
: undefined;
|
|
412
|
+
const pageTransitionInvalidation = unsettledWebMcpMutation
|
|
413
|
+
? buildPageTransitionRefSnapshotInvalidation("A detached WebMCP invocation is still pending or failed to settle and can mutate, rerender, or navigate the page, so prior snapshot refs remain invalid after URL verification. Run webmcp result or cancel, then take a fresh snapshot before using page-scoped refs.")
|
|
414
|
+
: processResult.agentBrowserStarted && (directTransitionInvalidation || plannedBatchTransitionInvalidation)
|
|
415
|
+
? directTransitionInvalidation ?? plannedBatchTransitionInvalidation
|
|
416
|
+
: failedTransitionReverification
|
|
417
|
+
? buildPageTransitionRefSnapshotInvalidation("A failed eval/back/forward/reload/connect/state-load/tab command may still have changed the page, so the prior snapshot refs were invalidated. Run snapshot -i before using page-scoped refs.")
|
|
418
|
+
: batchRefSnapshotState?.invalidation?.reason === "page-transition"
|
|
419
|
+
? batchRefSnapshotState.invalidation
|
|
420
|
+
: undefined;
|
|
421
|
+
if (currentSessionTabTarget) {
|
|
422
|
+
const tabUpdate = sessionPageState.applyTabTarget({ sessionName: sessionStateKey, target: currentSessionTabTarget, update: sessionPageStateUpdate });
|
|
423
|
+
if (!tabUpdate.applied && succeeded)
|
|
424
|
+
sessionPageState.markPinning(sessionStateKey, "drift");
|
|
425
|
+
}
|
|
426
|
+
else if (processResult.agentBrowserStarted && (resultingPageState.pageUrlUnknown || resultingPageState.pageTargetMayHaveChanged)) {
|
|
427
|
+
sessionPageState.markTabTargetUnknown({ sessionName: sessionStateKey, update: sessionPageStateUpdate });
|
|
428
|
+
}
|
|
429
|
+
const refSnapshot = unsettledWebMcpMutation
|
|
430
|
+
? undefined
|
|
431
|
+
: prepared.executionPlan.commandInfo.command === "batch"
|
|
432
|
+
? batchRefSnapshotState?.snapshot
|
|
433
|
+
: succeeded
|
|
434
|
+
? prepared.executionPlan.commandInfo.command === "snapshot" ? extractRefSnapshotFromData(presentationEnvelope?.data) : prepared.resolvedSemanticActionRefSnapshot ?? overlayBlockerDiagnostic?.snapshot
|
|
435
|
+
: undefined;
|
|
436
|
+
if (refSnapshot) {
|
|
437
|
+
const refUpdate = sessionPageState.applyRefSnapshot({ fallbackTarget: currentSessionTabTarget, sessionName: sessionStateKey, snapshot: refSnapshot, update: sessionPageStateUpdate });
|
|
438
|
+
currentRefSnapshot = refUpdate.refSnapshot;
|
|
439
|
+
currentRefSnapshotInvalidation = refUpdate.refSnapshotInvalidation;
|
|
440
|
+
}
|
|
441
|
+
else if (pageTransitionInvalidation) {
|
|
442
|
+
const refUpdate = sessionPageState.applyRefSnapshotInvalidation({ invalidation: pageTransitionInvalidation, sessionName: sessionStateKey, update: sessionPageStateUpdate });
|
|
443
|
+
currentRefSnapshot = refUpdate.refSnapshot;
|
|
444
|
+
currentRefSnapshotInvalidation = refUpdate.refSnapshotInvalidation;
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
const stateView = sessionPageState.get(sessionStateKey);
|
|
448
|
+
currentRefSnapshot = stateView.refSnapshot;
|
|
449
|
+
currentRefSnapshotInvalidation = stateView.refSnapshotInvalidation;
|
|
450
|
+
}
|
|
331
451
|
}
|
|
332
452
|
}
|
|
333
453
|
const priorManagedSessionActive = managedSessionActive;
|
|
@@ -335,12 +455,22 @@ export async function processBrowserOutput(input) {
|
|
|
335
455
|
const priorManagedSessionHeadedAutosaveInterval = managedSessionHeadedAutosaveInterval;
|
|
336
456
|
const priorManagedSessionName = managedSessionName;
|
|
337
457
|
const priorManagedSessionNamespace = managedSessionNamespace;
|
|
338
|
-
const
|
|
458
|
+
const priorManagedSessionKey = getSessionContextKey(priorManagedSessionName, priorManagedSessionNamespace) ?? priorManagedSessionName;
|
|
459
|
+
const closeAllTargetsPriorManagedSession = closeAllApplied
|
|
460
|
+
&& priorManagedSessionActive
|
|
461
|
+
&& isAgentBrowserSessionIdentityKeyInNamespace(priorManagedSessionKey, prepared.executionPlan.namespace);
|
|
462
|
+
const closeAllRetainsPriorManagedSession = closeAllTargetsPriorManagedSession
|
|
463
|
+
&& nestedBatchRemainsActive
|
|
464
|
+
&& sessionStateKey === priorManagedSessionKey;
|
|
465
|
+
const closeAllClosesPriorManagedSession = closeAllTargetsPriorManagedSession && !closeAllRetainsPriorManagedSession;
|
|
466
|
+
const commandClosesSession = isCloseCommand(prepared.executionPlan.commandInfo.command) || nestedBatchClosed || closeAllClosesPriorManagedSession;
|
|
467
|
+
const closeCommandSucceeded = (isCloseCommand(prepared.executionPlan.commandInfo.command) && succeeded) || nestedBatchClosed || closeAllClosesPriorManagedSession;
|
|
339
468
|
const closeTargetsPriorManagedNamespace = prepared.executionPlan.namespace === priorManagedSessionNamespace;
|
|
340
|
-
const managedCloseSessionName =
|
|
341
|
-
?
|
|
342
|
-
: prepared.executionPlan.
|
|
343
|
-
|
|
469
|
+
const managedCloseSessionName = closeAllClosesPriorManagedSession
|
|
470
|
+
? priorManagedSessionName
|
|
471
|
+
: closeCommandSucceeded && prepared.executionPlan.sessionName === priorManagedSessionName && closeTargetsPriorManagedNamespace
|
|
472
|
+
? prepared.executionPlan.sessionName
|
|
473
|
+
: prepared.executionPlan.managedSessionName;
|
|
344
474
|
const postLaunchBatchFailure = !succeeded && processSucceeded && parseSucceeded && prepared.sessionMode === "fresh" && prepared.executionPlan.commandInfo.command === "batch" && batchStartedManagedBrowser(presentationEnvelope?.data);
|
|
345
475
|
const postLaunchTimeoutWithPage = !succeeded && processResult.timedOut && prepared.sessionMode === "fresh" && prepared.executionPlan.commandInfo.command === "batch" && timeoutPartialProgress?.liveUrlRecovered === true;
|
|
346
476
|
const failedFreshSessionMayHaveStarted = !succeeded
|
|
@@ -361,8 +491,8 @@ export async function processBrowserOutput(input) {
|
|
|
361
491
|
}
|
|
362
492
|
// Only a confirmed inactive daemon proves that a started fresh command did not establish browser ownership.
|
|
363
493
|
const postLaunchFreshFailure = failedFreshDaemon !== undefined && failedFreshDaemon.status !== "inactive";
|
|
364
|
-
const managedTransitionSucceeded = succeeded ||
|
|
365
|
-
const managedSessionState = resolveManagedSessionState({ command: prepared.executionPlan.commandInfo.command, managedSessionName: managedCloseSessionName, managedSessionNamespace: prepared.executionPlan.namespace, priorActive: priorManagedSessionActive, priorNamespace: priorManagedSessionNamespace, priorSessionName: priorManagedSessionName, succeeded: managedTransitionSucceeded });
|
|
494
|
+
const managedTransitionSucceeded = succeeded || nestedBatchClosed || nestedBatchRemainsActive || postLaunchBatchFailure || postLaunchTimeoutWithPage || postLaunchFreshFailure;
|
|
495
|
+
const managedSessionState = resolveManagedSessionState({ command: commandClosesSession ? "close" : prepared.executionPlan.commandInfo.command, managedSessionName: managedCloseSessionName, managedSessionNamespace: prepared.executionPlan.namespace, priorActive: priorManagedSessionActive, priorNamespace: priorManagedSessionNamespace, priorSessionName: priorManagedSessionName, succeeded: managedTransitionSucceeded });
|
|
366
496
|
if (!managedTransitionSucceeded && prepared.sessionMode === "fresh" && prepared.executionPlan.managedSessionName) {
|
|
367
497
|
state.managedSessionRestoreState.clear(prepared.executionPlan.managedSessionName, prepared.executionPlan.namespace);
|
|
368
498
|
}
|
|
@@ -383,7 +513,7 @@ export async function processBrowserOutput(input) {
|
|
|
383
513
|
managedSessionHeadedAutosaveDisabled = prepared.ownedManagedSessionContext?.headedManagedAutosaveDisabled === true;
|
|
384
514
|
managedSessionHeadedAutosaveInterval = prepared.ownedManagedSessionContext?.headedManagedAutosaveInterval;
|
|
385
515
|
}
|
|
386
|
-
if (
|
|
516
|
+
if (closeCommandSucceeded && managedCloseSessionName === priorManagedSessionName && !managedSessionActive) {
|
|
387
517
|
const daemonRestoreKey = state.managedSessionRestoreState.getDaemonRestoreKey(managedCloseSessionName, priorManagedSessionNamespace);
|
|
388
518
|
const ownedRestoreKey = !state.managedSessionRestoreState.isDisabled(managedCloseSessionName, priorManagedSessionNamespace)
|
|
389
519
|
&& isManagedSessionRestoreKey(daemonRestoreKey) ? daemonRestoreKey : null;
|
|
@@ -398,7 +528,7 @@ export async function processBrowserOutput(input) {
|
|
|
398
528
|
managedSessionName = createFreshSessionName(state.managedSessionBaseName, state.ephemeralSessionSeed, freshSessionOrdinal);
|
|
399
529
|
managedSessionNamespace = undefined;
|
|
400
530
|
}
|
|
401
|
-
let managedSessionOutcome = buildManagedSessionOutcome({ activeAfter: managedSessionActive, activeBefore: priorManagedSessionActive, attemptedSessionName: managedCloseSessionName, command: prepared.executionPlan.commandInfo.command, currentSessionName: managedSessionName, currentSessionNamespace: managedSessionNamespace, previousSessionName: priorManagedSessionName, replacedSessionName: replacedManagedSessionName, replacedSessionNamespace: priorManagedSessionNamespace, sessionMode: prepared.sessionMode, succeeded: managedTransitionSucceeded });
|
|
531
|
+
let managedSessionOutcome = buildManagedSessionOutcome({ activeAfter: managedSessionActive, activeBefore: priorManagedSessionActive, attemptedSessionName: managedCloseSessionName, command: commandClosesSession ? "close" : prepared.executionPlan.commandInfo.command, currentSessionName: managedSessionName, currentSessionNamespace: managedSessionNamespace, previousSessionName: priorManagedSessionName, replacedSessionName: replacedManagedSessionName, replacedSessionNamespace: priorManagedSessionNamespace, sessionMode: prepared.sessionMode, succeeded: managedTransitionSucceeded });
|
|
402
532
|
if (prepared.executionPlan.managedSessionName && managedTransitionSucceeded && managedSessionActive) {
|
|
403
533
|
managedSessionCwd = cwd;
|
|
404
534
|
managedSessionNamespace = prepared.executionPlan.namespace;
|
|
@@ -410,9 +540,7 @@ export async function processBrowserOutput(input) {
|
|
|
410
540
|
sessionPageState.clearRestorePinning(sessionStateKey);
|
|
411
541
|
}
|
|
412
542
|
if (replacedManagedSessionName) {
|
|
413
|
-
allowedDomainsBySession = new Map(allowedDomainsBySession);
|
|
414
543
|
const replacedSessionStateKey = getSessionContextKey(replacedManagedSessionName, priorManagedSessionNamespace);
|
|
415
|
-
allowedDomainsBySession.delete(replacedSessionStateKey ?? replacedManagedSessionName);
|
|
416
544
|
networkRoutesBySession = new Map(networkRoutesBySession);
|
|
417
545
|
networkRoutesBySession.delete(replacedSessionStateKey ?? replacedManagedSessionName);
|
|
418
546
|
sessionPageState.clearSession(replacedSessionStateKey ?? replacedManagedSessionName);
|
|
@@ -439,7 +567,7 @@ export async function processBrowserOutput(input) {
|
|
|
439
567
|
if (succeeded && prepared.executionPlan.sessionName) {
|
|
440
568
|
const electronSessionName = prepared.executionPlan.sessionName;
|
|
441
569
|
const electronSessionStateKey = sessionStateKey ?? electronSessionName;
|
|
442
|
-
electronLaunchRecord = { ...prepared.electronLaunch.record, sessionName: electronSessionName };
|
|
570
|
+
electronLaunchRecord = { ...prepared.electronLaunch.record, namespace: prepared.executionPlan.namespace, sessionName: electronSessionName };
|
|
443
571
|
const electronHandoffMode = prepared.compiledElectron?.action === "launch" ? prepared.compiledElectron.handoff : "connect";
|
|
444
572
|
try {
|
|
445
573
|
electronHandoff = await collectElectronHandoff({ cwd, handoff: electronHandoffMode, namespace: prepared.executionPlan.namespace, sessionName: electronSessionName, signal });
|
|
@@ -467,8 +595,6 @@ export async function processBrowserOutput(input) {
|
|
|
467
595
|
}
|
|
468
596
|
if (!closeError) {
|
|
469
597
|
state.closedManagedSessionNames.add(electronSessionStateKey);
|
|
470
|
-
allowedDomainsBySession = new Map(allowedDomainsBySession);
|
|
471
|
-
allowedDomainsBySession.delete(electronSessionStateKey);
|
|
472
598
|
networkRoutesBySession = new Map(networkRoutesBySession);
|
|
473
599
|
networkRoutesBySession.delete(electronSessionStateKey);
|
|
474
600
|
sessionPageState.clearSession(electronSessionStateKey);
|
|
@@ -507,9 +633,7 @@ export async function processBrowserOutput(input) {
|
|
|
507
633
|
if (presentationEnvelope?.error !== undefined)
|
|
508
634
|
presentationEnvelope = { ...presentationEnvelope, error: redactClipboardPermissionErrorValue(prepared.executionPlan.commandInfo, presentationEnvelope.error, clipboardWritePayloadCandidates) };
|
|
509
635
|
}
|
|
510
|
-
const presentation = plainTextInspection ? { artifacts: undefined, batchFailure: undefined, batchSteps: undefined, content: [{ type: "text", text: inspectionText ?? "" }], data: undefined, fullOutputPath: undefined, fullOutputPaths: undefined, imagePath: undefined, imagePaths: undefined, savedFile: undefined, savedFilePath: undefined, summary: `${prepared.redactedArgs.join(" ")} completed` } : await buildToolPresentation({ args: prepared.redactedProcessArgs, artifactManifest, artifactRequest: screenshotArtifactRequest, batchArtifactRequests: batchScreenshotArtifactRequests, commandInfo: prepared.executionPlan.commandInfo, compiledSemanticAction: prepared.compiledSemanticAction, cwd, envelope: presentationEnvelope, errorText, namespace: prepared.executionPlan.namespace, networkRouteDiagnostics, networkRoutes: activeNetworkRoutes, persistentArtifactStore, sessionName: prepared.executionPlan.sessionName });
|
|
511
|
-
if (observedPageValidationError)
|
|
512
|
-
presentation.failureCategory = "validation-error";
|
|
636
|
+
const presentation = plainTextInspection ? { artifacts: undefined, batchFailure: undefined, batchSteps: undefined, content: [{ type: "text", text: inspectionText ?? "" }], data: undefined, fullOutputPath: undefined, fullOutputPaths: undefined, imagePath: undefined, imagePaths: undefined, savedFile: undefined, savedFilePath: undefined, summary: `${prepared.redactedArgs.join(" ")} completed` } : await buildToolPresentation({ args: prepared.redactedProcessArgs, artifactManifest, artifactMaxUpdatedAtMs: Date.now(), artifactMinUpdatedAtMs: input.artifactRunStartedAtMs, artifactRequest: screenshotArtifactRequest, batchArtifactRequests: batchScreenshotArtifactRequests, commandInfo: prepared.executionPlan.commandInfo, compiledSemanticAction: prepared.compiledSemanticAction, cwd, envelope: presentationEnvelope, errorText, namespace: prepared.executionPlan.namespace, networkRouteDiagnostics, networkRoutes: activeNetworkRoutes, persistentArtifactStore, sessionName: prepared.executionPlan.sessionName });
|
|
513
637
|
if (electronHandoff?.error && electronHandoff.failureCategory)
|
|
514
638
|
presentation.failureCategory = electronHandoff.failureCategory;
|
|
515
639
|
networkRoutesBySession = applyBatchNetworkRouteState({ data: presentationEnvelope?.data, routesBySession: networkRoutesBySession, sessionName: sessionStateKey, succeeded });
|
|
@@ -518,13 +642,20 @@ export async function processBrowserOutput(input) {
|
|
|
518
642
|
presentationEnvelope = { ...(presentationEnvelope ?? {}), error: presentation.summary, success: false };
|
|
519
643
|
}
|
|
520
644
|
if (scrollNoopDiagnostic) {
|
|
645
|
+
succeeded = false;
|
|
646
|
+
presentation.resultCategory = "failure";
|
|
647
|
+
presentation.failureCategory = "upstream-error";
|
|
648
|
+
presentationEnvelope = { ...(presentationEnvelope ?? {}), error: "Scroll completed with no observed movement.", success: false };
|
|
521
649
|
presentation.summary = "Scroll completed with no observed movement.";
|
|
522
650
|
if (isRecord(presentation.data))
|
|
523
651
|
presentation.data = { ...presentation.data, noMovement: true, scrolled: false };
|
|
524
|
-
if (presentation.content[0]?.type === "text")
|
|
525
|
-
presentation.
|
|
526
|
-
|
|
652
|
+
if (presentation.content[0]?.type === "text") {
|
|
653
|
+
const details = isRecord(presentation.data) ? JSON.stringify(omitUpstreamLifecycle(presentation.data), null, 2) : presentation.content[0].text;
|
|
654
|
+
presentation.content[0] = { ...presentation.content[0], text: `Scroll completed with no observed movement.\n\n${details}` };
|
|
655
|
+
}
|
|
656
|
+
else {
|
|
527
657
|
presentation.content.unshift({ type: "text", text: "Scroll completed with no observed movement." });
|
|
658
|
+
}
|
|
528
659
|
}
|
|
529
660
|
if (parseFailureOutput.artifactManifest) {
|
|
530
661
|
presentation.artifactManifest = parseFailureOutput.artifactManifest;
|
|
@@ -544,7 +675,7 @@ export async function processBrowserOutput(input) {
|
|
|
544
675
|
let qaAttachedTarget = prepared.compiledQaPreset?.checks.attached
|
|
545
676
|
? await collectQaAttachedTarget({ currentTarget: currentSessionTabTarget ?? prepared.priorSessionTabTarget, cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal })
|
|
546
677
|
: undefined;
|
|
547
|
-
const sourceLookupElectronContext = prepared.compiledSourceLookup ? getSourceLookupElectronContext({ currentTarget: currentSessionTabTarget, electronLaunchRecords, priorTarget: prepared.priorSessionTabTarget, sessionName: prepared.executionPlan.sessionName }) : undefined;
|
|
678
|
+
const sourceLookupElectronContext = prepared.compiledSourceLookup ? getSourceLookupElectronContext({ currentTarget: currentSessionTabTarget, electronLaunchRecords, namespace: prepared.executionPlan.namespace, priorTarget: prepared.priorSessionTabTarget, sessionName: prepared.executionPlan.sessionName }) : undefined;
|
|
548
679
|
const sourceLookup = prepared.compiledSourceLookup ? await analyzeSourceLookupResults(presentationEnvelope?.data, prepared.compiledSourceLookup, cwd, { electronContext: sourceLookupElectronContext, workspaceRoot: cwd }) : undefined;
|
|
549
680
|
const networkSourceLookup = prepared.compiledNetworkSourceLookup ? redactNetworkSourceLookupAnalysis(await analyzeNetworkSourceLookupResults(presentationEnvelope?.data, prepared.compiledNetworkSourceLookup, cwd)) : undefined;
|
|
550
681
|
if (networkSourceLookup && presentation.content[0]?.type === "text")
|
|
@@ -555,14 +686,22 @@ export async function processBrowserOutput(input) {
|
|
|
555
686
|
presentation.content[0] = { ...presentation.content[0], text: `${sourceLookup.summary}\n\n${presentation.content[0].text}` };
|
|
556
687
|
else if (sourceLookup)
|
|
557
688
|
presentation.content.unshift({ type: "text", text: sourceLookup.summary });
|
|
558
|
-
if (qaPreset && !qaPreset.passed && presentation.failureCategory !== "artifact-missing") {
|
|
689
|
+
if (qaPreset && !qaPreset.passed && prepared.compiledQaPreset && presentation.failureCategory !== "artifact-missing") {
|
|
559
690
|
succeeded = false;
|
|
560
691
|
presentation.failureCategory = "qa-failure";
|
|
561
692
|
presentation.summary = qaPreset.summary;
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
693
|
+
const compactText = buildQaCompactFailureText({
|
|
694
|
+
batchStepCount: presentation.batchSteps?.length ?? prepared.compiledQaPreset.steps.length,
|
|
695
|
+
checks: prepared.compiledQaPreset.checks,
|
|
696
|
+
page: extractQaPageContext({
|
|
697
|
+
attachedTarget: qaAttachedTarget,
|
|
698
|
+
batchData: presentationEnvelope?.data,
|
|
699
|
+
compiled: prepared.compiledQaPreset,
|
|
700
|
+
}),
|
|
701
|
+
qaPreset,
|
|
702
|
+
});
|
|
703
|
+
const nonTextContent = presentation.content.filter((item) => item.type !== "text");
|
|
704
|
+
presentation.content = [{ type: "text", text: compactText }, ...nonTextContent];
|
|
566
705
|
}
|
|
567
706
|
else if (qaPreset?.passed && prepared.compiledQaPreset && succeeded) {
|
|
568
707
|
const compactText = buildQaCompactPassText({
|
|
@@ -616,9 +755,12 @@ export async function processBrowserOutput(input) {
|
|
|
616
755
|
const resultHeadedManagedAutosaveInterval = resultRetainsPreparedManagedSession && !(commandClosesSession && succeeded)
|
|
617
756
|
? prepared.ownedManagedSessionContext?.headedManagedAutosaveInterval
|
|
618
757
|
: undefined;
|
|
619
|
-
const result = buildFinalAgentBrowserToolResult({ aboutBlankSessionMismatch, artifactCleanup, categoryDetails: finalRecoveryState.categoryDetails, clickDispatchDiagnostic, commandTokens: prepared.commandTokens, comboboxFocusDiagnostic, compiledNetworkSourceLookup: prepared.compiledNetworkSourceLookup, compiledSemanticAction: prepared.compiledSemanticAction, compatibilityWorkaround: prepared.compatibilityWorkaround, currentRefSnapshot, currentRefSnapshotInvalidation, currentSessionTabTarget, currentSessionTabTargetUnknown, electronBroadGetTextScopeDiagnostics, electronFailedConnectCleanup, electronHandoff, electronLaunch: prepared.electronLaunch, electronLaunchRecord, electronLaunchRecords, electronPostCommandHealth, electronProfileIsolationDetails: input.electronProfileIsolationDetails, electronRefFreshnessDiagnostic, electronSessionMismatch, errorText, evalResultWarning, evalStdinHint, exactSensitiveValues: prepared.exactSensitiveValues, executionPlan: prepared.executionPlan, fillVerificationDiagnostic, inspectionText, managedSessionHeadedAutosaveDisabled: resultHeadedManagedAutosaveDisabled || undefined, managedSessionHeadedAutosaveInterval: resultHeadedManagedAutosaveInterval, managedSessionOutcome, managedSessionRestoreDisabled: state.managedSessionRestoreState.isDisabled(prepared.executionPlan.sessionName, prepared.executionPlan.namespace), navigationSummary, networkSourceLookup, noActivePageSnapshotFailure: finalRecoveryState.noActivePageSnapshotFailure, openResultTabCorrection, overlayBlockerDiagnostic, parseError, parseFailureOutput, parseSucceeded, plainTextInspection, presentation, presentationEnvelope, priorSessionTabTarget: prepared.priorSessionTabTarget, processResult, qaAttachedTarget, qaPreset, recordingDependencyWarning, redactedArgs: prepared.redactedArgs, redactedCompiledElectron: prepared.redactedCompiledElectron, redactedCompiledJob: prepared.redactedCompiledJob, redactedCompiledNetworkSourceLookup: prepared.redactedCompiledNetworkSourceLookup, redactedCompiledQaPreset: prepared.redactedCompiledQaPreset, redactedCompiledSemanticAction: prepared.redactedCompiledSemanticAction, redactedCompiledSourceLookup: prepared.redactedCompiledSourceLookup, redactedContent, redactedProcessArgs: prepared.redactedProcessArgs, redactedRecoveryHint: prepared.redactedRecoveryHint, resultArtifactManifest, richInputRecoveryDiagnostic: finalRecoveryState.richInputRecoveryDiagnostic, scrollNoopDiagnostic, selectorTextVisibilityDiagnostics, sessionMode: prepared.sessionMode, sessionTabCorrection, sourceLookup, succeeded, timeoutPartialProgress, userRequestedJson: prepared.userRequestedJson, visibleRefFallbackDiagnostic: finalRecoveryState.visibleRefFallbackDiagnostic, visibleRefFallbackSessionName: finalRecoveryState.visibleRefFallbackSessionName });
|
|
620
|
-
const
|
|
621
|
-
|
|
758
|
+
const result = buildFinalAgentBrowserToolResult({ aboutBlankSessionMismatch, artifactCleanup, categoryDetails: finalRecoveryState.categoryDetails, clickDispatchDiagnostic, commandTokens: prepared.commandTokens, comboboxFocusDiagnostic, compiledNetworkSourceLookup: prepared.compiledNetworkSourceLookup, compiledSemanticAction: prepared.compiledSemanticAction, compatibilityWorkaround: prepared.compatibilityWorkaround, currentRefSnapshot, currentRefSnapshotInvalidation, currentSessionTabTarget, currentSessionTabTargetUnknown, electronBroadGetTextScopeDiagnostics, electronFailedConnectCleanup, electronHandoff, electronLaunch: prepared.electronLaunch, electronLaunchRecord, electronLaunchRecords, electronPostCommandHealth, electronProfileIsolationDetails: input.electronProfileIsolationDetails, electronRefFreshnessDiagnostic, electronSessionMismatch, errorText, evalResultWarning, evalStdinHint, exactSensitiveValues: prepared.exactSensitiveValues, executionPlan: prepared.executionPlan, fillVerificationDiagnostic, headedLaunch: prepared.headedLaunch, inspectionText, preserveAttachedBrowserSession: input.preserveAttachedBrowserSession === true, providerLaunch: prepared.providerLaunch, managedSessionHeadedAutosaveDisabled: resultHeadedManagedAutosaveDisabled || undefined, managedSessionHeadedAutosaveInterval: resultHeadedManagedAutosaveInterval, managedSessionOutcome, managedSessionRestoreDisabled: state.managedSessionRestoreState.isDisabled(prepared.executionPlan.sessionName, prepared.executionPlan.namespace), navigationSummary, networkSourceLookup, noActivePageSnapshotFailure: finalRecoveryState.noActivePageSnapshotFailure, openResultTabCorrection, overlayBlockerDiagnostic, parseError, parseFailureOutput, parseSucceeded, plainTextInspection, presentation, presentationEnvelope, priorSessionTabTarget: prepared.priorSessionTabTarget, processResult, qaAttachedTarget, qaPreset, recordingDependencyWarning, redactedArgs: prepared.redactedArgs, redactedCompiledElectron: prepared.redactedCompiledElectron, redactedCompiledJob: prepared.redactedCompiledJob, redactedCompiledNetworkSourceLookup: prepared.redactedCompiledNetworkSourceLookup, redactedCompiledQaPreset: prepared.redactedCompiledQaPreset, redactedCompiledSemanticAction: prepared.redactedCompiledSemanticAction, redactedCompiledSourceLookup: prepared.redactedCompiledSourceLookup, redactedContent, redactedProcessArgs: prepared.redactedProcessArgs, redactedRecoveryHint: prepared.redactedRecoveryHint, resultArtifactManifest, richInputRecoveryDiagnostic: finalRecoveryState.richInputRecoveryDiagnostic, scrollNoopDiagnostic, selectorTextVisibilityDiagnostics, sessionMode: prepared.sessionMode, sessionTabCorrection, sourceLookup, succeeded, timeoutPartialProgress, unsettledWebMcpMutation, userRequestedJson: prepared.userRequestedJson, visibleRefFallbackDiagnostic: finalRecoveryState.visibleRefFallbackDiagnostic, visibleRefFallbackSessionName: finalRecoveryState.visibleRefFallbackSessionName });
|
|
759
|
+
const resultWithCloseAll = closeAllApplied
|
|
760
|
+
? { ...result, details: { ...(isRecord(result.details) ? result.details : {}), closeAllApplied: true } }
|
|
761
|
+
: result;
|
|
762
|
+
const statePatch = { artifactManifest, freshSessionOrdinal, managedSessionActive, managedSessionCompatibilityWorkaround, managedSessionHeadedAutosaveDisabled, managedSessionHeadedAutosaveInterval, managedSessionCwd, managedSessionName, managedSessionNamespace, networkRoutesBySession };
|
|
763
|
+
return { result: resultWithCloseAll, statePatch };
|
|
622
764
|
}
|
|
623
765
|
finally {
|
|
624
766
|
if (processResult.stdoutSpillPath)
|