@browserbridge/bbx 1.7.4 → 1.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packages/agent-client/src/atomic-write.js +99 -0
- package/packages/agent-client/src/cli-helpers.js +20 -3
- package/packages/agent-client/src/cli.js +271 -74
- package/packages/agent-client/src/command-registry.js +12 -6
- package/packages/agent-client/src/install.js +39 -4
- package/packages/agent-client/src/mcp-config.js +28 -14
- package/packages/agent-client/src/remotes.js +93 -15
- package/packages/agent-client/src/runtime.js +5 -2
- package/packages/mcp-server/src/bin.js +10 -1
- package/packages/mcp-server/src/guidance.js +1 -1
- package/packages/mcp-server/src/handlers-capture.js +8 -5
- package/packages/mcp-server/src/handlers-dom.js +2 -2
- package/packages/mcp-server/src/handlers-navigation.js +20 -9
- package/packages/mcp-server/src/handlers-page.js +111 -111
- package/packages/mcp-server/src/handlers-utils.js +268 -8
- package/packages/mcp-server/src/handlers.js +31 -10
- package/packages/mcp-server/src/lifecycle.js +413 -0
- package/packages/mcp-server/src/server.js +27 -19
- package/packages/protocol/src/defaults.js +2 -0
- package/packages/protocol/src/protocol.js +106 -5
- package/packages/protocol/src/types.ts +19 -1
- package/skills/browser-bridge/SKILL.md +1 -1
|
@@ -6,12 +6,14 @@ import {
|
|
|
6
6
|
DEFAULT_A11Y_MAX_DEPTH,
|
|
7
7
|
DEFAULT_A11Y_MAX_NODES,
|
|
8
8
|
DEFAULT_CONSOLE_LIMIT,
|
|
9
|
+
DEFAULT_DEVICE_SCALE_FACTOR,
|
|
9
10
|
DEFAULT_EVAL_TIMEOUT_MS,
|
|
10
11
|
DEFAULT_LOG_TAIL_LIMIT,
|
|
11
12
|
DEFAULT_MAX_DEPTH,
|
|
12
13
|
DEFAULT_MAX_HTML_LENGTH,
|
|
13
14
|
DEFAULT_MAX_NODES,
|
|
14
15
|
DEFAULT_NAV_TIMEOUT_MS,
|
|
16
|
+
DEFAULT_NETWORK_INTERCEPT_ACTION,
|
|
15
17
|
DEFAULT_NETWORK_LIMIT,
|
|
16
18
|
DEFAULT_PAGE_TEXT_BUDGET,
|
|
17
19
|
DEFAULT_TEXT_BUDGET,
|
|
@@ -42,6 +44,7 @@ import { BRIDGE_METHODS, METHOD_SET, createBridgeMethodGroups } from './registry
|
|
|
42
44
|
/** @typedef {import('./types.js').InputActionParams} InputActionParams */
|
|
43
45
|
/** @typedef {import('./types.js').LogTailParams} LogTailParams */
|
|
44
46
|
/** @typedef {import('./types.js').NavigationActionParams} NavigationActionParams */
|
|
47
|
+
/** @typedef {import('./types.js').NetworkInterceptAddParams} NetworkInterceptAddParams */
|
|
45
48
|
/** @typedef {import('./types.js').NetworkParams} NetworkParams */
|
|
46
49
|
/** @typedef {import('./types.js').NormalizedAccessibilityTreeParams} NormalizedAccessibilityTreeParams */
|
|
47
50
|
/** @typedef {import('./types.js').NormalizedCheckedAction} NormalizedCheckedAction */
|
|
@@ -58,6 +61,7 @@ import { BRIDGE_METHODS, METHOD_SET, createBridgeMethodGroups } from './registry
|
|
|
58
61
|
/** @typedef {import('./types.js').NormalizedInputAction} NormalizedInputAction */
|
|
59
62
|
/** @typedef {import('./types.js').NormalizedLogTailParams} NormalizedLogTailParams */
|
|
60
63
|
/** @typedef {import('./types.js').NormalizedNavigationAction} NormalizedNavigationAction */
|
|
64
|
+
/** @typedef {import('./types.js').NormalizedNetworkInterceptAddParams} NormalizedNetworkInterceptAddParams */
|
|
61
65
|
/** @typedef {import('./types.js').NormalizedNetworkParams} NormalizedNetworkParams */
|
|
62
66
|
/** @typedef {import('./types.js').NormalizedPageTextParams} NormalizedPageTextParams */
|
|
63
67
|
/** @typedef {import('./types.js').NormalizedPatchOperation} NormalizedPatchOperation */
|
|
@@ -151,6 +155,30 @@ function clampInt(value, min, max, fallback) {
|
|
|
151
155
|
return Math.min(Math.max(integer, min), max);
|
|
152
156
|
}
|
|
153
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Clamp a finite number without discarding its fractional component.
|
|
160
|
+
*
|
|
161
|
+
* @param {unknown} value
|
|
162
|
+
* @param {number} min
|
|
163
|
+
* @param {number} max
|
|
164
|
+
* @param {number} fallback
|
|
165
|
+
* @returns {number}
|
|
166
|
+
*/
|
|
167
|
+
function clampNumber(value, min, max, fallback) {
|
|
168
|
+
const numeric = typeof value === 'number' && Number.isFinite(value) ? value : fallback;
|
|
169
|
+
return Math.min(Math.max(numeric, min), max);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @param {unknown} value
|
|
174
|
+
* @returns {value is Record<string, unknown>}
|
|
175
|
+
*/
|
|
176
|
+
function isPlainRecord(value) {
|
|
177
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
178
|
+
const prototype = Object.getPrototypeOf(value);
|
|
179
|
+
return prototype === Object.prototype || prototype === null;
|
|
180
|
+
}
|
|
181
|
+
|
|
154
182
|
/** @type {ReadonlyArray<BridgeMethod>} */
|
|
155
183
|
export const METHODS = BRIDGE_METHODS;
|
|
156
184
|
|
|
@@ -336,6 +364,8 @@ function normalizeRequestParams(method, params) {
|
|
|
336
364
|
return normalizePageTextParams(params);
|
|
337
365
|
case 'page.get_network':
|
|
338
366
|
return normalizeNetworkParams(params);
|
|
367
|
+
case 'network.intercept.add':
|
|
368
|
+
return normalizeNetworkInterceptAddParams(params);
|
|
339
369
|
case 'navigation.navigate':
|
|
340
370
|
case 'navigation.reload':
|
|
341
371
|
case 'navigation.go_back':
|
|
@@ -643,7 +673,7 @@ export function normalizeNavigationAction(params = {}) {
|
|
|
643
673
|
return {
|
|
644
674
|
url,
|
|
645
675
|
waitForLoad: params.waitForLoad !== false,
|
|
646
|
-
timeoutMs: clampInt(params.timeoutMs, 500, 120_000,
|
|
676
|
+
timeoutMs: clampInt(params.timeoutMs, 500, 120_000, DEFAULT_NAV_TIMEOUT_MS),
|
|
647
677
|
};
|
|
648
678
|
}
|
|
649
679
|
|
|
@@ -682,11 +712,17 @@ export function normalizeEvaluateParams(params = {}) {
|
|
|
682
712
|
`Expression too large (${expression.length} chars). Maximum is 100,000.`
|
|
683
713
|
);
|
|
684
714
|
}
|
|
715
|
+
if (params.returnByValue === false) {
|
|
716
|
+
throw new BridgeError(
|
|
717
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
718
|
+
'returnByValue=false is not supported because remote CDP objects cannot be consumed.'
|
|
719
|
+
);
|
|
720
|
+
}
|
|
685
721
|
return {
|
|
686
722
|
expression,
|
|
687
723
|
awaitPromise: Boolean(params.awaitPromise),
|
|
688
|
-
timeoutMs: clampInt(params.timeoutMs, 100, 30_000,
|
|
689
|
-
returnByValue:
|
|
724
|
+
timeoutMs: clampInt(params.timeoutMs, 100, 30_000, DEFAULT_EVAL_TIMEOUT_MS),
|
|
725
|
+
returnByValue: true,
|
|
690
726
|
};
|
|
691
727
|
}
|
|
692
728
|
|
|
@@ -829,7 +865,7 @@ export function normalizeStorageParams(params = {}) {
|
|
|
829
865
|
export function normalizeWaitForLoadStateParams(params = {}) {
|
|
830
866
|
return {
|
|
831
867
|
waitForLoad: params.waitForLoad !== false,
|
|
832
|
-
timeoutMs: clampInt(params.timeoutMs, 500, 120_000,
|
|
868
|
+
timeoutMs: clampInt(params.timeoutMs, 500, 120_000, DEFAULT_NAV_TIMEOUT_MS),
|
|
833
869
|
};
|
|
834
870
|
}
|
|
835
871
|
|
|
@@ -898,6 +934,71 @@ export function normalizeNetworkParams(params = {}) {
|
|
|
898
934
|
};
|
|
899
935
|
}
|
|
900
936
|
|
|
937
|
+
/**
|
|
938
|
+
* @param {NetworkInterceptAddParams} [params={}]
|
|
939
|
+
* @returns {NormalizedNetworkInterceptAddParams}
|
|
940
|
+
*/
|
|
941
|
+
export function normalizeNetworkInterceptAddParams(params = {}) {
|
|
942
|
+
if (typeof params.urlPattern !== 'string' || !params.urlPattern) {
|
|
943
|
+
throw new BridgeError(ERROR_CODES.INVALID_REQUEST, 'urlPattern is required.');
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
const action = params.action ?? DEFAULT_NETWORK_INTERCEPT_ACTION;
|
|
947
|
+
if (action !== 'fulfill' && action !== 'continue' && action !== 'block') {
|
|
948
|
+
throw new BridgeError(
|
|
949
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
950
|
+
'action must be one of fulfill, continue, or block.'
|
|
951
|
+
);
|
|
952
|
+
}
|
|
953
|
+
if (
|
|
954
|
+
params.statusCode !== undefined &&
|
|
955
|
+
(!Number.isInteger(params.statusCode) || params.statusCode < 100 || params.statusCode > 599)
|
|
956
|
+
) {
|
|
957
|
+
throw new BridgeError(
|
|
958
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
959
|
+
'statusCode must be an integer between 100 and 599.'
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
if (params.body !== undefined && typeof params.body !== 'string') {
|
|
963
|
+
throw new BridgeError(ERROR_CODES.INVALID_REQUEST, 'body must be a string.');
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/** @type {Record<string, string> | undefined} */
|
|
967
|
+
let headers;
|
|
968
|
+
if (params.headers !== undefined) {
|
|
969
|
+
if (!isPlainRecord(params.headers)) {
|
|
970
|
+
throw new BridgeError(
|
|
971
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
972
|
+
'headers must be an object containing string values.'
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
headers = {};
|
|
976
|
+
for (const [name, value] of Object.entries(params.headers)) {
|
|
977
|
+
if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name)) {
|
|
978
|
+
throw new BridgeError(
|
|
979
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
980
|
+
`Invalid header name: ${name || '(empty)'}.`
|
|
981
|
+
);
|
|
982
|
+
}
|
|
983
|
+
if (typeof value !== 'string' || /[\r\n]/.test(value)) {
|
|
984
|
+
throw new BridgeError(
|
|
985
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
986
|
+
`Header ${name} must have a string value without newlines.`
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
headers[name] = value;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
return {
|
|
994
|
+
urlPattern: params.urlPattern,
|
|
995
|
+
action,
|
|
996
|
+
...(params.statusCode === undefined ? {} : { statusCode: params.statusCode }),
|
|
997
|
+
...(params.body === undefined ? {} : { body: params.body }),
|
|
998
|
+
...(headers === undefined ? {} : { headers }),
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
|
|
901
1002
|
/**
|
|
902
1003
|
* @param {PageTextParams} [params={}]
|
|
903
1004
|
* @returns {NormalizedPageTextParams}
|
|
@@ -926,7 +1027,7 @@ export function normalizeViewportResizeParams(params = {}) {
|
|
|
926
1027
|
return {
|
|
927
1028
|
width: clampInt(params.width, 320, 7680, DEFAULT_VIEWPORT_WIDTH),
|
|
928
1029
|
height: clampInt(params.height, 200, 4320, DEFAULT_VIEWPORT_HEIGHT),
|
|
929
|
-
deviceScaleFactor:
|
|
1030
|
+
deviceScaleFactor: clampNumber(params.deviceScaleFactor, 0, 4, DEFAULT_DEVICE_SCALE_FACTOR),
|
|
930
1031
|
reset: Boolean(params.reset),
|
|
931
1032
|
};
|
|
932
1033
|
}
|
|
@@ -408,7 +408,7 @@ export interface NormalizedEvaluateParams extends BridgeParams {
|
|
|
408
408
|
expression: string;
|
|
409
409
|
awaitPromise: boolean;
|
|
410
410
|
timeoutMs: number;
|
|
411
|
-
returnByValue:
|
|
411
|
+
returnByValue: true;
|
|
412
412
|
}
|
|
413
413
|
|
|
414
414
|
export interface ConsoleParams {
|
|
@@ -565,6 +565,24 @@ export interface NormalizedNetworkParams extends BridgeParams {
|
|
|
565
565
|
urlPattern: string | null;
|
|
566
566
|
}
|
|
567
567
|
|
|
568
|
+
export type NetworkInterceptAction = 'fulfill' | 'continue' | 'block';
|
|
569
|
+
|
|
570
|
+
export interface NetworkInterceptAddParams {
|
|
571
|
+
urlPattern?: string;
|
|
572
|
+
action?: NetworkInterceptAction;
|
|
573
|
+
statusCode?: number;
|
|
574
|
+
body?: string;
|
|
575
|
+
headers?: Record<string, string>;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
export interface NormalizedNetworkInterceptAddParams extends BridgeParams {
|
|
579
|
+
urlPattern: string;
|
|
580
|
+
action: NetworkInterceptAction;
|
|
581
|
+
statusCode?: number;
|
|
582
|
+
body?: string;
|
|
583
|
+
headers?: Record<string, string>;
|
|
584
|
+
}
|
|
585
|
+
|
|
568
586
|
export interface PageTextParams {
|
|
569
587
|
textBudget?: number;
|
|
570
588
|
}
|
|
@@ -21,7 +21,7 @@ For open-ended investigation, start with structured reads (`page.get_state`, `do
|
|
|
21
21
|
bbx status # daemon + extension health
|
|
22
22
|
bbx doctor # install/access readiness
|
|
23
23
|
bbx access-request # ask user to enable access for the focused window
|
|
24
|
-
bbx restart # start/restart the
|
|
24
|
+
bbx restart # start/restart the daemon and running MCP servers
|
|
25
25
|
bbx call <method> '{...}' # any RPC method (raw output)
|
|
26
26
|
bbx <method> '{...}' # direct alias for an exact bridge method such as page.get_state
|
|
27
27
|
bbx call --tab 123 <method> '{...}' # explicit tab override
|