@lzehrung/codegraph 2.1.0 → 2.1.1

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 (426) hide show
  1. package/README.md +27 -29
  2. package/codegraph-skill/codegraph/SKILL.md +23 -21
  3. package/dist/agent/candidateTests.d.ts +12 -0
  4. package/dist/agent/candidateTests.d.ts.map +1 -0
  5. package/dist/agent/candidateTests.js +17 -0
  6. package/dist/agent/candidateTests.js.map +1 -0
  7. package/dist/agent/explore.d.ts.map +1 -1
  8. package/dist/agent/explore.js +9 -6
  9. package/dist/agent/explore.js.map +1 -1
  10. package/dist/agent/fileView.d.ts.map +1 -1
  11. package/dist/agent/fileView.js +113 -120
  12. package/dist/agent/fileView.js.map +1 -1
  13. package/dist/agent/orient.d.ts.map +1 -1
  14. package/dist/agent/orient.js +5 -4
  15. package/dist/agent/orient.js.map +1 -1
  16. package/dist/agent/query-index/candidates.d.ts +13 -2
  17. package/dist/agent/query-index/candidates.d.ts.map +1 -1
  18. package/dist/agent/query-index/candidates.js +28 -39
  19. package/dist/agent/query-index/candidates.js.map +1 -1
  20. package/dist/agent/query-index/schema.d.ts.map +1 -1
  21. package/dist/agent/query-index/schema.js.map +1 -1
  22. package/dist/agent/query-index/sessionStore.d.ts.map +1 -1
  23. package/dist/agent/query-index/sessionStore.js +42 -26
  24. package/dist/agent/query-index/sessionStore.js.map +1 -1
  25. package/dist/agent/query-index/store.d.ts +7 -0
  26. package/dist/agent/query-index/store.d.ts.map +1 -1
  27. package/dist/agent/query-index/store.js +71 -0
  28. package/dist/agent/query-index/store.js.map +1 -1
  29. package/dist/agent/refactorPlan.d.ts.map +1 -1
  30. package/dist/agent/refactorPlan.js +6 -14
  31. package/dist/agent/refactorPlan.js.map +1 -1
  32. package/dist/agent/renamePreview.d.ts +2 -5
  33. package/dist/agent/renamePreview.d.ts.map +1 -1
  34. package/dist/agent/renamePreview.js +82 -78
  35. package/dist/agent/renamePreview.js.map +1 -1
  36. package/dist/agent/search.d.ts.map +1 -1
  37. package/dist/agent/search.js +39 -17
  38. package/dist/agent/search.js.map +1 -1
  39. package/dist/agent/semanticSymbols.d.ts.map +1 -1
  40. package/dist/agent/semanticSymbols.js +2 -1
  41. package/dist/agent/semanticSymbols.js.map +1 -1
  42. package/dist/agent/session.d.ts +4 -0
  43. package/dist/agent/session.d.ts.map +1 -1
  44. package/dist/agent/session.js +19 -6
  45. package/dist/agent/session.js.map +1 -1
  46. package/dist/agent-tools.d.ts +1 -1
  47. package/dist/agent-tools.d.ts.map +1 -1
  48. package/dist/agent-tools.js +6 -15
  49. package/dist/agent-tools.js.map +1 -1
  50. package/dist/bin/cli.js +27556 -24941
  51. package/dist/bin/queryIndexWorker.js +47 -6
  52. package/dist/bin/rawQueryWorker.js +246 -0
  53. package/dist/chunking/chunkFile.d.ts +5 -0
  54. package/dist/chunking/chunkFile.d.ts.map +1 -1
  55. package/dist/chunking/chunkFile.js +14 -15
  56. package/dist/chunking/chunkFile.js.map +1 -1
  57. package/dist/cli/affected.d.ts.map +1 -1
  58. package/dist/cli/affected.js +17 -10
  59. package/dist/cli/affected.js.map +1 -1
  60. package/dist/cli/commandTable.d.ts.map +1 -1
  61. package/dist/cli/commandTable.js +15 -3
  62. package/dist/cli/commandTable.js.map +1 -1
  63. package/dist/cli/doctor.d.ts +7 -0
  64. package/dist/cli/doctor.d.ts.map +1 -1
  65. package/dist/cli/doctor.js +166 -0
  66. package/dist/cli/doctor.js.map +1 -1
  67. package/dist/cli/graph.d.ts +2 -1
  68. package/dist/cli/graph.d.ts.map +1 -1
  69. package/dist/cli/graph.js +8 -0
  70. package/dist/cli/graph.js.map +1 -1
  71. package/dist/cli/graphDelta.d.ts +2 -1
  72. package/dist/cli/graphDelta.d.ts.map +1 -1
  73. package/dist/cli/graphDelta.js +5 -0
  74. package/dist/cli/graphDelta.js.map +1 -1
  75. package/dist/cli/help.d.ts +34 -34
  76. package/dist/cli/help.d.ts.map +1 -1
  77. package/dist/cli/help.js +17 -8
  78. package/dist/cli/help.js.map +1 -1
  79. package/dist/cli/impact.d.ts +2 -1
  80. package/dist/cli/impact.d.ts.map +1 -1
  81. package/dist/cli/impact.js +5 -0
  82. package/dist/cli/impact.js.map +1 -1
  83. package/dist/cli/index.d.ts +2 -1
  84. package/dist/cli/index.d.ts.map +1 -1
  85. package/dist/cli/index.js +3 -0
  86. package/dist/cli/index.js.map +1 -1
  87. package/dist/cli/indexPolicy.d.ts.map +1 -1
  88. package/dist/cli/indexPolicy.js.map +1 -1
  89. package/dist/cli/inspect.d.ts +2 -1
  90. package/dist/cli/inspect.d.ts.map +1 -1
  91. package/dist/cli/inspect.js +25 -13
  92. package/dist/cli/inspect.js.map +1 -1
  93. package/dist/cli/invocationContext.d.ts.map +1 -1
  94. package/dist/cli/invocationContext.js +3 -0
  95. package/dist/cli/invocationContext.js.map +1 -1
  96. package/dist/cli/links.d.ts +2 -0
  97. package/dist/cli/links.d.ts.map +1 -1
  98. package/dist/cli/links.js +1 -1
  99. package/dist/cli/links.js.map +1 -1
  100. package/dist/cli/navigation.d.ts +41 -1
  101. package/dist/cli/navigation.d.ts.map +1 -1
  102. package/dist/cli/navigation.js +4 -1
  103. package/dist/cli/navigation.js.map +1 -1
  104. package/dist/cli/options.d.ts.map +1 -1
  105. package/dist/cli/options.js +9 -7
  106. package/dist/cli/options.js.map +1 -1
  107. package/dist/cli/review.d.ts +2 -1
  108. package/dist/cli/review.d.ts.map +1 -1
  109. package/dist/cli/review.js +5 -0
  110. package/dist/cli/review.js.map +1 -1
  111. package/dist/cli/skill.js +1 -1
  112. package/dist/cli/skill.js.map +1 -1
  113. package/dist/cli/viewer.d.ts.map +1 -1
  114. package/dist/cli/viewer.js +46 -34
  115. package/dist/cli/viewer.js.map +1 -1
  116. package/dist/config.d.ts +3 -0
  117. package/dist/config.d.ts.map +1 -1
  118. package/dist/config.js +35 -3
  119. package/dist/config.js.map +1 -1
  120. package/dist/documentLinks/check.d.ts +2 -1
  121. package/dist/documentLinks/check.d.ts.map +1 -1
  122. package/dist/documentLinks/check.js +2 -2
  123. package/dist/documentLinks/check.js.map +1 -1
  124. package/dist/duplicate-token-normalization.d.ts.map +1 -1
  125. package/dist/duplicate-token-normalization.js +10 -2
  126. package/dist/duplicate-token-normalization.js.map +1 -1
  127. package/dist/duplicates/scoring.d.ts +0 -10
  128. package/dist/duplicates/scoring.d.ts.map +1 -1
  129. package/dist/duplicates/scoring.js +9 -9
  130. package/dist/duplicates/scoring.js.map +1 -1
  131. package/dist/duplicates/unitCache.d.ts +15 -9
  132. package/dist/duplicates/unitCache.d.ts.map +1 -1
  133. package/dist/duplicates/unitCache.js +184 -33
  134. package/dist/duplicates/unitCache.js.map +1 -1
  135. package/dist/duplicates/units.d.ts +6 -15
  136. package/dist/duplicates/units.d.ts.map +1 -1
  137. package/dist/duplicates/units.js +36 -18
  138. package/dist/duplicates/units.js.map +1 -1
  139. package/dist/frameworks/angularjs.d.ts.map +1 -1
  140. package/dist/frameworks/angularjs.js +18 -12
  141. package/dist/frameworks/angularjs.js.map +1 -1
  142. package/dist/graph-builder.d.ts.map +1 -1
  143. package/dist/graph-builder.js +12 -9
  144. package/dist/graph-builder.js.map +1 -1
  145. package/dist/graph-edge-collector.d.ts +1 -0
  146. package/dist/graph-edge-collector.d.ts.map +1 -1
  147. package/dist/graph-edge-collector.js +1 -1
  148. package/dist/graph-edge-collector.js.map +1 -1
  149. package/dist/graphs/grep.d.ts.map +1 -1
  150. package/dist/graphs/grep.js +7 -2
  151. package/dist/graphs/grep.js.map +1 -1
  152. package/dist/graphs/specifiers.d.ts.map +1 -1
  153. package/dist/graphs/specifiers.js +8 -2
  154. package/dist/graphs/specifiers.js.map +1 -1
  155. package/dist/graphs/symbol-graph-detailed.d.ts.map +1 -1
  156. package/dist/graphs/symbol-graph-detailed.js +3 -1
  157. package/dist/graphs/symbol-graph-detailed.js.map +1 -1
  158. package/dist/impact/analyzer.d.ts.map +1 -1
  159. package/dist/impact/analyzer.js +15 -1
  160. package/dist/impact/analyzer.js.map +1 -1
  161. package/dist/impact/call-compatibility/textScanner.d.ts +23 -0
  162. package/dist/impact/call-compatibility/textScanner.d.ts.map +1 -0
  163. package/dist/impact/call-compatibility/textScanner.js +615 -0
  164. package/dist/impact/call-compatibility/textScanner.js.map +1 -0
  165. package/dist/impact/callCompatibility.d.ts.map +1 -1
  166. package/dist/impact/callCompatibility.js +9 -570
  167. package/dist/impact/callCompatibility.js.map +1 -1
  168. package/dist/impact/direct.js +7 -6
  169. package/dist/impact/direct.js.map +1 -1
  170. package/dist/impact/index.d.ts +6 -0
  171. package/dist/impact/index.d.ts.map +1 -1
  172. package/dist/impact/index.js +0 -8
  173. package/dist/impact/index.js.map +1 -1
  174. package/dist/impact/map.js +2 -2
  175. package/dist/impact/map.js.map +1 -1
  176. package/dist/impact/memberResolutionCoverage.d.ts.map +1 -1
  177. package/dist/impact/memberResolutionCoverage.js +5 -1
  178. package/dist/impact/memberResolutionCoverage.js.map +1 -1
  179. package/dist/impact/parse.d.ts.map +1 -1
  180. package/dist/impact/parse.js +98 -36
  181. package/dist/impact/parse.js.map +1 -1
  182. package/dist/impact/referenceCache.js +1 -1
  183. package/dist/impact/referenceCache.js.map +1 -1
  184. package/dist/impact/report-suggestions.d.ts.map +1 -1
  185. package/dist/impact/report-suggestions.js +330 -61
  186. package/dist/impact/report-suggestions.js.map +1 -1
  187. package/dist/impact/reportCompact.js +7 -0
  188. package/dist/impact/reportCompact.js.map +1 -1
  189. package/dist/impact/streaming.d.ts +32 -2
  190. package/dist/impact/streaming.d.ts.map +1 -1
  191. package/dist/impact/streaming.js +61 -2
  192. package/dist/impact/streaming.js.map +1 -1
  193. package/dist/impact/suggestions.d.ts.map +1 -1
  194. package/dist/impact/suggestions.js +1 -1
  195. package/dist/impact/suggestions.js.map +1 -1
  196. package/dist/impact/types.d.ts +7 -20
  197. package/dist/impact/types.d.ts.map +1 -1
  198. package/dist/impact/types.js.map +1 -1
  199. package/dist/index.d.ts +2 -2
  200. package/dist/index.d.ts.map +1 -1
  201. package/dist/index.js +1 -1
  202. package/dist/index.js.map +1 -1
  203. package/dist/indexer/build-cache/location.d.ts +19 -0
  204. package/dist/indexer/build-cache/location.d.ts.map +1 -0
  205. package/dist/indexer/build-cache/location.js +132 -0
  206. package/dist/indexer/build-cache/location.js.map +1 -0
  207. package/dist/indexer/build-cache/manifest.d.ts +9 -3
  208. package/dist/indexer/build-cache/manifest.d.ts.map +1 -1
  209. package/dist/indexer/build-cache/manifest.js +77 -20
  210. package/dist/indexer/build-cache/manifest.js.map +1 -1
  211. package/dist/indexer/build-cache/module-cache.d.ts +23 -2
  212. package/dist/indexer/build-cache/module-cache.d.ts.map +1 -1
  213. package/dist/indexer/build-cache/module-cache.js +92 -32
  214. package/dist/indexer/build-cache/module-cache.js.map +1 -1
  215. package/dist/indexer/build-cache/options.d.ts +3 -1
  216. package/dist/indexer/build-cache/options.d.ts.map +1 -1
  217. package/dist/indexer/build-cache/options.js +10 -2
  218. package/dist/indexer/build-cache/options.js.map +1 -1
  219. package/dist/indexer/build-cache/project-snapshot.d.ts +32 -8
  220. package/dist/indexer/build-cache/project-snapshot.d.ts.map +1 -1
  221. package/dist/indexer/build-cache/project-snapshot.js +333 -44
  222. package/dist/indexer/build-cache/project-snapshot.js.map +1 -1
  223. package/dist/indexer/build-cache/reports.d.ts.map +1 -1
  224. package/dist/indexer/build-cache/reports.js +10 -1
  225. package/dist/indexer/build-cache/reports.js.map +1 -1
  226. package/dist/indexer/build-cache/resolver-environment.d.ts +9 -0
  227. package/dist/indexer/build-cache/resolver-environment.d.ts.map +1 -0
  228. package/dist/indexer/build-cache/resolver-environment.js +133 -0
  229. package/dist/indexer/build-cache/resolver-environment.js.map +1 -0
  230. package/dist/indexer/build-cache.d.ts +4 -3
  231. package/dist/indexer/build-cache.d.ts.map +1 -1
  232. package/dist/indexer/build-cache.js +4 -3
  233. package/dist/indexer/build-cache.js.map +1 -1
  234. package/dist/indexer/build-index.d.ts.map +1 -1
  235. package/dist/indexer/build-index.js +154 -47
  236. package/dist/indexer/build-index.js.map +1 -1
  237. package/dist/indexer/build-manifest.d.ts +1 -0
  238. package/dist/indexer/build-manifest.d.ts.map +1 -1
  239. package/dist/indexer/build-manifest.js +12 -5
  240. package/dist/indexer/build-manifest.js.map +1 -1
  241. package/dist/indexer/call-hierarchy.d.ts.map +1 -1
  242. package/dist/indexer/call-hierarchy.js.map +1 -1
  243. package/dist/indexer/finalize.d.ts.map +1 -1
  244. package/dist/indexer/finalize.js +7 -4
  245. package/dist/indexer/finalize.js.map +1 -1
  246. package/dist/indexer/imports/jsTextImports.d.ts.map +1 -1
  247. package/dist/indexer/imports/jsTextImports.js +14 -6
  248. package/dist/indexer/imports/jsTextImports.js.map +1 -1
  249. package/dist/indexer/imports/languageSpecific.d.ts.map +1 -1
  250. package/dist/indexer/imports/languageSpecific.js +10 -5
  251. package/dist/indexer/imports/languageSpecific.js.map +1 -1
  252. package/dist/indexer/imports/nativeCaptures.d.ts.map +1 -1
  253. package/dist/indexer/imports/nativeCaptures.js +4 -1
  254. package/dist/indexer/imports/nativeCaptures.js.map +1 -1
  255. package/dist/indexer/imports/python.d.ts.map +1 -1
  256. package/dist/indexer/imports/python.js +7 -2
  257. package/dist/indexer/imports/python.js.map +1 -1
  258. package/dist/indexer/load-current-index.d.ts.map +1 -1
  259. package/dist/indexer/load-current-index.js.map +1 -1
  260. package/dist/indexer/locals-and-exports.d.ts.map +1 -1
  261. package/dist/indexer/locals-and-exports.js +52 -22
  262. package/dist/indexer/locals-and-exports.js.map +1 -1
  263. package/dist/indexer/navigation-goto.d.ts.map +1 -1
  264. package/dist/indexer/navigation-goto.js +26 -16
  265. package/dist/indexer/navigation-goto.js.map +1 -1
  266. package/dist/indexer/navigation-local.d.ts.map +1 -1
  267. package/dist/indexer/navigation-local.js +7 -4
  268. package/dist/indexer/navigation-local.js.map +1 -1
  269. package/dist/indexer/navigation-references.d.ts +1 -1
  270. package/dist/indexer/navigation-references.d.ts.map +1 -1
  271. package/dist/indexer/navigation-references.js +27 -16
  272. package/dist/indexer/navigation-references.js.map +1 -1
  273. package/dist/indexer/navigation-resolve.d.ts.map +1 -1
  274. package/dist/indexer/navigation-resolve.js +116 -53
  275. package/dist/indexer/navigation-resolve.js.map +1 -1
  276. package/dist/indexer/navigation.d.ts +2 -1
  277. package/dist/indexer/navigation.d.ts.map +1 -1
  278. package/dist/indexer/navigation.js +24 -20
  279. package/dist/indexer/navigation.js.map +1 -1
  280. package/dist/indexer/parse-context.d.ts +1 -1
  281. package/dist/indexer/parse-context.d.ts.map +1 -1
  282. package/dist/indexer/parse-context.js +2 -2
  283. package/dist/indexer/parse-context.js.map +1 -1
  284. package/dist/indexer/reference-context.d.ts +2 -2
  285. package/dist/indexer/reference-context.d.ts.map +1 -1
  286. package/dist/indexer/reference-context.js +4 -2
  287. package/dist/indexer/reference-context.js.map +1 -1
  288. package/dist/indexer/scope-types.d.ts +3 -0
  289. package/dist/indexer/scope-types.d.ts.map +1 -1
  290. package/dist/indexer/scope.js +37 -38
  291. package/dist/indexer/scope.js.map +1 -1
  292. package/dist/indexer/shared.d.ts.map +1 -1
  293. package/dist/indexer/shared.js +3 -1
  294. package/dist/indexer/shared.js.map +1 -1
  295. package/dist/indexer/type-hierarchy.d.ts.map +1 -1
  296. package/dist/indexer/type-hierarchy.js +12 -8
  297. package/dist/indexer/type-hierarchy.js.map +1 -1
  298. package/dist/indexer/types.d.ts +22 -0
  299. package/dist/indexer/types.d.ts.map +1 -1
  300. package/dist/indexer/workspace-symbols.d.ts.map +1 -1
  301. package/dist/indexer/workspace-symbols.js +5 -3
  302. package/dist/indexer/workspace-symbols.js.map +1 -1
  303. package/dist/installer/locks.d.ts +10 -0
  304. package/dist/installer/locks.d.ts.map +1 -0
  305. package/dist/installer/locks.js +234 -0
  306. package/dist/installer/locks.js.map +1 -0
  307. package/dist/installer/registry.d.ts.map +1 -1
  308. package/dist/installer/registry.js +13 -230
  309. package/dist/installer/registry.js.map +1 -1
  310. package/dist/languages/definitions/csharp.d.ts.map +1 -1
  311. package/dist/languages/definitions/csharp.js +8 -0
  312. package/dist/languages/definitions/csharp.js.map +1 -1
  313. package/dist/languages/definitions/java.d.ts.map +1 -1
  314. package/dist/languages/definitions/java.js +3 -0
  315. package/dist/languages/definitions/java.js.map +1 -1
  316. package/dist/languages/definitions/python.d.ts.map +1 -1
  317. package/dist/languages/definitions/python.js +2 -0
  318. package/dist/languages/definitions/python.js.map +1 -1
  319. package/dist/languages/definitions/rust.d.ts.map +1 -1
  320. package/dist/languages/definitions/rust.js +2 -0
  321. package/dist/languages/definitions/rust.js.map +1 -1
  322. package/dist/languages/importStatementParsers.d.ts +2 -0
  323. package/dist/languages/importStatementParsers.d.ts.map +1 -1
  324. package/dist/languages/importStatementParsers.js +24 -10
  325. package/dist/languages/importStatementParsers.js.map +1 -1
  326. package/dist/mcp/http.d.ts +3 -1
  327. package/dist/mcp/http.d.ts.map +1 -1
  328. package/dist/mcp/http.js +69 -20
  329. package/dist/mcp/http.js.map +1 -1
  330. package/dist/mcp/server.d.ts +43 -16
  331. package/dist/mcp/server.d.ts.map +1 -1
  332. package/dist/mcp/server.js +342 -127
  333. package/dist/mcp/server.js.map +1 -1
  334. package/dist/mcp/tools.d.ts +51 -1
  335. package/dist/mcp/tools.d.ts.map +1 -1
  336. package/dist/mcp/tools.js +121 -2
  337. package/dist/mcp/tools.js.map +1 -1
  338. package/dist/native/byteIndex.d.ts +26 -0
  339. package/dist/native/byteIndex.d.ts.map +1 -0
  340. package/dist/native/byteIndex.js +70 -0
  341. package/dist/native/byteIndex.js.map +1 -0
  342. package/dist/native/projectedTree.d.ts +3 -2
  343. package/dist/native/projectedTree.d.ts.map +1 -1
  344. package/dist/native/projectedTree.js +6 -50
  345. package/dist/native/projectedTree.js.map +1 -1
  346. package/dist/native/queryResults.d.ts +7 -1
  347. package/dist/native/queryResults.d.ts.map +1 -1
  348. package/dist/native/queryResults.js +13 -5
  349. package/dist/native/queryResults.js.map +1 -1
  350. package/dist/review/changes.d.ts +2 -0
  351. package/dist/review/changes.d.ts.map +1 -1
  352. package/dist/review/changes.js +10 -0
  353. package/dist/review/changes.js.map +1 -1
  354. package/dist/review/deleted.d.ts.map +1 -1
  355. package/dist/review/deleted.js +20 -2
  356. package/dist/review/deleted.js.map +1 -1
  357. package/dist/review/summaries.d.ts.map +1 -1
  358. package/dist/review/summaries.js +13 -10
  359. package/dist/review/summaries.js.map +1 -1
  360. package/dist/review.d.ts.map +1 -1
  361. package/dist/review.js +7 -2
  362. package/dist/review.js.map +1 -1
  363. package/dist/session.d.ts +20 -4
  364. package/dist/session.d.ts.map +1 -1
  365. package/dist/session.js +76 -16
  366. package/dist/session.js.map +1 -1
  367. package/dist/sql/types.d.ts.map +1 -1
  368. package/dist/sqlite/query.d.ts +29 -0
  369. package/dist/sqlite/query.d.ts.map +1 -1
  370. package/dist/sqlite/query.js +98 -11
  371. package/dist/sqlite/query.js.map +1 -1
  372. package/dist/sqlite/rawQueryWorker.d.ts +22 -0
  373. package/dist/sqlite/rawQueryWorker.d.ts.map +1 -0
  374. package/dist/sqlite/rawQueryWorker.js +31 -0
  375. package/dist/sqlite/rawQueryWorker.js.map +1 -0
  376. package/dist/sqlite/rawQueryWorkerPool.d.ts +66 -0
  377. package/dist/sqlite/rawQueryWorkerPool.d.ts.map +1 -0
  378. package/dist/sqlite/rawQueryWorkerPool.js +142 -0
  379. package/dist/sqlite/rawQueryWorkerPool.js.map +1 -0
  380. package/dist/sqlite/schema.d.ts.map +1 -1
  381. package/dist/sqlite/schema.js.map +1 -1
  382. package/dist/sqlite-driver.d.ts.map +1 -1
  383. package/dist/sqlite-driver.js +2 -1
  384. package/dist/sqlite-driver.js.map +1 -1
  385. package/dist/sqlite.d.ts +1 -1
  386. package/dist/sqlite.d.ts.map +1 -1
  387. package/dist/sqlite.js +1 -1
  388. package/dist/sqlite.js.map +1 -1
  389. package/dist/util/bloomFilter.d.ts +3 -2
  390. package/dist/util/bloomFilter.d.ts.map +1 -1
  391. package/dist/util/bloomFilter.js +8 -8
  392. package/dist/util/bloomFilter.js.map +1 -1
  393. package/dist/util/confinedFile.d.ts +41 -2
  394. package/dist/util/confinedFile.d.ts.map +1 -1
  395. package/dist/util/confinedFile.js +101 -2
  396. package/dist/util/confinedFile.js.map +1 -1
  397. package/dist/util/git.d.ts +2 -0
  398. package/dist/util/git.d.ts.map +1 -1
  399. package/dist/util/git.js +109 -26
  400. package/dist/util/git.js.map +1 -1
  401. package/dist/util/identifiers.d.ts +75 -0
  402. package/dist/util/identifiers.d.ts.map +1 -0
  403. package/dist/util/identifiers.js +82 -0
  404. package/dist/util/identifiers.js.map +1 -0
  405. package/dist/util/paths.d.ts.map +1 -1
  406. package/dist/util/paths.js.map +1 -1
  407. package/dist/util/projectFiles.d.ts.map +1 -1
  408. package/dist/util/projectFiles.js +43 -14
  409. package/dist/util/projectFiles.js.map +1 -1
  410. package/dist/util/resolution/jvm.d.ts.map +1 -1
  411. package/dist/util/resolution/jvm.js +9 -4
  412. package/dist/util/resolution/jvm.js.map +1 -1
  413. package/dist/util/resolution/php.d.ts.map +1 -1
  414. package/dist/util/resolution/php.js +6 -5
  415. package/dist/util/resolution/php.js.map +1 -1
  416. package/dist/util/rustTestModules.d.ts.map +1 -1
  417. package/dist/util/rustTestModules.js +4 -2
  418. package/dist/util/rustTestModules.js.map +1 -1
  419. package/dist/util/specifiers.d.ts.map +1 -1
  420. package/dist/util/specifiers.js +10 -3
  421. package/dist/util/specifiers.js.map +1 -1
  422. package/dist/util/sqliteSchema.d.ts.map +1 -1
  423. package/dist/util/sqliteSchema.js +10 -1
  424. package/dist/util/sqliteSchema.js.map +1 -1
  425. package/docs/mcp.md +32 -13
  426. package/package.json +3 -3
@@ -6,29 +6,32 @@ 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
11
  import { SymbolKind } from "../types.js";
12
12
  import { buildSymbolGraph, } from "../../graphs/symbol-graph.js";
13
13
  import { getImplementationFingerprint, normalizeGraphOptions } from "./options.js";
14
- import { cacheRoot } from "./module-cache.js";
14
+ import { cacheAbsolutePath, cacheRelativePath, transformPersistedExportFromModule, } from "./module-cache.js";
15
+ import { cacheRoot } from "./location.js";
15
16
  const SNAPSHOT_SYMBOL_KINDS = new Set(Object.values(SymbolKind));
16
- const PROJECT_SNAPSHOT_VERSION = 4;
17
+ const PROJECT_SNAPSHOT_VERSION = 9;
18
+ export const BLOOM_FILTER_SNAPSHOT_VERSION = 4;
19
+ export const BLOOM_FILTER_SNAPSHOT_FILENAME = "bloom-filters.json";
17
20
  const BLOOM_FILTER_MIN_SIZE = 1_000;
18
21
  const BLOOM_FILTER_MAX_SIZE = 1_000_000;
19
22
  const BLOOM_FILTER_MIN_HASH_COUNT = 1;
20
23
  const BLOOM_FILTER_MAX_HASH_COUNT = 10;
21
- const DETAILED_SYMBOL_GRAPH_SNAPSHOT_VERSION = 2;
24
+ const DETAILED_SYMBOL_GRAPH_SNAPSHOT_VERSION = 3;
22
25
  const DETAILED_SYMBOL_GRAPH_SNAPSHOT_FILENAME = "detailed-symbol-graph.json";
23
26
  const SNAPSHOT_TEMP_RETENTION_MS = 24 * 60 * 60 * 1_000;
24
27
  const SNAPSHOT_TEMP_SUFFIX = ".tmp";
25
28
  const MAX_SNAPSHOT_CACHE_ENTRIES = 32;
26
29
  const parsedSnapshotCache = new Map();
27
30
  const detailedSymbolGraphCache = new Map();
28
- export function projectSnapshotFilesSignature(entries) {
31
+ export function projectSnapshotFilesSignature(entries, projectRoot) {
29
32
  const hash = createHash("sha256");
30
33
  for (const [file, entry] of [...entries.entries()].sort(([left], [right]) => compareSnapshotPath(left, right))) {
31
- hash.update(file);
34
+ hash.update(projectRoot ? cacheRelativePath(projectRoot, file) : file);
32
35
  hash.update("\0");
33
36
  hash.update(entry.sig);
34
37
  hash.update("\0");
@@ -55,8 +58,115 @@ export function createProjectSnapshotIdentity(filesSignature, opts) {
55
58
  function serializedProjectRoot(projectRoot) {
56
59
  return normalizePath(path.resolve(projectRoot));
57
60
  }
58
- function projectRootMatches(projectRoot, storedProjectRoot) {
59
- return fileIdentityKey(path.resolve(projectRoot)) === fileIdentityKey(path.resolve(storedProjectRoot));
61
+ function transformPath(root, value, toRelative) {
62
+ if (toRelative) {
63
+ return path.isAbsolute(value) ? cacheRelativePath(root, value) : value;
64
+ }
65
+ return assertFilePathWithinRoot(root, cacheAbsolutePath(root, value), "Persisted cache path");
66
+ }
67
+ function transformHandle(root, value, toRelative) {
68
+ const separator = value.indexOf("::");
69
+ if (separator < 0)
70
+ return transformPath(root, value, toRelative);
71
+ const file = value.slice(0, separator);
72
+ return `${transformPath(root, file, toRelative)}${value.slice(separator)}`;
73
+ }
74
+ function transformModule(root, module, toRelative) {
75
+ const copy = structuredClone(module);
76
+ const file = (value) => transformPath(root, value, toRelative);
77
+ copy.file = file(copy.file);
78
+ for (const local of copy.locals)
79
+ local.file = file(local.file);
80
+ for (const entry of copy.exports) {
81
+ if (entry.type === "local") {
82
+ entry.target.file = file(entry.target.file);
83
+ }
84
+ else {
85
+ transformPersistedExportFromModule(root, entry, toRelative);
86
+ }
87
+ }
88
+ for (const binding of copy.imports) {
89
+ if (typeof binding.resolved === "string")
90
+ binding.resolved = file(binding.resolved);
91
+ }
92
+ return copy;
93
+ }
94
+ function transformSnapshotPaths(payload, root, toRelative) {
95
+ const copy = structuredClone(payload);
96
+ copy.graph.nodes = copy.graph.nodes.map((node) => transformPath(root, node, toRelative));
97
+ copy.graph.edges = copy.graph.edges.map((edge) => ({
98
+ ...edge,
99
+ from: transformPath(root, edge.from, toRelative),
100
+ to: edge.to.type === "file" ? { ...edge.to, path: transformPath(root, edge.to.path, toRelative) } : edge.to,
101
+ }));
102
+ copy.modules = copy.modules.map((module) => transformModule(root, module, toRelative));
103
+ if (copy.projectFiles) {
104
+ copy.projectFiles = copy.projectFiles.map((file) => ({
105
+ ...file,
106
+ path: transformPath(root, file.path, toRelative),
107
+ projectRoot: transformPath(root, file.projectRoot, toRelative),
108
+ }));
109
+ }
110
+ if (copy.bloomFilters) {
111
+ const bloomFilters = {};
112
+ for (const [file, filter] of Object.entries(copy.bloomFilters)) {
113
+ bloomFilters[transformPath(root, file, toRelative)] = filter;
114
+ }
115
+ copy.bloomFilters = bloomFilters;
116
+ }
117
+ const fileSignatures = {};
118
+ for (const [file, signature] of Object.entries(copy.fileSignatures ?? {})) {
119
+ fileSignatures[transformPath(root, file, toRelative)] = signature;
120
+ }
121
+ copy.fileSignatures = fileSignatures;
122
+ return copy;
123
+ }
124
+ function migrateProjectSnapshotPayload(value, currentRoot) {
125
+ if (!value || typeof value !== "object" || Array.isArray(value))
126
+ return value;
127
+ const payload = value;
128
+ if ((payload.version !== 4 && payload.version !== 5) || typeof payload.projectRoot !== "string")
129
+ return value;
130
+ const relative = transformSnapshotPaths(value, payload.projectRoot, true);
131
+ const migrated = transformSnapshotPaths(relative, currentRoot, false);
132
+ migrated.version = PROJECT_SNAPSHOT_VERSION;
133
+ migrated.projectRoot = serializedProjectRoot(currentRoot);
134
+ return migrated;
135
+ }
136
+ function transformDetailedGraph(graph, root, toRelative) {
137
+ return {
138
+ nodes: graph.nodes.map((node) => {
139
+ const file = transformPath(root, node.file, toRelative);
140
+ return { ...node, file, id: transformHandle(root, node.id, toRelative) };
141
+ }),
142
+ edges: graph.edges.map((edge) => ({
143
+ ...edge,
144
+ from: transformHandle(root, edge.from, toRelative),
145
+ to: transformHandle(root, edge.to, toRelative),
146
+ ...(edge.site
147
+ ? {
148
+ site: {
149
+ ...edge.site,
150
+ file: transformPath(root, edge.site.file, toRelative),
151
+ },
152
+ }
153
+ : {}),
154
+ })),
155
+ };
156
+ }
157
+ function migrateDetailedSymbolGraphPayload(value, currentRoot) {
158
+ if (!value || typeof value !== "object" || Array.isArray(value))
159
+ return value;
160
+ const payload = value;
161
+ if (payload.version !== 2 || typeof payload.projectRoot !== "string" || !payload.graph)
162
+ return value;
163
+ const relativeGraph = transformDetailedGraph(payload.graph, payload.projectRoot, true);
164
+ return {
165
+ ...payload,
166
+ version: DETAILED_SYMBOL_GRAPH_SNAPSHOT_VERSION,
167
+ projectRoot: serializedProjectRoot(currentRoot),
168
+ graph: transformDetailedGraph(relativeGraph, currentRoot, false),
169
+ };
60
170
  }
61
171
  function compareSnapshotPath(left, right) {
62
172
  if (left < right)
@@ -182,23 +292,24 @@ function projectIndexManifestEntries(entries) {
182
292
  ]));
183
293
  }
184
294
  export async function tryLoadProjectIndexSnapshot(projectRoot, opts, manifestEntries) {
185
- const filesSignature = projectSnapshotFilesSignature(manifestEntries);
295
+ const filesSignature = projectSnapshotFilesSignature(manifestEntries, projectRoot);
186
296
  if ((opts?.cache ?? "off") !== "disk")
187
297
  return null;
188
298
  try {
189
299
  const rawPayload = (await readParsedSnapshot(projectSnapshotPath(projectRoot, opts))).payload;
300
+ const migratedPayload = migrateProjectSnapshotPayload(rawPayload, projectRoot);
301
+ const payload = migratedPayload && typeof migratedPayload === "object" && !Array.isArray(migratedPayload)
302
+ ? transformSnapshotPaths(migratedPayload, projectRoot, false)
303
+ : migratedPayload;
190
304
  const nativeRuntimeFingerprint = getNativeRuntimeFingerprint(opts?.native);
191
305
  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) {
306
+ if (!isProjectIndexSnapshotPayload(payload) ||
307
+ payload.filesSignature !== filesSignature ||
308
+ payload.nativeMode !== normalizedSnapshotNativeMode(opts?.native) ||
309
+ payload.nativeRuntimeFingerprint !== nativeRuntimeFingerprint ||
310
+ payload.implementationFingerprint !== implementationFingerprint) {
198
311
  return null;
199
312
  }
200
- // Payload is freshly JSON.parsed from memoized compressed bytes (no deep clone).
201
- const payload = rawPayload;
202
313
  const graph = {
203
314
  nodes: new Set(payload.graph.nodes),
204
315
  edges: payload.graph.edges,
@@ -211,11 +322,12 @@ export async function tryLoadProjectIndexSnapshot(projectRoot, opts, manifestEnt
211
322
  modules,
212
323
  byFile: modules,
213
324
  projectRoot: serializedProjectRoot(projectRoot),
325
+ ...(payload.languageExtensions ? { languageExtensions: payload.languageExtensions } : {}),
214
326
  ...(payload.nativeMode ? { nativeMode: payload.nativeMode } : {}),
215
327
  exportCache: new Map(),
216
328
  scopeCache: new Map(),
217
329
  ...(shouldHydrateBloomFilters && payload.bloomFilters
218
- ? { bloomFilters: deserializeBloomFilterCache(payload.bloomFilters) }
330
+ ? { bloomFilters: deserializeBloomFilterCache(payload.bloomFilters, projectRoot) }
219
331
  : {}),
220
332
  ...(payload.projectFiles ? { projectFiles: payload.projectFiles } : {}),
221
333
  referenceCandidates: buildReferenceCandidateIndex(modules),
@@ -236,51 +348,148 @@ export async function tryLoadProjectIndexSnapshot(projectRoot, opts, manifestEnt
236
348
  }
237
349
  }
238
350
  /**
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.
351
+ * Load only the bloom-filter section of the last-written project snapshot. Hydration checks
352
+ * each requested file against its persisted signature before returning a filter, so a stale
353
+ * snapshot can still accelerate unchanged files without suppressing newly added references.
243
354
  * Only the bloom section is then read, so a corrupt payload is rejected without walking
244
355
  * `graph.edges` / `modules`. Returns `null` when disk caching is off, `useBloomFilters` is
245
356
  * disabled, or no valid snapshot with bloom data exists.
246
357
  */
358
+ export async function tryLoadProjectSnapshotModules(projectRoot, opts, fileSignatures) {
359
+ if ((opts?.cache ?? "off") !== "disk")
360
+ return null;
361
+ try {
362
+ const rawPayload = (await readParsedSnapshot(projectSnapshotPath(projectRoot, opts))).payload;
363
+ const migratedPayload = migrateProjectSnapshotPayload(rawPayload, projectRoot);
364
+ const payload = migratedPayload && typeof migratedPayload === "object" && !Array.isArray(migratedPayload)
365
+ ? transformSnapshotPaths(migratedPayload, projectRoot, false)
366
+ : migratedPayload;
367
+ const nativeRuntimeFingerprint = getNativeRuntimeFingerprint(opts?.native);
368
+ const implementationFingerprint = getImplementationFingerprint();
369
+ if (!isProjectIndexSnapshotPayload(payload) ||
370
+ payload.nativeMode !== normalizedSnapshotNativeMode(opts?.native) ||
371
+ payload.nativeRuntimeFingerprint !== nativeRuntimeFingerprint ||
372
+ payload.implementationFingerprint !== implementationFingerprint) {
373
+ return null;
374
+ }
375
+ const normalizedFileSignatures = new Map(Object.entries(payload.fileSignatures).map(([file, signature]) => [fileIdentityKey(file), signature]));
376
+ // `fileSignatures` (caller-supplied) is keyed by whatever discovered display path each file
377
+ // was found under, not necessarily `fileIdentityKey`-normalized; on a case-insensitive
378
+ // filesystem an uppercase path segment would otherwise miss this lookup.
379
+ const normalizedCurrentSignatures = new Map(Array.from(fileSignatures, ([file, signature]) => [fileIdentityKey(file), signature]));
380
+ const modules = new Map();
381
+ for (const mod of payload.modules) {
382
+ const moduleKey = fileIdentityKey(mod.file);
383
+ const signature = normalizedCurrentSignatures.get(moduleKey);
384
+ const snapshotSignature = normalizedFileSignatures.get(moduleKey);
385
+ if (!signature || !snapshotSignature || !snapshotSignatureMatches(snapshotSignature, signature))
386
+ continue;
387
+ modules.set(moduleKey, mod);
388
+ }
389
+ return modules;
390
+ }
391
+ catch {
392
+ return null;
393
+ }
394
+ }
247
395
  export async function tryLoadPersistedBloomFilters(projectRoot, opts) {
248
396
  if ((opts?.cache ?? "off") !== "disk" || (opts?.useBloomFilters ?? true) === false)
249
397
  return null;
398
+ try {
399
+ const sidecarPath = bloomFilterSnapshotPath(projectRoot, opts);
400
+ const sidecarParsed = (await readParsedSnapshot(sidecarPath)).payload;
401
+ const sidecarBloom = persistedBloomFiltersFromSidecar(sidecarParsed, projectRoot);
402
+ if (sidecarBloom) {
403
+ return createPersistedBloomFilters(sidecarBloom.bloomFilters, sidecarBloom.fileSignatures, projectRoot);
404
+ }
405
+ }
406
+ catch {
407
+ // Fall back to legacy project snapshot payload if sidecar is unavailable or corrupt
408
+ }
250
409
  try {
251
410
  const payload = (await readParsedSnapshot(projectSnapshotPath(projectRoot, opts))).payload;
252
411
  const bloomFilters = persistedBloomFiltersFromSnapshot(payload, projectRoot);
253
412
  if (!bloomFilters)
254
413
  return null;
255
- return deserializeBloomFilterCache(bloomFilters);
414
+ return createPersistedBloomFilters(bloomFilters.bloomFilters, bloomFilters.fileSignatures, projectRoot);
256
415
  }
257
416
  catch {
258
417
  return null;
259
418
  }
260
419
  }
261
- /** Light validation for bloom hydration: snapshot version, root identity, and bloom section only. */
262
- function persistedBloomFiltersFromSnapshot(value, projectRoot) {
420
+ function persistedBloomFiltersFromSidecar(value, projectRoot) {
263
421
  if (!value || typeof value !== "object")
264
422
  return null;
265
423
  const payload = value;
424
+ if (payload.version !== BLOOM_FILTER_SNAPSHOT_VERSION ||
425
+ typeof payload.projectRoot !== "string" ||
426
+ payload.implementationFingerprint !== getImplementationFingerprint() ||
427
+ typeof payload.projectSnapshotIdentity !== "string" ||
428
+ !/^[a-f0-9]{64}$/.test(payload.projectSnapshotIdentity)) {
429
+ return null;
430
+ }
431
+ const bloomFilters = payload.bloomFilters;
432
+ const fileSignatures = payload.fileSignatures;
433
+ if (!isSerializedBloomFilterRecord(bloomFilters) || !isSnapshotFileSignatureRecord(fileSignatures)) {
434
+ return null;
435
+ }
436
+ return { bloomFilters, fileSignatures };
437
+ }
438
+ /** Light validation for bloom hydration: snapshot version, root identity, and bloom section only. */
439
+ function persistedBloomFiltersFromSnapshot(value, projectRoot) {
440
+ const migrated = migrateProjectSnapshotPayload(value, projectRoot);
441
+ if (!migrated || typeof migrated !== "object")
442
+ return null;
443
+ const payload = migrated;
266
444
  if (payload.version !== PROJECT_SNAPSHOT_VERSION ||
267
445
  typeof payload.projectRoot !== "string" ||
268
- !projectRootMatches(projectRoot, payload.projectRoot) ||
269
446
  payload.implementationFingerprint !== getImplementationFingerprint()) {
270
447
  return null;
271
448
  }
272
- if (!isSerializedBloomFilterRecord(payload.bloomFilters))
449
+ const bloomFilters = payload.bloomFilters;
450
+ const fileSignatures = payload.fileSignatures;
451
+ if (!isSerializedBloomFilterRecord(bloomFilters) || !isSnapshotFileSignatureRecord(fileSignatures)) {
273
452
  return null;
274
- return payload.bloomFilters;
453
+ }
454
+ return { bloomFilters, fileSignatures };
455
+ }
456
+ function createPersistedBloomFilters(bloomFilters, fileSignatures, projectRoot) {
457
+ const filters = deserializeBloomFilterCache(bloomFilters, projectRoot);
458
+ const signatures = new Map(Object.entries(fileSignatures).map(([file, signature]) => [
459
+ fileIdentityKey(cacheAbsolutePath(projectRoot, file)),
460
+ signature,
461
+ ]));
462
+ return {
463
+ get: (file, signature) => {
464
+ const persistedSignature = signatures.get(fileIdentityKey(file));
465
+ if (!persistedSignature || !snapshotSignatureMatches(persistedSignature, signature))
466
+ return undefined;
467
+ return filters.get(file);
468
+ },
469
+ };
470
+ }
471
+ function snapshotSignatureMatches(snapshotSignature, currentSignature) {
472
+ const matchingGitSignature = !!snapshotSignature.gitSig && !!currentSignature.gitSig && snapshotSignature.gitSig === currentSignature.gitSig;
473
+ if (matchingGitSignature)
474
+ return true;
475
+ // `cacheSig` is git- or content-hash-derived (forced whenever caching is enabled without a git
476
+ // signature; see `fileSignature()`), so when both sides have it, it is a strictly stronger and
477
+ // authoritative identity check than the cheap `mtime:size` `sig`. Comparing bare `sig` alone
478
+ // would wrongly treat a same-size edit whose mtime got restored as unchanged.
479
+ if (snapshotSignature.cacheSig !== undefined && currentSignature.cacheSig !== undefined) {
480
+ return snapshotSignature.cacheSig === currentSignature.cacheSig;
481
+ }
482
+ return snapshotSignature.sig === currentSignature.sig;
275
483
  }
276
484
  export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesSignature) {
277
485
  const projectSnapshotIdentity = createProjectSnapshotIdentity(filesSignature, opts);
486
+ const fileSignatures = serializeSnapshotFileSignatures(index.manifestEntries, projectRoot);
278
487
  const serializedBloomFilters = index.bloomFilters
279
- ? serializeBloomFilterCache(index.bloomFilters, Array.from(index.byFile.values(), (module) => module.file))
488
+ ? serializeBloomFilterCache(index.bloomFilters, Array.from(index.byFile.values(), (module) => module.file), projectRoot)
280
489
  : undefined;
281
490
  const snapshotAnalysisReport = analysisReportFromBuildReport(index.buildReport);
282
491
  const snapshotAnalysis = index.buildReport ? summarizeAnalysis({ index, report: index.buildReport }) : index.analysis;
283
- const payload = {
492
+ const payload = transformSnapshotPaths({
284
493
  version: PROJECT_SNAPSHOT_VERSION,
285
494
  filesSignature,
286
495
  projectRoot: serializedProjectRoot(projectRoot),
@@ -291,6 +500,8 @@ export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesS
291
500
  edges: index.graph.edges,
292
501
  },
293
502
  modules: [...index.byFile.values()],
503
+ fileSignatures,
504
+ ...(index.languageExtensions ? { languageExtensions: index.languageExtensions } : {}),
294
505
  ...(normalizedSnapshotNativeMode(index.nativeMode)
295
506
  ? { nativeMode: normalizedSnapshotNativeMode(index.nativeMode) }
296
507
  : {}),
@@ -298,7 +509,7 @@ export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesS
298
509
  ...(serializedBloomFilters ? { bloomFilters: serializedBloomFilters } : {}),
299
510
  ...(snapshotAnalysis ? { analysis: snapshotAnalysis } : {}),
300
511
  ...(snapshotAnalysisReport ? { analysisReport: snapshotAnalysisReport } : {}),
301
- };
512
+ }, projectRoot, true);
302
513
  try {
303
514
  const snapshotPath = projectSnapshotPath(projectRoot, opts);
304
515
  const compressed = brotliCompressSync(JSON.stringify(payload), {
@@ -308,6 +519,31 @@ export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesS
308
519
  const identity = await snapshotFileIdentity(snapshotPath);
309
520
  setBoundedSnapshotCache(parsedSnapshotCache, snapshotPath, { identity, compressed });
310
521
  index.projectSnapshotIdentity = projectSnapshotIdentity;
522
+ if (serializedBloomFilters) {
523
+ try {
524
+ const bloomPayload = {
525
+ version: BLOOM_FILTER_SNAPSHOT_VERSION,
526
+ projectRoot: serializedProjectRoot(projectRoot),
527
+ implementationFingerprint: getImplementationFingerprint(),
528
+ projectSnapshotIdentity,
529
+ fileSignatures,
530
+ bloomFilters: serializedBloomFilters,
531
+ };
532
+ const bloomPath = bloomFilterSnapshotPath(projectRoot, opts);
533
+ const bloomCompressed = brotliCompressSync(JSON.stringify(bloomPayload), {
534
+ params: { [zlibConstants.BROTLI_PARAM_QUALITY]: 4 },
535
+ });
536
+ await writeSnapshotAtomically(bloomPath, bloomCompressed);
537
+ const bloomIdentity = await snapshotFileIdentity(bloomPath);
538
+ setBoundedSnapshotCache(parsedSnapshotCache, bloomPath, {
539
+ identity: bloomIdentity,
540
+ compressed: bloomCompressed,
541
+ });
542
+ }
543
+ catch {
544
+ // Bloom sidecar write failure must not fail indexing
545
+ }
546
+ }
311
547
  }
312
548
  catch {
313
549
  delete index.projectSnapshotIdentity;
@@ -317,6 +553,14 @@ export async function writeProjectIndexSnapshot(projectRoot, opts, index, filesS
317
553
  function projectSnapshotPath(projectRoot, opts) {
318
554
  return path.join(cacheRoot(projectRoot, opts), "project-index-snapshot.json");
319
555
  }
556
+ function bloomFilterSnapshotPath(projectRoot, opts) {
557
+ const root = path.resolve(cacheRoot(projectRoot, opts));
558
+ const snapshotPath = path.resolve(root, BLOOM_FILTER_SNAPSHOT_FILENAME);
559
+ if (!isFilePathWithinRoot(root, snapshotPath)) {
560
+ throw new Error(`Bloom filter snapshot escaped cache root: ${snapshotPath}`);
561
+ }
562
+ return snapshotPath;
563
+ }
320
564
  export async function tryLoadDetailedSymbolGraphSnapshot(projectRoot, opts, index) {
321
565
  if ((opts?.cache ?? "off") !== "disk" || !index.projectSnapshotIdentity)
322
566
  return null;
@@ -331,9 +575,14 @@ export async function tryLoadDetailedSymbolGraphSnapshot(projectRoot, opts, inde
331
575
  return materializeDetailedSymbolGraph(cached.graph);
332
576
  }
333
577
  const parsed = await readParsedSnapshot(snapshotPath);
334
- const payload = parsed.payload;
578
+ const migratedPayload = migrateDetailedSymbolGraphPayload(parsed.payload, projectRoot);
579
+ const payload = migratedPayload && typeof migratedPayload === "object" && !Array.isArray(migratedPayload)
580
+ ? {
581
+ ...migratedPayload,
582
+ graph: transformDetailedGraph(migratedPayload.graph, projectRoot, false),
583
+ }
584
+ : migratedPayload;
335
585
  if (!isDetailedSymbolGraphSnapshotPayload(payload) ||
336
- !projectRootMatches(projectRoot, payload.projectRoot) ||
337
586
  payload.implementationFingerprint !== getImplementationFingerprint() ||
338
587
  payload.projectSnapshotIdentity !== index.projectSnapshotIdentity) {
339
588
  return null;
@@ -365,10 +614,10 @@ export async function writeDetailedSymbolGraphSnapshot(projectRoot, opts, index,
365
614
  implementationFingerprint: getImplementationFingerprint(),
366
615
  graphHash: detailedSymbolGraphContentHash(index.projectSnapshotIdentity, graph),
367
616
  projectSnapshotIdentity: index.projectSnapshotIdentity,
368
- graph: {
617
+ graph: transformDetailedGraph({
369
618
  nodes: [...graph.nodes.values()],
370
619
  edges: graph.edges,
371
- },
620
+ }, projectRoot, true),
372
621
  };
373
622
  try {
374
623
  const snapshotPath = detailedSymbolGraphSnapshotPath(projectRoot, opts);
@@ -379,12 +628,14 @@ export async function writeDetailedSymbolGraphSnapshot(projectRoot, opts, index,
379
628
  });
380
629
  await writeSnapshotAtomically(snapshotPath, compressed);
381
630
  const identity = await snapshotFileIdentity(snapshotPath);
382
- const cachedPayload = structuredClone(payload);
383
631
  setBoundedSnapshotCache(parsedSnapshotCache, snapshotPath, { identity, compressed });
384
632
  setBoundedSnapshotCache(detailedSymbolGraphCache, snapshotPath, {
385
633
  identity,
386
634
  projectSnapshotIdentity: index.projectSnapshotIdentity,
387
- graph: cachedPayload.graph,
635
+ graph: {
636
+ nodes: [...graph.nodes.values()],
637
+ edges: graph.edges,
638
+ },
388
639
  });
389
640
  }
390
641
  catch {
@@ -659,7 +910,9 @@ function isProjectIndexSnapshotPayload(value) {
659
910
  payload.graph.edges.every(isGraphEdge) &&
660
911
  Array.isArray(payload.modules) &&
661
912
  payload.modules.every(isModuleIndex) &&
913
+ isSnapshotFileSignatureRecord(payload.fileSignatures) &&
662
914
  (payload.nativeMode === undefined || isSnapshotNativeMode(payload.nativeMode)) &&
915
+ (payload.languageExtensions === undefined || isLanguageExtensionMap(payload.languageExtensions)) &&
663
916
  (payload.bloomFilters === undefined || isSerializedBloomFilterRecord(payload.bloomFilters)) &&
664
917
  (payload.analysis === undefined || isAnalysisSummary(payload.analysis)) &&
665
918
  (payload.analysisReport === undefined || isSnapshotAnalysisReport(payload.analysisReport)) &&
@@ -746,14 +999,14 @@ function isAnalysisSummary(value) {
746
999
  typeof summary.nativeFilesFellBack === "number" &&
747
1000
  typeof summary.label === "string");
748
1001
  }
749
- function serializeBloomFilterCache(cache, files) {
1002
+ function serializeBloomFilterCache(cache, files, projectRoot) {
750
1003
  const serialized = {};
751
1004
  for (const file of files) {
752
1005
  const filter = cache.get(file);
753
1006
  if (!filter)
754
1007
  continue;
755
1008
  const metadata = filter.getMetadata();
756
- serialized[file] = {
1009
+ serialized[cacheRelativePath(projectRoot, file)] = {
757
1010
  size: metadata.size,
758
1011
  hashCount: metadata.hashCount,
759
1012
  bitsBase64: filter.toBuffer().toString("base64"),
@@ -761,10 +1014,35 @@ function serializeBloomFilterCache(cache, files) {
761
1014
  }
762
1015
  return Object.keys(serialized).length ? serialized : undefined;
763
1016
  }
764
- function deserializeBloomFilterCache(serialized) {
1017
+ function serializeSnapshotFileSignatures(entries, projectRoot) {
1018
+ const serialized = {};
1019
+ for (const [file, entry] of entries ?? []) {
1020
+ serialized[cacheRelativePath(projectRoot, file)] = {
1021
+ sig: entry.sig,
1022
+ ...(entry.gitSig ? { gitSig: entry.gitSig } : {}),
1023
+ ...(entry.cacheSig ? { cacheSig: entry.cacheSig } : {}),
1024
+ };
1025
+ }
1026
+ return serialized;
1027
+ }
1028
+ function isSnapshotFileSignatureRecord(value) {
1029
+ if (!value || typeof value !== "object" || Array.isArray(value))
1030
+ return false;
1031
+ return Object.values(value).every(isSnapshotFileSignature);
1032
+ }
1033
+ function isSnapshotFileSignature(value) {
1034
+ if (!value || typeof value !== "object" || Array.isArray(value))
1035
+ return false;
1036
+ const signature = value;
1037
+ return (typeof signature.sig === "string" &&
1038
+ (signature.gitSig === undefined || typeof signature.gitSig === "string") &&
1039
+ (signature.cacheSig === undefined || typeof signature.cacheSig === "string"));
1040
+ }
1041
+ function deserializeBloomFilterCache(serialized, projectRoot) {
765
1042
  const cache = new BloomFilterCache();
766
1043
  for (const [file, filter] of Object.entries(serialized)) {
767
- cache.set(file, BloomFilter.fromBuffer(Buffer.from(filter.bitsBase64, "base64"), filter.size, filter.hashCount));
1044
+ const absoluteFile = assertFilePathWithinRoot(projectRoot, cacheAbsolutePath(projectRoot, file), "Persisted cache path");
1045
+ cache.set(absoluteFile, BloomFilter.fromBuffer(Buffer.from(filter.bitsBase64, "base64"), filter.size, filter.hashCount));
768
1046
  }
769
1047
  return cache;
770
1048
  }
@@ -773,6 +1051,11 @@ function isSerializedBloomFilterRecord(value) {
773
1051
  return false;
774
1052
  return Object.values(value).every(isSerializedBloomFilter);
775
1053
  }
1054
+ function isLanguageExtensionMap(value) {
1055
+ if (!value || typeof value !== "object" || Array.isArray(value))
1056
+ return false;
1057
+ return Object.values(value).every((entry) => typeof entry === "string");
1058
+ }
776
1059
  function isSerializedBloomFilter(value) {
777
1060
  if (!value || typeof value !== "object")
778
1061
  return false;
@@ -788,9 +1071,15 @@ function isSerializedBloomFilter(value) {
788
1071
  typeof filter.bitsBase64 !== "string") {
789
1072
  return false;
790
1073
  }
791
- const maxBytes = Math.ceil(filter.size / 8);
792
- const maxBase64Length = Math.ceil(maxBytes / 3) * 4;
793
- return filter.bitsBase64.length === maxBase64Length;
1074
+ const expectedBytes = Math.ceil(filter.size / 8);
1075
+ let decoded;
1076
+ try {
1077
+ decoded = Buffer.from(filter.bitsBase64, "base64");
1078
+ }
1079
+ catch {
1080
+ return false;
1081
+ }
1082
+ return decoded.length === expectedBytes && decoded.toString("base64") === filter.bitsBase64;
794
1083
  }
795
1084
  function isModuleIndex(value) {
796
1085
  if (!value || typeof value !== "object")