@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
@@ -5,7 +5,6 @@ import {
5
5
  computeMaintainabilityIndex,
6
6
  } from '../metrics.js';
7
7
 
8
- // biome-ignore lint/suspicious/noExplicitAny: complexity/halstead rules are opaque language-specific objects
9
8
  type AnyRules = any;
10
9
 
11
10
  interface ComplexityAcc {
@@ -10,7 +10,6 @@ import {
10
10
  truncate,
11
11
  } from '../visitor-utils.js';
12
12
 
13
- // biome-ignore lint/suspicious/noExplicitAny: dataflow rules are opaque language-specific objects
14
13
  type AnyRules = any;
15
14
 
16
15
  interface ScopeEntry {
@@ -3,7 +3,7 @@ import { collectFile } from '../../db/query-builder.js';
3
3
  import { EVERY_SYMBOL_KIND } from '../../domain/queries.js';
4
4
  import { BATCH_COMMANDS, multiBatchData, splitTargets } from '../../features/batch.js';
5
5
  import { batch } from '../../presentation/batch.js';
6
- import { ConfigError } from '../../shared/errors.js';
6
+ import { ConfigError, toErrorMessage } from '../../shared/errors.js';
7
7
  import type { CommandDefinition } from '../types.js';
8
8
 
9
9
  interface MultiBatchItem {
@@ -58,8 +58,9 @@ export const command: CommandDefinition = {
58
58
  targets = splitTargets(positionalTargets as unknown as string[]);
59
59
  }
60
60
  } catch (err: unknown) {
61
- const message = err instanceof Error ? err.message : String(err);
62
- throw new ConfigError(`Failed to parse targets: ${message}`, { cause: err as Error });
61
+ throw new ConfigError(`Failed to parse targets: ${toErrorMessage(err)}`, {
62
+ cause: err as Error,
63
+ });
63
64
  }
64
65
 
65
66
  if (!targets || targets.length === 0) {
@@ -13,7 +13,7 @@ export const command: CommandDefinition = {
13
13
  async execute([base, target], opts, ctx) {
14
14
  const { branchCompare } = await import('../../presentation/branch-compare.js');
15
15
  await branchCompare(base!, target!, {
16
- engine: ctx.program.opts()['engine'],
16
+ engine: ctx.program.opts().engine,
17
17
  depth: parseInt(opts.depth as string, 10),
18
18
  noTests: ctx.resolveNoTests(opts),
19
19
  json: opts.json,
@@ -15,7 +15,7 @@ export const command: CommandDefinition = {
15
15
  ],
16
16
  async execute([dir], opts, ctx) {
17
17
  const root = path.resolve(dir || '.');
18
- const engine = ctx.program.opts()['engine'];
18
+ const engine = ctx.program.opts().engine;
19
19
  await buildGraph(root, {
20
20
  incremental: opts.incremental as boolean,
21
21
  ast: opts.ast as boolean,
@@ -9,7 +9,7 @@ export const command: CommandDefinition = {
9
9
  );
10
10
  const { getActiveEngine } = await import('../../domain/parser.js');
11
11
 
12
- const engine = ctx.program.opts()['engine'];
12
+ const engine = ctx.program.opts().engine;
13
13
  const { name: activeName, version: activeVersion } = getActiveEngine({ engine });
14
14
  const nativeAvailable = isNativeAvailable();
15
15
 
@@ -43,7 +43,6 @@ export const command: CommandDefinition = {
43
43
  const dbPath = findDbPath();
44
44
  const fs = await import('node:fs');
45
45
  if (fs.existsSync(dbPath)) {
46
- // @ts-expect-error -- better-sqlite3 default export typing
47
46
  const db = new Database(dbPath, { readonly: true });
48
47
  const buildEngine = getBuildMeta(db, 'engine');
49
48
  const buildVersion = getBuildMeta(db, 'codegraph_version');
@@ -4,11 +4,15 @@ import type { CommandDefinition } from '../types.js';
4
4
 
5
5
  export const command: CommandDefinition = {
6
6
  name: 'path <from> <to>',
7
- description: 'Find shortest path between two symbols',
7
+ description: 'Find shortest path between two symbols (or files with --file)',
8
8
  options: [
9
9
  ['-d, --db <path>', 'Path to graph.db'],
10
+ ['-f, --file', 'Treat <from> and <to> as file paths instead of symbol names'],
10
11
  ['--reverse', 'Follow edges backward'],
11
- ['--kinds <kinds>', 'Comma-separated edge kinds to follow (default: calls)'],
12
+ [
13
+ '--kinds <kinds>',
14
+ 'Comma-separated edge kinds to follow (default: calls; file mode: imports,imports-type)',
15
+ ],
12
16
  ['--from-file <path>', 'Disambiguate source symbol by file'],
13
17
  ['--to-file <path>', 'Disambiguate target symbol by file'],
14
18
  ['--depth <n>', 'Max traversal depth', '10'],
@@ -32,6 +36,7 @@ export const command: CommandDefinition = {
32
36
  kind: opts.kind,
33
37
  noTests: ctx.resolveNoTests(opts),
34
38
  json: opts.json,
39
+ file: opts.file,
35
40
  });
36
41
  },
37
42
  };
@@ -1,5 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
+ import { toErrorMessage } from '../../shared/errors.js';
3
4
  import { openGraph } from '../shared/open-graph.js';
4
5
  import type { CommandDefinition } from '../types.js';
5
6
 
@@ -51,8 +52,7 @@ export const command: CommandDefinition = {
51
52
  try {
52
53
  plotCfg = JSON.parse(fs.readFileSync(opts.config as string, 'utf-8')) as PlotConfig;
53
54
  } catch (e: unknown) {
54
- const message = e instanceof Error ? e.message : String(e);
55
- console.error(`Failed to load config: ${message}`);
55
+ console.error(`Failed to load config: ${toErrorMessage(e)}`);
56
56
  process.exitCode = 1;
57
57
  return;
58
58
  }
@@ -7,7 +7,7 @@ export const command: CommandDefinition = {
7
7
  description: 'Watch project for file changes and incrementally update the graph',
8
8
  async execute([dir], _opts, ctx) {
9
9
  const root = path.resolve(dir || '.');
10
- const engine = ctx.program.opts()['engine'];
10
+ const engine = ctx.program.opts().engine;
11
11
  await watchProject(root, { engine });
12
12
  },
13
13
  };
package/src/cli/index.ts CHANGED
@@ -27,12 +27,12 @@ program
27
27
  .option('--engine <engine>', 'Parser engine: native, wasm, or auto (default: auto)', 'auto')
28
28
  .hook('preAction', (thisCommand) => {
29
29
  const opts = thisCommand.opts();
30
- if (opts['verbose']) setVerbose(true);
30
+ if (opts.verbose) setVerbose(true);
31
31
  })
32
32
  .hook('postAction', async (_thisCommand, actionCommand) => {
33
33
  const name = actionCommand.name();
34
34
  if (name === 'mcp' || name === 'watch') return;
35
- if (actionCommand.opts()['json']) return;
35
+ if (actionCommand.opts().json) return;
36
36
  try {
37
37
  const result = await checkForUpdates(pkg.version);
38
38
  if (result) printUpdateNotification(result.current, result.latest);
@@ -1,11 +1,11 @@
1
- import type Database from 'better-sqlite3';
2
1
  import { openReadonlyOrFail } from '../../db/index.js';
2
+ import type { BetterSqlite3Database } from '../../types.js';
3
3
 
4
4
  /**
5
5
  * Open the graph database in readonly mode with a clean close() handle.
6
6
  */
7
7
  export function openGraph(opts: { db?: string } = {}): {
8
- db: Database.Database;
8
+ db: BetterSqlite3Database;
9
9
  close: () => void;
10
10
  } {
11
11
  const db = openReadonlyOrFail(opts.db);
package/src/cli/types.ts CHANGED
@@ -27,7 +27,7 @@ export interface CommandDefinition {
27
27
  description: string;
28
28
  queryOpts?: boolean;
29
29
  options?: Array<[string, string, ...unknown[]]>;
30
- validate?(args: string[], opts: CommandOpts, ctx: CliContext): string | void;
30
+ validate?(args: string[], opts: CommandOpts, ctx: CliContext): string | undefined;
31
31
  execute?(args: string[], opts: CommandOpts, ctx: CliContext): void | Promise<void>;
32
32
  subcommands?: CommandDefinition[];
33
33
  }
package/src/cli.ts CHANGED
@@ -1,15 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { run } from './cli/index.js';
4
- import { CodegraphError } from './shared/errors.js';
4
+ import { CodegraphError, toErrorMessage } from './shared/errors.js';
5
5
 
6
6
  run().catch((err: unknown) => {
7
7
  if (err instanceof CodegraphError) {
8
8
  console.error(`codegraph [${err.code}]: ${err.message}`);
9
9
  if (err.file) console.error(` file: ${err.file}`);
10
10
  } else {
11
- const message = err instanceof Error ? err.message : String(err);
12
- console.error(`codegraph: fatal error — ${message}`);
11
+ console.error(`codegraph: fatal error ${toErrorMessage(err)}`);
13
12
  }
14
13
  process.exit(1);
15
14
  });
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Lazy-loaded better-sqlite3 constructor.
3
+ *
4
+ * Centralises the `createRequire` + cache pattern so every call site that
5
+ * needs a JS-side SQLite handle can `import { getDatabase } from '…/db/better-sqlite3.js'`
6
+ * instead of duplicating the boilerplate. The native engine path (NativeDatabase /
7
+ * rusqlite) never touches this module.
8
+ */
9
+ import { createRequire } from 'node:module';
10
+
11
+ const _require = createRequire(import.meta.url);
12
+ let _Database: any;
13
+
14
+ /** Return the `better-sqlite3` Database constructor, loading it on first call. */
15
+ export function getDatabase(): new (...args: any[]) => any {
16
+ if (!_Database) {
17
+ _Database = _require('better-sqlite3');
18
+ }
19
+ return _Database;
20
+ }
@@ -1,13 +1,34 @@
1
1
  import { execFileSync } from 'node:child_process';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
- import Database from 'better-sqlite3';
4
+ import { fileURLToPath } from 'node:url';
5
5
  import { debug, warn } from '../infrastructure/logger.js';
6
+ import { getNative, isNativeAvailable } from '../infrastructure/native.js';
6
7
  import { DbError } from '../shared/errors.js';
7
- import type { BetterSqlite3Database } from '../types.js';
8
+ import type { BetterSqlite3Database, NativeDatabase } from '../types.js';
9
+ import { getDatabase } from './better-sqlite3.js';
8
10
  import { Repository } from './repository/base.js';
11
+ import { NativeRepository } from './repository/native-repository.js';
9
12
  import { SqliteRepository } from './repository/sqlite-repository.js';
10
13
 
14
+ /** Lazy-loaded package version (read once from package.json). */
15
+ let _packageVersion: string | undefined;
16
+ function getPackageVersion(): string {
17
+ if (_packageVersion !== undefined) return _packageVersion;
18
+ try {
19
+ const connDir = path.dirname(fileURLToPath(import.meta.url));
20
+ const pkgPath = path.join(connDir, '..', '..', 'package.json');
21
+ _packageVersion = (JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as { version: string })
22
+ .version;
23
+ } catch {
24
+ _packageVersion = '';
25
+ }
26
+ return _packageVersion;
27
+ }
28
+
29
+ /** Warn once per process when DB version mismatches the running codegraph version. */
30
+ let _versionWarned = false;
31
+
11
32
  /** DB instance with optional advisory lock path. */
12
33
  export type LockedDatabase = BetterSqlite3Database & { __lockPath?: string };
13
34
 
@@ -60,6 +81,11 @@ export function _resetRepoRootCache(): void {
60
81
  _cachedRepoRootCwd = undefined;
61
82
  }
62
83
 
84
+ /** Reset the version warning flag (for testing). */
85
+ export function _resetVersionWarning(): void {
86
+ _versionWarned = false;
87
+ }
88
+
63
89
  function isProcessAlive(pid: number): boolean {
64
90
  try {
65
91
  process.kill(pid, 0);
@@ -119,16 +145,13 @@ function isSameDirectory(a: string, b: string): boolean {
119
145
  }
120
146
 
121
147
  export function openDb(dbPath: string): LockedDatabase {
148
+ // Flush any deferred DB close from a previous build (avoids WAL contention)
149
+ flushDeferredClose();
122
150
  const dir = path.dirname(dbPath);
123
151
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
124
152
  acquireAdvisoryLock(dbPath);
125
- // vendor.d.ts declares Database as a callable; cast through unknown for construct usage
126
- const db = new (
127
- Database as unknown as new (
128
- path: string,
129
- opts?: Record<string, unknown>,
130
- ) => LockedDatabase
131
- )(dbPath);
153
+ const Database = getDatabase();
154
+ const db = new Database(dbPath) as unknown as LockedDatabase;
132
155
  db.pragma('journal_mode = WAL');
133
156
  db.pragma('busy_timeout = 5000');
134
157
  db.__lockPath = `${dbPath}.lock`;
@@ -140,6 +163,89 @@ export function closeDb(db: LockedDatabase): void {
140
163
  if (db.__lockPath) releaseAdvisoryLock(db.__lockPath);
141
164
  }
142
165
 
166
+ /** Pending deferred-close DB handles (not yet closed). */
167
+ const _deferredDbs: LockedDatabase[] = [];
168
+
169
+ /**
170
+ * Synchronously close any DB handles queued by `closeDbDeferred()`.
171
+ * Call before deleting DB files or in test teardown to avoid EBUSY on Windows.
172
+ */
173
+ export function flushDeferredClose(): void {
174
+ while (_deferredDbs.length > 0) {
175
+ const db = _deferredDbs.pop()!;
176
+ try {
177
+ db.close();
178
+ } catch {
179
+ /* ignore — handle may already be closed */
180
+ }
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Schedule DB close on the next event loop tick. Useful for incremental
186
+ * builds where the WAL checkpoint in db.close() is expensive (~250ms on
187
+ * Windows) and doesn't need to block the caller.
188
+ *
189
+ * The advisory lock is released immediately so subsequent opens succeed.
190
+ * The actual handle close (+ WAL checkpoint) happens asynchronously.
191
+ * Call `flushDeferredClose()` before deleting the DB file.
192
+ */
193
+ export function closeDbDeferred(db: LockedDatabase): void {
194
+ // Release the advisory lock immediately so the next open can proceed
195
+ if (db.__lockPath) {
196
+ releaseAdvisoryLock(db.__lockPath);
197
+ db.__lockPath = undefined;
198
+ }
199
+ _deferredDbs.push(db);
200
+ // Defer the expensive WAL checkpoint to after the caller returns
201
+ setImmediate(() => {
202
+ const idx = _deferredDbs.indexOf(db);
203
+ if (idx !== -1) {
204
+ _deferredDbs.splice(idx, 1);
205
+ try {
206
+ db.close();
207
+ } catch {
208
+ /* ignore — handle may already be closed by flush */
209
+ }
210
+ }
211
+ });
212
+ }
213
+
214
+ // ── Paired close helpers (Phase 6.16) ──────────────────────────────────
215
+ // When both a NativeDatabase and better-sqlite3 handle are open on the same
216
+ // DB file, these helpers ensure NativeDatabase is closed first (fast, ~1ms)
217
+ // before the better-sqlite3 close (which forces a WAL checkpoint, ~250ms).
218
+
219
+ /** A better-sqlite3 handle optionally paired with a NativeDatabase. */
220
+ export interface LockedDatabasePair {
221
+ db: LockedDatabase;
222
+ nativeDb?: NativeDatabase;
223
+ }
224
+
225
+ /** Close both handles: NativeDatabase first (fast), then better-sqlite3 (releases lock). */
226
+ export function closeDbPair(pair: LockedDatabasePair): void {
227
+ if (pair.nativeDb) {
228
+ try {
229
+ pair.nativeDb.close();
230
+ } catch {
231
+ /* ignore */
232
+ }
233
+ }
234
+ closeDb(pair.db);
235
+ }
236
+
237
+ /** Close NativeDatabase immediately, defer better-sqlite3 WAL checkpoint. */
238
+ export function closeDbPairDeferred(pair: LockedDatabasePair): void {
239
+ if (pair.nativeDb) {
240
+ try {
241
+ pair.nativeDb.close();
242
+ } catch {
243
+ /* ignore */
244
+ }
245
+ }
246
+ closeDbDeferred(pair.db);
247
+ }
248
+
143
249
  export function findDbPath(customPath?: string): string {
144
250
  if (customPath) return path.resolve(customPath);
145
251
  const rawCeiling = findRepoRoot();
@@ -190,19 +296,38 @@ export function openReadonlyOrFail(customPath?: string): BetterSqlite3Database {
190
296
  { file: dbPath },
191
297
  );
192
298
  }
193
- return new (
194
- Database as unknown as new (
195
- path: string,
196
- opts?: Record<string, unknown>,
197
- ) => BetterSqlite3Database
198
- )(dbPath, { readonly: true });
299
+ const Database = getDatabase();
300
+ const db = new Database(dbPath, { readonly: true }) as unknown as BetterSqlite3Database;
301
+
302
+ // Warn once per process if the DB was built with a different codegraph version
303
+ if (!_versionWarned) {
304
+ try {
305
+ const row = db
306
+ .prepare<{ value: string }>('SELECT value FROM build_meta WHERE key = ?')
307
+ .get('codegraph_version');
308
+ const buildVersion = row?.value;
309
+ const currentVersion = getPackageVersion();
310
+ if (buildVersion && currentVersion && buildVersion !== currentVersion) {
311
+ warn(
312
+ `DB was built with codegraph v${buildVersion}, running v${currentVersion}. Consider: codegraph build --no-incremental`,
313
+ );
314
+ }
315
+ } catch {
316
+ // build_meta table may not exist in older DBs — silently ignore
317
+ }
318
+ _versionWarned = true;
319
+ }
320
+
321
+ return db;
199
322
  }
200
323
 
201
324
  /**
202
325
  * Open a Repository from either an injected instance or a DB path.
203
326
  *
204
327
  * When `opts.repo` is a Repository instance, returns it directly (no DB opened).
205
- * Otherwise opens a readonly SQLite DB and wraps it in SqliteRepository.
328
+ * When the native engine is available, opens a NativeDatabase (rusqlite) and
329
+ * wraps it in NativeRepository. Otherwise falls back to better-sqlite3 via
330
+ * SqliteRepository.
206
331
  */
207
332
  export function openRepo(
208
333
  customDbPath?: string,
@@ -216,6 +341,56 @@ export function openRepo(
216
341
  }
217
342
  return { repo: opts.repo, close() {} };
218
343
  }
344
+
345
+ // Try native rusqlite path first (Phase 6.14)
346
+ if (isNativeAvailable()) {
347
+ try {
348
+ const dbPath = findDbPath(customDbPath);
349
+ if (!fs.existsSync(dbPath)) {
350
+ throw new DbError(
351
+ `No codegraph database found at ${dbPath}.\nRun "codegraph build" first to analyze your codebase.`,
352
+ { file: dbPath },
353
+ );
354
+ }
355
+ const native = getNative();
356
+ const ndb = native.NativeDatabase.openReadonly(dbPath);
357
+ try {
358
+ // Version check (same logic as openReadonlyOrFail)
359
+ if (!_versionWarned) {
360
+ try {
361
+ const buildVersion = ndb.getBuildMeta('codegraph_version');
362
+ const currentVersion = getPackageVersion();
363
+ if (buildVersion && currentVersion && buildVersion !== currentVersion) {
364
+ warn(
365
+ `DB was built with codegraph v${buildVersion}, running v${currentVersion}. Consider: codegraph build --no-incremental`,
366
+ );
367
+ }
368
+ } catch {
369
+ // build_meta table may not exist in older DBs
370
+ }
371
+ _versionWarned = true;
372
+ }
373
+
374
+ return {
375
+ repo: new NativeRepository(ndb),
376
+ close() {
377
+ ndb.close();
378
+ },
379
+ };
380
+ } catch (innerErr) {
381
+ ndb.close();
382
+ throw innerErr;
383
+ }
384
+ } catch (e) {
385
+ // Re-throw user-visible errors (e.g. DB not found) — only silently
386
+ // fall back for native-engine failures (e.g. incompatible native binary).
387
+ if (e instanceof DbError) throw e;
388
+ debug(
389
+ `openRepo: native path failed, falling back to better-sqlite3: ${(e as Error).message}`,
390
+ );
391
+ }
392
+ }
393
+
219
394
  const db = openReadonlyOrFail(customDbPath);
220
395
  return {
221
396
  repo: new SqliteRepository(db),
package/src/db/index.ts CHANGED
@@ -1,10 +1,14 @@
1
1
  // Barrel re-export — keeps all existing `import { ... } from '…/db/index.js'` working.
2
2
 
3
- export type { LockedDatabase } from './connection.js';
3
+ export type { LockedDatabase, LockedDatabasePair } from './connection.js';
4
4
  export {
5
5
  closeDb,
6
+ closeDbDeferred,
7
+ closeDbPair,
8
+ closeDbPairDeferred,
6
9
  findDbPath,
7
10
  findRepoRoot,
11
+ flushDeferredClose,
8
12
  openDb,
9
13
  openReadonlyOrFail,
10
14
  openRepo,
@@ -8,6 +8,8 @@ interface Migration {
8
8
  up: string;
9
9
  }
10
10
 
11
+ // IMPORTANT: Migration DDL is mirrored in crates/codegraph-core/src/native_db.rs.
12
+ // Any changes here MUST be reflected there (and vice-versa).
11
13
  export const MIGRATIONS: Migration[] = [
12
14
  {
13
15
  version: 1,
@@ -247,6 +249,13 @@ export const MIGRATIONS: Migration[] = [
247
249
  CREATE INDEX IF NOT EXISTS idx_nodes_scope ON nodes(scope);
248
250
  `,
249
251
  },
252
+ {
253
+ version: 16,
254
+ up: `
255
+ CREATE INDEX IF NOT EXISTS idx_edges_kind_target ON edges(kind, target_id);
256
+ CREATE INDEX IF NOT EXISTS idx_edges_kind_source ON edges(kind, source_id);
257
+ `,
258
+ },
250
259
  ];
251
260
 
252
261
  interface PragmaColumnInfo {
@@ -1,6 +1,6 @@
1
1
  import { DbError } from '../shared/errors.js';
2
2
  import { DEAD_ROLE_PREFIX, EVERY_EDGE_KIND } from '../shared/kinds.js';
3
- import type { BetterSqlite3Database } from '../types.js';
3
+ import type { BetterSqlite3Database, NativeDatabase } from '../types.js';
4
4
 
5
5
  // ─── Validation Helpers ─────────────────────────────────────────────
6
6
 
@@ -66,6 +66,17 @@ function validateEdgeKind(edgeKind: string): void {
66
66
  }
67
67
  }
68
68
 
69
+ /** Runtime-validate that every param is string, number, or null before sending to nativeDb. */
70
+ function validateNativeParams(params: (string | number)[]): Array<string | number | null> {
71
+ for (let i = 0; i < params.length; i++) {
72
+ const p = params[i];
73
+ if (p !== null && typeof p !== 'string' && typeof p !== 'number') {
74
+ throw new DbError(`NodeQuery param[${i}] has unsupported type: ${typeof p}`);
75
+ }
76
+ }
77
+ return params as Array<string | number | null>;
78
+ }
79
+
69
80
  // ─── LIKE Escaping ──────────────────────────────────────────────────
70
81
 
71
82
  /** Escape LIKE wildcards in a literal string segment. */
@@ -314,15 +325,29 @@ export class NodeQuery {
314
325
  return { sql, params };
315
326
  }
316
327
 
317
- /** Execute and return all rows. */
318
- all<TRow = Record<string, unknown>>(db: BetterSqlite3Database): TRow[] {
328
+ /** Execute and return all rows. When `nativeDb` is provided, dispatches through rusqlite. */
329
+ all<TRow = Record<string, unknown>>(
330
+ db: BetterSqlite3Database,
331
+ nativeDb?: NativeDatabase,
332
+ ): TRow[] {
319
333
  const { sql, params } = this.build();
334
+ if (nativeDb) {
335
+ return nativeDb.queryAll(sql, validateNativeParams(params)) as TRow[];
336
+ }
320
337
  return db.prepare<TRow>(sql).all(...params) as TRow[];
321
338
  }
322
339
 
323
- /** Execute and return first row. */
324
- get<TRow = Record<string, unknown>>(db: BetterSqlite3Database): TRow | undefined {
340
+ /** Execute and return first row. When `nativeDb` is provided, dispatches through rusqlite. */
341
+ get<TRow = Record<string, unknown>>(
342
+ db: BetterSqlite3Database,
343
+ nativeDb?: NativeDatabase,
344
+ ): TRow | undefined {
325
345
  const { sql, params } = this.build();
346
+ if (nativeDb) {
347
+ return (nativeDb.queryGet(sql, validateNativeParams(params)) ?? undefined) as
348
+ | TRow
349
+ | undefined;
350
+ }
326
351
  return db.prepare<TRow>(sql).get(...params) as TRow | undefined;
327
352
  }
328
353
 
@@ -28,6 +28,7 @@ export {
28
28
  export { getEmbeddingCount, getEmbeddingMeta, hasEmbeddings } from './embeddings.js';
29
29
  export { getCallableNodes, getCallEdges, getFileNodesAll, getImportEdges } from './graph-read.js';
30
30
  export { InMemoryRepository } from './in-memory-repository.js';
31
+ export { NativeRepository } from './native-repository.js';
31
32
  export {
32
33
  bulkNodeIdsByFile,
33
34
  countEdges,