gitnexus 1.6.8-rc.9 → 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 (430) 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 +11 -0
  135. package/dist/core/ingestion/languages/c-cpp.js +6 -1
  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 +3 -0
  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 +23 -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/parse-worker.d.ts +13 -0
  238. package/dist/core/ingestion/workers/parse-worker.js +76 -17
  239. package/dist/core/ingestion/workers/worker-pool.d.ts +9 -40
  240. package/dist/core/ingestion/workers/worker-pool.js +15 -2
  241. package/dist/core/lbug/csv-generator.d.ts +51 -3
  242. package/dist/core/lbug/csv-generator.js +369 -255
  243. package/dist/core/lbug/lbug-adapter.d.ts +58 -18
  244. package/dist/core/lbug/lbug-adapter.js +346 -84
  245. package/dist/core/lbug/lbug-config.d.ts +19 -0
  246. package/dist/core/lbug/lbug-config.js +29 -0
  247. package/dist/core/lbug/pdg-emit-sink.d.ts +127 -0
  248. package/dist/core/lbug/pdg-emit-sink.js +358 -0
  249. package/dist/core/lbug/pool-adapter.d.ts +35 -0
  250. package/dist/core/lbug/pool-adapter.js +90 -1
  251. package/dist/core/lbug/rel-pair-routing.d.ts +54 -0
  252. package/dist/core/lbug/rel-pair-routing.js +140 -0
  253. package/dist/core/lbug/schema.d.ts +2 -2
  254. package/dist/core/lbug/schema.js +3 -0
  255. package/dist/core/logger.d.ts +0 -5
  256. package/dist/core/run-analyze.d.ts +96 -0
  257. package/dist/core/run-analyze.js +207 -3
  258. package/dist/core/tree-sitter/parser-loader.js +5 -4
  259. package/dist/core/tree-sitter/safe-parse.d.ts +0 -5
  260. package/dist/core/tree-sitter/vendored-grammars.d.ts +39 -0
  261. package/dist/core/tree-sitter/vendored-grammars.js +57 -0
  262. package/dist/core/wiki/generator.js +3 -1
  263. package/dist/core/wiki/graph-queries.d.ts +6 -0
  264. package/dist/core/wiki/graph-queries.js +9 -1
  265. package/dist/mcp/http-transport.d.ts +134 -0
  266. package/dist/mcp/http-transport.js +503 -0
  267. package/dist/mcp/local/local-backend.d.ts +110 -24
  268. package/dist/mcp/local/local-backend.js +1225 -19
  269. package/dist/mcp/local/pdg-impact.d.ts +384 -0
  270. package/dist/mcp/local/pdg-impact.js +1972 -0
  271. package/dist/mcp/resources.js +13 -1
  272. package/dist/mcp/tools.d.ts +12 -0
  273. package/dist/mcp/tools.js +214 -7
  274. package/dist/server/analyze-launch.d.ts +29 -0
  275. package/dist/server/analyze-launch.js +137 -0
  276. package/dist/server/analyze-upload.d.ts +33 -0
  277. package/dist/server/analyze-upload.js +123 -0
  278. package/dist/server/analyze-worker.d.ts +17 -1
  279. package/dist/server/api.d.ts +17 -0
  280. package/dist/server/api.js +132 -168
  281. package/dist/server/git-clone.d.ts +43 -2
  282. package/dist/server/git-clone.js +211 -16
  283. package/dist/server/mcp-http.d.ts +5 -6
  284. package/dist/server/mcp-http.js +9 -82
  285. package/dist/server/middleware.d.ts +40 -0
  286. package/dist/server/middleware.js +92 -0
  287. package/dist/server/private-ip.d.ts +1 -0
  288. package/dist/server/private-ip.js +15 -0
  289. package/dist/server/upload-ingest.d.ts +56 -0
  290. package/dist/server/upload-ingest.js +276 -0
  291. package/dist/server/upload-paths.d.ts +37 -0
  292. package/dist/server/upload-paths.js +57 -0
  293. package/dist/server/upload-sweep.d.ts +20 -0
  294. package/dist/server/upload-sweep.js +57 -0
  295. package/dist/storage/git.js +5 -8
  296. package/dist/storage/parse-cache.d.ts +22 -1
  297. package/dist/storage/parse-cache.js +41 -10
  298. package/dist/storage/repo-manager.d.ts +121 -10
  299. package/dist/storage/repo-manager.js +43 -5
  300. package/dist/types/pipeline.d.ts +9 -0
  301. package/hooks/antigravity/gitnexus-antigravity-hook.cjs +110 -10
  302. package/hooks/claude/gitnexus-hook.cjs +110 -13
  303. package/hooks/claude/hook-db-lock-probe.cjs +513 -26
  304. package/package.json +8 -2
  305. package/scripts/assert-publish-grammar-coverage.cjs +31 -0
  306. package/scripts/build-tree-sitter-grammars.cjs +16 -10
  307. package/scripts/cross-platform-tests.ts +1 -0
  308. package/skills/gitnexus-debugging.md +16 -4
  309. package/skills/gitnexus-exploring.md +3 -3
  310. package/skills/gitnexus-guide.md +33 -0
  311. package/skills/gitnexus-pdg-query.md +89 -0
  312. package/skills/gitnexus-refactoring.md +1 -1
  313. package/skills/gitnexus-taint-analysis.md +178 -0
  314. package/vendor/tree-sitter-c/package.json +1 -1
  315. package/vendor/tree-sitter-dart/package.json +1 -1
  316. package/vendor/tree-sitter-kotlin/package.json +1 -1
  317. package/vendor/tree-sitter-proto/package.json +1 -1
  318. package/vendor/tree-sitter-swift/package.json +1 -1
  319. package/web/assets/{agent-CKPMqImC.js → agent-D3Xd7zZE.js} +123 -123
  320. package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +1 -0
  321. package/web/assets/architectureDiagram-UL44E2DR-ChH9xW-N.js +36 -0
  322. package/web/assets/{blockDiagram-7IZFK4PR-B4niSLvR.js → blockDiagram-7IZFK4PR-BkWhpzWB.js} +1 -1
  323. package/web/assets/{c4Diagram-Y2BXMSZH-DIzEXalR.js → c4Diagram-Y2BXMSZH-DtBvpzWD.js} +1 -1
  324. package/web/assets/{chunk-3SSMPTDK-BzGeeheI.js → chunk-3SSMPTDK-B4_etUhr.js} +2 -2
  325. package/web/assets/{chunk-5IMINLNL-CnTLsXIV.js → chunk-5IMINLNL-DOdTeQri.js} +1 -1
  326. package/web/assets/{chunk-5VCL7Z4A-w1BCx98Z.js → chunk-5VCL7Z4A-CQ-2dYWj.js} +1 -1
  327. package/web/assets/chunk-6764PJDD-DpIS7hxD.js +1 -0
  328. package/web/assets/{chunk-67TQ5CYL-CChC2cAv.js → chunk-67TQ5CYL-4sNPJU1q.js} +3 -3
  329. package/web/assets/{chunk-7W6UQGC5-CgFyfZ6k.js → chunk-7W6UQGC5-KyEG0HQg.js} +1 -1
  330. package/web/assets/{chunk-AZZRMDJM-5E9ARdDQ.js → chunk-AZZRMDJM-y-xJBuMz.js} +1 -1
  331. package/web/assets/{chunk-INKRHTLW-ELpfuk9h.js → chunk-INKRHTLW-Nu4ri9P-.js} +1 -1
  332. package/web/assets/{chunk-JQRUD6KW-Dcq_Qnyy.js → chunk-JQRUD6KW-Dbva2Z17.js} +1 -1
  333. package/web/assets/{chunk-KGFNY3KK-W-VR57xb.js → chunk-KGFNY3KK-JGMJvKCK.js} +1 -1
  334. package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +161 -0
  335. package/web/assets/{chunk-KNLZD3CH-BuZBOcso.js → chunk-KNLZD3CH-BGlP6X9R.js} +1 -1
  336. package/web/assets/{chunk-KRXBNO2N-DH2NPM7I.js → chunk-KRXBNO2N-BW5o0KUN.js} +1 -1
  337. package/web/assets/{chunk-LCXTWHL2-Dfmux4m1.js → chunk-LCXTWHL2-zoomRtWX.js} +1 -1
  338. package/web/assets/{chunk-LII3EMHJ-3X33tCpU.js → chunk-LII3EMHJ-D-jm-dLa.js} +1 -1
  339. package/web/assets/{chunk-QA3QBVWF-D5Ha3GgB.js → chunk-QA3QBVWF-BgRW3SXd.js} +1 -1
  340. package/web/assets/{chunk-RG4AUYOV-CAkzcoRj.js → chunk-RG4AUYOV-DD0B2N2B.js} +1 -1
  341. package/web/assets/{chunk-T2UQINTJ-kGYG7ppP.js → chunk-T2UQINTJ-DSBqkzH7.js} +1 -1
  342. package/web/assets/chunk-T5OCTHI4-DdZvN-9i.js +1 -0
  343. package/web/assets/{chunk-UY5QBCOK-Du-c56gs.js → chunk-UY5QBCOK-DyF0vyGd.js} +1 -1
  344. package/web/assets/{chunk-W44A43WB-lrCpuupA.js → chunk-W44A43WB-JqMLIpR0.js} +1 -1
  345. package/web/assets/{chunk-ZXARS5L4-CSZRiyOf.js → chunk-ZXARS5L4-CxN8oiwI.js} +1 -1
  346. package/web/assets/classDiagram-KGZ6W3CR-DJm9BgF-.js +1 -0
  347. package/web/assets/classDiagram-v2-72OJOZXJ-DJm9BgF-.js +1 -0
  348. package/web/assets/{context-builder-_HS0v2ma.js → context-builder-BHiFUA8O.js} +10 -2
  349. package/web/assets/{cose-bilkent-UX7MHV2Q-BHv2bbtl.js → cose-bilkent-UX7MHV2Q-D71wNYRJ.js} +1 -1
  350. package/web/assets/dagre-ND4H6XIP-BIkxmhcu.js +4 -0
  351. package/web/assets/diagram-3NCE3AQN-BTa6iH0T.js +43 -0
  352. package/web/assets/diagram-GF46GFSD-DZDV0vBj.js +24 -0
  353. package/web/assets/{diagram-HNR7UZ2L-fUWreZzx.js → diagram-HNR7UZ2L-DFCfd5LI.js} +2 -2
  354. package/web/assets/diagram-QXG6HAR7-BzM--Jj0.js +24 -0
  355. package/web/assets/diagram-WEQXMOUZ-DFFwz0k4.js +10 -0
  356. package/web/assets/{erDiagram-L5TCEMPS-QN2eEP1e.js → erDiagram-L5TCEMPS-CfHMJJqo.js} +1 -1
  357. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +1 -0
  358. package/web/assets/{flowDiagram-H6V6AXG4-CXbXImlN.js → flowDiagram-H6V6AXG4-Be805QiJ.js} +3 -3
  359. package/web/assets/{ganttDiagram-JCBTUEKG-BHQssTz6.js → ganttDiagram-JCBTUEKG-D3iL2Aet.js} +1 -1
  360. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +1 -0
  361. package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +106 -0
  362. package/web/assets/index-BvYev1UJ.js +635 -0
  363. package/web/assets/index-_lgn7hs5.css +2 -0
  364. package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +1 -0
  365. package/web/assets/infoDiagram-3YFTVSEB-Y7BKSoke.js +2 -0
  366. package/web/assets/{ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js → ishikawaDiagram-BNXS4ZKH-CT4SHFuI.js} +1 -1
  367. package/web/assets/{journeyDiagram-M6C3CM3L-DNPYCpvq.js → journeyDiagram-M6C3CM3L-CvArszLo.js} +1 -1
  368. package/web/assets/{kanban-definition-75IXJCU3-DgDi9oJT.js → kanban-definition-75IXJCU3-C6yDxr7N.js} +3 -3
  369. package/web/assets/{katex-K3KEBU37-CrVLz8l7.js → katex-K3KEBU37-CTc5BslQ.js} +1 -1
  370. package/web/assets/{mindmap-definition-2TDM6QVE-CwR5sBB-.js → mindmap-definition-2TDM6QVE-BOc2WEne.js} +1 -1
  371. package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +1 -0
  372. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +1 -0
  373. package/web/assets/{pieDiagram-CU6KROY3-By8g6f6B.js → pieDiagram-CU6KROY3-Cvc0f_Pd.js} +1 -1
  374. package/web/assets/{quadrantDiagram-VICAPDV7-bAm6Hi_5.js → quadrantDiagram-VICAPDV7-yXSZ2lLz.js} +1 -1
  375. package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +1 -0
  376. package/web/assets/{requirementDiagram-JXO7QTGE-7oDcJ1_J.js → requirementDiagram-JXO7QTGE-BRcZvHs4.js} +1 -1
  377. package/web/assets/{sankeyDiagram-URQDO5SZ-LFJz53u5.js → sankeyDiagram-URQDO5SZ-1qEjlFIB.js} +1 -1
  378. package/web/assets/{sequenceDiagram-VS2MUI6T-FySeKCUy.js → sequenceDiagram-VS2MUI6T-PcSCuvrB.js} +3 -3
  379. package/web/assets/stateDiagram-7D4R322I-D6qYSV1E.js +1 -0
  380. package/web/assets/stateDiagram-v2-36443NZ5-Bg-ImOSX.js +1 -0
  381. package/web/assets/{timeline-definition-O6YCAMPW-Ds2CnVZK.js → timeline-definition-O6YCAMPW-QWkh01xw.js} +1 -1
  382. package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +1 -0
  383. package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +1 -0
  384. package/web/assets/{vennDiagram-MWXL3ELB-DUIEwXWp.js → vennDiagram-MWXL3ELB-ak4DfwuM.js} +3 -3
  385. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +1 -0
  386. package/web/assets/{wardleyDiagram-CUQ6CDDI-DEiFPQih.js → wardleyDiagram-CUQ6CDDI-CTzR4Loq.js} +1 -1
  387. package/web/assets/{xychartDiagram-N2JHSOCM-BUbayhST.js → xychartDiagram-N2JHSOCM-DA1BEaQz.js} +1 -1
  388. package/web/index.html +13 -15
  389. package/scripts/materialize-vendor-grammars.cjs +0 -97
  390. package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +0 -1
  391. package/web/assets/architectureDiagram-UL44E2DR-D1EXI0zA.js +0 -36
  392. package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +0 -4
  393. package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +0 -1
  394. package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +0 -159
  395. package/web/assets/chunk-6764PJDD-ChwMM2z4.js +0 -1
  396. package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +0 -10
  397. package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +0 -1
  398. package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +0 -1
  399. package/web/assets/chunk-CilyBKbf.js +0 -1
  400. package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +0 -1
  401. package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +0 -1
  402. package/web/assets/chunk-RERM46MO-DQNbXtfw.js +0 -1
  403. package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +0 -1
  404. package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +0 -1
  405. package/web/assets/chunk-T5OCTHI4--9wWpVws.js +0 -1
  406. package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +0 -1
  407. package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +0 -1
  408. package/web/assets/classDiagram-KGZ6W3CR-Bv93af_b.js +0 -1
  409. package/web/assets/classDiagram-v2-72OJOZXJ-CLfEqHUa.js +0 -1
  410. package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +0 -4
  411. package/web/assets/diagram-3NCE3AQN-BqAtKUpW.js +0 -43
  412. package/web/assets/diagram-GF46GFSD-CaBG6n6o.js +0 -24
  413. package/web/assets/diagram-QXG6HAR7-CZ-O3rcV.js +0 -24
  414. package/web/assets/diagram-WEQXMOUZ-P4lSL4GH.js +0 -10
  415. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +0 -1
  416. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +0 -1
  417. package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +0 -106
  418. package/web/assets/index-BKWA-m7o.css +0 -2
  419. package/web/assets/index-CG6q8eTs.js +0 -626
  420. package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +0 -1
  421. package/web/assets/infoDiagram-3YFTVSEB-DmLICZx1.js +0 -2
  422. package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +0 -1
  423. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +0 -1
  424. package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +0 -1
  425. package/web/assets/stateDiagram-7D4R322I-CB2nABwH.js +0 -1
  426. package/web/assets/stateDiagram-v2-36443NZ5-COBGd2RL.js +0 -1
  427. package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +0 -1
  428. package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +0 -1
  429. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +0 -1
  430. /package/web/assets/{chunk-AQ6EADP3-CCFje6lL.js → chunk-AQ6EADP3-CZhslHi-.js} +0 -0
@@ -14,6 +14,8 @@
14
14
  import fs from 'fs/promises';
15
15
  import { createWriteStream } from 'fs';
16
16
  import path from 'path';
17
+ import { NODE_TABLES } from './schema.js';
18
+ import { RelPairRouter } from './rel-pair-routing.js';
17
19
  import { parseTruthyEnv } from '../ingestion/utils/env.js';
18
20
  /**
19
21
  * Deterministic output ordering — optional (out-of-core / windowed-resolve
@@ -31,6 +33,14 @@ const orderedNodes = (graph, sorted) => sorted ? [...graph.iterNodes()].sort(byG
31
33
  const orderedRelationships = (graph, sorted) => sorted ? [...graph.iterRelationships()].sort(byGraphId) : graph.iterRelationships();
32
34
  /** Flush buffered rows to disk every N rows */
33
35
  const FLUSH_EVERY = 500;
36
+ /**
37
+ * Yield the event loop every N relationship rows during the emit pass (#2226 F4)
38
+ * so a concurrent node COPY (the overlap in loadGraphToLbug) and write-stream
39
+ * drain callbacks get scheduling time during long synchronous emit stretches.
40
+ * Scheduling-only — never changes row content or order (byte-identical). Tuning
41
+ * constant, not load-bearing.
42
+ */
43
+ const REL_YIELD_EVERY = 5000;
34
44
  // ============================================================================
35
45
  // CSV ESCAPE UTILITIES
36
46
  // ============================================================================
@@ -158,13 +168,20 @@ class BufferedCSVWriter {
158
168
  this.ws.setMaxListeners(50);
159
169
  this.buffer.push(header);
160
170
  }
171
+ /**
172
+ * Buffer a row. Returns a promise ONLY when the buffer crossed FLUSH_EVERY
173
+ * and a disk write was issued; otherwise returns `undefined` so the caller
174
+ * can skip awaiting (#2203 U3) — avoiding a microtask tick on every buffered
175
+ * row (millions at scale). The flush promise still resolves on drain, so
176
+ * backpressure is preserved on the rows that actually write.
177
+ */
161
178
  addRow(row) {
162
179
  this.buffer.push(row);
163
180
  this.rows++;
164
181
  if (this.buffer.length >= FLUSH_EVERY) {
165
182
  return this.flush();
166
183
  }
167
- return Promise.resolve();
184
+ return undefined;
168
185
  }
169
186
  flush() {
170
187
  if (this.buffer.length === 0)
@@ -194,12 +211,65 @@ class BufferedCSVWriter {
194
211
  });
195
212
  }
196
213
  }
214
+ // ============================================================================
215
+ // STREAMING CSV GENERATION — SINGLE PASS
216
+ // ============================================================================
217
+ /** Canonical relationship CSV header — shared by the emit pass and the
218
+ * `splitRelCsvByLabelPair` differential oracle. */
219
+ export const REL_CSV_HEADER = 'from,to,type,confidence,reason,step';
220
+ /** Build the escaped CSV row (no trailing newline) for one relationship.
221
+ * Single source of the relationship row bytes — used by the emit pass and by
222
+ * the byte-identity differential test that feeds the legacy split oracle. */
223
+ export const buildRelRow = (rel) => [
224
+ escapeCSVField(rel.sourceId),
225
+ escapeCSVField(rel.targetId),
226
+ escapeCSVField(rel.type),
227
+ escapeCSVNumber(rel.confidence, 1.0),
228
+ escapeCSVField(rel.reason),
229
+ escapeCSVNumber(rel.step, 0),
230
+ ].join(',');
231
+ /** Canonical BasicBlock node CSV header — taint/PDG substrate (issue #2080).
232
+ * No `name` column; blocks are identified by id + source span. Shared by the
233
+ * whole-graph emit pass and the streaming PDG emit sink (issue #2202) so the
234
+ * two paths produce byte-identical BasicBlock rows by construction. */
235
+ export const BASICBLOCK_CSV_HEADER = 'id,filePath,startLine,endLine,text,callees,calleeIds';
236
+ /** Build the escaped CSV row (no trailing newline) for one BasicBlock node.
237
+ * Single source of the BasicBlock row bytes — used by `streamAllCSVsToDisk`
238
+ * and by the streaming `PdgEmitSink` (issue #2202). `callees` is a comma-free
239
+ * (space-joined) list of the leaf callee names invoked in the block — the
240
+ * statement-precise inter-procedural reach substrate (the field is itself a CSV
241
+ * cell, so the inner separator must NOT be a comma). `calleeIds` is the SOUND
242
+ * parallel to `callees`: the space-joined RESOLVED callee symbol ids for the
243
+ * block (#2227 follow-up), likewise a comma-free cell. */
244
+ export const buildBasicBlockRow = (node) => [
245
+ escapeCSVField(node.id),
246
+ escapeCSVField(node.properties.filePath || ''),
247
+ escapeCSVNumber(node.properties.startLine, -1),
248
+ escapeCSVNumber(node.properties.endLine, -1),
249
+ escapeCSVField(node.properties.text || ''),
250
+ escapeCSVField(String(node.properties.callees ?? '')),
251
+ escapeCSVField(String(node.properties.calleeIds ?? '')),
252
+ ].join(',');
197
253
  /**
198
254
  * Stream all CSV data directly to disk files.
199
255
  * Iterates graph nodes exactly ONCE — routes each node to the right writer.
200
256
  * File contents are lazy-read from disk with a generous LRU cache.
257
+ *
258
+ * `onNodePhaseComplete` (optional, #2203 parallelism leg): fired exactly once,
259
+ * right after every node CSV is fully flushed to disk and BEFORE the
260
+ * relationship pass starts writing any `rel_*.csv`. It receives the finished
261
+ * node-file manifest so the caller can begin `COPY`-ing nodes while this
262
+ * function keeps generating relationship CSVs (the only single-writer-safe
263
+ * overlap — node `COPY` ‖ relationship emit). It is intentionally NOT awaited:
264
+ * the relationship pass proceeds concurrently with whatever the caller
265
+ * schedules. A synchronous throw from the callback is allowed and propagates out
266
+ * of this function (rejecting the returned promise) — it is raised before the
267
+ * relationship pass begins, so no `rel_*.csv` is written; `loadGraphToLbug` uses
268
+ * this to surface its PDG-manifest collision guard. The callback must NOT, however,
269
+ * schedule un-awaited async work that can reject unobserved. Absent ⇒ today's
270
+ * behavior, byte-for-byte.
201
271
  */
202
- export const streamAllCSVsToDisk = async (graph, repoPath, csvDir) => {
272
+ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir, onNodePhaseComplete) => {
203
273
  // Deterministic (id-sorted) node/relationship row order when enabled;
204
274
  // default off = today's graph-insertion order (byte-identical).
205
275
  const sortOutput = parseTruthyEnv(process.env.GITNEXUS_SORT_GRAPH_OUTPUT);
@@ -213,191 +283,131 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir) => {
213
283
  // MaxListenersExceededWarning (restored after all streams finish).
214
284
  const prevMax = process.getMaxListeners();
215
285
  process.setMaxListeners(prevMax + 40);
216
- const contentCache = new FileContentCache(repoPath);
217
- // Create writers for every node type up-front
218
- const fileWriter = new BufferedCSVWriter(path.join(csvDir, 'file.csv'), 'id,name,filePath,content');
219
- const folderWriter = new BufferedCSVWriter(path.join(csvDir, 'folder.csv'), 'id,name,filePath');
220
- const codeElementHeader = 'id,name,filePath,startLine,endLine,isExported,content,description';
221
- const functionWriter = new BufferedCSVWriter(path.join(csvDir, 'function.csv'), codeElementHeader);
222
- const classWriter = new BufferedCSVWriter(path.join(csvDir, 'class.csv'), codeElementHeader);
223
- const interfaceWriter = new BufferedCSVWriter(path.join(csvDir, 'interface.csv'), codeElementHeader);
224
- const methodHeader = 'id,name,filePath,startLine,endLine,isExported,content,description,parameterCount,returnType';
225
- const methodWriter = new BufferedCSVWriter(path.join(csvDir, 'method.csv'), methodHeader);
226
- const codeElemWriter = new BufferedCSVWriter(path.join(csvDir, 'codeelement.csv'), codeElementHeader);
227
- const communityWriter = new BufferedCSVWriter(path.join(csvDir, 'community.csv'), 'id,label,heuristicLabel,keywords,description,enrichedBy,cohesion,symbolCount');
228
- const processWriter = new BufferedCSVWriter(path.join(csvDir, 'process.csv'), 'id,label,heuristicLabel,processType,stepCount,communities,entryPointId,terminalId');
229
- // Section nodes have an extra 'level' column
230
- const sectionWriter = new BufferedCSVWriter(path.join(csvDir, 'section.csv'), 'id,name,filePath,startLine,endLine,level,content,description');
231
- // Route nodes for API endpoint mapping
232
- const routeWriter = new BufferedCSVWriter(path.join(csvDir, 'route.csv'), 'id,name,filePath,responseKeys,errorKeys,middleware');
233
- // Tool nodes for MCP tool definitions
234
- const toolWriter = new BufferedCSVWriter(path.join(csvDir, 'tool.csv'), 'id,name,filePath,description');
235
- // BasicBlock nodes taint/PDG substrate (issue #2080). No `name` column;
236
- // blocks are identified by id + source span. Emitted by no phase yet.
237
- const basicBlockWriter = new BufferedCSVWriter(path.join(csvDir, 'basicblock.csv'), 'id,filePath,startLine,endLine,text');
238
- // Multi-language node types share the same CSV shape (no isExported column)
239
- const multiLangHeader = 'id,name,filePath,startLine,endLine,content,description';
240
- const MULTI_LANG_TYPES = [
241
- 'Struct',
242
- 'Enum',
243
- 'Macro',
244
- 'Typedef',
245
- 'Union',
246
- 'Namespace',
247
- 'Trait',
248
- 'Impl',
249
- 'TypeAlias',
250
- 'Const',
251
- 'Static',
252
- 'Variable',
253
- 'Property',
254
- 'Record',
255
- 'Delegate',
256
- 'Annotation',
257
- 'Constructor',
258
- 'Template',
259
- 'Module',
260
- ];
261
- const propertyHeader = 'id,name,filePath,startLine,endLine,content,description,declaredType';
262
- const multiLangWriters = new Map();
263
- for (const t of MULTI_LANG_TYPES) {
264
- multiLangWriters.set(t, new BufferedCSVWriter(path.join(csvDir, `${t.toLowerCase()}.csv`), t === 'Property' ? propertyHeader : multiLangHeader));
265
- }
266
- const codeWriterMap = {
267
- Function: functionWriter,
268
- Class: classWriter,
269
- Interface: interfaceWriter,
270
- CodeElement: codeElemWriter,
271
- };
272
- // Deduplicate all node types — the pipeline can produce duplicate IDs across
273
- // all symbol types (Class, Method, Function, etc.), not just File nodes.
274
- // A single Set covering every label prevents PK violations on COPY.
275
- const seenNodeIds = new Set();
276
- // --- SINGLE PASS over all nodes ---
277
- for (const node of orderedNodes(graph, sortOutput)) {
278
- if (seenNodeIds.has(node.id))
279
- continue;
280
- seenNodeIds.add(node.id);
281
- switch (node.label) {
282
- case 'File': {
283
- const content = await extractContent(node, contentCache);
284
- await fileWriter.addRow([
285
- escapeCSVField(node.id),
286
- escapeCSVField(node.properties.name || ''),
287
- escapeCSVField(node.properties.filePath || ''),
288
- escapeCSVField(content),
289
- ].join(','));
290
- break;
291
- }
292
- case 'Folder':
293
- await folderWriter.addRow([
294
- escapeCSVField(node.id),
295
- escapeCSVField(node.properties.name || ''),
296
- escapeCSVField(node.properties.filePath || ''),
297
- ].join(','));
298
- break;
299
- case 'Community': {
300
- const keywords = node.properties.keywords || [];
301
- const keywordsStr = `[${keywords.map((k) => `'${k.replace(/\\/g, '\\\\').replace(/'/g, "''").replace(/,/g, '\\,')}'`).join(',')}]`;
302
- await communityWriter.addRow([
303
- escapeCSVField(node.id),
304
- escapeCSVField(node.properties.name || ''),
305
- escapeCSVField(node.properties.heuristicLabel || ''),
306
- keywordsStr,
307
- escapeCSVField(node.properties.description || ''),
308
- escapeCSVField(node.properties.enrichedBy || 'heuristic'),
309
- escapeCSVNumber(node.properties.cohesion, 0),
310
- escapeCSVNumber(node.properties.symbolCount, 0),
311
- ].join(','));
312
- break;
313
- }
314
- case 'Process': {
315
- const communities = node.properties.communities || [];
316
- const communitiesStr = `[${communities.map((c) => `'${c.replace(/'/g, "''")}'`).join(',')}]`;
317
- await processWriter.addRow([
318
- escapeCSVField(node.id),
319
- escapeCSVField(node.properties.name || ''),
320
- escapeCSVField(node.properties.heuristicLabel || ''),
321
- escapeCSVField(node.properties.processType || ''),
322
- escapeCSVNumber(node.properties.stepCount, 0),
323
- escapeCSVField(communitiesStr),
324
- escapeCSVField(node.properties.entryPointId || ''),
325
- escapeCSVField(node.properties.terminalId || ''),
326
- ].join(','));
327
- break;
328
- }
329
- case 'Method': {
330
- const content = await extractContent(node, contentCache);
331
- await methodWriter.addRow([
332
- escapeCSVField(node.id),
333
- escapeCSVField(node.properties.name || ''),
334
- escapeCSVField(node.properties.filePath || ''),
335
- escapeCSVNumber(node.properties.startLine, -1),
336
- escapeCSVNumber(node.properties.endLine, -1),
337
- node.properties.isExported ? 'true' : 'false',
338
- escapeCSVField(content),
339
- escapeCSVField(node.properties.description || ''),
340
- escapeCSVNumber(node.properties.parameterCount, 0),
341
- escapeCSVField(node.properties.returnType || ''),
342
- ].join(','));
343
- break;
344
- }
345
- case 'Section': {
346
- const content = await extractContent(node, contentCache);
347
- await sectionWriter.addRow([
348
- escapeCSVField(node.id),
349
- escapeCSVField(node.properties.name || ''),
350
- escapeCSVField(node.properties.filePath || ''),
351
- escapeCSVNumber(node.properties.startLine, -1),
352
- escapeCSVNumber(node.properties.endLine, -1),
353
- escapeCSVNumber(node.properties.level, 1),
354
- escapeCSVField(content),
355
- escapeCSVField(node.properties.description || ''),
356
- ].join(','));
357
- break;
358
- }
359
- case 'Route': {
360
- const responseKeys = node.properties.responseKeys || [];
361
- // LadybugDB array literal inside a quoted CSV field: escapeCSVField wraps in "..."
362
- // and the array uses single-quoted elements
363
- const keysStr = `[${responseKeys.map((k) => `'${k.replace(/'/g, "''")}'`).join(',')}]`;
364
- const errorKeys = node.properties.errorKeys || [];
365
- const errorKeysStr = `[${errorKeys.map((k) => `'${k.replace(/'/g, "''")}'`).join(',')}]`;
366
- const middleware = node.properties.middleware || [];
367
- const middlewareStr = `[${middleware.map((m) => `'${m.replace(/'/g, "''")}'`).join(',')}]`;
368
- await routeWriter.addRow([
369
- escapeCSVField(node.id),
370
- escapeCSVField(node.properties.name || ''),
371
- escapeCSVField(node.properties.filePath || ''),
372
- escapeCSVField(keysStr),
373
- escapeCSVField(errorKeysStr),
374
- escapeCSVField(middlewareStr),
375
- ].join(','));
376
- break;
377
- }
378
- case 'Tool':
379
- await toolWriter.addRow([
380
- escapeCSVField(node.id),
381
- escapeCSVField(node.properties.name || ''),
382
- escapeCSVField(node.properties.filePath || ''),
383
- escapeCSVField(node.properties.description || ''),
384
- ].join(','));
385
- break;
386
- case 'BasicBlock':
387
- await basicBlockWriter.addRow([
388
- escapeCSVField(node.id),
389
- escapeCSVField(node.properties.filePath || ''),
390
- escapeCSVNumber(node.properties.startLine, -1),
391
- escapeCSVNumber(node.properties.endLine, -1),
392
- escapeCSVField(node.properties.text || ''),
393
- ].join(','));
394
- break;
395
- default: {
396
- // Code element nodes (Function, Class, Interface, CodeElement)
397
- const writer = codeWriterMap[node.label];
398
- if (writer) {
286
+ // try/finally so the listener bump is ALWAYS restored — including the
287
+ // rel-routing throw path (#2203 U2) and any node-writer finish() rejection,
288
+ // not just the success path (avoids leaking +40 listeners across failed runs
289
+ // in long-lived hosts / the test suite).
290
+ try {
291
+ const contentCache = new FileContentCache(repoPath);
292
+ // Create writers for every node type up-front
293
+ const fileWriter = new BufferedCSVWriter(path.join(csvDir, 'file.csv'), 'id,name,filePath,content');
294
+ const folderWriter = new BufferedCSVWriter(path.join(csvDir, 'folder.csv'), 'id,name,filePath');
295
+ const codeElementHeader = 'id,name,filePath,startLine,endLine,isExported,content,description';
296
+ const functionWriter = new BufferedCSVWriter(path.join(csvDir, 'function.csv'), codeElementHeader);
297
+ const classWriter = new BufferedCSVWriter(path.join(csvDir, 'class.csv'), codeElementHeader);
298
+ const interfaceWriter = new BufferedCSVWriter(path.join(csvDir, 'interface.csv'), codeElementHeader);
299
+ const methodHeader = 'id,name,filePath,startLine,endLine,isExported,content,description,parameterCount,returnType';
300
+ const methodWriter = new BufferedCSVWriter(path.join(csvDir, 'method.csv'), methodHeader);
301
+ const codeElemWriter = new BufferedCSVWriter(path.join(csvDir, 'codeelement.csv'), codeElementHeader);
302
+ const communityWriter = new BufferedCSVWriter(path.join(csvDir, 'community.csv'), 'id,label,heuristicLabel,keywords,description,enrichedBy,cohesion,symbolCount');
303
+ const processWriter = new BufferedCSVWriter(path.join(csvDir, 'process.csv'), 'id,label,heuristicLabel,processType,stepCount,communities,entryPointId,terminalId');
304
+ // Section nodes have an extra 'level' column
305
+ const sectionWriter = new BufferedCSVWriter(path.join(csvDir, 'section.csv'), 'id,name,filePath,startLine,endLine,level,content,description');
306
+ // Route nodes for API endpoint mapping
307
+ const routeWriter = new BufferedCSVWriter(path.join(csvDir, 'route.csv'), 'id,name,filePath,responseKeys,errorKeys,middleware,method');
308
+ // Tool nodes for MCP tool definitions
309
+ const toolWriter = new BufferedCSVWriter(path.join(csvDir, 'tool.csv'), 'id,name,filePath,description');
310
+ // BasicBlock nodes — taint/PDG substrate (issue #2080). No `name` column;
311
+ // blocks are identified by id + source span. Emitted by no phase yet.
312
+ const basicBlockWriter = new BufferedCSVWriter(path.join(csvDir, 'basicblock.csv'), BASICBLOCK_CSV_HEADER);
313
+ // Multi-language node types share the same CSV shape (no isExported column)
314
+ const multiLangHeader = 'id,name,filePath,startLine,endLine,content,description';
315
+ const MULTI_LANG_TYPES = [
316
+ 'Struct',
317
+ 'Enum',
318
+ 'Macro',
319
+ 'Typedef',
320
+ 'Union',
321
+ 'Namespace',
322
+ 'Trait',
323
+ 'Impl',
324
+ 'TypeAlias',
325
+ 'Const',
326
+ 'Static',
327
+ 'Variable',
328
+ 'Property',
329
+ 'Record',
330
+ 'Delegate',
331
+ 'Annotation',
332
+ 'Constructor',
333
+ 'Template',
334
+ 'Module',
335
+ ];
336
+ const propertyHeader = 'id,name,filePath,startLine,endLine,content,description,declaredType';
337
+ const multiLangWriters = new Map();
338
+ for (const t of MULTI_LANG_TYPES) {
339
+ multiLangWriters.set(t, new BufferedCSVWriter(path.join(csvDir, `${t.toLowerCase()}.csv`), t === 'Property' ? propertyHeader : multiLangHeader));
340
+ }
341
+ const codeWriterMap = {
342
+ Function: functionWriter,
343
+ Class: classWriter,
344
+ Interface: interfaceWriter,
345
+ CodeElement: codeElemWriter,
346
+ };
347
+ // Deduplicate all node types the pipeline can produce duplicate IDs across
348
+ // all symbol types (Class, Method, Function, etc.), not just File nodes.
349
+ // A single Set covering every label prevents PK violations on COPY.
350
+ const seenNodeIds = new Set();
351
+ // --- SINGLE PASS over all nodes ---
352
+ for (const node of orderedNodes(graph, sortOutput)) {
353
+ if (seenNodeIds.has(node.id))
354
+ continue;
355
+ seenNodeIds.add(node.id);
356
+ // addRow returns a promise only when it flushes; awaiting it once after the
357
+ // switch (instead of `await`-ing every addRow) skips a per-row microtask
358
+ // tick on the ~FLUSH_EVERY-1 buffered rows between flushes (#2203 U3).
359
+ let pending;
360
+ switch (node.label) {
361
+ case 'File': {
362
+ const content = await extractContent(node, contentCache);
363
+ pending = fileWriter.addRow([
364
+ escapeCSVField(node.id),
365
+ escapeCSVField(node.properties.name || ''),
366
+ escapeCSVField(node.properties.filePath || ''),
367
+ escapeCSVField(content),
368
+ ].join(','));
369
+ break;
370
+ }
371
+ case 'Folder':
372
+ pending = folderWriter.addRow([
373
+ escapeCSVField(node.id),
374
+ escapeCSVField(node.properties.name || ''),
375
+ escapeCSVField(node.properties.filePath || ''),
376
+ ].join(','));
377
+ break;
378
+ case 'Community': {
379
+ const keywords = node.properties.keywords || [];
380
+ const keywordsStr = `[${keywords.map((k) => `'${k.replace(/\\/g, '\\\\').replace(/'/g, "''").replace(/,/g, '\\,')}'`).join(',')}]`;
381
+ pending = communityWriter.addRow([
382
+ escapeCSVField(node.id),
383
+ escapeCSVField(node.properties.name || ''),
384
+ escapeCSVField(node.properties.heuristicLabel || ''),
385
+ keywordsStr,
386
+ escapeCSVField(node.properties.description || ''),
387
+ escapeCSVField(node.properties.enrichedBy || 'heuristic'),
388
+ escapeCSVNumber(node.properties.cohesion, 0),
389
+ escapeCSVNumber(node.properties.symbolCount, 0),
390
+ ].join(','));
391
+ break;
392
+ }
393
+ case 'Process': {
394
+ const communities = node.properties.communities || [];
395
+ const communitiesStr = `[${communities.map((c) => `'${c.replace(/'/g, "''")}'`).join(',')}]`;
396
+ pending = processWriter.addRow([
397
+ escapeCSVField(node.id),
398
+ escapeCSVField(node.properties.name || ''),
399
+ escapeCSVField(node.properties.heuristicLabel || ''),
400
+ escapeCSVField(node.properties.processType || ''),
401
+ escapeCSVNumber(node.properties.stepCount, 0),
402
+ escapeCSVField(communitiesStr),
403
+ escapeCSVField(node.properties.entryPointId || ''),
404
+ escapeCSVField(node.properties.terminalId || ''),
405
+ ].join(','));
406
+ break;
407
+ }
408
+ case 'Method': {
399
409
  const content = await extractContent(node, contentCache);
400
- await writer.addRow([
410
+ pending = methodWriter.addRow([
401
411
  escapeCSVField(node.id),
402
412
  escapeCSVField(node.properties.name || ''),
403
413
  escapeCSVField(node.properties.filePath || ''),
@@ -406,90 +416,194 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir) => {
406
416
  node.properties.isExported ? 'true' : 'false',
407
417
  escapeCSVField(content),
408
418
  escapeCSVField(node.properties.description || ''),
419
+ escapeCSVNumber(node.properties.parameterCount, 0),
420
+ escapeCSVField(node.properties.returnType || ''),
421
+ ].join(','));
422
+ break;
423
+ }
424
+ case 'Section': {
425
+ const content = await extractContent(node, contentCache);
426
+ pending = sectionWriter.addRow([
427
+ escapeCSVField(node.id),
428
+ escapeCSVField(node.properties.name || ''),
429
+ escapeCSVField(node.properties.filePath || ''),
430
+ escapeCSVNumber(node.properties.startLine, -1),
431
+ escapeCSVNumber(node.properties.endLine, -1),
432
+ escapeCSVNumber(node.properties.level, 1),
433
+ escapeCSVField(content),
434
+ escapeCSVField(node.properties.description || ''),
435
+ ].join(','));
436
+ break;
437
+ }
438
+ case 'Route': {
439
+ const responseKeys = node.properties.responseKeys || [];
440
+ // LadybugDB array literal inside a quoted CSV field: escapeCSVField wraps in "..."
441
+ // and the array uses single-quoted elements
442
+ const keysStr = `[${responseKeys.map((k) => `'${k.replace(/'/g, "''")}'`).join(',')}]`;
443
+ const errorKeys = node.properties.errorKeys || [];
444
+ const errorKeysStr = `[${errorKeys.map((k) => `'${k.replace(/'/g, "''")}'`).join(',')}]`;
445
+ const middleware = node.properties.middleware || [];
446
+ const middlewareStr = `[${middleware.map((m) => `'${m.replace(/'/g, "''")}'`).join(',')}]`;
447
+ pending = routeWriter.addRow([
448
+ escapeCSVField(node.id),
449
+ escapeCSVField(node.properties.name || ''),
450
+ escapeCSVField(node.properties.filePath || ''),
451
+ escapeCSVField(keysStr),
452
+ escapeCSVField(errorKeysStr),
453
+ escapeCSVField(middlewareStr),
454
+ escapeCSVField(String(node.properties.method ?? '')),
409
455
  ].join(','));
456
+ break;
410
457
  }
411
- else {
412
- // Multi-language node types (Struct, Impl, Trait, Macro, etc.)
413
- const mlWriter = multiLangWriters.get(node.label);
414
- if (mlWriter) {
458
+ case 'Tool':
459
+ pending = toolWriter.addRow([
460
+ escapeCSVField(node.id),
461
+ escapeCSVField(node.properties.name || ''),
462
+ escapeCSVField(node.properties.filePath || ''),
463
+ escapeCSVField(node.properties.description || ''),
464
+ ].join(','));
465
+ break;
466
+ case 'BasicBlock':
467
+ pending = basicBlockWriter.addRow(buildBasicBlockRow(node));
468
+ break;
469
+ default: {
470
+ // Code element nodes (Function, Class, Interface, CodeElement)
471
+ const writer = codeWriterMap[node.label];
472
+ if (writer) {
415
473
  const content = await extractContent(node, contentCache);
416
- await mlWriter.addRow([
474
+ pending = writer.addRow([
417
475
  escapeCSVField(node.id),
418
476
  escapeCSVField(node.properties.name || ''),
419
477
  escapeCSVField(node.properties.filePath || ''),
420
478
  escapeCSVNumber(node.properties.startLine, -1),
421
479
  escapeCSVNumber(node.properties.endLine, -1),
480
+ node.properties.isExported ? 'true' : 'false',
422
481
  escapeCSVField(content),
423
482
  escapeCSVField(node.properties.description || ''),
424
- ...(node.label === 'Property'
425
- ? [escapeCSVField(node.properties.declaredType || '')]
426
- : []),
427
483
  ].join(','));
428
484
  }
485
+ else {
486
+ // Multi-language node types (Struct, Impl, Trait, Macro, etc.)
487
+ const mlWriter = multiLangWriters.get(node.label);
488
+ if (mlWriter) {
489
+ const content = await extractContent(node, contentCache);
490
+ pending = mlWriter.addRow([
491
+ escapeCSVField(node.id),
492
+ escapeCSVField(node.properties.name || ''),
493
+ escapeCSVField(node.properties.filePath || ''),
494
+ escapeCSVNumber(node.properties.startLine, -1),
495
+ escapeCSVNumber(node.properties.endLine, -1),
496
+ escapeCSVField(content),
497
+ escapeCSVField(node.properties.description || ''),
498
+ ...(node.label === 'Property'
499
+ ? [escapeCSVField(node.properties.declaredType || '')]
500
+ : []),
501
+ ].join(','));
502
+ }
503
+ else {
504
+ // Unknown label: not in codeWriterMap or multiLangWriters, so there
505
+ // is no CSV table for it and it is intentionally NOT persisted —
506
+ // `pending` stays undefined, so the loop awaits nothing. Made
507
+ // explicit so a future node type isn't silently dropped here: wire
508
+ // it into one of the writer maps above (or this branch).
509
+ }
510
+ }
511
+ break;
429
512
  }
430
- break;
431
513
  }
514
+ if (pending)
515
+ await pending;
432
516
  }
433
- }
434
- // Finish all node writers
435
- const allWriters = [
436
- fileWriter,
437
- folderWriter,
438
- functionWriter,
439
- classWriter,
440
- interfaceWriter,
441
- methodWriter,
442
- codeElemWriter,
443
- communityWriter,
444
- processWriter,
445
- sectionWriter,
446
- routeWriter,
447
- toolWriter,
448
- basicBlockWriter,
449
- ...multiLangWriters.values(),
450
- ];
451
- await Promise.all(allWriters.map((w) => w.finish()));
452
- // --- Stream relationship CSV ---
453
- const relCsvPath = path.join(csvDir, 'relations.csv');
454
- const relWriter = new BufferedCSVWriter(relCsvPath, 'from,to,type,confidence,reason,step');
455
- for (const rel of orderedRelationships(graph, sortOutput)) {
456
- await relWriter.addRow([
457
- escapeCSVField(rel.sourceId),
458
- escapeCSVField(rel.targetId),
459
- escapeCSVField(rel.type),
460
- escapeCSVNumber(rel.confidence, 1.0),
461
- escapeCSVField(rel.reason),
462
- escapeCSVNumber(rel.step, 0),
463
- ].join(','));
464
- }
465
- await relWriter.finish();
466
- // Build result map — only include tables that have rows
467
- const nodeFiles = new Map();
468
- const tableMap = [
469
- ['File', fileWriter],
470
- ['Folder', folderWriter],
471
- ['Function', functionWriter],
472
- ['Class', classWriter],
473
- ['Interface', interfaceWriter],
474
- ['Method', methodWriter],
475
- ['CodeElement', codeElemWriter],
476
- ['Community', communityWriter],
477
- ['Process', processWriter],
478
- ['Section', sectionWriter],
479
- ['Route', routeWriter],
480
- ['Tool', toolWriter],
481
- ['BasicBlock', basicBlockWriter],
482
- ...Array.from(multiLangWriters.entries()).map(([name, w]) => [name, w]),
483
- ];
484
- for (const [name, writer] of tableMap) {
485
- if (writer.rows > 0) {
486
- nodeFiles.set(name, {
487
- csvPath: path.join(csvDir, `${name.toLowerCase()}.csv`),
488
- rows: writer.rows,
489
- });
517
+ // Finish all node writers
518
+ const allWriters = [
519
+ fileWriter,
520
+ folderWriter,
521
+ functionWriter,
522
+ classWriter,
523
+ interfaceWriter,
524
+ methodWriter,
525
+ codeElemWriter,
526
+ communityWriter,
527
+ processWriter,
528
+ sectionWriter,
529
+ routeWriter,
530
+ toolWriter,
531
+ basicBlockWriter,
532
+ ...multiLangWriters.values(),
533
+ ];
534
+ await Promise.all(allWriters.map((w) => w.finish()));
535
+ // Build the node-file manifest now (all writers are flushed; `.rows` is
536
+ // final). Hoisted above the relationship pass so `onNodePhaseComplete` can
537
+ // hand the caller a complete node manifest to start COPY-ing while we keep
538
+ // generating relationship CSVs below (#2203 overlap). The same map is
539
+ // returned, so the result is unchanged when no callback is supplied.
540
+ const nodeFiles = new Map();
541
+ const tableMap = [
542
+ ['File', fileWriter],
543
+ ['Folder', folderWriter],
544
+ ['Function', functionWriter],
545
+ ['Class', classWriter],
546
+ ['Interface', interfaceWriter],
547
+ ['Method', methodWriter],
548
+ ['CodeElement', codeElemWriter],
549
+ ['Community', communityWriter],
550
+ ['Process', processWriter],
551
+ ['Section', sectionWriter],
552
+ ['Route', routeWriter],
553
+ ['Tool', toolWriter],
554
+ ['BasicBlock', basicBlockWriter],
555
+ ...Array.from(multiLangWriters.entries()).map(([name, w]) => [name, w]),
556
+ ];
557
+ for (const [name, writer] of tableMap) {
558
+ if (writer.rows > 0) {
559
+ nodeFiles.set(name, {
560
+ csvPath: path.join(csvDir, `${name.toLowerCase()}.csv`),
561
+ rows: writer.rows,
562
+ });
563
+ }
564
+ }
565
+ // Node CSVs are on disk; relationship CSVs have not been touched yet. Hand
566
+ // the manifest to the caller (not awaited the rel pass runs concurrently).
567
+ onNodePhaseComplete?.(nodeFiles);
568
+ // --- Stream relationships directly to per-FROM→TO-label-pair files ---
569
+ // (#2203 U2) Route every edge to its pair file in this single pass. The old
570
+ // monolithic relations.csv — and its line-by-line re-read + per-edge regex
571
+ // re-split in loadGraphToLbug — are gone, so the ~1M-edge set is written and
572
+ // read once instead of twice. The router applies the SAME label-derivation +
573
+ // validTables filter as the legacy splitRelCsvByLabelPair, so the per-pair
574
+ // files are byte-identical (asserted by the differential test).
575
+ const relRouter = new RelPairRouter(csvDir, REL_CSV_HEADER, new Set(NODE_TABLES));
576
+ try {
577
+ let emitted = 0;
578
+ for (const rel of orderedRelationships(graph, sortOutput)) {
579
+ const pending = relRouter.route(rel.sourceId, rel.targetId, buildRelRow(rel));
580
+ if (pending)
581
+ await pending;
582
+ // Periodically hand the event loop back so the overlapped node COPY and
583
+ // write-stream drains run instead of starving behind this synchronous
584
+ // loop (#2226 F4). No effect on emitted bytes — pure scheduling.
585
+ if (++emitted % REL_YIELD_EVERY === 0)
586
+ await new Promise((r) => setImmediate(r));
587
+ }
588
+ await relRouter.close();
490
589
  }
590
+ catch (err) {
591
+ relRouter.destroy();
592
+ // Rethrow the real stream error (EMFILE / disk-full) rather than the generic
593
+ // AbortError a pending drain-await rejects with — mirrors the retained
594
+ // splitRelCsvByLabelPair's `throw streamError ?? err`.
595
+ throw relRouter.lastError ?? err;
596
+ }
597
+ return {
598
+ nodeFiles,
599
+ relsByPair: relRouter.byPair,
600
+ relHeader: REL_CSV_HEADER,
601
+ skippedRels: relRouter.skipped,
602
+ totalValidRels: relRouter.total,
603
+ };
604
+ }
605
+ finally {
606
+ // Restore original process listener limit on every path (success or throw).
607
+ process.setMaxListeners(prevMax);
491
608
  }
492
- // Restore original process listener limit
493
- process.setMaxListeners(prevMax);
494
- return { nodeFiles, relCsvPath, relRows: relWriter.rows };
495
609
  };