pi-agent-browser-native 0.6.9 → 0.6.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +62 -19
  3. package/dist/extensions/agent-browser/index.js +424 -451
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +6 -7
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +7 -1
  6. package/dist/extensions/agent-browser/lib/batch-lifecycle.js +4 -8
  7. package/dist/extensions/agent-browser/lib/command-policy.js +41 -2
  8. package/dist/extensions/agent-browser/lib/command-taxonomy.js +15 -2
  9. package/dist/extensions/agent-browser/lib/input-modes/params.js +1 -1
  10. package/dist/extensions/agent-browser/lib/input-modes/script.js +3 -2
  11. package/dist/extensions/agent-browser/lib/managed-session-restore.js +42 -12
  12. package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +3 -5
  13. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +6 -14
  14. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +14 -25
  15. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +12 -6
  16. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +1 -0
  17. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +3 -2
  18. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +38 -31
  19. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +60 -20
  20. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery.js +161 -0
  21. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +5 -5
  22. package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +2 -4
  23. package/dist/extensions/agent-browser/lib/orchestration/native-session-defaults.js +68 -0
  24. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +41 -6
  25. package/dist/extensions/agent-browser/lib/page-target-validation.js +9 -5
  26. package/dist/extensions/agent-browser/lib/playbook.js +13 -12
  27. package/dist/extensions/agent-browser/lib/process-environment.js +26 -8
  28. package/dist/extensions/agent-browser/lib/process.js +8 -5
  29. package/dist/extensions/agent-browser/lib/read-confirmation.js +59 -0
  30. package/dist/extensions/agent-browser/lib/recording-reservations.js +11 -1
  31. package/dist/extensions/agent-browser/lib/results/action-recommendations.js +8 -0
  32. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +6 -5
  33. package/dist/extensions/agent-browser/lib/results/categories.js +4 -2
  34. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +76 -57
  35. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +19 -8
  36. package/dist/extensions/agent-browser/lib/results/presentation/common.js +5 -25
  37. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +40 -38
  38. package/dist/extensions/agent-browser/lib/results/presentation/errors.js +1 -0
  39. package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +3 -3
  40. package/dist/extensions/agent-browser/lib/results/presentation.js +38 -9
  41. package/dist/extensions/agent-browser/lib/results/recording.js +50 -0
  42. package/dist/extensions/agent-browser/lib/runtime.js +72 -20
  43. package/dist/extensions/agent-browser/lib/session-page-state.js +24 -8
  44. package/dist/extensions/agent-browser/lib/temp.js +4 -0
  45. package/dist/scripts/agent-browser-target.mjs +1 -1
  46. package/docs/ARCHITECTURE.md +29 -12
  47. package/docs/COMMAND_REFERENCE.md +67 -31
  48. package/docs/RELEASE.md +6 -4
  49. package/docs/SUPPORT_MATRIX.md +24 -16
  50. package/docs/TOOL_CONTRACT.md +82 -28
  51. package/package.json +1 -1
  52. package/scripts/agent-browser-capability-baseline.mjs +10 -3
  53. package/scripts/agent-browser-target.mjs +1 -1
  54. package/scripts/prepare.mjs +2 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,53 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 0.6.11 - 2026-09-12
6
+
7
+ ### Added
8
+
9
+ - Set `PI_AGENT_BROWSER_SESSION_ARTIFACT_MAX_BYTES=0` to disable automatic persistent-session spill eviction. The default remains 32 MiB; positive limits and temporary spill cleanup are unchanged.
10
+ - Optional host `beforeExecute` callback before browser dispatch, including serial script inner calls with the original Pi call ID and cancellation signal. Configured hosts use Pi's native sequential scheduling; ordinary installs are unchanged.
11
+
12
+ ### Fixed
13
+
14
+ - Keep explicit URL reads and all-read batches out of browser preflights, managed-session replacement and timeout page probes. Preserve existing owned daemon settings and unsaved page state across reads, including after reload/resume.
15
+ - Keep read-first scripts connected to the daemon created by their fresh isolated session, including after a failed HTTP read, without enabling restore or adding browser preflights.
16
+ - Preserve policy-required read confirmations in the correct native session; only native ID-check capability enables browser-independent confirm/deny, including when the DOM target is unknown. Report failed confirmed reads as failures on older natives too, and retain the correct actions when a new DOM confirmation replaces a pending read.
17
+ - Resolve source-build dependencies through their ESM exports so Git installs and package preparation do not reinstall dependencies that are already available.
18
+ - Separate daemon and browser identity in `session info`, including native ownership versus Pi cleanup ownership and explicit unknowns for unavailable fields. Timed-out status checks preserve page state and offer a status-only retry.
19
+ - Carry native recording receipts and actual capture/encoder measurements through direct, restart and batch results, including failures. Recover uncertain stops with one bounded, identity-matched native receipt query; keep original attempt evidence and export failed or recovered recording receipts without overwriting artifacts.
20
+ - Preserve harmless bearer technical prose and unchanged URL spelling. Credential replacements remain visibly marked, and structured results use the same URL redaction as visible text and exports.
21
+ - Redact `authorization_session_id` in URLs, including contextual `state` / `nonce`, from model-visible content, details, and explicit result exports while preserving ordinary query values.
22
+ - Preserve nested serialized JSON, duplicate members and exact numeric literals during redaction; scrub auth URL keys and adjacent secrets before plaintext formatting.
23
+ - Bound eval and get summaries for large single-line output while retaining complete source in spills and exports.
24
+ - Honor configured native session/namespace defaults as caller-owned browsers across Pi sessions, including ordinary structured calls and helpers, without imposing implicit-session idle policy or quit cleanup.
25
+ - Keep disposable script sessions out of native user/project profile defaults by using an empty temporary config through execution and cleanup. Reject inner `--config` overrides without restricting ordinary native `args`.
26
+
27
+ ### Known limitations
28
+
29
+ - Full native browser-independent read/confirmation behavior, live browser identity, and detailed recording receipts require matching upstream support, currently in unmerged [agent-browser PR #1844](https://github.com/vercel-labs/agent-browser/pull/1844). Public 0.37.1 lacks these companion fixes; wrapper-owned read continuity does not add missing native capabilities. Missing native facts remain unknown; absent evidence does not imply a guarantee.
30
+
31
+ ### Validation
32
+
33
+ - The macOS-SSH and native-Windows platform gates were explicitly waived for this release and were not run. Permanent release gates are unchanged.
34
+
35
+ ## 0.6.10 - 2026-09-08
36
+
37
+ ### Fixed
38
+
39
+ - Follow native artifact operands and raw-batch precedence consistently in preflight, recording reservations, result metadata and timeout recovery. Preserve literal batch operands and replay retries as a single native row (#168).
40
+ - Handle recording `--fps` options without losing the requested path or intended pinned page. Keep conservative start/ref protection for older supported natives without claiming a page replacement; FPS-only restarts keep refs (#169).
41
+ - Show positive native WebMCP availability in navigation summaries and distinguish current recording dependency checks from older deferred failures (#169).
42
+
43
+ ### Changed
44
+
45
+ - Recommend `agent-browser` 0.37.0 while keeping the stable 0.35.0 minimum, no upper cap and native-owned recording/tab setup.
46
+
47
+ ### Known limitations
48
+
49
+ - Native 0.37 short/cold recordings on Ubuntu can still fail or produce a shorter clip. This release does not change the upstream recording engine.
50
+
3
51
  ## 0.6.9 - 2026-09-08
4
52
 
5
53
  ### Fixed
package/README.md CHANGED
@@ -19,6 +19,8 @@ Start here for install and common usage. For deeper work, use the active docs by
19
19
 
20
20
  The complete documentation ownership map lives in the repository source at [`docs/SOURCE_OF_TRUTH.md`](https://github.com/fitchmultz/pi-agent-browser-native/blob/main/docs/SOURCE_OF_TRUTH.md).
21
21
 
22
+ Embedding Pi in another host? The extension factory accepts an optional awaited [`beforeExecute` callback](docs/TOOL_CONTRACT.md#host-execution-hook) for saving host state before browser dispatch. Ordinary Pi installation needs no callback.
23
+
22
24
  ## What this looks like in Pi
23
25
 
24
26
  You prompt the agent in plain English:
@@ -82,13 +84,13 @@ The result is optimized for agent work:
82
84
  | Clicks can report success without the page receiving the event | Top-level non-Electron direct `click` calls on `xpath=` targets or role-gated current `@e…` refs (`button`, `checkbox`, `menuitem`, `radio`, `switch`, `tab`) install a bounded target-specific DOM-event probe; eligible `@e…` refs require a unique role/name in both the latest snapshot and the live candidates. Duplicate-name refs pass through without a probe: their old ordinal cannot prove which element received the click. If upstream reports success but no trusted event reaches the resolved target, the wrapper fails the tool, exposes `details.clickDispatch`, and suggests explicit retry/inspect next actions (no in-page replay), including a nested-scroll `scrollintoview` action when the probe sees the target outside a scroll container or viewport. Unresolved locator clicks such as raw `find … click` are left upstream-owned to avoid false failures for frame-scoped targets. Other click results still expose `details.pageChangeSummary`; `observed: false` explicitly marks dispatch-only mutation summaries and adds a visible `Action dispatched; application change unverified` warning. Unchanged-URL clicks can surface evidence-backed `details.overlayBlockers` candidates. | [`docs/TOOL_CONTRACT.md`](docs/TOOL_CONTRACT.md#details), `extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.ts`, `extensions/agent-browser/lib/results/presentation/navigation.ts`, `test/agent-browser.presentation.test.ts`, `test/agent-browser.extension-click-dispatch.test.ts` |
83
85
  | Dashboard scroll commands can look successful while nothing moves | Handles standard `scroll <dir> [px]` against the document first (including pages whose smooth-scroll CSS defeats upstream wheel timing), falls back upstream when the document cannot move, and samples viewport/containers around the fallback; unchanged positions fail as `upstream-error` with `details.scrollNoop`, visible recovery guidance, and exact snapshot/screenshot checks. Unsupported `scrollintoview text=...` fails before dispatch, including inside effective batch rows, and shows exact native `find text ... hover` and snapshot/ref recovery payloads; help remains native pass-through. | [`docs/TOOL_CONTRACT.md`](docs/TOOL_CONTRACT.md#details), [`docs/COMMAND_REFERENCE.md`](docs/COMMAND_REFERENCE.md#core-page-and-element-commands), `test/agent-browser.extension-validation.test.ts` |
84
86
  | Dropdown/combobox clicks can focus or hit native option box-model errors | Adds first-class `select <selector> <value...>` paths through raw `args`, `job`, and `semanticAction`; semantic role/name or label select resolves exactly one current visible combobox/listbox ref before action. Custom combobox clicks still detect focused controls with explicit `aria-expanded` state but no visible options and return `details.comboboxFocus` plus exact recovery `nextActions` | [`docs/TOOL_CONTRACT.md`](docs/TOOL_CONTRACT.md#details), [`docs/COMMAND_REFERENCE.md`](docs/COMMAND_REFERENCE.md#core-page-and-element-commands), `extensions/agent-browser/lib/input-modes/semantic-action.ts`, `test/agent-browser.extension-input-modes.test.ts`, `test/agent-browser.extension-validation.test.ts` |
85
- | Recording workflows fail late when `ffmpeg` is missing or report stale lifecycle state | After successful `record start` / `record restart`, reports `successCategory: "artifact-pending"`, returns an exact `stop-pending-recording` action, warns when `ffmpeg` is unavailable, and tells agents that `record start` switches to a fresh active page whose in-page state does not carry over while invalidating prior page-scoped `@e…` refs on every executed start attempt (even a failed already-active one) and on URL-bearing `record restart` (stale-ref until a fresh snapshot); an unbounded transcript-backed namespace/session index reserves active destinations across aliases, serializes artifact lifecycle and explicit wait/output writes, persists cross-branch close tombstones, retires every successful close path (including every matching namespace owner for `close --all`), rejects missing/stale restart output, coalesces terminal batch state, keeps only the newest pending path per identity, rejects recording starts after a nested close, folds Unicode path aliases, and retains exact cleanup actions with visible guidance on any later same-session failure | [`docs/TOOL_CONTRACT.md`](docs/TOOL_CONTRACT.md#details), [`docs/COMMAND_REFERENCE.md`](docs/COMMAND_REFERENCE.md#diff-debug-and-streaming), `test/agent-browser.extension-validation.test.ts`, `test/agent-browser.presentation-artifacts-batch.test.ts` |
86
- | Upstream CLI drift can silently invalidate wrapper behavior | Publishes a repo-readable command reference, verifies it against the recommended 0.36.0 target, and probes browser-backed calls once per cwd/PATH so stable versions below the 0.35.0 floor fail before browser launch with installed/expected version evidence | `npm run verify` |
87
- | Pages can expose structured workflows through experimental WebMCP | Passes through `webmcp list`, `invoke`, detached `result` / `cancel`, params/frame/timeout options, and the bundled `webmcp-gen` skill; treats `--no-webmcp` as launch-scoped, keeps pending or unsuccessfully settled targets unverified with an actionable `get url` follow-up, invalidates stale refs after page tools run, and budgets effective raw or stdin batch timeouts | [`docs/COMMAND_REFERENCE.md`](docs/COMMAND_REFERENCE.md#webmcp-page-tools), `test/agent-browser.extension-ref-guards.test.ts`, `test/agent-browser.wait-timeouts.test.ts`, `test/agent-browser.real-upstream-contract.test.ts` |
87
+ | Recording workflows fail late when `ffmpeg` is missing or report stale lifecycle state | After successful `record start` / `record restart`, reports `successCategory: "artifact-pending"`, returns an exact `stop-pending-recording` action, warns when older natives report pending output without `ffmpeg`, and conservatively invalidates prior page-scoped `@e…` refs on every executed start attempt and URL-bearing restart to protect older supported natives. This is not evidence of a page change: 0.37 records the active page unless a URL is supplied; FPS-only calls keep the intended tab; an unbounded transcript-backed namespace/session index reserves active destinations across aliases, serializes artifact lifecycle and explicit wait/output writes, persists cross-branch close tombstones, retires every successful close path (including every matching namespace owner for `close --all`), rejects missing/stale restart output, coalesces terminal batch state, keeps only the newest pending path per identity, rejects recording starts after a nested close, folds Unicode path aliases, and retains exact cleanup actions with visible guidance on any later same-session failure | [`docs/TOOL_CONTRACT.md`](docs/TOOL_CONTRACT.md#details), [`docs/COMMAND_REFERENCE.md`](docs/COMMAND_REFERENCE.md#diff-debug-and-streaming), `test/agent-browser.extension-validation.test.ts`, `test/agent-browser.presentation-artifacts-batch.test.ts` |
88
+ | Upstream CLI drift can silently invalidate wrapper behavior | Publishes a repo-readable command reference, verifies it against the recommended 0.37.0 target, and probes browser-backed calls once per cwd/PATH so stable versions below the 0.35.0 floor fail before browser launch with installed/expected version evidence | `npm run verify` |
89
+ | Pages can expose structured workflows through experimental WebMCP | Shows native positive WebMCP availability in navigation summaries and passes through `webmcp list`, `invoke`, detached `result` / `cancel`, params/frame/timeout options, and the bundled `webmcp-gen` skill; treats `--no-webmcp` as launch-scoped, keeps pending or unsuccessfully settled targets unverified with an actionable `get url` follow-up, invalidates stale refs after page tools run, and budgets effective raw or stdin batch timeouts | [`docs/COMMAND_REFERENCE.md`](docs/COMMAND_REFERENCE.md#webmcp-page-tools), `test/agent-browser.extension-ref-guards.test.ts`, `test/agent-browser.wait-timeouts.test.ts`, `test/agent-browser.real-upstream-contract.test.ts` |
88
90
  | Desktop Electron apps need discovery, CDP attach, and safe teardown | Top-level `electron` runs host `list` / isolated `launch` (temp profile, OS-chosen debug port) / `status` / `probe` / `cleanup`, merges `launchId` plus managed `sessionName`, supports `handoff` `snapshot` / `tabs` / `connect`, and surfaces mismatch and post-command health guidance; wrapper cleanup applies only to launches it created | `extensions/agent-browser/lib/electron/discovery.ts`, `launch.ts`, `cleanup.ts`, [`docs/TOOL_CONTRACT.md`](docs/TOOL_CONTRACT.md#electron), [`docs/COMMAND_REFERENCE.md`](docs/COMMAND_REFERENCE.md#electron-desktop-apps) |
89
91
  | Agents need bundled `skills` text and local setup/status commands without touching the live session | Treats `skills list/get/path`, local auth/profile/setup commands, `session list`, and local state lifecycle commands as sessionless reads/actions when upstream does not need a live page. Session/state rows and targets remain visible, and supported upstream state/config/path operations pass through unchanged. Browser-backed workflows still receive an implicit session only when the caller did not choose one. | [`docs/COMMAND_REFERENCE.md`](docs/COMMAND_REFERENCE.md#built-in-skills), `extensions/agent-browser/lib/command-policy.ts`, `extensions/agent-browser/lib/runtime.ts` |
90
92
 
91
- Artifact results show known requested paths separately from reported/resolved locations and infer image MIME types from file headers, not suffixes. Parent-directory failures return path-specific `validation-error` guidance before browser dispatch. Use absolute artifact paths in raw batch strings because the daemon's working directory may differ from Pi's. Dispatched `record start` and URL-bearing `record restart` attempts also return one fresh-snapshot warning on success or failure, including in JSON output; unreached rows do not claim a page change.
93
+ Artifact results show known requested paths separately from reported/resolved locations and infer image MIME types from file headers, not suffixes. Parent-directory failures return path-specific `validation-error` guidance before browser dispatch. Use absolute artifact paths in raw batch strings because the daemon's working directory may differ from Pi's. Dispatched `record start` and URL-bearing `record restart` attempts also return one fresh-snapshot warning on success or failure, including in JSON output. It describes conservative ref invalidation, not an observed page change; unreached rows do not emit it.
92
94
 
93
95
  ## Fastest way to try it
94
96
 
@@ -104,13 +106,13 @@ Optional external tools unlock the full command surface:
104
106
  | Dependency | Required for | macOS install example |
105
107
  | --- | --- | --- |
106
108
  | `agent-browser` | All browser automation through this extension | See upstream install docs |
107
- | `ffmpeg` | `record stop` WebM encoding after `record start` / `record restart` | `brew install ffmpeg` or `brew install ffmpeg-full` |
109
+ | `ffmpeg` | Recording WebM (libvpx) or MP4 (libx264); install before `record start` / `record restart` | `brew install ffmpeg` or `brew install ffmpeg-full` |
108
110
 
109
- Keep both binaries on `PATH`. This package recommends `agent-browser 0.36.0` and accepts stable versions at or above the 0.35.0 floor; browser-backed calls fail fast below that floor while local inspection/setup commands remain available for diagnosis. `record start` can begin without a file on disk, but `record stop` needs `ffmpeg` to encode the WebM.
111
+ Keep both binaries on `PATH`. This package recommends `agent-browser 0.37.0` and accepts stable versions at or above the 0.35.0 floor; browser-backed calls fail fast below that floor while local inspection/setup commands remain available for diagnosis. Native 0.37 validates `ffmpeg`, the output extension and FPS before recording; older supported natives may defer failures until stop. Use `record start <path.webm|path.mp4> [url] [--fps <n>]` (1–60 fps, default 30), then verify the completed file after `record stop`. Native `doctor` checks the recording dependency and encoders.
110
112
 
111
113
  ### Android / Termux
112
114
 
113
- Android support currently uses Termux's system Chromium rather than Chrome for Testing. Upstream issue [vercel-labs/agent-browser#1587](https://github.com/vercel-labs/agent-browser/issues/1587) tracks native Android packaging; until upstream ships an Android launcher, install the packaged Linux-musl arm64 binary without lifecycle scripts and point the global command at it:
115
+ Android support currently uses Termux's system Chromium rather than Chrome for Testing. Upstream issue [vercel-labs/agent-browser#1587](https://github.com/vercel-labs/agent-browser/issues/1587) tracks native Android packaging; until upstream ships an Android launcher, install the packaged Linux-musl arm64 binary without lifecycle scripts and point the global command at it. The last locally validated Android setup used 0.36.0:
114
116
 
115
117
  ```bash
116
118
  pkg install tur-repo x11-repo
@@ -186,7 +188,7 @@ npm run doctor
186
188
  The doctor checks:
187
189
 
188
190
  - upstream `agent-browser` exists on `PATH`
189
- - the installed upstream is a stable version at or above the supported 0.35.0 floor; 0.36.0 remains the recommended baseline
191
+ - the installed upstream is a stable version at or above the supported 0.35.0 floor; 0.37.0 remains the recommended baseline
190
192
  - `pi --version` meets the minimum Pi runtime floor for this release; older Pi versions are setup failures
191
193
  - Pi settings do not point at multiple active `pi-agent-browser-native` sources
192
194
 
@@ -375,7 +377,9 @@ Read documentation or other unstructured text without requiring a Chrome page, o
375
377
  { "args": ["read"] }
376
378
  ```
377
379
 
378
- Explicit URL reads prefer `text/markdown`, then try a `.md` path and nearby `llms.txt` links before falling back to readable HTML text. Use `--outline`, `--llms index|full`, `--require-md`, `--raw`, or `--timeout <ms>` when needed. The wrapper still starts the upstream CLI under the managed session identity. A concise visible `Read execution` line reports the fetch source, CLI start, managed browser lifecycle, and managed-session outcome; the same facts remain in `details.readSource`, `details.lifecycle.effectiveLaunch.browserLaunched`, `details.agentBrowserStarted`, and `details.managedSessionOutcome`. The lifecycle boolean can be `false` before any browser launch or `true` when the read reuses an already-active browser session. It renders upstream `data.content` first, preserves metadata in `details.data`, keeps fetched URLs from replacing the active browser tab target, and budgets explicit long read timeouts across upstream's `.md` and ancestor-`llms.txt` request fallbacks.
380
+ Explicit URL reads prefer `text/markdown`, then try a `.md` path and nearby `llms.txt` links before falling back to readable HTML text. Use `--outline`, `--llms index|full`, `--require-md`, `--raw`, or `--timeout <ms>` when needed. Explicit reads, including all-read batches, do not allocate or replace a managed browser, require a known page, or run browser helpers before, after, or following a timeout. Native config and argv pass through unchanged; the native HTTP reader owns fetching. A visible `Read execution` line reports the source, CLI start and native launch evidence without treating an HTTP read as proof of shared-browser liveness. Bare `read` still uses and verifies the current DOM. The native no-browser-effects path requires the companion upstream fix; older supported binaries do not guarantee it merely because this wrapper skips helpers. It renders upstream `data.content` first, preserves metadata in `details.data`, keeps fetched URLs from replacing the active browser tab target, and budgets explicit long read timeouts across upstream's `.md` and ancestor-`llms.txt` request fallbacks.
381
+
382
+ Use `session info` to inspect browser status. A timeout proves no liveness and returns only `retry-session-info` for that same session/namespace; it does not run page probes or change existing page/ref state.
379
383
 
380
384
  Evaluate page JavaScript through stdin. Put the script in the top-level `stdin` field, not as an extra `args` token after `--stdin`. Return the value you want as an expression; `eval --stdin` may warn with `details.evalStdinHint` when a function-shaped snippet serializes to `{}` instead of being invoked:
381
385
 
@@ -385,9 +389,17 @@ Evaluate page JavaScript through stdin. Put the script in the top-level `stdin`
385
389
  { "args": ["eval", "--stdin"], "stdin": "({ title: document.title, url: location.href })", "outputPath": "logs/page-state.json" }
386
390
  ```
387
391
 
388
- Use `outputPath` when `eval`, `get`, `snapshot`, or another extraction should be saved as a durable workspace file. Keep it distinct from screenshot, download, recording, and other browser artifact destinations; preflight rejects known same-call aliases before browser activity, and the result writer preserves the browser artifact if an alias becomes apparent only afterward. The wrapper writes `details.data` when present, otherwise the model-facing text content. When presentation compacted a large direct result, a result row, or the whole `batch`, it instead reads the full command-redacted pre-compaction payload only from the corresponding live wrapper-managed spill recorded in `details.artifactManifest`; if any required spill is unavailable or untrusted, the call fails without writing compact metadata to the requested path. `details.outputFile` reports the saved path and byte count. Explicit upstream `--json` content stays parseable; in that case the save notice lives only in `details.outputFile`.
392
+ Use `outputPath` when `eval`, `get`, `snapshot`, or another extraction should be saved as a durable workspace file. Recording results also export on failure or timeout: their JSON envelope retains the failed attempt, native receipt, verification and any recovery evidence rather than writing misleading bare success data. Keep it distinct from screenshot, download, recording, and other browser artifact destinations; preflight rejects known same-call aliases before browser activity, and the result writer preserves the browser artifact if an alias becomes apparent only afterward. The wrapper writes `details.data` when present, otherwise the model-facing text content. When presentation compacted a large direct result, a result row, or the whole `batch`, it instead reads the full command-redacted pre-compaction payload only from the corresponding live wrapper-managed spill recorded in `details.artifactManifest`; if any required spill is unavailable or untrusted, the call fails without writing compact metadata to the requested path. `details.outputFile` reports the saved path and byte count. Explicit upstream `--json` content stays parseable; in that case the save notice lives only in `details.outputFile`.
393
+
394
+ Recording receipts separate captured-frame rate and wall-clock capture duration from nominal/output FPS. `details.artifacts[].recording` includes native capture timestamps, received frame counts (not pixel-unique frames), encoded/written/held/dropped/skipped counts, and output duration. Missing native metrics stay unknown. Repeated, static, sparse or final-state-only frames cannot establish UI smoothness.
395
+
396
+ ```json
397
+ { "args": ["record", "stop"], "outputPath": "logs/record-stop.json" }
398
+ ```
399
+
400
+ A timed-out stop or `No recording in progress` response gets one bounded native `session info` query. Only a matching terminal native receipt, successful encoder measurements and a verified file can recover success; file presence alone cannot. The original attempt remains visible. A receipt can verify the recording from a timed-out batch without proving its other steps succeeded. Follow the exact status/stop actions returned, not blind retries or longer timeouts. See [recording receipts](docs/TOOL_CONTRACT.md#recording-receipts-and-recovery) for fields and native availability.
389
401
 
390
- Extract several known refs or selectors in one `batch` call instead of many serial getter calls:
402
+ Extract several known refs or selectors in one `batch` call instead of many serial getter calls. When a prior snapshot and session are available and the same-page freshness checks apply, ref-consuming calls add one extra `snapshot -i` preflight per top-level call or batch. Batching shares that probe across rows; it does not remove it:
391
403
 
392
404
  ```json
393
405
  { "args": ["batch"], "stdin": "[[\"get\",\"text\",\"@e64\"],[\"get\",\"text\",\"@e65\"]]" }
@@ -418,7 +430,7 @@ Use top-level `script` when the browser work needs a loop, a conditional page br
418
430
  }
419
431
  ```
420
432
 
421
- This mode is intentionally one-shot, not a reusable recipe runtime. Each invocation gets a unique non-profile browser session, never touches the implicit conversation session, serializes inner calls, and closes the isolated session in `finally`. It rejects caller `--session` / `--namespace`, browser lifecycle and attachment commands, persistent launch/profile/restore controls, nested `batch`, local/sessionless commands, and every other top-level input mode. Every script-owned helper and cleanup subprocess also clears ambient `AGENT_BROWSER_*` and standard proxy variables before the wrapper reapplies its own isolated-session controls, so shell defaults cannot attach, restore, or select a profile behind the script’s back. The sandbox has no imports, `require`, process, filesystem, network, timers, dynamic code generation, or host object/function references.
433
+ This mode is intentionally one-shot, not a reusable recipe runtime. Each invocation gets a unique non-profile browser session, never touches the implicit conversation session, serializes inner calls, and closes the isolated session in `finally`. It rejects caller `--session` / `--namespace` / `--config`, browser lifecycle and attachment commands, persistent launch/profile/restore controls, nested `batch`, local/sessionless commands, and every other top-level input mode. Every script-owned helper and cleanup subprocess also clears ambient `AGENT_BROWSER_*` and standard proxy variables before the wrapper reapplies its own isolated-session controls, so shell defaults cannot attach, restore, or select a profile behind the script’s back. The sandbox has no imports, `require`, process, filesystem, network, timers, dynamic code generation, or host object/function references.
422
434
 
423
435
  Limits are fixed: 25 attempted `browser()` calls, 64 KiB source, 64 KiB final emitted JSON, a 120-second default timeout, and a 300-second hard timeout ceiling. Final data is redacted, serialized compactly, and checked again before presentation; unsafe depth or post-redaction growth becomes a structured validation failure rather than unbounded prose. One approved top-level `agent_browser` call can authorize all 25 inner calls, so inspect the visible script source before approving it: the collapsed Pi tool row shows a bounded terminal-safe preview with source line breaks marked as `↵`, and expanding that row shows the full terminal-safe source with JavaScript line terminators preserved as visible newlines and removed controls marked visibly. The extension rehydrates only wrapper-verified parse-valid compact-result spills before returning inner `data`; ordinary result redaction still applies. Inner `summary` and `text` are bounded, and a complete envelope that still exceeds the IPC message cap becomes a handleable `upstream-error` browser result instead of breaking the sandbox bridge. Pi session persistence is required so the wrapper can append a model-invisible cleanup lease before the first browser launch and retry a failed close after restart. A rejected inner policy/validation call fails the top-level result even when source handles its returned envelope; an uncaught source exception returns `failureCategory: "script-error"`; a failed cleanup overrides any script outcome with `failureCategory: "cleanup-failed"`, `details.scriptSession.closeCommandArgs`, and an exact `close-script-session-after-cleanup-failure` next action. Compact prose confirms a successful isolated-session close after browser-bearing runs. Pi branch changes, quit, and reload abort active scripts, wait for isolated-session cleanup, and reap the sandbox child before restoring branch-visible state.
424
436
 
@@ -457,7 +469,7 @@ Typical pitfalls:
457
469
 
458
470
  ### Constrained browser jobs
459
471
 
460
- For short repeatable workflows, pass a top-level `job` instead of hand-writing `batch` stdin. Keep dynamic app jobs short around navigation, click, and rerender boundaries; avoid packing a whole checkout into one job. The wrapper only supports constrained steps (`open`, `click`, `fill`, `type`, `select`, `wait`, `assertText`, `assertUrl`, `waitForDownload`, `snapshot`, and `screenshot`), compiles them to existing upstream `batch` commands, and echoes the compiled commands as `details.compiledJob` for auditability. `open` steps can include `loadState` (`domcontentloaded`, `load`, or `networkidle`) to insert a readiness wait before the next step. `click` and `fill` steps can use either CSS `selector` or semantic locator fields (`locator`, `role`/`value`, optional `name`) so a job can express flows like role/name search without brittle selectors. `type` can use `selector`, `text`, optional `delayMs` for per-character pacing, and optional `press` for a final key such as `Enter`; paced type compiles to existing `focus`, `keyboard type`, `wait`, and `press` batch rows, is capped at 200 characters per delayed step, and compacts model-visible batch text while full rows remain in `details.batchSteps`. The same compile path backs top-level `qa`, so long `qa` runs surface the same timeout evidence shape. If a long `job`, `qa`, or `batch` hits the wrapper watchdog, `details.timeoutPartialProgress` may recover per-step status (`completed`, `failed`, `pending`, or `unknown`), current page URL plus a title after the URL is verified, declared artifact paths that already exist on disk, and either a `retry-timeout-step` next action for the first incomplete read-only or idempotent step, `inspect-current-page-after-timeout` when the target is already verified, or a fail-fast `verify-page-target-after-timeout` batch that runs `get url` before `snapshot -i` when the target is unknown (see [`docs/TOOL_CONTRACT.md#details`](docs/TOOL_CONTRACT.md#details)). There is no separate catalog of reusable named browser recipes above one-shot ad hoc `script`, `job`, `qa`, and raw `batch`; `script` has no names, registry, or persistent workflow state; see [`docs/ARCHITECTURE.md#no-reusable-recipe-layer-yet`](docs/ARCHITECTURE.md#no-reusable-recipe-layer-yet) for the closed `RQ-0068` decision and when to revisit it.
472
+ For short repeatable workflows, pass a top-level `job` instead of hand-writing `batch` stdin. Keep dynamic app jobs short around navigation, click, and rerender boundaries; avoid packing a whole checkout into one job. The wrapper only supports constrained steps (`open`, `click`, `fill`, `type`, `select`, `wait`, `assertText`, `assertUrl`, `waitForDownload`, `snapshot`, and `screenshot`), compiles them to existing upstream `batch` commands, and echoes the compiled commands as `details.compiledJob` for auditability. `open` steps can include `loadState` (`domcontentloaded`, `load`, or `networkidle`) to insert a readiness wait before the next step. `click` and `fill` steps can use either CSS `selector` or semantic locator fields (`locator`, `role`/`value`, optional `name`) so a job can express flows like role/name search without brittle selectors. `type` can use `selector`, `text`, optional `delayMs` for per-character pacing, and optional `press` for a final key such as `Enter`; paced type compiles to existing `focus`, `keyboard type`, `wait`, and `press` batch rows, is capped at 200 characters per delayed step, and compacts model-visible batch text while full rows remain in `details.batchSteps`. The same compile path backs top-level `qa`, so long `qa` runs surface the same timeout evidence shape. If a long `job`, `qa`, or `batch` hits the wrapper watchdog, `details.timeoutPartialProgress` may recover per-step status (`completed`, `failed`, `pending`, or `unknown`), current page URL plus a title after the URL is verified, declared artifact paths that already exist on disk, and either a `retry-timeout-step` next action for the first incomplete read-only or idempotent step, `inspect-current-page-after-timeout` when the target is already verified, or a fail-fast `verify-page-target-after-timeout` batch that runs `get url` before `snapshot -i` when the target is unknown (see [`docs/TOOL_CONTRACT.md#details`](docs/TOOL_CONTRACT.md#details)). Timeout recovery follows the effective batch source and native artifact operand positions, including literal dash-leading paths. Executable retries preserve the original row in a one-row batch. There is no separate catalog of reusable named browser recipes above one-shot ad hoc `script`, `job`, `qa`, and raw `batch`; `script` has no names, registry, or persistent workflow state; see [`docs/ARCHITECTURE.md#no-reusable-recipe-layer-yet`](docs/ARCHITECTURE.md#no-reusable-recipe-layer-yet) for the closed `RQ-0068` decision and when to revisit it.
461
473
 
462
474
  `assertText` accepts only `text`, not selector or locator fields. Clicks can stale later `@refs`; split the job and take a fresh snapshot before using them.
463
475
 
@@ -586,7 +598,7 @@ Start a fresh launch with a different Chromium-compatible executable:
586
598
  }
587
599
  ```
588
600
 
589
- After resuming a wrapper-managed session whose daemon has fully stopped, the first current-page operation, including `get url` or `reload`, reopens the complete recorded URL, including its fragment, when automatic managed restore is enabled. Non-page calls such as `tab list` or `read <url>` may start a daemon first without losing that pending reopen. The wrapper verifies the observed page and discards old refs; take a fresh `snapshot -i` before using refs. This restores the URL with cookies/storage, not unsaved forms, JavaScript memory, or history. A still-live wrong tab is selected or reported as missing, never silently navigated. Explicit URL reads, URL `a11y`/`vitals`, `diff url`, `window new`, and explicit navigation/context changes do not require the old tab. Caller-owned/attached and restore-disabled sessions are not auto-reopened. Cancellation after the reopen CLI starts preserves the consumed marker in the aborted result; replay does not repeat the navigation. Cancellation before that attempt leaves the reopen pending.
601
+ After resuming a wrapper-managed session whose daemon has fully stopped, the first current-page operation, including `get url` or `reload`, reopens the complete recorded URL, including its fragment, when automatic managed restore is enabled. Non-page calls such as `tab list` may start a daemon without losing that pending reopen; explicit URL reads leave the managed browser and its pending reopen untouched. The wrapper verifies the observed page and discards old refs; take a fresh `snapshot -i` before using refs. This restores the URL with cookies/storage, not unsaved forms, JavaScript memory, or history. A still-live wrong tab is selected or reported as missing, never silently navigated. Explicit URL reads, URL `a11y`/`vitals`, `diff url`, `window new`, and explicit navigation/context changes do not require the old tab. Caller-owned/attached and restore-disabled sessions are not auto-reopened. Cancellation after the reopen CLI starts preserves the consumed marker in the aborted result; replay does not repeat the navigation. Cancellation before that attempt leaves the reopen pending.
590
602
 
591
603
  `window new` leaves its new `about:blank` page active; `diff url` leaves the observed second destination active, including redirects to `about:blank`. Direct calls and reached batch rows discard the old target and refs rather than repinning the old tab. If the final URL cannot be observed, run `get url` before a fresh `snapshot -i`; the second URL argument alone is not proof of the final page.
592
604
 
@@ -594,7 +606,38 @@ After a successful unnamed fresh launch, later default `sessionMode: "auto"` cal
594
606
 
595
607
  ## Authenticated/profile workflows
596
608
 
597
- The wrapper does not clone profiles or hide what upstream Chrome/Chromium profile or executable you chose. Passing `--profile` or `--executable-path` is an explicit upstream `agent-browser` choice. Visible page content from real profiles is model-visible and may persist in transcripts or saved artifacts; redaction protects credential-like cookie/storage/auth values, not ordinary page text you asked the browser to read.
609
+ ### Shared browser defaults
610
+
611
+ To reuse one signed-in browser across Pi sessions, configure native `agent-browser` defaults in `~/.agent-browser/config.json`:
612
+
613
+ ```json
614
+ {
615
+ "session": "shared-work",
616
+ "namespace": "",
617
+ "profile": "/absolute/path/to/persistent-browser-profile",
618
+ "headed": true
619
+ }
620
+ ```
621
+
622
+ Use a dedicated full profile directory path, not a copied Chrome profile name. Add native `executablePath` if needed. Ordinary `args`, `semanticAction`, `job`, `qa`, and lookup calls then select that same caller-owned browser without repeating flags. This is separate from the advisory Pi package `browser.defaultProfile` setting. Existing native project config, environment and per-call flags keep their precedence; `--config` or `AGENT_BROWSER_CONFIG` replaces user/project config discovery.
623
+
624
+ Pi quit does not close a caller-owned shared browser or impose its implicit 15-minute idle timeout. Native idle policy applies, including its default headed-browser exemption; explicit `--idle-timeout` applies to every helper in that call too. Keep native idle settings consistent between calls because changing them can restart the daemon. `AGENT_BROWSER_SOCKET_DIR` is honored for caller-owned sessions; the wrapper-specific socket override still takes priority.
625
+
626
+ A configured native session, like explicit `--session`, takes precedence over `sessionMode: "fresh"`. To select a different browser, override the native session **and** profile/config as appropriate; changing only the name can contend for the same profile. Without a configured session, implicit ownership and fresh rotation are unchanged. `script` remains disposable: its helpers and cleanup use an empty temporary native config, never your user/project profile defaults. Electron launch retains its own isolated app lifecycle and generated session, even with a native session environment default. With a shared native default configured, target Electron's returned `sessionName` explicitly for browser follow-ups.
627
+
628
+ Use `{ "args": ["session", "info"] }` for one read-only preflight of the selected native session (or add `--namespace` / `--session` explicitly). It separates daemon activity/PID from verified browser liveness, Chrome PID, exact profile, tabs and native launched/attached ownership. Pi cleanup ownership is separate: a caller-owned shared browser is not closed by Pi, while an explicit name can still identify a wrapper-owned browser. Missing native fields remain unknown, never inferred from config or a live daemon.
629
+
630
+ Policy-required URL reads keep the two-call read → confirm/deny flow. Returned actions name the actual native namespace/session, including `default`; routing survives transcript resume and branch changes. Only explicit-read provenance plus native `capabilities.readRequiresConfirmation: true` permits matching confirm/deny without page helpers. This capability includes native confirmation-ID checking. Legacy prompts retain correct routing but normal page checks; DOM or content-shaped prompts never receive the exemption.
631
+
632
+ Full live identity, browser-independent native reads/confirmations and detailed recording receipts require the companion upstream fixes; the current recommended release does not yet supply all of them. Older supported versions remain accepted with unavailable evidence marked unknown. The extension does not upgrade or restart your installed browser to obtain these fields.
633
+
634
+ Coordinate tabs/navigation between agents sharing a browser; the wrapper's per-session queue is local to one Pi process. Persistent profile storage preserves browser data, not a promise of permanent website login: sites can expire or revoke sessions and require a new human challenge. Standing permission avoids repeated permission requests, but cannot change those site policies.
635
+
636
+ Before enabling global native profile defaults, update and fully restart every participating Pi runtime. Older loaded wrappers can still let disposable `script` launches read HOME config; editing this source or running `/reload` does not replace their cached code. Coordinate the browser cutover too: moving an existing daemon from the old wrapper's explicit 15-minute idle timeout to native idle policy changes its launch fingerprint and can restart it. Do not change that policy while another agent is using the browser.
637
+
638
+ ### Profile selection
639
+
640
+ The wrapper does not clone profiles or hide what upstream Chrome/Chromium profile or executable you chose. Passing `--profile` or `--executable-path` is an explicit upstream `agent-browser` choice. Visible page content from real profiles is model-visible and may persist in transcripts or saved artifacts; redaction protects credential-like cookie/storage/auth values, not ordinary page text you asked the browser to read. Redactions use `[REDACTED]` (URL-encoded in parsed URLs); ordinary technical phrases such as `bearer token` stay intact. URL redaction includes `code`, `authorization_session_id`, and auth-context `state` / `nonce` across visible text, details, spills, and `outputPath` exports. URLs needing no redaction keep their original spelling.
598
641
 
599
642
  Use these rules:
600
643
 
@@ -713,7 +756,7 @@ The opt-in real-upstream suite is separate because it drives a real browser inst
713
756
  npm run verify -- real-upstream
714
757
  ```
715
758
 
716
- That mode sets `PI_AGENT_BROWSER_REAL_UPSTREAM=1` and runs `test/agent-browser.real-upstream-contract.test.ts` against the real `agent-browser` on `PATH` (the stable version must meet the 0.35.0 floor; current command-reference validation targets the recommended 0.36.0 capability baseline). It covers inspection, skills, experimental WebMCP list/invoke/result/cancel plus `--no-webmcp`, and a broad core interaction and navigation matrix on localhost fixtures (including off-viewport click, frame-scoped selector/wait/click behavior, form command fixes, `batch` stdin, and `pushstate`), plus `vitals`, network route/requests/HAR, diff snapshot/screenshot/url, trace/profiler, console/errors/highlight, stream enable/status/disable, `cookies set --curl`, a `react tree` missing-renderer path, and `wait --download` with the on-disk caveat documented in release notes. The harness uses a throwaway temp `HOME` and dedicated socket/screenshot directories so the run does not touch your normal browser profile paths. Browser-opening or credential-dependent families such as `inspect`, `dashboard`, `chat`, provider clouds, and OS clipboard flows stay in fake-upstream or manual validation unless a safe deterministic fixture is added. For prerequisites, isolation details, and troubleshooting, see [`docs/RELEASE.md`](docs/RELEASE.md#real-upstream-contract-validation).
759
+ That mode sets `PI_AGENT_BROWSER_REAL_UPSTREAM=1` and runs `test/agent-browser.real-upstream-contract.test.ts` against the real `agent-browser` on `PATH` (the stable version must meet the 0.35.0 floor; current command-reference validation targets the recommended 0.37.0 capability baseline). It covers inspection, skills, experimental WebMCP list/invoke/result/cancel plus `--no-webmcp`, and a broad core interaction and navigation matrix on localhost fixtures (including off-viewport click, frame-scoped selector/wait/click behavior, form command fixes, `batch` stdin, and `pushstate`), plus `vitals`, network route/requests/HAR, diff snapshot/screenshot/url, trace/profiler, console/errors/highlight, stream enable/status/disable, `cookies set --curl`, a `react tree` missing-renderer path, and `wait --download` with the on-disk caveat documented in release notes. The harness uses a throwaway temp `HOME` and dedicated socket/screenshot directories so the run does not touch your normal browser profile paths. Browser-opening or credential-dependent families such as `inspect`, `dashboard`, `chat`, provider clouds, and OS clipboard flows stay in fake-upstream or manual validation unless a safe deterministic fixture is added. For prerequisites, isolation details, and troubleshooting, see [`docs/RELEASE.md`](docs/RELEASE.md#real-upstream-contract-validation).
717
760
 
718
761
  A deterministic host-only live-browser wrapper smoke is available without an LLM choosing tool calls:
719
762
 
@@ -746,12 +789,12 @@ npm run verify -- release
746
789
  5. Screenshots, downloads, recordings, traces, profiles, and spill files are normalized as Pi-visible artifacts where possible.
747
790
  6. Generated playbook text in docs and tool metadata stays aligned with `extensions/agent-browser/lib/playbook.ts`.
748
791
 
749
- The upstream browser engine remains [`agent-browser`](https://agent-browser.dev/). This package does not bundle it. The recommended baseline is 0.36.0 and the stable runtime floor is 0.35.0; newer stable versions are accepted without version-specific compatibility shims.
792
+ The upstream browser engine remains [`agent-browser`](https://agent-browser.dev/). This package does not bundle it. The recommended baseline is 0.37.0 and the stable runtime floor is 0.35.0; newer stable versions are accepted without version-specific compatibility shims.
750
793
 
751
794
  ## Current limits
752
795
 
753
796
  - Published pre-1.0 package.
754
- - Recommends upstream `agent-browser` 0.36.0 and accepts stable runtimes at or above 0.35.0.
797
+ - Recommends upstream `agent-browser` 0.37.0 and accepts stable runtimes at or above 0.35.0.
755
798
  - Does not bundle `agent-browser`; users install it separately.
756
799
  - Does not provide a human browser UI inside Pi; the primary UX is agent-invoked tool calls. `--headed` asks upstream to show a browser window, but the wrapper cannot yet prove that the window is visible on the user's desktop.
757
800
  - Localhost means the browser host's loopback, not necessarily the shell/Pi host. If `http://localhost:<port>` or `http://127.0.0.1:<port>` fails with errors such as `ERR_EMPTY_RESPONSE`, use an environment-specific host-reachable HTTP(S) address. A `file://` fixture is supported when upstream browser launch settings allow it; use HTTP(S) only when the browser environment cannot reach the local file.
@@ -813,7 +856,7 @@ These calls return plain text and stay stateless: the extension does not inject
813
856
  <!-- agent-browser-playbook:start wrapper-tab-recovery -->
814
857
  <!-- Generated from extensions/agent-browser/lib/playbook.ts. Run `npm run docs -- playbook write` to update. -->
815
858
  - 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.
816
- - After confirmed shutdown of an automatically restored managed session, the wrapper retains its complete recorded URL, including the fragment, until the first current-page operation (including get url and reload). Non-page calls such as tab list or read <url> may start a daemon without fulfilling that reopen. The wrapper uses native open once, verifies the observed tab, and discards old refs/frame scope; it does not restore unsaved forms, JavaScript memory, or history. Explicit navigation, caller-owned/attached sessions, and restore-disabled sessions are not auto-reopened.
859
+ - After confirmed shutdown of an automatically restored managed session, the wrapper retains its complete recorded URL, including the fragment, until the first current-page operation (including get url and reload). Non-page calls such as tab list may start a daemon without fulfilling that reopen; explicit URL reads leave the managed browser and pending reopen untouched. The wrapper uses native open once, verifies the observed tab, and discards old refs/frame scope; it does not restore unsaved forms, JavaScript memory, or history. Explicit navigation, caller-owned/attached sessions, and restore-disabled sessions are not auto-reopened.
817
860
  - For a still-live browser after tab drift or resume, the wrapper verifies/selects the intended tab before ref/semantic helpers and page commands; failed selection stops the call without navigating. Local commands, read <url>, URL a11y/vitals, diff url, window new, and explicit tab/navigation/connection/state recovery do not require the prior tab. Batch checks follow effective rows past non-page prefixes and stop at explicit context changes, preserving caller argv/stdin and continue-on-error behavior. Same-tab reselection is avoided because it clears refs. Use exact batch --bail for fail-fast, not --bail=<value>. Routine same-session calls skip tab-list preflights.
818
861
  - 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.
819
862
  - 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.