gitnexus 1.6.8-rc.8 → 1.6.8

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 (439) hide show
  1. package/README.md +3 -3
  2. package/dist/_shared/graph/types.d.ts +31 -1
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/language-detection.d.ts.map +1 -1
  5. package/dist/_shared/language-detection.js +11 -1
  6. package/dist/_shared/language-detection.js.map +1 -1
  7. package/dist/_shared/lbug/schema-constants.d.ts +1 -1
  8. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  9. package/dist/_shared/lbug/schema-constants.js +6 -0
  10. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  11. package/dist/_shared/scope-resolution/parsed-file.d.ts +21 -0
  12. package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
  13. package/dist/_shared/scope-resolution/symbol-definition.d.ts +6 -0
  14. package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
  15. package/dist/cli/ai-context.d.ts +31 -1
  16. package/dist/cli/ai-context.js +18 -16
  17. package/dist/cli/analyze-config.js +11 -0
  18. package/dist/cli/analyze.d.ts +14 -0
  19. package/dist/cli/analyze.js +98 -0
  20. package/dist/cli/embedding-dims.d.ts +33 -0
  21. package/dist/cli/embedding-dims.js +39 -0
  22. package/dist/cli/eval-server.d.ts +8 -0
  23. package/dist/cli/eval-server.js +242 -2
  24. package/dist/cli/help-i18n.js +19 -0
  25. package/dist/cli/i18n/en.d.ts +15 -1
  26. package/dist/cli/i18n/en.js +15 -1
  27. package/dist/cli/i18n/resources.d.ts +29 -1
  28. package/dist/cli/i18n/zh-CN.d.ts +14 -0
  29. package/dist/cli/i18n/zh-CN.js +15 -1
  30. package/dist/cli/index.js +89 -1
  31. package/dist/cli/mcp.d.ts +6 -1
  32. package/dist/cli/mcp.js +26 -1
  33. package/dist/cli/optional-grammars.d.ts +6 -8
  34. package/dist/cli/optional-grammars.js +8 -11
  35. package/dist/cli/setup.d.ts +3 -1
  36. package/dist/cli/setup.js +67 -17
  37. package/dist/cli/skill-gen.js +2 -1
  38. package/dist/cli/tool.d.ts +19 -1
  39. package/dist/cli/tool.js +96 -3
  40. package/dist/core/embeddings/hf-env.d.ts +0 -66
  41. package/dist/core/embeddings/http-client.d.ts +7 -0
  42. package/dist/core/embeddings/http-client.js +5 -3
  43. package/dist/core/embeddings/server-mapping.d.ts +1 -1
  44. package/dist/core/embeddings/server-mapping.js +7 -3
  45. package/dist/core/graph/import-cycles.d.ts +10 -0
  46. package/dist/core/graph/import-cycles.js +103 -0
  47. package/dist/core/group/cross-impact.d.ts +2 -1
  48. package/dist/core/group/cross-impact.js +5 -1
  49. package/dist/core/group/extractors/grpc-patterns/proto.js +10 -6
  50. package/dist/core/group/extractors/http-patterns/kotlin.js +7 -7
  51. package/dist/core/group/extractors/http-route-extractor.d.ts +24 -0
  52. package/dist/core/group/extractors/http-route-extractor.js +22 -4
  53. package/dist/core/group/extractors/include-extractor.js +22 -13
  54. package/dist/core/group/sync.d.ts +27 -1
  55. package/dist/core/group/sync.js +0 -0
  56. package/dist/core/incremental/subgraph-extract.js +18 -1
  57. package/dist/core/ingestion/cfg/cfg-builder.d.ts +114 -0
  58. package/dist/core/ingestion/cfg/cfg-builder.js +196 -0
  59. package/dist/core/ingestion/cfg/collect.d.ts +51 -0
  60. package/dist/core/ingestion/cfg/collect.js +77 -0
  61. package/dist/core/ingestion/cfg/control-dependence.d.ts +58 -0
  62. package/dist/core/ingestion/cfg/control-dependence.js +182 -0
  63. package/dist/core/ingestion/cfg/control-flow-context.d.ts +106 -0
  64. package/dist/core/ingestion/cfg/control-flow-context.js +124 -0
  65. package/dist/core/ingestion/cfg/emit.d.ts +293 -0
  66. package/dist/core/ingestion/cfg/emit.js +646 -0
  67. package/dist/core/ingestion/cfg/post-dominators.d.ts +79 -0
  68. package/dist/core/ingestion/cfg/post-dominators.js +176 -0
  69. package/dist/core/ingestion/cfg/reaching-def-reason-codec.d.ts +106 -0
  70. package/dist/core/ingestion/cfg/reaching-def-reason-codec.js +133 -0
  71. package/dist/core/ingestion/cfg/reaching-defs-graph.d.ts +18 -0
  72. package/dist/core/ingestion/cfg/reaching-defs-graph.js +312 -0
  73. package/dist/core/ingestion/cfg/reaching-defs.d.ts +162 -0
  74. package/dist/core/ingestion/cfg/reaching-defs.js +785 -0
  75. package/dist/core/ingestion/cfg/synthetic-escape.d.ts +124 -0
  76. package/dist/core/ingestion/cfg/synthetic-escape.js +300 -0
  77. package/dist/core/ingestion/cfg/traversal-result.d.ts +20 -0
  78. package/dist/core/ingestion/cfg/traversal-result.js +2 -0
  79. package/dist/core/ingestion/cfg/types.d.ts +274 -0
  80. package/dist/core/ingestion/cfg/types.js +13 -0
  81. package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.d.ts +111 -0
  82. package/dist/core/ingestion/cfg/visitors/c-cpp-harvest.js +541 -0
  83. package/dist/core/ingestion/cfg/visitors/c-cpp.d.ts +74 -0
  84. package/dist/core/ingestion/cfg/visitors/c-cpp.js +584 -0
  85. package/dist/core/ingestion/cfg/visitors/call-site-harvest.d.ts +195 -0
  86. package/dist/core/ingestion/cfg/visitors/call-site-harvest.js +350 -0
  87. package/dist/core/ingestion/cfg/visitors/csharp-harvest.d.ts +124 -0
  88. package/dist/core/ingestion/cfg/visitors/csharp-harvest.js +589 -0
  89. package/dist/core/ingestion/cfg/visitors/csharp.d.ts +87 -0
  90. package/dist/core/ingestion/cfg/visitors/csharp.js +867 -0
  91. package/dist/core/ingestion/cfg/visitors/dart-harvest.d.ts +278 -0
  92. package/dist/core/ingestion/cfg/visitors/dart-harvest.js +870 -0
  93. package/dist/core/ingestion/cfg/visitors/dart.d.ts +119 -0
  94. package/dist/core/ingestion/cfg/visitors/dart.js +836 -0
  95. package/dist/core/ingestion/cfg/visitors/go-harvest.d.ts +160 -0
  96. package/dist/core/ingestion/cfg/visitors/go-harvest.js +621 -0
  97. package/dist/core/ingestion/cfg/visitors/go.d.ts +108 -0
  98. package/dist/core/ingestion/cfg/visitors/go.js +638 -0
  99. package/dist/core/ingestion/cfg/visitors/java-harvest.d.ts +108 -0
  100. package/dist/core/ingestion/cfg/visitors/java-harvest.js +513 -0
  101. package/dist/core/ingestion/cfg/visitors/java.d.ts +101 -0
  102. package/dist/core/ingestion/cfg/visitors/java.js +812 -0
  103. package/dist/core/ingestion/cfg/visitors/kotlin-harvest.d.ts +253 -0
  104. package/dist/core/ingestion/cfg/visitors/kotlin-harvest.js +719 -0
  105. package/dist/core/ingestion/cfg/visitors/kotlin.d.ts +121 -0
  106. package/dist/core/ingestion/cfg/visitors/kotlin.js +809 -0
  107. package/dist/core/ingestion/cfg/visitors/php-harvest.d.ts +172 -0
  108. package/dist/core/ingestion/cfg/visitors/php-harvest.js +626 -0
  109. package/dist/core/ingestion/cfg/visitors/php.d.ts +96 -0
  110. package/dist/core/ingestion/cfg/visitors/php.js +721 -0
  111. package/dist/core/ingestion/cfg/visitors/python-harvest.d.ts +212 -0
  112. package/dist/core/ingestion/cfg/visitors/python-harvest.js +739 -0
  113. package/dist/core/ingestion/cfg/visitors/python.d.ts +103 -0
  114. package/dist/core/ingestion/cfg/visitors/python.js +558 -0
  115. package/dist/core/ingestion/cfg/visitors/ruby-harvest.d.ts +223 -0
  116. package/dist/core/ingestion/cfg/visitors/ruby-harvest.js +587 -0
  117. package/dist/core/ingestion/cfg/visitors/ruby.d.ts +112 -0
  118. package/dist/core/ingestion/cfg/visitors/ruby.js +756 -0
  119. package/dist/core/ingestion/cfg/visitors/rust-harvest.d.ts +324 -0
  120. package/dist/core/ingestion/cfg/visitors/rust-harvest.js +873 -0
  121. package/dist/core/ingestion/cfg/visitors/rust.d.ts +95 -0
  122. package/dist/core/ingestion/cfg/visitors/rust.js +558 -0
  123. package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.d.ts +87 -0
  124. package/dist/core/ingestion/cfg/visitors/scope-tree-harvest.js +116 -0
  125. package/dist/core/ingestion/cfg/visitors/swift-harvest.d.ts +255 -0
  126. package/dist/core/ingestion/cfg/visitors/swift-harvest.js +679 -0
  127. package/dist/core/ingestion/cfg/visitors/swift.d.ts +116 -0
  128. package/dist/core/ingestion/cfg/visitors/swift.js +787 -0
  129. package/dist/core/ingestion/cfg/visitors/typescript-harvest.d.ts +149 -0
  130. package/dist/core/ingestion/cfg/visitors/typescript-harvest.js +1056 -0
  131. package/dist/core/ingestion/cfg/visitors/typescript.d.ts +66 -0
  132. package/dist/core/ingestion/cfg/visitors/typescript.js +583 -0
  133. package/dist/core/ingestion/import-resolvers/utils.js +2 -0
  134. package/dist/core/ingestion/language-provider.d.ts +23 -2
  135. package/dist/core/ingestion/languages/c-cpp.js +17 -5
  136. package/dist/core/ingestion/languages/cobol.js +4 -0
  137. package/dist/core/ingestion/languages/cpp/arity-metadata.js +41 -2
  138. package/dist/core/ingestion/languages/cpp/captures.js +50 -1
  139. package/dist/core/ingestion/languages/cpp/conversion-rank.d.ts +2 -0
  140. package/dist/core/ingestion/languages/cpp/conversion-rank.js +89 -0
  141. package/dist/core/ingestion/languages/cpp/header-scan.d.ts +1 -1
  142. package/dist/core/ingestion/languages/cpp/header-scan.js +2 -2
  143. package/dist/core/ingestion/languages/cpp/inline-namespaces.js +7 -2
  144. package/dist/core/ingestion/languages/cpp/member-lookup.js +2 -1
  145. package/dist/core/ingestion/languages/cpp/query.js +23 -0
  146. package/dist/core/ingestion/languages/cpp/scope-resolver.js +2 -1
  147. package/dist/core/ingestion/languages/csharp.js +2 -0
  148. package/dist/core/ingestion/languages/dart.js +2 -0
  149. package/dist/core/ingestion/languages/go.js +2 -0
  150. package/dist/core/ingestion/languages/java.js +3 -0
  151. package/dist/core/ingestion/languages/kotlin/query.js +3 -2
  152. package/dist/core/ingestion/languages/kotlin.js +8 -1
  153. package/dist/core/ingestion/languages/php.js +2 -0
  154. package/dist/core/ingestion/languages/python.js +2 -0
  155. package/dist/core/ingestion/languages/ruby.js +2 -0
  156. package/dist/core/ingestion/languages/rust.js +2 -0
  157. package/dist/core/ingestion/languages/swift.js +2 -0
  158. package/dist/core/ingestion/languages/typescript.js +5 -0
  159. package/dist/core/ingestion/languages/vue.js +6 -0
  160. package/dist/core/ingestion/method-extractors/configs/c-cpp.js +6 -13
  161. package/dist/core/ingestion/method-extractors/generic.js +1 -0
  162. package/dist/core/ingestion/method-types.d.ts +2 -0
  163. package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
  164. package/dist/core/ingestion/model/symbol-table.js +1 -0
  165. package/dist/core/ingestion/mro-processor.js +109 -0
  166. package/dist/core/ingestion/parsing-processor.js +44 -0
  167. package/dist/core/ingestion/pipeline-phases/call-summaries.d.ts +26 -0
  168. package/dist/core/ingestion/pipeline-phases/call-summaries.js +46 -0
  169. package/dist/core/ingestion/pipeline-phases/index.d.ts +2 -0
  170. package/dist/core/ingestion/pipeline-phases/index.js +2 -0
  171. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +0 -21
  172. package/dist/core/ingestion/pipeline-phases/parse-impl.js +18 -1
  173. package/dist/core/ingestion/pipeline-phases/routes.d.ts +10 -0
  174. package/dist/core/ingestion/pipeline-phases/routes.js +30 -1
  175. package/dist/core/ingestion/pipeline-phases/taint-summaries.d.ts +30 -0
  176. package/dist/core/ingestion/pipeline-phases/taint-summaries.js +81 -0
  177. package/dist/core/ingestion/pipeline.d.ts +92 -10
  178. package/dist/core/ingestion/pipeline.js +11 -2
  179. package/dist/core/ingestion/scope-extractor.js +12 -2
  180. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +9 -0
  181. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.d.ts +75 -0
  182. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +67 -0
  183. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +12 -2
  184. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +14 -2
  185. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +6 -1
  186. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +13 -1
  187. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +9 -1
  188. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +28 -2
  189. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +4 -0
  190. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +9 -0
  191. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +6 -1
  192. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +174 -40
  193. package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +24 -0
  194. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +276 -190
  195. package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +43 -3
  196. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +75 -0
  197. package/dist/core/ingestion/scope-resolution/pipeline/run.js +349 -1
  198. package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
  199. package/dist/core/ingestion/taint/call-summary-codec.d.ts +75 -0
  200. package/dist/core/ingestion/taint/call-summary-codec.js +128 -0
  201. package/dist/core/ingestion/taint/call-summary-emit.d.ts +43 -0
  202. package/dist/core/ingestion/taint/call-summary-emit.js +70 -0
  203. package/dist/core/ingestion/taint/call-summary-harvest.d.ts +77 -0
  204. package/dist/core/ingestion/taint/call-summary-harvest.js +179 -0
  205. package/dist/core/ingestion/taint/call-summary-model.d.ts +47 -0
  206. package/dist/core/ingestion/taint/call-summary-model.js +25 -0
  207. package/dist/core/ingestion/taint/emit.d.ts +125 -0
  208. package/dist/core/ingestion/taint/emit.js +208 -0
  209. package/dist/core/ingestion/taint/interproc-emit.d.ts +50 -0
  210. package/dist/core/ingestion/taint/interproc-emit.js +88 -0
  211. package/dist/core/ingestion/taint/interproc-solver.d.ts +110 -0
  212. package/dist/core/ingestion/taint/interproc-solver.js +312 -0
  213. package/dist/core/ingestion/taint/match.d.ts +153 -0
  214. package/dist/core/ingestion/taint/match.js +278 -0
  215. package/dist/core/ingestion/taint/path-codec.d.ts +134 -0
  216. package/dist/core/ingestion/taint/path-codec.js +190 -0
  217. package/dist/core/ingestion/taint/propagate.d.ts +216 -0
  218. package/dist/core/ingestion/taint/propagate.js +659 -0
  219. package/dist/core/ingestion/taint/site-safety.d.ts +29 -0
  220. package/dist/core/ingestion/taint/site-safety.js +98 -0
  221. package/dist/core/ingestion/taint/source-sink-config.d.ts +107 -23
  222. package/dist/core/ingestion/taint/source-sink-config.js +35 -12
  223. package/dist/core/ingestion/taint/source-sink-registry.d.ts +6 -4
  224. package/dist/core/ingestion/taint/source-sink-registry.js +6 -4
  225. package/dist/core/ingestion/taint/summary-harvest-driver.d.ts +80 -0
  226. package/dist/core/ingestion/taint/summary-harvest-driver.js +179 -0
  227. package/dist/core/ingestion/taint/summary-harvest.d.ts +89 -0
  228. package/dist/core/ingestion/taint/summary-harvest.js +537 -0
  229. package/dist/core/ingestion/taint/summary-model.d.ts +200 -0
  230. package/dist/core/ingestion/taint/summary-model.js +86 -0
  231. package/dist/core/ingestion/taint/typescript-model.d.ts +38 -0
  232. package/dist/core/ingestion/taint/typescript-model.js +102 -0
  233. package/dist/core/ingestion/type-extractors/c-cpp.js +21 -0
  234. package/dist/core/ingestion/utils/env.d.ts +7 -0
  235. package/dist/core/ingestion/utils/env.js +12 -0
  236. package/dist/core/ingestion/utils/method-props.js +1 -0
  237. package/dist/core/ingestion/workers/clone-safety.d.ts +109 -0
  238. package/dist/core/ingestion/workers/clone-safety.js +465 -0
  239. package/dist/core/ingestion/workers/parse-worker.d.ts +23 -0
  240. package/dist/core/ingestion/workers/parse-worker.js +81 -53
  241. package/dist/core/ingestion/workers/post-result.d.ts +22 -0
  242. package/dist/core/ingestion/workers/post-result.js +87 -0
  243. package/dist/core/ingestion/workers/result-merge.d.ts +20 -0
  244. package/dist/core/ingestion/workers/result-merge.js +43 -0
  245. package/dist/core/ingestion/workers/worker-pool.d.ts +15 -40
  246. package/dist/core/ingestion/workers/worker-pool.js +43 -16
  247. package/dist/core/lbug/csv-generator.d.ts +51 -3
  248. package/dist/core/lbug/csv-generator.js +369 -255
  249. package/dist/core/lbug/lbug-adapter.d.ts +58 -18
  250. package/dist/core/lbug/lbug-adapter.js +346 -84
  251. package/dist/core/lbug/lbug-config.d.ts +19 -0
  252. package/dist/core/lbug/lbug-config.js +29 -0
  253. package/dist/core/lbug/pdg-emit-sink.d.ts +127 -0
  254. package/dist/core/lbug/pdg-emit-sink.js +358 -0
  255. package/dist/core/lbug/pool-adapter.d.ts +35 -0
  256. package/dist/core/lbug/pool-adapter.js +90 -1
  257. package/dist/core/lbug/rel-pair-routing.d.ts +54 -0
  258. package/dist/core/lbug/rel-pair-routing.js +140 -0
  259. package/dist/core/lbug/schema.d.ts +2 -2
  260. package/dist/core/lbug/schema.js +3 -0
  261. package/dist/core/logger.d.ts +0 -5
  262. package/dist/core/run-analyze.d.ts +96 -0
  263. package/dist/core/run-analyze.js +207 -3
  264. package/dist/core/tree-sitter/parser-loader.js +5 -4
  265. package/dist/core/tree-sitter/safe-parse.d.ts +0 -5
  266. package/dist/core/tree-sitter/vendored-grammars.d.ts +39 -0
  267. package/dist/core/tree-sitter/vendored-grammars.js +57 -0
  268. package/dist/core/wiki/generator.js +3 -1
  269. package/dist/core/wiki/graph-queries.d.ts +6 -0
  270. package/dist/core/wiki/graph-queries.js +9 -1
  271. package/dist/mcp/http-transport.d.ts +134 -0
  272. package/dist/mcp/http-transport.js +503 -0
  273. package/dist/mcp/local/local-backend.d.ts +110 -24
  274. package/dist/mcp/local/local-backend.js +1225 -19
  275. package/dist/mcp/local/pdg-impact.d.ts +384 -0
  276. package/dist/mcp/local/pdg-impact.js +1972 -0
  277. package/dist/mcp/resources.js +13 -1
  278. package/dist/mcp/tools.d.ts +12 -0
  279. package/dist/mcp/tools.js +214 -7
  280. package/dist/server/analyze-launch.d.ts +29 -0
  281. package/dist/server/analyze-launch.js +137 -0
  282. package/dist/server/analyze-upload.d.ts +33 -0
  283. package/dist/server/analyze-upload.js +123 -0
  284. package/dist/server/analyze-worker-ipc.d.ts +58 -0
  285. package/dist/server/analyze-worker-ipc.js +16 -0
  286. package/dist/server/analyze-worker.d.ts +17 -1
  287. package/dist/server/analyze-worker.js +7 -1
  288. package/dist/server/api.d.ts +17 -0
  289. package/dist/server/api.js +132 -168
  290. package/dist/server/git-clone.d.ts +43 -2
  291. package/dist/server/git-clone.js +211 -16
  292. package/dist/server/mcp-http.d.ts +5 -6
  293. package/dist/server/mcp-http.js +9 -82
  294. package/dist/server/middleware.d.ts +40 -0
  295. package/dist/server/middleware.js +92 -0
  296. package/dist/server/private-ip.d.ts +1 -0
  297. package/dist/server/private-ip.js +15 -0
  298. package/dist/server/upload-ingest.d.ts +56 -0
  299. package/dist/server/upload-ingest.js +276 -0
  300. package/dist/server/upload-paths.d.ts +37 -0
  301. package/dist/server/upload-paths.js +57 -0
  302. package/dist/server/upload-sweep.d.ts +20 -0
  303. package/dist/server/upload-sweep.js +57 -0
  304. package/dist/storage/git.js +5 -8
  305. package/dist/storage/parse-cache.d.ts +22 -1
  306. package/dist/storage/parse-cache.js +44 -10
  307. package/dist/storage/repo-manager.d.ts +121 -10
  308. package/dist/storage/repo-manager.js +43 -5
  309. package/dist/types/pipeline.d.ts +9 -0
  310. package/hooks/antigravity/gitnexus-antigravity-hook.cjs +110 -10
  311. package/hooks/claude/gitnexus-hook.cjs +110 -13
  312. package/hooks/claude/hook-db-lock-probe.cjs +513 -26
  313. package/package.json +8 -2
  314. package/scripts/assert-publish-grammar-coverage.cjs +31 -0
  315. package/scripts/build-tree-sitter-grammars.cjs +16 -10
  316. package/scripts/cross-platform-tests.ts +1 -0
  317. package/skills/gitnexus-debugging.md +16 -4
  318. package/skills/gitnexus-exploring.md +3 -3
  319. package/skills/gitnexus-guide.md +33 -0
  320. package/skills/gitnexus-pdg-query.md +89 -0
  321. package/skills/gitnexus-refactoring.md +1 -1
  322. package/skills/gitnexus-taint-analysis.md +178 -0
  323. package/vendor/tree-sitter-c/package.json +1 -1
  324. package/vendor/tree-sitter-dart/package.json +1 -1
  325. package/vendor/tree-sitter-kotlin/package.json +1 -1
  326. package/vendor/tree-sitter-proto/package.json +1 -1
  327. package/vendor/tree-sitter-swift/package.json +1 -1
  328. package/web/assets/{agent-CKPMqImC.js → agent-D3Xd7zZE.js} +123 -123
  329. package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +1 -0
  330. package/web/assets/architectureDiagram-UL44E2DR-ChH9xW-N.js +36 -0
  331. package/web/assets/{blockDiagram-7IZFK4PR-B4niSLvR.js → blockDiagram-7IZFK4PR-BkWhpzWB.js} +1 -1
  332. package/web/assets/{c4Diagram-Y2BXMSZH-DIzEXalR.js → c4Diagram-Y2BXMSZH-DtBvpzWD.js} +1 -1
  333. package/web/assets/{chunk-3SSMPTDK-BzGeeheI.js → chunk-3SSMPTDK-B4_etUhr.js} +2 -2
  334. package/web/assets/{chunk-5IMINLNL-CnTLsXIV.js → chunk-5IMINLNL-DOdTeQri.js} +1 -1
  335. package/web/assets/{chunk-5VCL7Z4A-w1BCx98Z.js → chunk-5VCL7Z4A-CQ-2dYWj.js} +1 -1
  336. package/web/assets/chunk-6764PJDD-DpIS7hxD.js +1 -0
  337. package/web/assets/{chunk-67TQ5CYL-CChC2cAv.js → chunk-67TQ5CYL-4sNPJU1q.js} +3 -3
  338. package/web/assets/{chunk-7W6UQGC5-CgFyfZ6k.js → chunk-7W6UQGC5-KyEG0HQg.js} +1 -1
  339. package/web/assets/{chunk-AZZRMDJM-5E9ARdDQ.js → chunk-AZZRMDJM-y-xJBuMz.js} +1 -1
  340. package/web/assets/{chunk-INKRHTLW-ELpfuk9h.js → chunk-INKRHTLW-Nu4ri9P-.js} +1 -1
  341. package/web/assets/{chunk-JQRUD6KW-Dcq_Qnyy.js → chunk-JQRUD6KW-Dbva2Z17.js} +1 -1
  342. package/web/assets/{chunk-KGFNY3KK-W-VR57xb.js → chunk-KGFNY3KK-JGMJvKCK.js} +1 -1
  343. package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +161 -0
  344. package/web/assets/{chunk-KNLZD3CH-BuZBOcso.js → chunk-KNLZD3CH-BGlP6X9R.js} +1 -1
  345. package/web/assets/{chunk-KRXBNO2N-DH2NPM7I.js → chunk-KRXBNO2N-BW5o0KUN.js} +1 -1
  346. package/web/assets/{chunk-LCXTWHL2-Dfmux4m1.js → chunk-LCXTWHL2-zoomRtWX.js} +1 -1
  347. package/web/assets/{chunk-LII3EMHJ-3X33tCpU.js → chunk-LII3EMHJ-D-jm-dLa.js} +1 -1
  348. package/web/assets/{chunk-QA3QBVWF-D5Ha3GgB.js → chunk-QA3QBVWF-BgRW3SXd.js} +1 -1
  349. package/web/assets/{chunk-RG4AUYOV-CAkzcoRj.js → chunk-RG4AUYOV-DD0B2N2B.js} +1 -1
  350. package/web/assets/{chunk-T2UQINTJ-kGYG7ppP.js → chunk-T2UQINTJ-DSBqkzH7.js} +1 -1
  351. package/web/assets/chunk-T5OCTHI4-DdZvN-9i.js +1 -0
  352. package/web/assets/{chunk-UY5QBCOK-Du-c56gs.js → chunk-UY5QBCOK-DyF0vyGd.js} +1 -1
  353. package/web/assets/{chunk-W44A43WB-lrCpuupA.js → chunk-W44A43WB-JqMLIpR0.js} +1 -1
  354. package/web/assets/{chunk-ZXARS5L4-CSZRiyOf.js → chunk-ZXARS5L4-CxN8oiwI.js} +1 -1
  355. package/web/assets/classDiagram-KGZ6W3CR-DJm9BgF-.js +1 -0
  356. package/web/assets/classDiagram-v2-72OJOZXJ-DJm9BgF-.js +1 -0
  357. package/web/assets/{context-builder-_HS0v2ma.js → context-builder-BHiFUA8O.js} +10 -2
  358. package/web/assets/{cose-bilkent-UX7MHV2Q-BHv2bbtl.js → cose-bilkent-UX7MHV2Q-D71wNYRJ.js} +1 -1
  359. package/web/assets/dagre-ND4H6XIP-BIkxmhcu.js +4 -0
  360. package/web/assets/diagram-3NCE3AQN-BTa6iH0T.js +43 -0
  361. package/web/assets/diagram-GF46GFSD-DZDV0vBj.js +24 -0
  362. package/web/assets/{diagram-HNR7UZ2L-fUWreZzx.js → diagram-HNR7UZ2L-DFCfd5LI.js} +2 -2
  363. package/web/assets/diagram-QXG6HAR7-BzM--Jj0.js +24 -0
  364. package/web/assets/diagram-WEQXMOUZ-DFFwz0k4.js +10 -0
  365. package/web/assets/{erDiagram-L5TCEMPS-QN2eEP1e.js → erDiagram-L5TCEMPS-CfHMJJqo.js} +1 -1
  366. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +1 -0
  367. package/web/assets/{flowDiagram-H6V6AXG4-CXbXImlN.js → flowDiagram-H6V6AXG4-Be805QiJ.js} +3 -3
  368. package/web/assets/{ganttDiagram-JCBTUEKG-BHQssTz6.js → ganttDiagram-JCBTUEKG-D3iL2Aet.js} +1 -1
  369. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +1 -0
  370. package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +106 -0
  371. package/web/assets/index-BvYev1UJ.js +635 -0
  372. package/web/assets/index-_lgn7hs5.css +2 -0
  373. package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +1 -0
  374. package/web/assets/infoDiagram-3YFTVSEB-Y7BKSoke.js +2 -0
  375. package/web/assets/{ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js → ishikawaDiagram-BNXS4ZKH-CT4SHFuI.js} +1 -1
  376. package/web/assets/{journeyDiagram-M6C3CM3L-DNPYCpvq.js → journeyDiagram-M6C3CM3L-CvArszLo.js} +1 -1
  377. package/web/assets/{kanban-definition-75IXJCU3-DgDi9oJT.js → kanban-definition-75IXJCU3-C6yDxr7N.js} +3 -3
  378. package/web/assets/{katex-K3KEBU37-CrVLz8l7.js → katex-K3KEBU37-CTc5BslQ.js} +1 -1
  379. package/web/assets/{mindmap-definition-2TDM6QVE-CwR5sBB-.js → mindmap-definition-2TDM6QVE-BOc2WEne.js} +1 -1
  380. package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +1 -0
  381. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +1 -0
  382. package/web/assets/{pieDiagram-CU6KROY3-By8g6f6B.js → pieDiagram-CU6KROY3-Cvc0f_Pd.js} +1 -1
  383. package/web/assets/{quadrantDiagram-VICAPDV7-bAm6Hi_5.js → quadrantDiagram-VICAPDV7-yXSZ2lLz.js} +1 -1
  384. package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +1 -0
  385. package/web/assets/{requirementDiagram-JXO7QTGE-7oDcJ1_J.js → requirementDiagram-JXO7QTGE-BRcZvHs4.js} +1 -1
  386. package/web/assets/{sankeyDiagram-URQDO5SZ-LFJz53u5.js → sankeyDiagram-URQDO5SZ-1qEjlFIB.js} +1 -1
  387. package/web/assets/{sequenceDiagram-VS2MUI6T-FySeKCUy.js → sequenceDiagram-VS2MUI6T-PcSCuvrB.js} +3 -3
  388. package/web/assets/stateDiagram-7D4R322I-D6qYSV1E.js +1 -0
  389. package/web/assets/stateDiagram-v2-36443NZ5-Bg-ImOSX.js +1 -0
  390. package/web/assets/{timeline-definition-O6YCAMPW-Ds2CnVZK.js → timeline-definition-O6YCAMPW-QWkh01xw.js} +1 -1
  391. package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +1 -0
  392. package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +1 -0
  393. package/web/assets/{vennDiagram-MWXL3ELB-DUIEwXWp.js → vennDiagram-MWXL3ELB-ak4DfwuM.js} +3 -3
  394. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +1 -0
  395. package/web/assets/{wardleyDiagram-CUQ6CDDI-DEiFPQih.js → wardleyDiagram-CUQ6CDDI-CTzR4Loq.js} +1 -1
  396. package/web/assets/{xychartDiagram-N2JHSOCM-BUbayhST.js → xychartDiagram-N2JHSOCM-DA1BEaQz.js} +1 -1
  397. package/web/index.html +13 -15
  398. package/scripts/materialize-vendor-grammars.cjs +0 -97
  399. package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +0 -1
  400. package/web/assets/architectureDiagram-UL44E2DR-D1EXI0zA.js +0 -36
  401. package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +0 -4
  402. package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +0 -1
  403. package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +0 -159
  404. package/web/assets/chunk-6764PJDD-ChwMM2z4.js +0 -1
  405. package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +0 -10
  406. package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +0 -1
  407. package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +0 -1
  408. package/web/assets/chunk-CilyBKbf.js +0 -1
  409. package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +0 -1
  410. package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +0 -1
  411. package/web/assets/chunk-RERM46MO-DQNbXtfw.js +0 -1
  412. package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +0 -1
  413. package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +0 -1
  414. package/web/assets/chunk-T5OCTHI4--9wWpVws.js +0 -1
  415. package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +0 -1
  416. package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +0 -1
  417. package/web/assets/classDiagram-KGZ6W3CR-Bv93af_b.js +0 -1
  418. package/web/assets/classDiagram-v2-72OJOZXJ-CLfEqHUa.js +0 -1
  419. package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +0 -4
  420. package/web/assets/diagram-3NCE3AQN-BqAtKUpW.js +0 -43
  421. package/web/assets/diagram-GF46GFSD-CaBG6n6o.js +0 -24
  422. package/web/assets/diagram-QXG6HAR7-CZ-O3rcV.js +0 -24
  423. package/web/assets/diagram-WEQXMOUZ-P4lSL4GH.js +0 -10
  424. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +0 -1
  425. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +0 -1
  426. package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +0 -106
  427. package/web/assets/index-BKWA-m7o.css +0 -2
  428. package/web/assets/index-CG6q8eTs.js +0 -626
  429. package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +0 -1
  430. package/web/assets/infoDiagram-3YFTVSEB-DmLICZx1.js +0 -2
  431. package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +0 -1
  432. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +0 -1
  433. package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +0 -1
  434. package/web/assets/stateDiagram-7D4R322I-CB2nABwH.js +0 -1
  435. package/web/assets/stateDiagram-v2-36443NZ5-COBGd2RL.js +0 -1
  436. package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +0 -1
  437. package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +0 -1
  438. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +0 -1
  439. /package/web/assets/{chunk-AQ6EADP3-CCFje6lL.js → chunk-AQ6EADP3-CZhslHi-.js} +0 -0
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Rust CfgVisitor (#2195 U7) — the EXPRESSION-ORIENTED CFG target. Unlike the
3
+ * C-family / Go / Python visitors (statement languages), Rust control flow is
4
+ * built from EXPRESSIONS: `if` / `loop` / `while` / `for` / `match` / `block`
5
+ * are all expressions that produce a value. The visitor still drives the
6
+ * language-agnostic {@link CfgBuilder} to produce a serializable
7
+ * {@link FunctionCfg} plus a def/use harvest ({@link RustHarvester}) for the
8
+ * reaching-defs / CDG solvers, structured like the sibling visitors — a
9
+ * `visit_<node_type>` dispatch over the control-flow taxonomy driving a
10
+ * per-function {@link ControlFlowContext} for labeled break/continue.
11
+ *
12
+ * Every node type and field literal below was grammar-validated against
13
+ * tree-sitter-rust via the introspection probe before use (mandatory pre-step).
14
+ * Rust shapes pre-empted (verified by a real parse):
15
+ * - functions: `function_item` (fields `name`/`parameters`/`return_type`/`body`;
16
+ * a method is a `function_item` inside an `impl_item`'s `declaration_list`)
17
+ * and `closure_expression` (field `parameters`=`closure_parameters`; `body` is
18
+ * a `block` OR a bare expression — `|x| x + 1`).
19
+ * - `if_expression` fields `condition` / `consequence` (a `block`) /
20
+ * `alternative` (an `else_clause` wrapping a `block` or a nested
21
+ * `if_expression` of an `else if`). The condition can be a `let_condition`
22
+ * (`if let PAT = e`) or a `let_chain` (`if let PAT = e && cond`).
23
+ * - `loop_expression` field `body` — the INFINITE loop (NO `condition` field);
24
+ * an optional `label` NAMED CHILD (label is NOT a field). The key
25
+ * non-terminating case.
26
+ * - `while_expression` fields `condition` (may be a `let_condition` for
27
+ * `while let`) / `body`; optional `label` named child.
28
+ * - `for_expression` fields `pattern` / `value` / `body`; optional `label`
29
+ * named child.
30
+ * - `match_expression` fields `value` / `body` (a `match_block` of `match_arm`s).
31
+ * A `match_arm` has field `pattern` (a `match_pattern`, which may carry an `if`
32
+ * guard with field `condition`) and field `value` (the arm body — an
33
+ * expression or a `block`). Arms do NOT fall through.
34
+ * - `break_expression` — optional `label` named child AND an optional value
35
+ * expression (`break 'a 42`). `continue_expression` — optional `label`.
36
+ * - `return_expression` — optional value child. `try_expression` (`expr?`) —
37
+ * the early-return operator.
38
+ * - a `label` node's bare name is its `identifier` child's text (`'outer`'s name
39
+ * is `outer`), matching `break 'outer` / `continue 'outer`.
40
+ *
41
+ * Edge-kind contract (matches the existing visitors — RD/CDG consume these):
42
+ * - if / else (incl. `if let`) → `cond-true` / `cond-false`
43
+ * - `loop {}` (no condition) → `loop-back` (body re-enters) PLUS a structural
44
+ * `cond-false` escape edge (header → loopExit) so EXIT stays reverse-reachable
45
+ * - `while` / `while let` / `for` → `cond-true` / `loop-back` / `cond-false`
46
+ * - `match` dispatch → `switch-case` (NO fallthrough — like Go / Python)
47
+ * - `break` / `continue` / `return` → the matching terminator kind; a labeled
48
+ * `break 'outer` / `continue 'outer` targets the labeled loop frame; a
49
+ * `break value` is still a `break` edge
50
+ * - the `?` operator (`try_expression`) → `throw` — an early error-return edge to
51
+ * EXIT from the `?` site (a conservative throw-like edge; the Err/None path)
52
+ * - straight-line → `seq`
53
+ *
54
+ * Rust-specific modeling decisions (documented approximations):
55
+ * - `loop {}` is the canonical Rust infinite loop with NO condition. We ALWAYS
56
+ * emit a structural `header → loopExit` escape edge (exactly as the C-family /
57
+ * Go visitors do for `while(true)` / `for {}`), so EXIT stays reverse-reachable
58
+ * and the post-dominator / CDG pass is not silently skipped for the function.
59
+ * This is the single highest-risk correctness property. A `loop {}` that
60
+ * DOES `break` also reaches EXIT via the break; the structural escape edge is
61
+ * emitted either way.
62
+ * - the `?` operator desugars to a `match` that returns the Err/None early. We
63
+ * model it conservatively as a `throw` edge to the function EXIT from the block
64
+ * that contains the `?` — so the post-`?` continuation stays reachable (the Ok
65
+ * path) AND the early-exit path is represented. Multiple `?` in one block emit
66
+ * one early-exit edge per `?`-bearing block (deduped by the builder).
67
+ * - a closure (`closure_expression`) is collected as its OWN function by
68
+ * `isFunction`, so its body gets a standalone CFG; in the ENCLOSING function it
69
+ * is an opaque straight-line value (its body is not followed inline), exactly
70
+ * as the Go visitor treats a spawned closure and the TS visitor an arrow body.
71
+ * - the trailing tail expression of a `block` (no `;`) is the block's value; for
72
+ * control-flow purposes it just falls off normally to the block's successor.
73
+ *
74
+ * Known limitations:
75
+ * - panic: a `panic!()` (or an out-of-bounds index, an `unwrap` on `None`) aborts
76
+ * the function abnormally, but tree-sitter sees only a normal macro/method call.
77
+ * The panic-unwind path is NOT modeled (documented gap, not faked) — Rust has
78
+ * no try/catch, so there is no handler structure to route to.
79
+ * - async (`async fn`, `.await`): the suspension points are modeled as normal
80
+ * straight-line control flow (no scheduler edges).
81
+ * - block scope + shadowing in the def/use harvest is flattened to one function
82
+ * table (see rust-harvest.ts) — a documented v1 over-approximation.
83
+ * - macro bodies (`println!`, `vec!`, custom macros) are opaque token trees — any
84
+ * control flow expanded by a macro is invisible.
85
+ *
86
+ * Returns `undefined` (never throws) for an AST shape it cannot model, so a
87
+ * malformed function never drops the whole file's CFG group (R4).
88
+ */
89
+ import type { SyntaxNode } from '../../utils/ast-helpers.js';
90
+ import type { CfgVisitor } from '../types.js';
91
+ /** Rust node types that own a CFG-bearing function body. */
92
+ declare const RUST_FUNCTION_TYPES: Set<string>;
93
+ /** The Rust CFG visitor. */
94
+ export declare function createRustCfgVisitor(): CfgVisitor<SyntaxNode>;
95
+ export { RUST_FUNCTION_TYPES };
@@ -0,0 +1,558 @@
1
+ import { CfgBuilder } from '../cfg-builder.js';
2
+ import { ControlFlowContext, wireJumpThroughFinalizers } from '../control-flow-context.js';
3
+ import { RustHarvester } from './rust-harvest.js';
4
+ /** Rust node types that own a CFG-bearing function body. */
5
+ const RUST_FUNCTION_TYPES = new Set(['function_item', 'closure_expression']);
6
+ /**
7
+ * Expression / statement node types that break a basic block (everything else
8
+ * coalesces). `expression_statement` is the `<expr>;` wrapper; the control-flow
9
+ * EXPRESSIONS inside it are unwrapped by {@link visitStmt}.
10
+ */
11
+ const CONTROL_FLOW_TYPES = new Set([
12
+ 'expression_statement',
13
+ 'if_expression',
14
+ 'loop_expression',
15
+ 'while_expression',
16
+ 'for_expression',
17
+ 'match_expression',
18
+ 'return_expression',
19
+ 'break_expression',
20
+ 'continue_expression',
21
+ 'block',
22
+ ]);
23
+ /** Expression node types that the statement walker treats as control-flow. */
24
+ const CONTROL_FLOW_EXPR_TYPES = new Set([
25
+ 'if_expression',
26
+ 'loop_expression',
27
+ 'while_expression',
28
+ 'for_expression',
29
+ 'match_expression',
30
+ 'return_expression',
31
+ 'break_expression',
32
+ 'continue_expression',
33
+ 'block',
34
+ ]);
35
+ /** Node types whose subtrees are opaque (a nested function owns its own CFG). */
36
+ const NESTED_FUNCTION_TYPES = new Set(['function_item', 'closure_expression']);
37
+ /** Rust comment node types — line (`//`) and block (slash-star) comments. */
38
+ const COMMENT_TYPES = new Set(['line_comment', 'block_comment']);
39
+ const isNotComment = (n) => !COMMENT_TYPES.has(n.type);
40
+ const startLineOf = (n) => n.startPosition.row + 1;
41
+ const endLineOf = (n) => n.endPosition.row + 1;
42
+ /**
43
+ * Per-function Rust walk state. One instance per function so the
44
+ * {@link ControlFlowContext} and label tables are scoped to that function and
45
+ * never leak across functions.
46
+ */
47
+ class RustCfgWalk {
48
+ builder;
49
+ harvest;
50
+ cfc = new ControlFlowContext();
51
+ constructor(builder, harvest) {
52
+ this.builder = builder;
53
+ this.harvest = harvest;
54
+ }
55
+ /** Statements of a `block`, ignoring comments. */
56
+ statementsOf(block) {
57
+ return block.namedChildren.filter(isNotComment);
58
+ }
59
+ /** The `body` of a node (a `block`, or a bare expression for a closure / arm). */
60
+ bodyOf(node) {
61
+ return node.childForFieldName('body') ?? undefined;
62
+ }
63
+ /** Visit a body that may be a `block` or a single expression. */
64
+ visitBody(node) {
65
+ return this.builder.withNesting(() => {
66
+ if (!node)
67
+ return null;
68
+ if (node.type === 'block')
69
+ return this.visitSeq(this.statementsOf(node));
70
+ return this.visitStmt(node);
71
+ });
72
+ }
73
+ /** Wire a sequence of statements, coalescing straight-line runs into blocks. */
74
+ visitSeq(stmts) {
75
+ return this.builder.withNesting(() => {
76
+ let entry;
77
+ let dangling = [];
78
+ let openSimple;
79
+ for (const stmt of stmts) {
80
+ if (this.isControlFlow(stmt)) {
81
+ openSimple = undefined; // close any open straight-line block
82
+ const res = this.visitStmt(stmt);
83
+ if (res === null)
84
+ continue; // transparent (empty nested block)
85
+ if (entry === undefined)
86
+ entry = res.entry;
87
+ else
88
+ this.builder.connect(dangling, res.entry, 'seq');
89
+ dangling = [...res.exits];
90
+ }
91
+ else {
92
+ const idx = openSimple === undefined ? this.openBlock(stmt) : this.extendOpen(openSimple, stmt);
93
+ if (openSimple === undefined) {
94
+ if (entry === undefined)
95
+ entry = idx;
96
+ else
97
+ this.builder.connect(dangling, idx, 'seq');
98
+ dangling = [idx];
99
+ }
100
+ openSimple = idx;
101
+ // A straight-line statement that contains a `?` early-returns to EXIT.
102
+ this.wireTryExits(stmt, idx);
103
+ }
104
+ }
105
+ if (entry === undefined)
106
+ return null;
107
+ return { entry, exits: dangling };
108
+ });
109
+ }
110
+ openBlock(stmt) {
111
+ return this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text, 'normal', this.harvest.facts(stmt));
112
+ }
113
+ extendOpen(open, stmt) {
114
+ this.builder.extendBlock(open, endLineOf(stmt), stmt.text, this.harvest.facts(stmt));
115
+ return open;
116
+ }
117
+ /** Whether a statement node breaks the current straight-line block. */
118
+ isControlFlow(stmt) {
119
+ if (stmt.type === 'expression_statement') {
120
+ const inner = this.exprStmtInner(stmt);
121
+ return inner ? CONTROL_FLOW_EXPR_TYPES.has(inner.type) : false;
122
+ }
123
+ if (stmt.type === 'let_declaration') {
124
+ // `let v = loop {…}` / `let w = if c {…} else {…}` / `let PAT = e else {…}`
125
+ // — the value is a control-flow EXPRESSION, or the let-else alternative
126
+ // block is divergent; either way the let must be modeled structurally.
127
+ const value = stmt.childForFieldName('value');
128
+ const alt = stmt.childForFieldName('alternative');
129
+ return (value !== null && CONTROL_FLOW_EXPR_TYPES.has(value.type)) || alt !== null;
130
+ }
131
+ return CONTROL_FLOW_TYPES.has(stmt.type);
132
+ }
133
+ /** The inner expression of an `expression_statement` (`if x {…};`). */
134
+ exprStmtInner(stmt) {
135
+ return stmt.namedChildren.find(isNotComment);
136
+ }
137
+ /** Dispatch one statement to its handler. Non-null except for empty blocks. */
138
+ visitStmt(stmt) {
139
+ // Unwrap an `expression_statement` to its control-flow expression.
140
+ if (stmt.type === 'expression_statement') {
141
+ const inner = this.exprStmtInner(stmt);
142
+ if (inner && CONTROL_FLOW_EXPR_TYPES.has(inner.type))
143
+ return this.visitStmt(inner);
144
+ return this.visitSimple(stmt);
145
+ }
146
+ if (stmt.type === 'let_declaration')
147
+ return this.visitLet(stmt);
148
+ switch (stmt.type) {
149
+ case 'if_expression':
150
+ return this.visitIf(stmt);
151
+ case 'loop_expression':
152
+ return this.visitLoop(stmt);
153
+ case 'while_expression':
154
+ return this.visitWhile(stmt);
155
+ case 'for_expression':
156
+ return this.visitFor(stmt);
157
+ case 'match_expression':
158
+ return this.visitMatch(stmt);
159
+ case 'return_expression':
160
+ return this.visitReturn(stmt);
161
+ case 'break_expression':
162
+ return this.visitBreak(stmt);
163
+ case 'continue_expression':
164
+ return this.visitContinue(stmt);
165
+ case 'block':
166
+ return this.visitSeq(this.statementsOf(stmt));
167
+ default:
168
+ return this.visitSimple(stmt);
169
+ }
170
+ }
171
+ visitSimple(stmt) {
172
+ const idx = this.openBlock(stmt);
173
+ this.wireTryExits(stmt, idx);
174
+ return { entry: idx, exits: [idx] };
175
+ }
176
+ /**
177
+ * `let PAT = VALUE [else { ALT }]` whose VALUE is a control-flow expression
178
+ * (`let v = loop {…}`, `let w = if c {…} else {…}`, `let m = match …`) or which
179
+ * has a divergent let-else ALT block. A plain `let x = e;` never reaches here
180
+ * (it coalesces into a straight-line block in {@link visitSeq}).
181
+ *
182
+ * The value's control-flow construct is visited as a sub-CFG; the let-pattern's
183
+ * bindings are defs that happen on the value's NORMAL completion — attached to a
184
+ * facts-only continuation block the value's exits feed. For a `let … else`, the
185
+ * ALT block runs on the refutable-failure path and (per Rust's rules) MUST
186
+ * diverge (return/break/continue/panic); it is visited as control flow, so its
187
+ * own jumps wire directly to their targets and it contributes no normal exit.
188
+ */
189
+ visitLet(stmt) {
190
+ const value = stmt.childForFieldName('value');
191
+ const alt = stmt.childForFieldName('alternative');
192
+ const cfValue = value !== null && CONTROL_FLOW_EXPR_TYPES.has(value.type);
193
+ let entry;
194
+ let normalExits;
195
+ if (cfValue && value) {
196
+ // `let v = loop {…}` — the value is a control-flow construct: visit it, then
197
+ // attach ONLY the pattern's binding defs to a facts-only continuation (the
198
+ // value's uses are already harvested onto its own blocks).
199
+ const valueRes = this.visitStmt(value);
200
+ const cont = this.builder.newBlock(startLineOf(stmt), startLineOf(stmt), '', 'normal', this.harvest.letPatternFacts(stmt));
201
+ this.builder.connect(valueRes?.exits ?? [], cont, 'seq');
202
+ entry = valueRes ? valueRes.entry : cont;
203
+ normalExits = [cont];
204
+ }
205
+ else {
206
+ // A simple-value `let PAT = e [else {…}]` — ONE block with the whole let's
207
+ // facts (value uses + pattern defs). It reaches here only via the let-else
208
+ // alternative (a plain `let x = e;` coalesces in visitSeq).
209
+ const idx = this.openBlock(stmt);
210
+ this.wireTryExits(stmt, idx);
211
+ entry = idx;
212
+ normalExits = [idx];
213
+ }
214
+ // `let … else { … }` — the else block runs on the binding-FAILURE path and
215
+ // (per Rust) MUST diverge (return/break/continue/panic); visit it as control
216
+ // flow so its jumps wire themselves to their targets. It is NOT on the normal
217
+ // continuation — branched from the binding site with a `cond-false` (refute)
218
+ // edge.
219
+ if (alt) {
220
+ const altRes = this.visitBody(alt);
221
+ if (altRes)
222
+ this.builder.connect(normalExits, altRes.entry, 'cond-false');
223
+ }
224
+ return { entry, exits: normalExits };
225
+ }
226
+ /**
227
+ * Emit a `throw` (early-return) edge to EXIT for every `?` operator inside a
228
+ * straight-line statement's subtree (excluding nested function bodies). The
229
+ * `?` desugars to "return Err(...) early"; modeling it as a throw-like edge to
230
+ * EXIT keeps the early-exit path represented while the Ok path falls through
231
+ * normally. Deduped by the builder, so repeated `?` in a block emit one edge.
232
+ */
233
+ wireTryExits(stmt, fromBlock) {
234
+ if (this.containsTry(stmt))
235
+ this.builder.edge(fromBlock, this.builder.exitIndex, 'throw');
236
+ }
237
+ containsTry(node) {
238
+ if (node.type === 'try_expression')
239
+ return true;
240
+ if (NESTED_FUNCTION_TYPES.has(node.type))
241
+ return false; // opaque
242
+ for (let i = 0; i < node.namedChildCount; i++) {
243
+ const c = node.namedChild(i);
244
+ if (c && this.containsTry(c))
245
+ return true;
246
+ }
247
+ return false;
248
+ }
249
+ /** `return [expr]` — direct edge to the function EXIT. */
250
+ visitReturn(stmt) {
251
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text, 'normal', this.harvest.facts(stmt));
252
+ // A `return f()?;` early-returns on the `?` path too.
253
+ this.wireTryExits(stmt, idx);
254
+ this.builder.edge(idx, this.builder.exitIndex, 'return');
255
+ return { entry: idx, exits: [] };
256
+ }
257
+ /**
258
+ * `break ['label] [value]` — targets the labeled loop frame if labeled, else the
259
+ * nearest enclosing loop. `break value` is still a `break` edge (the value is a
260
+ * normal use harvested onto the block).
261
+ */
262
+ visitBreak(stmt) {
263
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text, 'normal', this.harvest.facts(stmt));
264
+ this.wireTryExits(stmt, idx);
265
+ const label = this.jumpLabel(stmt);
266
+ const res = this.cfc.resolveBreak(label);
267
+ const { target, finalizers } = res ?? {
268
+ target: this.builder.exitIndex,
269
+ finalizers: this.cfc.finalizersForReturn(),
270
+ };
271
+ wireJumpThroughFinalizers(this.builder, idx, finalizers, target, 'break');
272
+ return { entry: idx, exits: [] };
273
+ }
274
+ /** `continue ['label]` — re-tests the labeled (or nearest) loop header. */
275
+ visitContinue(stmt) {
276
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text);
277
+ const label = this.jumpLabel(stmt);
278
+ const res = this.cfc.resolveContinue(label);
279
+ const { target, finalizers } = res ?? {
280
+ target: this.builder.exitIndex,
281
+ finalizers: this.cfc.finalizersForReturn(),
282
+ };
283
+ wireJumpThroughFinalizers(this.builder, idx, finalizers, target, 'continue');
284
+ return { entry: idx, exits: [] };
285
+ }
286
+ /** The bare name (`outer`) of a `break`/`continue`'s `'label`, if any. */
287
+ jumpLabel(stmt) {
288
+ const label = stmt.namedChildren.find((c) => c.type === 'label');
289
+ return this.labelName(label);
290
+ }
291
+ /** The bare identifier name of a `label` node (`'outer` ⇒ `outer`). */
292
+ labelName(label) {
293
+ if (!label)
294
+ return undefined;
295
+ const id = label.namedChildren.find((c) => c.type === 'identifier');
296
+ return id?.text ?? label.text.replace(/^'/, '');
297
+ }
298
+ /**
299
+ * The optional `'label` of a loop expression (a NAMED CHILD, not a field — Rust
300
+ * attaches the label directly to the loop, unlike Go's `labeled_statement`).
301
+ */
302
+ loopLabels(stmt) {
303
+ const label = stmt.namedChildren.find((c) => c.type === 'label');
304
+ const name = this.labelName(label);
305
+ return name !== undefined ? [name] : [];
306
+ }
307
+ /**
308
+ * `if COND { … } [else { … } | else if …]`. The condition can be a plain
309
+ * expression, a `let_condition` (`if let PAT = e`), or a `let_chain`. The header
310
+ * carries the condition's def/use facts (an `if let` pattern is a def, its value
311
+ * a use). The else `alternative` is an `else_clause` wrapping a `block` or a
312
+ * nested `if_expression` (the `else if` chain).
313
+ */
314
+ visitIf(stmt) {
315
+ const cond = stmt.childForFieldName('condition') ?? stmt;
316
+ const header = this.builder.newBlock(startLineOf(stmt), endLineOf(cond), cond.text, 'normal', this.condFacts(cond, false));
317
+ this.wireTryExits(cond, header);
318
+ const exits = [];
319
+ const thenRes = this.visitBody(stmt.childForFieldName('consequence'));
320
+ if (thenRes) {
321
+ this.builder.edge(header, thenRes.entry, 'cond-true');
322
+ exits.push(...thenRes.exits);
323
+ }
324
+ else {
325
+ exits.push(header); // empty then — true path falls through
326
+ }
327
+ const elseNode = this.elseBodyOf(stmt);
328
+ if (elseNode) {
329
+ const elseRes = this.visitBody(elseNode);
330
+ if (elseRes) {
331
+ this.builder.edge(header, elseRes.entry, 'cond-false');
332
+ exits.push(...elseRes.exits);
333
+ }
334
+ else {
335
+ exits.push(header);
336
+ }
337
+ }
338
+ else {
339
+ exits.push(header); // no else — false path falls through to the join
340
+ }
341
+ return { entry: header, exits: [...new Set(exits)] };
342
+ }
343
+ /** The else body of an `if_expression` (unwraps the `else_clause` wrapper). */
344
+ elseBodyOf(stmt) {
345
+ const alt = stmt.childForFieldName('alternative');
346
+ if (!alt)
347
+ return undefined;
348
+ if (alt.type === 'else_clause') {
349
+ // The clause wraps a `block` or a nested `if_expression` (`else if`).
350
+ return alt.namedChildren.find(isNotComment);
351
+ }
352
+ return alt;
353
+ }
354
+ /**
355
+ * `loop { … }` — Rust's INFINITE loop (NO condition). Body exits re-enter the
356
+ * header (`loop-back`); a `break` reaches `loopExit`. We ALWAYS emit a
357
+ * structural `header → loopExit` `cond-false` escape edge so EXIT stays
358
+ * reverse-reachable (a `loop {}` with no break never reaches EXIT otherwise, and
359
+ * the CDG pass would be silently skipped for the whole function).
360
+ */
361
+ visitLoop(stmt) {
362
+ const labels = this.loopLabels(stmt);
363
+ const header = this.builder.newBlock(startLineOf(stmt), startLineOf(stmt), 'loop');
364
+ const loopExit = this.builder.newBlock(endLineOf(stmt), endLineOf(stmt), '');
365
+ this.cfc.pushLoop(header, loopExit, labels);
366
+ const body = this.visitBody(this.bodyOf(stmt));
367
+ this.cfc.pop();
368
+ if (body) {
369
+ this.builder.edge(header, body.entry, 'cond-true');
370
+ this.builder.connect(body.exits, header, 'loop-back');
371
+ }
372
+ else {
373
+ this.builder.edge(header, header, 'loop-back'); // empty `loop {}` re-enters
374
+ }
375
+ // Structural escape edge — keeps EXIT reverse-reachable even for `loop {}`
376
+ // with no `break` (the canonical Rust non-terminating case).
377
+ this.builder.edge(header, loopExit, 'cond-false');
378
+ return { entry: header, exits: [loopExit] };
379
+ }
380
+ /**
381
+ * `while COND { … }` (and `while let PAT = e { … }`). Standard loop: header
382
+ * tests, true → body → loop-back, false → loop exit. The `while let` pattern is
383
+ * a may-def on the header (the binding does not happen on the exit iteration).
384
+ */
385
+ visitWhile(stmt) {
386
+ const labels = this.loopLabels(stmt);
387
+ const cond = stmt.childForFieldName('condition') ?? stmt;
388
+ const header = this.builder.newBlock(startLineOf(stmt), endLineOf(cond), cond.text, 'normal', this.condFacts(cond, true));
389
+ const loopExit = this.builder.newBlock(endLineOf(stmt), endLineOf(stmt), '');
390
+ this.cfc.pushLoop(header, loopExit, labels);
391
+ const body = this.visitBody(this.bodyOf(stmt));
392
+ this.cfc.pop();
393
+ if (body) {
394
+ this.builder.edge(header, body.entry, 'cond-true');
395
+ this.builder.connect(body.exits, header, 'loop-back');
396
+ }
397
+ else {
398
+ this.builder.edge(header, header, 'loop-back'); // empty body re-tests
399
+ }
400
+ // Structural exit edge — even `while true {}` keeps EXIT reverse-reachable.
401
+ this.builder.edge(header, loopExit, 'cond-false');
402
+ return { entry: header, exits: [loopExit] };
403
+ }
404
+ /**
405
+ * `for PAT in ITER { … }`. The header binds the loop pattern (a def) and uses
406
+ * the iterated expression. Standard loop topology.
407
+ */
408
+ visitFor(stmt) {
409
+ const labels = this.loopLabels(stmt);
410
+ const value = stmt.childForFieldName('value');
411
+ const headEnd = value ? endLineOf(value) : startLineOf(stmt);
412
+ const header = this.builder.newBlock(startLineOf(stmt), headEnd, this.forHeaderText(stmt), 'normal', this.harvest.forHeadFacts(stmt));
413
+ const loopExit = this.builder.newBlock(endLineOf(stmt), endLineOf(stmt), '');
414
+ this.cfc.pushLoop(header, loopExit, labels);
415
+ const body = this.visitBody(this.bodyOf(stmt));
416
+ this.cfc.pop();
417
+ if (body) {
418
+ this.builder.edge(header, body.entry, 'cond-true');
419
+ this.builder.connect(body.exits, header, 'loop-back');
420
+ }
421
+ else {
422
+ this.builder.edge(header, header, 'loop-back'); // empty body re-iterates
423
+ }
424
+ this.builder.edge(header, loopExit, 'cond-false');
425
+ return { entry: header, exits: [loopExit] };
426
+ }
427
+ forHeaderText(stmt) {
428
+ const pat = stmt.childForFieldName('pattern')?.text ?? '';
429
+ const value = stmt.childForFieldName('value')?.text ?? '';
430
+ return pat || value ? `for ${pat} in ${value}` : 'for';
431
+ }
432
+ /**
433
+ * `match VALUE { PAT [if guard] => ARM, … }`. Arms do NOT fall through (like
434
+ * Go / Python). Each arm body is dispatched from the subject block with a
435
+ * `switch-case` edge; arm bodies rejoin AFTER the match. A `match` with no
436
+ * irrefutable `_` arm also reaches the join directly (no-match path), keeping
437
+ * EXIT reverse-reachable.
438
+ */
439
+ visitMatch(stmt) {
440
+ const value = stmt.childForFieldName('value');
441
+ const dispatch = this.builder.newBlock(startLineOf(stmt), value ? endLineOf(value) : startLineOf(stmt), value ? `match ${value.text}` : 'match', 'normal', value ? this.harvest.facts(value) : undefined);
442
+ if (value)
443
+ this.wireTryExits(value, dispatch);
444
+ const matchExit = this.builder.newBlock(endLineOf(stmt), endLineOf(stmt), '');
445
+ const body = stmt.childForFieldName('body') ?? stmt.namedChildren.find((c) => c.type === 'match_block');
446
+ const arms = body ? body.namedChildren.filter((c) => c.type === 'match_arm') : [];
447
+ // Each arm's pattern bindings (`Some(n) =>`) are MAY-defs from the matched
448
+ // subject, and a guarded arm (`PAT if g`) evaluates `g` conditionally — both
449
+ // are harvested onto the dispatch block (co-located with the subject's use, so
450
+ // a tainted subject reaches the binding), as may-defs (a later arm binds/tests
451
+ // only when earlier ones didn't match). #2206.
452
+ for (const arm of arms) {
453
+ const patFacts = this.harvest.matchArmPatternFacts(arm);
454
+ if (patFacts)
455
+ this.builder.attachFacts(dispatch, patFacts);
456
+ const guard = this.armGuard(arm);
457
+ if (guard)
458
+ this.builder.attachFacts(dispatch, this.harvest.factsConditional(guard));
459
+ }
460
+ this.cfc.pushSwitch(matchExit, []);
461
+ let hasIrrefutable = false;
462
+ for (const arm of arms) {
463
+ // The arm body may be an expr or block; its pattern bindings were harvested
464
+ // onto the dispatch above (#2206).
465
+ const armBody = this.visitBody(arm.childForFieldName('value'));
466
+ const entry = armBody?.entry ?? matchExit;
467
+ this.builder.edge(dispatch, entry, 'switch-case');
468
+ if (armBody)
469
+ this.builder.connect(armBody.exits, matchExit, 'seq');
470
+ if (this.isIrrefutableArm(arm))
471
+ hasIrrefutable = true;
472
+ }
473
+ this.cfc.pop();
474
+ // No catch-all arm → a no-match path reaches the exit directly. (A real Rust
475
+ // match is exhaustive, but a non-`_`-tailed match keeps EXIT reverse-reachable
476
+ // even when every arm body jumps.)
477
+ if (!hasIrrefutable)
478
+ this.builder.edge(dispatch, matchExit, 'switch-case');
479
+ return { entry: dispatch, exits: [matchExit] };
480
+ }
481
+ /** The guard condition of a `match_arm` (`PAT if g`), if any. */
482
+ armGuard(arm) {
483
+ const pat = arm.childForFieldName('pattern');
484
+ return pat?.childForFieldName('condition') ?? undefined;
485
+ }
486
+ /** A `_ =>` arm with no guard is the unconditional catch-all. */
487
+ isIrrefutableArm(arm) {
488
+ if (this.armGuard(arm))
489
+ return false;
490
+ const pat = arm.childForFieldName('pattern');
491
+ return pat?.text.trim() === '_';
492
+ }
493
+ /**
494
+ * Def/use facts for an `if`/`while` condition. A `let_condition` binds a pattern
495
+ * (a def — a may-def for `while let`, which re-tests) and uses its value; a
496
+ * `let_chain` threads through each `let_condition`. A plain expression is walked
497
+ * for uses.
498
+ */
499
+ condFacts(cond, loopCond) {
500
+ if (cond.type === 'let_condition') {
501
+ return this.harvest.letConditionFacts(cond, loopCond);
502
+ }
503
+ // A `let_chain` (`let PAT = e && cond`) — harvest the whole chain. The let
504
+ // bindings inside it are defs (may-defs for a while-let chain).
505
+ return this.harvest.facts(cond);
506
+ }
507
+ }
508
+ /** Build the CFG for one Rust function / closure node, or `undefined`. */
509
+ function buildFunctionCfg(fnNode, filePath) {
510
+ try {
511
+ if (!RUST_FUNCTION_TYPES.has(fnNode.type))
512
+ return undefined;
513
+ const startLine = startLineOf(fnNode);
514
+ const endLine = endLineOf(fnNode);
515
+ const startColumn = fnNode.startPosition.column;
516
+ const body = fnNode.childForFieldName('body');
517
+ if (!body)
518
+ return undefined; // trait method signature / no body
519
+ const builder = new CfgBuilder(filePath, startLine, endLine, startColumn);
520
+ const harvest = new RustHarvester(fnNode);
521
+ const paramFacts = harvest.paramFacts();
522
+ if (paramFacts)
523
+ builder.attachFacts(builder.entryIndex, paramFacts);
524
+ const walk = new RustCfgWalk(builder, harvest);
525
+ if (body.type !== 'block') {
526
+ // A closure with an expression body (`|x| x + 1`): one block whose value is
527
+ // the returned expression. A `?` inside it early-returns to EXIT.
528
+ const res = walk.visitStmt(body);
529
+ builder.edge(builder.entryIndex, res ? res.entry : builder.exitIndex, 'seq');
530
+ builder.connect(res ? res.exits : [builder.entryIndex], builder.exitIndex, 'seq');
531
+ return builder.finish(harvest.bindingTable());
532
+ }
533
+ const res = walk.visitSeq(body.namedChildren.filter(isNotComment));
534
+ if (!res) {
535
+ builder.edge(builder.entryIndex, builder.exitIndex, 'seq'); // empty body
536
+ return builder.finish(harvest.bindingTable());
537
+ }
538
+ builder.edge(builder.entryIndex, res.entry, 'seq');
539
+ builder.connect(res.exits, builder.exitIndex, 'seq'); // normal fall-off → EXIT
540
+ return builder.finish(harvest.bindingTable());
541
+ }
542
+ catch (err) {
543
+ // Never throw out of buildFunctionCfg — a malformed AST shape must skip only
544
+ // this one function's CFG, never drop the whole file's language group (R4).
545
+ // eslint-disable-next-line no-console
546
+ console.warn(`[cfg] Rust buildFunctionCfg skipped a function in ${filePath}: ${String(err)}`);
547
+ return undefined;
548
+ }
549
+ }
550
+ /** Whether a node is a Rust function/closure this visitor builds a CFG for. */
551
+ function isFunction(node) {
552
+ return RUST_FUNCTION_TYPES.has(node.type);
553
+ }
554
+ /** The Rust CFG visitor. */
555
+ export function createRustCfgVisitor() {
556
+ return { buildFunctionCfg, isFunction };
557
+ }
558
+ export { RUST_FUNCTION_TYPES };