@0x1f320.sh/why-did-you-render-mcp 1.0.0-dev.12 → 1.0.0-dev.14
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 +101 -20
- 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 });
|
|
@@ -276,6 +277,33 @@ var RenderStore = class {
|
|
|
276
277
|
}
|
|
277
278
|
return summary;
|
|
278
279
|
}
|
|
280
|
+
getSummaryByCommit(projectId) {
|
|
281
|
+
const renders = this.getAllRenders(projectId);
|
|
282
|
+
const summary = {};
|
|
283
|
+
for (const r of renders) {
|
|
284
|
+
if (r.commitId == null) continue;
|
|
285
|
+
summary[r.project] ??= {};
|
|
286
|
+
summary[r.project][r.commitId] ??= {};
|
|
287
|
+
const commit = summary[r.project][r.commitId];
|
|
288
|
+
commit[r.displayName] = (commit[r.displayName] ?? 0) + 1;
|
|
289
|
+
}
|
|
290
|
+
return summary;
|
|
291
|
+
}
|
|
292
|
+
setTrackedComponents(components, projectId) {
|
|
293
|
+
this.trackedComponents.set(projectId, components);
|
|
294
|
+
}
|
|
295
|
+
getTrackedComponents(projectId) {
|
|
296
|
+
const result = {};
|
|
297
|
+
const projects = projectId ? [projectId] : this.getProjects();
|
|
298
|
+
for (const proj of projects) {
|
|
299
|
+
const observed = [...new Set(this.getAllRenders(proj).map((r) => r.displayName))];
|
|
300
|
+
result[proj] = {
|
|
301
|
+
registered: this.trackedComponents.get(proj) ?? [],
|
|
302
|
+
observed
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
279
307
|
bufferKey(projectId, commitId) {
|
|
280
308
|
return `${projectId}\0${commitId ?? NOCOMMIT}`;
|
|
281
309
|
}
|
|
@@ -343,7 +371,7 @@ function textResult(text) {
|
|
|
343
371
|
}
|
|
344
372
|
//#endregion
|
|
345
373
|
//#region src/server/tools/clear-renders.ts
|
|
346
|
-
function register$
|
|
374
|
+
function register$6(server) {
|
|
347
375
|
server.registerTool("clear_renders", {
|
|
348
376
|
title: "Clear Renders",
|
|
349
377
|
description: "Clears collected render data. If multiple projects are active and no project is specified, the tool will ask you to disambiguate.",
|
|
@@ -357,7 +385,7 @@ function register$5(server) {
|
|
|
357
385
|
}
|
|
358
386
|
//#endregion
|
|
359
387
|
//#region src/server/tools/get-commits.ts
|
|
360
|
-
function register$
|
|
388
|
+
function register$5(server) {
|
|
361
389
|
server.registerTool("get_commits", {
|
|
362
390
|
title: "Get Commits",
|
|
363
391
|
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.",
|
|
@@ -372,7 +400,7 @@ function register$4(server) {
|
|
|
372
400
|
}
|
|
373
401
|
//#endregion
|
|
374
402
|
//#region src/server/tools/get-projects.ts
|
|
375
|
-
function register$
|
|
403
|
+
function register$4(server) {
|
|
376
404
|
server.registerTool("get_projects", {
|
|
377
405
|
title: "Get Projects",
|
|
378
406
|
description: "Returns a list of project identifiers (browser origin URLs) that have recorded render data.",
|
|
@@ -385,27 +413,50 @@ function register$3(server) {
|
|
|
385
413
|
}
|
|
386
414
|
//#endregion
|
|
387
415
|
//#region src/server/tools/get-render-summary.ts
|
|
388
|
-
function register$
|
|
416
|
+
function register$3(server) {
|
|
389
417
|
server.registerTool("get_render_summary", {
|
|
390
418
|
title: "Get Render Summary",
|
|
391
|
-
description: "Returns a summary of re-renders grouped by component name with counts. If multiple projects are active and no project is specified, the tool will ask you to disambiguate.",
|
|
392
|
-
inputSchema: {
|
|
393
|
-
|
|
419
|
+
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.",
|
|
420
|
+
inputSchema: {
|
|
421
|
+
project: z.string().optional().describe("Project identifier (the browser's origin URL, e.g. http://localhost:3000). Omit to auto-detect."),
|
|
422
|
+
groupBy: z.enum(["commit"]).optional().describe("Group results by commit. When set to 'commit', returns per-commit render summaries instead of a single aggregate.")
|
|
423
|
+
}
|
|
424
|
+
}, async ({ project, groupBy }) => {
|
|
394
425
|
const resolved = resolveProject(project);
|
|
395
426
|
if (resolved.error) return textResult(resolved.error);
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
const lines = [];
|
|
399
|
-
for (const [projectId, components] of Object.entries(summary)) {
|
|
400
|
-
lines.push(`[${projectId}]`);
|
|
401
|
-
for (const [name, count] of Object.entries(components)) lines.push(` ${name}: ${count} re-render(s)`);
|
|
402
|
-
}
|
|
403
|
-
return textResult(`Re-render summary:\n\n${lines.join("\n")}`);
|
|
427
|
+
if (groupBy === "commit") return commitSummary(resolved.projectId);
|
|
428
|
+
return aggregateSummary(resolved.projectId);
|
|
404
429
|
});
|
|
405
430
|
}
|
|
431
|
+
function aggregateSummary(projectId) {
|
|
432
|
+
const summary = store.getSummary(projectId);
|
|
433
|
+
if (Object.keys(summary).length === 0) return textResult("No renders recorded yet.");
|
|
434
|
+
const lines = [];
|
|
435
|
+
for (const [proj, components] of Object.entries(summary)) {
|
|
436
|
+
lines.push(`[${proj}]`);
|
|
437
|
+
for (const [name, count] of Object.entries(components)) lines.push(` ${name}: ${count} re-render(s)`);
|
|
438
|
+
}
|
|
439
|
+
return textResult(`Re-render summary:\n\n${lines.join("\n")}`);
|
|
440
|
+
}
|
|
441
|
+
function commitSummary(projectId) {
|
|
442
|
+
const summary = store.getSummaryByCommit(projectId);
|
|
443
|
+
if (Object.keys(summary).length === 0) return textResult("No renders with commit IDs recorded yet.");
|
|
444
|
+
const lines = [];
|
|
445
|
+
for (const [proj, commits] of Object.entries(summary)) {
|
|
446
|
+
lines.push(`[${proj}]`);
|
|
447
|
+
const sortedCommitIds = Object.keys(commits).map(Number).sort((a, b) => a - b);
|
|
448
|
+
for (const commitId of sortedCommitIds) {
|
|
449
|
+
const components = commits[commitId];
|
|
450
|
+
const total = Object.values(components).reduce((s, c) => s + c, 0);
|
|
451
|
+
lines.push(` Commit #${commitId} (${total} re-render(s)):`);
|
|
452
|
+
for (const [name, count] of Object.entries(components)) lines.push(` ${name}: ${count}`);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return textResult(`Re-render summary (by commit):\n\n${lines.join("\n")}`);
|
|
456
|
+
}
|
|
406
457
|
//#endregion
|
|
407
458
|
//#region src/server/tools/get-renders-by-commit.ts
|
|
408
|
-
function register$
|
|
459
|
+
function register$2(server) {
|
|
409
460
|
server.registerTool("get_renders_by_commit", {
|
|
410
461
|
title: "Get Renders by Commit",
|
|
411
462
|
description: "Returns all re-renders for a specific React commit ID. Use get_commits first to discover available commit IDs.",
|
|
@@ -425,7 +476,7 @@ function register$1(server) {
|
|
|
425
476
|
}
|
|
426
477
|
//#endregion
|
|
427
478
|
//#region src/server/tools/get-renders.ts
|
|
428
|
-
function register(server) {
|
|
479
|
+
function register$1(server) {
|
|
429
480
|
server.registerTool("get_renders", {
|
|
430
481
|
title: "Get Renders",
|
|
431
482
|
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.",
|
|
@@ -442,14 +493,43 @@ function register(server) {
|
|
|
442
493
|
});
|
|
443
494
|
}
|
|
444
495
|
//#endregion
|
|
496
|
+
//#region src/server/tools/get-tracked-components.ts
|
|
497
|
+
function register(server) {
|
|
498
|
+
server.registerTool("get_tracked_components", {
|
|
499
|
+
title: "Get Tracked Components",
|
|
500
|
+
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.",
|
|
501
|
+
inputSchema: { project: z.string().optional().describe("Project identifier (the browser's origin URL, e.g. http://localhost:3000). Omit to auto-detect.") }
|
|
502
|
+
}, async ({ project }) => {
|
|
503
|
+
const resolved = resolveProject(project);
|
|
504
|
+
if (resolved.error) return textResult(resolved.error);
|
|
505
|
+
const tracked = store.getTrackedComponents(resolved.projectId);
|
|
506
|
+
if (Object.keys(tracked).length === 0) return textResult("No tracked components found. Make sure the browser is connected and triggering re-renders.");
|
|
507
|
+
const lines = [];
|
|
508
|
+
for (const [proj, { registered, observed }] of Object.entries(tracked)) {
|
|
509
|
+
lines.push(`[${proj}]`);
|
|
510
|
+
if (registered.length > 0) {
|
|
511
|
+
lines.push(" Registered:");
|
|
512
|
+
for (const name of registered) lines.push(` - ${name}`);
|
|
513
|
+
}
|
|
514
|
+
if (observed.length > 0) {
|
|
515
|
+
lines.push(" Observed in renders:");
|
|
516
|
+
for (const name of observed) lines.push(` - ${name}`);
|
|
517
|
+
}
|
|
518
|
+
if (registered.length === 0 && observed.length === 0) lines.push(" No components tracked yet.");
|
|
519
|
+
}
|
|
520
|
+
return textResult(lines.join("\n"));
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
//#endregion
|
|
445
524
|
//#region src/server/tools/index.ts
|
|
446
525
|
function registerTools(server) {
|
|
447
|
-
register(server);
|
|
448
|
-
register$2(server);
|
|
449
|
-
register$4(server);
|
|
450
526
|
register$1(server);
|
|
451
527
|
register$3(server);
|
|
452
528
|
register$5(server);
|
|
529
|
+
register$2(server);
|
|
530
|
+
register$4(server);
|
|
531
|
+
register(server);
|
|
532
|
+
register$6(server);
|
|
453
533
|
}
|
|
454
534
|
//#endregion
|
|
455
535
|
//#region src/server/liveness.ts
|
|
@@ -528,6 +608,7 @@ function createWsServer(port) {
|
|
|
528
608
|
heartbeat.setProjectId(ws, projectId);
|
|
529
609
|
if (msg.type === "render") store.addRender(msg.payload, projectId, msg.commitId);
|
|
530
610
|
else if (msg.type === "render-batch") for (const report of msg.payload) store.addRender(report, projectId, msg.commitId);
|
|
611
|
+
else if (msg.type === "register") store.setTrackedComponents(msg.components, projectId);
|
|
531
612
|
} catch {
|
|
532
613
|
console.error("[wdyr-mcp] invalid message received");
|
|
533
614
|
}
|
package/package.json
CHANGED