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,235 @@
1
+ /**
2
+ * Entry Point Scoring
3
+ *
4
+ * Calculates entry point scores for process detection based on:
5
+ * 1. Call ratio (existing algorithm - callees / (callers + 1))
6
+ * 2. Export status (exported functions get higher priority)
7
+ * 3. Name patterns (functions matching entry point patterns like handle*, on*, *Controller)
8
+ * 4. Framework detection (path-based detection for Next.js, Express, Django, etc.)
9
+ *
10
+ * This module is language-agnostic - language-specific patterns are defined per language.
11
+ */
12
+ import { detectFrameworkFromPath } from './framework-detection.js';
13
+ // ============================================================================
14
+ // NAME PATTERNS - All 9 supported languages
15
+ // ============================================================================
16
+ /**
17
+ * Common entry point naming patterns by language
18
+ * These patterns indicate functions that are likely feature entry points
19
+ */
20
+ const ENTRY_POINT_PATTERNS = {
21
+ // Universal patterns (apply to all languages)
22
+ '*': [
23
+ /^(main|init|bootstrap|start|run|setup|configure)$/i,
24
+ /^handle[A-Z]/, // handleLogin, handleSubmit
25
+ /^on[A-Z]/, // onClick, onSubmit
26
+ /Handler$/, // RequestHandler
27
+ /Controller$/, // UserController
28
+ /^process[A-Z]/, // processPayment
29
+ /^execute[A-Z]/, // executeQuery
30
+ /^perform[A-Z]/, // performAction
31
+ /^dispatch[A-Z]/, // dispatchEvent
32
+ /^trigger[A-Z]/, // triggerAction
33
+ /^fire[A-Z]/, // fireEvent
34
+ /^emit[A-Z]/, // emitEvent
35
+ ],
36
+ // JavaScript/TypeScript
37
+ 'javascript': [
38
+ /^use[A-Z]/, // React hooks (useEffect, etc.)
39
+ ],
40
+ 'typescript': [
41
+ /^use[A-Z]/, // React hooks
42
+ ],
43
+ // Python
44
+ 'python': [
45
+ /^app$/, // Flask/FastAPI app
46
+ /^(get|post|put|delete|patch)_/i, // REST conventions
47
+ /^api_/, // API functions
48
+ /^view_/, // Django views
49
+ ],
50
+ // Java
51
+ 'java': [
52
+ /^do[A-Z]/, // doGet, doPost (Servlets)
53
+ /^create[A-Z]/, // Factory patterns
54
+ /^build[A-Z]/, // Builder patterns
55
+ /Service$/, // UserService
56
+ ],
57
+ // C#
58
+ 'csharp': [
59
+ /^(Get|Post|Put|Delete)/, // ASP.NET conventions
60
+ /Action$/, // MVC actions
61
+ /^On[A-Z]/, // Event handlers
62
+ /Async$/, // Async entry points
63
+ ],
64
+ // Go
65
+ 'go': [
66
+ /Handler$/, // http.Handler pattern
67
+ /^Serve/, // ServeHTTP
68
+ /^New[A-Z]/, // Constructor pattern (returns new instance)
69
+ /^Make[A-Z]/, // Make functions
70
+ ],
71
+ // Rust
72
+ 'rust': [
73
+ /^(get|post|put|delete)_handler$/i,
74
+ /^handle_/, // handle_request
75
+ /^new$/, // Constructor pattern
76
+ /^run$/, // run entry point
77
+ /^spawn/, // Async spawn
78
+ ],
79
+ // C - explicit main() boost (critical for C programs)
80
+ 'c': [
81
+ /^main$/, // THE entry point
82
+ /^init_/, // Initialization functions
83
+ /^start_/, // Start functions
84
+ /^run_/, // Run functions
85
+ ],
86
+ // C++ - same as C plus class patterns
87
+ 'cpp': [
88
+ /^main$/, // THE entry point
89
+ /^init_/,
90
+ /^Create[A-Z]/, // Factory patterns
91
+ /^Run$/, // Run methods
92
+ /^Start$/, // Start methods
93
+ ],
94
+ };
95
+ // ============================================================================
96
+ // UTILITY PATTERNS - Functions that should be penalized
97
+ // ============================================================================
98
+ /**
99
+ * Patterns that indicate utility/helper functions (NOT entry points)
100
+ * These get penalized in scoring
101
+ */
102
+ const UTILITY_PATTERNS = [
103
+ /^(get|set|is|has|can|should|will|did)[A-Z]/, // Accessors/predicates
104
+ /^_/, // Private by convention
105
+ /^(format|parse|validate|convert|transform)/i, // Transformation utilities
106
+ /^(log|debug|error|warn|info)$/i, // Logging
107
+ /^(to|from)[A-Z]/, // Conversions
108
+ /^(encode|decode)/i, // Encoding utilities
109
+ /^(serialize|deserialize)/i, // Serialization
110
+ /^(clone|copy|deep)/i, // Cloning utilities
111
+ /^(merge|extend|assign)/i, // Object utilities
112
+ /^(filter|map|reduce|sort|find)/i, // Collection utilities (standalone)
113
+ /Helper$/,
114
+ /Util$/,
115
+ /Utils$/,
116
+ /^utils?$/i,
117
+ /^helpers?$/i,
118
+ ];
119
+ // ============================================================================
120
+ // MAIN SCORING FUNCTION
121
+ // ============================================================================
122
+ /**
123
+ * Calculate an entry point score for a function/method
124
+ *
125
+ * Higher scores indicate better entry point candidates.
126
+ * Score = baseScore × exportMultiplier × nameMultiplier
127
+ *
128
+ * @param name - Function/method name
129
+ * @param language - Programming language
130
+ * @param isExported - Whether the function is exported/public
131
+ * @param callerCount - Number of functions that call this function
132
+ * @param calleeCount - Number of functions this function calls
133
+ * @returns Score and array of reasons explaining the score
134
+ */
135
+ export function calculateEntryPointScore(name, language, isExported, callerCount, calleeCount, filePath = '' // Optional for backwards compatibility
136
+ ) {
137
+ const reasons = [];
138
+ // Must have outgoing calls to be an entry point (we need to trace forward)
139
+ if (calleeCount === 0) {
140
+ return { score: 0, reasons: ['no-outgoing-calls'] };
141
+ }
142
+ // Base score: call ratio (existing algorithm)
143
+ // High ratio = calls many, called by few = likely entry point
144
+ const baseScore = calleeCount / (callerCount + 1);
145
+ reasons.push(`base:${baseScore.toFixed(2)}`);
146
+ // Export bonus: exported/public functions are more likely entry points
147
+ const exportMultiplier = isExported ? 2.0 : 1.0;
148
+ if (isExported) {
149
+ reasons.push('exported');
150
+ }
151
+ // Name pattern scoring
152
+ let nameMultiplier = 1.0;
153
+ // Check negative patterns first (utilities get penalized)
154
+ if (UTILITY_PATTERNS.some(p => p.test(name))) {
155
+ nameMultiplier = 0.3; // Significant penalty
156
+ reasons.push('utility-pattern');
157
+ }
158
+ else {
159
+ // Check positive patterns
160
+ const universalPatterns = ENTRY_POINT_PATTERNS['*'] || [];
161
+ const langPatterns = ENTRY_POINT_PATTERNS[language] || [];
162
+ const allPatterns = [...universalPatterns, ...langPatterns];
163
+ if (allPatterns.some(p => p.test(name))) {
164
+ nameMultiplier = 1.5; // Bonus for matching entry point pattern
165
+ reasons.push('entry-pattern');
166
+ }
167
+ }
168
+ // Framework detection bonus (Phase 2)
169
+ let frameworkMultiplier = 1.0;
170
+ if (filePath) {
171
+ const frameworkHint = detectFrameworkFromPath(filePath);
172
+ if (frameworkHint) {
173
+ frameworkMultiplier = frameworkHint.entryPointMultiplier;
174
+ reasons.push(`framework:${frameworkHint.reason}`);
175
+ }
176
+ }
177
+ // Calculate final score
178
+ const finalScore = baseScore * exportMultiplier * nameMultiplier * frameworkMultiplier;
179
+ return {
180
+ score: finalScore,
181
+ reasons,
182
+ };
183
+ }
184
+ // ============================================================================
185
+ // HELPER FUNCTIONS
186
+ // ============================================================================
187
+ /**
188
+ * Check if a file path is a test file (should be excluded from entry points)
189
+ * Covers common test file patterns across all supported languages
190
+ */
191
+ export function isTestFile(filePath) {
192
+ const p = filePath.toLowerCase().replace(/\\/g, '/');
193
+ return (
194
+ // JavaScript/TypeScript test patterns
195
+ p.includes('.test.') ||
196
+ p.includes('.spec.') ||
197
+ p.includes('__tests__/') ||
198
+ p.includes('__mocks__/') ||
199
+ // Generic test folders
200
+ p.includes('/test/') ||
201
+ p.includes('/tests/') ||
202
+ p.includes('/testing/') ||
203
+ // Python test patterns
204
+ p.endsWith('_test.py') ||
205
+ p.includes('/test_') ||
206
+ // Go test patterns
207
+ p.endsWith('_test.go') ||
208
+ // Java test patterns
209
+ p.includes('/src/test/') ||
210
+ // Rust test patterns (inline tests are different, but test files)
211
+ p.includes('/tests/') ||
212
+ // C# test patterns
213
+ p.includes('.tests/') ||
214
+ p.includes('tests.cs'));
215
+ }
216
+ /**
217
+ * Check if a file path is likely a utility/helper file
218
+ * These might still have entry points but should be lower priority
219
+ */
220
+ export function isUtilityFile(filePath) {
221
+ const p = filePath.toLowerCase().replace(/\\/g, '/');
222
+ return (p.includes('/utils/') ||
223
+ p.includes('/util/') ||
224
+ p.includes('/helpers/') ||
225
+ p.includes('/helper/') ||
226
+ p.includes('/common/') ||
227
+ p.includes('/shared/') ||
228
+ p.includes('/lib/') ||
229
+ p.endsWith('/utils.ts') ||
230
+ p.endsWith('/utils.js') ||
231
+ p.endsWith('/helpers.ts') ||
232
+ p.endsWith('/helpers.js') ||
233
+ p.endsWith('_utils.py') ||
234
+ p.endsWith('_helpers.py'));
235
+ }
@@ -0,0 +1,5 @@
1
+ export interface FileEntry {
2
+ path: string;
3
+ content: string;
4
+ }
5
+ export declare const walkRepository: (repoPath: string, onProgress?: (current: number, total: number, filePath: string) => void) => Promise<FileEntry[]>;
@@ -0,0 +1,26 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import { glob } from 'glob';
4
+ import { shouldIgnorePath } from '../../config/ignore-service.js';
5
+ export const walkRepository = async (repoPath, onProgress) => {
6
+ const files = await glob('**/*', {
7
+ cwd: repoPath,
8
+ nodir: true,
9
+ dot: false,
10
+ });
11
+ const filtered = files.filter(file => !shouldIgnorePath(file));
12
+ const entries = [];
13
+ for (let i = 0; i < filtered.length; i++) {
14
+ const relativePath = filtered[i];
15
+ const fullPath = path.join(repoPath, relativePath);
16
+ try {
17
+ const content = await fs.readFile(fullPath, 'utf-8');
18
+ entries.push({ path: relativePath.replace(/\\/g, '/'), content });
19
+ onProgress?.(i + 1, filtered.length, relativePath);
20
+ }
21
+ catch {
22
+ onProgress?.(i + 1, filtered.length, relativePath);
23
+ }
24
+ }
25
+ return entries;
26
+ };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Framework Detection
3
+ *
4
+ * Detects frameworks from file path patterns and provides entry point multipliers.
5
+ * This enables framework-aware entry point scoring.
6
+ *
7
+ * DESIGN: Returns null for unknown frameworks, which causes a 1.0 multiplier
8
+ * (no bonus, no penalty) - same behavior as before this feature.
9
+ */
10
+ export interface FrameworkHint {
11
+ framework: string;
12
+ entryPointMultiplier: number;
13
+ reason: string;
14
+ }
15
+ /**
16
+ * Detect framework from file path patterns
17
+ *
18
+ * This provides entry point multipliers based on well-known framework conventions.
19
+ * Returns null if no framework pattern is detected (falls back to 1.0 multiplier).
20
+ */
21
+ export declare function detectFrameworkFromPath(filePath: string): FrameworkHint | null;
22
+ /**
23
+ * Patterns that indicate entry points within code (for future AST-based detection)
24
+ * These would require parsing decorators/annotations in the code itself.
25
+ */
26
+ export declare const FRAMEWORK_AST_PATTERNS: {
27
+ nestjs: string[];
28
+ express: string[];
29
+ fastapi: string[];
30
+ flask: string[];
31
+ spring: string[];
32
+ jaxrs: string[];
33
+ aspnet: string[];
34
+ 'go-http': string[];
35
+ actix: string[];
36
+ axum: string[];
37
+ rocket: string[];
38
+ };
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Framework Detection
3
+ *
4
+ * Detects frameworks from file path patterns and provides entry point multipliers.
5
+ * This enables framework-aware entry point scoring.
6
+ *
7
+ * DESIGN: Returns null for unknown frameworks, which causes a 1.0 multiplier
8
+ * (no bonus, no penalty) - same behavior as before this feature.
9
+ */
10
+ // ============================================================================
11
+ // PATH-BASED FRAMEWORK DETECTION
12
+ // ============================================================================
13
+ /**
14
+ * Detect framework from file path patterns
15
+ *
16
+ * This provides entry point multipliers based on well-known framework conventions.
17
+ * Returns null if no framework pattern is detected (falls back to 1.0 multiplier).
18
+ */
19
+ export function detectFrameworkFromPath(filePath) {
20
+ // Normalize path separators and ensure leading slash for consistent matching
21
+ let p = filePath.toLowerCase().replace(/\\/g, '/');
22
+ if (!p.startsWith('/')) {
23
+ p = '/' + p; // Add leading slash so patterns like '/app/' match 'app/...'
24
+ }
25
+ // ========== JAVASCRIPT / TYPESCRIPT FRAMEWORKS ==========
26
+ // Next.js - Pages Router (high confidence)
27
+ if (p.includes('/pages/') && !p.includes('/_') && !p.includes('/api/')) {
28
+ if (p.endsWith('.tsx') || p.endsWith('.ts') || p.endsWith('.jsx') || p.endsWith('.js')) {
29
+ return { framework: 'nextjs-pages', entryPointMultiplier: 3.0, reason: 'nextjs-page' };
30
+ }
31
+ }
32
+ // Next.js - App Router (page.tsx files)
33
+ if (p.includes('/app/') && (p.endsWith('page.tsx') || p.endsWith('page.ts') ||
34
+ p.endsWith('page.jsx') || p.endsWith('page.js'))) {
35
+ return { framework: 'nextjs-app', entryPointMultiplier: 3.0, reason: 'nextjs-app-page' };
36
+ }
37
+ // Next.js - API Routes
38
+ if (p.includes('/pages/api/') || (p.includes('/app/') && p.includes('/api/') && p.endsWith('route.ts'))) {
39
+ return { framework: 'nextjs-api', entryPointMultiplier: 3.0, reason: 'nextjs-api-route' };
40
+ }
41
+ // Next.js - Layout files (moderate - they're entry-ish but not the main entry)
42
+ if (p.includes('/app/') && (p.endsWith('layout.tsx') || p.endsWith('layout.ts'))) {
43
+ return { framework: 'nextjs-app', entryPointMultiplier: 2.0, reason: 'nextjs-layout' };
44
+ }
45
+ // Express / Node.js routes
46
+ if (p.includes('/routes/') && (p.endsWith('.ts') || p.endsWith('.js'))) {
47
+ return { framework: 'express', entryPointMultiplier: 2.5, reason: 'routes-folder' };
48
+ }
49
+ // Generic controllers (MVC pattern)
50
+ if (p.includes('/controllers/') && (p.endsWith('.ts') || p.endsWith('.js'))) {
51
+ return { framework: 'mvc', entryPointMultiplier: 2.5, reason: 'controllers-folder' };
52
+ }
53
+ // Generic handlers
54
+ if (p.includes('/handlers/') && (p.endsWith('.ts') || p.endsWith('.js'))) {
55
+ return { framework: 'handlers', entryPointMultiplier: 2.5, reason: 'handlers-folder' };
56
+ }
57
+ // React components (lower priority - not all are entry points)
58
+ if ((p.includes('/components/') || p.includes('/views/')) &&
59
+ (p.endsWith('.tsx') || p.endsWith('.jsx'))) {
60
+ // Only boost if PascalCase filename (likely a component, not util)
61
+ const fileName = p.split('/').pop() || '';
62
+ if (/^[A-Z]/.test(fileName)) {
63
+ return { framework: 'react', entryPointMultiplier: 1.5, reason: 'react-component' };
64
+ }
65
+ }
66
+ // ========== PYTHON FRAMEWORKS ==========
67
+ // Django views (high confidence)
68
+ if (p.endsWith('views.py')) {
69
+ return { framework: 'django', entryPointMultiplier: 3.0, reason: 'django-views' };
70
+ }
71
+ // Django URL configs
72
+ if (p.endsWith('urls.py')) {
73
+ return { framework: 'django', entryPointMultiplier: 2.0, reason: 'django-urls' };
74
+ }
75
+ // FastAPI / Flask routers
76
+ if ((p.includes('/routers/') || p.includes('/endpoints/') || p.includes('/routes/')) &&
77
+ p.endsWith('.py')) {
78
+ return { framework: 'fastapi', entryPointMultiplier: 2.5, reason: 'api-routers' };
79
+ }
80
+ // Python API folder
81
+ if (p.includes('/api/') && p.endsWith('.py') && !p.endsWith('__init__.py')) {
82
+ return { framework: 'python-api', entryPointMultiplier: 2.0, reason: 'api-folder' };
83
+ }
84
+ // ========== JAVA FRAMEWORKS ==========
85
+ // Spring Boot controllers
86
+ if ((p.includes('/controller/') || p.includes('/controllers/')) && p.endsWith('.java')) {
87
+ return { framework: 'spring', entryPointMultiplier: 3.0, reason: 'spring-controller' };
88
+ }
89
+ // Spring Boot - files ending in Controller.java
90
+ if (p.endsWith('controller.java')) {
91
+ return { framework: 'spring', entryPointMultiplier: 3.0, reason: 'spring-controller-file' };
92
+ }
93
+ // Java service layer (often entry points for business logic)
94
+ if ((p.includes('/service/') || p.includes('/services/')) && p.endsWith('.java')) {
95
+ return { framework: 'java-service', entryPointMultiplier: 1.8, reason: 'java-service' };
96
+ }
97
+ // ========== C# / .NET FRAMEWORKS ==========
98
+ // ASP.NET Controllers
99
+ if (p.includes('/controllers/') && p.endsWith('.cs')) {
100
+ return { framework: 'aspnet', entryPointMultiplier: 3.0, reason: 'aspnet-controller' };
101
+ }
102
+ // ASP.NET - files ending in Controller.cs
103
+ if (p.endsWith('controller.cs')) {
104
+ return { framework: 'aspnet', entryPointMultiplier: 3.0, reason: 'aspnet-controller-file' };
105
+ }
106
+ // Blazor pages
107
+ if (p.includes('/pages/') && p.endsWith('.razor')) {
108
+ return { framework: 'blazor', entryPointMultiplier: 2.5, reason: 'blazor-page' };
109
+ }
110
+ // ========== GO FRAMEWORKS ==========
111
+ // Go handlers
112
+ if ((p.includes('/handlers/') || p.includes('/handler/')) && p.endsWith('.go')) {
113
+ return { framework: 'go-http', entryPointMultiplier: 2.5, reason: 'go-handlers' };
114
+ }
115
+ // Go routes
116
+ if (p.includes('/routes/') && p.endsWith('.go')) {
117
+ return { framework: 'go-http', entryPointMultiplier: 2.5, reason: 'go-routes' };
118
+ }
119
+ // Go controllers
120
+ if (p.includes('/controllers/') && p.endsWith('.go')) {
121
+ return { framework: 'go-mvc', entryPointMultiplier: 2.5, reason: 'go-controller' };
122
+ }
123
+ // Go main.go files (THE entry point)
124
+ if (p.endsWith('/main.go') || p.endsWith('/cmd/') && p.endsWith('.go')) {
125
+ return { framework: 'go', entryPointMultiplier: 3.0, reason: 'go-main' };
126
+ }
127
+ // ========== RUST FRAMEWORKS ==========
128
+ // Rust handlers/routes
129
+ if ((p.includes('/handlers/') || p.includes('/routes/')) && p.endsWith('.rs')) {
130
+ return { framework: 'rust-web', entryPointMultiplier: 2.5, reason: 'rust-handlers' };
131
+ }
132
+ // Rust main.rs (THE entry point)
133
+ if (p.endsWith('/main.rs')) {
134
+ return { framework: 'rust', entryPointMultiplier: 3.0, reason: 'rust-main' };
135
+ }
136
+ // Rust bin folder (executables)
137
+ if (p.includes('/bin/') && p.endsWith('.rs')) {
138
+ return { framework: 'rust', entryPointMultiplier: 2.5, reason: 'rust-bin' };
139
+ }
140
+ // ========== C / C++ ==========
141
+ // C/C++ main files
142
+ if (p.endsWith('/main.c') || p.endsWith('/main.cpp') || p.endsWith('/main.cc')) {
143
+ return { framework: 'c-cpp', entryPointMultiplier: 3.0, reason: 'c-main' };
144
+ }
145
+ // C/C++ src folder entry points (if named specifically)
146
+ if ((p.includes('/src/') && (p.endsWith('/app.c') || p.endsWith('/app.cpp')))) {
147
+ return { framework: 'c-cpp', entryPointMultiplier: 2.5, reason: 'c-app' };
148
+ }
149
+ // ========== GENERIC PATTERNS ==========
150
+ // Any language: index files in API folders
151
+ if (p.includes('/api/') && (p.endsWith('/index.ts') || p.endsWith('/index.js') ||
152
+ p.endsWith('/__init__.py'))) {
153
+ return { framework: 'api', entryPointMultiplier: 1.8, reason: 'api-index' };
154
+ }
155
+ // No framework detected - return null for graceful fallback (1.0 multiplier)
156
+ return null;
157
+ }
158
+ // ============================================================================
159
+ // FUTURE: AST-BASED PATTERNS (for Phase 3)
160
+ // ============================================================================
161
+ /**
162
+ * Patterns that indicate entry points within code (for future AST-based detection)
163
+ * These would require parsing decorators/annotations in the code itself.
164
+ */
165
+ export const FRAMEWORK_AST_PATTERNS = {
166
+ // JavaScript/TypeScript decorators
167
+ 'nestjs': ['@Controller', '@Get', '@Post', '@Put', '@Delete', '@Patch'],
168
+ 'express': ['app.get', 'app.post', 'app.put', 'app.delete', 'router.get', 'router.post'],
169
+ // Python decorators
170
+ 'fastapi': ['@app.get', '@app.post', '@app.put', '@app.delete', '@router.get'],
171
+ 'flask': ['@app.route', '@blueprint.route'],
172
+ // Java annotations
173
+ 'spring': ['@RestController', '@Controller', '@GetMapping', '@PostMapping', '@RequestMapping'],
174
+ 'jaxrs': ['@Path', '@GET', '@POST', '@PUT', '@DELETE'],
175
+ // C# attributes
176
+ 'aspnet': ['[ApiController]', '[HttpGet]', '[HttpPost]', '[Route]'],
177
+ // Go patterns (function signatures)
178
+ 'go-http': ['http.Handler', 'http.HandlerFunc', 'ServeHTTP'],
179
+ // Rust macros
180
+ 'actix': ['#[get', '#[post', '#[put', '#[delete'],
181
+ 'axum': ['Router::new'],
182
+ 'rocket': ['#[get', '#[post'],
183
+ };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Heritage Processor
3
+ *
4
+ * Extracts class inheritance relationships:
5
+ * - EXTENDS: Class extends another Class (TS, JS, Python)
6
+ * - IMPLEMENTS: Class implements an Interface (TS only)
7
+ */
8
+ import { KnowledgeGraph } from '../graph/types.js';
9
+ import { ASTCache } from './ast-cache.js';
10
+ import { SymbolTable } from './symbol-table.js';
11
+ export declare const processHeritage: (graph: KnowledgeGraph, files: {
12
+ path: string;
13
+ content: string;
14
+ }[], astCache: ASTCache, symbolTable: SymbolTable, onProgress?: (current: number, total: number) => void) => Promise<void>;
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Heritage Processor
3
+ *
4
+ * Extracts class inheritance relationships:
5
+ * - EXTENDS: Class extends another Class (TS, JS, Python)
6
+ * - IMPLEMENTS: Class implements an Interface (TS only)
7
+ */
8
+ import Parser from 'tree-sitter';
9
+ import { loadParser, loadLanguage } from '../tree-sitter/parser-loader.js';
10
+ import { LANGUAGE_QUERIES } from './tree-sitter-queries.js';
11
+ import { generateId } from '../../lib/utils.js';
12
+ import { getLanguageFromFilename, yieldToEventLoop } from './utils.js';
13
+ export const processHeritage = async (graph, files, astCache, symbolTable, onProgress) => {
14
+ const parser = await loadParser();
15
+ for (let i = 0; i < files.length; i++) {
16
+ const file = files[i];
17
+ onProgress?.(i + 1, files.length);
18
+ if (i % 20 === 0)
19
+ await yieldToEventLoop();
20
+ // 1. Check language support
21
+ const language = getLanguageFromFilename(file.path);
22
+ if (!language)
23
+ continue;
24
+ const queryStr = LANGUAGE_QUERIES[language];
25
+ if (!queryStr)
26
+ continue;
27
+ // 2. Load the language
28
+ await loadLanguage(language, file.path);
29
+ // 3. Get AST
30
+ let tree = astCache.get(file.path);
31
+ let wasReparsed = false;
32
+ if (!tree) {
33
+ // Use larger bufferSize for files > 32KB
34
+ try {
35
+ tree = parser.parse(file.content, undefined, { bufferSize: 1024 * 256 });
36
+ }
37
+ catch (parseError) {
38
+ // Skip files that can't be parsed
39
+ continue;
40
+ }
41
+ wasReparsed = true;
42
+ }
43
+ let query;
44
+ let matches;
45
+ try {
46
+ const language = parser.getLanguage();
47
+ query = new Parser.Query(language, queryStr);
48
+ matches = query.matches(tree.rootNode);
49
+ }
50
+ catch (queryError) {
51
+ console.warn(`Heritage query error for ${file.path}:`, queryError);
52
+ if (wasReparsed)
53
+ tree.delete?.();
54
+ continue;
55
+ }
56
+ // 4. Process heritage matches
57
+ matches.forEach(match => {
58
+ const captureMap = {};
59
+ match.captures.forEach(c => {
60
+ captureMap[c.name] = c.node;
61
+ });
62
+ // EXTENDS: Class extends another Class
63
+ if (captureMap['heritage.class'] && captureMap['heritage.extends']) {
64
+ const className = captureMap['heritage.class'].text;
65
+ 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}`);
72
+ if (childId && parentId && childId !== parentId) {
73
+ const relId = generateId('EXTENDS', `${childId}->${parentId}`);
74
+ graph.addRelationship({
75
+ id: relId,
76
+ sourceId: childId,
77
+ targetId: parentId,
78
+ type: 'EXTENDS',
79
+ confidence: 1.0,
80
+ reason: '',
81
+ });
82
+ }
83
+ }
84
+ // IMPLEMENTS: Class implements Interface (TypeScript only)
85
+ if (captureMap['heritage.class'] && captureMap['heritage.implements']) {
86
+ const className = captureMap['heritage.class'].text;
87
+ 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}`);
94
+ if (classId && interfaceId) {
95
+ const relId = generateId('IMPLEMENTS', `${classId}->${interfaceId}`);
96
+ graph.addRelationship({
97
+ id: relId,
98
+ sourceId: classId,
99
+ targetId: interfaceId,
100
+ type: 'IMPLEMENTS',
101
+ confidence: 1.0,
102
+ reason: '',
103
+ });
104
+ }
105
+ }
106
+ // IMPLEMENTS (Rust): impl Trait for Struct
107
+ if (captureMap['heritage.trait'] && captureMap['heritage.class']) {
108
+ const structName = captureMap['heritage.class'].text;
109
+ 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}`);
116
+ if (structId && traitId) {
117
+ const relId = generateId('IMPLEMENTS', `${structId}->${traitId}`);
118
+ graph.addRelationship({
119
+ id: relId,
120
+ sourceId: structId,
121
+ targetId: traitId,
122
+ type: 'IMPLEMENTS',
123
+ confidence: 1.0,
124
+ reason: 'trait-impl',
125
+ });
126
+ }
127
+ }
128
+ });
129
+ // Cleanup
130
+ if (wasReparsed) {
131
+ tree.delete?.();
132
+ }
133
+ }
134
+ };
@@ -0,0 +1,8 @@
1
+ import { KnowledgeGraph } from '../graph/types.js';
2
+ import { ASTCache } from './ast-cache.js';
3
+ export type ImportMap = Map<string, Set<string>>;
4
+ export declare const createImportMap: () => ImportMap;
5
+ export declare const processImports: (graph: KnowledgeGraph, files: {
6
+ path: string;
7
+ content: string;
8
+ }[], astCache: ASTCache, importMap: ImportMap, onProgress?: (current: number, total: number) => void, repoRoot?: string) => Promise<void>;