@btraut/browser-bridge 0.14.0 → 0.15.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/CHANGELOG.md +30 -0
- package/README.md +27 -2
- package/dist/api.js +893 -166
- package/dist/api.js.map +4 -4
- package/dist/index.js +349 -115
- package/dist/index.js.map +4 -4
- package/extension/dist/background.js +468 -18
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/content.js +71 -8
- package/extension/dist/content.js.map +2 -2
- package/extension/dist/permissions-request-ui.js +111 -0
- package/extension/dist/permissions-request-ui.js.map +7 -0
- package/extension/manifest.json +2 -2
- package/package.json +1 -1
- package/skills/browser-bridge/SKILL.md +9 -0
- package/skills/browser-bridge/skill.json +1 -1
package/dist/index.js
CHANGED
|
@@ -663,9 +663,10 @@ var createCoreReadinessController = (options = {}) => {
|
|
|
663
663
|
return;
|
|
664
664
|
}
|
|
665
665
|
if (!ensurePromise) {
|
|
666
|
-
ensurePromise =
|
|
666
|
+
ensurePromise = (async () => {
|
|
667
|
+
await ensureCoreRunning();
|
|
668
|
+
})().finally(() => {
|
|
667
669
|
ensurePromise = null;
|
|
668
|
-
throw error;
|
|
669
670
|
});
|
|
670
671
|
}
|
|
671
672
|
await ensurePromise;
|
|
@@ -938,6 +939,63 @@ var SessionCloseInputSchema = SessionIdSchema;
|
|
|
938
939
|
var SessionCloseOutputSchema = import_zod3.z.object({
|
|
939
940
|
ok: import_zod3.z.boolean()
|
|
940
941
|
});
|
|
942
|
+
var PermissionsModeSchema = import_zod3.z.enum(["granular", "bypass"]);
|
|
943
|
+
var PermissionsRequestSourceSchema = import_zod3.z.enum(["cli", "mcp", "api"]);
|
|
944
|
+
var PermissionsPendingRequestKindSchema = import_zod3.z.enum([
|
|
945
|
+
"allow_site",
|
|
946
|
+
"revoke_site",
|
|
947
|
+
"set_mode"
|
|
948
|
+
]);
|
|
949
|
+
var PermissionsPendingRequestStatusSchema = import_zod3.z.enum([
|
|
950
|
+
"pending",
|
|
951
|
+
"approved",
|
|
952
|
+
"denied",
|
|
953
|
+
"timed_out"
|
|
954
|
+
]);
|
|
955
|
+
var PermissionsSiteEntrySchema = import_zod3.z.object({
|
|
956
|
+
site: import_zod3.z.string().min(1),
|
|
957
|
+
created_at: import_zod3.z.string().datetime(),
|
|
958
|
+
last_used_at: import_zod3.z.string().datetime()
|
|
959
|
+
});
|
|
960
|
+
var PermissionsListInputSchema = import_zod3.z.object({}).strict().default({});
|
|
961
|
+
var PermissionsListOutputSchema = import_zod3.z.object({
|
|
962
|
+
sites: import_zod3.z.array(PermissionsSiteEntrySchema)
|
|
963
|
+
});
|
|
964
|
+
var PermissionsGetModeInputSchema = import_zod3.z.object({}).strict().default({});
|
|
965
|
+
var PermissionsGetModeOutputSchema = import_zod3.z.object({
|
|
966
|
+
mode: PermissionsModeSchema
|
|
967
|
+
});
|
|
968
|
+
var PermissionsPendingRequestSchema = import_zod3.z.object({
|
|
969
|
+
request_id: import_zod3.z.string().min(1),
|
|
970
|
+
kind: PermissionsPendingRequestKindSchema,
|
|
971
|
+
status: PermissionsPendingRequestStatusSchema,
|
|
972
|
+
requested_at: import_zod3.z.string().datetime(),
|
|
973
|
+
site: import_zod3.z.string().min(1).optional(),
|
|
974
|
+
mode: PermissionsModeSchema.optional(),
|
|
975
|
+
source: PermissionsRequestSourceSchema.optional(),
|
|
976
|
+
warning: import_zod3.z.string().optional(),
|
|
977
|
+
message: import_zod3.z.string().optional()
|
|
978
|
+
});
|
|
979
|
+
var PermissionsListPendingRequestsInputSchema = import_zod3.z.object({}).strict().default({});
|
|
980
|
+
var PermissionsListPendingRequestsOutputSchema = import_zod3.z.object({
|
|
981
|
+
requests: import_zod3.z.array(PermissionsPendingRequestSchema)
|
|
982
|
+
});
|
|
983
|
+
var PermissionsRequestAllowSiteInputSchema = import_zod3.z.object({
|
|
984
|
+
site: import_zod3.z.string().min(1),
|
|
985
|
+
timeout_ms: import_zod3.z.number().int().positive().max(3e5).optional(),
|
|
986
|
+
source: PermissionsRequestSourceSchema.optional()
|
|
987
|
+
});
|
|
988
|
+
var PermissionsRequestRevokeSiteInputSchema = import_zod3.z.object({
|
|
989
|
+
site: import_zod3.z.string().min(1),
|
|
990
|
+
timeout_ms: import_zod3.z.number().int().positive().max(3e5).optional(),
|
|
991
|
+
source: PermissionsRequestSourceSchema.optional()
|
|
992
|
+
});
|
|
993
|
+
var PermissionsRequestSetModeInputSchema = import_zod3.z.object({
|
|
994
|
+
mode: PermissionsModeSchema,
|
|
995
|
+
timeout_ms: import_zod3.z.number().int().positive().max(3e5).optional(),
|
|
996
|
+
source: PermissionsRequestSourceSchema.optional()
|
|
997
|
+
});
|
|
998
|
+
var PermissionsRequestOutputSchema = PermissionsPendingRequestSchema;
|
|
941
999
|
var DriveWaitConditionSchema = import_zod3.z.object({
|
|
942
1000
|
kind: import_zod3.z.enum(["locator_visible", "text_present", "url_matches"]),
|
|
943
1001
|
value: import_zod3.z.string().min(1)
|
|
@@ -1124,6 +1182,12 @@ var FormFieldInfoSchema = import_zod3.z.object({
|
|
|
1124
1182
|
name: import_zod3.z.string(),
|
|
1125
1183
|
type: import_zod3.z.string(),
|
|
1126
1184
|
value: import_zod3.z.string(),
|
|
1185
|
+
selector: import_zod3.z.string().optional(),
|
|
1186
|
+
label: import_zod3.z.string().optional(),
|
|
1187
|
+
placeholder: import_zod3.z.string().optional(),
|
|
1188
|
+
checked: import_zod3.z.boolean().optional(),
|
|
1189
|
+
disabled: import_zod3.z.boolean().optional(),
|
|
1190
|
+
visible: import_zod3.z.boolean().optional(),
|
|
1127
1191
|
options: import_zod3.z.array(import_zod3.z.string()).optional()
|
|
1128
1192
|
});
|
|
1129
1193
|
var FormInfoSchema = import_zod3.z.object({
|
|
@@ -1136,7 +1200,31 @@ var StorageEntrySchema = import_zod3.z.object({
|
|
|
1136
1200
|
key: import_zod3.z.string(),
|
|
1137
1201
|
value: import_zod3.z.string()
|
|
1138
1202
|
});
|
|
1203
|
+
var FocusedElementSchema = import_zod3.z.object({
|
|
1204
|
+
selector: import_zod3.z.string().optional(),
|
|
1205
|
+
name: import_zod3.z.string().optional(),
|
|
1206
|
+
label: import_zod3.z.string().optional(),
|
|
1207
|
+
role: import_zod3.z.string().optional(),
|
|
1208
|
+
type: import_zod3.z.string().optional(),
|
|
1209
|
+
text: import_zod3.z.string().optional()
|
|
1210
|
+
});
|
|
1211
|
+
var PageActionSchema = import_zod3.z.object({
|
|
1212
|
+
selector: import_zod3.z.string(),
|
|
1213
|
+
role: import_zod3.z.string(),
|
|
1214
|
+
name: import_zod3.z.string()
|
|
1215
|
+
});
|
|
1216
|
+
var StorageSummarySchema = import_zod3.z.object({
|
|
1217
|
+
localStorageCount: import_zod3.z.number().int().nonnegative(),
|
|
1218
|
+
sessionStorageCount: import_zod3.z.number().int().nonnegative(),
|
|
1219
|
+
cookieCount: import_zod3.z.number().int().nonnegative()
|
|
1220
|
+
});
|
|
1139
1221
|
var PageStateSchema = import_zod3.z.object({
|
|
1222
|
+
url: import_zod3.z.string().optional(),
|
|
1223
|
+
title: import_zod3.z.string().optional(),
|
|
1224
|
+
readyState: import_zod3.z.string().optional(),
|
|
1225
|
+
focused: FocusedElementSchema.optional(),
|
|
1226
|
+
primaryActions: import_zod3.z.array(PageActionSchema).optional(),
|
|
1227
|
+
storageSummary: StorageSummarySchema.optional(),
|
|
1140
1228
|
forms: import_zod3.z.array(FormInfoSchema),
|
|
1141
1229
|
localStorage: import_zod3.z.array(StorageEntrySchema),
|
|
1142
1230
|
sessionStorage: import_zod3.z.array(StorageEntrySchema),
|
|
@@ -1199,6 +1287,7 @@ var InspectFindOutputSchema = import_zod3.z.object({
|
|
|
1199
1287
|
warnings: import_zod3.z.array(import_zod3.z.string()).optional()
|
|
1200
1288
|
});
|
|
1201
1289
|
var InspectPageStateInputSchema = SessionIdSchema.extend({
|
|
1290
|
+
include_values: import_zod3.z.boolean().default(false),
|
|
1202
1291
|
target: TargetHintSchema.optional()
|
|
1203
1292
|
});
|
|
1204
1293
|
var InspectPageStateOutputSchema = PageStateSchema;
|
|
@@ -1209,6 +1298,7 @@ var InspectExtractContentFormatSchema = import_zod3.z.enum([
|
|
|
1209
1298
|
]);
|
|
1210
1299
|
var InspectExtractContentInputSchema = SessionIdSchema.extend({
|
|
1211
1300
|
format: InspectExtractContentFormatSchema.default("markdown"),
|
|
1301
|
+
consistency: InspectConsistencySchema.default("quiesce"),
|
|
1212
1302
|
include_metadata: import_zod3.z.boolean().default(true),
|
|
1213
1303
|
target: TargetHintSchema.optional()
|
|
1214
1304
|
});
|
|
@@ -1221,6 +1311,7 @@ var InspectExtractContentOutputSchema = import_zod3.z.object({
|
|
|
1221
1311
|
warnings: import_zod3.z.array(import_zod3.z.string()).optional()
|
|
1222
1312
|
});
|
|
1223
1313
|
var InspectConsoleListInputSchema = SessionIdSchema.extend({
|
|
1314
|
+
since: import_zod3.z.string().optional(),
|
|
1224
1315
|
target: TargetHintSchema.optional()
|
|
1225
1316
|
});
|
|
1226
1317
|
var ConsoleSourceLocationSchema = import_zod3.z.object({
|
|
@@ -1326,6 +1417,7 @@ var import_zod4 = require("zod");
|
|
|
1326
1417
|
|
|
1327
1418
|
// packages/cli/src/core-client.ts
|
|
1328
1419
|
var import_node_child_process = require("node:child_process");
|
|
1420
|
+
var import_node_fs3 = require("node:fs");
|
|
1329
1421
|
var import_node_path3 = require("node:path");
|
|
1330
1422
|
var CoreClientError = class extends Error {
|
|
1331
1423
|
constructor(info) {
|
|
@@ -1349,6 +1441,7 @@ var resolveTimeoutMs2 = (timeoutMs) => {
|
|
|
1349
1441
|
var normalizePath = (path9) => path9.startsWith("/") ? path9 : `/${path9}`;
|
|
1350
1442
|
var durationMs = (startedAt) => Number((Number(process.hrtime.bigint() - startedAt) / 1e6).toFixed(3));
|
|
1351
1443
|
var MAX_RESPONSE_PREVIEW_LENGTH = 200;
|
|
1444
|
+
var STALE_DAEMON_GRACE_MS = 1e3;
|
|
1352
1445
|
var normalizeResponsePreview = (raw) => {
|
|
1353
1446
|
const normalized = raw.replace(/\s+/g, " ").trim();
|
|
1354
1447
|
if (normalized.length <= MAX_RESPONSE_PREVIEW_LENGTH) {
|
|
@@ -1400,6 +1493,15 @@ var createCoreClient = (options = {}) => {
|
|
|
1400
1493
|
const spawnImpl = options.spawnImpl ?? import_node_child_process.spawn;
|
|
1401
1494
|
const timeoutMs = resolveTimeoutMs2(options.timeoutMs);
|
|
1402
1495
|
const componentVersion = process.env.BROWSER_BRIDGE_VERSION ?? process.env.npm_package_version;
|
|
1496
|
+
const coreEntry = (0, import_node_path3.resolve)(__dirname, "api.js");
|
|
1497
|
+
const currentBuildTimeMs = options.currentBuildTimeMs ?? (() => {
|
|
1498
|
+
try {
|
|
1499
|
+
return (0, import_node_fs3.statSync)(coreEntry).mtimeMs;
|
|
1500
|
+
} catch {
|
|
1501
|
+
return void 0;
|
|
1502
|
+
}
|
|
1503
|
+
})();
|
|
1504
|
+
const killProcess = options.killProcess ?? ((pid) => process.kill(pid));
|
|
1403
1505
|
const readiness = createCoreReadinessController({
|
|
1404
1506
|
host: options.host,
|
|
1405
1507
|
port: options.port,
|
|
@@ -1411,7 +1513,7 @@ var createCoreClient = (options = {}) => {
|
|
|
1411
1513
|
logger,
|
|
1412
1514
|
logPrefix: "cli.core",
|
|
1413
1515
|
spawnDaemon: (runtime) => {
|
|
1414
|
-
const
|
|
1516
|
+
const coreEntry2 = (0, import_node_path3.resolve)(__dirname, "api.js");
|
|
1415
1517
|
const startOptions = [];
|
|
1416
1518
|
if (runtime.hostSource === "option" || runtime.hostSource === "env") {
|
|
1417
1519
|
startOptions.push(`host: ${JSON.stringify(runtime.host)}`);
|
|
@@ -1420,7 +1522,7 @@ var createCoreClient = (options = {}) => {
|
|
|
1420
1522
|
startOptions.push(`port: ${runtime.port}`);
|
|
1421
1523
|
}
|
|
1422
1524
|
const script = `const { startCoreServer } = require(${JSON.stringify(
|
|
1423
|
-
|
|
1525
|
+
coreEntry2
|
|
1424
1526
|
)});
|
|
1425
1527
|
startCoreServer({ ${startOptions.join(
|
|
1426
1528
|
", "
|
|
@@ -1557,8 +1659,60 @@ startCoreServer({ ${startOptions.join(
|
|
|
1557
1659
|
clearTimeout(timeout);
|
|
1558
1660
|
}
|
|
1559
1661
|
};
|
|
1560
|
-
const
|
|
1662
|
+
const maybeRestartStaleDaemon = async () => {
|
|
1663
|
+
if (currentBuildTimeMs === void 0) {
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
let payload;
|
|
1667
|
+
try {
|
|
1668
|
+
payload = await requestJson(
|
|
1669
|
+
"POST",
|
|
1670
|
+
"/health/check",
|
|
1671
|
+
{}
|
|
1672
|
+
);
|
|
1673
|
+
} catch {
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
if (!payload.ok || !payload.result?.started_at) {
|
|
1677
|
+
return;
|
|
1678
|
+
}
|
|
1679
|
+
const startedAtMs = Date.parse(payload.result.started_at);
|
|
1680
|
+
if (!Number.isFinite(startedAtMs)) {
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
if (startedAtMs + STALE_DAEMON_GRACE_MS >= currentBuildTimeMs) {
|
|
1684
|
+
return;
|
|
1685
|
+
}
|
|
1686
|
+
const pidValue = payload.result.pid;
|
|
1687
|
+
if (!Number.isInteger(pidValue) || pidValue === process.pid) {
|
|
1688
|
+
return;
|
|
1689
|
+
}
|
|
1690
|
+
const pid = pidValue;
|
|
1691
|
+
logger.warn("cli.core.ensure_ready.stale_daemon", {
|
|
1692
|
+
base_url: readiness.baseUrl,
|
|
1693
|
+
pid,
|
|
1694
|
+
started_at: payload.result.started_at,
|
|
1695
|
+
current_build_time_ms: currentBuildTimeMs
|
|
1696
|
+
});
|
|
1697
|
+
try {
|
|
1698
|
+
killProcess(pid);
|
|
1699
|
+
} catch (error) {
|
|
1700
|
+
logger.warn("cli.core.ensure_ready.stale_daemon_kill_failed", {
|
|
1701
|
+
base_url: readiness.baseUrl,
|
|
1702
|
+
pid,
|
|
1703
|
+
error
|
|
1704
|
+
});
|
|
1705
|
+
return;
|
|
1706
|
+
}
|
|
1707
|
+
await new Promise((resolve4) => setTimeout(resolve4, 150));
|
|
1561
1708
|
await readiness.ensureReady();
|
|
1709
|
+
};
|
|
1710
|
+
const ensureReady = async () => {
|
|
1711
|
+
await readiness.ensureReady();
|
|
1712
|
+
await maybeRestartStaleDaemon();
|
|
1713
|
+
};
|
|
1714
|
+
const post = async (path9, body) => {
|
|
1715
|
+
await ensureReady();
|
|
1562
1716
|
readiness.refreshRuntime();
|
|
1563
1717
|
const payload = path9 === "/diagnostics/doctor" && (!body || typeof body === "object" && !Array.isArray(body)) ? {
|
|
1564
1718
|
...body && typeof body === "object" ? body : {},
|
|
@@ -1586,7 +1740,7 @@ startCoreServer({ ${startOptions.join(
|
|
|
1586
1740
|
get baseUrl() {
|
|
1587
1741
|
return readiness.baseUrl;
|
|
1588
1742
|
},
|
|
1589
|
-
ensureReady
|
|
1743
|
+
ensureReady,
|
|
1590
1744
|
post
|
|
1591
1745
|
};
|
|
1592
1746
|
};
|
|
@@ -1865,6 +2019,7 @@ var registerDiagnosticsCommands = (program2) => {
|
|
|
1865
2019
|
|
|
1866
2020
|
// packages/cli/src/commands/dev.ts
|
|
1867
2021
|
var ENV_EXTENSION_ID = "BROWSER_BRIDGE_EXTENSION_ID";
|
|
2022
|
+
var INSPECT_PROBE_RETRY_DELAYS_MS = [150, 300, 600];
|
|
1868
2023
|
var normalizeToken = (value) => {
|
|
1869
2024
|
if (typeof value !== "string") {
|
|
1870
2025
|
return void 0;
|
|
@@ -1898,6 +2053,21 @@ var inspectCapabilityReady = (report, expectedExtensionId) => {
|
|
|
1898
2053
|
const extensionIdMatch = !expectedExtensionId || !reportedExtensionId || reportedExtensionId === expectedExtensionId;
|
|
1899
2054
|
return extensionIdMatch && hasPassingCheck(report, "inspect.capability");
|
|
1900
2055
|
};
|
|
2056
|
+
var sleep = async (ms) => {
|
|
2057
|
+
await new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
2058
|
+
};
|
|
2059
|
+
var shouldRetryInspectProbe = (report, expectedExtensionId) => {
|
|
2060
|
+
if (inspectCapabilityReady(report, expectedExtensionId)) {
|
|
2061
|
+
return false;
|
|
2062
|
+
}
|
|
2063
|
+
const observedExtensionId = getReportedExtensionId(report);
|
|
2064
|
+
if (expectedExtensionId && observedExtensionId && observedExtensionId !== expectedExtensionId) {
|
|
2065
|
+
return false;
|
|
2066
|
+
}
|
|
2067
|
+
const extensionConnected = report?.extension?.connected ?? false;
|
|
2068
|
+
const capabilityNegotiated = report?.runtime?.extension?.capability_negotiated === true || hasPassingCheck(report, "runtime.extension.capability_negotiated");
|
|
2069
|
+
return !extensionConnected || !capabilityNegotiated;
|
|
2070
|
+
};
|
|
1901
2071
|
var readDiagnosticReport = async (runtime) => {
|
|
1902
2072
|
const client = createCoreClient({
|
|
1903
2073
|
host: runtime.host,
|
|
@@ -1910,6 +2080,22 @@ var readDiagnosticReport = async (runtime) => {
|
|
|
1910
2080
|
);
|
|
1911
2081
|
return envelope2.ok ? envelope2.result : void 0;
|
|
1912
2082
|
};
|
|
2083
|
+
var readDiagnosticReportWithRetry = async (runtime, expectedExtensionId) => {
|
|
2084
|
+
let report;
|
|
2085
|
+
for (let attempt = 0; attempt <= INSPECT_PROBE_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
2086
|
+
if (attempt > 0) {
|
|
2087
|
+
const delayMs = INSPECT_PROBE_RETRY_DELAYS_MS[attempt - 1] ?? 0;
|
|
2088
|
+
if (delayMs > 0) {
|
|
2089
|
+
await sleep(delayMs);
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
report = await readDiagnosticReport(runtime);
|
|
2093
|
+
if (!shouldRetryInspectProbe(report, expectedExtensionId)) {
|
|
2094
|
+
return report;
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
return report;
|
|
2098
|
+
};
|
|
1913
2099
|
var buildInspectCapabilityError = (runtime, report, expectedExtension) => {
|
|
1914
2100
|
const observedExtensionId = getReportedExtensionId(report);
|
|
1915
2101
|
if (expectedExtension && observedExtensionId && observedExtensionId !== expectedExtension.extensionId) {
|
|
@@ -1973,7 +2159,10 @@ var registerDevCommands = (program2) => {
|
|
|
1973
2159
|
optionExtensionId: options.extensionId,
|
|
1974
2160
|
envExtensionId: process.env[ENV_EXTENSION_ID]
|
|
1975
2161
|
});
|
|
1976
|
-
const report = await
|
|
2162
|
+
const report = await readDiagnosticReportWithRetry(
|
|
2163
|
+
runtime,
|
|
2164
|
+
resolvedExtension?.extensionId
|
|
2165
|
+
);
|
|
1977
2166
|
if (!resolvedExtension) {
|
|
1978
2167
|
const reportedExtensionId = getReportedExtensionId(report);
|
|
1979
2168
|
if (reportedExtensionId) {
|
|
@@ -2440,30 +2629,36 @@ var registerInspectCommands = (program2) => {
|
|
|
2440
2629
|
return client.post("/inspect/find", parsed);
|
|
2441
2630
|
});
|
|
2442
2631
|
});
|
|
2443
|
-
inspect.command("extract-content").description("Extract main content from the page").requiredOption("--session-id <id>", "Session identifier").option("--format <format>", "Output format (markdown, text, article_json)").option(
|
|
2632
|
+
inspect.command("extract-content").description("Extract main content from the page").requiredOption("--session-id <id>", "Session identifier").option("--format <format>", "Output format (markdown, text, article_json)").option(
|
|
2633
|
+
"--consistency <mode>",
|
|
2634
|
+
"Capture consistency (best_effort, quiesce)"
|
|
2635
|
+
).option("--include-metadata", "Include article metadata").option("--no-include-metadata", "Exclude article metadata").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
|
|
2444
2636
|
await runCommand(command, (client) => {
|
|
2445
2637
|
const payload = parseInput(InspectExtractContentInputSchema, {
|
|
2446
2638
|
session_id: options.sessionId,
|
|
2447
2639
|
format: options.format,
|
|
2640
|
+
consistency: options.consistency,
|
|
2448
2641
|
include_metadata: options.includeMetadata,
|
|
2449
2642
|
target: buildTargetHint(options)
|
|
2450
2643
|
});
|
|
2451
2644
|
return client.post("/inspect/extract_content", payload);
|
|
2452
2645
|
});
|
|
2453
2646
|
});
|
|
2454
|
-
inspect.command("page-state").description("Capture form, storage, and cookie state").requiredOption("--session-id <id>", "Session identifier").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
|
|
2647
|
+
inspect.command("page-state").description("Capture form, storage, and cookie state").requiredOption("--session-id <id>", "Session identifier").option("--include-values", "Include captured values instead of redacting").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
|
|
2455
2648
|
await runCommand(command, (client) => {
|
|
2456
2649
|
const payload = parseInput(InspectPageStateInputSchema, {
|
|
2457
2650
|
session_id: options.sessionId,
|
|
2651
|
+
include_values: options.includeValues,
|
|
2458
2652
|
target: buildTargetHint(options)
|
|
2459
2653
|
});
|
|
2460
2654
|
return client.post("/inspect/page_state", payload);
|
|
2461
2655
|
});
|
|
2462
2656
|
});
|
|
2463
|
-
inspect.command("console-list").description("Fetch console entries").requiredOption("--session-id <id>", "Session identifier").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
|
|
2657
|
+
inspect.command("console-list").description("Fetch console entries").requiredOption("--session-id <id>", "Session identifier").option("--since <iso>", "Only include entries at or after this timestamp").option("--tab-id <id>", "Explicit tab identifier").action(async (options, command) => {
|
|
2464
2658
|
await runCommand(command, (client) => {
|
|
2465
2659
|
const payload = parseInput(InspectConsoleListInputSchema, {
|
|
2466
2660
|
session_id: options.sessionId,
|
|
2661
|
+
since: options.since,
|
|
2467
2662
|
target: buildTargetHint(options)
|
|
2468
2663
|
});
|
|
2469
2664
|
return client.post("/inspect/console_list", payload);
|
|
@@ -2714,6 +2909,10 @@ var readSessionId = (args) => {
|
|
|
2714
2909
|
const sessionId = args.session_id;
|
|
2715
2910
|
return typeof sessionId === "string" && sessionId.length > 0 ? sessionId : void 0;
|
|
2716
2911
|
};
|
|
2912
|
+
var withPermissionsSource = (source) => (args) => isRecord(args) ? {
|
|
2913
|
+
...args,
|
|
2914
|
+
source
|
|
2915
|
+
} : args;
|
|
2717
2916
|
var supportsSessionMigration = (corePath) => corePath.startsWith("/drive/") || corePath.startsWith("/inspect/") || corePath.startsWith("/artifacts/") || corePath === "/diagnostics/doctor";
|
|
2718
2917
|
var isSessionNotFoundEnvelope = (envelopeResult) => {
|
|
2719
2918
|
if (envelopeResult.ok) {
|
|
@@ -2827,6 +3026,69 @@ var TOOL_DEFINITIONS = [
|
|
|
2827
3026
|
corePath: "/session/close"
|
|
2828
3027
|
}
|
|
2829
3028
|
},
|
|
3029
|
+
{
|
|
3030
|
+
name: "permissions.list",
|
|
3031
|
+
config: {
|
|
3032
|
+
title: "Permissions List",
|
|
3033
|
+
description: "List allowlisted Browser Bridge sites.",
|
|
3034
|
+
inputSchema: PermissionsListInputSchema,
|
|
3035
|
+
outputSchema: envelope(PermissionsListOutputSchema),
|
|
3036
|
+
corePath: "/permissions/list"
|
|
3037
|
+
}
|
|
3038
|
+
},
|
|
3039
|
+
{
|
|
3040
|
+
name: "permissions.get_mode",
|
|
3041
|
+
config: {
|
|
3042
|
+
title: "Permissions Get Mode",
|
|
3043
|
+
description: "Read the current Browser Bridge permissions mode.",
|
|
3044
|
+
inputSchema: PermissionsGetModeInputSchema,
|
|
3045
|
+
outputSchema: envelope(PermissionsGetModeOutputSchema),
|
|
3046
|
+
corePath: "/permissions/get_mode"
|
|
3047
|
+
}
|
|
3048
|
+
},
|
|
3049
|
+
{
|
|
3050
|
+
name: "permissions.list_pending_requests",
|
|
3051
|
+
config: {
|
|
3052
|
+
title: "Permissions List Pending Requests",
|
|
3053
|
+
description: "List pending external Browser Bridge permission-change requests.",
|
|
3054
|
+
inputSchema: PermissionsListPendingRequestsInputSchema,
|
|
3055
|
+
outputSchema: envelope(PermissionsListPendingRequestsOutputSchema),
|
|
3056
|
+
corePath: "/permissions/list_pending_requests"
|
|
3057
|
+
}
|
|
3058
|
+
},
|
|
3059
|
+
{
|
|
3060
|
+
name: "permissions.request_allow_site",
|
|
3061
|
+
config: {
|
|
3062
|
+
title: "Permissions Request Allow Site",
|
|
3063
|
+
description: "Request allowlisting a site. A human must approve the change in Chrome before it applies.",
|
|
3064
|
+
inputSchema: PermissionsRequestAllowSiteInputSchema,
|
|
3065
|
+
outputSchema: envelope(PermissionsRequestOutputSchema),
|
|
3066
|
+
corePath: "/permissions/request_allow_site",
|
|
3067
|
+
transformInput: withPermissionsSource("mcp")
|
|
3068
|
+
}
|
|
3069
|
+
},
|
|
3070
|
+
{
|
|
3071
|
+
name: "permissions.request_revoke_site",
|
|
3072
|
+
config: {
|
|
3073
|
+
title: "Permissions Request Revoke Site",
|
|
3074
|
+
description: "Request revoking a site from the allowlist. A human must approve the change in Chrome before it applies.",
|
|
3075
|
+
inputSchema: PermissionsRequestRevokeSiteInputSchema,
|
|
3076
|
+
outputSchema: envelope(PermissionsRequestOutputSchema),
|
|
3077
|
+
corePath: "/permissions/request_revoke_site",
|
|
3078
|
+
transformInput: withPermissionsSource("mcp")
|
|
3079
|
+
}
|
|
3080
|
+
},
|
|
3081
|
+
{
|
|
3082
|
+
name: "permissions.request_set_mode",
|
|
3083
|
+
config: {
|
|
3084
|
+
title: "Permissions Request Set Mode",
|
|
3085
|
+
description: "Request changing Browser Bridge permission mode. A human must approve the change in Chrome before it applies.",
|
|
3086
|
+
inputSchema: PermissionsRequestSetModeInputSchema,
|
|
3087
|
+
outputSchema: envelope(PermissionsRequestOutputSchema),
|
|
3088
|
+
corePath: "/permissions/request_set_mode",
|
|
3089
|
+
transformInput: withPermissionsSource("mcp")
|
|
3090
|
+
}
|
|
3091
|
+
},
|
|
2830
3092
|
{
|
|
2831
3093
|
name: "drive.navigate",
|
|
2832
3094
|
config: {
|
|
@@ -4052,107 +4314,6 @@ var import_readability = require("@mozilla/readability");
|
|
|
4052
4314
|
var import_jsdom = require("jsdom");
|
|
4053
4315
|
var import_turndown = __toESM(require("turndown"));
|
|
4054
4316
|
|
|
4055
|
-
// packages/core/src/page-state-script.ts
|
|
4056
|
-
var PAGE_STATE_SCRIPT = [
|
|
4057
|
-
"(() => {",
|
|
4058
|
-
" const escape = (value) => {",
|
|
4059
|
-
" if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {",
|
|
4060
|
-
" return CSS.escape(value);",
|
|
4061
|
-
" }",
|
|
4062
|
-
` return String(value).replace(/["'\\\\]/g, '\\\\$&');`,
|
|
4063
|
-
" };",
|
|
4064
|
-
" const truncate = (value, max) => {",
|
|
4065
|
-
" const text = String(value ?? '');",
|
|
4066
|
-
" return text.length > max ? text.slice(0, max) : text;",
|
|
4067
|
-
" };",
|
|
4068
|
-
" const selectorFor = (element) => {",
|
|
4069
|
-
" if (element.id) {",
|
|
4070
|
-
" return `#${escape(element.id)}`;",
|
|
4071
|
-
" }",
|
|
4072
|
-
" const name = element.getAttribute('name');",
|
|
4073
|
-
" if (name) {",
|
|
4074
|
-
' return `${element.tagName.toLowerCase()}[name="${escape(name)}"]`;',
|
|
4075
|
-
" }",
|
|
4076
|
-
" const parts = [];",
|
|
4077
|
-
" let node = element;",
|
|
4078
|
-
" while (node && node.nodeType === 1 && parts.length < 4) {",
|
|
4079
|
-
" let part = node.tagName.toLowerCase();",
|
|
4080
|
-
" const parent = node.parentElement;",
|
|
4081
|
-
" if (parent) {",
|
|
4082
|
-
" const siblings = Array.from(parent.children).filter(",
|
|
4083
|
-
" (child) => child.tagName === node.tagName",
|
|
4084
|
-
" );",
|
|
4085
|
-
" if (siblings.length > 1) {",
|
|
4086
|
-
" part += `:nth-of-type(${siblings.indexOf(node) + 1})`;",
|
|
4087
|
-
" }",
|
|
4088
|
-
" }",
|
|
4089
|
-
" parts.unshift(part);",
|
|
4090
|
-
" node = parent;",
|
|
4091
|
-
" }",
|
|
4092
|
-
" return parts.join('>');",
|
|
4093
|
-
" };",
|
|
4094
|
-
" const readStorage = (storage, limit) => {",
|
|
4095
|
-
" try {",
|
|
4096
|
-
" return Object.keys(storage)",
|
|
4097
|
-
" .slice(0, limit)",
|
|
4098
|
-
" .map((key) => ({",
|
|
4099
|
-
" key,",
|
|
4100
|
-
" value: truncate(storage.getItem(key), 500),",
|
|
4101
|
-
" }));",
|
|
4102
|
-
" } catch {",
|
|
4103
|
-
" return [];",
|
|
4104
|
-
" }",
|
|
4105
|
-
" };",
|
|
4106
|
-
" const forms = Array.from(document.querySelectorAll('form')).map((form) => {",
|
|
4107
|
-
" const fields = Array.from(form.elements)",
|
|
4108
|
-
" .filter((element) => element && element.tagName)",
|
|
4109
|
-
" .map((element) => {",
|
|
4110
|
-
" const tag = element.tagName.toLowerCase();",
|
|
4111
|
-
" const type = 'type' in element && element.type ? element.type : tag;",
|
|
4112
|
-
" const name = element.name || element.getAttribute('name') || element.id || '';",
|
|
4113
|
-
" let value = '';",
|
|
4114
|
-
" let options;",
|
|
4115
|
-
" if (tag === 'select') {",
|
|
4116
|
-
" const select = element;",
|
|
4117
|
-
" value = select.value ?? '';",
|
|
4118
|
-
" options = Array.from(select.options).map((option) => option.text);",
|
|
4119
|
-
" } else if (tag === 'input' && element.type === 'password') {",
|
|
4120
|
-
" value = '[redacted]';",
|
|
4121
|
-
" } else if (tag === 'input' || tag === 'textarea') {",
|
|
4122
|
-
" value = element.value ?? '';",
|
|
4123
|
-
" } else if (element.isContentEditable) {",
|
|
4124
|
-
" value = element.textContent ?? '';",
|
|
4125
|
-
" } else if ('value' in element) {",
|
|
4126
|
-
" value = element.value ?? '';",
|
|
4127
|
-
" }",
|
|
4128
|
-
" return {",
|
|
4129
|
-
" name,",
|
|
4130
|
-
" type,",
|
|
4131
|
-
" value: truncate(value, 500),",
|
|
4132
|
-
" ...(options ? { options } : {}),",
|
|
4133
|
-
" };",
|
|
4134
|
-
" });",
|
|
4135
|
-
" return {",
|
|
4136
|
-
" selector: selectorFor(form),",
|
|
4137
|
-
" action: form.getAttribute('action') || undefined,",
|
|
4138
|
-
" method: form.getAttribute('method') || undefined,",
|
|
4139
|
-
" fields,",
|
|
4140
|
-
" };",
|
|
4141
|
-
" });",
|
|
4142
|
-
" const localStorage = readStorage(window.localStorage, 100);",
|
|
4143
|
-
" const sessionStorage = readStorage(window.sessionStorage, 100);",
|
|
4144
|
-
" const cookies = (document.cookie ? document.cookie.split(';') : [])",
|
|
4145
|
-
" .map((entry) => entry.trim())",
|
|
4146
|
-
" .filter((entry) => entry.length > 0)",
|
|
4147
|
-
" .slice(0, 50)",
|
|
4148
|
-
" .map((entry) => {",
|
|
4149
|
-
" const [key, ...rest] = entry.split('=');",
|
|
4150
|
-
" return { key, value: truncate(rest.join('='), 500) };",
|
|
4151
|
-
" });",
|
|
4152
|
-
" return { forms, localStorage, sessionStorage, cookies };",
|
|
4153
|
-
"})()"
|
|
4154
|
-
].join("\n");
|
|
4155
|
-
|
|
4156
4317
|
// packages/core/src/diagnostics.ts
|
|
4157
4318
|
var STALE_ERROR_THRESHOLD_MS = 2 * 60 * 1e3;
|
|
4158
4319
|
|
|
@@ -4201,6 +4362,78 @@ var registerOpenArtifactsCommand = (program2) => {
|
|
|
4201
4362
|
});
|
|
4202
4363
|
};
|
|
4203
4364
|
|
|
4365
|
+
// packages/cli/src/commands/permissions.ts
|
|
4366
|
+
var parseNumber5 = (value) => {
|
|
4367
|
+
if (value === void 0 || value === null || value === "") {
|
|
4368
|
+
return void 0;
|
|
4369
|
+
}
|
|
4370
|
+
const parsed = Number(value);
|
|
4371
|
+
return Number.isFinite(parsed) ? parsed : Number.NaN;
|
|
4372
|
+
};
|
|
4373
|
+
var registerPermissionsCommands = (program2) => {
|
|
4374
|
+
const permissions = program2.command("permissions").description("Manage Browser Bridge permissions");
|
|
4375
|
+
permissions.command("list").description("List allowlisted sites").action(async (_options, command) => {
|
|
4376
|
+
await runCommand(command, (client) => {
|
|
4377
|
+
const payload = parseInput(PermissionsListInputSchema, {});
|
|
4378
|
+
return client.post("/permissions/list", payload);
|
|
4379
|
+
});
|
|
4380
|
+
});
|
|
4381
|
+
permissions.command("mode").description("Show the current permissions mode").action(async (_options, command) => {
|
|
4382
|
+
await runCommand(command, (client) => {
|
|
4383
|
+
const payload = parseInput(PermissionsGetModeInputSchema, {});
|
|
4384
|
+
return client.post("/permissions/get_mode", payload);
|
|
4385
|
+
});
|
|
4386
|
+
});
|
|
4387
|
+
permissions.command("pending").description("List pending external permission-change requests").action(async (_options, command) => {
|
|
4388
|
+
await runCommand(command, (client) => {
|
|
4389
|
+
const payload = parseInput(
|
|
4390
|
+
PermissionsListPendingRequestsInputSchema,
|
|
4391
|
+
{}
|
|
4392
|
+
);
|
|
4393
|
+
return client.post("/permissions/list_pending_requests", payload);
|
|
4394
|
+
});
|
|
4395
|
+
});
|
|
4396
|
+
permissions.command("allow-site").description("Request allowlisting a site").requiredOption("--site <site>", "Site hostname[:port] to allowlist").option(
|
|
4397
|
+
"--timeout-ms <ms>",
|
|
4398
|
+
"How long to wait for approval before returning"
|
|
4399
|
+
).action(async (options, command) => {
|
|
4400
|
+
await runCommand(command, (client) => {
|
|
4401
|
+
const payload = parseInput(PermissionsRequestAllowSiteInputSchema, {
|
|
4402
|
+
site: options.site,
|
|
4403
|
+
timeout_ms: parseNumber5(options.timeoutMs),
|
|
4404
|
+
source: "cli"
|
|
4405
|
+
});
|
|
4406
|
+
return client.post("/permissions/request_allow_site", payload);
|
|
4407
|
+
});
|
|
4408
|
+
});
|
|
4409
|
+
permissions.command("revoke-site").description("Request revoking a site from the allowlist").requiredOption("--site <site>", "Site hostname[:port] to revoke").option(
|
|
4410
|
+
"--timeout-ms <ms>",
|
|
4411
|
+
"How long to wait for approval before returning"
|
|
4412
|
+
).action(async (options, command) => {
|
|
4413
|
+
await runCommand(command, (client) => {
|
|
4414
|
+
const payload = parseInput(PermissionsRequestRevokeSiteInputSchema, {
|
|
4415
|
+
site: options.site,
|
|
4416
|
+
timeout_ms: parseNumber5(options.timeoutMs),
|
|
4417
|
+
source: "cli"
|
|
4418
|
+
});
|
|
4419
|
+
return client.post("/permissions/request_revoke_site", payload);
|
|
4420
|
+
});
|
|
4421
|
+
});
|
|
4422
|
+
permissions.command("set-mode").description("Request changing the permissions mode").requiredOption("--mode <mode>", "Mode to request (granular or bypass)").option(
|
|
4423
|
+
"--timeout-ms <ms>",
|
|
4424
|
+
"How long to wait for approval before returning"
|
|
4425
|
+
).action(async (options, command) => {
|
|
4426
|
+
await runCommand(command, (client) => {
|
|
4427
|
+
const payload = parseInput(PermissionsRequestSetModeInputSchema, {
|
|
4428
|
+
mode: options.mode,
|
|
4429
|
+
timeout_ms: parseNumber5(options.timeoutMs),
|
|
4430
|
+
source: "cli"
|
|
4431
|
+
});
|
|
4432
|
+
return client.post("/permissions/request_set_mode", payload);
|
|
4433
|
+
});
|
|
4434
|
+
});
|
|
4435
|
+
};
|
|
4436
|
+
|
|
4204
4437
|
// packages/cli/src/commands/session.ts
|
|
4205
4438
|
var registerSessionCommands = (program2) => {
|
|
4206
4439
|
const session = program2.command("session").description("Manage Core sessions");
|
|
@@ -4346,14 +4579,14 @@ var resolveSkillSourceDir = async () => {
|
|
|
4346
4579
|
} catch {
|
|
4347
4580
|
}
|
|
4348
4581
|
const repoRoot = import_node_path8.default.resolve(rootDir, "..", "..");
|
|
4349
|
-
const
|
|
4582
|
+
const repoSkill = import_node_path8.default.join(repoRoot, ".agents", "skills", "browser-bridge");
|
|
4350
4583
|
try {
|
|
4351
|
-
await import_promises4.default.stat(
|
|
4352
|
-
return
|
|
4584
|
+
await import_promises4.default.stat(repoSkill);
|
|
4585
|
+
return repoSkill;
|
|
4353
4586
|
} catch {
|
|
4354
4587
|
}
|
|
4355
4588
|
throw new Error(
|
|
4356
|
-
`Unable to locate packaged skill. Expected ${packaged} (npm install) or ${
|
|
4589
|
+
`Unable to locate packaged skill. Expected ${packaged} (npm install) or ${repoSkill} (repo dev).`
|
|
4357
4590
|
);
|
|
4358
4591
|
};
|
|
4359
4592
|
|
|
@@ -4650,6 +4883,7 @@ var main = async () => {
|
|
|
4650
4883
|
"Output Browser Bridge CLI version"
|
|
4651
4884
|
).option("--host <host>", "Core host (default: 127.0.0.1)").option("--port <port>", "Core port (default: 3210)").option("--json", "Output JSON").option("--no-daemon", "Disable auto-starting Core");
|
|
4652
4885
|
registerSessionCommands(program);
|
|
4886
|
+
registerPermissionsCommands(program);
|
|
4653
4887
|
registerDriveCommands(program);
|
|
4654
4888
|
registerInspectCommands(program);
|
|
4655
4889
|
registerArtifactsCommands(program);
|