@0x1f320.sh/why-did-you-render-mcp 1.0.0-dev.13 → 1.0.0-dev.15
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/client/index.cjs +26 -17
- package/dist/client/index.d.cts +1 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +26 -17
- package/dist/server/index.js +91 -14
- package/package.json +1 -1
package/dist/client/index.cjs
CHANGED
|
@@ -206,25 +206,34 @@ function buildOptions(opts) {
|
|
|
206
206
|
});
|
|
207
207
|
pendingBatch = null;
|
|
208
208
|
}
|
|
209
|
-
return {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
209
|
+
return {
|
|
210
|
+
registerComponents(components) {
|
|
211
|
+
send({
|
|
212
|
+
type: "register",
|
|
213
|
+
projectId,
|
|
214
|
+
components
|
|
215
|
+
});
|
|
216
|
+
},
|
|
217
|
+
notifier(info) {
|
|
218
|
+
const report = {
|
|
219
|
+
displayName: info.displayName,
|
|
220
|
+
reason: sanitizeReason(info.reason),
|
|
221
|
+
hookName: info.hookName
|
|
221
222
|
};
|
|
223
|
+
if (pendingBatch && pendingBatch.commitId === commitId) pendingBatch.reports.push(report);
|
|
224
|
+
else {
|
|
225
|
+
if (pendingBatch) flushBatch();
|
|
226
|
+
pendingBatch = {
|
|
227
|
+
commitId,
|
|
228
|
+
reports: [report]
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
if (!flushScheduled) {
|
|
232
|
+
flushScheduled = true;
|
|
233
|
+
queueMicrotask(flushBatch);
|
|
234
|
+
}
|
|
222
235
|
}
|
|
223
|
-
|
|
224
|
-
flushScheduled = true;
|
|
225
|
-
queueMicrotask(flushBatch);
|
|
226
|
-
}
|
|
227
|
-
} };
|
|
236
|
+
};
|
|
228
237
|
}
|
|
229
238
|
//#endregion
|
|
230
239
|
exports.buildOptions = buildOptions;
|
package/dist/client/index.d.cts
CHANGED
package/dist/client/index.d.ts
CHANGED
package/dist/client/index.js
CHANGED
|
@@ -205,25 +205,34 @@ function buildOptions(opts) {
|
|
|
205
205
|
});
|
|
206
206
|
pendingBatch = null;
|
|
207
207
|
}
|
|
208
|
-
return {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
208
|
+
return {
|
|
209
|
+
registerComponents(components) {
|
|
210
|
+
send({
|
|
211
|
+
type: "register",
|
|
212
|
+
projectId,
|
|
213
|
+
components
|
|
214
|
+
});
|
|
215
|
+
},
|
|
216
|
+
notifier(info) {
|
|
217
|
+
const report = {
|
|
218
|
+
displayName: info.displayName,
|
|
219
|
+
reason: sanitizeReason(info.reason),
|
|
220
|
+
hookName: info.hookName
|
|
220
221
|
};
|
|
222
|
+
if (pendingBatch && pendingBatch.commitId === commitId) pendingBatch.reports.push(report);
|
|
223
|
+
else {
|
|
224
|
+
if (pendingBatch) flushBatch();
|
|
225
|
+
pendingBatch = {
|
|
226
|
+
commitId,
|
|
227
|
+
reports: [report]
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
if (!flushScheduled) {
|
|
231
|
+
flushScheduled = true;
|
|
232
|
+
queueMicrotask(flushBatch);
|
|
233
|
+
}
|
|
221
234
|
}
|
|
222
|
-
|
|
223
|
-
flushScheduled = true;
|
|
224
|
-
queueMicrotask(flushBatch);
|
|
225
|
-
}
|
|
226
|
-
} };
|
|
235
|
+
};
|
|
227
236
|
}
|
|
228
237
|
//#endregion
|
|
229
238
|
export { buildOptions };
|
package/dist/server/index.js
CHANGED
|
@@ -130,6 +130,7 @@ var RenderStore = class {
|
|
|
130
130
|
timers = /* @__PURE__ */ new Map();
|
|
131
131
|
dicts = /* @__PURE__ */ new Map();
|
|
132
132
|
bufferMeta = /* @__PURE__ */ new Map();
|
|
133
|
+
trackedComponents = /* @__PURE__ */ new Map();
|
|
133
134
|
constructor(dir) {
|
|
134
135
|
this.dir = dir ?? join(homedir(), ".wdyr-mcp", "renders");
|
|
135
136
|
mkdirSync(this.dir, { recursive: true });
|
|
@@ -272,7 +273,19 @@ var RenderStore = class {
|
|
|
272
273
|
for (const r of renders) {
|
|
273
274
|
summary[r.project] ??= {};
|
|
274
275
|
const project = summary[r.project];
|
|
275
|
-
project[r.displayName]
|
|
276
|
+
project[r.displayName] ??= {
|
|
277
|
+
count: 0,
|
|
278
|
+
reasons: {
|
|
279
|
+
props: 0,
|
|
280
|
+
state: 0,
|
|
281
|
+
hooks: 0
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
const entry = project[r.displayName];
|
|
285
|
+
entry.count++;
|
|
286
|
+
if (Array.isArray(r.reason.propsDifferences)) entry.reasons.props++;
|
|
287
|
+
if (Array.isArray(r.reason.stateDifferences)) entry.reasons.state++;
|
|
288
|
+
if (Array.isArray(r.reason.hookDifferences)) entry.reasons.hooks++;
|
|
276
289
|
}
|
|
277
290
|
return summary;
|
|
278
291
|
}
|
|
@@ -284,10 +297,37 @@ var RenderStore = class {
|
|
|
284
297
|
summary[r.project] ??= {};
|
|
285
298
|
summary[r.project][r.commitId] ??= {};
|
|
286
299
|
const commit = summary[r.project][r.commitId];
|
|
287
|
-
commit[r.displayName]
|
|
300
|
+
commit[r.displayName] ??= {
|
|
301
|
+
count: 0,
|
|
302
|
+
reasons: {
|
|
303
|
+
props: 0,
|
|
304
|
+
state: 0,
|
|
305
|
+
hooks: 0
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
const entry = commit[r.displayName];
|
|
309
|
+
entry.count++;
|
|
310
|
+
if (Array.isArray(r.reason.propsDifferences)) entry.reasons.props++;
|
|
311
|
+
if (Array.isArray(r.reason.stateDifferences)) entry.reasons.state++;
|
|
312
|
+
if (Array.isArray(r.reason.hookDifferences)) entry.reasons.hooks++;
|
|
288
313
|
}
|
|
289
314
|
return summary;
|
|
290
315
|
}
|
|
316
|
+
setTrackedComponents(components, projectId) {
|
|
317
|
+
this.trackedComponents.set(projectId, components);
|
|
318
|
+
}
|
|
319
|
+
getTrackedComponents(projectId) {
|
|
320
|
+
const result = {};
|
|
321
|
+
const projects = projectId ? [projectId] : this.getProjects();
|
|
322
|
+
for (const proj of projects) {
|
|
323
|
+
const observed = [...new Set(this.getAllRenders(proj).map((r) => r.displayName))];
|
|
324
|
+
result[proj] = {
|
|
325
|
+
registered: this.trackedComponents.get(proj) ?? [],
|
|
326
|
+
observed
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
291
331
|
bufferKey(projectId, commitId) {
|
|
292
332
|
return `${projectId}\0${commitId ?? NOCOMMIT}`;
|
|
293
333
|
}
|
|
@@ -355,7 +395,7 @@ function textResult(text) {
|
|
|
355
395
|
}
|
|
356
396
|
//#endregion
|
|
357
397
|
//#region src/server/tools/clear-renders.ts
|
|
358
|
-
function register$
|
|
398
|
+
function register$6(server) {
|
|
359
399
|
server.registerTool("clear_renders", {
|
|
360
400
|
title: "Clear Renders",
|
|
361
401
|
description: "Clears collected render data. If multiple projects are active and no project is specified, the tool will ask you to disambiguate.",
|
|
@@ -369,7 +409,7 @@ function register$5(server) {
|
|
|
369
409
|
}
|
|
370
410
|
//#endregion
|
|
371
411
|
//#region src/server/tools/get-commits.ts
|
|
372
|
-
function register$
|
|
412
|
+
function register$5(server) {
|
|
373
413
|
server.registerTool("get_commits", {
|
|
374
414
|
title: "Get Commits",
|
|
375
415
|
description: "Returns a list of React commit IDs that have recorded render data for a project. Use these IDs with get_renders_by_commit to inspect individual commits.",
|
|
@@ -384,7 +424,7 @@ function register$4(server) {
|
|
|
384
424
|
}
|
|
385
425
|
//#endregion
|
|
386
426
|
//#region src/server/tools/get-projects.ts
|
|
387
|
-
function register$
|
|
427
|
+
function register$4(server) {
|
|
388
428
|
server.registerTool("get_projects", {
|
|
389
429
|
title: "Get Projects",
|
|
390
430
|
description: "Returns a list of project identifiers (browser origin URLs) that have recorded render data.",
|
|
@@ -397,7 +437,7 @@ function register$3(server) {
|
|
|
397
437
|
}
|
|
398
438
|
//#endregion
|
|
399
439
|
//#region src/server/tools/get-render-summary.ts
|
|
400
|
-
function register$
|
|
440
|
+
function register$3(server) {
|
|
401
441
|
server.registerTool("get_render_summary", {
|
|
402
442
|
title: "Get Render Summary",
|
|
403
443
|
description: "Returns a summary of re-renders grouped by component name with counts. Use groupBy: 'commit' to get per-commit breakdowns instead of a single aggregate. If multiple projects are active and no project is specified, the tool will ask you to disambiguate.",
|
|
@@ -412,13 +452,20 @@ function register$2(server) {
|
|
|
412
452
|
return aggregateSummary(resolved.projectId);
|
|
413
453
|
});
|
|
414
454
|
}
|
|
455
|
+
function formatReasons(reasons) {
|
|
456
|
+
const parts = [];
|
|
457
|
+
if (reasons.props > 0) parts.push(`props: ${reasons.props}`);
|
|
458
|
+
if (reasons.state > 0) parts.push(`state: ${reasons.state}`);
|
|
459
|
+
if (reasons.hooks > 0) parts.push(`hooks: ${reasons.hooks}`);
|
|
460
|
+
return parts.length > 0 ? ` — ${parts.join(", ")}` : "";
|
|
461
|
+
}
|
|
415
462
|
function aggregateSummary(projectId) {
|
|
416
463
|
const summary = store.getSummary(projectId);
|
|
417
464
|
if (Object.keys(summary).length === 0) return textResult("No renders recorded yet.");
|
|
418
465
|
const lines = [];
|
|
419
466
|
for (const [proj, components] of Object.entries(summary)) {
|
|
420
467
|
lines.push(`[${proj}]`);
|
|
421
|
-
for (const [name, count] of Object.entries(components)) lines.push(` ${name}: ${count} re-render(s)`);
|
|
468
|
+
for (const [name, { count, reasons }] of Object.entries(components)) lines.push(` ${name}: ${count} re-render(s)${formatReasons(reasons)}`);
|
|
422
469
|
}
|
|
423
470
|
return textResult(`Re-render summary:\n\n${lines.join("\n")}`);
|
|
424
471
|
}
|
|
@@ -431,16 +478,16 @@ function commitSummary(projectId) {
|
|
|
431
478
|
const sortedCommitIds = Object.keys(commits).map(Number).sort((a, b) => a - b);
|
|
432
479
|
for (const commitId of sortedCommitIds) {
|
|
433
480
|
const components = commits[commitId];
|
|
434
|
-
const total = Object.values(components).reduce((s, c) => s + c, 0);
|
|
481
|
+
const total = Object.values(components).reduce((s, c) => s + c.count, 0);
|
|
435
482
|
lines.push(` Commit #${commitId} (${total} re-render(s)):`);
|
|
436
|
-
for (const [name, count] of Object.entries(components)) lines.push(` ${name}: ${count}`);
|
|
483
|
+
for (const [name, { count, reasons }] of Object.entries(components)) lines.push(` ${name}: ${count}${formatReasons(reasons)}`);
|
|
437
484
|
}
|
|
438
485
|
}
|
|
439
486
|
return textResult(`Re-render summary (by commit):\n\n${lines.join("\n")}`);
|
|
440
487
|
}
|
|
441
488
|
//#endregion
|
|
442
489
|
//#region src/server/tools/get-renders-by-commit.ts
|
|
443
|
-
function register$
|
|
490
|
+
function register$2(server) {
|
|
444
491
|
server.registerTool("get_renders_by_commit", {
|
|
445
492
|
title: "Get Renders by Commit",
|
|
446
493
|
description: "Returns all re-renders for a specific React commit ID. Use get_commits first to discover available commit IDs.",
|
|
@@ -460,7 +507,7 @@ function register$1(server) {
|
|
|
460
507
|
}
|
|
461
508
|
//#endregion
|
|
462
509
|
//#region src/server/tools/get-renders.ts
|
|
463
|
-
function register(server) {
|
|
510
|
+
function register$1(server) {
|
|
464
511
|
server.registerTool("get_renders", {
|
|
465
512
|
title: "Get Renders",
|
|
466
513
|
description: "Returns all re-renders collected from the browser. If multiple projects are active and no project is specified, the tool will ask you to disambiguate by asking the user for their dev server URL.",
|
|
@@ -477,14 +524,43 @@ function register(server) {
|
|
|
477
524
|
});
|
|
478
525
|
}
|
|
479
526
|
//#endregion
|
|
527
|
+
//#region src/server/tools/get-tracked-components.ts
|
|
528
|
+
function register(server) {
|
|
529
|
+
server.registerTool("get_tracked_components", {
|
|
530
|
+
title: "Get Tracked Components",
|
|
531
|
+
description: "Returns the list of components being tracked by why-did-you-render. Shows both explicitly registered components (sent by the client) and components observed in render data. If multiple projects are active and no project is specified, the tool will ask you to disambiguate.",
|
|
532
|
+
inputSchema: { project: z.string().optional().describe("Project identifier (the browser's origin URL, e.g. http://localhost:3000). Omit to auto-detect.") }
|
|
533
|
+
}, async ({ project }) => {
|
|
534
|
+
const resolved = resolveProject(project);
|
|
535
|
+
if (resolved.error) return textResult(resolved.error);
|
|
536
|
+
const tracked = store.getTrackedComponents(resolved.projectId);
|
|
537
|
+
if (Object.keys(tracked).length === 0) return textResult("No tracked components found. Make sure the browser is connected and triggering re-renders.");
|
|
538
|
+
const lines = [];
|
|
539
|
+
for (const [proj, { registered, observed }] of Object.entries(tracked)) {
|
|
540
|
+
lines.push(`[${proj}]`);
|
|
541
|
+
if (registered.length > 0) {
|
|
542
|
+
lines.push(" Registered:");
|
|
543
|
+
for (const name of registered) lines.push(` - ${name}`);
|
|
544
|
+
}
|
|
545
|
+
if (observed.length > 0) {
|
|
546
|
+
lines.push(" Observed in renders:");
|
|
547
|
+
for (const name of observed) lines.push(` - ${name}`);
|
|
548
|
+
}
|
|
549
|
+
if (registered.length === 0 && observed.length === 0) lines.push(" No components tracked yet.");
|
|
550
|
+
}
|
|
551
|
+
return textResult(lines.join("\n"));
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
//#endregion
|
|
480
555
|
//#region src/server/tools/index.ts
|
|
481
556
|
function registerTools(server) {
|
|
482
|
-
register(server);
|
|
483
|
-
register$2(server);
|
|
484
|
-
register$4(server);
|
|
485
557
|
register$1(server);
|
|
486
558
|
register$3(server);
|
|
487
559
|
register$5(server);
|
|
560
|
+
register$2(server);
|
|
561
|
+
register$4(server);
|
|
562
|
+
register(server);
|
|
563
|
+
register$6(server);
|
|
488
564
|
}
|
|
489
565
|
//#endregion
|
|
490
566
|
//#region src/server/liveness.ts
|
|
@@ -563,6 +639,7 @@ function createWsServer(port) {
|
|
|
563
639
|
heartbeat.setProjectId(ws, projectId);
|
|
564
640
|
if (msg.type === "render") store.addRender(msg.payload, projectId, msg.commitId);
|
|
565
641
|
else if (msg.type === "render-batch") for (const report of msg.payload) store.addRender(report, projectId, msg.commitId);
|
|
642
|
+
else if (msg.type === "register") store.setTrackedComponents(msg.components, projectId);
|
|
566
643
|
} catch {
|
|
567
644
|
console.error("[wdyr-mcp] invalid message received");
|
|
568
645
|
}
|
package/package.json
CHANGED