pi-agent-browser-native 0.9.0 → 0.9.2

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 (47) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +19 -3
  3. package/dist/extensions/agent-browser/index.js +3 -107
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +1 -1
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +3 -3
  6. package/dist/extensions/agent-browser/lib/browser-transcript.js +1 -1
  7. package/dist/extensions/agent-browser/lib/command-taxonomy.js +0 -3
  8. package/dist/extensions/agent-browser/lib/config-policy.js +0 -13
  9. package/dist/extensions/agent-browser/lib/config.js +3 -48
  10. package/dist/extensions/agent-browser/lib/electron/launch.js +4 -4
  11. package/dist/extensions/agent-browser/lib/input-modes/params.js +2 -3
  12. package/dist/extensions/agent-browser/lib/input-modes/script.js +28 -6
  13. package/dist/extensions/agent-browser/lib/input-modes/types.js +2 -2
  14. package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +4 -0
  15. package/dist/extensions/agent-browser/lib/managed-session-restore.js +1 -4
  16. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +0 -9
  17. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-merge.js +22 -0
  18. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +1 -1
  19. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +2 -2
  20. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +4 -3
  21. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +1 -1
  22. package/dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-observation.js +6 -2
  23. package/dist/extensions/agent-browser/lib/orchestration/execution-queue.js +86 -0
  24. package/dist/extensions/agent-browser/lib/orchestration/native-session-defaults.js +4 -3
  25. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +1 -1
  26. package/dist/extensions/agent-browser/lib/playbook.js +5 -4
  27. package/dist/extensions/agent-browser/lib/process.js +0 -3
  28. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +2 -2
  29. package/dist/extensions/agent-browser/lib/results/network-routes.js +1 -1
  30. package/dist/extensions/agent-browser/lib/results/network.js +1 -1
  31. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +7 -1
  32. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +1 -1
  33. package/dist/extensions/agent-browser/lib/results/presentation/common.js +1 -0
  34. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +1 -1
  35. package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +2 -2
  36. package/dist/extensions/agent-browser/lib/results/selector-recovery.js +1 -1
  37. package/dist/extensions/agent-browser/lib/runtime.js +4 -2
  38. package/dist/extensions/agent-browser/lib/session-page-state.js +1 -1
  39. package/dist/extensions/agent-browser/lib/web-search.js +15 -15
  40. package/docs/ARCHITECTURE.md +9 -8
  41. package/docs/COMMAND_REFERENCE.md +26 -4
  42. package/docs/RELEASE.md +1 -1
  43. package/docs/REQUIREMENTS.md +2 -1
  44. package/docs/SUPPORT_MATRIX.md +6 -3
  45. package/docs/TOOL_CONTRACT.md +12 -9
  46. package/package.json +3 -3
  47. package/scripts/doctor.mjs +10 -2
@@ -516,7 +516,7 @@ The upstream screenshot aliases are `screenshot --full` for full-page capture an
516
516
 
517
517
  Prefer `download <selector> <path>` when the target element itself is the downloadable link/control. Native download always owns the click and download, including loopback links, generated Blob exports, and redirects; the wrapper never substitutes a fetch of the anchor's `href`. Use `click` plus `wait --download [path]` when a previous action starts the download indirectly.
518
518
 
519
- Screenshot `imageObservations` includes verified pixel dimensions and capture kind. Matching pre/post CSS viewport, scroll, DPR, and crop samples may establish a measured document-space mapping; otherwise geometry remains unknown, including unmeasured batches and uncertain scrolled/iframe element captures. Native mouse uses current viewport CSS pixels. Account separately for crop origin, current scroll/frame, and any Pi resize before using coordinates; prefer refs. See [image geometry](TOOL_CONTRACT.md#image-observations). Code only attaches images selected with `emitImage` from a current-cell handle.
519
+ Screenshot `imageObservations` includes verified pixel dimensions and capture kind. Positively identified Lightpanda images also carry `rendering: "text"`: their text representation is not graphical layout and never establishes CSS/mouse coordinates. Matching pre/post CSS viewport, scroll, DPR, and crop samples may establish a measured document-space mapping; otherwise geometry remains unknown, including unmeasured batches and uncertain scrolled/iframe element captures. Native mouse uses current viewport CSS pixels. Account separately for crop origin, current scroll/frame, and any Pi resize before using coordinates; prefer refs. See [image geometry](TOOL_CONTRACT.md#image-observations). Code only attaches images selected with `emitImage` from a current-cell handle.
520
520
 
521
521
  For evidence-only screenshots, QA captures, or audit artifacts, save to an explicit path and branch on `details.artifactVerification` plus `details.artifacts` before reporting PASS/FAIL. Inline image attachments are optional convenience when size limits allow; do not require vision review unless the user asked for visual inspection.
522
522
 
@@ -759,6 +759,8 @@ These calls return plain text and stay stateless: the extension does not inject
759
759
  | `cookies [get|set|clear]` | Manage cookies. Full set form: `cookies set <name> <value> --url <url> --domain <domain> --path <path> --httpOnly --secure --sameSite <Strict|Lax|None> --expires <timestamp>`; also supports `cookies set --curl <file>` for JSON, cURL, or bare Cookie-header bulk imports. |
760
760
  | `storage <local|session>` | Manage web storage. |
761
761
 
762
+ `cookies set --curl <file>` selects native file-import mode even when `--curl` follows other set operands. Ordinary import paths remain visible in invocation echoes and failed batch diagnostics; inline cookie values, sensitive flags, and secret-bearing path text still redact. File contents are not echoed by this exception.
763
+
762
764
  Privacy note: `cookies get` can expose real profile cookies. Do not run it against `--profile Default` or other authenticated profiles unless the user explicitly needs cookie inspection; prefer task-specific page actions and storage checks.
763
765
 
764
766
  ### WebMCP page tools
@@ -987,7 +989,7 @@ Example config:
987
989
  }
988
990
  ```
989
991
 
990
- Browser defaults are scoped: global/override `defaultProfile` with `policy: "always"` and a Chrome profile name (not a path), plus `executablePath`, become native subprocess defaults only for automatic root browsers and their helpers. Roots have distinct named sessions and restore keys; parents and descendants share one root through `PI_SUBAGENT_ROOT_SESSION_ID`. These defaults never apply to unrelated explicit sessions or Electron launches. Code selecting the ordinary root browser uses the same defaults. Profile paths, other policies, and project-only guidance remain advisory. Native restore keeps cookies/localStorage/sessionStorage, not new IndexedDB, service workers, or memory-only grants; verify app access after a real restart. Avoid global native profile changes or a shared writable profile path; see [shared browser defaults](../README.md#shared-browser-defaults). Configure profile/executable guidance globally, in trusted project config, or through `PI_AGENT_BROWSER_CONFIG`. Ask the agent to run `profiles` and `doctor` when profile resolution fails, then use the reported Chrome profile directory name, a full profile/user-data directory path if upstream accepts one, or the configured `browser.executablePath` with top-level `sessionMode: "fresh"`.
992
+ Browser defaults are scoped: global/override `defaultProfile` with `policy: "always"` and a Chrome profile name (not a path), plus `executablePath`, become native subprocess defaults only for automatic root browsers and their helpers when the effective engine is Chrome. Lightpanda omits these wrapper defaults, without changing caller-selected launch settings. Roots have distinct named sessions and restore keys; parents and descendants share one root through `PI_SUBAGENT_ROOT_SESSION_ID`. These defaults never apply to unrelated explicit sessions or Electron launches. Code selecting the ordinary root browser uses the same defaults. Profile paths, other policies, and project-only guidance remain advisory. Native restore keeps cookies/localStorage/sessionStorage, not new IndexedDB, service workers, or memory-only grants; verify app access after a real restart. Avoid global native profile changes or a shared writable profile path; see [shared browser defaults](../README.md#shared-browser-defaults). Configure profile/executable guidance globally, in trusted project config, or through `PI_AGENT_BROWSER_CONFIG`. Ask the agent to run `profiles` and `doctor` when profile resolution fails, then use the reported Chrome profile directory name, a full profile/user-data directory path if upstream accepts one, or the configured `browser.executablePath` with top-level `sessionMode: "fresh"`.
991
993
 
992
994
  ## Important global flags, config, and environment
993
995
 
@@ -1030,13 +1032,33 @@ The extension composes stock `--args --no-startup-window` for local Chrome start
1030
1032
  - `--cdp <port|url>`: connect through Chrome DevTools Protocol. Use it, `--auto-connect`, or `connect <port|url>` once on a named/fresh session, verify with `get url`, then reuse that session without repeating the attach flag. After a successful attachment the wrapper avoids re-emitting its own compatibility launch argument; caller launch/config/file-access settings remain unchanged. Content-bearing first use is blocked until URL verification; later page reads/interactions live-check the URL because the attached browser can drift externally. `close` clears attachment state.
1031
1033
  - `--color-scheme <scheme>`: `dark`, `light`, or `no-preference`. Environment: `AGENT_BROWSER_COLOR_SCHEME`.
1032
1034
  - `--download-path <path>`: default browser download directory. Environment: `AGENT_BROWSER_DOWNLOAD_PATH`.
1033
- - `--engine <name>`: browser engine, `chrome` by default or `lightpanda`. Environment: `AGENT_BROWSER_ENGINE`.
1035
+ - `--engine <name>`: browser engine, `chrome` by default or `lightpanda`. Environment: `AGENT_BROWSER_ENGINE`. Launch-scoped; use `sessionMode: "fresh"` when changing a managed browser. See [Lightpanda](#lightpanda-engine).
1034
1036
 
1035
1037
  On Android/Termux, follow the README setup to install the packaged Linux-musl arm64 upstream binary, install Termux's `which`, and expose its launcher as `$PREFIX/bin/chromium`. Prefer that upstream system-browser discovery over ambient `AGENT_BROWSER_EXECUTABLE_PATH`: it survives isolated `HOME` values and works for ordinary native calls. Code retains the selected browser's normal launch configuration. Wrapper-generated Android managed identities use a compact 80-bit digest so ordinary namespaces and fresh rotations fit upstream's Unix socket path.
1036
1038
 
1037
1039
  - `--no-auto-dialog`: disable automatic dismissal of alert/beforeunload dialogs. Environment: `AGENT_BROWSER_NO_AUTO_DIALOG`.
1038
1040
  - `--idle-timeout <ms>`: native background browser lifecycle setting (also accepts `10s`, `3m`, `1h`). Caller-owned sessions retain native idle policy; an explicit flag is carried to every helper in that call. Keep it consistent between calls to avoid a native daemon restart. Only wrapper-owned sessions receive the implicit timeout and numeric mismatch check against `PI_AGENT_BROWSER_IMPLICIT_SESSION_IDLE_TIMEOUT_MS`.
1039
1041
 
1042
+ ### Lightpanda engine
1043
+
1044
+ [Lightpanda 1.0](https://lightpanda.io/blog/posts/lightpanda-1-0) is an optional headless engine, installed separately from this package and `agent-browser`. The [native engine guide](https://github.com/vercel-labs/agent-browser/blob/v0.38.2/docs/src/app/engines/lightpanda/page.mdx) describes setup. Put its `lightpanda` executable on `PATH`; select it with `--engine lightpanda`, `AGENT_BROWSER_ENGINE=lightpanda`, or native config `engine`. Chrome remains the default.
1045
+
1046
+ ```json
1047
+ { "args": ["--engine", "lightpanda", "open", "https://example.com"], "sessionMode": "fresh" }
1048
+ { "args": ["snapshot", "-i"] }
1049
+ { "args": ["screenshot", "/tmp/lightpanda-text.png"] }
1050
+ { "args": ["close"] }
1051
+ ```
1052
+
1053
+ - Engine selection belongs on launch, not routine follow-ups. Changing an active wrapper-managed browser returns the existing fresh-session recovery; caller-owned sessions retain native lifecycle semantics.
1054
+ - Package `browser.defaultProfile` / `browser.executablePath` Chrome bootstrap defaults are omitted when CLI → environment → native config selects Lightpanda. Caller-selected profile, executable, config and environment values remain untouched; upstream validates combinations.
1055
+ - `open`, snapshots/refs, form interaction, getters, `eval --stdin`, native batch and browser code can work, but successful dispatch is not Chrome-parity visibility or layout evidence. By default Lightpanda skips external stylesheets, images, iframes and workers. Snapshot/hidden-element and overlay/scroll assumptions differ from Chrome.
1056
+ - Screenshots are PNGs rendering page markdown/text. Native engine metadata identifies them for direct, batch and selected code output; standalone geometry samples can also recognize the browser's Lightpanda brand on attachments or older native results. Identified images carry `rendering: "text"` with unknown geometry and no crop/scale mapping. They remain verified image attachments, not graphical captures or a basis for mouse coordinates. Missing provenance stays unknown.
1057
+ - Lightpanda currently permits one target per browser context; `tab new` can fail. Use separate native sessions for independent pages, or Chrome when the task needs multiple tabs. Do not infer broad authentication/restore parity from a single-origin storage result.
1058
+ - Native Lightpanda launch rejects Chrome profiles/extensions, headed mode, launch `--state`, WebGPU, file-access switches, Chromium `--args`, and private CA trust. Native WebMCP currently rejects this engine even though Lightpanda advertises its own WebMCP support. There is no wrapper workaround or automatic Chrome fallback; choose a fresh Chrome launch explicitly when those capabilities are needed.
1059
+ - Lightpanda 1.0 enforces CORS by default, so cross-origin page `fetch`/XHR can fail where earlier Lightpanda did not. Preserve that protection; navigation is a separate capability.
1060
+ - The 1.0 release provides macOS/Linux x86_64/ARM64 binaries (Linux glibc), not native Windows/Android. Remote CDP or WSL is a separate setup, not native-platform qualification. Telemetry is upstream-owned; `LIGHTPANDA_DISABLE_TELEMETRY=true` opts out.
1061
+
1040
1062
  ### Output, provider, policy, and AI flags
1041
1063
 
1042
1064
  - `--json`: JSON output. The wrapper injects this automatically for normal tool execution. Environment: `AGENT_BROWSER_JSON`.
@@ -1078,7 +1100,7 @@ Other useful environment variables include `AGENT_BROWSER_DEFAULT_TIMEOUT`, `AGE
1078
1100
  ## Wrapper-specific behavior worth knowing
1079
1101
 
1080
1102
  - The extension may keep following one implicit managed session across later tool calls.
1081
- - If launch-scoped flags like `--profile`, `--args`, `--user-agent`, `--executable-path`, `--ca-cert`, `--no-ca-cert`, `--webgpu`, `--no-webmcp`, `--restore`, `--restore-save`, restore check flags, `--namespace`, `--session-name`, `--cdp`, `--state`, `--auto-connect`, `--init-script`, `--enable`, `--provider` / `-p`, or provider device flags like `--device` would replace or be ignored by an already-active managed session, retry with `sessionMode: "fresh"`. When the call explicitly names the current managed session, the structured recovery payload removes that `--session` so the fresh rotation can succeed.
1103
+ - If launch-scoped flags like `--engine`, `--profile`, `--args`, `--user-agent`, `--executable-path`, `--ca-cert`, `--no-ca-cert`, `--webgpu`, `--no-webmcp`, `--restore`, `--restore-save`, restore check flags, `--namespace`, `--session-name`, `--cdp`, `--state`, `--auto-connect`, `--init-script`, `--enable`, `--provider` / `-p`, or provider device flags like `--device` would replace or be ignored by an already-active managed session, retry with `sessionMode: "fresh"`. When the call explicitly names the current managed session, the structured recovery payload removes that `--session` so the fresh rotation can succeed.
1082
1104
  - 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.
1083
1105
  <!-- agent-browser-playbook:start wrapper-tab-recovery -->
1084
1106
  <!-- Generated from extensions/agent-browser/lib/playbook.ts. Run `npm run docs -- playbook write` to update. -->
package/docs/RELEASE.md CHANGED
@@ -274,7 +274,7 @@ These show up often in cloud dev boxes and scripted smokes; they are maintainer
274
274
  | Topic | What to watch for | Mitigation |
275
275
  | --- | --- | --- |
276
276
  | **Pi CLI vs repo devDependencies** | Global `pi` older than the minimum Pi runtime floor for the release can change TUI behavior, `/reload`, package installs, and tool routing during lifecycle or checkout smokes. | Run `npm run doctor` and align `pi` with the current audited baseline before release gates (`pi update` or install the matching version). The published peer range stays wildcard per Pi package docs, and the doctor enforces the minimum Pi runtime floor before package validation. |
277
- | **npm lockfile (`packageManager`)** | `package.json` pins **npm@12.1.0** for the Node 24.21.0 runtime baseline. Older npm versions can rewrite optional-platform metadata in `package-lock.json`; private registry proxies can also leak organization URLs into `resolved` entries. | Prefer `npx -y npm@12.1.0 install` when refreshing the lockfile; do not commit unrelated lockfile churn or WorkOS/private-registry URLs. |
277
+ | **npm lockfile (`packageManager`)** | `package.json` pins **npm@12.2.0** for the Node 24.21.0 runtime baseline. Older npm versions can rewrite optional-platform metadata in `package-lock.json`; private registry proxies can also leak organization URLs into `resolved` entries. | Prefer `npx -y npm@12.2.0 install` when refreshing the lockfile; do not commit unrelated lockfile churn or WorkOS/private-registry URLs. |
278
278
  | **`pi -p` / print mode** | Non-interactive `pi -p` may hang or emit no stdout for long real-browser smokes without a TTY. | Use **tmux**-driven interactive `pi` for release evidence and checkout smokes; reserve `-p` for short, non-browser checks. |
279
279
  | **Real-browser cleanup** | `real-upstream`, Sauce Demo, and live-site runs can leave defunct Chrome/`agent-browser` children if a session aborts mid-flow. | Close via `agent_browser` / `agent-browser` `close`, kill stray tmux sessions, and remove temp screenshots/HARs under `/tmp` or your chosen artifact dirs. |
280
280
  | **Automated prompt driving** | Grepping tmux pane text for words that also appear in the **user** prompt (`PASS`, `FAIL`, `checkout overview`, `Smoke result:`) can false-complete before the agent finishes. | Wait for pane idle (no `Working…`), `agent_browser close` / `Artifact lifecycle`, or JSONL tool results—not instruction phrases copied from the prompt. |
@@ -72,8 +72,9 @@ Define the product requirements and constraints for `pi-agent-browser-native`.
72
72
  - Hold a cooperating-process execution lock keyed by actual socket context, canonical namespace, and session across direct helper/action work or the entire code cell. Use ordered multi-identity acquisition for replacement/cleanup and a namespace barrier for direct close-all. This does not coordinate humans, third-party clients, or older versions, guarantee atomic browser actions, or provide rollback.
73
73
  - Persist one canonical begin/finish event format for direct/code/host work through native Pi custom entries and a shared reducer. Define full captures once, preserve exact targets/native identity, and persist artifact-row changes rather than unchanged views. Interrupted outcomes remain unknown until inspection; failed begin blocks dispatch and failed finish stops dependent work without mutation retry. Require actual journal publication before browser dispatch. Legacy browser/lease decoders belong only to validated offline stopped-copy conversion; preserve original bytes, all ancestry and owner UUIDs. A fork must never acquire its parent's cleanup rights. Bound extension replay with token projection and winning definitions on both hosts, while disclosing stock official Pi's eager native loader and individual-value memory ceilings; see [`SESSION_STORAGE.md`](SESSION_STORAGE.md).
74
74
  - Use one canonical model-visible observation for JSON/prose/code with success/data/error, exact recovery, artifact receipts, and image observations. Native `outputSchema`/`structuredContent` under the Browser tool namespace expose that same bounded redacted projection, not raw internal details. Loader inventory and normalized search data keep their existing shapes. Details is audit/replay metadata, not the sole source of actionable failures. Return canonical native `isError` without a result-repair hook; preserve prose notices and explicit JSON. Inner calls avoid full model rendering/spills/image encoding. Bound outer output and name a complete redacted observation spill rather than truncating executable payloads.
75
- - Attach only verified real images; code selects current-cell image handles explicitly. Report pixel dimensions and CSS viewport/DPR/crop/scroll/frame evidence conservatively. Unknown geometry remains unknown; neither full-page nor element captures are assumed viewport coordinates. Do not inject model-specific image-detail/provider payload changes.
75
+ - Attach only verified real images; code selects current-cell image handles explicitly. Report pixel dimensions and CSS viewport/DPR/crop/scroll/frame evidence conservatively. Unknown geometry remains unknown; neither full-page nor element captures are assumed viewport coordinates. Positively identified Lightpanda images are text-rendered, never graphical CSS/mouse-coordinate evidence. Do not inject model-specific image-detail/provider payload changes.
76
76
  - Direct upstream capability remains available: explicit sessions, state/restore paths, profiles, config, file access, launch arguments, environment, local pages, output paths, and close arguments pass through under ordinary native semantics. Keep all session/state rows visible. Wrapper validation concerns input shape, lifecycle integrity, and truthful evidence, not authorization of resources.
77
+ - Keep Chrome default and separately installed Lightpanda opt-in. Treat `--engine` as launch-scoped through existing managed fresh-launch recovery. Omit only wrapper-supplied Chrome profile/executable defaults when Lightpanda is selected; preserve native caller settings and unsupported-command errors. No new driver, engine cache, browser bundle, or automatic Chrome fallback.
77
78
  - Native download owns clicking and saving, including loopback, Blob exports, and redirects. Create artifact directories before dispatch and verify saved files; output-data writes must not alias browser artifacts. Pending recording is not saved video.
78
79
  - Maintain a deliberate 0.7 migration map and package-level rollback that preserves saved authentication, explicit artifacts, and Pi transcripts. Restart every cooperating Pi participant on the updated package before relying on shared ordering. No universal performance, sandbox, authentication-persistence, or Windows qualification claims.
79
80
 
@@ -40,6 +40,7 @@ The compact direct/code/loader surface replaces public multimode inputs while re
40
40
  | RQ-0142 code | Fresh permissioned Node child over persistent parent-selected browser; explicit JSON/current-cell image output, visible failures/counts, ordinary auth/config/environment, ordered Pi intent/completion transitions, child cancellation/reaping, no legacy public execution. |
41
41
  | Hotpath boundaries | Unrelated tools/harmless Bash return before prompt policy. Latest raw user intent is seeded on start/tree, updated by `message_end` and refreshed after native content replacement. Captured admission uses a validated append-only prefix; one queued replay restores branch/lease state and folds per-session launch settings once. Per-row renderer memoization skips unchanged formatting. No broad config/trust/history cache, new wait/timer or budget increase. |
42
42
  | Shared ordering | Actual socket/namespace/session lock spans helper/action or entire cell; sorted identity sets for replacement/cleanup and namespace barrier for direct close-all. Requires every participating Pi to run the updated package; no human/third-party/older-version guarantee or transaction. |
43
+ | Lightpanda engine | Chrome remains default; separately installed Lightpanda is opt-in. `--engine` uses existing managed fresh-launch recovery; effective CLI/env/config Lightpanda omits wrapper Chrome profile/executable defaults while preserving native choices. Positively identified images are text-rendered with unknown geometry, not visual/coordinate parity. No automatic fallback. `test/agent-browser.runtime.test.ts`, `test/agent-browser.shared-defaults.test.ts`, and `test/agent-browser.screenshot-geometry.test.ts` own the regressions; [limits](COMMAND_REFERENCE.md#lightpanda-engine). |
43
44
  | Observation and geometry | Canonical bounded JSON/prose/code/native `structuredContent` observations expose exact recovery and receipts, with native namespace/output-schema metadata and canonical returned `isError`; complete observation spills preserve large output. Image dimensions/CSS viewport/DPR/crop/scroll/frame evidence is measured or explicitly unknown; no viewport-coordinate assumptions for full-page/element images. |
44
45
  | Pi integration | Pi 1.0 floor with independently qualified official/fork graphs. Five advanced direct tools use native `defaultActive: false`; a narrow additive initial-resume fallback preserves available transcript selections without overriding explicit/defaultTools/filtered host selection. Loader/tree/reload retain native history; public `pi:instruction-groups` registration supplies one full `browser` instruction source. Managed hosts own deferred delivery; unmanaged/stock hosts receive identical full eager guidance even for generic prompts. No permission widening or legacy discovery metadata. `test/agent-browser.discovery.test.ts` covers full-text parity, dynamic ownership, and startup/late registration; tool-surface tests preserve host selections, with pipeline coverage in `test/agent-browser.pi-pipeline.test.ts`. No checkpoint or fork metadata/revision APIs, provider payload edits or image-detail overrides. |
45
46
 
@@ -99,7 +100,7 @@ Browser evidence (RQ-0152) is covered by `test/agent-browser.browser-evidence.te
99
100
 
100
101
  Contributor fixes #133/#152 remove unused prompt suffix entries without changing runtime guidance and diagnose bare `--no-sandbox` only in the command slot or navigation option positions. Native `--args` values and literal operands remain intact; batch checks use raw effective rows without treating row-local `--args` as a launch setting. `test/agent-browser.chromium-args.test.ts` covers pre-dispatch rejection, literal/flag-value controls, inspection, raw/stdin batch precedence and dispatcher outcomes. Existing prompt/grammar checks remain; source checks do not replace native-product gates.
101
102
 
102
- Electron diagnostics (RQ-0096, #128) keep list timeout rejection truthful, label explicit-ID cleaned records as historical without changing active selection or actions, and measure the tracked profile path with native `lstat` (`present` / ENOENT-only `absent` / `unknown`). Existing Electron discovery/lifecycle tests cover current liveness independently of cleanup history, native path errors and dangling symlinks, transcript replay, and unchanged cleanup ownership. Failed-startup diagnostics include redacted last-4096-byte stdout/stderr tails in visible text and structured details, using private profile-local regular files. Regression tests cover exact tails, empty output, capture/spawn errors and closed native file handles; a real spawned fixture with injected kill denial proves live output through temp cleanup, retained logs through native host-exit behavior, and persistence failure reporting. Tracked-child cleanup regressions require actual exit before profile removal and immediate executable deletion. Restored-PID cleanup uses native process command-line evidence on Windows and POSIX; real-process regressions verify matching profiles with spaces/Unicode, refusal of unrelated or mismatched profiles, and shutdown after transcript restoration. The shared daemon policy verifies a restored Electron attachment's live browser endpoint and named upstream `get cdp-url` before ordinary calls, status, or probe reuse; `test/agent-browser.extension-ref-guards.test.ts` covers successful reuse and repeated rejection of replaced app, connection, and namespace identities without weakening generic restore-disabled rules. These checks do not replace native-app, Pi lifecycle, package, or live-site gates.
103
+ Electron diagnostics (RQ-0096, #128) keep list timeout rejection truthful, label explicit-ID cleaned records as historical without changing active selection or actions, and measure the tracked profile path with native `lstat` (`present` / ENOENT-only `absent` / `unknown`). Focused Electron discovery, host-lifecycle, and branch-ownership tests cover current liveness independently of cleanup history, native path errors and dangling symlinks, transcript replay, and unchanged cleanup ownership. Failed-startup diagnostics include redacted last-4096-byte stdout/stderr tails in visible text and structured details, using private profile-local regular files. Regression tests cover exact tails, empty output, capture/spawn errors and closed native file handles; a real spawned fixture with injected kill denial proves live output through temp cleanup, retained logs through native host-exit behavior, and persistence failure reporting. Tracked-child cleanup regressions require actual exit before profile removal and immediate executable deletion. Restored-PID cleanup uses native process command-line evidence on Windows and POSIX; real-process regressions verify matching profiles with spaces/Unicode, refusal of unrelated or mismatched profiles, and shutdown after transcript restoration. The shared daemon policy verifies a restored Electron attachment's live browser endpoint and named upstream `get cdp-url` before ordinary calls, status, or probe reuse; `test/agent-browser.extension-electron-branch-ownership.test.ts` covers successful reuse and repeated rejection of replaced app, connection, and namespace identities without weakening generic restore-disabled rules. These checks do not replace native-app, Pi lifecycle, package, or live-site gates.
103
104
 
104
105
  Artifact diagnostics (#124/#127) use a shared pre-dispatch mkdir-error boundary, preserve raw batch argv/precedence, recommend absolute raw artifact paths, recognize image headers rather than filename MIME guesses, retain known requested/reported paths, and warn once about conservative ref invalidation after dispatched recording starts and URL-bearing restarts, on success or failure, without claiming an observed page change. `test/agent-browser.artifact-diagnostics.test.ts` covers registered filesystem failures, real image bytes and misleading suffixes, the inline bound, native macOS path aliases, recording/ref continuity and unreached-row negatives; `test/agent-browser.presentation-artifacts-batch.test.ts` retains artifact/persistence coverage. These source regressions do not qualify daemon-cwd differences or affected-filesystem timestamp behavior (#118), or replace native/Pi/package/live-site gates.
105
106
 
@@ -115,6 +116,8 @@ Batch/ref fidelity (#122/#123/#125/#126): tab recovery uses verified native sele
115
116
 
116
117
  Overlay recovery (RQ-0073, #147) recommends only `inspect-overlay-state` after an upstream covered-click rejection, preserving `upstream-error` and the exact session/namespace. Direct, semantic, raw `find` (including `nth` and default-click), and failed native-batch paths share the matcher; hover and generic errors do not qualify. `test/agent-browser.overlay-click-recovery.test.ts` covers presentation and error envelopes, `test/agent-browser.pi-pipeline.test.ts` covers persisted errors and parseable JSON, and the opt-in `test/agent-browser.overlay-real-upstream.test.ts` checks actual covered clicks, executable inspection, and unchanged target/blocker click counters. This is not a fix for silent input dispatch (#62).
117
118
 
119
+ Lightpanda support preserves native command access rather than promising Chrome parity. Registered-tool image controls cover native metadata in direct/JSON, batch and selected code attachments plus standalone browser-brand evidence when legacy/attached native output omits or mislabels the engine. Verified image bytes remain unchanged and coordinate claims stay unknown even when dimensions match synthetic browser geometry. Root-default controls cover CLI/env/native-config precedence and untouched caller settings; engine planner controls preserve fresh/new/explicit launches. See [engine limits](COMMAND_REFERENCE.md#lightpanda-engine). Release evidence below remains separate from these focused regressions.
120
+
118
121
  Shared native defaults are covered by `test/agent-browser.shared-defaults.test.ts`: environment/file/argv precedence, caller-owned reuse across independent Pi contexts, quit ownership, native helper idle settings, unchanged implicit cleanup, and an opt-in real local-profile fixture proving shared state and code follows the selected ordinary browser rather than a disposable isolated session. Code tests cover the fresh child language boundary and persistent browser behavior; the local Electron handoff regression in `test/agent-browser.extension-electron-lifecycle.test.ts` keeps generated launch ownership despite a native session environment default; native config validation uses upstream rather than a second schema. See [shared browser defaults](../README.md#shared-browser-defaults). These tests do not promise permanent third-party authentication.
119
122
 
120
123
  Browser correctness regressions cover credential-bearing filtered network details/exports, native generated-Blob downloads with actual saved bytes, accessible-name click target identity and abstention, smooth CSS-container movement, and parseable early-result JSON. Native fixture coverage complements deterministic dispatch/cleanup and output-shape checks; release qualification remains separate.
@@ -143,7 +146,7 @@ Re-run the gates below before each release. Dated outcomes in this table are his
143
146
  | Windows argument transport (#102/#131/#141) | `test/agent-browser.windows-argv.test.ts` exercises actual host argv, empty values, quotes, Unicode/spaces, stdin, custom shims and failure outcomes. `test/agent-browser.windows-stock-launcher.test.ts` covers the recognized global npm CMD template's direct-native path, command selection, fallback, literal LF/CRLF and cancellation. Custom or unrecognized batch launchers retain their existing newline limitation. POSIX keeps Node `spawn`. | Native Windows focused qualification on 2026-09-21 passed all seven stock-launcher controls, all 29 Chromium cases and 33 process/argv cases (two existing platform skips). Actual upstream Rust received all 12 expected operands; the original CMD path lost all four newline-bearing operands. These focused results do not replace full-suite, managed-browser, package or release gates. |
144
147
  | Real upstream contract | `npm run verify -- real-upstream` runs the localhost fixture matrix against a real stable `agent-browser` at or above the configured floor. | **Earlier recommended 0.36.0:** pass on 2026-09-01 (2/2 tests), including WebMCP and `--no-webmcp`; the 0.35.0 floor last passed on 2026-08-26 (2/2 tests). |
145
148
  | Packaged Pi smoke | `npm run verify -- package-pi` validates package contents, installs the extracted tarball's runtime dependencies without lifecycle scripts or host peers, loads the packaged `agent_browser` tool without requiring optional Brave config, and executes fake-upstream `--version`. | **Earlier package 0.6.2 / Pi 0.84.4:** pass on 2026-09-01; the 127-file tarball loaded exactly one packaged `agent_browser` and executed `--version`. |
146
- | Startup profile | `npm run verify -- startup-profile --samples <n>` clean-builds generated `dist/`, records direct package entrypoint import/factory timing in fresh Node processes, and writes `.artifacts/startup-profile/latest.json`. It must not launch Pi, tmux, mise, npm, browsers, or `agent-browser`; full Pi TUI ready-prompt profiling is intentionally excluded after it proved too invasive for routine verification. Run this opt-in evidence when package layout, the compiled entrypoint, top-level imports, schema registration, or prompt/config startup logic changes. | **Earlier compiled 0.6.2 entrypoint:** pass on 2026-09-01 with three samples; median 104.9 ms and max 114.5 ms, below the 250 ms budget. |
149
+ | Startup profile | `npm run verify -- startup-profile --samples <n>` clean-builds generated `dist/`, records direct package entrypoint import/factory timing in fresh Node processes using the same `scripts/startup-measurement.mjs` measurement and 250ms budget as the startup owner test (the test retains its Android-only 1000ms exception), and writes `.artifacts/startup-profile/latest.json`. It must not launch Pi, tmux, mise, npm, browsers, or `agent-browser`; full Pi TUI ready-prompt profiling is intentionally excluded after it proved too invasive for routine verification. Run this opt-in evidence when package layout, the compiled entrypoint, top-level imports, schema registration, or prompt/config startup logic changes. | **Earlier compiled 0.6.2 entrypoint:** pass on 2026-09-01 with three samples; median 104.9 ms and max 114.5 ms, below the 250 ms budget. |
147
150
  | Deterministic dogfood smoke | `npm run verify -- dogfood` clean-builds, then `scripts/verify-agent-browser-dogfood.ts` drives the native wrapper against a loopback HTTP fixture through persistent code aggregation, advanced QA/actions, native batch, screenshot artifact verification, and session close with the real `agent-browser` on `PATH`. | **Earlier 0.36.0 / package 0.6.2 / Pi 0.84.4:** pass on 2026-09-01; QA, script branching/cleanup, fresh/current opens, semantic clicks, job screenshot verification, and close all passed. |
148
151
  | WebGPU and restore autosave | Live 0.31.2 feature probes validate the new upstream paths independently from ordinary browser dogfood. | **macOS:** `doctor --webgpu` passed Apple Metal render/readback and headless red-pixel screenshot checks; the official Hello Triangle sample exposed the Metal adapter and produced a verified non-black screenshot. **Ubuntu image:** `doctor --webgpu --headed --json` passed SwiftShader render/readback and red-pixel screenshot checks with the baked Vulkan/Mesa/Xvfb dependencies. **Restore autosave:** an idle headless page timer changed localStorage and the namespaced restore file contained the new value before close; test state was removed. Wrapper-owned headed launches default periodic autosave off to avoid upstream 0.33.2 visible temporary collector tabs; native close still saves, direct window close can lose newer state because headed browsers are exempt from idle shutdown, and explicit `AGENT_BROWSER_AUTOSAVE_INTERVAL_MS` opts in at daemon launch; its effective value persists across resume, and changing a running wrapper-owned headed daemon in either direction requires close plus a fresh launch. On 2026-08-06, a headed checkout dogfood run crossed `react.dev` → `example.com` → `react.dev`, idled past the autosave interval while recording, showed no temporary page switch in frame/contact-sheet review, and closed both sessions successfully; disposable evidence was removed. **Windows interactive desktop:** post-release validation on 2026-07-15 used a disposable clone of snapshot `57cc3c0d-7d7c-4a4c-9c57-8270d4174679`, a logged-in console session, `agent-browser 0.31.2`, and Edge 150. The headed doctor WebGPU render/readback subcheck passed in 0.99s and its decoded screenshot subcheck passed with `rgb(255,0,0)`; a separate `--webgpu --headed` launch opened the proof page and the Parallels console capture visibly recorded the red triangle (553,500 bright-red pixels; SHA-256 `f5a28f5336cbdfeb0ff557af9425458bddc6b266d3cc6b946de7b101a0b43288`). The full doctor remained nonzero only for the unrelated absence of a separately installed Chrome binary; the explicit Edge executable completed the launch and both WebGPU probes. Local evidence is under `.artifacts/windows-webgpu-interactive/20260715T150903Z/summary.json`; the disposable clone and temporary account were deleted afterward. |
149
152
  | Android/Termux local bring-up | Non-release-blocking source validation uses Termux system Chromium through upstream's Linux `which chromium` discovery, the packaged Linux-musl arm64 CLI, real Pi managed-session smoke, deterministic dogfood, and the default unit/package gate. Electron desktop lifecycle is not applicable. | **Historical 0.6 local evidence (not 0.7 code qualification):** Android 17 / arm64 Termux passed implicit, explicit, and namespaced fresh sessions, managed restore, script, QA, semantic action, job, click, eval/batch stdin, screenshot attachment, recording dependencies, and cleanup; Android is not yet a Crabbox release target. |
@@ -160,7 +163,7 @@ Runtime floor note: package metadata requires Node 24.21.0 or newer, keeps optio
160
163
  | --- | --- | --- | --- | --- | --- |
161
164
  | Built-in skills | 19 canonical tokens from baseline section `skills`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#built-in-skills). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#built-in-skills), generated baseline block, README proof section, release docs. | `needsManagedSession` keeps read-only skills inspection sessionless while preserving thin upstream passthrough; upstream `@agent-browser/sandbox` remains external package guidance, not a bundled wrapper dependency. | Runtime and extension-validation skills/provider matrix; real-upstream inspection/skills group. | Supported. |
162
165
  | Core page, element, navigation, and extraction commands | Canonical tokens from baseline section `core-commands`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#core-page-and-element-commands). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#core-page-and-element-commands), [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md), README quick start. | Thin passthrough with wrapper-owned JSON/session planning, ref guidance, artifact verification, page-change summaries, click-dispatch diagnostics only after native temporary-marker target identity readback (otherwise abstaining), inspection-only recovery for upstream overlay-blocked clicks, deterministic document scroll before wheel/no-op diagnostics and instant CSS-container movement, shorthand compilers, and redaction. | Real-upstream core matrix (including snapshot-ref select) plus fake core matrix for passthrough, ordering, diagnostics, and compiler validation. | Supported. Upstream semantics remain upstream-owned. |
163
- | Sessions, state, tabs, frames, dialogs, and windows | 28 canonical tokens from baseline section `state-tabs-frames-dialogs`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#session-state-frames-dialogs-windows-and-inspection-commands). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#session-state-frames-dialogs-windows-and-inspection-commands), stateful workflow notes, [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details). | Stateful summaries redact credentials while preserving restore identifiers and every session/state list row; explicit targets and paths pass through. Runtime retains state artifact verification, sessionless local command planning, automatic managed restore, native-CDP-ID tab recovery across duplicate URLs and transcript replay, reached failed-batch target invalidation/live verification, active-target refresh after tab close, and close alias cleanup. | Extension tab/ref tests, real-upstream stable-id/label tab lifecycle, runtime session/resume tests, presentation redaction tests, lifecycle harness. | Supported. External profile/auth state remains operator-owned. |
166
+ | Sessions, state, tabs, frames, dialogs, and windows | 28 canonical tokens from baseline section `state-tabs-frames-dialogs`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#session-state-frames-dialogs-windows-and-inspection-commands). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#session-state-frames-dialogs-windows-and-inspection-commands), stateful workflow notes, [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details). | Stateful summaries redact credentials while preserving restore identifiers, every session/state list row, and ordinary `cookies set --curl` file operands in invocation echoes and failed batch diagnostics; explicit targets and paths pass through. Runtime retains state artifact verification, sessionless local command planning, automatic managed restore, native-CDP-ID tab recovery across duplicate URLs and transcript replay, reached failed-batch target invalidation/live verification, active-target refresh after tab close, and close alias cleanup. | Extension tab/ref tests, real-upstream stable-id/label tab lifecycle, runtime session/resume tests, presentation redaction tests, lifecycle harness. | Supported. External profile/auth state remains operator-owned. |
164
167
  | Network, storage, artifacts, diagnostics, and performance | Canonical tokens from baseline section `network-storage-artifacts-diagnostics`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#page-state-finding-mouse-settings-network-and-storage). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#page-state-finding-mouse-settings-network-and-storage), diagnostic sections, [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#details). | Thin passthrough plus native-owned click/download execution for all downloads (including loopback, Blob exports, and redirects), compact diagnostics with identical credential redaction for page/origin/URL-filtered details and exports, route-mock warnings, useful-but-redacted storage output, stream idempotency normalization, FPS/cursor/contact-sheet-aware recording destinations/pinning and contact-sheet image verification, truthful ref-refresh and missing-ffmpeg warnings, positive WebMCP navigation hints and catalog updates, sensitive-data redaction, timeout bounds, and cleanup-pair guidance. | Fake non-core matrix and safe real-upstream coverage for network/HAR, diff, trace/profiler, console/errors/highlight, stream, vitals, React missing-renderer, native FPS recording path/page checks and WebMCP navigation hints. | Supported. Environment-sensitive operations need suitable local/browser state. |
165
168
  | Batch, auth, confirmations, setup, dashboard, devices, and AI commands | Canonical tokens from baseline section `batch-auth-setup-ai`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#batch-auth-confirmations-sessions-chat-dashboard-devices-and-setup). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#batch-auth-confirmations-sessions-chat-dashboard-devices-and-setup), README security notes, release docs. | Native-tool batch stdin, generated QA/lookup batch plans, auth/confirmation redaction, sessionless local auth/setup/dashboard/doctor/plugin planning, upgrade-only native text normalization with error precedence and explicit-JSON results, plugin list/show JSON envelope normalization, bare-`mcp` validation with `mcp --help` preserved, timeout/cleanup guidance. | Parser/runtime plugin and MCP unit coverage; fake-upstream plugin list/show and MCP help/blocking coverage; registered upgrade text/success/nonzero/timeout/abort/JSON controls in `test/agent-browser.upgrade-output.test.ts`; real-upstream plugin list shape probe; structured input-mode tests. | Supported. Interactive side-effecting setup/auth/chat remains upstream-owned. `plugin` is local/sessionless; `mcp` is external-client-only except help; `auth login --credential-provider` resolves credentials via a plugin; `install --with-deps` failures remain upstream-owned. |
166
169
  | Global flags, config, providers, policy, and environment | Canonical tokens from baseline section `options-and-env`; see [`scripts/agent-browser-capability-baseline.mjs`](../scripts/agent-browser-capability-baseline.mjs) and generated [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#important-global-flags-config-and-environment). | [`COMMAND_REFERENCE.md`](COMMAND_REFERENCE.md#important-global-flags-config-and-environment), README provider/setup notes, [`TOOL_CONTRACT.md`](TOOL_CONTRACT.md#sessionmode), architecture/runtime docs. | Runtime preserves caller-requested JSON for early filters, scroll results, and preparation failures without output-file prose (help/version remains native text), and handles command discovery, value-flag prevalidation, launch-scoped flags, redacted echoes, fresh-session recovery hints, explicit sessions, provider/device launch-scoping, parent env forwarding with consistent managed idle-timeout/socket/operation-timeout overrides on top-level and helper subprocesses, subprocess completion, and package-owned Pi-scoped config for optional companion features. | Runtime tests for flags/planning/redaction/session behavior; process/ref tests for env consistency and stdio-linger completion; config/web-search/CLI tests; fake provider/specialized-skill matrix; package doctor. | Supported. Provider clouds, iOS/Appium, proxies, profiles, and credentials require external setup. |
@@ -223,10 +223,11 @@ URL-less `open` is executed as native `get url`, including effective raw/stdin b
223
223
  - Do not assume Playwright selector dialects such as text=Close or button:has-text('Close') are supported wrapper syntax unless current upstream agent-browser behavior has been verified.
224
224
  - For authenticated or user-specific content explicitly requested by the user, such as feeds, inboxes, account pages, or private dashboards, use a real profile only when the user/config asks for it or profiles have been inspected; do not assume --profile Default exists on every machine. Do not use a real profile for public pages just because they are dashboards. Treat visible page content from real profiles as model-visible transcript data. On macOS, copied Chrome profiles may omit encrypted cookies, so profile selection alone is not proof of authentication; verify the target page and use a user-approved headed login once when needed. Use --auto-connect only if profile-based reuse is unavailable or the task is specifically about attaching to a running debug-enabled browser. If profile/user-data-dir resolution fails, stop retrying opens, run profiles and/or doctor through agent_browser, then report what the user needs to configure.
225
225
  - Ordinary bare calls share one native browser within your root Pi parent/subagent group; unrelated roots browse independently. Coordinate multi-call navigation inside your group with existing subagent/intercom tools. Explicit native session defaults still win. Pi quit does not close group browsers; never close an unrelated browser.
226
- - When using launch-scoped flags (--auto-connect, --allowed-domains, --namespace, --cdp, --ca-cert, --no-ca-cert, --enable, --executable-path, --webgpu, --no-webmcp, --init-script, --idle-timeout, --args, --user-agent, --headed, --device, --profile, --provider, -p, --session-name, --restore, --restore-save, --restore-check-url, --restore-check-text, --restore-check-fn, --state), put them on the first command for that session. If you intentionally use an explicit --session, keep using that same explicit session for follow-ups.
226
+ - When using launch-scoped flags (--auto-connect, --allowed-domains, --namespace, --cdp, --ca-cert, --no-ca-cert, --enable, --engine, --executable-path, --webgpu, --no-webmcp, --init-script, --idle-timeout, --args, --user-agent, --headed, --device, --profile, --provider, -p, --session-name, --restore, --restore-save, --restore-check-url, --restore-check-text, --restore-check-fn, --state), put them on the first command for that session. If you intentionally use an explicit --session, keep using that same explicit session for follow-ups.
227
227
  - Cooperating Pi processes serialize each complete browser operation and code cell by native socket context, namespace, and session, including target/ref helpers and state updates. Different identities remain concurrent; namespace-wide close waits for matching operations. All participating Pi instances must load this release; humans, third-party clients, and older extensions are outside that coordination. It is not a transaction or rollback. For raw batches whose later content depends on navigation, use exact batch --bail or split the calls.
228
228
  - After a successful `connect`, `--cdp`, or enabled `--auto-connect` call, verify with get url and keep using the resulting session without repeating the attach flag. The wrapper remembers that attachment across active-branch reload/resume and live-checks the URL before later page reads/interactions because an attached browser can drift externally; caller config, file access, launch arguments, and environment pass through unchanged. A successful close clears the marker. When several named sessions share one Chrome, pass --pin-tab once (AGENT_BROWSER_PIN_TAB) so a closed bound tab fails as tab_gone instead of acting on a neighbor; recover with tab new or tab list. --no-pin-tab turns the sticky pin off. tab list includes each tab's CDP targetId, accepted as a tab ref.
229
- - If you already used the implicit session and now need launch-scoped flags (--auto-connect, --allowed-domains, --namespace, --cdp, --ca-cert, --no-ca-cert, --enable, --executable-path, --webgpu, --no-webmcp, --init-script, --idle-timeout, --args, --user-agent, --headed, --device, --profile, --provider, -p, --session-name, --restore, --restore-save, --restore-check-url, --restore-check-text, --restore-check-fn, --state), retry with top-level sessionMode set to fresh or pass an explicit --session for the new launch; never pass --session-mode inside args. After a successful unnamed fresh launch, later auto calls follow that new session.
229
+ - If you already used the implicit session and now need launch-scoped flags (--auto-connect, --allowed-domains, --namespace, --cdp, --ca-cert, --no-ca-cert, --enable, --engine, --executable-path, --webgpu, --no-webmcp, --init-script, --idle-timeout, --args, --user-agent, --headed, --device, --profile, --provider, -p, --session-name, --restore, --restore-save, --restore-check-url, --restore-check-text, --restore-check-fn, --state), retry with top-level sessionMode set to fresh or pass an explicit --session for the new launch; never pass --session-mode inside args. After a successful unnamed fresh launch, later auto calls follow that new session.
230
+ - Chrome is the default. Use separately installed Lightpanda only when explicitly selected with --engine lightpanda, environment or native config; --engine is launch-scoped, so use sessionMode:fresh to change a managed browser. Lightpanda text-rendered screenshots do not prove graphical layout/visibility or mouse coordinates. Chrome profiles, headed mode, multi-tab, WebGPU and native WebMCP are not parity capabilities; choose Chrome explicitly when needed, never assume automatic fallback.
230
231
  - For WebGPU pages, use args ["--webgpu", "open", "<url>"] on a fresh local browser launch; use doctor --webgpu (or --headed on Linux/Windows capture paths) to prove rendering before trusting a non-black screenshot. WebGPU cannot be combined with --cdp, --auto-connect, or provider launches unless --webgpu false overrides an enabled config/environment default.
231
232
  - For experimental WebMCP page tools, use webmcp list, then webmcp invoke <tool> with --params and optional --frame/--detach/--timeout; use webmcp result or cancel for detached calls. Locally managed Chrome enables WebMCP by default; a positive navigation hint means the page has tools to list. --no-webmcp is launch-scoped and requires a fresh session; invoke/result/cancel can mutate or navigate, so refresh snapshot refs afterward.
232
233
  - For --allowed-domains, use a fresh local Chrome context. Upstream rejects CDP/auto-connect, profiles, restore/state replay, direct-page providers, iOS/Safari, and startup/profile Chrome args because they cannot guarantee containment; Chromium also disables RTCPeerConnection while the allowlist is active.
@@ -321,7 +322,7 @@ The browser persists between code and direct calls. JavaScript variables do not.
321
322
 
322
323
  Inner calls are serialized, including calls issued with `Promise.all`. The maximum is 25 attempted calls, 64 KiB emitted JSON, 1 MiB per IPC message, and 8 MiB cumulative IPC. Inner execution keeps full redacted data without full model rendering/spilling/image encoding; only selected outer output is rendered. An observation that cannot fit the bridge limit fails rather than silently discarding recovery or fabricating data.
323
324
 
324
- Source runs in a fresh permissioned Node child with an empty child environment, 64 MiB V8 heap ceiling, and a VM context whose string/WebAssembly code generation is disabled. Task globals have null prototypes and JSON-only IPC; no parent promise/object/function is exposed. There are no host filesystem, network, process, import, or timer APIs. This language boundary is separate from native browser capabilities: parent-side browser subprocesses still receive ordinary auth/config/environment. `node:vm` alone is not a security boundary, and this contract is not a universal sandbox certification.
325
+ Source runs in a fresh permissioned Node child with an empty child environment, 64 MiB V8 heap ceiling, and a VM context whose string/WebAssembly code generation is disabled. Task globals have null prototypes and JSON-only IPC; no parent promise/object/function is exposed. There are no host filesystem, network, process, import, or timer APIs. When Pi itself runs as a Bun-compiled binary, the child is hosted by a real `node` runtime from `PATH`; if none is available the call fails as `missing-binary` with that exact remediation instead of hanging the handshake. This language boundary is separate from native browser capabilities: parent-side browser subprocesses still receive ordinary auth/config/environment. `node:vm` alone is not a security boundary, and this contract is not a universal sandbox certification.
325
326
 
326
327
  #### Failure and persistence
327
328
 
@@ -480,7 +481,7 @@ Example:
480
481
 
481
482
  ### `sessionMode`
482
483
 
483
- A native `session` default from user/project JSON or `AGENT_BROWSER_SESSION` selects a caller-owned browser for direct, code, action, QA, and source tools. Per-call flags still win. Like literal `--session`, this selection takes precedence over `fresh`; it reports `usedImplicitSession: false` and is not closed when Pi quits. Without a selected native session, attachment, or explicit fresh launch, auto calls select a stable root-Pi named session and root-specific native restore key. `PI_SUBAGENT_ROOT_SESSION_ID` carries the parent identity to descendants; ordinary new/fork/clone roots differ, while resume/cwd changes keep identity. Root sessions report `usedImplicitSession: false` and survive parent/child quit. Global/override package profile names with `policy: "always"` and executable defaults bootstrap only inactive automatic roots. Active roots preserve native launch settings/current restore key, including matching root-name follow-ups; unrelated explicit browsers are unchanged. Profile paths and project-only profile config remain advisory. Native restore covers cookies and web storage, not newly created IndexedDB or memory-only authentication. See the README for communal bootstrap and persistent-profile fallback. Active older/fresh managed sessions retain the lifecycle below. `agent_browser_qa` with `attached: true` can inspect this shared current session using the same live target checks. See [shared browser defaults](../README.md#shared-browser-defaults).
484
+ A native `session` default from user/project JSON or `AGENT_BROWSER_SESSION` selects a caller-owned browser for direct, code, action, QA, and source tools. Per-call flags still win. Like literal `--session`, this selection takes precedence over `fresh`; it reports `usedImplicitSession: false` and is not closed when Pi quits. Without a selected native session, attachment, or explicit fresh launch, auto calls select a stable root-Pi named session and root-specific native restore key. `PI_SUBAGENT_ROOT_SESSION_ID` carries the parent identity to descendants; ordinary new/fork/clone roots differ, while resume/cwd changes keep identity. Root sessions report `usedImplicitSession: false` and survive parent/child quit. Global/override package profile names with `policy: "always"` and executable defaults bootstrap only inactive automatic roots whose effective engine is Chrome. Lightpanda receives no wrapper-supplied Chrome profile/executable defaults; caller native args, environment and config remain authoritative. Active roots preserve native launch settings/current restore key, including matching root-name follow-ups; unrelated explicit browsers are unchanged. Profile paths and project-only profile config remain advisory. Native restore covers cookies and web storage, not newly created IndexedDB or memory-only authentication. See the README for communal bootstrap and persistent-profile fallback. Active older/fresh managed sessions retain the lifecycle below. `agent_browser_qa` with `attached: true` can inspect this shared current session using the same live target checks. See [shared browser defaults](../README.md#shared-browser-defaults).
484
485
 
485
486
  - type: `"auto" | "fresh"`
486
487
  - optional
@@ -490,7 +491,7 @@ Behavior:
490
491
  - if `args` already include `--session` (including argv compiled from `agent_browser_action.session`), upstream session choice wins
491
492
  - `"auto"` prepends the current extension-managed active session when appropriate
492
493
  - after resume, a confirmed inactive wrapper-owned daemon with automatic managed restore enabled reopens its complete recorded URL, including its fragment, before the first current-page operation, including `get url` and `reload`. Non-page calls such as `tab list` or explicit HTTP `read <url>` can start a daemon without consuming that pending reopen, even across branch/reload replay. The wrapper verifies the observed tab and invalidates old refs; native `open` resets frame scope. This reloads the page with restored cookies/storage, not unsaved forms, JavaScript memory, or history. Live wrong-tab recovery does not navigate. Explicit URL reads, URL `a11y`/`vitals`, `diff url`, `window new`, URL-bearing recording commands, and explicit navigation/context changes do not require the old tab. Caller-owned/attached and restore-disabled sessions are not auto-reopened
493
- - `"fresh"` rotates that managed session to a fresh upstream launch so startup-scoped flags like `--profile`, `--executable-path`, `--ca-cert`, `--no-ca-cert`, `--webgpu`, `--no-webmcp`, `--restore`, `--restore-save`, restore check flags, `--namespace`, `--session-name`, `--cdp`, `--state`, `--auto-connect`, `--init-script`, `--idle-timeout`, `--headed`, `--enable`, `-p` / `--provider`, or iOS `--device` apply and later default calls follow the new browser; `--idle-timeout` must equal the Pi process's configured managed idle timeout or the wrapper rejects it with restart guidance
494
+ - `"fresh"` rotates that managed session to a fresh upstream launch so startup-scoped flags like `--engine`, `--profile`, `--executable-path`, `--ca-cert`, `--no-ca-cert`, `--webgpu`, `--no-webmcp`, `--restore`, `--restore-save`, restore check flags, `--namespace`, `--session-name`, `--cdp`, `--state`, `--auto-connect`, `--init-script`, `--idle-timeout`, `--headed`, `--enable`, `-p` / `--provider`, or iOS `--device` apply and later default calls follow the new browser; `--idle-timeout` must equal the Pi process's configured managed idle timeout or the wrapper rejects it with restart guidance
494
495
  - upstream `--webgpu` is a launch-scoped optional boolean: both enabled and explicit `false` values require a fresh managed launch once an implicit session exists; enabled WebGPU is local-launch-only and upstream rejects combinations with CDP, auto-connect, or providers
495
496
  - upstream `--no-webmcp` is also launch-scoped for bare/`true` and explicit `false` values because it selects whether locally managed Chrome enables the experimental feature
496
497
  - upstream restore sessions may periodically save cookies/localStorage while open; an explicit `AGENT_BROWSER_AUTOSAVE_INTERVAL_MS` passes through unchanged when a daemon launches (`30000` upstream default, `0` disables periodic saves but keeps native close saves), while wrapper-owned headed launches default it to `0` when unset to avoid upstream 0.33.2's visible temporary collector tabs; direct window close can lose newer state because headed browsers are exempt from idle shutdown, the effective interval persists across resume and changing it in either direction on a running wrapper-owned headed daemon requires close plus a fresh launch, and those restore files remain upstream-owned rather than wrapper artifacts
@@ -540,10 +541,12 @@ Inner code calls use `modelVisible: false` internally: no full model prose rende
540
541
 
541
542
  ### Image observations
542
543
 
543
- `imageObservations[]` carries verified capture metadata: `path`, optional `id` (cell-local code handle), `mimeType`, optional image `pixels` dimensions, `capture` (`viewport`, `full-page`, `element`, or `unknown`), and `geometry`. `geometry.status` is `measured` or `unknown`, with a `reason` and available before/after samples. Samples include CSS viewport/document dimensions, scroll offsets, device pixel ratio, visual viewport, frame evidence, and a uniquely measured CSS element box when available.
544
+ `imageObservations[]` carries verified capture metadata: `path`, optional `id` (cell-local code handle), `mimeType`, optional image `pixels` dimensions, `capture` (`viewport`, `full-page`, `element`, or `unknown`), optional `rendering: "text"` for positively identified Lightpanda text representations, and `geometry`. `geometry.status` is `measured` or `unknown`, with a `reason` and available before/after samples. Samples include CSS viewport/document dimensions, scroll offsets, device pixel ratio, visual viewport, frame evidence, and a uniquely measured CSS element box when available.
544
545
 
545
546
  A measured mapping requires matching pre/post samples and image dimensions that exactly match the CSS crop at the sampled DPR. It includes document-space `crop: { x, y, width, height }` and independent `pixelsPerCssPixel: { x, y }`. This is bracketed measurement, not an atomic capture guarantee. Viewport crop starts at sampled document scroll; full-page crop starts at document origin. Scrolled/ambiguous/non-CSS element captures, child-frame uncertainty, changed geometry, zoom/offset visual viewports, and captures without samples (including native batch captures) remain unknown rather than borrowing final-page geometry.
546
547
 
548
+ Lightpanda renders page text into an image rather than capturing graphical layout. Native engine metadata labels verified direct/batch/code images; standalone samples also recognize its browser brand when native engine metadata is absent or describes a CDP attachment as Chrome. Identified images remain attached but always have unknown geometry with no crop/scale mapping, even if synthetic dimensions match. Missing provenance does not justify coordinates. See [engine limits](COMMAND_REFERENCE.md#lightpanda-engine).
549
+
547
550
  Native mouse coordinates are **current viewport CSS pixels**. For measured geometry, original image pixel `(px, py)` maps to document CSS `(crop.x + px / scale.x, crop.y + py / scale.y)`; subtract current document scroll for viewport coordinates only after rechecking frame/scroll context. Prefer current refs/locators. Pi resize notes map sent-image pixels to original-image pixels only, not CSS coordinates. No provider image-detail override or model-specific coordinate rewrite is applied.
548
551
 
549
552
  Conditional `changed: false` captures have no new image/artifact attachment. A path in JSON is not vision input. Ordinary screenshot attachments use existing verification/size checks; code explicitly selects a handle from its current call. Unknown geometry permits inspection, but cannot justify coordinate input.
@@ -618,7 +621,7 @@ Ref preflight details (command taxonomy in `extensions/agent-browser/lib/command
618
621
  - **URL alignment:** `refSnapshot.target.url` and the session’s current tab URL are compared via `targetsMatch` / `normalizeComparableUrl` in `extensions/agent-browser/index.ts`: values are trimmed, parsed as URLs when possible, compared **after dropping the `#fragment`**, and the query string remains significant. If either side lacks a `url`, `targetsMatch` treats the pair as matching so early-session calls are not blocked.
619
622
  - **Batch stdin ordering:** user `batch` JSON is scanned in order. Any step whose first token satisfies `isRefInvalidatingBatchCommand` sets a latch that blocks later steps whose first token satisfies `isRefGuardedCommand` and that mention `@e…` refs, except for same-snapshot native form-control steps whose current snapshot role metadata identifies all refs as safe controls (`check`/`uncheck` or direct `click`/`tap` on checkbox or radio refs, and `select` on combobox refs). A step whose first token is `snapshot` clears that latch for subsequent steps (pre-spawn intent only; it does not wait for upstream success). These predicates read explicit command capability flags from `command-taxonomy.ts`: navigation/mutation verbs such as `open` / `goto`, `reload`, non-form `click`, and related upstream commands have `invalidatesBatchRefs`, and `record start` steps (any outcome), `record restart` steps with a URL operand, plus WebMCP `invoke` / `result` / `cancel` steps also set the latch because upstream swaps or navigates the active page; same-snapshot `fill` rows and the role-checked native form-control rows stay guarded against missing/stale refs but do not set the latch, allowing ordinary form batches before a final click/submit step. Direct `click`/`tap @e…` is only treated as a safe form-control row when every ref in that step is a latest-snapshot checkbox or radio; other click/tap refs remain invalidating. Ref-guarded commands accept page-scoped refs for interaction (`click`, `fill`, `download`, `scrollintoview` / `scrollinto`, and others centralized in the command taxonomy). Changing either capability requires updating this contract, [`docs/SUPPORT_MATRIX.md`](SUPPORT_MATRIX.md) `RQ-0072`/`RQ-0087` notes, README and command-reference pitfalls, and `test/agent-browser.extension-validation.test.ts`.
620
623
 
621
- **Presentation redaction (implementation map):** Successful non-`batch` tool calls and each successful `batchSteps[]` row run upstream `data` through `redactPresentationData` in `extensions/agent-browser/lib/results/presentation/diagnostics.ts`: `cookies` still walk objects/arrays and replace case-insensitive `value` keys with `"[REDACTED]"`; `storage` redacts values when the key or value looks credential-like (token, cookie, auth, secret, JWT, bearer/basic credential, high-entropy token-like string, or nested sensitive JSON) but keeps low-risk primitive QA values such as booleans, numbers, and short strings visible. Redacted storage entries add `valueRedacted` plus `valueRedactionReason` in `details.data`; diagnostic formatters mirror the same decision. Every other command’s payload is recursively scrubbed with the shared `redactSensitiveValue`, which redacts known sensitive key names and applies string-level sensitivity heuristics so network, diff, trace/profiler, stream, dashboard, chat, and other structured results do not echo bearer tokens, proxy credentials, or similar fields verbatim into `details.data`. Echoed `command` arrays in `details` and in batch roll-ups use `redactInvocationArgs` from `extensions/agent-browser/lib/runtime.ts` to mask trailing values for sensitive global flags (including `--body`, `--headers`, `--password`, and `--proxy`), preserve the special positional rules for `cookies set`, `storage local|session set`, and `set credentials`, and scrub other argv tokens for URLs and inline secrets. Raw batch row strings are parsed and command-redacted for presentation and ordered intent/completion journals; execution argv remains unchanged. Failed batch steps additionally run `redactExactValues` on structured step errors so literals taken from that step’s argv (cookie value, storage set value, `--password` / `--password=` tokens) cannot reappear inside formatted error blobs. When the full batch is large enough to need its own aggregate spill, that spill reapplies these per-command data and argv redactors before persistence rather than using generic batch redaction.
624
+ **Presentation redaction (implementation map):** Successful non-`batch` tool calls and each successful `batchSteps[]` row run upstream `data` through `redactPresentationData` in `extensions/agent-browser/lib/results/presentation/diagnostics.ts`: `cookies` still walk objects/arrays and replace case-insensitive `value` keys with `"[REDACTED]"`; `storage` redacts values when the key or value looks credential-like (token, cookie, auth, secret, JWT, bearer/basic credential, high-entropy token-like string, or nested sensitive JSON) but keeps low-risk primitive QA values such as booleans, numbers, and short strings visible. Redacted storage entries add `valueRedacted` plus `valueRedactionReason` in `details.data`; diagnostic formatters mirror the same decision. Every other command’s payload is recursively scrubbed with the shared `redactSensitiveValue`, which redacts known sensitive key names and applies string-level sensitivity heuristics so network, diff, trace/profiler, stream, dashboard, chat, and other structured results do not echo bearer tokens, proxy credentials, or similar fields verbatim into `details.data`. Echoed `command` arrays in `details` and in batch roll-ups use `redactInvocationArgs` from `extensions/agent-browser/lib/runtime.ts` to mask trailing values for sensitive global flags (including `--body`, `--headers`, `--password`, and `--proxy`), preserve the special positional rules for `cookies set`, `storage local|session set`, and `set credentials` (native `cookies set --curl <file>` imports are file operands, so ordinary import paths remain visible in echoes and failed batch diagnostics), and scrub other argv tokens for URLs and inline secrets. Raw batch row strings are parsed and command-redacted for presentation and ordered intent/completion journals; execution argv remains unchanged. Failed batch steps additionally run `redactExactValues` on structured step errors so literals taken from that step’s argv (cookie value, storage set value, `--password` / `--password=` tokens) cannot reappear inside formatted error blobs. When the full batch is large enough to need its own aggregate spill, that spill reapplies these per-command data and argv redactors before persistence rather than using generic batch redaction.
622
625
 
623
626
  `nextActions` is an optional list of exact follow-ups. Each entry has a `tool`, `id`, `reason`, optional `safety`, and executable `params` or an `artifactPath`. Native actions use `agent_browser` with argv/stdin; Electron and network-source actions use their actual advanced tool name and flat params. Enable the corresponding capability with `agent_browser_tools` if needed. Both prose and JSON expose recovery; oversized observations retain complete payloads in the named observation spill rather than inventing shortened calls.
624
627
 
@@ -699,7 +702,7 @@ Additional structured fields can appear when relevant:
699
702
  - `attachedBrowserSession: true` on successful calls that establish or reuse a wrapper-tracked CDP/auto-connect/Electron attachment, and on a failed fresh attachment only when `managedSessionOutcome.activeAfter` proves its daemon remained active for cleanup. The marker restores attachment continuity from the active transcript branch, including that active-after-failure case; live state and transcript replay remove it after a terminal successful close/cleanup even when aggregate verification failed; a close followed by a later step whose lifecycle reports a browser launch preserves it, while a successful non-launching diagnostic leaves the close terminal. Caller config, environment, paths, and file-access settings remain upstream-owned; the marker only adds live-URL verification and lifecycle continuity.
700
703
  - `lifecycle: { effectiveLaunch: { browserLaunched } }` when upstream returned that boolean. It separates starting the requested `agent-browser` CLI process from the effective Chrome session context. `readSource` exposes upstream's string `data.source` for direct `read` calls and identifies the raw HTTP fetch path; its lifecycle boolean can be `false` before a browser launch or `true` when the same managed session already has an active browser. Direct reads also append one visible `Read execution` line with the source, CLI-start result, managed browser lifecycle, and managed-session outcome so Pi models do not have to infer model-invisible details.
701
704
  - `browserWindow: { mode: "headed", ownership: "wrapper-managed", sessionName, visibility: "unverified" }` only after a successful first/fresh local wrapper-managed headed call (including `batch`) that is not an attachment and whose lifecycle proves a browser launched and whose managed-session outcome is `created` or `replaced`. One visible handoff sentence tells the user to complete the login in that window if they can see it, then continue with `sessionMode: "auto"`; the field never claims OS desktop visibility.
702
- - `sessionTabTarget` retains the observed `url`, optional `title`, and native CDP `targetId` when available. When an observed page lacks a native ID, a read-only `tab list` observes current identity; earlier commands and equal URLs cannot supply it. If another tab matches the observed URL while the active tab does not, existing URL-based drift recovery selects the matching tab instead of attaching the unrelated active ID. Resume and branch recovery select that exact target, even when several tabs share an address/title; a missing known ID never falls back to another same-address tab. Older transcripts without an ID retain URL-based recovery. An existing cold-managed-browser reopen records its new native ID. `sessionTabCorrection.selectionKind` can be `targetId`, `tabId`, `label`, or `index`.
705
+ - `sessionTabTarget` retains the observed `url`, optional `title`, and native CDP `targetId` when available. When an observed page lacks a native ID, a read-only `tab list` observes current identity; earlier commands and equal URLs cannot supply it. If another tab matches the observed URL while the active tab does not, existing URL-based drift recovery selects the matching tab instead of attaching the unrelated active ID. Resume and branch recovery select that exact target, even when several tabs share an address/title; a missing known ID never falls back to another same-address tab. Older transcripts without an ID retain URL-based recovery. An existing cold-managed-browser reopen records its new native ID. `sessionTabCorrection.selectionKind` can be `targetId`, `tabId`, `label`, or `index`. `sessionTabCorrection` records an applied tab selection (before the command or during post-command recovery), not proof of the final page or successful later recovery. Use `sessionTabTarget` for the final observed position and `aboutBlankSessionMismatch.recoveryApplied` for the recovery outcome; the historical correction may remain when that recovery fails.
703
706
  - `sessionTabTargetUnknown: true` after a spawned `connect`, `state load`, history navigation, tab-selection/close, `window new`, or `diff url` call changes the active page without a trustworthy observed target. Direct `window new` / `diff url` and reached native batch rows retire the old target and refs; an intentional new blank window or an observed blank URL-diff destination never triggers old-tab recovery. URL diff inputs do not prove the final URL after redirects. Successful tab creation/selection/close, including dispatched batch rows, live-probes URL and a fresh non-blank title before state is committed, even when the new tab shares the prior URL; new blank tabs, explicitly selected `about:blank` tabs, and post-close blank targets are retained. It is persisted and restored across branch/reload replay, clears stale refs and tab pinning, and blocks page inspection until `get url` or explicit navigation observes a target; `tab list`, tab selection, close, and blocking-dialog `status` / `accept` / `dismiss` remain available. A timeout against an unknown target removes standalone snapshot actions and returns `verify-page-target-after-timeout`, a session-scoped `batch --bail` whose stdin runs `get url` before `snapshot -i`.
704
707
  - `compiledSemanticAction` when the call used `agent_browser_action` and the result includes the unified `details` merge: `{ action, locator, args }` for `find` actions or `{ action: "select", selector?, locator?, values, args }` for `select`, with the same redaction rules as `args` / `effectiveArgs`; omitted for plain direct native calls and omitted on some early error returns that omit this field (see the `agent_browser_action` section above)
705
708
  - `compiledJob` is internal QA batch-plan metadata: `{ args: ["batch", "--bail"], failFast: true, stdin, steps }`, with redacted step argv. It does not expose a public job input or compiler.
@@ -855,7 +858,7 @@ If `agent-browser` is not on `PATH`, fail with a message that:
855
858
  - keep wrapper-spawned commands bounded by clamping `AGENT_BROWSER_DEFAULT_TIMEOUT` to the upstream documented default of 25 seconds while the default wrapper child-process watchdog is 35 seconds (`PI_AGENT_BROWSER_PROCESS_TIMEOUT_MS` overrides it, and top-level `timeoutMs` overrides it per call for browser CLI subprocesses). Explicit `wait <ms>`, `wait --timeout <ms>`, and WebMCP `invoke` / `result --timeout <ms>` calls can exceed that default; when top-level `timeoutMs` is omitted, the wrapper derives a per-call subprocess watchdog from the requested command duration plus a small grace window. Dialog commands use `PI_AGENT_BROWSER_DIALOG_PROCESS_TIMEOUT_MS` (default 5000 ms), and click/tap/find refs or tokens plus `eval --stdin` snippets whose text looks like alert/confirm/prompt/dialog triggers use `PI_AGENT_BROWSER_DIALOG_TRIGGER_PROCESS_TIMEOUT_MS` (default 8000 ms). Timed-out advanced QA or native batch calls may add `details.timeoutPartialProgress` and visible `Timeout partial progress` evidence with per-step status, retry payloads, current page title/URL, and declared artifact path checks; timed-out dialog-like commands may add dialog status/dismiss/fresh-session recovery next actions
856
859
  - interactive or long-running upstream families such as `chat` without a prompt, `dashboard start`, `stream enable`, `trace start`, `profiler start`, `record start`, `inspect`, `install`, `upgrade`, `doctor --fix`, and `confirm-interactive` are passed through thinly but remain bounded by the same wrapper timeout/session planning rules; prefer explicit arguments, single-shot `chat <message>`, non-interactive flags like `doctor --offline --quick` or `doctor --json`, and cleanup pairs such as `dashboard stop`, `stream disable`, `trace stop`, `profiler stop`, and `record stop`
857
860
  - treat successful plain-text inspection commands like `--help` and `--version` as stateless: do not inject the implicit managed session and do not let those calls claim the managed-session slot
858
- - if startup-scoped flags like `--profile`, `--args`, `--user-agent`, `--executable-path`, `--ca-cert`, `--no-ca-cert`, `--webgpu`, `--restore`, `--restore-save`, restore check flags, `--namespace`, `--session-name`, `--cdp`, `--state`, `--auto-connect`, `--init-script`, `--idle-timeout`, `--enable`, `-p` / `--provider`, or iOS `--device` target the current active managed session, return a validation error with a structured recovery hint that recommends `sessionMode: "fresh"`; when the call explicitly names the current managed session, remove that `--session` from the recovery payload so rotation is actionable. If daemon inspection proves an explicitly targeted older wrapper-owned session active, reject its startup-scoped flags with close-first or fresh-rotation guidance before spawn
861
+ - if startup-scoped flags like `--engine`, `--profile`, `--args`, `--user-agent`, `--executable-path`, `--ca-cert`, `--no-ca-cert`, `--webgpu`, `--restore`, `--restore-save`, restore check flags, `--namespace`, `--session-name`, `--cdp`, `--state`, `--auto-connect`, `--init-script`, `--idle-timeout`, `--enable`, `-p` / `--provider`, or iOS `--device` target the current active managed session, return a validation error with a structured recovery hint that recommends `sessionMode: "fresh"`; when the call explicitly names the current managed session, remove that `--session` from the recovery payload so rotation is actionable. If daemon inspection proves an explicitly targeted older wrapper-owned session active, reject its startup-scoped flags with close-first or fresh-rotation guidance before spawn
859
862
  - for direct headless local Chrome launches to `chat.com` / `chatgpt.com` / `chat.openai.com` or `dash.cloudflare.com`, allow a narrow compatibility fallback that injects a normal Chrome `--user-agent` only when the caller did not explicitly provide one and did not choose raw Chrome arguments, headed, CDP, auto-connect, provider-backed, custom-UA, or non-Chrome behavior through argv or matching upstream environment. Wrapper-managed sessions retain that wrapper-owned user agent as per-session state across follow-up calls, failed replacement closes, and branch reload/resume. Active daemons omit both launch forms so upstream does not replace a launch-configured browser; a session proven inactive receives the retained compatibility launch values, including a fixed, comma-safe Chrome launch argument because the per-page override does not propagate to new tabs or SSO popups.
860
863
 
861
864
  ## Shared execution coordination
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-agent-browser-native",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
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)",
@@ -72,7 +72,7 @@
72
72
  "@earendil-works/pi-coding-agent": "1.0.0",
73
73
  "@earendil-works/pi-tui": "1.0.0",
74
74
  "@types/cross-spawn": "6.0.6",
75
- "@types/node": "24.19.0",
75
+ "@types/node": "24.19.1",
76
76
  "@types/which": "2.0.2",
77
77
  "tsx": "4.23.15",
78
78
  "typebox": "1.3.27",
@@ -98,7 +98,7 @@
98
98
  "startup-profile": "node ./scripts/profile-startup.mjs",
99
99
  "prepare": "node ./scripts/prepare.mjs"
100
100
  },
101
- "packageManager": "npm@12.1.0",
101
+ "packageManager": "npm@12.2.0",
102
102
  "peerDependenciesMeta": {
103
103
  "@earendil-works/pi-ai": {
104
104
  "optional": true
@@ -124,15 +124,23 @@ export function parseCliArgs(argv = process.argv.slice(2)) {
124
124
  }
125
125
 
126
126
  async function defaultRunAgentBrowser(args) {
127
- const { stdout, stderr } = await execFile("agent-browser", args, { maxBuffer: 1024 * 1024 });
127
+ const { stdout, stderr } = await execFile("agent-browser", args, { maxBuffer: 1024 * 1024, ...buildNpmShimExecOptions(process.platform) });
128
128
  return `${stdout}${stderr}`;
129
129
  }
130
130
 
131
131
  async function defaultRunPi(args) {
132
- const { stdout, stderr } = await execFile("pi", args, { maxBuffer: 1024 * 1024 });
132
+ const { stdout, stderr } = await execFile("pi", args, { maxBuffer: 1024 * 1024, ...buildNpmShimExecOptions(process.platform) });
133
133
  return `${stdout}${stderr}`;
134
134
  }
135
135
 
136
+ /**
137
+ * npm's global bin shims on Windows are `.cmd` files that `execFile` cannot launch without a
138
+ * shell. Doctor only passes fixed flag arrays here, so shell composition stays safe.
139
+ */
140
+ export function buildNpmShimExecOptions(platform = process.platform) {
141
+ return platform === "win32" ? { shell: true } : {};
142
+ }
143
+
136
144
  async function defaultPathExists(path) {
137
145
  try {
138
146
  await access(path);