@browserbridge/bbx 1.5.0 → 1.5.2
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 -1
- package/package.json +1 -1
- package/packages/agent-client/src/command-registry.js +1 -1
- package/packages/agent-client/src/runtime.js +17 -2
- package/packages/mcp-server/src/guidance.js +15 -11
- package/packages/mcp-server/src/server.js +1 -1
- package/packages/native-host/bin/install-manifest.js +2 -2
- package/packages/native-host/src/config.js +38 -8
- package/packages/native-host/src/install-manifest.js +37 -3
- package/skills/browser-bridge/SKILL.md +2 -0
package/README.md
CHANGED
|
@@ -107,11 +107,13 @@ Browser Bridge is optimized for the opposite starting point: **inspect the state
|
|
|
107
107
|
|
|
108
108
|
1. Install [Browser Bridge from the Chrome Web Store](https://chromewebstore.google.com/detail/browser-bridge/jjjkmmcdkpcgamlopogicbnnhdgebhie) in Chrome or another Chromium-based browser
|
|
109
109
|
2. `npm install -g @browserbridge/bbx` - installs the CLI and native host
|
|
110
|
-
3. Run `bbx install
|
|
110
|
+
3. Run `bbx install` (Chromium on Linux, Chrome elsewhere), or target a specific browser with `bbx install --browser chrome`, `bbx install --browser edge`, `bbx install --browser brave`, `bbx install --browser chromium`, or `bbx install --browser arc`
|
|
111
111
|
4. In the extension side panel, install MCP or CLI (skill) for your agent of choice
|
|
112
112
|
5. Enable Browser Bridge for the browser window you want to inspect/control with the AI agent
|
|
113
113
|
6. Ask your agent to use Browser Bridge via MCP (`BB MCP` or `Browser Bridge MCP`), or invoke the installed Browser Bridge skill in CLI mode (`/browser-bridge`, `browser-bridge`, or the client-specific skill trigger)
|
|
114
114
|
|
|
115
|
+
On Ubuntu, Chromium is commonly installed as a strict snap, and Flatpak Chromium is similarly sandboxed. If native messaging stays disconnected there, use a non-sandboxed Chromium-based browser such as Google Chrome, Brave, or Edge.
|
|
116
|
+
|
|
115
117
|
MCP mode is self-contained: the server exposes tools, startup instructions, and prompt templates, so a separate CLI skill is not required for MCP guidance.
|
|
116
118
|
|
|
117
119
|
## How it works
|
|
@@ -129,6 +131,7 @@ MCP mode is self-contained: the server exposes tools, startup instructions, and
|
|
|
129
131
|
- [Quickstart](https://github.com/koltyakov/browser-bridge/blob/main/docs/quickstart.md)
|
|
130
132
|
- [Usage scenarios](https://github.com/koltyakov/browser-bridge/blob/main/docs/usage-scenarios.md)
|
|
131
133
|
- [Manual setup](https://github.com/koltyakov/browser-bridge/blob/main/docs/manual-setup.md)
|
|
134
|
+
- [Agent permissions](https://github.com/koltyakov/browser-bridge/blob/main/docs/agent-permissions.md)
|
|
132
135
|
- [CLI guide](https://github.com/koltyakov/browser-bridge/blob/main/docs/cli-guide.md)
|
|
133
136
|
- [MCP vs CLI](https://github.com/koltyakov/browser-bridge/blob/main/docs/mcp-vs-cli.md)
|
|
134
137
|
- [Troubleshooting](https://github.com/koltyakov/browser-bridge/blob/main/docs/troubleshooting.md)
|
package/package.json
CHANGED
|
@@ -237,7 +237,7 @@ export const CLI_HELP_SECTIONS = Object.freeze([
|
|
|
237
237
|
{
|
|
238
238
|
title: 'Setup',
|
|
239
239
|
lines: [
|
|
240
|
-
'bbx install [extension-id] [--browser chrome|edge|brave|chromium|arc] [--all] Install native messaging manifest',
|
|
240
|
+
'bbx install [extension-id] [--browser chrome|edge|brave|chromium|arc] [--all] Install native messaging manifest (Linux defaults to Chromium)',
|
|
241
241
|
'bbx uninstall Remove native host manifests, Browser Bridge runtime files, and managed MCP/skill installs',
|
|
242
242
|
'bbx install-skill [targets|all] [--global] [--project <path>] Install/update the managed Browser Bridge CLI skill',
|
|
243
243
|
'bbx install-mcp [client|all] [--local] Write MCP config for codex|claude|cursor|copilot|opencode|antigravity|windsurf|agents',
|
|
@@ -21,6 +21,9 @@ import { BridgeClient } from './client.js';
|
|
|
21
21
|
/** @typedef {import('./types.js').DoctorReport} DoctorReport */
|
|
22
22
|
/** @typedef {import('./types.js').DoctorReportOptions} DoctorReportOptions */
|
|
23
23
|
|
|
24
|
+
const CHROMIUM_SANDBOXED_MANIFEST_RE =
|
|
25
|
+
/(?:^|[/\\])(?:snap[/\\]chromium|\.var[/\\]app[/\\]org\.chromium\.Chromium)[/\\]/;
|
|
26
|
+
|
|
24
27
|
/**
|
|
25
28
|
* @param {BridgeClient} client
|
|
26
29
|
* @returns {Promise<void>}
|
|
@@ -113,7 +116,7 @@ export async function withBridgeClient(callback) {
|
|
|
113
116
|
}
|
|
114
117
|
|
|
115
118
|
/**
|
|
116
|
-
* @param {SupportedBrowser} [browser
|
|
119
|
+
* @param {SupportedBrowser} [browser]
|
|
117
120
|
* @returns {string}
|
|
118
121
|
*/
|
|
119
122
|
export function getManifestPath(browser) {
|
|
@@ -121,7 +124,7 @@ export function getManifestPath(browser) {
|
|
|
121
124
|
}
|
|
122
125
|
|
|
123
126
|
/**
|
|
124
|
-
* @param {SupportedBrowser} [browser
|
|
127
|
+
* @param {SupportedBrowser} [browser]
|
|
125
128
|
* @returns {Promise<{allowed_origins?: string[]} | null>}
|
|
126
129
|
*/
|
|
127
130
|
export async function loadInstalledManifest(browser) {
|
|
@@ -164,6 +167,12 @@ export async function getDoctorReport(options = {}) {
|
|
|
164
167
|
|
|
165
168
|
const browserManifests = await (options.checkBrowserManifests || checkBrowserManifests)();
|
|
166
169
|
const manifestInstalled = Boolean(manifest) || browserManifests.some((b) => b.installed);
|
|
170
|
+
const chromiumSandboxedManifestInstalled = browserManifests.some(
|
|
171
|
+
(entry) =>
|
|
172
|
+
entry.installed &&
|
|
173
|
+
entry.browser === 'chromium' &&
|
|
174
|
+
CHROMIUM_SANDBOXED_MANIFEST_RE.test(entry.manifestPath)
|
|
175
|
+
);
|
|
167
176
|
|
|
168
177
|
/** @type {DoctorReport} */
|
|
169
178
|
const report = {
|
|
@@ -228,6 +237,12 @@ export async function getDoctorReport(options = {}) {
|
|
|
228
237
|
}
|
|
229
238
|
if (report.daemonReachable && !report.extensionConnected) {
|
|
230
239
|
report.issues.push('extension_disconnected');
|
|
240
|
+
if (chromiumSandboxedManifestInstalled) {
|
|
241
|
+
report.issues.push('chromium_sandboxed_native_host_limited');
|
|
242
|
+
report.nextSteps.push(
|
|
243
|
+
"Detected a sandboxed Chromium native host manifest for snap or Flatpak. Sandboxed Chromium may not be able to launch Browser Bridge's Node-based native host; use Google Chrome, Brave, or Edge from a non-sandboxed package and run `bbx install --browser <browser>`."
|
|
244
|
+
);
|
|
245
|
+
}
|
|
231
246
|
report.nextSteps.push(
|
|
232
247
|
'Open Chrome and make sure the Browser Bridge extension is installed and active.'
|
|
233
248
|
);
|
|
@@ -7,12 +7,14 @@ import * as z from 'zod/v4';
|
|
|
7
7
|
|
|
8
8
|
export const MCP_SERVER_INSTRUCTIONS = [
|
|
9
9
|
"Browser Bridge MCP inspects and interacts with the user's real Chrome tab through typed MCP tools.",
|
|
10
|
+
'In permission-ask hosts, use browser_call as the default Browser Bridge MCP tool so the user can approve one BBX tool instead of separate browser_status, browser_page, browser_dom, browser_input, and other tools.',
|
|
10
11
|
'Prefer Browser Bridge MCP tools over shelling out to bbx. Use bbx only for explicit CLI setup, doctor, logs, or raw debugging requests.',
|
|
11
|
-
'
|
|
12
|
-
'Use structured reads first:
|
|
12
|
+
'Start with browser_call method health.ping. If window access is disabled, call browser_call method access.request once, ask the user to click Enable in the Browser Bridge popup or side panel, then retry once.',
|
|
13
|
+
'Use structured reads first through browser_call: page.get_state, dom.query, page.get_text, styles.get_computed, layout.get_box_model, or batch. Keep budgets quick or normal before widening.',
|
|
13
14
|
'Reuse elementRef values returned by DOM tools. Use attribute allowlists for focused DOM reads.',
|
|
14
|
-
'Escalate to
|
|
15
|
-
'Use
|
|
15
|
+
'Escalate to screenshot.capture_element, screenshot.capture_region, accessibility_tree, page.evaluate, viewport.resize, or CDP only when structured reads cannot answer the question.',
|
|
16
|
+
'Use patch.apply_styles or patch.apply_dom for temporary experiments, and rollback patches before finishing unless the user asks to keep them.',
|
|
17
|
+
'Only use the specialized Browser Bridge MCP tools directly when the host has already allowed them or the user explicitly wants typed tool calls.',
|
|
16
18
|
].join('\n');
|
|
17
19
|
|
|
18
20
|
export const MCP_GUIDANCE_PROMPT_NAMES = Object.freeze([
|
|
@@ -97,13 +99,15 @@ function createGuidePrompt() {
|
|
|
97
99
|
'Use Browser Bridge MCP for this browser task.',
|
|
98
100
|
'',
|
|
99
101
|
'Rules:',
|
|
100
|
-
'1. Prefer MCP
|
|
101
|
-
'2.
|
|
102
|
-
'3. Start with
|
|
103
|
-
'4.
|
|
104
|
-
'5.
|
|
105
|
-
'6.
|
|
106
|
-
'7.
|
|
102
|
+
'1. Prefer MCP over `bbx`; do not shell out unless setup, doctor, logs, or raw CLI debugging is explicitly needed.',
|
|
103
|
+
'2. In permission-ask hosts, use `browser_call` as the default tool so the user can approve one BBX MCP tool instead of separate tools for status, page, DOM, input, and patches.',
|
|
104
|
+
'3. Start with `browser_call` method `health.ping`. If access is disabled, call `browser_call` method `access.request` once, ask the user to click Enable, then retry once.',
|
|
105
|
+
'4. Start with structured reads via `browser_call`: `page.get_state`, `dom.query`, `dom.find_by_text`, `dom.find_by_role`, `styles.get_computed`, and `batch`.',
|
|
106
|
+
'5. Keep budgets tight with `budgetPreset: "quick"` or `"normal"`; widen only when results are truncated.',
|
|
107
|
+
'6. Reuse `elementRef` values returned by DOM tools instead of rescanning.',
|
|
108
|
+
'7. Escalate to screenshots, accessibility tree, `page.evaluate`, viewport resize, or CDP only when structured reads cannot answer.',
|
|
109
|
+
'8. Use `patch.apply_styles` or `patch.apply_dom` for temporary experiments and rollback before finishing unless the user asks to keep patches.',
|
|
110
|
+
'9. Only use specialized Browser Bridge MCP tools directly when the host has already allowed them or the user explicitly wants typed tool calls.',
|
|
107
111
|
'',
|
|
108
112
|
'Return concise findings with evidence. Edit source code only after the live page behavior is understood.',
|
|
109
113
|
].join('\n')
|
|
@@ -656,7 +656,7 @@ export function createBridgeMcpServer() {
|
|
|
656
656
|
{
|
|
657
657
|
title: 'Raw Browser Bridge Call',
|
|
658
658
|
description:
|
|
659
|
-
'
|
|
659
|
+
'Primary Browser Bridge tool for permission-ask hosts: call any bridge method directly by name so the user can approve one BBX MCP tool instead of each specialized tool separately.',
|
|
660
660
|
inputSchema: {
|
|
661
661
|
method: z.string().describe('Bridge method name (e.g., "dom.query", "input.click")'),
|
|
662
662
|
params: z
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
parseExtensionId,
|
|
10
10
|
uninstallNativeManifest,
|
|
11
11
|
} from '../src/install-manifest.js';
|
|
12
|
-
import { SUPPORTED_BROWSERS } from '../src/config.js';
|
|
12
|
+
import { getDefaultBrowser, SUPPORTED_BROWSERS } from '../src/config.js';
|
|
13
13
|
|
|
14
14
|
/** @typedef {import('../src/config.js').SupportedBrowser} SupportedBrowser */
|
|
15
15
|
|
|
@@ -61,7 +61,7 @@ const targets = installAll
|
|
|
61
61
|
? [...SUPPORTED_BROWSERS]
|
|
62
62
|
: browsers.length > 0
|
|
63
63
|
? browsers
|
|
64
|
-
: [
|
|
64
|
+
: [getDefaultBrowser()];
|
|
65
65
|
|
|
66
66
|
for (const [index, target] of targets.entries()) {
|
|
67
67
|
if (uninstall) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
import fs from 'node:fs';
|
|
3
4
|
import os from 'node:os';
|
|
4
5
|
import path from 'node:path';
|
|
5
6
|
|
|
@@ -189,14 +190,37 @@ export function getLauncherFilename() {
|
|
|
189
190
|
*/
|
|
190
191
|
export const SUPPORTED_BROWSERS = ['chrome', 'edge', 'brave', 'chromium', 'arc'];
|
|
191
192
|
|
|
193
|
+
/**
|
|
194
|
+
* @returns {SupportedBrowser}
|
|
195
|
+
*/
|
|
196
|
+
export function getDefaultBrowser() {
|
|
197
|
+
return os.platform() === 'linux' ? 'chromium' : 'chrome';
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* @param {NodeJS.ProcessEnv} env
|
|
202
|
+
* @param {string} home
|
|
203
|
+
* @returns {string}
|
|
204
|
+
*/
|
|
205
|
+
function getLinuxConfigHome(env, home) {
|
|
206
|
+
if (env.CHROME_CONFIG_HOME) {
|
|
207
|
+
return env.CHROME_CONFIG_HOME;
|
|
208
|
+
}
|
|
209
|
+
if (env.XDG_CONFIG_HOME) {
|
|
210
|
+
return env.XDG_CONFIG_HOME;
|
|
211
|
+
}
|
|
212
|
+
return path.join(home, '.config');
|
|
213
|
+
}
|
|
214
|
+
|
|
192
215
|
/**
|
|
193
216
|
* Return the native messaging host manifest install directory for the given
|
|
194
217
|
* browser on the current platform.
|
|
195
218
|
*
|
|
196
|
-
* @param {SupportedBrowser} [browser=
|
|
219
|
+
* @param {SupportedBrowser} [browser=getDefaultBrowser()]
|
|
220
|
+
* @param {NodeJS.ProcessEnv} [env=process.env]
|
|
197
221
|
* @returns {string}
|
|
198
222
|
*/
|
|
199
|
-
export function getManifestInstallDir(browser =
|
|
223
|
+
export function getManifestInstallDir(browser = getDefaultBrowser(), env = process.env) {
|
|
200
224
|
const platform = os.platform();
|
|
201
225
|
const home = os.homedir();
|
|
202
226
|
|
|
@@ -213,7 +237,7 @@ export function getManifestInstallDir(browser = 'chrome') {
|
|
|
213
237
|
}
|
|
214
238
|
|
|
215
239
|
if (platform === 'win32') {
|
|
216
|
-
const winBase =
|
|
240
|
+
const winBase = env.LOCALAPPDATA || path.join(home, 'AppData', 'Local');
|
|
217
241
|
const winPaths = {
|
|
218
242
|
chrome: path.join(winBase, 'Google', 'Chrome', 'User Data', 'NativeMessagingHosts'),
|
|
219
243
|
edge: path.join(winBase, 'Microsoft', 'Edge', 'User Data', 'NativeMessagingHosts'),
|
|
@@ -231,12 +255,18 @@ export function getManifestInstallDir(browser = 'chrome') {
|
|
|
231
255
|
}
|
|
232
256
|
|
|
233
257
|
// Linux / others
|
|
258
|
+
const linuxConfigHome = getLinuxConfigHome(env, home);
|
|
259
|
+
const chromiumSnapProfile = path.join(home, 'snap', 'chromium', 'common', 'chromium');
|
|
260
|
+
const useChromiumSnapProfile =
|
|
261
|
+
!env.CHROME_CONFIG_HOME && !env.XDG_CONFIG_HOME && fs.existsSync(chromiumSnapProfile);
|
|
234
262
|
const linuxPaths = {
|
|
235
|
-
chrome: path.join(
|
|
236
|
-
edge: path.join(
|
|
237
|
-
brave: path.join(
|
|
238
|
-
chromium:
|
|
239
|
-
|
|
263
|
+
chrome: path.join(linuxConfigHome, 'google-chrome', 'NativeMessagingHosts'),
|
|
264
|
+
edge: path.join(linuxConfigHome, 'microsoft-edge', 'NativeMessagingHosts'),
|
|
265
|
+
brave: path.join(linuxConfigHome, 'BraveSoftware', 'Brave-Browser', 'NativeMessagingHosts'),
|
|
266
|
+
chromium: useChromiumSnapProfile
|
|
267
|
+
? path.join(chromiumSnapProfile, 'NativeMessagingHosts')
|
|
268
|
+
: path.join(linuxConfigHome, 'chromium', 'NativeMessagingHosts'),
|
|
269
|
+
arc: path.join(linuxConfigHome, 'Arc', 'User Data', 'NativeMessagingHosts'),
|
|
240
270
|
};
|
|
241
271
|
return linuxPaths[browser] ?? linuxPaths.chrome;
|
|
242
272
|
}
|
|
@@ -19,6 +19,10 @@ export const DEFAULT_EXTENSION_ID_ENV = 'BROWSER_BRIDGE_EXTENSION_ID';
|
|
|
19
19
|
export const BUILT_IN_EXTENSION_ID_SOURCE = 'built_in';
|
|
20
20
|
export const INSTALL_NATIVE_MANIFEST_ERROR = 'INSTALL_NATIVE_MANIFEST_FAILED';
|
|
21
21
|
|
|
22
|
+
const CHROMIUM_SNAP_NATIVE_MESSAGING_RE = /(?:^|[/\\])snap[/\\]chromium[/\\]/;
|
|
23
|
+
const CHROMIUM_FLATPAK_NATIVE_MESSAGING_RE =
|
|
24
|
+
/(?:^|[/\\])\.var[/\\]app[/\\]org\.chromium\.Chromium[/\\]/;
|
|
25
|
+
|
|
22
26
|
/** @typedef {import('./config.js').SupportedBrowser} SupportedBrowser */
|
|
23
27
|
/** @typedef {'env' | 'built_in' | 'none' | 'invalid_env'} ExtensionIdSource */
|
|
24
28
|
/** @typedef {NodeJS.ErrnoException & { cause?: unknown }} MaybeErrnoError */
|
|
@@ -259,13 +263,13 @@ export async function installNativeManifest(options) {
|
|
|
259
263
|
extensionIdArg,
|
|
260
264
|
browser,
|
|
261
265
|
nodePath = process.execPath,
|
|
262
|
-
|
|
263
|
-
|
|
266
|
+
env = process.env,
|
|
267
|
+
installDir = getManifestInstallDir(browser, env),
|
|
268
|
+
bridgeDir = getBridgeDir(env),
|
|
264
269
|
stdout = process.stdout,
|
|
265
270
|
stderr = process.stderr,
|
|
266
271
|
preserveCustomExtensionId = false,
|
|
267
272
|
writeRegistryValue: writeRegistryValueFn = writeRegistryValue,
|
|
268
|
-
env = process.env,
|
|
269
273
|
} = options;
|
|
270
274
|
|
|
271
275
|
const parsedExtensionId = parseExtensionId(extensionIdArg);
|
|
@@ -360,6 +364,18 @@ exec '${escapeSingleQuotes(nodePath)}' '${escapeSingleQuotes(hostPath)}' "$@"
|
|
|
360
364
|
);
|
|
361
365
|
}
|
|
362
366
|
|
|
367
|
+
if (isChromiumSnapManifestInstall(browser, installDir)) {
|
|
368
|
+
stderr.write(
|
|
369
|
+
'Compatibility warning: detected a Linux Chromium snap native messaging path. Strict snap Chromium commonly blocks launching Browser Bridge\'s Node-based native host with AppArmor, which leaves `bbx status` at "Extension: disconnected". Use a non-snap Chromium-based browser such as Google Chrome, Brave, or Edge and run `bbx install --browser <browser>`.\n'
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (isChromiumFlatpakManifestInstall(browser, installDir)) {
|
|
374
|
+
stderr.write(
|
|
375
|
+
'Compatibility warning: detected a Linux Chromium Flatpak native messaging path. Sandboxed Flatpak Chromium commonly blocks launching Browser Bridge\'s Node-based native host, which leaves `bbx status` at "Extension: disconnected". Use a non-sandboxed Chromium-based browser such as Google Chrome, Brave, or Edge and run `bbx install --browser <browser>`.\n'
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
363
379
|
const hasPlaceholder = allowedOrigins.some((origin) =>
|
|
364
380
|
origin.includes('__REPLACE_WITH_EXTENSION_ID__')
|
|
365
381
|
);
|
|
@@ -378,6 +394,24 @@ exec '${escapeSingleQuotes(nodePath)}' '${escapeSingleQuotes(hostPath)}' "$@"
|
|
|
378
394
|
};
|
|
379
395
|
}
|
|
380
396
|
|
|
397
|
+
/**
|
|
398
|
+
* @param {SupportedBrowser | undefined} browser
|
|
399
|
+
* @param {string} installDir
|
|
400
|
+
* @returns {boolean}
|
|
401
|
+
*/
|
|
402
|
+
function isChromiumSnapManifestInstall(browser, installDir) {
|
|
403
|
+
return browser === 'chromium' && CHROMIUM_SNAP_NATIVE_MESSAGING_RE.test(installDir);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* @param {SupportedBrowser | undefined} browser
|
|
408
|
+
* @param {string} installDir
|
|
409
|
+
* @returns {boolean}
|
|
410
|
+
*/
|
|
411
|
+
function isChromiumFlatpakManifestInstall(browser, installDir) {
|
|
412
|
+
return browser === 'chromium' && CHROMIUM_FLATPAK_NATIVE_MESSAGING_RE.test(installDir);
|
|
413
|
+
}
|
|
414
|
+
|
|
381
415
|
/**
|
|
382
416
|
* @param {UninstallManifestOptions} [options={}]
|
|
383
417
|
* @returns {Promise<{ manifestPath: string, bridgeDir: string, removedManifest: boolean, removedBridgeDir: boolean }>}
|
|
@@ -9,6 +9,8 @@ Token-efficient Chrome tab inspection, interaction, and CSS/DOM patching through
|
|
|
9
9
|
|
|
10
10
|
This CLI skill is for agents that can run shell commands and where direct `bbx` control fits better than MCP tools: manual debugging, terminal reproduction, install/doctor flows, raw protocol access, or environments without MCP.
|
|
11
11
|
|
|
12
|
+
Permission prompts are controlled by the host agent, not by Browser Bridge. In permission-ask MCP hosts, use the generic `browser_call` MCP tool by default so the user can approve one BBX tool instead of separate status, page, DOM, input, and patch tools. In Claude Code CLI mode, allow `bbx` with `Bash(bbx *)` when direct shell access is desired. Exact permission syntax varies by client.
|
|
13
|
+
|
|
12
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.
|
|
13
15
|
When the runtime supports subagents, delegate bridge inspection to a smaller, lower-cost worker and return only concise findings to the parent.
|
|
14
16
|
For open-ended investigation, start with structured reads (`page.get_state`, `dom.query`, `page.get_text`, `styles.get_computed`, `bbx batch`) and escalate to screenshots or debugger-backed methods only when structured evidence is insufficient.
|