gitnexus 1.6.11-rc.9 β†’ 1.6.11

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 (529) hide show
  1. package/README.md +94 -25
  2. package/dist/_shared/graph/types.d.ts +81 -2
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/integrations/circuit-breaker.d.ts.map +1 -1
  5. package/dist/_shared/integrations/circuit-breaker.js.map +1 -1
  6. package/dist/_shared/integrations/resilient-fetch.d.ts.map +1 -1
  7. package/dist/_shared/integrations/resilient-fetch.js.map +1 -1
  8. package/dist/_shared/language-detection.d.ts.map +1 -1
  9. package/dist/_shared/language-detection.js +2 -0
  10. package/dist/_shared/language-detection.js.map +1 -1
  11. package/dist/_shared/languages.d.ts +2 -1
  12. package/dist/_shared/languages.d.ts.map +1 -1
  13. package/dist/_shared/languages.js +1 -0
  14. package/dist/_shared/languages.js.map +1 -1
  15. package/dist/_shared/lbug/schema-constants.d.ts +2 -2
  16. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  17. package/dist/_shared/lbug/schema-constants.js +4 -0
  18. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  19. package/dist/_shared/scope-resolution/evidence-weights.d.ts.map +1 -1
  20. package/dist/_shared/scope-resolution/finalize-algorithm.js +1 -0
  21. package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
  22. package/dist/_shared/scope-resolution/language-classification.d.ts +3 -0
  23. package/dist/_shared/scope-resolution/language-classification.d.ts.map +1 -1
  24. package/dist/_shared/scope-resolution/language-classification.js +4 -0
  25. package/dist/_shared/scope-resolution/language-classification.js.map +1 -1
  26. package/dist/_shared/scope-resolution/reference-site.d.ts +10 -0
  27. package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -1
  28. package/dist/_shared/scope-resolution/registries/field-registry.js.map +1 -1
  29. package/dist/_shared/scope-resolution/registries/method-registry.js.map +1 -1
  30. package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -1
  31. package/dist/_shared/scope-resolution/scope-tree.js.map +1 -1
  32. package/dist/_shared/scope-resolution/types.d.ts +15 -0
  33. package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
  34. package/dist/cli/ai-context.d.ts +4 -0
  35. package/dist/cli/ai-context.js +90 -14
  36. package/dist/cli/analyze-config.js +14 -0
  37. package/dist/cli/analyze-options.d.ts +14 -0
  38. package/dist/cli/analyze-watch.d.ts +20 -0
  39. package/dist/cli/analyze-watch.js +434 -0
  40. package/dist/cli/analyze.js +27 -9
  41. package/dist/cli/auto-sync.d.ts +1 -0
  42. package/dist/cli/auto-sync.js +107 -0
  43. package/dist/cli/command-banner.d.ts +15 -0
  44. package/dist/cli/command-banner.js +42 -0
  45. package/dist/cli/detect-changes-format.js +21 -0
  46. package/dist/cli/doctor.d.ts +7 -0
  47. package/dist/cli/doctor.js +14 -0
  48. package/dist/cli/group.js +7 -1
  49. package/dist/cli/help-i18n.js +4 -0
  50. package/dist/cli/i18n/en.d.ts +18 -3
  51. package/dist/cli/i18n/en.js +18 -3
  52. package/dist/cli/i18n/resources.d.ts +33 -3
  53. package/dist/cli/i18n/zh-CN.d.ts +15 -0
  54. package/dist/cli/i18n/zh-CN.js +18 -3
  55. package/dist/cli/index.js +34 -7
  56. package/dist/cli/mcp.d.ts +15 -0
  57. package/dist/cli/mcp.js +44 -0
  58. package/dist/cli/optional-grammars.d.ts +3 -2
  59. package/dist/cli/optional-grammars.js +19 -3
  60. package/dist/cli/setup.js +41 -15
  61. package/dist/cli/update-notice.d.ts +34 -0
  62. package/dist/cli/update-notice.js +91 -0
  63. package/dist/cli/update.d.ts +21 -0
  64. package/dist/cli/update.js +93 -0
  65. package/dist/cli/watch.d.ts +1 -20
  66. package/dist/cli/watch.js +5 -371
  67. package/dist/core/analysis-feature-registry.d.ts +2 -0
  68. package/dist/core/analysis-feature-registry.js +15 -0
  69. package/dist/core/analyzer-identity.js +21 -3
  70. package/dist/core/auto-sync/analysis-worker-launch.d.ts +30 -0
  71. package/dist/core/auto-sync/analysis-worker-launch.js +166 -0
  72. package/dist/core/auto-sync/config.d.ts +33 -0
  73. package/dist/core/auto-sync/config.js +320 -0
  74. package/dist/core/auto-sync/index.d.ts +6 -0
  75. package/dist/core/auto-sync/index.js +6 -0
  76. package/dist/core/auto-sync/path-security.d.ts +9 -0
  77. package/dist/core/auto-sync/path-security.js +251 -0
  78. package/dist/core/auto-sync/repo.d.ts +1 -0
  79. package/dist/core/auto-sync/repo.js +6 -0
  80. package/dist/core/auto-sync/runner.d.ts +44 -0
  81. package/dist/core/auto-sync/runner.js +428 -0
  82. package/dist/core/auto-sync/starter.d.ts +50 -0
  83. package/dist/core/auto-sync/starter.js +497 -0
  84. package/dist/core/auto-sync/state.d.ts +37 -0
  85. package/dist/core/auto-sync/state.js +119 -0
  86. package/dist/core/group/config-parser.js +8 -1
  87. package/dist/core/group/cross-impact.d.ts +3 -0
  88. package/dist/core/group/cross-impact.js +36 -4
  89. package/dist/core/group/extractors/http-patterns/java.js +22 -8
  90. package/dist/core/group/extractors/http-patterns/kotlin.js +86 -31
  91. package/dist/core/group/extractors/http-patterns/node.js +145 -8
  92. package/dist/core/group/extractors/http-patterns/python.js +11 -7
  93. package/dist/core/group/extractors/http-route-extractor.js +63 -17
  94. package/dist/core/group/extractors/java-workspace-extractor.js +244 -31
  95. package/dist/core/group/group-lock.js +5 -6
  96. package/dist/core/group/normalization.d.ts +38 -1
  97. package/dist/core/group/normalization.js +59 -3
  98. package/dist/core/group/service.d.ts +11 -0
  99. package/dist/core/group/service.js +13 -1
  100. package/dist/core/group/storage.js +2 -2
  101. package/dist/core/group/sync.d.ts +24 -1
  102. package/dist/core/group/sync.js +46 -8
  103. package/dist/core/group/types.d.ts +13 -0
  104. package/dist/core/incremental/derived-writeback.d.ts +36 -0
  105. package/dist/core/incremental/derived-writeback.js +68 -0
  106. package/dist/core/incremental/spring-config-drift.d.ts +12 -0
  107. package/dist/core/incremental/spring-config-drift.js +46 -0
  108. package/dist/core/incremental/subgraph-extract.d.ts +7 -4
  109. package/dist/core/incremental/subgraph-extract.js +30 -5
  110. package/dist/core/ingestion/asyncapi/document.d.ts +226 -0
  111. package/dist/core/ingestion/asyncapi/document.js +758 -0
  112. package/dist/core/ingestion/asyncapi/protocol.d.ts +79 -0
  113. package/dist/core/ingestion/asyncapi/protocol.js +203 -0
  114. package/dist/core/ingestion/call-extractors/configs/zig.d.ts +2 -0
  115. package/dist/core/ingestion/call-extractors/configs/zig.js +4 -0
  116. package/dist/core/ingestion/call-extractors/zig-static-gating.d.ts +100 -0
  117. package/dist/core/ingestion/call-extractors/zig-static-gating.js +319 -0
  118. package/dist/core/ingestion/call-processor.js +3 -1
  119. package/dist/core/ingestion/class-extractors/configs/zig.d.ts +2 -0
  120. package/dist/core/ingestion/class-extractors/configs/zig.js +32 -0
  121. package/dist/core/ingestion/class-extractors/generic.js +4 -1
  122. package/dist/core/ingestion/class-types.d.ts +6 -2
  123. package/dist/core/ingestion/destination-key.d.ts +59 -0
  124. package/dist/core/ingestion/destination-key.js +61 -0
  125. package/dist/core/ingestion/entry-point-scoring.d.ts +6 -2
  126. package/dist/core/ingestion/entry-point-scoring.js +8 -44
  127. package/dist/core/ingestion/export-detection.d.ts +37 -0
  128. package/dist/core/ingestion/export-detection.js +60 -0
  129. package/dist/core/ingestion/field-extractors/configs/zig.d.ts +8 -0
  130. package/dist/core/ingestion/field-extractors/configs/zig.js +49 -0
  131. package/dist/core/ingestion/field-extractors/generic.d.ts +1 -1
  132. package/dist/core/ingestion/field-extractors/generic.js +12 -1
  133. package/dist/core/ingestion/frameworks/spring/actuator-runtime.d.ts +26 -0
  134. package/dist/core/ingestion/frameworks/spring/actuator-runtime.js +843 -0
  135. package/dist/core/ingestion/frameworks/spring/analysis-features.d.ts +5 -0
  136. package/dist/core/ingestion/frameworks/spring/analysis-features.js +9 -0
  137. package/dist/core/ingestion/frameworks/spring/annotation-arguments.js +8 -1
  138. package/dist/core/ingestion/frameworks/spring/argument-facts.d.ts +80 -0
  139. package/dist/core/ingestion/frameworks/spring/argument-facts.js +85 -0
  140. package/dist/core/ingestion/frameworks/spring/config-bindings.d.ts +1 -0
  141. package/dist/core/ingestion/frameworks/spring/config-bindings.js +2 -1
  142. package/dist/core/ingestion/frameworks/spring/destinations.d.ts +539 -0
  143. package/dist/core/ingestion/frameworks/spring/destinations.js +840 -0
  144. package/dist/core/ingestion/frameworks/spring/dynamic-lookups.d.ts +22 -0
  145. package/dist/core/ingestion/frameworks/spring/dynamic-lookups.js +124 -0
  146. package/dist/core/ingestion/frameworks/spring/message-producers.d.ts +78 -0
  147. package/dist/core/ingestion/frameworks/spring/message-producers.js +90 -0
  148. package/dist/core/ingestion/frameworks/spring/non-http-handlers.d.ts +29 -0
  149. package/dist/core/ingestion/frameworks/spring/vendor-prefixes.d.ts +7 -0
  150. package/dist/core/ingestion/frameworks/spring/vendor-prefixes.js +22 -0
  151. package/dist/core/ingestion/import-resolvers/configs/zig.d.ts +13 -0
  152. package/dist/core/ingestion/import-resolvers/configs/zig.js +26 -0
  153. package/dist/core/ingestion/import-resolvers/zig.d.ts +34 -0
  154. package/dist/core/ingestion/import-resolvers/zig.js +193 -0
  155. package/dist/core/ingestion/language-config.d.ts +177 -0
  156. package/dist/core/ingestion/language-config.js +719 -0
  157. package/dist/core/ingestion/language-provider.d.ts +178 -1
  158. package/dist/core/ingestion/language-provider.js +22 -0
  159. package/dist/core/ingestion/languages/csharp/razor-view-components.d.ts +62 -0
  160. package/dist/core/ingestion/languages/csharp/razor-view-components.js +954 -0
  161. package/dist/core/ingestion/languages/csharp/resolution-config.d.ts +3 -0
  162. package/dist/core/ingestion/languages/csharp/resolution-config.js +6 -1
  163. package/dist/core/ingestion/languages/csharp/scope-resolver.js +8 -0
  164. package/dist/core/ingestion/languages/index.d.ts +1 -0
  165. package/dist/core/ingestion/languages/index.js +2 -0
  166. package/dist/core/ingestion/languages/java/analysis-features.d.ts +1 -1
  167. package/dist/core/ingestion/languages/java/analysis-features.js +14 -6
  168. package/dist/core/ingestion/languages/java/capture-side-channel.d.ts +8 -0
  169. package/dist/core/ingestion/languages/java/capture-side-channel.js +34 -0
  170. package/dist/core/ingestion/languages/java/captures.js +22 -1
  171. package/dist/core/ingestion/languages/java/lombok-synthesizer.d.ts +42 -0
  172. package/dist/core/ingestion/languages/java/lombok-synthesizer.js +439 -0
  173. package/dist/core/ingestion/languages/java/scope-resolver.js +2 -0
  174. package/dist/core/ingestion/languages/java/spring-actuator.d.ts +2 -0
  175. package/dist/core/ingestion/languages/java/spring-actuator.js +62 -0
  176. package/dist/core/ingestion/languages/java/spring-di.d.ts +17 -1
  177. package/dist/core/ingestion/languages/java/spring-di.js +44 -2
  178. package/dist/core/ingestion/languages/java/spring-dynamic-lookup.d.ts +8 -0
  179. package/dist/core/ingestion/languages/java/spring-dynamic-lookup.js +62 -0
  180. package/dist/core/ingestion/languages/java/spring-message-producers.d.ts +20 -0
  181. package/dist/core/ingestion/languages/java/spring-message-producers.js +83 -0
  182. package/dist/core/ingestion/languages/java/spring-non-http-handlers.d.ts +11 -1
  183. package/dist/core/ingestion/languages/java/spring-non-http-handlers.js +13 -3
  184. package/dist/core/ingestion/languages/java.js +18 -8
  185. package/dist/core/ingestion/languages/jvm/accessor-synthesis.d.ts +99 -0
  186. package/dist/core/ingestion/languages/jvm/accessor-synthesis.js +173 -0
  187. package/dist/core/ingestion/languages/jvm/beanspec.d.ts +17 -0
  188. package/dist/core/ingestion/languages/jvm/beanspec.js +42 -0
  189. package/dist/core/ingestion/languages/kotlin/capture-side-channel.d.ts +15 -0
  190. package/dist/core/ingestion/languages/kotlin/capture-side-channel.js +50 -0
  191. package/dist/core/ingestion/languages/kotlin/captures.js +24 -1
  192. package/dist/core/ingestion/languages/kotlin/lombok-synthesizer.d.ts +26 -0
  193. package/dist/core/ingestion/languages/kotlin/lombok-synthesizer.js +417 -0
  194. package/dist/core/ingestion/languages/kotlin/scope-resolver.js +4 -0
  195. package/dist/core/ingestion/languages/kotlin/spring-actuator.d.ts +4 -0
  196. package/dist/core/ingestion/languages/kotlin/spring-actuator.js +172 -0
  197. package/dist/core/ingestion/languages/kotlin/spring-config-bindings.d.ts +18 -0
  198. package/dist/core/ingestion/languages/kotlin/spring-config-bindings.js +411 -0
  199. package/dist/core/ingestion/languages/kotlin/spring-di.d.ts +51 -1
  200. package/dist/core/ingestion/languages/kotlin/spring-di.js +86 -6
  201. package/dist/core/ingestion/languages/kotlin/spring-dynamic-lookup.d.ts +8 -0
  202. package/dist/core/ingestion/languages/kotlin/spring-dynamic-lookup.js +77 -0
  203. package/dist/core/ingestion/languages/kotlin/spring-message-producers.d.ts +17 -0
  204. package/dist/core/ingestion/languages/kotlin/spring-message-producers.js +119 -0
  205. package/dist/core/ingestion/languages/kotlin/spring-non-http-handlers.d.ts +16 -0
  206. package/dist/core/ingestion/languages/kotlin/spring-non-http-handlers.js +77 -2
  207. package/dist/core/ingestion/languages/kotlin.js +24 -0
  208. package/dist/core/ingestion/languages/python.js +2 -0
  209. package/dist/core/ingestion/languages/rust/query.js +8 -8
  210. package/dist/core/ingestion/languages/zig/captures.d.ts +260 -0
  211. package/dist/core/ingestion/languages/zig/captures.js +2070 -0
  212. package/dist/core/ingestion/languages/zig/index.d.ts +4 -0
  213. package/dist/core/ingestion/languages/zig/index.js +4 -0
  214. package/dist/core/ingestion/languages/zig/interpret.d.ts +36 -0
  215. package/dist/core/ingestion/languages/zig/interpret.js +176 -0
  216. package/dist/core/ingestion/languages/zig/query.d.ts +3 -0
  217. package/dist/core/ingestion/languages/zig/query.js +426 -0
  218. package/dist/core/ingestion/languages/zig/range-binding.d.ts +37 -0
  219. package/dist/core/ingestion/languages/zig/range-binding.js +373 -0
  220. package/dist/core/ingestion/languages/zig/scope-resolver.d.ts +12 -0
  221. package/dist/core/ingestion/languages/zig/scope-resolver.js +58 -0
  222. package/dist/core/ingestion/languages/zig/simple-hooks.d.ts +25 -0
  223. package/dist/core/ingestion/languages/zig/simple-hooks.js +143 -0
  224. package/dist/core/ingestion/languages/zig.d.ts +32 -0
  225. package/dist/core/ingestion/languages/zig.js +130 -0
  226. package/dist/core/ingestion/method-extractors/configs/zig.d.ts +2 -0
  227. package/dist/core/ingestion/method-extractors/configs/zig.js +120 -0
  228. package/dist/core/ingestion/method-extractors/generic.js +16 -4
  229. package/dist/core/ingestion/method-types.d.ts +10 -4
  230. package/dist/core/ingestion/model/field-registry.d.ts +3 -3
  231. package/dist/core/ingestion/model/field-registry.js +11 -7
  232. package/dist/core/ingestion/model/method-registry.d.ts +3 -3
  233. package/dist/core/ingestion/model/method-registry.js +13 -8
  234. package/dist/core/ingestion/model/registration-table.js +3 -0
  235. package/dist/core/ingestion/model/type-registry.js +8 -4
  236. package/dist/core/ingestion/pipeline-phases/di.js +47 -14
  237. package/dist/core/ingestion/pipeline-phases/index.d.ts +1 -0
  238. package/dist/core/ingestion/pipeline-phases/index.js +1 -0
  239. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +7 -1
  240. package/dist/core/ingestion/pipeline-phases/parse-impl.js +79 -91
  241. package/dist/core/ingestion/pipeline-phases/parse.d.ts +17 -0
  242. package/dist/core/ingestion/pipeline-phases/processes.d.ts +2 -1
  243. package/dist/core/ingestion/pipeline-phases/processes.js +39 -4
  244. package/dist/core/ingestion/pipeline-phases/routes.js +27 -18
  245. package/dist/core/ingestion/pipeline-phases/runner.d.ts +4 -1
  246. package/dist/core/ingestion/pipeline-phases/runner.js +34 -14
  247. package/dist/core/ingestion/pipeline-phases/scan.js +82 -1
  248. package/dist/core/ingestion/pipeline-phases/spring-auto-configuration.d.ts +2 -0
  249. package/dist/core/ingestion/pipeline-phases/spring-auto-configuration.js +8 -0
  250. package/dist/core/ingestion/pipeline-phases/spring-destinations.d.ts +123 -0
  251. package/dist/core/ingestion/pipeline-phases/spring-destinations.js +688 -0
  252. package/dist/core/ingestion/pipeline.d.ts +30 -1
  253. package/dist/core/ingestion/pipeline.js +52 -14
  254. package/dist/core/ingestion/resolve-references.js +5 -0
  255. package/dist/core/ingestion/route-extractors/constant-resolver.d.ts +16 -0
  256. package/dist/core/ingestion/route-extractors/constant-resolver.js +10 -0
  257. package/dist/core/ingestion/route-extractors/java-const-resolver.d.ts +27 -1
  258. package/dist/core/ingestion/route-extractors/java-const-resolver.js +161 -13
  259. package/dist/core/ingestion/route-extractors/kotlin-const-resolver.d.ts +12 -18
  260. package/dist/core/ingestion/route-extractors/kotlin-const-resolver.js +214 -33
  261. package/dist/core/ingestion/route-extractors/kotlin-spring.d.ts +13 -0
  262. package/dist/core/ingestion/route-extractors/kotlin-spring.js +259 -0
  263. package/dist/core/ingestion/route-extractors/python-decorator-handler.d.ts +6 -0
  264. package/dist/core/ingestion/route-extractors/python-decorator-handler.js +16 -0
  265. package/dist/core/ingestion/route-extractors/spring-shared.d.ts +30 -1
  266. package/dist/core/ingestion/route-extractors/spring-shared.js +77 -9
  267. package/dist/core/ingestion/route-extractors/spring.js +9 -5
  268. package/dist/core/ingestion/scope-extractor.js +8 -0
  269. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +62 -0
  270. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +4 -0
  271. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +2 -0
  272. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +28 -0
  273. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +11 -2
  274. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +23 -2
  275. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +24 -3
  276. package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.d.ts +11 -1
  277. package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.js +26 -6
  278. package/dist/core/ingestion/scope-resolution/passes/compound-receiver.d.ts +11 -0
  279. package/dist/core/ingestion/scope-resolution/passes/compound-receiver.js +29 -3
  280. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +8 -1
  281. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +35 -9
  282. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +1 -4
  283. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +277 -9
  284. package/dist/core/ingestion/scope-resolution/pipeline/registry.js +2 -0
  285. package/dist/core/ingestion/scope-resolution/pipeline/run.js +7 -3
  286. package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +43 -9
  287. package/dist/core/ingestion/scope-resolution/scope/walkers.js +71 -10
  288. package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -0
  289. package/dist/core/ingestion/tree-sitter-queries.js +161 -0
  290. package/dist/core/ingestion/type-extractors/zig.d.ts +2 -0
  291. package/dist/core/ingestion/type-extractors/zig.js +17 -0
  292. package/dist/core/ingestion/utils/ast-helpers.d.ts +40 -1
  293. package/dist/core/ingestion/utils/ast-helpers.js +124 -6
  294. package/dist/core/ingestion/utils/callable-flow-captures.d.ts +9 -0
  295. package/dist/core/ingestion/utils/callable-flow-captures.js +75 -14
  296. package/dist/core/ingestion/utils/test-file-path.d.ts +28 -0
  297. package/dist/core/ingestion/utils/test-file-path.js +87 -0
  298. package/dist/core/ingestion/variable-extractors/configs/zig.d.ts +2 -0
  299. package/dist/core/ingestion/variable-extractors/configs/zig.js +71 -0
  300. package/dist/core/ingestion/workers/parse-worker.js +85 -14
  301. package/dist/core/install-context.d.ts +4 -0
  302. package/dist/core/install-context.js +152 -0
  303. package/dist/core/lbug/csv-generator.d.ts +10 -1
  304. package/dist/core/lbug/csv-generator.js +92 -22
  305. package/dist/core/lbug/graph-emit-sink.d.ts +3 -2
  306. package/dist/core/lbug/graph-emit-sink.js +4 -2
  307. package/dist/core/lbug/lbug-adapter.d.ts +100 -5
  308. package/dist/core/lbug/lbug-adapter.js +236 -24
  309. package/dist/core/lbug/schema.d.ts +6 -5
  310. package/dist/core/lbug/schema.js +84 -22
  311. package/dist/core/net/url-guard.d.ts +6 -0
  312. package/dist/core/net/url-guard.js +147 -0
  313. package/dist/core/package-version.d.ts +5 -0
  314. package/dist/core/package-version.js +10 -0
  315. package/dist/core/run-analyze.d.ts +21 -4
  316. package/dist/core/run-analyze.js +426 -117
  317. package/dist/core/search/fts-indexes.d.ts +19 -1
  318. package/dist/core/search/fts-indexes.js +28 -1
  319. package/dist/core/tree-sitter/parser-loader.js +16 -0
  320. package/dist/core/update-cache.d.ts +39 -0
  321. package/dist/core/update-cache.js +141 -0
  322. package/dist/core/update-check.d.ts +31 -0
  323. package/dist/core/update-check.js +274 -0
  324. package/dist/mcp/local/local-backend.d.ts +3 -6
  325. package/dist/mcp/local/local-backend.js +70 -29
  326. package/dist/mcp/resources.js +8 -0
  327. package/dist/mcp/server.js +2 -4
  328. package/dist/mcp/tools.js +6 -6
  329. package/dist/server/analyze-launch.d.ts +2 -0
  330. package/dist/server/analyze-launch.js +2 -0
  331. package/dist/server/analyze-worker-protocol.d.ts +6 -1
  332. package/dist/server/analyze-worker.d.ts +1 -0
  333. package/dist/server/analyze-worker.js +38 -20
  334. package/dist/server/api.d.ts +5 -1
  335. package/dist/server/api.js +105 -88
  336. package/dist/server/git-clone.d.ts +40 -16
  337. package/dist/server/git-clone.js +253 -199
  338. package/dist/server/grep-params.d.ts +18 -0
  339. package/dist/server/grep-params.js +83 -0
  340. package/dist/server/grep-scan.d.ts +23 -0
  341. package/dist/server/grep-scan.js +107 -0
  342. package/dist/server/grep-worker.d.ts +1 -0
  343. package/dist/server/grep-worker.js +12 -0
  344. package/dist/server/mcp-http.d.ts +8 -0
  345. package/dist/server/mcp-http.js +16 -1
  346. package/dist/server/update-controller.d.ts +29 -0
  347. package/dist/server/update-controller.js +82 -0
  348. package/dist/storage/file-lock.d.ts +15 -0
  349. package/dist/storage/file-lock.js +155 -0
  350. package/dist/storage/fs-atomic.d.ts +24 -0
  351. package/dist/storage/fs-atomic.js +86 -2
  352. package/dist/storage/global-dir.d.ts +2 -0
  353. package/dist/storage/global-dir.js +6 -0
  354. package/dist/storage/parse-cache.d.ts +45 -7
  355. package/dist/storage/parse-cache.js +189 -42
  356. package/dist/storage/parsedfile-store.d.ts +41 -60
  357. package/dist/storage/parsedfile-store.js +247 -171
  358. package/dist/storage/repo-manager.d.ts +10 -4
  359. package/dist/storage/repo-manager.js +35 -25
  360. package/dist/storage/repo-meta.d.ts +34 -0
  361. package/dist/storage/v8-sidecar.d.ts +48 -0
  362. package/dist/storage/v8-sidecar.js +347 -0
  363. package/dist/types/pipeline.d.ts +14 -0
  364. package/dist/utils/process-identity.d.ts +2 -0
  365. package/dist/utils/process-identity.js +35 -0
  366. package/package.json +10 -4
  367. package/scripts/assert-web-assets.mjs +35 -0
  368. package/scripts/build-web.js +72 -0
  369. package/scripts/build.js +31 -28
  370. package/scripts/cross-platform-tests.ts +2 -0
  371. package/skills/gitnexus-cli.md +5 -1
  372. package/web/assets/ProcessFlowModal-DAeX2BHW.js +24 -0
  373. package/web/assets/{abnfDiagram-QNN2D4NM-Cq2djWWe.js β†’ abnfDiagram-PAR5IXJI-J3OdeHLl.js} +1 -1
  374. package/web/assets/{agent-BWAXPjC5.js β†’ agent-BMRqXorA.js} +6 -4
  375. package/web/assets/architecture-7GRP2DOG-M7G3SWCO-G3sWyX6M.js +1 -0
  376. package/web/assets/architectureDiagram-2PNWDENW-ysKcRlGT.js +36 -0
  377. package/web/assets/blockDiagram-PUWGUBOA-oLXTa1lY.js +129 -0
  378. package/web/assets/c4Diagram-3NLNHZP5-D3iu4eC0.js +38 -0
  379. package/web/assets/{chunk-2SREHG4O-Dip42xOq.js β†’ chunk-2NMSUPJH-B24w-wng.js} +1 -1
  380. package/web/assets/{chunk-VJFVEZTB-CX66F2ep.js β†’ chunk-32MCUW2P-ByUyt0Sa.js} +3 -3
  381. package/web/assets/{chunk-4RFN2BYJ-DHHWuC-n.js β†’ chunk-3NPNU5GP-DocZ07Sg.js} +1 -1
  382. package/web/assets/{chunk-XNMVGMAZ-Cg_LnPtj.js β†’ chunk-3SMGFRGC-CAu4JRLv.js} +1 -1
  383. package/web/assets/{chunk-W44A43WB-BN8EQc_u.js β†’ chunk-4CAJECRU-DRYMwG9z.js} +1 -1
  384. package/web/assets/chunk-4OADUZ5Q-CxrSvOwZ.js +10 -0
  385. package/web/assets/{chunk-DMV4VAQV-Bn6WXDSX.js β†’ chunk-5IQCK5RY-CCMhl4so.js} +2 -2
  386. package/web/assets/{chunk-RRFMTAIC-CMN0wcYA.js β†’ chunk-5MVFYWFU-Db9KvrYO.js} +1 -1
  387. package/web/assets/chunk-CLS4B6BI-Uvx5QNsu.js +168 -0
  388. package/web/assets/chunk-DZP67EKU-B3Mt380j.js +70 -0
  389. package/web/assets/{chunk-6L755F7B-CMhLBxi2.js β†’ chunk-EICP7K5X-CqwE9hui.js} +1 -1
  390. package/web/assets/{chunk-BI6VK774-D0oaWk8V.js β†’ chunk-GDY2UAB4-CtQQR0a8.js} +1 -1
  391. package/web/assets/chunk-H7VHZCWX-CE1nAmt6.js +1 -0
  392. package/web/assets/chunk-IJBDOHL6-BUKtY6oF.js +1 -0
  393. package/web/assets/{chunk-OIYT25JQ-CQ6KOZGX.js β†’ chunk-JFFVMJIA-0fJenqia.js} +1 -1
  394. package/web/assets/{chunk-HNC4WDU7-DoU3KnA7.js β†’ chunk-JZGDI5JK-BeTMSSkJ.js} +1 -1
  395. package/web/assets/{chunk-EQFTRU2I-1ix7TzW9.js β†’ chunk-KD6SPIPN-Qp1Pflah.js} +1 -1
  396. package/web/assets/chunk-NF366YI6-CpSpya3n.js +231 -0
  397. package/web/assets/chunk-NUDPKBEF-CU1-BQIW.js +34 -0
  398. package/web/assets/{chunk-SATU7PGQ-B1zhgOvc.js β†’ chunk-OJINMHTS-zOCQe4eI.js} +1 -1
  399. package/web/assets/{chunk-E5QJAATJ-dh-5CtIV.js β†’ chunk-Q6NGPIAH-yyBomb63.js} +1 -1
  400. package/web/assets/chunk-QJSWEUOL-D_rf9gPD.js +128 -0
  401. package/web/assets/chunk-R7JDMUKV-CRoqKpD6.js +1 -0
  402. package/web/assets/{chunk-VE5CLXGZ-C1vB7wpY.js β†’ chunk-RCXAM2GK-CUqrWQDV.js} +1 -1
  403. package/web/assets/{chunk-66DQ2XMT-CM0xjFAN.js β†’ chunk-RT4MAWR3-zXy9-Lvt.js} +1 -1
  404. package/web/assets/{chunk-TZUXEDM2-B7p9AcTw.js β†’ chunk-SFMINX4W-J2UrvMpD.js} +1 -1
  405. package/web/assets/{chunk-LORZLZWG-B57uGw2N.js β†’ chunk-SLDQ463B-CHY6e_bQ.js} +2 -2
  406. package/web/assets/{chunk-FWYVLQTC-BgDItRzJ.js β†’ chunk-TCEHX7R3-CXPDEVbm.js} +1 -1
  407. package/web/assets/{chunk-224SPVON-B8gxtXpy.js β†’ chunk-VQC2EELJ-Dc8fIy4R.js} +1 -1
  408. package/web/assets/chunk-VRZKL3EH-DB3KixTQ.js +1 -0
  409. package/web/assets/{chunk-A7VWPJGB-B4O3oQdQ.js β†’ chunk-VTHDQ7BV-b7FsPQZO.js} +1 -1
  410. package/web/assets/chunk-VY2OSTJR-Dkgc3Brg.js +2 -0
  411. package/web/assets/chunk-WUBWJARI-7FwILJ3k.js +2 -0
  412. package/web/assets/{chunk-D6VWDJW2-BxcBdZ9c.js β†’ chunk-YBMQ5JGJ-BSnyWZmd.js} +1 -1
  413. package/web/assets/chunk-YDMLL4PJ-IHhMngTz.js +2 -0
  414. package/web/assets/chunk-Z6V44ARX-BjCEsF0Q.js +62 -0
  415. package/web/assets/chunk-ZJJ7VQJP-Dz089b-K.js +321 -0
  416. package/web/assets/chunk-ZNLK7HRR-B0iFpmW4.js +1 -0
  417. package/web/assets/chunk-ZQN7UHIL-Cy7KAjQt.js +1 -0
  418. package/web/assets/{chunk-L5GCOVLC-CE2w8Nm_.js β†’ chunk-ZS6VBONO-DBjJO0w9.js} +2 -2
  419. package/web/assets/{chunk-NV3KIAZN-5yvcpMiu.js β†’ chunk-ZUNWM646-DNRJyNPe.js} +1 -1
  420. package/web/assets/classDiagram-FGAMPOII-C5Ibyode.js +1 -0
  421. package/web/assets/classDiagram-v2-AI5RJEK4-C5Ibyode.js +1 -0
  422. package/web/assets/{cose-bilkent-RZA4XIPR-BHpK4Crp.js β†’ cose-bilkent-Q72C2OJ3-DMeFXnK8.js} +1 -1
  423. package/web/assets/cynefin-OW5HDTMX-6OCTWOGG-vlqakYcO.js +1 -0
  424. package/web/assets/{cynefinDiagram-TR7LZUCG-C3Iar9lZ.js β†’ cynefinDiagram-2OOWUY4M-BY6DZkTt.js} +1 -1
  425. package/web/assets/dagre-MPVFI544-DWO70fy_.js +4 -0
  426. package/web/assets/diagram-AE4NWXFW-f7JRVRUL.js +24 -0
  427. package/web/assets/{diagram-L7DVE3PN-GIRyVUtt.js β†’ diagram-BUJID5UG-BXZv1rCS.js} +2 -2
  428. package/web/assets/{diagram-JCD7PQ7C-DC5-9FRr.js β†’ diagram-C44CZ5NI-CRNfvjCq.js} +1 -1
  429. package/web/assets/diagram-EYOLEXXS-DZOjKQVE.js +30 -0
  430. package/web/assets/diagram-P7B6PWOJ-D3SQmw3_.js +3 -0
  431. package/web/assets/{ebnfDiagram-DRHRQJWO-D8_CI4ZF.js β†’ ebnfDiagram-FTPZ3PV6-jKWpIDN2.js} +1 -1
  432. package/web/assets/erDiagram-H3ERR26V-BqJntEuJ.js +99 -0
  433. package/web/assets/eventmodeling-NTZA5JFV-WKSWQHFS-Bq4FqtBL.js +1 -0
  434. package/web/assets/flowDiagram-YHGXBVSY-Dnlk2bEu.js +1 -0
  435. package/web/assets/ganttDiagram-RWFTB7ED-Bl6Y1K5T.js +292 -0
  436. package/web/assets/gitGraph-4MIJSDKK-JH2HKYUO-B3yc4GkH.js +1 -0
  437. package/web/assets/gitGraphDiagram-MAR6GKOP-CkNvsrdw.js +106 -0
  438. package/web/assets/{index-CJDpyH-n.css β†’ index-C2_aej58.css} +1 -1
  439. package/web/assets/{index-DDRie6_8.js β†’ index-Dj3vQOHK.js} +51 -51
  440. package/web/assets/info-A6RAGUB7-3TX3OFWW-BM3N5_Dv.js +1 -0
  441. package/web/assets/infoDiagram-LV547AFH-COkFutAf.js +2 -0
  442. package/web/assets/{ishikawaDiagram-4JDSWWDM-DmqWtjkl.js β†’ ishikawaDiagram-PUJQGNDS-Bb8FylSR.js} +2 -2
  443. package/web/assets/{journeyDiagram-QUS3FAKT-XAzVzrQW.js β†’ journeyDiagram-EW5QJT4W-BzoHUBhM.js} +4 -4
  444. package/web/assets/{kanban-definition-D4L7SQKK-YurRnmYn.js β†’ kanban-definition-JSQERAZB-Uy2Pi0yQ.js} +4 -4
  445. package/web/assets/katex-CZ4GXH2S-C0Fcou7U.js +257 -0
  446. package/web/assets/{mindmap-definition-66QP5TD6-ChrWWnil.js β†’ mindmap-definition-VBJCLQLM-B-CnOnt_.js} +3 -3
  447. package/web/assets/packet-AYTQ26CC-MKII6P3Y-Bd52ZE3V.js +1 -0
  448. package/web/assets/{pegDiagram-YKIO5C6U-QGeQLEq2.js β†’ pegDiagram-7WILOQTJ-D9sneKXg.js} +1 -1
  449. package/web/assets/pie-WAS4IAKB-6B4OPMJ5-DW5Xy69Z.js +1 -0
  450. package/web/assets/pieDiagram-EFA7CBSB-Dx2NQofL.js +39 -0
  451. package/web/assets/{quadrantDiagram-VO5QLCXA-B7098wSc.js β†’ quadrantDiagram-WARVYA7P-DPKL9_0A.js} +3 -3
  452. package/web/assets/radar-RG4KPBEZ-UPTR3XUL-CkzibT2h.js +1 -0
  453. package/web/assets/railroad-74A4TZTK-MEFUPFMS-D9zF-mDN.js +1 -0
  454. package/web/assets/railroad-abnf-HS5TGJTU-R5YG2S5D-ruacjUbX.js +1 -0
  455. package/web/assets/railroad-ebnf-LZEXJU2U-G5QEX2L6-S1zc5OiO.js +1 -0
  456. package/web/assets/railroad-peg-WCYAUIDC-H5I2ZRY2-Cbcr0XzY.js +1 -0
  457. package/web/assets/{railroadDiagram-M77LTMSB-AXu4vxk_.js β†’ railroadDiagram-5NIQVNLQ-DsweTo14.js} +1 -1
  458. package/web/assets/{requirementDiagram-RASO5HTO-B-l8InpK.js β†’ requirementDiagram-SXREGOKZ-CXwdNSVR.js} +4 -4
  459. package/web/assets/{sankeyDiagram-F32LOJ6L-Kd7zjJgX.js β†’ sankeyDiagram-VV74M2VP-CA6jtP9P.js} +3 -3
  460. package/web/assets/{sequenceDiagram-URATNSBD-BlcdY9DS.js β†’ sequenceDiagram-52ZFIFDL-k_5rEbzm.js} +15 -15
  461. package/web/assets/src-Df5C1Nz4.js +1 -0
  462. package/web/assets/stateDiagram-3QAKPIVI-BejHTf31.js +1 -0
  463. package/web/assets/stateDiagram-v2-HN2P4RDZ-BrfoRuOc.js +1 -0
  464. package/web/assets/swimlanes-QLVP42QD-CQSVO5D6.js +1 -0
  465. package/web/assets/swimlanesDiagram-JKPDBFCN-DrWB9kcD.js +8 -0
  466. package/web/assets/{timeline-definition-WJXWRH4I-DUfp1R3E.js β†’ timeline-definition-GS45XAXW-C0Ks8rPP.js} +4 -4
  467. package/web/assets/treeView-Q6P3EWNA-ZRJGANNQ-DmKOCo6L.js +1 -0
  468. package/web/assets/treemap-WGGIJYW6-K64VN5AS-DO3xY92U.js +1 -0
  469. package/web/assets/{vennDiagram-K3VCMQLI-Bj-FN-XS.js β†’ vennDiagram-QIQU2ZRJ-rgPiS837.js} +3 -3
  470. package/web/assets/wardley-WFR3VGLG-D67OWCCH-DiDPBNft.js +1 -0
  471. package/web/assets/wardleyDiagram-U6YNM66N-DRVr7SPi.js +78 -0
  472. package/web/assets/{xychartDiagram-5VRUVLCW-CK_rbSWE.js β†’ xychartDiagram-XJAZEDNM-COtlZzYb.js} +3 -3
  473. package/web/index.html +19 -17
  474. package/web/assets/ProcessFlowModal-Badh2Pbg.js +0 -24
  475. package/web/assets/architecture-TIHT7OUA-V6N4J3SY-fTePvLoe.js +0 -1
  476. package/web/assets/architectureDiagram-OT7VKSJ7-mKEXxkeF.js +0 -36
  477. package/web/assets/blockDiagram-54WLDVWM-Dg_hrRWE.js +0 -132
  478. package/web/assets/c4Diagram-X2LASM7V-CnhoT4aV.js +0 -10
  479. package/web/assets/chunk-2AEHWXPW-CV4r6-1I.js +0 -127
  480. package/web/assets/chunk-5VCL7Z4A-CQ-2dYWj.js +0 -1
  481. package/web/assets/chunk-6BELYETK-ChsYtfHW.js +0 -1
  482. package/web/assets/chunk-7CWYLC5S-DRgGkkpF.js +0 -2
  483. package/web/assets/chunk-7FYTHRHK-CsmYIswB.js +0 -32
  484. package/web/assets/chunk-KRXBNO2N-C-UNuKKf.js +0 -1
  485. package/web/assets/chunk-LAHSG3N2-Bz4hcn0N.js +0 -321
  486. package/web/assets/chunk-LIEV3EAG-pyKGssV3.js +0 -1
  487. package/web/assets/chunk-NLANEA3F-XpH_NPA5.js +0 -62
  488. package/web/assets/chunk-PE7DX7ZZ-CCvRVj43.js +0 -10
  489. package/web/assets/chunk-Q67WD55A-BWCH2SVz.js +0 -156
  490. package/web/assets/chunk-SZD42YQK-ijyKKVr1.js +0 -70
  491. package/web/assets/chunk-TFPGFQPA-Dj6a-0pC.js +0 -231
  492. package/web/assets/chunk-TGVD4F4B-BMc31Gj2.js +0 -2
  493. package/web/assets/chunk-UAT7B5JY-DW-A_fpI.js +0 -1
  494. package/web/assets/chunk-VY5UBI4V-yxPQAWxw.js +0 -1
  495. package/web/assets/chunk-WJBAP47W-BckNkuEN.js +0 -1
  496. package/web/assets/classDiagram-VPOSVPXH-BjOiXA_C.js +0 -1
  497. package/web/assets/classDiagram-v2-5VFNUXQA-BjOiXA_C.js +0 -1
  498. package/web/assets/cynefin-VYW2F7L2-2VAHYKR6-DAsF6GZv.js +0 -1
  499. package/web/assets/dagre-K64A6Z3X-CUwi79mA.js +0 -4
  500. package/web/assets/diagram-2TLGJV2N-C2F5Nfym.js +0 -30
  501. package/web/assets/diagram-KFBZAVDW-Dfmf_4ti.js +0 -3
  502. package/web/assets/diagram-YP3FGXHI-CyNFYtkd.js +0 -24
  503. package/web/assets/erDiagram-SZLJLQMB-CohQjznC.js +0 -85
  504. package/web/assets/eventmodeling-45OFAUF4-AOUJWSLX-BvTc6iQi.js +0 -1
  505. package/web/assets/flowDiagram-BWE6NHOH-B6RnEvD9.js +0 -1
  506. package/web/assets/ganttDiagram-2QTCJSNI-Cks_mEcF.js +0 -292
  507. package/web/assets/gitGraph-TEB2WS4Q-U5VWYIBC-Dy7CCSZ5.js +0 -1
  508. package/web/assets/gitGraphDiagram-VVZAVV5G-CG41cIVc.js +0 -106
  509. package/web/assets/info-DKCQHKI2-DX6KST54-BLJg1ikX.js +0 -1
  510. package/web/assets/infoDiagram-FY4PZKRE-BJ3vPVwW.js +0 -2
  511. package/web/assets/katex-C5OPUE3Q-Bnbavtmu.js +0 -257
  512. package/web/assets/packet-7NZHBO7P-5WG45QPS-KUxcuvaA.js +0 -1
  513. package/web/assets/pie-RZYD4A2V-2OCZ2VTD-DPs08kJY.js +0 -1
  514. package/web/assets/pieDiagram-YPY3TKG5-BuT3MYzm.js +0 -39
  515. package/web/assets/radar-I7S5WNFK-EPLSA35B-w5F0K3a7.js +0 -1
  516. package/web/assets/railroad-3IZDKUUU-PWFQV6Y6-Bu668yqY.js +0 -1
  517. package/web/assets/railroad-abnf-AHOZXSZD-JYYJX3BS-B6ghpETS.js +0 -1
  518. package/web/assets/railroad-ebnf-EBAXGLYW-RBZ4ONAP-D-XmHh3M.js +0 -1
  519. package/web/assets/railroad-peg-LSFZ7HO6-KHNPXGPG-mhkrhzEn.js +0 -1
  520. package/web/assets/src-C5sx_gMp.js +0 -1
  521. package/web/assets/stateDiagram-DODFXNG5-DTdHc-fF.js +0 -1
  522. package/web/assets/stateDiagram-v2-JNMM5JRA-DioNLDDo.js +0 -1
  523. package/web/assets/swimlanes-OSWOYLSK-CA0ofdwY.js +0 -2
  524. package/web/assets/swimlanesDiagram-RHGX2RDE-PkwUdckC.js +0 -8
  525. package/web/assets/treeView-QDETBFTQ-EHYTSQNO-C5lpBgPm.js +0 -1
  526. package/web/assets/treemap-6X3UGDF4-CCWCF7EK-BB0ZyO-B.js +0 -1
  527. package/web/assets/wardley-OPB4EBWU-6OWERDVT-CEA3Nq0j.js +0 -1
  528. package/web/assets/wardleyDiagram-XK6FUAWV-CVV0dHFr.js +0 -78
  529. /package/web/assets/{sizeCapture-5GORAGP4-BEqQzsxs.js β†’ sizeCapture-FGA5AGYP-BEqQzsxs.js} +0 -0
@@ -16,6 +16,7 @@ export { ormPhase } from './orm.js';
16
16
  export { crossFilePhase } from './cross-file.js';
17
17
  export { scopeResolutionPhase, } from '../scope-resolution/pipeline/phase.js';
18
18
  export { springConfigPhase } from './spring-config.js';
19
+ export { springDestinationsPhase } from './spring-destinations.js';
19
20
  export { springAutoConfigurationPhase, } from './spring-auto-configuration.js';
20
21
  export { springAopPhase, springAopInheritancePhase, } from './spring-aop.js';
21
22
  export { pruneLocalSymbolsPhase } from './prune-local-symbols.js';
@@ -2,7 +2,7 @@
2
2
  * Parse implementation β€” chunked parse + resolve loop.
3
3
  *
4
4
  * This is the core parsing engine of the ingestion pipeline. It reads
5
- * source files in byte-budget chunks (~20MB each), parses via the worker
5
+ * source files in stable hash-bucket packs (~2MB each by default), parses via the worker
6
6
  * pool (the sole parse path β€” there is no sequential fallback), and emits
7
7
  * route CALLS edges. Import,
8
8
  * call, and inheritance resolution are owned by the scope-resolution
@@ -19,6 +19,7 @@ import { type ExportedTypeMap } from '../call-processor.js';
19
19
  import { type MutableSemanticModel } from '../model/index.js';
20
20
  import { type PipelineProgress } from '../../../_shared/index.js';
21
21
  import type { ExtractedDecoratorRoute, ExtractedFetchCall, ExtractedORMQuery, ExtractedRoute, ExtractedToolDef, FetchWrapperDef } from '../workers/parse-worker.js';
22
+ import type { ModuleConstants } from '../route-extractors/constant-resolver.js';
22
23
  import type { KnowledgeGraph } from '../../graph/types.js';
23
24
  import type { PipelineOptions } from '../pipeline.js';
24
25
  /** Projected main-thread heap need for the parse phase (#2649). */
@@ -96,11 +97,16 @@ export declare function runChunkedParseAndResolve(graph: KnowledgeGraph, scanned
96
97
  usedWorkerPool: boolean;
97
98
  /** Files dispatched to parser workers after parse-cache lookup. */
98
99
  reparsedFileCount: number;
100
+ /** Files restored from parse-cache chunks without parser-worker dispatch. */
101
+ parseCacheHitFileCount: number;
99
102
  /** Worker-produced ParsedFile artifacts aggregated across chunks.
100
103
  * Threaded into scope-resolution as a re-extract cache so the warm-
101
104
  * cache analyze run can skip the dominant `extractParsedFile` cost
102
105
  * (otherwise ~58s on a 1000-file repo). */
103
106
  parsedFiles: import('../../../_shared/index.js').ParsedFile[];
107
+ /** Repo-wide harvested constants, already prepared per provider. See
108
+ * `ParseOutput.moduleConstants` for why this leaves the parse phase. */
109
+ moduleConstants: ReadonlyMap<string, ModuleConstants>;
104
110
  scopeExtractionFailures: string[];
105
111
  /** Files excluded because their non-standalone language parser was unavailable. */
106
112
  unavailableScopeLanguageFiles: number;
@@ -2,7 +2,7 @@
2
2
  * Parse implementation β€” chunked parse + resolve loop.
3
3
  *
4
4
  * This is the core parsing engine of the ingestion pipeline. It reads
5
- * source files in byte-budget chunks (~20MB each), parses via the worker
5
+ * source files in stable hash-bucket packs (~2MB each by default), parses via the worker
6
6
  * pool (the sole parse path β€” there is no sequential fallback), and emits
7
7
  * route CALLS edges. Import,
8
8
  * call, and inheritance resolution are owned by the scope-resolution
@@ -16,8 +16,8 @@
16
16
  */
17
17
  import { BindingAccumulator, enrichExportedTypeMap, } from '../binding-accumulator.js';
18
18
  import { mergeChunkResults, dispatchChunkParse } from '../parsing-processor.js';
19
- import { fileContentHash, computeChunkHash, loadParseCacheChunk, persistParseCacheChunk, PARSE_CACHE_VERSION, } from '../../../storage/parse-cache.js';
20
- import { clearParsedFileStore, persistParsedFileChunk, loadParsedFilesForPaths, getDurableParsedFileDir, loadDurableParsedFileIndex, prepareDurableParsedFileChunk, restoreDurableParsedFileShard, } from '../../../storage/parsedfile-store.js';
19
+ import { fileContentHash, computeChunkHash, loadParseCacheChunk, persistParseCacheChunk, PARSE_CACHE_VERSION, packParseCacheChunks, } from '../../../storage/parse-cache.js';
20
+ import { clearParsedFileStore, persistParsedFileChunk, loadParsedFilesForPaths, getDurableParsedFileDir, loadDurableParsedFileIndex, prepareDurableParsedFileChunk, durableChunkHasShards, } from '../../../storage/parsedfile-store.js';
21
21
  import { DEFAULT_PDG_MAX_FUNCTION_LINES } from '../cfg/collect.js';
22
22
  import { processRoutesFromExtracted, resolveRouteHandlerSymbols, buildExportedTypeMapFromGraph, } from '../call-processor.js';
23
23
  import { createSemanticModel } from '../model/index.js';
@@ -30,7 +30,8 @@ import { SCOPE_RESOLVERS } from '../scope-resolution/pipeline/registry.js';
30
30
  import { DATA_ROUTE_TABLE_SOURCE } from '../route-extractors/data-route-table.js';
31
31
  import { createWorkerPool, workerPoolDisabledByEnv, resolveAutoPoolSize, WorkerPoolInitializationError, WorkerPoolDisabledError, } from '../workers/worker-pool.js';
32
32
  import { normalizeExtractedRoutePath } from '../route-extractors/route-path.js';
33
- import { resolveOperands, } from '../route-extractors/python-const-resolver.js';
33
+ import { resolveOperands } from '../route-extractors/python-const-resolver.js';
34
+ import { prepareRouteConstantsByProvider } from '../language-provider.js';
34
35
  import { resolveInheritedSpringRoutes, } from '../route-extractors/spring-shared.js';
35
36
  import fs from 'node:fs';
36
37
  import { effectiveRamBytes, memoryAutopilotDisabled } from '../utils/effective-ram.js';
@@ -111,38 +112,18 @@ export function heapPressureRemedy(heapLimitBytes) {
111
112
  return (`This machine is at its memory ceiling: exclude generated or vendored directories ` +
112
113
  `via .gitnexusignore, or analyze on a machine with more memory.`);
113
114
  }
114
- /** Max bytes of source content to load per parse chunk.
115
+ /** Max bytes of source content to load per parse cache pack.
115
116
  *
116
- * Memory bound for the worker pool dispatch + a granularity knob for
117
- * the parse cache. A single file change invalidates only its enclosing
118
- * chunk, so smaller budgets β†’ finer-grained invalidation.
119
- *
120
- * Override via GITNEXUS_CHUNK_BYTE_BUDGET (bytes) β€” the default of 2MB
121
- * gives a useful invalidation floor (~1/N chunks on a multi-MB repo)
122
- * while keeping worker dispatch overhead under 5% on cold runs.
123
- */
124
- /**
125
- * Built-in chunk byte budget when neither `PipelineOptions.chunkByteBudget`
126
- * nor `GITNEXUS_CHUNK_BYTE_BUDGET` is set. Tuned to give a useful
127
- * cache-invalidation floor (~1/N chunks on a multi-MB repo) while keeping
128
- * worker dispatch overhead under 5% on cold runs. Resolution happens at
129
- * call time inside `runChunkedParseAndResolve` (U14 from PR #1693 review)
130
- * β€” previously this was a module-load IIFE, which froze the env value at
131
- * import time and meant per-call option threading silently no-op'd.
117
+ * Granularity knob for the parse cache: a single file change invalidates only
118
+ * its enclosing pack. Override via GITNEXUS_CHUNK_BYTE_BUDGET. Resolution
119
+ * happens at call time (U14 from PR #1693) β€” not at module load.
132
120
  */
133
121
  const DEFAULT_CHUNK_BYTE_BUDGET = 2 * 1024 * 1024;
134
122
  /**
135
- * Per-worker share of a chunk's byte budget when auto-scaling (#worker-idle).
136
- *
137
- * A chunk is a single `WorkerPool.dispatch` unit; the pool fans a chunk's files
138
- * into sub-batch jobs and assigns them to idle workers (`wakeIdleSlots`). When
139
- * the chunk budget (2 MB) was far below the 8 MB sub-batch cap, every chunk
140
- * produced exactly ONE job β†’ ONE busy worker while the other N-1 sat idle. To
141
- * keep all workers fed, the auto chunk budget now scales as
142
- * `poolSize Γ— CHUNK_BYTES_PER_WORKER`, so each dispatch carries enough work to
143
- * fan across the whole pool. Sequential / explicit-budget runs are unaffected.
123
+ * Byte unit for auto pool sizing (one worker per this much source). Same
124
+ * magnitude as the default cache pack, but not a membership input (#3088).
144
125
  */
145
- const CHUNK_BYTES_PER_WORKER = 2 * 1024 * 1024;
126
+ const CHUNK_BYTES_PER_WORKER = DEFAULT_CHUNK_BYTE_BUDGET;
146
127
  /**
147
128
  * Target jobs-per-worker per dispatch. More jobs than workers gives the pool's
148
129
  * idle-slot assignment room to load-balance (a slow job doesn't strand a worker
@@ -151,16 +132,14 @@ const CHUNK_BYTES_PER_WORKER = 2 * 1024 * 1024;
151
132
  const TARGET_JOBS_PER_WORKER = 3;
152
133
  /** Floor for a derived sub-batch so jobs don't shrink to per-file IPC churn. */
153
134
  const MIN_SUB_BATCH_BYTES = 256 * 1024;
154
- function resolveChunkByteBudget(options, effectivePoolSize = 1) {
135
+ function resolveChunkByteBudget(options) {
155
136
  const opt = options?.chunkByteBudget;
156
137
  if (typeof opt === 'number' && Number.isFinite(opt) && opt > 0)
157
138
  return opt;
158
139
  const env = Number(process.env.GITNEXUS_CHUNK_BYTE_BUDGET);
159
140
  if (Number.isFinite(env) && env > 0)
160
141
  return env;
161
- // Auto: size each chunk so a dispatch can fan across the whole pool. A
162
- // single-worker (tiny-repo) run keeps the original 2 MB invalidation floor.
163
- return Math.max(DEFAULT_CHUNK_BYTE_BUDGET, effectivePoolSize * CHUNK_BYTES_PER_WORKER);
142
+ return DEFAULT_CHUNK_BYTE_BUDGET;
164
143
  }
165
144
  /**
166
145
  * Whole-repo, cross-file route extraction (main thread).
@@ -367,14 +346,6 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
367
346
  }
368
347
  }
369
348
  const unavailableScopeLanguageFiles = [...skippedByLang.values()].reduce((total, count) => total + count, 0);
370
- // Sort parseableScanned alphabetically for stable chunk membership
371
- // across runs (Finding 4). Without this, filesystem-scan order can
372
- // shift between runs (notably on macOS APFS where directory entry
373
- // order can change after modifications) β€” different files in the
374
- // same chunk β†’ different chunk hash β†’ cache miss even when no file
375
- // content changed. The cache also becomes platform-specific: a
376
- // Linux-built cache misses on macOS for the same repo.
377
- parseableScanned.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
378
349
  const totalParseable = parseableScanned.length;
379
350
  const totalBytes = parseableScanned.reduce((sum, f) => sum + f.size, 0);
380
351
  if (totalParseable === 0) {
@@ -416,24 +387,24 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
416
387
  // runs. Resolving in the function body restores per-call configurability
417
388
  // and matches the pattern used by resolveAutoPoolSize and the U1
418
389
  // parseChunkConcurrency resolver.
419
- // Effective worker count, computed up-front so the chunk budget can scale to
420
- // keep the whole pool busy (#worker-idle). The pool is ALWAYS used (sequential
421
- // parsing was removed; the disabled channels threw above). Size it to the
422
- // work: an explicit `--workers <N>` pins the size; otherwise the cores-based
423
- // auto size is capped by the repo's worth of work (~one worker per
424
- // CHUNK_BYTES_PER_WORKER of source) so a tiny repo spawns ~1 worker instead of
425
- // a full pool, replacing the job the deleted small-repo threshold used to do.
426
- // KTD-3 of the remove-sequential plan; the cap formula is intentionally coarse
427
- // (tuning deferred).
390
+ // Effective worker count: explicit `--workers <N>` pins it; otherwise
391
+ // cores-based auto size is capped by source bytes / CHUNK_BYTES_PER_WORKER
392
+ // so a tiny repo does not spawn a full idle pool. Cache pack membership
393
+ // is independent of this number (#3088).
428
394
  const explicitPoolSize = options?.workerPoolSize;
429
395
  const workProportionalCap = Math.max(1, Math.ceil(totalBytes / CHUNK_BYTES_PER_WORKER));
430
396
  const effectivePoolSize = explicitPoolSize && explicitPoolSize > 0
431
397
  ? explicitPoolSize
432
398
  : Math.min(resolveAutoPoolSize(), workProportionalCap);
433
- const chunkByteBudget = resolveChunkByteBudget(options, effectivePoolSize);
434
- // Sub-batch size so each chunk fans into ~`TARGET_JOBS_PER_WORKER` jobs per
435
- // worker, giving the pool's idle-slot assignment room to load-balance. An
436
- // explicit `GITNEXUS_WORKER_SUB_BATCH_MAX_BYTES` operator override wins.
399
+ // Cache packs: stable (language, hash(path) mod 128) buckets, then the
400
+ // per-call byte budget inside each bucket (#3088). Pool size is used only
401
+ // for worker count and sub-batch fan-out, not membership.
402
+ const chunkByteBudget = resolveChunkByteBudget(options);
403
+ // Sub-batch size so a 2 MiB pack fans into ~TARGET_JOBS_PER_WORKER jobs
404
+ // per worker, floored at MIN_SUB_BATCH_BYTES (256 KiB) so an 8-worker
405
+ // pool still gets ~8 jobs from one pack instead of one idle-heavy job
406
+ // (#worker-idle). Do not derive this from poolΓ—2 MiB while dispatching a
407
+ // 2 MiB pack. An explicit GITNEXUS_WORKER_SUB_BATCH_MAX_BYTES wins.
437
408
  const subBatchEnv = Number(process.env.GITNEXUS_WORKER_SUB_BATCH_MAX_BYTES);
438
409
  const dispatchSubBatchMaxBytes = Number.isFinite(subBatchEnv) && subBatchEnv > 0
439
410
  ? subBatchEnv
@@ -451,20 +422,11 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
451
422
  logger.warn(`Large repository: analyzing ${parseableScanned.length} files needs roughly ${Math.round(projectedHeapNeedBytes / 1024 / 1024 / 1024)}GB of memory, ` +
452
423
  `but Node is limited to ${Math.round(heapLimitBytes / 1024 / 1024 / 1024)}GB β€” analyze may stop early. ${heapPressureRemedy(heapLimitBytes)}`);
453
424
  }
454
- const chunks = [];
455
- let currentChunk = [];
456
- let currentBytes = 0;
457
- for (const file of parseableScanned) {
458
- if (currentChunk.length > 0 && currentBytes + file.size > chunkByteBudget) {
459
- chunks.push(currentChunk);
460
- currentChunk = [];
461
- currentBytes = 0;
462
- }
463
- currentChunk.push(file.path);
464
- currentBytes += file.size;
465
- }
466
- if (currentChunk.length > 0)
467
- chunks.push(currentChunk);
425
+ const chunks = packParseCacheChunks(parseableScanned.map((file) => ({
426
+ path: file.path,
427
+ size: file.size,
428
+ language: getLanguageFromFilename(file.path) ?? 'unknown',
429
+ })), chunkByteBudget);
468
430
  const numChunks = chunks.length;
469
431
  if (isDev) {
470
432
  const totalMB = parseableScanned.reduce((s, f) => s + f.size, 0) / (1024 * 1024);
@@ -586,15 +548,16 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
586
548
  // a sibling of the run-scoped store, NOT cleared per run. Workers write a
587
549
  // shard per chunk hash; on a warm parse-cache hit we restore the chunk's
588
550
  // shards into the run-scoped store so scope-resolution streams them without
589
- // re-parsing. `durableHitKeys` is the prior run's index, version-gated by
590
- // PARSE_CACHE_VERSION (a mismatch β‡’ empty β‡’ every chunk re-dispatches, which
591
- // repopulates the durable store β€” never the main-thread extract fallback).
551
+ // re-parsing. `durableHitEntries` is the prior run's path-coverage index,
552
+ // version-gated by PARSE_CACHE_VERSION (a mismatch β‡’ empty β‡’ every chunk
553
+ // re-dispatches, which repopulates the durable store).
592
554
  const durableParsedFileDir = parsedFileStorePath !== undefined ? getDurableParsedFileDir(parsedFileStorePath) : undefined;
593
- const durableHitKeys = durableParsedFileDir !== undefined
555
+ const durableHitEntries = durableParsedFileDir !== undefined
594
556
  ? await loadDurableParsedFileIndex(durableParsedFileDir, PARSE_CACHE_VERSION)
595
- : new Set();
557
+ : new Map();
596
558
  let chunkCacheHits = 0;
597
559
  let chunkCacheMisses = 0;
560
+ let parseCacheHitFileCount = 0;
598
561
  let reparsedFileCount = 0;
599
562
  try {
600
563
  // U1 β€” bounded chunk concurrency (B1 from PR #1693 review): pre-fetch
@@ -646,7 +609,11 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
646
609
  }
647
610
  if (chunkWorkerData.parsedFiles?.length) {
648
611
  if (parsedFileStorePath) {
649
- await persistParsedFileChunk(parsedFileStorePath, `chunk-${chunkIdx}`, chunkWorkerData.parsedFiles);
612
+ const wrote = await persistParsedFileChunk(parsedFileStorePath, `chunk-${chunkIdx}`, chunkWorkerData.parsedFiles);
613
+ if (!wrote) {
614
+ for (const item of chunkWorkerData.parsedFiles)
615
+ allParsedFiles.push(item);
616
+ }
650
617
  }
651
618
  else {
652
619
  for (const item of chunkWorkerData.parsedFiles)
@@ -833,7 +800,14 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
833
800
  // store was introduced, or a pruned/version-stale shard β€” fall through to
834
801
  // a worker re-dispatch to repopulate them. NEVER let scope-resolution
835
802
  // re-extract on the main thread (the #1983 OOM the durable store closes).
836
- const durableHit = chunkHash !== null && durableParsedFileDir !== undefined && durableHitKeys.has(chunkHash);
803
+ const durableExpectedPaths = chunkHash === null ? undefined : durableHitEntries.get(chunkHash);
804
+ const durableHit = cachedRaw !== undefined &&
805
+ cachedRaw.length > 0 &&
806
+ chunkHash !== null &&
807
+ durableParsedFileDir !== undefined &&
808
+ parsedFileStorePath !== undefined &&
809
+ durableExpectedPaths !== undefined &&
810
+ (await durableChunkHasShards(parsedFileStorePath, chunkHash, durableExpectedPaths));
837
811
  if (cachedRaw && cachedRaw.length > 0 && (durableHit || parsedFileStorePath === undefined)) {
838
812
  // Cache hit: replay cached worker output. Finalize any parked worker
839
813
  // chunk FIRST so deferred aggregation stays in chunk order, then merge
@@ -843,6 +817,7 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
843
817
  pendingWorkerChunk = null;
844
818
  }
845
819
  chunkCacheHits++;
820
+ parseCacheHitFileCount += chunkFiles.length;
846
821
  const chunkWorkerData = mergeChunkResults(graph, symbolTable, cachedRaw, exportedTypeMap);
847
822
  if (isDev) {
848
823
  logger.info(`πŸ“¦ parse-cache HIT: chunk ${chunkIdx + 1}/${numChunks} (${chunkFiles.length} files, ${chunkHash?.slice(0, 8) ?? 'unknown'})`);
@@ -863,16 +838,8 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
863
838
  nodesCreated: graph.nodeCount,
864
839
  },
865
840
  });
866
- // Restore the chunk's durable ParsedFile shards into the run-scoped
867
- // store so scope-resolution finds full coverage with ZERO main-thread
868
- // re-parse. A verbatim byte copy β€” byte-identical to a cold run.
869
- if (durableHit && durableParsedFileDir && parsedFileStorePath && chunkHash) {
870
- const restored = await restoreDurableParsedFileShard(durableParsedFileDir, parsedFileStorePath, chunkHash);
871
- if (restored === 0) {
872
- logger.warn(`parsedfile-cache: durable shards missing for cached chunk ` +
873
- `${chunkHash.slice(0, 8)} β€” scope-resolution will re-extract these files`);
874
- }
875
- }
841
+ // The durable gate already snapshotted warm `.v8` shards into the
842
+ // run-scoped store for scope resolution.
876
843
  await applyChunkResults(chunkWorkerData, chunkIdx, chunkFiles, chunkStartMs);
877
844
  }
878
845
  else {
@@ -1053,11 +1020,27 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
1053
1020
  // carries `routePathExpr`/`routePathOperands` and an empty `routePath`; we fold
1054
1021
  // the operands against the repo-wide, file-path-keyed constant map. On failure
1055
1022
  // we DROP the route (KTD5 skip floor) rather than emit a phantom `POST /`.
1023
+ //
1024
+ // Built (and prepared) UNCONDITIONALLY when anything was harvested, because
1025
+ // the map is also handed to downstream phases on `ParseOutput.moduleConstants`
1026
+ // β€” `springDestinations` folds broker-address constants against exactly the
1027
+ // same table. Preparation runs exactly once, here, on one map, before either
1028
+ // consumer folds. Deferring it into each consumer instead would need
1029
+ // `prepareRouteConstants` to be safe to call twice β€” it materializes deferred
1030
+ // wildcard bindings IN PLACE β€” or would leave whichever consumer ran first
1031
+ // folding against unprepared constants. Neither is worth the coupling; the
1032
+ // cost here is one pass over the harvested constants of a repo that has some.
1033
+ const repoConstants = new Map();
1034
+ for (const { filePath, constants } of allModuleConstants) {
1035
+ repoConstants.set(filePath, constants);
1036
+ }
1037
+ if (repoConstants.size > 0) {
1038
+ // Let each language prepare only its own constants slice before folding.
1039
+ // This is where deferred wildcard bindings can be materialized once per
1040
+ // provider without naming a language in the shared parse phase.
1041
+ prepareRouteConstantsByProvider(repoConstants, getProviderForFile);
1042
+ }
1056
1043
  if (allDecoratorRoutes.some((dr) => dr.routePathExpr !== undefined)) {
1057
- const repoConstants = new Map();
1058
- for (const { filePath, constants } of allModuleConstants) {
1059
- repoConstants.set(filePath, constants);
1060
- }
1061
1044
  const resolvedRoutes = [];
1062
1045
  let skipped = 0;
1063
1046
  for (const dr of allDecoratorRoutes) {
@@ -1343,11 +1326,16 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
1343
1326
  // is intentionally measured at dispatch time rather than inferred from
1344
1327
  // the git/hash diff.
1345
1328
  reparsedFileCount,
1329
+ parseCacheHitFileCount,
1346
1330
  // Per-file ParsedFile artifacts produced by workers' calls to
1347
1331
  // `extractParsedFile`. Consumed by scope-resolution as a re-extraction
1348
1332
  // cache: when the file's ParsedFile is here, scope-resolution skips its own
1349
1333
  // `extractParsedFile` call.
1350
1334
  parsedFiles: allParsedFiles,
1335
+ // Repo-wide, file-path-keyed constants, already through each provider's
1336
+ // `prepareRouteConstants` hook. Empty when no provider harvests constants
1337
+ // for the languages in this repo.
1338
+ moduleConstants: repoConstants,
1351
1339
  scopeExtractionFailures: [...scopeExtractionFailures].sort(),
1352
1340
  unavailableScopeLanguageFiles,
1353
1341
  };
@@ -20,6 +20,7 @@ import type { BindingAccumulator } from '../binding-accumulator.js';
20
20
  import type { ParsedFile } from '../../../_shared/index.js';
21
21
  import type { ExtractedFetchCall, ExtractedRoute, ExtractedDecoratorRoute, ExtractedToolDef, ExtractedORMQuery, FetchWrapperDef } from '../workers/parse-worker.js';
22
22
  import type { MutableSemanticModel } from '../model/index.js';
23
+ import type { ModuleConstants } from '../route-extractors/constant-resolver.js';
23
24
  export interface ParseOutput {
24
25
  /**
25
26
  * Read-only snapshot of exported type bindings keyed by file path.
@@ -70,6 +71,22 @@ export interface ParseOutput {
70
71
  * costing ~58s on a 1000-file repo).
71
72
  */
72
73
  readonly parsedFiles: readonly ParsedFile[];
74
+ /**
75
+ * Repo-wide string constants harvested by the providers that declare
76
+ * `extractModuleConstants`, keyed by file path and already through each
77
+ * provider's `prepareRouteConstants` hook.
78
+ *
79
+ * Exposed so a later phase can fold a constant reference the same way the
80
+ * decorator-route pass does β€” `springDestinations` resolves a broker address
81
+ * written as `Topics.ORDERS` against this table. It is a snapshot: parse does
82
+ * not mutate it after returning, and consumers must not either, because the
83
+ * preparation that made it foldable has already run.
84
+ *
85
+ * Empty when no provider in this repo harvests constants. A downstream fold
86
+ * against an empty table simply fails to resolve, which is a recorded refusal
87
+ * rather than a wrong answer.
88
+ */
89
+ readonly moduleConstants: ReadonlyMap<string, ModuleConstants>;
73
90
  /** Files whose scope extraction failed while legacy parsing continued. */
74
91
  readonly scopeExtractionFailures: readonly string[];
75
92
  /** Files omitted because their non-standalone language parser was unavailable. */
@@ -4,7 +4,8 @@
4
4
  * Detects execution flows (processes) and creates Process nodes +
5
5
  * STEP_IN_PROCESS edges. Also links Route/Tool nodes to processes.
6
6
  *
7
- * @deps communities, routes, tools, pruneLocalSymbols, structure, parse
7
+ * @deps communities, routes, tools, springAutoConfiguration,
8
+ * pruneLocalSymbols, structure, parse
8
9
  * @reads graph (all nodes and relationships), communityResult, routeRegistry,
9
10
  * toolDefs, parse's allFetchCalls + allORMQueries (R3-6 sink sites)
10
11
  * @writes graph (Process nodes, STEP_IN_PROCESS edges, ENTRY_POINT_OF edges)
@@ -4,7 +4,8 @@
4
4
  * Detects execution flows (processes) and creates Process nodes +
5
5
  * STEP_IN_PROCESS edges. Also links Route/Tool nodes to processes.
6
6
  *
7
- * @deps communities, routes, tools, pruneLocalSymbols, structure, parse
7
+ * @deps communities, routes, tools, springAutoConfiguration,
8
+ * pruneLocalSymbols, structure, parse
8
9
  * @reads graph (all nodes and relationships), communityResult, routeRegistry,
9
10
  * toolDefs, parse's allFetchCalls + allORMQueries (R3-6 sink sites)
10
11
  * @writes graph (Process nodes, STEP_IN_PROCESS edges, ENTRY_POINT_OF edges)
@@ -39,7 +40,15 @@ export const processesPhase = {
39
40
  // sinks rather than failing the phase. `pruneLocalSymbols` is declared
40
41
  // explicitly so process extraction always reads the trimmed graph even if a
41
42
  // future option drops the intervening `mro`/`communities` phases.
42
- deps: ['communities', 'routes', 'tools', 'pruneLocalSymbols', 'structure', 'parse'],
43
+ deps: [
44
+ 'communities',
45
+ 'routes',
46
+ 'tools',
47
+ 'springAutoConfiguration',
48
+ 'pruneLocalSymbols',
49
+ 'structure',
50
+ 'parse',
51
+ ],
43
52
  async execute(ctx, deps) {
44
53
  const { totalFiles } = getPhaseOutput(deps, 'structure');
45
54
  const { communityResult } = getPhaseOutput(deps, 'communities');
@@ -172,8 +181,34 @@ export const processesPhase = {
172
181
  step: step.step,
173
182
  });
174
183
  });
184
+ // The static registry is finalized before Spring runtime enrichment. Merge
185
+ // runtime-confirmed Route nodes from the graph after the explicit
186
+ // springAutoConfiguration dependency has completed, so Actuator-only
187
+ // mappings participate in the same process-linking path.
188
+ const processRouteRegistry = new Map(routeRegistry);
189
+ ctx.graph.forEachNode((node) => {
190
+ if (node.label !== 'Route' ||
191
+ node.properties.runtimeSource !== 'spring-actuator' ||
192
+ node.properties.runtimeConfirmed !== true) {
193
+ return;
194
+ }
195
+ const url = typeof node.properties.name === 'string' ? node.properties.name : undefined;
196
+ const filePath = typeof node.properties.filePath === 'string' ? node.properties.filePath : undefined;
197
+ const method = typeof node.properties.method === 'string' ? node.properties.method : undefined;
198
+ if (url === undefined || filePath === undefined)
199
+ return;
200
+ const key = routeNodeKey(method, url);
201
+ if (!processRouteRegistry.has(key)) {
202
+ processRouteRegistry.set(key, {
203
+ filePath,
204
+ source: 'spring-actuator-runtime',
205
+ url,
206
+ ...(method === undefined ? {} : { method }),
207
+ });
208
+ }
209
+ });
175
210
  // Link Route and Tool nodes to Processes
176
- if (routeRegistry.size > 0 || toolDefs.length > 0) {
211
+ if (processRouteRegistry.size > 0 || toolDefs.length > 0) {
177
212
  // Two-tier route lookup, mirroring the tool tables 10 lines below.
178
213
  // Routes whose handler resolved key by `handlerSymbolId` (read from
179
214
  // the Route node's graph properties β€” routes.ts stamps it there) and
@@ -188,7 +223,7 @@ export const processesPhase = {
188
223
  // routes phase stamps on the Route node was never consulted.
189
224
  const routesByHandlerId = new Map();
190
225
  const routesWithoutHandlerByFile = new Map();
191
- for (const [, entry] of routeRegistry) {
226
+ for (const [, entry] of processRouteRegistry) {
192
227
  // Push the Route node identity (`routeNodeKey`), not the bare URL, so the
193
228
  // ENTRY_POINT_OF edge targets the same node id the routes phase created
194
229
  // (#2289: a same-URL GET/POST pair is two distinct Route nodes).
@@ -265,28 +265,25 @@ export const routesPhase = {
265
265
  }
266
266
  let handlerContents;
267
267
  if (routeRegistry.size > 0) {
268
- const handlerPathFor = (routeKey, entry) => {
269
- if (entry.source !== DATA_ROUTE_TABLE_SOURCE)
270
- return entry.filePath;
271
- const handlerSymbolId = routeHandlerSymbols.get(routeKey);
272
- const resolvedPath = handlerSymbolId
273
- ? ctx.graph.getNode(handlerSymbolId)?.properties.filePath
268
+ // Resolve once so content attribution, the route stamp, and the edge use
269
+ // the same live graph node. Pre-seeded routes never own handler symbols.
270
+ const routes = [...routeRegistry].map(([routeKey, entry]) => {
271
+ const id = preSeededKeys.has(routeKey) ? undefined : routeHandlerSymbols.get(routeKey);
272
+ const node = id ? ctx.graph.getNode(id) : undefined;
273
+ const handlerSymbol = id && node ? { id, node } : undefined;
274
+ const resolvedPath = entry.source === DATA_ROUTE_TABLE_SOURCE
275
+ ? handlerSymbol?.node.properties.filePath
274
276
  : undefined;
275
- return typeof resolvedPath === 'string' ? resolvedPath : entry.filePath;
276
- };
277
- const handlerPaths = [...routeRegistry].map(([key, entry]) => handlerPathFor(key, entry));
278
- handlerContents = await readFileContents(ctx.repoPath, handlerPaths);
279
- for (const [routeKey, entry] of routeRegistry) {
277
+ const handlerPath = typeof resolvedPath === 'string' ? resolvedPath : entry.filePath;
278
+ return { routeKey, entry, handlerSymbol, handlerPath };
279
+ });
280
+ handlerContents = await readFileContents(ctx.repoPath, routes.map(({ handlerPath }) => handlerPath));
281
+ for (const { routeKey, entry, handlerSymbol, handlerPath } of routes) {
280
282
  const { source: routeSource, method: routeMethod, url } = entry;
281
- const handlerPath = handlerPathFor(routeKey, entry);
282
283
  const content = handlerContents.get(handlerPath);
283
- // A pre-seeded route can never legitimately appear in
284
- // `routeHandlerSymbols`, so a key that does is a route that LOST (#3049).
285
- const handlerSymbolId = preSeededKeys.has(routeKey)
286
- ? undefined
287
- : routeHandlerSymbols.get(routeKey);
284
+ const handlerSymbolId = handlerSymbol?.id;
288
285
  const analysisContent = entry.source === DATA_ROUTE_TABLE_SOURCE && content
289
- ? handlerSymbolContent(content, handlerSymbolId ? ctx.graph.getNode(handlerSymbolId) : undefined)
286
+ ? handlerSymbolContent(content, handlerSymbol?.node)
290
287
  : content;
291
288
  const { responseKeys, errorKeys } = analysisContent
292
289
  ? handlerPath.endsWith('.php')
@@ -318,6 +315,18 @@ export const routesPhase = {
318
315
  confidence: 1.0,
319
316
  reason: routeSource,
320
317
  });
318
+ // Keep the file edge for existing extractor queries; add the live
319
+ // definition edge for explicit handler-level traversal.
320
+ if (handlerSymbolId) {
321
+ ctx.graph.addRelationship({
322
+ id: generateId('HANDLES_ROUTE', `${handlerSymbolId}->${routeNodeId}`),
323
+ sourceId: handlerSymbolId,
324
+ targetId: routeNodeId,
325
+ type: 'HANDLES_ROUTE',
326
+ confidence: 1.0,
327
+ reason: routeSource,
328
+ });
329
+ }
321
330
  }
322
331
  if (isDev) {
323
332
  logger.info(`πŸ—ΊοΈ Route registry: ${routeRegistry.size} routes${duplicateRoutes > 0 ? ` (${duplicateRoutes} duplicate URLs skipped)` : ''}`);
@@ -17,6 +17,9 @@ import type { PipelinePhase, PipelineContext, PhaseResult } from './types.js';
17
17
  *
18
18
  * @param phases All phases to execute (order doesn't matter β€” sorted internally)
19
19
  * @param ctx Shared pipeline context
20
+ * @param seed Results of phases that already ran against this same context,
21
+ * available to `phases` as dependencies (#3016 deferred derived
22
+ * phases). Included in the returned map.
20
23
  * @returns Map of phase name β†’ PhaseResult (all completed phases)
21
24
  */
22
- export declare function runPipeline(phases: readonly PipelinePhase[], ctx: PipelineContext): Promise<ReadonlyMap<string, PhaseResult<unknown>>>;
25
+ export declare function runPipeline(phases: readonly PipelinePhase[], ctx: PipelineContext, seed?: ReadonlyMap<string, PhaseResult<unknown>>): Promise<ReadonlyMap<string, PhaseResult<unknown>>>;
@@ -13,22 +13,30 @@
13
13
  */
14
14
  import { isDev } from '../utils/env.js';
15
15
  import { logger } from '../../logger.js';
16
- /**
17
- * Validate that the phases form a valid dependency graph (no cycles, all deps present).
18
- * Returns phases in topological execution order.
19
- */
20
- function topologicalSort(phases) {
21
- const phaseMap = new Map();
16
+ function assertUniquePhaseNames(phases) {
17
+ const seen = new Set();
22
18
  for (const phase of phases) {
23
- if (phaseMap.has(phase.name)) {
19
+ if (seen.has(phase.name)) {
24
20
  throw new Error(`Duplicate phase name: '${phase.name}'`);
25
21
  }
26
- phaseMap.set(phase.name, phase);
22
+ seen.add(phase.name);
27
23
  }
24
+ }
25
+ /**
26
+ * Validate that the phases form a valid dependency graph (no cycles, all deps present).
27
+ * Returns phases in topological execution order.
28
+ *
29
+ * `satisfied` names phases whose results are already available (a deferred
30
+ * follow-up run over the same context, #3016). Their edges are dropped rather
31
+ * than validated, because they are resolved by definition.
32
+ */
33
+ function topologicalSort(phases, satisfied = new Set()) {
34
+ assertUniquePhaseNames(phases);
35
+ const phaseMap = new Map(phases.map((p) => [p.name, p]));
28
36
  // Validate all deps exist
29
37
  for (const phase of phases) {
30
38
  for (const dep of phase.deps) {
31
- if (!phaseMap.has(dep)) {
39
+ if (!phaseMap.has(dep) && !satisfied.has(dep)) {
32
40
  throw new Error(`Phase '${phase.name}' depends on '${dep}', which is not registered`);
33
41
  }
34
42
  }
@@ -37,8 +45,9 @@ function topologicalSort(phases) {
37
45
  const inDegree = new Map();
38
46
  const reverseDeps = new Map();
39
47
  for (const phase of phases) {
40
- inDegree.set(phase.name, phase.deps.length);
41
- for (const dep of phase.deps) {
48
+ const pendingDeps = phase.deps.filter((dep) => !satisfied.has(dep));
49
+ inDegree.set(phase.name, pendingDeps.length);
50
+ for (const dep of pendingDeps) {
42
51
  let rev = reverseDeps.get(dep);
43
52
  if (!rev) {
44
53
  rev = [];
@@ -125,12 +134,23 @@ function findCyclePath(remaining, phaseMap) {
125
134
  *
126
135
  * @param phases All phases to execute (order doesn't matter β€” sorted internally)
127
136
  * @param ctx Shared pipeline context
137
+ * @param seed Results of phases that already ran against this same context,
138
+ * available to `phases` as dependencies (#3016 deferred derived
139
+ * phases). Included in the returned map.
128
140
  * @returns Map of phase name β†’ PhaseResult (all completed phases)
129
141
  */
130
- export async function runPipeline(phases, ctx) {
142
+ export async function runPipeline(phases, ctx, seed) {
143
+ // A seeded phase has already run against this context; re-running it would
144
+ // apply its graph writes a second time. "Already ran" is the whole meaning of
145
+ // the seed, so honour it here rather than making every caller pre-filter.
146
+ const satisfied = new Set(seed?.keys() ?? []);
131
147
  let sorted;
132
148
  try {
133
- sorted = topologicalSort(phases);
149
+ // Duplicate names must be rejected on the caller-supplied list *before*
150
+ // seed-filtering. Filtering first would drop a seeded duplicate and let
151
+ // `topologicalSort` see a unique name (#3102).
152
+ assertUniquePhaseNames(phases);
153
+ sorted = topologicalSort(phases.filter((p) => !satisfied.has(p.name)), satisfied);
134
154
  }
135
155
  catch (err) {
136
156
  // Emit a terminal 'error' progress event for graph-validation failures
@@ -152,7 +172,7 @@ export async function runPipeline(phases, ctx) {
152
172
  }
153
173
  throw err;
154
174
  }
155
- const results = new Map();
175
+ const results = new Map(seed);
156
176
  for (const phase of sorted) {
157
177
  const start = Date.now();
158
178
  if (isDev) {