@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
@@ -9,7 +9,10 @@
9
9
  */
10
10
  import { z } from 'zod';
11
11
  import { getSnapshot } from '../heap-state.js';
12
- import { formatBytes, errorResult, toolResult, looksLikeFailurePayload, } from '../utils.js';
12
+ import { withAnonymizedBanner } from '../anonymized-snapshot.js';
13
+ import { formatBytes, errorResult, toolResult, looksLikeFailurePayload, suggestionsSuppressed, } from '../utils.js';
14
+ import { classifyNonProductionString } from '../artifact-classes.js';
15
+ import { buildStringIndex, stringIndexIsCached } from '../string-index.js';
13
16
  export function registerDuplicatedStrings(server) {
14
17
  server.tool('memlab_duplicated_strings', 'Find duplicated string instances in the heap. Shows strings that appear multiple times, ranked by total retained size — a common source of memory waste. Use after memlab_class_histogram shows high string counts. ' +
15
18
  '⚠ Full-heap scan — slow and memory-heavy on very large heaps (millions of nodes); raise min_count to bound the work.', {
@@ -31,50 +34,29 @@ export function registerDuplicatedStrings(server) {
31
34
  }, async ({ limit, min_count, include_node_ids }) => {
32
35
  try {
33
36
  const snapshot = getSnapshot();
34
- // Build frequency map: string value -> { count, totalSize, exampleIds }
35
- const stringMap = new Map();
36
- snapshot.nodes.forEach(node => {
37
- if (node.type !== 'string')
38
- return;
39
- // Skip sliced strings (they share backing storage)
40
- if (node.name === 'system / SlicedString')
41
- return;
42
- const strNode = node.toStringNode();
43
- if (!strNode)
44
- return;
45
- const value = strNode.stringValue;
46
- const entry = stringMap.get(value);
47
- if (entry) {
48
- entry.count++;
49
- entry.total_size += node.retainedSize;
50
- if (entry.example_node_ids.length < 3) {
51
- entry.example_node_ids.push(node.id);
52
- }
53
- }
54
- else {
55
- stringMap.set(value, {
56
- count: 1,
57
- total_size: node.retainedSize,
58
- example_node_ids: [node.id],
59
- });
60
- }
61
- });
37
+ // Shared with memlab_intern_opportunities, which needs the same
38
+ // value -> {count, size, ids} map. Cached per snapshot, so running the
39
+ // two back to back (the common case) walks every string node once
40
+ // instead of twice.
41
+ const reused = stringIndexIsCached();
42
+ const { byValue: stringMap } = buildStringIndex(snapshot);
62
43
  const duplicated = Array.from(stringMap.entries())
63
44
  .filter(([, stats]) => stats.count >= min_count)
64
- .sort((a, b) => b[1].total_size - a[1].total_size)
45
+ .sort((a, b) => b[1].totalSize - a[1].totalSize)
65
46
  .slice(0, limit)
66
47
  .map(([value, stats]) => {
67
- const per_copy_size = stats.count > 0 ? stats.total_size / stats.count : 0;
48
+ const per_copy_size = stats.count > 0 ? stats.totalSize / stats.count : 0;
68
49
  const potential_savings = (stats.count - 1) * per_copy_size;
69
50
  return {
70
51
  value: value.length > 200 ? value.substring(0, 200) + '...' : value,
71
52
  count: stats.count,
72
- total_size: stats.total_size,
73
- total_size_formatted: formatBytes(stats.total_size),
53
+ total_size: stats.totalSize,
54
+ total_size_formatted: formatBytes(stats.totalSize),
74
55
  potential_savings,
75
- example_node_ids: stats.example_node_ids,
56
+ example_node_ids: stats.exampleIds.slice(0, 3),
76
57
  field_context: null,
77
58
  actionability: null,
59
+ harness_what: null,
78
60
  };
79
61
  });
80
62
  if (duplicated.length === 0) {
@@ -131,7 +113,19 @@ export function registerDuplicatedStrings(server) {
131
113
  }
132
114
  }
133
115
  }
134
- if (appCount > 0 && frameworkCount > 0) {
116
+ // Non-production content outranks the app/framework split: whether it
117
+ // was injected by the measurement harness or exists only in a DEV
118
+ // build, it is not memory the shipped app has, so it must never be
119
+ // counted toward an interning win (see classifyNonProductionString).
120
+ const nonProd = classifyNonProductionString(d.value);
121
+ if (nonProd != null) {
122
+ d.actionability = 'harness';
123
+ d.harness_what =
124
+ nonProd.kind === 'dev-build'
125
+ ? `${nonProd.what} — DEV build only, absent in production`
126
+ : nonProd.what;
127
+ }
128
+ else if (appCount > 0 && frameworkCount > 0) {
135
129
  d.actionability = 'mixed';
136
130
  }
137
131
  else if (frameworkCount > 0) {
@@ -142,6 +136,8 @@ export function registerDuplicatedStrings(server) {
142
136
  }
143
137
  }
144
138
  const appActionableCount = duplicated.filter(d => d.actionability === 'app' || d.actionability === 'mixed').length;
139
+ const harnessEntries = duplicated.filter(d => d.actionability === 'harness');
140
+ const harnessBytes = harnessEntries.reduce((sum, d) => sum + d.potential_savings, 0);
145
141
  const lines = duplicated.map((d, i) => {
146
142
  const val = d.value.length > 80 ? d.value.slice(0, 80) + '...' : d.value;
147
143
  const nodeIdsPart = include_node_ids
@@ -150,7 +146,11 @@ export function registerDuplicatedStrings(server) {
150
146
  const context = d.field_context
151
147
  ? `\n commonly held as: ${d.field_context}`
152
148
  : '';
153
- const actionLabel = d.actionability ? ` [${d.actionability}]` : '';
149
+ const actionLabel = d.actionability === 'harness'
150
+ ? ` [harness — ${d.harness_what ?? 'measurement harness'}; not app memory]`
151
+ : d.actionability
152
+ ? ` [${d.actionability}]`
153
+ : '';
154
154
  const savingsLabel = d.potential_savings > 0
155
155
  ? `, savings: ${formatBytes(d.potential_savings)}`
156
156
  : '';
@@ -176,14 +176,23 @@ export function registerDuplicatedStrings(server) {
176
176
  'Consider string interning with a `Map<string, string>` pool applied at ingestion time, ' +
177
177
  'or deduplicating at the data source.');
178
178
  }
179
- const totalSavings = duplicated.reduce((sum, d) => sum + d.potential_savings, 0);
179
+ // Harness content is excluded from the headline: the number a caller
180
+ // acts on must be reclaimable from the application.
181
+ const totalSavings = duplicated.reduce((sum, d) => d.actionability === 'harness' ? sum : sum + d.potential_savings, 0);
180
182
  const summaryLine = appActionableCount > 0
181
183
  ? `${appActionableCount} of ${duplicated.length} entries are app-actionable`
182
184
  : `${duplicated.length} entries (all framework-held)`;
183
- const body = `Duplicated strings (${summaryLine}):\n\n${lines.join('\n')}\n\n**Total interning savings: ${formatBytes(totalSavings)}** (if each string were stored only once)`;
184
- return toolResult(suggestions.length > 0
185
+ const harnessNote = harnessEntries.length > 0
186
+ ? `\n\n⚠️ **${harnessEntries.length} entr${harnessEntries.length === 1 ? 'y' : 'ies'} (${formatBytes(harnessBytes)}) excluded from the total as measurement-harness content** — the CDP/devtools bridge injected into the page to drive this session, not application memory. Interning it reclaims nothing in production.`
187
+ : '';
188
+ // The two string tools answer different questions and their outputs
189
+ // used to restate each other. Say which is which, once, and note that
190
+ // the expensive scan is shared rather than repeated.
191
+ const relatedNote = `\n\n_This is the raw per-VALUE duplication table. \`memlab_intern_opportunities\` groups the same strings by property x parent shape and estimates what a canonical intern pool would actually reclaim (accounting for co-retention and the length cap) — use it to decide whether to write the fix, and this to see the values. It reuses this snapshot's string scan${reused ? ', which was itself already cached' : ''}, so running both costs one pass over the string nodes, not two._`;
192
+ const body = `Duplicated strings (${summaryLine}):\n\n${lines.join('\n')}\n\n**Total interning savings: ${formatBytes(totalSavings)}** (if each string were stored only once, harness content excluded)${harnessNote}${suggestionsSuppressed() ? '' : relatedNote}`;
193
+ return toolResult(withAnonymizedBanner(snapshot, suggestions.length > 0
185
194
  ? `${body}\n\n---\n\n${suggestions.join('\n')}`
186
- : body);
195
+ : body));
187
196
  }
188
197
  catch (err) {
189
198
  return errorResult(err);
@@ -1 +1 @@
1
- {"version":3,"file":"duplicated-strings.js","sourceRoot":"","sources":["../../src/tools/duplicated-strings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"duplicated-strings.js","sourceRoot":"","sources":["../../src/tools/duplicated-strings.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 registerEvalAcross(server: McpServer): void;
12
+ //# sourceMappingURL=eval-across.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval-across.d.ts","sourceRoot":"","sources":["../../src/tools/eval-across.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAuBvE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2I1D"}
@@ -0,0 +1,135 @@
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 { getCurrentHandle, getMetadataByHandle, listSnapshots, setCurrentSnapshot, } from '../heap-state.js';
12
+ import { errorResult, toolResult } from '../utils.js';
13
+ import { runEval } from './eval.js';
14
+ function textOf(result) {
15
+ const content = result?.content;
16
+ if (!Array.isArray(content))
17
+ return '(no output)';
18
+ return content
19
+ .map(c => (typeof c?.text === 'string' ? c.text : ''))
20
+ .join('\n')
21
+ .trim();
22
+ }
23
+ export function registerEvalAcross(server) {
24
+ server.tool('memlab_eval_across', 'Run ONE `memlab_eval` program against SEVERAL resident snapshots and return the results side by side. ' +
25
+ 'Exists because the interesting questions in a leak hunt are comparative — "how many of these were there at each rung?", ' +
26
+ '"did this collection grow?", "is the new population retained the same way as the old one?" — and answering them with ' +
27
+ '`memlab_eval` alone costs one switch + one paste + one manual diff per rung, which is enough friction that the question ' +
28
+ 'often just does not get asked. The code, the sandbox and the helper surface are identical to `memlab_eval` (this calls the ' +
29
+ 'same implementation, not a copy), so anything that runs there runs here.\n\n' +
30
+ 'Node ids are per-capture, so write code that computes COMPARABLE values (counts, sizes, shapes, string values) rather than ' +
31
+ 'code that hardcodes ids from one rung. `helpers.load(name)` still refuses cross-snapshot reads unless you pass ' +
32
+ '`{allowCrossSnapshot: true}`.\n\n' +
33
+ 'The active snapshot is restored when the run finishes, including on failure, so this does not disturb an in-progress investigation.', {
34
+ code: z
35
+ .string()
36
+ .describe('JavaScript to run against each snapshot. Same conventions as memlab_eval: assign to `result`, iterate with `snapshot.nodes.forEach`, use `helpers.*`. Run `memlab_eval({mode:"describe_env"})` for the full surface.'),
37
+ handles: z
38
+ .array(z.string())
39
+ .optional()
40
+ .describe('Snapshot handles to run against, in the order you want them reported (oldest rung first reads best). Defaults to every resident snapshot in load order.'),
41
+ timeout_ms: z
42
+ .number()
43
+ .optional()
44
+ .default(60000)
45
+ .describe('Execution timeout in milliseconds, applied PER snapshot (default 60000).'),
46
+ max_nodes: z
47
+ .number()
48
+ .int()
49
+ .min(1)
50
+ .optional()
51
+ .describe('Per-snapshot node-visit budget for full-heap walks. Defaults to a budget SCALED from each loaded graph (6 full passes, floored at 20,000,000). On overrun that rung reports a partial result instead of failing the whole run.'),
52
+ stop_on_error: z
53
+ .boolean()
54
+ .optional()
55
+ .default(false)
56
+ .describe('Stop at the first snapshot whose code throws (default false: record the error for that rung and continue, so one bad rung does not discard the others).'),
57
+ }, async ({ code, handles, timeout_ms, max_nodes, stop_on_error }) => {
58
+ const originalHandle = getCurrentHandle();
59
+ try {
60
+ const resident = listSnapshots().map(m => m.handle);
61
+ if (resident.length === 0) {
62
+ return errorResult(new Error('No snapshots are loaded. Load them with memlab_load_snapshot({keep_previous: true}) first — this tool compares snapshots that are already resident, it does not open files.'));
63
+ }
64
+ const targets = handles != null && handles.length > 0 ? handles : resident;
65
+ const unknown = targets.filter(h => getMetadataByHandle(h) == null);
66
+ if (unknown.length > 0) {
67
+ return errorResult(new Error(`Unknown snapshot handle(s): ${unknown.join(', ')}. Resident: ${resident.join(', ')}. ` +
68
+ 'Handles come from memlab_snapshots or the alias passed to memlab_load_snapshot.'));
69
+ }
70
+ if (targets.length < 2) {
71
+ // Not an error — a single-handle run is a legitimate way to script
72
+ // one rung — but the whole point of the tool is the comparison.
73
+ // Saying so beats silently returning a one-row report.
74
+ // (falls through and runs)
75
+ }
76
+ const sections = [];
77
+ let failures = 0;
78
+ for (const handle of targets) {
79
+ if (!setCurrentSnapshot(handle)) {
80
+ sections.push(`### ${handle}\n\n(could not switch to this snapshot)`);
81
+ failures++;
82
+ continue;
83
+ }
84
+ const meta = getMetadataByHandle(handle);
85
+ const header = `### ${handle}${meta ? ` — ${meta.fileName}` : ''}`;
86
+ try {
87
+ const res = await runEval({ code, timeout_ms, max_nodes });
88
+ const body = textOf(res);
89
+ if (/^Error:/m.test(body))
90
+ failures++;
91
+ sections.push(`${header}\n\n${body}`);
92
+ if (stop_on_error && /^Error:/m.test(body)) {
93
+ sections.push('_Stopped here: stop_on_error is set and this rung failed._');
94
+ break;
95
+ }
96
+ }
97
+ catch (err) {
98
+ failures++;
99
+ const msg = err instanceof Error ? err.message : String(err);
100
+ sections.push(`${header}\n\nError: ${msg}`);
101
+ if (stop_on_error) {
102
+ sections.push('_Stopped here: stop_on_error is set and this rung failed._');
103
+ break;
104
+ }
105
+ }
106
+ }
107
+ const lines = [
108
+ `## eval across ${targets.length} snapshot(s)`,
109
+ '',
110
+ `Order: ${targets.join(' → ')}${failures > 0 ? ` · ${failures} rung(s) reported an error` : ''}`,
111
+ '',
112
+ ...(targets.length < 2
113
+ ? [
114
+ '_Only one snapshot targeted — this tool exists for the comparison; load a second rung with `keep_previous: true` to get one._',
115
+ '',
116
+ ]
117
+ : []),
118
+ sections.join('\n\n'),
119
+ '',
120
+ '_Values are comparable across rungs; node IDS are not — they are assigned per capture. Compare counts, sizes, shapes and string values, never ids._',
121
+ ];
122
+ return toolResult(lines.join('\n'));
123
+ }
124
+ catch (err) {
125
+ return errorResult(err);
126
+ }
127
+ finally {
128
+ // Restore whatever the caller had active, so a comparison run is not a
129
+ // hidden state change for every tool that follows it.
130
+ if (originalHandle != null)
131
+ setCurrentSnapshot(originalHandle);
132
+ }
133
+ });
134
+ }
135
+ //# sourceMappingURL=eval-across.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval-across.js","sourceRoot":"","sources":["../../src/tools/eval-across.ts"],"names":[],"mappings":"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"}
@@ -8,5 +8,84 @@
8
8
  * @oncall memory_lab
9
9
  */
10
10
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
11
+ import { toolResult } from '../utils.js';
12
+ /**
13
+ * Wall-clock budget for one eval, scaled from the loaded graph.
14
+ *
15
+ * A fixed 60 s default is right for an indexed lookup and wrong for everything
16
+ * else: a full-heap walk on a 6M-node graph takes two to four minutes, so every
17
+ * large-snapshot eval aborted on its first attempt and had to be re-issued with
18
+ * an explicit `timeout_ms`. That is a guaranteed wasted call per question, and
19
+ * the node count needed to avoid it is already known.
20
+ *
21
+ * The floor stays at 60 s so small heaps behave exactly as before.
22
+ */
23
+ export declare function scaledEvalTimeoutMs(): number;
24
+ /**
25
+ * Default `max_nodes`, scaled to the loaded graph.
26
+ *
27
+ * A probe that makes several passes over the heap is the normal shape — one
28
+ * pass to census classes, one to match shapes, one to size things — so the
29
+ * budget has to be a MULTIPLE of the node count, not a constant. At the old
30
+ * flat 20,000,000 a routine two-pass probe on an 8.24M-node capture aborted
31
+ * mid-walk and returned a partial value; because the result was assigned after
32
+ * the loops, what came back was `undefined` with a note, which reads as a
33
+ * legitimate empty answer.
34
+ *
35
+ * Six passes is generous on purpose: the wall-clock timeout above is the real
36
+ * guard against a runaway eval, and this budget exists to stop pathological
37
+ * traversals, not ordinary multi-pass analysis.
38
+ */
39
+ export declare function scaledWalkBudget(): number;
40
+ /**
41
+ * Shorten a heap result STRUCTURALLY rather than mid-string.
42
+ *
43
+ * A census result is an array of rows or a `{key: count}` map, and cutting the
44
+ * JSON at a byte offset yields unparseable output plus a re-run with a
45
+ * hand-written limit — which is what actually happened to a detached-class
46
+ * census whose `blink::HeapVectorBacking<…>` keys blew the cap. Dropping whole
47
+ * entries keeps the value valid JSON and keeps the largest rows, which are the
48
+ * ones the question was about.
49
+ *
50
+ * Blink's C++ template names are elided first: they are frequently most of the
51
+ * payload and none of the information, and `abbreviateBlinkTypeName` is the same
52
+ * elision the table renderers already use.
53
+ */
54
+ export declare function shrinkResult(value: unknown, maxBytes: number): {
55
+ value: unknown;
56
+ truncated: boolean;
57
+ droppedEntries: number;
58
+ keptEntries: number;
59
+ };
60
+ export declare function unwrapNode<T>(node: T): T;
11
61
  export declare function registerEval(server: McpServer): void;
62
+ export declare function runEval({ mode, code, section, timeout_ms, save_as, max_nodes, sample, restrict_to_ids, dry_run, max_result_bytes, ownsScanBudget, }: {
63
+ mode?: 'eval' | 'describe_env' | 'list_saved' | 'lint';
64
+ code?: string;
65
+ section?: string;
66
+ timeout_ms?: number;
67
+ save_as?: string;
68
+ max_nodes?: number;
69
+ /** Visit every Nth node in a full-heap walk. 1/undefined = every node. */
70
+ sample?: number;
71
+ /** Restrict `snapshot.nodes.forEach` to these node ids. */
72
+ restrict_to_ids?: number[];
73
+ dry_run?: boolean;
74
+ max_result_bytes?: number;
75
+ /**
76
+ * True only for a direct `memlab_eval` MCP call, which owns the scan budget
77
+ * the guardrail armed for it and may therefore re-arm it to a scaled value.
78
+ * Left false by every in-process caller — `memlab_eval_across`,
79
+ * `memlab_ladder_probe`, `memlab_batch` — because those run MANY evals inside
80
+ * ONE MCP call and each re-arm would reset the shared wall clock.
81
+ */
82
+ ownsScanBudget?: boolean;
83
+ }): Promise<ReturnType<typeof toolResult>>;
84
+ /**
85
+ * A result that says "none of them" — 0, `[]`, `{}`, or an empty Map/Set.
86
+ *
87
+ * `undefined`/`null` are deliberately NOT included: those mean "the code
88
+ * assigned nothing", which is a different failure and is already handled.
89
+ */
90
+ export declare function isEmptyCensusResult(v: unknown): boolean;
12
91
  //# sourceMappingURL=eval.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"eval.d.ts","sourceRoot":"","sources":["../../src/tools/eval.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAmHvE,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsRpD"}
1
+ {"version":3,"file":"eval.d.ts","sourceRoot":"","sources":["../../src/tools/eval.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAuBvE,OAAO,EAGL,UAAU,EAgBX,MAAM,aAAa,CAAC;AAYrB;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAG5C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAGzC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,GACf;IACD,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB,CAkFA;AAwCD,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAMxC;AAiZD,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwIpD;AAqCD,wBAAsB,OAAO,CAAC,EAC5B,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,UAAU,EACV,OAAO,EACP,SAAS,EACT,MAAM,EACN,eAAe,EACf,OAAO,EACP,gBAAgB,EAChB,cAAc,GACf,EAAE;IACD,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,YAAY,GAAG,MAAM,CAAC;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAywDzC;AA2HD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAQvD"}