@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
@@ -23,7 +23,8 @@
23
23
  * @type {Readonly<Record<import('./types.js').BridgeMethod, string>>}
24
24
  */
25
25
  const BRIDGE_METHOD_DESCRIPTIONS = Object.freeze({
26
- 'access.request': 'Request Browser Bridge access for the focused window. Do not repeat while access is already pending.',
26
+ 'access.request':
27
+ 'Request Browser Bridge access for the focused window. Do not repeat while access is already pending.',
27
28
  'tabs.list': 'List tabs in the enabled window.',
28
29
  'tabs.create': 'Create a new tab in the enabled window.',
29
30
  'tabs.close': 'Close a tab in the enabled window.',
@@ -79,7 +80,7 @@ const BRIDGE_METHOD_DESCRIPTIONS = Object.freeze({
79
80
  'cdp.get_computed_styles_for_node': 'Read CDP computed styles for a node.',
80
81
  'performance.get_metrics': 'Read browser performance metrics.',
81
82
  'log.tail': 'Tail recent bridge log entries.',
82
- 'health.ping': 'Check daemon, extension, and access-routing health.'
83
+ 'health.ping': 'Check daemon, extension, and access-routing health.',
83
84
  });
84
85
 
85
86
  /**
@@ -105,9 +106,21 @@ function createRegistryEntry(method, group, tab, params, complexity = 'low') {
105
106
  export const BRIDGE_METHOD_REGISTRY = Object.freeze({
106
107
  // system — trivial
107
108
  'access.request': createRegistryEntry('access.request', 'system', false, [], 'trivial'),
108
- 'skill.get_runtime_context': createRegistryEntry('skill.get_runtime_context', 'system', false, [], 'trivial'),
109
+ 'skill.get_runtime_context': createRegistryEntry(
110
+ 'skill.get_runtime_context',
111
+ 'system',
112
+ false,
113
+ [],
114
+ 'trivial'
115
+ ),
109
116
  'setup.get_status': createRegistryEntry('setup.get_status', 'system', false, [], 'trivial'),
110
- 'setup.install': createRegistryEntry('setup.install', 'system', false, ['kind', 'target'], 'trivial'),
117
+ 'setup.install': createRegistryEntry(
118
+ 'setup.install',
119
+ 'system',
120
+ false,
121
+ ['kind', 'target'],
122
+ 'trivial'
123
+ ),
111
124
  'log.tail': createRegistryEntry('log.tail', 'system', false, [], 'trivial'),
112
125
  'health.ping': createRegistryEntry('health.ping', 'system', false, [], 'trivial'),
113
126
  // tabs — trivial
@@ -117,66 +130,308 @@ export const BRIDGE_METHOD_REGISTRY = Object.freeze({
117
130
  // page — low (basic reads), moderate (evaluate, debugger-backed)
118
131
  'page.get_state': createRegistryEntry('page.get_state', 'page', true, [], 'low'),
119
132
  'page.evaluate': {
120
- ...createRegistryEntry('page.evaluate', 'page', true, ['expression', 'awaitPromise', 'timeoutMs', 'returnByValue'], 'moderate')
133
+ ...createRegistryEntry(
134
+ 'page.evaluate',
135
+ 'page',
136
+ true,
137
+ ['expression', 'awaitPromise', 'timeoutMs', 'returnByValue'],
138
+ 'moderate'
139
+ ),
121
140
  },
122
- 'page.get_console': createRegistryEntry('page.get_console', 'page', true, ['level', 'clear', 'limit'], 'low'),
123
- 'page.wait_for_load_state': createRegistryEntry('page.wait_for_load_state', 'wait', true, ['timeoutMs'], 'low'),
124
- 'page.get_storage': createRegistryEntry('page.get_storage', 'page', true, ['type', 'keys'], 'low'),
141
+ 'page.get_console': createRegistryEntry(
142
+ 'page.get_console',
143
+ 'page',
144
+ true,
145
+ ['level', 'clear', 'limit'],
146
+ 'low'
147
+ ),
148
+ 'page.wait_for_load_state': createRegistryEntry(
149
+ 'page.wait_for_load_state',
150
+ 'wait',
151
+ true,
152
+ ['timeoutMs'],
153
+ 'low'
154
+ ),
155
+ 'page.get_storage': createRegistryEntry(
156
+ 'page.get_storage',
157
+ 'page',
158
+ true,
159
+ ['type', 'keys'],
160
+ 'low'
161
+ ),
125
162
  'page.get_text': createRegistryEntry('page.get_text', 'page', true, ['textBudget'], 'low'),
126
- 'page.get_network': createRegistryEntry('page.get_network', 'page', true, ['clear', 'limit', 'urlPattern'], 'low'),
163
+ 'page.get_network': createRegistryEntry(
164
+ 'page.get_network',
165
+ 'page',
166
+ true,
167
+ ['clear', 'limit', 'urlPattern'],
168
+ 'low'
169
+ ),
127
170
  // navigation — low
128
- 'navigation.navigate': createRegistryEntry('navigation.navigate', 'navigate', true, ['url', 'waitForLoad', 'timeoutMs'], 'low'),
129
- 'navigation.reload': createRegistryEntry('navigation.reload', 'navigate', true, ['waitForLoad', 'timeoutMs'], 'low'),
130
- 'navigation.go_back': createRegistryEntry('navigation.go_back', 'navigate', true, ['waitForLoad', 'timeoutMs'], 'low'),
131
- 'navigation.go_forward': createRegistryEntry('navigation.go_forward', 'navigate', true, ['waitForLoad', 'timeoutMs'], 'low'),
171
+ 'navigation.navigate': createRegistryEntry(
172
+ 'navigation.navigate',
173
+ 'navigate',
174
+ true,
175
+ ['url', 'waitForLoad', 'timeoutMs'],
176
+ 'low'
177
+ ),
178
+ 'navigation.reload': createRegistryEntry(
179
+ 'navigation.reload',
180
+ 'navigate',
181
+ true,
182
+ ['waitForLoad', 'timeoutMs'],
183
+ 'low'
184
+ ),
185
+ 'navigation.go_back': createRegistryEntry(
186
+ 'navigation.go_back',
187
+ 'navigate',
188
+ true,
189
+ ['waitForLoad', 'timeoutMs'],
190
+ 'low'
191
+ ),
192
+ 'navigation.go_forward': createRegistryEntry(
193
+ 'navigation.go_forward',
194
+ 'navigate',
195
+ true,
196
+ ['waitForLoad', 'timeoutMs'],
197
+ 'low'
198
+ ),
132
199
  // dom — low (reads), moderate (accessibility tree)
133
200
  'dom.query': {
134
- ...createRegistryEntry('dom.query', 'inspect', true, ['selector', 'withinRef', 'maxNodes', 'maxDepth', 'textBudget', 'includeBbox', 'attributeAllowlist'], 'low')
201
+ ...createRegistryEntry(
202
+ 'dom.query',
203
+ 'inspect',
204
+ true,
205
+ [
206
+ 'selector',
207
+ 'withinRef',
208
+ 'maxNodes',
209
+ 'maxDepth',
210
+ 'textBudget',
211
+ 'includeBbox',
212
+ 'attributeAllowlist',
213
+ ],
214
+ 'low'
215
+ ),
135
216
  },
136
217
  'dom.describe': createRegistryEntry('dom.describe', 'inspect', true, ['elementRef'], 'low'),
137
- 'dom.get_text': createRegistryEntry('dom.get_text', 'inspect', true, ['elementRef', 'textBudget'], 'low'),
138
- 'dom.get_attributes': createRegistryEntry('dom.get_attributes', 'inspect', true, ['elementRef', 'attributes'], 'low'),
139
- 'dom.wait_for': createRegistryEntry('dom.wait_for', 'wait', true, ['selector', 'text', 'state', 'timeoutMs'], 'low'),
140
- 'dom.find_by_text': createRegistryEntry('dom.find_by_text', 'inspect', true, ['text', 'exact', 'selector', 'maxResults'], 'low'),
141
- 'dom.find_by_role': createRegistryEntry('dom.find_by_role', 'inspect', true, ['role', 'name', 'selector', 'maxResults'], 'low'),
142
- 'dom.get_html': createRegistryEntry('dom.get_html', 'inspect', true, ['elementRef', 'outer', 'maxLength'], 'low'),
143
- 'dom.get_accessibility_tree': createRegistryEntry('dom.get_accessibility_tree', 'inspect', true, ['maxNodes', 'maxDepth'], 'moderate'),
218
+ 'dom.get_text': createRegistryEntry(
219
+ 'dom.get_text',
220
+ 'inspect',
221
+ true,
222
+ ['elementRef', 'textBudget'],
223
+ 'low'
224
+ ),
225
+ 'dom.get_attributes': createRegistryEntry(
226
+ 'dom.get_attributes',
227
+ 'inspect',
228
+ true,
229
+ ['elementRef', 'attributes'],
230
+ 'low'
231
+ ),
232
+ 'dom.wait_for': createRegistryEntry(
233
+ 'dom.wait_for',
234
+ 'wait',
235
+ true,
236
+ ['selector', 'text', 'state', 'timeoutMs'],
237
+ 'low'
238
+ ),
239
+ 'dom.find_by_text': createRegistryEntry(
240
+ 'dom.find_by_text',
241
+ 'inspect',
242
+ true,
243
+ ['text', 'exact', 'selector', 'maxResults'],
244
+ 'low'
245
+ ),
246
+ 'dom.find_by_role': createRegistryEntry(
247
+ 'dom.find_by_role',
248
+ 'inspect',
249
+ true,
250
+ ['role', 'name', 'selector', 'maxResults'],
251
+ 'low'
252
+ ),
253
+ 'dom.get_html': createRegistryEntry(
254
+ 'dom.get_html',
255
+ 'inspect',
256
+ true,
257
+ ['elementRef', 'outer', 'maxLength'],
258
+ 'low'
259
+ ),
260
+ 'dom.get_accessibility_tree': createRegistryEntry(
261
+ 'dom.get_accessibility_tree',
262
+ 'inspect',
263
+ true,
264
+ ['maxNodes', 'maxDepth'],
265
+ 'moderate'
266
+ ),
144
267
  // layout — low
145
- 'layout.get_box_model': createRegistryEntry('layout.get_box_model', 'inspect', true, ['elementRef'], 'low'),
268
+ 'layout.get_box_model': createRegistryEntry(
269
+ 'layout.get_box_model',
270
+ 'inspect',
271
+ true,
272
+ ['elementRef'],
273
+ 'low'
274
+ ),
146
275
  'layout.hit_test': createRegistryEntry('layout.hit_test', 'inspect', true, ['x', 'y'], 'low'),
147
276
  // styles — low (computed), moderate (matched rules)
148
- 'styles.get_computed': createRegistryEntry('styles.get_computed', 'inspect', true, ['elementRef', 'properties'], 'low'),
149
- 'styles.get_matched_rules': createRegistryEntry('styles.get_matched_rules', 'inspect', true, ['elementRef'], 'moderate'),
277
+ 'styles.get_computed': createRegistryEntry(
278
+ 'styles.get_computed',
279
+ 'inspect',
280
+ true,
281
+ ['elementRef', 'properties'],
282
+ 'low'
283
+ ),
284
+ 'styles.get_matched_rules': createRegistryEntry(
285
+ 'styles.get_matched_rules',
286
+ 'inspect',
287
+ true,
288
+ ['elementRef'],
289
+ 'moderate'
290
+ ),
150
291
  // viewport — low (scroll), moderate (resize, debugger-backed)
151
- 'viewport.scroll': createRegistryEntry('viewport.scroll', 'navigate', true, ['target', 'top', 'left', 'behavior', 'relative'], 'low'),
152
- 'viewport.resize': createRegistryEntry('viewport.resize', 'navigate', true, ['width', 'height', 'deviceScaleFactor', 'reset'], 'moderate'),
292
+ 'viewport.scroll': createRegistryEntry(
293
+ 'viewport.scroll',
294
+ 'navigate',
295
+ true,
296
+ ['target', 'top', 'left', 'behavior', 'relative'],
297
+ 'low'
298
+ ),
299
+ 'viewport.resize': createRegistryEntry(
300
+ 'viewport.resize',
301
+ 'navigate',
302
+ true,
303
+ ['width', 'height', 'deviceScaleFactor', 'reset'],
304
+ 'moderate'
305
+ ),
153
306
  // input — low (simple), moderate (drag)
154
- 'input.click': createRegistryEntry('input.click', 'interact', true, ['target', 'button', 'clickCount', 'modifiers'], 'low'),
307
+ 'input.click': createRegistryEntry(
308
+ 'input.click',
309
+ 'interact',
310
+ true,
311
+ ['target', 'button', 'clickCount', 'modifiers'],
312
+ 'low'
313
+ ),
155
314
  'input.focus': createRegistryEntry('input.focus', 'interact', true, ['target'], 'low'),
156
- 'input.type': createRegistryEntry('input.type', 'interact', true, ['target', 'text', 'clear', 'submit', 'modifiers'], 'low'),
157
- 'input.press_key': createRegistryEntry('input.press_key', 'interact', true, ['target', 'key', 'modifiers'], 'low'),
158
- 'input.set_checked': createRegistryEntry('input.set_checked', 'interact', true, ['target', 'checked'], 'low'),
159
- 'input.select_option': createRegistryEntry('input.select_option', 'interact', true, ['target', 'values', 'labels', 'indexes'], 'low'),
160
- 'input.hover': createRegistryEntry('input.hover', 'interact', true, ['target', 'duration', 'modifiers'], 'low'),
161
- 'input.drag': createRegistryEntry('input.drag', 'interact', true, ['source', 'destination', 'offsetX', 'offsetY'], 'moderate'),
162
- 'input.scroll_into_view': createRegistryEntry('input.scroll_into_view', 'interact', true, ['target'], 'low'),
315
+ 'input.type': createRegistryEntry(
316
+ 'input.type',
317
+ 'interact',
318
+ true,
319
+ ['target', 'text', 'clear', 'submit', 'modifiers'],
320
+ 'low'
321
+ ),
322
+ 'input.press_key': createRegistryEntry(
323
+ 'input.press_key',
324
+ 'interact',
325
+ true,
326
+ ['target', 'key', 'modifiers'],
327
+ 'low'
328
+ ),
329
+ 'input.set_checked': createRegistryEntry(
330
+ 'input.set_checked',
331
+ 'interact',
332
+ true,
333
+ ['target', 'checked'],
334
+ 'low'
335
+ ),
336
+ 'input.select_option': createRegistryEntry(
337
+ 'input.select_option',
338
+ 'interact',
339
+ true,
340
+ ['target', 'values', 'labels', 'indexes'],
341
+ 'low'
342
+ ),
343
+ 'input.hover': createRegistryEntry(
344
+ 'input.hover',
345
+ 'interact',
346
+ true,
347
+ ['target', 'duration', 'modifiers'],
348
+ 'low'
349
+ ),
350
+ 'input.drag': createRegistryEntry(
351
+ 'input.drag',
352
+ 'interact',
353
+ true,
354
+ ['source', 'destination', 'offsetX', 'offsetY'],
355
+ 'moderate'
356
+ ),
357
+ 'input.scroll_into_view': createRegistryEntry(
358
+ 'input.scroll_into_view',
359
+ 'interact',
360
+ true,
361
+ ['target'],
362
+ 'low'
363
+ ),
163
364
  // capture — high (screenshots, CDP)
164
- 'screenshot.capture_region': createRegistryEntry('screenshot.capture_region', 'capture', true, ['x', 'y', 'width', 'height'], 'high'),
165
- 'screenshot.capture_element': createRegistryEntry('screenshot.capture_element', 'capture', true, ['elementRef'], 'high'),
166
- 'screenshot.capture_full_page': createRegistryEntry('screenshot.capture_full_page', 'capture', true, [], 'high'),
365
+ 'screenshot.capture_region': createRegistryEntry(
366
+ 'screenshot.capture_region',
367
+ 'capture',
368
+ true,
369
+ ['x', 'y', 'width', 'height'],
370
+ 'high'
371
+ ),
372
+ 'screenshot.capture_element': createRegistryEntry(
373
+ 'screenshot.capture_element',
374
+ 'capture',
375
+ true,
376
+ ['elementRef'],
377
+ 'high'
378
+ ),
379
+ 'screenshot.capture_full_page': createRegistryEntry(
380
+ 'screenshot.capture_full_page',
381
+ 'capture',
382
+ true,
383
+ [],
384
+ 'high'
385
+ ),
167
386
  // patch — moderate (side effects)
168
- 'patch.apply_styles': createRegistryEntry('patch.apply_styles', 'patch', true, ['target', 'declarations', 'important', 'patchId', 'verify'], 'moderate'),
169
- 'patch.apply_dom': createRegistryEntry('patch.apply_dom', 'patch', true, ['target', 'operation', 'name', 'value', 'patchId', 'verify'], 'moderate'),
387
+ 'patch.apply_styles': createRegistryEntry(
388
+ 'patch.apply_styles',
389
+ 'patch',
390
+ true,
391
+ ['target', 'declarations', 'important', 'patchId', 'verify'],
392
+ 'moderate'
393
+ ),
394
+ 'patch.apply_dom': createRegistryEntry(
395
+ 'patch.apply_dom',
396
+ 'patch',
397
+ true,
398
+ ['target', 'operation', 'name', 'value', 'patchId', 'verify'],
399
+ 'moderate'
400
+ ),
170
401
  'patch.list': createRegistryEntry('patch.list', 'patch', true, [], 'low'),
171
402
  'patch.rollback': createRegistryEntry('patch.rollback', 'patch', true, ['patchId'], 'low'),
172
- 'patch.commit_session_baseline': createRegistryEntry('patch.commit_session_baseline', 'patch', true, [], 'low'),
403
+ 'patch.commit_session_baseline': createRegistryEntry(
404
+ 'patch.commit_session_baseline',
405
+ 'patch',
406
+ true,
407
+ [],
408
+ 'low'
409
+ ),
173
410
  // cdp — high (raw protocol, large payloads)
174
411
  'cdp.get_document': createRegistryEntry('cdp.get_document', 'cdp', true, [], 'high'),
175
412
  'cdp.get_dom_snapshot': createRegistryEntry('cdp.get_dom_snapshot', 'cdp', true, [], 'high'),
176
- 'cdp.get_box_model': createRegistryEntry('cdp.get_box_model', 'cdp', true, ['elementRef'], 'high'),
177
- 'cdp.get_computed_styles_for_node': createRegistryEntry('cdp.get_computed_styles_for_node', 'cdp', true, ['elementRef'], 'high'),
413
+ 'cdp.get_box_model': createRegistryEntry(
414
+ 'cdp.get_box_model',
415
+ 'cdp',
416
+ true,
417
+ ['elementRef'],
418
+ 'high'
419
+ ),
420
+ 'cdp.get_computed_styles_for_node': createRegistryEntry(
421
+ 'cdp.get_computed_styles_for_node',
422
+ 'cdp',
423
+ true,
424
+ ['elementRef'],
425
+ 'high'
426
+ ),
178
427
  // performance — moderate (debugger-backed)
179
- 'performance.get_metrics': createRegistryEntry('performance.get_metrics', 'performance', true, [], 'moderate'),
428
+ 'performance.get_metrics': createRegistryEntry(
429
+ 'performance.get_metrics',
430
+ 'performance',
431
+ true,
432
+ [],
433
+ 'moderate'
434
+ ),
180
435
  });
181
436
 
182
437
  /** @type {ReadonlyArray<import('./types.js').BridgeMethod>} */
@@ -229,7 +484,7 @@ const COMPLEXITY_LEVELS = ['trivial', 'low', 'moderate', 'high'];
229
484
  */
230
485
  export function getMethodsByMaxComplexity(maxComplexity) {
231
486
  const maxIndex = COMPLEXITY_LEVELS.indexOf(maxComplexity);
232
- return BRIDGE_METHODS.filter(m =>
233
- COMPLEXITY_LEVELS.indexOf(BRIDGE_METHOD_REGISTRY[m].complexity) <= maxIndex
487
+ return BRIDGE_METHODS.filter(
488
+ (m) => COMPLEXITY_LEVELS.indexOf(BRIDGE_METHOD_REGISTRY[m].complexity) <= maxIndex
234
489
  );
235
490
  }