gitnexus 1.6.5-rc.8 → 1.6.5

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 (335) hide show
  1. package/dist/_shared/scope-resolution/finalize-algorithm.js +10 -2
  2. package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
  3. package/dist/_shared/scope-resolution/method-dispatch-index.d.ts +26 -0
  4. package/dist/_shared/scope-resolution/method-dispatch-index.d.ts.map +1 -1
  5. package/dist/_shared/scope-resolution/method-dispatch-index.js +22 -3
  6. package/dist/_shared/scope-resolution/method-dispatch-index.js.map +1 -1
  7. package/dist/_shared/scope-resolution/registries/lookup-core.js +18 -1
  8. package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -1
  9. package/dist/_shared/scope-resolution/symbol-definition.d.ts +2 -0
  10. package/dist/_shared/scope-resolution/symbol-definition.d.ts.map +1 -1
  11. package/dist/cli/ai-context.d.ts +1 -0
  12. package/dist/cli/ai-context.js +70 -16
  13. package/dist/cli/analyze.d.ts +30 -2
  14. package/dist/cli/analyze.js +45 -5
  15. package/dist/cli/index.js +8 -1
  16. package/dist/cli/setup.js +18 -0
  17. package/dist/cli/wiki.d.ts +2 -0
  18. package/dist/cli/wiki.js +11 -0
  19. package/dist/core/augmentation/engine.js +24 -4
  20. package/dist/core/embeddings/http-client.js +22 -6
  21. package/dist/core/incremental/shadow-candidates.d.ts +44 -0
  22. package/dist/core/incremental/shadow-candidates.js +74 -0
  23. package/dist/core/incremental/subgraph-extract.d.ts +64 -0
  24. package/dist/core/incremental/subgraph-extract.js +111 -0
  25. package/dist/core/ingestion/call-processor.d.ts +12 -1
  26. package/dist/core/ingestion/call-processor.js +183 -47
  27. package/dist/core/ingestion/class-extractors/configs/c-cpp.js +38 -0
  28. package/dist/core/ingestion/class-extractors/generic.js +8 -0
  29. package/dist/core/ingestion/class-types.d.ts +15 -0
  30. package/dist/core/ingestion/community-processor.js +18 -0
  31. package/dist/core/ingestion/import-resolvers/standard.d.ts +5 -0
  32. package/dist/core/ingestion/import-resolvers/standard.js +31 -1
  33. package/dist/core/ingestion/import-resolvers/utils.js +4 -0
  34. package/dist/core/ingestion/languages/c-cpp.js +20 -2
  35. package/dist/core/ingestion/languages/cpp/adl.d.ts +141 -0
  36. package/dist/core/ingestion/languages/cpp/adl.js +478 -0
  37. package/dist/core/ingestion/languages/cpp/arity-metadata.d.ts +18 -0
  38. package/dist/core/ingestion/languages/cpp/arity-metadata.js +170 -0
  39. package/dist/core/ingestion/languages/cpp/arity.d.ts +17 -0
  40. package/dist/core/ingestion/languages/cpp/arity.js +31 -0
  41. package/dist/core/ingestion/languages/cpp/captures.d.ts +2 -0
  42. package/dist/core/ingestion/languages/cpp/captures.js +1131 -0
  43. package/dist/core/ingestion/languages/cpp/conversion-rank.d.ts +31 -0
  44. package/dist/core/ingestion/languages/cpp/conversion-rank.js +47 -0
  45. package/dist/core/ingestion/languages/cpp/file-local-linkage.d.ts +118 -0
  46. package/dist/core/ingestion/languages/cpp/file-local-linkage.js +266 -0
  47. package/dist/core/ingestion/languages/cpp/header-scan.d.ts +8 -0
  48. package/dist/core/ingestion/languages/cpp/header-scan.js +50 -0
  49. package/dist/core/ingestion/languages/cpp/import-decomposer.d.ts +19 -0
  50. package/dist/core/ingestion/languages/cpp/import-decomposer.js +111 -0
  51. package/dist/core/ingestion/languages/cpp/import-target.d.ts +10 -0
  52. package/dist/core/ingestion/languages/cpp/import-target.js +13 -0
  53. package/dist/core/ingestion/languages/cpp/index.d.ts +11 -0
  54. package/dist/core/ingestion/languages/cpp/index.js +11 -0
  55. package/dist/core/ingestion/languages/cpp/inline-namespaces.d.ts +67 -0
  56. package/dist/core/ingestion/languages/cpp/inline-namespaces.js +176 -0
  57. package/dist/core/ingestion/languages/cpp/interpret.d.ts +35 -0
  58. package/dist/core/ingestion/languages/cpp/interpret.js +113 -0
  59. package/dist/core/ingestion/languages/cpp/merge-bindings.d.ts +13 -0
  60. package/dist/core/ingestion/languages/cpp/merge-bindings.js +29 -0
  61. package/dist/core/ingestion/languages/cpp/query.d.ts +3 -0
  62. package/dist/core/ingestion/languages/cpp/query.js +508 -0
  63. package/dist/core/ingestion/languages/cpp/range-bindings.d.ts +20 -0
  64. package/dist/core/ingestion/languages/cpp/range-bindings.js +212 -0
  65. package/dist/core/ingestion/languages/cpp/scope-resolver.d.ts +17 -0
  66. package/dist/core/ingestion/languages/cpp/scope-resolver.js +246 -0
  67. package/dist/core/ingestion/languages/cpp/simple-hooks.d.ts +24 -0
  68. package/dist/core/ingestion/languages/cpp/simple-hooks.js +62 -0
  69. package/dist/core/ingestion/languages/cpp/two-phase-lookup.d.ts +76 -0
  70. package/dist/core/ingestion/languages/cpp/two-phase-lookup.js +195 -0
  71. package/dist/core/ingestion/languages/java/arity-metadata.d.ts +18 -0
  72. package/dist/core/ingestion/languages/java/arity-metadata.js +40 -0
  73. package/dist/core/ingestion/languages/java/arity.d.ts +10 -0
  74. package/dist/core/ingestion/languages/java/arity.js +24 -0
  75. package/dist/core/ingestion/languages/java/cache-stats.d.ts +15 -0
  76. package/dist/core/ingestion/languages/java/cache-stats.js +26 -0
  77. package/dist/core/ingestion/languages/java/captures.d.ts +17 -0
  78. package/dist/core/ingestion/languages/java/captures.js +187 -0
  79. package/dist/core/ingestion/languages/java/import-decomposer.d.ts +18 -0
  80. package/dist/core/ingestion/languages/java/import-decomposer.js +85 -0
  81. package/dist/core/ingestion/languages/java/import-target.d.ts +17 -0
  82. package/dist/core/ingestion/languages/java/import-target.js +100 -0
  83. package/dist/core/ingestion/languages/java/index.d.ts +29 -0
  84. package/dist/core/ingestion/languages/java/index.js +29 -0
  85. package/dist/core/ingestion/languages/java/interpret.d.ts +13 -0
  86. package/dist/core/ingestion/languages/java/interpret.js +131 -0
  87. package/dist/core/ingestion/languages/java/merge-bindings.d.ts +12 -0
  88. package/dist/core/ingestion/languages/java/merge-bindings.js +40 -0
  89. package/dist/core/ingestion/languages/java/query.d.ts +30 -0
  90. package/dist/core/ingestion/languages/java/query.js +192 -0
  91. package/dist/core/ingestion/languages/java/receiver-binding.d.ts +11 -0
  92. package/dist/core/ingestion/languages/java/receiver-binding.js +95 -0
  93. package/dist/core/ingestion/languages/java/scope-resolver.d.ts +50 -0
  94. package/dist/core/ingestion/languages/java/scope-resolver.js +74 -0
  95. package/dist/core/ingestion/languages/java/simple-hooks.d.ts +13 -0
  96. package/dist/core/ingestion/languages/java/simple-hooks.js +34 -0
  97. package/dist/core/ingestion/languages/java.js +11 -0
  98. package/dist/core/ingestion/languages/php/arity-metadata.d.ts +28 -0
  99. package/dist/core/ingestion/languages/php/arity-metadata.js +63 -0
  100. package/dist/core/ingestion/languages/php/arity.d.ts +25 -0
  101. package/dist/core/ingestion/languages/php/arity.js +40 -0
  102. package/dist/core/ingestion/languages/php/cache-stats.d.ts +15 -0
  103. package/dist/core/ingestion/languages/php/cache-stats.js +26 -0
  104. package/dist/core/ingestion/languages/php/captures.d.ts +34 -0
  105. package/dist/core/ingestion/languages/php/captures.js +739 -0
  106. package/dist/core/ingestion/languages/php/import-decomposer.d.ts +28 -0
  107. package/dist/core/ingestion/languages/php/import-decomposer.js +265 -0
  108. package/dist/core/ingestion/languages/php/import-target.d.ts +47 -0
  109. package/dist/core/ingestion/languages/php/import-target.js +100 -0
  110. package/dist/core/ingestion/languages/php/index.d.ts +68 -0
  111. package/dist/core/ingestion/languages/php/index.js +72 -0
  112. package/dist/core/ingestion/languages/php/interpret.d.ts +36 -0
  113. package/dist/core/ingestion/languages/php/interpret.js +241 -0
  114. package/dist/core/ingestion/languages/php/merge-bindings.d.ts +19 -0
  115. package/dist/core/ingestion/languages/php/merge-bindings.js +47 -0
  116. package/dist/core/ingestion/languages/php/namespace-siblings.d.ts +51 -0
  117. package/dist/core/ingestion/languages/php/namespace-siblings.js +288 -0
  118. package/dist/core/ingestion/languages/php/query.d.ts +32 -0
  119. package/dist/core/ingestion/languages/php/query.js +326 -0
  120. package/dist/core/ingestion/languages/php/receiver-binding.d.ts +36 -0
  121. package/dist/core/ingestion/languages/php/receiver-binding.js +128 -0
  122. package/dist/core/ingestion/languages/php/scope-resolver.d.ts +23 -0
  123. package/dist/core/ingestion/languages/php/scope-resolver.js +358 -0
  124. package/dist/core/ingestion/languages/php/simple-hooks.d.ts +42 -0
  125. package/dist/core/ingestion/languages/php/simple-hooks.js +111 -0
  126. package/dist/core/ingestion/languages/php.d.ts +0 -7
  127. package/dist/core/ingestion/languages/php.js +15 -0
  128. package/dist/core/ingestion/markdown-processor.js +6 -1
  129. package/dist/core/ingestion/model/symbol-table.d.ts +1 -0
  130. package/dist/core/ingestion/model/symbol-table.js +3 -0
  131. package/dist/core/ingestion/parsing-processor.d.ts +22 -2
  132. package/dist/core/ingestion/parsing-processor.js +123 -50
  133. package/dist/core/ingestion/pipeline-phases/cross-file-impl.js +54 -2
  134. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +5 -0
  135. package/dist/core/ingestion/pipeline-phases/parse-impl.js +119 -11
  136. package/dist/core/ingestion/pipeline-phases/parse.d.ts +14 -0
  137. package/dist/core/ingestion/pipeline.d.ts +13 -0
  138. package/dist/core/ingestion/registry-primary-flag.js +2 -0
  139. package/dist/core/ingestion/scope-extractor.js +4 -0
  140. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +167 -0
  141. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.js +3 -0
  142. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.d.ts +1 -0
  143. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +12 -0
  144. package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.d.ts +1 -1
  145. package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.js +12 -2
  146. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +16 -0
  147. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +36 -0
  148. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +204 -13
  149. package/dist/core/ingestion/scope-resolution/passes/imported-return-types.js +1 -1
  150. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +55 -4
  151. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +186 -5
  152. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +10 -1
  153. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +207 -9
  154. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +13 -1
  155. package/dist/core/ingestion/scope-resolution/pipeline/registry.js +6 -0
  156. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +17 -0
  157. package/dist/core/ingestion/scope-resolution/pipeline/run.js +86 -8
  158. package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +30 -0
  159. package/dist/core/ingestion/scope-resolution/scope/walkers.js +90 -8
  160. package/dist/core/ingestion/tree-sitter-queries.d.ts +2 -2
  161. package/dist/core/ingestion/tree-sitter-queries.js +23 -0
  162. package/dist/core/ingestion/utils/ast-helpers.js +6 -1
  163. package/dist/core/ingestion/utils/template-arguments.d.ts +11 -0
  164. package/dist/core/ingestion/utils/template-arguments.js +65 -0
  165. package/dist/core/ingestion/workers/parse-worker.d.ts +3 -0
  166. package/dist/core/ingestion/workers/parse-worker.js +42 -1
  167. package/dist/core/lbug/lbug-adapter.d.ts +39 -0
  168. package/dist/core/lbug/lbug-adapter.js +348 -48
  169. package/dist/core/run-analyze.d.ts +2 -0
  170. package/dist/core/run-analyze.js +323 -29
  171. package/dist/core/search/hybrid-search.d.ts +3 -0
  172. package/dist/core/search/hybrid-search.js +23 -6
  173. package/dist/core/wiki/generator.js +4 -3
  174. package/dist/core/wiki/html-viewer.js +2 -1
  175. package/dist/core/wiki/llm-client.d.ts +4 -0
  176. package/dist/core/wiki/llm-client.js +3 -3
  177. package/dist/core/wiki/mermaid-sanitizer.d.ts +2 -0
  178. package/dist/core/wiki/mermaid-sanitizer.js +100 -0
  179. package/dist/mcp/local/local-backend.js +20 -7
  180. package/dist/storage/file-hash.d.ts +47 -0
  181. package/dist/storage/file-hash.js +86 -0
  182. package/dist/storage/parse-cache.d.ts +73 -0
  183. package/dist/storage/parse-cache.js +253 -0
  184. package/dist/storage/repo-manager.d.ts +41 -1
  185. package/dist/storage/repo-manager.js +61 -6
  186. package/hooks/claude/gitnexus-hook.cjs +42 -4
  187. package/hooks/claude/hook-db-lock-probe.cjs +238 -0
  188. package/hooks/claude/hook-lock.cjs +119 -0
  189. package/hooks/claude/win-rm-list-json.ps1 +76 -0
  190. package/package.json +1 -1
  191. package/scripts/build.js +6 -2
  192. package/vendor/node_modules/node-addon-api/node_addon_api.target.mk +16 -16
  193. package/vendor/node_modules/node-addon-api/node_addon_api_except.target.mk +16 -16
  194. package/vendor/node_modules/node-addon-api/node_addon_api_except_all.target.mk +16 -16
  195. package/vendor/node_modules/node-addon-api/node_addon_api_maybe.target.mk +16 -16
  196. package/web/assets/{agent-BpHQleHE.js → agent-D2kLt6Dl.js} +91 -91
  197. package/web/assets/architecture-7EHR7CIX-6QZW5X65-BETj2x4g.js +1 -0
  198. package/web/assets/architectureDiagram-UL44E2DR-DvIkEGkp.js +36 -0
  199. package/web/assets/blockDiagram-7IZFK4PR-B4niSLvR.js +132 -0
  200. package/web/assets/{c4Diagram-DFAF54RM-DeJV1rCn.js → c4Diagram-Y2BXMSZH-DIzEXalR.js} +6 -6
  201. package/web/assets/chunk-2T2R6R2M-n6s9JZqv.js +4 -0
  202. package/web/assets/chunk-2UTLFMKG-CMBB1TMN.js +1 -0
  203. package/web/assets/{chunk-7RZVMHOQ-BdIU-RGO.js → chunk-3SSMPTDK-BzGeeheI.js} +1 -1
  204. package/web/assets/chunk-4R4BOZG6-mKhL59ul.js +159 -0
  205. package/web/assets/chunk-5IMINLNL-CnTLsXIV.js +1 -0
  206. package/web/assets/chunk-5VCL7Z4A-w1BCx98Z.js +1 -0
  207. package/web/assets/chunk-6764PJDD-ChwMM2z4.js +1 -0
  208. package/web/assets/chunk-67TQ5CYL-CChC2cAv.js +124 -0
  209. package/web/assets/chunk-7J6CGLKN-DT-b53FT.js +10 -0
  210. package/web/assets/chunk-7W6UQGC5-CgFyfZ6k.js +1 -0
  211. package/web/assets/chunk-AQ6EADP3-CCFje6lL.js +1 -0
  212. package/web/assets/{chunk-KSICW3F5-C2tZmXwv.js → chunk-AZZRMDJM-5E9ARdDQ.js} +1 -1
  213. package/web/assets/chunk-C62D2QBJ-CDAWj26E.js +1 -0
  214. package/web/assets/chunk-CEXFNPSA-D68Tk6ls.js +1 -0
  215. package/web/assets/chunk-INKRHTLW-ELpfuk9h.js +70 -0
  216. package/web/assets/chunk-J5EP6P6S-DxWW0yvu.js +1 -0
  217. package/web/assets/{chunk-AEOMTBSW-D7qjBMHW.js → chunk-JQRUD6KW-Dcq_Qnyy.js} +1 -1
  218. package/web/assets/chunk-KGFNY3KK-W-VR57xb.js +62 -0
  219. package/web/assets/chunk-KGYTTC2M-C6PHeuay.js +1 -0
  220. package/web/assets/chunk-KNLZD3CH-BuZBOcso.js +1 -0
  221. package/web/assets/chunk-KRXBNO2N-DH2NPM7I.js +1 -0
  222. package/web/assets/chunk-LCXTWHL2-CqJ0oo1x.js +231 -0
  223. package/web/assets/chunk-LII3EMHJ-3X33tCpU.js +1 -0
  224. package/web/assets/chunk-QA3QBVWF-D5Ha3GgB.js +2 -0
  225. package/web/assets/chunk-RERM46MO-DQNbXtfw.js +1 -0
  226. package/web/assets/chunk-RG4AUYOV-D0M6vdq9.js +206 -0
  227. package/web/assets/chunk-RKZBBQEN-BmTPLSyv.js +1 -0
  228. package/web/assets/chunk-RLI5ZMPA-DExu2DOK.js +1 -0
  229. package/web/assets/chunk-T2UQINTJ-kGYG7ppP.js +1 -0
  230. package/web/assets/chunk-T5OCTHI4--9wWpVws.js +1 -0
  231. package/web/assets/chunk-UP6H54XL-DsKdC6jC.js +1 -0
  232. package/web/assets/chunk-UXSXWOXI-DR81EqLr.js +1 -0
  233. package/web/assets/chunk-UY5QBCOK-Du-c56gs.js +1 -0
  234. package/web/assets/chunk-W44A43WB-lrCpuupA.js +1 -0
  235. package/web/assets/chunk-ZXARS5L4-CSZRiyOf.js +1 -0
  236. package/web/assets/classDiagram-KGZ6W3CR-BB-saqC1.js +1 -0
  237. package/web/assets/classDiagram-v2-72OJOZXJ-Bp2bAlS5.js +1 -0
  238. package/web/assets/cose-bilkent-UX7MHV2Q-BHv2bbtl.js +1 -0
  239. package/web/assets/dagre-ND4H6XIP-DsIr9MOv.js +4 -0
  240. package/web/assets/diagram-3NCE3AQN-BUxnDPOY.js +43 -0
  241. package/web/assets/diagram-GF46GFSD-BJTyqqvI.js +24 -0
  242. package/web/assets/diagram-HNR7UZ2L-fUWreZzx.js +3 -0
  243. package/web/assets/diagram-QXG6HAR7-DilMHamP.js +24 -0
  244. package/web/assets/diagram-WEQXMOUZ-8KUrarg1.js +10 -0
  245. package/web/assets/erDiagram-L5TCEMPS-Doj9mSiW.js +85 -0
  246. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-B3myHUst.js +1 -0
  247. package/web/assets/{flowDiagram-OTCZ4VVT-aAZw4c_M.js → flowDiagram-H6V6AXG4-BOSR-i3p.js} +12 -12
  248. package/web/assets/ganttDiagram-JCBTUEKG-BHQssTz6.js +292 -0
  249. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DF3rtf4A.js +1 -0
  250. package/web/assets/gitGraphDiagram-S2ZK5IYY-CCwVLT__.js +106 -0
  251. package/web/assets/index-j4-NuleT.js +623 -0
  252. package/web/assets/info-J43DQDTF-KCYPFFUO-R4XV_akJ.js +1 -0
  253. package/web/assets/infoDiagram-3YFTVSEB-Ce_TvtaV.js +2 -0
  254. package/web/assets/{ishikawaDiagram-YMYX4NHK-BF8AtDaj.js → ishikawaDiagram-BNXS4ZKH-4MXIDCSF.js} +6 -6
  255. package/web/assets/journeyDiagram-M6C3CM3L-DNPYCpvq.js +139 -0
  256. package/web/assets/kanban-definition-75IXJCU3-yYdfm8Kk.js +89 -0
  257. package/web/assets/{katex-GD7MH7QM-CJiOjBBJ.js → katex-K3KEBU37-CrVLz8l7.js} +1 -1
  258. package/web/assets/mindmap-definition-2TDM6QVE-DFNEKM77.js +96 -0
  259. package/web/assets/packet-YPE3B663-LP52Z2RK-CgQPdNZa.js +1 -0
  260. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BzWOwc_c.js +1 -0
  261. package/web/assets/pieDiagram-CU6KROY3-iZAqpvhd.js +30 -0
  262. package/web/assets/quadrantDiagram-VICAPDV7-bAm6Hi_5.js +7 -0
  263. package/web/assets/radar-GUYGQ44K-RDLRG3WG-B7KG0FN7.js +1 -0
  264. package/web/assets/requirementDiagram-JXO7QTGE-CtDijhnf.js +84 -0
  265. package/web/assets/sankeyDiagram-URQDO5SZ-LFJz53u5.js +40 -0
  266. package/web/assets/sequenceDiagram-VS2MUI6T-BdjvyCHM.js +162 -0
  267. package/web/assets/stateDiagram-7D4R322I-e5odN9fG.js +1 -0
  268. package/web/assets/stateDiagram-v2-36443NZ5-vPsvjR2D.js +1 -0
  269. package/web/assets/timeline-definition-O6YCAMPW-DPAksNQp.js +120 -0
  270. package/web/assets/treeView-BLDUP644-QA4HXRO3-CRSxEwLO.js +1 -0
  271. package/web/assets/treemap-LRROVOQU-LLAWBHMP-a0PfKoVn.js +1 -0
  272. package/web/assets/vennDiagram-MWXL3ELB-Dtlfdt7J.js +34 -0
  273. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-BKQ6e5mC.js +1 -0
  274. package/web/assets/wardleyDiagram-CUQ6CDDI-B23uRMUC.js +78 -0
  275. package/web/assets/{xychartDiagram-ZHJ5623Y-DZ7fP1_3.js → xychartDiagram-N2JHSOCM-DxwHeksW.js} +6 -6
  276. package/web/index.html +13 -2
  277. package/web/assets/architecture-YZFGNWBL-S5CXDPWN-BUzkWgDl.js +0 -1
  278. package/web/assets/architectureDiagram-EMZXCZ2Q-CXbzok1G.js +0 -36
  279. package/web/assets/blockDiagram-IGV67L2C-DA1QJ4ZB.js +0 -132
  280. package/web/assets/chunk-3GS5O3IE-B8hpnia8.js +0 -231
  281. package/web/assets/chunk-3YCYZ6SJ-B-BVu21C.js +0 -1
  282. package/web/assets/chunk-6NTNNK5N-DW-jYSDr.js +0 -1
  283. package/web/assets/chunk-A34GCYZU-BbZl-IKy.js +0 -1
  284. package/web/assets/chunk-DJ7UZH7F-B5tMfF87.js +0 -1
  285. package/web/assets/chunk-DKKBVRCY-Djm-6K_e.js +0 -4
  286. package/web/assets/chunk-DU5LTGQ6-QPoynYcp.js +0 -1
  287. package/web/assets/chunk-FXACKDTF-jieSmbe2.js +0 -159
  288. package/web/assets/chunk-H3VCZNTA-8EMHZ3SV.js +0 -1
  289. package/web/assets/chunk-HN6EAY2L-CgE_agsD.js +0 -1
  290. package/web/assets/chunk-O5ABG6QK-DEZV1O19.js +0 -1
  291. package/web/assets/chunk-PK6DOVAG-BXv0JnsJ.js +0 -206
  292. package/web/assets/chunk-RNJOYNJ4-BiBkF9dN.js +0 -1
  293. package/web/assets/chunk-RWUO3TPN-DTWzAhQ1.js +0 -1
  294. package/web/assets/chunk-TBF5ZNIQ-BSl6s9lT.js +0 -1
  295. package/web/assets/chunk-TU3PZOEN-DE5Qhc0N.js +0 -1
  296. package/web/assets/chunk-TYMNRAUI-D1NDLIMG.js +0 -1
  297. package/web/assets/chunk-VELTKBKT-C9dVN39o.js +0 -1
  298. package/web/assets/chunk-W7ZLLLMY-Bu-cdLzs.js +0 -1
  299. package/web/assets/chunk-WSB5WSVC-Dor71SOz.js +0 -1
  300. package/web/assets/chunk-XGPFEOL4-CUonLRle.js +0 -1
  301. package/web/assets/classDiagram-PPOCWD7C-Cdd6UdVv.js +0 -1
  302. package/web/assets/classDiagram-v2-23LJLIIU-DNhxY2Ib.js +0 -1
  303. package/web/assets/cose-bilkent-PNC4W37J-DdZq7Qz_.js +0 -1
  304. package/web/assets/dagre-E77IOHMT-Cfj_6e17.js +0 -4
  305. package/web/assets/diagram-H7BISOXX-BNvpsrBv.js +0 -43
  306. package/web/assets/diagram-JC5VWROH-Cn0rtDbJ.js +0 -24
  307. package/web/assets/diagram-LXUTUG65-CHfoVKNm.js +0 -10
  308. package/web/assets/diagram-WEHSV5V5-BLxHksnu.js +0 -24
  309. package/web/assets/erDiagram-GCSMX5X6-DfdN6iqF.js +0 -85
  310. package/web/assets/ganttDiagram-MUNLMDZQ-BEfC_7Or.js +0 -292
  311. package/web/assets/gitGraph-7Q5UKJZL-54BCDZD5-B6ZeRLP0.js +0 -1
  312. package/web/assets/gitGraphDiagram-3HKGZ4G3-CG0kC8Q5.js +0 -106
  313. package/web/assets/index-3NUCUW2s.js +0 -886
  314. package/web/assets/info-OMHHGYJF-BF2H5H6G-BIOsZy0W.js +0 -1
  315. package/web/assets/infoDiagram-MN7RKWGX-DUoMH-pq.js +0 -2
  316. package/web/assets/journeyDiagram-SO5T7YLQ-BW8oKa3N.js +0 -139
  317. package/web/assets/kanban-definition-LJHFXRCJ-DzbOsR-2.js +0 -89
  318. package/web/assets/mindmap-definition-2EUWGEK5-BIXGQALq.js +0 -96
  319. package/web/assets/packet-4T2RLAQJ-EV4IVRXR-Bs7ysNMU.js +0 -1
  320. package/web/assets/pie-ZZUOXDRM-N23DN5KN-Csi8nnbH.js +0 -1
  321. package/web/assets/pieDiagram-3IATQBI2-QY-u7P6a.js +0 -30
  322. package/web/assets/quadrantDiagram-E256RVCF-Di4aNiU8.js +0 -7
  323. package/web/assets/radar-PYXPWWZC-P6TP7ZYP-DJlyXh2-.js +0 -1
  324. package/web/assets/requirementDiagram-M5DCFWZL-CzUUrhQD.js +0 -84
  325. package/web/assets/sankeyDiagram-L3NBLAOT-D2fbMiIU.js +0 -10
  326. package/web/assets/sequenceDiagram-ZOUHS735-BNdkqguh.js +0 -157
  327. package/web/assets/stateDiagram-MLPALWAM-51_Q2w2L.js +0 -1
  328. package/web/assets/stateDiagram-v2-B5LQ5ZB2-8nHs2aNE.js +0 -1
  329. package/web/assets/timeline-definition-5SPVSISX-DkMiGj4Z.js +0 -120
  330. package/web/assets/treeView-SZITEDCU-5DXDK3XO-Cy6P0_CZ.js +0 -1
  331. package/web/assets/treemap-W4RFUUIX-WYLRDWKO-C_pp1R7A.js +0 -1
  332. package/web/assets/vennDiagram-IE5QUKF5-BCxMmf9q.js +0 -34
  333. package/web/assets/wardley-RL74JXVD-BCRCBASE-CMStJhpn.js +0 -1
  334. package/web/assets/wardleyDiagram-XU3VSMPF-ijlLF77s.js +0 -20
  335. /package/web/assets/{context-builder-CqQNhRj1.js → context-builder-_HS0v2ma.js} +0 -0
@@ -1,5 +1,5 @@
1
1
  import fs from 'fs/promises';
2
- import { createReadStream, createWriteStream } from 'fs';
2
+ import { createReadStream, createWriteStream, constants as fsConstants } from 'fs';
3
3
  import { createInterface } from 'readline';
4
4
  import { once } from 'events';
5
5
  import { finished } from 'stream/promises';
@@ -152,6 +152,136 @@ export const isReadOnlyDbError = (err) => {
152
152
  const msg = err instanceof Error ? err.message : String(err);
153
153
  return /read-only database/i.test(msg);
154
154
  };
155
+ const isMissingFileError = (err) => {
156
+ const errno = err;
157
+ return errno?.code === 'ENOENT';
158
+ };
159
+ const extractErrnoCode = (err) => {
160
+ const errno = err;
161
+ return errno?.code;
162
+ };
163
+ const MAX_LOGGED_ERROR_MESSAGE_LENGTH = 160;
164
+ const summarizeError = (err) => (err instanceof Error ? err.message : String(err)).slice(0, MAX_LOGGED_ERROR_MESSAGE_LENGTH);
165
+ // ---------------------------------------------------------------------------
166
+ // Cross-process init lock
167
+ //
168
+ // Prevents a TOCTOU race in orphan sidecar cleanup: between checking that
169
+ // the main DB file is missing and unlinking sidecars, another process could
170
+ // create a fresh DB. The lock file (`${dbPath}.init.lock`) is created with
171
+ // O_CREAT | O_EXCL (atomic create-or-fail) and contains the owning PID +
172
+ // timestamp so stale locks from crashed processes can be reclaimed.
173
+ // ---------------------------------------------------------------------------
174
+ /** Maximum age (ms) before an init lock is considered stale. */
175
+ const INIT_LOCK_STALE_MS = 30_000;
176
+ /** Maximum attempts to acquire the init lock before giving up. */
177
+ const INIT_LOCK_MAX_ATTEMPTS = 6;
178
+ /** Delay between lock-acquisition retries (ms). */
179
+ const INIT_LOCK_RETRY_DELAY_MS = 500;
180
+ const initLockPath = (dbPath) => `${dbPath}.init.lock`;
181
+ /**
182
+ * Returns true when the process identified by `pid` is still running.
183
+ * Uses `process.kill(pid, 0)` which sends signal 0 (a no-op probe) —
184
+ * it throws ESRCH when the process does not exist.
185
+ */
186
+ const isProcessAlive = (pid) => {
187
+ try {
188
+ process.kill(pid, 0);
189
+ return true;
190
+ }
191
+ catch {
192
+ return false;
193
+ }
194
+ };
195
+ /**
196
+ * Try to break a stale lock whose owning process has exited.
197
+ * Returns `true` if the stale lock was removed (caller should retry acquire).
198
+ * Returns `false` if the lock is still valid (another live process owns it).
199
+ */
200
+ const tryBreakStaleLock = async (lockPath) => {
201
+ try {
202
+ const content = await fs.readFile(lockPath, 'utf-8');
203
+ const parsed = JSON.parse(content);
204
+ // If the owning process is still alive AND the lock is not stale, don't break.
205
+ if (typeof parsed.pid === 'number' && isProcessAlive(parsed.pid)) {
206
+ // Even a live process's lock can be stale if it's been held too long
207
+ // (e.g. the process is hung). Check the timestamp.
208
+ if (typeof parsed.ts === 'number' && Date.now() - parsed.ts < INIT_LOCK_STALE_MS) {
209
+ return false;
210
+ }
211
+ }
212
+ // PID is gone or lock exceeded INIT_LOCK_STALE_MS — reclaim it.
213
+ await fs.unlink(lockPath);
214
+ logger.warn(`GitNexus: removed stale init lock (pid=${parsed.pid ?? '?'}, age=${typeof parsed.ts === 'number' ? `${Date.now() - parsed.ts}ms` : '?'})`);
215
+ return true;
216
+ }
217
+ catch (err) {
218
+ // Lock file disappeared between our read and unlink, or is unreadable.
219
+ // Either way, let the caller retry the acquire.
220
+ if (isMissingFileError(err))
221
+ return true;
222
+ // Permission error or corrupt content — log and let caller retry.
223
+ const code = extractErrnoCode(err);
224
+ logger.warn(`GitNexus: unable to inspect init lock (${code ?? 'UNKNOWN'}): ${summarizeError(err)}`);
225
+ return false;
226
+ }
227
+ };
228
+ /**
229
+ * Acquire a cross-process init lock for `dbPath`.
230
+ * Uses `O_CREAT | O_EXCL` for atomic create-or-fail semantics.
231
+ *
232
+ * Returns a release function that removes the lock file. The release
233
+ * function is idempotent and safe to call even if the lock was already
234
+ * cleaned up externally.
235
+ *
236
+ * Throws if the lock cannot be acquired after `INIT_LOCK_MAX_ATTEMPTS`.
237
+ */
238
+ export const acquireInitLock = async (dbPath) => {
239
+ const lockPath = initLockPath(dbPath);
240
+ const payload = JSON.stringify({ pid: process.pid, ts: Date.now() });
241
+ // Ensure the parent directory exists before creating the lock file.
242
+ // On a fresh repo the `.gitnexus/` directory may not exist yet, and
243
+ // fs.open with O_CREAT | O_EXCL would fail with ENOENT.
244
+ await fs.mkdir(path.dirname(lockPath), { recursive: true });
245
+ for (let attempt = 1; attempt <= INIT_LOCK_MAX_ATTEMPTS; attempt++) {
246
+ try {
247
+ const handle = await fs.open(lockPath, fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY);
248
+ await handle.writeFile(payload);
249
+ await handle.close();
250
+ // Return the idempotent release function
251
+ return async () => {
252
+ try {
253
+ await fs.unlink(lockPath);
254
+ }
255
+ catch (err) {
256
+ if (!isMissingFileError(err)) {
257
+ const code = extractErrnoCode(err);
258
+ logger.warn(`GitNexus: failed to release init lock (${code ?? 'UNKNOWN'}): ${summarizeError(err)}`);
259
+ }
260
+ }
261
+ };
262
+ }
263
+ catch (err) {
264
+ if (err?.code !== 'EEXIST') {
265
+ throw err; // Unexpected error — propagate immediately
266
+ }
267
+ // Lock file exists — check if it's stale
268
+ const broken = await tryBreakStaleLock(lockPath);
269
+ if (broken && attempt < INIT_LOCK_MAX_ATTEMPTS) {
270
+ continue; // Stale lock removed — retry immediately
271
+ }
272
+ if (attempt === INIT_LOCK_MAX_ATTEMPTS) {
273
+ throw new Error(`GitNexus: unable to acquire init lock after ${INIT_LOCK_MAX_ATTEMPTS} attempts — ` +
274
+ `another gitnexus process may be initializing the same database (${lockPath})`);
275
+ }
276
+ // Live process holds the lock — wait and retry
277
+ await new Promise((resolve) => setTimeout(resolve, INIT_LOCK_RETRY_DELAY_MS));
278
+ }
279
+ }
280
+ // Unreachable — loop always throws or returns
281
+ throw new Error('GitNexus: init lock acquisition failed unexpectedly');
282
+ };
283
+ /** Exported for testing — returns the lock file path for a given dbPath. */
284
+ export const _initLockPathForTest = initLockPath;
155
285
  const runWithSessionLock = async (operation) => {
156
286
  const previous = sessionLock;
157
287
  let release = null;
@@ -167,6 +297,65 @@ const runWithSessionLock = async (operation) => {
167
297
  }
168
298
  };
169
299
  const normalizeCopyPath = (filePath) => filePath.replace(/\\/g, '/');
300
+ const closeQueryResult = async (result) => {
301
+ try {
302
+ await result.close();
303
+ }
304
+ catch {
305
+ // Best-effort cleanup only.
306
+ }
307
+ };
308
+ const drainQueryResult = async (queryResult) => {
309
+ const results = Array.isArray(queryResult) ? queryResult : [queryResult];
310
+ let firstError;
311
+ let hasError = false;
312
+ for (const result of results) {
313
+ try {
314
+ await result.getAll();
315
+ }
316
+ catch (err) {
317
+ if (!hasError) {
318
+ firstError = err;
319
+ hasError = true;
320
+ }
321
+ }
322
+ finally {
323
+ await closeQueryResult(result);
324
+ }
325
+ }
326
+ if (hasError)
327
+ throw firstError;
328
+ };
329
+ const readQueryRows = async (queryResult) => {
330
+ const results = Array.isArray(queryResult) ? queryResult : [queryResult];
331
+ let rows = [];
332
+ let firstError;
333
+ let hasError = false;
334
+ for (let i = 0; i < results.length; i++) {
335
+ const result = results[i];
336
+ try {
337
+ const resultRows = await result.getAll();
338
+ if (i === 0)
339
+ rows = resultRows;
340
+ }
341
+ catch (err) {
342
+ if (!hasError) {
343
+ firstError = err;
344
+ hasError = true;
345
+ }
346
+ }
347
+ finally {
348
+ await closeQueryResult(result);
349
+ }
350
+ }
351
+ if (hasError)
352
+ throw firstError;
353
+ return rows;
354
+ };
355
+ const queryAndDrain = async (targetConn, cypher) => {
356
+ const queryResult = await targetConn.query(cypher);
357
+ await drainQueryResult(queryResult);
358
+ };
170
359
  export const initLbug = async (dbPath) => {
171
360
  return runWithSessionLock(() => ensureLbugInitialized(dbPath));
172
361
  };
@@ -251,18 +440,62 @@ const doInitLbug = async (dbPath) => {
251
440
  }
252
441
  // If it's a file, assume it's an existing LadybugDB database - LadybugDB will open it
253
442
  }
254
- catch {
443
+ catch (err) {
444
+ if (!isMissingFileError(err)) {
445
+ throw err;
446
+ }
255
447
  // Path doesn't exist, which is what LadybugDB wants for a new database
256
448
  }
257
- // Ensure parent directory exists
258
- const parentDir = path.dirname(dbPath);
259
- await fs.mkdir(parentDir, { recursive: true });
260
- const opened = await openLbugConnection(lbug, dbPath);
261
- db = opened.db;
262
- conn = opened.conn;
449
+ // ---------------------------------------------------------------------------
450
+ // Cross-process critical section: acquire init lock, clean orphan sidecars,
451
+ // and open the database. The lock prevents a TOCTOU race where another
452
+ // process could create a fresh DB between our access() check and the
453
+ // unlink() of stale sidecars.
454
+ // ---------------------------------------------------------------------------
455
+ const releaseInitLock = await acquireInitLock(dbPath);
456
+ try {
457
+ // Crash-recovery cleanup: if the main DB file is missing, stale sidecars
458
+ // from an interrupted run can block fresh opens indefinitely.
459
+ try {
460
+ await fs.access(dbPath);
461
+ }
462
+ catch (err) {
463
+ if (isMissingFileError(err)) {
464
+ // `.shadow` is documented by LadybugDB checkpointing and `.wal.checkpoint`
465
+ // was observed in the #1618 crash loop that motivated this recovery path.
466
+ const orphanSidecars = [`${dbPath}.shadow`, `${dbPath}.wal.checkpoint`];
467
+ for (const sidecar of orphanSidecars) {
468
+ try {
469
+ await fs.unlink(sidecar);
470
+ logger.warn(`GitNexus: removed orphan sidecar ${path.basename(sidecar)} (no main DB file present)`);
471
+ }
472
+ catch (err) {
473
+ if (isMissingFileError(err)) {
474
+ continue;
475
+ }
476
+ const code = extractErrnoCode(err);
477
+ logger.warn(`GitNexus: failed to remove orphan sidecar ${path.basename(sidecar)} (${code ?? 'UNKNOWN'}) while main DB file is missing; LadybugDB open may still fail: ${summarizeError(err)}`);
478
+ }
479
+ }
480
+ }
481
+ else {
482
+ const code = extractErrnoCode(err);
483
+ logger.warn(`GitNexus: unable to verify main DB file before orphan sidecar cleanup (${code ?? 'UNKNOWN'}); skipping cleanup: ${summarizeError(err)}`);
484
+ }
485
+ }
486
+ // Ensure parent directory exists
487
+ const parentDir = path.dirname(dbPath);
488
+ await fs.mkdir(parentDir, { recursive: true });
489
+ const opened = await openLbugConnection(lbug, dbPath);
490
+ db = opened.db;
491
+ conn = opened.conn;
492
+ }
493
+ finally {
494
+ await releaseInitLock();
495
+ }
263
496
  for (const schemaQuery of SCHEMA_QUERIES) {
264
497
  try {
265
- await conn.query(schemaQuery);
498
+ await queryAndDrain(conn, schemaQuery);
266
499
  }
267
500
  catch (err) {
268
501
  const msg = err instanceof Error ? err.message : String(err);
@@ -312,12 +545,12 @@ export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress)
312
545
  const normalizedPath = normalizeCopyPath(csvPath);
313
546
  const copyQuery = getCopyQuery(table, normalizedPath);
314
547
  try {
315
- await conn.query(copyQuery);
548
+ await queryAndDrain(conn, copyQuery);
316
549
  }
317
550
  catch (err) {
318
551
  try {
319
552
  const retryQuery = copyQuery.replace('auto_detect=false)', 'auto_detect=false, IGNORE_ERRORS=true)');
320
- await conn.query(retryQuery);
553
+ await queryAndDrain(conn, retryQuery);
321
554
  }
322
555
  catch (retryErr) {
323
556
  const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
@@ -350,12 +583,12 @@ export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress)
350
583
  log(`Loading edges: ${pairIdx}/${relsByPairMeta.size} types (${fromLabel} -> ${toLabel})`);
351
584
  }
352
585
  try {
353
- await conn.query(copyQuery);
586
+ await queryAndDrain(conn, copyQuery);
354
587
  }
355
588
  catch (err) {
356
589
  try {
357
590
  const retryQuery = copyQuery.replace('auto_detect=false)', 'auto_detect=false, IGNORE_ERRORS=true)');
358
- await conn.query(retryQuery);
591
+ await queryAndDrain(conn, retryQuery);
359
592
  }
360
593
  catch (retryErr) {
361
594
  const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
@@ -475,7 +708,7 @@ const fallbackRelationshipInserts = async (validRelLines, validTables, getNodeLa
475
708
  const confidence = parseFloat(confidenceStr) || 1.0;
476
709
  const step = parseInt(stepStr) || 0;
477
710
  const esc = (s) => s.replace(/'/g, "''").replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/\r/g, '\\r');
478
- await conn.query(`
711
+ await queryAndDrain(conn, `
479
712
  MATCH (a:${escapeLabel(fromLabel)} {id: '${esc(fromId)}' }),
480
713
  (b:${escapeLabel(toLabel)} {id: '${esc(toId)}' })
481
714
  CREATE (a)-[:${REL_TABLE_NAME} {type: '${esc(relType)}', confidence: ${confidence}, reason: '${esc(reason)}', step: ${step}}]->(b)
@@ -589,7 +822,7 @@ export const insertNodeToLbug = async (label, properties, dbPath) => {
589
822
  if (targetDbPath) {
590
823
  const tempHandle = await openLbugConnection(lbug, targetDbPath);
591
824
  try {
592
- await tempHandle.conn.query(query);
825
+ await queryAndDrain(tempHandle.conn, query);
593
826
  return true;
594
827
  }
595
828
  finally {
@@ -598,7 +831,7 @@ export const insertNodeToLbug = async (label, properties, dbPath) => {
598
831
  }
599
832
  else if (conn) {
600
833
  // Use existing persistent connection (when called from analyze)
601
- await conn.query(query);
834
+ await queryAndDrain(conn, query);
602
835
  return true;
603
836
  }
604
837
  return false;
@@ -667,7 +900,7 @@ export const batchInsertNodesToLbug = async (nodes, dbPath) => {
667
900
  : '';
668
901
  query = `MERGE (n:${t} {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.filePath = ${escapeValue(properties.filePath)}, n.startLine = ${properties.startLine || 0}, n.endLine = ${properties.endLine || 0}, n.content = ${escapeValue(properties.content || '')}${descPart}`;
669
902
  }
670
- await tempConn.query(query);
903
+ await queryAndDrain(tempConn, query);
671
904
  inserted++;
672
905
  }
673
906
  catch (e) {
@@ -686,19 +919,17 @@ export const executeQuery = async (cypher) => {
686
919
  throw new Error('LadybugDB not initialized. Call initLbug first.');
687
920
  }
688
921
  const queryResult = await conn.query(cypher);
689
- // LadybugDB uses getAll() instead of hasNext()/getNext()
690
- // Query returns QueryResult for single queries, QueryResult[] for multi-statement
691
- const result = Array.isArray(queryResult) ? queryResult[0] : queryResult;
692
- const rows = await result.getAll();
693
- return rows;
922
+ return await readQueryRows(queryResult);
694
923
  };
695
924
  export const streamQuery = async (cypher, onRow) => {
696
925
  if (!conn) {
697
926
  throw new Error('LadybugDB not initialized. Call initLbug first.');
698
927
  }
699
928
  const queryResult = await conn.query(cypher);
700
- const result = Array.isArray(queryResult) ? queryResult[0] : queryResult;
929
+ const results = Array.isArray(queryResult) ? queryResult : [queryResult];
930
+ const result = results[0];
701
931
  let rowCount = 0;
932
+ let streamError;
702
933
  try {
703
934
  while (await result.hasNext()) {
704
935
  const row = await result.getNext();
@@ -707,12 +938,17 @@ export const streamQuery = async (cypher, onRow) => {
707
938
  }
708
939
  return rowCount;
709
940
  }
941
+ catch (err) {
942
+ streamError = err;
943
+ throw err;
944
+ }
710
945
  finally {
711
946
  try {
712
- await result.close();
947
+ await drainQueryResult(results);
713
948
  }
714
- catch {
715
- // Best-effort cleanup only.
949
+ catch (err) {
950
+ if (streamError === undefined)
951
+ throw err;
716
952
  }
717
953
  }
718
954
  };
@@ -730,8 +966,7 @@ export const executePrepared = async (cypher, params) => {
730
966
  throw new Error(`Prepare failed: ${errMsg}`);
731
967
  }
732
968
  const queryResult = await conn.execute(stmt, params);
733
- const result = Array.isArray(queryResult) ? queryResult[0] : queryResult;
734
- return await result.getAll();
969
+ return await readQueryRows(queryResult);
735
970
  };
736
971
  export const executeWithReusedStatement = async (cypher, paramsList) => {
737
972
  if (!conn) {
@@ -749,7 +984,7 @@ export const executeWithReusedStatement = async (cypher, paramsList) => {
749
984
  }
750
985
  try {
751
986
  for (const params of subBatch) {
752
- await conn.execute(stmt, params);
987
+ await drainQueryResult(await conn.execute(stmt, params));
753
988
  }
754
989
  }
755
990
  catch (e) {
@@ -767,8 +1002,7 @@ export const getLbugStats = async () => {
767
1002
  for (const tableName of NODE_TABLES) {
768
1003
  try {
769
1004
  const queryResult = await conn.query(`MATCH (n:${escapeTableName(tableName)}) RETURN count(n) AS cnt`);
770
- const nodeResult = Array.isArray(queryResult) ? queryResult[0] : queryResult;
771
- const nodeRows = await nodeResult.getAll();
1005
+ const nodeRows = await readQueryRows(queryResult);
772
1006
  if (nodeRows.length > 0) {
773
1007
  totalNodes += Number(nodeRows[0]?.cnt ?? nodeRows[0]?.[0] ?? 0);
774
1008
  }
@@ -780,8 +1014,7 @@ export const getLbugStats = async () => {
780
1014
  let totalEdges = 0;
781
1015
  try {
782
1016
  const queryResult = await conn.query(`MATCH ()-[r:${REL_TABLE_NAME}]->() RETURN count(r) AS cnt`);
783
- const edgeResult = Array.isArray(queryResult) ? queryResult[0] : queryResult;
784
- const edgeRows = await edgeResult.getAll();
1017
+ const edgeRows = await readQueryRows(queryResult);
785
1018
  if (edgeRows.length > 0) {
786
1019
  totalEdges = Number(edgeRows[0]?.cnt ?? edgeRows[0]?.[0] ?? 0);
787
1020
  }
@@ -810,8 +1043,7 @@ export const loadCachedEmbeddings = async () => {
810
1043
  // If the query fails (column missing), we return empty cache to force a full rebuild.
811
1044
  try {
812
1045
  const check = await conn.query(`MATCH (e:${EMBEDDING_TABLE_NAME}) RETURN e.nodeId AS nodeId, e.chunkIndex AS chunkIndex LIMIT 1`);
813
- const checkResult = Array.isArray(check) ? check[0] : check;
814
- await checkResult.getAll();
1046
+ await readQueryRows(check);
815
1047
  }
816
1048
  catch {
817
1049
  return { embeddingNodeIds: new Set(), embeddings: [] };
@@ -833,8 +1065,7 @@ export const loadCachedEmbeddings = async () => {
833
1065
  throw err;
834
1066
  }
835
1067
  }
836
- const result = Array.isArray(rows) ? rows[0] : rows;
837
- for (const row of await result.getAll()) {
1068
+ for (const row of await readQueryRows(rows)) {
838
1069
  const nodeId = String(row.nodeId ?? row[0] ?? '');
839
1070
  if (!nodeId)
840
1071
  continue;
@@ -938,7 +1169,8 @@ export const flushWAL = async () => {
938
1169
  if (!conn)
939
1170
  return;
940
1171
  try {
941
- await conn.query('CHECKPOINT');
1172
+ const checkpointResult = await conn.query('CHECKPOINT');
1173
+ await drainQueryResult(checkpointResult);
942
1174
  }
943
1175
  catch {
944
1176
  /* ignore — older LadybugDB or schemaless DB may not accept it */
@@ -1036,12 +1268,11 @@ export const deleteNodesForFile = async (filePath, dbPath) => {
1036
1268
  // First count how many we'll delete
1037
1269
  const tn = escapeTableName(tableName);
1038
1270
  const countResult = await targetConn.query(`MATCH (n:${tn}) WHERE n.filePath = '${escapedPath}' RETURN count(n) AS cnt`);
1039
- const result = Array.isArray(countResult) ? countResult[0] : countResult;
1040
- const rows = await result.getAll();
1271
+ const rows = await readQueryRows(countResult);
1041
1272
  const count = Number(rows[0]?.cnt ?? rows[0]?.[0] ?? 0);
1042
1273
  if (count > 0) {
1043
1274
  // Delete nodes (and implicitly their relationships via DETACH)
1044
- await targetConn.query(`MATCH (n:${tn}) WHERE n.filePath = '${escapedPath}' DETACH DELETE n`);
1275
+ await queryAndDrain(targetConn, `MATCH (n:${tn}) WHERE n.filePath = '${escapedPath}' DETACH DELETE n`);
1045
1276
  deletedNodes += count;
1046
1277
  }
1047
1278
  }
@@ -1051,7 +1282,7 @@ export const deleteNodesForFile = async (filePath, dbPath) => {
1051
1282
  }
1052
1283
  // Also delete any embeddings for nodes in this file
1053
1284
  try {
1054
- await targetConn.query(`MATCH (e:${EMBEDDING_TABLE_NAME}) WHERE e.nodeId STARTS WITH '${escapedPath}' DELETE e`);
1285
+ await queryAndDrain(targetConn, `MATCH (e:${EMBEDDING_TABLE_NAME}) WHERE e.nodeId STARTS WITH '${escapedPath}' DELETE e`);
1055
1286
  }
1056
1287
  catch {
1057
1288
  // Embedding table may not exist or nodeId format may differ
@@ -1065,6 +1296,76 @@ export const deleteNodesForFile = async (filePath, dbPath) => {
1065
1296
  }
1066
1297
  };
1067
1298
  export const getEmbeddingTableName = () => EMBEDDING_TABLE_NAME;
1299
+ /**
1300
+ * Return the distinct repo-relative paths of files that import
1301
+ * `targetFilePath` according to the IMPORTS edges currently in the
1302
+ * DB. Used by the incremental writeback path to expand the
1303
+ * "files-to-rewrite" set so that files importing a changed file get
1304
+ * their edges (which may have been refined by cross-file resolution)
1305
+ * re-emitted, rather than left stale in the DB.
1306
+ *
1307
+ * The DB query reads the *previous* run's state — pre-pipeline, before
1308
+ * any nodes are deleted — so the returned importers are "files that
1309
+ * USED TO import the target". That's the right set to invalidate:
1310
+ * those are the files whose edges in the DB might no longer match
1311
+ * what cross-file resolution produces given the changed file's new
1312
+ * exports.
1313
+ */
1314
+ export const queryImporters = async (targetFilePath) => {
1315
+ if (!conn) {
1316
+ throw new Error('LadybugDB not initialized. Call initLbug first.');
1317
+ }
1318
+ const escaped = targetFilePath.replace(/'/g, "''");
1319
+ const cypher = `
1320
+ MATCH (a)-[r:${REL_TABLE_NAME}]->(b)
1321
+ WHERE r.type = 'IMPORTS' AND b.filePath = '${escaped}'
1322
+ RETURN DISTINCT a.filePath AS importer
1323
+ `;
1324
+ try {
1325
+ const queryResult = await conn.query(cypher);
1326
+ const result = Array.isArray(queryResult) ? queryResult[0] : queryResult;
1327
+ const rows = await result.getAll();
1328
+ const out = [];
1329
+ for (const row of rows) {
1330
+ const v = row.importer;
1331
+ if (typeof v === 'string' && v.length > 0)
1332
+ out.push(v);
1333
+ }
1334
+ return out;
1335
+ }
1336
+ catch {
1337
+ return [];
1338
+ }
1339
+ };
1340
+ /**
1341
+ * Drop every Community and Process node (and their MEMBER_OF /
1342
+ * STEP_IN_PROCESS edges via DETACH DELETE). Used at the start of an
1343
+ * incremental run so the communities and processes phases regenerate
1344
+ * them from scratch on the merged graph — required for the
1345
+ * "Leiden runs on the FULL graph" correctness invariant.
1346
+ */
1347
+ export const deleteAllCommunitiesAndProcesses = async () => {
1348
+ if (!conn) {
1349
+ throw new Error('LadybugDB not initialized. Call initLbug first.');
1350
+ }
1351
+ let nodesDeleted = 0;
1352
+ for (const label of ['Community', 'Process']) {
1353
+ try {
1354
+ const countResult = await conn.query(`MATCH (n:${label}) RETURN count(n) AS cnt`);
1355
+ const result = Array.isArray(countResult) ? countResult[0] : countResult;
1356
+ const rows = await result.getAll();
1357
+ const count = Number(rows[0]?.cnt ?? rows[0]?.[0] ?? 0);
1358
+ if (count > 0) {
1359
+ await conn.query(`MATCH (n:${label}) DETACH DELETE n`);
1360
+ nodesDeleted += count;
1361
+ }
1362
+ }
1363
+ catch {
1364
+ // Table may not exist yet on a freshly-initialized DB — fine.
1365
+ }
1366
+ }
1367
+ return { nodesDeleted };
1368
+ };
1068
1369
  // ============================================================================
1069
1370
  // Full-Text Search (FTS) Functions
1070
1371
  // ============================================================================
@@ -1088,7 +1389,7 @@ export const loadFTSExtension = async (targetConn, opts = {}) => {
1088
1389
  if (!c) {
1089
1390
  throw new Error('LadybugDB not initialized. Call initLbug first.');
1090
1391
  }
1091
- const loaded = await extensionManager.ensure((sql) => c.query(sql), 'fts', 'FTS', opts);
1392
+ const loaded = await extensionManager.ensure((sql) => queryAndDrain(c, sql), 'fts', 'FTS', opts);
1092
1393
  if (loaded && useModuleState)
1093
1394
  ftsLoaded = true;
1094
1395
  return loaded;
@@ -1116,7 +1417,7 @@ export const loadVectorExtension = async (targetConn, opts = {}) => {
1116
1417
  if (!c) {
1117
1418
  throw new Error('LadybugDB not initialized. Call initLbug first.');
1118
1419
  }
1119
- const loaded = await extensionManager.ensure((sql) => c.query(sql), 'VECTOR', 'VECTOR', opts);
1420
+ const loaded = await extensionManager.ensure((sql) => queryAndDrain(c, sql), 'VECTOR', 'VECTOR', opts);
1120
1421
  if (loaded && useModuleState)
1121
1422
  vectorExtensionLoaded = true;
1122
1423
  return loaded;
@@ -1141,7 +1442,7 @@ export const createFTSIndex = async (tableName, indexName, properties, stemmer =
1141
1442
  const propList = properties.map((p) => `'${p}'`).join(', ');
1142
1443
  const query = `CALL CREATE_FTS_INDEX('${tableName}', '${indexName}', [${propList}], stemmer := '${stemmer}')`;
1143
1444
  try {
1144
- await conn.query(query);
1445
+ await queryAndDrain(conn, query);
1145
1446
  ensuredFTSIndexes.add(key);
1146
1447
  }
1147
1448
  catch (e) {
@@ -1210,8 +1511,7 @@ export const queryFTS = async (tableName, indexName, query, limit = 20, conjunct
1210
1511
  `;
1211
1512
  try {
1212
1513
  const queryResult = await conn.query(cypher);
1213
- const result = Array.isArray(queryResult) ? queryResult[0] : queryResult;
1214
- const rows = await result.getAll();
1514
+ const rows = await readQueryRows(queryResult);
1215
1515
  return rows.map((row) => {
1216
1516
  const node = row.node || row[0] || {};
1217
1517
  const score = row.score ?? row[1] ?? 0;
@@ -1240,7 +1540,7 @@ export const dropFTSIndex = async (tableName, indexName) => {
1240
1540
  throw new Error('LadybugDB not initialized. Call initLbug first.');
1241
1541
  }
1242
1542
  try {
1243
- await conn.query(`CALL DROP_FTS_INDEX('${tableName}', '${indexName}')`);
1543
+ await queryAndDrain(conn, `CALL DROP_FTS_INDEX('${tableName}', '${indexName}')`);
1244
1544
  }
1245
1545
  catch {
1246
1546
  // Index may not exist
@@ -42,6 +42,8 @@ export interface AnalyzeOptions {
42
42
  skipAgentsMd?: boolean;
43
43
  /** Omit volatile symbol/relationship counts from AGENTS.md and CLAUDE.md. */
44
44
  noStats?: boolean;
45
+ /** Skip installing standard GitNexus skill files to .claude/skills/gitnexus/. */
46
+ skipSkills?: boolean;
45
47
  /**
46
48
  * User-provided alias for the registry `name` (#829). When set,
47
49
  * forwarded to `registerRepo` so the indexed repo is stored under