gitnexus 1.6.2-rc.8 → 1.6.2

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 (222) hide show
  1. package/dist/_shared/lbug/schema-constants.d.ts +1 -1
  2. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  3. package/dist/_shared/lbug/schema-constants.js +1 -0
  4. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  5. package/dist/_shared/mro-strategy.d.ts +38 -16
  6. package/dist/_shared/mro-strategy.d.ts.map +1 -1
  7. package/dist/cli/ai-context.js +0 -58
  8. package/dist/cli/analyze.js +3 -0
  9. package/dist/core/embeddings/ast-utils.d.ts +22 -0
  10. package/dist/core/embeddings/ast-utils.js +105 -0
  11. package/dist/core/embeddings/character-chunk.d.ts +12 -0
  12. package/dist/core/embeddings/character-chunk.js +43 -0
  13. package/dist/core/embeddings/chunker.d.ts +14 -0
  14. package/dist/core/embeddings/chunker.js +234 -0
  15. package/dist/core/embeddings/embedder.js +5 -0
  16. package/dist/core/embeddings/embedding-pipeline.d.ts +20 -24
  17. package/dist/core/embeddings/embedding-pipeline.js +176 -107
  18. package/dist/core/embeddings/line-index.d.ts +7 -0
  19. package/dist/core/embeddings/line-index.js +42 -0
  20. package/dist/core/embeddings/server-mapping.d.ts +15 -0
  21. package/dist/core/embeddings/server-mapping.js +33 -0
  22. package/dist/core/embeddings/structural-extractor.d.ts +15 -0
  23. package/dist/core/embeddings/structural-extractor.js +58 -0
  24. package/dist/core/embeddings/text-generator.d.ts +20 -13
  25. package/dist/core/embeddings/text-generator.js +151 -119
  26. package/dist/core/embeddings/types.d.ts +81 -3
  27. package/dist/core/embeddings/types.js +105 -3
  28. package/dist/core/group/extractors/http-patterns/node.js +130 -0
  29. package/dist/core/ingestion/call-extractors/configs/c-cpp.d.ts +3 -0
  30. package/dist/core/ingestion/call-extractors/configs/c-cpp.js +8 -0
  31. package/dist/core/ingestion/call-extractors/configs/csharp.d.ts +2 -0
  32. package/dist/core/ingestion/call-extractors/configs/csharp.js +6 -0
  33. package/dist/core/ingestion/call-extractors/configs/dart.d.ts +2 -0
  34. package/dist/core/ingestion/call-extractors/configs/dart.js +5 -0
  35. package/dist/core/ingestion/call-extractors/configs/go.d.ts +2 -0
  36. package/dist/core/ingestion/call-extractors/configs/go.js +5 -0
  37. package/dist/core/ingestion/call-extractors/configs/jvm.d.ts +3 -0
  38. package/dist/core/ingestion/call-extractors/configs/jvm.js +51 -0
  39. package/dist/core/ingestion/call-extractors/configs/php.d.ts +2 -0
  40. package/dist/core/ingestion/call-extractors/configs/php.js +5 -0
  41. package/dist/core/ingestion/call-extractors/configs/python.d.ts +2 -0
  42. package/dist/core/ingestion/call-extractors/configs/python.js +5 -0
  43. package/dist/core/ingestion/call-extractors/configs/ruby.d.ts +2 -0
  44. package/dist/core/ingestion/call-extractors/configs/ruby.js +5 -0
  45. package/dist/core/ingestion/call-extractors/configs/rust.d.ts +2 -0
  46. package/dist/core/ingestion/call-extractors/configs/rust.js +5 -0
  47. package/dist/core/ingestion/call-extractors/configs/swift.d.ts +2 -0
  48. package/dist/core/ingestion/call-extractors/configs/swift.js +5 -0
  49. package/dist/core/ingestion/call-extractors/configs/typescript-javascript.d.ts +3 -0
  50. package/dist/core/ingestion/call-extractors/configs/typescript-javascript.js +8 -0
  51. package/dist/core/ingestion/call-extractors/generic.d.ts +5 -0
  52. package/dist/core/ingestion/call-extractors/generic.js +59 -0
  53. package/dist/core/ingestion/call-processor.d.ts +2 -4
  54. package/dist/core/ingestion/call-processor.js +221 -89
  55. package/dist/core/ingestion/call-routing.d.ts +8 -12
  56. package/dist/core/ingestion/call-routing.js +13 -34
  57. package/dist/core/ingestion/call-types.d.ts +135 -0
  58. package/dist/core/ingestion/call-types.js +2 -0
  59. package/dist/core/ingestion/class-extractors/configs/c-cpp.d.ts +3 -0
  60. package/dist/core/ingestion/class-extractors/configs/c-cpp.js +11 -0
  61. package/dist/core/ingestion/class-extractors/configs/csharp.d.ts +2 -0
  62. package/dist/core/ingestion/class-extractors/configs/csharp.js +21 -0
  63. package/dist/core/ingestion/class-extractors/configs/dart.d.ts +2 -0
  64. package/dist/core/ingestion/class-extractors/configs/dart.js +7 -0
  65. package/dist/core/ingestion/class-extractors/configs/go.d.ts +2 -0
  66. package/dist/core/ingestion/class-extractors/configs/go.js +20 -0
  67. package/dist/core/ingestion/class-extractors/configs/jvm.d.ts +3 -0
  68. package/dist/core/ingestion/class-extractors/configs/jvm.js +35 -0
  69. package/dist/core/ingestion/class-extractors/configs/php.d.ts +2 -0
  70. package/dist/core/ingestion/class-extractors/configs/php.js +7 -0
  71. package/dist/core/ingestion/class-extractors/configs/python.d.ts +2 -0
  72. package/dist/core/ingestion/class-extractors/configs/python.js +7 -0
  73. package/dist/core/ingestion/class-extractors/configs/ruby.d.ts +2 -0
  74. package/dist/core/ingestion/class-extractors/configs/ruby.js +7 -0
  75. package/dist/core/ingestion/class-extractors/configs/rust.d.ts +2 -0
  76. package/dist/core/ingestion/class-extractors/configs/rust.js +7 -0
  77. package/dist/core/ingestion/class-extractors/configs/swift.d.ts +2 -0
  78. package/dist/core/ingestion/class-extractors/configs/swift.js +18 -0
  79. package/dist/core/ingestion/class-extractors/configs/typescript-javascript.d.ts +4 -0
  80. package/dist/core/ingestion/class-extractors/configs/typescript-javascript.js +28 -0
  81. package/dist/core/ingestion/field-types.d.ts +1 -1
  82. package/dist/core/ingestion/heritage-extractors/configs/go.d.ts +13 -0
  83. package/dist/core/ingestion/heritage-extractors/configs/go.js +20 -0
  84. package/dist/core/ingestion/heritage-extractors/configs/ruby.d.ts +18 -0
  85. package/dist/core/ingestion/heritage-extractors/configs/ruby.js +65 -0
  86. package/dist/core/ingestion/heritage-extractors/generic.d.ts +23 -0
  87. package/dist/core/ingestion/heritage-extractors/generic.js +47 -0
  88. package/dist/core/ingestion/heritage-processor.d.ts +9 -0
  89. package/dist/core/ingestion/heritage-processor.js +120 -85
  90. package/dist/core/ingestion/heritage-types.d.ts +73 -0
  91. package/dist/core/ingestion/heritage-types.js +2 -0
  92. package/dist/core/ingestion/import-resolvers/configs/c-cpp.d.ts +7 -0
  93. package/dist/core/ingestion/import-resolvers/configs/c-cpp.js +14 -0
  94. package/dist/core/ingestion/import-resolvers/configs/csharp.d.ts +8 -0
  95. package/dist/core/ingestion/import-resolvers/configs/csharp.js +27 -0
  96. package/dist/core/ingestion/import-resolvers/configs/dart.d.ts +17 -0
  97. package/dist/core/ingestion/import-resolvers/{dart.js → configs/dart.js} +26 -16
  98. package/dist/core/ingestion/import-resolvers/configs/go.d.ts +8 -0
  99. package/dist/core/ingestion/import-resolvers/configs/go.js +26 -0
  100. package/dist/core/ingestion/import-resolvers/configs/jvm.d.ts +13 -0
  101. package/dist/core/ingestion/import-resolvers/configs/jvm.js +68 -0
  102. package/dist/core/ingestion/import-resolvers/configs/php.d.ts +8 -0
  103. package/dist/core/ingestion/import-resolvers/configs/php.js +15 -0
  104. package/dist/core/ingestion/import-resolvers/configs/python.d.ts +12 -0
  105. package/dist/core/ingestion/import-resolvers/configs/python.js +41 -0
  106. package/dist/core/ingestion/import-resolvers/configs/ruby.d.ts +8 -0
  107. package/dist/core/ingestion/import-resolvers/configs/ruby.js +16 -0
  108. package/dist/core/ingestion/import-resolvers/configs/rust.d.ts +8 -0
  109. package/dist/core/ingestion/import-resolvers/configs/rust.js +54 -0
  110. package/dist/core/ingestion/import-resolvers/configs/swift.d.ts +8 -0
  111. package/dist/core/ingestion/import-resolvers/{swift.js → configs/swift.js} +10 -5
  112. package/dist/core/ingestion/import-resolvers/configs/typescript-javascript.d.ts +9 -0
  113. package/dist/core/ingestion/import-resolvers/configs/typescript-javascript.js +23 -0
  114. package/dist/core/ingestion/import-resolvers/csharp.d.ts +4 -5
  115. package/dist/core/ingestion/import-resolvers/csharp.js +4 -20
  116. package/dist/core/ingestion/import-resolvers/go.d.ts +4 -5
  117. package/dist/core/ingestion/import-resolvers/go.js +4 -19
  118. package/dist/core/ingestion/import-resolvers/jvm.d.ts +5 -10
  119. package/dist/core/ingestion/import-resolvers/jvm.js +5 -58
  120. package/dist/core/ingestion/import-resolvers/php.d.ts +4 -5
  121. package/dist/core/ingestion/import-resolvers/php.js +4 -7
  122. package/dist/core/ingestion/import-resolvers/python.d.ts +3 -6
  123. package/dist/core/ingestion/import-resolvers/python.js +3 -18
  124. package/dist/core/ingestion/import-resolvers/resolver-factory.d.ts +24 -0
  125. package/dist/core/ingestion/import-resolvers/resolver-factory.js +33 -0
  126. package/dist/core/ingestion/import-resolvers/ruby.d.ts +4 -5
  127. package/dist/core/ingestion/import-resolvers/ruby.js +4 -7
  128. package/dist/core/ingestion/import-resolvers/rust.d.ts +4 -5
  129. package/dist/core/ingestion/import-resolvers/rust.js +4 -47
  130. package/dist/core/ingestion/import-resolvers/standard.d.ts +3 -9
  131. package/dist/core/ingestion/import-resolvers/standard.js +7 -8
  132. package/dist/core/ingestion/import-resolvers/types.d.ts +24 -0
  133. package/dist/core/ingestion/language-provider.d.ts +80 -0
  134. package/dist/core/ingestion/languages/c-cpp.js +18 -12
  135. package/dist/core/ingestion/languages/csharp.js +13 -21
  136. package/dist/core/ingestion/languages/dart.js +13 -7
  137. package/dist/core/ingestion/languages/go.js +14 -20
  138. package/dist/core/ingestion/languages/java.js +13 -18
  139. package/dist/core/ingestion/languages/kotlin.js +13 -13
  140. package/dist/core/ingestion/languages/php.js +13 -7
  141. package/dist/core/ingestion/languages/python.js +13 -7
  142. package/dist/core/ingestion/languages/ruby.js +103 -22
  143. package/dist/core/ingestion/languages/rust.js +13 -7
  144. package/dist/core/ingestion/languages/swift.js +13 -18
  145. package/dist/core/ingestion/languages/typescript.js +18 -23
  146. package/dist/core/ingestion/languages/vue.js +13 -17
  147. package/dist/core/ingestion/model/heritage-map.d.ts +35 -0
  148. package/dist/core/ingestion/model/heritage-map.js +110 -9
  149. package/dist/core/ingestion/model/index.d.ts +2 -2
  150. package/dist/core/ingestion/model/index.js +1 -1
  151. package/dist/core/ingestion/model/resolve.d.ts +33 -28
  152. package/dist/core/ingestion/model/resolve.js +111 -27
  153. package/dist/core/ingestion/parsing-processor.d.ts +1 -2
  154. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +1 -0
  155. package/dist/core/ingestion/pipeline-phases/parse-impl.js +9 -3
  156. package/dist/core/ingestion/pipeline-phases/parse.d.ts +7 -0
  157. package/dist/core/ingestion/pipeline.d.ts +11 -0
  158. package/dist/core/ingestion/pipeline.js +9 -2
  159. package/dist/core/ingestion/tree-sitter-queries.d.ts +11 -11
  160. package/dist/core/ingestion/tree-sitter-queries.js +81 -0
  161. package/dist/core/ingestion/type-env.d.ts +1 -1
  162. package/dist/core/ingestion/utils/ast-helpers.d.ts +1 -1
  163. package/dist/core/ingestion/utils/ast-helpers.js +22 -2
  164. package/dist/core/ingestion/utils/ruby-self-call.d.ts +52 -0
  165. package/dist/core/ingestion/utils/ruby-self-call.js +59 -0
  166. package/dist/core/ingestion/variable-extractors/configs/c-cpp.d.ts +3 -0
  167. package/dist/core/ingestion/variable-extractors/configs/c-cpp.js +81 -0
  168. package/dist/core/ingestion/variable-extractors/configs/csharp.d.ts +9 -0
  169. package/dist/core/ingestion/variable-extractors/configs/csharp.js +63 -0
  170. package/dist/core/ingestion/variable-extractors/configs/dart.d.ts +2 -0
  171. package/dist/core/ingestion/variable-extractors/configs/dart.js +94 -0
  172. package/dist/core/ingestion/variable-extractors/configs/go.d.ts +2 -0
  173. package/dist/core/ingestion/variable-extractors/configs/go.js +83 -0
  174. package/dist/core/ingestion/variable-extractors/configs/jvm.d.ts +18 -0
  175. package/dist/core/ingestion/variable-extractors/configs/jvm.js +115 -0
  176. package/dist/core/ingestion/variable-extractors/configs/php.d.ts +14 -0
  177. package/dist/core/ingestion/variable-extractors/configs/php.js +58 -0
  178. package/dist/core/ingestion/variable-extractors/configs/python.d.ts +2 -0
  179. package/dist/core/ingestion/variable-extractors/configs/python.js +101 -0
  180. package/dist/core/ingestion/variable-extractors/configs/ruby.d.ts +11 -0
  181. package/dist/core/ingestion/variable-extractors/configs/ruby.js +52 -0
  182. package/dist/core/ingestion/variable-extractors/configs/rust.d.ts +2 -0
  183. package/dist/core/ingestion/variable-extractors/configs/rust.js +76 -0
  184. package/dist/core/ingestion/variable-extractors/configs/swift.d.ts +2 -0
  185. package/dist/core/ingestion/variable-extractors/configs/swift.js +88 -0
  186. package/dist/core/ingestion/variable-extractors/configs/typescript-javascript.d.ts +3 -0
  187. package/dist/core/ingestion/variable-extractors/configs/typescript-javascript.js +83 -0
  188. package/dist/core/ingestion/variable-extractors/generic.d.ts +5 -0
  189. package/dist/core/ingestion/variable-extractors/generic.js +80 -0
  190. package/dist/core/ingestion/variable-types.d.ts +82 -0
  191. package/dist/core/ingestion/variable-types.js +2 -0
  192. package/dist/core/ingestion/workers/parse-worker.js +244 -217
  193. package/dist/core/ingestion/workers/worker-pool.js +3 -0
  194. package/dist/core/lbug/csv-generator.js +1 -0
  195. package/dist/core/lbug/lbug-adapter.d.ts +4 -5
  196. package/dist/core/lbug/lbug-adapter.js +38 -14
  197. package/dist/core/lbug/schema.d.ts +2 -1
  198. package/dist/core/lbug/schema.js +10 -1
  199. package/dist/core/run-analyze.js +6 -7
  200. package/dist/core/tree-sitter/parser-loader.d.ts +3 -0
  201. package/dist/core/tree-sitter/parser-loader.js +17 -8
  202. package/dist/mcp/core/embedder.js +5 -0
  203. package/dist/mcp/local/local-backend.js +29 -19
  204. package/dist/server/api.js +2 -0
  205. package/dist/types/pipeline.d.ts +6 -0
  206. package/package.json +8 -7
  207. package/scripts/build-tree-sitter-proto.cjs +82 -0
  208. package/vendor/node_modules/node-addon-api/node_addon_api.Makefile +6 -0
  209. package/vendor/node_modules/node-addon-api/node_addon_api.target.mk +104 -0
  210. package/vendor/node_modules/node-addon-api/node_addon_api_except.target.mk +108 -0
  211. package/vendor/node_modules/node-addon-api/node_addon_api_except_all.target.mk +104 -0
  212. package/vendor/node_modules/node-addon-api/node_addon_api_maybe.target.mk +104 -0
  213. package/vendor/tree-sitter-proto/package.json +1 -7
  214. package/dist/core/ingestion/call-sites/extract-language-call-site.d.ts +0 -10
  215. package/dist/core/ingestion/call-sites/extract-language-call-site.js +0 -22
  216. package/dist/core/ingestion/call-sites/java.d.ts +0 -9
  217. package/dist/core/ingestion/call-sites/java.js +0 -30
  218. package/dist/core/ingestion/import-resolvers/dart.d.ts +0 -7
  219. package/dist/core/ingestion/import-resolvers/swift.d.ts +0 -7
  220. package/dist/core/ingestion/import-resolvers/vue.d.ts +0 -8
  221. package/dist/core/ingestion/import-resolvers/vue.js +0 -9
  222. package/scripts/preinstall-cleanup.cjs +0 -34
@@ -36,8 +36,7 @@ try {
36
36
  catch { }
37
37
  import { getLanguageFromFilename } from '../../../_shared/index.js';
38
38
  import { FUNCTION_NODE_TYPES, getDefinitionNodeFromCaptures, findEnclosingClassInfo, getLabelFromCaptures, findDescendant, extractStringContent, genericFuncName, inferFunctionLabel, CLASS_CONTAINER_TYPES, } from '../utils/ast-helpers.js';
39
- import { countCallArguments, inferCallForm, extractReceiverName, extractReceiverNode, extractMixedChain, extractCallArgTypes, } from '../utils/call-analysis.js';
40
- import { extractParsedCallSite } from '../call-sites/extract-language-call-site.js';
39
+ import { extractCallArgTypes } from '../utils/call-analysis.js';
41
40
  import { buildTypeEnv } from '../type-env.js';
42
41
  import { detectFrameworkFromAST } from '../framework-detection.js';
43
42
  import { generateId } from '../../../lib/utils.js';
@@ -1022,33 +1021,36 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1022
1021
  // Heritage edges (EXTENDS/IMPLEMENTS) are created by heritage-processor which runs
1023
1022
  // in PARALLEL with call-processor, so the graph edges don't exist when buildTypeEnv
1024
1023
  // runs. This pre-pass makes parent class information available for type resolution.
1024
+ const provider = getProvider(language);
1025
1025
  const fileParentMap = new Map();
1026
- for (const match of matches) {
1027
- const captureMap = {};
1028
- for (const c of match.captures) {
1029
- captureMap[c.name] = c.node;
1030
- }
1031
- if (captureMap['heritage.class'] && captureMap['heritage.extends']) {
1032
- const className = captureMap['heritage.class'].text;
1033
- const parentName = captureMap['heritage.extends'].text;
1034
- // Skip Go named fields (only anonymous fields are struct embedding)
1035
- const extendsNode = captureMap['heritage.extends'];
1036
- const fieldDecl = extendsNode.parent;
1037
- if (fieldDecl?.type === 'field_declaration' && fieldDecl.childForFieldName('name'))
1038
- continue;
1039
- let parents = fileParentMap.get(className);
1040
- if (!parents) {
1041
- parents = [];
1042
- fileParentMap.set(className, parents);
1026
+ if (provider.heritageExtractor) {
1027
+ for (const match of matches) {
1028
+ const captureMap = {};
1029
+ for (const c of match.captures) {
1030
+ captureMap[c.name] = c.node;
1031
+ }
1032
+ if (captureMap['heritage.class']) {
1033
+ const heritageItems = provider.heritageExtractor.extract(captureMap, {
1034
+ filePath: file.path,
1035
+ language,
1036
+ });
1037
+ for (const item of heritageItems) {
1038
+ if (item.kind === 'extends') {
1039
+ let parents = fileParentMap.get(item.className);
1040
+ if (!parents) {
1041
+ parents = [];
1042
+ fileParentMap.set(item.className, parents);
1043
+ }
1044
+ if (!parents.includes(item.parentName))
1045
+ parents.push(item.parentName);
1046
+ }
1047
+ }
1043
1048
  }
1044
- if (!parents.includes(parentName))
1045
- parents.push(parentName);
1046
1049
  }
1047
1050
  }
1048
1051
  // Build per-file type environment + constructor bindings in a single AST walk.
1049
1052
  // Constructor bindings are verified against the SymbolTable in processCallsFromExtracted.
1050
1053
  const parentMap = fileParentMap;
1051
- const provider = getProvider(language);
1052
1054
  const typeEnv = buildTypeEnv(tree, language, {
1053
1055
  parentMap,
1054
1056
  enclosingFunctionFinder: provider?.enclosingFunctionFinder,
@@ -1081,6 +1083,10 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1081
1083
  }
1082
1084
  // Per-file map: decorator end-line → decorator info, for associating with definitions
1083
1085
  const fileDecorators = new Map();
1086
+ // Track start indices of definition nodes already processed by higher-priority captures
1087
+ // (e.g. @definition.function) to avoid duplicate nodes when @definition.const/@definition.variable
1088
+ // patterns overlap with the same source range.
1089
+ const processedDefinitionNodes = new Set();
1084
1090
  for (const match of matches) {
1085
1091
  const captureMap = {};
1086
1092
  for (const c of match.captures) {
@@ -1248,98 +1254,130 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1248
1254
  }
1249
1255
  // Extract call sites
1250
1256
  if (captureMap['call']) {
1251
- const callNode0 = captureMap['call'];
1252
- const languageSeed = extractParsedCallSite(language, callNode0);
1253
- if (languageSeed) {
1254
- if (!provider.isBuiltInName(languageSeed.calledName)) {
1255
- const sourceId = findEnclosingFunctionId(callNode0, file.path, provider) ||
1256
- generateId('File', file.path);
1257
- const receiverName = languageSeed.callForm === 'member' ? languageSeed.receiverName : undefined;
1258
- let receiverTypeName = receiverName
1259
- ? typeEnv.lookup(receiverName, callNode0)
1260
- : undefined;
1261
- // Type-as-receiver (e.g. Java `User::getName`): no TypeEnv binding for the class name
1262
- if (receiverName !== undefined &&
1263
- receiverTypeName === undefined &&
1264
- languageSeed.callForm === 'member' &&
1265
- (language === SupportedLanguages.Java ||
1266
- language === SupportedLanguages.CSharp ||
1267
- language === SupportedLanguages.Kotlin)) {
1268
- const c0 = receiverName.charCodeAt(0);
1269
- if (c0 >= 65 && c0 <= 90)
1270
- receiverTypeName = receiverName;
1271
- }
1272
- result.calls.push({
1273
- filePath: file.path,
1274
- calledName: languageSeed.calledName,
1275
- sourceId,
1276
- callForm: languageSeed.callForm,
1277
- ...(receiverName !== undefined ? { receiverName } : {}),
1278
- ...(receiverTypeName !== undefined ? { receiverTypeName } : {}),
1279
- });
1280
- }
1281
- continue;
1282
- }
1257
+ const callNode = captureMap['call'];
1283
1258
  const callNameNode = captureMap['call.name'];
1284
- if (callNameNode) {
1285
- const calledName = callNameNode.text;
1286
- // Dispatch: route language-specific calls (heritage, properties, imports)
1287
- const routed = callRouter?.(calledName, captureMap['call']);
1288
- if (routed) {
1289
- if (routed.kind === 'skip')
1290
- continue;
1291
- if (routed.kind === 'import') {
1292
- result.imports.push({
1259
+ const callExtractor = provider.callExtractor;
1260
+ if (callExtractor) {
1261
+ // ── Path 1: Language-specific call site (bypasses routing) ────
1262
+ // Try language-specific extraction (e.g. Java `::` method references)
1263
+ // without callNameNode. If successful, skip routing and the generic
1264
+ // path entirely.
1265
+ const langCallSite = callExtractor.extract(callNode, undefined);
1266
+ if (langCallSite) {
1267
+ if (!provider.isBuiltInName(langCallSite.calledName)) {
1268
+ const sourceId = findEnclosingFunctionId(callNode, file.path, provider) ||
1269
+ generateId('File', file.path);
1270
+ const receiverName = langCallSite.callForm === 'member' ? langCallSite.receiverName : undefined;
1271
+ let receiverTypeName = receiverName
1272
+ ? typeEnv.lookup(receiverName, callNode)
1273
+ : undefined;
1274
+ // Type-as-receiver heuristic (e.g. Java `User::getName`)
1275
+ if (langCallSite.typeAsReceiverHeuristic &&
1276
+ receiverName !== undefined &&
1277
+ receiverTypeName === undefined &&
1278
+ langCallSite.callForm === 'member') {
1279
+ const c0 = receiverName.charCodeAt(0);
1280
+ if (c0 >= 65 && c0 <= 90)
1281
+ receiverTypeName = receiverName;
1282
+ }
1283
+ result.calls.push({
1293
1284
  filePath: file.path,
1294
- rawImportPath: routed.importPath,
1295
- language,
1285
+ calledName: langCallSite.calledName,
1286
+ sourceId,
1287
+ callForm: langCallSite.callForm,
1288
+ ...(receiverName !== undefined ? { receiverName } : {}),
1289
+ ...(receiverTypeName !== undefined ? { receiverTypeName } : {}),
1296
1290
  });
1297
- continue;
1298
- }
1299
- if (routed.kind === 'heritage') {
1300
- for (const item of routed.items) {
1301
- result.heritage.push({
1302
- filePath: file.path,
1303
- className: item.enclosingClass,
1304
- parentName: item.mixinName,
1305
- kind: item.heritageKind,
1306
- });
1307
- }
1308
- continue;
1309
1291
  }
1310
- if (routed.kind === 'properties') {
1311
- const propEnclosingInfo = cachedFindEnclosingClassInfo(captureMap['call'], file.path, provider.resolveEnclosingOwner);
1312
- const propEnclosingClassId = propEnclosingInfo?.classId ?? null;
1313
- // Enrich routed properties with FieldExtractor metadata
1314
- let routedFieldMap;
1315
- if (provider.fieldExtractor && typeEnv) {
1316
- const classNode = findEnclosingClassNode(captureMap['call']);
1317
- if (classNode) {
1318
- routedFieldMap = getFieldInfo(classNode, provider, {
1319
- typeEnv,
1320
- symbolTable: NOOP_SYMBOL_TABLE,
1292
+ continue;
1293
+ }
1294
+ // ── Path 2: Generic extraction via @call.name ────────────────
1295
+ if (callNameNode) {
1296
+ const calledName = callNameNode.text;
1297
+ // Check heritage extractor for call-based heritage (e.g., Ruby include/extend/prepend)
1298
+ if (provider.heritageExtractor?.extractFromCall) {
1299
+ const heritageItems = provider.heritageExtractor.extractFromCall(calledName, callNode, { filePath: file.path, language });
1300
+ if (heritageItems !== null) {
1301
+ for (const item of heritageItems) {
1302
+ result.heritage.push({
1321
1303
  filePath: file.path,
1322
- language,
1304
+ className: item.className,
1305
+ parentName: item.parentName,
1306
+ kind: item.kind,
1323
1307
  });
1324
1308
  }
1309
+ continue;
1325
1310
  }
1326
- for (const item of routed.items) {
1327
- const routedFieldInfo = routedFieldMap?.get(item.propName);
1328
- const propQualifiedName = propEnclosingInfo
1329
- ? `${propEnclosingInfo.className}.${item.propName}`
1330
- : item.propName;
1331
- const nodeId = generateId('Property', `${file.path}:${propQualifiedName}`);
1332
- result.nodes.push({
1333
- id: nodeId,
1334
- label: 'Property',
1335
- properties: {
1336
- name: item.propName,
1311
+ }
1312
+ // Dispatch: route language-specific calls (properties, imports)
1313
+ // Heritage routing is handled by heritageExtractor.extractFromCall above.
1314
+ const routed = callRouter?.(calledName, captureMap['call']);
1315
+ if (routed) {
1316
+ if (routed.kind === 'skip')
1317
+ continue;
1318
+ if (routed.kind === 'import') {
1319
+ result.imports.push({
1320
+ filePath: file.path,
1321
+ rawImportPath: routed.importPath,
1322
+ language,
1323
+ });
1324
+ continue;
1325
+ }
1326
+ if (routed.kind === 'properties') {
1327
+ const propEnclosingInfo = cachedFindEnclosingClassInfo(captureMap['call'], file.path, provider.resolveEnclosingOwner);
1328
+ const propEnclosingClassId = propEnclosingInfo?.classId ?? null;
1329
+ // Enrich routed properties with FieldExtractor metadata
1330
+ let routedFieldMap;
1331
+ if (provider.fieldExtractor && typeEnv) {
1332
+ const classNode = findEnclosingClassNode(captureMap['call']);
1333
+ if (classNode) {
1334
+ routedFieldMap = getFieldInfo(classNode, provider, {
1335
+ typeEnv,
1336
+ symbolTable: NOOP_SYMBOL_TABLE,
1337
+ filePath: file.path,
1338
+ language,
1339
+ });
1340
+ }
1341
+ }
1342
+ for (const item of routed.items) {
1343
+ const routedFieldInfo = routedFieldMap?.get(item.propName);
1344
+ const propQualifiedName = propEnclosingInfo
1345
+ ? `${propEnclosingInfo.className}.${item.propName}`
1346
+ : item.propName;
1347
+ const nodeId = generateId('Property', `${file.path}:${propQualifiedName}`);
1348
+ result.nodes.push({
1349
+ id: nodeId,
1350
+ label: 'Property',
1351
+ properties: {
1352
+ name: item.propName,
1353
+ filePath: file.path,
1354
+ startLine: item.startLine,
1355
+ endLine: item.endLine,
1356
+ language,
1357
+ isExported: true,
1358
+ description: item.accessorType,
1359
+ ...(item.declaredType
1360
+ ? { declaredType: item.declaredType }
1361
+ : routedFieldInfo?.type
1362
+ ? { declaredType: routedFieldInfo.type }
1363
+ : {}),
1364
+ ...(routedFieldInfo?.visibility !== undefined
1365
+ ? { visibility: routedFieldInfo.visibility }
1366
+ : {}),
1367
+ ...(routedFieldInfo?.isStatic !== undefined
1368
+ ? { isStatic: routedFieldInfo.isStatic }
1369
+ : {}),
1370
+ ...(routedFieldInfo?.isReadonly !== undefined
1371
+ ? { isReadonly: routedFieldInfo.isReadonly }
1372
+ : {}),
1373
+ },
1374
+ });
1375
+ result.symbols.push({
1337
1376
  filePath: file.path,
1338
- startLine: item.startLine,
1339
- endLine: item.endLine,
1340
- language,
1341
- isExported: true,
1342
- description: item.accessorType,
1377
+ name: item.propName,
1378
+ nodeId,
1379
+ type: 'Property',
1380
+ ...(propEnclosingClassId ? { ownerId: propEnclosingClassId } : {}),
1343
1381
  ...(item.declaredType
1344
1382
  ? { declaredType: item.declaredType }
1345
1383
  : routedFieldInfo?.type
@@ -1354,139 +1392,98 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1354
1392
  ...(routedFieldInfo?.isReadonly !== undefined
1355
1393
  ? { isReadonly: routedFieldInfo.isReadonly }
1356
1394
  : {}),
1357
- },
1358
- });
1359
- result.symbols.push({
1360
- filePath: file.path,
1361
- name: item.propName,
1362
- nodeId,
1363
- type: 'Property',
1364
- ...(propEnclosingClassId ? { ownerId: propEnclosingClassId } : {}),
1365
- ...(item.declaredType
1366
- ? { declaredType: item.declaredType }
1367
- : routedFieldInfo?.type
1368
- ? { declaredType: routedFieldInfo.type }
1369
- : {}),
1370
- ...(routedFieldInfo?.visibility !== undefined
1371
- ? { visibility: routedFieldInfo.visibility }
1372
- : {}),
1373
- ...(routedFieldInfo?.isStatic !== undefined
1374
- ? { isStatic: routedFieldInfo.isStatic }
1375
- : {}),
1376
- ...(routedFieldInfo?.isReadonly !== undefined
1377
- ? { isReadonly: routedFieldInfo.isReadonly }
1378
- : {}),
1379
- });
1380
- const fileId = generateId('File', file.path);
1381
- const relId = generateId('DEFINES', `${fileId}->${nodeId}`);
1382
- result.relationships.push({
1383
- id: relId,
1384
- sourceId: fileId,
1385
- targetId: nodeId,
1386
- type: 'DEFINES',
1387
- confidence: 1.0,
1388
- reason: '',
1389
- });
1390
- if (propEnclosingClassId) {
1395
+ });
1396
+ const fileId = generateId('File', file.path);
1397
+ const relId = generateId('DEFINES', `${fileId}->${nodeId}`);
1391
1398
  result.relationships.push({
1392
- id: generateId('HAS_PROPERTY', `${propEnclosingClassId}->${nodeId}`),
1393
- sourceId: propEnclosingClassId,
1399
+ id: relId,
1400
+ sourceId: fileId,
1394
1401
  targetId: nodeId,
1395
- type: 'HAS_PROPERTY',
1402
+ type: 'DEFINES',
1396
1403
  confidence: 1.0,
1397
1404
  reason: '',
1398
1405
  });
1406
+ if (propEnclosingClassId) {
1407
+ result.relationships.push({
1408
+ id: generateId('HAS_PROPERTY', `${propEnclosingClassId}->${nodeId}`),
1409
+ sourceId: propEnclosingClassId,
1410
+ targetId: nodeId,
1411
+ type: 'HAS_PROPERTY',
1412
+ confidence: 1.0,
1413
+ reason: '',
1414
+ });
1415
+ }
1399
1416
  }
1417
+ continue;
1400
1418
  }
1401
- continue;
1419
+ // kind === 'call' — fall through to normal call processing below
1402
1420
  }
1403
- // kind === 'call' — fall through to normal call processing below
1404
- }
1405
- if (!provider.isBuiltInName(calledName)) {
1406
- const callNode = captureMap['call'];
1407
- const sourceId = findEnclosingFunctionId(callNode, file.path, provider) ||
1408
- generateId('File', file.path);
1409
- const callForm = inferCallForm(callNode, callNameNode);
1410
- let receiverName = callForm === 'member' ? extractReceiverName(callNameNode) : undefined;
1411
- let receiverTypeName = receiverName
1412
- ? typeEnv.lookup(receiverName, callNode)
1413
- : undefined;
1414
- let receiverMixedChain;
1415
- // When the receiver is a complex expression (call chain, field chain, or mixed),
1416
- // extractReceiverName returns undefined. Walk the receiver node to build a unified
1417
- // mixed chain for deferred resolution in processCallsFromExtracted.
1418
- if (callForm === 'member' && receiverName === undefined && !receiverTypeName) {
1419
- const receiverNode = extractReceiverNode(callNameNode);
1420
- if (receiverNode) {
1421
- const extracted = extractMixedChain(receiverNode);
1422
- if (extracted && extracted.chain.length > 0) {
1423
- receiverMixedChain = extracted.chain;
1424
- receiverName = extracted.baseReceiverName;
1425
- // Try the type environment immediately for the base receiver
1426
- // (covers explicitly-typed locals and annotated parameters).
1427
- if (receiverName) {
1428
- receiverTypeName = typeEnv.lookup(receiverName, callNode);
1429
- }
1421
+ if (!provider.isBuiltInName(calledName)) {
1422
+ const callSite = callExtractor.extract(callNode, callNameNode);
1423
+ if (callSite) {
1424
+ const sourceId = findEnclosingFunctionId(callNode, file.path, provider) ||
1425
+ generateId('File', file.path);
1426
+ let receiverTypeName = callSite.receiverName
1427
+ ? typeEnv.lookup(callSite.receiverName, callNode)
1428
+ : undefined;
1429
+ // Type-as-receiver heuristic
1430
+ if (callSite.typeAsReceiverHeuristic &&
1431
+ callSite.receiverName !== undefined &&
1432
+ receiverTypeName === undefined &&
1433
+ callSite.callForm === 'member') {
1434
+ const c0 = callSite.receiverName.charCodeAt(0);
1435
+ if (c0 >= 65 && c0 <= 90)
1436
+ receiverTypeName = callSite.receiverName;
1430
1437
  }
1438
+ const inferLiteralType = provider.typeConfig?.inferLiteralType;
1439
+ // Skip when no arg list / zero args: nothing to infer for overload typing
1440
+ const argTypes = inferLiteralType && callSite.argCount !== undefined && callSite.argCount > 0
1441
+ ? extractCallArgTypes(callNode, inferLiteralType, (varName, cn) => typeEnv.lookup(varName, cn))
1442
+ : undefined;
1443
+ result.calls.push({
1444
+ filePath: file.path,
1445
+ calledName: callSite.calledName,
1446
+ sourceId,
1447
+ ...(callSite.argCount !== undefined ? { argCount: callSite.argCount } : {}),
1448
+ ...(callSite.callForm !== undefined ? { callForm: callSite.callForm } : {}),
1449
+ ...(callSite.receiverName !== undefined
1450
+ ? { receiverName: callSite.receiverName }
1451
+ : {}),
1452
+ ...(receiverTypeName !== undefined ? { receiverTypeName } : {}),
1453
+ ...(callSite.receiverMixedChain !== undefined
1454
+ ? { receiverMixedChain: callSite.receiverMixedChain }
1455
+ : {}),
1456
+ ...(argTypes !== undefined ? { argTypes } : {}),
1457
+ });
1431
1458
  }
1432
1459
  }
1433
- const inferLiteralType = provider.typeConfig?.inferLiteralType;
1434
- const argCountForOverloadHints = countCallArguments(callNode);
1435
- // Skip when no arg list / zero args: nothing to infer for overload typing; saves AST walks + payload size.
1436
- const argTypes = inferLiteralType &&
1437
- argCountForOverloadHints !== undefined &&
1438
- argCountForOverloadHints > 0
1439
- ? extractCallArgTypes(callNode, inferLiteralType, (varName, cn) => typeEnv.lookup(varName, cn))
1440
- : undefined;
1441
- result.calls.push({
1442
- filePath: file.path,
1443
- calledName,
1444
- sourceId,
1445
- argCount: countCallArguments(callNode),
1446
- ...(callForm !== undefined ? { callForm } : {}),
1447
- ...(receiverName !== undefined ? { receiverName } : {}),
1448
- ...(receiverTypeName !== undefined ? { receiverTypeName } : {}),
1449
- ...(receiverMixedChain !== undefined ? { receiverMixedChain } : {}),
1450
- ...(argTypes !== undefined ? { argTypes } : {}),
1451
- });
1452
1460
  }
1453
1461
  }
1454
1462
  continue;
1455
1463
  }
1456
- // Extract heritage (extends/implements)
1464
+ // Extract heritage (extends/implements) via provider heritage extractor
1457
1465
  if (captureMap['heritage.class']) {
1458
- if (captureMap['heritage.extends']) {
1459
- // Go struct embedding: the query matches ALL field_declarations with
1460
- // type_identifier, but only anonymous fields (no name) are embedded.
1461
- // Named fields like `Breed string` also match — skip them.
1462
- const extendsNode = captureMap['heritage.extends'];
1463
- const fieldDecl = extendsNode.parent;
1464
- const isNamedField = fieldDecl?.type === 'field_declaration' && fieldDecl.childForFieldName('name');
1465
- if (!isNamedField) {
1466
+ if (provider.heritageExtractor) {
1467
+ const heritageItems = provider.heritageExtractor.extract(captureMap, {
1468
+ filePath: file.path,
1469
+ language,
1470
+ });
1471
+ for (const item of heritageItems) {
1466
1472
  result.heritage.push({
1467
1473
  filePath: file.path,
1468
- className: captureMap['heritage.class'].text,
1469
- parentName: captureMap['heritage.extends'].text,
1470
- kind: 'extends',
1474
+ className: item.className,
1475
+ parentName: item.parentName,
1476
+ kind: item.kind,
1471
1477
  });
1472
1478
  }
1479
+ // When the extractor consumes the match, skip symbol processing below.
1480
+ if (heritageItems.length > 0) {
1481
+ continue;
1482
+ }
1473
1483
  }
1474
- if (captureMap['heritage.implements']) {
1475
- result.heritage.push({
1476
- filePath: file.path,
1477
- className: captureMap['heritage.class'].text,
1478
- parentName: captureMap['heritage.implements'].text,
1479
- kind: 'implements',
1480
- });
1481
- }
1482
- if (captureMap['heritage.trait']) {
1483
- result.heritage.push({
1484
- filePath: file.path,
1485
- className: captureMap['heritage.class'].text,
1486
- parentName: captureMap['heritage.trait'].text,
1487
- kind: 'trait-impl',
1488
- });
1489
- }
1484
+ // Fallback: the extractor returned [] (or is absent), but the match still
1485
+ // carries a heritage-specific capture. The match belongs to a heritage
1486
+ // clause and must not fall through to generic symbol processing.
1490
1487
  if (captureMap['heritage.extends'] ||
1491
1488
  captureMap['heritage.implements'] ||
1492
1489
  captureMap['heritage.trait']) {
@@ -1505,6 +1502,17 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1505
1502
  })
1506
1503
  : null;
1507
1504
  const nodeLabel = extractedClassSymbol?.type ?? defaultNodeLabel;
1505
+ // Dedup: variable captures (Const/Static/Variable) may overlap with higher-priority
1506
+ // captures (e.g. `const fn = () => {}` matches both @definition.function and @definition.const).
1507
+ // Skip variable captures whose definition node was already processed.
1508
+ if ((nodeLabel === 'Const' || nodeLabel === 'Static' || nodeLabel === 'Variable') &&
1509
+ definitionNode &&
1510
+ processedDefinitionNodes.has(definitionNode.startIndex)) {
1511
+ continue;
1512
+ }
1513
+ if (definitionNode) {
1514
+ processedDefinitionNodes.add(definitionNode.startIndex);
1515
+ }
1508
1516
  // Synthesize name for constructors without explicit @name capture (e.g. Swift init)
1509
1517
  if (!nameNode && nodeLabel !== 'Constructor' && !extractedClassSymbol)
1510
1518
  continue;
@@ -1657,6 +1665,25 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1657
1665
  }
1658
1666
  }
1659
1667
  }
1668
+ // Variable/Const/Static metadata extraction via VariableExtractor
1669
+ if ((nodeLabel === 'Const' || nodeLabel === 'Static' || nodeLabel === 'Variable') &&
1670
+ definitionNode &&
1671
+ provider.variableExtractor) {
1672
+ const varCtx = {
1673
+ filePath: file.path,
1674
+ language,
1675
+ };
1676
+ const varInfo = provider.variableExtractor.extract(definitionNode, varCtx);
1677
+ if (varInfo) {
1678
+ if (varInfo.type)
1679
+ declaredType = varInfo.type;
1680
+ methodProps.visibility = varInfo.visibility;
1681
+ methodProps.isStatic = varInfo.isStatic;
1682
+ methodProps.isConst = varInfo.isConst;
1683
+ methodProps.isMutable = varInfo.isMutable;
1684
+ methodProps.scope = varInfo.scope;
1685
+ }
1686
+ }
1660
1687
  result.nodes.push({
1661
1688
  id: nodeId,
1662
1689
  label: nodeLabel,
@@ -79,6 +79,9 @@ export const createWorkerPool = (workerUrl, poolSize) => {
79
79
  onProgress(total);
80
80
  }
81
81
  }
82
+ else if (msg.type === 'warning') {
83
+ console.warn(msg.message);
84
+ }
82
85
  else if (msg.type === 'sub-batch-done') {
83
86
  sendNextSubBatch();
84
87
  }
@@ -228,6 +228,7 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir) => {
228
228
  'TypeAlias',
229
229
  'Const',
230
230
  'Static',
231
+ 'Variable',
231
232
  'Property',
232
233
  'Record',
233
234
  'Delegate',
@@ -1,5 +1,6 @@
1
1
  import lbug from '@ladybugdb/core';
2
2
  import { KnowledgeGraph } from '../graph/types.js';
3
+ import type { CachedEmbedding } from '../embeddings/types.js';
3
4
  /** Factory for creating WriteStreams — injectable for testing. */
4
5
  export type WriteStreamFactory = (filePath: string) => import('fs').WriteStream;
5
6
  /** Result of splitting the relationship CSV into per-label-pair files. */
@@ -92,14 +93,12 @@ export declare const getLbugStats: () => Promise<{
92
93
  * Load cached embeddings from LadybugDB before a rebuild.
93
94
  * Returns all embedding vectors so they can be re-inserted after the graph is reloaded,
94
95
  * avoiding expensive re-embedding of unchanged nodes.
96
+ *
97
+ * Detects old schema (no chunkIndex column) and returns empty cache to trigger rebuild.
95
98
  */
96
99
  export declare const loadCachedEmbeddings: () => Promise<{
97
100
  embeddingNodeIds: Set<string>;
98
- embeddings: Array<{
99
- nodeId: string;
100
- embedding: number[];
101
- contentHash?: string;
102
- }>;
101
+ embeddings: CachedEmbedding[];
103
102
  }>;
104
103
  /**
105
104
  * Fetch existing embedding hashes from CodeEmbedding table for incremental embedding.