@opentabs-dev/mcp-server 0.0.19
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/audit-disk.d.ts +23 -0
- package/dist/audit-disk.d.ts.map +1 -0
- package/dist/audit-disk.js +74 -0
- package/dist/audit-disk.js.map +1 -0
- package/dist/browser-tools/analyze-site/detect-apis.d.ts +36 -0
- package/dist/browser-tools/analyze-site/detect-apis.d.ts.map +1 -0
- package/dist/browser-tools/analyze-site/detect-apis.js +383 -0
- package/dist/browser-tools/analyze-site/detect-apis.js.map +1 -0
- package/dist/browser-tools/analyze-site/detect-auth.d.ts +72 -0
- package/dist/browser-tools/analyze-site/detect-auth.d.ts.map +1 -0
- package/dist/browser-tools/analyze-site/detect-auth.js +384 -0
- package/dist/browser-tools/analyze-site/detect-auth.js.map +1 -0
- package/dist/browser-tools/analyze-site/detect-dom.d.ts +65 -0
- package/dist/browser-tools/analyze-site/detect-dom.d.ts.map +1 -0
- package/dist/browser-tools/analyze-site/detect-dom.js +45 -0
- package/dist/browser-tools/analyze-site/detect-dom.js.map +1 -0
- package/dist/browser-tools/analyze-site/detect-framework.d.ts +48 -0
- package/dist/browser-tools/analyze-site/detect-framework.d.ts.map +1 -0
- package/dist/browser-tools/analyze-site/detect-framework.js +31 -0
- package/dist/browser-tools/analyze-site/detect-framework.js.map +1 -0
- package/dist/browser-tools/analyze-site/detect-globals.d.ts +41 -0
- package/dist/browser-tools/analyze-site/detect-globals.d.ts.map +1 -0
- package/dist/browser-tools/analyze-site/detect-globals.js +42 -0
- package/dist/browser-tools/analyze-site/detect-globals.js.map +1 -0
- package/dist/browser-tools/analyze-site/detect-storage.d.ts +39 -0
- package/dist/browser-tools/analyze-site/detect-storage.d.ts.map +1 -0
- package/dist/browser-tools/analyze-site/detect-storage.js +34 -0
- package/dist/browser-tools/analyze-site/detect-storage.js.map +1 -0
- package/dist/browser-tools/analyze-site/index.d.ts +52 -0
- package/dist/browser-tools/analyze-site/index.d.ts.map +1 -0
- package/dist/browser-tools/analyze-site/index.js +827 -0
- package/dist/browser-tools/analyze-site/index.js.map +1 -0
- package/dist/browser-tools/analyze-site.d.ts +17 -0
- package/dist/browser-tools/analyze-site.d.ts.map +1 -0
- package/dist/browser-tools/analyze-site.js +41 -0
- package/dist/browser-tools/analyze-site.js.map +1 -0
- package/dist/browser-tools/clear-console-logs.d.ts +9 -0
- package/dist/browser-tools/clear-console-logs.d.ts.map +1 -0
- package/dist/browser-tools/clear-console-logs.js +16 -0
- package/dist/browser-tools/clear-console-logs.js.map +1 -0
- package/dist/browser-tools/click-element.d.ts +10 -0
- package/dist/browser-tools/click-element.d.ts.map +1 -0
- package/dist/browser-tools/click-element.js +22 -0
- package/dist/browser-tools/click-element.js.map +1 -0
- package/dist/browser-tools/close-tab.d.ts +9 -0
- package/dist/browser-tools/close-tab.d.ts.map +1 -0
- package/dist/browser-tools/close-tab.js +16 -0
- package/dist/browser-tools/close-tab.js.map +1 -0
- package/dist/browser-tools/definition.d.ts +26 -0
- package/dist/browser-tools/definition.d.ts.map +1 -0
- package/dist/browser-tools/definition.js +16 -0
- package/dist/browser-tools/definition.js.map +1 -0
- package/dist/browser-tools/delete-cookies.d.ts +10 -0
- package/dist/browser-tools/delete-cookies.d.ts.map +1 -0
- package/dist/browser-tools/delete-cookies.js +19 -0
- package/dist/browser-tools/delete-cookies.js.map +1 -0
- package/dist/browser-tools/disable-network-capture.d.ts +9 -0
- package/dist/browser-tools/disable-network-capture.d.ts.map +1 -0
- package/dist/browser-tools/disable-network-capture.js +16 -0
- package/dist/browser-tools/disable-network-capture.js.map +1 -0
- package/dist/browser-tools/enable-network-capture.d.ts +12 -0
- package/dist/browser-tools/enable-network-capture.d.ts.map +1 -0
- package/dist/browser-tools/enable-network-capture.js +42 -0
- package/dist/browser-tools/enable-network-capture.js.map +1 -0
- package/dist/browser-tools/execute-script.d.ts +19 -0
- package/dist/browser-tools/execute-script.d.ts.map +1 -0
- package/dist/browser-tools/execute-script.js +51 -0
- package/dist/browser-tools/execute-script.js.map +1 -0
- package/dist/browser-tools/extension-check-adapter.d.ts +11 -0
- package/dist/browser-tools/extension-check-adapter.d.ts.map +1 -0
- package/dist/browser-tools/extension-check-adapter.js +22 -0
- package/dist/browser-tools/extension-check-adapter.js.map +1 -0
- package/dist/browser-tools/extension-force-reconnect.d.ts +9 -0
- package/dist/browser-tools/extension-force-reconnect.d.ts.map +1 -0
- package/dist/browser-tools/extension-force-reconnect.js +19 -0
- package/dist/browser-tools/extension-force-reconnect.js.map +1 -0
- package/dist/browser-tools/extension-get-logs.d.ts +24 -0
- package/dist/browser-tools/extension-get-logs.d.ts.map +1 -0
- package/dist/browser-tools/extension-get-logs.js +34 -0
- package/dist/browser-tools/extension-get-logs.js.map +1 -0
- package/dist/browser-tools/extension-get-side-panel.d.ts +8 -0
- package/dist/browser-tools/extension-get-side-panel.d.ts.map +1 -0
- package/dist/browser-tools/extension-get-side-panel.js +17 -0
- package/dist/browser-tools/extension-get-side-panel.js.map +1 -0
- package/dist/browser-tools/extension-get-state.d.ts +9 -0
- package/dist/browser-tools/extension-get-state.d.ts.map +1 -0
- package/dist/browser-tools/extension-get-state.js +19 -0
- package/dist/browser-tools/extension-get-state.js.map +1 -0
- package/dist/browser-tools/focus-tab.d.ts +9 -0
- package/dist/browser-tools/focus-tab.d.ts.map +1 -0
- package/dist/browser-tools/focus-tab.js +17 -0
- package/dist/browser-tools/focus-tab.js.map +1 -0
- package/dist/browser-tools/get-console-logs.d.ts +18 -0
- package/dist/browser-tools/get-console-logs.d.ts.map +1 -0
- package/dist/browser-tools/get-console-logs.js +30 -0
- package/dist/browser-tools/get-console-logs.js.map +1 -0
- package/dist/browser-tools/get-cookies.d.ts +10 -0
- package/dist/browser-tools/get-cookies.d.ts.map +1 -0
- package/dist/browser-tools/get-cookies.js +23 -0
- package/dist/browser-tools/get-cookies.js.map +1 -0
- package/dist/browser-tools/get-network-requests.d.ts +10 -0
- package/dist/browser-tools/get-network-requests.d.ts.map +1 -0
- package/dist/browser-tools/get-network-requests.js +27 -0
- package/dist/browser-tools/get-network-requests.js.map +1 -0
- package/dist/browser-tools/get-page-html.d.ts +11 -0
- package/dist/browser-tools/get-page-html.d.ts.map +1 -0
- package/dist/browser-tools/get-page-html.js +32 -0
- package/dist/browser-tools/get-page-html.js.map +1 -0
- package/dist/browser-tools/get-resource-content.d.ts +11 -0
- package/dist/browser-tools/get-resource-content.d.ts.map +1 -0
- package/dist/browser-tools/get-resource-content.js +31 -0
- package/dist/browser-tools/get-resource-content.js.map +1 -0
- package/dist/browser-tools/get-storage.d.ts +14 -0
- package/dist/browser-tools/get-storage.d.ts.map +1 -0
- package/dist/browser-tools/get-storage.js +28 -0
- package/dist/browser-tools/get-storage.js.map +1 -0
- package/dist/browser-tools/get-tab-content.d.ts +11 -0
- package/dist/browser-tools/get-tab-content.d.ts.map +1 -0
- package/dist/browser-tools/get-tab-content.js +29 -0
- package/dist/browser-tools/get-tab-content.js.map +1 -0
- package/dist/browser-tools/get-tab-info.d.ts +9 -0
- package/dist/browser-tools/get-tab-info.d.ts.map +1 -0
- package/dist/browser-tools/get-tab-info.js +17 -0
- package/dist/browser-tools/get-tab-info.js.map +1 -0
- package/dist/browser-tools/handle-dialog.d.ts +14 -0
- package/dist/browser-tools/handle-dialog.d.ts.map +1 -0
- package/dist/browser-tools/handle-dialog.js +30 -0
- package/dist/browser-tools/handle-dialog.js.map +1 -0
- package/dist/browser-tools/hover-element.d.ts +11 -0
- package/dist/browser-tools/hover-element.d.ts.map +1 -0
- package/dist/browser-tools/hover-element.js +24 -0
- package/dist/browser-tools/hover-element.js.map +1 -0
- package/dist/browser-tools/index.d.ts +7 -0
- package/dist/browser-tools/index.d.ts.map +1 -0
- package/dist/browser-tools/index.js +81 -0
- package/dist/browser-tools/index.js.map +1 -0
- package/dist/browser-tools/list-resources.d.ts +10 -0
- package/dist/browser-tools/list-resources.d.ts.map +1 -0
- package/dist/browser-tools/list-resources.js +29 -0
- package/dist/browser-tools/list-resources.js.map +1 -0
- package/dist/browser-tools/list-tabs.d.ts +7 -0
- package/dist/browser-tools/list-tabs.d.ts.map +1 -0
- package/dist/browser-tools/list-tabs.js +16 -0
- package/dist/browser-tools/list-tabs.js.map +1 -0
- package/dist/browser-tools/navigate-tab.d.ts +10 -0
- package/dist/browser-tools/navigate-tab.d.ts.map +1 -0
- package/dist/browser-tools/navigate-tab.js +18 -0
- package/dist/browser-tools/navigate-tab.js.map +1 -0
- package/dist/browser-tools/open-tab.d.ts +9 -0
- package/dist/browser-tools/open-tab.d.ts.map +1 -0
- package/dist/browser-tools/open-tab.js +18 -0
- package/dist/browser-tools/open-tab.js.map +1 -0
- package/dist/browser-tools/press-key.d.ts +17 -0
- package/dist/browser-tools/press-key.d.ts.map +1 -0
- package/dist/browser-tools/press-key.js +43 -0
- package/dist/browser-tools/press-key.js.map +1 -0
- package/dist/browser-tools/query-elements.d.ts +12 -0
- package/dist/browser-tools/query-elements.d.ts.map +1 -0
- package/dist/browser-tools/query-elements.js +30 -0
- package/dist/browser-tools/query-elements.js.map +1 -0
- package/dist/browser-tools/reload-extension.d.ts +13 -0
- package/dist/browser-tools/reload-extension.d.ts.map +1 -0
- package/dist/browser-tools/reload-extension.js +35 -0
- package/dist/browser-tools/reload-extension.js.map +1 -0
- package/dist/browser-tools/screenshot-tab.d.ts +9 -0
- package/dist/browser-tools/screenshot-tab.d.ts.map +1 -0
- package/dist/browser-tools/screenshot-tab.js +22 -0
- package/dist/browser-tools/screenshot-tab.js.map +1 -0
- package/dist/browser-tools/scroll.d.ts +23 -0
- package/dist/browser-tools/scroll.d.ts.map +1 -0
- package/dist/browser-tools/scroll.js +56 -0
- package/dist/browser-tools/scroll.js.map +1 -0
- package/dist/browser-tools/select-option.d.ts +12 -0
- package/dist/browser-tools/select-option.d.ts.map +1 -0
- package/dist/browser-tools/select-option.js +25 -0
- package/dist/browser-tools/select-option.js.map +1 -0
- package/dist/browser-tools/set-cookie.d.ts +16 -0
- package/dist/browser-tools/set-cookie.d.ts.map +1 -0
- package/dist/browser-tools/set-cookie.js +42 -0
- package/dist/browser-tools/set-cookie.js.map +1 -0
- package/dist/browser-tools/type-text.d.ts +12 -0
- package/dist/browser-tools/type-text.d.ts.map +1 -0
- package/dist/browser-tools/type-text.js +25 -0
- package/dist/browser-tools/type-text.js.map +1 -0
- package/dist/browser-tools/url-validation.d.ts +13 -0
- package/dist/browser-tools/url-validation.d.ts.map +1 -0
- package/dist/browser-tools/url-validation.js +23 -0
- package/dist/browser-tools/url-validation.js.map +1 -0
- package/dist/browser-tools/wait-for-element.d.ts +12 -0
- package/dist/browser-tools/wait-for-element.d.ts.map +1 -0
- package/dist/browser-tools/wait-for-element.js +29 -0
- package/dist/browser-tools/wait-for-element.js.map +1 -0
- package/dist/config.d.ts +99 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +344 -0
- package/dist/config.js.map +1 -0
- package/dist/dev-mode.d.ts +14 -0
- package/dist/dev-mode.d.ts.map +1 -0
- package/dist/dev-mode.js +15 -0
- package/dist/dev-mode.js.map +1 -0
- package/dist/discovery-legacy.d.ts +32 -0
- package/dist/discovery-legacy.d.ts.map +1 -0
- package/dist/discovery-legacy.js +415 -0
- package/dist/discovery-legacy.js.map +1 -0
- package/dist/discovery.d.ts +28 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +97 -0
- package/dist/discovery.js.map +1 -0
- package/dist/extension-install.d.ts +27 -0
- package/dist/extension-install.d.ts.map +1 -0
- package/dist/extension-install.js +75 -0
- package/dist/extension-install.js.map +1 -0
- package/dist/extension-protocol.d.ts +130 -0
- package/dist/extension-protocol.d.ts.map +1 -0
- package/dist/extension-protocol.js +869 -0
- package/dist/extension-protocol.js.map +1 -0
- package/dist/file-watcher.d.ts +75 -0
- package/dist/file-watcher.d.ts.map +1 -0
- package/dist/file-watcher.js +616 -0
- package/dist/file-watcher.js.map +1 -0
- package/dist/http-routes.d.ts +88 -0
- package/dist/http-routes.d.ts.map +1 -0
- package/dist/http-routes.js +545 -0
- package/dist/http-routes.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +187 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +100 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +402 -0
- package/dist/loader.js.map +1 -0
- package/dist/log-buffer.d.ts +33 -0
- package/dist/log-buffer.d.ts.map +1 -0
- package/dist/log-buffer.js +64 -0
- package/dist/log-buffer.js.map +1 -0
- package/dist/logger.d.ts +34 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +81 -0
- package/dist/logger.js.map +1 -0
- package/dist/manifest-schema.d.ts +14 -0
- package/dist/manifest-schema.d.ts.map +1 -0
- package/dist/manifest-schema.js +51 -0
- package/dist/manifest-schema.js.map +1 -0
- package/dist/mcp-setup.d.ts +131 -0
- package/dist/mcp-setup.d.ts.map +1 -0
- package/dist/mcp-setup.js +673 -0
- package/dist/mcp-setup.js.map +1 -0
- package/dist/permissions.d.ts +59 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/permissions.js +141 -0
- package/dist/permissions.js.map +1 -0
- package/dist/registry.d.ts +78 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +187 -0
- package/dist/registry.js.map +1 -0
- package/dist/reload.d.ts +52 -0
- package/dist/reload.d.ts.map +1 -0
- package/dist/reload.js +326 -0
- package/dist/reload.js.map +1 -0
- package/dist/resolver.d.ts +53 -0
- package/dist/resolver.d.ts.map +1 -0
- package/dist/resolver.js +272 -0
- package/dist/resolver.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-tool-output.d.ts +20 -0
- package/dist/sanitize-tool-output.d.ts.map +1 -0
- package/dist/sanitize-tool-output.js +52 -0
- package/dist/sanitize-tool-output.js.map +1 -0
- package/dist/sdk-version.d.ts +11 -0
- package/dist/sdk-version.d.ts.map +1 -0
- package/dist/sdk-version.js +23 -0
- package/dist/sdk-version.js.map +1 -0
- package/dist/shutdown.d.ts +28 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +68 -0
- package/dist/shutdown.js.map +1 -0
- package/dist/skip-confirmation.d.ts +15 -0
- package/dist/skip-confirmation.d.ts.map +1 -0
- package/dist/skip-confirmation.js +16 -0
- package/dist/skip-confirmation.js.map +1 -0
- package/dist/skip-sanitization.d.ts +17 -0
- package/dist/skip-sanitization.d.ts.map +1 -0
- package/dist/skip-sanitization.js +18 -0
- package/dist/skip-sanitization.js.map +1 -0
- package/dist/skip-verification.d.ts +11 -0
- package/dist/skip-verification.d.ts.map +1 -0
- package/dist/skip-verification.js +12 -0
- package/dist/skip-verification.js.map +1 -0
- package/dist/state.d.ts +290 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +111 -0
- package/dist/state.js.map +1 -0
- package/dist/verify-plugin.d.ts +53 -0
- package/dist/verify-plugin.d.ts.map +1 -0
- package/dist/verify-plugin.js +123 -0
- package/dist/verify-plugin.js.map +1 -0
- package/dist/version-check.d.ts +35 -0
- package/dist/version-check.d.ts.map +1 -0
- package/dist/version-check.js +111 -0
- package/dist/version-check.js.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +22 -0
- package/dist/version.js.map +1 -0
- package/package.json +28 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy plugin discovery (opentabs-plugin.json based).
|
|
3
|
+
*
|
|
4
|
+
* Provides the old discoverPlugins and loadPluginFromDir functions that read
|
|
5
|
+
* opentabs-plugin.json manifests. Used by reload.ts and file-watcher.ts until
|
|
6
|
+
* they are migrated to the new package.json-based pipeline in later stories.
|
|
7
|
+
*
|
|
8
|
+
* This file will be deleted once US-009 (reload.ts), US-012 (file-watcher.ts),
|
|
9
|
+
* and US-020 (cleanup) are complete.
|
|
10
|
+
*/
|
|
11
|
+
import { browserTools } from './browser-tools/index.js';
|
|
12
|
+
import { log } from './logger.js';
|
|
13
|
+
import { parseManifest } from './manifest-schema.js';
|
|
14
|
+
import { isAllowedPluginPath } from './resolver.js';
|
|
15
|
+
import { validatePluginName, validateUrlPattern } from '@opentabs-dev/shared';
|
|
16
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
17
|
+
import { join, resolve, dirname } from 'node:path';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
19
|
+
/**
|
|
20
|
+
* The mcp-server package root directory, resolved from this module's URL.
|
|
21
|
+
* Used as the default rootDir for npm plugin discovery so that `node_modules`
|
|
22
|
+
* scanning works regardless of the process's working directory.
|
|
23
|
+
*/
|
|
24
|
+
const PACKAGE_DIR = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
25
|
+
/**
|
|
26
|
+
* Extract the plugin name from an npm package name.
|
|
27
|
+
* opentabs-plugin-slack → slack
|
|
28
|
+
* @myorg/opentabs-plugin-jira → myorg-jira
|
|
29
|
+
*/
|
|
30
|
+
const pluginNameFromPackage = (pkgName) => {
|
|
31
|
+
if (pkgName.startsWith('@')) {
|
|
32
|
+
// Scoped: @scope/opentabs-plugin-name → scope-name
|
|
33
|
+
const parts = pkgName.split('/');
|
|
34
|
+
const scopePart = parts[0] ?? '';
|
|
35
|
+
const namePart = parts[1] ?? '';
|
|
36
|
+
const scope = scopePart.slice(1); // remove @
|
|
37
|
+
const pluginSuffix = namePart.replace(/^opentabs-plugin-/, '');
|
|
38
|
+
return `${scope}-${pluginSuffix}`;
|
|
39
|
+
}
|
|
40
|
+
return pkgName.replace(/^opentabs-plugin-/, '');
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Determine trust tier from how the plugin was discovered.
|
|
44
|
+
*/
|
|
45
|
+
const determineTrustTierLegacy = (pkgName, isLocal) => {
|
|
46
|
+
if (isLocal)
|
|
47
|
+
return 'local';
|
|
48
|
+
if (pkgName && pkgName.startsWith('@opentabs-dev/'))
|
|
49
|
+
return 'official';
|
|
50
|
+
return 'community';
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Browser tool names that should not appear in plugin tool descriptions.
|
|
54
|
+
* Presence of these names may indicate a prompt injection attempt where
|
|
55
|
+
* a plugin tries to instruct the AI agent to invoke browser-level tools.
|
|
56
|
+
* Derived from the browserTools array so the list stays in sync automatically.
|
|
57
|
+
*/
|
|
58
|
+
const BROWSER_TOOL_NAMES = browserTools.map(t => t.name);
|
|
59
|
+
/**
|
|
60
|
+
* Check plugin tool descriptions for references to browser tool names.
|
|
61
|
+
* Returns an array of { toolName, browserToolName } for each match found.
|
|
62
|
+
*/
|
|
63
|
+
const checkBrowserToolReferences = (tools) => {
|
|
64
|
+
const matches = [];
|
|
65
|
+
for (const tool of tools) {
|
|
66
|
+
const descLower = tool.description.toLowerCase();
|
|
67
|
+
for (const btName of BROWSER_TOOL_NAMES) {
|
|
68
|
+
if (descLower.includes(btName)) {
|
|
69
|
+
matches.push({ toolName: tool.name, browserToolName: btName });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return matches;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Load a single plugin from a directory.
|
|
77
|
+
* Reads opentabs-plugin.json and dist/adapter.iife.js.
|
|
78
|
+
*/
|
|
79
|
+
const loadPluginFromDir = async (dir, trustTier, npmPkgName, sourcePath) => {
|
|
80
|
+
const manifestPath = join(dir, 'opentabs-plugin.json');
|
|
81
|
+
const iifePath = join(dir, 'dist', 'adapter.iife.js');
|
|
82
|
+
// Read and validate manifest
|
|
83
|
+
const manifestRaw = await Bun.file(manifestPath).text();
|
|
84
|
+
const manifest = parseManifest(manifestRaw, manifestPath);
|
|
85
|
+
// Derive the internal plugin name.
|
|
86
|
+
// Handles both bare names ("slack") and legacy prefixed names ("opentabs-plugin-slack").
|
|
87
|
+
let pluginName;
|
|
88
|
+
if (npmPkgName) {
|
|
89
|
+
pluginName = pluginNameFromPackage(npmPkgName);
|
|
90
|
+
const manifestBare = manifest.name.replace(/^opentabs-plugin-/, '');
|
|
91
|
+
if (manifestBare !== pluginName) {
|
|
92
|
+
log.warn(`Plugin manifest name "${manifest.name}" doesn't match package name "${npmPkgName}" (expected plugin name: ${pluginName}, got: ${manifestBare})`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// Local plugin — strip legacy prefix if present
|
|
97
|
+
pluginName = manifest.name.replace(/^opentabs-plugin-/, '');
|
|
98
|
+
}
|
|
99
|
+
// Validate plugin name
|
|
100
|
+
const nameError = validatePluginName(pluginName);
|
|
101
|
+
if (nameError) {
|
|
102
|
+
throw new Error(nameError);
|
|
103
|
+
}
|
|
104
|
+
// Validate URL patterns
|
|
105
|
+
for (const pattern of manifest.url_patterns) {
|
|
106
|
+
const patternError = validateUrlPattern(pattern);
|
|
107
|
+
if (patternError)
|
|
108
|
+
throw new Error(patternError);
|
|
109
|
+
}
|
|
110
|
+
// Warn if any tool description references browser tool names (possible prompt injection)
|
|
111
|
+
for (const match of checkBrowserToolReferences(manifest.tools)) {
|
|
112
|
+
log.warn(`Plugin "${pluginName}" tool "${match.toolName}" description references browser tool "${match.browserToolName}" — possible prompt injection attempt`);
|
|
113
|
+
}
|
|
114
|
+
// Read IIFE — reject missing, empty, or oversized files
|
|
115
|
+
const MAX_IIFE_SIZE = 5 * 1024 * 1024;
|
|
116
|
+
const iifeFile = Bun.file(iifePath);
|
|
117
|
+
if (!(await iifeFile.exists())) {
|
|
118
|
+
throw new Error(`Adapter IIFE not found at ${iifePath}`);
|
|
119
|
+
}
|
|
120
|
+
const iifeSize = iifeFile.size;
|
|
121
|
+
if (iifeSize > MAX_IIFE_SIZE) {
|
|
122
|
+
throw new Error(`Adapter IIFE for "${pluginName}" is ${(iifeSize / 1024 / 1024).toFixed(1)}MB, exceeding the 5MB limit`);
|
|
123
|
+
}
|
|
124
|
+
const iife = await iifeFile.text();
|
|
125
|
+
if (iife.length === 0) {
|
|
126
|
+
throw new Error(`Adapter IIFE at ${iifePath} is empty — rebuild the plugin`);
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
name: pluginName,
|
|
130
|
+
version: manifest.version,
|
|
131
|
+
displayName: manifest.displayName,
|
|
132
|
+
urlPatterns: manifest.url_patterns,
|
|
133
|
+
trustTier,
|
|
134
|
+
iife,
|
|
135
|
+
tools: manifest.tools.map(t => ({
|
|
136
|
+
name: t.name,
|
|
137
|
+
displayName: t.displayName,
|
|
138
|
+
description: t.description,
|
|
139
|
+
icon: t.icon,
|
|
140
|
+
input_schema: t.input_schema,
|
|
141
|
+
output_schema: t.output_schema,
|
|
142
|
+
})),
|
|
143
|
+
adapterHash: manifest.adapterHash,
|
|
144
|
+
sourcePath,
|
|
145
|
+
npmPackageName: npmPkgName ?? undefined,
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Check if a directory exists and is accessible.
|
|
150
|
+
*/
|
|
151
|
+
const dirExists = async (path) => {
|
|
152
|
+
try {
|
|
153
|
+
const s = await stat(path);
|
|
154
|
+
return s.isDirectory();
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Check if a file exists and is accessible.
|
|
162
|
+
*/
|
|
163
|
+
const fileExists = async (path) => Bun.file(path).exists();
|
|
164
|
+
/**
|
|
165
|
+
* Scan node_modules for opentabs plugins.
|
|
166
|
+
* Looks for:
|
|
167
|
+
* 1. node_modules/opentabs-plugin-* directories
|
|
168
|
+
* 2. node_modules/@* /opentabs-plugin-* directories (scoped packages)
|
|
169
|
+
* 3. Any package with 'opentabs-plugin' keyword in package.json
|
|
170
|
+
*
|
|
171
|
+
* Only packages listed in allowedPackages are loaded. Discovered packages
|
|
172
|
+
* not in the allow list are logged as skipped with instructions to add them.
|
|
173
|
+
*/
|
|
174
|
+
const discoverFromNodeModules = async (rootDir, allowedPackages) => {
|
|
175
|
+
const allowedSet = new Set(allowedPackages);
|
|
176
|
+
const results = [];
|
|
177
|
+
const nodeModulesDir = join(rootDir, 'node_modules');
|
|
178
|
+
if (!(await dirExists(nodeModulesDir))) {
|
|
179
|
+
return results;
|
|
180
|
+
}
|
|
181
|
+
let entries;
|
|
182
|
+
try {
|
|
183
|
+
entries = await readdir(nodeModulesDir);
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return results;
|
|
187
|
+
}
|
|
188
|
+
// Track already-discovered package dirs to avoid duplicate keyword scan
|
|
189
|
+
const discoveredDirs = new Set();
|
|
190
|
+
// 1. Direct matches: opentabs-plugin-*
|
|
191
|
+
for (const entry of entries) {
|
|
192
|
+
if (!entry.startsWith('opentabs-plugin-'))
|
|
193
|
+
continue;
|
|
194
|
+
const pkgDir = join(nodeModulesDir, entry);
|
|
195
|
+
if (!(await dirExists(pkgDir)))
|
|
196
|
+
continue;
|
|
197
|
+
if (!(await fileExists(join(pkgDir, 'opentabs-plugin.json'))))
|
|
198
|
+
continue;
|
|
199
|
+
if (!allowedSet.has(entry)) {
|
|
200
|
+
log.info(`Skipping npm plugin "${entry}" — not listed in config.npmPlugins. Add it to ~/.opentabs/config.json to enable.`);
|
|
201
|
+
discoveredDirs.add(pkgDir);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const trustTier = determineTrustTierLegacy(entry, false);
|
|
205
|
+
try {
|
|
206
|
+
const plugin = await loadPluginFromDir(pkgDir, trustTier, entry);
|
|
207
|
+
results.push({ plugin, source: `node_modules/${entry}` });
|
|
208
|
+
discoveredDirs.add(pkgDir);
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
log.error(`Failed to load plugin from node_modules/${entry}:`, err);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// 2. Scoped packages: @scope/opentabs-plugin-*
|
|
215
|
+
for (const entry of entries) {
|
|
216
|
+
if (!entry.startsWith('@'))
|
|
217
|
+
continue;
|
|
218
|
+
const scopeDir = join(nodeModulesDir, entry);
|
|
219
|
+
if (!(await dirExists(scopeDir)))
|
|
220
|
+
continue;
|
|
221
|
+
let scopeEntries;
|
|
222
|
+
try {
|
|
223
|
+
scopeEntries = await readdir(scopeDir);
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
for (const scopeEntry of scopeEntries) {
|
|
229
|
+
if (!scopeEntry.startsWith('opentabs-plugin-'))
|
|
230
|
+
continue;
|
|
231
|
+
const pkgDir = join(scopeDir, scopeEntry);
|
|
232
|
+
if (!(await dirExists(pkgDir)))
|
|
233
|
+
continue;
|
|
234
|
+
if (!(await fileExists(join(pkgDir, 'opentabs-plugin.json'))))
|
|
235
|
+
continue;
|
|
236
|
+
const fullPkgName = `${entry}/${scopeEntry}`;
|
|
237
|
+
if (!allowedSet.has(fullPkgName)) {
|
|
238
|
+
log.info(`Skipping npm plugin "${fullPkgName}" — not listed in config.npmPlugins. Add it to ~/.opentabs/config.json to enable.`);
|
|
239
|
+
discoveredDirs.add(pkgDir);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const trustTier = determineTrustTierLegacy(fullPkgName, false);
|
|
243
|
+
try {
|
|
244
|
+
const plugin = await loadPluginFromDir(pkgDir, trustTier, fullPkgName);
|
|
245
|
+
results.push({
|
|
246
|
+
plugin,
|
|
247
|
+
source: `node_modules/${fullPkgName}`,
|
|
248
|
+
});
|
|
249
|
+
discoveredDirs.add(pkgDir);
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
log.error(`Failed to load plugin from node_modules/${fullPkgName}:`, err);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// 3. Keyword fallback: scan remaining packages for 'opentabs-plugin' keyword.
|
|
257
|
+
// Check for opentabs-plugin.json first (cheap stat) before reading package.json (expensive parse).
|
|
258
|
+
for (const entry of entries) {
|
|
259
|
+
if (entry.startsWith('.') || entry.startsWith('@'))
|
|
260
|
+
continue;
|
|
261
|
+
if (entry.startsWith('opentabs-plugin-'))
|
|
262
|
+
continue; // Already checked
|
|
263
|
+
const pkgDir = join(nodeModulesDir, entry);
|
|
264
|
+
if (discoveredDirs.has(pkgDir))
|
|
265
|
+
continue;
|
|
266
|
+
if (!(await dirExists(pkgDir)))
|
|
267
|
+
continue;
|
|
268
|
+
if (!(await fileExists(join(pkgDir, 'opentabs-plugin.json'))))
|
|
269
|
+
continue;
|
|
270
|
+
const pkgJsonPath = join(pkgDir, 'package.json');
|
|
271
|
+
if (!(await fileExists(pkgJsonPath)))
|
|
272
|
+
continue;
|
|
273
|
+
try {
|
|
274
|
+
const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
|
|
275
|
+
const keywords = pkgJson.keywords;
|
|
276
|
+
if (!Array.isArray(keywords) || !keywords.includes('opentabs-plugin'))
|
|
277
|
+
continue;
|
|
278
|
+
if (!allowedSet.has(entry)) {
|
|
279
|
+
log.info(`Skipping npm plugin "${entry}" — not listed in config.npmPlugins. Add it to ~/.opentabs/config.json to enable.`);
|
|
280
|
+
discoveredDirs.add(pkgDir);
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
const trustTier = determineTrustTierLegacy(entry, false);
|
|
284
|
+
const plugin = await loadPluginFromDir(pkgDir, trustTier, entry);
|
|
285
|
+
results.push({ plugin, source: `node_modules/${entry} (keyword)` });
|
|
286
|
+
discoveredDirs.add(pkgDir);
|
|
287
|
+
}
|
|
288
|
+
catch (err) {
|
|
289
|
+
log.error(`Failed to load plugin from node_modules/${entry} (keyword):`, err);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// Keyword scan for scoped packages too
|
|
293
|
+
for (const entry of entries) {
|
|
294
|
+
if (!entry.startsWith('@'))
|
|
295
|
+
continue;
|
|
296
|
+
const scopeDir = join(nodeModulesDir, entry);
|
|
297
|
+
if (!(await dirExists(scopeDir)))
|
|
298
|
+
continue;
|
|
299
|
+
let scopeEntries;
|
|
300
|
+
try {
|
|
301
|
+
scopeEntries = await readdir(scopeDir);
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
for (const scopeEntry of scopeEntries) {
|
|
307
|
+
if (scopeEntry.startsWith('opentabs-plugin-'))
|
|
308
|
+
continue; // Already checked
|
|
309
|
+
const pkgDir = join(scopeDir, scopeEntry);
|
|
310
|
+
if (discoveredDirs.has(pkgDir))
|
|
311
|
+
continue;
|
|
312
|
+
if (!(await dirExists(pkgDir)))
|
|
313
|
+
continue;
|
|
314
|
+
if (!(await fileExists(join(pkgDir, 'opentabs-plugin.json'))))
|
|
315
|
+
continue;
|
|
316
|
+
const pkgJsonPath = join(pkgDir, 'package.json');
|
|
317
|
+
if (!(await fileExists(pkgJsonPath)))
|
|
318
|
+
continue;
|
|
319
|
+
try {
|
|
320
|
+
const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
|
|
321
|
+
const keywords = pkgJson.keywords;
|
|
322
|
+
if (!Array.isArray(keywords) || !keywords.includes('opentabs-plugin'))
|
|
323
|
+
continue;
|
|
324
|
+
const fullPkgName = `${entry}/${scopeEntry}`;
|
|
325
|
+
if (!allowedSet.has(fullPkgName)) {
|
|
326
|
+
log.info(`Skipping npm plugin "${fullPkgName}" — not listed in config.npmPlugins. Add it to ~/.opentabs/config.json to enable.`);
|
|
327
|
+
discoveredDirs.add(pkgDir);
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
const trustTier = determineTrustTierLegacy(fullPkgName, false);
|
|
331
|
+
const plugin = await loadPluginFromDir(pkgDir, trustTier, fullPkgName);
|
|
332
|
+
results.push({
|
|
333
|
+
plugin,
|
|
334
|
+
source: `node_modules/${fullPkgName} (keyword)`,
|
|
335
|
+
});
|
|
336
|
+
discoveredDirs.add(pkgDir);
|
|
337
|
+
}
|
|
338
|
+
catch (err) {
|
|
339
|
+
log.error(`Failed to load plugin from node_modules/${entry}/${scopeEntry} (keyword):`, err);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return results;
|
|
344
|
+
};
|
|
345
|
+
const discoverFromLocalPaths = async (paths) => {
|
|
346
|
+
const results = [];
|
|
347
|
+
const failures = [];
|
|
348
|
+
for (const pluginPath of paths) {
|
|
349
|
+
const resolvedPath = resolve(pluginPath);
|
|
350
|
+
if (!(await isAllowedPluginPath(resolvedPath))) {
|
|
351
|
+
const msg = `Rejected plugin path outside allowed directories: ${resolvedPath}`;
|
|
352
|
+
log.warn(msg);
|
|
353
|
+
failures.push({ path: resolvedPath, error: 'Path is outside allowed directories' });
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
if (!(await dirExists(resolvedPath))) {
|
|
357
|
+
const msg = `Local plugin path does not exist: ${resolvedPath}`;
|
|
358
|
+
log.warn(msg);
|
|
359
|
+
failures.push({ path: resolvedPath, error: 'Directory does not exist' });
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (!(await fileExists(join(resolvedPath, 'opentabs-plugin.json')))) {
|
|
363
|
+
const msg = `No opentabs-plugin.json found at: ${resolvedPath}`;
|
|
364
|
+
log.warn(msg);
|
|
365
|
+
failures.push({ path: resolvedPath, error: 'No opentabs-plugin.json found' });
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
try {
|
|
369
|
+
const plugin = await loadPluginFromDir(resolvedPath, 'local', null, resolvedPath);
|
|
370
|
+
results.push({ plugin, source: resolvedPath });
|
|
371
|
+
}
|
|
372
|
+
catch (err) {
|
|
373
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
374
|
+
log.error(`Failed to load local plugin from ${resolvedPath}:`, err);
|
|
375
|
+
failures.push({ path: resolvedPath, error: errorMsg });
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return { results, failures };
|
|
379
|
+
};
|
|
380
|
+
/**
|
|
381
|
+
* Legacy plugin discovery using opentabs-plugin.json manifests.
|
|
382
|
+
* Discovers from both node_modules and local filesystem paths.
|
|
383
|
+
*
|
|
384
|
+
* This function will be replaced by the new discoverPlugins in discovery.ts
|
|
385
|
+
* once reload.ts (US-009) and file-watcher.ts (US-012) are migrated.
|
|
386
|
+
*/
|
|
387
|
+
const discoverPluginsLegacy = async (localPaths, allowedNpmPackages, rootDir) => {
|
|
388
|
+
const resolvedRoot = rootDir ?? PACKAGE_DIR;
|
|
389
|
+
log.info('Starting plugin discovery...');
|
|
390
|
+
// Discover from both sources in parallel
|
|
391
|
+
const [npmResults, localDiscovery] = await Promise.all([
|
|
392
|
+
discoverFromNodeModules(resolvedRoot, allowedNpmPackages),
|
|
393
|
+
discoverFromLocalPaths(localPaths),
|
|
394
|
+
]);
|
|
395
|
+
// Local results first so local plugins take precedence over npm in dedup
|
|
396
|
+
const allResults = [...localDiscovery.results, ...npmResults];
|
|
397
|
+
const failures = [...localDiscovery.failures];
|
|
398
|
+
// Build new plugin Map, checking for duplicates
|
|
399
|
+
const plugins = new Map();
|
|
400
|
+
let loaded = 0;
|
|
401
|
+
for (const { plugin, source } of allResults) {
|
|
402
|
+
if (plugins.has(plugin.name)) {
|
|
403
|
+
log.warn(`Duplicate plugin "${plugin.name}" from ${source} — skipping (already loaded)`);
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
plugins.set(plugin.name, plugin);
|
|
407
|
+
loaded++;
|
|
408
|
+
const toolNames = plugin.tools.map(t => t.name).join(', ');
|
|
409
|
+
log.info(`Discovered plugin: ${plugin.name} v${plugin.version} (${plugin.trustTier}) from ${source} — tools: [${toolNames}]`);
|
|
410
|
+
}
|
|
411
|
+
log.info(`Plugin discovery complete: ${loaded} plugin(s) loaded`);
|
|
412
|
+
return { plugins, failures };
|
|
413
|
+
};
|
|
414
|
+
export { discoverPluginsLegacy, loadPluginFromDir };
|
|
415
|
+
//# sourceMappingURL=discovery-legacy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery-legacy.js","sourceRoot":"","sources":["../src/discovery-legacy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Plugin discovery orchestrator: resolve → load → register pipeline. */
|
|
2
|
+
import type { PluginRegistry } from './state.js';
|
|
3
|
+
import type { TrustTier } from '@opentabs-dev/shared';
|
|
4
|
+
/** Outcome of plugin discovery: an immutable registry plus any errors from failed plugins. */
|
|
5
|
+
interface DiscoveryResult {
|
|
6
|
+
readonly registry: PluginRegistry;
|
|
7
|
+
readonly errors: readonly DiscoveryError[];
|
|
8
|
+
}
|
|
9
|
+
/** A single plugin that failed to load during discovery, identified by its specifier. */
|
|
10
|
+
interface DiscoveryError {
|
|
11
|
+
readonly specifier: string;
|
|
12
|
+
readonly error: string;
|
|
13
|
+
}
|
|
14
|
+
/** Determine trust tier for an npm plugin directory path based on its package name. */
|
|
15
|
+
declare const npmTrustTier: (dir: string) => TrustTier;
|
|
16
|
+
/**
|
|
17
|
+
* Discover plugins from auto-discovered npm globals and explicit local paths.
|
|
18
|
+
*
|
|
19
|
+
* Phase 1: Discover npm plugins from global node_modules (auto-discovery).
|
|
20
|
+
* Phase 2: Resolve local plugin paths from config.localPlugins.
|
|
21
|
+
* Phase 3: Load all plugins in parallel.
|
|
22
|
+
* Phase 4: Merge — local plugins override npm plugins of the same name.
|
|
23
|
+
* Phase 5: Build immutable registry.
|
|
24
|
+
*/
|
|
25
|
+
declare const discoverPlugins: (localPlugins: string[], configDir: string) => Promise<DiscoveryResult>;
|
|
26
|
+
export { discoverPlugins, npmTrustTier };
|
|
27
|
+
export type { DiscoveryError, DiscoveryResult };
|
|
28
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,yEAAyE;AAQzE,OAAO,KAAK,EAAgB,cAAc,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,8FAA8F;AAC9F,UAAU,eAAe;IACvB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC;CAC5C;AAED,yFAAyF;AACzF,UAAU,cAAc;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,uFAAuF;AACvF,QAAA,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,SAInC,CAAC;AAEF;;;;;;;;GAQG;AACH,QAAA,MAAM,eAAe,GAAU,cAAc,MAAM,EAAE,EAAE,WAAW,MAAM,KAAG,OAAO,CAAC,eAAe,CAuFjG,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;AACzC,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/** Plugin discovery orchestrator: resolve → load → register pipeline. */
|
|
2
|
+
import { loadPlugin } from './loader.js';
|
|
3
|
+
import { log } from './logger.js';
|
|
4
|
+
import { buildRegistry } from './registry.js';
|
|
5
|
+
import { discoverGlobalNpmPlugins, resolvePluginPath } from './resolver.js';
|
|
6
|
+
import { isErr } from '@opentabs-dev/shared';
|
|
7
|
+
/** Determine trust tier for an npm plugin directory path based on its package name. */
|
|
8
|
+
const npmTrustTier = (dir) => {
|
|
9
|
+
// Scoped @opentabs-dev packages are official
|
|
10
|
+
if (dir.includes('/@opentabs-dev/'))
|
|
11
|
+
return 'official';
|
|
12
|
+
return 'community';
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Discover plugins from auto-discovered npm globals and explicit local paths.
|
|
16
|
+
*
|
|
17
|
+
* Phase 1: Discover npm plugins from global node_modules (auto-discovery).
|
|
18
|
+
* Phase 2: Resolve local plugin paths from config.localPlugins.
|
|
19
|
+
* Phase 3: Load all plugins in parallel.
|
|
20
|
+
* Phase 4: Merge — local plugins override npm plugins of the same name.
|
|
21
|
+
* Phase 5: Build immutable registry.
|
|
22
|
+
*/
|
|
23
|
+
const discoverPlugins = async (localPlugins, configDir) => {
|
|
24
|
+
log.info('Starting plugin discovery...');
|
|
25
|
+
const errors = [];
|
|
26
|
+
const failures = [];
|
|
27
|
+
// Phase 1: Auto-discover npm plugins from global node_modules
|
|
28
|
+
const { dirs: npmDirs, errors: npmErrors } = await discoverGlobalNpmPlugins();
|
|
29
|
+
for (const npmErr of npmErrors) {
|
|
30
|
+
errors.push({ specifier: '(npm auto-discovery)', error: npmErr });
|
|
31
|
+
}
|
|
32
|
+
// Phase 2 + 3: Resolve and load all plugins in parallel
|
|
33
|
+
const loadNpm = npmDirs.map(async (dir) => {
|
|
34
|
+
const trustTier = npmTrustTier(dir);
|
|
35
|
+
const loadResult = await loadPlugin(dir, trustTier, 'npm');
|
|
36
|
+
if (isErr(loadResult)) {
|
|
37
|
+
errors.push({ specifier: dir, error: loadResult.error });
|
|
38
|
+
failures.push({ path: dir, error: loadResult.error });
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return loadResult.value;
|
|
42
|
+
});
|
|
43
|
+
const loadLocal = localPlugins.map(async (specifier) => {
|
|
44
|
+
const resolveResult = await resolvePluginPath(specifier, configDir);
|
|
45
|
+
if (isErr(resolveResult)) {
|
|
46
|
+
errors.push({ specifier, error: resolveResult.error });
|
|
47
|
+
failures.push({ path: specifier, error: resolveResult.error });
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
const dir = resolveResult.value;
|
|
51
|
+
const loadResult = await loadPlugin(dir, 'local', 'local');
|
|
52
|
+
if (isErr(loadResult)) {
|
|
53
|
+
errors.push({ specifier, error: loadResult.error });
|
|
54
|
+
failures.push({ path: dir, error: loadResult.error });
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return loadResult.value;
|
|
58
|
+
});
|
|
59
|
+
const [npmSettled, localSettled] = await Promise.all([Promise.allSettled(loadNpm), Promise.allSettled(loadLocal)]);
|
|
60
|
+
// Collect results
|
|
61
|
+
const collectLoaded = (settled) => {
|
|
62
|
+
const loaded = [];
|
|
63
|
+
for (const result of settled) {
|
|
64
|
+
if (result.status === 'fulfilled' && result.value !== null) {
|
|
65
|
+
loaded.push(result.value);
|
|
66
|
+
}
|
|
67
|
+
else if (result.status === 'rejected') {
|
|
68
|
+
const errorMsg = result.reason instanceof Error ? result.reason.message : String(result.reason);
|
|
69
|
+
errors.push({ specifier: '(unknown)', error: errorMsg });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return loaded;
|
|
73
|
+
};
|
|
74
|
+
const npmLoaded = collectLoaded(npmSettled);
|
|
75
|
+
const localLoaded = collectLoaded(localSettled);
|
|
76
|
+
// Phase 4: Merge — local plugins override npm plugins of the same name
|
|
77
|
+
const merged = new Map();
|
|
78
|
+
for (const plugin of npmLoaded) {
|
|
79
|
+
merged.set(plugin.name, plugin);
|
|
80
|
+
}
|
|
81
|
+
for (const plugin of localLoaded) {
|
|
82
|
+
if (merged.has(plugin.name)) {
|
|
83
|
+
log.info(`Local plugin "${plugin.name}" overrides npm auto-discovered version`);
|
|
84
|
+
}
|
|
85
|
+
merged.set(plugin.name, plugin);
|
|
86
|
+
}
|
|
87
|
+
// Phase 5: Build immutable registry
|
|
88
|
+
const registry = buildRegistry(Array.from(merged.values()), failures);
|
|
89
|
+
for (const plugin of registry.plugins.values()) {
|
|
90
|
+
const toolNames = plugin.tools.map(t => t.name).join(', ');
|
|
91
|
+
log.info(`Discovered plugin: ${plugin.name} v${plugin.version} (${plugin.trustTier}, ${plugin.source}) from ${plugin.sourcePath ?? '(npm)'} — tools: [${toolNames}]`);
|
|
92
|
+
}
|
|
93
|
+
log.info(`Plugin discovery complete: ${registry.plugins.size} plugin(s) loaded, ${errors.length} error(s)`);
|
|
94
|
+
return { registry, errors };
|
|
95
|
+
};
|
|
96
|
+
export { discoverPlugins, npmTrustTier };
|
|
97
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Managed extension auto-install.
|
|
3
|
+
*
|
|
4
|
+
* On every MCP server startup (and hot reload), checks whether the browser
|
|
5
|
+
* extension in ~/.opentabs/extension/ is up to date with the server's package
|
|
6
|
+
* version. If the version file is missing or stale, copies the extension from
|
|
7
|
+
* the platform/browser-extension/ source directory, writes a version marker,
|
|
8
|
+
* and creates the adapters/ directory for plugin IIFEs.
|
|
9
|
+
*
|
|
10
|
+
* The copy excludes build/development artifacts (node_modules, src, .git,
|
|
11
|
+
* tsconfig*) — only the files needed to load an unpacked extension in Chrome.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Ensure the managed extension in ~/.opentabs/extension/ matches the current
|
|
15
|
+
* server version. Copies the extension source if the version is missing or
|
|
16
|
+
* outdated, creating the directory structure as needed.
|
|
17
|
+
*
|
|
18
|
+
* Safe to call on every reload — skips the copy when versions match.
|
|
19
|
+
*/
|
|
20
|
+
interface ExtensionInstallResult {
|
|
21
|
+
/** Whether the extension files were updated (version mismatch detected and files copied) */
|
|
22
|
+
versionChanged: boolean;
|
|
23
|
+
}
|
|
24
|
+
declare const ensureExtensionInstalled: () => Promise<ExtensionInstallResult>;
|
|
25
|
+
export type { ExtensionInstallResult };
|
|
26
|
+
export { ensureExtensionInstalled };
|
|
27
|
+
//# sourceMappingURL=extension-install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension-install.d.ts","sourceRoot":"","sources":["../src/extension-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAkBH;;;;;;GAMG;AACH,UAAU,sBAAsB;IAC9B,4FAA4F;IAC5F,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,QAAA,MAAM,wBAAwB,QAAa,OAAO,CAAC,sBAAsB,CAuDxE,CAAC;AAEF,YAAY,EAAE,sBAAsB,EAAE,CAAC;AACvC,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
|