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,103 @@
1
+ /**
2
+ * Python CfgVisitor — the most STRUCTURALLY DIVERGENT CFG target (PDG layer
3
+ * beyond the C-family). Python has no braces (suites are indented `block` nodes),
4
+ * `elif` clauses, `for`/`while ... else` (the else runs on NORMAL completion, not
5
+ * on `break`), `with` (deterministic `__exit__` on both normal AND exception
6
+ * exit — a try/finally analogue), `try` / `except` / `except-group` (except-star)
7
+ * / `else` / `finally`, and `match`/`case` (no fallthrough). A good stress test
8
+ * that the shared CFG core
9
+ * carries no hidden brace-family assumptions.
10
+ *
11
+ * Walks a Python `function_definition` / `lambda`'s tree-sitter AST and drives
12
+ * the language-agnostic {@link CfgBuilder} to produce a serializable
13
+ * {@link FunctionCfg}, plus a def/use harvest ({@link PythonHarvester}) for the
14
+ * reaching-defs / CDG solvers. Structured like the C-family visitors — a
15
+ * `visit_<node_type>` dispatch over the statement taxonomy, driving a
16
+ * per-function {@link ControlFlowContext} for break/continue and the `with` /
17
+ * `finally` completion chain (finalizer route-through). NO call-site `sites[]`
18
+ * are harvested (taint substrate is a later step — see python-harvest.ts).
19
+ *
20
+ * Every node type and field literal below was grammar-validated against
21
+ * tree-sitter-python (0.23.x) via the introspection probe before use (mandatory
22
+ * pre-step). Python shapes pre-empted (verified by a real parse):
23
+ * - functions: `function_definition` (fields `name`/`parameters`/`body`; async
24
+ * is the SAME node with an `async` token child), `lambda` (fields
25
+ * `parameters`/`body`; the body is an EXPRESSION, not a `block`).
26
+ * - `if_statement` fields `condition`/`consequence` plus ZERO-OR-MORE
27
+ * `alternative` fields, each an `elif_clause` (fields `condition`/`consequence`)
28
+ * or an `else_clause` (field `body`) — Python has no nested-`if` else chain.
29
+ * - `for_statement` fields `left`/`right`/`body` + optional `alternative`
30
+ * (`else_clause`); `while_statement` fields `condition`/`body` + optional
31
+ * `alternative` (`else_clause`). The loop `else` runs on the cond-false /
32
+ * normal-completion path, NOT on `break`.
33
+ * - `with_statement` field `body`; a `with_clause` of `with_item`s (field
34
+ * `value` = `as_pattern` or a bare expression). `__exit__` runs on normal AND
35
+ * exception exit — modeled as a finalizer (try/finally analogue).
36
+ * - `try_statement` field `body`; children `except_clause` /
37
+ * `except_group_clause` (each holds the exception expr/`as_pattern` + a
38
+ * `block`), `else_clause` (field `body`, runs if NO exception), and
39
+ * `finally_clause` (holds a `block`).
40
+ * - `match_statement` fields `subject`/`body`; the `body` `block` holds
41
+ * `case_clause`s (field `alternative`), each with `case_pattern` child(ren),
42
+ * an optional `guard` (`if_clause`), and a `consequence` `block`. No
43
+ * fallthrough between cases.
44
+ * - `return_statement` / `raise_statement` / `break_statement` /
45
+ * `continue_statement` / `pass_statement`.
46
+ *
47
+ * Edge-kind contract (matches the existing visitors — RD/CDG consume these):
48
+ * - if/elif/else → `cond-true` / `cond-false`
49
+ * - for/while → `cond-true` / `loop-back` / `cond-false`; the loop `else` runs
50
+ * on the `cond-false` / normal-completion path (NOT on `break`)
51
+ * - match dispatch → `switch-case` (no fallthrough — like Go's switch)
52
+ * - try/except → `throw` (every protected block → each except handler)
53
+ * - a `break`/`continue`/`return` crossing a `with` `__exit__` or a `finally`
54
+ * threads through as `break`/`continue`/`return` (first leg) +
55
+ * `finally-break`/`finally-continue`/`finally-return` (each completion leg)
56
+ * - return/raise/break/continue → the matching terminator kind
57
+ * - straight-line → `seq`
58
+ *
59
+ * Python-specific modeling decisions (documented approximations):
60
+ * - `with EXPR as t:` runs the body then `__exit__` deterministically on BOTH
61
+ * the normal exit and an exception (it can suppress the exception, but the
62
+ * common case re-raises). Modeled exactly like `try/finally`: a finalizer
63
+ * frame for the body's exit-dispose, with the protected body edging the
64
+ * dispose block on `throw`. APPROXIMATION: exception SUPPRESSION by a context
65
+ * manager is not modeled (the dispose re-propagates), the sound direction.
66
+ * - the loop `else` clause runs once on normal completion (the loop ran to
67
+ * exhaustion without `break`). It sits on the `cond-false` edge BEFORE the
68
+ * join; a `break` targets the loop exit AFTER the else, so `break` skips it.
69
+ * - `match`/`case` cases do NOT fall through (like Go). The dispatch fans a
70
+ * `switch-case` edge to each case body; a guarded / non-wildcard tail with no
71
+ * `case _` also reaches the join directly (no-match path), keeping EXIT
72
+ * reverse-reachable.
73
+ * - `while True:` (and any loop with no statically-false exit) STILL emits the
74
+ * structural `header → loopExit` `cond-false` edge — exactly like the
75
+ * C-family visitors — so EXIT stays reverse-reachable and the post-dominator /
76
+ * CDG pass is not silently skipped for the function. Highest-risk property.
77
+ * - `lambda` has an EXPRESSION body (no `block`): one block whose value is the
78
+ * returned expression.
79
+ * - comprehensions are harvested for their target bindings but kept INLINE (no
80
+ * separate CFG blocks) — the plan's explicit choice.
81
+ *
82
+ * Known limitations:
83
+ * - async (`async def`, `await`, `async for`, `async with`) is the same node
84
+ * shape as the sync form plus an `async` token; the suspension points are
85
+ * modeled as normal straight-line control flow (no scheduler edges).
86
+ * - generators (`yield` / `yield from`): a `yield` is a normal expression here
87
+ * (no suspend/resume edge); the generator's resumption flow is not modeled.
88
+ * - comprehension target scoping: comprehension targets are declared in the
89
+ * single function table (Python 3 gives them their own scope; the leaked-name
90
+ * distinction is not modeled) — see python-harvest.ts.
91
+ * - context-manager exception SUPPRESSION and `recover`-style flow are not
92
+ * modeled (the `with` dispose always re-propagates).
93
+ *
94
+ * Returns `undefined` (never throws) for an AST shape it cannot model, so a
95
+ * malformed function never drops the whole file's CFG group (R4).
96
+ */
97
+ import type { SyntaxNode } from '../../utils/ast-helpers.js';
98
+ import type { CfgVisitor } from '../types.js';
99
+ /** Python node types that own a CFG-bearing function body. */
100
+ declare const PY_FUNCTION_TYPES: Set<string>;
101
+ /** The Python CFG visitor. */
102
+ export declare function createPythonCfgVisitor(): CfgVisitor<SyntaxNode>;
103
+ export { PY_FUNCTION_TYPES };
@@ -0,0 +1,558 @@
1
+ import { CfgBuilder } from '../cfg-builder.js';
2
+ import { ControlFlowContext, drainFinalizerPending, wireJumpThroughFinalizers, } from '../control-flow-context.js';
3
+ import { PythonHarvester } from './python-harvest.js';
4
+ /** Python node types that own a CFG-bearing function body. */
5
+ const PY_FUNCTION_TYPES = new Set(['function_definition', 'lambda']);
6
+ /** Statement node types that break a basic block (everything else coalesces). */
7
+ const CONTROL_FLOW_TYPES = new Set([
8
+ 'if_statement',
9
+ 'for_statement',
10
+ 'while_statement',
11
+ 'with_statement',
12
+ 'try_statement',
13
+ 'match_statement',
14
+ 'return_statement',
15
+ 'raise_statement',
16
+ 'break_statement',
17
+ 'continue_statement',
18
+ 'block',
19
+ ]);
20
+ const startLineOf = (n) => n.startPosition.row + 1;
21
+ const endLineOf = (n) => n.endPosition.row + 1;
22
+ /**
23
+ * Per-function Python walk state. One instance per function so the
24
+ * {@link ControlFlowContext}, the exception-handler stack, and the `with` /
25
+ * `finally` finalizer chain are scoped to that function and never leak across
26
+ * functions.
27
+ */
28
+ class PythonCfgWalk {
29
+ builder;
30
+ harvest;
31
+ cfc = new ControlFlowContext();
32
+ /** Stack of exception-handler entry blocks (except/finally/with-dispose) a `raise` jumps to. */
33
+ handlers = [];
34
+ constructor(builder, harvest) {
35
+ this.builder = builder;
36
+ this.harvest = harvest;
37
+ }
38
+ /** Statements of a block node, ignoring comments. */
39
+ statementsOf(block) {
40
+ return block.namedChildren.filter((c) => c.type !== 'comment');
41
+ }
42
+ /** The `body` block of a node (field, or the first `block` child). */
43
+ bodyBlockOf(node) {
44
+ return node.childForFieldName('body') ?? node.namedChildren.find((c) => c.type === 'block');
45
+ }
46
+ /** Visit a body that may be a `block` or a single statement. */
47
+ visitBody(node) {
48
+ return this.builder.withNesting(() => {
49
+ if (!node)
50
+ return null;
51
+ if (node.type === 'block')
52
+ return this.visitSeq(this.statementsOf(node));
53
+ return this.visitStmt(node);
54
+ });
55
+ }
56
+ /** Wire a sequence of statements, coalescing straight-line runs into blocks. */
57
+ visitSeq(stmts) {
58
+ return this.builder.withNesting(() => {
59
+ let entry;
60
+ let dangling = [];
61
+ let openSimple;
62
+ for (const stmt of stmts) {
63
+ if (CONTROL_FLOW_TYPES.has(stmt.type)) {
64
+ openSimple = undefined; // close any open straight-line block
65
+ const res = this.visitStmt(stmt);
66
+ if (res === null)
67
+ continue; // transparent (empty nested block)
68
+ if (entry === undefined)
69
+ entry = res.entry;
70
+ else
71
+ this.builder.connect(dangling, res.entry, 'seq');
72
+ dangling = [...res.exits];
73
+ }
74
+ else {
75
+ if (openSimple === undefined) {
76
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text, 'normal', this.harvest.facts(stmt));
77
+ if (entry === undefined)
78
+ entry = idx;
79
+ else
80
+ this.builder.connect(dangling, idx, 'seq');
81
+ openSimple = idx;
82
+ dangling = [idx];
83
+ }
84
+ else {
85
+ this.builder.extendBlock(openSimple, endLineOf(stmt), stmt.text, this.harvest.facts(stmt));
86
+ }
87
+ }
88
+ }
89
+ if (entry === undefined)
90
+ return null;
91
+ return { entry, exits: dangling };
92
+ });
93
+ }
94
+ /** Dispatch one statement to its handler. Non-null except for empty blocks. */
95
+ visitStmt(stmt) {
96
+ switch (stmt.type) {
97
+ case 'if_statement':
98
+ return this.visitIf(stmt);
99
+ case 'for_statement':
100
+ return this.visitFor(stmt);
101
+ case 'while_statement':
102
+ return this.visitWhile(stmt);
103
+ case 'with_statement':
104
+ return this.visitWith(stmt);
105
+ case 'try_statement':
106
+ return this.visitTry(stmt);
107
+ case 'match_statement':
108
+ return this.visitMatch(stmt);
109
+ case 'return_statement':
110
+ return this.visitReturn(stmt);
111
+ case 'raise_statement':
112
+ return this.visitRaise(stmt);
113
+ case 'break_statement':
114
+ return this.visitBreak(stmt);
115
+ case 'continue_statement':
116
+ return this.visitContinue(stmt);
117
+ case 'block':
118
+ return this.visitSeq(this.statementsOf(stmt));
119
+ default:
120
+ return this.visitSimple(stmt);
121
+ }
122
+ }
123
+ visitSimple(stmt) {
124
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text, 'normal', this.harvest.facts(stmt));
125
+ return { entry: idx, exits: [idx] };
126
+ }
127
+ /** `return [expr]` — threads through EVERY active `with`/`finally` before EXIT. */
128
+ visitReturn(stmt) {
129
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text, 'normal', this.harvest.facts(stmt));
130
+ wireJumpThroughFinalizers(this.builder, idx, this.cfc.finalizersForReturn(), this.builder.exitIndex, 'return');
131
+ return { entry: idx, exits: [] };
132
+ }
133
+ /** `raise [expr]` — jumps to the nearest handler (except / with-dispose / EXIT). */
134
+ visitRaise(stmt) {
135
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text, 'normal', this.harvest.facts(stmt));
136
+ this.builder.edge(idx, this.currentHandler(), 'throw');
137
+ return { entry: idx, exits: [] };
138
+ }
139
+ visitBreak(stmt) {
140
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text);
141
+ const res = this.cfc.resolveBreak();
142
+ const { target, finalizers } = res ?? {
143
+ target: this.builder.exitIndex,
144
+ finalizers: this.cfc.finalizersForReturn(),
145
+ };
146
+ wireJumpThroughFinalizers(this.builder, idx, finalizers, target, 'break');
147
+ return { entry: idx, exits: [] };
148
+ }
149
+ visitContinue(stmt) {
150
+ const idx = this.builder.newBlock(startLineOf(stmt), endLineOf(stmt), stmt.text);
151
+ const res = this.cfc.resolveContinue();
152
+ const { target, finalizers } = res ?? {
153
+ target: this.builder.exitIndex,
154
+ finalizers: this.cfc.finalizersForReturn(),
155
+ };
156
+ wireJumpThroughFinalizers(this.builder, idx, finalizers, target, 'continue');
157
+ return { entry: idx, exits: [] };
158
+ }
159
+ /**
160
+ * `if cond: … elif cond: … else: …`. Python has NO nested-if else chain: an
161
+ * `if_statement` carries the condition + consequence plus zero-or-more
162
+ * `alternative` fields, each an `elif_clause` (its own condition + consequence)
163
+ * or a single trailing `else_clause`. The elif chain is threaded on the
164
+ * `cond-false` edge.
165
+ */
166
+ visitIf(stmt) {
167
+ const cond = stmt.childForFieldName('condition') ?? stmt;
168
+ const header = this.builder.newBlock(startLineOf(stmt), endLineOf(cond), cond.text, 'normal', this.harvest.facts(cond));
169
+ const exits = [];
170
+ const thenRes = this.visitBody(stmt.childForFieldName('consequence'));
171
+ if (thenRes) {
172
+ this.builder.edge(header, thenRes.entry, 'cond-true');
173
+ exits.push(...thenRes.exits);
174
+ }
175
+ else {
176
+ exits.push(header); // empty then — true path falls through
177
+ }
178
+ // The alternatives, in source order: elif_clause* then optional else_clause.
179
+ const alternatives = this.alternativesOf(stmt);
180
+ let falseFrom = header; // block whose cond-false edge feeds the next alternative
181
+ for (const alt of alternatives) {
182
+ if (alt.type === 'elif_clause') {
183
+ const elifCond = alt.childForFieldName('condition') ?? alt;
184
+ const elifHeader = this.builder.newBlock(startLineOf(alt), endLineOf(elifCond), elifCond.text, 'normal', this.harvest.facts(elifCond));
185
+ this.builder.edge(falseFrom, elifHeader, 'cond-false');
186
+ const elifRes = this.visitBody(alt.childForFieldName('consequence'));
187
+ if (elifRes) {
188
+ this.builder.edge(elifHeader, elifRes.entry, 'cond-true');
189
+ exits.push(...elifRes.exits);
190
+ }
191
+ else {
192
+ exits.push(elifHeader);
193
+ }
194
+ falseFrom = elifHeader;
195
+ }
196
+ else if (alt.type === 'else_clause') {
197
+ const elseRes = this.visitBody(alt.childForFieldName('body'));
198
+ if (elseRes) {
199
+ this.builder.edge(falseFrom, elseRes.entry, 'cond-false');
200
+ exits.push(...elseRes.exits);
201
+ }
202
+ else {
203
+ exits.push(falseFrom);
204
+ }
205
+ falseFrom = -1; // an else consumes the false path entirely
206
+ }
207
+ }
208
+ // No trailing else: the last header's cond-false falls through to the join.
209
+ if (falseFrom >= 0)
210
+ exits.push(falseFrom);
211
+ return { entry: header, exits: [...new Set(exits)] };
212
+ }
213
+ /** The `alternative`-field children of an `if_statement`, in source order. */
214
+ alternativesOf(stmt) {
215
+ const out = [];
216
+ for (let i = 0; i < stmt.childCount; i++) {
217
+ if (stmt.fieldNameForChild(i) === 'alternative') {
218
+ const c = stmt.child(i);
219
+ if (c)
220
+ out.push(c);
221
+ }
222
+ }
223
+ return out;
224
+ }
225
+ /**
226
+ * `for TARGET in ITER: … [else: …]`. Header = the iteration test (a use of the
227
+ * iterable + a def of the target). The loop `else` runs on NORMAL completion
228
+ * (the cond-false path) — a `break` targets the loop exit AFTER the else, so it
229
+ * skips the else.
230
+ */
231
+ visitFor(stmt) {
232
+ const left = stmt.childForFieldName('left');
233
+ const right = stmt.childForFieldName('right');
234
+ const headEnd = right ? endLineOf(right) : startLineOf(stmt);
235
+ const header = this.builder.newBlock(startLineOf(stmt), headEnd, this.loopHeaderText(stmt, left, right), 'normal', this.harvest.loopHeadFacts(stmt));
236
+ const loopExit = this.builder.newBlock(endLineOf(stmt), endLineOf(stmt), '');
237
+ this.cfc.pushLoop(header, loopExit, []);
238
+ const body = this.visitBody(this.bodyBlockOf(stmt));
239
+ this.cfc.pop();
240
+ if (body) {
241
+ this.builder.edge(header, body.entry, 'cond-true');
242
+ this.builder.connect(body.exits, header, 'loop-back');
243
+ }
244
+ else {
245
+ this.builder.edge(header, header, 'loop-back'); // empty body re-tests
246
+ }
247
+ this.wireLoopElse(stmt, header, loopExit);
248
+ return { entry: header, exits: [loopExit] };
249
+ }
250
+ /** `while cond: … [else: …]`. Same `else`-on-normal-completion semantics as `for`. */
251
+ visitWhile(stmt) {
252
+ const cond = stmt.childForFieldName('condition') ?? stmt;
253
+ const header = this.builder.newBlock(startLineOf(stmt), endLineOf(cond), cond.text, 'normal', this.harvest.facts(cond));
254
+ const loopExit = this.builder.newBlock(endLineOf(stmt), endLineOf(stmt), '');
255
+ this.cfc.pushLoop(header, loopExit, []);
256
+ const body = this.visitBody(this.bodyBlockOf(stmt));
257
+ this.cfc.pop();
258
+ if (body) {
259
+ this.builder.edge(header, body.entry, 'cond-true');
260
+ this.builder.connect(body.exits, header, 'loop-back');
261
+ }
262
+ else {
263
+ this.builder.edge(header, header, 'loop-back'); // empty `while c: pass` re-tests
264
+ }
265
+ this.wireLoopElse(stmt, header, loopExit);
266
+ return { entry: header, exits: [loopExit] };
267
+ }
268
+ /**
269
+ * Wire the optional loop `else` clause. The else runs once on normal completion
270
+ * (the header's `cond-false` edge). With an else, the cond-false edge goes
271
+ * `header → elseEntry` and the else's exits reach `loopExit`; without one, the
272
+ * structural `header → loopExit` `cond-false` edge keeps EXIT reverse-reachable
273
+ * (critical for `while True:` — and matches the C-family visitors). A `break`
274
+ * always targets `loopExit` directly, so it never runs the else.
275
+ */
276
+ wireLoopElse(stmt, header, loopExit) {
277
+ const elseClause = this.loopElseOf(stmt);
278
+ if (elseClause) {
279
+ const elseRes = this.visitBody(elseClause.childForFieldName('body'));
280
+ if (elseRes) {
281
+ this.builder.edge(header, elseRes.entry, 'cond-false');
282
+ this.builder.connect(elseRes.exits, loopExit, 'seq');
283
+ return;
284
+ }
285
+ }
286
+ // No (or empty) else — normal completion falls straight to the loop exit.
287
+ this.builder.edge(header, loopExit, 'cond-false');
288
+ }
289
+ /** The `else_clause` of a `for`/`while` (its `alternative` field), if any. */
290
+ loopElseOf(stmt) {
291
+ const alt = stmt.childForFieldName('alternative');
292
+ return alt?.type === 'else_clause' ? alt : undefined;
293
+ }
294
+ loopHeaderText(stmt, left, right) {
295
+ const l = left?.text ?? '';
296
+ const r = right?.text ?? '';
297
+ return l || r ? `for ${l} in ${r}` : stmt.text.split('\n')[0];
298
+ }
299
+ /**
300
+ * `with EXPR [as t], …: BODY`. The context managers' `__exit__` runs
301
+ * deterministically on BOTH the normal exit and an exception — modeled exactly
302
+ * like `try/finally`: a finalizer frame holding the dispose block, plus a
303
+ * `throw` edge from every protected-body block to the dispose. A
304
+ * `return`/`break`/`continue` inside the body threads through the dispose. The
305
+ * dispose re-propagates on the exception path (suppression is not modeled).
306
+ */
307
+ visitWith(stmt) {
308
+ // The dispose block carries the `with`-header facts (the `as` aliases are
309
+ // defs, the manager expressions uses) — it runs on every exit, so attaching
310
+ // the binding facts here is the single execution point of the bindings.
311
+ const items = this.withItems(stmt);
312
+ const dispose = this.builder.newBlock(startLineOf(stmt), startLineOf(stmt), this.withHeaderText(stmt));
313
+ for (const item of items)
314
+ this.builder.attachFacts(dispose, this.harvest.withItemFacts(item));
315
+ const finFrame = this.cfc.pushFinalizer(dispose);
316
+ // The body raises into the dispose (which re-propagates to the outer handler).
317
+ this.handlers.push(dispose);
318
+ const protectedStart = this.builder.blockCount;
319
+ const body = this.visitBody(this.bodyBlockOf(stmt));
320
+ this.handlers.pop();
321
+ // Conservative exceptional edges: ANY block in the with-body may raise to the
322
+ // dispose (an exception fires mid-block) — sound over-approximation.
323
+ for (let b = protectedStart; b < this.builder.blockCount; b++) {
324
+ this.builder.edge(b, dispose, 'throw');
325
+ }
326
+ this.cfc.pop();
327
+ drainFinalizerPending(this.builder, finFrame, [dispose]);
328
+ // Normal completion of the body flows into the dispose; the dispose's normal
329
+ // exit is the with-statement's exit. The dispose re-propagates the exception
330
+ // path to the OUTER handler (a CM normally re-raises).
331
+ if (body)
332
+ this.builder.connect(body.exits, dispose, 'seq');
333
+ this.builder.edge(dispose, this.currentHandler(), 'throw');
334
+ const entry = body?.entry ?? dispose;
335
+ return { entry, exits: [dispose] };
336
+ }
337
+ /** The `with_item`s of a `with_statement` (under its `with_clause`). */
338
+ withItems(stmt) {
339
+ const clause = stmt.namedChildren.find((c) => c.type === 'with_clause');
340
+ if (!clause)
341
+ return [];
342
+ return clause.namedChildren.filter((c) => c.type === 'with_item');
343
+ }
344
+ withHeaderText(stmt) {
345
+ const clause = stmt.namedChildren.find((c) => c.type === 'with_clause');
346
+ return clause ? `with ${clause.text}` : 'with';
347
+ }
348
+ /**
349
+ * `try: BODY [except …: H]* [else: E] [finally: F]`. Mirrors the TS visitor's
350
+ * try-route-through:
351
+ * - `finally` runs on every exit (normal, exception, and early jumps) — a
352
+ * finalizer frame for early-exit threading + a normal/exceptional join.
353
+ * - each `except` / except-group handler catches from the protected body.
354
+ * - `else` runs only if the body completed with no exception.
355
+ */
356
+ visitTry(stmt) {
357
+ const bodyNode = stmt.childForFieldName('body');
358
+ const exceptClauses = [];
359
+ let elseClause;
360
+ let finallyClause;
361
+ for (let i = 0; i < stmt.namedChildCount; i++) {
362
+ const c = stmt.namedChild(i);
363
+ if (!c)
364
+ continue;
365
+ if (c.type === 'except_clause' || c.type === 'except_group_clause')
366
+ exceptClauses.push(c);
367
+ else if (c.type === 'else_clause')
368
+ elseClause = c;
369
+ else if (c.type === 'finally_clause')
370
+ finallyClause = c;
371
+ }
372
+ // Build finally first — known as both a normal join and a handler target. It
373
+ // runs OUTSIDE this try's finalizer frame (a return inside finally threads
374
+ // only OUTER finallys).
375
+ const finallyBlock = finallyClause
376
+ ? (this.bodyBlockOf(finallyClause) ??
377
+ finallyClause.namedChildren.find((c) => c.type === 'block'))
378
+ : undefined;
379
+ const finallyRes = finallyBlock ? this.visitSeq(this.statementsOf(finallyBlock)) : null;
380
+ const finFrame = finallyRes ? this.cfc.pushFinalizer(finallyRes.entry) : null;
381
+ // Each except handler. A `raise` inside a handler propagates to finally (if
382
+ // any), else the outer handler.
383
+ const handlerEntries = [];
384
+ const handlerExits = [];
385
+ for (const clause of exceptClauses) {
386
+ if (finallyRes)
387
+ this.handlers.push(finallyRes.entry);
388
+ const handlerBlock = clause.namedChildren.find((c) => c.type === 'block');
389
+ // The `except E as e:` header binds `e` — its own facts-only block in front
390
+ // of the handler body (the binding happens once, on handler entry).
391
+ const headFacts = this.harvest.exceptHeadFacts(clause);
392
+ const headBlock = this.builder.newBlock(startLineOf(clause), startLineOf(clause), '', 'normal', headFacts);
393
+ const bodyRes = handlerBlock ? this.visitSeq(this.statementsOf(handlerBlock)) : null;
394
+ if (bodyRes) {
395
+ this.builder.edge(headBlock, bodyRes.entry, 'seq');
396
+ handlerExits.push(...bodyRes.exits);
397
+ }
398
+ else {
399
+ handlerExits.push(headBlock); // empty handler body — header is the exit
400
+ }
401
+ handlerEntries.push(headBlock);
402
+ if (finallyRes)
403
+ this.handlers.pop();
404
+ }
405
+ // Handler for the try body: the first except if present, else finally, else
406
+ // the outer handler.
407
+ const tryHandler = handlerEntries[0] ?? finallyRes?.entry ?? this.currentHandler();
408
+ const protectedStart = this.builder.blockCount;
409
+ this.handlers.push(tryHandler);
410
+ const bodyRes = bodyNode ? this.visitSeq(this.statementsOf(bodyNode)) : null;
411
+ this.handlers.pop();
412
+ // Conservative exceptional edges: ANY protected-region block may raise to
413
+ // EACH handler (an unmatched exception type tries the next handler).
414
+ if (exceptClauses.length > 0 || finallyClause) {
415
+ const targets = handlerEntries.length > 0 ? handlerEntries : finallyRes ? [finallyRes.entry] : [];
416
+ for (let b = protectedStart; b < this.builder.blockCount; b++) {
417
+ for (const h of targets)
418
+ this.builder.edge(b, h, 'throw');
419
+ }
420
+ }
421
+ // The `else` runs only on no-exception normal completion of the body.
422
+ let normalAfterBody = bodyRes ? [...bodyRes.exits] : [];
423
+ if (elseClause) {
424
+ const elseRes = this.visitBody(elseClause.childForFieldName('body'));
425
+ if (elseRes && bodyRes) {
426
+ this.builder.connect(bodyRes.exits, elseRes.entry, 'seq');
427
+ normalAfterBody = [...elseRes.exits];
428
+ }
429
+ else if (elseRes) {
430
+ normalAfterBody = [...elseRes.exits];
431
+ }
432
+ }
433
+ // Close the finalizer frame; wire crossing-jump completion legs.
434
+ if (finFrame && finallyRes) {
435
+ this.cfc.pop();
436
+ drainFinalizerPending(this.builder, finFrame, finallyRes.exits);
437
+ }
438
+ const exits = [];
439
+ if (finallyRes) {
440
+ // Normal completion of (body→else) AND each handler flows through finally.
441
+ this.builder.connect(normalAfterBody, finallyRes.entry, 'seq');
442
+ this.builder.connect(handlerExits, finallyRes.entry, 'seq');
443
+ exits.push(...finallyRes.exits);
444
+ // A try with no except → an uncaught exception re-propagates after finally.
445
+ if (handlerEntries.length === 0) {
446
+ this.builder.connect(finallyRes.exits, this.currentHandler(), 'throw');
447
+ }
448
+ }
449
+ else {
450
+ exits.push(...normalAfterBody);
451
+ exits.push(...handlerExits);
452
+ }
453
+ const entry = bodyRes?.entry ?? finallyRes?.entry ?? handlerEntries[0];
454
+ if (entry === undefined)
455
+ return null;
456
+ return { entry, exits: [...new Set(exits)] };
457
+ }
458
+ /**
459
+ * `match SUBJECT: case P [if guard]: BODY …`. Cases do NOT fall through (like
460
+ * Go's switch). Each case body is dispatched from the subject block with a
461
+ * `switch-case` edge; a `match` with no `case _` wildcard also reaches the join
462
+ * directly (no-match path), keeping EXIT reverse-reachable.
463
+ */
464
+ visitMatch(stmt) {
465
+ const subject = stmt.childForFieldName('subject');
466
+ const dispatch = this.builder.newBlock(startLineOf(stmt), subject ? endLineOf(subject) : startLineOf(stmt), subject ? `match ${subject.text}` : 'match', 'normal', subject ? this.harvest.facts(subject) : undefined);
467
+ const matchExit = this.builder.newBlock(endLineOf(stmt), endLineOf(stmt), '');
468
+ const body = stmt.childForFieldName('body') ?? stmt.namedChildren.find((c) => c.type === 'block');
469
+ const cases = body ? body.namedChildren.filter((c) => c.type === 'case_clause') : [];
470
+ // A case guard (`case P if g:`) evaluates conditionally — harvest its uses
471
+ // onto the dispatch block (a later case only tests when earlier patterns
472
+ // didn't match; defs there are may-defs).
473
+ for (const c of cases) {
474
+ const guard = c.childForFieldName('guard');
475
+ if (guard)
476
+ this.builder.attachFacts(dispatch, this.harvest.factsConditional(guard));
477
+ }
478
+ this.cfc.pushSwitch(matchExit, []);
479
+ let hasWildcard = false;
480
+ for (const c of cases) {
481
+ const caseBody = this.visitBody(c.childForFieldName('consequence'));
482
+ const entry = caseBody?.entry ?? matchExit;
483
+ this.builder.edge(dispatch, entry, 'switch-case');
484
+ if (caseBody)
485
+ this.builder.connect(caseBody.exits, matchExit, 'seq');
486
+ if (this.isWildcardCase(c))
487
+ hasWildcard = true;
488
+ }
489
+ this.cfc.pop();
490
+ // No catch-all `case _` (or no cases) → a no-match path reaches the exit
491
+ // directly. Keeps EXIT reverse-reachable even when every case body jumps.
492
+ if (!hasWildcard)
493
+ this.builder.edge(dispatch, matchExit, 'switch-case');
494
+ return { entry: dispatch, exits: [matchExit] };
495
+ }
496
+ /** A `case _:` (bare wildcard with no guard) is the unconditional catch-all. */
497
+ isWildcardCase(caseClause) {
498
+ if (caseClause.childForFieldName('guard'))
499
+ return false;
500
+ const pattern = caseClause.namedChildren.find((c) => c.type === 'case_pattern');
501
+ return pattern?.text.trim() === '_';
502
+ }
503
+ /** Nearest enclosing exception handler, or the function EXIT. */
504
+ currentHandler() {
505
+ return this.handlers.length ? this.handlers[this.handlers.length - 1] : this.builder.exitIndex;
506
+ }
507
+ }
508
+ /** Build the CFG for one Python function/lambda node, or `undefined` if not modelable. */
509
+ function buildFunctionCfg(fnNode, filePath) {
510
+ try {
511
+ if (!PY_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; // no body — nothing to model
519
+ const builder = new CfgBuilder(filePath, startLine, endLine, startColumn);
520
+ const harvest = new PythonHarvester(fnNode);
521
+ const paramFacts = harvest.paramFacts();
522
+ if (paramFacts)
523
+ builder.attachFacts(builder.entryIndex, paramFacts);
524
+ if (fnNode.type === 'lambda' || body.type !== 'block') {
525
+ // `lambda x: expr` — the body is an EXPRESSION (no `block`): one block whose
526
+ // value is returned. Threads through no finally (a lambda has none).
527
+ const blk = builder.newBlock(startLineOf(body), endLineOf(body), body.text, 'normal', harvest.facts(body));
528
+ builder.edge(builder.entryIndex, blk, 'seq');
529
+ builder.edge(blk, builder.exitIndex, 'return');
530
+ return builder.finish(harvest.bindingTable());
531
+ }
532
+ const walk = new PythonCfgWalk(builder, harvest);
533
+ const res = walk.visitSeq(body.namedChildren.filter((c) => c.type !== 'comment'));
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] Python buildFunctionCfg skipped a function in ${filePath}: ${String(err)}`);
547
+ return undefined;
548
+ }
549
+ }
550
+ /** Whether a node is a Python function this visitor builds a CFG for. */
551
+ function isFunction(node) {
552
+ return PY_FUNCTION_TYPES.has(node.type);
553
+ }
554
+ /** The Python CFG visitor. */
555
+ export function createPythonCfgVisitor() {
556
+ return { buildFunctionCfg, isFunction };
557
+ }
558
+ export { PY_FUNCTION_TYPES };