@memlab/mcp-server 2.1.1 → 2.18.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 (175) hide show
  1. package/README.md +83 -3
  2. package/dist/analysis-budget.d.ts +71 -0
  3. package/dist/analysis-budget.d.ts.map +1 -0
  4. package/dist/analysis-budget.js +118 -0
  5. package/dist/analysis-budget.js.map +1 -0
  6. package/dist/guardrail.d.ts +24 -0
  7. package/dist/guardrail.d.ts.map +1 -0
  8. package/dist/guardrail.js +65 -0
  9. package/dist/guardrail.js.map +1 -0
  10. package/dist/heap-state.d.ts +53 -1
  11. package/dist/heap-state.d.ts.map +1 -1
  12. package/dist/heap-state.js +153 -10
  13. package/dist/heap-state.js.map +1 -1
  14. package/dist/index.js +38 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/tools/array-group-by.d.ts +12 -0
  17. package/dist/tools/array-group-by.d.ts.map +1 -0
  18. package/dist/tools/array-group-by.js +191 -0
  19. package/dist/tools/array-group-by.js.map +1 -0
  20. package/dist/tools/auto-investigate.d.ts.map +1 -1
  21. package/dist/tools/auto-investigate.js +1056 -52
  22. package/dist/tools/auto-investigate.js.map +1 -1
  23. package/dist/tools/cache-analysis.d.ts.map +1 -1
  24. package/dist/tools/cache-analysis.js +438 -21
  25. package/dist/tools/cache-analysis.js.map +1 -1
  26. package/dist/tools/check-health.d.ts.map +1 -1
  27. package/dist/tools/check-health.js +261 -1
  28. package/dist/tools/check-health.js.map +1 -1
  29. package/dist/tools/class-histogram.d.ts.map +1 -1
  30. package/dist/tools/class-histogram.js +142 -33
  31. package/dist/tools/class-histogram.js.map +1 -1
  32. package/dist/tools/closure-inspection.d.ts.map +1 -1
  33. package/dist/tools/closure-inspection.js +238 -25
  34. package/dist/tools/closure-inspection.js.map +1 -1
  35. package/dist/tools/detached-dom.d.ts.map +1 -1
  36. package/dist/tools/detached-dom.js +25 -3
  37. package/dist/tools/detached-dom.js.map +1 -1
  38. package/dist/tools/dev-artifacts.d.ts +33 -0
  39. package/dist/tools/dev-artifacts.d.ts.map +1 -0
  40. package/dist/tools/dev-artifacts.js +165 -0
  41. package/dist/tools/dev-artifacts.js.map +1 -0
  42. package/dist/tools/diff-snapshots.d.ts.map +1 -1
  43. package/dist/tools/diff-snapshots.js +200 -48
  44. package/dist/tools/diff-snapshots.js.map +1 -1
  45. package/dist/tools/duplicated-strings.d.ts.map +1 -1
  46. package/dist/tools/duplicated-strings.js +74 -12
  47. package/dist/tools/duplicated-strings.js.map +1 -1
  48. package/dist/tools/eval.d.ts.map +1 -1
  49. package/dist/tools/eval.js +189 -10
  50. package/dist/tools/eval.js.map +1 -1
  51. package/dist/tools/event-listener-leaks.d.ts.map +1 -1
  52. package/dist/tools/event-listener-leaks.js +235 -13
  53. package/dist/tools/event-listener-leaks.js.map +1 -1
  54. package/dist/tools/event-registry.d.ts +12 -0
  55. package/dist/tools/event-registry.d.ts.map +1 -0
  56. package/dist/tools/event-registry.js +183 -0
  57. package/dist/tools/event-registry.js.map +1 -0
  58. package/dist/tools/find-by-property.d.ts.map +1 -1
  59. package/dist/tools/find-by-property.js +113 -31
  60. package/dist/tools/find-by-property.js.map +1 -1
  61. package/dist/tools/find-by-shape.d.ts +12 -0
  62. package/dist/tools/find-by-shape.d.ts.map +1 -0
  63. package/dist/tools/find-by-shape.js +178 -0
  64. package/dist/tools/find-by-shape.js.map +1 -0
  65. package/dist/tools/find-nodes-by-class.d.ts.map +1 -1
  66. package/dist/tools/find-nodes-by-class.js +50 -6
  67. package/dist/tools/find-nodes-by-class.js.map +1 -1
  68. package/dist/tools/for-each.d.ts.map +1 -1
  69. package/dist/tools/for-each.js +1 -1
  70. package/dist/tools/for-each.js.map +1 -1
  71. package/dist/tools/get-node.d.ts.map +1 -1
  72. package/dist/tools/get-node.js +6 -0
  73. package/dist/tools/get-node.js.map +1 -1
  74. package/dist/tools/get-references.d.ts.map +1 -1
  75. package/dist/tools/get-references.js +35 -6
  76. package/dist/tools/get-references.js.map +1 -1
  77. package/dist/tools/get-referrers.d.ts.map +1 -1
  78. package/dist/tools/get-referrers.js +35 -6
  79. package/dist/tools/get-referrers.js.map +1 -1
  80. package/dist/tools/get-string.d.ts +12 -0
  81. package/dist/tools/get-string.d.ts.map +1 -0
  82. package/dist/tools/get-string.js +223 -0
  83. package/dist/tools/get-string.js.map +1 -0
  84. package/dist/tools/get-value.d.ts +12 -0
  85. package/dist/tools/get-value.d.ts.map +1 -0
  86. package/dist/tools/get-value.js +152 -0
  87. package/dist/tools/get-value.js.map +1 -0
  88. package/dist/tools/global-variables.d.ts.map +1 -1
  89. package/dist/tools/global-variables.js +54 -34
  90. package/dist/tools/global-variables.js.map +1 -1
  91. package/dist/tools/growth-signals.d.ts +12 -0
  92. package/dist/tools/growth-signals.d.ts.map +1 -0
  93. package/dist/tools/growth-signals.js +211 -0
  94. package/dist/tools/growth-signals.js.map +1 -0
  95. package/dist/tools/intern-opportunities.d.ts +12 -0
  96. package/dist/tools/intern-opportunities.d.ts.map +1 -0
  97. package/dist/tools/intern-opportunities.js +870 -0
  98. package/dist/tools/intern-opportunities.js.map +1 -0
  99. package/dist/tools/largest-objects.d.ts.map +1 -1
  100. package/dist/tools/largest-objects.js +37 -14
  101. package/dist/tools/largest-objects.js.map +1 -1
  102. package/dist/tools/load-snapshot.d.ts +70 -0
  103. package/dist/tools/load-snapshot.d.ts.map +1 -1
  104. package/dist/tools/load-snapshot.js +446 -17
  105. package/dist/tools/load-snapshot.js.map +1 -1
  106. package/dist/tools/object-cost-breakdown.d.ts +12 -0
  107. package/dist/tools/object-cost-breakdown.d.ts.map +1 -0
  108. package/dist/tools/object-cost-breakdown.js +439 -0
  109. package/dist/tools/object-cost-breakdown.js.map +1 -0
  110. package/dist/tools/object-shape.d.ts.map +1 -1
  111. package/dist/tools/object-shape.js +109 -2
  112. package/dist/tools/object-shape.js.map +1 -1
  113. package/dist/tools/pinch-points.d.ts.map +1 -1
  114. package/dist/tools/pinch-points.js +9 -9
  115. package/dist/tools/pinch-points.js.map +1 -1
  116. package/dist/tools/property-distribution.d.ts +12 -0
  117. package/dist/tools/property-distribution.d.ts.map +1 -0
  118. package/dist/tools/property-distribution.js +168 -0
  119. package/dist/tools/property-distribution.js.map +1 -0
  120. package/dist/tools/quick-diagnosis.d.ts.map +1 -1
  121. package/dist/tools/quick-diagnosis.js +65 -20
  122. package/dist/tools/quick-diagnosis.js.map +1 -1
  123. package/dist/tools/retainer-summary.d.ts.map +1 -1
  124. package/dist/tools/retainer-summary.js +90 -5
  125. package/dist/tools/retainer-summary.js.map +1 -1
  126. package/dist/tools/retainer-trace.d.ts.map +1 -1
  127. package/dist/tools/retainer-trace.js +173 -43
  128. package/dist/tools/retainer-trace.js.map +1 -1
  129. package/dist/tools/search-nodes.d.ts.map +1 -1
  130. package/dist/tools/search-nodes.js +10 -3
  131. package/dist/tools/search-nodes.js.map +1 -1
  132. package/dist/tools/search-strings.d.ts +12 -0
  133. package/dist/tools/search-strings.d.ts.map +1 -0
  134. package/dist/tools/search-strings.js +182 -0
  135. package/dist/tools/search-strings.js.map +1 -0
  136. package/dist/tools/sequence-analysis.d.ts +12 -0
  137. package/dist/tools/sequence-analysis.d.ts.map +1 -0
  138. package/dist/tools/sequence-analysis.js +244 -0
  139. package/dist/tools/sequence-analysis.js.map +1 -0
  140. package/dist/tools/server-status.d.ts +12 -0
  141. package/dist/tools/server-status.d.ts.map +1 -0
  142. package/dist/tools/server-status.js +41 -0
  143. package/dist/tools/server-status.js.map +1 -0
  144. package/dist/tools/shape-histogram.d.ts.map +1 -1
  145. package/dist/tools/shape-histogram.js +61 -16
  146. package/dist/tools/shape-histogram.js.map +1 -1
  147. package/dist/tools/sliced-strings.d.ts.map +1 -1
  148. package/dist/tools/sliced-strings.js +38 -15
  149. package/dist/tools/sliced-strings.js.map +1 -1
  150. package/dist/tools/snapshot-header.d.ts +28 -0
  151. package/dist/tools/snapshot-header.d.ts.map +1 -0
  152. package/dist/tools/snapshot-header.js +111 -0
  153. package/dist/tools/snapshot-header.js.map +1 -0
  154. package/dist/tools/snapshot-summary.d.ts.map +1 -1
  155. package/dist/tools/snapshot-summary.js +55 -13
  156. package/dist/tools/snapshot-summary.js.map +1 -1
  157. package/dist/tools/snapshots.d.ts +12 -0
  158. package/dist/tools/snapshots.d.ts.map +1 -0
  159. package/dist/tools/snapshots.js +93 -0
  160. package/dist/tools/snapshots.js.map +1 -0
  161. package/dist/tools/stale-collections.d.ts.map +1 -1
  162. package/dist/tools/stale-collections.js +248 -7
  163. package/dist/tools/stale-collections.js.map +1 -1
  164. package/dist/tools/trace-dominators.d.ts.map +1 -1
  165. package/dist/tools/trace-dominators.js +28 -1
  166. package/dist/tools/trace-dominators.js.map +1 -1
  167. package/dist/tools/weakmap-entries.d.ts +12 -0
  168. package/dist/tools/weakmap-entries.d.ts.map +1 -0
  169. package/dist/tools/weakmap-entries.js +156 -0
  170. package/dist/tools/weakmap-entries.js.map +1 -0
  171. package/dist/utils.d.ts +139 -2
  172. package/dist/utils.d.ts.map +1 -1
  173. package/dist/utils.js +448 -35
  174. package/dist/utils.js.map +1 -1
  175. package/package.json +3 -3
@@ -11,31 +11,53 @@ import { z } from 'zod';
11
11
  import { getSnapshot } from '../heap-state.js';
12
12
  import { formatBytes, formatNumber, markdownTable, truncateNodeName, errorResult, toolResult, } from '../utils.js';
13
13
  export function registerGetReferences(server) {
14
- server.tool('memlab_get_references', 'Get outgoing edges (references) from a heap node, sorted by target retained size. Shows what objects this node points to — its properties, elements, and closure captures. Complements memlab_get_referrers (incoming edges). Use memlab_object_shape for a quick property overview, or memlab_closure_inspection for closure-specific analysis.', {
14
+ server.tool('memlab_get_references', 'Get outgoing edges (references) from a heap node, sorted by target retained size. Shows what objects this node points to — its properties, elements, and closure captures. Supports edge_filter (match by edge name) and offset (pagination) so a node with thousands of references can be explored beyond the first page. Complements memlab_get_referrers (incoming edges). Use memlab_object_shape for a quick property overview, or memlab_closure_inspection for closure-specific analysis.', {
15
15
  node_id: z.number().describe('The numeric ID of the heap node'),
16
16
  limit: z
17
17
  .number()
18
18
  .optional()
19
19
  .default(30)
20
20
  .describe('Maximum number of references to return (default 30)'),
21
+ offset: z
22
+ .number()
23
+ .optional()
24
+ .default(0)
25
+ .describe('Number of (filtered, sorted) references to skip before returning — for paging past the first `limit` on high-degree nodes (default 0).'),
26
+ edge_filter: z
27
+ .string()
28
+ .optional()
29
+ .describe('Case-insensitive substring; only edges whose name/index contains it are returned (e.g. "context", or a specific property name). Applied before sort + pagination, so you can isolate one edge among thousands instead of scanning the top-N.'),
21
30
  compact: z
22
31
  .boolean()
23
32
  .optional()
24
33
  .default(true)
25
34
  .describe('Truncate target names to 60 chars to save tokens (default true). Set to false to see full names.'),
26
- }, async ({ node_id, limit, compact }) => {
35
+ }, async ({ node_id, limit, offset, edge_filter, compact }) => {
27
36
  try {
28
37
  const snapshot = getSnapshot();
29
38
  const node = snapshot.getNodeById(node_id);
30
39
  if (!node) {
31
40
  return errorResult(`Node with id ${node_id} not found`);
32
41
  }
33
- const edges = node.references
42
+ // Treat an empty / whitespace-only filter as "no filter" so the header
43
+ // doesn't advertise a filter that matches every edge, and clamp a
44
+ // negative offset to 0 rather than letting slice() read from the tail.
45
+ const activeFilter = edge_filter != null && edge_filter.trim() !== '' ? edge_filter : null;
46
+ const filterLc = activeFilter?.toLowerCase();
47
+ const safeOffset = Math.max(0, offset);
48
+ const matched = node.references
34
49
  .slice()
35
- .sort((a, b) => b.toNode.retainedSize - a.toNode.retainedSize)
36
- .slice(0, limit);
50
+ .filter(e => filterLc == null
51
+ ? true
52
+ : String(e.name_or_index).toLowerCase().includes(filterLc))
53
+ .sort((a, b) => b.toNode.retainedSize - a.toNode.retainedSize);
54
+ const edges = matched.slice(safeOffset, safeOffset + limit);
55
+ const filterNote = activeFilter != null
56
+ ? `, ${formatNumber(matched.length)} match "${activeFilter}"`
57
+ : '';
58
+ const offsetNote = safeOffset > 0 ? ` (from offset ${safeOffset})` : '';
37
59
  const lines = [
38
- `**@${node_id} ${node.name}** — ${formatNumber(node.edge_count)} total references, showing ${edges.length}`,
60
+ `**@${node_id} ${node.name}** — ${formatNumber(node.edge_count)} total references${filterNote}, showing ${edges.length}${offsetNote}`,
39
61
  '',
40
62
  ];
41
63
  const headers = [
@@ -57,6 +79,13 @@ export function registerGetReferences(server) {
57
79
  formatBytes(e.toNode.retainedSize),
58
80
  ]);
59
81
  lines.push(markdownTable(headers, rows, rightCols));
82
+ const shownEnd = safeOffset + edges.length;
83
+ if (shownEnd < matched.length) {
84
+ lines.push('', `_${formatNumber(matched.length - shownEnd)} more — pass offset=${shownEnd} for the next page._`);
85
+ }
86
+ else if (edges.length === 0 && safeOffset > 0 && matched.length > 0) {
87
+ lines.push('', `_offset ${safeOffset} is past the last of ${formatNumber(matched.length)} matched references — use a smaller offset._`);
88
+ }
60
89
  return toolResult(lines.join('\n'));
61
90
  }
62
91
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"get-references.js","sourceRoot":"","sources":["../../src/tools/get-references.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"get-references.js","sourceRoot":"","sources":["../../src/tools/get-references.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"get-referrers.d.ts","sourceRoot":"","sources":["../../src/tools/get-referrers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAYvE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoE5D"}
1
+ {"version":3,"file":"get-referrers.d.ts","sourceRoot":"","sources":["../../src/tools/get-referrers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAYvE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+G5D"}
@@ -11,31 +11,53 @@ import { z } from 'zod';
11
11
  import { getSnapshot } from '../heap-state.js';
12
12
  import { formatBytes, formatNumber, markdownTable, truncateNodeName, errorResult, toolResult, } from '../utils.js';
13
13
  export function registerGetReferrers(server) {
14
- server.tool('memlab_get_referrers', 'Get incoming edges (referrers) to a heap node, sorted by source retained size. Shows what objects hold references to this node. Complements memlab_get_references (outgoing edges). Use memlab_retainer_trace to see the full GC root path.', {
14
+ server.tool('memlab_get_referrers', 'Get incoming edges (referrers) to a heap node, sorted by source retained size. Shows what objects hold references to this node. Supports edge_filter (match by edge name) and offset (pagination) so a widely-referenced singleton can be explored beyond the first page — e.g. "which referrers are NOT the dev-only Debug alias?". Complements memlab_get_references (outgoing edges). Use memlab_retainer_trace to see the full GC root path.', {
15
15
  node_id: z.number().describe('The numeric ID of the heap node'),
16
16
  limit: z
17
17
  .number()
18
18
  .optional()
19
19
  .default(30)
20
20
  .describe('Maximum number of referrers to return (default 30)'),
21
+ offset: z
22
+ .number()
23
+ .optional()
24
+ .default(0)
25
+ .describe('Number of (filtered, sorted) referrers to skip before returning — for paging past the first `limit` on widely-referenced nodes (default 0).'),
26
+ edge_filter: z
27
+ .string()
28
+ .optional()
29
+ .describe('Case-insensitive substring; only referrers whose edge name/index contains it are returned. Applied before sort + pagination, so you can isolate one referrer among hundreds instead of scanning the top-N.'),
21
30
  compact: z
22
31
  .boolean()
23
32
  .optional()
24
33
  .default(true)
25
34
  .describe('Truncate source names to 60 chars to save tokens (default true). Set to false to see full names.'),
26
- }, async ({ node_id, limit, compact }) => {
35
+ }, async ({ node_id, limit, offset, edge_filter, compact }) => {
27
36
  try {
28
37
  const snapshot = getSnapshot();
29
38
  const node = snapshot.getNodeById(node_id);
30
39
  if (!node) {
31
40
  return errorResult(`Node with id ${node_id} not found`);
32
41
  }
33
- const edges = node.referrers
42
+ // Treat an empty / whitespace-only filter as "no filter" so the header
43
+ // doesn't advertise a filter that matches every referrer, and clamp a
44
+ // negative offset to 0 rather than letting slice() read from the tail.
45
+ const activeFilter = edge_filter != null && edge_filter.trim() !== '' ? edge_filter : null;
46
+ const filterLc = activeFilter?.toLowerCase();
47
+ const safeOffset = Math.max(0, offset);
48
+ const matched = node.referrers
34
49
  .slice()
35
- .sort((a, b) => b.fromNode.retainedSize - a.fromNode.retainedSize)
36
- .slice(0, limit);
50
+ .filter(e => filterLc == null
51
+ ? true
52
+ : String(e.name_or_index).toLowerCase().includes(filterLc))
53
+ .sort((a, b) => b.fromNode.retainedSize - a.fromNode.retainedSize);
54
+ const edges = matched.slice(safeOffset, safeOffset + limit);
55
+ const filterNote = activeFilter != null
56
+ ? `, ${formatNumber(matched.length)} match "${activeFilter}"`
57
+ : '';
58
+ const offsetNote = safeOffset > 0 ? ` (from offset ${safeOffset})` : '';
37
59
  const lines = [
38
- `**@${node_id} ${node.name}** — ${formatNumber(node.numOfReferrers)} total referrers, showing ${edges.length}`,
60
+ `**@${node_id} ${node.name}** — ${formatNumber(node.numOfReferrers)} total referrers${filterNote}, showing ${edges.length}${offsetNote}`,
39
61
  '',
40
62
  ];
41
63
  const headers = [
@@ -57,6 +79,13 @@ export function registerGetReferrers(server) {
57
79
  formatBytes(e.fromNode.retainedSize),
58
80
  ]);
59
81
  lines.push(markdownTable(headers, rows, rightCols));
82
+ const shownEnd = safeOffset + edges.length;
83
+ if (shownEnd < matched.length) {
84
+ lines.push('', `_${formatNumber(matched.length - shownEnd)} more — pass offset=${shownEnd} for the next page._`);
85
+ }
86
+ else if (edges.length === 0 && safeOffset > 0 && matched.length > 0) {
87
+ lines.push('', `_offset ${safeOffset} is past the last of ${formatNumber(matched.length)} matched referrers — use a smaller offset._`);
88
+ }
60
89
  return toolResult(lines.join('\n'));
61
90
  }
62
91
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"get-referrers.js","sourceRoot":"","sources":["../../src/tools/get-referrers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"get-referrers.js","sourceRoot":"","sources":["../../src/tools/get-referrers.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 registerGetString(server: McpServer): void;
12
+ //# sourceMappingURL=get-string.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-string.d.ts","sourceRoot":"","sources":["../../src/tools/get-string.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAsLvE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsGzD"}
@@ -0,0 +1,223 @@
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 { z } from 'zod';
11
+ import { getSnapshot } from '../heap-state.js';
12
+ import { formatBytes, formatNodeInline, errorResult, toolResult, } from '../utils.js';
13
+ function resolveStringValue(node, maxLen) {
14
+ // Try the standard stringValue API first
15
+ if (node.isString) {
16
+ const strNode = node.toStringNode();
17
+ if (strNode) {
18
+ const val = strNode.stringValue;
19
+ if (val.length > maxLen) {
20
+ return {
21
+ value: val.slice(0, maxLen),
22
+ truncated: true,
23
+ encoding: 'direct',
24
+ };
25
+ }
26
+ return { value: val, truncated: false, encoding: 'direct' };
27
+ }
28
+ }
29
+ // For concatenated strings, walk the first/second tree
30
+ if (node.name === '(concatenated string)' ||
31
+ node.type === 'concatenated string') {
32
+ return resolveConcatenatedString(node, maxLen);
33
+ }
34
+ // For sliced strings, resolve the parent and extract the slice
35
+ if (node.name === '(sliced string)' || node.type === 'sliced string') {
36
+ return resolveSlicedString(node, maxLen);
37
+ }
38
+ // For cons strings (another name for concatenated)
39
+ if (node.name === '(cons string)') {
40
+ return resolveConcatenatedString(node, maxLen);
41
+ }
42
+ return { value: '', truncated: false, encoding: 'unknown' };
43
+ }
44
+ function resolveConcatenatedString(node, maxLen) {
45
+ const parts = [];
46
+ let totalLen = 0;
47
+ let truncated = false;
48
+ function walk(n) {
49
+ if (truncated)
50
+ return;
51
+ // If this node is a flat string, get its value directly
52
+ if (n.isString) {
53
+ const strNode = n.toStringNode();
54
+ if (strNode) {
55
+ const val = strNode.stringValue;
56
+ if (totalLen + val.length > maxLen) {
57
+ parts.push(val.slice(0, maxLen - totalLen));
58
+ totalLen = maxLen;
59
+ truncated = true;
60
+ return;
61
+ }
62
+ parts.push(val);
63
+ totalLen += val.length;
64
+ return;
65
+ }
66
+ }
67
+ // Walk first and second edges for concatenated/cons strings
68
+ let first = null;
69
+ let second = null;
70
+ for (const edge of n.references) {
71
+ const name = String(edge.name_or_index);
72
+ if (name === 'first')
73
+ first = edge.toNode;
74
+ else if (name === 'second')
75
+ second = edge.toNode;
76
+ }
77
+ if (first)
78
+ walk(first);
79
+ if (second)
80
+ walk(second);
81
+ }
82
+ walk(node);
83
+ return { value: parts.join(''), truncated, encoding: 'concatenated' };
84
+ }
85
+ function resolveSlicedString(node, maxLen) {
86
+ // Sliced strings have a "parent" edge pointing to the original string
87
+ for (const edge of node.references) {
88
+ const name = String(edge.name_or_index);
89
+ if (name === 'parent') {
90
+ const parent = edge.toNode;
91
+ const resolved = resolveStringValue(parent, maxLen * 2);
92
+ // The sliced string is a substring of the parent.
93
+ // V8 stores offset and length internally, but the snapshot API
94
+ // exposes the stringValue directly via toStringNode() which should
95
+ // already handle this. If we got here, toStringNode() didn't work,
96
+ // so return the parent's full value as context.
97
+ return {
98
+ value: resolved.value,
99
+ truncated: resolved.truncated,
100
+ encoding: `sliced (from parent @${parent.id}, ${formatBytes(parent.self_size)})`,
101
+ };
102
+ }
103
+ }
104
+ return { value: '', truncated: false, encoding: 'sliced (parent not found)' };
105
+ }
106
+ function getStringStructure(node, depth = 0, maxDepth = 5) {
107
+ const lines = [];
108
+ const indent = ' '.repeat(depth);
109
+ if (depth > maxDepth) {
110
+ lines.push(`${indent}… (max depth reached)`);
111
+ return lines;
112
+ }
113
+ const typeLabel = node.type === 'concatenated string'
114
+ ? 'concat'
115
+ : node.name === '(concatenated string)'
116
+ ? 'concat'
117
+ : node.name === '(cons string)'
118
+ ? 'cons'
119
+ : node.name === '(sliced string)'
120
+ ? 'sliced'
121
+ : node.isString
122
+ ? 'flat'
123
+ : node.type;
124
+ if (node.isString &&
125
+ node.type !== 'concatenated string' &&
126
+ node.name !== '(concatenated string)' &&
127
+ node.name !== '(cons string)') {
128
+ const strNode = node.toStringNode();
129
+ if (strNode) {
130
+ const val = strNode.stringValue;
131
+ const preview = val.length > 60 ? val.slice(0, 60) + '…' : val;
132
+ lines.push(`${indent}@${node.id} [${typeLabel}] "${preview}" (${formatBytes(node.self_size)})`);
133
+ return lines;
134
+ }
135
+ }
136
+ lines.push(`${indent}@${node.id} [${typeLabel}] (${formatBytes(node.self_size)})`);
137
+ for (const edge of node.references) {
138
+ const name = String(edge.name_or_index);
139
+ if (name === 'first' || name === 'second' || name === 'parent') {
140
+ lines.push(`${indent} ${name}:`);
141
+ lines.push(...getStringStructure(edge.toNode, depth + 2, maxDepth));
142
+ }
143
+ }
144
+ return lines;
145
+ }
146
+ export function registerGetString(server) {
147
+ server.tool('memlab_get_string', 'Resolve any V8 string node to its full text value. Handles all V8 string encodings: ' +
148
+ 'flat strings, concatenated strings (ConsString with first/second tree), sliced strings ' +
149
+ '(substring of a parent), and cons strings. Returns the resolved text value and optionally ' +
150
+ 'shows the internal string tree structure. Essential when investigating event names, log ' +
151
+ 'messages, or error strings that V8 stores as concatenated string trees rather than flat strings.', {
152
+ node_id: z.number().describe('The numeric ID of the string node'),
153
+ max_length: z
154
+ .number()
155
+ .optional()
156
+ .default(10000)
157
+ .describe('Maximum characters to return (default 10000). Use higher values for full log messages.'),
158
+ show_structure: z
159
+ .boolean()
160
+ .optional()
161
+ .default(false)
162
+ .describe('Show the internal string tree structure (concatenation tree, parent references). Useful for understanding why a large parent string is kept alive by a small sliced substring.'),
163
+ }, async ({ node_id, max_length, show_structure }) => {
164
+ try {
165
+ const snapshot = getSnapshot();
166
+ const node = snapshot.getNodeById(node_id);
167
+ if (!node) {
168
+ return errorResult(`Node with id ${node_id} not found`);
169
+ }
170
+ const isStringType = node.isString ||
171
+ node.type === 'concatenated string' ||
172
+ node.type === 'sliced string' ||
173
+ node.name === '(concatenated string)' ||
174
+ node.name === '(cons string)' ||
175
+ node.name === '(sliced string)' ||
176
+ node.type === 'string';
177
+ if (!isStringType) {
178
+ return toolResult(`Node @${node_id} is not a string node (type: "${node.type}", name: "${node.name}"). ` +
179
+ 'This tool is designed for string, concatenated string, sliced string, and cons string nodes.\n\n' +
180
+ 'If you need to read a string property of an object, use `memlab_get_property` to navigate to the string node first.');
181
+ }
182
+ const resolved = resolveStringValue(node, max_length);
183
+ const lines = [];
184
+ lines.push(`**Node:** ${formatNodeInline(node.id, node.name, node.type, node.self_size)}`);
185
+ lines.push(`**Self Size:** ${formatBytes(node.self_size)} | **Retained Size:** ${formatBytes(node.retainedSize)}`);
186
+ lines.push(`**Encoding:** ${resolved.encoding}`);
187
+ lines.push(`**Length:** ${resolved.value.length}${resolved.truncated ? ` (truncated from longer value, use max_length to see more)` : ''} characters`);
188
+ lines.push('');
189
+ lines.push('**Value:**');
190
+ lines.push('```');
191
+ lines.push(resolved.value);
192
+ lines.push('```');
193
+ if (show_structure) {
194
+ lines.push('');
195
+ lines.push('**String Tree Structure:**');
196
+ lines.push('```');
197
+ lines.push(...getStringStructure(node));
198
+ lines.push('```');
199
+ }
200
+ // Show referrers for context
201
+ const referrerContexts = [];
202
+ let refCount = 0;
203
+ for (const edge of node.referrers) {
204
+ if (refCount >= 5)
205
+ break;
206
+ if (edge.fromNode.id <= 3)
207
+ continue;
208
+ referrerContexts.push(`- \`${String(edge.name_or_index)}\` on @${edge.fromNode.id} \`${edge.fromNode.name}\` (${edge.fromNode.type})`);
209
+ refCount++;
210
+ }
211
+ if (referrerContexts.length > 0) {
212
+ lines.push('');
213
+ lines.push('**Referenced by:**');
214
+ lines.push(...referrerContexts);
215
+ }
216
+ return toolResult(lines.join('\n'));
217
+ }
218
+ catch (err) {
219
+ return errorResult(err);
220
+ }
221
+ });
222
+ }
223
+ //# sourceMappingURL=get-string.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-string.js","sourceRoot":"","sources":["../../src/tools/get-string.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 registerGetValue(server: McpServer): void;
12
+ //# sourceMappingURL=get-value.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-value.d.ts","sourceRoot":"","sources":["../../src/tools/get-value.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AA4EvE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmIxD"}
@@ -0,0 +1,152 @@
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 { z } from 'zod';
11
+ import { getSnapshot } from '../heap-state.js';
12
+ import { formatBytes, formatNodeInline, errorResult, toolResult, suggestionsSuppressed, } from '../utils.js';
13
+ function decodeSmi(node) {
14
+ // V8 stores Small Integers (SMIs) with the value encoded in the node ID.
15
+ // SMI node IDs are odd numbers; the actual value is id >> 1.
16
+ // SMI nodes have type "number" and name "smi number" with self_size 0.
17
+ if (node.name === 'smi number' && node.self_size === 0) {
18
+ return node.id >> 1;
19
+ }
20
+ return null;
21
+ }
22
+ function decodeHeapNumber(node) {
23
+ // V8 stores heap numbers (doubles that don't fit in SMI range) as
24
+ // separate heap objects. The actual IEEE 754 value is not directly
25
+ // accessible via the heap snapshot API, but we can identify them.
26
+ if (node.name === 'heap number' ||
27
+ (node.type === 'number' && node.name !== 'smi number')) {
28
+ // Heap numbers have self_size of 12 or 16 bytes (object header + 8-byte double).
29
+ // The value itself is not exposed in the standard heap snapshot format,
30
+ // but we can check if it's referenced by a property edge to provide context.
31
+ return {
32
+ value: null,
33
+ raw: 'IEEE 754 double (value not stored in snapshot format)',
34
+ };
35
+ }
36
+ return { value: null, raw: null };
37
+ }
38
+ function getPropertyContext(node) {
39
+ const contexts = [];
40
+ for (const edge of node.referrers) {
41
+ if (edge.type === 'property' ||
42
+ edge.type === 'element' ||
43
+ edge.type === 'context') {
44
+ const from = edge.fromNode;
45
+ if (from.id <= 3)
46
+ continue;
47
+ contexts.push({
48
+ ownerName: from.name,
49
+ ownerType: from.type,
50
+ ownerId: from.id,
51
+ propertyName: String(edge.name_or_index),
52
+ });
53
+ if (contexts.length >= 10)
54
+ break;
55
+ }
56
+ }
57
+ return contexts;
58
+ }
59
+ export function registerGetValue(server) {
60
+ server.tool('memlab_get_value', 'Decode the actual numeric value of a V8 SMI (Small Integer) or heap number node. ' +
61
+ 'V8 stores numbers as either SMI nodes (value encoded as id >> 1, self_size 0) or ' +
62
+ 'heap number nodes (IEEE 754 doubles). This tool decodes them and shows which objects ' +
63
+ 'reference the number and via which property name, providing the context needed to ' +
64
+ 'understand what the number represents. Essential when inspecting numeric properties ' +
65
+ 'like counters, capacities, or sizes that appear as opaque "smi number" or "heap number" nodes.', {
66
+ node_id: z
67
+ .number()
68
+ .describe('The numeric ID of the number node to decode, OR (with property_name) the owner object whose numeric property should be decoded.'),
69
+ property_name: z
70
+ .string()
71
+ .optional()
72
+ .describe('Optional: decode this numeric property of node_id instead of node_id itself. Lets you decode an inline SMI/number property by (node_id, property_name) without first looking up the value node.'),
73
+ }, async ({ node_id, property_name }) => {
74
+ try {
75
+ const snapshot = getSnapshot();
76
+ const owner = snapshot.getNodeById(node_id);
77
+ if (!owner) {
78
+ return errorResult(`Node with id ${node_id} not found`);
79
+ }
80
+ let node = owner;
81
+ if (property_name != null) {
82
+ const edge = owner.references.find(e => e.type === 'property' &&
83
+ String(e.name_or_index) === property_name);
84
+ if (!edge) {
85
+ return errorResult(`Property "${property_name}" not found on @${node_id} (${owner.name}).`);
86
+ }
87
+ node = edge.toNode;
88
+ }
89
+ const lines = [];
90
+ if (property_name != null) {
91
+ lines.push(`**Property:** \`${property_name}\` on @${node_id} ${owner.name} (${owner.type})`);
92
+ }
93
+ lines.push(`**Node:** ${formatNodeInline(node.id, node.name, node.type, node.self_size)}`);
94
+ lines.push(`**Self Size:** ${formatBytes(node.self_size)} | **Retained Size:** ${formatBytes(node.retainedSize)}`);
95
+ lines.push('');
96
+ const smiValue = decodeSmi(node);
97
+ if (smiValue !== null) {
98
+ lines.push(`**Decoded SMI Value:** ${smiValue}`);
99
+ lines.push(`**Encoding:** SMI (Small Integer) — value = node_id >> 1 = ${node.id} >> 1 = ${smiValue}`);
100
+ }
101
+ else {
102
+ const heapNum = decodeHeapNumber(node);
103
+ if (heapNum.raw) {
104
+ lines.push(`**Type:** Heap Number (boxed double-precision float)`);
105
+ lines.push(`**Note:** ${heapNum.raw}`);
106
+ lines.push('');
107
+ lines.push('_The V8 heap snapshot format does not include the raw IEEE 754 value for heap numbers. Check the property name and owner context below to infer meaning._');
108
+ }
109
+ else if (node.type === 'number') {
110
+ lines.push(`**Type:** Number node (unrecognized encoding)`);
111
+ }
112
+ else {
113
+ lines.push(`**Note:** Node @${node.id} is not a number node (type: "${node.type}", name: "${node.name}").`);
114
+ lines.push('This tool is designed for "smi number" and "heap number" nodes.');
115
+ if (node.isString) {
116
+ const strNode = node.toStringNode();
117
+ if (strNode) {
118
+ const val = strNode.stringValue;
119
+ const numVal = Number(val);
120
+ if (!isNaN(numVal)) {
121
+ lines.push('');
122
+ lines.push(`However, this is a string node with numeric content: "${val.slice(0, 100)}" (parsed as ${numVal})`);
123
+ }
124
+ }
125
+ }
126
+ }
127
+ }
128
+ const contexts = getPropertyContext(node);
129
+ if (contexts.length > 0) {
130
+ lines.push('');
131
+ lines.push('**Referenced by:**');
132
+ for (const ctx of contexts) {
133
+ lines.push(`- \`${ctx.propertyName}\` on @${ctx.ownerId} \`${ctx.ownerName}\` (${ctx.ownerType})`);
134
+ }
135
+ }
136
+ if (!suggestionsSuppressed()) {
137
+ lines.push('');
138
+ lines.push('**Suggested next steps:**');
139
+ if (contexts.length > 0) {
140
+ lines.push(`- Inspect owner: \`memlab_object_shape(${contexts[0].ownerId})\``);
141
+ lines.push(`- Trace owner retention: \`memlab_retainer_trace(${contexts[0].ownerId})\``);
142
+ }
143
+ lines.push(`- For all number properties on an object, use \`memlab_object_shape\` — it decodes SMI values inline`);
144
+ }
145
+ return toolResult(lines.join('\n'));
146
+ }
147
+ catch (err) {
148
+ return errorResult(err);
149
+ }
150
+ });
151
+ }
152
+ //# sourceMappingURL=get-value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-value.js","sourceRoot":"","sources":["../../src/tools/get-value.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"global-variables.d.ts","sourceRoot":"","sources":["../../src/tools/global-variables.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAsQvE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyF/D"}
1
+ {"version":3,"file":"global-variables.d.ts","sourceRoot":"","sources":["../../src/tools/global-variables.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAuQvE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+G/D"}