gitnexus 1.6.3-rc.8 → 1.6.3

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 (285) hide show
  1. package/README.md +21 -5
  2. package/dist/_shared/graph/types.d.ts +16 -0
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/index.d.ts +20 -2
  5. package/dist/_shared/index.d.ts.map +1 -1
  6. package/dist/_shared/index.js +11 -0
  7. package/dist/_shared/index.js.map +1 -1
  8. package/dist/_shared/scope-resolution/def-index.js +2 -2
  9. package/dist/_shared/scope-resolution/def-index.js.map +1 -1
  10. package/dist/_shared/scope-resolution/method-dispatch-index.d.ts +8 -0
  11. package/dist/_shared/scope-resolution/method-dispatch-index.d.ts.map +1 -1
  12. package/dist/_shared/scope-resolution/method-dispatch-index.js +2 -2
  13. package/dist/_shared/scope-resolution/method-dispatch-index.js.map +1 -1
  14. package/dist/_shared/scope-resolution/module-scope-index.d.ts +8 -0
  15. package/dist/_shared/scope-resolution/module-scope-index.d.ts.map +1 -1
  16. package/dist/_shared/scope-resolution/module-scope-index.js +10 -2
  17. package/dist/_shared/scope-resolution/module-scope-index.js.map +1 -1
  18. package/dist/_shared/scope-resolution/parsed-file.d.ts +76 -0
  19. package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -0
  20. package/dist/_shared/scope-resolution/parsed-file.js +54 -0
  21. package/dist/_shared/scope-resolution/parsed-file.js.map +1 -0
  22. package/dist/_shared/scope-resolution/position-index.d.ts +12 -0
  23. package/dist/_shared/scope-resolution/position-index.d.ts.map +1 -1
  24. package/dist/_shared/scope-resolution/position-index.js +2 -2
  25. package/dist/_shared/scope-resolution/position-index.js.map +1 -1
  26. package/dist/_shared/scope-resolution/qualified-name-index.js +2 -2
  27. package/dist/_shared/scope-resolution/qualified-name-index.js.map +1 -1
  28. package/dist/_shared/scope-resolution/reference-site.d.ts +75 -0
  29. package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -0
  30. package/dist/_shared/scope-resolution/reference-site.js +24 -0
  31. package/dist/_shared/scope-resolution/reference-site.js.map +1 -0
  32. package/dist/_shared/scope-resolution/registries/class-registry.d.ts +27 -0
  33. package/dist/_shared/scope-resolution/registries/class-registry.d.ts.map +1 -0
  34. package/dist/_shared/scope-resolution/registries/class-registry.js +30 -0
  35. package/dist/_shared/scope-resolution/registries/class-registry.js.map +1 -0
  36. package/dist/_shared/scope-resolution/registries/context.d.ts +69 -0
  37. package/dist/_shared/scope-resolution/registries/context.d.ts.map +1 -0
  38. package/dist/_shared/scope-resolution/registries/context.js +44 -0
  39. package/dist/_shared/scope-resolution/registries/context.js.map +1 -0
  40. package/dist/_shared/scope-resolution/registries/evidence.d.ts +56 -0
  41. package/dist/_shared/scope-resolution/registries/evidence.d.ts.map +1 -0
  42. package/dist/_shared/scope-resolution/registries/evidence.js +150 -0
  43. package/dist/_shared/scope-resolution/registries/evidence.js.map +1 -0
  44. package/dist/_shared/scope-resolution/registries/field-registry.d.ts +26 -0
  45. package/dist/_shared/scope-resolution/registries/field-registry.d.ts.map +1 -0
  46. package/dist/_shared/scope-resolution/registries/field-registry.js +31 -0
  47. package/dist/_shared/scope-resolution/registries/field-registry.js.map +1 -0
  48. package/dist/_shared/scope-resolution/registries/lookup-core.d.ts +81 -0
  49. package/dist/_shared/scope-resolution/registries/lookup-core.d.ts.map +1 -0
  50. package/dist/_shared/scope-resolution/registries/lookup-core.js +332 -0
  51. package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -0
  52. package/dist/_shared/scope-resolution/registries/lookup-qualified.d.ts +33 -0
  53. package/dist/_shared/scope-resolution/registries/lookup-qualified.d.ts.map +1 -0
  54. package/dist/_shared/scope-resolution/registries/lookup-qualified.js +56 -0
  55. package/dist/_shared/scope-resolution/registries/lookup-qualified.js.map +1 -0
  56. package/dist/_shared/scope-resolution/registries/method-registry.d.ts +36 -0
  57. package/dist/_shared/scope-resolution/registries/method-registry.d.ts.map +1 -0
  58. package/dist/_shared/scope-resolution/registries/method-registry.js +32 -0
  59. package/dist/_shared/scope-resolution/registries/method-registry.js.map +1 -0
  60. package/dist/_shared/scope-resolution/registries/tie-breaks.d.ts +43 -0
  61. package/dist/_shared/scope-resolution/registries/tie-breaks.d.ts.map +1 -0
  62. package/dist/_shared/scope-resolution/registries/tie-breaks.js +60 -0
  63. package/dist/_shared/scope-resolution/registries/tie-breaks.js.map +1 -0
  64. package/dist/_shared/scope-resolution/resolve-type-ref.d.ts +1 -10
  65. package/dist/_shared/scope-resolution/resolve-type-ref.d.ts.map +1 -1
  66. package/dist/_shared/scope-resolution/resolve-type-ref.js +6 -0
  67. package/dist/_shared/scope-resolution/resolve-type-ref.js.map +1 -1
  68. package/dist/_shared/scope-resolution/scope-tree.d.ts +4 -4
  69. package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -1
  70. package/dist/_shared/scope-resolution/scope-tree.js +3 -2
  71. package/dist/_shared/scope-resolution/scope-tree.js.map +1 -1
  72. package/dist/_shared/scope-resolution/shadow/aggregate.d.ts +6 -2
  73. package/dist/_shared/scope-resolution/shadow/aggregate.d.ts.map +1 -1
  74. package/dist/_shared/scope-resolution/shadow/aggregate.js +5 -0
  75. package/dist/_shared/scope-resolution/shadow/aggregate.js.map +1 -1
  76. package/dist/_shared/scope-resolution/types.d.ts +11 -0
  77. package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
  78. package/dist/cli/ai-context.js +35 -4
  79. package/dist/cli/analyze.d.ts +27 -0
  80. package/dist/cli/analyze.js +31 -1
  81. package/dist/cli/clean.js +19 -1
  82. package/dist/cli/group.js +73 -0
  83. package/dist/cli/index-repo.js +8 -1
  84. package/dist/cli/index.js +26 -1
  85. package/dist/cli/list.js +11 -1
  86. package/dist/cli/remove.d.ts +30 -0
  87. package/dist/cli/remove.js +99 -0
  88. package/dist/cli/setup.js +185 -57
  89. package/dist/cli/tool.d.ts +5 -0
  90. package/dist/cli/tool.js +42 -0
  91. package/dist/config/ignore-service.d.ts +9 -0
  92. package/dist/config/ignore-service.js +80 -13
  93. package/dist/core/embedding-mode.d.ts +30 -0
  94. package/dist/core/embedding-mode.js +30 -0
  95. package/dist/core/embeddings/ast-utils.js +22 -22
  96. package/dist/core/embeddings/chunker.js +30 -25
  97. package/dist/core/embeddings/embedding-pipeline.d.ts +6 -0
  98. package/dist/core/embeddings/embedding-pipeline.js +15 -6
  99. package/dist/core/embeddings/text-generator.d.ts +1 -1
  100. package/dist/core/embeddings/text-generator.js +33 -24
  101. package/dist/core/embeddings/types.d.ts +43 -1
  102. package/dist/core/embeddings/types.js +101 -29
  103. package/dist/core/git-staleness.d.ts +18 -0
  104. package/dist/core/git-staleness.js +108 -0
  105. package/dist/core/graph/graph.js +115 -20
  106. package/dist/core/graph/types.d.ts +12 -1
  107. package/dist/core/group/config-parser.d.ts +4 -0
  108. package/dist/core/group/config-parser.js +18 -1
  109. package/dist/core/group/cross-impact.d.ts +41 -0
  110. package/dist/core/group/cross-impact.js +441 -0
  111. package/dist/core/group/extractors/http-patterns/php.js +126 -18
  112. package/dist/core/group/group-path-utils.d.ts +17 -0
  113. package/dist/core/group/group-path-utils.js +40 -0
  114. package/dist/core/group/resolve-at-member.d.ts +10 -0
  115. package/dist/core/group/resolve-at-member.js +31 -0
  116. package/dist/core/group/service.d.ts +9 -0
  117. package/dist/core/group/service.js +259 -25
  118. package/dist/core/group/types.d.ts +30 -0
  119. package/dist/core/ingestion/ast-cache.d.ts +16 -1
  120. package/dist/core/ingestion/ast-cache.js +14 -2
  121. package/dist/core/ingestion/call-processor.js +9 -0
  122. package/dist/core/ingestion/emit-references.d.ts +88 -0
  123. package/dist/core/ingestion/emit-references.js +229 -0
  124. package/dist/core/ingestion/filesystem-walker.js +6 -4
  125. package/dist/core/ingestion/finalize-orchestrator.d.ts +63 -0
  126. package/dist/core/ingestion/finalize-orchestrator.js +139 -0
  127. package/dist/core/ingestion/framework-detection.js +6 -2
  128. package/dist/core/ingestion/import-processor.js +4 -0
  129. package/dist/core/ingestion/import-resolvers/python.js +9 -6
  130. package/dist/core/ingestion/import-target-adapter.d.ts +73 -0
  131. package/dist/core/ingestion/import-target-adapter.js +95 -0
  132. package/dist/core/ingestion/language-provider.d.ts +36 -33
  133. package/dist/core/ingestion/languages/csharp/accessor-unwrap.d.ts +21 -0
  134. package/dist/core/ingestion/languages/csharp/accessor-unwrap.js +56 -0
  135. package/dist/core/ingestion/languages/csharp/arity-metadata.d.ts +26 -0
  136. package/dist/core/ingestion/languages/csharp/arity-metadata.js +46 -0
  137. package/dist/core/ingestion/languages/csharp/arity.d.ts +23 -0
  138. package/dist/core/ingestion/languages/csharp/arity.js +37 -0
  139. package/dist/core/ingestion/languages/csharp/cache-stats.d.ts +15 -0
  140. package/dist/core/ingestion/languages/csharp/cache-stats.js +26 -0
  141. package/dist/core/ingestion/languages/csharp/captures.d.ts +19 -0
  142. package/dist/core/ingestion/languages/csharp/captures.js +249 -0
  143. package/dist/core/ingestion/languages/csharp/import-decomposer.d.ts +19 -0
  144. package/dist/core/ingestion/languages/csharp/import-decomposer.js +93 -0
  145. package/dist/core/ingestion/languages/csharp/import-target.d.ts +25 -0
  146. package/dist/core/ingestion/languages/csharp/import-target.js +123 -0
  147. package/dist/core/ingestion/languages/csharp/index.d.ts +82 -0
  148. package/dist/core/ingestion/languages/csharp/index.js +82 -0
  149. package/dist/core/ingestion/languages/csharp/interpret.d.ts +15 -0
  150. package/dist/core/ingestion/languages/csharp/interpret.js +132 -0
  151. package/dist/core/ingestion/languages/csharp/merge-bindings.d.ts +27 -0
  152. package/dist/core/ingestion/languages/csharp/merge-bindings.js +55 -0
  153. package/dist/core/ingestion/languages/csharp/namespace-siblings.d.ts +50 -0
  154. package/dist/core/ingestion/languages/csharp/namespace-siblings.js +374 -0
  155. package/dist/core/ingestion/languages/csharp/query.d.ts +35 -0
  156. package/dist/core/ingestion/languages/csharp/query.js +515 -0
  157. package/dist/core/ingestion/languages/csharp/receiver-binding.d.ts +31 -0
  158. package/dist/core/ingestion/languages/csharp/receiver-binding.js +135 -0
  159. package/dist/core/ingestion/languages/csharp/scope-resolver.d.ts +10 -0
  160. package/dist/core/ingestion/languages/csharp/scope-resolver.js +63 -0
  161. package/dist/core/ingestion/languages/csharp/simple-hooks.d.ts +53 -0
  162. package/dist/core/ingestion/languages/csharp/simple-hooks.js +76 -0
  163. package/dist/core/ingestion/languages/csharp.js +14 -0
  164. package/dist/core/ingestion/languages/python/arity-metadata.d.ts +24 -0
  165. package/dist/core/ingestion/languages/python/arity-metadata.js +45 -0
  166. package/dist/core/ingestion/languages/python/arity.d.ts +22 -0
  167. package/dist/core/ingestion/languages/python/arity.js +38 -0
  168. package/dist/core/ingestion/languages/python/cache-stats.d.ts +17 -0
  169. package/dist/core/ingestion/languages/python/cache-stats.js +28 -0
  170. package/dist/core/ingestion/languages/python/captures.d.ts +19 -0
  171. package/dist/core/ingestion/languages/python/captures.js +106 -0
  172. package/dist/core/ingestion/languages/python/import-decomposer.d.ts +15 -0
  173. package/dist/core/ingestion/languages/python/import-decomposer.js +112 -0
  174. package/dist/core/ingestion/languages/python/import-target.d.ts +21 -0
  175. package/dist/core/ingestion/languages/python/import-target.js +99 -0
  176. package/dist/core/ingestion/languages/python/index.d.ts +80 -0
  177. package/dist/core/ingestion/languages/python/index.js +80 -0
  178. package/dist/core/ingestion/languages/python/interpret.d.ts +15 -0
  179. package/dist/core/ingestion/languages/python/interpret.js +191 -0
  180. package/dist/core/ingestion/languages/python/merge-bindings.d.ts +16 -0
  181. package/dist/core/ingestion/languages/python/merge-bindings.js +44 -0
  182. package/dist/core/ingestion/languages/python/query.d.ts +9 -0
  183. package/dist/core/ingestion/languages/python/query.js +267 -0
  184. package/dist/core/ingestion/languages/python/receiver-binding.d.ts +21 -0
  185. package/dist/core/ingestion/languages/python/receiver-binding.js +116 -0
  186. package/dist/core/ingestion/languages/python/scope-resolver.d.ts +16 -0
  187. package/dist/core/ingestion/languages/python/scope-resolver.js +53 -0
  188. package/dist/core/ingestion/languages/python/simple-hooks.d.ts +23 -0
  189. package/dist/core/ingestion/languages/python/simple-hooks.js +35 -0
  190. package/dist/core/ingestion/languages/python.js +14 -0
  191. package/dist/core/ingestion/model/method-registry.d.ts +9 -0
  192. package/dist/core/ingestion/model/method-registry.js +4 -0
  193. package/dist/core/ingestion/model/scope-resolution-indexes.d.ts +59 -0
  194. package/dist/core/ingestion/model/scope-resolution-indexes.js +42 -0
  195. package/dist/core/ingestion/model/semantic-model.d.ts +64 -0
  196. package/dist/core/ingestion/model/semantic-model.js +55 -0
  197. package/dist/core/ingestion/mro-processor.js +38 -22
  198. package/dist/core/ingestion/parsing-processor.d.ts +18 -1
  199. package/dist/core/ingestion/parsing-processor.js +45 -11
  200. package/dist/core/ingestion/pipeline-phases/index.d.ts +1 -0
  201. package/dist/core/ingestion/pipeline-phases/index.js +1 -0
  202. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +10 -0
  203. package/dist/core/ingestion/pipeline-phases/parse-impl.js +17 -2
  204. package/dist/core/ingestion/pipeline-phases/parse.d.ts +18 -0
  205. package/dist/core/ingestion/pipeline.js +2 -1
  206. package/dist/core/ingestion/registry-primary-flag.d.ts +86 -0
  207. package/dist/core/ingestion/registry-primary-flag.js +111 -0
  208. package/dist/core/ingestion/resolve-references.d.ts +63 -0
  209. package/dist/core/ingestion/resolve-references.js +175 -0
  210. package/dist/core/ingestion/scope-extractor-bridge.d.ts +32 -0
  211. package/dist/core/ingestion/scope-extractor-bridge.js +44 -0
  212. package/dist/core/ingestion/scope-extractor.d.ts +86 -0
  213. package/dist/core/ingestion/scope-extractor.js +758 -0
  214. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +372 -0
  215. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.js +212 -0
  216. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +43 -0
  217. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +79 -0
  218. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.d.ts +57 -0
  219. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +112 -0
  220. package/dist/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.d.ts +17 -0
  221. package/dist/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.js +46 -0
  222. package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.d.ts +19 -0
  223. package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.js +30 -0
  224. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.d.ts +37 -0
  225. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +113 -0
  226. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +38 -0
  227. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +73 -0
  228. package/dist/core/ingestion/scope-resolution/passes/compound-receiver.d.ts +42 -0
  229. package/dist/core/ingestion/scope-resolution/passes/compound-receiver.js +198 -0
  230. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +27 -0
  231. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +131 -0
  232. package/dist/core/ingestion/scope-resolution/passes/imported-return-types.d.ts +48 -0
  233. package/dist/core/ingestion/scope-resolution/passes/imported-return-types.js +130 -0
  234. package/dist/core/ingestion/scope-resolution/passes/mro.d.ts +42 -0
  235. package/dist/core/ingestion/scope-resolution/passes/mro.js +99 -0
  236. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +26 -0
  237. package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +61 -0
  238. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +46 -0
  239. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +327 -0
  240. package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +47 -0
  241. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +130 -0
  242. package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.d.ts +68 -0
  243. package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +125 -0
  244. package/dist/core/ingestion/scope-resolution/pipeline/registry.d.ts +17 -0
  245. package/dist/core/ingestion/scope-resolution/pipeline/registry.js +21 -0
  246. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +66 -0
  247. package/dist/core/ingestion/scope-resolution/pipeline/run.js +157 -0
  248. package/dist/core/ingestion/scope-resolution/scope/namespace-targets.d.ts +36 -0
  249. package/dist/core/ingestion/scope-resolution/scope/namespace-targets.js +52 -0
  250. package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +127 -0
  251. package/dist/core/ingestion/scope-resolution/scope/walkers.js +349 -0
  252. package/dist/core/ingestion/scope-resolution/workspace-index.d.ts +52 -0
  253. package/dist/core/ingestion/scope-resolution/workspace-index.js +61 -0
  254. package/dist/core/ingestion/shadow-harness.d.ts +113 -0
  255. package/dist/core/ingestion/shadow-harness.js +148 -0
  256. package/dist/core/ingestion/utils/ast-helpers.d.ts +19 -1
  257. package/dist/core/ingestion/utils/ast-helpers.js +70 -0
  258. package/dist/core/ingestion/utils/max-file-size.d.ts +20 -0
  259. package/dist/core/ingestion/utils/max-file-size.js +52 -0
  260. package/dist/core/ingestion/workers/parse-worker.d.ts +9 -0
  261. package/dist/core/ingestion/workers/parse-worker.js +57 -21
  262. package/dist/core/lbug/lbug-adapter.d.ts +22 -2
  263. package/dist/core/lbug/lbug-adapter.js +58 -14
  264. package/dist/core/lbug/pool-adapter.d.ts +17 -0
  265. package/dist/core/lbug/pool-adapter.js +24 -14
  266. package/dist/core/run-analyze.d.ts +32 -0
  267. package/dist/core/run-analyze.js +74 -19
  268. package/dist/core/search/bm25-index.d.ts +18 -0
  269. package/dist/core/search/bm25-index.js +125 -12
  270. package/dist/core/tree-sitter/parser-loader.js +6 -1
  271. package/dist/mcp/local/local-backend.d.ts +67 -3
  272. package/dist/mcp/local/local-backend.js +296 -34
  273. package/dist/mcp/resources.d.ts +31 -0
  274. package/dist/mcp/resources.js +100 -17
  275. package/dist/mcp/tools.d.ts +4 -1
  276. package/dist/mcp/tools.js +75 -54
  277. package/dist/server/api.js +6 -2
  278. package/dist/storage/git.d.ts +49 -0
  279. package/dist/storage/git.js +111 -0
  280. package/dist/storage/repo-manager.d.ts +246 -1
  281. package/dist/storage/repo-manager.js +391 -9
  282. package/package.json +7 -6
  283. package/scripts/bench-scope-resolution.ts +134 -0
  284. package/scripts/ci-list-migrated-languages.ts +24 -0
  285. package/skills/gitnexus-cli.md +1 -0
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Tree-sitter query for Python scope captures (RFC §5.1).
3
+ *
4
+ * Exposes lazy `Parser` and `Query` singletons so callers don't
5
+ * pay tree-sitter init cost per file.
6
+ */
7
+ import Parser from 'tree-sitter';
8
+ import Python from 'tree-sitter-python';
9
+ const PYTHON_SCOPE_QUERY = `
10
+ ;; Scopes
11
+ (module) @scope.module
12
+ (class_definition) @scope.class
13
+ (function_definition) @scope.function
14
+
15
+ ;; Declarations
16
+ (class_definition
17
+ name: (identifier) @declaration.name) @declaration.class
18
+
19
+ (function_definition
20
+ name: (identifier) @declaration.name) @declaration.function
21
+
22
+ (assignment
23
+ left: (identifier) @declaration.name) @declaration.variable
24
+
25
+ ;; Declarations: for-loop target — Python for-statements do NOT introduce
26
+ ;; a new scope, so the loop variable binds in the enclosing function/module
27
+ ;; scope. We emit it as a Variable declaration so Pass-2 attaches it.
28
+ (for_statement
29
+ left: (identifier) @declaration.name) @declaration.variable
30
+
31
+ ;; Imports — single anchor per statement; interpretImport decomposes
32
+ (import_statement) @import.statement
33
+ (import_from_statement) @import.statement
34
+
35
+ ;; Type bindings (parameter annotations)
36
+ (typed_parameter
37
+ (identifier) @type-binding.name
38
+ type: (type) @type-binding.type) @type-binding.parameter
39
+
40
+ (typed_default_parameter
41
+ name: (identifier) @type-binding.name
42
+ type: (type) @type-binding.type) @type-binding.parameter
43
+
44
+ ;; Type bindings (constructor-inferred: \`u = User(...)\`)
45
+ ;; Listed BEFORE the annotation pattern so \`u: User = find()\` — which
46
+ ;; matches BOTH patterns — has the annotation (stronger source) win over
47
+ ;; the constructor-inferred guess via the scope-extractor's source-
48
+ ;; strength tie-break in pass4CollectTypeBindings.
49
+ (assignment
50
+ left: (identifier) @type-binding.name
51
+ right: (call
52
+ function: (identifier) @type-binding.type)) @type-binding.constructor
53
+
54
+ ;; Qualified constructor (\`u = models.User(...)\`). Captures the
55
+ ;; attribute node as the type — its \`.text\` is the full dotted path
56
+ ;; (\`models.User\`), which \`resolveTypeRef\` resolves via
57
+ ;; \`QualifiedNameIndex\` Phase 2.
58
+ (assignment
59
+ left: (identifier) @type-binding.name
60
+ right: (call
61
+ function: (attribute) @type-binding.type)) @type-binding.constructor
62
+
63
+ ;; Walrus operator: \`(u := User(...))\`. Python 3.8+ named expression.
64
+ ;; Shares the constructor-inferred shape so the binding lands in the
65
+ ;; enclosing function/module scope's typeBindings the same way a plain
66
+ ;; assignment would.
67
+ (named_expression
68
+ name: (identifier) @type-binding.name
69
+ value: (call
70
+ function: (identifier) @type-binding.type)) @type-binding.constructor
71
+
72
+ (named_expression
73
+ name: (identifier) @type-binding.name
74
+ value: (call
75
+ function: (attribute) @type-binding.type)) @type-binding.constructor
76
+
77
+ ;; Match-case as-pattern: \`case User() as u:\` → \`u: User\`. The
78
+ ;; class_pattern's dotted_name carries the type; the outer as_pattern's
79
+ ;; second child is the binding name.
80
+ (as_pattern
81
+ (case_pattern
82
+ (class_pattern
83
+ (dotted_name) @type-binding.type))
84
+ (identifier) @type-binding.name) @type-binding.constructor
85
+
86
+ ;; Assignment chain: \`alias = user\` — the new name inherits the
87
+ ;; RHS-identifier's type. The pattern emits a TypeRef whose rawName is
88
+ ;; the RHS identifier's text; the scope-extractor's post-pass follows
89
+ ;; the chain so \`alias\` ends up pointing at whatever type \`user\` has.
90
+ (assignment
91
+ left: (identifier) @type-binding.name
92
+ right: (identifier) @type-binding.type) @type-binding.alias
93
+
94
+ ;; For-loop iterable of an already-typed variable:
95
+ ;; def f(users: list[User]):
96
+ ;; for u in users: # u: users (chained via post-pass)
97
+ ;; u.save()
98
+ ;; The chain post-pass resolves \`users\` → its own type \`User\` via
99
+ ;; the generic-arg stripping in \`interpret.ts\`.
100
+ (for_statement
101
+ left: (identifier) @type-binding.name
102
+ right: (identifier) @type-binding.type) @type-binding.alias
103
+
104
+ ;; For-loop iterable of a free-call result:
105
+ ;; def get_users() -> list[User]: ...
106
+ ;; for u in get_users(): # u: get_users → User via chain follow
107
+ ;; u.save()
108
+ ;; Captures the call's function identifier as the rawName. With
109
+ ;; \`propagateImportedReturnTypes\`, this works cross-file too.
110
+ (for_statement
111
+ left: (identifier) @type-binding.name
112
+ right: (call
113
+ function: (identifier) @type-binding.type)) @type-binding.alias
114
+
115
+ ;; for (i, u) in enumerate(X) — paren-tuple, bind last element to X's
116
+ ;; element type. \`enumerate(X)\` yields (int, X-element); the second
117
+ ;; pattern var takes X (which the chain-follow then unwraps to its
118
+ ;; element type via generic-strip in interpret.ts).
119
+ (for_statement
120
+ left: (tuple_pattern
121
+ (identifier)
122
+ (identifier) @type-binding.name)
123
+ right: (call
124
+ function: (identifier) @_enum
125
+ arguments: (argument_list
126
+ (identifier) @type-binding.type))
127
+ (#eq? @_enum "enumerate")) @type-binding.alias
128
+
129
+ ;; for i, u in enumerate(X) — pattern_list (no parens) variant.
130
+ (for_statement
131
+ left: (pattern_list
132
+ (identifier)
133
+ (identifier) @type-binding.name)
134
+ right: (call
135
+ function: (identifier) @_enum
136
+ arguments: (argument_list
137
+ (identifier) @type-binding.type))
138
+ (#eq? @_enum "enumerate")) @type-binding.alias
139
+
140
+ ;; for k, v in d.items() — bind v to d. The chain-follow unwraps d's
141
+ ;; dict[K, V] annotation to V via the dict-aware stripGeneric in
142
+ ;; interpret.ts. Covers both pattern_list and tuple_pattern shapes.
143
+ (for_statement
144
+ left: (pattern_list
145
+ (identifier)
146
+ (identifier) @type-binding.name)
147
+ right: (call
148
+ function: (attribute
149
+ object: (identifier) @type-binding.type
150
+ attribute: (identifier) @_items))
151
+ (#eq? @_items "items")) @type-binding.alias
152
+
153
+ (for_statement
154
+ left: (tuple_pattern
155
+ (identifier)
156
+ (identifier) @type-binding.name)
157
+ right: (call
158
+ function: (attribute
159
+ object: (identifier) @type-binding.type
160
+ attribute: (identifier) @_items))
161
+ (#eq? @_items "items")) @type-binding.alias
162
+
163
+ ;; for i, (k, v) in enumerate(d.items()) — nested tuple destructuring.
164
+ ;; Bind v (last id of the nested tuple) to d (the dict).
165
+ (for_statement
166
+ left: (pattern_list
167
+ (identifier)
168
+ (tuple_pattern
169
+ (identifier)
170
+ (identifier) @type-binding.name))
171
+ right: (call
172
+ function: (identifier) @_enum
173
+ arguments: (argument_list
174
+ (call
175
+ function: (attribute
176
+ object: (identifier) @type-binding.type
177
+ attribute: (identifier) @_items))))
178
+ (#eq? @_enum "enumerate")
179
+ (#eq? @_items "items")) @type-binding.alias
180
+
181
+ ;; for i, k, v in enumerate(d.items()) — 3-var flat destructuring of
182
+ ;; the (i, (k,v)) tuple emitted by enumerate over items(). Bind v
183
+ ;; (last id) to d.
184
+ (for_statement
185
+ left: (pattern_list
186
+ (identifier)
187
+ (identifier)
188
+ (identifier) @type-binding.name)
189
+ right: (call
190
+ function: (identifier) @_enum
191
+ arguments: (argument_list
192
+ (call
193
+ function: (attribute
194
+ object: (identifier) @type-binding.type
195
+ attribute: (identifier) @_items))))
196
+ (#eq? @_enum "enumerate")
197
+ (#eq? @_items "items")) @type-binding.alias
198
+
199
+ ;; for u in self.X — heuristic: bind u to X (the attribute name).
200
+ ;; The chain-follow then resolves X via the enclosing method's
201
+ ;; parameter typeBinding, supporting fixtures that reference
202
+ ;; \`self.X\` as a stand-in for a parameter X (matches legacy DAG
203
+ ;; behavior).
204
+ (for_statement
205
+ left: (identifier) @type-binding.name
206
+ right: (attribute
207
+ object: (identifier) @_self
208
+ attribute: (identifier) @type-binding.type)
209
+ (#eq? @_self "self")) @type-binding.alias
210
+
211
+ ;; for v in d.values() — bind v to d (dict-strip yields value type).
212
+ (for_statement
213
+ left: (identifier) @type-binding.name
214
+ right: (call
215
+ function: (attribute
216
+ object: (identifier) @type-binding.type
217
+ attribute: (identifier) @_values))
218
+ (#eq? @_values "values")) @type-binding.alias
219
+
220
+ ;; Type bindings (variable annotations: \`u: User\` / \`u: User = x\`)
221
+ (assignment
222
+ left: (identifier) @type-binding.name
223
+ type: (type) @type-binding.type) @type-binding.annotation
224
+
225
+ ;; Return-type annotation: \`def get_user() -> User:\` binds the
226
+ ;; FUNCTION'S NAME to its return type in the enclosing scope. Combined
227
+ ;; with the constructor-inferred + chain-follow path, \`u = get_user()\`
228
+ ;; then resolves \`u: User\` cross-call. The Python provider hoists the
229
+ ;; binding via \`pythonBindingScopeFor\` to the function's parent scope
230
+ ;; so callers in module/class scope see it.
231
+ (function_definition
232
+ name: (identifier) @type-binding.name
233
+ return_type: (type) @type-binding.type) @type-binding.return
234
+
235
+ ;; References — calls
236
+ (call
237
+ function: (identifier) @reference.name) @reference.call.free
238
+
239
+ (call
240
+ function: (attribute
241
+ object: (_) @reference.receiver
242
+ attribute: (identifier) @reference.name)) @reference.call.member
243
+
244
+ ;; References — attribute writes: \`obj.name = "x"\` emits a write
245
+ ;; ACCESSES edge from the enclosing function to the field on obj's
246
+ ;; class. The receiver-bound emit pass resolves obj → its class and
247
+ ;; \`name\` → the field def via the existing typeref-receiver path.
248
+ (assignment
249
+ left: (attribute
250
+ object: (_) @reference.receiver
251
+ attribute: (identifier) @reference.name)) @reference.write.member
252
+ `;
253
+ let _parser = null;
254
+ let _query = null;
255
+ export function getPythonParser() {
256
+ if (_parser === null) {
257
+ _parser = new Parser();
258
+ _parser.setLanguage(Python);
259
+ }
260
+ return _parser;
261
+ }
262
+ export function getPythonScopeQuery() {
263
+ if (_query === null) {
264
+ _query = new Parser.Query(Python, PYTHON_SCOPE_QUERY);
265
+ }
266
+ return _query;
267
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Synthesize `@type-binding.self` / `@type-binding.cls` captures for
3
+ * methods.
4
+ *
5
+ * Tree-sitter can't easily express "the first parameter of a function
6
+ * defined directly inside a class body" via a single static query.
7
+ * Doing this in code keeps the embedded scope query declarative and
8
+ * lets us encode the `@classmethod` / `@staticmethod` decorator
9
+ * awareness that Python's runtime depends on.
10
+ */
11
+ import type { CaptureMatch } from '../../../../_shared/index.js';
12
+ import { type SyntaxNode } from '../../utils/ast-helpers.js';
13
+ /**
14
+ * Build a `@type-binding.self` (instance method) or `@type-binding.cls`
15
+ * (`@classmethod`) match for `fnNode`, or `null` if `fnNode` is not a
16
+ * method, is `@staticmethod`, or has no parameters.
17
+ *
18
+ * The caller is responsible for guaranteeing `fnNode.type ===
19
+ * 'function_definition'`.
20
+ */
21
+ export declare function synthesizeReceiverTypeBinding(fnNode: SyntaxNode): CaptureMatch | null;
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Synthesize `@type-binding.self` / `@type-binding.cls` captures for
3
+ * methods.
4
+ *
5
+ * Tree-sitter can't easily express "the first parameter of a function
6
+ * defined directly inside a class body" via a single static query.
7
+ * Doing this in code keeps the embedded scope query declarative and
8
+ * lets us encode the `@classmethod` / `@staticmethod` decorator
9
+ * awareness that Python's runtime depends on.
10
+ */
11
+ import { nodeToCapture, syntheticCapture } from '../../utils/ast-helpers.js';
12
+ /** Walk up to the enclosing `class_definition`, ignoring the immediate
13
+ * `decorated_definition` wrapper. Returns `null` when the function is
14
+ * free, lambda-bodied, or nested inside another function. */
15
+ function findEnclosingClassDefinition(node) {
16
+ let cur = node.parent;
17
+ while (cur !== null) {
18
+ if (cur.type === 'class_definition')
19
+ return cur;
20
+ if (cur.type === 'function_definition')
21
+ return null;
22
+ cur = cur.parent;
23
+ }
24
+ return null;
25
+ }
26
+ function classDefinitionName(classNode) {
27
+ return classNode.childForFieldName('name')?.text ?? null;
28
+ }
29
+ /** Does the function carry a `@<decoratorName>` decorator? Matches both
30
+ * bare `@classmethod` and module-qualified `@functools.classmethod`. */
31
+ function hasDecorator(fnNode, decoratorName) {
32
+ const parent = fnNode.parent;
33
+ if (parent === null || parent.type !== 'decorated_definition')
34
+ return false;
35
+ for (let i = 0; i < parent.namedChildCount; i++) {
36
+ const child = parent.namedChild(i);
37
+ if (child === null || child.type !== 'decorator')
38
+ continue;
39
+ const text = child.text.replace(/^@/, '').split('(')[0].trim();
40
+ const tail = text.split('.').pop();
41
+ if (tail === decoratorName)
42
+ return true;
43
+ }
44
+ return false;
45
+ }
46
+ function firstNamedParameter(parameters) {
47
+ for (let i = 0; i < parameters.namedChildCount; i++) {
48
+ const child = parameters.namedChild(i);
49
+ if (child === null)
50
+ continue;
51
+ // Skip `*` / `/` markers.
52
+ if (child.type === 'positional_separator' || child.type === 'keyword_separator')
53
+ continue;
54
+ return child;
55
+ }
56
+ return null;
57
+ }
58
+ function firstParameterName(param) {
59
+ if (param.type === 'identifier')
60
+ return param.text;
61
+ // typed_parameter / default_parameter / typed_default_parameter:
62
+ // first child holds the identifier / pattern.
63
+ const ident = param.childForFieldName('name') ?? findIdentifierChild(param);
64
+ return ident?.text ?? null;
65
+ }
66
+ function findIdentifierChild(node) {
67
+ for (let i = 0; i < node.namedChildCount; i++) {
68
+ const child = node.namedChild(i);
69
+ if (child !== null && child.type === 'identifier')
70
+ return child;
71
+ }
72
+ return null;
73
+ }
74
+ /**
75
+ * Build a `@type-binding.self` (instance method) or `@type-binding.cls`
76
+ * (`@classmethod`) match for `fnNode`, or `null` if `fnNode` is not a
77
+ * method, is `@staticmethod`, or has no parameters.
78
+ *
79
+ * The caller is responsible for guaranteeing `fnNode.type ===
80
+ * 'function_definition'`.
81
+ */
82
+ export function synthesizeReceiverTypeBinding(fnNode) {
83
+ const enclosingClass = findEnclosingClassDefinition(fnNode);
84
+ if (enclosingClass === null)
85
+ return null;
86
+ // Skip @staticmethod-decorated methods (no implicit receiver).
87
+ if (hasDecorator(fnNode, 'staticmethod'))
88
+ return null;
89
+ const isClassmethod = hasDecorator(fnNode, 'classmethod');
90
+ const params = fnNode.childForFieldName('parameters');
91
+ if (params === null)
92
+ return null;
93
+ const first = firstNamedParameter(params);
94
+ if (first === null)
95
+ return null;
96
+ const className = classDefinitionName(enclosingClass);
97
+ if (className === null)
98
+ return null;
99
+ const firstName = firstParameterName(first);
100
+ if (firstName === null)
101
+ return null;
102
+ // Receiver convention: instance methods get `self`, classmethods get `cls`.
103
+ // We trust the AST literal name (Python convention is strict in practice).
104
+ if (isClassmethod) {
105
+ return {
106
+ '@type-binding.cls': nodeToCapture('@type-binding.cls', first),
107
+ '@type-binding.name': syntheticCapture('@type-binding.name', first, firstName),
108
+ '@type-binding.type': syntheticCapture('@type-binding.type', first, className),
109
+ };
110
+ }
111
+ return {
112
+ '@type-binding.self': nodeToCapture('@type-binding.self', first),
113
+ '@type-binding.name': syntheticCapture('@type-binding.name', first, firstName),
114
+ '@type-binding.type': syntheticCapture('@type-binding.type', first, className),
115
+ };
116
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Python `ScopeResolver` registered in `SCOPE_RESOLVERS` and consumed
3
+ * by the generic `runScopeResolution` orchestrator.
4
+ *
5
+ * The provider is a thin wiring object — Python's specific bits
6
+ * (super recognizer, LEGB merge precedence, Python's relative-import
7
+ * resolver, the simplified MRO walk) plug into `runScopeResolution`.
8
+ *
9
+ * Migration reference: when bringing up the next language
10
+ * (TypeScript / Java / Kotlin / Ruby), copy this file's structure —
11
+ * implement the 6 required `ScopeResolver` fields, optionally toggle
12
+ * the 2 booleans, and register in `scope-resolution/pipeline/registry.ts`.
13
+ */
14
+ import type { ScopeResolver } from '../../scope-resolution/contract/scope-resolver.js';
15
+ declare const pythonScopeResolver: ScopeResolver;
16
+ export { pythonScopeResolver };
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Python `ScopeResolver` registered in `SCOPE_RESOLVERS` and consumed
3
+ * by the generic `runScopeResolution` orchestrator.
4
+ *
5
+ * The provider is a thin wiring object — Python's specific bits
6
+ * (super recognizer, LEGB merge precedence, Python's relative-import
7
+ * resolver, the simplified MRO walk) plug into `runScopeResolution`.
8
+ *
9
+ * Migration reference: when bringing up the next language
10
+ * (TypeScript / Java / Kotlin / Ruby), copy this file's structure —
11
+ * implement the 6 required `ScopeResolver` fields, optionally toggle
12
+ * the 2 booleans, and register in `scope-resolution/pipeline/registry.ts`.
13
+ */
14
+ import { SupportedLanguages } from '../../../../_shared/index.js';
15
+ import { buildMro, defaultLinearize } from '../../scope-resolution/passes/mro.js';
16
+ import { populateClassOwnedMembers } from '../../scope-resolution/scope/walkers.js';
17
+ import { pythonProvider } from '../python.js';
18
+ import { pythonArityCompatibility, pythonMergeBindings, resolvePythonImportTarget, } from './index.js';
19
+ const pythonScopeResolver = {
20
+ language: SupportedLanguages.Python,
21
+ languageProvider: pythonProvider,
22
+ importEdgeReason: 'python-scope: import',
23
+ resolveImportTarget: (targetRaw, fromFile, allFilePaths) => {
24
+ // Copy the orchestrator's `ReadonlySet` into a `Set` because the
25
+ // legacy Python resolver chain (`resolvePythonImportInternal` →
26
+ // `resolveAbsoluteFromFiles` / `hasRepoCandidate`) is typed to
27
+ // receive a mutable `Set<string>`. The copy is O(N) but called
28
+ // once per import — trivial compared to the parser work.
29
+ const ws = { fromFile, allFilePaths: new Set(allFilePaths) };
30
+ // `WorkspaceIndex` is an opaque `unknown` placeholder in the
31
+ // shared contract, so `ws` passes structurally without a cast.
32
+ return resolvePythonImportTarget({ kind: 'named', localName: '_', importedName: '_', targetRaw }, ws);
33
+ },
34
+ // Python LEGB precedence: local > import/namespace/reexport > wildcard.
35
+ // The per-scope id is unused by pythonMergeBindings (tier ordering
36
+ // is computed purely from BindingRef.origin), so we don't need to
37
+ // synthesize a Scope.
38
+ mergeBindings: (existing, incoming) => [...pythonMergeBindings([...existing, ...incoming])],
39
+ // Adapter: pythonArityCompatibility predates RegistryProviders and
40
+ // uses (def, callsite). ScopeResolver contract is (callsite, def).
41
+ // Wrapper kept to honor both contracts without altering the legacy
42
+ // shape that LanguageProvider.arityCompatibility consumes.
43
+ arityCompatibility: (callsite, def) => pythonArityCompatibility(def, callsite),
44
+ buildMro: (graph, parsedFiles, nodeLookup) => buildMro(graph, parsedFiles, nodeLookup, defaultLinearize),
45
+ populateOwners: (parsed) => populateClassOwnedMembers(parsed),
46
+ isSuperReceiver: (text) => /^super\s*\(/.test(text),
47
+ // Python is dynamically typed — field-fallback heuristic on, return-
48
+ // type propagation across imports on. Both default to true; listed
49
+ // explicitly here for documentation.
50
+ fieldFallbackOnMethodLookup: true,
51
+ propagatesReturnTypesAcrossImports: true,
52
+ };
53
+ export { pythonScopeResolver };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Trivial / no-op-ish hooks for the Python provider. Kept together
3
+ * because each is a few lines and they share a common theme: they exist
4
+ * to make the provider's choice explicit (rather than relying on
5
+ * "absence == default") so reviewers don't have to re-derive the
6
+ * analysis.
7
+ */
8
+ import type { CaptureMatch, ParsedImport, Scope, ScopeId, ScopeTree, TypeRef } from '../../../../_shared/index.js';
9
+ /** Python has no block scope, so the central extractor's "innermost
10
+ * enclosing scope" default is already correct: `for x in …` creates
11
+ * `x` in the enclosing function/module scope (because we never emit a
12
+ * `@scope.block` for the for-loop body), comprehension variables stay
13
+ * in their expression context, etc. Returns `null` to delegate. */
14
+ export declare function pythonBindingScopeFor(_decl: CaptureMatch, _innermost: Scope, _tree: ScopeTree): ScopeId | null;
15
+ /** Function-local `from x import Y` should attach the binding to the
16
+ * function scope, not the module. Class-body imports (rare but legal —
17
+ * `class A: import x` makes `x` a class attribute) attach to the class.
18
+ * Module-level imports delegate to the central default. */
19
+ export declare function pythonImportOwningScope(_imp: ParsedImport, innermost: Scope, _tree: ScopeTree): ScopeId | null;
20
+ /** Look up `self` or `cls` in the function scope's type bindings.
21
+ * Returns `null` for free functions (no `self`/`cls`) and for
22
+ * non-Function scopes. */
23
+ export declare function pythonReceiverBinding(functionScope: Scope): TypeRef | null;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Trivial / no-op-ish hooks for the Python provider. Kept together
3
+ * because each is a few lines and they share a common theme: they exist
4
+ * to make the provider's choice explicit (rather than relying on
5
+ * "absence == default") so reviewers don't have to re-derive the
6
+ * analysis.
7
+ */
8
+ // ─── bindingScopeFor ──────────────────────────────────────────────────────
9
+ /** Python has no block scope, so the central extractor's "innermost
10
+ * enclosing scope" default is already correct: `for x in …` creates
11
+ * `x` in the enclosing function/module scope (because we never emit a
12
+ * `@scope.block` for the for-loop body), comprehension variables stay
13
+ * in their expression context, etc. Returns `null` to delegate. */
14
+ export function pythonBindingScopeFor(_decl, _innermost, _tree) {
15
+ return null;
16
+ }
17
+ // ─── importOwningScope ────────────────────────────────────────────────────
18
+ /** Function-local `from x import Y` should attach the binding to the
19
+ * function scope, not the module. Class-body imports (rare but legal —
20
+ * `class A: import x` makes `x` a class attribute) attach to the class.
21
+ * Module-level imports delegate to the central default. */
22
+ export function pythonImportOwningScope(_imp, innermost, _tree) {
23
+ if (innermost.kind === 'Function' || innermost.kind === 'Class')
24
+ return innermost.id;
25
+ return null;
26
+ }
27
+ // ─── receiverBinding ──────────────────────────────────────────────────────
28
+ /** Look up `self` or `cls` in the function scope's type bindings.
29
+ * Returns `null` for free functions (no `self`/`cls`) and for
30
+ * non-Function scopes. */
31
+ export function pythonReceiverBinding(functionScope) {
32
+ if (functionScope.kind !== 'Function')
33
+ return null;
34
+ return functionScope.typeBindings.get('self') ?? functionScope.typeBindings.get('cls') ?? null;
35
+ }
@@ -28,6 +28,7 @@ import { pythonVariableConfig } from '../variable-extractors/configs/python.js';
28
28
  import { createCallExtractor } from '../call-extractors/generic.js';
29
29
  import { pythonCallConfig } from '../call-extractors/configs/python.js';
30
30
  import { createHeritageExtractor } from '../heritage-extractors/generic.js';
31
+ import { emitPythonScopeCaptures, interpretPythonImport, interpretPythonTypeBinding, pythonArityCompatibility, pythonBindingScopeFor, pythonImportOwningScope, pythonMergeBindings, pythonReceiverBinding, resolvePythonImportTarget, } from './python/index.js';
31
32
  const BUILT_INS = new Set([
32
33
  'print',
33
34
  'len',
@@ -74,4 +75,17 @@ export const pythonProvider = defineLanguage({
74
75
  classExtractor: createClassExtractor(pythonClassConfig),
75
76
  heritageExtractor: createHeritageExtractor(SupportedLanguages.Python),
76
77
  builtInNames: BUILT_INS,
78
+ // ── RFC #909 Ring 3: scope-based resolution hooks (RFC §5) ──────────
79
+ // Python is the first migration. See ./python/index.ts for the
80
+ // full per-hook rationale and the canonical capture vocabulary in
81
+ // ./python/query.ts (PYTHON_SCOPE_QUERY constant).
82
+ emitScopeCaptures: emitPythonScopeCaptures,
83
+ interpretImport: interpretPythonImport,
84
+ interpretTypeBinding: interpretPythonTypeBinding,
85
+ bindingScopeFor: pythonBindingScopeFor,
86
+ importOwningScope: pythonImportOwningScope,
87
+ mergeBindings: (_scope, bindings) => pythonMergeBindings(bindings),
88
+ receiverBinding: pythonReceiverBinding,
89
+ arityCompatibility: pythonArityCompatibility,
90
+ resolveImportTarget: resolvePythonImportTarget,
77
91
  });
@@ -37,6 +37,15 @@ export interface MethodRegistry {
37
37
  * allocation reachable from two indexes.
38
38
  */
39
39
  lookupMethodByName(name: string): readonly SymbolDefinition[];
40
+ /**
41
+ * Return every overload registered under `(ownerNodeId, methodName)`,
42
+ * unfiltered by arity or return type. This is the raw owner-scoped
43
+ * view — callers that need arity narrowing or unambiguous single-
44
+ * result semantics should use `lookupMethodByOwner` instead.
45
+ *
46
+ * Returns `[]` on miss so callers can iterate without null checks.
47
+ */
48
+ lookupAllByOwner(ownerNodeId: string, methodName: string): readonly SymbolDefinition[];
40
49
  /**
41
50
  * True iff at least one registered def has `type === 'Function'` — i.e.,
42
51
  * a Python/Rust/Kotlin class method emitted by the worker as
@@ -88,6 +88,9 @@ export const createMethodRegistry = () => {
88
88
  const lookupMethodByName = (name) => {
89
89
  return methodsByName.get(name) ?? EMPTY;
90
90
  };
91
+ const lookupAllByOwner = (ownerNodeId, methodName) => {
92
+ return methodByOwner.get(`${ownerNodeId}\0${methodName}`) ?? EMPTY;
93
+ };
91
94
  const register = (ownerNodeId, methodName, def) => {
92
95
  const key = `${ownerNodeId}\0${methodName}`;
93
96
  const existing = methodByOwner.get(key);
@@ -121,6 +124,7 @@ export const createMethodRegistry = () => {
121
124
  return {
122
125
  lookupMethodByOwner,
123
126
  lookupMethodByName,
127
+ lookupAllByOwner,
124
128
  register,
125
129
  clear,
126
130
  get hasFunctionMethods() {
@@ -0,0 +1,59 @@
1
+ /**
2
+ * `ScopeResolutionIndexes` — the bundle of materialized indexes produced
3
+ * by the finalize-orchestrator (RFC #909 Ring 2 PKG #921) and attached
4
+ * to `MutableSemanticModel`.
5
+ *
6
+ * Produced by `finalizeScopeModel(parsedFiles, hooks)` in
7
+ * `finalize-orchestrator.ts`. Consumed by the resolution phase (future
8
+ * tickets) where `Registry.lookup` / `resolveTypeRef` query this bundle
9
+ * to answer call-resolution questions without re-walking any AST.
10
+ *
11
+ * ## Lifecycle
12
+ *
13
+ * 1. Pipeline collects `ParsedFile[]` from the parsing-processor (#920).
14
+ * 2. Pipeline invokes `finalizeScopeModel(parsedFiles, hooks)` →
15
+ * returns a `ScopeResolutionIndexes` (this interface).
16
+ * 3. Pipeline calls `model.attachScopeIndexes(indexes)` to stamp them
17
+ * onto the `MutableSemanticModel`. This is a **one-shot write**;
18
+ * subsequent calls throw. After attachment, the indexes are frozen
19
+ * at the type level (everything is `readonly`) and at runtime via
20
+ * `Object.freeze` on the bundle.
21
+ * 4. Resolution callers hold a `SemanticModel` reference and read
22
+ * `model.scopes` to query.
23
+ *
24
+ * ## Content
25
+ *
26
+ * - `scopeTree` / `moduleScopes` / `defs` / `qualifiedNames` — the
27
+ * four Ring 2 SHARED indexes built over per-file artifacts.
28
+ * - `methodDispatch` — MRO + implements materialized view (#914).
29
+ * - `imports` — finalized `ImportEdge[]` per module scope (`parsedImports`
30
+ * resolved through cross-file link + wildcard expansion).
31
+ * - `bindings` — merged bindings per module scope (local + import +
32
+ * wildcard + re-export), with the provider's precedence applied.
33
+ * - `referenceSites` — union of every file's pre-resolution usage
34
+ * facts. Consumed by the resolution phase (future) to emit
35
+ * `Reference` records into `ReferenceIndex`.
36
+ * - `stats` — coarse-grained counts from the shared finalize algorithm
37
+ * (total files/edges, linked vs unresolved, SCC topology).
38
+ *
39
+ * `ReferenceIndex` is deliberately NOT here — it is populated in a later
40
+ * phase (RFC §3.2 Phase 4 / Ring 2 PKG #925) and owned separately.
41
+ */
42
+ import type { BindingRef, DefIndex, FinalizedScc, FinalizeStats, ImportEdge, MethodDispatchIndex, ModuleScopeIndex, QualifiedNameIndex, ReferenceSite, ScopeId, ScopeTree } from '../../../_shared/index.js';
43
+ export interface ScopeResolutionIndexes {
44
+ readonly scopeTree: ScopeTree;
45
+ readonly defs: DefIndex;
46
+ readonly qualifiedNames: QualifiedNameIndex;
47
+ readonly moduleScopes: ModuleScopeIndex;
48
+ readonly methodDispatch: MethodDispatchIndex;
49
+ /** Finalized `ImportEdge[]` per module scope. */
50
+ readonly imports: ReadonlyMap<ScopeId, readonly ImportEdge[]>;
51
+ /** Merged bindings (local + imports + wildcards) per module scope. */
52
+ readonly bindings: ReadonlyMap<ScopeId, ReadonlyMap<string, readonly BindingRef[]>>;
53
+ /** Pre-resolution usage facts; consumed by the resolution phase. */
54
+ readonly referenceSites: readonly ReferenceSite[];
55
+ /** SCC condensation of the file-level import graph — callers that want
56
+ * parallel per-SCC processing in the resolution phase read this. */
57
+ readonly sccs: readonly FinalizedScc[];
58
+ readonly stats: FinalizeStats;
59
+ }