@browserbridge/bbx 1.0.1 → 1.1.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/README.md +4 -4
- package/package.json +11 -13
- package/packages/agent-client/src/cli-helpers.js +33 -0
- package/packages/agent-client/src/cli.js +116 -41
- package/packages/agent-client/src/client.js +29 -4
- package/packages/agent-client/src/command-registry.js +3 -0
- package/packages/agent-client/src/detect.js +159 -48
- package/packages/agent-client/src/install.js +24 -1
- package/packages/agent-client/src/mcp-config.js +29 -10
- package/packages/agent-client/src/setup-status.js +12 -4
- package/packages/mcp-server/src/bin.js +57 -5
- package/packages/mcp-server/src/handlers.js +28 -7
- package/packages/mcp-server/src/server.js +12 -2
- package/packages/native-host/bin/bridge-daemon.js +33 -4
- package/packages/native-host/bin/install-manifest.js +24 -2
- package/packages/native-host/src/config.js +131 -6
- package/packages/native-host/src/daemon-process.js +396 -0
- package/packages/native-host/src/daemon.js +217 -68
- package/packages/native-host/src/framing.js +131 -11
- package/packages/native-host/src/install-manifest.js +121 -7
- package/packages/native-host/src/native-host.js +110 -73
- package/packages/protocol/src/capabilities.js +3 -0
- package/packages/protocol/src/defaults.js +1 -0
- package/packages/protocol/src/errors.js +4 -0
- package/packages/protocol/src/payload-cost.js +19 -6
- package/packages/protocol/src/protocol.js +143 -7
- package/packages/protocol/src/registry.js +11 -0
- package/packages/protocol/src/summary.js +18 -10
- package/packages/protocol/src/types.js +28 -3
- package/skills/browser-bridge/SKILL.md +2 -1
- package/skills/browser-bridge/references/interaction.md +1 -0
- package/skills/browser-bridge/references/protocol.md +2 -1
- package/CHANGELOG.md +0 -55
- package/assets/banner.jpg +0 -0
- package/assets/logo.png +0 -0
- package/assets/logo.svg +0 -65
- package/docs/api-reference.md +0 -157
- package/docs/cli-guide.md +0 -128
- package/docs/index.md +0 -25
- package/docs/manual-setup.md +0 -140
- package/docs/mcp-vs-cli.md +0 -258
- package/docs/publishing.md +0 -112
- package/docs/quickstart.md +0 -104
- package/docs/troubleshooting.md +0 -59
- package/docs/unpacked-extension.md +0 -72
- package/docs/usage-scenarios.md +0 -136
- package/manifest.json +0 -38
- package/packages/extension/assets/icon-128.png +0 -0
- package/packages/extension/assets/icon-16.png +0 -0
- package/packages/extension/assets/icon-32.png +0 -0
- package/packages/extension/assets/icon-48.png +0 -0
- package/packages/extension/src/background-helpers.js +0 -474
- package/packages/extension/src/background-routing.js +0 -89
- package/packages/extension/src/background.js +0 -3490
- package/packages/extension/src/content-script-helpers.js +0 -282
- package/packages/extension/src/content-script.js +0 -2043
- package/packages/extension/src/debugger-coordinator.js +0 -188
- package/packages/extension/src/sidepanel-helpers.js +0 -104
- package/packages/extension/ui/popup.html +0 -35
- package/packages/extension/ui/popup.js +0 -298
- package/packages/extension/ui/sidepanel.html +0 -102
- package/packages/extension/ui/sidepanel.js +0 -1771
- package/packages/extension/ui/ui.css +0 -1160
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
DEFAULT_WAIT_TIMEOUT_MS,
|
|
20
20
|
} from './defaults.js';
|
|
21
21
|
import { BridgeError, ERROR_CODES, getErrorRecovery } from './errors.js';
|
|
22
|
-
import { BRIDGE_METHODS, createBridgeMethodGroups } from './registry.js';
|
|
22
|
+
import { BRIDGE_METHODS, METHOD_SET, createBridgeMethodGroups } from './registry.js';
|
|
23
23
|
|
|
24
24
|
/** @typedef {import('./types.js').AccessibilityTreeParams} AccessibilityTreeParams */
|
|
25
25
|
/** @typedef {import('./types.js').BridgeFailureResponse} BridgeFailureResponse */
|
|
@@ -28,6 +28,7 @@ import { BRIDGE_METHODS, createBridgeMethodGroups } from './registry.js';
|
|
|
28
28
|
/** @typedef {import('./types.js').BridgeRequest} BridgeRequest */
|
|
29
29
|
/** @typedef {import('./types.js').BridgeSuccessResponse} BridgeSuccessResponse */
|
|
30
30
|
/** @typedef {import('./types.js').CheckedActionParams} CheckedActionParams */
|
|
31
|
+
/** @typedef {import('./types.js').CdpDispatchKeyEventParams} CdpDispatchKeyEventParams */
|
|
31
32
|
/** @typedef {import('./types.js').ConsoleParams} ConsoleParams */
|
|
32
33
|
/** @typedef {import('./types.js').DomQueryParams} DomQueryParams */
|
|
33
34
|
/** @typedef {import('./types.js').DragParams} DragParams */
|
|
@@ -41,6 +42,7 @@ import { BRIDGE_METHODS, createBridgeMethodGroups } from './registry.js';
|
|
|
41
42
|
/** @typedef {import('./types.js').NetworkParams} NetworkParams */
|
|
42
43
|
/** @typedef {import('./types.js').NormalizedAccessibilityTreeParams} NormalizedAccessibilityTreeParams */
|
|
43
44
|
/** @typedef {import('./types.js').NormalizedCheckedAction} NormalizedCheckedAction */
|
|
45
|
+
/** @typedef {import('./types.js').NormalizedCdpDispatchKeyEventParams} NormalizedCdpDispatchKeyEventParams */
|
|
44
46
|
/** @typedef {import('./types.js').NormalizedConsoleParams} NormalizedConsoleParams */
|
|
45
47
|
/** @typedef {import('./types.js').NormalizedDomQuery} NormalizedDomQuery */
|
|
46
48
|
/** @typedef {import('./types.js').NormalizedDragParams} NormalizedDragParams */
|
|
@@ -182,7 +184,7 @@ export function validateBridgeRequest(request) {
|
|
|
182
184
|
|
|
183
185
|
if (
|
|
184
186
|
typeof candidate.method !== 'string' ||
|
|
185
|
-
!
|
|
187
|
+
!METHOD_SET.has(/** @type {BridgeMethod} */ (candidate.method))
|
|
186
188
|
) {
|
|
187
189
|
throw new BridgeError(
|
|
188
190
|
ERROR_CODES.INVALID_REQUEST,
|
|
@@ -190,6 +192,13 @@ export function validateBridgeRequest(request) {
|
|
|
190
192
|
);
|
|
191
193
|
}
|
|
192
194
|
|
|
195
|
+
if (
|
|
196
|
+
candidate.meta != null &&
|
|
197
|
+
(typeof candidate.meta !== 'object' || Array.isArray(candidate.meta))
|
|
198
|
+
) {
|
|
199
|
+
throw new BridgeError(ERROR_CODES.INVALID_REQUEST, 'Request meta must be an object.');
|
|
200
|
+
}
|
|
201
|
+
|
|
193
202
|
const meta =
|
|
194
203
|
candidate.meta && typeof candidate.meta === 'object'
|
|
195
204
|
? /** @type {Record<string, unknown>} */ (candidate.meta)
|
|
@@ -202,14 +211,17 @@ export function validateBridgeRequest(request) {
|
|
|
202
211
|
}
|
|
203
212
|
const parsedTabId = Number(candidate.tab_id);
|
|
204
213
|
|
|
214
|
+
const method = /** @type {BridgeMethod} */ (candidate.method);
|
|
215
|
+
const params =
|
|
216
|
+
candidate.params && typeof candidate.params === 'object'
|
|
217
|
+
? /** @type {Record<string, unknown>} */ (candidate.params)
|
|
218
|
+
: {};
|
|
219
|
+
|
|
205
220
|
return {
|
|
206
221
|
id: candidate.id,
|
|
207
|
-
method
|
|
222
|
+
method,
|
|
208
223
|
tab_id: Number.isFinite(parsedTabId) && parsedTabId > 0 ? parsedTabId : null,
|
|
209
|
-
params:
|
|
210
|
-
candidate.params && typeof candidate.params === 'object'
|
|
211
|
-
? /** @type {Record<string, unknown>} */ (candidate.params)
|
|
212
|
-
: {},
|
|
224
|
+
params: normalizeRequestParams(method, params),
|
|
213
225
|
meta: {
|
|
214
226
|
...meta,
|
|
215
227
|
protocol_version:
|
|
@@ -220,6 +232,82 @@ export function validateBridgeRequest(request) {
|
|
|
220
232
|
};
|
|
221
233
|
}
|
|
222
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Normalize request params early so malformed payloads fail at the shared
|
|
237
|
+
* protocol boundary before daemon or extension dispatch.
|
|
238
|
+
*
|
|
239
|
+
* @param {BridgeMethod} method
|
|
240
|
+
* @param {Record<string, unknown>} params
|
|
241
|
+
* @returns {Record<string, unknown>}
|
|
242
|
+
*/
|
|
243
|
+
function normalizeRequestParams(method, params) {
|
|
244
|
+
switch (method) {
|
|
245
|
+
case 'dom.query':
|
|
246
|
+
return normalizeDomQuery(params);
|
|
247
|
+
case 'page.evaluate':
|
|
248
|
+
return normalizeEvaluateParams(params);
|
|
249
|
+
case 'page.get_console':
|
|
250
|
+
return normalizeConsoleParams(params);
|
|
251
|
+
case 'page.wait_for_load_state':
|
|
252
|
+
return normalizeWaitForLoadStateParams(params);
|
|
253
|
+
case 'page.get_storage':
|
|
254
|
+
return normalizeStorageParams(params);
|
|
255
|
+
case 'page.get_text':
|
|
256
|
+
return normalizePageTextParams(params);
|
|
257
|
+
case 'page.get_network':
|
|
258
|
+
return normalizeNetworkParams(params);
|
|
259
|
+
case 'navigation.navigate':
|
|
260
|
+
case 'navigation.reload':
|
|
261
|
+
case 'navigation.go_back':
|
|
262
|
+
case 'navigation.go_forward':
|
|
263
|
+
return normalizeNavigationAction(params);
|
|
264
|
+
case 'dom.wait_for':
|
|
265
|
+
return normalizeWaitForParams(params);
|
|
266
|
+
case 'dom.find_by_text':
|
|
267
|
+
return normalizeFindByTextParams(params);
|
|
268
|
+
case 'dom.find_by_role':
|
|
269
|
+
return normalizeFindByRoleParams(params);
|
|
270
|
+
case 'dom.get_html':
|
|
271
|
+
return normalizeGetHtmlParams(params);
|
|
272
|
+
case 'dom.get_accessibility_tree':
|
|
273
|
+
return normalizeAccessibilityTreeParams(params);
|
|
274
|
+
case 'styles.get_computed':
|
|
275
|
+
case 'styles.get_matched_rules':
|
|
276
|
+
return normalizeStyleQuery(params);
|
|
277
|
+
case 'viewport.scroll':
|
|
278
|
+
return normalizeViewportAction(params);
|
|
279
|
+
case 'viewport.resize':
|
|
280
|
+
return normalizeViewportResizeParams(params);
|
|
281
|
+
case 'input.click':
|
|
282
|
+
case 'input.focus':
|
|
283
|
+
case 'input.type':
|
|
284
|
+
case 'input.press_key':
|
|
285
|
+
return normalizeInputAction(params);
|
|
286
|
+
case 'cdp.dispatch_key_event':
|
|
287
|
+
return normalizeCdpDispatchKeyEventParams(params);
|
|
288
|
+
case 'input.set_checked':
|
|
289
|
+
return normalizeCheckedAction(params);
|
|
290
|
+
case 'input.select_option':
|
|
291
|
+
return normalizeSelectAction(params);
|
|
292
|
+
case 'input.hover':
|
|
293
|
+
return normalizeHoverParams(params);
|
|
294
|
+
case 'input.drag':
|
|
295
|
+
return normalizeDragParams(params);
|
|
296
|
+
case 'patch.apply_styles':
|
|
297
|
+
case 'patch.apply_dom':
|
|
298
|
+
case 'patch.list':
|
|
299
|
+
case 'patch.rollback':
|
|
300
|
+
case 'patch.commit_session_baseline':
|
|
301
|
+
return normalizePatchOperation(params);
|
|
302
|
+
case 'tabs.create':
|
|
303
|
+
return normalizeTabCreateParams(params);
|
|
304
|
+
case 'tabs.close':
|
|
305
|
+
return normalizeTabCloseParams(params);
|
|
306
|
+
default:
|
|
307
|
+
return params;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
223
311
|
/**
|
|
224
312
|
* @param {DomQueryParams} [params={}]
|
|
225
313
|
* @returns {NormalizedDomQuery}
|
|
@@ -293,6 +381,54 @@ export function normalizeInputAction(params = {}) {
|
|
|
293
381
|
};
|
|
294
382
|
}
|
|
295
383
|
|
|
384
|
+
/**
|
|
385
|
+
* @param {CdpDispatchKeyEventParams} [params={}]
|
|
386
|
+
* @returns {NormalizedCdpDispatchKeyEventParams}
|
|
387
|
+
*/
|
|
388
|
+
export function normalizeCdpDispatchKeyEventParams(params = {}) {
|
|
389
|
+
if (typeof params.key !== 'string' || !params.key.trim()) {
|
|
390
|
+
throw new BridgeError(ERROR_CODES.INVALID_REQUEST, 'key must be a non-empty string.');
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (
|
|
394
|
+
params.modifiers != null &&
|
|
395
|
+
typeof params.modifiers !== 'number' &&
|
|
396
|
+
!Array.isArray(params.modifiers)
|
|
397
|
+
) {
|
|
398
|
+
throw new BridgeError(
|
|
399
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
400
|
+
'modifiers must be an array of Alt, Control, Meta, Shift or a bitmask 0-15.'
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (
|
|
405
|
+
typeof params.modifiers === 'number' &&
|
|
406
|
+
(!Number.isInteger(params.modifiers) || params.modifiers < 0 || params.modifiers > 15)
|
|
407
|
+
) {
|
|
408
|
+
throw new BridgeError(
|
|
409
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
410
|
+
'modifiers must be an array of Alt, Control, Meta, Shift or a bitmask 0-15.'
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (Array.isArray(params.modifiers)) {
|
|
415
|
+
for (const modifier of params.modifiers) {
|
|
416
|
+
if (typeof modifier !== 'string' || !['Alt', 'Control', 'Meta', 'Shift'].includes(modifier)) {
|
|
417
|
+
throw new BridgeError(
|
|
418
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
419
|
+
'modifiers must contain only Alt, Control, Meta, or Shift.'
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return {
|
|
426
|
+
key: params.key,
|
|
427
|
+
code: typeof params.code === 'string' ? params.code.trim() : '',
|
|
428
|
+
modifiers: params.modifiers ?? [],
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
296
432
|
/**
|
|
297
433
|
* @param {CheckedActionParams} [params={}]
|
|
298
434
|
* @returns {NormalizedCheckedAction}
|
|
@@ -78,6 +78,7 @@ const BRIDGE_METHOD_DESCRIPTIONS = Object.freeze({
|
|
|
78
78
|
'cdp.get_dom_snapshot': 'Read a CDP DOM snapshot.',
|
|
79
79
|
'cdp.get_box_model': 'Read a CDP box model for a node.',
|
|
80
80
|
'cdp.get_computed_styles_for_node': 'Read CDP computed styles for a node.',
|
|
81
|
+
'cdp.dispatch_key_event': 'Dispatch a key press through Chrome DevTools Protocol input.',
|
|
81
82
|
'performance.get_metrics': 'Read browser performance metrics.',
|
|
82
83
|
'log.tail': 'Tail recent bridge log entries.',
|
|
83
84
|
'health.ping': 'Check daemon, extension, and access-routing health.',
|
|
@@ -424,6 +425,13 @@ export const BRIDGE_METHOD_REGISTRY = Object.freeze({
|
|
|
424
425
|
['elementRef'],
|
|
425
426
|
'high'
|
|
426
427
|
),
|
|
428
|
+
'cdp.dispatch_key_event': createRegistryEntry(
|
|
429
|
+
'cdp.dispatch_key_event',
|
|
430
|
+
'cdp',
|
|
431
|
+
true,
|
|
432
|
+
['key', 'code', 'modifiers'],
|
|
433
|
+
'moderate'
|
|
434
|
+
),
|
|
427
435
|
// performance — moderate (debugger-backed)
|
|
428
436
|
'performance.get_metrics': createRegistryEntry(
|
|
429
437
|
'performance.get_metrics',
|
|
@@ -439,6 +447,9 @@ export const BRIDGE_METHODS = Object.freeze(
|
|
|
439
447
|
/** @type {import('./types.js').BridgeMethod[]} */ (Object.keys(BRIDGE_METHOD_REGISTRY))
|
|
440
448
|
);
|
|
441
449
|
|
|
450
|
+
/** @type {ReadonlySet<import('./types.js').BridgeMethod>} */
|
|
451
|
+
export const METHOD_SET = new Set(BRIDGE_METHODS);
|
|
452
|
+
|
|
442
453
|
/**
|
|
443
454
|
* @returns {Record<string, import('./types.js').BridgeMethod[]>}
|
|
444
455
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { estimateSerializedPayloadCost, getCostClass, serializeJsonPayload } from './index.js';
|
|
4
4
|
|
|
5
5
|
/** @typedef {import('./types.js').BridgeResponse} BridgeResponse */
|
|
6
6
|
/** @typedef {import('./types.js').BridgeMethod} SummaryMethod */
|
|
@@ -99,15 +99,21 @@ const ACTION_SUMMARIES = {
|
|
|
99
99
|
* @returns {AnnotatedBridgeSummary}
|
|
100
100
|
*/
|
|
101
101
|
export function annotateBridgeSummary(summary, response) {
|
|
102
|
-
const
|
|
102
|
+
const metaTransportBytes =
|
|
103
103
|
getNumericMetaField(response.meta, 'transport_bytes') ??
|
|
104
|
-
getNumericMetaField(response.meta, 'response_bytes')
|
|
105
|
-
|
|
106
|
-
const transportTokens =
|
|
104
|
+
getNumericMetaField(response.meta, 'response_bytes');
|
|
105
|
+
const metaTransportTokens =
|
|
107
106
|
getNumericMetaField(response.meta, 'transport_approx_tokens') ??
|
|
108
|
-
getNumericMetaField(response.meta, 'approx_tokens')
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
getNumericMetaField(response.meta, 'approx_tokens');
|
|
108
|
+
const transportCost =
|
|
109
|
+
metaTransportBytes == null || metaTransportTokens == null
|
|
110
|
+
? estimateSerializedPayloadCost(
|
|
111
|
+
serializeJsonPayload(response.ok ? response.result : { error: response.error })
|
|
112
|
+
)
|
|
113
|
+
: null;
|
|
114
|
+
const transportBytes = metaTransportBytes ?? transportCost?.bytes ?? 0;
|
|
115
|
+
const transportTokens = metaTransportTokens ?? transportCost?.approxTokens ?? 0;
|
|
116
|
+
const summaryCost = estimateSerializedPayloadCost(serializeJsonPayload(summary));
|
|
111
117
|
|
|
112
118
|
return {
|
|
113
119
|
...summary,
|
|
@@ -659,13 +665,12 @@ export function summarizeBridgeResponse(response, method) {
|
|
|
659
665
|
*/
|
|
660
666
|
export function summarizeBatchResponseItem({ method, tabId, response, durationMs }) {
|
|
661
667
|
const summary = annotateBridgeSummary(summarizeBridgeResponse(response, method), response);
|
|
662
|
-
const cost = estimateJsonPayloadCost(response.ok ? response.result : { error: response.error });
|
|
663
668
|
return {
|
|
664
669
|
method,
|
|
665
670
|
tabId,
|
|
666
671
|
...summary,
|
|
667
672
|
durationMs,
|
|
668
|
-
approxTokens:
|
|
673
|
+
approxTokens: summary.transportTokens,
|
|
669
674
|
meta: response.meta,
|
|
670
675
|
error: response.ok ? null : response.error,
|
|
671
676
|
response: response.ok ? response.result : null,
|
|
@@ -756,6 +761,9 @@ function summarizeErrorHint(code) {
|
|
|
756
761
|
if (code === 'ELEMENT_STALE') {
|
|
757
762
|
return 'Re-query the current page after navigation or DOM updates.';
|
|
758
763
|
}
|
|
764
|
+
if (code === 'RESULT_TRUNCATED') {
|
|
765
|
+
return 'Narrow the query or raise the relevant budget if more detail is required.';
|
|
766
|
+
}
|
|
759
767
|
return '';
|
|
760
768
|
}
|
|
761
769
|
|
|
@@ -7,7 +7,7 @@ export {};
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* @typedef {'page.read' | 'page.evaluate' | 'dom.read' | 'styles.read' | 'layout.read' | 'viewport.control' | 'navigation.control' | 'screenshot.partial' | 'patch.dom' | 'patch.styles' | 'cdp.dom_snapshot' | 'cdp.box_model' | 'cdp.styles' | 'automation.input' | 'tabs.manage' | 'performance.read' | 'network.read'} Capability
|
|
10
|
+
* @typedef {'page.read' | 'page.evaluate' | 'dom.read' | 'styles.read' | 'layout.read' | 'viewport.control' | 'navigation.control' | 'screenshot.partial' | 'patch.dom' | 'patch.styles' | 'cdp.dom_snapshot' | 'cdp.box_model' | 'cdp.styles' | 'cdp.input' | 'automation.input' | 'tabs.manage' | 'performance.read' | 'network.read'} Capability
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -15,7 +15,7 @@ export {};
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* @typedef {'access.request' | 'tabs.list' | 'tabs.create' | 'tabs.close' | 'skill.get_runtime_context' | 'setup.get_status' | 'setup.install' | 'page.get_state' | 'page.evaluate' | 'page.get_console' | 'page.wait_for_load_state' | 'page.get_storage' | 'page.get_text' | 'page.get_network' | 'navigation.navigate' | 'navigation.reload' | 'navigation.go_back' | 'navigation.go_forward' | 'dom.query' | 'dom.describe' | 'dom.get_text' | 'dom.get_attributes' | 'dom.wait_for' | 'dom.find_by_text' | 'dom.find_by_role' | 'dom.get_html' | 'dom.get_accessibility_tree' | 'layout.get_box_model' | 'layout.hit_test' | 'styles.get_computed' | 'styles.get_matched_rules' | 'viewport.scroll' | 'viewport.resize' | 'input.click' | 'input.focus' | 'input.type' | 'input.press_key' | 'input.set_checked' | 'input.select_option' | 'input.hover' | 'input.drag' | 'input.scroll_into_view' | 'screenshot.capture_region' | 'screenshot.capture_element' | 'screenshot.capture_full_page' | 'patch.apply_styles' | 'patch.apply_dom' | 'patch.list' | 'patch.rollback' | 'patch.commit_session_baseline' | 'cdp.get_document' | 'cdp.get_dom_snapshot' | 'cdp.get_box_model' | 'cdp.get_computed_styles_for_node' | 'performance.get_metrics' | 'log.tail' | 'health.ping'} BridgeMethod
|
|
18
|
+
* @typedef {'access.request' | 'tabs.list' | 'tabs.create' | 'tabs.close' | 'skill.get_runtime_context' | 'setup.get_status' | 'setup.install' | 'page.get_state' | 'page.evaluate' | 'page.get_console' | 'page.wait_for_load_state' | 'page.get_storage' | 'page.get_text' | 'page.get_network' | 'navigation.navigate' | 'navigation.reload' | 'navigation.go_back' | 'navigation.go_forward' | 'dom.query' | 'dom.describe' | 'dom.get_text' | 'dom.get_attributes' | 'dom.wait_for' | 'dom.find_by_text' | 'dom.find_by_role' | 'dom.get_html' | 'dom.get_accessibility_tree' | 'layout.get_box_model' | 'layout.hit_test' | 'styles.get_computed' | 'styles.get_matched_rules' | 'viewport.scroll' | 'viewport.resize' | 'input.click' | 'input.focus' | 'input.type' | 'input.press_key' | 'input.set_checked' | 'input.select_option' | 'input.hover' | 'input.drag' | 'input.scroll_into_view' | 'screenshot.capture_region' | 'screenshot.capture_element' | 'screenshot.capture_full_page' | 'patch.apply_styles' | 'patch.apply_dom' | 'patch.list' | 'patch.rollback' | 'patch.commit_session_baseline' | 'cdp.get_document' | 'cdp.get_dom_snapshot' | 'cdp.get_box_model' | 'cdp.get_computed_styles_for_node' | 'cdp.dispatch_key_event' | 'performance.get_metrics' | 'log.tail' | 'health.ping'} BridgeMethod
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -52,11 +52,20 @@ export {};
|
|
|
52
52
|
* }} BridgeRequest
|
|
53
53
|
*/
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* @typedef {{
|
|
57
|
+
* hint: string,
|
|
58
|
+
* retry?: boolean,
|
|
59
|
+
* retryAfterMs?: number
|
|
60
|
+
* }} BridgeRecovery
|
|
61
|
+
*/
|
|
62
|
+
|
|
55
63
|
/**
|
|
56
64
|
* @typedef {{
|
|
57
65
|
* code: ErrorCode,
|
|
58
66
|
* message: string,
|
|
59
|
-
* details: unknown
|
|
67
|
+
* details: unknown,
|
|
68
|
+
* recovery?: BridgeRecovery
|
|
60
69
|
* }} BridgeFailure
|
|
61
70
|
*/
|
|
62
71
|
|
|
@@ -187,6 +196,22 @@ export {};
|
|
|
187
196
|
* }} NormalizedInputAction
|
|
188
197
|
*/
|
|
189
198
|
|
|
199
|
+
/**
|
|
200
|
+
* @typedef {{
|
|
201
|
+
* key?: string,
|
|
202
|
+
* code?: string,
|
|
203
|
+
* modifiers?: string[] | number
|
|
204
|
+
* }} CdpDispatchKeyEventParams
|
|
205
|
+
*/
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* @typedef {{
|
|
209
|
+
* key: string,
|
|
210
|
+
* code: string,
|
|
211
|
+
* modifiers: string[] | number
|
|
212
|
+
* }} NormalizedCdpDispatchKeyEventParams
|
|
213
|
+
*/
|
|
214
|
+
|
|
190
215
|
/**
|
|
191
216
|
* @typedef {{
|
|
192
217
|
* target?: InputTarget,
|
|
@@ -69,6 +69,7 @@ bbx click <ref> [button] # click element
|
|
|
69
69
|
bbx focus <ref> # focus element
|
|
70
70
|
bbx type <ref> <text...> # type into element
|
|
71
71
|
bbx press-key <key> [ref] # send key event
|
|
72
|
+
bbx cdp-press-key --tab <id> Escape # CDP key event without foreground focus
|
|
72
73
|
bbx hover <ref> # hover over element
|
|
73
74
|
bbx call input.scroll_into_view '{"target":{"elementRef":"el_123"}}' # ensure target is visible
|
|
74
75
|
bbx patch-style <ref> prop=val... # apply style patch
|
|
@@ -202,7 +203,7 @@ bbx page-text 2000 # extract page content
|
|
|
202
203
|
| Find | `dom.find_by_text`, `dom.find_by_role`, `dom.wait_for`, `dom.get_accessibility_tree` |
|
|
203
204
|
| Page State | `page.get_console`, `page.get_storage`, `page.get_text`, `page.wait_for_load_state`, `page.evaluate` (debugger-backed) |
|
|
204
205
|
| Network | `page.get_network` |
|
|
205
|
-
| Interact | `input.click`, `input.type`, `input.focus`, `input.press_key`, `input.hover`, `input.drag`, `input.scroll_into_view`
|
|
206
|
+
| Interact | `input.click`, `input.type`, `input.focus`, `input.press_key`, `cdp.dispatch_key_event`, `input.hover`, `input.drag`, `input.scroll_into_view` |
|
|
206
207
|
| Tabs | `tabs.list` (preferred), `tabs.create` (avoid unless necessary), `tabs.close` |
|
|
207
208
|
| Patch | `patch.apply_styles`, `patch.apply_dom`, `patch.rollback` |
|
|
208
209
|
| Navigate | `navigation.navigate`, `viewport.scroll`, `viewport.resize` |
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
| `input.focus` | `focus <ref>` | Focus an element |
|
|
9
9
|
| `input.type` | `type <ref> <text>` | Type into input/textarea/contenteditable |
|
|
10
10
|
| `input.press_key` | `press-key <key> [ref]` | Send keyboard key (Enter, Backspace, etc.) |
|
|
11
|
+
| `cdp.dispatch_key_event` | `cdp-press-key --tab <id> <key>` | CDP keyDown/keyUp without focusing the target tab |
|
|
11
12
|
| `input.set_checked` | `call input.set_checked '{...}'` | Toggle checkbox/radio |
|
|
12
13
|
| `input.select_option` | `call input.select_option '{...}'` | Select native `<select>` by value/label/index |
|
|
13
14
|
| `input.hover` | `hover <ref>` | Trigger CSS `:hover` state (mouseenter/mouseover/mousemove) |
|
|
@@ -88,6 +88,7 @@ The table below includes the legacy capability bucket for each method so agents
|
|
|
88
88
|
| 55 | `cdp.get_dom_snapshot` | Yes | CDP | cdp | `cdp.dom_snapshot` | DevTools DOM snapshot |
|
|
89
89
|
| 56 | `cdp.get_box_model` | Yes | CDP | cdp | `cdp.box_model` | DevTools-backed element geometry |
|
|
90
90
|
| 57 | `cdp.get_computed_styles_for_node` | Yes | CDP | cdp | `cdp.styles` | DevTools-backed computed styles |
|
|
91
|
+
| 58 | `cdp.dispatch_key_event` | Yes | CDP | cdp | `cdp.input` | DevTools keyDown/keyUp without foreground focus |
|
|
91
92
|
|
|
92
93
|
## CLI
|
|
93
94
|
|
|
@@ -98,7 +99,7 @@ bbx call --tab 123 <method> '{...}' # explicit tab target inside enabled
|
|
|
98
99
|
bbx batch '[{"method":"...","params":{}}]' # parallel calls
|
|
99
100
|
```
|
|
100
101
|
|
|
101
|
-
**Convenience shortcuts:** `access-request`, `dom-query`, `describe`, `text`, `styles`, `box`, `click`, `focus`, `type`, `press-key`, `patch-style`, `patch-text`, `patches`, `rollback`, `screenshot`, `eval`, `console`, `wait`, `find`, `find-role`, `html`, `hover`, `navigate`, `storage`, `tab-create`, `tab-close`, `page-text`, `network`, `a11y-tree`, `perf`, `resize`, `reload`, `back`, `forward`, `attrs`, `matched-rules`
|
|
102
|
+
**Convenience shortcuts:** `access-request`, `dom-query`, `describe`, `text`, `styles`, `box`, `click`, `focus`, `type`, `press-key`, `cdp-press-key`, `patch-style`, `patch-text`, `patches`, `rollback`, `screenshot`, `eval`, `console`, `wait`, `find`, `find-role`, `html`, `hover`, `navigate`, `storage`, `tab-create`, `tab-close`, `page-text`, `network`, `a11y-tree`, `perf`, `resize`, `reload`, `back`, `forward`, `attrs`, `matched-rules`
|
|
102
103
|
|
|
103
104
|
Newer bridge methods such as `input.scroll_into_view` and `screenshot.capture_full_page` currently use the raw path: `bbx call <method> '{...}'`.
|
|
104
105
|
|
package/CHANGELOG.md
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
-
but this file is maintained as a cumulative feature log rather than a sequence
|
|
7
|
-
of tagged releases.
|
|
8
|
-
|
|
9
|
-
## [Unreleased]
|
|
10
|
-
|
|
11
|
-
### Added
|
|
12
|
-
|
|
13
|
-
- **Core platform:** Browser Bridge as a local bridge between coding agents and
|
|
14
|
-
a real Chrome tab, preserving the existing browser state instead of starting
|
|
15
|
-
from a clean automation session. This includes the Chrome extension, native
|
|
16
|
-
messaging host, long-lived daemon, shared protocol package, agent client, and
|
|
17
|
-
MCP server.
|
|
18
|
-
- **Browser inspection:** Structured DOM inspection for subtree queries,
|
|
19
|
-
element description, text, HTML, attributes, semantic search by text or ARIA
|
|
20
|
-
role, wait conditions, and accessibility-tree reads.
|
|
21
|
-
- **Page and runtime reads:** Page state, storage, visible page text, console
|
|
22
|
-
output, network activity, performance metrics, and targeted JavaScript
|
|
23
|
-
evaluation when structured reads are insufficient.
|
|
24
|
-
- **Layout and styling reads:** Computed styles, matched CSS rules, box model
|
|
25
|
-
data, hit testing, scrolling, and viewport resizing.
|
|
26
|
-
- **Browser control:** Clicking, typing, focusing, hovering, keyboard input,
|
|
27
|
-
form controls, drag-and-drop, tab management, and page navigation.
|
|
28
|
-
- **Capture and DevTools fallback:** Partial screenshots, DOM snapshots, and
|
|
29
|
-
CDP-backed geometry and style reads for cases where standard DOM inspection is
|
|
30
|
-
not enough.
|
|
31
|
-
- **Live patching:** Reversible style and DOM patching, plus patch listing,
|
|
32
|
-
rollback, and session-baseline commit support so fixes can be proven in the
|
|
33
|
-
browser before being moved into source.
|
|
34
|
-
- **CLI integration:** The `bbx` CLI with raw RPC access, shortcut commands,
|
|
35
|
-
batch execution, diagnostics, and runtime skill/context helpers.
|
|
36
|
-
- **MCP integration:** The `bbx-mcp` server so MCP-capable agents can use
|
|
37
|
-
Browser Bridge through native tool calls.
|
|
38
|
-
- **Agent setup flows:** Managed MCP and skill installation for Codex, Claude
|
|
39
|
-
Code, Cursor, GitHub Copilot, OpenCode, Antigravity, Windsurf, and generic
|
|
40
|
-
`.agents` setups.
|
|
41
|
-
- **Documentation and skills:** Agent-facing skill packaging plus quick-start,
|
|
42
|
-
API, publishing, capability-matrix, contributor, and workflow documentation.
|
|
43
|
-
- **Validation and release tooling:** Automated tests across the protocol,
|
|
44
|
-
native host, agent client, MCP server, and extension, plus linting, coverage
|
|
45
|
-
checks, extension packaging validation, and release verification steps.
|
|
46
|
-
- **Access model and routing:** Explicit per-window enablement with active-tab
|
|
47
|
-
default routing instead of ambient browser-wide access.
|
|
48
|
-
- **Protocol and efficiency model:** Structured, token-efficient browser reads
|
|
49
|
-
with shared protocol types, normalization, error codes, recovery hints, and
|
|
50
|
-
budget presets.
|
|
51
|
-
- **Runtime hardening:** Setup readiness checks, health and diagnostic flows,
|
|
52
|
-
socket and config permission hardening, protocol negotiation, reconnect
|
|
53
|
-
behavior, and disconnected-client handling.
|
|
54
|
-
- **Typing expectations:** Strict JSDoc-backed typing across the JavaScript
|
|
55
|
-
codebase with repository-wide `npm run typecheck` validation.
|
package/assets/banner.jpg
DELETED
|
Binary file
|
package/assets/logo.png
DELETED
|
Binary file
|
package/assets/logo.svg
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
2
|
-
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
3
|
-
|
|
4
|
-
<svg
|
|
5
|
-
width="78.190598mm"
|
|
6
|
-
height="81.232712mm"
|
|
7
|
-
viewBox="0 0 78.190598 81.232712"
|
|
8
|
-
version="1.1"
|
|
9
|
-
id="svg1"
|
|
10
|
-
xml:space="preserve"
|
|
11
|
-
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
12
|
-
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
13
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
14
|
-
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
|
15
|
-
id="namedview1"
|
|
16
|
-
pagecolor="#ffffff"
|
|
17
|
-
bordercolor="#000000"
|
|
18
|
-
borderopacity="0.25"
|
|
19
|
-
inkscape:showpageshadow="2"
|
|
20
|
-
inkscape:pageopacity="0.0"
|
|
21
|
-
inkscape:pagecheckerboard="0"
|
|
22
|
-
inkscape:deskcolor="#d1d1d1"
|
|
23
|
-
inkscape:document-units="mm"><inkscape:page
|
|
24
|
-
x="0"
|
|
25
|
-
y="0"
|
|
26
|
-
width="78.190598"
|
|
27
|
-
height="81.232712"
|
|
28
|
-
id="page2"
|
|
29
|
-
margin="0"
|
|
30
|
-
bleed="0" /></sodipodi:namedview><defs
|
|
31
|
-
id="defs1" /><g
|
|
32
|
-
inkscape:label="Layer 1"
|
|
33
|
-
inkscape:groupmode="layer"
|
|
34
|
-
id="layer1"
|
|
35
|
-
transform="translate(-42.680867,-100)"><g
|
|
36
|
-
id="g2"><path
|
|
37
|
-
id="rect2-6"
|
|
38
|
-
style="fill:#d34a1e;fill-opacity:1;stroke:none;stroke-width:0.221409"
|
|
39
|
-
d="m -20.02,163.43555 -21.040492,2.4e-4 a 16.5,16.5 0 0 1 -1.090567,14.99993 l 22.283145,-8e-5 A 16.5,16.5 0 0 1 -20.02,163.43555 Z"
|
|
40
|
-
transform="rotate(-40.047795)" /><path
|
|
41
|
-
id="rect2"
|
|
42
|
-
style="fill:#d34a1e;fill-opacity:1;stroke:none;stroke-width:0.221409"
|
|
43
|
-
d="m 136.94552,-47.53585 a 16.5,16.5 0 0 1 1.66989,10.051485 16.5,16.5 0 0 1 -1.57039,4.948831 l 22.89662,-6.5e-5 a 16.5,16.5 0 0 1 -2.02368,-10.697809 16.5,16.5 0 0 1 1.26306,-4.302113 z"
|
|
44
|
-
transform="rotate(81.447977)" /><path
|
|
45
|
-
id="rect2-6-4"
|
|
46
|
-
style="fill:#d34a1e;fill-opacity:1;stroke:none;stroke-width:0.221409"
|
|
47
|
-
d="m 110.73366,76.358885 a 16.5,16.5 0 0 1 1.19568,2.379247 16.5,16.5 0 0 1 -0.096,12.620524 l 21.61171,9e-6 a 16.5,16.5 0 0 1 -0.2602,-0.606591 16.5,16.5 0 0 1 0.97427,-14.393019 z"
|
|
48
|
-
transform="rotate(22.050959)" /><circle
|
|
49
|
-
style="fill:#d34a1e;fill-opacity:1;stroke:none;stroke-width:0.424555"
|
|
50
|
-
id="path1-0-7"
|
|
51
|
-
cx="66.236229"
|
|
52
|
-
cy="166.23273"
|
|
53
|
-
r="15"
|
|
54
|
-
inkscape:transform-center-x="-0.58870168"
|
|
55
|
-
inkscape:transform-center-y="1.4717542" /><circle
|
|
56
|
-
style="fill:#d34a1e;fill-opacity:1;stroke:none;stroke-width:0.424555"
|
|
57
|
-
id="path1"
|
|
58
|
-
cx="57.68087"
|
|
59
|
-
cy="115.00001"
|
|
60
|
-
r="15" /><circle
|
|
61
|
-
style="fill:#d34a1e;fill-opacity:1;stroke:none;stroke-width:0.424555"
|
|
62
|
-
id="path1-0"
|
|
63
|
-
cx="105.87147"
|
|
64
|
-
cy="134.11552"
|
|
65
|
-
r="15" /></g></g></svg>
|