what-devtools-mcp 0.13.4 → 0.13.6
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/package.json +3 -3
- package/src/bridge.js +2 -0
- package/src/client-commands.js +5 -3
- package/src/client.js +9 -2
- package/src/tools-extended.js +5 -0
- package/src/tools.js +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "what-devtools-mcp",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.6",
|
|
4
4
|
"description": "MCP server bridging AI agents to live What Framework app state via WebSocket",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
29
|
-
"ws": "^8.
|
|
30
|
-
"zod": "^
|
|
29
|
+
"ws": "^8.21.3",
|
|
30
|
+
"zod": "^4.4.3"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"what-devtools": ">=0.7.0"
|
package/src/bridge.js
CHANGED
|
@@ -23,6 +23,7 @@ export function createBridge({ port = 9229, host = '127.0.0.1', onError } = {})
|
|
|
23
23
|
let latestSnapshot = null;
|
|
24
24
|
const eventLog = [];
|
|
25
25
|
const errorLog = [];
|
|
26
|
+
/** @type {import('ws').WebSocket | null} */
|
|
26
27
|
let browserSocket = null;
|
|
27
28
|
let correlationCounter = 0;
|
|
28
29
|
const pendingCommands = new Map();
|
|
@@ -33,6 +34,7 @@ export function createBridge({ port = 9229, host = '127.0.0.1', onError } = {})
|
|
|
33
34
|
const SNAPSHOT_CACHE_MS = 100;
|
|
34
35
|
|
|
35
36
|
// Baseline snapshot for diff tool
|
|
37
|
+
/** @type {any} */
|
|
36
38
|
let baselineSnapshot = null;
|
|
37
39
|
|
|
38
40
|
// Use a fixed token from env if provided, otherwise generate a random one.
|
package/src/client-commands.js
CHANGED
|
@@ -49,6 +49,7 @@ function getComponentElement(entry) {
|
|
|
49
49
|
|
|
50
50
|
const MAX_WRITE_LOG = 200;
|
|
51
51
|
let _signalWriteLog = []; // { signalId, signalName, previousValue, newValue, timestamp, writerEffect }
|
|
52
|
+
/** @type {{ id: any, name: any, timestamp: number } | null} */
|
|
52
53
|
let _lastRunningEffect = null; // { id, name, timestamp } — most recent effect:run event
|
|
53
54
|
let _trackingInitialized = false;
|
|
54
55
|
let _unsubTracker = null;
|
|
@@ -111,11 +112,12 @@ function findLastWrite(signalId) {
|
|
|
111
112
|
* Handle extended commands sent from the MCP server via the bridge.
|
|
112
113
|
*
|
|
113
114
|
* @param {string} command - The command name
|
|
114
|
-
* @param {
|
|
115
|
-
* @param {
|
|
116
|
-
* @returns {Promise<
|
|
115
|
+
* @param {Record<string, any>} [args] - Command arguments
|
|
116
|
+
* @param {any} [devtools] - window.__WHAT_DEVTOOLS__ reference (live hook bag)
|
|
117
|
+
* @returns {Promise<Record<string, any>|null>} Result object, or null if command not handled
|
|
117
118
|
*/
|
|
118
119
|
export async function handleExtendedCommand(command, args, devtools) {
|
|
120
|
+
args = args || /** @type {Record<string, any>} */ ({});
|
|
119
121
|
switch (command) {
|
|
120
122
|
|
|
121
123
|
// -------------------------------------------------------------------------
|
package/src/client.js
CHANGED
|
@@ -31,9 +31,11 @@ export function connectDevToolsMCP({ port = 9229, token = '', discoveryUrl = ''
|
|
|
31
31
|
}
|
|
32
32
|
} catch {}
|
|
33
33
|
|
|
34
|
+
/** @type {WebSocket | null} */
|
|
34
35
|
let ws = null;
|
|
35
36
|
let connected = false;
|
|
36
37
|
let stopped = false;
|
|
38
|
+
/** @type {ReturnType<typeof setTimeout> | null} */
|
|
37
39
|
let probeTimer = null;
|
|
38
40
|
// Probe back-off: first retry after 10s, then ×3 each time, capped at 5min.
|
|
39
41
|
// With no bridge running this yields probes at ~0s / 10s / 40s / 130s / 430s…
|
|
@@ -46,7 +48,9 @@ export function connectDevToolsMCP({ port = 9229, token = '', discoveryUrl = ''
|
|
|
46
48
|
let eventCount = 0;
|
|
47
49
|
let hasLoggedMissingBridge = false;
|
|
48
50
|
let hasShownBanner = false;
|
|
51
|
+
/** @type {(() => void) | null} */
|
|
49
52
|
let unsubscribeFn = null;
|
|
53
|
+
/** @type {(() => void) | null} */
|
|
50
54
|
let flushEventBatch = null; // Hoisted — set during subscription, called by set-signal
|
|
51
55
|
let discoveredToken = token;
|
|
52
56
|
let discoveredPort = port;
|
|
@@ -178,10 +182,11 @@ export function connectDevToolsMCP({ port = 9229, token = '', discoveryUrl = ''
|
|
|
178
182
|
}
|
|
179
183
|
if (devtools) {
|
|
180
184
|
let eventBatch = [];
|
|
185
|
+
/** @type {ReturnType<typeof setTimeout> | null} */
|
|
181
186
|
let batchTimer = null;
|
|
182
187
|
|
|
183
188
|
// Hoisted so set-signal can call it to flush after programmatic writes
|
|
184
|
-
|
|
189
|
+
const flush = function() {
|
|
185
190
|
if (eventBatch.length === 0) return;
|
|
186
191
|
if (eventBatch.length === 1) {
|
|
187
192
|
const item = eventBatch[0];
|
|
@@ -192,12 +197,13 @@ export function connectDevToolsMCP({ port = 9229, token = '', discoveryUrl = ''
|
|
|
192
197
|
eventBatch = [];
|
|
193
198
|
if (batchTimer) { clearTimeout(batchTimer); batchTimer = null; }
|
|
194
199
|
};
|
|
200
|
+
flushEventBatch = flush;
|
|
195
201
|
|
|
196
202
|
unsubscribeFn = devtools.subscribe((event, data) => {
|
|
197
203
|
eventCount++;
|
|
198
204
|
eventBatch.push({ event, data: devtools.safeSerialize(data) });
|
|
199
205
|
if (!batchTimer) {
|
|
200
|
-
batchTimer = setTimeout(
|
|
206
|
+
batchTimer = setTimeout(flush, 16);
|
|
201
207
|
}
|
|
202
208
|
});
|
|
203
209
|
log('MCP', BADGE, 'Subscribed to reactive events — streaming to bridge (batched)');
|
|
@@ -328,6 +334,7 @@ export function connectDevToolsMCP({ port = 9229, token = '', discoveryUrl = ''
|
|
|
328
334
|
}
|
|
329
335
|
default: {
|
|
330
336
|
// Try extended command handlers
|
|
337
|
+
/** @type {Record<string, any> | null} */
|
|
331
338
|
let extResult = null;
|
|
332
339
|
try {
|
|
333
340
|
const { handleExtendedCommand, initEventTracking } = await import('./client-commands.js');
|
package/src/tools-extended.js
CHANGED
|
@@ -189,6 +189,7 @@ export function registerExtendedTools(server, bridge) {
|
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
// Optional filter — keep subtrees that contain a matching node
|
|
192
|
+
/** @type {RegExp | null} */
|
|
192
193
|
let filterRe = null;
|
|
193
194
|
if (filter) {
|
|
194
195
|
try {
|
|
@@ -308,6 +309,9 @@ export function registerExtendedTools(server, bridge) {
|
|
|
308
309
|
|
|
309
310
|
// If a specific signal or effect is requested, filter the graph
|
|
310
311
|
let filteredEdges = allEdges;
|
|
312
|
+
// `any` rather than `Set | null`: the set is read inside filter
|
|
313
|
+
// callbacks, and TS 7 does not narrow a closed-over nullable.
|
|
314
|
+
/** @type {any} */
|
|
311
315
|
let nodeIds = null; // Set of "type:id" strings we want to include
|
|
312
316
|
|
|
313
317
|
if (signalId != null) {
|
|
@@ -933,6 +937,7 @@ export function registerExtendedTools(server, bridge) {
|
|
|
933
937
|
}));
|
|
934
938
|
|
|
935
939
|
// DOM output (if requested and bridge connected)
|
|
940
|
+
/** @type {{ html: any, structure: any } | null} */
|
|
936
941
|
let dom = null;
|
|
937
942
|
if (includeDOM) {
|
|
938
943
|
try {
|
package/src/tools.js
CHANGED