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
@@ -10,6 +10,7 @@ import { realpathSync } from 'fs';
10
10
  import path from 'path';
11
11
  import os from 'os';
12
12
  import { getInferredRepoName, resolveRepoIdentityRoot } from './git.js';
13
+ import { logger } from '../core/logger.js';
13
14
  /**
14
15
  * Normalise a repo path for registry comparison across platforms
15
16
  * (#664 review feedback from @evander-wang).
@@ -49,6 +50,10 @@ export const canonicalizePath = (p) => {
49
50
  return resolved;
50
51
  }
51
52
  };
53
+ /**
54
+ * Bumped whenever incremental-indexing invariants change incompatibly.
55
+ */
56
+ export const INCREMENTAL_SCHEMA_VERSION = 1;
52
57
  const GITNEXUS_DIR = '.gitnexus';
53
58
  const GITNEXUS_EXCLUDE_ENTRY = `${GITNEXUS_DIR}/`;
54
59
  // ─── Local Storage Helpers ─────────────────────────────────────────────
@@ -137,12 +142,23 @@ export const loadMeta = async (storagePath) => {
137
142
  }
138
143
  };
139
144
  /**
140
- * Save metadata to storage
145
+ * Save metadata to storage.
146
+ *
147
+ * Atomic via tmp-file + rename (matches `saveParseCache`'s pattern). The
148
+ * `incrementalInProgress` dirty flag travels through this file — a crash
149
+ * mid-write would leave a corrupt `meta.json` that the next run's
150
+ * `loadMeta` would silently treat as "no prior index", losing the dirty
151
+ * flag and skipping the recovery full-rebuild. Write-and-rename rules
152
+ * that out: the rename is atomic on POSIX and on Windows (`fs.rename`
153
+ * on `node:fs/promises` uses `MoveFileEx(REPLACE_EXISTING)`), so either
154
+ * the old or the new file is observed at every moment.
141
155
  */
142
156
  export const saveMeta = async (storagePath, meta) => {
143
157
  await fs.mkdir(storagePath, { recursive: true });
144
158
  const metaPath = path.join(storagePath, 'meta.json');
145
- await fs.writeFile(metaPath, JSON.stringify(meta, null, 2), 'utf-8');
159
+ const tmpPath = `${metaPath}.tmp`;
160
+ await fs.writeFile(tmpPath, JSON.stringify(meta, null, 2), 'utf-8');
161
+ await fs.rename(tmpPath, metaPath);
146
162
  };
147
163
  /**
148
164
  * Check if a path has a GitNexus index
@@ -185,13 +201,42 @@ export const findRepo = async (startPath) => {
185
201
  }
186
202
  return null;
187
203
  };
204
+ function isReadOnlyFilesystemError(err) {
205
+ const code = err?.code;
206
+ return code === 'EROFS' || code === 'EACCES' || code === 'EPERM';
207
+ }
188
208
  /**
189
209
  * Keep generated index files ignored without modifying the user's root .gitignore.
190
210
  */
191
211
  export const ensureGitNexusIgnored = async (repoPath) => {
192
212
  const gitignorePath = path.join(getStoragePath(repoPath), '.gitignore');
193
- await fs.mkdir(path.dirname(gitignorePath), { recursive: true });
194
- await fs.writeFile(gitignorePath, '*\n', 'utf-8');
213
+ const desired = '*\n';
214
+ // Idempotent fast path: skip the write entirely when the file already has
215
+ // the expected content. Lets this run cleanly on read-only mounts (e.g.
216
+ // the documented Docker workflow with WORKSPACE_DIR bound :ro) when an
217
+ // earlier `analyze` already created the file. See issue #1549.
218
+ try {
219
+ if ((await fs.readFile(gitignorePath, 'utf-8')) === desired) {
220
+ await ensureGitInfoExclude(repoPath);
221
+ return;
222
+ }
223
+ }
224
+ catch (err) {
225
+ if (err?.code !== 'ENOENT')
226
+ throw err;
227
+ }
228
+ try {
229
+ await fs.mkdir(path.dirname(gitignorePath), { recursive: true });
230
+ await fs.writeFile(gitignorePath, desired, 'utf-8');
231
+ }
232
+ catch (err) {
233
+ if (isReadOnlyFilesystemError(err)) {
234
+ logger.warn({ path: gitignorePath, code: err.code }, 'GitNexus storage filesystem is not writable; skipping .gitnexus/.gitignore. Generated files may appear as untracked in this repo locally.');
235
+ }
236
+ else {
237
+ throw err;
238
+ }
239
+ }
195
240
  await ensureGitInfoExclude(repoPath);
196
241
  };
197
242
  const ensureGitInfoExclude = async (repoPath) => {
@@ -205,7 +250,6 @@ const ensureGitInfoExclude = async (repoPath) => {
205
250
  catch {
206
251
  return;
207
252
  }
208
- await fs.mkdir(path.dirname(excludePath), { recursive: true });
209
253
  let content = '';
210
254
  try {
211
255
  content = await fs.readFile(excludePath, 'utf-8');
@@ -221,7 +265,18 @@ const ensureGitInfoExclude = async (repoPath) => {
221
265
  if (excludes.includes(GITNEXUS_DIR) || excludes.includes(GITNEXUS_EXCLUDE_ENTRY))
222
266
  return;
223
267
  const separator = content.length === 0 || content.endsWith('\n') ? '' : '\n';
224
- await fs.writeFile(excludePath, `${content}${separator}${GITNEXUS_EXCLUDE_ENTRY}\n`, 'utf-8');
268
+ try {
269
+ await fs.mkdir(path.dirname(excludePath), { recursive: true });
270
+ await fs.writeFile(excludePath, `${content}${separator}${GITNEXUS_EXCLUDE_ENTRY}\n`, 'utf-8');
271
+ }
272
+ catch (err) {
273
+ if (isReadOnlyFilesystemError(err)) {
274
+ logger.warn({ path: excludePath, code: err.code }, 'GitNexus storage filesystem is not writable; skipping .git/info/exclude update. .gitnexus/ may appear as untracked in `git status` locally.');
275
+ }
276
+ else {
277
+ throw err;
278
+ }
279
+ }
225
280
  };
226
281
  // ─── Global Registry (~/.gitnexus/registry.json) ───────────────────────
227
282
  /**
@@ -14,6 +14,8 @@
14
14
  const fs = require('fs');
15
15
  const path = require('path');
16
16
  const { spawnSync } = require('child_process');
17
+ const { acquireHookSlot } = require('./hook-lock.cjs');
18
+ const { hasGitNexusDbLockedByGitNexusServer } = require('./hook-db-lock-probe.cjs');
17
19
 
18
20
  /**
19
21
  * Read JSON input from stdin synchronously.
@@ -102,6 +104,28 @@ function findGitNexusDir(startDir) {
102
104
  return null;
103
105
  }
104
106
 
107
+ function hasGitNexusServerOwner(gitNexusDir) {
108
+ return hasGitNexusDbLockedByGitNexusServer(path.join(gitNexusDir, 'lbug'), process.pid);
109
+ }
110
+
111
+ function extractAugmentContext(stderr) {
112
+ const output = (stderr || '').trim();
113
+ const marker = output.indexOf('[GitNexus]');
114
+ const debug = process.env.GITNEXUS_DEBUG === '1' || process.env.GITNEXUS_DEBUG === 'true';
115
+ if (debug && output.length > 0) {
116
+ // Emit the FULL discarded prefix (everything before the marker, or all of
117
+ // it when no marker is present) so suppressed diagnostics — KuzuDB lock
118
+ // warnings, parser errors, etc. — remain recoverable on the hook's own
119
+ // stderr. The untruncated payload lets operators see exactly what was
120
+ // filtered out instead of a 180-char JSON-quoted preview.
121
+ const discarded = marker === -1 ? output : output.slice(0, marker).trim();
122
+ if (discarded.length > 0) {
123
+ process.stderr.write(`[GitNexus hook] augment stderr discarded prefix:\n${discarded}\n`);
124
+ }
125
+ }
126
+ return marker === -1 ? '' : output.slice(marker).trim();
127
+ }
128
+
105
129
  /**
106
130
  * Extract search pattern from tool input.
107
131
  */
@@ -167,6 +191,10 @@ function extractPattern(toolName, toolInput) {
167
191
  * 3. Fall back to npx (returns empty string)
168
192
  */
169
193
  function resolveCliPath() {
194
+ const fromEnv = process.env.GITNEXUS_HOOK_CLI_PATH;
195
+ if (fromEnv !== undefined && String(fromEnv).trim() && fs.existsSync(String(fromEnv))) {
196
+ return String(fromEnv);
197
+ }
170
198
  let cliPath = path.resolve(__dirname, '..', '..', 'dist', 'cli', 'index.js');
171
199
  if (!fs.existsSync(cliPath)) {
172
200
  try {
@@ -207,7 +235,8 @@ function runGitNexusCli(cliPath, args, cwd, timeout) {
207
235
  function handlePreToolUse(input) {
208
236
  const cwd = input.cwd || process.cwd();
209
237
  if (!path.isAbsolute(cwd)) return;
210
- if (!findGitNexusDir(cwd)) return;
238
+ const gitNexusDir = findGitNexusDir(cwd);
239
+ if (!gitNexusDir) return;
211
240
 
212
241
  const toolName = input.tool_name || '';
213
242
  const toolInput = input.tool_input || {};
@@ -216,20 +245,29 @@ function handlePreToolUse(input) {
216
245
 
217
246
  const pattern = extractPattern(toolName, toolInput);
218
247
  if (!pattern || pattern.length < 3) return;
248
+ if (hasGitNexusServerOwner(gitNexusDir)) {
249
+ process.stderr.write('[GitNexus] augment skipped: MCP server owns DB\n');
250
+ return;
251
+ }
252
+
253
+ const release = acquireHookSlot(gitNexusDir);
254
+ if (!release) return;
219
255
 
220
256
  const cliPath = resolveCliPath();
221
257
  let result = '';
222
258
  try {
223
259
  const child = runGitNexusCli(cliPath, ['augment', '--', pattern], cwd, 7000);
224
260
  if (!child.error && child.status === 0) {
225
- result = child.stderr || '';
261
+ result = extractAugmentContext(child.stderr || '');
226
262
  }
227
263
  } catch {
228
264
  /* graceful failure */
265
+ } finally {
266
+ release();
229
267
  }
230
268
 
231
- if (result && result.trim()) {
232
- sendHookResponse('PreToolUse', result.trim());
269
+ if (result) {
270
+ sendHookResponse('PreToolUse', result);
233
271
  }
234
272
  }
235
273
 
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Cross-platform best-effort probe: does another process hold dbPath open
3
+ * with a command line that looks like a GitNexus MCP/serve server?
4
+ *
5
+ * Backends (no user-installed Sysinternals):
6
+ * - Linux: scan procfs under /proc (per-PID fd entries) via stat(2) (dev+inode); works without lsof;
7
+ * optional lsof fallback when proc scan finds nothing.
8
+ * - macOS / *BSD / etc.: trusted lsof + ps (absolute paths first).
9
+ * - Windows: Restart Manager (rstrtmgr) via bundled PowerShell script +
10
+ * Win32_Process for command lines; trusted powershell.exe under %SystemRoot%.
11
+ *
12
+ * Fail-open on most errors; fail-closed only on lsof ETIMEDOUT (Unix) or
13
+ * PowerShell ETIMEDOUT (Windows), matching the hook contract.
14
+ */
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const { spawnSync } = require('child_process');
19
+
20
+ function isGitNexusServerCommand(command) {
21
+ const hasServerMode = /(?:^|\s)(mcp|serve)(?:\s|$)/.test(command);
22
+ const hasGitNexus =
23
+ /(?:^|[/\\\s])gitnexus(?:\.cmd)?(?:\s|$)/.test(command) ||
24
+ /node_modules[/\\]gitnexus[/\\]/.test(command);
25
+ return hasServerMode && hasGitNexus;
26
+ }
27
+
28
+ function resolveHookBinary(tool) {
29
+ const envKey = tool === 'lsof' ? 'GITNEXUS_HOOK_LSOF_PATH' : 'GITNEXUS_HOOK_PS_PATH';
30
+ const fromEnv = process.env[envKey];
31
+ if (fromEnv && String(fromEnv).trim() && fs.existsSync(String(fromEnv))) {
32
+ return String(fromEnv);
33
+ }
34
+ const candidates =
35
+ tool === 'lsof'
36
+ ? ['/usr/bin/lsof', '/usr/sbin/lsof', '/sbin/lsof', tool]
37
+ : ['/bin/ps', '/usr/bin/ps', tool];
38
+ for (const candidate of candidates) {
39
+ if (candidate === tool) return tool;
40
+ try {
41
+ if (fs.existsSync(candidate)) return candidate;
42
+ } catch {
43
+ /* ignore */
44
+ }
45
+ }
46
+ return tool;
47
+ }
48
+
49
+ function resolveWindowsPowerShellPath() {
50
+ const fromEnv = process.env.GITNEXUS_HOOK_POWERSHELL_PATH;
51
+ if (fromEnv && String(fromEnv).trim() && fs.existsSync(String(fromEnv).trim())) {
52
+ return String(fromEnv).trim();
53
+ }
54
+ const root = process.env.SystemRoot || 'C:\\Windows';
55
+ const ps = path.join(root, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
56
+ if (fs.existsSync(ps)) return ps;
57
+ const psWow = path.join(root, 'SysWOW64', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
58
+ if (fs.existsSync(psWow)) return psWow;
59
+ return 'powershell.exe';
60
+ }
61
+
62
+ // Sentinel:
63
+ // undefined = not loaded yet (try the read)
64
+ // string = encoded PowerShell command (successful load)
65
+ // null = load attempted and failed (do not retry; warning already emitted)
66
+ let windowsRmListPsEncodedCommandCache;
67
+ let windowsRmListPsLoadFailureWarned = false;
68
+ function getWindowsRmListEncodedCommand() {
69
+ if (windowsRmListPsEncodedCommandCache !== undefined) {
70
+ return windowsRmListPsEncodedCommandCache;
71
+ }
72
+ try {
73
+ const ps1Path = path.join(__dirname, 'win-rm-list-json.ps1');
74
+ const src = fs
75
+ .readFileSync(ps1Path, 'utf8')
76
+ .replace(/^\uFEFF/, '')
77
+ .replace(/\r\n/g, '\n');
78
+ windowsRmListPsEncodedCommandCache = Buffer.from(src, 'utf16le').toString('base64');
79
+ } catch (err) {
80
+ windowsRmListPsEncodedCommandCache = null;
81
+ if (
82
+ !windowsRmListPsLoadFailureWarned &&
83
+ (process.env.GITNEXUS_DEBUG === '1' || process.env.GITNEXUS_DEBUG === 'true')
84
+ ) {
85
+ windowsRmListPsLoadFailureWarned = true;
86
+ const msg = err && err.message ? String(err.message).slice(0, 200) : 'unknown';
87
+ process.stderr.write(`[GitNexus hook] win-rm-list-json.ps1 load failed: ${msg}\n`);
88
+ }
89
+ }
90
+ return windowsRmListPsEncodedCommandCache;
91
+ }
92
+
93
+ function hasGitNexusServerOwnerWindows(dbPathAbs, myPid) {
94
+ const encoded = getWindowsRmListEncodedCommand();
95
+ if (!encoded) return false;
96
+ const psExe = resolveWindowsPowerShellPath();
97
+ const r = spawnSync(
98
+ psExe,
99
+ [
100
+ '-NoProfile',
101
+ '-NonInteractive',
102
+ '-ExecutionPolicy',
103
+ 'Bypass',
104
+ '-STA',
105
+ '-EncodedCommand',
106
+ encoded,
107
+ ],
108
+ {
109
+ encoding: 'utf-8',
110
+ timeout: 6000,
111
+ stdio: ['ignore', 'pipe', 'ignore'],
112
+ env: { ...process.env, GITNEXUS_HOOK_RM_TARGET: dbPathAbs },
113
+ },
114
+ );
115
+ // ETIMEDOUT means the PowerShell probe didn't return in time; treat as 'unresponsive process holds DB' → fail-closed (skip augment).
116
+ if (r.error) return r.error.code === 'ETIMEDOUT';
117
+ if (r.status !== 0) return false;
118
+ let rows;
119
+ try {
120
+ rows = JSON.parse(String(r.stdout || '').trim() || '[]');
121
+ } catch {
122
+ return false;
123
+ }
124
+ if (!Array.isArray(rows)) return false;
125
+ for (const row of rows) {
126
+ const procId = Number(row.pid);
127
+ const cmd = String(row.cmd || '');
128
+ if (!Number.isFinite(procId) || procId === myPid) continue;
129
+ if (isGitNexusServerCommand(cmd)) return true;
130
+ }
131
+ return false;
132
+ }
133
+
134
+ function readLinuxCmdline(pidStr) {
135
+ try {
136
+ return fs.readFileSync(`/proc/${pidStr}/cmdline`, 'utf8').replace(/\0+/g, ' ').trim();
137
+ } catch {
138
+ return '';
139
+ }
140
+ }
141
+
142
+ function linuxProcScanFindGitNexusServer(dbPathAbs, myPid) {
143
+ const raw = process.env.GITNEXUS_HOOK_LINUX_PROC_BUDGET_MS;
144
+ const budget = Number(raw && String(raw).trim()) ? Number.parseInt(String(raw), 10) : 1200;
145
+ const start = Date.now();
146
+ let targetStat;
147
+ try {
148
+ targetStat = fs.statSync(dbPathAbs);
149
+ } catch {
150
+ return false;
151
+ }
152
+ let procEntries;
153
+ try {
154
+ procEntries = fs.readdirSync('/proc', { withFileTypes: true });
155
+ } catch {
156
+ return false;
157
+ }
158
+ for (const ent of procEntries) {
159
+ if (Date.now() - start > budget) return false;
160
+ if (!ent.isDirectory() || !/^\d+$/.test(ent.name)) continue;
161
+ const pid = Number.parseInt(ent.name, 10);
162
+ if (!Number.isFinite(pid) || pid === myPid) continue;
163
+ const fdDir = path.join('/proc', ent.name, 'fd');
164
+ let fds;
165
+ try {
166
+ fds = fs.readdirSync(fdDir);
167
+ } catch {
168
+ continue;
169
+ }
170
+ let holds = false;
171
+ for (const fd of fds) {
172
+ if (Date.now() - start > budget) return false;
173
+ try {
174
+ const st = fs.statSync(path.join(fdDir, fd));
175
+ if (st.dev === targetStat.dev && st.ino === targetStat.ino) {
176
+ holds = true;
177
+ break;
178
+ }
179
+ } catch {
180
+ /* ignore */
181
+ }
182
+ }
183
+ if (!holds) continue;
184
+ if (isGitNexusServerCommand(readLinuxCmdline(ent.name))) return true;
185
+ }
186
+ return false;
187
+ }
188
+
189
+ function unixLsofPsFindGitNexusServer(dbPathAbs, myPid) {
190
+ const lsofPath = resolveHookBinary('lsof');
191
+ const lsof = spawnSync(lsofPath, ['-nP', '-t', '--', dbPathAbs], {
192
+ encoding: 'utf-8',
193
+ timeout: 1000,
194
+ stdio: ['ignore', 'pipe', 'ignore'],
195
+ });
196
+ if (lsof.error) return lsof.error.code === 'ETIMEDOUT';
197
+
198
+ const pids = (lsof.stdout || '').split(/\s+/).filter(Boolean);
199
+ const psPath = resolveHookBinary('ps');
200
+ for (const pid of pids) {
201
+ if (Number(pid) === myPid) continue;
202
+ const ps = spawnSync(psPath, ['-p', pid, '-o', 'command='], {
203
+ encoding: 'utf-8',
204
+ timeout: 500,
205
+ stdio: ['ignore', 'pipe', 'ignore'],
206
+ });
207
+ if (ps.error) {
208
+ if (ps.error.code === 'ETIMEDOUT') return true;
209
+ continue;
210
+ }
211
+ if (isGitNexusServerCommand(ps.stdout || '')) return true;
212
+ }
213
+ return false;
214
+ }
215
+
216
+ /**
217
+ * @param {string} dbPath Absolute or relative path to the DB file (e.g. .../lbug).
218
+ * @param {number} myPid Current process PID (hook runner), excluded from matches.
219
+ */
220
+ function hasGitNexusDbLockedByGitNexusServer(dbPath, myPid) {
221
+ if (!fs.existsSync(dbPath)) return false;
222
+ const dbPathAbs = path.resolve(dbPath);
223
+
224
+ if (process.platform === 'win32') {
225
+ return hasGitNexusServerOwnerWindows(dbPathAbs, myPid);
226
+ }
227
+
228
+ if (process.platform === 'linux') {
229
+ if (linuxProcScanFindGitNexusServer(dbPathAbs, myPid)) return true;
230
+ return unixLsofPsFindGitNexusServer(dbPathAbs, myPid);
231
+ }
232
+
233
+ return unixLsofPsFindGitNexusServer(dbPathAbs, myPid);
234
+ }
235
+
236
+ module.exports = {
237
+ hasGitNexusDbLockedByGitNexusServer,
238
+ };
@@ -0,0 +1,119 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const HOOK_LOCK_SUBDIR = '.hook-locks';
5
+ const HOOK_LOCK_MAX_INFLIGHT = 3;
6
+ const HOOK_LOCK_STALE_MS = 30000;
7
+
8
+ function acquireHookSlot(gitNexusDir) {
9
+ const lockDir = path.join(gitNexusDir, HOOK_LOCK_SUBDIR);
10
+ try {
11
+ fs.mkdirSync(lockDir, { recursive: true });
12
+ } catch {
13
+ // Cannot create lock dir (read-only fs, cross-user perm denial, out of
14
+ // inodes, etc.) — fail closed by returning null. Caller skips augment.
15
+ // Fail-open here would let N concurrent hooks all proceed unguarded and
16
+ // reintroduce the #1486 fan-out the guard exists to prevent.
17
+ return null;
18
+ }
19
+
20
+ const myPidStr = String(process.pid);
21
+
22
+ for (let slot = 0; slot < HOOK_LOCK_MAX_INFLIGHT; slot++) {
23
+ const slotPath = path.join(lockDir, `slot-${slot}.lock`);
24
+ for (let attempt = 0; attempt < 2; attempt++) {
25
+ try {
26
+ fs.writeFileSync(slotPath, myPidStr, { flag: 'wx' });
27
+ let released = false;
28
+ const release = () => {
29
+ if (released) return;
30
+ released = true;
31
+ try {
32
+ // Only unlink if we still own the slot. If we appeared stale and
33
+ // another hook took over, the file now belongs to it — leave alone.
34
+ const content = fs.readFileSync(slotPath, 'utf-8').trim();
35
+ if (content === myPidStr) fs.unlinkSync(slotPath);
36
+ } catch {
37
+ /* already removed or unreadable */
38
+ }
39
+ };
40
+ process.on('exit', release);
41
+ return release;
42
+ } catch {
43
+ // Slot exists. Decide whether to take it over.
44
+ // Open once and inspect mtime + content via the same fd so there's
45
+ // no TOCTOU between the metadata check and the content read
46
+ // (codeql js/file-system-race).
47
+ let fd;
48
+ try {
49
+ fd = fs.openSync(slotPath, 'r');
50
+ } catch {
51
+ continue; // Vanished between EEXIST and open — retry this slot.
52
+ }
53
+ let isLive = false;
54
+ let mtimeMs = Date.now();
55
+ try {
56
+ mtimeMs = fs.fstatSync(fd).mtimeMs;
57
+ const buf = Buffer.alloc(32);
58
+ const n = fs.readSync(fd, buf, 0, 32, 0);
59
+ const ownerStr = buf.slice(0, n).toString('utf-8').trim();
60
+ if (ownerStr === '') {
61
+ // Owner created the file but hasn't written its PID yet. The
62
+ // wx open+write window is microseconds; give it the benefit
63
+ // of the doubt and treat as live.
64
+ isLive = true;
65
+ } else {
66
+ const owner = Number.parseInt(ownerStr, 10);
67
+ if (Number.isFinite(owner) && owner > 0) {
68
+ try {
69
+ process.kill(owner, 0);
70
+ isLive = true;
71
+ } catch (e) {
72
+ // ESRCH = process gone → treat as dead. EPERM = process exists
73
+ // but owned by another user (cross-user lock dir) → still alive,
74
+ // keep the slot. Anything else: be conservative, assume alive.
75
+ if (e && e.code === 'ESRCH') {
76
+ isLive = false;
77
+ } else {
78
+ isLive = true;
79
+ }
80
+ }
81
+ }
82
+ }
83
+ } catch {
84
+ /* unreadable — treat as dead */
85
+ } finally {
86
+ try {
87
+ fs.closeSync(fd);
88
+ } catch {
89
+ /* already closed */
90
+ }
91
+ }
92
+ // For slots younger than HOOK_LOCK_STALE_MS, PID-liveness wins —
93
+ // a slow-but-alive hook is never wrongly evicted. For older slots,
94
+ // age is the final arbiter as a defense against PID reuse on long-
95
+ // abandoned slots. 30s >> the 7s augment timeout, so a healthy run
96
+ // never crosses this threshold.
97
+ if (isLive && Date.now() - mtimeMs > HOOK_LOCK_STALE_MS) {
98
+ isLive = false;
99
+ }
100
+ if (isLive) break; // Try the next slot.
101
+ try {
102
+ fs.unlinkSync(slotPath);
103
+ } catch {
104
+ /* another hook beat us to it — retry will hit EEXIST */
105
+ }
106
+ // Loop and retry this slot.
107
+ }
108
+ }
109
+ }
110
+
111
+ return null;
112
+ }
113
+
114
+ module.exports = {
115
+ HOOK_LOCK_SUBDIR,
116
+ HOOK_LOCK_MAX_INFLIGHT,
117
+ HOOK_LOCK_STALE_MS,
118
+ acquireHookSlot,
119
+ };
@@ -0,0 +1,76 @@
1
+ $ErrorActionPreference = 'Stop'
2
+ $target = $env:GITNEXUS_HOOK_RM_TARGET
3
+ if ([string]::IsNullOrWhiteSpace($target)) { Write-Output '[]'; exit 0 }
4
+ $target = (Resolve-Path -LiteralPath $target).ProviderPath
5
+
6
+ if (-not ([Management.Automation.PSTypeName]'GitNexusHookRm.Native').Type) {
7
+ Add-Type @'
8
+ using System;
9
+ using System.Runtime.InteropServices;
10
+ namespace GitNexusHookRm {
11
+ public static class Native {
12
+ public const int ErrorMoreData = 234;
13
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
14
+ public struct RM_UNIQUE_PROCESS {
15
+ public int dwProcessId;
16
+ public long ProcessStartTime;
17
+ }
18
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
19
+ public struct RM_PROCESS_INFO {
20
+ public RM_UNIQUE_PROCESS Process;
21
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
22
+ public string strAppName;
23
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
24
+ public string strServiceShortName;
25
+ public uint ApplicationType;
26
+ public uint AppStatus;
27
+ public uint TSSessionId;
28
+ public uint bRestartable;
29
+ }
30
+ [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
31
+ public static extern int RmStartSession(out uint pSessionHandle, uint dwSessionFlags, string strSessionKey);
32
+ [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
33
+ public static extern int RmRegisterResources(uint pSessionHandle, uint nFiles, string[] rgsFileNames, uint nApplications, IntPtr rgApplications, uint nServices, string[] rgsServiceNames);
34
+ [DllImport("rstrtmgr.dll")]
35
+ public static extern int RmGetList(uint dwSessionHandle, out uint pnProcInfoNeeded, ref uint pnProcInfo, [In, Out] RM_PROCESS_INFO[] rgAffectedApps, ref uint lpdwRebootReasons);
36
+ [DllImport("rstrtmgr.dll")]
37
+ public static extern int RmEndSession(uint pSessionHandle);
38
+ }
39
+ }
40
+ '@
41
+ }
42
+
43
+ $h = [uint32]0
44
+ $key = [guid]::NewGuid().ToString('N')
45
+ $rmErr = [GitNexusHookRm.Native]::RmStartSession([ref]$h, 0, $key)
46
+ if ($rmErr -ne 0) { Write-Output '[]'; exit 0 }
47
+ $files = @($target)
48
+ $err = [GitNexusHookRm.Native]::RmRegisterResources($h, 1, $files, 0, [IntPtr]::Zero, 0, $null)
49
+ if ($err -ne 0) {
50
+ [void][GitNexusHookRm.Native]::RmEndSession($h)
51
+ Write-Output '[]'
52
+ exit 0
53
+ }
54
+ $need = [uint32]0
55
+ $n = [uint32]0
56
+ $reboot = [uint32]0
57
+ $err = [GitNexusHookRm.Native]::RmGetList($h, [ref]$need, [ref]$n, $null, [ref]$reboot)
58
+ if ($err -ne [GitNexusHookRm.Native]::ErrorMoreData) {
59
+ [void][GitNexusHookRm.Native]::RmEndSession($h)
60
+ Write-Output '[]'
61
+ exit 0
62
+ }
63
+ $n = $need
64
+ $buf = New-Object GitNexusHookRm.Native+RM_PROCESS_INFO[] ([int]$n)
65
+ $err = [GitNexusHookRm.Native]::RmGetList($h, [ref]$need, [ref]$n, $buf, [ref]$reboot)
66
+ [void][GitNexusHookRm.Native]::RmEndSession($h)
67
+ if ($err -ne 0) { Write-Output '[]'; exit 0 }
68
+
69
+ $out = @()
70
+ for ($i = 0; $i -lt [int]$n; $i++) {
71
+ $procId = $buf[$i].Process.dwProcessId
72
+ $p = Get-CimInstance -ClassName Win32_Process -Filter "ProcessId=$procId" -ErrorAction SilentlyContinue
73
+ $cmd = if ($p) { $p.CommandLine } else { '' }
74
+ $out += [PSCustomObject]@{ pid = [int]$procId; cmd = $cmd }
75
+ }
76
+ ConvertTo-Json -InputObject @($out) -Compress
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.5-rc.8",
3
+ "version": "1.6.5",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",
package/scripts/build.js CHANGED
@@ -21,11 +21,15 @@ const SHARED_DEST = path.join(DIST, '_shared');
21
21
 
22
22
  // ── 1. Build gitnexus-shared ───────────────────────────────────────
23
23
  console.log('[build] compiling gitnexus-shared…');
24
- execSync('npx tsc', { cwd: SHARED_ROOT, stdio: 'inherit', timeout: 120_000 });
24
+ const tscCmd =
25
+ process.platform === 'win32'
26
+ ? path.join('node_modules', '.bin', 'tsc.cmd')
27
+ : path.join('node_modules', '.bin', 'tsc');
28
+ execSync(tscCmd, { cwd: SHARED_ROOT, stdio: 'inherit', timeout: 120_000 });
25
29
 
26
30
  // ── 2. Build gitnexus ──────────────────────────────────────────────
27
31
  console.log('[build] compiling gitnexus…');
28
- execSync('npx tsc', { cwd: ROOT, stdio: 'inherit', timeout: 120_000 });
32
+ execSync(tscCmd, { cwd: ROOT, stdio: 'inherit', timeout: 120_000 });
29
33
 
30
34
  // ── 3. Copy shared dist ────────────────────────────────────────────
31
35
  console.log('[build] copying shared module into dist/_shared…');