@memlab/mcp-server 2.18.1 → 2.52.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.
Files changed (186) hide show
  1. package/README.md +8 -14
  2. package/bin/.eslintrc.js +26 -0
  3. package/bin/memlab-cli.js +313 -0
  4. package/dist/artifact-classes.d.ts +86 -0
  5. package/dist/artifact-classes.d.ts.map +1 -0
  6. package/dist/artifact-classes.js +261 -0
  7. package/dist/artifact-classes.js.map +1 -0
  8. package/dist/capture-mode.d.ts +60 -0
  9. package/dist/capture-mode.d.ts.map +1 -0
  10. package/dist/capture-mode.js +39 -0
  11. package/dist/capture-mode.js.map +1 -0
  12. package/dist/guardrail.d.ts.map +1 -1
  13. package/dist/guardrail.js +13 -0
  14. package/dist/guardrail.js.map +1 -1
  15. package/dist/heap-state.d.ts +89 -2
  16. package/dist/heap-state.d.ts.map +1 -1
  17. package/dist/heap-state.js +186 -2
  18. package/dist/heap-state.js.map +1 -1
  19. package/dist/index.js +39 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/progress.d.ts +25 -0
  22. package/dist/progress.d.ts.map +1 -0
  23. package/dist/progress.js +46 -0
  24. package/dist/progress.js.map +1 -0
  25. package/dist/result-handles.d.ts +11 -0
  26. package/dist/result-handles.d.ts.map +1 -0
  27. package/dist/result-handles.js +77 -0
  28. package/dist/result-handles.js.map +1 -0
  29. package/dist/string-index.d.ts +55 -0
  30. package/dist/string-index.d.ts.map +1 -0
  31. package/dist/string-index.js +91 -0
  32. package/dist/string-index.js.map +1 -0
  33. package/dist/tool-registry.d.ts +42 -0
  34. package/dist/tool-registry.d.ts.map +1 -0
  35. package/dist/tool-registry.js +20 -0
  36. package/dist/tool-registry.js.map +1 -0
  37. package/dist/tools/analyze-run.d.ts +12 -0
  38. package/dist/tools/analyze-run.d.ts.map +1 -0
  39. package/dist/tools/analyze-run.js +343 -0
  40. package/dist/tools/analyze-run.js.map +1 -0
  41. package/dist/tools/app-heap.d.ts +12 -0
  42. package/dist/tools/app-heap.d.ts.map +1 -0
  43. package/dist/tools/app-heap.js +140 -0
  44. package/dist/tools/app-heap.js.map +1 -0
  45. package/dist/tools/batch.d.ts +12 -0
  46. package/dist/tools/batch.d.ts.map +1 -0
  47. package/dist/tools/batch.js +168 -0
  48. package/dist/tools/batch.js.map +1 -0
  49. package/dist/tools/cache-analysis.d.ts.map +1 -1
  50. package/dist/tools/cache-analysis.js +156 -5
  51. package/dist/tools/cache-analysis.js.map +1 -1
  52. package/dist/tools/class-histogram.d.ts.map +1 -1
  53. package/dist/tools/class-histogram.js +14 -3
  54. package/dist/tools/class-histogram.js.map +1 -1
  55. package/dist/tools/collection-trend.d.ts +55 -0
  56. package/dist/tools/collection-trend.d.ts.map +1 -0
  57. package/dist/tools/collection-trend.js +315 -0
  58. package/dist/tools/collection-trend.js.map +1 -0
  59. package/dist/tools/detached-dom.d.ts +2 -0
  60. package/dist/tools/detached-dom.d.ts.map +1 -1
  61. package/dist/tools/detached-dom.js +291 -20
  62. package/dist/tools/detached-dom.js.map +1 -1
  63. package/dist/tools/dev-artifacts.d.ts +62 -6
  64. package/dist/tools/dev-artifacts.d.ts.map +1 -1
  65. package/dist/tools/dev-artifacts.js +466 -23
  66. package/dist/tools/dev-artifacts.js.map +1 -1
  67. package/dist/tools/dominator-attribution.d.ts +12 -0
  68. package/dist/tools/dominator-attribution.d.ts.map +1 -0
  69. package/dist/tools/dominator-attribution.js +189 -0
  70. package/dist/tools/dominator-attribution.js.map +1 -0
  71. package/dist/tools/dominator-chain.d.ts +12 -0
  72. package/dist/tools/dominator-chain.d.ts.map +1 -0
  73. package/dist/tools/dominator-chain.js +92 -0
  74. package/dist/tools/dominator-chain.js.map +1 -0
  75. package/dist/tools/duplicate-objects.d.ts +12 -0
  76. package/dist/tools/duplicate-objects.d.ts.map +1 -0
  77. package/dist/tools/duplicate-objects.js +172 -0
  78. package/dist/tools/duplicate-objects.js.map +1 -0
  79. package/dist/tools/duplicated-strings.d.ts.map +1 -1
  80. package/dist/tools/duplicated-strings.js +46 -38
  81. package/dist/tools/duplicated-strings.js.map +1 -1
  82. package/dist/tools/eval.d.ts +1 -0
  83. package/dist/tools/eval.d.ts.map +1 -1
  84. package/dist/tools/eval.js +785 -28
  85. package/dist/tools/eval.js.map +1 -1
  86. package/dist/tools/explain-delta.d.ts +12 -0
  87. package/dist/tools/explain-delta.d.ts.map +1 -0
  88. package/dist/tools/explain-delta.js +170 -0
  89. package/dist/tools/explain-delta.js.map +1 -0
  90. package/dist/tools/find-nodes-by-class.d.ts.map +1 -1
  91. package/dist/tools/find-nodes-by-class.js +112 -13
  92. package/dist/tools/find-nodes-by-class.js.map +1 -1
  93. package/dist/tools/finding-index.d.ts +22 -0
  94. package/dist/tools/finding-index.d.ts.map +1 -0
  95. package/dist/tools/finding-index.js +247 -0
  96. package/dist/tools/finding-index.js.map +1 -0
  97. package/dist/tools/for-each.d.ts.map +1 -1
  98. package/dist/tools/for-each.js +15 -3
  99. package/dist/tools/for-each.js.map +1 -1
  100. package/dist/tools/get-referrers.d.ts.map +1 -1
  101. package/dist/tools/get-referrers.js +17 -0
  102. package/dist/tools/get-referrers.js.map +1 -1
  103. package/dist/tools/hunt-report.d.ts +12 -0
  104. package/dist/tools/hunt-report.d.ts.map +1 -0
  105. package/dist/tools/hunt-report.js +186 -0
  106. package/dist/tools/hunt-report.js.map +1 -0
  107. package/dist/tools/hypothesis.d.ts +12 -0
  108. package/dist/tools/hypothesis.d.ts.map +1 -0
  109. package/dist/tools/hypothesis.js +221 -0
  110. package/dist/tools/hypothesis.js.map +1 -0
  111. package/dist/tools/intern-opportunities.d.ts.map +1 -1
  112. package/dist/tools/intern-opportunities.js +112 -47
  113. package/dist/tools/intern-opportunities.js.map +1 -1
  114. package/dist/tools/ladder.d.ts +33 -0
  115. package/dist/tools/ladder.d.ts.map +1 -0
  116. package/dist/tools/ladder.js +266 -0
  117. package/dist/tools/ladder.js.map +1 -0
  118. package/dist/tools/largest-objects.d.ts.map +1 -1
  119. package/dist/tools/largest-objects.js +6 -2
  120. package/dist/tools/largest-objects.js.map +1 -1
  121. package/dist/tools/leak-report.d.ts +12 -0
  122. package/dist/tools/leak-report.d.ts.map +1 -0
  123. package/dist/tools/leak-report.js +256 -0
  124. package/dist/tools/leak-report.js.map +1 -0
  125. package/dist/tools/load-snapshot.d.ts +18 -0
  126. package/dist/tools/load-snapshot.d.ts.map +1 -1
  127. package/dist/tools/load-snapshot.js +211 -13
  128. package/dist/tools/load-snapshot.js.map +1 -1
  129. package/dist/tools/map-entries.d.ts +12 -0
  130. package/dist/tools/map-entries.d.ts.map +1 -0
  131. package/dist/tools/map-entries.js +139 -0
  132. package/dist/tools/map-entries.js.map +1 -0
  133. package/dist/tools/match-object.d.ts +12 -0
  134. package/dist/tools/match-object.d.ts.map +1 -0
  135. package/dist/tools/match-object.js +165 -0
  136. package/dist/tools/match-object.js.map +1 -0
  137. package/dist/tools/object-shape.d.ts.map +1 -1
  138. package/dist/tools/object-shape.js +53 -5
  139. package/dist/tools/object-shape.js.map +1 -1
  140. package/dist/tools/population-diff.d.ts +57 -0
  141. package/dist/tools/population-diff.d.ts.map +1 -0
  142. package/dist/tools/population-diff.js +338 -0
  143. package/dist/tools/population-diff.js.map +1 -0
  144. package/dist/tools/retainer-layers.d.ts +23 -0
  145. package/dist/tools/retainer-layers.d.ts.map +1 -0
  146. package/dist/tools/retainer-layers.js +179 -0
  147. package/dist/tools/retainer-layers.js.map +1 -0
  148. package/dist/tools/retainer-summary.d.ts +1 -0
  149. package/dist/tools/retainer-summary.d.ts.map +1 -1
  150. package/dist/tools/retainer-summary.js +128 -32
  151. package/dist/tools/retainer-summary.js.map +1 -1
  152. package/dist/tools/retainer-trace.d.ts.map +1 -1
  153. package/dist/tools/retainer-trace.js +4 -2
  154. package/dist/tools/retainer-trace.js.map +1 -1
  155. package/dist/tools/search-nodes.d.ts.map +1 -1
  156. package/dist/tools/search-nodes.js +5 -1
  157. package/dist/tools/search-nodes.js.map +1 -1
  158. package/dist/tools/search-strings.d.ts.map +1 -1
  159. package/dist/tools/search-strings.js +53 -7
  160. package/dist/tools/search-strings.js.map +1 -1
  161. package/dist/tools/sequence-analysis.d.ts +49 -0
  162. package/dist/tools/sequence-analysis.d.ts.map +1 -1
  163. package/dist/tools/sequence-analysis.js +266 -86
  164. package/dist/tools/sequence-analysis.js.map +1 -1
  165. package/dist/tools/shape-histogram.d.ts.map +1 -1
  166. package/dist/tools/shape-histogram.js +9 -2
  167. package/dist/tools/shape-histogram.js.map +1 -1
  168. package/dist/tools/string-patterns.d.ts.map +1 -1
  169. package/dist/tools/string-patterns.js +5 -4
  170. package/dist/tools/string-patterns.js.map +1 -1
  171. package/dist/tools/tools-index.d.ts +12 -0
  172. package/dist/tools/tools-index.d.ts.map +1 -0
  173. package/dist/tools/tools-index.js +342 -0
  174. package/dist/tools/tools-index.js.map +1 -0
  175. package/dist/tools/verify-fix.d.ts +23 -0
  176. package/dist/tools/verify-fix.d.ts.map +1 -0
  177. package/dist/tools/verify-fix.js +211 -0
  178. package/dist/tools/verify-fix.js.map +1 -0
  179. package/dist/tools/weakmap-entries.d.ts.map +1 -1
  180. package/dist/tools/weakmap-entries.js +6 -1
  181. package/dist/tools/weakmap-entries.js.map +1 -1
  182. package/dist/utils.d.ts +146 -1
  183. package/dist/utils.d.ts.map +1 -1
  184. package/dist/utils.js +335 -10
  185. package/dist/utils.js.map +1 -1
  186. package/package.json +5 -4
@@ -0,0 +1,261 @@
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
+ /**
11
+ * V8 internal structures emitted while JIT-compiling and warming up code paths.
12
+ * Exercising NEW interactions during a hunt compiles new functions, so this
13
+ * whole family climbs "every step" without being an app leak.
14
+ *
15
+ * Note what is deliberately NOT here: `PropertyArray`, `DescriptorArray`,
16
+ * `(object elements)`, `(object properties)`, `Context`. Those grow with real
17
+ * application objects and suppressing them would hide genuine leaks.
18
+ */
19
+ const WARMUP_CLASS_NAMES = new Set([
20
+ 'InstructionStream',
21
+ 'Code',
22
+ 'CodeDataContainer',
23
+ 'CodeWrapper',
24
+ 'BytecodeArray',
25
+ 'BytecodeWrapper',
26
+ 'FeedbackVector',
27
+ 'FeedbackMetadata',
28
+ 'FeedbackCell',
29
+ 'ClosureFeedbackCellArray',
30
+ 'ScopeInfo',
31
+ 'SharedFunctionInfo',
32
+ 'SharedFunctionInfoWrapper',
33
+ 'UncompiledDataWithoutPreparseData',
34
+ 'UncompiledDataWithPreparseData',
35
+ 'InterpreterData',
36
+ 'TrustedByteArray',
37
+ 'ProtectedFixedArray',
38
+ 'TrustedWeakFixedArray',
39
+ 'WeakArrayList',
40
+ 'LoadHandler',
41
+ 'StoreHandler',
42
+ 'AllocationSite',
43
+ 'ConstantPool',
44
+ '(constant pool)',
45
+ 'ObjectBoilerplateDescription',
46
+ ]);
47
+ /**
48
+ * Blink accessibility caches, materialized by CDP-driven automation.
49
+ */
50
+ const AX_NAME_RE = /AXObjectCache|AXNodeObject|AXDirtyObject|AXComputedObject|blink::AX/;
51
+ /**
52
+ * The attached inspector's network log. Every request the page makes while CDP
53
+ * is attached is retained by `blink::InspectorNetworkAgent` for the lifetime of
54
+ * the session, so on a dev build that polls (hot reload, long-poll transports)
55
+ * this climbs forever. Retained by the DevToolsSession, not by the app.
56
+ */
57
+ const CDP_NETWORK_NAME_RE = /NetworkResourcesData|XHRReplayData|InspectorNetworkAgent|PerformanceResourceTiming|^URI$/;
58
+ /**
59
+ * The inspector's performance timeline. Long-task/layout-shift/script-timing
60
+ * entries accumulate only because something is observing them.
61
+ */
62
+ const CDP_PERF_NAME_RE = /PerformanceLongTaskTiming|PerformanceLongAnimationFrameTiming|PerformanceScriptTiming|TaskAttributionTiming|ScriptTimingInfo|^LayoutShift$|LayoutShiftAttribution/;
63
+ /**
64
+ * Console message storage held by the inspector. Distinct from
65
+ * `dev_artifacts`' console detection, which works on retainer edges: this
66
+ * catches the native message objects by class name.
67
+ */
68
+ const CDP_CONSOLE_NAME_RE = /ConsoleMessage/;
69
+ /**
70
+ * Captured error stacks. `StackFrameInfo` / `ErrorStackData` balloon when
71
+ * something constructs `Error`s at high frequency — most often React's DEV-only
72
+ * `_debugStack` owner stacks (see the `reactDebugStack` detector in
73
+ * `dev-artifacts`), or dev-build logging that captures a stack per record.
74
+ *
75
+ * Flagged as `stack-capture` rather than asserted dev-only: a production build
76
+ * can legitimately grow these, so the annotation points at the likely cause
77
+ * instead of dismissing the row.
78
+ */
79
+ const STACK_CAPTURE_NAME_RE = /StackFrameInfo|ErrorStackData/;
80
+ const KIND_LABEL = {
81
+ warmup: '⚙ JIT/compile warmup (not a leak)',
82
+ ax: '♿ a11y/CDP cache (automation artifact)',
83
+ 'cdp-network': '🔌 CDP network-inspector retention (artifact)',
84
+ 'cdp-perf': '🔌 CDP performance-timeline retention (artifact)',
85
+ 'cdp-console': '🔌 CDP console retention (artifact)',
86
+ 'stack-capture': '🧵 captured Error stacks (often React DEV _debugStack)',
87
+ };
88
+ const KIND_NOTE = {
89
+ warmup: '⚙️ V8 **compilation-warmup** structures (`Code`, `BytecodeArray`, `FeedbackVector`, `ScopeInfo`, `InstructionStream`, …) are growing. Exercising new code paths during a hunt JIT-compiles them, so they climb every step without being an app leak.',
90
+ ax: '♿ Blink **accessibility caches** (`AXObjectCacheImpl` / `AXNodeObject` / `AXDirtyObject`) are growing. These are inflated by CDP-driven automation building the a11y tree, and they co-retain detached DOM, so retainer traces can route through them and mislead.',
91
+ 'cdp-network': '🔌 The attached inspector is retaining the **network log** (`blink::NetworkResourcesData` / `XHRReplayData` / `PerformanceResourceTiming`). Every request made while CDP is attached is held by `blink::DevToolsSession → InspectorNetworkAgent` for the session, so a dev build that polls (hot reload, long-poll transports) grows this forever. Not app memory.',
92
+ 'cdp-perf': '🔌 The attached inspector is retaining the **performance timeline** (long-task / layout-shift / script-timing entries). These accumulate because something is observing them, not because the app leaks.',
93
+ 'cdp-console': '🔌 The attached inspector is retaining **console messages**. Cross-check with `memlab_dev_artifacts`, which also detects console retention by retainer edge.',
94
+ 'stack-capture': '🧵 **Captured Error stacks** (`StackFrameInfo` / `ErrorStackData`) are growing. The usual cause is React DEV `_debugStack` owner stacks or dev-build logging that captures a stack per record — both dev-build-only. `memlab_dev_artifacts` reports the `React DEV owner stack` category when that is the source.',
95
+ };
96
+ export function artifactLabel(kind) {
97
+ return KIND_LABEL[kind];
98
+ }
99
+ export function artifactNote(kind) {
100
+ return KIND_NOTE[kind];
101
+ }
102
+ /**
103
+ * Content signatures of strings that do NOT ship: the CDP-driven bridge the
104
+ * agent injects to observe the page (browser MCP plugin, browser-tools
105
+ * extension, Puppeteer helpers), and DEV-build-only framework machinery.
106
+ *
107
+ * Why this needs its own classifier, separate from `classifyArtifact`: these are
108
+ * matched on string CONTENT, not on a class name, and they are not reachable
109
+ * from a dev *global*, so neither the class-name registry above nor
110
+ * `dev_artifacts`' root scan sees them.
111
+ *
112
+ * Why it matters: on a measured WA Web round the injected bridge bundle appeared
113
+ * as 64 copies of one 235.6 KB string — 14.7 MB total, the single largest entry
114
+ * in `duplicated_strings` and the single largest "opportunity" in
115
+ * `intern_opportunities`. Interning it would save the application nothing,
116
+ * because none of it ships. Reporting it as a win is worse than not reporting it
117
+ * at all: it sends a fix author after the test rig. The React DEV entries below
118
+ * were the same story a round later: 4,529 `_debugStack` Error stacks, 3.0 MB,
119
+ * none of which exist in a production build.
120
+ *
121
+ * Every pattern here has to be specific enough that application source cannot
122
+ * match it — a false "this doesn't ship" hides a real win, which is the more
123
+ * expensive direction to be wrong in for THIS classifier (the opposite of
124
+ * `classifyArtifact`, where a false artifact hides a real leak).
125
+ */
126
+ const NON_PRODUCTION_STRING_SIGNATURES = [
127
+ {
128
+ // The UMD/CommonJS prologue every bundled bridge is wrapped in. Anchored at
129
+ // the start and required to reach `commonjsGlobal` within the prologue, so
130
+ // ordinary application source strings do not match.
131
+ re: /^\(function\s*\(exports\)\s*\{[\s\S]{0,400}commonjsGlobal/,
132
+ kind: 'harness',
133
+ what: 'injected CommonJS bundle (automation/devtools bridge)',
134
+ },
135
+ {
136
+ re: /^\s*at (?:Object\.)?__PUPPETEER|puppeteer_evaluation_script/,
137
+ kind: 'harness',
138
+ what: 'Puppeteer evaluation frame',
139
+ },
140
+ {
141
+ // react-dom DEV names the frames it inserts into owner stacks
142
+ // `react-stack-top-frame` / `react-stack-bottom-frame`, in hyphenated and
143
+ // underscored spellings depending on the build. BOTH ends must be matched:
144
+ // measured on one 2.5M-node capture, `react-stack-top-frame` appears 56
145
+ // times and `react_stack_bottom_frame` twice, so a bottom-only pattern
146
+ // misses the dominant form and classifies most DEV owner stacks as
147
+ // production. The hyphenated spelling cannot be a JS identifier, so it only
148
+ // ever appears inside a captured stack string.
149
+ re: /react[-_]stack[-_](?:top|bottom)[-_]frame/,
150
+ kind: 'dev-build',
151
+ what: 'React DEV owner stack (_debugStack) — not captured in production',
152
+ },
153
+ {
154
+ // A compiled DEV module's Fast Refresh epilogue. Requires the call form, so
155
+ // a string that merely mentions the identifier does not match.
156
+ re: /\$RefreshReg\$\(|\$RefreshSig\$\(/,
157
+ kind: 'dev-build',
158
+ what: 'React Fast Refresh instrumentation in compiled source (DEV bundle only)',
159
+ },
160
+ ];
161
+ /**
162
+ * Classify a string VALUE as non-production (harness-injected or DEV-build
163
+ * only), or null when it is app content that really does ship.
164
+ */
165
+ export function classifyNonProductionString(value) {
166
+ for (const { re, kind, what } of NON_PRODUCTION_STRING_SIGNATURES) {
167
+ if (re.test(value))
168
+ return { kind, what };
169
+ }
170
+ return null;
171
+ }
172
+ /**
173
+ * Back-compatible wrapper returning just the description. Prefer
174
+ * {@link classifyNonProductionString} when the caller can act on the kind.
175
+ */
176
+ export function classifyHarnessString(value) {
177
+ return classifyNonProductionString(value)?.what ?? null;
178
+ }
179
+ /**
180
+ * React Fast Refresh module-scope registries, by the edge name that binds each
181
+ * one. These live in the refresh runtime's closure and are reachable only
182
+ * through compiled-code constant pools, so a retainer-root scan does not find
183
+ * them and they classify as `production` unless matched by name here. See
184
+ * `tools/dev-artifacts` for the measured cost of missing them.
185
+ */
186
+ export const REACT_REFRESH_REGISTRY_EDGE_NAMES = new Set([
187
+ 'allFamiliesByID',
188
+ 'allFamiliesByType',
189
+ 'allSignaturesByType',
190
+ 'updatedFamiliesByType',
191
+ 'pendingUpdates',
192
+ 'helpersByRendererID',
193
+ 'helpersByRoot',
194
+ 'mountedRoots',
195
+ 'failedRoots',
196
+ 'rootElements',
197
+ ]);
198
+ /**
199
+ * The rarest property of the react-refresh signature record. Callers gate on
200
+ * this before confirming the full shape, so a scan stays one name compare per
201
+ * edge on everything else.
202
+ */
203
+ export const REACT_REFRESH_SIGNATURE_GATE_PROP = 'getCustomHooks';
204
+ const REACT_REFRESH_SIGNATURE_PROPS = [
205
+ 'forceReset',
206
+ 'ownKey',
207
+ 'fullKey',
208
+ 'getCustomHooks',
209
+ ];
210
+ /**
211
+ * Recognize the per-type signature record react-refresh stores via
212
+ * `setSignature(type, key, forceReset, getCustomHooks)` — the value side of
213
+ * `allSignaturesByType`, shaped `{forceReset, ownKey, fullKey, getCustomHooks}`.
214
+ */
215
+ export function isReactRefreshSignatureShape(propNames) {
216
+ const seen = new Set();
217
+ for (const name of propNames) {
218
+ if (REACT_REFRESH_SIGNATURE_PROPS.includes(name))
219
+ seen.add(name);
220
+ if (seen.size === REACT_REFRESH_SIGNATURE_PROPS.length)
221
+ return true;
222
+ }
223
+ return false;
224
+ }
225
+ /**
226
+ * Recognize the parent object SHAPE of an MCP/devtools tool manifest entry.
227
+ *
228
+ * The bridge's tool definitions carry long `.description` strings — one per tool
229
+ * — and a per-load intern pool would happily "save" them. The shape is
230
+ * distinctive enough to match directly, and matching the shape (rather than the
231
+ * description text) keeps app strings that merely have a `description` property
232
+ * out of it.
233
+ */
234
+ export function isHarnessToolManifestShape(propNames) {
235
+ const props = new Set(propNames);
236
+ return (props.has('description') &&
237
+ props.has('inputSchema') &&
238
+ (props.has('call') || props.has('handler')) &&
239
+ props.has('name'));
240
+ }
241
+ /**
242
+ * Classify a class NAME as a known measurement artifact, or null when it is a
243
+ * genuine leak candidate.
244
+ */
245
+ export function classifyArtifact(name) {
246
+ const bare = name.replace(/^system \/ /, '');
247
+ if (WARMUP_CLASS_NAMES.has(bare))
248
+ return 'warmup';
249
+ if (AX_NAME_RE.test(name))
250
+ return 'ax';
251
+ if (CDP_NETWORK_NAME_RE.test(bare))
252
+ return 'cdp-network';
253
+ if (CDP_PERF_NAME_RE.test(bare))
254
+ return 'cdp-perf';
255
+ if (CDP_CONSOLE_NAME_RE.test(bare))
256
+ return 'cdp-console';
257
+ if (STACK_CAPTURE_NAME_RE.test(bare))
258
+ return 'stack-capture';
259
+ return null;
260
+ }
261
+ //# sourceMappingURL=artifact-classes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-classes.js","sourceRoot":"","sources":["../src/artifact-classes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
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 { SnapshotEnv } from './heap-state.js';
11
+ /**
12
+ * Was this snapshot captured with numeric-value capture on?
13
+ *
14
+ * Background: `heap number` is a perennial top grower, and the standing advice
15
+ * was "that is probably a capture artifact — check whether you captured with
16
+ * numeric values on". That advice pushed a decision onto the caller that the
17
+ * caller usually cannot answer (the snapshot may be days old, or captured by
18
+ * someone else), and it rested on a mechanism that was never measured.
19
+ *
20
+ * It was measured for this change, with matched pairs — the same program/page,
21
+ * two snapshots differing ONLY in the `captureNumericValue` CDP flag:
22
+ *
23
+ * - **Node.js** (`inspector` → `HeapProfiler.takeHeapSnapshot`): the flag adds
24
+ * `smi number` nodes and nothing else. Off: 10,100 number nodes, zero of them
25
+ * `smi number`. On: 10,390, of which 290 `smi number`. `heap number` was
26
+ * IDENTICAL at 10,100 in both. Smis are immediate values, not heap objects,
27
+ * so they only become graph nodes when the flag asks V8 to materialize them —
28
+ * which makes their presence a sound detector here.
29
+ * - **Chrome**: no detectable difference at all. On a page holding 20,000
30
+ * objects each with a double and a Smi field, on and off produced the same
31
+ * populations to the node: 40,026 `heap number`, 20,000 `smi number`, 1,063
32
+ * `int`. Chrome emits `smi number` either way, so the Node detector does not
33
+ * transfer, and no other field varies.
34
+ *
35
+ * Neither environment ever encodes the numeric VALUE in the node name (0
36
+ * value-named number nodes across all four snapshots), so name-based detection
37
+ * — the approach a previous round tried and rejected — cannot work in principle.
38
+ *
39
+ * Two consequences, both of which change what the tools should say:
40
+ * 1. For a BROWSER snapshot the question is not merely unanswerable, it is
41
+ * moot: the flag changes nothing, so `heap number` growth in a browser
42
+ * capture is never a numeric-capture artifact and must be investigated as
43
+ * real.
44
+ * 2. The old claim that the mode "emits one node per distinct number and ~3x
45
+ * inflates the graph" is not what was measured in either environment.
46
+ */
47
+ export type NumericCaptureMode = 'on' | 'off' | 'not-applicable' | 'unknown';
48
+ export interface NumericCaptureVerdict {
49
+ mode: NumericCaptureMode;
50
+ /** One sentence stating the answer, for direct inclusion in a tool result. */
51
+ note: string;
52
+ }
53
+ /**
54
+ * @param env which runtime produced the snapshot
55
+ * @param hasSmiNumberNodes whether any `smi number` node is present
56
+ */
57
+ export declare function classifyNumericCapture(env: SnapshotEnv, hasSmiNumberNodes: boolean): NumericCaptureVerdict;
58
+ /** Class-histogram key for the marker node type, as `type::name`. */
59
+ export declare const SMI_NUMBER_CLASS_KEY = "number::smi number";
60
+ //# sourceMappingURL=capture-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture-mode.d.ts","sourceRoot":"","sources":["../src/capture-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,iBAAiB,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,KAAK,GAAG,gBAAgB,GAAG,SAAS,CAAC;AAE7E,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,kBAAkB,CAAC;IACzB,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,WAAW,EAChB,iBAAiB,EAAE,OAAO,GACzB,qBAAqB,CAsBvB;AAED,qEAAqE;AACrE,eAAO,MAAM,oBAAoB,uBAAuB,CAAC"}
@@ -0,0 +1,39 @@
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
+ /**
11
+ * @param env which runtime produced the snapshot
12
+ * @param hasSmiNumberNodes whether any `smi number` node is present
13
+ */
14
+ export function classifyNumericCapture(env, hasSmiNumberNodes) {
15
+ if (env === 'browser') {
16
+ return {
17
+ mode: 'not-applicable',
18
+ note: 'This is a **browser** capture, where `capture_numeric_value` makes no difference to the snapshot: a matched pair taken with the flag on and off produced identical number-node populations (40,026 `heap number` / 20,000 `smi number` in both). So `heap number` growth here is **not** a numeric-capture artifact — treat it as real and trace it with `memlab_retainer_summary` on `heap number`.',
19
+ };
20
+ }
21
+ if (env === 'node') {
22
+ return hasSmiNumberNodes
23
+ ? {
24
+ mode: 'on',
25
+ note: 'This **Node.js** capture was taken with **numeric-value capture ON** — `smi number` nodes are present, and V8 only materializes Smis as graph nodes in that mode. `smi number` growth is therefore a capture artifact. `heap number` is emitted either way (a matched pair had an identical `heap number` count with the flag on and off), so `heap number` growth is still worth investigating.',
26
+ }
27
+ : {
28
+ mode: 'off',
29
+ note: 'This **Node.js** capture was taken with **numeric-value capture OFF** (no `smi number` nodes present). `heap number` nodes are therefore ordinary boxed doubles that V8 allocates anyway — this growth may be real, so investigate it rather than dismissing it.',
30
+ };
31
+ }
32
+ return {
33
+ mode: 'unknown',
34
+ note: 'The runtime that produced this snapshot could not be identified, so the numeric-capture mode cannot be stated. In browser captures the flag makes no difference; in Node.js captures it adds `smi number` nodes.',
35
+ };
36
+ }
37
+ /** Class-histogram key for the marker node type, as `type::name`. */
38
+ export const SMI_NUMBER_CLASS_KEY = 'number::smi number';
39
+ //# sourceMappingURL=capture-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture-mode.js","sourceRoot":"","sources":["../src/capture-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgDH;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,GAAgB,EAChB,iBAA0B;IAE1B,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO;YACL,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,sYAAsY;SAC7Y,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,OAAO,iBAAiB;YACtB,CAAC,CAAC;gBACE,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE,kYAAkY;aACzY;YACH,CAAC,CAAC;gBACE,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE,kQAAkQ;aACzQ,CAAC;IACR,CAAC;IACD,OAAO;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,kNAAkN;KACzN,CAAC;AACJ,CAAC;AAED,qEAAqE;AACrE,MAAM,CAAC,MAAM,oBAAoB,GAAG,oBAAoB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"guardrail.d.ts","sourceRoot":"","sources":["../src/guardrail.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAYvE;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2ChE"}
1
+ {"version":3,"file":"guardrail.d.ts","sourceRoot":"","sources":["../src/guardrail.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAavE;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwDhE"}
package/dist/guardrail.js CHANGED
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import { beginAnalysisBudget, endAnalysisBudget, getAnalysisTimeoutMs, activeElapsedMs, ScanTimeoutError, } from './analysis-budget.js';
11
11
  import { toolResult } from './utils.js';
12
+ import { recordToolHandler } from './tool-registry.js';
12
13
  /**
13
14
  * Install a process-wide wall-clock guardrail around every tool call.
14
15
  *
@@ -29,6 +30,18 @@ export function installAnalysisGuardrail(server) {
29
30
  const handler = toolArgs[lastIdx];
30
31
  if (typeof handler === 'function') {
31
32
  const inner = handler;
33
+ // Index the raw handler plus its zod shape so tools can dispatch to each
34
+ // other in-process without re-entering the budget, and without losing the
35
+ // schema defaults the SDK would normally apply (see tool-registry.ts).
36
+ // Registration is tool(name, description?, shape?, handler): the shape is
37
+ // whatever plain object sits immediately before the handler.
38
+ const maybeShape = lastIdx > 0 ? toolArgs[lastIdx - 1] : undefined;
39
+ const shape = maybeShape != null &&
40
+ typeof maybeShape === 'object' &&
41
+ !Array.isArray(maybeShape)
42
+ ? maybeShape
43
+ : null;
44
+ recordToolHandler(name, inner, shape);
32
45
  toolArgs[lastIdx] = async (...hArgs) => {
33
46
  // The SDK calls handler(args, extra) for schema tools, handler(extra)
34
47
  // otherwise. Read an optional per-call timeout_ms off the params.
@@ -1 +1 @@
1
- {"version":3,"file":"guardrail.js","sourceRoot":"","sources":["../src/guardrail.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAC,UAAU,EAAC,MAAM,YAAY,CAAC;AAItC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,MAAM,QAAQ,GAAI,MAAM,CAAC,IAAc,CAAC,IAAI,CAAC,MAAM,CAAU,CAAC;IAC7D,MAAmC,CAAC,IAAI,GAAG,CAAC,GAAG,QAAmB,EAAE,EAAE;QACrE,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,OAAgB,CAAC;YAC/B,QAAQ,CAAC,OAAO,CAAC,GAAG,KAAK,EAAE,GAAG,KAAgB,EAAE,EAAE;gBAChD,sEAAsE;gBACtE,kEAAkE;gBAClE,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACxB,MAAM,QAAQ,GACZ,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,YAAY,IAAI,MAAM;oBAC5D,CAAC,CAAE,MAAiC,CAAC,UAAU;oBAC/C,CAAC,CAAC,SAAS,CAAC;gBAChB,MAAM,SAAS,GAAG,oBAAoB,CACpC,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CACpD,CAAC;gBACF,mBAAmB,CAAC,SAAS,CAAC,CAAC;gBAC/B,IAAI,CAAC;oBACH,OAAO,MAAM,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC;gBAC/B,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,IAAI,CAAC,YAAY,gBAAgB,EAAE,CAAC;wBAClC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,GAAG,IAAI,CAAC,CAAC;wBACjD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;wBAC3C,OAAO,UAAU,CACf,yBAAyB,IAAI,mBAAmB,KAAK,qBAAqB,GAAG,2FAA2F;4BACtK,uDAAuD;4BACvD,8GAA8G;4BAC9G,8GAA8G;4BAC9G,2JAA2J;4BAC3J,wIAAwI,KAAK,uBAAuB,CACvK,CAAC;oBACJ,CAAC;oBACD,MAAM,CAAC,CAAC;gBACV,CAAC;wBAAS,CAAC;oBACT,iBAAiB,EAAE,CAAC;gBACtB,CAAC;YACH,CAAC,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC;IAC/B,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"guardrail.js","sourceRoot":"","sources":["../src/guardrail.ts"],"names":[],"mappings":"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"}
@@ -22,7 +22,30 @@ export interface SnapshotMetadata {
22
22
  edgeCount: number;
23
23
  totalSize: number;
24
24
  env: SnapshotEnv;
25
+ /**
26
+ * True when the snapshot was parsed WITHOUT memlab's path/dominator pass
27
+ * (`memlab_load_snapshot({light: true})`). Roughly halves load time, at the
28
+ * cost of `retainedSize`, `dominatorNode` and `pathEdge` being absent — see
29
+ * {@link getSnapshot}.
30
+ */
31
+ light: boolean;
25
32
  }
33
+ /**
34
+ * Drop the least-recently-used resident snapshot, never the current one.
35
+ * Returns its metadata, or null when there is nothing else to evict.
36
+ *
37
+ * Used by the loader's memory-headroom guard: with `keep_previous`, several
38
+ * full graphs stay resident, and the load that tips the process over is the one
39
+ * that dies — taking every resident snapshot with it. Evicting the coldest one
40
+ * first turns an OOM crash into a slower session.
41
+ */
42
+ export declare function evictLeastRecentlyUsed(): SnapshotMetadata | null;
43
+ /**
44
+ * Returns the mutable scratch object for the current snapshot, creating it on
45
+ * first use. Node ids and any derived index are only valid for the snapshot they
46
+ * were built from, so the scratch is keyed to the active handle.
47
+ */
48
+ export declare function getEvalScratch(): Record<string, unknown>;
26
49
  /**
27
50
  * Session-level output controls to trim repeated boilerplate tokens.
28
51
  * - `quietHeader`: when true, the per-call snapshot header is printed only
@@ -42,7 +65,52 @@ export declare function setSessionConfig(patch: Partial<SessionConfig>): Session
42
65
  * whether to prepend the snapshot header.
43
66
  */
44
67
  export declare function shouldEmitHeader(): boolean;
45
- export declare function getSnapshot(): IHeapSnapshot;
68
+ export declare function shouldEmitNote(key: string): boolean;
69
+ /** True if `key` has already been emitted, without marking it. */
70
+ export declare function noteAlreadyEmitted(key: string): boolean;
71
+ /** Force the standing notes to print again (used by `repeat_notes`). */
72
+ export declare function resetEmittedNotes(): void;
73
+ /**
74
+ * Named results saved from `memlab_eval` (`save_as` / `helpers.save`).
75
+ *
76
+ * SESSION-scoped, deliberately not snapshot-scoped. Comparing a baseline scan
77
+ * against a final scan is the central job of a leak hunt, and the previous
78
+ * per-snapshot scratch dropped the baseline the moment the next rung was loaded
79
+ * — i.e. exactly when it became useful. The handle each value was saved against
80
+ * is recorded alongside it, because node ids are per-capture: `helpers.load`
81
+ * refuses a cross-snapshot read unless the caller says the value is portable.
82
+ */
83
+ interface SavedResult {
84
+ value: unknown;
85
+ handle: string;
86
+ }
87
+ export declare function setSavedResult(name: string, value: unknown, handle: string): void;
88
+ export declare function getSavedResult(name: string): SavedResult | undefined;
89
+ export declare function listSavedResults(): Array<{
90
+ name: string;
91
+ handle: string;
92
+ }>;
93
+ /**
94
+ * The current snapshot.
95
+ *
96
+ * A LIGHT snapshot (loaded with `light: true`) has no dominator tree, no
97
+ * retained sizes and no shortest-path edges. On such a snapshot `retainedSize`
98
+ * reads 0 and `dominatorNode` / `pathEdge` are absent — which does not throw, it
99
+ * silently produces zeros and empty traces. A tool that reported those as
100
+ * results would be confidently wrong, which is worse than refusing.
101
+ *
102
+ * So light access is DENY-BY-DEFAULT and must be opted into per call site with
103
+ * `{allowLight: true}`, by tools that read only counts, names, types, self
104
+ * sizes, string values or edges. Enforcing it here rather than in the tool
105
+ * wrapper is deliberate: this is the one funnel every tool goes through,
106
+ * including tools dispatched in-process by `memlab_batch`, which bypass the
107
+ * guardrail wrapper entirely.
108
+ */
109
+ export declare function getSnapshot(opts?: {
110
+ allowLight?: boolean;
111
+ }): IHeapSnapshot;
112
+ /** True when the current snapshot was loaded without the dominator pass. */
113
+ export declare function isLightSnapshot(): boolean;
46
114
  export declare function getFilePath(): string | null;
47
115
  export declare function getSnapshotEnv(): SnapshotEnv;
48
116
  export declare function getSnapshotMetadata(): SnapshotMetadata | null;
@@ -57,7 +125,9 @@ export declare function getSnapshotMetadata(): SnapshotMetadata | null;
57
125
  * preserving the single-resident memory profile. When false, keep
58
126
  * previously-loaded snapshots resident for diffing/comparison.
59
127
  */
60
- export declare function setSnapshot(snapshot: IHeapSnapshot, filePath: string, metadata: Omit<SnapshotMetadata, 'filePath' | 'handle'>, opts?: {
128
+ export declare function setSnapshot(snapshot: IHeapSnapshot, filePath: string, metadata: Omit<SnapshotMetadata, 'filePath' | 'handle' | 'light'> & {
129
+ light?: boolean;
130
+ }, opts?: {
61
131
  alias?: string;
62
132
  replace?: boolean;
63
133
  }): SnapshotMetadata;
@@ -69,9 +139,26 @@ export declare function listSnapshots(): SnapshotMetadata[];
69
139
  * in P2403258184 §3).
70
140
  */
71
141
  export declare function clearAllSnapshots(): void;
142
+ /**
143
+ * A resident snapshot loaded from this exact path, if any.
144
+ *
145
+ * The point of a snapshot cache is to not re-parse a file this process already
146
+ * has in memory; that check has to key on the resolved path, since the handle is
147
+ * derived from the file name and may have been disambiguated.
148
+ */
149
+ export declare function findResidentByPath(filePath: string): SnapshotMetadata | null;
150
+ /**
151
+ * Drop every resident snapshot except `handle`, which becomes current.
152
+ *
153
+ * Used by the load cache-hit path so a hit is indistinguishable from a real load
154
+ * apart from speed: a replace-mode load unloads the others, and a hit must do
155
+ * the same or the two paths leave different state behind.
156
+ */
157
+ export declare function retainOnlySnapshot(handle: string): boolean;
72
158
  export declare function getCurrentHandle(): string | null;
73
159
  export declare function getSnapshotByHandle(handle: string): IHeapSnapshot | null;
74
160
  export declare function getMetadataByHandle(handle: string): SnapshotMetadata | null;
75
161
  export declare function setCurrentSnapshot(handle: string): boolean;
76
162
  export declare function removeSnapshot(handle: string): boolean;
163
+ export {};
77
164
  //# sourceMappingURL=heap-state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"heap-state.d.ts","sourceRoot":"","sources":["../src/heap-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,cAAc,CAAC;AAGhD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAgCzD,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,WAAW,CAAC;CAClB;AAaD;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAWD,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,aAAa,CAM7E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAK1C;AAgBD,wBAAgB,WAAW,IAAI,aAAa,CAO3C;AAED,wBAAgB,WAAW,IAAI,MAAM,GAAG,IAAI,CAG3C;AAED,wBAAgB,cAAc,IAAI,WAAW,CAG5C;AAED,wBAAgB,mBAAmB,IAAI,gBAAgB,GAAG,IAAI,CAG7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,aAAa,EACvB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,IAAI,CAAC,gBAAgB,EAAE,UAAU,GAAG,QAAQ,CAAC,EACvD,IAAI,GAAE;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAM,GAC7C,gBAAgB,CAWlB;AAED,wBAAgB,aAAa,IAAI,gBAAgB,EAAE,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEhD;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAExE;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAE3E;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAK1D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAOtD"}
1
+ {"version":3,"file":"heap-state.d.ts","sourceRoot":"","sources":["../src/heap-state.ts"],"names":[],"mappings":"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"}