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
@@ -97,6 +97,32 @@ export function normalizeExtractedRoutePath(routePath, prefix) {
97
97
  function escapeRegex(s) {
98
98
  return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
99
99
  }
100
+ /**
101
+ * Canonicalize a route's HTTP verb for persistence on the Route node.
102
+ * Returns an upper-cased standard method, or `undefined` when the value
103
+ * is not a real HTTP verb. Laravel `Route::resource` / `apiResource`
104
+ * surface `httpMethod` values like `resource` / `apiResource` (they
105
+ * expand to several verbs at runtime), so they must not be stored as a
106
+ * method — leaving them `undefined` keeps the column clean and lets the
107
+ * contract extractor fall back to its source-scan path for those routes.
108
+ */
109
+ const VALID_HTTP_METHODS = new Set([
110
+ 'GET',
111
+ 'POST',
112
+ 'PUT',
113
+ 'PATCH',
114
+ 'DELETE',
115
+ 'HEAD',
116
+ 'OPTIONS',
117
+ 'TRACE',
118
+ 'CONNECT',
119
+ ]);
120
+ export function normalizeRouteMethod(raw) {
121
+ if (typeof raw !== 'string')
122
+ return undefined;
123
+ const verb = raw.trim().toUpperCase();
124
+ return VALID_HTTP_METHODS.has(verb) ? verb : undefined;
125
+ }
100
126
  export const routesPhase = {
101
127
  name: 'routes',
102
128
  deps: ['parse'],
@@ -166,6 +192,7 @@ export const routesPhase = {
166
192
  addRoute(routeUrl, {
167
193
  filePath: route.filePath,
168
194
  source: 'framework-route',
195
+ method: normalizeRouteMethod(route.httpMethod),
169
196
  });
170
197
  if (route.routeName && !namedRouteRegistry.has(route.routeName)) {
171
198
  namedRouteRegistry.set(route.routeName, routeUrl);
@@ -176,6 +203,7 @@ export const routesPhase = {
176
203
  addRoute(url, {
177
204
  filePath: dr.filePath,
178
205
  source: `decorator-${dr.decoratorName}`,
206
+ method: normalizeRouteMethod(dr.httpMethod),
179
207
  });
180
208
  }
181
209
  let handlerContents;
@@ -183,7 +211,7 @@ export const routesPhase = {
183
211
  const handlerPaths = [...routeRegistry.values()].map((e) => e.filePath);
184
212
  handlerContents = await readFileContents(ctx.repoPath, handlerPaths);
185
213
  for (const [routeURL, entry] of routeRegistry) {
186
- const { filePath: handlerPath, source: routeSource } = entry;
214
+ const { filePath: handlerPath, source: routeSource, method: routeMethod } = entry;
187
215
  const content = handlerContents.get(handlerPath);
188
216
  const { responseKeys, errorKeys } = content
189
217
  ? handlerPath.endsWith('.php')
@@ -199,6 +227,7 @@ export const routesPhase = {
199
227
  properties: {
200
228
  name: routeURL,
201
229
  filePath: handlerPath,
230
+ ...(routeMethod ? { method: routeMethod } : {}),
202
231
  ...(responseKeys ? { responseKeys } : {}),
203
232
  ...(errorKeys ? { errorKeys } : {}),
204
233
  ...(middleware && middleware.length > 0 ? { middleware } : {}),
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Phase: taintSummaries (#2084 M4 U3/U5)
3
+ *
4
+ * The interprocedural taint fixpoint. Runs AFTER scope-resolution (where the
5
+ * complete, resolved `CALLS` graph lives in `ctx.graph` and the per-function
6
+ * summaries were harvested in-phase) and composes those summaries to find
7
+ * source→sink flows that cross function and file boundaries.
8
+ *
9
+ * Opt-in: registered with `enabledWhen: (o) => o.pdg === true` (the first real
10
+ * pdg-gated phase). A default `analyze` run never includes it, so the graph is
11
+ * byte-identical. No always-on phase depends on it (a filtered-out dep would
12
+ * throw in `getPhaseOutput`).
13
+ *
14
+ * @deps scopeResolution, pruneLocalSymbols
15
+ * @reads graph (CALLS edges, Function/Method nodes), scopeResolution output
16
+ * (functionSummaries)
17
+ * @writes graph (TAINT_PATH edges)
18
+ */
19
+ import type { PipelinePhase } from './types.js';
20
+ export interface TaintSummariesOutput {
21
+ /** Function summaries fed to the fixpoint. */
22
+ summaries: number;
23
+ /** Cross-function findings (pre-cap). */
24
+ findings: number;
25
+ /** TAINT_PATH edges persisted. */
26
+ edgesEmitted: number;
27
+ /** Call sites whose callee did not resolve to a summary edge (diagnostics). */
28
+ unmatchedCallSites: number;
29
+ }
30
+ export declare const taintSummariesPhase: PipelinePhase<TaintSummariesOutput>;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Phase: taintSummaries (#2084 M4 U3/U5)
3
+ *
4
+ * The interprocedural taint fixpoint. Runs AFTER scope-resolution (where the
5
+ * complete, resolved `CALLS` graph lives in `ctx.graph` and the per-function
6
+ * summaries were harvested in-phase) and composes those summaries to find
7
+ * source→sink flows that cross function and file boundaries.
8
+ *
9
+ * Opt-in: registered with `enabledWhen: (o) => o.pdg === true` (the first real
10
+ * pdg-gated phase). A default `analyze` run never includes it, so the graph is
11
+ * byte-identical. No always-on phase depends on it (a filtered-out dep would
12
+ * throw in `getPhaseOutput`).
13
+ *
14
+ * @deps scopeResolution, pruneLocalSymbols
15
+ * @reads graph (CALLS edges, Function/Method nodes), scopeResolution output
16
+ * (functionSummaries)
17
+ * @writes graph (TAINT_PATH edges)
18
+ */
19
+ import { getPhaseOutput } from './types.js';
20
+ import { solveInterprocTaint, DEFAULT_MAX_INTERPROC_HOPS, DEFAULT_PDG_MAX_INTERPROC_FINDINGS, } from '../taint/interproc-solver.js';
21
+ import { emitInterprocTaint, DEFAULT_PDG_MAX_INTERPROC_EDGES } from '../taint/interproc-emit.js';
22
+ import { logger } from '../../logger.js';
23
+ const EMPTY = {
24
+ summaries: 0,
25
+ findings: 0,
26
+ edgesEmitted: 0,
27
+ unmatchedCallSites: 0,
28
+ };
29
+ export const taintSummariesPhase = {
30
+ name: 'taintSummaries',
31
+ deps: ['scopeResolution', 'pruneLocalSymbols'],
32
+ async execute(ctx, deps) {
33
+ const scope = getPhaseOutput(deps, 'scopeResolution');
34
+ const summaries = scope.functionSummaries;
35
+ if (summaries.length === 0)
36
+ return EMPTY;
37
+ // Index summaries by function node id.
38
+ const summaryMap = new Map(summaries.map((s) => [s.fnId, s]));
39
+ // Build the call-edge adjacency from resolved CALLS edges. The join to a
40
+ // summary's call-arg edge is by CALLEE NAME (base-independent — see the
41
+ // solver doc); recover it from the callee node's `name` property.
42
+ const callEdges = [];
43
+ for (const rel of ctx.graph.iterRelationshipsByType('CALLS')) {
44
+ const callee = ctx.graph.getNode(rel.targetId);
45
+ const calleeName = callee && typeof callee.properties.name === 'string' ? callee.properties.name : undefined;
46
+ if (calleeName === undefined)
47
+ continue;
48
+ callEdges.push({ callerId: rel.sourceId, calleeId: rel.targetId, calleeName });
49
+ }
50
+ // Arm the per-run caps (#2084 review P1-3) — every other pdg layer bounds
51
+ // its output via RepoMeta.pdg; without this the fixpoint state + TAINT_PATH
52
+ // edges grow unbounded on a fan-in-heavy repo (OOM). `0` ⇒ unlimited
53
+ // (preserved like the other pdg caps). The solver/emit already implement
54
+ // deterministic truncate-and-warn — this just hands them the budgets.
55
+ const maxFindings = ctx.options?.pdgMaxInterprocFindings ?? DEFAULT_PDG_MAX_INTERPROC_FINDINGS;
56
+ const maxHops = ctx.options?.pdgMaxInterprocHops ?? DEFAULT_MAX_INTERPROC_HOPS;
57
+ const maxEdges = ctx.options?.pdgMaxInterprocEdges ?? DEFAULT_PDG_MAX_INTERPROC_EDGES;
58
+ const solved = solveInterprocTaint(summaryMap, callEdges, { maxFindings, maxHops });
59
+ const emit = emitInterprocTaint(ctx.graph, solved.findings, { maxEdges }, (m) => logger.warn(m));
60
+ // Surface drops UNCONDITIONALLY (R4 — never silently truncate the layer).
61
+ if (solved.droppedFindings > 0 || emit.edgesDropped > 0) {
62
+ logger.warn(`[taint-interproc] capped: ${solved.droppedFindings} finding(s) dropped by the ` +
63
+ `per-run findings cap (${maxFindings}), ${emit.edgesDropped} edge(s) by the edge cap ` +
64
+ `(${maxEdges}) — raise pdgMaxInterprocFindings/pdgMaxInterprocEdges if intentional`);
65
+ }
66
+ if (solved.findings.length > 0 || emit.edgesEmitted > 0) {
67
+ logger.debug(`[taint-interproc] ${summaries.length} summaries, ${callEdges.length} CALLS edges → ` +
68
+ `${solved.findings.length} cross-function finding(s), ${emit.edgesEmitted} TAINT_PATH edge(s)` +
69
+ (emit.hopsTruncated > 0 ? `, ${emit.hopsTruncated} with truncated paths` : '') +
70
+ (solved.unmatchedCallSites > 0
71
+ ? `, ${solved.unmatchedCallSites} unmatched call site(s)`
72
+ : ''));
73
+ }
74
+ return {
75
+ summaries: summaries.length,
76
+ findings: solved.findings.length,
77
+ edgesEmitted: emit.edgesEmitted,
78
+ unmatchedCallSites: solved.unmatchedCallSites,
79
+ };
80
+ },
81
+ };
@@ -25,6 +25,98 @@ export interface PipelineOptions {
25
25
  * to retain those nodes under `skipGraphPhases`.
26
26
  */
27
27
  skipGraphPhases?: boolean;
28
+ /**
29
+ * Build the control-flow-graph / PDG substrate (#2081 M1, opt-in via `--pdg`).
30
+ * Off by default: workers skip all CFG work and emit no `cfgSideChannel`, and
31
+ * scope-resolution emits no BasicBlock nodes or CFG edges — so the default
32
+ * graph is byte-identical to a pre-#2081 run. Folded into the parse-cache key
33
+ * so a pdg-off warm cache is not reused on a `--pdg` run.
34
+ */
35
+ pdg?: boolean;
36
+ /**
37
+ * Per-function source-line cap for worker-side CFG construction.
38
+ * `undefined` ⇒ the worker applies `DEFAULT_PDG_MAX_FUNCTION_LINES`; `0` ⇒ no
39
+ * cap (unlimited). Bounds the cost of a pathological mega-function; over-cap
40
+ * functions are skipped (no CFG emitted for them). No CLI flag in M1 —
41
+ * programmatic / server analyze-worker path only.
42
+ */
43
+ pdgMaxFunctionLines?: number;
44
+ /**
45
+ * Per-function CFG edge cap for the scope-resolution emit step.
46
+ * `undefined` ⇒ `DEFAULT_MAX_CFG_EDGES_PER_FUNCTION`; `0` ⇒ no cap (unlimited).
47
+ * Over-cap functions stop at the cap and log a structured drop warning (no
48
+ * silent truncation). No CLI flag in M1 — programmatic / server path only.
49
+ */
50
+ pdgMaxEdgesPerFunction?: number;
51
+ /**
52
+ * Per-function REACHING_DEF edge cap for the scope-resolution emit step
53
+ * (#2082 M2). `undefined` ⇒ `DEFAULT_PDG_MAX_REACHING_DEF_EDGES_PER_FUNCTION`
54
+ * (4000); `0` ⇒ no cap (unlimited). Emit-time-only — NOT folded into the
55
+ * parse-cache chunk key (the worker never sees it); recorded in
56
+ * `RepoMeta.pdg` so a cap change forces a full writeback. No CLI flag —
57
+ * programmatic / server path only, like the M1 caps.
58
+ */
59
+ pdgMaxReachingDefEdgesPerFunction?: number;
60
+ /**
61
+ * Per-function CDG (control-dependence) edge cap for the scope-resolution
62
+ * emit step (#2085 M5). `undefined` ⇒ `DEFAULT_PDG_MAX_CDG_EDGES_PER_FUNCTION`
63
+ * (5000); `0` ⇒ no cap (unlimited). Emit-time-only — NOT folded into the
64
+ * parse-cache chunk key; recorded resolved in `RepoMeta.pdg` so introducing
65
+ * CDG (an absent stamp key) forces a full writeback for pre-CDG `--pdg`
66
+ * indexes. No CLI flag — programmatic / server path only.
67
+ */
68
+ pdgMaxCdgEdgesPerFunction?: number;
69
+ /**
70
+ * Per-function taint findings cap for the scope-resolution taint pass
71
+ * (#2083 M3). `undefined` ⇒ `DEFAULT_PDG_MAX_TAINT_FINDINGS_PER_FUNCTION`
72
+ * (200); `0` ⇒ no cap (unlimited). Emit-time-only — NOT folded into the
73
+ * parse-cache chunk key; recorded resolved in `RepoMeta.pdg` so a cap
74
+ * change forces a full writeback. No CLI flag or rc key (KTD8) —
75
+ * programmatic / server path only, like the other pdg caps.
76
+ */
77
+ pdgMaxTaintFindingsPerFunction?: number;
78
+ /**
79
+ * Per-finding taint hop cap (#2083 M3, KTD6 — bounds the persisted
80
+ * hop-encoded `reason`). `undefined` ⇒ `DEFAULT_PDG_MAX_TAINT_HOPS` (32);
81
+ * `0` ⇒ no cap (unlimited). Same emit-time-only / RepoMeta-stamped /
82
+ * no-CLI-flag discipline as `pdgMaxTaintFindingsPerFunction`.
83
+ */
84
+ pdgMaxTaintHops?: number;
85
+ /**
86
+ * Per-run cross-function findings cap (#2084 M4 review P1-3). `undefined` ⇒
87
+ * `DEFAULT_PDG_MAX_INTERPROC_FINDINGS` (2000); `0` ⇒ no cap. Consumed by the
88
+ * `taintSummaries` phase; RepoMeta-stamped, no CLI flag (KTD8) — same
89
+ * discipline as the per-function taint caps.
90
+ */
91
+ pdgMaxInterprocFindings?: number;
92
+ /** Per-finding cross-function hop cap (#2084 review P1-3). `undefined` ⇒
93
+ * `DEFAULT_MAX_INTERPROC_HOPS` (32); `0` ⇒ no cap. */
94
+ pdgMaxInterprocHops?: number;
95
+ /** Per-run `TAINT_PATH` edge cap (#2084 review P1-3). `undefined` ⇒
96
+ * `DEFAULT_PDG_MAX_INTERPROC_EDGES` (1000); `0` ⇒ no cap. */
97
+ pdgMaxInterprocEdges?: number;
98
+ /** Per-run `CALL_SUMMARY` edge cap (PDG FU-C, U-C3). `undefined` ⇒
99
+ * `DEFAULT_PDG_MAX_CALL_SUMMARY_EDGES` (0 = unlimited); `0` ⇒ no cap.
100
+ * Programmatic only, no CLI flag (KTD8) — same discipline as the other
101
+ * pdg caps. */
102
+ pdgMaxCallSummaryEdges?: number;
103
+ /**
104
+ * Streaming/chunked PDG graph emit (#2202). When true, the BasicBlock +
105
+ * intra-file PDG-edge layer (CFG / REACHING_DEF / CDG / POST_DOMINATE /
106
+ * TAINTED / SANITIZES) is streamed to CSV-on-disk during the scope-resolution
107
+ * emit loop instead of being materialized in the in-memory graph, bounding
108
+ * peak RSS to O(chunk) rather than O(graph) at full-kernel scale. Already
109
+ * gated by the caller to full-rebuild runs only (the incremental writeback
110
+ * reads BasicBlocks back from the in-memory graph). Memory-only — produces a
111
+ * byte-identical persisted graph and is NOT part of `RepoMeta.pdg`, so
112
+ * toggling it never trips `pdgModeMismatch`. Default/false ⇒ today's
113
+ * whole-graph emit.
114
+ */
115
+ streamPdgEmit?: boolean;
116
+ /** Streamed PDG-emit write buffer (rows) when `streamPdgEmit` is on (#2202).
117
+ * `undefined` ⇒ `DEFAULT_PDG_EMIT_CHUNK_ROWS`. Memory-only; does not affect
118
+ * emitted bytes. */
119
+ pdgEmitChunkSize?: number;
28
120
  /**
29
121
  * Request parsing with the worker pool disabled. The sequential parser was
30
122
  * removed — the worker pool is the sole parse path — so setting this now
@@ -33,16 +125,6 @@ export interface PipelineOptions {
33
125
  * silently-different result.
34
126
  */
35
127
  skipWorkers?: boolean;
36
- /**
37
- * @internal Test-only override for the worker script URL the pool
38
- * spawns. When unset, parse-impl resolves `parse-worker.js` from the
39
- * adjacent `workers/` directory (or the compiled `dist/` fallback
40
- * under vitest). Integration tests use this to inject a custom
41
- * worker script that deterministically triggers worker-pool
42
- * resilience paths (e.g., crash-on-poison-file). Do not use from production
43
- * call sites.
44
- */
45
- workerUrlForTest?: URL;
46
128
  /**
47
129
  * Incremental-indexing parse cache. When provided:
48
130
  * - The parse phase looks up each chunk's content hash in
@@ -15,7 +15,7 @@
15
15
  * See ARCHITECTURE.md for the full phase dependency diagram.
16
16
  */
17
17
  import { createKnowledgeGraph } from '../graph/graph.js';
18
- import { runPipeline, getPhaseOutput, scanPhase, structurePhase, markdownPhase, cobolPhase, parsePhase, routesPhase, toolsPhase, ormPhase, crossFilePhase, scopeResolutionPhase, pruneLocalSymbolsPhase, mroPhase, communitiesPhase, processesPhase, PhaseRegistry, } from './pipeline-phases/index.js';
18
+ import { runPipeline, getPhaseOutput, scanPhase, structurePhase, markdownPhase, cobolPhase, parsePhase, routesPhase, toolsPhase, ormPhase, crossFilePhase, scopeResolutionPhase, pruneLocalSymbolsPhase, taintSummariesPhase, callSummariesPhase, mroPhase, communitiesPhase, processesPhase, PhaseRegistry, } from './pipeline-phases/index.js';
19
19
  // ── Phase registry ─────────────────────────────────────────────────────────
20
20
  /**
21
21
  * All pipeline phases with their dependency relationships.
@@ -49,6 +49,11 @@ export function buildPhaseList(options) {
49
49
  .register(crossFilePhase)
50
50
  .register(scopeResolutionPhase)
51
51
  .register(pruneLocalSymbolsPhase)
52
+ // M4 (#2084): interprocedural taint fixpoint — the first real opt-in
53
+ // pdg-gated phase. Off ⇒ absent ⇒ byte-identical graph. No always-on
54
+ // phase depends on it (a filtered-out dep would throw in getPhaseOutput).
55
+ .register(taintSummariesPhase, { enabledWhen: (o) => o.pdg === true })
56
+ .register(callSummariesPhase, { enabledWhen: (o) => o.pdg === true })
52
57
  .register(mroPhase, { enabledWhen: (o) => !o.skipGraphPhases })
53
58
  .register(communitiesPhase, { enabledWhen: (o) => !o.skipGraphPhases })
54
59
  .register(processesPhase, { enabledWhen: (o) => !o.skipGraphPhases })
@@ -72,7 +77,10 @@ export const runPipelineFromRepo = async (repoPath, onProgress, options) => {
72
77
  const { totalFiles, usedWorkerPool } = getPhaseOutput(results, 'parse');
73
78
  let communityResult;
74
79
  let processResult;
75
- const resolutionOutcomes = getPhaseOutput(results, 'scopeResolution').resolutionOutcomes;
80
+ const scopeResolutionOutput = getPhaseOutput(results, 'scopeResolution');
81
+ const resolutionOutcomes = scopeResolutionOutput.resolutionOutcomes;
82
+ // Streamed PDG-emit manifest (#2202): present only when streaming was on.
83
+ const pdgEmitManifest = scopeResolutionOutput.pdgEmitManifest;
76
84
  if (!options?.skipGraphPhases) {
77
85
  communityResult = getPhaseOutput(results, 'communities').communityResult;
78
86
  processResult = getPhaseOutput(results, 'processes').processResult;
@@ -97,5 +105,6 @@ export const runPipelineFromRepo = async (repoPath, onProgress, options) => {
97
105
  processResult,
98
106
  resolutionOutcomes,
99
107
  usedWorkerPool,
108
+ pdgEmitManifest,
100
109
  };
101
110
  };
@@ -399,6 +399,7 @@ function buildDefFromDeclarationMatch(match, anchor, filePath) {
399
399
  const returnType = match['@declaration.return-type']?.text;
400
400
  const templateConstraints = parseJsonCapture(match['@declaration.template-constraints']);
401
401
  const isExplicit = parseBooleanCapture(match['@declaration.is-explicit']);
402
+ const isDeleted = parseBooleanCapture(match['@declaration.is-deleted']);
402
403
  return {
403
404
  nodeId: makeDefId(filePath, anchor.range, type, nameCap.text),
404
405
  filePath,
@@ -413,6 +414,7 @@ function buildDefFromDeclarationMatch(match, anchor, filePath) {
413
414
  ...(templateArguments !== undefined ? { templateArguments } : {}),
414
415
  ...(templateConstraints !== undefined ? { templateConstraints } : {}),
415
416
  ...(isExplicit === true ? { isExplicit: true } : {}),
417
+ ...(isDeleted === true ? { isDeleted: true } : {}),
416
418
  };
417
419
  }
418
420
  /** Parse an opaque JSON payload synthesized by per-language captures
@@ -475,12 +477,19 @@ function parseJsonParameterTypeClassesCapture(cap) {
475
477
  if (typeof o.pointerDepth !== 'number' || !Number.isFinite(o.pointerDepth)) {
476
478
  return undefined;
477
479
  }
478
- out.push({
480
+ const shape = {
479
481
  base: o.base,
480
482
  cv: o.cv,
481
483
  indirection: o.indirection,
482
484
  pointerDepth: o.pointerDepth,
483
- });
485
+ };
486
+ if (Array.isArray(o.templateArguments)) {
487
+ if (!o.templateArguments.every((x) => typeof x === 'string')) {
488
+ return undefined;
489
+ }
490
+ shape.templateArguments = [...o.templateArguments];
491
+ }
492
+ out.push(shape);
484
493
  }
485
494
  return out;
486
495
  }
@@ -922,6 +931,7 @@ const KNOWN_SUB_TAGS = new Set([
922
931
  '@declaration.return-type',
923
932
  '@declaration.template-constraints',
924
933
  '@declaration.is-explicit',
934
+ '@declaration.is-deleted',
925
935
  ]);
926
936
  /**
927
937
  * Return the anchor capture for a match — the one whose name begins with
@@ -618,6 +618,15 @@ export interface ScopeResolver {
618
618
  * `cppConversionRank`; other languages define their own if needed.
619
619
  */
620
620
  readonly conversionRankFn?: ConversionRankFn;
621
+ /**
622
+ * Optional per-language argument-type prefixes for conversion-only
623
+ * argument sentinels. When ranking cannot find any viable candidate
624
+ * for a multi-overload set containing one of these sentinels, shared
625
+ * narrowing suppresses the ambiguous set instead of falling back to
626
+ * arity-only candidates. Languages without such sentinels leave this
627
+ * undefined.
628
+ */
629
+ readonly conversionOnlyArgTypePrefixes?: readonly string[];
621
630
  /**
622
631
  * Optional predicate to identify definitions with file-local linkage
623
632
  * (e.g. C `static` functions). When provided, `pickUniqueGlobalCallable`
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Resolved-callee-id capture sink (#2227 follow-up plan U2).
3
+ *
4
+ * During Phase-4 scope-resolution CALLS-edge emission, each resolved call
5
+ * site's `(callSiteLine, callSiteCol) → resolvedCalleeId` mapping is
6
+ * accumulated here — across ALL THREE CALLS emit paths
7
+ * (`emitReceiverBoundCalls` via `tryEmitEdge`/`tryEmitEdgeWithExplicitTargetId`,
8
+ * and the inline `graph.addRelationship` in `emitFreeCallFallback` and
9
+ * `emitReferencesViaLookup`), each BEFORE its dedup (KTD6/R8). A later unit
10
+ * (U3) joins this map to CFG `BasicBlock`s by exact call-site position and
11
+ * emits a `BasicBlock.calleeIds` set.
12
+ *
13
+ * KEY ALIGNMENT (plan KTD7 — load-bearing): the key is the call/new
14
+ * expression node's start position — `line` 1-based (`startPosition.row + 1`),
15
+ * `col` 0-based (`startPosition.column`). This MUST equal the U1
16
+ * `SiteRecord.at` so the U3 position join lands. The CALLS resolution exposes
17
+ * the same node's range via `site.atRange` (`atRange: anchor.range`,
18
+ * scope-extractor.ts:1030), whose `startLine`/`startCol` are built by
19
+ * `nodeToCapture` as `row + 1` / `column` (1-based line, 0-based col — see the
20
+ * `Range` doc in gitnexus-shared). So a capture keyed on
21
+ * `(atRange.startLine, atRange.startCol)` is byte-equal to U1's `at` — no
22
+ * normalization needed.
23
+ *
24
+ * Gating (R4): the concrete sink is created in `run.ts` only when
25
+ * `input.pdg === true`; otherwise `undefined` is threaded through, so off-mode
26
+ * does zero work and emits byte-identical output.
27
+ *
28
+ * Multi-target dispatch (R2/KTD8): one site → multiple emit calls → the `Set`
29
+ * accumulates every resolved target. Capture is per-emit-call, so the
30
+ * candidate set is complete and a real target is never dropped.
31
+ */
32
+ /** Encoded position key: `${line}:${col}` (1-based line, 0-based col). */
33
+ export type CalleeIdPosKey = string;
34
+ /** Build the position key from a call-site anchor. Single source of truth so
35
+ * producer (this sink) and consumer (U3's CFG join) encode positions
36
+ * identically. */
37
+ export declare function calleeIdPosKey(line: number, col: number): CalleeIdPosKey;
38
+ /**
39
+ * Write-side contract handed to the three CALLS emitters. Each resolved CALLS
40
+ * edge feeds one `add` BEFORE its dedup, keyed on the call-site anchor.
41
+ */
42
+ export interface CalleeIdSink {
43
+ /**
44
+ * Record that the call site at `(line, col)` in `filePath` resolved to
45
+ * `calleeId`. Idempotent per `(filePath, line, col, calleeId)` — the
46
+ * underlying value is a `Set`, so repeat targets collapse.
47
+ */
48
+ add(filePath: string, line: number, col: number, calleeId: string): void;
49
+ }
50
+ /**
51
+ * Read-side accessor consumed by U3's CFG-emit join. Returns the per-file
52
+ * `posKey → Set<calleeId>` map (or `undefined` when the file produced no
53
+ * captures). Kept separate from the write interface so the emitters only see
54
+ * the narrow `add` surface.
55
+ */
56
+ export interface CalleeIdMapView {
57
+ /** Per-file position→ids map, or `undefined` if nothing was captured for it. */
58
+ get(filePath: string): ReadonlyMap<CalleeIdPosKey, ReadonlySet<string>> | undefined;
59
+ /**
60
+ * Release a file's captured map once its CFG emit has consumed it (R6). The
61
+ * three CALLS passes fully precede the CFG-emit loop and each file is read
62
+ * exactly once, so releasing after consumption bounds the accumulator to one
63
+ * file's call sites instead of holding the whole repo's for the full phase.
64
+ */
65
+ delete(filePath: string): void;
66
+ }
67
+ /** The concrete accumulator: a write sink that also exposes the read view. */
68
+ export interface CalleeIdAccumulator extends CalleeIdSink, CalleeIdMapView {
69
+ }
70
+ /**
71
+ * Create the concrete nested-`Map` accumulator. Call ONLY when
72
+ * `input.pdg === true` (else thread `undefined` for byte-identity / zero
73
+ * overhead — R4).
74
+ */
75
+ export declare function createCalleeIdAccumulator(): CalleeIdAccumulator;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Resolved-callee-id capture sink (#2227 follow-up plan U2).
3
+ *
4
+ * During Phase-4 scope-resolution CALLS-edge emission, each resolved call
5
+ * site's `(callSiteLine, callSiteCol) → resolvedCalleeId` mapping is
6
+ * accumulated here — across ALL THREE CALLS emit paths
7
+ * (`emitReceiverBoundCalls` via `tryEmitEdge`/`tryEmitEdgeWithExplicitTargetId`,
8
+ * and the inline `graph.addRelationship` in `emitFreeCallFallback` and
9
+ * `emitReferencesViaLookup`), each BEFORE its dedup (KTD6/R8). A later unit
10
+ * (U3) joins this map to CFG `BasicBlock`s by exact call-site position and
11
+ * emits a `BasicBlock.calleeIds` set.
12
+ *
13
+ * KEY ALIGNMENT (plan KTD7 — load-bearing): the key is the call/new
14
+ * expression node's start position — `line` 1-based (`startPosition.row + 1`),
15
+ * `col` 0-based (`startPosition.column`). This MUST equal the U1
16
+ * `SiteRecord.at` so the U3 position join lands. The CALLS resolution exposes
17
+ * the same node's range via `site.atRange` (`atRange: anchor.range`,
18
+ * scope-extractor.ts:1030), whose `startLine`/`startCol` are built by
19
+ * `nodeToCapture` as `row + 1` / `column` (1-based line, 0-based col — see the
20
+ * `Range` doc in gitnexus-shared). So a capture keyed on
21
+ * `(atRange.startLine, atRange.startCol)` is byte-equal to U1's `at` — no
22
+ * normalization needed.
23
+ *
24
+ * Gating (R4): the concrete sink is created in `run.ts` only when
25
+ * `input.pdg === true`; otherwise `undefined` is threaded through, so off-mode
26
+ * does zero work and emits byte-identical output.
27
+ *
28
+ * Multi-target dispatch (R2/KTD8): one site → multiple emit calls → the `Set`
29
+ * accumulates every resolved target. Capture is per-emit-call, so the
30
+ * candidate set is complete and a real target is never dropped.
31
+ */
32
+ /** Build the position key from a call-site anchor. Single source of truth so
33
+ * producer (this sink) and consumer (U3's CFG join) encode positions
34
+ * identically. */
35
+ export function calleeIdPosKey(line, col) {
36
+ return `${line}:${col}`;
37
+ }
38
+ /**
39
+ * Create the concrete nested-`Map` accumulator. Call ONLY when
40
+ * `input.pdg === true` (else thread `undefined` for byte-identity / zero
41
+ * overhead — R4).
42
+ */
43
+ export function createCalleeIdAccumulator() {
44
+ const byFile = new Map();
45
+ return {
46
+ add(filePath, line, col, calleeId) {
47
+ let byPos = byFile.get(filePath);
48
+ if (byPos === undefined) {
49
+ byPos = new Map();
50
+ byFile.set(filePath, byPos);
51
+ }
52
+ const key = calleeIdPosKey(line, col);
53
+ let ids = byPos.get(key);
54
+ if (ids === undefined) {
55
+ ids = new Set();
56
+ byPos.set(key, ids);
57
+ }
58
+ ids.add(calleeId);
59
+ },
60
+ get(filePath) {
61
+ return byFile.get(filePath);
62
+ },
63
+ delete(filePath) {
64
+ byFile.delete(filePath);
65
+ },
66
+ };
67
+ }
@@ -18,6 +18,16 @@ import type { Reference, ScopeId, SymbolDefinition } from '../../../../_shared/i
18
18
  import type { KnowledgeGraph } from '../../../graph/types.js';
19
19
  import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js';
20
20
  import type { GraphNodeLookup } from '../graph-bridge/node-lookup.js';
21
+ import type { CalleeIdSink } from './callee-id-sink.js';
22
+ /**
23
+ * Optional resolved-callee-id capture context (#2227 follow-up U2). Threaded
24
+ * in only under `--pdg` (else `undefined` → zero overhead, byte-identity R4).
25
+ * `filePath` is NOT on the `site` param, so it rides here alongside the sink.
26
+ */
27
+ export interface CalleeIdCaptureCtx {
28
+ readonly sink: CalleeIdSink;
29
+ readonly filePath: string;
30
+ }
21
31
  /**
22
32
  * Map a `Reference.kind` to a graph edge type. `import-use` is dropped
23
33
  * (no edge type today — provenance lives on the IMPORTS edge emitted
@@ -40,7 +50,7 @@ export declare function tryEmitEdge(graph: KnowledgeGraph, scopes: ScopeResoluti
40
50
  startCol: number;
41
51
  };
42
52
  readonly kind: string;
43
- }, targetDef: SymbolDefinition, reason: string, seen: Set<string>, confidence?: number, collapseByCallerTarget?: boolean): boolean;
53
+ }, targetDef: SymbolDefinition, reason: string, seen: Set<string>, confidence?: number, collapseByCallerTarget?: boolean, calleeCapture?: CalleeIdCaptureCtx): boolean;
44
54
  /**
45
55
  * Variant of `tryEmitEdge` that takes a pre-resolved target graph id
46
56
  * instead of resolving it from a `SymbolDefinition`. Used by the
@@ -61,4 +71,4 @@ export declare function tryEmitEdgeWithExplicitTargetId(graph: KnowledgeGraph, s
61
71
  startCol: number;
62
72
  };
63
73
  readonly kind: string;
64
- }, targetGraphId: string, reason: string, seen: Set<string>, confidence?: number, collapseByCallerTarget?: boolean): boolean;
74
+ }, targetGraphId: string, reason: string, seen: Set<string>, confidence?: number, collapseByCallerTarget?: boolean, calleeCapture?: CalleeIdCaptureCtx): boolean;
@@ -51,7 +51,7 @@ export function mapReferenceKindToEdgeType(kind) {
51
51
  * multiple language-specific post-passes can share it and never
52
52
  * double-emit a resolution one of them already produced.
53
53
  */
54
- export function tryEmitEdge(graph, scopes, nodeLookup, site, targetDef, reason, seen, confidence = 0.85, collapseByCallerTarget = false) {
54
+ export function tryEmitEdge(graph, scopes, nodeLookup, site, targetDef, reason, seen, confidence = 0.85, collapseByCallerTarget = false, calleeCapture) {
55
55
  // Inheritance edges are emitted directly by `preEmitInheritanceEdges` (which
56
56
  // owns the enclosing-class caller and the EXTENDS-vs-IMPLEMENTS type), so this
57
57
  // generic bridge derives caller + edge type purely from the site.
@@ -64,6 +64,13 @@ export function tryEmitEdge(graph, scopes, nodeLookup, site, targetDef, reason,
64
64
  return false;
65
65
  if (edgeType === undefined)
66
66
  return false;
67
+ // Resolved-callee-id capture (#2227 U2/KTD6/R8): record this CALLS site's
68
+ // resolved target BEFORE the dedup `seen` check, so collapsed same-target
69
+ // multi-line calls are still captured per site. Keyed on `site.atRange`
70
+ // (1-based line / 0-based col — byte-equal to U1's SiteRecord.at).
71
+ if (calleeCapture !== undefined && edgeType === 'CALLS') {
72
+ calleeCapture.sink.add(calleeCapture.filePath, site.atRange.startLine, site.atRange.startCol, targetGraphId);
73
+ }
67
74
  // CALLS edges may collapse to `(caller, target)` granularity when
68
75
  // the provider opts in (C# matches legacy DAG behavior this way).
69
76
  // Write/read ACCESSES keep per-site dedup so multiple writes to the
@@ -98,13 +105,18 @@ export function tryEmitEdge(graph, scopes, nodeLookup, site, targetDef, reason,
98
105
  * All other invariants of `tryEmitEdge` apply: dedup key shape, collapse
99
106
  * flag honoring, edge-type mapping, caller-id resolution.
100
107
  */
101
- export function tryEmitEdgeWithExplicitTargetId(graph, scopes, nodeLookup, site, targetGraphId, reason, seen, confidence = 0.85, collapseByCallerTarget = false) {
108
+ export function tryEmitEdgeWithExplicitTargetId(graph, scopes, nodeLookup, site, targetGraphId, reason, seen, confidence = 0.85, collapseByCallerTarget = false, calleeCapture) {
102
109
  const callerGraphId = resolveCallerGraphId(site.inScope, scopes, nodeLookup, site.atRange);
103
110
  const edgeType = mapReferenceKindToEdgeType(site.kind);
104
111
  if (callerGraphId === undefined)
105
112
  return false;
106
113
  if (edgeType === undefined)
107
114
  return false;
115
+ // Resolved-callee-id capture (#2227 U2/KTD6/R8) — before dedup, see
116
+ // `tryEmitEdge`. The explicit target id IS the resolved callee id.
117
+ if (calleeCapture !== undefined && edgeType === 'CALLS') {
118
+ calleeCapture.sink.add(calleeCapture.filePath, site.atRange.startLine, site.atRange.startCol, targetGraphId);
119
+ }
108
120
  const useCollapsed = collapseByCallerTarget && edgeType === 'CALLS';
109
121
  const dedupKey = useCollapsed
110
122
  ? `${edgeType}:${callerGraphId}->${targetGraphId}`
@@ -21,6 +21,7 @@ import type { Reference, ScopeId } from '../../../../_shared/index.js';
21
21
  import type { KnowledgeGraph } from '../../../graph/types.js';
22
22
  import type { ScopeResolutionIndexes } from '../../model/scope-resolution-indexes.js';
23
23
  import type { GraphNodeLookup } from '../graph-bridge/node-lookup.js';
24
+ import type { CalleeIdSink } from '../graph-bridge/callee-id-sink.js';
24
25
  /**
25
26
  * Optional opaque skip key — providers may pre-emit edges (e.g. via
26
27
  * receiver-bound post-passes) and want this loop to skip references at
@@ -31,7 +32,11 @@ import type { GraphNodeLookup } from '../graph-bridge/node-lookup.js';
31
32
  type ReferenceSiteSkipSet = ReadonlySet<string>;
32
33
  export declare function emitReferencesViaLookup(graph: KnowledgeGraph, scopes: ScopeResolutionIndexes, referenceIndex: {
33
34
  readonly bySourceScope: ReadonlyMap<ScopeId, readonly Reference[]>;
34
- }, nodeLookup: GraphNodeLookup, skipSites?: ReferenceSiteSkipSet): {
35
+ }, nodeLookup: GraphNodeLookup, skipSites?: ReferenceSiteSkipSet,
36
+ /** Resolved-callee-id capture sink (#2227 U2). Threaded in only under
37
+ * `--pdg`; `undefined` ⇒ zero overhead, byte-identity (R4). Captured at the
38
+ * CALLS emit below BEFORE this loop's `seen` dedup (KTD6/R8). */
39
+ calleeIdSink?: CalleeIdSink): {
35
40
  emitted: number;
36
41
  skipped: number;
37
42
  };