@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
@@ -3,21 +3,20 @@
3
3
  *
4
4
  * WASM cleanup, stats logging, drift detection, build metadata, registry, journal.
5
5
  */
6
- import fs from 'node:fs';
6
+ import { tmpdir } from 'node:os';
7
7
  import path from 'node:path';
8
8
  import { performance } from 'node:perf_hooks';
9
- import { closeDb, getBuildMeta, setBuildMeta } from '../../../../db/index.js';
9
+ import {
10
+ closeDbPair,
11
+ closeDbPairDeferred,
12
+ getBuildMeta,
13
+ setBuildMeta,
14
+ } from '../../../../db/index.js';
10
15
  import { debug, info, warn } from '../../../../infrastructure/logger.js';
16
+ import { CODEGRAPH_VERSION } from '../../../../shared/version.js';
11
17
  import { writeJournalHeader } from '../../journal.js';
12
18
  import type { PipelineContext } from '../context.js';
13
19
 
14
- const __builderDir = path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/i, '$1'));
15
- const CODEGRAPH_VERSION = (
16
- JSON.parse(
17
- fs.readFileSync(path.join(__builderDir, '..', '..', '..', '..', '..', 'package.json'), 'utf-8'),
18
- ) as { version: string }
19
- ).version;
20
-
21
20
  export async function finalize(ctx: PipelineContext): Promise<void> {
22
21
  const { db, allSymbols, rootDir, isFullBuild, hasEmbeddings, config, opts, schemaVersion } = ctx;
23
22
 
@@ -46,10 +45,15 @@ export async function finalize(ctx: PipelineContext): Promise<void> {
46
45
  info(`Graph built: ${nodeCount} nodes, ${actualEdgeCount} edges`);
47
46
  info(`Stored in ${ctx.dbPath}`);
48
47
 
49
- // Incremental drift detection
50
- if (!isFullBuild) {
51
- const prevNodes = getBuildMeta(db, 'node_count');
52
- const prevEdges = getBuildMeta(db, 'edge_count');
48
+ // Incremental drift detection — skip for small incremental changes where
49
+ // count fluctuation is expected (reverse-dep edge churn).
50
+ if (!isFullBuild && allSymbols.size > 3) {
51
+ const prevNodes = ctx.nativeDb
52
+ ? ctx.nativeDb.getBuildMeta('node_count')
53
+ : getBuildMeta(db, 'node_count');
54
+ const prevEdges = ctx.nativeDb
55
+ ? ctx.nativeDb.getBuildMeta('edge_count')
56
+ : getBuildMeta(db, 'edge_count');
53
57
  if (prevNodes && prevEdges) {
54
58
  const prevN = Number(prevNodes);
55
59
  const prevE = Number(prevEdges);
@@ -67,96 +71,142 @@ export async function finalize(ctx: PipelineContext): Promise<void> {
67
71
  }
68
72
  }
69
73
 
70
- // Persist build metadata early so downstream checks (e.g. stale-embeddings)
71
- // can read the *current* build's built_at rather than the previous one.
72
- try {
73
- setBuildMeta(db, {
74
- engine: ctx.engineName,
75
- engine_version: ctx.engineVersion || '',
76
- codegraph_version: CODEGRAPH_VERSION,
77
- schema_version: String(schemaVersion),
78
- built_at: buildNow.toISOString(),
79
- node_count: nodeCount,
80
- edge_count: actualEdgeCount,
81
- });
82
- } catch (err) {
83
- warn(`Failed to write build metadata: ${(err as Error).message}`);
74
+ // For small incremental builds, skip persisting build metadata — the
75
+ // engine/version/schema haven't changed (would have triggered a full rebuild),
76
+ // built_at is only used by stale-embeddings check (skipped for incremental),
77
+ // and counts are only used by drift detection (skipped for ≤3 files).
78
+ // This avoids a transaction commit + WAL fsync (~15-30ms).
79
+ // Threshold aligned with drift detection gate (allSymbols.size > 3) so stored
80
+ // counts stay fresh whenever drift detection reads them.
81
+ if (isFullBuild || allSymbols.size > 3) {
82
+ try {
83
+ if (ctx.nativeDb) {
84
+ ctx.nativeDb.setBuildMeta(
85
+ Object.entries({
86
+ engine: ctx.engineName,
87
+ engine_version: ctx.engineVersion || '',
88
+ codegraph_version: CODEGRAPH_VERSION,
89
+ schema_version: String(schemaVersion),
90
+ built_at: buildNow.toISOString(),
91
+ node_count: String(nodeCount),
92
+ edge_count: String(actualEdgeCount),
93
+ }).map(([key, value]) => ({ key, value: String(value) })),
94
+ );
95
+ } else {
96
+ setBuildMeta(db, {
97
+ engine: ctx.engineName,
98
+ engine_version: ctx.engineVersion || '',
99
+ codegraph_version: CODEGRAPH_VERSION,
100
+ schema_version: String(schemaVersion),
101
+ built_at: buildNow.toISOString(),
102
+ node_count: nodeCount,
103
+ edge_count: actualEdgeCount,
104
+ });
105
+ }
106
+ } catch (err) {
107
+ warn(`Failed to write build metadata: ${(err as Error).message}`);
108
+ }
84
109
  }
85
110
 
86
- // Orphaned embeddings warning
87
- if (hasEmbeddings) {
111
+ // Skip expensive advisory queries for incremental builds — these are
112
+ // informational warnings that don't affect correctness and cost ~40-60ms.
113
+ if (!isFullBuild) {
114
+ debug(
115
+ 'Finalize: skipping advisory queries (orphaned/stale embeddings, unused exports) for incremental build',
116
+ );
117
+ } else {
118
+ // Orphaned embeddings warning
119
+ if (hasEmbeddings) {
120
+ try {
121
+ const orphaned = (
122
+ db
123
+ .prepare(
124
+ 'SELECT COUNT(*) as c FROM embeddings WHERE node_id NOT IN (SELECT id FROM nodes)',
125
+ )
126
+ .get() as { c: number }
127
+ ).c;
128
+ if (orphaned > 0) {
129
+ warn(
130
+ `${orphaned} embeddings are orphaned (nodes changed). Run "codegraph embed" to refresh.`,
131
+ );
132
+ }
133
+ } catch {
134
+ /* ignore - embeddings table may have been dropped */
135
+ }
136
+ }
137
+
138
+ // Stale embeddings warning (built before current graph rebuild)
139
+ if (hasEmbeddings) {
140
+ try {
141
+ const embedBuiltAt = (
142
+ db.prepare("SELECT value FROM embedding_meta WHERE key = 'built_at'").get() as
143
+ | { value: string }
144
+ | undefined
145
+ )?.value;
146
+ if (embedBuiltAt) {
147
+ const embedTime = new Date(embedBuiltAt).getTime();
148
+ if (!Number.isNaN(embedTime) && embedTime < buildNow.getTime()) {
149
+ warn(
150
+ 'Embeddings were built before the last graph rebuild. Run "codegraph embed" to update.',
151
+ );
152
+ }
153
+ }
154
+ } catch {
155
+ /* ignore - embedding_meta table may not exist */
156
+ }
157
+ }
158
+
159
+ // Unused exports warning
88
160
  try {
89
- const orphaned = (
161
+ const unusedCount = (
90
162
  db
91
163
  .prepare(
92
- 'SELECT COUNT(*) as c FROM embeddings WHERE node_id NOT IN (SELECT id FROM nodes)',
164
+ `SELECT COUNT(*) as c FROM nodes
165
+ WHERE exported = 1 AND kind != 'file'
166
+ AND id NOT IN (
167
+ SELECT DISTINCT e.target_id FROM edges e
168
+ JOIN nodes caller ON e.source_id = caller.id
169
+ JOIN nodes target ON e.target_id = target.id
170
+ WHERE e.kind = 'calls' AND caller.file != target.file
171
+ )`,
93
172
  )
94
173
  .get() as { c: number }
95
174
  ).c;
96
- if (orphaned > 0) {
175
+ if (unusedCount > 0) {
97
176
  warn(
98
- `${orphaned} embeddings are orphaned (nodes changed). Run "codegraph embed" to refresh.`,
177
+ `${unusedCount} exported symbol${unusedCount > 1 ? 's have' : ' has'} zero cross-file consumers. Run "codegraph exports <file> --unused" to inspect.`,
99
178
  );
100
179
  }
101
180
  } catch {
102
- /* ignore - embeddings table may have been dropped */
181
+ /* exported column may not exist on older DBs */
103
182
  }
104
183
  }
105
184
 
106
- // Stale embeddings warning (built before current graph rebuild)
107
- if (hasEmbeddings) {
108
- try {
109
- const embedBuiltAt = (
110
- db.prepare("SELECT value FROM embedding_meta WHERE key = 'built_at'").get() as
111
- | { value: string }
112
- | undefined
113
- )?.value;
114
- if (embedBuiltAt) {
115
- const embedTime = new Date(embedBuiltAt).getTime();
116
- if (!Number.isNaN(embedTime) && embedTime < buildNow.getTime()) {
117
- warn(
118
- 'Embeddings were built before the last graph rebuild. Run "codegraph embed" to update.',
119
- );
120
- }
121
- }
122
- } catch {
123
- /* ignore - embedding_meta table may not exist */
124
- }
125
- }
185
+ // Intentionally measured before closeDb / writeJournalHeader / auto-registration:
186
+ // for the deferred-close path the close is async (setImmediate), and for full
187
+ // builds the metric captures finalize logic only — DB close cost is tracked
188
+ // separately via timing.closeDbMs when available.
189
+ ctx.timing.finalizeMs = performance.now() - t0;
126
190
 
127
- // Unused exports warning
128
- try {
129
- const unusedCount = (
130
- db
131
- .prepare(
132
- `SELECT COUNT(*) as c FROM nodes
133
- WHERE exported = 1 AND kind != 'file'
134
- AND id NOT IN (
135
- SELECT DISTINCT e.target_id FROM edges e
136
- JOIN nodes caller ON e.source_id = caller.id
137
- JOIN nodes target ON e.target_id = target.id
138
- WHERE e.kind = 'calls' AND caller.file != target.file
139
- )`,
140
- )
141
- .get() as { c: number }
142
- ).c;
143
- if (unusedCount > 0) {
144
- warn(
145
- `${unusedCount} exported symbol${unusedCount > 1 ? 's have' : ' has'} zero cross-file consumers. Run "codegraph exports <file> --unused" to inspect.`,
146
- );
147
- }
148
- } catch {
149
- /* exported column may not exist on older DBs */
191
+ // Close NativeDatabase (fast, ~1ms) then better-sqlite3 (WAL checkpoint).
192
+ // For small incremental builds, defer the expensive WAL checkpoint to the
193
+ // next event loop tick. Skip for temp directories (tests) — they rmSync
194
+ // immediately after build.
195
+ const pair = { db, nativeDb: ctx.nativeDb };
196
+ const isTempDir = path.resolve(rootDir).startsWith(path.resolve(tmpdir()));
197
+ if (!isFullBuild && allSymbols.size <= 5 && !isTempDir) {
198
+ closeDbPairDeferred(pair);
199
+ } else {
200
+ closeDbPair(pair);
150
201
  }
151
202
 
152
- closeDb(db);
153
-
154
203
  // Write journal header after successful build
155
204
  writeJournalHeader(rootDir, Date.now());
156
205
 
157
- // Auto-registration
158
- if (!opts.skipRegistry) {
159
- const { tmpdir } = await import('node:os');
206
+ // Skip auto-registration for incremental builds — the repo was already
207
+ // registered during the initial full build. The dynamic import + file I/O
208
+ // costs ~100ms which dominates incremental finalize time.
209
+ if (!opts.skipRegistry && isFullBuild) {
160
210
  const tmpDir = path.resolve(tmpdir());
161
211
  const resolvedRoot = path.resolve(rootDir);
162
212
  if (resolvedRoot.startsWith(tmpDir)) {
@@ -172,6 +222,4 @@ export async function finalize(ctx: PipelineContext): Promise<void> {
172
222
  }
173
223
  }
174
224
  }
175
-
176
- ctx.timing.finalizeMs = performance.now() - t0;
177
225
  }
@@ -3,12 +3,20 @@
3
3
  *
4
4
  * Batch-inserts file nodes, definitions, exports, children, and contains/parameter_of edges.
5
5
  * Updates file hashes for incremental builds.
6
+ *
7
+ * When the native engine is available, delegates all SQLite writes to Rust via
8
+ * `bulkInsertNodes` — eliminating JS↔C boundary overhead. Falls back to the
9
+ * JS implementation on failure or when native is unavailable.
6
10
  */
7
11
  import path from 'node:path';
8
12
  import { performance } from 'node:perf_hooks';
9
- import type BetterSqlite3 from 'better-sqlite3';
10
13
  import { bulkNodeIdsByFile } from '../../../../db/index.js';
11
- import type { ExtractorOutput, MetadataUpdate } from '../../../../types.js';
14
+ import type {
15
+ BetterSqlite3Database,
16
+ ExtractorOutput,
17
+ MetadataUpdate,
18
+ SqliteStatement,
19
+ } from '../../../../types.js';
12
20
  import type { PipelineContext } from '../context.js';
13
21
  import {
14
22
  batchInsertEdges,
@@ -28,10 +36,115 @@ interface PrecomputedFileData {
28
36
  _reverseDepOnly?: boolean;
29
37
  }
30
38
 
31
- // ── Phase 1: Insert file nodes, definitions, exports ────────────────────
39
+ // ── Native fast-path ─────────────────────────────────────────────────
40
+
41
+ function tryNativeInsert(ctx: PipelineContext): boolean {
42
+ // Use NativeDatabase persistent connection (Phase 6.15+).
43
+ // Standalone napi functions were removed in 6.17 — falls through to JS if nativeDb unavailable.
44
+ if (!ctx.nativeDb?.bulkInsertNodes) return false;
45
+
46
+ const { allSymbols, filesToParse, metadataUpdates, rootDir, removed } = ctx;
47
+
48
+ // Marshal allSymbols → InsertNodesBatch[]
49
+ const batches: Array<{
50
+ file: string;
51
+ definitions: Array<{
52
+ name: string;
53
+ kind: string;
54
+ line: number;
55
+ endLine?: number | null;
56
+ visibility?: string | null;
57
+ children: Array<{
58
+ name: string;
59
+ kind: string;
60
+ line: number;
61
+ endLine?: number | null;
62
+ visibility?: string | null;
63
+ }>;
64
+ }>;
65
+ exports: Array<{ name: string; kind: string; line: number }>;
66
+ }> = [];
67
+
68
+ for (const [relPath, symbols] of allSymbols) {
69
+ batches.push({
70
+ file: relPath,
71
+ definitions: symbols.definitions.map((def) => ({
72
+ name: def.name,
73
+ kind: def.kind,
74
+ line: def.line,
75
+ endLine: def.endLine ?? null,
76
+ visibility: def.visibility ?? null,
77
+ children: (def.children ?? []).map((c) => ({
78
+ name: c.name,
79
+ kind: c.kind,
80
+ line: c.line,
81
+ endLine: c.endLine ?? null,
82
+ visibility: c.visibility ?? null,
83
+ })),
84
+ })),
85
+ exports: symbols.exports.map((exp) => ({
86
+ name: exp.name,
87
+ kind: exp.kind,
88
+ line: exp.line,
89
+ })),
90
+ });
91
+ }
92
+
93
+ // Build file hash entries
94
+ const precomputedData = new Map<string, PrecomputedFileData>();
95
+ for (const item of filesToParse) {
96
+ if (item.relPath) precomputedData.set(item.relPath, item as PrecomputedFileData);
97
+ }
98
+
99
+ const fileHashes: Array<{ file: string; hash: string; mtime: number; size: number }> = [];
100
+ for (const [relPath] of allSymbols) {
101
+ const precomputed = precomputedData.get(relPath);
102
+ if (precomputed?._reverseDepOnly) {
103
+ continue; // file unchanged, hash already correct
104
+ }
105
+ if (precomputed?.hash) {
106
+ let mtime: number;
107
+ let size: number;
108
+ if (precomputed.stat) {
109
+ mtime = precomputed.stat.mtime;
110
+ size = precomputed.stat.size;
111
+ } else {
112
+ const rawStat = fileStat(path.join(rootDir, relPath));
113
+ mtime = rawStat ? Math.floor(rawStat.mtimeMs) : 0;
114
+ size = rawStat ? rawStat.size : 0;
115
+ }
116
+ fileHashes.push({ file: relPath, hash: precomputed.hash, mtime, size });
117
+ } else {
118
+ const absPath = path.join(rootDir, relPath);
119
+ let code: string | null;
120
+ try {
121
+ code = readFileSafe(absPath);
122
+ } catch {
123
+ code = null;
124
+ }
125
+ if (code !== null) {
126
+ const stat = fileStat(absPath);
127
+ const mtime = stat ? Math.floor(stat.mtimeMs) : 0;
128
+ const size = stat ? stat.size : 0;
129
+ fileHashes.push({ file: relPath, hash: fileHash(code), mtime, size });
130
+ }
131
+ }
132
+ }
133
+
134
+ // Also include metadata-only updates (self-heal mtime/size without re-parse)
135
+ for (const item of metadataUpdates) {
136
+ const mtime = item.stat ? Math.floor(item.stat.mtime) : 0;
137
+ const size = item.stat ? item.stat.size : 0;
138
+ fileHashes.push({ file: item.relPath, hash: item.hash, mtime, size });
139
+ }
140
+
141
+ return ctx.nativeDb.bulkInsertNodes(batches, fileHashes, removed);
142
+ }
143
+
144
+ // ── JS fallback: Phase 1 ────────────────────────────────────────────
32
145
 
33
146
  function insertDefinitionsAndExports(
34
- db: BetterSqlite3.Database,
147
+ db: BetterSqlite3Database,
35
148
  allSymbols: Map<string, ExtractorOutput>,
36
149
  ): void {
37
150
  const phase1Rows: unknown[][] = [];
@@ -63,7 +176,7 @@ function insertDefinitionsAndExports(
63
176
  // Mark exported symbols in batches (cache prepared statements by chunk size)
64
177
  if (exportKeys.length > 0) {
65
178
  const EXPORT_CHUNK = 500;
66
- const exportStmtCache = new Map<number, BetterSqlite3.Statement>();
179
+ const exportStmtCache = new Map<number, SqliteStatement>();
67
180
  for (let i = 0; i < exportKeys.length; i += EXPORT_CHUNK) {
68
181
  const end = Math.min(i + EXPORT_CHUNK, exportKeys.length);
69
182
  const chunkSize = end - i;
@@ -86,10 +199,10 @@ function insertDefinitionsAndExports(
86
199
  }
87
200
  }
88
201
 
89
- // ── Phase 2+3: Insert children and containment edges (two nodeIdMap passes) ──
202
+ // ── JS fallback: Phase 2+3 ──────────────────────────────────────────
90
203
 
91
204
  function insertChildrenAndEdges(
92
- db: BetterSqlite3.Database,
205
+ db: BetterSqlite3Database,
93
206
  allSymbols: Map<string, ExtractorOutput>,
94
207
  ): void {
95
208
  const childRows: unknown[][] = [];
@@ -161,15 +274,15 @@ function insertChildrenAndEdges(
161
274
  batchInsertEdges(db, edgeRows);
162
275
  }
163
276
 
164
- // ── Phase 4: Update file hashes ─────────────────────────────────────────
277
+ // ── JS fallback: Phase 4 ────────────────────────────────────────────
165
278
 
166
279
  function updateFileHashes(
167
- _db: BetterSqlite3.Database,
280
+ _db: BetterSqlite3Database,
168
281
  allSymbols: Map<string, ExtractorOutput>,
169
282
  precomputedData: Map<string, PrecomputedFileData>,
170
283
  metadataUpdates: MetadataUpdate[],
171
284
  rootDir: string,
172
- upsertHash: BetterSqlite3.Statement | null,
285
+ upsertHash: SqliteStatement | null,
173
286
  ): void {
174
287
  if (!upsertHash) return;
175
288
 
@@ -214,17 +327,33 @@ function updateFileHashes(
214
327
  }
215
328
  }
216
329
 
217
- // ── Main entry point ────────────────────────────────────────────────────
330
+ // ── Main entry point ────────────────────────────────────────────────
218
331
 
219
332
  export async function insertNodes(ctx: PipelineContext): Promise<void> {
220
333
  const { db, allSymbols, filesToParse, metadataUpdates, rootDir, removed } = ctx;
221
334
 
335
+ // Populate fileSymbols before any DB writes (used by later stages)
336
+ for (const [relPath, symbols] of allSymbols) {
337
+ ctx.fileSymbols.set(relPath, symbols);
338
+ }
339
+
340
+ const t0 = performance.now();
341
+
342
+ // Try native Rust path first — single transaction, no JS↔C overhead
343
+ if (ctx.engineName === 'native' && tryNativeInsert(ctx)) {
344
+ ctx.timing.insertMs = performance.now() - t0;
345
+
346
+ // Removed-file hash cleanup is handled inside the native call
347
+ return;
348
+ }
349
+
350
+ // JS fallback
222
351
  const precomputedData = new Map<string, PrecomputedFileData>();
223
352
  for (const item of filesToParse) {
224
353
  if (item.relPath) precomputedData.set(item.relPath, item as PrecomputedFileData);
225
354
  }
226
355
 
227
- let upsertHash: BetterSqlite3.Statement | null;
356
+ let upsertHash: SqliteStatement | null;
228
357
  try {
229
358
  upsertHash = db.prepare(
230
359
  'INSERT OR REPLACE INTO file_hashes (file, hash, mtime, size) VALUES (?, ?, ?, ?)',
@@ -233,18 +362,12 @@ export async function insertNodes(ctx: PipelineContext): Promise<void> {
233
362
  upsertHash = null;
234
363
  }
235
364
 
236
- // Populate fileSymbols before the transaction so it is a pure input
237
- for (const [relPath, symbols] of allSymbols) {
238
- ctx.fileSymbols.set(relPath, symbols);
239
- }
240
-
241
365
  const insertAll = db.transaction(() => {
242
366
  insertDefinitionsAndExports(db, allSymbols);
243
367
  insertChildrenAndEdges(db, allSymbols);
244
368
  updateFileHashes(db, allSymbols, precomputedData, metadataUpdates, rootDir, upsertHash);
245
369
  });
246
370
 
247
- const t0 = performance.now();
248
371
  insertAll();
249
372
  ctx.timing.insertMs = performance.now() - t0;
250
373
 
@@ -41,18 +41,83 @@ export async function resolveImports(ctx: PipelineContext): Promise<void> {
41
41
 
42
42
  ctx.barrelOnlyFiles = new Set<string>();
43
43
  if (!isFullBuild) {
44
- const barrelCandidates = db
45
- .prepare(`SELECT DISTINCT n1.file FROM edges e
44
+ // Collect the set of changed file paths to scope barrel re-parsing.
45
+ const changedRelPaths = new Set<string>(fileSymbols.keys());
46
+
47
+ // For small incremental builds (≤5 files), only re-parse barrel files
48
+ // that are related to the changed files — either re-exporting from them
49
+ // or imported by them. For larger changes, re-parse all barrels.
50
+ let barrelCandidates: Array<{ file: string }>;
51
+ if (changedRelPaths.size <= 5) {
52
+ // All known barrel files (has at least one reexport edge)
53
+ const allBarrelFiles = new Set(
54
+ (
55
+ db
56
+ .prepare(
57
+ `SELECT DISTINCT n1.file FROM edges e
58
+ JOIN nodes n1 ON e.source_id = n1.id
59
+ WHERE e.kind = 'reexports' AND n1.kind = 'file'`,
60
+ )
61
+ .all() as Array<{ file: string }>
62
+ ).map((r) => r.file),
63
+ );
64
+
65
+ const barrels = new Set<string>();
66
+
67
+ // Find barrels imported by changed files using parsed import data
68
+ // (can't query DB edges — they were purged for the changed files).
69
+ for (const relPath of changedRelPaths) {
70
+ const symbols = fileSymbols.get(relPath);
71
+ if (!symbols) continue;
72
+ for (const imp of symbols.imports) {
73
+ const resolved = ctx.batchResolved?.get(`${path.join(rootDir, relPath)}|${imp.source}`);
74
+ const target =
75
+ resolved ??
76
+ resolveImportPath(path.join(rootDir, relPath), imp.source, rootDir, aliases);
77
+ if (allBarrelFiles.has(target)) barrels.add(target);
78
+ }
79
+ }
80
+
81
+ // Also find barrels that re-export from the changed files
82
+ const reexportSourceStmt = db.prepare(
83
+ `SELECT DISTINCT n1.file FROM edges e
46
84
  JOIN nodes n1 ON e.source_id = n1.id
47
- WHERE e.kind = 'reexports' AND n1.kind = 'file'`)
48
- .all() as Array<{ file: string }>;
85
+ JOIN nodes n2 ON e.target_id = n2.id
86
+ WHERE e.kind = 'reexports' AND n1.kind = 'file' AND n2.file = ?`,
87
+ );
88
+ for (const relPath of changedRelPaths) {
89
+ for (const row of reexportSourceStmt.all(relPath) as Array<{ file: string }>) {
90
+ barrels.add(row.file);
91
+ }
92
+ }
93
+ barrelCandidates = [...barrels].map((file) => ({ file }));
94
+ } else {
95
+ barrelCandidates = db
96
+ .prepare(
97
+ `SELECT DISTINCT n1.file FROM edges e
98
+ JOIN nodes n1 ON e.source_id = n1.id
99
+ WHERE e.kind = 'reexports' AND n1.kind = 'file'`,
100
+ )
101
+ .all() as Array<{ file: string }>;
102
+ }
103
+
104
+ // Batch-parse all barrel candidates at once instead of one-by-one
105
+ const barrelPaths: string[] = [];
49
106
  for (const { file: relPath } of barrelCandidates) {
50
- if (fileSymbols.has(relPath)) continue;
51
- const absPath = path.join(rootDir, relPath);
107
+ if (!fileSymbols.has(relPath)) {
108
+ barrelPaths.push(path.join(rootDir, relPath));
109
+ }
110
+ }
111
+
112
+ if (barrelPaths.length > 0) {
113
+ const deleteOutgoingEdges = db.prepare(
114
+ 'DELETE FROM edges WHERE source_id IN (SELECT id FROM nodes WHERE file = ?)',
115
+ );
116
+
52
117
  try {
53
- const symbols = await parseFilesAuto([absPath], rootDir, engineOpts);
54
- const fileSym = symbols.get(relPath);
55
- if (fileSym) {
118
+ const barrelSymbols = await parseFilesAuto(barrelPaths, rootDir, engineOpts);
119
+ for (const [relPath, fileSym] of barrelSymbols) {
120
+ deleteOutgoingEdges.run(relPath);
56
121
  fileSymbols.set(relPath, fileSym);
57
122
  ctx.barrelOnlyFiles.add(relPath);
58
123
  const reexports = fileSym.imports.filter((imp: Import) => imp.reexport);
@@ -60,7 +125,7 @@ export async function resolveImports(ctx: PipelineContext): Promise<void> {
60
125
  ctx.reexportMap.set(
61
126
  relPath,
62
127
  reexports.map((imp: Import) => ({
63
- source: getResolved(ctx, absPath, imp.source),
128
+ source: getResolved(ctx, path.join(rootDir, relPath), imp.source),
64
129
  names: imp.names,
65
130
  wildcardReexport: imp.wildcardReexport || false,
66
131
  })),
@@ -16,9 +16,9 @@ export function findCycles(
16
16
  const idToLabel = new Map<string, string>();
17
17
  for (const [id, attrs] of graph.nodes()) {
18
18
  if (fileLevel) {
19
- idToLabel.set(id, attrs['file'] as string);
19
+ idToLabel.set(id, attrs.file as string);
20
20
  } else {
21
- idToLabel.set(id, `${attrs['label']}|${attrs['file']}`);
21
+ idToLabel.set(id, `${attrs.label}|${attrs.file}`);
22
22
  }
23
23
  }
24
24