@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,46 @@
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
+ const NOOP = {
11
+ phase: () => {
12
+ // No progress channel and no stderr labelling to do for a caller that
13
+ // supplied no `extra` (in-process dispatch); reporting is simply off.
14
+ },
15
+ };
16
+ /**
17
+ * Build a reporter from a tool handler's `extra` argument.
18
+ *
19
+ * Tolerates a missing or empty `extra`: tools dispatched in-process by
20
+ * `memlab_batch` are called with `{}`, and a reporter that threw there would
21
+ * turn a progress nicety into a batch-wide failure.
22
+ */
23
+ export function makeProgressReporter(extra, label) {
24
+ if (extra == null || typeof extra !== 'object')
25
+ return NOOP;
26
+ const e = extra;
27
+ const token = e._meta?.progressToken;
28
+ const send = typeof e.sendNotification === 'function' ? e.sendNotification : null;
29
+ return {
30
+ phase(step, total, message) {
31
+ process.stderr.write(`[${label} ${step}/${total}] ${message}\n`);
32
+ if (send == null || token == null)
33
+ return;
34
+ // Fire-and-forget: a client that cannot accept the notification must not
35
+ // fail the operation the notification is about.
36
+ void send({
37
+ method: 'notifications/progress',
38
+ params: { progressToken: token, progress: step, total, message },
39
+ }).catch(() => {
40
+ // Swallowed on purpose: a client that rejects the notification must not
41
+ // fail the operation the notification is merely describing.
42
+ });
43
+ },
44
+ };
45
+ }
46
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6CH,MAAM,IAAI,GAAqB;IAC7B,KAAK,EAAE,GAAG,EAAE;QACV,sEAAsE;QACtE,sEAAsE;IACxE,CAAC;CACF,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAc,EACd,KAAa;IAEb,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC5D,MAAM,CAAC,GAAG,KAA6B,CAAC;IACxC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC;IACrC,MAAM,IAAI,GACR,OAAO,CAAC,CAAC,gBAAgB,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC;IAEvE,OAAO;QACL,KAAK,CAAC,IAAY,EAAE,KAAa,EAAE,OAAe;YAChD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,OAAO,IAAI,CAAC,CAAC;YACjE,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI;gBAAE,OAAO;YAC1C,yEAAyE;YACzE,gDAAgD;YAChD,KAAK,IAAI,CAAC;gBACR,MAAM,EAAE,wBAAwB;gBAChC,MAAM,EAAE,EAAC,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAC;aAC/D,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;gBACZ,wEAAwE;gBACxE,4DAA4D;YAC9D,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,42 @@
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
+ * Recognising React structures in a heap snapshot.
12
+ *
13
+ * Fibers, hooks, update queues and update records are ALL plain `Object` in a
14
+ * production bundle, so every class-name-based heuristic walks straight past
15
+ * them. On one population `helpers.owner()` returned `(none)` for 100% of
16
+ * 1,645 records for exactly this reason, and the useful answer —
17
+ * `BaseTooltipSimple` — needed a hand-written walk to the fiber plus a read of
18
+ * `elementType`.
19
+ *
20
+ * That walk has now been hand-written for four findings of the same family
21
+ * across this workstream. The `elementType` / `stateNode` / `memoizedProps`
22
+ * layout is stable across every React version Meta ships, so it belongs here
23
+ * rather than in each investigation.
24
+ */
25
+ import type { IHeapNode } from '@memlab/core';
26
+ /** Property set of a React update record — the eager-bailout leak family. */
27
+ export declare const UPDATE_RECORD_FIELDS: string[];
28
+ /** Does this node look like a React fiber? */
29
+ export declare function isFiberNode(node: IHeapNode): boolean;
30
+ /** Does this node look like a React update record (`queue.pending` member)? */
31
+ export declare function isUpdateRecord(node: IHeapNode): boolean;
32
+ /**
33
+ * The component name behind a fiber.
34
+ *
35
+ * Three shapes, in the order they occur: `elementType` is a closure (function
36
+ * component — the closure's own name is the component name), or a string (host
37
+ * element), or an object carrying `render` / `type` (memo, forwardRef, lazy),
38
+ * in which case the name is one level deeper.
39
+ */
40
+ export declare function fiberComponentName(fiber: IHeapNode): string | null;
41
+ export declare function nearestFiber(node: IHeapNode, maxHops: number): IHeapNode | null;
42
+ //# sourceMappingURL=react-shapes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-shapes.d.ts","sourceRoot":"","sources":["../src/react-shapes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAe5C,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,UAMhC,CAAC;AAYF,8CAA8C;AAC9C,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAOpD;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAWvD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAOlE;AAyCD,wBAAgB,YAAY,CAC1B,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,MAAM,GACd,SAAS,GAAG,IAAI,CAsBlB"}
@@ -0,0 +1,149 @@
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
+ * Fields that only a fiber carries. `stateNode` alone is too weak (a class
12
+ * instance has one), so a match needs `elementType` or `memoizedProps`, which
13
+ * together with `return`/`child` are fiber-specific.
14
+ */
15
+ const FIBER_STRONG_FIELDS = ['elementType', 'memoizedProps', 'pendingProps'];
16
+ const FIBER_SUPPORTING_FIELDS = [
17
+ 'return',
18
+ 'child',
19
+ 'stateNode',
20
+ 'memoizedState',
21
+ ];
22
+ /** Property set of a React update record — the eager-bailout leak family. */
23
+ export const UPDATE_RECORD_FIELDS = [
24
+ 'action',
25
+ 'eagerState',
26
+ 'hasEagerState',
27
+ 'lane',
28
+ 'next',
29
+ ];
30
+ /** Own property names of a node, as a Set. Cheap; used by every check here. */
31
+ function propertyNames(node) {
32
+ const names = new Set();
33
+ for (const edge of node.references) {
34
+ if (edge.type !== 'property')
35
+ continue;
36
+ names.add(String(edge.name_or_index));
37
+ }
38
+ return names;
39
+ }
40
+ /** Does this node look like a React fiber? */
41
+ export function isFiberNode(node) {
42
+ if (node.type !== 'object')
43
+ return false;
44
+ const names = propertyNames(node);
45
+ const strong = FIBER_STRONG_FIELDS.filter(f => names.has(f)).length;
46
+ if (strong === 0)
47
+ return false;
48
+ const supporting = FIBER_SUPPORTING_FIELDS.filter(f => names.has(f)).length;
49
+ return strong + supporting >= 3;
50
+ }
51
+ /** Does this node look like a React update record (`queue.pending` member)? */
52
+ export function isUpdateRecord(node) {
53
+ if (node.type !== 'object')
54
+ return false;
55
+ const names = propertyNames(node);
56
+ // `eagerState` may be absent when the update never took the eager path, so
57
+ // require the rest and treat it as optional.
58
+ return (names.has('action') &&
59
+ names.has('lane') &&
60
+ names.has('next') &&
61
+ (names.has('hasEagerState') || names.has('eagerState')));
62
+ }
63
+ /**
64
+ * The component name behind a fiber.
65
+ *
66
+ * Three shapes, in the order they occur: `elementType` is a closure (function
67
+ * component — the closure's own name is the component name), or a string (host
68
+ * element), or an object carrying `render` / `type` (memo, forwardRef, lazy),
69
+ * in which case the name is one level deeper.
70
+ */
71
+ export function fiberComponentName(fiber) {
72
+ for (const edge of fiber.references) {
73
+ if (edge.type !== 'property')
74
+ continue;
75
+ if (String(edge.name_or_index) !== 'elementType')
76
+ continue;
77
+ return elementTypeName(edge.toNode, 0);
78
+ }
79
+ return null;
80
+ }
81
+ function elementTypeName(node, depth) {
82
+ if (depth > 2)
83
+ return null;
84
+ if (node.type === 'string' || node.type === 'concatenated string') {
85
+ const value = node.toStringNode()?.stringValue ?? node.name;
86
+ return value ? `<${value}>` : null;
87
+ }
88
+ if (node.type === 'closure') {
89
+ // A minified bundle still names the closure after the component in the
90
+ // overwhelming majority of cases; an empty name is worth reporting as
91
+ // unknown rather than as "".
92
+ return node.name && node.name !== 'function' ? node.name : null;
93
+ }
94
+ // memo / forwardRef / lazy wrappers.
95
+ for (const edge of node.references) {
96
+ if (edge.type !== 'property')
97
+ continue;
98
+ const name = String(edge.name_or_index);
99
+ if (name !== 'render' && name !== 'type')
100
+ continue;
101
+ const inner = elementTypeName(edge.toNode, depth + 1);
102
+ if (inner != null)
103
+ return inner;
104
+ }
105
+ return null;
106
+ }
107
+ /**
108
+ * Walk up from a hook/queue/record to the fiber that owns it.
109
+ *
110
+ * Prefers the edges that actually lead there — a hook's owner is reached via
111
+ * `memoizedState` / `next` / `queue` / `baseQueue`, not by whatever referrer
112
+ * happens to come first — and falls back to any referrer so a slightly
113
+ * different shape still resolves.
114
+ */
115
+ const OWNER_EDGE_PREFERENCE = [
116
+ 'memoizedState',
117
+ 'queue',
118
+ 'baseQueue',
119
+ 'next',
120
+ 'return',
121
+ ];
122
+ export function nearestFiber(node, maxHops) {
123
+ let current = node;
124
+ const seen = new Set([node.id]);
125
+ for (let hop = 0; hop < maxHops; hop++) {
126
+ if (isFiberNode(current))
127
+ return current;
128
+ let chosen = null;
129
+ let fallback = null;
130
+ for (const edge of current.referrers) {
131
+ const from = edge.fromNode;
132
+ if (from.id <= 3 || seen.has(from.id))
133
+ continue;
134
+ if (OWNER_EDGE_PREFERENCE.includes(String(edge.name_or_index))) {
135
+ chosen = from;
136
+ break;
137
+ }
138
+ if (fallback == null)
139
+ fallback = from;
140
+ }
141
+ const next = chosen ?? fallback;
142
+ if (next == null)
143
+ return null;
144
+ seen.add(next.id);
145
+ current = next;
146
+ }
147
+ return null;
148
+ }
149
+ //# sourceMappingURL=react-shapes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-shapes.js","sourceRoot":"","sources":["../src/react-shapes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
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
+ export declare function resolveSavedNodeIds(name: string): number[];
11
+ //# sourceMappingURL=result-handles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-handles.d.ts","sourceRoot":"","sources":["../src/result-handles.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAuBH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA+C1D"}
@@ -0,0 +1,77 @@
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 { getEvalScratch } from './heap-state.js';
11
+ /**
12
+ * Read a saved result (from `memlab_eval`'s `save_as` / `helpers.save`) as a
13
+ * node-id list, so one tool's output can feed another's input without the ids
14
+ * making a round trip through the transcript.
15
+ *
16
+ * A list of a few thousand ids is tens of thousands of tokens to print and
17
+ * re-type, and re-typing them is where they get truncated or corrupted. The
18
+ * scratch store already existed for `eval`; this makes it readable by the tools
19
+ * that take `node_ids`, which is where such a list is actually wanted.
20
+ *
21
+ * Accepts the shapes a result realistically has: an array of numbers, an array
22
+ * of `{id}` objects, or an object with an `ids`/`node_ids` array.
23
+ */
24
+ // `memlab_eval` namespaces saved values in the shared per-snapshot scratch so
25
+ // they cannot collide with its own indexes. Reading them back means honoring
26
+ // that prefix — a bare-name lookup finds nothing and reports "not saved" for a
27
+ // result that is sitting right there.
28
+ const SAVED_PREFIX = '__saved:';
29
+ export function resolveSavedNodeIds(name) {
30
+ const scratch = getEvalScratch();
31
+ const prefixed = SAVED_PREFIX + name;
32
+ const key = prefixed in scratch ? prefixed : name;
33
+ if (!(key in scratch)) {
34
+ const available = Object.keys(scratch)
35
+ .filter(k => k.startsWith(SAVED_PREFIX))
36
+ .map(k => k.slice(SAVED_PREFIX.length));
37
+ throw new Error(`No saved result named "${name}". ` +
38
+ (available.length > 0
39
+ ? `Saved: ${available.join(', ')}.`
40
+ : 'Nothing is saved for this snapshot. Save one with memlab_eval({code, save_as: "name"}).') +
41
+ ' Saved results are per-snapshot and are dropped when the snapshot is replaced.');
42
+ }
43
+ const raw = scratch[key];
44
+ const fromArray = (arr) => {
45
+ const ids = [];
46
+ for (const item of arr) {
47
+ if (typeof item === 'number' && Number.isFinite(item)) {
48
+ ids.push(item);
49
+ }
50
+ else if (item != null && typeof item === 'object' && 'id' in item) {
51
+ const id = item.id;
52
+ if (typeof id === 'number')
53
+ ids.push(id);
54
+ }
55
+ }
56
+ return ids;
57
+ };
58
+ let ids = [];
59
+ if (Array.isArray(raw)) {
60
+ ids = fromArray(raw);
61
+ }
62
+ else if (raw != null && typeof raw === 'object') {
63
+ const obj = raw;
64
+ const arr = Array.isArray(obj.ids)
65
+ ? obj.ids
66
+ : Array.isArray(obj.node_ids)
67
+ ? obj.node_ids
68
+ : null;
69
+ if (arr != null)
70
+ ids = fromArray(arr);
71
+ }
72
+ if (ids.length === 0) {
73
+ throw new Error(`Saved result "${name}" holds no node ids. Expected an array of ids, an array of objects with an \`id\` field, or an object with an \`ids\` array.`);
74
+ }
75
+ return ids;
76
+ }
77
+ //# sourceMappingURL=result-handles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-handles.js","sourceRoot":"","sources":["../src/result-handles.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,cAAc,EAAC,MAAM,iBAAiB,CAAC;AAE/C;;;;;;;;;;;;GAYG;AACH,8EAA8E;AAC9E,6EAA6E;AAC7E,+EAA+E;AAC/E,sCAAsC;AACtC,MAAM,YAAY,GAAG,UAAU,CAAC;AAEhC,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IACjC,MAAM,QAAQ,GAAG,YAAY,GAAG,IAAI,CAAC;IACrC,MAAM,GAAG,GAAG,QAAQ,IAAI,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;IAClD,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE,CAAC;QACtB,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;aACnC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;aACvC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,0BAA0B,IAAI,KAAK;YACjC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;gBACnB,CAAC,CAAC,UAAU,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBACnC,CAAC,CAAC,yFAAyF,CAAC;YAC9F,gFAAgF,CACnF,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAY,OAAO,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,CAAC,GAAc,EAAY,EAAE;QAC7C,MAAM,GAAG,GAAa,EAAE,CAAC;QACzB,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;YACvB,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,CAAC;iBAAM,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;gBACpE,MAAM,EAAE,GAAI,IAAuB,CAAC,EAAE,CAAC;gBACvC,IAAI,OAAO,EAAE,KAAK,QAAQ;oBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;IACF,IAAI,GAAG,GAAa,EAAE,CAAC;IACvB,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;SAAM,IAAI,GAAG,IAAI,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAClD,MAAM,GAAG,GAAG,GAA0C,CAAC;QACvD,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAChC,CAAC,CAAC,GAAG,CAAC,GAAG;YACT,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;gBAC3B,CAAC,CAAC,GAAG,CAAC,QAAQ;gBACd,CAAC,CAAC,IAAI,CAAC;QACX,IAAI,GAAG,IAAI,IAAI;YAAE,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IACxC,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CACb,iBAAiB,IAAI,8HAA8H,CACpJ,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,19 @@
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
+ * The version this server reports about itself.
12
+ *
13
+ * Kept in its own module so `memlab_server_status` can report it without
14
+ * importing `index.ts` (which would be an import cycle — index imports every
15
+ * tool). Keep in sync with `package.json`; `scripts/check-version-sync.mjs`
16
+ * enforces that.
17
+ */
18
+ export declare const SERVER_VERSION = "2.86.0";
19
+ //# sourceMappingURL=server-version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-version.d.ts","sourceRoot":"","sources":["../src/server-version.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,WAAW,CAAC"}
@@ -0,0 +1,19 @@
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
+ * The version this server reports about itself.
12
+ *
13
+ * Kept in its own module so `memlab_server_status` can report it without
14
+ * importing `index.ts` (which would be an import cycle — index imports every
15
+ * tool). Keep in sync with `package.json`; `scripts/check-version-sync.mjs`
16
+ * enforces that.
17
+ */
18
+ export const SERVER_VERSION = '2.86.0';
19
+ //# sourceMappingURL=server-version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-version.js","sourceRoot":"","sources":["../src/server-version.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,QAAQ,CAAC"}
@@ -0,0 +1,67 @@
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 { IHeapSnapshot } from '@memlab/core';
11
+ /**
12
+ * Run `fn` against the snapshot at `localPath`, loading it only if it is not
13
+ * already resident, and leaving the session exactly as it was found.
14
+ *
15
+ * Every tool that walks an ORDERED ladder needs this, and each one getting it
16
+ * subtly wrong is the failure mode worth designing out. Three invariants:
17
+ *
18
+ * - **Reuse a resident graph.** Re-parsing a 250 MB capture that is already in
19
+ * memory is the single most expensive avoidable thing these tools do.
20
+ * - **Hold one graph at a time.** `memlab_eval_across` needs every rung
21
+ * resident simultaneously, which is precisely why it cannot serve a ladder of
22
+ * large captures. Loading and dropping keeps peak RSS at one rung.
23
+ * - **Restore the caller's active snapshot.** A ladder walk is a measurement,
24
+ * not a navigation; silently leaving the session pointed at rung 6 makes the
25
+ * caller's next `memlab_eval` answer a question about the wrong capture, and
26
+ * nothing in that output says so.
27
+ */
28
+ export declare function withSnapshotAt<T>(localPath: string, fn: (snapshot: IHeapSnapshot) => Promise<T> | T): Promise<T>;
29
+ export interface ResolvedRung {
30
+ /** The path as the caller wrote it, used in report rows. */
31
+ label: string;
32
+ localPath: string;
33
+ sizeMB: number;
34
+ }
35
+ /**
36
+ * Resolve every path and check its size BEFORE anything is loaded.
37
+ *
38
+ * Ordering matters here: an unreadable or oversized rung five should fail in a
39
+ * second, not after four multi-minute loads have already been paid for.
40
+ */
41
+ export declare function resolveRungs(paths: string[], maxFileSizeMB?: number): {
42
+ rungs: ResolvedRung[];
43
+ largestMB: number;
44
+ };
45
+ /**
46
+ * A full-heap walk on a multi-million-node graph does not finish inside the
47
+ * 60 s eval default, and every caller discovering that by timing out first is
48
+ * pure friction. Scale from the largest rung.
49
+ */
50
+ export declare function scaledTimeoutMs(largestMB: number, explicit?: number): number;
51
+ /**
52
+ * Re-arm the whole-heap scan guardrail for the work about to be done.
53
+ *
54
+ * Scaling a tool's own `timeout_ms` is NOT enough on its own, which is only
55
+ * obvious once you run against a big graph. The guardrail in `guardrail.ts`
56
+ * arms a 90s scan budget from the tool's incoming params before the handler
57
+ * runs; a tool that then computes a larger per-snapshot timeout is still inside
58
+ * that 90s budget, so a full-heap walk dies at 90s no matter what it asked for.
59
+ * Measured on a real 690 MB / 5.1M-node Ads Manager capture: a detached-node
60
+ * probe raised its eval timeout to 414s and still lost the rung to
61
+ * `Scan exceeded its 90000ms budget`.
62
+ *
63
+ * Re-arming per snapshot is what `memlab_analyze_run` already does for its
64
+ * steps. The guardrail's own `finally` disarms afterwards, so nothing leaks.
65
+ */
66
+ export declare function armScanBudgetFor(timeoutMs: number): void;
67
+ //# sourceMappingURL=snapshot-borrow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-borrow.d.ts","sourceRoot":"","sources":["../src/snapshot-borrow.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,cAAc,CAAC;AAkBhD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAC9C,OAAO,CAAC,CAAC,CAAC,CA+BZ;AAED,MAAM,WAAW,YAAY;IAC3B,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EAAE,EACf,aAAa,CAAC,EAAE,MAAM,GACrB;IAAC,KAAK,EAAE,YAAY,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAC,CAoB5C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAExD"}
@@ -0,0 +1,113 @@
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 memlabHeapAnalysis from '@memlab/heap-analysis';
12
+ const { getFullHeapFromFile } = memlabHeapAnalysis;
13
+ import { findResidentByPath, getCurrentHandle, getSnapshotByHandle, removeSnapshot, setCurrentSnapshot, setSnapshot, } from './heap-state.js';
14
+ import { beginAnalysisBudget } from './analysis-budget.js';
15
+ import { resolveMaxFileSizeMB, resolveSnapshotPath, } from './tools/load-snapshot.js';
16
+ /**
17
+ * Run `fn` against the snapshot at `localPath`, loading it only if it is not
18
+ * already resident, and leaving the session exactly as it was found.
19
+ *
20
+ * Every tool that walks an ORDERED ladder needs this, and each one getting it
21
+ * subtly wrong is the failure mode worth designing out. Three invariants:
22
+ *
23
+ * - **Reuse a resident graph.** Re-parsing a 250 MB capture that is already in
24
+ * memory is the single most expensive avoidable thing these tools do.
25
+ * - **Hold one graph at a time.** `memlab_eval_across` needs every rung
26
+ * resident simultaneously, which is precisely why it cannot serve a ladder of
27
+ * large captures. Loading and dropping keeps peak RSS at one rung.
28
+ * - **Restore the caller's active snapshot.** A ladder walk is a measurement,
29
+ * not a navigation; silently leaving the session pointed at rung 6 makes the
30
+ * caller's next `memlab_eval` answer a question about the wrong capture, and
31
+ * nothing in that output says so.
32
+ */
33
+ export async function withSnapshotAt(localPath, fn) {
34
+ const resident = findResidentByPath(localPath);
35
+ let snapshot = resident != null ? getSnapshotByHandle(resident.handle) : null;
36
+ const previousHandle = getCurrentHandle();
37
+ let temporaryHandle = null;
38
+ try {
39
+ if (snapshot == null) {
40
+ snapshot = await getFullHeapFromFile(localPath);
41
+ const meta = setSnapshot(snapshot, localPath, {
42
+ fileName: localPath.replace(/^.*\//, ''),
43
+ nodeCount: snapshot.nodes?.length ?? 0,
44
+ edgeCount: snapshot.edges?.length ?? 0,
45
+ totalSize: 0,
46
+ env: 'unknown',
47
+ }, { replace: false });
48
+ temporaryHandle = meta.handle;
49
+ }
50
+ else if (resident != null) {
51
+ setCurrentSnapshot(resident.handle);
52
+ }
53
+ return await fn(snapshot);
54
+ }
55
+ finally {
56
+ if (temporaryHandle != null)
57
+ removeSnapshot(temporaryHandle);
58
+ if (previousHandle != null)
59
+ setCurrentSnapshot(previousHandle);
60
+ }
61
+ }
62
+ /**
63
+ * Resolve every path and check its size BEFORE anything is loaded.
64
+ *
65
+ * Ordering matters here: an unreadable or oversized rung five should fail in a
66
+ * second, not after four multi-minute loads have already been paid for.
67
+ */
68
+ export function resolveRungs(paths, maxFileSizeMB) {
69
+ const rungs = [];
70
+ let largestMB = 0;
71
+ for (const p of paths) {
72
+ const { localPath, fetchedFrom } = resolveSnapshotPath(p);
73
+ if (!fs.existsSync(localPath)) {
74
+ throw new Error(`File not found: ${localPath}`);
75
+ }
76
+ const sizeMB = fs.statSync(localPath).size / (1024 * 1024);
77
+ largestMB = Math.max(largestMB, sizeMB);
78
+ const limit = resolveMaxFileSizeMB(maxFileSizeMB, fetchedFrom != null);
79
+ if (sizeMB > limit) {
80
+ throw new Error(`${p} is ${sizeMB.toFixed(0)} MB — exceeds the ${limit} MB per-file ` +
81
+ 'limit. Raise it with max_file_size_mb.');
82
+ }
83
+ rungs.push({ label: p.replace(/^.*\//, ''), localPath, sizeMB });
84
+ }
85
+ return { rungs, largestMB };
86
+ }
87
+ /**
88
+ * A full-heap walk on a multi-million-node graph does not finish inside the
89
+ * 60 s eval default, and every caller discovering that by timing out first is
90
+ * pure friction. Scale from the largest rung.
91
+ */
92
+ export function scaledTimeoutMs(largestMB, explicit) {
93
+ return explicit ?? Math.max(60000, Math.ceil(largestMB * 600));
94
+ }
95
+ /**
96
+ * Re-arm the whole-heap scan guardrail for the work about to be done.
97
+ *
98
+ * Scaling a tool's own `timeout_ms` is NOT enough on its own, which is only
99
+ * obvious once you run against a big graph. The guardrail in `guardrail.ts`
100
+ * arms a 90s scan budget from the tool's incoming params before the handler
101
+ * runs; a tool that then computes a larger per-snapshot timeout is still inside
102
+ * that 90s budget, so a full-heap walk dies at 90s no matter what it asked for.
103
+ * Measured on a real 690 MB / 5.1M-node Ads Manager capture: a detached-node
104
+ * probe raised its eval timeout to 414s and still lost the rung to
105
+ * `Scan exceeded its 90000ms budget`.
106
+ *
107
+ * Re-arming per snapshot is what `memlab_analyze_run` already does for its
108
+ * steps. The guardrail's own `finally` disarms afterwards, so nothing leaks.
109
+ */
110
+ export function armScanBudgetFor(timeoutMs) {
111
+ beginAnalysisBudget(timeoutMs);
112
+ }
113
+ //# sourceMappingURL=snapshot-borrow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-borrow.js","sourceRoot":"","sources":["../src/snapshot-borrow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
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
+ /**
12
+ * Per-value string duplication stats: how many copies, what they cost, and a
13
+ * bounded sample of node ids to follow up on.
14
+ */
15
+ export interface StringDupStats {
16
+ count: number;
17
+ totalSize: number;
18
+ exampleIds: number[];
19
+ /**
20
+ * Copies reachable ONLY through a dev/automation root. -1 when the index was
21
+ * built without the dev-root pass (see {@link buildStringIndex}).
22
+ */
23
+ devOnlyCount: number;
24
+ }
25
+ export interface StringIndex {
26
+ byValue: Map<string, StringDupStats>;
27
+ /** True when `devOnlyCount` is populated. */
28
+ hasDevOnly: boolean;
29
+ concatStringCount: number;
30
+ concatStringSize: number;
31
+ }
32
+ /**
33
+ * Build (or reuse) the per-value string duplication index for a snapshot.
34
+ *
35
+ * `memlab_duplicated_strings` and `memlab_intern_opportunities` were each doing
36
+ * their own full pass over every string node to build the same value → {count,
37
+ * size, ids} map, and both are commonly run back to back on the same snapshot —
38
+ * so the second one re-walked millions of nodes to recompute what the first had
39
+ * already produced. The scan is cached in the per-snapshot eval scratch, which
40
+ * already has exactly the lifecycle this needs: keyed by the active handle, and
41
+ * dropped when that snapshot is replaced or unloaded, so a stale index can never
42
+ * outlive the graph its node ids refer to.
43
+ *
44
+ * `withDevOnly` gates the dev/automation reachability pass, which is a whole-
45
+ * graph walk that only `intern_opportunities` needs. A cached index built
46
+ * without it is UPGRADED (rebuilt once) rather than silently returned, since
47
+ * `devOnlyCount: -1` would otherwise be read as "no dev-only copies".
48
+ */
49
+ export declare function buildStringIndex(snapshot: IHeapSnapshot, opts?: {
50
+ withDevOnly?: boolean;
51
+ isDevOnlyNode?: (node: IHeapNode) => boolean;
52
+ }): StringIndex;
53
+ /** True when this snapshot's string index is already built and resident. */
54
+ export declare function stringIndexIsCached(): boolean;
55
+ //# sourceMappingURL=string-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"string-index.d.ts","sourceRoot":"","sources":["../src/string-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAE,aAAa,EAAC,MAAM,cAAc,CAAC;AAG3D;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACrC,6CAA6C;IAC7C,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAQD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,aAAa,EACvB,IAAI,GAAE;IACJ,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC;CACzC,GACL,WAAW,CA8Db;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C"}