@memlab/mcp-server 2.0.3 → 2.1.0
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/README.md +13 -13
- package/dist/heap-state.d.ts +12 -1
- package/dist/heap-state.d.ts.map +1 -1
- package/dist/heap-state.js +10 -4
- package/dist/heap-state.js.map +1 -1
- package/dist/index.js +27 -1
- package/dist/index.js.map +1 -1
- package/dist/tools/aggregate-nodes.d.ts.map +1 -1
- package/dist/tools/aggregate-nodes.js +2 -2
- package/dist/tools/aggregate-nodes.js.map +1 -1
- package/dist/tools/auto-investigate.d.ts +12 -0
- package/dist/tools/auto-investigate.d.ts.map +1 -0
- package/dist/tools/auto-investigate.js +683 -0
- package/dist/tools/auto-investigate.js.map +1 -0
- package/dist/tools/cache-analysis.d.ts +12 -0
- package/dist/tools/cache-analysis.d.ts.map +1 -0
- package/dist/tools/cache-analysis.js +341 -0
- package/dist/tools/cache-analysis.js.map +1 -0
- package/dist/tools/check-health.d.ts +12 -0
- package/dist/tools/check-health.d.ts.map +1 -0
- package/dist/tools/check-health.js +289 -0
- package/dist/tools/check-health.js.map +1 -0
- package/dist/tools/class-histogram.d.ts.map +1 -1
- package/dist/tools/class-histogram.js +70 -14
- package/dist/tools/class-histogram.js.map +1 -1
- package/dist/tools/closure-inspection.d.ts.map +1 -1
- package/dist/tools/closure-inspection.js +5 -5
- package/dist/tools/closure-inspection.js.map +1 -1
- package/dist/tools/detached-dom.d.ts.map +1 -1
- package/dist/tools/detached-dom.js +151 -5
- package/dist/tools/detached-dom.js.map +1 -1
- package/dist/tools/diff-snapshots.d.ts +12 -0
- package/dist/tools/diff-snapshots.d.ts.map +1 -0
- package/dist/tools/diff-snapshots.js +224 -0
- package/dist/tools/diff-snapshots.js.map +1 -0
- package/dist/tools/dominator-subtree.d.ts.map +1 -1
- package/dist/tools/dominator-subtree.js +29 -4
- package/dist/tools/dominator-subtree.js.map +1 -1
- package/dist/tools/duplicated-strings.d.ts.map +1 -1
- package/dist/tools/duplicated-strings.js +62 -9
- package/dist/tools/duplicated-strings.js.map +1 -1
- package/dist/tools/eval.d.ts.map +1 -1
- package/dist/tools/eval.js +111 -7
- package/dist/tools/eval.js.map +1 -1
- package/dist/tools/event-listener-leaks.d.ts +12 -0
- package/dist/tools/event-listener-leaks.d.ts.map +1 -0
- package/dist/tools/event-listener-leaks.js +266 -0
- package/dist/tools/event-listener-leaks.js.map +1 -0
- package/dist/tools/find-by-property.d.ts.map +1 -1
- package/dist/tools/find-by-property.js +38 -4
- package/dist/tools/find-by-property.js.map +1 -1
- package/dist/tools/find-nodes-by-class.d.ts.map +1 -1
- package/dist/tools/find-nodes-by-class.js +4 -4
- package/dist/tools/find-nodes-by-class.js.map +1 -1
- package/dist/tools/for-each.d.ts.map +1 -1
- package/dist/tools/for-each.js +2 -2
- package/dist/tools/for-each.js.map +1 -1
- package/dist/tools/get-node.d.ts.map +1 -1
- package/dist/tools/get-node.js +2 -2
- package/dist/tools/get-node.js.map +1 -1
- package/dist/tools/get-property.d.ts.map +1 -1
- package/dist/tools/get-property.js +4 -4
- package/dist/tools/get-property.js.map +1 -1
- package/dist/tools/get-references.d.ts.map +1 -1
- package/dist/tools/get-references.js +11 -5
- package/dist/tools/get-references.js.map +1 -1
- package/dist/tools/get-referrers.d.ts.map +1 -1
- package/dist/tools/get-referrers.js +11 -5
- package/dist/tools/get-referrers.js.map +1 -1
- package/dist/tools/global-variables.d.ts.map +1 -1
- package/dist/tools/global-variables.js +10 -6
- package/dist/tools/global-variables.js.map +1 -1
- package/dist/tools/largest-objects.d.ts.map +1 -1
- package/dist/tools/largest-objects.js +78 -8
- package/dist/tools/largest-objects.js.map +1 -1
- package/dist/tools/load-snapshot.d.ts.map +1 -1
- package/dist/tools/load-snapshot.js +118 -4
- package/dist/tools/load-snapshot.js.map +1 -1
- package/dist/tools/object-shape.d.ts.map +1 -1
- package/dist/tools/object-shape.js +66 -47
- package/dist/tools/object-shape.js.map +1 -1
- package/dist/tools/pinch-points.d.ts +12 -0
- package/dist/tools/pinch-points.d.ts.map +1 -0
- package/dist/tools/pinch-points.js +124 -0
- package/dist/tools/pinch-points.js.map +1 -0
- package/dist/tools/quick-diagnosis.d.ts +12 -0
- package/dist/tools/quick-diagnosis.d.ts.map +1 -0
- package/dist/tools/quick-diagnosis.js +213 -0
- package/dist/tools/quick-diagnosis.js.map +1 -0
- package/dist/tools/referrer-summary.d.ts +12 -0
- package/dist/tools/referrer-summary.d.ts.map +1 -0
- package/dist/tools/referrer-summary.js +119 -0
- package/dist/tools/referrer-summary.js.map +1 -0
- package/dist/tools/reports.d.ts.map +1 -1
- package/dist/tools/reports.js +5 -5
- package/dist/tools/reports.js.map +1 -1
- package/dist/tools/retainer-summary.d.ts +12 -0
- package/dist/tools/retainer-summary.d.ts.map +1 -0
- package/dist/tools/retainer-summary.js +307 -0
- package/dist/tools/retainer-summary.js.map +1 -0
- package/dist/tools/retainer-trace.d.ts.map +1 -1
- package/dist/tools/retainer-trace.js +88 -14
- package/dist/tools/retainer-trace.js.map +1 -1
- package/dist/tools/search-nodes.d.ts.map +1 -1
- package/dist/tools/search-nodes.js +2 -2
- package/dist/tools/search-nodes.js.map +1 -1
- package/dist/tools/shape-histogram.d.ts +12 -0
- package/dist/tools/shape-histogram.d.ts.map +1 -0
- package/dist/tools/shape-histogram.js +119 -0
- package/dist/tools/shape-histogram.js.map +1 -0
- package/dist/tools/sliced-strings.d.ts +12 -0
- package/dist/tools/sliced-strings.d.ts.map +1 -0
- package/dist/tools/sliced-strings.js +126 -0
- package/dist/tools/sliced-strings.js.map +1 -0
- package/dist/tools/snapshot-summary.d.ts.map +1 -1
- package/dist/tools/snapshot-summary.js +42 -3
- package/dist/tools/snapshot-summary.js.map +1 -1
- package/dist/tools/stale-collections.d.ts.map +1 -1
- package/dist/tools/stale-collections.js +30 -6
- package/dist/tools/stale-collections.js.map +1 -1
- package/dist/tools/string-patterns.d.ts +12 -0
- package/dist/tools/string-patterns.d.ts.map +1 -0
- package/dist/tools/string-patterns.js +115 -0
- package/dist/tools/string-patterns.js.map +1 -0
- package/dist/tools/trace-dominators.d.ts +12 -0
- package/dist/tools/trace-dominators.d.ts.map +1 -0
- package/dist/tools/trace-dominators.js +237 -0
- package/dist/tools/trace-dominators.js.map +1 -0
- package/dist/utils.d.ts +9 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +67 -5
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -9,15 +9,25 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { z } from 'zod';
|
|
11
11
|
import { getSnapshot } from '../heap-state.js';
|
|
12
|
-
import { formatBytes, errorResult,
|
|
12
|
+
import { formatBytes, errorResult, toolResult } from '../utils.js';
|
|
13
13
|
export function registerDuplicatedStrings(server) {
|
|
14
|
-
server.tool('memlab_duplicated_strings', 'Find duplicated string instances in the heap. Shows strings that appear multiple times, ranked by total retained size — a common source of memory waste.', {
|
|
14
|
+
server.tool('memlab_duplicated_strings', 'Find duplicated string instances in the heap. Shows strings that appear multiple times, ranked by total retained size — a common source of memory waste. Use after memlab_class_histogram shows high string counts.', {
|
|
15
15
|
limit: z
|
|
16
16
|
.number()
|
|
17
17
|
.optional()
|
|
18
18
|
.default(15)
|
|
19
19
|
.describe('Maximum number of results (default 15)'),
|
|
20
|
-
|
|
20
|
+
min_count: z
|
|
21
|
+
.number()
|
|
22
|
+
.optional()
|
|
23
|
+
.default(2)
|
|
24
|
+
.describe('Minimum number of copies to include (default 2). Increase to focus on heavily duplicated strings (e.g., 100).'),
|
|
25
|
+
include_node_ids: z
|
|
26
|
+
.boolean()
|
|
27
|
+
.optional()
|
|
28
|
+
.default(false)
|
|
29
|
+
.describe('Include example node IDs in the output for follow-up with retainer_summary. Omitted by default to save ~20-30 tokens per entry.'),
|
|
30
|
+
}, async ({ limit, min_count, include_node_ids }) => {
|
|
21
31
|
try {
|
|
22
32
|
const snapshot = getSnapshot();
|
|
23
33
|
// Build frequency map: string value -> { count, totalSize, exampleIds }
|
|
@@ -48,9 +58,8 @@ export function registerDuplicatedStrings(server) {
|
|
|
48
58
|
});
|
|
49
59
|
}
|
|
50
60
|
});
|
|
51
|
-
// Filter to only duplicated strings (count > 1) and rank by total size
|
|
52
61
|
const duplicated = Array.from(stringMap.entries())
|
|
53
|
-
.filter(([, stats]) => stats.count
|
|
62
|
+
.filter(([, stats]) => stats.count >= min_count)
|
|
54
63
|
.sort((a, b) => b[1].total_size - a[1].total_size)
|
|
55
64
|
.slice(0, limit)
|
|
56
65
|
.map(([value, stats]) => ({
|
|
@@ -59,16 +68,60 @@ export function registerDuplicatedStrings(server) {
|
|
|
59
68
|
total_size: stats.total_size,
|
|
60
69
|
total_size_formatted: formatBytes(stats.total_size),
|
|
61
70
|
example_node_ids: stats.example_node_ids,
|
|
71
|
+
field_context: null,
|
|
62
72
|
}));
|
|
63
73
|
if (duplicated.length === 0) {
|
|
64
|
-
return
|
|
74
|
+
return toolResult('No duplicated strings found.');
|
|
75
|
+
}
|
|
76
|
+
// For top entries, sample referrer objects to show field context
|
|
77
|
+
for (const d of duplicated.slice(0, 10)) {
|
|
78
|
+
const propCounts = new Map();
|
|
79
|
+
for (const nodeId of d.example_node_ids) {
|
|
80
|
+
const node = snapshot.getNodeById(nodeId);
|
|
81
|
+
if (!node)
|
|
82
|
+
continue;
|
|
83
|
+
for (const ref of node.referrers) {
|
|
84
|
+
if (ref.type === 'property' || ref.type === 'context') {
|
|
85
|
+
const propName = String(ref.name_or_index);
|
|
86
|
+
const entry = propCounts.get(propName);
|
|
87
|
+
if (entry) {
|
|
88
|
+
entry.count++;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
propCounts.set(propName, {
|
|
92
|
+
count: 1,
|
|
93
|
+
ownerName: ref.fromNode.name,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (propCounts.size > 0) {
|
|
100
|
+
const topProp = [...propCounts.entries()].sort((a, b) => b[1].count - a[1].count)[0];
|
|
101
|
+
d.field_context = `.${topProp[0]} on \`${topProp[1].ownerName}\` instances`;
|
|
102
|
+
}
|
|
65
103
|
}
|
|
66
104
|
const lines = duplicated.map((d, i) => {
|
|
67
105
|
const val = d.value.length > 80 ? d.value.slice(0, 80) + '...' : d.value;
|
|
68
|
-
const
|
|
69
|
-
|
|
106
|
+
const nodeIdsPart = include_node_ids
|
|
107
|
+
? ` (nodes: ${d.example_node_ids.map(id => `@${id}`).join(', ')})`
|
|
108
|
+
: '';
|
|
109
|
+
const context = d.field_context
|
|
110
|
+
? `\n commonly held as: ${d.field_context}`
|
|
111
|
+
: '';
|
|
112
|
+
return `${i + 1}. "${val}" x ${d.count} copies, ${d.total_size_formatted} total${nodeIdsPart}${context}`;
|
|
70
113
|
});
|
|
71
|
-
|
|
114
|
+
const hasHeavyDups = duplicated.some(d => d.count >= 1000);
|
|
115
|
+
const suggestions = [];
|
|
116
|
+
if (hasHeavyDups) {
|
|
117
|
+
suggestions.push('**Suggested action:** Heavily duplicated strings often come from `JSON.parse()` or API responses. ' +
|
|
118
|
+
'Consider string interning with a `Map<string, string>` pool applied at ingestion time, ' +
|
|
119
|
+
'or deduplicating at the data source.');
|
|
120
|
+
}
|
|
121
|
+
const body = `Duplicated strings (${duplicated.length} entries):\n\n${lines.join('\n')}`;
|
|
122
|
+
return toolResult(suggestions.length > 0
|
|
123
|
+
? `${body}\n\n---\n\n${suggestions.join('\n')}`
|
|
124
|
+
: body);
|
|
72
125
|
}
|
|
73
126
|
catch (err) {
|
|
74
127
|
return errorResult(err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duplicated-strings.js","sourceRoot":"","sources":["../../src/tools/duplicated-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAC,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAC,WAAW,EAAE,WAAW,EAAE,UAAU,EAAC,MAAM,aAAa,CAAC;AAEjE,MAAM,UAAU,yBAAyB,CAAC,MAAiB;IACzD,MAAM,CAAC,IAAI,CACT,2BAA2B,EAC3B,
|
|
1
|
+
{"version":3,"file":"duplicated-strings.js","sourceRoot":"","sources":["../../src/tools/duplicated-strings.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/eval.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eval.d.ts","sourceRoot":"","sources":["../../src/tools/eval.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"eval.d.ts","sourceRoot":"","sources":["../../src/tools/eval.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAmHvE,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4IpD"}
|
package/dist/tools/eval.js
CHANGED
|
@@ -12,27 +12,131 @@ import vm from 'node:vm';
|
|
|
12
12
|
import memlabCore from '@memlab/core';
|
|
13
13
|
const { utils } = memlabCore;
|
|
14
14
|
import { getSnapshot } from '../heap-state.js';
|
|
15
|
-
import { errorResult,
|
|
15
|
+
import { errorResult, toolResult, serializeNodeSummary, serializeNodeDetail, formatBytes, formatNumber, markdownTable, isNodeWorthInspecting, filterLargestObjects, queryNodes, } from '../utils.js';
|
|
16
16
|
const MAX_OUTPUT_SIZE = 50 * 1024; // 50KB
|
|
17
17
|
function truncate(str, max) {
|
|
18
18
|
if (str.length <= max)
|
|
19
19
|
return str;
|
|
20
20
|
return str.slice(0, max) + '\n... [truncated, output exceeded 50KB]';
|
|
21
21
|
}
|
|
22
|
+
const NODE_PROPERTY_ALIASES = {
|
|
23
|
+
retained_size: 'retainedSize',
|
|
24
|
+
referrer_count: 'numOfReferrers',
|
|
25
|
+
};
|
|
26
|
+
function wrapNode(node) {
|
|
27
|
+
if (node == null)
|
|
28
|
+
return node;
|
|
29
|
+
return new Proxy(node, {
|
|
30
|
+
get(target, prop, receiver) {
|
|
31
|
+
if (typeof prop === 'string' && prop in NODE_PROPERTY_ALIASES) {
|
|
32
|
+
return target[NODE_PROPERTY_ALIASES[prop]];
|
|
33
|
+
}
|
|
34
|
+
const val = Reflect.get(target, prop, receiver);
|
|
35
|
+
if (prop === 'references' || prop === 'referrers') {
|
|
36
|
+
return wrapEdgeIterable(val);
|
|
37
|
+
}
|
|
38
|
+
if (prop === 'dominatorNode' || prop === 'pathEdge') {
|
|
39
|
+
if (val != null && typeof val === 'object' && 'fromNode' in val) {
|
|
40
|
+
return wrapEdge(val);
|
|
41
|
+
}
|
|
42
|
+
if (val != null && typeof val === 'object' && 'id' in val) {
|
|
43
|
+
return wrapNode(val);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return val;
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function wrapEdge(edge) {
|
|
51
|
+
if (edge == null)
|
|
52
|
+
return edge;
|
|
53
|
+
return new Proxy(edge, {
|
|
54
|
+
get(target, prop, receiver) {
|
|
55
|
+
const val = Reflect.get(target, prop, receiver);
|
|
56
|
+
if (prop === 'toNode' || prop === 'fromNode') {
|
|
57
|
+
return wrapNode(val);
|
|
58
|
+
}
|
|
59
|
+
return val;
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function wrapEdgeIterable(iterable) {
|
|
64
|
+
if (iterable == null)
|
|
65
|
+
return iterable;
|
|
66
|
+
const original = iterable;
|
|
67
|
+
return {
|
|
68
|
+
[Symbol.iterator]() {
|
|
69
|
+
const iter = original[Symbol.iterator]();
|
|
70
|
+
return {
|
|
71
|
+
next() {
|
|
72
|
+
const result = iter.next();
|
|
73
|
+
if (result.done)
|
|
74
|
+
return result;
|
|
75
|
+
return { done: false, value: wrapEdge(result.value) };
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function wrapSnapshot(snapshot) {
|
|
82
|
+
return new Proxy(snapshot, {
|
|
83
|
+
get(target, prop, receiver) {
|
|
84
|
+
if (prop === 'getNodeById') {
|
|
85
|
+
const orig = target.getNodeById.bind(target);
|
|
86
|
+
return (id) => wrapNode(orig(id));
|
|
87
|
+
}
|
|
88
|
+
if (prop === 'nodes') {
|
|
89
|
+
const nodes = Reflect.get(target, prop, receiver);
|
|
90
|
+
return new Proxy(nodes, {
|
|
91
|
+
get(nodesTarget, nodesProp, nodesReceiver) {
|
|
92
|
+
if (nodesProp === 'forEach') {
|
|
93
|
+
const origForEach = nodesTarget.forEach.bind(nodesTarget);
|
|
94
|
+
return (cb) => {
|
|
95
|
+
origForEach((node) => cb(wrapNode(node)));
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return Reflect.get(nodesTarget, nodesProp, nodesReceiver);
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return Reflect.get(target, prop, receiver);
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
22
106
|
export function registerEval(server) {
|
|
23
107
|
server.tool('memlab_eval', 'Execute arbitrary JavaScript code against the loaded heap snapshot. ' +
|
|
24
108
|
'The code runs in a sandboxed VM with access to `snapshot` (IHeapSnapshot), ' +
|
|
25
109
|
'`utils` (@memlab/core utils), and `helpers` (plugin utility functions). ' +
|
|
26
110
|
'Assign your result to the `result` variable. ' +
|
|
27
|
-
'No require/process/fs/network access. Read-only heap analysis only
|
|
111
|
+
'No require/process/fs/network access. Read-only heap analysis only.\n\n' +
|
|
112
|
+
'**IHeapNode API:** Each node has: `.id`, `.name`, `.type`, `.self_size`, ' +
|
|
113
|
+
'`.retained_size` (alias: `.retainedSize`), `.edge_count`, `.is_detached`, ' +
|
|
114
|
+
'`.referrer_count` (alias: `.numOfReferrers`), `.isString`, `.hasPathEdge`, ' +
|
|
115
|
+
'`.pathEdge`, `.dominatorNode`, `.location` (script_id/line/column).\n' +
|
|
116
|
+
'**Traversal:** Use `node.references` (outgoing edges, iterable with for-of) and ' +
|
|
117
|
+
'`node.referrers` (incoming edges, iterable with for-of). ' +
|
|
118
|
+
'Each edge has: `.name_or_index`, `.type` (property/element/context/internal/hidden/shortcut), ' +
|
|
119
|
+
'`.toNode`, `.fromNode`.\n' +
|
|
120
|
+
'**Iterating all nodes:** `snapshot.nodes.forEach(node => { ... })` — NOT for-of.\n' +
|
|
121
|
+
'**Get node by ID:** `snapshot.getNodeById(id)` returns IHeapNode or null.\n' +
|
|
122
|
+
'**String values:** `node.toStringNode()?.stringValue` for string nodes.\n\n' +
|
|
123
|
+
'**Example — inspect Map entries:**\n' +
|
|
124
|
+
'```\nconst map = snapshot.getNodeById(12345);\nconst entries = [];\n' +
|
|
125
|
+
'for (const edge of map.references) {\n' +
|
|
126
|
+
' if (edge.name_or_index === "table") {\n' +
|
|
127
|
+
' for (const te of edge.toNode.references) {\n' +
|
|
128
|
+
' entries.push({name: te.toNode.name, type: te.toNode.type});\n' +
|
|
129
|
+
' }\n }\n}\nresult = entries.slice(0, 10);\n```', {
|
|
28
130
|
code: z
|
|
29
131
|
.string()
|
|
30
132
|
.describe('JavaScript code to execute. Must assign the output to a `result` variable. ' +
|
|
31
|
-
'Available globals: snapshot (IHeapSnapshot),
|
|
32
|
-
'aggregateDominatorMetrics, isFiberNode, isDetachedDOMNode
|
|
133
|
+
'Available globals: snapshot (IHeapSnapshot — use .nodes.forEach(), .getNodeById(), .edges.forEach()), ' +
|
|
134
|
+
'utils (@memlab/core utils with aggregateDominatorMetrics, isFiberNode, isDetachedDOMNode), ' +
|
|
33
135
|
'helpers ({ serializeNodeSummary, serializeNodeDetail, formatBytes, formatNumber, ' +
|
|
34
136
|
'markdownTable, isNodeWorthInspecting, filterLargestObjects, queryNodes }), ' +
|
|
35
|
-
'and standard JS built-ins
|
|
137
|
+
'and standard JS built-ins. ' +
|
|
138
|
+
'Node traversal: use node.references (outgoing) and node.referrers (incoming) with for-of. ' +
|
|
139
|
+
'Edge properties: .name_or_index, .type, .toNode, .fromNode.'),
|
|
36
140
|
timeout_ms: z
|
|
37
141
|
.number()
|
|
38
142
|
.optional()
|
|
@@ -59,7 +163,7 @@ export function registerEval(server) {
|
|
|
59
163
|
queryNodes,
|
|
60
164
|
};
|
|
61
165
|
const sandbox = {
|
|
62
|
-
snapshot,
|
|
166
|
+
snapshot: wrapSnapshot(snapshot),
|
|
63
167
|
utils,
|
|
64
168
|
helpers,
|
|
65
169
|
console: capturedConsole,
|
|
@@ -105,7 +209,7 @@ export function registerEval(server) {
|
|
|
105
209
|
const consolePart = truncate(consoleOutput.join('\n'), MAX_OUTPUT_SIZE - output.length > 1024 ? 4096 : 1024);
|
|
106
210
|
output += '\n\n--- console output ---\n' + consolePart;
|
|
107
211
|
}
|
|
108
|
-
return
|
|
212
|
+
return toolResult(output);
|
|
109
213
|
}
|
|
110
214
|
catch (err) {
|
|
111
215
|
if (err instanceof Error &&
|
package/dist/tools/eval.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eval.js","sourceRoot":"","sources":["../../src/tools/eval.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,UAAU,MAAM,cAAc,CAAC;AACtC,MAAM,EAAC,KAAK,EAAC,GAAG,UAAU,CAAC;AAC3B,OAAO,EAAC,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EACL,WAAW,EACX,UAAU,EACV,oBAAoB,EACpB,mBAAmB,EACnB,WAAW,EACX,YAAY,EACZ,aAAa,EACb,qBAAqB,EACrB,oBAAoB,EACpB,UAAU,GACX,MAAM,aAAa,CAAC;AAErB,MAAM,eAAe,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO;AAE1C,SAAS,QAAQ,CAAC,GAAW,EAAE,GAAW;IACxC,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,GAAG,CAAC;IAClC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,yCAAyC,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAiB;IAC5C,MAAM,CAAC,IAAI,CACT,aAAa,EACb,sEAAsE;QACpE,6EAA6E;QAC7E,0EAA0E;QAC1E,+CAA+C;QAC/C,qEAAqE,
|
|
1
|
+
{"version":3,"file":"eval.js","sourceRoot":"","sources":["../../src/tools/eval.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 registerEventListenerLeaks(server: McpServer): void;
|
|
12
|
+
//# sourceMappingURL=event-listener-leaks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-listener-leaks.d.ts","sourceRoot":"","sources":["../../src/tools/event-listener-leaks.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AA0JvE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2LlE"}
|
|
@@ -0,0 +1,266 @@
|
|
|
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, formatNumber, markdownTable, truncateNodeName, errorResult, toolResult, } from '../utils.js';
|
|
13
|
+
const EVENT_PROPERTY_NAMES = new Set([
|
|
14
|
+
'_events',
|
|
15
|
+
'_listeners',
|
|
16
|
+
'eventMap',
|
|
17
|
+
'__events',
|
|
18
|
+
'_eventHandlers',
|
|
19
|
+
'listeners',
|
|
20
|
+
'__listeners',
|
|
21
|
+
]);
|
|
22
|
+
function inspectEventContainer(container) {
|
|
23
|
+
const events = [];
|
|
24
|
+
for (const edge of container.references) {
|
|
25
|
+
const eventName = String(edge.name_or_index);
|
|
26
|
+
if (edge.toNode.type === 'hidden' || edge.toNode.id <= 3)
|
|
27
|
+
continue;
|
|
28
|
+
const listeners = [];
|
|
29
|
+
if (edge.toNode.type === 'object' && edge.toNode.name === 'Array') {
|
|
30
|
+
for (const arrEdge of edge.toNode.references) {
|
|
31
|
+
if (arrEdge.type !== 'element')
|
|
32
|
+
continue;
|
|
33
|
+
const entry = arrEdge.toNode;
|
|
34
|
+
if (entry.id <= 3)
|
|
35
|
+
continue;
|
|
36
|
+
if (entry.type === 'closure') {
|
|
37
|
+
listeners.push({
|
|
38
|
+
callbackId: entry.id,
|
|
39
|
+
callbackName: entry.name,
|
|
40
|
+
contextId: null,
|
|
41
|
+
contextName: null,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
else if (entry.type === 'object') {
|
|
45
|
+
let callbackId = 0;
|
|
46
|
+
let callbackName = '';
|
|
47
|
+
let contextId = null;
|
|
48
|
+
let contextName = null;
|
|
49
|
+
for (const propEdge of entry.references) {
|
|
50
|
+
const pName = String(propEdge.name_or_index);
|
|
51
|
+
if (pName === 'callback' ||
|
|
52
|
+
pName === 'fn' ||
|
|
53
|
+
pName === 'handler' ||
|
|
54
|
+
pName === 'listener') {
|
|
55
|
+
callbackId = propEdge.toNode.id;
|
|
56
|
+
callbackName = propEdge.toNode.name;
|
|
57
|
+
}
|
|
58
|
+
if (pName === 'context' ||
|
|
59
|
+
pName === 'ctx' ||
|
|
60
|
+
pName === 'this' ||
|
|
61
|
+
pName === 'target') {
|
|
62
|
+
contextId = propEdge.toNode.id;
|
|
63
|
+
contextName = propEdge.toNode.name;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (callbackId > 0) {
|
|
67
|
+
listeners.push({
|
|
68
|
+
callbackId,
|
|
69
|
+
callbackName,
|
|
70
|
+
contextId,
|
|
71
|
+
contextName,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (edge.toNode.type === 'closure') {
|
|
78
|
+
listeners.push({
|
|
79
|
+
callbackId: edge.toNode.id,
|
|
80
|
+
callbackName: edge.toNode.name,
|
|
81
|
+
contextId: null,
|
|
82
|
+
contextName: null,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (listeners.length > 0) {
|
|
86
|
+
events.push({ eventName, listeners });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return events;
|
|
90
|
+
}
|
|
91
|
+
function countZombies(listeners, snapshot) {
|
|
92
|
+
let zombies = 0;
|
|
93
|
+
for (const l of listeners) {
|
|
94
|
+
if (l.contextId == null)
|
|
95
|
+
continue;
|
|
96
|
+
const ctxNode = snapshot.getNodeById(l.contextId);
|
|
97
|
+
if (!ctxNode)
|
|
98
|
+
continue;
|
|
99
|
+
if (ctxNode.numOfReferrers <= 2) {
|
|
100
|
+
zombies++;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return zombies;
|
|
104
|
+
}
|
|
105
|
+
function countDuplicateCallbacks(listeners) {
|
|
106
|
+
const callbackContextPairs = new Map();
|
|
107
|
+
for (const l of listeners) {
|
|
108
|
+
const key = `${l.callbackName}\0${l.contextName ?? ''}`;
|
|
109
|
+
callbackContextPairs.set(key, (callbackContextPairs.get(key) ?? 0) + 1);
|
|
110
|
+
}
|
|
111
|
+
let duplicates = 0;
|
|
112
|
+
for (const count of callbackContextPairs.values()) {
|
|
113
|
+
if (count > 1)
|
|
114
|
+
duplicates += count - 1;
|
|
115
|
+
}
|
|
116
|
+
return duplicates;
|
|
117
|
+
}
|
|
118
|
+
export function registerEventListenerLeaks(server) {
|
|
119
|
+
server.tool('memlab_event_listener_leaks', 'Detect EventEmitter-style listener accumulation — the #1 cause of memory leaks in ' +
|
|
120
|
+
'Backbone/Node.js/EventEmitter-based apps. Scans for objects with _events/_listeners ' +
|
|
121
|
+
'properties and flags: arrays with >N entries (accumulation), entries where the ' +
|
|
122
|
+
'context/ctx object has no other referrers (zombie listeners from missed .off() calls), ' +
|
|
123
|
+
'and multiple entries with the same callback but different contexts (mount/unmount leaks). ' +
|
|
124
|
+
'Use after memlab_auto_investigate flags subscription accumulation.', {
|
|
125
|
+
min_listeners: z
|
|
126
|
+
.number()
|
|
127
|
+
.optional()
|
|
128
|
+
.default(50)
|
|
129
|
+
.describe('Minimum total listener count on a single host to report (default 50)'),
|
|
130
|
+
limit: z
|
|
131
|
+
.number()
|
|
132
|
+
.optional()
|
|
133
|
+
.default(15)
|
|
134
|
+
.describe('Maximum number of hosts to return (default 15)'),
|
|
135
|
+
check_zombies: z
|
|
136
|
+
.boolean()
|
|
137
|
+
.optional()
|
|
138
|
+
.default(true)
|
|
139
|
+
.describe('Check for zombie listeners whose context objects have no other referrers (default true). Can be slow on very large snapshots.'),
|
|
140
|
+
}, async ({ min_listeners, limit, check_zombies }) => {
|
|
141
|
+
try {
|
|
142
|
+
const snapshot = getSnapshot();
|
|
143
|
+
const accumulations = [];
|
|
144
|
+
snapshot.nodes.forEach(node => {
|
|
145
|
+
if (node.id <= 3)
|
|
146
|
+
return;
|
|
147
|
+
if (node.type !== 'object')
|
|
148
|
+
return;
|
|
149
|
+
for (const edge of node.references) {
|
|
150
|
+
const eName = String(edge.name_or_index);
|
|
151
|
+
if (!EVENT_PROPERTY_NAMES.has(eName))
|
|
152
|
+
continue;
|
|
153
|
+
if (edge.toNode.id <= 3)
|
|
154
|
+
continue;
|
|
155
|
+
const events = inspectEventContainer(edge.toNode);
|
|
156
|
+
const totalListeners = events.reduce((s, e) => s + e.listeners.length, 0);
|
|
157
|
+
if (totalListeners < min_listeners)
|
|
158
|
+
continue;
|
|
159
|
+
const allListeners = events.flatMap(e => e.listeners);
|
|
160
|
+
const zombieCount = check_zombies
|
|
161
|
+
? countZombies(allListeners, snapshot)
|
|
162
|
+
: 0;
|
|
163
|
+
const duplicateCallbackCount = countDuplicateCallbacks(allListeners);
|
|
164
|
+
const entry = {
|
|
165
|
+
hostNodeId: node.id,
|
|
166
|
+
hostName: node.name,
|
|
167
|
+
hostType: node.type,
|
|
168
|
+
eventPropertyName: eName,
|
|
169
|
+
eventContainerId: edge.toNode.id,
|
|
170
|
+
totalListeners,
|
|
171
|
+
eventBreakdown: events
|
|
172
|
+
.sort((a, b) => b.listeners.length - a.listeners.length)
|
|
173
|
+
.slice(0, 10)
|
|
174
|
+
.map(e => ({
|
|
175
|
+
eventName: e.eventName,
|
|
176
|
+
listenerCount: e.listeners.length,
|
|
177
|
+
sampleListeners: e.listeners.slice(0, 3),
|
|
178
|
+
})),
|
|
179
|
+
zombieCount,
|
|
180
|
+
duplicateCallbackCount,
|
|
181
|
+
totalRetainedSize: node.retainedSize,
|
|
182
|
+
};
|
|
183
|
+
let inserted = false;
|
|
184
|
+
for (let i = 0; i < accumulations.length; i++) {
|
|
185
|
+
if (totalListeners > accumulations[i].totalListeners) {
|
|
186
|
+
accumulations.splice(i, 0, entry);
|
|
187
|
+
inserted = true;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (!inserted)
|
|
192
|
+
accumulations.push(entry);
|
|
193
|
+
if (accumulations.length > limit)
|
|
194
|
+
accumulations.length = limit;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
if (accumulations.length === 0) {
|
|
199
|
+
return toolResult(`No event listener accumulation found with >= ${min_listeners} listeners. ` +
|
|
200
|
+
`Try lowering min_listeners or check \`memlab_find_by_property\` with property_name="_events".`);
|
|
201
|
+
}
|
|
202
|
+
const lines = [
|
|
203
|
+
`## Event Listener Leak Detection`,
|
|
204
|
+
`Found ${accumulations.length} object(s) with potential listener accumulation`,
|
|
205
|
+
'',
|
|
206
|
+
];
|
|
207
|
+
const headers = [
|
|
208
|
+
'Host',
|
|
209
|
+
'Class',
|
|
210
|
+
'Property',
|
|
211
|
+
'Listeners',
|
|
212
|
+
'Zombies',
|
|
213
|
+
'Duplicates',
|
|
214
|
+
'Retained',
|
|
215
|
+
];
|
|
216
|
+
const rightCols = new Set([3, 4, 5, 6]);
|
|
217
|
+
const rows = accumulations.map(a => [
|
|
218
|
+
`@${a.hostNodeId}`,
|
|
219
|
+
truncateNodeName(a.hostName, a.hostType, 0, 30),
|
|
220
|
+
a.eventPropertyName,
|
|
221
|
+
formatNumber(a.totalListeners),
|
|
222
|
+
check_zombies ? formatNumber(a.zombieCount) : '-',
|
|
223
|
+
formatNumber(a.duplicateCallbackCount),
|
|
224
|
+
formatBytes(a.totalRetainedSize),
|
|
225
|
+
]);
|
|
226
|
+
lines.push(markdownTable(headers, rows, rightCols));
|
|
227
|
+
lines.push('');
|
|
228
|
+
for (const a of accumulations.slice(0, 5)) {
|
|
229
|
+
lines.push(`### @${a.hostNodeId} \`${truncateNodeName(a.hostName, a.hostType, 0, 40)}\` — ${formatNumber(a.totalListeners)} listeners`);
|
|
230
|
+
lines.push('');
|
|
231
|
+
if (a.zombieCount > 0) {
|
|
232
|
+
lines.push(`**${formatNumber(a.zombieCount)} zombie listener(s)** — context objects with no other referrers (likely from missing \`.off()\` calls)`);
|
|
233
|
+
lines.push('');
|
|
234
|
+
}
|
|
235
|
+
if (a.duplicateCallbackCount > 0) {
|
|
236
|
+
lines.push(`**${formatNumber(a.duplicateCallbackCount)} duplicate callback(s)** — same callback registered multiple times (classic mount/unmount leak)`);
|
|
237
|
+
lines.push('');
|
|
238
|
+
}
|
|
239
|
+
lines.push('Event breakdown:');
|
|
240
|
+
for (const ev of a.eventBreakdown) {
|
|
241
|
+
lines.push(`- \`${ev.eventName}\`: ${formatNumber(ev.listenerCount)} listener(s)`);
|
|
242
|
+
for (const l of ev.sampleListeners) {
|
|
243
|
+
const ctx = l.contextName
|
|
244
|
+
? `, context: \`${l.contextName}\` @${l.contextId}`
|
|
245
|
+
: '';
|
|
246
|
+
lines.push(` - callback: \`${l.callbackName}\` @${l.callbackId}${ctx}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
lines.push('');
|
|
250
|
+
}
|
|
251
|
+
lines.push('**Suggested next steps:**');
|
|
252
|
+
const top = accumulations[0];
|
|
253
|
+
lines.push(`- Inspect host: \`memlab_object_shape(${top.hostNodeId})\``);
|
|
254
|
+
lines.push(`- Trace retention: \`memlab_retainer_trace(${top.hostNodeId})\``);
|
|
255
|
+
lines.push(`- Inspect event container: \`memlab_get_references(${top.eventContainerId})\``);
|
|
256
|
+
if (top.zombieCount > 0) {
|
|
257
|
+
lines.push(`- Find zombie contexts: use \`memlab_referrer_summary(${top.eventContainerId})\` to identify which context classes dominate`);
|
|
258
|
+
}
|
|
259
|
+
return toolResult(lines.join('\n'));
|
|
260
|
+
}
|
|
261
|
+
catch (err) {
|
|
262
|
+
return errorResult(err);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=event-listener-leaks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-listener-leaks.js","sourceRoot":"","sources":["../../src/tools/event-listener-leaks.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-by-property.d.ts","sourceRoot":"","sources":["../../src/tools/find-by-property.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"find-by-property.d.ts","sourceRoot":"","sources":["../../src/tools/find-by-property.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAavE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA+G9D"}
|