@opentabs-dev/browser-extension 0.0.34
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/dist/background-log-state.d.ts +10 -0
- package/dist/background-log-state.d.ts.map +1 -0
- package/dist/background-log-state.js +11 -0
- package/dist/background-log-state.js.map +1 -0
- package/dist/background-message-handlers.d.ts +41 -0
- package/dist/background-message-handlers.d.ts.map +1 -0
- package/dist/background-message-handlers.js +214 -0
- package/dist/background-message-handlers.js.map +1 -0
- package/dist/background.d.ts +2 -0
- package/dist/background.d.ts.map +1 -0
- package/dist/background.js +3780 -0
- package/dist/background.js.map +1 -0
- package/dist/bg-log-state.d.ts +10 -0
- package/dist/bg-log-state.d.ts.map +1 -0
- package/dist/bg-log-state.js +11 -0
- package/dist/bg-log-state.js.map +1 -0
- package/dist/browser-commands/content-commands.d.ts +25 -0
- package/dist/browser-commands/content-commands.d.ts.map +1 -0
- package/dist/browser-commands/content-commands.js +166 -0
- package/dist/browser-commands/content-commands.js.map +1 -0
- package/dist/browser-commands/cookie-commands.d.ts +14 -0
- package/dist/browser-commands/cookie-commands.d.ts.map +1 -0
- package/dist/browser-commands/cookie-commands.js +99 -0
- package/dist/browser-commands/cookie-commands.js.map +1 -0
- package/dist/browser-commands/extension-commands.d.ts +12 -0
- package/dist/browser-commands/extension-commands.d.ts.map +1 -0
- package/dist/browser-commands/extension-commands.js +386 -0
- package/dist/browser-commands/extension-commands.js.map +1 -0
- package/dist/browser-commands/helpers.d.ts +35 -0
- package/dist/browser-commands/helpers.d.ts.map +1 -0
- package/dist/browser-commands/helpers.js +121 -0
- package/dist/browser-commands/helpers.js.map +1 -0
- package/dist/browser-commands/index.d.ts +11 -0
- package/dist/browser-commands/index.d.ts.map +1 -0
- package/dist/browser-commands/index.js +10 -0
- package/dist/browser-commands/index.js.map +1 -0
- package/dist/browser-commands/interaction-commands.d.ts +23 -0
- package/dist/browser-commands/interaction-commands.d.ts.map +1 -0
- package/dist/browser-commands/interaction-commands.js +353 -0
- package/dist/browser-commands/interaction-commands.js.map +1 -0
- package/dist/browser-commands/key-press-command.d.ts +2 -0
- package/dist/browser-commands/key-press-command.d.ts.map +1 -0
- package/dist/browser-commands/key-press-command.js +144 -0
- package/dist/browser-commands/key-press-command.js.map +1 -0
- package/dist/browser-commands/network-commands.d.ts +6 -0
- package/dist/browser-commands/network-commands.d.ts.map +1 -0
- package/dist/browser-commands/network-commands.js +69 -0
- package/dist/browser-commands/network-commands.js.map +1 -0
- package/dist/browser-commands/resource-commands.d.ts +37 -0
- package/dist/browser-commands/resource-commands.d.ts.map +1 -0
- package/dist/browser-commands/resource-commands.js +153 -0
- package/dist/browser-commands/resource-commands.js.map +1 -0
- package/dist/browser-commands/scroll-command.d.ts +2 -0
- package/dist/browser-commands/scroll-command.d.ts.map +1 -0
- package/dist/browser-commands/scroll-command.js +133 -0
- package/dist/browser-commands/scroll-command.js.map +1 -0
- package/dist/browser-commands/tab-commands.d.ts +33 -0
- package/dist/browser-commands/tab-commands.d.ts.map +1 -0
- package/dist/browser-commands/tab-commands.js +121 -0
- package/dist/browser-commands/tab-commands.js.map +1 -0
- package/dist/browser-commands.d.ts +36 -0
- package/dist/browser-commands.d.ts.map +1 -0
- package/dist/browser-commands.js +1931 -0
- package/dist/browser-commands.js.map +1 -0
- package/dist/confirmation-badge.d.ts +17 -0
- package/dist/confirmation-badge.d.ts.map +1 -0
- package/dist/confirmation-badge.js +64 -0
- package/dist/confirmation-badge.js.map +1 -0
- package/dist/constants.d.ts +79 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +79 -0
- package/dist/constants.js.map +1 -0
- package/dist/dispatch-helpers.d.ts +61 -0
- package/dist/dispatch-helpers.d.ts.map +1 -0
- package/dist/dispatch-helpers.js +149 -0
- package/dist/dispatch-helpers.js.map +1 -0
- package/dist/extension-messages.d.ts +146 -0
- package/dist/extension-messages.d.ts.map +1 -0
- package/dist/extension-messages.js +2 -0
- package/dist/extension-messages.js.map +1 -0
- package/dist/iife-injection.d.ts +55 -0
- package/dist/iife-injection.d.ts.map +1 -0
- package/dist/iife-injection.js +474 -0
- package/dist/iife-injection.js.map +1 -0
- package/dist/json-rpc-errors.d.ts +8 -0
- package/dist/json-rpc-errors.d.ts.map +1 -0
- package/dist/json-rpc-errors.js +8 -0
- package/dist/json-rpc-errors.js.map +1 -0
- package/dist/known-methods.d.ts +19 -0
- package/dist/known-methods.d.ts.map +1 -0
- package/dist/known-methods.js +68 -0
- package/dist/known-methods.js.map +1 -0
- package/dist/log-collector.d.ts +45 -0
- package/dist/log-collector.d.ts.map +1 -0
- package/dist/log-collector.js +99 -0
- package/dist/log-collector.js.map +1 -0
- package/dist/message-router.d.ts +28 -0
- package/dist/message-router.d.ts.map +1 -0
- package/dist/message-router.js +367 -0
- package/dist/message-router.js.map +1 -0
- package/dist/messaging.d.ts +15 -0
- package/dist/messaging.d.ts.map +1 -0
- package/dist/messaging.js +41 -0
- package/dist/messaging.js.map +1 -0
- package/dist/network-capture.d.ts +56 -0
- package/dist/network-capture.d.ts.map +1 -0
- package/dist/network-capture.js +374 -0
- package/dist/network-capture.js.map +1 -0
- package/dist/offscreen/index.d.ts +16 -0
- package/dist/offscreen/index.d.ts.map +1 -0
- package/dist/offscreen/index.js +549 -0
- package/dist/offscreen/index.js.map +1 -0
- package/dist/plugin-storage.d.ts +19 -0
- package/dist/plugin-storage.d.ts.map +1 -0
- package/dist/plugin-storage.js +100 -0
- package/dist/plugin-storage.js.map +1 -0
- package/dist/rate-limiter.d.ts +18 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +53 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/resource-prompt-dispatch.d.ts +14 -0
- package/dist/resource-prompt-dispatch.d.ts.map +1 -0
- package/dist/resource-prompt-dispatch.js +195 -0
- package/dist/resource-prompt-dispatch.js.map +1 -0
- package/dist/sanitize-error.d.ts +8 -0
- package/dist/sanitize-error.d.ts.map +1 -0
- package/dist/sanitize-error.js +25 -0
- package/dist/sanitize-error.js.map +1 -0
- package/dist/sanitize-svg.d.ts +20 -0
- package/dist/sanitize-svg.d.ts.map +1 -0
- package/dist/sanitize-svg.js +296 -0
- package/dist/sanitize-svg.js.map +1 -0
- package/dist/side-panel/App.d.ts +3 -0
- package/dist/side-panel/App.d.ts.map +1 -0
- package/dist/side-panel/App.js +147 -0
- package/dist/side-panel/App.js.map +1 -0
- package/dist/side-panel/bridge.d.ts +50 -0
- package/dist/side-panel/bridge.d.ts.map +1 -0
- package/dist/side-panel/bridge.js +113 -0
- package/dist/side-panel/bridge.js.map +1 -0
- package/dist/side-panel/components/ConfirmationDialog.d.ts +16 -0
- package/dist/side-panel/components/ConfirmationDialog.d.ts.map +1 -0
- package/dist/side-panel/components/ConfirmationDialog.js +39 -0
- package/dist/side-panel/components/ConfirmationDialog.js.map +1 -0
- package/dist/side-panel/components/EmptyStates.d.ts +8 -0
- package/dist/side-panel/components/EmptyStates.d.ts.map +1 -0
- package/dist/side-panel/components/EmptyStates.js +40 -0
- package/dist/side-panel/components/EmptyStates.js.map +1 -0
- package/dist/side-panel/components/ErrorBoundary.d.ts +23 -0
- package/dist/side-panel/components/ErrorBoundary.d.ts.map +1 -0
- package/dist/side-panel/components/ErrorBoundary.js +28 -0
- package/dist/side-panel/components/ErrorBoundary.js.map +1 -0
- package/dist/side-panel/components/FailedPluginCard.d.ts +6 -0
- package/dist/side-panel/components/FailedPluginCard.d.ts.map +1 -0
- package/dist/side-panel/components/FailedPluginCard.js +9 -0
- package/dist/side-panel/components/FailedPluginCard.js.map +1 -0
- package/dist/side-panel/components/Footer.d.ts +3 -0
- package/dist/side-panel/components/Footer.d.ts.map +1 -0
- package/dist/side-panel/components/Footer.js +32 -0
- package/dist/side-panel/components/Footer.js.map +1 -0
- package/dist/side-panel/components/Header.d.ts +5 -0
- package/dist/side-panel/components/Header.d.ts.map +1 -0
- package/dist/side-panel/components/Header.js +6 -0
- package/dist/side-panel/components/Header.js.map +1 -0
- package/dist/side-panel/components/PluginCard.d.ts +10 -0
- package/dist/side-panel/components/PluginCard.d.ts.map +1 -0
- package/dist/side-panel/components/PluginCard.js +50 -0
- package/dist/side-panel/components/PluginCard.js.map +1 -0
- package/dist/side-panel/components/PluginIcon.d.ts +21 -0
- package/dist/side-panel/components/PluginIcon.d.ts.map +1 -0
- package/dist/side-panel/components/PluginIcon.js +48 -0
- package/dist/side-panel/components/PluginIcon.js.map +1 -0
- package/dist/side-panel/components/PluginList.d.ts +11 -0
- package/dist/side-panel/components/PluginList.d.ts.map +1 -0
- package/dist/side-panel/components/PluginList.js +17 -0
- package/dist/side-panel/components/PluginList.js.map +1 -0
- package/dist/side-panel/components/ToolIcon.d.ts +7 -0
- package/dist/side-panel/components/ToolIcon.d.ts.map +1 -0
- package/dist/side-panel/components/ToolIcon.js +8 -0
- package/dist/side-panel/components/ToolIcon.js.map +1 -0
- package/dist/side-panel/components/ToolRow.d.ts +11 -0
- package/dist/side-panel/components/ToolRow.d.ts.map +1 -0
- package/dist/side-panel/components/ToolRow.js +8 -0
- package/dist/side-panel/components/ToolRow.js.map +1 -0
- package/dist/side-panel/components/VersionMismatchBanner.d.ts +3 -0
- package/dist/side-panel/components/VersionMismatchBanner.d.ts.map +1 -0
- package/dist/side-panel/components/VersionMismatchBanner.js +5 -0
- package/dist/side-panel/components/VersionMismatchBanner.js.map +1 -0
- package/dist/side-panel/components/retro/Accordion.d.ts +8 -0
- package/dist/side-panel/components/retro/Accordion.d.ts.map +1 -0
- package/dist/side-panel/components/retro/Accordion.js +15 -0
- package/dist/side-panel/components/retro/Accordion.js.map +1 -0
- package/dist/side-panel/components/retro/Alert.d.ts +25 -0
- package/dist/side-panel/components/retro/Alert.d.ts.map +1 -0
- package/dist/side-panel/components/retro/Alert.js +33 -0
- package/dist/side-panel/components/retro/Alert.js.map +1 -0
- package/dist/side-panel/components/retro/Badge.d.ts +15 -0
- package/dist/side-panel/components/retro/Badge.d.ts.map +1 -0
- package/dist/side-panel/components/retro/Badge.js +23 -0
- package/dist/side-panel/components/retro/Badge.js.map +1 -0
- package/dist/side-panel/components/retro/Button.d.ts +13 -0
- package/dist/side-panel/components/retro/Button.d.ts.map +1 -0
- package/dist/side-panel/components/retro/Button.js +33 -0
- package/dist/side-panel/components/retro/Button.js.map +1 -0
- package/dist/side-panel/components/retro/Empty.d.ts +31 -0
- package/dist/side-panel/components/retro/Empty.d.ts.map +1 -0
- package/dist/side-panel/components/retro/Empty.js +25 -0
- package/dist/side-panel/components/retro/Empty.js.map +1 -0
- package/dist/side-panel/components/retro/Input.d.ts +8 -0
- package/dist/side-panel/components/retro/Input.d.ts.map +1 -0
- package/dist/side-panel/components/retro/Input.js +7 -0
- package/dist/side-panel/components/retro/Input.js.map +1 -0
- package/dist/side-panel/components/retro/Loader.d.ts +14 -0
- package/dist/side-panel/components/retro/Loader.d.ts.map +1 -0
- package/dist/side-panel/components/retro/Loader.js +30 -0
- package/dist/side-panel/components/retro/Loader.js.map +1 -0
- package/dist/side-panel/components/retro/Menu.d.ts +9 -0
- package/dist/side-panel/components/retro/Menu.d.ts.map +1 -0
- package/dist/side-panel/components/retro/Menu.js +17 -0
- package/dist/side-panel/components/retro/Menu.js.map +1 -0
- package/dist/side-panel/components/retro/NumberStepper.d.ts +18 -0
- package/dist/side-panel/components/retro/NumberStepper.d.ts.map +1 -0
- package/dist/side-panel/components/retro/NumberStepper.js +38 -0
- package/dist/side-panel/components/retro/NumberStepper.js.map +1 -0
- package/dist/side-panel/components/retro/Progress.d.ts +9 -0
- package/dist/side-panel/components/retro/Progress.d.ts.map +1 -0
- package/dist/side-panel/components/retro/Progress.js +6 -0
- package/dist/side-panel/components/retro/Progress.js.map +1 -0
- package/dist/side-panel/components/retro/Switch.d.ts +4 -0
- package/dist/side-panel/components/retro/Switch.d.ts.map +1 -0
- package/dist/side-panel/components/retro/Switch.js +6 -0
- package/dist/side-panel/components/retro/Switch.js.map +1 -0
- package/dist/side-panel/components/retro/Text.d.ts +11 -0
- package/dist/side-panel/components/retro/Text.d.ts.map +1 -0
- package/dist/side-panel/components/retro/Text.js +28 -0
- package/dist/side-panel/components/retro/Text.js.map +1 -0
- package/dist/side-panel/components/retro/Tooltip.d.ts +12 -0
- package/dist/side-panel/components/retro/Tooltip.d.ts.map +1 -0
- package/dist/side-panel/components/retro/Tooltip.js +32 -0
- package/dist/side-panel/components/retro/Tooltip.js.map +1 -0
- package/dist/side-panel/constants.d.ts +5 -0
- package/dist/side-panel/constants.d.ts.map +1 -0
- package/dist/side-panel/constants.js +5 -0
- package/dist/side-panel/constants.js.map +1 -0
- package/dist/side-panel/hooks/useServerNotifications.d.ts +21 -0
- package/dist/side-panel/hooks/useServerNotifications.d.ts.map +1 -0
- package/dist/side-panel/hooks/useServerNotifications.js +93 -0
- package/dist/side-panel/hooks/useServerNotifications.js.map +1 -0
- package/dist/side-panel/hooks/useTheme.d.ts +8 -0
- package/dist/side-panel/hooks/useTheme.d.ts.map +1 -0
- package/dist/side-panel/hooks/useTheme.js +30 -0
- package/dist/side-panel/hooks/useTheme.js.map +1 -0
- package/dist/side-panel/index.d.ts +2 -0
- package/dist/side-panel/index.d.ts.map +1 -0
- package/dist/side-panel/index.js +12 -0
- package/dist/side-panel/index.js.map +1 -0
- package/dist/side-panel/lib/cn.d.ts +3 -0
- package/dist/side-panel/lib/cn.d.ts.map +1 -0
- package/dist/side-panel/lib/cn.js +4 -0
- package/dist/side-panel/lib/cn.js.map +1 -0
- package/dist/side-panel/lib/utils.d.ts +3 -0
- package/dist/side-panel/lib/utils.d.ts.map +1 -0
- package/dist/side-panel/lib/utils.js +4 -0
- package/dist/side-panel/lib/utils.js.map +1 -0
- package/dist/side-panel/side-panel.js +78034 -0
- package/dist/side-panel/styles.css +2 -0
- package/dist/side-panel-state.d.ts +11 -0
- package/dist/side-panel-state.d.ts.map +1 -0
- package/dist/side-panel-state.js +38 -0
- package/dist/side-panel-state.js.map +1 -0
- package/dist/side-panel-toggle.d.ts +3 -0
- package/dist/side-panel-toggle.d.ts.map +1 -0
- package/dist/side-panel-toggle.js +31 -0
- package/dist/side-panel-toggle.js.map +1 -0
- package/dist/tab-matching.d.ts +51 -0
- package/dist/tab-matching.d.ts.map +1 -0
- package/dist/tab-matching.js +160 -0
- package/dist/tab-matching.js.map +1 -0
- package/dist/tab-state.d.ts +56 -0
- package/dist/tab-state.d.ts.map +1 -0
- package/dist/tab-state.js +282 -0
- package/dist/tab-state.js.map +1 -0
- package/dist/tool-dispatch.d.ts +19 -0
- package/dist/tool-dispatch.d.ts.map +1 -0
- package/dist/tool-dispatch.js +336 -0
- package/dist/tool-dispatch.js.map +1 -0
- package/dist/types.d.ts +82 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/icons/icon-128.png +0 -0
- package/icons/icon-16.png +0 -0
- package/icons/icon-32.png +0 -0
- package/icons/icon-48.png +0 -0
- package/icons/icon.svg +6 -0
- package/manifest.json +38 -0
- package/offscreen/offscreen.html +10 -0
- package/package.json +49 -0
- package/side-panel/dark-mode.js +29 -0
- package/side-panel/fonts/archivo-black-latin.woff2 +0 -0
- package/side-panel/fonts/space-grotesk-latin.woff2 +0 -0
- package/side-panel/fonts/space-mono-400-latin.woff2 +0 -0
- package/side-panel/fonts/space-mono-700-latin.woff2 +0 -0
- package/side-panel/fonts.css +34 -0
- package/side-panel/side-panel.html +16 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { IS_READY_TIMEOUT_MS } from './constants.js';
|
|
2
|
+
import { forwardToSidePanel, sendTabStateNotification, sendToServer } from './messaging.js';
|
|
3
|
+
import { getAllPluginMeta } from './plugin-storage.js';
|
|
4
|
+
import { findAllMatchingTabs, urlMatchesPatterns } from './tab-matching.js';
|
|
5
|
+
/**
|
|
6
|
+
* Last-known tab state cache per plugin. Used by checkTabChanged and
|
|
7
|
+
* checkTabRemoved to suppress redundant tab.stateChanged notifications
|
|
8
|
+
* when a tab event fires but the plugin's effective state hasn't actually
|
|
9
|
+
* changed (e.g., a page reload where the plugin was "ready" before and
|
|
10
|
+
* is still "ready" after).
|
|
11
|
+
*
|
|
12
|
+
* The cache is populated by sendTabSyncAll (called after sync.full) and
|
|
13
|
+
* updated on every state change notification sent to the server.
|
|
14
|
+
* It is cleared on disconnect and repopulated when sync.full arrives on
|
|
15
|
+
* the next connection.
|
|
16
|
+
*/
|
|
17
|
+
const lastKnownState = new Map();
|
|
18
|
+
/**
|
|
19
|
+
* Per-plugin promise chain for serializing state computations. Concurrent
|
|
20
|
+
* calls for the same plugin are chained sequentially so lastKnownState reads
|
|
21
|
+
* and writes are atomic within each plugin. Different plugins run in parallel.
|
|
22
|
+
*/
|
|
23
|
+
const pluginLocks = new Map();
|
|
24
|
+
/**
|
|
25
|
+
* Chain an async operation onto a plugin's lock so it runs sequentially
|
|
26
|
+
* with any other pending operations for the same plugin. Returns the
|
|
27
|
+
* promise for the operation itself (rejections are logged on the lock
|
|
28
|
+
* chain but propagated to the caller via the returned promise).
|
|
29
|
+
*/
|
|
30
|
+
const withPluginLock = (pluginName, fn) => {
|
|
31
|
+
const prev = pluginLocks.get(pluginName) ?? Promise.resolve();
|
|
32
|
+
const next = prev.then(fn);
|
|
33
|
+
pluginLocks.set(pluginName, next.catch((err) => {
|
|
34
|
+
console.warn('[opentabs] tab state operation failed for plugin', pluginName, ':', err);
|
|
35
|
+
}));
|
|
36
|
+
return next;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Probe a single tab for adapter readiness. Returns true if the adapter's
|
|
40
|
+
* isReady() returns true within the timeout, false otherwise.
|
|
41
|
+
*/
|
|
42
|
+
const probeTabReadiness = async (tabId, pluginName) => {
|
|
43
|
+
let timerId;
|
|
44
|
+
try {
|
|
45
|
+
const results = await Promise.race([
|
|
46
|
+
chrome.scripting.executeScript({
|
|
47
|
+
target: { tabId },
|
|
48
|
+
world: 'MAIN',
|
|
49
|
+
func: async (pName) => {
|
|
50
|
+
const ot = globalThis.__openTabs;
|
|
51
|
+
const adapter = ot?.adapters?.[pName];
|
|
52
|
+
if (!adapter || typeof adapter !== 'object')
|
|
53
|
+
return false;
|
|
54
|
+
if (typeof adapter.isReady !== 'function')
|
|
55
|
+
return false;
|
|
56
|
+
return await adapter.isReady();
|
|
57
|
+
},
|
|
58
|
+
args: [pluginName],
|
|
59
|
+
}),
|
|
60
|
+
new Promise(resolve => {
|
|
61
|
+
timerId = setTimeout(() => resolve(null), IS_READY_TIMEOUT_MS);
|
|
62
|
+
}),
|
|
63
|
+
]);
|
|
64
|
+
if (results === null) {
|
|
65
|
+
console.warn(`[opentabs] isReady() timed out for plugin "${pluginName}" in tab ${tabId}`);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
const readyResult = results[0];
|
|
69
|
+
return readyResult?.result === true;
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
if (timerId !== undefined)
|
|
73
|
+
clearTimeout(timerId);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Compute the tab state for a single plugin by checking all matching tabs
|
|
78
|
+
* for adapter readiness. Reports 'ready' if ANY matching tab is ready,
|
|
79
|
+
* 'unavailable' if tabs exist but none are ready, 'closed' if no tabs match.
|
|
80
|
+
*/
|
|
81
|
+
const computePluginTabState = async (plugin) => {
|
|
82
|
+
const tabs = await findAllMatchingTabs(plugin);
|
|
83
|
+
if (tabs.length === 0) {
|
|
84
|
+
return { state: 'closed', tabId: null, url: null };
|
|
85
|
+
}
|
|
86
|
+
// Track the first unavailable tab for fallback reporting
|
|
87
|
+
let firstUnavailable;
|
|
88
|
+
for (const tab of tabs) {
|
|
89
|
+
if (tab.id === undefined)
|
|
90
|
+
continue;
|
|
91
|
+
try {
|
|
92
|
+
const ready = await probeTabReadiness(tab.id, plugin.name);
|
|
93
|
+
if (ready) {
|
|
94
|
+
return { state: 'ready', tabId: tab.id, url: tab.url ?? null };
|
|
95
|
+
}
|
|
96
|
+
firstUnavailable ??= tab;
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
console.warn(`[opentabs] computePluginTabState failed for plugin ${plugin.name} in tab ${tab.id}:`, err);
|
|
100
|
+
firstUnavailable ??= tab;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// All matching tabs exist but none are ready
|
|
104
|
+
const fallbackTab = firstUnavailable ?? tabs[0];
|
|
105
|
+
return {
|
|
106
|
+
state: 'unavailable',
|
|
107
|
+
tabId: fallbackTab?.id ?? null,
|
|
108
|
+
url: fallbackTab?.url ?? null,
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Scan all open tabs and send tab.syncAll to MCP server with current state
|
|
113
|
+
* of all known plugins. Called after sync.full is processed so the extension
|
|
114
|
+
* has up-to-date plugin metadata before reporting tab states.
|
|
115
|
+
*
|
|
116
|
+
* Also populates the lastKnownState cache so subsequent checkTabChanged /
|
|
117
|
+
* checkTabRemoved calls can suppress redundant notifications.
|
|
118
|
+
*/
|
|
119
|
+
const sendTabSyncAll = async () => {
|
|
120
|
+
const index = await getAllPluginMeta();
|
|
121
|
+
const plugins = Object.values(index);
|
|
122
|
+
if (plugins.length === 0)
|
|
123
|
+
return;
|
|
124
|
+
const settled = await Promise.allSettled(plugins.map(async (plugin) => [plugin.name, await computePluginTabState(plugin)]));
|
|
125
|
+
const entries = [];
|
|
126
|
+
for (const result of settled) {
|
|
127
|
+
if (result.status === 'fulfilled') {
|
|
128
|
+
entries.push(result.value);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
console.warn('[opentabs] Tab state computation failed during syncAll:', result.reason);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (entries.length === 0)
|
|
135
|
+
return;
|
|
136
|
+
const tabSyncPayload = Object.fromEntries(entries);
|
|
137
|
+
// Write each plugin's state through the per-plugin lock so concurrent
|
|
138
|
+
// checkTabChanged / checkTabRemoved calls are properly serialized.
|
|
139
|
+
const pluginNamesInSync = new Set();
|
|
140
|
+
await Promise.all(entries.map(([pluginName, stateInfo]) => {
|
|
141
|
+
pluginNamesInSync.add(pluginName);
|
|
142
|
+
return withPluginLock(pluginName, () => {
|
|
143
|
+
lastKnownState.set(pluginName, stateInfo.state);
|
|
144
|
+
return Promise.resolve();
|
|
145
|
+
});
|
|
146
|
+
}));
|
|
147
|
+
// Remove entries for plugins no longer in the index
|
|
148
|
+
for (const key of lastKnownState.keys()) {
|
|
149
|
+
if (!pluginNamesInSync.has(key)) {
|
|
150
|
+
lastKnownState.delete(key);
|
|
151
|
+
pluginLocks.delete(key);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
sendToServer({
|
|
155
|
+
jsonrpc: '2.0',
|
|
156
|
+
method: 'tab.syncAll',
|
|
157
|
+
params: { tabs: tabSyncPayload },
|
|
158
|
+
});
|
|
159
|
+
// Forward individual tab.stateChanged messages to the side panel so it
|
|
160
|
+
// gets initial tab states on connect without a separate fetch round-trip.
|
|
161
|
+
for (const [pluginName, stateInfo] of entries) {
|
|
162
|
+
forwardToSidePanel({
|
|
163
|
+
type: 'sp:serverMessage',
|
|
164
|
+
data: {
|
|
165
|
+
jsonrpc: '2.0',
|
|
166
|
+
method: 'tab.stateChanged',
|
|
167
|
+
params: { plugin: pluginName, state: stateInfo.state, tabId: stateInfo.tabId, url: stateInfo.url },
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* Clear the last-known state cache. Called on WebSocket disconnect so the
|
|
174
|
+
* next connect triggers a full sync without stale cache interference.
|
|
175
|
+
*/
|
|
176
|
+
const clearTabStateCache = () => {
|
|
177
|
+
lastKnownState.clear();
|
|
178
|
+
pluginLocks.clear();
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* Remove tab-state tracking entries for a single plugin. Called when a plugin
|
|
182
|
+
* is uninstalled or removed during sync.full so the maps do not grow
|
|
183
|
+
* unboundedly during long-running sessions.
|
|
184
|
+
*/
|
|
185
|
+
const clearPluginTabState = (pluginName) => {
|
|
186
|
+
lastKnownState.delete(pluginName);
|
|
187
|
+
pluginLocks.delete(pluginName);
|
|
188
|
+
};
|
|
189
|
+
/**
|
|
190
|
+
* Update the last-known state for a single plugin, serialized through the
|
|
191
|
+
* plugin lock so it cannot interleave with checkTabChanged / checkTabRemoved
|
|
192
|
+
* reads and writes for the same plugin. Called by handlePluginUpdate in
|
|
193
|
+
* message-router.ts after computing the new state via computePluginTabState.
|
|
194
|
+
*/
|
|
195
|
+
const updateLastKnownState = (pluginName, state) => withPluginLock(pluginName, () => {
|
|
196
|
+
lastKnownState.set(pluginName, state);
|
|
197
|
+
return Promise.resolve();
|
|
198
|
+
});
|
|
199
|
+
/** Return a snapshot of last-known tab states for all plugins. */
|
|
200
|
+
const getLastKnownStates = () => lastKnownState;
|
|
201
|
+
/**
|
|
202
|
+
* Compute state for each affected plugin, diff against the lastKnownState
|
|
203
|
+
* cache, and send tab.stateChanged only when the state actually changed.
|
|
204
|
+
* Each plugin's computation is serialized via withPluginLock to prevent
|
|
205
|
+
* interleaving with concurrent calls or updateLastKnownState writes.
|
|
206
|
+
*/
|
|
207
|
+
const notifyAffectedPlugins = async (affectedPlugins) => {
|
|
208
|
+
await Promise.all(affectedPlugins.map(plugin => withPluginLock(plugin.name, async () => {
|
|
209
|
+
const newState = await computePluginTabState(plugin);
|
|
210
|
+
// Suppress redundant notifications: only send if state actually changed
|
|
211
|
+
const previous = lastKnownState.get(plugin.name);
|
|
212
|
+
if (previous === newState.state)
|
|
213
|
+
return;
|
|
214
|
+
// Update the cache before sending so rapid sequential events see the
|
|
215
|
+
// latest state and don't produce duplicate notifications.
|
|
216
|
+
lastKnownState.set(plugin.name, newState.state);
|
|
217
|
+
sendTabStateNotification(plugin.name, newState);
|
|
218
|
+
})));
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* Check if a tab removal affects any plugin's tab state. All plugins are
|
|
222
|
+
* checked because chrome.tabs.get fails for removed tabs and onRemoved
|
|
223
|
+
* provides no URL, so pattern matching is not possible.
|
|
224
|
+
*/
|
|
225
|
+
const checkTabRemoved = async (_removedTabId) => {
|
|
226
|
+
const index = await getAllPluginMeta();
|
|
227
|
+
const plugins = Object.values(index);
|
|
228
|
+
if (plugins.length === 0)
|
|
229
|
+
return;
|
|
230
|
+
await notifyAffectedPlugins(plugins);
|
|
231
|
+
};
|
|
232
|
+
/**
|
|
233
|
+
* Check if a tab URL change or page load affects any plugin's tab state.
|
|
234
|
+
* Only plugins whose patterns match the changed URL or that have an active
|
|
235
|
+
* (non-closed) state are checked, avoiding O(n × scripting calls) per event.
|
|
236
|
+
*
|
|
237
|
+
* Optimized paths:
|
|
238
|
+
* - URL change: plugins matching the new URL OR plugins with active state
|
|
239
|
+
* - status=complete: the tab's URL is fetched once and matched against all
|
|
240
|
+
* plugin patterns, avoiding per-plugin chrome.tabs queries
|
|
241
|
+
*/
|
|
242
|
+
const checkTabChanged = async (changedTabId, changeInfo) => {
|
|
243
|
+
const index = await getAllPluginMeta();
|
|
244
|
+
const plugins = Object.values(index);
|
|
245
|
+
if (plugins.length === 0)
|
|
246
|
+
return;
|
|
247
|
+
let affectedPlugins;
|
|
248
|
+
if (changeInfo.url) {
|
|
249
|
+
// URL changed — check plugins matching the new URL plus plugins with
|
|
250
|
+
// active state (not 'closed'). Active plugins may have been on this tab
|
|
251
|
+
// before navigation, so recomputing their state discovers they no longer
|
|
252
|
+
// have a matching tab and transitions them to 'closed'.
|
|
253
|
+
const changedUrl = changeInfo.url;
|
|
254
|
+
affectedPlugins = plugins.filter(p => urlMatchesPatterns(changedUrl, p.urlPatterns) ||
|
|
255
|
+
(lastKnownState.has(p.name) && lastKnownState.get(p.name) !== 'closed'));
|
|
256
|
+
}
|
|
257
|
+
else if (changeInfo.status === 'complete') {
|
|
258
|
+
// Page finished loading — fetch the tab's current URL once and filter
|
|
259
|
+
// plugins by pattern match instead of calling findMatchingTab per plugin.
|
|
260
|
+
let tabUrl;
|
|
261
|
+
try {
|
|
262
|
+
const tab = await chrome.tabs.get(changedTabId);
|
|
263
|
+
tabUrl = tab.url;
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
// Tab may have been closed between event and handler — nothing to do
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
if (!tabUrl)
|
|
270
|
+
return;
|
|
271
|
+
affectedPlugins = plugins.filter(p => urlMatchesPatterns(tabUrl, p.urlPatterns) ||
|
|
272
|
+
(lastKnownState.has(p.name) && lastKnownState.get(p.name) !== 'closed'));
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (affectedPlugins.length === 0)
|
|
278
|
+
return;
|
|
279
|
+
await notifyAffectedPlugins(affectedPlugins);
|
|
280
|
+
};
|
|
281
|
+
export { checkTabChanged, checkTabRemoved, clearPluginTabState, clearTabStateCache, computePluginTabState, getLastKnownStates, sendTabSyncAll, updateLastKnownState, };
|
|
282
|
+
//# sourceMappingURL=tab-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tab-state.js","sourceRoot":"","sources":["../src/tab-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC5F,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAI5E;;;;;;;;;;;GAWG;AACH,MAAM,cAAc,GAAG,IAAI,GAAG,EAAoB,CAAC;AAEnD;;;;GAIG;AACH,MAAM,WAAW,GAAG,IAAI,GAAG,EAAyB,CAAC;AAErD;;;;;GAKG;AACH,MAAM,cAAc,GAAG,CAAC,UAAkB,EAAE,EAAuB,EAAiB,EAAE;IACpF,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3B,WAAW,CAAC,GAAG,CACb,UAAU,EACV,IAAI,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QAC1B,OAAO,CAAC,IAAI,CAAC,kDAAkD,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACzF,CAAC,CAAC,CACH,CAAC;IACF,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,iBAAiB,GAAG,KAAK,EAAE,KAAa,EAAE,UAAkB,EAAoB,EAAE;IACtF,IAAI,OAAkD,CAAC;IACvD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;YACjC,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC;gBAC7B,MAAM,EAAE,EAAE,KAAK,EAAE;gBACjB,KAAK,EAAE,MAAM;gBACb,IAAI,EAAE,KAAK,EAAE,KAAa,EAAE,EAAE;oBAC5B,MAAM,EAAE,GAAI,UAAsC,CAAC,UAEtC,CAAC;oBACd,MAAM,OAAO,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC;oBACtC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;wBAAE,OAAO,KAAK,CAAC;oBAC1D,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,UAAU;wBAAE,OAAO,KAAK,CAAC;oBACxD,OAAO,MAAO,OAAO,CAAC,OAAkC,EAAE,CAAC;gBAC7D,CAAC;gBACD,IAAI,EAAE,CAAC,UAAU,CAAC;aACnB,CAAC;YACF,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE;gBAC1B,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,mBAAmB,CAAC,CAAC;YACjE,CAAC,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,8CAA8C,UAAU,YAAY,KAAK,EAAE,CAAC,CAAC;YAC1F,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAqC,CAAC;QACnE,OAAO,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,CAAC;YAAS,CAAC;QACT,IAAI,OAAO,KAAK,SAAS;YAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC;AACH,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,qBAAqB,GAAG,KAAK,EAAE,MAAkB,EAA+B,EAAE;IACtF,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC/C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IACrD,CAAC;IAED,yDAAyD;IACzD,IAAI,gBAA6C,CAAC;IAElD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,CAAC,EAAE,KAAK,SAAS;YAAE,SAAS;QACnC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YAC3D,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;YACjE,CAAC;YACD,gBAAgB,KAAK,GAAG,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,sDAAsD,MAAM,CAAC,IAAI,WAAW,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;YACzG,gBAAgB,KAAK,GAAG,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,6CAA6C;IAC7C,MAAM,WAAW,GAAG,gBAAgB,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;IAChD,OAAO;QACL,KAAK,EAAE,aAAa;QACpB,KAAK,EAAE,WAAW,EAAE,EAAE,IAAI,IAAI;QAC9B,GAAG,EAAE,WAAW,EAAE,GAAG,IAAI,IAAI;KAC9B,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,cAAc,GAAG,KAAK,IAAmB,EAAE;IAC/C,MAAM,KAAK,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAEjC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CACtC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAC,MAAM,EAAC,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAU,CAAC,CACzF,CAAC;IACF,MAAM,OAAO,GAA8C,EAAE,CAAC;IAC9D,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,yDAAyD,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QACzF,CAAC;IACH,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IACjC,MAAM,cAAc,GAAuC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAEvF,sEAAsE;IACtE,mEAAmE;IACnE,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC5C,MAAM,OAAO,CAAC,GAAG,CACf,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,EAAE,EAAE;QACtC,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAClC,OAAO,cAAc,CAAC,UAAU,EAAE,GAAG,EAAE;YACrC,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;YAChD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CACH,CAAC;IACF,oDAAoD;IACpD,KAAK,MAAM,GAAG,IAAI,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC;QACxC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAChC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,YAAY,CAAC;QACX,OAAO,EAAE,KAAK;QACd,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE;KACjC,CAAC,CAAC;IAEH,uEAAuE;IACvE,0EAA0E;IAC1E,KAAK,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,IAAI,OAAO,EAAE,CAAC;QAC9C,kBAAkB,CAAC;YACjB,IAAI,EAAE,kBAAkB;YACxB,IAAI,EAAE;gBACJ,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,kBAAkB;gBAC1B,MAAM,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,CAAC,GAAG,EAAE;aACnG;SACF,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,kBAAkB,GAAG,GAAS,EAAE;IACpC,cAAc,CAAC,KAAK,EAAE,CAAC;IACvB,WAAW,CAAC,KAAK,EAAE,CAAC;AACtB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,mBAAmB,GAAG,CAAC,UAAkB,EAAQ,EAAE;IACvD,cAAc,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAClC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AACjC,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,oBAAoB,GAAG,CAAC,UAAkB,EAAE,KAAe,EAAiB,EAAE,CAClF,cAAc,CAAC,UAAU,EAAE,GAAG,EAAE;IAC9B,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACtC,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;AAC3B,CAAC,CAAC,CAAC;AAEL,kEAAkE;AAClE,MAAM,kBAAkB,GAAG,GAAkC,EAAE,CAAC,cAAc,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,qBAAqB,GAAG,KAAK,EAAE,eAA6B,EAAiB,EAAE;IACnF,MAAM,OAAO,CAAC,GAAG,CACf,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAC3B,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE;QACrC,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,MAAM,CAAC,CAAC;QAErD,wEAAwE;QACxE,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,QAAQ,KAAK,QAAQ,CAAC,KAAK;YAAE,OAAO;QAExC,qEAAqE;QACrE,0DAA0D;QAC1D,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;QAEhD,wBAAwB,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAClD,CAAC,CAAC,CACH,CACF,CAAC;AACJ,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,eAAe,GAAG,KAAK,EAAE,aAAqB,EAAiB,EAAE;IACrE,MAAM,KAAK,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAEjC,MAAM,qBAAqB,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,eAAe,GAAG,KAAK,EAAE,YAAoB,EAAE,UAAqC,EAAiB,EAAE;IAC3G,MAAM,KAAK,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAEjC,IAAI,eAA6B,CAAC;IAElC,IAAI,UAAU,CAAC,GAAG,EAAE,CAAC;QACnB,qEAAqE;QACrE,wEAAwE;QACxE,yEAAyE;QACzE,wDAAwD;QACxD,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC;QAClC,eAAe,GAAG,OAAO,CAAC,MAAM,CAC9B,CAAC,CAAC,EAAE,CACF,kBAAkB,CAAC,UAAU,EAAE,CAAC,CAAC,WAAW,CAAC;YAC7C,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,CAC1E,CAAC;IACJ,CAAC;SAAM,IAAI,UAAU,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAC5C,sEAAsE;QACtE,0EAA0E;QAC1E,IAAI,MAA0B,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YAChD,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;YACrE,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,eAAe,GAAG,OAAO,CAAC,MAAM,CAC9B,CAAC,CAAC,EAAE,CACF,kBAAkB,CAAC,MAAM,EAAE,CAAC,CAAC,WAAW,CAAC;YACzC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,CAC1E,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO;IACT,CAAC;IAED,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAEzC,MAAM,qBAAqB,CAAC,eAAe,CAAC,CAAC;AAC/C,CAAC,CAAC;AAEF,OAAO,EACL,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,EACd,oBAAoB,GACrB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { PluginMeta } from './extension-messages.js';
|
|
2
|
+
/**
|
|
3
|
+
* Notify the extension-side dispatch that a progress event arrived.
|
|
4
|
+
* Called from the background message handler (tool:progress case).
|
|
5
|
+
*/
|
|
6
|
+
declare const notifyDispatchProgress: (dispatchId: string) => void;
|
|
7
|
+
/**
|
|
8
|
+
* Get the link for console.warn logging: npm URL for published plugins, filesystem path for local.
|
|
9
|
+
*/
|
|
10
|
+
declare const getPluginLink: (plugin: PluginMeta) => string;
|
|
11
|
+
/**
|
|
12
|
+
* Handle tool.dispatch request from MCP server.
|
|
13
|
+
* Finds matching tabs, checks adapter readiness (with fallback to other
|
|
14
|
+
* matching tabs when the best-ranked tab is not ready), executes the tool,
|
|
15
|
+
* and returns the result.
|
|
16
|
+
*/
|
|
17
|
+
declare const handleToolDispatch: (params: Record<string, unknown>, id: string | number) => Promise<void>;
|
|
18
|
+
export { getPluginLink, handleToolDispatch, notifyDispatchProgress };
|
|
19
|
+
//# sourceMappingURL=tool-dispatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-dispatch.d.ts","sourceRoot":"","sources":["../src/tool-dispatch.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAS1D;;;GAGG;AACH,QAAA,MAAM,sBAAsB,GAAI,YAAY,MAAM,KAAG,IAGpD,CAAC;AAEF;;GAEG;AACH,QAAA,MAAM,aAAa,GAAI,QAAQ,UAAU,KAAG,MAQ3C,CAAC;AA6RF;;;;;GAKG;AACH,QAAA,MAAM,kBAAkB,GAAU,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,MAAM,GAAG,MAAM,KAAG,OAAO,CAAC,IAAI,CAmEpG,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,CAAC"}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import { requireStringParam } from './browser-commands/helpers.js';
|
|
2
|
+
import { MAX_INPUT_SIZE, MAX_SCRIPT_TIMEOUT_MS, SCRIPT_TIMEOUT_MS } from './constants.js';
|
|
3
|
+
import { dispatchWithTabFallback, resolvePlugin } from './dispatch-helpers.js';
|
|
4
|
+
import { JSONRPC_INTERNAL_ERROR, JSONRPC_INVALID_PARAMS } from './json-rpc-errors.js';
|
|
5
|
+
import { sendToServer } from './messaging.js';
|
|
6
|
+
import { toErrorMessage } from '@opentabs-dev/shared';
|
|
7
|
+
/**
|
|
8
|
+
* Per-dispatch progress callbacks — keyed by dispatchId, called by background.ts
|
|
9
|
+
* when a tool:progress message arrives. Each callback resets the extension-side
|
|
10
|
+
* script timeout for the corresponding dispatch.
|
|
11
|
+
*/
|
|
12
|
+
const progressCallbacks = new Map();
|
|
13
|
+
/**
|
|
14
|
+
* Notify the extension-side dispatch that a progress event arrived.
|
|
15
|
+
* Called from the background message handler (tool:progress case).
|
|
16
|
+
*/
|
|
17
|
+
const notifyDispatchProgress = (dispatchId) => {
|
|
18
|
+
const cb = progressCallbacks.get(dispatchId);
|
|
19
|
+
if (cb)
|
|
20
|
+
cb();
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Get the link for console.warn logging: npm URL for published plugins, filesystem path for local.
|
|
24
|
+
*/
|
|
25
|
+
const getPluginLink = (plugin) => {
|
|
26
|
+
if (plugin.trustTier === 'local' && plugin.sourcePath) {
|
|
27
|
+
return plugin.sourcePath;
|
|
28
|
+
}
|
|
29
|
+
if (plugin.trustTier === 'official') {
|
|
30
|
+
return `https://npmjs.com/package/@opentabs-dev/plugin-${plugin.name}`;
|
|
31
|
+
}
|
|
32
|
+
return `https://npmjs.com/package/opentabs-plugin-${plugin.name}`;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Inject a console.warn into the target tab before tool execution for transparency.
|
|
36
|
+
*/
|
|
37
|
+
const injectToolInvocationLog = async (tabId, pluginName, toolName, link) => {
|
|
38
|
+
try {
|
|
39
|
+
await chrome.scripting.executeScript({
|
|
40
|
+
target: { tabId },
|
|
41
|
+
world: 'MAIN',
|
|
42
|
+
func: (pName, tName, lnk) => {
|
|
43
|
+
console.warn(`[opentabs] ${pName}.${tName} invoked — ${lnk}`);
|
|
44
|
+
},
|
|
45
|
+
args: [pluginName, toolName, link],
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Tab may not be injectable — logging is best-effort
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Inject an ISOLATED world content script that listens for opentabs:progress
|
|
54
|
+
* CustomEvents from the MAIN world and relays them to the background service
|
|
55
|
+
* worker via chrome.runtime.sendMessage. Returns after the listener is installed.
|
|
56
|
+
*
|
|
57
|
+
* CustomEvents fired in MAIN world are visible in ISOLATED world because they
|
|
58
|
+
* share the same DOM — this is the correct, CSP-safe pattern for cross-world
|
|
59
|
+
* communication in Chrome extensions.
|
|
60
|
+
*/
|
|
61
|
+
const injectProgressListener = async (tabId, dispatchId) => {
|
|
62
|
+
try {
|
|
63
|
+
await chrome.scripting.executeScript({
|
|
64
|
+
target: { tabId },
|
|
65
|
+
world: 'ISOLATED',
|
|
66
|
+
func: (dId) => {
|
|
67
|
+
const eventName = `opentabs:progress:${dId}`;
|
|
68
|
+
const handler = (e) => {
|
|
69
|
+
const detail = e.detail;
|
|
70
|
+
if (!detail)
|
|
71
|
+
return;
|
|
72
|
+
void chrome.runtime.sendMessage({
|
|
73
|
+
type: 'tool:progress',
|
|
74
|
+
dispatchId: detail.dispatchId,
|
|
75
|
+
progress: detail.progress,
|
|
76
|
+
total: detail.total,
|
|
77
|
+
message: detail.message,
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
document.addEventListener(eventName, handler);
|
|
81
|
+
// Store a cleanup function on the document so we can remove the listener later
|
|
82
|
+
const cleanupKey = `__opentabs_progress_cleanup_${dId}`;
|
|
83
|
+
const doc = document;
|
|
84
|
+
doc[cleanupKey] = () => {
|
|
85
|
+
document.removeEventListener(eventName, handler);
|
|
86
|
+
doc[cleanupKey] = undefined;
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
args: [dispatchId],
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Tab may not be injectable — progress is best-effort
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Remove the ISOLATED world progress listener installed by injectProgressListener.
|
|
98
|
+
* Fire-and-forget — errors are silently ignored since the dispatch is already complete.
|
|
99
|
+
*/
|
|
100
|
+
const removeProgressListener = (tabId, dispatchId) => {
|
|
101
|
+
chrome.scripting
|
|
102
|
+
.executeScript({
|
|
103
|
+
target: { tabId },
|
|
104
|
+
world: 'ISOLATED',
|
|
105
|
+
func: (dId) => {
|
|
106
|
+
const cleanupKey = `__opentabs_progress_cleanup_${dId}`;
|
|
107
|
+
const cleanup = document[cleanupKey];
|
|
108
|
+
if (cleanup)
|
|
109
|
+
cleanup();
|
|
110
|
+
},
|
|
111
|
+
args: [dispatchId],
|
|
112
|
+
})
|
|
113
|
+
.catch(() => {
|
|
114
|
+
// Best-effort cleanup
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Execute a tool on a specific tab. Returns the structured result from the
|
|
119
|
+
* adapter script, or throws if the tab is inaccessible (e.g., closed).
|
|
120
|
+
*
|
|
121
|
+
* The extension-side timeout starts at SCRIPT_TIMEOUT_MS (25s). When the tool
|
|
122
|
+
* reports progress, the timeout is reset via the progressCallbacks registry.
|
|
123
|
+
* The absolute upper bound is MAX_SCRIPT_TIMEOUT_MS (295s).
|
|
124
|
+
*
|
|
125
|
+
* @param dispatchId - Correlation ID for progress reporting. The injected MAIN
|
|
126
|
+
* world function creates a ToolHandlerContext with a reportProgress callback
|
|
127
|
+
* that fires CustomEvents keyed by this ID.
|
|
128
|
+
*/
|
|
129
|
+
const executeToolOnTab = async (tabId, pluginName, toolName, input, dispatchId) => {
|
|
130
|
+
let timeoutId;
|
|
131
|
+
const startTs = Date.now();
|
|
132
|
+
const scriptPromise = chrome.scripting.executeScript({
|
|
133
|
+
target: { tabId },
|
|
134
|
+
world: 'MAIN',
|
|
135
|
+
func: async (pName, tName, tInput, dId) => {
|
|
136
|
+
const ot = globalThis.__openTabs;
|
|
137
|
+
const adapter = ot?.adapters?.[pName];
|
|
138
|
+
if (!adapter || typeof adapter !== 'object') {
|
|
139
|
+
return { type: 'error', code: -32002, message: `Adapter "${pName}" not injected or not ready` };
|
|
140
|
+
}
|
|
141
|
+
// Defense-in-depth: reject adapters that are not frozen. Legitimate
|
|
142
|
+
// adapters are always frozen by the hashAndFreeze snippet appended to
|
|
143
|
+
// the IIFE. An unfrozen adapter indicates tampering by a page script.
|
|
144
|
+
if (!Object.isFrozen(adapter)) {
|
|
145
|
+
return {
|
|
146
|
+
type: 'error',
|
|
147
|
+
code: -32002,
|
|
148
|
+
message: `Adapter "${pName}" failed integrity check (not frozen)`,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
if (typeof adapter.isReady !== 'function') {
|
|
152
|
+
return { type: 'error', code: -32002, message: `Adapter "${pName}" has no isReady function` };
|
|
153
|
+
}
|
|
154
|
+
if (!Array.isArray(adapter.tools)) {
|
|
155
|
+
return { type: 'error', code: -32002, message: `Adapter "${pName}" has no tools array` };
|
|
156
|
+
}
|
|
157
|
+
let ready;
|
|
158
|
+
try {
|
|
159
|
+
ready = await adapter.isReady();
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return { type: 'error', code: -32002, message: `Adapter "${pName}" isReady() threw an error` };
|
|
163
|
+
}
|
|
164
|
+
if (!ready) {
|
|
165
|
+
return {
|
|
166
|
+
type: 'error',
|
|
167
|
+
code: -32002,
|
|
168
|
+
message: `Plugin "${pName}" is not ready (state: unavailable)`,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const tool = adapter.tools.find((t) => t.name === tName);
|
|
172
|
+
if (!tool || typeof tool.handle !== 'function') {
|
|
173
|
+
return { type: 'error', code: -32603, message: `Tool "${tName}" not found in adapter "${pName}"` };
|
|
174
|
+
}
|
|
175
|
+
// Create ToolHandlerContext with reportProgress that fires a CustomEvent
|
|
176
|
+
// on the document. The ISOLATED world content script listens for this event
|
|
177
|
+
// and relays it to the background service worker. Missing progress/total
|
|
178
|
+
// default to 0 for indeterminate progress reporting.
|
|
179
|
+
const context = {
|
|
180
|
+
reportProgress(opts) {
|
|
181
|
+
try {
|
|
182
|
+
document.dispatchEvent(new CustomEvent(`opentabs:progress:${dId}`, {
|
|
183
|
+
detail: {
|
|
184
|
+
dispatchId: dId,
|
|
185
|
+
progress: opts.progress ?? 0,
|
|
186
|
+
total: opts.total ?? 0,
|
|
187
|
+
message: opts.message,
|
|
188
|
+
},
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// Fire-and-forget — progress reporting errors must not affect tool execution
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
try {
|
|
197
|
+
const output = await tool.handle(tInput, context);
|
|
198
|
+
return { type: 'success', output };
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
const caughtError = err;
|
|
202
|
+
if (typeof caughtError.code !== 'string') {
|
|
203
|
+
return {
|
|
204
|
+
type: 'error',
|
|
205
|
+
code: -32603,
|
|
206
|
+
message: caughtError.message ?? 'Tool execution failed',
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const data = { code: caughtError.code };
|
|
210
|
+
if (typeof caughtError.retryable === 'boolean')
|
|
211
|
+
data.retryable = caughtError.retryable;
|
|
212
|
+
if (typeof caughtError.retryAfterMs === 'number')
|
|
213
|
+
data.retryAfterMs = caughtError.retryAfterMs;
|
|
214
|
+
if (typeof caughtError.category === 'string')
|
|
215
|
+
data.category = caughtError.category;
|
|
216
|
+
return {
|
|
217
|
+
type: 'error',
|
|
218
|
+
code: -32603,
|
|
219
|
+
message: caughtError.message ?? 'Tool execution failed',
|
|
220
|
+
data,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
args: [pluginName, toolName, input, dispatchId],
|
|
225
|
+
});
|
|
226
|
+
let timeoutReject;
|
|
227
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
228
|
+
timeoutReject = reject;
|
|
229
|
+
timeoutId = setTimeout(() => {
|
|
230
|
+
reject(new Error(`Script execution timed out after ${SCRIPT_TIMEOUT_MS}ms`));
|
|
231
|
+
}, SCRIPT_TIMEOUT_MS);
|
|
232
|
+
});
|
|
233
|
+
// Register a progress callback that resets the extension-side timeout.
|
|
234
|
+
// Called by background.ts when a tool:progress message arrives.
|
|
235
|
+
progressCallbacks.set(dispatchId, () => {
|
|
236
|
+
clearTimeout(timeoutId);
|
|
237
|
+
const elapsed = Date.now() - startTs;
|
|
238
|
+
const remainingMax = MAX_SCRIPT_TIMEOUT_MS - elapsed;
|
|
239
|
+
if (remainingMax <= 0) {
|
|
240
|
+
timeoutReject?.(new Error(`Script execution exceeded absolute max timeout of ${MAX_SCRIPT_TIMEOUT_MS}ms`));
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const nextTimeout = Math.min(SCRIPT_TIMEOUT_MS, remainingMax);
|
|
244
|
+
timeoutId = setTimeout(() => {
|
|
245
|
+
timeoutReject?.(new Error(`Script execution timed out after ${SCRIPT_TIMEOUT_MS}ms`));
|
|
246
|
+
}, nextTimeout);
|
|
247
|
+
});
|
|
248
|
+
let results;
|
|
249
|
+
try {
|
|
250
|
+
results = await Promise.race([scriptPromise, timeoutPromise]);
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
clearTimeout(timeoutId);
|
|
254
|
+
progressCallbacks.delete(dispatchId);
|
|
255
|
+
}
|
|
256
|
+
const firstResult = results[0];
|
|
257
|
+
const result = firstResult?.result;
|
|
258
|
+
if (!result || typeof result !== 'object' || !('type' in result)) {
|
|
259
|
+
return { type: 'error', code: JSONRPC_INTERNAL_ERROR, message: 'No result from tool execution' };
|
|
260
|
+
}
|
|
261
|
+
return result;
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* Handle tool.dispatch request from MCP server.
|
|
265
|
+
* Finds matching tabs, checks adapter readiness (with fallback to other
|
|
266
|
+
* matching tabs when the best-ranked tab is not ready), executes the tool,
|
|
267
|
+
* and returns the result.
|
|
268
|
+
*/
|
|
269
|
+
const handleToolDispatch = async (params, id) => {
|
|
270
|
+
// dispatchId is the correlation key for progress reporting, injected by the MCP server
|
|
271
|
+
const dispatchId = typeof params.dispatchId === 'string' ? params.dispatchId : String(id);
|
|
272
|
+
const pluginName = requireStringParam(params, 'plugin', id);
|
|
273
|
+
if (!pluginName)
|
|
274
|
+
return;
|
|
275
|
+
const toolName = requireStringParam(params, 'tool', id);
|
|
276
|
+
if (!toolName)
|
|
277
|
+
return;
|
|
278
|
+
const rawInput = params.input;
|
|
279
|
+
if (rawInput !== undefined && rawInput !== null && (typeof rawInput !== 'object' || Array.isArray(rawInput))) {
|
|
280
|
+
sendToServer({
|
|
281
|
+
jsonrpc: '2.0',
|
|
282
|
+
error: { code: JSONRPC_INVALID_PARAMS, message: 'Invalid "input" param (expected object)' },
|
|
283
|
+
id,
|
|
284
|
+
});
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const input = (rawInput ?? {});
|
|
288
|
+
let inputJson;
|
|
289
|
+
try {
|
|
290
|
+
inputJson = JSON.stringify(input);
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
sendToServer({
|
|
294
|
+
jsonrpc: '2.0',
|
|
295
|
+
error: {
|
|
296
|
+
code: JSONRPC_INVALID_PARAMS,
|
|
297
|
+
message: `Failed to serialize tool input: ${toErrorMessage(err)}`,
|
|
298
|
+
},
|
|
299
|
+
id,
|
|
300
|
+
});
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (inputJson.length > MAX_INPUT_SIZE) {
|
|
304
|
+
sendToServer({
|
|
305
|
+
jsonrpc: '2.0',
|
|
306
|
+
error: {
|
|
307
|
+
code: JSONRPC_INVALID_PARAMS,
|
|
308
|
+
message: `Tool input too large: ${(inputJson.length / 1024 / 1024).toFixed(1)}MB (limit: 10MB)`,
|
|
309
|
+
},
|
|
310
|
+
id,
|
|
311
|
+
});
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const plugin = await resolvePlugin(pluginName, id);
|
|
315
|
+
if (!plugin)
|
|
316
|
+
return;
|
|
317
|
+
const link = getPluginLink(plugin);
|
|
318
|
+
await dispatchWithTabFallback({
|
|
319
|
+
id,
|
|
320
|
+
pluginName,
|
|
321
|
+
plugin,
|
|
322
|
+
operationName: 'tool execution',
|
|
323
|
+
executeOnTab: async (tabId) => {
|
|
324
|
+
await injectToolInvocationLog(tabId, pluginName, toolName, link);
|
|
325
|
+
await injectProgressListener(tabId, dispatchId);
|
|
326
|
+
try {
|
|
327
|
+
return await executeToolOnTab(tabId, pluginName, toolName, input, dispatchId);
|
|
328
|
+
}
|
|
329
|
+
finally {
|
|
330
|
+
removeProgressListener(tabId, dispatchId);
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
};
|
|
335
|
+
export { getPluginLink, handleToolDispatch, notifyDispatchProgress };
|
|
336
|
+
//# sourceMappingURL=tool-dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-dispatch.js","sourceRoot":"","sources":["../src/tool-dispatch.ts"],"names":[],"mappings":"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"}
|