pi-agent-browser-native 0.2.48 → 0.2.50

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.
Files changed (189) hide show
  1. package/CHANGELOG.md +27 -1
  2. package/README.md +21 -11
  3. package/dist/extensions/agent-browser/index.js +808 -0
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +71 -0
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +121 -0
  6. package/dist/extensions/agent-browser/lib/bash-guard.js +190 -0
  7. package/dist/extensions/agent-browser/lib/command-policy.js +85 -0
  8. package/dist/extensions/agent-browser/lib/command-taxonomy.js +302 -0
  9. package/dist/extensions/agent-browser/lib/config-policy.js +669 -0
  10. package/dist/extensions/agent-browser/lib/config.js +122 -0
  11. package/dist/extensions/agent-browser/lib/electron/cdp.js +51 -0
  12. package/dist/extensions/agent-browser/lib/electron/cleanup.js +212 -0
  13. package/dist/extensions/agent-browser/lib/electron/discovery.js +633 -0
  14. package/dist/extensions/agent-browser/lib/electron/launch.js +351 -0
  15. package/{extensions/agent-browser/lib/electron/text.ts → dist/extensions/agent-browser/lib/electron/text.js} +5 -5
  16. package/dist/extensions/agent-browser/lib/executable-path.js +20 -0
  17. package/dist/extensions/agent-browser/lib/fs-utils.js +18 -0
  18. package/dist/extensions/agent-browser/lib/input-modes/electron.js +165 -0
  19. package/dist/extensions/agent-browser/lib/input-modes/job.js +519 -0
  20. package/dist/extensions/agent-browser/lib/input-modes/lookups.js +440 -0
  21. package/dist/extensions/agent-browser/lib/input-modes/params.js +164 -0
  22. package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +119 -0
  23. package/dist/extensions/agent-browser/lib/input-modes/shared.js +42 -0
  24. package/dist/extensions/agent-browser/lib/input-modes/types.js +21 -0
  25. package/dist/extensions/agent-browser/lib/input-modes.js +10 -0
  26. package/dist/extensions/agent-browser/lib/json-schema.js +58 -0
  27. package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +59 -0
  28. package/dist/extensions/agent-browser/lib/navigation-policy.js +83 -0
  29. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +62 -0
  30. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +39 -0
  31. package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +276 -0
  32. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +909 -0
  33. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +443 -0
  34. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +47 -0
  35. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.js +141 -0
  36. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +108 -0
  37. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +112 -0
  38. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +158 -0
  39. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +54 -0
  40. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +762 -0
  41. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +491 -0
  42. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.js +40 -0
  43. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.js +5 -0
  44. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +731 -0
  45. package/dist/extensions/agent-browser/lib/orchestration/browser-run/types.js +1 -0
  46. package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +718 -0
  47. package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +247 -0
  48. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +68 -0
  49. package/{extensions/agent-browser/lib/parsing.ts → dist/extensions/agent-browser/lib/parsing.js} +12 -11
  50. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +241 -0
  51. package/dist/extensions/agent-browser/lib/playbook.js +121 -0
  52. package/dist/extensions/agent-browser/lib/process.js +363 -0
  53. package/dist/extensions/agent-browser/lib/prompt-policy.js +91 -0
  54. package/dist/extensions/agent-browser/lib/results/action-recommendations.js +220 -0
  55. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +111 -0
  56. package/{extensions/agent-browser/lib/results/artifact-state.ts → dist/extensions/agent-browser/lib/results/artifact-state.js} +4 -8
  57. package/dist/extensions/agent-browser/lib/results/categories.js +76 -0
  58. package/dist/extensions/agent-browser/lib/results/confirmation.js +63 -0
  59. package/dist/extensions/agent-browser/lib/results/contracts.js +8 -0
  60. package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +74 -0
  61. package/dist/extensions/agent-browser/lib/results/envelope.js +166 -0
  62. package/dist/extensions/agent-browser/lib/results/network-routes.js +92 -0
  63. package/dist/extensions/agent-browser/lib/results/network.js +73 -0
  64. package/dist/extensions/agent-browser/lib/results/next-actions.js +72 -0
  65. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +515 -0
  66. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +397 -0
  67. package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +55 -0
  68. package/dist/extensions/agent-browser/lib/results/presentation/common.js +46 -0
  69. package/dist/extensions/agent-browser/lib/results/presentation/content.js +24 -0
  70. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +956 -0
  71. package/dist/extensions/agent-browser/lib/results/presentation/errors.js +205 -0
  72. package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +134 -0
  73. package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +159 -0
  74. package/dist/extensions/agent-browser/lib/results/presentation/registry.js +216 -0
  75. package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +104 -0
  76. package/dist/extensions/agent-browser/lib/results/presentation/skills.js +152 -0
  77. package/dist/extensions/agent-browser/lib/results/presentation.js +177 -0
  78. package/dist/extensions/agent-browser/lib/results/recovery-actions.js +107 -0
  79. package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +50 -0
  80. package/dist/extensions/agent-browser/lib/results/selector-recovery.js +225 -0
  81. package/{extensions/agent-browser/lib/results/shared.ts → dist/extensions/agent-browser/lib/results/shared.js} +0 -1
  82. package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +208 -0
  83. package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +78 -0
  84. package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +331 -0
  85. package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +40 -0
  86. package/dist/extensions/agent-browser/lib/results/snapshot.js +264 -0
  87. package/dist/extensions/agent-browser/lib/results/text.js +40 -0
  88. package/{extensions/agent-browser/lib/results.ts → dist/extensions/agent-browser/lib/results.js} +2 -32
  89. package/dist/extensions/agent-browser/lib/runtime.js +855 -0
  90. package/dist/extensions/agent-browser/lib/session-page-state.js +411 -0
  91. package/dist/extensions/agent-browser/lib/string-enum-schema.js +13 -0
  92. package/dist/extensions/agent-browser/lib/temp.js +498 -0
  93. package/dist/extensions/agent-browser/lib/web-search.js +562 -0
  94. package/docs/ARCHITECTURE.md +5 -5
  95. package/docs/COMMAND_REFERENCE.md +4 -4
  96. package/docs/RELEASE.md +22 -11
  97. package/docs/REQUIREMENTS.md +1 -1
  98. package/docs/SUPPORT_MATRIX.md +5 -4
  99. package/docs/TOOL_CONTRACT.md +1 -1
  100. package/package.json +9 -5
  101. package/scripts/config.mjs +14 -20
  102. package/scripts/doctor.mjs +8 -7
  103. package/extensions/agent-browser/index.ts +0 -961
  104. package/extensions/agent-browser/lib/argv-descriptor.ts +0 -90
  105. package/extensions/agent-browser/lib/argv-grammar.ts +0 -128
  106. package/extensions/agent-browser/lib/bash-guard.ts +0 -205
  107. package/extensions/agent-browser/lib/command-policy.ts +0 -71
  108. package/extensions/agent-browser/lib/command-taxonomy.ts +0 -336
  109. package/extensions/agent-browser/lib/config-policy.js +0 -690
  110. package/extensions/agent-browser/lib/config.ts +0 -211
  111. package/extensions/agent-browser/lib/electron/cdp.ts +0 -69
  112. package/extensions/agent-browser/lib/electron/cleanup.ts +0 -235
  113. package/extensions/agent-browser/lib/electron/discovery.ts +0 -710
  114. package/extensions/agent-browser/lib/electron/launch.ts +0 -499
  115. package/extensions/agent-browser/lib/executable-path.ts +0 -19
  116. package/extensions/agent-browser/lib/fs-utils.ts +0 -18
  117. package/extensions/agent-browser/lib/input-modes/electron.ts +0 -170
  118. package/extensions/agent-browser/lib/input-modes/job.ts +0 -527
  119. package/extensions/agent-browser/lib/input-modes/lookups.ts +0 -447
  120. package/extensions/agent-browser/lib/input-modes/params.ts +0 -205
  121. package/extensions/agent-browser/lib/input-modes/semantic-action.ts +0 -127
  122. package/extensions/agent-browser/lib/input-modes/shared.ts +0 -46
  123. package/extensions/agent-browser/lib/input-modes/types.ts +0 -225
  124. package/extensions/agent-browser/lib/input-modes.ts +0 -45
  125. package/extensions/agent-browser/lib/json-schema.ts +0 -73
  126. package/extensions/agent-browser/lib/launch-scoped-flags.ts +0 -67
  127. package/extensions/agent-browser/lib/navigation-policy.ts +0 -95
  128. package/extensions/agent-browser/lib/orchestration/batch-stdin.ts +0 -65
  129. package/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.ts +0 -44
  130. package/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.ts +0 -280
  131. package/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.ts +0 -914
  132. package/extensions/agent-browser/lib/orchestration/browser-run/final-result.ts +0 -521
  133. package/extensions/agent-browser/lib/orchestration/browser-run/index.ts +0 -53
  134. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.ts +0 -158
  135. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.ts +0 -116
  136. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.ts +0 -147
  137. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.ts +0 -183
  138. package/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.ts +0 -58
  139. package/extensions/agent-browser/lib/orchestration/browser-run/prepare.ts +0 -847
  140. package/extensions/agent-browser/lib/orchestration/browser-run/process-output.ts +0 -559
  141. package/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.ts +0 -47
  142. package/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.ts +0 -8
  143. package/extensions/agent-browser/lib/orchestration/browser-run/session-state.ts +0 -868
  144. package/extensions/agent-browser/lib/orchestration/browser-run/types.ts +0 -565
  145. package/extensions/agent-browser/lib/orchestration/electron-host/index.ts +0 -855
  146. package/extensions/agent-browser/lib/orchestration/input-plan.ts +0 -375
  147. package/extensions/agent-browser/lib/orchestration/output-file.ts +0 -86
  148. package/extensions/agent-browser/lib/pi-tool-rendering.ts +0 -267
  149. package/extensions/agent-browser/lib/playbook.ts +0 -142
  150. package/extensions/agent-browser/lib/process.ts +0 -516
  151. package/extensions/agent-browser/lib/prompt-policy.ts +0 -105
  152. package/extensions/agent-browser/lib/results/action-recommendations.ts +0 -264
  153. package/extensions/agent-browser/lib/results/artifact-manifest.ts +0 -111
  154. package/extensions/agent-browser/lib/results/categories.ts +0 -106
  155. package/extensions/agent-browser/lib/results/confirmation.ts +0 -76
  156. package/extensions/agent-browser/lib/results/contracts.ts +0 -241
  157. package/extensions/agent-browser/lib/results/editable-ref-evidence.ts +0 -72
  158. package/extensions/agent-browser/lib/results/envelope.ts +0 -195
  159. package/extensions/agent-browser/lib/results/network-routes.ts +0 -83
  160. package/extensions/agent-browser/lib/results/network.ts +0 -78
  161. package/extensions/agent-browser/lib/results/next-actions.ts +0 -117
  162. package/extensions/agent-browser/lib/results/presentation/artifacts.ts +0 -588
  163. package/extensions/agent-browser/lib/results/presentation/batch.ts +0 -450
  164. package/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.ts +0 -67
  165. package/extensions/agent-browser/lib/results/presentation/common.ts +0 -53
  166. package/extensions/agent-browser/lib/results/presentation/content.ts +0 -36
  167. package/extensions/agent-browser/lib/results/presentation/diagnostics.ts +0 -923
  168. package/extensions/agent-browser/lib/results/presentation/errors.ts +0 -227
  169. package/extensions/agent-browser/lib/results/presentation/large-output.ts +0 -182
  170. package/extensions/agent-browser/lib/results/presentation/navigation.ts +0 -184
  171. package/extensions/agent-browser/lib/results/presentation/registry.ts +0 -242
  172. package/extensions/agent-browser/lib/results/presentation/semantic-action.ts +0 -131
  173. package/extensions/agent-browser/lib/results/presentation/skills.ts +0 -143
  174. package/extensions/agent-browser/lib/results/presentation.ts +0 -257
  175. package/extensions/agent-browser/lib/results/recovery-actions.ts +0 -139
  176. package/extensions/agent-browser/lib/results/recovery-next-actions.ts +0 -71
  177. package/extensions/agent-browser/lib/results/selector-recovery.ts +0 -320
  178. package/extensions/agent-browser/lib/results/snapshot-high-value-controls.ts +0 -273
  179. package/extensions/agent-browser/lib/results/snapshot-refs.ts +0 -100
  180. package/extensions/agent-browser/lib/results/snapshot-segments.ts +0 -366
  181. package/extensions/agent-browser/lib/results/snapshot-spill.ts +0 -63
  182. package/extensions/agent-browser/lib/results/snapshot.ts +0 -329
  183. package/extensions/agent-browser/lib/results/text.ts +0 -40
  184. package/extensions/agent-browser/lib/runtime.ts +0 -988
  185. package/extensions/agent-browser/lib/session-page-state.ts +0 -512
  186. package/extensions/agent-browser/lib/string-enum-schema.ts +0 -20
  187. package/extensions/agent-browser/lib/temp.ts +0 -577
  188. package/extensions/agent-browser/lib/web-search.ts +0 -728
  189. /package/{extensions/agent-browser/lib/orchestration/browser-run.ts → dist/extensions/agent-browser/lib/orchestration/browser-run.js} +0 -0
@@ -0,0 +1,762 @@
1
+ import { copyFile, mkdir } from "node:fs/promises";
2
+ import { dirname, resolve } from "node:path";
3
+ import { launchElectronApp } from "../../electron/launch.js";
4
+ import { pathExists } from "../../fs-utils.js";
5
+ import { getCompiledSemanticActionSessionPrefix } from "../../input-modes.js";
6
+ import { tryDirectAnchorDownload } from "./prepare/direct-anchor-download.js";
7
+ import { tryNetworkRequestsPageFilter } from "./prepare/network-page-filter.js";
8
+ import { tryContainerScroll, tryPageScrollTo } from "./prepare/scroll-shims.js";
9
+ import { trySnapshotFilter } from "./prepare/snapshot-filter.js";
10
+ import { getWaitAwareProcessTimeoutMs } from "./prepare/wait-timeouts.js";
11
+ import { getPersistentSessionArtifactStore } from "./session-artifacts.js";
12
+ import { buildAgentBrowserResultCategoryDetails } from "../../results.js";
13
+ import { buildSessionAwareStaleRefNextActions, buildSessionTabRecoveryNextActions } from "../../results/recovery-next-actions.js";
14
+ import { resolveVisibleRefActionFromSnapshot } from "../../results/selector-recovery.js";
15
+ import { extractRefSnapshotFromData } from "../../session-page-state.js";
16
+ import { buildExecutionPlan, createFreshSessionName, extractCommandTokens, redactInvocationArgs, } from "../../runtime.js";
17
+ import { applyOpenResultTabCorrection, buildManagedSessionOutcome, buildPinnedBatchPlan, buildSessionDetailFields, buildStaleRefPreflight, collectSessionTabSelection, getGuardedRefUsage, getTraceOwnerGuardMessage, runSessionCommandData, shouldPinSessionTabForCommand, } from "./session-state.js";
18
+ import { parseBatchStdinJsonArray } from "../batch-stdin.js";
19
+ import { buildElectronHostFailureResult, getElectronLaunchFailureCategory, redactRecoveryHint } from "./final-result.js";
20
+ import { prepareClickDispatchProbe } from "./click-dispatch.js";
21
+ import { collectScrollPositionSnapshot, validateQaAttachedPrecondition } from "./diagnostics.js";
22
+ import { getScreenshotPathTokenIndex } from "./artifact-paths.js";
23
+ import { findRequestedArtifactCloseViolation } from "./prompt-guards.js";
24
+ export function normalizeRunInput(input) {
25
+ const base = { redactedArgs: input.redactedArgs, toolArgs: input.toolArgs, toolStdin: input.toolStdin };
26
+ switch (input.kind) {
27
+ case "electron":
28
+ return { ...base, compiledElectron: input.compiledElectron, redactedCompiledElectron: input.redactedCompiledElectron };
29
+ case "job":
30
+ return { ...base, compiledJob: input.compiledJob, redactedCompiledJob: input.redactedCompiledJob };
31
+ case "networkSourceLookup":
32
+ return { ...base, compiledNetworkSourceLookup: input.compiledNetworkSourceLookup, redactedCompiledNetworkSourceLookup: input.redactedCompiledNetworkSourceLookup };
33
+ case "qa":
34
+ return { ...base, compiledJob: input.compiledJob, compiledQaPreset: input.compiledQaPreset, redactedCompiledJob: input.redactedCompiledJob, redactedCompiledQaPreset: input.redactedCompiledQaPreset };
35
+ case "semanticAction":
36
+ return { ...base, compiledSemanticAction: input.compiledSemanticAction, redactedCompiledSemanticAction: input.redactedCompiledSemanticAction };
37
+ case "sourceLookup":
38
+ return { ...base, compiledSourceLookup: input.compiledSourceLookup, redactedCompiledSourceLookup: input.redactedCompiledSourceLookup };
39
+ case "args":
40
+ return base;
41
+ }
42
+ }
43
+ export function buildInvocationPreview(effectiveArgs) {
44
+ const preview = effectiveArgs.join(" ");
45
+ return preview.length > 120 ? `${preview.slice(0, 117)}...` : preview;
46
+ }
47
+ function getArtifactParentPathTokenIndex(commandTokens) {
48
+ if (commandTokens[0] === "download" && commandTokens.length >= 3)
49
+ return 2;
50
+ if (commandTokens[0] === "pdf" && commandTokens.length >= 2)
51
+ return 1;
52
+ if (commandTokens[0] === "state" && commandTokens[1] === "save" && commandTokens.length >= 3)
53
+ return 2;
54
+ if (commandTokens[0] === "wait") {
55
+ const downloadIndex = commandTokens.findIndex((token) => token === "--download");
56
+ const pathIndex = downloadIndex >= 0 ? downloadIndex + 1 : -1;
57
+ if (pathIndex > 0 && typeof commandTokens[pathIndex] === "string" && !commandTokens[pathIndex].startsWith("-"))
58
+ return pathIndex;
59
+ }
60
+ return undefined;
61
+ }
62
+ async function ensureArtifactParentDirectory(commandTokens, cwd) {
63
+ const pathIndex = getArtifactParentPathTokenIndex(commandTokens);
64
+ if (pathIndex === undefined)
65
+ return;
66
+ const requestedPath = commandTokens[pathIndex];
67
+ if (!requestedPath)
68
+ return;
69
+ await mkdir(dirname(resolve(cwd, requestedPath)), { recursive: true });
70
+ }
71
+ async function normalizeScreenshotPathInTokens(commandTokens, cwd) {
72
+ const screenshotPathTokenIndex = getScreenshotPathTokenIndex(commandTokens);
73
+ if (screenshotPathTokenIndex === undefined) {
74
+ return { tokens: commandTokens };
75
+ }
76
+ const requestedPath = commandTokens[screenshotPathTokenIndex];
77
+ const absolutePath = resolve(cwd, requestedPath);
78
+ await mkdir(dirname(absolutePath), { recursive: true });
79
+ const tokens = [...commandTokens];
80
+ tokens[screenshotPathTokenIndex] = absolutePath;
81
+ const terminatorIndex = tokens.indexOf("--");
82
+ if (terminatorIndex >= 0) {
83
+ tokens.splice(terminatorIndex, 1);
84
+ }
85
+ return {
86
+ request: {
87
+ absolutePath,
88
+ path: requestedPath,
89
+ },
90
+ tokens,
91
+ };
92
+ }
93
+ async function prepareBatchScreenshotPaths(args, stdin, cwd) {
94
+ const commandTokens = extractCommandTokens(args);
95
+ if (commandTokens[0] !== "batch" || stdin === undefined) {
96
+ return undefined;
97
+ }
98
+ const parsed = parseBatchStdinJsonArray(stdin);
99
+ if (parsed.error || parsed.steps === undefined) {
100
+ return undefined;
101
+ }
102
+ let changed = false;
103
+ const batchScreenshotPathRequests = [];
104
+ const preparedSteps = await Promise.all(parsed.steps.map(async (step, index) => {
105
+ if (!Array.isArray(step) || !step.every((item) => typeof item === "string")) {
106
+ return step;
107
+ }
108
+ await ensureArtifactParentDirectory(step, cwd);
109
+ if (step[0] !== "screenshot") {
110
+ return step;
111
+ }
112
+ const normalized = await normalizeScreenshotPathInTokens(step, cwd);
113
+ batchScreenshotPathRequests[index] = normalized.request;
114
+ if (normalized.request) {
115
+ changed = true;
116
+ }
117
+ return normalized.tokens;
118
+ }));
119
+ return changed
120
+ ? {
121
+ args,
122
+ batchScreenshotPathRequests,
123
+ stdin: JSON.stringify(preparedSteps),
124
+ }
125
+ : undefined;
126
+ }
127
+ export async function prepareAgentBrowserArgs(args, stdin, cwd) {
128
+ const preparedBatch = await prepareBatchScreenshotPaths(args, stdin, cwd);
129
+ if (preparedBatch) {
130
+ return preparedBatch;
131
+ }
132
+ const commandTokens = extractCommandTokens(args);
133
+ await ensureArtifactParentDirectory(commandTokens, cwd);
134
+ const normalized = await normalizeScreenshotPathInTokens(commandTokens, cwd);
135
+ if (!normalized.request) {
136
+ return { args };
137
+ }
138
+ const commandStartIndex = args.length - commandTokens.length;
139
+ return {
140
+ args: [...args.slice(0, commandStartIndex), ...normalized.tokens],
141
+ screenshotPathRequest: normalized.request,
142
+ };
143
+ }
144
+ async function repairScreenshotData(options) {
145
+ const { cwd, data, request } = options;
146
+ const reportedPath = typeof data.path === "string" ? data.path : undefined;
147
+ const reportedAbsolutePath = reportedPath ? resolve(cwd, reportedPath) : undefined;
148
+ let status = await pathExists(request.absolutePath) ? "saved" : "missing";
149
+ let tempPath;
150
+ if (reportedAbsolutePath && reportedAbsolutePath !== request.absolutePath) {
151
+ tempPath = reportedAbsolutePath;
152
+ if (status === "missing" && await pathExists(reportedAbsolutePath)) {
153
+ await mkdir(dirname(request.absolutePath), { recursive: true });
154
+ await copyFile(reportedAbsolutePath, request.absolutePath);
155
+ status = "repaired-from-temp";
156
+ }
157
+ }
158
+ return {
159
+ data: {
160
+ ...data,
161
+ path: request.absolutePath,
162
+ },
163
+ request: {
164
+ ...request,
165
+ status,
166
+ tempPath,
167
+ },
168
+ };
169
+ }
170
+ export { repairScreenshotData };
171
+ const DIALOG_COMMAND_PROCESS_TIMEOUT_MS = 5_000;
172
+ const DIALOG_COMMAND_PROCESS_TIMEOUT_ENV = "PI_AGENT_BROWSER_DIALOG_PROCESS_TIMEOUT_MS";
173
+ const LIKELY_DIALOG_TRIGGER_PROCESS_TIMEOUT_MS = 8_000;
174
+ const LIKELY_DIALOG_TRIGGER_PROCESS_TIMEOUT_ENV = "PI_AGENT_BROWSER_DIALOG_TRIGGER_PROCESS_TIMEOUT_MS";
175
+ const DIALOG_TRIGGER_TEXT_PATTERN = /\b(?:alert|confirm|dialog|prompt)\b/i;
176
+ function getPositiveIntegerEnv(name) {
177
+ const value = process.env[name];
178
+ if (!value || !/^\d+$/.test(value.trim()))
179
+ return undefined;
180
+ const parsed = Number(value.trim());
181
+ return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined;
182
+ }
183
+ function getRefIdsFromDirectCommand(commandTokens) {
184
+ return [...new Set(getGuardedRefUsage(commandTokens))];
185
+ }
186
+ function commandTextLooksLikeDialogTrigger(commandTokens, refSnapshot) {
187
+ if (commandTokens.some((token) => DIALOG_TRIGGER_TEXT_PATTERN.test(token)))
188
+ return true;
189
+ for (const refId of getRefIdsFromDirectCommand(commandTokens)) {
190
+ const ref = refSnapshot?.refs?.[refId];
191
+ if (ref && DIALOG_TRIGGER_TEXT_PATTERN.test(`${ref.role} ${ref.name}`))
192
+ return true;
193
+ }
194
+ return false;
195
+ }
196
+ function getDialogAwareProcessTimeoutMs(commandTokens, refSnapshot, stdin) {
197
+ const command = commandTokens[0];
198
+ if (command === "dialog")
199
+ return getPositiveIntegerEnv(DIALOG_COMMAND_PROCESS_TIMEOUT_ENV) ?? DIALOG_COMMAND_PROCESS_TIMEOUT_MS;
200
+ if (command === "eval" && typeof stdin === "string" && DIALOG_TRIGGER_TEXT_PATTERN.test(stdin))
201
+ return getPositiveIntegerEnv(LIKELY_DIALOG_TRIGGER_PROCESS_TIMEOUT_ENV) ?? LIKELY_DIALOG_TRIGGER_PROCESS_TIMEOUT_MS;
202
+ if ((command === "click" || command === "tap" || (command === "find" && commandTokens.includes("click"))) && commandTextLooksLikeDialogTrigger(commandTokens, refSnapshot))
203
+ return getPositiveIntegerEnv(LIKELY_DIALOG_TRIGGER_PROCESS_TIMEOUT_ENV) ?? LIKELY_DIALOG_TRIGGER_PROCESS_TIMEOUT_MS;
204
+ return undefined;
205
+ }
206
+ function describeRef(refSnapshot, refId) {
207
+ const ref = refSnapshot?.refs?.[refId];
208
+ return ref ? `${ref.role} ${JSON.stringify(ref.name)}` : "not present";
209
+ }
210
+ function getSamePageFreshnessPreflightFailure(options) {
211
+ if (options.commandTokens[0] === "batch")
212
+ return undefined;
213
+ const refIds = getRefIdsFromDirectCommand(options.commandTokens);
214
+ if (refIds.length === 0)
215
+ return undefined;
216
+ const previousUrl = options.previousSnapshot.target?.url;
217
+ const currentUrl = options.currentSnapshot.target?.url;
218
+ if (!previousUrl || !currentUrl || previousUrl !== currentUrl || currentUrl === "about:blank")
219
+ return undefined;
220
+ const mismatchedRefs = refIds.filter((refId) => {
221
+ const previous = options.previousSnapshot.refs?.[refId];
222
+ const current = options.currentSnapshot.refs?.[refId];
223
+ if (!options.currentSnapshot.refIds.includes(refId))
224
+ return true;
225
+ if (!previous || !current)
226
+ return previous !== current;
227
+ return previous.role !== current.role || previous.name !== current.name;
228
+ });
229
+ if (mismatchedRefs.length === 0)
230
+ return undefined;
231
+ const refText = mismatchedRefs.map((refId) => `@${refId}`).join(", ");
232
+ const evidence = mismatchedRefs.map((refId) => `@${refId}: previous ${describeRef(options.previousSnapshot, refId)}, current ${describeRef(options.currentSnapshot, refId)}`).join("; ");
233
+ return {
234
+ message: `Ref ${refText} no longer matches the latest same-page snapshot. The page likely rerendered after the previous snapshot; run snapshot -i and retry with current refs. Evidence: ${evidence}.`,
235
+ refIds: mismatchedRefs,
236
+ };
237
+ }
238
+ async function collectSamePageRefFreshnessPreflight(options) {
239
+ if (!options.previousSnapshot || !options.sessionName || options.commandTokens[0] === "batch" || getRefIdsFromDirectCommand(options.commandTokens).length === 0)
240
+ return undefined;
241
+ const previousUrl = options.previousSnapshot.target?.url;
242
+ const currentTargetUrl = options.currentTarget?.url;
243
+ if (currentTargetUrl === "about:blank" || (previousUrl && currentTargetUrl && previousUrl !== currentTargetUrl))
244
+ return undefined;
245
+ const snapshotData = await runSessionCommandData({ args: ["snapshot", "-i"], cwd: options.cwd, sessionName: options.sessionName, signal: options.signal });
246
+ const currentSnapshot = extractRefSnapshotFromData(snapshotData);
247
+ if (!currentSnapshot)
248
+ return undefined;
249
+ const snapshotWithTarget = { ...currentSnapshot, target: currentSnapshot.target ?? options.currentTarget };
250
+ const mismatch = getSamePageFreshnessPreflightFailure({ commandTokens: options.commandTokens, currentSnapshot: snapshotWithTarget, previousSnapshot: options.previousSnapshot });
251
+ if (!mismatch)
252
+ return undefined;
253
+ return { message: mismatch.message, refIds: mismatch.refIds, snapshot: snapshotWithTarget };
254
+ }
255
+ function isPasswordStdinAuthSave(options) {
256
+ return options.command === "auth" && options.commandTokens[1] === "save" && options.commandTokens.includes("--password-stdin");
257
+ }
258
+ export function getExactSensitiveStdinValues(options) {
259
+ if (options.stdin === undefined || !isPasswordStdinAuthSave(options)) {
260
+ return [];
261
+ }
262
+ return [...new Set([options.stdin, options.stdin.trimEnd(), options.stdin.trim()].filter((value) => value.length > 0))];
263
+ }
264
+ export function validateStdinCommandContract(options) {
265
+ if (options.stdin === undefined) {
266
+ return undefined;
267
+ }
268
+ if (options.command === "batch") {
269
+ return undefined;
270
+ }
271
+ if (options.command === "eval" && options.commandTokens.includes("--stdin")) {
272
+ return undefined;
273
+ }
274
+ if (isPasswordStdinAuthSave(options)) {
275
+ return undefined;
276
+ }
277
+ const commandLabel = options.command ? `\`${options.command}\`` : "the requested command";
278
+ return `agent_browser stdin is only supported for \`batch\`, \`eval --stdin\`, and \`auth save --password-stdin\`; remove stdin from ${commandLabel} or use one of those command forms.`;
279
+ }
280
+ export async function resolveSemanticActionVisibleRefArgs(options) {
281
+ if (!options.compiled || !options.sessionName || options.compiled.locator !== "role" || !["check", "click", "fill"].includes(options.compiled.action))
282
+ return undefined;
283
+ const snapshotData = await runSessionCommandData({ args: ["snapshot", "-i"], cwd: options.cwd, sessionName: options.sessionName, signal: options.signal });
284
+ const resolution = resolveVisibleRefActionFromSnapshot({ allowFill: true, compiledAction: options.compiled, snapshotData });
285
+ if (!resolution)
286
+ return undefined;
287
+ return { args: [...getCompiledSemanticActionSessionPrefix(options.compiled), ...resolution.args], snapshot: resolution.snapshot };
288
+ }
289
+ export async function prepareBrowserRun(options) {
290
+ const { cwd, implicitSessionIdleTimeoutMs, onUpdate, params, signal, state } = options;
291
+ const { sessionPageState, traceOwners, managedSessionBaseName, ephemeralSessionSeed } = state;
292
+ let freshSessionOrdinal = state.freshSessionOrdinal;
293
+ const { compiledElectron, compiledJob, compiledNetworkSourceLookup, compiledQaPreset, compiledSemanticAction, compiledSourceLookup, redactedArgs, redactedCompiledElectron, redactedCompiledJob, redactedCompiledNetworkSourceLookup, redactedCompiledQaPreset, redactedCompiledSemanticAction, redactedCompiledSourceLookup, toolArgs, toolStdin, } = normalizeRunInput(options.input);
294
+ let runtimeToolArgs = toolArgs;
295
+ let runtimeToolStdin = toolStdin;
296
+ let electronLaunch;
297
+ const sessionMode = compiledElectron?.action === "launch" ? "fresh" : params.sessionMode ?? "auto";
298
+ const freshSessionName = createFreshSessionName(managedSessionBaseName, ephemeralSessionSeed, freshSessionOrdinal + 1);
299
+ if (compiledElectron?.action === "launch") {
300
+ const launchResult = await launchElectronApp(compiledElectron);
301
+ if (!launchResult.ok) {
302
+ const managedSessionOutcome = buildManagedSessionOutcome({
303
+ activeAfter: state.managedSessionActive,
304
+ activeBefore: state.managedSessionActive,
305
+ attemptedSessionName: freshSessionName,
306
+ command: "connect",
307
+ currentSessionName: state.managedSessionName,
308
+ previousSessionName: state.managedSessionName,
309
+ sessionMode: "fresh",
310
+ succeeded: false,
311
+ });
312
+ return { kind: "early-result", result: buildElectronHostFailureResult({
313
+ compiledElectron: redactedCompiledElectron ?? compiledElectron,
314
+ errorText: launchResult.failure.error,
315
+ failureCategory: getElectronLaunchFailureCategory(launchResult.failure),
316
+ launchFailure: launchResult.failure,
317
+ managedSessionOutcome,
318
+ status: launchResult.failure.reason,
319
+ }) };
320
+ }
321
+ electronLaunch = launchResult.value;
322
+ runtimeToolArgs = ["connect", electronLaunch.connectArg];
323
+ runtimeToolStdin = undefined;
324
+ }
325
+ const preparedArgs = await prepareAgentBrowserArgs(runtimeToolArgs, runtimeToolStdin, cwd);
326
+ const userRequestedJson = runtimeToolArgs.includes("--json");
327
+ let executionPlan = buildExecutionPlan(preparedArgs.args, {
328
+ freshSessionName,
329
+ managedSessionActive: state.managedSessionActive,
330
+ managedSessionName: state.managedSessionName,
331
+ sessionMode,
332
+ });
333
+ let semanticActionVisibleRefResolution;
334
+ if (!executionPlan.validationError && executionPlan.managedSessionName !== freshSessionName) {
335
+ semanticActionVisibleRefResolution = await resolveSemanticActionVisibleRefArgs({
336
+ compiled: compiledSemanticAction,
337
+ cwd,
338
+ sessionName: executionPlan.sessionName,
339
+ signal,
340
+ });
341
+ if (semanticActionVisibleRefResolution) {
342
+ executionPlan = buildExecutionPlan(semanticActionVisibleRefResolution.args, {
343
+ freshSessionName,
344
+ managedSessionActive: state.managedSessionActive,
345
+ managedSessionName: state.managedSessionName,
346
+ sessionMode,
347
+ });
348
+ }
349
+ }
350
+ const redactedEffectiveArgs = redactInvocationArgs(executionPlan.effectiveArgs);
351
+ const redactedRecoveryHint = redactRecoveryHint(executionPlan.recoveryHint);
352
+ const compatibilityWorkaround = executionPlan.compatibilityWorkaround;
353
+ const statePatch = executionPlan.managedSessionName === freshSessionName
354
+ ? { freshSessionOrdinal: freshSessionOrdinal + 1 }
355
+ : {};
356
+ if (executionPlan.managedSessionName === freshSessionName) {
357
+ freshSessionOrdinal += 1;
358
+ }
359
+ if (executionPlan.validationError) {
360
+ return { kind: "early-result", statePatch, result: {
361
+ content: [{ type: "text", text: executionPlan.validationError }],
362
+ details: {
363
+ args: redactedArgs,
364
+ compiledElectron: redactedCompiledElectron,
365
+ compiledJob: redactedCompiledJob,
366
+ compiledQaPreset: redactedCompiledQaPreset,
367
+ compiledSourceLookup: redactedCompiledSourceLookup,
368
+ compiledNetworkSourceLookup: redactedCompiledNetworkSourceLookup,
369
+ invalidValueFlag: executionPlan.invalidValueFlag,
370
+ sessionMode,
371
+ sessionRecoveryHint: redactedRecoveryHint,
372
+ startupScopedFlags: executionPlan.startupScopedFlags,
373
+ ...buildAgentBrowserResultCategoryDetails({ args: redactedArgs, command: executionPlan.commandInfo.command, errorText: executionPlan.validationError, succeeded: false, validationError: executionPlan.validationError }),
374
+ validationError: executionPlan.validationError,
375
+ },
376
+ isError: true,
377
+ } };
378
+ }
379
+ const commandTokens = semanticActionVisibleRefResolution ? extractCommandTokens(semanticActionVisibleRefResolution.args) : extractCommandTokens(preparedArgs.args);
380
+ const exactSensitiveValues = getExactSensitiveStdinValues({
381
+ command: executionPlan.commandInfo.command,
382
+ commandTokens,
383
+ stdin: runtimeToolStdin,
384
+ });
385
+ const traceOwnerGuardMessage = getTraceOwnerGuardMessage({
386
+ command: executionPlan.commandInfo.command,
387
+ sessionName: executionPlan.sessionName,
388
+ subcommand: executionPlan.commandInfo.subcommand,
389
+ traceOwners,
390
+ });
391
+ if (traceOwnerGuardMessage) {
392
+ return { kind: "early-result", statePatch, result: {
393
+ content: [{ type: "text", text: traceOwnerGuardMessage }],
394
+ details: {
395
+ args: redactedArgs,
396
+ command: executionPlan.commandInfo.command,
397
+ compatibilityWorkaround,
398
+ effectiveArgs: redactedEffectiveArgs,
399
+ sessionMode,
400
+ ...buildAgentBrowserResultCategoryDetails({ args: redactedEffectiveArgs, command: executionPlan.commandInfo.command, errorText: traceOwnerGuardMessage, succeeded: false, validationError: traceOwnerGuardMessage }),
401
+ validationError: traceOwnerGuardMessage,
402
+ ...buildSessionDetailFields(executionPlan.sessionName, executionPlan.usedImplicitSession),
403
+ },
404
+ isError: true,
405
+ } };
406
+ }
407
+ const stdinValidationError = validateStdinCommandContract({
408
+ command: executionPlan.commandInfo.command,
409
+ commandTokens,
410
+ stdin: runtimeToolStdin,
411
+ });
412
+ if (stdinValidationError) {
413
+ return { kind: "early-result", statePatch, result: {
414
+ content: [{ type: "text", text: stdinValidationError }],
415
+ details: {
416
+ args: redactedArgs,
417
+ command: executionPlan.commandInfo.command,
418
+ compatibilityWorkaround,
419
+ effectiveArgs: redactedEffectiveArgs,
420
+ sessionMode,
421
+ ...buildAgentBrowserResultCategoryDetails({ args: redactedEffectiveArgs, command: executionPlan.commandInfo.command, errorText: stdinValidationError, succeeded: false, validationError: stdinValidationError }),
422
+ validationError: stdinValidationError,
423
+ ...buildSessionDetailFields(executionPlan.sessionName, executionPlan.usedImplicitSession),
424
+ },
425
+ isError: true,
426
+ } };
427
+ }
428
+ const priorSessionPageState = sessionPageState.get(executionPlan.sessionName);
429
+ const priorSessionTabTarget = priorSessionPageState.tabTarget;
430
+ const sessionTabPinningReason = priorSessionPageState.pinningReason;
431
+ const priorRefSnapshotState = priorSessionPageState.refSnapshot;
432
+ const priorRefSnapshotInvalidation = priorSessionPageState.refSnapshotInvalidation;
433
+ const resolvedSemanticActionRefSnapshot = semanticActionVisibleRefResolution?.snapshot
434
+ ? { ...semanticActionVisibleRefResolution.snapshot, target: semanticActionVisibleRefResolution.snapshot.target ?? priorSessionTabTarget }
435
+ : undefined;
436
+ const promptRefSnapshot = resolvedSemanticActionRefSnapshot ?? priorRefSnapshotState;
437
+ const requestedArtifactCloseViolation = await findRequestedArtifactCloseViolation({ artifactManifest: state.artifactManifest, command: executionPlan.commandInfo.command, cwd, promptPolicy: options.promptPolicy });
438
+ if (requestedArtifactCloseViolation) {
439
+ return { kind: "early-result", statePatch, result: {
440
+ content: [{ type: "text", text: requestedArtifactCloseViolation.message }],
441
+ details: {
442
+ args: redactedArgs,
443
+ command: executionPlan.commandInfo.command,
444
+ compatibilityWorkaround,
445
+ effectiveArgs: redactedEffectiveArgs,
446
+ promptGuard: requestedArtifactCloseViolation,
447
+ sessionMode,
448
+ ...buildAgentBrowserResultCategoryDetails({ args: redactedEffectiveArgs, command: executionPlan.commandInfo.command, errorText: requestedArtifactCloseViolation.message, failureCategory: "policy-blocked", succeeded: false, validationError: requestedArtifactCloseViolation.message }),
449
+ validationError: requestedArtifactCloseViolation.message,
450
+ ...buildSessionDetailFields(executionPlan.sessionName, executionPlan.usedImplicitSession),
451
+ },
452
+ isError: true,
453
+ } };
454
+ }
455
+ const staleRefPreflight = buildStaleRefPreflight({
456
+ commandTokens,
457
+ currentTarget: priorSessionTabTarget,
458
+ refSnapshot: resolvedSemanticActionRefSnapshot ?? priorRefSnapshotState,
459
+ refSnapshotInvalidation: resolvedSemanticActionRefSnapshot ? undefined : priorRefSnapshotInvalidation,
460
+ stdin: runtimeToolStdin,
461
+ });
462
+ if (staleRefPreflight) {
463
+ return { kind: "early-result", statePatch, result: {
464
+ content: [{ type: "text", text: staleRefPreflight.message }],
465
+ details: {
466
+ args: redactedArgs,
467
+ command: executionPlan.commandInfo.command,
468
+ compatibilityWorkaround,
469
+ effectiveArgs: redactedEffectiveArgs,
470
+ nextActions: buildSessionAwareStaleRefNextActions(executionPlan.sessionName),
471
+ refIds: staleRefPreflight.refIds,
472
+ refSnapshot: staleRefPreflight.snapshot,
473
+ refSnapshotInvalidation: staleRefPreflight.snapshotInvalidation,
474
+ sessionMode,
475
+ ...buildAgentBrowserResultCategoryDetails({ args: redactedEffectiveArgs, command: executionPlan.commandInfo.command, errorText: staleRefPreflight.message, failureCategory: "stale-ref", succeeded: false }),
476
+ ...buildSessionDetailFields(executionPlan.sessionName, executionPlan.usedImplicitSession),
477
+ },
478
+ isError: true,
479
+ } };
480
+ }
481
+ const samePageRefFreshnessPreflight = await collectSamePageRefFreshnessPreflight({
482
+ commandTokens,
483
+ cwd,
484
+ currentTarget: priorSessionTabTarget,
485
+ previousSnapshot: resolvedSemanticActionRefSnapshot ? undefined : priorRefSnapshotState,
486
+ sessionName: executionPlan.sessionName,
487
+ signal,
488
+ });
489
+ if (samePageRefFreshnessPreflight) {
490
+ if (samePageRefFreshnessPreflight.snapshot && executionPlan.sessionName) {
491
+ sessionPageState.applyRefSnapshot({ fallbackTarget: priorSessionTabTarget, sessionName: executionPlan.sessionName, snapshot: samePageRefFreshnessPreflight.snapshot, update: options.sessionPageStateUpdate });
492
+ }
493
+ return { kind: "early-result", statePatch, result: {
494
+ content: [{ type: "text", text: samePageRefFreshnessPreflight.message }],
495
+ details: {
496
+ args: redactedArgs,
497
+ command: executionPlan.commandInfo.command,
498
+ compatibilityWorkaround,
499
+ effectiveArgs: redactedEffectiveArgs,
500
+ nextActions: buildSessionAwareStaleRefNextActions(executionPlan.sessionName),
501
+ refIds: samePageRefFreshnessPreflight.refIds,
502
+ refSnapshot: samePageRefFreshnessPreflight.snapshot,
503
+ sessionMode,
504
+ ...buildAgentBrowserResultCategoryDetails({ args: redactedEffectiveArgs, command: executionPlan.commandInfo.command, errorText: samePageRefFreshnessPreflight.message, failureCategory: "stale-ref", succeeded: false }),
505
+ ...buildSessionDetailFields(executionPlan.sessionName, executionPlan.usedImplicitSession),
506
+ },
507
+ isError: true,
508
+ } };
509
+ }
510
+ if (compiledQaPreset?.checks.attached) {
511
+ const qaAttachedPrecondition = await validateQaAttachedPrecondition({
512
+ cwd,
513
+ sessionName: executionPlan.sessionName,
514
+ signal,
515
+ });
516
+ if (qaAttachedPrecondition) {
517
+ return { kind: "early-result", statePatch, result: {
518
+ content: [{ type: "text", text: qaAttachedPrecondition.error }],
519
+ details: {
520
+ args: redactedArgs,
521
+ compiledQaPreset: redactedCompiledQaPreset,
522
+ compatibilityWorkaround,
523
+ effectiveArgs: redactedEffectiveArgs,
524
+ nextActions: qaAttachedPrecondition.nextActions,
525
+ sessionMode,
526
+ ...buildAgentBrowserResultCategoryDetails({ args: redactedEffectiveArgs, command: executionPlan.commandInfo.command, errorText: qaAttachedPrecondition.error, succeeded: false, validationError: qaAttachedPrecondition.error }),
527
+ validationError: qaAttachedPrecondition.error,
528
+ ...buildSessionDetailFields(executionPlan.sessionName, executionPlan.usedImplicitSession),
529
+ },
530
+ isError: true,
531
+ } };
532
+ }
533
+ }
534
+ const persistentArtifactStore = getPersistentSessionArtifactStore(options.ctx);
535
+ const snapshotFilter = await trySnapshotFilter({
536
+ artifactManifest: state.artifactManifest,
537
+ commandTokens,
538
+ compatibilityWorkaround,
539
+ cwd,
540
+ effectiveArgs: redactedEffectiveArgs,
541
+ persistentArtifactStore,
542
+ previousRefSnapshot: priorRefSnapshotState,
543
+ redactedArgs,
544
+ sessionMode,
545
+ sessionName: executionPlan.sessionName,
546
+ sessionPageState,
547
+ sessionPageStateUpdate: options.sessionPageStateUpdate,
548
+ signal,
549
+ usedImplicitSession: executionPlan.usedImplicitSession,
550
+ });
551
+ if (snapshotFilter)
552
+ return { kind: "early-result", statePatch: { ...statePatch, artifactManifest: snapshotFilter.artifactManifest ?? statePatch.artifactManifest }, result: snapshotFilter.result };
553
+ const networkRequestsPageFilter = await tryNetworkRequestsPageFilter({
554
+ commandTokens,
555
+ compatibilityWorkaround,
556
+ cwd,
557
+ effectiveArgs: redactedEffectiveArgs,
558
+ redactedArgs,
559
+ sessionMode,
560
+ sessionName: executionPlan.sessionName,
561
+ signal,
562
+ usedImplicitSession: executionPlan.usedImplicitSession,
563
+ });
564
+ if (networkRequestsPageFilter)
565
+ return { kind: "early-result", statePatch, result: networkRequestsPageFilter };
566
+ const containerScroll = await tryContainerScroll({
567
+ commandTokens,
568
+ compatibilityWorkaround,
569
+ cwd,
570
+ effectiveArgs: redactedEffectiveArgs,
571
+ redactedArgs,
572
+ sessionMode,
573
+ sessionName: executionPlan.sessionName,
574
+ signal,
575
+ usedImplicitSession: executionPlan.usedImplicitSession,
576
+ });
577
+ if (containerScroll)
578
+ return { kind: "early-result", statePatch, result: containerScroll };
579
+ const pageScrollTo = await tryPageScrollTo({
580
+ commandTokens,
581
+ compatibilityWorkaround,
582
+ cwd,
583
+ effectiveArgs: redactedEffectiveArgs,
584
+ redactedArgs,
585
+ sessionMode,
586
+ sessionName: executionPlan.sessionName,
587
+ signal,
588
+ usedImplicitSession: executionPlan.usedImplicitSession,
589
+ });
590
+ if (pageScrollTo)
591
+ return { kind: "early-result", statePatch, result: pageScrollTo };
592
+ const directAnchorDownload = await tryDirectAnchorDownload({
593
+ artifactManifest: state.artifactManifest,
594
+ commandTokens,
595
+ compatibilityWorkaround,
596
+ cwd,
597
+ effectiveArgs: redactedEffectiveArgs,
598
+ redactedArgs,
599
+ sessionMode,
600
+ sessionName: executionPlan.sessionName,
601
+ signal,
602
+ usedImplicitSession: executionPlan.usedImplicitSession,
603
+ });
604
+ if (directAnchorDownload)
605
+ return { kind: "early-result", statePatch: { ...statePatch, artifactManifest: directAnchorDownload.artifactManifest ?? statePatch.artifactManifest }, result: directAnchorDownload.result };
606
+ let pinnedBatchUnwrapMode;
607
+ let includePinnedNavigationSummary = false;
608
+ let sessionTabCorrection;
609
+ let processArgs = executionPlan.effectiveArgs;
610
+ let processStdin = preparedArgs.stdin ?? runtimeToolStdin;
611
+ if (priorSessionTabTarget &&
612
+ shouldPinSessionTabForCommand({
613
+ command: executionPlan.commandInfo.command,
614
+ commandTokens,
615
+ pinningRequired: sessionTabPinningReason !== undefined,
616
+ sessionName: executionPlan.sessionName,
617
+ stdin: runtimeToolStdin,
618
+ })) {
619
+ const plannedSessionTabSelection = await collectSessionTabSelection({
620
+ cwd,
621
+ sessionName: executionPlan.sessionName,
622
+ signal,
623
+ target: priorSessionTabTarget,
624
+ });
625
+ if (plannedSessionTabSelection && executionPlan.sessionName) {
626
+ if (executionPlan.commandInfo.command === "eval" && runtimeToolStdin !== undefined) {
627
+ const appliedSessionTabSelection = await applyOpenResultTabCorrection({
628
+ correction: plannedSessionTabSelection,
629
+ cwd,
630
+ sessionName: executionPlan.sessionName,
631
+ signal,
632
+ });
633
+ if (!appliedSessionTabSelection) {
634
+ const error = "agent-browser could not re-select the intended tab before running the command.";
635
+ return { kind: "early-result", statePatch, result: {
636
+ content: [{ type: "text", text: error }],
637
+ details: {
638
+ args: redactedArgs,
639
+ command: executionPlan.commandInfo.command,
640
+ compatibilityWorkaround,
641
+ effectiveArgs: redactedEffectiveArgs,
642
+ sessionMode,
643
+ sessionTabCorrection: plannedSessionTabSelection,
644
+ ...buildAgentBrowserResultCategoryDetails({ args: redactedEffectiveArgs, command: executionPlan.commandInfo.command, errorText: error, failureCategory: "tab-drift", succeeded: false, tabDrift: true, validationError: error }),
645
+ nextActions: buildSessionTabRecoveryNextActions({
646
+ kind: "tab-drift",
647
+ resultCategory: "failure",
648
+ sessionName: executionPlan.sessionName,
649
+ tabCorrection: plannedSessionTabSelection,
650
+ target: priorSessionTabTarget,
651
+ }),
652
+ validationError: error,
653
+ ...buildSessionDetailFields(executionPlan.sessionName, executionPlan.usedImplicitSession),
654
+ },
655
+ isError: true,
656
+ } };
657
+ }
658
+ sessionTabCorrection = appliedSessionTabSelection;
659
+ }
660
+ else {
661
+ const pinnedBatchPlan = buildPinnedBatchPlan({
662
+ command: executionPlan.commandInfo.command,
663
+ commandTokens,
664
+ selectedTab: plannedSessionTabSelection.selectedTab,
665
+ stdin: runtimeToolStdin,
666
+ });
667
+ if (pinnedBatchPlan && "error" in pinnedBatchPlan) {
668
+ return { kind: "early-result", statePatch, result: {
669
+ content: [{ type: "text", text: pinnedBatchPlan.error }],
670
+ details: {
671
+ args: redactedArgs,
672
+ command: executionPlan.commandInfo.command,
673
+ compatibilityWorkaround,
674
+ effectiveArgs: redactedEffectiveArgs,
675
+ sessionMode,
676
+ sessionTabCorrection: plannedSessionTabSelection,
677
+ ...buildAgentBrowserResultCategoryDetails({ args: redactedEffectiveArgs, command: executionPlan.commandInfo.command, errorText: pinnedBatchPlan.error, failureCategory: "tab-drift", succeeded: false, tabDrift: true, validationError: pinnedBatchPlan.error }),
678
+ nextActions: buildSessionTabRecoveryNextActions({
679
+ kind: "tab-drift",
680
+ resultCategory: "failure",
681
+ sessionName: executionPlan.sessionName,
682
+ tabCorrection: plannedSessionTabSelection,
683
+ target: priorSessionTabTarget,
684
+ }),
685
+ validationError: pinnedBatchPlan.error,
686
+ ...buildSessionDetailFields(executionPlan.sessionName, executionPlan.usedImplicitSession),
687
+ },
688
+ isError: true,
689
+ } };
690
+ }
691
+ if (pinnedBatchPlan) {
692
+ sessionTabCorrection = plannedSessionTabSelection;
693
+ processArgs = ["--json", "--session", executionPlan.sessionName, "batch"];
694
+ processStdin = JSON.stringify(pinnedBatchPlan.steps);
695
+ includePinnedNavigationSummary = pinnedBatchPlan.includeNavigationSummary;
696
+ pinnedBatchUnwrapMode = pinnedBatchPlan.unwrapMode;
697
+ }
698
+ }
699
+ }
700
+ }
701
+ const clickDispatchProbe = pinnedBatchUnwrapMode === undefined && compiledElectron === undefined
702
+ ? await prepareClickDispatchProbe({ commandTokens, cwd, refSnapshot: promptRefSnapshot, sessionName: executionPlan.sessionName, signal })
703
+ : undefined;
704
+ const processTimeoutMs = options.params.timeoutMs ?? getDialogAwareProcessTimeoutMs(commandTokens, promptRefSnapshot, processStdin) ?? getWaitAwareProcessTimeoutMs(commandTokens, processStdin);
705
+ const redactedProcessArgs = redactInvocationArgs(processArgs);
706
+ const shouldProbeScrollNoop = executionPlan.commandInfo.command === "scroll" && executionPlan.startupScopedFlags.length === 0;
707
+ const scrollPositionBefore = shouldProbeScrollNoop
708
+ ? await collectScrollPositionSnapshot({ cwd, sessionName: executionPlan.sessionName, signal })
709
+ : undefined;
710
+ onUpdate?.({
711
+ content: [{ type: "text", text: `Running agent-browser ${buildInvocationPreview(redactedProcessArgs)}` }],
712
+ details: {
713
+ compatibilityWorkaround,
714
+ effectiveArgs: redactedProcessArgs,
715
+ sessionMode,
716
+ sessionTabCorrection,
717
+ ...buildSessionDetailFields(executionPlan.sessionName, executionPlan.usedImplicitSession),
718
+ },
719
+ });
720
+ return { kind: "ready", prepared: {
721
+ commandTokens,
722
+ compiledElectron,
723
+ compiledJob,
724
+ compiledNetworkSourceLookup,
725
+ compiledQaPreset,
726
+ compiledSemanticAction,
727
+ compiledSourceLookup,
728
+ compatibilityWorkaround,
729
+ clickDispatchProbe,
730
+ electronLaunch,
731
+ exactSensitiveValues,
732
+ executionPlan,
733
+ includePinnedNavigationSummary,
734
+ pinnedBatchUnwrapMode,
735
+ preparedArgs,
736
+ priorRefSnapshotState,
737
+ priorSessionTabTarget,
738
+ processArgs,
739
+ processStdin,
740
+ processTimeoutMs,
741
+ redactedArgs,
742
+ redactedCompiledElectron,
743
+ redactedCompiledJob,
744
+ redactedCompiledNetworkSourceLookup,
745
+ redactedCompiledQaPreset,
746
+ redactedCompiledSemanticAction,
747
+ redactedCompiledSourceLookup,
748
+ redactedEffectiveArgs,
749
+ redactedProcessArgs,
750
+ redactedRecoveryHint,
751
+ resolvedSemanticActionRefSnapshot,
752
+ runtimeToolArgs,
753
+ runtimeToolStdin,
754
+ scrollPositionBefore,
755
+ sessionMode,
756
+ sessionTabCorrection,
757
+ sessionTabPinningReason,
758
+ shouldProbeScrollNoop,
759
+ statePatch,
760
+ userRequestedJson,
761
+ } };
762
+ }