@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,616 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File watcher for local plugins.
|
|
3
|
+
*
|
|
4
|
+
* Watches local plugin directories (from config.json plugins array) for changes
|
|
5
|
+
* to dist/tools.json and dist/adapter.iife.js. On change:
|
|
6
|
+
* - IIFE change → re-read, send plugin.update to extension
|
|
7
|
+
* - tools.json change → re-read tools AND IIFE, re-register MCP tools, notify MCP clients.
|
|
8
|
+
* Both files are re-read on tools.json change because `bun run build` typically produces
|
|
9
|
+
* both new tools and a new IIFE simultaneously. Re-reading the IIFE here avoids
|
|
10
|
+
* a brief race where the extension has new tool definitions pointing at old adapter code.
|
|
11
|
+
*
|
|
12
|
+
* Only watches local plugins — not npm-installed packages.
|
|
13
|
+
* File change events are debounced at ~200ms.
|
|
14
|
+
*
|
|
15
|
+
* Hot reload safety:
|
|
16
|
+
* Watcher handles and debounce timers are stored on ServerState (not module-level
|
|
17
|
+
* variables) so that stopFileWatching() — called from the NEW module after
|
|
18
|
+
* bun --hot re-evaluates — can always reach and close the PREVIOUS iteration's
|
|
19
|
+
* FSWatcher instances. Module-level variables reset to empty on each reload,
|
|
20
|
+
* which would orphan the old handles.
|
|
21
|
+
*/
|
|
22
|
+
import { getConfigDir } from './config.js';
|
|
23
|
+
import { loadPlugin } from './loader.js';
|
|
24
|
+
import { log } from './logger.js';
|
|
25
|
+
import { buildRegistry } from './registry.js';
|
|
26
|
+
import { isOk } from '@opentabs-dev/shared';
|
|
27
|
+
import { statSync, watch } from 'node:fs';
|
|
28
|
+
import { join } from 'node:path';
|
|
29
|
+
/** Polling interval for mtime-based fallback detection (ms) */
|
|
30
|
+
const MTIME_POLL_INTERVAL_MS = 30_000;
|
|
31
|
+
/** Number of polling detections within the window that triggers a stale-watcher warning */
|
|
32
|
+
const STALE_WATCHER_THRESHOLD = 3;
|
|
33
|
+
/** Time window (ms) for counting polling detections toward a stale-watcher warning */
|
|
34
|
+
const STALE_WATCHER_WINDOW_MS = 5 * 60 * 1000;
|
|
35
|
+
/** Maximum number of detection timestamps to keep (prevents unbounded growth) */
|
|
36
|
+
const MAX_DETECTION_TIMESTAMPS = 20;
|
|
37
|
+
/**
|
|
38
|
+
* Read a file with retries and exponential backoff.
|
|
39
|
+
* Handles the case where the file is briefly unavailable during a write.
|
|
40
|
+
*/
|
|
41
|
+
const readFileWithRetry = async (path, maxRetries = 3, initialDelayMs = 100) => {
|
|
42
|
+
let delay = initialDelayMs;
|
|
43
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
44
|
+
try {
|
|
45
|
+
return await Bun.file(path).text();
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
if (attempt === maxRetries)
|
|
49
|
+
throw err;
|
|
50
|
+
await new Promise(r => setTimeout(r, delay));
|
|
51
|
+
delay *= 2;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
throw new Error('readFileWithRetry: unreachable');
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Check if a file exists.
|
|
58
|
+
*/
|
|
59
|
+
const fileExists = async (path) => Bun.file(path).exists();
|
|
60
|
+
/**
|
|
61
|
+
* Get the mtimeMs for a file, or null if the file does not exist or stat fails.
|
|
62
|
+
*/
|
|
63
|
+
const getFileMtimeMs = (path) => {
|
|
64
|
+
try {
|
|
65
|
+
const stat = statSync(path, { throwIfNoEntry: false });
|
|
66
|
+
return stat ? stat.mtimeMs : null;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Find the FileWatcherEntry for a given plugin directory.
|
|
74
|
+
*/
|
|
75
|
+
const findEntry = (state, pluginDir) => state.fileWatcherEntries.find(e => e.pluginDir === pluginDir);
|
|
76
|
+
/**
|
|
77
|
+
* Record the current mtime for a file on a FileWatcherEntry's lastSeenMtimes map.
|
|
78
|
+
*/
|
|
79
|
+
const recordMtime = (entry, filePath) => {
|
|
80
|
+
const mtime = getFileMtimeMs(filePath);
|
|
81
|
+
if (mtime !== null) {
|
|
82
|
+
entry.lastSeenMtimes.set(filePath, mtime);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Record a mtime poll detection and emit a warning if detections exceed the
|
|
87
|
+
* threshold within the rolling window. Keeps the timestamps array bounded.
|
|
88
|
+
*/
|
|
89
|
+
const recordPollDetection = (state) => {
|
|
90
|
+
const now = Date.now();
|
|
91
|
+
state.mtimePollDetections++;
|
|
92
|
+
state.mtimePollDetectionTimestamps.push(now);
|
|
93
|
+
// Trim to bounded size
|
|
94
|
+
if (state.mtimePollDetectionTimestamps.length > MAX_DETECTION_TIMESTAMPS) {
|
|
95
|
+
state.mtimePollDetectionTimestamps = state.mtimePollDetectionTimestamps.slice(-MAX_DETECTION_TIMESTAMPS);
|
|
96
|
+
}
|
|
97
|
+
// Count detections within the window
|
|
98
|
+
const windowStart = now - STALE_WATCHER_WINDOW_MS;
|
|
99
|
+
const recentDetections = state.mtimePollDetectionTimestamps.filter(ts => ts >= windowStart);
|
|
100
|
+
// Emit warning exactly when crossing the threshold (not on every subsequent detection)
|
|
101
|
+
if (recentDetections.length === STALE_WATCHER_THRESHOLD) {
|
|
102
|
+
log.warn(`File watchers may be stale — detected ${STALE_WATCHER_THRESHOLD} changes via polling that fs.watch missed. Consider restarting the MCP server.`);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Extract the adapter hash embedded by the CLI's hash-setter snippet.
|
|
107
|
+
*
|
|
108
|
+
* The `opentabs-plugin build` CLI appends a self-contained hash-setter IIFE to every
|
|
109
|
+
* adapter bundle: `a.__adapterHash="<sha256-of-core-content>";`. The embedded
|
|
110
|
+
* hash is computed from the core IIFE content BEFORE the hash-setter is
|
|
111
|
+
* appended, so it matches what the injected adapter reports at runtime.
|
|
112
|
+
*
|
|
113
|
+
* Computing SHA-256 of the full file (including the hash-setter) produces a
|
|
114
|
+
* different value and causes spurious hash-mismatch errors in the extension.
|
|
115
|
+
* Reading the embedded hash directly is always correct.
|
|
116
|
+
*
|
|
117
|
+
* Returns undefined for old adapters built without the hash-setter.
|
|
118
|
+
*/
|
|
119
|
+
const extractEmbeddedAdapterHash = (iife) => {
|
|
120
|
+
const match = iife.match(/\.__adapterHash="([0-9a-f]{64})"/);
|
|
121
|
+
return match?.[1];
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Handle an IIFE file change for a local plugin.
|
|
125
|
+
*/
|
|
126
|
+
const handleIifeChange = async (state, pluginName, pluginDir, callbacks) => {
|
|
127
|
+
const iifePath = join(pluginDir, 'dist', 'adapter.iife.js');
|
|
128
|
+
if (!(await fileExists(iifePath))) {
|
|
129
|
+
log.warn(`File watcher: IIFE not found at ${iifePath} — skipping`);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const iife = await readFileWithRetry(iifePath);
|
|
134
|
+
const plugin = state.registry.plugins.get(pluginName);
|
|
135
|
+
if (!plugin) {
|
|
136
|
+
log.warn(`File watcher: Plugin "${pluginName}" not found in state — skipping IIFE update`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
// Update in-memory plugin state
|
|
140
|
+
plugin.iife = iife;
|
|
141
|
+
// Use the hash embedded in the IIFE by the CLI's hash-setter snippet. The
|
|
142
|
+
// embedded hash is SHA-256 of the core content (before the hash-setter was
|
|
143
|
+
// appended), which is what the adapter reports at runtime via __adapterHash.
|
|
144
|
+
// Computing SHA-256 of the full file would include the hash-setter and
|
|
145
|
+
// produce a value that never matches the runtime adapter hash.
|
|
146
|
+
const embeddedHash = extractEmbeddedAdapterHash(iife);
|
|
147
|
+
if (embeddedHash) {
|
|
148
|
+
plugin.adapterHash = embeddedHash;
|
|
149
|
+
}
|
|
150
|
+
// Read source map if available
|
|
151
|
+
const sourceMapPath = join(pluginDir, 'dist', 'adapter.iife.js.map');
|
|
152
|
+
let sourceMap;
|
|
153
|
+
try {
|
|
154
|
+
if (await fileExists(sourceMapPath)) {
|
|
155
|
+
sourceMap = await readFileWithRetry(sourceMapPath);
|
|
156
|
+
plugin.iifeSourceMap = sourceMap;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// Source map read failed — proceed without it
|
|
161
|
+
}
|
|
162
|
+
// Update mtime for polling fallback
|
|
163
|
+
const entry = findEntry(state, pluginDir);
|
|
164
|
+
if (entry)
|
|
165
|
+
recordMtime(entry, iifePath);
|
|
166
|
+
log.info(`File watcher: IIFE updated for "${pluginName}" — sending plugin.update`);
|
|
167
|
+
callbacks.onIifeChanged(pluginName, iife, sourceMap);
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
log.error(`File watcher: Failed to read IIFE for "${pluginName}":`, err);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* Parse a tools.json file contents into validated ManifestTool[].
|
|
175
|
+
* Supports both legacy array format and current { tools: [...] } format.
|
|
176
|
+
* Returns null if parsing fails.
|
|
177
|
+
*/
|
|
178
|
+
const parseToolsJson = (raw, filePath) => {
|
|
179
|
+
let parsed;
|
|
180
|
+
try {
|
|
181
|
+
parsed = JSON.parse(raw);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
log.error(`File watcher: Invalid JSON in ${filePath}`);
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
// Extract the tools array from either format
|
|
188
|
+
let toolsArray;
|
|
189
|
+
if (Array.isArray(parsed)) {
|
|
190
|
+
toolsArray = parsed;
|
|
191
|
+
}
|
|
192
|
+
else if (typeof parsed === 'object' && parsed !== null && 'tools' in parsed) {
|
|
193
|
+
const candidate = parsed.tools;
|
|
194
|
+
if (!Array.isArray(candidate)) {
|
|
195
|
+
log.error(`File watcher: ${filePath} .tools is not an array`);
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
toolsArray = candidate;
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
log.error(`File watcher: ${filePath} is not a valid manifest`);
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
const tools = [];
|
|
205
|
+
for (const t of toolsArray) {
|
|
206
|
+
if (typeof t !== 'object' || t === null)
|
|
207
|
+
continue;
|
|
208
|
+
const obj = t;
|
|
209
|
+
if (typeof obj.name !== 'string' || typeof obj.description !== 'string')
|
|
210
|
+
continue;
|
|
211
|
+
const displayName = typeof obj.displayName === 'string' ? obj.displayName : obj.name;
|
|
212
|
+
const icon = typeof obj.icon === 'string' ? obj.icon : 'wrench';
|
|
213
|
+
const inputSchema = typeof obj.input_schema === 'object' && obj.input_schema !== null
|
|
214
|
+
? obj.input_schema
|
|
215
|
+
: { type: 'object', properties: {} };
|
|
216
|
+
const outputSchema = typeof obj.output_schema === 'object' && obj.output_schema !== null
|
|
217
|
+
? obj.output_schema
|
|
218
|
+
: { type: 'object', properties: {} };
|
|
219
|
+
tools.push({
|
|
220
|
+
name: obj.name,
|
|
221
|
+
displayName,
|
|
222
|
+
description: obj.description,
|
|
223
|
+
icon,
|
|
224
|
+
input_schema: inputSchema,
|
|
225
|
+
output_schema: outputSchema,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
return tools;
|
|
229
|
+
};
|
|
230
|
+
/**
|
|
231
|
+
* Handle a dist/tools.json file change for a local plugin.
|
|
232
|
+
*
|
|
233
|
+
* Also re-reads the IIFE from disk because `bun run build` typically updates
|
|
234
|
+
* both tools.json and IIFE simultaneously. Without this, the tools.json watcher
|
|
235
|
+
* would send a plugin.update with the old IIFE, and the extension would
|
|
236
|
+
* briefly have new tool definitions pointing at stale adapter code until
|
|
237
|
+
* the IIFE watcher fires separately.
|
|
238
|
+
*/
|
|
239
|
+
const handleToolsJsonChange = async (state, pluginName, pluginDir, callbacks) => {
|
|
240
|
+
const toolsJsonPath = join(pluginDir, 'dist', 'tools.json');
|
|
241
|
+
if (!(await fileExists(toolsJsonPath))) {
|
|
242
|
+
log.warn(`File watcher: tools.json not found at ${toolsJsonPath} — skipping`);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
const raw = await readFileWithRetry(toolsJsonPath);
|
|
247
|
+
const tools = parseToolsJson(raw, toolsJsonPath);
|
|
248
|
+
if (!tools)
|
|
249
|
+
return;
|
|
250
|
+
const plugin = state.registry.plugins.get(pluginName);
|
|
251
|
+
if (!plugin) {
|
|
252
|
+
log.warn(`File watcher: Plugin "${pluginName}" not found in state — skipping tools.json update`);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
// Update tool definitions
|
|
256
|
+
plugin.tools = tools;
|
|
257
|
+
// Re-read IIFE from disk so the extension has the latest adapter code.
|
|
258
|
+
// Use the hash embedded in the IIFE rather than recomputing from the full
|
|
259
|
+
// file. The full file includes the hash-setter snippet, so SHA-256(full
|
|
260
|
+
// file) differs from SHA-256(core content) = the value the runtime adapter
|
|
261
|
+
// reports. The embedded hash is always authoritative.
|
|
262
|
+
const iifePath = join(pluginDir, 'dist', 'adapter.iife.js');
|
|
263
|
+
if (await fileExists(iifePath)) {
|
|
264
|
+
try {
|
|
265
|
+
const iife = await readFileWithRetry(iifePath);
|
|
266
|
+
plugin.iife = iife;
|
|
267
|
+
const embeddedHash = extractEmbeddedAdapterHash(iife);
|
|
268
|
+
if (embeddedHash) {
|
|
269
|
+
plugin.adapterHash = embeddedHash;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
// IIFE read failed — the IIFE watcher will handle it separately
|
|
274
|
+
}
|
|
275
|
+
// Read source map if available
|
|
276
|
+
const sourceMapPath = join(pluginDir, 'dist', 'adapter.iife.js.map');
|
|
277
|
+
try {
|
|
278
|
+
if (await fileExists(sourceMapPath)) {
|
|
279
|
+
plugin.iifeSourceMap = await readFileWithRetry(sourceMapPath);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
// Source map read failed — proceed without it
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
// Update mtimes for polling fallback (both tools.json and IIFE were re-read)
|
|
287
|
+
const entry = findEntry(state, pluginDir);
|
|
288
|
+
if (entry) {
|
|
289
|
+
recordMtime(entry, toolsJsonPath);
|
|
290
|
+
recordMtime(entry, iifePath);
|
|
291
|
+
}
|
|
292
|
+
log.info(`File watcher: tools.json updated for "${pluginName}" — re-registering MCP tools`);
|
|
293
|
+
callbacks.onManifestChanged(pluginName);
|
|
294
|
+
}
|
|
295
|
+
catch (err) {
|
|
296
|
+
log.error(`File watcher: Failed to read tools.json for "${pluginName}":`, err);
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
/**
|
|
300
|
+
* Handle a file change in a pending plugin directory (one that failed initial
|
|
301
|
+
* discovery). Attempts full discovery via loadPlugin; on success, adds
|
|
302
|
+
* the plugin to state and invokes onPluginDiscovered so MCP tools are
|
|
303
|
+
* re-registered and the extension is synced.
|
|
304
|
+
*/
|
|
305
|
+
const handlePendingPluginChange = async (state, pluginDir, callbacks) => {
|
|
306
|
+
const result = await loadPlugin(pluginDir, 'local', 'local');
|
|
307
|
+
if (!isOk(result))
|
|
308
|
+
return; // Discovery still failing — keep watching silently
|
|
309
|
+
const plugin = result.value;
|
|
310
|
+
// Plugin loaded successfully — add to registry
|
|
311
|
+
if (state.registry.plugins.has(plugin.name)) {
|
|
312
|
+
log.warn(`File watcher: Pending plugin "${plugin.name}" at ${pluginDir} conflicts with existing plugin — skipping`);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
// Build a new registry that includes the newly discovered plugin
|
|
316
|
+
const updatedPlugins = [...state.registry.plugins.values(), plugin];
|
|
317
|
+
state.registry = buildRegistry(updatedPlugins, [...state.registry.failures]);
|
|
318
|
+
// Update mtimes for polling fallback
|
|
319
|
+
const entry = findEntry(state, pluginDir);
|
|
320
|
+
if (entry) {
|
|
321
|
+
recordMtime(entry, join(pluginDir, 'dist', 'tools.json'));
|
|
322
|
+
recordMtime(entry, join(pluginDir, 'dist', 'adapter.iife.js'));
|
|
323
|
+
}
|
|
324
|
+
log.info(`File watcher: Discovered pending plugin "${plugin.name}" at ${pluginDir}`);
|
|
325
|
+
callbacks.onPluginDiscovered(plugin.name);
|
|
326
|
+
};
|
|
327
|
+
/**
|
|
328
|
+
* Set up file watching for a pending plugin directory (one that failed initial
|
|
329
|
+
* discovery). Watches for tools.json and IIFE changes in dist/, and attempts
|
|
330
|
+
* full discovery on each change.
|
|
331
|
+
*/
|
|
332
|
+
const watchPendingPlugin = (state, pluginDir, callbacks) => {
|
|
333
|
+
const watchers = [];
|
|
334
|
+
const distDir = join(pluginDir, 'dist');
|
|
335
|
+
const gen = state.fileWatcherGeneration;
|
|
336
|
+
// Watch dist directory for tools.json and IIFE creation/changes
|
|
337
|
+
try {
|
|
338
|
+
const distWatcher = watch(distDir, (_eventType, filename) => {
|
|
339
|
+
if (filename !== 'tools.json' && filename !== 'adapter.iife.js')
|
|
340
|
+
return;
|
|
341
|
+
const key = `${pluginDir}:pending`;
|
|
342
|
+
const existing = state.fileWatcherTimers.get(key);
|
|
343
|
+
if (existing)
|
|
344
|
+
clearTimeout(existing);
|
|
345
|
+
state.fileWatcherTimers.set(key, setTimeout(() => {
|
|
346
|
+
state.fileWatcherTimers.delete(key);
|
|
347
|
+
if (state.fileWatcherGeneration !== gen)
|
|
348
|
+
return;
|
|
349
|
+
void handlePendingPluginChange(state, pluginDir, callbacks);
|
|
350
|
+
}, 200));
|
|
351
|
+
});
|
|
352
|
+
watchers.push(distWatcher);
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
// dist/ may not exist yet — will be watched once plugin is rebuilt
|
|
356
|
+
}
|
|
357
|
+
return { pluginDir, pluginName: `(pending:${pluginDir})`, watchers, lastSeenMtimes: new Map() };
|
|
358
|
+
};
|
|
359
|
+
/**
|
|
360
|
+
* Set up file watching for a single local plugin directory.
|
|
361
|
+
*
|
|
362
|
+
* Watches the dist/ subdirectory for tools.json and adapter.iife.js changes.
|
|
363
|
+
* Uses directory-level watching (not file-level) because on macOS, file-level
|
|
364
|
+
* fs.watch() via kqueue fails to deliver events after a close + recreate cycle
|
|
365
|
+
* (which happens on every hot reload). Directory-level watching uses FSEvents
|
|
366
|
+
* on macOS and reliably delivers events across watcher restarts.
|
|
367
|
+
*/
|
|
368
|
+
const watchPlugin = (state, pluginDir, pluginName, callbacks) => {
|
|
369
|
+
const watchers = [];
|
|
370
|
+
const distDir = join(pluginDir, 'dist');
|
|
371
|
+
const gen = state.fileWatcherGeneration;
|
|
372
|
+
// Watch dist directory for tools.json and IIFE changes
|
|
373
|
+
try {
|
|
374
|
+
const distWatcher = watch(distDir, (_eventType, filename) => {
|
|
375
|
+
if (filename === 'tools.json') {
|
|
376
|
+
const key = `${pluginDir}:tools`;
|
|
377
|
+
const existing = state.fileWatcherTimers.get(key);
|
|
378
|
+
if (existing)
|
|
379
|
+
clearTimeout(existing);
|
|
380
|
+
state.fileWatcherTimers.set(key, setTimeout(() => {
|
|
381
|
+
state.fileWatcherTimers.delete(key);
|
|
382
|
+
if (state.fileWatcherGeneration !== gen)
|
|
383
|
+
return;
|
|
384
|
+
void handleToolsJsonChange(state, pluginName, pluginDir, callbacks);
|
|
385
|
+
}, 200));
|
|
386
|
+
}
|
|
387
|
+
else if (filename === 'adapter.iife.js') {
|
|
388
|
+
const key = `${pluginDir}:iife`;
|
|
389
|
+
const existing = state.fileWatcherTimers.get(key);
|
|
390
|
+
if (existing)
|
|
391
|
+
clearTimeout(existing);
|
|
392
|
+
state.fileWatcherTimers.set(key, setTimeout(() => {
|
|
393
|
+
state.fileWatcherTimers.delete(key);
|
|
394
|
+
if (state.fileWatcherGeneration !== gen)
|
|
395
|
+
return;
|
|
396
|
+
void handleIifeChange(state, pluginName, pluginDir, callbacks);
|
|
397
|
+
}, 200));
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
watchers.push(distWatcher);
|
|
401
|
+
}
|
|
402
|
+
catch (err) {
|
|
403
|
+
log.warn(`File watcher: Could not watch dist dir at ${distDir}:`, err);
|
|
404
|
+
}
|
|
405
|
+
return { pluginDir, pluginName, watchers, lastSeenMtimes: new Map() };
|
|
406
|
+
};
|
|
407
|
+
/**
|
|
408
|
+
* Start watching the config directory for changes to config.json.
|
|
409
|
+
* Uses directory-level watching (not file-level) because on macOS, file-level
|
|
410
|
+
* fs.watch() via kqueue fails to deliver events after a close + recreate cycle.
|
|
411
|
+
* The debounce pattern matches plugin file watchers — uses fileWatcherTimers
|
|
412
|
+
* with a 'config' key and checks fileWatcherGeneration to discard stale callbacks.
|
|
413
|
+
*/
|
|
414
|
+
const startConfigWatching = (state, callbacks) => {
|
|
415
|
+
// Close any existing config watcher
|
|
416
|
+
if (state.configWatcher) {
|
|
417
|
+
state.configWatcher.close();
|
|
418
|
+
state.configWatcher = null;
|
|
419
|
+
}
|
|
420
|
+
const configDir = getConfigDir();
|
|
421
|
+
const gen = state.fileWatcherGeneration;
|
|
422
|
+
// Record initial config.json mtime for mtime polling fallback
|
|
423
|
+
const configPath = join(configDir, 'config.json');
|
|
424
|
+
state.configLastSeenMtime = getFileMtimeMs(configPath);
|
|
425
|
+
try {
|
|
426
|
+
state.configWatcher = watch(configDir, (_eventType, filename) => {
|
|
427
|
+
if (filename !== 'config.json')
|
|
428
|
+
return;
|
|
429
|
+
const key = 'config';
|
|
430
|
+
const existing = state.fileWatcherTimers.get(key);
|
|
431
|
+
if (existing)
|
|
432
|
+
clearTimeout(existing);
|
|
433
|
+
state.fileWatcherTimers.set(key, setTimeout(() => {
|
|
434
|
+
state.fileWatcherTimers.delete(key);
|
|
435
|
+
if (state.fileWatcherGeneration !== gen)
|
|
436
|
+
return;
|
|
437
|
+
log.info('Config watcher: config.json changed — triggering reload');
|
|
438
|
+
// Update config mtime for polling fallback
|
|
439
|
+
state.configLastSeenMtime = getFileMtimeMs(configPath);
|
|
440
|
+
callbacks.onConfigChanged();
|
|
441
|
+
}, 200));
|
|
442
|
+
});
|
|
443
|
+
log.info(`Config watcher: Watching ${configDir} for config.json changes`);
|
|
444
|
+
}
|
|
445
|
+
catch (err) {
|
|
446
|
+
log.warn(`Config watcher: Could not watch config dir at ${configDir}:`, err);
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
/**
|
|
450
|
+
* Start periodic mtime polling as a fallback for stale fs.watch() watchers.
|
|
451
|
+
*
|
|
452
|
+
* fs.watch() can go stale on macOS (FSEvents bug in long-running Bun processes)
|
|
453
|
+
* and Linux (inotify limits). This polling loop stats every watched file and
|
|
454
|
+
* config.json on a fixed interval. If a file's mtime is newer than what was
|
|
455
|
+
* last recorded, the appropriate handler is invoked — the same handler that
|
|
456
|
+
* fs.watch() would have called. Because handlers already debounce and check
|
|
457
|
+
* fileWatcherGeneration, duplicate invocations from both fs.watch() and
|
|
458
|
+
* polling are safely deduplicated.
|
|
459
|
+
*/
|
|
460
|
+
const startMtimePolling = (state, callbacks) => {
|
|
461
|
+
// Clean up any existing poll timer (defensive — stopFileWatching should clear this)
|
|
462
|
+
if (state.mtimePollTimerId !== null) {
|
|
463
|
+
clearInterval(state.mtimePollTimerId);
|
|
464
|
+
state.mtimePollTimerId = null;
|
|
465
|
+
}
|
|
466
|
+
const gen = state.fileWatcherGeneration;
|
|
467
|
+
state.mtimePollTimerId = setInterval(() => {
|
|
468
|
+
// Bail out if a new generation started (hot reload happened)
|
|
469
|
+
if (state.fileWatcherGeneration !== gen) {
|
|
470
|
+
if (state.mtimePollTimerId !== null) {
|
|
471
|
+
clearInterval(state.mtimePollTimerId);
|
|
472
|
+
state.mtimePollTimerId = null;
|
|
473
|
+
}
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
state.mtimeLastPollAt = Date.now();
|
|
477
|
+
// Poll plugin files (tools.json + IIFE)
|
|
478
|
+
for (const entry of state.fileWatcherEntries) {
|
|
479
|
+
const toolsJsonPath = join(entry.pluginDir, 'dist', 'tools.json');
|
|
480
|
+
const iifePath = join(entry.pluginDir, 'dist', 'adapter.iife.js');
|
|
481
|
+
const isPending = entry.pluginName.startsWith('(pending:');
|
|
482
|
+
// Check tools.json mtime
|
|
483
|
+
const toolsMtime = getFileMtimeMs(toolsJsonPath);
|
|
484
|
+
const lastToolsMtime = entry.lastSeenMtimes.get(toolsJsonPath);
|
|
485
|
+
if (toolsMtime !== null && lastToolsMtime !== undefined && toolsMtime > lastToolsMtime) {
|
|
486
|
+
log.info(`Mtime poll: Detected change to ${toolsJsonPath} (old=${lastToolsMtime}, new=${toolsMtime}) — fs.watch may be stale`);
|
|
487
|
+
recordPollDetection(state);
|
|
488
|
+
entry.lastSeenMtimes.set(toolsJsonPath, toolsMtime);
|
|
489
|
+
if (isPending) {
|
|
490
|
+
void handlePendingPluginChange(state, entry.pluginDir, callbacks);
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
void handleToolsJsonChange(state, entry.pluginName, entry.pluginDir, callbacks);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
// Check IIFE mtime
|
|
497
|
+
const iifeMtime = getFileMtimeMs(iifePath);
|
|
498
|
+
const lastIifeMtime = entry.lastSeenMtimes.get(iifePath);
|
|
499
|
+
if (iifeMtime !== null && lastIifeMtime !== undefined && iifeMtime > lastIifeMtime) {
|
|
500
|
+
log.info(`Mtime poll: Detected change to ${iifePath} (old=${lastIifeMtime}, new=${iifeMtime}) — fs.watch may be stale`);
|
|
501
|
+
recordPollDetection(state);
|
|
502
|
+
entry.lastSeenMtimes.set(iifePath, iifeMtime);
|
|
503
|
+
if (isPending) {
|
|
504
|
+
void handlePendingPluginChange(state, entry.pluginDir, callbacks);
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
void handleIifeChange(state, entry.pluginName, entry.pluginDir, callbacks);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
// Poll config.json mtime
|
|
512
|
+
const configPath = join(getConfigDir(), 'config.json');
|
|
513
|
+
const configMtime = getFileMtimeMs(configPath);
|
|
514
|
+
if (configMtime !== null && state.configLastSeenMtime !== null && configMtime > state.configLastSeenMtime) {
|
|
515
|
+
log.info(`Mtime poll: Detected change to ${configPath} (old=${state.configLastSeenMtime}, new=${configMtime}) — fs.watch may be stale`);
|
|
516
|
+
recordPollDetection(state);
|
|
517
|
+
state.configLastSeenMtime = configMtime;
|
|
518
|
+
callbacks.onConfigChanged();
|
|
519
|
+
}
|
|
520
|
+
}, MTIME_POLL_INTERVAL_MS);
|
|
521
|
+
log.info(`Mtime polling started (interval=${MTIME_POLL_INTERVAL_MS}ms)`);
|
|
522
|
+
};
|
|
523
|
+
/**
|
|
524
|
+
* Start file watching for all local plugins and pending plugin paths.
|
|
525
|
+
*
|
|
526
|
+
* Watches two categories:
|
|
527
|
+
* 1. Successfully loaded local plugins (from state.plugins) — watches for
|
|
528
|
+
* manifest and IIFE updates using the existing per-event handlers.
|
|
529
|
+
* 2. Pending plugin paths (configured in config.json but failed initial
|
|
530
|
+
* discovery) — watches for any file changes and reattempts full discovery
|
|
531
|
+
* via loadPluginFromDir.
|
|
532
|
+
*
|
|
533
|
+
* @param resolvedPluginPaths - Absolute paths to all configured local plugin
|
|
534
|
+
* directories (from config.json, resolved against the config dir). Paths
|
|
535
|
+
* that exist on disk but are not in state.plugins are watched as pending.
|
|
536
|
+
*/
|
|
537
|
+
const startFileWatching = (state, callbacks, resolvedPluginPaths = []) => {
|
|
538
|
+
// Clean up any existing watchers first
|
|
539
|
+
stopFileWatching(state);
|
|
540
|
+
state.fileWatcherGeneration++;
|
|
541
|
+
// Build set of paths already successfully loaded
|
|
542
|
+
const loadedPaths = new Set();
|
|
543
|
+
// Watch successfully loaded local plugins
|
|
544
|
+
const localPlugins = Array.from(state.registry.plugins.values()).filter(p => p.trustTier === 'local' && p.sourcePath);
|
|
545
|
+
for (const plugin of localPlugins) {
|
|
546
|
+
const srcPath = plugin.sourcePath;
|
|
547
|
+
if (!srcPath)
|
|
548
|
+
continue;
|
|
549
|
+
loadedPaths.add(srcPath);
|
|
550
|
+
const entry = watchPlugin(state, srcPath, plugin.name, callbacks);
|
|
551
|
+
state.fileWatcherEntries.push(entry);
|
|
552
|
+
// Record initial mtimes for mtime polling fallback
|
|
553
|
+
recordMtime(entry, join(srcPath, 'dist', 'tools.json'));
|
|
554
|
+
recordMtime(entry, join(srcPath, 'dist', 'adapter.iife.js'));
|
|
555
|
+
log.info(`File watcher: Watching "${plugin.name}" at ${srcPath}`);
|
|
556
|
+
}
|
|
557
|
+
// Watch pending plugin paths that failed initial discovery
|
|
558
|
+
let pendingCount = 0;
|
|
559
|
+
for (const pluginPath of resolvedPluginPaths) {
|
|
560
|
+
if (loadedPaths.has(pluginPath))
|
|
561
|
+
continue;
|
|
562
|
+
// Skip paths that don't exist on disk
|
|
563
|
+
try {
|
|
564
|
+
if (!statSync(pluginPath, { throwIfNoEntry: false })?.isDirectory())
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
catch {
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
const entry = watchPendingPlugin(state, pluginPath, callbacks);
|
|
571
|
+
state.fileWatcherEntries.push(entry);
|
|
572
|
+
// Record initial mtimes for mtime polling fallback
|
|
573
|
+
recordMtime(entry, join(pluginPath, 'dist', 'tools.json'));
|
|
574
|
+
recordMtime(entry, join(pluginPath, 'dist', 'adapter.iife.js'));
|
|
575
|
+
pendingCount++;
|
|
576
|
+
log.info(`File watcher: Watching pending plugin path at ${pluginPath}`);
|
|
577
|
+
}
|
|
578
|
+
const loadedCount = state.fileWatcherEntries.length - pendingCount;
|
|
579
|
+
if (loadedCount === 0 && pendingCount === 0) {
|
|
580
|
+
log.info('File watcher: No local plugins to watch');
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
log.info(`File watcher: Watching ${loadedCount} loaded + ${pendingCount} pending plugin path(s)`);
|
|
584
|
+
}
|
|
585
|
+
// Start mtime polling as a fallback for stale fs.watch() watchers
|
|
586
|
+
startMtimePolling(state, callbacks);
|
|
587
|
+
};
|
|
588
|
+
/**
|
|
589
|
+
* Stop all file watchers and clean up.
|
|
590
|
+
* Reads watcher handles and timers from state (not module-level variables)
|
|
591
|
+
* so that the new module after hot reload can close the old module's watchers.
|
|
592
|
+
*/
|
|
593
|
+
const stopFileWatching = (state) => {
|
|
594
|
+
for (const entry of state.fileWatcherEntries) {
|
|
595
|
+
for (const watcher of entry.watchers) {
|
|
596
|
+
watcher.close();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
state.fileWatcherEntries.length = 0;
|
|
600
|
+
// Close config watcher
|
|
601
|
+
if (state.configWatcher) {
|
|
602
|
+
state.configWatcher.close();
|
|
603
|
+
state.configWatcher = null;
|
|
604
|
+
}
|
|
605
|
+
// Stop mtime polling
|
|
606
|
+
if (state.mtimePollTimerId !== null) {
|
|
607
|
+
clearInterval(state.mtimePollTimerId);
|
|
608
|
+
state.mtimePollTimerId = null;
|
|
609
|
+
}
|
|
610
|
+
for (const timer of state.fileWatcherTimers.values()) {
|
|
611
|
+
clearTimeout(timer);
|
|
612
|
+
}
|
|
613
|
+
state.fileWatcherTimers.clear();
|
|
614
|
+
};
|
|
615
|
+
export { handleToolsJsonChange, startConfigWatching, startFileWatching, stopFileWatching };
|
|
616
|
+
//# sourceMappingURL=file-watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-watcher.js","sourceRoot":"","sources":["../src/file-watcher.ts"],"names":[],"mappings":"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"}
|