@optave/codegraph 3.4.0 → 3.5.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 (453) hide show
  1. package/README.md +23 -22
  2. package/dist/ast-analysis/engine.d.ts.map +1 -1
  3. package/dist/ast-analysis/engine.js +3 -9
  4. package/dist/ast-analysis/engine.js.map +1 -1
  5. package/dist/ast-analysis/rules/javascript.d.ts.map +1 -1
  6. package/dist/ast-analysis/rules/javascript.js +1 -0
  7. package/dist/ast-analysis/rules/javascript.js.map +1 -1
  8. package/dist/ast-analysis/shared.d.ts.map +1 -1
  9. package/dist/ast-analysis/shared.js +0 -1
  10. package/dist/ast-analysis/shared.js.map +1 -1
  11. package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
  12. package/dist/ast-analysis/visitors/ast-store-visitor.js +103 -35
  13. package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
  14. package/dist/ast-analysis/visitors/cfg-conditionals.d.ts +5 -0
  15. package/dist/ast-analysis/visitors/cfg-conditionals.d.ts.map +1 -0
  16. package/dist/ast-analysis/visitors/cfg-conditionals.js +166 -0
  17. package/dist/ast-analysis/visitors/cfg-conditionals.js.map +1 -0
  18. package/dist/ast-analysis/visitors/cfg-loops.d.ts +7 -0
  19. package/dist/ast-analysis/visitors/cfg-loops.d.ts.map +1 -0
  20. package/dist/ast-analysis/visitors/cfg-loops.js +73 -0
  21. package/dist/ast-analysis/visitors/cfg-loops.js.map +1 -0
  22. package/dist/ast-analysis/visitors/cfg-shared.d.ts +56 -0
  23. package/dist/ast-analysis/visitors/cfg-shared.d.ts.map +1 -0
  24. package/dist/ast-analysis/visitors/cfg-shared.js +107 -0
  25. package/dist/ast-analysis/visitors/cfg-shared.js.map +1 -0
  26. package/dist/ast-analysis/visitors/cfg-try-catch.d.ts +4 -0
  27. package/dist/ast-analysis/visitors/cfg-try-catch.d.ts.map +1 -0
  28. package/dist/ast-analysis/visitors/cfg-try-catch.js +100 -0
  29. package/dist/ast-analysis/visitors/cfg-try-catch.js.map +1 -0
  30. package/dist/ast-analysis/visitors/cfg-visitor.d.ts +2 -2
  31. package/dist/ast-analysis/visitors/cfg-visitor.d.ts.map +1 -1
  32. package/dist/ast-analysis/visitors/cfg-visitor.js +11 -445
  33. package/dist/ast-analysis/visitors/cfg-visitor.js.map +1 -1
  34. package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
  35. package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
  36. package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
  37. package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
  38. package/dist/cli/commands/batch.d.ts.map +1 -1
  39. package/dist/cli/commands/batch.js +4 -3
  40. package/dist/cli/commands/batch.js.map +1 -1
  41. package/dist/cli/commands/branch-compare.js +1 -1
  42. package/dist/cli/commands/branch-compare.js.map +1 -1
  43. package/dist/cli/commands/build.js +1 -1
  44. package/dist/cli/commands/build.js.map +1 -1
  45. package/dist/cli/commands/info.d.ts.map +1 -1
  46. package/dist/cli/commands/info.js +1 -2
  47. package/dist/cli/commands/info.js.map +1 -1
  48. package/dist/cli/commands/path.d.ts.map +1 -1
  49. package/dist/cli/commands/path.js +7 -2
  50. package/dist/cli/commands/path.js.map +1 -1
  51. package/dist/cli/commands/plot.d.ts.map +1 -1
  52. package/dist/cli/commands/plot.js +2 -2
  53. package/dist/cli/commands/plot.js.map +1 -1
  54. package/dist/cli/commands/watch.js +1 -1
  55. package/dist/cli/commands/watch.js.map +1 -1
  56. package/dist/cli/index.js +2 -2
  57. package/dist/cli/index.js.map +1 -1
  58. package/dist/cli/shared/open-graph.d.ts +2 -2
  59. package/dist/cli/shared/open-graph.d.ts.map +1 -1
  60. package/dist/cli/shared/open-graph.js.map +1 -1
  61. package/dist/cli/types.d.ts +1 -1
  62. package/dist/cli/types.d.ts.map +1 -1
  63. package/dist/cli.js +2 -3
  64. package/dist/cli.js.map +1 -1
  65. package/dist/db/better-sqlite3.d.ts +3 -0
  66. package/dist/db/better-sqlite3.d.ts.map +1 -0
  67. package/dist/db/better-sqlite3.js +19 -0
  68. package/dist/db/better-sqlite3.js.map +1 -0
  69. package/dist/db/connection.d.ts +30 -2
  70. package/dist/db/connection.d.ts.map +1 -1
  71. package/dist/db/connection.js +167 -4
  72. package/dist/db/connection.js.map +1 -1
  73. package/dist/db/index.d.ts +2 -2
  74. package/dist/db/index.d.ts.map +1 -1
  75. package/dist/db/index.js +1 -1
  76. package/dist/db/index.js.map +1 -1
  77. package/dist/db/migrations.d.ts.map +1 -1
  78. package/dist/db/migrations.js +9 -0
  79. package/dist/db/migrations.js.map +1 -1
  80. package/dist/db/query-builder.d.ts +5 -5
  81. package/dist/db/query-builder.d.ts.map +1 -1
  82. package/dist/db/query-builder.js +20 -4
  83. package/dist/db/query-builder.js.map +1 -1
  84. package/dist/db/repository/index.d.ts +1 -0
  85. package/dist/db/repository/index.d.ts.map +1 -1
  86. package/dist/db/repository/index.js +1 -0
  87. package/dist/db/repository/index.js.map +1 -1
  88. package/dist/db/repository/native-repository.d.ts +58 -0
  89. package/dist/db/repository/native-repository.d.ts.map +1 -0
  90. package/dist/db/repository/native-repository.js +261 -0
  91. package/dist/db/repository/native-repository.js.map +1 -0
  92. package/dist/db/repository/nodes.d.ts +4 -4
  93. package/dist/db/repository/nodes.d.ts.map +1 -1
  94. package/dist/db/repository/nodes.js +6 -6
  95. package/dist/db/repository/nodes.js.map +1 -1
  96. package/dist/domain/analysis/brief.d.ts.map +1 -1
  97. package/dist/domain/analysis/brief.js +1 -3
  98. package/dist/domain/analysis/brief.js.map +1 -1
  99. package/dist/domain/analysis/context.d.ts.map +1 -1
  100. package/dist/domain/analysis/context.js +2 -4
  101. package/dist/domain/analysis/context.js.map +1 -1
  102. package/dist/domain/analysis/dependencies.d.ts +49 -0
  103. package/dist/domain/analysis/dependencies.d.ts.map +1 -1
  104. package/dist/domain/analysis/dependencies.js +145 -0
  105. package/dist/domain/analysis/dependencies.js.map +1 -1
  106. package/dist/domain/analysis/diff-impact.d.ts +76 -0
  107. package/dist/domain/analysis/diff-impact.d.ts.map +1 -0
  108. package/dist/domain/analysis/diff-impact.js +282 -0
  109. package/dist/domain/analysis/diff-impact.js.map +1 -0
  110. package/dist/domain/analysis/exports.d.ts.map +1 -1
  111. package/dist/domain/analysis/exports.js +0 -1
  112. package/dist/domain/analysis/exports.js.map +1 -1
  113. package/dist/domain/analysis/fn-impact.d.ts +66 -0
  114. package/dist/domain/analysis/fn-impact.d.ts.map +1 -0
  115. package/dist/domain/analysis/fn-impact.js +189 -0
  116. package/dist/domain/analysis/fn-impact.js.map +1 -0
  117. package/dist/domain/analysis/impact.d.ts +8 -148
  118. package/dist/domain/analysis/impact.d.ts.map +1 -1
  119. package/dist/domain/analysis/impact.js +8 -568
  120. package/dist/domain/analysis/impact.js.map +1 -1
  121. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  122. package/dist/domain/analysis/module-map.js +1 -3
  123. package/dist/domain/analysis/module-map.js.map +1 -1
  124. package/dist/domain/graph/builder/context.d.ts +3 -3
  125. package/dist/domain/graph/builder/context.d.ts.map +1 -1
  126. package/dist/domain/graph/builder/context.js +1 -0
  127. package/dist/domain/graph/builder/context.js.map +1 -1
  128. package/dist/domain/graph/builder/helpers.d.ts +4 -5
  129. package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
  130. package/dist/domain/graph/builder/helpers.js +1 -2
  131. package/dist/domain/graph/builder/helpers.js.map +1 -1
  132. package/dist/domain/graph/builder/incremental.d.ts +2 -3
  133. package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
  134. package/dist/domain/graph/builder/incremental.js.map +1 -1
  135. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  136. package/dist/domain/graph/builder/pipeline.js +34 -6
  137. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  138. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  139. package/dist/domain/graph/builder/stages/build-edges.js +113 -15
  140. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  141. package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
  142. package/dist/domain/graph/builder/stages/build-structure.js +186 -62
  143. package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
  144. package/dist/domain/graph/builder/stages/collect-files.d.ts.map +1 -1
  145. package/dist/domain/graph/builder/stages/collect-files.js +71 -7
  146. package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
  147. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  148. package/dist/domain/graph/builder/stages/detect-changes.js +42 -20
  149. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  150. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
  151. package/dist/domain/graph/builder/stages/finalize.js +111 -64
  152. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  153. package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
  154. package/dist/domain/graph/builder/stages/insert-nodes.js +104 -9
  155. package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
  156. package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
  157. package/dist/domain/graph/builder/stages/resolve-imports.js +58 -11
  158. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  159. package/dist/domain/graph/cycles.js +2 -2
  160. package/dist/domain/graph/cycles.js.map +1 -1
  161. package/dist/domain/graph/resolve.d.ts.map +1 -1
  162. package/dist/domain/graph/resolve.js +10 -8
  163. package/dist/domain/graph/resolve.js.map +1 -1
  164. package/dist/domain/graph/watcher.d.ts.map +1 -1
  165. package/dist/domain/graph/watcher.js +1 -3
  166. package/dist/domain/graph/watcher.js.map +1 -1
  167. package/dist/domain/parser.d.ts.map +1 -1
  168. package/dist/domain/parser.js +12 -12
  169. package/dist/domain/parser.js.map +1 -1
  170. package/dist/domain/queries.d.ts +3 -2
  171. package/dist/domain/queries.d.ts.map +1 -1
  172. package/dist/domain/queries.js +3 -2
  173. package/dist/domain/queries.js.map +1 -1
  174. package/dist/domain/search/generator.d.ts.map +1 -1
  175. package/dist/domain/search/generator.js.map +1 -1
  176. package/dist/extractors/csharp.js +2 -2
  177. package/dist/extractors/csharp.js.map +1 -1
  178. package/dist/extractors/go.js +2 -2
  179. package/dist/extractors/go.js.map +1 -1
  180. package/dist/extractors/helpers.d.ts +5 -0
  181. package/dist/extractors/helpers.d.ts.map +1 -1
  182. package/dist/extractors/helpers.js +5 -0
  183. package/dist/extractors/helpers.js.map +1 -1
  184. package/dist/extractors/javascript.js +111 -98
  185. package/dist/extractors/javascript.js.map +1 -1
  186. package/dist/extractors/php.js +2 -2
  187. package/dist/extractors/php.js.map +1 -1
  188. package/dist/extractors/python.js +2 -2
  189. package/dist/extractors/python.js.map +1 -1
  190. package/dist/extractors/rust.js +4 -3
  191. package/dist/extractors/rust.js.map +1 -1
  192. package/dist/features/ast.d.ts +14 -1
  193. package/dist/features/ast.d.ts.map +1 -1
  194. package/dist/features/ast.js +38 -1
  195. package/dist/features/ast.js.map +1 -1
  196. package/dist/features/audit.d.ts.map +1 -1
  197. package/dist/features/audit.js +1 -2
  198. package/dist/features/audit.js.map +1 -1
  199. package/dist/features/branch-compare.d.ts.map +1 -1
  200. package/dist/features/branch-compare.js +5 -4
  201. package/dist/features/branch-compare.js.map +1 -1
  202. package/dist/features/cfg.d.ts.map +1 -1
  203. package/dist/features/cfg.js +2 -4
  204. package/dist/features/cfg.js.map +1 -1
  205. package/dist/features/cochange.js +4 -4
  206. package/dist/features/cochange.js.map +1 -1
  207. package/dist/features/communities.js +4 -4
  208. package/dist/features/communities.js.map +1 -1
  209. package/dist/features/complexity-query.d.ts +37 -0
  210. package/dist/features/complexity-query.d.ts.map +1 -0
  211. package/dist/features/complexity-query.js +263 -0
  212. package/dist/features/complexity-query.js.map +1 -0
  213. package/dist/features/complexity.d.ts +2 -30
  214. package/dist/features/complexity.d.ts.map +1 -1
  215. package/dist/features/complexity.js +7 -261
  216. package/dist/features/complexity.js.map +1 -1
  217. package/dist/features/dataflow.d.ts.map +1 -1
  218. package/dist/features/dataflow.js +8 -24
  219. package/dist/features/dataflow.js.map +1 -1
  220. package/dist/features/export.d.ts +7 -8
  221. package/dist/features/export.d.ts.map +1 -1
  222. package/dist/features/export.js.map +1 -1
  223. package/dist/features/flow.d.ts.map +1 -1
  224. package/dist/features/flow.js.map +1 -1
  225. package/dist/features/graph-enrichment.d.ts.map +1 -1
  226. package/dist/features/graph-enrichment.js +1 -3
  227. package/dist/features/graph-enrichment.js.map +1 -1
  228. package/dist/features/manifesto.js +8 -8
  229. package/dist/features/manifesto.js.map +1 -1
  230. package/dist/features/snapshot.js +2 -2
  231. package/dist/features/snapshot.js.map +1 -1
  232. package/dist/features/structure-query.d.ts +76 -0
  233. package/dist/features/structure-query.d.ts.map +1 -0
  234. package/dist/features/structure-query.js +245 -0
  235. package/dist/features/structure-query.js.map +1 -0
  236. package/dist/features/structure.d.ts +12 -67
  237. package/dist/features/structure.d.ts.map +1 -1
  238. package/dist/features/structure.js +188 -244
  239. package/dist/features/structure.js.map +1 -1
  240. package/dist/features/triage.js +2 -2
  241. package/dist/features/triage.js.map +1 -1
  242. package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
  243. package/dist/graph/algorithms/leiden/adapter.js +2 -9
  244. package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
  245. package/dist/graph/classifiers/roles.d.ts +5 -1
  246. package/dist/graph/classifiers/roles.d.ts.map +1 -1
  247. package/dist/graph/classifiers/roles.js +20 -12
  248. package/dist/graph/classifiers/roles.js.map +1 -1
  249. package/dist/index.d.ts +1 -0
  250. package/dist/index.d.ts.map +1 -1
  251. package/dist/index.js.map +1 -1
  252. package/dist/infrastructure/config.d.ts.map +1 -1
  253. package/dist/infrastructure/config.js +12 -11
  254. package/dist/infrastructure/config.js.map +1 -1
  255. package/dist/infrastructure/native.d.ts.map +1 -1
  256. package/dist/infrastructure/native.js +7 -3
  257. package/dist/infrastructure/native.js.map +1 -1
  258. package/dist/infrastructure/registry.d.ts.map +1 -1
  259. package/dist/infrastructure/registry.js +1 -1
  260. package/dist/infrastructure/registry.js.map +1 -1
  261. package/dist/infrastructure/update-check.js +3 -3
  262. package/dist/infrastructure/update-check.js.map +1 -1
  263. package/dist/mcp/server.d.ts.map +1 -1
  264. package/dist/mcp/server.js +4 -17
  265. package/dist/mcp/server.js.map +1 -1
  266. package/dist/mcp/tool-registry.d.ts.map +1 -1
  267. package/dist/mcp/tool-registry.js +9 -4
  268. package/dist/mcp/tool-registry.js.map +1 -1
  269. package/dist/mcp/tools/audit.js +1 -1
  270. package/dist/mcp/tools/audit.js.map +1 -1
  271. package/dist/mcp/tools/cfg.js +1 -1
  272. package/dist/mcp/tools/cfg.js.map +1 -1
  273. package/dist/mcp/tools/check.js +2 -2
  274. package/dist/mcp/tools/check.js.map +1 -1
  275. package/dist/mcp/tools/dataflow.js +2 -2
  276. package/dist/mcp/tools/dataflow.js.map +1 -1
  277. package/dist/mcp/tools/export-graph.js +1 -1
  278. package/dist/mcp/tools/export-graph.js.map +1 -1
  279. package/dist/mcp/tools/index.d.ts.map +1 -1
  280. package/dist/mcp/tools/index.js.map +1 -1
  281. package/dist/mcp/tools/path.d.ts +1 -0
  282. package/dist/mcp/tools/path.d.ts.map +1 -1
  283. package/dist/mcp/tools/path.js +9 -0
  284. package/dist/mcp/tools/path.js.map +1 -1
  285. package/dist/mcp/tools/query.js +1 -1
  286. package/dist/mcp/tools/query.js.map +1 -1
  287. package/dist/mcp/tools/semantic-search.js +1 -1
  288. package/dist/mcp/tools/semantic-search.js.map +1 -1
  289. package/dist/mcp/tools/sequence.js +1 -1
  290. package/dist/mcp/tools/sequence.js.map +1 -1
  291. package/dist/mcp/tools/symbol-children.js +1 -1
  292. package/dist/mcp/tools/symbol-children.js.map +1 -1
  293. package/dist/mcp/tools/triage.js +1 -1
  294. package/dist/mcp/tools/triage.js.map +1 -1
  295. package/dist/presentation/audit.d.ts.map +1 -1
  296. package/dist/presentation/audit.js +0 -1
  297. package/dist/presentation/audit.js.map +1 -1
  298. package/dist/presentation/diff-impact-mermaid.d.ts +11 -0
  299. package/dist/presentation/diff-impact-mermaid.d.ts.map +1 -0
  300. package/dist/presentation/diff-impact-mermaid.js +105 -0
  301. package/dist/presentation/diff-impact-mermaid.js.map +1 -0
  302. package/dist/presentation/flow.d.ts.map +1 -1
  303. package/dist/presentation/flow.js +0 -2
  304. package/dist/presentation/flow.js.map +1 -1
  305. package/dist/presentation/manifesto.d.ts.map +1 -1
  306. package/dist/presentation/manifesto.js +0 -1
  307. package/dist/presentation/manifesto.js.map +1 -1
  308. package/dist/presentation/queries-cli/inspect.d.ts.map +1 -1
  309. package/dist/presentation/queries-cli/inspect.js.map +1 -1
  310. package/dist/presentation/queries-cli/path.d.ts.map +1 -1
  311. package/dist/presentation/queries-cli/path.js +45 -1
  312. package/dist/presentation/queries-cli/path.js.map +1 -1
  313. package/dist/presentation/result-formatter.d.ts.map +1 -1
  314. package/dist/presentation/result-formatter.js +1 -3
  315. package/dist/presentation/result-formatter.js.map +1 -1
  316. package/dist/presentation/sequence.d.ts.map +1 -1
  317. package/dist/presentation/sequence.js +0 -1
  318. package/dist/presentation/sequence.js.map +1 -1
  319. package/dist/presentation/structure.d.ts.map +1 -1
  320. package/dist/presentation/structure.js.map +1 -1
  321. package/dist/presentation/triage.d.ts.map +1 -1
  322. package/dist/presentation/triage.js +0 -1
  323. package/dist/presentation/triage.js.map +1 -1
  324. package/dist/shared/constants.d.ts +9 -3
  325. package/dist/shared/constants.d.ts.map +1 -1
  326. package/dist/shared/constants.js +6 -3
  327. package/dist/shared/constants.js.map +1 -1
  328. package/dist/shared/errors.d.ts +2 -0
  329. package/dist/shared/errors.d.ts.map +1 -1
  330. package/dist/shared/errors.js +4 -0
  331. package/dist/shared/errors.js.map +1 -1
  332. package/dist/shared/version.d.ts +2 -0
  333. package/dist/shared/version.d.ts.map +1 -0
  334. package/dist/shared/version.js +5 -0
  335. package/dist/shared/version.js.map +1 -0
  336. package/dist/types.d.ts +230 -2
  337. package/dist/types.d.ts.map +1 -1
  338. package/package.json +62 -11
  339. package/src/ast-analysis/engine.ts +3 -9
  340. package/src/ast-analysis/rules/javascript.ts +1 -0
  341. package/src/ast-analysis/shared.ts +0 -1
  342. package/src/ast-analysis/visitors/ast-store-visitor.ts +102 -33
  343. package/src/ast-analysis/visitors/cfg-conditionals.ts +227 -0
  344. package/src/ast-analysis/visitors/cfg-loops.ts +136 -0
  345. package/src/ast-analysis/visitors/cfg-shared.ts +196 -0
  346. package/src/ast-analysis/visitors/cfg-try-catch.ts +142 -0
  347. package/src/ast-analysis/visitors/cfg-visitor.ts +34 -655
  348. package/src/ast-analysis/visitors/complexity-visitor.ts +0 -1
  349. package/src/ast-analysis/visitors/dataflow-visitor.ts +0 -1
  350. package/src/cli/commands/batch.ts +4 -3
  351. package/src/cli/commands/branch-compare.ts +1 -1
  352. package/src/cli/commands/build.ts +1 -1
  353. package/src/cli/commands/info.ts +1 -2
  354. package/src/cli/commands/path.ts +7 -2
  355. package/src/cli/commands/plot.ts +2 -2
  356. package/src/cli/commands/watch.ts +1 -1
  357. package/src/cli/index.ts +2 -2
  358. package/src/cli/shared/open-graph.ts +2 -2
  359. package/src/cli/types.ts +1 -1
  360. package/src/cli.ts +2 -3
  361. package/src/db/better-sqlite3.ts +20 -0
  362. package/src/db/connection.ts +191 -16
  363. package/src/db/index.ts +5 -1
  364. package/src/db/migrations.ts +9 -0
  365. package/src/db/query-builder.ts +30 -5
  366. package/src/db/repository/index.ts +1 -0
  367. package/src/db/repository/native-repository.ts +361 -0
  368. package/src/db/repository/nodes.ts +7 -3
  369. package/src/domain/analysis/brief.ts +0 -1
  370. package/src/domain/analysis/context.ts +2 -6
  371. package/src/domain/analysis/dependencies.ts +165 -0
  372. package/src/domain/analysis/diff-impact.ts +354 -0
  373. package/src/domain/analysis/exports.ts +0 -2
  374. package/src/domain/analysis/fn-impact.ts +241 -0
  375. package/src/domain/analysis/impact.ts +8 -718
  376. package/src/domain/analysis/module-map.ts +1 -5
  377. package/src/domain/graph/builder/context.ts +4 -2
  378. package/src/domain/graph/builder/helpers.ts +14 -11
  379. package/src/domain/graph/builder/incremental.ts +33 -28
  380. package/src/domain/graph/builder/pipeline.ts +37 -5
  381. package/src/domain/graph/builder/stages/build-edges.ts +131 -20
  382. package/src/domain/graph/builder/stages/build-structure.ts +245 -80
  383. package/src/domain/graph/builder/stages/collect-files.ts +84 -7
  384. package/src/domain/graph/builder/stages/detect-changes.ts +49 -32
  385. package/src/domain/graph/builder/stages/finalize.ts +132 -84
  386. package/src/domain/graph/builder/stages/insert-nodes.ts +141 -18
  387. package/src/domain/graph/builder/stages/resolve-imports.ts +75 -10
  388. package/src/domain/graph/cycles.ts +2 -2
  389. package/src/domain/graph/resolve.ts +14 -8
  390. package/src/domain/graph/watcher.ts +2 -4
  391. package/src/domain/parser.ts +12 -13
  392. package/src/domain/queries.ts +2 -2
  393. package/src/domain/search/generator.ts +3 -4
  394. package/src/extractors/csharp.ts +2 -2
  395. package/src/extractors/go.ts +2 -2
  396. package/src/extractors/helpers.ts +6 -0
  397. package/src/extractors/javascript.ts +112 -97
  398. package/src/extractors/php.ts +2 -2
  399. package/src/extractors/python.ts +2 -2
  400. package/src/extractors/rust.ts +4 -3
  401. package/src/features/ast.ts +66 -1
  402. package/src/features/audit.ts +1 -2
  403. package/src/features/branch-compare.ts +6 -10
  404. package/src/features/cfg.ts +2 -4
  405. package/src/features/cochange.ts +4 -4
  406. package/src/features/communities.ts +4 -4
  407. package/src/features/complexity-query.ts +370 -0
  408. package/src/features/complexity.ts +6 -365
  409. package/src/features/dataflow.ts +48 -70
  410. package/src/features/export.ts +12 -16
  411. package/src/features/flow.ts +0 -1
  412. package/src/features/graph-enrichment.ts +1 -3
  413. package/src/features/manifesto.ts +8 -8
  414. package/src/features/snapshot.ts +3 -3
  415. package/src/features/structure-query.ts +387 -0
  416. package/src/features/structure.ts +231 -376
  417. package/src/features/triage.ts +2 -2
  418. package/src/graph/algorithms/leiden/adapter.ts +2 -9
  419. package/src/graph/classifiers/roles.ts +22 -13
  420. package/src/index.ts +1 -0
  421. package/src/infrastructure/config.ts +12 -13
  422. package/src/infrastructure/native.ts +7 -3
  423. package/src/infrastructure/registry.ts +1 -1
  424. package/src/infrastructure/update-check.ts +3 -3
  425. package/src/mcp/server.ts +4 -20
  426. package/src/mcp/tool-registry.ts +11 -4
  427. package/src/mcp/tools/audit.ts +1 -1
  428. package/src/mcp/tools/cfg.ts +1 -1
  429. package/src/mcp/tools/check.ts +2 -2
  430. package/src/mcp/tools/dataflow.ts +2 -2
  431. package/src/mcp/tools/export-graph.ts +1 -1
  432. package/src/mcp/tools/index.ts +0 -1
  433. package/src/mcp/tools/path.ts +10 -0
  434. package/src/mcp/tools/query.ts +1 -1
  435. package/src/mcp/tools/semantic-search.ts +1 -1
  436. package/src/mcp/tools/sequence.ts +1 -1
  437. package/src/mcp/tools/symbol-children.ts +1 -1
  438. package/src/mcp/tools/triage.ts +1 -1
  439. package/src/presentation/audit.ts +0 -1
  440. package/src/presentation/diff-impact-mermaid.ts +127 -0
  441. package/src/presentation/flow.ts +0 -2
  442. package/src/presentation/manifesto.ts +0 -1
  443. package/src/presentation/queries-cli/inspect.ts +0 -1
  444. package/src/presentation/queries-cli/path.ts +71 -1
  445. package/src/presentation/result-formatter.ts +0 -1
  446. package/src/presentation/sequence.ts +0 -1
  447. package/src/presentation/structure.ts +0 -12
  448. package/src/presentation/triage.ts +0 -1
  449. package/src/shared/constants.ts +33 -19
  450. package/src/shared/errors.ts +5 -0
  451. package/src/shared/version.ts +10 -0
  452. package/src/types.ts +277 -10
  453. package/src/vendor.d.ts +0 -39
@@ -380,11 +380,7 @@ export function moduleMapData(customDbPath: string, limit = 20, opts: { noTests?
380
380
  }
381
381
  }
382
382
 
383
- export function statsData(
384
- customDbPath: string,
385
- // biome-ignore lint/suspicious/noExplicitAny: config shape is dynamic
386
- opts: { noTests?: boolean; config?: any } = {},
387
- ) {
383
+ export function statsData(customDbPath: string, opts: { noTests?: boolean; config?: any } = {}) {
388
384
  const db = openReadonlyOrFail(customDbPath);
389
385
  try {
390
386
  const noTests = opts.noTests || false;
@@ -4,14 +4,15 @@
4
4
  * Each stage reads what it needs and writes what it produces.
5
5
  * This replaces the closure-captured locals in the old monolithic buildGraph().
6
6
  */
7
- import type BetterSqlite3 from 'better-sqlite3';
8
7
  import type {
8
+ BetterSqlite3Database,
9
9
  BuildGraphOpts,
10
10
  CodegraphConfig,
11
11
  EngineOpts,
12
12
  ExtractorOutput,
13
13
  FileToParse,
14
14
  MetadataUpdate,
15
+ NativeDatabase,
15
16
  NodeRow,
16
17
  ParseChange,
17
18
  PathAliases,
@@ -20,7 +21,7 @@ import type {
20
21
  export class PipelineContext {
21
22
  // ── Inputs (set during setup) ──────────────────────────────────────
22
23
  rootDir!: string;
23
- db!: BetterSqlite3.Database;
24
+ db!: BetterSqlite3Database;
24
25
  dbPath!: string;
25
26
  config!: CodegraphConfig;
26
27
  opts!: BuildGraphOpts;
@@ -31,6 +32,7 @@ export class PipelineContext {
31
32
  incremental!: boolean;
32
33
  forceFullRebuild: boolean = false;
33
34
  schemaVersion!: number;
35
+ nativeDb?: NativeDatabase;
34
36
 
35
37
  // ── File collection (set by collectFiles stage) ────────────────────
36
38
  allFiles!: string[];
@@ -6,11 +6,15 @@
6
6
  import { createHash } from 'node:crypto';
7
7
  import fs from 'node:fs';
8
8
  import path from 'node:path';
9
- import type BetterSqlite3 from 'better-sqlite3';
10
9
  import { purgeFilesData } from '../../../db/index.js';
11
10
  import { warn } from '../../../infrastructure/logger.js';
12
11
  import { EXTENSIONS, IGNORE_DIRS } from '../../../shared/constants.js';
13
- import type { BetterSqlite3Database, CodegraphConfig, PathAliases } from '../../../types.js';
12
+ import type {
13
+ BetterSqlite3Database,
14
+ CodegraphConfig,
15
+ PathAliases,
16
+ SqliteStatement,
17
+ } from '../../../types.js';
14
18
 
15
19
  export const BUILTIN_RECEIVERS: Set<string> = new Set([
16
20
  'console',
@@ -132,8 +136,7 @@ export function loadPathAliases(rootDir: string): PathAliases {
132
136
  try {
133
137
  const raw = fs
134
138
  .readFileSync(configPath, 'utf-8')
135
- .replace(/\/\/.*$/gm, '')
136
- .replace(/\/\*[\s\S]*?\*\//g, '')
139
+ .replace(/("(?:[^"\\]|\\.)*")|\/\*[\s\S]*?\*\/|\/\/.*$/gm, (_, str) => str ?? '')
137
140
  .replace(/,\s*([\]}])/g, '$1');
138
141
  const config = JSON.parse(raw) as {
139
142
  compilerOptions?: { baseUrl?: string; paths?: Record<string, string[]> };
@@ -199,7 +202,7 @@ export function readFileSafe(filePath: string, retries: number = 2): string {
199
202
  * Purge all graph data for the specified files.
200
203
  */
201
204
  export function purgeFilesFromGraph(
202
- db: BetterSqlite3.Database,
205
+ db: BetterSqlite3Database,
203
206
  files: string[],
204
207
  options: Record<string, unknown> = {},
205
208
  ): void {
@@ -211,10 +214,10 @@ export function purgeFilesFromGraph(
211
214
  const BATCH_CHUNK = 500;
212
215
 
213
216
  // Statement caches keyed by chunk size — avoids recompiling for every batch.
214
- const nodeStmtCache = new WeakMap<BetterSqlite3.Database, Map<number, BetterSqlite3.Statement>>();
215
- const edgeStmtCache = new WeakMap<BetterSqlite3.Database, Map<number, BetterSqlite3.Statement>>();
217
+ const nodeStmtCache = new WeakMap<BetterSqlite3Database, Map<number, SqliteStatement>>();
218
+ const edgeStmtCache = new WeakMap<BetterSqlite3Database, Map<number, SqliteStatement>>();
216
219
 
217
- function getNodeStmt(db: BetterSqlite3.Database, chunkSize: number): BetterSqlite3.Statement {
220
+ function getNodeStmt(db: BetterSqlite3Database, chunkSize: number): SqliteStatement {
218
221
  let cache = nodeStmtCache.get(db);
219
222
  if (!cache) {
220
223
  cache = new Map();
@@ -232,7 +235,7 @@ function getNodeStmt(db: BetterSqlite3.Database, chunkSize: number): BetterSqlit
232
235
  return stmt;
233
236
  }
234
237
 
235
- function getEdgeStmt(db: BetterSqlite3.Database, chunkSize: number): BetterSqlite3.Statement {
238
+ function getEdgeStmt(db: BetterSqlite3Database, chunkSize: number): SqliteStatement {
236
239
  let cache = edgeStmtCache.get(db);
237
240
  if (!cache) {
238
241
  cache = new Map();
@@ -254,7 +257,7 @@ function getEdgeStmt(db: BetterSqlite3.Database, chunkSize: number): BetterSqlit
254
257
  * Batch-insert node rows via multi-value INSERT statements.
255
258
  * Each row: [name, kind, file, line, end_line, parent_id, qualified_name, scope, visibility]
256
259
  */
257
- export function batchInsertNodes(db: BetterSqlite3.Database, rows: unknown[][]): void {
260
+ export function batchInsertNodes(db: BetterSqlite3Database, rows: unknown[][]): void {
258
261
  if (!rows.length) return;
259
262
  for (let i = 0; i < rows.length; i += BATCH_CHUNK) {
260
263
  const end = Math.min(i + BATCH_CHUNK, rows.length);
@@ -273,7 +276,7 @@ export function batchInsertNodes(db: BetterSqlite3.Database, rows: unknown[][]):
273
276
  * Batch-insert edge rows via multi-value INSERT statements.
274
277
  * Each row: [source_id, target_id, kind, confidence, dynamic]
275
278
  */
276
- export function batchInsertEdges(db: BetterSqlite3.Database, rows: unknown[][]): void {
279
+ export function batchInsertEdges(db: BetterSqlite3Database, rows: unknown[][]): void {
277
280
  if (!rows.length) return;
278
281
  for (let i = 0; i < rows.length; i += BATCH_CHUNK) {
279
282
  const end = Math.min(i + BATCH_CHUNK, rows.length);
@@ -9,11 +9,16 @@
9
9
  */
10
10
  import fs from 'node:fs';
11
11
  import path from 'node:path';
12
- import type BetterSqlite3 from 'better-sqlite3';
13
12
  import { bulkNodeIdsByFile } from '../../../db/index.js';
14
13
  import { warn } from '../../../infrastructure/logger.js';
15
14
  import { normalizePath } from '../../../shared/constants.js';
16
- import type { EngineOpts, ExtractorOutput, PathAliases } from '../../../types.js';
15
+ import type {
16
+ BetterSqlite3Database,
17
+ EngineOpts,
18
+ ExtractorOutput,
19
+ PathAliases,
20
+ SqliteStatement,
21
+ } from '../../../types.js';
17
22
  import { parseFileIncremental } from '../../parser.js';
18
23
  import { computeConfidence, resolveImportPath } from '../resolve.js';
19
24
  import { BUILTIN_RECEIVERS, readFileSafe } from './helpers.js';
@@ -64,7 +69,7 @@ function insertFileNodes(stmts: IncrementalStmts, relPath: string, symbols: Extr
64
69
  // ── Containment edges ──────────────────────────────────────────────────
65
70
 
66
71
  function buildContainmentEdges(
67
- db: BetterSqlite3.Database,
72
+ db: BetterSqlite3Database,
68
73
  stmts: IncrementalStmts,
69
74
  relPath: string,
70
75
  symbols: ExtractorOutput,
@@ -101,13 +106,13 @@ function buildContainmentEdges(
101
106
  // ── Reverse-dep cascade ────────────────────────────────────────────────
102
107
 
103
108
  // Lazily-cached prepared statements for reverse-dep operations
104
- let _revDepDb: BetterSqlite3.Database | null = null;
105
- let _findRevDepsStmt: BetterSqlite3.Statement | null = null;
106
- let _deleteOutEdgesStmt: BetterSqlite3.Statement | null = null;
109
+ let _revDepDb: BetterSqlite3Database | null = null;
110
+ let _findRevDepsStmt: SqliteStatement | null = null;
111
+ let _deleteOutEdgesStmt: SqliteStatement | null = null;
107
112
 
108
- function getRevDepStmts(db: BetterSqlite3.Database): {
109
- findRevDepsStmt: BetterSqlite3.Statement;
110
- deleteOutEdgesStmt: BetterSqlite3.Statement;
113
+ function getRevDepStmts(db: BetterSqlite3Database): {
114
+ findRevDepsStmt: SqliteStatement;
115
+ deleteOutEdgesStmt: SqliteStatement;
111
116
  } {
112
117
  if (_revDepDb !== db) {
113
118
  _revDepDb = db;
@@ -127,12 +132,12 @@ function getRevDepStmts(db: BetterSqlite3.Database): {
127
132
  };
128
133
  }
129
134
 
130
- function findReverseDeps(db: BetterSqlite3.Database, relPath: string): string[] {
135
+ function findReverseDeps(db: BetterSqlite3Database, relPath: string): string[] {
131
136
  const { findRevDepsStmt } = getRevDepStmts(db);
132
137
  return (findRevDepsStmt.all(relPath, relPath) as Array<{ file: string }>).map((r) => r.file);
133
138
  }
134
139
 
135
- function deleteOutgoingEdges(db: BetterSqlite3.Database, relPath: string): void {
140
+ function deleteOutgoingEdges(db: BetterSqlite3Database, relPath: string): void {
136
141
  const { deleteOutEdgesStmt } = getRevDepStmts(db);
137
142
  deleteOutEdgesStmt.run(relPath);
138
143
  }
@@ -157,7 +162,7 @@ async function parseReverseDep(
157
162
  }
158
163
 
159
164
  function rebuildReverseDepEdges(
160
- db: BetterSqlite3.Database,
165
+ db: BetterSqlite3Database,
161
166
  rootDir: string,
162
167
  depRelPath: string,
163
168
  symbols: ExtractorOutput,
@@ -187,7 +192,7 @@ function rebuildReverseDepEdges(
187
192
  // ── Directory containment edges ────────────────────────────────────────
188
193
 
189
194
  function rebuildDirContainment(
190
- _db: BetterSqlite3.Database,
195
+ _db: BetterSqlite3Database,
191
196
  stmts: IncrementalStmts,
192
197
  relPath: string,
193
198
  ): number {
@@ -204,7 +209,7 @@ function rebuildDirContainment(
204
209
 
205
210
  // ── Ancillary table cleanup ────────────────────────────────────────────
206
211
 
207
- function purgeAncillaryData(db: BetterSqlite3.Database, relPath: string): void {
212
+ function purgeAncillaryData(db: BetterSqlite3Database, relPath: string): void {
208
213
  const tryExec = (sql: string, ...args: string[]): void => {
209
214
  try {
210
215
  db.prepare(sql).run(...args);
@@ -239,15 +244,15 @@ function purgeAncillaryData(db: BetterSqlite3.Database, relPath: string): void {
239
244
  // ── Import edge building ────────────────────────────────────────────────
240
245
 
241
246
  // Lazily-cached prepared statements for barrel resolution (avoid re-preparing in hot loops)
242
- let _barrelDb: BetterSqlite3.Database | null = null;
243
- let _isBarrelStmt: BetterSqlite3.Statement | null = null;
244
- let _reexportTargetsStmt: BetterSqlite3.Statement | null = null;
245
- let _hasDefStmt: BetterSqlite3.Statement | null = null;
246
-
247
- function getBarrelStmts(db: BetterSqlite3.Database): {
248
- isBarrelStmt: BetterSqlite3.Statement;
249
- reexportTargetsStmt: BetterSqlite3.Statement;
250
- hasDefStmt: BetterSqlite3.Statement;
247
+ let _barrelDb: BetterSqlite3Database | null = null;
248
+ let _isBarrelStmt: SqliteStatement | null = null;
249
+ let _reexportTargetsStmt: SqliteStatement | null = null;
250
+ let _hasDefStmt: SqliteStatement | null = null;
251
+
252
+ function getBarrelStmts(db: BetterSqlite3Database): {
253
+ isBarrelStmt: SqliteStatement;
254
+ reexportTargetsStmt: SqliteStatement;
255
+ hasDefStmt: SqliteStatement;
251
256
  } {
252
257
  if (_barrelDb !== db) {
253
258
  _barrelDb = db;
@@ -273,14 +278,14 @@ function getBarrelStmts(db: BetterSqlite3.Database): {
273
278
  };
274
279
  }
275
280
 
276
- function isBarrelFile(db: BetterSqlite3.Database, relPath: string): boolean {
281
+ function isBarrelFile(db: BetterSqlite3Database, relPath: string): boolean {
277
282
  const { isBarrelStmt } = getBarrelStmts(db);
278
283
  const reexportCount = (isBarrelStmt.get(relPath) as { c: number } | undefined)?.c;
279
284
  return (reexportCount || 0) > 0;
280
285
  }
281
286
 
282
287
  function resolveBarrelTarget(
283
- db: BetterSqlite3.Database,
288
+ db: BetterSqlite3Database,
284
289
  barrelPath: string,
285
290
  symbolName: string,
286
291
  visited: Set<string> = new Set(),
@@ -312,7 +317,7 @@ function resolveBarrelTarget(
312
317
  * Shared by buildImportEdges (primary file) and Pass 2 of the reverse-dep cascade.
313
318
  */
314
319
  function resolveBarrelImportEdges(
315
- db: BetterSqlite3.Database,
320
+ db: BetterSqlite3Database,
316
321
  stmts: IncrementalStmts,
317
322
  fileNodeId: number,
318
323
  resolvedPath: string,
@@ -344,7 +349,7 @@ function buildImportEdges(
344
349
  rootDir: string,
345
350
  fileNodeId: number,
346
351
  aliases: PathAliases,
347
- db: BetterSqlite3.Database | null,
352
+ db: BetterSqlite3Database | null,
348
353
  ): number {
349
354
  let edgesAdded = 0;
350
355
  for (const imp of symbols.imports) {
@@ -504,7 +509,7 @@ function buildCallEdges(
504
509
  * Parse a single file and update the database incrementally.
505
510
  */
506
511
  export async function rebuildFile(
507
- db: BetterSqlite3.Database,
512
+ db: BetterSqlite3Database,
508
513
  rootDir: string,
509
514
  filePath: string,
510
515
  stmts: IncrementalStmts,
@@ -6,9 +6,11 @@
6
6
  */
7
7
  import path from 'node:path';
8
8
  import { performance } from 'node:perf_hooks';
9
- import { closeDb, getBuildMeta, initSchema, MIGRATIONS, openDb } from '../../../db/index.js';
9
+ import { closeDbPair, getBuildMeta, initSchema, MIGRATIONS, openDb } from '../../../db/index.js';
10
10
  import { detectWorkspaces, loadConfig } from '../../../infrastructure/config.js';
11
11
  import { info, warn } from '../../../infrastructure/logger.js';
12
+ import { loadNative } from '../../../infrastructure/native.js';
13
+ import { CODEGRAPH_VERSION } from '../../../shared/version.js';
12
14
  import type { BuildGraphOpts, BuildResult } from '../../../types.js';
13
15
  import { getActiveEngine } from '../../parser.js';
14
16
  import { setWorkspaces } from '../resolve.js';
@@ -32,6 +34,7 @@ function initializeEngine(ctx: PipelineContext): void {
32
34
  engine: ctx.opts.engine || 'auto',
33
35
  dataflow: ctx.opts.dataflow !== false,
34
36
  ast: ctx.opts.ast !== false,
37
+ nativeDb: ctx.nativeDb,
35
38
  };
36
39
  const { name: engineName, version: engineVersion } = getActiveEngine(ctx.engineOpts);
37
40
  ctx.engineName = engineName as 'native' | 'wasm';
@@ -45,18 +48,29 @@ function checkEngineSchemaMismatch(ctx: PipelineContext): void {
45
48
  ctx.forceFullRebuild = false;
46
49
  if (!ctx.incremental) return;
47
50
 
48
- const prevEngine = getBuildMeta(ctx.db, 'engine');
51
+ // Route metadata reads through NativeDatabase when available (Phase 6.13)
52
+ const meta = (key: string): string | null =>
53
+ ctx.nativeDb ? ctx.nativeDb.getBuildMeta(key) : getBuildMeta(ctx.db, key);
54
+
55
+ const prevEngine = meta('engine');
49
56
  if (prevEngine && prevEngine !== ctx.engineName) {
50
57
  info(`Engine changed (${prevEngine} → ${ctx.engineName}), promoting to full rebuild.`);
51
58
  ctx.forceFullRebuild = true;
52
59
  }
53
- const prevSchema = getBuildMeta(ctx.db, 'schema_version');
60
+ const prevSchema = meta('schema_version');
54
61
  if (prevSchema && Number(prevSchema) !== ctx.schemaVersion) {
55
62
  info(
56
63
  `Schema version changed (${prevSchema} → ${ctx.schemaVersion}), promoting to full rebuild.`,
57
64
  );
58
65
  ctx.forceFullRebuild = true;
59
66
  }
67
+ const prevVersion = meta('codegraph_version');
68
+ if (prevVersion && prevVersion !== CODEGRAPH_VERSION) {
69
+ info(
70
+ `Codegraph version changed (${prevVersion} → ${CODEGRAPH_VERSION}), promoting to full rebuild.`,
71
+ );
72
+ ctx.forceFullRebuild = true;
73
+ }
60
74
  }
61
75
 
62
76
  function loadAliases(ctx: PipelineContext): void {
@@ -83,7 +97,23 @@ function setupPipeline(ctx: PipelineContext): void {
83
97
  ctx.rootDir = path.resolve(ctx.rootDir);
84
98
  ctx.dbPath = path.join(ctx.rootDir, '.codegraph', 'graph.db');
85
99
  ctx.db = openDb(ctx.dbPath);
86
- initSchema(ctx.db);
100
+
101
+ // Use NativeDatabase for schema init when native engine is available (Phase 6.13).
102
+ // better-sqlite3 (ctx.db) is still always opened — needed for queries and stages
103
+ // that haven't been migrated to rusqlite yet.
104
+ const native = loadNative();
105
+ if (native?.NativeDatabase) {
106
+ try {
107
+ ctx.nativeDb = native.NativeDatabase.openReadWrite(ctx.dbPath);
108
+ ctx.nativeDb.initSchema();
109
+ } catch (err) {
110
+ warn(`NativeDatabase init failed, falling back to JS: ${(err as Error).message}`);
111
+ ctx.nativeDb = undefined;
112
+ initSchema(ctx.db);
113
+ }
114
+ } else {
115
+ initSchema(ctx.db);
116
+ }
87
117
 
88
118
  ctx.config = loadConfig(ctx.rootDir);
89
119
  ctx.incremental =
@@ -160,7 +190,9 @@ export async function buildGraph(
160
190
  setupPipeline(ctx);
161
191
  await runPipelineStages(ctx);
162
192
  } catch (err) {
163
- if (!ctx.earlyExit && ctx.db) closeDb(ctx.db);
193
+ if (!ctx.earlyExit && ctx.db) {
194
+ closeDbPair({ db: ctx.db, nativeDb: ctx.nativeDb });
195
+ }
164
196
  throw err;
165
197
  }
166
198
 
@@ -6,19 +6,19 @@
6
6
  */
7
7
  import path from 'node:path';
8
8
  import { performance } from 'node:perf_hooks';
9
- import type BetterSqlite3 from 'better-sqlite3';
10
- import { getNodeId } from '../../../../db/index.js';
11
- import { loadNative } from '../../../../infrastructure/native.js';
9
+ import { getNodeId } from '#db/index.js';
10
+ import { debug } from '#infrastructure/logger.js';
11
+ import { loadNative } from '#infrastructure/native.js';
12
12
  import type {
13
+ BetterSqlite3Database,
13
14
  Call,
14
15
  ClassRelation,
15
- Definition,
16
16
  ExtractorOutput,
17
17
  Import,
18
18
  NativeAddon,
19
19
  NodeRow,
20
20
  TypeMapEntry,
21
- } from '../../../../types.js';
21
+ } from '#types';
22
22
  import { computeConfidence } from '../../resolve.js';
23
23
  import type { PipelineContext } from '../context.js';
24
24
  import { BUILTIN_RECEIVERS, batchInsertEdges } from '../helpers.js';
@@ -69,7 +69,7 @@ interface NormalizedTypeEntry {
69
69
 
70
70
  // ── Node lookup setup ───────────────────────────────────────────────────
71
71
 
72
- function makeGetNodeIdStmt(db: BetterSqlite3.Database): NodeIdStmt {
72
+ function makeGetNodeIdStmt(db: BetterSqlite3Database): NodeIdStmt {
73
73
  return {
74
74
  get: (name: string, kind: string, file: string, line: number) => {
75
75
  const id = getNodeId(db, name, kind, file, line);
@@ -102,12 +102,15 @@ function buildImportEdges(
102
102
  const { fileSymbols, barrelOnlyFiles, rootDir } = ctx;
103
103
 
104
104
  for (const [relPath, symbols] of fileSymbols) {
105
- if (barrelOnlyFiles.has(relPath)) continue;
105
+ const isBarrelOnly = barrelOnlyFiles.has(relPath);
106
106
  const fileNodeRow = getNodeIdStmt.get(relPath, 'file', relPath, 0);
107
107
  if (!fileNodeRow) continue;
108
108
  const fileNodeId = fileNodeRow.id;
109
109
 
110
110
  for (const imp of symbols.imports) {
111
+ // Barrel-only files: only emit reexport edges, skip regular imports
112
+ if (isBarrelOnly && !imp.reexport) continue;
113
+
111
114
  const resolvedPath = getResolved(ctx, path.join(rootDir, relPath), imp.source);
112
115
  const targetRow = getNodeIdStmt.get(resolvedPath, 'file', resolvedPath, 0);
113
116
  if (!targetRow) continue;
@@ -559,33 +562,141 @@ function buildClassHierarchyEdges(
559
562
 
560
563
  // ── Main entry point ────────────────────────────────────────────────────
561
564
 
565
+ /**
566
+ * For small incremental builds (≤5 changed files on a large codebase), scope
567
+ * the node loading query to only files that are relevant: changed files +
568
+ * their import targets. Falls back to loading ALL nodes for full builds or
569
+ * larger incremental changes.
570
+ */
571
+ function loadNodes(ctx: PipelineContext): { rows: QueryNodeRow[]; scoped: boolean } {
572
+ const { db, fileSymbols, isFullBuild, batchResolved } = ctx;
573
+ const nodeKindFilter = `kind IN ('function','method','class','interface','struct','type','module','enum','trait','record','constant')`;
574
+
575
+ // Gate: only scope for small incremental on large codebases
576
+ if (!isFullBuild && fileSymbols.size <= 5) {
577
+ const existingFileCount = (
578
+ db.prepare("SELECT COUNT(*) as c FROM nodes WHERE kind = 'file'").get() as { c: number }
579
+ ).c;
580
+ if (existingFileCount > 20) {
581
+ // Collect relevant files: changed files + their import targets
582
+ const relevantFiles = new Set<string>(fileSymbols.keys());
583
+ if (batchResolved) {
584
+ for (const resolvedPath of batchResolved.values()) {
585
+ relevantFiles.add(resolvedPath);
586
+ }
587
+ }
588
+ // Also add barrel-only files
589
+ for (const barrelPath of ctx.barrelOnlyFiles) {
590
+ relevantFiles.add(barrelPath);
591
+ }
592
+
593
+ const placeholders = [...relevantFiles].map(() => '?').join(',');
594
+ const rows = db
595
+ .prepare(
596
+ `SELECT id, name, kind, file, line FROM nodes WHERE ${nodeKindFilter} AND file IN (${placeholders})`,
597
+ )
598
+ .all(...relevantFiles) as QueryNodeRow[];
599
+ return { rows, scoped: true };
600
+ }
601
+ }
602
+
603
+ const rows = db
604
+ .prepare(`SELECT id, name, kind, file, line FROM nodes WHERE ${nodeKindFilter}`)
605
+ .all() as QueryNodeRow[];
606
+ return { rows, scoped: false };
607
+ }
608
+
609
+ /**
610
+ * For scoped node loading, patch nodesByName.get with a lazy SQL fallback
611
+ * so global name-only lookups (resolveByMethodOrGlobal, supplementReceiverEdges)
612
+ * can still find nodes outside the scoped set.
613
+ */
614
+ function addLazyFallback(ctx: PipelineContext, scopedLoad: boolean): void {
615
+ if (!scopedLoad) return;
616
+ const { db } = ctx;
617
+ const fallbackStmt = db.prepare(
618
+ `SELECT id, name, kind, file, line FROM nodes WHERE name = ? AND kind != 'file'`,
619
+ );
620
+ const originalGet = ctx.nodesByName.get.bind(ctx.nodesByName);
621
+ ctx.nodesByName.get = (name: string) => {
622
+ const result = originalGet(name);
623
+ if (result !== undefined) return result;
624
+ const rows = fallbackStmt.all(name) as unknown as NodeRow[];
625
+ if (rows.length > 0) {
626
+ ctx.nodesByName.set(name, rows);
627
+ return rows;
628
+ }
629
+ return undefined;
630
+ };
631
+ }
632
+
562
633
  export async function buildEdges(ctx: PipelineContext): Promise<void> {
563
634
  const { db, engineName } = ctx;
564
635
 
565
636
  const getNodeIdStmt = makeGetNodeIdStmt(db);
566
637
 
567
- const allNodes = db
568
- .prepare(
569
- `SELECT id, name, kind, file, line FROM nodes WHERE kind IN ('function','method','class','interface','struct','type','module','enum','trait','record','constant')`,
570
- )
571
- .all() as QueryNodeRow[];
572
- setupNodeLookups(ctx, allNodes);
638
+ const { rows: allNodesBefore, scoped: scopedLoad } = loadNodes(ctx);
639
+ setupNodeLookups(ctx, allNodesBefore);
640
+ addLazyFallback(ctx, scopedLoad);
573
641
 
574
642
  const t0 = performance.now();
575
- const buildEdgesTx = db.transaction(() => {
576
- const allEdgeRows: EdgeRowTuple[] = [];
643
+ const native = engineName === 'native' ? loadNative() : null;
644
+
645
+ // Phase 1: Compute edges inside a better-sqlite3 transaction.
646
+ // Barrel-edge deletion lives here so that the JS path (which also inserts
647
+ // edges in this transaction) keeps deletion + insertion atomic.
648
+ // When using the native rusqlite path, insertion happens in Phase 2 on a
649
+ // separate connection — a crash between Phase 1 and Phase 2 would leave
650
+ // barrel edges missing until the next incremental rebuild re-creates them.
651
+ const allEdgeRows: EdgeRowTuple[] = [];
652
+ const computeEdgesTx = db.transaction(() => {
653
+ if (ctx.barrelOnlyFiles.size > 0) {
654
+ const deleteOutgoingEdges = db.prepare(
655
+ 'DELETE FROM edges WHERE source_id IN (SELECT id FROM nodes WHERE file = ?)',
656
+ );
657
+ for (const relPath of ctx.barrelOnlyFiles) {
658
+ deleteOutgoingEdges.run(relPath);
659
+ }
660
+ }
577
661
 
578
662
  buildImportEdges(ctx, getNodeIdStmt, allEdgeRows);
579
663
 
580
- const native = engineName === 'native' ? loadNative() : null;
581
- if (native?.buildCallEdges) {
582
- buildCallEdgesNative(ctx, getNodeIdStmt, allEdgeRows, allNodes, native);
664
+ // Skip native call-edge path for small incremental builds (≤3 files):
665
+ // napi-rs marshaling overhead for allNodes exceeds computation savings.
666
+ const useNativeCallEdges =
667
+ native?.buildCallEdges && (ctx.isFullBuild || ctx.fileSymbols.size > 3);
668
+ if (useNativeCallEdges) {
669
+ buildCallEdgesNative(ctx, getNodeIdStmt, allEdgeRows, allNodesBefore, native!);
583
670
  } else {
584
671
  buildCallEdgesJS(ctx, getNodeIdStmt, allEdgeRows);
585
672
  }
586
673
 
587
- batchInsertEdges(db, allEdgeRows);
674
+ // When using native edge insert, skip JS insert here — do it after tx commits.
675
+ // Otherwise insert edges within this transaction for atomicity.
676
+ const useNativeEdgeInsert = !!ctx.nativeDb?.bulkInsertEdges;
677
+ if (!useNativeEdgeInsert) {
678
+ batchInsertEdges(db, allEdgeRows);
679
+ }
588
680
  });
589
- buildEdgesTx();
681
+ computeEdgesTx();
682
+
683
+ // Phase 2: Native rusqlite bulk insert (outside better-sqlite3 transaction
684
+ // to avoid SQLITE_BUSY contention). Uses NativeDatabase persistent connection.
685
+ // Standalone napi functions were removed in 6.17.
686
+ if (ctx.nativeDb?.bulkInsertEdges && allEdgeRows.length > 0) {
687
+ const nativeEdges = allEdgeRows.map((r) => ({
688
+ sourceId: r[0],
689
+ targetId: r[1],
690
+ kind: r[2],
691
+ confidence: r[3],
692
+ dynamic: r[4],
693
+ }));
694
+ const ok = ctx.nativeDb.bulkInsertEdges(nativeEdges);
695
+ if (!ok) {
696
+ debug('Native bulkInsertEdges failed — falling back to JS batchInsertEdges');
697
+ batchInsertEdges(db, allEdgeRows);
698
+ }
699
+ }
700
+
590
701
  ctx.timing.edgesMs = performance.now() - t0;
591
702
  }