@optave/codegraph 3.7.0 → 3.8.1

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 (401) hide show
  1. package/README.md +28 -16
  2. package/dist/ast-analysis/engine.d.ts.map +1 -1
  3. package/dist/ast-analysis/engine.js +195 -30
  4. package/dist/ast-analysis/engine.js.map +1 -1
  5. package/dist/ast-analysis/metrics.d.ts +0 -3
  6. package/dist/ast-analysis/metrics.d.ts.map +1 -1
  7. package/dist/ast-analysis/metrics.js +30 -13
  8. package/dist/ast-analysis/metrics.js.map +1 -1
  9. package/dist/ast-analysis/rules/javascript.d.ts.map +1 -1
  10. package/dist/ast-analysis/rules/javascript.js +0 -1
  11. package/dist/ast-analysis/rules/javascript.js.map +1 -1
  12. package/dist/ast-analysis/shared.d.ts.map +1 -1
  13. package/dist/ast-analysis/shared.js +24 -19
  14. package/dist/ast-analysis/shared.js.map +1 -1
  15. package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
  16. package/dist/ast-analysis/visitor-utils.js +55 -39
  17. package/dist/ast-analysis/visitor-utils.js.map +1 -1
  18. package/dist/ast-analysis/visitor.d.ts.map +1 -1
  19. package/dist/ast-analysis/visitor.js +91 -70
  20. package/dist/ast-analysis/visitor.js.map +1 -1
  21. package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
  22. package/dist/ast-analysis/visitors/ast-store-visitor.js +52 -129
  23. package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
  24. package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
  25. package/dist/ast-analysis/visitors/complexity-visitor.js +32 -39
  26. package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
  27. package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
  28. package/dist/ast-analysis/visitors/dataflow-visitor.js +57 -38
  29. package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
  30. package/dist/cli/commands/ast.js +2 -2
  31. package/dist/cli/commands/ast.js.map +1 -1
  32. package/dist/cli/commands/watch.d.ts.map +1 -1
  33. package/dist/cli/commands/watch.js +16 -2
  34. package/dist/cli/commands/watch.js.map +1 -1
  35. package/dist/db/connection.d.ts.map +1 -1
  36. package/dist/db/connection.js +29 -26
  37. package/dist/db/connection.js.map +1 -1
  38. package/dist/db/query-builder.d.ts.map +1 -1
  39. package/dist/db/query-builder.js +16 -5
  40. package/dist/db/query-builder.js.map +1 -1
  41. package/dist/db/repository/base.d.ts +10 -0
  42. package/dist/db/repository/base.d.ts.map +1 -1
  43. package/dist/db/repository/base.js +17 -0
  44. package/dist/db/repository/base.js.map +1 -1
  45. package/dist/db/repository/native-repository.d.ts +6 -1
  46. package/dist/db/repository/native-repository.d.ts.map +1 -1
  47. package/dist/db/repository/native-repository.js +77 -1
  48. package/dist/db/repository/native-repository.js.map +1 -1
  49. package/dist/db/repository/nodes.d.ts.map +1 -1
  50. package/dist/db/repository/nodes.js +8 -4
  51. package/dist/db/repository/nodes.js.map +1 -1
  52. package/dist/db/repository/sqlite-repository.d.ts +3 -0
  53. package/dist/db/repository/sqlite-repository.d.ts.map +1 -1
  54. package/dist/db/repository/sqlite-repository.js +26 -0
  55. package/dist/db/repository/sqlite-repository.js.map +1 -1
  56. package/dist/domain/analysis/brief.d.ts.map +1 -1
  57. package/dist/domain/analysis/brief.js +13 -17
  58. package/dist/domain/analysis/brief.js.map +1 -1
  59. package/dist/domain/analysis/context.d.ts.map +1 -1
  60. package/dist/domain/analysis/context.js +14 -11
  61. package/dist/domain/analysis/context.js.map +1 -1
  62. package/dist/domain/analysis/dependencies.d.ts.map +1 -1
  63. package/dist/domain/analysis/dependencies.js +53 -52
  64. package/dist/domain/analysis/dependencies.js.map +1 -1
  65. package/dist/domain/analysis/fn-impact.d.ts +2 -7
  66. package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
  67. package/dist/domain/analysis/fn-impact.js +33 -31
  68. package/dist/domain/analysis/fn-impact.js.map +1 -1
  69. package/dist/domain/analysis/implementations.d.ts.map +1 -1
  70. package/dist/domain/analysis/implementations.js +11 -19
  71. package/dist/domain/analysis/implementations.js.map +1 -1
  72. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  73. package/dist/domain/analysis/module-map.js +55 -76
  74. package/dist/domain/analysis/module-map.js.map +1 -1
  75. package/dist/domain/analysis/query-helpers.d.ts +7 -0
  76. package/dist/domain/analysis/query-helpers.d.ts.map +1 -1
  77. package/dist/domain/analysis/query-helpers.js +15 -1
  78. package/dist/domain/analysis/query-helpers.js.map +1 -1
  79. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  80. package/dist/domain/graph/builder/pipeline.js +315 -43
  81. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  82. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  83. package/dist/domain/graph/builder/stages/build-edges.js +106 -1
  84. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  85. package/dist/domain/graph/builder/stages/collect-files.d.ts.map +1 -1
  86. package/dist/domain/graph/builder/stages/collect-files.js +17 -5
  87. package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
  88. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  89. package/dist/domain/graph/builder/stages/detect-changes.js +99 -51
  90. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  91. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
  92. package/dist/domain/graph/builder/stages/finalize.js +34 -7
  93. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  94. package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
  95. package/dist/domain/graph/builder/stages/insert-nodes.js +50 -26
  96. package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
  97. package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
  98. package/dist/domain/graph/builder/stages/resolve-imports.js +95 -84
  99. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  100. package/dist/domain/graph/cycles.d.ts +6 -0
  101. package/dist/domain/graph/cycles.d.ts.map +1 -1
  102. package/dist/domain/graph/cycles.js +114 -22
  103. package/dist/domain/graph/cycles.js.map +1 -1
  104. package/dist/domain/graph/resolve.js +1 -1
  105. package/dist/domain/graph/resolve.js.map +1 -1
  106. package/dist/domain/graph/watcher.d.ts +2 -0
  107. package/dist/domain/graph/watcher.d.ts.map +1 -1
  108. package/dist/domain/graph/watcher.js +170 -75
  109. package/dist/domain/graph/watcher.js.map +1 -1
  110. package/dist/domain/parser.d.ts +1 -6
  111. package/dist/domain/parser.d.ts.map +1 -1
  112. package/dist/domain/parser.js +101 -32
  113. package/dist/domain/parser.js.map +1 -1
  114. package/dist/domain/search/generator.js +1 -1
  115. package/dist/domain/search/generator.js.map +1 -1
  116. package/dist/domain/search/models.d.ts +4 -3
  117. package/dist/domain/search/models.d.ts.map +1 -1
  118. package/dist/domain/search/models.js +18 -5
  119. package/dist/domain/search/models.js.map +1 -1
  120. package/dist/domain/search/search/hybrid.d.ts.map +1 -1
  121. package/dist/domain/search/search/hybrid.js +29 -18
  122. package/dist/domain/search/search/hybrid.js.map +1 -1
  123. package/dist/extractors/clojure.d.ts +12 -0
  124. package/dist/extractors/clojure.d.ts.map +1 -0
  125. package/dist/extractors/clojure.js +245 -0
  126. package/dist/extractors/clojure.js.map +1 -0
  127. package/dist/extractors/cuda.d.ts +11 -0
  128. package/dist/extractors/cuda.d.ts.map +1 -0
  129. package/dist/extractors/cuda.js +302 -0
  130. package/dist/extractors/cuda.js.map +1 -0
  131. package/dist/extractors/erlang.d.ts +14 -0
  132. package/dist/extractors/erlang.d.ts.map +1 -0
  133. package/dist/extractors/erlang.js +239 -0
  134. package/dist/extractors/erlang.js.map +1 -0
  135. package/dist/extractors/fsharp.d.ts +13 -0
  136. package/dist/extractors/fsharp.d.ts.map +1 -0
  137. package/dist/extractors/fsharp.js +218 -0
  138. package/dist/extractors/fsharp.js.map +1 -0
  139. package/dist/extractors/gleam.d.ts +14 -0
  140. package/dist/extractors/gleam.d.ts.map +1 -0
  141. package/dist/extractors/gleam.js +229 -0
  142. package/dist/extractors/gleam.js.map +1 -0
  143. package/dist/extractors/go.js +36 -33
  144. package/dist/extractors/go.js.map +1 -1
  145. package/dist/extractors/groovy.d.ts +10 -0
  146. package/dist/extractors/groovy.d.ts.map +1 -0
  147. package/dist/extractors/groovy.js +304 -0
  148. package/dist/extractors/groovy.js.map +1 -0
  149. package/dist/extractors/helpers.d.ts.map +1 -1
  150. package/dist/extractors/helpers.js +40 -29
  151. package/dist/extractors/helpers.js.map +1 -1
  152. package/dist/extractors/index.d.ts +11 -0
  153. package/dist/extractors/index.d.ts.map +1 -1
  154. package/dist/extractors/index.js +11 -0
  155. package/dist/extractors/index.js.map +1 -1
  156. package/dist/extractors/java.js +58 -46
  157. package/dist/extractors/java.js.map +1 -1
  158. package/dist/extractors/javascript.js +46 -45
  159. package/dist/extractors/javascript.js.map +1 -1
  160. package/dist/extractors/julia.d.ts +16 -0
  161. package/dist/extractors/julia.d.ts.map +1 -0
  162. package/dist/extractors/julia.js +287 -0
  163. package/dist/extractors/julia.js.map +1 -0
  164. package/dist/extractors/kotlin.js +84 -78
  165. package/dist/extractors/kotlin.js.map +1 -1
  166. package/dist/extractors/objc.d.ts +9 -0
  167. package/dist/extractors/objc.d.ts.map +1 -0
  168. package/dist/extractors/objc.js +406 -0
  169. package/dist/extractors/objc.js.map +1 -0
  170. package/dist/extractors/ocaml.js +74 -0
  171. package/dist/extractors/ocaml.js.map +1 -1
  172. package/dist/extractors/python.js +29 -24
  173. package/dist/extractors/python.js.map +1 -1
  174. package/dist/extractors/r.d.ts +13 -0
  175. package/dist/extractors/r.d.ts.map +1 -0
  176. package/dist/extractors/r.js +251 -0
  177. package/dist/extractors/r.js.map +1 -0
  178. package/dist/extractors/rust.js +41 -32
  179. package/dist/extractors/rust.js.map +1 -1
  180. package/dist/extractors/solidity.d.ts +9 -0
  181. package/dist/extractors/solidity.d.ts.map +1 -0
  182. package/dist/extractors/solidity.js +365 -0
  183. package/dist/extractors/solidity.js.map +1 -0
  184. package/dist/extractors/swift.js +83 -81
  185. package/dist/extractors/swift.js.map +1 -1
  186. package/dist/extractors/verilog.d.ts +9 -0
  187. package/dist/extractors/verilog.d.ts.map +1 -0
  188. package/dist/extractors/verilog.js +286 -0
  189. package/dist/extractors/verilog.js.map +1 -0
  190. package/dist/extractors/zig.js +58 -60
  191. package/dist/extractors/zig.js.map +1 -1
  192. package/dist/features/ast.d.ts +16 -14
  193. package/dist/features/ast.d.ts.map +1 -1
  194. package/dist/features/ast.js +84 -83
  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 +8 -6
  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 +69 -72
  201. package/dist/features/branch-compare.js.map +1 -1
  202. package/dist/features/communities.d.ts.map +1 -1
  203. package/dist/features/communities.js +19 -7
  204. package/dist/features/communities.js.map +1 -1
  205. package/dist/features/complexity.d.ts.map +1 -1
  206. package/dist/features/complexity.js +120 -125
  207. package/dist/features/complexity.js.map +1 -1
  208. package/dist/features/dataflow.d.ts.map +1 -1
  209. package/dist/features/dataflow.js +136 -137
  210. package/dist/features/dataflow.js.map +1 -1
  211. package/dist/features/flow.d.ts.map +1 -1
  212. package/dist/features/flow.js +84 -79
  213. package/dist/features/flow.js.map +1 -1
  214. package/dist/features/structure-query.d.ts.map +1 -1
  215. package/dist/features/structure-query.js +69 -65
  216. package/dist/features/structure-query.js.map +1 -1
  217. package/dist/graph/algorithms/bfs.d.ts +2 -0
  218. package/dist/graph/algorithms/bfs.d.ts.map +1 -1
  219. package/dist/graph/algorithms/bfs.js +27 -0
  220. package/dist/graph/algorithms/bfs.js.map +1 -1
  221. package/dist/graph/algorithms/centrality.d.ts +2 -0
  222. package/dist/graph/algorithms/centrality.d.ts.map +1 -1
  223. package/dist/graph/algorithms/centrality.js +28 -0
  224. package/dist/graph/algorithms/centrality.js.map +1 -1
  225. package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
  226. package/dist/graph/algorithms/leiden/optimiser.js +70 -55
  227. package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
  228. package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
  229. package/dist/graph/algorithms/leiden/partition.js +288 -266
  230. package/dist/graph/algorithms/leiden/partition.js.map +1 -1
  231. package/dist/graph/algorithms/louvain.d.ts +3 -4
  232. package/dist/graph/algorithms/louvain.d.ts.map +1 -1
  233. package/dist/graph/algorithms/louvain.js +29 -0
  234. package/dist/graph/algorithms/louvain.js.map +1 -1
  235. package/dist/graph/algorithms/shortest-path.d.ts +2 -0
  236. package/dist/graph/algorithms/shortest-path.d.ts.map +1 -1
  237. package/dist/graph/algorithms/shortest-path.js +18 -1
  238. package/dist/graph/algorithms/shortest-path.js.map +1 -1
  239. package/dist/graph/model.d.ts.map +1 -1
  240. package/dist/graph/model.js +5 -1
  241. package/dist/graph/model.js.map +1 -1
  242. package/dist/infrastructure/config.d.ts.map +1 -1
  243. package/dist/infrastructure/config.js +6 -4
  244. package/dist/infrastructure/config.js.map +1 -1
  245. package/dist/infrastructure/suppress.d.ts +25 -0
  246. package/dist/infrastructure/suppress.d.ts.map +1 -0
  247. package/dist/infrastructure/suppress.js +43 -0
  248. package/dist/infrastructure/suppress.js.map +1 -0
  249. package/dist/mcp/server.d.ts.map +1 -1
  250. package/dist/mcp/server.js +29 -24
  251. package/dist/mcp/server.js.map +1 -1
  252. package/dist/presentation/dataflow.d.ts.map +1 -1
  253. package/dist/presentation/dataflow.js +47 -38
  254. package/dist/presentation/dataflow.js.map +1 -1
  255. package/dist/presentation/diff-impact-mermaid.d.ts.map +1 -1
  256. package/dist/presentation/diff-impact-mermaid.js +60 -51
  257. package/dist/presentation/diff-impact-mermaid.js.map +1 -1
  258. package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
  259. package/dist/presentation/queries-cli/exports.js +20 -14
  260. package/dist/presentation/queries-cli/exports.js.map +1 -1
  261. package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
  262. package/dist/presentation/queries-cli/impact.js +15 -13
  263. package/dist/presentation/queries-cli/impact.js.map +1 -1
  264. package/dist/presentation/queries-cli/inspect.d.ts.map +1 -1
  265. package/dist/presentation/queries-cli/inspect.js +101 -79
  266. package/dist/presentation/queries-cli/inspect.js.map +1 -1
  267. package/dist/presentation/queries-cli/overview.d.ts.map +1 -1
  268. package/dist/presentation/queries-cli/overview.js +25 -16
  269. package/dist/presentation/queries-cli/overview.js.map +1 -1
  270. package/dist/presentation/queries-cli/path.js +26 -20
  271. package/dist/presentation/queries-cli/path.js.map +1 -1
  272. package/dist/presentation/result-formatter.d.ts +10 -0
  273. package/dist/presentation/result-formatter.d.ts.map +1 -1
  274. package/dist/presentation/result-formatter.js +16 -1
  275. package/dist/presentation/result-formatter.js.map +1 -1
  276. package/dist/presentation/viewer.d.ts.map +1 -1
  277. package/dist/presentation/viewer.js +18 -12
  278. package/dist/presentation/viewer.js.map +1 -1
  279. package/dist/shared/errors.d.ts +5 -0
  280. package/dist/shared/errors.d.ts.map +1 -1
  281. package/dist/shared/errors.js +5 -0
  282. package/dist/shared/errors.js.map +1 -1
  283. package/dist/shared/hierarchy.d.ts +8 -2
  284. package/dist/shared/hierarchy.d.ts.map +1 -1
  285. package/dist/shared/hierarchy.js +42 -1
  286. package/dist/shared/hierarchy.js.map +1 -1
  287. package/dist/shared/normalize.d.ts +6 -1
  288. package/dist/shared/normalize.d.ts.map +1 -1
  289. package/dist/shared/normalize.js +20 -12
  290. package/dist/shared/normalize.js.map +1 -1
  291. package/dist/shared/paginate.d.ts +0 -9
  292. package/dist/shared/paginate.d.ts.map +1 -1
  293. package/dist/shared/paginate.js +0 -15
  294. package/dist/shared/paginate.js.map +1 -1
  295. package/dist/types.d.ts +129 -3
  296. package/dist/types.d.ts.map +1 -1
  297. package/grammars/tree-sitter-clojure.wasm +0 -0
  298. package/grammars/tree-sitter-cuda.wasm +0 -0
  299. package/grammars/tree-sitter-erlang.wasm +0 -0
  300. package/grammars/tree-sitter-fsharp.wasm +0 -0
  301. package/grammars/tree-sitter-gleam.wasm +0 -0
  302. package/grammars/tree-sitter-groovy.wasm +0 -0
  303. package/grammars/tree-sitter-julia.wasm +0 -0
  304. package/grammars/tree-sitter-objc.wasm +0 -0
  305. package/grammars/tree-sitter-ocaml_interface.wasm +0 -0
  306. package/grammars/tree-sitter-r.wasm +0 -0
  307. package/grammars/tree-sitter-solidity.wasm +0 -0
  308. package/grammars/tree-sitter-verilog.wasm +0 -0
  309. package/package.json +18 -7
  310. package/src/ast-analysis/engine.ts +245 -42
  311. package/src/ast-analysis/metrics.ts +33 -11
  312. package/src/ast-analysis/rules/javascript.ts +0 -1
  313. package/src/ast-analysis/shared.ts +33 -24
  314. package/src/ast-analysis/visitor-utils.ts +52 -32
  315. package/src/ast-analysis/visitor.ts +132 -71
  316. package/src/ast-analysis/visitors/ast-store-visitor.ts +49 -119
  317. package/src/ast-analysis/visitors/complexity-visitor.ts +35 -40
  318. package/src/ast-analysis/visitors/dataflow-visitor.ts +87 -43
  319. package/src/cli/commands/ast.ts +2 -2
  320. package/src/cli/commands/watch.ts +16 -2
  321. package/src/db/connection.ts +29 -28
  322. package/src/db/query-builder.ts +15 -3
  323. package/src/db/repository/base.ts +20 -0
  324. package/src/db/repository/native-repository.ts +79 -1
  325. package/src/db/repository/nodes.ts +13 -8
  326. package/src/db/repository/sqlite-repository.ts +29 -0
  327. package/src/domain/analysis/brief.ts +15 -25
  328. package/src/domain/analysis/context.ts +17 -10
  329. package/src/domain/analysis/dependencies.ts +67 -76
  330. package/src/domain/analysis/fn-impact.ts +36 -43
  331. package/src/domain/analysis/implementations.ts +11 -17
  332. package/src/domain/analysis/module-map.ts +58 -92
  333. package/src/domain/analysis/query-helpers.ts +18 -1
  334. package/src/domain/graph/builder/pipeline.ts +366 -41
  335. package/src/domain/graph/builder/stages/build-edges.ts +162 -1
  336. package/src/domain/graph/builder/stages/collect-files.ts +18 -7
  337. package/src/domain/graph/builder/stages/detect-changes.ts +110 -56
  338. package/src/domain/graph/builder/stages/finalize.ts +41 -11
  339. package/src/domain/graph/builder/stages/insert-nodes.ts +75 -39
  340. package/src/domain/graph/builder/stages/resolve-imports.ts +122 -100
  341. package/src/domain/graph/cycles.ts +110 -23
  342. package/src/domain/graph/resolve.ts +1 -1
  343. package/src/domain/graph/watcher.ts +202 -96
  344. package/src/domain/parser.ts +122 -28
  345. package/src/domain/search/generator.ts +1 -1
  346. package/src/domain/search/models.ts +17 -4
  347. package/src/domain/search/search/hybrid.ts +69 -51
  348. package/src/extractors/clojure.ts +273 -0
  349. package/src/extractors/cuda.ts +316 -0
  350. package/src/extractors/erlang.ts +252 -0
  351. package/src/extractors/fsharp.ts +253 -0
  352. package/src/extractors/gleam.ts +246 -0
  353. package/src/extractors/go.ts +43 -33
  354. package/src/extractors/groovy.ts +332 -0
  355. package/src/extractors/helpers.ts +37 -23
  356. package/src/extractors/index.ts +11 -0
  357. package/src/extractors/java.ts +66 -47
  358. package/src/extractors/javascript.ts +45 -46
  359. package/src/extractors/julia.ts +318 -0
  360. package/src/extractors/kotlin.ts +84 -77
  361. package/src/extractors/objc.ts +431 -0
  362. package/src/extractors/ocaml.ts +78 -0
  363. package/src/extractors/python.ts +31 -25
  364. package/src/extractors/r.ts +253 -0
  365. package/src/extractors/rust.ts +37 -29
  366. package/src/extractors/solidity.ts +394 -0
  367. package/src/extractors/swift.ts +81 -80
  368. package/src/extractors/verilog.ts +315 -0
  369. package/src/extractors/zig.ts +58 -61
  370. package/src/features/ast.ts +131 -112
  371. package/src/features/audit.ts +8 -6
  372. package/src/features/branch-compare.ts +105 -79
  373. package/src/features/communities.ts +25 -10
  374. package/src/features/complexity.ts +171 -134
  375. package/src/features/dataflow.ts +165 -175
  376. package/src/features/flow.ts +129 -92
  377. package/src/features/structure-query.ts +79 -64
  378. package/src/graph/algorithms/bfs.ts +34 -0
  379. package/src/graph/algorithms/centrality.ts +30 -0
  380. package/src/graph/algorithms/leiden/optimiser.ts +99 -55
  381. package/src/graph/algorithms/leiden/partition.ts +359 -294
  382. package/src/graph/algorithms/louvain.ts +31 -4
  383. package/src/graph/algorithms/shortest-path.ts +20 -1
  384. package/src/graph/model.ts +6 -1
  385. package/src/infrastructure/config.ts +6 -4
  386. package/src/infrastructure/suppress.ts +47 -0
  387. package/src/mcp/server.ts +53 -37
  388. package/src/presentation/dataflow.ts +50 -44
  389. package/src/presentation/diff-impact-mermaid.ts +104 -62
  390. package/src/presentation/queries-cli/exports.ts +21 -13
  391. package/src/presentation/queries-cli/impact.ts +15 -13
  392. package/src/presentation/queries-cli/inspect.ts +100 -81
  393. package/src/presentation/queries-cli/overview.ts +26 -16
  394. package/src/presentation/queries-cli/path.ts +33 -25
  395. package/src/presentation/result-formatter.ts +19 -1
  396. package/src/presentation/viewer.ts +42 -14
  397. package/src/shared/errors.ts +6 -0
  398. package/src/shared/hierarchy.ts +50 -2
  399. package/src/shared/normalize.ts +31 -12
  400. package/src/shared/paginate.ts +0 -17
  401. package/src/types.ts +138 -3
@@ -68,6 +68,67 @@ interface DirectoryEntry {
68
68
  subdirectories: string[];
69
69
  }
70
70
 
71
+ function buildDirectoryEntry(
72
+ d: DirRow,
73
+ filesStmt: { all(...params: unknown[]): unknown[] },
74
+ subdirsStmt: { all(...params: unknown[]): unknown[] },
75
+ noTests: boolean,
76
+ ): DirectoryEntry {
77
+ let files = filesStmt.all(d.id) as FileMetricRow[];
78
+ if (noTests) files = files.filter((f) => !isTestFile(f.name));
79
+
80
+ const subdirs = subdirsStmt.all(d.id) as { name: string }[];
81
+
82
+ const fileCount = noTests ? files.length : d.file_count || 0;
83
+ return {
84
+ directory: d.name,
85
+ fileCount,
86
+ symbolCount: d.symbol_count || 0,
87
+ fanIn: d.fan_in || 0,
88
+ fanOut: d.fan_out || 0,
89
+ cohesion: d.cohesion,
90
+ density: fileCount > 0 ? (d.symbol_count || 0) / fileCount : 0,
91
+ files: files.map((f) => ({
92
+ file: f.name,
93
+ lineCount: f.line_count || 0,
94
+ symbolCount: f.symbol_count || 0,
95
+ importCount: f.import_count || 0,
96
+ exportCount: f.export_count || 0,
97
+ fanIn: f.fan_in || 0,
98
+ fanOut: f.fan_out || 0,
99
+ })),
100
+ subdirectories: subdirs.map((s) => s.name),
101
+ };
102
+ }
103
+
104
+ function applyFileLimit(
105
+ result: DirectoryEntry[],
106
+ fileLimit: number,
107
+ ): { directories: DirectoryEntry[]; count: number; suppressed: number; warning: string } | null {
108
+ const totalFiles = result.reduce((sum, d) => sum + d.files.length, 0);
109
+ if (totalFiles <= fileLimit) return null;
110
+
111
+ let shown = 0;
112
+ for (const d of result) {
113
+ const remaining = fileLimit - shown;
114
+ if (remaining <= 0) {
115
+ d.files = [];
116
+ } else if (d.files.length > remaining) {
117
+ d.files = d.files.slice(0, remaining);
118
+ shown = fileLimit;
119
+ } else {
120
+ shown += d.files.length;
121
+ }
122
+ }
123
+ const suppressed = totalFiles - fileLimit;
124
+ return {
125
+ directories: result,
126
+ count: result.length,
127
+ suppressed,
128
+ warning: `${suppressed} files omitted (showing ${fileLimit}/${totalFiles}). Use --full to show all files, or narrow with --directory.`,
129
+ };
130
+ }
131
+
71
132
  export function structureData(
72
133
  customDbPath?: string,
73
134
  opts: StructureDataOpts = {},
@@ -115,73 +176,27 @@ export function structureData(
115
176
  dirs.sort(sortFn);
116
177
 
117
178
  // Get file metrics for each directory
118
- const result: DirectoryEntry[] = dirs.map((d) => {
119
- let files = db
120
- .prepare(`
121
- SELECT n.name, nm.line_count, nm.symbol_count, nm.import_count, nm.export_count, nm.fan_in, nm.fan_out
122
- FROM edges e
123
- JOIN nodes n ON e.target_id = n.id
124
- LEFT JOIN node_metrics nm ON n.id = nm.node_id
125
- WHERE e.source_id = ? AND e.kind = 'contains' AND n.kind = 'file'
126
- `)
127
- .all(d.id) as FileMetricRow[];
128
- if (noTests) files = files.filter((f) => !isTestFile(f.name));
129
-
130
- const subdirs = db
131
- .prepare(`
132
- SELECT n.name
133
- FROM edges e
134
- JOIN nodes n ON e.target_id = n.id
135
- WHERE e.source_id = ? AND e.kind = 'contains' AND n.kind = 'directory'
136
- `)
137
- .all(d.id) as { name: string }[];
138
-
139
- const fileCount = noTests ? files.length : d.file_count || 0;
140
- return {
141
- directory: d.name,
142
- fileCount,
143
- symbolCount: d.symbol_count || 0,
144
- fanIn: d.fan_in || 0,
145
- fanOut: d.fan_out || 0,
146
- cohesion: d.cohesion,
147
- density: fileCount > 0 ? (d.symbol_count || 0) / fileCount : 0,
148
- files: files.map((f) => ({
149
- file: f.name,
150
- lineCount: f.line_count || 0,
151
- symbolCount: f.symbol_count || 0,
152
- importCount: f.import_count || 0,
153
- exportCount: f.export_count || 0,
154
- fanIn: f.fan_in || 0,
155
- fanOut: f.fan_out || 0,
156
- })),
157
- subdirectories: subdirs.map((s) => s.name),
158
- };
159
- });
179
+ const filesStmt = db.prepare(`
180
+ SELECT n.name, nm.line_count, nm.symbol_count, nm.import_count, nm.export_count, nm.fan_in, nm.fan_out
181
+ FROM edges e
182
+ JOIN nodes n ON e.target_id = n.id
183
+ LEFT JOIN node_metrics nm ON n.id = nm.node_id
184
+ WHERE e.source_id = ? AND e.kind = 'contains' AND n.kind = 'file'
185
+ `);
186
+ const subdirsStmt = db.prepare(`
187
+ SELECT n.name
188
+ FROM edges e
189
+ JOIN nodes n ON e.target_id = n.id
190
+ WHERE e.source_id = ? AND e.kind = 'contains' AND n.kind = 'directory'
191
+ `);
192
+ const result: DirectoryEntry[] = dirs.map((d) =>
193
+ buildDirectoryEntry(d, filesStmt, subdirsStmt, noTests),
194
+ );
160
195
 
161
196
  // Apply global file limit unless full mode
162
197
  if (!full) {
163
- const totalFiles = result.reduce((sum, d) => sum + d.files.length, 0);
164
- if (totalFiles > fileLimit) {
165
- let shown = 0;
166
- for (const d of result) {
167
- const remaining = fileLimit - shown;
168
- if (remaining <= 0) {
169
- d.files = [];
170
- } else if (d.files.length > remaining) {
171
- d.files = d.files.slice(0, remaining);
172
- shown = fileLimit;
173
- } else {
174
- shown += d.files.length;
175
- }
176
- }
177
- const suppressed = totalFiles - fileLimit;
178
- return {
179
- directories: result,
180
- count: result.length,
181
- suppressed,
182
- warning: `${suppressed} files omitted (showing ${fileLimit}/${totalFiles}). Use --full to show all files, or narrow with --directory.`,
183
- };
184
- }
198
+ const limited = applyFileLimit(result, fileLimit);
199
+ if (limited) return limited;
185
200
  }
186
201
 
187
202
  const base = { directories: result, count: result.length };
@@ -1,3 +1,4 @@
1
+ import { loadNative } from '../../infrastructure/native.js';
1
2
  import type { CodeGraph } from '../model.js';
2
3
 
3
4
  export interface BfsOpts {
@@ -8,6 +9,8 @@ export interface BfsOpts {
8
9
  /**
9
10
  * Breadth-first traversal on a CodeGraph.
10
11
  *
12
+ * Tries the native Rust implementation first, falls back to JS.
13
+ *
11
14
  * @returns nodeId → depth from nearest start node
12
15
  */
13
16
  export function bfs(
@@ -19,6 +22,37 @@ export function bfs(
19
22
  const direction = opts.direction ?? 'forward';
20
23
  const starts = Array.isArray(startIds) ? startIds : [startIds];
21
24
 
25
+ const native = loadNative();
26
+ if (native?.bfsTraversal) {
27
+ const edges = graph.toEdgeArray();
28
+ const nativeMaxDepth = maxDepth === Infinity ? null : maxDepth;
29
+ // Undirected graphs deduplicate edges to one canonical direction in toEdgeArray(),
30
+ // so the Rust side must traverse both directions to preserve symmetry.
31
+ const nativeDirection = !graph.directed ? 'both' : direction;
32
+ const result = native.bfsTraversal(edges, starts, nativeMaxDepth, nativeDirection);
33
+ const depths = new Map<string, number>();
34
+ for (const entry of result) {
35
+ depths.set(entry.node, entry.depth);
36
+ }
37
+ // The Rust side only knows nodes referenced by edges; restore any isolated start nodes.
38
+ for (const startId of starts) {
39
+ if (graph.hasNode(startId) && !depths.has(startId)) {
40
+ depths.set(startId, 0);
41
+ }
42
+ }
43
+ return depths;
44
+ }
45
+
46
+ return bfsJS(graph, starts, maxDepth, direction);
47
+ }
48
+
49
+ /** Pure JS fallback for BFS (used when native addon is unavailable). */
50
+ function bfsJS(
51
+ graph: CodeGraph,
52
+ starts: string[],
53
+ maxDepth: number,
54
+ direction: string,
55
+ ): Map<string, number> {
22
56
  const depths = new Map<string, number>();
23
57
  const queue: string[] = [];
24
58
 
@@ -1,3 +1,4 @@
1
+ import { loadNative } from '../../infrastructure/native.js';
1
2
  import type { CodeGraph } from '../model.js';
2
3
 
3
4
  export interface FanInOut {
@@ -7,8 +8,37 @@ export interface FanInOut {
7
8
 
8
9
  /**
9
10
  * Fan-in / fan-out centrality for all nodes in a CodeGraph.
11
+ *
12
+ * Tries the native Rust implementation first, falls back to JS.
10
13
  */
11
14
  export function fanInOut(graph: CodeGraph): Map<string, FanInOut> {
15
+ const native = loadNative();
16
+ if (native?.fanInOut) {
17
+ let edges = graph.toEdgeArray();
18
+ if (!graph.directed) {
19
+ // Undirected: toEdgeArray() deduplicates to one canonical direction;
20
+ // mirror each edge so the Rust side counts symmetric in/out degrees.
21
+ edges = [...edges, ...edges.map((e) => ({ source: e.target, target: e.source }))];
22
+ }
23
+ const nativeResult = native.fanInOut(edges);
24
+ const result = new Map<string, FanInOut>();
25
+ for (const entry of nativeResult) {
26
+ result.set(entry.node, { fanIn: entry.fanIn, fanOut: entry.fanOut });
27
+ }
28
+ // Ensure isolated nodes (no edges) are included
29
+ for (const id of graph.nodeIds()) {
30
+ if (!result.has(id)) {
31
+ result.set(id, { fanIn: 0, fanOut: 0 });
32
+ }
33
+ }
34
+ return result;
35
+ }
36
+
37
+ return fanInOutJS(graph);
38
+ }
39
+
40
+ /** Pure JS fallback for fan-in/out. */
41
+ function fanInOutJS(graph: CodeGraph): Map<string, FanInOut> {
12
42
  const result = new Map<string, FanInOut>();
13
43
  for (const id of graph.nodeIds()) {
14
44
  result.set(id, {
@@ -18,6 +18,13 @@ const DEFAULT_MAX_LEVELS: number = 50;
18
18
  const DEFAULT_MAX_LOCAL_PASSES: number = 20;
19
19
  const GAIN_EPSILON: number = 1e-12;
20
20
 
21
+ /** Pre-allocated scratch buffers for refinement candidate collection. */
22
+ interface RefinementScratch {
23
+ candC: Int32Array;
24
+ candGain: Float64Array;
25
+ candWeight: Float64Array;
26
+ }
27
+
21
28
  const CandidateStrategy = {
22
29
  Neighbors: 0,
23
30
  All: 1,
@@ -335,6 +342,79 @@ function buildCoarseGraph(g: GraphAdapter, p: Partition): CodeGraph {
335
342
  return coarse;
336
343
  }
337
344
 
345
+ /**
346
+ * Collect eligible candidate communities for node `v` during refinement.
347
+ * A candidate must: (a) be in the same macro-community, (b) respect the size
348
+ * limit, and (c) produce a positive quality gain above GAIN_EPSILON.
349
+ * Returns the number of collected candidates written into `scratch`.
350
+ */
351
+ function collectRefinementCandidates(
352
+ p: Partition,
353
+ g: GraphAdapter,
354
+ v: number,
355
+ touchedCount: number,
356
+ macroV: number,
357
+ commMacro: Int32Array,
358
+ maxSize: number,
359
+ opts: NormalizedOptions,
360
+ scratch: RefinementScratch,
361
+ ): number {
362
+ let candLen: number = 0;
363
+ for (let t = 0; t < touchedCount; t++) {
364
+ const c: number = p.getCandidateCommunityAt(t);
365
+ if (c === p.nodeCommunity[v]!) continue;
366
+ if (commMacro[c]! !== macroV) continue;
367
+ if (maxSize < Infinity) {
368
+ const nextSize: number = p.getCommunityTotalSize(c) + g.size[v]!;
369
+ if (nextSize > maxSize) continue;
370
+ }
371
+ const gain: number = computeQualityGain(p, v, c, opts);
372
+ if (gain > GAIN_EPSILON) {
373
+ scratch.candC[candLen] = c;
374
+ scratch.candGain[candLen] = gain;
375
+ candLen++;
376
+ }
377
+ }
378
+ return candLen;
379
+ }
380
+
381
+ /**
382
+ * Boltzmann probabilistic selection from collected candidates (Algorithm 3).
383
+ * Returns the chosen community ID, or -1 if the node should stay as singleton.
384
+ *
385
+ * p(v, C) is proportional to exp(deltaH / theta), with the "stay as singleton"
386
+ * option (deltaH = 0) included. For numerical stability, the max gain is
387
+ * subtracted before exponentiation.
388
+ */
389
+ function boltzmannSelectCandidate(
390
+ candLen: number,
391
+ theta: number,
392
+ rng: () => number,
393
+ scratch: RefinementScratch,
394
+ ): number {
395
+ let maxGain: number = 0;
396
+ for (let i = 0; i < candLen; i++) {
397
+ if (scratch.candGain[i]! > maxGain) maxGain = scratch.candGain[i]!;
398
+ }
399
+ // "Stay as singleton" weight: exp((0 - maxGain) / theta)
400
+ const stayWeight: number = Math.exp((0 - maxGain) / theta);
401
+ let totalWeight: number = stayWeight;
402
+ for (let i = 0; i < candLen; i++) {
403
+ scratch.candWeight[i] = Math.exp((scratch.candGain[i]! - maxGain) / theta);
404
+ totalWeight += scratch.candWeight[i]!;
405
+ }
406
+
407
+ const r: number = rng() * totalWeight;
408
+ if (r < stayWeight) return -1; // node stays as singleton
409
+
410
+ let cumulative: number = stayWeight;
411
+ for (let i = 0; i < candLen; i++) {
412
+ cumulative += scratch.candWeight[i]!;
413
+ if (r < cumulative) return scratch.candC[i]!;
414
+ }
415
+ return scratch.candC[candLen - 1]!; // fallback
416
+ }
417
+
338
418
  /**
339
419
  * True Leiden refinement phase (Algorithm 3, Traag et al. 2019).
340
420
  *
@@ -380,10 +460,12 @@ function refineWithinCoarseCommunities(
380
460
  shuffleArrayInPlace(order, rng);
381
461
 
382
462
  // Pre-allocate flat arrays for candidate collection to avoid per-node GC pressure.
383
- // Maximum possible candidates per node is bounded by g.n (community count).
384
- const candC = new Int32Array(g.n);
385
- const candGain = new Float64Array(g.n);
386
- const candWeight = new Float64Array(g.n);
463
+ const scratch: RefinementScratch = {
464
+ candC: new Int32Array(g.n),
465
+ candGain: new Float64Array(g.n),
466
+ candWeight: new Float64Array(g.n),
467
+ };
468
+ const maxSize: number = Number.isFinite(opts.maxCommunitySize) ? opts.maxCommunitySize : Infinity;
387
469
 
388
470
  for (let idx = 0; idx < order.length; idx++) {
389
471
  const v: number = order[idx]!;
@@ -394,59 +476,21 @@ function refineWithinCoarseCommunities(
394
476
 
395
477
  const macroV: number = macro[v]!;
396
478
  const touchedCount: number = p.accumulateNeighborCommunityEdgeWeights(v);
397
- const maxSize: number = Number.isFinite(opts.maxCommunitySize)
398
- ? opts.maxCommunitySize
399
- : Infinity;
400
-
401
- // Collect eligible communities and their quality gains.
402
- let candLen: number = 0;
403
- for (let t = 0; t < touchedCount; t++) {
404
- const c: number = p.getCandidateCommunityAt(t);
405
- if (c === p.nodeCommunity[v]!) continue;
406
- if (commMacro[c]! !== macroV) continue;
407
- if (maxSize < Infinity) {
408
- const nextSize: number = p.getCommunityTotalSize(c) + g.size[v]!;
409
- if (nextSize > maxSize) continue;
410
- }
411
- const gain: number = computeQualityGain(p, v, c, opts);
412
- if (gain > GAIN_EPSILON) {
413
- candC[candLen] = c;
414
- candGain[candLen] = gain;
415
- candLen++;
416
- }
417
- }
418
-
479
+ const candLen: number = collectRefinementCandidates(
480
+ p,
481
+ g,
482
+ v,
483
+ touchedCount,
484
+ macroV,
485
+ commMacro,
486
+ maxSize,
487
+ opts,
488
+ scratch,
489
+ );
419
490
  if (candLen === 0) continue;
420
491
 
421
- // Probabilistic selection: p(v, C) proportional to exp(deltaH / theta),
422
- // with the "stay" option (deltaH = 0) included per Algorithm 3.
423
- // For numerical stability, subtract the max gain before exponentiation.
424
- let maxGain: number = 0;
425
- for (let i = 0; i < candLen; i++) {
426
- if (candGain[i]! > maxGain) maxGain = candGain[i]!;
427
- }
428
- // "Stay as singleton" weight: exp((0 - maxGain) / theta)
429
- const stayWeight: number = Math.exp((0 - maxGain) / theta);
430
- let totalWeight: number = stayWeight;
431
- for (let i = 0; i < candLen; i++) {
432
- candWeight[i] = Math.exp((candGain[i]! - maxGain) / theta);
433
- totalWeight += candWeight[i]!;
434
- }
435
-
436
- const r: number = rng() * totalWeight;
437
- if (r < stayWeight) continue; // node stays as singleton
438
-
439
- let cumulative: number = stayWeight;
440
- let chosenC: number = candC[candLen - 1]!; // fallback
441
- for (let i = 0; i < candLen; i++) {
442
- cumulative += candWeight[i]!;
443
- if (r < cumulative) {
444
- chosenC = candC[i]!;
445
- break;
446
- }
447
- }
448
-
449
- p.moveNodeToCommunity(v, chosenC);
492
+ const chosenC: number = boltzmannSelectCandidate(candLen, theta, rng, scratch);
493
+ if (chosenC >= 0) p.moveNodeToCommunity(v, chosenC);
450
494
  }
451
495
  return p;
452
496
  }