@browserbridge/bbx 1.7.7 → 1.8.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/PRIVACY.md +111 -0
- package/README.md +13 -5
- package/RESPONSIBLE_USE.md +16 -0
- package/SECURITY.md +52 -0
- package/package.json +12 -6
- package/packages/agent-client/src/cli-args.js +24 -0
- package/packages/agent-client/src/cli.js +46 -52
- package/packages/agent-client/src/client.js +140 -5
- package/packages/agent-client/src/command-registry.js +56 -53
- package/packages/agent-client/src/content-extract.js +198 -0
- package/packages/agent-client/src/remotes.js +1 -1
- package/packages/agent-client/src/runtime.js +768 -35
- package/packages/agent-client/src/types.ts +131 -6
- package/packages/mcp-server/src/guidance.js +1 -1
- package/packages/mcp-server/src/handlers-capture.js +41 -5
- package/packages/mcp-server/src/handlers-dom.js +8 -2
- package/packages/mcp-server/src/handlers-navigation.js +2 -1
- package/packages/mcp-server/src/handlers-page.js +41 -4
- package/packages/mcp-server/src/handlers-utils.js +67 -7
- package/packages/mcp-server/src/handlers.js +4 -4
- package/packages/mcp-server/src/server.js +102 -6
- package/packages/native-host/src/daemon.js +158 -6
- package/packages/native-host/src/native-host.js +3 -1
- package/packages/protocol/src/defaults.js +3 -0
- package/packages/protocol/src/errors.js +54 -1
- package/packages/protocol/src/protocol.js +297 -1
- package/packages/protocol/src/registry.js +66 -35
- package/packages/protocol/src/summary.js +87 -5
- package/packages/protocol/src/types.ts +234 -0
- package/skills/browser-bridge/SKILL.md +34 -13
- package/skills/browser-bridge/references/interaction.md +55 -11
- package/skills/browser-bridge/references/patch-workflow.md +2 -0
- package/skills/browser-bridge/references/protocol.md +157 -82
- package/skills/browser-bridge/references/token-efficiency.md +19 -13
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
export type BridgeRequestSource = 'cli' | 'mcp';
|
|
2
2
|
|
|
3
|
+
export type AccessIntent = 'inspect' | 'interact' | 'capture' | 'navigate' | 'debugger' | 'general';
|
|
4
|
+
|
|
5
|
+
export interface AccessRequestParams {
|
|
6
|
+
intent?: AccessIntent;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface NormalizedAccessRequestParams extends BridgeParams {
|
|
10
|
+
intent: AccessIntent;
|
|
11
|
+
}
|
|
12
|
+
|
|
3
13
|
export type Capability =
|
|
4
14
|
| 'page.read'
|
|
5
15
|
| 'page.evaluate'
|
|
@@ -25,6 +35,15 @@ export type ErrorCode =
|
|
|
25
35
|
| 'ACCESS_DENIED'
|
|
26
36
|
| 'TAB_MISMATCH'
|
|
27
37
|
| 'ELEMENT_STALE'
|
|
38
|
+
| 'ELEMENT_AMBIGUOUS'
|
|
39
|
+
| 'ELEMENT_NOT_ACTIONABLE'
|
|
40
|
+
| 'ELEMENT_OBSCURED'
|
|
41
|
+
| 'ELEMENT_NOT_FOUND'
|
|
42
|
+
| 'INPUT_UNSUPPORTED'
|
|
43
|
+
| 'INPUT_INVALID_TARGET'
|
|
44
|
+
| 'INPUT_FOCUS_CHANGED'
|
|
45
|
+
| 'DIALOG_NOT_OPEN'
|
|
46
|
+
| 'DIALOG_ACTION_CONFLICT'
|
|
28
47
|
| 'RESULT_TRUNCATED'
|
|
29
48
|
| 'RATE_LIMITED'
|
|
30
49
|
| 'INTERNAL_ERROR'
|
|
@@ -45,9 +64,11 @@ export type BridgeMethod =
|
|
|
45
64
|
| 'page.get_state'
|
|
46
65
|
| 'page.evaluate'
|
|
47
66
|
| 'page.get_console'
|
|
67
|
+
| 'page.handle_dialog'
|
|
48
68
|
| 'page.wait_for_load_state'
|
|
49
69
|
| 'page.get_storage'
|
|
50
70
|
| 'page.get_text'
|
|
71
|
+
| 'page.extract_content'
|
|
51
72
|
| 'page.get_network'
|
|
52
73
|
| 'network.intercept.add'
|
|
53
74
|
| 'network.intercept.remove'
|
|
@@ -228,6 +249,29 @@ export interface InputTarget {
|
|
|
228
249
|
selector?: string;
|
|
229
250
|
}
|
|
230
251
|
|
|
252
|
+
export type InputExecutionMode = 'dom' | 'cdp';
|
|
253
|
+
|
|
254
|
+
export interface InputResolutionMetadata {
|
|
255
|
+
strategy: 'elementRef' | 'selector-first' | 'selector-ranked' | 'stale-recovery';
|
|
256
|
+
candidateCount: number;
|
|
257
|
+
evaluatedCount: number;
|
|
258
|
+
scrolled: boolean;
|
|
259
|
+
hitTest: 'target' | 'descendant' | 'none' | 'not-required';
|
|
260
|
+
recovered: boolean;
|
|
261
|
+
oldRef?: string;
|
|
262
|
+
newRef?: string;
|
|
263
|
+
matchedFields?: string[];
|
|
264
|
+
confidenceBasis?: string;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export interface InputExecutionMetadata {
|
|
268
|
+
requestedMode: InputExecutionMode;
|
|
269
|
+
actualMode: InputExecutionMode;
|
|
270
|
+
fallbackReason: null;
|
|
271
|
+
debuggerUsed: boolean;
|
|
272
|
+
targetCoordinates?: { x: number; y: number };
|
|
273
|
+
}
|
|
274
|
+
|
|
231
275
|
export interface InputActionParams {
|
|
232
276
|
target?: InputTarget;
|
|
233
277
|
button?: 'left' | 'middle' | 'right';
|
|
@@ -239,6 +283,8 @@ export interface InputActionParams {
|
|
|
239
283
|
submit?: boolean;
|
|
240
284
|
key?: string;
|
|
241
285
|
modifiers?: string[];
|
|
286
|
+
executionMode?: InputExecutionMode;
|
|
287
|
+
recoverStale?: boolean;
|
|
242
288
|
}
|
|
243
289
|
|
|
244
290
|
export interface NormalizedInputAction extends BridgeParams {
|
|
@@ -252,6 +298,8 @@ export interface NormalizedInputAction extends BridgeParams {
|
|
|
252
298
|
submit: boolean;
|
|
253
299
|
key: string;
|
|
254
300
|
modifiers: string[];
|
|
301
|
+
executionMode: InputExecutionMode;
|
|
302
|
+
recoverStale: boolean;
|
|
255
303
|
}
|
|
256
304
|
|
|
257
305
|
export interface CdpDispatchKeyEventParams {
|
|
@@ -277,11 +325,15 @@ export interface NormalizedCdpNodeIdParams extends BridgeParams {
|
|
|
277
325
|
export interface CheckedActionParams {
|
|
278
326
|
target?: InputTarget;
|
|
279
327
|
checked?: boolean;
|
|
328
|
+
executionMode?: InputExecutionMode;
|
|
329
|
+
recoverStale?: boolean;
|
|
280
330
|
}
|
|
281
331
|
|
|
282
332
|
export interface NormalizedCheckedAction extends BridgeParams {
|
|
283
333
|
target: InputTarget;
|
|
284
334
|
checked: boolean;
|
|
335
|
+
executionMode: InputExecutionMode;
|
|
336
|
+
recoverStale: boolean;
|
|
285
337
|
}
|
|
286
338
|
|
|
287
339
|
export interface SelectActionParams {
|
|
@@ -289,6 +341,8 @@ export interface SelectActionParams {
|
|
|
289
341
|
values?: string[];
|
|
290
342
|
labels?: string[];
|
|
291
343
|
indexes?: number[];
|
|
344
|
+
executionMode?: InputExecutionMode;
|
|
345
|
+
recoverStale?: boolean;
|
|
292
346
|
}
|
|
293
347
|
|
|
294
348
|
export interface NormalizedSelectAction extends BridgeParams {
|
|
@@ -296,6 +350,8 @@ export interface NormalizedSelectAction extends BridgeParams {
|
|
|
296
350
|
values: string[];
|
|
297
351
|
labels: string[];
|
|
298
352
|
indexes: number[];
|
|
353
|
+
executionMode: InputExecutionMode;
|
|
354
|
+
recoverStale: boolean;
|
|
299
355
|
}
|
|
300
356
|
|
|
301
357
|
export interface ViewportActionParams {
|
|
@@ -417,6 +473,21 @@ export interface ConsoleParams {
|
|
|
417
473
|
limit?: number;
|
|
418
474
|
}
|
|
419
475
|
|
|
476
|
+
export type DialogAction = 'inspect' | 'accept' | 'dismiss';
|
|
477
|
+
|
|
478
|
+
export interface HandleDialogParams {
|
|
479
|
+
action?: DialogAction;
|
|
480
|
+
promptText?: string;
|
|
481
|
+
/** Optional stale-decision check performed immediately before CDP dispatch. */
|
|
482
|
+
expectedDialogId?: string;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
export interface NormalizedHandleDialogParams extends BridgeParams {
|
|
486
|
+
action: DialogAction;
|
|
487
|
+
promptText: string | null;
|
|
488
|
+
expectedDialogId: string | null;
|
|
489
|
+
}
|
|
490
|
+
|
|
420
491
|
export interface NormalizedConsoleParams extends BridgeParams {
|
|
421
492
|
level: string;
|
|
422
493
|
clear: boolean;
|
|
@@ -483,12 +554,16 @@ export interface HoverParams {
|
|
|
483
554
|
target?: InputTarget;
|
|
484
555
|
duration?: number;
|
|
485
556
|
modifiers?: string[];
|
|
557
|
+
executionMode?: InputExecutionMode;
|
|
558
|
+
recoverStale?: boolean;
|
|
486
559
|
}
|
|
487
560
|
|
|
488
561
|
export interface NormalizedHoverParams extends BridgeParams {
|
|
489
562
|
target: InputTarget;
|
|
490
563
|
duration: number;
|
|
491
564
|
modifiers: string[];
|
|
565
|
+
executionMode: InputExecutionMode;
|
|
566
|
+
recoverStale: boolean;
|
|
492
567
|
}
|
|
493
568
|
|
|
494
569
|
export interface DragParams {
|
|
@@ -496,6 +571,8 @@ export interface DragParams {
|
|
|
496
571
|
destination?: InputTarget;
|
|
497
572
|
offsetX?: number;
|
|
498
573
|
offsetY?: number;
|
|
574
|
+
executionMode?: InputExecutionMode;
|
|
575
|
+
recoverStale?: boolean;
|
|
499
576
|
}
|
|
500
577
|
|
|
501
578
|
export interface NormalizedDragParams extends BridgeParams {
|
|
@@ -503,6 +580,8 @@ export interface NormalizedDragParams extends BridgeParams {
|
|
|
503
580
|
destination: InputTarget;
|
|
504
581
|
offsetX: number;
|
|
505
582
|
offsetY: number;
|
|
583
|
+
executionMode: InputExecutionMode;
|
|
584
|
+
recoverStale: boolean;
|
|
506
585
|
}
|
|
507
586
|
|
|
508
587
|
export interface StorageParams {
|
|
@@ -515,14 +594,75 @@ export interface NormalizedStorageParams extends BridgeParams {
|
|
|
515
594
|
keys: string[] | null;
|
|
516
595
|
}
|
|
517
596
|
|
|
597
|
+
export type ExtractContentFormat = 'text' | 'markdown';
|
|
598
|
+
export type ExtractContentConsistency = 'best_effort' | 'settled';
|
|
599
|
+
export type ExtractContentSource = 'readability' | 'semantic-root' | 'body';
|
|
600
|
+
export type ScreenshotFormat = 'png' | 'jpeg' | 'webp';
|
|
601
|
+
|
|
602
|
+
export interface ExtractContentParams {
|
|
603
|
+
format?: ExtractContentFormat;
|
|
604
|
+
selector?: string;
|
|
605
|
+
includeMetadata?: boolean;
|
|
606
|
+
consistency?: ExtractContentConsistency;
|
|
607
|
+
textBudget?: number;
|
|
608
|
+
settleTimeoutMs?: number;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
export interface NormalizedExtractContentParams extends BridgeParams {
|
|
612
|
+
format: ExtractContentFormat;
|
|
613
|
+
selector: string | null;
|
|
614
|
+
includeMetadata: boolean;
|
|
615
|
+
consistency: ExtractContentConsistency;
|
|
616
|
+
textBudget: number;
|
|
617
|
+
settleTimeoutMs: number;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
export interface ScreenshotParams extends BridgeParams {
|
|
621
|
+
format?: ScreenshotFormat;
|
|
622
|
+
quality?: number;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
export interface NormalizedScreenshotParams extends BridgeParams {
|
|
626
|
+
format: ScreenshotFormat;
|
|
627
|
+
quality: number | null;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
export interface ScreenshotResult {
|
|
631
|
+
image: string;
|
|
632
|
+
mimeType: `image/${ScreenshotFormat}`;
|
|
633
|
+
format: ScreenshotFormat;
|
|
634
|
+
rect: { x: number; y: number; width: number; height: number; scale: number };
|
|
635
|
+
complete: boolean;
|
|
636
|
+
clipped: boolean;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
export interface ExtractContentResult {
|
|
640
|
+
format: ExtractContentFormat;
|
|
641
|
+
content: string;
|
|
642
|
+
title?: string;
|
|
643
|
+
byline?: string;
|
|
644
|
+
excerpt?: string;
|
|
645
|
+
siteName?: string;
|
|
646
|
+
source: ExtractContentSource;
|
|
647
|
+
root?: { tag: string; selector?: string };
|
|
648
|
+
length: number;
|
|
649
|
+
truncated: boolean;
|
|
650
|
+
omitted: number;
|
|
651
|
+
settlement?: { requested: boolean; quietMs: number; timedOut: boolean };
|
|
652
|
+
}
|
|
653
|
+
|
|
518
654
|
export interface WaitForLoadStateParams {
|
|
519
655
|
waitForLoad?: boolean;
|
|
520
656
|
timeoutMs?: number;
|
|
657
|
+
url?: string;
|
|
658
|
+
urlMatch?: 'exact' | 'contains' | 'regex';
|
|
521
659
|
}
|
|
522
660
|
|
|
523
661
|
export interface NormalizedWaitForLoadStateParams extends BridgeParams {
|
|
524
662
|
waitForLoad: boolean;
|
|
525
663
|
timeoutMs: number;
|
|
664
|
+
url: string | null;
|
|
665
|
+
urlMatch: 'exact' | 'contains' | 'regex' | null;
|
|
526
666
|
}
|
|
527
667
|
|
|
528
668
|
export interface TabCreateParams {
|
|
@@ -544,25 +684,119 @@ export interface NormalizedTabCloseParams extends BridgeParams {
|
|
|
544
684
|
}
|
|
545
685
|
|
|
546
686
|
export interface AccessibilityTreeParams {
|
|
687
|
+
selector?: string;
|
|
547
688
|
maxDepth?: number;
|
|
548
689
|
maxNodes?: number;
|
|
690
|
+
compact?: boolean;
|
|
691
|
+
interactiveOnly?: boolean;
|
|
549
692
|
}
|
|
550
693
|
|
|
551
694
|
export interface NormalizedAccessibilityTreeParams extends BridgeParams {
|
|
695
|
+
selector: string | null;
|
|
552
696
|
maxDepth: number;
|
|
553
697
|
maxNodes: number;
|
|
698
|
+
compact: boolean;
|
|
699
|
+
interactiveOnly: boolean;
|
|
554
700
|
}
|
|
555
701
|
|
|
702
|
+
export interface AccessibilityTreeNode {
|
|
703
|
+
nodeId: string;
|
|
704
|
+
role: string;
|
|
705
|
+
name: string;
|
|
706
|
+
description: string;
|
|
707
|
+
value: string;
|
|
708
|
+
focused: boolean;
|
|
709
|
+
required: boolean;
|
|
710
|
+
checked: 'true' | 'false' | 'mixed' | null;
|
|
711
|
+
disabled: boolean;
|
|
712
|
+
interactive: boolean;
|
|
713
|
+
semanticInteractive: boolean;
|
|
714
|
+
focusable: boolean;
|
|
715
|
+
focusableAndEnabled: boolean;
|
|
716
|
+
ignored: boolean;
|
|
717
|
+
childIds: string[];
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
export interface AccessibilityTreeResult {
|
|
721
|
+
nodes: AccessibilityTreeNode[];
|
|
722
|
+
rootIds: string[];
|
|
723
|
+
count: number;
|
|
724
|
+
total: number;
|
|
725
|
+
rawTotal: number;
|
|
726
|
+
source: 'cdp-accessibility';
|
|
727
|
+
compact: boolean;
|
|
728
|
+
interactiveOnly: boolean;
|
|
729
|
+
truncated: boolean;
|
|
730
|
+
truncation: {
|
|
731
|
+
reason: 'maxNodes' | 'maxDepth';
|
|
732
|
+
reasons: Array<'maxNodes' | 'maxDepth'>;
|
|
733
|
+
maxNodes: number;
|
|
734
|
+
maxDepth: number;
|
|
735
|
+
omitted: number;
|
|
736
|
+
missingChildCount: number;
|
|
737
|
+
partialTopology: true;
|
|
738
|
+
};
|
|
739
|
+
continuationHint: string;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
export type NetworkSource = 'fetch-xhr' | 'cdp';
|
|
743
|
+
export type NetworkCaptureAction = 'read' | 'start' | 'clear' | 'stop';
|
|
744
|
+
|
|
556
745
|
export interface NetworkParams {
|
|
557
746
|
clear?: boolean;
|
|
558
747
|
limit?: number;
|
|
559
748
|
urlPattern?: string;
|
|
749
|
+
source?: NetworkSource;
|
|
750
|
+
capture?: NetworkCaptureAction;
|
|
560
751
|
}
|
|
561
752
|
|
|
562
753
|
export interface NormalizedNetworkParams extends BridgeParams {
|
|
563
754
|
clear: boolean;
|
|
564
755
|
limit: number;
|
|
565
756
|
urlPattern: string | null;
|
|
757
|
+
source: NetworkSource;
|
|
758
|
+
capture: NetworkCaptureAction;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
export interface CdpNetworkEntry {
|
|
762
|
+
requestId: string;
|
|
763
|
+
url: string;
|
|
764
|
+
method: string;
|
|
765
|
+
resourceType: string;
|
|
766
|
+
status: number;
|
|
767
|
+
mimeType: string;
|
|
768
|
+
protocol: string;
|
|
769
|
+
fromCache: boolean;
|
|
770
|
+
fromDiskCache: boolean;
|
|
771
|
+
fromServiceWorker: boolean;
|
|
772
|
+
fromPrefetchCache: boolean;
|
|
773
|
+
redirect: {
|
|
774
|
+
count: number;
|
|
775
|
+
hops: Array<{ url: string; status: number }>;
|
|
776
|
+
truncated: boolean;
|
|
777
|
+
};
|
|
778
|
+
failureReason: string;
|
|
779
|
+
duration: number;
|
|
780
|
+
timestamp: number;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
export interface NetworkResult {
|
|
784
|
+
entries: Array<CdpNetworkEntry | Record<string, unknown>>;
|
|
785
|
+
count: number;
|
|
786
|
+
total: number;
|
|
787
|
+
filteredTotal: number;
|
|
788
|
+
dropped: number;
|
|
789
|
+
abandoned: number;
|
|
790
|
+
source: NetworkSource;
|
|
791
|
+
capture: NetworkCaptureAction | null;
|
|
792
|
+
armed: boolean;
|
|
793
|
+
armedDuringCapture: boolean;
|
|
794
|
+
captureState: 'armed' | 'stop_failed' | 'stopped' | 'instrumented';
|
|
795
|
+
ownershipHeld: boolean;
|
|
796
|
+
startedAt: number | null;
|
|
797
|
+
inflight: number;
|
|
798
|
+
truncated: boolean;
|
|
799
|
+
truncation: { reason: 'limit' | null; limit: number; omitted: number };
|
|
566
800
|
}
|
|
567
801
|
|
|
568
802
|
export type NetworkInterceptAction = 'fulfill' | 'continue' | 'block';
|
|
@@ -13,13 +13,13 @@ Permission prompts are controlled by the host agent, not by Browser Bridge. In p
|
|
|
13
13
|
|
|
14
14
|
Skill name: `browser-bridge` (also known as `bbx`). In GitHub Copilot, invoke as `/browser-bridge`. `bbx` is the CLI command used throughout this skill.
|
|
15
15
|
When the runtime supports subagents, delegate bridge inspection to a smaller, lower-cost worker and return only concise findings to the parent.
|
|
16
|
-
For open-ended investigation, start with structured reads (`page.get_state`, `dom.query`, `page.get_text`, `styles.get_computed`, and `bbx batch` for CLI or `browser_batch` for MCP) and escalate to screenshots or debugger-backed methods only when structured evidence is insufficient. `browser_call` accepts one protocol method at a time; `batch` is not a valid `browser_call` method.
|
|
16
|
+
For open-ended investigation, start with structured reads (`page.get_state`, `dom.query`, `page.get_text`, `page.extract_content`, `styles.get_computed`, and `bbx batch` for CLI or `browser_batch` for MCP) and escalate to screenshots or debugger-backed methods only when structured evidence is insufficient. `browser_call` accepts one protocol method at a time; `batch` is not a valid `browser_call` method.
|
|
17
17
|
|
|
18
18
|
## CLI
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
bbx status # daemon + extension health
|
|
22
|
-
bbx doctor #
|
|
22
|
+
bbx doctor # consolidated local diagnostics (does not probe remotes)
|
|
23
23
|
bbx access-request # ask user to enable access for the focused window
|
|
24
24
|
bbx restart # start/restart the daemon and running MCP servers
|
|
25
25
|
bbx call <method> '{...}' # any RPC method (raw output)
|
|
@@ -58,7 +58,7 @@ bbx a11y-tree [maxNodes] [maxDepth] # accessibility tree
|
|
|
58
58
|
```bash
|
|
59
59
|
bbx eval [--await] <expression> # JS eval (--await for promises, - for stdin)
|
|
60
60
|
bbx console [level] # console output
|
|
61
|
-
bbx network [limit] #
|
|
61
|
+
bbx network [limit] # recent fetch/XHR requests
|
|
62
62
|
bbx intercept add <pattern> [--respond <body>] [--status <code>] [--block] # intercept matching requests
|
|
63
63
|
bbx intercept list|remove <id>|clear # manage interception rules
|
|
64
64
|
bbx page-text [budget] # full page text
|
|
@@ -70,6 +70,8 @@ bbx back # navigate back
|
|
|
70
70
|
bbx forward # navigate forward
|
|
71
71
|
bbx scroll <top> [left] # scroll viewport
|
|
72
72
|
bbx resize <width> <height> # resize viewport
|
|
73
|
+
bbx call page.wait_for_load_state '{"url":"/dashboard","urlMatch":"contains","waitForLoad":false}'
|
|
74
|
+
bbx call page.handle_dialog '{"action":"inspect"}' # inspect current JS dialog; never auto-accept
|
|
73
75
|
```
|
|
74
76
|
|
|
75
77
|
### Interact & Patch
|
|
@@ -83,11 +85,12 @@ bbx press-key <key> [ref] # send key event
|
|
|
83
85
|
bbx cdp-press-key --tab <id> Escape # CDP key event without foreground focus
|
|
84
86
|
bbx hover <ref> # hover over element
|
|
85
87
|
bbx call input.scroll_into_view '{"target":{"elementRef":"el_123"}}' # ensure target is visible
|
|
88
|
+
bbx call input.click '{"target":{"elementRef":"el_123"},"executionMode":"cdp"}' # optional native click
|
|
86
89
|
bbx patch-style <ref> prop=val... # apply style patch
|
|
87
90
|
bbx patch-text <ref> <text...> # apply text patch
|
|
88
91
|
bbx patches # list active patches
|
|
89
92
|
bbx rollback <patchId> # rollback a patch
|
|
90
|
-
bbx screenshot <ref> [outPath]
|
|
93
|
+
bbx screenshot [--format png|jpeg|webp] [--quality 0-100] <ref> [outPath] # complete element capture
|
|
91
94
|
bbx call screenshot.capture_full_page '{}' # raw base64; avoid unless document context matters
|
|
92
95
|
```
|
|
93
96
|
|
|
@@ -104,6 +107,8 @@ bbx dom-query "#app" --remote <name>
|
|
|
104
107
|
|
|
105
108
|
In MCP mode, pass `destinationId` on any browser tool call instead; `browser_status` lists all destinations with reachability. Only use remotes the user has configured; local remains the default.
|
|
106
109
|
|
|
110
|
+
`bbx doctor` is intentionally local-only. It reports how many remotes are configured, but marks their status `not_probed_local_only` and credentials `unverified`; use `bbx remote test <name>` when the user wants a remote probe.
|
|
111
|
+
|
|
107
112
|
## Access Flow
|
|
108
113
|
|
|
109
114
|
Browser Bridge access is window-scoped. The user turns it on once for the current browser window in the popup or side panel.
|
|
@@ -132,6 +137,12 @@ After access is enabled:
|
|
|
132
137
|
| ------------------------- | -------- | ----------------------------------------------------------------------------------------- |
|
|
133
138
|
| `ACCESS_DENIED` | No | Failed call already surfaced an `Enable` cue; ask user to click `Enable`, then retry once |
|
|
134
139
|
| `ELEMENT_STALE` | No | Re-query with `dom.query` or `dom.find_by_text` to get a fresh ref |
|
|
140
|
+
| `ELEMENT_AMBIGUOUS` | No | Narrow the selector or use an explicit `elementRef`; do not guess |
|
|
141
|
+
| `ELEMENT_NOT_ACTIONABLE` | No | Inspect hidden/disabled/inert state with `dom.describe` |
|
|
142
|
+
| `ELEMENT_OBSCURED` | No | Inspect bounded blocker details or use `layout.hit_test` |
|
|
143
|
+
| `INPUT_FOCUS_CHANGED` | No | Inspect focus handlers; do not replay native text automatically |
|
|
144
|
+
| `DIALOG_NOT_OPEN` | No | Trigger or inspect the dialog again |
|
|
145
|
+
| `DIALOG_ACTION_CONFLICT` | No | Inspect current dialog state; never auto-repeat accept/dismiss |
|
|
135
146
|
| `TAB_MISMATCH` | No | Tab closed or not found - use `tabs.list` to find an available tab |
|
|
136
147
|
| `TIMEOUT` | Once | Retry once; if still failing, simplify (smaller `maxNodes`, narrower selector) |
|
|
137
148
|
| `RATE_LIMITED` | After 2s | Back off 2 seconds, then retry |
|
|
@@ -157,14 +168,18 @@ Error responses now include a machine-readable `error.recovery` field with `retr
|
|
|
157
168
|
9. **Batch reads** - combine independent reads with `bbx batch` in CLI mode or `browser_batch` in MCP mode; do not pass `batch` as a `browser_call` method.
|
|
158
169
|
10. **Avoid debugger first** - prefer DOM/content-script methods (`dom.*`, `styles.*`, `layout.get_box_model`, `page.get_console`, `page.get_text`, `page.get_storage`, `page.get_network`) before any debugger-backed method. Escalate to CDP only when those cannot answer the question.
|
|
159
170
|
11. **Evaluate only when needed** - `page.evaluate` is powerful but debugger-backed; use it only when DOM, storage, console, network, or text reads cannot expose the needed state.
|
|
160
|
-
12. **Debugger-backed methods are last resort** - treat `page.evaluate`, `dom.get_accessibility_tree`, `viewport.resize`, `performance.get_metrics`, `screenshot.capture_*`, and all `cdp.*` methods as escalation steps because they attach `chrome.debugger`.
|
|
171
|
+
12. **Debugger-backed methods are last resort** - treat `page.evaluate`, `page.handle_dialog`, `dom.get_accessibility_tree`, `page.get_network` with `source: 'cdp'`, input with `executionMode: 'cdp'`, `viewport.resize`, `performance.get_metrics`, `screenshot.capture_*`, and all `cdp.*` methods as escalation steps because they attach `chrome.debugger`.
|
|
161
172
|
13. **Wait after change** - after editing source, wait for expected new text, a selector matching the changed attribute, or a detach/attach remount; waiting for `attached` on a selector that already exists does not prove HMR ran. Use `page.wait_for_load_state` for navigation, not HMR.
|
|
162
|
-
14. **Prime event buffers** - before reproducing a console or
|
|
173
|
+
14. **Prime event buffers** - before reproducing a console or fetch/XHR issue, call `page.get_console` and default `page.get_network` once with `clear: true`; then reproduce and read without clearing. CDP all-resource capture instead requires explicit `start`, reproduce, `read`, and `stop` calls.
|
|
163
174
|
15. **Semantic finding** - use `dom.find_by_text` / `dom.find_by_role` when you know the label but not the selector.
|
|
164
|
-
16. **Text extraction** - use `page.
|
|
175
|
+
16. **Text extraction** - use `page.extract_content` for articles/documentation, or `page.get_text` for all visible UI text, instead of `dom.query` on body.
|
|
165
176
|
17. **Network monitoring** - use `page.get_network` to inspect API calls; auto-installs interceptor.
|
|
166
177
|
18. **Accessibility tree only when necessary** - `dom.get_accessibility_tree` is debugger-backed; use it when semantic structure cannot be inferred from DOM queries and role/text search.
|
|
167
178
|
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.
|
|
179
|
+
20. **Verify after input** - a dispatched DOM or CDP event does not prove application state changed. Follow it with the cheapest relevant wait or structured read.
|
|
180
|
+
21. **Do not guess input targets** - for targeted click, focus, type, fill, press-key, checked-state, option-selection, hover, and drag calls, honor actionability errors and returned `resolution` metadata. `cdp_press_key` and `scroll_into_view` use separate contracts. `executionMode` is only `dom` or `cdp`; `input.fill.mode: auto` is a separate DOM setter/keystroke strategy.
|
|
181
|
+
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.
|
|
182
|
+
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`.
|
|
168
183
|
|
|
169
184
|
## Token Budget Quick Rules
|
|
170
185
|
|
|
@@ -172,7 +187,7 @@ Error responses now include a machine-readable `error.recovery` field with `retr
|
|
|
172
187
|
2. **Use `attributeAllowlist`** - filter irrelevant attributes (e.g. `['class', 'href', 'data-testid']`)
|
|
173
188
|
3. **Batch independent reads** - combine into a single `bbx batch` / `browser_batch` call
|
|
174
189
|
4. **Refresh refs after pruning** - if `dom.query` returns `_registryPruned: true`, old refs may have been evicted; re-query before reusing them
|
|
175
|
-
5. **Watch overflow counters** - `page.get_console` and `page.get_network` return `dropped` when hot pages overflow the 200-entry buffers
|
|
190
|
+
5. **Watch overflow counters** - `page.get_console` and `page.get_network` return `dropped` when hot pages overflow the 200-entry buffers; CDP network also reports `abandoned` and capture lifecycle state
|
|
176
191
|
|
|
177
192
|
## Investigate Workflow
|
|
178
193
|
|
|
@@ -235,7 +250,8 @@ bbx page-text 2000 # extract page content
|
|
|
235
250
|
| Inspect | `dom.query`, `dom.describe`, `dom.get_html`, `styles.get_computed`, `layout.get_box_model` |
|
|
236
251
|
| Find | `dom.find_by_text`, `dom.find_by_role`, `dom.wait_for`, `dom.get_accessibility_tree` |
|
|
237
252
|
| Page State | `page.get_console`, `page.get_storage`, `page.get_text`, `page.wait_for_load_state`, `page.evaluate` (debugger-backed) |
|
|
238
|
-
|
|
|
253
|
+
| Dialogs | `page.handle_dialog` (debugger-backed; explicit inspect/accept/dismiss only) |
|
|
254
|
+
| Network | `page.get_network` (fetch/XHR default; optional CDP lifecycle), `network.intercept.add/remove/list/clear` (debugger-backed) |
|
|
239
255
|
| Interact | `input.click`, `input.type`, `input.fill`, `input.focus`, `input.press_key`, `cdp.dispatch_key_event`, `input.hover`, `input.drag`, `input.scroll_into_view` |
|
|
240
256
|
| Tabs | `tabs.list` (preferred), `tabs.create` (avoid unless necessary), `tabs.close`, `tabs.activate` |
|
|
241
257
|
| Patch | `patch.apply_styles`, `patch.apply_dom`, `patch.rollback` |
|
|
@@ -273,8 +289,8 @@ page.get_state → page.get_console(clear: true) + page.get_network(clear: true)
|
|
|
273
289
|
|
|
274
290
|
```
|
|
275
291
|
dom.find_by_role('button', 'Login') → input.click
|
|
292
|
+
→ page.wait_for_load_state({url: '/dashboard', urlMatch: 'contains', waitForLoad: false})
|
|
276
293
|
→ dom.wait_for('.dashboard', {state: 'visible', timeoutMs: 10000})
|
|
277
|
-
→ page.get_state (verify URL changed)
|
|
278
294
|
→ page.get_console (check for errors)
|
|
279
295
|
→ dom.query('.dashboard', {maxNodes: 15}) (inspect result)
|
|
280
296
|
```
|
|
@@ -291,6 +307,8 @@ dom.find_by_role('button', 'Login') → input.click
|
|
|
291
307
|
|
|
292
308
|
`bbx a11y-tree` and `dom.get_accessibility_tree` are sensitive to `maxDepth` and `maxNodes`. Shallow runs can undercount interactive nodes on real pages, so widen those limits before treating a low interactive count as a bug.
|
|
293
309
|
|
|
310
|
+
For control discovery, prefer `compact: true` or `interactiveOnly: true`, then use role/name with `dom.find_by_role` to obtain an input ref. AX `interactive` means semantic/focusable, not currently visible, unobscured, or otherwise actionable; AX results are depth-limited partial topology and include truncation metadata even when `maxNodes` was not reached.
|
|
311
|
+
|
|
294
312
|
> **MCP mode:** If Browser Bridge is connected via MCP (tools named `browser_dom`, `browser_capture`, etc.), use the MCP tools directly - do not shell out to `bbx`. The MCP tools map 1:1 to CLI capabilities. In prompts, `BB MCP` and `Browser Bridge MCP` both work. Do not treat `bbx-mcp` as a skill alias.
|
|
295
313
|
>
|
|
296
314
|
> For open-ended MCP inspection tasks, prefer `browser_investigate` first. It is read-only, designed for cheaper delegated investigation, and falls back to a deterministic sequence when the client cannot delegate. Escalate to `browser_capture` only when the structured investigation is not enough.
|
|
@@ -306,7 +324,7 @@ Every CLI shortcut command produces consistent `{ok, summary, evidence}` JSON. U
|
|
|
306
324
|
## CLI Raw Params Gotchas
|
|
307
325
|
|
|
308
326
|
- Use `selector`, not `scope`, to narrow `dom.find_by_text` and `dom.find_by_role`.
|
|
309
|
-
- Wrap
|
|
327
|
+
- Wrap targeted DOM input as `target: { elementRef }` or `target: { selector }`; `input.press_key` may omit the target to use the active element, `input.scroll_into_view` also accepts `target`, and `cdp.dispatch_key_event` targets the tab. **Do not pass `ref` or `elementRef` at the top level**:
|
|
310
328
|
```bash
|
|
311
329
|
# CORRECT
|
|
312
330
|
bbx call input.click '{"target":{"elementRef":"el_xxx"}}'
|
|
@@ -316,6 +334,9 @@ Every CLI shortcut command produces consistent `{ok, summary, evidence}` JSON. U
|
|
|
316
334
|
bbx call input.click '{"elementRef":"el_xxx"}'
|
|
317
335
|
```
|
|
318
336
|
- `input.drag` uses `source`, `destination`, and optional destination offsets `offsetX` / `offsetY`.
|
|
337
|
+
- `executionMode` accepts `dom` or `cdp` and defaults to `dom`; CDP supports only click, hover, drag, type, and fill. `input.fill.mode` (`auto`, `setter`, `keystrokes`) is a separate DOM strategy.
|
|
338
|
+
- `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.
|
|
339
|
+
- `page.handle_dialog` mutations are not atomically bound to `expectedDialogId`; treat `commandDispatched` as dispatch evidence and verify follow-up state.
|
|
319
340
|
- Raw `screenshot.capture_region` and `screenshot.capture_full_page` return base64 JSON; prefer `bbx screenshot <ref> [outPath]` when one element is enough.
|
|
320
341
|
|
|
321
342
|
## Response Shapes
|
|
@@ -324,7 +345,7 @@ The summarizer auto-detects response types and produces concise summaries:
|
|
|
324
345
|
|
|
325
346
|
Shortcut commands intentionally expose only the common case. Use `bbx call <method> '{...}'` when you need method-specific fields that are not surfaced by a shortcut, such as `tabs.create.active`.
|
|
326
347
|
|
|
327
|
-
`dom.query` results include `registrySize` and may include `_registryPruned: true` after element-ref eviction. `page.get_console` and `page.get_network` include `dropped` when older buffered entries were discarded.
|
|
348
|
+
`dom.query` results include `registrySize` and may include `_registryPruned: true` after element-ref eviction. `page.get_console` and `page.get_network` include `dropped` when older buffered entries were discarded. Targeted click, focus, type, fill, press-key, checked-state, option-selection, hover, and drag results include bounded `resolution` and `execution` metadata; `cdp_press_key` and `scroll_into_view` use separate contracts.
|
|
328
349
|
|
|
329
350
|
| Response Type | Detection | Summary Format |
|
|
330
351
|
| ---------------- | -------------------------------- | ------------------------------------------------------------ |
|
|
@@ -338,7 +359,7 @@ Shortcut commands intentionally expose only the common case. Use `bbx call <meth
|
|
|
338
359
|
| Element describe | `result.tag + elementRef + bbox` | `Element tag#id: text.` |
|
|
339
360
|
| Computed styles | `result.properties + elementRef` | `Computed N style(s) for ref.` |
|
|
340
361
|
| Box model | `result.content + border` | `Box model: W×H at (x, y).` |
|
|
341
|
-
| Network | `entries
|
|
362
|
+
| Network | `result.source + entries` | `Network: N requests.` |
|
|
342
363
|
| Console | `entries` (no type field) | `Console: N entries.` |
|
|
343
364
|
| Logs | `entries[0].at + method` | `Log: N entries.` |
|
|
344
365
|
| Patch apply | `result.patchId` | `Patch id applied.` |
|