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
@@ -11,40 +11,24 @@ import { getDefinitionNodeFromCaptures, findEnclosingClassInfo, getLabelFromCapt
11
11
  import { detectFrameworkFromAST } from './framework-detection.js';
12
12
  import { buildTypeEnv } from './type-env.js';
13
13
  import { buildMethodProps, arityForIdFromInfo, typeTagForId, constTagForId, buildCollisionGroups, } from './utils/method-props.js';
14
+ import { extractTemplateArguments, templateArgumentsIdTag } from './utils/template-arguments.js';
14
15
  import { logger } from '../logger.js';
15
16
  import { getTreeSitterBufferSize, getTreeSitterContentByteLength, TREE_SITTER_MAX_BUFFER, } from './constants.js';
16
17
  // ============================================================================
17
18
  // Worker-based parallel parsing
18
19
  // ============================================================================
19
- const processParsingWithWorkers = async (graph, files, symbolTable, astCache, workerPool, onFileProgress) => {
20
- // Filter to parseable files only
21
- const parseableFiles = [];
22
- for (const file of files) {
23
- const lang = getLanguageFromFilename(file.path);
24
- if (lang)
25
- parseableFiles.push({ path: file.path, content: file.content });
26
- }
27
- if (parseableFiles.length === 0)
28
- return {
29
- imports: [],
30
- calls: [],
31
- assignments: [],
32
- heritage: [],
33
- routes: [],
34
- fetchCalls: [],
35
- decoratorRoutes: [],
36
- toolDefs: [],
37
- ormQueries: [],
38
- constructorBindings: [],
39
- fileScopeBindings: [],
40
- parsedFiles: [],
41
- };
42
- const total = files.length;
43
- // Dispatch to worker pool — pool handles splitting into chunks and sub-batching
44
- const chunkResults = await workerPool.dispatch(parseableFiles, (filesProcessed) => {
45
- onFileProgress?.(Math.min(filesProcessed, total), total, 'Parsing...');
46
- });
47
- // Merge results from all workers into graph and symbol table
20
+ /**
21
+ * Merge a list of `ParseWorkerResult`s into the running graph + symbol
22
+ * table state and produce the chunk-aggregated `WorkerExtractedData`.
23
+ *
24
+ * Extracted from `processParsingWithWorkers` so the same merge logic can
25
+ * be applied to both freshly-parsed worker output AND cached worker
26
+ * output replayed during incremental analyze. Idempotent on the
27
+ * accumulator fields (push-only); idempotent on graph if the caller
28
+ * starts from a clean graph (otherwise duplicate `addNode` calls are
29
+ * silently no-op'd by `KnowledgeGraph`).
30
+ */
31
+ export const mergeChunkResults = (graph, symbolTable, chunkResults) => {
48
32
  const allImports = [];
49
33
  const allCalls = [];
50
34
  const allAssignments = [];
@@ -75,6 +59,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
75
59
  parameterTypes: sym.parameterTypes,
76
60
  returnType: sym.returnType,
77
61
  declaredType: sym.declaredType,
62
+ templateArguments: sym.templateArguments,
78
63
  ownerId: sym.ownerId,
79
64
  qualifiedName: sym.qualifiedName,
80
65
  });
@@ -103,14 +88,70 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
103
88
  if (result.fileScopeBindings)
104
89
  for (const item of result.fileScopeBindings)
105
90
  fileScopeBindingsByFile.push(item);
106
- // RFC #909 Ring 2: aggregate per-file scope artifacts. Tolerant of
107
- // workers that don't emit the field yet (older worker builds or
108
- // partial rollouts), since the additive contract means undefined =
109
- // "this worker produced no ParsedFiles for this chunk".
110
91
  if (result.parsedFiles)
111
92
  for (const item of result.parsedFiles)
112
93
  allParsedFiles.push(item);
113
94
  }
95
+ return {
96
+ imports: allImports,
97
+ calls: allCalls,
98
+ assignments: allAssignments,
99
+ heritage: allHeritage,
100
+ routes: allRoutes,
101
+ fetchCalls: allFetchCalls,
102
+ decoratorRoutes: allDecoratorRoutes,
103
+ toolDefs: allToolDefs,
104
+ ormQueries: allORMQueries,
105
+ constructorBindings: allConstructorBindings,
106
+ fileScopeBindings: fileScopeBindingsByFile,
107
+ parsedFiles: allParsedFiles,
108
+ };
109
+ };
110
+ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, workerPool, onFileProgress,
111
+ /**
112
+ * When provided, populated with the raw worker results before merging.
113
+ * Used by the incremental-indexing parse cache to capture the per-chunk
114
+ * worker output for caching across runs. The mutation happens in-place
115
+ * so the caller (parse-impl) can keep a reference. See
116
+ * `gitnexus/src/storage/parse-cache.ts`.
117
+ */
118
+ outRawResults) => {
119
+ // Filter to parseable files only
120
+ const parseableFiles = [];
121
+ for (const file of files) {
122
+ const lang = getLanguageFromFilename(file.path);
123
+ if (lang)
124
+ parseableFiles.push({ path: file.path, content: file.content });
125
+ }
126
+ if (parseableFiles.length === 0)
127
+ return {
128
+ imports: [],
129
+ calls: [],
130
+ assignments: [],
131
+ heritage: [],
132
+ routes: [],
133
+ fetchCalls: [],
134
+ decoratorRoutes: [],
135
+ toolDefs: [],
136
+ ormQueries: [],
137
+ constructorBindings: [],
138
+ fileScopeBindings: [],
139
+ parsedFiles: [],
140
+ };
141
+ const total = files.length;
142
+ // Dispatch to worker pool — pool handles splitting into chunks and sub-batching
143
+ const chunkResults = await workerPool.dispatch(parseableFiles, (filesProcessed) => {
144
+ onFileProgress?.(Math.min(filesProcessed, total), total, 'Parsing...');
145
+ });
146
+ // Capture the raw chunk results for the incremental parse cache before
147
+ // merging — the cache stores the unmerged worker output so a future run
148
+ // can re-merge them into a fresh graph state.
149
+ if (outRawResults) {
150
+ for (const r of chunkResults)
151
+ outRawResults.push(r);
152
+ }
153
+ // Merge results from all workers into graph and symbol table.
154
+ const merged = mergeChunkResults(graph, symbolTable, chunkResults);
114
155
  // Merge and log skipped languages from workers
115
156
  const skippedLanguages = new Map();
116
157
  for (const result of chunkResults) {
@@ -126,20 +167,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
126
167
  }
127
168
  // Final progress
128
169
  onFileProgress?.(total, total, 'done');
129
- return {
130
- imports: allImports,
131
- calls: allCalls,
132
- assignments: allAssignments,
133
- heritage: allHeritage,
134
- routes: allRoutes,
135
- fetchCalls: allFetchCalls,
136
- decoratorRoutes: allDecoratorRoutes,
137
- toolDefs: allToolDefs,
138
- ormQueries: allORMQueries,
139
- constructorBindings: allConstructorBindings,
140
- fileScopeBindings: fileScopeBindingsByFile,
141
- parsedFiles: allParsedFiles,
142
- };
170
+ return merged;
143
171
  };
144
172
  // ============================================================================
145
173
  // Sequential fallback (original implementation)
@@ -339,6 +367,20 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
339
367
  })
340
368
  : null;
341
369
  const nodeLabel = extractedClassSymbol?.type ?? defaultNodeLabel;
370
+ const isClassLikeLabel = nodeLabel === 'Class' ||
371
+ nodeLabel === 'Struct' ||
372
+ nodeLabel === 'Interface' ||
373
+ nodeLabel === 'Enum' ||
374
+ nodeLabel === 'Record';
375
+ if (isClassLikeLabel &&
376
+ provider.classExtractor?.shouldSkipClassCapture?.({
377
+ captureMap,
378
+ definitionNode,
379
+ nameNode,
380
+ nodeLabel,
381
+ }) === true) {
382
+ return;
383
+ }
342
384
  // Synthesize name for constructors without explicit @name capture (e.g. Swift init)
343
385
  if (!nameNode && nodeLabel !== 'Constructor' && !extractedClassSymbol)
344
386
  return;
@@ -438,7 +480,26 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
438
480
  arityTag += typeTagForId(cached.map, nodeName, arityForId, seqDefMethodInfo, language, cached.groups);
439
481
  arityTag += constTagForId(cached.map, nodeName, arityForId, seqDefMethodInfo, cached.groups);
440
482
  }
441
- const nodeId = generateId(nodeLabel, `${file.path}:${qualifiedName}${arityTag}`);
483
+ const classTemplateArguments = extractedClassSymbol?.templateArguments ??
484
+ provider.classExtractor?.extractTemplateArgumentsFromCapture?.({
485
+ captureMap,
486
+ definitionNode,
487
+ nameNode,
488
+ }) ??
489
+ (captureMap['template-arguments']
490
+ ? extractTemplateArguments(captureMap['template-arguments'].text)
491
+ : undefined) ??
492
+ (nameNode && nameNode.text ? extractTemplateArguments(nameNode.text) : undefined);
493
+ const classTemplateTag = (nodeLabel === 'Class' ||
494
+ nodeLabel === 'Struct' ||
495
+ nodeLabel === 'Interface' ||
496
+ nodeLabel === 'Enum' ||
497
+ nodeLabel === 'Record') &&
498
+ classTemplateArguments !== undefined &&
499
+ classTemplateArguments.length > 0
500
+ ? templateArgumentsIdTag(classTemplateArguments)
501
+ : '';
502
+ const nodeId = generateId(nodeLabel, `${file.path}:${qualifiedName}${classTemplateTag}${arityTag}`);
442
503
  const classNodeForSymbol = definitionNodeForRange || definitionNode || nameNode;
443
504
  const qualifiedTypeName = extractedClassSymbol?.qualifiedName ??
444
505
  (classNodeForSymbol && provider.classExtractor?.isTypeDeclaration(classNodeForSymbol)
@@ -464,6 +525,9 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
464
525
  ? isVueSetupTopLevel(nameNode || definitionNodeForRange)
465
526
  : cachedExportCheck(provider.exportChecker, nameNode || definitionNodeForRange, nodeName),
466
527
  ...(qualifiedTypeName !== undefined ? { qualifiedName: qualifiedTypeName } : {}),
528
+ ...(classTemplateArguments !== undefined && classTemplateArguments.length > 0
529
+ ? { templateArguments: classTemplateArguments }
530
+ : {}),
467
531
  ...(frameworkHint
468
532
  ? {
469
533
  astFrameworkMultiplier: frameworkHint.entryPointMultiplier,
@@ -517,6 +581,7 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
517
581
  parameterTypes: methodProps.parameterTypes,
518
582
  returnType: methodProps.returnType,
519
583
  declaredType,
584
+ templateArguments: classTemplateArguments,
520
585
  ownerId: enclosingClassId ?? undefined,
521
586
  qualifiedName: qualifiedTypeName,
522
587
  });
@@ -562,7 +627,15 @@ export const processParsing = async (graph, files, symbolTable, astCache,
562
627
  * Worker-mode parses skip — Trees can't cross MessageChannels.
563
628
  * Pass `undefined` if no consumer needs cross-phase access.
564
629
  */
565
- scopeTreeCache, onFileProgress, workerPool) => {
630
+ scopeTreeCache, onFileProgress, workerPool,
631
+ /**
632
+ * Optional out-parameter for the incremental parse cache. When
633
+ * provided AND the worker-pool path runs successfully, populated
634
+ * with the raw `ParseWorkerResult[]` from the workers (pre-merge).
635
+ * Stays empty for the sequential fallback path (no per-chunk
636
+ * artifact to cache there). See `gitnexus/src/storage/parse-cache.ts`.
637
+ */
638
+ outRawResults) => {
566
639
  let lastProgress = 0;
567
640
  const reportProgress = onFileProgress
568
641
  ? (current, total, detail) => {
@@ -579,7 +652,7 @@ scopeTreeCache, onFileProgress, workerPool) => {
579
652
  logger.warn(`[scope-resolution prof] worker pool engaged for ${files.length} files — cross-phase tree cache will be empty; scope-resolution re-parses.`);
580
653
  }
581
654
  try {
582
- return await processParsingWithWorkers(graph, files, symbolTable, astCache, workerPool, reportProgress);
655
+ return await processParsingWithWorkers(graph, files, symbolTable, astCache, workerPool, reportProgress, outRawResults);
583
656
  }
584
657
  catch (err) {
585
658
  const message = err instanceof Error ? err.message : String(err);
@@ -9,9 +9,10 @@
9
9
  */
10
10
  import { processCalls, buildImportedReturnTypes, buildImportedRawReturnTypes, } from '../call-processor.js';
11
11
  import { createASTCache } from '../ast-cache.js';
12
- import { getLanguageFromFilename } from '../../../_shared/index.js';
12
+ import { getLanguageFromFilename, } from '../../../_shared/index.js';
13
13
  import { readFileContents } from '../filesystem-walker.js';
14
14
  import { isLanguageAvailable } from '../../tree-sitter/parser-loader.js';
15
+ import { isRegistryPrimary } from '../registry-primary-flag.js';
15
16
  import { topologicalLevelSort } from '../utils/graph-sort.js';
16
17
  import { isDev } from '../utils/env.js';
17
18
  import { logger } from '../../logger.js';
@@ -88,6 +89,40 @@ export async function runCrossFileBindingPropagation(graph, ctx, parseExportedTy
88
89
  let crossFileResolved = 0;
89
90
  const crossFileStart = Date.now();
90
91
  const astCache = createASTCache(AST_CACHE_CAP);
92
+ // Compiled query objects keyed by language name. Shared across all processCalls
93
+ // invocations in this phase so the same tree-sitter query string is only
94
+ // compiled once per language instead of once per file (O(1) vs O(N)).
95
+ const compiledQueryCache = new Map();
96
+ // Snapshot total topological candidates for progress math. We walk the
97
+ // levels once more here (fast — no I/O) so we can report meaningful
98
+ // percentages rather than a frozen display.
99
+ let totalCandidates = 0;
100
+ for (const level of levels) {
101
+ for (const filePath of level) {
102
+ if (totalCandidates >= MAX_CROSS_FILE_REPROCESS)
103
+ break;
104
+ const imports = ctx.namedImportMap.get(filePath);
105
+ if (!imports)
106
+ continue;
107
+ if (!allPathSet.has(filePath))
108
+ continue;
109
+ const lang = getLanguageFromFilename(filePath);
110
+ if (!lang || !isLanguageAvailable(lang))
111
+ continue;
112
+ // Registry-primary languages have their call resolution handled by the
113
+ // scope-resolution pipeline — processCalls skips them immediately. Skip
114
+ // here too so we avoid the I/O cost (readFileContents) and map-building
115
+ // overhead for files that would be no-ops anyway.
116
+ if (isRegistryPrimary(lang))
117
+ continue;
118
+ totalCandidates++;
119
+ }
120
+ if (totalCandidates >= MAX_CROSS_FILE_REPROCESS)
121
+ break;
122
+ }
123
+ const cappedTotal = Math.min(totalCandidates, MAX_CROSS_FILE_REPROCESS);
124
+ /** Emit a progress event every PROGRESS_INTERVAL files so the UI stays alive. */
125
+ const PROGRESS_INTERVAL = 25;
91
126
  for (const level of levels) {
92
127
  const levelCandidates = [];
93
128
  for (const filePath of level) {
@@ -114,6 +149,11 @@ export async function runCrossFileBindingPropagation(graph, ctx, parseExportedTy
114
149
  const lang = getLanguageFromFilename(filePath);
115
150
  if (!lang || !isLanguageAvailable(lang))
116
151
  continue;
152
+ // Registry-primary languages have their call resolution handled by the
153
+ // scope-resolution pipeline — processCalls skips them immediately. Skip
154
+ // here to avoid readFileContents I/O and map-building for no-op files.
155
+ if (isRegistryPrimary(lang))
156
+ continue;
117
157
  levelCandidates.push({ filePath, seeded, importedReturns, importedRawReturns });
118
158
  }
119
159
  if (levelCandidates.length === 0)
@@ -136,8 +176,20 @@ export async function runCrossFileBindingPropagation(graph, ctx, parseExportedTy
136
176
  if (importedRawReturns.size > 0) {
137
177
  importedRawReturnTypesMap.set(filePath, importedRawReturns);
138
178
  }
139
- await processCalls(graph, reFile, astCache, ctx, undefined, exportedTypeMap, bindings.size > 0 ? bindings : undefined, importedReturnTypesMap.size > 0 ? importedReturnTypesMap : undefined, importedRawReturnTypesMap.size > 0 ? importedRawReturnTypesMap : undefined);
179
+ await processCalls(graph, reFile, astCache, ctx, undefined, exportedTypeMap, bindings.size > 0 ? bindings : undefined, importedReturnTypesMap.size > 0 ? importedReturnTypesMap : undefined, importedRawReturnTypesMap.size > 0 ? importedRawReturnTypesMap : undefined, undefined, undefined, compiledQueryCache);
140
180
  crossFileResolved++;
181
+ // Emit progress every PROGRESS_INTERVAL files so the UI shows real
182
+ // movement instead of a frozen display (cross-file can take minutes
183
+ // on large repos with many cross-file imports).
184
+ if (crossFileResolved % PROGRESS_INTERVAL === 0 || crossFileResolved === cappedTotal) {
185
+ const pct = cappedTotal > 0 ? Math.round((crossFileResolved / cappedTotal) * 8) : 0;
186
+ onProgress({
187
+ phase: 'parsing',
188
+ percent: 82 + pct,
189
+ message: `Cross-file type propagation (${crossFileResolved}/${cappedTotal} files)...`,
190
+ stats: { filesProcessed: crossFileResolved, totalFiles, nodesCreated: graph.nodeCount },
191
+ });
192
+ }
141
193
  }
142
194
  if (crossFileResolved >= MAX_CROSS_FILE_REPROCESS) {
143
195
  if (isDev)
@@ -54,5 +54,10 @@ export declare function runChunkedParseAndResolve(graph: KnowledgeGraph, scanned
54
54
  * source. See plan
55
55
  * docs/plans/2026-04-20-002-perf-parse-heritage-mro-plan.md (Unit 4). */
56
56
  scopeTreeCache: ASTCache;
57
+ /** Worker-produced ParsedFile artifacts aggregated across chunks.
58
+ * Threaded into scope-resolution as a re-extract cache so the warm-
59
+ * cache analyze run can skip the dominant `extractParsedFile` cost
60
+ * (otherwise ~58s on a 1000-file repo). */
61
+ parsedFiles: import('../../../_shared/index.js').ParsedFile[];
57
62
  }>;
58
63
  export {};
@@ -12,7 +12,8 @@
12
12
  * @module
13
13
  */
14
14
  import { BindingAccumulator, enrichExportedTypeMap, } from '../binding-accumulator.js';
15
- import { processParsing } from '../parsing-processor.js';
15
+ import { processParsing, mergeChunkResults } from '../parsing-processor.js';
16
+ import { fileContentHash, computeChunkHash } from '../../../storage/parse-cache.js';
16
17
  import { processImports, processImportsFromExtracted, buildImportResolutionContext, } from '../import-processor.js';
17
18
  import { EMPTY_INDEX } from '../import-resolvers/utils.js';
18
19
  import { processCalls, processCallsFromExtracted, processAssignmentsFromExtracted, processRoutesFromExtracted, seedCrossFileReceiverTypes, buildExportedTypeMapFromGraph, } from '../call-processor.js';
@@ -33,8 +34,22 @@ import { synthesizeWildcardImportBindings, needsSynthesis } from './wildcard-syn
33
34
  import { extractORMQueriesInline } from './orm-extraction.js';
34
35
  import { logger } from '../../logger.js';
35
36
  // ── Constants ──────────────────────────────────────────────────────────────
36
- /** Max bytes of source content to load per parse chunk. */
37
- const CHUNK_BYTE_BUDGET = 20 * 1024 * 1024; // 20MB
37
+ /** Max bytes of source content to load per parse chunk.
38
+ *
39
+ * Memory bound for the worker pool dispatch + a granularity knob for
40
+ * the parse cache. A single file change invalidates only its enclosing
41
+ * chunk, so smaller budgets → finer-grained invalidation.
42
+ *
43
+ * Override via GITNEXUS_CHUNK_BYTE_BUDGET (bytes) — the default of 2MB
44
+ * gives a useful invalidation floor (~1/N chunks on a multi-MB repo)
45
+ * while keeping worker dispatch overhead under 5% on cold runs.
46
+ */
47
+ const CHUNK_BYTE_BUDGET = (() => {
48
+ const env = Number(process.env.GITNEXUS_CHUNK_BYTE_BUDGET);
49
+ if (Number.isFinite(env) && env > 0)
50
+ return env;
51
+ return 2 * 1024 * 1024;
52
+ })();
38
53
  /**
39
54
  * Chunked parse + resolve loop.
40
55
  *
@@ -64,6 +79,14 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
64
79
  for (const [lang, count] of skippedByLang) {
65
80
  logger.warn(`Skipping ${count} ${lang} file(s) — ${lang} parser not available (native binding may not have built). Try: npm rebuild tree-sitter-${lang}`);
66
81
  }
82
+ // Sort parseableScanned alphabetically for stable chunk membership
83
+ // across runs (Finding 4). Without this, filesystem-scan order can
84
+ // shift between runs (notably on macOS APFS where directory entry
85
+ // order can change after modifications) — different files in the
86
+ // same chunk → different chunk hash → cache miss even when no file
87
+ // content changed. The cache also becomes platform-specific: a
88
+ // Linux-built cache misses on macOS for the same repo.
89
+ parseableScanned.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
67
90
  const totalParseable = parseableScanned.length;
68
91
  if (totalParseable === 0) {
69
92
  onProgress({
@@ -164,6 +187,19 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
164
187
  const deferredWorkerHeritage = [];
165
188
  const deferredConstructorBindings = [];
166
189
  const deferredAssignments = [];
190
+ // Aggregated per-file ParsedFile artifacts produced by workers' calls
191
+ // to `extractParsedFile`. Threaded through to the scope-resolution
192
+ // phase so it can SKIP its own re-extraction on cache hits — this is
193
+ // the second-half of the parse-cache speedup since scope-resolution's
194
+ // re-parse otherwise dominates the warm-cache wall-clock time.
195
+ const allParsedFiles = [];
196
+ // Incremental parse cache (Option B): chunk-level content-addressed.
197
+ // When the chunk's (filePath, content-hash) signature matches a prior
198
+ // run's, replay the cached ParseWorkerResult[] instead of dispatching
199
+ // to workers. See gitnexus/src/storage/parse-cache.ts.
200
+ const parseCache = options?.parseCache;
201
+ let chunkCacheHits = 0;
202
+ let chunkCacheMisses = 0;
167
203
  try {
168
204
  for (let chunkIdx = 0; chunkIdx < numChunks; chunkIdx++) {
169
205
  const chunkPaths = chunks[chunkIdx];
@@ -171,21 +207,76 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
171
207
  const chunkFiles = chunkPaths
172
208
  .filter((p) => chunkContents.has(p))
173
209
  .map((p) => ({ path: p, content: chunkContents.get(p) }));
174
- const chunkWorkerData = await processParsing(graph, chunkFiles, symbolTable, astCache, scopeTreeCache, (current, _total, filePath) => {
175
- const globalCurrent = filesParsedSoFar + current;
176
- const parsingProgress = 20 + (globalCurrent / totalParseable) * 62;
210
+ // Compute the chunk's content-hash signature (if cache available).
211
+ let chunkHash = null;
212
+ if (parseCache) {
213
+ const entries = chunkFiles.map((f) => ({
214
+ filePath: f.path,
215
+ contentHash: fileContentHash(f.content),
216
+ }));
217
+ chunkHash = computeChunkHash(entries);
218
+ }
219
+ let chunkWorkerData;
220
+ const cachedRaw = chunkHash ? parseCache.entries.get(chunkHash) : undefined;
221
+ // Track every chunk hash we touched so the orchestrator can
222
+ // prune stale entries (chunks whose composition no longer
223
+ // corresponds to a live chunk in the current scan) before saving.
224
+ if (parseCache && chunkHash)
225
+ parseCache.usedKeys.add(chunkHash);
226
+ if (cachedRaw && cachedRaw.length > 0) {
227
+ // Cache hit: replay the cached worker output through the same
228
+ // merge logic the live worker path uses.
229
+ chunkCacheHits++;
230
+ chunkWorkerData = mergeChunkResults(graph, symbolTable, cachedRaw);
231
+ if (isDev) {
232
+ logger.info(`📦 parse-cache HIT: chunk ${chunkIdx + 1}/${numChunks} (${chunkFiles.length} files, ${chunkHash.slice(0, 8)})`);
233
+ }
234
+ // Progress update so UI advances even on a cache hit.
235
+ const cachedFiles = chunkFiles.length;
177
236
  onProgress({
178
237
  phase: 'parsing',
179
- percent: Math.round(parsingProgress),
180
- message: `Parsing chunk ${chunkIdx + 1}/${numChunks}...`,
181
- detail: filePath,
238
+ percent: Math.round(20 + ((filesParsedSoFar + cachedFiles) / totalParseable) * 62),
239
+ message: `Parsing chunk ${chunkIdx + 1}/${numChunks} (cache)...`,
182
240
  stats: {
183
- filesProcessed: globalCurrent,
241
+ filesProcessed: filesParsedSoFar + cachedFiles,
184
242
  totalFiles: totalParseable,
185
243
  nodesCreated: graph.nodeCount,
186
244
  },
187
245
  });
188
- }, workerPool);
246
+ }
247
+ else {
248
+ // Cache miss: dispatch to workers, capture the raw results, store
249
+ // them under the chunk hash for the next run.
250
+ chunkCacheMisses++;
251
+ const rawResults = [];
252
+ chunkWorkerData = await processParsing(graph, chunkFiles, symbolTable, astCache, scopeTreeCache, (current, _total, filePath) => {
253
+ const globalCurrent = filesParsedSoFar + current;
254
+ const parsingProgress = 20 + (globalCurrent / totalParseable) * 62;
255
+ onProgress({
256
+ phase: 'parsing',
257
+ percent: Math.round(parsingProgress),
258
+ message: `Parsing chunk ${chunkIdx + 1}/${numChunks}...`,
259
+ detail: filePath,
260
+ stats: {
261
+ filesProcessed: globalCurrent,
262
+ totalFiles: totalParseable,
263
+ nodesCreated: graph.nodeCount,
264
+ },
265
+ });
266
+ }, workerPool,
267
+ // Capture raw results only when we have a cache to write to —
268
+ // otherwise we'd retain extra arrays for nothing.
269
+ parseCache && chunkHash ? rawResults : undefined);
270
+ // Persist the raw results for this chunk hash. Sequential path
271
+ // doesn't populate rawResults (it writes directly to graph), so
272
+ // small repos without worker pool simply don't cache. That's fine.
273
+ if (parseCache && chunkHash && rawResults.length > 0) {
274
+ parseCache.entries.set(chunkHash, rawResults);
275
+ if (isDev) {
276
+ logger.info(`📦 parse-cache MISS+store: chunk ${chunkIdx + 1}/${numChunks} (${chunkFiles.length} files, ${chunkHash.slice(0, 8)})`);
277
+ }
278
+ }
279
+ }
189
280
  const chunkBasePercent = 20 + (filesParsedSoFar / totalParseable) * 62;
190
281
  if (chunkWorkerData) {
191
282
  await processImportsFromExtracted(graph, allPathObjects, chunkWorkerData.imports, ctx, (current, total) => {
@@ -217,6 +308,13 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
217
308
  deferredWorkerHeritage.push(item);
218
309
  for (const item of chunkWorkerData.constructorBindings)
219
310
  deferredConstructorBindings.push(item);
311
+ // Aggregate worker-produced ParsedFile artifacts so scope-
312
+ // resolution can use them as a re-extraction cache (skips its
313
+ // own tree-sitter re-parse on warm runs).
314
+ if (chunkWorkerData.parsedFiles?.length) {
315
+ for (const item of chunkWorkerData.parsedFiles)
316
+ allParsedFiles.push(item);
317
+ }
220
318
  if (chunkWorkerData.assignments?.length) {
221
319
  for (const item of chunkWorkerData.assignments)
222
320
  deferredAssignments.push(item);
@@ -297,6 +395,9 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
297
395
  filesParsedSoFar += chunkFiles.length;
298
396
  astCache.clear();
299
397
  }
398
+ if (isDev && parseCache && (chunkCacheHits > 0 || chunkCacheMisses > 0)) {
399
+ logger.info(`📦 parse-cache summary: ${chunkCacheHits} chunk hit(s), ${chunkCacheMisses} miss(es) across ${numChunks} chunk(s)`);
400
+ }
300
401
  const fullWorkerHeritageMap = deferredWorkerHeritage.length > 0
301
402
  ? buildHeritageMap(deferredWorkerHeritage, ctx, getHeritageStrategyForLanguage)
302
403
  : undefined;
@@ -455,5 +556,12 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
455
556
  // chunk-local `astCache` above is intentionally NOT exposed
456
557
  // because parse-impl clears it between chunks.
457
558
  scopeTreeCache,
559
+ // Per-file ParsedFile artifacts produced by workers' calls to
560
+ // `extractParsedFile`. Empty when only the sequential path ran
561
+ // (sequential doesn't go through the worker, and extracts ParsedFile
562
+ // inline rather than emitting it). Consumed by scope-resolution as
563
+ // a re-extraction cache: when the file's ParsedFile is here,
564
+ // scope-resolution skips its own `extractParsedFile` call.
565
+ parsedFiles: allParsedFiles,
458
566
  };
459
567
  }
@@ -17,6 +17,7 @@
17
17
  */
18
18
  import type { PipelinePhase } from './types.js';
19
19
  import type { BindingAccumulator } from '../binding-accumulator.js';
20
+ import type { ParsedFile } from '../../../_shared/index.js';
20
21
  import type { ExtractedFetchCall, ExtractedRoute, ExtractedDecoratorRoute, ExtractedToolDef, ExtractedORMQuery } from '../workers/parse-worker.js';
21
22
  import type { createResolutionContext } from '../model/resolution-context.js';
22
23
  import type { ASTCache } from '../ast-cache.js';
@@ -70,5 +71,18 @@ export interface ParseOutput {
70
71
  * `scopeTreeCache.clear()` after its extract loop finishes.
71
72
  */
72
73
  readonly scopeTreeCache: ASTCache;
74
+ /**
75
+ * Per-file `ParsedFile` artifacts produced by workers' calls to
76
+ * `extractParsedFile`. Threaded through to `scopeResolutionPhase`
77
+ * as a re-extraction cache: when a file's ParsedFile is present here,
78
+ * scope-resolution can skip its own `extractParsedFile` (which would
79
+ * otherwise re-parse the file with tree-sitter on the main thread,
80
+ * costing ~58s on a 1000-file repo).
81
+ *
82
+ * Empty for files that went through the sequential parse fallback —
83
+ * sequential doesn't emit ParsedFile artifacts; scope-resolution
84
+ * falls back to a fresh extract for those.
85
+ */
86
+ readonly parsedFiles: readonly ParsedFile[];
73
87
  }
74
88
  export declare const parsePhase: PipelinePhase<ParseOutput>;
@@ -32,5 +32,18 @@ export interface PipelineOptions {
32
32
  minFiles?: number;
33
33
  minBytes?: number;
34
34
  };
35
+ /**
36
+ * Incremental-indexing parse cache. When provided:
37
+ * - The parse phase looks up each chunk's content hash in
38
+ * `parseCache.entries`. On hit, it replays the cached
39
+ * `ParseWorkerResult[]` instead of dispatching to workers.
40
+ * - On miss, it runs the workers as today and stores the new
41
+ * results in `parseCache.entries` keyed by chunk hash.
42
+ * The caller (`run-analyze.ts`) is responsible for loading the cache
43
+ * before the pipeline runs and persisting it after. Cache survives
44
+ * `--force` because keys are content-addressed.
45
+ * See `gitnexus/src/storage/parse-cache.ts`.
46
+ */
47
+ parseCache?: import('../../storage/parse-cache.js').ParseCache;
35
48
  }
36
49
  export declare const runPipelineFromRepo: (repoPath: string, onProgress: (progress: PipelineProgress) => void, options?: PipelineOptions) => Promise<PipelineResult>;
@@ -70,6 +70,8 @@ export const MIGRATED_LANGUAGES = new Set([
70
70
  SupportedLanguages.TypeScript,
71
71
  SupportedLanguages.Go,
72
72
  SupportedLanguages.C,
73
+ SupportedLanguages.CPlusPlus,
74
+ SupportedLanguages.PHP,
73
75
  ]);
74
76
  /**
75
77
  * Return the env-var name that controls a given language's registry-
@@ -59,6 +59,7 @@
59
59
  * - `ParsedFile.referenceSites` — pre-resolution usage facts.
60
60
  */
61
61
  import { buildPositionIndex, buildScopeTree, canParentScope, makeScopeId } from '../../_shared/index.js';
62
+ import { extractTemplateArguments } from './utils/template-arguments.js';
62
63
  // ─── Public entry point ─────────────────────────────────────────────────────
63
64
  /**
64
65
  * Drive the five extraction passes and return a `ParsedFile`.
@@ -362,6 +363,8 @@ function buildDefFromDeclarationMatch(match, anchor, filePath) {
362
363
  return undefined;
363
364
  const qualifiedCap = match['@declaration.qualified_name'];
364
365
  const qualifiedName = qualifiedCap?.text;
366
+ const templateArguments = extractTemplateArguments(match['@declaration.template-arguments']?.text ?? '') ??
367
+ extractTemplateArguments(qualifiedName ?? nameCap.text);
365
368
  // Optional arity metadata — producers (e.g. Python emit-captures)
366
369
  // synthesize these on function/method declarations. Their absence is
367
370
  // the normal case for other producers; readers treat undefined as
@@ -381,6 +384,7 @@ function buildDefFromDeclarationMatch(match, anchor, filePath) {
381
384
  ...(parameterTypes !== undefined ? { parameterTypes } : {}),
382
385
  ...(declaredType !== undefined ? { declaredType } : {}),
383
386
  ...(returnType !== undefined ? { returnType } : {}),
387
+ ...(templateArguments !== undefined ? { templateArguments } : {}),
384
388
  };
385
389
  }
386
390
  function parseIntCapture(cap) {