@optave/codegraph 3.4.0 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (453) hide show
  1. package/README.md +23 -22
  2. package/dist/ast-analysis/engine.d.ts.map +1 -1
  3. package/dist/ast-analysis/engine.js +3 -9
  4. package/dist/ast-analysis/engine.js.map +1 -1
  5. package/dist/ast-analysis/rules/javascript.d.ts.map +1 -1
  6. package/dist/ast-analysis/rules/javascript.js +1 -0
  7. package/dist/ast-analysis/rules/javascript.js.map +1 -1
  8. package/dist/ast-analysis/shared.d.ts.map +1 -1
  9. package/dist/ast-analysis/shared.js +0 -1
  10. package/dist/ast-analysis/shared.js.map +1 -1
  11. package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
  12. package/dist/ast-analysis/visitors/ast-store-visitor.js +103 -35
  13. package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
  14. package/dist/ast-analysis/visitors/cfg-conditionals.d.ts +5 -0
  15. package/dist/ast-analysis/visitors/cfg-conditionals.d.ts.map +1 -0
  16. package/dist/ast-analysis/visitors/cfg-conditionals.js +166 -0
  17. package/dist/ast-analysis/visitors/cfg-conditionals.js.map +1 -0
  18. package/dist/ast-analysis/visitors/cfg-loops.d.ts +7 -0
  19. package/dist/ast-analysis/visitors/cfg-loops.d.ts.map +1 -0
  20. package/dist/ast-analysis/visitors/cfg-loops.js +73 -0
  21. package/dist/ast-analysis/visitors/cfg-loops.js.map +1 -0
  22. package/dist/ast-analysis/visitors/cfg-shared.d.ts +56 -0
  23. package/dist/ast-analysis/visitors/cfg-shared.d.ts.map +1 -0
  24. package/dist/ast-analysis/visitors/cfg-shared.js +107 -0
  25. package/dist/ast-analysis/visitors/cfg-shared.js.map +1 -0
  26. package/dist/ast-analysis/visitors/cfg-try-catch.d.ts +4 -0
  27. package/dist/ast-analysis/visitors/cfg-try-catch.d.ts.map +1 -0
  28. package/dist/ast-analysis/visitors/cfg-try-catch.js +100 -0
  29. package/dist/ast-analysis/visitors/cfg-try-catch.js.map +1 -0
  30. package/dist/ast-analysis/visitors/cfg-visitor.d.ts +2 -2
  31. package/dist/ast-analysis/visitors/cfg-visitor.d.ts.map +1 -1
  32. package/dist/ast-analysis/visitors/cfg-visitor.js +11 -445
  33. package/dist/ast-analysis/visitors/cfg-visitor.js.map +1 -1
  34. package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
  35. package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
  36. package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
  37. package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
  38. package/dist/cli/commands/batch.d.ts.map +1 -1
  39. package/dist/cli/commands/batch.js +4 -3
  40. package/dist/cli/commands/batch.js.map +1 -1
  41. package/dist/cli/commands/branch-compare.js +1 -1
  42. package/dist/cli/commands/branch-compare.js.map +1 -1
  43. package/dist/cli/commands/build.js +1 -1
  44. package/dist/cli/commands/build.js.map +1 -1
  45. package/dist/cli/commands/info.d.ts.map +1 -1
  46. package/dist/cli/commands/info.js +1 -2
  47. package/dist/cli/commands/info.js.map +1 -1
  48. package/dist/cli/commands/path.d.ts.map +1 -1
  49. package/dist/cli/commands/path.js +7 -2
  50. package/dist/cli/commands/path.js.map +1 -1
  51. package/dist/cli/commands/plot.d.ts.map +1 -1
  52. package/dist/cli/commands/plot.js +2 -2
  53. package/dist/cli/commands/plot.js.map +1 -1
  54. package/dist/cli/commands/watch.js +1 -1
  55. package/dist/cli/commands/watch.js.map +1 -1
  56. package/dist/cli/index.js +2 -2
  57. package/dist/cli/index.js.map +1 -1
  58. package/dist/cli/shared/open-graph.d.ts +2 -2
  59. package/dist/cli/shared/open-graph.d.ts.map +1 -1
  60. package/dist/cli/shared/open-graph.js.map +1 -1
  61. package/dist/cli/types.d.ts +1 -1
  62. package/dist/cli/types.d.ts.map +1 -1
  63. package/dist/cli.js +2 -3
  64. package/dist/cli.js.map +1 -1
  65. package/dist/db/better-sqlite3.d.ts +3 -0
  66. package/dist/db/better-sqlite3.d.ts.map +1 -0
  67. package/dist/db/better-sqlite3.js +19 -0
  68. package/dist/db/better-sqlite3.js.map +1 -0
  69. package/dist/db/connection.d.ts +30 -2
  70. package/dist/db/connection.d.ts.map +1 -1
  71. package/dist/db/connection.js +167 -4
  72. package/dist/db/connection.js.map +1 -1
  73. package/dist/db/index.d.ts +2 -2
  74. package/dist/db/index.d.ts.map +1 -1
  75. package/dist/db/index.js +1 -1
  76. package/dist/db/index.js.map +1 -1
  77. package/dist/db/migrations.d.ts.map +1 -1
  78. package/dist/db/migrations.js +9 -0
  79. package/dist/db/migrations.js.map +1 -1
  80. package/dist/db/query-builder.d.ts +5 -5
  81. package/dist/db/query-builder.d.ts.map +1 -1
  82. package/dist/db/query-builder.js +20 -4
  83. package/dist/db/query-builder.js.map +1 -1
  84. package/dist/db/repository/index.d.ts +1 -0
  85. package/dist/db/repository/index.d.ts.map +1 -1
  86. package/dist/db/repository/index.js +1 -0
  87. package/dist/db/repository/index.js.map +1 -1
  88. package/dist/db/repository/native-repository.d.ts +58 -0
  89. package/dist/db/repository/native-repository.d.ts.map +1 -0
  90. package/dist/db/repository/native-repository.js +261 -0
  91. package/dist/db/repository/native-repository.js.map +1 -0
  92. package/dist/db/repository/nodes.d.ts +4 -4
  93. package/dist/db/repository/nodes.d.ts.map +1 -1
  94. package/dist/db/repository/nodes.js +6 -6
  95. package/dist/db/repository/nodes.js.map +1 -1
  96. package/dist/domain/analysis/brief.d.ts.map +1 -1
  97. package/dist/domain/analysis/brief.js +1 -3
  98. package/dist/domain/analysis/brief.js.map +1 -1
  99. package/dist/domain/analysis/context.d.ts.map +1 -1
  100. package/dist/domain/analysis/context.js +2 -4
  101. package/dist/domain/analysis/context.js.map +1 -1
  102. package/dist/domain/analysis/dependencies.d.ts +49 -0
  103. package/dist/domain/analysis/dependencies.d.ts.map +1 -1
  104. package/dist/domain/analysis/dependencies.js +145 -0
  105. package/dist/domain/analysis/dependencies.js.map +1 -1
  106. package/dist/domain/analysis/diff-impact.d.ts +76 -0
  107. package/dist/domain/analysis/diff-impact.d.ts.map +1 -0
  108. package/dist/domain/analysis/diff-impact.js +282 -0
  109. package/dist/domain/analysis/diff-impact.js.map +1 -0
  110. package/dist/domain/analysis/exports.d.ts.map +1 -1
  111. package/dist/domain/analysis/exports.js +0 -1
  112. package/dist/domain/analysis/exports.js.map +1 -1
  113. package/dist/domain/analysis/fn-impact.d.ts +66 -0
  114. package/dist/domain/analysis/fn-impact.d.ts.map +1 -0
  115. package/dist/domain/analysis/fn-impact.js +189 -0
  116. package/dist/domain/analysis/fn-impact.js.map +1 -0
  117. package/dist/domain/analysis/impact.d.ts +8 -148
  118. package/dist/domain/analysis/impact.d.ts.map +1 -1
  119. package/dist/domain/analysis/impact.js +8 -568
  120. package/dist/domain/analysis/impact.js.map +1 -1
  121. package/dist/domain/analysis/module-map.d.ts.map +1 -1
  122. package/dist/domain/analysis/module-map.js +1 -3
  123. package/dist/domain/analysis/module-map.js.map +1 -1
  124. package/dist/domain/graph/builder/context.d.ts +3 -3
  125. package/dist/domain/graph/builder/context.d.ts.map +1 -1
  126. package/dist/domain/graph/builder/context.js +1 -0
  127. package/dist/domain/graph/builder/context.js.map +1 -1
  128. package/dist/domain/graph/builder/helpers.d.ts +4 -5
  129. package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
  130. package/dist/domain/graph/builder/helpers.js +1 -2
  131. package/dist/domain/graph/builder/helpers.js.map +1 -1
  132. package/dist/domain/graph/builder/incremental.d.ts +2 -3
  133. package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
  134. package/dist/domain/graph/builder/incremental.js.map +1 -1
  135. package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
  136. package/dist/domain/graph/builder/pipeline.js +34 -6
  137. package/dist/domain/graph/builder/pipeline.js.map +1 -1
  138. package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
  139. package/dist/domain/graph/builder/stages/build-edges.js +113 -15
  140. package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
  141. package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
  142. package/dist/domain/graph/builder/stages/build-structure.js +186 -62
  143. package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
  144. package/dist/domain/graph/builder/stages/collect-files.d.ts.map +1 -1
  145. package/dist/domain/graph/builder/stages/collect-files.js +71 -7
  146. package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
  147. package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
  148. package/dist/domain/graph/builder/stages/detect-changes.js +42 -20
  149. package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
  150. package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
  151. package/dist/domain/graph/builder/stages/finalize.js +111 -64
  152. package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
  153. package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
  154. package/dist/domain/graph/builder/stages/insert-nodes.js +104 -9
  155. package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
  156. package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
  157. package/dist/domain/graph/builder/stages/resolve-imports.js +58 -11
  158. package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
  159. package/dist/domain/graph/cycles.js +2 -2
  160. package/dist/domain/graph/cycles.js.map +1 -1
  161. package/dist/domain/graph/resolve.d.ts.map +1 -1
  162. package/dist/domain/graph/resolve.js +10 -8
  163. package/dist/domain/graph/resolve.js.map +1 -1
  164. package/dist/domain/graph/watcher.d.ts.map +1 -1
  165. package/dist/domain/graph/watcher.js +1 -3
  166. package/dist/domain/graph/watcher.js.map +1 -1
  167. package/dist/domain/parser.d.ts.map +1 -1
  168. package/dist/domain/parser.js +12 -12
  169. package/dist/domain/parser.js.map +1 -1
  170. package/dist/domain/queries.d.ts +3 -2
  171. package/dist/domain/queries.d.ts.map +1 -1
  172. package/dist/domain/queries.js +3 -2
  173. package/dist/domain/queries.js.map +1 -1
  174. package/dist/domain/search/generator.d.ts.map +1 -1
  175. package/dist/domain/search/generator.js.map +1 -1
  176. package/dist/extractors/csharp.js +2 -2
  177. package/dist/extractors/csharp.js.map +1 -1
  178. package/dist/extractors/go.js +2 -2
  179. package/dist/extractors/go.js.map +1 -1
  180. package/dist/extractors/helpers.d.ts +5 -0
  181. package/dist/extractors/helpers.d.ts.map +1 -1
  182. package/dist/extractors/helpers.js +5 -0
  183. package/dist/extractors/helpers.js.map +1 -1
  184. package/dist/extractors/javascript.js +111 -98
  185. package/dist/extractors/javascript.js.map +1 -1
  186. package/dist/extractors/php.js +2 -2
  187. package/dist/extractors/php.js.map +1 -1
  188. package/dist/extractors/python.js +2 -2
  189. package/dist/extractors/python.js.map +1 -1
  190. package/dist/extractors/rust.js +4 -3
  191. package/dist/extractors/rust.js.map +1 -1
  192. package/dist/features/ast.d.ts +14 -1
  193. package/dist/features/ast.d.ts.map +1 -1
  194. package/dist/features/ast.js +38 -1
  195. package/dist/features/ast.js.map +1 -1
  196. package/dist/features/audit.d.ts.map +1 -1
  197. package/dist/features/audit.js +1 -2
  198. package/dist/features/audit.js.map +1 -1
  199. package/dist/features/branch-compare.d.ts.map +1 -1
  200. package/dist/features/branch-compare.js +5 -4
  201. package/dist/features/branch-compare.js.map +1 -1
  202. package/dist/features/cfg.d.ts.map +1 -1
  203. package/dist/features/cfg.js +2 -4
  204. package/dist/features/cfg.js.map +1 -1
  205. package/dist/features/cochange.js +4 -4
  206. package/dist/features/cochange.js.map +1 -1
  207. package/dist/features/communities.js +4 -4
  208. package/dist/features/communities.js.map +1 -1
  209. package/dist/features/complexity-query.d.ts +37 -0
  210. package/dist/features/complexity-query.d.ts.map +1 -0
  211. package/dist/features/complexity-query.js +263 -0
  212. package/dist/features/complexity-query.js.map +1 -0
  213. package/dist/features/complexity.d.ts +2 -30
  214. package/dist/features/complexity.d.ts.map +1 -1
  215. package/dist/features/complexity.js +7 -261
  216. package/dist/features/complexity.js.map +1 -1
  217. package/dist/features/dataflow.d.ts.map +1 -1
  218. package/dist/features/dataflow.js +8 -24
  219. package/dist/features/dataflow.js.map +1 -1
  220. package/dist/features/export.d.ts +7 -8
  221. package/dist/features/export.d.ts.map +1 -1
  222. package/dist/features/export.js.map +1 -1
  223. package/dist/features/flow.d.ts.map +1 -1
  224. package/dist/features/flow.js.map +1 -1
  225. package/dist/features/graph-enrichment.d.ts.map +1 -1
  226. package/dist/features/graph-enrichment.js +1 -3
  227. package/dist/features/graph-enrichment.js.map +1 -1
  228. package/dist/features/manifesto.js +8 -8
  229. package/dist/features/manifesto.js.map +1 -1
  230. package/dist/features/snapshot.js +2 -2
  231. package/dist/features/snapshot.js.map +1 -1
  232. package/dist/features/structure-query.d.ts +76 -0
  233. package/dist/features/structure-query.d.ts.map +1 -0
  234. package/dist/features/structure-query.js +245 -0
  235. package/dist/features/structure-query.js.map +1 -0
  236. package/dist/features/structure.d.ts +12 -67
  237. package/dist/features/structure.d.ts.map +1 -1
  238. package/dist/features/structure.js +188 -244
  239. package/dist/features/structure.js.map +1 -1
  240. package/dist/features/triage.js +2 -2
  241. package/dist/features/triage.js.map +1 -1
  242. package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
  243. package/dist/graph/algorithms/leiden/adapter.js +2 -9
  244. package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
  245. package/dist/graph/classifiers/roles.d.ts +5 -1
  246. package/dist/graph/classifiers/roles.d.ts.map +1 -1
  247. package/dist/graph/classifiers/roles.js +20 -12
  248. package/dist/graph/classifiers/roles.js.map +1 -1
  249. package/dist/index.d.ts +1 -0
  250. package/dist/index.d.ts.map +1 -1
  251. package/dist/index.js.map +1 -1
  252. package/dist/infrastructure/config.d.ts.map +1 -1
  253. package/dist/infrastructure/config.js +12 -11
  254. package/dist/infrastructure/config.js.map +1 -1
  255. package/dist/infrastructure/native.d.ts.map +1 -1
  256. package/dist/infrastructure/native.js +7 -3
  257. package/dist/infrastructure/native.js.map +1 -1
  258. package/dist/infrastructure/registry.d.ts.map +1 -1
  259. package/dist/infrastructure/registry.js +1 -1
  260. package/dist/infrastructure/registry.js.map +1 -1
  261. package/dist/infrastructure/update-check.js +3 -3
  262. package/dist/infrastructure/update-check.js.map +1 -1
  263. package/dist/mcp/server.d.ts.map +1 -1
  264. package/dist/mcp/server.js +4 -17
  265. package/dist/mcp/server.js.map +1 -1
  266. package/dist/mcp/tool-registry.d.ts.map +1 -1
  267. package/dist/mcp/tool-registry.js +9 -4
  268. package/dist/mcp/tool-registry.js.map +1 -1
  269. package/dist/mcp/tools/audit.js +1 -1
  270. package/dist/mcp/tools/audit.js.map +1 -1
  271. package/dist/mcp/tools/cfg.js +1 -1
  272. package/dist/mcp/tools/cfg.js.map +1 -1
  273. package/dist/mcp/tools/check.js +2 -2
  274. package/dist/mcp/tools/check.js.map +1 -1
  275. package/dist/mcp/tools/dataflow.js +2 -2
  276. package/dist/mcp/tools/dataflow.js.map +1 -1
  277. package/dist/mcp/tools/export-graph.js +1 -1
  278. package/dist/mcp/tools/export-graph.js.map +1 -1
  279. package/dist/mcp/tools/index.d.ts.map +1 -1
  280. package/dist/mcp/tools/index.js.map +1 -1
  281. package/dist/mcp/tools/path.d.ts +1 -0
  282. package/dist/mcp/tools/path.d.ts.map +1 -1
  283. package/dist/mcp/tools/path.js +9 -0
  284. package/dist/mcp/tools/path.js.map +1 -1
  285. package/dist/mcp/tools/query.js +1 -1
  286. package/dist/mcp/tools/query.js.map +1 -1
  287. package/dist/mcp/tools/semantic-search.js +1 -1
  288. package/dist/mcp/tools/semantic-search.js.map +1 -1
  289. package/dist/mcp/tools/sequence.js +1 -1
  290. package/dist/mcp/tools/sequence.js.map +1 -1
  291. package/dist/mcp/tools/symbol-children.js +1 -1
  292. package/dist/mcp/tools/symbol-children.js.map +1 -1
  293. package/dist/mcp/tools/triage.js +1 -1
  294. package/dist/mcp/tools/triage.js.map +1 -1
  295. package/dist/presentation/audit.d.ts.map +1 -1
  296. package/dist/presentation/audit.js +0 -1
  297. package/dist/presentation/audit.js.map +1 -1
  298. package/dist/presentation/diff-impact-mermaid.d.ts +11 -0
  299. package/dist/presentation/diff-impact-mermaid.d.ts.map +1 -0
  300. package/dist/presentation/diff-impact-mermaid.js +105 -0
  301. package/dist/presentation/diff-impact-mermaid.js.map +1 -0
  302. package/dist/presentation/flow.d.ts.map +1 -1
  303. package/dist/presentation/flow.js +0 -2
  304. package/dist/presentation/flow.js.map +1 -1
  305. package/dist/presentation/manifesto.d.ts.map +1 -1
  306. package/dist/presentation/manifesto.js +0 -1
  307. package/dist/presentation/manifesto.js.map +1 -1
  308. package/dist/presentation/queries-cli/inspect.d.ts.map +1 -1
  309. package/dist/presentation/queries-cli/inspect.js.map +1 -1
  310. package/dist/presentation/queries-cli/path.d.ts.map +1 -1
  311. package/dist/presentation/queries-cli/path.js +45 -1
  312. package/dist/presentation/queries-cli/path.js.map +1 -1
  313. package/dist/presentation/result-formatter.d.ts.map +1 -1
  314. package/dist/presentation/result-formatter.js +1 -3
  315. package/dist/presentation/result-formatter.js.map +1 -1
  316. package/dist/presentation/sequence.d.ts.map +1 -1
  317. package/dist/presentation/sequence.js +0 -1
  318. package/dist/presentation/sequence.js.map +1 -1
  319. package/dist/presentation/structure.d.ts.map +1 -1
  320. package/dist/presentation/structure.js.map +1 -1
  321. package/dist/presentation/triage.d.ts.map +1 -1
  322. package/dist/presentation/triage.js +0 -1
  323. package/dist/presentation/triage.js.map +1 -1
  324. package/dist/shared/constants.d.ts +9 -3
  325. package/dist/shared/constants.d.ts.map +1 -1
  326. package/dist/shared/constants.js +6 -3
  327. package/dist/shared/constants.js.map +1 -1
  328. package/dist/shared/errors.d.ts +2 -0
  329. package/dist/shared/errors.d.ts.map +1 -1
  330. package/dist/shared/errors.js +4 -0
  331. package/dist/shared/errors.js.map +1 -1
  332. package/dist/shared/version.d.ts +2 -0
  333. package/dist/shared/version.d.ts.map +1 -0
  334. package/dist/shared/version.js +5 -0
  335. package/dist/shared/version.js.map +1 -0
  336. package/dist/types.d.ts +230 -2
  337. package/dist/types.d.ts.map +1 -1
  338. package/package.json +62 -11
  339. package/src/ast-analysis/engine.ts +3 -9
  340. package/src/ast-analysis/rules/javascript.ts +1 -0
  341. package/src/ast-analysis/shared.ts +0 -1
  342. package/src/ast-analysis/visitors/ast-store-visitor.ts +102 -33
  343. package/src/ast-analysis/visitors/cfg-conditionals.ts +227 -0
  344. package/src/ast-analysis/visitors/cfg-loops.ts +136 -0
  345. package/src/ast-analysis/visitors/cfg-shared.ts +196 -0
  346. package/src/ast-analysis/visitors/cfg-try-catch.ts +142 -0
  347. package/src/ast-analysis/visitors/cfg-visitor.ts +34 -655
  348. package/src/ast-analysis/visitors/complexity-visitor.ts +0 -1
  349. package/src/ast-analysis/visitors/dataflow-visitor.ts +0 -1
  350. package/src/cli/commands/batch.ts +4 -3
  351. package/src/cli/commands/branch-compare.ts +1 -1
  352. package/src/cli/commands/build.ts +1 -1
  353. package/src/cli/commands/info.ts +1 -2
  354. package/src/cli/commands/path.ts +7 -2
  355. package/src/cli/commands/plot.ts +2 -2
  356. package/src/cli/commands/watch.ts +1 -1
  357. package/src/cli/index.ts +2 -2
  358. package/src/cli/shared/open-graph.ts +2 -2
  359. package/src/cli/types.ts +1 -1
  360. package/src/cli.ts +2 -3
  361. package/src/db/better-sqlite3.ts +20 -0
  362. package/src/db/connection.ts +191 -16
  363. package/src/db/index.ts +5 -1
  364. package/src/db/migrations.ts +9 -0
  365. package/src/db/query-builder.ts +30 -5
  366. package/src/db/repository/index.ts +1 -0
  367. package/src/db/repository/native-repository.ts +361 -0
  368. package/src/db/repository/nodes.ts +7 -3
  369. package/src/domain/analysis/brief.ts +0 -1
  370. package/src/domain/analysis/context.ts +2 -6
  371. package/src/domain/analysis/dependencies.ts +165 -0
  372. package/src/domain/analysis/diff-impact.ts +354 -0
  373. package/src/domain/analysis/exports.ts +0 -2
  374. package/src/domain/analysis/fn-impact.ts +241 -0
  375. package/src/domain/analysis/impact.ts +8 -718
  376. package/src/domain/analysis/module-map.ts +1 -5
  377. package/src/domain/graph/builder/context.ts +4 -2
  378. package/src/domain/graph/builder/helpers.ts +14 -11
  379. package/src/domain/graph/builder/incremental.ts +33 -28
  380. package/src/domain/graph/builder/pipeline.ts +37 -5
  381. package/src/domain/graph/builder/stages/build-edges.ts +131 -20
  382. package/src/domain/graph/builder/stages/build-structure.ts +245 -80
  383. package/src/domain/graph/builder/stages/collect-files.ts +84 -7
  384. package/src/domain/graph/builder/stages/detect-changes.ts +49 -32
  385. package/src/domain/graph/builder/stages/finalize.ts +132 -84
  386. package/src/domain/graph/builder/stages/insert-nodes.ts +141 -18
  387. package/src/domain/graph/builder/stages/resolve-imports.ts +75 -10
  388. package/src/domain/graph/cycles.ts +2 -2
  389. package/src/domain/graph/resolve.ts +14 -8
  390. package/src/domain/graph/watcher.ts +2 -4
  391. package/src/domain/parser.ts +12 -13
  392. package/src/domain/queries.ts +2 -2
  393. package/src/domain/search/generator.ts +3 -4
  394. package/src/extractors/csharp.ts +2 -2
  395. package/src/extractors/go.ts +2 -2
  396. package/src/extractors/helpers.ts +6 -0
  397. package/src/extractors/javascript.ts +112 -97
  398. package/src/extractors/php.ts +2 -2
  399. package/src/extractors/python.ts +2 -2
  400. package/src/extractors/rust.ts +4 -3
  401. package/src/features/ast.ts +66 -1
  402. package/src/features/audit.ts +1 -2
  403. package/src/features/branch-compare.ts +6 -10
  404. package/src/features/cfg.ts +2 -4
  405. package/src/features/cochange.ts +4 -4
  406. package/src/features/communities.ts +4 -4
  407. package/src/features/complexity-query.ts +370 -0
  408. package/src/features/complexity.ts +6 -365
  409. package/src/features/dataflow.ts +48 -70
  410. package/src/features/export.ts +12 -16
  411. package/src/features/flow.ts +0 -1
  412. package/src/features/graph-enrichment.ts +1 -3
  413. package/src/features/manifesto.ts +8 -8
  414. package/src/features/snapshot.ts +3 -3
  415. package/src/features/structure-query.ts +387 -0
  416. package/src/features/structure.ts +231 -376
  417. package/src/features/triage.ts +2 -2
  418. package/src/graph/algorithms/leiden/adapter.ts +2 -9
  419. package/src/graph/classifiers/roles.ts +22 -13
  420. package/src/index.ts +1 -0
  421. package/src/infrastructure/config.ts +12 -13
  422. package/src/infrastructure/native.ts +7 -3
  423. package/src/infrastructure/registry.ts +1 -1
  424. package/src/infrastructure/update-check.ts +3 -3
  425. package/src/mcp/server.ts +4 -20
  426. package/src/mcp/tool-registry.ts +11 -4
  427. package/src/mcp/tools/audit.ts +1 -1
  428. package/src/mcp/tools/cfg.ts +1 -1
  429. package/src/mcp/tools/check.ts +2 -2
  430. package/src/mcp/tools/dataflow.ts +2 -2
  431. package/src/mcp/tools/export-graph.ts +1 -1
  432. package/src/mcp/tools/index.ts +0 -1
  433. package/src/mcp/tools/path.ts +10 -0
  434. package/src/mcp/tools/query.ts +1 -1
  435. package/src/mcp/tools/semantic-search.ts +1 -1
  436. package/src/mcp/tools/sequence.ts +1 -1
  437. package/src/mcp/tools/symbol-children.ts +1 -1
  438. package/src/mcp/tools/triage.ts +1 -1
  439. package/src/presentation/audit.ts +0 -1
  440. package/src/presentation/diff-impact-mermaid.ts +127 -0
  441. package/src/presentation/flow.ts +0 -2
  442. package/src/presentation/manifesto.ts +0 -1
  443. package/src/presentation/queries-cli/inspect.ts +0 -1
  444. package/src/presentation/queries-cli/path.ts +71 -1
  445. package/src/presentation/result-formatter.ts +0 -1
  446. package/src/presentation/sequence.ts +0 -1
  447. package/src/presentation/structure.ts +0 -12
  448. package/src/presentation/triage.ts +0 -1
  449. package/src/shared/constants.ts +33 -19
  450. package/src/shared/errors.ts +5 -0
  451. package/src/shared/version.ts +10 -0
  452. package/src/types.ts +277 -10
  453. package/src/vendor.d.ts +0 -39
@@ -0,0 +1,361 @@
1
+ /**
2
+ * NativeRepository — delegates all Repository read methods to NativeDatabase (rusqlite via napi-rs).
3
+ *
4
+ * Phase 6.14: every query runs via rusqlite when the native engine is available.
5
+ * Falls back to SqliteRepository (better-sqlite3) when native is unavailable.
6
+ *
7
+ * napi-rs converts Rust snake_case fields to JS camelCase. This class maps them
8
+ * back to the snake_case field names that the Repository interface expects.
9
+ */
10
+
11
+ import { ConfigError } from '../../shared/errors.js';
12
+ import type {
13
+ AdjacentEdgeRow,
14
+ CallableNodeRow,
15
+ CallEdgeRow,
16
+ ChildNodeRow,
17
+ ComplexityMetrics,
18
+ FileNodeRow,
19
+ ImportEdgeRow,
20
+ ImportGraphEdgeRow,
21
+ IntraFileCallEdge,
22
+ ListFunctionOpts,
23
+ NativeAdjacentEdgeRow,
24
+ NativeCallableNodeRow,
25
+ NativeCallEdgeRow,
26
+ NativeChildNodeRow,
27
+ NativeComplexityMetrics,
28
+ NativeDatabase,
29
+ NativeFileNodeRow,
30
+ NativeImportEdgeRow,
31
+ NativeImportGraphEdgeRow,
32
+ NativeIntraFileCallEdge,
33
+ NativeNodeIdRow,
34
+ NativeNodeRow,
35
+ NativeNodeRowWithFanIn,
36
+ NativeRelatedNodeRow,
37
+ NativeTriageNodeRow,
38
+ NodeIdRow,
39
+ NodeRow,
40
+ NodeRowWithFanIn,
41
+ QueryOpts,
42
+ RelatedNodeRow,
43
+ TriageNodeRow,
44
+ TriageQueryOpts,
45
+ } from '../../types.js';
46
+ import { Repository } from './base.js';
47
+
48
+ // ── Row converters (napi camelCase → Repository snake_case) ─────────────
49
+
50
+ function toNodeRow(r: NativeNodeRow): NodeRow {
51
+ return {
52
+ id: r.id,
53
+ name: r.name,
54
+ kind: r.kind as NodeRow['kind'],
55
+ file: r.file,
56
+ line: r.line ?? 0,
57
+ end_line: r.endLine ?? null,
58
+ parent_id: r.parentId ?? null,
59
+ exported: (r.exported ?? null) as 0 | 1 | null,
60
+ qualified_name: r.qualifiedName ?? null,
61
+ scope: r.scope ?? null,
62
+ visibility: (r.visibility ?? null) as NodeRow['visibility'],
63
+ role: (r.role ?? null) as NodeRow['role'],
64
+ };
65
+ }
66
+
67
+ function toNodeRowWithFanIn(r: NativeNodeRowWithFanIn): NodeRowWithFanIn {
68
+ return { ...toNodeRow(r), fan_in: r.fanIn };
69
+ }
70
+
71
+ function toTriageNodeRow(r: NativeTriageNodeRow): TriageNodeRow {
72
+ return {
73
+ ...toNodeRow(r),
74
+ fan_in: r.fanIn,
75
+ cognitive: r.cognitive,
76
+ mi: r.mi,
77
+ cyclomatic: r.cyclomatic,
78
+ max_nesting: r.maxNesting,
79
+ churn: r.churn,
80
+ };
81
+ }
82
+
83
+ function toNodeIdRow(r: NativeNodeIdRow): NodeIdRow {
84
+ return { id: r.id, name: r.name, kind: r.kind, line: r.line ?? 0 };
85
+ }
86
+
87
+ function toChildNodeRow(r: NativeChildNodeRow): ChildNodeRow {
88
+ return {
89
+ name: r.name,
90
+ kind: r.kind as ChildNodeRow['kind'],
91
+ line: r.line ?? 0,
92
+ end_line: r.endLine ?? null,
93
+ qualified_name: r.qualifiedName ?? null,
94
+ scope: r.scope ?? null,
95
+ visibility: (r.visibility ?? null) as ChildNodeRow['visibility'],
96
+ };
97
+ }
98
+
99
+ function toRelatedNodeRow(r: NativeRelatedNodeRow): RelatedNodeRow {
100
+ return {
101
+ id: r.id,
102
+ name: r.name,
103
+ kind: r.kind,
104
+ file: r.file,
105
+ line: r.line ?? 0,
106
+ end_line: r.endLine,
107
+ };
108
+ }
109
+
110
+ function toAdjacentEdgeRow(r: NativeAdjacentEdgeRow): AdjacentEdgeRow {
111
+ return {
112
+ name: r.name,
113
+ kind: r.kind,
114
+ file: r.file,
115
+ line: r.line ?? 0,
116
+ edge_kind: r.edgeKind as AdjacentEdgeRow['edge_kind'],
117
+ };
118
+ }
119
+
120
+ function toImportEdgeRow(r: NativeImportEdgeRow): ImportEdgeRow {
121
+ return { file: r.file, edge_kind: r.edgeKind as ImportEdgeRow['edge_kind'] };
122
+ }
123
+
124
+ function toIntraFileCallEdge(r: NativeIntraFileCallEdge): IntraFileCallEdge {
125
+ return { caller_name: r.callerName, callee_name: r.calleeName };
126
+ }
127
+
128
+ function toCallableNodeRow(r: NativeCallableNodeRow): CallableNodeRow {
129
+ return { id: r.id, name: r.name, kind: r.kind, file: r.file };
130
+ }
131
+
132
+ function toCallEdgeRow(r: NativeCallEdgeRow): CallEdgeRow {
133
+ return {
134
+ source_id: r.sourceId,
135
+ target_id: r.targetId,
136
+ confidence: r.confidence,
137
+ };
138
+ }
139
+
140
+ function toFileNodeRow(r: NativeFileNodeRow): FileNodeRow {
141
+ return { id: r.id, name: r.name, file: r.file };
142
+ }
143
+
144
+ function toImportGraphEdgeRow(r: NativeImportGraphEdgeRow): ImportGraphEdgeRow {
145
+ return { source_id: r.sourceId, target_id: r.targetId };
146
+ }
147
+
148
+ function toComplexityMetrics(r: NativeComplexityMetrics): ComplexityMetrics {
149
+ return {
150
+ cognitive: r.cognitive,
151
+ cyclomatic: r.cyclomatic,
152
+ max_nesting: r.maxNesting,
153
+ maintainability_index: r.maintainabilityIndex ?? null,
154
+ halstead_volume: r.halsteadVolume ?? null,
155
+ };
156
+ }
157
+
158
+ // ── NativeRepository ────────────────────────────────────────────────────
159
+
160
+ export class NativeRepository extends Repository {
161
+ #ndb: NativeDatabase;
162
+
163
+ constructor(ndb: NativeDatabase) {
164
+ super();
165
+ this.#ndb = ndb;
166
+ }
167
+
168
+ // ── Node lookups ──────────────────────────────────────────────────
169
+
170
+ findNodeById(id: number): NodeRow | undefined {
171
+ const r = this.#ndb.findNodeById(id);
172
+ return r ? toNodeRow(r) : undefined;
173
+ }
174
+
175
+ findNodesByFile(file: string): NodeRow[] {
176
+ return this.#ndb.findNodesByFile(file).map(toNodeRow);
177
+ }
178
+
179
+ findFileNodes(fileLike: string): NodeRow[] {
180
+ return this.#ndb.findFileNodes(fileLike).map(toNodeRow);
181
+ }
182
+
183
+ findNodesWithFanIn(namePattern: string, opts: QueryOpts = {}): NodeRowWithFanIn[] {
184
+ return this.#ndb
185
+ .findNodesWithFanIn(namePattern, opts.kinds ?? null, opts.file ?? null)
186
+ .map(toNodeRowWithFanIn);
187
+ }
188
+
189
+ countNodes(): number {
190
+ return this.#ndb.countNodes();
191
+ }
192
+
193
+ countEdges(): number {
194
+ return this.#ndb.countEdges();
195
+ }
196
+
197
+ countFiles(): number {
198
+ return this.#ndb.countFiles();
199
+ }
200
+
201
+ getNodeId(name: string, kind: string, file: string, line: number): number | undefined {
202
+ return this.#ndb.getNodeId(name, kind, file, line) ?? undefined;
203
+ }
204
+
205
+ getFunctionNodeId(name: string, file: string, line: number): number | undefined {
206
+ return this.#ndb.getFunctionNodeId(name, file, line) ?? undefined;
207
+ }
208
+
209
+ bulkNodeIdsByFile(file: string): NodeIdRow[] {
210
+ return this.#ndb.bulkNodeIdsByFile(file).map(toNodeIdRow);
211
+ }
212
+
213
+ findNodeChildren(parentId: number): ChildNodeRow[] {
214
+ return this.#ndb.findNodeChildren(parentId).map(toChildNodeRow);
215
+ }
216
+
217
+ findNodesByScope(scopeName: string, opts: QueryOpts = {}): NodeRow[] {
218
+ return this.#ndb
219
+ .findNodesByScope(scopeName, opts.kind ?? null, opts.file ?? null)
220
+ .map(toNodeRow);
221
+ }
222
+
223
+ findNodeByQualifiedName(qualifiedName: string, opts: { file?: string } = {}): NodeRow[] {
224
+ return this.#ndb.findNodeByQualifiedName(qualifiedName, opts.file ?? null).map(toNodeRow);
225
+ }
226
+
227
+ listFunctionNodes(opts: ListFunctionOpts = {}): NodeRow[] {
228
+ return this.#ndb
229
+ .listFunctionNodes(opts.file ?? null, opts.pattern ?? null, opts.noTests ?? null)
230
+ .map(toNodeRow);
231
+ }
232
+
233
+ iterateFunctionNodes(opts: ListFunctionOpts = {}): IterableIterator<NodeRow> {
234
+ const rows = this.#ndb
235
+ .iterateFunctionNodes(opts.file ?? null, opts.pattern ?? null, opts.noTests ?? null)
236
+ .map(toNodeRow);
237
+ return rows[Symbol.iterator]();
238
+ }
239
+
240
+ findNodesForTriage(opts: TriageQueryOpts = {}): TriageNodeRow[] {
241
+ try {
242
+ return this.#ndb
243
+ .findNodesForTriage(
244
+ opts.kind ?? null,
245
+ opts.role ?? null,
246
+ opts.file ?? null,
247
+ opts.noTests ?? null,
248
+ )
249
+ .map(toTriageNodeRow);
250
+ } catch (e: unknown) {
251
+ const msg = (e as Error).message;
252
+ if (msg.startsWith('Invalid kind:') || msg.startsWith('Invalid role:')) {
253
+ throw new ConfigError(msg);
254
+ }
255
+ throw e;
256
+ }
257
+ }
258
+
259
+ // ── Edge queries ──────────────────────────────────────────────────
260
+
261
+ findCallees(nodeId: number): RelatedNodeRow[] {
262
+ return this.#ndb.findCallees(nodeId).map(toRelatedNodeRow);
263
+ }
264
+
265
+ findCallers(nodeId: number): RelatedNodeRow[] {
266
+ return this.#ndb.findCallers(nodeId).map(toRelatedNodeRow);
267
+ }
268
+
269
+ findDistinctCallers(nodeId: number): RelatedNodeRow[] {
270
+ return this.#ndb.findDistinctCallers(nodeId).map(toRelatedNodeRow);
271
+ }
272
+
273
+ findAllOutgoingEdges(nodeId: number): AdjacentEdgeRow[] {
274
+ return this.#ndb.findAllOutgoingEdges(nodeId).map(toAdjacentEdgeRow);
275
+ }
276
+
277
+ findAllIncomingEdges(nodeId: number): AdjacentEdgeRow[] {
278
+ return this.#ndb.findAllIncomingEdges(nodeId).map(toAdjacentEdgeRow);
279
+ }
280
+
281
+ findCalleeNames(nodeId: number): string[] {
282
+ return this.#ndb.findCalleeNames(nodeId);
283
+ }
284
+
285
+ findCallerNames(nodeId: number): string[] {
286
+ return this.#ndb.findCallerNames(nodeId);
287
+ }
288
+
289
+ findImportTargets(nodeId: number): ImportEdgeRow[] {
290
+ return this.#ndb.findImportTargets(nodeId).map(toImportEdgeRow);
291
+ }
292
+
293
+ findImportSources(nodeId: number): ImportEdgeRow[] {
294
+ return this.#ndb.findImportSources(nodeId).map(toImportEdgeRow);
295
+ }
296
+
297
+ findImportDependents(nodeId: number): NodeRow[] {
298
+ return this.#ndb.findImportDependents(nodeId).map(toNodeRow);
299
+ }
300
+
301
+ findCrossFileCallTargets(file: string): Set<number> {
302
+ return new Set(this.#ndb.findCrossFileCallTargets(file));
303
+ }
304
+
305
+ countCrossFileCallers(nodeId: number, file: string): number {
306
+ return this.#ndb.countCrossFileCallers(nodeId, file);
307
+ }
308
+
309
+ getClassHierarchy(classNodeId: number): Set<number> {
310
+ return new Set(this.#ndb.getClassHierarchy(classNodeId));
311
+ }
312
+
313
+ findImplementors(nodeId: number): RelatedNodeRow[] {
314
+ return this.#ndb.findImplementors(nodeId).map(toRelatedNodeRow);
315
+ }
316
+
317
+ findInterfaces(nodeId: number): RelatedNodeRow[] {
318
+ return this.#ndb.findInterfaces(nodeId).map(toRelatedNodeRow);
319
+ }
320
+
321
+ findIntraFileCallEdges(file: string): IntraFileCallEdge[] {
322
+ return this.#ndb.findIntraFileCallEdges(file).map(toIntraFileCallEdge);
323
+ }
324
+
325
+ // ── Graph-read queries ────────────────────────────────────────────
326
+
327
+ getCallableNodes(): CallableNodeRow[] {
328
+ return this.#ndb.getCallableNodes().map(toCallableNodeRow);
329
+ }
330
+
331
+ getCallEdges(): CallEdgeRow[] {
332
+ return this.#ndb.getCallEdges().map(toCallEdgeRow);
333
+ }
334
+
335
+ getFileNodesAll(): FileNodeRow[] {
336
+ return this.#ndb.getFileNodesAll().map(toFileNodeRow);
337
+ }
338
+
339
+ getImportEdges(): ImportGraphEdgeRow[] {
340
+ return this.#ndb.getImportEdges().map(toImportGraphEdgeRow);
341
+ }
342
+
343
+ // ── Optional table checks ─────────────────────────────────────────
344
+
345
+ hasCfgTables(): boolean {
346
+ return this.#ndb.hasCfgTables();
347
+ }
348
+
349
+ hasEmbeddings(): boolean {
350
+ return this.#ndb.hasEmbeddings();
351
+ }
352
+
353
+ hasDataflowTable(): boolean {
354
+ return this.#ndb.hasDataflowTable();
355
+ }
356
+
357
+ getComplexityForNode(nodeId: number): ComplexityMetrics | undefined {
358
+ const r = this.#ndb.getComplexityForNode(nodeId);
359
+ return r ? toComplexityMetrics(r) : undefined;
360
+ }
361
+ }
@@ -4,6 +4,7 @@ import type {
4
4
  BetterSqlite3Database,
5
5
  ChildNodeRow,
6
6
  ListFunctionOpts,
7
+ NativeDatabase,
7
8
  NodeIdRow,
8
9
  NodeRow,
9
10
  NodeRowWithFanIn,
@@ -24,6 +25,7 @@ export function findNodesWithFanIn(
24
25
  db: BetterSqlite3Database,
25
26
  namePattern: string,
26
27
  opts: QueryOpts = {},
28
+ nativeDb?: NativeDatabase,
27
29
  ): NodeRowWithFanIn[] {
28
30
  const q = new NodeQuery()
29
31
  .select('n.*, COALESCE(fi.cnt, 0) AS fan_in')
@@ -37,7 +39,7 @@ export function findNodesWithFanIn(
37
39
  q.fileFilter(opts.file);
38
40
  }
39
41
 
40
- return q.all(db);
42
+ return q.all(db, nativeDb);
41
43
  }
42
44
 
43
45
  /**
@@ -46,6 +48,7 @@ export function findNodesWithFanIn(
46
48
  export function findNodesForTriage(
47
49
  db: BetterSqlite3Database,
48
50
  opts: TriageQueryOpts = {},
51
+ nativeDb?: NativeDatabase,
49
52
  ): TriageNodeRow[] {
50
53
  if (opts.kind && !(EVERY_SYMBOL_KIND as readonly string[]).includes(opts.kind)) {
51
54
  throw new ConfigError(
@@ -77,7 +80,7 @@ export function findNodesForTriage(
77
80
  .roleFilter(opts.role)
78
81
  .orderBy('n.file, n.line');
79
82
 
80
- return q.all(db);
83
+ return q.all(db, nativeDb);
81
84
  }
82
85
 
83
86
  /**
@@ -99,8 +102,9 @@ function _functionNodeQuery(opts: ListFunctionOpts = {}): InstanceType<typeof No
99
102
  export function listFunctionNodes(
100
103
  db: BetterSqlite3Database,
101
104
  opts: ListFunctionOpts = {},
105
+ nativeDb?: NativeDatabase,
102
106
  ): NodeRow[] {
103
- return _functionNodeQuery(opts).all(db);
107
+ return _functionNodeQuery(opts).all(db, nativeDb);
104
108
  }
105
109
 
106
110
  /**
@@ -113,7 +113,6 @@ function countTransitiveImporters(
113
113
  export function briefData(
114
114
  file: string,
115
115
  customDbPath: string,
116
- // biome-ignore lint/suspicious/noExplicitAny: config shape is dynamic
117
116
  opts: { noTests?: boolean; config?: any } = {},
118
117
  ) {
119
118
  const db = openReadonlyOrFail(customDbPath);
@@ -379,7 +379,6 @@ function explainFunctionImpl(
379
379
  });
380
380
  }
381
381
 
382
- // biome-ignore lint/suspicious/noExplicitAny: explainFunctionImpl results have dynamic shape with _depth
383
382
  function explainCallees(
384
383
  parentResults: any[],
385
384
  currentDepth: number,
@@ -405,8 +404,8 @@ function explainCallees(
405
404
  );
406
405
  const exact = calleeResults.find((cr) => cr.file === callee.file && cr.line === callee.line);
407
406
  if (exact) {
408
- (exact as Record<string, unknown>)['_depth'] =
409
- (((r as Record<string, unknown>)['_depth'] as number) || 0) + 1;
407
+ (exact as Record<string, unknown>)._depth =
408
+ (((r as Record<string, unknown>)._depth as number) || 0) + 1;
410
409
  newCallees.push(exact);
411
410
  }
412
411
  }
@@ -431,7 +430,6 @@ export function contextData(
431
430
  kind?: string;
432
431
  limit?: number;
433
432
  offset?: number;
434
- // biome-ignore lint/suspicious/noExplicitAny: config shape is dynamic
435
433
  config?: any;
436
434
  } = {},
437
435
  ) {
@@ -509,7 +507,6 @@ export function explainData(
509
507
  depth?: number;
510
508
  limit?: number;
511
509
  offset?: number;
512
- // biome-ignore lint/suspicious/noExplicitAny: config shape is dynamic
513
510
  config?: any;
514
511
  } = {},
515
512
  ) {
@@ -533,7 +530,6 @@ export function explainData(
533
530
  : explainFunctionImpl(db, target, noTests, getFileLines, displayOpts);
534
531
 
535
532
  if (kind === 'function' && depth > 0 && results.length > 0) {
536
- // biome-ignore lint/suspicious/noExplicitAny: results are function results when kind === 'function'
537
533
  const visited = new Set(results.map((r: any) => `${r.name}:${r.file}:${r.line ?? ''}`));
538
534
  explainCallees(results, depth, visited, db, noTests, getFileLines, displayOpts);
539
535
  }
@@ -481,3 +481,168 @@ export function pathData(
481
481
  db.close();
482
482
  }
483
483
  }
484
+
485
+ // ── File-level shortest path ────────────────────────────────────────────
486
+
487
+ /**
488
+ * BFS at the file level: find shortest import/edge path between two files.
489
+ * Adjacency: file A → file B if any symbol in A has an edge to any symbol in B.
490
+ */
491
+ export function filePathData(
492
+ from: string,
493
+ to: string,
494
+ customDbPath: string,
495
+ opts: {
496
+ noTests?: boolean;
497
+ maxDepth?: number;
498
+ edgeKinds?: string[];
499
+ reverse?: boolean;
500
+ } = {},
501
+ ) {
502
+ const db = openReadonlyOrFail(customDbPath);
503
+ try {
504
+ const noTests = opts.noTests || false;
505
+ const maxDepth = opts.maxDepth || 10;
506
+ const edgeKinds = opts.edgeKinds || ['imports', 'imports-type'];
507
+ const reverse = opts.reverse || false;
508
+
509
+ // Resolve from/to as file paths (LIKE match)
510
+ const fromFiles = findFileNodes(db, `%${from}%`) as NodeRow[];
511
+ if (fromFiles.length === 0) {
512
+ return {
513
+ from,
514
+ to,
515
+ found: false,
516
+ error: `No file matching "${from}"`,
517
+ path: [],
518
+ fromCandidates: [],
519
+ toCandidates: [],
520
+ };
521
+ }
522
+ const toFiles = findFileNodes(db, `%${to}%`) as NodeRow[];
523
+ if (toFiles.length === 0) {
524
+ return {
525
+ from,
526
+ to,
527
+ found: false,
528
+ error: `No file matching "${to}"`,
529
+ path: [],
530
+ fromCandidates: fromFiles.slice(0, 5).map((f) => f.file),
531
+ toCandidates: [],
532
+ };
533
+ }
534
+
535
+ const sourceFile = fromFiles[0]!.file;
536
+ const targetFile = toFiles[0]!.file;
537
+
538
+ const fromCandidates = fromFiles.slice(0, 5).map((f) => f.file);
539
+ const toCandidates = toFiles.slice(0, 5).map((f) => f.file);
540
+
541
+ if (sourceFile === targetFile) {
542
+ return {
543
+ from,
544
+ to,
545
+ fromCandidates,
546
+ toCandidates,
547
+ found: true,
548
+ hops: 0,
549
+ path: [sourceFile],
550
+ alternateCount: 0,
551
+ edgeKinds,
552
+ reverse,
553
+ maxDepth,
554
+ };
555
+ }
556
+
557
+ // Build neighbor query: find all distinct files adjacent to a given file via edges
558
+ const kindPlaceholders = edgeKinds.map(() => '?').join(', ');
559
+ const neighborQuery = reverse
560
+ ? `SELECT DISTINCT n_src.file AS neighbor_file
561
+ FROM nodes n_tgt
562
+ JOIN edges e ON e.target_id = n_tgt.id
563
+ JOIN nodes n_src ON e.source_id = n_src.id
564
+ WHERE n_tgt.file = ? AND e.kind IN (${kindPlaceholders}) AND n_src.file != n_tgt.file`
565
+ : `SELECT DISTINCT n_tgt.file AS neighbor_file
566
+ FROM nodes n_src
567
+ JOIN edges e ON e.source_id = n_src.id
568
+ JOIN nodes n_tgt ON e.target_id = n_tgt.id
569
+ WHERE n_src.file = ? AND e.kind IN (${kindPlaceholders}) AND n_tgt.file != n_src.file`;
570
+ const neighborStmt = db.prepare(neighborQuery);
571
+
572
+ // BFS
573
+ const visited = new Set([sourceFile]);
574
+ const parentMap = new Map<string, string>();
575
+ let queue = [sourceFile];
576
+ let found = false;
577
+ let alternateCount = 0;
578
+
579
+ for (let depth = 1; depth <= maxDepth; depth++) {
580
+ const nextQueue: string[] = [];
581
+ for (const currentFile of queue) {
582
+ const neighbors = neighborStmt.all(currentFile, ...edgeKinds) as Array<{
583
+ neighbor_file: string;
584
+ }>;
585
+ for (const n of neighbors) {
586
+ if (noTests && isTestFile(n.neighbor_file)) continue;
587
+ if (n.neighbor_file === targetFile) {
588
+ if (!found) {
589
+ found = true;
590
+ parentMap.set(n.neighbor_file, currentFile);
591
+ }
592
+ alternateCount++;
593
+ continue;
594
+ }
595
+ if (!visited.has(n.neighbor_file)) {
596
+ visited.add(n.neighbor_file);
597
+ parentMap.set(n.neighbor_file, currentFile);
598
+ nextQueue.push(n.neighbor_file);
599
+ }
600
+ }
601
+ }
602
+ if (found) break;
603
+ queue = nextQueue;
604
+ if (queue.length === 0) break;
605
+ }
606
+
607
+ if (!found) {
608
+ return {
609
+ from,
610
+ to,
611
+ fromCandidates,
612
+ toCandidates,
613
+ found: false,
614
+ hops: null,
615
+ path: [],
616
+ alternateCount: 0,
617
+ edgeKinds,
618
+ reverse,
619
+ maxDepth,
620
+ };
621
+ }
622
+
623
+ // Reconstruct path
624
+ const filePath: string[] = [targetFile];
625
+ let cur = targetFile;
626
+ while (cur !== sourceFile) {
627
+ cur = parentMap.get(cur)!;
628
+ filePath.push(cur);
629
+ }
630
+ filePath.reverse();
631
+
632
+ return {
633
+ from,
634
+ to,
635
+ fromCandidates,
636
+ toCandidates,
637
+ found: true,
638
+ hops: filePath.length - 1,
639
+ path: filePath,
640
+ alternateCount: Math.max(0, alternateCount - 1),
641
+ edgeKinds,
642
+ reverse,
643
+ maxDepth,
644
+ };
645
+ } finally {
646
+ db.close();
647
+ }
648
+ }