@veewo/gitnexus 1.3.4

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 (231) hide show
  1. package/README.md +234 -0
  2. package/dist/benchmark/agent-context/evaluators.d.ts +9 -0
  3. package/dist/benchmark/agent-context/evaluators.js +196 -0
  4. package/dist/benchmark/agent-context/evaluators.test.d.ts +1 -0
  5. package/dist/benchmark/agent-context/evaluators.test.js +39 -0
  6. package/dist/benchmark/agent-context/io.d.ts +2 -0
  7. package/dist/benchmark/agent-context/io.js +23 -0
  8. package/dist/benchmark/agent-context/io.test.d.ts +1 -0
  9. package/dist/benchmark/agent-context/io.test.js +19 -0
  10. package/dist/benchmark/agent-context/report.d.ts +2 -0
  11. package/dist/benchmark/agent-context/report.js +59 -0
  12. package/dist/benchmark/agent-context/report.test.d.ts +1 -0
  13. package/dist/benchmark/agent-context/report.test.js +85 -0
  14. package/dist/benchmark/agent-context/runner.d.ts +46 -0
  15. package/dist/benchmark/agent-context/runner.js +111 -0
  16. package/dist/benchmark/agent-context/runner.test.d.ts +1 -0
  17. package/dist/benchmark/agent-context/runner.test.js +79 -0
  18. package/dist/benchmark/agent-context/tool-runner.d.ts +7 -0
  19. package/dist/benchmark/agent-context/tool-runner.js +18 -0
  20. package/dist/benchmark/agent-context/tool-runner.test.d.ts +1 -0
  21. package/dist/benchmark/agent-context/tool-runner.test.js +11 -0
  22. package/dist/benchmark/agent-context/types.d.ts +40 -0
  23. package/dist/benchmark/agent-context/types.js +1 -0
  24. package/dist/benchmark/analyze-runner.d.ts +16 -0
  25. package/dist/benchmark/analyze-runner.js +51 -0
  26. package/dist/benchmark/analyze-runner.test.d.ts +1 -0
  27. package/dist/benchmark/analyze-runner.test.js +37 -0
  28. package/dist/benchmark/evaluators.d.ts +6 -0
  29. package/dist/benchmark/evaluators.js +10 -0
  30. package/dist/benchmark/evaluators.test.d.ts +1 -0
  31. package/dist/benchmark/evaluators.test.js +12 -0
  32. package/dist/benchmark/io.d.ts +7 -0
  33. package/dist/benchmark/io.js +25 -0
  34. package/dist/benchmark/io.test.d.ts +1 -0
  35. package/dist/benchmark/io.test.js +35 -0
  36. package/dist/benchmark/neonspark-candidates.d.ts +19 -0
  37. package/dist/benchmark/neonspark-candidates.js +94 -0
  38. package/dist/benchmark/neonspark-candidates.test.d.ts +1 -0
  39. package/dist/benchmark/neonspark-candidates.test.js +43 -0
  40. package/dist/benchmark/neonspark-materialize.d.ts +19 -0
  41. package/dist/benchmark/neonspark-materialize.js +111 -0
  42. package/dist/benchmark/neonspark-materialize.test.d.ts +1 -0
  43. package/dist/benchmark/neonspark-materialize.test.js +124 -0
  44. package/dist/benchmark/neonspark-sync.d.ts +3 -0
  45. package/dist/benchmark/neonspark-sync.js +53 -0
  46. package/dist/benchmark/neonspark-sync.test.d.ts +1 -0
  47. package/dist/benchmark/neonspark-sync.test.js +20 -0
  48. package/dist/benchmark/report.d.ts +1 -0
  49. package/dist/benchmark/report.js +7 -0
  50. package/dist/benchmark/runner.d.ts +48 -0
  51. package/dist/benchmark/runner.js +302 -0
  52. package/dist/benchmark/runner.test.d.ts +1 -0
  53. package/dist/benchmark/runner.test.js +50 -0
  54. package/dist/benchmark/scoring.d.ts +16 -0
  55. package/dist/benchmark/scoring.js +27 -0
  56. package/dist/benchmark/scoring.test.d.ts +1 -0
  57. package/dist/benchmark/scoring.test.js +24 -0
  58. package/dist/benchmark/tool-runner.d.ts +6 -0
  59. package/dist/benchmark/tool-runner.js +17 -0
  60. package/dist/benchmark/types.d.ts +36 -0
  61. package/dist/benchmark/types.js +1 -0
  62. package/dist/cli/ai-context.d.ts +22 -0
  63. package/dist/cli/ai-context.js +184 -0
  64. package/dist/cli/ai-context.test.d.ts +1 -0
  65. package/dist/cli/ai-context.test.js +30 -0
  66. package/dist/cli/analyze-multi-scope-regression.test.d.ts +1 -0
  67. package/dist/cli/analyze-multi-scope-regression.test.js +22 -0
  68. package/dist/cli/analyze-options.d.ts +7 -0
  69. package/dist/cli/analyze-options.js +56 -0
  70. package/dist/cli/analyze-options.test.d.ts +1 -0
  71. package/dist/cli/analyze-options.test.js +36 -0
  72. package/dist/cli/analyze.d.ts +14 -0
  73. package/dist/cli/analyze.js +384 -0
  74. package/dist/cli/augment.d.ts +13 -0
  75. package/dist/cli/augment.js +33 -0
  76. package/dist/cli/benchmark-agent-context.d.ts +29 -0
  77. package/dist/cli/benchmark-agent-context.js +61 -0
  78. package/dist/cli/benchmark-agent-context.test.d.ts +1 -0
  79. package/dist/cli/benchmark-agent-context.test.js +80 -0
  80. package/dist/cli/benchmark-unity.d.ts +15 -0
  81. package/dist/cli/benchmark-unity.js +31 -0
  82. package/dist/cli/benchmark-unity.test.d.ts +1 -0
  83. package/dist/cli/benchmark-unity.test.js +18 -0
  84. package/dist/cli/claude-hooks.d.ts +22 -0
  85. package/dist/cli/claude-hooks.js +97 -0
  86. package/dist/cli/clean.d.ts +10 -0
  87. package/dist/cli/clean.js +60 -0
  88. package/dist/cli/eval-server.d.ts +30 -0
  89. package/dist/cli/eval-server.js +372 -0
  90. package/dist/cli/index.d.ts +2 -0
  91. package/dist/cli/index.js +182 -0
  92. package/dist/cli/list.d.ts +6 -0
  93. package/dist/cli/list.js +33 -0
  94. package/dist/cli/mcp.d.ts +8 -0
  95. package/dist/cli/mcp.js +34 -0
  96. package/dist/cli/repo-manager-alias.test.d.ts +1 -0
  97. package/dist/cli/repo-manager-alias.test.js +40 -0
  98. package/dist/cli/scope-filter.test.d.ts +1 -0
  99. package/dist/cli/scope-filter.test.js +49 -0
  100. package/dist/cli/serve.d.ts +4 -0
  101. package/dist/cli/serve.js +6 -0
  102. package/dist/cli/setup.d.ts +8 -0
  103. package/dist/cli/setup.js +311 -0
  104. package/dist/cli/setup.test.d.ts +1 -0
  105. package/dist/cli/setup.test.js +31 -0
  106. package/dist/cli/status.d.ts +6 -0
  107. package/dist/cli/status.js +27 -0
  108. package/dist/cli/tool.d.ts +40 -0
  109. package/dist/cli/tool.js +94 -0
  110. package/dist/cli/version.test.d.ts +1 -0
  111. package/dist/cli/version.test.js +19 -0
  112. package/dist/cli/wiki.d.ts +15 -0
  113. package/dist/cli/wiki.js +361 -0
  114. package/dist/config/ignore-service.d.ts +1 -0
  115. package/dist/config/ignore-service.js +210 -0
  116. package/dist/config/supported-languages.d.ts +12 -0
  117. package/dist/config/supported-languages.js +15 -0
  118. package/dist/core/augmentation/engine.d.ts +26 -0
  119. package/dist/core/augmentation/engine.js +213 -0
  120. package/dist/core/embeddings/embedder.d.ts +60 -0
  121. package/dist/core/embeddings/embedder.js +251 -0
  122. package/dist/core/embeddings/embedding-pipeline.d.ts +51 -0
  123. package/dist/core/embeddings/embedding-pipeline.js +329 -0
  124. package/dist/core/embeddings/index.d.ts +9 -0
  125. package/dist/core/embeddings/index.js +9 -0
  126. package/dist/core/embeddings/text-generator.d.ts +24 -0
  127. package/dist/core/embeddings/text-generator.js +182 -0
  128. package/dist/core/embeddings/types.d.ts +87 -0
  129. package/dist/core/embeddings/types.js +32 -0
  130. package/dist/core/graph/graph.d.ts +2 -0
  131. package/dist/core/graph/graph.js +66 -0
  132. package/dist/core/graph/types.d.ts +61 -0
  133. package/dist/core/graph/types.js +1 -0
  134. package/dist/core/ingestion/ast-cache.d.ts +11 -0
  135. package/dist/core/ingestion/ast-cache.js +34 -0
  136. package/dist/core/ingestion/call-processor.d.ts +15 -0
  137. package/dist/core/ingestion/call-processor.js +327 -0
  138. package/dist/core/ingestion/cluster-enricher.d.ts +38 -0
  139. package/dist/core/ingestion/cluster-enricher.js +170 -0
  140. package/dist/core/ingestion/community-processor.d.ts +39 -0
  141. package/dist/core/ingestion/community-processor.js +312 -0
  142. package/dist/core/ingestion/entry-point-scoring.d.ts +39 -0
  143. package/dist/core/ingestion/entry-point-scoring.js +260 -0
  144. package/dist/core/ingestion/filesystem-walker.d.ts +28 -0
  145. package/dist/core/ingestion/filesystem-walker.js +80 -0
  146. package/dist/core/ingestion/framework-detection.d.ts +39 -0
  147. package/dist/core/ingestion/framework-detection.js +235 -0
  148. package/dist/core/ingestion/heritage-processor.d.ts +20 -0
  149. package/dist/core/ingestion/heritage-processor.js +197 -0
  150. package/dist/core/ingestion/import-processor.d.ts +38 -0
  151. package/dist/core/ingestion/import-processor.js +778 -0
  152. package/dist/core/ingestion/parsing-processor.d.ts +15 -0
  153. package/dist/core/ingestion/parsing-processor.js +291 -0
  154. package/dist/core/ingestion/pipeline.d.ts +5 -0
  155. package/dist/core/ingestion/pipeline.js +323 -0
  156. package/dist/core/ingestion/process-processor.d.ts +51 -0
  157. package/dist/core/ingestion/process-processor.js +309 -0
  158. package/dist/core/ingestion/scope-filter.d.ts +25 -0
  159. package/dist/core/ingestion/scope-filter.js +100 -0
  160. package/dist/core/ingestion/structure-processor.d.ts +2 -0
  161. package/dist/core/ingestion/structure-processor.js +36 -0
  162. package/dist/core/ingestion/symbol-table.d.ts +33 -0
  163. package/dist/core/ingestion/symbol-table.js +38 -0
  164. package/dist/core/ingestion/tree-sitter-queries.d.ts +12 -0
  165. package/dist/core/ingestion/tree-sitter-queries.js +398 -0
  166. package/dist/core/ingestion/utils.d.ts +10 -0
  167. package/dist/core/ingestion/utils.js +50 -0
  168. package/dist/core/ingestion/workers/parse-worker.d.ts +59 -0
  169. package/dist/core/ingestion/workers/parse-worker.js +672 -0
  170. package/dist/core/ingestion/workers/worker-pool.d.ts +16 -0
  171. package/dist/core/ingestion/workers/worker-pool.js +120 -0
  172. package/dist/core/kuzu/csv-generator.d.ts +29 -0
  173. package/dist/core/kuzu/csv-generator.js +336 -0
  174. package/dist/core/kuzu/kuzu-adapter.d.ts +101 -0
  175. package/dist/core/kuzu/kuzu-adapter.js +753 -0
  176. package/dist/core/kuzu/schema.d.ts +53 -0
  177. package/dist/core/kuzu/schema.js +407 -0
  178. package/dist/core/search/bm25-index.d.ts +23 -0
  179. package/dist/core/search/bm25-index.js +95 -0
  180. package/dist/core/search/hybrid-search.d.ts +49 -0
  181. package/dist/core/search/hybrid-search.js +118 -0
  182. package/dist/core/tree-sitter/parser-loader.d.ts +4 -0
  183. package/dist/core/tree-sitter/parser-loader.js +44 -0
  184. package/dist/core/wiki/generator.d.ts +110 -0
  185. package/dist/core/wiki/generator.js +786 -0
  186. package/dist/core/wiki/graph-queries.d.ts +80 -0
  187. package/dist/core/wiki/graph-queries.js +238 -0
  188. package/dist/core/wiki/html-viewer.d.ts +10 -0
  189. package/dist/core/wiki/html-viewer.js +297 -0
  190. package/dist/core/wiki/llm-client.d.ts +40 -0
  191. package/dist/core/wiki/llm-client.js +162 -0
  192. package/dist/core/wiki/prompts.d.ts +53 -0
  193. package/dist/core/wiki/prompts.js +174 -0
  194. package/dist/lib/utils.d.ts +1 -0
  195. package/dist/lib/utils.js +3 -0
  196. package/dist/mcp/core/embedder.d.ts +27 -0
  197. package/dist/mcp/core/embedder.js +108 -0
  198. package/dist/mcp/core/kuzu-adapter.d.ts +34 -0
  199. package/dist/mcp/core/kuzu-adapter.js +231 -0
  200. package/dist/mcp/local/local-backend.d.ts +160 -0
  201. package/dist/mcp/local/local-backend.js +1646 -0
  202. package/dist/mcp/resources.d.ts +31 -0
  203. package/dist/mcp/resources.js +407 -0
  204. package/dist/mcp/server.d.ts +23 -0
  205. package/dist/mcp/server.js +251 -0
  206. package/dist/mcp/staleness.d.ts +15 -0
  207. package/dist/mcp/staleness.js +29 -0
  208. package/dist/mcp/tools.d.ts +24 -0
  209. package/dist/mcp/tools.js +195 -0
  210. package/dist/server/api.d.ts +10 -0
  211. package/dist/server/api.js +344 -0
  212. package/dist/server/mcp-http.d.ts +13 -0
  213. package/dist/server/mcp-http.js +100 -0
  214. package/dist/storage/git.d.ts +6 -0
  215. package/dist/storage/git.js +32 -0
  216. package/dist/storage/repo-manager.d.ts +125 -0
  217. package/dist/storage/repo-manager.js +257 -0
  218. package/dist/types/pipeline.d.ts +34 -0
  219. package/dist/types/pipeline.js +18 -0
  220. package/hooks/claude/gitnexus-hook.cjs +135 -0
  221. package/hooks/claude/pre-tool-use.sh +78 -0
  222. package/hooks/claude/session-start.sh +42 -0
  223. package/package.json +92 -0
  224. package/skills/gitnexus-cli.md +82 -0
  225. package/skills/gitnexus-debugging.md +89 -0
  226. package/skills/gitnexus-exploring.md +78 -0
  227. package/skills/gitnexus-guide.md +64 -0
  228. package/skills/gitnexus-impact-analysis.md +97 -0
  229. package/skills/gitnexus-refactoring.md +121 -0
  230. package/vendor/leiden/index.cjs +355 -0
  231. package/vendor/leiden/utils.cjs +392 -0
@@ -0,0 +1,66 @@
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
+ iterNodes: () => nodeMap.values(),
50
+ iterRelationships: () => relationshipMap.values(),
51
+ forEachNode(fn) { nodeMap.forEach(fn); },
52
+ forEachRelationship(fn) { relationshipMap.forEach(fn); },
53
+ getNode: (id) => nodeMap.get(id),
54
+ // O(1) count getters - avoid creating arrays just for length
55
+ get nodeCount() {
56
+ return nodeMap.size;
57
+ },
58
+ get relationshipCount() {
59
+ return relationshipMap.size;
60
+ },
61
+ addNode,
62
+ addRelationship,
63
+ removeNode,
64
+ removeNodesByFile,
65
+ };
66
+ };
@@ -0,0 +1,61 @@
1
+ export type NodeLabel = 'Project' | 'Package' | 'Module' | 'Folder' | 'File' | 'Class' | 'Function' | 'Method' | 'Variable' | 'Interface' | 'Enum' | 'Decorator' | 'Import' | 'Type' | 'CodeElement' | 'Community' | 'Process' | 'Struct' | 'Macro' | 'Typedef' | 'Union' | 'Namespace' | 'Trait' | 'Impl' | 'TypeAlias' | 'Const' | 'Static' | 'Property' | 'Record' | 'Delegate' | 'Annotation' | 'Constructor' | 'Template';
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
+ /** Returns a full array copy — prefer iterNodes() for iteration */
43
+ nodes: GraphNode[];
44
+ /** Returns a full array copy — prefer iterRelationships() for iteration */
45
+ relationships: GraphRelationship[];
46
+ /** Zero-copy iterator over nodes */
47
+ iterNodes: () => IterableIterator<GraphNode>;
48
+ /** Zero-copy iterator over relationships */
49
+ iterRelationships: () => IterableIterator<GraphRelationship>;
50
+ /** Zero-copy forEach — avoids iterator protocol overhead in hot loops */
51
+ forEachNode: (fn: (node: GraphNode) => void) => void;
52
+ forEachRelationship: (fn: (rel: GraphRelationship) => void) => void;
53
+ /** Lookup a single node by id — O(1) */
54
+ getNode: (id: string) => GraphNode | undefined;
55
+ nodeCount: number;
56
+ relationshipCount: number;
57
+ addNode: (node: GraphNode) => void;
58
+ addRelationship: (relationship: GraphRelationship) => void;
59
+ removeNode: (nodeId: string) => boolean;
60
+ removeNodesByFile: (filePath: string) => number;
61
+ }
@@ -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,15 @@
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
+ import type { ExtractedCall } from './workers/parse-worker.js';
6
+ export declare const processCalls: (graph: KnowledgeGraph, files: {
7
+ path: string;
8
+ content: string;
9
+ }[], astCache: ASTCache, symbolTable: SymbolTable, importMap: ImportMap, onProgress?: (current: number, total: number) => void) => Promise<void>;
10
+ /**
11
+ * Fast path: resolve pre-extracted call sites from workers.
12
+ * No AST parsing — workers already extracted calledName + sourceId.
13
+ * This function only does symbol table lookups + graph mutations.
14
+ */
15
+ export declare const processCallsFromExtracted: (graph: KnowledgeGraph, extractedCalls: ExtractedCall[], symbolTable: SymbolTable, importMap: ImportMap, onProgress?: (current: number, total: number) => void) => Promise<void>;
@@ -0,0 +1,327 @@
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
+ // Cache re-parsed tree so heritage phase gets hits
149
+ astCache.set(file.path, tree);
150
+ }
151
+ let query;
152
+ let matches;
153
+ try {
154
+ const language = parser.getLanguage();
155
+ query = new Parser.Query(language, queryStr);
156
+ matches = query.matches(tree.rootNode);
157
+ }
158
+ catch (queryError) {
159
+ console.warn(`Query error for ${file.path}:`, queryError);
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
+ // Tree is now owned by the LRU cache — no manual delete needed
196
+ }
197
+ };
198
+ /**
199
+ * Resolve a function call to its target node ID using priority strategy:
200
+ * A. Check imported files first (highest confidence)
201
+ * B. Check local file definitions
202
+ * C. Fuzzy global search (lowest confidence)
203
+ *
204
+ * Returns confidence score so agents know what to trust.
205
+ */
206
+ const resolveCallTarget = (calledName, currentFile, symbolTable, importMap) => {
207
+ // Strategy B first (cheapest — single map lookup): Check local file
208
+ const localNodeId = symbolTable.lookupExact(currentFile, calledName);
209
+ if (localNodeId) {
210
+ return { nodeId: localNodeId, confidence: 0.85, reason: 'same-file' };
211
+ }
212
+ // Strategy A: Check if any definition of calledName is in an imported file
213
+ // Reversed: instead of iterating all imports and checking each, get all definitions
214
+ // and check if any is imported. O(definitions) instead of O(imports).
215
+ const allDefs = symbolTable.lookupFuzzy(calledName);
216
+ if (allDefs.length > 0) {
217
+ const importedFiles = importMap.get(currentFile);
218
+ if (importedFiles) {
219
+ for (const def of allDefs) {
220
+ if (importedFiles.has(def.filePath)) {
221
+ return { nodeId: def.nodeId, confidence: 0.9, reason: 'import-resolved' };
222
+ }
223
+ }
224
+ }
225
+ // Strategy C: Fuzzy global (no import match found)
226
+ const confidence = allDefs.length === 1 ? 0.5 : 0.3;
227
+ return { nodeId: allDefs[0].nodeId, confidence, reason: 'fuzzy-global' };
228
+ }
229
+ return null;
230
+ };
231
+ /**
232
+ * Filter out common built-in functions and noise
233
+ * that shouldn't be tracked as calls
234
+ */
235
+ /** Pre-built set (module-level singleton) to avoid re-creating per call */
236
+ const BUILT_IN_NAMES = new Set([
237
+ // JavaScript/TypeScript built-ins
238
+ 'console', 'log', 'warn', 'error', 'info', 'debug',
239
+ 'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval',
240
+ 'parseInt', 'parseFloat', 'isNaN', 'isFinite',
241
+ 'encodeURI', 'decodeURI', 'encodeURIComponent', 'decodeURIComponent',
242
+ 'JSON', 'parse', 'stringify',
243
+ 'Object', 'Array', 'String', 'Number', 'Boolean', 'Symbol', 'BigInt',
244
+ 'Map', 'Set', 'WeakMap', 'WeakSet',
245
+ 'Promise', 'resolve', 'reject', 'then', 'catch', 'finally',
246
+ 'Math', 'Date', 'RegExp', 'Error',
247
+ 'require', 'import', 'export',
248
+ 'fetch', 'Response', 'Request',
249
+ // React hooks and common functions
250
+ 'useState', 'useEffect', 'useCallback', 'useMemo', 'useRef', 'useContext',
251
+ 'useReducer', 'useLayoutEffect', 'useImperativeHandle', 'useDebugValue',
252
+ 'createElement', 'createContext', 'createRef', 'forwardRef', 'memo', 'lazy',
253
+ // Common array/object methods
254
+ 'map', 'filter', 'reduce', 'forEach', 'find', 'findIndex', 'some', 'every',
255
+ 'includes', 'indexOf', 'slice', 'splice', 'concat', 'join', 'split',
256
+ 'push', 'pop', 'shift', 'unshift', 'sort', 'reverse',
257
+ 'keys', 'values', 'entries', 'assign', 'freeze', 'seal',
258
+ 'hasOwnProperty', 'toString', 'valueOf',
259
+ // Python built-ins
260
+ 'print', 'len', 'range', 'str', 'int', 'float', 'list', 'dict', 'set', 'tuple',
261
+ 'open', 'read', 'write', 'close', 'append', 'extend', 'update',
262
+ 'super', 'type', 'isinstance', 'issubclass', 'getattr', 'setattr', 'hasattr',
263
+ 'enumerate', 'zip', 'sorted', 'reversed', 'min', 'max', 'sum', 'abs',
264
+ // C/C++ standard library and common kernel helpers
265
+ 'printf', 'fprintf', 'sprintf', 'snprintf', 'vprintf', 'vfprintf', 'vsprintf', 'vsnprintf',
266
+ 'scanf', 'fscanf', 'sscanf',
267
+ 'malloc', 'calloc', 'realloc', 'free', 'memcpy', 'memmove', 'memset', 'memcmp',
268
+ 'strlen', 'strcpy', 'strncpy', 'strcat', 'strncat', 'strcmp', 'strncmp', 'strstr', 'strchr', 'strrchr',
269
+ 'atoi', 'atol', 'atof', 'strtol', 'strtoul', 'strtoll', 'strtoull', 'strtod',
270
+ 'sizeof', 'offsetof', 'typeof',
271
+ 'assert', 'abort', 'exit', '_exit',
272
+ 'fopen', 'fclose', 'fread', 'fwrite', 'fseek', 'ftell', 'rewind', 'fflush', 'fgets', 'fputs',
273
+ // Linux kernel common macros/helpers (not real call targets)
274
+ 'likely', 'unlikely', 'BUG', 'BUG_ON', 'WARN', 'WARN_ON', 'WARN_ONCE',
275
+ 'IS_ERR', 'PTR_ERR', 'ERR_PTR', 'IS_ERR_OR_NULL',
276
+ 'ARRAY_SIZE', 'container_of', 'list_for_each_entry', 'list_for_each_entry_safe',
277
+ 'min', 'max', 'clamp', 'abs', 'swap',
278
+ 'pr_info', 'pr_warn', 'pr_err', 'pr_debug', 'pr_notice', 'pr_crit', 'pr_emerg',
279
+ 'printk', 'dev_info', 'dev_warn', 'dev_err', 'dev_dbg',
280
+ 'GFP_KERNEL', 'GFP_ATOMIC',
281
+ 'spin_lock', 'spin_unlock', 'spin_lock_irqsave', 'spin_unlock_irqrestore',
282
+ 'mutex_lock', 'mutex_unlock', 'mutex_init',
283
+ 'kfree', 'kmalloc', 'kzalloc', 'kcalloc', 'krealloc', 'kvmalloc', 'kvfree',
284
+ 'get', 'put',
285
+ ]);
286
+ const isBuiltInOrNoise = (name) => BUILT_IN_NAMES.has(name);
287
+ /**
288
+ * Fast path: resolve pre-extracted call sites from workers.
289
+ * No AST parsing — workers already extracted calledName + sourceId.
290
+ * This function only does symbol table lookups + graph mutations.
291
+ */
292
+ export const processCallsFromExtracted = async (graph, extractedCalls, symbolTable, importMap, onProgress) => {
293
+ // Group by file for progress reporting
294
+ const byFile = new Map();
295
+ for (const call of extractedCalls) {
296
+ let list = byFile.get(call.filePath);
297
+ if (!list) {
298
+ list = [];
299
+ byFile.set(call.filePath, list);
300
+ }
301
+ list.push(call);
302
+ }
303
+ const totalFiles = byFile.size;
304
+ let filesProcessed = 0;
305
+ for (const [_filePath, calls] of byFile) {
306
+ filesProcessed++;
307
+ if (filesProcessed % 100 === 0) {
308
+ onProgress?.(filesProcessed, totalFiles);
309
+ await yieldToEventLoop();
310
+ }
311
+ for (const call of calls) {
312
+ const resolved = resolveCallTarget(call.calledName, call.filePath, symbolTable, importMap);
313
+ if (!resolved)
314
+ continue;
315
+ const relId = generateId('CALLS', `${call.sourceId}:${call.calledName}->${resolved.nodeId}`);
316
+ graph.addRelationship({
317
+ id: relId,
318
+ sourceId: call.sourceId,
319
+ targetId: resolved.nodeId,
320
+ type: 'CALLS',
321
+ confidence: resolved.confidence,
322
+ reason: resolved.reason,
323
+ });
324
+ }
325
+ }
326
+ onProgress?.(totalFiles, totalFiles);
327
+ };
@@ -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>;