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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "what-devtools-mcp",
3
- "version": "0.13.4",
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.18.0",
30
- "zod": "^3.25.0"
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.
@@ -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 {object} args - Command arguments
115
- * @param {object|null} devtools - window.__WHAT_DEVTOOLS__ reference
116
- * @returns {Promise<object|null>} Result object, or null if command not handled
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
- flushEventBatch = function() {
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(flushEventBatch, 16);
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');
@@ -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
@@ -63,6 +63,7 @@ export function registerTools(server, bridge) {
63
63
  const componentCount = snapshot?.components?.length || 0;
64
64
 
65
65
  // Try to get app metadata from the browser
66
+ /** @type {Record<string, any> | null} */
66
67
  let appInfo = null;
67
68
  if (connected) {
68
69
  try {