cgraphx 2.0.2 → 2.0.6

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 (754) hide show
  1. package/dist/.claude-template/FLOW-MAP.md +13 -3
  2. package/dist/.claude-template/agents/task-history.md +186 -0
  3. package/dist/.claude-template/commands/end.md +1 -0
  4. package/dist/.claude-template/skills/cgraphx-guide/SKILL.md +5 -3
  5. package/dist/.claude-template/skills/cgraphx-guide/how-to-use.html +8 -8
  6. package/dist/.claude-template/skills/cgraphx-guide/how-to-use.md +8 -8
  7. package/dist/.claude-template/skills/clarify-requirements/SKILL.md +13 -9
  8. package/dist/.claude-template/skills/db-query/SKILL.md +19 -2
  9. package/dist/.claude-template/skills/iboc-check/SKILL.md +51 -23
  10. package/dist/.claude-template/skills/iboc-check/filler-prompt.md +3 -4
  11. package/dist/.claude-template/skills/run-api-test/SKILL.md +15 -15
  12. package/dist/.claude-template/skills/run-api-test/assets/{template-test-report.md → template-/346/216/245/345/217/243/346/265/213/350/257/225/346/212/245/345/221/212.md} +4 -4
  13. package/dist/.claude-template/skills/run-api-test/references/bru-run.md +1 -1
  14. package/dist/.claude-template/skills/run-api-test/references/db-verification.md +2 -2
  15. package/dist/.claude-template/skills/run-api-test/references/report-format.md +6 -6
  16. package/dist/.claude-template/skills/run-api-test/references/service-readiness.md +1 -1
  17. package/dist/.claude-template/skills/run-api-test/references/test-scope.md +6 -6
  18. package/dist/.claude-template/skills/run-ui-test/SKILL.md +186 -0
  19. package/dist/.claude-template/skills/run-ui-test/references/report-format.md +77 -0
  20. package/dist/.claude-template/skills/subagent-implement/SKILL.md +3 -2
  21. package/dist/.claude-template/skills/write-api/SKILL.md +18 -18
  22. package/dist/.claude-template/skills/write-api/assets/{template-api-spec.md → template-/346/216/245/345/217/243/346/265/213/350/257/225-spec.md} +1 -1
  23. package/dist/.claude-template/skills/write-api/references/{api-spec-format.md → /346/216/245/345/217/243/346/265/213/350/257/225-spec-format.md} +3 -3
  24. package/dist/.claude-template/skills/write-plan/SKILL.md +4 -2
  25. package/dist/.claude-template/skills/write-ui-test/SKILL.md +125 -0
  26. package/dist/.claude-template/skills/write-ui-test/references//347/224/250/344/276/213/350/247/204/346/240/274-format.md +94 -0
  27. package/dist/core/code/engine/cli/analyze-config.js +320 -0
  28. package/dist/core/code/engine/cli/analyze.js +1086 -0
  29. package/dist/core/code/engine/cli/cli-message.js +83 -0
  30. package/dist/core/code/engine/cli/detect-changes-format.js +58 -0
  31. package/dist/core/code/engine/cli/embedding-dims.js +43 -0
  32. package/dist/core/code/engine/cli/format-elapsed.js +12 -0
  33. package/dist/core/code/engine/cli/help-i18n.js +144 -0
  34. package/dist/core/code/engine/cli/i18n/en.js +110 -0
  35. package/dist/core/code/engine/cli/i18n/index.js +47 -0
  36. package/dist/core/code/engine/cli/i18n/resources.js +9 -0
  37. package/dist/core/code/engine/cli/i18n/zh-CN.js +110 -0
  38. package/dist/core/code/engine/cli/lazy-action.js +67 -0
  39. package/dist/core/code/engine/cli/optional-grammars.js +136 -0
  40. package/dist/core/code/engine/cli/resolve-invocation.js +76 -0
  41. package/dist/core/code/engine/cli/status.js +156 -0
  42. package/dist/core/code/engine/cli/tool.js +384 -0
  43. package/dist/core/code/engine/config/ignore-service.js +511 -0
  44. package/dist/core/code/engine/config/supported-languages.js +17 -0
  45. package/dist/core/code/engine/core/analysis-features.js +64 -0
  46. package/dist/core/code/engine/core/analyzer-identity.js +2171 -0
  47. package/dist/core/code/engine/core/git-staleness.js +180 -0
  48. package/dist/core/code/engine/core/graph/graph.js +180 -0
  49. package/dist/core/code/engine/core/graph/import-cycles.js +106 -0
  50. package/dist/core/code/engine/core/graph/types.js +2 -0
  51. package/dist/core/code/engine/core/index-freshness.js +12 -0
  52. package/dist/core/code/engine/core/ingestion/binding-accumulator.js +341 -0
  53. package/dist/core/code/engine/core/ingestion/call-extractors/configs/c-cpp.js +168 -0
  54. package/dist/core/code/engine/core/ingestion/call-extractors/configs/csharp.js +9 -0
  55. package/dist/core/code/engine/core/ingestion/call-extractors/configs/dart.js +8 -0
  56. package/dist/core/code/engine/core/ingestion/call-extractors/configs/go.js +8 -0
  57. package/dist/core/code/engine/core/ingestion/call-extractors/configs/jvm.js +54 -0
  58. package/dist/core/code/engine/core/ingestion/call-extractors/configs/php.js +8 -0
  59. package/dist/core/code/engine/core/ingestion/call-extractors/configs/python.js +8 -0
  60. package/dist/core/code/engine/core/ingestion/call-extractors/configs/ruby.js +8 -0
  61. package/dist/core/code/engine/core/ingestion/call-extractors/configs/rust.js +8 -0
  62. package/dist/core/code/engine/core/ingestion/call-extractors/configs/swift.js +8 -0
  63. package/dist/core/code/engine/core/ingestion/call-extractors/configs/typescript-javascript.js +11 -0
  64. package/dist/core/code/engine/core/ingestion/call-extractors/generic.js +62 -0
  65. package/dist/core/code/engine/core/ingestion/call-processor.js +503 -0
  66. package/dist/core/code/engine/core/ingestion/call-routing.js +98 -0
  67. package/dist/core/code/engine/core/ingestion/call-types.js +3 -0
  68. package/dist/core/code/engine/core/ingestion/cfg/callee-cell-format.js +45 -0
  69. package/dist/core/code/engine/core/ingestion/cfg/cfg-builder.js +202 -0
  70. package/dist/core/code/engine/core/ingestion/cfg/collect.js +81 -0
  71. package/dist/core/code/engine/core/ingestion/cfg/control-dependence.js +185 -0
  72. package/dist/core/code/engine/core/ingestion/cfg/control-flow-context.js +130 -0
  73. package/dist/core/code/engine/core/ingestion/cfg/emit.js +646 -0
  74. package/dist/core/code/engine/core/ingestion/cfg/post-dominators.js +182 -0
  75. package/dist/core/code/engine/core/ingestion/cfg/reaching-def-reason-codec.js +139 -0
  76. package/dist/core/code/engine/core/ingestion/cfg/reaching-defs-graph.js +322 -0
  77. package/dist/core/code/engine/core/ingestion/cfg/reaching-defs.js +792 -0
  78. package/dist/core/code/engine/core/ingestion/cfg/synthetic-escape.js +305 -0
  79. package/dist/core/code/engine/core/ingestion/cfg/traversal-result.js +6 -0
  80. package/dist/core/code/engine/core/ingestion/cfg/types.js +14 -0
  81. package/dist/core/code/engine/core/ingestion/cfg/visitors/c-cpp-harvest.js +545 -0
  82. package/dist/core/code/engine/core/ingestion/cfg/visitors/c-cpp.js +590 -0
  83. package/dist/core/code/engine/core/ingestion/cfg/visitors/call-site-harvest.js +356 -0
  84. package/dist/core/code/engine/core/ingestion/cfg/visitors/csharp-harvest.js +593 -0
  85. package/dist/core/code/engine/core/ingestion/cfg/visitors/csharp.js +871 -0
  86. package/dist/core/code/engine/core/ingestion/cfg/visitors/dart-harvest.js +874 -0
  87. package/dist/core/code/engine/core/ingestion/cfg/visitors/dart.js +840 -0
  88. package/dist/core/code/engine/core/ingestion/cfg/visitors/go-harvest.js +625 -0
  89. package/dist/core/code/engine/core/ingestion/cfg/visitors/go.js +642 -0
  90. package/dist/core/code/engine/core/ingestion/cfg/visitors/java-harvest.js +517 -0
  91. package/dist/core/code/engine/core/ingestion/cfg/visitors/java.js +816 -0
  92. package/dist/core/code/engine/core/ingestion/cfg/visitors/kotlin-harvest.js +723 -0
  93. package/dist/core/code/engine/core/ingestion/cfg/visitors/kotlin.js +813 -0
  94. package/dist/core/code/engine/core/ingestion/cfg/visitors/php-harvest.js +630 -0
  95. package/dist/core/code/engine/core/ingestion/cfg/visitors/php.js +725 -0
  96. package/dist/core/code/engine/core/ingestion/cfg/visitors/python-harvest.js +776 -0
  97. package/dist/core/code/engine/core/ingestion/cfg/visitors/python.js +562 -0
  98. package/dist/core/code/engine/core/ingestion/cfg/visitors/ruby-harvest.js +591 -0
  99. package/dist/core/code/engine/core/ingestion/cfg/visitors/ruby.js +760 -0
  100. package/dist/core/code/engine/core/ingestion/cfg/visitors/rust-harvest.js +877 -0
  101. package/dist/core/code/engine/core/ingestion/cfg/visitors/rust.js +562 -0
  102. package/dist/core/code/engine/core/ingestion/cfg/visitors/scope-tree-harvest.js +120 -0
  103. package/dist/core/code/engine/core/ingestion/cfg/visitors/swift-harvest.js +683 -0
  104. package/dist/core/code/engine/core/ingestion/cfg/visitors/swift.js +791 -0
  105. package/dist/core/code/engine/core/ingestion/cfg/visitors/typescript-harvest.js +1060 -0
  106. package/dist/core/code/engine/core/ingestion/cfg/visitors/typescript.js +587 -0
  107. package/dist/core/code/engine/core/ingestion/class-extractors/configs/c-cpp.js +77 -0
  108. package/dist/core/code/engine/core/ingestion/class-extractors/configs/csharp.js +24 -0
  109. package/dist/core/code/engine/core/ingestion/class-extractors/configs/dart.js +10 -0
  110. package/dist/core/code/engine/core/ingestion/class-extractors/configs/go.js +28 -0
  111. package/dist/core/code/engine/core/ingestion/class-extractors/configs/jvm.js +67 -0
  112. package/dist/core/code/engine/core/ingestion/class-extractors/configs/php.js +10 -0
  113. package/dist/core/code/engine/core/ingestion/class-extractors/configs/python.js +10 -0
  114. package/dist/core/code/engine/core/ingestion/class-extractors/configs/ruby.js +13 -0
  115. package/dist/core/code/engine/core/ingestion/class-extractors/configs/rust.js +10 -0
  116. package/dist/core/code/engine/core/ingestion/class-extractors/configs/swift.js +21 -0
  117. package/dist/core/code/engine/core/ingestion/class-extractors/configs/typescript-javascript.js +31 -0
  118. package/dist/core/code/engine/core/ingestion/class-extractors/generic.js +144 -0
  119. package/dist/core/code/engine/core/ingestion/class-types.js +2 -0
  120. package/dist/core/code/engine/core/ingestion/cluster-enricher.js +174 -0
  121. package/dist/core/code/engine/core/ingestion/community-processor.js +604 -0
  122. package/dist/core/code/engine/core/ingestion/constants.js +26 -0
  123. package/dist/core/code/engine/core/ingestion/cpp-ue-preprocessor.js +263 -0
  124. package/dist/core/code/engine/core/ingestion/csharp-namespace-gate.js +133 -0
  125. package/dist/core/code/engine/core/ingestion/di-extractors/index.js +38 -0
  126. package/dist/core/code/engine/core/ingestion/di-extractors/spring.js +310 -0
  127. package/dist/core/code/engine/core/ingestion/emit-references.js +244 -0
  128. package/dist/core/code/engine/core/ingestion/entry-point-scoring.js +201 -0
  129. package/dist/core/code/engine/core/ingestion/export-detection.js +244 -0
  130. package/dist/core/code/engine/core/ingestion/field-extractor.js +29 -0
  131. package/dist/core/code/engine/core/ingestion/field-extractors/configs/c-cpp.js +107 -0
  132. package/dist/core/code/engine/core/ingestion/field-extractors/configs/csharp.js +124 -0
  133. package/dist/core/code/engine/core/ingestion/field-extractors/configs/dart.js +99 -0
  134. package/dist/core/code/engine/core/ingestion/field-extractors/configs/go.js +102 -0
  135. package/dist/core/code/engine/core/ingestion/field-extractors/configs/helpers.js +198 -0
  136. package/dist/core/code/engine/core/ingestion/field-extractors/configs/jvm.js +172 -0
  137. package/dist/core/code/engine/core/ingestion/field-extractors/configs/php.js +67 -0
  138. package/dist/core/code/engine/core/ingestion/field-extractors/configs/python.js +94 -0
  139. package/dist/core/code/engine/core/ingestion/field-extractors/configs/ruby.js +79 -0
  140. package/dist/core/code/engine/core/ingestion/field-extractors/configs/rust.js +55 -0
  141. package/dist/core/code/engine/core/ingestion/field-extractors/configs/swift.js +93 -0
  142. package/dist/core/code/engine/core/ingestion/field-extractors/configs/typescript-javascript.js +59 -0
  143. package/dist/core/code/engine/core/ingestion/field-extractors/generic.js +147 -0
  144. package/dist/core/code/engine/core/ingestion/field-extractors/typescript.js +266 -0
  145. package/dist/core/code/engine/core/ingestion/field-types.js +3 -0
  146. package/dist/core/code/engine/core/ingestion/filesystem-walker.js +136 -0
  147. package/dist/core/code/engine/core/ingestion/finalize-orchestrator.js +159 -0
  148. package/dist/core/code/engine/core/ingestion/framework-detection.js +432 -0
  149. package/dist/core/code/engine/core/ingestion/frameworks/spring/analysis-features.js +38 -0
  150. package/dist/core/code/engine/core/ingestion/frameworks/spring/annotation-arguments.js +234 -0
  151. package/dist/core/code/engine/core/ingestion/frameworks/spring/aop-candidates.js +88 -0
  152. package/dist/core/code/engine/core/ingestion/frameworks/spring/aop.js +487 -0
  153. package/dist/core/code/engine/core/ingestion/frameworks/spring/auto-configuration.js +21 -0
  154. package/dist/core/code/engine/core/ingestion/frameworks/spring/bean-candidates.js +189 -0
  155. package/dist/core/code/engine/core/ingestion/frameworks/spring/bean-catalog.js +32 -0
  156. package/dist/core/code/engine/core/ingestion/frameworks/spring/bean-factories.js +73 -0
  157. package/dist/core/code/engine/core/ingestion/frameworks/spring/conditionals.js +323 -0
  158. package/dist/core/code/engine/core/ingestion/frameworks/spring/config-bindings.js +119 -0
  159. package/dist/core/code/engine/core/ingestion/frameworks/spring/di-metadata.js +385 -0
  160. package/dist/core/code/engine/core/ingestion/frameworks/spring/resource-injection.js +96 -0
  161. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/c-cpp.js +17 -0
  162. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/csharp.js +46 -0
  163. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/dart.js +59 -0
  164. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/go.js +30 -0
  165. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/jvm.js +73 -0
  166. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/php.js +19 -0
  167. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/python.js +45 -0
  168. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/ruby.js +20 -0
  169. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/rust.js +58 -0
  170. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/swift.js +94 -0
  171. package/dist/core/code/engine/core/ingestion/import-resolvers/configs/typescript-javascript.js +26 -0
  172. package/dist/core/code/engine/core/ingestion/import-resolvers/csharp.js +128 -0
  173. package/dist/core/code/engine/core/ingestion/import-resolvers/go.js +50 -0
  174. package/dist/core/code/engine/core/ingestion/import-resolvers/jvm.js +112 -0
  175. package/dist/core/code/engine/core/ingestion/import-resolvers/php.js +80 -0
  176. package/dist/core/code/engine/core/ingestion/import-resolvers/python.js +75 -0
  177. package/dist/core/code/engine/core/ingestion/import-resolvers/resolver-factory.js +36 -0
  178. package/dist/core/code/engine/core/ingestion/import-resolvers/ruby.js +20 -0
  179. package/dist/core/code/engine/core/ingestion/import-resolvers/rust.js +79 -0
  180. package/dist/core/code/engine/core/ingestion/import-resolvers/standard.js +180 -0
  181. package/dist/core/code/engine/core/ingestion/import-resolvers/types.js +7 -0
  182. package/dist/core/code/engine/core/ingestion/import-resolvers/utils.js +153 -0
  183. package/dist/core/code/engine/core/ingestion/import-target-adapter.js +99 -0
  184. package/dist/core/code/engine/core/ingestion/language-config.js +391 -0
  185. package/dist/core/code/engine/core/ingestion/language-provider.js +25 -0
  186. package/dist/core/code/engine/core/ingestion/languages/c/arity-metadata.js +98 -0
  187. package/dist/core/code/engine/core/ingestion/languages/c/arity.js +21 -0
  188. package/dist/core/code/engine/core/ingestion/languages/c/capture-side-channel.js +69 -0
  189. package/dist/core/code/engine/core/ingestion/languages/c/captures.js +189 -0
  190. package/dist/core/code/engine/core/ingestion/languages/c/header-scan.js +58 -0
  191. package/dist/core/code/engine/core/ingestion/languages/c/import-decomposer.js +68 -0
  192. package/dist/core/code/engine/core/ingestion/languages/c/import-target.js +103 -0
  193. package/dist/core/code/engine/core/ingestion/languages/c/index.js +33 -0
  194. package/dist/core/code/engine/core/ingestion/languages/c/interpret.js +53 -0
  195. package/dist/core/code/engine/core/ingestion/languages/c/merge-bindings.js +26 -0
  196. package/dist/core/code/engine/core/ingestion/languages/c/query.js +210 -0
  197. package/dist/core/code/engine/core/ingestion/languages/c/scope-resolver.js +112 -0
  198. package/dist/core/code/engine/core/ingestion/languages/c/simple-hooks.js +24 -0
  199. package/dist/core/code/engine/core/ingestion/languages/c/static-linkage.js +109 -0
  200. package/dist/core/code/engine/core/ingestion/languages/c-cpp.js +506 -0
  201. package/dist/core/code/engine/core/ingestion/languages/cpp/adl.js +804 -0
  202. package/dist/core/code/engine/core/ingestion/languages/cpp/arity-metadata.js +258 -0
  203. package/dist/core/code/engine/core/ingestion/languages/cpp/arity.js +37 -0
  204. package/dist/core/code/engine/core/ingestion/languages/cpp/capture-side-channel.js +89 -0
  205. package/dist/core/code/engine/core/ingestion/languages/cpp/captures.js +1975 -0
  206. package/dist/core/code/engine/core/ingestion/languages/cpp/constraint-extractor.js +311 -0
  207. package/dist/core/code/engine/core/ingestion/languages/cpp/constraint-filter.js +210 -0
  208. package/dist/core/code/engine/core/ingestion/languages/cpp/conversion-rank.js +163 -0
  209. package/dist/core/code/engine/core/ingestion/languages/cpp/file-local-linkage.js +327 -0
  210. package/dist/core/code/engine/core/ingestion/languages/cpp/header-scan.js +53 -0
  211. package/dist/core/code/engine/core/ingestion/languages/cpp/import-decomposer.js +134 -0
  212. package/dist/core/code/engine/core/ingestion/languages/cpp/import-target.js +16 -0
  213. package/dist/core/code/engine/core/ingestion/languages/cpp/index.js +33 -0
  214. package/dist/core/code/engine/core/ingestion/languages/cpp/inline-namespaces.js +379 -0
  215. package/dist/core/code/engine/core/ingestion/languages/cpp/interpret.js +239 -0
  216. package/dist/core/code/engine/core/ingestion/languages/cpp/member-lookup.js +470 -0
  217. package/dist/core/code/engine/core/ingestion/languages/cpp/merge-bindings.js +32 -0
  218. package/dist/core/code/engine/core/ingestion/languages/cpp/query.js +763 -0
  219. package/dist/core/code/engine/core/ingestion/languages/cpp/range-bindings.js +230 -0
  220. package/dist/core/code/engine/core/ingestion/languages/cpp/scope-resolver.js +354 -0
  221. package/dist/core/code/engine/core/ingestion/languages/cpp/simple-hooks.js +67 -0
  222. package/dist/core/code/engine/core/ingestion/languages/cpp/two-phase-lookup.js +348 -0
  223. package/dist/core/code/engine/core/ingestion/languages/cpp/type-classifier.js +56 -0
  224. package/dist/core/code/engine/core/ingestion/languages/cpp/user-defined-conversions.js +128 -0
  225. package/dist/core/code/engine/core/ingestion/languages/csharp/accessor-unwrap.js +67 -0
  226. package/dist/core/code/engine/core/ingestion/languages/csharp/arity-metadata.js +49 -0
  227. package/dist/core/code/engine/core/ingestion/languages/csharp/arity.js +40 -0
  228. package/dist/core/code/engine/core/ingestion/languages/csharp/cache-stats.js +32 -0
  229. package/dist/core/code/engine/core/ingestion/languages/csharp/captures.js +557 -0
  230. package/dist/core/code/engine/core/ingestion/languages/csharp/import-decomposer.js +96 -0
  231. package/dist/core/code/engine/core/ingestion/languages/csharp/import-target.js +176 -0
  232. package/dist/core/code/engine/core/ingestion/languages/csharp/index.js +95 -0
  233. package/dist/core/code/engine/core/ingestion/languages/csharp/interpret.js +150 -0
  234. package/dist/core/code/engine/core/ingestion/languages/csharp/merge-bindings.js +58 -0
  235. package/dist/core/code/engine/core/ingestion/languages/csharp/namespace-siblings.js +708 -0
  236. package/dist/core/code/engine/core/ingestion/languages/csharp/qualified-type-names.js +62 -0
  237. package/dist/core/code/engine/core/ingestion/languages/csharp/query.js +578 -0
  238. package/dist/core/code/engine/core/ingestion/languages/csharp/receiver-binding.js +142 -0
  239. package/dist/core/code/engine/core/ingestion/languages/csharp/resolution-config.js +18 -0
  240. package/dist/core/code/engine/core/ingestion/languages/csharp/scope-resolver.js +84 -0
  241. package/dist/core/code/engine/core/ingestion/languages/csharp/simple-hooks.js +81 -0
  242. package/dist/core/code/engine/core/ingestion/languages/csharp.js +204 -0
  243. package/dist/core/code/engine/core/ingestion/languages/dart/arity-metadata.js +38 -0
  244. package/dist/core/code/engine/core/ingestion/languages/dart/arity.js +34 -0
  245. package/dist/core/code/engine/core/ingestion/languages/dart/built-ins.js +37 -0
  246. package/dist/core/code/engine/core/ingestion/languages/dart/cache-stats.js +30 -0
  247. package/dist/core/code/engine/core/ingestion/languages/dart/captures.js +1096 -0
  248. package/dist/core/code/engine/core/ingestion/languages/dart/expand-wildcards.js +34 -0
  249. package/dist/core/code/engine/core/ingestion/languages/dart/extension-type-preprocess.js +33 -0
  250. package/dist/core/code/engine/core/ingestion/languages/dart/import-target.js +68 -0
  251. package/dist/core/code/engine/core/ingestion/languages/dart/index.js +45 -0
  252. package/dist/core/code/engine/core/ingestion/languages/dart/interpret.js +101 -0
  253. package/dist/core/code/engine/core/ingestion/languages/dart/merge-bindings.js +42 -0
  254. package/dist/core/code/engine/core/ingestion/languages/dart/query.js +246 -0
  255. package/dist/core/code/engine/core/ingestion/languages/dart/receiver-binding.js +90 -0
  256. package/dist/core/code/engine/core/ingestion/languages/dart/scope-resolver.js +197 -0
  257. package/dist/core/code/engine/core/ingestion/languages/dart/signature-bindings.js +54 -0
  258. package/dist/core/code/engine/core/ingestion/languages/dart/simple-hooks.js +61 -0
  259. package/dist/core/code/engine/core/ingestion/languages/dart.js +138 -0
  260. package/dist/core/code/engine/core/ingestion/languages/go/arity-metadata.js +71 -0
  261. package/dist/core/code/engine/core/ingestion/languages/go/arity.js +17 -0
  262. package/dist/core/code/engine/core/ingestion/languages/go/cache-stats.js +21 -0
  263. package/dist/core/code/engine/core/ingestion/languages/go/captures.js +492 -0
  264. package/dist/core/code/engine/core/ingestion/languages/go/expand-wildcards.js +97 -0
  265. package/dist/core/code/engine/core/ingestion/languages/go/generic-type-parameters.js +146 -0
  266. package/dist/core/code/engine/core/ingestion/languages/go/import-decomposer.js +47 -0
  267. package/dist/core/code/engine/core/ingestion/languages/go/import-target.js +70 -0
  268. package/dist/core/code/engine/core/ingestion/languages/go/index.js +39 -0
  269. package/dist/core/code/engine/core/ingestion/languages/go/interface-impls.js +955 -0
  270. package/dist/core/code/engine/core/ingestion/languages/go/interpret.js +177 -0
  271. package/dist/core/code/engine/core/ingestion/languages/go/merge-bindings.js +21 -0
  272. package/dist/core/code/engine/core/ingestion/languages/go/method-owners.js +131 -0
  273. package/dist/core/code/engine/core/ingestion/languages/go/namespace-mirror.js +56 -0
  274. package/dist/core/code/engine/core/ingestion/languages/go/package-clause.js +79 -0
  275. package/dist/core/code/engine/core/ingestion/languages/go/package-siblings.js +83 -0
  276. package/dist/core/code/engine/core/ingestion/languages/go/query.js +298 -0
  277. package/dist/core/code/engine/core/ingestion/languages/go/range-binding.js +127 -0
  278. package/dist/core/code/engine/core/ingestion/languages/go/receiver-binding.js +24 -0
  279. package/dist/core/code/engine/core/ingestion/languages/go/scope-resolver.js +75 -0
  280. package/dist/core/code/engine/core/ingestion/languages/go/simple-hooks.js +31 -0
  281. package/dist/core/code/engine/core/ingestion/languages/go/type-binding.js +279 -0
  282. package/dist/core/code/engine/core/ingestion/languages/go.js +160 -0
  283. package/dist/core/code/engine/core/ingestion/languages/index.js +66 -0
  284. package/dist/core/code/engine/core/ingestion/languages/java/analysis-features.js +16 -0
  285. package/dist/core/code/engine/core/ingestion/languages/java/arity-metadata.js +43 -0
  286. package/dist/core/code/engine/core/ingestion/languages/java/arity.js +27 -0
  287. package/dist/core/code/engine/core/ingestion/languages/java/cache-stats.js +32 -0
  288. package/dist/core/code/engine/core/ingestion/languages/java/capture-side-channel.js +123 -0
  289. package/dist/core/code/engine/core/ingestion/languages/java/captures.js +791 -0
  290. package/dist/core/code/engine/core/ingestion/languages/java/import-decomposer.js +88 -0
  291. package/dist/core/code/engine/core/ingestion/languages/java/import-target.js +103 -0
  292. package/dist/core/code/engine/core/ingestion/languages/java/index.js +43 -0
  293. package/dist/core/code/engine/core/ingestion/languages/java/interpret.js +146 -0
  294. package/dist/core/code/engine/core/ingestion/languages/java/merge-bindings.js +43 -0
  295. package/dist/core/code/engine/core/ingestion/languages/java/package-facts.js +16 -0
  296. package/dist/core/code/engine/core/ingestion/languages/java/package-siblings.js +11 -0
  297. package/dist/core/code/engine/core/ingestion/languages/java/query.js +319 -0
  298. package/dist/core/code/engine/core/ingestion/languages/java/receiver-binding.js +98 -0
  299. package/dist/core/code/engine/core/ingestion/languages/java/scope-resolver.js +213 -0
  300. package/dist/core/code/engine/core/ingestion/languages/java/simple-hooks.js +39 -0
  301. package/dist/core/code/engine/core/ingestion/languages/java/spring-aop.js +53 -0
  302. package/dist/core/code/engine/core/ingestion/languages/java/spring-bean-metadata.js +11 -0
  303. package/dist/core/code/engine/core/ingestion/languages/java/spring-conditionals.js +52 -0
  304. package/dist/core/code/engine/core/ingestion/languages/java/spring-config-bindings.js +222 -0
  305. package/dist/core/code/engine/core/ingestion/languages/java/spring-di.js +165 -0
  306. package/dist/core/code/engine/core/ingestion/languages/java.js +192 -0
  307. package/dist/core/code/engine/core/ingestion/languages/javascript/arity.js +15 -0
  308. package/dist/core/code/engine/core/ingestion/languages/javascript/captures.js +1122 -0
  309. package/dist/core/code/engine/core/ingestion/languages/javascript/import-target.js +56 -0
  310. package/dist/core/code/engine/core/ingestion/languages/javascript/index.js +109 -0
  311. package/dist/core/code/engine/core/ingestion/languages/javascript/interpret.js +45 -0
  312. package/dist/core/code/engine/core/ingestion/languages/javascript/merge-bindings.js +21 -0
  313. package/dist/core/code/engine/core/ingestion/languages/javascript/query.js +659 -0
  314. package/dist/core/code/engine/core/ingestion/languages/javascript/scope-resolver.js +78 -0
  315. package/dist/core/code/engine/core/ingestion/languages/javascript/simple-hooks.js +44 -0
  316. package/dist/core/code/engine/core/ingestion/languages/jvm/package-facts.js +46 -0
  317. package/dist/core/code/engine/core/ingestion/languages/jvm/package-siblings.js +200 -0
  318. package/dist/core/code/engine/core/ingestion/languages/kotlin/arity-metadata.js +23 -0
  319. package/dist/core/code/engine/core/ingestion/languages/kotlin/arity.js +18 -0
  320. package/dist/core/code/engine/core/ingestion/languages/kotlin/cache-stats.js +21 -0
  321. package/dist/core/code/engine/core/ingestion/languages/kotlin/capture-side-channel.js +160 -0
  322. package/dist/core/code/engine/core/ingestion/languages/kotlin/captures.js +1262 -0
  323. package/dist/core/code/engine/core/ingestion/languages/kotlin/companion-scopes.js +72 -0
  324. package/dist/core/code/engine/core/ingestion/languages/kotlin/import-decomposer.js +40 -0
  325. package/dist/core/code/engine/core/ingestion/languages/kotlin/import-target.js +135 -0
  326. package/dist/core/code/engine/core/ingestion/languages/kotlin/index.js +26 -0
  327. package/dist/core/code/engine/core/ingestion/languages/kotlin/interpret.js +75 -0
  328. package/dist/core/code/engine/core/ingestion/languages/kotlin/merge-bindings.js +28 -0
  329. package/dist/core/code/engine/core/ingestion/languages/kotlin/owners.js +134 -0
  330. package/dist/core/code/engine/core/ingestion/languages/kotlin/package-facts.js +16 -0
  331. package/dist/core/code/engine/core/ingestion/languages/kotlin/package-siblings.js +11 -0
  332. package/dist/core/code/engine/core/ingestion/languages/kotlin/query.js +243 -0
  333. package/dist/core/code/engine/core/ingestion/languages/kotlin/receiver-binding.js +103 -0
  334. package/dist/core/code/engine/core/ingestion/languages/kotlin/scope-resolver.js +207 -0
  335. package/dist/core/code/engine/core/ingestion/languages/kotlin/simple-hooks.js +42 -0
  336. package/dist/core/code/engine/core/ingestion/languages/kotlin/spring-aop.js +68 -0
  337. package/dist/core/code/engine/core/ingestion/languages/kotlin/spring-bean-metadata.js +11 -0
  338. package/dist/core/code/engine/core/ingestion/languages/kotlin/spring-conditionals.js +53 -0
  339. package/dist/core/code/engine/core/ingestion/languages/kotlin/spring-di.js +304 -0
  340. package/dist/core/code/engine/core/ingestion/languages/kotlin.js +189 -0
  341. package/dist/core/code/engine/core/ingestion/languages/php/arity-metadata.js +66 -0
  342. package/dist/core/code/engine/core/ingestion/languages/php/arity.js +43 -0
  343. package/dist/core/code/engine/core/ingestion/languages/php/cache-stats.js +32 -0
  344. package/dist/core/code/engine/core/ingestion/languages/php/captures.js +1166 -0
  345. package/dist/core/code/engine/core/ingestion/languages/php/import-decomposer.js +238 -0
  346. package/dist/core/code/engine/core/ingestion/languages/php/import-target.js +213 -0
  347. package/dist/core/code/engine/core/ingestion/languages/php/index.js +85 -0
  348. package/dist/core/code/engine/core/ingestion/languages/php/interpret.js +256 -0
  349. package/dist/core/code/engine/core/ingestion/languages/php/merge-bindings.js +50 -0
  350. package/dist/core/code/engine/core/ingestion/languages/php/namespace-siblings.js +353 -0
  351. package/dist/core/code/engine/core/ingestion/languages/php/query.js +391 -0
  352. package/dist/core/code/engine/core/ingestion/languages/php/receiver-binding.js +135 -0
  353. package/dist/core/code/engine/core/ingestion/languages/php/scope-resolver.js +361 -0
  354. package/dist/core/code/engine/core/ingestion/languages/php/simple-hooks.js +116 -0
  355. package/dist/core/code/engine/core/ingestion/languages/php.js +302 -0
  356. package/dist/core/code/engine/core/ingestion/languages/python/arity-metadata.js +49 -0
  357. package/dist/core/code/engine/core/ingestion/languages/python/arity.js +41 -0
  358. package/dist/core/code/engine/core/ingestion/languages/python/cache-stats.js +34 -0
  359. package/dist/core/code/engine/core/ingestion/languages/python/captures.js +299 -0
  360. package/dist/core/code/engine/core/ingestion/languages/python/depends-references.js +68 -0
  361. package/dist/core/code/engine/core/ingestion/languages/python/import-decomposer.js +115 -0
  362. package/dist/core/code/engine/core/ingestion/languages/python/import-target.js +440 -0
  363. package/dist/core/code/engine/core/ingestion/languages/python/index-stats.js +30 -0
  364. package/dist/core/code/engine/core/ingestion/languages/python/index.js +96 -0
  365. package/dist/core/code/engine/core/ingestion/languages/python/interpret.js +430 -0
  366. package/dist/core/code/engine/core/ingestion/languages/python/merge-bindings.js +47 -0
  367. package/dist/core/code/engine/core/ingestion/languages/python/query.js +323 -0
  368. package/dist/core/code/engine/core/ingestion/languages/python/receiver-binding.js +310 -0
  369. package/dist/core/code/engine/core/ingestion/languages/python/scope-resolver.js +80 -0
  370. package/dist/core/code/engine/core/ingestion/languages/python/simple-hooks.js +53 -0
  371. package/dist/core/code/engine/core/ingestion/languages/python.js +140 -0
  372. package/dist/core/code/engine/core/ingestion/languages/ruby/arity.js +41 -0
  373. package/dist/core/code/engine/core/ingestion/languages/ruby/cache-stats.js +21 -0
  374. package/dist/core/code/engine/core/ingestion/languages/ruby/captures.js +864 -0
  375. package/dist/core/code/engine/core/ingestion/languages/ruby/import-target.js +88 -0
  376. package/dist/core/code/engine/core/ingestion/languages/ruby/index.js +29 -0
  377. package/dist/core/code/engine/core/ingestion/languages/ruby/interpret.js +115 -0
  378. package/dist/core/code/engine/core/ingestion/languages/ruby/merge-bindings.js +21 -0
  379. package/dist/core/code/engine/core/ingestion/languages/ruby/query.js +349 -0
  380. package/dist/core/code/engine/core/ingestion/languages/ruby/receiver-binding.js +70 -0
  381. package/dist/core/code/engine/core/ingestion/languages/ruby/scope-resolver.js +263 -0
  382. package/dist/core/code/engine/core/ingestion/languages/ruby/simple-hooks.js +68 -0
  383. package/dist/core/code/engine/core/ingestion/languages/ruby.js +215 -0
  384. package/dist/core/code/engine/core/ingestion/languages/rust/arity.js +16 -0
  385. package/dist/core/code/engine/core/ingestion/languages/rust/cache-stats.js +21 -0
  386. package/dist/core/code/engine/core/ingestion/languages/rust/captures.js +304 -0
  387. package/dist/core/code/engine/core/ingestion/languages/rust/import-decomposer.js +167 -0
  388. package/dist/core/code/engine/core/ingestion/languages/rust/import-target.js +108 -0
  389. package/dist/core/code/engine/core/ingestion/languages/rust/index.js +29 -0
  390. package/dist/core/code/engine/core/ingestion/languages/rust/interpret.js +201 -0
  391. package/dist/core/code/engine/core/ingestion/languages/rust/merge-bindings.js +21 -0
  392. package/dist/core/code/engine/core/ingestion/languages/rust/method-owners.js +76 -0
  393. package/dist/core/code/engine/core/ingestion/languages/rust/module-path.js +222 -0
  394. package/dist/core/code/engine/core/ingestion/languages/rust/qualified-call.js +482 -0
  395. package/dist/core/code/engine/core/ingestion/languages/rust/query.js +280 -0
  396. package/dist/core/code/engine/core/ingestion/languages/rust/range-binding.js +687 -0
  397. package/dist/core/code/engine/core/ingestion/languages/rust/receiver-binding.js +148 -0
  398. package/dist/core/code/engine/core/ingestion/languages/rust/scope-resolver.js +151 -0
  399. package/dist/core/code/engine/core/ingestion/languages/rust/simple-hooks.js +32 -0
  400. package/dist/core/code/engine/core/ingestion/languages/rust.js +183 -0
  401. package/dist/core/code/engine/core/ingestion/languages/swift/arity-metadata.js +44 -0
  402. package/dist/core/code/engine/core/ingestion/languages/swift/arity.js +45 -0
  403. package/dist/core/code/engine/core/ingestion/languages/swift/base-type.js +30 -0
  404. package/dist/core/code/engine/core/ingestion/languages/swift/cache-stats.js +32 -0
  405. package/dist/core/code/engine/core/ingestion/languages/swift/captures.js +594 -0
  406. package/dist/core/code/engine/core/ingestion/languages/swift/conditional-directive-preprocess.js +256 -0
  407. package/dist/core/code/engine/core/ingestion/languages/swift/implicit-imports.js +60 -0
  408. package/dist/core/code/engine/core/ingestion/languages/swift/import-decomposer.js +87 -0
  409. package/dist/core/code/engine/core/ingestion/languages/swift/import-target.js +84 -0
  410. package/dist/core/code/engine/core/ingestion/languages/swift/index.js +56 -0
  411. package/dist/core/code/engine/core/ingestion/languages/swift/interpret.js +93 -0
  412. package/dist/core/code/engine/core/ingestion/languages/swift/merge-bindings.js +51 -0
  413. package/dist/core/code/engine/core/ingestion/languages/swift/query.js +226 -0
  414. package/dist/core/code/engine/core/ingestion/languages/swift/receiver-binding.js +169 -0
  415. package/dist/core/code/engine/core/ingestion/languages/swift/scope-resolver.js +192 -0
  416. package/dist/core/code/engine/core/ingestion/languages/swift/sibling-type-bindings.js +68 -0
  417. package/dist/core/code/engine/core/ingestion/languages/swift/signature-bindings.js +69 -0
  418. package/dist/core/code/engine/core/ingestion/languages/swift/simple-hooks.js +65 -0
  419. package/dist/core/code/engine/core/ingestion/languages/swift/target-grouping.js +97 -0
  420. package/dist/core/code/engine/core/ingestion/languages/swift/target-siblings.js +74 -0
  421. package/dist/core/code/engine/core/ingestion/languages/swift.js +246 -0
  422. package/dist/core/code/engine/core/ingestion/languages/typescript/arity-metadata.js +106 -0
  423. package/dist/core/code/engine/core/ingestion/languages/typescript/arity.js +57 -0
  424. package/dist/core/code/engine/core/ingestion/languages/typescript/array-callback.js +58 -0
  425. package/dist/core/code/engine/core/ingestion/languages/typescript/cache-stats.js +34 -0
  426. package/dist/core/code/engine/core/ingestion/languages/typescript/captures.js +956 -0
  427. package/dist/core/code/engine/core/ingestion/languages/typescript/cjs-export-assignment.js +535 -0
  428. package/dist/core/code/engine/core/ingestion/languages/typescript/cjs-module-exports.js +196 -0
  429. package/dist/core/code/engine/core/ingestion/languages/typescript/import-decomposer.js +374 -0
  430. package/dist/core/code/engine/core/ingestion/languages/typescript/import-target.js +65 -0
  431. package/dist/core/code/engine/core/ingestion/languages/typescript/index.js +108 -0
  432. package/dist/core/code/engine/core/ingestion/languages/typescript/interpret.js +344 -0
  433. package/dist/core/code/engine/core/ingestion/languages/typescript/merge-bindings.js +161 -0
  434. package/dist/core/code/engine/core/ingestion/languages/typescript/nuxt-auto-imports.js +325 -0
  435. package/dist/core/code/engine/core/ingestion/languages/typescript/query.js +1328 -0
  436. package/dist/core/code/engine/core/ingestion/languages/typescript/receiver-binding.js +201 -0
  437. package/dist/core/code/engine/core/ingestion/languages/typescript/scope-resolver.js +293 -0
  438. package/dist/core/code/engine/core/ingestion/languages/typescript/simple-hooks.js +139 -0
  439. package/dist/core/code/engine/core/ingestion/languages/typescript.js +455 -0
  440. package/dist/core/code/engine/core/ingestion/languages/vue/captures.js +70 -0
  441. package/dist/core/code/engine/core/ingestion/languages/vue/import-target.js +61 -0
  442. package/dist/core/code/engine/core/ingestion/languages/vue/index.js +55 -0
  443. package/dist/core/code/engine/core/ingestion/languages/vue/scope-resolver.js +295 -0
  444. package/dist/core/code/engine/core/ingestion/languages/vue.js +96 -0
  445. package/dist/core/code/engine/core/ingestion/local-symbol-pruner.js +68 -0
  446. package/dist/core/code/engine/core/ingestion/method-extractors/configs/c-cpp.js +387 -0
  447. package/dist/core/code/engine/core/ingestion/method-extractors/configs/csharp.js +290 -0
  448. package/dist/core/code/engine/core/ingestion/method-extractors/configs/dart.js +392 -0
  449. package/dist/core/code/engine/core/ingestion/method-extractors/configs/go.js +179 -0
  450. package/dist/core/code/engine/core/ingestion/method-extractors/configs/jvm.js +350 -0
  451. package/dist/core/code/engine/core/ingestion/method-extractors/configs/php.js +306 -0
  452. package/dist/core/code/engine/core/ingestion/method-extractors/configs/python.js +312 -0
  453. package/dist/core/code/engine/core/ingestion/method-extractors/configs/ruby.js +289 -0
  454. package/dist/core/code/engine/core/ingestion/method-extractors/configs/rust.js +198 -0
  455. package/dist/core/code/engine/core/ingestion/method-extractors/configs/swift.js +286 -0
  456. package/dist/core/code/engine/core/ingestion/method-extractors/configs/typescript-javascript.js +341 -0
  457. package/dist/core/code/engine/core/ingestion/method-extractors/generic.js +209 -0
  458. package/dist/core/code/engine/core/ingestion/method-types.js +3 -0
  459. package/dist/core/code/engine/core/ingestion/model/field-registry.js +41 -0
  460. package/dist/core/code/engine/core/ingestion/model/index.js +52 -0
  461. package/dist/core/code/engine/core/ingestion/model/method-registry.js +138 -0
  462. package/dist/core/code/engine/core/ingestion/model/owned-members-lookup.js +46 -0
  463. package/dist/core/code/engine/core/ingestion/model/registration-table.js +234 -0
  464. package/dist/core/code/engine/core/ingestion/model/resolve.js +183 -0
  465. package/dist/core/code/engine/core/ingestion/model/scope-resolution-indexes.js +43 -0
  466. package/dist/core/code/engine/core/ingestion/model/semantic-model.js +179 -0
  467. package/dist/core/code/engine/core/ingestion/model/symbol-table.js +216 -0
  468. package/dist/core/code/engine/core/ingestion/model/type-registry.js +84 -0
  469. package/dist/core/code/engine/core/ingestion/mro-processor.js +709 -0
  470. package/dist/core/code/engine/core/ingestion/parsing-processor.js +312 -0
  471. package/dist/core/code/engine/core/ingestion/pipeline-phases/communities.js +69 -0
  472. package/dist/core/code/engine/core/ingestion/pipeline-phases/cross-file.js +71 -0
  473. package/dist/core/code/engine/core/ingestion/pipeline-phases/di.js +338 -0
  474. package/dist/core/code/engine/core/ingestion/pipeline-phases/http-api-calls.js +312 -0
  475. package/dist/core/code/engine/core/ingestion/pipeline-phases/index.js +54 -0
  476. package/dist/core/code/engine/core/ingestion/pipeline-phases/mro.js +40 -0
  477. package/dist/core/code/engine/core/ingestion/pipeline-phases/orm.js +78 -0
  478. package/dist/core/code/engine/core/ingestion/pipeline-phases/parse-impl.js +1286 -0
  479. package/dist/core/code/engine/core/ingestion/pipeline-phases/parse.js +41 -0
  480. package/dist/core/code/engine/core/ingestion/pipeline-phases/processes.js +193 -0
  481. package/dist/core/code/engine/core/ingestion/pipeline-phases/prune-local-symbols.js +29 -0
  482. package/dist/core/code/engine/core/ingestion/pipeline-phases/registry.js +52 -0
  483. package/dist/core/code/engine/core/ingestion/pipeline-phases/routes.js +409 -0
  484. package/dist/core/code/engine/core/ingestion/pipeline-phases/rpc-edges.js +301 -0
  485. package/dist/core/code/engine/core/ingestion/pipeline-phases/runner.js +207 -0
  486. package/dist/core/code/engine/core/ingestion/pipeline-phases/scan.js +49 -0
  487. package/dist/core/code/engine/core/ingestion/pipeline-phases/spring-aop.js +442 -0
  488. package/dist/core/code/engine/core/ingestion/pipeline-phases/spring-auto-configuration.js +264 -0
  489. package/dist/core/code/engine/core/ingestion/pipeline-phases/spring-config.js +440 -0
  490. package/dist/core/code/engine/core/ingestion/pipeline-phases/structure.js +38 -0
  491. package/dist/core/code/engine/core/ingestion/pipeline-phases/tools.js +89 -0
  492. package/dist/core/code/engine/core/ingestion/pipeline-phases/types.js +40 -0
  493. package/dist/core/code/engine/core/ingestion/pipeline.js +152 -0
  494. package/dist/core/code/engine/core/ingestion/process-processor.js +325 -0
  495. package/dist/core/code/engine/core/ingestion/resolve-references.js +205 -0
  496. package/dist/core/code/engine/core/ingestion/route-extractors/constant-resolver.js +135 -0
  497. package/dist/core/code/engine/core/ingestion/route-extractors/django-root-discovery.js +221 -0
  498. package/dist/core/code/engine/core/ingestion/route-extractors/django.js +428 -0
  499. package/dist/core/code/engine/core/ingestion/route-extractors/expo.js +39 -0
  500. package/dist/core/code/engine/core/ingestion/route-extractors/fastapi-router-bindings.js +264 -0
  501. package/dist/core/code/engine/core/ingestion/route-extractors/laravel.js +501 -0
  502. package/dist/core/code/engine/core/ingestion/route-extractors/middleware.js +175 -0
  503. package/dist/core/code/engine/core/ingestion/route-extractors/nextjs.js +81 -0
  504. package/dist/core/code/engine/core/ingestion/route-extractors/php.js +25 -0
  505. package/dist/core/code/engine/core/ingestion/route-extractors/python-const-resolver.js +307 -0
  506. package/dist/core/code/engine/core/ingestion/route-extractors/response-shapes.js +299 -0
  507. package/dist/core/code/engine/core/ingestion/route-extractors/route-path.js +71 -0
  508. package/dist/core/code/engine/core/ingestion/route-extractors/spring-shared.js +310 -0
  509. package/dist/core/code/engine/core/ingestion/route-extractors/spring.js +441 -0
  510. package/dist/core/code/engine/core/ingestion/scope-extractor-bridge.js +60 -0
  511. package/dist/core/code/engine/core/ingestion/scope-extractor.js +1373 -0
  512. package/dist/core/code/engine/core/ingestion/scope-resolution/contract/scope-resolver.js +282 -0
  513. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +72 -0
  514. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/edges.js +194 -0
  515. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/ids.js +472 -0
  516. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.js +49 -0
  517. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/method-dispatch.js +43 -0
  518. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +274 -0
  519. package/dist/core/code/engine/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +93 -0
  520. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/callable-value-flow.js +1240 -0
  521. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/compound-receiver.js +1174 -0
  522. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/free-call-fallback.js +873 -0
  523. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/imported-return-types.js +226 -0
  524. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/mro.js +107 -0
  525. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/overload-narrowing.js +441 -0
  526. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/property-dispatch.js +122 -0
  527. package/dist/core/code/engine/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +1720 -0
  528. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/phase.js +395 -0
  529. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +208 -0
  530. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/registry.js +49 -0
  531. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/run.js +632 -0
  532. package/dist/core/code/engine/core/ingestion/scope-resolution/pipeline/validate-bindings-immutability.js +112 -0
  533. package/dist/core/code/engine/core/ingestion/scope-resolution/resolution-outcome.js +41 -0
  534. package/dist/core/code/engine/core/ingestion/scope-resolution/scope/namespace-targets.js +81 -0
  535. package/dist/core/code/engine/core/ingestion/scope-resolution/scope/walkers.js +1835 -0
  536. package/dist/core/code/engine/core/ingestion/scope-resolution/unresolved-receivers.js +242 -0
  537. package/dist/core/code/engine/core/ingestion/scope-resolution/utils/definition-id.js +22 -0
  538. package/dist/core/code/engine/core/ingestion/scope-resolution/workspace-index.js +151 -0
  539. package/dist/core/code/engine/core/ingestion/structure-processor.js +40 -0
  540. package/dist/core/code/engine/core/ingestion/tree-sitter-queries.js +2244 -0
  541. package/dist/core/code/engine/core/ingestion/ts-js-hoc-utils.js +115 -0
  542. package/dist/core/code/engine/core/ingestion/type-env.js +1136 -0
  543. package/dist/core/code/engine/core/ingestion/type-extractors/c-cpp.js +555 -0
  544. package/dist/core/code/engine/core/ingestion/type-extractors/csharp.js +570 -0
  545. package/dist/core/code/engine/core/ingestion/type-extractors/dart.js +372 -0
  546. package/dist/core/code/engine/core/ingestion/type-extractors/go.js +508 -0
  547. package/dist/core/code/engine/core/ingestion/type-extractors/jvm.js +875 -0
  548. package/dist/core/code/engine/core/ingestion/type-extractors/php.js +537 -0
  549. package/dist/core/code/engine/core/ingestion/type-extractors/python.js +477 -0
  550. package/dist/core/code/engine/core/ingestion/type-extractors/ruby.js +380 -0
  551. package/dist/core/code/engine/core/ingestion/type-extractors/rust.js +502 -0
  552. package/dist/core/code/engine/core/ingestion/type-extractors/shared.js +843 -0
  553. package/dist/core/code/engine/core/ingestion/type-extractors/swift.js +490 -0
  554. package/dist/core/code/engine/core/ingestion/type-extractors/types.js +2 -0
  555. package/dist/core/code/engine/core/ingestion/type-extractors/typescript.js +690 -0
  556. package/dist/core/code/engine/core/ingestion/utils/ast-helpers.js +1693 -0
  557. package/dist/core/code/engine/core/ingestion/utils/call-analysis.js +779 -0
  558. package/dist/core/code/engine/core/ingestion/utils/callable-flow-captures.js +932 -0
  559. package/dist/core/code/engine/core/ingestion/utils/callable-labels.js +49 -0
  560. package/dist/core/code/engine/core/ingestion/utils/deferred-resolution-profile.js +151 -0
  561. package/dist/core/code/engine/core/ingestion/utils/effective-ram.js +67 -0
  562. package/dist/core/code/engine/core/ingestion/utils/env.js +60 -0
  563. package/dist/core/code/engine/core/ingestion/utils/event-loop.js +9 -0
  564. package/dist/core/code/engine/core/ingestion/utils/graph-sort.js +103 -0
  565. package/dist/core/code/engine/core/ingestion/utils/heap-probe.js +45 -0
  566. package/dist/core/code/engine/core/ingestion/utils/heritage-marker.js +47 -0
  567. package/dist/core/code/engine/core/ingestion/utils/line-base.js +24 -0
  568. package/dist/core/code/engine/core/ingestion/utils/max-file-size.js +59 -0
  569. package/dist/core/code/engine/core/ingestion/utils/method-props.js +198 -0
  570. package/dist/core/code/engine/core/ingestion/utils/qualified-name.js +73 -0
  571. package/dist/core/code/engine/core/ingestion/utils/receiver-chain-captures.js +60 -0
  572. package/dist/core/code/engine/core/ingestion/utils/receiver-chain-codec.js +188 -0
  573. package/dist/core/code/engine/core/ingestion/utils/scope-tree-walk.js +36 -0
  574. package/dist/core/code/engine/core/ingestion/utils/symbol-labels.js +48 -0
  575. package/dist/core/code/engine/core/ingestion/utils/template-arguments.js +187 -0
  576. package/dist/core/code/engine/core/ingestion/utils/type-parameters.js +209 -0
  577. package/dist/core/code/engine/core/ingestion/utils/verbose.js +6 -0
  578. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/c-cpp.js +133 -0
  579. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/csharp.js +66 -0
  580. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/dart.js +111 -0
  581. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/go.js +153 -0
  582. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/jvm.js +145 -0
  583. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/php.js +61 -0
  584. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/python.js +104 -0
  585. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/ruby.js +55 -0
  586. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/rust.js +79 -0
  587. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/swift.js +91 -0
  588. package/dist/core/code/engine/core/ingestion/variable-extractors/configs/typescript-javascript.js +86 -0
  589. package/dist/core/code/engine/core/ingestion/variable-extractors/generic.js +111 -0
  590. package/dist/core/code/engine/core/ingestion/variable-types.js +3 -0
  591. package/dist/core/code/engine/core/ingestion/vue-sfc-extractor.js +544 -0
  592. package/dist/core/code/engine/core/ingestion/workers/callable-id.js +122 -0
  593. package/dist/core/code/engine/core/ingestion/workers/clone-safety.js +470 -0
  594. package/dist/core/code/engine/core/ingestion/workers/parse-worker.js +2456 -0
  595. package/dist/core/code/engine/core/ingestion/workers/post-result.js +90 -0
  596. package/dist/core/code/engine/core/ingestion/workers/quarantine.js +41 -0
  597. package/dist/core/code/engine/core/ingestion/workers/result-merge.js +59 -0
  598. package/dist/core/code/engine/core/ingestion/workers/worker-pool.js +1725 -0
  599. package/dist/core/code/engine/core/ingestion/workspace-config.js +139 -0
  600. package/dist/core/code/engine/core/lbug/conn-lock.js +72 -0
  601. package/dist/core/code/engine/core/lbug/csv-generator.js +710 -0
  602. package/dist/core/code/engine/core/lbug/cypher-escape.js +24 -0
  603. package/dist/core/code/engine/core/lbug/extension-load-error.js +339 -0
  604. package/dist/core/code/engine/core/lbug/extension-loader.js +261 -0
  605. package/dist/core/code/engine/core/lbug/graph-emit-sink.js +584 -0
  606. package/dist/core/code/engine/core/lbug/lbug-adapter.js +2703 -0
  607. package/dist/core/code/engine/core/lbug/lbug-config.js +1029 -0
  608. package/dist/core/code/engine/core/lbug/native-check.js +435 -0
  609. package/dist/core/code/engine/core/lbug/pool-adapter.js +973 -0
  610. package/dist/core/code/engine/core/lbug/query-params.js +25 -0
  611. package/dist/core/code/engine/core/lbug/query-result-utils.js +31 -0
  612. package/dist/core/code/engine/core/lbug/rel-pair-routing.js +373 -0
  613. package/dist/core/code/engine/core/lbug/schema.js +771 -0
  614. package/dist/core/code/engine/core/lbug/shutdown-helpers.js +40 -0
  615. package/dist/core/code/engine/core/lbug/sidecar-recovery.js +716 -0
  616. package/dist/core/code/engine/core/lbug/stdio-capture.js +49 -0
  617. package/dist/core/code/engine/core/lbug/sync-csv-writer.js +115 -0
  618. package/dist/core/code/engine/core/lbug/wal-checkpoint-driver.js +215 -0
  619. package/dist/core/code/engine/core/lbug/wal-driver-state.js +28 -0
  620. package/dist/core/code/engine/core/logger.js +339 -0
  621. package/dist/core/code/engine/core/platform/capabilities.js +91 -0
  622. package/dist/core/code/engine/core/run-analyze.js +1098 -0
  623. package/dist/core/code/engine/core/tree-sitter/parser-loader.js +281 -0
  624. package/dist/core/code/engine/core/tree-sitter/safe-parse.js +258 -0
  625. package/dist/core/code/engine/core/tree-sitter/vendored-grammars.js +64 -0
  626. package/dist/core/code/engine/lib/utils.js +121 -0
  627. package/dist/core/code/engine/mcp/core/lbug-adapter.js +27 -0
  628. package/dist/core/code/engine/mcp/local/aop-metadata.js +230 -0
  629. package/dist/core/code/engine/mcp/local/bean-metadata.js +49 -0
  630. package/dist/core/code/engine/mcp/local/limits.js +15 -0
  631. package/dist/core/code/engine/mcp/local/line-display.js +6 -0
  632. package/dist/core/code/engine/mcp/local/local-backend.js +4142 -0
  633. package/dist/core/code/engine/storage/branch-index.js +72 -0
  634. package/dist/core/code/engine/storage/file-hash.js +95 -0
  635. package/dist/core/code/engine/storage/fs-atomic.js +34 -0
  636. package/dist/core/code/engine/storage/git.js +555 -0
  637. package/dist/core/code/engine/storage/index-lock.js +664 -0
  638. package/dist/core/code/engine/storage/parse-cache.js +650 -0
  639. package/dist/core/code/engine/storage/parsedfile-store.js +620 -0
  640. package/dist/core/code/engine/storage/repo-manager.js +1061 -0
  641. package/dist/core/code/engine/storage/scope-index-store.js +247 -0
  642. package/dist/core/code/engine/types/pipeline.js +2 -0
  643. package/dist/core/code/scripts/install-duckdb-extension.mjs +125 -0
  644. package/dist/core/code/scripts/resolve-analyze-cmd.cjs +346 -0
  645. package/dist/core/code/shared/graph/types.js +8 -0
  646. package/dist/core/code/shared/index.js +105 -0
  647. package/dist/core/code/shared/integrations/circuit-breaker.js +242 -0
  648. package/dist/core/code/shared/integrations/resilient-fetch.js +224 -0
  649. package/dist/core/code/shared/integrations/retry.js +70 -0
  650. package/dist/core/code/shared/integrations/understand-quickly.js +145 -0
  651. package/dist/core/code/shared/language-detection.js +162 -0
  652. package/dist/core/code/shared/languages.js +27 -0
  653. package/dist/core/code/shared/lbug/schema-constants.js +98 -0
  654. package/dist/core/code/shared/mro-strategy.js +2 -0
  655. package/dist/core/code/shared/pipeline.js +5 -0
  656. package/dist/core/code/shared/scope-resolution/callable-flow-site.js +11 -0
  657. package/dist/core/code/shared/scope-resolution/def-index.js +53 -0
  658. package/dist/core/code/shared/scope-resolution/evidence-weights.js +87 -0
  659. package/dist/core/code/shared/scope-resolution/finalize-algorithm.js +807 -0
  660. package/dist/core/code/shared/scope-resolution/language-classification.js +46 -0
  661. package/dist/core/code/shared/scope-resolution/method-dispatch-index.js +100 -0
  662. package/dist/core/code/shared/scope-resolution/module-scope-index.js +59 -0
  663. package/dist/core/code/shared/scope-resolution/origin-priority.js +23 -0
  664. package/dist/core/code/shared/scope-resolution/parsed-file.js +54 -0
  665. package/dist/core/code/shared/scope-resolution/position-index.js +136 -0
  666. package/dist/core/code/shared/scope-resolution/qualified-name-index.js +77 -0
  667. package/dist/core/code/shared/scope-resolution/reference-site.js +24 -0
  668. package/dist/core/code/shared/scope-resolution/registries/class-registry.js +32 -0
  669. package/dist/core/code/shared/scope-resolution/registries/context.js +52 -0
  670. package/dist/core/code/shared/scope-resolution/registries/evidence.js +152 -0
  671. package/dist/core/code/shared/scope-resolution/registries/field-registry.js +33 -0
  672. package/dist/core/code/shared/scope-resolution/registries/lookup-core.js +392 -0
  673. package/dist/core/code/shared/scope-resolution/registries/lookup-qualified.js +58 -0
  674. package/dist/core/code/shared/scope-resolution/registries/macro-registry.js +34 -0
  675. package/dist/core/code/shared/scope-resolution/registries/method-registry.js +34 -0
  676. package/dist/core/code/shared/scope-resolution/registries/tie-breaks.js +63 -0
  677. package/dist/core/code/shared/scope-resolution/resolve-type-ref.js +128 -0
  678. package/dist/core/code/shared/scope-resolution/scope-id.js +49 -0
  679. package/dist/core/code/shared/scope-resolution/scope-tree.js +225 -0
  680. package/dist/core/code/shared/scope-resolution/symbol-definition.js +12 -0
  681. package/dist/core/code/shared/scope-resolution/types.js +25 -0
  682. package/dist/core/code/shared/test-helpers.js +17 -0
  683. package/dist/core/code/vendor/leiden/index.cjs +355 -0
  684. package/dist/core/code/vendor/leiden/utils.cjs +419 -0
  685. package/dist/core/dbquery/cli.d.ts.map +1 -1
  686. package/dist/core/dbquery/cli.js +5 -4
  687. package/dist/core/dbquery/cli.js.map +1 -1
  688. package/dist/core/dbquery/config.d.ts.map +1 -1
  689. package/dist/core/dbquery/config.js +39 -3
  690. package/dist/core/dbquery/config.js.map +1 -1
  691. package/dist/core/dbquery/drivers/http.d.ts +23 -0
  692. package/dist/core/dbquery/drivers/http.d.ts.map +1 -0
  693. package/dist/core/dbquery/drivers/http.js +125 -0
  694. package/dist/core/dbquery/drivers/http.js.map +1 -0
  695. package/dist/core/dbquery/drivers/mysql.js +1 -1
  696. package/dist/core/dbquery/drivers/mysql.js.map +1 -1
  697. package/dist/core/dbquery/drivers/postgres.js +1 -1
  698. package/dist/core/dbquery/drivers/postgres.js.map +1 -1
  699. package/dist/core/dbquery/executor.d.ts.map +1 -1
  700. package/dist/core/dbquery/executor.js +46 -12
  701. package/dist/core/dbquery/executor.js.map +1 -1
  702. package/dist/core/dbquery/format.d.ts.map +1 -1
  703. package/dist/core/dbquery/format.js +2 -1
  704. package/dist/core/dbquery/format.js.map +1 -1
  705. package/dist/core/dbquery/init.d.ts.map +1 -1
  706. package/dist/core/dbquery/init.js +7 -0
  707. package/dist/core/dbquery/init.js.map +1 -1
  708. package/dist/core/dbquery/types.d.ts +55 -7
  709. package/dist/core/dbquery/types.d.ts.map +1 -1
  710. package/dist/core/directory.d.ts +17 -0
  711. package/dist/core/directory.d.ts.map +1 -1
  712. package/dist/core/directory.js +37 -0
  713. package/dist/core/directory.js.map +1 -1
  714. package/dist/core/features/cli.d.ts.map +1 -1
  715. package/dist/core/features/cli.js +3 -2
  716. package/dist/core/features/cli.js.map +1 -1
  717. package/dist/core/features/scanner.d.ts +1 -1
  718. package/dist/core/features/scanner.d.ts.map +1 -1
  719. package/dist/core/features/scanner.js +20 -4
  720. package/dist/core/features/scanner.js.map +1 -1
  721. package/dist/core/markdown/cli.d.ts.map +1 -1
  722. package/dist/core/markdown/cli.js +9 -8
  723. package/dist/core/markdown/cli.js.map +1 -1
  724. package/dist/core/timeline/cli.d.ts.map +1 -1
  725. package/dist/core/timeline/cli.js +13 -6
  726. package/dist/core/timeline/cli.js.map +1 -1
  727. package/dist/core/timeline/debris.d.ts +20 -0
  728. package/dist/core/timeline/debris.d.ts.map +1 -0
  729. package/dist/core/timeline/debris.js +124 -0
  730. package/dist/core/timeline/debris.js.map +1 -0
  731. package/dist/core/timeline/hook-runner.d.ts.map +1 -1
  732. package/dist/core/timeline/hook-runner.js +3 -1
  733. package/dist/core/timeline/hook-runner.js.map +1 -1
  734. package/dist/core/timeline/hooks.d.ts.map +1 -1
  735. package/dist/core/timeline/hooks.js +13 -5
  736. package/dist/core/timeline/hooks.js.map +1 -1
  737. package/dist/core/timeline/installer.d.ts +2 -0
  738. package/dist/core/timeline/installer.d.ts.map +1 -1
  739. package/dist/core/timeline/installer.js +12 -0
  740. package/dist/core/timeline/installer.js.map +1 -1
  741. package/dist/core/timeline/project-root.d.ts +21 -0
  742. package/dist/core/timeline/project-root.d.ts.map +1 -0
  743. package/dist/core/timeline/project-root.js +83 -0
  744. package/dist/core/timeline/project-root.js.map +1 -0
  745. package/dist/web/register.d.ts.map +1 -1
  746. package/dist/web/register.js +2 -1
  747. package/dist/web/register.js.map +1 -1
  748. package/package.json +1 -1
  749. package/dist/.claude-template/.cgraphx/timeline-current-turn.json +0 -1
  750. package/dist/.claude-template/skills/.cgraphx/timeline-current-turn.json +0 -1
  751. package/dist/.claude-template/skills/handdrawn-deck/.cgraphx/timeline-current-turn.json +0 -1
  752. package/dist/.claude-template/skills/handdrawn-deck/references/.cgraphx/timeline-current-turn.json +0 -1
  753. package/dist/.claude-template/skills/handdrawn-sketch-engine/.cgraphx/timeline-current-turn.json +0 -1
  754. /package/dist/.claude-template/skills/run-api-test/assets/{template-test-verify.jsonl → template-/346/216/245/345/217/243/346/265/213/350/257/225/351/252/214/350/257/201.jsonl"} +0 -0
@@ -0,0 +1,1286 @@
1
+ "use strict";
2
+ /**
3
+ * Parse implementation — chunked parse + resolve loop.
4
+ *
5
+ * This is the core parsing engine of the ingestion pipeline. It reads
6
+ * source files in byte-budget chunks (~20MB each), parses via the worker
7
+ * pool (the sole parse path — there is no sequential fallback), and emits
8
+ * route CALLS edges. Import,
9
+ * call, and inheritance resolution are owned by the scope-resolution
10
+ * phase, not here (RING4-1 #942 removed the legacy call DAG; RING4-2 #943
11
+ * removed the legacy per-file import resolution + wildcard synthesis).
12
+ *
13
+ * Consumed by the parse phase (`parse.ts`) — the phase file handles
14
+ * dependency wiring while the heavy implementation lives here.
15
+ *
16
+ * @module
17
+ */
18
+ var __importDefault = (this && this.__importDefault) || function (mod) {
19
+ return (mod && mod.__esModule) ? mod : { "default": mod };
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.projectParseHeapNeedBytes = projectParseHeapNeedBytes;
23
+ exports.shouldAbortForHeapPressure = shouldAbortForHeapPressure;
24
+ exports.heapPressureRemedy = heapPressureRemedy;
25
+ exports.extractCrossFileRoutes = extractCrossFileRoutes;
26
+ exports.handleWorkerStartupFailure = handleWorkerStartupFailure;
27
+ exports.runChunkedParseAndResolve = runChunkedParseAndResolve;
28
+ const binding_accumulator_js_1 = require("../binding-accumulator.js");
29
+ const parsing_processor_js_1 = require("../parsing-processor.js");
30
+ const parse_cache_js_1 = require("../../../storage/parse-cache.js");
31
+ const parsedfile_store_js_1 = require("../../../storage/parsedfile-store.js");
32
+ const call_processor_js_1 = require("../call-processor.js");
33
+ const index_js_1 = require("../model/index.js");
34
+ const index_js_2 = require("../../../../shared/index.js");
35
+ const filesystem_walker_js_1 = require("../filesystem-walker.js");
36
+ const parser_loader_js_1 = require("../../tree-sitter/parser-loader.js");
37
+ const safe_parse_js_1 = require("../../tree-sitter/safe-parse.js");
38
+ const index_js_3 = require("../languages/index.js");
39
+ const worker_pool_js_1 = require("../workers/worker-pool.js");
40
+ const route_path_js_1 = require("../route-extractors/route-path.js");
41
+ const python_const_resolver_js_1 = require("../route-extractors/python-const-resolver.js");
42
+ const spring_shared_js_1 = require("../route-extractors/spring-shared.js");
43
+ const node_fs_1 = __importDefault(require("node:fs"));
44
+ const effective_ram_js_1 = require("../utils/effective-ram.js");
45
+ const node_path_1 = __importDefault(require("node:path"));
46
+ const node_v8_1 = __importDefault(require("node:v8"));
47
+ const node_url_1 = require("node:url");
48
+ const env_js_1 = require("../utils/env.js");
49
+ const verbose_js_1 = require("../utils/verbose.js");
50
+ const deferred_resolution_profile_js_1 = require("../utils/deferred-resolution-profile.js");
51
+ const heap_probe_js_1 = require("../utils/heap-probe.js");
52
+ const logger_js_1 = require("../../logger.js");
53
+ // ── Constants ──────────────────────────────────────────────────────────────
54
+ /**
55
+ * Heap-scale guardrail constants (#2649). Measured on a Linux-kernel analyze:
56
+ * ~75 graph nodes per PARSEABLE file (~5M nodes / ~65k parseable files;
57
+ * validated against heap probes at chunks 25/50/75 of 113 — the first
58
+ * calibration divided by total scanned files and under-projected by ~30%),
59
+ * main-thread heap per node. C-heavy corpus; other language mixes vary — these
60
+ * feed a WARNING and an emergency abort, never a hard admission gate, so
61
+ * estimate error only shifts when the operator hears about the problem, not
62
+ * whether analyze runs.
63
+ *
64
+ * RECALIBRATED for streamed structural emit (#2680), which is on by default for
65
+ * full rebuilds and holds relationships out of the JS heap. The original 2250
66
+ * was measured against the object-based graph; an A/B at 400k nodes / 1.08M
67
+ * edges put streaming at 1.40x smaller (819 MB -> 584 MB), so the corpus-
68
+ * calibrated figure is divided by that ratio: 2250 / 1.40 ~= 1600. Scaling the
69
+ * measured constant rather than substituting a synthetic one keeps #2649's
70
+ * kernel calibration intact and changes only the one thing that actually moved.
71
+ *
72
+ * If streaming is disabled (CGRAPH_STREAM_GRAPH_EMIT=0, or any non-force run)
73
+ * this UNDER-projects by ~40%, so the preflight warning may stay quiet on a repo
74
+ * that then struggles. That is the safe direction to be wrong in: the abort
75
+ * below reads LIVE heap use, not this projection, so it still catches the real
76
+ * condition — only the early warning is affected.
77
+ */
78
+ const PROJECTED_NODES_PER_FILE = 75;
79
+ const PROJECTED_HEAP_BYTES_PER_NODE = 1600;
80
+ /** Warn at scan end when the projection crosses this share of the heap limit. */
81
+ const PREFLIGHT_WARN_FRACTION = 0.85;
82
+ /**
83
+ * Abort the chunk loop when live heap use crosses this share of the limit.
84
+ * Above ~0.95 V8 enters the ineffective-mark-compact death spiral (2s+ GC
85
+ * pauses that also falsely idle-timeout healthy workers, #2649); 0.92 leaves
86
+ * one chunk's worth of headroom to fail with an actionable message instead.
87
+ * `CGRAPH_MEMORY=off` declines the abort (proceed-at-own-risk).
88
+ */
89
+ const HEAP_ABORT_FRACTION = 0.92;
90
+ /** Projected main-thread heap need for the parse phase (#2649). */
91
+ function projectParseHeapNeedBytes(parseableFileCount) {
92
+ return parseableFileCount * PROJECTED_NODES_PER_FILE * PROJECTED_HEAP_BYTES_PER_NODE;
93
+ }
94
+ /** True when the mid-loop heap guard should abort the parse (#2649). */
95
+ function shouldAbortForHeapPressure(heapUsedBytes, heapLimitBytes) {
96
+ if ((0, effective_ram_js_1.memoryAutopilotDisabled)())
97
+ return false;
98
+ return heapUsedBytes > heapLimitBytes * HEAP_ABORT_FRACTION;
99
+ }
100
+ /**
101
+ * The ONE action a user should take when this repository doesn't fit the
102
+ * current heap (#2649). Users hitting memory limits are already frustrated —
103
+ * a menu of env knobs at that moment is noise. Branch on whether the machine
104
+ * itself has more memory to give: if this process's limit sits well below
105
+ * what the RAM-aware auto-sizer would grant (an inherited NODE_OPTIONS pin or
106
+ * explicit flag), the fix is to drop the pin — gitnexus sizes itself.
107
+ * Otherwise the machine is the ceiling and only scope or hardware helps.
108
+ * Escape hatches (CGRAPH_MEMORY etc.) stay in the README env table.
109
+ */
110
+ function heapPressureRemedy(heapLimitBytes) {
111
+ // Effective RAM honors a real cgroup limit — raw os.totalmem() told users
112
+ // inside an 8GB-limited container on a 64GB host that "this machine has
113
+ // more memory available", an advice loop with no exit (#2649 review).
114
+ const autoCapBytes = (0, effective_ram_js_1.effectiveRamBytes)() * 0.75;
115
+ if (heapLimitBytes < autoCapBytes * 0.9) {
116
+ return (`This machine has more memory available: re-run without the --max-old-space-size ` +
117
+ `pin (NODE_OPTIONS or node flag) — gitnexus sizes its heap to the machine automatically.`);
118
+ }
119
+ return (`This machine is at its memory ceiling: exclude generated or vendored directories ` +
120
+ `via .cgraphignore, or analyze on a machine with more memory.`);
121
+ }
122
+ /** Max bytes of source content to load per parse chunk.
123
+ *
124
+ * Memory bound for the worker pool dispatch + a granularity knob for
125
+ * the parse cache. A single file change invalidates only its enclosing
126
+ * chunk, so smaller budgets → finer-grained invalidation.
127
+ *
128
+ * Override via CGRAPH_CHUNK_BYTE_BUDGET (bytes) — the default of 2MB
129
+ * gives a useful invalidation floor (~1/N chunks on a multi-MB repo)
130
+ * while keeping worker dispatch overhead under 5% on cold runs.
131
+ */
132
+ /**
133
+ * Built-in chunk byte budget when neither `PipelineOptions.chunkByteBudget`
134
+ * nor `CGRAPH_CHUNK_BYTE_BUDGET` is set. Tuned to give a useful
135
+ * cache-invalidation floor (~1/N chunks on a multi-MB repo) while keeping
136
+ * worker dispatch overhead under 5% on cold runs. Resolution happens at
137
+ * call time inside `runChunkedParseAndResolve` (U14 from PR #1693 review)
138
+ * — previously this was a module-load IIFE, which froze the env value at
139
+ * import time and meant per-call option threading silently no-op'd.
140
+ */
141
+ const DEFAULT_CHUNK_BYTE_BUDGET = 2 * 1024 * 1024;
142
+ /**
143
+ * Per-worker share of a chunk's byte budget when auto-scaling (#worker-idle).
144
+ *
145
+ * A chunk is a single `WorkerPool.dispatch` unit; the pool fans a chunk's files
146
+ * into sub-batch jobs and assigns them to idle workers (`wakeIdleSlots`). When
147
+ * the chunk budget (2 MB) was far below the 8 MB sub-batch cap, every chunk
148
+ * produced exactly ONE job → ONE busy worker while the other N-1 sat idle. To
149
+ * keep all workers fed, the auto chunk budget now scales as
150
+ * `poolSize × CHUNK_BYTES_PER_WORKER`, so each dispatch carries enough work to
151
+ * fan across the whole pool. Sequential / explicit-budget runs are unaffected.
152
+ */
153
+ const CHUNK_BYTES_PER_WORKER = 2 * 1024 * 1024;
154
+ /**
155
+ * Target jobs-per-worker per dispatch. More jobs than workers gives the pool's
156
+ * idle-slot assignment room to load-balance (a slow job doesn't strand a worker
157
+ * while the rest finish early). Drives the derived `subBatchMaxBytes`.
158
+ */
159
+ const TARGET_JOBS_PER_WORKER = 3;
160
+ /** Floor for a derived sub-batch so jobs don't shrink to per-file IPC churn. */
161
+ const MIN_SUB_BATCH_BYTES = 256 * 1024;
162
+ function resolveChunkByteBudget(options, effectivePoolSize = 1) {
163
+ const opt = options?.chunkByteBudget;
164
+ if (typeof opt === 'number' && Number.isFinite(opt) && opt > 0)
165
+ return opt;
166
+ const env = Number(process.env.CGRAPH_CHUNK_BYTE_BUDGET);
167
+ if (Number.isFinite(env) && env > 0)
168
+ return env;
169
+ // Auto: size each chunk so a dispatch can fan across the whole pool. A
170
+ // single-worker (tiny-repo) run keeps the original 2 MB invalidation floor.
171
+ return Math.max(DEFAULT_CHUNK_BYTE_BUDGET, effectivePoolSize * CHUNK_BYTES_PER_WORKER);
172
+ }
173
+ /**
174
+ * Whole-repo, cross-file route extraction (main thread).
175
+ *
176
+ * Some frameworks define their route table from a single root file that pulls
177
+ * in other files across the repo — e.g. Django follows
178
+ * `manage.py → DJANGO_SETTINGS_MODULE → ROOT_URLCONF → root urls.py`, then walks
179
+ * `include()` chains across many files. Unlike single-file route files (Laravel
180
+ * `routes/*.php`), which the parse worker extracts in isolation, these need a
181
+ * whole-repo view and on-demand cross-file reads — neither of which the
182
+ * filesystem-free worker can provide, and which a per-chunk worker view gets
183
+ * wrong whenever the root file and its includes land in different chunks.
184
+ *
185
+ * So it runs here, once, after every file is scanned — mirroring the FastAPI
186
+ * router-include join further below. The pass is language-agnostic: any
187
+ * {@link LanguageProvider} exposing both `discoverRootRouteFile` and
188
+ * `extractRoutes` participates (today only Python/Django). For repos without
189
+ * such a framework the cost is a path scan plus one `manage.py`-style miss.
190
+ */
191
+ async function extractCrossFileRoutes(allPaths, repoPath) {
192
+ const out = [];
193
+ // Languages whose provider implements the cross-file route hooks. Route
194
+ // results are intentionally NOT persisted across analyze runs, so a repo
195
+ // using such a framework (e.g. Django) re-derives its routes on every run;
196
+ // a repo without one does effectively nothing here. Cross-run route caching
197
+ // is a deliberate follow-up — see #1836.
198
+ const routeCapableLangs = new Set();
199
+ for (const provider of Object.values(index_js_3.providers)) {
200
+ if (provider.discoverRootRouteFiles && provider.extractRoutes) {
201
+ routeCapableLangs.add(provider.id);
202
+ }
203
+ }
204
+ if (routeCapableLangs.size === 0)
205
+ return out;
206
+ // Bucket only the paths whose language can contribute routes, so a non-
207
+ // framework repo never pays to bucket the languages it doesn't use here.
208
+ const pathsByLang = new Map();
209
+ for (const p of allPaths) {
210
+ const lang = (0, index_js_2.getLanguageFromFilename)(p);
211
+ if (!lang || !routeCapableLangs.has(lang))
212
+ continue;
213
+ let bucket = pathsByLang.get(lang);
214
+ if (!bucket) {
215
+ bucket = [];
216
+ pathsByLang.set(lang, bucket);
217
+ }
218
+ bucket.push(p);
219
+ }
220
+ for (const [lang, langPaths] of pathsByLang) {
221
+ if (!(0, parser_loader_js_1.isLanguageAvailable)(lang))
222
+ continue;
223
+ const provider = (0, index_js_3.getProvider)(lang);
224
+ if (!provider.discoverRootRouteFiles || !provider.extractRoutes)
225
+ continue;
226
+ // Disk-backed reader keyed on repo-relative paths. Discovery and the
227
+ // include() walk read through this; nothing is pre-loaded, so a repo that
228
+ // lacks the framework pays only the reads its own discovery probes trigger.
229
+ const readCache = new Map();
230
+ const reader = (relativePath) => {
231
+ const cached = readCache.get(relativePath);
232
+ if (cached !== undefined)
233
+ return cached;
234
+ let content = null;
235
+ try {
236
+ content = node_fs_1.default.readFileSync(node_path_1.default.join(repoPath, relativePath), 'utf-8');
237
+ }
238
+ catch {
239
+ content = null;
240
+ }
241
+ readCache.set(relativePath, content);
242
+ return content;
243
+ };
244
+ // One root route file per discoverable project (a monorepo can have several).
245
+ const rootPaths = provider.discoverRootRouteFiles(langPaths.map((p) => ({ path: p })), undefined, reader);
246
+ if (rootPaths.length === 0)
247
+ continue;
248
+ // One parser per language — the grammar is language-scoped, so it is reused
249
+ // for every project root and every include() re-parse.
250
+ let parser;
251
+ try {
252
+ parser = await (0, parser_loader_js_1.createParserForLanguage)(lang, rootPaths[0]);
253
+ }
254
+ catch {
255
+ continue; // grammar unavailable — skip the language, mirrors worker safety net
256
+ }
257
+ for (const rootPath of rootPaths) {
258
+ const rootContent = reader(rootPath);
259
+ if (rootContent === null)
260
+ continue; // skip this root only, not the language
261
+ let rootTree;
262
+ try {
263
+ rootTree = (0, safe_parse_js_1.parseSourceSafe)(parser, rootContent);
264
+ }
265
+ catch {
266
+ logger_js_1.logger.warn(`Skipping unparseable root route file: ${rootPath}`);
267
+ continue; // skip this root only
268
+ }
269
+ // Isolate a misbehaving provider: a throw here must not abort the whole
270
+ // analyze (mirrors the worker's per-file isolation). Skip this root, warn.
271
+ try {
272
+ const routes = provider.extractRoutes(rootTree, rootPath, reader, parser);
273
+ for (const r of routes)
274
+ out.push(r);
275
+ }
276
+ catch (err) {
277
+ logger_js_1.logger.warn({ err }, `Cross-file route extraction failed for ${rootPath}`);
278
+ }
279
+ }
280
+ }
281
+ return out;
282
+ }
283
+ /**
284
+ * Handle a worker-pool startup failure by FAILING FAST with the captured cause
285
+ * (#1741). The pool self-heals *transient* worker crashes on its own — a
286
+ * bounded, jittered startup restart loop (see worker-pool.ts) — so this is
287
+ * reached only when that self-heal is EXHAUSTED, or a deterministic crash-loop
288
+ * was detected, or the pool could not even be constructed. In every such case
289
+ * the workers genuinely cannot start.
290
+ *
291
+ * There is no sequential parser to silently degrade to — that fallback was
292
+ * removed (and it had masked a worker-startup regression as a 2-hour "stuck"
293
+ * run in #1741, rc99: a dropped `logger.warn` plus an unbounded sequential
294
+ * grind). GitNexus surfaces the real crash and aborts so the operator fixes the
295
+ * worker startup (commonly a missing build). The pool's own crash
296
+ * classification (`crashClass` on WorkerPoolInitializationError) sharpens the
297
+ * message.
298
+ *
299
+ * @throws always — an actionable Error carrying the captured worker crash.
300
+ * @internal Exported for unit tests; production callers are the parse loop's
301
+ * two worker-startup catch sites below.
302
+ */
303
+ function handleWorkerStartupFailure(err) {
304
+ const isInit = err instanceof worker_pool_js_1.WorkerPoolInitializationError;
305
+ const readinessFailures = isInit ? err.readinessFailures : [];
306
+ const crashClass = isInit ? err.crashClass : undefined;
307
+ // Surface the real cause verbatim: readiness failures for an init crash, or
308
+ // the construction error message (e.g. "Worker script not found: …") when the
309
+ // pool never got to spawn workers.
310
+ const failureDetail = readinessFailures.length > 0
311
+ ? ` Underlying worker failure(s): ${readinessFailures.join(' | ')}`
312
+ : isInit
313
+ ? ''
314
+ : ` Underlying error: ${err.message}`;
315
+ // Always surface the real crash — never let a startup failure pass silently.
316
+ logger_js_1.logger.error({ err: err.message, readinessFailures, crashClass }, 'Worker pool failed to start — workers could not start (bounded self-heal exhausted).');
317
+ const cause = crashClass === 'deterministic-startup'
318
+ ? `every worker crashed identically during startup (a deterministic ` +
319
+ `crash-loop — retrying cannot help), so the pool has no usable workers.`
320
+ : isInit
321
+ ? `workers exhausted the bounded startup retry budget without reporting ` +
322
+ `ready, so the pool has no usable workers.`
323
+ : `the worker pool could not be constructed.`;
324
+ // Class-aware fix hint: a missing/broken native binding is the likely cause
325
+ // when workers crashed during init, but it is the WRONG guess for a pool that
326
+ // never constructed (commonly a missing build / unresolvable worker path).
327
+ const fixHint = isInit
328
+ ? `Fix the worker startup failure shown above (often a missing/broken native ` +
329
+ `binding or a top-of-script import error in parse-worker).`
330
+ : `Fix the worker pool construction error shown above (commonly a missing ` +
331
+ `build, so dist/ has no parse-worker, or an unresolvable worker path).`;
332
+ throw new Error(`Worker pool failed to start: ${cause}${failureDetail}\n\n` +
333
+ `The worker pool is GitNexus's only parse path — there is no sequential ` +
334
+ `fallback to hide this crash behind (silently degrading masked a ` +
335
+ `worker-startup regression as a 2-hour "stuck" run in #1741). Fix:\n` +
336
+ ` • ${fixHint}`);
337
+ }
338
+ /**
339
+ * Chunked parse + resolve loop.
340
+ *
341
+ * Reads source in byte-budget chunks (~20MB each):
342
+ * 1. Parse each chunk via the worker pool (the sole parse path)
343
+ * 2. After all chunks parse, emit route CALLS edges (deferred so resolution
344
+ * sees the full repo graph) and collect the exported-type map
345
+ * 3. Collect TypeEnv bindings for cross-file propagation
346
+ *
347
+ * Import, call, and inheritance edges are emitted by the scope-resolution
348
+ * phase, not here (RING4-1 #942 / RING4-2 #943 removed the legacy passes).
349
+ */
350
+ async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, totalFiles, repoPath, pipelineStart, onProgress, options) {
351
+ const model = (0, index_js_1.createSemanticModel)();
352
+ const symbolTable = model.symbols;
353
+ const parseableScanned = scannedFiles.filter((f) => {
354
+ const lang = (0, index_js_2.getLanguageFromFilename)(f.path);
355
+ return lang && (0, parser_loader_js_1.isLanguageAvailable)(lang);
356
+ });
357
+ // Warn about files skipped due to unavailable parsers
358
+ const skippedByLang = new Map();
359
+ for (const f of scannedFiles) {
360
+ const lang = (0, index_js_2.getLanguageFromFilename)(f.path);
361
+ const provider = lang === null ? undefined : (0, index_js_3.getProvider)(lang);
362
+ if (lang && provider?.parseStrategy !== 'standalone' && !(0, parser_loader_js_1.isLanguageAvailable)(lang)) {
363
+ skippedByLang.set(lang, (skippedByLang.get(lang) || 0) + 1);
364
+ }
365
+ }
366
+ for (const [lang, count] of skippedByLang) {
367
+ // Distinguish a deliberate runtime opt-out from a genuinely-missing binding
368
+ // so we don't tell a user who set CGRAPH_SKIP_OPTIONAL_GRAMMARS to
369
+ // `npm rebuild` a grammar that built fine (#2091/#2093 review).
370
+ if ((0, parser_loader_js_1.isGrammarRuntimeSkipped)(lang)) {
371
+ logger_js_1.logger.warn(`Skipping ${count} ${lang} file(s) — ${lang} parsing disabled via CGRAPH_SKIP_OPTIONAL_GRAMMARS.`);
372
+ }
373
+ else {
374
+ logger_js_1.logger.warn(`Skipping ${count} ${lang} file(s) — ${lang} parser not available (native binding may not have built). Try: npm rebuild tree-sitter-${lang}`);
375
+ }
376
+ }
377
+ // Sort parseableScanned alphabetically for stable chunk membership
378
+ // across runs (Finding 4). Without this, filesystem-scan order can
379
+ // shift between runs (notably on macOS APFS where directory entry
380
+ // order can change after modifications) — different files in the
381
+ // same chunk → different chunk hash → cache miss even when no file
382
+ // content changed. The cache also becomes platform-specific: a
383
+ // Linux-built cache misses on macOS for the same repo.
384
+ parseableScanned.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
385
+ const totalParseable = parseableScanned.length;
386
+ const totalBytes = parseableScanned.reduce((sum, f) => sum + f.size, 0);
387
+ if (totalParseable === 0) {
388
+ onProgress({
389
+ phase: 'parsing',
390
+ // Skip directly to the end of the parse-phase progress band (M2 from PR
391
+ // #1693 review). Parse 20-70%, deferred 70-95%; nothing in either runs
392
+ // when there's no parseable file, so jump to 95.
393
+ percent: 95,
394
+ message: 'No parseable files found — skipping parsing phase',
395
+ stats: { filesProcessed: 0, totalFiles: 0, nodesCreated: graph.nodeCount },
396
+ });
397
+ }
398
+ // Sequential parsing has been removed: the worker pool (quarantine +
399
+ // respawn/recycle + circuit breaker) is the sole parse path. The three
400
+ // channels that used to select an in-process parser are now hard errors, so
401
+ // an operator who set one gets an actionable message instead of a silently
402
+ // slower (now nonexistent) fallback. Validated before any chunk work; a
403
+ // zero-parseable-file repo is exempt (nothing to parse).
404
+ if (totalParseable > 0) {
405
+ const requestedPoolSize = options?.workerPoolSize;
406
+ const disabledByEnv = requestedPoolSize === undefined && (0, worker_pool_js_1.workerPoolDisabledByEnv)();
407
+ if (options?.skipWorkers || requestedPoolSize === 0 || disabledByEnv) {
408
+ const reason = options?.skipWorkers
409
+ ? '`skipWorkers: true` was passed'
410
+ : requestedPoolSize === 0
411
+ ? '`--workers 0` (workerPoolSize=0) was requested'
412
+ : '`CGRAPH_WORKER_POOL_SIZE=0` is set';
413
+ throw new worker_pool_js_1.WorkerPoolDisabledError(`Worker-pool parsing cannot be disabled (${reason}). GitNexus no longer ` +
414
+ `has a sequential parser — the worker pool self-heals via quarantine + ` +
415
+ `respawn, so there is no slower path to fall back to. Pass ` +
416
+ `\`--workers <N>\` with N>=1, or omit it for an auto-sized pool.`);
417
+ }
418
+ }
419
+ // Build byte-budget chunks. The budget is resolved per-call (U14): options
420
+ // first, then env, then the built-in default. Pre-U14 this was a
421
+ // module-load IIFE constant, which froze the env value at import time
422
+ // and made `PipelineOptions.chunkByteBudget` silently no-op on warm test
423
+ // runs. Resolving in the function body restores per-call configurability
424
+ // and matches the pattern used by resolveAutoPoolSize and the U1
425
+ // parseChunkConcurrency resolver.
426
+ // Effective worker count, computed up-front so the chunk budget can scale to
427
+ // keep the whole pool busy (#worker-idle). The pool is ALWAYS used (sequential
428
+ // parsing was removed; the disabled channels threw above). Size it to the
429
+ // work: an explicit `--workers <N>` pins the size; otherwise the cores-based
430
+ // auto size is capped by the repo's worth of work (~one worker per
431
+ // CHUNK_BYTES_PER_WORKER of source) so a tiny repo spawns ~1 worker instead of
432
+ // a full pool, replacing the job the deleted small-repo threshold used to do.
433
+ // KTD-3 of the remove-sequential plan; the cap formula is intentionally coarse
434
+ // (tuning deferred).
435
+ const explicitPoolSize = options?.workerPoolSize;
436
+ const workProportionalCap = Math.max(1, Math.ceil(totalBytes / CHUNK_BYTES_PER_WORKER));
437
+ const effectivePoolSize = explicitPoolSize && explicitPoolSize > 0
438
+ ? explicitPoolSize
439
+ : Math.min((0, worker_pool_js_1.resolveAutoPoolSize)(), workProportionalCap);
440
+ const chunkByteBudget = resolveChunkByteBudget(options, effectivePoolSize);
441
+ // Sub-batch size so each chunk fans into ~`TARGET_JOBS_PER_WORKER` jobs per
442
+ // worker, giving the pool's idle-slot assignment room to load-balance. An
443
+ // explicit `CGRAPH_WORKER_SUB_BATCH_MAX_BYTES` operator override wins.
444
+ const subBatchEnv = Number(process.env.CGRAPH_WORKER_SUB_BATCH_MAX_BYTES);
445
+ const dispatchSubBatchMaxBytes = Number.isFinite(subBatchEnv) && subBatchEnv > 0
446
+ ? subBatchEnv
447
+ : Math.max(MIN_SUB_BATCH_BYTES, Math.ceil(chunkByteBudget / (effectivePoolSize * TARGET_JOBS_PER_WORKER)));
448
+ // Heap-scale guardrails (#2649), measured on a Linux-kernel analyze
449
+ // (94,773 files): ~55 graph nodes per parseable file and ~2.2KB of
450
+ // main-thread heap per node, linear across 113 chunks (see
451
+ // docs/plans/2026-07-23-gitnexus-plan-large-repo-analyze-oom.md §2).
452
+ // Estimates, not contracts — used only to warn early (preflight) and to
453
+ // convert a certain multi-minute GC death spiral into an immediate
454
+ // actionable error (mid-loop guard).
455
+ const projectedHeapNeedBytes = projectParseHeapNeedBytes(parseableScanned.length);
456
+ const heapLimitBytes = node_v8_1.default.getHeapStatistics().heap_size_limit;
457
+ if (projectedHeapNeedBytes > heapLimitBytes * PREFLIGHT_WARN_FRACTION) {
458
+ logger_js_1.logger.warn(`Large repository: analyzing ${parseableScanned.length} files needs roughly ${Math.round(projectedHeapNeedBytes / 1024 / 1024 / 1024)}GB of memory, ` +
459
+ `but Node is limited to ${Math.round(heapLimitBytes / 1024 / 1024 / 1024)}GB — analyze may stop early. ${heapPressureRemedy(heapLimitBytes)}`);
460
+ }
461
+ const chunks = [];
462
+ let currentChunk = [];
463
+ let currentBytes = 0;
464
+ for (const file of parseableScanned) {
465
+ if (currentChunk.length > 0 && currentBytes + file.size > chunkByteBudget) {
466
+ chunks.push(currentChunk);
467
+ currentChunk = [];
468
+ currentBytes = 0;
469
+ }
470
+ currentChunk.push(file.path);
471
+ currentBytes += file.size;
472
+ }
473
+ if (currentChunk.length > 0)
474
+ chunks.push(currentChunk);
475
+ const numChunks = chunks.length;
476
+ if (env_js_1.isDev) {
477
+ const totalMB = parseableScanned.reduce((s, f) => s + f.size, 0) / (1024 * 1024);
478
+ logger_js_1.logger.info(`📂 Scan: ${totalFiles} paths, ${totalParseable} parseable (${totalMB.toFixed(0)}MB), ${numChunks} chunks @ ${chunkByteBudget / (1024 * 1024)}MB budget`);
479
+ }
480
+ // Skip the "Parsing N files..." announcement when there's nothing to parse
481
+ // — the early-return branch above already emitted percent 95 ("skipping
482
+ // parsing phase"), and emitting percent 20 here would regress the
483
+ // progress stream non-monotonically (M2 from PR #1693 review).
484
+ if (totalParseable > 0) {
485
+ onProgress({
486
+ phase: 'parsing',
487
+ percent: 20,
488
+ message: `Parsing ${totalParseable} files in ${numChunks} chunk${numChunks !== 1 ? 's' : ''}...`,
489
+ stats: { filesProcessed: 0, totalFiles: totalParseable, nodesCreated: graph.nodeCount },
490
+ });
491
+ }
492
+ // Create the worker pool lazily, reusing it across cache-miss chunks.
493
+ //
494
+ // KTD-8 — the pool is intentionally NOT created before the parse-cache
495
+ // lookup: a warm-cache all-hit run must replay cached worker output without
496
+ // loading parse-worker.js or any tree-sitter/N-API native bindings. So
497
+ // `getOrCreateWorkerPool` is called only from inside the chunk loop, on the
498
+ // first cache MISS. There is no longer a "should we use workers?" gate:
499
+ // sequential parsing was removed and the disabled channels (`--workers 0` /
500
+ // env=0 / `skipWorkers`) threw above, so for any repo with parseable files
501
+ // the pool is always the parse path.
502
+ let workerPool;
503
+ const getOrCreateWorkerPool = () => {
504
+ if (workerPool)
505
+ return workerPool;
506
+ try {
507
+ // Test-only injection: integration tests pass a custom worker script URL
508
+ // via `workerUrlForTest` so they can drive the chunk-loop with
509
+ // deterministically-misbehaving workers without mocking the module import
510
+ // graph. When unset, the normal src/ → dist/ resolution runs.
511
+ let workerUrl = options?.workerUrlForTest ?? new URL('../workers/parse-worker.js', (0, node_url_1.pathToFileURL)(__filename));
512
+ // When running under vitest, import.meta.url points to src/ where no .js exists.
513
+ // Fall back to the compiled dist/ worker so the pool can spawn real worker threads.
514
+ const thisDir = __dirname;
515
+ if (!options?.workerUrlForTest && !node_fs_1.default.existsSync((0, node_url_1.fileURLToPath)(workerUrl))) {
516
+ const distWorker = node_path_1.default.resolve(thisDir, '..', '..', '..', '..', 'dist', 'core', 'ingestion', 'workers', 'parse-worker.js');
517
+ if (node_fs_1.default.existsSync(distWorker)) {
518
+ workerUrl = (0, node_url_1.pathToFileURL)(distWorker);
519
+ }
520
+ }
521
+ // Thread the ParsedFile store path into the pool so workers write their
522
+ // own shards (#1983 parallel serialization). `parsedFileStorePath` is
523
+ // declared below but this closure only runs from inside the chunk loop,
524
+ // after it is initialized; `undefined` drives the worker no-store
525
+ // fallback (return ParsedFiles in the result).
526
+ workerPool = (0, worker_pool_js_1.createWorkerPool)(workerUrl, effectivePoolSize, {
527
+ parsedFileStoreStoragePath: parsedFileStorePath,
528
+ // Durable, content-addressed shard dir for warm-cache reuse (#2038).
529
+ // Initialized below before the chunk loop (same deferred-init pattern
530
+ // as `parsedFileStorePath`); this closure only runs from the loop.
531
+ durableParsedFileStoragePath: durableParsedFileDir,
532
+ // Fan each chunk across the whole pool (#worker-idle): without this a
533
+ // chunk smaller than the 8 MB sub-batch cap became a single job on a
534
+ // single worker. Honors an explicit `subBatchMaxBytes` / env override.
535
+ subBatchMaxBytes: dispatchSubBatchMaxBytes,
536
+ });
537
+ return workerPool;
538
+ }
539
+ catch (err) {
540
+ // Pool *construction* failed (e.g. the worker script is missing — a
541
+ // broken install). Fail fast with the cause (#1741). There is no
542
+ // sequential parser to fall back to; the operator must fix the worker
543
+ // startup (commonly a missing build so dist/ has no parse-worker).
544
+ handleWorkerStartupFailure(err);
545
+ }
546
+ };
547
+ let filesParsedSoFar = 0;
548
+ const exportedTypeMap = new Map();
549
+ const bindingAccumulator = new binding_accumulator_js_1.BindingAccumulator();
550
+ const allFetchCalls = [];
551
+ const allFetchWrapperDefs = [];
552
+ const allExtractedRoutes = [];
553
+ const allDecoratorRoutes = [];
554
+ const allRouterIncludes = [];
555
+ const allRouterImports = [];
556
+ const allRouterConstructorPrefixes = [];
557
+ const allRouterModuleAliases = [];
558
+ // Per-file Python module constants (#2391); resolved into decorator route paths
559
+ // below, after cross-file aggregation, alongside the include_router prefix pass.
560
+ const allModuleConstants = [];
561
+ const allSpringTypes = [];
562
+ const allToolDefs = [];
563
+ const allORMQueries = [];
564
+ // Aggregated per-file ParsedFile artifacts produced by workers' calls
565
+ // to `extractParsedFile`. Threaded through to the scope-resolution
566
+ // phase so it can SKIP its own re-extraction on cache hits — this is
567
+ // the second-half of the parse-cache speedup since scope-resolution's
568
+ // re-parse otherwise dominates the warm-cache wall-clock time.
569
+ const allParsedFiles = [];
570
+ // Content-addressed parse cache (spec §5.3 compliant — this is NOT the
571
+ // removed incremental index). The graph is rebuilt from scratch every run;
572
+ // this cache only skips tree-sitter worker dispatch + byte-copies the
573
+ // ParsedFile shards when a chunk's file contents are unchanged (chunkHash
574
+ // hit → replay cached ParseWorkerResult[], restore durable shards). Loaded
575
+ // before the run and persisted after by the caller (run-analyze.ts); this
576
+ // function mutates `entries` / `usedKeys` in place. See parse-cache.ts.
577
+ const parseCache = options?.parseCache;
578
+ // Disk-backed ParsedFile store (#1983): when a storage path is available we
579
+ // flush worker-produced ParsedFiles to disk per chunk (instead of retaining
580
+ // them in `allParsedFiles`) and scope-resolution streams them back per
581
+ // language — avoiding both the ~1× semantic-model RAM cost of holding them
582
+ // and, critically, the unbounded native tree-sitter re-parse leak that
583
+ // scope-resolution's main-thread re-extraction otherwise accumulates. When
584
+ // there is no storage path (tests / direct pipeline calls), we fall back to
585
+ // retaining them in `allParsedFiles` (small-repo path, preserves prior
586
+ // behavior). Cleared up-front so a prior run's shards never leak in.
587
+ const parsedFileStorePath = options?.parsedFileStorePath;
588
+ if (parsedFileStorePath)
589
+ await (0, parsedfile_store_js_1.clearParsedFileStore)(parsedFileStorePath);
590
+ // Durable, content-addressed ParsedFile store (#2038 warm-cache coverage) —
591
+ // a sibling of the run-scoped store, NOT cleared per run. Workers write a
592
+ // shard per chunk hash; on a warm parse-cache hit we restore the chunk's
593
+ // shards into the run-scoped store so scope-resolution streams them without
594
+ // re-parsing. `durableHitKeys` is the prior run's index, version-gated by
595
+ // PARSE_CACHE_VERSION (a mismatch ⇒ empty ⇒ every chunk re-dispatches, which
596
+ // repopulates the durable store — never the main-thread extract fallback).
597
+ const durableParsedFileDir = parsedFileStorePath !== undefined ? (0, parsedfile_store_js_1.getDurableParsedFileDir)(parsedFileStorePath) : undefined;
598
+ const durableHitKeys = durableParsedFileDir !== undefined
599
+ ? await (0, parsedfile_store_js_1.loadDurableParsedFileIndex)(durableParsedFileDir, parse_cache_js_1.PARSE_CACHE_VERSION)
600
+ : new Set();
601
+ let chunkCacheHits = 0;
602
+ let chunkCacheMisses = 0;
603
+ try {
604
+ // U1 — bounded chunk concurrency (B1 from PR #1693 review): pre-fetch
605
+ // chunk file contents up to `parseChunkConcurrency` chunks ahead of the
606
+ // dispatch cursor so file I/O overlaps with worker compute. Worker
607
+ // dispatch itself stays serial because `WorkerPool.dispatch` is not
608
+ // reentrant (concurrent calls would race on the shared per-slot
609
+ // busy/in-flight state). With concurrency=1 behavior is identical to
610
+ // the pure-serial loop. F4: deferred-state aggregation still happens
611
+ // in chunkIdx order (the for-loop below iterates sequentially), so
612
+ // cross-chunk processors see deterministic input regardless of
613
+ // file-read completion order. Honors options.parseChunkConcurrency
614
+ // (threaded from the CLI), then CGRAPH_PARSE_CHUNK_CONCURRENCY env
615
+ // (default 2 — matches the help text the CLI advertises).
616
+ const parseChunkConcurrency = (() => {
617
+ const opt = options?.parseChunkConcurrency;
618
+ if (typeof opt === 'number' && Number.isInteger(opt) && opt >= 1)
619
+ return opt;
620
+ const env = Number(process.env.CGRAPH_PARSE_CHUNK_CONCURRENCY);
621
+ if (Number.isInteger(env) && env >= 1)
622
+ return env;
623
+ return 2;
624
+ })();
625
+ const chunkContentPromises = new Array(numChunks);
626
+ const startChunkPrefetch = (i) => {
627
+ if (i >= numChunks || chunkContentPromises[i] !== undefined)
628
+ return;
629
+ chunkContentPromises[i] = (0, filesystem_walker_js_1.readFileContents)(repoPath, chunks[i]);
630
+ };
631
+ for (let i = 0; i < Math.min(parseChunkConcurrency, numChunks); i++) {
632
+ startChunkPrefetch(i);
633
+ }
634
+ // Hoisted loop-invariant: CGRAPH_VERBOSE / NODE_ENV are read once
635
+ // (not on every chunk). Previously evaluated at the top of the loop
636
+ // body, which re-read process.env on every iteration even though
637
+ // the env can't change mid-run.
638
+ const verboseThroughputLog = env_js_1.isDev || (0, verbose_js_1.isVerboseIngestionEnabled)();
639
+ const heapProbeEveryN = (0, heap_probe_js_1.isDebugHeapEnabled)() ? 25 : 0;
640
+ let pendingWorkerChunk = null;
641
+ // Apply one chunk's merged worker data: per-chunk aggregation into the
642
+ // run-level accumulators + the throughput log. Shared by the cache-hit
643
+ // (inline) and worker (deferred) paths. The `| null` guard is defensive —
644
+ // every live caller passes real worker data now that sequential parsing
645
+ // (which was the only path that passed null) is gone.
646
+ const applyChunkResults = async (chunkWorkerData, chunkIdx, chunkFiles, chunkStartMs) => {
647
+ if (chunkWorkerData) {
648
+ if (chunkWorkerData.parsedFiles?.length) {
649
+ if (parsedFileStorePath) {
650
+ await (0, parsedfile_store_js_1.persistParsedFileChunk)(parsedFileStorePath, `chunk-${chunkIdx}`, chunkWorkerData.parsedFiles);
651
+ }
652
+ else {
653
+ for (const item of chunkWorkerData.parsedFiles)
654
+ allParsedFiles.push(item);
655
+ }
656
+ }
657
+ if (chunkWorkerData.fileScopeBindings?.length) {
658
+ for (const { filePath, bindings } of chunkWorkerData.fileScopeBindings) {
659
+ if (typeof filePath !== 'string' || filePath.length === 0)
660
+ continue;
661
+ if (!Array.isArray(bindings))
662
+ continue;
663
+ const entries = [];
664
+ for (const tuple of bindings) {
665
+ if (!Array.isArray(tuple) || tuple.length !== 2)
666
+ continue;
667
+ const [varName, typeName] = tuple;
668
+ if (typeof varName !== 'string' || typeof typeName !== 'string')
669
+ continue;
670
+ entries.push({ scope: '', varName, typeName });
671
+ }
672
+ if (entries.length > 0) {
673
+ bindingAccumulator.appendFile(filePath, entries);
674
+ }
675
+ }
676
+ }
677
+ if (chunkWorkerData.fetchCalls?.length) {
678
+ for (const item of chunkWorkerData.fetchCalls)
679
+ allFetchCalls.push(item);
680
+ }
681
+ if (chunkWorkerData.fetchWrapperDefs?.length) {
682
+ for (const item of chunkWorkerData.fetchWrapperDefs)
683
+ allFetchWrapperDefs.push(item);
684
+ }
685
+ if (chunkWorkerData.routes?.length) {
686
+ for (const item of chunkWorkerData.routes)
687
+ allExtractedRoutes.push(item);
688
+ }
689
+ if (chunkWorkerData.decoratorRoutes?.length) {
690
+ for (const item of chunkWorkerData.decoratorRoutes)
691
+ allDecoratorRoutes.push(item);
692
+ }
693
+ if (chunkWorkerData.routerIncludes?.length) {
694
+ for (const item of chunkWorkerData.routerIncludes)
695
+ allRouterIncludes.push(item);
696
+ }
697
+ if (chunkWorkerData.routerImports?.length) {
698
+ for (const item of chunkWorkerData.routerImports)
699
+ allRouterImports.push(item);
700
+ }
701
+ if (chunkWorkerData.routerConstructorPrefixes?.length) {
702
+ for (const item of chunkWorkerData.routerConstructorPrefixes) {
703
+ allRouterConstructorPrefixes.push(item);
704
+ }
705
+ }
706
+ if (chunkWorkerData.routerModuleAliases?.length) {
707
+ for (const item of chunkWorkerData.routerModuleAliases)
708
+ allRouterModuleAliases.push(item);
709
+ }
710
+ if (chunkWorkerData.moduleConstants?.length) {
711
+ for (const item of chunkWorkerData.moduleConstants)
712
+ allModuleConstants.push(item);
713
+ }
714
+ if (chunkWorkerData.springTypes?.length) {
715
+ for (const item of chunkWorkerData.springTypes)
716
+ allSpringTypes.push(item);
717
+ }
718
+ if (chunkWorkerData.toolDefs?.length) {
719
+ for (const item of chunkWorkerData.toolDefs)
720
+ allToolDefs.push(item);
721
+ }
722
+ if (chunkWorkerData.ormQueries?.length) {
723
+ for (const item of chunkWorkerData.ormQueries)
724
+ allORMQueries.push(item);
725
+ }
726
+ }
727
+ filesParsedSoFar += chunkFiles.length;
728
+ if (verboseThroughputLog && chunkStartMs !== null) {
729
+ const elapsedMs = Date.now() - chunkStartMs;
730
+ const filesPerSec = elapsedMs > 0 ? (chunkFiles.length * 1000) / elapsedMs : 0;
731
+ const stats = workerPool?.getStats?.();
732
+ const poolFrag = stats
733
+ ? ` pool: ${stats.activeSlots}/${stats.size} active, ` +
734
+ `${stats.quarantined} quarantined${stats.poolBroken ? ', BROKEN' : ''}`
735
+ : ' (cache replay)';
736
+ logger_js_1.logger.info(`📊 chunk ${chunkIdx + 1}/${numChunks}: ${chunkFiles.length} files in ${elapsedMs}ms ` +
737
+ `(${filesPerSec.toFixed(1)} files/s)${poolFrag}`);
738
+ }
739
+ };
740
+ // Merge + finalize a parked worker chunk: graph merge (the overlapped
741
+ // main-thread step) → parse-cache write-guard → run-level aggregation.
742
+ const finalizeWorkerChunk = async (p) => {
743
+ const chunkWorkerData = (0, parsing_processor_js_1.mergeChunkResults)(graph, symbolTable, p.rawResults, exportedTypeMap);
744
+ // Persist raw results for this chunk hash (skipping when any chunk file
745
+ // was worker-quarantined, so the narrower rawResults isn't cached under
746
+ // the full-chunk key).
747
+ if (parseCache && p.chunkHash && p.rawResults.length > 0) {
748
+ const quarantineSet = new Set(workerPool?.getQuarantinedPaths?.() ?? []);
749
+ const chunkHadQuarantine = p.chunkFiles.some((f) => quarantineSet.has(f.path));
750
+ if (chunkHadQuarantine) {
751
+ if (env_js_1.isDev) {
752
+ const quarantinedInChunk = p.chunkFiles.filter((f) => quarantineSet.has(f.path)).length;
753
+ logger_js_1.logger.info(`📦 parse-cache SKIP: chunk ${p.chunkIdx + 1}/${numChunks} ` +
754
+ `had ${quarantinedInChunk} worker-quarantined file(s); ` +
755
+ `next run will rediscover (${p.chunkHash.slice(0, 8)})`);
756
+ }
757
+ }
758
+ else {
759
+ await (0, parse_cache_js_1.persistParseCacheChunk)(parseCache, p.chunkHash, p.rawResults);
760
+ if (env_js_1.isDev) {
761
+ logger_js_1.logger.info(`📦 parse-cache MISS+store: chunk ${p.chunkIdx + 1}/${numChunks} (${p.chunkFiles.length} files, ${p.chunkHash.slice(0, 8)})`);
762
+ }
763
+ }
764
+ }
765
+ await applyChunkResults(chunkWorkerData, p.chunkIdx, p.chunkFiles, p.chunkStartMs);
766
+ };
767
+ for (let chunkIdx = 0; chunkIdx < numChunks; chunkIdx++) {
768
+ if (heapProbeEveryN > 0 && chunkIdx > 0 && chunkIdx % heapProbeEveryN === 0) {
769
+ (0, heap_probe_js_1.logHeapProbe)(`parse-chunk-${chunkIdx}`, `nodes=${graph.nodeCount} parsedFiles=${allParsedFiles.length}`);
770
+ }
771
+ // #2649 mid-loop heap guard: fail actionably BEFORE V8 enters the
772
+ // ineffective-mark-compact death spiral (which also falsely times out
773
+ // healthy workers). The pool is torn down by this function's finally.
774
+ const heapUsedNow = process.memoryUsage().heapUsed;
775
+ const heapLimitNow = node_v8_1.default.getHeapStatistics().heap_size_limit;
776
+ if (shouldAbortForHeapPressure(heapUsedNow, heapLimitNow)) {
777
+ throw new Error(`Analyze stopped before running out of memory: ${Math.round(heapUsedNow / 1024 / 1024)}MB of the ` +
778
+ `${Math.round(heapLimitNow / 1024 / 1024)}MB Node heap in use at parse chunk ${chunkIdx + 1}/${numChunks} (#2649). ` +
779
+ heapPressureRemedy(heapLimitNow));
780
+ }
781
+ const chunkPaths = chunks[chunkIdx];
782
+ // Start wall-clock for the per-chunk throughput log emitted at end
783
+ // of this iteration. The gate is computed once above; here we just
784
+ // sample the clock if the gate is on. Computed when either
785
+ // NODE_ENV=development OR the operator passed `--verbose`
786
+ // (CGRAPH_VERBOSE) — the previous `isDev`-only gate meant
787
+ // operators running `cgraph analyze --verbose` in production
788
+ // never saw the log (M3 from PR #1693 review).
789
+ const chunkStartMs = verboseThroughputLog ? Date.now() : null;
790
+ const chunkContentPromise = chunkContentPromises[chunkIdx];
791
+ if (!chunkContentPromise) {
792
+ throw new Error(`Missing prefetched parse chunk ${chunkIdx + 1}/${numChunks}`);
793
+ }
794
+ const chunkContents = await chunkContentPromise;
795
+ chunkContentPromises[chunkIdx] = undefined; // release the in-memory copy
796
+ startChunkPrefetch(chunkIdx + parseChunkConcurrency);
797
+ const chunkFiles = [];
798
+ for (const p of chunkPaths) {
799
+ const content = chunkContents.get(p);
800
+ if (content !== undefined)
801
+ chunkFiles.push({ path: p, content });
802
+ }
803
+ // Compute the chunk's content-hash signature (if cache available).
804
+ let chunkHash = null;
805
+ if (parseCache) {
806
+ const entries = chunkFiles.map((f) => ({
807
+ filePath: f.path,
808
+ contentHash: (0, parse_cache_js_1.fileContentHash)(f.content),
809
+ }));
810
+ chunkHash = (0, parse_cache_js_1.computeChunkHash)(entries, false);
811
+ }
812
+ const cachedRaw = chunkHash && parseCache ? await (0, parse_cache_js_1.loadParseCacheChunk)(parseCache, chunkHash) : undefined;
813
+ // Track every chunk hash we touched so the orchestrator can
814
+ // prune stale entries (chunks whose composition no longer
815
+ // corresponds to a live chunk in the current scan) before saving.
816
+ if (parseCache && chunkHash)
817
+ parseCache.usedKeys.add(chunkHash);
818
+ // A parse-cache hit may skip the workers ONLY if the chunk's ParsedFiles
819
+ // are recoverable without a main-thread re-parse: restored from a durable
820
+ // shard (store path) or carried in the cached result (no-store path). If a
821
+ // cached chunk's durable shards are missing — first run after the durable
822
+ // store was introduced, or a pruned/version-stale shard — fall through to
823
+ // a worker re-dispatch to repopulate them. NEVER let scope-resolution
824
+ // re-extract on the main thread (the #1983 OOM the durable store closes).
825
+ const durableHit = chunkHash !== null && durableParsedFileDir !== undefined && durableHitKeys.has(chunkHash);
826
+ if (cachedRaw && cachedRaw.length > 0 && (durableHit || parsedFileStorePath === undefined)) {
827
+ // Cache hit: replay cached worker output. Finalize any parked worker
828
+ // chunk FIRST so deferred aggregation stays in chunk order, then merge
829
+ // + apply this hit inline (no worker dispatch to overlap).
830
+ if (pendingWorkerChunk) {
831
+ await finalizeWorkerChunk(pendingWorkerChunk);
832
+ pendingWorkerChunk = null;
833
+ }
834
+ chunkCacheHits++;
835
+ const chunkWorkerData = (0, parsing_processor_js_1.mergeChunkResults)(graph, symbolTable, cachedRaw, exportedTypeMap);
836
+ if (env_js_1.isDev) {
837
+ logger_js_1.logger.info(`📦 parse-cache HIT: chunk ${chunkIdx + 1}/${numChunks} (${chunkFiles.length} files, ${chunkHash?.slice(0, 8) ?? 'unknown'})`);
838
+ }
839
+ // Progress update so UI advances even on a cache hit.
840
+ const cachedFiles = chunkFiles.length;
841
+ onProgress({
842
+ phase: 'parsing',
843
+ // Parse phase covers 20-70 (50 points). Deferred extraction below
844
+ // takes 70-95 so the UI advances through the (potentially long)
845
+ // resolution stages instead of holding at 82 (M2 from PR #1693
846
+ // review).
847
+ percent: Math.round(20 + ((filesParsedSoFar + cachedFiles) / totalParseable) * 50),
848
+ message: `Parsing chunk ${chunkIdx + 1}/${numChunks} (cache)...`,
849
+ stats: {
850
+ filesProcessed: filesParsedSoFar + cachedFiles,
851
+ totalFiles: totalParseable,
852
+ nodesCreated: graph.nodeCount,
853
+ },
854
+ });
855
+ // Restore the chunk's durable ParsedFile shards into the run-scoped
856
+ // store so scope-resolution finds full coverage with ZERO main-thread
857
+ // re-parse. A verbatim byte copy — byte-identical to a cold run.
858
+ if (durableHit && durableParsedFileDir && parsedFileStorePath && chunkHash) {
859
+ const restored = await (0, parsedfile_store_js_1.restoreDurableParsedFileShard)(durableParsedFileDir, parsedFileStorePath, chunkHash);
860
+ if (restored === 0) {
861
+ logger_js_1.logger.warn(`parsedfile-cache: durable shards missing for cached chunk ` +
862
+ `${chunkHash.slice(0, 8)} — scope-resolution will re-extract these files`);
863
+ }
864
+ }
865
+ await applyChunkResults(chunkWorkerData, chunkIdx, chunkFiles, chunkStartMs);
866
+ }
867
+ else {
868
+ // Cache miss: dispatch to workers, capture the raw results, store
869
+ // them under the chunk hash for the next run.
870
+ chunkCacheMisses++;
871
+ if (durableParsedFileDir !== undefined && chunkHash !== null) {
872
+ try {
873
+ await (0, parsedfile_store_js_1.prepareDurableParsedFileChunk)(durableParsedFileDir, chunkHash);
874
+ }
875
+ catch (err) {
876
+ // The durable store is an optimization — degrade like the restore
877
+ // path does instead of failing the analyze. Workers recreate the
878
+ // directory on write, so at worst the old generation lingers.
879
+ logger_js_1.logger.warn({ err, chunkHash: chunkHash.slice(0, 8) }, 'parsedfile-cache: could not reset durable chunk generation; continuing');
880
+ }
881
+ }
882
+ const progressForChunk = (current, _total, filePath) => {
883
+ const globalCurrent = filesParsedSoFar + current;
884
+ // Parse phase covers 20-70 (M2). Deferred extraction handles 70-95.
885
+ const parsingProgress = 20 + (globalCurrent / totalParseable) * 50;
886
+ onProgress({
887
+ phase: 'parsing',
888
+ percent: Math.round(parsingProgress),
889
+ message: `Parsing chunk ${chunkIdx + 1}/${numChunks}...`,
890
+ detail: filePath,
891
+ stats: {
892
+ filesProcessed: globalCurrent,
893
+ totalFiles: totalParseable,
894
+ nodesCreated: graph.nodeCount,
895
+ },
896
+ });
897
+ };
898
+ const activeWorkerPool = getOrCreateWorkerPool();
899
+ // Worker path — PIPELINE: kick off this chunk's dispatch, merge the
900
+ // PREVIOUS chunk while these workers parse, then park this chunk for
901
+ // the next iteration to merge (overlapping its parse). The deferred
902
+ // merge + parse-cache write-guard + aggregation all run in
903
+ // `finalizeWorkerChunk`, in chunk order. The pool is the sole parse
904
+ // path — `getOrCreateWorkerPool` returns a pool or throws.
905
+ const dispatchPromise = (0, parsing_processor_js_1.dispatchChunkParse)(chunkFiles, activeWorkerPool, progressForChunk, undefined, chunkHash ?? undefined);
906
+ // Mark handled so a rejection during the overlap drain below isn't
907
+ // flagged as unhandled; the `await` re-throws it for real handling.
908
+ dispatchPromise.catch(() => { });
909
+ if (pendingWorkerChunk) {
910
+ await finalizeWorkerChunk(pendingWorkerChunk);
911
+ pendingWorkerChunk = null;
912
+ }
913
+ let chunkResults;
914
+ try {
915
+ chunkResults = await dispatchPromise;
916
+ }
917
+ catch (err) {
918
+ if (!(err instanceof worker_pool_js_1.WorkerPoolInitializationError))
919
+ throw err;
920
+ // Every worker crashed during startup and the pool's bounded
921
+ // self-heal was exhausted. Fail fast (#1741) — there is no sequential
922
+ // parser to degrade to. `handleWorkerStartupFailure` always throws, so
923
+ // `chunkResults` stays definitely assigned for the parked chunk below.
924
+ handleWorkerStartupFailure(err);
925
+ }
926
+ pendingWorkerChunk = {
927
+ rawResults: chunkResults,
928
+ chunkIdx,
929
+ chunkHash,
930
+ chunkFiles,
931
+ chunkStartMs,
932
+ };
933
+ }
934
+ // (Per-chunk aggregation + parse-cache write + throughput log now run in
935
+ // `applyChunkResults` / `finalizeWorkerChunk` — see the merge-pipelining
936
+ // block above. Route/import/inheritance edges are emitted later: route
937
+ // resolution in the single end-of-loop pass below, the rest by the
938
+ // scope-resolution phase, RING4-2 #943.)
939
+ }
940
+ // Drain the final parked worker chunk — the last pipelined chunk has no
941
+ // successor to overlap its merge with, so merge + finalize it here.
942
+ if (pendingWorkerChunk) {
943
+ await finalizeWorkerChunk(pendingWorkerChunk);
944
+ pendingWorkerChunk = null;
945
+ }
946
+ // The summary line is always logged (not gated by isDev) because it is the
947
+ // ONLY production-visible signal that the content-addressed parse cache is
948
+ // alive — one line per run, zero noise. Without it a warm re-analyze shows
949
+ // no evidence of cache hits and the modest total speedup looks like OS
950
+ // file caching, which has caused misdiagnosis of the cache as broken.
951
+ // Per-chunk HIT/MISS+store logs stay dev-only (verbose on large repos).
952
+ if (parseCache && (chunkCacheHits > 0 || chunkCacheMisses > 0)) {
953
+ logger_js_1.logger.info(`📦 parse-cache summary: ${chunkCacheHits} chunk hit(s), ${chunkCacheMisses} miss(es) across ${numChunks} chunk(s)`);
954
+ }
955
+ (0, heap_probe_js_1.logHeapProbe)('post-parse-chunks', `routes=${allExtractedRoutes.length} nodes=${graph.nodeCount} parsedFiles=${allParsedFiles.length}`);
956
+ // Deferred end-of-loop extraction (moved out of the per-chunk block):
957
+ // 1. route resolution on all chunks' routes
958
+ // Resolution sees the full repo graph instead of just current-and-earlier
959
+ // chunks. Import, call, and inheritance edges are emitted by the
960
+ // scope-resolution phase, not here (RING4-1 #942 removed the legacy call
961
+ // DAG; RING4-2 #943 removed the legacy import-map resolution + wildcard
962
+ // synthesis). Progress band: the route stage gets a slice of the 70-95
963
+ // range; a zero-length input leaves its band as a no-op jump.
964
+ // routes: 80 -> 85 (5)
965
+ const deferredProfile = (0, deferred_resolution_profile_js_1.isDeferredResolutionProfileEnabled)();
966
+ if (deferredProfile) {
967
+ (0, deferred_resolution_profile_js_1.logDeferredProfile)(`deferred band start: routes=${allExtractedRoutes.length}`);
968
+ }
969
+ // Populate `exportedTypeMap` from the in-progress graph so the post-parse
970
+ // enrichment pass (enrichExportedTypeMap) sees cross-file export types.
971
+ if (exportedTypeMap.size === 0 && graph.nodeCount > 0) {
972
+ (0, heap_probe_js_1.logHeapProbe)('pre-buildExportedTypeMapFromGraph');
973
+ const graphExports = (0, call_processor_js_1.buildExportedTypeMapFromGraph)(graph, model.symbols);
974
+ for (const [fp, exports] of graphExports)
975
+ exportedTypeMap.set(fp, exports);
976
+ (0, heap_probe_js_1.logHeapProbe)('post-buildExportedTypeMapFromGraph');
977
+ }
978
+ // Whole-repo, cross-file route extraction (e.g. Django) runs on the main
979
+ // thread — the worker has no filesystem access and can't follow `include()`
980
+ // chains across files. Merge its routes in before `processRoutesFromExtracted`
981
+ // and the routes phase consume `allExtractedRoutes`.
982
+ const crossFileRoutes = await extractCrossFileRoutes(allPaths, repoPath);
983
+ if (crossFileRoutes.length > 0) {
984
+ for (const r of crossFileRoutes)
985
+ allExtractedRoutes.push(r);
986
+ if (deferredProfile) {
987
+ (0, deferred_resolution_profile_js_1.logDeferredProfile)(`cross-file routes: +${crossFileRoutes.length}`);
988
+ }
989
+ }
990
+ if (allExtractedRoutes.length > 0) {
991
+ const tRoutes = (0, deferred_resolution_profile_js_1.startTimer)(deferredProfile);
992
+ await (0, call_processor_js_1.processRoutesFromExtracted)(graph, allExtractedRoutes, model, (current, total) => {
993
+ const ratio = total > 0 ? current / total : 1;
994
+ onProgress({
995
+ phase: 'parsing',
996
+ percent: 80 + Math.round(ratio * 5),
997
+ message: 'Resolving routes (all chunks)...',
998
+ detail: `${current}/${total} routes`,
999
+ stats: {
1000
+ filesProcessed: filesParsedSoFar,
1001
+ totalFiles: totalParseable,
1002
+ nodesCreated: graph.nodeCount,
1003
+ },
1004
+ });
1005
+ });
1006
+ (0, deferred_resolution_profile_js_1.endTimer)(tRoutes, (ms) => `processRoutesFromExtracted: ${ms.toFixed(0)}ms (${allExtractedRoutes.length} routes)`);
1007
+ }
1008
+ }
1009
+ finally {
1010
+ await workerPool?.terminate();
1011
+ }
1012
+ // Fetch calls + ORM queries were already extracted inside each worker
1013
+ // (returned in ParseWorkerResult, aggregated per chunk in applyChunkResults).
1014
+ // With sequential parsing removed there is no post-loop drain to run — only
1015
+ // the TypeEnv finalize + enrichment that the drain's `finally` used to host.
1016
+ // Finalize the accumulator and propagate any fixpoint-inferred exports before
1017
+ // `crossFile` disposes it downstream. Wrapped in try/catch so a cleanup
1018
+ // failure never masks a real parse error; disposal stays with `crossFile`.
1019
+ try {
1020
+ bindingAccumulator.finalize();
1021
+ const enriched = (0, binding_accumulator_js_1.enrichExportedTypeMap)(bindingAccumulator, graph, exportedTypeMap);
1022
+ if (env_js_1.isDev && enriched > 0) {
1023
+ logger_js_1.logger.info(`🔗 Worker TypeEnv enrichment: ${enriched} fixpoint-inferred exports added to ExportedTypeMap`);
1024
+ }
1025
+ }
1026
+ catch (enrichErr) {
1027
+ if (env_js_1.isDev) {
1028
+ logger_js_1.logger.warn({ err: enrichErr.message }, 'Post-parse finalize/enrich failed during cleanup:');
1029
+ }
1030
+ }
1031
+ // Worker-path enrichment: if exportedTypeMap is empty (e.g. the worker pool
1032
+ // built TypeEnv inside workers without access to SymbolTable), reconstruct
1033
+ // the map from graph nodes + SymbolTable here in the main thread before
1034
+ // handing the (now read-only) map to downstream phases. Doing it here means
1035
+ // crossFile receives a fully-populated map and never needs to mutate it for
1036
+ // initial-graph enrichment.
1037
+ if (exportedTypeMap.size === 0 && graph.nodeCount > 0) {
1038
+ const graphExports = (0, call_processor_js_1.buildExportedTypeMapFromGraph)(graph, model.symbols);
1039
+ for (const [fp, exports] of graphExports)
1040
+ exportedTypeMap.set(fp, exports);
1041
+ }
1042
+ // FastAPI router-prefix resolution (cross-file).
1043
+ //
1044
+ // #2391: resolve non-literal FastAPI decorator route paths (imported/composed
1045
+ // string constants) BEFORE the include_router/APIRouter prefix pass below, so a
1046
+ // resolved path is then prefix-joined like any literal path. Each such route
1047
+ // carries `routePathExpr`/`routePathOperands` and an empty `routePath`; we fold
1048
+ // the operands against the repo-wide, file-path-keyed constant map. On failure
1049
+ // we DROP the route (KTD5 skip floor) rather than emit a phantom `POST /`.
1050
+ if (allDecoratorRoutes.some((dr) => dr.routePathExpr !== undefined)) {
1051
+ const repoConstants = new Map();
1052
+ for (const { filePath, constants } of allModuleConstants) {
1053
+ repoConstants.set(filePath, constants);
1054
+ }
1055
+ const resolvedRoutes = [];
1056
+ let skipped = 0;
1057
+ for (const dr of allDecoratorRoutes) {
1058
+ if (dr.routePathExpr === undefined) {
1059
+ resolvedRoutes.push(dr);
1060
+ continue;
1061
+ }
1062
+ const value = dr.routePathOperands
1063
+ ? (0, python_const_resolver_js_1.resolveOperands)(dr.filePath, dr.routePathOperands, repoConstants)
1064
+ : null;
1065
+ if (value === null) {
1066
+ skipped++;
1067
+ continue;
1068
+ }
1069
+ resolvedRoutes.push({ ...dr, routePath: value });
1070
+ }
1071
+ allDecoratorRoutes.length = 0;
1072
+ for (const dr of resolvedRoutes)
1073
+ allDecoratorRoutes.push(dr);
1074
+ if (env_js_1.isDev && skipped > 0) {
1075
+ logger_js_1.logger.info(` 🧩 Resolved composed route constants; ${skipped} unresolved route(s) skipped`);
1076
+ }
1077
+ }
1078
+ // Workers emit two kinds of records per Python file:
1079
+ // • `routerIncludes` — every `app.include_router(<routerExpr>, prefix='/x')`
1080
+ // site, where `routerExpr` is either `<module>.router` (Shape A) or a
1081
+ // bare local name (Shape B).
1082
+ // • `routerImports` — every `from <module> import router [as <alias>]`,
1083
+ // mapping a local name to a module key (the basename of the source
1084
+ // module). These let us resolve Shape-B router includes back to the
1085
+ // module that defines the router.
1086
+ //
1087
+ // We build `module-basename → Set<prefix>` and then walk
1088
+ // `allDecoratorRoutes`: any decorator route emitted from a `router.<verb>`
1089
+ // decorator inherits its file-basename's prefix. When a router is mounted
1090
+ // under multiple prefixes we duplicate the route entry, mirroring FastAPI's
1091
+ // runtime behaviour.
1092
+ if ((allRouterIncludes.length > 0 || allRouterConstructorPrefixes.length > 0) &&
1093
+ allDecoratorRoutes.length > 0) {
1094
+ const importsByFile = new Map();
1095
+ for (const imp of allRouterImports) {
1096
+ let m = importsByFile.get(imp.filePath);
1097
+ if (!m) {
1098
+ m = new Map();
1099
+ importsByFile.set(imp.filePath, m);
1100
+ }
1101
+ m.set(imp.localName, {
1102
+ moduleKey: imp.moduleKey,
1103
+ moduleKeyLong: imp.moduleKeyLong,
1104
+ });
1105
+ }
1106
+ // Module-alias map keyed by file: `localName` (the imported module
1107
+ // identifier in this file) → long key. Shape-A receivers like
1108
+ // `users.router` are matched against this map; the long key, when
1109
+ // present, scopes the prefix to the precise source file.
1110
+ const moduleAliasesByFile = new Map();
1111
+ for (const alias of allRouterModuleAliases) {
1112
+ let m = moduleAliasesByFile.get(alias.filePath);
1113
+ if (!m) {
1114
+ m = new Map();
1115
+ moduleAliasesByFile.set(alias.filePath, m);
1116
+ }
1117
+ m.set(alias.localName, alias.moduleKeyLong);
1118
+ }
1119
+ // Two parallel maps: long-key (precise) and short-key (basename
1120
+ // fallback). Long-key entries are preferred when the file's own long
1121
+ // key matches; short-key entries match any file with that basename and
1122
+ // remain the fallback when no long key is known (e.g. Shape A includes
1123
+ // without a corresponding import statement).
1124
+ const prefixesByLongKey = new Map();
1125
+ const prefixesByShortKey = new Map();
1126
+ // Constructor prefixes are `router`-only (the apply gate below and the
1127
+ // group-layer tree-sitter both pin to the literal name `router`), so a
1128
+ // flat file-key → prefix map suffices — mirrors the group layer's shape.
1129
+ const constructorPrefixesByLongKey = new Map();
1130
+ const constructorPrefixesByShortKey = new Map();
1131
+ const recordPrefix = (target, key, prefix) => {
1132
+ let set = target.get(key);
1133
+ if (!set) {
1134
+ set = new Set();
1135
+ target.set(key, set);
1136
+ }
1137
+ set.add(prefix);
1138
+ };
1139
+ for (const inc of allRouterIncludes) {
1140
+ // Shape A: `<module>.router`. The worker emits `routerExpr` already
1141
+ // including `.router`, so split it back. We only know a short module
1142
+ // key here — the call site doesn't carry the dotted package path. If
1143
+ // the same file imports `<module>` via `from <pkg> import <module>`
1144
+ // (recorded in `allRouterModuleAliases`) we promote to a long key.
1145
+ const dotIdx = inc.routerExpr.indexOf('.router');
1146
+ if (dotIdx > 0) {
1147
+ const moduleShort = inc.routerExpr.slice(0, dotIdx);
1148
+ const aliasLong = moduleAliasesByFile.get(inc.filePath)?.get(moduleShort);
1149
+ if (aliasLong) {
1150
+ recordPrefix(prefixesByLongKey, aliasLong, inc.prefix);
1151
+ }
1152
+ else {
1153
+ recordPrefix(prefixesByShortKey, moduleShort, inc.prefix);
1154
+ }
1155
+ continue;
1156
+ }
1157
+ // Shape B: bare local name. Resolve through this file's imports. The
1158
+ // import line gives us a long key whenever the module path was multi-
1159
+ // segment, so cross-package collisions are eliminated for Shape B.
1160
+ const localImp = importsByFile.get(inc.filePath)?.get(inc.routerExpr);
1161
+ if (!localImp)
1162
+ continue;
1163
+ if (localImp.moduleKeyLong) {
1164
+ recordPrefix(prefixesByLongKey, localImp.moduleKeyLong, inc.prefix);
1165
+ }
1166
+ else {
1167
+ recordPrefix(prefixesByShortKey, localImp.moduleKey, inc.prefix);
1168
+ }
1169
+ }
1170
+ if (prefixesByLongKey.size > 0 ||
1171
+ prefixesByShortKey.size > 0 ||
1172
+ allRouterConstructorPrefixes.length > 0) {
1173
+ const fileLongKey = (rel) => {
1174
+ // Strip `.py`, then take the last two path segments. `api/users.py`
1175
+ // → `api/users`. Files at the repo root return the empty string,
1176
+ // which can never match a long-key entry (those always include a
1177
+ // parent directory) and so fall through to the short-key lookup.
1178
+ const noExt = rel.endsWith('.py') ? rel.slice(0, -3) : rel;
1179
+ const lastSlash = noExt.lastIndexOf('/');
1180
+ if (lastSlash < 0)
1181
+ return '';
1182
+ const beforeLast = noExt.slice(0, lastSlash);
1183
+ const stem = noExt.slice(lastSlash + 1);
1184
+ const prevSlash = beforeLast.lastIndexOf('/');
1185
+ const parent = prevSlash >= 0 ? beforeLast.slice(prevSlash + 1) : beforeLast;
1186
+ return `${parent}/${stem}`;
1187
+ };
1188
+ const fileShortKey = (rel) => {
1189
+ const slash = rel.lastIndexOf('/');
1190
+ const file = slash >= 0 ? rel.slice(slash + 1) : rel;
1191
+ return file.endsWith('.py') ? file.slice(0, -3) : file;
1192
+ };
1193
+ for (const ctor of allRouterConstructorPrefixes) {
1194
+ const longKey = fileLongKey(ctor.filePath);
1195
+ if (longKey) {
1196
+ constructorPrefixesByLongKey.set(longKey, ctor.prefix);
1197
+ }
1198
+ else {
1199
+ constructorPrefixesByShortKey.set(fileShortKey(ctor.filePath), ctor.prefix);
1200
+ }
1201
+ }
1202
+ const expanded = [];
1203
+ for (const dr of allDecoratorRoutes) {
1204
+ if (dr.decoratorReceiver !== 'router' || !dr.filePath.endsWith('.py')) {
1205
+ expanded.push(dr);
1206
+ continue;
1207
+ }
1208
+ // Long-key lookup first; only fall back to the short key when no
1209
+ // long-key prefix targets this file. This avoids prefix leakage
1210
+ // between e.g. `api/users.py` and `admin/users.py`.
1211
+ const longKey = fileLongKey(dr.filePath);
1212
+ const longPrefixes = longKey ? prefixesByLongKey.get(longKey) : undefined;
1213
+ const shortPrefixes = longPrefixes
1214
+ ? undefined
1215
+ : prefixesByShortKey.get(fileShortKey(dr.filePath));
1216
+ const prefixes = longPrefixes ?? shortPrefixes;
1217
+ // Constructor prefixes are keyed like include_router prefixes:
1218
+ // long-key entries are precise, while short-key entries are only
1219
+ // valid for repo-root/single-segment files where `fileLongKey`
1220
+ // returns ''. Do not fall back from a missing long-key match to the
1221
+ // short key or a root `users.py` prefix can leak onto
1222
+ // `admin/users.py`.
1223
+ const constructorPrefix = longKey
1224
+ ? constructorPrefixesByLongKey.get(longKey)
1225
+ : constructorPrefixesByShortKey.get(fileShortKey(dr.filePath));
1226
+ const routePath = constructorPrefix
1227
+ ? (0, route_path_js_1.normalizeExtractedRoutePath)(dr.routePath, constructorPrefix)
1228
+ : dr.routePath;
1229
+ if (!prefixes || prefixes.size === 0) {
1230
+ expanded.push(routePath === dr.routePath ? dr : { ...dr, routePath });
1231
+ continue;
1232
+ }
1233
+ for (const prefix of prefixes) {
1234
+ expanded.push({ ...dr, routePath, prefix });
1235
+ }
1236
+ }
1237
+ allDecoratorRoutes.length = 0;
1238
+ for (const dr of expanded)
1239
+ allDecoratorRoutes.push(dr);
1240
+ }
1241
+ }
1242
+ // Cross-file Spring interface-inheritance pass (#2288): a concrete
1243
+ // `@RestController` inherits the `@*Mapping`s declared on the interfaces it
1244
+ // implements. The per-file `SharedSpringType` views collected by the Java
1245
+ // provider's `extractRouteInheritanceTypes` hook are resolved here, project-
1246
+ // wide, into decorator routes attributed to the implementing controller (the
1247
+ // interface's own per-file routes were suppressed at extraction). Mirrors the
1248
+ // group layer via the shared `resolveInheritedSpringRoutes` so both agree.
1249
+ if (allSpringTypes.length > 0) {
1250
+ for (const inherited of (0, spring_shared_js_1.resolveInheritedSpringRoutes)(allSpringTypes)) {
1251
+ allDecoratorRoutes.push({
1252
+ filePath: inherited.filePath,
1253
+ routePath: inherited.path,
1254
+ httpMethod: inherited.method,
1255
+ decoratorName: 'inherited-mapping',
1256
+ lineNumber: 0,
1257
+ handlerName: inherited.methodName,
1258
+ });
1259
+ }
1260
+ }
1261
+ (0, heap_probe_js_1.logHeapProbe)('parse-impl-return', `exportedTypeMap=${exportedTypeMap.size} parsedFiles=${allParsedFiles.length} nodes=${graph.nodeCount}`);
1262
+ // Part 2 (#2138): resolve each route's handler to a real symbol UID now that
1263
+ // the model is fully populated and decorator-route prefixes are finalized.
1264
+ const routeHandlerSymbols = (0, call_processor_js_1.resolveRouteHandlerSymbols)(model, allExtractedRoutes, allDecoratorRoutes);
1265
+ return {
1266
+ exportedTypeMap,
1267
+ allFetchCalls,
1268
+ allFetchWrapperDefs,
1269
+ allExtractedRoutes,
1270
+ allDecoratorRoutes,
1271
+ allToolDefs,
1272
+ allORMQueries,
1273
+ bindingAccumulator,
1274
+ routeHandlerSymbols,
1275
+ model,
1276
+ // Whether a worker pool was actually constructed for this run. False means
1277
+ // no pool was needed: a warm all-cache-hit run replays cached worker output
1278
+ // without spawning workers, or there were no parseable files.
1279
+ usedWorkerPool: workerPool !== undefined,
1280
+ // Per-file ParsedFile artifacts produced by workers' calls to
1281
+ // `extractParsedFile`. Consumed by scope-resolution as a re-extraction
1282
+ // cache: when the file's ParsedFile is here, scope-resolution skips its own
1283
+ // `extractParsedFile` call.
1284
+ parsedFiles: allParsedFiles,
1285
+ };
1286
+ }