pi-agent-browser-native 0.2.64 → 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 CHANGED
@@ -2,6 +2,18 @@
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
+
5
17
  ## 0.2.64 - 2026-07-01
6
18
 
7
19
  ### Fixed
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 launch-scoped open/goto/navigate calls that can restore existing tabs (for example --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.
707
- - After the wrapper observes tab-drift risk for a session (for example profile restore 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 is known.
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 { dirname, join, resolve } from "node:path";
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 = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
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
- export async function resolveSemanticActionVisibleRefArgs(options) {
282
- if (!options.compiled || !options.sessionName || options.compiled.locator !== "role" || !["check", "click", "fill"].includes(options.compiled.action))
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 snapshotData = await runSessionCommandData({ args: ["snapshot", "-i"], cwd: options.cwd, namespace: options.namespace, sessionName: options.sessionName, signal: options.signal });
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(options.compiled), ...resolution.args], snapshot: resolution.snapshot };
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
- if (semanticActionVisibleRefResolution) {
345
- executionPlan = buildExecutionPlan(semanticActionVisibleRefResolution.args, {
346
- freshSessionName,
347
- managedSessionActive: state.managedSessionActive,
348
- managedSessionName: state.managedSessionName,
349
- managedSessionNamespace: state.managedSessionNamespace,
350
- sessionMode,
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 plannedSessionTabSelection = await collectSessionTabSelection({
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, hasLaunchScopedTabCorrectionFlag, resolveManagedSessionState } from "../../runtime.js";
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 && hasLaunchScopedTabCorrectionFlag(prepared.runtimeToolArgs) && isOpenNavigationCommand(prepared.executionPlan.commandInfo.command)) {
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
- export async function collectSessionTabSelection(options) {
513
- const { cwd, namespace, sessionName, signal, target } = options;
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
- return selectSessionTargetTab({ tabs, target });
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;
@@ -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 launch-scoped open/goto/navigate calls that can restore existing tabs (for example --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.",
75
- "After the wrapper observes tab-drift risk for a session (for example profile restore 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 is known.",
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
  ];
@@ -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, LAUNCH_SCOPED_TAB_CORRECTION_FLAGS } from "./launch-scoped-flags.js";
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);
@@ -891,8 +891,8 @@ Other useful environment variables include `AGENT_BROWSER_DEFAULT_TIMEOUT`, `AGE
891
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.
892
892
  <!-- agent-browser-playbook:start wrapper-tab-recovery -->
893
893
  <!-- Generated from extensions/agent-browser/lib/playbook.ts. Run `npm run docs -- playbook write` to update. -->
894
- - After launch-scoped open/goto/navigate calls that can restore existing tabs (for example --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.
895
- - After the wrapper observes tab-drift risk for a session (for example profile restore 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 is known.
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.
896
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.
897
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.
898
898
  <!-- agent-browser-playbook:end wrapper-tab-recovery -->
@@ -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 launch-scoped open/goto/navigate calls that can restore existing tabs (for example --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.
881
- - After the wrapper observes tab-drift risk for a session (for example profile restore 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 is known.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-agent-browser-native",
3
- "version": "0.2.64",
3
+ "version": "0.2.65",
4
4
  "description": "pi extension that exposes agent-browser as a native tool for browser automation",
5
5
  "type": "module",
6
6
  "author": "Mitch Fultz (https://github.com/fitchmultz)",