@lzehrung/codegraph 2.1.0 → 2.1.2

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 (536) hide show
  1. package/README.md +27 -29
  2. package/codegraph-skill/codegraph/SKILL.md +27 -26
  3. package/dist/agent/artifact.d.ts.map +1 -1
  4. package/dist/agent/artifact.js +105 -14
  5. package/dist/agent/artifact.js.map +1 -1
  6. package/dist/agent/candidateTests.d.ts +12 -0
  7. package/dist/agent/candidateTests.d.ts.map +1 -0
  8. package/dist/agent/candidateTests.js +17 -0
  9. package/dist/agent/candidateTests.js.map +1 -0
  10. package/dist/agent/explain.d.ts +3 -0
  11. package/dist/agent/explain.d.ts.map +1 -1
  12. package/dist/agent/explain.js +8 -0
  13. package/dist/agent/explain.js.map +1 -1
  14. package/dist/agent/explore.d.ts.map +1 -1
  15. package/dist/agent/explore.js +11 -6
  16. package/dist/agent/explore.js.map +1 -1
  17. package/dist/agent/fileView.d.ts.map +1 -1
  18. package/dist/agent/fileView.js +113 -120
  19. package/dist/agent/fileView.js.map +1 -1
  20. package/dist/agent/orient.d.ts.map +1 -1
  21. package/dist/agent/orient.js +7 -4
  22. package/dist/agent/orient.js.map +1 -1
  23. package/dist/agent/packet.d.ts.map +1 -1
  24. package/dist/agent/packet.js +5 -12
  25. package/dist/agent/packet.js.map +1 -1
  26. package/dist/agent/query-index/candidates.d.ts +13 -2
  27. package/dist/agent/query-index/candidates.d.ts.map +1 -1
  28. package/dist/agent/query-index/candidates.js +28 -39
  29. package/dist/agent/query-index/candidates.js.map +1 -1
  30. package/dist/agent/query-index/content.d.ts +1 -1
  31. package/dist/agent/query-index/content.js +4 -4
  32. package/dist/agent/query-index/content.js.map +1 -1
  33. package/dist/agent/query-index/schema.d.ts.map +1 -1
  34. package/dist/agent/query-index/schema.js.map +1 -1
  35. package/dist/agent/query-index/sessionStore.d.ts.map +1 -1
  36. package/dist/agent/query-index/sessionStore.js +42 -26
  37. package/dist/agent/query-index/sessionStore.js.map +1 -1
  38. package/dist/agent/query-index/store.d.ts +10 -4
  39. package/dist/agent/query-index/store.d.ts.map +1 -1
  40. package/dist/agent/query-index/store.js +115 -10
  41. package/dist/agent/query-index/store.js.map +1 -1
  42. package/dist/agent/query-index/update.d.ts.map +1 -1
  43. package/dist/agent/query-index/update.js +24 -9
  44. package/dist/agent/query-index/update.js.map +1 -1
  45. package/dist/agent/refactorPlan.d.ts.map +1 -1
  46. package/dist/agent/refactorPlan.js +6 -14
  47. package/dist/agent/refactorPlan.js.map +1 -1
  48. package/dist/agent/renamePreview.d.ts +2 -5
  49. package/dist/agent/renamePreview.d.ts.map +1 -1
  50. package/dist/agent/renamePreview.js +133 -80
  51. package/dist/agent/renamePreview.js.map +1 -1
  52. package/dist/agent/search.d.ts +3 -1
  53. package/dist/agent/search.d.ts.map +1 -1
  54. package/dist/agent/search.js +103 -35
  55. package/dist/agent/search.js.map +1 -1
  56. package/dist/agent/semanticSymbols.d.ts.map +1 -1
  57. package/dist/agent/semanticSymbols.js +2 -1
  58. package/dist/agent/semanticSymbols.js.map +1 -1
  59. package/dist/agent/session.d.ts +4 -0
  60. package/dist/agent/session.d.ts.map +1 -1
  61. package/dist/agent/session.js +20 -7
  62. package/dist/agent/session.js.map +1 -1
  63. package/dist/agent-tools.d.ts +1 -1
  64. package/dist/agent-tools.d.ts.map +1 -1
  65. package/dist/agent-tools.js +12 -21
  66. package/dist/agent-tools.js.map +1 -1
  67. package/dist/bin/cli.js +29242 -25373
  68. package/dist/bin/queryIndexWorker.js +131 -42
  69. package/dist/bin/rawQueryWorker.js +270 -0
  70. package/dist/chunking/chunkFile.d.ts +5 -0
  71. package/dist/chunking/chunkFile.d.ts.map +1 -1
  72. package/dist/chunking/chunkFile.js +14 -15
  73. package/dist/chunking/chunkFile.js.map +1 -1
  74. package/dist/cli/affected.d.ts.map +1 -1
  75. package/dist/cli/affected.js +17 -10
  76. package/dist/cli/affected.js.map +1 -1
  77. package/dist/cli/callHierarchy.d.ts.map +1 -1
  78. package/dist/cli/callHierarchy.js +9 -2
  79. package/dist/cli/callHierarchy.js.map +1 -1
  80. package/dist/cli/commandTable.d.ts.map +1 -1
  81. package/dist/cli/commandTable.js +16 -4
  82. package/dist/cli/commandTable.js.map +1 -1
  83. package/dist/cli/doctor.d.ts +7 -0
  84. package/dist/cli/doctor.d.ts.map +1 -1
  85. package/dist/cli/doctor.js +166 -0
  86. package/dist/cli/doctor.js.map +1 -1
  87. package/dist/cli/graph.d.ts +2 -1
  88. package/dist/cli/graph.d.ts.map +1 -1
  89. package/dist/cli/graph.js +60 -16
  90. package/dist/cli/graph.js.map +1 -1
  91. package/dist/cli/graphDelta.d.ts +2 -1
  92. package/dist/cli/graphDelta.d.ts.map +1 -1
  93. package/dist/cli/graphDelta.js +5 -0
  94. package/dist/cli/graphDelta.js.map +1 -1
  95. package/dist/cli/grep.d.ts +1 -1
  96. package/dist/cli/grep.d.ts.map +1 -1
  97. package/dist/cli/grep.js +14 -4
  98. package/dist/cli/grep.js.map +1 -1
  99. package/dist/cli/help.d.ts +34 -34
  100. package/dist/cli/help.d.ts.map +1 -1
  101. package/dist/cli/help.js +17 -8
  102. package/dist/cli/help.js.map +1 -1
  103. package/dist/cli/impact.d.ts +2 -1
  104. package/dist/cli/impact.d.ts.map +1 -1
  105. package/dist/cli/impact.js +5 -0
  106. package/dist/cli/impact.js.map +1 -1
  107. package/dist/cli/index.d.ts +2 -1
  108. package/dist/cli/index.d.ts.map +1 -1
  109. package/dist/cli/index.js +3 -0
  110. package/dist/cli/index.js.map +1 -1
  111. package/dist/cli/indexPolicy.d.ts.map +1 -1
  112. package/dist/cli/indexPolicy.js.map +1 -1
  113. package/dist/cli/inspect.d.ts +2 -1
  114. package/dist/cli/inspect.d.ts.map +1 -1
  115. package/dist/cli/inspect.js +25 -13
  116. package/dist/cli/inspect.js.map +1 -1
  117. package/dist/cli/install.js +1 -1
  118. package/dist/cli/install.js.map +1 -1
  119. package/dist/cli/invocationContext.d.ts.map +1 -1
  120. package/dist/cli/invocationContext.js +3 -0
  121. package/dist/cli/invocationContext.js.map +1 -1
  122. package/dist/cli/links.d.ts +2 -0
  123. package/dist/cli/links.d.ts.map +1 -1
  124. package/dist/cli/links.js +1 -1
  125. package/dist/cli/links.js.map +1 -1
  126. package/dist/cli/navigation.d.ts +41 -1
  127. package/dist/cli/navigation.d.ts.map +1 -1
  128. package/dist/cli/navigation.js +4 -1
  129. package/dist/cli/navigation.js.map +1 -1
  130. package/dist/cli/options.d.ts.map +1 -1
  131. package/dist/cli/options.js +32 -11
  132. package/dist/cli/options.js.map +1 -1
  133. package/dist/cli/renamePreview.d.ts.map +1 -1
  134. package/dist/cli/renamePreview.js +7 -1
  135. package/dist/cli/renamePreview.js.map +1 -1
  136. package/dist/cli/review.d.ts +2 -1
  137. package/dist/cli/review.d.ts.map +1 -1
  138. package/dist/cli/review.js +5 -0
  139. package/dist/cli/review.js.map +1 -1
  140. package/dist/cli/rootPolicy.d.ts.map +1 -1
  141. package/dist/cli/rootPolicy.js +36 -3
  142. package/dist/cli/rootPolicy.js.map +1 -1
  143. package/dist/cli/skill.js +2 -2
  144. package/dist/cli/skill.js.map +1 -1
  145. package/dist/cli/sql.js +1 -1
  146. package/dist/cli/symbols.d.ts.map +1 -1
  147. package/dist/cli/symbols.js +4 -2
  148. package/dist/cli/symbols.js.map +1 -1
  149. package/dist/cli/viewer.d.ts.map +1 -1
  150. package/dist/cli/viewer.js +46 -34
  151. package/dist/cli/viewer.js.map +1 -1
  152. package/dist/cli.d.ts.map +1 -1
  153. package/dist/cli.js +36 -16
  154. package/dist/cli.js.map +1 -1
  155. package/dist/config.d.ts +3 -0
  156. package/dist/config.d.ts.map +1 -1
  157. package/dist/config.js +35 -3
  158. package/dist/config.js.map +1 -1
  159. package/dist/documentLinks/check.d.ts +2 -1
  160. package/dist/documentLinks/check.d.ts.map +1 -1
  161. package/dist/documentLinks/check.js +22 -11
  162. package/dist/documentLinks/check.js.map +1 -1
  163. package/dist/duplicate-token-normalization.d.ts.map +1 -1
  164. package/dist/duplicate-token-normalization.js +10 -2
  165. package/dist/duplicate-token-normalization.js.map +1 -1
  166. package/dist/duplicates/scoring.d.ts +0 -10
  167. package/dist/duplicates/scoring.d.ts.map +1 -1
  168. package/dist/duplicates/scoring.js +9 -9
  169. package/dist/duplicates/scoring.js.map +1 -1
  170. package/dist/duplicates/types.d.ts +2 -0
  171. package/dist/duplicates/types.d.ts.map +1 -1
  172. package/dist/duplicates/unitCache.d.ts +15 -9
  173. package/dist/duplicates/unitCache.d.ts.map +1 -1
  174. package/dist/duplicates/unitCache.js +184 -33
  175. package/dist/duplicates/unitCache.js.map +1 -1
  176. package/dist/duplicates/units.d.ts +6 -15
  177. package/dist/duplicates/units.d.ts.map +1 -1
  178. package/dist/duplicates/units.js +42 -20
  179. package/dist/duplicates/units.js.map +1 -1
  180. package/dist/duplicates.d.ts.map +1 -1
  181. package/dist/duplicates.js +59 -0
  182. package/dist/duplicates.js.map +1 -1
  183. package/dist/frameworks/angularjs.d.ts.map +1 -1
  184. package/dist/frameworks/angularjs.js +18 -12
  185. package/dist/frameworks/angularjs.js.map +1 -1
  186. package/dist/graph-builder.d.ts.map +1 -1
  187. package/dist/graph-builder.js +12 -9
  188. package/dist/graph-builder.js.map +1 -1
  189. package/dist/graph-edge-collector.d.ts +1 -0
  190. package/dist/graph-edge-collector.d.ts.map +1 -1
  191. package/dist/graph-edge-collector.js +1 -1
  192. package/dist/graph-edge-collector.js.map +1 -1
  193. package/dist/graphs/grep.d.ts.map +1 -1
  194. package/dist/graphs/grep.js +7 -2
  195. package/dist/graphs/grep.js.map +1 -1
  196. package/dist/graphs/specifiers.d.ts.map +1 -1
  197. package/dist/graphs/specifiers.js +8 -2
  198. package/dist/graphs/specifiers.js.map +1 -1
  199. package/dist/graphs/symbol-graph-detailed.d.ts +10 -1
  200. package/dist/graphs/symbol-graph-detailed.d.ts.map +1 -1
  201. package/dist/graphs/symbol-graph-detailed.js +21 -5
  202. package/dist/graphs/symbol-graph-detailed.js.map +1 -1
  203. package/dist/impact/analyzer.d.ts.map +1 -1
  204. package/dist/impact/analyzer.js +19 -2
  205. package/dist/impact/analyzer.js.map +1 -1
  206. package/dist/impact/budgets.d.ts.map +1 -1
  207. package/dist/impact/budgets.js +5 -3
  208. package/dist/impact/budgets.js.map +1 -1
  209. package/dist/impact/call-compatibility/textScanner.d.ts +23 -0
  210. package/dist/impact/call-compatibility/textScanner.d.ts.map +1 -0
  211. package/dist/impact/call-compatibility/textScanner.js +615 -0
  212. package/dist/impact/call-compatibility/textScanner.js.map +1 -0
  213. package/dist/impact/callCompatibility.d.ts +8 -1
  214. package/dist/impact/callCompatibility.d.ts.map +1 -1
  215. package/dist/impact/callCompatibility.js +64 -587
  216. package/dist/impact/callCompatibility.js.map +1 -1
  217. package/dist/impact/context.d.ts.map +1 -1
  218. package/dist/impact/context.js +4 -1
  219. package/dist/impact/context.js.map +1 -1
  220. package/dist/impact/direct.d.ts +1 -1
  221. package/dist/impact/direct.d.ts.map +1 -1
  222. package/dist/impact/direct.js +7 -6
  223. package/dist/impact/direct.js.map +1 -1
  224. package/dist/impact/index.d.ts +6 -0
  225. package/dist/impact/index.d.ts.map +1 -1
  226. package/dist/impact/index.js +0 -8
  227. package/dist/impact/index.js.map +1 -1
  228. package/dist/impact/map.js +2 -2
  229. package/dist/impact/map.js.map +1 -1
  230. package/dist/impact/memberResolutionCoverage.d.ts.map +1 -1
  231. package/dist/impact/memberResolutionCoverage.js +5 -1
  232. package/dist/impact/memberResolutionCoverage.js.map +1 -1
  233. package/dist/impact/parse.d.ts.map +1 -1
  234. package/dist/impact/parse.js +108 -37
  235. package/dist/impact/parse.js.map +1 -1
  236. package/dist/impact/referenceCache.js +1 -1
  237. package/dist/impact/referenceCache.js.map +1 -1
  238. package/dist/impact/report-suggestions.d.ts.map +1 -1
  239. package/dist/impact/report-suggestions.js +347 -72
  240. package/dist/impact/report-suggestions.js.map +1 -1
  241. package/dist/impact/report.d.ts.map +1 -1
  242. package/dist/impact/report.js +13 -2
  243. package/dist/impact/report.js.map +1 -1
  244. package/dist/impact/reportCompact.d.ts.map +1 -1
  245. package/dist/impact/reportCompact.js +8 -0
  246. package/dist/impact/reportCompact.js.map +1 -1
  247. package/dist/impact/reportFull.d.ts.map +1 -1
  248. package/dist/impact/reportFull.js +1 -0
  249. package/dist/impact/reportFull.js.map +1 -1
  250. package/dist/impact/reportParts.d.ts +9 -0
  251. package/dist/impact/reportParts.d.ts.map +1 -1
  252. package/dist/impact/severity.d.ts +3 -2
  253. package/dist/impact/severity.d.ts.map +1 -1
  254. package/dist/impact/severity.js +16 -5
  255. package/dist/impact/severity.js.map +1 -1
  256. package/dist/impact/streaming.d.ts +32 -2
  257. package/dist/impact/streaming.d.ts.map +1 -1
  258. package/dist/impact/streaming.js +62 -3
  259. package/dist/impact/streaming.js.map +1 -1
  260. package/dist/impact/suggestions.d.ts.map +1 -1
  261. package/dist/impact/suggestions.js +1 -1
  262. package/dist/impact/suggestions.js.map +1 -1
  263. package/dist/impact/transitive.d.ts.map +1 -1
  264. package/dist/impact/transitive.js +13 -5
  265. package/dist/impact/transitive.js.map +1 -1
  266. package/dist/impact/types.d.ts +21 -20
  267. package/dist/impact/types.d.ts.map +1 -1
  268. package/dist/impact/types.js.map +1 -1
  269. package/dist/index.d.ts +2 -2
  270. package/dist/index.d.ts.map +1 -1
  271. package/dist/index.js +1 -1
  272. package/dist/index.js.map +1 -1
  273. package/dist/indexer/build-cache/location.d.ts +19 -0
  274. package/dist/indexer/build-cache/location.d.ts.map +1 -0
  275. package/dist/indexer/build-cache/location.js +132 -0
  276. package/dist/indexer/build-cache/location.js.map +1 -0
  277. package/dist/indexer/build-cache/manifest.d.ts +14 -6
  278. package/dist/indexer/build-cache/manifest.d.ts.map +1 -1
  279. package/dist/indexer/build-cache/manifest.js +194 -30
  280. package/dist/indexer/build-cache/manifest.js.map +1 -1
  281. package/dist/indexer/build-cache/module-cache.d.ts +24 -2
  282. package/dist/indexer/build-cache/module-cache.d.ts.map +1 -1
  283. package/dist/indexer/build-cache/module-cache.js +98 -32
  284. package/dist/indexer/build-cache/module-cache.js.map +1 -1
  285. package/dist/indexer/build-cache/options.d.ts +3 -1
  286. package/dist/indexer/build-cache/options.d.ts.map +1 -1
  287. package/dist/indexer/build-cache/options.js +10 -2
  288. package/dist/indexer/build-cache/options.js.map +1 -1
  289. package/dist/indexer/build-cache/project-snapshot.d.ts +33 -13
  290. package/dist/indexer/build-cache/project-snapshot.d.ts.map +1 -1
  291. package/dist/indexer/build-cache/project-snapshot.js +472 -91
  292. package/dist/indexer/build-cache/project-snapshot.js.map +1 -1
  293. package/dist/indexer/build-cache/reports.d.ts.map +1 -1
  294. package/dist/indexer/build-cache/reports.js +10 -1
  295. package/dist/indexer/build-cache/reports.js.map +1 -1
  296. package/dist/indexer/build-cache/resolver-environment.d.ts +9 -0
  297. package/dist/indexer/build-cache/resolver-environment.d.ts.map +1 -0
  298. package/dist/indexer/build-cache/resolver-environment.js +160 -0
  299. package/dist/indexer/build-cache/resolver-environment.js.map +1 -0
  300. package/dist/indexer/build-cache.d.ts +4 -3
  301. package/dist/indexer/build-cache.d.ts.map +1 -1
  302. package/dist/indexer/build-cache.js +4 -3
  303. package/dist/indexer/build-cache.js.map +1 -1
  304. package/dist/indexer/build-index.d.ts.map +1 -1
  305. package/dist/indexer/build-index.js +268 -96
  306. package/dist/indexer/build-index.js.map +1 -1
  307. package/dist/indexer/build-manifest.d.ts +1 -0
  308. package/dist/indexer/build-manifest.d.ts.map +1 -1
  309. package/dist/indexer/build-manifest.js +15 -5
  310. package/dist/indexer/build-manifest.js.map +1 -1
  311. package/dist/indexer/build-workers.d.ts +1 -1
  312. package/dist/indexer/build-workers.d.ts.map +1 -1
  313. package/dist/indexer/build-workers.js +57 -42
  314. package/dist/indexer/build-workers.js.map +1 -1
  315. package/dist/indexer/call-hierarchy.d.ts.map +1 -1
  316. package/dist/indexer/call-hierarchy.js.map +1 -1
  317. package/dist/indexer/finalize.d.ts.map +1 -1
  318. package/dist/indexer/finalize.js +7 -4
  319. package/dist/indexer/finalize.js.map +1 -1
  320. package/dist/indexer/import-types.d.ts +8 -0
  321. package/dist/indexer/import-types.d.ts.map +1 -1
  322. package/dist/indexer/imports/jsTextImports.d.ts.map +1 -1
  323. package/dist/indexer/imports/jsTextImports.js +14 -6
  324. package/dist/indexer/imports/jsTextImports.js.map +1 -1
  325. package/dist/indexer/imports/languageSpecific.d.ts.map +1 -1
  326. package/dist/indexer/imports/languageSpecific.js +10 -5
  327. package/dist/indexer/imports/languageSpecific.js.map +1 -1
  328. package/dist/indexer/imports/nativeCaptures.d.ts.map +1 -1
  329. package/dist/indexer/imports/nativeCaptures.js +4 -1
  330. package/dist/indexer/imports/nativeCaptures.js.map +1 -1
  331. package/dist/indexer/imports/python.d.ts.map +1 -1
  332. package/dist/indexer/imports/python.js +19 -9
  333. package/dist/indexer/imports/python.js.map +1 -1
  334. package/dist/indexer/incremental-plan.d.ts +2 -1
  335. package/dist/indexer/incremental-plan.d.ts.map +1 -1
  336. package/dist/indexer/incremental-plan.js +7 -4
  337. package/dist/indexer/incremental-plan.js.map +1 -1
  338. package/dist/indexer/load-current-index.d.ts.map +1 -1
  339. package/dist/indexer/load-current-index.js.map +1 -1
  340. package/dist/indexer/locals-and-exports.d.ts.map +1 -1
  341. package/dist/indexer/locals-and-exports.js +77 -22
  342. package/dist/indexer/locals-and-exports.js.map +1 -1
  343. package/dist/indexer/navigation-goto.d.ts.map +1 -1
  344. package/dist/indexer/navigation-goto.js +26 -16
  345. package/dist/indexer/navigation-goto.js.map +1 -1
  346. package/dist/indexer/navigation-local.d.ts.map +1 -1
  347. package/dist/indexer/navigation-local.js +7 -4
  348. package/dist/indexer/navigation-local.js.map +1 -1
  349. package/dist/indexer/navigation-references.d.ts +1 -1
  350. package/dist/indexer/navigation-references.d.ts.map +1 -1
  351. package/dist/indexer/navigation-references.js +34 -17
  352. package/dist/indexer/navigation-references.js.map +1 -1
  353. package/dist/indexer/navigation-resolve.d.ts.map +1 -1
  354. package/dist/indexer/navigation-resolve.js +116 -53
  355. package/dist/indexer/navigation-resolve.js.map +1 -1
  356. package/dist/indexer/navigation.d.ts +2 -1
  357. package/dist/indexer/navigation.d.ts.map +1 -1
  358. package/dist/indexer/navigation.js +34 -20
  359. package/dist/indexer/navigation.js.map +1 -1
  360. package/dist/indexer/parse-context.d.ts +2 -2
  361. package/dist/indexer/parse-context.d.ts.map +1 -1
  362. package/dist/indexer/parse-context.js +25 -4
  363. package/dist/indexer/parse-context.js.map +1 -1
  364. package/dist/indexer/reference-context.d.ts +2 -2
  365. package/dist/indexer/reference-context.d.ts.map +1 -1
  366. package/dist/indexer/reference-context.js +4 -2
  367. package/dist/indexer/reference-context.js.map +1 -1
  368. package/dist/indexer/scope-types.d.ts +3 -0
  369. package/dist/indexer/scope-types.d.ts.map +1 -1
  370. package/dist/indexer/scope.js +37 -38
  371. package/dist/indexer/scope.js.map +1 -1
  372. package/dist/indexer/shared.d.ts.map +1 -1
  373. package/dist/indexer/shared.js +3 -1
  374. package/dist/indexer/shared.js.map +1 -1
  375. package/dist/indexer/type-hierarchy.d.ts.map +1 -1
  376. package/dist/indexer/type-hierarchy.js +12 -8
  377. package/dist/indexer/type-hierarchy.js.map +1 -1
  378. package/dist/indexer/types.d.ts +27 -1
  379. package/dist/indexer/types.d.ts.map +1 -1
  380. package/dist/indexer/workspace-symbols.d.ts.map +1 -1
  381. package/dist/indexer/workspace-symbols.js +5 -3
  382. package/dist/indexer/workspace-symbols.js.map +1 -1
  383. package/dist/installer/locks.d.ts +10 -0
  384. package/dist/installer/locks.d.ts.map +1 -0
  385. package/dist/installer/locks.js +232 -0
  386. package/dist/installer/locks.js.map +1 -0
  387. package/dist/installer/registry.d.ts.map +1 -1
  388. package/dist/installer/registry.js +75 -235
  389. package/dist/installer/registry.js.map +1 -1
  390. package/dist/languages/definitions/csharp.d.ts.map +1 -1
  391. package/dist/languages/definitions/csharp.js +8 -0
  392. package/dist/languages/definitions/csharp.js.map +1 -1
  393. package/dist/languages/definitions/java.d.ts.map +1 -1
  394. package/dist/languages/definitions/java.js +3 -0
  395. package/dist/languages/definitions/java.js.map +1 -1
  396. package/dist/languages/definitions/python.d.ts.map +1 -1
  397. package/dist/languages/definitions/python.js +2 -0
  398. package/dist/languages/definitions/python.js.map +1 -1
  399. package/dist/languages/definitions/rust.d.ts.map +1 -1
  400. package/dist/languages/definitions/rust.js +2 -0
  401. package/dist/languages/definitions/rust.js.map +1 -1
  402. package/dist/languages/importStatementParsers.d.ts +2 -0
  403. package/dist/languages/importStatementParsers.d.ts.map +1 -1
  404. package/dist/languages/importStatementParsers.js +24 -10
  405. package/dist/languages/importStatementParsers.js.map +1 -1
  406. package/dist/mcp/http.d.ts +3 -1
  407. package/dist/mcp/http.d.ts.map +1 -1
  408. package/dist/mcp/http.js +69 -20
  409. package/dist/mcp/http.js.map +1 -1
  410. package/dist/mcp/server.d.ts +58 -16
  411. package/dist/mcp/server.d.ts.map +1 -1
  412. package/dist/mcp/server.js +447 -140
  413. package/dist/mcp/server.js.map +1 -1
  414. package/dist/mcp/tools.d.ts +51 -1
  415. package/dist/mcp/tools.d.ts.map +1 -1
  416. package/dist/mcp/tools.js +129 -3
  417. package/dist/mcp/tools.js.map +1 -1
  418. package/dist/native/byteIndex.d.ts +26 -0
  419. package/dist/native/byteIndex.d.ts.map +1 -0
  420. package/dist/native/byteIndex.js +70 -0
  421. package/dist/native/byteIndex.js.map +1 -0
  422. package/dist/native/projectedTree.d.ts +3 -2
  423. package/dist/native/projectedTree.d.ts.map +1 -1
  424. package/dist/native/projectedTree.js +6 -50
  425. package/dist/native/projectedTree.js.map +1 -1
  426. package/dist/native/queryResults.d.ts +7 -1
  427. package/dist/native/queryResults.d.ts.map +1 -1
  428. package/dist/native/queryResults.js +13 -5
  429. package/dist/native/queryResults.js.map +1 -1
  430. package/dist/review/candidates.d.ts.map +1 -1
  431. package/dist/review/candidates.js +4 -1
  432. package/dist/review/candidates.js.map +1 -1
  433. package/dist/review/changes.d.ts +2 -0
  434. package/dist/review/changes.d.ts.map +1 -1
  435. package/dist/review/changes.js +10 -0
  436. package/dist/review/changes.js.map +1 -1
  437. package/dist/review/deleted.d.ts.map +1 -1
  438. package/dist/review/deleted.js +20 -2
  439. package/dist/review/deleted.js.map +1 -1
  440. package/dist/review/summaries.d.ts +5 -0
  441. package/dist/review/summaries.d.ts.map +1 -1
  442. package/dist/review/summaries.js +32 -21
  443. package/dist/review/summaries.js.map +1 -1
  444. package/dist/review/types.d.ts +3 -1
  445. package/dist/review/types.d.ts.map +1 -1
  446. package/dist/review/types.js +8 -1
  447. package/dist/review/types.js.map +1 -1
  448. package/dist/review.d.ts.map +1 -1
  449. package/dist/review.js +14 -5
  450. package/dist/review.js.map +1 -1
  451. package/dist/session.d.ts +20 -4
  452. package/dist/session.d.ts.map +1 -1
  453. package/dist/session.js +76 -16
  454. package/dist/session.js.map +1 -1
  455. package/dist/sql/types.d.ts.map +1 -1
  456. package/dist/sqlite/query.d.ts +29 -0
  457. package/dist/sqlite/query.d.ts.map +1 -1
  458. package/dist/sqlite/query.js +98 -11
  459. package/dist/sqlite/query.js.map +1 -1
  460. package/dist/sqlite/rawQueryWorker.d.ts +22 -0
  461. package/dist/sqlite/rawQueryWorker.d.ts.map +1 -0
  462. package/dist/sqlite/rawQueryWorker.js +31 -0
  463. package/dist/sqlite/rawQueryWorker.js.map +1 -0
  464. package/dist/sqlite/rawQueryWorkerPool.d.ts +66 -0
  465. package/dist/sqlite/rawQueryWorkerPool.d.ts.map +1 -0
  466. package/dist/sqlite/rawQueryWorkerPool.js +142 -0
  467. package/dist/sqlite/rawQueryWorkerPool.js.map +1 -0
  468. package/dist/sqlite/schema.d.ts +2 -1
  469. package/dist/sqlite/schema.d.ts.map +1 -1
  470. package/dist/sqlite/schema.js +15 -1
  471. package/dist/sqlite/schema.js.map +1 -1
  472. package/dist/sqlite/write.d.ts.map +1 -1
  473. package/dist/sqlite/write.js +15 -0
  474. package/dist/sqlite/write.js.map +1 -1
  475. package/dist/sqlite-driver.d.ts +11 -0
  476. package/dist/sqlite-driver.d.ts.map +1 -1
  477. package/dist/sqlite-driver.js +28 -2
  478. package/dist/sqlite-driver.js.map +1 -1
  479. package/dist/sqlite.d.ts +1 -1
  480. package/dist/sqlite.d.ts.map +1 -1
  481. package/dist/sqlite.js +1 -1
  482. package/dist/sqlite.js.map +1 -1
  483. package/dist/util/bloomFilter.d.ts +3 -2
  484. package/dist/util/bloomFilter.d.ts.map +1 -1
  485. package/dist/util/bloomFilter.js +8 -8
  486. package/dist/util/bloomFilter.js.map +1 -1
  487. package/dist/util/concurrency.d.ts +1 -0
  488. package/dist/util/concurrency.d.ts.map +1 -1
  489. package/dist/util/concurrency.js +9 -2
  490. package/dist/util/concurrency.js.map +1 -1
  491. package/dist/util/confinedFile.d.ts +42 -2
  492. package/dist/util/confinedFile.d.ts.map +1 -1
  493. package/dist/util/confinedFile.js +114 -3
  494. package/dist/util/confinedFile.js.map +1 -1
  495. package/dist/util/errors.d.ts +2 -0
  496. package/dist/util/errors.d.ts.map +1 -1
  497. package/dist/util/errors.js +18 -0
  498. package/dist/util/errors.js.map +1 -1
  499. package/dist/util/git.d.ts +2 -0
  500. package/dist/util/git.d.ts.map +1 -1
  501. package/dist/util/git.js +174 -26
  502. package/dist/util/git.js.map +1 -1
  503. package/dist/util/identifiers.d.ts +75 -0
  504. package/dist/util/identifiers.d.ts.map +1 -0
  505. package/dist/util/identifiers.js +82 -0
  506. package/dist/util/identifiers.js.map +1 -0
  507. package/dist/util/paths.d.ts.map +1 -1
  508. package/dist/util/paths.js +45 -9
  509. package/dist/util/paths.js.map +1 -1
  510. package/dist/util/projectFiles.d.ts.map +1 -1
  511. package/dist/util/projectFiles.js +43 -14
  512. package/dist/util/projectFiles.js.map +1 -1
  513. package/dist/util/resolution/jvm.d.ts.map +1 -1
  514. package/dist/util/resolution/jvm.js +20 -9
  515. package/dist/util/resolution/jvm.js.map +1 -1
  516. package/dist/util/resolution/php.d.ts.map +1 -1
  517. package/dist/util/resolution/php.js +6 -5
  518. package/dist/util/resolution/php.js.map +1 -1
  519. package/dist/util/resolution/tsconfig.d.ts.map +1 -1
  520. package/dist/util/resolution/tsconfig.js +26 -12
  521. package/dist/util/resolution/tsconfig.js.map +1 -1
  522. package/dist/util/rustTestModules.d.ts.map +1 -1
  523. package/dist/util/rustTestModules.js +4 -2
  524. package/dist/util/rustTestModules.js.map +1 -1
  525. package/dist/util/specifiers.d.ts.map +1 -1
  526. package/dist/util/specifiers.js +10 -3
  527. package/dist/util/specifiers.js.map +1 -1
  528. package/dist/util/sqliteSchema.d.ts.map +1 -1
  529. package/dist/util/sqliteSchema.js +10 -1
  530. package/dist/util/sqliteSchema.js.map +1 -1
  531. package/dist/worker/nativeExtractWorker.d.ts +4 -2
  532. package/dist/worker/nativeExtractWorker.d.ts.map +1 -1
  533. package/dist/worker/nativeExtractWorker.js +12 -11
  534. package/dist/worker/nativeExtractWorker.js.map +1 -1
  535. package/docs/mcp.md +35 -14
  536. package/package.json +3 -3
@@ -6,29 +6,35 @@ import { buildGraphAdjacency } from "../../graphs/adjacency.js";
6
6
  import { buildReferenceCandidateIndex } from "../reference-candidates.js";
7
7
  import { BloomFilter, BloomFilterCache } from "../../util/bloomFilter.js";
8
8
  import { summarizeAnalysis } from "../../analysisSummary.js";
9
- import { fileIdentityKey, isFilePathWithinRoot, normalizePath } from "../../util/paths.js";
9
+ import { assertFilePathWithinRoot, fileIdentityKey, isFilePathWithinRoot, normalizePath } from "../../util/paths.js";
10
10
  import { getNativeRuntimeFingerprint } from "../../native/treeSitterNative.js";
11
+ import { logWithLevel } from "../../logging.js";
11
12
  import { SymbolKind } from "../types.js";
12
13
  import { buildSymbolGraph, } from "../../graphs/symbol-graph.js";
13
14
  import { getImplementationFingerprint, normalizeGraphOptions } from "./options.js";
14
- import { cacheRoot } from "./module-cache.js";
15
+ import { cacheAbsolutePath, cacheRelativePath, transformPersistedExportFromModule, } from "./module-cache.js";
16
+ import { cacheRoot } from "./location.js";
15
17
  const SNAPSHOT_SYMBOL_KINDS = new Set(Object.values(SymbolKind));
16
- const PROJECT_SNAPSHOT_VERSION = 4;
18
+ const PROJECT_SNAPSHOT_VERSION = 9;
19
+ export const BLOOM_FILTER_SNAPSHOT_VERSION = 4;
20
+ export const BLOOM_FILTER_SNAPSHOT_FILENAME = "bloom-filters.json";
17
21
  const BLOOM_FILTER_MIN_SIZE = 1_000;
18
22
  const BLOOM_FILTER_MAX_SIZE = 1_000_000;
19
23
  const BLOOM_FILTER_MIN_HASH_COUNT = 1;
20
24
  const BLOOM_FILTER_MAX_HASH_COUNT = 10;
21
- const DETAILED_SYMBOL_GRAPH_SNAPSHOT_VERSION = 2;
25
+ const DETAILED_SYMBOL_GRAPH_SNAPSHOT_VERSION = 3;
22
26
  const DETAILED_SYMBOL_GRAPH_SNAPSHOT_FILENAME = "detailed-symbol-graph.json";
23
27
  const SNAPSHOT_TEMP_RETENTION_MS = 24 * 60 * 60 * 1_000;
24
28
  const SNAPSHOT_TEMP_SUFFIX = ".tmp";
25
29
  const MAX_SNAPSHOT_CACHE_ENTRIES = 32;
26
30
  const parsedSnapshotCache = new Map();
31
+ const transformedSnapshotCache = new Map();
32
+ const transformedSnapshotModulesCache = new Map();
27
33
  const detailedSymbolGraphCache = new Map();
28
- export function projectSnapshotFilesSignature(entries) {
34
+ export function projectSnapshotFilesSignature(entries, projectRoot) {
29
35
  const hash = createHash("sha256");
30
36
  for (const [file, entry] of [...entries.entries()].sort(([left], [right]) => compareSnapshotPath(left, right))) {
31
- hash.update(file);
37
+ hash.update(projectRoot ? cacheRelativePath(projectRoot, file) : file);
32
38
  hash.update("\0");
33
39
  hash.update(entry.sig);
34
40
  hash.update("\0");
@@ -55,8 +61,115 @@ export function createProjectSnapshotIdentity(filesSignature, opts) {
55
61
  function serializedProjectRoot(projectRoot) {
56
62
  return normalizePath(path.resolve(projectRoot));
57
63
  }
58
- function projectRootMatches(projectRoot, storedProjectRoot) {
59
- return fileIdentityKey(path.resolve(projectRoot)) === fileIdentityKey(path.resolve(storedProjectRoot));
64
+ function transformPath(root, value, toRelative) {
65
+ if (toRelative) {
66
+ return path.isAbsolute(value) ? cacheRelativePath(root, value) : value;
67
+ }
68
+ return assertFilePathWithinRoot(root, cacheAbsolutePath(root, value), "Persisted cache path");
69
+ }
70
+ function transformHandle(root, value, toRelative) {
71
+ const separator = value.indexOf("::");
72
+ if (separator < 0)
73
+ return transformPath(root, value, toRelative);
74
+ const file = value.slice(0, separator);
75
+ return `${transformPath(root, file, toRelative)}${value.slice(separator)}`;
76
+ }
77
+ function transformModule(root, module, toRelative) {
78
+ const copy = structuredClone(module);
79
+ const file = (value) => transformPath(root, value, toRelative);
80
+ copy.file = file(copy.file);
81
+ for (const local of copy.locals)
82
+ local.file = file(local.file);
83
+ for (const entry of copy.exports) {
84
+ if (entry.type === "local") {
85
+ entry.target.file = file(entry.target.file);
86
+ }
87
+ else {
88
+ transformPersistedExportFromModule(root, entry, toRelative);
89
+ }
90
+ }
91
+ for (const binding of copy.imports) {
92
+ if (typeof binding.resolved === "string")
93
+ binding.resolved = file(binding.resolved);
94
+ }
95
+ return copy;
96
+ }
97
+ function transformSnapshotPaths(payload, root, toRelative) {
98
+ const copy = structuredClone(payload);
99
+ copy.graph.nodes = copy.graph.nodes.map((node) => transformPath(root, node, toRelative));
100
+ copy.graph.edges = copy.graph.edges.map((edge) => ({
101
+ ...edge,
102
+ from: transformPath(root, edge.from, toRelative),
103
+ to: edge.to.type === "file" ? { ...edge.to, path: transformPath(root, edge.to.path, toRelative) } : edge.to,
104
+ }));
105
+ copy.modules = copy.modules.map((module) => transformModule(root, module, toRelative));
106
+ if (copy.projectFiles) {
107
+ copy.projectFiles = copy.projectFiles.map((file) => ({
108
+ ...file,
109
+ path: transformPath(root, file.path, toRelative),
110
+ projectRoot: transformPath(root, file.projectRoot, toRelative),
111
+ }));
112
+ }
113
+ if (copy.bloomFilters) {
114
+ const bloomFilters = {};
115
+ for (const [file, filter] of Object.entries(copy.bloomFilters)) {
116
+ bloomFilters[transformPath(root, file, toRelative)] = filter;
117
+ }
118
+ copy.bloomFilters = bloomFilters;
119
+ }
120
+ const fileSignatures = {};
121
+ for (const [file, signature] of Object.entries(copy.fileSignatures ?? {})) {
122
+ fileSignatures[transformPath(root, file, toRelative)] = signature;
123
+ }
124
+ copy.fileSignatures = fileSignatures;
125
+ return copy;
126
+ }
127
+ function migrateProjectSnapshotPayload(value, currentRoot) {
128
+ if (!value || typeof value !== "object" || Array.isArray(value))
129
+ return value;
130
+ const payload = value;
131
+ if ((payload.version !== 4 && payload.version !== 5) || typeof payload.projectRoot !== "string")
132
+ return value;
133
+ const relative = transformSnapshotPaths(value, payload.projectRoot, true);
134
+ const migrated = transformSnapshotPaths(relative, currentRoot, false);
135
+ migrated.version = PROJECT_SNAPSHOT_VERSION;
136
+ migrated.projectRoot = serializedProjectRoot(currentRoot);
137
+ return migrated;
138
+ }
139
+ function transformDetailedGraph(graph, root, toRelative) {
140
+ return {
141
+ nodes: graph.nodes.map((node) => {
142
+ const file = transformPath(root, node.file, toRelative);
143
+ return { ...node, file, id: transformHandle(root, node.id, toRelative) };
144
+ }),
145
+ edges: graph.edges.map((edge) => ({
146
+ ...edge,
147
+ from: transformHandle(root, edge.from, toRelative),
148
+ to: transformHandle(root, edge.to, toRelative),
149
+ ...(edge.site
150
+ ? {
151
+ site: {
152
+ ...edge.site,
153
+ file: transformPath(root, edge.site.file, toRelative),
154
+ },
155
+ }
156
+ : {}),
157
+ })),
158
+ };
159
+ }
160
+ function migrateDetailedSymbolGraphPayload(value, currentRoot) {
161
+ if (!value || typeof value !== "object" || Array.isArray(value))
162
+ return value;
163
+ const payload = value;
164
+ if (payload.version !== 2 || typeof payload.projectRoot !== "string" || !payload.graph)
165
+ return value;
166
+ const relativeGraph = transformDetailedGraph(payload.graph, payload.projectRoot, true);
167
+ return {
168
+ ...payload,
169
+ version: DETAILED_SYMBOL_GRAPH_SNAPSHOT_VERSION,
170
+ projectRoot: serializedProjectRoot(currentRoot),
171
+ graph: transformDetailedGraph(relativeGraph, currentRoot, false),
172
+ };
60
173
  }
61
174
  function compareSnapshotPath(left, right) {
62
175
  if (left < right)
@@ -153,17 +266,30 @@ function materializeDetailedSymbolGraph(payload) {
153
266
  function decodeSnapshotPayload(compressed) {
154
267
  return JSON.parse(brotliDecompressSync(compressed).toString("utf8"));
155
268
  }
269
+ function recordSnapshotCorruption(report, artifact, reason, logLevel) {
270
+ if (report) {
271
+ report.manifest ??= { used: true, reused: false };
272
+ report.manifest.corruptions ??= [];
273
+ if (!report.manifest.corruptions.some((entry) => entry.artifact === artifact)) {
274
+ report.manifest.corruptions.push({ artifact, reason });
275
+ }
276
+ }
277
+ logWithLevel(logLevel, "warn", `Warning: Corrupt cache artifact ${artifact}: ${reason}`);
278
+ }
279
+ function isMissingArtifactError(error) {
280
+ return !!error && typeof error === "object" && "code" in error && error.code === "ENOENT";
281
+ }
156
282
  async function readParsedSnapshot(snapshotPath) {
157
283
  const before = await snapshotFileIdentity(snapshotPath);
158
284
  const cached = parsedSnapshotCache.get(snapshotPath);
159
285
  if (cached && sameSnapshotFileIdentity(cached.identity, before)) {
160
286
  setBoundedSnapshotCache(parsedSnapshotCache, snapshotPath, cached);
161
- return { identity: cached.identity, payload: decodeSnapshotPayload(cached.compressed) };
287
+ return { identity: cached.identity, payload: cached.payload };
162
288
  }
163
289
  const compressed = Buffer.from(await fsp.readFile(snapshotPath));
164
290
  const payload = decodeSnapshotPayload(compressed);
165
291
  const after = await snapshotFileIdentity(snapshotPath);
166
- const entry = { identity: before, compressed };
292
+ const entry = { identity: before, compressed, payload };
167
293
  if (sameSnapshotFileIdentity(before, after)) {
168
294
  setBoundedSnapshotCache(parsedSnapshotCache, snapshotPath, entry);
169
295
  }
@@ -172,6 +298,55 @@ async function readParsedSnapshot(snapshotPath) {
172
298
  }
173
299
  return { identity: before, payload };
174
300
  }
301
+ function transformCachedProjectSnapshot(snapshotPath, identity, rawPayload, projectRoot) {
302
+ const cached = transformedSnapshotCache.get(snapshotPath);
303
+ if (cached && cached.root === projectRoot && sameSnapshotFileIdentity(cached.identity, identity)) {
304
+ setBoundedSnapshotCache(transformedSnapshotCache, snapshotPath, cached);
305
+ return structuredClone(cached.payload);
306
+ }
307
+ const migratedPayload = migrateProjectSnapshotPayload(rawPayload, projectRoot);
308
+ const payload = migratedPayload && typeof migratedPayload === "object" && !Array.isArray(migratedPayload)
309
+ ? transformSnapshotPaths(migratedPayload, projectRoot, false)
310
+ : migratedPayload;
311
+ setBoundedSnapshotCache(transformedSnapshotCache, snapshotPath, { identity, root: projectRoot, payload });
312
+ return structuredClone(payload);
313
+ }
314
+ function transformCachedProjectSnapshotModules(snapshotPath, identity, rawPayload, projectRoot) {
315
+ const cached = transformedSnapshotModulesCache.get(snapshotPath);
316
+ if (cached && cached.root === projectRoot && sameSnapshotFileIdentity(cached.identity, identity)) {
317
+ setBoundedSnapshotCache(transformedSnapshotModulesCache, snapshotPath, cached);
318
+ return structuredClone(cached.payload);
319
+ }
320
+ const migratedPayload = migrateProjectSnapshotPayload(rawPayload, projectRoot);
321
+ if (!migratedPayload || typeof migratedPayload !== "object" || Array.isArray(migratedPayload)) {
322
+ return migratedPayload;
323
+ }
324
+ const payload = migratedPayload;
325
+ if (!Array.isArray(payload.modules) || !payload.fileSignatures || typeof payload.fileSignatures !== "object") {
326
+ return migratedPayload;
327
+ }
328
+ const modules = structuredClone(payload.modules).map((module) => transformModule(projectRoot, module, false));
329
+ const fileSignatures = {};
330
+ for (const [file, signature] of Object.entries(payload.fileSignatures)) {
331
+ fileSignatures[transformPath(projectRoot, file, false)] = signature;
332
+ }
333
+ const transformed = {
334
+ version: payload.version ?? PROJECT_SNAPSHOT_VERSION,
335
+ filesSignature: payload.filesSignature ?? "",
336
+ projectRoot: serializedProjectRoot(projectRoot),
337
+ ...(payload.nativeMode !== undefined ? { nativeMode: payload.nativeMode } : {}),
338
+ nativeRuntimeFingerprint: payload.nativeRuntimeFingerprint ?? "",
339
+ implementationFingerprint: payload.implementationFingerprint ?? "",
340
+ modules,
341
+ fileSignatures,
342
+ };
343
+ setBoundedSnapshotCache(transformedSnapshotModulesCache, snapshotPath, {
344
+ identity,
345
+ root: projectRoot,
346
+ payload: transformed,
347
+ });
348
+ return structuredClone(transformed);
349
+ }
175
350
  function projectIndexManifestEntries(entries) {
176
351
  return new Map(Array.from(entries, ([file, entry]) => [
177
352
  file,
@@ -181,24 +356,22 @@ function projectIndexManifestEntries(entries) {
181
356
  },
182
357
  ]));
183
358
  }
184
- export async function tryLoadProjectIndexSnapshot(projectRoot, opts, manifestEntries) {
185
- const filesSignature = projectSnapshotFilesSignature(manifestEntries);
359
+ export async function tryLoadProjectIndexSnapshot(projectRoot, opts, manifestEntries, report) {
360
+ const filesSignature = projectSnapshotFilesSignature(manifestEntries, projectRoot);
186
361
  if ((opts?.cache ?? "off") !== "disk")
187
362
  return null;
188
363
  try {
189
- const rawPayload = (await readParsedSnapshot(projectSnapshotPath(projectRoot, opts))).payload;
364
+ const parsedSnapshot = await readParsedSnapshot(projectSnapshotPath(projectRoot, opts));
365
+ const payload = transformCachedProjectSnapshot(projectSnapshotPath(projectRoot, opts), parsedSnapshot.identity, parsedSnapshot.payload, projectRoot);
190
366
  const nativeRuntimeFingerprint = getNativeRuntimeFingerprint(opts?.native);
191
367
  const implementationFingerprint = getImplementationFingerprint();
192
- if (!isProjectIndexSnapshotPayload(rawPayload) ||
193
- rawPayload.filesSignature !== filesSignature ||
194
- !projectRootMatches(projectRoot, rawPayload.projectRoot) ||
195
- rawPayload.nativeMode !== normalizedSnapshotNativeMode(opts?.native) ||
196
- rawPayload.nativeRuntimeFingerprint !== nativeRuntimeFingerprint ||
197
- rawPayload.implementationFingerprint !== implementationFingerprint) {
368
+ if (!isProjectIndexSnapshotPayload(payload) ||
369
+ payload.filesSignature !== filesSignature ||
370
+ payload.nativeMode !== normalizedSnapshotNativeMode(opts?.native) ||
371
+ payload.nativeRuntimeFingerprint !== nativeRuntimeFingerprint ||
372
+ payload.implementationFingerprint !== implementationFingerprint) {
198
373
  return null;
199
374
  }
200
- // Payload is freshly JSON.parsed from memoized compressed bytes (no deep clone).
201
- const payload = rawPayload;
202
375
  const graph = {
203
376
  nodes: new Set(payload.graph.nodes),
204
377
  edges: payload.graph.edges,
@@ -211,11 +384,12 @@ export async function tryLoadProjectIndexSnapshot(projectRoot, opts, manifestEnt
211
384
  modules,
212
385
  byFile: modules,
213
386
  projectRoot: serializedProjectRoot(projectRoot),
387
+ ...(payload.languageExtensions ? { languageExtensions: payload.languageExtensions } : {}),
214
388
  ...(payload.nativeMode ? { nativeMode: payload.nativeMode } : {}),
215
389
  exportCache: new Map(),
216
390
  scopeCache: new Map(),
217
391
  ...(shouldHydrateBloomFilters && payload.bloomFilters
218
- ? { bloomFilters: deserializeBloomFilterCache(payload.bloomFilters) }
392
+ ? { bloomFilters: deserializeBloomFilterCache(payload.bloomFilters, projectRoot) }
219
393
  : {}),
220
394
  ...(payload.projectFiles ? { projectFiles: payload.projectFiles } : {}),
221
395
  referenceCandidates: buildReferenceCandidateIndex(modules),
@@ -231,56 +405,157 @@ export async function tryLoadProjectIndexSnapshot(projectRoot, opts, manifestEnt
231
405
  ...(payload.analysisReport ? { analysisReport: payload.analysisReport } : {}),
232
406
  };
233
407
  }
234
- catch {
408
+ catch (error) {
409
+ if (!isMissingArtifactError(error)) {
410
+ recordSnapshotCorruption(report, projectSnapshotPath(projectRoot, opts), String(error), opts?.logLevel);
411
+ }
235
412
  return null;
236
413
  }
237
414
  }
238
415
  /**
239
- * Load only the bloom-filter section of the last-written project snapshot, without requiring
240
- * the whole snapshot to match this build's files signature or native runtime fingerprint.
241
- * Bloom filters are a pure function of a file's text, so a filter persisted for a given file
242
- * is safe to reuse after its snapshot's root and implementation fingerprints are validated.
243
- * Only the bloom section is then read, so a corrupt payload is rejected without walking
244
- * `graph.edges` / `modules`. Returns `null` when disk caching is off, `useBloomFilters` is
245
- * disabled, or no valid snapshot with bloom data exists.
416
+ * Load only modules and signatures from the last-written project snapshot. Path transforms avoid
417
+ * cloning the graph and project metadata, while each returned module remains caller-owned.
246
418
  */
247
- export async function tryLoadPersistedBloomFilters(projectRoot, opts) {
419
+ export async function tryLoadProjectSnapshotModules(projectRoot, opts, fileSignatures, report) {
420
+ if ((opts?.cache ?? "off") !== "disk")
421
+ return null;
422
+ try {
423
+ const parsedSnapshot = await readParsedSnapshot(projectSnapshotPath(projectRoot, opts));
424
+ const payload = transformCachedProjectSnapshotModules(projectSnapshotPath(projectRoot, opts), parsedSnapshot.identity, parsedSnapshot.payload, projectRoot);
425
+ const nativeRuntimeFingerprint = getNativeRuntimeFingerprint(opts?.native);
426
+ const implementationFingerprint = getImplementationFingerprint();
427
+ if (!isProjectSnapshotModulesPayload(payload) ||
428
+ payload.nativeMode !== normalizedSnapshotNativeMode(opts?.native) ||
429
+ payload.nativeRuntimeFingerprint !== nativeRuntimeFingerprint ||
430
+ payload.implementationFingerprint !== implementationFingerprint) {
431
+ return null;
432
+ }
433
+ const normalizedFileSignatures = new Map(Object.entries(payload.fileSignatures).map(([file, signature]) => [fileIdentityKey(file), signature]));
434
+ const normalizedCurrentSignatures = new Map(Array.from(fileSignatures, ([file, signature]) => [fileIdentityKey(file), signature]));
435
+ const modules = new Map();
436
+ for (const mod of payload.modules) {
437
+ const moduleKey = fileIdentityKey(mod.file);
438
+ const signature = normalizedCurrentSignatures.get(moduleKey);
439
+ const snapshotSignature = normalizedFileSignatures.get(moduleKey);
440
+ if (!signature || !snapshotSignature || !snapshotSignatureMatches(snapshotSignature, signature))
441
+ continue;
442
+ modules.set(moduleKey, mod);
443
+ }
444
+ return modules;
445
+ }
446
+ catch (error) {
447
+ if (!isMissingArtifactError(error)) {
448
+ recordSnapshotCorruption(report, projectSnapshotPath(projectRoot, opts), String(error), opts?.logLevel);
449
+ }
450
+ return null;
451
+ }
452
+ }
453
+ export async function tryLoadPersistedBloomFilters(projectRoot, opts, report) {
248
454
  if ((opts?.cache ?? "off") !== "disk" || (opts?.useBloomFilters ?? true) === false)
249
455
  return null;
456
+ try {
457
+ const sidecarPath = bloomFilterSnapshotPath(projectRoot, opts);
458
+ const sidecarParsed = (await readParsedSnapshot(sidecarPath)).payload;
459
+ const sidecarBloom = persistedBloomFiltersFromSidecar(sidecarParsed, projectRoot);
460
+ if (sidecarBloom) {
461
+ return createPersistedBloomFilters(sidecarBloom.bloomFilters, sidecarBloom.fileSignatures, projectRoot);
462
+ }
463
+ recordSnapshotCorruption(report, sidecarPath, "invalid bloom filter payload", opts?.logLevel);
464
+ }
465
+ catch (error) {
466
+ const isMissing = error && typeof error === "object" && "code" in error && error.code === "ENOENT";
467
+ if (!isMissing) {
468
+ recordSnapshotCorruption(report, bloomFilterSnapshotPath(projectRoot, opts), String(error), opts?.logLevel);
469
+ }
470
+ }
250
471
  try {
251
472
  const payload = (await readParsedSnapshot(projectSnapshotPath(projectRoot, opts))).payload;
252
473
  const bloomFilters = persistedBloomFiltersFromSnapshot(payload, projectRoot);
253
474
  if (!bloomFilters)
254
475
  return null;
255
- return deserializeBloomFilterCache(bloomFilters);
476
+ return createPersistedBloomFilters(bloomFilters.bloomFilters, bloomFilters.fileSignatures, projectRoot);
256
477
  }
257
- catch {
478
+ catch (error) {
479
+ const isMissing = error && typeof error === "object" && "code" in error && error.code === "ENOENT";
480
+ if (!isMissing) {
481
+ recordSnapshotCorruption(report, projectSnapshotPath(projectRoot, opts), String(error), opts?.logLevel);
482
+ }
258
483
  return null;
259
484
  }
260
485
  }
261
- /** Light validation for bloom hydration: snapshot version, root identity, and bloom section only. */
262
- function persistedBloomFiltersFromSnapshot(value, projectRoot) {
486
+ function persistedBloomFiltersFromSidecar(value, projectRoot) {
263
487
  if (!value || typeof value !== "object")
264
488
  return null;
265
489
  const payload = value;
490
+ if (payload.version !== BLOOM_FILTER_SNAPSHOT_VERSION ||
491
+ typeof payload.projectRoot !== "string" ||
492
+ payload.implementationFingerprint !== getImplementationFingerprint() ||
493
+ typeof payload.projectSnapshotIdentity !== "string" ||
494
+ !/^[a-f0-9]{64}$/.test(payload.projectSnapshotIdentity)) {
495
+ return null;
496
+ }
497
+ const bloomFilters = payload.bloomFilters;
498
+ const fileSignatures = payload.fileSignatures;
499
+ if (!isSerializedBloomFilterRecord(bloomFilters) || !isSnapshotFileSignatureRecord(fileSignatures)) {
500
+ return null;
501
+ }
502
+ return { bloomFilters, fileSignatures };
503
+ }
504
+ /** Light validation for bloom hydration: snapshot version, root identity, and bloom section only. */
505
+ function persistedBloomFiltersFromSnapshot(value, projectRoot) {
506
+ const migrated = migrateProjectSnapshotPayload(value, projectRoot);
507
+ if (!migrated || typeof migrated !== "object")
508
+ return null;
509
+ const payload = migrated;
266
510
  if (payload.version !== PROJECT_SNAPSHOT_VERSION ||
267
511
  typeof payload.projectRoot !== "string" ||
268
- !projectRootMatches(projectRoot, payload.projectRoot) ||
269
512
  payload.implementationFingerprint !== getImplementationFingerprint()) {
270
513
  return null;
271
514
  }
272
- if (!isSerializedBloomFilterRecord(payload.bloomFilters))
515
+ const bloomFilters = payload.bloomFilters;
516
+ const fileSignatures = payload.fileSignatures;
517
+ if (!isSerializedBloomFilterRecord(bloomFilters) || !isSnapshotFileSignatureRecord(fileSignatures)) {
273
518
  return null;
274
- return payload.bloomFilters;
519
+ }
520
+ return { bloomFilters, fileSignatures };
521
+ }
522
+ function createPersistedBloomFilters(bloomFilters, fileSignatures, projectRoot) {
523
+ const filters = deserializeBloomFilterCache(bloomFilters, projectRoot);
524
+ const signatures = new Map(Object.entries(fileSignatures).map(([file, signature]) => [
525
+ fileIdentityKey(cacheAbsolutePath(projectRoot, file)),
526
+ signature,
527
+ ]));
528
+ return {
529
+ get: (file, signature) => {
530
+ const persistedSignature = signatures.get(fileIdentityKey(file));
531
+ if (!persistedSignature || !snapshotSignatureMatches(persistedSignature, signature))
532
+ return undefined;
533
+ return filters.get(file);
534
+ },
535
+ };
536
+ }
537
+ function snapshotSignatureMatches(snapshotSignature, currentSignature) {
538
+ const matchingGitSignature = !!snapshotSignature.gitSig && !!currentSignature.gitSig && snapshotSignature.gitSig === currentSignature.gitSig;
539
+ if (matchingGitSignature)
540
+ return true;
541
+ // `cacheSig` is git- or content-hash-derived (forced whenever caching is enabled without a git
542
+ // signature; see `fileSignature()`), so when both sides have it, it is a strictly stronger and
543
+ // authoritative identity check than the cheap `mtime:size` `sig`. Comparing bare `sig` alone
544
+ // would wrongly treat a same-size edit whose mtime got restored as unchanged.
545
+ if (snapshotSignature.cacheSig !== undefined && currentSignature.cacheSig !== undefined) {
546
+ return snapshotSignature.cacheSig === currentSignature.cacheSig;
547
+ }
548
+ return snapshotSignature.sig === currentSignature.sig;
275
549
  }
276
550
  export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesSignature) {
277
551
  const projectSnapshotIdentity = createProjectSnapshotIdentity(filesSignature, opts);
552
+ const fileSignatures = serializeSnapshotFileSignatures(index.manifestEntries, projectRoot);
278
553
  const serializedBloomFilters = index.bloomFilters
279
- ? serializeBloomFilterCache(index.bloomFilters, Array.from(index.byFile.values(), (module) => module.file))
554
+ ? serializeBloomFilterCache(index.bloomFilters, Array.from(index.byFile.values(), (module) => module.file), projectRoot)
280
555
  : undefined;
281
556
  const snapshotAnalysisReport = analysisReportFromBuildReport(index.buildReport);
282
557
  const snapshotAnalysis = index.buildReport ? summarizeAnalysis({ index, report: index.buildReport }) : index.analysis;
283
- const payload = {
558
+ const payload = transformSnapshotPaths({
284
559
  version: PROJECT_SNAPSHOT_VERSION,
285
560
  filesSignature,
286
561
  projectRoot: serializedProjectRoot(projectRoot),
@@ -291,6 +566,8 @@ export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesS
291
566
  edges: index.graph.edges,
292
567
  },
293
568
  modules: [...index.byFile.values()],
569
+ fileSignatures,
570
+ ...(index.languageExtensions ? { languageExtensions: index.languageExtensions } : {}),
294
571
  ...(normalizedSnapshotNativeMode(index.nativeMode)
295
572
  ? { nativeMode: normalizedSnapshotNativeMode(index.nativeMode) }
296
573
  : {}),
@@ -298,7 +575,7 @@ export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesS
298
575
  ...(serializedBloomFilters ? { bloomFilters: serializedBloomFilters } : {}),
299
576
  ...(snapshotAnalysis ? { analysis: snapshotAnalysis } : {}),
300
577
  ...(snapshotAnalysisReport ? { analysisReport: snapshotAnalysisReport } : {}),
301
- };
578
+ }, projectRoot, true);
302
579
  try {
303
580
  const snapshotPath = projectSnapshotPath(projectRoot, opts);
304
581
  const compressed = brotliCompressSync(JSON.stringify(payload), {
@@ -306,8 +583,36 @@ export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesS
306
583
  });
307
584
  await writeSnapshotAtomically(snapshotPath, compressed);
308
585
  const identity = await snapshotFileIdentity(snapshotPath);
309
- setBoundedSnapshotCache(parsedSnapshotCache, snapshotPath, { identity, compressed });
586
+ transformedSnapshotCache.delete(snapshotPath);
587
+ transformedSnapshotModulesCache.delete(snapshotPath);
588
+ setBoundedSnapshotCache(parsedSnapshotCache, snapshotPath, { identity, compressed, payload });
310
589
  index.projectSnapshotIdentity = projectSnapshotIdentity;
590
+ if (serializedBloomFilters) {
591
+ try {
592
+ const bloomPayload = {
593
+ version: BLOOM_FILTER_SNAPSHOT_VERSION,
594
+ projectRoot: serializedProjectRoot(projectRoot),
595
+ implementationFingerprint: getImplementationFingerprint(),
596
+ projectSnapshotIdentity,
597
+ fileSignatures,
598
+ bloomFilters: serializedBloomFilters,
599
+ };
600
+ const bloomPath = bloomFilterSnapshotPath(projectRoot, opts);
601
+ const bloomCompressed = brotliCompressSync(JSON.stringify(bloomPayload), {
602
+ params: { [zlibConstants.BROTLI_PARAM_QUALITY]: 4 },
603
+ });
604
+ await writeSnapshotAtomically(bloomPath, bloomCompressed);
605
+ const bloomIdentity = await snapshotFileIdentity(bloomPath);
606
+ setBoundedSnapshotCache(parsedSnapshotCache, bloomPath, {
607
+ identity: bloomIdentity,
608
+ compressed: bloomCompressed,
609
+ payload: bloomPayload,
610
+ });
611
+ }
612
+ catch {
613
+ // Bloom sidecar write failure must not fail indexing
614
+ }
615
+ }
311
616
  }
312
617
  catch {
313
618
  delete index.projectSnapshotIdentity;
@@ -317,44 +622,13 @@ export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesS
317
622
  function projectSnapshotPath(projectRoot, opts) {
318
623
  return path.join(cacheRoot(projectRoot, opts), "project-index-snapshot.json");
319
624
  }
320
- export async function tryLoadDetailedSymbolGraphSnapshot(projectRoot, opts, index) {
321
- if ((opts?.cache ?? "off") !== "disk" || !index.projectSnapshotIdentity)
322
- return null;
323
- try {
324
- const snapshotPath = detailedSymbolGraphSnapshotPath(projectRoot, opts);
325
- const observedIdentity = await snapshotFileIdentity(snapshotPath);
326
- const cached = detailedSymbolGraphCache.get(snapshotPath);
327
- if (cached &&
328
- cached.projectSnapshotIdentity === index.projectSnapshotIdentity &&
329
- sameSnapshotFileIdentity(cached.identity, observedIdentity)) {
330
- setBoundedSnapshotCache(detailedSymbolGraphCache, snapshotPath, cached);
331
- return materializeDetailedSymbolGraph(cached.graph);
332
- }
333
- const parsed = await readParsedSnapshot(snapshotPath);
334
- const payload = parsed.payload;
335
- if (!isDetailedSymbolGraphSnapshotPayload(payload) ||
336
- !projectRootMatches(projectRoot, payload.projectRoot) ||
337
- payload.implementationFingerprint !== getImplementationFingerprint() ||
338
- payload.projectSnapshotIdentity !== index.projectSnapshotIdentity) {
339
- return null;
340
- }
341
- const graph = materializeDetailedSymbolGraph(payload.graph);
342
- if (!(await isDetailedSymbolGraphCompatibleWithProject(projectRoot, index, graph))) {
343
- return null;
344
- }
345
- const identity = await snapshotFileIdentity(snapshotPath);
346
- if (!sameSnapshotFileIdentity(parsed.identity, identity))
347
- return null;
348
- setBoundedSnapshotCache(detailedSymbolGraphCache, snapshotPath, {
349
- identity,
350
- projectSnapshotIdentity: index.projectSnapshotIdentity,
351
- graph: payload.graph,
352
- });
353
- return graph;
354
- }
355
- catch {
356
- return null;
625
+ function bloomFilterSnapshotPath(projectRoot, opts) {
626
+ const root = path.resolve(cacheRoot(projectRoot, opts));
627
+ const snapshotPath = path.resolve(root, BLOOM_FILTER_SNAPSHOT_FILENAME);
628
+ if (!isFilePathWithinRoot(root, snapshotPath)) {
629
+ throw new Error(`Bloom filter snapshot escaped cache root: ${snapshotPath}`);
357
630
  }
631
+ return snapshotPath;
358
632
  }
359
633
  export async function writeDetailedSymbolGraphSnapshot(projectRoot, opts, index, graph) {
360
634
  if ((opts?.cache ?? "off") !== "disk" || !index.projectSnapshotIdentity)
@@ -365,26 +639,29 @@ export async function writeDetailedSymbolGraphSnapshot(projectRoot, opts, index,
365
639
  implementationFingerprint: getImplementationFingerprint(),
366
640
  graphHash: detailedSymbolGraphContentHash(index.projectSnapshotIdentity, graph),
367
641
  projectSnapshotIdentity: index.projectSnapshotIdentity,
368
- graph: {
642
+ graph: transformDetailedGraph({
369
643
  nodes: [...graph.nodes.values()],
370
644
  edges: graph.edges,
371
- },
645
+ }, projectRoot, true),
372
646
  };
373
647
  try {
374
648
  const snapshotPath = detailedSymbolGraphSnapshotPath(projectRoot, opts);
375
649
  parsedSnapshotCache.delete(snapshotPath);
650
+ transformedSnapshotModulesCache.delete(snapshotPath);
376
651
  detailedSymbolGraphCache.delete(snapshotPath);
377
652
  const compressed = brotliCompressSync(JSON.stringify(payload), {
378
653
  params: { [zlibConstants.BROTLI_PARAM_QUALITY]: 4 },
379
654
  });
380
655
  await writeSnapshotAtomically(snapshotPath, compressed);
381
656
  const identity = await snapshotFileIdentity(snapshotPath);
382
- const cachedPayload = structuredClone(payload);
383
- setBoundedSnapshotCache(parsedSnapshotCache, snapshotPath, { identity, compressed });
657
+ setBoundedSnapshotCache(parsedSnapshotCache, snapshotPath, { identity, compressed, payload });
384
658
  setBoundedSnapshotCache(detailedSymbolGraphCache, snapshotPath, {
385
659
  identity,
386
660
  projectSnapshotIdentity: index.projectSnapshotIdentity,
387
- graph: cachedPayload.graph,
661
+ graph: {
662
+ nodes: [...graph.nodes.values()],
663
+ edges: graph.edges,
664
+ },
388
665
  });
389
666
  }
390
667
  catch {
@@ -399,6 +676,57 @@ function detailedSymbolGraphSnapshotPath(projectRoot, opts) {
399
676
  }
400
677
  return snapshotPath;
401
678
  }
679
+ export async function tryLoadDetailedSymbolGraphSnapshot(projectRoot, opts, index, report) {
680
+ if ((opts?.cache ?? "off") !== "disk" || !index.projectSnapshotIdentity)
681
+ return null;
682
+ const snapshotPath = detailedSymbolGraphSnapshotPath(projectRoot, opts);
683
+ try {
684
+ const observedIdentity = await snapshotFileIdentity(snapshotPath);
685
+ const cached = detailedSymbolGraphCache.get(snapshotPath);
686
+ if (cached &&
687
+ cached.projectSnapshotIdentity === index.projectSnapshotIdentity &&
688
+ sameSnapshotFileIdentity(cached.identity, observedIdentity)) {
689
+ setBoundedSnapshotCache(detailedSymbolGraphCache, snapshotPath, cached);
690
+ return materializeDetailedSymbolGraph(cached.graph);
691
+ }
692
+ const parsed = await readParsedSnapshot(snapshotPath);
693
+ const migratedPayload = migrateDetailedSymbolGraphPayload(parsed.payload, projectRoot);
694
+ const payload = migratedPayload && typeof migratedPayload === "object" && !Array.isArray(migratedPayload)
695
+ ? {
696
+ ...migratedPayload,
697
+ graph: transformDetailedGraph(migratedPayload.graph, projectRoot, false),
698
+ }
699
+ : migratedPayload;
700
+ if (!isDetailedSymbolGraphSnapshotPayload(payload) ||
701
+ payload.implementationFingerprint !== getImplementationFingerprint() ||
702
+ payload.projectSnapshotIdentity !== index.projectSnapshotIdentity) {
703
+ recordSnapshotCorruption(report, snapshotPath, "invalid detailed symbol graph payload", opts?.logLevel);
704
+ return null;
705
+ }
706
+ const graph = materializeDetailedSymbolGraph(payload.graph);
707
+ if (!(await isDetailedSymbolGraphCompatibleWithProject(projectRoot, index, graph))) {
708
+ recordSnapshotCorruption(report, snapshotPath, "detailed symbol graph does not match project", opts?.logLevel);
709
+ return null;
710
+ }
711
+ const identity = await snapshotFileIdentity(snapshotPath);
712
+ if (!sameSnapshotFileIdentity(parsed.identity, identity)) {
713
+ recordSnapshotCorruption(report, snapshotPath, "detailed symbol graph changed while reading", opts?.logLevel);
714
+ return null;
715
+ }
716
+ setBoundedSnapshotCache(detailedSymbolGraphCache, snapshotPath, {
717
+ identity,
718
+ projectSnapshotIdentity: index.projectSnapshotIdentity,
719
+ graph: payload.graph,
720
+ });
721
+ return graph;
722
+ }
723
+ catch (error) {
724
+ if (!isMissingArtifactError(error)) {
725
+ recordSnapshotCorruption(report, snapshotPath, String(error), opts?.logLevel);
726
+ }
727
+ return null;
728
+ }
729
+ }
402
730
  function detailedSymbolGraphContentHash(projectSnapshotIdentity, graph) {
403
731
  const hash = createHash("sha256");
404
732
  hash.update(projectSnapshotIdentity);
@@ -642,6 +970,21 @@ function isProjectFileType(value) {
642
970
  function isProjectFileRole(value) {
643
971
  return value === "manifest" || value === "lockfile" || value === "config" || value === "solution" || value === "ide";
644
972
  }
973
+ function isProjectSnapshotModulesPayload(value) {
974
+ if (!value || typeof value !== "object")
975
+ return false;
976
+ const payload = value;
977
+ return (payload.version === PROJECT_SNAPSHOT_VERSION &&
978
+ typeof payload.filesSignature === "string" &&
979
+ typeof payload.projectRoot === "string" &&
980
+ typeof payload.nativeRuntimeFingerprint === "string" &&
981
+ typeof payload.implementationFingerprint === "string" &&
982
+ /^[a-f0-9]{64}$/.test(payload.implementationFingerprint) &&
983
+ Array.isArray(payload.modules) &&
984
+ payload.modules.every(isModuleIndex) &&
985
+ isSnapshotFileSignatureRecord(payload.fileSignatures) &&
986
+ (payload.nativeMode === undefined || isSnapshotNativeMode(payload.nativeMode)));
987
+ }
645
988
  function isProjectIndexSnapshotPayload(value) {
646
989
  if (!value || typeof value !== "object")
647
990
  return false;
@@ -659,7 +1002,9 @@ function isProjectIndexSnapshotPayload(value) {
659
1002
  payload.graph.edges.every(isGraphEdge) &&
660
1003
  Array.isArray(payload.modules) &&
661
1004
  payload.modules.every(isModuleIndex) &&
1005
+ isSnapshotFileSignatureRecord(payload.fileSignatures) &&
662
1006
  (payload.nativeMode === undefined || isSnapshotNativeMode(payload.nativeMode)) &&
1007
+ (payload.languageExtensions === undefined || isLanguageExtensionMap(payload.languageExtensions)) &&
663
1008
  (payload.bloomFilters === undefined || isSerializedBloomFilterRecord(payload.bloomFilters)) &&
664
1009
  (payload.analysis === undefined || isAnalysisSummary(payload.analysis)) &&
665
1010
  (payload.analysisReport === undefined || isSnapshotAnalysisReport(payload.analysisReport)) &&
@@ -746,14 +1091,14 @@ function isAnalysisSummary(value) {
746
1091
  typeof summary.nativeFilesFellBack === "number" &&
747
1092
  typeof summary.label === "string");
748
1093
  }
749
- function serializeBloomFilterCache(cache, files) {
1094
+ function serializeBloomFilterCache(cache, files, projectRoot) {
750
1095
  const serialized = {};
751
1096
  for (const file of files) {
752
1097
  const filter = cache.get(file);
753
1098
  if (!filter)
754
1099
  continue;
755
1100
  const metadata = filter.getMetadata();
756
- serialized[file] = {
1101
+ serialized[cacheRelativePath(projectRoot, file)] = {
757
1102
  size: metadata.size,
758
1103
  hashCount: metadata.hashCount,
759
1104
  bitsBase64: filter.toBuffer().toString("base64"),
@@ -761,10 +1106,35 @@ function serializeBloomFilterCache(cache, files) {
761
1106
  }
762
1107
  return Object.keys(serialized).length ? serialized : undefined;
763
1108
  }
764
- function deserializeBloomFilterCache(serialized) {
1109
+ function serializeSnapshotFileSignatures(entries, projectRoot) {
1110
+ const serialized = {};
1111
+ for (const [file, entry] of entries ?? []) {
1112
+ serialized[cacheRelativePath(projectRoot, file)] = {
1113
+ sig: entry.sig,
1114
+ ...(entry.gitSig ? { gitSig: entry.gitSig } : {}),
1115
+ ...(entry.cacheSig ? { cacheSig: entry.cacheSig } : {}),
1116
+ };
1117
+ }
1118
+ return serialized;
1119
+ }
1120
+ function isSnapshotFileSignatureRecord(value) {
1121
+ if (!value || typeof value !== "object" || Array.isArray(value))
1122
+ return false;
1123
+ return Object.values(value).every(isSnapshotFileSignature);
1124
+ }
1125
+ function isSnapshotFileSignature(value) {
1126
+ if (!value || typeof value !== "object" || Array.isArray(value))
1127
+ return false;
1128
+ const signature = value;
1129
+ return (typeof signature.sig === "string" &&
1130
+ (signature.gitSig === undefined || typeof signature.gitSig === "string") &&
1131
+ (signature.cacheSig === undefined || typeof signature.cacheSig === "string"));
1132
+ }
1133
+ function deserializeBloomFilterCache(serialized, projectRoot) {
765
1134
  const cache = new BloomFilterCache();
766
1135
  for (const [file, filter] of Object.entries(serialized)) {
767
- cache.set(file, BloomFilter.fromBuffer(Buffer.from(filter.bitsBase64, "base64"), filter.size, filter.hashCount));
1136
+ const absoluteFile = assertFilePathWithinRoot(projectRoot, cacheAbsolutePath(projectRoot, file), "Persisted cache path");
1137
+ cache.set(absoluteFile, BloomFilter.fromBuffer(Buffer.from(filter.bitsBase64, "base64"), filter.size, filter.hashCount));
768
1138
  }
769
1139
  return cache;
770
1140
  }
@@ -773,6 +1143,11 @@ function isSerializedBloomFilterRecord(value) {
773
1143
  return false;
774
1144
  return Object.values(value).every(isSerializedBloomFilter);
775
1145
  }
1146
+ function isLanguageExtensionMap(value) {
1147
+ if (!value || typeof value !== "object" || Array.isArray(value))
1148
+ return false;
1149
+ return Object.values(value).every((entry) => typeof entry === "string");
1150
+ }
776
1151
  function isSerializedBloomFilter(value) {
777
1152
  if (!value || typeof value !== "object")
778
1153
  return false;
@@ -788,9 +1163,15 @@ function isSerializedBloomFilter(value) {
788
1163
  typeof filter.bitsBase64 !== "string") {
789
1164
  return false;
790
1165
  }
791
- const maxBytes = Math.ceil(filter.size / 8);
792
- const maxBase64Length = Math.ceil(maxBytes / 3) * 4;
793
- return filter.bitsBase64.length === maxBase64Length;
1166
+ const expectedBytes = Math.ceil(filter.size / 8);
1167
+ let decoded;
1168
+ try {
1169
+ decoded = Buffer.from(filter.bitsBase64, "base64");
1170
+ }
1171
+ catch {
1172
+ return false;
1173
+ }
1174
+ return decoded.length === expectedBytes && decoded.toString("base64") === filter.bitsBase64;
794
1175
  }
795
1176
  function isModuleIndex(value) {
796
1177
  if (!value || typeof value !== "object")