@browserbridge/bbx 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/PRIVACY.md +29 -3
  2. package/README.md +10 -3
  3. package/SECURITY.md +12 -0
  4. package/package.json +7 -1
  5. package/packages/agent-client/src/cli-args.js +35 -0
  6. package/packages/agent-client/src/cli-batch.js +121 -58
  7. package/packages/agent-client/src/cli-output.js +8 -1
  8. package/packages/agent-client/src/cli.js +227 -19
  9. package/packages/agent-client/src/client.js +156 -3
  10. package/packages/agent-client/src/command-registry.js +8 -2
  11. package/packages/agent-client/src/config.js +195 -0
  12. package/packages/agent-client/src/npm-self-update.js +305 -0
  13. package/packages/agent-client/src/remotes.js +4 -2
  14. package/packages/agent-client/src/runtime.js +97 -5
  15. package/packages/agent-client/src/types.ts +38 -0
  16. package/packages/mcp-server/src/handlers-capture.js +29 -2
  17. package/packages/mcp-server/src/handlers-dom.js +54 -3
  18. package/packages/mcp-server/src/handlers-page.js +180 -60
  19. package/packages/mcp-server/src/handlers-utils.js +35 -4
  20. package/packages/mcp-server/src/handlers.js +10 -3
  21. package/packages/mcp-server/src/server.js +75 -6
  22. package/packages/native-host/src/artifact-store.js +353 -0
  23. package/packages/native-host/src/config.js +9 -1
  24. package/packages/native-host/src/daemon-logger.js +3 -1
  25. package/packages/native-host/src/daemon.js +543 -27
  26. package/packages/native-host/src/native-host.js +25 -2
  27. package/packages/protocol/src/capability-values.js +2 -0
  28. package/packages/protocol/src/defaults.js +28 -0
  29. package/packages/protocol/src/errors.js +48 -5
  30. package/packages/protocol/src/incidental-sanitizer.js +197 -0
  31. package/packages/protocol/src/index.js +2 -0
  32. package/packages/protocol/src/protocol.js +316 -6
  33. package/packages/protocol/src/recovery-telemetry.js +302 -0
  34. package/packages/protocol/src/registry.js +143 -6
  35. package/packages/protocol/src/summary.js +116 -25
  36. package/packages/protocol/src/types.ts +489 -4
  37. package/skills/browser-bridge/SKILL.md +22 -8
  38. package/skills/browser-bridge/references/protocol.md +117 -13
  39. package/skills/browser-bridge/references/token-efficiency.md +17 -7
@@ -27,7 +27,7 @@ The table below includes the legacy capability bucket for each method so agents
27
27
  - `-` means the method is global/system-scoped and was never gated by a former capability bucket.
28
28
  - Capability names are descriptive coverage labels only. Browser Bridge access is window-scoped now; there are no capability-scoped sessions.
29
29
 
30
- ## All Methods (67)
30
+ ## All Methods (75)
31
31
 
32
32
  | Method | Tab? | CDP? | Group | Capability | Notes |
33
33
  | ---------------------------------- | ---- | ---------- | ----------- | -------------------- | ------------------------------------------------------------------------------------------ |
@@ -39,18 +39,20 @@ The table below includes the legacy capability bucket for each method so agents
39
39
  | `skill.get_runtime_context` | No | - | system | `-` | Live budget presets and method groups |
40
40
  | `setup.get_status` | No | - | system | `-` | Global MCP config and CLI skill install status |
41
41
  | `setup.install` | No | - | system | `-` | Install or uninstall MCP/skill integration targets |
42
- | `health.ping` | No | - | system | `-` | Connectivity, enabled-window routing, debugger, and capture state |
42
+ | `health.ping` | No | - | system | `-` | Connectivity, routing, capture, and daemon/routed-extension recovery summaries |
43
43
  | `log.tail` | No | - | system | `-` | Recent redacted bridge logs |
44
- | `daemon.metrics` | No | - | system | `-` | Daemon health and performance metrics |
44
+ | `daemon.metrics` | No | - | system | `-` | Daemon health, performance, and process-local recovery metrics |
45
45
  | `page.get_state` | Yes | - | page | `page.read` | URL, readiness, focus, viewport, and observable dialog status |
46
46
  | `page.evaluate` | Yes | CDP | page | `page.evaluate` | JS expression in page context; last resort |
47
47
  | `page.get_console` | Yes | - | page | `page.read` | Buffered console messages; filter by `level`, `limit` |
48
48
  | `page.handle_dialog` | Yes | CDP | page | `navigation.control` | Inspect or explicitly accept/dismiss the currently observable dialog |
49
49
  | `page.wait_for_load_state` | Yes | - | wait | `page.read` | Wait for truthful tab `complete` state and/or a URL condition |
50
- | `page.get_storage` | Yes | - | page | `page.read` | `localStorage`/`sessionStorage`; optional `keys` |
50
+ | `page.get_storage` | Yes | - | page | `page.read` | Bounded storage key/presence metadata; optional `keys`; never values |
51
+ | `sensitive.read` | Yes | - | sensitive | `sensitive.read` | One exact local/session storage key; sequential, non-retryable, whole-or-error |
51
52
  | `page.get_text` | Yes | - | page | `page.read` | Full page text; `textBudget` limits size |
52
53
  | `page.extract_content` | Yes | - | page | `page.read` | Node-processed semantic text/Markdown with bounded HTML snapshots and optional settlement |
53
54
  | `page.get_network` | Yes | Conditional | page | `network.read` | Fetch/XHR by default; explicit CDP all-resource capture lifecycle |
55
+ | `network.export_har` | Yes | No* | page | `network.read` | Read an already armed CDP capture as bounded metadata-only HAR 1.2 |
54
56
  | `network.intercept.add` | Yes | CDP | page | `network.intercept` | Add interception rule; action fulfill/continue/block |
55
57
  | `network.intercept.remove` | Yes | CDP | page | `network.intercept` | Remove rule by `ruleId` |
56
58
  | `network.intercept.list` | Yes | CDP | page | `network.intercept` | List active rules (rules drop on debugger detach) |
@@ -60,6 +62,10 @@ The table below includes the legacy capability bucket for each method so agents
60
62
  | `navigation.go_back` | Yes | - | navigate | `navigation.control` | History back |
61
63
  | `navigation.go_forward` | Yes | - | navigate | `navigation.control` | History forward |
62
64
  | `dom.query` | Yes | - | inspect | `dom.read` | Query subtree with budget constraints |
65
+ | `dom.baseline.create` | Yes | - | inspect | `dom.read` | Retain a short-lived memory-only semantic snapshot; sequential only |
66
+ | `dom.baseline.compare` | Yes | - | inspect | `dom.read` | Compare current semantic DOM to an explicit retained baseline; batch-safe |
67
+ | `dom.baseline.describe` | Yes | - | inspect | `dom.read` | Return exact baseline scope, options, expiry, and snapshot statistics; batch-safe |
68
+ | `dom.baseline.release` | Yes | - | inspect | `dom.read` | Idempotently release retained baseline state; sequential only |
63
69
  | `dom.describe` | Yes | - | inspect | `dom.read` | Single element details via `elementRef` |
64
70
  | `dom.get_text` | Yes | - | inspect | `dom.read` | Text content with `textBudget` |
65
71
  | `dom.get_attributes` | Yes | - | inspect | `dom.read` | Targeted attribute read |
@@ -87,18 +93,24 @@ The table below includes the legacy capability bucket for each method so agents
87
93
  | `screenshot.capture_element` | Yes | CDP | capture | `screenshot.partial` | Complete element screenshot with explicit completeness metadata |
88
94
  | `screenshot.capture_region` | Yes | CDP | capture | `screenshot.partial` | Cropped viewport region in PNG, JPEG, or WebP |
89
95
  | `screenshot.capture_full_page` | Yes | CDP | capture | `screenshot.partial` | Full document screenshot; fails coherently above Chrome capture limits |
96
+ | `artifact.read` | No | daemon | raw | None | Read one bounded chunk from an owner-scoped artifact handle |
97
+ | `artifact.delete` | No | daemon | raw | None | Delete an owner-scoped artifact handle |
90
98
  | `patch.apply_styles` | Yes | - | patch | `patch.styles` | Reversible CSS patch; `verify` returns computed result |
91
- | `patch.apply_dom` | Yes | - | patch | `patch.dom` | Reversible DOM mutation; `verify` returns result |
99
+ | `patch.apply_dom` | Yes | - | patch | `patch.dom` | Reversible text, attribute, add/remove/toggle-class mutation; `verify` returns result |
92
100
  | `patch.list` | Yes | - | patch | `patch.dom` | Active rollback records in the current document |
93
101
  | `patch.rollback` | Yes | - | patch | `patch.dom` | Revert one active patch |
94
102
  | `patch.commit_session_baseline` | Yes | - | patch | `patch.dom` | Keep current mutations and discard their rollback history |
95
103
  | `performance.get_metrics` | Yes | CDP | performance | `performance.read` | Chrome performance counters |
96
104
  | `cdp.get_document` | Yes | CDP | cdp | `cdp.dom_snapshot` | DevTools document tree |
97
- | `cdp.get_dom_snapshot` | Yes | CDP | cdp | `cdp.dom_snapshot` | DevTools DOM snapshot |
105
+ | `cdp.get_dom_snapshot` | Yes | CDP | cdp | `cdp.dom_snapshot` | DevTools DOM snapshot; optional bounded `computedStyles` property names |
98
106
  | `cdp.get_box_model` | Yes | CDP | cdp | `cdp.box_model` | DevTools-backed element geometry |
99
107
  | `cdp.get_computed_styles_for_node` | Yes | CDP | cdp | `cdp.styles` | DevTools-backed computed styles |
100
108
  | `cdp.dispatch_key_event` | Yes | CDP | cdp | `cdp.input` | DevTools keyDown/keyUp without foreground focus |
101
109
 
110
+ `No*` means HAR export issues no CDP command itself, but its source capture must
111
+ already be armed and continues to hold debugger ownership until explicitly
112
+ stopped.
113
+
102
114
  ## CLI
103
115
 
104
116
  ```bash
@@ -108,7 +120,7 @@ bbx call --tab 123 <method> '{...}' # explicit tab target inside enabled
108
120
  bbx batch '[{"method":"...","params":{}}]' # parallel calls
109
121
  ```
110
122
 
111
- **Convenience shortcuts:** `access-request`, `dom-query`, `describe`, `text`, `styles`, `box`, `click`, `focus`, `type`, `press-key`, `cdp-press-key`, `patch-style`, `patch-text`, `patches`, `rollback`, `screenshot`, `eval`, `console`, `wait`, `find`, `find-role`, `html`, `hover`, `navigate`, `storage`, `tab-create`, `tab-close`, `page-text`, `network`, `a11y-tree`, `perf`, `scroll`, `resize`, `reload`, `back`, `forward`, `attrs`, `matched-rules`
123
+ **Convenience shortcuts:** `access-request`, `dom-query`, `describe`, `text`, `styles`, `box`, `click`, `focus`, `type`, `press-key`, `cdp-press-key`, `patch-style`, `patch-text`, `patches`, `rollback`, `screenshot`, `har`, `eval`, `console`, `wait`, `find`, `find-role`, `html`, `hover`, `navigate`, `storage`, `tab-create`, `tab-close`, `page-text`, `network`, `a11y-tree`, `perf`, `scroll`, `resize`, `reload`, `back`, `forward`, `attrs`, `matched-rules`
112
124
 
113
125
  Newer bridge methods such as `input.scroll_into_view` and `screenshot.capture_full_page` currently use the raw path: `bbx call <method> '{...}'`.
114
126
 
@@ -181,7 +193,7 @@ bbx call page.wait_for_load_state '{"url":"/dashboard","urlMatch":"contains","wa
181
193
 
182
194
  ### page.get_storage
183
195
 
184
- Read `localStorage` or `sessionStorage` entries. Values truncated at 500 chars each.
196
+ Read bounded `localStorage` or `sessionStorage` key/presence metadata. Values are never returned.
185
197
 
186
198
  ```bash
187
199
  bbx storage # all localStorage
@@ -189,6 +201,17 @@ bbx storage session token,user # specific sessionStorage keys
189
201
  bbx call page.get_storage '{"type":"session","keys":["token"]}'
190
202
  ```
191
203
 
204
+ ### sensitive.read
205
+
206
+ Deliberately read one exact Web Storage value after discovering its key. The
207
+ value bypasses token truncation, is never batched or automatically retried, and
208
+ is returned whole or rejected whole. Every attempt creates a Sensitive access
209
+ Recent Activity warning without retaining the key or value.
210
+
211
+ ```bash
212
+ bbx call sensitive.read '{"source":"session_storage","key":"token"}'
213
+ ```
214
+
192
215
  ### dom.query
193
216
 
194
217
  Run a bounded breadth-first DOM summary rooted at a selector or existing ref. Returns `{nodes, revision, truncated, registrySize}` and may also include `_registryPruned: true` when the element registry evicted older refs.
@@ -200,6 +223,23 @@ bbx call dom.query '{"selector":"main","maxNodes":10,"attributeAllowlist":["clas
200
223
 
201
224
  If `_registryPruned` is true, refresh previously cached refs before reusing them.
202
225
 
226
+ ### dom.baseline.create, compare, describe, and release
227
+
228
+ Use an explicit semantic baseline when an action must be verified against a known before-state without returning two full DOM snapshots. Baselines retain bounded structured summaries in extension memory only; they do not add attributes, scripts, or markers to the application page.
229
+
230
+ ```bash
231
+ bbx call dom.baseline.create '{"selector":"main","maxNodes":100,"maxDepth":8,"textBudget":160,"attributeAllowlist":["data-testid"]}'
232
+ bbx call dom.baseline.compare '{"baselineId":"baseline_...","maxChanges":50}'
233
+ bbx call dom.baseline.describe '{"baselineId":"baseline_..."}'
234
+ bbx call dom.baseline.release '{"baselineId":"baseline_..."}'
235
+ ```
236
+
237
+ The create result is a destination-bound opaque handle plus creation/expiry timestamps, window/tab/frame/document/selector/representation scope, effective capture options, and snapshot counts. It never returns retained nodes. `compare` reports exact `added`, `removed`, `changed`, `moved`, `unchanged`, and total counts while bounding returned examples with `maxChanges`; ambiguity and omitted evidence are explicit. `describe` returns the exact descriptor. `release` is idempotent.
238
+
239
+ Creation and release are stateful and excluded from read-only batch. Compare and describe do not mutate the baseline or extend its five-minute expiry, so they are batch-safe. Navigation, document replacement, tab/window cleanup, access disable, destination disconnect, expiry, quota eviction, or explicit release makes the handle unavailable. Navigation and document replacement return `DOM_BASELINE_INVALIDATED`; missing, expired, released, or evicted handles return `DOM_BASELINE_NOT_FOUND`.
240
+
241
+ Capture defaults to stable semantic fields and safe attributes. Form values and event-handler attributes are never retained, URL credentials/fragments/query values are removed, opaque URL payloads are redacted, and caller-provided attribute names are canonicalized and bounded. Use a narrow selector for dialogs, forms, lists, or application regions.
242
+
203
243
  ### dom.wait_for
204
244
 
205
245
  Wait for a DOM condition using MutationObserver + 250 ms polling fallback. A text-only wait searches all elements. `hidden` succeeds when no matching visible element remains, including when it is absent. Returns `{found, elementRef, duration}`.
@@ -359,6 +399,42 @@ bbx call page.get_network '{"source":"cdp","capture":"stop"}'
359
399
 
360
400
  CDP URL output removes credentials and fragments, replaces every query value with `[redacted]`, and summarizes data/blob URLs. Request/response bodies, cookies, authorization values, and complete headers are not returned. This mode captures all observed resource classes and is materially more expensive and intrusive than fetch/XHR instrumentation; always stop it when finished.
361
401
 
402
+ ### network.export_har
403
+
404
+ Export metadata-only HAR 1.2 from a CDP capture that is currently armed. The
405
+ method is a read and does not attach, start, stop, clear, or otherwise change the
406
+ capture. Use this exact sequence:
407
+
408
+ ```bash
409
+ bbx call page.get_network '{"source":"cdp","capture":"start"}'
410
+ # reproduce the activity
411
+ bbx har --limit 100 --url-pattern /api/ reproduction.har
412
+ bbx call page.get_network '{"source":"cdp","capture":"stop"}'
413
+ ```
414
+
415
+ Parameters are `limit` (1-200, default 50), `urlPattern` (at most 2048
416
+ characters; substring match on sanitized URLs), and `delivery` (`auto` default,
417
+ `inline`, or `artifact`). Count and inline byte/token limits retain the newest
418
+ matching entries and remove complete oldest entries; fields are not truncated to
419
+ fit. `auto` uses an artifact above 256 KiB, while explicit `artifact` always
420
+ returns one. Artifacts last five minutes, are readable/deletable only by their
421
+ requesting client, use private daemon files, and expose no browser-host path.
422
+
423
+ HAR URLs preserve schemes, hosts, paths, and query names, remove credentials and
424
+ fragments, and replace query values with `[redacted]`. `queryString`, headers,
425
+ and cookies are empty; bodies and authorization data are absent. Unsupported
426
+ header/body/content sizes and send/wait/receive timing phases are `-1`.
427
+ `entry.time` is observed total duration. Redirects are separate observed entries;
428
+ `_bbx` reports resource type, failure reason, and memory/disk/prefetch cache and
429
+ service-worker observations. Result counters expose completed-entry loss as
430
+ `dropped`, discarded unfinished activity as `abandoned`, and requests still
431
+ unfinished and omitted from the HAR as `inflight`.
432
+
433
+ MCP uses `browser_page` with `action: "har"`. `bbx har` accepts the same limit,
434
+ URL pattern, and delivery choices, then uses one client connection to download
435
+ owner-scoped chunks, verify byte length/SHA-256 and HAR shape, delete the
436
+ artifact, and atomically write the output on the CLI host.
437
+
362
438
  ### dom.get_accessibility_tree
363
439
 
364
440
  Retrieve a depth-limited accessibility tree via CDP. Full reads use `Accessibility.getFullAXTree`; an optional unique `selector` resolves through CDP DOM methods and uses `Accessibility.getPartialAXTree`, retaining only the selected subtree and required ancestor chain. Missing and ambiguous selectors return typed errors instead of selecting an arbitrary candidate. Nodes include `role`, `name`, `description`, `value`, state fields, `interactive`, `semanticInteractive`, `focusable`, `focusableAndEnabled`, `ignored`, and `childIds`. `interactive` is semantic/focusability metadata, not current pointer actionability.
@@ -389,7 +465,9 @@ bbx call viewport.resize '{"reset":true}'
389
465
 
390
466
  ### performance.get_metrics
391
467
 
392
- Read Chrome performance counters via CDP `Performance.getMetrics`. Returns a flat `{metrics}` object with keys like `JSHeapUsedSize`, `LayoutCount`, `TaskDuration`, etc.
468
+ Read a browser-maintained point sample of raw Chrome counters via CDP `Performance.getMetrics`. The additive result is `{metrics, measurement}`, where `measurement` identifies the CDP source, `timeTicks` domain, sample timestamp, point-sample observation, and `webVitals: "not_measured"`. Metric names, availability, and units are defined by Chrome/CDP and can vary by browser version.
469
+
470
+ BBX does not establish a navigation observation window and does not measure LCP, CLS, or INP. Do not interpret the returned counters as Web Vitals or page-load measurements.
393
471
 
394
472
  Debugger-backed. Use after lighter reads fail to explain a performance symptom.
395
473
 
@@ -400,16 +478,40 @@ bbx call performance.get_metrics
400
478
 
401
479
  ### screenshot.capture_\*
402
480
 
403
- Capture a complete element, a tight viewport region, or a full document. All methods accept `format: "png" | "jpeg" | "webp"`; JPEG and WebP additionally accept integer `quality` from 0 to 100. Results include matching `format`, `mimeType`, `complete`, and `clipped` metadata.
481
+ Capture a complete element, a tight viewport region, or a full document. All methods accept `format: "png" | "jpeg" | "webp"`, `scale` from 0.1 to 4, and `delivery: "inline" | "artifact" | "auto"`; JPEG and WebP additionally accept integer `quality` from 0 to 100. Results include matching `format`, `mimeType`, encoded `byteLength`, actual `dimensions`, `complete`, `clipped`, and `delivery` metadata.
404
482
 
405
483
  Element capture uses full page-coordinate bounds with CDP capture beyond the viewport. If Browser Bridge cannot guarantee the entire element, or if an element/page exceeds Chrome capture limits, it returns a typed failure rather than a viewport-clipped image labeled complete. Use full-page capture only when element or tight region captures cannot express the issue.
406
484
 
407
- Raw calls return base64 JSON. Prefer `bbx screenshot [--format png|jpeg|webp] [--quality 0-100] <ref> [outPath]` when one element is enough; the CLI chooses or validates the output extension from the encoding.
485
+ Raw calls default to inline base64 for compatibility. `auto` keeps small captures inline and returns a short-lived, daemon-owned opaque artifact handle for large captures; explicit `inline` preserves MCP image content when model vision is needed. Artifact handles expose no browser-host path and support owner-scoped bounded `artifact.read` and `artifact.delete` calls. Prefer `bbx screenshot [--format png|jpeg|webp] [--quality 0-100] <ref> [outPath]` when one element is enough; the CLI downloads, verifies, deletes, and atomically writes the artifact on the CLI host.
486
+
487
+ Artifact handles expire after five minutes and can be read or deleted only by
488
+ the requesting client. The daemon creates a private artifact directory and
489
+ owner-only files on POSIX hosts, removes artifacts on expiry/teardown, and never
490
+ returns its browser-host filesystem path.
408
491
 
409
492
  ```bash
410
- bbx call screenshot.capture_full_page '{"format":"jpeg","quality":75}'
493
+ bbx call screenshot.capture_full_page '{"format":"jpeg","quality":75,"delivery":"auto","scale":0.75}'
411
494
  ```
412
495
 
496
+ ## Recovery Telemetry
497
+
498
+ Recovery telemetry is process-local and uses fixed five-second buckets over a
499
+ five-minute window. Three failures for the same hidden group within 60 seconds
500
+ set `activeLoop` for that category. Public summaries always use only these fixed
501
+ categories: `automatic_mcp_retry`, `stale_ref_recovery`, `debugger_reattach`,
502
+ `content_script_reinjection`, `native_host_reconnect`, and `request_outcome`.
503
+ They contain attempts/successes/failures/pending, bounded rates, saturation,
504
+ last-event timestamps, and loop flags, but no page data, URL, selector, payload,
505
+ error text, method name, tab identifier, or internal group name.
506
+
507
+ `health.ping` includes daemon and available routed-extension summaries;
508
+ `daemon.metrics` includes daemon scope. `bbx doctor` combines both, marks active
509
+ loops as issues, and emits fixed guidance. Stop repeated attempts: re-query stale
510
+ refs, close competing debuggers, reload extension/page after reinjection
511
+ failures, restart for native-host reconnect failures, stop automatic MCP retry
512
+ loops, or inspect the first typed error for request failures. Extension data
513
+ resets with the service worker and daemon data resets with the daemon.
514
+
413
515
  ## Request Envelope
414
516
 
415
517
  ```json
@@ -433,6 +535,9 @@ bbx call screenshot.capture_full_page '{"format":"jpeg","quality":75}'
433
535
  | `ELEMENT_NOT_ACTIONABLE` | Inspect hidden/disabled/inert/zero-size target | `retry: false`, use `dom.describe` |
434
536
  | `ELEMENT_OBSCURED` | Inspect the element blocking the target point | `retry: false`, use `layout.hit_test` |
435
537
  | `ELEMENT_NOT_FOUND` | Correct or narrow the selector | `retry: false`, use `dom.query` |
538
+ | `DOM_BASELINE_NOT_FOUND` | Handle expired, released, evicted, or does not exist | `retry: false`, create a new baseline |
539
+ | `DOM_BASELINE_INVALIDATED` | Navigation, document, or access scope changed | `retry: false`, create a new baseline |
540
+ | `DOM_BASELINE_QUOTA_EXCEEDED` | Snapshot or retained-state quota was exceeded | `retry: false`, narrow selector or release |
436
541
  | `INPUT_UNSUPPORTED` | Use DOM execution or a CDP-supported input method | `retry: false` |
437
542
  | `INPUT_INVALID_TARGET` | Choose a control compatible with the input | `retry: false`, use `dom.describe` |
438
543
  | `INPUT_FOCUS_CHANGED` | Inspect focus handlers; do not replay native text blindly | `retry: false`, use `dom.describe` |
@@ -442,7 +547,6 @@ bbx call screenshot.capture_full_page '{"format":"jpeg","quality":75}'
442
547
  | `NATIVE_HOST_UNAVAILABLE` | Check daemon: `bbx status` | `retry: false` |
443
548
  | `EXTENSION_DISCONNECTED` | Extension not connected to daemon | `retry: true` after 3 s, check `health.ping` |
444
549
  | `TIMEOUT` | Wait/evaluate exceeded `timeoutMs` | `retry: true` after 1 s |
445
- | `RATE_LIMITED` | Too many requests | `retry: true` after 2 s |
446
550
 
447
551
  Timeout on content-script request → use narrower `dom.query` or CDP fallback.
448
552
  Timeout on navigation → increase `timeoutMs`, set `waitForLoad:false`, or check `page.get_state`.
@@ -14,7 +14,7 @@ These presets are also available at runtime via `bbx skill`.
14
14
 
15
15
  ## Debugger Policy
16
16
 
17
- Avoid debugger-backed methods until they are clearly necessary. In Browser Bridge, `page.evaluate`, `page.handle_dialog`, `dom.get_accessibility_tree`, CDP network capture, CDP input execution, `viewport.resize`, `performance.get_metrics`, `screenshot.capture_*`, and `cdp.*` attach `chrome.debugger`, which can make Chrome show its native debugging banner across the running browser instance.
17
+ Avoid debugger-backed methods until they are clearly necessary. In Browser Bridge, `page.evaluate`, `page.handle_dialog`, `dom.get_accessibility_tree`, CDP network capture, CDP input execution, `viewport.resize`, `performance.get_metrics`, `screenshot.capture_*`, and `cdp.*` attach `chrome.debugger`, which can make Chrome show its native debugging banner across the running browser instance. `network.export_har` does not attach by itself, but it requires the explicit CDP capture to remain armed.
18
18
 
19
19
  ## Decision Tree
20
20
 
@@ -28,12 +28,13 @@ Avoid debugger-backed methods until they are clearly necessary. In Browser Bridg
28
28
  8. **Need article or documentation content?** → `page.extract_content` (removes navigation and repeated chrome)
29
29
  9. **Need all visible page UI text?** → `page.get_text` (cheaper than `dom.query` on body)
30
30
  10. **Need API call history?** → default `page.get_network` (intercepted fetch/XHR log)
31
- 11. **Need framework/app state and no lighter read can expose it?** → `page.evaluate` (debugger-backed)
32
- 12. **Need semantic structure and role/text queries are insufficient?** → compact or interactive-only `dom.get_accessibility_tree` (debugger-backed)
33
- 13. **Need performance data?** → `performance.get_metrics` (debugger-backed)
34
- 14. **Testing responsive with an exact forced viewport?** → `viewport.resize` (debugger-backed)
35
- 15. **Visual ambiguity after structured reads?** → `screenshot.capture_element` first, or `screenshot.capture_region` with a tight crop when one element is not enough (debugger-backed)
36
- 16. **Content-script blocked?** → `cdp.get_document` or `cdp.get_dom_snapshot` (debugger-backed fallback)
31
+ 11. **Need portable all-resource evidence?** → explicitly arm CDP, reproduce, `network.export_har`, then stop capture
32
+ 12. **Need framework/app state and no lighter read can expose it?** → `page.evaluate` (debugger-backed)
33
+ 13. **Need semantic structure and role/text queries are insufficient?** → compact or interactive-only `dom.get_accessibility_tree` (debugger-backed)
34
+ 14. **Need a raw Chrome/CDP counter point sample?** → `performance.get_metrics` (debugger-backed; no BBX navigation window or LCP/CLS/INP measurement)
35
+ 15. **Testing responsive with an exact forced viewport?** → `viewport.resize` (debugger-backed)
36
+ 16. **Visual ambiguity after structured reads?** → `screenshot.capture_element` first, or `screenshot.capture_region` with a tight crop when one element is not enough (debugger-backed)
37
+ 17. **Content-script blocked?** → `cdp.get_document` or `cdp.get_dom_snapshot` (debugger-backed fallback)
37
38
 
38
39
  ## Allowlist Strategy
39
40
 
@@ -70,6 +71,7 @@ Omitting allowlists or leaving the text budget wide open often returns 3–5× t
70
71
  | Fetching network via evaluate hacks | ~400 tok | Use `page.get_network` (auto-interceptor) |
71
72
  | Full a11y tree with no limits | ~3000 tok | Set `maxNodes` ≤ 50, `maxDepth` ≤ 4 |
72
73
  | CDP network capture for API-only traffic | debugger lifecycle | Use default fetch/XHR capture; reserve CDP for all-resource failures |
74
+ | Broad inline HAR export | token/byte pressure | Narrow `urlPattern`/`limit`, or use `delivery: "artifact"`; bounds remove whole entries |
73
75
  | Repeated page-state polling for a route | ~500 tok/poll | Use one event-aware `page.wait_for_load_state` URL condition |
74
76
 
75
77
  ## Efficient Loop
@@ -133,6 +135,14 @@ The interceptor auto-installs on first call. Before reproducing an event, call `
133
135
 
134
136
  Only escalate to `source: "cdp"` when fetch/XHR misses the relevant document, asset, socket, cache, redirect, or failed-resource metadata. CDP must be started before reproduction and explicitly stopped afterward; it holds debugger ownership, tracks in-flight state, and returns a larger entry shape. Its URLs redact credentials, fragments, and query values, and it never returns bodies, cookies, authorization values, or complete headers.
135
137
 
138
+ For a HAR, export while that capture is still armed, then stop it. Use a narrow
139
+ sanitized-URL `urlPattern` and small `limit` first. Inline delivery removes whole
140
+ oldest entries to meet byte/token bounds rather than truncating fields; inspect
141
+ `truncation`, `dropped`, `abandoned`, and `inflight`. Use `delivery: "artifact"`
142
+ for larger evidence. The five-minute opaque handle is owner-scoped and has no
143
+ browser-host path; `bbx har` downloads, verifies, deletes, and atomically writes
144
+ it on the CLI host through the same client.
145
+
136
146
  ## Accessibility Tree for Semantic Discovery
137
147
 
138
148
  When you need to understand the page's interactive structure without guessing selectors: