pi-agent-browser-native 0.2.63 → 0.2.65
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 +23 -0
- package/README.md +2 -2
- package/dist/extensions/agent-browser/index.js +18 -2
- package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +1 -6
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +32 -23
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +3 -2
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +32 -7
- package/dist/extensions/agent-browser/lib/playbook.js +5 -5
- package/dist/extensions/agent-browser/lib/results/presentation/errors.js +1 -1
- package/dist/extensions/agent-browser/lib/runtime.js +1 -10
- package/docs/COMMAND_REFERENCE.md +5 -3
- package/docs/TOOL_CONTRACT.md +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.2.65 - 2026-07-06
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed installed-package prompt guidance so the compiled `dist/` entrypoint points agents at package-root `README.md`, `docs/COMMAND_REFERENCE.md`, and `docs/TOOL_CONTRACT.md` instead of nonexistent `dist/docs/...` paths.
|
|
10
|
+
- Tightened managed-session tab recovery so snapshot-scoped `@e...` follow-up commands can re-select the snapshot page after about:blank/tab drift without adding routine tab-list probes to ordinary same-session commands.
|
|
11
|
+
- Resolved semantic role `click` / `fill` shortcuts from a fresh visible snapshot when exact current refs exist, avoiding stale cached-ref reuse after tab or page drift.
|
|
12
|
+
|
|
13
|
+
### Validation
|
|
14
|
+
|
|
15
|
+
- Ran `npm run verify`, focused extension-validation tests, `npm run docs`, `npm run typecheck`, `git diff --check`, and a thermo-nuclear reviewer subagent loop until it returned no material findings.
|
|
16
|
+
|
|
17
|
+
## 0.2.64 - 2026-07-01
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Clarified `agent_browser` prompt, command-reference, and error-hint guidance so selector-required getters such as `get text/html/value/count <selector>` and `get attr <selector> <name>` are no longer grouped with selector-less `get title/url`.
|
|
22
|
+
- Expanded adjacent shorthand command guidance for React, network, diff, trace/profiler/record, and clipboard families so prompts do not imply missing arguments are valid.
|
|
23
|
+
|
|
24
|
+
### Validation
|
|
25
|
+
|
|
26
|
+
- Ran `npm run verify`, focused prompt/error/doc tests, `git diff --check`, and a reviewer subagent loop until both reviewers returned `GREEN`.
|
|
27
|
+
|
|
5
28
|
## 0.2.63 - 2026-06-26
|
|
6
29
|
|
|
7
30
|
### Changed
|
package/README.md
CHANGED
|
@@ -703,8 +703,8 @@ These calls return plain text and stay stateless: the extension does not inject
|
|
|
703
703
|
|
|
704
704
|
<!-- agent-browser-playbook:start wrapper-tab-recovery -->
|
|
705
705
|
<!-- Generated from extensions/agent-browser/lib/playbook.ts. Run `npm run docs -- playbook write` to update. -->
|
|
706
|
-
- After
|
|
707
|
-
- After the wrapper observes tab-drift risk for a session (for example
|
|
706
|
+
- After open/goto/navigate calls with --profile, --restore, --session-name, or --state, agent_browser best-effort re-selects the tab whose URL matches the returned page when restored tabs steal focus during launch or reconnect.
|
|
707
|
+
- After the wrapper observes tab-drift risk for a session (for example open correction, overlapping stale opens, or resumed session state), later active-tab commands best-effort pin that tab inside the same upstream invocation. Routine same-session commands are not preflighted with tab list just because a target tab or ref snapshot is known.
|
|
708
708
|
- For sessions with observed tab-drift risk, after a successful command on a known target tab, agent_browser also best-effort restores that intended tab if a restored/background tab steals focus after the command completes. Routine same-session commands skip this post-command tab-list probe.
|
|
709
709
|
- If a known session target unexpectedly reports about:blank, agent_browser best-effort re-selects the prior intended target when it still exists; if recovery fails, it records the observed about:blank target and reports exact recovery guidance instead of treating the prior page as active.
|
|
710
710
|
<!-- agent-browser-playbook:end wrapper-tab-recovery -->
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* Usage: Loaded by pi through the package manifest in this package, or explicitly via `pi --no-extensions -e .` during local checkout development.
|
|
6
6
|
* Invariants/Assumptions: agent-browser is installed separately on PATH, the wrapper targets the current locally installed upstream version only, and no backward-compatibility shims are provided.
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
8
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
9
10
|
import { fileURLToPath } from "node:url";
|
|
10
11
|
import { Text } from "@earendil-works/pi-tui";
|
|
11
12
|
import { PROJECT_RULE_PROMPT, buildBrowserDefaultProfileGuideline, buildBrowserExecutablePathGuideline, buildToolPromptGuidelines, } from "./lib/playbook.js";
|
|
@@ -446,8 +447,23 @@ class AsyncExecutionQueue {
|
|
|
446
447
|
})();
|
|
447
448
|
}
|
|
448
449
|
}
|
|
450
|
+
function findPackageRoot(startDir) {
|
|
451
|
+
let currentDir = startDir;
|
|
452
|
+
while (true) {
|
|
453
|
+
const packageJsonPath = join(currentDir, "package.json");
|
|
454
|
+
if (existsSync(packageJsonPath)) {
|
|
455
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
456
|
+
if (packageJson.name === "pi-agent-browser-native")
|
|
457
|
+
return currentDir;
|
|
458
|
+
}
|
|
459
|
+
const parentDir = dirname(currentDir);
|
|
460
|
+
if (parentDir === currentDir)
|
|
461
|
+
return startDir;
|
|
462
|
+
currentDir = parentDir;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
449
465
|
function getInstalledDocsPaths() {
|
|
450
|
-
const packageRoot =
|
|
466
|
+
const packageRoot = findPackageRoot(dirname(fileURLToPath(import.meta.url)));
|
|
451
467
|
return {
|
|
452
468
|
readmePath: join(packageRoot, "README.md"),
|
|
453
469
|
commandReferencePath: join(packageRoot, "docs", "COMMAND_REFERENCE.md"),
|
|
@@ -75,9 +75,4 @@ export const LAUNCH_SCOPED_FLAG_DEFINITIONS = [
|
|
|
75
75
|
];
|
|
76
76
|
export const LAUNCH_SCOPED_FLAGS = LAUNCH_SCOPED_FLAG_DEFINITIONS.map((definition) => definition.flag);
|
|
77
77
|
export const LAUNCH_SCOPED_FLAG_LABEL = LAUNCH_SCOPED_FLAGS.join(", ");
|
|
78
|
-
|
|
79
|
-
* The subset of launch-scoped flags that can restore browser/auth state with pre-existing tabs
|
|
80
|
-
* and are plausible wrong-active-tab sources after a fresh launch. These trigger post-open
|
|
81
|
-
* tab-correction (the `tab list` + re-select cycle).
|
|
82
|
-
*/
|
|
83
|
-
export const LAUNCH_SCOPED_TAB_CORRECTION_FLAGS = new Set(["--profile", "--session-name", "--restore", "--state"]);
|
|
78
|
+
export const OPEN_RESULT_TAB_CORRECTION_FLAGS = new Set(["--profile", "--restore", "--session-name", "--state"]);
|
|
@@ -15,7 +15,7 @@ import { buildSessionAwareStaleRefNextActions, buildSessionTabRecoveryNextAction
|
|
|
15
15
|
import { resolveVisibleRefActionFromSnapshot } from "../../results/selector-recovery.js";
|
|
16
16
|
import { extractRefSnapshotFromData } from "../../session-page-state.js";
|
|
17
17
|
import { buildExecutionPlan, createFreshSessionName, extractCommandTokens, redactInvocationArgs, } from "../../runtime.js";
|
|
18
|
-
import { applyOpenResultTabCorrection, buildManagedSessionOutcome, buildPinnedBatchPlan, buildSessionDetailFields, buildStaleRefPreflight, getSessionContextKey, collectSessionTabSelection, getGuardedRefUsage, getTraceOwnerGuardMessage, runSessionCommandData, shouldPinSessionTabForCommand, } from "./session-state.js";
|
|
18
|
+
import { applyOpenResultTabCorrection, buildManagedSessionOutcome, buildPinnedBatchPlan, buildSessionDetailFields, buildStaleRefPreflight, getSessionContextKey, collectAnySessionTabSelection, collectSessionTabSelection, getGuardedRefUsage, getTraceOwnerGuardMessage, runSessionCommandData, shouldPinSessionTabForCommand, } from "./session-state.js";
|
|
19
19
|
import { parseBatchStdinJsonArray } from "../batch-stdin.js";
|
|
20
20
|
import { buildElectronHostFailureResult, getElectronLaunchFailureCategory, redactRecoveryHint } from "./final-result.js";
|
|
21
21
|
import { prepareClickDispatchProbe } from "./click-dispatch.js";
|
|
@@ -278,14 +278,22 @@ export function validateStdinCommandContract(options) {
|
|
|
278
278
|
const commandLabel = options.command ? `\`${options.command}\`` : "the requested command";
|
|
279
279
|
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.`;
|
|
280
280
|
}
|
|
281
|
-
|
|
282
|
-
|
|
281
|
+
function canResolveSemanticVisibleRef(compiled) {
|
|
282
|
+
return compiled !== undefined && compiled.locator === "role" && ["check", "click", "fill"].includes(compiled.action);
|
|
283
|
+
}
|
|
284
|
+
function resolveSemanticActionVisibleRefArgsFromSnapshot(compiled, snapshotData) {
|
|
285
|
+
if (!canResolveSemanticVisibleRef(compiled))
|
|
283
286
|
return undefined;
|
|
284
|
-
const
|
|
285
|
-
const resolution = resolveVisibleRefActionFromSnapshot({ allowFill: true, compiledAction: options.compiled, snapshotData });
|
|
287
|
+
const resolution = resolveVisibleRefActionFromSnapshot({ allowFill: true, compiledAction: compiled, snapshotData });
|
|
286
288
|
if (!resolution)
|
|
287
289
|
return undefined;
|
|
288
|
-
return { args: [...getCompiledSemanticActionSessionPrefix(
|
|
290
|
+
return { args: [...getCompiledSemanticActionSessionPrefix(compiled), ...resolution.args], snapshot: resolution.snapshot };
|
|
291
|
+
}
|
|
292
|
+
export async function resolveSemanticActionVisibleRefArgs(options) {
|
|
293
|
+
if (!options.compiled || !options.sessionName)
|
|
294
|
+
return undefined;
|
|
295
|
+
const snapshotData = await runSessionCommandData({ args: ["snapshot", "-i"], cwd: options.cwd, namespace: options.namespace, sessionName: options.sessionName, signal: options.signal });
|
|
296
|
+
return resolveSemanticActionVisibleRefArgsFromSnapshot(options.compiled, snapshotData);
|
|
289
297
|
}
|
|
290
298
|
export async function prepareBrowserRun(options) {
|
|
291
299
|
const { cwd, implicitSessionIdleTimeoutMs, onUpdate, params, signal, state } = options;
|
|
@@ -332,8 +340,14 @@ export async function prepareBrowserRun(options) {
|
|
|
332
340
|
managedSessionNamespace: state.managedSessionNamespace,
|
|
333
341
|
sessionMode,
|
|
334
342
|
});
|
|
343
|
+
const sessionStateKey = getSessionContextKey(executionPlan.sessionName, executionPlan.namespace);
|
|
344
|
+
const priorSessionPageState = sessionPageState.get(sessionStateKey);
|
|
345
|
+
const priorSessionTabTarget = priorSessionPageState.tabTarget;
|
|
346
|
+
const sessionTabPinningReason = priorSessionPageState.pinningReason;
|
|
347
|
+
const priorRefSnapshotState = priorSessionPageState.refSnapshot;
|
|
348
|
+
const priorRefSnapshotInvalidation = priorSessionPageState.refSnapshotInvalidation;
|
|
335
349
|
let semanticActionVisibleRefResolution;
|
|
336
|
-
if (!executionPlan.validationError && executionPlan.managedSessionName !== freshSessionName) {
|
|
350
|
+
if (!executionPlan.validationError && executionPlan.managedSessionName !== freshSessionName && canResolveSemanticVisibleRef(compiledSemanticAction)) {
|
|
337
351
|
semanticActionVisibleRefResolution = await resolveSemanticActionVisibleRefArgs({
|
|
338
352
|
compiled: compiledSemanticAction,
|
|
339
353
|
cwd,
|
|
@@ -341,15 +355,15 @@ export async function prepareBrowserRun(options) {
|
|
|
341
355
|
sessionName: executionPlan.sessionName,
|
|
342
356
|
signal,
|
|
343
357
|
});
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
358
|
+
}
|
|
359
|
+
if (semanticActionVisibleRefResolution) {
|
|
360
|
+
executionPlan = buildExecutionPlan(semanticActionVisibleRefResolution.args, {
|
|
361
|
+
freshSessionName,
|
|
362
|
+
managedSessionActive: state.managedSessionActive,
|
|
363
|
+
managedSessionName: state.managedSessionName,
|
|
364
|
+
managedSessionNamespace: state.managedSessionNamespace,
|
|
365
|
+
sessionMode,
|
|
366
|
+
});
|
|
353
367
|
}
|
|
354
368
|
const redactedEffectiveArgs = redactInvocationArgs(executionPlan.effectiveArgs);
|
|
355
369
|
const redactedRecoveryHint = redactRecoveryHint(executionPlan.recoveryHint);
|
|
@@ -386,7 +400,6 @@ export async function prepareBrowserRun(options) {
|
|
|
386
400
|
commandTokens,
|
|
387
401
|
stdin: runtimeToolStdin,
|
|
388
402
|
});
|
|
389
|
-
const sessionStateKey = getSessionContextKey(executionPlan.sessionName, executionPlan.namespace);
|
|
390
403
|
const traceOwnerGuardMessage = getTraceOwnerGuardMessage({
|
|
391
404
|
command: executionPlan.commandInfo.command,
|
|
392
405
|
sessionName: sessionStateKey,
|
|
@@ -430,11 +443,6 @@ export async function prepareBrowserRun(options) {
|
|
|
430
443
|
isError: true,
|
|
431
444
|
} };
|
|
432
445
|
}
|
|
433
|
-
const priorSessionPageState = sessionPageState.get(sessionStateKey);
|
|
434
|
-
const priorSessionTabTarget = priorSessionPageState.tabTarget;
|
|
435
|
-
const sessionTabPinningReason = priorSessionPageState.pinningReason;
|
|
436
|
-
const priorRefSnapshotState = priorSessionPageState.refSnapshot;
|
|
437
|
-
const priorRefSnapshotInvalidation = priorSessionPageState.refSnapshotInvalidation;
|
|
438
446
|
const resolvedSemanticActionRefSnapshot = semanticActionVisibleRefResolution?.snapshot
|
|
439
447
|
? { ...semanticActionVisibleRefResolution.snapshot, target: semanticActionVisibleRefResolution.snapshot.target ?? priorSessionTabTarget }
|
|
440
448
|
: undefined;
|
|
@@ -629,7 +637,8 @@ export async function prepareBrowserRun(options) {
|
|
|
629
637
|
sessionName: executionPlan.sessionName,
|
|
630
638
|
stdin: runtimeToolStdin,
|
|
631
639
|
})) {
|
|
632
|
-
const
|
|
640
|
+
const collectTabSelection = promptRefSnapshot && getGuardedRefUsage(commandTokens, runtimeToolStdin).length > 0 ? collectAnySessionTabSelection : collectSessionTabSelection;
|
|
641
|
+
const plannedSessionTabSelection = await collectTabSelection({
|
|
633
642
|
cwd,
|
|
634
643
|
namespace: executionPlan.namespace,
|
|
635
644
|
sessionName: executionPlan.sessionName,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile, rm } from "node:fs/promises";
|
|
2
2
|
import { isCloseCommand, isNavigationObservableCommandName, isOpenNavigationCommand } from "../../command-taxonomy.js";
|
|
3
|
+
import { OPEN_RESULT_TAB_CORRECTION_FLAGS } from "../../launch-scoped-flags.js";
|
|
3
4
|
import { cleanupElectronLaunchResources, inspectElectronLaunchStatus } from "../../electron/cleanup.js";
|
|
4
5
|
import { getAllowedDomainsViolation, parseAllowedDomainsPolicyFromArgs } from "../../navigation-policy.js";
|
|
5
6
|
import { analyzeNetworkSourceLookupResults, analyzeQaPresetResults, analyzeQaPresetTimeout, analyzeSourceLookupResults, buildQaCompactPassText, extractQaPageContext, redactNetworkSourceLookupAnalysis, } from "../../input-modes.js";
|
|
@@ -10,7 +11,7 @@ import { shouldCaptureSemanticActionNavigationSummary } from "../../results/pres
|
|
|
10
11
|
import { commandExplicitlyTargetsAboutBlank, deriveSessionTabTarget, extractLatestRefSnapshotStateFromBatchResults, extractRefSnapshotFromData, extractSessionTabTargetFromBatchResults, extractSessionTabTargetFromCommandData, isAboutBlankSessionTabTarget, normalizeSessionTabTarget, } from "../../session-page-state.js";
|
|
11
12
|
import { writePersistentSessionArtifactFile, writeSecureTempFile } from "../../temp.js";
|
|
12
13
|
import { isRecord } from "../../parsing.js";
|
|
13
|
-
import { createFreshSessionName, extractCommandTokens,
|
|
14
|
+
import { createFreshSessionName, extractCommandTokens, resolveManagedSessionState } from "../../runtime.js";
|
|
14
15
|
import { applyOpenResultTabCorrection, buildAboutBlankRecoveryHint, buildAboutBlankWarning, buildElectronPostCommandHealthDiagnostic, buildElectronRefFreshnessDiagnostic, buildElectronSessionMismatch, buildManagedSessionOutcome, closeManagedSession, collectOpenResultTabCorrection, collectSessionTabSelection, extractNavigationSummaryFromData, extractStringResultField, findElectronLaunchRecordForSession, formatElectronPostCommandHealthText, formatElectronSessionMismatchText, getSessionContextKey, getStaleRefArgs, mergeNavigationSummaryIntoData, shouldCaptureNavigationSummary, shouldCorrectSessionTabAfterCommand, shouldInspectElectronPostCommandHealth, unwrapPinnedSessionBatchEnvelope, updateTraceOwnerState, } from "./session-state.js";
|
|
15
16
|
import { collectClickDispatchDiagnostic } from "./click-dispatch.js";
|
|
16
17
|
import { buildScrollNoopDiagnostic, collectComboboxFocusDiagnostic, collectElectronBroadGetTextScopeDiagnostics, collectElectronHandoff, collectFillVerificationDiagnostic, collectNavigationSummary, collectOverlayBlockerDiagnostic, collectQaAttachedTarget, collectSnapshotOverlayBlockerDiagnostic, collectRecordingDependencyWarning, collectScrollPositionSnapshot, collectSelectorTextVisibilityDiagnostics, collectTimeoutPartialProgress, sleepMs, formatQaAttachedTargetText, getArtifactCleanupGuidance, getEvalResultWarning, getEvalStdinHint, getSourceLookupElectronContext, } from "./diagnostics.js";
|
|
@@ -194,7 +195,7 @@ export async function processBrowserOutput(input) {
|
|
|
194
195
|
presentationEnvelope = { ...presentationEnvelope, data: mergeNavigationSummaryIntoData(presentationEnvelope.data, navigationSummary) };
|
|
195
196
|
let overlayBlockerDiagnostic;
|
|
196
197
|
let openResultTabCorrection;
|
|
197
|
-
if (succeeded && prepared.executionPlan.sessionName &&
|
|
198
|
+
if (succeeded && prepared.executionPlan.sessionName && prepared.executionPlan.startupScopedFlags.some((flag) => OPEN_RESULT_TAB_CORRECTION_FLAGS.has(flag)) && isOpenNavigationCommand(prepared.executionPlan.commandInfo.command) && !commandExplicitlyTargetsAboutBlank(prepared.commandTokens)) {
|
|
198
199
|
const targetTitle = extractStringResultField(presentationEnvelope?.data, "title");
|
|
199
200
|
const targetUrl = extractStringResultField(presentationEnvelope?.data, "url");
|
|
200
201
|
const plannedTabCorrection = await collectOpenResultTabCorrection({ cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal, targetTitle, targetUrl });
|
|
@@ -407,6 +407,13 @@ export function shouldCorrectSessionTabAfterCommand(options) {
|
|
|
407
407
|
options.command !== undefined &&
|
|
408
408
|
!isSessionTabPostCommandCorrectionExcludedCommand(options.command));
|
|
409
409
|
}
|
|
410
|
+
function getTabSelection(tab) {
|
|
411
|
+
if (typeof tab.tabId === "string" && tab.tabId.trim().length > 0)
|
|
412
|
+
return { selectedTab: tab.tabId.trim(), selectionKind: "tabId" };
|
|
413
|
+
if (typeof tab.label === "string" && tab.label.trim().length > 0)
|
|
414
|
+
return { selectedTab: tab.label.trim(), selectionKind: "label" };
|
|
415
|
+
return typeof tab.index === "number" ? { selectedTab: String(tab.index), selectionKind: "index" } : undefined;
|
|
416
|
+
}
|
|
410
417
|
function selectSessionTargetTab(options) {
|
|
411
418
|
return chooseOpenResultTabCorrection({
|
|
412
419
|
tabs: options.tabs,
|
|
@@ -414,6 +421,16 @@ function selectSessionTargetTab(options) {
|
|
|
414
421
|
targetUrl: options.target.url,
|
|
415
422
|
});
|
|
416
423
|
}
|
|
424
|
+
function selectAnySessionTargetTab(options) {
|
|
425
|
+
const targetUrl = typeof options.target.url === "string" ? normalizeComparableUrl(options.target.url) : undefined;
|
|
426
|
+
if (!targetUrl)
|
|
427
|
+
return undefined;
|
|
428
|
+
const matchingTabs = options.tabs.filter((tab) => normalizeComparableUrl(tab.url ?? "") === targetUrl);
|
|
429
|
+
const targetTitle = options.target.title?.trim() ?? "";
|
|
430
|
+
const selectedTab = (targetTitle ? matchingTabs.find((tab) => tab.title?.trim() === targetTitle) : undefined) ?? matchingTabs[0];
|
|
431
|
+
const selection = selectedTab ? getTabSelection(selectedTab) : undefined;
|
|
432
|
+
return selection ? { ...selection, ...(targetTitle ? { targetTitle } : {}), targetUrl } : undefined;
|
|
433
|
+
}
|
|
417
434
|
export function unwrapPinnedSessionBatchEnvelope(options) {
|
|
418
435
|
if (!options.envelope) {
|
|
419
436
|
return {};
|
|
@@ -509,13 +526,10 @@ export async function collectOpenResultTabCorrection(options) {
|
|
|
509
526
|
}));
|
|
510
527
|
return chooseOpenResultTabCorrection({ tabs, targetTitle, targetUrl });
|
|
511
528
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
const tabData = await runSessionCommandData({ args: ["tab", "list"], cwd, namespace, sessionName, signal });
|
|
515
|
-
if (!isRecord(tabData) || !Array.isArray(tabData.tabs)) {
|
|
529
|
+
function mapTabData(tabData) {
|
|
530
|
+
if (!isRecord(tabData) || !Array.isArray(tabData.tabs))
|
|
516
531
|
return undefined;
|
|
517
|
-
|
|
518
|
-
const tabs = tabData.tabs.filter(isRecord).map((tab, index) => ({
|
|
532
|
+
return tabData.tabs.filter(isRecord).map((tab, index) => ({
|
|
519
533
|
active: tab.active === true,
|
|
520
534
|
index: typeof tab.index === "number" ? tab.index : index,
|
|
521
535
|
label: typeof tab.label === "string" ? tab.label : undefined,
|
|
@@ -523,7 +537,18 @@ export async function collectSessionTabSelection(options) {
|
|
|
523
537
|
title: typeof tab.title === "string" ? tab.title : undefined,
|
|
524
538
|
url: typeof tab.url === "string" ? tab.url : undefined,
|
|
525
539
|
}));
|
|
526
|
-
|
|
540
|
+
}
|
|
541
|
+
export async function collectSessionTabSelection(options) {
|
|
542
|
+
const { cwd, namespace, sessionName, signal, target } = options;
|
|
543
|
+
const tabData = await runSessionCommandData({ args: ["tab", "list"], cwd, namespace, sessionName, signal });
|
|
544
|
+
const tabs = mapTabData(tabData);
|
|
545
|
+
return tabs ? selectSessionTargetTab({ tabs, target }) : undefined;
|
|
546
|
+
}
|
|
547
|
+
export async function collectAnySessionTabSelection(options) {
|
|
548
|
+
const { cwd, namespace, sessionName, signal, target } = options;
|
|
549
|
+
const tabData = await runSessionCommandData({ args: ["tab", "list"], cwd, namespace, sessionName, signal });
|
|
550
|
+
const tabs = mapTabData(tabData);
|
|
551
|
+
return tabs ? selectAnySessionTargetTab({ tabs, target }) : undefined;
|
|
527
552
|
}
|
|
528
553
|
export async function applyOpenResultTabCorrection(options) {
|
|
529
554
|
const { correction, cwd, namespace, sessionName, signal } = options;
|
|
@@ -20,7 +20,7 @@ export const QUICK_START_GUIDELINES = [
|
|
|
20
20
|
"Locator-first clicks/fills and native select changes without hand-building argv: { semanticAction: { action: \"click\", locator: \"text\", value: \"Close\" } }, { semanticAction: { action: \"fill\", locator: \"label\", value: \"Email\", text: \"user@example.com\" } }, direct current targets such as { semanticAction: { action: \"fill\", selector: \"@e1\", text: \"prompt\" } }, or { semanticAction: { action: \"select\", selector: \"#flavor\", value: \"chocolate\" } }; add semanticAction.session when targeting a named upstream browser session; details.compiledSemanticAction shows the semantic target, while details.effectiveArgs may show a resolved current @ref for active-session role/name click/check/fill actions to avoid hidden duplicate matches; semanticAction does not expose uncheck while upstream find ... uncheck is not runtime-supported, so use raw uncheck with a stable selector or current ref; selector-not-found failures may append bounded click try-*-candidate next actions or, for fill misses with current editable refs, details.richInputRecovery with focus/click actions that do not copy fill text; stale-ref failures can return retry-semantic-action-after-stale-ref for compiled find actions when retry safety is provable.",
|
|
21
21
|
`Common advanced calls: { args: ["batch"], stdin: "[[\"open\",\"https://example.com\"],[\"snapshot\",\"-i\"]]" }, { job: { steps: [{ action: "open", url: "https://example.com" }, { action: "assertText", text: "Example Domain" }, { action: "screenshot", path: ".dogfood/example.png" }] } }, { qa: { url: "https://example.com", expectedText: "Example Domain", screenshotPath: ".dogfood/qa-example.png" } } (example.com smoke only; elsewhere match exact visible text from snapshot -i), { electron: { action: "list", query: "code" } }, { electron: { action: "launch", appName: "Visual Studio Code", handoff: "snapshot" } }, { electron: { action: "probe" } }, { qa: { attached: true, expectedText: "Explorer" } }, { args: ["eval", "--stdin"], stdin: "document.title", outputPath: "logs/page-title.json" }, { args: ["auth", "save", "name", "--password-stdin"], stdin: "<password from user-approved secret source>" }, { args: ["--profile", "Default", "open", "https://example.com/account"], sessionMode: "fresh" }, and { args: ["open", "--enable", "react-devtools", "https://example.com"], sessionMode: "fresh" }. For app pages with a native dropdown, job steps can include { action: "select", selector: "#flavor", value: "chocolate" } before the dependent assertion; for locator-friendly pages, job click/fill steps can use semantic locator fields such as { action: "fill", locator: "role", role: "searchbox", name: "Search", text: "agent browser" }; for human-paced input, job type steps can use { action: "type", selector: "#prompt", text: "hello", delayMs: 20, press: "Enter" }; delayed typing is capped at 200 characters per step, and generated per-character rows are compacted in visible batch prose while full rows remain in details.batchSteps.`,
|
|
22
22
|
"Constrained job navigation is explicit only: click (and select/submit flows that may navigate) does not prove the next page loaded; add assertUrl and/or assertText after navigation-prone steps before screenshot or later interactions. Keep jobs short around navigation, click, and rerender boundaries on dynamic React/product apps; avoid a whole checkout in one job. If a long job times out and details.timeoutPartialProgress shows a mutating incomplete step, inspect current page state and continue with a shorter job or single action instead of blindly retrying the mutating step. Example: { job: { steps: [{ action: \"open\", url: \"https://shop.example/checkout\" }, { action: \"fill\", selector: \"#email\", text: \"user@example.com\" }, { action: \"click\", selector: \"#continue\" }, { action: \"assertUrl\", url: \"**/shipping\" }, { action: \"assertText\", text: \"Shipping address\" }, { action: \"screenshot\", path: \".dogfood/shipping.png\" }] } }. Top-level click may add pageChangeSummary hints, but job never auto-inserts post-click asserts.",
|
|
23
|
-
"High-value command reference: click <selector> --new-tab opens link-like targets in a new tab; select <selector> <value...> changes native dropdown values; scroll <dir> [px] --selector <sel>, wrapper-handled scroll <selector> <dir> [px|percent] targets nested scrollers, and wrapper-handled scroll to end/top targets document scrolling; download <selector> <path> saves a file triggered by a click; get title/url
|
|
23
|
+
"High-value command reference: click <selector> --new-tab opens link-like targets in a new tab; select <selector> <value...> changes native dropdown values; scroll <dir> [px] --selector <sel>, wrapper-handled scroll <selector> <dir> [px|percent] targets nested scrollers, and wrapper-handled scroll to end/top targets document scrolling; download <selector> <path> saves a file triggered by a click; get title/url need no selector; get text/html/value/count <selector> and get attr <selector> <name> read elements/page state (use body for whole-page text/html); screenshot [selector] [path] captures a page or element image; pdf <path> saves a PDF; tab list and tab <tab-id-or-label> inspect or recover the active tab; react tree, react inspect <fiberId>, react renders start/stop, and react suspense introspect React after --enable react-devtools; vitals [url] measures Core Web Vitals; pushstate <url> performs SPA navigation; tap <selector> and swipe <direction> [distance] support iOS/provider touch flows.",
|
|
24
24
|
"For artifact-producing commands, read the visible artifact block and details.artifactVerification before using files: check requested path, absolute path, existence, size bytes, artifact kind, optional mediaType, status, optional limitation, and verified/missing/pending/unverified counts. details.artifacts contains per-file metadata; record start rows are pending/openRecording until record stop writes the target. The wrapper creates parent directories for direct artifact paths and can save simple loopback HTTP(S) anchor downloads directly to the requested path before upstream download fallback. Browser close does not delete explicit saved files; if close reports details.artifactCleanup, use host file tools to remove paths listed in explicitArtifactPaths (when non-empty) after inspection. If close fails with details.promptGuard.reason=requested-artifacts-missing-before-close, save the exact required artifact path before closing. For annotated screenshots inside batch, put --annotate in top-level args (for example { args: [\"--annotate\", \"batch\"], stdin: \"[[\\\"screenshot\\\",\\\"/tmp/page.png\\\"]]\" }) rather than inside the screenshot step; if annotation labels crowd a dense page, use a scoped or non-annotated screenshot plus snapshot refs instead.",
|
|
25
25
|
"When details.nextActions is present, prefer those exact native agent_browser follow-up payloads over prose guidance; they may include args, stdin, sessionMode, networkSourceLookup, safety notes, or artifactPath for saved files.",
|
|
26
26
|
];
|
|
@@ -41,7 +41,7 @@ export const SHARED_BROWSER_PLAYBOOK_GUIDELINES = [
|
|
|
41
41
|
"For first-navigation setup, use open without a URL plus network route --resource-type <csv>, cookies set --curl <file>, or --init-script/--enable before navigate/opening the target page.",
|
|
42
42
|
"For stateful browser context work, prefer purpose-specific page actions before dumping browser data: use auth save --password-stdin with the tool stdin field for credentials, auth list/show/delete/remove for local auth-profile maintenance, auth login when you need the browser to fill a saved profile, state save/load for portable test state, state list/show/rename/clear/clear -a/clean for saved-state lifecycle cleanup, cookies get/set/clear and storage local|session only when the task needs those values, and expect cookie/storage/auth/state summaries to redact credential-like fields while allowing benign primitive storage values when useful for local QA.",
|
|
43
43
|
"For batch chains that touch cookies, storage, auth, or other secret-bearing commands, use details.batchSteps for per-step artifacts, categories, spill paths, and full structured errors; top-level details.data on batch is only a compact redacted step matrix (success, argv-redacted command, redacted result or scrubbed error text) built from the same presentation rules as standalone calls.",
|
|
44
|
-
"For non-core families, pass current upstream commands through the native tool directly: network
|
|
44
|
+
"For non-core families, pass current upstream commands through the native tool directly: network requests, network route <url>, network har start/stop [path], diff snapshot, diff screenshot --baseline <file>, diff url <u1> <u2>, trace start, trace stop [path], profiler start, profiler stop [path], record start <path>, record stop, console/errors [--clear], highlight <selector>, inspect, clipboard read, clipboard write <text>, clipboard copy/paste, stream enable/disable/status, dashboard start/stop, device list for iOS simulator inventory, and chat <message>. For compact network requests output, prefer details.nextActions for request detail, route-mock diagnostics, actionable failed-request networkSourceLookup, filtering, clearing the aggregate buffer before repro, or HAR capture follow-ups instead of guessing request-id syntax. Artifact-producing commands report details.artifacts and verification state; long-running starts such as stream, dashboard, trace/profiler, and record should be paired with the matching stop/disable command when the task is done; stream enable already-enabled outcomes are treated as idempotent success with status/disable follow-ups.",
|
|
45
45
|
"For Electron desktop apps, prefer top-level electron for wrapper-owned discovery, isolated launch, status, compact probe, and cleanup: list first, treat likely-sensitive annotations as hints rather than enforcement, launch with the default snapshot handoff unless handoff: \"tabs\" is the safer diagnostic starting point, use electron.probe or snapshot -i/qa.attached for current-session state, and always cleanup the returned launchId when done. electron.launch uses an isolated temporary profile; it does not reuse the app's normal signed-in profile or attach to an already-running authenticated app. For signed-in local app state, host-launch the normal app with --remote-debugging-port when appropriate, then use raw args connect <port|url>; after connect, inspect tab list, select the stable tab id such as tab t2, then run a condition wait or snapshot -i before using refs. close commands (`close`, `quit`, or `exit`) only close the browser/CDP session; leave manually launched app shutdown, profile cleanup, and explicit artifacts to the host owner.",
|
|
46
46
|
"For provider or specialized app workflows, load version-matched upstream guidance with skills get agentcore|electron|slack|dogfood|vercel-sandbox through the native tool; add --full when you need references/templates, and use skills get --all only for broad skill audits. Hosted sandbox workflows should use upstream @agent-browser/sandbox helpers outside this wrapper. Provider launches such as -p ios, --provider browserbase/kernel/browseruse/browserless/agentcore, and iOS --device are upstream-owned setup paths; use sessionMode fresh when switching providers and expect external credentials or local Appium/Xcode setup to be required.",
|
|
47
47
|
"For dialogs and frames, use dialog status/accept/dismiss and frame <selector|main> through native args; dialog commands and eval snippets that look like alert/confirm/prompt/dialog triggers are shorter-bounded than normal browser calls, and timed-out dialog-like interactions may add inspect-dialog-after-timeout, dismiss-dialog-after-timeout, or recover-fresh-session-after-dialog-timeout nextActions. When --confirm-actions produces a pending confirmation, use details.nextActions or exact confirm <id> / deny <id> calls instead of inventing ids.",
|
|
@@ -71,8 +71,8 @@ export const INSPECTION_TOOL_CALL_EXAMPLES = [
|
|
|
71
71
|
'{ "args": ["--version"] }',
|
|
72
72
|
];
|
|
73
73
|
export const WRAPPER_TAB_RECOVERY_BEHAVIOR = [
|
|
74
|
-
"After
|
|
75
|
-
"After the wrapper observes tab-drift risk for a session (for example
|
|
74
|
+
"After open/goto/navigate calls with --profile, --restore, --session-name, or --state, agent_browser best-effort re-selects the tab whose URL matches the returned page when restored tabs steal focus during launch or reconnect.",
|
|
75
|
+
"After the wrapper observes tab-drift risk for a session (for example open correction, overlapping stale opens, or resumed session state), later active-tab commands best-effort pin that tab inside the same upstream invocation. Routine same-session commands are not preflighted with tab list just because a target tab or ref snapshot is known.",
|
|
76
76
|
"For sessions with observed tab-drift risk, after a successful command on a known target tab, agent_browser also best-effort restores that intended tab if a restored/background tab steals focus after the command completes. Routine same-session commands skip this post-command tab-list probe.",
|
|
77
77
|
"If a known session target unexpectedly reports about:blank, agent_browser best-effort re-selects the prior intended target when it still exists; if recovery fails, it records the observed about:blank target and reports exact recovery guidance instead of treating the prior page as active.",
|
|
78
78
|
];
|
|
@@ -90,7 +90,7 @@ export const RUNTIME_PROMPT_GUIDELINES = [
|
|
|
90
90
|
"Use agent_browser sessionMode=fresh for launch-scoped flags; never put --session-mode in args. Use requested/configured profiles only; on profile failures run profiles/doctor. Profile content is model-visible.",
|
|
91
91
|
"For agent_browser artifacts, use exact user paths and verify details.artifactVerification/details.artifacts before claiming success. Save details.promptGuard-required artifacts before close; record stop needs ffmpeg; close keeps files; waited:timeout is not proof.",
|
|
92
92
|
"When agent_browser details.nextActions exists, use exact payloads over guessed selectors/prose. Dense snapshots: check Omitted high-value controls/highValueControlRefIds. Dashboards: verify scroll with screenshot/snapshot.",
|
|
93
|
-
"For agent_browser extraction,
|
|
93
|
+
"For agent_browser extraction, use get title/url; get text/html/value/count <selector> or get attr <selector> <name>; or eval --stdin returning a value. Use get text body for full-page text. Batch 3+ reads; heed selector visibility warnings.",
|
|
94
94
|
];
|
|
95
95
|
export function buildBrowserExecutablePathGuideline(executablePath) {
|
|
96
96
|
if (!executablePath)
|
|
@@ -104,7 +104,7 @@ export function redactClipboardPermissionErrorValue(commandInfo, value, payloadC
|
|
|
104
104
|
const UNKNOWN_COMMAND_SUGGESTIONS = {
|
|
105
105
|
attr: [{ description: "Use `get attr <selector> <name>` to read an attribute from a selector or current `@ref`." }],
|
|
106
106
|
count: [{ description: "Use `get count <selector>` to count matching elements." }],
|
|
107
|
-
html: [{ description: "Use `get html <selector>` to read element HTML
|
|
107
|
+
html: [{ description: "Use `get html <selector>` to read element HTML from a selector or current `@ref`; use `get html body` when you need whole-page body HTML." }],
|
|
108
108
|
text: [{ description: "Use `get text <selector>` to read text from a selector or current `@ref`; run `snapshot -i` first when you need a safe `@ref`." }],
|
|
109
109
|
title: [{ args: ["get", "title"], description: "Use `get title` to read the current page title.", id: "use-get-title" }],
|
|
110
110
|
url: [{ args: ["get", "url"], description: "Use `get url` to read the current page URL.", id: "use-get-url" }],
|
|
@@ -13,7 +13,7 @@ import { findCommandStartIndex, parseArgvDescriptor, parseCommandInfo, } from ".
|
|
|
13
13
|
import { GLOBAL_VALUE_FLAGS_ALLOWING_DASH_VALUE, PREVALIDATED_VALUE_FLAGS, optionalGlobalValueFlagConsumesNext, } from "./argv-grammar.js";
|
|
14
14
|
import { needsManagedSession } from "./command-policy.js";
|
|
15
15
|
import { isCloseCommand, isOpenNavigationCommand } from "./command-taxonomy.js";
|
|
16
|
-
import { LAUNCH_SCOPED_FLAG_DEFINITIONS, LAUNCH_SCOPED_FLAG_LABEL
|
|
16
|
+
import { LAUNCH_SCOPED_FLAG_DEFINITIONS, LAUNCH_SCOPED_FLAG_LABEL } from "./launch-scoped-flags.js";
|
|
17
17
|
export { extractCommandTokens, findCommandStartIndex, parseArgvDescriptor, parseCommandInfo } from "./argv-descriptor.js";
|
|
18
18
|
import { isRecord } from "./parsing.js";
|
|
19
19
|
const OPENAI_HEADLESS_COMPAT_HOSTS = new Set(["chat.com", "chat.openai.com", "chatgpt.com"]);
|
|
@@ -773,15 +773,6 @@ export function getStartupScopedFlags(args) {
|
|
|
773
773
|
.map((definition) => definition.flag)
|
|
774
774
|
.filter((flag) => hasLaunchScopedFlagToken(args, flag));
|
|
775
775
|
}
|
|
776
|
-
export function hasLaunchScopedTabCorrectionFlag(args) {
|
|
777
|
-
return args.some((token) => {
|
|
778
|
-
for (const flag of LAUNCH_SCOPED_TAB_CORRECTION_FLAGS) {
|
|
779
|
-
if (token === flag || token.startsWith(`${flag}=`))
|
|
780
|
-
return true;
|
|
781
|
-
}
|
|
782
|
-
return false;
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
776
|
export function buildExecutionPlan(args, options) {
|
|
786
777
|
const invalidValueFlag = getInvalidValueFlagDetails(args);
|
|
787
778
|
const explicitNamespace = extractExplicitNamespace(args);
|
|
@@ -616,7 +616,9 @@ These calls return plain text and stay stateless: the extension does not inject
|
|
|
616
616
|
|
|
617
617
|
| Family | Surface |
|
|
618
618
|
| --- | --- |
|
|
619
|
-
| `get
|
|
619
|
+
| `get title`, `get url`, `get cdp-url` | Read page/browser metadata without a selector. Upstream root help summarizes this family as `get <what> [selector]`, but the selector is not optional for DOM getters. |
|
|
620
|
+
| `get text/html/value/count <selector>` | Read matched elements; use `get text body` for whole-page text. |
|
|
621
|
+
| `get attr <selector> <name>`, `get box <selector>`, `get styles <selector>` | Read an attribute, bounding box, or computed styles from matched elements. |
|
|
620
622
|
| `is <what> <selector>` | Check `visible`, `enabled`, or `checked`. |
|
|
621
623
|
| `find <locator> <value> <action> [text]` | Locator types include `role`, `text`, `label`, `placeholder`, `alt`, `title`, and `testid`; selector helpers include `find first <sel>`, `find last <sel>`, and `find nth <n> <sel>`. Role/text filters include `find role <role> --name <name>` and `find ... --exact`. |
|
|
622
624
|
| `mouse <action> [args]` | `move <x> <y>`, `down [btn]`, `up [btn]`, `wheel <dy> [dx]`. |
|
|
@@ -889,8 +891,8 @@ Other useful environment variables include `AGENT_BROWSER_DEFAULT_TIMEOUT`, `AGE
|
|
|
889
891
|
- If a `sessionMode: "fresh"` call fails (including upstream failure, timeout, missing binary, or **`qa`** reclassification after a nominally successful batch), read `details.managedSessionOutcome` before assuming where the next default call will go: `preserved` means the prior managed session remains current, while `abandoned` means no managed session became current. When the failure reason is not the fresh launch itself—for example `failureCategory: "qa-failure"`—`status`/`summary` may still describe the managed-session transition while `succeeded` on this object matches the final tool outcome.
|
|
890
892
|
<!-- agent-browser-playbook:start wrapper-tab-recovery -->
|
|
891
893
|
<!-- Generated from extensions/agent-browser/lib/playbook.ts. Run `npm run docs -- playbook write` to update. -->
|
|
892
|
-
- After
|
|
893
|
-
- After the wrapper observes tab-drift risk for a session (for example
|
|
894
|
+
- After open/goto/navigate calls with --profile, --restore, --session-name, or --state, agent_browser best-effort re-selects the tab whose URL matches the returned page when restored tabs steal focus during launch or reconnect.
|
|
895
|
+
- After the wrapper observes tab-drift risk for a session (for example open correction, overlapping stale opens, or resumed session state), later active-tab commands best-effort pin that tab inside the same upstream invocation. Routine same-session commands are not preflighted with tab list just because a target tab or ref snapshot is known.
|
|
894
896
|
- For sessions with observed tab-drift risk, after a successful command on a known target tab, agent_browser also best-effort restores that intended tab if a restored/background tab steals focus after the command completes. Routine same-session commands skip this post-command tab-list probe.
|
|
895
897
|
- If a known session target unexpectedly reports about:blank, agent_browser best-effort re-selects the prior intended target when it still exists; if recovery fails, it records the observed about:blank target and reports exact recovery guidance instead of treating the prior page as active.
|
|
896
898
|
<!-- agent-browser-playbook:end wrapper-tab-recovery -->
|
package/docs/TOOL_CONTRACT.md
CHANGED
|
@@ -155,7 +155,7 @@ The extension always plans normal browser commands with `--json` prepended in `e
|
|
|
155
155
|
- For first-navigation setup, use open without a URL plus network route --resource-type <csv>, cookies set --curl <file>, or --init-script/--enable before navigate/opening the target page.
|
|
156
156
|
- For stateful browser context work, prefer purpose-specific page actions before dumping browser data: use auth save --password-stdin with the tool stdin field for credentials, auth list/show/delete/remove for local auth-profile maintenance, auth login when you need the browser to fill a saved profile, state save/load for portable test state, state list/show/rename/clear/clear -a/clean for saved-state lifecycle cleanup, cookies get/set/clear and storage local|session only when the task needs those values, and expect cookie/storage/auth/state summaries to redact credential-like fields while allowing benign primitive storage values when useful for local QA.
|
|
157
157
|
- For batch chains that touch cookies, storage, auth, or other secret-bearing commands, use details.batchSteps for per-step artifacts, categories, spill paths, and full structured errors; top-level details.data on batch is only a compact redacted step matrix (success, argv-redacted command, redacted result or scrubbed error text) built from the same presentation rules as standalone calls.
|
|
158
|
-
- For non-core families, pass current upstream commands through the native tool directly: network
|
|
158
|
+
- For non-core families, pass current upstream commands through the native tool directly: network requests, network route <url>, network har start/stop [path], diff snapshot, diff screenshot --baseline <file>, diff url <u1> <u2>, trace start, trace stop [path], profiler start, profiler stop [path], record start <path>, record stop, console/errors [--clear], highlight <selector>, inspect, clipboard read, clipboard write <text>, clipboard copy/paste, stream enable/disable/status, dashboard start/stop, device list for iOS simulator inventory, and chat <message>. For compact network requests output, prefer details.nextActions for request detail, route-mock diagnostics, actionable failed-request networkSourceLookup, filtering, clearing the aggregate buffer before repro, or HAR capture follow-ups instead of guessing request-id syntax. Artifact-producing commands report details.artifacts and verification state; long-running starts such as stream, dashboard, trace/profiler, and record should be paired with the matching stop/disable command when the task is done; stream enable already-enabled outcomes are treated as idempotent success with status/disable follow-ups.
|
|
159
159
|
- For Electron desktop apps, prefer top-level electron for wrapper-owned discovery, isolated launch, status, compact probe, and cleanup: list first, treat likely-sensitive annotations as hints rather than enforcement, launch with the default snapshot handoff unless handoff: "tabs" is the safer diagnostic starting point, use electron.probe or snapshot -i/qa.attached for current-session state, and always cleanup the returned launchId when done. electron.launch uses an isolated temporary profile; it does not reuse the app's normal signed-in profile or attach to an already-running authenticated app. For signed-in local app state, host-launch the normal app with --remote-debugging-port when appropriate, then use raw args connect <port|url>; after connect, inspect tab list, select the stable tab id such as tab t2, then run a condition wait or snapshot -i before using refs. close commands (`close`, `quit`, or `exit`) only close the browser/CDP session; leave manually launched app shutdown, profile cleanup, and explicit artifacts to the host owner.
|
|
160
160
|
- For provider or specialized app workflows, load version-matched upstream guidance with skills get agentcore|electron|slack|dogfood|vercel-sandbox through the native tool; add --full when you need references/templates, and use skills get --all only for broad skill audits. Hosted sandbox workflows should use upstream @agent-browser/sandbox helpers outside this wrapper. Provider launches such as -p ios, --provider browserbase/kernel/browseruse/browserless/agentcore, and iOS --device are upstream-owned setup paths; use sessionMode fresh when switching providers and expect external credentials or local Appium/Xcode setup to be required.
|
|
161
161
|
- For dialogs and frames, use dialog status/accept/dismiss and frame <selector|main> through native args; dialog commands and eval snippets that look like alert/confirm/prompt/dialog triggers are shorter-bounded than normal browser calls, and timed-out dialog-like interactions may add inspect-dialog-after-timeout, dismiss-dialog-after-timeout, or recover-fresh-session-after-dialog-timeout nextActions. When --confirm-actions produces a pending confirmation, use details.nextActions or exact confirm <id> / deny <id> calls instead of inventing ids.
|
|
@@ -877,8 +877,8 @@ If `agent-browser` is not on `PATH`, fail with a message that:
|
|
|
877
877
|
- pass explicit `--profile` straight through to upstream `agent-browser`; no profile-cloning or isolation layer is added in v1
|
|
878
878
|
<!-- agent-browser-playbook:start wrapper-tab-recovery -->
|
|
879
879
|
<!-- Generated from extensions/agent-browser/lib/playbook.ts. Run `npm run docs -- playbook write` to update. -->
|
|
880
|
-
- After
|
|
881
|
-
- After the wrapper observes tab-drift risk for a session (for example
|
|
880
|
+
- After open/goto/navigate calls with --profile, --restore, --session-name, or --state, agent_browser best-effort re-selects the tab whose URL matches the returned page when restored tabs steal focus during launch or reconnect.
|
|
881
|
+
- After the wrapper observes tab-drift risk for a session (for example open correction, overlapping stale opens, or resumed session state), later active-tab commands best-effort pin that tab inside the same upstream invocation. Routine same-session commands are not preflighted with tab list just because a target tab or ref snapshot is known.
|
|
882
882
|
- For sessions with observed tab-drift risk, after a successful command on a known target tab, agent_browser also best-effort restores that intended tab if a restored/background tab steals focus after the command completes. Routine same-session commands skip this post-command tab-list probe.
|
|
883
883
|
- If a known session target unexpectedly reports about:blank, agent_browser best-effort re-selects the prior intended target when it still exists; if recovery fails, it records the observed about:blank target and reports exact recovery guidance instead of treating the prior page as active.
|
|
884
884
|
<!-- agent-browser-playbook:end wrapper-tab-recovery -->
|
package/package.json
CHANGED