@memlab/mcp-server 2.0.3 → 2.1.1

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.
Files changed (133) hide show
  1. package/README.md +28 -13
  2. package/dist/heap-state.d.ts +12 -1
  3. package/dist/heap-state.d.ts.map +1 -1
  4. package/dist/heap-state.js +10 -4
  5. package/dist/heap-state.js.map +1 -1
  6. package/dist/index.js +27 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/tools/aggregate-nodes.d.ts.map +1 -1
  9. package/dist/tools/aggregate-nodes.js +2 -2
  10. package/dist/tools/aggregate-nodes.js.map +1 -1
  11. package/dist/tools/auto-investigate.d.ts +12 -0
  12. package/dist/tools/auto-investigate.d.ts.map +1 -0
  13. package/dist/tools/auto-investigate.js +683 -0
  14. package/dist/tools/auto-investigate.js.map +1 -0
  15. package/dist/tools/cache-analysis.d.ts +12 -0
  16. package/dist/tools/cache-analysis.d.ts.map +1 -0
  17. package/dist/tools/cache-analysis.js +341 -0
  18. package/dist/tools/cache-analysis.js.map +1 -0
  19. package/dist/tools/check-health.d.ts +12 -0
  20. package/dist/tools/check-health.d.ts.map +1 -0
  21. package/dist/tools/check-health.js +289 -0
  22. package/dist/tools/check-health.js.map +1 -0
  23. package/dist/tools/class-histogram.d.ts.map +1 -1
  24. package/dist/tools/class-histogram.js +70 -14
  25. package/dist/tools/class-histogram.js.map +1 -1
  26. package/dist/tools/closure-inspection.d.ts.map +1 -1
  27. package/dist/tools/closure-inspection.js +5 -5
  28. package/dist/tools/closure-inspection.js.map +1 -1
  29. package/dist/tools/detached-dom.d.ts.map +1 -1
  30. package/dist/tools/detached-dom.js +151 -5
  31. package/dist/tools/detached-dom.js.map +1 -1
  32. package/dist/tools/diff-snapshots.d.ts +12 -0
  33. package/dist/tools/diff-snapshots.d.ts.map +1 -0
  34. package/dist/tools/diff-snapshots.js +224 -0
  35. package/dist/tools/diff-snapshots.js.map +1 -0
  36. package/dist/tools/dominator-subtree.d.ts.map +1 -1
  37. package/dist/tools/dominator-subtree.js +29 -4
  38. package/dist/tools/dominator-subtree.js.map +1 -1
  39. package/dist/tools/duplicated-strings.d.ts.map +1 -1
  40. package/dist/tools/duplicated-strings.js +62 -9
  41. package/dist/tools/duplicated-strings.js.map +1 -1
  42. package/dist/tools/eval.d.ts.map +1 -1
  43. package/dist/tools/eval.js +111 -7
  44. package/dist/tools/eval.js.map +1 -1
  45. package/dist/tools/event-listener-leaks.d.ts +12 -0
  46. package/dist/tools/event-listener-leaks.d.ts.map +1 -0
  47. package/dist/tools/event-listener-leaks.js +266 -0
  48. package/dist/tools/event-listener-leaks.js.map +1 -0
  49. package/dist/tools/find-by-property.d.ts.map +1 -1
  50. package/dist/tools/find-by-property.js +38 -4
  51. package/dist/tools/find-by-property.js.map +1 -1
  52. package/dist/tools/find-nodes-by-class.d.ts.map +1 -1
  53. package/dist/tools/find-nodes-by-class.js +4 -4
  54. package/dist/tools/find-nodes-by-class.js.map +1 -1
  55. package/dist/tools/for-each.d.ts.map +1 -1
  56. package/dist/tools/for-each.js +2 -2
  57. package/dist/tools/for-each.js.map +1 -1
  58. package/dist/tools/get-node.d.ts.map +1 -1
  59. package/dist/tools/get-node.js +2 -2
  60. package/dist/tools/get-node.js.map +1 -1
  61. package/dist/tools/get-property.d.ts.map +1 -1
  62. package/dist/tools/get-property.js +4 -4
  63. package/dist/tools/get-property.js.map +1 -1
  64. package/dist/tools/get-references.d.ts.map +1 -1
  65. package/dist/tools/get-references.js +11 -5
  66. package/dist/tools/get-references.js.map +1 -1
  67. package/dist/tools/get-referrers.d.ts.map +1 -1
  68. package/dist/tools/get-referrers.js +11 -5
  69. package/dist/tools/get-referrers.js.map +1 -1
  70. package/dist/tools/global-variables.d.ts.map +1 -1
  71. package/dist/tools/global-variables.js +10 -6
  72. package/dist/tools/global-variables.js.map +1 -1
  73. package/dist/tools/largest-objects.d.ts.map +1 -1
  74. package/dist/tools/largest-objects.js +78 -8
  75. package/dist/tools/largest-objects.js.map +1 -1
  76. package/dist/tools/load-snapshot.d.ts.map +1 -1
  77. package/dist/tools/load-snapshot.js +118 -4
  78. package/dist/tools/load-snapshot.js.map +1 -1
  79. package/dist/tools/object-shape.d.ts.map +1 -1
  80. package/dist/tools/object-shape.js +66 -47
  81. package/dist/tools/object-shape.js.map +1 -1
  82. package/dist/tools/pinch-points.d.ts +12 -0
  83. package/dist/tools/pinch-points.d.ts.map +1 -0
  84. package/dist/tools/pinch-points.js +124 -0
  85. package/dist/tools/pinch-points.js.map +1 -0
  86. package/dist/tools/quick-diagnosis.d.ts +12 -0
  87. package/dist/tools/quick-diagnosis.d.ts.map +1 -0
  88. package/dist/tools/quick-diagnosis.js +213 -0
  89. package/dist/tools/quick-diagnosis.js.map +1 -0
  90. package/dist/tools/referrer-summary.d.ts +12 -0
  91. package/dist/tools/referrer-summary.d.ts.map +1 -0
  92. package/dist/tools/referrer-summary.js +119 -0
  93. package/dist/tools/referrer-summary.js.map +1 -0
  94. package/dist/tools/reports.d.ts.map +1 -1
  95. package/dist/tools/reports.js +5 -5
  96. package/dist/tools/reports.js.map +1 -1
  97. package/dist/tools/retainer-summary.d.ts +12 -0
  98. package/dist/tools/retainer-summary.d.ts.map +1 -0
  99. package/dist/tools/retainer-summary.js +307 -0
  100. package/dist/tools/retainer-summary.js.map +1 -0
  101. package/dist/tools/retainer-trace.d.ts.map +1 -1
  102. package/dist/tools/retainer-trace.js +88 -14
  103. package/dist/tools/retainer-trace.js.map +1 -1
  104. package/dist/tools/search-nodes.d.ts.map +1 -1
  105. package/dist/tools/search-nodes.js +2 -2
  106. package/dist/tools/search-nodes.js.map +1 -1
  107. package/dist/tools/shape-histogram.d.ts +12 -0
  108. package/dist/tools/shape-histogram.d.ts.map +1 -0
  109. package/dist/tools/shape-histogram.js +119 -0
  110. package/dist/tools/shape-histogram.js.map +1 -0
  111. package/dist/tools/sliced-strings.d.ts +12 -0
  112. package/dist/tools/sliced-strings.d.ts.map +1 -0
  113. package/dist/tools/sliced-strings.js +126 -0
  114. package/dist/tools/sliced-strings.js.map +1 -0
  115. package/dist/tools/snapshot-summary.d.ts.map +1 -1
  116. package/dist/tools/snapshot-summary.js +42 -3
  117. package/dist/tools/snapshot-summary.js.map +1 -1
  118. package/dist/tools/stale-collections.d.ts.map +1 -1
  119. package/dist/tools/stale-collections.js +30 -6
  120. package/dist/tools/stale-collections.js.map +1 -1
  121. package/dist/tools/string-patterns.d.ts +12 -0
  122. package/dist/tools/string-patterns.d.ts.map +1 -0
  123. package/dist/tools/string-patterns.js +115 -0
  124. package/dist/tools/string-patterns.js.map +1 -0
  125. package/dist/tools/trace-dominators.d.ts +12 -0
  126. package/dist/tools/trace-dominators.d.ts.map +1 -0
  127. package/dist/tools/trace-dominators.js +237 -0
  128. package/dist/tools/trace-dominators.js.map +1 -0
  129. package/dist/utils.d.ts +9 -1
  130. package/dist/utils.d.ts.map +1 -1
  131. package/dist/utils.js +67 -5
  132. package/dist/utils.js.map +1 -1
  133. package/package.json +1 -1
@@ -8,8 +8,8 @@
8
8
  * @oncall memory_lab
9
9
  */
10
10
  import { z } from 'zod';
11
- import { getSnapshot } from '../heap-state.js';
12
- import { queryNodes, formatQueryNodesResult, errorResult, textResult, } from '../utils.js';
11
+ import { getSnapshot, getSnapshotEnv } from '../heap-state.js';
12
+ import { queryNodes, formatQueryNodesResult, formatBytes, formatNumber, markdownTable, errorResult, toolResult, } from '../utils.js';
13
13
  function isDetachedDOMNode(node) {
14
14
  if (node.id <= 3)
15
15
  return false;
@@ -17,13 +17,60 @@ function isDetachedDOMNode(node) {
17
17
  return true;
18
18
  return node.name.startsWith('Detached ');
19
19
  }
20
+ function extractElementTag(name) {
21
+ // V8 names detached DOM as "Detached <div>" or "Detached <div class="...">"
22
+ const match = name.match(/^(?:Detached\s+)?<(\w+)/);
23
+ return match ? match[1] : name;
24
+ }
25
+ function extractTestId(node) {
26
+ // Look for data-testid in the node name (V8 includes attributes)
27
+ const testIdMatch = node.name.match(/data-testid="([^"]+)"/);
28
+ if (testIdMatch)
29
+ return testIdMatch[1];
30
+ return '(no testid)';
31
+ }
32
+ function getFirstNonFrameworkRetainer(node) {
33
+ const frameworkNames = new Set([
34
+ 'system / Context',
35
+ '(GC roots)',
36
+ '(Strong roots)',
37
+ '(Builtins)',
38
+ '(Startup object cache)',
39
+ ]);
40
+ let cur = node;
41
+ const visited = new Set([node.id]);
42
+ while (cur && cur.hasPathEdge) {
43
+ const edge = cur.pathEdge;
44
+ if (!edge)
45
+ break;
46
+ const from = edge.fromNode;
47
+ if (visited.has(from.id))
48
+ break;
49
+ visited.add(from.id);
50
+ if (!frameworkNames.has(from.name) &&
51
+ !from.name.startsWith('system / ') &&
52
+ from.type !== 'hidden' &&
53
+ from.type !== 'array' &&
54
+ from.type !== 'synthetic' &&
55
+ from.type !== 'native') {
56
+ const edgeName = String(edge.name_or_index);
57
+ return `${from.name} (${from.type}) .${edgeName}`;
58
+ }
59
+ cur = from;
60
+ }
61
+ return '(unknown)';
62
+ }
20
63
  export function registerDetachedDom(server) {
21
- server.tool('memlab_detached_dom', 'Find detached DOM elements still retained in memory. These are common sources of memory leaks — DOM nodes removed from the document but kept alive by JavaScript references. Supports count-only and ids-only modes for large result sets.', {
64
+ server.tool('memlab_detached_dom', 'Find detached DOM elements still retained in memory. These are common sources of memory leaks — DOM nodes removed from the document but kept alive by JavaScript references. Supports count-only and ids-only modes for large result sets. Use group_by to aggregate by element tag, retainer pattern, or data-testid.', {
22
65
  output_mode: z
23
66
  .enum(['full', 'count', 'ids'])
24
67
  .optional()
25
68
  .default('full')
26
69
  .describe('Output verbosity: "full" returns node summaries (default), "count" returns only the total count, "ids" returns only node IDs'),
70
+ group_by: z
71
+ .enum(['element', 'retainer', 'testid'])
72
+ .optional()
73
+ .describe('Group detached DOM nodes instead of listing individually. "element" groups by HTML tag (div, span, button), "retainer" groups by first non-framework retainer (the component/module holding them), "testid" groups by data-testid attribute.'),
27
74
  offset: z
28
75
  .number()
29
76
  .optional()
@@ -34,16 +81,115 @@ export function registerDetachedDom(server) {
34
81
  .optional()
35
82
  .default(20)
36
83
  .describe('Maximum number of results (default 20, up to 10000 for ids mode)'),
37
- }, async ({ output_mode, offset, limit }) => {
84
+ }, async ({ output_mode, group_by, offset, limit }) => {
38
85
  try {
86
+ const env = getSnapshotEnv();
87
+ if (env === 'node') {
88
+ return toolResult('This is a Node.js snapshot — DOM nodes do not exist in this environment.\n\n' +
89
+ 'For Node.js memory investigation, try instead:\n' +
90
+ '- `memlab_duplicated_strings` — find duplicated string instances\n' +
91
+ '- `memlab_closure_inspection` — inspect closure captured variables\n' +
92
+ '- `memlab_largest_objects` — find objects consuming the most memory\n' +
93
+ '- `memlab_class_histogram` — per-class instance counts and sizes');
94
+ }
39
95
  const snapshot = getSnapshot();
96
+ if (group_by) {
97
+ const groups = new Map();
98
+ let totalDetached = 0;
99
+ let totalRetainedAll = 0;
100
+ snapshot.nodes.forEach(node => {
101
+ if (!isDetachedDOMNode(node))
102
+ return;
103
+ totalDetached++;
104
+ totalRetainedAll += node.retainedSize;
105
+ let key;
106
+ switch (group_by) {
107
+ case 'element':
108
+ key = extractElementTag(node.name);
109
+ break;
110
+ case 'retainer':
111
+ key = getFirstNonFrameworkRetainer(node);
112
+ break;
113
+ case 'testid':
114
+ key = extractTestId(node);
115
+ break;
116
+ }
117
+ const existing = groups.get(key);
118
+ if (existing) {
119
+ existing.count++;
120
+ existing.totalRetained += node.retainedSize;
121
+ if (node.retainedSize > existing.maxRetainedSize) {
122
+ existing.exampleId = node.id;
123
+ existing.maxRetainedSize = node.retainedSize;
124
+ }
125
+ }
126
+ else {
127
+ groups.set(key, {
128
+ count: 1,
129
+ totalRetained: node.retainedSize,
130
+ exampleId: node.id,
131
+ maxRetainedSize: node.retainedSize,
132
+ });
133
+ }
134
+ });
135
+ if (groups.size === 0) {
136
+ return toolResult('No detached DOM nodes found.');
137
+ }
138
+ const sorted = [...groups.entries()]
139
+ .sort((a, b) => b[1].totalRetained - a[1].totalRetained)
140
+ .slice(0, limit);
141
+ const groupLabel = group_by === 'element'
142
+ ? 'Element'
143
+ : group_by === 'retainer'
144
+ ? 'Retainer'
145
+ : 'data-testid';
146
+ const headers = [
147
+ groupLabel,
148
+ 'Count',
149
+ 'Total Retained',
150
+ '% of Detached',
151
+ 'Example ID',
152
+ ];
153
+ const rightCols = new Set([1, 2, 3]);
154
+ const rows = sorted.map(([key, stats]) => {
155
+ const pct = totalRetainedAll > 0
156
+ ? ((stats.totalRetained / totalRetainedAll) * 100).toFixed(1) +
157
+ '%'
158
+ : '-';
159
+ return [
160
+ key.length > 60 ? key.slice(0, 57) + '...' : key,
161
+ formatNumber(stats.count),
162
+ formatBytes(stats.totalRetained),
163
+ pct,
164
+ `@${stats.exampleId}`,
165
+ ];
166
+ });
167
+ const lines = [
168
+ `Detached DOM grouped by ${group_by}: ${formatNumber(totalDetached)} total nodes, ${formatBytes(totalRetainedAll)} total retained`,
169
+ '',
170
+ markdownTable(headers, rows, rightCols),
171
+ ];
172
+ if (sorted.length > 0) {
173
+ lines.push('', `**Suggested action:** Use \`memlab_retainer_summary\` with node_ids from the top group's example to trace the common retention pattern.`);
174
+ }
175
+ return toolResult(lines.join('\n'));
176
+ }
40
177
  const effectiveLimit = output_mode === 'ids' ? Math.min(limit, 10000) : Math.min(limit, 500);
41
178
  const result = queryNodes(snapshot, isDetachedDOMNode, {
42
179
  limit: effectiveLimit,
43
180
  offset,
44
181
  outputMode: output_mode,
45
182
  });
46
- return textResult(formatQueryNodesResult(result, offset));
183
+ const output = formatQueryNodesResult(result, offset);
184
+ if (result.total_count > 0 && output_mode === 'full') {
185
+ return toolResult(output +
186
+ '\n\n---\n\n' +
187
+ '**Suggested action:** Check for missing `removeEventListener` calls, ' +
188
+ 'React component cleanup in `useEffect` return, or refs not cleared on unmount. ' +
189
+ 'Use `memlab_retainer_trace` on top entries to find the retention path. ' +
190
+ 'Use `group_by: "retainer"` to see which components are retaining the most detached DOM.');
191
+ }
192
+ return toolResult(output);
47
193
  }
48
194
  catch (err) {
49
195
  return errorResult(err);
@@ -1 +1 @@
1
- {"version":3,"file":"detached-dom.js","sourceRoot":"","sources":["../../src/tools/detached-dom.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAC,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EACL,UAAU,EACV,sBAAsB,EACtB,WAAW,EACX,UAAU,GACX,MAAM,aAAa,CAAC;AAGrB,SAAS,iBAAiB,CAAC,IAAe;IACxC,IAAI,IAAI,CAAC,EAAE,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/B,IAAI,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAClC,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAiB;IACnD,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,4OAA4O,EAC5O;QACE,WAAW,EAAE,CAAC;aACX,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;aAC9B,QAAQ,EAAE;aACV,OAAO,CAAC,MAAM,CAAC;aACf,QAAQ,CACP,8HAA8H,CAC/H;QACH,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,OAAO,CAAC,CAAC,CAAC;aACV,QAAQ,CAAC,2CAA2C,CAAC;QACxD,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CACP,kEAAkE,CACnE;KACJ,EACD,KAAK,EAAE,EAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAC,EAAE,EAAE;QACrC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;YAC/B,MAAM,cAAc,GAClB,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAExE,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,EAAE,iBAAiB,EAAE;gBACrD,KAAK,EAAE,cAAc;gBACrB,MAAM;gBACN,UAAU,EAAE,WAAyB;aACtC,CAAC,CAAC;YAEH,OAAO,UAAU,CAAC,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAC5D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"detached-dom.js","sourceRoot":"","sources":["../../src/tools/detached-dom.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
11
+ export declare function registerDiffSnapshots(server: McpServer): void;
12
+ //# sourceMappingURL=diff-snapshots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-snapshots.d.ts","sourceRoot":"","sources":["../../src/tools/diff-snapshots.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAsCvE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyP7D"}
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ import { z } from 'zod';
13
+ import memlabHeapAnalysis from '@memlab/heap-analysis';
14
+ const { getFullHeapFromFile } = memlabHeapAnalysis;
15
+ import { setSnapshot } from '../heap-state.js';
16
+ import { formatBytes, formatNumber, markdownTable, errorResult, toolResult, } from '../utils.js';
17
+ function buildHistogram(snapshot) {
18
+ const map = new Map();
19
+ snapshot.nodes.forEach(node => {
20
+ if (node.id <= 3)
21
+ return;
22
+ const key = `${node.type}::${node.name}`;
23
+ const entry = map.get(key);
24
+ if (entry) {
25
+ entry.count++;
26
+ entry.self_size += node.self_size;
27
+ }
28
+ else {
29
+ map.set(key, { count: 1, self_size: node.self_size });
30
+ }
31
+ });
32
+ return map;
33
+ }
34
+ export function registerDiffSnapshots(server) {
35
+ server.tool('memlab_diff_snapshots', 'Compare two heap snapshots by class histogram. Shows classes that grew, shrunk, appeared, or disappeared between "before" and "after" snapshots. The "after" snapshot becomes the active snapshot for subsequent analysis.', {
36
+ before_path: z
37
+ .string()
38
+ .describe('Absolute path to the "before" .heapsnapshot file'),
39
+ after_path: z
40
+ .string()
41
+ .describe('Absolute path to the "after" .heapsnapshot file'),
42
+ limit: z
43
+ .number()
44
+ .optional()
45
+ .default(30)
46
+ .describe('Maximum rows per section (default 30)'),
47
+ min_count_delta: z
48
+ .number()
49
+ .optional()
50
+ .default(0)
51
+ .describe('Minimum absolute change in instance count to show (default 0). Use to filter noise.'),
52
+ min_size_delta: z
53
+ .number()
54
+ .optional()
55
+ .default(0)
56
+ .describe('Minimum absolute change in self size (bytes) to show (default 0).'),
57
+ }, async ({ before_path, after_path, limit, min_count_delta, min_size_delta, }) => {
58
+ try {
59
+ const resolvedBefore = path.resolve(before_path);
60
+ const resolvedAfter = path.resolve(after_path);
61
+ if (!fs.existsSync(resolvedBefore)) {
62
+ return errorResult(new Error(`Before file not found: ${resolvedBefore}`));
63
+ }
64
+ if (!fs.existsSync(resolvedAfter)) {
65
+ return errorResult(new Error(`After file not found: ${resolvedAfter}`));
66
+ }
67
+ const [beforeSnapshot, afterSnapshot] = await Promise.all([
68
+ getFullHeapFromFile(resolvedBefore),
69
+ getFullHeapFromFile(resolvedAfter),
70
+ ]);
71
+ const beforeHist = buildHistogram(beforeSnapshot);
72
+ const afterHist = buildHistogram(afterSnapshot);
73
+ // Make "after" the active snapshot
74
+ let afterNodeCount = 0;
75
+ let afterEdgeCount = 0;
76
+ let afterTotalSize = 0;
77
+ afterSnapshot.nodes.forEach(node => {
78
+ afterNodeCount++;
79
+ afterTotalSize += node.self_size;
80
+ });
81
+ afterSnapshot.edges.forEach(() => {
82
+ afterEdgeCount++;
83
+ });
84
+ let hasWindow = false;
85
+ let hasModule = false;
86
+ afterSnapshot.nodes.forEach(node => {
87
+ if (hasWindow)
88
+ return;
89
+ if (node.name.startsWith('Window ') && node.type === 'object')
90
+ hasWindow = true;
91
+ if (node.name === 'Module' && node.type === 'object' && !hasModule)
92
+ hasModule = true;
93
+ });
94
+ const afterEnv = hasWindow ? 'browser' : hasModule ? 'node' : 'unknown';
95
+ setSnapshot(afterSnapshot, after_path, {
96
+ fileName: path.basename(after_path),
97
+ nodeCount: afterNodeCount,
98
+ edgeCount: afterEdgeCount,
99
+ totalSize: afterTotalSize,
100
+ env: afterEnv,
101
+ });
102
+ // Compute deltas
103
+ const allKeys = new Set([...beforeHist.keys(), ...afterHist.keys()]);
104
+ const diffs = [];
105
+ for (const key of allKeys) {
106
+ const before = beforeHist.get(key);
107
+ const after = afterHist.get(key);
108
+ const bc = before?.count ?? 0;
109
+ const ac = after?.count ?? 0;
110
+ const bs = before?.self_size ?? 0;
111
+ const as_ = after?.self_size ?? 0;
112
+ const countDelta = ac - bc;
113
+ const sizeDelta = as_ - bs;
114
+ if (Math.abs(countDelta) < min_count_delta ||
115
+ Math.abs(sizeDelta) < min_size_delta) {
116
+ continue;
117
+ }
118
+ const parts = key.split('::');
119
+ diffs.push({
120
+ key,
121
+ name: parts.slice(1).join('::'),
122
+ type: parts[0],
123
+ before_count: bc,
124
+ after_count: ac,
125
+ count_delta: countDelta,
126
+ before_size: bs,
127
+ after_size: as_,
128
+ size_delta: sizeDelta,
129
+ });
130
+ }
131
+ const grew = diffs
132
+ .filter(d => d.count_delta > 0)
133
+ .sort((a, b) => b.count_delta - a.count_delta);
134
+ const shrunk = diffs
135
+ .filter(d => d.count_delta < 0)
136
+ .sort((a, b) => a.count_delta - b.count_delta);
137
+ const lines = [];
138
+ // Overall summary
139
+ let totalBeforeNodes = 0;
140
+ let totalBeforeSize = 0;
141
+ let totalAfterNodes = 0;
142
+ let totalAfterSize = 0;
143
+ beforeHist.forEach(v => {
144
+ totalBeforeNodes += v.count;
145
+ totalBeforeSize += v.self_size;
146
+ });
147
+ afterHist.forEach(v => {
148
+ totalAfterNodes += v.count;
149
+ totalAfterSize += v.self_size;
150
+ });
151
+ const nodeDelta = totalAfterNodes - totalBeforeNodes;
152
+ const sizeDelta = totalAfterSize - totalBeforeSize;
153
+ const sign = (n) => (n >= 0 ? '+' : '-');
154
+ lines.push('## Snapshot Comparison');
155
+ lines.push('');
156
+ lines.push(`| | Before | After | Delta |`);
157
+ lines.push(`|---|---:|---:|---:|`);
158
+ lines.push(`| Nodes | ${formatNumber(totalBeforeNodes)} | ${formatNumber(totalAfterNodes)} | ${sign(nodeDelta)}${formatNumber(Math.abs(nodeDelta))} |`);
159
+ lines.push(`| Self Size | ${formatBytes(totalBeforeSize)} | ${formatBytes(totalAfterSize)} | ${sign(sizeDelta)}${formatBytes(Math.abs(sizeDelta))} |`);
160
+ lines.push('');
161
+ // Grew section
162
+ if (grew.length > 0) {
163
+ const headers = [
164
+ 'Class',
165
+ 'Type',
166
+ 'Before',
167
+ 'After',
168
+ 'Δ Count',
169
+ 'Δ Size',
170
+ ];
171
+ const rightCols = new Set([2, 3, 4, 5]);
172
+ const rows = grew
173
+ .slice(0, limit)
174
+ .map(d => [
175
+ d.name,
176
+ d.type,
177
+ formatNumber(d.before_count),
178
+ formatNumber(d.after_count),
179
+ `+${formatNumber(d.count_delta)}`,
180
+ `${sign(d.size_delta)}${formatBytes(Math.abs(d.size_delta))}`,
181
+ ]);
182
+ lines.push(`### Classes that grew (${formatNumber(grew.length)} total, showing ${rows.length})`);
183
+ lines.push('');
184
+ lines.push(markdownTable(headers, rows, rightCols));
185
+ lines.push('');
186
+ }
187
+ // Shrunk section
188
+ if (shrunk.length > 0) {
189
+ const headers = [
190
+ 'Class',
191
+ 'Type',
192
+ 'Before',
193
+ 'After',
194
+ 'Δ Count',
195
+ 'Δ Size',
196
+ ];
197
+ const rightCols = new Set([2, 3, 4, 5]);
198
+ const rows = shrunk
199
+ .slice(0, limit)
200
+ .map(d => [
201
+ d.name,
202
+ d.type,
203
+ formatNumber(d.before_count),
204
+ formatNumber(d.after_count),
205
+ formatNumber(d.count_delta),
206
+ `${sign(d.size_delta)}${formatBytes(Math.abs(d.size_delta))}`,
207
+ ]);
208
+ lines.push(`### Classes that shrunk (${formatNumber(shrunk.length)} total, showing ${rows.length})`);
209
+ lines.push('');
210
+ lines.push(markdownTable(headers, rows, rightCols));
211
+ lines.push('');
212
+ }
213
+ if (grew.length === 0 && shrunk.length === 0) {
214
+ lines.push('No significant differences found between the two snapshots.');
215
+ }
216
+ lines.push(`\n*The "after" snapshot is now active for further analysis.*`);
217
+ return toolResult(lines.join('\n'));
218
+ }
219
+ catch (err) {
220
+ return errorResult(err);
221
+ }
222
+ });
223
+ }
224
+ //# sourceMappingURL=diff-snapshots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-snapshots.js","sourceRoot":"","sources":["../../src/tools/diff-snapshots.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"dominator-subtree.d.ts","sourceRoot":"","sources":["../../src/tools/dominator-subtree.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAevE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuEhE"}
1
+ {"version":3,"file":"dominator-subtree.d.ts","sourceRoot":"","sources":["../../src/tools/dominator-subtree.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAevE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsGhE"}
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import { z } from 'zod';
11
11
  import { getSnapshot } from '../heap-state.js';
12
- import { serializeNodeSummary, isNodeWorthInspecting, formatNodeSummaryTable, formatNodeInline, errorResult, textResult, formatBytes, formatNumber, } from '../utils.js';
12
+ import { serializeNodeSummary, isNodeWorthInspecting, formatNodeSummaryTable, formatNodeInline, errorResult, toolResult, formatBytes, formatNumber, } from '../utils.js';
13
13
  export function registerDominatorSubtree(server) {
14
14
  server.tool('memlab_dominator_subtree', 'Show the direct children in the dominator tree for a given node — i.e., objects whose retained size is exclusively attributed to this node. These are the objects that would be freed if this node were garbage collected. Useful for understanding what composes a large retained size.', {
15
15
  node_id: z.number().describe('The numeric ID of the heap node'),
@@ -56,18 +56,43 @@ export function registerDominatorSubtree(server) {
56
56
  }
57
57
  }
58
58
  });
59
- const summaries = dominated.map(serializeNodeSummary);
59
+ let summaries = dominated.map(serializeNodeSummary);
60
+ if (summaries.length === 0 && totalDominated > 0 && !include_internal) {
61
+ const internalChildren = [];
62
+ snapshot.nodes.forEach(node => {
63
+ if (node.dominatorNode?.id === node_id && node.id !== node_id) {
64
+ const size = node.retainedSize;
65
+ let inserted = false;
66
+ for (let i = 0; i < internalChildren.length; i++) {
67
+ if (size > internalChildren[i].retainedSize) {
68
+ internalChildren.splice(i, 0, node);
69
+ inserted = true;
70
+ break;
71
+ }
72
+ }
73
+ if (!inserted)
74
+ internalChildren.push(node);
75
+ if (internalChildren.length > limit)
76
+ internalChildren.length = limit;
77
+ }
78
+ });
79
+ summaries = internalChildren.map(serializeNodeSummary);
80
+ }
81
+ const autoIncluded = summaries.length > 0 && dominated.length === 0 && !include_internal;
60
82
  const lines = [
61
- `**${formatNodeInline(targetNode.id, targetNode.name, targetNode.type)}** — retained ${formatBytes(targetNode.retainedSize)}, ${formatNumber(totalDominated)} dominated nodes (showing ${summaries.length})`,
83
+ `**${formatNodeInline(targetNode.id, targetNode.name, targetNode.type, targetNode.self_size)}** — retained ${formatBytes(targetNode.retainedSize)}, ${formatNumber(totalDominated)} dominated nodes (showing ${summaries.length})`,
62
84
  '',
63
85
  ];
86
+ if (autoIncluded) {
87
+ lines.push(`_All ${formatNumber(totalDominated)} dominated children are internal/V8 nodes — showing them automatically (pass \`include_internal: true\` to always include)._`, '');
88
+ }
64
89
  if (summaries.length > 0) {
65
90
  lines.push(formatNodeSummaryTable(summaries));
66
91
  }
67
92
  else {
68
93
  lines.push('No dominated nodes found.');
69
94
  }
70
- return textResult(lines.join('\n'));
95
+ return toolResult(lines.join('\n'));
71
96
  }
72
97
  catch (err) {
73
98
  return errorResult(err);
@@ -1 +1 @@
1
- {"version":3,"file":"dominator-subtree.js","sourceRoot":"","sources":["../../src/tools/dominator-subtree.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dominator-subtree.js","sourceRoot":"","sources":["../../src/tools/dominator-subtree.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"duplicated-strings.d.ts","sourceRoot":"","sources":["../../src/tools/duplicated-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAKvE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4EjE"}
1
+ {"version":3,"file":"duplicated-strings.d.ts","sourceRoot":"","sources":["../../src/tools/duplicated-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAKvE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6IjE"}