gitnexus 1.6.4-rc.2 → 1.6.4-rc.21

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 (243) hide show
  1. package/README.md +35 -0
  2. package/dist/_shared/index.d.ts +1 -1
  3. package/dist/_shared/index.d.ts.map +1 -1
  4. package/dist/_shared/index.js +1 -1
  5. package/dist/_shared/index.js.map +1 -1
  6. package/dist/_shared/scope-resolution/finalize-algorithm.d.ts +22 -14
  7. package/dist/_shared/scope-resolution/finalize-algorithm.d.ts.map +1 -1
  8. package/dist/_shared/scope-resolution/finalize-algorithm.js +298 -37
  9. package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
  10. package/dist/_shared/scope-resolution/scope-tree.d.ts +23 -1
  11. package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -1
  12. package/dist/_shared/scope-resolution/scope-tree.js +36 -2
  13. package/dist/_shared/scope-resolution/scope-tree.js.map +1 -1
  14. package/dist/_shared/scope-resolution/types.d.ts +47 -3
  15. package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
  16. package/dist/_shared/scope-resolution/types.js +10 -2
  17. package/dist/_shared/scope-resolution/types.js.map +1 -1
  18. package/dist/cli/analyze.d.ts +6 -0
  19. package/dist/cli/analyze.js +35 -0
  20. package/dist/cli/doctor.d.ts +1 -0
  21. package/dist/cli/doctor.js +31 -0
  22. package/dist/cli/index.js +13 -0
  23. package/dist/cli/setup.js +2 -2
  24. package/dist/core/embeddings/config.d.ts +2 -0
  25. package/dist/core/embeddings/config.js +36 -0
  26. package/dist/core/embeddings/embedder.js +11 -6
  27. package/dist/core/embeddings/embedding-pipeline.d.ts +7 -1
  28. package/dist/core/embeddings/embedding-pipeline.js +93 -29
  29. package/dist/core/embeddings/exact-search.d.ts +15 -0
  30. package/dist/core/embeddings/exact-search.js +27 -0
  31. package/dist/core/embeddings/types.d.ts +4 -0
  32. package/dist/core/embeddings/types.js +2 -0
  33. package/dist/core/group/config-parser.js +2 -0
  34. package/dist/core/group/matching.d.ts +3 -3
  35. package/dist/core/group/matching.js +46 -6
  36. package/dist/core/group/storage.js +2 -0
  37. package/dist/core/group/sync.js +1 -1
  38. package/dist/core/group/types.d.ts +18 -0
  39. package/dist/core/ingestion/call-processor.d.ts +3 -3
  40. package/dist/core/ingestion/call-processor.js +58 -65
  41. package/dist/core/ingestion/constants.d.ts +4 -3
  42. package/dist/core/ingestion/constants.js +8 -3
  43. package/dist/core/ingestion/finalize-orchestrator.js +6 -3
  44. package/dist/core/ingestion/heritage-processor.js +2 -2
  45. package/dist/core/ingestion/import-processor.js +1 -1
  46. package/dist/core/ingestion/language-provider.d.ts +8 -0
  47. package/dist/core/ingestion/languages/csharp/captures.js +4 -1
  48. package/dist/core/ingestion/languages/csharp/namespace-siblings.d.ts +14 -13
  49. package/dist/core/ingestion/languages/csharp/namespace-siblings.js +62 -50
  50. package/dist/core/ingestion/languages/python/captures.js +9 -1
  51. package/dist/core/ingestion/languages/python/index.d.ts +1 -1
  52. package/dist/core/ingestion/languages/python/index.js +1 -1
  53. package/dist/core/ingestion/languages/python/simple-hooks.d.ts +3 -1
  54. package/dist/core/ingestion/languages/python/simple-hooks.js +8 -0
  55. package/dist/core/ingestion/languages/python.js +28 -1
  56. package/dist/core/ingestion/languages/swift.js +14 -0
  57. package/dist/core/ingestion/languages/typescript/arity-metadata.d.ts +59 -0
  58. package/dist/core/ingestion/languages/typescript/arity-metadata.js +103 -0
  59. package/dist/core/ingestion/languages/typescript/arity.d.ts +37 -0
  60. package/dist/core/ingestion/languages/typescript/arity.js +54 -0
  61. package/dist/core/ingestion/languages/typescript/cache-stats.d.ts +17 -0
  62. package/dist/core/ingestion/languages/typescript/cache-stats.js +28 -0
  63. package/dist/core/ingestion/languages/typescript/captures.d.ts +28 -0
  64. package/dist/core/ingestion/languages/typescript/captures.js +451 -0
  65. package/dist/core/ingestion/languages/typescript/import-decomposer.d.ts +49 -0
  66. package/dist/core/ingestion/languages/typescript/import-decomposer.js +371 -0
  67. package/dist/core/ingestion/languages/typescript/import-target.d.ts +50 -0
  68. package/dist/core/ingestion/languages/typescript/import-target.js +61 -0
  69. package/dist/core/ingestion/languages/typescript/index.d.ts +94 -0
  70. package/dist/core/ingestion/languages/typescript/index.js +94 -0
  71. package/dist/core/ingestion/languages/typescript/interpret.d.ts +35 -0
  72. package/dist/core/ingestion/languages/typescript/interpret.js +317 -0
  73. package/dist/core/ingestion/languages/typescript/merge-bindings.d.ts +62 -0
  74. package/dist/core/ingestion/languages/typescript/merge-bindings.js +158 -0
  75. package/dist/core/ingestion/languages/typescript/query.d.ts +77 -0
  76. package/dist/core/ingestion/languages/typescript/query.js +778 -0
  77. package/dist/core/ingestion/languages/typescript/receiver-binding.d.ts +59 -0
  78. package/dist/core/ingestion/languages/typescript/receiver-binding.js +171 -0
  79. package/dist/core/ingestion/languages/typescript/scope-resolver.d.ts +16 -0
  80. package/dist/core/ingestion/languages/typescript/scope-resolver.js +113 -0
  81. package/dist/core/ingestion/languages/typescript/simple-hooks.d.ts +71 -0
  82. package/dist/core/ingestion/languages/typescript/simple-hooks.js +131 -0
  83. package/dist/core/ingestion/languages/typescript.js +19 -0
  84. package/dist/core/ingestion/method-extractors/configs/swift.js +3 -4
  85. package/dist/core/ingestion/model/scope-resolution-indexes.d.ts +14 -1
  86. package/dist/core/ingestion/parsing-processor.js +20 -9
  87. package/dist/core/ingestion/pipeline-phases/processes.js +9 -4
  88. package/dist/core/ingestion/pipeline-phases/tools.d.ts +1 -0
  89. package/dist/core/ingestion/pipeline-phases/tools.js +10 -4
  90. package/dist/core/ingestion/registry-primary-flag.d.ts +3 -1
  91. package/dist/core/ingestion/registry-primary-flag.js +4 -1
  92. package/dist/core/ingestion/scope-extractor-bridge.d.ts +5 -2
  93. package/dist/core/ingestion/scope-extractor-bridge.js +7 -2
  94. package/dist/core/ingestion/scope-extractor.js +19 -18
  95. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +73 -11
  96. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.js +48 -10
  97. package/dist/core/ingestion/scope-resolution/passes/compound-receiver.js +283 -14
  98. package/dist/core/ingestion/scope-resolution/passes/imported-return-types.d.ts +23 -2
  99. package/dist/core/ingestion/scope-resolution/passes/imported-return-types.js +109 -37
  100. package/dist/core/ingestion/scope-resolution/passes/mro.js +3 -1
  101. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +13 -5
  102. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +11 -2
  103. package/dist/core/ingestion/scope-resolution/pipeline/registry.js +2 -0
  104. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +8 -0
  105. package/dist/core/ingestion/scope-resolution/pipeline/run.js +21 -5
  106. package/dist/core/ingestion/scope-resolution/pipeline/validate-bindings-immutability.d.ts +39 -0
  107. package/dist/core/ingestion/scope-resolution/pipeline/validate-bindings-immutability.js +65 -0
  108. package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +54 -11
  109. package/dist/core/ingestion/scope-resolution/scope/walkers.js +105 -30
  110. package/dist/core/ingestion/type-extractors/swift.js +7 -4
  111. package/dist/core/ingestion/utils/ast-helpers.d.ts +2 -0
  112. package/dist/core/ingestion/utils/ast-helpers.js +12 -0
  113. package/dist/core/ingestion/utils/env.d.ts +10 -0
  114. package/dist/core/ingestion/utils/env.js +14 -0
  115. package/dist/core/ingestion/workers/parse-worker.d.ts +1 -0
  116. package/dist/core/ingestion/workers/parse-worker.js +15 -9
  117. package/dist/core/ingestion/workers/worker-pool.d.ts +11 -4
  118. package/dist/core/ingestion/workers/worker-pool.js +244 -48
  119. package/dist/core/lbug/extension-loader.d.ts +86 -0
  120. package/dist/core/lbug/extension-loader.js +184 -0
  121. package/dist/core/lbug/lbug-adapter.d.ts +18 -17
  122. package/dist/core/lbug/lbug-adapter.js +45 -73
  123. package/dist/core/lbug/pool-adapter.js +10 -28
  124. package/dist/core/platform/capabilities.d.ts +24 -0
  125. package/dist/core/platform/capabilities.js +54 -0
  126. package/dist/core/run-analyze.js +36 -9
  127. package/dist/core/search/bm25-index.d.ts +0 -17
  128. package/dist/core/search/bm25-index.js +10 -118
  129. package/dist/core/search/fts-indexes.d.ts +1 -0
  130. package/dist/core/search/fts-indexes.js +7 -0
  131. package/dist/core/search/fts-schema.d.ts +6 -0
  132. package/dist/core/search/fts-schema.js +7 -0
  133. package/dist/mcp/core/embedder.js +11 -4
  134. package/dist/mcp/local/local-backend.js +50 -15
  135. package/dist/server/api.d.ts +5 -0
  136. package/dist/server/api.js +113 -0
  137. package/hooks/claude/gitnexus-hook.cjs +11 -1
  138. package/package.json +6 -5
  139. package/scripts/build-tree-sitter-dart.cjs +42 -0
  140. package/scripts/build-tree-sitter-proto.cjs +1 -1
  141. package/scripts/build.js +22 -2
  142. package/scripts/install-duckdb-extension.mjs +37 -0
  143. package/vendor/tree-sitter-dart/README.md +18 -0
  144. package/vendor/tree-sitter-dart/binding.gyp +31 -0
  145. package/vendor/tree-sitter-dart/bindings/node/binding.cc +20 -0
  146. package/vendor/tree-sitter-dart/bindings/node/index.d.ts +28 -0
  147. package/vendor/tree-sitter-dart/bindings/node/index.js +7 -0
  148. package/vendor/tree-sitter-dart/grammar.js +2895 -0
  149. package/vendor/tree-sitter-dart/package.json +18 -0
  150. package/vendor/tree-sitter-dart/queries/highlights.scm +246 -0
  151. package/vendor/tree-sitter-dart/queries/tags.scm +92 -0
  152. package/vendor/tree-sitter-dart/queries/test.scm +1 -0
  153. package/vendor/tree-sitter-dart/src/grammar.json +12459 -0
  154. package/vendor/tree-sitter-dart/src/node-types.json +15055 -0
  155. package/vendor/tree-sitter-dart/src/parser.c +196127 -0
  156. package/vendor/tree-sitter-dart/src/scanner.c +130 -0
  157. package/vendor/tree-sitter-dart/src/tree_sitter/alloc.h +54 -0
  158. package/vendor/tree-sitter-dart/src/tree_sitter/array.h +290 -0
  159. package/vendor/tree-sitter-dart/src/tree_sitter/parser.h +265 -0
  160. package/vendor/tree-sitter-swift/LICENSE +21 -0
  161. package/vendor/tree-sitter-swift/README.md +139 -0
  162. package/vendor/tree-sitter-swift/bindings/node/index.d.ts +28 -0
  163. package/vendor/tree-sitter-swift/bindings/node/index.js +7 -0
  164. package/vendor/tree-sitter-swift/package.json +28 -0
  165. package/vendor/tree-sitter-swift/prebuilds/darwin-arm64/tree-sitter-swift.node +0 -0
  166. package/vendor/tree-sitter-swift/prebuilds/darwin-x64/tree-sitter-swift.node +0 -0
  167. package/vendor/tree-sitter-swift/prebuilds/linux-arm64/tree-sitter-swift.node +0 -0
  168. package/vendor/tree-sitter-swift/prebuilds/linux-x64/tree-sitter-swift.node +0 -0
  169. package/vendor/tree-sitter-swift/prebuilds/win32-arm64/tree-sitter-swift.node +0 -0
  170. package/vendor/tree-sitter-swift/prebuilds/win32-x64/tree-sitter-swift.node +0 -0
  171. package/vendor/tree-sitter-swift/src/node-types.json +30694 -0
  172. package/web/assets/agent-DaprsFSX.js +597 -0
  173. package/web/assets/architecture-YZFGNWBL-S5CXDPWN-DEdGaPg2.js +1 -0
  174. package/web/assets/architectureDiagram-EMZXCZ2Q-Domyk_gO.js +36 -0
  175. package/web/assets/blockDiagram-IGV67L2C-B_2kD7tM.js +132 -0
  176. package/web/assets/c4Diagram-DFAF54RM-BhJJW8Gg.js +10 -0
  177. package/web/assets/chunk-3GS5O3IE-jlWIjPsl.js +231 -0
  178. package/web/assets/chunk-3YCYZ6SJ-Blq_IzZs.js +1 -0
  179. package/web/assets/chunk-6NTNNK5N-DyPc58pp.js +1 -0
  180. package/web/assets/chunk-7RZVMHOQ-BdIU-RGO.js +321 -0
  181. package/web/assets/chunk-A34GCYZU-BI2i_LdU.js +1 -0
  182. package/web/assets/chunk-AEOMTBSW-D7qjBMHW.js +1 -0
  183. package/web/assets/chunk-CilyBKbf.js +1 -0
  184. package/web/assets/chunk-DJ7UZH7F-i11ywiBl.js +1 -0
  185. package/web/assets/chunk-DKKBVRCY-1SffGI1N.js +4 -0
  186. package/web/assets/chunk-DU5LTGQ6-DaPeiwD5.js +1 -0
  187. package/web/assets/chunk-FXACKDTF-uhhi2PC2.js +159 -0
  188. package/web/assets/chunk-H3VCZNTA-IchcISDt.js +1 -0
  189. package/web/assets/chunk-HN6EAY2L-D7ZFMNrB.js +1 -0
  190. package/web/assets/chunk-KSICW3F5-C2tZmXwv.js +15 -0
  191. package/web/assets/chunk-O5ABG6QK-Bt-Km84H.js +1 -0
  192. package/web/assets/chunk-PK6DOVAG-ChlWY0BQ.js +206 -0
  193. package/web/assets/chunk-RNJOYNJ4-B724K7cW.js +1 -0
  194. package/web/assets/chunk-RWUO3TPN-DYn1XriD.js +1 -0
  195. package/web/assets/chunk-TBF5ZNIQ-DKtDz6ae.js +1 -0
  196. package/web/assets/chunk-TU3PZOEN-DE5Qhc0N.js +1 -0
  197. package/web/assets/chunk-TYMNRAUI-g1h33cq-.js +1 -0
  198. package/web/assets/chunk-VELTKBKT-C9dVN39o.js +1 -0
  199. package/web/assets/chunk-W7ZLLLMY-Du-Hb9yb.js +1 -0
  200. package/web/assets/chunk-WSB5WSVC-B123clsZ.js +1 -0
  201. package/web/assets/chunk-XGPFEOL4-BR7Eue38.js +1 -0
  202. package/web/assets/classDiagram-PPOCWD7C-BglfKSs_.js +1 -0
  203. package/web/assets/classDiagram-v2-23LJLIIU-BSzTM28O.js +1 -0
  204. package/web/assets/context-builder-CqQNhRj1.js +15 -0
  205. package/web/assets/cose-bilkent-PNC4W37J-DCfErU-A.js +1 -0
  206. package/web/assets/dagre-E77IOHMT-tDRRhDoN.js +4 -0
  207. package/web/assets/diagram-H7BISOXX-CUVHlmAh.js +43 -0
  208. package/web/assets/diagram-JC5VWROH-BoyOxulB.js +24 -0
  209. package/web/assets/diagram-LXUTUG65-osr9hb7N.js +10 -0
  210. package/web/assets/diagram-WEHSV5V5-d8nUqS39.js +24 -0
  211. package/web/assets/erDiagram-GCSMX5X6-b-IwOhPS.js +85 -0
  212. package/web/assets/flowDiagram-OTCZ4VVT-Ott2Q0AP.js +162 -0
  213. package/web/assets/ganttDiagram-MUNLMDZQ-BYtgN_5s.js +292 -0
  214. package/web/assets/gitGraph-7Q5UKJZL-54BCDZD5-CFyBIGZq.js +1 -0
  215. package/web/assets/gitGraphDiagram-3HKGZ4G3-CsVD2gn4.js +106 -0
  216. package/web/assets/index-BleGLU8S.css +2 -0
  217. package/web/assets/index-C_xK08EW.js +885 -0
  218. package/web/assets/info-OMHHGYJF-BF2H5H6G-yjAxKEzh.js +1 -0
  219. package/web/assets/infoDiagram-MN7RKWGX-DXK0Unn5.js +2 -0
  220. package/web/assets/ishikawaDiagram-YMYX4NHK-CXsnC2FA.js +70 -0
  221. package/web/assets/journeyDiagram-SO5T7YLQ-BzZ07B-X.js +139 -0
  222. package/web/assets/kanban-definition-LJHFXRCJ-C6_EpAd9.js +89 -0
  223. package/web/assets/katex-GD7MH7QM-CJiOjBBJ.js +261 -0
  224. package/web/assets/mindmap-definition-2EUWGEK5-CCYGWZ1m.js +96 -0
  225. package/web/assets/packet-4T2RLAQJ-EV4IVRXR-B8k4E3IT.js +1 -0
  226. package/web/assets/pie-ZZUOXDRM-N23DN5KN-DdvfY118.js +1 -0
  227. package/web/assets/pieDiagram-3IATQBI2-RyvRlQb4.js +30 -0
  228. package/web/assets/quadrantDiagram-E256RVCF-Bfb6sxCx.js +7 -0
  229. package/web/assets/radar-PYXPWWZC-P6TP7ZYP-1EEDC_yU.js +1 -0
  230. package/web/assets/requirementDiagram-M5DCFWZL-DjvHDyvN.js +84 -0
  231. package/web/assets/sankeyDiagram-L3NBLAOT-CBCbbl8s.js +10 -0
  232. package/web/assets/sequenceDiagram-ZOUHS735-BscU8TUR.js +157 -0
  233. package/web/assets/stateDiagram-MLPALWAM-CJusEK2D.js +1 -0
  234. package/web/assets/stateDiagram-v2-B5LQ5ZB2-DImJ3PXD.js +1 -0
  235. package/web/assets/timeline-definition-5SPVSISX-DigPA1X8.js +120 -0
  236. package/web/assets/treeView-SZITEDCU-5DXDK3XO-CzPDt3aG.js +1 -0
  237. package/web/assets/treemap-W4RFUUIX-WYLRDWKO-B9Iqiorr.js +1 -0
  238. package/web/assets/vennDiagram-IE5QUKF5-C91UkZIf.js +34 -0
  239. package/web/assets/wardley-RL74JXVD-BCRCBASE-x42Qw7hp.js +1 -0
  240. package/web/assets/wardleyDiagram-XU3VSMPF-DloBhI0U.js +20 -0
  241. package/web/assets/xychartDiagram-ZHJ5623Y-BGWJvgwI.js +7 -0
  242. package/web/index.html +21 -0
  243. package/scripts/patch-tree-sitter-swift.cjs +0 -78
@@ -10,7 +10,7 @@ import { getDefinitionNodeFromCaptures, findEnclosingClassInfo, getLabelFromCapt
10
10
  import { detectFrameworkFromAST } from './framework-detection.js';
11
11
  import { buildTypeEnv } from './type-env.js';
12
12
  import { buildMethodProps, arityForIdFromInfo, typeTagForId, constTagForId, buildCollisionGroups, } from './utils/method-props.js';
13
- import { getTreeSitterBufferSize, TREE_SITTER_MAX_BUFFER } from './constants.js';
13
+ import { getTreeSitterBufferSize, getTreeSitterContentByteLength, TREE_SITTER_MAX_BUFFER, } from './constants.js';
14
14
  // ============================================================================
15
15
  // Worker-based parallel parsing
16
16
  // ============================================================================
@@ -247,7 +247,7 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
247
247
  continue;
248
248
  }
249
249
  // Skip files larger than the max tree-sitter buffer (32 MB)
250
- if (file.content.length > TREE_SITTER_MAX_BUFFER)
250
+ if (getTreeSitterContentByteLength(file.content) > TREE_SITTER_MAX_BUFFER)
251
251
  continue;
252
252
  // Vue SFC preprocessing: extract <script> block content
253
253
  let parseContent = file.content;
@@ -270,7 +270,7 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
270
270
  let tree;
271
271
  try {
272
272
  tree = parser.parse(parseContent, undefined, {
273
- bufferSize: getTreeSitterBufferSize(parseContent.length),
273
+ bufferSize: getTreeSitterBufferSize(parseContent),
274
274
  });
275
275
  }
276
276
  catch (parseError) {
@@ -412,10 +412,12 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, sco
412
412
  }
413
413
  }
414
414
  }
415
- // Append #<paramCount> to Method/Constructor IDs to disambiguate overloads.
416
- // Functions are not suffixed they don't overload by name in the same scope.
415
+ // Append #<paramCount> to owned callable IDs to disambiguate overloads.
416
+ // Top-level Function IDs stay stable; functions inside an owner may overload.
417
417
  // When same-arity collisions exist, append ~type1,type2 for further disambiguation.
418
- const needsAritySuffix = nodeLabel === 'Method' || nodeLabel === 'Constructor';
418
+ const needsAritySuffix = nodeLabel === 'Method' ||
419
+ nodeLabel === 'Constructor' ||
420
+ (nodeLabel === 'Function' && enclosingClassId !== null);
419
421
  let arityTag = needsAritySuffix && arityForId !== undefined ? `#${arityForId}` : '';
420
422
  if (arityTag && seqDefMethods && seqDefMethodInfo && seqClassNodeId !== undefined) {
421
423
  // Use cached method map + collision groups (built once per class, not per method)
@@ -555,6 +557,13 @@ export const processParsing = async (graph, files, symbolTable, astCache,
555
557
  * Pass `undefined` if no consumer needs cross-phase access.
556
558
  */
557
559
  scopeTreeCache, onFileProgress, workerPool) => {
560
+ let lastProgress = 0;
561
+ const reportProgress = onFileProgress
562
+ ? (current, total, detail) => {
563
+ lastProgress = Math.max(lastProgress, current);
564
+ onFileProgress(lastProgress, total, detail);
565
+ }
566
+ : undefined;
558
567
  if (workerPool) {
559
568
  if (scopeTreeCache !== undefined && process.env.PROF_SCOPE_RESOLUTION === '1') {
560
569
  // Trees can't cross MessageChannels, so worker-parsed files land
@@ -564,13 +573,15 @@ scopeTreeCache, onFileProgress, workerPool) => {
564
573
  console.warn(`[scope-resolution prof] worker pool engaged for ${files.length} files — cross-phase tree cache will be empty; scope-resolution re-parses.`);
565
574
  }
566
575
  try {
567
- return await processParsingWithWorkers(graph, files, symbolTable, astCache, workerPool, onFileProgress);
576
+ return await processParsingWithWorkers(graph, files, symbolTable, astCache, workerPool, reportProgress);
568
577
  }
569
578
  catch (err) {
570
- console.warn('Worker pool parsing failed, falling back to sequential:', err instanceof Error ? err.message : err);
579
+ const message = err instanceof Error ? err.message : String(err);
580
+ console.warn('Worker pool parsing stopped; continuing with sequential parser:', message);
581
+ reportProgress?.(lastProgress, files.length, `Sequential fallback after worker issue: ${message}`);
571
582
  }
572
583
  }
573
584
  // Fallback: sequential parsing (no pre-extracted data)
574
- await processParsingSequential(graph, files, symbolTable, astCache, scopeTreeCache, onFileProgress);
585
+ await processParsingSequential(graph, files, symbolTable, astCache, scopeTreeCache, reportProgress);
575
586
  return null;
576
587
  };
@@ -84,12 +84,15 @@ export const processesPhase = {
84
84
  }
85
85
  list.push(url);
86
86
  }
87
- const toolsByFile = new Map();
87
+ const toolsByHandlerId = new Map();
88
+ const toolsWithoutHandlerByFile = new Map();
88
89
  for (const td of toolDefs) {
89
- let list = toolsByFile.get(td.filePath);
90
+ const key = td.handlerNodeId ?? td.filePath;
91
+ const targetMap = td.handlerNodeId ? toolsByHandlerId : toolsWithoutHandlerByFile;
92
+ let list = targetMap.get(key);
90
93
  if (!list) {
91
94
  list = [];
92
- toolsByFile.set(td.filePath, list);
95
+ targetMap.set(key, list);
93
96
  }
94
97
  list.push(td.name);
95
98
  }
@@ -118,7 +121,9 @@ export const processesPhase = {
118
121
  linked++;
119
122
  }
120
123
  }
121
- const toolNames = toolsByFile.get(entryFile);
124
+ const exactToolNames = toolsByHandlerId.get(proc.entryPointId);
125
+ const fallbackToolNames = toolsWithoutHandlerByFile.get(entryFile);
126
+ const toolNames = exactToolNames ?? fallbackToolNames;
122
127
  if (toolNames) {
123
128
  for (const toolName of toolNames) {
124
129
  const toolNodeId = generateId('Tool', toolName);
@@ -13,6 +13,7 @@ export interface ToolDef {
13
13
  name: string;
14
14
  filePath: string;
15
15
  description: string;
16
+ handlerNodeId?: string;
16
17
  }
17
18
  export interface ToolsOutput {
18
19
  toolDefs: ToolDef[];
@@ -23,7 +23,13 @@ export const toolsPhase = {
23
23
  if (seenToolNames.has(td.toolName))
24
24
  continue;
25
25
  seenToolNames.add(td.toolName);
26
- toolDefs.push({ name: td.toolName, filePath: td.filePath, description: td.description });
26
+ const handlerNodeId = td.handlerNodeId && ctx.graph.getNode(td.handlerNodeId) ? td.handlerNodeId : undefined;
27
+ toolDefs.push({
28
+ name: td.toolName,
29
+ filePath: td.filePath,
30
+ description: td.description,
31
+ ...(handlerNodeId !== undefined ? { handlerNodeId } : {}),
32
+ });
27
33
  }
28
34
  // TS tool definition arrays — require inputSchema nearby
29
35
  const toolCandidatePaths = allPaths.filter((p) => (p.endsWith('.ts') || p.endsWith('.js')) &&
@@ -60,10 +66,10 @@ export const toolsPhase = {
60
66
  label: 'Tool',
61
67
  properties: { name: td.name, filePath: td.filePath, description: td.description },
62
68
  });
63
- const handlerFileId = generateId('File', td.filePath);
69
+ const handlerId = td.handlerNodeId ?? generateId('File', td.filePath);
64
70
  ctx.graph.addRelationship({
65
- id: generateId('HANDLES_TOOL', `${handlerFileId}->${toolNodeId}`),
66
- sourceId: handlerFileId,
71
+ id: generateId('HANDLES_TOOL', `${handlerId}->${toolNodeId}`),
72
+ sourceId: handlerId,
67
73
  targetId: toolNodeId,
68
74
  type: 'HANDLES_TOOL',
69
75
  confidence: 1.0,
@@ -56,7 +56,9 @@ import { SupportedLanguages } from '../../_shared/index.js';
56
56
  * so this set also controls what gets silenced in the legacy DAG.
57
57
  *
58
58
  * Add a language here ONLY after shadow parity ≥ 99% fixtures / ≥ 98%
59
- * corpus per RFC §6.4. The parity CI gate will block the PR otherwise.
59
+ * corpus per RFC §6.4. TypeScript is temporarily accepted under the
60
+ * Ring 3 CI parity gate while corpus-level shadow-mode wiring is tracked
61
+ * in #927 for this migration.
60
62
  *
61
63
  * The set is intentionally a static TypeScript literal (not a JSON import,
62
64
  * not an env lookup) so CI can discover it via `tsx` without a build step
@@ -56,7 +56,9 @@ import { SupportedLanguages } from '../../_shared/index.js';
56
56
  * so this set also controls what gets silenced in the legacy DAG.
57
57
  *
58
58
  * Add a language here ONLY after shadow parity ≥ 99% fixtures / ≥ 98%
59
- * corpus per RFC §6.4. The parity CI gate will block the PR otherwise.
59
+ * corpus per RFC §6.4. TypeScript is temporarily accepted under the
60
+ * Ring 3 CI parity gate while corpus-level shadow-mode wiring is tracked
61
+ * in #927 for this migration.
60
62
  *
61
63
  * The set is intentionally a static TypeScript literal (not a JSON import,
62
64
  * not an env lookup) so CI can discover it via `tsx` without a build step
@@ -65,6 +67,7 @@ import { SupportedLanguages } from '../../_shared/index.js';
65
67
  export const MIGRATED_LANGUAGES = new Set([
66
68
  SupportedLanguages.Python,
67
69
  SupportedLanguages.CSharp,
70
+ SupportedLanguages.TypeScript,
68
71
  ]);
69
72
  /**
70
73
  * Return the env-var name that controls a given language's registry-
@@ -13,8 +13,11 @@
13
13
  * `emitScopeCaptures`. Returns `undefined`; zero work done. This is
14
14
  * the state of every language today — `ParsedFile` production stays
15
15
  * dormant until a language migrates.
16
- * 2. Invokes the hook + feeds its output to `ScopeExtractor.extract`.
17
- * 3. **Swallows exceptions from either side.** A failure here returns
16
+ * 2. Short-circuits empty / whitespace-only files. There is no scope
17
+ * content to extract, and some tree-sitter queries do not match an
18
+ * otherwise valid empty root node.
19
+ * 3. Invokes the hook + feeds its output to `ScopeExtractor.extract`.
20
+ * 4. **Swallows exceptions from either side.** A failure here returns
18
21
  * `undefined` and emits a warning via `onWarn`; legacy parsing on
19
22
  * the same file continues unaffected by the scope-extraction miss.
20
23
  * Scope-based resolution is the new path under construction — it
@@ -13,8 +13,11 @@
13
13
  * `emitScopeCaptures`. Returns `undefined`; zero work done. This is
14
14
  * the state of every language today — `ParsedFile` production stays
15
15
  * dormant until a language migrates.
16
- * 2. Invokes the hook + feeds its output to `ScopeExtractor.extract`.
17
- * 3. **Swallows exceptions from either side.** A failure here returns
16
+ * 2. Short-circuits empty / whitespace-only files. There is no scope
17
+ * content to extract, and some tree-sitter queries do not match an
18
+ * otherwise valid empty root node.
19
+ * 3. Invokes the hook + feeds its output to `ScopeExtractor.extract`.
20
+ * 4. **Swallows exceptions from either side.** A failure here returns
18
21
  * `undefined` and emits a warning via `onWarn`; legacy parsing on
19
22
  * the same file continues unaffected by the scope-extraction miss.
20
23
  * Scope-based resolution is the new path under construction — it
@@ -29,6 +32,8 @@ import { extract as extractScope } from './scope-extractor.js';
29
32
  export function extractParsedFile(provider, sourceText, filePath, onWarn, cachedTree) {
30
33
  if (provider.emitScopeCaptures === undefined)
31
34
  return undefined;
35
+ if (sourceText.trim().length === 0)
36
+ return undefined;
32
37
  try {
33
38
  const captures = provider.emitScopeCaptures(sourceText, filePath, cachedTree);
34
39
  return extractScope(captures, filePath, provider);
@@ -58,7 +58,7 @@
58
58
  * - `ParsedFile.localDefs` — flattened union of `Scope.ownedDefs`.
59
59
  * - `ParsedFile.referenceSites` — pre-resolution usage facts.
60
60
  */
61
- import { buildPositionIndex, buildScopeTree, makeScopeId } from '../../_shared/index.js';
61
+ import { buildPositionIndex, buildScopeTree, canParentScope, makeScopeId } from '../../_shared/index.js';
62
62
  // ─── Public entry point ─────────────────────────────────────────────────────
63
63
  /**
64
64
  * Drive the five extraction passes and return a `ParsedFile`.
@@ -210,7 +210,11 @@ function pass1BuildScopes(matches, filePath, provider) {
210
210
  candidates.push({ match, range: anchor.range, kind, id });
211
211
  }
212
212
  // Sort by (startLine, startCol) ASC, (endLine, endCol) DESC so outer
213
- // scopes appear before their children for parent-resolution.
213
+ // scopes appear before their children for parent-resolution. When two
214
+ // candidates have exactly equal ranges (e.g. a `compilation_unit` and
215
+ // the only top-level scope in the file — see `canParentScope`), Module
216
+ // sorts first so it lands on the stack ahead of the candidate that will
217
+ // claim it as parent.
214
218
  candidates.sort((a, b) => {
215
219
  if (a.range.startLine !== b.range.startLine)
216
220
  return a.range.startLine - b.range.startLine;
@@ -218,13 +222,23 @@ function pass1BuildScopes(matches, filePath, provider) {
218
222
  return a.range.startCol - b.range.startCol;
219
223
  if (a.range.endLine !== b.range.endLine)
220
224
  return b.range.endLine - a.range.endLine;
221
- return b.range.endCol - a.range.endCol;
225
+ if (a.range.endCol !== b.range.endCol)
226
+ return b.range.endCol - a.range.endCol;
227
+ if (a.kind === b.kind)
228
+ return 0;
229
+ if (a.kind === 'Module')
230
+ return -1;
231
+ if (b.kind === 'Module')
232
+ return 1;
233
+ return 0;
222
234
  });
223
235
  const drafts = [];
224
236
  const stack = []; // enclosing real scopes, outermost at [0]
225
237
  for (const cand of candidates) {
226
- // Pop the stack until the top strictly contains this candidate.
227
- while (stack.length > 0 && !rangeStrictlyContains(stack[stack.length - 1].range, cand.range)) {
238
+ // Pop the stack until the top can parent this candidate (strict
239
+ // containment, plus the equal-range Module carve-out).
240
+ while (stack.length > 0 &&
241
+ !canParentScope(stack[stack.length - 1].range, cand.range, stack[stack.length - 1].kind, cand.kind)) {
228
242
  stack.pop();
229
243
  }
230
244
  const parent = stack.length > 0 ? stack[stack.length - 1].id : null;
@@ -692,19 +706,6 @@ function rangesEqual(a, b) {
692
706
  a.endLine === b.endLine &&
693
707
  a.endCol === b.endCol);
694
708
  }
695
- function rangeStrictlyContains(outer, inner) {
696
- if (outer.startLine === inner.startLine &&
697
- outer.startCol === inner.startCol &&
698
- outer.endLine === inner.endLine &&
699
- outer.endCol === inner.endCol) {
700
- return false;
701
- }
702
- const startsBefore = outer.startLine < inner.startLine ||
703
- (outer.startLine === inner.startLine && outer.startCol <= inner.startCol);
704
- const endsAfter = outer.endLine > inner.endLine ||
705
- (outer.endLine === inner.endLine && outer.endCol >= inner.endCol);
706
- return startsBefore && endsAfter;
707
- }
708
709
  /**
709
710
  * Capture names that are never anchors — they are sub-tags nested inside a
710
711
  * larger anchor (e.g., the receiver expression inside a `@reference.call`
@@ -88,14 +88,21 @@
88
88
  * per-(caller, target) collapse semantics require multiple call
89
89
  * sites in the same caller body not produce multiple edges.
90
90
  *
91
- * - **I3 — `propagateImportedReturnTypes` mutation timing.** The
92
- * pass mutates `Scope.typeBindings` (a plain `new Map(...)` from
91
+ * - **I3 — `propagateImportedReturnTypes` mutation timing + ordering.**
92
+ * The pass mutates `Scope.typeBindings` (a plain `new Map(...)` from
93
93
  * `draftToScope`, NOT frozen). It MUST run AFTER `finalizeScopeModel`
94
94
  * (so `indexes.bindings` is populated) and BEFORE
95
95
  * `resolveReferenceSites` (so resolution sees the propagated types).
96
96
  * The pass also re-runs `followChainPostFinalize` on every scope's
97
97
  * typeBindings because scope-extractor's pass-4 already ran and
98
98
  * missed any chain whose terminal lives in a foreign file.
99
+ * Within the pass, files are walked in `indexes.sccs` reverse-
100
+ * topological order (leaves first) so multi-hop alias chains
101
+ * (e.g. `models.User → service.user → app.user`) collapse to the
102
+ * terminal class in a single pass — every importer sees its
103
+ * source's already-chain-followed typeBindings. Cyclic SCCs reach
104
+ * a partial fixpoint within a single pass without iterating to
105
+ * convergence; `ts-circular` only asserts pipeline-no-throw.
99
106
  *
100
107
  * - **I4 — `emitReceiverBoundCalls` case order.** Cases are evaluated
101
108
  * in this order; the FIRST that emits an edge wins:
@@ -129,14 +136,45 @@
129
136
  * once per workspace at resolve time), and merging would create a
130
137
  * god-interface that complicates future migrations.
131
138
  *
132
- * - **I8 — Post-finalize hooks may mutate `Scope.typeBindings` and
133
- * `indexes.bindings`.** `propagateImportedReturnTypes` and
134
- * `populateNamespaceSiblings` both write to these structures via
135
- * `as Map<...>` casts through `ReadonlyMap` facades. Downstream
136
- * consumers MUST NOT freeze or snapshot these maps before all
137
- * post-finalize hooks have run. The `ReadonlyMap<...>` type on
138
- * `ScopeResolutionIndexes` is a read-guidance surface for
139
- * consumers, NOT an immutability promise during the resolve phase.
139
+ * - **I8 — Two-channel binding lifecycle.**
140
+ * `indexes.bindings` is the **finalize-output channel**. After
141
+ * `finalizeScopeModel` returns, its inner `BindingRef[]` arrays
142
+ * are deep-frozen by `materializeBindings` and MUST NOT be
143
+ * mutated by any post-finalize hook. Treat `indexes.bindings` as
144
+ * immutable from the moment `finalizeScopeModel` returns.
145
+ *
146
+ * `indexes.bindingAugmentations` is the **post-finalize
147
+ * append-only channel**. Hooks like `populateNamespaceSiblings`
148
+ * append cross-file bindings synthesized after finalize (C#
149
+ * same-namespace visibility, `using static` member exposure)
150
+ * into this channel, NOT into `indexes.bindings`. Inner arrays
151
+ * here are NEVER frozen — hooks `push()` directly. Any consumer
152
+ * that reads post-finalize workspace bindings MUST query both
153
+ * index channels via `lookupBindingsAt`
154
+ * (`scope-resolution/scope/walkers.ts`); the helper returns
155
+ * finalized refs first, appends unique augmentation refs after,
156
+ * and dedupes by `def.nodeId` so finalized metadata wins on
157
+ * duplicate defs. Per-`Scope.bindings` local declarations are the
158
+ * lexical extraction channel and remain a separate first-tier
159
+ * lookup for local shadowing.
160
+ *
161
+ * `Scope.typeBindings` remains mutable post-finalize per I6 (it
162
+ * is intentionally not frozen at any point).
163
+ *
164
+ * The `ReadonlyMap<...>` types on `ScopeResolutionIndexes` are
165
+ * compile-time read-guidance for consumers; structural mutation
166
+ * of `bindingAugmentations` is performed via a deliberate
167
+ * `as Map<...>` cast inside the hook implementations and is the
168
+ * ONLY sanctioned channel for post-finalize binding fanout.
169
+ *
170
+ * The dev-mode runtime validator
171
+ * (`validateBindingsImmutability` in
172
+ * `scope-resolution/validate-bindings-immutability.ts`) surfaces
173
+ * any drift — i.e. a hook writing to `indexes.bindings` instead
174
+ * of `bindingAugmentations`, or producing a non-frozen finalized
175
+ * bucket — via `onWarn` when explicitly enabled by
176
+ * `NODE_ENV === 'development' || VALIDATE_SEMANTIC_MODEL === '1'`
177
+ * (`VALIDATE_SEMANTIC_MODEL=0` is an explicit off switch).
140
178
  *
141
179
  * - **I9 — `SemanticModel` is the single authoritative symbol store.**
142
180
  * Every symbol-indexed lookup (key = `nodeId | simpleName |
@@ -244,8 +282,32 @@ export interface ScopeResolver {
244
282
  * resolvers that must distinguish "this module exists in the repo"
245
283
  * from "this module is external" (Python's fallback resolver, for
246
284
  * example).
285
+ *
286
+ * `resolutionConfig` is the opaque value returned by
287
+ * `loadResolutionConfig` (loaded once per workspace pass by the
288
+ * orchestrator). TypeScript uses this to thread `tsconfig.json` path
289
+ * aliases through to the standard resolver. Languages that don't
290
+ * need any extra config ignore the parameter.
291
+ */
292
+ resolveImportTarget(targetRaw: string, fromFile: string, allFilePaths: ReadonlySet<string>, resolutionConfig?: unknown): string | null;
293
+ /**
294
+ * Optional one-shot loader for cross-file import-resolution config
295
+ * (e.g. tsconfig path aliases for TypeScript, go.mod paths for Go,
296
+ * composer.json autoload for PHP). The orchestrator calls this once
297
+ * per workspace pass with the repo root and threads the result into
298
+ * every subsequent `resolveImportTarget` call as the
299
+ * `resolutionConfig` parameter.
300
+ *
301
+ * Languages that don't need any per-workspace config leave this
302
+ * undefined; the orchestrator threads `undefined` to
303
+ * `resolveImportTarget` in that case. Returning `null` is also
304
+ * supported and equivalent to "no config available".
305
+ *
306
+ * May be sync or async — the orchestrator awaits the result. The
307
+ * shape is opaque to the orchestrator (`unknown`); the per-language
308
+ * `resolveImportTarget` casts it to the language's expected shape.
247
309
  */
248
- resolveImportTarget(targetRaw: string, fromFile: string, allFilePaths: ReadonlySet<string>): string | null;
310
+ loadResolutionConfig?(repoPath: string): Promise<unknown> | unknown;
249
311
  /**
250
312
  * Per-scope binding-merge precedence. The shared finalize pass
251
313
  * collects bindings from multiple sources (local declarations,
@@ -88,14 +88,21 @@
88
88
  * per-(caller, target) collapse semantics require multiple call
89
89
  * sites in the same caller body not produce multiple edges.
90
90
  *
91
- * - **I3 — `propagateImportedReturnTypes` mutation timing.** The
92
- * pass mutates `Scope.typeBindings` (a plain `new Map(...)` from
91
+ * - **I3 — `propagateImportedReturnTypes` mutation timing + ordering.**
92
+ * The pass mutates `Scope.typeBindings` (a plain `new Map(...)` from
93
93
  * `draftToScope`, NOT frozen). It MUST run AFTER `finalizeScopeModel`
94
94
  * (so `indexes.bindings` is populated) and BEFORE
95
95
  * `resolveReferenceSites` (so resolution sees the propagated types).
96
96
  * The pass also re-runs `followChainPostFinalize` on every scope's
97
97
  * typeBindings because scope-extractor's pass-4 already ran and
98
98
  * missed any chain whose terminal lives in a foreign file.
99
+ * Within the pass, files are walked in `indexes.sccs` reverse-
100
+ * topological order (leaves first) so multi-hop alias chains
101
+ * (e.g. `models.User → service.user → app.user`) collapse to the
102
+ * terminal class in a single pass — every importer sees its
103
+ * source's already-chain-followed typeBindings. Cyclic SCCs reach
104
+ * a partial fixpoint within a single pass without iterating to
105
+ * convergence; `ts-circular` only asserts pipeline-no-throw.
99
106
  *
100
107
  * - **I4 — `emitReceiverBoundCalls` case order.** Cases are evaluated
101
108
  * in this order; the FIRST that emits an edge wins:
@@ -129,14 +136,45 @@
129
136
  * once per workspace at resolve time), and merging would create a
130
137
  * god-interface that complicates future migrations.
131
138
  *
132
- * - **I8 — Post-finalize hooks may mutate `Scope.typeBindings` and
133
- * `indexes.bindings`.** `propagateImportedReturnTypes` and
134
- * `populateNamespaceSiblings` both write to these structures via
135
- * `as Map<...>` casts through `ReadonlyMap` facades. Downstream
136
- * consumers MUST NOT freeze or snapshot these maps before all
137
- * post-finalize hooks have run. The `ReadonlyMap<...>` type on
138
- * `ScopeResolutionIndexes` is a read-guidance surface for
139
- * consumers, NOT an immutability promise during the resolve phase.
139
+ * - **I8 — Two-channel binding lifecycle.**
140
+ * `indexes.bindings` is the **finalize-output channel**. After
141
+ * `finalizeScopeModel` returns, its inner `BindingRef[]` arrays
142
+ * are deep-frozen by `materializeBindings` and MUST NOT be
143
+ * mutated by any post-finalize hook. Treat `indexes.bindings` as
144
+ * immutable from the moment `finalizeScopeModel` returns.
145
+ *
146
+ * `indexes.bindingAugmentations` is the **post-finalize
147
+ * append-only channel**. Hooks like `populateNamespaceSiblings`
148
+ * append cross-file bindings synthesized after finalize (C#
149
+ * same-namespace visibility, `using static` member exposure)
150
+ * into this channel, NOT into `indexes.bindings`. Inner arrays
151
+ * here are NEVER frozen — hooks `push()` directly. Any consumer
152
+ * that reads post-finalize workspace bindings MUST query both
153
+ * index channels via `lookupBindingsAt`
154
+ * (`scope-resolution/scope/walkers.ts`); the helper returns
155
+ * finalized refs first, appends unique augmentation refs after,
156
+ * and dedupes by `def.nodeId` so finalized metadata wins on
157
+ * duplicate defs. Per-`Scope.bindings` local declarations are the
158
+ * lexical extraction channel and remain a separate first-tier
159
+ * lookup for local shadowing.
160
+ *
161
+ * `Scope.typeBindings` remains mutable post-finalize per I6 (it
162
+ * is intentionally not frozen at any point).
163
+ *
164
+ * The `ReadonlyMap<...>` types on `ScopeResolutionIndexes` are
165
+ * compile-time read-guidance for consumers; structural mutation
166
+ * of `bindingAugmentations` is performed via a deliberate
167
+ * `as Map<...>` cast inside the hook implementations and is the
168
+ * ONLY sanctioned channel for post-finalize binding fanout.
169
+ *
170
+ * The dev-mode runtime validator
171
+ * (`validateBindingsImmutability` in
172
+ * `scope-resolution/validate-bindings-immutability.ts`) surfaces
173
+ * any drift — i.e. a hook writing to `indexes.bindings` instead
174
+ * of `bindingAugmentations`, or producing a non-frozen finalized
175
+ * bucket — via `onWarn` when explicitly enabled by
176
+ * `NODE_ENV === 'development' || VALIDATE_SEMANTIC_MODEL === '1'`
177
+ * (`VALIDATE_SEMANTIC_MODEL=0` is an explicit off switch).
140
178
  *
141
179
  * - **I9 — `SemanticModel` is the single authoritative symbol store.**
142
180
  * Every symbol-indexed lookup (key = `nodeId | simpleName |