gitnexus 1.6.5-rc.2 → 1.6.5-rc.21

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 (288) hide show
  1. package/README.md +1 -1
  2. package/dist/_shared/scope-resolution/method-dispatch-index.d.ts +26 -0
  3. package/dist/_shared/scope-resolution/method-dispatch-index.d.ts.map +1 -1
  4. package/dist/_shared/scope-resolution/method-dispatch-index.js +22 -3
  5. package/dist/_shared/scope-resolution/method-dispatch-index.js.map +1 -1
  6. package/dist/_shared/scope-resolution/registries/lookup-core.js +18 -1
  7. package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -1
  8. package/dist/cli/ai-context.d.ts +1 -0
  9. package/dist/cli/ai-context.js +30 -12
  10. package/dist/cli/analyze.d.ts +18 -0
  11. package/dist/cli/analyze.js +33 -4
  12. package/dist/cli/augment.d.ts +1 -1
  13. package/dist/cli/augment.js +1 -1
  14. package/dist/cli/index.js +6 -1
  15. package/dist/cli/setup.js +6 -0
  16. package/dist/core/augmentation/engine.d.ts +2 -2
  17. package/dist/core/augmentation/engine.js +26 -6
  18. package/dist/core/embeddings/ast-utils.js +2 -1
  19. package/dist/core/embeddings/http-client.js +22 -6
  20. package/dist/core/group/extractors/grpc-extractor.js +2 -1
  21. package/dist/core/group/extractors/http-patterns/python.js +175 -0
  22. package/dist/core/group/extractors/http-route-extractor.js +2 -1
  23. package/dist/core/group/extractors/include-extractor.js +2 -1
  24. package/dist/core/group/extractors/thrift-extractor.js +2 -1
  25. package/dist/core/group/extractors/tree-sitter-scanner.js +2 -1
  26. package/dist/core/incremental/shadow-candidates.d.ts +44 -0
  27. package/dist/core/incremental/shadow-candidates.js +74 -0
  28. package/dist/core/incremental/subgraph-extract.d.ts +64 -0
  29. package/dist/core/incremental/subgraph-extract.js +111 -0
  30. package/dist/core/ingestion/call-processor.js +166 -47
  31. package/dist/core/ingestion/community-processor.js +18 -0
  32. package/dist/core/ingestion/heritage-processor.js +3 -2
  33. package/dist/core/ingestion/import-processor.js +2 -1
  34. package/dist/core/ingestion/import-resolvers/standard.d.ts +5 -0
  35. package/dist/core/ingestion/import-resolvers/standard.js +27 -1
  36. package/dist/core/ingestion/import-resolvers/utils.js +4 -0
  37. package/dist/core/ingestion/languages/c/arity-metadata.d.ts +14 -0
  38. package/dist/core/ingestion/languages/c/arity-metadata.js +94 -0
  39. package/dist/core/ingestion/languages/c/arity.d.ts +6 -0
  40. package/dist/core/ingestion/languages/c/arity.js +18 -0
  41. package/dist/core/ingestion/languages/c/captures.d.ts +2 -0
  42. package/dist/core/ingestion/languages/c/captures.js +105 -0
  43. package/dist/core/ingestion/languages/c/header-scan.d.ts +7 -0
  44. package/dist/core/ingestion/languages/c/header-scan.js +55 -0
  45. package/dist/core/ingestion/languages/c/import-decomposer.d.ts +8 -0
  46. package/dist/core/ingestion/languages/c/import-decomposer.js +50 -0
  47. package/dist/core/ingestion/languages/c/import-target.d.ts +14 -0
  48. package/dist/core/ingestion/languages/c/import-target.js +57 -0
  49. package/dist/core/ingestion/languages/c/index.d.ts +11 -0
  50. package/dist/core/ingestion/languages/c/index.js +11 -0
  51. package/dist/core/ingestion/languages/c/interpret.d.ts +14 -0
  52. package/dist/core/ingestion/languages/c/interpret.js +48 -0
  53. package/dist/core/ingestion/languages/c/merge-bindings.d.ts +7 -0
  54. package/dist/core/ingestion/languages/c/merge-bindings.js +23 -0
  55. package/dist/core/ingestion/languages/c/query.d.ts +3 -0
  56. package/dist/core/ingestion/languages/c/query.js +161 -0
  57. package/dist/core/ingestion/languages/c/scope-resolver.d.ts +13 -0
  58. package/dist/core/ingestion/languages/c/scope-resolver.js +60 -0
  59. package/dist/core/ingestion/languages/c/simple-hooks.d.ts +14 -0
  60. package/dist/core/ingestion/languages/c/simple-hooks.js +19 -0
  61. package/dist/core/ingestion/languages/c/static-linkage.d.ts +13 -0
  62. package/dist/core/ingestion/languages/c/static-linkage.js +57 -0
  63. package/dist/core/ingestion/languages/c-cpp.js +10 -0
  64. package/dist/core/ingestion/languages/csharp/captures.js +2 -1
  65. package/dist/core/ingestion/languages/csharp/namespace-siblings.js +3 -2
  66. package/dist/core/ingestion/languages/go/captures.js +2 -1
  67. package/dist/core/ingestion/languages/go/range-binding.js +2 -1
  68. package/dist/core/ingestion/languages/java/arity-metadata.d.ts +18 -0
  69. package/dist/core/ingestion/languages/java/arity-metadata.js +40 -0
  70. package/dist/core/ingestion/languages/java/arity.d.ts +10 -0
  71. package/dist/core/ingestion/languages/java/arity.js +24 -0
  72. package/dist/core/ingestion/languages/java/cache-stats.d.ts +15 -0
  73. package/dist/core/ingestion/languages/java/cache-stats.js +26 -0
  74. package/dist/core/ingestion/languages/java/captures.d.ts +17 -0
  75. package/dist/core/ingestion/languages/java/captures.js +187 -0
  76. package/dist/core/ingestion/languages/java/import-decomposer.d.ts +18 -0
  77. package/dist/core/ingestion/languages/java/import-decomposer.js +85 -0
  78. package/dist/core/ingestion/languages/java/import-target.d.ts +17 -0
  79. package/dist/core/ingestion/languages/java/import-target.js +100 -0
  80. package/dist/core/ingestion/languages/java/index.d.ts +29 -0
  81. package/dist/core/ingestion/languages/java/index.js +29 -0
  82. package/dist/core/ingestion/languages/java/interpret.d.ts +13 -0
  83. package/dist/core/ingestion/languages/java/interpret.js +131 -0
  84. package/dist/core/ingestion/languages/java/merge-bindings.d.ts +12 -0
  85. package/dist/core/ingestion/languages/java/merge-bindings.js +40 -0
  86. package/dist/core/ingestion/languages/java/query.d.ts +30 -0
  87. package/dist/core/ingestion/languages/java/query.js +192 -0
  88. package/dist/core/ingestion/languages/java/receiver-binding.d.ts +11 -0
  89. package/dist/core/ingestion/languages/java/receiver-binding.js +95 -0
  90. package/dist/core/ingestion/languages/java/scope-resolver.d.ts +50 -0
  91. package/dist/core/ingestion/languages/java/scope-resolver.js +74 -0
  92. package/dist/core/ingestion/languages/java/simple-hooks.d.ts +13 -0
  93. package/dist/core/ingestion/languages/java/simple-hooks.js +34 -0
  94. package/dist/core/ingestion/languages/java.js +11 -0
  95. package/dist/core/ingestion/languages/php/arity-metadata.d.ts +28 -0
  96. package/dist/core/ingestion/languages/php/arity-metadata.js +63 -0
  97. package/dist/core/ingestion/languages/php/arity.d.ts +25 -0
  98. package/dist/core/ingestion/languages/php/arity.js +40 -0
  99. package/dist/core/ingestion/languages/php/cache-stats.d.ts +15 -0
  100. package/dist/core/ingestion/languages/php/cache-stats.js +26 -0
  101. package/dist/core/ingestion/languages/php/captures.d.ts +34 -0
  102. package/dist/core/ingestion/languages/php/captures.js +739 -0
  103. package/dist/core/ingestion/languages/php/import-decomposer.d.ts +28 -0
  104. package/dist/core/ingestion/languages/php/import-decomposer.js +265 -0
  105. package/dist/core/ingestion/languages/php/import-target.d.ts +47 -0
  106. package/dist/core/ingestion/languages/php/import-target.js +100 -0
  107. package/dist/core/ingestion/languages/php/index.d.ts +68 -0
  108. package/dist/core/ingestion/languages/php/index.js +72 -0
  109. package/dist/core/ingestion/languages/php/interpret.d.ts +36 -0
  110. package/dist/core/ingestion/languages/php/interpret.js +241 -0
  111. package/dist/core/ingestion/languages/php/merge-bindings.d.ts +19 -0
  112. package/dist/core/ingestion/languages/php/merge-bindings.js +47 -0
  113. package/dist/core/ingestion/languages/php/namespace-siblings.d.ts +51 -0
  114. package/dist/core/ingestion/languages/php/namespace-siblings.js +288 -0
  115. package/dist/core/ingestion/languages/php/query.d.ts +32 -0
  116. package/dist/core/ingestion/languages/php/query.js +326 -0
  117. package/dist/core/ingestion/languages/php/receiver-binding.d.ts +36 -0
  118. package/dist/core/ingestion/languages/php/receiver-binding.js +128 -0
  119. package/dist/core/ingestion/languages/php/scope-resolver.d.ts +23 -0
  120. package/dist/core/ingestion/languages/php/scope-resolver.js +358 -0
  121. package/dist/core/ingestion/languages/php/simple-hooks.d.ts +42 -0
  122. package/dist/core/ingestion/languages/php/simple-hooks.js +111 -0
  123. package/dist/core/ingestion/languages/php.d.ts +0 -7
  124. package/dist/core/ingestion/languages/php.js +15 -0
  125. package/dist/core/ingestion/languages/python/captures.js +2 -1
  126. package/dist/core/ingestion/languages/typescript/captures.js +2 -1
  127. package/dist/core/ingestion/parsing-processor.d.ts +22 -2
  128. package/dist/core/ingestion/parsing-processor.js +85 -50
  129. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +5 -0
  130. package/dist/core/ingestion/pipeline-phases/parse-impl.js +119 -11
  131. package/dist/core/ingestion/pipeline-phases/parse.d.ts +14 -0
  132. package/dist/core/ingestion/pipeline.d.ts +13 -0
  133. package/dist/core/ingestion/registry-primary-flag.js +2 -0
  134. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +65 -0
  135. package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.d.ts +1 -1
  136. package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.js +12 -2
  137. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +5 -0
  138. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +25 -1
  139. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +79 -7
  140. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +7 -3
  141. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +24 -4
  142. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +21 -2
  143. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +13 -1
  144. package/dist/core/ingestion/scope-resolution/pipeline/registry.js +6 -0
  145. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +17 -0
  146. package/dist/core/ingestion/scope-resolution/pipeline/run.js +31 -7
  147. package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
  148. package/dist/core/ingestion/tree-sitter-queries.js +10 -0
  149. package/dist/core/ingestion/workers/parse-worker.js +2 -1
  150. package/dist/core/lbug/lbug-adapter.d.ts +26 -0
  151. package/dist/core/lbug/lbug-adapter.js +174 -40
  152. package/dist/core/lbug/pool-adapter.js +19 -2
  153. package/dist/core/run-analyze.d.ts +2 -0
  154. package/dist/core/run-analyze.js +323 -29
  155. package/dist/core/tree-sitter/safe-parse.d.ts +6 -0
  156. package/dist/core/tree-sitter/safe-parse.js +32 -0
  157. package/dist/server/git-clone.js +10 -13
  158. package/dist/storage/file-hash.d.ts +47 -0
  159. package/dist/storage/file-hash.js +86 -0
  160. package/dist/storage/git.d.ts +17 -6
  161. package/dist/storage/git.js +46 -12
  162. package/dist/storage/parse-cache.d.ts +67 -0
  163. package/dist/storage/parse-cache.js +182 -0
  164. package/dist/storage/repo-manager.d.ts +41 -1
  165. package/dist/storage/repo-manager.js +17 -2
  166. package/hooks/claude/gitnexus-hook.cjs +8 -1
  167. package/hooks/claude/hook-lock.cjs +119 -0
  168. package/package.json +1 -1
  169. package/web/assets/{agent-BpHQleHE.js → agent-BG6RCOzz.js} +1 -1
  170. package/web/assets/architecture-7EHR7CIX-6QZW5X65-F-tujre-.js +1 -0
  171. package/web/assets/architectureDiagram-UL44E2DR-2GL7nOvO.js +36 -0
  172. package/web/assets/blockDiagram-7IZFK4PR-5AjX0pPU.js +132 -0
  173. package/web/assets/{c4Diagram-DFAF54RM-DeJV1rCn.js → c4Diagram-Y2BXMSZH-hLOeq7xC.js} +2 -2
  174. package/web/assets/chunk-2T2R6R2M-B_pq_2nf.js +4 -0
  175. package/web/assets/chunk-2UTLFMKG-CpoohCFN.js +1 -0
  176. package/web/assets/{chunk-7RZVMHOQ-BdIU-RGO.js → chunk-3SSMPTDK-CfqpR3Nr.js} +1 -1
  177. package/web/assets/chunk-4R4BOZG6-D3gm7tYj.js +159 -0
  178. package/web/assets/chunk-6764PJDD-WcI965eO.js +1 -0
  179. package/web/assets/chunk-AQ6EADP3-BpMj3rQl.js +1 -0
  180. package/web/assets/{chunk-KSICW3F5-C2tZmXwv.js → chunk-AZZRMDJM-DSoCJlUA.js} +1 -1
  181. package/web/assets/chunk-C62D2QBJ-CvFF2PnB.js +1 -0
  182. package/web/assets/chunk-CEXFNPSA-DdNtJtrF.js +1 -0
  183. package/web/assets/chunk-J5EP6P6S-DtcVaAJI.js +1 -0
  184. package/web/assets/{chunk-AEOMTBSW-D7qjBMHW.js → chunk-JQRUD6KW-DElaNjc0.js} +1 -1
  185. package/web/assets/chunk-KGYTTC2M-D0K5or7e.js +1 -0
  186. package/web/assets/chunk-KRXBNO2N-DpR8iDt8.js +1 -0
  187. package/web/assets/chunk-LCXTWHL2-DdMObOEk.js +231 -0
  188. package/web/assets/chunk-LII3EMHJ-I78zXtzi.js +1 -0
  189. package/web/assets/chunk-RERM46MO-Betu1cSy.js +1 -0
  190. package/web/assets/chunk-RG4AUYOV-BUCJ2JP5.js +206 -0
  191. package/web/assets/chunk-RKZBBQEN-Cutpza0t.js +1 -0
  192. package/web/assets/chunk-RLI5ZMPA-BFUxCvX2.js +1 -0
  193. package/web/assets/chunk-T5OCTHI4-DKwlkuvB.js +1 -0
  194. package/web/assets/chunk-UP6H54XL-0YWa0NDg.js +1 -0
  195. package/web/assets/chunk-UXSXWOXI-CSz0OXpz.js +1 -0
  196. package/web/assets/chunk-W44A43WB-AOmgoT-X.js +1 -0
  197. package/web/assets/{chunk-RWUO3TPN-DTWzAhQ1.js → chunk-ZXARS5L4-DIzgxjMw.js} +1 -1
  198. package/web/assets/classDiagram-KGZ6W3CR-BT-rn7LF.js +1 -0
  199. package/web/assets/classDiagram-v2-72OJOZXJ-uR3nDadY.js +1 -0
  200. package/web/assets/{cose-bilkent-PNC4W37J-DdZq7Qz_.js → cose-bilkent-UX7MHV2Q-DCSCD1TK.js} +1 -1
  201. package/web/assets/dagre-ND4H6XIP-CsciHSij.js +4 -0
  202. package/web/assets/diagram-3NCE3AQN-BKUT5Rpc.js +43 -0
  203. package/web/assets/diagram-GF46GFSD-Dxb4hZSo.js +24 -0
  204. package/web/assets/diagram-HNR7UZ2L-D3qus9Cn.js +3 -0
  205. package/web/assets/diagram-QXG6HAR7-r9BMLGGP.js +24 -0
  206. package/web/assets/diagram-WEQXMOUZ-BGXqs7-m.js +10 -0
  207. package/web/assets/{erDiagram-GCSMX5X6-DfdN6iqF.js → erDiagram-L5TCEMPS-LgSWVrkZ.js} +2 -2
  208. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-By7r3bla.js +1 -0
  209. package/web/assets/flowDiagram-H6V6AXG4-Bj_vV5ky.js +162 -0
  210. package/web/assets/ganttDiagram-JCBTUEKG-B1eVITSh.js +292 -0
  211. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-ClEP6RdE.js +1 -0
  212. package/web/assets/gitGraphDiagram-S2ZK5IYY-BP0R-_FD.js +106 -0
  213. package/web/assets/{index-3NUCUW2s.js → index-oL-ZNYwb.js} +80 -81
  214. package/web/assets/info-J43DQDTF-KCYPFFUO-bBJRjmP5.js +1 -0
  215. package/web/assets/infoDiagram-3YFTVSEB-Dmj4OEO3.js +2 -0
  216. package/web/assets/{ishikawaDiagram-YMYX4NHK-BF8AtDaj.js → ishikawaDiagram-BNXS4ZKH-B3NgQ4lJ.js} +2 -2
  217. package/web/assets/{journeyDiagram-SO5T7YLQ-BW8oKa3N.js → journeyDiagram-M6C3CM3L-DALmL4_N.js} +3 -3
  218. package/web/assets/{kanban-definition-LJHFXRCJ-DzbOsR-2.js → kanban-definition-75IXJCU3-AvVbHpnN.js} +4 -4
  219. package/web/assets/{katex-GD7MH7QM-CJiOjBBJ.js → katex-K3KEBU37-CqF6_ZN-.js} +1 -1
  220. package/web/assets/{mindmap-definition-2EUWGEK5-BIXGQALq.js → mindmap-definition-2TDM6QVE-B5c9VOzs.js} +28 -28
  221. package/web/assets/packet-YPE3B663-LP52Z2RK-1ZCldnu3.js +1 -0
  222. package/web/assets/pie-LRSECV5Y-TCRJHUBD-EhjHC5EE.js +1 -0
  223. package/web/assets/pieDiagram-CU6KROY3-Po2HSSR4.js +30 -0
  224. package/web/assets/quadrantDiagram-VICAPDV7-C47UxSZD.js +7 -0
  225. package/web/assets/radar-GUYGQ44K-RDLRG3WG-CvXjgxlW.js +1 -0
  226. package/web/assets/{requirementDiagram-M5DCFWZL-CzUUrhQD.js → requirementDiagram-JXO7QTGE-CpECN_Hq.js} +6 -6
  227. package/web/assets/sankeyDiagram-URQDO5SZ-B3b7cLrS.js +40 -0
  228. package/web/assets/sequenceDiagram-VS2MUI6T-CRJ95oVP.js +162 -0
  229. package/web/assets/stateDiagram-7D4R322I-C7U9b3ks.js +1 -0
  230. package/web/assets/stateDiagram-v2-36443NZ5-BQajbtov.js +1 -0
  231. package/web/assets/{timeline-definition-5SPVSISX-DkMiGj4Z.js → timeline-definition-O6YCAMPW-rtbk6BBo.js} +4 -4
  232. package/web/assets/treeView-BLDUP644-QA4HXRO3-R2o5gwfP.js +1 -0
  233. package/web/assets/treemap-LRROVOQU-LLAWBHMP-Cesmac_u.js +1 -0
  234. package/web/assets/{vennDiagram-IE5QUKF5-BCxMmf9q.js → vennDiagram-MWXL3ELB-W8Yoaayh.js} +3 -3
  235. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-B9HYoRgA.js +1 -0
  236. package/web/assets/wardleyDiagram-CUQ6CDDI-DIZw5Abj.js +78 -0
  237. package/web/assets/{xychartDiagram-ZHJ5623Y-DZ7fP1_3.js → xychartDiagram-N2JHSOCM-DGRtrj4P.js} +3 -3
  238. package/web/index.html +2 -2
  239. package/web/assets/architecture-YZFGNWBL-S5CXDPWN-BUzkWgDl.js +0 -1
  240. package/web/assets/architectureDiagram-EMZXCZ2Q-CXbzok1G.js +0 -36
  241. package/web/assets/blockDiagram-IGV67L2C-DA1QJ4ZB.js +0 -132
  242. package/web/assets/chunk-3GS5O3IE-B8hpnia8.js +0 -231
  243. package/web/assets/chunk-3YCYZ6SJ-B-BVu21C.js +0 -1
  244. package/web/assets/chunk-6NTNNK5N-DW-jYSDr.js +0 -1
  245. package/web/assets/chunk-A34GCYZU-BbZl-IKy.js +0 -1
  246. package/web/assets/chunk-DJ7UZH7F-B5tMfF87.js +0 -1
  247. package/web/assets/chunk-DKKBVRCY-Djm-6K_e.js +0 -4
  248. package/web/assets/chunk-DU5LTGQ6-QPoynYcp.js +0 -1
  249. package/web/assets/chunk-FXACKDTF-jieSmbe2.js +0 -159
  250. package/web/assets/chunk-H3VCZNTA-8EMHZ3SV.js +0 -1
  251. package/web/assets/chunk-HN6EAY2L-CgE_agsD.js +0 -1
  252. package/web/assets/chunk-O5ABG6QK-DEZV1O19.js +0 -1
  253. package/web/assets/chunk-PK6DOVAG-BXv0JnsJ.js +0 -206
  254. package/web/assets/chunk-RNJOYNJ4-BiBkF9dN.js +0 -1
  255. package/web/assets/chunk-TBF5ZNIQ-BSl6s9lT.js +0 -1
  256. package/web/assets/chunk-TU3PZOEN-DE5Qhc0N.js +0 -1
  257. package/web/assets/chunk-TYMNRAUI-D1NDLIMG.js +0 -1
  258. package/web/assets/chunk-VELTKBKT-C9dVN39o.js +0 -1
  259. package/web/assets/chunk-W7ZLLLMY-Bu-cdLzs.js +0 -1
  260. package/web/assets/chunk-WSB5WSVC-Dor71SOz.js +0 -1
  261. package/web/assets/chunk-XGPFEOL4-CUonLRle.js +0 -1
  262. package/web/assets/classDiagram-PPOCWD7C-Cdd6UdVv.js +0 -1
  263. package/web/assets/classDiagram-v2-23LJLIIU-DNhxY2Ib.js +0 -1
  264. package/web/assets/dagre-E77IOHMT-Cfj_6e17.js +0 -4
  265. package/web/assets/diagram-H7BISOXX-BNvpsrBv.js +0 -43
  266. package/web/assets/diagram-JC5VWROH-Cn0rtDbJ.js +0 -24
  267. package/web/assets/diagram-LXUTUG65-CHfoVKNm.js +0 -10
  268. package/web/assets/diagram-WEHSV5V5-BLxHksnu.js +0 -24
  269. package/web/assets/flowDiagram-OTCZ4VVT-aAZw4c_M.js +0 -162
  270. package/web/assets/ganttDiagram-MUNLMDZQ-BEfC_7Or.js +0 -292
  271. package/web/assets/gitGraph-7Q5UKJZL-54BCDZD5-B6ZeRLP0.js +0 -1
  272. package/web/assets/gitGraphDiagram-3HKGZ4G3-CG0kC8Q5.js +0 -106
  273. package/web/assets/info-OMHHGYJF-BF2H5H6G-BIOsZy0W.js +0 -1
  274. package/web/assets/infoDiagram-MN7RKWGX-DUoMH-pq.js +0 -2
  275. package/web/assets/packet-4T2RLAQJ-EV4IVRXR-Bs7ysNMU.js +0 -1
  276. package/web/assets/pie-ZZUOXDRM-N23DN5KN-Csi8nnbH.js +0 -1
  277. package/web/assets/pieDiagram-3IATQBI2-QY-u7P6a.js +0 -30
  278. package/web/assets/quadrantDiagram-E256RVCF-Di4aNiU8.js +0 -7
  279. package/web/assets/radar-PYXPWWZC-P6TP7ZYP-DJlyXh2-.js +0 -1
  280. package/web/assets/sankeyDiagram-L3NBLAOT-D2fbMiIU.js +0 -10
  281. package/web/assets/sequenceDiagram-ZOUHS735-BNdkqguh.js +0 -157
  282. package/web/assets/stateDiagram-MLPALWAM-51_Q2w2L.js +0 -1
  283. package/web/assets/stateDiagram-v2-B5LQ5ZB2-8nHs2aNE.js +0 -1
  284. package/web/assets/treeView-SZITEDCU-5DXDK3XO-Cy6P0_CZ.js +0 -1
  285. package/web/assets/treemap-W4RFUUIX-WYLRDWKO-C_pp1R7A.js +0 -1
  286. package/web/assets/wardley-RL74JXVD-BCRCBASE-CMStJhpn.js +0 -1
  287. package/web/assets/wardleyDiagram-XU3VSMPF-ijlLF77s.js +0 -20
  288. /package/web/assets/{context-builder-CqQNhRj1.js → context-builder-CG-ydtp4.js} +0 -0
@@ -3,6 +3,7 @@ import { glob } from 'glob';
3
3
  import Parser from 'tree-sitter';
4
4
  import { createIgnoreFilter } from '../../../config/ignore-service.js';
5
5
  import { readSafe } from './fs-utils.js';
6
+ import { parseSourceSafe } from '../../tree-sitter/safe-parse.js';
6
7
  import { logger } from '../../logger.js';
7
8
  import { GRPC_SCAN_GLOB, getPluginForFile, hasProtoPlugin, } from './grpc-patterns/index.js';
8
9
  /**
@@ -352,7 +353,7 @@ export class GrpcExtractor {
352
353
  let detections = [];
353
354
  try {
354
355
  parser.setLanguage(plugin.language);
355
- const tree = parser.parse(content);
356
+ const tree = parseSourceSafe(parser, content);
356
357
  detections = plugin.scan(tree);
357
358
  }
358
359
  catch {
@@ -5,6 +5,7 @@ import { compilePatterns, runCompiledPatterns, unquoteLiteral, } from '../tree-s
5
5
  * - FastAPI `@app.get("/path")` provider decorators
6
6
  * - `requests.get/post/...("url")` consumer calls
7
7
  * - Generic `requests.request("METHOD", "url")` consumer calls
8
+ * - `httpx.AsyncClient` instances calling `.get/.post/...("url")`
8
9
  */
9
10
  const FASTAPI_VERBS = {
10
11
  get: 'GET',
@@ -65,11 +66,142 @@ const REQUESTS_GENERIC_PATTERNS = compilePatterns({
65
66
  },
66
67
  ],
67
68
  });
69
+ // ─── Consumer: httpx.AsyncClient assignments ────────────────────────
70
+ // NOTE: This targeted detector only tracks explicit `httpx.AsyncClient(...)`
71
+ // construction. Direct imports (`from httpx import AsyncClient`) and module
72
+ // aliases (`import httpx as hx`) and annotated assignments (`client: httpx.AsyncClient = ...`)
73
+ // are intentionally left for a follow-up. Module-scope clients are only matched
74
+ // at module scope; calls inside functions require a function/class-local tracked
75
+ // client to avoid false positives from same-name local variables.
76
+ const HTTPX_ASYNC_CLIENT_ASSIGN_PATTERNS = compilePatterns({
77
+ name: 'python-httpx-async-client-assign',
78
+ language: Python,
79
+ patterns: [
80
+ {
81
+ meta: {},
82
+ query: `
83
+ (assignment
84
+ left: (_) @client
85
+ right: (call
86
+ function: (attribute
87
+ object: (identifier) @module (#eq? @module "httpx")
88
+ attribute: (identifier) @client_class (#eq? @client_class "AsyncClient"))))
89
+ `,
90
+ },
91
+ ],
92
+ });
93
+ // ─── Consumer: async with httpx.AsyncClient() as client ──────────────
94
+ const HTTPX_ASYNC_CLIENT_WITH_ALIAS_PATTERNS = compilePatterns({
95
+ name: 'python-httpx-async-client-with-alias',
96
+ language: Python,
97
+ patterns: [
98
+ {
99
+ meta: {},
100
+ query: `
101
+ (as_pattern
102
+ (call
103
+ function: (attribute
104
+ object: (identifier) @module (#eq? @module "httpx")
105
+ attribute: (identifier) @client_class (#eq? @client_class "AsyncClient")))
106
+ (as_pattern_target (identifier) @client))
107
+ `,
108
+ },
109
+ ],
110
+ });
111
+ function getScopeKey(node, preferClass = false) {
112
+ if (preferClass) {
113
+ let current = node;
114
+ while (current) {
115
+ if (current.type === 'class_definition') {
116
+ return `class:${current.startIndex}:${current.endIndex}`;
117
+ }
118
+ current = current.parent;
119
+ }
120
+ }
121
+ let current = node;
122
+ while (current) {
123
+ if (current.type === 'function_definition') {
124
+ return `function:${current.startIndex}:${current.endIndex}`;
125
+ }
126
+ current = current.parent;
127
+ }
128
+ return 'module';
129
+ }
130
+ function trackedClientScopeKey(clientNode) {
131
+ return getScopeKey(clientNode.parent, clientNode.text.includes('.'));
132
+ }
133
+ function callScopeKeys(clientNode) {
134
+ const keys = new Set();
135
+ const preferClass = clientNode.text.includes('.');
136
+ const nearestScope = getScopeKey(clientNode.parent, preferClass);
137
+ keys.add(nearestScope);
138
+ return [...keys];
139
+ }
140
+ function collectHttpxAsyncClients(tree) {
141
+ const clients = new Map();
142
+ const addClient = (clientNode) => {
143
+ if (!clientNode)
144
+ return;
145
+ const scopeKey = trackedClientScopeKey(clientNode);
146
+ const clientText = clientNode.text;
147
+ const scopes = clients.get(clientText) ?? new Set();
148
+ scopes.add(scopeKey);
149
+ clients.set(clientText, scopes);
150
+ };
151
+ for (const match of runCompiledPatterns(HTTPX_ASYNC_CLIENT_ASSIGN_PATTERNS, tree)) {
152
+ addClient(match.captures.client);
153
+ }
154
+ for (const match of runCompiledPatterns(HTTPX_ASYNC_CLIENT_WITH_ALIAS_PATTERNS, tree)) {
155
+ addClient(match.captures.client);
156
+ }
157
+ return clients;
158
+ }
159
+ function hasTrackedHttpxAsyncClient(clients, clientNode) {
160
+ const scopes = clients.get(clientNode.text);
161
+ if (!scopes)
162
+ return false;
163
+ return callScopeKeys(clientNode).some((scopeKey) => scopes.has(scopeKey));
164
+ }
165
+ // ─── Consumer: httpx AsyncClient .get/.post/...("url") ──────────────
166
+ const HTTPX_ASYNC_CLIENT_VERB_PATTERNS = compilePatterns({
167
+ name: 'python-httpx-async-client-verb',
168
+ language: Python,
169
+ patterns: [
170
+ {
171
+ meta: {},
172
+ query: `
173
+ (call
174
+ function: (attribute
175
+ object: (_) @client
176
+ attribute: (identifier) @method (#match? @method "^(get|post|put|delete|patch)$"))
177
+ arguments: (argument_list . (string) @path))
178
+ `,
179
+ },
180
+ ],
181
+ });
182
+ // ─── Consumer: httpx AsyncClient .request("METHOD", "url") ─────────
183
+ const HTTPX_ASYNC_CLIENT_GENERIC_PATTERNS = compilePatterns({
184
+ name: 'python-httpx-async-client-generic',
185
+ language: Python,
186
+ patterns: [
187
+ {
188
+ meta: {},
189
+ query: `
190
+ (call
191
+ function: (attribute
192
+ object: (_) @client
193
+ attribute: (identifier) @method (#eq? @method "request"))
194
+ arguments: (argument_list . (string) @http_method (string) @path))
195
+ `,
196
+ },
197
+ ],
198
+ });
68
199
  export const PYTHON_HTTP_PLUGIN = {
69
200
  name: 'python-http',
70
201
  language: Python,
71
202
  scan(tree) {
72
203
  const out = [];
204
+ const httpxAsyncClients = collectHttpxAsyncClients(tree);
73
205
  // Providers: FastAPI
74
206
  for (const match of runCompiledPatterns(FASTAPI_PATTERNS, tree)) {
75
207
  const methodNode = match.captures.method;
@@ -128,6 +260,49 @@ export const PYTHON_HTTP_PLUGIN = {
128
260
  confidence: 0.7,
129
261
  });
130
262
  }
263
+ // Consumers: httpx.AsyncClient.<verb>("url")
264
+ for (const match of runCompiledPatterns(HTTPX_ASYNC_CLIENT_VERB_PATTERNS, tree)) {
265
+ const clientNode = match.captures.client;
266
+ const methodNode = match.captures.method;
267
+ const pathNode = match.captures.path;
268
+ if (!clientNode || !methodNode || !pathNode)
269
+ continue;
270
+ if (!hasTrackedHttpxAsyncClient(httpxAsyncClients, clientNode))
271
+ continue;
272
+ const path = unquoteLiteral(pathNode.text);
273
+ if (path === null)
274
+ continue;
275
+ out.push({
276
+ role: 'consumer',
277
+ framework: 'python-httpx',
278
+ method: methodNode.text.toUpperCase(),
279
+ path,
280
+ name: null,
281
+ confidence: 0.7,
282
+ });
283
+ }
284
+ // Consumers: httpx.AsyncClient.request("METHOD", "url")
285
+ for (const match of runCompiledPatterns(HTTPX_ASYNC_CLIENT_GENERIC_PATTERNS, tree)) {
286
+ const clientNode = match.captures.client;
287
+ const methodNode = match.captures.http_method;
288
+ const pathNode = match.captures.path;
289
+ if (!clientNode || !methodNode || !pathNode)
290
+ continue;
291
+ if (!hasTrackedHttpxAsyncClient(httpxAsyncClients, clientNode))
292
+ continue;
293
+ const methodRaw = unquoteLiteral(methodNode.text);
294
+ const path = unquoteLiteral(pathNode.text);
295
+ if (methodRaw === null || path === null)
296
+ continue;
297
+ out.push({
298
+ role: 'consumer',
299
+ framework: 'python-httpx',
300
+ method: methodRaw.toUpperCase(),
301
+ path,
302
+ name: null,
303
+ confidence: 0.7,
304
+ });
305
+ }
131
306
  return out;
132
307
  },
133
308
  };
@@ -3,6 +3,7 @@ import { glob } from 'glob';
3
3
  import Parser from 'tree-sitter';
4
4
  import { createIgnoreFilter } from '../../../config/ignore-service.js';
5
5
  import { readSafe } from './fs-utils.js';
6
+ import { parseSourceSafe } from '../../tree-sitter/safe-parse.js';
6
7
  import { getPluginForFile, HTTP_SCAN_GLOB } from './http-patterns/index.js';
7
8
  /**
8
9
  * Language-agnostic orchestrator for HTTP route (provider + consumer)
@@ -154,7 +155,7 @@ export class HttpRouteExtractor {
154
155
  }
155
156
  try {
156
157
  parser.setLanguage(plugin.language);
157
- const tree = parser.parse(content);
158
+ const tree = parseSourceSafe(parser, content);
158
159
  const detections = plugin.scan(tree);
159
160
  cachedDetections.set(rel, detections);
160
161
  return detections;
@@ -8,6 +8,7 @@ import { readSafe } from './fs-utils.js';
8
8
  import { buildSuffixIndex } from '../../ingestion/import-resolvers/utils.js';
9
9
  import { createIgnoreFilter } from '../../../config/ignore-service.js';
10
10
  import { getMaxFileSizeBytes } from '../../ingestion/utils/max-file-size.js';
11
+ import { parseSourceSafe } from '../../tree-sitter/safe-parse.js';
11
12
  import { logger } from '../../logger.js';
12
13
  /**
13
14
  * Cross-repo C/C++ `#include` dependency extractor.
@@ -457,7 +458,7 @@ export class IncludeExtractor {
457
458
  let extractionSource;
458
459
  try {
459
460
  parser.setLanguage(lang);
460
- const tree = parser.parse(content);
461
+ const tree = parseSourceSafe(parser, content);
461
462
  let matches;
462
463
  try {
463
464
  matches = query.matches(tree.rootNode);
@@ -1,6 +1,7 @@
1
1
  import { glob } from 'glob';
2
2
  import Parser from 'tree-sitter';
3
3
  import { readSafe } from './fs-utils.js';
4
+ import { parseSourceSafe } from '../../tree-sitter/safe-parse.js';
4
5
  import { getPluginForFile, THRIFT_SCAN_GLOB, } from './thrift-patterns/index.js';
5
6
  function normalizeThriftPath(rel) {
6
7
  return rel.replace(/\\/g, '/');
@@ -228,7 +229,7 @@ export class ThriftExtractor {
228
229
  let detections = [];
229
230
  try {
230
231
  parser.setLanguage(plugin.language);
231
- const tree = parser.parse(content);
232
+ const tree = parseSourceSafe(parser, content);
232
233
  detections = plugin.scan(tree);
233
234
  }
234
235
  catch {
@@ -1,4 +1,5 @@
1
1
  import Parser from 'tree-sitter';
2
+ import { parseSourceSafe } from '../../tree-sitter/safe-parse.js';
2
3
  /**
3
4
  * Compile a LanguagePatterns bundle. Call this once per plugin, at
4
5
  * module load time, and export the result. Throws if any pattern
@@ -60,7 +61,7 @@ export function scanFile(parser, plugin, content) {
60
61
  let tree;
61
62
  try {
62
63
  parser.setLanguage(plugin.language);
63
- tree = parser.parse(content);
64
+ tree = parseSourceSafe(parser, content);
64
65
  }
65
66
  catch {
66
67
  return [];
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Shadow-candidate path derivation for incremental indexing.
3
+ *
4
+ * Background — Bugbot review on PR #1479:
5
+ * queryImporters() on a NEWLY ADDED file returns 0 importers in the
6
+ * pre-pipeline DB, because the new file's IMPORTS rows haven't been
7
+ * written yet. But pre-existing files may have IMPORTS edges that
8
+ * *resolved to a sibling path*, and the newcomer can now steal that
9
+ * resolution under standard JS/TS module-resolution rules. Without
10
+ * pulling those pre-existing files into the writable set, their
11
+ * stale CALLS edges remain pointing at the OLD resolution target.
12
+ *
13
+ * Given an added file path, this helper enumerates the pre-existing
14
+ * file paths whose import-resolution claim the newcomer can steal.
15
+ * Caller filters the candidates against the prior-run `fileHashes`
16
+ * map so we only query importers of paths that actually existed.
17
+ *
18
+ * Shadow patterns covered (resolution-priority-aware):
19
+ *
20
+ * (a) Same basename, different extension —
21
+ * added `foo/bar.ts` shadows `foo/bar.{tsx,js,jsx,mjs,cjs,d.ts}`.
22
+ * (b) Bare-file beats directory-style index —
23
+ * added `foo/bar.ts` shadows `foo/bar/index.{ts,tsx,...}`.
24
+ * (c) Directory-index beats bare-file —
25
+ * added `foo/index.ts` shadows `foo.{ts,tsx,...}` (rare but real,
26
+ * e.g. converting a single-file module into a directory module).
27
+ *
28
+ * Resolution-order priority is conservatively wide: we enumerate ALL
29
+ * common extensions because we don't know which the importer actually
30
+ * specified, and over-seeding is harmless (extra BFS work, but the
31
+ * subgraph extract still gates write-back by file membership).
32
+ *
33
+ * Cross-platform path separators: candidates are emitted with both `/`
34
+ * and `\` for shadow pattern (b), since the caller's prior fileHashes
35
+ * map may use either depending on the OS that wrote it.
36
+ */
37
+ /**
38
+ * Enumerate pre-existing paths whose import-resolution `added` can steal.
39
+ *
40
+ * @param added — repo-relative path of a newly-added file
41
+ * @returns deduplicated list of candidate paths (NOT filtered against
42
+ * any known-files set — caller does that)
43
+ */
44
+ export declare const shadowCandidatesFor: (added: string) => string[];
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Shadow-candidate path derivation for incremental indexing.
3
+ *
4
+ * Background — Bugbot review on PR #1479:
5
+ * queryImporters() on a NEWLY ADDED file returns 0 importers in the
6
+ * pre-pipeline DB, because the new file's IMPORTS rows haven't been
7
+ * written yet. But pre-existing files may have IMPORTS edges that
8
+ * *resolved to a sibling path*, and the newcomer can now steal that
9
+ * resolution under standard JS/TS module-resolution rules. Without
10
+ * pulling those pre-existing files into the writable set, their
11
+ * stale CALLS edges remain pointing at the OLD resolution target.
12
+ *
13
+ * Given an added file path, this helper enumerates the pre-existing
14
+ * file paths whose import-resolution claim the newcomer can steal.
15
+ * Caller filters the candidates against the prior-run `fileHashes`
16
+ * map so we only query importers of paths that actually existed.
17
+ *
18
+ * Shadow patterns covered (resolution-priority-aware):
19
+ *
20
+ * (a) Same basename, different extension —
21
+ * added `foo/bar.ts` shadows `foo/bar.{tsx,js,jsx,mjs,cjs,d.ts}`.
22
+ * (b) Bare-file beats directory-style index —
23
+ * added `foo/bar.ts` shadows `foo/bar/index.{ts,tsx,...}`.
24
+ * (c) Directory-index beats bare-file —
25
+ * added `foo/index.ts` shadows `foo.{ts,tsx,...}` (rare but real,
26
+ * e.g. converting a single-file module into a directory module).
27
+ *
28
+ * Resolution-order priority is conservatively wide: we enumerate ALL
29
+ * common extensions because we don't know which the importer actually
30
+ * specified, and over-seeding is harmless (extra BFS work, but the
31
+ * subgraph extract still gates write-back by file membership).
32
+ *
33
+ * Cross-platform path separators: candidates are emitted with both `/`
34
+ * and `\` for shadow pattern (b), since the caller's prior fileHashes
35
+ * map may use either depending on the OS that wrote it.
36
+ */
37
+ const SHADOW_EXTS = ['.d.ts', '.tsx', '.ts', '.jsx', '.js', '.mjs', '.cjs'];
38
+ /**
39
+ * Enumerate pre-existing paths whose import-resolution `added` can steal.
40
+ *
41
+ * @param added — repo-relative path of a newly-added file
42
+ * @returns deduplicated list of candidate paths (NOT filtered against
43
+ * any known-files set — caller does that)
44
+ */
45
+ export const shadowCandidatesFor = (added) => {
46
+ const ext = SHADOW_EXTS.find((e) => added.endsWith(e));
47
+ if (!ext)
48
+ return [];
49
+ const noExt = added.slice(0, -ext.length);
50
+ const out = new Set();
51
+ // (a) Same basename, different extension.
52
+ for (const alt of SHADOW_EXTS) {
53
+ if (alt !== ext)
54
+ out.add(noExt + alt);
55
+ }
56
+ // (b) Bare file beats sibling directory-style index.
57
+ for (const idx of SHADOW_EXTS) {
58
+ out.add(`${noExt}/index${idx}`);
59
+ out.add(`${noExt}\\index${idx}`);
60
+ }
61
+ // (c) New `foo/index.ext` shadows old `foo.ext`.
62
+ const idxSuffixSlash = '/index';
63
+ const idxSuffixBack = '\\index';
64
+ let dir = null;
65
+ if (noExt.endsWith(idxSuffixSlash))
66
+ dir = noExt.slice(0, -idxSuffixSlash.length);
67
+ else if (noExt.endsWith(idxSuffixBack))
68
+ dir = noExt.slice(0, -idxSuffixBack.length);
69
+ if (dir !== null) {
70
+ for (const alt of SHADOW_EXTS)
71
+ out.add(dir + alt);
72
+ }
73
+ return [...out];
74
+ };
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Subgraph extraction for incremental DB writeback.
3
+ *
4
+ * Given the FULL ctx.graph produced by the pipeline (all files parsed,
5
+ * all phases run) and the set of file paths whose DB rows must be
6
+ * replaced, produce a smaller KnowledgeGraph that contains:
7
+ *
8
+ * - Every node whose `properties.filePath` is in `toWriteSet`.
9
+ * - Every graph-wide node (Community, Process) — these are regenerated
10
+ * each run by the communities/processes phases and must be fully
11
+ * rewritten.
12
+ * - Every relationship where AT LEAST ONE endpoint is in the writable
13
+ * set above. Relationships entirely between unchanged-file nodes
14
+ * are skipped — their rows are still in the DB and re-inserting
15
+ * them would PK-conflict at COPY time.
16
+ *
17
+ * The resulting subgraph is what gets passed to `loadGraphToLbug` after
18
+ * the orchestrator has deleted the corresponding DB rows. Hydrated
19
+ * unchanged-file rows are never touched in the DB.
20
+ *
21
+ * # Cross-file edge consistency (Finding 1)
22
+ *
23
+ * `extractChangedSubgraph` intentionally does NOT expand the set it is
24
+ * given — expansion is the orchestrator's job, so the SAME expanded set
25
+ * can be fed to both `deleteNodesForFile` and this function (asymmetry
26
+ * between the delete set and the write set silently corrupts the DB).
27
+ * `computeEffectiveWriteSet` below performs the boundary-crossing 1-hop
28
+ * walk; the orchestrator composes it with its importer-BFS expansion and
29
+ * passes the result here.
30
+ *
31
+ * Why the 1-hop walk is needed: consider a barrel re-export change —
32
+ * file C (a barrel) shifts `export { foo } from './b'` to
33
+ * `export { foo } from './d'`. After scope resolution, file A's CALLS
34
+ * edge to `foo` resolves to D instead of B, even though A's content is
35
+ * byte-for-byte identical:
36
+ *
37
+ * - Old A→B edge survives in DB (neither A nor B is changed → not deleted)
38
+ * - New A→D edge is missing (neither A nor D in writable set → skipped)
39
+ *
40
+ * Pulling the unchanged-side file of every writable-boundary-crossing
41
+ * edge into the write set fixes both halves: the orchestrator's
42
+ * `DETACH DELETE` cleans up the stale unchanged-side rows, and the new
43
+ * cross-file edges land because at least one endpoint is now writable.
44
+ *
45
+ * Limitation (documented): if a file X *stopped* importing from a
46
+ * changed file C, X has no edge to C in the new graph, so this 1-hop
47
+ * walk doesn't catch it. The orchestrator's importer-BFS (which reads
48
+ * IMPORTS from the pre-pipeline DB) covers that case instead.
49
+ */
50
+ import type { KnowledgeGraph } from '../graph/types.js';
51
+ export declare const extractChangedSubgraph: (fullGraph: KnowledgeGraph, toWriteSet: ReadonlySet<string>) => KnowledgeGraph;
52
+ /**
53
+ * Public — derive the EFFECTIVE write-set: `toWriteSet` expanded by one
54
+ * hop along every edge in the new graph that crosses the writable
55
+ * boundary (one endpoint in a writable file, the other in an unchanged
56
+ * file). The unchanged-side file is pulled in so its stale rows are
57
+ * deleted + rewritten in lockstep with the changed side.
58
+ *
59
+ * Single pass over the edge list. Does NOT mutate `toWriteSet`. The
60
+ * orchestrator MUST feed the returned set to both `deleteNodesForFile`
61
+ * and `extractChangedSubgraph` — feeding the unexpanded set to either
62
+ * one leaves stale rows or PK-conflicts at COPY time.
63
+ */
64
+ export declare const computeEffectiveWriteSet: (fullGraph: KnowledgeGraph, toWriteSet: ReadonlySet<string>) => Set<string>;
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Subgraph extraction for incremental DB writeback.
3
+ *
4
+ * Given the FULL ctx.graph produced by the pipeline (all files parsed,
5
+ * all phases run) and the set of file paths whose DB rows must be
6
+ * replaced, produce a smaller KnowledgeGraph that contains:
7
+ *
8
+ * - Every node whose `properties.filePath` is in `toWriteSet`.
9
+ * - Every graph-wide node (Community, Process) — these are regenerated
10
+ * each run by the communities/processes phases and must be fully
11
+ * rewritten.
12
+ * - Every relationship where AT LEAST ONE endpoint is in the writable
13
+ * set above. Relationships entirely between unchanged-file nodes
14
+ * are skipped — their rows are still in the DB and re-inserting
15
+ * them would PK-conflict at COPY time.
16
+ *
17
+ * The resulting subgraph is what gets passed to `loadGraphToLbug` after
18
+ * the orchestrator has deleted the corresponding DB rows. Hydrated
19
+ * unchanged-file rows are never touched in the DB.
20
+ *
21
+ * # Cross-file edge consistency (Finding 1)
22
+ *
23
+ * `extractChangedSubgraph` intentionally does NOT expand the set it is
24
+ * given — expansion is the orchestrator's job, so the SAME expanded set
25
+ * can be fed to both `deleteNodesForFile` and this function (asymmetry
26
+ * between the delete set and the write set silently corrupts the DB).
27
+ * `computeEffectiveWriteSet` below performs the boundary-crossing 1-hop
28
+ * walk; the orchestrator composes it with its importer-BFS expansion and
29
+ * passes the result here.
30
+ *
31
+ * Why the 1-hop walk is needed: consider a barrel re-export change —
32
+ * file C (a barrel) shifts `export { foo } from './b'` to
33
+ * `export { foo } from './d'`. After scope resolution, file A's CALLS
34
+ * edge to `foo` resolves to D instead of B, even though A's content is
35
+ * byte-for-byte identical:
36
+ *
37
+ * - Old A→B edge survives in DB (neither A nor B is changed → not deleted)
38
+ * - New A→D edge is missing (neither A nor D in writable set → skipped)
39
+ *
40
+ * Pulling the unchanged-side file of every writable-boundary-crossing
41
+ * edge into the write set fixes both halves: the orchestrator's
42
+ * `DETACH DELETE` cleans up the stale unchanged-side rows, and the new
43
+ * cross-file edges land because at least one endpoint is now writable.
44
+ *
45
+ * Limitation (documented): if a file X *stopped* importing from a
46
+ * changed file C, X has no edge to C in the new graph, so this 1-hop
47
+ * walk doesn't catch it. The orchestrator's importer-BFS (which reads
48
+ * IMPORTS from the pre-pipeline DB) covers that case instead.
49
+ */
50
+ import { createKnowledgeGraph } from '../graph/graph.js';
51
+ const isGraphWide = (label) => label === 'Community' || label === 'Process';
52
+ /**
53
+ * Build a Map<nodeId, filePath> for every File-bound node in the graph.
54
+ * Graph-wide nodes (Community/Process) have no filePath and are filtered.
55
+ */
56
+ const indexNodeFilePaths = (fullGraph) => {
57
+ const idx = new Map();
58
+ fullGraph.forEachNode((n) => {
59
+ const fp = n.properties?.filePath;
60
+ if (fp)
61
+ idx.set(n.id, fp);
62
+ });
63
+ return idx;
64
+ };
65
+ export const extractChangedSubgraph = (fullGraph, toWriteSet) => {
66
+ const sub = createKnowledgeGraph();
67
+ const writableNodeIds = new Set();
68
+ fullGraph.forEachNode((n) => {
69
+ const filePath = n.properties?.filePath;
70
+ const include = (filePath && toWriteSet.has(filePath)) || isGraphWide(n.label);
71
+ if (include) {
72
+ sub.addNode(n);
73
+ writableNodeIds.add(n.id);
74
+ }
75
+ });
76
+ fullGraph.forEachRelationship((r) => {
77
+ if (writableNodeIds.has(r.sourceId) || writableNodeIds.has(r.targetId)) {
78
+ sub.addRelationship(r);
79
+ }
80
+ });
81
+ return sub;
82
+ };
83
+ /**
84
+ * Public — derive the EFFECTIVE write-set: `toWriteSet` expanded by one
85
+ * hop along every edge in the new graph that crosses the writable
86
+ * boundary (one endpoint in a writable file, the other in an unchanged
87
+ * file). The unchanged-side file is pulled in so its stale rows are
88
+ * deleted + rewritten in lockstep with the changed side.
89
+ *
90
+ * Single pass over the edge list. Does NOT mutate `toWriteSet`. The
91
+ * orchestrator MUST feed the returned set to both `deleteNodesForFile`
92
+ * and `extractChangedSubgraph` — feeding the unexpanded set to either
93
+ * one leaves stale rows or PK-conflicts at COPY time.
94
+ */
95
+ export const computeEffectiveWriteSet = (fullGraph, toWriteSet) => {
96
+ const nodeFilePaths = indexNodeFilePaths(fullGraph);
97
+ const expanded = new Set(toWriteSet);
98
+ fullGraph.forEachRelationship((r) => {
99
+ const sourcePath = nodeFilePaths.get(r.sourceId);
100
+ const targetPath = nodeFilePaths.get(r.targetId);
101
+ if (!sourcePath || !targetPath)
102
+ return; // skip edges to graph-wide nodes
103
+ const sourceWritable = toWriteSet.has(sourcePath);
104
+ const targetWritable = toWriteSet.has(targetPath);
105
+ if (sourceWritable && !targetWritable)
106
+ expanded.add(targetPath);
107
+ else if (targetWritable && !sourceWritable)
108
+ expanded.add(sourcePath);
109
+ });
110
+ return expanded;
111
+ };