@memlab/mcp-server 2.18.1 → 2.86.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 +30 -16
- package/bin/.eslintrc.js +26 -0
- package/bin/memlab-cli.js +313 -0
- package/dist/anonymized-snapshot.d.ts +75 -0
- package/dist/anonymized-snapshot.d.ts.map +1 -0
- package/dist/anonymized-snapshot.js +101 -0
- package/dist/anonymized-snapshot.js.map +1 -0
- package/dist/artifact-classes.d.ts +86 -0
- package/dist/artifact-classes.d.ts.map +1 -0
- package/dist/artifact-classes.js +261 -0
- package/dist/artifact-classes.js.map +1 -0
- package/dist/capture-mode.d.ts +60 -0
- package/dist/capture-mode.d.ts.map +1 -0
- package/dist/capture-mode.js +39 -0
- package/dist/capture-mode.js.map +1 -0
- package/dist/eval-hints.d.ts +41 -0
- package/dist/eval-hints.d.ts.map +1 -0
- package/dist/eval-hints.js +115 -0
- package/dist/eval-hints.js.map +1 -0
- package/dist/guardrail.d.ts.map +1 -1
- package/dist/guardrail.js +13 -0
- package/dist/guardrail.js.map +1 -1
- package/dist/heap-budget.d.ts +32 -0
- package/dist/heap-budget.d.ts.map +1 -0
- package/dist/heap-budget.js +90 -0
- package/dist/heap-budget.js.map +1 -0
- package/dist/heap-shapes.d.ts +148 -0
- package/dist/heap-shapes.d.ts.map +1 -0
- package/dist/heap-shapes.js +193 -0
- package/dist/heap-shapes.js.map +1 -0
- package/dist/heap-state.d.ts +109 -2
- package/dist/heap-state.d.ts.map +1 -1
- package/dist/heap-state.js +194 -3
- package/dist/heap-state.js.map +1 -1
- package/dist/index.js +102 -1
- package/dist/index.js.map +1 -1
- package/dist/progress.d.ts +25 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +46 -0
- package/dist/progress.js.map +1 -0
- package/dist/react-shapes.d.ts +42 -0
- package/dist/react-shapes.d.ts.map +1 -0
- package/dist/react-shapes.js +149 -0
- package/dist/react-shapes.js.map +1 -0
- package/dist/result-handles.d.ts +11 -0
- package/dist/result-handles.d.ts.map +1 -0
- package/dist/result-handles.js +77 -0
- package/dist/result-handles.js.map +1 -0
- package/dist/server-version.d.ts +19 -0
- package/dist/server-version.d.ts.map +1 -0
- package/dist/server-version.js +19 -0
- package/dist/server-version.js.map +1 -0
- package/dist/snapshot-borrow.d.ts +67 -0
- package/dist/snapshot-borrow.d.ts.map +1 -0
- package/dist/snapshot-borrow.js +113 -0
- package/dist/snapshot-borrow.js.map +1 -0
- package/dist/string-index.d.ts +55 -0
- package/dist/string-index.d.ts.map +1 -0
- package/dist/string-index.js +99 -0
- package/dist/string-index.js.map +1 -0
- package/dist/tool-registry.d.ts +42 -0
- package/dist/tool-registry.d.ts.map +1 -0
- package/dist/tool-registry.js +20 -0
- package/dist/tool-registry.js.map +1 -0
- package/dist/tools/analyze-run.d.ts +12 -0
- package/dist/tools/analyze-run.d.ts.map +1 -0
- package/dist/tools/analyze-run.js +404 -0
- package/dist/tools/analyze-run.js.map +1 -0
- package/dist/tools/anonymize-snapshot.d.ts +12 -0
- package/dist/tools/anonymize-snapshot.d.ts.map +1 -0
- package/dist/tools/anonymize-snapshot.js +159 -0
- package/dist/tools/anonymize-snapshot.js.map +1 -0
- package/dist/tools/app-config.d.ts +12 -0
- package/dist/tools/app-config.d.ts.map +1 -0
- package/dist/tools/app-config.js +217 -0
- package/dist/tools/app-config.js.map +1 -0
- package/dist/tools/app-heap.d.ts +30 -0
- package/dist/tools/app-heap.d.ts.map +1 -0
- package/dist/tools/app-heap.js +106 -0
- package/dist/tools/app-heap.js.map +1 -0
- package/dist/tools/artifact-budget.d.ts +12 -0
- package/dist/tools/artifact-budget.d.ts.map +1 -0
- package/dist/tools/artifact-budget.js +219 -0
- package/dist/tools/artifact-budget.js.map +1 -0
- package/dist/tools/async-census.d.ts +12 -0
- package/dist/tools/async-census.d.ts.map +1 -0
- package/dist/tools/async-census.js +243 -0
- package/dist/tools/async-census.js.map +1 -0
- package/dist/tools/auto-investigate.d.ts.map +1 -1
- package/dist/tools/auto-investigate.js +54 -5
- package/dist/tools/auto-investigate.js.map +1 -1
- package/dist/tools/batch.d.ts +12 -0
- package/dist/tools/batch.d.ts.map +1 -0
- package/dist/tools/batch.js +196 -0
- package/dist/tools/batch.js.map +1 -0
- package/dist/tools/cache-analysis.d.ts +15 -0
- package/dist/tools/cache-analysis.d.ts.map +1 -1
- package/dist/tools/cache-analysis.js +240 -14
- package/dist/tools/cache-analysis.js.map +1 -1
- package/dist/tools/census-diff.d.ts +55 -0
- package/dist/tools/census-diff.d.ts.map +1 -0
- package/dist/tools/census-diff.js +228 -0
- package/dist/tools/census-diff.js.map +1 -0
- package/dist/tools/chain-walk.d.ts +12 -0
- package/dist/tools/chain-walk.d.ts.map +1 -0
- package/dist/tools/chain-walk.js +184 -0
- package/dist/tools/chain-walk.js.map +1 -0
- package/dist/tools/class-histogram.d.ts.map +1 -1
- package/dist/tools/class-histogram.js +14 -3
- package/dist/tools/class-histogram.js.map +1 -1
- package/dist/tools/collection-diff.d.ts +44 -0
- package/dist/tools/collection-diff.d.ts.map +1 -0
- package/dist/tools/collection-diff.js +343 -0
- package/dist/tools/collection-diff.js.map +1 -0
- package/dist/tools/collection-trend.d.ts +55 -0
- package/dist/tools/collection-trend.d.ts.map +1 -0
- package/dist/tools/collection-trend.js +315 -0
- package/dist/tools/collection-trend.js.map +1 -0
- package/dist/tools/detached-dom.d.ts +5 -0
- package/dist/tools/detached-dom.d.ts.map +1 -1
- package/dist/tools/detached-dom.js +368 -22
- package/dist/tools/detached-dom.js.map +1 -1
- package/dist/tools/dev-artifacts.d.ts +62 -6
- package/dist/tools/dev-artifacts.d.ts.map +1 -1
- package/dist/tools/dev-artifacts.js +685 -24
- package/dist/tools/dev-artifacts.js.map +1 -1
- package/dist/tools/diff-snapshots.d.ts.map +1 -1
- package/dist/tools/diff-snapshots.js +18 -2
- package/dist/tools/diff-snapshots.js.map +1 -1
- package/dist/tools/dom-audit.d.ts +37 -0
- package/dist/tools/dom-audit.d.ts.map +1 -0
- package/dist/tools/dom-audit.js +247 -0
- package/dist/tools/dom-audit.js.map +1 -0
- package/dist/tools/dominator-attribution.d.ts +12 -0
- package/dist/tools/dominator-attribution.d.ts.map +1 -0
- package/dist/tools/dominator-attribution.js +189 -0
- package/dist/tools/dominator-attribution.js.map +1 -0
- package/dist/tools/dominator-chain.d.ts +12 -0
- package/dist/tools/dominator-chain.d.ts.map +1 -0
- package/dist/tools/dominator-chain.js +92 -0
- package/dist/tools/dominator-chain.js.map +1 -0
- package/dist/tools/duplicate-objects.d.ts +12 -0
- package/dist/tools/duplicate-objects.d.ts.map +1 -0
- package/dist/tools/duplicate-objects.js +172 -0
- package/dist/tools/duplicate-objects.js.map +1 -0
- package/dist/tools/duplicated-strings.d.ts.map +1 -1
- package/dist/tools/duplicated-strings.js +49 -40
- package/dist/tools/duplicated-strings.js.map +1 -1
- package/dist/tools/eval-across.d.ts +12 -0
- package/dist/tools/eval-across.d.ts.map +1 -0
- package/dist/tools/eval-across.js +135 -0
- package/dist/tools/eval-across.js.map +1 -0
- package/dist/tools/eval.d.ts +79 -0
- package/dist/tools/eval.d.ts.map +1 -1
- package/dist/tools/eval.js +2523 -197
- 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 +42 -17
- package/dist/tools/event-listener-leaks.js.map +1 -1
- package/dist/tools/event-registry.d.ts.map +1 -1
- package/dist/tools/event-registry.js +42 -8
- package/dist/tools/event-registry.js.map +1 -1
- package/dist/tools/explain-delta.d.ts +12 -0
- package/dist/tools/explain-delta.d.ts.map +1 -0
- package/dist/tools/explain-delta.js +221 -0
- package/dist/tools/explain-delta.js.map +1 -0
- package/dist/tools/find-nodes-by-class.d.ts.map +1 -1
- package/dist/tools/find-nodes-by-class.js +112 -13
- package/dist/tools/find-nodes-by-class.js.map +1 -1
- package/dist/tools/finding-index.d.ts +203 -0
- package/dist/tools/finding-index.d.ts.map +1 -0
- package/dist/tools/finding-index.js +566 -0
- package/dist/tools/finding-index.js.map +1 -0
- package/dist/tools/for-each.d.ts.map +1 -1
- package/dist/tools/for-each.js +15 -3
- package/dist/tools/for-each.js.map +1 -1
- package/dist/tools/get-referrers.d.ts.map +1 -1
- package/dist/tools/get-referrers.js +17 -0
- package/dist/tools/get-referrers.js.map +1 -1
- package/dist/tools/get-value.d.ts +16 -0
- package/dist/tools/get-value.d.ts.map +1 -1
- package/dist/tools/get-value.js +96 -2
- package/dist/tools/get-value.js.map +1 -1
- package/dist/tools/hunt-report.d.ts +12 -0
- package/dist/tools/hunt-report.d.ts.map +1 -0
- package/dist/tools/hunt-report.js +186 -0
- package/dist/tools/hunt-report.js.map +1 -0
- package/dist/tools/hypothesis.d.ts +12 -0
- package/dist/tools/hypothesis.d.ts.map +1 -0
- package/dist/tools/hypothesis.js +280 -0
- package/dist/tools/hypothesis.js.map +1 -0
- package/dist/tools/id-space-audit.d.ts +12 -0
- package/dist/tools/id-space-audit.d.ts.map +1 -0
- package/dist/tools/id-space-audit.js +262 -0
- package/dist/tools/id-space-audit.js.map +1 -0
- package/dist/tools/identify.d.ts +12 -0
- package/dist/tools/identify.d.ts.map +1 -0
- package/dist/tools/identify.js +205 -0
- package/dist/tools/identify.js.map +1 -0
- package/dist/tools/identity-diff.d.ts +12 -0
- package/dist/tools/identity-diff.d.ts.map +1 -0
- package/dist/tools/identity-diff.js +188 -0
- package/dist/tools/identity-diff.js.map +1 -0
- package/dist/tools/intern-opportunities.d.ts.map +1 -1
- package/dist/tools/intern-opportunities.js +116 -50
- package/dist/tools/intern-opportunities.js.map +1 -1
- package/dist/tools/ladder-probe.d.ts +65 -0
- package/dist/tools/ladder-probe.d.ts.map +1 -0
- package/dist/tools/ladder-probe.js +445 -0
- package/dist/tools/ladder-probe.js.map +1 -0
- package/dist/tools/ladder.d.ts +33 -0
- package/dist/tools/ladder.d.ts.map +1 -0
- package/dist/tools/ladder.js +266 -0
- package/dist/tools/ladder.js.map +1 -0
- package/dist/tools/largest-objects.d.ts.map +1 -1
- package/dist/tools/largest-objects.js +6 -2
- package/dist/tools/largest-objects.js.map +1 -1
- package/dist/tools/leak-report.d.ts +35 -0
- package/dist/tools/leak-report.d.ts.map +1 -0
- package/dist/tools/leak-report.js +398 -0
- package/dist/tools/leak-report.js.map +1 -0
- package/dist/tools/load-snapshot.d.ts +29 -0
- package/dist/tools/load-snapshot.d.ts.map +1 -1
- package/dist/tools/load-snapshot.js +294 -23
- package/dist/tools/load-snapshot.js.map +1 -1
- package/dist/tools/map-entries.d.ts +12 -0
- package/dist/tools/map-entries.d.ts.map +1 -0
- package/dist/tools/map-entries.js +139 -0
- package/dist/tools/map-entries.js.map +1 -0
- package/dist/tools/match-object.d.ts +12 -0
- package/dist/tools/match-object.d.ts.map +1 -0
- package/dist/tools/match-object.js +165 -0
- package/dist/tools/match-object.js.map +1 -0
- package/dist/tools/metric.d.ts +13 -0
- package/dist/tools/metric.d.ts.map +1 -0
- package/dist/tools/metric.js +185 -0
- package/dist/tools/metric.js.map +1 -0
- package/dist/tools/module-attribution.d.ts +36 -0
- package/dist/tools/module-attribution.d.ts.map +1 -0
- package/dist/tools/module-attribution.js +235 -0
- package/dist/tools/module-attribution.js.map +1 -0
- package/dist/tools/next-measurement.d.ts +26 -0
- package/dist/tools/next-measurement.d.ts.map +1 -0
- package/dist/tools/next-measurement.js +149 -0
- package/dist/tools/next-measurement.js.map +1 -0
- package/dist/tools/object-cost-breakdown.d.ts.map +1 -1
- package/dist/tools/object-cost-breakdown.js +64 -0
- package/dist/tools/object-cost-breakdown.js.map +1 -1
- package/dist/tools/object-shape.d.ts.map +1 -1
- package/dist/tools/object-shape.js +53 -5
- package/dist/tools/object-shape.js.map +1 -1
- package/dist/tools/population-diff.d.ts +57 -0
- package/dist/tools/population-diff.d.ts.map +1 -0
- package/dist/tools/population-diff.js +338 -0
- package/dist/tools/population-diff.js.map +1 -0
- package/dist/tools/population-vs-owners.d.ts +12 -0
- package/dist/tools/population-vs-owners.d.ts.map +1 -0
- package/dist/tools/population-vs-owners.js +183 -0
- package/dist/tools/population-vs-owners.js.map +1 -0
- package/dist/tools/property-names.d.ts +29 -0
- package/dist/tools/property-names.d.ts.map +1 -0
- package/dist/tools/property-names.js +131 -0
- package/dist/tools/property-names.js.map +1 -0
- package/dist/tools/quick-diagnosis.d.ts.map +1 -1
- package/dist/tools/quick-diagnosis.js +7 -1
- package/dist/tools/quick-diagnosis.js.map +1 -1
- package/dist/tools/react-owners.d.ts +12 -0
- package/dist/tools/react-owners.d.ts.map +1 -0
- package/dist/tools/react-owners.js +167 -0
- package/dist/tools/react-owners.js.map +1 -0
- package/dist/tools/react-update-queues.d.ts +12 -0
- package/dist/tools/react-update-queues.d.ts.map +1 -0
- package/dist/tools/react-update-queues.js +173 -0
- package/dist/tools/react-update-queues.js.map +1 -0
- package/dist/tools/replicate.d.ts +49 -0
- package/dist/tools/replicate.d.ts.map +1 -0
- package/dist/tools/replicate.js +241 -0
- package/dist/tools/replicate.js.map +1 -0
- package/dist/tools/retainer-diff.d.ts +12 -0
- package/dist/tools/retainer-diff.d.ts.map +1 -0
- package/dist/tools/retainer-diff.js +168 -0
- package/dist/tools/retainer-diff.js.map +1 -0
- package/dist/tools/retainer-layers.d.ts +23 -0
- package/dist/tools/retainer-layers.d.ts.map +1 -0
- package/dist/tools/retainer-layers.js +179 -0
- package/dist/tools/retainer-layers.js.map +1 -0
- package/dist/tools/retainer-summary.d.ts +18 -0
- package/dist/tools/retainer-summary.d.ts.map +1 -1
- package/dist/tools/retainer-summary.js +210 -51
- 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 +14 -2
- package/dist/tools/retainer-trace.js.map +1 -1
- package/dist/tools/round-audit.d.ts +66 -0
- package/dist/tools/round-audit.d.ts.map +1 -0
- package/dist/tools/round-audit.js +258 -0
- package/dist/tools/round-audit.js.map +1 -0
- package/dist/tools/round-digest.d.ts +12 -0
- package/dist/tools/round-digest.d.ts.map +1 -0
- package/dist/tools/round-digest.js +190 -0
- package/dist/tools/round-digest.js.map +1 -0
- package/dist/tools/script-census.d.ts +12 -0
- package/dist/tools/script-census.d.ts.map +1 -0
- package/dist/tools/script-census.js +182 -0
- package/dist/tools/script-census.js.map +1 -0
- package/dist/tools/search-nodes.d.ts.map +1 -1
- package/dist/tools/search-nodes.js +5 -1
- package/dist/tools/search-nodes.js.map +1 -1
- package/dist/tools/search-strings.d.ts.map +1 -1
- package/dist/tools/search-strings.js +53 -7
- package/dist/tools/search-strings.js.map +1 -1
- package/dist/tools/sequence-analysis.d.ts +53 -0
- package/dist/tools/sequence-analysis.d.ts.map +1 -1
- package/dist/tools/sequence-analysis.js +313 -89
- package/dist/tools/sequence-analysis.js.map +1 -1
- package/dist/tools/server-status.d.ts.map +1 -1
- package/dist/tools/server-status.js +4 -1
- package/dist/tools/server-status.js.map +1 -1
- package/dist/tools/settle-check.d.ts +12 -0
- package/dist/tools/settle-check.d.ts.map +1 -0
- package/dist/tools/settle-check.js +188 -0
- package/dist/tools/settle-check.js.map +1 -0
- package/dist/tools/shape-histogram.d.ts.map +1 -1
- package/dist/tools/shape-histogram.js +9 -2
- 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 +2 -1
- package/dist/tools/sliced-strings.js.map +1 -1
- package/dist/tools/snapshots.d.ts.map +1 -1
- package/dist/tools/snapshots.js +24 -6
- package/dist/tools/snapshots.js.map +1 -1
- package/dist/tools/sparse-elements.d.ts +12 -0
- package/dist/tools/sparse-elements.d.ts.map +1 -0
- package/dist/tools/sparse-elements.js +215 -0
- package/dist/tools/sparse-elements.js.map +1 -0
- package/dist/tools/stale-collections.d.ts +17 -0
- package/dist/tools/stale-collections.d.ts.map +1 -1
- package/dist/tools/stale-collections.js +28 -0
- package/dist/tools/stale-collections.js.map +1 -1
- package/dist/tools/string-patterns.d.ts.map +1 -1
- package/dist/tools/string-patterns.js +7 -5
- package/dist/tools/string-patterns.js.map +1 -1
- package/dist/tools/tools-index.d.ts +12 -0
- package/dist/tools/tools-index.d.ts.map +1 -0
- package/dist/tools/tools-index.js +492 -0
- package/dist/tools/tools-index.js.map +1 -0
- package/dist/tools/trace-all.d.ts +42 -0
- package/dist/tools/trace-all.d.ts.map +1 -0
- package/dist/tools/trace-all.js +263 -0
- package/dist/tools/trace-all.js.map +1 -0
- package/dist/tools/unit-cost.d.ts +12 -0
- package/dist/tools/unit-cost.d.ts.map +1 -0
- package/dist/tools/unit-cost.js +219 -0
- package/dist/tools/unit-cost.js.map +1 -0
- package/dist/tools/verify-fix.d.ts +23 -0
- package/dist/tools/verify-fix.d.ts.map +1 -0
- package/dist/tools/verify-fix.js +219 -0
- package/dist/tools/verify-fix.js.map +1 -0
- package/dist/tools/weakmap-entries.d.ts.map +1 -1
- package/dist/tools/weakmap-entries.js +6 -1
- package/dist/tools/weakmap-entries.js.map +1 -1
- package/dist/tools/weakref-census.d.ts +15 -0
- package/dist/tools/weakref-census.d.ts.map +1 -0
- package/dist/tools/weakref-census.js +147 -0
- package/dist/tools/weakref-census.js.map +1 -0
- package/dist/tools/what-if.d.ts +12 -0
- package/dist/tools/what-if.d.ts.map +1 -0
- package/dist/tools/what-if.js +285 -0
- package/dist/tools/what-if.js.map +1 -0
- package/dist/utils.d.ts +238 -3
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +507 -15
- package/dist/utils.js.map +1 -1
- package/package.json +7 -6
|
@@ -0,0 +1,182 @@
|
|
|
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 { errorResult, formatBytes, formatNumber, markdownTable, toolResult, } from '../utils.js';
|
|
13
|
+
/**
|
|
14
|
+
* Retained JS SOURCE TEXT — the largest single line item in a browser heap and,
|
|
15
|
+
* until now, the one with no tool.
|
|
16
|
+
*
|
|
17
|
+
* V8 keeps a script's source alive as an external string for as long as any
|
|
18
|
+
* function compiled from it is reachable, so source text is not overhead you can
|
|
19
|
+
* ignore: measured across one 20-round sweep it was 46-60% of the heap in every
|
|
20
|
+
* single round.
|
|
21
|
+
*
|
|
22
|
+
* The finding that motivated this: the two largest strings in one capture were
|
|
23
|
+
* the SAME package set, fetched twice — once at page load and once again
|
|
24
|
+
* mid-session — with both copies retained, for ~74 MB (15% of that heap). No
|
|
25
|
+
* existing tool could see it:
|
|
26
|
+
*
|
|
27
|
+
* - `memlab_duplicated_strings` matches EXACTLY, and the two copies differed
|
|
28
|
+
* by 74 bytes of header, so it reported ~nothing.
|
|
29
|
+
* - `memlab_intern_opportunities` groups by property + parent shape; script
|
|
30
|
+
* source is not a property value.
|
|
31
|
+
* - `memlab_largest_objects` shows the two strings but not that they are the
|
|
32
|
+
* same bundle, because the distinguishing part is a 200-char comment header.
|
|
33
|
+
*
|
|
34
|
+
* So the grouping key here is the PACKAGE LIST parsed out of the header comment,
|
|
35
|
+
* not the bytes. Two builds of the same package set are near-duplicates by
|
|
36
|
+
* construction and byte-equality is the wrong test.
|
|
37
|
+
*/
|
|
38
|
+
// `/*<ts>,,<hash-or-"no">,<ms>,HYP:<pkg-list>*/` — the wrapper Meta's JS
|
|
39
|
+
// packager emits at the top of every served bundle. Parsed defensively: an
|
|
40
|
+
// unrecognised header degrades to "no header", never to a throw.
|
|
41
|
+
const HEADER_RE = /^\/\*(\d+),,([^,]*),(\d+)ms,([^*]*)\*\//;
|
|
42
|
+
function parseHeader(text) {
|
|
43
|
+
const m = HEADER_RE.exec(text);
|
|
44
|
+
if (!m)
|
|
45
|
+
return { timestamp: null, loadMs: null, packageKey: null };
|
|
46
|
+
const [, ts, , ms, tail] = m;
|
|
47
|
+
// The package list is the stable identity of a bundle; the revision hash and
|
|
48
|
+
// the timing in the header are not. Normalise to the sorted set of `pkg:` ids
|
|
49
|
+
// so a re-fetch of the same set groups with the original however the packager
|
|
50
|
+
// ordered or re-hashed it.
|
|
51
|
+
const pkgs = [...tail.matchAll(/pkg:([a-z0-9]+)/gi)].map(x => x[1]);
|
|
52
|
+
const key = pkgs.length > 0
|
|
53
|
+
? [...new Set(pkgs)].sort().join(',')
|
|
54
|
+
: tail.trim().slice(0, 120) || null;
|
|
55
|
+
return { timestamp: ts, loadMs: Number(ms), packageKey: key };
|
|
56
|
+
}
|
|
57
|
+
export function registerScriptCensus(server) {
|
|
58
|
+
server.tool('memlab_script_census', 'Census the retained JS SOURCE TEXT in the heap, and flag the same bundle being retained more than once. ' +
|
|
59
|
+
'Source text is routinely 46-60% of a browser heap — the single largest line item — and no other tool reports it: memlab_duplicated_strings matches byte-exactly (two builds of one bundle differ in their header and do not match), memlab_intern_opportunities only groups property values, and memlab_largest_objects shows the strings without showing that two of them are the same package set. ' +
|
|
60
|
+
'Scripts are grouped by the PACKAGE LIST parsed from the packager header comment, not by bytes, because a re-fetch of the same package set is a near-duplicate by construction. A group with more than one member is a superseded copy still being retained — measured once at ~74 MB, 15% of that heap. ' +
|
|
61
|
+
'Reports total source bytes, share of heap, and reclaimable bytes if superseded copies were released.', {
|
|
62
|
+
limit: z
|
|
63
|
+
.number()
|
|
64
|
+
.optional()
|
|
65
|
+
.default(20)
|
|
66
|
+
.describe('Maximum individual scripts to list (default 20).'),
|
|
67
|
+
min_size: z
|
|
68
|
+
.number()
|
|
69
|
+
.optional()
|
|
70
|
+
.default(65536)
|
|
71
|
+
.describe('Ignore script sources smaller than this many bytes (default 64 KB).'),
|
|
72
|
+
}, async ({ limit, min_size }) => {
|
|
73
|
+
try {
|
|
74
|
+
const snapshot = getSnapshot();
|
|
75
|
+
if (!snapshot) {
|
|
76
|
+
return errorResult('No heap snapshot loaded. Use memlab_load_snapshot first.');
|
|
77
|
+
}
|
|
78
|
+
const scripts = [];
|
|
79
|
+
let totalHeap = 0;
|
|
80
|
+
let totalSource = 0;
|
|
81
|
+
snapshot.nodes.forEach((node) => {
|
|
82
|
+
totalHeap += node.self_size;
|
|
83
|
+
if (node.name !== 'system / ExternalStringData')
|
|
84
|
+
return;
|
|
85
|
+
totalSource += node.self_size;
|
|
86
|
+
if (node.self_size < min_size)
|
|
87
|
+
return;
|
|
88
|
+
// The owning string node carries the text; the ExternalStringData node
|
|
89
|
+
// carries the bytes.
|
|
90
|
+
let text = '';
|
|
91
|
+
for (const edge of node.referrers) {
|
|
92
|
+
const from = edge.fromNode;
|
|
93
|
+
if (from != null && from.isString) {
|
|
94
|
+
text = from.name ?? '';
|
|
95
|
+
if (text.length > 0)
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const h = parseHeader(text);
|
|
100
|
+
scripts.push({
|
|
101
|
+
id: node.id,
|
|
102
|
+
bytes: node.self_size,
|
|
103
|
+
timestamp: h.timestamp,
|
|
104
|
+
loadMs: h.loadMs,
|
|
105
|
+
packageKey: h.packageKey,
|
|
106
|
+
headerPreview: text.slice(0, 96),
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
scripts.sort((a, b) => b.bytes - a.bytes);
|
|
110
|
+
const lines = [
|
|
111
|
+
'## Script source census',
|
|
112
|
+
'',
|
|
113
|
+
`Retained JS source (\`system / ExternalStringData\`): **${formatBytes(totalSource)}**` +
|
|
114
|
+
(totalHeap > 0
|
|
115
|
+
? ` — **${((totalSource / totalHeap) * 100).toFixed(1)}% of the ${formatBytes(totalHeap)} heap**`
|
|
116
|
+
: ''),
|
|
117
|
+
`Scripts at or above ${formatBytes(min_size)}: ${formatNumber(scripts.length)}`,
|
|
118
|
+
'',
|
|
119
|
+
];
|
|
120
|
+
// Duplicate / superseded detection.
|
|
121
|
+
const groups = new Map();
|
|
122
|
+
for (const s of scripts) {
|
|
123
|
+
if (s.packageKey == null)
|
|
124
|
+
continue;
|
|
125
|
+
const g = groups.get(s.packageKey);
|
|
126
|
+
if (g)
|
|
127
|
+
g.push(s);
|
|
128
|
+
else
|
|
129
|
+
groups.set(s.packageKey, [s]);
|
|
130
|
+
}
|
|
131
|
+
const dupGroups = [...groups.values()]
|
|
132
|
+
.filter(g => g.length > 1)
|
|
133
|
+
.sort((a, b) => b.reduce((n, s) => n + s.bytes, 0) -
|
|
134
|
+
a.reduce((n, s) => n + s.bytes, 0));
|
|
135
|
+
let reclaimable = 0;
|
|
136
|
+
for (const g of dupGroups) {
|
|
137
|
+
const sorted = [...g].sort((a, b) => b.bytes - a.bytes);
|
|
138
|
+
// Keep the largest; every other copy of the same package set is a
|
|
139
|
+
// superseded retention.
|
|
140
|
+
for (const s of sorted.slice(1))
|
|
141
|
+
reclaimable += s.bytes;
|
|
142
|
+
}
|
|
143
|
+
if (dupGroups.length > 0) {
|
|
144
|
+
lines.push(`### ⚠ ${formatNumber(dupGroups.length)} package set(s) retained MORE THAN ONCE — **${formatBytes(reclaimable)} reclaimable**`, '');
|
|
145
|
+
for (const g of dupGroups.slice(0, 8)) {
|
|
146
|
+
const sorted = [...g].sort((a, b) => b.bytes - a.bytes);
|
|
147
|
+
lines.push(`**${sorted.length} copies of package set \`${sorted[0].packageKey?.slice(0, 72)}\`** — ${formatBytes(sorted.reduce((n, s) => n + s.bytes, 0))} total:`);
|
|
148
|
+
for (const s of sorted) {
|
|
149
|
+
lines.push(`- \`@${s.id}\` ${formatBytes(s.bytes)}` +
|
|
150
|
+
(s.timestamp != null
|
|
151
|
+
? ` · loaded at ts \`${s.timestamp}\``
|
|
152
|
+
: '') +
|
|
153
|
+
(s.loadMs != null ? ` in ${formatNumber(s.loadMs)}ms` : '') +
|
|
154
|
+
(s.loadMs != null && s.loadMs < 2000
|
|
155
|
+
? ' (warm — a re-fetch)'
|
|
156
|
+
: ''));
|
|
157
|
+
}
|
|
158
|
+
lines.push('');
|
|
159
|
+
}
|
|
160
|
+
lines.push("_Same package set, different load. V8 keeps a script's source alive while any function compiled from it is reachable, so two script objects for one package set cost two full copies. Sizes differing by a few dozen bytes is the normal shape here (a header/revision delta), which is exactly why a byte-exact duplicate scan does not find this._", '');
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
lines.push('_No package set is retained more than once._', '');
|
|
164
|
+
}
|
|
165
|
+
const headers = ['Node', 'Bytes', 'Loaded (ms)', 'Header'];
|
|
166
|
+
lines.push('### Largest retained sources', markdownTable(headers, scripts
|
|
167
|
+
.slice(0, limit)
|
|
168
|
+
.map(s => [
|
|
169
|
+
`@${s.id}`,
|
|
170
|
+
formatBytes(s.bytes),
|
|
171
|
+
s.loadMs != null ? formatNumber(s.loadMs) : '—',
|
|
172
|
+
s.headerPreview.replace(/\|/g, '\\|') || '(no packager header)',
|
|
173
|
+
]), new Set([1, 2])));
|
|
174
|
+
lines.push('', '_Source text is not an application leak and usually cannot be trimmed by application code — but it IS the denominator. Quote the non-source remainder alongside any heap total, or the number misleads._');
|
|
175
|
+
return toolResult(lines.join('\n'));
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
return errorResult(`Failed to census scripts: ${error instanceof Error ? error.message : String(error)}`);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=script-census.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script-census.js","sourceRoot":"","sources":["../../src/tools/script-census.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-nodes.d.ts","sourceRoot":"","sources":["../../src/tools/search-nodes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAavE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"search-nodes.d.ts","sourceRoot":"","sources":["../../src/tools/search-nodes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAavE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwG3D"}
|
|
@@ -55,7 +55,11 @@ export function registerSearchNodes(server) {
|
|
|
55
55
|
.describe('Wall-clock budget for the full-heap scan (default 45000). On very large browser heaps, returns partial results with a note instead of hanging.'),
|
|
56
56
|
}, async ({ name_pattern, type, min_retained_size, min_self_size, is_detached, output_mode, offset, limit, timeout_ms, }) => {
|
|
57
57
|
try {
|
|
58
|
-
|
|
58
|
+
// A retained-size FILTER needs the dominator pass; without it the scan
|
|
59
|
+
// is name/type/self-size only, which a light load fully supports.
|
|
60
|
+
const snapshot = getSnapshot({
|
|
61
|
+
allowLight: min_retained_size == null,
|
|
62
|
+
});
|
|
59
63
|
const nameRegex = name_pattern ? new RegExp(name_pattern, 'i') : null;
|
|
60
64
|
const effectiveLimit = output_mode === 'ids' ? Math.min(limit, 10000) : Math.min(limit, 500);
|
|
61
65
|
const filter = (node) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-nodes.js","sourceRoot":"","sources":["../../src/tools/search-nodes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAC,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EACL,UAAU,EACV,sBAAsB,EACtB,WAAW,EACX,UAAU,EACV,cAAc,GACf,MAAM,aAAa,CAAC;AAGrB,MAAM,UAAU,mBAAmB,CAAC,MAAiB;IACnD,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,iPAAiP;QAC/O,iJAAiJ,EACnJ;QACE,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,2CAA2C,CAAC;QACxD,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,yGAAyG,CAC1G;QACH,iBAAiB,EAAE,CAAC;aACjB,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,gCAAgC,CAAC;QAC7C,aAAa,EAAE,CAAC;aACb,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,sCAAsC,CAAC;QACnD,WAAW,EAAE,CAAC;aACX,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,6BAA6B,CAAC;QAC1C,WAAW,EAAE,CAAC;aACX,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;aAC9B,QAAQ,EAAE;aACV,OAAO,CAAC,MAAM,CAAC;aACf,QAAQ,CACP,8HAA8H,CAC/H;QACH,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,OAAO,CAAC,CAAC,CAAC;aACV,QAAQ,CAAC,2CAA2C,CAAC;QACxD,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CACP,kEAAkE,CACnE;QACH,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,OAAO,CAAC,KAAK,CAAC;aACd,QAAQ,CACP,gJAAgJ,CACjJ;KACJ,EACD,KAAK,EAAE,EACL,YAAY,EACZ,IAAI,EACJ,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,WAAW,EACX,MAAM,EACN,KAAK,EACL,UAAU,GACX,EAAE,EAAE;QACH,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"search-nodes.js","sourceRoot":"","sources":["../../src/tools/search-nodes.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-strings.d.ts","sourceRoot":"","sources":["../../src/tools/search-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAWvE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"search-strings.d.ts","sourceRoot":"","sources":["../../src/tools/search-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAWvE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0Q7D"}
|
|
@@ -8,13 +8,15 @@
|
|
|
8
8
|
* @oncall memory_lab
|
|
9
9
|
*/
|
|
10
10
|
import { z } from 'zod';
|
|
11
|
-
import { getSnapshot } from '../heap-state.js';
|
|
11
|
+
import { getSnapshot, isLightSnapshot } from '../heap-state.js';
|
|
12
12
|
import { formatBytes, formatNumber, markdownTable, errorResult, toolResult, } from '../utils.js';
|
|
13
13
|
export function registerSearchStrings(server) {
|
|
14
14
|
server.tool('memlab_search_strings', 'Search the content (stringValue) of all string nodes in the heap snapshot. ' +
|
|
15
15
|
'Unlike memlab_search_nodes which searches by node name/class, this searches the ' +
|
|
16
16
|
'actual text content of strings. Essential for finding string constants (error messages, ' +
|
|
17
17
|
'event names, config keys, URLs) and tracing them back to their origin. ' +
|
|
18
|
+
'Scope, because the two are easy to confuse: this sees ONLY the values of heap string nodes. ' +
|
|
19
|
+
"Class and constructor names (what memlab_class_histogram and memlab_search_nodes report) live in the snapshot name table and are NOT string nodes, so a class name will not be found here no matter how many instances exist — the result says so and points at the right tool when the pattern matches node names. Sliced strings are also skipped, since they share a parent string's storage. " +
|
|
18
20
|
'Supports exact substring match and regex patterns. ' +
|
|
19
21
|
"⚠ Full-heap scan over every string's content — slow on very large heaps (millions of nodes); use a specific pattern and a small limit.", {
|
|
20
22
|
pattern: z
|
|
@@ -42,7 +44,8 @@ export function registerSearchStrings(server) {
|
|
|
42
44
|
.describe('Show which objects reference each matching string (default true). Disable for faster results when you only need the string values.'),
|
|
43
45
|
}, async ({ pattern, limit, min_length, max_length, show_referrers }) => {
|
|
44
46
|
try {
|
|
45
|
-
const snapshot = getSnapshot();
|
|
47
|
+
const snapshot = getSnapshot({ allowLight: true });
|
|
48
|
+
const light = isLightSnapshot();
|
|
46
49
|
let regex = null;
|
|
47
50
|
let substring = null;
|
|
48
51
|
if (pattern.startsWith('/') && pattern.lastIndexOf('/') > 0) {
|
|
@@ -57,11 +60,37 @@ export function registerSearchStrings(server) {
|
|
|
57
60
|
const matches = [];
|
|
58
61
|
let scannedCount = 0;
|
|
59
62
|
let totalStringNodes = 0;
|
|
63
|
+
// Nodes whose NAME matches the pattern. A class/constructor name (e.g.
|
|
64
|
+
// `ChatstateCollection`) lives in the snapshot's name table, not as a
|
|
65
|
+
// heap string node, so it is invisible to a string-VALUE search: a real
|
|
66
|
+
// investigation saw 226 nodes named `*chatstate*` next to 5 matching
|
|
67
|
+
// string values and read the gap as a parser bug. Counted in the same
|
|
68
|
+
// pass so the cross-check costs nothing, and reported so the caller is
|
|
69
|
+
// pointed at memlab_search_nodes instead of concluding the data is
|
|
70
|
+
// missing.
|
|
71
|
+
let nameMatchCount = 0;
|
|
72
|
+
const nameMatchExamples = [];
|
|
73
|
+
const matchesText = (v) => regex
|
|
74
|
+
? regex.test(v)
|
|
75
|
+
: substring != null
|
|
76
|
+
? v.includes(substring)
|
|
77
|
+
: false;
|
|
60
78
|
snapshot.nodes.forEach(node => {
|
|
61
79
|
if (node.id <= 3)
|
|
62
80
|
return;
|
|
63
|
-
if (!node.isString)
|
|
81
|
+
if (!node.isString) {
|
|
82
|
+
if (matchesText(node.name)) {
|
|
83
|
+
nameMatchCount++;
|
|
84
|
+
if (nameMatchExamples.length < 3) {
|
|
85
|
+
nameMatchExamples.push({
|
|
86
|
+
id: node.id,
|
|
87
|
+
name: node.name,
|
|
88
|
+
type: node.type,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
64
92
|
return;
|
|
93
|
+
}
|
|
65
94
|
totalStringNodes++;
|
|
66
95
|
const strNode = node.toStringNode();
|
|
67
96
|
if (!strNode)
|
|
@@ -81,7 +110,10 @@ export function registerSearchStrings(server) {
|
|
|
81
110
|
}
|
|
82
111
|
if (!isMatch)
|
|
83
112
|
return;
|
|
84
|
-
|
|
113
|
+
// A light load has no retained sizes, so ranking by them would sort
|
|
114
|
+
// every match to a tie and silently return scan order instead of the
|
|
115
|
+
// heaviest strings. Fall back to self size, which is always present.
|
|
116
|
+
const size = light ? node.self_size : node.retainedSize;
|
|
85
117
|
let inserted = false;
|
|
86
118
|
for (let i = 0; i < matches.length; i++) {
|
|
87
119
|
if (size > matches[i].retainedSize) {
|
|
@@ -110,6 +142,11 @@ export function registerSearchStrings(server) {
|
|
|
110
142
|
matches.length = limit;
|
|
111
143
|
});
|
|
112
144
|
const patternDesc = regex ? `regex ${pattern}` : `"${pattern}"`;
|
|
145
|
+
const nameMatchNote = nameMatchCount > 0
|
|
146
|
+
? `\n\n> \u2139\ufe0f **${formatNumber(nameMatchCount)} non-string node(s) also match ${patternDesc} in their NAME** (e.g. ${nameMatchExamples
|
|
147
|
+
.map(e => `@${e.id} \`${e.name.length > 40 ? e.name.slice(0, 37) + '\u2026' : e.name}\` (${e.type})`)
|
|
148
|
+
.join(', ')}). This tool searches string VALUES only; class and constructor names live in the snapshot's name table, not in heap string nodes, so they never appear above. Search those with \`memlab_search_nodes({name_pattern: ...})\` or \`memlab_class_histogram\`.`
|
|
149
|
+
: '';
|
|
113
150
|
if (matches.length === 0) {
|
|
114
151
|
return toolResult(`No strings matching ${patternDesc} found.\n\n` +
|
|
115
152
|
`Scanned ${formatNumber(scannedCount)} of ${formatNumber(totalStringNodes)} string nodes` +
|
|
@@ -119,14 +156,21 @@ export function registerSearchStrings(server) {
|
|
|
119
156
|
'- Use a shorter or less specific pattern\n' +
|
|
120
157
|
'- Use regex for flexible matching: `/partial.*match/i`\n' +
|
|
121
158
|
'- Remove min_length/max_length filters\n' +
|
|
122
|
-
'- Use `memlab_duplicated_strings` if looking for repeated strings'
|
|
159
|
+
'- Use `memlab_duplicated_strings` if looking for repeated strings' +
|
|
160
|
+
nameMatchNote);
|
|
123
161
|
}
|
|
124
162
|
const lines = [
|
|
125
163
|
`## String Content Search`,
|
|
126
164
|
`Found ${formatNumber(matches.length)} string(s) matching ${patternDesc} (scanned ${formatNumber(scannedCount)} of ${formatNumber(totalStringNodes)} string nodes)`,
|
|
127
165
|
'',
|
|
128
166
|
];
|
|
129
|
-
const headers = [
|
|
167
|
+
const headers = [
|
|
168
|
+
'ID',
|
|
169
|
+
'Preview',
|
|
170
|
+
'Length',
|
|
171
|
+
'Self Size',
|
|
172
|
+
light ? 'Retained (n/a)' : 'Retained',
|
|
173
|
+
];
|
|
130
174
|
const rightCols = new Set([2, 3, 4]);
|
|
131
175
|
const rows = matches.map(m => {
|
|
132
176
|
const preview = m.stringValue.length > 80
|
|
@@ -137,7 +181,7 @@ export function registerSearchStrings(server) {
|
|
|
137
181
|
`"${preview.replace(/\n/g, '\\n').replace(/\|/g, '\\|')}"`,
|
|
138
182
|
formatNumber(m.stringValue.length),
|
|
139
183
|
formatBytes(m.selfSize),
|
|
140
|
-
formatBytes(m.retainedSize),
|
|
184
|
+
light ? 'n/a (light)' : formatBytes(m.retainedSize),
|
|
141
185
|
];
|
|
142
186
|
});
|
|
143
187
|
lines.push(markdownTable(headers, rows, rightCols));
|
|
@@ -166,6 +210,8 @@ export function registerSearchStrings(server) {
|
|
|
166
210
|
}
|
|
167
211
|
}
|
|
168
212
|
}
|
|
213
|
+
if (nameMatchNote)
|
|
214
|
+
lines.push(nameMatchNote);
|
|
169
215
|
lines.push('');
|
|
170
216
|
lines.push('**Suggested next steps:**');
|
|
171
217
|
const top = matches[0];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-strings.js","sourceRoot":"","sources":["../../src/tools/search-strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AACtB,OAAO,EAAC,WAAW,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"search-strings.js","sourceRoot":"","sources":["../../src/tools/search-strings.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,5 +8,58 @@
|
|
|
8
8
|
* @oncall memory_lab
|
|
9
9
|
*/
|
|
10
10
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
11
|
+
import type { ProgressReporter } from '../progress.js';
|
|
12
|
+
import { type ArtifactKind } from '../artifact-classes.js';
|
|
13
|
+
interface ClassStats {
|
|
14
|
+
count: number;
|
|
15
|
+
selfSize: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function normalizeClassName(name: string): string;
|
|
18
|
+
type Trend = 'monotonic-up' | 'monotonic-down' | 'grew-net' | 'flat-or-mixed';
|
|
19
|
+
export interface SequenceStep {
|
|
20
|
+
label: string;
|
|
21
|
+
localPath: string;
|
|
22
|
+
hist: Map<string, ClassStats>;
|
|
23
|
+
nodeCount: number;
|
|
24
|
+
totalSize: number;
|
|
25
|
+
}
|
|
26
|
+
export interface SequenceRow {
|
|
27
|
+
key: string;
|
|
28
|
+
type: string;
|
|
29
|
+
name: string;
|
|
30
|
+
counts: number[];
|
|
31
|
+
netCount: number;
|
|
32
|
+
netSize: number;
|
|
33
|
+
trend: Trend;
|
|
34
|
+
artifact: ArtifactKind | null;
|
|
35
|
+
}
|
|
36
|
+
export interface SequenceTrends {
|
|
37
|
+
steps: SequenceStep[];
|
|
38
|
+
rows: SequenceRow[];
|
|
39
|
+
reusedHandles: string[];
|
|
40
|
+
keys: Set<string>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Load an ordered ladder of snapshots and compute per-class growth trends.
|
|
44
|
+
*
|
|
45
|
+
* Extracted from the `memlab_sequence_analysis` handler so it can be composed
|
|
46
|
+
* (see `memlab_leak_report`) instead of re-implemented: the loop that loads each
|
|
47
|
+
* rung, histograms it, and drops the graph before the next is both the expensive
|
|
48
|
+
* part and the part that is easy to get subtly wrong (resolution, size guard,
|
|
49
|
+
* one-graph-resident-at-a-time).
|
|
50
|
+
*
|
|
51
|
+
* Failures THROW rather than returning an MCP error envelope — the callers are
|
|
52
|
+
* tool handlers that already wrap their body in try/catch, and a composed caller
|
|
53
|
+
* needs a failure it cannot accidentally treat as a result.
|
|
54
|
+
*/
|
|
55
|
+
export declare function computeSequenceTrends(paths: string[], opts: {
|
|
56
|
+
minGrowthCount: number;
|
|
57
|
+
monotonicOnly?: boolean;
|
|
58
|
+
maxFileSizeMB?: number;
|
|
59
|
+
light?: boolean;
|
|
60
|
+
toolName?: string;
|
|
61
|
+
progress?: ProgressReporter;
|
|
62
|
+
}): Promise<SequenceTrends>;
|
|
11
63
|
export declare function registerSequenceAnalysis(server: McpServer): void;
|
|
64
|
+
export {};
|
|
12
65
|
//# sourceMappingURL=sequence-analysis.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequence-analysis.d.ts","sourceRoot":"","sources":["../../src/tools/sequence-analysis.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"sequence-analysis.d.ts","sourceRoot":"","sources":["../../src/tools/sequence-analysis.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAwBvE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,gBAAgB,CAAC;AAGrD,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,wBAAwB,CAAC;AAGhC,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAkBD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AA0BD,KAAK,KAAK,GAAG,cAAc,GAAG,gBAAgB,GAAG,UAAU,GAAG,eAAe,CAAC;AAgB9E,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IAGd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,YAAY,EAAE,CAAC;IAItB,IAAI,EAAE,WAAW,EAAE,CAAC;IAGpB,aAAa,EAAE,MAAM,EAAE,CAAC;IAExB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE;IACJ,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IAKvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAIlB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B,GACA,OAAO,CAAC,cAAc,CAAC,CA2IzB;AAkBD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAqUhE"}
|