@optave/codegraph 3.4.1 → 3.6.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 (349) hide show
  1. package/README.md +50 -28
  2. package/dist/ast-analysis/engine.d.ts.map +1 -1
  3. package/dist/ast-analysis/engine.js +119 -127
  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/visitors/ast-store-visitor.d.ts.map +1 -1
  9. package/dist/ast-analysis/visitors/ast-store-visitor.js +116 -35
  10. package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
  11. package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
  12. package/dist/ast-analysis/visitors/complexity-visitor.js +11 -13
  13. package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
  14. package/dist/db/better-sqlite3.d.ts +3 -0
  15. package/dist/db/better-sqlite3.d.ts.map +1 -0
  16. package/dist/db/better-sqlite3.js +19 -0
  17. package/dist/db/better-sqlite3.js.map +1 -0
  18. package/dist/db/connection.d.ts +25 -4
  19. package/dist/db/connection.d.ts.map +1 -1
  20. package/dist/db/connection.js +125 -23
  21. package/dist/db/connection.js.map +1 -1
  22. package/dist/db/index.d.ts +2 -2
  23. package/dist/db/index.d.ts.map +1 -1
  24. package/dist/db/index.js +1 -1
  25. package/dist/db/index.js.map +1 -1
  26. package/dist/db/migrations.d.ts.map +1 -1
  27. package/dist/db/migrations.js +40 -32
  28. package/dist/db/migrations.js.map +1 -1
  29. package/dist/db/query-builder.d.ts +5 -5
  30. package/dist/db/query-builder.d.ts.map +1 -1
  31. package/dist/db/query-builder.js +20 -4
  32. package/dist/db/query-builder.js.map +1 -1
  33. package/dist/db/repository/index.d.ts +1 -0
  34. package/dist/db/repository/index.d.ts.map +1 -1
  35. package/dist/db/repository/index.js +1 -0
  36. package/dist/db/repository/index.js.map +1 -1
  37. package/dist/db/repository/native-repository.d.ts +58 -0
  38. package/dist/db/repository/native-repository.d.ts.map +1 -0
  39. package/dist/db/repository/native-repository.js +261 -0
  40. package/dist/db/repository/native-repository.js.map +1 -0
  41. package/dist/db/repository/nodes.d.ts +4 -4
  42. package/dist/db/repository/nodes.d.ts.map +1 -1
  43. package/dist/db/repository/nodes.js +6 -6
  44. package/dist/db/repository/nodes.js.map +1 -1
  45. package/dist/domain/analysis/context.d.ts.map +1 -1
  46. package/dist/domain/analysis/context.js +51 -66
  47. package/dist/domain/analysis/context.js.map +1 -1
  48. package/dist/domain/analysis/dependencies.d.ts.map +1 -1
  49. package/dist/domain/analysis/dependencies.js +62 -70
  50. package/dist/domain/analysis/dependencies.js.map +1 -1
  51. package/dist/domain/analysis/diff-impact.d.ts +9 -7
  52. package/dist/domain/analysis/diff-impact.d.ts.map +1 -1
  53. package/dist/domain/analysis/exports.d.ts.map +1 -1
  54. package/dist/domain/analysis/exports.js +29 -33
  55. package/dist/domain/analysis/exports.js.map +1 -1
  56. package/dist/domain/analysis/fn-impact.d.ts +15 -17
  57. package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
  58. package/dist/domain/analysis/fn-impact.js +35 -65
  59. package/dist/domain/analysis/fn-impact.js.map +1 -1
  60. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  61. package/dist/domain/analysis/module-map.js +91 -6
  62. package/dist/domain/analysis/module-map.js.map +1 -1
  63. package/dist/domain/analysis/query-helpers.d.ts +20 -0
  64. package/dist/domain/analysis/query-helpers.d.ts.map +1 -0
  65. package/dist/domain/analysis/query-helpers.js +27 -0
  66. package/dist/domain/analysis/query-helpers.js.map +1 -0
  67. package/dist/domain/graph/builder/context.d.ts +2 -1
  68. package/dist/domain/graph/builder/context.d.ts.map +1 -1
  69. package/dist/domain/graph/builder/context.js +1 -0
  70. package/dist/domain/graph/builder/context.js.map +1 -1
  71. package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
  72. package/dist/domain/graph/builder/helpers.js +15 -9
  73. package/dist/domain/graph/builder/helpers.js.map +1 -1
  74. package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
  75. package/dist/domain/graph/builder/incremental.js +3 -2
  76. package/dist/domain/graph/builder/incremental.js.map +1 -1
  77. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  78. package/dist/domain/graph/builder/pipeline.js +95 -7
  79. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  80. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  81. package/dist/domain/graph/builder/stages/build-edges.js +101 -57
  82. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  83. package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
  84. package/dist/domain/graph/builder/stages/build-structure.js +33 -3
  85. package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
  86. package/dist/domain/graph/builder/stages/collect-files.d.ts.map +1 -1
  87. package/dist/domain/graph/builder/stages/collect-files.js +70 -6
  88. package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
  89. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  90. package/dist/domain/graph/builder/stages/detect-changes.js +36 -14
  91. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  92. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
  93. package/dist/domain/graph/builder/stages/finalize.js +130 -88
  94. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  95. package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
  96. package/dist/domain/graph/builder/stages/insert-nodes.js +124 -16
  97. package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
  98. package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
  99. package/dist/domain/graph/builder/stages/resolve-imports.js +3 -2
  100. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  101. package/dist/domain/graph/resolve.d.ts +0 -4
  102. package/dist/domain/graph/resolve.d.ts.map +1 -1
  103. package/dist/domain/graph/resolve.js +32 -48
  104. package/dist/domain/graph/resolve.js.map +1 -1
  105. package/dist/domain/graph/watcher.d.ts.map +1 -1
  106. package/dist/domain/graph/watcher.js +12 -12
  107. package/dist/domain/graph/watcher.js.map +1 -1
  108. package/dist/domain/parser.d.ts +1 -1
  109. package/dist/domain/parser.d.ts.map +1 -1
  110. package/dist/domain/parser.js +165 -101
  111. package/dist/domain/parser.js.map +1 -1
  112. package/dist/domain/search/search/cli-formatter.d.ts.map +1 -1
  113. package/dist/domain/search/search/cli-formatter.js +88 -83
  114. package/dist/domain/search/search/cli-formatter.js.map +1 -1
  115. package/dist/extractors/bash.d.ts +6 -0
  116. package/dist/extractors/bash.d.ts.map +1 -0
  117. package/dist/extractors/bash.js +91 -0
  118. package/dist/extractors/bash.js.map +1 -0
  119. package/dist/extractors/c.d.ts +6 -0
  120. package/dist/extractors/c.d.ts.map +1 -0
  121. package/dist/extractors/c.js +204 -0
  122. package/dist/extractors/c.js.map +1 -0
  123. package/dist/extractors/cpp.d.ts +6 -0
  124. package/dist/extractors/cpp.d.ts.map +1 -0
  125. package/dist/extractors/cpp.js +283 -0
  126. package/dist/extractors/cpp.js.map +1 -0
  127. package/dist/extractors/csharp.d.ts.map +1 -1
  128. package/dist/extractors/csharp.js +42 -54
  129. package/dist/extractors/csharp.js.map +1 -1
  130. package/dist/extractors/go.d.ts.map +1 -1
  131. package/dist/extractors/go.js +126 -130
  132. package/dist/extractors/go.js.map +1 -1
  133. package/dist/extractors/hcl.js +6 -6
  134. package/dist/extractors/hcl.js.map +1 -1
  135. package/dist/extractors/helpers.d.ts +32 -1
  136. package/dist/extractors/helpers.d.ts.map +1 -1
  137. package/dist/extractors/helpers.js +74 -0
  138. package/dist/extractors/helpers.js.map +1 -1
  139. package/dist/extractors/index.d.ts +6 -0
  140. package/dist/extractors/index.d.ts.map +1 -1
  141. package/dist/extractors/index.js +6 -0
  142. package/dist/extractors/index.js.map +1 -1
  143. package/dist/extractors/java.d.ts.map +1 -1
  144. package/dist/extractors/java.js +32 -47
  145. package/dist/extractors/java.js.map +1 -1
  146. package/dist/extractors/javascript.d.ts.map +1 -1
  147. package/dist/extractors/javascript.js +359 -330
  148. package/dist/extractors/javascript.js.map +1 -1
  149. package/dist/extractors/kotlin.d.ts +6 -0
  150. package/dist/extractors/kotlin.d.ts.map +1 -0
  151. package/dist/extractors/kotlin.js +275 -0
  152. package/dist/extractors/kotlin.js.map +1 -0
  153. package/dist/extractors/php.d.ts.map +1 -1
  154. package/dist/extractors/php.js +39 -44
  155. package/dist/extractors/php.js.map +1 -1
  156. package/dist/extractors/python.d.ts.map +1 -1
  157. package/dist/extractors/python.js +75 -93
  158. package/dist/extractors/python.js.map +1 -1
  159. package/dist/extractors/ruby.js +6 -13
  160. package/dist/extractors/ruby.js.map +1 -1
  161. package/dist/extractors/rust.d.ts.map +1 -1
  162. package/dist/extractors/rust.js +58 -82
  163. package/dist/extractors/rust.js.map +1 -1
  164. package/dist/extractors/scala.d.ts +6 -0
  165. package/dist/extractors/scala.d.ts.map +1 -0
  166. package/dist/extractors/scala.js +269 -0
  167. package/dist/extractors/scala.js.map +1 -0
  168. package/dist/extractors/swift.d.ts +6 -0
  169. package/dist/extractors/swift.d.ts.map +1 -0
  170. package/dist/extractors/swift.js +275 -0
  171. package/dist/extractors/swift.js.map +1 -0
  172. package/dist/features/ast.d.ts +16 -1
  173. package/dist/features/ast.d.ts.map +1 -1
  174. package/dist/features/ast.js +45 -23
  175. package/dist/features/ast.js.map +1 -1
  176. package/dist/features/audit.d.ts.map +1 -1
  177. package/dist/features/audit.js +17 -21
  178. package/dist/features/audit.js.map +1 -1
  179. package/dist/features/branch-compare.d.ts.map +1 -1
  180. package/dist/features/branch-compare.js +50 -4
  181. package/dist/features/branch-compare.js.map +1 -1
  182. package/dist/features/cfg.d.ts +7 -1
  183. package/dist/features/cfg.d.ts.map +1 -1
  184. package/dist/features/cfg.js +118 -62
  185. package/dist/features/cfg.js.map +1 -1
  186. package/dist/features/check.d.ts.map +1 -1
  187. package/dist/features/check.js +79 -62
  188. package/dist/features/check.js.map +1 -1
  189. package/dist/features/complexity-query.d.ts.map +1 -1
  190. package/dist/features/complexity-query.js +142 -137
  191. package/dist/features/complexity-query.js.map +1 -1
  192. package/dist/features/complexity.d.ts +7 -1
  193. package/dist/features/complexity.d.ts.map +1 -1
  194. package/dist/features/complexity.js +62 -1
  195. package/dist/features/complexity.js.map +1 -1
  196. package/dist/features/dataflow.d.ts +7 -1
  197. package/dist/features/dataflow.d.ts.map +1 -1
  198. package/dist/features/dataflow.js +356 -188
  199. package/dist/features/dataflow.js.map +1 -1
  200. package/dist/features/graph-enrichment.d.ts.map +1 -1
  201. package/dist/features/graph-enrichment.js +117 -104
  202. package/dist/features/graph-enrichment.js.map +1 -1
  203. package/dist/features/sequence.d.ts.map +1 -1
  204. package/dist/features/sequence.js +25 -4
  205. package/dist/features/sequence.js.map +1 -1
  206. package/dist/features/snapshot.d.ts.map +1 -1
  207. package/dist/features/snapshot.js +2 -1
  208. package/dist/features/snapshot.js.map +1 -1
  209. package/dist/features/structure-query.d.ts.map +1 -1
  210. package/dist/features/structure-query.js +29 -4
  211. package/dist/features/structure-query.js.map +1 -1
  212. package/dist/features/structure.d.ts.map +1 -1
  213. package/dist/features/structure.js +35 -15
  214. package/dist/features/structure.js.map +1 -1
  215. package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
  216. package/dist/graph/algorithms/leiden/adapter.js +88 -73
  217. package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
  218. package/dist/graph/algorithms/leiden/index.js +43 -28
  219. package/dist/graph/algorithms/leiden/index.js.map +1 -1
  220. package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
  221. package/dist/graph/algorithms/leiden/optimiser.js +90 -104
  222. package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
  223. package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
  224. package/dist/graph/algorithms/leiden/partition.js +89 -106
  225. package/dist/graph/algorithms/leiden/partition.js.map +1 -1
  226. package/dist/graph/model.d.ts +2 -0
  227. package/dist/graph/model.d.ts.map +1 -1
  228. package/dist/graph/model.js +20 -8
  229. package/dist/graph/model.js.map +1 -1
  230. package/dist/infrastructure/config.d.ts +0 -8
  231. package/dist/infrastructure/config.d.ts.map +1 -1
  232. package/dist/infrastructure/config.js +73 -62
  233. package/dist/infrastructure/config.js.map +1 -1
  234. package/dist/infrastructure/registry.d.ts +0 -8
  235. package/dist/infrastructure/registry.d.ts.map +1 -1
  236. package/dist/infrastructure/registry.js +12 -14
  237. package/dist/infrastructure/registry.js.map +1 -1
  238. package/dist/mcp/server.d.ts.map +1 -1
  239. package/dist/mcp/server.js +47 -45
  240. package/dist/mcp/server.js.map +1 -1
  241. package/dist/presentation/audit.d.ts.map +1 -1
  242. package/dist/presentation/audit.js +61 -57
  243. package/dist/presentation/audit.js.map +1 -1
  244. package/dist/presentation/branch-compare.d.ts.map +1 -1
  245. package/dist/presentation/branch-compare.js +56 -38
  246. package/dist/presentation/branch-compare.js.map +1 -1
  247. package/dist/presentation/check.d.ts.map +1 -1
  248. package/dist/presentation/check.js +30 -32
  249. package/dist/presentation/check.js.map +1 -1
  250. package/dist/presentation/colors.d.ts.map +1 -1
  251. package/dist/presentation/colors.js +2 -0
  252. package/dist/presentation/colors.js.map +1 -1
  253. package/dist/presentation/complexity.d.ts.map +1 -1
  254. package/dist/presentation/complexity.js +25 -19
  255. package/dist/presentation/complexity.js.map +1 -1
  256. package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
  257. package/dist/presentation/queries-cli/exports.js +15 -15
  258. package/dist/presentation/queries-cli/exports.js.map +1 -1
  259. package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
  260. package/dist/presentation/queries-cli/impact.js +29 -19
  261. package/dist/presentation/queries-cli/impact.js.map +1 -1
  262. package/dist/types.d.ts +406 -3
  263. package/dist/types.d.ts.map +1 -1
  264. package/grammars/tree-sitter-bash.wasm +0 -0
  265. package/grammars/tree-sitter-c.wasm +0 -0
  266. package/grammars/tree-sitter-cpp.wasm +0 -0
  267. package/grammars/tree-sitter-kotlin.wasm +0 -0
  268. package/grammars/tree-sitter-scala.wasm +0 -0
  269. package/grammars/tree-sitter-swift.wasm +0 -0
  270. package/package.json +67 -11
  271. package/src/ast-analysis/engine.ts +147 -138
  272. package/src/ast-analysis/rules/javascript.ts +1 -0
  273. package/src/ast-analysis/visitors/ast-store-visitor.ts +116 -34
  274. package/src/ast-analysis/visitors/complexity-visitor.ts +11 -11
  275. package/src/db/better-sqlite3.ts +20 -0
  276. package/src/db/connection.ts +148 -26
  277. package/src/db/index.ts +4 -1
  278. package/src/db/migrations.ts +38 -32
  279. package/src/db/query-builder.ts +30 -5
  280. package/src/db/repository/index.ts +1 -0
  281. package/src/db/repository/native-repository.ts +361 -0
  282. package/src/db/repository/nodes.ts +7 -3
  283. package/src/domain/analysis/context.ts +73 -75
  284. package/src/domain/analysis/dependencies.ts +78 -68
  285. package/src/domain/analysis/exports.ts +45 -34
  286. package/src/domain/analysis/fn-impact.ts +67 -64
  287. package/src/domain/analysis/module-map.ts +103 -8
  288. package/src/domain/analysis/query-helpers.ts +35 -0
  289. package/src/domain/graph/builder/context.ts +2 -0
  290. package/src/domain/graph/builder/helpers.ts +12 -6
  291. package/src/domain/graph/builder/incremental.ts +3 -2
  292. package/src/domain/graph/builder/pipeline.ts +98 -6
  293. package/src/domain/graph/builder/stages/build-edges.ts +116 -83
  294. package/src/domain/graph/builder/stages/build-structure.ts +46 -8
  295. package/src/domain/graph/builder/stages/collect-files.ts +83 -6
  296. package/src/domain/graph/builder/stages/detect-changes.ts +44 -21
  297. package/src/domain/graph/builder/stages/finalize.ts +172 -109
  298. package/src/domain/graph/builder/stages/insert-nodes.ts +147 -17
  299. package/src/domain/graph/builder/stages/resolve-imports.ts +3 -2
  300. package/src/domain/graph/resolve.ts +34 -46
  301. package/src/domain/graph/watcher.ts +12 -14
  302. package/src/domain/parser.ts +169 -97
  303. package/src/domain/search/search/cli-formatter.ts +121 -94
  304. package/src/extractors/bash.ts +97 -0
  305. package/src/extractors/c.ts +212 -0
  306. package/src/extractors/cpp.ts +298 -0
  307. package/src/extractors/csharp.ts +53 -56
  308. package/src/extractors/go.ts +152 -134
  309. package/src/extractors/hcl.ts +6 -6
  310. package/src/extractors/helpers.ts +93 -1
  311. package/src/extractors/index.ts +6 -0
  312. package/src/extractors/java.ts +43 -48
  313. package/src/extractors/javascript.ts +382 -317
  314. package/src/extractors/kotlin.ts +293 -0
  315. package/src/extractors/php.ts +46 -40
  316. package/src/extractors/python.ts +81 -104
  317. package/src/extractors/ruby.ts +6 -13
  318. package/src/extractors/rust.ts +65 -84
  319. package/src/extractors/scala.ts +285 -0
  320. package/src/extractors/swift.ts +293 -0
  321. package/src/features/ast.ts +74 -24
  322. package/src/features/audit.ts +24 -20
  323. package/src/features/branch-compare.ts +54 -5
  324. package/src/features/cfg.ts +158 -65
  325. package/src/features/check.ts +90 -74
  326. package/src/features/complexity-query.ts +181 -163
  327. package/src/features/complexity.ts +64 -1
  328. package/src/features/dataflow.ts +462 -217
  329. package/src/features/graph-enrichment.ts +161 -117
  330. package/src/features/sequence.ts +27 -4
  331. package/src/features/snapshot.ts +2 -1
  332. package/src/features/structure-query.ts +43 -4
  333. package/src/features/structure.ts +50 -22
  334. package/src/graph/algorithms/leiden/adapter.ts +126 -71
  335. package/src/graph/algorithms/leiden/index.ts +67 -28
  336. package/src/graph/algorithms/leiden/optimiser.ts +114 -105
  337. package/src/graph/algorithms/leiden/partition.ts +131 -98
  338. package/src/graph/model.ts +19 -7
  339. package/src/infrastructure/config.ts +60 -58
  340. package/src/infrastructure/registry.ts +17 -14
  341. package/src/mcp/server.ts +48 -47
  342. package/src/presentation/audit.ts +72 -67
  343. package/src/presentation/branch-compare.ts +54 -50
  344. package/src/presentation/check.ts +34 -34
  345. package/src/presentation/colors.ts +2 -0
  346. package/src/presentation/complexity.ts +39 -33
  347. package/src/presentation/queries-cli/exports.ts +17 -17
  348. package/src/presentation/queries-cli/impact.ts +30 -22
  349. package/src/types.ts +458 -3
@@ -2,11 +2,13 @@ import { execFileSync } from 'node:child_process';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
- import Database from 'better-sqlite3';
6
5
  import { debug, warn } from '../infrastructure/logger.js';
6
+ import { getNative, isNativeAvailable } from '../infrastructure/native.js';
7
7
  import { DbError } from '../shared/errors.js';
8
- import type { BetterSqlite3Database } from '../types.js';
8
+ import type { BetterSqlite3Database, NativeDatabase } from '../types.js';
9
+ import { getDatabase } from './better-sqlite3.js';
9
10
  import { Repository } from './repository/base.js';
11
+ import { NativeRepository } from './repository/native-repository.js';
10
12
  import { SqliteRepository } from './repository/sqlite-repository.js';
11
13
 
12
14
  /** Lazy-loaded package version (read once from package.json). */
@@ -27,6 +29,23 @@ function getPackageVersion(): string {
27
29
  /** Warn once per process when DB version mismatches the running codegraph version. */
28
30
  let _versionWarned = false;
29
31
 
32
+ /** Check and warn (once) if the running codegraph version differs from the DB build version. */
33
+ function warnOnVersionMismatch(getBuildVersion: () => string | undefined | null): void {
34
+ if (_versionWarned) return;
35
+ _versionWarned = true;
36
+ try {
37
+ const buildVersion = getBuildVersion();
38
+ const currentVersion = getPackageVersion();
39
+ if (buildVersion && currentVersion && buildVersion !== currentVersion) {
40
+ warn(
41
+ `DB was built with codegraph v${buildVersion}, running v${currentVersion}. Consider: codegraph build --no-incremental`,
42
+ );
43
+ }
44
+ } catch {
45
+ // build_meta table may not exist in older DBs — silently ignore
46
+ }
47
+ }
48
+
30
49
  /** DB instance with optional advisory lock path. */
31
50
  export type LockedDatabase = BetterSqlite3Database & { __lockPath?: string };
32
51
 
@@ -79,11 +98,6 @@ export function _resetRepoRootCache(): void {
79
98
  _cachedRepoRootCwd = undefined;
80
99
  }
81
100
 
82
- /** Reset the version warning flag (for testing). */
83
- export function _resetVersionWarning(): void {
84
- _versionWarned = false;
85
- }
86
-
87
101
  function isProcessAlive(pid: number): boolean {
88
102
  try {
89
103
  process.kill(pid, 0);
@@ -148,6 +162,7 @@ export function openDb(dbPath: string): LockedDatabase {
148
162
  const dir = path.dirname(dbPath);
149
163
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
150
164
  acquireAdvisoryLock(dbPath);
165
+ const Database = getDatabase();
151
166
  const db = new Database(dbPath) as unknown as LockedDatabase;
152
167
  db.pragma('journal_mode = WAL');
153
168
  db.pragma('busy_timeout = 5000');
@@ -208,6 +223,41 @@ export function closeDbDeferred(db: LockedDatabase): void {
208
223
  });
209
224
  }
210
225
 
226
+ // ── Paired close helpers (Phase 6.16) ──────────────────────────────────
227
+ // When both a NativeDatabase and better-sqlite3 handle are open on the same
228
+ // DB file, these helpers ensure NativeDatabase is closed first (fast, ~1ms)
229
+ // before the better-sqlite3 close (which forces a WAL checkpoint, ~250ms).
230
+
231
+ /** A better-sqlite3 handle optionally paired with a NativeDatabase. */
232
+ export interface LockedDatabasePair {
233
+ db: LockedDatabase;
234
+ nativeDb?: NativeDatabase;
235
+ }
236
+
237
+ /** Close both handles: NativeDatabase first (fast), then better-sqlite3 (releases lock). */
238
+ export function closeDbPair(pair: LockedDatabasePair): void {
239
+ if (pair.nativeDb) {
240
+ try {
241
+ pair.nativeDb.close();
242
+ } catch {
243
+ /* ignore */
244
+ }
245
+ }
246
+ closeDb(pair.db);
247
+ }
248
+
249
+ /** Close NativeDatabase immediately, defer better-sqlite3 WAL checkpoint. */
250
+ export function closeDbPairDeferred(pair: LockedDatabasePair): void {
251
+ if (pair.nativeDb) {
252
+ try {
253
+ pair.nativeDb.close();
254
+ } catch {
255
+ /* ignore */
256
+ }
257
+ }
258
+ closeDbDeferred(pair.db);
259
+ }
260
+
211
261
  export function findDbPath(customPath?: string): string {
212
262
  if (customPath) return path.resolve(customPath);
213
263
  const rawCeiling = findRepoRoot();
@@ -258,35 +308,51 @@ export function openReadonlyOrFail(customPath?: string): BetterSqlite3Database {
258
308
  { file: dbPath },
259
309
  );
260
310
  }
311
+ const Database = getDatabase();
261
312
  const db = new Database(dbPath, { readonly: true }) as unknown as BetterSqlite3Database;
262
313
 
263
- // Warn once per process if the DB was built with a different codegraph version
264
- if (!_versionWarned) {
265
- try {
266
- const row = db
267
- .prepare<{ value: string }>('SELECT value FROM build_meta WHERE key = ?')
268
- .get('codegraph_version');
269
- const buildVersion = row?.value;
270
- const currentVersion = getPackageVersion();
271
- if (buildVersion && currentVersion && buildVersion !== currentVersion) {
272
- warn(
273
- `DB was built with codegraph v${buildVersion}, running v${currentVersion}. Consider: codegraph build --no-incremental`,
274
- );
275
- }
276
- } catch {
277
- // build_meta table may not exist in older DBs — silently ignore
278
- }
279
- _versionWarned = true;
280
- }
314
+ warnOnVersionMismatch(() => {
315
+ const row = db
316
+ .prepare<{ value: string }>('SELECT value FROM build_meta WHERE key = ?')
317
+ .get('codegraph_version');
318
+ return row?.value;
319
+ });
281
320
 
282
321
  return db;
283
322
  }
284
323
 
324
+ /** Open a NativeRepository via rusqlite, throwing DbError if the DB file is missing. */
325
+ function openRepoNative(customDbPath?: string): { repo: Repository; close(): void } {
326
+ const dbPath = findDbPath(customDbPath);
327
+ if (!fs.existsSync(dbPath)) {
328
+ throw new DbError(
329
+ `No codegraph database found at ${dbPath}.\nRun "codegraph build" first to analyze your codebase.`,
330
+ { file: dbPath },
331
+ );
332
+ }
333
+ const native = getNative();
334
+ const ndb = native.NativeDatabase.openReadonly(dbPath);
335
+ try {
336
+ warnOnVersionMismatch(() => ndb.getBuildMeta('codegraph_version'));
337
+ return {
338
+ repo: new NativeRepository(ndb),
339
+ close() {
340
+ ndb.close();
341
+ },
342
+ };
343
+ } catch (innerErr) {
344
+ ndb.close();
345
+ throw innerErr;
346
+ }
347
+ }
348
+
285
349
  /**
286
350
  * Open a Repository from either an injected instance or a DB path.
287
351
  *
288
352
  * When `opts.repo` is a Repository instance, returns it directly (no DB opened).
289
- * Otherwise opens a readonly SQLite DB and wraps it in SqliteRepository.
353
+ * When the native engine is available, opens a NativeDatabase (rusqlite) and
354
+ * wraps it in NativeRepository. Otherwise falls back to better-sqlite3 via
355
+ * SqliteRepository.
290
356
  */
291
357
  export function openRepo(
292
358
  customDbPath?: string,
@@ -300,6 +366,21 @@ export function openRepo(
300
366
  }
301
367
  return { repo: opts.repo, close() {} };
302
368
  }
369
+
370
+ // Try native rusqlite path first (Phase 6.14)
371
+ if (isNativeAvailable()) {
372
+ try {
373
+ return openRepoNative(customDbPath);
374
+ } catch (e) {
375
+ // Re-throw user-visible errors (e.g. DB not found) — only silently
376
+ // fall back for native-engine failures (e.g. incompatible native binary).
377
+ if (e instanceof DbError) throw e;
378
+ debug(
379
+ `openRepo: native path failed, falling back to better-sqlite3: ${(e as Error).message}`,
380
+ );
381
+ }
382
+ }
383
+
303
384
  const db = openReadonlyOrFail(customDbPath);
304
385
  return {
305
386
  repo: new SqliteRepository(db),
@@ -308,3 +389,44 @@ export function openRepo(
308
389
  },
309
390
  };
310
391
  }
392
+
393
+ /**
394
+ * Open a readonly DB with an optional NativeDatabase alongside it.
395
+ *
396
+ * Returns the better-sqlite3 handle (for backwards compat) plus an optional
397
+ * NativeDatabase for modules that can use batched Rust query methods.
398
+ * Callers should use nativeDb when available and fall back to db.prepare().
399
+ */
400
+ export function openReadonlyWithNative(customPath?: string): {
401
+ db: BetterSqlite3Database;
402
+ nativeDb: NativeDatabase | undefined;
403
+ close(): void;
404
+ } {
405
+ const db = openReadonlyOrFail(customPath);
406
+
407
+ let nativeDb: NativeDatabase | undefined;
408
+ if (isNativeAvailable()) {
409
+ try {
410
+ const dbPath = findDbPath(customPath);
411
+ const native = getNative();
412
+ nativeDb = native.NativeDatabase.openReadonly(dbPath);
413
+ } catch (e) {
414
+ debug(`openReadonlyWithNative: native path failed: ${(e as Error).message}`);
415
+ }
416
+ }
417
+
418
+ return {
419
+ db,
420
+ nativeDb,
421
+ close() {
422
+ db.close();
423
+ if (nativeDb) {
424
+ try {
425
+ nativeDb.close();
426
+ } catch {
427
+ // already closed or not closeable
428
+ }
429
+ }
430
+ },
431
+ };
432
+ }
package/src/db/index.ts CHANGED
@@ -1,14 +1,17 @@
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
6
  closeDbDeferred,
7
+ closeDbPair,
8
+ closeDbPairDeferred,
7
9
  findDbPath,
8
10
  findRepoRoot,
9
11
  flushDeferredClose,
10
12
  openDb,
11
13
  openReadonlyOrFail,
14
+ openReadonlyWithNative,
12
15
  openRepo,
13
16
  } from './connection.js';
14
17
  export { getBuildMeta, initSchema, MIGRATIONS, setBuildMeta } from './migrations.js';
@@ -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,
@@ -302,7 +304,8 @@ export function setBuildMeta(
302
304
  tx();
303
305
  }
304
306
 
305
- export function initSchema(db: BetterSqlite3Database): void {
307
+ /** Run numbered migrations that haven't been applied yet. */
308
+ function applyMigrations(db: BetterSqlite3Database): void {
306
309
  db.exec(`CREATE TABLE IF NOT EXISTS schema_version (version INTEGER NOT NULL DEFAULT 0)`);
307
310
 
308
311
  const row = db.prepare<{ version: number }>('SELECT version FROM schema_version').get();
@@ -320,40 +323,43 @@ export function initSchema(db: BetterSqlite3Database): void {
320
323
  currentVersion = migration.version;
321
324
  }
322
325
  }
326
+ }
323
327
 
324
- // Legacy column compat — add columns that may be missing from pre-migration DBs
328
+ /** Ensure columns and indexes exist for pre-migration DBs (legacy compat). */
329
+ function ensureLegacyColumns(db: BetterSqlite3Database): void {
325
330
  if (hasTable(db, 'nodes')) {
326
- if (!hasColumn(db, 'nodes', 'end_line')) {
327
- db.exec('ALTER TABLE nodes ADD COLUMN end_line INTEGER');
328
- }
329
- if (!hasColumn(db, 'nodes', 'role')) {
330
- db.exec('ALTER TABLE nodes ADD COLUMN role TEXT');
331
- }
332
- db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_role ON nodes(role)');
333
- if (!hasColumn(db, 'nodes', 'parent_id')) {
334
- db.exec('ALTER TABLE nodes ADD COLUMN parent_id INTEGER REFERENCES nodes(id)');
335
- }
336
- db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_parent ON nodes(parent_id)');
337
- db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_kind_parent ON nodes(kind, parent_id)');
338
- if (!hasColumn(db, 'nodes', 'qualified_name')) {
339
- db.exec('ALTER TABLE nodes ADD COLUMN qualified_name TEXT');
340
- }
341
- if (!hasColumn(db, 'nodes', 'scope')) {
342
- db.exec('ALTER TABLE nodes ADD COLUMN scope TEXT');
343
- }
344
- if (!hasColumn(db, 'nodes', 'visibility')) {
345
- db.exec('ALTER TABLE nodes ADD COLUMN visibility TEXT');
346
- }
347
- db.exec('UPDATE nodes SET qualified_name = name WHERE qualified_name IS NULL');
348
- db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_qualified_name ON nodes(qualified_name)');
349
- db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_scope ON nodes(scope)');
331
+ ensureNodeColumns(db);
350
332
  }
351
333
  if (hasTable(db, 'edges')) {
352
- if (!hasColumn(db, 'edges', 'confidence')) {
353
- db.exec('ALTER TABLE edges ADD COLUMN confidence REAL DEFAULT 1.0');
354
- }
355
- if (!hasColumn(db, 'edges', 'dynamic')) {
356
- db.exec('ALTER TABLE edges ADD COLUMN dynamic INTEGER DEFAULT 0');
357
- }
334
+ ensureEdgeColumns(db);
358
335
  }
359
336
  }
337
+
338
+ function ensureNodeColumns(db: BetterSqlite3Database): void {
339
+ const missing = (col: string) => !hasColumn(db, 'nodes', col);
340
+ if (missing('end_line')) db.exec('ALTER TABLE nodes ADD COLUMN end_line INTEGER');
341
+ if (missing('role')) db.exec('ALTER TABLE nodes ADD COLUMN role TEXT');
342
+ db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_role ON nodes(role)');
343
+ if (missing('parent_id'))
344
+ db.exec('ALTER TABLE nodes ADD COLUMN parent_id INTEGER REFERENCES nodes(id)');
345
+ db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_parent ON nodes(parent_id)');
346
+ db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_kind_parent ON nodes(kind, parent_id)');
347
+ if (missing('qualified_name')) db.exec('ALTER TABLE nodes ADD COLUMN qualified_name TEXT');
348
+ if (missing('scope')) db.exec('ALTER TABLE nodes ADD COLUMN scope TEXT');
349
+ if (missing('visibility')) db.exec('ALTER TABLE nodes ADD COLUMN visibility TEXT');
350
+ db.exec('UPDATE nodes SET qualified_name = name WHERE qualified_name IS NULL');
351
+ db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_qualified_name ON nodes(qualified_name)');
352
+ db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_scope ON nodes(scope)');
353
+ }
354
+
355
+ function ensureEdgeColumns(db: BetterSqlite3Database): void {
356
+ if (!hasColumn(db, 'edges', 'confidence'))
357
+ db.exec('ALTER TABLE edges ADD COLUMN confidence REAL DEFAULT 1.0');
358
+ if (!hasColumn(db, 'edges', 'dynamic'))
359
+ db.exec('ALTER TABLE edges ADD COLUMN dynamic INTEGER DEFAULT 0');
360
+ }
361
+
362
+ export function initSchema(db: BetterSqlite3Database): void {
363
+ applyMigrations(db);
364
+ ensureLegacyColumns(db);
365
+ }
@@ -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,