optave-codegraph 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1672) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +984 -0
  3. package/dist/ast-analysis/engine.d.ts +19 -0
  4. package/dist/ast-analysis/engine.d.ts.map +1 -0
  5. package/dist/ast-analysis/engine.js +660 -0
  6. package/dist/ast-analysis/engine.js.map +1 -0
  7. package/dist/ast-analysis/metrics.d.ts +34 -0
  8. package/dist/ast-analysis/metrics.d.ts.map +1 -0
  9. package/dist/ast-analysis/metrics.js +123 -0
  10. package/dist/ast-analysis/metrics.js.map +1 -0
  11. package/dist/ast-analysis/rules/b2.d.ts +7 -0
  12. package/dist/ast-analysis/rules/b2.d.ts.map +1 -0
  13. package/dist/ast-analysis/rules/b2.js +240 -0
  14. package/dist/ast-analysis/rules/b2.js.map +1 -0
  15. package/dist/ast-analysis/rules/b3.d.ts +6 -0
  16. package/dist/ast-analysis/rules/b3.d.ts.map +1 -0
  17. package/dist/ast-analysis/rules/b3.js +105 -0
  18. package/dist/ast-analysis/rules/b3.js.map +1 -0
  19. package/dist/ast-analysis/rules/b4.d.ts +9 -0
  20. package/dist/ast-analysis/rules/b4.d.ts.map +1 -0
  21. package/dist/ast-analysis/rules/b4.js +361 -0
  22. package/dist/ast-analysis/rules/b4.js.map +1 -0
  23. package/dist/ast-analysis/rules/b5.d.ts +4 -0
  24. package/dist/ast-analysis/rules/b5.d.ts.map +1 -0
  25. package/dist/ast-analysis/rules/b5.js +52 -0
  26. package/dist/ast-analysis/rules/b5.js.map +1 -0
  27. package/dist/ast-analysis/rules/c.d.ts +4 -0
  28. package/dist/ast-analysis/rules/c.d.ts.map +1 -0
  29. package/dist/ast-analysis/rules/c.js +143 -0
  30. package/dist/ast-analysis/rules/c.js.map +1 -0
  31. package/dist/ast-analysis/rules/csharp.d.ts +7 -0
  32. package/dist/ast-analysis/rules/csharp.d.ts.map +1 -0
  33. package/dist/ast-analysis/rules/csharp.js +196 -0
  34. package/dist/ast-analysis/rules/csharp.js.map +1 -0
  35. package/dist/ast-analysis/rules/go.d.ts +7 -0
  36. package/dist/ast-analysis/rules/go.d.ts.map +1 -0
  37. package/dist/ast-analysis/rules/go.js +173 -0
  38. package/dist/ast-analysis/rules/go.js.map +1 -0
  39. package/dist/ast-analysis/rules/index.d.ts +13 -0
  40. package/dist/ast-analysis/rules/index.d.ts.map +1 -0
  41. package/dist/ast-analysis/rules/index.js +325 -0
  42. package/dist/ast-analysis/rules/index.js.map +1 -0
  43. package/dist/ast-analysis/rules/java.d.ts +7 -0
  44. package/dist/ast-analysis/rules/java.d.ts.map +1 -0
  45. package/dist/ast-analysis/rules/java.js +167 -0
  46. package/dist/ast-analysis/rules/java.js.map +1 -0
  47. package/dist/ast-analysis/rules/javascript.d.ts +7 -0
  48. package/dist/ast-analysis/rules/javascript.d.ts.map +1 -0
  49. package/dist/ast-analysis/rules/javascript.js +233 -0
  50. package/dist/ast-analysis/rules/javascript.js.map +1 -0
  51. package/dist/ast-analysis/rules/php.d.ts +7 -0
  52. package/dist/ast-analysis/rules/php.d.ts.map +1 -0
  53. package/dist/ast-analysis/rules/php.js +212 -0
  54. package/dist/ast-analysis/rules/php.js.map +1 -0
  55. package/dist/ast-analysis/rules/python.d.ts +7 -0
  56. package/dist/ast-analysis/rules/python.d.ts.map +1 -0
  57. package/dist/ast-analysis/rules/python.js +189 -0
  58. package/dist/ast-analysis/rules/python.js.map +1 -0
  59. package/dist/ast-analysis/rules/ruby.d.ts +7 -0
  60. package/dist/ast-analysis/rules/ruby.d.ts.map +1 -0
  61. package/dist/ast-analysis/rules/ruby.js +193 -0
  62. package/dist/ast-analysis/rules/ruby.js.map +1 -0
  63. package/dist/ast-analysis/rules/rust.d.ts +7 -0
  64. package/dist/ast-analysis/rules/rust.d.ts.map +1 -0
  65. package/dist/ast-analysis/rules/rust.js +166 -0
  66. package/dist/ast-analysis/rules/rust.js.map +1 -0
  67. package/dist/ast-analysis/shared.d.ts +12 -0
  68. package/dist/ast-analysis/shared.d.ts.map +1 -0
  69. package/dist/ast-analysis/shared.js +166 -0
  70. package/dist/ast-analysis/shared.js.map +1 -0
  71. package/dist/ast-analysis/visitor-utils.d.ts +70 -0
  72. package/dist/ast-analysis/visitor-utils.d.ts.map +1 -0
  73. package/dist/ast-analysis/visitor-utils.js +235 -0
  74. package/dist/ast-analysis/visitor-utils.js.map +1 -0
  75. package/dist/ast-analysis/visitor.d.ts +27 -0
  76. package/dist/ast-analysis/visitor.d.ts.map +1 -0
  77. package/dist/ast-analysis/visitor.js +178 -0
  78. package/dist/ast-analysis/visitor.js.map +1 -0
  79. package/dist/ast-analysis/visitors/ast-store-visitor.d.ts +4 -0
  80. package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -0
  81. package/dist/ast-analysis/visitors/ast-store-visitor.js +288 -0
  82. package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -0
  83. package/dist/ast-analysis/visitors/cfg-conditionals.d.ts +5 -0
  84. package/dist/ast-analysis/visitors/cfg-conditionals.d.ts.map +1 -0
  85. package/dist/ast-analysis/visitors/cfg-conditionals.js +166 -0
  86. package/dist/ast-analysis/visitors/cfg-conditionals.js.map +1 -0
  87. package/dist/ast-analysis/visitors/cfg-loops.d.ts +7 -0
  88. package/dist/ast-analysis/visitors/cfg-loops.d.ts.map +1 -0
  89. package/dist/ast-analysis/visitors/cfg-loops.js +73 -0
  90. package/dist/ast-analysis/visitors/cfg-loops.js.map +1 -0
  91. package/dist/ast-analysis/visitors/cfg-shared.d.ts +56 -0
  92. package/dist/ast-analysis/visitors/cfg-shared.d.ts.map +1 -0
  93. package/dist/ast-analysis/visitors/cfg-shared.js +107 -0
  94. package/dist/ast-analysis/visitors/cfg-shared.js.map +1 -0
  95. package/dist/ast-analysis/visitors/cfg-try-catch.d.ts +4 -0
  96. package/dist/ast-analysis/visitors/cfg-try-catch.d.ts.map +1 -0
  97. package/dist/ast-analysis/visitors/cfg-try-catch.js +100 -0
  98. package/dist/ast-analysis/visitors/cfg-try-catch.js.map +1 -0
  99. package/dist/ast-analysis/visitors/cfg-visitor.d.ts +5 -0
  100. package/dist/ast-analysis/visitors/cfg-visitor.d.ts.map +1 -0
  101. package/dist/ast-analysis/visitors/cfg-visitor.js +231 -0
  102. package/dist/ast-analysis/visitors/cfg-visitor.js.map +1 -0
  103. package/dist/ast-analysis/visitors/complexity-visitor.d.ts +8 -0
  104. package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -0
  105. package/dist/ast-analysis/visitors/complexity-visitor.js +233 -0
  106. package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -0
  107. package/dist/ast-analysis/visitors/dataflow-visitor.d.ts +5 -0
  108. package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -0
  109. package/dist/ast-analysis/visitors/dataflow-visitor.js +378 -0
  110. package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -0
  111. package/dist/cli/commands/ast.d.ts +3 -0
  112. package/dist/cli/commands/ast.d.ts.map +1 -0
  113. package/dist/cli/commands/ast.js +23 -0
  114. package/dist/cli/commands/ast.js.map +1 -0
  115. package/dist/cli/commands/audit.d.ts +3 -0
  116. package/dist/cli/commands/audit.d.ts.map +1 -0
  117. package/dist/cli/commands/audit.js +47 -0
  118. package/dist/cli/commands/audit.js.map +1 -0
  119. package/dist/cli/commands/batch.d.ts +3 -0
  120. package/dist/cli/commands/batch.d.ts.map +1 -0
  121. package/dist/cli/commands/batch.js +66 -0
  122. package/dist/cli/commands/batch.js.map +1 -0
  123. package/dist/cli/commands/branch-compare.d.ts +3 -0
  124. package/dist/cli/commands/branch-compare.d.ts.map +1 -0
  125. package/dist/cli/commands/branch-compare.js +26 -0
  126. package/dist/cli/commands/branch-compare.js.map +1 -0
  127. package/dist/cli/commands/brief.d.ts +3 -0
  128. package/dist/cli/commands/brief.d.ts.map +1 -0
  129. package/dist/cli/commands/brief.js +12 -0
  130. package/dist/cli/commands/brief.js.map +1 -0
  131. package/dist/cli/commands/build.d.ts +3 -0
  132. package/dist/cli/commands/build.d.ts.map +1 -0
  133. package/dist/cli/commands/build.js +33 -0
  134. package/dist/cli/commands/build.js.map +1 -0
  135. package/dist/cli/commands/cfg.d.ts +3 -0
  136. package/dist/cli/commands/cfg.d.ts.map +1 -0
  137. package/dist/cli/commands/cfg.js +27 -0
  138. package/dist/cli/commands/cfg.js.map +1 -0
  139. package/dist/cli/commands/check.d.ts +3 -0
  140. package/dist/cli/commands/check.d.ts.map +1 -0
  141. package/dist/cli/commands/check.js +65 -0
  142. package/dist/cli/commands/check.js.map +1 -0
  143. package/dist/cli/commands/children.d.ts +3 -0
  144. package/dist/cli/commands/children.d.ts.map +1 -0
  145. package/dist/cli/commands/children.js +33 -0
  146. package/dist/cli/commands/children.js.map +1 -0
  147. package/dist/cli/commands/co-change.d.ts +3 -0
  148. package/dist/cli/commands/co-change.d.ts.map +1 -0
  149. package/dist/cli/commands/co-change.js +66 -0
  150. package/dist/cli/commands/co-change.js.map +1 -0
  151. package/dist/cli/commands/communities.d.ts +3 -0
  152. package/dist/cli/commands/communities.d.ts.map +1 -0
  153. package/dist/cli/commands/communities.js +20 -0
  154. package/dist/cli/commands/communities.js.map +1 -0
  155. package/dist/cli/commands/complexity.d.ts +3 -0
  156. package/dist/cli/commands/complexity.d.ts.map +1 -0
  157. package/dist/cli/commands/complexity.js +47 -0
  158. package/dist/cli/commands/complexity.js.map +1 -0
  159. package/dist/cli/commands/config.d.ts +3 -0
  160. package/dist/cli/commands/config.d.ts.map +1 -0
  161. package/dist/cli/commands/config.js +275 -0
  162. package/dist/cli/commands/config.js.map +1 -0
  163. package/dist/cli/commands/context.d.ts +3 -0
  164. package/dist/cli/commands/context.d.ts.map +1 -0
  165. package/dist/cli/commands/context.js +35 -0
  166. package/dist/cli/commands/context.js.map +1 -0
  167. package/dist/cli/commands/cycles.d.ts +3 -0
  168. package/dist/cli/commands/cycles.d.ts.map +1 -0
  169. package/dist/cli/commands/cycles.js +33 -0
  170. package/dist/cli/commands/cycles.js.map +1 -0
  171. package/dist/cli/commands/dataflow.d.ts +3 -0
  172. package/dist/cli/commands/dataflow.d.ts.map +1 -0
  173. package/dist/cli/commands/dataflow.js +29 -0
  174. package/dist/cli/commands/dataflow.js.map +1 -0
  175. package/dist/cli/commands/deps.d.ts +3 -0
  176. package/dist/cli/commands/deps.d.ts.map +1 -0
  177. package/dist/cli/commands/deps.js +18 -0
  178. package/dist/cli/commands/deps.js.map +1 -0
  179. package/dist/cli/commands/diff-impact.d.ts +3 -0
  180. package/dist/cli/commands/diff-impact.d.ts.map +1 -0
  181. package/dist/cli/commands/diff-impact.js +29 -0
  182. package/dist/cli/commands/diff-impact.js.map +1 -0
  183. package/dist/cli/commands/embed.d.ts +3 -0
  184. package/dist/cli/commands/embed.d.ts.map +1 -0
  185. package/dist/cli/commands/embed.js +75 -0
  186. package/dist/cli/commands/embed.js.map +1 -0
  187. package/dist/cli/commands/export.d.ts +3 -0
  188. package/dist/cli/commands/export.d.ts.map +1 -0
  189. package/dist/cli/commands/export.js +72 -0
  190. package/dist/cli/commands/export.js.map +1 -0
  191. package/dist/cli/commands/exports.d.ts +3 -0
  192. package/dist/cli/commands/exports.d.ts.map +1 -0
  193. package/dist/cli/commands/exports.js +14 -0
  194. package/dist/cli/commands/exports.js.map +1 -0
  195. package/dist/cli/commands/flow.d.ts +3 -0
  196. package/dist/cli/commands/flow.d.ts.map +1 -0
  197. package/dist/cli/commands/flow.js +32 -0
  198. package/dist/cli/commands/flow.js.map +1 -0
  199. package/dist/cli/commands/fn-impact.d.ts +3 -0
  200. package/dist/cli/commands/fn-impact.d.ts.map +1 -0
  201. package/dist/cli/commands/fn-impact.js +33 -0
  202. package/dist/cli/commands/fn-impact.js.map +1 -0
  203. package/dist/cli/commands/impact.d.ts +3 -0
  204. package/dist/cli/commands/impact.d.ts.map +1 -0
  205. package/dist/cli/commands/impact.js +12 -0
  206. package/dist/cli/commands/impact.js.map +1 -0
  207. package/dist/cli/commands/implementations.d.ts +3 -0
  208. package/dist/cli/commands/implementations.d.ts.map +1 -0
  209. package/dist/cli/commands/implementations.js +29 -0
  210. package/dist/cli/commands/implementations.js.map +1 -0
  211. package/dist/cli/commands/info.d.ts +3 -0
  212. package/dist/cli/commands/info.d.ts.map +1 -0
  213. package/dist/cli/commands/info.js +67 -0
  214. package/dist/cli/commands/info.js.map +1 -0
  215. package/dist/cli/commands/interfaces.d.ts +3 -0
  216. package/dist/cli/commands/interfaces.d.ts.map +1 -0
  217. package/dist/cli/commands/interfaces.js +29 -0
  218. package/dist/cli/commands/interfaces.js.map +1 -0
  219. package/dist/cli/commands/map.d.ts +3 -0
  220. package/dist/cli/commands/map.d.ts.map +1 -0
  221. package/dist/cli/commands/map.js +19 -0
  222. package/dist/cli/commands/map.js.map +1 -0
  223. package/dist/cli/commands/mcp.d.ts +3 -0
  224. package/dist/cli/commands/mcp.d.ts.map +1 -0
  225. package/dist/cli/commands/mcp.js +18 -0
  226. package/dist/cli/commands/mcp.js.map +1 -0
  227. package/dist/cli/commands/models.d.ts +3 -0
  228. package/dist/cli/commands/models.d.ts.map +1 -0
  229. package/dist/cli/commands/models.js +19 -0
  230. package/dist/cli/commands/models.js.map +1 -0
  231. package/dist/cli/commands/owners.d.ts +3 -0
  232. package/dist/cli/commands/owners.d.ts.map +1 -0
  233. package/dist/cli/commands/owners.js +27 -0
  234. package/dist/cli/commands/owners.js.map +1 -0
  235. package/dist/cli/commands/path.d.ts +3 -0
  236. package/dist/cli/commands/path.d.ts.map +1 -0
  237. package/dist/cli/commands/path.js +41 -0
  238. package/dist/cli/commands/path.js.map +1 -0
  239. package/dist/cli/commands/plot.d.ts +3 -0
  240. package/dist/cli/commands/plot.d.ts.map +1 -0
  241. package/dist/cli/commands/plot.js +96 -0
  242. package/dist/cli/commands/plot.js.map +1 -0
  243. package/dist/cli/commands/query.d.ts +3 -0
  244. package/dist/cli/commands/query.d.ts.map +1 -0
  245. package/dist/cli/commands/query.js +51 -0
  246. package/dist/cli/commands/query.js.map +1 -0
  247. package/dist/cli/commands/registry.d.ts +3 -0
  248. package/dist/cli/commands/registry.d.ts.map +1 -0
  249. package/dist/cli/commands/registry.js +95 -0
  250. package/dist/cli/commands/registry.js.map +1 -0
  251. package/dist/cli/commands/roles.d.ts +3 -0
  252. package/dist/cli/commands/roles.d.ts.map +1 -0
  253. package/dist/cli/commands/roles.js +36 -0
  254. package/dist/cli/commands/roles.js.map +1 -0
  255. package/dist/cli/commands/search.d.ts +3 -0
  256. package/dist/cli/commands/search.d.ts.map +1 -0
  257. package/dist/cli/commands/search.js +43 -0
  258. package/dist/cli/commands/search.js.map +1 -0
  259. package/dist/cli/commands/sequence.d.ts +3 -0
  260. package/dist/cli/commands/sequence.d.ts.map +1 -0
  261. package/dist/cli/commands/sequence.js +29 -0
  262. package/dist/cli/commands/sequence.js.map +1 -0
  263. package/dist/cli/commands/snapshot.d.ts +3 -0
  264. package/dist/cli/commands/snapshot.d.ts.map +1 -0
  265. package/dist/cli/commands/snapshot.js +61 -0
  266. package/dist/cli/commands/snapshot.js.map +1 -0
  267. package/dist/cli/commands/stats.d.ts +3 -0
  268. package/dist/cli/commands/stats.d.ts.map +1 -0
  269. package/dist/cli/commands/stats.js +15 -0
  270. package/dist/cli/commands/stats.js.map +1 -0
  271. package/dist/cli/commands/structure.d.ts +3 -0
  272. package/dist/cli/commands/structure.d.ts.map +1 -0
  273. package/dist/cli/commands/structure.js +50 -0
  274. package/dist/cli/commands/structure.js.map +1 -0
  275. package/dist/cli/commands/triage.d.ts +3 -0
  276. package/dist/cli/commands/triage.d.ts.map +1 -0
  277. package/dist/cli/commands/triage.js +89 -0
  278. package/dist/cli/commands/triage.js.map +1 -0
  279. package/dist/cli/commands/watch.d.ts +3 -0
  280. package/dist/cli/commands/watch.d.ts.map +1 -0
  281. package/dist/cli/commands/watch.js +28 -0
  282. package/dist/cli/commands/watch.js.map +1 -0
  283. package/dist/cli/commands/where.d.ts +3 -0
  284. package/dist/cli/commands/where.d.ts.map +1 -0
  285. package/dist/cli/commands/where.js +20 -0
  286. package/dist/cli/commands/where.js.map +1 -0
  287. package/dist/cli/index.d.ts +22 -0
  288. package/dist/cli/index.d.ts.map +1 -0
  289. package/dist/cli/index.js +139 -0
  290. package/dist/cli/index.js.map +1 -0
  291. package/dist/cli/shared/open-graph.d.ts +11 -0
  292. package/dist/cli/shared/open-graph.d.ts.map +1 -0
  293. package/dist/cli/shared/open-graph.js +9 -0
  294. package/dist/cli/shared/open-graph.js.map +1 -0
  295. package/dist/cli/shared/options.d.ts +25 -0
  296. package/dist/cli/shared/options.d.ts.map +1 -0
  297. package/dist/cli/shared/options.js +66 -0
  298. package/dist/cli/shared/options.js.map +1 -0
  299. package/dist/cli/shared/output.d.ts +2 -0
  300. package/dist/cli/shared/output.d.ts.map +1 -0
  301. package/dist/cli/shared/output.js +2 -0
  302. package/dist/cli/shared/output.js.map +1 -0
  303. package/dist/cli/types.d.ts +32 -0
  304. package/dist/cli/types.d.ts.map +1 -0
  305. package/dist/cli/types.js +2 -0
  306. package/dist/cli/types.js.map +1 -0
  307. package/dist/cli.d.ts +3 -0
  308. package/dist/cli.d.ts.map +1 -0
  309. package/dist/cli.js +38 -0
  310. package/dist/cli.js.map +1 -0
  311. package/dist/db/better-sqlite3.d.ts +4 -0
  312. package/dist/db/better-sqlite3.d.ts.map +1 -0
  313. package/dist/db/better-sqlite3.js +19 -0
  314. package/dist/db/better-sqlite3.js.map +1 -0
  315. package/dist/db/connection.d.ts +82 -0
  316. package/dist/db/connection.d.ts.map +1 -0
  317. package/dist/db/connection.js +444 -0
  318. package/dist/db/connection.js.map +1 -0
  319. package/dist/db/index.d.ts +6 -0
  320. package/dist/db/index.d.ts.map +1 -0
  321. package/dist/db/index.js +6 -0
  322. package/dist/db/index.js.map +1 -0
  323. package/dist/db/migrations.d.ts +11 -0
  324. package/dist/db/migrations.d.ts.map +1 -0
  325. package/dist/db/migrations.js +416 -0
  326. package/dist/db/migrations.js.map +1 -0
  327. package/dist/db/query-builder.d.ts +88 -0
  328. package/dist/db/query-builder.d.ts.map +1 -0
  329. package/dist/db/query-builder.js +321 -0
  330. package/dist/db/query-builder.js.map +1 -0
  331. package/dist/db/repository/base.d.ts +103 -0
  332. package/dist/db/repository/base.d.ts.map +1 -0
  333. package/dist/db/repository/base.js +172 -0
  334. package/dist/db/repository/base.js.map +1 -0
  335. package/dist/db/repository/build-stmts.d.ts +16 -0
  336. package/dist/db/repository/build-stmts.d.ts.map +1 -0
  337. package/dist/db/repository/build-stmts.js +76 -0
  338. package/dist/db/repository/build-stmts.js.map +1 -0
  339. package/dist/db/repository/cached-stmt.d.ts +9 -0
  340. package/dist/db/repository/cached-stmt.d.ts.map +1 -0
  341. package/dist/db/repository/cached-stmt.js +15 -0
  342. package/dist/db/repository/cached-stmt.js.map +1 -0
  343. package/dist/db/repository/cfg.d.ts +34 -0
  344. package/dist/db/repository/cfg.d.ts.map +1 -0
  345. package/dist/db/repository/cfg.js +46 -0
  346. package/dist/db/repository/cfg.js.map +1 -0
  347. package/dist/db/repository/cochange.d.ts +14 -0
  348. package/dist/db/repository/cochange.d.ts.map +1 -0
  349. package/dist/db/repository/cochange.js +38 -0
  350. package/dist/db/repository/cochange.js.map +1 -0
  351. package/dist/db/repository/complexity.d.ts +7 -0
  352. package/dist/db/repository/complexity.d.ts.map +1 -0
  353. package/dist/db/repository/complexity.js +12 -0
  354. package/dist/db/repository/complexity.js.map +1 -0
  355. package/dist/db/repository/dataflow.d.ts +11 -0
  356. package/dist/db/repository/dataflow.d.ts.map +1 -0
  357. package/dist/db/repository/dataflow.js +30 -0
  358. package/dist/db/repository/dataflow.js.map +1 -0
  359. package/dist/db/repository/edges.d.ts +66 -0
  360. package/dist/db/repository/edges.d.ts.map +1 -0
  361. package/dist/db/repository/edges.js +175 -0
  362. package/dist/db/repository/edges.js.map +1 -0
  363. package/dist/db/repository/embeddings.d.ts +14 -0
  364. package/dist/db/repository/embeddings.d.ts.map +1 -0
  365. package/dist/db/repository/embeddings.js +40 -0
  366. package/dist/db/repository/embeddings.js.map +1 -0
  367. package/dist/db/repository/graph-read.d.ts +18 -0
  368. package/dist/db/repository/graph-read.d.ts.map +1 -0
  369. package/dist/db/repository/graph-read.js +33 -0
  370. package/dist/db/repository/graph-read.js.map +1 -0
  371. package/dist/db/repository/in-memory-repository.d.ts +88 -0
  372. package/dist/db/repository/in-memory-repository.d.ts.map +1 -0
  373. package/dist/db/repository/in-memory-repository.js +541 -0
  374. package/dist/db/repository/in-memory-repository.js.map +1 -0
  375. package/dist/db/repository/index.d.ts +16 -0
  376. package/dist/db/repository/index.d.ts.map +1 -0
  377. package/dist/db/repository/index.js +16 -0
  378. package/dist/db/repository/index.js.map +1 -0
  379. package/dist/db/repository/native-repository.d.ts +70 -0
  380. package/dist/db/repository/native-repository.d.ts.map +1 -0
  381. package/dist/db/repository/native-repository.js +418 -0
  382. package/dist/db/repository/native-repository.js.map +1 -0
  383. package/dist/db/repository/nodes.d.ts +86 -0
  384. package/dist/db/repository/nodes.d.ts.map +1 -0
  385. package/dist/db/repository/nodes.js +203 -0
  386. package/dist/db/repository/nodes.js.map +1 -0
  387. package/dist/db/repository/sqlite-repository.d.ts +59 -0
  388. package/dist/db/repository/sqlite-repository.d.ts.map +1 -0
  389. package/dist/db/repository/sqlite-repository.js +199 -0
  390. package/dist/db/repository/sqlite-repository.js.map +1 -0
  391. package/dist/domain/analysis/brief.d.ts +25 -0
  392. package/dist/domain/analysis/brief.d.ts.map +1 -0
  393. package/dist/domain/analysis/brief.js +136 -0
  394. package/dist/domain/analysis/brief.js.map +1 -0
  395. package/dist/domain/analysis/context.d.ts +241 -0
  396. package/dist/domain/analysis/context.d.ts.map +1 -0
  397. package/dist/domain/analysis/context.js +361 -0
  398. package/dist/domain/analysis/context.js.map +1 -0
  399. package/dist/domain/analysis/dependencies.d.ts +158 -0
  400. package/dist/domain/analysis/dependencies.d.ts.map +1 -0
  401. package/dist/domain/analysis/dependencies.js +522 -0
  402. package/dist/domain/analysis/dependencies.js.map +1 -0
  403. package/dist/domain/analysis/diff-impact.d.ts +90 -0
  404. package/dist/domain/analysis/diff-impact.d.ts.map +1 -0
  405. package/dist/domain/analysis/diff-impact.js +301 -0
  406. package/dist/domain/analysis/diff-impact.js.map +1 -0
  407. package/dist/domain/analysis/exports.d.ts +8 -0
  408. package/dist/domain/analysis/exports.d.ts.map +1 -0
  409. package/dist/domain/analysis/exports.js +178 -0
  410. package/dist/domain/analysis/exports.js.map +1 -0
  411. package/dist/domain/analysis/fn-impact.d.ts +61 -0
  412. package/dist/domain/analysis/fn-impact.d.ts.map +1 -0
  413. package/dist/domain/analysis/fn-impact.js +190 -0
  414. package/dist/domain/analysis/fn-impact.js.map +1 -0
  415. package/dist/domain/analysis/impact.d.ts +11 -0
  416. package/dist/domain/analysis/impact.d.ts.map +1 -0
  417. package/dist/domain/analysis/impact.js +11 -0
  418. package/dist/domain/analysis/impact.js.map +1 -0
  419. package/dist/domain/analysis/implementations.d.ts +59 -0
  420. package/dist/domain/analysis/implementations.d.ts.map +1 -0
  421. package/dist/domain/analysis/implementations.js +65 -0
  422. package/dist/domain/analysis/implementations.js.map +1 -0
  423. package/dist/domain/analysis/module-map.d.ts +86 -0
  424. package/dist/domain/analysis/module-map.d.ts.map +1 -0
  425. package/dist/domain/analysis/module-map.js +468 -0
  426. package/dist/domain/analysis/module-map.js.map +1 -0
  427. package/dist/domain/analysis/query-helpers.d.ts +27 -0
  428. package/dist/domain/analysis/query-helpers.d.ts.map +1 -0
  429. package/dist/domain/analysis/query-helpers.js +41 -0
  430. package/dist/domain/analysis/query-helpers.js.map +1 -0
  431. package/dist/domain/analysis/roles.d.ts +20 -0
  432. package/dist/domain/analysis/roles.d.ts.map +1 -0
  433. package/dist/domain/analysis/roles.js +74 -0
  434. package/dist/domain/analysis/roles.js.map +1 -0
  435. package/dist/domain/analysis/symbol-lookup.d.ts +125 -0
  436. package/dist/domain/analysis/symbol-lookup.d.ts.map +1 -0
  437. package/dist/domain/analysis/symbol-lookup.js +206 -0
  438. package/dist/domain/analysis/symbol-lookup.js.map +1 -0
  439. package/dist/domain/graph/builder/call-resolver.d.ts +89 -0
  440. package/dist/domain/graph/builder/call-resolver.d.ts.map +1 -0
  441. package/dist/domain/graph/builder/call-resolver.js +212 -0
  442. package/dist/domain/graph/builder/call-resolver.js.map +1 -0
  443. package/dist/domain/graph/builder/cha.d.ts +69 -0
  444. package/dist/domain/graph/builder/cha.d.ts.map +1 -0
  445. package/dist/domain/graph/builder/cha.js +158 -0
  446. package/dist/domain/graph/builder/cha.js.map +1 -0
  447. package/dist/domain/graph/builder/context.d.ts +91 -0
  448. package/dist/domain/graph/builder/context.d.ts.map +1 -0
  449. package/dist/domain/graph/builder/context.js +66 -0
  450. package/dist/domain/graph/builder/context.js.map +1 -0
  451. package/dist/domain/graph/builder/helpers.d.ts +97 -0
  452. package/dist/domain/graph/builder/helpers.d.ts.map +1 -0
  453. package/dist/domain/graph/builder/helpers.js +558 -0
  454. package/dist/domain/graph/builder/helpers.js.map +1 -0
  455. package/dist/domain/graph/builder/incremental.d.ts +53 -0
  456. package/dist/domain/graph/builder/incremental.d.ts.map +1 -0
  457. package/dist/domain/graph/builder/incremental.js +647 -0
  458. package/dist/domain/graph/builder/incremental.js.map +1 -0
  459. package/dist/domain/graph/builder/native-db-proxy.d.ts +24 -0
  460. package/dist/domain/graph/builder/native-db-proxy.d.ts.map +1 -0
  461. package/dist/domain/graph/builder/native-db-proxy.js +91 -0
  462. package/dist/domain/graph/builder/native-db-proxy.js.map +1 -0
  463. package/dist/domain/graph/builder/pipeline.d.ts +9 -0
  464. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -0
  465. package/dist/domain/graph/builder/pipeline.js +448 -0
  466. package/dist/domain/graph/builder/pipeline.js.map +1 -0
  467. package/dist/domain/graph/builder/stages/build-edges.d.ts +3 -0
  468. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -0
  469. package/dist/domain/graph/builder/stages/build-edges.js +1425 -0
  470. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -0
  471. package/dist/domain/graph/builder/stages/build-structure.d.ts +3 -0
  472. package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -0
  473. package/dist/domain/graph/builder/stages/build-structure.js +250 -0
  474. package/dist/domain/graph/builder/stages/build-structure.js.map +1 -0
  475. package/dist/domain/graph/builder/stages/collect-files.d.ts +3 -0
  476. package/dist/domain/graph/builder/stages/collect-files.d.ts.map +1 -0
  477. package/dist/domain/graph/builder/stages/collect-files.js +161 -0
  478. package/dist/domain/graph/builder/stages/collect-files.js.map +1 -0
  479. package/dist/domain/graph/builder/stages/detect-changes.d.ts +27 -0
  480. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -0
  481. package/dist/domain/graph/builder/stages/detect-changes.js +593 -0
  482. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -0
  483. package/dist/domain/graph/builder/stages/finalize.d.ts +3 -0
  484. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -0
  485. package/dist/domain/graph/builder/stages/finalize.js +274 -0
  486. package/dist/domain/graph/builder/stages/finalize.js.map +1 -0
  487. package/dist/domain/graph/builder/stages/insert-nodes.d.ts +35 -0
  488. package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -0
  489. package/dist/domain/graph/builder/stages/insert-nodes.js +351 -0
  490. package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -0
  491. package/dist/domain/graph/builder/stages/native-db-lifecycle.d.ts +14 -0
  492. package/dist/domain/graph/builder/stages/native-db-lifecycle.d.ts.map +1 -0
  493. package/dist/domain/graph/builder/stages/native-db-lifecycle.js +77 -0
  494. package/dist/domain/graph/builder/stages/native-db-lifecycle.js.map +1 -0
  495. package/dist/domain/graph/builder/stages/native-orchestrator.d.ts +62 -0
  496. package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -0
  497. package/dist/domain/graph/builder/stages/native-orchestrator.js +1763 -0
  498. package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -0
  499. package/dist/domain/graph/builder/stages/parse-files.d.ts +3 -0
  500. package/dist/domain/graph/builder/stages/parse-files.d.ts.map +1 -0
  501. package/dist/domain/graph/builder/stages/parse-files.js +22 -0
  502. package/dist/domain/graph/builder/stages/parse-files.js.map +1 -0
  503. package/dist/domain/graph/builder/stages/resolve-imports.d.ts +7 -0
  504. package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -0
  505. package/dist/domain/graph/builder/stages/resolve-imports.js +231 -0
  506. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -0
  507. package/dist/domain/graph/builder/stages/run-analyses.d.ts +3 -0
  508. package/dist/domain/graph/builder/stages/run-analyses.d.ts.map +1 -0
  509. package/dist/domain/graph/builder/stages/run-analyses.js +23 -0
  510. package/dist/domain/graph/builder/stages/run-analyses.js.map +1 -0
  511. package/dist/domain/graph/builder.d.ts +4 -0
  512. package/dist/domain/graph/builder.d.ts.map +1 -0
  513. package/dist/domain/graph/builder.js +6 -0
  514. package/dist/domain/graph/builder.js.map +1 -0
  515. package/dist/domain/graph/change-journal.d.ts +50 -0
  516. package/dist/domain/graph/change-journal.d.ts.map +1 -0
  517. package/dist/domain/graph/change-journal.js +97 -0
  518. package/dist/domain/graph/change-journal.js.map +1 -0
  519. package/dist/domain/graph/cycles.d.ts +19 -0
  520. package/dist/domain/graph/cycles.d.ts.map +1 -0
  521. package/dist/domain/graph/cycles.js +142 -0
  522. package/dist/domain/graph/cycles.js.map +1 -0
  523. package/dist/domain/graph/journal.d.ts +30 -0
  524. package/dist/domain/graph/journal.d.ts.map +1 -0
  525. package/dist/domain/graph/journal.js +360 -0
  526. package/dist/domain/graph/journal.js.map +1 -0
  527. package/dist/domain/graph/resolve.d.ts +67 -0
  528. package/dist/domain/graph/resolve.d.ts.map +1 -0
  529. package/dist/domain/graph/resolve.js +521 -0
  530. package/dist/domain/graph/resolve.js.map +1 -0
  531. package/dist/domain/graph/resolver/points-to.d.ts +53 -0
  532. package/dist/domain/graph/resolver/points-to.d.ts.map +1 -0
  533. package/dist/domain/graph/resolver/points-to.js +261 -0
  534. package/dist/domain/graph/resolver/points-to.js.map +1 -0
  535. package/dist/domain/graph/resolver/strategy.d.ts +61 -0
  536. package/dist/domain/graph/resolver/strategy.d.ts.map +1 -0
  537. package/dist/domain/graph/resolver/strategy.js +222 -0
  538. package/dist/domain/graph/resolver/strategy.js.map +1 -0
  539. package/dist/domain/graph/resolver/ts-resolver.d.ts +9 -0
  540. package/dist/domain/graph/resolver/ts-resolver.d.ts.map +1 -0
  541. package/dist/domain/graph/resolver/ts-resolver.js +476 -0
  542. package/dist/domain/graph/resolver/ts-resolver.js.map +1 -0
  543. package/dist/domain/graph/watcher.d.ts +23 -0
  544. package/dist/domain/graph/watcher.d.ts.map +1 -0
  545. package/dist/domain/graph/watcher.js +272 -0
  546. package/dist/domain/graph/watcher.js.map +1 -0
  547. package/dist/domain/parser.d.ts +128 -0
  548. package/dist/domain/parser.d.ts.map +1 -0
  549. package/dist/domain/parser.js +1246 -0
  550. package/dist/domain/parser.js.map +1 -0
  551. package/dist/domain/queries.d.ts +22 -0
  552. package/dist/domain/queries.d.ts.map +1 -0
  553. package/dist/domain/queries.js +26 -0
  554. package/dist/domain/queries.js.map +1 -0
  555. package/dist/domain/search/generator.d.ts +16 -0
  556. package/dist/domain/search/generator.d.ts.map +1 -0
  557. package/dist/domain/search/generator.js +181 -0
  558. package/dist/domain/search/generator.js.map +1 -0
  559. package/dist/domain/search/index.d.ts +15 -0
  560. package/dist/domain/search/index.d.ts.map +1 -0
  561. package/dist/domain/search/index.js +13 -0
  562. package/dist/domain/search/index.js.map +1 -0
  563. package/dist/domain/search/models.d.ts +63 -0
  564. package/dist/domain/search/models.d.ts.map +1 -0
  565. package/dist/domain/search/models.js +303 -0
  566. package/dist/domain/search/models.js.map +1 -0
  567. package/dist/domain/search/search/cli-formatter.d.ts +10 -0
  568. package/dist/domain/search/search/cli-formatter.d.ts.map +1 -0
  569. package/dist/domain/search/search/cli-formatter.js +134 -0
  570. package/dist/domain/search/search/cli-formatter.js.map +1 -0
  571. package/dist/domain/search/search/filters.d.ts +9 -0
  572. package/dist/domain/search/search/filters.d.ts.map +1 -0
  573. package/dist/domain/search/search/filters.js +31 -0
  574. package/dist/domain/search/search/filters.js.map +1 -0
  575. package/dist/domain/search/search/hybrid.d.ts +21 -0
  576. package/dist/domain/search/search/hybrid.d.ts.map +1 -0
  577. package/dist/domain/search/search/hybrid.js +122 -0
  578. package/dist/domain/search/search/hybrid.js.map +1 -0
  579. package/dist/domain/search/search/keyword.d.ts +18 -0
  580. package/dist/domain/search/search/keyword.d.ts.map +1 -0
  581. package/dist/domain/search/search/keyword.js +58 -0
  582. package/dist/domain/search/search/keyword.js.map +1 -0
  583. package/dist/domain/search/search/prepare.d.ts +25 -0
  584. package/dist/domain/search/search/prepare.d.ts.map +1 -0
  585. package/dist/domain/search/search/prepare.js +63 -0
  586. package/dist/domain/search/search/prepare.js.map +1 -0
  587. package/dist/domain/search/search/semantic.d.ts +41 -0
  588. package/dist/domain/search/search/semantic.d.ts.map +1 -0
  589. package/dist/domain/search/search/semantic.js +135 -0
  590. package/dist/domain/search/search/semantic.js.map +1 -0
  591. package/dist/domain/search/stores/fts5.d.ts +10 -0
  592. package/dist/domain/search/stores/fts5.d.ts.map +1 -0
  593. package/dist/domain/search/stores/fts5.js +27 -0
  594. package/dist/domain/search/stores/fts5.js.map +1 -0
  595. package/dist/domain/search/stores/sqlite-blob.d.ts +5 -0
  596. package/dist/domain/search/stores/sqlite-blob.d.ts.map +1 -0
  597. package/dist/domain/search/stores/sqlite-blob.js +16 -0
  598. package/dist/domain/search/stores/sqlite-blob.js.map +1 -0
  599. package/dist/domain/search/strategies/source.d.ts +6 -0
  600. package/dist/domain/search/strategies/source.d.ts.map +1 -0
  601. package/dist/domain/search/strategies/source.js +14 -0
  602. package/dist/domain/search/strategies/source.js.map +1 -0
  603. package/dist/domain/search/strategies/structured.d.ts +10 -0
  604. package/dist/domain/search/strategies/structured.d.ts.map +1 -0
  605. package/dist/domain/search/strategies/structured.js +35 -0
  606. package/dist/domain/search/strategies/structured.js.map +1 -0
  607. package/dist/domain/search/strategies/text-utils.d.ts +9 -0
  608. package/dist/domain/search/strategies/text-utils.d.ts.map +1 -0
  609. package/dist/domain/search/strategies/text-utils.js +45 -0
  610. package/dist/domain/search/strategies/text-utils.js.map +1 -0
  611. package/dist/domain/wasm-worker-entry.d.ts +24 -0
  612. package/dist/domain/wasm-worker-entry.d.ts.map +1 -0
  613. package/dist/domain/wasm-worker-entry.js +749 -0
  614. package/dist/domain/wasm-worker-entry.js.map +1 -0
  615. package/dist/domain/wasm-worker-pool.d.ts +59 -0
  616. package/dist/domain/wasm-worker-pool.d.ts.map +1 -0
  617. package/dist/domain/wasm-worker-pool.js +363 -0
  618. package/dist/domain/wasm-worker-pool.js.map +1 -0
  619. package/dist/domain/wasm-worker-protocol.d.ts +81 -0
  620. package/dist/domain/wasm-worker-protocol.d.ts.map +1 -0
  621. package/dist/domain/wasm-worker-protocol.js +13 -0
  622. package/dist/domain/wasm-worker-protocol.js.map +1 -0
  623. package/dist/extractors/bash.d.ts +6 -0
  624. package/dist/extractors/bash.d.ts.map +1 -0
  625. package/dist/extractors/bash.js +91 -0
  626. package/dist/extractors/bash.js.map +1 -0
  627. package/dist/extractors/c.d.ts +6 -0
  628. package/dist/extractors/c.d.ts.map +1 -0
  629. package/dist/extractors/c.js +223 -0
  630. package/dist/extractors/c.js.map +1 -0
  631. package/dist/extractors/clojure.d.ts +12 -0
  632. package/dist/extractors/clojure.d.ts.map +1 -0
  633. package/dist/extractors/clojure.js +245 -0
  634. package/dist/extractors/clojure.js.map +1 -0
  635. package/dist/extractors/cpp.d.ts +6 -0
  636. package/dist/extractors/cpp.d.ts.map +1 -0
  637. package/dist/extractors/cpp.js +365 -0
  638. package/dist/extractors/cpp.js.map +1 -0
  639. package/dist/extractors/csharp.d.ts +6 -0
  640. package/dist/extractors/csharp.d.ts.map +1 -0
  641. package/dist/extractors/csharp.js +430 -0
  642. package/dist/extractors/csharp.js.map +1 -0
  643. package/dist/extractors/cuda.d.ts +11 -0
  644. package/dist/extractors/cuda.d.ts.map +1 -0
  645. package/dist/extractors/cuda.js +419 -0
  646. package/dist/extractors/cuda.js.map +1 -0
  647. package/dist/extractors/dart.d.ts +6 -0
  648. package/dist/extractors/dart.d.ts.map +1 -0
  649. package/dist/extractors/dart.js +277 -0
  650. package/dist/extractors/dart.js.map +1 -0
  651. package/dist/extractors/elixir.d.ts +9 -0
  652. package/dist/extractors/elixir.d.ts.map +1 -0
  653. package/dist/extractors/elixir.js +327 -0
  654. package/dist/extractors/elixir.js.map +1 -0
  655. package/dist/extractors/erlang.d.ts +14 -0
  656. package/dist/extractors/erlang.d.ts.map +1 -0
  657. package/dist/extractors/erlang.js +275 -0
  658. package/dist/extractors/erlang.js.map +1 -0
  659. package/dist/extractors/fsharp.d.ts +20 -0
  660. package/dist/extractors/fsharp.d.ts.map +1 -0
  661. package/dist/extractors/fsharp.js +312 -0
  662. package/dist/extractors/fsharp.js.map +1 -0
  663. package/dist/extractors/gleam.d.ts +14 -0
  664. package/dist/extractors/gleam.d.ts.map +1 -0
  665. package/dist/extractors/gleam.js +225 -0
  666. package/dist/extractors/gleam.js.map +1 -0
  667. package/dist/extractors/go.d.ts +6 -0
  668. package/dist/extractors/go.d.ts.map +1 -0
  669. package/dist/extractors/go.js +460 -0
  670. package/dist/extractors/go.js.map +1 -0
  671. package/dist/extractors/groovy.d.ts +10 -0
  672. package/dist/extractors/groovy.d.ts.map +1 -0
  673. package/dist/extractors/groovy.js +403 -0
  674. package/dist/extractors/groovy.js.map +1 -0
  675. package/dist/extractors/haskell.d.ts +8 -0
  676. package/dist/extractors/haskell.d.ts.map +1 -0
  677. package/dist/extractors/haskell.js +261 -0
  678. package/dist/extractors/haskell.js.map +1 -0
  679. package/dist/extractors/hcl.d.ts +6 -0
  680. package/dist/extractors/hcl.d.ts.map +1 -0
  681. package/dist/extractors/hcl.js +114 -0
  682. package/dist/extractors/hcl.js.map +1 -0
  683. package/dist/extractors/helpers.d.ts +144 -0
  684. package/dist/extractors/helpers.d.ts.map +1 -0
  685. package/dist/extractors/helpers.js +360 -0
  686. package/dist/extractors/helpers.js.map +1 -0
  687. package/dist/extractors/index.d.ts +33 -0
  688. package/dist/extractors/index.d.ts.map +1 -0
  689. package/dist/extractors/index.js +33 -0
  690. package/dist/extractors/index.js.map +1 -0
  691. package/dist/extractors/java.d.ts +6 -0
  692. package/dist/extractors/java.d.ts.map +1 -0
  693. package/dist/extractors/java.js +390 -0
  694. package/dist/extractors/java.js.map +1 -0
  695. package/dist/extractors/javascript.d.ts +10 -0
  696. package/dist/extractors/javascript.d.ts.map +1 -0
  697. package/dist/extractors/javascript.js +3618 -0
  698. package/dist/extractors/javascript.js.map +1 -0
  699. package/dist/extractors/julia.d.ts +16 -0
  700. package/dist/extractors/julia.d.ts.map +1 -0
  701. package/dist/extractors/julia.js +411 -0
  702. package/dist/extractors/julia.js.map +1 -0
  703. package/dist/extractors/kotlin.d.ts +6 -0
  704. package/dist/extractors/kotlin.d.ts.map +1 -0
  705. package/dist/extractors/kotlin.js +340 -0
  706. package/dist/extractors/kotlin.js.map +1 -0
  707. package/dist/extractors/lua.d.ts +6 -0
  708. package/dist/extractors/lua.d.ts.map +1 -0
  709. package/dist/extractors/lua.js +162 -0
  710. package/dist/extractors/lua.js.map +1 -0
  711. package/dist/extractors/objc.d.ts +9 -0
  712. package/dist/extractors/objc.d.ts.map +1 -0
  713. package/dist/extractors/objc.js +543 -0
  714. package/dist/extractors/objc.js.map +1 -0
  715. package/dist/extractors/ocaml.d.ts +6 -0
  716. package/dist/extractors/ocaml.d.ts.map +1 -0
  717. package/dist/extractors/ocaml.js +310 -0
  718. package/dist/extractors/ocaml.js.map +1 -0
  719. package/dist/extractors/php.d.ts +6 -0
  720. package/dist/extractors/php.d.ts.map +1 -0
  721. package/dist/extractors/php.js +381 -0
  722. package/dist/extractors/php.js.map +1 -0
  723. package/dist/extractors/python.d.ts +6 -0
  724. package/dist/extractors/python.d.ts.map +1 -0
  725. package/dist/extractors/python.js +428 -0
  726. package/dist/extractors/python.js.map +1 -0
  727. package/dist/extractors/r.d.ts +13 -0
  728. package/dist/extractors/r.d.ts.map +1 -0
  729. package/dist/extractors/r.js +267 -0
  730. package/dist/extractors/r.js.map +1 -0
  731. package/dist/extractors/ruby.d.ts +6 -0
  732. package/dist/extractors/ruby.d.ts.map +1 -0
  733. package/dist/extractors/ruby.js +281 -0
  734. package/dist/extractors/ruby.js.map +1 -0
  735. package/dist/extractors/rust.d.ts +6 -0
  736. package/dist/extractors/rust.d.ts.map +1 -0
  737. package/dist/extractors/rust.js +354 -0
  738. package/dist/extractors/rust.js.map +1 -0
  739. package/dist/extractors/scala.d.ts +6 -0
  740. package/dist/extractors/scala.d.ts.map +1 -0
  741. package/dist/extractors/scala.js +315 -0
  742. package/dist/extractors/scala.js.map +1 -0
  743. package/dist/extractors/solidity.d.ts +9 -0
  744. package/dist/extractors/solidity.d.ts.map +1 -0
  745. package/dist/extractors/solidity.js +351 -0
  746. package/dist/extractors/solidity.js.map +1 -0
  747. package/dist/extractors/swift.d.ts +6 -0
  748. package/dist/extractors/swift.d.ts.map +1 -0
  749. package/dist/extractors/swift.js +326 -0
  750. package/dist/extractors/swift.js.map +1 -0
  751. package/dist/extractors/verilog.d.ts +9 -0
  752. package/dist/extractors/verilog.d.ts.map +1 -0
  753. package/dist/extractors/verilog.js +351 -0
  754. package/dist/extractors/verilog.js.map +1 -0
  755. package/dist/extractors/zig.d.ts +9 -0
  756. package/dist/extractors/zig.d.ts.map +1 -0
  757. package/dist/extractors/zig.js +274 -0
  758. package/dist/extractors/zig.js.map +1 -0
  759. package/dist/features/ast.d.ts +78 -0
  760. package/dist/features/ast.d.ts.map +1 -0
  761. package/dist/features/ast.js +228 -0
  762. package/dist/features/ast.js.map +1 -0
  763. package/dist/features/audit.d.ts +15 -0
  764. package/dist/features/audit.d.ts.map +1 -0
  765. package/dist/features/audit.js +275 -0
  766. package/dist/features/audit.js.map +1 -0
  767. package/dist/features/batch.d.ts +54 -0
  768. package/dist/features/batch.d.ts.map +1 -0
  769. package/dist/features/batch.js +97 -0
  770. package/dist/features/batch.js.map +1 -0
  771. package/dist/features/boundaries.d.ts +51 -0
  772. package/dist/features/boundaries.d.ts.map +1 -0
  773. package/dist/features/boundaries.js +248 -0
  774. package/dist/features/boundaries.js.map +1 -0
  775. package/dist/features/branch-compare.d.ts +71 -0
  776. package/dist/features/branch-compare.d.ts.map +1 -0
  777. package/dist/features/branch-compare.js +444 -0
  778. package/dist/features/branch-compare.js.map +1 -0
  779. package/dist/features/cfg.d.ts +79 -0
  780. package/dist/features/cfg.d.ts.map +1 -0
  781. package/dist/features/cfg.js +483 -0
  782. package/dist/features/cfg.js.map +1 -0
  783. package/dist/features/check.d.ts +84 -0
  784. package/dist/features/check.d.ts.map +1 -0
  785. package/dist/features/check.js +290 -0
  786. package/dist/features/check.js.map +1 -0
  787. package/dist/features/cochange.d.ts +68 -0
  788. package/dist/features/cochange.d.ts.map +1 -0
  789. package/dist/features/cochange.js +384 -0
  790. package/dist/features/cochange.js.map +1 -0
  791. package/dist/features/communities.d.ts +26 -0
  792. package/dist/features/communities.d.ts.map +1 -0
  793. package/dist/features/communities.js +149 -0
  794. package/dist/features/communities.js.map +1 -0
  795. package/dist/features/complexity-query.d.ts +37 -0
  796. package/dist/features/complexity-query.d.ts.map +1 -0
  797. package/dist/features/complexity-query.js +268 -0
  798. package/dist/features/complexity-query.js.map +1 -0
  799. package/dist/features/complexity.d.ts +52 -0
  800. package/dist/features/complexity.d.ts.map +1 -0
  801. package/dist/features/complexity.js +490 -0
  802. package/dist/features/complexity.js.map +1 -0
  803. package/dist/features/dataflow.d.ts +129 -0
  804. package/dist/features/dataflow.d.ts.map +1 -0
  805. package/dist/features/dataflow.js +1079 -0
  806. package/dist/features/dataflow.js.map +1 -0
  807. package/dist/features/export.d.ts +35 -0
  808. package/dist/features/export.d.ts.map +1 -0
  809. package/dist/features/export.js +340 -0
  810. package/dist/features/export.js.map +1 -0
  811. package/dist/features/flow.d.ts +21 -0
  812. package/dist/features/flow.d.ts.map +1 -0
  813. package/dist/features/flow.js +195 -0
  814. package/dist/features/flow.js.map +1 -0
  815. package/dist/features/graph-enrichment.d.ts +44 -0
  816. package/dist/features/graph-enrichment.d.ts.map +1 -0
  817. package/dist/features/graph-enrichment.js +312 -0
  818. package/dist/features/graph-enrichment.js.map +1 -0
  819. package/dist/features/manifesto.d.ts +23 -0
  820. package/dist/features/manifesto.d.ts.map +1 -0
  821. package/dist/features/manifesto.js +382 -0
  822. package/dist/features/manifesto.js.map +1 -0
  823. package/dist/features/owners.d.ts +60 -0
  824. package/dist/features/owners.d.ts.map +1 -0
  825. package/dist/features/owners.js +248 -0
  826. package/dist/features/owners.js.map +1 -0
  827. package/dist/features/sequence.d.ts +42 -0
  828. package/dist/features/sequence.d.ts.map +1 -0
  829. package/dist/features/sequence.js +271 -0
  830. package/dist/features/sequence.js.map +1 -0
  831. package/dist/features/shared/find-nodes.d.ts +7 -0
  832. package/dist/features/shared/find-nodes.d.ts.map +1 -0
  833. package/dist/features/shared/find-nodes.js +18 -0
  834. package/dist/features/shared/find-nodes.js.map +1 -0
  835. package/dist/features/snapshot.d.ts +25 -0
  836. package/dist/features/snapshot.d.ts.map +1 -0
  837. package/dist/features/snapshot.js +188 -0
  838. package/dist/features/snapshot.js.map +1 -0
  839. package/dist/features/structure-query.d.ts +76 -0
  840. package/dist/features/structure-query.d.ts.map +1 -0
  841. package/dist/features/structure-query.js +274 -0
  842. package/dist/features/structure-query.js.map +1 -0
  843. package/dist/features/structure.d.ts +39 -0
  844. package/dist/features/structure.d.ts.map +1 -0
  845. package/dist/features/structure.js +796 -0
  846. package/dist/features/structure.js.map +1 -0
  847. package/dist/features/triage.d.ts +47 -0
  848. package/dist/features/triage.d.ts.map +1 -0
  849. package/dist/features/triage.js +123 -0
  850. package/dist/features/triage.js.map +1 -0
  851. package/dist/graph/algorithms/bfs.d.ts +14 -0
  852. package/dist/graph/algorithms/bfs.d.ts.map +1 -0
  853. package/dist/graph/algorithms/bfs.js +72 -0
  854. package/dist/graph/algorithms/bfs.js.map +1 -0
  855. package/dist/graph/algorithms/centrality.d.ts +12 -0
  856. package/dist/graph/algorithms/centrality.d.ts.map +1 -0
  857. package/dist/graph/algorithms/centrality.js +42 -0
  858. package/dist/graph/algorithms/centrality.js.map +1 -0
  859. package/dist/graph/algorithms/index.d.ts +7 -0
  860. package/dist/graph/algorithms/index.d.ts.map +1 -0
  861. package/dist/graph/algorithms/index.js +7 -0
  862. package/dist/graph/algorithms/index.js.map +1 -0
  863. package/dist/graph/algorithms/leiden/adapter.d.ts +37 -0
  864. package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -0
  865. package/dist/graph/algorithms/leiden/adapter.js +173 -0
  866. package/dist/graph/algorithms/leiden/adapter.js.map +1 -0
  867. package/dist/graph/algorithms/leiden/cpm.d.ts +28 -0
  868. package/dist/graph/algorithms/leiden/cpm.d.ts.map +1 -0
  869. package/dist/graph/algorithms/leiden/cpm.js +48 -0
  870. package/dist/graph/algorithms/leiden/cpm.js.map +1 -0
  871. package/dist/graph/algorithms/leiden/index.d.ts +37 -0
  872. package/dist/graph/algorithms/leiden/index.d.ts.map +1 -0
  873. package/dist/graph/algorithms/leiden/index.js +157 -0
  874. package/dist/graph/algorithms/leiden/index.js.map +1 -0
  875. package/dist/graph/algorithms/leiden/modularity.d.ts +33 -0
  876. package/dist/graph/algorithms/leiden/modularity.d.ts.map +1 -0
  877. package/dist/graph/algorithms/leiden/modularity.js +80 -0
  878. package/dist/graph/algorithms/leiden/modularity.js.map +1 -0
  879. package/dist/graph/algorithms/leiden/optimiser.d.ts +62 -0
  880. package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -0
  881. package/dist/graph/algorithms/leiden/optimiser.js +530 -0
  882. package/dist/graph/algorithms/leiden/optimiser.js.map +1 -0
  883. package/dist/graph/algorithms/leiden/partition.d.ts +44 -0
  884. package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -0
  885. package/dist/graph/algorithms/leiden/partition.js +438 -0
  886. package/dist/graph/algorithms/leiden/partition.js.map +1 -0
  887. package/dist/graph/algorithms/leiden/rng.d.ts +9 -0
  888. package/dist/graph/algorithms/leiden/rng.d.ts.map +1 -0
  889. package/dist/graph/algorithms/leiden/rng.js +17 -0
  890. package/dist/graph/algorithms/leiden/rng.js.map +1 -0
  891. package/dist/graph/algorithms/louvain.d.ts +20 -0
  892. package/dist/graph/algorithms/louvain.d.ts.map +1 -0
  893. package/dist/graph/algorithms/louvain.js +52 -0
  894. package/dist/graph/algorithms/louvain.js.map +1 -0
  895. package/dist/graph/algorithms/shortest-path.d.ts +10 -0
  896. package/dist/graph/algorithms/shortest-path.d.ts.map +1 -0
  897. package/dist/graph/algorithms/shortest-path.js +55 -0
  898. package/dist/graph/algorithms/shortest-path.js.map +1 -0
  899. package/dist/graph/algorithms/tarjan.d.ts +9 -0
  900. package/dist/graph/algorithms/tarjan.d.ts.map +1 -0
  901. package/dist/graph/algorithms/tarjan.js +52 -0
  902. package/dist/graph/algorithms/tarjan.js.map +1 -0
  903. package/dist/graph/builders/dependency.d.ts +18 -0
  904. package/dist/graph/builders/dependency.d.ts.map +1 -0
  905. package/dist/graph/builders/dependency.js +101 -0
  906. package/dist/graph/builders/dependency.js.map +1 -0
  907. package/dist/graph/builders/index.d.ts +4 -0
  908. package/dist/graph/builders/index.d.ts.map +1 -0
  909. package/dist/graph/builders/index.js +4 -0
  910. package/dist/graph/builders/index.js.map +1 -0
  911. package/dist/graph/builders/structure.d.ts +10 -0
  912. package/dist/graph/builders/structure.d.ts.map +1 -0
  913. package/dist/graph/builders/structure.js +33 -0
  914. package/dist/graph/builders/structure.js.map +1 -0
  915. package/dist/graph/builders/temporal.d.ts +13 -0
  916. package/dist/graph/builders/temporal.d.ts.map +1 -0
  917. package/dist/graph/builders/temporal.js +29 -0
  918. package/dist/graph/builders/temporal.js.map +1 -0
  919. package/dist/graph/classifiers/index.d.ts +3 -0
  920. package/dist/graph/classifiers/index.d.ts.map +1 -0
  921. package/dist/graph/classifiers/index.js +3 -0
  922. package/dist/graph/classifiers/index.js.map +1 -0
  923. package/dist/graph/classifiers/risk.d.ts +39 -0
  924. package/dist/graph/classifiers/risk.d.ts.map +1 -0
  925. package/dist/graph/classifiers/risk.js +78 -0
  926. package/dist/graph/classifiers/risk.js.map +1 -0
  927. package/dist/graph/classifiers/roles.d.ts +48 -0
  928. package/dist/graph/classifiers/roles.d.ts.map +1 -0
  929. package/dist/graph/classifiers/roles.js +180 -0
  930. package/dist/graph/classifiers/roles.js.map +1 -0
  931. package/dist/graph/index.d.ts +5 -0
  932. package/dist/graph/index.d.ts.map +1 -0
  933. package/dist/graph/index.js +6 -0
  934. package/dist/graph/index.js.map +1 -0
  935. package/dist/graph/model.d.ts +57 -0
  936. package/dist/graph/model.d.ts.map +1 -0
  937. package/dist/graph/model.js +205 -0
  938. package/dist/graph/model.js.map +1 -0
  939. package/dist/index.cjs +16 -0
  940. package/dist/index.d.ts +37 -0
  941. package/dist/index.d.ts.map +1 -0
  942. package/dist/index.js +36 -0
  943. package/dist/index.js.map +1 -0
  944. package/dist/infrastructure/config.d.ts +281 -0
  945. package/dist/infrastructure/config.d.ts.map +1 -0
  946. package/dist/infrastructure/config.js +857 -0
  947. package/dist/infrastructure/config.js.map +1 -0
  948. package/dist/infrastructure/logger.d.ts +7 -0
  949. package/dist/infrastructure/logger.d.ts.map +1 -0
  950. package/dist/infrastructure/logger.js +21 -0
  951. package/dist/infrastructure/logger.js.map +1 -0
  952. package/dist/infrastructure/native.d.ts +38 -0
  953. package/dist/infrastructure/native.d.ts.map +1 -0
  954. package/dist/infrastructure/native.js +182 -0
  955. package/dist/infrastructure/native.js.map +1 -0
  956. package/dist/infrastructure/registry.d.ts +81 -0
  957. package/dist/infrastructure/registry.d.ts.map +1 -0
  958. package/dist/infrastructure/registry.js +229 -0
  959. package/dist/infrastructure/registry.js.map +1 -0
  960. package/dist/infrastructure/result-formatter.d.ts +2 -0
  961. package/dist/infrastructure/result-formatter.d.ts.map +1 -0
  962. package/dist/infrastructure/result-formatter.js +3 -0
  963. package/dist/infrastructure/result-formatter.js.map +1 -0
  964. package/dist/infrastructure/suppress.d.ts +25 -0
  965. package/dist/infrastructure/suppress.d.ts.map +1 -0
  966. package/dist/infrastructure/suppress.js +43 -0
  967. package/dist/infrastructure/suppress.js.map +1 -0
  968. package/dist/infrastructure/test-filter.d.ts +5 -0
  969. package/dist/infrastructure/test-filter.d.ts.map +1 -0
  970. package/dist/infrastructure/test-filter.js +7 -0
  971. package/dist/infrastructure/test-filter.js.map +1 -0
  972. package/dist/infrastructure/update-check.d.ts +26 -0
  973. package/dist/infrastructure/update-check.d.ts.map +1 -0
  974. package/dist/infrastructure/update-check.js +164 -0
  975. package/dist/infrastructure/update-check.js.map +1 -0
  976. package/dist/mcp/index.d.ts +3 -0
  977. package/dist/mcp/index.d.ts.map +1 -0
  978. package/dist/mcp/index.js +3 -0
  979. package/dist/mcp/index.js.map +1 -0
  980. package/dist/mcp/middleware.d.ts +26 -0
  981. package/dist/mcp/middleware.d.ts.map +1 -0
  982. package/dist/mcp/middleware.js +32 -0
  983. package/dist/mcp/middleware.js.map +1 -0
  984. package/dist/mcp/server.d.ts +14 -0
  985. package/dist/mcp/server.d.ts.map +1 -0
  986. package/dist/mcp/server.js +193 -0
  987. package/dist/mcp/server.js.map +1 -0
  988. package/dist/mcp/tool-registry.d.ts +21 -0
  989. package/dist/mcp/tool-registry.d.ts.map +1 -0
  990. package/dist/mcp/tool-registry.js +839 -0
  991. package/dist/mcp/tool-registry.js.map +1 -0
  992. package/dist/mcp/tools/ast-query.d.ts +14 -0
  993. package/dist/mcp/tools/ast-query.d.ts.map +1 -0
  994. package/dist/mcp/tools/ast-query.js +13 -0
  995. package/dist/mcp/tools/ast-query.js.map +1 -0
  996. package/dist/mcp/tools/audit.d.ts +15 -0
  997. package/dist/mcp/tools/audit.d.ts.map +1 -0
  998. package/dist/mcp/tools/audit.js +20 -0
  999. package/dist/mcp/tools/audit.js.map +1 -0
  1000. package/dist/mcp/tools/batch-query.d.ts +13 -0
  1001. package/dist/mcp/tools/batch-query.d.ts.map +1 -0
  1002. package/dist/mcp/tools/batch-query.js +11 -0
  1003. package/dist/mcp/tools/batch-query.js.map +1 -0
  1004. package/dist/mcp/tools/branch-compare.d.ts +12 -0
  1005. package/dist/mcp/tools/branch-compare.d.ts.map +1 -0
  1006. package/dist/mcp/tools/branch-compare.js +10 -0
  1007. package/dist/mcp/tools/branch-compare.js.map +1 -0
  1008. package/dist/mcp/tools/brief.d.ts +9 -0
  1009. package/dist/mcp/tools/brief.d.ts.map +1 -0
  1010. package/dist/mcp/tools/brief.js +8 -0
  1011. package/dist/mcp/tools/brief.js.map +1 -0
  1012. package/dist/mcp/tools/cfg.d.ts +14 -0
  1013. package/dist/mcp/tools/cfg.d.ts.map +1 -0
  1014. package/dist/mcp/tools/cfg.js +20 -0
  1015. package/dist/mcp/tools/cfg.js.map +1 -0
  1016. package/dist/mcp/tools/check.d.ts +20 -0
  1017. package/dist/mcp/tools/check.d.ts.map +1 -0
  1018. package/dist/mcp/tools/check.js +39 -0
  1019. package/dist/mcp/tools/check.js.map +1 -0
  1020. package/dist/mcp/tools/co-changes.d.ts +12 -0
  1021. package/dist/mcp/tools/co-changes.d.ts.map +1 -0
  1022. package/dist/mcp/tools/co-changes.js +19 -0
  1023. package/dist/mcp/tools/co-changes.js.map +1 -0
  1024. package/dist/mcp/tools/code-owners.d.ts +12 -0
  1025. package/dist/mcp/tools/code-owners.d.ts.map +1 -0
  1026. package/dist/mcp/tools/code-owners.js +12 -0
  1027. package/dist/mcp/tools/code-owners.js.map +1 -0
  1028. package/dist/mcp/tools/communities.d.ts +13 -0
  1029. package/dist/mcp/tools/communities.d.ts.map +1 -0
  1030. package/dist/mcp/tools/communities.js +14 -0
  1031. package/dist/mcp/tools/communities.js.map +1 -0
  1032. package/dist/mcp/tools/complexity.d.ts +16 -0
  1033. package/dist/mcp/tools/complexity.d.ts.map +1 -0
  1034. package/dist/mcp/tools/complexity.js +16 -0
  1035. package/dist/mcp/tools/complexity.js.map +1 -0
  1036. package/dist/mcp/tools/context.d.ts +16 -0
  1037. package/dist/mcp/tools/context.d.ts.map +1 -0
  1038. package/dist/mcp/tools/context.js +16 -0
  1039. package/dist/mcp/tools/context.js.map +1 -0
  1040. package/dist/mcp/tools/dataflow.d.ts +15 -0
  1041. package/dist/mcp/tools/dataflow.d.ts.map +1 -0
  1042. package/dist/mcp/tools/dataflow.js +25 -0
  1043. package/dist/mcp/tools/dataflow.js.map +1 -0
  1044. package/dist/mcp/tools/diff-impact.d.ts +14 -0
  1045. package/dist/mcp/tools/diff-impact.d.ts.map +1 -0
  1046. package/dist/mcp/tools/diff-impact.js +23 -0
  1047. package/dist/mcp/tools/diff-impact.js.map +1 -0
  1048. package/dist/mcp/tools/execution-flow.d.ts +15 -0
  1049. package/dist/mcp/tools/execution-flow.d.ts.map +1 -0
  1050. package/dist/mcp/tools/execution-flow.js +25 -0
  1051. package/dist/mcp/tools/execution-flow.js.map +1 -0
  1052. package/dist/mcp/tools/export-graph.d.ts +11 -0
  1053. package/dist/mcp/tools/export-graph.d.ts.map +1 -0
  1054. package/dist/mcp/tools/export-graph.js +57 -0
  1055. package/dist/mcp/tools/export-graph.js.map +1 -0
  1056. package/dist/mcp/tools/file-deps.d.ts +11 -0
  1057. package/dist/mcp/tools/file-deps.d.ts.map +1 -0
  1058. package/dist/mcp/tools/file-deps.js +11 -0
  1059. package/dist/mcp/tools/file-deps.js.map +1 -0
  1060. package/dist/mcp/tools/file-exports.d.ts +12 -0
  1061. package/dist/mcp/tools/file-exports.d.ts.map +1 -0
  1062. package/dist/mcp/tools/file-exports.js +12 -0
  1063. package/dist/mcp/tools/file-exports.js.map +1 -0
  1064. package/dist/mcp/tools/find-cycles.d.ts +7 -0
  1065. package/dist/mcp/tools/find-cycles.d.ts.map +1 -0
  1066. package/dist/mcp/tools/find-cycles.js +15 -0
  1067. package/dist/mcp/tools/find-cycles.js.map +1 -0
  1068. package/dist/mcp/tools/fn-impact.d.ts +14 -0
  1069. package/dist/mcp/tools/fn-impact.d.ts.map +1 -0
  1070. package/dist/mcp/tools/fn-impact.js +14 -0
  1071. package/dist/mcp/tools/fn-impact.js.map +1 -0
  1072. package/dist/mcp/tools/impact-analysis.d.ts +9 -0
  1073. package/dist/mcp/tools/impact-analysis.d.ts.map +1 -0
  1074. package/dist/mcp/tools/impact-analysis.js +8 -0
  1075. package/dist/mcp/tools/impact-analysis.js.map +1 -0
  1076. package/dist/mcp/tools/implementations.d.ts +13 -0
  1077. package/dist/mcp/tools/implementations.d.ts.map +1 -0
  1078. package/dist/mcp/tools/implementations.js +13 -0
  1079. package/dist/mcp/tools/implementations.js.map +1 -0
  1080. package/dist/mcp/tools/index.d.ts +7 -0
  1081. package/dist/mcp/tools/index.d.ts.map +1 -0
  1082. package/dist/mcp/tools/index.js +76 -0
  1083. package/dist/mcp/tools/index.js.map +1 -0
  1084. package/dist/mcp/tools/interfaces.d.ts +13 -0
  1085. package/dist/mcp/tools/interfaces.d.ts.map +1 -0
  1086. package/dist/mcp/tools/interfaces.js +13 -0
  1087. package/dist/mcp/tools/interfaces.js.map +1 -0
  1088. package/dist/mcp/tools/list-functions.d.ts +12 -0
  1089. package/dist/mcp/tools/list-functions.d.ts.map +1 -0
  1090. package/dist/mcp/tools/list-functions.js +13 -0
  1091. package/dist/mcp/tools/list-functions.js.map +1 -0
  1092. package/dist/mcp/tools/list-repos.d.ts +8 -0
  1093. package/dist/mcp/tools/list-repos.d.ts.map +1 -0
  1094. package/dist/mcp/tools/list-repos.js +11 -0
  1095. package/dist/mcp/tools/list-repos.js.map +1 -0
  1096. package/dist/mcp/tools/module-map.d.ts +9 -0
  1097. package/dist/mcp/tools/module-map.d.ts.map +1 -0
  1098. package/dist/mcp/tools/module-map.js +6 -0
  1099. package/dist/mcp/tools/module-map.js.map +1 -0
  1100. package/dist/mcp/tools/node-roles.d.ts +12 -0
  1101. package/dist/mcp/tools/node-roles.d.ts.map +1 -0
  1102. package/dist/mcp/tools/node-roles.js +13 -0
  1103. package/dist/mcp/tools/node-roles.js.map +1 -0
  1104. package/dist/mcp/tools/path.d.ts +15 -0
  1105. package/dist/mcp/tools/path.d.ts.map +1 -0
  1106. package/dist/mcp/tools/path.js +21 -0
  1107. package/dist/mcp/tools/path.js.map +1 -0
  1108. package/dist/mcp/tools/query.d.ts +20 -0
  1109. package/dist/mcp/tools/query.d.ts.map +1 -0
  1110. package/dist/mcp/tools/query.js +29 -0
  1111. package/dist/mcp/tools/query.js.map +1 -0
  1112. package/dist/mcp/tools/semantic-search.d.ts +13 -0
  1113. package/dist/mcp/tools/semantic-search.d.ts.map +1 -0
  1114. package/dist/mcp/tools/semantic-search.js +62 -0
  1115. package/dist/mcp/tools/semantic-search.js.map +1 -0
  1116. package/dist/mcp/tools/sequence.d.ts +16 -0
  1117. package/dist/mcp/tools/sequence.d.ts.map +1 -0
  1118. package/dist/mcp/tools/sequence.js +16 -0
  1119. package/dist/mcp/tools/sequence.js.map +1 -0
  1120. package/dist/mcp/tools/structure.d.ts +13 -0
  1121. package/dist/mcp/tools/structure.d.ts.map +1 -0
  1122. package/dist/mcp/tools/structure.js +14 -0
  1123. package/dist/mcp/tools/structure.js.map +1 -0
  1124. package/dist/mcp/tools/symbol-children.d.ts +13 -0
  1125. package/dist/mcp/tools/symbol-children.d.ts.map +1 -0
  1126. package/dist/mcp/tools/symbol-children.js +13 -0
  1127. package/dist/mcp/tools/symbol-children.js.map +1 -0
  1128. package/dist/mcp/tools/triage.d.ts +17 -0
  1129. package/dist/mcp/tools/triage.d.ts.map +1 -0
  1130. package/dist/mcp/tools/triage.js +34 -0
  1131. package/dist/mcp/tools/triage.js.map +1 -0
  1132. package/dist/mcp/tools/where.d.ts +12 -0
  1133. package/dist/mcp/tools/where.d.ts.map +1 -0
  1134. package/dist/mcp/tools/where.js +12 -0
  1135. package/dist/mcp/tools/where.js.map +1 -0
  1136. package/dist/mcp/types.d.ts +19 -0
  1137. package/dist/mcp/types.d.ts.map +1 -0
  1138. package/dist/mcp/types.js +6 -0
  1139. package/dist/mcp/types.js.map +1 -0
  1140. package/dist/presentation/audit.d.ts +15 -0
  1141. package/dist/presentation/audit.d.ts.map +1 -0
  1142. package/dist/presentation/audit.js +78 -0
  1143. package/dist/presentation/audit.js.map +1 -0
  1144. package/dist/presentation/batch.d.ts +20 -0
  1145. package/dist/presentation/batch.d.ts.map +1 -0
  1146. package/dist/presentation/batch.js +21 -0
  1147. package/dist/presentation/batch.js.map +1 -0
  1148. package/dist/presentation/branch-compare.d.ts +13 -0
  1149. package/dist/presentation/branch-compare.d.ts.map +1 -0
  1150. package/dist/presentation/branch-compare.js +91 -0
  1151. package/dist/presentation/branch-compare.js.map +1 -0
  1152. package/dist/presentation/brief.d.ts +9 -0
  1153. package/dist/presentation/brief.d.ts.map +1 -0
  1154. package/dist/presentation/brief.js +39 -0
  1155. package/dist/presentation/brief.js.map +1 -0
  1156. package/dist/presentation/cfg.d.ts +13 -0
  1157. package/dist/presentation/cfg.d.ts.map +1 -0
  1158. package/dist/presentation/cfg.js +62 -0
  1159. package/dist/presentation/cfg.js.map +1 -0
  1160. package/dist/presentation/check.d.ts +19 -0
  1161. package/dist/presentation/check.d.ts.map +1 -0
  1162. package/dist/presentation/check.js +74 -0
  1163. package/dist/presentation/check.js.map +1 -0
  1164. package/dist/presentation/cochange.d.ts +32 -0
  1165. package/dist/presentation/cochange.d.ts.map +1 -0
  1166. package/dist/presentation/cochange.js +33 -0
  1167. package/dist/presentation/cochange.js.map +1 -0
  1168. package/dist/presentation/colors.d.ts +12 -0
  1169. package/dist/presentation/colors.d.ts.map +1 -0
  1170. package/dist/presentation/colors.js +47 -0
  1171. package/dist/presentation/colors.js.map +1 -0
  1172. package/dist/presentation/communities.d.ts +11 -0
  1173. package/dist/presentation/communities.d.ts.map +1 -0
  1174. package/dist/presentation/communities.js +57 -0
  1175. package/dist/presentation/communities.js.map +1 -0
  1176. package/dist/presentation/complexity.d.ts +17 -0
  1177. package/dist/presentation/complexity.d.ts.map +1 -0
  1178. package/dist/presentation/complexity.js +59 -0
  1179. package/dist/presentation/complexity.js.map +1 -0
  1180. package/dist/presentation/dataflow.d.ts +14 -0
  1181. package/dist/presentation/dataflow.d.ts.map +1 -0
  1182. package/dist/presentation/dataflow.js +100 -0
  1183. package/dist/presentation/dataflow.js.map +1 -0
  1184. package/dist/presentation/diff-impact-mermaid.d.ts +11 -0
  1185. package/dist/presentation/diff-impact-mermaid.d.ts.map +1 -0
  1186. package/dist/presentation/diff-impact-mermaid.js +114 -0
  1187. package/dist/presentation/diff-impact-mermaid.js.map +1 -0
  1188. package/dist/presentation/export.d.ts +130 -0
  1189. package/dist/presentation/export.d.ts.map +1 -0
  1190. package/dist/presentation/export.js +311 -0
  1191. package/dist/presentation/export.js.map +1 -0
  1192. package/dist/presentation/flow.d.ts +16 -0
  1193. package/dist/presentation/flow.d.ts.map +1 -0
  1194. package/dist/presentation/flow.js +85 -0
  1195. package/dist/presentation/flow.js.map +1 -0
  1196. package/dist/presentation/manifesto.d.ts +13 -0
  1197. package/dist/presentation/manifesto.d.ts.map +1 -0
  1198. package/dist/presentation/manifesto.js +51 -0
  1199. package/dist/presentation/manifesto.js.map +1 -0
  1200. package/dist/presentation/owners.d.ts +16 -0
  1201. package/dist/presentation/owners.d.ts.map +1 -0
  1202. package/dist/presentation/owners.js +42 -0
  1203. package/dist/presentation/owners.js.map +1 -0
  1204. package/dist/presentation/queries-cli/exports.d.ts +12 -0
  1205. package/dist/presentation/queries-cli/exports.d.ts.map +1 -0
  1206. package/dist/presentation/queries-cli/exports.js +100 -0
  1207. package/dist/presentation/queries-cli/exports.js.map +1 -0
  1208. package/dist/presentation/queries-cli/impact.d.ts +23 -0
  1209. package/dist/presentation/queries-cli/impact.d.ts.map +1 -0
  1210. package/dist/presentation/queries-cli/impact.js +208 -0
  1211. package/dist/presentation/queries-cli/impact.js.map +1 -0
  1212. package/dist/presentation/queries-cli/index.d.ts +6 -0
  1213. package/dist/presentation/queries-cli/index.d.ts.map +1 -0
  1214. package/dist/presentation/queries-cli/index.js +6 -0
  1215. package/dist/presentation/queries-cli/index.js.map +1 -0
  1216. package/dist/presentation/queries-cli/inspect.d.ts +23 -0
  1217. package/dist/presentation/queries-cli/inspect.d.ts.map +1 -0
  1218. package/dist/presentation/queries-cli/inspect.js +376 -0
  1219. package/dist/presentation/queries-cli/inspect.js.map +1 -0
  1220. package/dist/presentation/queries-cli/overview.d.ts +19 -0
  1221. package/dist/presentation/queries-cli/overview.d.ts.map +1 -0
  1222. package/dist/presentation/queries-cli/overview.js +196 -0
  1223. package/dist/presentation/queries-cli/overview.js.map +1 -0
  1224. package/dist/presentation/queries-cli/path.d.ts +15 -0
  1225. package/dist/presentation/queries-cli/path.d.ts.map +1 -0
  1226. package/dist/presentation/queries-cli/path.js +101 -0
  1227. package/dist/presentation/queries-cli/path.js.map +1 -0
  1228. package/dist/presentation/queries-cli.d.ts +12 -0
  1229. package/dist/presentation/queries-cli.d.ts.map +1 -0
  1230. package/dist/presentation/queries-cli.js +12 -0
  1231. package/dist/presentation/queries-cli.js.map +1 -0
  1232. package/dist/presentation/query.d.ts +2 -0
  1233. package/dist/presentation/query.d.ts.map +1 -0
  1234. package/dist/presentation/query.js +2 -0
  1235. package/dist/presentation/query.js.map +1 -0
  1236. package/dist/presentation/result-formatter.d.ts +23 -0
  1237. package/dist/presentation/result-formatter.d.ts.map +1 -0
  1238. package/dist/presentation/result-formatter.js +122 -0
  1239. package/dist/presentation/result-formatter.js.map +1 -0
  1240. package/dist/presentation/sequence-renderer.d.ts +19 -0
  1241. package/dist/presentation/sequence-renderer.d.ts.map +1 -0
  1242. package/dist/presentation/sequence-renderer.js +23 -0
  1243. package/dist/presentation/sequence-renderer.js.map +1 -0
  1244. package/dist/presentation/sequence.d.ts +15 -0
  1245. package/dist/presentation/sequence.d.ts.map +1 -0
  1246. package/dist/presentation/sequence.js +26 -0
  1247. package/dist/presentation/sequence.js.map +1 -0
  1248. package/dist/presentation/structure.d.ts +46 -0
  1249. package/dist/presentation/structure.d.ts.map +1 -0
  1250. package/dist/presentation/structure.js +50 -0
  1251. package/dist/presentation/structure.js.map +1 -0
  1252. package/dist/presentation/table.d.ts +24 -0
  1253. package/dist/presentation/table.d.ts.map +1 -0
  1254. package/dist/presentation/table.js +33 -0
  1255. package/dist/presentation/table.js.map +1 -0
  1256. package/dist/presentation/triage.d.ts +19 -0
  1257. package/dist/presentation/triage.d.ts.map +1 -0
  1258. package/dist/presentation/triage.js +34 -0
  1259. package/dist/presentation/triage.js.map +1 -0
  1260. package/dist/presentation/viewer.d.ts +102 -0
  1261. package/dist/presentation/viewer.d.ts.map +1 -0
  1262. package/dist/presentation/viewer.js +618 -0
  1263. package/dist/presentation/viewer.js.map +1 -0
  1264. package/dist/shared/constants.d.ts +33 -0
  1265. package/dist/shared/constants.d.ts.map +1 -0
  1266. package/dist/shared/constants.js +54 -0
  1267. package/dist/shared/constants.js.map +1 -0
  1268. package/dist/shared/errors.d.ts +46 -0
  1269. package/dist/shared/errors.d.ts.map +1 -0
  1270. package/dist/shared/errors.js +69 -0
  1271. package/dist/shared/errors.js.map +1 -0
  1272. package/dist/shared/file-utils.d.ts +27 -0
  1273. package/dist/shared/file-utils.d.ts.map +1 -0
  1274. package/dist/shared/file-utils.js +186 -0
  1275. package/dist/shared/file-utils.js.map +1 -0
  1276. package/dist/shared/generators.d.ts +57 -0
  1277. package/dist/shared/generators.d.ts.map +1 -0
  1278. package/dist/shared/generators.js +106 -0
  1279. package/dist/shared/generators.js.map +1 -0
  1280. package/dist/shared/globs.d.ts +40 -0
  1281. package/dist/shared/globs.d.ts.map +1 -0
  1282. package/dist/shared/globs.js +126 -0
  1283. package/dist/shared/globs.js.map +1 -0
  1284. package/dist/shared/hierarchy.d.ts +9 -0
  1285. package/dist/shared/hierarchy.d.ts.map +1 -0
  1286. package/dist/shared/hierarchy.js +68 -0
  1287. package/dist/shared/hierarchy.js.map +1 -0
  1288. package/dist/shared/kinds.d.ts +12 -0
  1289. package/dist/shared/kinds.d.ts.map +1 -0
  1290. package/dist/shared/kinds.js +67 -0
  1291. package/dist/shared/kinds.js.map +1 -0
  1292. package/dist/shared/normalize.d.ts +49 -0
  1293. package/dist/shared/normalize.d.ts.map +1 -0
  1294. package/dist/shared/normalize.js +57 -0
  1295. package/dist/shared/normalize.js.map +1 -0
  1296. package/dist/shared/paginate.d.ts +32 -0
  1297. package/dist/shared/paginate.d.ts.map +1 -0
  1298. package/dist/shared/paginate.js +82 -0
  1299. package/dist/shared/paginate.js.map +1 -0
  1300. package/dist/shared/version.d.ts +2 -0
  1301. package/dist/shared/version.d.ts.map +1 -0
  1302. package/dist/shared/version.js +5 -0
  1303. package/dist/shared/version.js.map +1 -0
  1304. package/dist/types.d.ts +2468 -0
  1305. package/dist/types.d.ts.map +1 -0
  1306. package/dist/types.js +10 -0
  1307. package/dist/types.js.map +1 -0
  1308. package/grammars/tree-sitter-bash.wasm +0 -0
  1309. package/grammars/tree-sitter-c.wasm +0 -0
  1310. package/grammars/tree-sitter-c_sharp.wasm +0 -0
  1311. package/grammars/tree-sitter-clojure.wasm +0 -0
  1312. package/grammars/tree-sitter-cpp.wasm +0 -0
  1313. package/grammars/tree-sitter-cuda.wasm +0 -0
  1314. package/grammars/tree-sitter-dart.wasm +0 -0
  1315. package/grammars/tree-sitter-elixir.wasm +0 -0
  1316. package/grammars/tree-sitter-erlang.wasm +0 -0
  1317. package/grammars/tree-sitter-fsharp.wasm +0 -0
  1318. package/grammars/tree-sitter-fsharp_signature.wasm +0 -0
  1319. package/grammars/tree-sitter-gleam.wasm +0 -0
  1320. package/grammars/tree-sitter-go.wasm +0 -0
  1321. package/grammars/tree-sitter-groovy.wasm +0 -0
  1322. package/grammars/tree-sitter-haskell.wasm +0 -0
  1323. package/grammars/tree-sitter-hcl.wasm +0 -0
  1324. package/grammars/tree-sitter-java.wasm +0 -0
  1325. package/grammars/tree-sitter-javascript.wasm +0 -0
  1326. package/grammars/tree-sitter-julia.wasm +0 -0
  1327. package/grammars/tree-sitter-kotlin.wasm +0 -0
  1328. package/grammars/tree-sitter-lua.wasm +0 -0
  1329. package/grammars/tree-sitter-objc.wasm +0 -0
  1330. package/grammars/tree-sitter-ocaml.wasm +0 -0
  1331. package/grammars/tree-sitter-ocaml_interface.wasm +0 -0
  1332. package/grammars/tree-sitter-php.wasm +0 -0
  1333. package/grammars/tree-sitter-python.wasm +0 -0
  1334. package/grammars/tree-sitter-r.wasm +0 -0
  1335. package/grammars/tree-sitter-ruby.wasm +0 -0
  1336. package/grammars/tree-sitter-rust.wasm +0 -0
  1337. package/grammars/tree-sitter-scala.wasm +0 -0
  1338. package/grammars/tree-sitter-solidity.wasm +0 -0
  1339. package/grammars/tree-sitter-swift.wasm +0 -0
  1340. package/grammars/tree-sitter-tsx.wasm +0 -0
  1341. package/grammars/tree-sitter-typescript.wasm +0 -0
  1342. package/grammars/tree-sitter-verilog.wasm +0 -0
  1343. package/grammars/tree-sitter-zig.wasm +0 -0
  1344. package/package.json +188 -0
  1345. package/src/ast-analysis/engine.ts +926 -0
  1346. package/src/ast-analysis/metrics.ts +150 -0
  1347. package/src/ast-analysis/rules/b2.ts +263 -0
  1348. package/src/ast-analysis/rules/b3.ts +127 -0
  1349. package/src/ast-analysis/rules/b4.ts +378 -0
  1350. package/src/ast-analysis/rules/b5.ts +65 -0
  1351. package/src/ast-analysis/rules/c.ts +157 -0
  1352. package/src/ast-analysis/rules/csharp.ts +210 -0
  1353. package/src/ast-analysis/rules/go.ts +187 -0
  1354. package/src/ast-analysis/rules/index.ts +380 -0
  1355. package/src/ast-analysis/rules/java.ts +181 -0
  1356. package/src/ast-analysis/rules/javascript.ts +249 -0
  1357. package/src/ast-analysis/rules/php.ts +226 -0
  1358. package/src/ast-analysis/rules/python.ts +202 -0
  1359. package/src/ast-analysis/rules/ruby.ts +209 -0
  1360. package/src/ast-analysis/rules/rust.ts +179 -0
  1361. package/src/ast-analysis/shared.ts +223 -0
  1362. package/src/ast-analysis/visitor-utils.ts +278 -0
  1363. package/src/ast-analysis/visitor.ts +266 -0
  1364. package/src/ast-analysis/visitors/ast-store-visitor.ts +334 -0
  1365. package/src/ast-analysis/visitors/cfg-conditionals.ts +227 -0
  1366. package/src/ast-analysis/visitors/cfg-loops.ts +136 -0
  1367. package/src/ast-analysis/visitors/cfg-shared.ts +196 -0
  1368. package/src/ast-analysis/visitors/cfg-try-catch.ts +142 -0
  1369. package/src/ast-analysis/visitors/cfg-visitor.ts +367 -0
  1370. package/src/ast-analysis/visitors/complexity-visitor.ts +328 -0
  1371. package/src/ast-analysis/visitors/dataflow-visitor.ts +571 -0
  1372. package/src/cli/commands/ast.ts +24 -0
  1373. package/src/cli/commands/audit.ts +48 -0
  1374. package/src/cli/commands/batch.ts +66 -0
  1375. package/src/cli/commands/branch-compare.ts +27 -0
  1376. package/src/cli/commands/brief.ts +13 -0
  1377. package/src/cli/commands/build.ts +35 -0
  1378. package/src/cli/commands/cfg.ts +28 -0
  1379. package/src/cli/commands/check.ts +72 -0
  1380. package/src/cli/commands/children.ts +34 -0
  1381. package/src/cli/commands/co-change.ts +72 -0
  1382. package/src/cli/commands/communities.ts +21 -0
  1383. package/src/cli/commands/complexity.ts +48 -0
  1384. package/src/cli/commands/config.ts +353 -0
  1385. package/src/cli/commands/context.ts +36 -0
  1386. package/src/cli/commands/cycles.ts +33 -0
  1387. package/src/cli/commands/dataflow.ts +30 -0
  1388. package/src/cli/commands/deps.ts +18 -0
  1389. package/src/cli/commands/diff-impact.ts +30 -0
  1390. package/src/cli/commands/embed.ts +82 -0
  1391. package/src/cli/commands/export.ts +79 -0
  1392. package/src/cli/commands/exports.ts +15 -0
  1393. package/src/cli/commands/flow.ts +34 -0
  1394. package/src/cli/commands/fn-impact.ts +34 -0
  1395. package/src/cli/commands/impact.ts +13 -0
  1396. package/src/cli/commands/implementations.ts +30 -0
  1397. package/src/cli/commands/info.ts +79 -0
  1398. package/src/cli/commands/interfaces.ts +30 -0
  1399. package/src/cli/commands/map.ts +20 -0
  1400. package/src/cli/commands/mcp.ts +19 -0
  1401. package/src/cli/commands/models.ts +29 -0
  1402. package/src/cli/commands/owners.ts +28 -0
  1403. package/src/cli/commands/path.ts +42 -0
  1404. package/src/cli/commands/plot.ts +110 -0
  1405. package/src/cli/commands/query.ts +51 -0
  1406. package/src/cli/commands/registry.ts +106 -0
  1407. package/src/cli/commands/roles.ts +38 -0
  1408. package/src/cli/commands/search.ts +45 -0
  1409. package/src/cli/commands/sequence.ts +30 -0
  1410. package/src/cli/commands/snapshot.ts +67 -0
  1411. package/src/cli/commands/stats.ts +16 -0
  1412. package/src/cli/commands/structure.ts +55 -0
  1413. package/src/cli/commands/triage.ts +93 -0
  1414. package/src/cli/commands/watch.ts +29 -0
  1415. package/src/cli/commands/where.ts +21 -0
  1416. package/src/cli/index.ts +159 -0
  1417. package/src/cli/shared/open-graph.ts +13 -0
  1418. package/src/cli/shared/options.ts +69 -0
  1419. package/src/cli/shared/output.ts +1 -0
  1420. package/src/cli/types.ts +35 -0
  1421. package/src/cli.ts +37 -0
  1422. package/src/db/better-sqlite3.ts +21 -0
  1423. package/src/db/connection.ts +478 -0
  1424. package/src/db/index.ts +84 -0
  1425. package/src/db/migrations.ts +440 -0
  1426. package/src/db/query-builder.ts +371 -0
  1427. package/src/db/repository/base.ts +269 -0
  1428. package/src/db/repository/build-stmts.ts +126 -0
  1429. package/src/db/repository/cached-stmt.ts +20 -0
  1430. package/src/db/repository/cfg.ts +81 -0
  1431. package/src/db/repository/cochange.ts +48 -0
  1432. package/src/db/repository/complexity.ts +21 -0
  1433. package/src/db/repository/dataflow.ts +35 -0
  1434. package/src/db/repository/edges.ts +281 -0
  1435. package/src/db/repository/embeddings.ts +47 -0
  1436. package/src/db/repository/graph-read.ts +62 -0
  1437. package/src/db/repository/in-memory-repository.ts +657 -0
  1438. package/src/db/repository/index.ts +53 -0
  1439. package/src/db/repository/native-repository.ts +546 -0
  1440. package/src/db/repository/nodes.ts +322 -0
  1441. package/src/db/repository/sqlite-repository.ts +303 -0
  1442. package/src/domain/analysis/brief.ts +165 -0
  1443. package/src/domain/analysis/context.ts +537 -0
  1444. package/src/domain/analysis/dependencies.ts +738 -0
  1445. package/src/domain/analysis/diff-impact.ts +381 -0
  1446. package/src/domain/analysis/exports.ts +262 -0
  1447. package/src/domain/analysis/fn-impact.ts +311 -0
  1448. package/src/domain/analysis/impact.ts +11 -0
  1449. package/src/domain/analysis/implementations.ts +81 -0
  1450. package/src/domain/analysis/module-map.ts +576 -0
  1451. package/src/domain/analysis/query-helpers.ts +52 -0
  1452. package/src/domain/analysis/roles.ts +95 -0
  1453. package/src/domain/analysis/symbol-lookup.ts +284 -0
  1454. package/src/domain/graph/builder/call-resolver.ts +289 -0
  1455. package/src/domain/graph/builder/cha.ts +192 -0
  1456. package/src/domain/graph/builder/context.ts +120 -0
  1457. package/src/domain/graph/builder/helpers.ts +665 -0
  1458. package/src/domain/graph/builder/incremental.ts +987 -0
  1459. package/src/domain/graph/builder/native-db-proxy.ts +104 -0
  1460. package/src/domain/graph/builder/pipeline.ts +517 -0
  1461. package/src/domain/graph/builder/stages/build-edges.ts +1986 -0
  1462. package/src/domain/graph/builder/stages/build-structure.ts +330 -0
  1463. package/src/domain/graph/builder/stages/collect-files.ts +175 -0
  1464. package/src/domain/graph/builder/stages/detect-changes.ts +751 -0
  1465. package/src/domain/graph/builder/stages/finalize.ts +321 -0
  1466. package/src/domain/graph/builder/stages/insert-nodes.ts +489 -0
  1467. package/src/domain/graph/builder/stages/native-db-lifecycle.ts +74 -0
  1468. package/src/domain/graph/builder/stages/native-orchestrator.ts +2241 -0
  1469. package/src/domain/graph/builder/stages/parse-files.ts +26 -0
  1470. package/src/domain/graph/builder/stages/resolve-imports.ts +285 -0
  1471. package/src/domain/graph/builder/stages/run-analyses.ts +26 -0
  1472. package/src/domain/graph/builder.ts +11 -0
  1473. package/src/domain/graph/change-journal.ts +141 -0
  1474. package/src/domain/graph/cycles.ts +155 -0
  1475. package/src/domain/graph/journal.ts +377 -0
  1476. package/src/domain/graph/resolve.ts +579 -0
  1477. package/src/domain/graph/resolver/points-to.ts +377 -0
  1478. package/src/domain/graph/resolver/strategy.ts +265 -0
  1479. package/src/domain/graph/resolver/ts-resolver.ts +536 -0
  1480. package/src/domain/graph/watcher.ts +339 -0
  1481. package/src/domain/parser.ts +1437 -0
  1482. package/src/domain/queries.ts +50 -0
  1483. package/src/domain/search/generator.ts +260 -0
  1484. package/src/domain/search/index.ts +15 -0
  1485. package/src/domain/search/models.ts +356 -0
  1486. package/src/domain/search/search/cli-formatter.ts +179 -0
  1487. package/src/domain/search/search/filters.ts +38 -0
  1488. package/src/domain/search/search/hybrid.ts +197 -0
  1489. package/src/domain/search/search/keyword.ts +101 -0
  1490. package/src/domain/search/search/prepare.ts +95 -0
  1491. package/src/domain/search/search/semantic.ts +226 -0
  1492. package/src/domain/search/stores/fts5.ts +27 -0
  1493. package/src/domain/search/stores/sqlite-blob.ts +15 -0
  1494. package/src/domain/search/strategies/source.ts +19 -0
  1495. package/src/domain/search/strategies/structured.ts +48 -0
  1496. package/src/domain/search/strategies/text-utils.ts +41 -0
  1497. package/src/domain/wasm-worker-entry.ts +921 -0
  1498. package/src/domain/wasm-worker-pool.ts +375 -0
  1499. package/src/domain/wasm-worker-protocol.ts +98 -0
  1500. package/src/extractors/bash.ts +97 -0
  1501. package/src/extractors/c.ts +231 -0
  1502. package/src/extractors/clojure.ts +273 -0
  1503. package/src/extractors/cpp.ts +383 -0
  1504. package/src/extractors/csharp.ts +448 -0
  1505. package/src/extractors/cuda.ts +433 -0
  1506. package/src/extractors/dart.ts +304 -0
  1507. package/src/extractors/elixir.ts +350 -0
  1508. package/src/extractors/erlang.ts +295 -0
  1509. package/src/extractors/fsharp.ts +357 -0
  1510. package/src/extractors/gleam.ts +247 -0
  1511. package/src/extractors/go.ts +512 -0
  1512. package/src/extractors/groovy.ts +436 -0
  1513. package/src/extractors/haskell.ts +276 -0
  1514. package/src/extractors/hcl.ts +136 -0
  1515. package/src/extractors/helpers.ts +449 -0
  1516. package/src/extractors/index.ts +32 -0
  1517. package/src/extractors/java.ts +439 -0
  1518. package/src/extractors/javascript.ts +3844 -0
  1519. package/src/extractors/julia.ts +432 -0
  1520. package/src/extractors/kotlin.ts +358 -0
  1521. package/src/extractors/lua.ts +169 -0
  1522. package/src/extractors/objc.ts +555 -0
  1523. package/src/extractors/ocaml.ts +337 -0
  1524. package/src/extractors/php.ts +399 -0
  1525. package/src/extractors/python.ts +439 -0
  1526. package/src/extractors/r.ts +275 -0
  1527. package/src/extractors/ruby.ts +292 -0
  1528. package/src/extractors/rust.ts +371 -0
  1529. package/src/extractors/scala.ts +335 -0
  1530. package/src/extractors/solidity.ts +375 -0
  1531. package/src/extractors/swift.ts +337 -0
  1532. package/src/extractors/verilog.ts +383 -0
  1533. package/src/extractors/zig.ts +291 -0
  1534. package/src/features/ast.ts +405 -0
  1535. package/src/features/audit.ts +446 -0
  1536. package/src/features/batch.ts +182 -0
  1537. package/src/features/boundaries.ts +345 -0
  1538. package/src/features/branch-compare.ts +618 -0
  1539. package/src/features/cfg.ts +750 -0
  1540. package/src/features/check.ts +454 -0
  1541. package/src/features/cochange.ts +506 -0
  1542. package/src/features/communities.ts +232 -0
  1543. package/src/features/complexity-query.ts +388 -0
  1544. package/src/features/complexity.ts +753 -0
  1545. package/src/features/dataflow.ts +1654 -0
  1546. package/src/features/export.ts +486 -0
  1547. package/src/features/flow.ts +307 -0
  1548. package/src/features/graph-enrichment.ts +493 -0
  1549. package/src/features/manifesto.ts +508 -0
  1550. package/src/features/owners.ts +360 -0
  1551. package/src/features/sequence.ts +410 -0
  1552. package/src/features/shared/find-nodes.ts +28 -0
  1553. package/src/features/snapshot.ts +221 -0
  1554. package/src/features/structure-query.ts +456 -0
  1555. package/src/features/structure.ts +1100 -0
  1556. package/src/features/triage.ts +199 -0
  1557. package/src/graph/algorithms/bfs.ts +92 -0
  1558. package/src/graph/algorithms/centrality.ts +50 -0
  1559. package/src/graph/algorithms/index.ts +6 -0
  1560. package/src/graph/algorithms/leiden/LICENSE +24 -0
  1561. package/src/graph/algorithms/leiden/adapter.ts +252 -0
  1562. package/src/graph/algorithms/leiden/cpm.ts +77 -0
  1563. package/src/graph/algorithms/leiden/index.ts +224 -0
  1564. package/src/graph/algorithms/leiden/modularity.ts +122 -0
  1565. package/src/graph/algorithms/leiden/optimiser.ts +706 -0
  1566. package/src/graph/algorithms/leiden/partition.ts +577 -0
  1567. package/src/graph/algorithms/leiden/rng.ts +20 -0
  1568. package/src/graph/algorithms/louvain.ts +75 -0
  1569. package/src/graph/algorithms/shortest-path.ts +59 -0
  1570. package/src/graph/algorithms/tarjan.ts +55 -0
  1571. package/src/graph/builders/dependency.ts +148 -0
  1572. package/src/graph/builders/index.ts +3 -0
  1573. package/src/graph/builders/structure.ts +58 -0
  1574. package/src/graph/builders/temporal.ts +51 -0
  1575. package/src/graph/classifiers/index.ts +2 -0
  1576. package/src/graph/classifiers/risk.ts +123 -0
  1577. package/src/graph/classifiers/roles.ts +226 -0
  1578. package/src/graph/index.ts +13 -0
  1579. package/src/graph/model.ts +238 -0
  1580. package/src/index.cjs +16 -0
  1581. package/src/index.ts +72 -0
  1582. package/src/infrastructure/config.ts +954 -0
  1583. package/src/infrastructure/logger.ts +24 -0
  1584. package/src/infrastructure/native.ts +199 -0
  1585. package/src/infrastructure/registry.ts +313 -0
  1586. package/src/infrastructure/result-formatter.ts +2 -0
  1587. package/src/infrastructure/suppress.ts +47 -0
  1588. package/src/infrastructure/test-filter.ts +7 -0
  1589. package/src/infrastructure/update-check.ts +196 -0
  1590. package/src/mcp/index.ts +2 -0
  1591. package/src/mcp/middleware.ts +38 -0
  1592. package/src/mcp/server.ts +259 -0
  1593. package/src/mcp/tool-registry.ts +890 -0
  1594. package/src/mcp/tools/ast-query.ts +25 -0
  1595. package/src/mcp/tools/audit.ts +33 -0
  1596. package/src/mcp/tools/batch-query.ts +22 -0
  1597. package/src/mcp/tools/branch-compare.ts +22 -0
  1598. package/src/mcp/tools/brief.ts +15 -0
  1599. package/src/mcp/tools/cfg.ts +32 -0
  1600. package/src/mcp/tools/check.ts +60 -0
  1601. package/src/mcp/tools/co-changes.ts +29 -0
  1602. package/src/mcp/tools/code-owners.ts +22 -0
  1603. package/src/mcp/tools/communities.ts +25 -0
  1604. package/src/mcp/tools/complexity.ts +30 -0
  1605. package/src/mcp/tools/context.ts +30 -0
  1606. package/src/mcp/tools/dataflow.ts +38 -0
  1607. package/src/mcp/tools/diff-impact.ts +35 -0
  1608. package/src/mcp/tools/execution-flow.ts +38 -0
  1609. package/src/mcp/tools/export-graph.ts +67 -0
  1610. package/src/mcp/tools/file-deps.ts +20 -0
  1611. package/src/mcp/tools/file-exports.ts +22 -0
  1612. package/src/mcp/tools/find-cycles.ts +19 -0
  1613. package/src/mcp/tools/fn-impact.ts +26 -0
  1614. package/src/mcp/tools/impact-analysis.ts +15 -0
  1615. package/src/mcp/tools/implementations.ts +24 -0
  1616. package/src/mcp/tools/index.ts +81 -0
  1617. package/src/mcp/tools/interfaces.ts +24 -0
  1618. package/src/mcp/tools/list-functions.ts +23 -0
  1619. package/src/mcp/tools/list-repos.ts +17 -0
  1620. package/src/mcp/tools/module-map.ts +13 -0
  1621. package/src/mcp/tools/node-roles.ts +23 -0
  1622. package/src/mcp/tools/path.ts +34 -0
  1623. package/src/mcp/tools/query.ts +47 -0
  1624. package/src/mcp/tools/semantic-search.ts +76 -0
  1625. package/src/mcp/tools/sequence.ts +30 -0
  1626. package/src/mcp/tools/structure.ts +25 -0
  1627. package/src/mcp/tools/symbol-children.ts +24 -0
  1628. package/src/mcp/tools/triage.ts +50 -0
  1629. package/src/mcp/tools/where.ts +22 -0
  1630. package/src/mcp/types.ts +21 -0
  1631. package/src/presentation/audit.ts +109 -0
  1632. package/src/presentation/batch.ts +50 -0
  1633. package/src/presentation/branch-compare.ts +148 -0
  1634. package/src/presentation/brief.ts +63 -0
  1635. package/src/presentation/cfg.ts +103 -0
  1636. package/src/presentation/check.ts +138 -0
  1637. package/src/presentation/cochange.ts +57 -0
  1638. package/src/presentation/colors.ts +51 -0
  1639. package/src/presentation/communities.ts +114 -0
  1640. package/src/presentation/complexity.ts +127 -0
  1641. package/src/presentation/dataflow.ts +179 -0
  1642. package/src/presentation/diff-impact-mermaid.ts +169 -0
  1643. package/src/presentation/export.ts +509 -0
  1644. package/src/presentation/flow.ts +147 -0
  1645. package/src/presentation/manifesto.ts +92 -0
  1646. package/src/presentation/owners.ts +89 -0
  1647. package/src/presentation/queries-cli/exports.ts +152 -0
  1648. package/src/presentation/queries-cli/impact.ts +340 -0
  1649. package/src/presentation/queries-cli/index.ts +13 -0
  1650. package/src/presentation/queries-cli/inspect.ts +594 -0
  1651. package/src/presentation/queries-cli/overview.ts +375 -0
  1652. package/src/presentation/queries-cli/path.ts +187 -0
  1653. package/src/presentation/queries-cli.ts +30 -0
  1654. package/src/presentation/query.ts +17 -0
  1655. package/src/presentation/result-formatter.ts +161 -0
  1656. package/src/presentation/sequence-renderer.ts +46 -0
  1657. package/src/presentation/sequence.ts +43 -0
  1658. package/src/presentation/structure.ts +109 -0
  1659. package/src/presentation/table.ts +45 -0
  1660. package/src/presentation/triage.ts +84 -0
  1661. package/src/presentation/viewer.ts +715 -0
  1662. package/src/shared/constants.ts +70 -0
  1663. package/src/shared/errors.ts +85 -0
  1664. package/src/shared/file-utils.ts +233 -0
  1665. package/src/shared/generators.ts +176 -0
  1666. package/src/shared/globs.ts +121 -0
  1667. package/src/shared/hierarchy.ts +81 -0
  1668. package/src/shared/kinds.ts +85 -0
  1669. package/src/shared/normalize.ts +106 -0
  1670. package/src/shared/paginate.ts +93 -0
  1671. package/src/shared/version.ts +10 -0
  1672. package/src/types.ts +2871 -0
@@ -0,0 +1,2241 @@
1
+ /**
2
+ * Native build orchestrator stage — runs the full Rust pipeline when available,
3
+ * with WASM fallback for files the native engine drops.
4
+ *
5
+ * Extracted from `pipeline.ts` to break the name-collision cycle between
6
+ * `buildGraph()` (this module's caller) and `ctx.nativeDb.buildGraph()` (the
7
+ * Rust orchestrator entry point invoked here). Codegraph's name-based call
8
+ * resolver previously conflated the two and reported a false-positive
9
+ * function-level cycle (`buildGraph ↔ tryNativeOrchestrator`).
10
+ *
11
+ * The orchestrator-selection strategy lives here so `pipeline.ts` stays a thin
12
+ * top-level controller: detect changes, try native, fall back to JS stages.
13
+ */
14
+ import { execFileSync } from 'node:child_process';
15
+ import path from 'node:path';
16
+ import { performance } from 'node:perf_hooks';
17
+ import {
18
+ acquireAdvisoryLock,
19
+ closeDbPair,
20
+ openDb,
21
+ purgeFilesData,
22
+ releaseAdvisoryLock,
23
+ setBuildMeta,
24
+ } from '../../../../db/index.js';
25
+ import { debug, info, warn } from '../../../../infrastructure/logger.js';
26
+ import { loadNative } from '../../../../infrastructure/native.js';
27
+ import { semverCompare } from '../../../../infrastructure/update-check.js';
28
+ import { normalizePath, TS_NATIVE_CONFIDENCE_FLOOR } from '../../../../shared/constants.js';
29
+ import { toErrorMessage } from '../../../../shared/errors.js';
30
+ import { CODEGRAPH_VERSION } from '../../../../shared/version.js';
31
+ import type {
32
+ BetterSqlite3Database,
33
+ BuildResult,
34
+ DataflowResult,
35
+ Definition,
36
+ ExtractorOutput,
37
+ SqliteStatement,
38
+ } from '../../../../types.js';
39
+ import {
40
+ classifyNativeDrops,
41
+ formatDropExtensionSummary,
42
+ getInstalledWasmExtensions,
43
+ NATIVE_SUPPORTED_EXTENSIONS,
44
+ parseFilesWasmForBackfill,
45
+ patchDataflowResult,
46
+ } from '../../../parser.js';
47
+ import { computeConfidence } from '../../resolve.js';
48
+ import type { CallNodeLookup } from '../call-resolver.js';
49
+ import type { ChaContext } from '../cha.js';
50
+ import { resolveThisDispatch } from '../cha.js';
51
+ import type { PipelineContext } from '../context.js';
52
+ import {
53
+ batchInsertEdges,
54
+ batchInsertNodes,
55
+ CHA_DISPATCH_PENALTY,
56
+ CHA_TYPED_DISPATCH_CONFIDENCE,
57
+ collectFiles as collectFilesUtil,
58
+ fileHash,
59
+ fileStat,
60
+ readFileSafe,
61
+ } from '../helpers.js';
62
+ import { NativeDbProxy } from '../native-db-proxy.js';
63
+ import { closeNativeDb } from './native-db-lifecycle.js';
64
+
65
+ // ── Native orchestrator types ──────────────────────────────────────────
66
+
67
+ interface NativeOrchestratorResult {
68
+ phases: Record<string, number>;
69
+ earlyExit?: boolean;
70
+ nodeCount?: number;
71
+ edgeCount?: number;
72
+ fileCount?: number;
73
+ changedFiles?: string[];
74
+ changedCount?: number;
75
+ removedCount?: number;
76
+ isFullBuild?: boolean;
77
+ /** Whether the Rust pipeline handled the structure phase (small-incremental fast path). */
78
+ structureHandled?: boolean;
79
+ /** Whether the Rust pipeline wrote AST/complexity/CFG/dataflow to DB. */
80
+ analysisComplete?: boolean;
81
+ }
82
+
83
+ /** Files the native orchestrator silently dropped — the working set for backfill. */
84
+ interface DroppedLanguageGap {
85
+ /** Relative paths (normalized) of files missing from `nodes` or `file_hashes`. */
86
+ missingRel: string[];
87
+ /** Absolute paths, aligned by index with `missingRel`. */
88
+ missingAbs: string[];
89
+ /**
90
+ * Relative paths of WASM-only files present in DB but absent from disk (#1073).
91
+ * Rust's `detect_removed_files` filter (#1070) skips these, so the JS-side
92
+ * backfill must purge them. Always disjoint from `missingRel`.
93
+ */
94
+ staleRel: string[];
95
+ }
96
+
97
+ /**
98
+ * Inputs to {@link computeWasmOnlyStaleFiles}. Sets are passed in so the helper
99
+ * is pure and unit-testable independently of `getInstalledWasmExtensions` and
100
+ * the `NATIVE_SUPPORTED_EXTENSIONS` global state.
101
+ */
102
+ export interface WasmOnlyStaleFilesInput {
103
+ /** Distinct `file` values from the `nodes` table. */
104
+ existingNodes: ReadonlySet<string>;
105
+ /** Distinct `file` values from the `file_hashes` table. */
106
+ existingHashes: ReadonlySet<string>;
107
+ /** Relative paths currently on disk (from `collectFilesUtil`). */
108
+ expected: ReadonlySet<string>;
109
+ /** Lowercased extensions whose WASM grammar is installed. */
110
+ installedExts: ReadonlySet<string>;
111
+ /** Extensions covered by the Rust addon — Rust owns deletion for these. */
112
+ nativeSupported: ReadonlySet<string>;
113
+ }
114
+
115
+ // ── Native orchestrator helpers ───────────────────────────────────────
116
+
117
+ /** Determine whether the native orchestrator should be skipped. Returns a reason string, or null if it should run. */
118
+ function shouldSkipNativeOrchestrator(ctx: PipelineContext): string | null {
119
+ if (ctx.forceFullRebuild) return 'forceFullRebuild';
120
+ // v3.9.0 addon had buggy incremental purge (wrong SQL on analysis tables,
121
+ // scoped removal over-detection). Fixed in v3.9.1 by PR #865. Gate on
122
+ // < 3.9.1 so v3.9.1+ uses the fast Rust orchestrator path.
123
+ const orchestratorBuggy = !!ctx.engineVersion && semverCompare(ctx.engineVersion, '3.9.1') < 0;
124
+ if (orchestratorBuggy) return `buggy addon ${ctx.engineVersion}`;
125
+ if (ctx.engineName !== 'native') return `engine=${ctx.engineName}`;
126
+ return null;
127
+ }
128
+
129
+ /** Checkpoint WAL through rusqlite, close nativeDb, and reopen better-sqlite3.
130
+ * Returns false if the DB reopen fails (caller should return partial result). */
131
+ function handoffWalAfterNativeBuild(ctx: PipelineContext): boolean {
132
+ closeNativeDb(ctx, 'post-native-build');
133
+ try {
134
+ ctx.db.close();
135
+ } catch (e) {
136
+ debug(`handoffWal JS db close failed: ${toErrorMessage(e)}`);
137
+ }
138
+ try {
139
+ ctx.db = openDb(ctx.dbPath);
140
+ return true;
141
+ } catch (reopenErr) {
142
+ warn(`Failed to reopen DB after native build: ${(reopenErr as Error).message}`);
143
+ return false;
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Reconstruct fileSymbols from the DB after a native orchestrator build.
149
+ * When `scopeFiles` is provided, only loads those files (for analysis-only).
150
+ * When omitted, loads all files (needed for structure rebuilds).
151
+ */
152
+ function reconstructFileSymbolsFromDb(
153
+ ctx: PipelineContext,
154
+ scopeFiles?: string[],
155
+ ): Map<string, ExtractorOutput> {
156
+ let query =
157
+ 'SELECT file, name, kind, line, end_line as endLine FROM nodes WHERE file IS NOT NULL';
158
+ const params: string[] = [];
159
+ if (scopeFiles && scopeFiles.length > 0) {
160
+ const placeholders = scopeFiles.map(() => '?').join(',');
161
+ query += ` AND file IN (${placeholders})`;
162
+ params.push(...scopeFiles);
163
+ }
164
+ query += ' ORDER BY file, line';
165
+
166
+ const rows = ctx.db.prepare(query).all(...params) as {
167
+ file: string;
168
+ name: string;
169
+ kind: string;
170
+ line: number;
171
+ endLine: number | null;
172
+ }[];
173
+
174
+ const fileSymbols = new Map<string, ExtractorOutput>();
175
+ for (const row of rows) {
176
+ let entry = fileSymbols.get(row.file);
177
+ if (!entry) {
178
+ entry = {
179
+ definitions: [],
180
+ calls: [],
181
+ imports: [],
182
+ classes: [],
183
+ exports: [],
184
+ typeMap: new Map(),
185
+ };
186
+ fileSymbols.set(row.file, entry);
187
+ }
188
+ entry.definitions.push({
189
+ name: row.name,
190
+ kind: row.kind as Definition['kind'],
191
+ line: row.line,
192
+ endLine: row.endLine ?? undefined,
193
+ });
194
+ }
195
+
196
+ // Populate import/export counts from DB edges so buildStructure
197
+ // computes correct import_count/export_count in node_metrics.
198
+ // The extractor arrays aren't persisted to the DB, so we derive
199
+ // counts from edge data instead (#804).
200
+ const importCountRows = ctx.db
201
+ .prepare(
202
+ `SELECT n.file, COUNT(*) AS cnt
203
+ FROM edges e JOIN nodes n ON e.source_id = n.id
204
+ WHERE e.kind IN ('imports', 'imports-type', 'dynamic-imports')
205
+ AND n.file IS NOT NULL
206
+ GROUP BY n.file`,
207
+ )
208
+ .all() as { file: string; cnt: number }[];
209
+ for (const row of importCountRows) {
210
+ const entry = fileSymbols.get(row.file);
211
+ if (entry) entry.imports = new Array(row.cnt) as ExtractorOutput['imports'];
212
+ }
213
+
214
+ const exportCountRows = ctx.db
215
+ .prepare(
216
+ `SELECT n_tgt.file, COUNT(DISTINCT n_tgt.id) AS cnt
217
+ FROM edges e
218
+ JOIN nodes n_tgt ON e.target_id = n_tgt.id
219
+ JOIN nodes n_src ON e.source_id = n_src.id
220
+ WHERE e.kind IN ('imports', 'imports-type', 'reexports')
221
+ AND n_tgt.file IS NOT NULL
222
+ AND n_src.file != n_tgt.file
223
+ GROUP BY n_tgt.file`,
224
+ )
225
+ .all() as { file: string; cnt: number }[];
226
+ for (const row of exportCountRows) {
227
+ const entry = fileSymbols.get(row.file);
228
+ if (entry) entry.exports = new Array(row.cnt) as ExtractorOutput['exports'];
229
+ }
230
+
231
+ return fileSymbols;
232
+ }
233
+
234
+ /**
235
+ * Run JS buildStructure() after native orchestrator to fill directory nodes + contains edges.
236
+ * For full builds, passes changedFiles=null (full rebuild).
237
+ * For incremental builds, passes the changed file list to scope the update.
238
+ */
239
+ async function runPostNativeStructure(
240
+ ctx: PipelineContext,
241
+ allFileSymbols: Map<string, ExtractorOutput>,
242
+ isFullBuild: boolean,
243
+ changedFiles: string[] | undefined,
244
+ ): Promise<number> {
245
+ const structureStart = performance.now();
246
+ try {
247
+ const directories = new Set<string>();
248
+ for (const relPath of allFileSymbols.keys()) {
249
+ const parts = relPath.split('/');
250
+ for (let i = 1; i < parts.length; i++) {
251
+ directories.add(parts.slice(0, i).join('/'));
252
+ }
253
+ }
254
+
255
+ const lineCountMap = new Map<string, number>();
256
+ const cachedLineCounts = ctx.db
257
+ .prepare(
258
+ `SELECT n.name AS file, m.line_count
259
+ FROM node_metrics m JOIN nodes n ON m.node_id = n.id
260
+ WHERE n.kind = 'file'`,
261
+ )
262
+ .all() as Array<{ file: string; line_count: number }>;
263
+ for (const row of cachedLineCounts) {
264
+ lineCountMap.set(row.file, row.line_count);
265
+ }
266
+
267
+ // Full builds need null (rebuild everything). Incremental builds pass the
268
+ // changed file list so buildStructure only updates those files' metrics
269
+ // and contains edges — matching the JS pipeline's medium-incremental path.
270
+ const changedFilePaths = isFullBuild || !changedFiles?.length ? null : changedFiles;
271
+ const { buildStructure: buildStructureFn } = (await import(
272
+ '../../../../features/structure.js'
273
+ )) as {
274
+ buildStructure: (
275
+ db: typeof ctx.db,
276
+ fileSymbols: Map<string, ExtractorOutput>,
277
+ rootDir: string,
278
+ lineCountMap: Map<string, number>,
279
+ directories: Set<string>,
280
+ changedFiles: string[] | null,
281
+ ) => void;
282
+ };
283
+ buildStructureFn(
284
+ ctx.db,
285
+ allFileSymbols,
286
+ ctx.rootDir,
287
+ lineCountMap,
288
+ directories,
289
+ changedFilePaths,
290
+ );
291
+ debug(
292
+ `Structure phase completed after native orchestrator${changedFilePaths ? ` (${changedFilePaths.length} files)` : ' (full)'}`,
293
+ );
294
+ } catch (err) {
295
+ warn(`Structure phase failed after native build: ${toErrorMessage(err)}`);
296
+ }
297
+ return performance.now() - structureStart;
298
+ }
299
+
300
+ /**
301
+ * P6: Build dataflow_vertices and inter-procedural edges after the Rust
302
+ * orchestrator completes.
303
+ *
304
+ * The Rust pipeline writes flows_to/returns/mutates edges directly to the DB
305
+ * but never writes to dataflow_vertices or dataflow_summary. This pass re-runs
306
+ * the Rust dataflow visitor (via extractDataflowAnalysis — fast, no re-parse)
307
+ * to get the DataflowResult and calls buildDataflowVerticesFromMap.
308
+ *
309
+ * Languages for which Rust has no dataflow rules return null from
310
+ * extractDataflowAnalysis and are silently skipped here. A follow-up issue
311
+ * (#1614 adjacent) will add WASM fallback for those languages.
312
+ */
313
+ async function runDataflowVertexPass(
314
+ ctx: PipelineContext,
315
+ changedFiles: string[] | undefined,
316
+ ): Promise<void> {
317
+ if (ctx.opts.dataflow === false) return;
318
+
319
+ const native = loadNative();
320
+ if (!native?.extractDataflowAnalysis) return;
321
+
322
+ // Determine which files to process: changed files for incremental, all for full builds.
323
+ let filesToProcess: string[];
324
+ if (changedFiles && changedFiles.length > 0) {
325
+ filesToProcess = changedFiles;
326
+ } else {
327
+ // Full build: scope to files that need vertex extraction rather than scanning every
328
+ // file in the project. Two categories:
329
+ // (a) Non-native language files — NATIVE_SUPPORTED_EXTENSIONS doesn't cover them,
330
+ // so extractDataflowAnalysis returns null; the wasmStubs path calls buildDataflowEdges
331
+ // which writes both edges AND vertices for those files.
332
+ // (b) Native-language files with dataflow edges already written by the Rust orchestrator
333
+ // (flows_to/returns/mutates) — those need vertex rows to connect them.
334
+ //
335
+ // Skipping native-language files with no dataflow edges is safe: extractDataflowAnalysis
336
+ // would return argFlows=[], assignments=[], mutations=[] for them, producing zero vertices
337
+ // and zero inter-procedural edges. Excluding them avoids O(n_total_files) re-analysis on
338
+ // every full build (codegraph itself: ~2000 files, ~50-80% with no dataflow edges).
339
+ const filesWithDataflow = new Set(
340
+ (
341
+ ctx.db
342
+ .prepare(
343
+ `SELECT DISTINCT n.file
344
+ FROM dataflow d
345
+ JOIN nodes n ON n.id = d.source_id
346
+ WHERE n.file IS NOT NULL`,
347
+ )
348
+ .all() as { file: string }[]
349
+ ).map((r) => r.file),
350
+ );
351
+
352
+ filesToProcess = (
353
+ ctx.db
354
+ .prepare(`SELECT DISTINCT file FROM nodes WHERE file IS NOT NULL AND kind != 'directory'`)
355
+ .all() as { file: string }[]
356
+ )
357
+ .map((r) => r.file)
358
+ .filter((f) => {
359
+ const ext = path.extname(f).toLowerCase();
360
+ // Non-native files: always include (WASM handles them via wasmStubs path).
361
+ if (!NATIVE_SUPPORTED_EXTENSIONS.has(ext)) return true;
362
+ // Native files: only include when Rust wrote dataflow edges for them.
363
+ return filesWithDataflow.has(f);
364
+ });
365
+ }
366
+
367
+ // Split files into two buckets:
368
+ // nativeDataflow — Rust extracted data (vertex-only pass; edges already in DB)
369
+ // wasmStubs — Rust returned null (WASM will handle edges + vertices)
370
+ const nativeDataflow = new Map<string, DataflowResult>();
371
+ const wasmStubs = new Map<string, { definitions: []; _langId: null; _tree: null }>();
372
+
373
+ for (const relPath of filesToProcess) {
374
+ const absPath = path.join(ctx.rootDir, relPath);
375
+ const source = readFileSafe(absPath);
376
+ if (!source) continue;
377
+ let result: DataflowResult | null = null;
378
+ try {
379
+ result = native.extractDataflowAnalysis(source, absPath);
380
+ } catch {
381
+ // Language-specific parse failure — fall through to WASM.
382
+ }
383
+ if (result) {
384
+ // Normalise the native DataflowResult: Rust emits `bindingType: string | null`
385
+ // (flat) while the TS dataflow layer expects `binding: { type, index? }` (object).
386
+ // patchNativeResult handles this via patchDataflow for the full parse path;
387
+ // extractDataflowAnalysis is a vertex-only fast path that bypasses patchNativeResult,
388
+ // so we apply the same normalisation here.
389
+ patchDataflowResult(result);
390
+ nativeDataflow.set(relPath, result);
391
+ } else {
392
+ // Rust has no dataflow rules for this language; WASM fallback will handle
393
+ // both edge insertion and vertex extraction. Since Rust inserted 0 dataflow
394
+ // edges for these files, there is no risk of duplicates.
395
+ wasmStubs.set(relPath, { definitions: [], _langId: null, _tree: null });
396
+ }
397
+ }
398
+
399
+ const { buildExtToLangMap } = (await import('../../../../ast-analysis/shared.js')) as {
400
+ buildExtToLangMap: () => Map<string, string>;
401
+ };
402
+
403
+ const {
404
+ buildDataflowVerticesFromMap,
405
+ buildDataflowEdges,
406
+ collectCallerStitchCandidates,
407
+ collectFuncIdsForFiles,
408
+ } = (await import('../../../../features/dataflow.js')) as {
409
+ buildDataflowVerticesFromMap: (
410
+ db: BetterSqlite3Database,
411
+ dataflowMap: Map<string, DataflowResult>,
412
+ extraCandidates?: Array<{
413
+ callerFuncId: number;
414
+ calleeFuncId: number;
415
+ argIndex: number;
416
+ bindingType: string;
417
+ bindingIndex: number;
418
+ argName: string;
419
+ expression: string | null;
420
+ line: number;
421
+ confidence: number;
422
+ }>,
423
+ extraCaptures?: Array<{ callerFuncId: number; calleeFuncId: number; varName: string }>,
424
+ ) => number;
425
+ buildDataflowEdges: (
426
+ db: BetterSqlite3Database,
427
+ fileSymbols: Map<string, unknown>,
428
+ rootDir: string,
429
+ engineOpts?: unknown,
430
+ ) => Promise<void>;
431
+ collectCallerStitchCandidates: (
432
+ db: BetterSqlite3Database,
433
+ changedFuncIds: number[],
434
+ changedRelPaths: Set<string>,
435
+ rootDir: string,
436
+ extToLang: Map<string, string>,
437
+ parsers: unknown,
438
+ getParserFn: unknown,
439
+ ) => Promise<{
440
+ candidates: Array<{
441
+ callerFuncId: number;
442
+ calleeFuncId: number;
443
+ argIndex: number;
444
+ bindingType: string;
445
+ bindingIndex: number;
446
+ argName: string;
447
+ expression: string | null;
448
+ line: number;
449
+ confidence: number;
450
+ }>;
451
+ captures: Array<{ callerFuncId: number; calleeFuncId: number; varName: string }>;
452
+ }>;
453
+ collectFuncIdsForFiles: (db: BetterSqlite3Database, relPaths: Iterable<string>) => number[];
454
+ };
455
+
456
+ // Rust-supported languages: build vertices only (edges already written by Rust orchestrator).
457
+ if (nativeDataflow.size > 0) {
458
+ // P4: On incremental builds, unchanged caller files' arg_in edges were deleted when
459
+ // the changed files' param vertices were purged and recreated. Re-collect stitch
460
+ // candidates from those caller files so buildInterproceduralStitch can reconnect them.
461
+ // Skip on full builds (changedFiles absent/empty) — nativeDataflow covers all files.
462
+ let p4Candidates: Array<{
463
+ callerFuncId: number;
464
+ calleeFuncId: number;
465
+ argIndex: number;
466
+ bindingType: string;
467
+ bindingIndex: number;
468
+ argName: string;
469
+ expression: string | null;
470
+ line: number;
471
+ confidence: number;
472
+ }> = [];
473
+ let p4Captures: Array<{ callerFuncId: number; calleeFuncId: number; varName: string }> = [];
474
+
475
+ if (changedFiles && changedFiles.length > 0) {
476
+ const changedSet = new Set(changedFiles);
477
+ const totalFilesInDb = (
478
+ ctx.db.prepare(`SELECT COUNT(DISTINCT file) AS n FROM nodes`).get() as { n: number }
479
+ ).n;
480
+ // Only run P4 when this is a real incremental build (not all files changed).
481
+ if (nativeDataflow.size < totalFilesInDb) {
482
+ const changedFuncIds = collectFuncIdsForFiles(ctx.db, changedSet);
483
+ if (changedFuncIds.length > 0) {
484
+ const extra = await collectCallerStitchCandidates(
485
+ ctx.db,
486
+ changedFuncIds,
487
+ changedSet,
488
+ ctx.rootDir,
489
+ buildExtToLangMap(),
490
+ null, // parsers — lazily loaded inside collectCallerStitchCandidates
491
+ null, // getParserFn — lazily loaded inside collectCallerStitchCandidates
492
+ );
493
+ p4Candidates = extra.candidates as typeof p4Candidates;
494
+ p4Captures = extra.captures;
495
+ }
496
+ }
497
+ }
498
+
499
+ const interCount = buildDataflowVerticesFromMap(
500
+ ctx.db,
501
+ nativeDataflow,
502
+ p4Candidates.length > 0 ? p4Candidates : undefined,
503
+ p4Captures.length > 0 ? p4Captures : undefined,
504
+ );
505
+ if (interCount > 0) {
506
+ info(
507
+ `Dataflow (native orchestrator): ${interCount} inter-procedural edges inserted${p4Candidates.length > 0 ? ` (P4: ${p4Candidates.length} re-stitch candidate(s) from unchanged callers)` : ''}`,
508
+ );
509
+ }
510
+ }
511
+
512
+ // Rust-unsupported languages: run the full WASM extraction (edges + vertices).
513
+ // wasmStubs entries have no `.dataflow` property, so the native bulk-insert
514
+ // fast path in buildDataflowEdges is always skipped for them — WASM runs
515
+ // both edge insertion and vertex extraction end-to-end.
516
+ if (wasmStubs.size > 0) {
517
+ await buildDataflowEdges(ctx.db, wasmStubs, ctx.rootDir);
518
+ }
519
+ }
520
+
521
+ /**
522
+ * JS fallback for AST/complexity/CFG/dataflow analysis after native orchestrator.
523
+ * Used when the Rust addon doesn't include analysis persistence (older addon
524
+ * version) or when analysis failed on the Rust side.
525
+ */
526
+ async function runPostNativeAnalysis(
527
+ ctx: PipelineContext,
528
+ allFileSymbols: Map<string, ExtractorOutput>,
529
+ changedFiles: string[] | undefined,
530
+ ): Promise<{ astMs: number; complexityMs: number; cfgMs: number; dataflowMs: number }> {
531
+ const timing = { astMs: 0, complexityMs: 0, cfgMs: 0, dataflowMs: 0 };
532
+
533
+ // Scope analysis fileSymbols to changed files only
534
+ let analysisFileSymbols: Map<string, ExtractorOutput>;
535
+ if (changedFiles && changedFiles.length > 0) {
536
+ analysisFileSymbols = new Map();
537
+ for (const f of changedFiles) {
538
+ const entry = allFileSymbols.get(f);
539
+ if (entry) analysisFileSymbols.set(f, entry);
540
+ }
541
+ } else {
542
+ analysisFileSymbols = allFileSymbols;
543
+ }
544
+
545
+ // Reopen nativeDb for analysis features (suspend/resume WAL pattern).
546
+ const native = loadNative();
547
+ if (native?.NativeDatabase) {
548
+ try {
549
+ ctx.nativeDb = native.NativeDatabase.openReadWrite(ctx.dbPath);
550
+ if (ctx.engineOpts) ctx.engineOpts.nativeDb = ctx.nativeDb;
551
+ } catch {
552
+ ctx.nativeDb = undefined;
553
+ if (ctx.engineOpts) ctx.engineOpts.nativeDb = undefined;
554
+ }
555
+ }
556
+
557
+ // Flush JS WAL pages once so Rust can see them, then no-op callbacks.
558
+ // Previously each feature called wal_checkpoint(TRUNCATE) individually
559
+ // (~68ms each × 3-4 features). One FULL checkpoint suffices.
560
+ if (ctx.nativeDb && ctx.engineOpts) {
561
+ ctx.db.pragma('wal_checkpoint(FULL)');
562
+ ctx.engineOpts.suspendJsDb = () => {};
563
+ ctx.engineOpts.resumeJsDb = () => {};
564
+ }
565
+
566
+ try {
567
+ const { runAnalyses: runAnalysesFn } = (await import('../../../../ast-analysis/engine.js')) as {
568
+ runAnalyses: (
569
+ db: BetterSqlite3Database,
570
+ fileSymbols: Map<string, ExtractorOutput>,
571
+ rootDir: string,
572
+ opts: Record<string, unknown>,
573
+ engineOpts?: Record<string, unknown>,
574
+ ) => Promise<{ astMs?: number; complexityMs?: number; cfgMs?: number; dataflowMs?: number }>;
575
+ };
576
+ const result = await runAnalysesFn(
577
+ ctx.db,
578
+ analysisFileSymbols,
579
+ ctx.rootDir,
580
+ ctx.opts as Record<string, unknown>,
581
+ ctx.engineOpts as unknown as Record<string, unknown> | undefined,
582
+ );
583
+ timing.astMs = result.astMs ?? 0;
584
+ timing.complexityMs = result.complexityMs ?? 0;
585
+ timing.cfgMs = result.cfgMs ?? 0;
586
+ timing.dataflowMs = result.dataflowMs ?? 0;
587
+ } catch (err) {
588
+ warn(`Analysis phases failed after native build: ${toErrorMessage(err)}`);
589
+ }
590
+
591
+ // Close nativeDb after analyses — TRUNCATE checkpoint flushes all Rust
592
+ // WAL writes so JS and external readers can see them. Runs once after
593
+ // all analysis features complete (not per-feature).
594
+ if (ctx.nativeDb) {
595
+ try {
596
+ ctx.nativeDb.exec('PRAGMA wal_checkpoint(TRUNCATE)');
597
+ } catch {
598
+ /* ignore checkpoint errors */
599
+ }
600
+ try {
601
+ ctx.nativeDb.close();
602
+ } catch {
603
+ /* ignore close errors */
604
+ }
605
+ ctx.nativeDb = undefined;
606
+ if (ctx.engineOpts) {
607
+ ctx.engineOpts.nativeDb = undefined;
608
+ ctx.engineOpts.suspendJsDb = undefined;
609
+ ctx.engineOpts.resumeJsDb = undefined;
610
+ }
611
+ }
612
+
613
+ return timing;
614
+ }
615
+
616
+ // ── CHA post-pass helpers ────────────────────────────────────────────────────
617
+
618
+ /** Build implementors map: parent/interface name → [child/implementing class names]. */
619
+ function buildChaImplementorsMap(db: BetterSqlite3Database): Map<string, string[]> {
620
+ const hierarchyRows = db
621
+ .prepare(`
622
+ SELECT src.name AS child_name, tgt.name AS parent_name
623
+ FROM edges e
624
+ JOIN nodes src ON e.source_id = src.id
625
+ JOIN nodes tgt ON e.target_id = tgt.id
626
+ WHERE e.kind IN ('extends', 'implements')
627
+ `)
628
+ .all() as Array<{ child_name: string; parent_name: string }>;
629
+
630
+ const implementors = new Map<string, string[]>();
631
+ for (const row of hierarchyRows) {
632
+ let list = implementors.get(row.parent_name);
633
+ if (!list) {
634
+ list = [];
635
+ implementors.set(row.parent_name, list);
636
+ }
637
+ if (!list.includes(row.child_name)) list.push(row.child_name);
638
+ }
639
+ return implementors;
640
+ }
641
+
642
+ /**
643
+ * Build RTA set: class names actually instantiated via `new X()`.
644
+ * Primary query targets `class`-kind nodes (the canonical schema).
645
+ * Fallback also matches `constructor`/`function`-kind nodes because some native
646
+ * engine versions record constructor calls against those kinds instead of `class`.
647
+ * Returns `{ instantiated, noRtaEvidence }` where `noRtaEvidence` means no
648
+ * constructor-call evidence exists — skip RTA filtering so interface dispatch
649
+ * still produces edges.
650
+ */
651
+ function buildChaRtaSet(db: BetterSqlite3Database): {
652
+ instantiated: Set<string>;
653
+ noRtaEvidence: boolean;
654
+ } {
655
+ let rtaRows = db
656
+ .prepare(`
657
+ SELECT DISTINCT tgt.name
658
+ FROM edges e
659
+ JOIN nodes tgt ON e.target_id = tgt.id
660
+ WHERE e.kind = 'calls' AND tgt.kind = 'class'
661
+ `)
662
+ .all() as Array<{ name: string }>;
663
+ if (rtaRows.length === 0) {
664
+ // Fallback: try constructor/function-kind nodes for older native engine schemas
665
+ rtaRows = db
666
+ .prepare(`
667
+ SELECT DISTINCT tgt.name
668
+ FROM edges e
669
+ JOIN nodes tgt ON e.target_id = tgt.id
670
+ WHERE e.kind = 'calls' AND tgt.kind IN ('constructor', 'function')
671
+ AND INSTR(tgt.name, '.') = 0
672
+ `)
673
+ .all() as Array<{ name: string }>;
674
+ }
675
+ const instantiated = new Set(rtaRows.map((r) => r.name));
676
+ const noRtaEvidence = instantiated.size === 0;
677
+ if (noRtaEvidence) {
678
+ debug('runPostNativeCha: no constructor-call evidence found — proceeding without RTA filter');
679
+ }
680
+ return { instantiated, noRtaEvidence };
681
+ }
682
+
683
+ /**
684
+ * Determine CHA candidate scope for incremental builds.
685
+ *
686
+ * Gate A: did a changed file add/change a class hierarchy node?
687
+ * A new `extends`/`implements` edge means a previously-untracked implementor
688
+ * is now in the hierarchy — unchanged call sites in OTHER files may gain new
689
+ * valid expansions, so the full scan is required.
690
+ * Note: *removed* class nodes are safe — Rust's `purge_changed_files` runs
691
+ * before this post-pass and deletes stale nodes and their hierarchy edges, so
692
+ * Gate A queries the post-purge DB. A deleted class returns no row here, which
693
+ * is correct: its stale CHA edges were already cleaned up by the Rust purge.
694
+ *
695
+ * Gate B: did a changed file add new RTA evidence (`new ConcreteX()`)?
696
+ * A new `calls` edge to a class/constructor/function-kind target means the
697
+ * instantiated set grew — previously RTA-filtered expansions in unchanged
698
+ * caller files become admissible, so the full scan is required.
699
+ * (`constructor`/`function` cover the older native engine fallback schema.)
700
+ *
701
+ * Returns `true` when the scan should be scoped to changed-file sources only.
702
+ * Returns `false` (full scan) when changedFiles is null, empty, or either gate fires.
703
+ */
704
+ function computeChaScope(db: BetterSqlite3Database, changedFiles: string[] | null): boolean {
705
+ if (changedFiles === null || changedFiles.length === 0) return false;
706
+
707
+ const CHUNK_SIZE = 500;
708
+ let gateAFired = false;
709
+ for (let i = 0; i < changedFiles.length && !gateAFired; i += CHUNK_SIZE) {
710
+ const chunk = changedFiles.slice(i, i + CHUNK_SIZE);
711
+ const ph = chunk.map(() => '?').join(',');
712
+ const row = db
713
+ .prepare(
714
+ `SELECT 1 FROM nodes
715
+ WHERE file IN (${ph})
716
+ AND kind IN ('class', 'interface', 'trait', 'struct', 'record')
717
+ LIMIT 1`,
718
+ )
719
+ .get(...chunk);
720
+ if (row) gateAFired = true;
721
+ }
722
+
723
+ let gateBFired = false;
724
+ if (!gateAFired) {
725
+ for (let i = 0; i < changedFiles.length && !gateBFired; i += CHUNK_SIZE) {
726
+ const chunk = changedFiles.slice(i, i + CHUNK_SIZE);
727
+ const ph = chunk.map(() => '?').join(',');
728
+ const row = db
729
+ .prepare(
730
+ `SELECT 1 FROM edges e
731
+ JOIN nodes src ON e.source_id = src.id
732
+ JOIN nodes tgt ON e.target_id = tgt.id
733
+ WHERE e.kind = 'calls'
734
+ AND tgt.kind IN ('class', 'interface', 'trait', 'struct', 'record', 'constructor', 'function')
735
+ AND src.file IN (${ph})
736
+ LIMIT 1`,
737
+ )
738
+ .get(...chunk);
739
+ if (row) gateBFired = true;
740
+ }
741
+ }
742
+
743
+ if (!gateAFired && !gateBFired) {
744
+ debug(
745
+ `runPostNativeCha: neither gate fired — scoping candidate scan to ${changedFiles.length} changed file(s)`,
746
+ );
747
+ return true;
748
+ }
749
+ debug(
750
+ `runPostNativeCha: ${gateAFired ? 'Gate A (hierarchy)' : 'Gate B (RTA)'} fired — running full scan`,
751
+ );
752
+ return false;
753
+ }
754
+
755
+ type ChaCallRow = {
756
+ source_id: number;
757
+ caller_name: string;
758
+ method_name: string;
759
+ caller_file: string | null;
760
+ };
761
+
762
+ /**
763
+ * Fetch call→method rows that are candidates for CHA expansion.
764
+ * When `scopeToChangedFiles` is true, restricts to source nodes in `changedFiles`.
765
+ */
766
+ function fetchChaCallToMethods(
767
+ db: BetterSqlite3Database,
768
+ changedFiles: string[] | null,
769
+ scopeToChangedFiles: boolean,
770
+ ): ChaCallRow[] {
771
+ if (scopeToChangedFiles && changedFiles && changedFiles.length > 0) {
772
+ const CHUNK_SIZE = 500;
773
+ const rows: ChaCallRow[] = [];
774
+ for (let i = 0; i < changedFiles.length; i += CHUNK_SIZE) {
775
+ const chunk = changedFiles.slice(i, i + CHUNK_SIZE);
776
+ const ph = chunk.map(() => '?').join(',');
777
+ const chunkRows = db
778
+ .prepare(
779
+ `SELECT e.source_id, src.name AS caller_name, tgt.name AS method_name, src.file AS caller_file
780
+ FROM edges e
781
+ JOIN nodes tgt ON e.target_id = tgt.id
782
+ JOIN nodes src ON e.source_id = src.id
783
+ WHERE e.kind = 'calls' AND tgt.kind = 'method'
784
+ AND INSTR(tgt.name, '.') > 0
785
+ AND (e.technique IS NULL OR e.technique != 'cha-expanded')
786
+ AND src.file IN (${ph})`,
787
+ )
788
+ .all(...chunk) as ChaCallRow[];
789
+ rows.push(...chunkRows);
790
+ }
791
+ return rows;
792
+ }
793
+ return db
794
+ .prepare(`
795
+ SELECT e.source_id, src.name AS caller_name, tgt.name AS method_name, src.file AS caller_file
796
+ FROM edges e
797
+ JOIN nodes tgt ON e.target_id = tgt.id
798
+ JOIN nodes src ON e.source_id = src.id
799
+ WHERE e.kind = 'calls' AND tgt.kind = 'method'
800
+ AND INSTR(tgt.name, '.') > 0
801
+ AND (e.technique IS NULL OR e.technique != 'cha-expanded')
802
+ `)
803
+ .all() as ChaCallRow[];
804
+ }
805
+
806
+ /**
807
+ * BFS-expand CHA call edges and insert new edges into the DB.
808
+ * Returns `{ newEdgeCount, affectedFiles }` for role re-classification scoping.
809
+ */
810
+ function expandChaEdges(
811
+ db: BetterSqlite3Database,
812
+ callToMethods: ChaCallRow[],
813
+ implementors: Map<string, string[]>,
814
+ instantiated: Set<string>,
815
+ noRtaEvidence: boolean,
816
+ ): { newEdgeCount: number; affectedFiles: Set<string> } {
817
+ const affectedFiles = new Set<string>();
818
+
819
+ // Seed seen-pairs only from the source_ids we'll be expanding — avoids loading every
820
+ // call edge in the DB (which would be O(all edges)) for large codebases.
821
+ const seen = new Set<string>();
822
+ if (callToMethods.length > 0) {
823
+ const sourceIds = [...new Set(callToMethods.map((r) => r.source_id))];
824
+ const CHUNK_SIZE = 500;
825
+ for (let i = 0; i < sourceIds.length; i += CHUNK_SIZE) {
826
+ const chunk = sourceIds.slice(i, i + CHUNK_SIZE);
827
+ const placeholders = chunk.map(() => '?').join(',');
828
+ const existingPairs = db
829
+ .prepare(
830
+ `SELECT source_id, target_id FROM edges WHERE kind = 'calls' AND source_id IN (${placeholders})`,
831
+ )
832
+ .all(...chunk) as Array<{ source_id: number; target_id: number }>;
833
+ for (const e of existingPairs) seen.add(`${e.source_id}|${e.target_id}`);
834
+ }
835
+ }
836
+
837
+ // No LIMIT: multiple files can define the same qualified name in a monorepo.
838
+ const findMethodStmt = db.prepare(
839
+ `SELECT id, file AS method_file FROM nodes WHERE name = ? AND kind = 'method'`,
840
+ );
841
+ const newEdges: Array<[number, number, string, number, number, string]> = [];
842
+ let newEdgeCount = 0;
843
+
844
+ for (const { source_id, method_name, caller_file } of callToMethods) {
845
+ const dotIdx = method_name.indexOf('.');
846
+ if (dotIdx === -1) continue;
847
+ const typeName = method_name.slice(0, dotIdx);
848
+ const methodSuffix = method_name.slice(dotIdx + 1);
849
+
850
+ // BFS over the implementors map — handles multi-level hierarchies where
851
+ // abstract/non-instantiated classes sit between the call-site type and
852
+ // the concrete leaf implementations (issue #1311).
853
+ const bfsQueue: string[] = [typeName];
854
+ const bfsVisited = new Set<string>([typeName]);
855
+ while (bfsQueue.length > 0) {
856
+ const current = bfsQueue.shift()!;
857
+ const children = implementors.get(current);
858
+ if (!children?.length) continue;
859
+
860
+ for (const cls of children) {
861
+ if (bfsVisited.has(cls)) continue;
862
+ bfsVisited.add(cls);
863
+
864
+ if (noRtaEvidence || instantiated.has(cls)) {
865
+ const qualifiedName = `${cls}.${methodSuffix}`;
866
+ const methodNodes = findMethodStmt.all(qualifiedName) as Array<{
867
+ id: number;
868
+ method_file: string | null;
869
+ }>;
870
+ for (const methodNode of methodNodes) {
871
+ if (methodNode.id === source_id) continue; // skip self-loops
872
+ const key = `${source_id}|${methodNode.id}`;
873
+ if (seen.has(key)) continue;
874
+ seen.add(key);
875
+ const conf = CHA_TYPED_DISPATCH_CONFIDENCE;
876
+ newEdges.push([source_id, methodNode.id, 'calls', conf, 0, 'cha-expanded']);
877
+ newEdgeCount++;
878
+ if (caller_file) affectedFiles.add(caller_file);
879
+ if (methodNode.method_file) affectedFiles.add(methodNode.method_file);
880
+ }
881
+ }
882
+
883
+ // Always traverse children — non-instantiated classes may have instantiated subclasses.
884
+ bfsQueue.push(cls);
885
+ }
886
+ }
887
+ }
888
+
889
+ if (newEdges.length > 0) {
890
+ db.transaction(() => batchInsertEdges(db, newEdges))();
891
+ // Account for post-pass edges excluded from the build summary line (#1452),
892
+ // mirroring the this/super dispatch post-pass insertion log.
893
+ debug(`CHA expansion post-pass: inserted ${newEdgeCount} edge(s)`);
894
+ }
895
+ return { newEdgeCount, affectedFiles };
896
+ }
897
+
898
+ /**
899
+ * Phase 8.6: CHA expansion post-pass for the native orchestrator path.
900
+ *
901
+ * The Rust build pipeline resolves typed receiver calls (e.g. `worker.doWork()`
902
+ * where `worker: IWorker`) to the interface method declaration only. This
903
+ * post-pass reads the class hierarchy (via `implements`/`extends` edges) and
904
+ * instantiated types (via `calls` edges to class nodes) from the DB and expands
905
+ * each call to an interface/abstract method to ALL RTA-filtered concrete
906
+ * implementations.
907
+ *
908
+ * Note: `this`/`super` dispatch is handled separately by `runPostNativeThisDispatch`,
909
+ * which WASM-re-parses JS/TS files to obtain raw call site receiver info.
910
+ *
911
+ * `changedFiles` controls candidate scoping on incremental builds:
912
+ * - null → full build; scan all call→method edges (existing behaviour).
913
+ * - array → incremental; two cheap gate queries decide scope:
914
+ * Gate A: any class/interface/trait/struct/record nodes in changed files?
915
+ * If yes, a new implementor may have appeared — full scan required.
916
+ * Gate B: any `calls` edges from changed-file sources targeting
917
+ * class/constructor/function-kind nodes? If yes, the RTA set may
918
+ * have grown (also covers the older-schema fallback where
919
+ * constructor calls target `constructor`/`function` nodes instead
920
+ * of `class` nodes) — full scan required.
921
+ * If neither gate fires: scope `callToMethods` to `src.file IN changedFiles`
922
+ * (safe because no hierarchy or RTA evidence changed).
923
+ *
924
+ * Returns the count of newly inserted CHA edges plus the set of files containing
925
+ * the new edges' endpoints, so the caller can scope role re-classification to the
926
+ * nodes whose fan-in/out actually changed. A zero count means no edges were added
927
+ * and role re-classification is unnecessary.
928
+ */
929
+ function runPostNativeCha(
930
+ db: BetterSqlite3Database,
931
+ changedFiles: string[] | null,
932
+ ): {
933
+ newEdgeCount: number;
934
+ affectedFiles: Set<string>;
935
+ } {
936
+ const affectedFiles = new Set<string>();
937
+ const empty = { newEdgeCount: 0, affectedFiles };
938
+ // Fast guard: no hierarchy edges → no CHA work
939
+ const hasHierarchy = db
940
+ .prepare(`SELECT 1 FROM edges WHERE kind IN ('extends', 'implements') LIMIT 1`)
941
+ .get();
942
+ if (!hasHierarchy) return empty;
943
+
944
+ const implementors = buildChaImplementorsMap(db);
945
+ if (implementors.size === 0) return empty;
946
+
947
+ const { instantiated, noRtaEvidence } = buildChaRtaSet(db);
948
+ const scopeToChangedFiles = computeChaScope(db, changedFiles);
949
+ const callToMethods = fetchChaCallToMethods(db, changedFiles, scopeToChangedFiles);
950
+
951
+ return expandChaEdges(db, callToMethods, implementors, instantiated, noRtaEvidence);
952
+ }
953
+
954
+ // Extensions where `this`/`super` dispatch can occur (JS/TS family)
955
+ const THIS_DISPATCH_EXTS = new Set(['.js', '.ts', '.tsx', '.jsx', '.mjs', '.cjs', '.mts', '.cts']);
956
+
957
+ // ── this/super dispatch post-pass helpers ───────────────────────────────────
958
+
959
+ /**
960
+ * Build parents map: child class → direct parent class (from `extends` edges).
961
+ * May be empty when only func-prop methods exist (no class inheritance) —
962
+ * resolveThisDispatch handles that case via direct class-prefix lookup.
963
+ */
964
+ function buildThisDispatchParentsMap(
965
+ db: BetterSqlite3Database,
966
+ hasExtends: unknown,
967
+ ): Map<string, string> {
968
+ const parents = new Map<string, string>();
969
+ if (!hasExtends) return parents;
970
+ const parentRows = db
971
+ .prepare(`
972
+ SELECT src.name AS child_name, tgt.name AS parent_name
973
+ FROM edges e
974
+ JOIN nodes src ON e.source_id = src.id
975
+ JOIN nodes tgt ON e.target_id = tgt.id
976
+ WHERE e.kind = 'extends'
977
+ `)
978
+ .all() as Array<{ child_name: string; parent_name: string }>;
979
+ for (const row of parentRows) {
980
+ if (!parents.has(row.child_name)) parents.set(row.child_name, row.parent_name);
981
+ }
982
+ return parents;
983
+ }
984
+
985
+ /**
986
+ * Determine the set of relative file paths to re-parse for this/super dispatch.
987
+ *
988
+ * On a full build we do NOT re-parse every JS/TS file — that would WASM-parse
989
+ * the entire project on top of the native pass, causing a massive regression
990
+ * (measured: +358% ms/file on codegraph itself). Instead we restrict to files
991
+ * that are part of the class inheritance hierarchy OR that contain dot-named
992
+ * method nodes (func-prop assignments whose bodies may call `this.sibling()`).
993
+ */
994
+ function selectThisDispatchFiles(
995
+ db: BetterSqlite3Database,
996
+ changedFiles: string[] | undefined,
997
+ isFullBuild: boolean,
998
+ ): string[] {
999
+ if (isFullBuild || !changedFiles) {
1000
+ const rows = db
1001
+ .prepare(`
1002
+ SELECT DISTINCT file FROM (
1003
+ SELECT src.file AS file
1004
+ FROM edges e
1005
+ JOIN nodes src ON e.source_id = src.id
1006
+ WHERE e.kind = 'extends' AND src.file IS NOT NULL
1007
+ UNION
1008
+ SELECT tgt.file AS file
1009
+ FROM edges e
1010
+ JOIN nodes tgt ON e.target_id = tgt.id
1011
+ WHERE e.kind = 'extends' AND tgt.file IS NOT NULL
1012
+ UNION
1013
+ -- Files with func-prop method definitions (e.g. f.h = function(){this.g()}).
1014
+ -- Only include files where the method's owner prefix is NOT a known class name —
1015
+ -- this keeps the re-parse set small (func-prop files only, not all class-method files).
1016
+ -- AND name IS NOT NULL guards the NOT IN sub-select: if any class node had a NULL
1017
+ -- name the entire NOT IN clause would silently return no rows (SQL NULL semantics).
1018
+ SELECT n.file AS file
1019
+ FROM nodes n
1020
+ WHERE n.kind = 'method'
1021
+ AND INSTR(n.name, '.') > 0
1022
+ AND n.file IS NOT NULL
1023
+ AND SUBSTR(n.name, 1, INSTR(n.name, '.') - 1) NOT IN (
1024
+ SELECT name FROM nodes WHERE kind IN ('class', 'struct', 'interface', 'type')
1025
+ AND name IS NOT NULL
1026
+ )
1027
+ )
1028
+ `)
1029
+ .all() as Array<{ file: string }>;
1030
+ return rows
1031
+ .map((r) => r.file)
1032
+ .filter((f) => THIS_DISPATCH_EXTS.has(path.extname(f).toLowerCase()));
1033
+ }
1034
+ // NOTE: Only files explicitly listed in changedFiles are re-parsed.
1035
+ // If a parent-class method is replaced (new node ID) but the child file is
1036
+ // unchanged, the stale super.method() edge is not refreshed here. A full
1037
+ // rebuild (isFullBuild=true) is required to recover in that scenario.
1038
+ return changedFiles.filter((f) => THIS_DISPATCH_EXTS.has(path.extname(f).toLowerCase()));
1039
+ }
1040
+
1041
+ /**
1042
+ * Re-parse files via native (preferred) + WASM fallback to obtain call sites
1043
+ * with receiver info. Returns a map of relPath → calls array.
1044
+ *
1045
+ * The native engine is preferred: this pass only runs after a native
1046
+ * orchestrator build, so the addon is already loaded and re-parses the
1047
+ * hierarchy file set in single-digit milliseconds with the same
1048
+ * receiver-annotated call sites as the WASM extractor. Booting the WASM
1049
+ * runtime here instead cost ~40–110ms per full build (in-process
1050
+ * web-tree-sitter + grammar init dominated) — part of the v3.12.0
1051
+ * publish-gate regression. Files the native engine cannot parse (extension
1052
+ * outside NATIVE_SUPPORTED_EXTENSIONS, e.g. .mts/.cts) and native parse
1053
+ * failures fall back to the WASM backfill path so the sweep stays complete.
1054
+ */
1055
+ async function parseFilesForThisDispatch(
1056
+ absFiles: string[],
1057
+ rootDir: string,
1058
+ ): Promise<{
1059
+ callsByRel: Map<string, { name: string; receiver?: string; line: number }[]>;
1060
+ wasmResults: Map<string, ExtractorOutput>;
1061
+ }> {
1062
+ const callsByRel = new Map<string, { name: string; receiver?: string; line: number }[]>();
1063
+ const nativeAbs = absFiles.filter((f) =>
1064
+ NATIVE_SUPPORTED_EXTENSIONS.has(path.extname(f).toLowerCase()),
1065
+ );
1066
+ // Track native-supported files that returned null (per-file parse error) so
1067
+ // they can be included in the WASM fallback set below, ensuring no file's
1068
+ // this/super call sites are silently discarded.
1069
+ const nativeNullFiles = new Set<string>();
1070
+ let nativeParsed = false;
1071
+ if (nativeAbs.length > 0) {
1072
+ const native = loadNative();
1073
+ if (native) {
1074
+ try {
1075
+ const results = native.parseFiles(nativeAbs, rootDir, false, false) as Array<{
1076
+ file: string;
1077
+ calls?: { name: string; receiver?: string; line: number }[];
1078
+ } | null>;
1079
+ for (let i = 0; i < results.length; i++) {
1080
+ const r = results[i];
1081
+ if (!r) {
1082
+ // Per-file parse failure — fall back to WASM for this file.
1083
+ const abs = nativeAbs[i];
1084
+ if (abs) nativeNullFiles.add(abs);
1085
+ continue;
1086
+ }
1087
+ callsByRel.set(normalizePath(path.relative(rootDir, r.file)), r.calls ?? []);
1088
+ }
1089
+ nativeParsed = true;
1090
+ } catch (e) {
1091
+ debug(`this-dispatch native re-parse failed, falling back to WASM: ${toErrorMessage(e)}`);
1092
+ }
1093
+ }
1094
+ }
1095
+ // WASM handles: (a) non-native extensions (e.g. .mts/.cts), (b) the entire
1096
+ // file list when the native batch threw, and (c) individual files where the
1097
+ // native addon returned null (per-file parse error).
1098
+ const wasmAbs = nativeParsed
1099
+ ? [
1100
+ ...absFiles.filter((f) => !NATIVE_SUPPORTED_EXTENSIONS.has(path.extname(f).toLowerCase())),
1101
+ ...nativeNullFiles,
1102
+ ]
1103
+ : absFiles;
1104
+ const wasmResults =
1105
+ wasmAbs.length > 0
1106
+ ? await parseFilesWasmForBackfill(wasmAbs, rootDir, { symbolsOnly: true })
1107
+ : new Map<string, ExtractorOutput>();
1108
+ for (const [relPath, symbols] of wasmResults) {
1109
+ callsByRel.set(relPath, symbols.calls ?? []);
1110
+ }
1111
+ return { callsByRel, wasmResults };
1112
+ }
1113
+
1114
+ /** Emit this/super dispatch edges from re-parsed call sites. */
1115
+ function emitThisDispatchEdges(
1116
+ db: BetterSqlite3Database,
1117
+ callsByRel: Map<string, { name: string; receiver?: string; line: number }[]>,
1118
+ chaCtx: ChaContext,
1119
+ lookup: CallNodeLookup,
1120
+ seen: Set<string>,
1121
+ ): {
1122
+ newEdges: Array<[number, number, string, number, number, string]>;
1123
+ targetIds: Set<number>;
1124
+ affectedFiles: Set<string>;
1125
+ } {
1126
+ // Find the innermost containing method/function for a call at `line` in `file`.
1127
+ // COALESCE maps NULL end_line to a large sentinel so unbounded nodes sort last
1128
+ // (SQLite ASC orders NULLs first, so a raw `end_line - line` would pick them first).
1129
+ const findCallerByLineStmt = db.prepare(`
1130
+ SELECT id, name FROM nodes
1131
+ WHERE file = ? AND kind IN ('method', 'function')
1132
+ AND line <= ? AND (end_line IS NULL OR end_line >= ?)
1133
+ ORDER BY COALESCE(end_line - line, 999999999) ASC
1134
+ LIMIT 1
1135
+ `);
1136
+
1137
+ const newEdges: Array<[number, number, string, number, number, string]> = [];
1138
+ const targetIds = new Set<number>();
1139
+ const affectedFiles = new Set<string>();
1140
+
1141
+ for (const [relPath, calls] of callsByRel) {
1142
+ for (const call of calls) {
1143
+ // Only 'this' and 'super' are class-instance receivers in JS/TS.
1144
+ // 'self' refers to WindowOrWorkerGlobalScope — not a class instance — so
1145
+ // filtering it here prevents spurious dispatch edges from Worker call sites.
1146
+ if (call.receiver !== 'this' && call.receiver !== 'super') continue;
1147
+
1148
+ const callerRow = findCallerByLineStmt.get(relPath, call.line, call.line) as
1149
+ | { id: number; name: string }
1150
+ | undefined;
1151
+ if (!callerRow) continue;
1152
+
1153
+ const targets = resolveThisDispatch(
1154
+ call.name,
1155
+ callerRow.name,
1156
+ call.receiver as 'this' | 'super',
1157
+ chaCtx,
1158
+ lookup,
1159
+ relPath,
1160
+ );
1161
+
1162
+ for (const t of targets) {
1163
+ if (t.id === callerRow.id) continue; // skip self-loops
1164
+ const key = `${callerRow.id}|${t.id}`;
1165
+ if (seen.has(key)) continue;
1166
+ seen.add(key);
1167
+ const conf = computeConfidence(relPath, t.file, null) - CHA_DISPATCH_PENALTY;
1168
+ if (conf <= 0) continue;
1169
+ // Tag super-dispatch edges distinctly so runPostNativeCha can exclude them
1170
+ // from further CHA expansion (super calls are not virtual dispatch).
1171
+ const technique = call.receiver === 'super' ? 'super-dispatch' : 'cha';
1172
+ newEdges.push([callerRow.id, t.id, 'calls', conf, 0, technique]);
1173
+ targetIds.add(t.id);
1174
+ affectedFiles.add(relPath);
1175
+ if (t.file) affectedFiles.add(t.file);
1176
+ }
1177
+ }
1178
+ }
1179
+ return { newEdges, targetIds, affectedFiles };
1180
+ }
1181
+
1182
+ /** Free WASM parse trees after this-dispatch post-pass to prevent memory leaks. */
1183
+ function cleanupThisDispatchWasmTrees(wasmResults: Map<string, ExtractorOutput>): void {
1184
+ for (const [, symbols] of wasmResults) {
1185
+ const tree = (symbols as { _tree?: { delete?: () => void } })._tree;
1186
+ if (tree && typeof tree.delete === 'function') {
1187
+ try {
1188
+ tree.delete();
1189
+ } catch {
1190
+ /* ignore cleanup errors */
1191
+ }
1192
+ }
1193
+ (symbols as { _tree?: unknown; _langId?: unknown })._tree = undefined;
1194
+ (symbols as { _tree?: unknown; _langId?: unknown })._langId = undefined;
1195
+ }
1196
+ }
1197
+
1198
+ /**
1199
+ * Phase 8.5: this/super dispatch post-pass for the native orchestrator path.
1200
+ *
1201
+ * The Rust build pipeline resolves typed receiver calls but does NOT persist raw
1202
+ * unresolved call site receiver info (e.g. `this`, `super`) to the DB. This
1203
+ * hybrid post-pass re-parses JS/TS/TSX files via WASM to collect call sites with
1204
+ * `this`/`super` receivers, then resolves them through the class hierarchy stored
1205
+ * in DB `extends` edges — mirroring what `buildChaPostPass` does on the WASM path.
1206
+ *
1207
+ * Also handles function-as-object-property methods (`f.h = function() { this.g() }`):
1208
+ * these use `this` to reference sibling properties on the same object (`f`), so
1209
+ * `resolveThisDispatch` resolves them by treating the dot-prefix of the caller name
1210
+ * (`f` from `f.h`) as the class and looking up `f.g` directly — no `extends` edge needed.
1211
+ *
1212
+ * Runs when either `extends` edges exist (class inheritance) OR dot-named `method`
1213
+ * nodes exist (func-prop assignments); skips only when neither is present.
1214
+ */
1215
+ async function runPostNativeThisDispatch(
1216
+ db: BetterSqlite3Database,
1217
+ rootDir: string,
1218
+ changedFiles: string[] | undefined,
1219
+ isFullBuild: boolean,
1220
+ ): Promise<{ elapsedMs: number; targetIds: Set<number>; affectedFiles: Set<string> }> {
1221
+ const t0 = performance.now();
1222
+
1223
+ // Fast guard: need at least one extends edge (class inheritance) OR a dot-named
1224
+ // method node (func-prop assignment: `f.h = function() { this.g() }`) for
1225
+ // this/super dispatch to produce any edges.
1226
+ const hasExtends = db.prepare(`SELECT 1 FROM edges WHERE kind = 'extends' LIMIT 1`).get();
1227
+ const hasFuncPropMethod = db
1228
+ .prepare(`SELECT 1 FROM nodes WHERE kind = 'method' AND INSTR(name, '.') > 0 LIMIT 1`)
1229
+ .get();
1230
+ const emptyResult = {
1231
+ elapsedMs: 0,
1232
+ targetIds: new Set<number>(),
1233
+ affectedFiles: new Set<string>(),
1234
+ };
1235
+ if (!hasExtends && !hasFuncPropMethod) return emptyResult;
1236
+
1237
+ const parents = buildThisDispatchParentsMap(db, hasExtends);
1238
+ // Note: parents may be empty when hasFuncPropMethod but !hasExtends — that is
1239
+ // intentional. resolveThisDispatch still resolves `this.g()` inside `f.h` by
1240
+ // treating `f` (the dot-prefix of callerName `f.h`) as the class and looking
1241
+ // up `f.g` directly via lookup.byName(), without traversing the parents chain.
1242
+
1243
+ const chaCtx: ChaContext = {
1244
+ implementors: new Map(), // not needed for this/super resolution
1245
+ parents,
1246
+ instantiatedTypes: new Set(), // not needed for this/super resolution
1247
+ };
1248
+
1249
+ const relFiles = selectThisDispatchFiles(db, changedFiles, isFullBuild);
1250
+ if (relFiles.length === 0) return emptyResult;
1251
+
1252
+ // DB-backed CallNodeLookup — resolveThisDispatch only calls byName()
1253
+ const findByNameStmt = db.prepare(`SELECT id, file, kind FROM nodes WHERE name = ?`);
1254
+ const lookup: CallNodeLookup = {
1255
+ byName: (name) => findByNameStmt.all(name) as Array<{ id: number; file: string; kind: string }>,
1256
+ byNameAndFile: (name, file) =>
1257
+ (findByNameStmt.all(name) as Array<{ id: number; file: string; kind: string }>).filter(
1258
+ (n) => n.file === file,
1259
+ ),
1260
+ isBarrel: () => false,
1261
+ resolveBarrel: () => null,
1262
+ nodeId: () => undefined,
1263
+ };
1264
+
1265
+ // Seed seen-pairs from existing call edges on source nodes in our file set
1266
+ const seen = new Set<string>();
1267
+ const CHUNK = 500;
1268
+ for (let i = 0; i < relFiles.length; i += CHUNK) {
1269
+ const chunk = relFiles.slice(i, i + CHUNK);
1270
+ const ph = chunk.map(() => '?').join(',');
1271
+ const rows = db
1272
+ .prepare(
1273
+ `SELECT e.source_id, e.target_id
1274
+ FROM edges e
1275
+ JOIN nodes n ON e.source_id = n.id
1276
+ WHERE e.kind = 'calls' AND n.file IN (${ph})`,
1277
+ )
1278
+ .all(...chunk) as Array<{ source_id: number; target_id: number }>;
1279
+ for (const r of rows) seen.add(`${r.source_id}|${r.target_id}`);
1280
+ }
1281
+
1282
+ const absFiles = relFiles.map((f) => path.join(rootDir, f));
1283
+ const { callsByRel, wasmResults } = await parseFilesForThisDispatch(absFiles, rootDir);
1284
+
1285
+ const { newEdges, targetIds, affectedFiles } = emitThisDispatchEdges(
1286
+ db,
1287
+ callsByRel,
1288
+ chaCtx,
1289
+ lookup,
1290
+ seen,
1291
+ );
1292
+
1293
+ if (newEdges.length > 0) {
1294
+ db.transaction(() => batchInsertEdges(db, newEdges))();
1295
+ debug(`this/super dispatch post-pass: inserted ${newEdges.length} edge(s)`);
1296
+ }
1297
+
1298
+ cleanupThisDispatchWasmTrees(wasmResults);
1299
+
1300
+ return { elapsedMs: performance.now() - t0, targetIds, affectedFiles };
1301
+ }
1302
+
1303
+ interface PostPassTimings {
1304
+ gapDetectMs: number;
1305
+ chaMs: number;
1306
+ thisDispatchMs: number;
1307
+ reclassifyMs: number;
1308
+ techniqueBackfillMs: number;
1309
+ }
1310
+
1311
+ /** Format timing result from native orchestrator phases + JS post-processing. */
1312
+ function formatNativeTimingResult(
1313
+ p: Record<string, number>,
1314
+ structurePatchMs: number,
1315
+ analysisTiming: { astMs: number; complexityMs: number; cfgMs: number; dataflowMs: number },
1316
+ postPass: PostPassTimings,
1317
+ ): BuildResult {
1318
+ return {
1319
+ phases: {
1320
+ setupMs: +(p.setupMs ?? 0).toFixed(1),
1321
+ collectMs: +(p.collectMs ?? 0).toFixed(1),
1322
+ detectMs: +(p.detectMs ?? 0).toFixed(1),
1323
+ parseMs: +(p.parseMs ?? 0).toFixed(1),
1324
+ insertMs: +(p.insertMs ?? 0).toFixed(1),
1325
+ resolveMs: +(p.resolveMs ?? 0).toFixed(1),
1326
+ edgesMs: +(p.edgesMs ?? 0).toFixed(1),
1327
+ structureMs: +((p.structureMs ?? 0) + structurePatchMs).toFixed(1),
1328
+ rolesMs: +(p.rolesMs ?? 0).toFixed(1),
1329
+ gapDetectMs: +postPass.gapDetectMs.toFixed(1),
1330
+ chaMs: +postPass.chaMs.toFixed(1),
1331
+ thisDispatchMs: +postPass.thisDispatchMs.toFixed(1),
1332
+ reclassifyMs: +postPass.reclassifyMs.toFixed(1),
1333
+ techniqueBackfillMs: +postPass.techniqueBackfillMs.toFixed(1),
1334
+ astMs: +(analysisTiming.astMs ?? 0).toFixed(1),
1335
+ complexityMs: +(analysisTiming.complexityMs ?? 0).toFixed(1),
1336
+ cfgMs: +(analysisTiming.cfgMs ?? 0).toFixed(1),
1337
+ dataflowMs: +(analysisTiming.dataflowMs ?? 0).toFixed(1),
1338
+ finalizeMs: +(p.finalizeMs ?? 0).toFixed(1),
1339
+ },
1340
+ };
1341
+ }
1342
+
1343
+ /**
1344
+ * Compute the WASM-only files present in the DB but missing from disk (#1073).
1345
+ *
1346
+ * Returns relative paths that:
1347
+ * - appear in `existingNodes` or `existingHashes` (in DB),
1348
+ * - are absent from `expected` (not on disk),
1349
+ * - have an extension installed for WASM, AND
1350
+ * - have an extension NOT covered by `nativeSupported` — Rust's
1351
+ * `purge_changed_files` handles deletion for natively-supported extensions
1352
+ * via its own `detect_removed_files`, so the caller must not double-purge.
1353
+ *
1354
+ * Extensions are lowercased before lookup to match the registry and Rust's
1355
+ * `LanguageKind::from_extension` (which normalises case for the languages
1356
+ * where both cases are conventional, e.g. R's `.r` / `.R`).
1357
+ *
1358
+ * DB paths are forced to forward slashes before comparison with `expected`
1359
+ * (which is always normalised). The on-disk invariant is that DB rows are
1360
+ * written with forward slashes, but a stale row written by older code on
1361
+ * Windows could carry back-slashes — normalising here makes the comparison
1362
+ * platform-safe and prevents false-positive purges of live rows. We replace
1363
+ * `\\` explicitly (rather than calling `normalizePath`, which only touches
1364
+ * `path.sep`) so the defence works when running on POSIX against a DB that
1365
+ * was migrated from Windows.
1366
+ *
1367
+ * Exported for unit testing.
1368
+ */
1369
+ export function computeWasmOnlyStaleFiles(input: WasmOnlyStaleFilesInput): string[] {
1370
+ const { existingNodes, existingHashes, expected, installedExts, nativeSupported } = input;
1371
+ const stale: string[] = [];
1372
+ const seen = new Set<string>();
1373
+ const consider = (rawRel: string): void => {
1374
+ const rel = rawRel.replace(/\\/g, '/');
1375
+ if (expected.has(rel) || seen.has(rel)) return;
1376
+ const ext = path.extname(rel).toLowerCase();
1377
+ if (nativeSupported.has(ext)) return;
1378
+ if (!installedExts.has(ext)) return;
1379
+ seen.add(rel);
1380
+ // Push the ORIGINAL raw path (not the normalised form) so the eventual
1381
+ // `DELETE FROM nodes WHERE file = ?` predicate in `purgeFilesData`
1382
+ // matches the actual stored row. The dedup `seen` set keeps the
1383
+ // normalised form so a file written once with `\` and once with `/`
1384
+ // is still treated as one entry — but the value the SQL sees has to
1385
+ // be byte-identical to what's on disk in the DB.
1386
+ stale.push(rawRel);
1387
+ };
1388
+ for (const rel of existingNodes) consider(rel);
1389
+ for (const rel of existingHashes) consider(rel);
1390
+ return stale;
1391
+ }
1392
+
1393
+ /**
1394
+ * Group relative paths by their lowercased extension. Shape matches the bucket
1395
+ * type that `formatDropExtensionSummary` consumes, so callers can render a
1396
+ * log-friendly per-extension summary without going through `classifyNativeDrops`
1397
+ * when the reason is already known (e.g. the stale-purge path where every path
1398
+ * is guaranteed `unsupported-by-native`).
1399
+ */
1400
+ function groupByExtension(relPaths: Iterable<string>): Map<string, string[]> {
1401
+ const buckets = new Map<string, string[]>();
1402
+ for (const rel of relPaths) {
1403
+ const ext = path.extname(rel).toLowerCase();
1404
+ let list = buckets.get(ext);
1405
+ if (!list) {
1406
+ list = [];
1407
+ buckets.set(ext, list);
1408
+ }
1409
+ list.push(rel);
1410
+ }
1411
+ return buckets;
1412
+ }
1413
+
1414
+ /**
1415
+ * Return the subset of relative paths that are gitignored in `rootDir`.
1416
+ *
1417
+ * Runs `git check-ignore --stdin` with all candidate paths piped in. Any
1418
+ * path that git echoes back is gitignored. Fails silently (returns an empty
1419
+ * set) when git is unavailable, the directory is not a git repo, or the
1420
+ * check-ignore call throws — the gap-detection logic handles those cases
1421
+ * gracefully without this filter.
1422
+ *
1423
+ * Uses relative paths (forward-slash separated) as both input and output so
1424
+ * the result set can be matched directly against the `expected` set in
1425
+ * `detectDroppedLanguageGap` without any further path manipulation.
1426
+ */
1427
+ function queryGitIgnoredFiles(rootDir: string, relPaths: Iterable<string>): Set<string> {
1428
+ const ignored = new Set<string>();
1429
+ const paths = [...relPaths];
1430
+ if (paths.length === 0) return ignored;
1431
+ try {
1432
+ const stdin = paths.join('\n');
1433
+ const output = execFileSync('git', ['check-ignore', '--stdin'], {
1434
+ cwd: rootDir,
1435
+ input: stdin,
1436
+ encoding: 'utf-8',
1437
+ maxBuffer: 100 * 1024 * 1024,
1438
+ // git check-ignore exits with 1 when none of the paths are ignored —
1439
+ // that is not an error for our purposes. stdio: 'pipe' lets us capture
1440
+ // stdout without swallowing stderr, and the try/catch handles the
1441
+ // non-zero exit from execFileSync when ALL paths are non-ignored
1442
+ // (exit code 1 from git check-ignore means "no matches").
1443
+ stdio: ['pipe', 'pipe', 'pipe'],
1444
+ });
1445
+ for (const line of output.split('\n')) {
1446
+ const trimmed = normalizePath(line.trim());
1447
+ if (trimmed) ignored.add(trimmed);
1448
+ }
1449
+ } catch (e: unknown) {
1450
+ // Exit code 1 means no paths were ignored — not an error. Any other
1451
+ // failure (git unavailable, not a repo, etc.) is silently swallowed
1452
+ // so the caller proceeds with the unfiltered set.
1453
+ const exitCode = (e as { status?: number }).status;
1454
+ if (exitCode !== 1) {
1455
+ debug(`queryGitIgnoredFiles: git check-ignore failed: ${toErrorMessage(e)}`);
1456
+ }
1457
+ // On exit code 1, output is empty so ignored stays empty — correct.
1458
+ // On other errors we also proceed with the empty set (safe degradation).
1459
+ }
1460
+ return ignored;
1461
+ }
1462
+
1463
+ /**
1464
+ * Detect files the native orchestrator silently dropped.
1465
+ *
1466
+ * Walks the filesystem and compares against `nodes` + `file_hashes`. A file
1467
+ * is "missing" if it's absent from EITHER table — both must be present for
1468
+ * the fast-skip pre-flight (#1054) to work, and the two can diverge (e.g.
1469
+ * legacy DBs where `nodes` was populated but `file_hashes` was not).
1470
+ *
1471
+ * Restricted to files with an installed WASM grammar; extensions in
1472
+ * `LANGUAGE_REGISTRY` without a shipped grammar (e.g. groovy on minimal
1473
+ * installs) can't be parsed by either engine, so they're not a native
1474
+ * regression — excluding them keeps the warn count in
1475
+ * `backfillNativeDroppedFiles` meaningful.
1476
+ *
1477
+ * Also detects WASM-only files deleted from disk (#1073). Rust's
1478
+ * `detect_removed_files` filter (#1070) skips files outside its supported
1479
+ * extensions, so deletions of WASM-only languages don't reach the native
1480
+ * purge path; the rest of the backfill only inserts rows, so without this
1481
+ * step stale `nodes`/`file_hashes` rows would linger across incremental
1482
+ * rebuilds until the next full rebuild.
1483
+ *
1484
+ * Cheap (no DB handoff, no parsing): used both to gate the backfill call
1485
+ * and as its working set. NativeDbProxy supports `.prepare().all()`, so
1486
+ * this works whether `ctx.db` is a proxy or a real better-sqlite3
1487
+ * connection — letting us skip the close-native / reopen-better-sqlite3
1488
+ * cost when there's nothing to backfill.
1489
+ */
1490
+ function detectDroppedLanguageGap(ctx: PipelineContext): DroppedLanguageGap {
1491
+ const collected = collectFilesUtil(ctx.rootDir, [], ctx.config, new Set<string>());
1492
+ const expectedRaw = collected.files.map((f) => normalizePath(path.relative(ctx.rootDir, f)));
1493
+
1494
+ // The native Rust engine uses the `ignore` crate with git_ignore(true), so it
1495
+ // respects .gitignore and never processes gitignored files. The JS collectFiles
1496
+ // walker has no gitignore awareness, so without this filter gitignored files
1497
+ // (e.g. NAPI-RS generated crates/codegraph-core/index.js / index.d.ts) appear
1498
+ // in `expected` but not in the DB, causing a spurious "native extractor bug"
1499
+ // WARN and triggering an unnecessary WASM backfill (#1626).
1500
+ const gitIgnored = queryGitIgnoredFiles(ctx.rootDir, expectedRaw);
1501
+ const expected = new Set(
1502
+ gitIgnored.size > 0 ? expectedRaw.filter((r) => !gitIgnored.has(r)) : expectedRaw,
1503
+ );
1504
+
1505
+ const existingNodeRows = ctx.db
1506
+ .prepare("SELECT DISTINCT file FROM nodes WHERE kind = 'file'")
1507
+ .all() as Array<{ file: string }>;
1508
+ const existingNodes = new Set(existingNodeRows.map((r) => r.file));
1509
+
1510
+ let existingHashes = new Set<string>();
1511
+ try {
1512
+ const existingHashRows = ctx.db
1513
+ .prepare('SELECT DISTINCT file FROM file_hashes')
1514
+ .all() as Array<{ file: string }>;
1515
+ existingHashes = new Set(existingHashRows.map((r) => r.file));
1516
+ } catch (e) {
1517
+ // file_hashes table may not exist on legacy DBs; treat as fully missing
1518
+ // so the backfill writes rows on the upsert path below.
1519
+ debug(
1520
+ `detectDroppedLanguageGap: file_hashes read failed (table may not exist): ${toErrorMessage(e)}`,
1521
+ );
1522
+ }
1523
+
1524
+ const installedExts = getInstalledWasmExtensions();
1525
+ const missingRel: string[] = [];
1526
+ const missingAbs: string[] = [];
1527
+ for (const rel of expected) {
1528
+ if (existingNodes.has(rel) && existingHashes.has(rel)) continue;
1529
+ const ext = path.extname(rel).toLowerCase();
1530
+ if (!installedExts.has(ext)) continue;
1531
+ missingRel.push(rel);
1532
+ missingAbs.push(path.join(ctx.rootDir, rel));
1533
+ }
1534
+
1535
+ const staleRel = computeWasmOnlyStaleFiles({
1536
+ existingNodes,
1537
+ existingHashes,
1538
+ expected,
1539
+ installedExts,
1540
+ nativeSupported: NATIVE_SUPPORTED_EXTENSIONS,
1541
+ });
1542
+
1543
+ return { missingRel, missingAbs, staleRel };
1544
+ }
1545
+
1546
+ // ── backfillNativeDroppedFiles helpers ───────────────────────────────────────
1547
+
1548
+ /** Purge stale WASM-only files deleted from disk (#1073). */
1549
+ function purgeStaleWasmOnlyFiles(db: BetterSqlite3Database, staleRel: string[]): void {
1550
+ // `computeWasmOnlyStaleFiles` guarantees every path here has an extension
1551
+ // outside NATIVE_SUPPORTED_EXTENSIONS, so `classifyNativeDrops` would
1552
+ // always bucket 100% into `unsupported-by-native`. Build the extension
1553
+ // summary directly to avoid a redundant classification pass.
1554
+ const staleByExt = groupByExtension(staleRel);
1555
+ info(
1556
+ `Detected ${staleRel.length} deleted WASM-only file(s) across ${staleByExt.size} extension(s) the native orchestrator skipped; purging stale rows:${formatDropExtensionSummary(staleByExt)}`,
1557
+ );
1558
+ purgeFilesData(db, staleRel);
1559
+ }
1560
+
1561
+ /**
1562
+ * Classify and log dropped file buckets.
1563
+ * Three-way split of native-extractor-failure files:
1564
+ * realFailureBuckets — WASM found symbols → real Rust extractor bug (WARN)
1565
+ * emptyFileBuckets — WASM parsed but found 0 symbols → gitignored/empty (debug)
1566
+ * wasmSkipBuckets — WASM skipped entirely → no file-node insert (debug)
1567
+ */
1568
+ function classifyAndLogDroppedFiles(
1569
+ missingRel: string[],
1570
+ wasmParsedFiles: Set<string>,
1571
+ wasmFoundSymbols: Set<string>,
1572
+ ): void {
1573
+ const { byReason, totals } = classifyNativeDrops(missingRel);
1574
+ if (totals['unsupported-by-native'] > 0) {
1575
+ const buckets = byReason['unsupported-by-native'];
1576
+ info(
1577
+ `Native orchestrator skipped ${totals['unsupported-by-native']} file(s) across ${buckets.size} extension(s) in languages without a Rust extractor; backfilling via WASM:${formatDropExtensionSummary(buckets)}`,
1578
+ );
1579
+ }
1580
+ if (totals['native-extractor-failure'] > 0) {
1581
+ const allFailurePaths = byReason['native-extractor-failure'];
1582
+ const realFailureBuckets = new Map<string, string[]>();
1583
+ const emptyFileBuckets = new Map<string, string[]>();
1584
+ const wasmSkipBuckets = new Map<string, string[]>();
1585
+ for (const [ext, paths] of allFailurePaths) {
1586
+ for (const relPath of paths) {
1587
+ let bucket: Map<string, string[]>;
1588
+ if (wasmFoundSymbols.has(relPath)) {
1589
+ bucket = realFailureBuckets;
1590
+ } else if (wasmParsedFiles.has(relPath)) {
1591
+ bucket = emptyFileBuckets;
1592
+ } else {
1593
+ bucket = wasmSkipBuckets;
1594
+ }
1595
+ let list = bucket.get(ext);
1596
+ if (!list) {
1597
+ list = [];
1598
+ bucket.set(ext, list);
1599
+ }
1600
+ list.push(relPath);
1601
+ }
1602
+ }
1603
+ if (realFailureBuckets.size > 0) {
1604
+ const realCount = [...realFailureBuckets.values()].reduce((s, a) => s + a.length, 0);
1605
+ warn(
1606
+ `Native orchestrator dropped ${realCount} file(s) across ${realFailureBuckets.size} extension(s) in natively-supported languages — likely a Rust extractor bug. Backfilling via WASM:${formatDropExtensionSummary(realFailureBuckets)}`,
1607
+ );
1608
+ }
1609
+ if (emptyFileBuckets.size > 0) {
1610
+ const emptyCount = [...emptyFileBuckets.values()].reduce((s, a) => s + a.length, 0);
1611
+ debug(
1612
+ `Native orchestrator skipped ${emptyCount} file(s) in natively-supported languages that also produced 0 symbols via WASM (likely gitignored or empty); backfilling file nodes:${formatDropExtensionSummary(emptyFileBuckets)}`,
1613
+ );
1614
+ }
1615
+ if (wasmSkipBuckets.size > 0) {
1616
+ const skipCount = [...wasmSkipBuckets.values()].reduce((s, a) => s + a.length, 0);
1617
+ debug(
1618
+ `Native orchestrator skipped ${skipCount} file(s) in natively-supported languages that WASM also could not parse (unregistered extension or parse error); no file-node inserted:${formatDropExtensionSummary(wasmSkipBuckets)}`,
1619
+ );
1620
+ }
1621
+ }
1622
+ }
1623
+
1624
+ /** Insert node rows for all backfilled files and mark exported symbols. */
1625
+ function insertBackfilledNodes(
1626
+ db: BetterSqlite3Database,
1627
+ wasmResults: Map<string, ExtractorOutput>,
1628
+ ): void {
1629
+ const rows: unknown[][] = [];
1630
+ const exportKeys: unknown[][] = [];
1631
+ for (const [relPath, symbols] of wasmResults) {
1632
+ // File row — mirrors insertDefinitionsAndExports: qualified_name is null.
1633
+ rows.push([relPath, 'file', relPath, 0, null, null, null, null, null]);
1634
+ for (const def of symbols.definitions ?? []) {
1635
+ // Populate qualified_name/scope the same way the JS fallback does so
1636
+ // downstream queries (cross-file references, "go to definition") find
1637
+ // these symbols.
1638
+ const dotIdx = def.name.lastIndexOf('.');
1639
+ const scope = dotIdx !== -1 ? def.name.slice(0, dotIdx) : null;
1640
+ rows.push([
1641
+ def.name,
1642
+ def.kind,
1643
+ relPath,
1644
+ def.line,
1645
+ def.endLine ?? null,
1646
+ null,
1647
+ def.name,
1648
+ scope,
1649
+ def.visibility ?? null,
1650
+ ]);
1651
+ }
1652
+ // Exports: insert the row (INSERT OR IGNORE — a matching definition row
1653
+ // is a no-op) and queue a key for the second-pass exported=1 update, so
1654
+ // queries filtering on exported=1 find backfilled symbols (#970).
1655
+ for (const exp of symbols.exports ?? []) {
1656
+ rows.push([exp.name, exp.kind, relPath, exp.line, null, null, exp.name, null, null]);
1657
+ exportKeys.push([exp.name, exp.kind, relPath, exp.line]);
1658
+ }
1659
+ }
1660
+ batchInsertNodes(db, rows);
1661
+
1662
+ // Mark exported symbols in batches — mirrors insertDefinitionsAndExports.
1663
+ if (exportKeys.length > 0) {
1664
+ const EXPORT_CHUNK = 500;
1665
+ const exportStmtCache = new Map<number, SqliteStatement>();
1666
+ for (let i = 0; i < exportKeys.length; i += EXPORT_CHUNK) {
1667
+ const end = Math.min(i + EXPORT_CHUNK, exportKeys.length);
1668
+ const chunkSize = end - i;
1669
+ let updateStmt = exportStmtCache.get(chunkSize);
1670
+ if (!updateStmt) {
1671
+ const conditions = Array.from(
1672
+ { length: chunkSize },
1673
+ () => '(name = ? AND kind = ? AND file = ? AND line = ?)',
1674
+ ).join(' OR ');
1675
+ updateStmt = db.prepare(`UPDATE nodes SET exported = 1 WHERE ${conditions}`);
1676
+ exportStmtCache.set(chunkSize, updateStmt);
1677
+ }
1678
+ const vals: unknown[] = [];
1679
+ for (let j = i; j < end; j++) {
1680
+ const k = exportKeys[j] as unknown[];
1681
+ vals.push(k[0], k[1], k[2], k[3]);
1682
+ }
1683
+ updateStmt.run(...vals);
1684
+ }
1685
+ }
1686
+ }
1687
+
1688
+ /**
1689
+ * Persist file_hashes rows for every backfilled file.
1690
+ *
1691
+ * The Rust orchestrator only hashes files it parsed itself, so without this
1692
+ * step files in optional-language extensions (e.g. .clj when no Rust extractor
1693
+ * exists) would be missing from `file_hashes` — permanently breaking the JS-side
1694
+ * fast-skip pre-flight (#1054), which rejects on `collected file missing
1695
+ * from file_hashes` and forces every no-op rebuild back through the full
1696
+ * ~2s native pipeline (#1068).
1697
+ *
1698
+ * Iterates `missingRel` (every collected file the Rust orchestrator dropped),
1699
+ * not `wasmResults`, so files that produced zero symbols still get a row.
1700
+ */
1701
+ function backfillFileHashes(
1702
+ db: BetterSqlite3Database,
1703
+ missingRel: string[],
1704
+ missingAbs: string[],
1705
+ ): void {
1706
+ try {
1707
+ const upsertHash = db.prepare(
1708
+ 'INSERT OR REPLACE INTO file_hashes (file, hash, mtime, size) VALUES (?, ?, ?, ?)',
1709
+ );
1710
+ const writeHashes = db.transaction(() => {
1711
+ for (let i = 0; i < missingRel.length; i++) {
1712
+ const relPath = missingRel[i];
1713
+ const absPath = missingAbs[i];
1714
+ if (!relPath || !absPath) continue;
1715
+ let code: string | null;
1716
+ try {
1717
+ code = readFileSafe(absPath);
1718
+ } catch (e) {
1719
+ debug(`backfillNativeDroppedFiles: read failed for ${relPath}: ${toErrorMessage(e)}`);
1720
+ continue;
1721
+ }
1722
+ if (code === null) continue;
1723
+ const stat = fileStat(absPath);
1724
+ const mtime = stat ? stat.mtime : 0;
1725
+ const size = stat ? stat.size : 0;
1726
+ upsertHash.run(relPath, fileHash(code), mtime, size);
1727
+ }
1728
+ });
1729
+ writeHashes();
1730
+ } catch (e) {
1731
+ debug(
1732
+ `backfillNativeDroppedFiles: file_hashes write failed (table may not exist): ${toErrorMessage(e)}`,
1733
+ );
1734
+ }
1735
+ }
1736
+
1737
+ /**
1738
+ * Backfill files that the native orchestrator silently dropped during parse.
1739
+ * Falls back to WASM + inserts file/symbol nodes so engine counts match (#967).
1740
+ *
1741
+ * Also purges stale rows for WASM-only files deleted from disk (#1073), which
1742
+ * Rust's `detect_removed_files` filter (#1070) skips.
1743
+ *
1744
+ * Accepts a pre-computed `gap` from `detectDroppedLanguageGap` so the caller
1745
+ * can use the same scan for both gating and the actual backfill — avoiding
1746
+ * a redundant fs walk when the orchestrator's signals already triggered.
1747
+ */
1748
+ async function backfillNativeDroppedFiles(
1749
+ ctx: PipelineContext,
1750
+ gap: DroppedLanguageGap,
1751
+ ): Promise<void> {
1752
+ const { missingRel, missingAbs, staleRel } = gap;
1753
+ if (missingAbs.length === 0 && staleRel.length === 0) return;
1754
+
1755
+ // Now that we know there's work to do, hand off to better-sqlite3 (needed
1756
+ // for the INSERT path below).
1757
+ if (ctx.nativeFirstProxy) {
1758
+ closeNativeDb(ctx, 'pre-parity-backfill');
1759
+ ctx.db = openDb(ctx.dbPath);
1760
+ ctx.nativeFirstProxy = false;
1761
+ }
1762
+
1763
+ const dbConn = ctx.db as unknown as BetterSqlite3Database;
1764
+
1765
+ // Purge WASM-only files that were deleted from disk (#1073). Rust's
1766
+ // detect_removed_files skips them and the insert path below never visits
1767
+ // them, so without this their rows would persist across rebuilds until the
1768
+ // next full rebuild reset the DB.
1769
+ if (staleRel.length > 0) {
1770
+ purgeStaleWasmOnlyFiles(dbConn, staleRel);
1771
+ }
1772
+
1773
+ if (missingAbs.length === 0) return;
1774
+
1775
+ // Parse all missing files via WASM first so we can distinguish real native
1776
+ // extractor failures (WASM finds symbols but native didn't) from files the
1777
+ // Rust engine legitimately skipped (gitignored artifacts, empty declaration
1778
+ // files, etc. where WASM also produces 0 symbols). Both categories are
1779
+ // backfilled — only the former triggers a WARN (#1566).
1780
+ const wasmResults = await parseFilesWasmForBackfill(missingAbs, ctx.rootDir);
1781
+
1782
+ // Build two sets from wasmResults:
1783
+ // wasmParsedFiles — rel-paths present in wasmResults (WASM succeeded, even 0 symbols)
1784
+ // wasmFoundSymbols — subset where WASM found ≥1 symbol
1785
+ // Files absent from wasmParsedFiles were skipped by WASM entirely (extension
1786
+ // not in _extToLang, wasmExtractSymbols returned null, or a read error).
1787
+ // Those files do NOT end up in the batchInsertNodes loop below.
1788
+ const wasmParsedFiles = new Set<string>();
1789
+ const wasmFoundSymbols = new Set<string>();
1790
+ for (const [relPath, symbols] of wasmResults) {
1791
+ wasmParsedFiles.add(relPath);
1792
+ if ((symbols.definitions?.length ?? 0) > 0 || (symbols.exports?.length ?? 0) > 0) {
1793
+ wasmFoundSymbols.add(relPath);
1794
+ }
1795
+ }
1796
+
1797
+ // Classify drops so users see per-extension reasons instead of just a count
1798
+ // (#1011). `unsupported-by-native` is a legitimate parser limit (no Rust
1799
+ // extractor); `native-extractor-failure` indicates a real native bug since
1800
+ // the language IS supported by the addon yet WASM found symbols the native
1801
+ // engine should have extracted. Files where both engines produce 0 symbols
1802
+ // are legitimately empty (e.g. gitignored napi-generated declaration stubs)
1803
+ // and logged at debug level only.
1804
+ classifyAndLogDroppedFiles(missingRel, wasmParsedFiles, wasmFoundSymbols);
1805
+
1806
+ insertBackfilledNodes(dbConn, wasmResults);
1807
+ backfillFileHashes(dbConn, missingRel, missingAbs);
1808
+
1809
+ // Free WASM parse trees from the inline backfill path (#1058).
1810
+ // `parseFilesWasmInline` sets `symbols._tree` (a live web-tree-sitter Tree
1811
+ // backed by WASM linear memory) on every result, but these symbols are
1812
+ // consumed locally for DB row construction and never added to
1813
+ // `ctx.allSymbols`, so the finalize-stage `releaseWasmTrees` sweep never
1814
+ // sees them. Without this, trees leak WASM memory until process exit —
1815
+ // bounded per run but cumulative across in-process integration tests.
1816
+ // Mirrors the cleanup discipline established for #931.
1817
+ cleanupThisDispatchWasmTrees(wasmResults);
1818
+ }
1819
+
1820
+ /**
1821
+ * Backfill the `technique` column on `calls` edges written by the native Rust
1822
+ * orchestrator, which does not write the column itself. Also lifts any
1823
+ * resolved ts-native edge whose confidence is below TS_NATIVE_CONFIDENCE_FLOOR
1824
+ * to that floor value so that the name-lookup quality of the native resolver is
1825
+ * reflected in the call-confidence metric.
1826
+ *
1827
+ * For full builds, all `calls` edges in the DB are new so a global UPDATE is
1828
+ * correct. For incremental builds, only changed-file source nodes are updated
1829
+ * to avoid overwriting previously-set technique values on unchanged edges.
1830
+ */
1831
+ function backfillEdgeTechniquesAfterNativeOrchestrator(
1832
+ db: BetterSqlite3Database,
1833
+ isFullBuild: boolean,
1834
+ changedFiles: string[] | undefined,
1835
+ ): void {
1836
+ // Quiet incremental: no files changed → no new edges inserted, nothing to tag.
1837
+ // Running the global UPDATE here would mis-tag pre-migration NULL-technique edges
1838
+ // from unchanged files as 'ts-native'.
1839
+ if (!isFullBuild && changedFiles && changedFiles.length === 0) {
1840
+ return;
1841
+ }
1842
+ if (isFullBuild || !changedFiles) {
1843
+ db.prepare(
1844
+ "UPDATE edges SET technique = 'ts-native' WHERE kind = 'calls' AND technique IS NULL",
1845
+ ).run();
1846
+ // Lift resolved ts-native edges below the confidence floor.
1847
+ db.prepare(
1848
+ `UPDATE edges SET confidence = ?
1849
+ WHERE kind = 'calls' AND technique = 'ts-native'
1850
+ AND confidence > 0 AND confidence < ?`,
1851
+ ).run(TS_NATIVE_CONFIDENCE_FLOOR, TS_NATIVE_CONFIDENCE_FLOOR);
1852
+ return;
1853
+ }
1854
+ // Incremental: scope to source nodes whose file is one of the changed files.
1855
+ // Chunk to stay within SQLite's SQLITE_LIMIT_VARIABLE_NUMBER (999 on older builds).
1856
+ const CHUNK_SIZE = 500;
1857
+ const tx = db.transaction(() => {
1858
+ for (let i = 0; i < changedFiles.length; i += CHUNK_SIZE) {
1859
+ const chunk = changedFiles.slice(i, i + CHUNK_SIZE);
1860
+ const placeholders = chunk.map(() => '?').join(',');
1861
+ db.prepare(
1862
+ `UPDATE edges SET technique = 'ts-native'
1863
+ WHERE kind = 'calls' AND technique IS NULL
1864
+ AND source_id IN (
1865
+ SELECT id FROM nodes WHERE file IN (${placeholders})
1866
+ )`,
1867
+ ).run(...chunk);
1868
+ // Lift resolved ts-native edges below the confidence floor for this chunk.
1869
+ db.prepare(
1870
+ `UPDATE edges SET confidence = ?
1871
+ WHERE kind = 'calls' AND technique = 'ts-native'
1872
+ AND confidence > 0 AND confidence < ?
1873
+ AND source_id IN (
1874
+ SELECT id FROM nodes WHERE file IN (${placeholders})
1875
+ )`,
1876
+ ).run(TS_NATIVE_CONFIDENCE_FLOOR, TS_NATIVE_CONFIDENCE_FLOOR, ...chunk);
1877
+ }
1878
+ });
1879
+ tx();
1880
+ }
1881
+
1882
+ // ── tryNativeOrchestrator helpers ────────────────────────────────────────────
1883
+
1884
+ /**
1885
+ * Open NativeDatabase on demand — deferred from setupPipeline to skip the
1886
+ * ~60ms cost on no-op/early-exit builds.
1887
+ *
1888
+ * Closes the better-sqlite3 connection first to avoid dual-connection WAL
1889
+ * corruption. On setup failure, falls back to reopening better-sqlite3 and
1890
+ * leaves ctx.nativeDb undefined so the caller falls through to the JS pipeline.
1891
+ */
1892
+ function openNativeDatabase(ctx: PipelineContext): void {
1893
+ if (ctx.nativeDb || !ctx.nativeAvailable) return;
1894
+ const native = loadNative();
1895
+ if (!native?.NativeDatabase) return;
1896
+ try {
1897
+ // Close better-sqlite3 before opening rusqlite to avoid WAL conflicts.
1898
+ // Uses raw close() instead of closeDb() intentionally — the advisory lock
1899
+ // is kept and transferred to the NativeDbProxy below, not released here.
1900
+ ctx.db.close();
1901
+ acquireAdvisoryLock(ctx.dbPath);
1902
+ ctx.nativeDb = native.NativeDatabase.openReadWrite(ctx.dbPath);
1903
+ ctx.nativeDb.initSchema();
1904
+ // Replace ctx.db with a NativeDbProxy so post-native JS fallback
1905
+ // (structure, analysis) can use it without reopening better-sqlite3.
1906
+ const proxy = new NativeDbProxy(ctx.nativeDb);
1907
+ proxy.__lockPath = `${ctx.dbPath}.lock`;
1908
+ ctx.db = proxy as unknown as typeof ctx.db;
1909
+ ctx.nativeFirstProxy = true;
1910
+ } catch (err) {
1911
+ warn(`NativeDatabase setup failed, falling back to JS: ${toErrorMessage(err)}`);
1912
+ try {
1913
+ ctx.nativeDb?.close();
1914
+ } catch (e) {
1915
+ debug(`tryNativeOrchestrator: close failed during fallback: ${toErrorMessage(e)}`);
1916
+ }
1917
+ ctx.nativeDb = undefined;
1918
+ ctx.nativeFirstProxy = false; // defensive: reset in case future refactors move the assignment above throwing lines
1919
+ releaseAdvisoryLock(`${ctx.dbPath}.lock`);
1920
+ // Reopen better-sqlite3 for JS pipeline fallback
1921
+ ctx.db = openDb(ctx.dbPath);
1922
+ }
1923
+ }
1924
+
1925
+ /**
1926
+ * Coordinate all post-native edge-writing post-passes, role re-classification,
1927
+ * and technique backfill. Returns timing data for the build result.
1928
+ *
1929
+ * Post-passes run before structure/analysis so role classification sees the
1930
+ * complete graph including CHA + this/super dispatch edges.
1931
+ */
1932
+ async function runPostNativePasses(
1933
+ ctx: PipelineContext,
1934
+ result: NativeOrchestratorResult,
1935
+ ): Promise<PostPassTimings & { backfillHappened: boolean }> {
1936
+ // Engine parity: the native orchestrator silently drops files whose
1937
+ // Rust extractor/grammar is missing or fails (e.g. HCL, Scala, Swift on
1938
+ // stale native binaries). WASM handles those — backfill via WASM so both
1939
+ // engines process the same file set (#967).
1940
+ //
1941
+ // Detect the gap once (fs walk + 2 DB queries) and use it for both gating
1942
+ // and the backfill itself. On quiet incrementals we still pay the walk so
1943
+ // we can detect brand-new files in dropped-language extensions — a gap that
1944
+ // the orchestrator's `detect_removed_files` filter (#1070) leaves open
1945
+ // (#1083, #1091). The pre-check is cheap because the expensive part (WASM
1946
+ // re-parse of the missing set) is gated below.
1947
+ const gapDetectStart = performance.now();
1948
+ const gap = detectDroppedLanguageGap(ctx);
1949
+ const backfillHappened = gap.missingAbs.length > 0 || gap.staleRel.length > 0;
1950
+ if (backfillHappened) {
1951
+ await backfillNativeDroppedFiles(ctx, gap);
1952
+ }
1953
+ const gapDetectMs = performance.now() - gapDetectStart;
1954
+
1955
+ // Phase 8.5: this/super dispatch — hybrid WASM re-parse to resolve call sites
1956
+ // whose raw receiver info the Rust pipeline does not persist to DB.
1957
+ // Runs BEFORE the CHA expansion pass so that super.method() → Parent.method edges
1958
+ // (technique='cha') are in the DB when runPostNativeCha expands them to sibling
1959
+ // class overrides (e.g. PostMixin.m → B.m when PostMixin and B both extend A).
1960
+ const {
1961
+ elapsedMs: thisDispatchMs,
1962
+ targetIds: thisDispatchTargetIds,
1963
+ affectedFiles: thisDispatchAffectedFiles,
1964
+ } = await runPostNativeThisDispatch(
1965
+ ctx.db as unknown as BetterSqlite3Database,
1966
+ ctx.rootDir,
1967
+ result.changedFiles,
1968
+ !!result.isFullBuild,
1969
+ );
1970
+
1971
+ // Phase 8.6: expand CHA call edges (interface dispatch → concrete implementations).
1972
+ // Returns the affected files so role re-classification below can be scoped to
1973
+ // the nodes whose fan-in/out actually changed.
1974
+ //
1975
+ // Runs AFTER this/super dispatch so super.method() edges are already in the DB.
1976
+ // The 'cha-expanded' technique tag on this pass's own output prevents re-expansion
1977
+ // of those edges in subsequent incremental builds, while 'cha'-tagged edges from
1978
+ // this/super dispatch remain eligible for expansion here.
1979
+ //
1980
+ // Function-as-object-property methods (`fn.method = function() {}`) are extracted
1981
+ // natively by the Rust engine (#1432) and resolved in-build by its edge builder, so
1982
+ // no WASM re-parse post-pass is needed for them. `Foo.prototype.bar = fn` likewise.
1983
+ const chaStart = performance.now();
1984
+ const { newEdgeCount: chaEdgeCount, affectedFiles: chaAffectedFiles } = runPostNativeCha(
1985
+ ctx.db as unknown as BetterSqlite3Database,
1986
+ // null = full build (scan all call→method edges); array = incremental (gate queries decide scope)
1987
+ result.isFullBuild ? null : (result.changedFiles ?? null),
1988
+ );
1989
+ const chaMs = performance.now() - chaStart;
1990
+
1991
+ // Role re-classification after JS edge-writing post-passes.
1992
+ // The Rust orchestrator classifies roles before these post-passes (CHA,
1993
+ // this-dispatch) add edges, so roles for the edge endpoints are stale.
1994
+ // Scoped to the files containing those endpoints: a new edge only changes
1995
+ // fan-in/out for its own source and target nodes, so re-classifying their
1996
+ // files restores correctness without re-running the classifier over the
1997
+ // whole graph (which cost ~130ms per build on codegraph itself and was a
1998
+ // major part of the v3.12.0 native full-build benchmark regression).
1999
+ let reclassifyMs = 0;
2000
+ if (chaEdgeCount > 0 || thisDispatchTargetIds.size > 0) {
2001
+ const affectedFiles = [...new Set([...chaAffectedFiles, ...thisDispatchAffectedFiles])];
2002
+ // When edges were inserted but all their endpoint nodes have null `file`
2003
+ // columns (rare but possible), affectedFiles stays empty even though
2004
+ // fan-in/out changed. Fall back to full-graph re-classification in that
2005
+ // case — scoped classification with an empty set would be a no-op, leaving
2006
+ // roles stale for those nodes.
2007
+ const scopedFiles = affectedFiles.length > 0 ? affectedFiles : null;
2008
+ const reclassifyStart = performance.now();
2009
+ try {
2010
+ const { classifyNodeRoles } = (await import('../../../../features/structure.js')) as {
2011
+ classifyNodeRoles: (
2012
+ db: BetterSqlite3Database,
2013
+ changedFiles?: string[] | null,
2014
+ ) => Record<string, number>;
2015
+ };
2016
+ classifyNodeRoles(ctx.db as unknown as BetterSqlite3Database, scopedFiles);
2017
+ debug(
2018
+ scopedFiles
2019
+ ? `Post-pass role re-classification complete (${scopedFiles.length} file(s))`
2020
+ : 'Post-pass role re-classification complete (full graph — null-file endpoints)',
2021
+ );
2022
+ } catch (err) {
2023
+ debug(`Post-pass role re-classification failed: ${toErrorMessage(err)}`);
2024
+ }
2025
+ reclassifyMs = performance.now() - reclassifyStart;
2026
+ }
2027
+
2028
+ // Backfill the `technique` column on `calls` edges written by the Rust
2029
+ // orchestrator, which does not write the column. Runs after all edge-writing
2030
+ // phases (including the WASM dropped-language backfill, CHA post-pass, and
2031
+ // this/super dispatch) so every new edge in this build cycle gets a label.
2032
+ const techniqueBackfillStart = performance.now();
2033
+ backfillEdgeTechniquesAfterNativeOrchestrator(ctx.db, !!result.isFullBuild, result.changedFiles);
2034
+ const techniqueBackfillMs = performance.now() - techniqueBackfillStart;
2035
+
2036
+ // Re-count nodes/edges now that all edge-writing post-passes have run: the
2037
+ // Rust orchestrator captured its counts before the JS post-passes added
2038
+ // edges, so both its summary and build_meta under-report (#1452).
2039
+ //
2040
+ // Fast path: skip the COUNT(*) scan when no post-pass wrote any edges.
2041
+ // COUNT(*) on large tables (50K+ edges) is non-trivial, especially via the
2042
+ // NativeDbProxy napi-rs round-trip. When all post-passes were no-ops, the
2043
+ // Rust orchestrator's counts are still accurate — no re-count needed.
2044
+ let finalNodeCount = result.nodeCount ?? 0;
2045
+ let finalEdgeCount = result.edgeCount ?? 0;
2046
+ const postPassWroteData = backfillHappened || chaEdgeCount > 0 || thisDispatchTargetIds.size > 0;
2047
+ if (postPassWroteData) {
2048
+ try {
2049
+ const counts = (ctx.db as unknown as BetterSqlite3Database)
2050
+ .prepare('SELECT (SELECT COUNT(*) FROM nodes) AS n, (SELECT COUNT(*) FROM edges) AS e')
2051
+ .get() as { n: number; e: number };
2052
+ if (counts.n !== finalNodeCount || counts.e !== finalEdgeCount) {
2053
+ finalNodeCount = counts.n;
2054
+ finalEdgeCount = counts.e;
2055
+ setBuildMeta(ctx.db, { node_count: finalNodeCount, edge_count: finalEdgeCount });
2056
+ }
2057
+ } catch (err) {
2058
+ debug(`Post-pass node/edge re-count failed: ${toErrorMessage(err)}`);
2059
+ }
2060
+ }
2061
+ info(
2062
+ `Native build orchestrator completed: ${finalNodeCount} nodes, ${finalEdgeCount} edges, ${result.fileCount ?? 0} files`,
2063
+ );
2064
+
2065
+ return {
2066
+ gapDetectMs,
2067
+ chaMs,
2068
+ thisDispatchMs,
2069
+ reclassifyMs,
2070
+ techniqueBackfillMs,
2071
+ backfillHappened,
2072
+ };
2073
+ }
2074
+
2075
+ /**
2076
+ * Try the native build orchestrator.
2077
+ *
2078
+ * Returns:
2079
+ * - `BuildResult` on success (caller should return it directly).
2080
+ * - `'early-exit'` when the orchestrator detected no changes (caller should return undefined).
2081
+ * - `undefined` when native is unavailable or skipped (caller should fall through to the JS pipeline).
2082
+ *
2083
+ * Encapsulates the orchestrator-selection strategy: open `NativeDatabase`,
2084
+ * invoke `nativeDb.buildGraph()` (the Rust pipeline), and run post-native
2085
+ * structure + analysis fallbacks. Lives in its own file to keep the Rust
2086
+ * orchestrator entry point separated from the JS-side `buildGraph()` driver
2087
+ * in `pipeline.ts`.
2088
+ */
2089
+ export async function tryNativeOrchestrator(
2090
+ ctx: PipelineContext,
2091
+ ): Promise<BuildResult | undefined | 'early-exit'> {
2092
+ const skipReason = shouldSkipNativeOrchestrator(ctx);
2093
+ if (skipReason) {
2094
+ debug(`Skipping native orchestrator: ${skipReason}`);
2095
+ return undefined;
2096
+ }
2097
+
2098
+ openNativeDatabase(ctx);
2099
+
2100
+ if (!ctx.nativeDb?.buildGraph) return undefined;
2101
+
2102
+ const resultJson = ctx.nativeDb.buildGraph(
2103
+ ctx.rootDir,
2104
+ JSON.stringify(ctx.config),
2105
+ JSON.stringify(ctx.aliases),
2106
+ JSON.stringify(ctx.opts),
2107
+ );
2108
+ const result = JSON.parse(resultJson) as NativeOrchestratorResult;
2109
+
2110
+ if (result.earlyExit) {
2111
+ info('No changes detected');
2112
+ // Even on no-op rebuilds, dropped-language files added since the last
2113
+ // full build are still missing from `nodes`/`file_hashes` (#1083), and
2114
+ // WASM-only files deleted from disk leave stale rows behind (#1073).
2115
+ // The orchestrator's collect_files skipped them, so its earlyExit
2116
+ // doesn't imply DB consistency. Run the gap repair before returning.
2117
+ const gap = detectDroppedLanguageGap(ctx);
2118
+ if (gap.missingAbs.length > 0 || gap.staleRel.length > 0) {
2119
+ await backfillNativeDroppedFiles(ctx, gap);
2120
+ }
2121
+ closeDbPair({ db: ctx.db, nativeDb: ctx.nativeDb });
2122
+ return 'early-exit';
2123
+ }
2124
+
2125
+ // Log incremental status to match JS pipeline output
2126
+ const changed = result.changedCount ?? 0;
2127
+ const removed = result.removedCount ?? 0;
2128
+ if (!result.isFullBuild && (changed > 0 || removed > 0)) {
2129
+ info(`Incremental: ${changed} changed, ${removed} removed`);
2130
+ }
2131
+
2132
+ const p = result.phases;
2133
+
2134
+ // Sync build_meta so JS-side version/engine checks work on next build.
2135
+ // Use the binary's CARGO_PKG_VERSION (ctx.nativeBinaryVersion), not the
2136
+ // platform package.json version (ctx.engineVersion). The Rust side's
2137
+ // check_version_mismatch compares against CARGO_PKG_VERSION; writing
2138
+ // the package.json value would create a permanent mismatch whenever
2139
+ // the binary and platform package.json diverge — e.g., CI hot-swap
2140
+ // via ci-install-native.mjs (#1066) — forcing every subsequent build
2141
+ // to be a full rebuild.
2142
+ //
2143
+ // When the native addon doesn't expose engineVersion() (older addon),
2144
+ // fall back to CODEGRAPH_VERSION — same fallback used by both
2145
+ // checkEngineSchemaMismatch (read path) and persistBuildMetadata
2146
+ // (the JS-pipeline write path in finalize.ts). Using ctx.engineVersion
2147
+ // here would re-introduce the asymmetry this PR fixes for that case.
2148
+ const nativeVersionForMeta = ctx.nativeBinaryVersion || CODEGRAPH_VERSION;
2149
+ setBuildMeta(ctx.db, {
2150
+ engine: ctx.engineName,
2151
+ engine_version: nativeVersionForMeta,
2152
+ codegraph_version: nativeVersionForMeta,
2153
+ schema_version: String(ctx.schemaVersion),
2154
+ built_at: new Date().toISOString(),
2155
+ });
2156
+
2157
+ // The build summary is logged after the JS edge-writing post-passes below
2158
+ // (dropped-language backfill, CHA, this/super dispatch) so the reported
2159
+ // counts include their edges (#1452).
2160
+
2161
+ // ── Post-native structure + analysis ──────────────────────────────
2162
+ let analysisTiming = {
2163
+ astMs: +(p.astMs ?? 0),
2164
+ complexityMs: +(p.complexityMs ?? 0),
2165
+ cfgMs: +(p.cfgMs ?? 0),
2166
+ dataflowMs: +(p.dataflowMs ?? 0),
2167
+ };
2168
+ let structurePatchMs = 0;
2169
+ // Skip JS structure when the Rust pipeline's small-incremental fast path
2170
+ // already handled it. For full builds and large incrementals where Rust
2171
+ // skipped structure, we must run the JS fallback.
2172
+ const needsStructure = !result.structureHandled;
2173
+ // When the Rust addon doesn't include analysis persistence (older addon
2174
+ // version or analysis failed), fall back to JS-side analysis.
2175
+ const needsAnalysisFallback =
2176
+ !result.analysisComplete &&
2177
+ (ctx.opts.ast !== false ||
2178
+ ctx.opts.complexity !== false ||
2179
+ ctx.opts.cfg !== false ||
2180
+ ctx.opts.dataflow !== false);
2181
+
2182
+ // ── DB handoff ────────────────────────────────────────────────────────────
2183
+ // Ensure a proper better-sqlite3 connection is open before any post-pass that
2184
+ // writes edges (dropped-language backfill, CHA) and before structure/analysis.
2185
+ // When analysis fallback is needed the handoff already happened above; when
2186
+ // neither structure nor analysis is needed the proxy conversion is deferred to
2187
+ // here so CHA and technique-backfill can still write rows.
2188
+ if (needsStructure || needsAnalysisFallback) {
2189
+ if (needsAnalysisFallback && ctx.nativeFirstProxy) {
2190
+ closeNativeDb(ctx, 'pre-analysis-fallback');
2191
+ ctx.db = openDb(ctx.dbPath);
2192
+ ctx.nativeFirstProxy = false;
2193
+ } else if (!ctx.nativeFirstProxy && !handoffWalAfterNativeBuild(ctx)) {
2194
+ // DB reopen failed — return partial result (no post-pass phases completed)
2195
+ return formatNativeTimingResult(p, 0, analysisTiming, {
2196
+ gapDetectMs: 0,
2197
+ chaMs: 0,
2198
+ thisDispatchMs: 0,
2199
+ reclassifyMs: 0,
2200
+ techniqueBackfillMs: 0,
2201
+ });
2202
+ }
2203
+ }
2204
+
2205
+ const postPassTimings = await runPostNativePasses(ctx, result);
2206
+
2207
+ // ── Structure and analysis fallback (run after edge-writing so roles see full graph) ──
2208
+ // Reconstruct fileSymbols once for both structure and analysis to avoid two
2209
+ // expensive DB scans. The DB handoff above already ensured ctx.db is a proper
2210
+ // better-sqlite3 connection when either flag is set.
2211
+ if (needsStructure || needsAnalysisFallback) {
2212
+ const fileSymbols = reconstructFileSymbolsFromDb(ctx);
2213
+
2214
+ if (needsStructure) {
2215
+ structurePatchMs = await runPostNativeStructure(
2216
+ ctx,
2217
+ fileSymbols,
2218
+ !!result.isFullBuild,
2219
+ result.changedFiles,
2220
+ );
2221
+ }
2222
+
2223
+ if (needsAnalysisFallback) {
2224
+ analysisTiming = await runPostNativeAnalysis(ctx, fileSymbols, result.changedFiles);
2225
+ }
2226
+ }
2227
+
2228
+ // P6: Vertex extraction for the analysisComplete=true path.
2229
+ // When needsAnalysisFallback=false (the normal native case), runPostNativeAnalysis
2230
+ // was skipped, so buildDataflowEdges never ran and dataflow_vertices were never
2231
+ // populated. Re-run the Rust dataflow visitor per file (fast — no re-parse) to
2232
+ // get the DataflowResult, then build vertices and inter-procedural edges.
2233
+ // Languages where Rust has no dataflow rules are silently skipped; a WASM
2234
+ // fallback for those is tracked in issue #1614.
2235
+ if (ctx.opts.dataflow !== false && !needsAnalysisFallback) {
2236
+ await runDataflowVertexPass(ctx, result.changedFiles);
2237
+ }
2238
+
2239
+ closeDbPair({ db: ctx.db, nativeDb: ctx.nativeDb });
2240
+ return formatNativeTimingResult(p, structurePatchMs, analysisTiming, postPassTimings);
2241
+ }