@browserbridge/bbx 1.11.3 → 1.12.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.
- package/package.json +14 -8
- package/packages/agent-client/src/client.js +18 -1
- package/packages/agent-client/src/types.ts +2 -0
- package/packages/mcp-server/src/handlers-capture.js +19 -7
- package/packages/mcp-server/src/handlers-dom.js +6 -1
- package/packages/mcp-server/src/handlers-utils.js +3 -0
- package/packages/mcp-server/src/server.js +59 -3
- package/packages/protocol/src/defaults.js +16 -0
- package/packages/protocol/src/protocol.js +366 -12
- package/packages/protocol/src/registry.js +34 -10
- package/packages/protocol/src/summary.js +249 -38
- package/packages/protocol/src/types.ts +157 -7
- package/skills/browser-bridge/SKILL.md +23 -13
- package/skills/browser-bridge/references/interaction.md +86 -21
- package/skills/browser-bridge/references/protocol.md +39 -10
- package/skills/browser-bridge/references/token-efficiency.md +12 -6
|
@@ -53,7 +53,8 @@ bbx box <ref> # box model dimensions
|
|
|
53
53
|
bbx find <text> # find by text content
|
|
54
54
|
bbx find-role <role> [name] # find by ARIA role
|
|
55
55
|
bbx wait <selector> [timeoutMs] # wait for DOM element
|
|
56
|
-
bbx a11y-tree [maxNodes] [maxDepth] # accessibility tree
|
|
56
|
+
bbx a11y-tree [maxNodes] [maxDepth] # accessibility tree (CDP)
|
|
57
|
+
bbx call dom.get_accessibility_tree '{"source":"dom","interactiveOnly":true}' # actionable outline with refs
|
|
57
58
|
```
|
|
58
59
|
|
|
59
60
|
### Page & Evaluate
|
|
@@ -90,6 +91,8 @@ bbx press-key <key> [ref] # send key event
|
|
|
90
91
|
bbx cdp-press-key --tab <id> Escape # CDP key event without foreground focus
|
|
91
92
|
bbx hover <ref> # hover over element
|
|
92
93
|
bbx call input.scroll_into_view '{"target":{"elementRef":"el_123"}}' # ensure target is visible
|
|
94
|
+
bbx call input.click '{"target":{"role":"button","name":"Save"}}' # find + wait + click + effects in one call
|
|
95
|
+
bbx call input.fill '{"target":{"label":"Email"},"value":"a@b.co"}' # locate a field by its label
|
|
93
96
|
bbx call input.click '{"target":{"elementRef":"el_123"},"executionMode":"cdp"}' # optional native click
|
|
94
97
|
bbx patch-style <ref> prop=val... # apply style patch
|
|
95
98
|
bbx patch-text <ref> <text...> # apply text patch
|
|
@@ -131,10 +134,13 @@ After the Enable cue appears:
|
|
|
131
134
|
|
|
132
135
|
After access is enabled:
|
|
133
136
|
|
|
134
|
-
1.
|
|
135
|
-
2. If the user switches
|
|
136
|
-
3.
|
|
137
|
-
4.
|
|
137
|
+
1. Your first tab-bound call binds your session to the active tab: that becomes your **working tab**.
|
|
138
|
+
2. The working tab is sticky. If the user switches to another tab (to read mail, say), your calls keep running in your working tab; they never navigate or type into the tab the user is looking at.
|
|
139
|
+
3. Responses report `meta.tab_id`; when the user's active tab differs, the summary says so (`Ran in working tab 12; the user's active tab is 34`). If the user asks you to work in "this tab", pass that `tabId` once; the explicit tab becomes your new working tab. `tabs.create` and `tabs.activate` also move your working tab.
|
|
140
|
+
4. If your working tab was closed, calls fail with `TAB_MISMATCH` (`reason: working_tab_closed`) instead of silently using another tab; pick a tab with `tabId` or `tabs.list` (which marks `working: true`).
|
|
141
|
+
5. The binding expires after 15 idle minutes.
|
|
142
|
+
6. Do not stop at a generic "no access" message before making a real Browser Bridge call, because the first denied call is what triggers the UI cue.
|
|
143
|
+
7. CLI agents running separate `bbx` processes share one working tab unless each sets `BBX_SESSION=<name>`; MCP sessions are separated automatically.
|
|
138
144
|
|
|
139
145
|
## Error Recovery
|
|
140
146
|
|
|
@@ -148,7 +154,7 @@ After access is enabled:
|
|
|
148
154
|
| `INPUT_FOCUS_CHANGED` | No | Inspect focus handlers; do not replay native text automatically |
|
|
149
155
|
| `DIALOG_NOT_OPEN` | No | Trigger or inspect the dialog again |
|
|
150
156
|
| `DIALOG_ACTION_CONFLICT` | No | Inspect current dialog state; never auto-repeat accept/dismiss |
|
|
151
|
-
| `TAB_MISMATCH` | No | Tab closed or not found - use `tabs.list`
|
|
157
|
+
| `TAB_MISMATCH` | No | Tab closed or not found (`working_tab_closed`: your working tab is gone) - pass `tabId` or use `tabs.list` |
|
|
152
158
|
| `TIMEOUT` | Once | Retry once; if still failing, simplify (smaller `maxNodes`, narrower selector) |
|
|
153
159
|
| `CONTENT_SCRIPT_UNAVAILABLE` | No | Switch to a normal http(s) page in the enabled window |
|
|
154
160
|
| `EXTENSION_DISCONNECTED` | After 3s | Check Chrome is running; `bbx status` to verify, then retry |
|
|
@@ -181,20 +187,23 @@ they contain no page data, URLs, selectors, payloads, errors, or group names.
|
|
|
181
187
|
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.
|
|
182
188
|
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.
|
|
183
189
|
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.
|
|
184
|
-
12. **Debugger-backed methods are last resort** - treat `page.evaluate`, `page.handle_dialog`, `dom.get_accessibility_tree
|
|
190
|
+
12. **Debugger-backed methods are last resort** - treat `page.evaluate`, `page.handle_dialog`, `dom.get_accessibility_tree` with the default CDP source, `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.
|
|
185
191
|
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.
|
|
186
192
|
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.
|
|
187
|
-
15. **
|
|
193
|
+
15. **Act on what you can name** - when you know the label but not the selector, put a locator straight into the input target (`{"role":"button","name":"Save"}`, `{"label":"Email"}`, `{"text":"Load more"}`, `{"placeholder":"Search"}`, `{"testId":"submit"}`; add `nth` to pick among matches). Use `dom.find_by_text` / `dom.find_by_role` only when you need to look before acting. Locators and finders search shadow DOM and iframes, use real accessible names (`<label for>`, wrapping labels, `aria-*`, `alt`), and skip hidden matches (`hiddenMatches` counts them; `includeHidden: true` lists them).
|
|
188
194
|
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.
|
|
189
195
|
17. **Network monitoring** - use `page.get_network` to inspect API calls; auto-installs interceptor.
|
|
190
|
-
18. **
|
|
196
|
+
18. **Overview with the DOM outline** - for "what can I do on this page?", call `dom.get_accessibility_tree` with `source: "dom"` (add `interactiveOnly: true` for controls only). It returns compact lines like `- button "Save" [el_k7q2_1f] disabled` whose refs work directly as input targets, includes shadow DOM and iframes, and needs no debugger. Reserve the default CDP source for accessibility audits.
|
|
191
197
|
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.
|
|
192
|
-
20. **
|
|
193
|
-
21. **
|
|
198
|
+
20. **Read the effects before reading the page** - click, press_key, set_checked, select_option, and submitting type/fill return `effects` after a short settle: same-document `url` changes, `navigation: "unloading"`, newly opened `dialogs`, alert/status/live-region `messages`, the `focused` element, `dom` churn, and the target's new state (`value`, `checked`, `expanded`, `removed`). The summary digests them (`Effects: URL → /done; alert: "Saved"`). Only follow up with a read when the effects do not answer the question; `changed: false` means nothing visible happened. Pass `observe: true` to other actions, or `observe: false` to skip the settle.
|
|
199
|
+
21. **Let actions wait** - targeted actions wait up to `timeoutMs` (default 2500, max 15000, `0` disables) for the target to appear, become enabled/visible/unobscured, and stop animating. Do not add a separate `dom.wait_for` before an action. Honor the errors that remain after the wait, plus `resolution.waitedMs`. `cdp_press_key` and `scroll_into_view` use separate contracts; `input.fill.mode: auto` is a separate DOM setter/keystroke strategy.
|
|
194
200
|
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.
|
|
195
201
|
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`.
|
|
196
202
|
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`.
|
|
197
203
|
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.
|
|
204
|
+
26. **Keep timing inside the browser** - for rhythm, games, gestures, or any steps that must happen at set times or back-to-back, send one `input.perform` with the whole schedule (`atMs` from the sequence start, or `delayMs` after the previous step). Never spread timed input across tool calls (each call costs an agent round-trip) and never issue input as parallel tool calls (they land all at once).
|
|
205
|
+
27. **Use trusted input when the page needs a user gesture** - DOM-mode events are untrusted, so Chrome may refuse audio or media start, popups, clipboard writes, and fullscreen. `executionMode: "auto"` picks debugger input only for file inputs, media, `target=_blank` links, rich-text editors, or when the debugger is already attached (`execution.selectionReason` says why). Use `executionMode: "cdp"` to force it (click, hover, drag, type, fill, press_key, touch); `input.perform` accepts it once for every step. If a DOM click reports `changed: false` on a page that should react, retry once with `cdp` rather than repeating the DOM click. CDP input is not available for targets inside iframes.
|
|
206
|
+
28. **Simultaneous presses need touch** - a mouse has one pointer. For chords or multi-finger gestures use `input.touch` with several `points` (optionally `to` end positions for swipes and pinches); add `holdMs` to `input.click`/`input.press_key` when the press must last.
|
|
198
207
|
|
|
199
208
|
## Token Budget Quick Rules
|
|
200
209
|
|
|
@@ -267,7 +276,7 @@ bbx page-text 2000 # extract page content
|
|
|
267
276
|
| Page State | `page.get_console`, `page.get_storage`, `page.get_text`, `page.wait_for_load_state`, `page.evaluate` (debugger-backed) |
|
|
268
277
|
| Dialogs | `page.handle_dialog` (debugger-backed; explicit inspect/accept/dismiss only) |
|
|
269
278
|
| Network | `page.get_network` (fetch/XHR default; optional CDP lifecycle), `network.export_har`, `network.intercept.add/remove/list/clear` (debugger-backed) |
|
|
270
|
-
| Interact | `input.click`, `input.type`, `input.fill`, `input.focus`, `input.press_key`, `cdp.dispatch_key_event`, `input.hover`, `input.drag`, `input.scroll_into_view` |
|
|
279
|
+
| Interact | `input.click`, `input.type`, `input.fill`, `input.focus`, `input.press_key`, `cdp.dispatch_key_event`, `input.hover`, `input.drag`, `input.touch`, `input.perform` (timed sequences), `input.scroll_into_view` |
|
|
271
280
|
| Tabs | `tabs.list` (preferred), `tabs.create` (avoid unless necessary), `tabs.close`, `tabs.activate` |
|
|
272
281
|
| Patch | `patch.apply_styles`, `patch.apply_dom`, `patch.rollback` |
|
|
273
282
|
| Navigate | `navigation.navigate`, `viewport.scroll`, `viewport.resize` |
|
|
@@ -349,7 +358,8 @@ Every CLI shortcut command produces consistent `{ok, summary, evidence}` JSON. U
|
|
|
349
358
|
bbx call input.click '{"elementRef":"el_xxx"}'
|
|
350
359
|
```
|
|
351
360
|
- `input.drag` uses `source`, `destination`, and optional destination offsets `offsetX` / `offsetY`.
|
|
352
|
-
- `executionMode` accepts `dom` or `cdp` and defaults to `dom`; CDP supports
|
|
361
|
+
- `executionMode` accepts `dom` or `cdp` and defaults to `dom`; CDP supports click, hover, drag, type, fill, press_key, and touch. `input.fill.mode` (`auto`, `setter`, `keystrokes`) is a separate DOM strategy.
|
|
362
|
+
- `input.perform` takes `steps: [{ method, params, atMs | delayMs }]` using the same params each method takes alone. Steps run in order inside the extension; it stops at the first failed step (or a `dom.wait_for` that times out) unless `continueOnError: true`, and reports `startedAtMs` for every step.
|
|
353
363
|
- `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.
|
|
354
364
|
- `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.
|
|
355
365
|
- `page.handle_dialog` mutations are not atomically bound to `expectedDialogId`; treat `commandDispatched` as dispatch evidence and verify follow-up state.
|
|
@@ -4,16 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
| Method | CLI Shortcut | Purpose |
|
|
6
6
|
| ------------------------ | ------------------------------------- | ----------------------------------------------------------- |
|
|
7
|
-
| `input.click` | `click <ref> [button]` |
|
|
7
|
+
| `input.click` | `click <ref> [button]` | Auto-waiting, actionability-aware click with observed `effects`; locator targets; optional CDP; `holdMs` |
|
|
8
8
|
| `input.focus` | `focus <ref>` | Focus an element |
|
|
9
9
|
| `input.type` | `type <ref> <text>` | DOM key sequence; optional CDP native text insertion |
|
|
10
10
|
| `input.fill` | `fill <ref> <value>` | DOM fill strategy; optional CDP clear and text insertion |
|
|
11
|
-
| `input.press_key` | `press-key <key> [ref]` | Send keyboard key (Enter, Backspace, etc.)
|
|
11
|
+
| `input.press_key` | `press-key <key> [ref]` | Send keyboard key (Enter, Backspace, etc.); optional CDP; `holdMs` |
|
|
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
15
|
| `input.hover` | `hover <ref>` | DOM hover events or optional CDP pointer move |
|
|
16
|
-
| `input.drag` | `call input.drag '{...}'` |
|
|
16
|
+
| `input.drag` | `call input.drag '{...}'` | HTML5 drag for draggable sources, pointer drag otherwise; optional CDP |
|
|
17
|
+
| `input.touch` | `call input.touch '{...}'` | One or more simultaneous touch points: chords, taps, swipes, pinches |
|
|
18
|
+
| `input.perform` | `call input.perform '{...}'` | Ordered, timed sequence of input steps run inside the browser |
|
|
17
19
|
| `input.scroll_into_view` | `call input.scroll_into_view '{...}'` | Ensure a target is visible before inspect/capture |
|
|
18
20
|
|
|
19
21
|
## Navigation
|
|
@@ -84,30 +86,26 @@ Typical workflow - compare two pages (only when comparison is required):
|
|
|
84
86
|
3. Inspect both tabs (`--tab <id>` or MCP `tabId` only when you need the non-active tab)
|
|
85
87
|
4. `tabs.close` when done
|
|
86
88
|
|
|
87
|
-
## Accessibility
|
|
89
|
+
## Accessibility Outline
|
|
88
90
|
|
|
89
|
-
|
|
91
|
+
For a page overview you can act on, use the DOM outline. It needs no debugger, covers shadow DOM and iframes, and every line carries a ref that input methods accept directly:
|
|
90
92
|
|
|
91
93
|
```bash
|
|
92
|
-
bbx
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
bbx call dom.get_accessibility_tree '{"source":"dom","interactiveOnly":true}'
|
|
95
|
+
# - textbox "Email address" [el_k7q2_3] required
|
|
96
|
+
# - button "Place order" [el_k7q2_4]
|
|
97
|
+
# - iframe [frame 7]
|
|
98
|
+
# - button "Pay now" [el_m2xa_1]
|
|
99
|
+
bbx call input.click '{"target":{"elementRef":"el_m2xa_1"}}'
|
|
97
100
|
```
|
|
98
101
|
|
|
99
|
-
|
|
102
|
+
Usually you can skip the overview and act with a locator in one call: `{"target":{"role":"button","name":"Pay now"}}`.
|
|
100
103
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
1. `dom.get_accessibility_tree` with small `maxNodes`
|
|
104
|
-
2. Scan for nodes with `interactive: true`
|
|
105
|
-
3. Use role/name to identify the right control
|
|
106
|
-
4. `dom.find_by_role` to get an `elementRef` for interaction
|
|
104
|
+
The default `source: "cdp"` returns Chrome's AX tree through the debugger. Use it for accessibility audits (`compact`, `interactiveOnly`, `maxDepth`, `format: "outline"`); its nodes have no refs.
|
|
107
105
|
|
|
108
106
|
## Multi-Tab Workflows
|
|
109
107
|
|
|
110
|
-
Access is window-scoped.
|
|
108
|
+
Access is window-scoped. Your first call binds your session to the active tab in the enabled window, which becomes your working tab, and later calls stay there even when the user switches tabs. Responses include `meta.tab_id`; when the user is looking at a different tab, the summary names both. `tabs.list` marks your tab with `working: true`. Passing `tabId`, `tabs.create`, or `tabs.activate` moves your working tab. A closed working tab fails with `TAB_MISMATCH` (`working_tab_closed`) rather than switching to whatever tab is active.
|
|
111
109
|
|
|
112
110
|
```bash
|
|
113
111
|
# Default routing follows the active tab in the enabled window:
|
|
@@ -225,7 +223,69 @@ bbx type el_123 hello # simulate per-character keystrokes
|
|
|
225
223
|
|
|
226
224
|
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).
|
|
227
225
|
|
|
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
|
|
226
|
+
`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 for click, hover, drag, type, fill, press_key, and touch; unsupported combinations fail with `INPUT_UNSUPPORTED` instead of silently changing paths.
|
|
227
|
+
|
|
228
|
+
## DOM vs CDP Input
|
|
229
|
+
|
|
230
|
+
DOM mode dispatches the same event sequence a real device produces, so most pages cannot tell the difference:
|
|
231
|
+
|
|
232
|
+
- **Clicks**: `pointerover`/`pointerenter`/`mouseover`/`mouseenter` (only when the virtual pointer moves onto a new element), `pointermove`/`mousemove`, `pointerdown`/`mousedown`, focus, optional hold, `pointerup`/`mouseup`, then `click` (`contextmenu` for right, `auxclick` for middle) carrying coordinates, modifiers, `detail`, and `pointerType`. A canceled `pointerdown` suppresses the mouse events; a canceled `mousedown` keeps focus where it was. Leaving an element fires `pointerout`/`mouseout`/`leave` on it.
|
|
233
|
+
- **Keys**: `keydown` with `key`, `code`, and `keyCode`, `keypress` for character keys, the editing action, then `keyup`. A canceled `keydown` suppresses the character, as in browsers.
|
|
234
|
+
|
|
235
|
+
DOM events are still untrusted (`isTrusted: false`) and do not count as a user gesture, so Chrome may refuse what a page gates on one: starting audio or media (unless the site already has autoplay engagement), popups, clipboard writes, and fullscreen. When a page needs a real gesture, use `executionMode: "cdp"`, which dispatches trusted input through Chrome. If sound or video stays silent after a DOM click, retry the first interaction with CDP.
|
|
236
|
+
|
|
237
|
+
## Press and Hold
|
|
238
|
+
|
|
239
|
+
`holdMs` (0-10000) keeps a mouse button or key pressed between down and up:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
bbx call input.click '{"target":{"selector":"[data-midi=\"60\"]"},"holdMs":400}'
|
|
243
|
+
bbx call input.press_key '{"key":"q","holdMs":400,"executionMode":"cdp"}'
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Use it for long-press menus, sustained notes, and buttons that act while pressed.
|
|
247
|
+
|
|
248
|
+
## Timed Sequences
|
|
249
|
+
|
|
250
|
+
Every tool call costs an agent round-trip, so steps sent one call at a time arrive seconds apart, and steps sent as parallel tool calls all land at once. When timing matters (music, games, animations, gestures, quick reactions), send the whole schedule as one `input.perform`:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
bbx call input.perform '{
|
|
254
|
+
"executionMode": "cdp",
|
|
255
|
+
"steps": [
|
|
256
|
+
{"method":"input.click","params":{"target":{"selector":"[data-midi=\"60\"]"},"holdMs":350},"atMs":0},
|
|
257
|
+
{"method":"input.click","params":{"target":{"selector":"[data-midi=\"62\"]"},"holdMs":350},"atMs":400},
|
|
258
|
+
{"method":"input.touch","params":{"points":[{"target":{"selector":"[data-midi=\"60\"]"}},{"target":{"selector":"[data-midi=\"64\"]"}},{"target":{"selector":"[data-midi=\"67\"]"}}],"holdMs":700},"atMs":800}
|
|
259
|
+
]
|
|
260
|
+
}'
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
- Each step is `{ method, params, atMs | delayMs }`; `params` are exactly what the method takes on its own.
|
|
264
|
+
- Allowed step methods: `input.click`, `input.focus`, `input.type`, `input.fill`, `input.press_key`, `input.set_checked`, `input.select_option`, `input.hover`, `input.drag`, `input.touch`, `input.scroll_into_view`, `viewport.scroll`, `dom.wait_for`, `page.wait_for_load_state`.
|
|
265
|
+
- `atMs` is the earliest start measured from the sequence start, so delays never accumulate; `delayMs` waits after the previous step finished. Steps always run in order, so a step whose `atMs` has already passed starts immediately.
|
|
266
|
+
- A top-level `executionMode` applies to every step that supports it unless the step sets its own.
|
|
267
|
+
- Add `dom.wait_for` steps to react to the page without a round-trip, e.g. click, wait for `.menu`, click the item. A wait that times out counts as a failed step.
|
|
268
|
+
- The sequence stops at the first failure with that step's error code and `details.failedStep`, `completed`, and `startedAtMs`. Set `continueOnError: true` to run every step and collect `failures`.
|
|
269
|
+
- `timeoutMs` (default 30000, max 120000) bounds the whole sequence, and waiting steps are capped to the remaining budget. At most 200 steps.
|
|
270
|
+
- The result reports `startedAtMs` (actual start of every step), so you can verify the rhythm without a screenshot. Then verify application state as usual.
|
|
271
|
+
|
|
272
|
+
## Touch and Multi-Finger Input
|
|
273
|
+
|
|
274
|
+
A mouse is one pointer, so it cannot press two things at once. `input.touch` puts every point down together, holds them for `holdMs` (default 50), and lifts them together:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
# Three-finger chord
|
|
278
|
+
bbx call input.touch '{"points":[{"target":{"selector":"#c4"}},{"target":{"selector":"#e4"}},{"target":{"selector":"#g4"}}],"holdMs":600,"executionMode":"cdp"}'
|
|
279
|
+
# Swipe, and pinch-out with viewport coordinates
|
|
280
|
+
bbx call input.touch '{"points":[{"x":300,"y":400,"to":{"x":60,"y":400}}],"holdMs":250}'
|
|
281
|
+
bbx call input.touch '{"points":[{"x":200,"y":300,"to":{"x":120,"y":300}},{"x":240,"y":300,"to":{"x":320,"y":300}}],"holdMs":300,"moveSteps":12}'
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
- Each point is either `target` (`elementRef`/`selector`, actionability-checked at its center) or viewport `x`/`y`, plus an optional `to` end position. Up to 10 points.
|
|
285
|
+
- Points with `to` move in `moveSteps` (default 10) interpolated steps spread across `holdMs`.
|
|
286
|
+
- DOM mode fires per-finger `pointerdown`/`pointermove`/`pointerup` (`pointerType: "touch"`, distinct `pointerId`, first finger primary) and `touchstart`/`touchmove`/`touchend` with accurate `touches`. A single-finger tap without movement also produces the compatibility `mousedown`/`mouseup`/`click`.
|
|
287
|
+
- CDP mode sends trusted `Input.dispatchTouchEvent` events; fingers are always lifted, even after an error. Pages that only enable touch handlers after feature-detecting a touch screen may still ignore desktop touch input.
|
|
288
|
+
- Result: `pointCount`, per-point `elementRef` and coordinates, and in DOM mode `canceled` (the page called `preventDefault`) and `clicked`.
|
|
229
289
|
|
|
230
290
|
## Actionability And Stale Refs
|
|
231
291
|
|
|
@@ -256,7 +316,7 @@ bbx hover el_abc123
|
|
|
256
316
|
bbx call input.hover '{"target":{"elementRef":"el_abc123"}}'
|
|
257
317
|
```
|
|
258
318
|
|
|
259
|
-
**Hold hover for inspection:** set `duration` (ms) to
|
|
319
|
+
**Hold hover for inspection:** set `duration` (ms) to wait after hovering before the call returns. The pointer stays over the element until a later input moves it elsewhere, which then fires `mouseout`/`mouseleave`:
|
|
260
320
|
|
|
261
321
|
```bash
|
|
262
322
|
bbx call input.hover '{"target":{"elementRef":"el_abc123"},"duration":2000}'
|
|
@@ -283,7 +343,12 @@ With pixel offsets for precise positioning:
|
|
|
283
343
|
bbx call input.drag '{"source":{"elementRef":"el_src"},"destination":{"elementRef":"el_dst"},"offsetX":5,"offsetY":5}'
|
|
284
344
|
```
|
|
285
345
|
|
|
286
|
-
|
|
346
|
+
DOM mode picks the sequence a browser would use:
|
|
347
|
+
|
|
348
|
+
- **Draggable sources** (`draggable="true"`, links, images): `pointerdown → mousedown → dragstart → pointercancel → drag → dragenter → dragover → drop → dragend`. `drop` only fires when the destination cancels `dragover`, as real drop zones must; otherwise it gets `dragleave`.
|
|
349
|
+
- **Other sources** (sortable lists, sliders, canvases, and other pointer-driven UIs): `pointerdown/mousedown`, ten interpolated `pointermove/mousemove` steps with the button held across whatever elements lie under the path (with over/out transitions), then `pointerup/mouseup` at the destination.
|
|
350
|
+
|
|
351
|
+
The result's `strategy` reports `html5` or `pointer`. CDP mode drives a real pointer drag either way.
|
|
287
352
|
|
|
288
353
|
Typical workflow - reorder a list:
|
|
289
354
|
|
|
@@ -78,22 +78,24 @@ omit both for the group index.
|
|
|
78
78
|
| `dom.find_by_text` | Yes | - | inspect | `dom.read` | Find by visible text; returns `{nodes, count}` |
|
|
79
79
|
| `dom.find_by_role` | Yes | - | inspect | `dom.read` | Find by ARIA role; optional `name` filter |
|
|
80
80
|
| `dom.get_html` | Yes | - | inspect | `dom.read` | `innerHTML`/`outerHTML`; `maxLength` truncation |
|
|
81
|
-
| `dom.get_accessibility_tree` | Yes | CDP
|
|
81
|
+
| `dom.get_accessibility_tree` | Yes | CDP / none | inspect | `dom.read` | AX tree (CDP) or `source: "dom"` actionable outline with refs, no debugger |
|
|
82
82
|
| `layout.get_box_model` | Yes | - | inspect | `layout.read` | Element geometry |
|
|
83
83
|
| `layout.hit_test` | Yes | - | inspect | `layout.read` | Topmost element at viewport point |
|
|
84
84
|
| `styles.get_computed` | Yes | - | inspect | `styles.read` | Requested properties; omission returns display/position/width/height/color |
|
|
85
85
|
| `styles.get_matched_rules` | Yes | - | inspect | `styles.read` | Element ref, class list, and inline style only; not stylesheet cascade data |
|
|
86
86
|
| `viewport.scroll` | Yes | - | navigate | `viewport.control` | Window or element scroll |
|
|
87
87
|
| `viewport.resize` | Yes | CDP | navigate | `viewport.control` | Set viewport via device emulation; `reset: true` |
|
|
88
|
-
| `input.click` | Yes | Optional | interact | `automation.input` | Actionability-aware DOM or CDP click
|
|
88
|
+
| `input.click` | Yes | Optional | interact | `automation.input` | Actionability-aware DOM or CDP click; `holdMs` keeps the button pressed |
|
|
89
89
|
| `input.focus` | Yes | - | interact | `automation.input` | Actionability-aware DOM focus |
|
|
90
90
|
| `input.type` | Yes | Optional | interact | `automation.input` | DOM key sequence or CDP text insertion |
|
|
91
91
|
| `input.fill` | Yes | Optional | interact | `automation.input` | DOM fill strategy or CDP clear/insert; see `mode` versus `executionMode` |
|
|
92
|
-
| `input.press_key` | Yes |
|
|
92
|
+
| `input.press_key` | Yes | Optional | interact | `automation.input` | DOM key events (with `code`/`keyCode`) or trusted CDP key pair; `holdMs` |
|
|
93
93
|
| `input.set_checked` | Yes | - | interact | `automation.input` | Checkbox/radio toggle |
|
|
94
94
|
| `input.select_option` | Yes | - | interact | `automation.input` | Native select by value/label/index |
|
|
95
95
|
| `input.hover` | Yes | Optional | interact | `automation.input` | DOM hover events or native CDP pointer move |
|
|
96
|
-
| `input.drag` | Yes | Optional | interact | `automation.input` |
|
|
96
|
+
| `input.drag` | Yes | Optional | interact | `automation.input` | HTML5 drag for draggable sources, pointer drag otherwise; or native CDP pointer drag |
|
|
97
|
+
| `input.touch` | Yes | Optional | interact | `automation.input` | 1-10 simultaneous touch points (chords, taps, swipes, pinches) held for `holdMs` |
|
|
98
|
+
| `input.perform` | Yes | Per step | interact | `automation.input` | Ordered, timed sequence of input steps executed inside the extension |
|
|
97
99
|
| `input.scroll_into_view` | Yes | - | interact | `automation.input` | Explicitly scroll target into view before inspect/capture |
|
|
98
100
|
| `screenshot.capture_element` | Yes | CDP | capture | `screenshot.partial` | Complete element screenshot with explicit completeness metadata |
|
|
99
101
|
| `screenshot.capture_region` | Yes | CDP | capture | `screenshot.partial` | Cropped viewport region in PNG, JPEG, or WebP |
|
|
@@ -261,7 +263,7 @@ bbx call dom.wait_for '{"selector":".modal","state":"visible","timeoutMs":10000}
|
|
|
261
263
|
|
|
262
264
|
### dom.find_by_text
|
|
263
265
|
|
|
264
|
-
Find elements matching visible text content. Like Playwright's `getByText
|
|
266
|
+
Find elements matching visible text content. Like Playwright's `getByText`: own text and text-like attributes match first, otherwise the innermost element whose combined text matches (so `<button><b>Place</b> order</button>` matches "Place order" on the button). `script`/`style`/`template` content never matches. Searches open and closed shadow roots and, when the top document has no match, child iframes (nodes then carry `frameId`). Hidden matches are omitted and counted in `hiddenMatches`; pass `includeHidden: true` to list them (marked `visible: false`).
|
|
265
267
|
|
|
266
268
|
```bash
|
|
267
269
|
bbx find 'Submit Order'
|
|
@@ -270,7 +272,7 @@ bbx call dom.find_by_text '{"text":"Submit","selector":"button","exact":false}'
|
|
|
270
272
|
|
|
271
273
|
### dom.find_by_role
|
|
272
274
|
|
|
273
|
-
Find elements by ARIA role (explicit `role` attribute or implicit from HTML tag).
|
|
275
|
+
Find elements by ARIA role (explicit `role` attribute or implicit from HTML tag) and accessible name. Names come from `aria-labelledby`, `aria-label`, associated `<label for>` or wrapping `<label>`, `alt`, button values, content for name-from-content roles, `title`, then `placeholder`. A single `<select>` matches `combobox` and `listbox`; number inputs match `spinbutton` and `textbox`. `exact: true` requires the whole name. Same shadow DOM, iframe, and hidden-match behavior as `dom.find_by_text`. Results include the computed `role` and `name`.
|
|
274
276
|
|
|
275
277
|
```bash
|
|
276
278
|
bbx find-role button 'Save'
|
|
@@ -292,9 +294,13 @@ When `properties` is omitted, `styles.get_computed` returns exactly `display`, `
|
|
|
292
294
|
|
|
293
295
|
### Actionable input targets
|
|
294
296
|
|
|
297
|
+
Targets are `{ elementRef }`, `{ selector }`, or a semantic locator: `role` (+ `name`), `text`, `label`, `placeholder`, or `testId` (`data-testid`, `data-test-id`, `data-test`, `data-qa`), with optional `exact`, `nth` (pick among visible matches), and `selector` (narrows locator candidates). Selectors and locators reach into shadow roots; when the top document has no match, child iframes are probed and the action runs in the frame that has it (refs remember their frame).
|
|
298
|
+
|
|
299
|
+
Before dispatch, targeted actions wait up to `timeoutMs` (default 2500, max 15000; `0` disables) while the target is missing, not actionable, obscured, or still animating; `resolution.waitedMs` reports the wait. Click, press_key, set_checked, select_option, and type/fill with `submit` then observe for up to `observe.settleMs` (default 500) until the DOM is quiet for 150ms and return `effects`: `url` (same-document change), `navigation: "unloading"`, `title`, newly visible `dialogs` (`role`, `name`, `ref`), `messages` from alert/status/live regions, `focused`, `dom` (`added`/`removed`), `target` state (`value`, `checked`, `expanded`, `selected`, `pressed`, `disabled`, or `removed`), `changed`, and `settledMs`. Pass `observe: true` to other actions or `observe: false` to skip. Steps inside `input.perform` observe only on request.
|
|
300
|
+
|
|
295
301
|
Input calls preserve an explicit `elementRef`. For selectors, the first actionable match wins; if it is not actionable, Browser Bridge evaluates at most 25 matches and chooses only a uniquely better candidate. It scrolls the selected target if needed and rechecks visibility, disabled/inert state, rendered bounds, and pointer hit testing before dispatch. Failures use `ELEMENT_NOT_FOUND`, `ELEMENT_NOT_ACTIONABLE`, `ELEMENT_OBSCURED`, or `ELEMENT_AMBIGUOUS` with bounded details.
|
|
296
302
|
|
|
297
|
-
Successful targeted click, focus, type, fill, press-key, checked-state, option-selection, hover, and drag results include `resolution` (`strategy`, candidate/evaluated counts, scrolling, hit test, and recovery fields) and `execution` (`requestedMode`, `actualMode`, `fallbackReason`, `debuggerUsed`, and coordinates). `cdp.dispatch_key_event`/MCP `cdp_press_key` and `input.scroll_into_view` use separate response contracts. `executionMode` is the dispatch path
|
|
303
|
+
Successful targeted click, focus, type, fill, press-key, checked-state, option-selection, hover, and drag results include `resolution` (`strategy`, candidate/evaluated counts, scrolling, hit test, and recovery fields) and `execution` (`requestedMode`, `actualMode`, `fallbackReason`, `debuggerUsed`, and coordinates). `cdp.dispatch_key_event`/MCP `cdp_press_key` and `input.scroll_into_view` use separate response contracts. `executionMode` is the dispatch path: `dom` (default), `cdp`, or `auto`. `auto` uses CDP only when the debugger is already attached to the tab or the target likely needs trusted input (file input, media, `target=_blank` link, rich-text editor), and reports `execution.selectionReason`. It never retries an action through a second path. CDP is not available for targets inside iframes (`INPUT_UNSUPPORTED`); `auto` stays on DOM there. CDP is supported by click, hover, drag, type, fill, press_key, and touch; unsupported combinations return `INPUT_UNSUPPORTED` instead of falling back silently. DOM events mirror real device event order (pointer events, boundary transitions, `code`/`keyCode`) but are untrusted, so Chrome may refuse gesture-gated features such as audio/media start; use CDP for those.
|
|
298
304
|
|
|
299
305
|
`input.fill.mode` is separate: `auto`, `setter`, and `keystrokes` choose the DOM fill strategy. `mode: "auto"` may fall back from the setter to keystrokes and reports the used `mode`; it does not select CDP. With `executionMode: "cdp"`, fill uses native clear/text dispatch and reports `mode: "cdp"`.
|
|
300
306
|
|
|
@@ -313,13 +319,30 @@ bbx call input.hover '{"target":{"elementRef":"el_abc123"},"duration":1000}'
|
|
|
313
319
|
|
|
314
320
|
### input.drag
|
|
315
321
|
|
|
316
|
-
|
|
322
|
+
For natively draggable sources the DOM path dispatches `pointerdown → mousedown → dragstart → pointercancel → drag → dragenter → dragover → drop → dragend` (`drop` only when the destination cancels `dragover`). Other sources get a pointer drag: press, ten interpolated moves with the button held, release at the destination. `strategy` reports `html5` or `pointer`. The CDP path performs a bounded interpolated native pointer drag and guarantees a release attempt after failure. Both accept source, destination, and optional destination offsets.
|
|
317
323
|
|
|
318
324
|
```bash
|
|
319
325
|
bbx call input.drag '{"source":{"elementRef":"el_src"},"destination":{"elementRef":"el_dst"}}'
|
|
320
326
|
bbx call input.drag '{"source":{"elementRef":"el_src"},"destination":{"elementRef":"el_dst"},"offsetX":10,"offsetY":10}'
|
|
321
327
|
```
|
|
322
328
|
|
|
329
|
+
### input.touch
|
|
330
|
+
|
|
331
|
+
Put 1-10 fingers down at once, hold them for `holdMs` (default 50), optionally move points that have a `to` end position over `moveSteps` (default 10), then lift them. Each point is `{ target }` or viewport `{ x, y }`. DOM mode fires per-finger pointer events (`pointerType: "touch"`) and touch events; CDP mode uses trusted `Input.dispatchTouchEvent`.
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
bbx call input.touch '{"points":[{"target":{"selector":"#c4"}},{"target":{"selector":"#e4"}}],"holdMs":500,"executionMode":"cdp"}'
|
|
335
|
+
bbx call input.touch '{"points":[{"x":300,"y":400,"to":{"x":60,"y":400}}],"holdMs":250}'
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### input.perform
|
|
339
|
+
|
|
340
|
+
Run `steps: [{ method, params, atMs | delayMs }]` in order inside the extension, so timing does not depend on agent round-trips. Step methods: input click/focus/type/fill/press_key/set_checked/select_option/hover/drag/touch/scroll_into_view, `viewport.scroll`, `dom.wait_for`, and `page.wait_for_load_state`. `atMs` is measured from the sequence start (no drift); `delayMs` follows the previous step. A top-level `executionMode` applies to steps that support it. The sequence stops at the first failed step (including a timed-out `dom.wait_for`) with that step's code and `details.failedStep`, unless `continueOnError: true`. `timeoutMs` defaults to 30000 (max 120000); at most 200 steps. Success returns `completed`, `total`, `elapsedMs`, `startedAtMs`, and `failures`.
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
bbx call input.perform '{"executionMode":"cdp","steps":[{"method":"input.click","params":{"target":{"selector":"#c4"},"holdMs":300},"atMs":0},{"method":"input.click","params":{"target":{"selector":"#d4"},"holdMs":300},"atMs":400}]}'
|
|
344
|
+
```
|
|
345
|
+
|
|
323
346
|
### input.scroll_into_view
|
|
324
347
|
|
|
325
348
|
Explicitly scroll an element into the visible viewport before inspecting, hovering, or capturing it.
|
|
@@ -443,7 +466,13 @@ artifact, and atomically write the output on the CLI host.
|
|
|
443
466
|
|
|
444
467
|
### dom.get_accessibility_tree
|
|
445
468
|
|
|
446
|
-
|
|
469
|
+
`source: "dom"` builds an actionable outline in the content script, with no debugger. It covers visible interactive controls (plus headings, landmarks, dialogs, alerts, and named regions unless `interactiveOnly: true`) across shadow roots and iframes. Each line looks like `- button "Save" [el_k7q2_1f] disabled`, and states include `checked`, `expanded`/`collapsed`, `selected`, `pressed`, `required`, `focused`, `level=N`, and `value="…"` (never for passwords). Refs work directly as input targets. `format: "tree"` returns the same entries as `nodes`. `maxNodes` bounds it (default 150).
|
|
470
|
+
|
|
471
|
+
```bash
|
|
472
|
+
bbx call dom.get_accessibility_tree '{"source":"dom","interactiveOnly":true}'
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
The default `source: "cdp"` retrieves a depth-limited accessibility tree via CDP. Full reads use `Accessibility.getFullAXTree`; an optional unique `selector` resolves through CDP DOM methods, starts with `Accessibility.getPartialAXTree`, and incrementally fetches selected descendant layers with `Accessibility.getChildAXNodes`. Only the selected subtree and required ancestor chain are retained. 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.
|
|
447
476
|
|
|
448
477
|
This is debugger-backed. Prefer `dom.find_by_role`, `dom.find_by_text`, and targeted `dom.query`/`dom.describe` first.
|
|
449
478
|
|
|
@@ -455,7 +484,7 @@ bbx call dom.get_accessibility_tree '{"maxNodes":100,"maxDepth":6,"interactiveOn
|
|
|
455
484
|
bbx call dom.get_accessibility_tree '{"selector":"[role=dialog]","maxNodes":50,"compact":true}'
|
|
456
485
|
```
|
|
457
486
|
|
|
458
|
-
Filtering occurs before `maxNodes`. Compact mode drops ignored, decorative, and empty nodes while reconnecting retained descendants; interactive-only keeps non-ignored semantic interactive roles. Full reads ask CDP for the requested depth, while selector-scoped reads fetch descendant layers up to that same bound.
|
|
487
|
+
Filtering occurs before `maxNodes`. Compact mode drops ignored, decorative, and empty nodes while reconnecting retained descendants; interactive-only keeps non-ignored semantic interactive roles. Full reads ask CDP for the requested depth, while selector-scoped reads fetch descendant layers up to that same bound. `truncated` and `partialTopology` are true only when `maxNodes` cut nodes or the depth bound left children unfetched (`missingChildCount`), and only then is a continuation hint returned. `format: "outline"` renders CDP nodes as compact lines. CDP AX nodes carry no element refs; use `source: "dom"` (or a role/name locator) to act on them.
|
|
459
488
|
|
|
460
489
|
### viewport.resize
|
|
461
490
|
|
|
@@ -61,13 +61,15 @@ Omitting allowlists or leaving the text budget wide open often returns 3–5× t
|
|
|
61
61
|
| Full-page screenshot | ~3000 tok | Use `screenshot.capture_element`, or `screenshot.capture_region` with a tight rect |
|
|
62
62
|
| Requesting broad computed styles via CDP | ~800 tok | Use `styles.get_computed`; omission returns five core props, or pass 3-8 explicit props |
|
|
63
63
|
| Multiple CLI calls for independent reads | overhead/call | Use `batch` command |
|
|
64
|
-
| Guessing selectors for known labels | ~300 tok wasted/try |
|
|
64
|
+
| Guessing selectors for known labels | ~300 tok wasted/try | Put a locator in the input target (`{"role":"button","name":"Save"}`, `{"label":"Email"}`) |
|
|
65
|
+
| Find, then act, then re-read | 3 round trips | One locator-targeted action; read its `effects` instead of re-querying |
|
|
66
|
+
| `dom.wait_for` before every action | 1 extra round trip | Actions auto-wait (`timeoutMs`, default 2500) |
|
|
65
67
|
| Polling page state with repeated queries | ~500 tok/poll | Use `dom.wait_for` (single call, waits async) |
|
|
66
68
|
| Inspecting DOM to read app state | ~800 tok | Use `page.evaluate` to read JS directly |
|
|
67
69
|
| Re-querying after HMR without waiting | ~500 tok stale | `dom.wait_for` first, then query |
|
|
68
70
|
| Separate call to verify a patch | ~500 tok wasted | Set `verify: true` on `patch.apply_styles` / `patch.apply_dom` to get computed result inline |
|
|
69
71
|
| `dom.query` on body for page text | ~2000 tok | Use `page.get_text` (extracts innerText directly) |
|
|
70
|
-
| Guessing interactive elements from DOM | ~600 tok/try |
|
|
72
|
+
| Guessing interactive elements from DOM | ~600 tok/try | `dom.get_accessibility_tree` with `source: "dom"`: ~10 tokens per control, refs included |
|
|
71
73
|
| Fetching network via evaluate hacks | ~400 tok | Use `page.get_network` (auto-interceptor) |
|
|
72
74
|
| Full a11y tree with no limits | ~3000 tok | Set `maxNodes` ≤ 50, `maxDepth` ≤ 4 |
|
|
73
75
|
| CDP network capture for API-only traffic | debugger lifecycle | Use default fetch/XHR capture; reserve CDP for all-resource failures |
|
|
@@ -143,15 +145,19 @@ for larger evidence. The five-minute opaque handle is owner-scoped and has no
|
|
|
143
145
|
browser-host path; `bbx har` downloads, verifies, deletes, and atomically writes
|
|
144
146
|
it on the CLI host through the same client.
|
|
145
147
|
|
|
146
|
-
## Accessibility
|
|
148
|
+
## Accessibility Outline for Semantic Discovery
|
|
147
149
|
|
|
148
|
-
When you need
|
|
150
|
+
When you need the page's interactive structure without guessing selectors:
|
|
149
151
|
|
|
150
152
|
```bash
|
|
151
|
-
bbx call dom.get_accessibility_tree '{"
|
|
153
|
+
bbx call dom.get_accessibility_tree '{"source":"dom","interactiveOnly":true,"maxNodes":60}'
|
|
152
154
|
```
|
|
153
155
|
|
|
154
|
-
|
|
156
|
+
Each control is one line (`- button "Save" [el_k7q2_1f]`, about 10 tokens versus about 80 for a JSON AX node), refs act directly, and no debugger is attached. The CDP tree (`source` omitted) is for audits; add `format: "outline"` to keep it compact.
|
|
157
|
+
|
|
158
|
+
## Act, Then Read Effects
|
|
159
|
+
|
|
160
|
+
Input actions return what changed (`effects`: URL, dialogs, alerts/status text, focus, DOM churn, target state), and the summary digests it in one line. Routine successes omit resolution/execution metadata; it appears only when something notable happened (scroll, wait, ranking, stale recovery, CDP). Element refs are short (`el_k7q2_1f`). Re-read the page only when the effects leave the question open.
|
|
155
161
|
|
|
156
162
|
## Semantic finding Saves Selector Guessing
|
|
157
163
|
|