@optave/codegraph 3.12.0 → 3.15.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 (524) hide show
  1. package/README.md +83 -46
  2. package/dist/ast-analysis/engine.d.ts.map +1 -1
  3. package/dist/ast-analysis/engine.js +38 -40
  4. package/dist/ast-analysis/engine.js.map +1 -1
  5. package/dist/ast-analysis/rules/b2.d.ts +7 -0
  6. package/dist/ast-analysis/rules/b2.d.ts.map +1 -0
  7. package/dist/ast-analysis/rules/b2.js +240 -0
  8. package/dist/ast-analysis/rules/b2.js.map +1 -0
  9. package/dist/ast-analysis/rules/b3.d.ts +6 -0
  10. package/dist/ast-analysis/rules/b3.d.ts.map +1 -0
  11. package/dist/ast-analysis/rules/b3.js +105 -0
  12. package/dist/ast-analysis/rules/b3.js.map +1 -0
  13. package/dist/ast-analysis/rules/b4.d.ts +9 -0
  14. package/dist/ast-analysis/rules/b4.d.ts.map +1 -0
  15. package/dist/ast-analysis/rules/b4.js +361 -0
  16. package/dist/ast-analysis/rules/b4.js.map +1 -0
  17. package/dist/ast-analysis/rules/b5.d.ts +4 -0
  18. package/dist/ast-analysis/rules/b5.d.ts.map +1 -0
  19. package/dist/ast-analysis/rules/b5.js +52 -0
  20. package/dist/ast-analysis/rules/b5.js.map +1 -0
  21. package/dist/ast-analysis/rules/c.d.ts +4 -0
  22. package/dist/ast-analysis/rules/c.d.ts.map +1 -0
  23. package/dist/ast-analysis/rules/c.js +143 -0
  24. package/dist/ast-analysis/rules/c.js.map +1 -0
  25. package/dist/ast-analysis/rules/index.d.ts.map +1 -1
  26. package/dist/ast-analysis/rules/index.js +34 -0
  27. package/dist/ast-analysis/rules/index.js.map +1 -1
  28. package/dist/ast-analysis/rules/javascript.d.ts.map +1 -1
  29. package/dist/ast-analysis/rules/javascript.js +3 -0
  30. package/dist/ast-analysis/rules/javascript.js.map +1 -1
  31. package/dist/ast-analysis/shared.d.ts.map +1 -1
  32. package/dist/ast-analysis/shared.js +2 -0
  33. package/dist/ast-analysis/shared.js.map +1 -1
  34. package/dist/ast-analysis/visitor-utils.d.ts +1 -0
  35. package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
  36. package/dist/ast-analysis/visitor-utils.js +5 -0
  37. package/dist/ast-analysis/visitor-utils.js.map +1 -1
  38. package/dist/ast-analysis/visitor.d.ts.map +1 -1
  39. package/dist/ast-analysis/visitor.js +60 -47
  40. package/dist/ast-analysis/visitor.js.map +1 -1
  41. package/dist/ast-analysis/visitors/cfg-visitor.d.ts.map +1 -1
  42. package/dist/ast-analysis/visitors/cfg-visitor.js +126 -76
  43. package/dist/ast-analysis/visitors/cfg-visitor.js.map +1 -1
  44. package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
  45. package/dist/ast-analysis/visitors/complexity-visitor.js +27 -15
  46. package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
  47. package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
  48. package/dist/ast-analysis/visitors/dataflow-visitor.js +54 -21
  49. package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
  50. package/dist/cli/commands/audit.d.ts.map +1 -1
  51. package/dist/cli/commands/audit.js +2 -1
  52. package/dist/cli/commands/audit.js.map +1 -1
  53. package/dist/cli/commands/batch.d.ts.map +1 -1
  54. package/dist/cli/commands/batch.js +1 -0
  55. package/dist/cli/commands/batch.js.map +1 -1
  56. package/dist/cli/commands/build.d.ts.map +1 -1
  57. package/dist/cli/commands/build.js +6 -1
  58. package/dist/cli/commands/build.js.map +1 -1
  59. package/dist/cli/commands/config.d.ts +3 -0
  60. package/dist/cli/commands/config.d.ts.map +1 -0
  61. package/dist/cli/commands/config.js +275 -0
  62. package/dist/cli/commands/config.js.map +1 -0
  63. package/dist/cli/commands/roles.d.ts.map +1 -1
  64. package/dist/cli/commands/roles.js +6 -1
  65. package/dist/cli/commands/roles.js.map +1 -1
  66. package/dist/cli/commands/triage.js +1 -1
  67. package/dist/cli/commands/triage.js.map +1 -1
  68. package/dist/cli/index.d.ts.map +1 -1
  69. package/dist/cli/index.js +10 -0
  70. package/dist/cli/index.js.map +1 -1
  71. package/dist/cli/shared/options.d.ts +2 -1
  72. package/dist/cli/shared/options.d.ts.map +1 -1
  73. package/dist/cli/shared/options.js +11 -1
  74. package/dist/cli/shared/options.js.map +1 -1
  75. package/dist/cli/types.d.ts +2 -0
  76. package/dist/cli/types.d.ts.map +1 -1
  77. package/dist/db/better-sqlite3.d.ts +2 -1
  78. package/dist/db/better-sqlite3.d.ts.map +1 -1
  79. package/dist/db/better-sqlite3.js.map +1 -1
  80. package/dist/db/connection.d.ts +7 -1
  81. package/dist/db/connection.d.ts.map +1 -1
  82. package/dist/db/connection.js +20 -5
  83. package/dist/db/connection.js.map +1 -1
  84. package/dist/db/index.d.ts +1 -1
  85. package/dist/db/index.d.ts.map +1 -1
  86. package/dist/db/index.js +1 -1
  87. package/dist/db/index.js.map +1 -1
  88. package/dist/db/migrations.d.ts.map +1 -1
  89. package/dist/db/migrations.js +69 -1
  90. package/dist/db/migrations.js.map +1 -1
  91. package/dist/db/repository/build-stmts.d.ts.map +1 -1
  92. package/dist/db/repository/build-stmts.js +18 -0
  93. package/dist/db/repository/build-stmts.js.map +1 -1
  94. package/dist/db/repository/dataflow.d.ts +5 -0
  95. package/dist/db/repository/dataflow.d.ts.map +1 -1
  96. package/dist/db/repository/dataflow.js +14 -0
  97. package/dist/db/repository/dataflow.js.map +1 -1
  98. package/dist/db/repository/index.d.ts +1 -1
  99. package/dist/db/repository/index.d.ts.map +1 -1
  100. package/dist/db/repository/index.js +1 -1
  101. package/dist/db/repository/index.js.map +1 -1
  102. package/dist/db/repository/native-repository.d.ts.map +1 -1
  103. package/dist/db/repository/native-repository.js +47 -34
  104. package/dist/db/repository/native-repository.js.map +1 -1
  105. package/dist/domain/analysis/context.d.ts +2 -2
  106. package/dist/domain/analysis/dependencies.d.ts +2 -2
  107. package/dist/domain/analysis/diff-impact.d.ts +2 -2
  108. package/dist/domain/analysis/fn-impact.d.ts +3 -1
  109. package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
  110. package/dist/domain/analysis/fn-impact.js +4 -0
  111. package/dist/domain/analysis/fn-impact.js.map +1 -1
  112. package/dist/domain/analysis/implementations.d.ts +2 -2
  113. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  114. package/dist/domain/analysis/module-map.js +32 -5
  115. package/dist/domain/analysis/module-map.js.map +1 -1
  116. package/dist/domain/analysis/roles.d.ts +7 -1
  117. package/dist/domain/analysis/roles.d.ts.map +1 -1
  118. package/dist/domain/analysis/roles.js +16 -0
  119. package/dist/domain/analysis/roles.js.map +1 -1
  120. package/dist/domain/analysis/symbol-lookup.d.ts +4 -4
  121. package/dist/domain/graph/builder/call-resolver.d.ts +29 -13
  122. package/dist/domain/graph/builder/call-resolver.d.ts.map +1 -1
  123. package/dist/domain/graph/builder/call-resolver.js +125 -205
  124. package/dist/domain/graph/builder/call-resolver.js.map +1 -1
  125. package/dist/domain/graph/builder/cha.d.ts +9 -1
  126. package/dist/domain/graph/builder/cha.d.ts.map +1 -1
  127. package/dist/domain/graph/builder/cha.js +17 -2
  128. package/dist/domain/graph/builder/cha.js.map +1 -1
  129. package/dist/domain/graph/builder/context.d.ts +1 -0
  130. package/dist/domain/graph/builder/context.d.ts.map +1 -1
  131. package/dist/domain/graph/builder/context.js.map +1 -1
  132. package/dist/domain/graph/builder/helpers.d.ts +24 -1
  133. package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
  134. package/dist/domain/graph/builder/helpers.js +174 -65
  135. package/dist/domain/graph/builder/helpers.js.map +1 -1
  136. package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
  137. package/dist/domain/graph/builder/incremental.js +166 -97
  138. package/dist/domain/graph/builder/incremental.js.map +1 -1
  139. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  140. package/dist/domain/graph/builder/pipeline.js +46 -5
  141. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  142. package/dist/domain/graph/builder/stages/build-edges.d.ts +0 -2
  143. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  144. package/dist/domain/graph/builder/stages/build-edges.js +554 -538
  145. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  146. package/dist/domain/graph/builder/stages/collect-files.d.ts.map +1 -1
  147. package/dist/domain/graph/builder/stages/collect-files.js +10 -7
  148. package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
  149. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  150. package/dist/domain/graph/builder/stages/detect-changes.js +3 -2
  151. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  152. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
  153. package/dist/domain/graph/builder/stages/finalize.js +4 -0
  154. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  155. package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -1
  156. package/dist/domain/graph/builder/stages/native-orchestrator.js +952 -343
  157. package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -1
  158. package/dist/domain/graph/builder/stages/resolve-imports.js +1 -1
  159. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  160. package/dist/domain/graph/resolver/points-to.d.ts.map +1 -1
  161. package/dist/domain/graph/resolver/points-to.js +105 -57
  162. package/dist/domain/graph/resolver/points-to.js.map +1 -1
  163. package/dist/domain/graph/resolver/strategy.d.ts +61 -0
  164. package/dist/domain/graph/resolver/strategy.d.ts.map +1 -0
  165. package/dist/domain/graph/resolver/strategy.js +222 -0
  166. package/dist/domain/graph/resolver/strategy.js.map +1 -0
  167. package/dist/domain/graph/watcher.d.ts.map +1 -1
  168. package/dist/domain/graph/watcher.js +16 -9
  169. package/dist/domain/graph/watcher.js.map +1 -1
  170. package/dist/domain/parser.d.ts +16 -5
  171. package/dist/domain/parser.d.ts.map +1 -1
  172. package/dist/domain/parser.js +58 -17
  173. package/dist/domain/parser.js.map +1 -1
  174. package/dist/domain/queries.d.ts +1 -1
  175. package/dist/domain/queries.d.ts.map +1 -1
  176. package/dist/domain/queries.js +1 -1
  177. package/dist/domain/queries.js.map +1 -1
  178. package/dist/domain/wasm-worker-entry.js +13 -2
  179. package/dist/domain/wasm-worker-entry.js.map +1 -1
  180. package/dist/domain/wasm-worker-pool.d.ts.map +1 -1
  181. package/dist/domain/wasm-worker-pool.js +26 -5
  182. package/dist/domain/wasm-worker-pool.js.map +1 -1
  183. package/dist/domain/wasm-worker-protocol.d.ts +8 -0
  184. package/dist/domain/wasm-worker-protocol.d.ts.map +1 -1
  185. package/dist/extractors/cpp.d.ts.map +1 -1
  186. package/dist/extractors/cpp.js +42 -1
  187. package/dist/extractors/cpp.js.map +1 -1
  188. package/dist/extractors/cuda.d.ts.map +1 -1
  189. package/dist/extractors/cuda.js +42 -1
  190. package/dist/extractors/cuda.js.map +1 -1
  191. package/dist/extractors/dart.js +48 -3
  192. package/dist/extractors/dart.js.map +1 -1
  193. package/dist/extractors/groovy.js +62 -3
  194. package/dist/extractors/groovy.js.map +1 -1
  195. package/dist/extractors/helpers.d.ts +15 -2
  196. package/dist/extractors/helpers.d.ts.map +1 -1
  197. package/dist/extractors/helpers.js +45 -1
  198. package/dist/extractors/helpers.js.map +1 -1
  199. package/dist/extractors/java.d.ts.map +1 -1
  200. package/dist/extractors/java.js +85 -8
  201. package/dist/extractors/java.js.map +1 -1
  202. package/dist/extractors/javascript.d.ts.map +1 -1
  203. package/dist/extractors/javascript.js +686 -169
  204. package/dist/extractors/javascript.js.map +1 -1
  205. package/dist/extractors/kotlin.js +58 -3
  206. package/dist/extractors/kotlin.js.map +1 -1
  207. package/dist/extractors/objc.js +25 -2
  208. package/dist/extractors/objc.js.map +1 -1
  209. package/dist/extractors/scala.js +62 -2
  210. package/dist/extractors/scala.js.map +1 -1
  211. package/dist/extractors/swift.js +52 -3
  212. package/dist/extractors/swift.js.map +1 -1
  213. package/dist/features/audit.js +26 -23
  214. package/dist/features/audit.js.map +1 -1
  215. package/dist/features/boundaries.d.ts.map +1 -1
  216. package/dist/features/boundaries.js +12 -9
  217. package/dist/features/boundaries.js.map +1 -1
  218. package/dist/features/cfg.d.ts.map +1 -1
  219. package/dist/features/cfg.js +25 -18
  220. package/dist/features/cfg.js.map +1 -1
  221. package/dist/features/check.d.ts.map +1 -1
  222. package/dist/features/check.js +18 -5
  223. package/dist/features/check.js.map +1 -1
  224. package/dist/features/communities.d.ts +4 -2
  225. package/dist/features/communities.d.ts.map +1 -1
  226. package/dist/features/communities.js +6 -4
  227. package/dist/features/communities.js.map +1 -1
  228. package/dist/features/dataflow.d.ts +60 -0
  229. package/dist/features/dataflow.d.ts.map +1 -1
  230. package/dist/features/dataflow.js +530 -6
  231. package/dist/features/dataflow.js.map +1 -1
  232. package/dist/features/manifesto.d.ts.map +1 -1
  233. package/dist/features/manifesto.js +59 -72
  234. package/dist/features/manifesto.js.map +1 -1
  235. package/dist/features/sequence.d.ts.map +1 -1
  236. package/dist/features/sequence.js +27 -22
  237. package/dist/features/sequence.js.map +1 -1
  238. package/dist/features/snapshot.d.ts.map +1 -1
  239. package/dist/features/snapshot.js +36 -28
  240. package/dist/features/snapshot.js.map +1 -1
  241. package/dist/features/structure-query.d.ts +1 -1
  242. package/dist/features/structure-query.d.ts.map +1 -1
  243. package/dist/features/structure-query.js +6 -6
  244. package/dist/features/structure-query.js.map +1 -1
  245. package/dist/features/structure.d.ts.map +1 -1
  246. package/dist/features/structure.js +150 -62
  247. package/dist/features/structure.js.map +1 -1
  248. package/dist/features/triage.d.ts.map +1 -1
  249. package/dist/features/triage.js +18 -11
  250. package/dist/features/triage.js.map +1 -1
  251. package/dist/graph/algorithms/bfs.d.ts +1 -1
  252. package/dist/graph/algorithms/bfs.d.ts.map +1 -1
  253. package/dist/graph/algorithms/bfs.js +14 -13
  254. package/dist/graph/algorithms/bfs.js.map +1 -1
  255. package/dist/graph/algorithms/tarjan.d.ts.map +1 -1
  256. package/dist/graph/algorithms/tarjan.js +5 -0
  257. package/dist/graph/algorithms/tarjan.js.map +1 -1
  258. package/dist/graph/builders/dependency.js +28 -22
  259. package/dist/graph/builders/dependency.js.map +1 -1
  260. package/dist/graph/classifiers/roles.d.ts +10 -1
  261. package/dist/graph/classifiers/roles.d.ts.map +1 -1
  262. package/dist/graph/classifiers/roles.js +60 -6
  263. package/dist/graph/classifiers/roles.js.map +1 -1
  264. package/dist/index.d.ts +1 -1
  265. package/dist/index.d.ts.map +1 -1
  266. package/dist/index.js +1 -1
  267. package/dist/index.js.map +1 -1
  268. package/dist/infrastructure/config.d.ts +87 -4
  269. package/dist/infrastructure/config.d.ts.map +1 -1
  270. package/dist/infrastructure/config.js +424 -22
  271. package/dist/infrastructure/config.js.map +1 -1
  272. package/dist/infrastructure/registry.d.ts +27 -7
  273. package/dist/infrastructure/registry.d.ts.map +1 -1
  274. package/dist/infrastructure/registry.js +79 -5
  275. package/dist/infrastructure/registry.js.map +1 -1
  276. package/dist/infrastructure/update-check.d.ts.map +1 -1
  277. package/dist/infrastructure/update-check.js +49 -31
  278. package/dist/infrastructure/update-check.js.map +1 -1
  279. package/dist/mcp/server.d.ts +2 -10
  280. package/dist/mcp/server.d.ts.map +1 -1
  281. package/dist/mcp/server.js.map +1 -1
  282. package/dist/mcp/tools/ast-query.d.ts +1 -1
  283. package/dist/mcp/tools/ast-query.d.ts.map +1 -1
  284. package/dist/mcp/tools/audit.d.ts +1 -1
  285. package/dist/mcp/tools/audit.d.ts.map +1 -1
  286. package/dist/mcp/tools/batch-query.d.ts +1 -1
  287. package/dist/mcp/tools/batch-query.d.ts.map +1 -1
  288. package/dist/mcp/tools/branch-compare.d.ts +1 -1
  289. package/dist/mcp/tools/branch-compare.d.ts.map +1 -1
  290. package/dist/mcp/tools/brief.d.ts +1 -1
  291. package/dist/mcp/tools/brief.d.ts.map +1 -1
  292. package/dist/mcp/tools/cfg.d.ts +1 -1
  293. package/dist/mcp/tools/cfg.d.ts.map +1 -1
  294. package/dist/mcp/tools/check.d.ts +1 -1
  295. package/dist/mcp/tools/check.d.ts.map +1 -1
  296. package/dist/mcp/tools/co-changes.d.ts +1 -1
  297. package/dist/mcp/tools/co-changes.d.ts.map +1 -1
  298. package/dist/mcp/tools/code-owners.d.ts +1 -1
  299. package/dist/mcp/tools/code-owners.d.ts.map +1 -1
  300. package/dist/mcp/tools/communities.d.ts +1 -1
  301. package/dist/mcp/tools/communities.d.ts.map +1 -1
  302. package/dist/mcp/tools/complexity.d.ts +1 -1
  303. package/dist/mcp/tools/complexity.d.ts.map +1 -1
  304. package/dist/mcp/tools/context.d.ts +1 -1
  305. package/dist/mcp/tools/context.d.ts.map +1 -1
  306. package/dist/mcp/tools/dataflow.d.ts +1 -1
  307. package/dist/mcp/tools/dataflow.d.ts.map +1 -1
  308. package/dist/mcp/tools/diff-impact.d.ts +1 -1
  309. package/dist/mcp/tools/diff-impact.d.ts.map +1 -1
  310. package/dist/mcp/tools/execution-flow.d.ts +1 -1
  311. package/dist/mcp/tools/execution-flow.d.ts.map +1 -1
  312. package/dist/mcp/tools/export-graph.d.ts +1 -1
  313. package/dist/mcp/tools/export-graph.d.ts.map +1 -1
  314. package/dist/mcp/tools/file-deps.d.ts +1 -1
  315. package/dist/mcp/tools/file-deps.d.ts.map +1 -1
  316. package/dist/mcp/tools/file-exports.d.ts +1 -1
  317. package/dist/mcp/tools/file-exports.d.ts.map +1 -1
  318. package/dist/mcp/tools/find-cycles.d.ts +1 -1
  319. package/dist/mcp/tools/find-cycles.d.ts.map +1 -1
  320. package/dist/mcp/tools/fn-impact.d.ts +1 -1
  321. package/dist/mcp/tools/fn-impact.d.ts.map +1 -1
  322. package/dist/mcp/tools/impact-analysis.d.ts +1 -1
  323. package/dist/mcp/tools/impact-analysis.d.ts.map +1 -1
  324. package/dist/mcp/tools/implementations.d.ts +1 -1
  325. package/dist/mcp/tools/implementations.d.ts.map +1 -1
  326. package/dist/mcp/tools/index.d.ts +2 -5
  327. package/dist/mcp/tools/index.d.ts.map +1 -1
  328. package/dist/mcp/tools/index.js.map +1 -1
  329. package/dist/mcp/tools/interfaces.d.ts +1 -1
  330. package/dist/mcp/tools/interfaces.d.ts.map +1 -1
  331. package/dist/mcp/tools/list-functions.d.ts +1 -1
  332. package/dist/mcp/tools/list-functions.d.ts.map +1 -1
  333. package/dist/mcp/tools/list-repos.d.ts +1 -1
  334. package/dist/mcp/tools/list-repos.d.ts.map +1 -1
  335. package/dist/mcp/tools/module-map.d.ts +1 -1
  336. package/dist/mcp/tools/module-map.d.ts.map +1 -1
  337. package/dist/mcp/tools/node-roles.d.ts +1 -1
  338. package/dist/mcp/tools/node-roles.d.ts.map +1 -1
  339. package/dist/mcp/tools/path.d.ts +1 -1
  340. package/dist/mcp/tools/path.d.ts.map +1 -1
  341. package/dist/mcp/tools/query.d.ts +1 -1
  342. package/dist/mcp/tools/query.d.ts.map +1 -1
  343. package/dist/mcp/tools/semantic-search.d.ts +1 -1
  344. package/dist/mcp/tools/semantic-search.d.ts.map +1 -1
  345. package/dist/mcp/tools/sequence.d.ts +1 -1
  346. package/dist/mcp/tools/sequence.d.ts.map +1 -1
  347. package/dist/mcp/tools/structure.d.ts +1 -1
  348. package/dist/mcp/tools/structure.d.ts.map +1 -1
  349. package/dist/mcp/tools/symbol-children.d.ts +1 -1
  350. package/dist/mcp/tools/symbol-children.d.ts.map +1 -1
  351. package/dist/mcp/tools/triage.d.ts +1 -1
  352. package/dist/mcp/tools/triage.d.ts.map +1 -1
  353. package/dist/mcp/tools/where.d.ts +1 -1
  354. package/dist/mcp/tools/where.d.ts.map +1 -1
  355. package/dist/mcp/types.d.ts +19 -0
  356. package/dist/mcp/types.d.ts.map +1 -0
  357. package/dist/mcp/types.js +6 -0
  358. package/dist/mcp/types.js.map +1 -0
  359. package/dist/presentation/queries-cli/index.d.ts +1 -1
  360. package/dist/presentation/queries-cli/index.d.ts.map +1 -1
  361. package/dist/presentation/queries-cli/index.js +1 -1
  362. package/dist/presentation/queries-cli/index.js.map +1 -1
  363. package/dist/presentation/queries-cli/overview.d.ts +1 -0
  364. package/dist/presentation/queries-cli/overview.d.ts.map +1 -1
  365. package/dist/presentation/queries-cli/overview.js +20 -1
  366. package/dist/presentation/queries-cli/overview.js.map +1 -1
  367. package/dist/presentation/queries-cli.d.ts +1 -1
  368. package/dist/presentation/queries-cli.d.ts.map +1 -1
  369. package/dist/presentation/queries-cli.js +1 -1
  370. package/dist/presentation/queries-cli.js.map +1 -1
  371. package/dist/presentation/structure.d.ts +1 -1
  372. package/dist/presentation/structure.d.ts.map +1 -1
  373. package/dist/presentation/structure.js +2 -2
  374. package/dist/presentation/structure.js.map +1 -1
  375. package/dist/presentation/viewer.d.ts.map +1 -1
  376. package/dist/presentation/viewer.js +45 -32
  377. package/dist/presentation/viewer.js.map +1 -1
  378. package/dist/shared/constants.d.ts +21 -0
  379. package/dist/shared/constants.d.ts.map +1 -1
  380. package/dist/shared/constants.js +25 -0
  381. package/dist/shared/constants.js.map +1 -1
  382. package/dist/shared/normalize.d.ts.map +1 -1
  383. package/dist/shared/normalize.js +12 -22
  384. package/dist/shared/normalize.js.map +1 -1
  385. package/dist/shared/paginate.d.ts +4 -17
  386. package/dist/shared/paginate.d.ts.map +1 -1
  387. package/dist/shared/paginate.js.map +1 -1
  388. package/dist/types.d.ts +113 -1
  389. package/dist/types.d.ts.map +1 -1
  390. package/grammars/tree-sitter-erlang.wasm +0 -0
  391. package/grammars/tree-sitter-gleam.wasm +0 -0
  392. package/package.json +7 -8
  393. package/src/ast-analysis/engine.ts +43 -63
  394. package/src/ast-analysis/rules/b2.ts +263 -0
  395. package/src/ast-analysis/rules/b3.ts +127 -0
  396. package/src/ast-analysis/rules/b4.ts +378 -0
  397. package/src/ast-analysis/rules/b5.ts +65 -0
  398. package/src/ast-analysis/rules/c.ts +157 -0
  399. package/src/ast-analysis/rules/index.ts +34 -0
  400. package/src/ast-analysis/rules/javascript.ts +3 -0
  401. package/src/ast-analysis/shared.ts +2 -0
  402. package/src/ast-analysis/visitor-utils.ts +5 -0
  403. package/src/ast-analysis/visitor.ts +82 -52
  404. package/src/ast-analysis/visitors/cfg-visitor.ts +198 -84
  405. package/src/ast-analysis/visitors/complexity-visitor.ts +44 -16
  406. package/src/ast-analysis/visitors/dataflow-visitor.ts +68 -29
  407. package/src/cli/commands/audit.ts +2 -1
  408. package/src/cli/commands/batch.ts +1 -0
  409. package/src/cli/commands/build.ts +6 -1
  410. package/src/cli/commands/config.ts +353 -0
  411. package/src/cli/commands/roles.ts +6 -1
  412. package/src/cli/commands/triage.ts +1 -1
  413. package/src/cli/index.ts +10 -0
  414. package/src/cli/shared/options.ts +11 -1
  415. package/src/cli/types.ts +2 -0
  416. package/src/db/better-sqlite3.ts +5 -4
  417. package/src/db/connection.ts +23 -5
  418. package/src/db/index.ts +1 -0
  419. package/src/db/migrations.ts +69 -1
  420. package/src/db/repository/build-stmts.ts +30 -0
  421. package/src/db/repository/dataflow.ts +16 -0
  422. package/src/db/repository/index.ts +1 -1
  423. package/src/db/repository/native-repository.ts +56 -40
  424. package/src/domain/analysis/fn-impact.ts +4 -0
  425. package/src/domain/analysis/module-map.ts +38 -6
  426. package/src/domain/analysis/roles.ts +23 -0
  427. package/src/domain/graph/builder/call-resolver.ts +156 -218
  428. package/src/domain/graph/builder/cha.ts +18 -1
  429. package/src/domain/graph/builder/context.ts +1 -0
  430. package/src/domain/graph/builder/helpers.ts +205 -67
  431. package/src/domain/graph/builder/incremental.ts +249 -119
  432. package/src/domain/graph/builder/pipeline.ts +59 -6
  433. package/src/domain/graph/builder/stages/build-edges.ts +783 -652
  434. package/src/domain/graph/builder/stages/collect-files.ts +12 -6
  435. package/src/domain/graph/builder/stages/detect-changes.ts +4 -2
  436. package/src/domain/graph/builder/stages/finalize.ts +4 -0
  437. package/src/domain/graph/builder/stages/native-orchestrator.ts +1214 -398
  438. package/src/domain/graph/builder/stages/resolve-imports.ts +1 -1
  439. package/src/domain/graph/resolver/points-to.ts +182 -59
  440. package/src/domain/graph/resolver/strategy.ts +265 -0
  441. package/src/domain/graph/watcher.ts +19 -9
  442. package/src/domain/parser.ts +57 -16
  443. package/src/domain/queries.ts +1 -1
  444. package/src/domain/wasm-worker-entry.ts +13 -2
  445. package/src/domain/wasm-worker-pool.ts +29 -4
  446. package/src/domain/wasm-worker-protocol.ts +5 -0
  447. package/src/extractors/cpp.ts +44 -1
  448. package/src/extractors/cuda.ts +44 -1
  449. package/src/extractors/dart.ts +48 -3
  450. package/src/extractors/groovy.ts +62 -2
  451. package/src/extractors/helpers.ts +48 -2
  452. package/src/extractors/java.ts +88 -8
  453. package/src/extractors/javascript.ts +693 -167
  454. package/src/extractors/kotlin.ts +57 -3
  455. package/src/extractors/objc.ts +25 -1
  456. package/src/extractors/scala.ts +63 -1
  457. package/src/extractors/swift.ts +46 -3
  458. package/src/features/audit.ts +43 -34
  459. package/src/features/boundaries.ts +17 -9
  460. package/src/features/cfg.ts +31 -22
  461. package/src/features/check.ts +21 -5
  462. package/src/features/communities.ts +28 -19
  463. package/src/features/dataflow.ts +755 -6
  464. package/src/features/manifesto.ts +76 -75
  465. package/src/features/sequence.ts +29 -23
  466. package/src/features/snapshot.ts +36 -25
  467. package/src/features/structure-query.ts +7 -7
  468. package/src/features/structure.ts +185 -55
  469. package/src/features/triage.ts +28 -15
  470. package/src/graph/algorithms/bfs.ts +13 -12
  471. package/src/graph/algorithms/tarjan.ts +5 -0
  472. package/src/graph/builders/dependency.ts +35 -23
  473. package/src/graph/classifiers/roles.ts +74 -7
  474. package/src/index.ts +5 -1
  475. package/src/infrastructure/config.ts +511 -23
  476. package/src/infrastructure/registry.ts +117 -12
  477. package/src/infrastructure/update-check.ts +55 -33
  478. package/src/mcp/server.ts +2 -8
  479. package/src/mcp/tools/ast-query.ts +1 -1
  480. package/src/mcp/tools/audit.ts +1 -1
  481. package/src/mcp/tools/batch-query.ts +1 -1
  482. package/src/mcp/tools/branch-compare.ts +1 -1
  483. package/src/mcp/tools/brief.ts +1 -1
  484. package/src/mcp/tools/cfg.ts +1 -1
  485. package/src/mcp/tools/check.ts +1 -1
  486. package/src/mcp/tools/co-changes.ts +1 -1
  487. package/src/mcp/tools/code-owners.ts +1 -1
  488. package/src/mcp/tools/communities.ts +1 -1
  489. package/src/mcp/tools/complexity.ts +1 -1
  490. package/src/mcp/tools/context.ts +1 -1
  491. package/src/mcp/tools/dataflow.ts +1 -1
  492. package/src/mcp/tools/diff-impact.ts +1 -1
  493. package/src/mcp/tools/execution-flow.ts +1 -1
  494. package/src/mcp/tools/export-graph.ts +1 -1
  495. package/src/mcp/tools/file-deps.ts +1 -1
  496. package/src/mcp/tools/file-exports.ts +1 -1
  497. package/src/mcp/tools/find-cycles.ts +1 -1
  498. package/src/mcp/tools/fn-impact.ts +1 -1
  499. package/src/mcp/tools/impact-analysis.ts +1 -1
  500. package/src/mcp/tools/implementations.ts +1 -1
  501. package/src/mcp/tools/index.ts +2 -5
  502. package/src/mcp/tools/interfaces.ts +1 -1
  503. package/src/mcp/tools/list-functions.ts +1 -1
  504. package/src/mcp/tools/list-repos.ts +1 -1
  505. package/src/mcp/tools/module-map.ts +1 -1
  506. package/src/mcp/tools/node-roles.ts +1 -1
  507. package/src/mcp/tools/path.ts +1 -1
  508. package/src/mcp/tools/query.ts +1 -1
  509. package/src/mcp/tools/semantic-search.ts +1 -1
  510. package/src/mcp/tools/sequence.ts +1 -1
  511. package/src/mcp/tools/structure.ts +1 -1
  512. package/src/mcp/tools/symbol-children.ts +1 -1
  513. package/src/mcp/tools/triage.ts +1 -1
  514. package/src/mcp/tools/where.ts +1 -1
  515. package/src/mcp/types.ts +21 -0
  516. package/src/presentation/queries-cli/index.ts +1 -1
  517. package/src/presentation/queries-cli/overview.ts +35 -1
  518. package/src/presentation/queries-cli.ts +1 -0
  519. package/src/presentation/structure.ts +3 -3
  520. package/src/presentation/viewer.ts +98 -87
  521. package/src/shared/constants.ts +26 -0
  522. package/src/shared/normalize.ts +13 -22
  523. package/src/shared/paginate.ts +4 -18
  524. package/src/types.ts +127 -1
@@ -7,14 +7,15 @@
7
7
  * rusqlite) never touches this module.
8
8
  */
9
9
  import { createRequire } from 'node:module';
10
+ import type Database from 'better-sqlite3';
10
11
 
11
12
  const _require = createRequire(import.meta.url);
12
- let _Database: any;
13
+ let _Database: typeof Database | undefined;
13
14
 
14
15
  /** Return the `better-sqlite3` Database constructor, loading it on first call. */
15
- export function getDatabase(): new (...args: any[]) => any {
16
+ export function getDatabase(): typeof Database {
16
17
  if (!_Database) {
17
- _Database = _require('better-sqlite3');
18
+ _Database = _require('better-sqlite3') as typeof Database;
18
19
  }
19
- return _Database;
20
+ return _Database!;
20
21
  }
@@ -2,6 +2,7 @@ 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 { loadConfig } from '../infrastructure/config.js';
5
6
  import { debug, warn } from '../infrastructure/logger.js';
6
7
  import { getNative, isNativeAvailable } from '../infrastructure/native.js';
7
8
  import { DbError, toErrorMessage } from '../shared/errors.js';
@@ -379,9 +380,14 @@ export function openRepo(
379
380
  return { repo: opts.repo, close() {} };
380
381
  }
381
382
 
382
- // Respect explicit engine selection: opts.engine > CODEGRAPH_ENGINE env > auto.
383
+ // Derive rootDir from customDbPath so loadConfig reads the right project config.
384
+ // Convention: customDbPath = <rootDir>/.codegraph/graph.db
385
+ const rootDir = customDbPath ? path.dirname(path.dirname(path.resolve(customDbPath))) : undefined;
386
+ // Respect explicit engine selection: opts.engine > config.build.engine > auto.
387
+ // config.build.engine is already populated from CODEGRAPH_ENGINE env by applyEnvOverrides,
388
+ // so this covers both the env-var path and the .codegraphrc.json config-file path.
383
389
  // This ensures --engine wasm and benchmark workers bypass the native path.
384
- const engine = opts.engine || process.env.CODEGRAPH_ENGINE || 'auto';
390
+ const engine = opts.engine ?? loadConfig(rootDir).build.engine ?? 'auto';
385
391
 
386
392
  // Try native rusqlite path first (Phase 6.14)
387
393
  if (engine !== 'wasm' && isNativeAvailable()) {
@@ -416,16 +422,28 @@ export function openRepo(
416
422
  * Returns the better-sqlite3 handle (for backwards compat) plus an optional
417
423
  * NativeDatabase for modules that can use batched Rust query methods.
418
424
  * Callers should use nativeDb when available and fall back to db.prepare().
425
+ *
426
+ * @param opts.engine - Per-call engine override: 'native' | 'wasm' | 'auto'.
427
+ * When omitted, falls back to config.build.engine then 'auto', mirroring
428
+ * the priority chain used by openRepo().
419
429
  */
420
- export function openReadonlyWithNative(customPath?: string): {
430
+ export function openReadonlyWithNative(
431
+ customPath?: string,
432
+ opts: { engine?: 'native' | 'wasm' | 'auto' } = {},
433
+ ): {
421
434
  db: BetterSqlite3Database;
422
435
  nativeDb: NativeDatabase | undefined;
423
436
  close(): void;
424
437
  } {
425
438
  const db = openReadonlyOrFail(customPath);
426
439
 
427
- // Respect explicit engine selection, consistent with openRepo().
428
- const engine = process.env.CODEGRAPH_ENGINE || 'auto';
440
+ // Derive rootDir from customPath so loadConfig reads the right project config,
441
+ // consistent with openRepo(). Convention: customPath = <rootDir>/.codegraph/graph.db
442
+ const rootDir = customPath ? path.dirname(path.dirname(path.resolve(customPath))) : undefined;
443
+ // Respect explicit engine selection: opts.engine > config.build.engine > auto.
444
+ // config.build.engine covers both CODEGRAPH_ENGINE env (via applyEnvOverrides)
445
+ // and the .codegraphrc.json config-file path. Mirrors openRepo() priority chain.
446
+ const engine = opts.engine ?? loadConfig(rootDir).build.engine ?? 'auto';
429
447
 
430
448
  let nativeDb: NativeDatabase | undefined;
431
449
  if (engine !== 'wasm' && isNativeAvailable()) {
package/src/db/index.ts CHANGED
@@ -71,6 +71,7 @@ export {
71
71
  hasCfgTables,
72
72
  hasCoChanges,
73
73
  hasDataflowTable,
74
+ hasDataflowVertices,
74
75
  hasEmbeddings,
75
76
  InMemoryRepository,
76
77
  iterateFunctionNodes,
@@ -8,7 +8,7 @@ interface Migration {
8
8
  up: string;
9
9
  }
10
10
 
11
- // IMPORTANT: Migration DDL is mirrored in crates/codegraph-core/src/native_db.rs.
11
+ // IMPORTANT: Migration DDL is mirrored in crates/codegraph-core/src/db/connection.rs.
12
12
  // Any changes here MUST be reflected there (and vice-versa).
13
13
  export const MIGRATIONS: Migration[] = [
14
14
  {
@@ -263,6 +263,74 @@ export const MIGRATIONS: Migration[] = [
263
263
  CREATE INDEX IF NOT EXISTS idx_edges_technique ON edges(technique);
264
264
  `,
265
265
  },
266
+ {
267
+ version: 18,
268
+ up: `
269
+ CREATE TABLE IF NOT EXISTS dataflow_vertices (
270
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
271
+ func_id INTEGER NOT NULL REFERENCES nodes(id),
272
+ kind TEXT NOT NULL,
273
+ name TEXT,
274
+ param_index INTEGER,
275
+ line INTEGER,
276
+ node_id INTEGER REFERENCES nodes(id)
277
+ );
278
+ CREATE INDEX IF NOT EXISTS idx_dfv_func ON dataflow_vertices(func_id);
279
+ CREATE INDEX IF NOT EXISTS idx_dfv_func_kind ON dataflow_vertices(func_id, kind);
280
+ CREATE INDEX IF NOT EXISTS idx_dfv_node ON dataflow_vertices(node_id);
281
+
282
+ ALTER TABLE dataflow ADD COLUMN source_vertex INTEGER REFERENCES dataflow_vertices(id);
283
+ ALTER TABLE dataflow ADD COLUMN target_vertex INTEGER REFERENCES dataflow_vertices(id);
284
+ ALTER TABLE dataflow ADD COLUMN scope TEXT;
285
+ ALTER TABLE dataflow ADD COLUMN call_edge_id INTEGER REFERENCES edges(id);
286
+
287
+ CREATE INDEX IF NOT EXISTS idx_dataflow_sv ON dataflow(source_vertex);
288
+ CREATE INDEX IF NOT EXISTS idx_dataflow_tv ON dataflow(target_vertex);
289
+ CREATE INDEX IF NOT EXISTS idx_dataflow_scope ON dataflow(scope);
290
+
291
+ CREATE TABLE IF NOT EXISTS dataflow_summary (
292
+ func_id INTEGER NOT NULL REFERENCES nodes(id),
293
+ param_index INTEGER NOT NULL,
294
+ flows_to_return INTEGER NOT NULL DEFAULT 0,
295
+ is_mutated INTEGER NOT NULL DEFAULT 0,
296
+ PRIMARY KEY(func_id, param_index)
297
+ );
298
+ CREATE INDEX IF NOT EXISTS idx_dfs_func ON dataflow_summary(func_id);
299
+
300
+ -- dataflow_fn exposes only vertex-linked (v18+) interprocedural flows.
301
+ -- The INNER JOINs intentionally exclude pre-v18 rows where source_vertex
302
+ -- and target_vertex are NULL — this is NOT a backward-compat replacement
303
+ -- for querying the dataflow table directly; legacy consumers must continue
304
+ -- to query dataflow directly to avoid silently dropping historical rows.
305
+ CREATE VIEW IF NOT EXISTS dataflow_fn AS
306
+ SELECT
307
+ sv.func_id AS source_id,
308
+ tv.func_id AS target_id,
309
+ d.kind,
310
+ d.param_index,
311
+ d.expression,
312
+ d.line,
313
+ d.confidence
314
+ FROM dataflow d
315
+ JOIN dataflow_vertices sv ON d.source_vertex = sv.id
316
+ JOIN dataflow_vertices tv ON d.target_vertex = tv.id
317
+ WHERE sv.func_id != tv.func_id;
318
+ `,
319
+ },
320
+ {
321
+ version: 19,
322
+ // P6 sentinel: forces a full rebuild so that databases built with the native
323
+ // fast path (which skipped vertex extraction before P6) backfill
324
+ // dataflow_vertices and dataflow_summary on the next `codegraph build`.
325
+ up: `SELECT 1`,
326
+ },
327
+ {
328
+ version: 20,
329
+ up: `
330
+ ALTER TABLE edges ADD COLUMN dynamic_kind TEXT;
331
+ CREATE INDEX IF NOT EXISTS idx_edges_dynamic_kind ON edges(dynamic_kind) WHERE dynamic_kind IS NOT NULL;
332
+ `,
333
+ },
266
334
  ];
267
335
 
268
336
  interface PragmaColumnInfo {
@@ -5,6 +5,10 @@ interface PurgeStmts {
5
5
  cfgEdges: SqliteStatement | null;
6
6
  cfgBlocks: SqliteStatement | null;
7
7
  dataflow: SqliteStatement | null;
8
+ dataflowByVertex: SqliteStatement | null;
9
+ dataflowByCallEdge: SqliteStatement | null;
10
+ dataflowSummary: SqliteStatement | null;
11
+ dataflowVertices: SqliteStatement | null;
8
12
  complexity: SqliteStatement | null;
9
13
  nodeMetrics: SqliteStatement | null;
10
14
  astNodes: SqliteStatement | null;
@@ -44,6 +48,26 @@ function preparePurgeStmts(db: BetterSqlite3Database): PurgeStmts {
44
48
  dataflow: tryPrepare(
45
49
  'DELETE FROM dataflow WHERE source_id IN (SELECT id FROM nodes WHERE file = ?) OR target_id IN (SELECT id FROM nodes WHERE file = ?)',
46
50
  ),
51
+ dataflowByVertex: tryPrepare(
52
+ `DELETE FROM dataflow WHERE source_vertex IN (SELECT id FROM dataflow_vertices WHERE func_id IN (SELECT id FROM nodes WHERE file = ?))
53
+ OR target_vertex IN (SELECT id FROM dataflow_vertices WHERE func_id IN (SELECT id FROM nodes WHERE file = ?))`,
54
+ ),
55
+ // Delete dataflow rows whose call_edge_id references a calls edge that
56
+ // touches the deleted file (source or target). These rows are not caught by
57
+ // the source_id/target_id or vertex-based deletions above when the dataflow
58
+ // row's own nodes live in other files. Must run before the edges delete to
59
+ // avoid SQLITE_CONSTRAINT_FOREIGNKEY: dataflow.call_edge_id REFERENCES edges(id).
60
+ dataflowByCallEdge: tryPrepare(
61
+ `DELETE FROM dataflow WHERE call_edge_id IN
62
+ (SELECT id FROM edges WHERE source_id IN (SELECT id FROM nodes WHERE file = @f)
63
+ OR target_id IN (SELECT id FROM nodes WHERE file = @f))`,
64
+ ),
65
+ dataflowSummary: tryPrepare(
66
+ 'DELETE FROM dataflow_summary WHERE func_id IN (SELECT id FROM nodes WHERE file = ?)',
67
+ ),
68
+ dataflowVertices: tryPrepare(
69
+ 'DELETE FROM dataflow_vertices WHERE func_id IN (SELECT id FROM nodes WHERE file = ?)',
70
+ ),
47
71
  complexity: tryPrepare(
48
72
  'DELETE FROM function_complexity WHERE node_id IN (SELECT id FROM nodes WHERE file = ?)',
49
73
  ),
@@ -80,6 +104,12 @@ function runPurge(stmts: PurgeStmts, file: string, opts: PurgeOpts = {}): void {
80
104
  stmts.cfgEdges?.run(file);
81
105
  stmts.cfgBlocks?.run(file);
82
106
  stmts.dataflow?.run(file, file);
107
+ stmts.dataflowByVertex?.run(file, file);
108
+ // Clear dataflow rows keyed by call_edge_id before deleting edges so the FK
109
+ // (dataflow.call_edge_id REFERENCES edges(id)) does not block the edge purge.
110
+ stmts.dataflowByCallEdge?.run({ f: file });
111
+ stmts.dataflowSummary?.run(file);
112
+ stmts.dataflowVertices?.run(file);
83
113
  stmts.complexity?.run(file);
84
114
  stmts.nodeMetrics?.run(file);
85
115
  stmts.astNodes?.run(file);
@@ -3,6 +3,7 @@ import { cachedStmt } from './cached-stmt.js';
3
3
 
4
4
  // ─── Statement caches (one prepared statement per db instance) ────────────
5
5
  const _hasDataflowTableStmt: StmtCache<{ c: number }> = new WeakMap();
6
+ const _hasDataflowVerticesStmt: StmtCache<{ c: number }> = new WeakMap();
6
7
 
7
8
  /**
8
9
  * Check whether the dataflow table exists and has data.
@@ -17,3 +18,18 @@ export function hasDataflowTable(db: BetterSqlite3Database): boolean {
17
18
  return false;
18
19
  }
19
20
  }
21
+
22
+ /**
23
+ * Check whether the dataflow_vertices table exists and has data.
24
+ * Returns false on DBs built before migration v18.
25
+ */
26
+ export function hasDataflowVertices(db: BetterSqlite3Database): boolean {
27
+ try {
28
+ return (
29
+ (cachedStmt(_hasDataflowVerticesStmt, db, 'SELECT COUNT(*) AS c FROM dataflow_vertices').get()
30
+ ?.c ?? 0) > 0
31
+ );
32
+ } catch {
33
+ return false;
34
+ }
35
+ }
@@ -7,7 +7,7 @@ export { cachedStmt } from './cached-stmt.js';
7
7
  export { deleteCfgForNode, getCfgBlocks, getCfgEdges, hasCfgTables } from './cfg.js';
8
8
  export { getCoChangeMeta, hasCoChanges, upsertCoChangeMeta } from './cochange.js';
9
9
  export { getComplexityForNode } from './complexity.js';
10
- export { hasDataflowTable } from './dataflow.js';
10
+ export { hasDataflowTable, hasDataflowVertices } from './dataflow.js';
11
11
  export {
12
12
  countCrossFileCallers,
13
13
  findAllIncomingEdges,
@@ -163,6 +163,61 @@ function toComplexityMetrics(r: NativeComplexityMetrics): ComplexityMetrics {
163
163
  };
164
164
  }
165
165
 
166
+ // ── fnDeps conversion helpers ────────────────────────────────────────────
167
+
168
+ /**
169
+ * Convert a native transitive-callers array (array of `{ depth, callers[] }`)
170
+ * into the JS `Record<number, FnDepsNode[]>` shape the Repository interface expects.
171
+ */
172
+ function mapTransitiveCallers(groups: any[]): Record<number, FnDepsNode[]> {
173
+ const result: Record<number, FnDepsNode[]> = {};
174
+ for (const group of groups ?? []) {
175
+ result[group.depth] = (group.callers ?? []).map(
176
+ (c: any): FnDepsNode => ({
177
+ name: c.name,
178
+ kind: c.kind,
179
+ file: c.file,
180
+ line: c.line ?? null,
181
+ }),
182
+ );
183
+ }
184
+ return result;
185
+ }
186
+
187
+ /**
188
+ * Convert a single raw native fnDeps entry into the typed `FnDepsEntry` shape.
189
+ * Handles napi-rs camelCase → Repository snake_case field aliasing.
190
+ */
191
+ function mapFnDepsEntry(entry: any): FnDepsEntry {
192
+ return {
193
+ name: entry.name,
194
+ kind: entry.kind,
195
+ file: entry.file,
196
+ line: entry.line ?? null,
197
+ endLine: entry.endLine ?? entry.end_line ?? null,
198
+ role: entry.role ?? null,
199
+ fileHash: entry.fileHash ?? entry.file_hash ?? null,
200
+ callees: (entry.callees ?? []).map(
201
+ (c: any): FnDepsNode => ({
202
+ name: c.name,
203
+ kind: c.kind,
204
+ file: c.file,
205
+ line: c.line ?? null,
206
+ }),
207
+ ),
208
+ callers: (entry.callers ?? []).map(
209
+ (c: any): FnDepsCallerNode => ({
210
+ name: c.name,
211
+ kind: c.kind,
212
+ file: c.file,
213
+ line: c.line ?? null,
214
+ viaHierarchy: c.viaHierarchy ?? c.via_hierarchy ?? undefined,
215
+ }),
216
+ ),
217
+ transitiveCallers: mapTransitiveCallers(entry.transitiveCallers),
218
+ };
219
+ }
220
+
166
221
  // ── NativeRepository ────────────────────────────────────────────────────
167
222
 
168
223
  export class NativeRepository extends Repository {
@@ -485,46 +540,7 @@ export class NativeRepository extends Repository {
485
540
  // to JS format (transitiveCallers as Record<number, Array>)
486
541
  return {
487
542
  name: raw.name,
488
- results: raw.results.map((entry: any): FnDepsEntry => {
489
- const transitiveCallers: Record<number, FnDepsNode[]> = {};
490
- for (const group of entry.transitiveCallers ?? []) {
491
- transitiveCallers[group.depth] = (group.callers ?? []).map(
492
- (c: any): FnDepsNode => ({
493
- name: c.name,
494
- kind: c.kind,
495
- file: c.file,
496
- line: c.line ?? null,
497
- }),
498
- );
499
- }
500
- return {
501
- name: entry.name,
502
- kind: entry.kind,
503
- file: entry.file,
504
- line: entry.line ?? null,
505
- endLine: entry.endLine ?? entry.end_line ?? null,
506
- role: entry.role ?? null,
507
- fileHash: entry.fileHash ?? entry.file_hash ?? null,
508
- callees: (entry.callees ?? []).map(
509
- (c: any): FnDepsNode => ({
510
- name: c.name,
511
- kind: c.kind,
512
- file: c.file,
513
- line: c.line ?? null,
514
- }),
515
- ),
516
- callers: (entry.callers ?? []).map(
517
- (c: any): FnDepsCallerNode => ({
518
- name: c.name,
519
- kind: c.kind,
520
- file: c.file,
521
- line: c.line ?? null,
522
- viaHierarchy: c.viaHierarchy ?? c.via_hierarchy ?? undefined,
523
- }),
524
- ),
525
- transitiveCallers,
526
- };
527
- }),
543
+ results: raw.results.map(mapFnDepsEntry),
528
544
  };
529
545
  }
530
546
  }
@@ -294,10 +294,14 @@ export function fnImpactData(
294
294
  maxDepth,
295
295
  includeImplementors,
296
296
  });
297
+ const direct = levels[1]?.length ?? 0;
298
+ const transitive = totalDependents - direct;
297
299
  return {
298
300
  ...normalizeSymbol(node, repo, hc),
299
301
  levels,
300
302
  totalDependents,
303
+ direct,
304
+ transitive,
301
305
  };
302
306
  });
303
307
 
@@ -211,12 +211,20 @@ function computeQualityMetrics(
211
211
  const totalCallEdges = (
212
212
  db.prepare("SELECT COUNT(*) as c FROM edges WHERE kind = 'calls'").get() as { c: number }
213
213
  ).c;
214
+ // Exclude sink edges (confidence=0.0) from the confidence ratio: they flag
215
+ // unresolvable dynamic calls (eval/computed-key) and are not resolution
216
+ // attempts — including them in the denominator unfairly penalises the metric.
217
+ const resolvedCallEdges = (
218
+ db.prepare("SELECT COUNT(*) as c FROM edges WHERE kind = 'calls' AND confidence > 0").get() as {
219
+ c: number;
220
+ }
221
+ ).c;
214
222
  const highConfCallEdges = (
215
223
  db
216
224
  .prepare("SELECT COUNT(*) as c FROM edges WHERE kind = 'calls' AND confidence >= 0.7")
217
225
  .get() as { c: number }
218
226
  ).c;
219
- const callConfidence = totalCallEdges > 0 ? highConfCallEdges / totalCallEdges : 0;
227
+ const callConfidence = resolvedCallEdges > 0 ? highConfCallEdges / resolvedCallEdges : 0;
220
228
 
221
229
  const falsePositiveWarnings = buildFalsePositiveWarnings(queryFalsePositiveRows(db, fpThreshold));
222
230
 
@@ -239,7 +247,7 @@ function computeQualityMetrics(
239
247
  callConfidence: {
240
248
  ratio: callConfidence,
241
249
  highConf: highConfCallEdges,
242
- total: totalCallEdges,
250
+ total: resolvedCallEdges,
243
251
  },
244
252
  falsePositiveWarnings,
245
253
  };
@@ -373,11 +381,29 @@ function queryFalsePositiveRows(
373
381
  .all(fpThreshold) as FalsePositiveRow[];
374
382
  }
375
383
 
384
+ /**
385
+ * Returns true when a high-caller-count row is a known structural false positive
386
+ * that should be silently excluded from warnings.
387
+ *
388
+ * Rust `::new()` methods (kind = method, local name = "new", file ends in ".rs")
389
+ * are conventional constructors — their high call counts are expected and carry
390
+ * no architectural signal. Any pattern-based exclusion should be added here
391
+ * rather than hardcoding specific symbol names.
392
+ */
393
+ function isStructuralFalsePositive(r: FalsePositiveRow): boolean {
394
+ const localName = r.name.includes('.') ? r.name.split('.').pop()! : r.name;
395
+ // Rust ::new() constructors are always high-caller by design.
396
+ if (localName === 'new' && r.file.endsWith('.rs')) return true;
397
+ return false;
398
+ }
399
+
376
400
  /** Filter false-positive rows by the configured name set and shape them for the report. */
377
401
  function buildFalsePositiveWarnings(rows: FalsePositiveRow[]) {
378
402
  return rows
379
- .filter((r) =>
380
- FALSE_POSITIVE_NAMES.has(r.name.includes('.') ? r.name.split('.').pop()! : r.name),
403
+ .filter(
404
+ (r) =>
405
+ !isStructuralFalsePositive(r) &&
406
+ FALSE_POSITIVE_NAMES.has(r.name.includes('.') ? r.name.split('.').pop()! : r.name),
381
407
  )
382
408
  .map((r) => ({ name: r.name, file: r.file, line: r.line, callerCount: r.caller_count }));
383
409
  }
@@ -427,15 +453,21 @@ function buildStatsFromNative(
427
453
 
428
454
  const callerCoverage =
429
455
  s.quality.callableTotal > 0 ? s.quality.callableWithCallers / s.quality.callableTotal : 0;
456
+ // s.quality.callEdges is now the resolved (confidence>0) edge count — sink
457
+ // edges (confidence=0.0) are excluded so they don't dilute the ratio.
430
458
  const callConfidence =
431
459
  s.quality.callEdges > 0 ? s.quality.highConfCallEdges / s.quality.callEdges : 0;
432
460
 
433
- // False-positive analysis still uses JS (needs FALSE_POSITIVE_NAMES set)
461
+ // False-positive analysis still uses JS (needs FALSE_POSITIVE_NAMES set).
462
+ // FP ratio uses the total calls count as denominator. When edgesByKind['calls']
463
+ // is undefined there are no call edges at all, so fpEdgeCount is 0 and the
464
+ // > 0 guard below returns 0 regardless — use 0 as the safe fallback.
465
+ const totalCallEdgesForFp = edgesByKind.calls ?? 0;
434
466
  const fpThreshold = config.analysis?.falsePositiveCallers ?? FALSE_POSITIVE_CALLER_THRESHOLD;
435
467
  const falsePositiveWarnings = buildFalsePositiveWarnings(queryFalsePositiveRows(db, fpThreshold));
436
468
  let fpEdgeCount = 0;
437
469
  for (const fp of falsePositiveWarnings) fpEdgeCount += fp.callerCount;
438
- const falsePositiveRatio = s.quality.callEdges > 0 ? fpEdgeCount / s.quality.callEdges : 0;
470
+ const falsePositiveRatio = totalCallEdgesForFp > 0 ? fpEdgeCount / totalCallEdgesForFp : 0;
439
471
  const score = computeQualityScore(callerCoverage, callConfidence, falsePositiveRatio);
440
472
  const testFilter = testFilterSQL('n.file', noTests);
441
473
  const byTechnique = countCallEdgesByTechnique(db, testFilter);
@@ -6,6 +6,29 @@ import { normalizeSymbol } from '../../shared/normalize.js';
6
6
  import { paginateResult } from '../../shared/paginate.js';
7
7
  import type { NodeRow } from '../../types.js';
8
8
 
9
+ export interface DynamicCallCount {
10
+ dynamic_kind: string;
11
+ count: number;
12
+ }
13
+
14
+ /** Return a count of flagged dynamic call sink edges, grouped by kind. */
15
+ export function dynamicCallsData(customDbPath: string): DynamicCallCount[] {
16
+ const db = openReadonlyOrFail(customDbPath);
17
+ try {
18
+ return db
19
+ .prepare(
20
+ `SELECT dynamic_kind, COUNT(*) AS count
21
+ FROM edges
22
+ WHERE dynamic_kind IS NOT NULL
23
+ GROUP BY dynamic_kind
24
+ ORDER BY count DESC`,
25
+ )
26
+ .all() as DynamicCallCount[];
27
+ } finally {
28
+ db.close();
29
+ }
30
+ }
31
+
9
32
  export function rolesData(
10
33
  customDbPath: string,
11
34
  opts: {