pi-agent-browser-native 0.2.77 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/README.md +69 -35
  3. package/dist/extensions/agent-browser/index.js +911 -121
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +35 -8
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +48 -7
  6. package/dist/extensions/agent-browser/lib/batch-lifecycle.js +71 -0
  7. package/dist/extensions/agent-browser/lib/command-policy.js +1 -6
  8. package/dist/extensions/agent-browser/lib/command-taxonomy.js +35 -8
  9. package/dist/extensions/agent-browser/lib/config-policy.js +0 -5
  10. package/dist/extensions/agent-browser/lib/config.js +0 -6
  11. package/dist/extensions/agent-browser/lib/electron/cdp.js +6 -7
  12. package/dist/extensions/agent-browser/lib/electron/cleanup.js +0 -7
  13. package/dist/extensions/agent-browser/lib/electron/discovery.js +0 -7
  14. package/dist/extensions/agent-browser/lib/electron/launch.js +0 -7
  15. package/dist/extensions/agent-browser/lib/input-modes/electron.js +0 -5
  16. package/dist/extensions/agent-browser/lib/input-modes/job.js +61 -9
  17. package/dist/extensions/agent-browser/lib/input-modes/lookups.js +2 -7
  18. package/dist/extensions/agent-browser/lib/input-modes/params.js +23 -29
  19. package/dist/extensions/agent-browser/lib/input-modes/script.js +462 -0
  20. package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +51 -17
  21. package/dist/extensions/agent-browser/lib/input-modes/shared.js +0 -5
  22. package/dist/extensions/agent-browser/lib/input-modes/types.js +0 -5
  23. package/dist/extensions/agent-browser/lib/json-schema.js +0 -5
  24. package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +12 -5
  25. package/dist/extensions/agent-browser/lib/managed-session-capabilities.js +0 -2
  26. package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +3 -4
  27. package/dist/extensions/agent-browser/lib/managed-session-restore.js +55 -48
  28. package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +2 -9
  29. package/dist/extensions/agent-browser/lib/managed-session-state-policy.js +48 -36
  30. package/dist/extensions/agent-browser/lib/managed-session-storage.js +50 -29
  31. package/dist/extensions/agent-browser/lib/navigation-policy.js +0 -5
  32. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +26 -5
  33. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +110 -30
  34. package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +2 -1
  35. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +27 -26
  36. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +58 -33
  37. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +2 -1
  38. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +22 -14
  39. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.js +1 -1
  40. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +1 -1
  41. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +1 -1
  42. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +1 -1
  43. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +148 -34
  44. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +225 -61
  45. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +74 -30
  46. package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +47 -26
  47. package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +40 -19
  48. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +42 -1
  49. package/dist/extensions/agent-browser/lib/orchestration/script-mode.js +299 -0
  50. package/dist/extensions/agent-browser/lib/parsing.js +0 -7
  51. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +36 -11
  52. package/dist/extensions/agent-browser/lib/playbook.js +20 -24
  53. package/dist/extensions/agent-browser/lib/process-environment.js +14 -0
  54. package/dist/extensions/agent-browser/lib/process-identity.js +4 -9
  55. package/dist/extensions/agent-browser/lib/process.js +131 -48
  56. package/dist/extensions/agent-browser/lib/prompt-policy.js +171 -27
  57. package/dist/extensions/agent-browser/lib/recording-reservations.js +183 -0
  58. package/dist/extensions/agent-browser/lib/results/action-recommendations.js +63 -13
  59. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +68 -11
  60. package/dist/extensions/agent-browser/lib/results/categories.js +7 -9
  61. package/dist/extensions/agent-browser/lib/results/confirmation.js +0 -7
  62. package/dist/extensions/agent-browser/lib/results/contracts.js +0 -7
  63. package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +0 -7
  64. package/dist/extensions/agent-browser/lib/results/envelope.js +0 -7
  65. package/dist/extensions/agent-browser/lib/results/network.js +0 -7
  66. package/dist/extensions/agent-browser/lib/results/next-actions.js +19 -35
  67. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +85 -44
  68. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +66 -11
  69. package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +0 -5
  70. package/dist/extensions/agent-browser/lib/results/presentation/common.js +18 -5
  71. package/dist/extensions/agent-browser/lib/results/presentation/content.js +0 -5
  72. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +7 -6
  73. package/dist/extensions/agent-browser/lib/results/presentation/errors.js +2 -1
  74. package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +0 -5
  75. package/dist/extensions/agent-browser/lib/results/presentation/managed-list-filter.js +0 -5
  76. package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +26 -16
  77. package/dist/extensions/agent-browser/lib/results/presentation/registry.js +58 -13
  78. package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +1 -15
  79. package/dist/extensions/agent-browser/lib/results/presentation/skills.js +0 -5
  80. package/dist/extensions/agent-browser/lib/results/presentation.js +6 -8
  81. package/dist/extensions/agent-browser/lib/results/recovery-actions.js +2 -7
  82. package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +0 -7
  83. package/dist/extensions/agent-browser/lib/results/selector-recovery.js +51 -15
  84. package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +13 -14
  85. package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +0 -7
  86. package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +0 -7
  87. package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +0 -7
  88. package/dist/extensions/agent-browser/lib/results/snapshot.js +0 -7
  89. package/dist/extensions/agent-browser/lib/results/text.js +0 -7
  90. package/dist/extensions/agent-browser/lib/runtime.js +119 -52
  91. package/dist/extensions/agent-browser/lib/session-page-state.js +62 -17
  92. package/dist/extensions/agent-browser/lib/string-enum-schema.js +0 -5
  93. package/dist/extensions/agent-browser/lib/temp.js +0 -7
  94. package/dist/extensions/agent-browser/lib/upstream-version.js +14 -0
  95. package/dist/extensions/agent-browser/lib/web-search.js +0 -5
  96. package/dist/extensions/agent-browser/script-worker.js +169 -0
  97. package/dist/scripts/agent-browser-target.mjs +3 -0
  98. package/docs/ARCHITECTURE.md +50 -31
  99. package/docs/COMMAND_REFERENCE.md +97 -41
  100. package/docs/ELECTRON.md +3 -19
  101. package/docs/RELEASE.md +8 -20
  102. package/docs/REQUIREMENTS.md +8 -6
  103. package/docs/SUPPORT_MATRIX.md +32 -25
  104. package/docs/TOOL_CONTRACT.md +107 -64
  105. package/docs/platform-smoke.md +1 -1
  106. package/package.json +7 -6
  107. package/platform-smoke.config.mjs +2 -2
  108. package/scripts/agent-browser-capability-baseline.mjs +24 -6
  109. package/scripts/agent-browser-target.mjs +3 -0
  110. package/scripts/build.mjs +41 -0
  111. package/scripts/doctor.mjs +8 -7
  112. package/scripts/platform-smoke/browser-dogfood-windows.ps1 +9 -3
  113. package/scripts/platform-smoke/targets.mjs +12 -6
  114. package/dist/extensions/agent-browser/lib/electron/text.js +0 -13
  115. package/dist/extensions/agent-browser/lib/input-modes.js +0 -10
  116. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.js +0 -5
  117. package/dist/extensions/agent-browser/lib/results/artifact-state.js +0 -13
  118. package/dist/extensions/agent-browser/lib/results.js +0 -14
@@ -1,27 +1,29 @@
1
1
  import { copyFile, mkdir } from "node:fs/promises";
2
2
  import { dirname, resolve } from "node:path";
3
+ import { getBooleanFlagValue, isUpstreamEnvFlagEnabled, projectUpstreamGlobalFlags } from "../../argv-grammar.js";
3
4
  import { isCloseCommand } from "../../command-taxonomy.js";
4
5
  import { cleanupElectronLaunchResources } from "../../electron/cleanup.js";
5
6
  import { launchElectronApp } from "../../electron/launch.js";
6
7
  import { pathExists } from "../../fs-utils.js";
7
- import { getCompiledSemanticActionSessionPrefix } from "../../input-modes.js";
8
+ import { getCompiledSemanticActionSessionPrefix } from "../../input-modes/semantic-action.js";
8
9
  import { tryDirectAnchorDownload } from "./prepare/direct-anchor-download.js";
9
10
  import { tryNetworkRequestsPageFilter } from "./prepare/network-page-filter.js";
10
11
  import { tryContainerScroll, tryPageScrollTo } from "./prepare/scroll-shims.js";
11
12
  import { trySnapshotFilter } from "./prepare/snapshot-filter.js";
12
13
  import { commandTimeoutNeedsActivePageUrl, getCommandAwareProcessTimeoutMs } from "./prepare/wait-timeouts.js";
13
- import { getPersistentSessionArtifactStore } from "./session-artifacts.js";
14
- import { buildAgentBrowserResultCategoryDetails } from "../../results.js";
14
+ import { getPersistentSessionArtifactStore } from "./session-state.js";
15
+ import { buildAgentBrowserResultCategoryDetails } from "../../results/categories.js";
15
16
  import { applyNamespaceToNextActions } from "../../results/next-actions.js";
16
17
  import { buildSessionAwareStaleRefNextActions, buildSessionTabRecoveryNextActions } from "../../results/recovery-next-actions.js";
17
18
  import { resolveVisibleRefActionFromSnapshot } from "../../results/selector-recovery.js";
18
19
  import { extractRefSnapshotFromData } from "../../session-page-state.js";
19
- import { buildExecutionPlan, createFreshSessionName, extractCommandTokens, getDefaultHeadlessCompatUserAgent, redactInvocationArgs, } from "../../runtime.js";
20
- import { buildOwnedManagedSessionRestoreContext, canonicalizeOwnedManagedSessionCloseArgs, withOwnedManagedSessionContext, } from "../../managed-session-restore.js";
20
+ import { buildExecutionPlan, canUseHeadlessCompatibilityUserAgent, createFreshSessionName, extractCommandTokens, extractUpstreamCommandTokens, getDefaultHeadlessCompatUserAgent, parseWaitCommandTokens, redactInvocationArgs, } from "../../runtime.js";
21
+ import { buildOwnedManagedSessionRestoreContext, canonicalizeOwnedManagedSessionCloseArgs, resolveExplicitAutosaveInterval, withOwnedManagedSessionContext, } from "../../managed-session-restore.js";
22
+ import { getAgentBrowserProcessEnvironment } from "../../process-environment.js";
21
23
  import { getCallerOwnedSessionLivePageVerificationRequirement, getManagedSessionStateAccessValidationError, getManagedSessionTargetAccessValidationError, } from "../../managed-session-state-policy.js";
22
- import { acquireOwnedManagedSessionDaemonPolicy } from "./managed-session-daemon-policy.js";
24
+ import { acquireOwnedManagedSessionDaemonPolicy, getRunningHeadedAutosavePolicyChangeError } from "./managed-session-daemon-policy.js";
23
25
  import { applyOpenResultTabCorrection, buildManagedSessionOutcome, buildPinnedBatchPlan, buildSessionDetailFields, buildStaleRefPreflight, getSessionContextKey, extractStringResultField, collectAnySessionTabSelection, collectSessionTabSelection, getGuardedRefUsage, getTraceOwnerGuardMessage, runSessionCommandData, shouldPinSessionTabForCommand, } from "./session-state.js";
24
- import { parseBatchStdinJsonArray } from "../batch-stdin.js";
26
+ import { getUpstreamEffectiveBatchSteps, parseBatchStdinJsonArray } from "../batch-stdin.js";
25
27
  import { buildElectronHostFailureResult, getElectronLaunchFailureCategory, redactRecoveryHint } from "./final-result.js";
26
28
  import { prepareClickDispatchProbe } from "./click-dispatch.js";
27
29
  import { collectScrollPositionSnapshot, validateQaAttachedPrecondition } from "./diagnostics.js";
@@ -42,6 +44,7 @@ export function normalizeRunInput(input) {
42
44
  return { ...base, compiledSemanticAction: input.compiledSemanticAction, redactedCompiledSemanticAction: input.redactedCompiledSemanticAction };
43
45
  case "sourceLookup":
44
46
  return { ...base, compiledSourceLookup: input.compiledSourceLookup, redactedCompiledSourceLookup: input.redactedCompiledSourceLookup };
47
+ case "script":
45
48
  case "args":
46
49
  return base;
47
50
  }
@@ -57,12 +60,8 @@ function getArtifactParentPathTokenIndex(commandTokens) {
57
60
  return 1;
58
61
  if (commandTokens[0] === "state" && commandTokens[1] === "save" && commandTokens.length >= 3)
59
62
  return 2;
60
- if (commandTokens[0] === "wait") {
61
- const downloadIndex = commandTokens.findIndex((token) => token === "--download");
62
- const pathIndex = downloadIndex >= 0 ? downloadIndex + 1 : -1;
63
- if (pathIndex > 0 && typeof commandTokens[pathIndex] === "string" && !commandTokens[pathIndex].startsWith("-"))
64
- return pathIndex;
65
- }
63
+ if (commandTokens[0] === "wait")
64
+ return parseWaitCommandTokens(commandTokens).downloadPathIndex;
66
65
  return undefined;
67
66
  }
68
67
  async function ensureArtifactParentDirectory(commandTokens, cwd) {
@@ -75,10 +74,14 @@ async function ensureArtifactParentDirectory(commandTokens, cwd) {
75
74
  await mkdir(dirname(resolve(cwd, requestedPath)), { recursive: true });
76
75
  }
77
76
  async function normalizeScreenshotPathInTokens(commandTokens, cwd) {
78
- const screenshotPathTokenIndex = getScreenshotPathTokenIndex(commandTokens);
79
- if (screenshotPathTokenIndex === undefined) {
77
+ const scopedCommandTokens = extractCommandTokens(commandTokens);
78
+ const projection = projectUpstreamGlobalFlags(scopedCommandTokens);
79
+ const projectedPathTokenIndex = getScreenshotPathTokenIndex(projection.tokens);
80
+ const scopedPathTokenIndex = projectedPathTokenIndex === undefined ? undefined : projection.indices[projectedPathTokenIndex];
81
+ if (scopedPathTokenIndex === undefined) {
80
82
  return { tokens: commandTokens };
81
83
  }
84
+ const screenshotPathTokenIndex = commandTokens.length - scopedCommandTokens.length + scopedPathTokenIndex;
82
85
  const requestedPath = commandTokens[screenshotPathTokenIndex];
83
86
  const absolutePath = resolve(cwd, requestedPath);
84
87
  await mkdir(dirname(absolutePath), { recursive: true });
@@ -97,8 +100,28 @@ async function normalizeScreenshotPathInTokens(commandTokens, cwd) {
97
100
  };
98
101
  }
99
102
  async function prepareBatchScreenshotPaths(args, stdin, cwd) {
100
- const commandTokens = extractCommandTokens(args);
101
- if (commandTokens[0] !== "batch" || stdin === undefined) {
103
+ const commandTokens = extractUpstreamCommandTokens(args);
104
+ if (commandTokens[0] !== "batch") {
105
+ return undefined;
106
+ }
107
+ const argumentSteps = getUpstreamEffectiveBatchSteps(commandTokens, undefined);
108
+ if (argumentSteps.length > 0) {
109
+ // Upstream executes raw argument steps exclusively and ignores stdin, so
110
+ // prepare parent directories for the rows that will run and skip stdin
111
+ // preparation (no directories for never-executed rows).
112
+ for (const step of argumentSteps) {
113
+ const stepTokens = extractUpstreamCommandTokens(step);
114
+ await ensureArtifactParentDirectory(stepTokens, cwd);
115
+ if (stepTokens[0] === "screenshot") {
116
+ // Reuse the screenshot path resolution for its parent-directory side
117
+ // effect only: raw strings are never rewritten, so the normalized
118
+ // tokens and path request are deliberately discarded.
119
+ await normalizeScreenshotPathInTokens(step, cwd);
120
+ }
121
+ }
122
+ return undefined;
123
+ }
124
+ if (stdin === undefined) {
102
125
  return undefined;
103
126
  }
104
127
  const parsed = parseBatchStdinJsonArray(stdin);
@@ -111,8 +134,9 @@ async function prepareBatchScreenshotPaths(args, stdin, cwd) {
111
134
  if (!Array.isArray(step) || !step.every((item) => typeof item === "string")) {
112
135
  return step;
113
136
  }
114
- await ensureArtifactParentDirectory(step, cwd);
115
- if (step[0] !== "screenshot") {
137
+ const upstreamStep = extractUpstreamCommandTokens(step);
138
+ await ensureArtifactParentDirectory(upstreamStep, cwd);
139
+ if (upstreamStep[0] !== "screenshot") {
116
140
  return step;
117
141
  }
118
142
  const normalized = await normalizeScreenshotPathInTokens(step, cwd);
@@ -136,7 +160,7 @@ export async function prepareAgentBrowserArgs(args, stdin, cwd) {
136
160
  return preparedBatch;
137
161
  }
138
162
  const commandTokens = extractCommandTokens(args);
139
- await ensureArtifactParentDirectory(commandTokens, cwd);
163
+ await ensureArtifactParentDirectory(extractUpstreamCommandTokens(args), cwd);
140
164
  const normalized = await normalizeScreenshotPathInTokens(commandTokens, cwd);
141
165
  if (!normalized.request) {
142
166
  return { args };
@@ -180,7 +204,7 @@ const LIKELY_DIALOG_TRIGGER_PROCESS_TIMEOUT_MS = 8_000;
180
204
  const LIKELY_DIALOG_TRIGGER_PROCESS_TIMEOUT_ENV = "PI_AGENT_BROWSER_DIALOG_TRIGGER_PROCESS_TIMEOUT_MS";
181
205
  const DIALOG_TRIGGER_TEXT_PATTERN = /\b(?:alert|confirm|dialog|prompt)\b/i;
182
206
  function getPositiveIntegerEnv(name) {
183
- const value = process.env[name];
207
+ const value = getAgentBrowserProcessEnvironment()[name];
184
208
  if (!value || !/^\d+$/.test(value.trim()))
185
209
  return undefined;
186
210
  const parsed = Number(value.trim());
@@ -214,9 +238,7 @@ function describeRef(refSnapshot, refId) {
214
238
  return ref ? `${ref.role} ${JSON.stringify(ref.name)}` : "not present";
215
239
  }
216
240
  function getSamePageFreshnessPreflightFailure(options) {
217
- if (options.commandTokens[0] === "batch")
218
- return undefined;
219
- const refIds = getRefIdsFromDirectCommand(options.commandTokens);
241
+ const { refIds } = options;
220
242
  if (refIds.length === 0)
221
243
  return undefined;
222
244
  const previousUrl = options.previousSnapshot.target?.url;
@@ -242,7 +264,8 @@ function getSamePageFreshnessPreflightFailure(options) {
242
264
  };
243
265
  }
244
266
  async function collectSamePageRefFreshnessPreflight(options) {
245
- if (!options.previousSnapshot || !options.sessionName || options.commandTokens[0] === "batch" || getRefIdsFromDirectCommand(options.commandTokens).length === 0)
267
+ const refIds = [...new Set(getGuardedRefUsage(options.commandTokens, options.stdin))];
268
+ if (!options.previousSnapshot || !options.sessionName || refIds.length === 0)
246
269
  return undefined;
247
270
  const previousUrl = options.previousSnapshot.target?.url;
248
271
  const currentTargetUrl = options.currentTarget?.url;
@@ -253,7 +276,7 @@ async function collectSamePageRefFreshnessPreflight(options) {
253
276
  if (!currentSnapshot)
254
277
  return undefined;
255
278
  const snapshotWithTarget = { ...currentSnapshot, target: currentSnapshot.target ?? options.currentTarget };
256
- const mismatch = getSamePageFreshnessPreflightFailure({ commandTokens: options.commandTokens, currentSnapshot: snapshotWithTarget, previousSnapshot: options.previousSnapshot });
279
+ const mismatch = getSamePageFreshnessPreflightFailure({ currentSnapshot: snapshotWithTarget, previousSnapshot: options.previousSnapshot, refIds });
257
280
  if (!mismatch)
258
281
  return undefined;
259
282
  return { message: mismatch.message, refIds: mismatch.refIds, snapshot: snapshotWithTarget };
@@ -296,7 +319,14 @@ export function validateStdinCommandContract(options) {
296
319
  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.`;
297
320
  }
298
321
  function canResolveSemanticVisibleRef(compiled) {
299
- return compiled !== undefined && compiled.locator === "role" && ["check", "click", "fill"].includes(compiled.action);
322
+ if (!compiled?.locator)
323
+ return false;
324
+ if (compiled.action === "select")
325
+ return true;
326
+ return compiled.locator === "role" && ["check", "click", "fill"].includes(compiled.action);
327
+ }
328
+ function requiresResolvedSemanticVisibleRef(compiled) {
329
+ return compiled?.action === "select" && compiled.locator !== undefined;
300
330
  }
301
331
  function resolveSemanticActionVisibleRefArgsFromSnapshot(compiled, snapshotData) {
302
332
  if (!canResolveSemanticVisibleRef(compiled))
@@ -315,6 +345,7 @@ export async function resolveSemanticActionVisibleRefArgs(options) {
315
345
  export async function prepareBrowserRun(options) {
316
346
  const { cwd, onUpdate, params, signal, state } = options;
317
347
  const { sessionPageState, traceOwners, managedSessionBaseName, ephemeralSessionSeed } = state;
348
+ const agentBrowserProcessEnv = getAgentBrowserProcessEnvironment();
318
349
  let freshSessionOrdinal = state.freshSessionOrdinal;
319
350
  const { compiledElectron, compiledJob, compiledNetworkSourceLookup, compiledQaPreset, compiledSemanticAction, compiledSourceLookup, redactedArgs, redactedCompiledElectron, redactedCompiledJob, redactedCompiledNetworkSourceLookup, redactedCompiledQaPreset, redactedCompiledSemanticAction, redactedCompiledSourceLookup, toolArgs, toolStdin, } = normalizeRunInput(options.input);
320
351
  let runtimeToolArgs = toolArgs;
@@ -325,6 +356,7 @@ export async function prepareBrowserRun(options) {
325
356
  const rawManagedStateAccessError = getManagedSessionStateAccessValidationError({
326
357
  args: runtimeToolArgs,
327
358
  cwd,
359
+ parentEnv: agentBrowserProcessEnv,
328
360
  stdin: runtimeToolStdin,
329
361
  trustedFirstBatchTabSelection: true,
330
362
  });
@@ -392,26 +424,67 @@ export async function prepareBrowserRun(options) {
392
424
  currentPageUrl: plannedSessionPageState.tabTarget?.url,
393
425
  pageUrlUnknown: plannedSessionPageState.tabTargetUnknown === true,
394
426
  cwd,
427
+ parentEnv: agentBrowserProcessEnv,
395
428
  stdin: runtimeToolStdin,
396
429
  });
397
430
  if (!executionPlan.validationError && managedStateAccessError)
398
431
  executionPlan = { ...executionPlan, recoveryHint: undefined, validationError: managedStateAccessError };
399
432
  const recordedOwnedSession = ownedSessionKey ? state.ownedManagedSessions.get(ownedSessionKey) : undefined;
433
+ const targetsCurrentManagedSession = state.managedSessionActive
434
+ && ownedSessionKey === getSessionContextKey(state.managedSessionName, state.managedSessionNamespace);
435
+ const targetsOffCurrentOwnedSession = recordedOwnedSession !== undefined && !targetsCurrentManagedSession;
436
+ const offCurrentLaunchScopedFlags = targetsOffCurrentOwnedSession
437
+ ? executionPlan.startupScopedFlags.filter((flag) => flag !== "--namespace")
438
+ : [];
439
+ const offCurrentCompatibilityUpgrade = targetsOffCurrentOwnedSession
440
+ && executionPlan.compatibilityWorkaround !== undefined
441
+ && recordedOwnedSession.compatibilityWorkaround === undefined;
442
+ if (targetsOffCurrentOwnedSession && canUseHeadlessCompatibilityUserAgent(preparedArgs.args, agentBrowserProcessEnv)) {
443
+ const compatibilityWorkaround = executionPlan.compatibilityWorkaround ?? recordedOwnedSession.compatibilityWorkaround;
444
+ if (compatibilityWorkaround) {
445
+ const userAgentIndex = executionPlan.effectiveArgs.indexOf("--user-agent");
446
+ executionPlan = {
447
+ ...executionPlan,
448
+ compatibilityWorkaround,
449
+ effectiveArgs: userAgentIndex < 0
450
+ ? executionPlan.effectiveArgs
451
+ : [...executionPlan.effectiveArgs.slice(0, userAgentIndex), ...executionPlan.effectiveArgs.slice(userAgentIndex + 2)],
452
+ };
453
+ }
454
+ }
455
+ const retainedHeadedAutosaveDisabled = recordedOwnedSession?.headedManagedAutosaveDisabled === true
456
+ || (targetsCurrentManagedSession && state.managedSessionHeadedAutosaveDisabled === true);
457
+ const retainedHeadedAutosaveInterval = recordedOwnedSession?.headedManagedAutosaveInterval
458
+ ?? (targetsCurrentManagedSession ? state.managedSessionHeadedAutosaveInterval : undefined);
459
+ const explicitAutosaveInterval = resolveExplicitAutosaveInterval(agentBrowserProcessEnv.AGENT_BROWSER_AUTOSAVE_INTERVAL_MS);
460
+ const autosavePolicyChangeError = getRunningHeadedAutosavePolicyChangeError(retainedHeadedAutosaveInterval, isCloseCommand(executionPlan.commandInfo.command));
461
+ if (!executionPlan.validationError && autosavePolicyChangeError) {
462
+ executionPlan = { ...executionPlan, recoveryHint: undefined, validationError: autosavePolicyChangeError };
463
+ }
464
+ const headedLaunch = getBooleanFlagValue(executionPlan.effectiveArgs, "--headed") ?? isUpstreamEnvFlagEnabled(agentBrowserProcessEnv.AGENT_BROWSER_HEADED);
465
+ const headedManagedAutosaveDisabled = retainedHeadedAutosaveDisabled || (explicitAutosaveInterval === undefined && headedLaunch);
466
+ const headedManagedAutosaveInterval = retainedHeadedAutosaveInterval ?? (headedLaunch ? explicitAutosaveInterval ?? "0" : undefined);
467
+ const compatibilityUserAgent = executionPlan.compatibilityWorkaround ? getDefaultHeadlessCompatUserAgent() : undefined;
468
+ const compatibilityUserAgentApplied = compatibilityUserAgent !== undefined
469
+ && executionPlan.effectiveArgs.some((token, index) => token === "--user-agent" && executionPlan.effectiveArgs[index + 1] === compatibilityUserAgent);
400
470
  const ownedManagedSession = buildOwnedManagedSessionRestoreContext({
401
471
  args: executionPlan.effectiveArgs,
402
472
  cwd: recordedOwnedSession?.cwd ?? cwd,
403
473
  currentManagedSessionName: state.managedSessionName,
404
474
  currentManagedSessionNamespace: state.managedSessionNamespace,
475
+ headedManagedAutosaveDisabled,
476
+ headedManagedAutosaveInterval,
405
477
  managedSessionName: executionPlan.managedSessionName,
406
478
  namespace: executionPlan.namespace,
479
+ parentEnv: agentBrowserProcessEnv,
407
480
  recordedOwnedSession,
408
481
  restoreState: state.managedSessionRestoreState,
409
482
  sessionName: executionPlan.sessionName,
410
483
  stdin: runtimeToolStdin,
411
- compatibilityUserAgent: executionPlan.compatibilityWorkaround ? getDefaultHeadlessCompatUserAgent() : undefined,
412
- wrapperInjectedUserAgent: executionPlan.compatibilityWorkaround !== undefined,
484
+ compatibilityUserAgent: compatibilityUserAgentApplied ? compatibilityUserAgent : undefined,
485
+ wrapperInjectedUserAgent: compatibilityUserAgentApplied,
413
486
  });
414
- const managedSessionTargetError = getManagedSessionTargetAccessValidationError(executionPlan.effectiveArgs, ownedManagedSession !== undefined);
487
+ const managedSessionTargetError = getManagedSessionTargetAccessValidationError(executionPlan.effectiveArgs, ownedManagedSession !== undefined, agentBrowserProcessEnv);
415
488
  if (!executionPlan.validationError && managedSessionTargetError)
416
489
  executionPlan = { ...executionPlan, recoveryHint: undefined, validationError: managedSessionTargetError };
417
490
  if (!executionPlan.validationError && ownedManagedSession) {
@@ -429,6 +502,27 @@ export async function prepareBrowserRun(options) {
429
502
  validationError: policy.error,
430
503
  };
431
504
  }
505
+ else if (!closeCommand && policy.daemonStatus === "active" && offCurrentLaunchScopedFlags.length > 0) {
506
+ executionPlan = {
507
+ ...executionPlan,
508
+ recoveryHint: undefined,
509
+ validationError: `This older wrapper-owned session is already running, so launch-scoped flags ${offCurrentLaunchScopedFlags.join(", ")} would replace or be ignored by upstream agent-browser. Close it first, or remove the explicit --session and retry with sessionMode: \"fresh\".`,
510
+ };
511
+ }
512
+ else if (!closeCommand && policy.daemonStatus === "active" && offCurrentCompatibilityUpgrade) {
513
+ executionPlan = {
514
+ ...executionPlan,
515
+ recoveryHint: undefined,
516
+ validationError: "This older wrapper-owned session is already running without the user agent required by this site. Close it first, or remove the explicit --session and retry with sessionMode: \"fresh\".",
517
+ };
518
+ }
519
+ else if (!closeCommand && policy.daemonStatus === "inactive" && compatibilityUserAgent && !compatibilityUserAgentApplied) {
520
+ ownedManagedSession.compatibilityUserAgent = compatibilityUserAgent;
521
+ executionPlan = {
522
+ ...executionPlan,
523
+ effectiveArgs: ["--user-agent", compatibilityUserAgent, ...executionPlan.effectiveArgs],
524
+ };
525
+ }
432
526
  else if (closeCommand && managedSessionPolicyLock) {
433
527
  executionPlan = {
434
528
  ...executionPlan,
@@ -488,6 +582,7 @@ export async function prepareBrowserRun(options) {
488
582
  currentPageUrl: liveUrl,
489
583
  cwd,
490
584
  pageUrlUnknown: false,
585
+ parentEnv: agentBrowserProcessEnv,
491
586
  stdin: request.stdin,
492
587
  });
493
588
  if (livePageValidationError) {
@@ -498,7 +593,8 @@ export async function prepareBrowserRun(options) {
498
593
  priorSessionTabTarget ??= { url: liveUrl };
499
594
  priorSessionTabTargetUnknown = undefined;
500
595
  };
501
- const mayResolveSemanticVisibleRef = executionPlan.managedSessionName !== freshSessionName && canResolveSemanticVisibleRef(compiledSemanticAction);
596
+ const hasPotentialLiveSemanticSession = state.managedSessionActive || priorSessionTabTarget !== undefined || isCallerOwnedExplicitSession() || options.preserveAttachedBrowserSession === true;
597
+ const mayResolveSemanticVisibleRef = executionPlan.managedSessionName !== freshSessionName && hasPotentialLiveSemanticSession && canResolveSemanticVisibleRef(compiledSemanticAction);
502
598
  if (!executionPlan.validationError && mayResolveSemanticVisibleRef && requiresLivePageVerification()) {
503
599
  await verifyLivePage({
504
600
  args: ["snapshot", "-i"],
@@ -514,6 +610,17 @@ export async function prepareBrowserRun(options) {
514
610
  signal,
515
611
  });
516
612
  }
613
+ if (!executionPlan.validationError && requiresResolvedSemanticVisibleRef(compiledSemanticAction) && !semanticActionVisibleRefResolution) {
614
+ const freshLocatorError = executionPlan.managedSessionName === freshSessionName
615
+ ? "semanticAction select with locator cannot resolve a current @ref in sessionMode fresh. Open the page first, then reuse that session, or pass selector plus value/values."
616
+ : undefined;
617
+ executionPlan = {
618
+ ...executionPlan,
619
+ validationError: freshLocatorError ?? (hasPotentialLiveSemanticSession
620
+ ? "semanticAction select with locator could not resolve to exactly one current visible combobox/listbox ref. Run snapshot -i and retry with selector or a more specific role/name."
621
+ : "semanticAction select with locator requires an active browser session so the wrapper can resolve a current @ref; open a page first or pass selector plus value/values."),
622
+ };
623
+ }
517
624
  if (semanticActionVisibleRefResolution) {
518
625
  executionPlan = buildExecutionPlan(semanticActionVisibleRefResolution.args, {
519
626
  freshSessionName,
@@ -524,7 +631,7 @@ export async function prepareBrowserRun(options) {
524
631
  sessionMode,
525
632
  });
526
633
  }
527
- const commandTokens = semanticActionVisibleRefResolution ? extractCommandTokens(semanticActionVisibleRefResolution.args) : extractCommandTokens(preparedArgs.args);
634
+ const commandTokens = semanticActionVisibleRefResolution ? extractUpstreamCommandTokens(semanticActionVisibleRefResolution.args) : extractUpstreamCommandTokens(preparedArgs.args);
528
635
  const resolvedSemanticActionRefSnapshot = semanticActionVisibleRefResolution?.snapshot
529
636
  ? { ...semanticActionVisibleRefResolution.snapshot, target: semanticActionVisibleRefResolution.snapshot.target ?? priorSessionTabTarget }
530
637
  : undefined;
@@ -679,6 +786,7 @@ export async function prepareBrowserRun(options) {
679
786
  cwd,
680
787
  currentTarget: priorSessionTabTarget,
681
788
  previousSnapshot: resolvedSemanticActionRefSnapshot ? undefined : priorRefSnapshotState,
789
+ stdin: runtimeToolStdin,
682
790
  namespace: executionPlan.namespace,
683
791
  sessionName: executionPlan.sessionName,
684
792
  signal,
@@ -904,7 +1012,11 @@ export async function prepareBrowserRun(options) {
904
1012
  }
905
1013
  if (pinnedBatchPlan) {
906
1014
  sessionTabCorrection = plannedSessionTabSelection;
907
- processArgs = ["--json", ...(executionPlan.namespace ? ["--namespace", executionPlan.namespace] : []), "--session", executionPlan.sessionName, "batch"];
1015
+ // The rewritten batch must keep the caller's fail-fast semantics:
1016
+ // upstream reads only the exact --bail token, so re-emit it whenever
1017
+ // the original batch tokens carried it (argv or stdin/job/qa mode).
1018
+ const pinnedBailArgs = commandTokens.includes("--bail") ? ["--bail"] : [];
1019
+ processArgs = ["--json", ...(executionPlan.namespace !== undefined ? ["--namespace", executionPlan.namespace] : []), "--session", executionPlan.sessionName, "batch", ...pinnedBailArgs];
908
1020
  processStdin = JSON.stringify(pinnedBatchPlan.steps);
909
1021
  includePinnedNavigationSummary = pinnedBatchPlan.includeNavigationSummary;
910
1022
  pinnedBatchUnwrapMode = pinnedBatchPlan.unwrapMode;
@@ -973,7 +1085,9 @@ export async function prepareBrowserRun(options) {
973
1085
  redactedCompiledJob,
974
1086
  redactedCompiledNetworkSourceLookup,
975
1087
  redactedCompiledQaPreset,
976
- redactedCompiledSemanticAction,
1088
+ redactedCompiledSemanticAction: semanticActionVisibleRefResolution && redactedCompiledSemanticAction?.action === "select"
1089
+ ? { ...redactedCompiledSemanticAction, args: redactInvocationArgs(semanticActionVisibleRefResolution.args) }
1090
+ : redactedCompiledSemanticAction,
977
1091
  redactedCompiledSourceLookup,
978
1092
  redactedEffectiveArgs,
979
1093
  redactedProcessArgs,