@btraut/browser-bridge 0.12.1 → 0.13.1
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 +34 -1
- package/README.md +9 -9
- package/dist/api.js +1109 -447
- package/dist/api.js.map +4 -4
- package/dist/index.js +689 -438
- package/dist/index.js.map +4 -4
- package/extension/dist/background.js +310 -52
- package/extension/dist/background.js.map +3 -3
- package/extension/dist/content.js +42 -4
- package/extension/dist/content.js.map +3 -3
- package/extension/dist/options-ui.js +80 -0
- package/extension/dist/options-ui.js.map +2 -2
- package/extension/manifest.json +14 -4
- package/package.json +1 -1
- package/skills/browser-bridge/SKILL.md +3 -4
- package/skills/browser-bridge/skill.json +1 -1
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// packages/shared/src/contract-version.ts
|
|
2
|
+
var DRIVE_WS_PROTOCOL_VERSION = "2026-02-17.1";
|
|
3
|
+
|
|
1
4
|
// packages/extension/src/error-sanitizer.ts
|
|
2
5
|
var TRAILING_PUNCTUATION_RE = /[.,;:!?]+$/;
|
|
3
6
|
var stripTrailingPunctuation = (value) => {
|
|
@@ -97,7 +100,9 @@ var SITE_ALLOWLIST_KEY = "siteAllowlist";
|
|
|
97
100
|
var PERMISSION_PROMPT_WAIT_MS_KEY = "permissionPromptWaitMs";
|
|
98
101
|
var DEFAULT_PERMISSION_PROMPT_WAIT_MS = 3e4;
|
|
99
102
|
var SITE_PERMISSIONS_MODE_KEY = "sitePermissionsMode";
|
|
103
|
+
var DEBUGGER_CAPABILITY_ENABLED_KEY = "debuggerCapabilityEnabled";
|
|
100
104
|
var DEFAULT_SITE_PERMISSIONS_MODE = "granular";
|
|
105
|
+
var DEFAULT_DEBUGGER_CAPABILITY_ENABLED = false;
|
|
101
106
|
var siteKeyFromUrl = (rawUrl) => {
|
|
102
107
|
if (!rawUrl || typeof rawUrl !== "string") {
|
|
103
108
|
return null;
|
|
@@ -199,6 +204,27 @@ var readPermissionPromptWaitMs = async () => {
|
|
|
199
204
|
);
|
|
200
205
|
});
|
|
201
206
|
};
|
|
207
|
+
var readDebuggerCapabilityEnabled = async () => {
|
|
208
|
+
return await new Promise((resolve) => {
|
|
209
|
+
chrome.storage.local.get(
|
|
210
|
+
[DEBUGGER_CAPABILITY_ENABLED_KEY],
|
|
211
|
+
(result) => {
|
|
212
|
+
const raw = result?.[DEBUGGER_CAPABILITY_ENABLED_KEY];
|
|
213
|
+
if (typeof raw === "boolean") {
|
|
214
|
+
resolve(raw);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
chrome.storage.local.set({
|
|
219
|
+
[DEBUGGER_CAPABILITY_ENABLED_KEY]: DEFAULT_DEBUGGER_CAPABILITY_ENABLED
|
|
220
|
+
});
|
|
221
|
+
} catch {
|
|
222
|
+
}
|
|
223
|
+
resolve(DEFAULT_DEBUGGER_CAPABILITY_ENABLED);
|
|
224
|
+
}
|
|
225
|
+
);
|
|
226
|
+
});
|
|
227
|
+
};
|
|
202
228
|
var isSiteAllowed = async (siteKey) => {
|
|
203
229
|
const key = normalizeSiteKey(siteKey);
|
|
204
230
|
const allowlist = await readAllowlistRaw();
|
|
@@ -410,6 +436,54 @@ var PermissionPromptController = class {
|
|
|
410
436
|
}
|
|
411
437
|
};
|
|
412
438
|
|
|
439
|
+
// packages/extension/src/drive-reliability.ts
|
|
440
|
+
var TRANSIENT_TAB_CHANNEL_ERROR_PATTERNS = [
|
|
441
|
+
"receiving end does not exist",
|
|
442
|
+
"message channel closed before a response was received",
|
|
443
|
+
"the message port closed before a response was received",
|
|
444
|
+
"extension port is moved into back/forward cache"
|
|
445
|
+
];
|
|
446
|
+
var TAB_CHANNEL_RETRY_DELAYS_MS = [120, 200, 320, 500, 750, 1e3, 1200];
|
|
447
|
+
var normalizePathname = (pathname) => {
|
|
448
|
+
if (pathname.length === 0) {
|
|
449
|
+
return "/";
|
|
450
|
+
}
|
|
451
|
+
if (pathname.length > 1 && pathname.endsWith("/")) {
|
|
452
|
+
return pathname.slice(0, -1);
|
|
453
|
+
}
|
|
454
|
+
return pathname;
|
|
455
|
+
};
|
|
456
|
+
var isTransientTabChannelError = (message) => {
|
|
457
|
+
if (typeof message !== "string") {
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
const normalized = message.toLowerCase();
|
|
461
|
+
return TRANSIENT_TAB_CHANNEL_ERROR_PATTERNS.some(
|
|
462
|
+
(pattern) => normalized.includes(pattern)
|
|
463
|
+
);
|
|
464
|
+
};
|
|
465
|
+
var getTabChannelRetryDelayMs = (attempt) => {
|
|
466
|
+
if (!Number.isInteger(attempt) || attempt < 1) {
|
|
467
|
+
return void 0;
|
|
468
|
+
}
|
|
469
|
+
return TAB_CHANNEL_RETRY_DELAYS_MS[attempt - 1];
|
|
470
|
+
};
|
|
471
|
+
var isLikelyNavigationCommitted = (requestedUrl, tabUrl) => {
|
|
472
|
+
if (typeof requestedUrl !== "string" || typeof tabUrl !== "string") {
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
if (requestedUrl === tabUrl) {
|
|
476
|
+
return true;
|
|
477
|
+
}
|
|
478
|
+
try {
|
|
479
|
+
const requested = new URL(requestedUrl);
|
|
480
|
+
const actual = new URL(tabUrl);
|
|
481
|
+
return requested.origin === actual.origin && normalizePathname(requested.pathname) === normalizePathname(actual.pathname) && requested.search === actual.search;
|
|
482
|
+
} catch {
|
|
483
|
+
return requestedUrl === tabUrl;
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
|
|
413
487
|
// packages/extension/src/connection-state.ts
|
|
414
488
|
var toIso = (ms) => new Date(ms).toISOString();
|
|
415
489
|
var ConnectionStateTracker = class {
|
|
@@ -501,9 +575,62 @@ var HISTORY_POST_NAV_DOM_GRACE_TIMEOUT_MS = 2e3;
|
|
|
501
575
|
var AGENT_TAB_ID_KEY = "agentTabId";
|
|
502
576
|
var AGENT_TAB_GROUP_TITLE = "Browser Bridge";
|
|
503
577
|
var AGENT_TAB_BOOTSTRAP_PATH = "agent-tab.html";
|
|
578
|
+
var AGENT_TAB_FAVICON_ASSET_PATH = "assets/icons/icon-32.png";
|
|
579
|
+
var AGENT_TAB_BRANDING_ACTION = "drive.agent_tab_branding";
|
|
580
|
+
var AGENT_TAB_GROUP_RETRY_DELAYS_MS = [0, 120, 300];
|
|
581
|
+
var AGENT_TAB_BRANDING_TIMEOUT_MS = 1500;
|
|
582
|
+
var BASE_NEGOTIATED_CAPABILITIES = Object.freeze({
|
|
583
|
+
"drive.navigate": true,
|
|
584
|
+
"drive.go_back": true,
|
|
585
|
+
"drive.go_forward": true,
|
|
586
|
+
"drive.click": true,
|
|
587
|
+
"drive.hover": true,
|
|
588
|
+
"drive.select": true,
|
|
589
|
+
"drive.type": true,
|
|
590
|
+
"drive.fill_form": true,
|
|
591
|
+
"drive.drag": true,
|
|
592
|
+
"drive.handle_dialog": true,
|
|
593
|
+
"drive.key": true,
|
|
594
|
+
"drive.key_press": true,
|
|
595
|
+
"drive.scroll": true,
|
|
596
|
+
"drive.screenshot": true,
|
|
597
|
+
"drive.wait_for": true,
|
|
598
|
+
"drive.tab_list": true,
|
|
599
|
+
"drive.tab_activate": true,
|
|
600
|
+
"drive.tab_close": true,
|
|
601
|
+
"drive.ping": true
|
|
602
|
+
});
|
|
603
|
+
var DEBUGGER_CAPABILITY_ACTIONS = [
|
|
604
|
+
"debugger.attach",
|
|
605
|
+
"debugger.detach",
|
|
606
|
+
"debugger.command"
|
|
607
|
+
];
|
|
608
|
+
var buildNegotiatedCapabilities = (debuggerCapabilityEnabled) => {
|
|
609
|
+
const capabilities = {
|
|
610
|
+
...BASE_NEGOTIATED_CAPABILITIES
|
|
611
|
+
};
|
|
612
|
+
for (const action of DEBUGGER_CAPABILITY_ACTIONS) {
|
|
613
|
+
capabilities[action] = debuggerCapabilityEnabled;
|
|
614
|
+
}
|
|
615
|
+
return capabilities;
|
|
616
|
+
};
|
|
617
|
+
var debuggerCapabilityDisabledError = () => {
|
|
618
|
+
return {
|
|
619
|
+
code: "ATTACH_DENIED",
|
|
620
|
+
message: "Debugger capability is disabled. Enable debugger-based inspect in extension options and retry.",
|
|
621
|
+
retryable: false,
|
|
622
|
+
details: {
|
|
623
|
+
reason: "debugger_capability_disabled",
|
|
624
|
+
next_step: "Open Browser Bridge extension options, enable debugger-based inspect, then retry."
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
};
|
|
504
628
|
var getAgentTabBootstrapUrl = () => {
|
|
505
629
|
return typeof chrome.runtime?.getURL === "function" ? chrome.runtime.getURL(AGENT_TAB_BOOTSTRAP_PATH) : AGENT_TAB_BOOTSTRAP_PATH;
|
|
506
630
|
};
|
|
631
|
+
var getAgentTabFaviconUrl = () => {
|
|
632
|
+
return typeof chrome.runtime?.getURL === "function" ? chrome.runtime.getURL(AGENT_TAB_FAVICON_ASSET_PATH) : AGENT_TAB_FAVICON_ASSET_PATH;
|
|
633
|
+
};
|
|
507
634
|
var nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
508
635
|
var makeEventId = /* @__PURE__ */ (() => {
|
|
509
636
|
let counter = 0;
|
|
@@ -872,23 +999,38 @@ var ensureAgentTabGroup = async (tabId, windowId) => {
|
|
|
872
999
|
if (!chrome.tabGroups || typeof chrome.tabGroups.update !== "function") {
|
|
873
1000
|
return;
|
|
874
1001
|
}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
1002
|
+
let lastError;
|
|
1003
|
+
for (const retryDelayMs of AGENT_TAB_GROUP_RETRY_DELAYS_MS) {
|
|
1004
|
+
if (retryDelayMs > 0) {
|
|
1005
|
+
await delayMs(retryDelayMs);
|
|
1006
|
+
}
|
|
1007
|
+
try {
|
|
1008
|
+
const groupId = await wrapChromeCallback(
|
|
1009
|
+
(callback) => chrome.tabs.group(
|
|
1010
|
+
{ tabIds: tabId, createProperties: { windowId } },
|
|
1011
|
+
callback
|
|
1012
|
+
)
|
|
1013
|
+
);
|
|
1014
|
+
await wrapChromeVoid(
|
|
1015
|
+
(callback) => chrome.tabGroups.update(
|
|
1016
|
+
groupId,
|
|
1017
|
+
{ title: AGENT_TAB_GROUP_TITLE },
|
|
1018
|
+
() => callback()
|
|
1019
|
+
)
|
|
1020
|
+
);
|
|
1021
|
+
return;
|
|
1022
|
+
} catch (error) {
|
|
1023
|
+
lastError = error;
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
console.debug("Failed to create/update agent tab group.", lastError);
|
|
1027
|
+
};
|
|
1028
|
+
var ensureAgentTabGroupForTab = async (tabId, tab) => {
|
|
1029
|
+
const windowId = tab.windowId;
|
|
1030
|
+
if (typeof windowId !== "number") {
|
|
1031
|
+
return;
|
|
891
1032
|
}
|
|
1033
|
+
await ensureAgentTabGroup(tabId, windowId);
|
|
892
1034
|
};
|
|
893
1035
|
var createAgentWindow = async () => {
|
|
894
1036
|
const created = await wrapChromeCallback(
|
|
@@ -943,6 +1085,8 @@ var getOrCreateAgentTabId = async () => {
|
|
|
943
1085
|
if (typeof url === "string" && isRestrictedUrl(url)) {
|
|
944
1086
|
throw new Error(`Agent tab points at restricted URL: ${url}`);
|
|
945
1087
|
}
|
|
1088
|
+
await ensureAgentTabGroupForTab(agentTabId, tab);
|
|
1089
|
+
void refreshAgentTabBranding(agentTabId);
|
|
946
1090
|
return agentTabId;
|
|
947
1091
|
} catch {
|
|
948
1092
|
clearAgentTarget();
|
|
@@ -959,6 +1103,8 @@ var getOrCreateAgentTabId = async () => {
|
|
|
959
1103
|
agentTabId = stored;
|
|
960
1104
|
ensureLastActiveAt(stored);
|
|
961
1105
|
markTabActive(stored);
|
|
1106
|
+
await ensureAgentTabGroupForTab(stored, tab);
|
|
1107
|
+
void refreshAgentTabBranding(stored);
|
|
962
1108
|
return stored;
|
|
963
1109
|
} catch {
|
|
964
1110
|
await writeAgentTabId(null);
|
|
@@ -1017,12 +1163,18 @@ var sendToTab = async (tabId, action, params, options) => {
|
|
|
1017
1163
|
chrome.tabs.sendMessage(tabId, message, (response) => {
|
|
1018
1164
|
const error = chrome.runtime.lastError;
|
|
1019
1165
|
if (error) {
|
|
1166
|
+
const retryable = isTransientTabChannelError(error.message);
|
|
1020
1167
|
finish({
|
|
1021
1168
|
ok: false,
|
|
1022
1169
|
error: {
|
|
1023
1170
|
code: "EVALUATION_FAILED",
|
|
1024
1171
|
message: error.message,
|
|
1025
|
-
retryable
|
|
1172
|
+
retryable,
|
|
1173
|
+
...retryable ? {
|
|
1174
|
+
details: {
|
|
1175
|
+
reason: "transient_tab_channel_error"
|
|
1176
|
+
}
|
|
1177
|
+
} : {}
|
|
1026
1178
|
}
|
|
1027
1179
|
});
|
|
1028
1180
|
return;
|
|
@@ -1042,27 +1194,31 @@ var sendToTab = async (tabId, action, params, options) => {
|
|
|
1042
1194
|
});
|
|
1043
1195
|
});
|
|
1044
1196
|
};
|
|
1045
|
-
|
|
1046
|
-
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt += 1) {
|
|
1197
|
+
for (let attempt = 1; ; attempt += 1) {
|
|
1047
1198
|
const result = await attemptSend();
|
|
1048
1199
|
if (result.ok) {
|
|
1049
1200
|
return result;
|
|
1050
1201
|
}
|
|
1051
|
-
|
|
1052
|
-
const isNoReceiver = typeof message === "string" && message.toLowerCase().includes("receiving end does not exist");
|
|
1053
|
-
if (!isNoReceiver || attempt === MAX_ATTEMPTS) {
|
|
1202
|
+
if (!isTransientTabChannelError(result.error?.message)) {
|
|
1054
1203
|
return result;
|
|
1055
1204
|
}
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
ok: false,
|
|
1060
|
-
error: {
|
|
1061
|
-
code: "INTERNAL",
|
|
1062
|
-
message: "Failed to send message to content script.",
|
|
1063
|
-
retryable: false
|
|
1205
|
+
const retryDelayMs = getTabChannelRetryDelayMs(attempt);
|
|
1206
|
+
if (retryDelayMs === void 0) {
|
|
1207
|
+
return result;
|
|
1064
1208
|
}
|
|
1065
|
-
|
|
1209
|
+
await delayMs(retryDelayMs);
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1212
|
+
var refreshAgentTabBranding = async (tabId) => {
|
|
1213
|
+
const result = await sendToTab(
|
|
1214
|
+
tabId,
|
|
1215
|
+
AGENT_TAB_BRANDING_ACTION,
|
|
1216
|
+
{ favicon_url: getAgentTabFaviconUrl() },
|
|
1217
|
+
{ timeoutMs: AGENT_TAB_BRANDING_TIMEOUT_MS }
|
|
1218
|
+
);
|
|
1219
|
+
if (!result.ok) {
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1066
1222
|
};
|
|
1067
1223
|
var waitForHistoryNavigationSignal = async (tabId, timeoutMs) => {
|
|
1068
1224
|
return await new Promise((resolve, reject) => {
|
|
@@ -1290,6 +1446,11 @@ var DriveSocket = class {
|
|
|
1290
1446
|
getConnectionStatus() {
|
|
1291
1447
|
return this.connection.getStatus();
|
|
1292
1448
|
}
|
|
1449
|
+
refreshCapabilities() {
|
|
1450
|
+
void this.sendHello().catch((error) => {
|
|
1451
|
+
console.error("DriveSocket refreshCapabilities failed:", error);
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1293
1454
|
handleSocketUnavailable(socket2, reason) {
|
|
1294
1455
|
if (this.socket !== socket2) {
|
|
1295
1456
|
return;
|
|
@@ -1319,6 +1480,7 @@ var DriveSocket = class {
|
|
|
1319
1480
|
async sendHello() {
|
|
1320
1481
|
const manifest = chrome.runtime.getManifest();
|
|
1321
1482
|
const endpoint = await readCoreEndpointConfig();
|
|
1483
|
+
const debuggerCapabilityEnabled = await readDebuggerCapabilityEnabled();
|
|
1322
1484
|
let tabs = [];
|
|
1323
1485
|
try {
|
|
1324
1486
|
tabs = await queryTabs();
|
|
@@ -1328,6 +1490,8 @@ var DriveSocket = class {
|
|
|
1328
1490
|
}
|
|
1329
1491
|
const params = {
|
|
1330
1492
|
version: manifest.version,
|
|
1493
|
+
protocol_version: DRIVE_WS_PROTOCOL_VERSION,
|
|
1494
|
+
capabilities: buildNegotiatedCapabilities(debuggerCapabilityEnabled),
|
|
1331
1495
|
core_host: endpoint.host,
|
|
1332
1496
|
core_port: endpoint.port,
|
|
1333
1497
|
core_port_source: endpoint.portSource,
|
|
@@ -1402,6 +1566,19 @@ var DriveSocket = class {
|
|
|
1402
1566
|
});
|
|
1403
1567
|
}
|
|
1404
1568
|
}
|
|
1569
|
+
async refreshDebuggerCapabilityState() {
|
|
1570
|
+
const enabled = await readDebuggerCapabilityEnabled();
|
|
1571
|
+
if (!enabled) {
|
|
1572
|
+
await this.detachAllDebuggerSessions();
|
|
1573
|
+
}
|
|
1574
|
+
this.refreshCapabilities();
|
|
1575
|
+
}
|
|
1576
|
+
async handleDebuggerCapabilityChange(enabled) {
|
|
1577
|
+
if (!enabled) {
|
|
1578
|
+
await this.detachAllDebuggerSessions();
|
|
1579
|
+
}
|
|
1580
|
+
this.refreshCapabilities();
|
|
1581
|
+
}
|
|
1405
1582
|
async handleRequest(message) {
|
|
1406
1583
|
let driveMessage = null;
|
|
1407
1584
|
let gatedSiteKey = null;
|
|
@@ -1440,6 +1617,15 @@ var DriveSocket = class {
|
|
|
1440
1617
|
return;
|
|
1441
1618
|
}
|
|
1442
1619
|
if (message.action.startsWith("debugger.")) {
|
|
1620
|
+
if (!await readDebuggerCapabilityEnabled()) {
|
|
1621
|
+
this.sendMessage({
|
|
1622
|
+
id: message.id,
|
|
1623
|
+
action: message.action,
|
|
1624
|
+
status: "error",
|
|
1625
|
+
error: sanitizeDriveErrorInfo(debuggerCapabilityDisabledError())
|
|
1626
|
+
});
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1443
1629
|
await this.handleDebuggerRequest(message);
|
|
1444
1630
|
return;
|
|
1445
1631
|
}
|
|
@@ -1451,8 +1637,6 @@ var DriveSocket = class {
|
|
|
1451
1637
|
"drive.navigate",
|
|
1452
1638
|
"drive.go_back",
|
|
1453
1639
|
"drive.go_forward",
|
|
1454
|
-
"drive.back",
|
|
1455
|
-
"drive.forward",
|
|
1456
1640
|
"drive.click",
|
|
1457
1641
|
"drive.hover",
|
|
1458
1642
|
"drive.select",
|
|
@@ -1629,29 +1813,42 @@ var DriveSocket = class {
|
|
|
1629
1813
|
tabId = await getDefaultTabId();
|
|
1630
1814
|
}
|
|
1631
1815
|
const waitMode = params.wait === "none" || params.wait === "domcontentloaded" ? params.wait : "domcontentloaded";
|
|
1816
|
+
const domContentLoadedSignal = waitMode === "domcontentloaded" ? waitForDomContentLoaded(tabId, 3e4) : null;
|
|
1817
|
+
const warnings = [];
|
|
1632
1818
|
await wrapChromeVoid(
|
|
1633
1819
|
(callback) => chrome.tabs.update(tabId, { url }, () => callback())
|
|
1634
1820
|
);
|
|
1635
1821
|
markTabActive(tabId);
|
|
1636
|
-
if (
|
|
1822
|
+
if (domContentLoadedSignal) {
|
|
1637
1823
|
try {
|
|
1638
|
-
await
|
|
1824
|
+
await domContentLoadedSignal;
|
|
1639
1825
|
} catch (error) {
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1826
|
+
const tab = await getTab(tabId).catch(() => void 0);
|
|
1827
|
+
if (tab && isLikelyNavigationCommitted(url, tab.url ?? void 0)) {
|
|
1828
|
+
warnings.push(
|
|
1829
|
+
"Timed out waiting for DOMContentLoaded, but the tab URL already updated to the requested target."
|
|
1830
|
+
);
|
|
1831
|
+
} else {
|
|
1832
|
+
respondError({
|
|
1833
|
+
code: "TIMEOUT",
|
|
1834
|
+
message: error instanceof Error ? error.message : "Timed out waiting.",
|
|
1835
|
+
retryable: true
|
|
1836
|
+
});
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1646
1839
|
}
|
|
1647
1840
|
}
|
|
1648
|
-
|
|
1841
|
+
if (tabId === agentTabId) {
|
|
1842
|
+
void refreshAgentTabBranding(tabId);
|
|
1843
|
+
}
|
|
1844
|
+
respondOk({
|
|
1845
|
+
ok: true,
|
|
1846
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
1847
|
+
});
|
|
1649
1848
|
return;
|
|
1650
1849
|
}
|
|
1651
1850
|
case "drive.go_back":
|
|
1652
|
-
case "drive.
|
|
1653
|
-
case "drive.go_forward":
|
|
1654
|
-
case "drive.forward": {
|
|
1851
|
+
case "drive.go_forward": {
|
|
1655
1852
|
const params = message.params ?? {};
|
|
1656
1853
|
let tabId = params.tab_id;
|
|
1657
1854
|
if (tabId !== void 0 && typeof tabId !== "number") {
|
|
@@ -1693,11 +1890,18 @@ var DriveSocket = class {
|
|
|
1693
1890
|
}
|
|
1694
1891
|
} catch {
|
|
1695
1892
|
if (!result.ok) {
|
|
1696
|
-
respondError(
|
|
1893
|
+
respondError({
|
|
1894
|
+
...result.error
|
|
1895
|
+
});
|
|
1697
1896
|
return;
|
|
1698
1897
|
}
|
|
1699
1898
|
}
|
|
1700
|
-
|
|
1899
|
+
if (tabId === agentTabId) {
|
|
1900
|
+
void refreshAgentTabBranding(tabId);
|
|
1901
|
+
}
|
|
1902
|
+
respondOk({
|
|
1903
|
+
ok: true
|
|
1904
|
+
});
|
|
1701
1905
|
return;
|
|
1702
1906
|
}
|
|
1703
1907
|
case "drive.tab_list": {
|
|
@@ -3082,6 +3286,9 @@ var DriveSocket = class {
|
|
|
3082
3286
|
}
|
|
3083
3287
|
}
|
|
3084
3288
|
async handleDebuggerEvent(source, method, params) {
|
|
3289
|
+
if (!await readDebuggerCapabilityEnabled()) {
|
|
3290
|
+
return;
|
|
3291
|
+
}
|
|
3085
3292
|
const tabId = source.tabId;
|
|
3086
3293
|
if (typeof tabId !== "number") {
|
|
3087
3294
|
return;
|
|
@@ -3100,6 +3307,9 @@ var DriveSocket = class {
|
|
|
3100
3307
|
return;
|
|
3101
3308
|
}
|
|
3102
3309
|
this.clearDebuggerSession(tabId);
|
|
3310
|
+
if (!await readDebuggerCapabilityEnabled()) {
|
|
3311
|
+
return;
|
|
3312
|
+
}
|
|
3103
3313
|
this.sendDebuggerEvent({
|
|
3104
3314
|
tab_id: tabId,
|
|
3105
3315
|
method: "Debugger.detached",
|
|
@@ -3238,6 +3448,15 @@ var DriveSocket = class {
|
|
|
3238
3448
|
}
|
|
3239
3449
|
return null;
|
|
3240
3450
|
}
|
|
3451
|
+
async detachAllDebuggerSessions() {
|
|
3452
|
+
const tabIds = Array.from(this.debuggerSessions.keys());
|
|
3453
|
+
for (const tabId of tabIds) {
|
|
3454
|
+
const error = await this.detachDebugger(tabId);
|
|
3455
|
+
if (error) {
|
|
3456
|
+
console.warn("DriveSocket detachDebugger failed:", tabId, error);
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
}
|
|
3241
3460
|
async sendDebuggerCommand(tabId, method, params, timeoutMs) {
|
|
3242
3461
|
return await new Promise((resolve, reject) => {
|
|
3243
3462
|
let finished = false;
|
|
@@ -3368,14 +3587,53 @@ chrome.debugger.onDetach.addListener(
|
|
|
3368
3587
|
);
|
|
3369
3588
|
chrome.runtime.onMessage.addListener(
|
|
3370
3589
|
(message, _sender, sendResponse) => {
|
|
3371
|
-
if (!message || typeof message !== "object"
|
|
3590
|
+
if (!message || typeof message !== "object") {
|
|
3372
3591
|
return void 0;
|
|
3373
3592
|
}
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3593
|
+
const action = message.action;
|
|
3594
|
+
if (action === "drive.connection_status") {
|
|
3595
|
+
sendResponse({
|
|
3596
|
+
ok: true,
|
|
3597
|
+
result: socket.getConnectionStatus()
|
|
3598
|
+
});
|
|
3599
|
+
return true;
|
|
3600
|
+
}
|
|
3601
|
+
if (action === "drive.refresh_capabilities") {
|
|
3602
|
+
void socket.refreshDebuggerCapabilityState().then(() => {
|
|
3603
|
+
sendResponse({ ok: true, result: { refreshed: true } });
|
|
3604
|
+
}).catch((error) => {
|
|
3605
|
+
const message2 = error instanceof Error ? error.message : "Failed to refresh capabilities.";
|
|
3606
|
+
sendResponse({ ok: false, error: { message: message2 } });
|
|
3607
|
+
});
|
|
3608
|
+
return true;
|
|
3609
|
+
}
|
|
3610
|
+
return void 0;
|
|
3611
|
+
}
|
|
3612
|
+
);
|
|
3613
|
+
chrome.storage.onChanged.addListener(
|
|
3614
|
+
(changes, areaName) => {
|
|
3615
|
+
if (areaName !== "local") {
|
|
3616
|
+
return;
|
|
3617
|
+
}
|
|
3618
|
+
const debuggerChange = changes[DEBUGGER_CAPABILITY_ENABLED_KEY];
|
|
3619
|
+
if (!debuggerChange) {
|
|
3620
|
+
return;
|
|
3621
|
+
}
|
|
3622
|
+
if (typeof debuggerChange.newValue === "boolean") {
|
|
3623
|
+
void socket.handleDebuggerCapabilityChange(debuggerChange.newValue).catch((error) => {
|
|
3624
|
+
console.error(
|
|
3625
|
+
"DriveSocket handleDebuggerCapabilityChange failed:",
|
|
3626
|
+
error
|
|
3627
|
+
);
|
|
3628
|
+
});
|
|
3629
|
+
return;
|
|
3630
|
+
}
|
|
3631
|
+
void socket.refreshDebuggerCapabilityState().catch((error) => {
|
|
3632
|
+
console.error(
|
|
3633
|
+
"DriveSocket refreshDebuggerCapabilityState failed:",
|
|
3634
|
+
error
|
|
3635
|
+
);
|
|
3377
3636
|
});
|
|
3378
|
-
return true;
|
|
3379
3637
|
}
|
|
3380
3638
|
);
|
|
3381
3639
|
socket.start();
|