pi-agent-browser-native 0.2.31 → 0.2.33
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 +35 -0
- package/README.md +64 -18
- package/docs/ARCHITECTURE.md +13 -10
- package/docs/COMMAND_REFERENCE.md +71 -16
- package/docs/ELECTRON.md +387 -0
- package/docs/RELEASE.md +34 -4
- package/docs/REQUIREMENTS.md +5 -3
- package/docs/SUPPORT_MATRIX.md +36 -21
- package/docs/TOOL_CONTRACT.md +198 -40
- package/extensions/agent-browser/index.ts +1585 -3486
- package/extensions/agent-browser/lib/electron/cleanup.ts +287 -0
- package/extensions/agent-browser/lib/electron/discovery.ts +717 -0
- package/extensions/agent-browser/lib/electron/launch.ts +553 -0
- package/extensions/agent-browser/lib/input-modes/electron.ts +170 -0
- package/extensions/agent-browser/lib/input-modes/job.ts +203 -0
- package/extensions/agent-browser/lib/input-modes/lookups.ts +447 -0
- package/extensions/agent-browser/lib/input-modes/params.ts +188 -0
- package/extensions/agent-browser/lib/input-modes/semantic-action.ts +107 -0
- package/extensions/agent-browser/lib/input-modes/shared.ts +46 -0
- package/extensions/agent-browser/lib/input-modes/types.ts +221 -0
- package/extensions/agent-browser/lib/input-modes.ts +41 -0
- package/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.ts +696 -0
- package/extensions/agent-browser/lib/orchestration/browser-run/final-result.ts +450 -0
- package/extensions/agent-browser/lib/orchestration/browser-run/index.ts +46 -0
- package/extensions/agent-browser/lib/orchestration/browser-run/prepare.ts +711 -0
- package/extensions/agent-browser/lib/orchestration/browser-run/process-output.ts +386 -0
- package/extensions/agent-browser/lib/orchestration/browser-run/session-state.ts +868 -0
- package/extensions/agent-browser/lib/orchestration/browser-run/types.ts +476 -0
- package/extensions/agent-browser/lib/orchestration/browser-run.ts +1 -0
- package/extensions/agent-browser/lib/orchestration/input-plan.ts +338 -0
- package/extensions/agent-browser/lib/playbook.ts +15 -13
- package/extensions/agent-browser/lib/process.ts +106 -4
- package/extensions/agent-browser/lib/results/action-recommendations.ts +269 -0
- package/extensions/agent-browser/lib/results/artifact-manifest.ts +114 -0
- package/extensions/agent-browser/lib/results/artifact-state.ts +13 -0
- package/extensions/agent-browser/lib/results/categories.ts +106 -0
- package/extensions/agent-browser/lib/results/contracts.ts +220 -0
- package/extensions/agent-browser/lib/results/editable-ref-evidence.ts +72 -0
- package/extensions/agent-browser/lib/results/envelope.ts +2 -1
- package/extensions/agent-browser/lib/results/network.ts +64 -0
- package/extensions/agent-browser/lib/results/next-actions.ts +117 -0
- package/extensions/agent-browser/lib/results/presentation/artifacts.ts +506 -0
- package/extensions/agent-browser/lib/results/presentation/batch.ts +355 -0
- package/extensions/agent-browser/lib/results/presentation/common.ts +53 -0
- package/extensions/agent-browser/lib/results/presentation/content.ts +36 -0
- package/extensions/agent-browser/lib/results/presentation/diagnostics.ts +730 -0
- package/extensions/agent-browser/lib/results/presentation/errors.ts +125 -0
- package/extensions/agent-browser/lib/results/presentation/large-output.ts +182 -0
- package/extensions/agent-browser/lib/results/presentation/navigation.ts +216 -0
- package/extensions/agent-browser/lib/results/presentation/registry.ts +154 -0
- package/extensions/agent-browser/lib/results/presentation/skills.ts +143 -0
- package/extensions/agent-browser/lib/results/presentation.ts +87 -2369
- package/extensions/agent-browser/lib/results/recovery-actions.ts +139 -0
- package/extensions/agent-browser/lib/results/recovery-next-actions.ts +71 -0
- package/extensions/agent-browser/lib/results/selector-recovery.ts +312 -0
- package/extensions/agent-browser/lib/results/shared.ts +17 -701
- package/extensions/agent-browser/lib/results/snapshot-high-value-controls.ts +262 -0
- package/extensions/agent-browser/lib/results/snapshot-refs.ts +100 -0
- package/extensions/agent-browser/lib/results/snapshot-segments.ts +366 -0
- package/extensions/agent-browser/lib/results/snapshot-spill.ts +63 -0
- package/extensions/agent-browser/lib/results/snapshot.ts +37 -489
- package/extensions/agent-browser/lib/results/text.ts +40 -0
- package/extensions/agent-browser/lib/results.ts +16 -5
- package/extensions/agent-browser/lib/session-page-state.ts +486 -0
- package/extensions/agent-browser/lib/temp.ts +26 -0
- package/package.json +6 -4
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { readFile, rm } from "node:fs/promises";
|
|
2
|
+
|
|
3
|
+
import { cleanupElectronLaunchResources, inspectElectronLaunchStatus, type ElectronCleanupResult } from "../../electron/cleanup.js";
|
|
4
|
+
import type { ElectronLaunchRecord } from "../../electron/launch.js";
|
|
5
|
+
import {
|
|
6
|
+
analyzeNetworkSourceLookupResults,
|
|
7
|
+
analyzeQaPresetResults,
|
|
8
|
+
analyzeSourceLookupResults,
|
|
9
|
+
redactNetworkSourceLookupAnalysis,
|
|
10
|
+
} from "../../input-modes.js";
|
|
11
|
+
import {
|
|
12
|
+
buildToolPresentation,
|
|
13
|
+
getAgentBrowserErrorText,
|
|
14
|
+
parseAgentBrowserEnvelope,
|
|
15
|
+
type AgentBrowserEnvelope,
|
|
16
|
+
} from "../../results.js";
|
|
17
|
+
import {
|
|
18
|
+
buildEvictedSessionArtifactEntries,
|
|
19
|
+
formatSessionArtifactRetentionSummary,
|
|
20
|
+
mergeSessionArtifactManifest,
|
|
21
|
+
} from "../../results/artifact-manifest.js";
|
|
22
|
+
import type { SessionArtifactManifest } from "../../results/contracts.js";
|
|
23
|
+
import {
|
|
24
|
+
commandExplicitlyTargetsAboutBlank,
|
|
25
|
+
deriveSessionTabTarget,
|
|
26
|
+
extractLatestRefSnapshotStateFromBatchResults,
|
|
27
|
+
extractRefSnapshotFromData,
|
|
28
|
+
extractSessionTabTargetFromBatchResults,
|
|
29
|
+
extractSessionTabTargetFromCommandData,
|
|
30
|
+
isAboutBlankSessionTabTarget,
|
|
31
|
+
normalizeSessionTabTarget,
|
|
32
|
+
type SessionRefSnapshot,
|
|
33
|
+
type SessionRefSnapshotInvalidation,
|
|
34
|
+
} from "../../session-page-state.js";
|
|
35
|
+
import type { PersistentSessionArtifactEviction, PersistentSessionArtifactStore } from "../../temp.js";
|
|
36
|
+
import { writePersistentSessionArtifactFile, writeSecureTempFile } from "../../temp.js";
|
|
37
|
+
import { isRecord } from "../../parsing.js";
|
|
38
|
+
import { hasLaunchScopedTabCorrectionFlag, resolveManagedSessionState } from "../../runtime.js";
|
|
39
|
+
import {
|
|
40
|
+
applyOpenResultTabCorrection,
|
|
41
|
+
buildAboutBlankRecoveryHint,
|
|
42
|
+
buildAboutBlankWarning,
|
|
43
|
+
buildElectronPostCommandHealthDiagnostic,
|
|
44
|
+
buildElectronRefFreshnessDiagnostic,
|
|
45
|
+
buildElectronSessionMismatch,
|
|
46
|
+
buildManagedSessionOutcome,
|
|
47
|
+
closeManagedSession,
|
|
48
|
+
collectOpenResultTabCorrection,
|
|
49
|
+
collectSessionTabSelection,
|
|
50
|
+
extractStringResultField,
|
|
51
|
+
findElectronLaunchRecordForSession,
|
|
52
|
+
formatElectronPostCommandHealthText,
|
|
53
|
+
formatElectronSessionMismatchText,
|
|
54
|
+
getStaleRefArgs,
|
|
55
|
+
mergeNavigationSummaryIntoData,
|
|
56
|
+
shouldCaptureNavigationSummary,
|
|
57
|
+
shouldCorrectSessionTabAfterCommand,
|
|
58
|
+
shouldInspectElectronPostCommandHealth,
|
|
59
|
+
unwrapPinnedSessionBatchEnvelope,
|
|
60
|
+
updateTraceOwnerState,
|
|
61
|
+
} from "./session-state.js";
|
|
62
|
+
import {
|
|
63
|
+
buildScrollNoopDiagnostic,
|
|
64
|
+
collectComboboxFocusDiagnostic,
|
|
65
|
+
collectElectronBroadGetTextScopeDiagnostics,
|
|
66
|
+
collectElectronHandoff,
|
|
67
|
+
collectFillVerificationDiagnostic,
|
|
68
|
+
collectNavigationSummary,
|
|
69
|
+
collectOverlayBlockerDiagnostic,
|
|
70
|
+
collectQaAttachedTarget,
|
|
71
|
+
collectRecordingDependencyWarning,
|
|
72
|
+
collectScrollPositionSnapshot,
|
|
73
|
+
collectSelectorTextVisibilityDiagnostics,
|
|
74
|
+
collectTimeoutPartialProgress,
|
|
75
|
+
formatQaAttachedTargetText,
|
|
76
|
+
getArtifactCleanupGuidance,
|
|
77
|
+
getEvalStdinHint,
|
|
78
|
+
getSourceLookupElectronContext,
|
|
79
|
+
sleepMs,
|
|
80
|
+
} from "./diagnostics.js";
|
|
81
|
+
import { repairScreenshotData } from "./prepare.js";
|
|
82
|
+
import {
|
|
83
|
+
buildFinalAgentBrowserToolResult,
|
|
84
|
+
buildRedactedPresentationContent,
|
|
85
|
+
buildWrapperRecoveryHint,
|
|
86
|
+
prepareFinalResultRecoveryState,
|
|
87
|
+
redactExactSensitiveText,
|
|
88
|
+
redactExactSensitiveValue,
|
|
89
|
+
} from "./final-result.js";
|
|
90
|
+
import type {
|
|
91
|
+
AboutBlankSessionMismatch,
|
|
92
|
+
AgentBrowserToolResult,
|
|
93
|
+
BrowserProcessOutputResult,
|
|
94
|
+
BrowserRunContext,
|
|
95
|
+
BrowserRunOptions,
|
|
96
|
+
BrowserRunStatePatch,
|
|
97
|
+
ParseFailureOutput,
|
|
98
|
+
ProcessBrowserOutputInput,
|
|
99
|
+
ScreenshotArtifactRequest,
|
|
100
|
+
ScreenshotPathRequest,
|
|
101
|
+
} from "./types.js";
|
|
102
|
+
|
|
103
|
+
function getPersistentSessionArtifactStore(ctx: BrowserRunContext): PersistentSessionArtifactStore | undefined {
|
|
104
|
+
const sessionDir = typeof ctx.sessionManager.getSessionDir === "function" ? ctx.sessionManager.getSessionDir() : undefined;
|
|
105
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
106
|
+
return sessionDir && sessionId ? { sessionDir, sessionId } : undefined;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function repairScreenshotArtifact(options: {
|
|
110
|
+
cwd: string;
|
|
111
|
+
envelope?: AgentBrowserEnvelope;
|
|
112
|
+
request?: ScreenshotPathRequest;
|
|
113
|
+
}): Promise<{ envelope?: AgentBrowserEnvelope; request?: ScreenshotArtifactRequest }> {
|
|
114
|
+
const { cwd, envelope, request } = options;
|
|
115
|
+
if (!request || !envelope || !isRecord(envelope.data)) return { envelope, request };
|
|
116
|
+
const repaired = await repairScreenshotData({ cwd, data: envelope.data, request });
|
|
117
|
+
return { envelope: { ...envelope, data: repaired.data }, request: repaired.request };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function repairBatchScreenshotArtifacts(options: {
|
|
121
|
+
cwd: string;
|
|
122
|
+
envelope?: AgentBrowserEnvelope;
|
|
123
|
+
requests?: Array<ScreenshotPathRequest | undefined>;
|
|
124
|
+
}): Promise<{ envelope?: AgentBrowserEnvelope; requests?: Array<ScreenshotArtifactRequest | undefined> }> {
|
|
125
|
+
const { cwd, envelope, requests } = options;
|
|
126
|
+
if (!envelope || !Array.isArray(envelope.data) || !requests?.some((request) => request !== undefined)) return { envelope, requests };
|
|
127
|
+
const repairedRequests: Array<ScreenshotArtifactRequest | undefined> = [];
|
|
128
|
+
const repairedData = await Promise.all(envelope.data.map(async (item, index) => {
|
|
129
|
+
const request = requests[index];
|
|
130
|
+
if (!request || !isRecord(item) || !isRecord(item.result)) return item;
|
|
131
|
+
const repaired = await repairScreenshotData({ cwd, data: item.result, request });
|
|
132
|
+
repairedRequests[index] = repaired.request;
|
|
133
|
+
return { ...item, result: repaired.data };
|
|
134
|
+
}));
|
|
135
|
+
return { envelope: { ...envelope, data: repairedData }, requests: repairedRequests };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export async function preserveParseFailureOutput(options: {
|
|
139
|
+
artifactManifest?: SessionArtifactManifest;
|
|
140
|
+
exactSensitiveValues?: string[];
|
|
141
|
+
persistentArtifactStore?: PersistentSessionArtifactStore;
|
|
142
|
+
stdoutSpillPath?: string;
|
|
143
|
+
}): Promise<ParseFailureOutput> {
|
|
144
|
+
if (!options.stdoutSpillPath) return {};
|
|
145
|
+
try {
|
|
146
|
+
const rawOutput = redactExactSensitiveText(await readFile(options.stdoutSpillPath, "utf8"), options.exactSensitiveValues ?? []);
|
|
147
|
+
const nowMs = Date.now();
|
|
148
|
+
let evictedArtifacts: PersistentSessionArtifactEviction[] = [];
|
|
149
|
+
let fullOutputPath: string;
|
|
150
|
+
let storageScope: "persistent-session" | "process-temp";
|
|
151
|
+
if (options.persistentArtifactStore) {
|
|
152
|
+
const result = await writePersistentSessionArtifactFile({ content: rawOutput, prefix: "pi-agent-browser-parse-failure-output", store: options.persistentArtifactStore, suffix: ".txt" });
|
|
153
|
+
fullOutputPath = result.path;
|
|
154
|
+
evictedArtifacts = result.evictedArtifacts;
|
|
155
|
+
storageScope = "persistent-session";
|
|
156
|
+
} else {
|
|
157
|
+
fullOutputPath = await writeSecureTempFile({ content: rawOutput, prefix: "pi-agent-browser-parse-failure-output", suffix: ".txt" });
|
|
158
|
+
storageScope = "process-temp";
|
|
159
|
+
}
|
|
160
|
+
const artifactManifest = mergeSessionArtifactManifest({
|
|
161
|
+
base: options.artifactManifest,
|
|
162
|
+
entries: [{ command: "agent-browser", createdAtMs: nowMs, kind: "spill", path: fullOutputPath, retentionState: storageScope === "persistent-session" ? "live" : "ephemeral", storageScope }, ...buildEvictedSessionArtifactEntries(evictedArtifacts, nowMs)],
|
|
163
|
+
nowMs,
|
|
164
|
+
});
|
|
165
|
+
return { artifactManifest, artifactRetentionSummary: artifactManifest ? formatSessionArtifactRetentionSummary(artifactManifest) : undefined, fullOutputPath };
|
|
166
|
+
} catch (error) {
|
|
167
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
168
|
+
return { fullOutputUnavailable: message };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export async function processBrowserOutput(input: ProcessBrowserOutputInput): Promise<BrowserProcessOutputResult> {
|
|
173
|
+
const { ctx, cwd, electronPostCommandStatusSettleMs, implicitSessionCloseTimeoutMs, sessionPageStateUpdate, signal, state } = input;
|
|
174
|
+
const { prepared, processResult } = input;
|
|
175
|
+
const { electronChildProcesses, electronLaunchRecords, sessionPageState, traceOwners } = state;
|
|
176
|
+
let artifactManifest = state.artifactManifest;
|
|
177
|
+
let managedSessionActive = state.managedSessionActive;
|
|
178
|
+
let managedSessionCwd = state.managedSessionCwd;
|
|
179
|
+
let managedSessionName = state.managedSessionName;
|
|
180
|
+
try {
|
|
181
|
+
const persistentArtifactStore = getPersistentSessionArtifactStore(ctx);
|
|
182
|
+
const parsed = await parseAgentBrowserEnvelope({ stdout: processResult.stdout, stdoutPath: processResult.stdoutSpillPath });
|
|
183
|
+
let parseError = parsed.parseError;
|
|
184
|
+
let presentationEnvelope = parsed.envelope;
|
|
185
|
+
let navigationSummary = undefined as Awaited<ReturnType<typeof collectNavigationSummary>> | undefined;
|
|
186
|
+
if (prepared.pinnedBatchUnwrapMode) {
|
|
187
|
+
const pinnedBatchResult = unwrapPinnedSessionBatchEnvelope({ envelope: parsed.envelope, includeNavigationSummary: prepared.includePinnedNavigationSummary, mode: prepared.pinnedBatchUnwrapMode });
|
|
188
|
+
parseError = pinnedBatchResult.parseError ?? parseError;
|
|
189
|
+
presentationEnvelope = pinnedBatchResult.envelope ?? presentationEnvelope;
|
|
190
|
+
navigationSummary = pinnedBatchResult.navigationSummary;
|
|
191
|
+
}
|
|
192
|
+
const repairedScreenshot = await repairScreenshotArtifact({ cwd, envelope: presentationEnvelope, request: prepared.preparedArgs.screenshotPathRequest });
|
|
193
|
+
presentationEnvelope = repairedScreenshot.envelope;
|
|
194
|
+
const repairedBatchScreenshots = await repairBatchScreenshotArtifacts({ cwd, envelope: presentationEnvelope, requests: prepared.preparedArgs.batchScreenshotPathRequests });
|
|
195
|
+
presentationEnvelope = repairedBatchScreenshots.envelope;
|
|
196
|
+
const screenshotArtifactRequest = repairedScreenshot.request;
|
|
197
|
+
const batchScreenshotArtifactRequests = repairedBatchScreenshots.requests;
|
|
198
|
+
if (presentationEnvelope && prepared.exactSensitiveValues.length > 0) presentationEnvelope = redactExactSensitiveValue(presentationEnvelope, prepared.exactSensitiveValues) as AgentBrowserEnvelope;
|
|
199
|
+
const parseFailureOutput = parseError ? await preserveParseFailureOutput({ artifactManifest, exactSensitiveValues: prepared.exactSensitiveValues, persistentArtifactStore, stdoutSpillPath: processResult.stdoutSpillPath }) : {};
|
|
200
|
+
const processSucceeded = !processResult.aborted && !processResult.spawnError && processResult.exitCode === 0;
|
|
201
|
+
const plainTextInspection = prepared.executionPlan.plainTextInspection && processSucceeded;
|
|
202
|
+
const parseSucceeded = plainTextInspection || parseError === undefined;
|
|
203
|
+
const envelopeSuccess = plainTextInspection ? true : presentationEnvelope?.success !== false;
|
|
204
|
+
let succeeded = processSucceeded && parseSucceeded && envelopeSuccess;
|
|
205
|
+
const inspectionText = plainTextInspection ? processResult.stdout.trim() : undefined;
|
|
206
|
+
updateTraceOwnerState({ command: prepared.executionPlan.commandInfo.command, sessionName: prepared.executionPlan.sessionName, subcommand: prepared.executionPlan.commandInfo.subcommand, succeeded, traceOwners });
|
|
207
|
+
|
|
208
|
+
if (succeeded && !navigationSummary && shouldCaptureNavigationSummary(prepared.executionPlan.commandInfo.command, presentationEnvelope?.data)) {
|
|
209
|
+
navigationSummary = await collectNavigationSummary({ cwd, sessionName: prepared.executionPlan.sessionName, signal });
|
|
210
|
+
}
|
|
211
|
+
if (navigationSummary && presentationEnvelope) presentationEnvelope = { ...presentationEnvelope, data: mergeNavigationSummaryIntoData(presentationEnvelope.data, navigationSummary) };
|
|
212
|
+
let overlayBlockerDiagnostic: Awaited<ReturnType<typeof collectOverlayBlockerDiagnostic>>;
|
|
213
|
+
|
|
214
|
+
let openResultTabCorrection: Awaited<ReturnType<typeof collectOpenResultTabCorrection>>;
|
|
215
|
+
if (succeeded && prepared.executionPlan.sessionName && hasLaunchScopedTabCorrectionFlag(prepared.runtimeToolArgs) && ["goto", "navigate", "open"].includes(prepared.executionPlan.commandInfo.command ?? "")) {
|
|
216
|
+
const targetTitle = extractStringResultField(presentationEnvelope?.data, "title");
|
|
217
|
+
const targetUrl = extractStringResultField(presentationEnvelope?.data, "url");
|
|
218
|
+
const plannedTabCorrection = await collectOpenResultTabCorrection({ cwd, sessionName: prepared.executionPlan.sessionName, signal, targetTitle, targetUrl });
|
|
219
|
+
if (plannedTabCorrection) openResultTabCorrection = await applyOpenResultTabCorrection({ correction: plannedTabCorrection, cwd, sessionName: prepared.executionPlan.sessionName, signal });
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const observedSessionTabTarget = normalizeSessionTabTarget(navigationSummary) ?? extractSessionTabTargetFromBatchResults(presentationEnvelope?.data) ?? extractSessionTabTargetFromCommandData(prepared.commandTokens, presentationEnvelope?.data);
|
|
223
|
+
let currentSessionTabTarget = deriveSessionTabTarget({ command: prepared.executionPlan.commandInfo.command, data: presentationEnvelope?.data, navigationSummary, previousTarget: prepared.priorSessionTabTarget, subcommand: prepared.executionPlan.commandInfo.subcommand });
|
|
224
|
+
let aboutBlankSessionMismatch: AboutBlankSessionMismatch | undefined;
|
|
225
|
+
let electronPostCommandHealth: ReturnType<typeof buildElectronPostCommandHealthDiagnostic>;
|
|
226
|
+
let electronRefFreshnessDiagnostic: ReturnType<typeof buildElectronRefFreshnessDiagnostic>;
|
|
227
|
+
let electronSessionMismatch: ReturnType<typeof buildElectronSessionMismatch>;
|
|
228
|
+
let electronStatusAfterCommand: Awaited<ReturnType<typeof inspectElectronLaunchStatus>> | undefined;
|
|
229
|
+
const shouldTreatAboutBlankAsMismatch = succeeded && prepared.priorSessionTabTarget !== undefined && !isAboutBlankSessionTabTarget(prepared.priorSessionTabTarget) && isAboutBlankSessionTabTarget(observedSessionTabTarget ?? currentSessionTabTarget) && !commandExplicitlyTargetsAboutBlank(prepared.commandTokens);
|
|
230
|
+
let sessionTabCorrection = prepared.sessionTabCorrection;
|
|
231
|
+
if (shouldTreatAboutBlankAsMismatch && prepared.priorSessionTabTarget) {
|
|
232
|
+
const aboutBlankObservedTarget = observedSessionTabTarget ?? currentSessionTabTarget;
|
|
233
|
+
const aboutBlankRecovery = await collectSessionTabSelection({ cwd, sessionName: prepared.executionPlan.sessionName, signal, target: prepared.priorSessionTabTarget });
|
|
234
|
+
const appliedAboutBlankRecovery = aboutBlankRecovery ? await applyOpenResultTabCorrection({ correction: aboutBlankRecovery, cwd, sessionName: prepared.executionPlan.sessionName, signal }) : undefined;
|
|
235
|
+
if (appliedAboutBlankRecovery) { sessionTabCorrection = appliedAboutBlankRecovery; currentSessionTabTarget = prepared.priorSessionTabTarget; }
|
|
236
|
+
else currentSessionTabTarget = aboutBlankObservedTarget ?? normalizeSessionTabTarget({ url: "about:blank" });
|
|
237
|
+
aboutBlankSessionMismatch = { activeUrl: "about:blank", recoveryApplied: appliedAboutBlankRecovery !== undefined, recoveryHint: buildAboutBlankRecoveryHint(), targetTitle: prepared.priorSessionTabTarget.title, targetUrl: prepared.priorSessionTabTarget.url };
|
|
238
|
+
const electronRecord = findElectronLaunchRecordForSession(prepared.executionPlan.sessionName, electronLaunchRecords);
|
|
239
|
+
if (electronRecord && prepared.executionPlan.sessionName) {
|
|
240
|
+
electronStatusAfterCommand = await inspectElectronLaunchStatus(electronRecord);
|
|
241
|
+
electronSessionMismatch = buildElectronSessionMismatch({ managedSession: { sessionName: prepared.executionPlan.sessionName, title: aboutBlankObservedTarget?.title, url: aboutBlankObservedTarget?.url ?? "about:blank" }, record: electronRecord, statusTargets: electronStatusAfterCommand.targets });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (succeeded && prepared.priorSessionTabTarget && !sessionTabCorrection && !aboutBlankSessionMismatch && !commandExplicitlyTargetsAboutBlank(prepared.commandTokens) && observedSessionTabTarget && shouldCorrectSessionTabAfterCommand({ command: prepared.executionPlan.commandInfo.command, pinningRequired: prepared.sessionTabPinningReason !== undefined, sessionName: prepared.executionPlan.sessionName })) {
|
|
245
|
+
const postCommandTabCorrection = await collectSessionTabSelection({ cwd, sessionName: prepared.executionPlan.sessionName, signal, target: observedSessionTabTarget });
|
|
246
|
+
if (postCommandTabCorrection) {
|
|
247
|
+
const appliedPostCommandCorrection = await applyOpenResultTabCorrection({ correction: postCommandTabCorrection, cwd, sessionName: prepared.executionPlan.sessionName, signal });
|
|
248
|
+
if (appliedPostCommandCorrection && !sessionTabCorrection) sessionTabCorrection = appliedPostCommandCorrection;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const electronRecordForCommand = findElectronLaunchRecordForSession(prepared.executionPlan.sessionName, electronLaunchRecords);
|
|
252
|
+
if (succeeded && electronRecordForCommand && shouldInspectElectronPostCommandHealth(prepared.executionPlan.commandInfo.command)) {
|
|
253
|
+
electronStatusAfterCommand ??= await inspectElectronLaunchStatus(electronRecordForCommand);
|
|
254
|
+
electronPostCommandHealth = buildElectronPostCommandHealthDiagnostic({ command: prepared.executionPlan.commandInfo.command, record: electronRecordForCommand, status: electronStatusAfterCommand, target: observedSessionTabTarget ?? currentSessionTabTarget });
|
|
255
|
+
if (electronPostCommandHealth && electronPostCommandHealth.reason !== "process-dead") {
|
|
256
|
+
await sleepMs(electronPostCommandStatusSettleMs);
|
|
257
|
+
electronStatusAfterCommand = await inspectElectronLaunchStatus(electronRecordForCommand);
|
|
258
|
+
electronPostCommandHealth = buildElectronPostCommandHealthDiagnostic({ command: prepared.executionPlan.commandInfo.command, record: electronRecordForCommand, status: electronStatusAfterCommand, target: observedSessionTabTarget ?? currentSessionTabTarget });
|
|
259
|
+
}
|
|
260
|
+
if (electronPostCommandHealth) succeeded = false;
|
|
261
|
+
}
|
|
262
|
+
let fillVerificationDiagnostic: Awaited<ReturnType<typeof collectFillVerificationDiagnostic>>;
|
|
263
|
+
let selectorTextVisibilityDiagnostics: Awaited<ReturnType<typeof collectSelectorTextVisibilityDiagnostics>> = [];
|
|
264
|
+
let electronBroadGetTextScopeDiagnostics: ReturnType<typeof collectElectronBroadGetTextScopeDiagnostics> = [];
|
|
265
|
+
const timeoutPartialProgress = processResult.timedOut ? await collectTimeoutPartialProgress({ command: prepared.executionPlan.commandInfo.command, compiledJob: prepared.compiledJob, cwd, sessionName: prepared.executionPlan.sessionName, stdin: prepared.runtimeToolStdin }) : undefined;
|
|
266
|
+
if (succeeded && electronRecordForCommand) {
|
|
267
|
+
fillVerificationDiagnostic = await collectFillVerificationDiagnostic({ commandTokens: prepared.commandTokens, cwd, sessionName: prepared.executionPlan.sessionName, signal });
|
|
268
|
+
electronRefFreshnessDiagnostic = buildElectronRefFreshnessDiagnostic({ command: prepared.executionPlan.commandInfo.command, commandTokens: prepared.commandTokens, record: electronRecordForCommand, sessionName: prepared.executionPlan.sessionName, stdin: prepared.runtimeToolStdin });
|
|
269
|
+
}
|
|
270
|
+
if (succeeded && !sessionTabCorrection && !aboutBlankSessionMismatch && !electronRecordForCommand) overlayBlockerDiagnostic = await collectOverlayBlockerDiagnostic({ command: prepared.executionPlan.commandInfo.command, cwd, data: presentationEnvelope?.data, navigationSummary, priorTarget: prepared.priorSessionTabTarget, sessionName: prepared.executionPlan.sessionName, signal });
|
|
271
|
+
if (succeeded) {
|
|
272
|
+
selectorTextVisibilityDiagnostics = await collectSelectorTextVisibilityDiagnostics({ commandInfo: prepared.executionPlan.commandInfo, commandTokens: prepared.commandTokens, cwd, data: presentationEnvelope?.data, sessionName: prepared.executionPlan.sessionName, signal });
|
|
273
|
+
electronBroadGetTextScopeDiagnostics = collectElectronBroadGetTextScopeDiagnostics({ commandInfo: prepared.executionPlan.commandInfo, commandTokens: prepared.commandTokens, currentTarget: currentSessionTabTarget, data: presentationEnvelope?.data, electronLaunchRecords, priorTarget: prepared.priorSessionTabTarget, sessionName: prepared.executionPlan.sessionName });
|
|
274
|
+
}
|
|
275
|
+
const comboboxFocusDiagnostic = succeeded ? await collectComboboxFocusDiagnostic({ command: prepared.executionPlan.commandInfo.command, commandTokens: prepared.commandTokens, cwd, semanticAction: prepared.compiledSemanticAction, sessionName: prepared.executionPlan.sessionName, signal }) : undefined;
|
|
276
|
+
const recordingDependencyWarning = await collectRecordingDependencyWarning({ command: prepared.executionPlan.commandInfo.command, commandTokens: prepared.commandTokens, succeeded });
|
|
277
|
+
const scrollNoopDiagnostic = succeeded && prepared.shouldProbeScrollNoop ? buildScrollNoopDiagnostic(prepared.scrollPositionBefore, await collectScrollPositionSnapshot({ cwd, sessionName: prepared.executionPlan.sessionName, signal })) : undefined;
|
|
278
|
+
let currentRefSnapshot: SessionRefSnapshot | undefined;
|
|
279
|
+
let currentRefSnapshotInvalidation: SessionRefSnapshotInvalidation | undefined;
|
|
280
|
+
const batchRefSnapshotState = prepared.executionPlan.commandInfo.command === "batch" ? extractLatestRefSnapshotStateFromBatchResults(presentationEnvelope?.data) : undefined;
|
|
281
|
+
if (prepared.executionPlan.sessionName) {
|
|
282
|
+
if (prepared.executionPlan.commandInfo.command === "close" && succeeded) sessionPageState.clearSession(prepared.executionPlan.sessionName);
|
|
283
|
+
else if (currentSessionTabTarget) {
|
|
284
|
+
const tabUpdate = sessionPageState.applyTabTarget({ sessionName: prepared.executionPlan.sessionName, target: currentSessionTabTarget, update: sessionPageStateUpdate });
|
|
285
|
+
if (!tabUpdate.applied && succeeded) sessionPageState.markPinning(prepared.executionPlan.sessionName, "drift");
|
|
286
|
+
}
|
|
287
|
+
const refSnapshot = prepared.executionPlan.commandInfo.command === "batch" ? batchRefSnapshotState?.snapshot : succeeded ? prepared.executionPlan.commandInfo.command === "snapshot" ? extractRefSnapshotFromData(presentationEnvelope?.data) : prepared.resolvedSemanticActionRefSnapshot ?? overlayBlockerDiagnostic?.snapshot : undefined;
|
|
288
|
+
if (refSnapshot) {
|
|
289
|
+
const refUpdate = sessionPageState.applyRefSnapshot({ fallbackTarget: currentSessionTabTarget, sessionName: prepared.executionPlan.sessionName, snapshot: refSnapshot, update: sessionPageStateUpdate });
|
|
290
|
+
currentRefSnapshot = refUpdate.refSnapshot;
|
|
291
|
+
currentRefSnapshotInvalidation = refUpdate.refSnapshotInvalidation;
|
|
292
|
+
} else {
|
|
293
|
+
const stateView = sessionPageState.get(prepared.executionPlan.sessionName);
|
|
294
|
+
currentRefSnapshot = stateView.refSnapshot;
|
|
295
|
+
currentRefSnapshotInvalidation = stateView.refSnapshotInvalidation;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const priorManagedSessionActive = managedSessionActive;
|
|
300
|
+
const priorManagedSessionCwd = managedSessionCwd;
|
|
301
|
+
const priorManagedSessionName = managedSessionName;
|
|
302
|
+
const managedSessionState = resolveManagedSessionState({ command: prepared.executionPlan.commandInfo.command, managedSessionName: prepared.executionPlan.managedSessionName, priorActive: priorManagedSessionActive, priorSessionName: priorManagedSessionName, succeeded });
|
|
303
|
+
const replacedManagedSessionName = managedSessionState.replacedSessionName;
|
|
304
|
+
managedSessionActive = managedSessionState.active;
|
|
305
|
+
managedSessionName = managedSessionState.sessionName;
|
|
306
|
+
let managedSessionOutcome = buildManagedSessionOutcome({ activeAfter: managedSessionActive, activeBefore: priorManagedSessionActive, attemptedSessionName: prepared.executionPlan.managedSessionName, command: prepared.executionPlan.commandInfo.command, currentSessionName: managedSessionName, previousSessionName: priorManagedSessionName, replacedSessionName: replacedManagedSessionName, sessionMode: prepared.sessionMode, succeeded });
|
|
307
|
+
if (prepared.executionPlan.managedSessionName && succeeded) managedSessionCwd = cwd;
|
|
308
|
+
if (prepared.executionPlan.sessionName && succeeded) {
|
|
309
|
+
if (openResultTabCorrection || sessionTabCorrection || aboutBlankSessionMismatch?.recoveryApplied) sessionPageState.markPinning(prepared.executionPlan.sessionName, "drift");
|
|
310
|
+
else if (prepared.sessionTabPinningReason === "restore") sessionPageState.clearRestorePinning(prepared.executionPlan.sessionName);
|
|
311
|
+
}
|
|
312
|
+
if (replacedManagedSessionName) {
|
|
313
|
+
sessionPageState.clearSession(replacedManagedSessionName);
|
|
314
|
+
await closeManagedSession({ cwd: priorManagedSessionCwd, sessionName: replacedManagedSessionName, timeoutMs: implicitSessionCloseTimeoutMs });
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
let electronLaunchRecord: ElectronLaunchRecord | undefined;
|
|
318
|
+
let electronFailedConnectCleanup: ElectronCleanupResult | undefined = prepared.electronFailedConnectCleanup;
|
|
319
|
+
let electronHandoff = prepared.electronHandoff;
|
|
320
|
+
if (prepared.electronLaunch) {
|
|
321
|
+
if (succeeded && prepared.executionPlan.sessionName) {
|
|
322
|
+
electronLaunchRecord = { ...prepared.electronLaunch.record, sessionName: prepared.executionPlan.sessionName };
|
|
323
|
+
electronLaunchRecords.set(electronLaunchRecord.launchId, electronLaunchRecord);
|
|
324
|
+
electronChildProcesses.set(electronLaunchRecord.launchId, prepared.electronLaunch.child);
|
|
325
|
+
const electronHandoffMode = prepared.compiledElectron?.action === "launch" ? prepared.compiledElectron.handoff : "connect";
|
|
326
|
+
try { electronHandoff = await collectElectronHandoff({ cwd, handoff: electronHandoffMode, sessionName: prepared.executionPlan.sessionName, signal }); }
|
|
327
|
+
catch (error) { electronHandoff = { error: error instanceof Error ? error.message : String(error), handoff: electronHandoffMode }; }
|
|
328
|
+
if (electronHandoff?.refSnapshot) {
|
|
329
|
+
const refUpdate = sessionPageState.applyRefSnapshot({ sessionName: prepared.executionPlan.sessionName, snapshot: electronHandoff.refSnapshot, update: sessionPageStateUpdate });
|
|
330
|
+
currentRefSnapshot = refUpdate.refSnapshot;
|
|
331
|
+
currentRefSnapshotInvalidation = refUpdate.refSnapshotInvalidation;
|
|
332
|
+
if (electronHandoff.refSnapshot.target) {
|
|
333
|
+
currentSessionTabTarget = electronHandoff.refSnapshot.target;
|
|
334
|
+
sessionPageState.applyTabTarget({ sessionName: prepared.executionPlan.sessionName, target: electronHandoff.refSnapshot.target, update: sessionPageStateUpdate });
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
} else {
|
|
338
|
+
electronFailedConnectCleanup = await cleanupElectronLaunchResources({ child: prepared.electronLaunch.child, record: prepared.electronLaunch.record, timeoutMs: implicitSessionCloseTimeoutMs });
|
|
339
|
+
electronLaunchRecord = electronFailedConnectCleanup.record;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const errorText = getAgentBrowserErrorText({ aborted: processResult.aborted, command: prepared.executionPlan.commandInfo.command, effectiveArgs: prepared.redactedProcessArgs, envelope: presentationEnvelope, exitCode: processResult.exitCode, parseError, plainTextInspection, staleRefArgs: getStaleRefArgs(prepared.commandTokens, prepared.runtimeToolStdin), spawnError: processResult.spawnError, stderr: processResult.stderr, timedOut: processResult.timedOut, timeoutMs: processResult.timeoutMs, wrapperRecoveryHint: buildWrapperRecoveryHint({ pinnedBatchUnwrapMode: prepared.pinnedBatchUnwrapMode, sessionTabCorrection }) });
|
|
344
|
+
const presentation = plainTextInspection ? { artifacts: undefined, batchFailure: undefined, batchSteps: undefined, content: [{ type: "text" as const, 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, cwd, envelope: presentationEnvelope, errorText, persistentArtifactStore, sessionName: prepared.executionPlan.sessionName });
|
|
345
|
+
if (parseFailureOutput.artifactManifest) { presentation.artifactManifest = parseFailureOutput.artifactManifest; presentation.artifactRetentionSummary = parseFailureOutput.artifactRetentionSummary; }
|
|
346
|
+
if (parseFailureOutput.fullOutputPath || parseFailureOutput.fullOutputUnavailable) {
|
|
347
|
+
const existingText = presentation.content[0]?.type === "text" ? presentation.content[0].text : "";
|
|
348
|
+
const noticeLines = [parseFailureOutput.fullOutputPath ? `Full output path: ${parseFailureOutput.fullOutputPath}` : `Full raw output unavailable: ${parseFailureOutput.fullOutputUnavailable}`, parseFailureOutput.artifactRetentionSummary].filter((item): item is string => item !== undefined);
|
|
349
|
+
const notice = noticeLines.join("\n");
|
|
350
|
+
presentation.content[0] = { type: "text", text: existingText.length > 0 ? `${existingText}\n\n${notice}` : notice };
|
|
351
|
+
}
|
|
352
|
+
if (presentation.artifactManifest) artifactManifest = presentation.artifactManifest;
|
|
353
|
+
const qaPreset = prepared.compiledQaPreset ? analyzeQaPresetResults(presentationEnvelope?.data) : undefined;
|
|
354
|
+
const qaAttachedTarget = prepared.compiledQaPreset?.checks.attached ? await collectQaAttachedTarget({ currentTarget: currentSessionTabTarget ?? prepared.priorSessionTabTarget, cwd, sessionName: prepared.executionPlan.sessionName, signal }) : undefined;
|
|
355
|
+
const sourceLookupElectronContext = prepared.compiledSourceLookup ? getSourceLookupElectronContext({ currentTarget: currentSessionTabTarget, electronLaunchRecords, priorTarget: prepared.priorSessionTabTarget, sessionName: prepared.executionPlan.sessionName }) : undefined;
|
|
356
|
+
const sourceLookup = prepared.compiledSourceLookup ? await analyzeSourceLookupResults(presentationEnvelope?.data, prepared.compiledSourceLookup, cwd, { electronContext: sourceLookupElectronContext, workspaceRoot: cwd }) : undefined;
|
|
357
|
+
const networkSourceLookup = prepared.compiledNetworkSourceLookup ? redactNetworkSourceLookupAnalysis(await analyzeNetworkSourceLookupResults(presentationEnvelope?.data, prepared.compiledNetworkSourceLookup, cwd)) : undefined;
|
|
358
|
+
if (networkSourceLookup && presentation.content[0]?.type === "text") presentation.content[0] = { ...presentation.content[0], text: `${networkSourceLookup.summary}\n\n${presentation.content[0].text}` };
|
|
359
|
+
else if (networkSourceLookup) presentation.content.unshift({ type: "text", text: networkSourceLookup.summary });
|
|
360
|
+
if (sourceLookup && presentation.content[0]?.type === "text") presentation.content[0] = { ...presentation.content[0], text: `${sourceLookup.summary}\n\n${presentation.content[0].text}` };
|
|
361
|
+
else if (sourceLookup) presentation.content.unshift({ type: "text", text: sourceLookup.summary });
|
|
362
|
+
if (qaPreset && (!qaPreset.passed || qaPreset.warnings.length > 0)) {
|
|
363
|
+
if (!qaPreset.passed) { succeeded = false; presentation.failureCategory = "qa-failure"; }
|
|
364
|
+
presentation.summary = qaPreset.summary;
|
|
365
|
+
if (presentation.content[0]?.type === "text") presentation.content[0] = { ...presentation.content[0], text: `${qaPreset.summary}\n\n${presentation.content[0].text}` };
|
|
366
|
+
else presentation.content.unshift({ type: "text", text: qaPreset.summary });
|
|
367
|
+
}
|
|
368
|
+
const qaAttachedTargetText = formatQaAttachedTargetText(qaAttachedTarget);
|
|
369
|
+
if (qaAttachedTargetText && presentation.content[0]?.type === "text") presentation.content[0] = { ...presentation.content[0], text: `${qaAttachedTargetText}\n\n${presentation.content[0].text}` };
|
|
370
|
+
else if (qaAttachedTargetText) presentation.content.unshift({ type: "text", text: qaAttachedTargetText });
|
|
371
|
+
if (managedSessionOutcome && managedSessionOutcome.succeeded !== succeeded) managedSessionOutcome = { ...managedSessionOutcome, succeeded };
|
|
372
|
+
const evalStdinHint = getEvalStdinHint({ command: prepared.executionPlan.commandInfo.command, data: presentationEnvelope?.data, stdin: prepared.runtimeToolStdin });
|
|
373
|
+
const resultArtifactManifest = presentation.artifactManifest ?? artifactManifest;
|
|
374
|
+
const artifactCleanup = await getArtifactCleanupGuidance({ command: prepared.executionPlan.commandInfo.command, cwd, manifest: resultArtifactManifest, succeeded });
|
|
375
|
+
const warningText = electronPostCommandHealth ? formatElectronPostCommandHealthText(electronPostCommandHealth) : electronSessionMismatch ? formatElectronSessionMismatchText(electronSessionMismatch) : aboutBlankSessionMismatch ? buildAboutBlankWarning(aboutBlankSessionMismatch) : undefined;
|
|
376
|
+
const redactedContent = buildRedactedPresentationContent({ exactSensitiveValues: prepared.exactSensitiveValues, plainTextInspection, presentation, presentationEnvelope, succeeded, userRequestedJson: prepared.userRequestedJson, warningText });
|
|
377
|
+
const finalRecoveryState = await prepareFinalResultRecoveryState({ aboutBlankSessionMismatch, batchRefSnapshotState, commandTokens: prepared.commandTokens, compiledSemanticAction: prepared.compiledSemanticAction, currentRefSnapshot, currentRefSnapshotInvalidation, currentSessionTabTarget, cwd, electronPostCommandHealth, errorText, executionPlan: prepared.executionPlan, parseError, plainTextInspection, presentation, processResult, redactedProcessArgs: prepared.redactedProcessArgs, runtimeToolArgs: prepared.runtimeToolArgs, sessionPageState, sessionPageStateUpdate, sessionTabCorrection, signal, succeeded });
|
|
378
|
+
currentRefSnapshot = finalRecoveryState.currentRefSnapshot;
|
|
379
|
+
currentRefSnapshotInvalidation = finalRecoveryState.currentRefSnapshotInvalidation;
|
|
380
|
+
const result = buildFinalAgentBrowserToolResult({ aboutBlankSessionMismatch, artifactCleanup, categoryDetails: finalRecoveryState.categoryDetails, comboboxFocusDiagnostic, compiledNetworkSourceLookup: prepared.compiledNetworkSourceLookup, compiledSemanticAction: prepared.compiledSemanticAction, compatibilityWorkaround: prepared.compatibilityWorkaround, currentRefSnapshot, currentRefSnapshotInvalidation, currentSessionTabTarget, electronBroadGetTextScopeDiagnostics, electronFailedConnectCleanup, electronHandoff, electronLaunch: prepared.electronLaunch, electronLaunchRecord, electronLaunchRecords, electronPostCommandHealth, electronProfileIsolationDetails: input.electronProfileIsolationDetails, electronRefFreshnessDiagnostic, electronSessionMismatch, errorText, evalStdinHint, exactSensitiveValues: prepared.exactSensitiveValues, executionPlan: prepared.executionPlan, fillVerificationDiagnostic, inspectionText, managedSessionOutcome, 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 });
|
|
381
|
+
const statePatch: BrowserRunStatePatch = { artifactManifest, managedSessionActive, managedSessionCwd, managedSessionName };
|
|
382
|
+
return { result, statePatch };
|
|
383
|
+
} finally {
|
|
384
|
+
if (processResult.stdoutSpillPath) await rm(processResult.stdoutSpillPath, { force: true }).catch(() => undefined);
|
|
385
|
+
}
|
|
386
|
+
}
|