@veewo/gitnexus 1.3.11 → 1.4.6-rc

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 (181) hide show
  1. package/README.md +37 -80
  2. package/dist/benchmark/agent-context/tool-runner.js +2 -2
  3. package/dist/benchmark/neonspark-candidates.js +3 -3
  4. package/dist/benchmark/tool-runner.js +2 -2
  5. package/dist/cli/ai-context.d.ts +2 -1
  6. package/dist/cli/ai-context.js +16 -12
  7. package/dist/cli/analyze.d.ts +2 -0
  8. package/dist/cli/analyze.js +68 -48
  9. package/dist/cli/augment.js +1 -1
  10. package/dist/cli/eval-server.d.ts +8 -1
  11. package/dist/cli/eval-server.js +30 -13
  12. package/dist/cli/index.js +28 -82
  13. package/dist/cli/lazy-action.d.ts +6 -0
  14. package/dist/cli/lazy-action.js +18 -0
  15. package/dist/cli/mcp.js +3 -1
  16. package/dist/cli/setup.js +87 -48
  17. package/dist/cli/setup.test.js +18 -13
  18. package/dist/cli/skill-gen.d.ts +26 -0
  19. package/dist/cli/skill-gen.js +549 -0
  20. package/dist/cli/status.js +13 -4
  21. package/dist/cli/tool.d.ts +3 -2
  22. package/dist/cli/tool.js +50 -16
  23. package/dist/cli/wiki.js +8 -4
  24. package/dist/config/ignore-service.d.ts +25 -0
  25. package/dist/config/ignore-service.js +76 -0
  26. package/dist/config/supported-languages.d.ts +4 -1
  27. package/dist/config/supported-languages.js +3 -2
  28. package/dist/core/augmentation/engine.js +94 -67
  29. package/dist/core/embeddings/embedder.d.ts +1 -1
  30. package/dist/core/embeddings/embedder.js +1 -1
  31. package/dist/core/embeddings/embedding-pipeline.d.ts +3 -3
  32. package/dist/core/embeddings/embedding-pipeline.js +52 -25
  33. package/dist/core/embeddings/types.d.ts +1 -1
  34. package/dist/core/graph/types.d.ts +7 -2
  35. package/dist/core/ingestion/ast-cache.js +3 -2
  36. package/dist/core/ingestion/call-processor.d.ts +8 -6
  37. package/dist/core/ingestion/call-processor.js +468 -206
  38. package/dist/core/ingestion/call-routing.d.ts +53 -0
  39. package/dist/core/ingestion/call-routing.js +108 -0
  40. package/dist/core/ingestion/constants.d.ts +16 -0
  41. package/dist/core/ingestion/constants.js +16 -0
  42. package/dist/core/ingestion/entry-point-scoring.d.ts +2 -1
  43. package/dist/core/ingestion/entry-point-scoring.js +116 -23
  44. package/dist/core/ingestion/export-detection.d.ts +18 -0
  45. package/dist/core/ingestion/export-detection.js +231 -0
  46. package/dist/core/ingestion/filesystem-walker.js +4 -3
  47. package/dist/core/ingestion/framework-detection.d.ts +19 -4
  48. package/dist/core/ingestion/framework-detection.js +182 -6
  49. package/dist/core/ingestion/heritage-processor.d.ts +13 -5
  50. package/dist/core/ingestion/heritage-processor.js +109 -55
  51. package/dist/core/ingestion/import-processor.d.ts +16 -20
  52. package/dist/core/ingestion/import-processor.js +199 -579
  53. package/dist/core/ingestion/language-config.d.ts +46 -0
  54. package/dist/core/ingestion/language-config.js +167 -0
  55. package/dist/core/ingestion/mro-processor.d.ts +45 -0
  56. package/dist/core/ingestion/mro-processor.js +369 -0
  57. package/dist/core/ingestion/named-binding-extraction.d.ts +61 -0
  58. package/dist/core/ingestion/named-binding-extraction.js +363 -0
  59. package/dist/core/ingestion/parsing-processor.d.ts +4 -1
  60. package/dist/core/ingestion/parsing-processor.js +107 -109
  61. package/dist/core/ingestion/pipeline.d.ts +6 -3
  62. package/dist/core/ingestion/pipeline.js +208 -114
  63. package/dist/core/ingestion/process-processor.js +8 -2
  64. package/dist/core/ingestion/resolution-context.d.ts +53 -0
  65. package/dist/core/ingestion/resolution-context.js +132 -0
  66. package/dist/core/ingestion/resolvers/csharp.d.ts +22 -0
  67. package/dist/core/ingestion/resolvers/csharp.js +109 -0
  68. package/dist/core/ingestion/resolvers/go.d.ts +19 -0
  69. package/dist/core/ingestion/resolvers/go.js +42 -0
  70. package/dist/core/ingestion/resolvers/index.d.ts +18 -0
  71. package/dist/core/ingestion/resolvers/index.js +13 -0
  72. package/dist/core/ingestion/resolvers/jvm.d.ts +23 -0
  73. package/dist/core/ingestion/resolvers/jvm.js +87 -0
  74. package/dist/core/ingestion/resolvers/php.d.ts +15 -0
  75. package/dist/core/ingestion/resolvers/php.js +35 -0
  76. package/dist/core/ingestion/resolvers/python.d.ts +19 -0
  77. package/dist/core/ingestion/resolvers/python.js +52 -0
  78. package/dist/core/ingestion/resolvers/ruby.d.ts +12 -0
  79. package/dist/core/ingestion/resolvers/ruby.js +15 -0
  80. package/dist/core/ingestion/resolvers/rust.d.ts +15 -0
  81. package/dist/core/ingestion/resolvers/rust.js +73 -0
  82. package/dist/core/ingestion/resolvers/standard.d.ts +28 -0
  83. package/dist/core/ingestion/resolvers/standard.js +123 -0
  84. package/dist/core/ingestion/resolvers/utils.d.ts +33 -0
  85. package/dist/core/ingestion/resolvers/utils.js +122 -0
  86. package/dist/core/ingestion/symbol-table.d.ts +21 -1
  87. package/dist/core/ingestion/symbol-table.js +40 -12
  88. package/dist/core/ingestion/tree-sitter-queries.d.ts +13 -10
  89. package/dist/core/ingestion/tree-sitter-queries.js +297 -7
  90. package/dist/core/ingestion/type-env.d.ts +49 -0
  91. package/dist/core/ingestion/type-env.js +611 -0
  92. package/dist/core/ingestion/type-extractors/c-cpp.d.ts +2 -0
  93. package/dist/core/ingestion/type-extractors/c-cpp.js +385 -0
  94. package/dist/core/ingestion/type-extractors/csharp.d.ts +2 -0
  95. package/dist/core/ingestion/type-extractors/csharp.js +383 -0
  96. package/dist/core/ingestion/type-extractors/go.d.ts +2 -0
  97. package/dist/core/ingestion/type-extractors/go.js +467 -0
  98. package/dist/core/ingestion/type-extractors/index.d.ts +22 -0
  99. package/dist/core/ingestion/type-extractors/index.js +31 -0
  100. package/dist/core/ingestion/type-extractors/jvm.d.ts +3 -0
  101. package/dist/core/ingestion/type-extractors/jvm.js +681 -0
  102. package/dist/core/ingestion/type-extractors/php.d.ts +2 -0
  103. package/dist/core/ingestion/type-extractors/php.js +549 -0
  104. package/dist/core/ingestion/type-extractors/python.d.ts +2 -0
  105. package/dist/core/ingestion/type-extractors/python.js +406 -0
  106. package/dist/core/ingestion/type-extractors/ruby.d.ts +2 -0
  107. package/dist/core/ingestion/type-extractors/ruby.js +389 -0
  108. package/dist/core/ingestion/type-extractors/rust.d.ts +2 -0
  109. package/dist/core/ingestion/type-extractors/rust.js +449 -0
  110. package/dist/core/ingestion/type-extractors/shared.d.ts +133 -0
  111. package/dist/core/ingestion/type-extractors/shared.js +703 -0
  112. package/dist/core/ingestion/type-extractors/swift.d.ts +2 -0
  113. package/dist/core/ingestion/type-extractors/swift.js +137 -0
  114. package/dist/core/ingestion/type-extractors/types.d.ts +127 -0
  115. package/dist/core/ingestion/type-extractors/typescript.d.ts +2 -0
  116. package/dist/core/ingestion/type-extractors/typescript.js +494 -0
  117. package/dist/core/ingestion/utils.d.ts +103 -0
  118. package/dist/core/ingestion/utils.js +1085 -4
  119. package/dist/core/ingestion/workers/parse-worker.d.ts +51 -4
  120. package/dist/core/ingestion/workers/parse-worker.js +634 -222
  121. package/dist/core/ingestion/workers/worker-pool.js +8 -0
  122. package/dist/core/{kuzu → lbug}/csv-generator.d.ts +12 -10
  123. package/dist/core/{kuzu → lbug}/csv-generator.js +82 -101
  124. package/dist/core/{kuzu/kuzu-adapter.d.ts → lbug/lbug-adapter.d.ts} +20 -25
  125. package/dist/core/{kuzu/kuzu-adapter.js → lbug/lbug-adapter.js} +150 -122
  126. package/dist/core/{kuzu → lbug}/schema.d.ts +4 -4
  127. package/dist/core/{kuzu → lbug}/schema.js +23 -22
  128. package/dist/core/lbug/schema.test.d.ts +1 -0
  129. package/dist/core/search/bm25-index.d.ts +4 -4
  130. package/dist/core/search/bm25-index.js +12 -11
  131. package/dist/core/search/hybrid-search.d.ts +2 -2
  132. package/dist/core/search/hybrid-search.js +6 -6
  133. package/dist/core/tree-sitter/parser-loader.d.ts +1 -0
  134. package/dist/core/tree-sitter/parser-loader.js +19 -0
  135. package/dist/core/wiki/generator.d.ts +2 -2
  136. package/dist/core/wiki/generator.js +6 -6
  137. package/dist/core/wiki/graph-queries.d.ts +4 -4
  138. package/dist/core/wiki/graph-queries.js +7 -7
  139. package/dist/mcp/compatible-stdio-transport.d.ts +25 -0
  140. package/dist/mcp/compatible-stdio-transport.js +200 -0
  141. package/dist/mcp/core/{kuzu-adapter.d.ts → lbug-adapter.d.ts} +11 -10
  142. package/dist/mcp/core/lbug-adapter.js +327 -0
  143. package/dist/mcp/local/local-backend.d.ts +21 -16
  144. package/dist/mcp/local/local-backend.js +306 -706
  145. package/dist/mcp/local/unity-parity-seed-loader.d.ts +6 -1
  146. package/dist/mcp/local/unity-parity-seed-loader.js +119 -9
  147. package/dist/mcp/local/unity-parity-seed-loader.test.js +95 -7
  148. package/dist/mcp/resources.js +2 -2
  149. package/dist/mcp/server.js +28 -13
  150. package/dist/mcp/staleness.js +2 -2
  151. package/dist/mcp/tools.js +12 -3
  152. package/dist/server/api.js +12 -12
  153. package/dist/server/mcp-http.d.ts +1 -1
  154. package/dist/server/mcp-http.js +1 -1
  155. package/dist/storage/git.js +4 -1
  156. package/dist/storage/repo-manager.d.ts +20 -2
  157. package/dist/storage/repo-manager.js +74 -4
  158. package/dist/types/pipeline.d.ts +1 -1
  159. package/hooks/claude/gitnexus-hook.cjs +149 -46
  160. package/hooks/claude/pre-tool-use.sh +2 -1
  161. package/hooks/claude/session-start.sh +0 -0
  162. package/package.json +20 -4
  163. package/scripts/patch-tree-sitter-swift.cjs +74 -0
  164. package/skills/gitnexus-cli.md +8 -8
  165. package/skills/gitnexus-debugging.md +1 -1
  166. package/skills/gitnexus-exploring.md +1 -1
  167. package/skills/gitnexus-guide.md +1 -1
  168. package/skills/gitnexus-impact-analysis.md +1 -1
  169. package/skills/gitnexus-pr-review.md +163 -0
  170. package/skills/gitnexus-refactoring.md +1 -1
  171. package/dist/cli/claude-hooks.d.ts +0 -22
  172. package/dist/cli/claude-hooks.js +0 -97
  173. package/dist/mcp/core/kuzu-adapter.js +0 -231
  174. /package/dist/core/{kuzu/csv-generator.test.d.ts → ingestion/type-extractors/types.js} +0 -0
  175. /package/dist/core/{kuzu/relationship-pair-buckets.test.d.ts → lbug/csv-generator.test.d.ts} +0 -0
  176. /package/dist/core/{kuzu → lbug}/csv-generator.test.js +0 -0
  177. /package/dist/core/{kuzu → lbug}/relationship-pair-buckets.d.ts +0 -0
  178. /package/dist/core/{kuzu → lbug}/relationship-pair-buckets.js +0 -0
  179. /package/dist/core/{kuzu/schema.test.d.ts → lbug/relationship-pair-buckets.test.d.ts} +0 -0
  180. /package/dist/core/{kuzu → lbug}/relationship-pair-buckets.test.js +0 -0
  181. /package/dist/core/{kuzu → lbug}/schema.test.js +0 -0
@@ -2,16 +2,73 @@
2
2
  * Heritage Processor
3
3
  *
4
4
  * Extracts class inheritance relationships:
5
- * - EXTENDS: Class extends another Class (TS, JS, Python)
6
- * - IMPLEMENTS: Class implements an Interface (TS only)
5
+ * - EXTENDS: Class extends another Class (TS, JS, Python, C#, C++)
6
+ * - IMPLEMENTS: Class implements an Interface (TS, C#, Java, Kotlin, PHP)
7
+ *
8
+ * Languages like C# use a single `base_list` for both class and interface parents.
9
+ * We resolve the correct edge type by checking the symbol table: if the parent is
10
+ * registered as an Interface, we emit IMPLEMENTS; otherwise EXTENDS. For unresolved
11
+ * external symbols, the fallback heuristic is language-gated:
12
+ * - C# / Java: apply the `I[A-Z]` naming convention (e.g. IDisposable → IMPLEMENTS)
13
+ * - Swift: default to IMPLEMENTS (protocol conformance is more common than class inheritance)
14
+ * - All other languages: default to EXTENDS
7
15
  */
8
16
  import Parser from 'tree-sitter';
9
- import { loadParser, loadLanguage } from '../tree-sitter/parser-loader.js';
17
+ import { isLanguageAvailable, loadParser, loadLanguage } from '../tree-sitter/parser-loader.js';
10
18
  import { LANGUAGE_QUERIES } from './tree-sitter-queries.js';
11
19
  import { generateId } from '../../lib/utils.js';
12
- import { getLanguageFromFilename, yieldToEventLoop } from './utils.js';
13
- export const processHeritage = async (graph, files, astCache, symbolTable, onProgress) => {
20
+ import { getLanguageFromFilename, isVerboseIngestionEnabled, yieldToEventLoop } from './utils.js';
21
+ import { SupportedLanguages } from '../../config/supported-languages.js';
22
+ import { getTreeSitterBufferSize } from './constants.js';
23
+ /** C#/Java convention: interfaces start with I followed by an uppercase letter */
24
+ const INTERFACE_NAME_RE = /^I[A-Z]/;
25
+ /**
26
+ * Determine whether a heritage.extends capture is actually an IMPLEMENTS relationship.
27
+ * Uses the symbol table first (authoritative — Tier 1); falls back to a language-gated
28
+ * heuristic for external symbols not present in the graph:
29
+ * - C# / Java: `I[A-Z]` naming convention
30
+ * - Swift: default IMPLEMENTS (protocol conformance is the norm)
31
+ * - All others: default EXTENDS
32
+ */
33
+ const resolveExtendsType = (parentName, currentFilePath, ctx, language) => {
34
+ const resolved = ctx.resolve(parentName, currentFilePath);
35
+ if (resolved && resolved.candidates.length > 0) {
36
+ const isInterface = resolved.candidates[0].type === 'Interface';
37
+ return isInterface
38
+ ? { type: 'IMPLEMENTS', idPrefix: 'Interface' }
39
+ : { type: 'EXTENDS', idPrefix: 'Class' };
40
+ }
41
+ // Unresolved symbol — fall back to language-specific heuristic
42
+ if (language === SupportedLanguages.CSharp || language === SupportedLanguages.Java) {
43
+ if (INTERFACE_NAME_RE.test(parentName)) {
44
+ return { type: 'IMPLEMENTS', idPrefix: 'Interface' };
45
+ }
46
+ }
47
+ else if (language === SupportedLanguages.Swift) {
48
+ // Protocol conformance is far more common than class inheritance in Swift
49
+ return { type: 'IMPLEMENTS', idPrefix: 'Interface' };
50
+ }
51
+ return { type: 'EXTENDS', idPrefix: 'Class' };
52
+ };
53
+ /**
54
+ * Resolve a symbol ID for heritage, with fallback to generated ID.
55
+ * Uses ctx.resolve() → pick first candidate's nodeId → generate synthetic ID.
56
+ */
57
+ const resolveHeritageId = (name, filePath, ctx, fallbackLabel, fallbackKey) => {
58
+ const resolved = ctx.resolve(name, filePath);
59
+ if (resolved && resolved.candidates.length > 0) {
60
+ // For global with multiple candidates, refuse (a wrong edge is worse than no edge)
61
+ if (resolved.tier === 'global' && resolved.candidates.length > 1) {
62
+ return generateId(fallbackLabel, fallbackKey ?? name);
63
+ }
64
+ return resolved.candidates[0].nodeId;
65
+ }
66
+ return generateId(fallbackLabel, fallbackKey ?? name);
67
+ };
68
+ export const processHeritage = async (graph, files, astCache, ctx, onProgress) => {
14
69
  const parser = await loadParser();
70
+ const logSkipped = isVerboseIngestionEnabled();
71
+ const skippedByLang = logSkipped ? new Map() : null;
15
72
  for (let i = 0; i < files.length; i++) {
16
73
  const file = files[i];
17
74
  onProgress?.(i + 1, files.length);
@@ -21,6 +78,12 @@ export const processHeritage = async (graph, files, astCache, symbolTable, onPro
21
78
  const language = getLanguageFromFilename(file.path);
22
79
  if (!language)
23
80
  continue;
81
+ if (!isLanguageAvailable(language)) {
82
+ if (skippedByLang) {
83
+ skippedByLang.set(language, (skippedByLang.get(language) ?? 0) + 1);
84
+ }
85
+ continue;
86
+ }
24
87
  const queryStr = LANGUAGE_QUERIES[language];
25
88
  if (!queryStr)
26
89
  continue;
@@ -28,17 +91,15 @@ export const processHeritage = async (graph, files, astCache, symbolTable, onPro
28
91
  await loadLanguage(language, file.path);
29
92
  // 3. Get AST
30
93
  let tree = astCache.get(file.path);
31
- let wasReparsed = false;
32
94
  if (!tree) {
33
95
  // Use larger bufferSize for files > 32KB
34
96
  try {
35
- tree = parser.parse(file.content, undefined, { bufferSize: 1024 * 256 });
97
+ tree = parser.parse(file.content, undefined, { bufferSize: getTreeSitterBufferSize(file.content.length) });
36
98
  }
37
99
  catch (parseError) {
38
100
  // Skip files that can't be parsed
39
101
  continue;
40
102
  }
41
- wasReparsed = true;
42
103
  // Cache re-parsed tree for potential future use
43
104
  astCache.set(file.path, tree);
44
105
  }
@@ -59,23 +120,26 @@ export const processHeritage = async (graph, files, astCache, symbolTable, onPro
59
120
  match.captures.forEach(c => {
60
121
  captureMap[c.name] = c.node;
61
122
  });
62
- // EXTENDS: Class extends another Class
123
+ // EXTENDS or IMPLEMENTS: resolve via symbol table for languages where
124
+ // the tree-sitter query can't distinguish classes from interfaces (C#, Java)
63
125
  if (captureMap['heritage.class'] && captureMap['heritage.extends']) {
126
+ // Go struct embedding: skip named fields (only anonymous fields are embedded)
127
+ const extendsNode = captureMap['heritage.extends'];
128
+ const fieldDecl = extendsNode.parent;
129
+ if (fieldDecl?.type === 'field_declaration' && fieldDecl.childForFieldName('name')) {
130
+ return; // Named field, not struct embedding
131
+ }
64
132
  const className = captureMap['heritage.class'].text;
65
133
  const parentClassName = captureMap['heritage.extends'].text;
66
- // Resolve both class IDs
67
- const childId = symbolTable.lookupExact(file.path, className) ||
68
- symbolTable.lookupFuzzy(className)[0]?.nodeId ||
69
- generateId('Class', `${file.path}:${className}`);
70
- const parentId = symbolTable.lookupFuzzy(parentClassName)[0]?.nodeId ||
71
- generateId('Class', `${parentClassName}`);
134
+ const { type: relType, idPrefix } = resolveExtendsType(parentClassName, file.path, ctx, language);
135
+ const childId = resolveHeritageId(className, file.path, ctx, 'Class', `${file.path}:${className}`);
136
+ const parentId = resolveHeritageId(parentClassName, file.path, ctx, idPrefix);
72
137
  if (childId && parentId && childId !== parentId) {
73
- const relId = generateId('EXTENDS', `${childId}->${parentId}`);
74
138
  graph.addRelationship({
75
- id: relId,
139
+ id: generateId(relType, `${childId}->${parentId}`),
76
140
  sourceId: childId,
77
141
  targetId: parentId,
78
- type: 'EXTENDS',
142
+ type: relType,
79
143
  confidence: 1.0,
80
144
  reason: '',
81
145
  });
@@ -85,16 +149,11 @@ export const processHeritage = async (graph, files, astCache, symbolTable, onPro
85
149
  if (captureMap['heritage.class'] && captureMap['heritage.implements']) {
86
150
  const className = captureMap['heritage.class'].text;
87
151
  const interfaceName = captureMap['heritage.implements'].text;
88
- // Resolve class and interface IDs
89
- const classId = symbolTable.lookupExact(file.path, className) ||
90
- symbolTable.lookupFuzzy(className)[0]?.nodeId ||
91
- generateId('Class', `${file.path}:${className}`);
92
- const interfaceId = symbolTable.lookupFuzzy(interfaceName)[0]?.nodeId ||
93
- generateId('Interface', `${interfaceName}`);
152
+ const classId = resolveHeritageId(className, file.path, ctx, 'Class', `${file.path}:${className}`);
153
+ const interfaceId = resolveHeritageId(interfaceName, file.path, ctx, 'Interface');
94
154
  if (classId && interfaceId) {
95
- const relId = generateId('IMPLEMENTS', `${classId}->${interfaceId}`);
96
155
  graph.addRelationship({
97
- id: relId,
156
+ id: generateId('IMPLEMENTS', `${classId}->${interfaceId}`),
98
157
  sourceId: classId,
99
158
  targetId: interfaceId,
100
159
  type: 'IMPLEMENTS',
@@ -107,16 +166,11 @@ export const processHeritage = async (graph, files, astCache, symbolTable, onPro
107
166
  if (captureMap['heritage.trait'] && captureMap['heritage.class']) {
108
167
  const structName = captureMap['heritage.class'].text;
109
168
  const traitName = captureMap['heritage.trait'].text;
110
- // Resolve struct and trait IDs
111
- const structId = symbolTable.lookupExact(file.path, structName) ||
112
- symbolTable.lookupFuzzy(structName)[0]?.nodeId ||
113
- generateId('Struct', `${file.path}:${structName}`);
114
- const traitId = symbolTable.lookupFuzzy(traitName)[0]?.nodeId ||
115
- generateId('Trait', `${traitName}`);
169
+ const structId = resolveHeritageId(structName, file.path, ctx, 'Struct', `${file.path}:${structName}`);
170
+ const traitId = resolveHeritageId(traitName, file.path, ctx, 'Trait');
116
171
  if (structId && traitId) {
117
- const relId = generateId('IMPLEMENTS', `${structId}->${traitId}`);
118
172
  graph.addRelationship({
119
- id: relId,
173
+ id: generateId('IMPLEMENTS', `${structId}->${traitId}`),
120
174
  sourceId: structId,
121
175
  targetId: traitId,
122
176
  type: 'IMPLEMENTS',
@@ -128,12 +182,17 @@ export const processHeritage = async (graph, files, astCache, symbolTable, onPro
128
182
  });
129
183
  // Tree is now owned by the LRU cache — no manual delete needed
130
184
  }
185
+ if (skippedByLang && skippedByLang.size > 0) {
186
+ for (const [lang, count] of skippedByLang.entries()) {
187
+ console.warn(`[ingestion] Skipped ${count} ${lang} file(s) in heritage processing — ${lang} parser not available.`);
188
+ }
189
+ }
131
190
  };
132
191
  /**
133
192
  * Fast path: resolve pre-extracted heritage from workers.
134
193
  * No AST parsing — workers already extracted className + parentName + kind.
135
194
  */
136
- export const processHeritageFromExtracted = async (graph, extractedHeritage, symbolTable, onProgress) => {
195
+ export const processHeritageFromExtracted = async (graph, extractedHeritage, ctx, onProgress) => {
137
196
  const total = extractedHeritage.length;
138
197
  for (let i = 0; i < extractedHeritage.length; i++) {
139
198
  if (i % 500 === 0) {
@@ -142,28 +201,26 @@ export const processHeritageFromExtracted = async (graph, extractedHeritage, sym
142
201
  }
143
202
  const h = extractedHeritage[i];
144
203
  if (h.kind === 'extends') {
145
- const childId = symbolTable.lookupExact(h.filePath, h.className) ||
146
- symbolTable.lookupFuzzy(h.className)[0]?.nodeId ||
147
- generateId('Class', `${h.filePath}:${h.className}`);
148
- const parentId = symbolTable.lookupFuzzy(h.parentName)[0]?.nodeId ||
149
- generateId('Class', `${h.parentName}`);
204
+ const fileLanguage = getLanguageFromFilename(h.filePath);
205
+ if (!fileLanguage)
206
+ continue;
207
+ const { type: relType, idPrefix } = resolveExtendsType(h.parentName, h.filePath, ctx, fileLanguage);
208
+ const childId = resolveHeritageId(h.className, h.filePath, ctx, 'Class', `${h.filePath}:${h.className}`);
209
+ const parentId = resolveHeritageId(h.parentName, h.filePath, ctx, idPrefix);
150
210
  if (childId && parentId && childId !== parentId) {
151
211
  graph.addRelationship({
152
- id: generateId('EXTENDS', `${childId}->${parentId}`),
212
+ id: generateId(relType, `${childId}->${parentId}`),
153
213
  sourceId: childId,
154
214
  targetId: parentId,
155
- type: 'EXTENDS',
215
+ type: relType,
156
216
  confidence: 1.0,
157
217
  reason: '',
158
218
  });
159
219
  }
160
220
  }
161
221
  else if (h.kind === 'implements') {
162
- const classId = symbolTable.lookupExact(h.filePath, h.className) ||
163
- symbolTable.lookupFuzzy(h.className)[0]?.nodeId ||
164
- generateId('Class', `${h.filePath}:${h.className}`);
165
- const interfaceId = symbolTable.lookupFuzzy(h.parentName)[0]?.nodeId ||
166
- generateId('Interface', `${h.parentName}`);
222
+ const classId = resolveHeritageId(h.className, h.filePath, ctx, 'Class', `${h.filePath}:${h.className}`);
223
+ const interfaceId = resolveHeritageId(h.parentName, h.filePath, ctx, 'Interface');
167
224
  if (classId && interfaceId) {
168
225
  graph.addRelationship({
169
226
  id: generateId('IMPLEMENTS', `${classId}->${interfaceId}`),
@@ -175,20 +232,17 @@ export const processHeritageFromExtracted = async (graph, extractedHeritage, sym
175
232
  });
176
233
  }
177
234
  }
178
- else if (h.kind === 'trait-impl') {
179
- const structId = symbolTable.lookupExact(h.filePath, h.className) ||
180
- symbolTable.lookupFuzzy(h.className)[0]?.nodeId ||
181
- generateId('Struct', `${h.filePath}:${h.className}`);
182
- const traitId = symbolTable.lookupFuzzy(h.parentName)[0]?.nodeId ||
183
- generateId('Trait', `${h.parentName}`);
235
+ else if (h.kind === 'trait-impl' || h.kind === 'include' || h.kind === 'extend' || h.kind === 'prepend') {
236
+ const structId = resolveHeritageId(h.className, h.filePath, ctx, 'Struct', `${h.filePath}:${h.className}`);
237
+ const traitId = resolveHeritageId(h.parentName, h.filePath, ctx, 'Trait');
184
238
  if (structId && traitId) {
185
239
  graph.addRelationship({
186
- id: generateId('IMPLEMENTS', `${structId}->${traitId}`),
240
+ id: generateId('IMPLEMENTS', `${structId}->${traitId}:${h.kind}`),
187
241
  sourceId: structId,
188
242
  targetId: traitId,
189
243
  type: 'IMPLEMENTS',
190
244
  confidence: 1.0,
191
- reason: 'trait-impl',
245
+ reason: h.kind,
192
246
  });
193
247
  }
194
248
  }
@@ -1,8 +1,21 @@
1
1
  import { KnowledgeGraph } from '../graph/types.js';
2
2
  import { ASTCache } from './ast-cache.js';
3
3
  import type { ExtractedImport } from './workers/parse-worker.js';
4
+ import type { ResolutionContext } from './resolution-context.js';
5
+ import type { SuffixIndex } from './resolvers/index.js';
6
+ export type { SuffixIndex, TsconfigPaths, GoModuleConfig, CSharpProjectConfig, ComposerConfig } from './resolvers/index.js';
4
7
  export type ImportMap = Map<string, Set<string>>;
5
- export declare const createImportMap: () => ImportMap;
8
+ export type PackageMap = Map<string, Set<string>>;
9
+ export interface NamedImportBinding {
10
+ sourcePath: string;
11
+ exportedName: string;
12
+ }
13
+ export type NamedImportMap = Map<string, Map<string, NamedImportBinding>>;
14
+ /**
15
+ * Check if a file path is directly inside a package directory identified by its suffix.
16
+ * Used by the symbol resolver for Go and C# directory-level import matching.
17
+ */
18
+ export declare function isFileInPackageDir(filePath: string, dirSuffix: string): boolean;
6
19
  /** Pre-built lookup structures for import resolution. Build once, reuse across chunks. */
7
20
  export interface ImportResolutionContext {
8
21
  allFilePaths: Set<string>;
@@ -12,27 +25,10 @@ export interface ImportResolutionContext {
12
25
  resolveCache: Map<string, string | null>;
13
26
  }
14
27
  export declare function buildImportResolutionContext(allPaths: string[]): ImportResolutionContext;
15
- /**
16
- * Build a suffix index for O(1) endsWith lookups.
17
- * Maps every possible path suffix to its original file path.
18
- * e.g. for "src/com/example/Foo.java":
19
- * "Foo.java" -> "src/com/example/Foo.java"
20
- * "example/Foo.java" -> "src/com/example/Foo.java"
21
- * "com/example/Foo.java" -> "src/com/example/Foo.java"
22
- * etc.
23
- */
24
- export interface SuffixIndex {
25
- /** Exact suffix lookup (case-sensitive) */
26
- get(suffix: string): string | undefined;
27
- /** Case-insensitive suffix lookup */
28
- getInsensitive(suffix: string): string | undefined;
29
- /** Get all files in a directory suffix */
30
- getFilesInDir(dirSuffix: string, extension: string): string[];
31
- }
32
28
  export declare const processImports: (graph: KnowledgeGraph, files: {
33
29
  path: string;
34
30
  content: string;
35
- }[], astCache: ASTCache, importMap: ImportMap, onProgress?: (current: number, total: number) => void, repoRoot?: string, allPaths?: string[]) => Promise<void>;
31
+ }[], astCache: ASTCache, ctx: ResolutionContext, onProgress?: (current: number, total: number) => void, repoRoot?: string, allPaths?: string[]) => Promise<void>;
36
32
  export declare const processImportsFromExtracted: (graph: KnowledgeGraph, files: {
37
33
  path: string;
38
- }[], extractedImports: ExtractedImport[], importMap: ImportMap, onProgress?: (current: number, total: number) => void, repoRoot?: string, prebuiltCtx?: ImportResolutionContext) => Promise<void>;
34
+ }[], extractedImports: ExtractedImport[], ctx: ResolutionContext, onProgress?: (current: number, total: number) => void, repoRoot?: string, prebuiltCtx?: ImportResolutionContext) => Promise<void>;