pi-agent-browser-native 0.3.0 → 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.
- package/CHANGELOG.md +127 -0
- package/README.md +63 -20
- package/dist/extensions/agent-browser/index.js +787 -105
- package/dist/extensions/agent-browser/lib/argv-descriptor.js +35 -3
- package/dist/extensions/agent-browser/lib/argv-grammar.js +44 -2
- package/dist/extensions/agent-browser/lib/batch-lifecycle.js +71 -0
- package/dist/extensions/agent-browser/lib/command-policy.js +1 -1
- package/dist/extensions/agent-browser/lib/command-taxonomy.js +35 -2
- package/dist/extensions/agent-browser/lib/input-modes/job.js +61 -4
- package/dist/extensions/agent-browser/lib/input-modes/lookups.js +2 -2
- package/dist/extensions/agent-browser/lib/input-modes/params.js +22 -23
- package/dist/extensions/agent-browser/lib/input-modes/script.js +462 -0
- package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +51 -12
- package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +8 -0
- package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +3 -1
- package/dist/extensions/agent-browser/lib/managed-session-restore.js +26 -36
- package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +2 -4
- package/dist/extensions/agent-browser/lib/managed-session-state-policy.js +47 -29
- package/dist/extensions/agent-browser/lib/managed-session-storage.js +50 -24
- package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +26 -5
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +110 -30
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +2 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +26 -25
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +17 -3
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +2 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +6 -4
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +129 -32
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +191 -55
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +57 -29
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +15 -11
- package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +36 -18
- package/dist/extensions/agent-browser/lib/orchestration/script-mode.js +299 -0
- package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +32 -10
- package/dist/extensions/agent-browser/lib/playbook.js +18 -15
- package/dist/extensions/agent-browser/lib/process-environment.js +14 -0
- package/dist/extensions/agent-browser/lib/process-identity.js +4 -4
- package/dist/extensions/agent-browser/lib/process.js +131 -41
- package/dist/extensions/agent-browser/lib/recording-reservations.js +183 -0
- package/dist/extensions/agent-browser/lib/results/action-recommendations.js +62 -5
- package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +62 -4
- package/dist/extensions/agent-browser/lib/results/categories.js +6 -1
- package/dist/extensions/agent-browser/lib/results/next-actions.js +19 -5
- package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +85 -38
- package/dist/extensions/agent-browser/lib/results/presentation/batch.js +66 -11
- package/dist/extensions/agent-browser/lib/results/presentation/common.js +18 -0
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +7 -1
- package/dist/extensions/agent-browser/lib/results/presentation/errors.js +2 -1
- package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +26 -11
- package/dist/extensions/agent-browser/lib/results/presentation/registry.js +58 -13
- package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +1 -10
- package/dist/extensions/agent-browser/lib/results/presentation.js +6 -3
- package/dist/extensions/agent-browser/lib/results/recovery-actions.js +2 -0
- package/dist/extensions/agent-browser/lib/results/selector-recovery.js +51 -8
- package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +13 -7
- package/dist/extensions/agent-browser/lib/runtime.js +116 -39
- package/dist/extensions/agent-browser/lib/session-page-state.js +62 -10
- package/dist/extensions/agent-browser/lib/upstream-version.js +14 -0
- package/dist/extensions/agent-browser/script-worker.js +169 -0
- package/dist/scripts/agent-browser-target.mjs +3 -0
- package/docs/ARCHITECTURE.md +40 -21
- package/docs/COMMAND_REFERENCE.md +90 -35
- package/docs/RELEASE.md +3 -3
- package/docs/REQUIREMENTS.md +4 -2
- package/docs/SUPPORT_MATRIX.md +26 -19
- package/docs/TOOL_CONTRACT.md +93 -52
- package/package.json +3 -1
- package/platform-smoke.config.mjs +2 -2
- package/scripts/agent-browser-capability-baseline.mjs +24 -6
- package/scripts/agent-browser-target.mjs +3 -0
- package/scripts/build.mjs +41 -0
- package/scripts/doctor.mjs +7 -6
- package/scripts/platform-smoke/browser-dogfood-windows.ps1 +9 -3
- package/scripts/platform-smoke/targets.mjs +12 -6
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { copyFile, mkdir } from "node:fs/promises";
|
|
2
2
|
import { dirname, resolve } from "node:path";
|
|
3
|
-
import { getBooleanFlagValue, isUpstreamEnvFlagEnabled } from "../../argv-grammar.js";
|
|
3
|
+
import { getBooleanFlagValue, isUpstreamEnvFlagEnabled, projectUpstreamGlobalFlags } from "../../argv-grammar.js";
|
|
4
4
|
import { isCloseCommand } from "../../command-taxonomy.js";
|
|
5
5
|
import { cleanupElectronLaunchResources } from "../../electron/cleanup.js";
|
|
6
6
|
import { launchElectronApp } from "../../electron/launch.js";
|
|
@@ -17,12 +17,13 @@ import { applyNamespaceToNextActions } from "../../results/next-actions.js";
|
|
|
17
17
|
import { buildSessionAwareStaleRefNextActions, buildSessionTabRecoveryNextActions } from "../../results/recovery-next-actions.js";
|
|
18
18
|
import { resolveVisibleRefActionFromSnapshot } from "../../results/selector-recovery.js";
|
|
19
19
|
import { extractRefSnapshotFromData } from "../../session-page-state.js";
|
|
20
|
-
import { buildExecutionPlan, createFreshSessionName, extractCommandTokens, getDefaultHeadlessCompatUserAgent, redactInvocationArgs, } from "../../runtime.js";
|
|
20
|
+
import { buildExecutionPlan, canUseHeadlessCompatibilityUserAgent, createFreshSessionName, extractCommandTokens, extractUpstreamCommandTokens, getDefaultHeadlessCompatUserAgent, parseWaitCommandTokens, redactInvocationArgs, } from "../../runtime.js";
|
|
21
21
|
import { buildOwnedManagedSessionRestoreContext, canonicalizeOwnedManagedSessionCloseArgs, resolveExplicitAutosaveInterval, withOwnedManagedSessionContext, } from "../../managed-session-restore.js";
|
|
22
|
+
import { getAgentBrowserProcessEnvironment } from "../../process-environment.js";
|
|
22
23
|
import { getCallerOwnedSessionLivePageVerificationRequirement, getManagedSessionStateAccessValidationError, getManagedSessionTargetAccessValidationError, } from "../../managed-session-state-policy.js";
|
|
23
24
|
import { acquireOwnedManagedSessionDaemonPolicy, getRunningHeadedAutosavePolicyChangeError } from "./managed-session-daemon-policy.js";
|
|
24
25
|
import { applyOpenResultTabCorrection, buildManagedSessionOutcome, buildPinnedBatchPlan, buildSessionDetailFields, buildStaleRefPreflight, getSessionContextKey, extractStringResultField, collectAnySessionTabSelection, collectSessionTabSelection, getGuardedRefUsage, getTraceOwnerGuardMessage, runSessionCommandData, shouldPinSessionTabForCommand, } from "./session-state.js";
|
|
25
|
-
import { parseBatchStdinJsonArray } from "../batch-stdin.js";
|
|
26
|
+
import { getUpstreamEffectiveBatchSteps, parseBatchStdinJsonArray } from "../batch-stdin.js";
|
|
26
27
|
import { buildElectronHostFailureResult, getElectronLaunchFailureCategory, redactRecoveryHint } from "./final-result.js";
|
|
27
28
|
import { prepareClickDispatchProbe } from "./click-dispatch.js";
|
|
28
29
|
import { collectScrollPositionSnapshot, validateQaAttachedPrecondition } from "./diagnostics.js";
|
|
@@ -43,6 +44,7 @@ export function normalizeRunInput(input) {
|
|
|
43
44
|
return { ...base, compiledSemanticAction: input.compiledSemanticAction, redactedCompiledSemanticAction: input.redactedCompiledSemanticAction };
|
|
44
45
|
case "sourceLookup":
|
|
45
46
|
return { ...base, compiledSourceLookup: input.compiledSourceLookup, redactedCompiledSourceLookup: input.redactedCompiledSourceLookup };
|
|
47
|
+
case "script":
|
|
46
48
|
case "args":
|
|
47
49
|
return base;
|
|
48
50
|
}
|
|
@@ -58,12 +60,8 @@ function getArtifactParentPathTokenIndex(commandTokens) {
|
|
|
58
60
|
return 1;
|
|
59
61
|
if (commandTokens[0] === "state" && commandTokens[1] === "save" && commandTokens.length >= 3)
|
|
60
62
|
return 2;
|
|
61
|
-
if (commandTokens[0] === "wait")
|
|
62
|
-
|
|
63
|
-
const pathIndex = downloadIndex >= 0 ? downloadIndex + 1 : -1;
|
|
64
|
-
if (pathIndex > 0 && typeof commandTokens[pathIndex] === "string" && !commandTokens[pathIndex].startsWith("-"))
|
|
65
|
-
return pathIndex;
|
|
66
|
-
}
|
|
63
|
+
if (commandTokens[0] === "wait")
|
|
64
|
+
return parseWaitCommandTokens(commandTokens).downloadPathIndex;
|
|
67
65
|
return undefined;
|
|
68
66
|
}
|
|
69
67
|
async function ensureArtifactParentDirectory(commandTokens, cwd) {
|
|
@@ -76,10 +74,14 @@ async function ensureArtifactParentDirectory(commandTokens, cwd) {
|
|
|
76
74
|
await mkdir(dirname(resolve(cwd, requestedPath)), { recursive: true });
|
|
77
75
|
}
|
|
78
76
|
async function normalizeScreenshotPathInTokens(commandTokens, cwd) {
|
|
79
|
-
const
|
|
80
|
-
|
|
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) {
|
|
81
82
|
return { tokens: commandTokens };
|
|
82
83
|
}
|
|
84
|
+
const screenshotPathTokenIndex = commandTokens.length - scopedCommandTokens.length + scopedPathTokenIndex;
|
|
83
85
|
const requestedPath = commandTokens[screenshotPathTokenIndex];
|
|
84
86
|
const absolutePath = resolve(cwd, requestedPath);
|
|
85
87
|
await mkdir(dirname(absolutePath), { recursive: true });
|
|
@@ -98,8 +100,28 @@ async function normalizeScreenshotPathInTokens(commandTokens, cwd) {
|
|
|
98
100
|
};
|
|
99
101
|
}
|
|
100
102
|
async function prepareBatchScreenshotPaths(args, stdin, cwd) {
|
|
101
|
-
const commandTokens =
|
|
102
|
-
if (commandTokens[0] !== "batch"
|
|
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) {
|
|
103
125
|
return undefined;
|
|
104
126
|
}
|
|
105
127
|
const parsed = parseBatchStdinJsonArray(stdin);
|
|
@@ -112,8 +134,9 @@ async function prepareBatchScreenshotPaths(args, stdin, cwd) {
|
|
|
112
134
|
if (!Array.isArray(step) || !step.every((item) => typeof item === "string")) {
|
|
113
135
|
return step;
|
|
114
136
|
}
|
|
115
|
-
|
|
116
|
-
|
|
137
|
+
const upstreamStep = extractUpstreamCommandTokens(step);
|
|
138
|
+
await ensureArtifactParentDirectory(upstreamStep, cwd);
|
|
139
|
+
if (upstreamStep[0] !== "screenshot") {
|
|
117
140
|
return step;
|
|
118
141
|
}
|
|
119
142
|
const normalized = await normalizeScreenshotPathInTokens(step, cwd);
|
|
@@ -137,7 +160,7 @@ export async function prepareAgentBrowserArgs(args, stdin, cwd) {
|
|
|
137
160
|
return preparedBatch;
|
|
138
161
|
}
|
|
139
162
|
const commandTokens = extractCommandTokens(args);
|
|
140
|
-
await ensureArtifactParentDirectory(
|
|
163
|
+
await ensureArtifactParentDirectory(extractUpstreamCommandTokens(args), cwd);
|
|
141
164
|
const normalized = await normalizeScreenshotPathInTokens(commandTokens, cwd);
|
|
142
165
|
if (!normalized.request) {
|
|
143
166
|
return { args };
|
|
@@ -181,7 +204,7 @@ const LIKELY_DIALOG_TRIGGER_PROCESS_TIMEOUT_MS = 8_000;
|
|
|
181
204
|
const LIKELY_DIALOG_TRIGGER_PROCESS_TIMEOUT_ENV = "PI_AGENT_BROWSER_DIALOG_TRIGGER_PROCESS_TIMEOUT_MS";
|
|
182
205
|
const DIALOG_TRIGGER_TEXT_PATTERN = /\b(?:alert|confirm|dialog|prompt)\b/i;
|
|
183
206
|
function getPositiveIntegerEnv(name) {
|
|
184
|
-
const value =
|
|
207
|
+
const value = getAgentBrowserProcessEnvironment()[name];
|
|
185
208
|
if (!value || !/^\d+$/.test(value.trim()))
|
|
186
209
|
return undefined;
|
|
187
210
|
const parsed = Number(value.trim());
|
|
@@ -215,9 +238,7 @@ function describeRef(refSnapshot, refId) {
|
|
|
215
238
|
return ref ? `${ref.role} ${JSON.stringify(ref.name)}` : "not present";
|
|
216
239
|
}
|
|
217
240
|
function getSamePageFreshnessPreflightFailure(options) {
|
|
218
|
-
|
|
219
|
-
return undefined;
|
|
220
|
-
const refIds = getRefIdsFromDirectCommand(options.commandTokens);
|
|
241
|
+
const { refIds } = options;
|
|
221
242
|
if (refIds.length === 0)
|
|
222
243
|
return undefined;
|
|
223
244
|
const previousUrl = options.previousSnapshot.target?.url;
|
|
@@ -243,7 +264,8 @@ function getSamePageFreshnessPreflightFailure(options) {
|
|
|
243
264
|
};
|
|
244
265
|
}
|
|
245
266
|
async function collectSamePageRefFreshnessPreflight(options) {
|
|
246
|
-
|
|
267
|
+
const refIds = [...new Set(getGuardedRefUsage(options.commandTokens, options.stdin))];
|
|
268
|
+
if (!options.previousSnapshot || !options.sessionName || refIds.length === 0)
|
|
247
269
|
return undefined;
|
|
248
270
|
const previousUrl = options.previousSnapshot.target?.url;
|
|
249
271
|
const currentTargetUrl = options.currentTarget?.url;
|
|
@@ -254,7 +276,7 @@ async function collectSamePageRefFreshnessPreflight(options) {
|
|
|
254
276
|
if (!currentSnapshot)
|
|
255
277
|
return undefined;
|
|
256
278
|
const snapshotWithTarget = { ...currentSnapshot, target: currentSnapshot.target ?? options.currentTarget };
|
|
257
|
-
const mismatch = getSamePageFreshnessPreflightFailure({
|
|
279
|
+
const mismatch = getSamePageFreshnessPreflightFailure({ currentSnapshot: snapshotWithTarget, previousSnapshot: options.previousSnapshot, refIds });
|
|
258
280
|
if (!mismatch)
|
|
259
281
|
return undefined;
|
|
260
282
|
return { message: mismatch.message, refIds: mismatch.refIds, snapshot: snapshotWithTarget };
|
|
@@ -297,7 +319,14 @@ export function validateStdinCommandContract(options) {
|
|
|
297
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.`;
|
|
298
320
|
}
|
|
299
321
|
function canResolveSemanticVisibleRef(compiled) {
|
|
300
|
-
|
|
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;
|
|
301
330
|
}
|
|
302
331
|
function resolveSemanticActionVisibleRefArgsFromSnapshot(compiled, snapshotData) {
|
|
303
332
|
if (!canResolveSemanticVisibleRef(compiled))
|
|
@@ -316,6 +345,7 @@ export async function resolveSemanticActionVisibleRefArgs(options) {
|
|
|
316
345
|
export async function prepareBrowserRun(options) {
|
|
317
346
|
const { cwd, onUpdate, params, signal, state } = options;
|
|
318
347
|
const { sessionPageState, traceOwners, managedSessionBaseName, ephemeralSessionSeed } = state;
|
|
348
|
+
const agentBrowserProcessEnv = getAgentBrowserProcessEnvironment();
|
|
319
349
|
let freshSessionOrdinal = state.freshSessionOrdinal;
|
|
320
350
|
const { compiledElectron, compiledJob, compiledNetworkSourceLookup, compiledQaPreset, compiledSemanticAction, compiledSourceLookup, redactedArgs, redactedCompiledElectron, redactedCompiledJob, redactedCompiledNetworkSourceLookup, redactedCompiledQaPreset, redactedCompiledSemanticAction, redactedCompiledSourceLookup, toolArgs, toolStdin, } = normalizeRunInput(options.input);
|
|
321
351
|
let runtimeToolArgs = toolArgs;
|
|
@@ -326,6 +356,7 @@ export async function prepareBrowserRun(options) {
|
|
|
326
356
|
const rawManagedStateAccessError = getManagedSessionStateAccessValidationError({
|
|
327
357
|
args: runtimeToolArgs,
|
|
328
358
|
cwd,
|
|
359
|
+
parentEnv: agentBrowserProcessEnv,
|
|
329
360
|
stdin: runtimeToolStdin,
|
|
330
361
|
trustedFirstBatchTabSelection: true,
|
|
331
362
|
});
|
|
@@ -393,6 +424,7 @@ export async function prepareBrowserRun(options) {
|
|
|
393
424
|
currentPageUrl: plannedSessionPageState.tabTarget?.url,
|
|
394
425
|
pageUrlUnknown: plannedSessionPageState.tabTargetUnknown === true,
|
|
395
426
|
cwd,
|
|
427
|
+
parentEnv: agentBrowserProcessEnv,
|
|
396
428
|
stdin: runtimeToolStdin,
|
|
397
429
|
});
|
|
398
430
|
if (!executionPlan.validationError && managedStateAccessError)
|
|
@@ -400,18 +432,41 @@ export async function prepareBrowserRun(options) {
|
|
|
400
432
|
const recordedOwnedSession = ownedSessionKey ? state.ownedManagedSessions.get(ownedSessionKey) : undefined;
|
|
401
433
|
const targetsCurrentManagedSession = state.managedSessionActive
|
|
402
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
|
+
}
|
|
403
455
|
const retainedHeadedAutosaveDisabled = recordedOwnedSession?.headedManagedAutosaveDisabled === true
|
|
404
456
|
|| (targetsCurrentManagedSession && state.managedSessionHeadedAutosaveDisabled === true);
|
|
405
457
|
const retainedHeadedAutosaveInterval = recordedOwnedSession?.headedManagedAutosaveInterval
|
|
406
458
|
?? (targetsCurrentManagedSession ? state.managedSessionHeadedAutosaveInterval : undefined);
|
|
407
|
-
const explicitAutosaveInterval = resolveExplicitAutosaveInterval(
|
|
459
|
+
const explicitAutosaveInterval = resolveExplicitAutosaveInterval(agentBrowserProcessEnv.AGENT_BROWSER_AUTOSAVE_INTERVAL_MS);
|
|
408
460
|
const autosavePolicyChangeError = getRunningHeadedAutosavePolicyChangeError(retainedHeadedAutosaveInterval, isCloseCommand(executionPlan.commandInfo.command));
|
|
409
461
|
if (!executionPlan.validationError && autosavePolicyChangeError) {
|
|
410
462
|
executionPlan = { ...executionPlan, recoveryHint: undefined, validationError: autosavePolicyChangeError };
|
|
411
463
|
}
|
|
412
|
-
const headedLaunch = getBooleanFlagValue(executionPlan.effectiveArgs, "--headed") ?? isUpstreamEnvFlagEnabled(
|
|
464
|
+
const headedLaunch = getBooleanFlagValue(executionPlan.effectiveArgs, "--headed") ?? isUpstreamEnvFlagEnabled(agentBrowserProcessEnv.AGENT_BROWSER_HEADED);
|
|
413
465
|
const headedManagedAutosaveDisabled = retainedHeadedAutosaveDisabled || (explicitAutosaveInterval === undefined && headedLaunch);
|
|
414
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);
|
|
415
470
|
const ownedManagedSession = buildOwnedManagedSessionRestoreContext({
|
|
416
471
|
args: executionPlan.effectiveArgs,
|
|
417
472
|
cwd: recordedOwnedSession?.cwd ?? cwd,
|
|
@@ -421,14 +476,15 @@ export async function prepareBrowserRun(options) {
|
|
|
421
476
|
headedManagedAutosaveInterval,
|
|
422
477
|
managedSessionName: executionPlan.managedSessionName,
|
|
423
478
|
namespace: executionPlan.namespace,
|
|
479
|
+
parentEnv: agentBrowserProcessEnv,
|
|
424
480
|
recordedOwnedSession,
|
|
425
481
|
restoreState: state.managedSessionRestoreState,
|
|
426
482
|
sessionName: executionPlan.sessionName,
|
|
427
483
|
stdin: runtimeToolStdin,
|
|
428
|
-
compatibilityUserAgent:
|
|
429
|
-
wrapperInjectedUserAgent:
|
|
484
|
+
compatibilityUserAgent: compatibilityUserAgentApplied ? compatibilityUserAgent : undefined,
|
|
485
|
+
wrapperInjectedUserAgent: compatibilityUserAgentApplied,
|
|
430
486
|
});
|
|
431
|
-
const managedSessionTargetError = getManagedSessionTargetAccessValidationError(executionPlan.effectiveArgs, ownedManagedSession !== undefined);
|
|
487
|
+
const managedSessionTargetError = getManagedSessionTargetAccessValidationError(executionPlan.effectiveArgs, ownedManagedSession !== undefined, agentBrowserProcessEnv);
|
|
432
488
|
if (!executionPlan.validationError && managedSessionTargetError)
|
|
433
489
|
executionPlan = { ...executionPlan, recoveryHint: undefined, validationError: managedSessionTargetError };
|
|
434
490
|
if (!executionPlan.validationError && ownedManagedSession) {
|
|
@@ -446,6 +502,27 @@ export async function prepareBrowserRun(options) {
|
|
|
446
502
|
validationError: policy.error,
|
|
447
503
|
};
|
|
448
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
|
+
}
|
|
449
526
|
else if (closeCommand && managedSessionPolicyLock) {
|
|
450
527
|
executionPlan = {
|
|
451
528
|
...executionPlan,
|
|
@@ -505,6 +582,7 @@ export async function prepareBrowserRun(options) {
|
|
|
505
582
|
currentPageUrl: liveUrl,
|
|
506
583
|
cwd,
|
|
507
584
|
pageUrlUnknown: false,
|
|
585
|
+
parentEnv: agentBrowserProcessEnv,
|
|
508
586
|
stdin: request.stdin,
|
|
509
587
|
});
|
|
510
588
|
if (livePageValidationError) {
|
|
@@ -515,7 +593,8 @@ export async function prepareBrowserRun(options) {
|
|
|
515
593
|
priorSessionTabTarget ??= { url: liveUrl };
|
|
516
594
|
priorSessionTabTargetUnknown = undefined;
|
|
517
595
|
};
|
|
518
|
-
const
|
|
596
|
+
const hasPotentialLiveSemanticSession = state.managedSessionActive || priorSessionTabTarget !== undefined || isCallerOwnedExplicitSession() || options.preserveAttachedBrowserSession === true;
|
|
597
|
+
const mayResolveSemanticVisibleRef = executionPlan.managedSessionName !== freshSessionName && hasPotentialLiveSemanticSession && canResolveSemanticVisibleRef(compiledSemanticAction);
|
|
519
598
|
if (!executionPlan.validationError && mayResolveSemanticVisibleRef && requiresLivePageVerification()) {
|
|
520
599
|
await verifyLivePage({
|
|
521
600
|
args: ["snapshot", "-i"],
|
|
@@ -531,6 +610,17 @@ export async function prepareBrowserRun(options) {
|
|
|
531
610
|
signal,
|
|
532
611
|
});
|
|
533
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
|
+
}
|
|
534
624
|
if (semanticActionVisibleRefResolution) {
|
|
535
625
|
executionPlan = buildExecutionPlan(semanticActionVisibleRefResolution.args, {
|
|
536
626
|
freshSessionName,
|
|
@@ -541,7 +631,7 @@ export async function prepareBrowserRun(options) {
|
|
|
541
631
|
sessionMode,
|
|
542
632
|
});
|
|
543
633
|
}
|
|
544
|
-
const commandTokens = semanticActionVisibleRefResolution ?
|
|
634
|
+
const commandTokens = semanticActionVisibleRefResolution ? extractUpstreamCommandTokens(semanticActionVisibleRefResolution.args) : extractUpstreamCommandTokens(preparedArgs.args);
|
|
545
635
|
const resolvedSemanticActionRefSnapshot = semanticActionVisibleRefResolution?.snapshot
|
|
546
636
|
? { ...semanticActionVisibleRefResolution.snapshot, target: semanticActionVisibleRefResolution.snapshot.target ?? priorSessionTabTarget }
|
|
547
637
|
: undefined;
|
|
@@ -696,6 +786,7 @@ export async function prepareBrowserRun(options) {
|
|
|
696
786
|
cwd,
|
|
697
787
|
currentTarget: priorSessionTabTarget,
|
|
698
788
|
previousSnapshot: resolvedSemanticActionRefSnapshot ? undefined : priorRefSnapshotState,
|
|
789
|
+
stdin: runtimeToolStdin,
|
|
699
790
|
namespace: executionPlan.namespace,
|
|
700
791
|
sessionName: executionPlan.sessionName,
|
|
701
792
|
signal,
|
|
@@ -921,7 +1012,11 @@ export async function prepareBrowserRun(options) {
|
|
|
921
1012
|
}
|
|
922
1013
|
if (pinnedBatchPlan) {
|
|
923
1014
|
sessionTabCorrection = plannedSessionTabSelection;
|
|
924
|
-
|
|
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];
|
|
925
1020
|
processStdin = JSON.stringify(pinnedBatchPlan.steps);
|
|
926
1021
|
includePinnedNavigationSummary = pinnedBatchPlan.includeNavigationSummary;
|
|
927
1022
|
pinnedBatchUnwrapMode = pinnedBatchPlan.unwrapMode;
|
|
@@ -990,7 +1085,9 @@ export async function prepareBrowserRun(options) {
|
|
|
990
1085
|
redactedCompiledJob,
|
|
991
1086
|
redactedCompiledNetworkSourceLookup,
|
|
992
1087
|
redactedCompiledQaPreset,
|
|
993
|
-
redactedCompiledSemanticAction
|
|
1088
|
+
redactedCompiledSemanticAction: semanticActionVisibleRefResolution && redactedCompiledSemanticAction?.action === "select"
|
|
1089
|
+
? { ...redactedCompiledSemanticAction, args: redactInvocationArgs(semanticActionVisibleRefResolution.args) }
|
|
1090
|
+
: redactedCompiledSemanticAction,
|
|
994
1091
|
redactedCompiledSourceLookup,
|
|
995
1092
|
redactedEffectiveArgs,
|
|
996
1093
|
redactedProcessArgs,
|