gitnexus 1.6.9 → 1.6.10-aptos.1

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 (540) hide show
  1. package/README.md +236 -53
  2. package/dist/_shared/graph/types.d.ts +67 -3
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/index.d.ts +1 -0
  5. package/dist/_shared/index.d.ts.map +1 -1
  6. package/dist/_shared/index.js.map +1 -1
  7. package/dist/_shared/integrations/resilient-fetch.d.ts +3 -1
  8. package/dist/_shared/integrations/resilient-fetch.d.ts.map +1 -1
  9. package/dist/_shared/integrations/resilient-fetch.js +4 -3
  10. package/dist/_shared/integrations/resilient-fetch.js.map +1 -1
  11. package/dist/_shared/language-detection.d.ts.map +1 -1
  12. package/dist/_shared/language-detection.js +2 -0
  13. package/dist/_shared/language-detection.js.map +1 -1
  14. package/dist/_shared/languages.d.ts +2 -0
  15. package/dist/_shared/languages.d.ts.map +1 -1
  16. package/dist/_shared/languages.js +2 -0
  17. package/dist/_shared/languages.js.map +1 -1
  18. package/dist/_shared/lbug/schema-constants.d.ts +2 -2
  19. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  20. package/dist/_shared/lbug/schema-constants.js +8 -0
  21. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  22. package/dist/_shared/pipeline.d.ts +1 -1
  23. package/dist/_shared/pipeline.d.ts.map +1 -1
  24. package/dist/_shared/scope-resolution/callable-flow-site.d.ts +110 -0
  25. package/dist/_shared/scope-resolution/callable-flow-site.d.ts.map +1 -0
  26. package/dist/_shared/scope-resolution/callable-flow-site.js +11 -0
  27. package/dist/_shared/scope-resolution/callable-flow-site.js.map +1 -0
  28. package/dist/_shared/scope-resolution/finalize-algorithm.d.ts +1 -1
  29. package/dist/_shared/scope-resolution/finalize-algorithm.d.ts.map +1 -1
  30. package/dist/_shared/scope-resolution/finalize-algorithm.js +1 -1
  31. package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
  32. package/dist/_shared/scope-resolution/language-classification.d.ts.map +1 -1
  33. package/dist/_shared/scope-resolution/language-classification.js +1 -0
  34. package/dist/_shared/scope-resolution/language-classification.js.map +1 -1
  35. package/dist/_shared/scope-resolution/parsed-file.d.ts +7 -0
  36. package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
  37. package/dist/_shared/scope-resolution/reference-site.d.ts +9 -1
  38. package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -1
  39. package/dist/_shared/scope-resolution/types.d.ts +20 -3
  40. package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
  41. package/dist/cli/ai-context.d.ts +1 -1
  42. package/dist/cli/ai-context.js +25 -44
  43. package/dist/cli/analyze.d.ts +5 -2
  44. package/dist/cli/analyze.js +205 -11
  45. package/dist/cli/clean.js +17 -3
  46. package/dist/cli/cli-message.d.ts +1 -1
  47. package/dist/cli/doctor.d.ts +18 -0
  48. package/dist/cli/doctor.js +96 -5
  49. package/dist/cli/editor-targets.d.ts +17 -2
  50. package/dist/cli/editor-targets.js +44 -0
  51. package/dist/cli/embeddings.d.ts +12 -0
  52. package/dist/cli/embeddings.js +49 -0
  53. package/dist/cli/eval-server.d.ts +23 -1
  54. package/dist/cli/eval-server.js +126 -8
  55. package/dist/cli/help-i18n.js +6 -0
  56. package/dist/cli/i18n/en.d.ts +18 -8
  57. package/dist/cli/i18n/en.js +18 -8
  58. package/dist/cli/i18n/resources.d.ts +28 -8
  59. package/dist/cli/i18n/zh-CN.d.ts +10 -0
  60. package/dist/cli/i18n/zh-CN.js +18 -8
  61. package/dist/cli/index.js +21 -7
  62. package/dist/cli/lazy-action.d.ts +7 -0
  63. package/dist/cli/lazy-action.js +27 -0
  64. package/dist/cli/mcp.js +6 -3
  65. package/dist/cli/move-availability.d.ts +5 -0
  66. package/dist/cli/move-availability.js +11 -0
  67. package/dist/cli/setup.d.ts +8 -0
  68. package/dist/cli/setup.js +230 -32
  69. package/dist/cli/skill-gen.js +38 -18
  70. package/dist/cli/standard-skills.d.ts +76 -0
  71. package/dist/cli/standard-skills.js +45 -0
  72. package/dist/cli/status.d.ts +4 -1
  73. package/dist/cli/status.js +57 -4
  74. package/dist/cli/tool.js +11 -0
  75. package/dist/cli/uninstall.js +77 -18
  76. package/dist/cli/wiki.d.ts +1 -0
  77. package/dist/cli/wiki.js +7 -1
  78. package/dist/config/ignore-service.d.ts +2 -0
  79. package/dist/config/ignore-service.js +27 -0
  80. package/dist/core/analysis-features.d.ts +21 -0
  81. package/dist/core/analysis-features.js +59 -0
  82. package/dist/core/analyzer-identity.d.ts +74 -0
  83. package/dist/core/analyzer-identity.js +1820 -0
  84. package/dist/core/augmentation/engine.js +13 -8
  85. package/dist/core/embeddings/embedder.d.ts +3 -2
  86. package/dist/core/embeddings/embedder.js +24 -7
  87. package/dist/core/embeddings/embedding-identity.d.ts +11 -0
  88. package/dist/core/embeddings/embedding-identity.js +24 -0
  89. package/dist/core/embeddings/embedding-pipeline.d.ts +36 -1
  90. package/dist/core/embeddings/embedding-pipeline.js +100 -9
  91. package/dist/core/embeddings/http-client.d.ts +33 -3
  92. package/dist/core/embeddings/http-client.js +237 -25
  93. package/dist/core/embeddings/node-module-compat.d.ts +25 -0
  94. package/dist/core/embeddings/node-module-compat.js +25 -0
  95. package/dist/core/embeddings/onnxruntime-common-resolver.js +8 -5
  96. package/dist/core/embeddings/onnxruntime-node-resolver.js +33 -7
  97. package/dist/core/embeddings/runtime-install.d.ts +119 -0
  98. package/dist/core/embeddings/runtime-install.js +372 -0
  99. package/dist/core/embeddings/runtime-support.d.ts +48 -17
  100. package/dist/core/embeddings/runtime-support.js +96 -0
  101. package/dist/core/git-staleness.js +1 -1
  102. package/dist/core/group/bridge-db.js +2 -0
  103. package/dist/core/group/extractors/http-patterns/python.js +246 -108
  104. package/dist/core/group/extractors/manifest-extractor.js +4 -0
  105. package/dist/core/incremental/escalation-gate.d.ts +38 -0
  106. package/dist/core/incremental/escalation-gate.js +48 -0
  107. package/dist/core/incremental/shadow-candidates.d.ts +3 -3
  108. package/dist/core/incremental/shadow-candidates.js +3 -3
  109. package/dist/core/incremental/subgraph-extract.d.ts +2 -2
  110. package/dist/core/incremental/subgraph-extract.js +2 -2
  111. package/dist/core/index-freshness.d.ts +5 -0
  112. package/dist/core/index-freshness.js +13 -0
  113. package/dist/core/ingestion/class-extractors/configs/jvm.js +29 -0
  114. package/dist/core/ingestion/cobol/cobol-preprocessor.js +1 -1
  115. package/dist/core/ingestion/cobol/jcl-processor.js +9 -8
  116. package/dist/core/ingestion/cobol-processor.js +27 -26
  117. package/dist/core/ingestion/community-processor.d.ts +51 -1
  118. package/dist/core/ingestion/community-processor.js +323 -64
  119. package/dist/core/ingestion/emit-references.js +7 -2
  120. package/dist/core/ingestion/filesystem-walker.js +4 -0
  121. package/dist/core/ingestion/frameworks/spring/analysis-features.d.ts +3 -0
  122. package/dist/core/ingestion/frameworks/spring/analysis-features.js +7 -0
  123. package/dist/core/ingestion/frameworks/spring/bean-candidates.d.ts +30 -0
  124. package/dist/core/ingestion/frameworks/spring/bean-candidates.js +182 -0
  125. package/dist/core/ingestion/frameworks/spring/bean-catalog.d.ts +12 -0
  126. package/dist/core/ingestion/frameworks/spring/bean-catalog.js +26 -0
  127. package/dist/core/ingestion/frameworks/spring/config-bindings.d.ts +24 -0
  128. package/dist/core/ingestion/frameworks/spring/config-bindings.js +115 -0
  129. package/dist/core/ingestion/languages/c/captures.js +56 -0
  130. package/dist/core/ingestion/languages/c/query.js +17 -0
  131. package/dist/core/ingestion/languages/c/scope-resolver.js +6 -0
  132. package/dist/core/ingestion/languages/cobol/captures.js +93 -0
  133. package/dist/core/ingestion/languages/cobol/scope-resolver.js +7 -0
  134. package/dist/core/ingestion/languages/cpp/captures.js +365 -75
  135. package/dist/core/ingestion/languages/cpp/scope-resolver.js +14 -0
  136. package/dist/core/ingestion/languages/csharp/captures.js +25 -0
  137. package/dist/core/ingestion/languages/dart/captures.js +90 -2
  138. package/dist/core/ingestion/languages/dart/extension-type-preprocess.d.ts +7 -0
  139. package/dist/core/ingestion/languages/dart/extension-type-preprocess.js +30 -0
  140. package/dist/core/ingestion/languages/dart.js +2 -0
  141. package/dist/core/ingestion/languages/go/captures.js +34 -0
  142. package/dist/core/ingestion/languages/index.d.ts +1 -0
  143. package/dist/core/ingestion/languages/index.js +2 -0
  144. package/dist/core/ingestion/languages/java/analysis-features.d.ts +3 -0
  145. package/dist/core/ingestion/languages/java/analysis-features.js +13 -0
  146. package/dist/core/ingestion/languages/java/capture-side-channel.d.ts +22 -0
  147. package/dist/core/ingestion/languages/java/capture-side-channel.js +58 -0
  148. package/dist/core/ingestion/languages/java/captures.d.ts +4 -3
  149. package/dist/core/ingestion/languages/java/captures.js +193 -17
  150. package/dist/core/ingestion/languages/java/package-facts.d.ts +5 -0
  151. package/dist/core/ingestion/languages/java/package-facts.js +9 -0
  152. package/dist/core/ingestion/languages/java/package-siblings.d.ts +3 -16
  153. package/dist/core/ingestion/languages/java/package-siblings.js +8 -147
  154. package/dist/core/ingestion/languages/java/query.js +23 -0
  155. package/dist/core/ingestion/languages/java/scope-resolver.js +23 -0
  156. package/dist/core/ingestion/languages/java/spring-bean-metadata.d.ts +2 -0
  157. package/dist/core/ingestion/languages/java/spring-bean-metadata.js +8 -0
  158. package/dist/core/ingestion/languages/java/spring-config-bindings.d.ts +23 -0
  159. package/dist/core/ingestion/languages/java/spring-config-bindings.js +215 -0
  160. package/dist/core/ingestion/languages/java.js +3 -0
  161. package/dist/core/ingestion/languages/javascript/captures.js +16 -0
  162. package/dist/core/ingestion/languages/javascript/query.js +21 -0
  163. package/dist/core/ingestion/languages/jvm/package-facts.d.ts +35 -0
  164. package/dist/core/ingestion/languages/jvm/package-facts.js +40 -0
  165. package/dist/core/ingestion/languages/jvm/package-siblings.d.ts +14 -0
  166. package/dist/core/ingestion/languages/jvm/package-siblings.js +129 -0
  167. package/dist/core/ingestion/languages/kotlin/capture-side-channel.d.ts +17 -3
  168. package/dist/core/ingestion/languages/kotlin/capture-side-channel.js +42 -8
  169. package/dist/core/ingestion/languages/kotlin/captures.js +59 -0
  170. package/dist/core/ingestion/languages/kotlin/package-facts.d.ts +5 -0
  171. package/dist/core/ingestion/languages/kotlin/package-facts.js +9 -0
  172. package/dist/core/ingestion/languages/kotlin/package-siblings.d.ts +4 -0
  173. package/dist/core/ingestion/languages/kotlin/package-siblings.js +8 -0
  174. package/dist/core/ingestion/languages/kotlin/query.js +19 -0
  175. package/dist/core/ingestion/languages/kotlin/scope-resolver.js +9 -1
  176. package/dist/core/ingestion/languages/kotlin/spring-bean-metadata.d.ts +2 -0
  177. package/dist/core/ingestion/languages/kotlin/spring-bean-metadata.js +8 -0
  178. package/dist/core/ingestion/languages/kotlin.js +5 -6
  179. package/dist/core/ingestion/languages/move.d.ts +1 -0
  180. package/dist/core/ingestion/languages/move.js +27 -0
  181. package/dist/core/ingestion/languages/php/captures.js +40 -0
  182. package/dist/core/ingestion/languages/php/import-decomposer.js +12 -0
  183. package/dist/core/ingestion/languages/php/import-target.d.ts +2 -1
  184. package/dist/core/ingestion/languages/php/import-target.js +110 -2
  185. package/dist/core/ingestion/languages/php/interpret.js +10 -0
  186. package/dist/core/ingestion/languages/php/scope-resolver.js +1 -1
  187. package/dist/core/ingestion/languages/python/captures.d.ts +3 -4
  188. package/dist/core/ingestion/languages/python/captures.js +24 -5
  189. package/dist/core/ingestion/languages/python/interpret.js +4 -0
  190. package/dist/core/ingestion/languages/python/receiver-binding.d.ts +15 -2
  191. package/dist/core/ingestion/languages/python/receiver-binding.js +96 -2
  192. package/dist/core/ingestion/languages/python/simple-hooks.d.ts +5 -5
  193. package/dist/core/ingestion/languages/python/simple-hooks.js +15 -5
  194. package/dist/core/ingestion/languages/ruby/captures.js +42 -0
  195. package/dist/core/ingestion/languages/rust/captures.js +13 -0
  196. package/dist/core/ingestion/languages/rust/interpret.js +18 -0
  197. package/dist/core/ingestion/languages/rust/query.js +9 -0
  198. package/dist/core/ingestion/languages/rust/range-binding.js +6 -2
  199. package/dist/core/ingestion/languages/swift/captures.js +12 -0
  200. package/dist/core/ingestion/languages/typescript/captures.js +21 -0
  201. package/dist/core/ingestion/languages/typescript/nuxt-auto-imports.js +2 -1
  202. package/dist/core/ingestion/languages/typescript/query.js +37 -0
  203. package/dist/core/ingestion/markdown-processor.js +3 -2
  204. package/dist/core/ingestion/model/registration-table.js +1 -0
  205. package/dist/core/ingestion/parsing-processor.d.ts +3 -1
  206. package/dist/core/ingestion/parsing-processor.js +36 -1
  207. package/dist/core/ingestion/pipeline-phases/index.d.ts +2 -0
  208. package/dist/core/ingestion/pipeline-phases/index.js +2 -0
  209. package/dist/core/ingestion/pipeline-phases/parse-impl.js +56 -2
  210. package/dist/core/ingestion/pipeline-phases/parse.d.ts +0 -2
  211. package/dist/core/ingestion/pipeline-phases/parse.js +12 -3
  212. package/dist/core/ingestion/pipeline-phases/processes.d.ts +8 -0
  213. package/dist/core/ingestion/pipeline-phases/processes.js +11 -1
  214. package/dist/core/ingestion/pipeline-phases/spring-config.d.ts +37 -0
  215. package/dist/core/ingestion/pipeline-phases/spring-config.js +433 -0
  216. package/dist/core/ingestion/pipeline-phases/standalone-ingest.d.ts +16 -0
  217. package/dist/core/ingestion/pipeline-phases/standalone-ingest.js +6 -0
  218. package/dist/core/ingestion/pipeline.d.ts +4 -2
  219. package/dist/core/ingestion/pipeline.js +14 -2
  220. package/dist/core/ingestion/resolve-references.js +12 -0
  221. package/dist/core/ingestion/route-extractors/constant-resolver.d.ts +83 -0
  222. package/dist/core/ingestion/route-extractors/constant-resolver.js +131 -0
  223. package/dist/core/ingestion/route-extractors/python-const-resolver.d.ts +75 -0
  224. package/dist/core/ingestion/route-extractors/python-const-resolver.js +299 -0
  225. package/dist/core/ingestion/scope-extractor.js +306 -43
  226. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +71 -2
  227. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.d.ts +7 -7
  228. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +8 -7
  229. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +3 -1
  230. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +6 -0
  231. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +1 -0
  232. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +4 -1
  233. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +7 -2
  234. package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.d.ts +47 -0
  235. package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.js +1138 -0
  236. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +16 -4
  237. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +97 -1
  238. package/dist/core/ingestion/scope-resolution/passes/property-dispatch.d.ts +60 -0
  239. package/dist/core/ingestion/scope-resolution/passes/property-dispatch.js +111 -0
  240. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +4 -3
  241. package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +5 -0
  242. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +25 -38
  243. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +6 -0
  244. package/dist/core/ingestion/scope-resolution/pipeline/run.js +147 -35
  245. package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
  246. package/dist/core/ingestion/scope-resolution/scope/walkers.js +73 -44
  247. package/dist/core/ingestion/taint/typescript-model.js +34 -2
  248. package/dist/core/ingestion/tree-sitter-queries.d.ts +2 -2
  249. package/dist/core/ingestion/tree-sitter-queries.js +23 -2
  250. package/dist/core/ingestion/type-extractors/jvm.js +17 -2
  251. package/dist/core/ingestion/utils/ast-helpers.d.ts +1 -0
  252. package/dist/core/ingestion/utils/ast-helpers.js +153 -2
  253. package/dist/core/ingestion/utils/callable-flow-captures.d.ts +94 -0
  254. package/dist/core/ingestion/utils/callable-flow-captures.js +878 -0
  255. package/dist/core/ingestion/utils/line-base.d.ts +20 -0
  256. package/dist/core/ingestion/utils/line-base.js +20 -0
  257. package/dist/core/ingestion/utils/symbol-labels.d.ts +21 -0
  258. package/dist/core/ingestion/utils/symbol-labels.js +45 -0
  259. package/dist/core/ingestion/workers/parse-worker.d.ts +34 -0
  260. package/dist/core/ingestion/workers/parse-worker.js +40 -5
  261. package/dist/core/ingestion/workers/result-merge.js +4 -0
  262. package/dist/core/ingestion/workers/worker-pool.d.ts +28 -0
  263. package/dist/core/ingestion/workers/worker-pool.js +128 -28
  264. package/dist/core/lbug/csv-generator.d.ts +15 -0
  265. package/dist/core/lbug/csv-generator.js +124 -27
  266. package/dist/core/lbug/cypher-escape.d.ts +20 -0
  267. package/dist/core/lbug/cypher-escape.js +20 -0
  268. package/dist/core/lbug/extension-load-error.d.ts +67 -0
  269. package/dist/core/lbug/extension-load-error.js +326 -0
  270. package/dist/core/lbug/extension-loader.d.ts +17 -2
  271. package/dist/core/lbug/extension-loader.js +38 -13
  272. package/dist/core/lbug/lbug-adapter.d.ts +203 -2
  273. package/dist/core/lbug/lbug-adapter.js +527 -86
  274. package/dist/core/lbug/lbug-config.d.ts +56 -2
  275. package/dist/core/lbug/lbug-config.js +267 -7
  276. package/dist/core/lbug/move-columns.d.ts +7 -0
  277. package/dist/core/lbug/move-columns.js +86 -0
  278. package/dist/core/lbug/native-check.d.ts +40 -0
  279. package/dist/core/lbug/native-check.js +90 -0
  280. package/dist/core/lbug/node-table-layout.d.ts +29 -0
  281. package/dist/core/lbug/node-table-layout.js +119 -0
  282. package/dist/core/lbug/pool-adapter.d.ts +23 -1
  283. package/dist/core/lbug/pool-adapter.js +115 -8
  284. package/dist/core/lbug/schema.d.ts +4 -3
  285. package/dist/core/lbug/schema.js +16 -16
  286. package/dist/core/lbug/sidecar-recovery.d.ts +172 -0
  287. package/dist/core/lbug/sidecar-recovery.js +418 -16
  288. package/dist/core/lbug/wal-checkpoint-driver.js +3 -0
  289. package/dist/core/move/artifact-download.d.ts +19 -0
  290. package/dist/core/move/artifact-download.js +179 -0
  291. package/dist/core/move/compiler-facts.d.ts +120 -0
  292. package/dist/core/move/compiler-facts.js +9 -0
  293. package/dist/core/move/consistency.d.ts +74 -0
  294. package/dist/core/move/consistency.js +182 -0
  295. package/dist/core/move/constants.d.ts +98 -0
  296. package/dist/core/move/constants.js +136 -0
  297. package/dist/core/move/discovery.d.ts +10 -0
  298. package/dist/core/move/discovery.js +22 -0
  299. package/dist/core/move/entry-points.d.ts +14 -0
  300. package/dist/core/move/entry-points.js +40 -0
  301. package/dist/core/move/facts-mapper.d.ts +75 -0
  302. package/dist/core/move/facts-mapper.js +534 -0
  303. package/dist/core/move/install-lock.d.ts +14 -0
  304. package/dist/core/move/install-lock.js +102 -0
  305. package/dist/core/move/install.d.ts +39 -0
  306. package/dist/core/move/install.js +391 -0
  307. package/dist/core/move/mcp-client.d.ts +115 -0
  308. package/dist/core/move/mcp-client.js +436 -0
  309. package/dist/core/move/move-ingest.d.ts +52 -0
  310. package/dist/core/move/move-ingest.js +403 -0
  311. package/dist/core/move/provision.d.ts +19 -0
  312. package/dist/core/move/provision.js +91 -0
  313. package/dist/core/move/release.d.ts +6 -0
  314. package/dist/core/move/release.js +10 -0
  315. package/dist/core/move/symbol-id.d.ts +35 -0
  316. package/dist/core/move/symbol-id.js +65 -0
  317. package/dist/core/move/type-parser.d.ts +11 -0
  318. package/dist/core/move/type-parser.js +38 -0
  319. package/dist/core/platform/capabilities.d.ts +0 -1
  320. package/dist/core/platform/capabilities.js +39 -8
  321. package/dist/core/run-analyze.d.ts +9 -3
  322. package/dist/core/run-analyze.js +1002 -184
  323. package/dist/core/search/fts-indexes.d.ts +31 -0
  324. package/dist/core/search/fts-indexes.js +73 -0
  325. package/dist/core/search/fts-schema.js +2 -0
  326. package/dist/core/tree-sitter/safe-parse.d.ts +8 -3
  327. package/dist/core/tree-sitter/safe-parse.js +21 -7
  328. package/dist/core/wiki/graph-queries.js +6 -5
  329. package/dist/core/wiki/llm-client.d.ts +8 -2
  330. package/dist/core/wiki/llm-client.js +41 -5
  331. package/dist/mcp/core/embedder.js +16 -2
  332. package/dist/mcp/http-transport.d.ts +5 -0
  333. package/dist/mcp/http-transport.js +19 -5
  334. package/dist/mcp/local/bean-metadata.d.ts +2 -0
  335. package/dist/mcp/local/bean-metadata.js +25 -0
  336. package/dist/mcp/local/line-display.d.ts +22 -0
  337. package/dist/mcp/local/line-display.js +3 -0
  338. package/dist/mcp/local/local-backend.d.ts +19 -1
  339. package/dist/mcp/local/local-backend.js +402 -155
  340. package/dist/mcp/local/pdg-impact.d.ts +5 -3
  341. package/dist/mcp/local/pdg-impact.js +5 -2
  342. package/dist/mcp/output-budget.d.ts +5 -0
  343. package/dist/mcp/output-budget.js +52 -0
  344. package/dist/mcp/read-only-policy.d.ts +12 -0
  345. package/dist/mcp/read-only-policy.js +102 -0
  346. package/dist/mcp/repository-policy.d.ts +34 -0
  347. package/dist/mcp/repository-policy.js +328 -0
  348. package/dist/mcp/resources.js +32 -5
  349. package/dist/mcp/server.d.ts +5 -2
  350. package/dist/mcp/server.js +29 -9
  351. package/dist/mcp/tools.d.ts +0 -8
  352. package/dist/mcp/tools.js +102 -5
  353. package/dist/server/analyze-job.d.ts +3 -0
  354. package/dist/server/analyze-job.js +17 -0
  355. package/dist/server/analyze-launch.d.ts +6 -0
  356. package/dist/server/analyze-launch.js +82 -6
  357. package/dist/server/analyze-worker-core.d.ts +2 -1
  358. package/dist/server/analyze-worker-core.js +5 -2
  359. package/dist/server/analyze-worker.js +29 -6
  360. package/dist/server/api.d.ts +30 -0
  361. package/dist/server/api.js +120 -34
  362. package/dist/server/mcp-http.d.ts +1 -1
  363. package/dist/server/mcp-http.js +4 -2
  364. package/dist/server/upload-ingest.js +2 -1
  365. package/dist/server/validation.js +2 -1
  366. package/dist/storage/git.d.ts +31 -0
  367. package/dist/storage/git.js +111 -1
  368. package/dist/storage/parse-cache.js +7 -1
  369. package/dist/storage/parsedfile-store.d.ts +8 -0
  370. package/dist/storage/parsedfile-store.js +165 -1
  371. package/dist/storage/repo-manager.d.ts +194 -2
  372. package/dist/storage/repo-manager.js +56 -1
  373. package/dist/types/pipeline.d.ts +7 -0
  374. package/hooks/antigravity/gitnexus-antigravity-hook.cjs +50 -3
  375. package/hooks/claude/gitnexus-hook.cjs +59 -9
  376. package/hooks/claude/pre-tool-use.sh +0 -0
  377. package/hooks/claude/session-start.sh +0 -0
  378. package/package.json +21 -15
  379. package/scripts/cross-platform-tests.ts +56 -0
  380. package/scripts/ensure-fts.ts +43 -0
  381. package/scripts/install-duckdb-extension.mjs +85 -24
  382. package/scripts/run-cross-platform.ts +61 -6
  383. package/scripts/shard-arg.ts +30 -0
  384. package/scripts/sync-plugin-manifests.mjs +192 -0
  385. package/skills/gitnexus-lfg/README.md +55 -0
  386. package/skills/gitnexus-lfg/SKILL.md +86 -0
  387. package/skills/gitnexus-plan/README.md +142 -0
  388. package/skills/gitnexus-plan/SKILL.md +348 -0
  389. package/skills/gitnexus-plan/references/context-ledger.md +137 -0
  390. package/skills/gitnexus-plan/references/context-pack.md +126 -0
  391. package/skills/gitnexus-plan/references/evidence-provenance.md +272 -0
  392. package/skills/gitnexus-plan/references/pdg-slice.md +109 -0
  393. package/skills/gitnexus-plan/references/plan-template.md +201 -0
  394. package/skills/gitnexus-plan/scripts/evidence-provenance.mjs +2084 -0
  395. package/skills/gitnexus-review/SKILL.md +273 -0
  396. package/skills/gitnexus-review/ci-personas/ci-adversarial-lens.md +42 -0
  397. package/skills/gitnexus-review/ci-personas/ci-blast-radius-lens.md +39 -0
  398. package/skills/gitnexus-review/ci-personas/ci-correctness-lens.md +37 -0
  399. package/skills/gitnexus-review/ci-personas/ci-coverage-lens.md +40 -0
  400. package/skills/gitnexus-review/ci-personas/ci-critic-lens.md +42 -0
  401. package/skills/gitnexus-review/ci-personas/ci-security-lens.md +39 -0
  402. package/skills/gitnexus-work/README.md +71 -0
  403. package/skills/gitnexus-work/SKILL.md +269 -0
  404. package/skills/gitnexus-work/references/evidence-provenance.md +272 -0
  405. package/skills/gitnexus-work/scripts/evidence-provenance.mjs +2084 -0
  406. package/web/assets/ProcessFlowModal-B_bfBySy.js +22 -0
  407. package/web/assets/__vite-browser-external-bMKyYQkO.js +1 -0
  408. package/web/assets/agent-Bqxn-abU.js +626 -0
  409. package/web/assets/architecture-7EHR7CIX-6QZW5X65-BVWFvYz2.js +1 -0
  410. package/web/assets/architectureDiagram-UL44E2DR-CmG3uPWf.js +36 -0
  411. package/web/assets/{blockDiagram-7IZFK4PR-BkWhpzWB.js → blockDiagram-7IZFK4PR-DBefcjof.js} +7 -7
  412. package/web/assets/{c4Diagram-Y2BXMSZH-DtBvpzWD.js → c4Diagram-Y2BXMSZH-EjWnjEJl.js} +6 -6
  413. package/web/assets/chunk-2T2R6R2M-Bb6Sy3_j.js +4 -0
  414. package/web/assets/chunk-2UTLFMKG-CXlhF3Pt.js +1 -0
  415. package/web/assets/chunk-3SSMPTDK-rPsRM1x0.js +321 -0
  416. package/web/assets/chunk-4R4BOZG6-Be_F0JoX.js +159 -0
  417. package/web/assets/{chunk-6764PJDD-DpIS7hxD.js → chunk-6764PJDD-C7xxk063.js} +1 -1
  418. package/web/assets/chunk-67TQ5CYL-CA7OhIEf.js +124 -0
  419. package/web/assets/chunk-7FYTHRHK-CsmYIswB.js +32 -0
  420. package/web/assets/chunk-7J6CGLKN-BlKwgXKs.js +10 -0
  421. package/web/assets/chunk-7W6UQGC5-pyKGssV3.js +1 -0
  422. package/web/assets/chunk-C62D2QBJ-3gdL8EKc.js +1 -0
  423. package/web/assets/chunk-CEXFNPSA-CjwtMDkc.js +1 -0
  424. package/web/assets/{chunk-INKRHTLW-Nu4ri9P-.js → chunk-INKRHTLW-Ckl3_KkO.js} +13 -13
  425. package/web/assets/chunk-J5EP6P6S-L19oz55R.js +1 -0
  426. package/web/assets/{chunk-KGFNY3KK-JGMJvKCK.js → chunk-KGFNY3KK-BZeP-55u.js} +17 -17
  427. package/web/assets/chunk-KGYTTC2M-zm6n242I.js +1 -0
  428. package/web/assets/{chunk-KRXBNO2N-BW5o0KUN.js → chunk-KRXBNO2N-C-UNuKKf.js} +1 -1
  429. package/web/assets/{chunk-LCXTWHL2-CfLLCywY.js → chunk-LCXTWHL2-C162wE5z.js} +5 -5
  430. package/web/assets/chunk-LII3EMHJ-BL6lKJ_P.js +1 -0
  431. package/web/assets/chunk-LRIF4GLE-n59lhprL.js +1 -0
  432. package/web/assets/chunk-QA3QBVWF-DVXPOIxe.js +2 -0
  433. package/web/assets/chunk-RERM46MO-B5dAdWpP.js +1 -0
  434. package/web/assets/chunk-RG4AUYOV-ZNgyLFq6.js +206 -0
  435. package/web/assets/chunk-RKZBBQEN-MyIQbGgD.js +1 -0
  436. package/web/assets/chunk-RLI5ZMPA-CkXZ0y0U.js +1 -0
  437. package/web/assets/chunk-T2UQINTJ-BEyXhZWe.js +1 -0
  438. package/web/assets/chunk-UP6H54XL-BG-n7qDp.js +1 -0
  439. package/web/assets/chunk-UXSXWOXI-CW1_r5cS.js +1 -0
  440. package/web/assets/chunk-UY5QBCOK-ByqTVLvh.js +1 -0
  441. package/web/assets/chunk-VU6ZFW4Y-BLeasdkU.js +2 -0
  442. package/web/assets/{chunk-W44A43WB-JqMLIpR0.js → chunk-W44A43WB-BN8EQc_u.js} +1 -1
  443. package/web/assets/chunk-ZXARS5L4-C3v-4Fsw.js +1 -0
  444. package/web/assets/classDiagram-KGZ6W3CR-olpO3fMe.js +1 -0
  445. package/web/assets/classDiagram-v2-72OJOZXJ-olpO3fMe.js +1 -0
  446. package/web/assets/cose-bilkent-UX7MHV2Q-BmnZ7Mvj.js +1 -0
  447. package/web/assets/dagre-ND4H6XIP-CY4iIF7v.js +4 -0
  448. package/web/assets/diagram-3NCE3AQN-CO6QpzEE.js +43 -0
  449. package/web/assets/diagram-GF46GFSD-B2atbzmU.js +24 -0
  450. package/web/assets/diagram-HNR7UZ2L-DVRltWbL.js +3 -0
  451. package/web/assets/diagram-QXG6HAR7-DR6AHD2h.js +24 -0
  452. package/web/assets/diagram-WEQXMOUZ-DkpoMwTL.js +10 -0
  453. package/web/assets/erDiagram-L5TCEMPS-n8g_90bc.js +85 -0
  454. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-CgFBM7e-.js +1 -0
  455. package/web/assets/flowDiagram-H6V6AXG4-SGMDiCkB.js +162 -0
  456. package/web/assets/ganttDiagram-JCBTUEKG-Cb3UBqRS.js +292 -0
  457. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DCJv7SII.js +1 -0
  458. package/web/assets/gitGraphDiagram-S2ZK5IYY-Bs9CR7tq.js +106 -0
  459. package/web/assets/index-CX_fADmQ.css +2 -0
  460. package/web/assets/index-D1Z3dGGz.js +575 -0
  461. package/web/assets/info-J43DQDTF-KCYPFFUO-BfNy-9Nd.js +1 -0
  462. package/web/assets/infoDiagram-3YFTVSEB-T368on4D.js +2 -0
  463. package/web/assets/{ishikawaDiagram-BNXS4ZKH-DfYpxnE5.js → ishikawaDiagram-BNXS4ZKH-XpjJRU9h.js} +6 -6
  464. package/web/assets/journeyDiagram-M6C3CM3L-C6wjooas.js +139 -0
  465. package/web/assets/kanban-definition-75IXJCU3-5_UVY79g.js +89 -0
  466. package/web/assets/{katex-K3KEBU37-CTc5BslQ.js → katex-K3KEBU37-qRQBy-EZ.js} +2 -2
  467. package/web/assets/{mindmap-definition-2TDM6QVE-DypvbOMQ.js → mindmap-definition-2TDM6QVE-8xDLzk2e.js} +29 -29
  468. package/web/assets/node-Ct_zna8U.js +8 -0
  469. package/web/assets/packet-YPE3B663-LP52Z2RK-D4qkeG9k.js +1 -0
  470. package/web/assets/pie-LRSECV5Y-TCRJHUBD-B_yMKyQa.js +1 -0
  471. package/web/assets/pieDiagram-CU6KROY3-Bv4LpAbr.js +30 -0
  472. package/web/assets/preload-helper-Czpn1I53.js +1 -0
  473. package/web/assets/{quadrantDiagram-VICAPDV7-yXSZ2lLz.js → quadrantDiagram-VICAPDV7-DR54jOeR.js} +6 -6
  474. package/web/assets/radar-GUYGQ44K-RDLRG3WG-DeD6yN_0.js +1 -0
  475. package/web/assets/requirementDiagram-JXO7QTGE-PEkg7sKC.js +84 -0
  476. package/web/assets/rolldown-runtime-QTnfLwEv.js +1 -0
  477. package/web/assets/sankeyDiagram-URQDO5SZ-DDWEtjcs.js +40 -0
  478. package/web/assets/sdk-CzHHH8tD.js +37 -0
  479. package/web/assets/sequenceDiagram-VS2MUI6T-Bv-uwANx.js +162 -0
  480. package/web/assets/src-JV30wyV8.js +1 -0
  481. package/web/assets/stateDiagram-7D4R322I-DVNjmkEq.js +1 -0
  482. package/web/assets/stateDiagram-v2-36443NZ5-CyN4Fh7_.js +1 -0
  483. package/web/assets/timeline-definition-O6YCAMPW-Qmsuo7qS.js +120 -0
  484. package/web/assets/treeView-BLDUP644-QA4HXRO3-CDuSYnd4.js +1 -0
  485. package/web/assets/treemap-LRROVOQU-LLAWBHMP-imazucyJ.js +1 -0
  486. package/web/assets/vennDiagram-MWXL3ELB-BD1iK1SX.js +34 -0
  487. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-DqrT9tB8.js +1 -0
  488. package/web/assets/wardleyDiagram-CUQ6CDDI-D6TzLVob.js +78 -0
  489. package/web/assets/{xychartDiagram-N2JHSOCM-BOLm0eNm.js → xychartDiagram-N2JHSOCM-CoZ_Tits.js} +6 -6
  490. package/web/index.html +18 -10
  491. package/skills/gitnexus-pr-review.md +0 -163
  492. package/web/assets/agent-Dli_x7bU.js +0 -660
  493. package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +0 -1
  494. package/web/assets/architectureDiagram-UL44E2DR-dEkqUZN9.js +0 -36
  495. package/web/assets/chunk-3SSMPTDK-B4_etUhr.js +0 -321
  496. package/web/assets/chunk-67TQ5CYL-4sNPJU1q.js +0 -124
  497. package/web/assets/chunk-7W6UQGC5-KyEG0HQg.js +0 -1
  498. package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +0 -161
  499. package/web/assets/chunk-LII3EMHJ-D-jm-dLa.js +0 -1
  500. package/web/assets/chunk-QA3QBVWF-BgRW3SXd.js +0 -2
  501. package/web/assets/chunk-RG4AUYOV-CqWzWsV3.js +0 -206
  502. package/web/assets/chunk-T2UQINTJ-DSBqkzH7.js +0 -1
  503. package/web/assets/chunk-UY5QBCOK-DyF0vyGd.js +0 -1
  504. package/web/assets/chunk-ZXARS5L4-CxN8oiwI.js +0 -1
  505. package/web/assets/classDiagram-KGZ6W3CR-CMne4tG9.js +0 -1
  506. package/web/assets/classDiagram-v2-72OJOZXJ-CMne4tG9.js +0 -1
  507. package/web/assets/cose-bilkent-UX7MHV2Q-D71wNYRJ.js +0 -1
  508. package/web/assets/dagre-ND4H6XIP-Co5rRx9X.js +0 -4
  509. package/web/assets/diagram-3NCE3AQN-DBp4O00j.js +0 -43
  510. package/web/assets/diagram-GF46GFSD-6N_8yS0i.js +0 -24
  511. package/web/assets/diagram-HNR7UZ2L-DFCfd5LI.js +0 -3
  512. package/web/assets/diagram-QXG6HAR7-Di093rFg.js +0 -24
  513. package/web/assets/diagram-WEQXMOUZ-DZWi4SUN.js +0 -10
  514. package/web/assets/erDiagram-L5TCEMPS-8X1y6R4Y.js +0 -85
  515. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +0 -1
  516. package/web/assets/flowDiagram-H6V6AXG4-CMpY8Ufn.js +0 -162
  517. package/web/assets/ganttDiagram-JCBTUEKG-D3iL2Aet.js +0 -292
  518. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +0 -1
  519. package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +0 -106
  520. package/web/assets/index-KctnI3Vq.js +0 -635
  521. package/web/assets/index-_lgn7hs5.css +0 -2
  522. package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +0 -1
  523. package/web/assets/infoDiagram-3YFTVSEB-BaLMZkUg.js +0 -2
  524. package/web/assets/journeyDiagram-M6C3CM3L-CvArszLo.js +0 -139
  525. package/web/assets/kanban-definition-75IXJCU3-CpfVLLf9.js +0 -89
  526. package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +0 -1
  527. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +0 -1
  528. package/web/assets/pieDiagram-CU6KROY3-s27EFWgP.js +0 -30
  529. package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +0 -1
  530. package/web/assets/requirementDiagram-JXO7QTGE-CWhqInuf.js +0 -84
  531. package/web/assets/sankeyDiagram-URQDO5SZ-1qEjlFIB.js +0 -40
  532. package/web/assets/sequenceDiagram-VS2MUI6T-RyTlZ5cR.js +0 -162
  533. package/web/assets/stateDiagram-7D4R322I-DTjVfX4A.js +0 -1
  534. package/web/assets/stateDiagram-v2-36443NZ5-xY9_k9_Q.js +0 -1
  535. package/web/assets/timeline-definition-O6YCAMPW-DrrqLYAf.js +0 -120
  536. package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +0 -1
  537. package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +0 -1
  538. package/web/assets/vennDiagram-MWXL3ELB-B0RkWAim.js +0 -34
  539. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +0 -1
  540. package/web/assets/wardleyDiagram-CUQ6CDDI-boUxiQ5F.js +0 -78
@@ -98,6 +98,7 @@ function parseUseClause(clause, qualifier) {
98
98
  if (alias !== '') {
99
99
  return {
100
100
  kind: 'alias',
101
+ symbolKind: symbolKindFor(qualifier),
101
102
  source,
102
103
  name: alias,
103
104
  alias,
@@ -108,6 +109,7 @@ function parseUseClause(clause, qualifier) {
108
109
  }
109
110
  return {
110
111
  kind: qualifier,
112
+ symbolKind: symbolKindFor(qualifier),
111
113
  source,
112
114
  name: lastSegment(source),
113
115
  atNode: clause,
@@ -178,6 +180,7 @@ function parseInnerClause(clause, prefix, qualifier) {
178
180
  if (alias !== '') {
179
181
  return {
180
182
  kind: 'alias',
183
+ symbolKind: symbolKindFor(qualifier),
181
184
  source,
182
185
  name: alias,
183
186
  alias,
@@ -188,6 +191,7 @@ function parseInnerClause(clause, prefix, qualifier) {
188
191
  }
189
192
  return {
190
193
  kind: qualifier,
194
+ symbolKind: symbolKindFor(qualifier),
191
195
  source,
192
196
  name: lastSegment(innerPath),
193
197
  atNode: clause,
@@ -198,6 +202,7 @@ function buildImportMatch(stmtNode, spec) {
198
202
  const m = {
199
203
  '@import.statement': nodeToCapture('@import.statement', stmtNode),
200
204
  '@import.kind': syntheticCapture('@import.kind', spec.atNode, spec.kind),
205
+ '@import.symbol-kind': syntheticCapture('@import.symbol-kind', spec.atNode, spec.symbolKind),
201
206
  '@import.source': syntheticCapture('@import.source', spec.atNode, spec.source),
202
207
  '@import.name': syntheticCapture('@import.name', spec.atNode, spec.name),
203
208
  };
@@ -212,6 +217,13 @@ function lastSegment(path) {
212
217
  const parts = path.split('\\').filter(Boolean);
213
218
  return parts[parts.length - 1] ?? path;
214
219
  }
220
+ function symbolKindFor(kind) {
221
+ if (kind === 'function')
222
+ return 'function';
223
+ if (kind === 'const')
224
+ return 'const';
225
+ return 'type';
226
+ }
215
227
  /** Find the first named child with a given node type. */
216
228
  function findNamedChild(node, type) {
217
229
  for (let i = 0; i < node.namedChildCount; i++) {
@@ -15,6 +15,7 @@
15
15
  * `linkStatus: 'unresolved'`.
16
16
  */
17
17
  import type { ParsedImport, WorkspaceIndex } from '../../../../_shared/index.js';
18
+ import type { ImportResolutionContext } from '../../scope-resolution/contract/scope-resolver.js';
18
19
  import type { ComposerConfig } from '../../language-config.js';
19
20
  export interface PhpResolveContext {
20
21
  readonly fromFile: string;
@@ -44,4 +45,4 @@ export declare function resolvePhpImportTarget(parsedImport: ParsedImport, works
44
45
  * (a `ComposerConfig | null` loaded once per workspace by
45
46
  * `loadPhpComposerConfig`) and threads it into `resolvePhpImportInternal`.
46
47
  */
47
- export declare function resolvePhpImportTargetInternal(targetRaw: string, _fromFile: string, allFilePaths: ReadonlySet<string>, resolutionConfig?: unknown): string | null;
48
+ export declare function resolvePhpImportTargetInternal(targetRaw: string, _fromFile: string, allFilePaths: ReadonlySet<string>, resolutionConfig?: unknown, context?: ImportResolutionContext): string | null;
@@ -17,6 +17,73 @@
17
17
  import { resolvePhpImportInternal } from '../../import-resolvers/php.js';
18
18
  import { readFileSync } from 'node:fs';
19
19
  import { join } from 'node:path';
20
+ function normalizePhpPath(value) {
21
+ return value.replace(/\\/g, '/').replace(/^\.\//, '').replace(/\/+$/, '');
22
+ }
23
+ function namespaceDirectories(targetRaw, composerConfig, resolved) {
24
+ const directories = new Set();
25
+ if (resolved !== null) {
26
+ const normalizedResolved = normalizePhpPath(resolved);
27
+ const separator = normalizedResolved.lastIndexOf('/');
28
+ if (separator >= 0)
29
+ directories.add(normalizedResolved.slice(0, separator));
30
+ }
31
+ if (composerConfig === null)
32
+ return [...directories];
33
+ const normalizedTarget = normalizePhpPath(targetRaw);
34
+ const mappings = [...composerConfig.psr4.entries()].sort((left, right) => {
35
+ const lengthDifference = right[0].length - left[0].length;
36
+ return lengthDifference !== 0 ? lengthDifference : left[0].localeCompare(right[0]);
37
+ });
38
+ for (const [namespacePrefix, directoryPrefix] of mappings) {
39
+ const normalizedPrefix = normalizePhpPath(namespacePrefix);
40
+ if (normalizedTarget !== normalizedPrefix &&
41
+ !normalizedTarget.startsWith(`${normalizedPrefix}/`)) {
42
+ continue;
43
+ }
44
+ const remainder = normalizedTarget.slice(normalizedPrefix.length).replace(/^\//, '');
45
+ const separator = remainder.lastIndexOf('/');
46
+ const relativeNamespace = separator >= 0 ? remainder.slice(0, separator) : '';
47
+ directories.add(normalizePhpPath(relativeNamespace === '' ? directoryPrefix : `${directoryPrefix}/${relativeNamespace}`));
48
+ break;
49
+ }
50
+ return [...directories];
51
+ }
52
+ // A scope-resolution pass shares one stable parsedFiles array across imports.
53
+ const phpDirectoryIndexCache = new WeakMap();
54
+ function parentDirectory(filePath) {
55
+ const normalizedPath = normalizePhpPath(filePath);
56
+ const separator = normalizedPath.lastIndexOf('/');
57
+ return separator < 0 ? '' : normalizedPath.slice(0, separator);
58
+ }
59
+ function directoryAliases(filePath) {
60
+ const normalizedPath = normalizePhpPath(filePath);
61
+ const separator = normalizedPath.lastIndexOf('/');
62
+ if (separator < 0)
63
+ return [''];
64
+ const parent = normalizedPath.slice(0, separator);
65
+ const aliases = new Set([parent]);
66
+ const segments = parent.split('/').filter(Boolean);
67
+ for (let index = 0; index < segments.length; index++) {
68
+ aliases.add(segments.slice(index).join('/'));
69
+ }
70
+ return [...aliases];
71
+ }
72
+ function filesByDirectory(parsedFiles) {
73
+ const cached = phpDirectoryIndexCache.get(parsedFiles);
74
+ if (cached)
75
+ return cached;
76
+ const mutable = new Map();
77
+ for (const parsed of parsedFiles) {
78
+ for (const directory of directoryAliases(parsed.filePath)) {
79
+ const files = mutable.get(directory) ?? [];
80
+ files.push(parsed);
81
+ mutable.set(directory, files);
82
+ }
83
+ }
84
+ phpDirectoryIndexCache.set(parsedFiles, mutable);
85
+ return mutable;
86
+ }
20
87
  // ─── loadResolutionConfig ──────────────────────────────────────────────────
21
88
  /**
22
89
  * Load and parse `composer.json` from the repo root. Returns a
@@ -87,7 +154,7 @@ export function resolvePhpImportTarget(parsedImport, workspaceIndex) {
87
154
  * (a `ComposerConfig | null` loaded once per workspace by
88
155
  * `loadPhpComposerConfig`) and threads it into `resolvePhpImportInternal`.
89
156
  */
90
- export function resolvePhpImportTargetInternal(targetRaw, _fromFile, allFilePaths, resolutionConfig) {
157
+ export function resolvePhpImportTargetInternal(targetRaw, _fromFile, allFilePaths, resolutionConfig, context) {
91
158
  if (targetRaw === '')
92
159
  return null;
93
160
  const composerConfig = resolutionConfig !== undefined && resolutionConfig !== null
@@ -96,5 +163,46 @@ export function resolvePhpImportTargetInternal(targetRaw, _fromFile, allFilePath
96
163
  const allFiles = allFilePaths;
97
164
  const normalizedFileList = [...allFiles].map((f) => f.replace(/\\/g, '/'));
98
165
  const allFileList = [...allFiles];
99
- return resolvePhpImportInternal(targetRaw, composerConfig, allFiles, normalizedFileList, allFileList, undefined);
166
+ const resolved = resolvePhpImportInternal(targetRaw, composerConfig, allFiles, normalizedFileList, allFileList, undefined);
167
+ const parsedImport = context?.parsedImport;
168
+ const symbolKind = parsedImport?.kind === 'named' || parsedImport?.kind === 'alias'
169
+ ? parsedImport.importedSymbolKind
170
+ : undefined;
171
+ if (context === undefined ||
172
+ parsedImport === undefined ||
173
+ (symbolKind !== 'function' && symbolKind !== 'const')) {
174
+ return resolved;
175
+ }
176
+ const importedName = targetRaw.replace(/\\/g, '/').split('/').filter(Boolean).at(-1);
177
+ if (importedName === undefined)
178
+ return resolved;
179
+ const directories = namespaceDirectories(targetRaw, composerConfig, resolved);
180
+ const directoryIndex = filesByDirectory(context.parsedFiles);
181
+ const candidateFiles = [
182
+ ...new Set(directories.flatMap((directory) => {
183
+ const files = directoryIndex.get(normalizePhpPath(directory)) ?? [];
184
+ // A suffix alias can match directories under different roots (for
185
+ // example app/Models and vendor/pkg/app/Models). Picking either root
186
+ // would be a guess, so fail closed to the composer resolution instead.
187
+ const distinctParents = new Set(files.map((file) => parentDirectory(file.filePath)));
188
+ return distinctParents.size > 1 ? [] : files;
189
+ })),
190
+ ];
191
+ const expectedType = symbolKind === 'function' ? 'Function' : 'Variable';
192
+ const declaringFiles = candidateFiles.filter((parsed) => parsed.localDefs.some((def) => {
193
+ if (def.type !== expectedType)
194
+ return false;
195
+ const simpleName = (def.qualifiedName ?? '').split(/[\\.]/).at(-1);
196
+ return simpleName === importedName;
197
+ }));
198
+ if (declaringFiles.length > 1)
199
+ return null;
200
+ if (declaringFiles.length === 1)
201
+ return declaringFiles[0].filePath;
202
+ // PHP constants are not currently emitted as local definitions. A single
203
+ // file in the namespace directory is still unambiguous; multiple files must
204
+ // fail closed rather than inheriting Set iteration order.
205
+ if (symbolKind === 'const' && candidateFiles.length === 1)
206
+ return candidateFiles[0].filePath;
207
+ return resolved;
100
208
  }
@@ -16,12 +16,18 @@ export function interpretPhpImport(captures) {
16
16
  const sourceCap = captures['@import.source'];
17
17
  const nameCap = captures['@import.name'];
18
18
  const aliasCap = captures['@import.alias'];
19
+ const symbolKindCap = captures['@import.symbol-kind'];
19
20
  const kind = kindCap?.text;
20
21
  if (kind === undefined || sourceCap === undefined)
21
22
  return null;
22
23
  const source = sourceCap.text.trim();
23
24
  if (source === '')
24
25
  return null;
26
+ const importedSymbolKind = symbolKindCap?.text === 'function' || symbolKindCap?.text === 'const'
27
+ ? symbolKindCap.text
28
+ : kind === 'function' || kind === 'const'
29
+ ? kind
30
+ : 'type';
25
31
  switch (kind) {
26
32
  case 'namespace': {
27
33
  // `use Foo\Bar;` — PHP `use` is a NAMED import (binds the class
@@ -34,6 +40,7 @@ export function interpretPhpImport(captures) {
34
40
  localName,
35
41
  importedName: localName,
36
42
  targetRaw: source,
43
+ importedSymbolKind,
37
44
  };
38
45
  }
39
46
  case 'alias': {
@@ -50,6 +57,7 @@ export function interpretPhpImport(captures) {
50
57
  importedName,
51
58
  alias,
52
59
  targetRaw: source,
60
+ importedSymbolKind,
53
61
  };
54
62
  }
55
63
  case 'function': {
@@ -61,6 +69,7 @@ export function interpretPhpImport(captures) {
61
69
  localName,
62
70
  importedName: localName,
63
71
  targetRaw: source,
72
+ importedSymbolKind,
64
73
  };
65
74
  }
66
75
  case 'const': {
@@ -71,6 +80,7 @@ export function interpretPhpImport(captures) {
71
80
  localName,
72
81
  importedName: localName,
73
82
  targetRaw: source,
83
+ importedSymbolKind,
74
84
  };
75
85
  }
76
86
  default:
@@ -308,7 +308,7 @@ const phpScopeResolver = {
308
308
  language: SupportedLanguages.PHP,
309
309
  languageProvider: phpProvider,
310
310
  importEdgeReason: 'php-scope: use',
311
- resolveImportTarget: (targetRaw, fromFile, allFilePaths, resolutionConfig) => resolvePhpImportTargetInternal(targetRaw, fromFile, allFilePaths, resolutionConfig),
311
+ resolveImportTarget: (targetRaw, fromFile, allFilePaths, resolutionConfig, context) => resolvePhpImportTargetInternal(targetRaw, fromFile, allFilePaths, resolutionConfig, context),
312
312
  loadResolutionConfig: (repoPath) => loadPhpComposerConfig(repoPath),
313
313
  // PHP LEGB-like precedence: local > import/namespace/reexport > wildcard.
314
314
  // The per-scope id is unused by phpMergeBindings (tier ordering computed
@@ -8,10 +8,9 @@
8
8
  * 1. **Per-name import statements** — `import a, b` and
9
9
  * `from m import x, y` decompose to one match per imported name
10
10
  * (see `import-decomposer.ts`).
11
- * 2. **Receiver type bindings** — each `function_definition` inside a
12
- * class body emits a `@type-binding.self` (or `@type-binding.cls`
13
- * for `@classmethod`) capture so Pass-4 attaches the implicit
14
- * receiver (see `receiver-binding.ts`).
11
+ * 2. **Receiver type bindings** — methods emit an implicit `self` / `cls`
12
+ * binding, and `__init__` assignments from annotated parameters emit
13
+ * class-scoped instance-field bindings (see `receiver-binding.ts`).
15
14
  *
16
15
  * Pure given the input source text. No I/O, no globals consulted.
17
16
  */
@@ -8,23 +8,40 @@
8
8
  * 1. **Per-name import statements** — `import a, b` and
9
9
  * `from m import x, y` decompose to one match per imported name
10
10
  * (see `import-decomposer.ts`).
11
- * 2. **Receiver type bindings** — each `function_definition` inside a
12
- * class body emits a `@type-binding.self` (or `@type-binding.cls`
13
- * for `@classmethod`) capture so Pass-4 attaches the implicit
14
- * receiver (see `receiver-binding.ts`).
11
+ * 2. **Receiver type bindings** — methods emit an implicit `self` / `cls`
12
+ * binding, and `__init__` assignments from annotated parameters emit
13
+ * class-scoped instance-field bindings (see `receiver-binding.ts`).
15
14
  *
16
15
  * Pure given the input source text. No I/O, no globals consulted.
17
16
  */
18
17
  import { nodeToCapture, syntheticCapture, walkNamedTree, } from '../../utils/ast-helpers.js';
19
18
  import { splitImportStatement } from './import-decomposer.js';
20
19
  import { getPythonParser, getPythonScopeQuery } from './query.js';
21
- import { synthesizeReceiverTypeBinding } from './receiver-binding.js';
20
+ import { synthesizeConstructorFieldTypeBindings, synthesizeReceiverTypeBinding, } from './receiver-binding.js';
22
21
  import { synthesizeDependsReferences } from './depends-references.js';
23
22
  import { computePythonArityMetadata } from './arity-metadata.js';
24
23
  import { recordCacheHit, recordCacheMiss } from './cache-stats.js';
25
24
  import { getTreeSitterBufferSize } from '../../constants.js';
26
25
  import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
27
26
  import { pythonFunctionDefinitionLabel } from './simple-hooks.js';
27
+ import { synthesizeCallableFlowCaptures } from '../../utils/callable-flow-captures.js';
28
+ const PYTHON_CALLABLE_CAPTURE_OPTIONS = {
29
+ functionNodeTypes: new Set(['function_definition', 'lambda']),
30
+ callNodeTypes: new Set(['call']),
31
+ parameterListNodeTypes: new Set(['parameters', 'argument_list']),
32
+ parameterNodeTypes: new Set([
33
+ 'identifier',
34
+ 'default_parameter',
35
+ 'typed_parameter',
36
+ 'typed_default_parameter',
37
+ 'list_splat_pattern',
38
+ 'dictionary_splat_pattern',
39
+ ]),
40
+ bindingNodeTypes: new Set(['assignment', 'named_expression']),
41
+ assignmentNodeTypes: new Set(['assignment', 'named_expression']),
42
+ identifierNodeTypes: new Set(['identifier']),
43
+ functionScopedValueBindings: true,
44
+ };
28
45
  export function emitPythonScopeCaptures(sourceText, _filePath, cachedTree) {
29
46
  // Skip the parse when the caller (the scope-resolution orchestrator's
30
47
  // `treeCache`) already produced a Tree for this source — empty under
@@ -104,6 +121,7 @@ export function emitPythonScopeCaptures(sourceText, _filePath, cachedTree) {
104
121
  const synth = synthesizeReceiverTypeBinding(fnNode);
105
122
  if (synth !== null)
106
123
  out.push(synth);
124
+ out.push(...synthesizeConstructorFieldTypeBindings(fnNode));
107
125
  for (const depRef of synthesizeDependsReferences(fnNode))
108
126
  out.push(depRef);
109
127
  }
@@ -145,6 +163,7 @@ export function emitPythonScopeCaptures(sourceText, _filePath, cachedTree) {
145
163
  out.push(grouped);
146
164
  }
147
165
  out.push(...synthesizePythonInheritanceReferences(tree.rootNode));
166
+ out.push(...synthesizeCallableFlowCaptures(tree.rootNode, PYTHON_CALLABLE_CAPTURE_OPTIONS));
148
167
  return out;
149
168
  }
150
169
  /**
@@ -118,6 +118,10 @@ export function interpretPythonTypeBinding(captures) {
118
118
  // `Registry.lookup` Step 2 treats them identically.
119
119
  else if (captures['@type-binding.cls'] !== undefined)
120
120
  source = 'self';
121
+ else if (captures['@type-binding.instance-field'] !== undefined) {
122
+ source =
123
+ captures['@type-binding.parameter'] !== undefined ? 'parameter-annotation' : 'annotation';
124
+ }
121
125
  else if (captures['@type-binding.constructor'] !== undefined)
122
126
  source = 'constructor-inferred';
123
127
  else if (captures['@type-binding.annotation'] !== undefined)
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Synthesize `@type-binding.self` / `@type-binding.cls` captures for
3
- * methods.
2
+ * Synthesize implicit receiver and constructor-assigned field type bindings
3
+ * for methods.
4
4
  *
5
5
  * Tree-sitter can't easily express "the first parameter of a function
6
6
  * defined directly inside a class body" via a single static query.
@@ -19,3 +19,16 @@ import { type SyntaxNode } from '../../utils/ast-helpers.js';
19
19
  * 'function_definition'`.
20
20
  */
21
21
  export declare function synthesizeReceiverTypeBinding(fnNode: SyntaxNode): CaptureMatch | null;
22
+ /**
23
+ * Synthesize class-scope field bindings for the common Python constructor
24
+ * injection pattern:
25
+ *
26
+ * def __init__(self, service: Service):
27
+ * self.service = service
28
+ *
29
+ * An explicit field annotation (`self.service: Service = ...`) is also
30
+ * accepted and takes precedence over a parameter annotation. Deliberately do
31
+ * not infer from arbitrary unannotated RHS expressions: the receiver resolver
32
+ * needs a declared type, not a name-only guess.
33
+ */
34
+ export declare function synthesizeConstructorFieldTypeBindings(fnNode: SyntaxNode): CaptureMatch[];
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Synthesize `@type-binding.self` / `@type-binding.cls` captures for
3
- * methods.
2
+ * Synthesize implicit receiver and constructor-assigned field type bindings
3
+ * for methods.
4
4
  *
5
5
  * Tree-sitter can't easily express "the first parameter of a function
6
6
  * defined directly inside a class body" via a single static query.
@@ -114,3 +114,97 @@ export function synthesizeReceiverTypeBinding(fnNode) {
114
114
  '@type-binding.type': syntheticCapture('@type-binding.type', first, className),
115
115
  };
116
116
  }
117
+ /**
118
+ * Synthesize class-scope field bindings for the common Python constructor
119
+ * injection pattern:
120
+ *
121
+ * def __init__(self, service: Service):
122
+ * self.service = service
123
+ *
124
+ * An explicit field annotation (`self.service: Service = ...`) is also
125
+ * accepted and takes precedence over a parameter annotation. Deliberately do
126
+ * not infer from arbitrary unannotated RHS expressions: the receiver resolver
127
+ * needs a declared type, not a name-only guess.
128
+ */
129
+ export function synthesizeConstructorFieldTypeBindings(fnNode) {
130
+ if (fnNode.childForFieldName('name')?.text !== '__init__')
131
+ return [];
132
+ if (findEnclosingClassDefinition(fnNode) === null)
133
+ return [];
134
+ if (hasDecorator(fnNode, 'staticmethod') || hasDecorator(fnNode, 'classmethod'))
135
+ return [];
136
+ const receiver = synthesizeReceiverTypeBinding(fnNode);
137
+ const receiverName = receiver?.['@type-binding.self']?.text;
138
+ if (receiverName === undefined)
139
+ return [];
140
+ const parameters = fnNode.childForFieldName('parameters');
141
+ const body = fnNode.childForFieldName('body');
142
+ if (parameters === null || body === null)
143
+ return [];
144
+ const parameterTypes = new Map();
145
+ for (let i = 0; i < parameters.namedChildCount; i++) {
146
+ const parameter = parameters.namedChild(i);
147
+ if (parameter === null)
148
+ continue;
149
+ const name = firstParameterName(parameter);
150
+ const annotation = parameter.childForFieldName('type');
151
+ if (name !== null && annotation !== null)
152
+ parameterTypes.set(name, annotation.text);
153
+ }
154
+ const candidates = new Map();
155
+ const stack = [body];
156
+ while (stack.length > 0) {
157
+ const node = stack.pop();
158
+ if (node !== body &&
159
+ (node.type === 'function_definition' ||
160
+ node.type === 'lambda' ||
161
+ node.type === 'class_definition' ||
162
+ node.type === 'if_statement' ||
163
+ node.type === 'for_statement' ||
164
+ node.type === 'while_statement' ||
165
+ node.type === 'try_statement' ||
166
+ node.type === 'match_statement')) {
167
+ continue;
168
+ }
169
+ if (node.type === 'assignment') {
170
+ const left = node.childForFieldName('left');
171
+ const right = node.childForFieldName('right');
172
+ if (left?.type === 'attribute') {
173
+ const object = left.childForFieldName('object');
174
+ const field = left.childForFieldName('attribute');
175
+ if (object?.type === 'identifier' && object.text === receiverName && field !== null) {
176
+ const explicitType = node.childForFieldName('type');
177
+ const parameterType = right?.type === 'identifier' ? parameterTypes.get(right.text) : undefined;
178
+ const typeName = explicitType?.text ?? parameterType;
179
+ if (typeName !== undefined) {
180
+ const explicit = explicitType !== null;
181
+ const existing = candidates.get(field.text);
182
+ if (existing === undefined || explicit || !existing.explicit) {
183
+ candidates.set(field.text, {
184
+ explicit,
185
+ match: {
186
+ '@type-binding.name': syntheticCapture('@type-binding.name', field, field.text),
187
+ '@type-binding.type': syntheticCapture('@type-binding.type', explicitType ?? right ?? field, typeName),
188
+ ...(explicit
189
+ ? {}
190
+ : {
191
+ '@type-binding.parameter': syntheticCapture('@type-binding.parameter', right ?? field, '1'),
192
+ }),
193
+ '@type-binding.instance-field': syntheticCapture('@type-binding.instance-field', node, '1'),
194
+ },
195
+ });
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+ // Push in reverse so the LIFO walk visits source order. That keeps Map
202
+ // insertion order (and therefore emitted capture order) deterministic.
203
+ for (let i = node.namedChildCount - 1; i >= 0; i--) {
204
+ const child = node.namedChild(i);
205
+ if (child !== null)
206
+ stack.push(child);
207
+ }
208
+ }
209
+ return [...candidates.values()].map(({ match }) => match);
210
+ }
@@ -9,11 +9,11 @@ import type { CaptureMatch, NodeLabel, ParsedImport, Scope, ScopeId, ScopeTree,
9
9
  import type { SyntaxNode } from 'tree-sitter';
10
10
  export declare function pythonFunctionDefinitionLabel(functionNode: SyntaxNode, defaultLabel: NodeLabel): NodeLabel;
11
11
  /** Python has no block scope, so the central extractor's "innermost
12
- * enclosing scope" default is already correct: `for x in …` creates
13
- * `x` in the enclosing function/module scope (because we never emit a
14
- * `@scope.block` for the for-loop body), comprehension variables stay
15
- * in their expression context, etc. Returns `null` to delegate. */
16
- export declare function pythonBindingScopeFor(_decl: CaptureMatch, _innermost: Scope, _tree: ScopeTree): ScopeId | null;
12
+ * enclosing scope" default is already correct for ordinary bindings.
13
+ * Constructor-injected instance fields are the exception: their marker is
14
+ * anchored inside `__init__`, but compound receiver resolution needs the
15
+ * field type on the enclosing Class scope. */
16
+ export declare function pythonBindingScopeFor(decl: CaptureMatch, innermost: Scope, tree: ScopeTree): ScopeId | null;
17
17
  /** Function-local `from x import Y` should attach the binding to the
18
18
  * function scope, not the module. Class-body imports (rare but legal —
19
19
  * `class A: import x` makes `x` a class attribute) attach to the class.
@@ -15,11 +15,21 @@ export function pythonFunctionDefinitionLabel(functionNode, defaultLabel) {
15
15
  }
16
16
  // ─── bindingScopeFor ──────────────────────────────────────────────────────
17
17
  /** Python has no block scope, so the central extractor's "innermost
18
- * enclosing scope" default is already correct: `for x in …` creates
19
- * `x` in the enclosing function/module scope (because we never emit a
20
- * `@scope.block` for the for-loop body), comprehension variables stay
21
- * in their expression context, etc. Returns `null` to delegate. */
22
- export function pythonBindingScopeFor(_decl, _innermost, _tree) {
18
+ * enclosing scope" default is already correct for ordinary bindings.
19
+ * Constructor-injected instance fields are the exception: their marker is
20
+ * anchored inside `__init__`, but compound receiver resolution needs the
21
+ * field type on the enclosing Class scope. */
22
+ export function pythonBindingScopeFor(decl, innermost, tree) {
23
+ if (decl['@type-binding.instance-field'] !== undefined) {
24
+ let current = innermost;
25
+ while (current !== undefined) {
26
+ if (current.kind === 'Class')
27
+ return current.id;
28
+ if (current.parent === null)
29
+ break;
30
+ current = tree.getScope(current.parent);
31
+ }
32
+ }
23
33
  return null;
24
34
  }
25
35
  // ─── importOwningScope ────────────────────────────────────────────────────
@@ -6,6 +6,7 @@ import { getTreeSitterBufferSize } from '../../constants.js';
6
6
  import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
7
7
  import { splitQualifiedName } from '../../utils/qualified-name.js';
8
8
  import { encodeMarker } from '../../utils/heritage-marker.js';
9
+ import { synthesizeCallableFlowCaptures } from '../../utils/callable-flow-captures.js';
9
10
  const FUNCTION_NODE_TYPES = ['method', 'singleton_method'];
10
11
  const HERITAGE_CALL_NAMES = new Set(['include', 'extend', 'prepend']);
11
12
  const ATTR_CALL_NAMES = new Set([
@@ -13,6 +14,46 @@ const ATTR_CALL_NAMES = new Set([
13
14
  'attr_reader',
14
15
  'attr_writer',
15
16
  ]);
17
+ const RUBY_CALLABLE_CAPTURE_OPTIONS = {
18
+ functionNodeTypes: new Set(['method', 'singleton_method', 'lambda']),
19
+ callNodeTypes: new Set(['call']),
20
+ parameterListNodeTypes: new Set(['method_parameters', 'argument_list']),
21
+ parameterNodeTypes: new Set([
22
+ 'identifier',
23
+ 'optional_parameter',
24
+ 'splat_parameter',
25
+ 'hash_splat_parameter',
26
+ 'block_parameter',
27
+ ]),
28
+ bindingNodeTypes: new Set(['assignment']),
29
+ assignmentNodeTypes: new Set(['assignment', 'operator_assignment']),
30
+ identifierNodeTypes: new Set([
31
+ 'identifier',
32
+ 'constant',
33
+ 'instance_variable',
34
+ 'class_variable',
35
+ 'global_variable',
36
+ ]),
37
+ functionScopedValueBindings: true,
38
+ callableProtocolMethods: new Set(['call']),
39
+ // A bare receiver-less identifier in value position is a method CALL in
40
+ // Ruby (`action = process` stores process's RETURN value) — only explicit
41
+ // reference forms (method(:x), &:x, lambda/proc) reference the callable.
42
+ bareNamesAreCalls: true,
43
+ extractCallableReference: (node) => {
44
+ if (node.type !== 'call')
45
+ return undefined;
46
+ const method = node.childForFieldName('method');
47
+ if (method?.text !== 'method' && method?.text !== 'public_method')
48
+ return undefined;
49
+ const args = node.childForFieldName('arguments');
50
+ const symbol = args?.namedChildren.find((child) => child !== null && child.type === 'simple_symbol');
51
+ if (symbol === undefined)
52
+ return undefined;
53
+ const name = symbol.text.replace(/^:/, '');
54
+ return name.length === 0 ? undefined : { name, anchor: symbol };
55
+ },
56
+ };
16
57
  /**
17
58
  * Build the full `.`-joined qualified owner name for a heritage/attr call by
18
59
  * walking ALL enclosing class/module ancestors (not just the immediate one),
@@ -400,6 +441,7 @@ export function emitRubyScopeCaptures(sourceText, _filePath, cachedTree) {
400
441
  // flow through `emitHeritageEdges` (the `__heritage__:` import path above),
401
442
  // an independent lane that stays intact when the legacy heritage leg is gated off.
402
443
  out.push(...synthesizeRubySuperclassReferences(tree.rootNode));
444
+ out.push(...synthesizeCallableFlowCaptures(tree.rootNode, RUBY_CALLABLE_CAPTURE_OPTIONS));
403
445
  return out;
404
446
  }
405
447
  /**
@@ -5,6 +5,18 @@ import { splitRustUseDeclaration } from './import-decomposer.js';
5
5
  import { synthesizeRustReceiverBinding } from './receiver-binding.js';
6
6
  import { getTreeSitterBufferSize } from '../../constants.js';
7
7
  import { parseSourceSafe } from '../../../tree-sitter/safe-parse.js';
8
+ import { synthesizeCallableFlowCaptures } from '../../utils/callable-flow-captures.js';
9
+ const RUST_CALLABLE_CAPTURE_OPTIONS = {
10
+ functionNodeTypes: new Set(['function_item', 'closure_expression']),
11
+ callNodeTypes: new Set(['call_expression']),
12
+ parameterListNodeTypes: new Set(['parameters', 'arguments']),
13
+ parameterNodeTypes: new Set(['parameter', 'self_parameter']),
14
+ bindingNodeTypes: new Set(['let_declaration']),
15
+ assignmentNodeTypes: new Set(['assignment_expression']),
16
+ identifierNodeTypes: new Set(['identifier', 'type_identifier', 'field_identifier']),
17
+ callableReferenceNodeTypes: new Set(['scoped_identifier']),
18
+ normalizeQualifiedName: (raw) => raw.replaceAll('::', '.'),
19
+ };
8
20
  export function emitRustScopeCaptures(sourceText, _filePath, cachedTree) {
9
21
  let tree = cachedTree;
10
22
  if (tree === undefined) {
@@ -117,6 +129,7 @@ export function emitRustScopeCaptures(sourceText, _filePath, cachedTree) {
117
129
  out.push(grouped);
118
130
  }
119
131
  out.push(...synthesizeRustInheritanceReferences(tree.rootNode));
132
+ out.push(...synthesizeCallableFlowCaptures(tree.rootNode, RUST_CALLABLE_CAPTURE_OPTIONS));
120
133
  return out;
121
134
  }
122
135
  /**