@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.
Files changed (374) hide show
  1. package/README.md +30 -16
  2. package/bin/.eslintrc.js +26 -0
  3. package/bin/memlab-cli.js +313 -0
  4. package/dist/anonymized-snapshot.d.ts +75 -0
  5. package/dist/anonymized-snapshot.d.ts.map +1 -0
  6. package/dist/anonymized-snapshot.js +101 -0
  7. package/dist/anonymized-snapshot.js.map +1 -0
  8. package/dist/artifact-classes.d.ts +86 -0
  9. package/dist/artifact-classes.d.ts.map +1 -0
  10. package/dist/artifact-classes.js +261 -0
  11. package/dist/artifact-classes.js.map +1 -0
  12. package/dist/capture-mode.d.ts +60 -0
  13. package/dist/capture-mode.d.ts.map +1 -0
  14. package/dist/capture-mode.js +39 -0
  15. package/dist/capture-mode.js.map +1 -0
  16. package/dist/eval-hints.d.ts +41 -0
  17. package/dist/eval-hints.d.ts.map +1 -0
  18. package/dist/eval-hints.js +115 -0
  19. package/dist/eval-hints.js.map +1 -0
  20. package/dist/guardrail.d.ts.map +1 -1
  21. package/dist/guardrail.js +13 -0
  22. package/dist/guardrail.js.map +1 -1
  23. package/dist/heap-budget.d.ts +32 -0
  24. package/dist/heap-budget.d.ts.map +1 -0
  25. package/dist/heap-budget.js +90 -0
  26. package/dist/heap-budget.js.map +1 -0
  27. package/dist/heap-shapes.d.ts +148 -0
  28. package/dist/heap-shapes.d.ts.map +1 -0
  29. package/dist/heap-shapes.js +193 -0
  30. package/dist/heap-shapes.js.map +1 -0
  31. package/dist/heap-state.d.ts +109 -2
  32. package/dist/heap-state.d.ts.map +1 -1
  33. package/dist/heap-state.js +194 -3
  34. package/dist/heap-state.js.map +1 -1
  35. package/dist/index.js +102 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/progress.d.ts +25 -0
  38. package/dist/progress.d.ts.map +1 -0
  39. package/dist/progress.js +46 -0
  40. package/dist/progress.js.map +1 -0
  41. package/dist/react-shapes.d.ts +42 -0
  42. package/dist/react-shapes.d.ts.map +1 -0
  43. package/dist/react-shapes.js +149 -0
  44. package/dist/react-shapes.js.map +1 -0
  45. package/dist/result-handles.d.ts +11 -0
  46. package/dist/result-handles.d.ts.map +1 -0
  47. package/dist/result-handles.js +77 -0
  48. package/dist/result-handles.js.map +1 -0
  49. package/dist/server-version.d.ts +19 -0
  50. package/dist/server-version.d.ts.map +1 -0
  51. package/dist/server-version.js +19 -0
  52. package/dist/server-version.js.map +1 -0
  53. package/dist/snapshot-borrow.d.ts +67 -0
  54. package/dist/snapshot-borrow.d.ts.map +1 -0
  55. package/dist/snapshot-borrow.js +113 -0
  56. package/dist/snapshot-borrow.js.map +1 -0
  57. package/dist/string-index.d.ts +55 -0
  58. package/dist/string-index.d.ts.map +1 -0
  59. package/dist/string-index.js +99 -0
  60. package/dist/string-index.js.map +1 -0
  61. package/dist/tool-registry.d.ts +42 -0
  62. package/dist/tool-registry.d.ts.map +1 -0
  63. package/dist/tool-registry.js +20 -0
  64. package/dist/tool-registry.js.map +1 -0
  65. package/dist/tools/analyze-run.d.ts +12 -0
  66. package/dist/tools/analyze-run.d.ts.map +1 -0
  67. package/dist/tools/analyze-run.js +404 -0
  68. package/dist/tools/analyze-run.js.map +1 -0
  69. package/dist/tools/anonymize-snapshot.d.ts +12 -0
  70. package/dist/tools/anonymize-snapshot.d.ts.map +1 -0
  71. package/dist/tools/anonymize-snapshot.js +159 -0
  72. package/dist/tools/anonymize-snapshot.js.map +1 -0
  73. package/dist/tools/app-config.d.ts +12 -0
  74. package/dist/tools/app-config.d.ts.map +1 -0
  75. package/dist/tools/app-config.js +217 -0
  76. package/dist/tools/app-config.js.map +1 -0
  77. package/dist/tools/app-heap.d.ts +30 -0
  78. package/dist/tools/app-heap.d.ts.map +1 -0
  79. package/dist/tools/app-heap.js +106 -0
  80. package/dist/tools/app-heap.js.map +1 -0
  81. package/dist/tools/artifact-budget.d.ts +12 -0
  82. package/dist/tools/artifact-budget.d.ts.map +1 -0
  83. package/dist/tools/artifact-budget.js +219 -0
  84. package/dist/tools/artifact-budget.js.map +1 -0
  85. package/dist/tools/async-census.d.ts +12 -0
  86. package/dist/tools/async-census.d.ts.map +1 -0
  87. package/dist/tools/async-census.js +243 -0
  88. package/dist/tools/async-census.js.map +1 -0
  89. package/dist/tools/auto-investigate.d.ts.map +1 -1
  90. package/dist/tools/auto-investigate.js +54 -5
  91. package/dist/tools/auto-investigate.js.map +1 -1
  92. package/dist/tools/batch.d.ts +12 -0
  93. package/dist/tools/batch.d.ts.map +1 -0
  94. package/dist/tools/batch.js +196 -0
  95. package/dist/tools/batch.js.map +1 -0
  96. package/dist/tools/cache-analysis.d.ts +15 -0
  97. package/dist/tools/cache-analysis.d.ts.map +1 -1
  98. package/dist/tools/cache-analysis.js +240 -14
  99. package/dist/tools/cache-analysis.js.map +1 -1
  100. package/dist/tools/census-diff.d.ts +55 -0
  101. package/dist/tools/census-diff.d.ts.map +1 -0
  102. package/dist/tools/census-diff.js +228 -0
  103. package/dist/tools/census-diff.js.map +1 -0
  104. package/dist/tools/chain-walk.d.ts +12 -0
  105. package/dist/tools/chain-walk.d.ts.map +1 -0
  106. package/dist/tools/chain-walk.js +184 -0
  107. package/dist/tools/chain-walk.js.map +1 -0
  108. package/dist/tools/class-histogram.d.ts.map +1 -1
  109. package/dist/tools/class-histogram.js +14 -3
  110. package/dist/tools/class-histogram.js.map +1 -1
  111. package/dist/tools/collection-diff.d.ts +44 -0
  112. package/dist/tools/collection-diff.d.ts.map +1 -0
  113. package/dist/tools/collection-diff.js +343 -0
  114. package/dist/tools/collection-diff.js.map +1 -0
  115. package/dist/tools/collection-trend.d.ts +55 -0
  116. package/dist/tools/collection-trend.d.ts.map +1 -0
  117. package/dist/tools/collection-trend.js +315 -0
  118. package/dist/tools/collection-trend.js.map +1 -0
  119. package/dist/tools/detached-dom.d.ts +5 -0
  120. package/dist/tools/detached-dom.d.ts.map +1 -1
  121. package/dist/tools/detached-dom.js +368 -22
  122. package/dist/tools/detached-dom.js.map +1 -1
  123. package/dist/tools/dev-artifacts.d.ts +62 -6
  124. package/dist/tools/dev-artifacts.d.ts.map +1 -1
  125. package/dist/tools/dev-artifacts.js +685 -24
  126. package/dist/tools/dev-artifacts.js.map +1 -1
  127. package/dist/tools/diff-snapshots.d.ts.map +1 -1
  128. package/dist/tools/diff-snapshots.js +18 -2
  129. package/dist/tools/diff-snapshots.js.map +1 -1
  130. package/dist/tools/dom-audit.d.ts +37 -0
  131. package/dist/tools/dom-audit.d.ts.map +1 -0
  132. package/dist/tools/dom-audit.js +247 -0
  133. package/dist/tools/dom-audit.js.map +1 -0
  134. package/dist/tools/dominator-attribution.d.ts +12 -0
  135. package/dist/tools/dominator-attribution.d.ts.map +1 -0
  136. package/dist/tools/dominator-attribution.js +189 -0
  137. package/dist/tools/dominator-attribution.js.map +1 -0
  138. package/dist/tools/dominator-chain.d.ts +12 -0
  139. package/dist/tools/dominator-chain.d.ts.map +1 -0
  140. package/dist/tools/dominator-chain.js +92 -0
  141. package/dist/tools/dominator-chain.js.map +1 -0
  142. package/dist/tools/duplicate-objects.d.ts +12 -0
  143. package/dist/tools/duplicate-objects.d.ts.map +1 -0
  144. package/dist/tools/duplicate-objects.js +172 -0
  145. package/dist/tools/duplicate-objects.js.map +1 -0
  146. package/dist/tools/duplicated-strings.d.ts.map +1 -1
  147. package/dist/tools/duplicated-strings.js +49 -40
  148. package/dist/tools/duplicated-strings.js.map +1 -1
  149. package/dist/tools/eval-across.d.ts +12 -0
  150. package/dist/tools/eval-across.d.ts.map +1 -0
  151. package/dist/tools/eval-across.js +135 -0
  152. package/dist/tools/eval-across.js.map +1 -0
  153. package/dist/tools/eval.d.ts +79 -0
  154. package/dist/tools/eval.d.ts.map +1 -1
  155. package/dist/tools/eval.js +2523 -197
  156. package/dist/tools/eval.js.map +1 -1
  157. package/dist/tools/event-listener-leaks.d.ts.map +1 -1
  158. package/dist/tools/event-listener-leaks.js +42 -17
  159. package/dist/tools/event-listener-leaks.js.map +1 -1
  160. package/dist/tools/event-registry.d.ts.map +1 -1
  161. package/dist/tools/event-registry.js +42 -8
  162. package/dist/tools/event-registry.js.map +1 -1
  163. package/dist/tools/explain-delta.d.ts +12 -0
  164. package/dist/tools/explain-delta.d.ts.map +1 -0
  165. package/dist/tools/explain-delta.js +221 -0
  166. package/dist/tools/explain-delta.js.map +1 -0
  167. package/dist/tools/find-nodes-by-class.d.ts.map +1 -1
  168. package/dist/tools/find-nodes-by-class.js +112 -13
  169. package/dist/tools/find-nodes-by-class.js.map +1 -1
  170. package/dist/tools/finding-index.d.ts +203 -0
  171. package/dist/tools/finding-index.d.ts.map +1 -0
  172. package/dist/tools/finding-index.js +566 -0
  173. package/dist/tools/finding-index.js.map +1 -0
  174. package/dist/tools/for-each.d.ts.map +1 -1
  175. package/dist/tools/for-each.js +15 -3
  176. package/dist/tools/for-each.js.map +1 -1
  177. package/dist/tools/get-referrers.d.ts.map +1 -1
  178. package/dist/tools/get-referrers.js +17 -0
  179. package/dist/tools/get-referrers.js.map +1 -1
  180. package/dist/tools/get-value.d.ts +16 -0
  181. package/dist/tools/get-value.d.ts.map +1 -1
  182. package/dist/tools/get-value.js +96 -2
  183. package/dist/tools/get-value.js.map +1 -1
  184. package/dist/tools/hunt-report.d.ts +12 -0
  185. package/dist/tools/hunt-report.d.ts.map +1 -0
  186. package/dist/tools/hunt-report.js +186 -0
  187. package/dist/tools/hunt-report.js.map +1 -0
  188. package/dist/tools/hypothesis.d.ts +12 -0
  189. package/dist/tools/hypothesis.d.ts.map +1 -0
  190. package/dist/tools/hypothesis.js +280 -0
  191. package/dist/tools/hypothesis.js.map +1 -0
  192. package/dist/tools/id-space-audit.d.ts +12 -0
  193. package/dist/tools/id-space-audit.d.ts.map +1 -0
  194. package/dist/tools/id-space-audit.js +262 -0
  195. package/dist/tools/id-space-audit.js.map +1 -0
  196. package/dist/tools/identify.d.ts +12 -0
  197. package/dist/tools/identify.d.ts.map +1 -0
  198. package/dist/tools/identify.js +205 -0
  199. package/dist/tools/identify.js.map +1 -0
  200. package/dist/tools/identity-diff.d.ts +12 -0
  201. package/dist/tools/identity-diff.d.ts.map +1 -0
  202. package/dist/tools/identity-diff.js +188 -0
  203. package/dist/tools/identity-diff.js.map +1 -0
  204. package/dist/tools/intern-opportunities.d.ts.map +1 -1
  205. package/dist/tools/intern-opportunities.js +116 -50
  206. package/dist/tools/intern-opportunities.js.map +1 -1
  207. package/dist/tools/ladder-probe.d.ts +65 -0
  208. package/dist/tools/ladder-probe.d.ts.map +1 -0
  209. package/dist/tools/ladder-probe.js +445 -0
  210. package/dist/tools/ladder-probe.js.map +1 -0
  211. package/dist/tools/ladder.d.ts +33 -0
  212. package/dist/tools/ladder.d.ts.map +1 -0
  213. package/dist/tools/ladder.js +266 -0
  214. package/dist/tools/ladder.js.map +1 -0
  215. package/dist/tools/largest-objects.d.ts.map +1 -1
  216. package/dist/tools/largest-objects.js +6 -2
  217. package/dist/tools/largest-objects.js.map +1 -1
  218. package/dist/tools/leak-report.d.ts +35 -0
  219. package/dist/tools/leak-report.d.ts.map +1 -0
  220. package/dist/tools/leak-report.js +398 -0
  221. package/dist/tools/leak-report.js.map +1 -0
  222. package/dist/tools/load-snapshot.d.ts +29 -0
  223. package/dist/tools/load-snapshot.d.ts.map +1 -1
  224. package/dist/tools/load-snapshot.js +294 -23
  225. package/dist/tools/load-snapshot.js.map +1 -1
  226. package/dist/tools/map-entries.d.ts +12 -0
  227. package/dist/tools/map-entries.d.ts.map +1 -0
  228. package/dist/tools/map-entries.js +139 -0
  229. package/dist/tools/map-entries.js.map +1 -0
  230. package/dist/tools/match-object.d.ts +12 -0
  231. package/dist/tools/match-object.d.ts.map +1 -0
  232. package/dist/tools/match-object.js +165 -0
  233. package/dist/tools/match-object.js.map +1 -0
  234. package/dist/tools/metric.d.ts +13 -0
  235. package/dist/tools/metric.d.ts.map +1 -0
  236. package/dist/tools/metric.js +185 -0
  237. package/dist/tools/metric.js.map +1 -0
  238. package/dist/tools/module-attribution.d.ts +36 -0
  239. package/dist/tools/module-attribution.d.ts.map +1 -0
  240. package/dist/tools/module-attribution.js +235 -0
  241. package/dist/tools/module-attribution.js.map +1 -0
  242. package/dist/tools/next-measurement.d.ts +26 -0
  243. package/dist/tools/next-measurement.d.ts.map +1 -0
  244. package/dist/tools/next-measurement.js +149 -0
  245. package/dist/tools/next-measurement.js.map +1 -0
  246. package/dist/tools/object-cost-breakdown.d.ts.map +1 -1
  247. package/dist/tools/object-cost-breakdown.js +64 -0
  248. package/dist/tools/object-cost-breakdown.js.map +1 -1
  249. package/dist/tools/object-shape.d.ts.map +1 -1
  250. package/dist/tools/object-shape.js +53 -5
  251. package/dist/tools/object-shape.js.map +1 -1
  252. package/dist/tools/population-diff.d.ts +57 -0
  253. package/dist/tools/population-diff.d.ts.map +1 -0
  254. package/dist/tools/population-diff.js +338 -0
  255. package/dist/tools/population-diff.js.map +1 -0
  256. package/dist/tools/population-vs-owners.d.ts +12 -0
  257. package/dist/tools/population-vs-owners.d.ts.map +1 -0
  258. package/dist/tools/population-vs-owners.js +183 -0
  259. package/dist/tools/population-vs-owners.js.map +1 -0
  260. package/dist/tools/property-names.d.ts +29 -0
  261. package/dist/tools/property-names.d.ts.map +1 -0
  262. package/dist/tools/property-names.js +131 -0
  263. package/dist/tools/property-names.js.map +1 -0
  264. package/dist/tools/quick-diagnosis.d.ts.map +1 -1
  265. package/dist/tools/quick-diagnosis.js +7 -1
  266. package/dist/tools/quick-diagnosis.js.map +1 -1
  267. package/dist/tools/react-owners.d.ts +12 -0
  268. package/dist/tools/react-owners.d.ts.map +1 -0
  269. package/dist/tools/react-owners.js +167 -0
  270. package/dist/tools/react-owners.js.map +1 -0
  271. package/dist/tools/react-update-queues.d.ts +12 -0
  272. package/dist/tools/react-update-queues.d.ts.map +1 -0
  273. package/dist/tools/react-update-queues.js +173 -0
  274. package/dist/tools/react-update-queues.js.map +1 -0
  275. package/dist/tools/replicate.d.ts +49 -0
  276. package/dist/tools/replicate.d.ts.map +1 -0
  277. package/dist/tools/replicate.js +241 -0
  278. package/dist/tools/replicate.js.map +1 -0
  279. package/dist/tools/retainer-diff.d.ts +12 -0
  280. package/dist/tools/retainer-diff.d.ts.map +1 -0
  281. package/dist/tools/retainer-diff.js +168 -0
  282. package/dist/tools/retainer-diff.js.map +1 -0
  283. package/dist/tools/retainer-layers.d.ts +23 -0
  284. package/dist/tools/retainer-layers.d.ts.map +1 -0
  285. package/dist/tools/retainer-layers.js +179 -0
  286. package/dist/tools/retainer-layers.js.map +1 -0
  287. package/dist/tools/retainer-summary.d.ts +18 -0
  288. package/dist/tools/retainer-summary.d.ts.map +1 -1
  289. package/dist/tools/retainer-summary.js +210 -51
  290. package/dist/tools/retainer-summary.js.map +1 -1
  291. package/dist/tools/retainer-trace.d.ts.map +1 -1
  292. package/dist/tools/retainer-trace.js +14 -2
  293. package/dist/tools/retainer-trace.js.map +1 -1
  294. package/dist/tools/round-audit.d.ts +66 -0
  295. package/dist/tools/round-audit.d.ts.map +1 -0
  296. package/dist/tools/round-audit.js +258 -0
  297. package/dist/tools/round-audit.js.map +1 -0
  298. package/dist/tools/round-digest.d.ts +12 -0
  299. package/dist/tools/round-digest.d.ts.map +1 -0
  300. package/dist/tools/round-digest.js +190 -0
  301. package/dist/tools/round-digest.js.map +1 -0
  302. package/dist/tools/script-census.d.ts +12 -0
  303. package/dist/tools/script-census.d.ts.map +1 -0
  304. package/dist/tools/script-census.js +182 -0
  305. package/dist/tools/script-census.js.map +1 -0
  306. package/dist/tools/search-nodes.d.ts.map +1 -1
  307. package/dist/tools/search-nodes.js +5 -1
  308. package/dist/tools/search-nodes.js.map +1 -1
  309. package/dist/tools/search-strings.d.ts.map +1 -1
  310. package/dist/tools/search-strings.js +53 -7
  311. package/dist/tools/search-strings.js.map +1 -1
  312. package/dist/tools/sequence-analysis.d.ts +53 -0
  313. package/dist/tools/sequence-analysis.d.ts.map +1 -1
  314. package/dist/tools/sequence-analysis.js +313 -89
  315. package/dist/tools/sequence-analysis.js.map +1 -1
  316. package/dist/tools/server-status.d.ts.map +1 -1
  317. package/dist/tools/server-status.js +4 -1
  318. package/dist/tools/server-status.js.map +1 -1
  319. package/dist/tools/settle-check.d.ts +12 -0
  320. package/dist/tools/settle-check.d.ts.map +1 -0
  321. package/dist/tools/settle-check.js +188 -0
  322. package/dist/tools/settle-check.js.map +1 -0
  323. package/dist/tools/shape-histogram.d.ts.map +1 -1
  324. package/dist/tools/shape-histogram.js +9 -2
  325. package/dist/tools/shape-histogram.js.map +1 -1
  326. package/dist/tools/sliced-strings.d.ts.map +1 -1
  327. package/dist/tools/sliced-strings.js +2 -1
  328. package/dist/tools/sliced-strings.js.map +1 -1
  329. package/dist/tools/snapshots.d.ts.map +1 -1
  330. package/dist/tools/snapshots.js +24 -6
  331. package/dist/tools/snapshots.js.map +1 -1
  332. package/dist/tools/sparse-elements.d.ts +12 -0
  333. package/dist/tools/sparse-elements.d.ts.map +1 -0
  334. package/dist/tools/sparse-elements.js +215 -0
  335. package/dist/tools/sparse-elements.js.map +1 -0
  336. package/dist/tools/stale-collections.d.ts +17 -0
  337. package/dist/tools/stale-collections.d.ts.map +1 -1
  338. package/dist/tools/stale-collections.js +28 -0
  339. package/dist/tools/stale-collections.js.map +1 -1
  340. package/dist/tools/string-patterns.d.ts.map +1 -1
  341. package/dist/tools/string-patterns.js +7 -5
  342. package/dist/tools/string-patterns.js.map +1 -1
  343. package/dist/tools/tools-index.d.ts +12 -0
  344. package/dist/tools/tools-index.d.ts.map +1 -0
  345. package/dist/tools/tools-index.js +492 -0
  346. package/dist/tools/tools-index.js.map +1 -0
  347. package/dist/tools/trace-all.d.ts +42 -0
  348. package/dist/tools/trace-all.d.ts.map +1 -0
  349. package/dist/tools/trace-all.js +263 -0
  350. package/dist/tools/trace-all.js.map +1 -0
  351. package/dist/tools/unit-cost.d.ts +12 -0
  352. package/dist/tools/unit-cost.d.ts.map +1 -0
  353. package/dist/tools/unit-cost.js +219 -0
  354. package/dist/tools/unit-cost.js.map +1 -0
  355. package/dist/tools/verify-fix.d.ts +23 -0
  356. package/dist/tools/verify-fix.d.ts.map +1 -0
  357. package/dist/tools/verify-fix.js +219 -0
  358. package/dist/tools/verify-fix.js.map +1 -0
  359. package/dist/tools/weakmap-entries.d.ts.map +1 -1
  360. package/dist/tools/weakmap-entries.js +6 -1
  361. package/dist/tools/weakmap-entries.js.map +1 -1
  362. package/dist/tools/weakref-census.d.ts +15 -0
  363. package/dist/tools/weakref-census.d.ts.map +1 -0
  364. package/dist/tools/weakref-census.js +147 -0
  365. package/dist/tools/weakref-census.js.map +1 -0
  366. package/dist/tools/what-if.d.ts +12 -0
  367. package/dist/tools/what-if.d.ts.map +1 -0
  368. package/dist/tools/what-if.js +285 -0
  369. package/dist/tools/what-if.js.map +1 -0
  370. package/dist/utils.d.ts +238 -3
  371. package/dist/utils.d.ts.map +1 -1
  372. package/dist/utils.js +507 -15
  373. package/dist/utils.js.map +1 -1
  374. package/package.json +7 -6
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @format
8
+ * @oncall memory_lab
9
+ */
10
+ import { z } from 'zod';
11
+ import { getSnapshot } from '../heap-state.js';
12
+ import { formatBytes, formatNumber, markdownTable, truncateNodeName, errorResult, toolResult, enumerateMapEntries, enumerateSetElements, } from '../utils.js';
13
+ // Render a node as a short label, inlining the string value for string nodes so
14
+ // cache keys are visible verbatim (the whole point of enumerating a cache Map).
15
+ function describeNode(node, maxLen) {
16
+ if (node.isString) {
17
+ const strNode = node.toStringNode();
18
+ if (strNode) {
19
+ const val = strNode.stringValue;
20
+ const shown = val.length > maxLen ? val.slice(0, maxLen) + '...' : val;
21
+ return `"${shown}"`;
22
+ }
23
+ }
24
+ return `${truncateNodeName(node.name, node.type, node.self_size, maxLen)} (${node.type})`;
25
+ }
26
+ export function registerMapEntries(server) {
27
+ server.tool('memlab_map_entries', 'Enumerate the entries of ONE Map or Set (node_id is REQUIRED — this is not a global scan). The companion to memlab_weakmap_entries for strongly-held collections. The KEYS are usually the whole diagnosis of an unbounded cache: a Store/singleton Map keyed by "(filter,timeRange,interval)" or a query hash tells you the cache DIMENSION that is driving growth — which is exactly what you cannot see from a class histogram or retainer trace alone. Shows each key (string keys inlined verbatim), the value class, and value retained size. First locate a Map/Set with memlab_find_nodes_by_class("Map") / ("Set") (or memlab_largest_objects), then pass its node id here.', {
28
+ node_id: z
29
+ .number()
30
+ .describe('REQUIRED. The numeric ID of a single Map or Set node. Find candidates with memlab_find_nodes_by_class("Map") or ("Set"); there is no scan-all mode. For WeakMaps use memlab_weakmap_entries.'),
31
+ limit: z
32
+ .number()
33
+ .optional()
34
+ .default(20)
35
+ .describe('Maximum number of entries to return (default 20)'),
36
+ sort_by: z
37
+ .enum(['retained_size', 'retained', 'key_name', 'insertion'])
38
+ .optional()
39
+ .default('retained_size')
40
+ .describe('Sort by entry retained size ("retained_size", alias "retained"), key name ("key_name"), or backing-store order ("insertion"). Default: retained_size.'),
41
+ }, async ({ node_id, limit, sort_by }) => {
42
+ try {
43
+ const snapshot = getSnapshot();
44
+ const node = snapshot.getNodeById(node_id);
45
+ if (!node) {
46
+ return errorResult(`Node with id ${node_id} not found`);
47
+ }
48
+ const isMap = node.name === 'Map';
49
+ const isSet = node.name === 'Set';
50
+ if (!isMap && !isSet) {
51
+ return errorResult(`@${node_id} is a ${node.name} (${node.type}), not a Map or Set. ` +
52
+ `Use \`memlab_find_nodes_by_class("Map")\` or \`("Set")\` to find ` +
53
+ `instances. For WeakMaps use \`memlab_weakmap_entries\`.`);
54
+ }
55
+ // Enumerate via the shared, index-aware backing-store walk
56
+ // (`src/utils.ts`). It pairs each key with the value in the immediately
57
+ // following FixedArray slot INDEX, so a Map with SMI values (whose value
58
+ // slots emit no edge) reports value:null instead of mispairing the key
59
+ // with the next entry's key. Set elements come back one-per-slot.
60
+ const entries = (isSet
61
+ ? enumerateSetElements(node).map(k => ({ key: k, value: null }))
62
+ : enumerateMapEntries(node)).map(e => ({
63
+ key: e.key,
64
+ value: e.value,
65
+ keyRetained: e.key.retainedSize,
66
+ valueRetained: e.value ? e.value.retainedSize : 0,
67
+ }));
68
+ if (entries.length === 0) {
69
+ return toolResult(`${node.name} @${node_id} has no enumerable entries.\n\n` +
70
+ `**Note:** the backing store may hold primitive (SMI/number/bool) ` +
71
+ `values inline rather than as heap objects, or V8's layout may not ` +
72
+ `expose them in this snapshot. Try \`memlab_get_references(${node_id})\` ` +
73
+ `to inspect the raw structure.`);
74
+ }
75
+ if (sort_by === 'retained_size' || sort_by === 'retained') {
76
+ entries.sort((a, b) => b.keyRetained +
77
+ b.valueRetained -
78
+ (a.keyRetained + a.valueRetained));
79
+ }
80
+ else if (sort_by === 'key_name') {
81
+ entries.sort((a, b) => a.key.name.localeCompare(b.key.name));
82
+ } // 'insertion' keeps backing-store order
83
+ const shown = entries.slice(0, limit);
84
+ const totalEntries = entries.length;
85
+ const totalKeyRetained = entries.reduce((s, e) => s + e.keyRetained, 0);
86
+ const totalValueRetained = entries.reduce((s, e) => s + e.valueRetained, 0);
87
+ let entryTable;
88
+ if (isSet) {
89
+ const headers = ['Value ID', 'Value', 'Retained'];
90
+ const rightCols = new Set([2]);
91
+ const rows = shown.map(e => [
92
+ `@${e.key.id}`,
93
+ describeNode(e.key, 60),
94
+ formatBytes(e.keyRetained),
95
+ ]);
96
+ entryTable = markdownTable(headers, rows, rightCols);
97
+ }
98
+ else {
99
+ const headers = [
100
+ 'Key ID',
101
+ 'Key',
102
+ 'Value ID',
103
+ 'Value',
104
+ 'Value Retained',
105
+ ];
106
+ const rightCols = new Set([4]);
107
+ const rows = shown.map(e => [
108
+ `@${e.key.id}`,
109
+ describeNode(e.key, 60),
110
+ e.value ? `@${e.value.id}` : '—',
111
+ e.value ? describeNode(e.value, 40) : '—',
112
+ formatBytes(e.valueRetained),
113
+ ]);
114
+ entryTable = markdownTable(headers, rows, rightCols);
115
+ }
116
+ const lines = [
117
+ `${node.name} @${node_id}: ${formatNumber(totalEntries)} entries` +
118
+ (totalEntries > limit ? ` (showing top ${limit})` : ''),
119
+ isSet
120
+ ? `Total retained: ${formatBytes(totalKeyRetained)}`
121
+ : `Total key retained: ${formatBytes(totalKeyRetained)}, ` +
122
+ `total value retained: ${formatBytes(totalValueRetained)}`,
123
+ '',
124
+ entryTable,
125
+ ];
126
+ if (isMap) {
127
+ lines.push('', '_Keys are paired with the value in the immediately-following backing-' +
128
+ 'store slot INDEX. Entries whose value is an inline SMI (small int) ' +
129
+ 'emit no heap edge, so their value shows as "—" (primitive, not ' +
130
+ 'captured) rather than being mispaired with the next entry._');
131
+ }
132
+ return toolResult(lines.join('\n'));
133
+ }
134
+ catch (err) {
135
+ return errorResult(err);
136
+ }
137
+ });
138
+ }
139
+ //# sourceMappingURL=map-entries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"map-entries.js","sourceRoot":"","sources":["../../src/tools/map-entries.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 registerMatchObject(server: McpServer): void;
12
+ //# sourceMappingURL=match-object.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match-object.d.ts","sourceRoot":"","sources":["../../src/tools/match-object.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAmEvE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoJ3D"}
@@ -0,0 +1,165 @@
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, getSnapshotByHandle, getMetadataByHandle, listSnapshots, } from '../heap-state.js';
12
+ import { formatBytes, formatNumber, markdownTable, truncateNodeName, errorResult, toolResult, } from '../utils.js';
13
+ import { getFirstNonFrameworkRetainer } from './detached-dom.js';
14
+ // Property names sampled to fingerprint an object's shape. Matches the cap the
15
+ // other shape-based tools use, so a fingerprint is comparable across them.
16
+ const SHAPE_PROP_CAP = 12;
17
+ // Cap on candidates scored per match. A class with a million instances would
18
+ // otherwise turn an identity lookup into a full-heap ranking problem.
19
+ const MAX_CANDIDATES = 5000;
20
+ /**
21
+ * Property-name fingerprint, or null when the node is too wide to fingerprint.
22
+ *
23
+ * Returning an empty array for a wide node was wrong in a way that inverted the
24
+ * result: `jaccard(empty, empty)` is 1, so two wide objects of the same class
25
+ * scored a PERFECT shape match without a single property having been compared.
26
+ * "Not computed" and "genuinely has no properties" have to be distinguishable.
27
+ */
28
+ function shapeOf(node) {
29
+ const props = [];
30
+ if (node.edge_count > 1024)
31
+ return null;
32
+ node.forEachReference(edge => {
33
+ if (edge.type === 'property') {
34
+ props.push(String(edge.name_or_index));
35
+ if (props.length >= SHAPE_PROP_CAP)
36
+ return { stop: true };
37
+ }
38
+ });
39
+ props.sort();
40
+ return props;
41
+ }
42
+ function jaccard(a, b) {
43
+ if (a.size === 0 && b.size === 0)
44
+ return 1;
45
+ let inter = 0;
46
+ for (const x of a)
47
+ if (b.has(x))
48
+ inter++;
49
+ const union = a.size + b.size - inter;
50
+ return union === 0 ? 0 : inter / union;
51
+ }
52
+ export function registerMatchObject(server) {
53
+ server.tool('memlab_match_object', 'Find the object in ANOTHER loaded snapshot that corresponds to a given object in the current one. ' +
54
+ 'Heap node ids are assigned per capture and are meaningless across snapshots, which is why every cross-snapshot question ("did THIS object survive?", "did THIS cache grow?") otherwise degrades into comparing aggregate class counts. This matches on identity evidence instead: class name and type (required), property-shape overlap, and the first non-framework retainer path. ' +
55
+ 'Returns ranked candidates with a score and the retained-size delta, NOT a single answer — object identity across captures is inferred, never proven, and the tool says so rather than presenting a guess as a fact. Both snapshots must be resident: load them with keep_previous:true and see memlab_snapshots for handles.', {
56
+ node_id: z
57
+ .number()
58
+ .describe('Node id in the CURRENT snapshot to find a match for.'),
59
+ target_handle: z
60
+ .string()
61
+ .describe('Handle of the other resident snapshot to search (memlab_snapshots lists them).'),
62
+ limit: z
63
+ .number()
64
+ .optional()
65
+ .default(5)
66
+ .describe('Maximum candidates to return (default 5).'),
67
+ min_score: z
68
+ .number()
69
+ .optional()
70
+ .default(0.5)
71
+ .describe('Minimum match score, 0-1 (default 0.5). Score is 0.7×shape overlap + 0.3×retainer-path agreement; name and type must match exactly regardless.'),
72
+ }, async ({ node_id, target_handle, limit, min_score }) => {
73
+ try {
74
+ const source = getSnapshot();
75
+ const target = getSnapshotByHandle(target_handle);
76
+ if (target == null) {
77
+ const available = listSnapshots()
78
+ .map(m => m.handle)
79
+ .join(', ');
80
+ return errorResult(`No resident snapshot with handle "${target_handle}". Resident: ${available || '(none)'}. Load the other snapshot with memlab_load_snapshot({file_path, keep_previous: true}).`);
81
+ }
82
+ const targetMeta = getMetadataByHandle(target_handle);
83
+ if (targetMeta?.light) {
84
+ return errorResult(`Snapshot "${target_handle}" was loaded in LIGHT mode; matching compares retained sizes and retainer paths, which it does not have. Reload it without light.`);
85
+ }
86
+ const src = source.getNodeById(node_id);
87
+ if (!src)
88
+ return errorResult(`Node @${node_id} not found.`);
89
+ const srcShapeProps = shapeOf(src);
90
+ const srcShape = srcShapeProps == null ? null : new Set(srcShapeProps);
91
+ const srcRetainer = getFirstNonFrameworkRetainer(src);
92
+ const candidates = [];
93
+ let sameClass = 0;
94
+ let truncated = false;
95
+ target.nodes.forEach(node => {
96
+ if (node.id <= 3)
97
+ return;
98
+ if (node.name !== src.name || node.type !== src.type)
99
+ return;
100
+ sameClass++;
101
+ if (candidates.length >= MAX_CANDIDATES) {
102
+ truncated = true;
103
+ return;
104
+ }
105
+ const candProps = shapeOf(node);
106
+ // Either side being unfingerprintable means the shape term carries no
107
+ // evidence; score it 0 rather than 1 so a wide object cannot reach a
108
+ // perfect score on class and retainer alone.
109
+ const shapeKnown = srcShape != null && candProps != null;
110
+ const shapeScore = shapeKnown
111
+ ? jaccard(srcShape, new Set(candProps))
112
+ : 0;
113
+ const retainerMatch = srcRetainer !== '(unknown)' &&
114
+ getFirstNonFrameworkRetainer(node) === srcRetainer;
115
+ const score = 0.7 * shapeScore + 0.3 * (retainerMatch ? 1 : 0);
116
+ candidates.push({ node, score, shapeScore, shapeKnown, retainerMatch });
117
+ });
118
+ if (sameClass === 0) {
119
+ return toolResult(`No node named \`${src.name}\` (${src.type}) exists in "${target_handle}". ` +
120
+ 'The class is absent from that snapshot entirely — which is itself the answer if you were asking whether these objects survive.');
121
+ }
122
+ candidates.sort((a, b) => b.score - a.score);
123
+ const shown = candidates
124
+ .filter(c => c.score >= min_score)
125
+ .slice(0, limit);
126
+ const lines = [
127
+ `## Cross-snapshot match for @${src.id} \`${truncateNodeName(src.name, src.type, src.self_size, 50)}\` (${src.type})`,
128
+ '',
129
+ `Source retains ${formatBytes(src.retainedSize)}; searched **${formatNumber(sameClass)}** same-class node(s) in "${target_handle}".`,
130
+ '',
131
+ ];
132
+ if (shown.length === 0) {
133
+ lines.push(`No candidate scored at or above ${min_score}. The class exists there but no instance resembles this one in shape or retainer path — lower \`min_score\` to see the closest anyway.`);
134
+ return toolResult(lines.join('\n'));
135
+ }
136
+ lines.push(markdownTable([
137
+ 'Candidate',
138
+ 'Score',
139
+ 'Shape',
140
+ 'Same retainer',
141
+ 'Retained',
142
+ 'Δ vs source',
143
+ ], shown.map(c => {
144
+ const delta = c.node.retainedSize - src.retainedSize;
145
+ return [
146
+ `@${c.node.id}`,
147
+ c.score.toFixed(2),
148
+ c.shapeKnown ? `${Math.round(c.shapeScore * 100)}%` : 'n/a',
149
+ c.retainerMatch ? 'yes' : 'no',
150
+ formatBytes(c.node.retainedSize),
151
+ `${delta >= 0 ? '+' : '−'}${formatBytes(Math.abs(delta))}`,
152
+ ];
153
+ }), new Set([1, 2, 4, 5])), '', `_Source retainer: \`${srcRetainer}\`._`);
154
+ if (truncated) {
155
+ lines.push('', `_⚠ Scoring stopped after ${formatNumber(MAX_CANDIDATES)} same-class candidates; ${formatNumber(sameClass)} exist. With this many instances a per-object identity match is weak evidence — compare counts and shapes instead._`);
156
+ }
157
+ lines.push('', '_Identity across captures is INFERRED from class, shape and retainer path — node ids are per-capture and cannot confirm it. A high score means "indistinguishable by the available evidence", not "the same object". Confirm with `memlab_retainer_trace` on both sides before drawing a conclusion._');
158
+ return toolResult(lines.join('\n'));
159
+ }
160
+ catch (err) {
161
+ return errorResult(err);
162
+ }
163
+ });
164
+ }
165
+ //# sourceMappingURL=match-object.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match-object.js","sourceRoot":"","sources":["../../src/tools/match-object.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
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 metricStorePath(): string;
12
+ export declare function registerMetric(server: McpServer): void;
13
+ //# sourceMappingURL=metric.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metric.d.ts","sourceRoot":"","sources":["../../src/tools/metric.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAuCvE,wBAAgB,eAAe,IAAI,MAAM,CAIxC;AAuCD,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4KtD"}
@@ -0,0 +1,185 @@
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 os from 'os';
12
+ import path from 'path';
13
+ import { z } from 'zod';
14
+ import { getSnapshotMetadata } from '../heap-state.js';
15
+ import { errorResult, formatNumber, markdownTable, toolResult, } from '../utils.js';
16
+ const MAX_POINTS_PER_METRIC = 200;
17
+ export function metricStorePath() {
18
+ const dir = process.env.MEMLAB_STATE_DIR ?? path.join(os.homedir(), '.memlab');
19
+ return path.join(dir, 'metrics.json');
20
+ }
21
+ function readStore() {
22
+ const file = metricStorePath();
23
+ try {
24
+ const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
25
+ if (parsed?.version === 1 && parsed.metrics != null)
26
+ return parsed;
27
+ }
28
+ catch {
29
+ // A missing or corrupt store is not an error worth failing a measurement
30
+ // over — start a fresh one rather than losing the number being recorded.
31
+ }
32
+ return { version: 1, metrics: {} };
33
+ }
34
+ function writeStore(store) {
35
+ const file = metricStorePath();
36
+ fs.mkdirSync(path.dirname(file), { recursive: true });
37
+ fs.writeFileSync(file, JSON.stringify(store, null, 2));
38
+ }
39
+ function formatValue(p) {
40
+ return `${formatNumber(Math.round(p.value * 100) / 100)}${p.unit === '' ? '' : ` ${p.unit}`}`;
41
+ }
42
+ function trendLine(points) {
43
+ if (points.length < 2) {
44
+ return '_One point so far — record the same metric again after the next capture to get a trend._';
45
+ }
46
+ const first = points[0];
47
+ const last = points[points.length - 1];
48
+ if (first.unit !== last.unit) {
49
+ return `⚠ Units changed across points (\`${first.unit}\` → \`${last.unit}\`); the delta below is arithmetic only and may be meaningless.`;
50
+ }
51
+ const delta = last.value - first.value;
52
+ const pct = first.value !== 0 ? (delta / Math.abs(first.value)) * 100 : 0;
53
+ const dir = delta > 0 ? 'up' : delta < 0 ? 'down' : 'unchanged';
54
+ return `**${dir}** ${formatNumber(Math.abs(Math.round(delta * 100) / 100))} ${last.unit} across ${points.length} points (${first.label} → ${last.label})${first.value !== 0 ? `, ${pct >= 0 ? '+' : ''}${pct.toFixed(1)}%` : ''}.`;
55
+ }
56
+ export function registerMetric(server) {
57
+ server.tool('memlab_metric', 'Record a measurement under a name and keep it across sessions, so a number measured today can be compared with one measured next week.\n\n' +
58
+ 'Snapshots are far too large to keep resident between sessions and node ids are per-capture, so the only thing that can persist is the measurement itself. Without this, every number from an earlier session lives in a transcript nobody reloads, and the before/after comparison that decides whether a fix worked either gets re-derived from scratch or skipped.\n\n' +
59
+ 'Modes: `record` a named value, `history` for one metric with its trend, `list` for everything recorded, `forget` to drop one. Values are stored on disk under `~/.memlab/metrics.json` (override with `MEMLAB_STATE_DIR`).', {
60
+ mode: z
61
+ .enum(['record', 'history', 'list', 'forget'])
62
+ .optional()
63
+ .default('record')
64
+ .describe('What to do (default "record").'),
65
+ name: z
66
+ .string()
67
+ .optional()
68
+ .describe('Metric name — reuse the SAME name across sessions for anything you want to compare, e.g. "wa.listener_records" or "wa.heap_after_100_msgs".'),
69
+ value: z.number().optional().describe('The measured value to record.'),
70
+ unit: z
71
+ .string()
72
+ .optional()
73
+ .default('')
74
+ .describe('Unit for the value, e.g. "bytes", "MB", "objects", "per cycle". Recorded verbatim and compared on read, so keep it consistent for one metric.'),
75
+ label: z
76
+ .string()
77
+ .optional()
78
+ .describe('What this point describes — the build, gate state or rung, e.g. "gate off, 100 msgs". Defaults to the active snapshot\'s name.'),
79
+ note: z
80
+ .string()
81
+ .optional()
82
+ .describe('Optional free text: how it was measured, which tool call produced it, what to be careful about.'),
83
+ limit: z
84
+ .number()
85
+ .optional()
86
+ .default(20)
87
+ .describe('Rows to show in history/list (default 20).'),
88
+ }, async ({ mode, name, value, unit, label, note, limit }) => {
89
+ try {
90
+ const store = readStore();
91
+ if (mode === 'list') {
92
+ const names = Object.keys(store.metrics).sort();
93
+ if (names.length === 0) {
94
+ return toolResult(`No metrics recorded yet (store: \`${metricStorePath()}\`).\n\nRecord one with \`memlab_metric({name: "...", value: 123, unit: "objects"})\` — the point of it is the comparison you will want in a later session.`);
95
+ }
96
+ const rows = names.slice(0, limit).map(n => {
97
+ const points = store.metrics[n];
98
+ const last = points[points.length - 1];
99
+ return [
100
+ n,
101
+ formatNumber(points.length),
102
+ formatValue(last),
103
+ last.label,
104
+ ];
105
+ });
106
+ return toolResult([
107
+ '## Recorded metrics',
108
+ '',
109
+ markdownTable(['Metric', 'Points', 'Latest', 'Latest label'], rows, new Set([1, 2])),
110
+ '',
111
+ `Store: \`${metricStorePath()}\`. Use \`memlab_metric({mode: "history", name})\` for the full series.`,
112
+ ].join('\n'));
113
+ }
114
+ if (name == null || name === '') {
115
+ return errorResult(new Error('Pass `name` — every metric is identified by its name.'));
116
+ }
117
+ if (mode === 'forget') {
118
+ if (store.metrics[name] == null) {
119
+ return toolResult(`No metric named \`${name}\`; nothing to drop.`);
120
+ }
121
+ delete store.metrics[name];
122
+ writeStore(store);
123
+ return toolResult(`Dropped \`${name}\`.`);
124
+ }
125
+ if (mode === 'history') {
126
+ const points = store.metrics[name];
127
+ if (points == null || points.length === 0) {
128
+ return toolResult(`No points recorded for \`${name}\`. \`memlab_metric({mode: "list"})\` shows what is recorded.`);
129
+ }
130
+ const shown = points.slice(-limit);
131
+ const rows = shown.map(p => [
132
+ String(p.seq),
133
+ p.label,
134
+ formatValue(p),
135
+ p.note ?? '',
136
+ ]);
137
+ return toolResult([
138
+ `## \`${name}\``,
139
+ '',
140
+ trendLine(points),
141
+ '',
142
+ markdownTable(['#', 'Label', 'Value', 'Note'], rows, new Set([2])),
143
+ points.length > shown.length
144
+ ? `\n_Showing the last ${shown.length} of ${points.length} points._`
145
+ : '',
146
+ '',
147
+ '_Points are compared in the order they were recorded, which is not necessarily chronological order of the captures they describe — the label is the only thing that says what a point is._',
148
+ ].join('\n'));
149
+ }
150
+ if (value == null) {
151
+ return errorResult(new Error('Pass `value` — the number to record under this name.'));
152
+ }
153
+ const meta = getSnapshotMetadata();
154
+ const points = store.metrics[name] ?? [];
155
+ const point = {
156
+ value,
157
+ unit: unit ?? '',
158
+ label: label ?? meta?.fileName ?? meta?.handle ?? 'unlabelled',
159
+ note,
160
+ seq: points.length + 1,
161
+ };
162
+ points.push(point);
163
+ // Bounded: a metric recorded in a loop should not grow the store
164
+ // without limit, and the oldest points are the least useful.
165
+ store.metrics[name] = points.slice(-MAX_POINTS_PER_METRIC);
166
+ writeStore(store);
167
+ const prev = points.length >= 2 ? points[points.length - 2] : null;
168
+ const lines = [
169
+ `Recorded \`${name}\` = **${formatValue(point)}** (${point.label}), point ${point.seq}.`,
170
+ ];
171
+ if (prev != null && prev.unit === point.unit) {
172
+ const delta = point.value - prev.value;
173
+ lines.push('', `Previous point (${prev.label}): ${formatValue(prev)} — ${delta === 0 ? 'no change' : `${delta > 0 ? '+' : ''}${formatNumber(Math.round(delta * 100) / 100)} ${point.unit}`}.`);
174
+ }
175
+ if (point.label === 'unlabelled') {
176
+ lines.push('', '⚠ No label and no active snapshot, so this point records a number with nothing saying what it describes. Pass `label` — in a later session that is all there is to go on.');
177
+ }
178
+ return toolResult(lines.join('\n'));
179
+ }
180
+ catch (err) {
181
+ return errorResult(err);
182
+ }
183
+ });
184
+ }
185
+ //# sourceMappingURL=metric.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metric.js","sourceRoot":"","sources":["../../src/tools/metric.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
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 { IHeapNode, IHeapSnapshot } from '@memlab/core';
11
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
12
+ interface Registry {
13
+ node: IHeapNode;
14
+ edgeName: string;
15
+ /** module-export node id -> module id/name */
16
+ moduleByNodeId: Map<number, string>;
17
+ }
18
+ export declare function findModuleRegistries(snapshot: IHeapSnapshot): Registry[];
19
+ interface ModuleStat {
20
+ module: string;
21
+ selfBytes: number;
22
+ nodes: number;
23
+ }
24
+ /**
25
+ * One pass with a memo indexed by `nodeIndex`: each node inherits its immediate
26
+ * dominator's module unless it IS a module export, so the whole heap is
27
+ * attributed in O(N) rather than one bounded walk per node.
28
+ */
29
+ export declare function attributeByModule(snapshot: IHeapSnapshot, registries: Registry[]): {
30
+ stats: ModuleStat[];
31
+ attributed: number;
32
+ unattributed: number;
33
+ };
34
+ export declare function registerModuleAttribution(server: McpServer): void;
35
+ export {};
36
+ //# sourceMappingURL=module-attribution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-attribution.d.ts","sourceRoot":"","sources":["../../src/tools/module-attribution.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAE,aAAa,EAAC,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAgDvE,UAAU,QAAQ;IAChB,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,GAAG,QAAQ,EAAE,CA0BxE;AAED,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,aAAa,EACvB,UAAU,EAAE,QAAQ,EAAE,GACrB;IAAC,KAAK,EAAE,UAAU,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAC,CA+DjE;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6GjE"}