@browserbridge/bbx 1.0.0 → 1.0.1

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 (52) hide show
  1. package/README.md +3 -1
  2. package/docs/api-reference.md +33 -33
  3. package/docs/mcp-vs-cli.md +104 -104
  4. package/docs/publishing.md +1 -3
  5. package/docs/quickstart.md +6 -6
  6. package/docs/unpacked-extension.md +72 -0
  7. package/manifest.json +3 -17
  8. package/package.json +44 -42
  9. package/packages/agent-client/src/cli-helpers.js +10 -5
  10. package/packages/agent-client/src/cli.js +65 -135
  11. package/packages/agent-client/src/client.js +37 -17
  12. package/packages/agent-client/src/command-registry.js +101 -69
  13. package/packages/agent-client/src/detect.js +3 -6
  14. package/packages/agent-client/src/install.js +10 -27
  15. package/packages/agent-client/src/mcp-config.js +11 -30
  16. package/packages/agent-client/src/runtime.js +41 -20
  17. package/packages/agent-client/src/setup-status.js +13 -28
  18. package/packages/extension/src/background-helpers.js +51 -36
  19. package/packages/extension/src/background-routing.js +11 -13
  20. package/packages/extension/src/background.js +562 -299
  21. package/packages/extension/src/content-script-helpers.js +17 -16
  22. package/packages/extension/src/content-script.js +175 -109
  23. package/packages/extension/src/sidepanel-helpers.js +3 -1
  24. package/packages/extension/ui/popup.js +39 -20
  25. package/packages/extension/ui/sidepanel.js +108 -191
  26. package/packages/extension/ui/ui.css +2 -1
  27. package/packages/mcp-server/src/handlers.js +546 -250
  28. package/packages/mcp-server/src/server.js +558 -257
  29. package/packages/native-host/bin/bridge-daemon.js +6 -2
  30. package/packages/native-host/bin/install-manifest.js +2 -2
  31. package/packages/native-host/bin/postinstall.js +4 -2
  32. package/packages/native-host/src/config.js +11 -7
  33. package/packages/native-host/src/daemon.js +143 -92
  34. package/packages/native-host/src/install-manifest.js +73 -22
  35. package/packages/native-host/src/native-host.js +55 -40
  36. package/packages/protocol/src/budget.js +3 -7
  37. package/packages/protocol/src/capabilities.js +3 -3
  38. package/packages/protocol/src/errors.js +11 -11
  39. package/packages/protocol/src/protocol.js +104 -71
  40. package/packages/protocol/src/registry.js +300 -45
  41. package/packages/protocol/src/summary.js +249 -106
  42. package/packages/protocol/src/types.js +1 -1
  43. package/skills/browser-bridge/SKILL.md +1 -1
  44. package/skills/browser-bridge/agents/openai.yaml +3 -3
  45. package/skills/browser-bridge/references/interaction.md +33 -11
  46. package/skills/browser-bridge/references/patch-workflow.md +3 -0
  47. package/skills/browser-bridge/references/protocol.md +125 -70
  48. package/skills/browser-bridge/references/tailwind.md +12 -11
  49. package/skills/browser-bridge/references/token-efficiency.md +23 -22
  50. package/skills/browser-bridge/references/ui-workflows.md +8 -0
  51. package/packages/extension/ui/offscreen.html +0 -6
  52. package/packages/extension/ui/offscreen.js +0 -61
@@ -2,17 +2,17 @@
2
2
 
3
3
  ## Input Methods
4
4
 
5
- | Method | CLI Shortcut | Purpose |
6
- |--------|-------------|---------|
7
- | `input.click` | `click <ref> [button]` | DOM-level click |
8
- | `input.focus` | `focus <ref>` | Focus an element |
9
- | `input.type` | `type <ref> <text>` | Type into input/textarea/contenteditable |
10
- | `input.press_key` | `press-key <key> [ref]` | Send keyboard key (Enter, Backspace, etc.) |
11
- | `input.set_checked` | `call input.set_checked '{...}'` | Toggle checkbox/radio |
12
- | `input.select_option` | `call input.select_option '{...}'` | Select native `<select>` by value/label/index |
13
- | `input.hover` | `hover <ref>` | Trigger CSS `:hover` state (mouseenter/mouseover/mousemove) |
14
- | `input.drag` | `call input.drag '{...}'` | Full drag-and-drop event sequence |
15
- | `input.scroll_into_view` | `call input.scroll_into_view '{...}'` | Ensure a target is visible before inspect/capture |
5
+ | Method | CLI Shortcut | Purpose |
6
+ | ------------------------ | ------------------------------------- | ----------------------------------------------------------- |
7
+ | `input.click` | `click <ref> [button]` | DOM-level click |
8
+ | `input.focus` | `focus <ref>` | Focus an element |
9
+ | `input.type` | `type <ref> <text>` | Type into input/textarea/contenteditable |
10
+ | `input.press_key` | `press-key <key> [ref]` | Send keyboard key (Enter, Backspace, etc.) |
11
+ | `input.set_checked` | `call input.set_checked '{...}'` | Toggle checkbox/radio |
12
+ | `input.select_option` | `call input.select_option '{...}'` | Select native `<select>` by value/label/index |
13
+ | `input.hover` | `hover <ref>` | Trigger CSS `:hover` state (mouseenter/mouseover/mousemove) |
14
+ | `input.drag` | `call input.drag '{...}'` | Full drag-and-drop event sequence |
15
+ | `input.scroll_into_view` | `call input.scroll_into_view '{...}'` | Ensure a target is visible before inspect/capture |
16
16
 
17
17
  ## Navigation
18
18
 
@@ -39,6 +39,7 @@ Scrolls the window or a specific scrollable element.
39
39
  ### Resize Viewport
40
40
 
41
41
  Set device viewport dimensions (useful for responsive testing):
42
+
42
43
  ```bash
43
44
  bbx resize 375 812 # iPhone-size
44
45
  bbx resize 1024 768 # tablet
@@ -50,6 +51,7 @@ Uses CDP device emulation - the page re-renders at the new size immediately.
50
51
  ## Tab Management
51
52
 
52
53
  **IMPORTANT: Prefer existing tabs.** Never create new tabs unless:
54
+
53
55
  - The user explicitly requests opening a new page
54
56
  - The task requires a clean/fresh page state (e.g., testing initial load)
55
57
  - You need to compare multiple pages simultaneously
@@ -65,6 +67,7 @@ bbx call tabs.create '{"url":"https://example.com","active":false}'
65
67
  ```
66
68
 
67
69
  Typical workflow - compare two pages (only when comparison is required):
70
+
68
71
  1. `tabs.list` to see current tabs
69
72
  2. `tabs.create` with second URL
70
73
  3. Inspect both tabs (`--tab <id>` or MCP `tabId` only when you need the non-active tab)
@@ -83,6 +86,7 @@ bbx call dom.get_accessibility_tree '{"maxNodes":100,"maxDepth":5}'
83
86
  Each node: `role`, `name`, `description`, `value`, `focused`, `required`, `checked`, `disabled`, `interactive`, `childIds`.
84
87
 
85
88
  Typical workflow - find interactive controls:
89
+
86
90
  1. `dom.get_accessibility_tree` with small `maxNodes`
87
91
  2. Scan for nodes with `interactive: true`
88
92
  3. Use role/name to identify the right control
@@ -103,6 +107,7 @@ bbx call --tab 200 dom.query '{"selector":"main"}'
103
107
  ```
104
108
 
105
109
  Open a new tab programmatically:
110
+
106
111
  ```bash
107
112
  bbx tab-create https://example.com # creates a new tab in the enabled window
108
113
  bbx call --tab <new-tabId> page.get_state
@@ -127,6 +132,7 @@ Scrolls the window by default. Pass an `elementRef` to scroll an inner scrollabl
127
132
  ### Scroll target into view
128
133
 
129
134
  Use this when the page has nested containers or when you want the target centered before a screenshot or hover:
135
+
130
136
  ```bash
131
137
  bbx call input.scroll_into_view '{"target":{"elementRef":"el_123"}}'
132
138
  bbx call input.scroll_into_view '{"target":{"selector":"[data-testid=\"submit-button\"]"}}'
@@ -143,6 +149,7 @@ bbx call page.get_network '{"limit":20,"clear":true}'
143
149
  Each entry: `method`, `url`, `status`, `duration`, `initiator`.
144
150
 
145
151
  Typical workflow - debug API calls:
152
+
146
153
  1. `page.get_network` to see recent requests
147
154
  2. Filter by URL pattern or status code
148
155
  3. Cross-reference with `page.get_console` for errors
@@ -151,11 +158,13 @@ Typical workflow - debug API calls:
151
158
  ## Form Controls
152
159
 
153
160
  **Checkbox/radio:**
161
+
154
162
  ```bash
155
163
  bbx call input.set_checked '{"target":{"elementRef":"el_123"},"checked":true}'
156
164
  ```
157
165
 
158
166
  **Select dropdown:**
167
+
159
168
  ```bash
160
169
  bbx call input.select_option '{"target":{"elementRef":"el_456"},"values":["us"]}'
161
170
  ```
@@ -172,11 +181,13 @@ bbx call input.hover '{"target":{"elementRef":"el_abc123"}}'
172
181
  ```
173
182
 
174
183
  **Hold hover for inspection:** set `duration` (ms) to keep hover active before auto-releasing with `mouseleave`:
184
+
175
185
  ```bash
176
186
  bbx call input.hover '{"target":{"elementRef":"el_abc123"},"duration":2000}'
177
187
  ```
178
188
 
179
189
  Typical workflow - inspect a tooltip:
190
+
180
191
  1. `dom.query` to find the trigger element → `elementRef`
181
192
  2. `input.hover` with `duration: 2000`
182
193
  3. While hover holds, `dom.query` for tooltip content (e.g. `[role="tooltip"]`)
@@ -191,6 +202,7 @@ bbx call input.drag '{"source":{"elementRef":"el_src"},"destination":{"elementRe
191
202
  ```
192
203
 
193
204
  With pixel offsets for precise positioning:
205
+
194
206
  ```bash
195
207
  bbx call input.drag '{"source":{"elementRef":"el_src"},"destination":{"elementRef":"el_dst"},"sourceOffset":{"x":10,"y":10},"destinationOffset":{"x":5,"y":5}}'
196
208
  ```
@@ -198,6 +210,7 @@ bbx call input.drag '{"source":{"elementRef":"el_src"},"destination":{"elementRe
198
210
  Event sequence: `mousedown → dragstart → drag → dragenter → dragover → drop → dragend → mouseup`.
199
211
 
200
212
  Typical workflow - reorder a list:
213
+
201
214
  1. `dom.query` to find draggable items → get source and destination `elementRef` values
202
215
  2. `input.drag` from source to destination
203
216
  3. `dom.wait_for` to confirm the DOM updated
@@ -206,16 +219,21 @@ Typical workflow - reorder a list:
206
219
  ## Finding Elements
207
220
 
208
221
  ### By text content
222
+
209
223
  Find elements matching visible text. Faster than `dom.query` when you know the label:
224
+
210
225
  ```bash
211
226
  bbx find 'Submit Order'
212
227
  bbx call dom.find_by_text '{"text":"Add to Cart","scope":"button","exact":false}'
213
228
  ```
229
+
214
230
  - `scope`: optional CSS selector to narrow search (e.g. `"button"`, `".sidebar"`)
215
231
  - `exact`: `true` for exact match, `false` (default) for substring/case-insensitive
216
232
 
217
233
  ### By ARIA role
234
+
218
235
  Find elements by explicit `role` attribute or implicit HTML role (e.g. `<nav>` → `navigation`):
236
+
219
237
  ```bash
220
238
  bbx find-role button 'Save'
221
239
  bbx call dom.find_by_role '{"role":"navigation"}'
@@ -225,19 +243,23 @@ bbx call dom.find_by_role '{"role":"heading","name":"Dashboard"}'
225
243
  ## Waiting
226
244
 
227
245
  ### Wait for DOM condition
246
+
228
247
  ```bash
229
248
  bbx wait '.success-message' 10000
230
249
  bbx call dom.wait_for '{"selector":".modal","state":"visible","timeoutMs":10000}'
231
250
  bbx call dom.wait_for '{"selector":".spinner","state":"detached","timeoutMs":5000}'
232
251
  ```
252
+
233
253
  - `state`: `attached` (exists in DOM), `detached` (removed), `visible` (non-zero size), `hidden`
234
254
  - Uses MutationObserver + 250 ms polling fallback
235
255
  - Returns `{found, elementRef, duration}` - NOT an error on timeout
236
256
 
237
257
  ### Wait for page load
258
+
238
259
  ```bash
239
260
  bbx call page.wait_for_load_state '{"timeoutMs":10000}'
240
261
  ```
262
+
241
263
  Use after clicking navigation links.
242
264
 
243
265
  ## Interaction Flow
@@ -12,6 +12,7 @@ Use this order for layout or styling issues:
12
12
  6. `patch.rollback`
13
13
 
14
14
  Prefer style patches for:
15
+
15
16
  - overflow fixes
16
17
  - spacing adjustments
17
18
  - flex or grid tuning
@@ -21,6 +22,7 @@ Prefer style patches for:
21
22
  ## DOM patch loop
22
23
 
23
24
  Use DOM patches for:
25
+
24
26
  - text replacement
25
27
  - setting or removing an attribute
26
28
  - toggling a class
@@ -30,6 +32,7 @@ Keep DOM patches minimal and reversible.
30
32
  ## Verification
31
33
 
32
34
  After any patch:
35
+
33
36
  - compare box metrics when geometry matters
34
37
  - compare computed styles when appearance matters
35
38
  - capture a cropped screenshot only when the visual outcome is still unclear
@@ -29,65 +29,65 @@ The table below includes the legacy capability bucket for each method so agents
29
29
 
30
30
  ## All Methods (57)
31
31
 
32
- | # | Method | Tab? | CDP? | Group | Capability | Notes |
33
- |---|--------|------|------|-------|------------|-------|
34
- | 1 | `access.request` | No | - | system | `-` | Request window access; surfaces Enable prompt in extension UI |
35
- | 2 | `tabs.list` | No | - | tabs | `-` | Discover available tabs |
36
- | 3 | `tabs.create` | No | - | tabs | `tabs.manage` | Open a new tab; optional `url` and `active` |
37
- | 4 | `tabs.close` | No | - | tabs | `tabs.manage` | Close a tab by `tabId` |
38
- | 5 | `skill.get_runtime_context` | No | - | system | `-` | Live budget presets + method groups |
39
- | 6 | `setup.get_status` | No | - | system | `-` | Global MCP config + CLI skill install status |
40
- | 7 | `setup.install` | No | - | system | `-` | Install or uninstall MCP/skill integration targets |
41
- | 8 | `health.ping` | No | - | system | `-` | Connectivity check + access routing state |
42
- | 9 | `log.tail` | No | - | system | `-` | Recent bridge logs |
43
- | 10 | `page.get_state` | Yes | - | page | `page.read` | URL, readiness, focus, scroll, viewport |
44
- | 11 | `page.evaluate` | Yes | CDP | page | `page.evaluate` | JS expression in page context; last resort |
45
- | 12 | `page.get_console` | Yes | - | page | `page.read` | Buffered console messages; filter by `level`, `limit` |
46
- | 13 | `page.wait_for_load_state` | Yes | - | wait | `page.read` | Block until tab `complete`; `timeoutMs` capped 30 s |
47
- | 14 | `page.get_storage` | Yes | - | page | `page.read` | `localStorage`/`sessionStorage`; optional `keys` |
48
- | 15 | `page.get_text` | Yes | - | page | `page.read` | Full page text; `textBudget` limits size |
49
- | 16 | `page.get_network` | Yes | - | page | `network.read` | Intercepted fetch/XHR; `limit` entries |
50
- | 17 | `navigation.navigate` | Yes | - | navigate | `navigation.control` | Go to URL; `waitForLoad` default true |
51
- | 18 | `navigation.reload` | Yes | - | navigate | `navigation.control` | Reload; `waitForLoad` default true |
52
- | 19 | `navigation.go_back` | Yes | - | navigate | `navigation.control` | History back |
53
- | 20 | `navigation.go_forward` | Yes | - | navigate | `navigation.control` | History forward |
54
- | 21 | `dom.query` | Yes | - | inspect | `dom.read` | Query subtree with budget constraints |
55
- | 22 | `dom.describe` | Yes | - | inspect | `dom.read` | Single element details via `elementRef` |
56
- | 23 | `dom.get_text` | Yes | - | inspect | `dom.read` | Text content with `textBudget` |
57
- | 24 | `dom.get_attributes` | Yes | - | inspect | `dom.read` | Targeted attribute read |
58
- | 25 | `dom.wait_for` | Yes | - | wait | `dom.read` | Wait for DOM condition; MutationObserver + polling |
59
- | 26 | `dom.find_by_text` | Yes | - | inspect | `dom.read` | Find by visible text; returns `{nodes, count}` |
60
- | 27 | `dom.find_by_role` | Yes | - | inspect | `dom.read` | Find by ARIA role; optional `name` filter |
61
- | 28 | `dom.get_html` | Yes | - | inspect | `dom.read` | `innerHTML`/`outerHTML`; `maxLength` truncation |
62
- | 29 | `dom.get_accessibility_tree` | Yes | CDP | inspect | `dom.read` | Full a11y tree; `maxNodes`/`maxDepth` limits |
63
- | 30 | `layout.get_box_model` | Yes | - | inspect | `layout.read` | Element geometry (no budget needed) |
64
- | 31 | `layout.hit_test` | Yes | - | inspect | `layout.read` | Element at viewport point |
65
- | 32 | `styles.get_computed` | Yes | - | inspect | `styles.read` | Computed CSS; always set `properties` |
66
- | 33 | `styles.get_matched_rules` | Yes | - | inspect | `styles.read` | Matching CSS rules |
67
- | 34 | `viewport.scroll` | Yes | - | navigate | `viewport.control` | Window or element scroll |
68
- | 35 | `viewport.resize` | Yes | CDP | navigate | `viewport.control` | Set viewport via device emulation; `reset: true` |
69
- | 36 | `input.click` | Yes | - | interact | `automation.input` | DOM-level click |
70
- | 37 | `input.focus` | Yes | - | interact | `automation.input` | Focus element |
71
- | 38 | `input.type` | Yes | - | interact | `automation.input` | Type into input/textarea/contenteditable |
72
- | 39 | `input.press_key` | Yes | - | interact | `automation.input` | Single key event |
73
- | 40 | `input.set_checked` | Yes | - | interact | `automation.input` | Checkbox/radio toggle |
74
- | 41 | `input.select_option` | Yes | - | interact | `automation.input` | Native select by value/label/index |
75
- | 42 | `input.hover` | Yes | - | interact | `automation.input` | mouseenter/mouseover/mousemove; optional `duration` |
76
- | 43 | `input.drag` | Yes | - | interact | `automation.input` | Full drag-and-drop event sequence |
77
- | 44 | `input.scroll_into_view` | Yes | - | interact | `automation.input` | Explicitly scroll target into view before inspect/capture |
78
- | 45 | `screenshot.capture_element` | Yes | CDP | capture | `screenshot.partial` | Cropped element screenshot |
79
- | 46 | `screenshot.capture_region` | Yes | CDP | capture | `screenshot.partial` | Cropped viewport region |
80
- | 47 | `screenshot.capture_full_page` | Yes | CDP | capture | `screenshot.partial` | Full document screenshot; use only when page-level context is necessary |
81
- | 48 | `patch.apply_styles` | Yes | - | patch | `patch.styles` | Reversible CSS patch; `verify` returns computed result |
82
- | 49 | `patch.apply_dom` | Yes | - | patch | `patch.dom` | Reversible DOM mutation; `verify` returns result |
83
- | 50 | `patch.list` | Yes | - | patch | `patch.dom` | Active patches |
84
- | 51 | `patch.rollback` | Yes | - | patch | `patch.dom` | Revert one patch |
85
- | 52 | `patch.commit_session_baseline` | Yes | - | patch | `patch.dom` | Accept current state as baseline |
86
- | 53 | `performance.get_metrics` | Yes | CDP | performance | `performance.read` | Chrome performance counters |
87
- | 54 | `cdp.get_document` | Yes | CDP | cdp | `cdp.dom_snapshot` | DevTools document tree |
88
- | 55 | `cdp.get_dom_snapshot` | Yes | CDP | cdp | `cdp.dom_snapshot` | DevTools DOM snapshot |
89
- | 56 | `cdp.get_box_model` | Yes | CDP | cdp | `cdp.box_model` | DevTools-backed element geometry |
90
- | 57 | `cdp.get_computed_styles_for_node` | Yes | CDP | cdp | `cdp.styles` | DevTools-backed computed styles |
32
+ | # | Method | Tab? | CDP? | Group | Capability | Notes |
33
+ | --- | ---------------------------------- | ---- | ---- | ----------- | -------------------- | ----------------------------------------------------------------------- |
34
+ | 1 | `access.request` | No | - | system | `-` | Request window access; surfaces Enable prompt in extension UI |
35
+ | 2 | `tabs.list` | No | - | tabs | `-` | Discover available tabs |
36
+ | 3 | `tabs.create` | No | - | tabs | `tabs.manage` | Open a new tab; optional `url` and `active` |
37
+ | 4 | `tabs.close` | No | - | tabs | `tabs.manage` | Close a tab by `tabId` |
38
+ | 5 | `skill.get_runtime_context` | No | - | system | `-` | Live budget presets + method groups |
39
+ | 6 | `setup.get_status` | No | - | system | `-` | Global MCP config + CLI skill install status |
40
+ | 7 | `setup.install` | No | - | system | `-` | Install or uninstall MCP/skill integration targets |
41
+ | 8 | `health.ping` | No | - | system | `-` | Connectivity check + access routing state |
42
+ | 9 | `log.tail` | No | - | system | `-` | Recent bridge logs |
43
+ | 10 | `page.get_state` | Yes | - | page | `page.read` | URL, readiness, focus, scroll, viewport |
44
+ | 11 | `page.evaluate` | Yes | CDP | page | `page.evaluate` | JS expression in page context; last resort |
45
+ | 12 | `page.get_console` | Yes | - | page | `page.read` | Buffered console messages; filter by `level`, `limit` |
46
+ | 13 | `page.wait_for_load_state` | Yes | - | wait | `page.read` | Block until tab `complete`; `timeoutMs` capped 30 s |
47
+ | 14 | `page.get_storage` | Yes | - | page | `page.read` | `localStorage`/`sessionStorage`; optional `keys` |
48
+ | 15 | `page.get_text` | Yes | - | page | `page.read` | Full page text; `textBudget` limits size |
49
+ | 16 | `page.get_network` | Yes | - | page | `network.read` | Intercepted fetch/XHR; `limit` entries |
50
+ | 17 | `navigation.navigate` | Yes | - | navigate | `navigation.control` | Go to URL; `waitForLoad` default true |
51
+ | 18 | `navigation.reload` | Yes | - | navigate | `navigation.control` | Reload; `waitForLoad` default true |
52
+ | 19 | `navigation.go_back` | Yes | - | navigate | `navigation.control` | History back |
53
+ | 20 | `navigation.go_forward` | Yes | - | navigate | `navigation.control` | History forward |
54
+ | 21 | `dom.query` | Yes | - | inspect | `dom.read` | Query subtree with budget constraints |
55
+ | 22 | `dom.describe` | Yes | - | inspect | `dom.read` | Single element details via `elementRef` |
56
+ | 23 | `dom.get_text` | Yes | - | inspect | `dom.read` | Text content with `textBudget` |
57
+ | 24 | `dom.get_attributes` | Yes | - | inspect | `dom.read` | Targeted attribute read |
58
+ | 25 | `dom.wait_for` | Yes | - | wait | `dom.read` | Wait for DOM condition; MutationObserver + polling |
59
+ | 26 | `dom.find_by_text` | Yes | - | inspect | `dom.read` | Find by visible text; returns `{nodes, count}` |
60
+ | 27 | `dom.find_by_role` | Yes | - | inspect | `dom.read` | Find by ARIA role; optional `name` filter |
61
+ | 28 | `dom.get_html` | Yes | - | inspect | `dom.read` | `innerHTML`/`outerHTML`; `maxLength` truncation |
62
+ | 29 | `dom.get_accessibility_tree` | Yes | CDP | inspect | `dom.read` | Full a11y tree; `maxNodes`/`maxDepth` limits |
63
+ | 30 | `layout.get_box_model` | Yes | - | inspect | `layout.read` | Element geometry (no budget needed) |
64
+ | 31 | `layout.hit_test` | Yes | - | inspect | `layout.read` | Element at viewport point |
65
+ | 32 | `styles.get_computed` | Yes | - | inspect | `styles.read` | Computed CSS; always set `properties` |
66
+ | 33 | `styles.get_matched_rules` | Yes | - | inspect | `styles.read` | Matching CSS rules |
67
+ | 34 | `viewport.scroll` | Yes | - | navigate | `viewport.control` | Window or element scroll |
68
+ | 35 | `viewport.resize` | Yes | CDP | navigate | `viewport.control` | Set viewport via device emulation; `reset: true` |
69
+ | 36 | `input.click` | Yes | - | interact | `automation.input` | DOM-level click |
70
+ | 37 | `input.focus` | Yes | - | interact | `automation.input` | Focus element |
71
+ | 38 | `input.type` | Yes | - | interact | `automation.input` | Type into input/textarea/contenteditable |
72
+ | 39 | `input.press_key` | Yes | - | interact | `automation.input` | Single key event |
73
+ | 40 | `input.set_checked` | Yes | - | interact | `automation.input` | Checkbox/radio toggle |
74
+ | 41 | `input.select_option` | Yes | - | interact | `automation.input` | Native select by value/label/index |
75
+ | 42 | `input.hover` | Yes | - | interact | `automation.input` | mouseenter/mouseover/mousemove; optional `duration` |
76
+ | 43 | `input.drag` | Yes | - | interact | `automation.input` | Full drag-and-drop event sequence |
77
+ | 44 | `input.scroll_into_view` | Yes | - | interact | `automation.input` | Explicitly scroll target into view before inspect/capture |
78
+ | 45 | `screenshot.capture_element` | Yes | CDP | capture | `screenshot.partial` | Cropped element screenshot |
79
+ | 46 | `screenshot.capture_region` | Yes | CDP | capture | `screenshot.partial` | Cropped viewport region |
80
+ | 47 | `screenshot.capture_full_page` | Yes | CDP | capture | `screenshot.partial` | Full document screenshot; use only when page-level context is necessary |
81
+ | 48 | `patch.apply_styles` | Yes | - | patch | `patch.styles` | Reversible CSS patch; `verify` returns computed result |
82
+ | 49 | `patch.apply_dom` | Yes | - | patch | `patch.dom` | Reversible DOM mutation; `verify` returns result |
83
+ | 50 | `patch.list` | Yes | - | patch | `patch.dom` | Active patches |
84
+ | 51 | `patch.rollback` | Yes | - | patch | `patch.dom` | Revert one patch |
85
+ | 52 | `patch.commit_session_baseline` | Yes | - | patch | `patch.dom` | Accept current state as baseline |
86
+ | 53 | `performance.get_metrics` | Yes | CDP | performance | `performance.read` | Chrome performance counters |
87
+ | 54 | `cdp.get_document` | Yes | CDP | cdp | `cdp.dom_snapshot` | DevTools document tree |
88
+ | 55 | `cdp.get_dom_snapshot` | Yes | CDP | cdp | `cdp.dom_snapshot` | DevTools DOM snapshot |
89
+ | 56 | `cdp.get_box_model` | Yes | CDP | cdp | `cdp.box_model` | DevTools-backed element geometry |
90
+ | 57 | `cdp.get_computed_styles_for_node` | Yes | CDP | cdp | `cdp.styles` | DevTools-backed computed styles |
91
91
 
92
92
  ## CLI
93
93
 
@@ -105,19 +105,24 @@ Newer bridge methods such as `input.scroll_into_view` and `screenshot.capture_fu
105
105
  ## Method Details
106
106
 
107
107
  ### access.request
108
+
108
109
  Request Browser Bridge access for the focused browser window. Surfaces an Enable prompt in the extension popup or side panel so the user can grant access. Does not require an existing session.
110
+
109
111
  ```bash
110
112
  bbx access-request
111
113
  bbx call access.request
112
114
  ```
115
+
113
116
  If a tab-bound call returns `ACCESS_DENIED`, it also surfaces the Enable prompt automatically — so explicit `access.request` is optional but useful for proactive setup.
114
117
 
115
118
  If access is already pending for a window, do not call `access.request` again. Ask the user to click `Enable` for the requested window and wait for confirmation before continuing.
116
119
 
117
120
  ### page.evaluate
121
+
118
122
  Run a JS expression in the page context via CDP `Runtime.evaluate`. Expression is evaluated as a statement and the return value is serialized. Supports `awaitPromise` for async expressions.
119
123
 
120
124
  Use only when non-debugger reads are insufficient. Prefer `page.get_storage`, `page.get_text`, `page.get_console`, `page.get_network`, or DOM methods first.
125
+
121
126
  ```bash
122
127
  bbx eval 'document.title'
123
128
  bbx eval 'window.__NEXT_DATA__.props'
@@ -125,22 +130,29 @@ bbx call page.evaluate '{"expression":"await fetch(\"/api/health\").then(r=>r.js
125
130
  ```
126
131
 
127
132
  ### page.get_console
133
+
128
134
  Read buffered console output. The console interceptor is auto-installed on first call. Captures `log`, `warn`, `error`, `info`, `debug` plus uncaught exceptions and unhandled rejections.
135
+
129
136
  ```bash
130
137
  bbx console # all levels
131
138
  bbx console error # errors only
132
139
  bbx call page.get_console '{"level":"error","limit":20,"clear":true}'
133
140
  ```
141
+
134
142
  Responses include `dropped` when older buffered entries were discarded on noisy pages.
135
143
 
136
144
  ### page.wait_for_load_state
145
+
137
146
  Block until the tab reaches `complete` status. Useful after `input.click` on a navigation link.
147
+
138
148
  ```bash
139
149
  bbx call page.wait_for_load_state '{"timeoutMs":10000}'
140
150
  ```
141
151
 
142
152
  ### page.get_storage
153
+
143
154
  Read `localStorage` or `sessionStorage` entries. Values truncated at 500 chars each.
155
+
144
156
  ```bash
145
157
  bbx storage # all localStorage
146
158
  bbx storage session token,user # specific sessionStorage keys
@@ -148,67 +160,87 @@ bbx call page.get_storage '{"type":"session","keys":["token"]}'
148
160
  ```
149
161
 
150
162
  ### dom.query
163
+
151
164
  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.
165
+
152
166
  ```bash
153
167
  bbx dom-query main
154
168
  bbx call dom.query '{"selector":"main","maxNodes":10,"attributeAllowlist":["class","data-testid"]}'
155
169
  ```
170
+
156
171
  If `_registryPruned` is true, refresh previously cached refs before reusing them.
157
172
 
158
173
  ### dom.wait_for
174
+
159
175
  Wait for a DOM condition using MutationObserver + 250 ms polling fallback. Returns `{found, elementRef, duration}`.
176
+
160
177
  - `state`: `attached` (default), `detached`, `visible`, `hidden`
161
178
  - `text`: optional text content filter
162
179
  - `timeoutMs`: 100–30000 (default 5000)
180
+
163
181
  ```bash
164
182
  bbx wait '.toast-success' 5000
165
183
  bbx call dom.wait_for '{"selector":".modal","state":"visible","timeoutMs":10000}'
166
184
  ```
167
185
 
168
186
  ### dom.find_by_text
187
+
169
188
  Find elements matching visible text content. Like Playwright's `getByText`.
189
+
170
190
  ```bash
171
191
  bbx find 'Submit Order'
172
192
  bbx call dom.find_by_text '{"text":"Submit","scope":"button","exact":false}'
173
193
  ```
174
194
 
175
195
  ### dom.find_by_role
196
+
176
197
  Find elements by ARIA role (explicit `role` attribute or implicit from HTML tag). Covers 25+ implicit role mappings.
198
+
177
199
  ```bash
178
200
  bbx find-role button 'Save'
179
201
  bbx call dom.find_by_role '{"role":"navigation"}'
180
202
  ```
181
203
 
182
204
  ### dom.get_html
205
+
183
206
  Get raw HTML of an element. Defaults to `innerHTML`; set `outer: true` for `outerHTML`.
207
+
184
208
  ```bash
185
209
  bbx html el_abc123
186
210
  bbx call dom.get_html '{"elementRef":"el_abc123","outer":true,"maxLength":2000}'
187
211
  ```
188
212
 
189
213
  ### input.hover
214
+
190
215
  Trigger CSS `:hover` state by dispatching `mouseenter`, `mouseover`, `mousemove`. Optional `duration` to hold hover before auto-releasing.
216
+
191
217
  ```bash
192
218
  bbx hover el_abc123
193
219
  bbx call input.hover '{"target":{"elementRef":"el_abc123"},"duration":1000}'
194
220
  ```
195
221
 
196
222
  ### input.drag
223
+
197
224
  Full drag-and-drop sequence: `mousedown → dragstart → drag → dragenter → dragover → drop → dragend → mouseup`. Accepts source target, destination target, and optional pixel offsets.
225
+
198
226
  ```bash
199
227
  bbx call input.drag '{"source":{"elementRef":"el_src"},"destination":{"elementRef":"el_dst"}}'
200
228
  bbx call input.drag '{"source":{"elementRef":"el_src"},"destination":{"elementRef":"el_dst"},"sourceOffset":{"x":10,"y":10}}'
201
229
  ```
202
230
 
203
231
  ### input.scroll_into_view
232
+
204
233
  Explicitly scroll an element into the visible viewport before inspecting, hovering, or capturing it.
234
+
205
235
  ```bash
206
236
  bbx call input.scroll_into_view '{"target":{"elementRef":"el_abc123"}}'
207
237
  bbx call input.scroll_into_view '{"target":{"selector":"[data-testid=\\"checkout-summary\\"]"}}'
208
238
  ```
209
239
 
210
240
  ### tabs.create
241
+
211
242
  Open a new browser tab. Optional `url` (defaults to `about:blank`) and `active` flag (defaults to `true`). Does not require a session.
243
+
212
244
  ```bash
213
245
  bbx tab-create https://example.com
214
246
  bbx call tabs.create '{"url":"https://example.com","active":false}'
@@ -217,20 +249,26 @@ bbx call tabs.create '{"url":"https://example.com","active":false}'
217
249
  The `bbx tab-create` shortcut intentionally covers the common case. Use `bbx call tabs.create ...` when you need advanced fields such as `active:false`.
218
250
 
219
251
  ### setup.get_status
252
+
220
253
  Inspect the host-side Browser Bridge setup. Returns global MCP config status for supported clients and global CLI skill install status for supported targets.
254
+
221
255
  ```bash
222
256
  bbx call setup.get_status
223
257
  ```
224
258
 
225
259
  ### tabs.close
260
+
226
261
  Close a tab by its `tabId`. Does not require a session.
262
+
227
263
  ```bash
228
264
  bbx tab-close 12345
229
265
  bbx call tabs.close '{"tabId":12345}'
230
266
  ```
231
267
 
232
268
  ### page.get_text
269
+
233
270
  Extract the full visible text content of the page (`document.body.innerText`). Truncated to `textBudget` (default 8000 chars). Lighter than `dom.query` on `body` when you only need text.
271
+
234
272
  ```bash
235
273
  bbx page-text
236
274
  bbx page-text 8000
@@ -238,18 +276,23 @@ bbx call page.get_text '{"textBudget":2000}'
238
276
  ```
239
277
 
240
278
  ### page.get_network
279
+
241
280
  Read intercepted fetch/XHR requests. The interceptor is auto-installed on first call (via MAIN world script). Returns `{entries, count}` sorted newest-first.
281
+
242
282
  ```bash
243
283
  bbx network
244
284
  bbx network 50
245
285
  bbx call page.get_network '{"limit":20,"clear":true}'
246
286
  ```
287
+
247
288
  Each entry: `{method, url, status, duration, initiator}`. Responses include `dropped` when older buffered entries were discarded.
248
289
 
249
290
  ### dom.get_accessibility_tree
291
+
250
292
  Retrieve the page's accessibility tree via CDP `Accessibility.getFullAXTree`. Each node is simplified to: `role`, `name`, `description`, `value`, `focused`, `required`, `checked`, `disabled`, `interactive`, `childIds`. Use `maxNodes` and `maxDepth` to control size.
251
293
 
252
294
  This is debugger-backed. Prefer `dom.find_by_role`, `dom.find_by_text`, and targeted `dom.query`/`dom.describe` first.
295
+
253
296
  ```bash
254
297
  bbx a11y-tree
255
298
  bbx a11y-tree 50 3
@@ -257,9 +300,11 @@ bbx call dom.get_accessibility_tree '{"maxNodes":100,"maxDepth":5}'
257
300
  ```
258
301
 
259
302
  ### viewport.resize
303
+
260
304
  Set the browser viewport to specific dimensions using CDP device emulation. Pass `reset: true` to clear the override.
261
305
 
262
306
  Debugger-backed. Use only when an exact viewport override is required for responsive verification.
307
+
263
308
  ```bash
264
309
  bbx resize 375 812
265
310
  bbx call viewport.resize '{"width":1024,"height":768}'
@@ -267,16 +312,20 @@ bbx call viewport.resize '{"reset":true}'
267
312
  ```
268
313
 
269
314
  ### performance.get_metrics
315
+
270
316
  Read Chrome performance counters via CDP `Performance.getMetrics`. Returns a flat `{metrics}` object with keys like `JSHeapUsedSize`, `LayoutCount`, `TaskDuration`, etc.
271
317
 
272
318
  Debugger-backed. Use after lighter reads fail to explain a performance symptom.
319
+
273
320
  ```bash
274
321
  bbx perf
275
322
  bbx call performance.get_metrics
276
323
  ```
277
324
 
278
325
  ### screenshot.capture_full_page
326
+
279
327
  Capture a full-document screenshot beyond the current viewport. Use only when element or tight region captures cannot express the issue. Chrome capture limits still apply on very large pages.
328
+
280
329
  ```bash
281
330
  bbx call screenshot.capture_full_page '{}'
282
331
  ```
@@ -284,21 +333,27 @@ bbx call screenshot.capture_full_page '{}'
284
333
  ## Request Envelope
285
334
 
286
335
  ```json
287
- {"id":"req_1","tab_id":123,"method":"dom.query","params":{},"meta":{"protocol_version":"1.0","token_budget":1200}}
336
+ {
337
+ "id": "req_1",
338
+ "tab_id": 123,
339
+ "method": "dom.query",
340
+ "params": {},
341
+ "meta": { "protocol_version": "1.0", "token_budget": 1200 }
342
+ }
288
343
  ```
289
344
 
290
345
  ## Error Codes
291
346
 
292
- | Code | Action | Recovery |
293
- |------|--------|----------|
294
- | `ACCESS_DENIED` | Turn on Browser Bridge for the target window | `retry: false` |
295
- | `TAB_MISMATCH` | Explicit `tabId` is missing, closed, or outside enabled window | `retry: false`, use `tabs.list` |
296
- | `ELEMENT_STALE` | Re-query DOM for fresh `elementRef` | `retry: false`, use `dom.query` |
297
- | `CONTENT_SCRIPT_UNAVAILABLE` | Page is restricted (chrome://, extensions, etc.) | `retry: false` |
298
- | `NATIVE_HOST_UNAVAILABLE` | Check daemon: `bbx status` | `retry: false` |
299
- | `EXTENSION_DISCONNECTED` | Extension not connected to daemon | `retry: true` after 3 s, check `health.ping` |
300
- | `TIMEOUT` | Wait/evaluate exceeded `timeoutMs` | `retry: true` after 1 s |
301
- | `RATE_LIMITED` | Too many requests | `retry: true` after 2 s |
347
+ | Code | Action | Recovery |
348
+ | ---------------------------- | -------------------------------------------------------------- | -------------------------------------------- |
349
+ | `ACCESS_DENIED` | Turn on Browser Bridge for the target window | `retry: false` |
350
+ | `TAB_MISMATCH` | Explicit `tabId` is missing, closed, or outside enabled window | `retry: false`, use `tabs.list` |
351
+ | `ELEMENT_STALE` | Re-query DOM for fresh `elementRef` | `retry: false`, use `dom.query` |
352
+ | `CONTENT_SCRIPT_UNAVAILABLE` | Page is restricted (chrome://, extensions, etc.) | `retry: false` |
353
+ | `NATIVE_HOST_UNAVAILABLE` | Check daemon: `bbx status` | `retry: false` |
354
+ | `EXTENSION_DISCONNECTED` | Extension not connected to daemon | `retry: true` after 3 s, check `health.ping` |
355
+ | `TIMEOUT` | Wait/evaluate exceeded `timeoutMs` | `retry: true` after 1 s |
356
+ | `RATE_LIMITED` | Too many requests | `retry: true` after 2 s |
302
357
 
303
358
  Timeout on content-script request → use narrower `dom.query` or CDP fallback.
304
359
  Timeout on navigation → increase `timeoutMs`, set `waitForLoad:false`, or check `page.get_state`.