@memlab/mcp-server 2.1.1 → 2.3.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 +73 -3
- package/dist/analysis-budget.d.ts +71 -0
- package/dist/analysis-budget.d.ts.map +1 -0
- package/dist/analysis-budget.js +118 -0
- package/dist/analysis-budget.js.map +1 -0
- package/dist/guardrail.d.ts +24 -0
- package/dist/guardrail.d.ts.map +1 -0
- package/dist/guardrail.js +65 -0
- package/dist/guardrail.js.map +1 -0
- package/dist/heap-state.d.ts +46 -1
- package/dist/heap-state.d.ts.map +1 -1
- package/dist/heap-state.js +142 -10
- package/dist/heap-state.js.map +1 -1
- package/dist/index.js +36 -1
- package/dist/index.js.map +1 -1
- package/dist/tools/array-group-by.d.ts +12 -0
- package/dist/tools/array-group-by.d.ts.map +1 -0
- package/dist/tools/array-group-by.js +191 -0
- package/dist/tools/array-group-by.js.map +1 -0
- package/dist/tools/auto-investigate.d.ts.map +1 -1
- package/dist/tools/auto-investigate.js +999 -37
- package/dist/tools/auto-investigate.js.map +1 -1
- package/dist/tools/cache-analysis.d.ts.map +1 -1
- package/dist/tools/cache-analysis.js +438 -21
- package/dist/tools/cache-analysis.js.map +1 -1
- package/dist/tools/check-health.d.ts.map +1 -1
- package/dist/tools/check-health.js +261 -1
- package/dist/tools/check-health.js.map +1 -1
- package/dist/tools/class-histogram.d.ts.map +1 -1
- package/dist/tools/class-histogram.js +142 -33
- 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 +238 -25
- 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 +25 -3
- package/dist/tools/detached-dom.js.map +1 -1
- package/dist/tools/dev-artifacts.d.ts +33 -0
- package/dist/tools/dev-artifacts.d.ts.map +1 -0
- package/dist/tools/dev-artifacts.js +165 -0
- package/dist/tools/dev-artifacts.js.map +1 -0
- package/dist/tools/diff-snapshots.d.ts.map +1 -1
- package/dist/tools/diff-snapshots.js +113 -18
- package/dist/tools/diff-snapshots.js.map +1 -1
- package/dist/tools/duplicated-strings.d.ts.map +1 -1
- package/dist/tools/duplicated-strings.js +74 -12
- package/dist/tools/duplicated-strings.js.map +1 -1
- package/dist/tools/eval.d.ts.map +1 -1
- package/dist/tools/eval.js +189 -10
- package/dist/tools/eval.js.map +1 -1
- package/dist/tools/event-listener-leaks.d.ts.map +1 -1
- package/dist/tools/event-listener-leaks.js +235 -13
- package/dist/tools/event-listener-leaks.js.map +1 -1
- package/dist/tools/event-registry.d.ts +12 -0
- package/dist/tools/event-registry.d.ts.map +1 -0
- package/dist/tools/event-registry.js +183 -0
- package/dist/tools/event-registry.js.map +1 -0
- package/dist/tools/find-by-property.d.ts.map +1 -1
- package/dist/tools/find-by-property.js +113 -31
- package/dist/tools/find-by-property.js.map +1 -1
- package/dist/tools/find-by-shape.d.ts +12 -0
- package/dist/tools/find-by-shape.d.ts.map +1 -0
- package/dist/tools/find-by-shape.js +178 -0
- package/dist/tools/find-by-shape.js.map +1 -0
- package/dist/tools/find-nodes-by-class.d.ts.map +1 -1
- package/dist/tools/find-nodes-by-class.js +50 -6
- 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 +1 -1
- 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 +6 -0
- package/dist/tools/get-node.js.map +1 -1
- package/dist/tools/get-string.d.ts +12 -0
- package/dist/tools/get-string.d.ts.map +1 -0
- package/dist/tools/get-string.js +223 -0
- package/dist/tools/get-string.js.map +1 -0
- package/dist/tools/get-value.d.ts +12 -0
- package/dist/tools/get-value.d.ts.map +1 -0
- package/dist/tools/get-value.js +152 -0
- package/dist/tools/get-value.js.map +1 -0
- package/dist/tools/global-variables.d.ts.map +1 -1
- package/dist/tools/global-variables.js +54 -34
- package/dist/tools/global-variables.js.map +1 -1
- package/dist/tools/growth-signals.d.ts +12 -0
- package/dist/tools/growth-signals.d.ts.map +1 -0
- package/dist/tools/growth-signals.js +211 -0
- package/dist/tools/growth-signals.js.map +1 -0
- package/dist/tools/intern-opportunities.d.ts +12 -0
- package/dist/tools/intern-opportunities.d.ts.map +1 -0
- package/dist/tools/intern-opportunities.js +289 -0
- package/dist/tools/intern-opportunities.js.map +1 -0
- package/dist/tools/load-snapshot.d.ts +10 -0
- package/dist/tools/load-snapshot.d.ts.map +1 -1
- package/dist/tools/load-snapshot.js +152 -15
- package/dist/tools/load-snapshot.js.map +1 -1
- package/dist/tools/object-cost-breakdown.d.ts +12 -0
- package/dist/tools/object-cost-breakdown.d.ts.map +1 -0
- package/dist/tools/object-cost-breakdown.js +439 -0
- package/dist/tools/object-cost-breakdown.js.map +1 -0
- package/dist/tools/object-shape.d.ts.map +1 -1
- package/dist/tools/object-shape.js +95 -2
- package/dist/tools/object-shape.js.map +1 -1
- package/dist/tools/pinch-points.d.ts.map +1 -1
- package/dist/tools/pinch-points.js +9 -9
- package/dist/tools/pinch-points.js.map +1 -1
- package/dist/tools/property-distribution.d.ts +12 -0
- package/dist/tools/property-distribution.d.ts.map +1 -0
- package/dist/tools/property-distribution.js +168 -0
- package/dist/tools/property-distribution.js.map +1 -0
- package/dist/tools/quick-diagnosis.d.ts.map +1 -1
- package/dist/tools/quick-diagnosis.js +56 -19
- package/dist/tools/quick-diagnosis.js.map +1 -1
- package/dist/tools/retainer-summary.d.ts.map +1 -1
- package/dist/tools/retainer-summary.js +90 -5
- package/dist/tools/retainer-summary.js.map +1 -1
- package/dist/tools/retainer-trace.d.ts.map +1 -1
- package/dist/tools/retainer-trace.js +74 -22
- 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 +10 -3
- package/dist/tools/search-nodes.js.map +1 -1
- package/dist/tools/search-strings.d.ts +12 -0
- package/dist/tools/search-strings.d.ts.map +1 -0
- package/dist/tools/search-strings.js +182 -0
- package/dist/tools/search-strings.js.map +1 -0
- package/dist/tools/sequence-analysis.d.ts +12 -0
- package/dist/tools/sequence-analysis.d.ts.map +1 -0
- package/dist/tools/sequence-analysis.js +234 -0
- package/dist/tools/sequence-analysis.js.map +1 -0
- package/dist/tools/server-status.d.ts +12 -0
- package/dist/tools/server-status.d.ts.map +1 -0
- package/dist/tools/server-status.js +41 -0
- package/dist/tools/server-status.js.map +1 -0
- package/dist/tools/shape-histogram.d.ts.map +1 -1
- package/dist/tools/shape-histogram.js +61 -16
- package/dist/tools/shape-histogram.js.map +1 -1
- package/dist/tools/sliced-strings.d.ts.map +1 -1
- package/dist/tools/sliced-strings.js +16 -11
- package/dist/tools/sliced-strings.js.map +1 -1
- package/dist/tools/snapshot-summary.d.ts.map +1 -1
- package/dist/tools/snapshot-summary.js +55 -13
- package/dist/tools/snapshot-summary.js.map +1 -1
- package/dist/tools/snapshots.d.ts +12 -0
- package/dist/tools/snapshots.d.ts.map +1 -0
- package/dist/tools/snapshots.js +93 -0
- package/dist/tools/snapshots.js.map +1 -0
- package/dist/tools/stale-collections.d.ts.map +1 -1
- package/dist/tools/stale-collections.js +248 -7
- package/dist/tools/stale-collections.js.map +1 -1
- package/dist/tools/trace-dominators.d.ts.map +1 -1
- package/dist/tools/trace-dominators.js +28 -1
- package/dist/tools/trace-dominators.js.map +1 -1
- package/dist/tools/weakmap-entries.d.ts +12 -0
- package/dist/tools/weakmap-entries.d.ts.map +1 -0
- package/dist/tools/weakmap-entries.js +156 -0
- package/dist/tools/weakmap-entries.js.map +1 -0
- package/dist/utils.d.ts +81 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +303 -35
- package/dist/utils.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,234 @@
|
|
|
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 { z } from 'zod';
|
|
12
|
+
import memlabHeapAnalysis from '@memlab/heap-analysis';
|
|
13
|
+
const { getFullHeapFromFile } = memlabHeapAnalysis;
|
|
14
|
+
import { resolveSnapshotPath } from './load-snapshot.js';
|
|
15
|
+
import { formatBytes, formatNumber, markdownTable, errorResult, toolResult, } from '../utils.js';
|
|
16
|
+
// A class key is "<type>::<name>". Value-named string "classes" (literal
|
|
17
|
+
// values used as the name, e.g. "554", "1780525701808.81", "o:10,add") are
|
|
18
|
+
// noise across a sequence — drop them like diff_snapshots does (§10).
|
|
19
|
+
function isNoiseClass(type, name) {
|
|
20
|
+
if (type !== 'string' && type !== 'concatenated string')
|
|
21
|
+
return false;
|
|
22
|
+
if (name.length < 8)
|
|
23
|
+
return true;
|
|
24
|
+
if (/^[\s\d.,:+-]*$/.test(name))
|
|
25
|
+
return true;
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
function buildHistogram(snapshot) {
|
|
29
|
+
const hist = new Map();
|
|
30
|
+
let nodeCount = 0;
|
|
31
|
+
let totalSize = 0;
|
|
32
|
+
snapshot.nodes.forEach(node => {
|
|
33
|
+
nodeCount++;
|
|
34
|
+
totalSize += node.self_size;
|
|
35
|
+
if (node.id <= 3)
|
|
36
|
+
return;
|
|
37
|
+
const key = `${node.type}::${node.name}`;
|
|
38
|
+
const e = hist.get(key);
|
|
39
|
+
if (e) {
|
|
40
|
+
e.count++;
|
|
41
|
+
e.selfSize += node.self_size;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
hist.set(key, { count: 1, selfSize: node.self_size });
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
return { hist, nodeCount, totalSize };
|
|
48
|
+
}
|
|
49
|
+
function classifyTrend(counts) {
|
|
50
|
+
let up = true;
|
|
51
|
+
let down = true;
|
|
52
|
+
for (let i = 1; i < counts.length; i++) {
|
|
53
|
+
if (counts[i] <= counts[i - 1])
|
|
54
|
+
up = false;
|
|
55
|
+
if (counts[i] >= counts[i - 1])
|
|
56
|
+
down = false;
|
|
57
|
+
}
|
|
58
|
+
const net = counts[counts.length - 1] - counts[0];
|
|
59
|
+
if (up && net > 0)
|
|
60
|
+
return 'monotonic-up';
|
|
61
|
+
if (down && net < 0)
|
|
62
|
+
return 'monotonic-down';
|
|
63
|
+
if (net > 0)
|
|
64
|
+
return 'grew-net';
|
|
65
|
+
return 'flat-or-mixed';
|
|
66
|
+
}
|
|
67
|
+
export function registerSequenceAnalysis(server) {
|
|
68
|
+
server.tool('memlab_sequence_analysis', 'Trend analysis across an ORDERED sequence of >=2 heap snapshots (the canonical "is anything growing unboundedly?" tool). Loads each snapshot transiently (does NOT change your active snapshot), builds per-class histograms, and reports each class\'s value at every step plus a growth verdict: "monotonic-up" (grew every step — strongest leak signal) vs "grew-net" (grew overall but not every step — often GC/navigation noise) vs flat/shrank. Also lists classes new since the baseline. Paths may be local, manifold:// URLs, or bare filenames.', {
|
|
69
|
+
paths: z
|
|
70
|
+
.array(z.string())
|
|
71
|
+
.min(2)
|
|
72
|
+
.describe('Ordered list of >=2 snapshot paths (oldest first). Each may be a local absolute path, a manifold:// URL, or a bare snapshot filename.'),
|
|
73
|
+
limit: z
|
|
74
|
+
.number()
|
|
75
|
+
.optional()
|
|
76
|
+
.default(25)
|
|
77
|
+
.describe('Maximum number of growing classes to report (default 25).'),
|
|
78
|
+
min_growth_count: z
|
|
79
|
+
.number()
|
|
80
|
+
.optional()
|
|
81
|
+
.default(50)
|
|
82
|
+
.describe('Only report classes whose net instance-count growth is at least this (default 50).'),
|
|
83
|
+
monotonic_only: z
|
|
84
|
+
.boolean()
|
|
85
|
+
.optional()
|
|
86
|
+
.default(false)
|
|
87
|
+
.describe('Report only classes that grew at EVERY step (default false: include grew-net too, flagged).'),
|
|
88
|
+
max_file_size_mb: z
|
|
89
|
+
.number()
|
|
90
|
+
.optional()
|
|
91
|
+
.default(900)
|
|
92
|
+
.describe('Per-file size ceiling (default 900) to avoid OOM.'),
|
|
93
|
+
}, async ({ paths, limit, min_growth_count, monotonic_only, max_file_size_mb, }) => {
|
|
94
|
+
try {
|
|
95
|
+
const steps = [];
|
|
96
|
+
for (const p of paths) {
|
|
97
|
+
let local;
|
|
98
|
+
let fetchedFrom = null;
|
|
99
|
+
try {
|
|
100
|
+
const r = resolveSnapshotPath(p);
|
|
101
|
+
local = r.localPath;
|
|
102
|
+
fetchedFrom = r.fetchedFrom;
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
return errorResult(new Error(`Failed to resolve "${p}": ${e instanceof Error ? e.message : String(e)}`));
|
|
106
|
+
}
|
|
107
|
+
if (!fs.existsSync(local)) {
|
|
108
|
+
return errorResult(new Error(`File not found: ${local}`));
|
|
109
|
+
}
|
|
110
|
+
const sizeMB = fs.statSync(local).size / (1024 * 1024);
|
|
111
|
+
if (sizeMB > max_file_size_mb) {
|
|
112
|
+
return errorResult(new Error(`${p} is ${sizeMB.toFixed(0)} MB — exceeds max_file_size_mb (${max_file_size_mb}).`));
|
|
113
|
+
}
|
|
114
|
+
// Load sequentially and drop the graph before the next one so only
|
|
115
|
+
// one full graph is resident at a time (memory-safe for big heaps).
|
|
116
|
+
const snapshot = await getFullHeapFromFile(local);
|
|
117
|
+
const { hist, nodeCount, totalSize } = buildHistogram(snapshot);
|
|
118
|
+
steps.push({
|
|
119
|
+
label: fetchedFrom ?? p.replace(/^.*\//, ''),
|
|
120
|
+
hist,
|
|
121
|
+
nodeCount,
|
|
122
|
+
totalSize,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
const n = steps.length;
|
|
126
|
+
const first = steps[0].hist;
|
|
127
|
+
const last = steps[n - 1].hist;
|
|
128
|
+
// Union of non-noise class keys.
|
|
129
|
+
const keys = new Set();
|
|
130
|
+
for (const s of steps) {
|
|
131
|
+
for (const k of s.hist.keys()) {
|
|
132
|
+
const sep = k.indexOf('::');
|
|
133
|
+
const type = k.slice(0, sep);
|
|
134
|
+
const name = k.slice(sep + 2);
|
|
135
|
+
if (!isNoiseClass(type, name))
|
|
136
|
+
keys.add(k);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const rows = [];
|
|
140
|
+
for (const k of keys) {
|
|
141
|
+
const counts = steps.map(s => s.hist.get(k)?.count ?? 0);
|
|
142
|
+
const sizes = steps.map(s => s.hist.get(k)?.selfSize ?? 0);
|
|
143
|
+
const netCount = counts[n - 1] - counts[0];
|
|
144
|
+
const netSize = sizes[n - 1] - sizes[0];
|
|
145
|
+
if (netCount < min_growth_count)
|
|
146
|
+
continue;
|
|
147
|
+
const trend = classifyTrend(counts);
|
|
148
|
+
if (monotonic_only && trend !== 'monotonic-up')
|
|
149
|
+
continue;
|
|
150
|
+
if (trend !== 'monotonic-up' && trend !== 'grew-net')
|
|
151
|
+
continue;
|
|
152
|
+
rows.push({ key: k, counts, netCount, netSize, trend });
|
|
153
|
+
}
|
|
154
|
+
// Monotonic growers first, then by net size delta.
|
|
155
|
+
rows.sort((a, b) => {
|
|
156
|
+
if (a.trend !== b.trend)
|
|
157
|
+
return a.trend === 'monotonic-up' ? -1 : 1;
|
|
158
|
+
return b.netSize - a.netSize;
|
|
159
|
+
});
|
|
160
|
+
const top = rows.slice(0, limit);
|
|
161
|
+
const lines = [
|
|
162
|
+
`## Sequence / Trend Analysis (${n} snapshots)`,
|
|
163
|
+
'',
|
|
164
|
+
];
|
|
165
|
+
// Per-step heap totals.
|
|
166
|
+
const totalHeaders = ['Step', 'Snapshot', 'Nodes', 'Heap (self)'];
|
|
167
|
+
const totalRows = steps.map((s, i) => [
|
|
168
|
+
String(i + 1),
|
|
169
|
+
s.label.length > 40 ? '…' + s.label.slice(-39) : s.label,
|
|
170
|
+
formatNumber(s.nodeCount),
|
|
171
|
+
formatBytes(s.totalSize),
|
|
172
|
+
]);
|
|
173
|
+
lines.push(markdownTable(totalHeaders, totalRows, new Set([2, 3])));
|
|
174
|
+
const heapNet = steps[n - 1].totalSize - steps[0].totalSize;
|
|
175
|
+
lines.push('', `Overall heap self-size ${heapNet >= 0 ? 'grew' : 'shrank'} by ${formatBytes(Math.abs(heapNet))} across the sequence.`, '');
|
|
176
|
+
if (top.length === 0) {
|
|
177
|
+
lines.push(`No classes grew by >= ${formatNumber(min_growth_count)} instances across the sequence. Heap looks flat-to-shrinking — no unbounded-growth signal.`);
|
|
178
|
+
return toolResult(lines.join('\n'));
|
|
179
|
+
}
|
|
180
|
+
lines.push('### Growing classes', '');
|
|
181
|
+
const headers = [
|
|
182
|
+
'Class',
|
|
183
|
+
'Type',
|
|
184
|
+
...steps.map((_, i) => `#${i + 1}`),
|
|
185
|
+
'Δ count',
|
|
186
|
+
'Δ size',
|
|
187
|
+
'Verdict',
|
|
188
|
+
];
|
|
189
|
+
const rightCols = new Set();
|
|
190
|
+
for (let i = 2; i < headers.length - 1; i++)
|
|
191
|
+
rightCols.add(i);
|
|
192
|
+
const tableRows = top.map(r => {
|
|
193
|
+
const sep = r.key.indexOf('::');
|
|
194
|
+
const type = r.key.slice(0, sep);
|
|
195
|
+
const name = r.key.slice(sep + 2);
|
|
196
|
+
const verdict = r.trend === 'monotonic-up'
|
|
197
|
+
? '↑ every step (LEAK signal)'
|
|
198
|
+
: 'grew net (noisy)';
|
|
199
|
+
return [
|
|
200
|
+
name.length > 36 ? name.slice(0, 33) + '…' : name,
|
|
201
|
+
type,
|
|
202
|
+
...r.counts.map(c => formatNumber(c)),
|
|
203
|
+
`+${formatNumber(r.netCount)}`,
|
|
204
|
+
`${r.netSize >= 0 ? '+' : ''}${formatBytes(r.netSize)}`,
|
|
205
|
+
verdict,
|
|
206
|
+
];
|
|
207
|
+
});
|
|
208
|
+
lines.push(markdownTable(headers, tableRows, rightCols));
|
|
209
|
+
// New-since-baseline classes (absent at step 1, present at step N).
|
|
210
|
+
const newClasses = [];
|
|
211
|
+
for (const k of keys) {
|
|
212
|
+
if (!first.has(k) && last.has(k)) {
|
|
213
|
+
const c = last.get(k)?.count ?? 0;
|
|
214
|
+
if (c >= min_growth_count) {
|
|
215
|
+
const sep = k.indexOf('::');
|
|
216
|
+
newClasses.push(`${k.slice(sep + 2)} (${formatNumber(c)})`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (newClasses.length > 0) {
|
|
221
|
+
lines.push('', '### New since baseline', '', newClasses.slice(0, 20).join(', ') +
|
|
222
|
+
(newClasses.length > 20
|
|
223
|
+
? `, … +${newClasses.length - 20} more`
|
|
224
|
+
: ''));
|
|
225
|
+
}
|
|
226
|
+
lines.push('', '_"↑ every step" is the strong unbounded-growth signal; "grew net (noisy)" often reflects GC timing or navigation and warrants a closer look before treating as a leak. Object-identity matching across snapshots is not available (node ids differ per capture) — to localize a specific growing collection, load the last snapshot and use `memlab_cache_analysis` / `memlab_event_listener_leaks` / `memlab_growth_signals`._');
|
|
227
|
+
return toolResult(lines.join('\n'));
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
return errorResult(err);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=sequence-analysis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sequence-analysis.js","sourceRoot":"","sources":["../../src/tools/sequence-analysis.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 registerServerStatus(server: McpServer): void;
|
|
12
|
+
//# sourceMappingURL=server-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-status.d.ts","sourceRoot":"","sources":["../../src/tools/server-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAIvE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsC5D"}
|
|
@@ -0,0 +1,41 @@
|
|
|
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 { listSnapshots, getCurrentHandle } from '../heap-state.js';
|
|
11
|
+
import { formatBytes, formatNumber, errorResult, textResult } from '../utils.js';
|
|
12
|
+
export function registerServerStatus(server) {
|
|
13
|
+
server.tool('memlab_server_status', 'Cheap liveness/health check: returns instantly with the server process RSS, uptime, and the resident snapshots. Use it to confirm the server is responsive (vs. stuck behind a heavy scan) and to watch RSS against the snapshot-size ceiling. Scan tools are time-budgeted (timeout_ms) so a heavy scan returns cleanly instead of wedging the server; if a call ever seems hung, this check should still answer immediately.', {}, async () => {
|
|
14
|
+
try {
|
|
15
|
+
const mem = process.memoryUsage();
|
|
16
|
+
const uptimeS = Math.round(process.uptime());
|
|
17
|
+
const all = listSnapshots();
|
|
18
|
+
const cur = getCurrentHandle();
|
|
19
|
+
const lines = [
|
|
20
|
+
'## memlab server status',
|
|
21
|
+
'',
|
|
22
|
+
`- Status: ready`,
|
|
23
|
+
`- Uptime: ${uptimeS}s`,
|
|
24
|
+
`- Process RSS: ${formatBytes(mem.rss)} (heapUsed ${formatBytes(mem.heapUsed)} / heapTotal ${formatBytes(mem.heapTotal)})`,
|
|
25
|
+
`- Resident snapshots: ${all.length}`,
|
|
26
|
+
];
|
|
27
|
+
for (const m of all) {
|
|
28
|
+
lines.push(` ${m.handle === cur ? '→' : ' '} ${m.handle} — ${m.fileName}, ${formatBytes(m.totalSize)}, ${formatNumber(m.nodeCount)} nodes`);
|
|
29
|
+
}
|
|
30
|
+
if (all.length === 0) {
|
|
31
|
+
lines.push(' (none loaded — use memlab_load_snapshot)');
|
|
32
|
+
}
|
|
33
|
+
lines.push('', '_Tip: full-heap scan tools (search_nodes, find_by_property, global_variables) accept timeout_ms and return partial results rather than hanging. If RSS approaches your --max-old-space-size, unload snapshots with memlab_snapshots(action:"unload")._', '_Recovery: if a prior long/interrupted call left the server unresponsive (even trivial calls hang), starting a FRESH server instance fully recovers it — restart the MCP server and reload the snapshot._');
|
|
34
|
+
return textResult(lines.join('\n'));
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
return errorResult(err);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=server-status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-status.js","sourceRoot":"","sources":["../../src/tools/server-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAC,aAAa,EAAE,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAC,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAC,MAAM,aAAa,CAAC;AAE/E,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,CAAC,IAAI,CACT,sBAAsB,EACtB,gaAAga,EACha,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAC7C,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;YAC5B,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG;gBACZ,yBAAyB;gBACzB,EAAE;gBACF,iBAAiB;gBACjB,aAAa,OAAO,GAAG;gBACvB,kBAAkB,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,cAAc,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,gBAAgB,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG;gBAC1H,yBAAyB,GAAG,CAAC,MAAM,EAAE;aACtC,CAAC;YACF,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;gBACpB,KAAK,CAAC,IAAI,CACR,KAAK,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CACjI,CAAC;YACJ,CAAC;YACD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACrB,KAAK,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;YAC3D,CAAC;YACD,KAAK,CAAC,IAAI,CACR,EAAE,EACF,wPAAwP,EACxP,2MAA2M,CAC5M,CAAC;YACF,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shape-histogram.d.ts","sourceRoot":"","sources":["../../src/tools/shape-histogram.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"shape-histogram.d.ts","sourceRoot":"","sources":["../../src/tools/shape-histogram.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAmCvE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2L9D"}
|
|
@@ -11,7 +11,7 @@ import memlabCore from '@memlab/core';
|
|
|
11
11
|
const { utils, NumericSet } = memlabCore;
|
|
12
12
|
import { z } from 'zod';
|
|
13
13
|
import { getSnapshot } from '../heap-state.js';
|
|
14
|
-
import { formatBytes, formatNumber, errorResult, toolResult } from '../utils.js';
|
|
14
|
+
import { formatBytes, formatNumber, errorResult, toolResult, suggestionsSuppressed, } from '../utils.js';
|
|
15
15
|
function getPropertyNames(node) {
|
|
16
16
|
const names = [];
|
|
17
17
|
for (const edge of node.references) {
|
|
@@ -25,7 +25,8 @@ function getPropertyNames(node) {
|
|
|
25
25
|
return names;
|
|
26
26
|
}
|
|
27
27
|
export function registerShapeHistogram(server) {
|
|
28
|
-
server.tool('memlab_shape_histogram', 'Group objects by their property structure (shape/hidden class). Objects with the same set of property names are grouped together, revealing distinct record types. Much more useful than class_histogram when most objects are generic "Object" — this tells you exactly what data structures exist and how much memory each shape consumes. Essential for data-heavy apps where millions of "Object" instances hide 3-5 distinct record shapes.'
|
|
28
|
+
server.tool('memlab_shape_histogram', 'Group objects by their property structure (shape/hidden class). Objects with the same set of property names are grouped together, revealing distinct record types. Much more useful than class_histogram when most objects are generic "Object" — this tells you exactly what data structures exist and how much memory each shape consumes. Essential for data-heavy apps where millions of "Object" instances hide 3-5 distinct record shapes. ' +
|
|
29
|
+
'By DEFAULT retained size per shape is reported as a cheap RANGE (lower = Σ self size, upper = Σ retained size) from a single O(N) pass; sorting/filtering by retained uses the upper bound. The exact dominator-deduped value needs a per-shape dominator walk that can stall/OOM the server on very large heaps — pass `exact_retained_size:true` ONLY when the user explicitly asks for it.', {
|
|
29
30
|
limit: z
|
|
30
31
|
.number()
|
|
31
32
|
.optional()
|
|
@@ -44,8 +45,24 @@ export function registerShapeHistogram(server) {
|
|
|
44
45
|
.string()
|
|
45
46
|
.optional()
|
|
46
47
|
.describe('Filter to objects with this constructor name (e.g., "Object"). If omitted, includes all object-type nodes.'),
|
|
47
|
-
|
|
48
|
+
sort_by: z
|
|
49
|
+
.enum(['retained_size', 'retained', 'count', 'self_size', 'self'])
|
|
50
|
+
.optional()
|
|
51
|
+
.default('retained_size')
|
|
52
|
+
.describe('Sort order: "retained_size" (default; alias "retained" — uses the upper-bound retained unless exact_retained_size is set), "count" (instance count — find accumulation patterns), or "self_size" (alias "self").'),
|
|
53
|
+
exact_retained_size: z
|
|
54
|
+
.boolean()
|
|
55
|
+
.optional()
|
|
56
|
+
.default(false)
|
|
57
|
+
.describe('Compute the EXACT dominator-deduped retained size per shape via aggregateDominatorMetrics. DEFAULT false: report a retained-size range instead (lower = Σ self size, upper = Σ raw retained) from the O(N) pass; sorting/filtering by retained uses the upper bound. Set true ONLY on explicit user request — the exact walk can be very slow or time out on huge heaps.'),
|
|
58
|
+
}, async ({ limit, min_count, min_retained_size, class_name, sort_by, exact_retained_size, }) => {
|
|
48
59
|
try {
|
|
60
|
+
// Normalize sort aliases so the vocabulary matches other tools.
|
|
61
|
+
const sort = sort_by === 'retained'
|
|
62
|
+
? 'retained_size'
|
|
63
|
+
: sort_by === 'self'
|
|
64
|
+
? 'self_size'
|
|
65
|
+
: sort_by;
|
|
49
66
|
const snapshot = getSnapshot();
|
|
50
67
|
const shapeMap = new Map();
|
|
51
68
|
snapshot.nodes.forEach(node => {
|
|
@@ -63,28 +80,47 @@ export function registerShapeHistogram(server) {
|
|
|
63
80
|
if (existing) {
|
|
64
81
|
existing.count++;
|
|
65
82
|
existing.totalSelfSize += node.self_size;
|
|
66
|
-
existing.
|
|
83
|
+
existing.rawRetained += node.retainedSize;
|
|
84
|
+
if (existing.nodeIds)
|
|
85
|
+
existing.nodeIds.add(node.id);
|
|
67
86
|
}
|
|
68
87
|
else {
|
|
69
88
|
shapeMap.set(key, {
|
|
70
89
|
properties: props,
|
|
71
90
|
count: 1,
|
|
72
91
|
totalSelfSize: node.self_size,
|
|
73
|
-
|
|
92
|
+
rawRetained: node.retainedSize,
|
|
93
|
+
// Per-node ids only needed for the opt-in exact dominator walk.
|
|
94
|
+
nodeIds: exact_retained_size ? new NumericSet([node.id]) : null,
|
|
74
95
|
exampleNodeId: node.id,
|
|
75
96
|
});
|
|
76
97
|
}
|
|
77
98
|
});
|
|
78
99
|
const filtered = [...shapeMap.values()].filter(g => g.count >= min_count);
|
|
100
|
+
// By DEFAULT skip the exact dominator walk (the part that stalls the
|
|
101
|
+
// server on huge heaps) and rank/filter by the upper-bound raw retained
|
|
102
|
+
// sum; only compute exact dominator-deduped retained when asked.
|
|
79
103
|
const withRetained = filtered.map(g => {
|
|
80
|
-
|
|
81
|
-
|
|
104
|
+
let exact = null;
|
|
105
|
+
if (exact_retained_size && g.nodeIds) {
|
|
106
|
+
exact = utils.aggregateDominatorMetrics(g.nodeIds, snapshot, () => true, (node) => node.retainedSize);
|
|
107
|
+
}
|
|
108
|
+
const retainedRank = exact ?? g.rawRetained;
|
|
109
|
+
return { ...g, exact, retainedRank };
|
|
82
110
|
});
|
|
83
111
|
let finalList = withRetained;
|
|
84
112
|
if (min_retained_size != null) {
|
|
85
|
-
finalList = finalList.filter(g => g.
|
|
113
|
+
finalList = finalList.filter(g => g.retainedRank >= min_retained_size);
|
|
114
|
+
}
|
|
115
|
+
if (sort === 'count') {
|
|
116
|
+
finalList.sort((a, b) => b.count - a.count);
|
|
117
|
+
}
|
|
118
|
+
else if (sort === 'self_size') {
|
|
119
|
+
finalList.sort((a, b) => b.totalSelfSize - a.totalSelfSize);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
finalList.sort((a, b) => b.retainedRank - a.retainedRank);
|
|
86
123
|
}
|
|
87
|
-
finalList.sort((a, b) => b.retainedSize - a.retainedSize);
|
|
88
124
|
finalList = finalList.slice(0, limit);
|
|
89
125
|
if (finalList.length === 0) {
|
|
90
126
|
return toolResult('No object shapes found matching the criteria. Try lowering min_count or removing class_name filter.');
|
|
@@ -99,15 +135,24 @@ export function registerShapeHistogram(server) {
|
|
|
99
135
|
const propsDisplay = g.properties.length <= 8
|
|
100
136
|
? `{${g.properties.join(', ')}}`
|
|
101
137
|
: `{${g.properties.slice(0, 6).join(', ')}, … +${g.properties.length - 6} more}`;
|
|
102
|
-
|
|
138
|
+
const retainedStr = exact_retained_size
|
|
139
|
+
? `${formatBytes(g.exact ?? 0)} retained, ${formatBytes(g.totalSelfSize)} self`
|
|
140
|
+
: `retained ∈ [${formatBytes(g.totalSelfSize)}, ≤ ${formatBytes(g.rawRetained)}]`;
|
|
141
|
+
lines.push(`${i + 1}. **${propsDisplay}** — ${formatNumber(g.count)} instances, ${retainedStr}`);
|
|
103
142
|
lines.push(` Example: @${g.exampleNodeId}`);
|
|
104
143
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
144
|
+
if (!exact_retained_size) {
|
|
145
|
+
lines.push('', "_Retained shown as a range `[lower, ≤ upper]`: lower = Σ self size (objects' own bytes), upper = Σ retained size (double-counts subtrees shared between instances on the dominator tree). The exact dominator-deduped value needs a per-shape dominator walk that can stall or time out on large heaps — pass `exact_retained_size:true` for it._");
|
|
146
|
+
}
|
|
147
|
+
if (!suggestionsSuppressed()) {
|
|
148
|
+
lines.push('', '**Suggested next steps:**');
|
|
149
|
+
const top = finalList[0];
|
|
150
|
+
lines.push(`- Inspect example: \`memlab_object_shape(${top.exampleNodeId})\``);
|
|
151
|
+
lines.push(`- Distribution of a property's values: \`memlab_property_distribution\` (cardinality + top values)`);
|
|
152
|
+
lines.push(`- Trace retention: \`memlab_retainer_trace(${top.exampleNodeId})\``);
|
|
153
|
+
if (finalList.length > 1) {
|
|
154
|
+
lines.push(`- Compare shapes: \`memlab_object_shape\` on examples from different shapes`);
|
|
155
|
+
}
|
|
111
156
|
}
|
|
112
157
|
return toolResult(lines.join('\n'));
|
|
113
158
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shape-histogram.js","sourceRoot":"","sources":["../../src/tools/shape-histogram.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,UAAU,MAAM,cAAc,CAAC;AACtC,MAAM,EAAC,KAAK,EAAE,UAAU,EAAC,GAAG,UAAU,CAAC;AACvC,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAC,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAC7C,OAAO,
|
|
1
|
+
{"version":3,"file":"shape-histogram.js","sourceRoot":"","sources":["../../src/tools/shape-histogram.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sliced-strings.d.ts","sourceRoot":"","sources":["../../src/tools/sliced-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"sliced-strings.d.ts","sourceRoot":"","sources":["../../src/tools/sliced-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAqBvE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4I7D"}
|
|
@@ -31,9 +31,12 @@ export function registerSlicedStrings(server) {
|
|
|
31
31
|
// Map from parent node ID -> stats
|
|
32
32
|
const parentMap = new Map();
|
|
33
33
|
snapshot.nodes.forEach(node => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
// V8 represents these as distinct node *types*, not as `string`
|
|
35
|
+
// nodes with a special name. A sliced string shares the backing
|
|
36
|
+
// store of a parent; a concatenated (cons) string references two
|
|
37
|
+
// halves via `first`/`second`.
|
|
38
|
+
const isSliced = node.type === 'sliced string';
|
|
39
|
+
const isConcat = node.type === 'concatenated string';
|
|
37
40
|
if (!isSliced && !isConcat)
|
|
38
41
|
return;
|
|
39
42
|
if (isSliced) {
|
|
@@ -44,17 +47,18 @@ export function registerSlicedStrings(server) {
|
|
|
44
47
|
concatCount++;
|
|
45
48
|
concatTotalSize += node.self_size;
|
|
46
49
|
}
|
|
47
|
-
//
|
|
48
|
-
//
|
|
50
|
+
// Only sliced strings keep a single large parent alive through the
|
|
51
|
+
// `parent` edge. (Cons strings split across two halves and rarely
|
|
52
|
+
// pin one oversized backing buffer, so they're counted but not
|
|
53
|
+
// attributed to a parent here.)
|
|
54
|
+
if (!isSliced)
|
|
55
|
+
return;
|
|
49
56
|
for (const edge of node.references) {
|
|
50
|
-
|
|
51
|
-
if (target.type !== 'string')
|
|
57
|
+
if (String(edge.name_or_index) !== 'parent')
|
|
52
58
|
continue;
|
|
53
|
-
|
|
54
|
-
if (target.
|
|
55
|
-
target.name === 'system / ConsString') {
|
|
59
|
+
const target = edge.toNode;
|
|
60
|
+
if (!target.isString)
|
|
56
61
|
continue;
|
|
57
|
-
}
|
|
58
62
|
const existing = parentMap.get(target.id);
|
|
59
63
|
if (existing) {
|
|
60
64
|
existing.sliced_ref_count++;
|
|
@@ -70,6 +74,7 @@ export function registerSlicedStrings(server) {
|
|
|
70
74
|
sliced_total_size: node.self_size,
|
|
71
75
|
});
|
|
72
76
|
}
|
|
77
|
+
break;
|
|
73
78
|
}
|
|
74
79
|
});
|
|
75
80
|
if (slicedCount === 0 && concatCount === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sliced-strings.js","sourceRoot":"","sources":["../../src/tools/sliced-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAC,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EACL,WAAW,EACX,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,WAAW,
|
|
1
|
+
{"version":3,"file":"sliced-strings.js","sourceRoot":"","sources":["../../src/tools/sliced-strings.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot-summary.d.ts","sourceRoot":"","sources":["../../src/tools/snapshot-summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"snapshot-summary.d.ts","sourceRoot":"","sources":["../../src/tools/snapshot-summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAevE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwL/D"}
|