gitnexus 1.0.0

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 (110) hide show
  1. package/README.md +181 -0
  2. package/dist/cli/ai-context.d.ts +21 -0
  3. package/dist/cli/ai-context.js +219 -0
  4. package/dist/cli/analyze.d.ts +10 -0
  5. package/dist/cli/analyze.js +118 -0
  6. package/dist/cli/clean.d.ts +8 -0
  7. package/dist/cli/clean.js +29 -0
  8. package/dist/cli/index.d.ts +2 -0
  9. package/dist/cli/index.js +42 -0
  10. package/dist/cli/list.d.ts +6 -0
  11. package/dist/cli/list.js +27 -0
  12. package/dist/cli/mcp.d.ts +7 -0
  13. package/dist/cli/mcp.js +85 -0
  14. package/dist/cli/serve.d.ts +3 -0
  15. package/dist/cli/serve.js +5 -0
  16. package/dist/cli/status.d.ts +6 -0
  17. package/dist/cli/status.js +27 -0
  18. package/dist/config/ignore-service.d.ts +1 -0
  19. package/dist/config/ignore-service.js +208 -0
  20. package/dist/config/supported-languages.d.ts +11 -0
  21. package/dist/config/supported-languages.js +15 -0
  22. package/dist/core/embeddings/embedder.d.ts +60 -0
  23. package/dist/core/embeddings/embedder.js +205 -0
  24. package/dist/core/embeddings/embedding-pipeline.d.ts +50 -0
  25. package/dist/core/embeddings/embedding-pipeline.js +321 -0
  26. package/dist/core/embeddings/index.d.ts +9 -0
  27. package/dist/core/embeddings/index.js +9 -0
  28. package/dist/core/embeddings/text-generator.d.ts +24 -0
  29. package/dist/core/embeddings/text-generator.js +182 -0
  30. package/dist/core/embeddings/types.d.ts +87 -0
  31. package/dist/core/embeddings/types.js +32 -0
  32. package/dist/core/graph/graph.d.ts +2 -0
  33. package/dist/core/graph/graph.js +61 -0
  34. package/dist/core/graph/types.d.ts +50 -0
  35. package/dist/core/graph/types.js +1 -0
  36. package/dist/core/ingestion/ast-cache.d.ts +11 -0
  37. package/dist/core/ingestion/ast-cache.js +34 -0
  38. package/dist/core/ingestion/call-processor.d.ts +8 -0
  39. package/dist/core/ingestion/call-processor.js +269 -0
  40. package/dist/core/ingestion/cluster-enricher.d.ts +38 -0
  41. package/dist/core/ingestion/cluster-enricher.js +170 -0
  42. package/dist/core/ingestion/community-processor.d.ts +39 -0
  43. package/dist/core/ingestion/community-processor.js +269 -0
  44. package/dist/core/ingestion/entry-point-scoring.d.ts +39 -0
  45. package/dist/core/ingestion/entry-point-scoring.js +235 -0
  46. package/dist/core/ingestion/filesystem-walker.d.ts +5 -0
  47. package/dist/core/ingestion/filesystem-walker.js +26 -0
  48. package/dist/core/ingestion/framework-detection.d.ts +38 -0
  49. package/dist/core/ingestion/framework-detection.js +183 -0
  50. package/dist/core/ingestion/heritage-processor.d.ts +14 -0
  51. package/dist/core/ingestion/heritage-processor.js +134 -0
  52. package/dist/core/ingestion/import-processor.d.ts +8 -0
  53. package/dist/core/ingestion/import-processor.js +490 -0
  54. package/dist/core/ingestion/parsing-processor.d.ts +8 -0
  55. package/dist/core/ingestion/parsing-processor.js +249 -0
  56. package/dist/core/ingestion/pipeline.d.ts +2 -0
  57. package/dist/core/ingestion/pipeline.js +228 -0
  58. package/dist/core/ingestion/process-processor.d.ts +51 -0
  59. package/dist/core/ingestion/process-processor.js +278 -0
  60. package/dist/core/ingestion/structure-processor.d.ts +2 -0
  61. package/dist/core/ingestion/structure-processor.js +36 -0
  62. package/dist/core/ingestion/symbol-table.d.ts +33 -0
  63. package/dist/core/ingestion/symbol-table.js +38 -0
  64. package/dist/core/ingestion/tree-sitter-queries.d.ts +11 -0
  65. package/dist/core/ingestion/tree-sitter-queries.js +319 -0
  66. package/dist/core/ingestion/utils.d.ts +10 -0
  67. package/dist/core/ingestion/utils.js +44 -0
  68. package/dist/core/kuzu/csv-generator.d.ts +22 -0
  69. package/dist/core/kuzu/csv-generator.js +272 -0
  70. package/dist/core/kuzu/kuzu-adapter.d.ts +81 -0
  71. package/dist/core/kuzu/kuzu-adapter.js +568 -0
  72. package/dist/core/kuzu/schema.d.ts +53 -0
  73. package/dist/core/kuzu/schema.js +380 -0
  74. package/dist/core/search/bm25-index.d.ts +22 -0
  75. package/dist/core/search/bm25-index.js +52 -0
  76. package/dist/core/search/hybrid-search.d.ts +49 -0
  77. package/dist/core/search/hybrid-search.js +118 -0
  78. package/dist/core/tree-sitter/parser-loader.d.ts +4 -0
  79. package/dist/core/tree-sitter/parser-loader.js +42 -0
  80. package/dist/lib/utils.d.ts +1 -0
  81. package/dist/lib/utils.js +3 -0
  82. package/dist/mcp/core/embedder.d.ts +27 -0
  83. package/dist/mcp/core/embedder.js +93 -0
  84. package/dist/mcp/core/kuzu-adapter.d.ts +23 -0
  85. package/dist/mcp/core/kuzu-adapter.js +62 -0
  86. package/dist/mcp/local/local-backend.d.ts +73 -0
  87. package/dist/mcp/local/local-backend.js +752 -0
  88. package/dist/mcp/resources.d.ts +31 -0
  89. package/dist/mcp/resources.js +279 -0
  90. package/dist/mcp/server.d.ts +12 -0
  91. package/dist/mcp/server.js +130 -0
  92. package/dist/mcp/staleness.d.ts +15 -0
  93. package/dist/mcp/staleness.js +29 -0
  94. package/dist/mcp/tools.d.ts +24 -0
  95. package/dist/mcp/tools.js +160 -0
  96. package/dist/server/api.d.ts +6 -0
  97. package/dist/server/api.js +156 -0
  98. package/dist/storage/git.d.ts +7 -0
  99. package/dist/storage/git.js +39 -0
  100. package/dist/storage/repo-manager.d.ts +61 -0
  101. package/dist/storage/repo-manager.js +106 -0
  102. package/dist/types/pipeline.d.ts +28 -0
  103. package/dist/types/pipeline.js +16 -0
  104. package/package.json +80 -0
  105. package/skills/debugging.md +104 -0
  106. package/skills/exploring.md +112 -0
  107. package/skills/impact-analysis.md +114 -0
  108. package/skills/refactoring.md +119 -0
  109. package/vendor/leiden/index.cjs +355 -0
  110. package/vendor/leiden/utils.cjs +392 -0
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Embedding Pipeline Types
3
+ *
4
+ * Type definitions for the embedding generation and semantic search system.
5
+ */
6
+ /**
7
+ * Node labels that should be embedded for semantic search
8
+ * These are code elements that benefit from semantic matching
9
+ */
10
+ export const EMBEDDABLE_LABELS = [
11
+ 'Function',
12
+ 'Class',
13
+ 'Method',
14
+ 'Interface',
15
+ 'File',
16
+ ];
17
+ /**
18
+ * Check if a label should be embedded
19
+ */
20
+ export const isEmbeddableLabel = (label) => EMBEDDABLE_LABELS.includes(label);
21
+ /**
22
+ * Default embedding configuration
23
+ * Uses snowflake-arctic-embed-xs for browser efficiency
24
+ * Tries WebGPU first (fast), user can choose WASM fallback if unavailable
25
+ */
26
+ export const DEFAULT_EMBEDDING_CONFIG = {
27
+ modelId: 'Snowflake/snowflake-arctic-embed-xs',
28
+ batchSize: 16,
29
+ dimensions: 384,
30
+ device: 'auto',
31
+ maxSnippetLength: 500,
32
+ };
@@ -0,0 +1,2 @@
1
+ import { KnowledgeGraph } from './types.js';
2
+ export declare const createKnowledgeGraph: () => KnowledgeGraph;
@@ -0,0 +1,61 @@
1
+ export const createKnowledgeGraph = () => {
2
+ const nodeMap = new Map();
3
+ const relationshipMap = new Map();
4
+ const addNode = (node) => {
5
+ if (!nodeMap.has(node.id)) {
6
+ nodeMap.set(node.id, node);
7
+ }
8
+ };
9
+ const addRelationship = (relationship) => {
10
+ if (!relationshipMap.has(relationship.id)) {
11
+ relationshipMap.set(relationship.id, relationship);
12
+ }
13
+ };
14
+ /**
15
+ * Remove a single node and all relationships involving it
16
+ */
17
+ const removeNode = (nodeId) => {
18
+ if (!nodeMap.has(nodeId))
19
+ return false;
20
+ nodeMap.delete(nodeId);
21
+ // Remove all relationships involving this node
22
+ for (const [relId, rel] of relationshipMap) {
23
+ if (rel.sourceId === nodeId || rel.targetId === nodeId) {
24
+ relationshipMap.delete(relId);
25
+ }
26
+ }
27
+ return true;
28
+ };
29
+ /**
30
+ * Remove all nodes (and their relationships) belonging to a file
31
+ */
32
+ const removeNodesByFile = (filePath) => {
33
+ let removed = 0;
34
+ for (const [nodeId, node] of nodeMap) {
35
+ if (node.properties?.filePath === filePath) {
36
+ removeNode(nodeId);
37
+ removed++;
38
+ }
39
+ }
40
+ return removed;
41
+ };
42
+ return {
43
+ get nodes() {
44
+ return Array.from(nodeMap.values());
45
+ },
46
+ get relationships() {
47
+ return Array.from(relationshipMap.values());
48
+ },
49
+ // O(1) count getters - avoid creating arrays just for length
50
+ get nodeCount() {
51
+ return nodeMap.size;
52
+ },
53
+ get relationshipCount() {
54
+ return relationshipMap.size;
55
+ },
56
+ addNode,
57
+ addRelationship,
58
+ removeNode,
59
+ removeNodesByFile,
60
+ };
61
+ };
@@ -0,0 +1,50 @@
1
+ export type NodeLabel = 'Project' | 'Package' | 'Module' | 'Folder' | 'File' | 'Class' | 'Function' | 'Method' | 'Variable' | 'Interface' | 'Enum' | 'Decorator' | 'Import' | 'Type' | 'CodeElement' | 'Community' | 'Process';
2
+ export type NodeProperties = {
3
+ name: string;
4
+ filePath: string;
5
+ startLine?: number;
6
+ endLine?: number;
7
+ language?: string;
8
+ isExported?: boolean;
9
+ heuristicLabel?: string;
10
+ cohesion?: number;
11
+ symbolCount?: number;
12
+ keywords?: string[];
13
+ description?: string;
14
+ enrichedBy?: 'heuristic' | 'llm';
15
+ processType?: 'intra_community' | 'cross_community';
16
+ stepCount?: number;
17
+ communities?: string[];
18
+ entryPointId?: string;
19
+ terminalId?: string;
20
+ entryPointScore?: number;
21
+ entryPointReason?: string;
22
+ };
23
+ export type RelationshipType = 'CONTAINS' | 'CALLS' | 'INHERITS' | 'OVERRIDES' | 'IMPORTS' | 'USES' | 'DEFINES' | 'DECORATES' | 'IMPLEMENTS' | 'EXTENDS' | 'MEMBER_OF' | 'STEP_IN_PROCESS';
24
+ export interface GraphNode {
25
+ id: string;
26
+ label: NodeLabel;
27
+ properties: NodeProperties;
28
+ }
29
+ export interface GraphRelationship {
30
+ id: string;
31
+ sourceId: string;
32
+ targetId: string;
33
+ type: RelationshipType;
34
+ /** Confidence score 0-1 (1.0 = certain, lower = uncertain resolution) */
35
+ confidence: number;
36
+ /** Resolution reason: 'import-resolved', 'same-file', 'fuzzy-global', or empty for non-CALLS */
37
+ reason: string;
38
+ /** Step number for STEP_IN_PROCESS relationships (1-indexed) */
39
+ step?: number;
40
+ }
41
+ export interface KnowledgeGraph {
42
+ nodes: GraphNode[];
43
+ relationships: GraphRelationship[];
44
+ nodeCount: number;
45
+ relationshipCount: number;
46
+ addNode: (node: GraphNode) => void;
47
+ addRelationship: (relationship: GraphRelationship) => void;
48
+ removeNode: (nodeId: string) => boolean;
49
+ removeNodesByFile: (filePath: string) => number;
50
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import Parser from 'tree-sitter';
2
+ export interface ASTCache {
3
+ get: (filePath: string) => Parser.Tree | undefined;
4
+ set: (filePath: string, tree: Parser.Tree) => void;
5
+ clear: () => void;
6
+ stats: () => {
7
+ size: number;
8
+ maxSize: number;
9
+ };
10
+ }
11
+ export declare const createASTCache: (maxSize?: number) => ASTCache;
@@ -0,0 +1,34 @@
1
+ import { LRUCache } from 'lru-cache';
2
+ export const createASTCache = (maxSize = 50) => {
3
+ // Initialize the cache with a 'dispose' handler
4
+ // This is the magic: When an item is evicted (dropped), this runs automatically.
5
+ const cache = new LRUCache({
6
+ max: maxSize,
7
+ dispose: (tree) => {
8
+ try {
9
+ // NOTE: web-tree-sitter has tree.delete(); native tree-sitter trees are GC-managed.
10
+ // Keep this try/catch so we don't crash on either runtime.
11
+ tree.delete?.();
12
+ }
13
+ catch (e) {
14
+ console.warn('Failed to delete tree from WASM memory', e);
15
+ }
16
+ }
17
+ });
18
+ return {
19
+ get: (filePath) => {
20
+ const tree = cache.get(filePath);
21
+ return tree; // Returns undefined if not found
22
+ },
23
+ set: (filePath, tree) => {
24
+ cache.set(filePath, tree);
25
+ },
26
+ clear: () => {
27
+ cache.clear();
28
+ },
29
+ stats: () => ({
30
+ size: cache.size,
31
+ maxSize: maxSize
32
+ })
33
+ };
34
+ };
@@ -0,0 +1,8 @@
1
+ import { KnowledgeGraph } from '../graph/types.js';
2
+ import { ASTCache } from './ast-cache.js';
3
+ import { SymbolTable } from './symbol-table.js';
4
+ import { ImportMap } from './import-processor.js';
5
+ export declare const processCalls: (graph: KnowledgeGraph, files: {
6
+ path: string;
7
+ content: string;
8
+ }[], astCache: ASTCache, symbolTable: SymbolTable, importMap: ImportMap, onProgress?: (current: number, total: number) => void) => Promise<void>;
@@ -0,0 +1,269 @@
1
+ import Parser from 'tree-sitter';
2
+ import { loadParser, loadLanguage } from '../tree-sitter/parser-loader.js';
3
+ import { LANGUAGE_QUERIES } from './tree-sitter-queries.js';
4
+ import { generateId } from '../../lib/utils.js';
5
+ import { getLanguageFromFilename, yieldToEventLoop } from './utils.js';
6
+ /**
7
+ * Node types that represent function/method definitions across languages.
8
+ * Used to find the enclosing function for a call site.
9
+ */
10
+ const FUNCTION_NODE_TYPES = new Set([
11
+ // TypeScript/JavaScript
12
+ 'function_declaration',
13
+ 'arrow_function',
14
+ 'function_expression',
15
+ 'method_definition',
16
+ 'generator_function_declaration',
17
+ // Python
18
+ 'function_definition',
19
+ // Common async variants
20
+ 'async_function_declaration',
21
+ 'async_arrow_function',
22
+ // Java
23
+ 'method_declaration',
24
+ 'constructor_declaration',
25
+ // C/C++
26
+ // 'function_definition' already included above
27
+ // Go
28
+ // 'method_declaration' already included from Java
29
+ // C#
30
+ 'local_function_statement',
31
+ // Rust
32
+ 'function_item',
33
+ 'impl_item', // Methods inside impl blocks
34
+ ]);
35
+ /**
36
+ * Walk up the AST from a node to find the enclosing function/method.
37
+ * Returns null if the call is at module/file level (top-level code).
38
+ */
39
+ const findEnclosingFunction = (node, filePath, symbolTable) => {
40
+ let current = node.parent;
41
+ while (current) {
42
+ if (FUNCTION_NODE_TYPES.has(current.type)) {
43
+ // Found enclosing function - try to get its name
44
+ let funcName = null;
45
+ let label = 'Function';
46
+ // Different node types have different name locations
47
+ if (current.type === 'function_declaration' ||
48
+ current.type === 'function_definition' ||
49
+ current.type === 'async_function_declaration' ||
50
+ current.type === 'generator_function_declaration' ||
51
+ current.type === 'function_item') { // Rust function
52
+ // Named function: function foo() {}
53
+ const nameNode = current.childForFieldName?.('name') ||
54
+ current.children?.find((c) => c.type === 'identifier' || c.type === 'property_identifier');
55
+ funcName = nameNode?.text;
56
+ }
57
+ else if (current.type === 'impl_item') {
58
+ // Rust method inside impl block: wrapper around function_item or const_item
59
+ // We need to look inside for the function_item
60
+ const funcItem = current.children?.find((c) => c.type === 'function_item');
61
+ if (funcItem) {
62
+ const nameNode = funcItem.childForFieldName?.('name') ||
63
+ funcItem.children?.find((c) => c.type === 'identifier');
64
+ funcName = nameNode?.text;
65
+ label = 'Method';
66
+ }
67
+ }
68
+ else if (current.type === 'method_definition') {
69
+ // Method: foo() {} inside class (JS/TS)
70
+ const nameNode = current.childForFieldName?.('name') ||
71
+ current.children?.find((c) => c.type === 'property_identifier');
72
+ funcName = nameNode?.text;
73
+ label = 'Method';
74
+ }
75
+ else if (current.type === 'method_declaration') {
76
+ // Java method: public void foo() {}
77
+ const nameNode = current.childForFieldName?.('name') ||
78
+ current.children?.find((c) => c.type === 'identifier');
79
+ funcName = nameNode?.text;
80
+ label = 'Method';
81
+ }
82
+ else if (current.type === 'constructor_declaration') {
83
+ // Java constructor: public ClassName() {}
84
+ const nameNode = current.childForFieldName?.('name') ||
85
+ current.children?.find((c) => c.type === 'identifier');
86
+ funcName = nameNode?.text;
87
+ label = 'Method'; // Treat constructors as methods for process detection
88
+ }
89
+ else if (current.type === 'arrow_function' || current.type === 'function_expression') {
90
+ // Arrow/expression: const foo = () => {} - check parent variable declarator
91
+ const parent = current.parent;
92
+ if (parent?.type === 'variable_declarator') {
93
+ const nameNode = parent.childForFieldName?.('name') ||
94
+ parent.children?.find((c) => c.type === 'identifier');
95
+ funcName = nameNode?.text;
96
+ }
97
+ }
98
+ if (funcName) {
99
+ // Look up the function in symbol table to get its node ID
100
+ // Try exact match first
101
+ const nodeId = symbolTable.lookupExact(filePath, funcName);
102
+ if (nodeId)
103
+ return nodeId;
104
+ // Try construct ID manually if lookup fails (common for non-exported internal functions)
105
+ // Format should match what parsing-processor generates: "Function:path/to/file:funcName"
106
+ // Check if we already have a node with this ID in the symbol table to be safe
107
+ const generatedId = generateId(label, `${filePath}:${funcName}`);
108
+ // Ideally we should verify this ID exists, but strictly speaking if we are inside it,
109
+ // it SHOULD exist. Returning it is better than falling back to File.
110
+ return generatedId;
111
+ }
112
+ // Couldn't determine function name - try parent (might be nested)
113
+ }
114
+ current = current.parent;
115
+ }
116
+ return null; // Top-level call (not inside any function)
117
+ };
118
+ export const processCalls = async (graph, files, astCache, symbolTable, importMap, onProgress) => {
119
+ const parser = await loadParser();
120
+ for (let i = 0; i < files.length; i++) {
121
+ const file = files[i];
122
+ onProgress?.(i + 1, files.length);
123
+ if (i % 20 === 0)
124
+ await yieldToEventLoop();
125
+ // 1. Check language support first
126
+ const language = getLanguageFromFilename(file.path);
127
+ if (!language)
128
+ continue;
129
+ const queryStr = LANGUAGE_QUERIES[language];
130
+ if (!queryStr)
131
+ continue;
132
+ // 2. ALWAYS load the language before querying (parser is stateful)
133
+ await loadLanguage(language, file.path);
134
+ // 3. Get AST (Try Cache First)
135
+ let tree = astCache.get(file.path);
136
+ let wasReparsed = false;
137
+ if (!tree) {
138
+ // Cache Miss: Re-parse
139
+ // Use larger bufferSize for files > 32KB
140
+ try {
141
+ tree = parser.parse(file.content, undefined, { bufferSize: 1024 * 256 });
142
+ }
143
+ catch (parseError) {
144
+ // Skip files that can't be parsed
145
+ continue;
146
+ }
147
+ wasReparsed = true;
148
+ }
149
+ let query;
150
+ let matches;
151
+ try {
152
+ const language = parser.getLanguage();
153
+ query = new Parser.Query(language, queryStr);
154
+ matches = query.matches(tree.rootNode);
155
+ }
156
+ catch (queryError) {
157
+ console.warn(`Query error for ${file.path}:`, queryError);
158
+ if (wasReparsed)
159
+ tree.delete?.();
160
+ continue;
161
+ }
162
+ // 3. Process each call match
163
+ matches.forEach(match => {
164
+ const captureMap = {};
165
+ match.captures.forEach(c => captureMap[c.name] = c.node);
166
+ // Only process @call captures
167
+ if (!captureMap['call'])
168
+ return;
169
+ const nameNode = captureMap['call.name'];
170
+ if (!nameNode)
171
+ return;
172
+ const calledName = nameNode.text;
173
+ // Skip common built-ins and noise
174
+ if (isBuiltInOrNoise(calledName))
175
+ return;
176
+ // 4. Resolve the target using priority strategy (returns confidence)
177
+ const resolved = resolveCallTarget(calledName, file.path, symbolTable, importMap);
178
+ if (!resolved)
179
+ return;
180
+ // 5. Find the enclosing function (caller)
181
+ const callNode = captureMap['call'];
182
+ const enclosingFuncId = findEnclosingFunction(callNode, file.path, symbolTable);
183
+ // Use enclosing function as source, fallback to file for top-level calls
184
+ const sourceId = enclosingFuncId || generateId('File', file.path);
185
+ const relId = generateId('CALLS', `${sourceId}:${calledName}->${resolved.nodeId}`);
186
+ graph.addRelationship({
187
+ id: relId,
188
+ sourceId,
189
+ targetId: resolved.nodeId,
190
+ type: 'CALLS',
191
+ confidence: resolved.confidence,
192
+ reason: resolved.reason,
193
+ });
194
+ });
195
+ // Cleanup if re-parsed
196
+ if (wasReparsed) {
197
+ tree.delete?.();
198
+ }
199
+ }
200
+ };
201
+ /**
202
+ * Resolve a function call to its target node ID using priority strategy:
203
+ * A. Check imported files first (highest confidence)
204
+ * B. Check local file definitions
205
+ * C. Fuzzy global search (lowest confidence)
206
+ *
207
+ * Returns confidence score so agents know what to trust.
208
+ */
209
+ const resolveCallTarget = (calledName, currentFile, symbolTable, importMap) => {
210
+ // Strategy A: Check imported files (HIGH confidence - we know the import chain)
211
+ const importedFiles = importMap.get(currentFile);
212
+ if (importedFiles) {
213
+ for (const importedFile of importedFiles) {
214
+ const nodeId = symbolTable.lookupExact(importedFile, calledName);
215
+ if (nodeId) {
216
+ return { nodeId, confidence: 0.9, reason: 'import-resolved' };
217
+ }
218
+ }
219
+ }
220
+ // Strategy B: Check local file (HIGH confidence - same file definition)
221
+ const localNodeId = symbolTable.lookupExact(currentFile, calledName);
222
+ if (localNodeId) {
223
+ return { nodeId: localNodeId, confidence: 0.85, reason: 'same-file' };
224
+ }
225
+ // Strategy C: Fuzzy global search (LOW confidence - just matching by name)
226
+ const fuzzyMatches = symbolTable.lookupFuzzy(calledName);
227
+ if (fuzzyMatches.length > 0) {
228
+ // Lower confidence if multiple matches exist (more ambiguous)
229
+ const confidence = fuzzyMatches.length === 1 ? 0.5 : 0.3;
230
+ return { nodeId: fuzzyMatches[0].nodeId, confidence, reason: 'fuzzy-global' };
231
+ }
232
+ return null;
233
+ };
234
+ /**
235
+ * Filter out common built-in functions and noise
236
+ * that shouldn't be tracked as calls
237
+ */
238
+ const isBuiltInOrNoise = (name) => {
239
+ const builtIns = new Set([
240
+ // JavaScript/TypeScript built-ins
241
+ 'console', 'log', 'warn', 'error', 'info', 'debug',
242
+ 'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval',
243
+ 'parseInt', 'parseFloat', 'isNaN', 'isFinite',
244
+ 'encodeURI', 'decodeURI', 'encodeURIComponent', 'decodeURIComponent',
245
+ 'JSON', 'parse', 'stringify',
246
+ 'Object', 'Array', 'String', 'Number', 'Boolean', 'Symbol', 'BigInt',
247
+ 'Map', 'Set', 'WeakMap', 'WeakSet',
248
+ 'Promise', 'resolve', 'reject', 'then', 'catch', 'finally',
249
+ 'Math', 'Date', 'RegExp', 'Error',
250
+ 'require', 'import', 'export',
251
+ 'fetch', 'Response', 'Request',
252
+ // React hooks and common functions
253
+ 'useState', 'useEffect', 'useCallback', 'useMemo', 'useRef', 'useContext',
254
+ 'useReducer', 'useLayoutEffect', 'useImperativeHandle', 'useDebugValue',
255
+ 'createElement', 'createContext', 'createRef', 'forwardRef', 'memo', 'lazy',
256
+ // Common array/object methods
257
+ 'map', 'filter', 'reduce', 'forEach', 'find', 'findIndex', 'some', 'every',
258
+ 'includes', 'indexOf', 'slice', 'splice', 'concat', 'join', 'split',
259
+ 'push', 'pop', 'shift', 'unshift', 'sort', 'reverse',
260
+ 'keys', 'values', 'entries', 'assign', 'freeze', 'seal',
261
+ 'hasOwnProperty', 'toString', 'valueOf',
262
+ // Python built-ins
263
+ 'print', 'len', 'range', 'str', 'int', 'float', 'list', 'dict', 'set', 'tuple',
264
+ 'open', 'read', 'write', 'close', 'append', 'extend', 'update',
265
+ 'super', 'type', 'isinstance', 'issubclass', 'getattr', 'setattr', 'hasattr',
266
+ 'enumerate', 'zip', 'sorted', 'reversed', 'min', 'max', 'sum', 'abs',
267
+ ]);
268
+ return builtIns.has(name);
269
+ };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Cluster Enricher
3
+ *
4
+ * LLM-based enrichment for community clusters.
5
+ * Generates semantic names, keywords, and descriptions using an LLM.
6
+ */
7
+ import { CommunityNode } from './community-processor.js';
8
+ export interface ClusterEnrichment {
9
+ name: string;
10
+ keywords: string[];
11
+ description: string;
12
+ }
13
+ export interface EnrichmentResult {
14
+ enrichments: Map<string, ClusterEnrichment>;
15
+ tokensUsed: number;
16
+ }
17
+ export interface LLMClient {
18
+ generate: (prompt: string) => Promise<string>;
19
+ }
20
+ export interface ClusterMemberInfo {
21
+ name: string;
22
+ filePath: string;
23
+ type: string;
24
+ }
25
+ /**
26
+ * Enrich clusters with LLM-generated names, keywords, and descriptions
27
+ *
28
+ * @param communities - Community nodes to enrich
29
+ * @param memberMap - Map of communityId -> member info
30
+ * @param llmClient - LLM client for generation
31
+ * @param onProgress - Progress callback
32
+ */
33
+ export declare const enrichClusters: (communities: CommunityNode[], memberMap: Map<string, ClusterMemberInfo[]>, llmClient: LLMClient, onProgress?: (current: number, total: number) => void) => Promise<EnrichmentResult>;
34
+ /**
35
+ * Enrich multiple clusters in a single LLM call (batch mode)
36
+ * More efficient for token usage but requires larger context window
37
+ */
38
+ export declare const enrichClustersBatch: (communities: CommunityNode[], memberMap: Map<string, ClusterMemberInfo[]>, llmClient: LLMClient, batchSize?: number, onProgress?: (current: number, total: number) => void) => Promise<EnrichmentResult>;