@browserbridge/bbx 1.7.8 → 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 (44) hide show
  1. package/PRIVACY.md +57 -12
  2. package/README.md +19 -8
  3. package/SECURITY.md +12 -0
  4. package/package.json +15 -6
  5. package/packages/agent-client/src/cli-args.js +59 -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 +272 -70
  9. package/packages/agent-client/src/client.js +296 -8
  10. package/packages/agent-client/src/command-registry.js +64 -55
  11. package/packages/agent-client/src/config.js +195 -0
  12. package/packages/agent-client/src/content-extract.js +198 -0
  13. package/packages/agent-client/src/npm-self-update.js +305 -0
  14. package/packages/agent-client/src/remotes.js +4 -2
  15. package/packages/agent-client/src/runtime.js +864 -39
  16. package/packages/agent-client/src/types.ts +169 -6
  17. package/packages/mcp-server/src/guidance.js +1 -1
  18. package/packages/mcp-server/src/handlers-capture.js +69 -6
  19. package/packages/mcp-server/src/handlers-dom.js +61 -4
  20. package/packages/mcp-server/src/handlers-navigation.js +2 -1
  21. package/packages/mcp-server/src/handlers-page.js +211 -54
  22. package/packages/mcp-server/src/handlers-utils.js +101 -10
  23. package/packages/mcp-server/src/handlers.js +14 -7
  24. package/packages/mcp-server/src/server.js +176 -11
  25. package/packages/native-host/src/artifact-store.js +353 -0
  26. package/packages/native-host/src/config.js +9 -1
  27. package/packages/native-host/src/daemon-logger.js +3 -1
  28. package/packages/native-host/src/daemon.js +701 -33
  29. package/packages/native-host/src/native-host.js +28 -3
  30. package/packages/protocol/src/capability-values.js +2 -0
  31. package/packages/protocol/src/defaults.js +31 -0
  32. package/packages/protocol/src/errors.js +102 -6
  33. package/packages/protocol/src/incidental-sanitizer.js +197 -0
  34. package/packages/protocol/src/index.js +2 -0
  35. package/packages/protocol/src/protocol.js +612 -6
  36. package/packages/protocol/src/recovery-telemetry.js +302 -0
  37. package/packages/protocol/src/registry.js +206 -38
  38. package/packages/protocol/src/summary.js +203 -30
  39. package/packages/protocol/src/types.ts +721 -2
  40. package/skills/browser-bridge/SKILL.md +54 -19
  41. package/skills/browser-bridge/references/interaction.md +55 -11
  42. package/skills/browser-bridge/references/patch-workflow.md +2 -0
  43. package/skills/browser-bridge/references/protocol.md +265 -86
  44. package/skills/browser-bridge/references/token-efficiency.md +29 -13
@@ -13,13 +13,13 @@ Permission prompts are controlled by the host agent, not by Browser Bridge. In p
13
13
 
14
14
  Skill name: `browser-bridge` (also known as `bbx`). In GitHub Copilot, invoke as `/browser-bridge`. `bbx` is the CLI command used throughout this skill.
15
15
  When the runtime supports subagents, delegate bridge inspection to a smaller, lower-cost worker and return only concise findings to the parent.
16
- For open-ended investigation, start with structured reads (`page.get_state`, `dom.query`, `page.get_text`, `styles.get_computed`, and `bbx batch` for CLI or `browser_batch` for MCP) and escalate to screenshots or debugger-backed methods only when structured evidence is insufficient. `browser_call` accepts one protocol method at a time; `batch` is not a valid `browser_call` method.
16
+ For open-ended investigation, start with structured reads (`page.get_state`, `dom.query`, `page.get_text`, `page.extract_content`, `styles.get_computed`, and `bbx batch` for CLI or `browser_batch` for MCP) and escalate to screenshots or debugger-backed methods only when structured evidence is insufficient. `browser_call` accepts one protocol method at a time; `batch` is not a valid `browser_call` method.
17
17
 
18
18
  ## CLI
19
19
 
20
20
  ```bash
21
21
  bbx status # daemon + extension health
22
- bbx doctor # install/access readiness
22
+ bbx doctor # consolidated local diagnostics (does not probe remotes)
23
23
  bbx access-request # ask user to enable access for the focused window
24
24
  bbx restart # start/restart the daemon and running MCP servers
25
25
  bbx call <method> '{...}' # any RPC method (raw output)
@@ -58,18 +58,22 @@ bbx a11y-tree [maxNodes] [maxDepth] # accessibility tree
58
58
  ```bash
59
59
  bbx eval [--await] <expression> # JS eval (--await for promises, - for stdin)
60
60
  bbx console [level] # console output
61
- bbx network [limit] # network requests
61
+ bbx network [limit] # recent fetch/XHR requests
62
+ bbx har [options] [outPath] # export armed CDP capture as sanitized HAR 1.2
62
63
  bbx intercept add <pattern> [--respond <body>] [--status <code>] [--block] # intercept matching requests
63
64
  bbx intercept list|remove <id>|clear # manage interception rules
64
65
  bbx page-text [budget] # full page text
65
- bbx storage [local|session] [keys] # browser storage
66
- bbx perf # performance metrics
66
+ bbx storage [local|session] [keys] # storage key/presence metadata
67
+ bbx call sensitive.read '{"source":"local_storage","key":"name"}' # deliberate exact value
68
+ bbx perf # raw Chrome/CDP counter point sample
67
69
  bbx navigate <url> # navigate to URL
68
70
  bbx reload # reload current page
69
71
  bbx back # navigate back
70
72
  bbx forward # navigate forward
71
73
  bbx scroll <top> [left] # scroll viewport
72
74
  bbx resize <width> <height> # resize viewport
75
+ bbx call page.wait_for_load_state '{"url":"/dashboard","urlMatch":"contains","waitForLoad":false}'
76
+ bbx call page.handle_dialog '{"action":"inspect"}' # inspect current JS dialog; never auto-accept
73
77
  ```
74
78
 
75
79
  ### Interact & Patch
@@ -83,11 +87,12 @@ bbx press-key <key> [ref] # send key event
83
87
  bbx cdp-press-key --tab <id> Escape # CDP key event without foreground focus
84
88
  bbx hover <ref> # hover over element
85
89
  bbx call input.scroll_into_view '{"target":{"elementRef":"el_123"}}' # ensure target is visible
90
+ bbx call input.click '{"target":{"elementRef":"el_123"},"executionMode":"cdp"}' # optional native click
86
91
  bbx patch-style <ref> prop=val... # apply style patch
87
92
  bbx patch-text <ref> <text...> # apply text patch
88
93
  bbx patches # list active patches
89
94
  bbx rollback <patchId> # rollback a patch
90
- bbx screenshot <ref> [outPath] # capture partial element screenshot
95
+ bbx screenshot [--format png|jpeg|webp] [--quality 0-100] <ref> [outPath] # complete element capture
91
96
  bbx call screenshot.capture_full_page '{}' # raw base64; avoid unless document context matters
92
97
  ```
93
98
 
@@ -104,6 +109,8 @@ bbx dom-query "#app" --remote <name>
104
109
 
105
110
  In MCP mode, pass `destinationId` on any browser tool call instead; `browser_status` lists all destinations with reachability. Only use remotes the user has configured; local remains the default.
106
111
 
112
+ `bbx doctor` is intentionally local-only. It reports how many remotes are configured, but marks their status `not_probed_local_only` and credentials `unverified`; use `bbx remote test <name>` when the user wants a remote probe.
113
+
107
114
  ## Access Flow
108
115
 
109
116
  Browser Bridge access is window-scoped. The user turns it on once for the current browser window in the popup or side panel.
@@ -132,9 +139,15 @@ After access is enabled:
132
139
  | ------------------------- | -------- | ----------------------------------------------------------------------------------------- |
133
140
  | `ACCESS_DENIED` | No | Failed call already surfaced an `Enable` cue; ask user to click `Enable`, then retry once |
134
141
  | `ELEMENT_STALE` | No | Re-query with `dom.query` or `dom.find_by_text` to get a fresh ref |
142
+ | `ELEMENT_AMBIGUOUS` | No | Narrow the selector or use an explicit `elementRef`; do not guess |
143
+ | `ELEMENT_NOT_ACTIONABLE` | No | Inspect hidden/disabled/inert state with `dom.describe` |
144
+ | `ELEMENT_OBSCURED` | No | Inspect bounded blocker details or use `layout.hit_test` |
145
+ | `INPUT_FOCUS_CHANGED` | No | Inspect focus handlers; do not replay native text automatically |
146
+ | `DIALOG_NOT_OPEN` | No | Trigger or inspect the dialog again |
147
+ | `DIALOG_ACTION_CONFLICT` | No | Inspect current dialog state; never auto-repeat accept/dismiss |
135
148
  | `TAB_MISMATCH` | No | Tab closed or not found - use `tabs.list` to find an available tab |
136
149
  | `TIMEOUT` | Once | Retry once; if still failing, simplify (smaller `maxNodes`, narrower selector) |
137
- | `RATE_LIMITED` | After 2s | Back off 2 seconds, then retry |
150
+ | `CONTENT_SCRIPT_UNAVAILABLE` | No | Switch to a normal http(s) page in the enabled window |
138
151
  | `EXTENSION_DISCONNECTED` | After 3s | Check Chrome is running; `bbx status` to verify, then retry |
139
152
  | `NATIVE_HOST_UNAVAILABLE` | No | Run `bbx doctor` to diagnose the installation |
140
153
  | `INTERNAL_ERROR` | Once | Retry once; if persistent, check `page.get_console` for details |
@@ -144,6 +157,13 @@ After access is enabled:
144
157
 
145
158
  Error responses now include a machine-readable `error.recovery` field with `retry`, `retryAfterMs`, `alternativeMethod`, and `hint`.
146
159
 
160
+ `health.ping`, `daemon.metrics`, and `bbx doctor` also expose process-local
161
+ five-minute recovery summaries for six fixed, content-free categories. Three
162
+ failures in the same hidden group within 60 seconds marks an active loop. Stop
163
+ repeating the action and follow Doctor's fixed category guidance. Extension
164
+ summaries reset on service-worker restart and daemon summaries on daemon restart;
165
+ they contain no page data, URLs, selectors, payloads, errors, or group names.
166
+
147
167
  ## Core Rules
148
168
 
149
169
  1. **Work in existing tabs** - Never create new tabs unless the user explicitly asks for it, or the task absolutely requires a fresh page (e.g., testing a clean state, comparing across URLs). Prefer `tabs.list` to find an appropriate existing tab.
@@ -157,14 +177,21 @@ Error responses now include a machine-readable `error.recovery` field with `retr
157
177
  9. **Batch reads** - combine independent reads with `bbx batch` in CLI mode or `browser_batch` in MCP mode; do not pass `batch` as a `browser_call` method.
158
178
  10. **Avoid debugger first** - prefer DOM/content-script methods (`dom.*`, `styles.*`, `layout.get_box_model`, `page.get_console`, `page.get_text`, `page.get_storage`, `page.get_network`) before any debugger-backed method. Escalate to CDP only when those cannot answer the question.
159
179
  11. **Evaluate only when needed** - `page.evaluate` is powerful but debugger-backed; use it only when DOM, storage, console, network, or text reads cannot expose the needed state.
160
- 12. **Debugger-backed methods are last resort** - treat `page.evaluate`, `dom.get_accessibility_tree`, `viewport.resize`, `performance.get_metrics`, `screenshot.capture_*`, and all `cdp.*` methods as escalation steps because they attach `chrome.debugger`.
180
+ 12. **Treat exact storage as sensitive** - use `page.get_storage` for metadata first. Call `sensitive.read` for one exact key only when necessary; never batch or automatically retry it, and never repeat a failed attempt without new evidence.
181
+ 12. **Debugger-backed methods are last resort** - treat `page.evaluate`, `page.handle_dialog`, `dom.get_accessibility_tree`, `page.get_network` with `source: 'cdp'`, input with `executionMode: 'cdp'`, `viewport.resize`, `performance.get_metrics`, `screenshot.capture_*`, and all `cdp.*` methods as escalation steps because they attach `chrome.debugger`. `performance.get_metrics` is a raw browser-maintained CDP counter point sample, not Web Vitals.
161
182
  13. **Wait after change** - after editing source, wait for expected new text, a selector matching the changed attribute, or a detach/attach remount; waiting for `attached` on a selector that already exists does not prove HMR ran. Use `page.wait_for_load_state` for navigation, not HMR.
162
- 14. **Prime event buffers** - before reproducing a console or network issue, call `page.get_console` and `page.get_network` once with `clear: true`; then reproduce the event and read each buffer without clearing it.
183
+ 14. **Prime event buffers** - before reproducing a console or fetch/XHR issue, call `page.get_console` and default `page.get_network` once with `clear: true`; then reproduce and read without clearing. CDP all-resource capture instead requires explicit `start`, reproduce, `read`, and `stop` calls.
163
184
  15. **Semantic finding** - use `dom.find_by_text` / `dom.find_by_role` when you know the label but not the selector.
164
- 16. **Text extraction** - use `page.get_text` for full page text instead of `dom.query` on body.
185
+ 16. **Text extraction** - use `page.extract_content` for articles/documentation, or `page.get_text` for all visible UI text, instead of `dom.query` on body.
165
186
  17. **Network monitoring** - use `page.get_network` to inspect API calls; auto-installs interceptor.
166
187
  18. **Accessibility tree only when necessary** - `dom.get_accessibility_tree` is debugger-backed; use it when semantic structure cannot be inferred from DOM queries and role/text search.
167
188
  19. **Tailwind-aware** - when `page.get_state` returns `hints.tailwind: true`, load `references/tailwind.md`; avoid selecting by utility classes, prefer `find_by_text`/`find_by_role`; `dom.query` auto-escapes `[]` brackets.
189
+ 20. **Verify after input** - a dispatched DOM or CDP event does not prove application state changed. Follow it with the cheapest relevant wait or structured read.
190
+ 21. **Do not guess input targets** - for targeted click, focus, type, fill, press-key, checked-state, option-selection, hover, and drag calls, honor actionability errors and returned `resolution` metadata. `cdp_press_key` and `scroll_into_view` use separate contracts. `executionMode` is only `dom` or `cdp`; `input.fill.mode: auto` is a separate DOM setter/keystroke strategy.
191
+ 22. **Stale recovery stays opt-in** - prefer re-querying. Use `recoverStale: true` once only when the same document/URL and a strong unique semantic descriptor should still identify the target; inspect `recovered`, old/new refs, and matched fields. A scan with more than 100 same-tag candidates fails as `ELEMENT_AMBIGUOUS`/`scan_incomplete` because uniqueness is not provable.
192
+ 23. **Dialogs are explicit** - inspect first, then accept or dismiss only when intended. `expectedDialogId` is a pre-dispatch stale-decision check, not an atomic CDP binding; never auto-repeat `DIALOG_ACTION_CONFLICT`.
193
+ 24. **DOM diffs use explicit baselines** - call `dom.baseline.create` before the action, `dom.baseline.compare` afterward, then `dom.baseline.release`. Use a narrow selector and bounded evidence. Never substitute unrelated DOM reads for the retained baseline, and recreate it after `DOM_BASELINE_INVALIDATED`.
194
+ 25. **HAR export reads an armed capture** - use CDP capture `start`, reproduce, `network.export_har`/`bbx har`, then `stop`. Export never starts, stops, or clears capture. Inspect truncation plus `dropped`, `abandoned`, and `inflight` before claiming completeness.
168
195
 
169
196
  ## Token Budget Quick Rules
170
197
 
@@ -172,7 +199,7 @@ Error responses now include a machine-readable `error.recovery` field with `retr
172
199
  2. **Use `attributeAllowlist`** - filter irrelevant attributes (e.g. `['class', 'href', 'data-testid']`)
173
200
  3. **Batch independent reads** - combine into a single `bbx batch` / `browser_batch` call
174
201
  4. **Refresh refs after pruning** - if `dom.query` returns `_registryPruned: true`, old refs may have been evicted; re-query before reusing them
175
- 5. **Watch overflow counters** - `page.get_console` and `page.get_network` return `dropped` when hot pages overflow the 200-entry buffers
202
+ 5. **Watch overflow counters** - `page.get_console` and `page.get_network` return `dropped` when hot pages overflow the 200-entry buffers; CDP network also reports `abandoned` and capture lifecycle state
176
203
 
177
204
  ## Investigate Workflow
178
205
 
@@ -235,12 +262,13 @@ bbx page-text 2000 # extract page content
235
262
  | Inspect | `dom.query`, `dom.describe`, `dom.get_html`, `styles.get_computed`, `layout.get_box_model` |
236
263
  | Find | `dom.find_by_text`, `dom.find_by_role`, `dom.wait_for`, `dom.get_accessibility_tree` |
237
264
  | Page State | `page.get_console`, `page.get_storage`, `page.get_text`, `page.wait_for_load_state`, `page.evaluate` (debugger-backed) |
238
- | Network | `page.get_network`, `network.intercept.add/remove/list/clear` (debugger-backed; rules are in-memory and drop if the debugger detaches - verify with `list`) |
265
+ | Dialogs | `page.handle_dialog` (debugger-backed; explicit inspect/accept/dismiss only) |
266
+ | Network | `page.get_network` (fetch/XHR default; optional CDP lifecycle), `network.export_har`, `network.intercept.add/remove/list/clear` (debugger-backed) |
239
267
  | Interact | `input.click`, `input.type`, `input.fill`, `input.focus`, `input.press_key`, `cdp.dispatch_key_event`, `input.hover`, `input.drag`, `input.scroll_into_view` |
240
268
  | Tabs | `tabs.list` (preferred), `tabs.create` (avoid unless necessary), `tabs.close`, `tabs.activate` |
241
269
  | Patch | `patch.apply_styles`, `patch.apply_dom`, `patch.rollback` |
242
270
  | Navigate | `navigation.navigate`, `viewport.scroll`, `viewport.resize` |
243
- | Performance | `performance.get_metrics` (debugger-backed) |
271
+ | Performance | `performance.get_metrics` (raw Chrome/CDP counter point sample; debugger-backed) |
244
272
  | Escalate | `dom.get_accessibility_tree`, `screenshot.capture_element`, `screenshot.capture_region` (tight crops only), `screenshot.capture_full_page`, `cdp.*` |
245
273
 
246
274
  ## Dev-Server Workflow (HMR-aware)
@@ -273,8 +301,8 @@ page.get_state → page.get_console(clear: true) + page.get_network(clear: true)
273
301
 
274
302
  ```
275
303
  dom.find_by_role('button', 'Login') → input.click
304
+ → page.wait_for_load_state({url: '/dashboard', urlMatch: 'contains', waitForLoad: false})
276
305
  → dom.wait_for('.dashboard', {state: 'visible', timeoutMs: 10000})
277
- → page.get_state (verify URL changed)
278
306
  → page.get_console (check for errors)
279
307
  → dom.query('.dashboard', {maxNodes: 15}) (inspect result)
280
308
  ```
@@ -291,6 +319,8 @@ dom.find_by_role('button', 'Login') → input.click
291
319
 
292
320
  `bbx a11y-tree` and `dom.get_accessibility_tree` are sensitive to `maxDepth` and `maxNodes`. Shallow runs can undercount interactive nodes on real pages, so widen those limits before treating a low interactive count as a bug.
293
321
 
322
+ For control discovery, prefer `compact: true` or `interactiveOnly: true`, then use role/name with `dom.find_by_role` to obtain an input ref. AX `interactive` means semantic/focusable, not currently visible, unobscured, or otherwise actionable; AX results are depth-limited partial topology and include truncation metadata even when `maxNodes` was not reached.
323
+
294
324
  > **MCP mode:** If Browser Bridge is connected via MCP (tools named `browser_dom`, `browser_capture`, etc.), use the MCP tools directly - do not shell out to `bbx`. The MCP tools map 1:1 to CLI capabilities. In prompts, `BB MCP` and `Browser Bridge MCP` both work. Do not treat `bbx-mcp` as a skill alias.
295
325
  >
296
326
  > For open-ended MCP inspection tasks, prefer `browser_investigate` first. It is read-only, designed for cheaper delegated investigation, and falls back to a deterministic sequence when the client cannot delegate. Escalate to `browser_capture` only when the structured investigation is not enough.
@@ -306,7 +336,7 @@ Every CLI shortcut command produces consistent `{ok, summary, evidence}` JSON. U
306
336
  ## CLI Raw Params Gotchas
307
337
 
308
338
  - Use `selector`, not `scope`, to narrow `dom.find_by_text` and `dom.find_by_role`.
309
- - Wrap interaction targets as `target: { elementRef }` or `target: { selector }`; `viewport.scroll` also uses the `target` wrapper for element scrolling. **Do not pass `ref` or `elementRef` at the top level** -- interaction methods require the nested `target` wrapper:
339
+ - Wrap targeted DOM input as `target: { elementRef }` or `target: { selector }`; `input.press_key` may omit the target to use the active element, `input.scroll_into_view` also accepts `target`, and `cdp.dispatch_key_event` targets the tab. **Do not pass `ref` or `elementRef` at the top level**:
310
340
  ```bash
311
341
  # CORRECT
312
342
  bbx call input.click '{"target":{"elementRef":"el_xxx"}}'
@@ -316,7 +346,11 @@ Every CLI shortcut command produces consistent `{ok, summary, evidence}` JSON. U
316
346
  bbx call input.click '{"elementRef":"el_xxx"}'
317
347
  ```
318
348
  - `input.drag` uses `source`, `destination`, and optional destination offsets `offsetX` / `offsetY`.
319
- - Raw `screenshot.capture_region` and `screenshot.capture_full_page` return base64 JSON; prefer `bbx screenshot <ref> [outPath]` when one element is enough.
349
+ - `executionMode` accepts `dom` or `cdp` and defaults to `dom`; CDP supports only click, hover, drag, type, and fill. `input.fill.mode` (`auto`, `setter`, `keystrokes`) is a separate DOM strategy.
350
+ - `page.get_network` defaults to low-cost fetch/XHR instrumentation. All-resource CDP capture must be armed before the activity with `source: "cdp", capture: "start"`, read later, and explicitly stopped.
351
+ - `network.export_har` requires that explicit capture to still be armed. Params are `limit` (1-200), sanitized-URL substring `urlPattern`, and `delivery` (`auto`, `inline`, `artifact`). Inline bounds remove whole oldest entries; export never changes capture state. `bbx har` uses the same client to download, length/SHA-256 verify, delete, validate, and atomically write artifacts locally.
352
+ - `page.handle_dialog` mutations are not atomically bound to `expectedDialogId`; treat `commandDispatched` as dispatch evidence and verify follow-up state.
353
+ - Raw screenshot calls default to inline base64. Use `delivery: "auto"` for size-aware artifact fallback, or explicit `inline` when MCP image content is required; prefer `bbx screenshot <ref> [outPath]` when one element is enough because the CLI downloads and verifies artifacts locally.
320
354
 
321
355
  ## Response Shapes
322
356
 
@@ -324,7 +358,7 @@ The summarizer auto-detects response types and produces concise summaries:
324
358
 
325
359
  Shortcut commands intentionally expose only the common case. Use `bbx call <method> '{...}'` when you need method-specific fields that are not surfaced by a shortcut, such as `tabs.create.active`.
326
360
 
327
- `dom.query` results include `registrySize` and may include `_registryPruned: true` after element-ref eviction. `page.get_console` and `page.get_network` include `dropped` when older buffered entries were discarded.
361
+ `dom.query` results include `registrySize` and may include `_registryPruned: true` after element-ref eviction. `page.get_console` and `page.get_network` include `dropped` when older buffered entries were discarded. Targeted click, focus, type, fill, press-key, checked-state, option-selection, hover, and drag results include bounded `resolution` and `execution` metadata; `cdp_press_key` and `scroll_into_view` use separate contracts.
328
362
 
329
363
  | Response Type | Detection | Summary Format |
330
364
  | ---------------- | -------------------------------- | ------------------------------------------------------------ |
@@ -338,14 +372,15 @@ Shortcut commands intentionally expose only the common case. Use `bbx call <meth
338
372
  | Element describe | `result.tag + elementRef + bbox` | `Element tag#id: text.` |
339
373
  | Computed styles | `result.properties + elementRef` | `Computed N style(s) for ref.` |
340
374
  | Box model | `result.content + border` | `Box model: W×H at (x, y).` |
341
- | Network | `entries[0].type=fetch/xhr` | `Network: N requests.` |
375
+ | Network | `result.source + entries` | `Network: N requests.` |
376
+ | HAR export | `result.format === "har"` | `HAR export delivered mode: N/M entries.` |
342
377
  | Console | `entries` (no type field) | `Console: N entries.` |
343
378
  | Logs | `entries[0].at + method` | `Log: N entries.` |
344
379
  | Patch apply | `result.patchId` | `Patch id applied.` |
345
380
  | Patch rollback | `result.rolled_back` | `Patch rolled back.` |
346
381
  | Patch list | `result.patches` | `N active patch(es).` |
347
382
  | HTML | `result.html` | `HTML fragment: N chars.` |
348
- | Performance | `result.metrics` | `Performance: N metrics collected.` |
383
+ | Performance | `result.metrics` | `Raw CDP performance counters: N collected; Web Vitals not measured.` |
349
384
  | Storage | `result.type + count + entries` | `Storage (type): N entries.` |
350
385
  | Click/Focus/Type | `result.clicked/focused/typed` | `Clicked/Focused/Typed ref.` |
351
386
  | Key press | `result.pressed` | `Key pressed (key).` |
@@ -4,16 +4,16 @@
4
4
 
5
5
  | Method | CLI Shortcut | Purpose |
6
6
  | ------------------------ | ------------------------------------- | ----------------------------------------------------------- |
7
- | `input.click` | `click <ref> [button]` | DOM-level click |
7
+ | `input.click` | `click <ref> [button]` | Actionability-aware DOM click; optional CDP native click |
8
8
  | `input.focus` | `focus <ref>` | Focus an element |
9
- | `input.type` | `type <ref> <text>` | Type into input/textarea/contenteditable |
10
- | `input.fill` | `fill <ref> <value>` | Set field value via native setter (React/Vue/Angular-safe) |
9
+ | `input.type` | `type <ref> <text>` | DOM key sequence; optional CDP native text insertion |
10
+ | `input.fill` | `fill <ref> <value>` | DOM fill strategy; optional CDP clear and text insertion |
11
11
  | `input.press_key` | `press-key <key> [ref]` | Send keyboard key (Enter, Backspace, etc.) |
12
12
  | `cdp.dispatch_key_event` | `cdp-press-key --tab <id> <key>` | CDP keyDown/keyUp without focusing the target tab |
13
13
  | `input.set_checked` | `call input.set_checked '{...}'` | Toggle checkbox/radio |
14
14
  | `input.select_option` | `call input.select_option '{...}'` | Select native `<select>` by value/label/index |
15
- | `input.hover` | `hover <ref>` | Trigger CSS `:hover` state (mouseenter/mouseover/mousemove) |
16
- | `input.drag` | `call input.drag '{...}'` | Full drag-and-drop event sequence |
15
+ | `input.hover` | `hover <ref>` | DOM hover events or optional CDP pointer move |
16
+ | `input.drag` | `call input.drag '{...}'` | DOM drag events or optional CDP pointer drag |
17
17
  | `input.scroll_into_view` | `call input.scroll_into_view '{...}'` | Ensure a target is visible before inspect/capture |
18
18
 
19
19
  ## Navigation
@@ -29,6 +29,14 @@ bbx call navigation.go_forward
29
29
  - `waitForLoad` defaults `true`; set `false` for long-lived pages.
30
30
  - If navigation times out, retry with larger `timeoutMs` or check with `page.get_state`.
31
31
 
32
+ For a navigation or SPA route caused by input, use event-aware URL conditions instead of polling:
33
+
34
+ ```bash
35
+ bbx call page.wait_for_load_state '{"url":"/dashboard","urlMatch":"contains","waitForLoad":false,"timeoutMs":10000}'
36
+ ```
37
+
38
+ The current URL is checked first. The wait then observes full navigation, tab URL/status updates, `pushState`, `replaceState`, `popstate`, and hash changes. It returns the final URL, elapsed time, and observed navigation kind. `waitForLoad: true` means Chrome tab status `complete`, not `networkidle`. Regex mode is deliberately restricted to a bounded linear subset without grouping, alternation, quantifiers, or backreferences.
39
+
32
40
  ## Viewport
33
41
 
34
42
  ```bash
@@ -78,15 +86,17 @@ Typical workflow - compare two pages (only when comparison is required):
78
86
 
79
87
  ## Accessibility Tree
80
88
 
81
- Retrieve the full accessibility tree for the page. Useful for understanding semantic structure, finding interactive elements, and accessibility audits.
89
+ Retrieve a depth-limited accessibility tree for the page. Useful for understanding semantic structure, finding interactive elements, and accessibility audits.
82
90
 
83
91
  ```bash
84
92
  bbx a11y-tree # default limits
85
93
  bbx a11y-tree 50 3 # max 50 nodes, depth 3
86
94
  bbx call dom.get_accessibility_tree '{"maxNodes":100,"maxDepth":5}'
95
+ bbx call dom.get_accessibility_tree '{"maxNodes":100,"maxDepth":6,"compact":true}'
96
+ bbx call dom.get_accessibility_tree '{"maxNodes":100,"maxDepth":6,"interactiveOnly":true}'
87
97
  ```
88
98
 
89
- Each node: `role`, `name`, `description`, `value`, `focused`, `required`, `checked`, `disabled`, `interactive`, `childIds`.
99
+ Each node includes semantic state plus `interactive`, `semanticInteractive`, `focusable`, `focusableAndEnabled`, `ignored`, and `childIds`. `interactive` is not a current actionability guarantee. Compact and interactive-only filters run before `maxNodes`; results report partial depth topology, missing children, and continuation guidance. AX nodes do not become page refs, so use `dom.find_by_role` before input.
90
100
 
91
101
  Typical workflow - find interactive controls:
92
102
 
@@ -151,7 +161,7 @@ bbx network 50 # newly captured requests
151
161
  bbx console error # newly captured errors
152
162
  ```
153
163
 
154
- Each entry: `method`, `url`, `status`, `duration`, `initiator`.
164
+ Default fetch/XHR entries are retained in capture order and contain `method`, `url`, `status`, `duration`, `type`, `ts`, and `size`.
155
165
 
156
166
  Typical workflow - debug API calls:
157
167
 
@@ -161,6 +171,17 @@ Typical workflow - debug API calls:
161
171
  4. Cross-reference with `page.get_console` for errors
162
172
  5. Use `page.evaluate` only if lighter evidence cannot expose the needed response state
163
173
 
174
+ For document, script, stylesheet, image, WebSocket, WebTransport, and other resource metadata, explicitly arm CDP before reproducing:
175
+
176
+ ```bash
177
+ bbx call page.get_network '{"source":"cdp","capture":"start"}'
178
+ # reproduce activity
179
+ bbx call page.get_network '{"source":"cdp","capture":"read","limit":50}'
180
+ bbx call page.get_network '{"source":"cdp","capture":"stop"}'
181
+ ```
182
+
183
+ This holds debugger ownership and is more expensive than default instrumentation. A plain read cannot recover events from before `start`. CDP results report armed/ownership/inflight/drop state and redact URL credentials, fragments, and query values; bodies, cookies, authorization values, and complete headers are excluded.
184
+
164
185
  ## Network Interception
165
186
 
166
187
  Block, stub, or modify matching requests via CDP (debugger-backed). Patterns are globs: `*` matches any characters, `?` matches one character.
@@ -204,6 +225,28 @@ bbx type el_123 hello # simulate per-character keystrokes
204
225
 
205
226
  Prefer `fill` for setting form values: it uses the native prototype setter plus `input`/`change`/`blur` events, which React, Vue, and Angular pick up reliably. `mode` defaults to `auto` (setter first, keystroke fallback if the value did not stick); pass `"mode":"keystrokes"` via `bbx call input.fill` for components that only react to per-key events. Use `type` when page logic depends on individual key events (autocomplete, masked inputs).
206
227
 
228
+ `mode` is not `executionMode`. The latter accepts only `dom` or `cdp`, defaults to `dom` for compatibility, and selects the dispatch path. CDP execution is available only for click, hover, drag, type, and fill; unsupported combinations fail with `INPUT_UNSUPPORTED` instead of silently changing paths.
229
+
230
+ ## Actionability And Stale Refs
231
+
232
+ Input selectors preserve the first match when it is actionable. Otherwise Browser Bridge evaluates at most 25 candidates and proceeds only when one is uniquely preferable. It scrolls the selected target as needed, then rechecks rendered bounds, hidden/disabled/inert state, and pointer hit testing. Expect structured `ELEMENT_NOT_FOUND`, `ELEMENT_NOT_ACTIONABLE`, `ELEMENT_OBSCURED`, or `ELEMENT_AMBIGUOUS` errors rather than best-effort retargeting.
233
+
234
+ Successful targeted click, focus, type, fill, press-key, checked-state, option-selection, hover, and drag results report `resolution` and `execution` metadata. `cdp_press_key` and `scroll_into_view` use separate contracts. Explicit refs preserve exact identity. Stale refs fail by default; `recoverStale: true` allows a single same-document, unchanged-URL recovery only from a strong unique semantic descriptor, and reports old/new refs and matched fields. The recovery scan evaluates at most 100 same-tag candidates and returns `ELEMENT_AMBIGUOUS` with `reason: "scan_incomplete"` whenever additional candidates make uniqueness unprovable. Prefer a fresh query unless this strict recovery contract clearly applies.
235
+
236
+ After any DOM or CDP input, verify the intended application outcome with a targeted wait or structured read. Event dispatch alone is not proof that application state changed.
237
+
238
+ ## JavaScript Dialogs
239
+
240
+ Dialogs are never accepted or dismissed automatically:
241
+
242
+ ```bash
243
+ bbx call page.handle_dialog '{"action":"inspect"}'
244
+ bbx call page.handle_dialog '{"action":"accept","expectedDialogId":"00000000-0000-4000-8000-000000000000:1"}' # replace with inspected dialogId
245
+ bbx call page.handle_dialog '{"action":"dismiss","expectedDialogId":"00000000-0000-4000-8000-000000000000:1"}' # replace with inspected dialogId
246
+ ```
247
+
248
+ `expectedDialogId` is checked immediately before the CDP command, but Chrome cannot atomically bind that command to the observation. A successful mutation reports `commandDispatched: true` and `atomicDialogBinding: false`. On `DIALOG_ACTION_CONFLICT`, inspect again and do not automatically repeat the mutation. Dialog text is returned only to the caller and is excluded from persisted action logs.
249
+
207
250
  ## Hover
208
251
 
209
252
  Dispatch mouse events to trigger CSS `:hover` rules, tooltip display, dropdown menus, etc.
@@ -297,7 +340,7 @@ Use after clicking navigation links.
297
340
 
298
341
  ## Raw `bbx call` for Interaction Methods
299
342
 
300
- All interaction methods (`input.click`, `input.type`, `input.focus`, `input.hover`, etc.) require the target wrapped in a `target` object -- do not pass `ref` or `elementRef` at the top level:
343
+ Targeted DOM input methods require the target wrapped in a `target` object; `input.press_key` may omit it to use the active element. Do not pass `ref` or `elementRef` at the top level. `cdp.dispatch_key_event` targets the tab, while `input.scroll_into_view` accepts `target` but does not return actionability/execution metadata:
301
344
 
302
345
  ```bash
303
346
  # CORRECT
@@ -318,5 +361,6 @@ The CLI shortcuts (`bbx click el_xxx`) handle this wrapping automatically, but `
318
361
  1. **Find target**: `dom.find_by_text`, `dom.find_by_role`, or `dom.query` → get `elementRef`
319
362
  2. **Focus** if needed: `input.focus` (for keyboard input)
320
363
  3. **Act**: `click`, `type`, `press_key`, `hover`, `drag`, `scroll_into_view`, etc.
321
- 4. **Wait**: `dom.wait_for` if action triggers async updates
322
- 5. **Verify**: `dom.describe`, `styles.get_computed`, or `page.get_console` for errors
364
+ 4. **Inspect metadata**: confirm resolution strategy, hit test, stale recovery, and actual execution path
365
+ 5. **Wait**: use `dom.wait_for` or an event-aware URL wait if the action triggers async updates
366
+ 6. **Verify**: `dom.describe`, `styles.get_computed`, `page.get_state`, or `page.get_console`; never infer app success from dispatch alone
@@ -41,3 +41,5 @@ After any patch:
41
41
 
42
42
  - Roll back every patch before finishing.
43
43
  - If multiple patches are active, list them before rolling back so the subagent can explain what was tested.
44
+ - Rollback records live in the current document. Browser Bridge attempts to roll them back when access is disabled or switched to another window; navigation or document replacement removes the page-side registry and may make old patch IDs unusable.
45
+ - `patch.commit_session_baseline` keeps the current DOM/style changes but clears their rollback records. Use it only when the user intentionally wants those live changes to become the new patch baseline; it does not write source files or grant a longer-lived browser session.