@optave/codegraph 3.13.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 (458) hide show
  1. package/README.md +35 -34
  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/config.d.ts.map +1 -1
  51. package/dist/cli/commands/config.js +137 -134
  52. package/dist/cli/commands/config.js.map +1 -1
  53. package/dist/cli/commands/roles.d.ts.map +1 -1
  54. package/dist/cli/commands/roles.js +6 -1
  55. package/dist/cli/commands/roles.js.map +1 -1
  56. package/dist/db/better-sqlite3.d.ts +2 -1
  57. package/dist/db/better-sqlite3.d.ts.map +1 -1
  58. package/dist/db/better-sqlite3.js.map +1 -1
  59. package/dist/db/connection.d.ts +7 -1
  60. package/dist/db/connection.d.ts.map +1 -1
  61. package/dist/db/connection.js +20 -5
  62. package/dist/db/connection.js.map +1 -1
  63. package/dist/db/index.d.ts +1 -1
  64. package/dist/db/index.d.ts.map +1 -1
  65. package/dist/db/index.js +1 -1
  66. package/dist/db/index.js.map +1 -1
  67. package/dist/db/migrations.d.ts.map +1 -1
  68. package/dist/db/migrations.js +68 -0
  69. package/dist/db/migrations.js.map +1 -1
  70. package/dist/db/repository/build-stmts.d.ts.map +1 -1
  71. package/dist/db/repository/build-stmts.js +18 -0
  72. package/dist/db/repository/build-stmts.js.map +1 -1
  73. package/dist/db/repository/dataflow.d.ts +5 -0
  74. package/dist/db/repository/dataflow.d.ts.map +1 -1
  75. package/dist/db/repository/dataflow.js +14 -0
  76. package/dist/db/repository/dataflow.js.map +1 -1
  77. package/dist/db/repository/index.d.ts +1 -1
  78. package/dist/db/repository/index.d.ts.map +1 -1
  79. package/dist/db/repository/index.js +1 -1
  80. package/dist/db/repository/index.js.map +1 -1
  81. package/dist/db/repository/native-repository.d.ts.map +1 -1
  82. package/dist/db/repository/native-repository.js +47 -34
  83. package/dist/db/repository/native-repository.js.map +1 -1
  84. package/dist/domain/analysis/context.d.ts +2 -2
  85. package/dist/domain/analysis/dependencies.d.ts +2 -2
  86. package/dist/domain/analysis/diff-impact.d.ts +2 -2
  87. package/dist/domain/analysis/fn-impact.d.ts +3 -1
  88. package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
  89. package/dist/domain/analysis/fn-impact.js +4 -0
  90. package/dist/domain/analysis/fn-impact.js.map +1 -1
  91. package/dist/domain/analysis/implementations.d.ts +2 -2
  92. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  93. package/dist/domain/analysis/module-map.js +32 -5
  94. package/dist/domain/analysis/module-map.js.map +1 -1
  95. package/dist/domain/analysis/roles.d.ts +7 -1
  96. package/dist/domain/analysis/roles.d.ts.map +1 -1
  97. package/dist/domain/analysis/roles.js +16 -0
  98. package/dist/domain/analysis/roles.js.map +1 -1
  99. package/dist/domain/analysis/symbol-lookup.d.ts +4 -4
  100. package/dist/domain/graph/builder/call-resolver.d.ts +17 -5
  101. package/dist/domain/graph/builder/call-resolver.d.ts.map +1 -1
  102. package/dist/domain/graph/builder/call-resolver.js +85 -220
  103. package/dist/domain/graph/builder/call-resolver.js.map +1 -1
  104. package/dist/domain/graph/builder/context.d.ts +1 -0
  105. package/dist/domain/graph/builder/context.d.ts.map +1 -1
  106. package/dist/domain/graph/builder/context.js.map +1 -1
  107. package/dist/domain/graph/builder/helpers.d.ts +16 -1
  108. package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
  109. package/dist/domain/graph/builder/helpers.js +162 -72
  110. package/dist/domain/graph/builder/helpers.js.map +1 -1
  111. package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
  112. package/dist/domain/graph/builder/incremental.js +166 -97
  113. package/dist/domain/graph/builder/incremental.js.map +1 -1
  114. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  115. package/dist/domain/graph/builder/pipeline.js +10 -4
  116. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  117. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  118. package/dist/domain/graph/builder/stages/build-edges.js +496 -250
  119. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  120. package/dist/domain/graph/builder/stages/collect-files.d.ts.map +1 -1
  121. package/dist/domain/graph/builder/stages/collect-files.js +10 -7
  122. package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
  123. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  124. package/dist/domain/graph/builder/stages/detect-changes.js +2 -1
  125. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  126. package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -1
  127. package/dist/domain/graph/builder/stages/native-orchestrator.js +895 -545
  128. package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -1
  129. package/dist/domain/graph/resolver/points-to.d.ts.map +1 -1
  130. package/dist/domain/graph/resolver/points-to.js +105 -57
  131. package/dist/domain/graph/resolver/points-to.js.map +1 -1
  132. package/dist/domain/graph/resolver/strategy.d.ts +61 -0
  133. package/dist/domain/graph/resolver/strategy.d.ts.map +1 -0
  134. package/dist/domain/graph/resolver/strategy.js +222 -0
  135. package/dist/domain/graph/resolver/strategy.js.map +1 -0
  136. package/dist/domain/graph/watcher.d.ts.map +1 -1
  137. package/dist/domain/graph/watcher.js +16 -9
  138. package/dist/domain/graph/watcher.js.map +1 -1
  139. package/dist/domain/parser.d.ts +12 -0
  140. package/dist/domain/parser.d.ts.map +1 -1
  141. package/dist/domain/parser.js +12 -2
  142. package/dist/domain/parser.js.map +1 -1
  143. package/dist/domain/queries.d.ts +1 -1
  144. package/dist/domain/queries.d.ts.map +1 -1
  145. package/dist/domain/queries.js +1 -1
  146. package/dist/domain/queries.js.map +1 -1
  147. package/dist/domain/wasm-worker-entry.js +3 -0
  148. package/dist/domain/wasm-worker-entry.js.map +1 -1
  149. package/dist/domain/wasm-worker-pool.d.ts.map +1 -1
  150. package/dist/domain/wasm-worker-pool.js +24 -5
  151. package/dist/domain/wasm-worker-pool.js.map +1 -1
  152. package/dist/domain/wasm-worker-protocol.d.ts +7 -0
  153. package/dist/domain/wasm-worker-protocol.d.ts.map +1 -1
  154. package/dist/extractors/dart.js +48 -3
  155. package/dist/extractors/dart.js.map +1 -1
  156. package/dist/extractors/groovy.js +62 -3
  157. package/dist/extractors/groovy.js.map +1 -1
  158. package/dist/extractors/helpers.d.ts +4 -2
  159. package/dist/extractors/helpers.d.ts.map +1 -1
  160. package/dist/extractors/helpers.js +5 -1
  161. package/dist/extractors/helpers.js.map +1 -1
  162. package/dist/extractors/java.js +77 -1
  163. package/dist/extractors/java.js.map +1 -1
  164. package/dist/extractors/javascript.d.ts.map +1 -1
  165. package/dist/extractors/javascript.js +549 -163
  166. package/dist/extractors/javascript.js.map +1 -1
  167. package/dist/extractors/kotlin.js +58 -3
  168. package/dist/extractors/kotlin.js.map +1 -1
  169. package/dist/extractors/objc.js +25 -2
  170. package/dist/extractors/objc.js.map +1 -1
  171. package/dist/extractors/scala.js +62 -2
  172. package/dist/extractors/scala.js.map +1 -1
  173. package/dist/extractors/swift.js +52 -3
  174. package/dist/extractors/swift.js.map +1 -1
  175. package/dist/features/audit.js +26 -23
  176. package/dist/features/audit.js.map +1 -1
  177. package/dist/features/boundaries.d.ts.map +1 -1
  178. package/dist/features/boundaries.js +12 -9
  179. package/dist/features/boundaries.js.map +1 -1
  180. package/dist/features/cfg.d.ts.map +1 -1
  181. package/dist/features/cfg.js +25 -18
  182. package/dist/features/cfg.js.map +1 -1
  183. package/dist/features/check.d.ts.map +1 -1
  184. package/dist/features/check.js +18 -5
  185. package/dist/features/check.js.map +1 -1
  186. package/dist/features/communities.d.ts +4 -2
  187. package/dist/features/communities.d.ts.map +1 -1
  188. package/dist/features/communities.js +6 -4
  189. package/dist/features/communities.js.map +1 -1
  190. package/dist/features/dataflow.d.ts +60 -0
  191. package/dist/features/dataflow.d.ts.map +1 -1
  192. package/dist/features/dataflow.js +530 -6
  193. package/dist/features/dataflow.js.map +1 -1
  194. package/dist/features/manifesto.d.ts.map +1 -1
  195. package/dist/features/manifesto.js +59 -72
  196. package/dist/features/manifesto.js.map +1 -1
  197. package/dist/features/sequence.d.ts.map +1 -1
  198. package/dist/features/sequence.js +27 -22
  199. package/dist/features/sequence.js.map +1 -1
  200. package/dist/features/snapshot.d.ts.map +1 -1
  201. package/dist/features/snapshot.js +36 -28
  202. package/dist/features/snapshot.js.map +1 -1
  203. package/dist/features/structure.d.ts.map +1 -1
  204. package/dist/features/structure.js +150 -62
  205. package/dist/features/structure.js.map +1 -1
  206. package/dist/features/triage.d.ts.map +1 -1
  207. package/dist/features/triage.js +18 -11
  208. package/dist/features/triage.js.map +1 -1
  209. package/dist/graph/algorithms/bfs.d.ts +1 -1
  210. package/dist/graph/algorithms/bfs.d.ts.map +1 -1
  211. package/dist/graph/algorithms/bfs.js +14 -13
  212. package/dist/graph/algorithms/bfs.js.map +1 -1
  213. package/dist/graph/algorithms/tarjan.d.ts.map +1 -1
  214. package/dist/graph/algorithms/tarjan.js +5 -0
  215. package/dist/graph/algorithms/tarjan.js.map +1 -1
  216. package/dist/graph/builders/dependency.js +28 -22
  217. package/dist/graph/builders/dependency.js.map +1 -1
  218. package/dist/graph/classifiers/roles.d.ts +10 -1
  219. package/dist/graph/classifiers/roles.d.ts.map +1 -1
  220. package/dist/graph/classifiers/roles.js +60 -6
  221. package/dist/graph/classifiers/roles.js.map +1 -1
  222. package/dist/infrastructure/config.d.ts +10 -0
  223. package/dist/infrastructure/config.d.ts.map +1 -1
  224. package/dist/infrastructure/config.js +31 -3
  225. package/dist/infrastructure/config.js.map +1 -1
  226. package/dist/infrastructure/registry.d.ts +0 -7
  227. package/dist/infrastructure/registry.d.ts.map +1 -1
  228. package/dist/infrastructure/registry.js +29 -13
  229. package/dist/infrastructure/registry.js.map +1 -1
  230. package/dist/infrastructure/update-check.d.ts.map +1 -1
  231. package/dist/infrastructure/update-check.js +49 -31
  232. package/dist/infrastructure/update-check.js.map +1 -1
  233. package/dist/mcp/server.d.ts +2 -10
  234. package/dist/mcp/server.d.ts.map +1 -1
  235. package/dist/mcp/server.js.map +1 -1
  236. package/dist/mcp/tools/ast-query.d.ts +1 -1
  237. package/dist/mcp/tools/ast-query.d.ts.map +1 -1
  238. package/dist/mcp/tools/audit.d.ts +1 -1
  239. package/dist/mcp/tools/audit.d.ts.map +1 -1
  240. package/dist/mcp/tools/batch-query.d.ts +1 -1
  241. package/dist/mcp/tools/batch-query.d.ts.map +1 -1
  242. package/dist/mcp/tools/branch-compare.d.ts +1 -1
  243. package/dist/mcp/tools/branch-compare.d.ts.map +1 -1
  244. package/dist/mcp/tools/brief.d.ts +1 -1
  245. package/dist/mcp/tools/brief.d.ts.map +1 -1
  246. package/dist/mcp/tools/cfg.d.ts +1 -1
  247. package/dist/mcp/tools/cfg.d.ts.map +1 -1
  248. package/dist/mcp/tools/check.d.ts +1 -1
  249. package/dist/mcp/tools/check.d.ts.map +1 -1
  250. package/dist/mcp/tools/co-changes.d.ts +1 -1
  251. package/dist/mcp/tools/co-changes.d.ts.map +1 -1
  252. package/dist/mcp/tools/code-owners.d.ts +1 -1
  253. package/dist/mcp/tools/code-owners.d.ts.map +1 -1
  254. package/dist/mcp/tools/communities.d.ts +1 -1
  255. package/dist/mcp/tools/communities.d.ts.map +1 -1
  256. package/dist/mcp/tools/complexity.d.ts +1 -1
  257. package/dist/mcp/tools/complexity.d.ts.map +1 -1
  258. package/dist/mcp/tools/context.d.ts +1 -1
  259. package/dist/mcp/tools/context.d.ts.map +1 -1
  260. package/dist/mcp/tools/dataflow.d.ts +1 -1
  261. package/dist/mcp/tools/dataflow.d.ts.map +1 -1
  262. package/dist/mcp/tools/diff-impact.d.ts +1 -1
  263. package/dist/mcp/tools/diff-impact.d.ts.map +1 -1
  264. package/dist/mcp/tools/execution-flow.d.ts +1 -1
  265. package/dist/mcp/tools/execution-flow.d.ts.map +1 -1
  266. package/dist/mcp/tools/export-graph.d.ts +1 -1
  267. package/dist/mcp/tools/export-graph.d.ts.map +1 -1
  268. package/dist/mcp/tools/file-deps.d.ts +1 -1
  269. package/dist/mcp/tools/file-deps.d.ts.map +1 -1
  270. package/dist/mcp/tools/file-exports.d.ts +1 -1
  271. package/dist/mcp/tools/file-exports.d.ts.map +1 -1
  272. package/dist/mcp/tools/find-cycles.d.ts +1 -1
  273. package/dist/mcp/tools/find-cycles.d.ts.map +1 -1
  274. package/dist/mcp/tools/fn-impact.d.ts +1 -1
  275. package/dist/mcp/tools/fn-impact.d.ts.map +1 -1
  276. package/dist/mcp/tools/impact-analysis.d.ts +1 -1
  277. package/dist/mcp/tools/impact-analysis.d.ts.map +1 -1
  278. package/dist/mcp/tools/implementations.d.ts +1 -1
  279. package/dist/mcp/tools/implementations.d.ts.map +1 -1
  280. package/dist/mcp/tools/index.d.ts +2 -5
  281. package/dist/mcp/tools/index.d.ts.map +1 -1
  282. package/dist/mcp/tools/index.js.map +1 -1
  283. package/dist/mcp/tools/interfaces.d.ts +1 -1
  284. package/dist/mcp/tools/interfaces.d.ts.map +1 -1
  285. package/dist/mcp/tools/list-functions.d.ts +1 -1
  286. package/dist/mcp/tools/list-functions.d.ts.map +1 -1
  287. package/dist/mcp/tools/list-repos.d.ts +1 -1
  288. package/dist/mcp/tools/list-repos.d.ts.map +1 -1
  289. package/dist/mcp/tools/module-map.d.ts +1 -1
  290. package/dist/mcp/tools/module-map.d.ts.map +1 -1
  291. package/dist/mcp/tools/node-roles.d.ts +1 -1
  292. package/dist/mcp/tools/node-roles.d.ts.map +1 -1
  293. package/dist/mcp/tools/path.d.ts +1 -1
  294. package/dist/mcp/tools/path.d.ts.map +1 -1
  295. package/dist/mcp/tools/query.d.ts +1 -1
  296. package/dist/mcp/tools/query.d.ts.map +1 -1
  297. package/dist/mcp/tools/semantic-search.d.ts +1 -1
  298. package/dist/mcp/tools/semantic-search.d.ts.map +1 -1
  299. package/dist/mcp/tools/sequence.d.ts +1 -1
  300. package/dist/mcp/tools/sequence.d.ts.map +1 -1
  301. package/dist/mcp/tools/structure.d.ts +1 -1
  302. package/dist/mcp/tools/structure.d.ts.map +1 -1
  303. package/dist/mcp/tools/symbol-children.d.ts +1 -1
  304. package/dist/mcp/tools/symbol-children.d.ts.map +1 -1
  305. package/dist/mcp/tools/triage.d.ts +1 -1
  306. package/dist/mcp/tools/triage.d.ts.map +1 -1
  307. package/dist/mcp/tools/where.d.ts +1 -1
  308. package/dist/mcp/tools/where.d.ts.map +1 -1
  309. package/dist/mcp/types.d.ts +19 -0
  310. package/dist/mcp/types.d.ts.map +1 -0
  311. package/dist/mcp/types.js +6 -0
  312. package/dist/mcp/types.js.map +1 -0
  313. package/dist/presentation/queries-cli/index.d.ts +1 -1
  314. package/dist/presentation/queries-cli/index.d.ts.map +1 -1
  315. package/dist/presentation/queries-cli/index.js +1 -1
  316. package/dist/presentation/queries-cli/index.js.map +1 -1
  317. package/dist/presentation/queries-cli/overview.d.ts +1 -0
  318. package/dist/presentation/queries-cli/overview.d.ts.map +1 -1
  319. package/dist/presentation/queries-cli/overview.js +20 -1
  320. package/dist/presentation/queries-cli/overview.js.map +1 -1
  321. package/dist/presentation/queries-cli.d.ts +1 -1
  322. package/dist/presentation/queries-cli.d.ts.map +1 -1
  323. package/dist/presentation/queries-cli.js +1 -1
  324. package/dist/presentation/queries-cli.js.map +1 -1
  325. package/dist/presentation/viewer.d.ts.map +1 -1
  326. package/dist/presentation/viewer.js +45 -32
  327. package/dist/presentation/viewer.js.map +1 -1
  328. package/dist/shared/constants.d.ts +21 -0
  329. package/dist/shared/constants.d.ts.map +1 -1
  330. package/dist/shared/constants.js +25 -0
  331. package/dist/shared/constants.js.map +1 -1
  332. package/dist/shared/normalize.d.ts.map +1 -1
  333. package/dist/shared/normalize.js +12 -22
  334. package/dist/shared/normalize.js.map +1 -1
  335. package/dist/shared/paginate.d.ts +4 -17
  336. package/dist/shared/paginate.d.ts.map +1 -1
  337. package/dist/shared/paginate.js.map +1 -1
  338. package/dist/types.d.ts +76 -1
  339. package/dist/types.d.ts.map +1 -1
  340. package/grammars/tree-sitter-erlang.wasm +0 -0
  341. package/package.json +7 -7
  342. package/src/ast-analysis/engine.ts +43 -63
  343. package/src/ast-analysis/rules/b2.ts +263 -0
  344. package/src/ast-analysis/rules/b3.ts +127 -0
  345. package/src/ast-analysis/rules/b4.ts +378 -0
  346. package/src/ast-analysis/rules/b5.ts +65 -0
  347. package/src/ast-analysis/rules/c.ts +157 -0
  348. package/src/ast-analysis/rules/index.ts +34 -0
  349. package/src/ast-analysis/rules/javascript.ts +3 -0
  350. package/src/ast-analysis/shared.ts +2 -0
  351. package/src/ast-analysis/visitor-utils.ts +5 -0
  352. package/src/ast-analysis/visitor.ts +82 -52
  353. package/src/ast-analysis/visitors/cfg-visitor.ts +198 -84
  354. package/src/ast-analysis/visitors/complexity-visitor.ts +44 -16
  355. package/src/ast-analysis/visitors/dataflow-visitor.ts +68 -29
  356. package/src/cli/commands/config.ts +184 -184
  357. package/src/cli/commands/roles.ts +6 -1
  358. package/src/db/better-sqlite3.ts +5 -4
  359. package/src/db/connection.ts +23 -5
  360. package/src/db/index.ts +1 -0
  361. package/src/db/migrations.ts +68 -0
  362. package/src/db/repository/build-stmts.ts +30 -0
  363. package/src/db/repository/dataflow.ts +16 -0
  364. package/src/db/repository/index.ts +1 -1
  365. package/src/db/repository/native-repository.ts +56 -40
  366. package/src/domain/analysis/fn-impact.ts +4 -0
  367. package/src/domain/analysis/module-map.ts +38 -6
  368. package/src/domain/analysis/roles.ts +23 -0
  369. package/src/domain/graph/builder/call-resolver.ts +112 -232
  370. package/src/domain/graph/builder/context.ts +1 -0
  371. package/src/domain/graph/builder/helpers.ts +190 -72
  372. package/src/domain/graph/builder/incremental.ts +249 -120
  373. package/src/domain/graph/builder/pipeline.ts +11 -5
  374. package/src/domain/graph/builder/stages/build-edges.ts +696 -296
  375. package/src/domain/graph/builder/stages/collect-files.ts +12 -6
  376. package/src/domain/graph/builder/stages/detect-changes.ts +3 -1
  377. package/src/domain/graph/builder/stages/native-orchestrator.ts +1102 -590
  378. package/src/domain/graph/resolver/points-to.ts +182 -59
  379. package/src/domain/graph/resolver/strategy.ts +265 -0
  380. package/src/domain/graph/watcher.ts +19 -9
  381. package/src/domain/parser.ts +12 -2
  382. package/src/domain/queries.ts +1 -1
  383. package/src/domain/wasm-worker-entry.ts +3 -0
  384. package/src/domain/wasm-worker-pool.ts +28 -4
  385. package/src/domain/wasm-worker-protocol.ts +4 -0
  386. package/src/extractors/dart.ts +48 -3
  387. package/src/extractors/groovy.ts +62 -2
  388. package/src/extractors/helpers.ts +5 -2
  389. package/src/extractors/java.ts +80 -1
  390. package/src/extractors/javascript.ts +566 -161
  391. package/src/extractors/kotlin.ts +57 -3
  392. package/src/extractors/objc.ts +25 -1
  393. package/src/extractors/scala.ts +63 -1
  394. package/src/extractors/swift.ts +46 -3
  395. package/src/features/audit.ts +43 -34
  396. package/src/features/boundaries.ts +17 -9
  397. package/src/features/cfg.ts +31 -22
  398. package/src/features/check.ts +21 -5
  399. package/src/features/communities.ts +28 -19
  400. package/src/features/dataflow.ts +755 -6
  401. package/src/features/manifesto.ts +76 -75
  402. package/src/features/sequence.ts +29 -23
  403. package/src/features/snapshot.ts +36 -25
  404. package/src/features/structure.ts +185 -55
  405. package/src/features/triage.ts +28 -15
  406. package/src/graph/algorithms/bfs.ts +13 -12
  407. package/src/graph/algorithms/tarjan.ts +5 -0
  408. package/src/graph/builders/dependency.ts +35 -23
  409. package/src/graph/classifiers/roles.ts +74 -7
  410. package/src/infrastructure/config.ts +32 -3
  411. package/src/infrastructure/registry.ts +44 -20
  412. package/src/infrastructure/update-check.ts +55 -33
  413. package/src/mcp/server.ts +2 -8
  414. package/src/mcp/tools/ast-query.ts +1 -1
  415. package/src/mcp/tools/audit.ts +1 -1
  416. package/src/mcp/tools/batch-query.ts +1 -1
  417. package/src/mcp/tools/branch-compare.ts +1 -1
  418. package/src/mcp/tools/brief.ts +1 -1
  419. package/src/mcp/tools/cfg.ts +1 -1
  420. package/src/mcp/tools/check.ts +1 -1
  421. package/src/mcp/tools/co-changes.ts +1 -1
  422. package/src/mcp/tools/code-owners.ts +1 -1
  423. package/src/mcp/tools/communities.ts +1 -1
  424. package/src/mcp/tools/complexity.ts +1 -1
  425. package/src/mcp/tools/context.ts +1 -1
  426. package/src/mcp/tools/dataflow.ts +1 -1
  427. package/src/mcp/tools/diff-impact.ts +1 -1
  428. package/src/mcp/tools/execution-flow.ts +1 -1
  429. package/src/mcp/tools/export-graph.ts +1 -1
  430. package/src/mcp/tools/file-deps.ts +1 -1
  431. package/src/mcp/tools/file-exports.ts +1 -1
  432. package/src/mcp/tools/find-cycles.ts +1 -1
  433. package/src/mcp/tools/fn-impact.ts +1 -1
  434. package/src/mcp/tools/impact-analysis.ts +1 -1
  435. package/src/mcp/tools/implementations.ts +1 -1
  436. package/src/mcp/tools/index.ts +2 -5
  437. package/src/mcp/tools/interfaces.ts +1 -1
  438. package/src/mcp/tools/list-functions.ts +1 -1
  439. package/src/mcp/tools/list-repos.ts +1 -1
  440. package/src/mcp/tools/module-map.ts +1 -1
  441. package/src/mcp/tools/node-roles.ts +1 -1
  442. package/src/mcp/tools/path.ts +1 -1
  443. package/src/mcp/tools/query.ts +1 -1
  444. package/src/mcp/tools/semantic-search.ts +1 -1
  445. package/src/mcp/tools/sequence.ts +1 -1
  446. package/src/mcp/tools/structure.ts +1 -1
  447. package/src/mcp/tools/symbol-children.ts +1 -1
  448. package/src/mcp/tools/triage.ts +1 -1
  449. package/src/mcp/tools/where.ts +1 -1
  450. package/src/mcp/types.ts +21 -0
  451. package/src/presentation/queries-cli/index.ts +1 -1
  452. package/src/presentation/queries-cli/overview.ts +35 -1
  453. package/src/presentation/queries-cli.ts +1 -0
  454. package/src/presentation/viewer.ts +98 -87
  455. package/src/shared/constants.ts +26 -0
  456. package/src/shared/normalize.ts +13 -22
  457. package/src/shared/paginate.ts +4 -18
  458. package/src/types.ts +86 -1
@@ -287,6 +287,28 @@ function handleAssignment(
287
287
  }
288
288
  }
289
289
 
290
+ /** Unwrap argument wrapper and spread nodes to get the core argument node. */
291
+ function unwrapArg(
292
+ arg: TreeSitterNode,
293
+ rules: AnyRules,
294
+ ): { unwrapped: TreeSitterNode; raw: TreeSitterNode } {
295
+ let raw = arg;
296
+ if (rules.argumentWrapperType && arg.type === rules.argumentWrapperType) {
297
+ raw = arg.namedChildren[0] || arg;
298
+ }
299
+ const unwrapped =
300
+ rules.spreadType && raw.type === rules.spreadType ? raw.namedChildren[0] || raw : raw;
301
+ return { unwrapped, raw };
302
+ }
303
+
304
+ /** Resolve the tracked name for a call argument (identifier or member receiver). */
305
+ function resolveArgTrackedName(node: TreeSitterNode, rules: AnyRules): string | null {
306
+ const argName = isIdent(node.type, rules) ? node.text : null;
307
+ const argMember =
308
+ rules.memberNode && node.type === rules.memberNode ? memberReceiver(node, rules) : null;
309
+ return argName || argMember;
310
+ }
311
+
290
312
  function handleCallExpr(
291
313
  node: TreeSitterNode,
292
314
  rules: AnyRules,
@@ -299,24 +321,14 @@ function handleCallExpr(
299
321
  if (!callee || !argsNode || !scope?.funcName) return;
300
322
 
301
323
  let argIndex = 0;
302
- for (let arg of argsNode.namedChildren) {
303
- if (rules.argumentWrapperType && arg.type === rules.argumentWrapperType) {
304
- arg = arg.namedChildren[0] || arg;
305
- }
306
- const unwrapped =
307
- rules.spreadType && arg.type === rules.spreadType ? arg.namedChildren[0] || arg : arg;
324
+ for (const arg of argsNode.namedChildren) {
325
+ const { unwrapped, raw } = unwrapArg(arg, rules);
308
326
  if (!unwrapped) {
309
327
  argIndex++;
310
328
  continue;
311
329
  }
312
330
 
313
- const argName = isIdent(unwrapped.type, rules) ? unwrapped.text : null;
314
- const argMember =
315
- rules.memberNode && unwrapped.type === rules.memberNode
316
- ? memberReceiver(unwrapped, rules)
317
- : null;
318
- const trackedName = argName || argMember;
319
-
331
+ const trackedName = resolveArgTrackedName(unwrapped, rules);
320
332
  if (trackedName) {
321
333
  const binding = findBinding(trackedName, scopeStack);
322
334
  if (binding) {
@@ -327,7 +339,7 @@ function handleCallExpr(
327
339
  argName: trackedName,
328
340
  binding,
329
341
  confidence: bindingConfidence(binding),
330
- expression: truncate(arg.text),
342
+ expression: truncate(raw.text),
331
343
  line: node.startPosition.row + 1,
332
344
  });
333
345
  }
@@ -336,17 +348,11 @@ function handleCallExpr(
336
348
  }
337
349
  }
338
350
 
339
- function handleExprStmtMutation(
340
- node: TreeSitterNode,
351
+ /** Resolve the method name and receiver from a call expression node. */
352
+ function resolveMutationCallParts(
353
+ expr: TreeSitterNode,
341
354
  rules: AnyRules,
342
- scopeStack: ScopeEntry[],
343
- mutations: DataflowMutation[],
344
- isCallNode: (t: string) => boolean,
345
- ): void {
346
- if (rules.mutatingMethods.size === 0) return;
347
- const expr = node.namedChildren[0];
348
- if (!expr || !isCall(expr, isCallNode)) return;
349
-
355
+ ): { methodName: string | null; receiver: string | null } {
350
356
  let methodName: string | null = null;
351
357
  let receiver: string | null = null;
352
358
 
@@ -366,6 +372,21 @@ function handleExprStmtMutation(
366
372
  }
367
373
  }
368
374
 
375
+ return { methodName, receiver };
376
+ }
377
+
378
+ function handleExprStmtMutation(
379
+ node: TreeSitterNode,
380
+ rules: AnyRules,
381
+ scopeStack: ScopeEntry[],
382
+ mutations: DataflowMutation[],
383
+ isCallNode: (t: string) => boolean,
384
+ ): void {
385
+ if (rules.mutatingMethods.size === 0) return;
386
+ const expr = node.namedChildren[0];
387
+ if (!expr || !isCall(expr, isCallNode)) return;
388
+
389
+ const { methodName, receiver } = resolveMutationCallParts(expr, rules);
369
390
  if (!methodName || !rules.mutatingMethods.has(methodName)) return;
370
391
 
371
392
  const scope = currentScope(scopeStack);
@@ -405,15 +426,27 @@ function handleReturn(
405
426
  }
406
427
  }
407
428
 
408
- /** Collect parameter entries for a function and push a new scope onto the stack. */
429
+ /**
430
+ * Collect parameter entries for a function and push a new scope onto the stack.
431
+ *
432
+ * Returns `true` if a scope was pushed, `false` if the node was skipped (i.e.
433
+ * `nameExtractor` rejected it). Callers must pop the stack only when this
434
+ * returns `true` to keep push/pop symmetric.
435
+ */
409
436
  function enterFunctionScope(
410
437
  funcNode: TreeSitterNode,
411
438
  rules: AnyRules,
412
439
  scopeStack: ScopeEntry[],
413
440
  parameters: DataflowParam[],
414
- ): void {
441
+ ): boolean {
442
+ // When nameExtractor is set it acts as a gate: null means this node is not a function
443
+ // definition. Needed for languages (Elixir, Clojure) where functionNodes includes generic
444
+ // node types (call/list_lit) that are only sometimes function definitions.
445
+ if (rules.nameExtractor && !rules.nameExtractor(funcNode)) return false;
415
446
  const name = functionName(funcNode, rules);
416
- const paramsNode = funcNode.childForFieldName(rules.paramListField);
447
+ const paramsNode = rules.getParamListNode
448
+ ? rules.getParamListNode(funcNode)
449
+ : funcNode.childForFieldName(rules.paramListField);
417
450
  const paramList = extractParams(paramsNode, rules);
418
451
  const paramMap = new Map<string, number>();
419
452
  for (const p of paramList) {
@@ -428,6 +461,7 @@ function enterFunctionScope(
428
461
  }
429
462
  }
430
463
  scopeStack.push({ funcName: name, funcNode, params: paramMap, locals: new Map() });
464
+ return true;
431
465
  }
432
466
 
433
467
  interface DataflowDispatchCtx {
@@ -489,6 +523,11 @@ export function createDataflowVisitor(rules: AnyRules): Visitor {
489
523
  const argFlows: DataflowArgFlow[] = [];
490
524
  const mutations: DataflowMutation[] = [];
491
525
  const scopeStack: ScopeEntry[] = [];
526
+ // Parallel stack that records whether each enterFunction call actually pushed a
527
+ // scope frame. exitFunction pops scopeStack only when the matching entry is true,
528
+ // keeping push/pop symmetric even for languages (Elixir, Clojure) where
529
+ // enterFunctionScope may return early without pushing.
530
+ const pushRecord: boolean[] = [];
492
531
 
493
532
  const dispatchCtx: DataflowDispatchCtx = {
494
533
  rules,
@@ -509,7 +548,7 @@ export function createDataflowVisitor(rules: AnyRules): Visitor {
509
548
  _funcName: string | null,
510
549
  _context: VisitorContext,
511
550
  ): void {
512
- enterFunctionScope(funcNode, rules, scopeStack, parameters);
551
+ pushRecord.push(enterFunctionScope(funcNode, rules, scopeStack, parameters));
513
552
  },
514
553
 
515
554
  exitFunction(
@@ -517,7 +556,7 @@ export function createDataflowVisitor(rules: AnyRules): Visitor {
517
556
  _funcName: string | null,
518
557
  _context: VisitorContext,
519
558
  ): void {
520
- scopeStack.pop();
559
+ if (pushRecord.pop()) scopeStack.pop();
521
560
  },
522
561
 
523
562
  enterNode(node: TreeSitterNode, _context: VisitorContext): EnterNodeResult | undefined {
@@ -148,6 +148,181 @@ function buildInitTemplate(): string {
148
148
  return `${JSON.stringify(template, null, 2)}\n`;
149
149
  }
150
150
 
151
+ // ─── Subcommand handlers ───────────────────────────────────────────────
152
+
153
+ function handleInit(): void {
154
+ const targetPath = getDefaultUserConfigPath();
155
+ if (fs.existsSync(targetPath)) {
156
+ process.stderr.write(
157
+ `Global config already exists at ${targetPath}\n` +
158
+ `Run \`codegraph config --edit\` to open it, or delete it and re-run --init.\n`,
159
+ );
160
+ process.exit(1);
161
+ }
162
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
163
+ fs.writeFileSync(targetPath, buildInitTemplate(), 'utf-8');
164
+ process.stdout.write(`Created global config at ${targetPath}\n`);
165
+ process.stdout.write(
166
+ `Next steps:\n` +
167
+ ` 1. Edit the file: codegraph config --edit\n` +
168
+ ` 2. Enable it for this repo: codegraph config --enable-global\n`,
169
+ );
170
+ }
171
+
172
+ function handleEdit(): void {
173
+ // Prefer the existing file; fall back to the default path so the user
174
+ // can create-and-edit in one step even before running --init.
175
+ const filePath = resolveUserConfigPath() ?? getDefaultUserConfigPath();
176
+
177
+ const editor = process.env.EDITOR || process.env.VISUAL;
178
+ if (!editor) {
179
+ process.stdout.write(`${filePath}\n`);
180
+ process.stderr.write(
181
+ `$EDITOR is not set. Set it in your shell profile (e.g. export EDITOR=nano)\n` +
182
+ `or open the file manually at the path printed above.\n`,
183
+ );
184
+ return;
185
+ }
186
+
187
+ // Ensure the directory exists so the editor can create the file
188
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
189
+
190
+ const result = spawnSync(editor, [filePath], { stdio: 'inherit' });
191
+ if (result.error) {
192
+ process.stderr.write(`Failed to launch editor "${editor}": ${result.error.message}\n`);
193
+ process.exit(1);
194
+ }
195
+ if (result.status !== 0) {
196
+ process.exit(result.status ?? 1);
197
+ }
198
+ }
199
+
200
+ function handleEnableGlobal(rootDir: string): void {
201
+ setUserConfigConsent(rootDir, 'enabled');
202
+ clearConfigCache();
203
+ const globalPath = resolveUserConfigPath();
204
+ if (!globalPath) {
205
+ process.stderr.write(
206
+ `Consent recorded: "enabled" for ${rootDir}\n` +
207
+ `Note: no global config file found. Create one at ~/.config/codegraph/config.json\n`,
208
+ );
209
+ } else {
210
+ process.stderr.write(
211
+ `Consent recorded: "enabled" for ${rootDir}\n` + `Global config: ${globalPath}\n`,
212
+ );
213
+ }
214
+ }
215
+
216
+ function handleDisableGlobal(rootDir: string): void {
217
+ setUserConfigConsent(rootDir, 'disabled');
218
+ clearConfigCache();
219
+ process.stderr.write(`Consent recorded: "disabled" for ${rootDir}\n`);
220
+ }
221
+
222
+ function handleListGlobal(json: boolean): void {
223
+ const entries = listUserConfigConsent(REGISTRY_PATH);
224
+ if (json) {
225
+ process.stdout.write(`${JSON.stringify(entries, null, 2)}\n`);
226
+ return;
227
+ }
228
+ if (entries.length === 0) {
229
+ process.stdout.write('No repos have a recorded global-config consent decision.\n');
230
+ return;
231
+ }
232
+ process.stdout.write('Global config consent decisions:\n\n');
233
+ for (const { path: p, decision } of entries) {
234
+ process.stdout.write(` ${decision === 'enabled' ? '✔' : '✘'} ${decision.padEnd(8)} ${p}\n`);
235
+ }
236
+ }
237
+
238
+ function handleExplain(
239
+ rootDir: string,
240
+ json: boolean,
241
+ userConfigOverride: string | undefined,
242
+ ): void {
243
+ const { config, provenance, appliedGlobalPath, consentDecision } = loadConfigWithProvenance(
244
+ rootDir,
245
+ { userConfig: userConfigOverride },
246
+ );
247
+ const globalPath = resolveUserConfigPath();
248
+ const consent = getUserConfigConsent(rootDir);
249
+
250
+ if (json) {
251
+ process.stdout.write(
252
+ `${JSON.stringify(
253
+ {
254
+ config,
255
+ provenance,
256
+ appliedGlobalPath,
257
+ globalFilePath: globalPath,
258
+ consentDecision: consentDecision ?? consent ?? 'undecided',
259
+ },
260
+ null,
261
+ 2,
262
+ )}\n`,
263
+ );
264
+ return;
265
+ }
266
+
267
+ // Human-readable explain output
268
+ process.stdout.write('=== Codegraph config provenance ===\n\n');
269
+
270
+ const consentStr = consentDecision ?? consent ?? 'undecided';
271
+ process.stdout.write(`Global config file : ${globalPath ?? '(none found)'}\n`);
272
+ process.stdout.write(`Applied this run : ${appliedGlobalPath ? 'yes' : 'no'}\n`);
273
+ process.stdout.write(`Consent for repo : ${consentStr}\n`);
274
+ process.stdout.write(
275
+ ` (change with \`codegraph config --enable-global\` or \`--disable-global\`)\n`,
276
+ );
277
+
278
+ if (!globalPath) {
279
+ process.stdout.write(
280
+ `\nDiscovery hint: create a global config at ~/.config/codegraph/config.json\n` +
281
+ `then run \`codegraph config --enable-global\` in repos where you want it applied.\n`,
282
+ );
283
+ } else if (!appliedGlobalPath) {
284
+ process.stdout.write(
285
+ `\nDiscovery hint: global config exists but is not applied to this repo.\n` +
286
+ `Run \`codegraph config --enable-global\` to enable it here.\n`,
287
+ );
288
+ }
289
+
290
+ process.stdout.write('\n--- Per-key provenance ---\n\n');
291
+ const provenanceEntries = Object.entries(provenance).sort(([a], [b]) => a.localeCompare(b));
292
+ for (const [key, source] of provenanceEntries) {
293
+ process.stdout.write(` ${source.padEnd(8)} ${key}\n`);
294
+ }
295
+ }
296
+
297
+ function handleShowConfig(
298
+ rootDir: string,
299
+ json: boolean,
300
+ userConfigOverride: string | undefined,
301
+ ): void {
302
+ const globalPath = resolveUserConfigPath();
303
+ const consent = getUserConfigConsent(rootDir);
304
+
305
+ if (json) {
306
+ const config = loadConfig(rootDir, { userConfig: userConfigOverride });
307
+ process.stdout.write(`${JSON.stringify(config, null, 2)}\n`);
308
+ return;
309
+ }
310
+
311
+ // Human-readable table: Key | Value | Source
312
+ const { config, provenance } = loadConfigWithProvenance(rootDir, {
313
+ userConfig: userConfigOverride,
314
+ });
315
+ process.stdout.write(renderConfigTable(config as unknown as Record<string, unknown>, provenance));
316
+
317
+ if (globalPath && !consent) {
318
+ process.stderr.write(
319
+ `\nℹ Global config found at ${globalPath} — not applied to this repo.\n` +
320
+ ` Run \`codegraph config --enable-global\` to opt in, or\n` +
321
+ ` \`codegraph config --disable-global\` to dismiss this notice.\n`,
322
+ );
323
+ }
324
+ }
325
+
151
326
  export const command: CommandDefinition = {
152
327
  name: 'config',
153
328
  description: 'Show or manage codegraph configuration (project + user-level global config)',
@@ -165,189 +340,14 @@ export const command: CommandDefinition = {
165
340
  ],
166
341
  execute(_args, opts, ctx) {
167
342
  const rootDir = path.resolve('.');
168
-
169
- // ── Init: scaffold global config ───────────────────────────────────
170
-
171
- if (opts.init) {
172
- const targetPath = getDefaultUserConfigPath();
173
- if (fs.existsSync(targetPath)) {
174
- process.stderr.write(
175
- `Global config already exists at ${targetPath}\n` +
176
- `Run \`codegraph config --edit\` to open it, or delete it and re-run --init.\n`,
177
- );
178
- process.exit(1);
179
- }
180
- fs.mkdirSync(path.dirname(targetPath), { recursive: true });
181
- fs.writeFileSync(targetPath, buildInitTemplate(), 'utf-8');
182
- process.stdout.write(`Created global config at ${targetPath}\n`);
183
- process.stdout.write(
184
- `Next steps:\n` +
185
- ` 1. Edit the file: codegraph config --edit\n` +
186
- ` 2. Enable it for this repo: codegraph config --enable-global\n`,
187
- );
188
- return;
189
- }
190
-
191
- // ── Edit: open global config in $EDITOR ────────────────────────────
192
-
193
- if (opts.edit) {
194
- // Prefer the existing file; fall back to the default path so the user
195
- // can create-and-edit in one step even before running --init.
196
- const filePath = resolveUserConfigPath() ?? getDefaultUserConfigPath();
197
-
198
- const editor = process.env.EDITOR || process.env.VISUAL;
199
- if (!editor) {
200
- process.stdout.write(`${filePath}\n`);
201
- process.stderr.write(
202
- `$EDITOR is not set. Set it in your shell profile (e.g. export EDITOR=nano)\n` +
203
- `or open the file manually at the path printed above.\n`,
204
- );
205
- return;
206
- }
207
-
208
- // Ensure the directory exists so the editor can create the file
209
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
210
-
211
- const result = spawnSync(editor, [filePath], { stdio: 'inherit' });
212
- if (result.error) {
213
- process.stderr.write(`Failed to launch editor "${editor}": ${result.error.message}\n`);
214
- process.exit(1);
215
- }
216
- if (result.status !== 0) {
217
- process.exit(result.status ?? 1);
218
- }
219
- return;
220
- }
221
-
222
- // ── Consent management ─────────────────────────────────────────────
223
-
224
- if (opts.enableGlobal) {
225
- setUserConfigConsent(rootDir, 'enabled');
226
- clearConfigCache();
227
- const globalPath = resolveUserConfigPath();
228
- if (!globalPath) {
229
- process.stderr.write(
230
- `Consent recorded: "enabled" for ${rootDir}\n` +
231
- `Note: no global config file found. Create one at ~/.config/codegraph/config.json\n`,
232
- );
233
- } else {
234
- process.stderr.write(
235
- `Consent recorded: "enabled" for ${rootDir}\n` + `Global config: ${globalPath}\n`,
236
- );
237
- }
238
- return;
239
- }
240
-
241
- if (opts.disableGlobal) {
242
- setUserConfigConsent(rootDir, 'disabled');
243
- clearConfigCache();
244
- process.stderr.write(`Consent recorded: "disabled" for ${rootDir}\n`);
245
- return;
246
- }
247
-
248
- if (opts.listGlobal) {
249
- const entries = listUserConfigConsent(REGISTRY_PATH);
250
- if (opts.json) {
251
- process.stdout.write(`${JSON.stringify(entries, null, 2)}\n`);
252
- return;
253
- }
254
- if (entries.length === 0) {
255
- process.stdout.write('No repos have a recorded global-config consent decision.\n');
256
- return;
257
- }
258
- process.stdout.write('Global config consent decisions:\n\n');
259
- for (const { path: p, decision } of entries) {
260
- process.stdout.write(
261
- ` ${decision === 'enabled' ? '✔' : '✘'} ${decision.padEnd(8)} ${p}\n`,
262
- );
263
- }
264
- return;
265
- }
266
-
267
- // ── Explain mode ───────────────────────────────────────────────────
268
-
269
- if (opts.explain) {
270
- const { config, provenance, appliedGlobalPath, consentDecision } = loadConfigWithProvenance(
271
- rootDir,
272
- {
273
- userConfig: ctx.program.opts().userConfig,
274
- },
275
- );
276
- const globalPath = resolveUserConfigPath();
277
- const consent = getUserConfigConsent(rootDir);
278
-
279
- if (opts.json) {
280
- process.stdout.write(
281
- `${JSON.stringify(
282
- {
283
- config,
284
- provenance,
285
- appliedGlobalPath,
286
- globalFilePath: globalPath,
287
- consentDecision: consentDecision ?? consent ?? 'undecided',
288
- },
289
- null,
290
- 2,
291
- )}\n`,
292
- );
293
- return;
294
- }
295
-
296
- // Human-readable explain output
297
- process.stdout.write('=== Codegraph config provenance ===\n\n');
298
-
299
- const consentStr = consentDecision ?? consent ?? 'undecided';
300
- process.stdout.write(`Global config file : ${globalPath ?? '(none found)'}\n`);
301
- process.stdout.write(`Applied this run : ${appliedGlobalPath ? 'yes' : 'no'}\n`);
302
- process.stdout.write(`Consent for repo : ${consentStr}\n`);
303
- process.stdout.write(
304
- ` (change with \`codegraph config --enable-global\` or \`--disable-global\`)\n`,
305
- );
306
-
307
- if (!globalPath) {
308
- process.stdout.write(
309
- `\nDiscovery hint: create a global config at ~/.config/codegraph/config.json\n` +
310
- `then run \`codegraph config --enable-global\` in repos where you want it applied.\n`,
311
- );
312
- } else if (!appliedGlobalPath) {
313
- process.stdout.write(
314
- `\nDiscovery hint: global config exists but is not applied to this repo.\n` +
315
- `Run \`codegraph config --enable-global\` to enable it here.\n`,
316
- );
317
- }
318
-
319
- process.stdout.write('\n--- Per-key provenance ---\n\n');
320
- const provenanceEntries = Object.entries(provenance).sort(([a], [b]) => a.localeCompare(b));
321
- for (const [key, source] of provenanceEntries) {
322
- process.stdout.write(` ${source.padEnd(8)} ${key}\n`);
323
- }
324
- return;
325
- }
326
-
327
- // ── Default: print effective config ────────────────────────────────
328
-
329
- const globalPath = resolveUserConfigPath();
330
- const consent = getUserConfigConsent(rootDir);
331
-
332
- if (opts.json) {
333
- const config = loadConfig(rootDir, { userConfig: ctx.program.opts().userConfig });
334
- process.stdout.write(`${JSON.stringify(config, null, 2)}\n`);
335
- } else {
336
- // Human-readable table: Key | Value | Source
337
- const { config, provenance } = loadConfigWithProvenance(rootDir, {
338
- userConfig: ctx.program.opts().userConfig,
339
- });
340
- process.stdout.write(
341
- renderConfigTable(config as unknown as Record<string, unknown>, provenance),
342
- );
343
-
344
- if (globalPath && !consent) {
345
- process.stderr.write(
346
- `\nℹ Global config found at ${globalPath} — not applied to this repo.\n` +
347
- ` Run \`codegraph config --enable-global\` to opt in, or\n` +
348
- ` \`codegraph config --disable-global\` to dismiss this notice.\n`,
349
- );
350
- }
351
- }
343
+ const userConfigOverride = ctx.program.opts().userConfig as string | undefined;
344
+
345
+ if (opts.init) return handleInit();
346
+ if (opts.edit) return handleEdit();
347
+ if (opts.enableGlobal) return handleEnableGlobal(rootDir);
348
+ if (opts.disableGlobal) return handleDisableGlobal(rootDir);
349
+ if (opts.listGlobal) return handleListGlobal(opts.json);
350
+ if (opts.explain) return handleExplain(rootDir, opts.json, userConfigOverride);
351
+ return handleShowConfig(rootDir, opts.json, userConfigOverride);
352
352
  },
353
353
  };
@@ -1,6 +1,6 @@
1
1
  import { collectFile } from '../../db/query-builder.js';
2
2
  import { VALID_ROLES } from '../../domain/queries.js';
3
- import { roles } from '../../presentation/queries-cli.js';
3
+ import { dynamicCalls, roles } from '../../presentation/queries-cli.js';
4
4
  import type { CommandDefinition } from '../types.js';
5
5
 
6
6
  export const command: CommandDefinition = {
@@ -17,6 +17,7 @@ export const command: CommandDefinition = {
17
17
  ['-n, --limit <number>', 'Max results to return'],
18
18
  ['--offset <number>', 'Skip N results (default: 0)'],
19
19
  ['--ndjson', 'Newline-delimited JSON output'],
20
+ ['--dynamic', 'Show flagged dynamic call sites instead of symbol roles'],
20
21
  ],
21
22
  validate(_args, opts) {
22
23
  if (opts.role && !(VALID_ROLES as readonly string[]).includes(opts.role)) {
@@ -24,6 +25,10 @@ export const command: CommandDefinition = {
24
25
  }
25
26
  },
26
27
  execute(_args, opts, ctx) {
28
+ if (opts.dynamic) {
29
+ dynamicCalls(opts.db, ctx.resolveQueryOpts(opts));
30
+ return;
31
+ }
27
32
  roles(opts.db, {
28
33
  role: opts.role,
29
34
  file: opts.file,
@@ -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,