code-auditor-mcp 1.20.0 → 2.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 (180) hide show
  1. package/dist/adapters/GoAdapter.d.ts +53 -0
  2. package/dist/adapters/GoAdapter.d.ts.map +1 -0
  3. package/dist/adapters/GoAdapter.js +602 -0
  4. package/dist/adapters/GoAdapter.js.map +1 -0
  5. package/dist/adapters/GoConfig.d.ts +35 -0
  6. package/dist/adapters/GoConfig.d.ts.map +1 -0
  7. package/dist/adapters/GoConfig.js +155 -0
  8. package/dist/adapters/GoConfig.js.map +1 -0
  9. package/dist/adapters/LanguageAdapter.d.ts +135 -0
  10. package/dist/adapters/LanguageAdapter.d.ts.map +1 -0
  11. package/dist/adapters/LanguageAdapter.js +47 -0
  12. package/dist/adapters/LanguageAdapter.js.map +1 -0
  13. package/dist/adapters/TypeScriptAdapter.d.ts +43 -0
  14. package/dist/adapters/TypeScriptAdapter.d.ts.map +1 -0
  15. package/dist/adapters/TypeScriptAdapter.js +386 -0
  16. package/dist/adapters/TypeScriptAdapter.js.map +1 -0
  17. package/dist/adapters/UniversalAnalyzer.d.ts +42 -0
  18. package/dist/adapters/UniversalAnalyzer.d.ts.map +1 -0
  19. package/dist/adapters/UniversalAnalyzer.js +103 -0
  20. package/dist/adapters/UniversalAnalyzer.js.map +1 -0
  21. package/dist/adapters/UniversalSOLIDAnalyzer.d.ts +48 -0
  22. package/dist/adapters/UniversalSOLIDAnalyzer.d.ts.map +1 -0
  23. package/dist/adapters/UniversalSOLIDAnalyzer.js +178 -0
  24. package/dist/adapters/UniversalSOLIDAnalyzer.js.map +1 -0
  25. package/dist/adapters/solidAnalyzerCompat.d.ts +21 -0
  26. package/dist/adapters/solidAnalyzerCompat.d.ts.map +1 -0
  27. package/dist/adapters/solidAnalyzerCompat.js +78 -0
  28. package/dist/adapters/solidAnalyzerCompat.js.map +1 -0
  29. package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts +103 -0
  30. package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts.map +1 -0
  31. package/dist/analyzers/cross-language/APIContractAnalyzer.js +425 -0
  32. package/dist/analyzers/cross-language/APIContractAnalyzer.js.map +1 -0
  33. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.d.ts +117 -0
  34. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.d.ts.map +1 -0
  35. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.js +618 -0
  36. package/dist/analyzers/cross-language/CrossLanguageSOLIDAnalyzer.js.map +1 -0
  37. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts +129 -0
  38. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -0
  39. package/dist/analyzers/cross-language/DependencyGraphBuilder.js +473 -0
  40. package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -0
  41. package/dist/analyzers/cross-language/SchemaValidator.d.ts +126 -0
  42. package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -0
  43. package/dist/analyzers/cross-language/SchemaValidator.js +522 -0
  44. package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -0
  45. package/dist/analyzers/dataAccessAnalyzerCompat.d.ts +20 -0
  46. package/dist/analyzers/dataAccessAnalyzerCompat.d.ts.map +1 -0
  47. package/dist/analyzers/dataAccessAnalyzerCompat.js +59 -0
  48. package/dist/analyzers/dataAccessAnalyzerCompat.js.map +1 -0
  49. package/dist/analyzers/documentationAnalyzerCompat.d.ts +20 -0
  50. package/dist/analyzers/documentationAnalyzerCompat.d.ts.map +1 -0
  51. package/dist/analyzers/documentationAnalyzerCompat.js +52 -0
  52. package/dist/analyzers/documentationAnalyzerCompat.js.map +1 -0
  53. package/dist/analyzers/dryAnalyzerCompat.d.ts +20 -0
  54. package/dist/analyzers/dryAnalyzerCompat.d.ts.map +1 -0
  55. package/dist/analyzers/dryAnalyzerCompat.js +44 -0
  56. package/dist/analyzers/dryAnalyzerCompat.js.map +1 -0
  57. package/dist/analyzers/schemaAnalyzer.d.ts +21 -0
  58. package/dist/analyzers/schemaAnalyzer.d.ts.map +1 -0
  59. package/dist/analyzers/schemaAnalyzer.js +405 -0
  60. package/dist/analyzers/schemaAnalyzer.js.map +1 -0
  61. package/dist/analyzers/schemaAnalyzerCompat.d.ts +20 -0
  62. package/dist/analyzers/schemaAnalyzerCompat.d.ts.map +1 -0
  63. package/dist/analyzers/schemaAnalyzerCompat.js +69 -0
  64. package/dist/analyzers/schemaAnalyzerCompat.js.map +1 -0
  65. package/dist/analyzers/solidAnalyzerCompat.d.ts +20 -0
  66. package/dist/analyzers/solidAnalyzerCompat.d.ts.map +1 -0
  67. package/dist/analyzers/solidAnalyzerCompat.js +78 -0
  68. package/dist/analyzers/solidAnalyzerCompat.js.map +1 -0
  69. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +71 -0
  70. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -0
  71. package/dist/analyzers/universal/UniversalDRYAnalyzer.js +276 -0
  72. package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -0
  73. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts +82 -0
  74. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -0
  75. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +489 -0
  76. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -0
  77. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts +48 -0
  78. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -0
  79. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +175 -0
  80. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -0
  81. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts +64 -0
  82. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -0
  83. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +286 -0
  84. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -0
  85. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts +119 -0
  86. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -0
  87. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +812 -0
  88. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -0
  89. package/dist/auditRunner.d.ts.map +1 -1
  90. package/dist/auditRunner.js +23 -7
  91. package/dist/auditRunner.js.map +1 -1
  92. package/dist/codeIndexDB-enhanced.d.ts +80 -0
  93. package/dist/codeIndexDB-enhanced.d.ts.map +1 -0
  94. package/dist/codeIndexDB-enhanced.js +488 -0
  95. package/dist/codeIndexDB-enhanced.js.map +1 -0
  96. package/dist/codeIndexDb.d.ts +70 -1
  97. package/dist/codeIndexDb.d.ts.map +1 -1
  98. package/dist/codeIndexDb.js +199 -2
  99. package/dist/codeIndexDb.js.map +1 -1
  100. package/dist/config/defaults.js +1 -1
  101. package/dist/config/defaults.js.map +1 -1
  102. package/dist/languages/LanguageOrchestrator.d.ts +181 -0
  103. package/dist/languages/LanguageOrchestrator.d.ts.map +1 -0
  104. package/dist/languages/LanguageOrchestrator.js +365 -0
  105. package/dist/languages/LanguageOrchestrator.js.map +1 -0
  106. package/dist/languages/LanguageRegistry.d.ts +43 -0
  107. package/dist/languages/LanguageRegistry.d.ts.map +1 -0
  108. package/dist/languages/LanguageRegistry.js +86 -0
  109. package/dist/languages/LanguageRegistry.js.map +1 -0
  110. package/dist/languages/RuntimeManager.d.ts +181 -0
  111. package/dist/languages/RuntimeManager.d.ts.map +1 -0
  112. package/dist/languages/RuntimeManager.js +841 -0
  113. package/dist/languages/RuntimeManager.js.map +1 -0
  114. package/dist/languages/UniversalAnalyzer.d.ts +37 -0
  115. package/dist/languages/UniversalAnalyzer.d.ts.map +1 -0
  116. package/dist/languages/UniversalAnalyzer.js +101 -0
  117. package/dist/languages/UniversalAnalyzer.js.map +1 -0
  118. package/dist/languages/go/GoAdapter.d.ts +57 -0
  119. package/dist/languages/go/GoAdapter.d.ts.map +1 -0
  120. package/dist/languages/go/GoAdapter.js +360 -0
  121. package/dist/languages/go/GoAdapter.js.map +1 -0
  122. package/dist/languages/index.d.ts +13 -0
  123. package/dist/languages/index.d.ts.map +1 -0
  124. package/dist/languages/index.js +23 -0
  125. package/dist/languages/index.js.map +1 -0
  126. package/dist/languages/types.d.ts +182 -0
  127. package/dist/languages/types.d.ts.map +1 -0
  128. package/dist/languages/types.js +5 -0
  129. package/dist/languages/types.js.map +1 -0
  130. package/dist/languages/typescript/TypeScriptAdapter.d.ts +108 -0
  131. package/dist/languages/typescript/TypeScriptAdapter.d.ts.map +1 -0
  132. package/dist/languages/typescript/TypeScriptAdapter.js +567 -0
  133. package/dist/languages/typescript/TypeScriptAdapter.js.map +1 -0
  134. package/dist/languages/typescript/test-extraction.d.ts +2 -0
  135. package/dist/languages/typescript/test-extraction.d.ts.map +1 -0
  136. package/dist/languages/typescript/test-extraction.js +36 -0
  137. package/dist/languages/typescript/test-extraction.js.map +1 -0
  138. package/dist/mcp-hybrid.d.ts +10 -0
  139. package/dist/mcp-hybrid.d.ts.map +1 -0
  140. package/dist/mcp-hybrid.js +41 -0
  141. package/dist/mcp-hybrid.js.map +1 -0
  142. package/dist/mcp-index.d.ts +11 -0
  143. package/dist/mcp-index.d.ts.map +1 -0
  144. package/dist/mcp-index.js +101 -0
  145. package/dist/mcp-index.js.map +1 -0
  146. package/dist/mcp-tools/workflowGuide.d.ts.map +1 -1
  147. package/dist/mcp-tools/workflowGuide.js +67 -10
  148. package/dist/mcp-tools/workflowGuide.js.map +1 -1
  149. package/dist/mcp-tools-shared.d.ts +49 -0
  150. package/dist/mcp-tools-shared.d.ts.map +1 -0
  151. package/dist/mcp-tools-shared.js +1282 -0
  152. package/dist/mcp-tools-shared.js.map +1 -0
  153. package/dist/mcp-ui-server.d.ts +27 -0
  154. package/dist/mcp-ui-server.d.ts.map +1 -0
  155. package/dist/mcp-ui-server.js +484 -0
  156. package/dist/mcp-ui-server.js.map +1 -0
  157. package/dist/mcp-ui-simple.d.ts +27 -0
  158. package/dist/mcp-ui-simple.d.ts.map +1 -0
  159. package/dist/mcp-ui-simple.js +425 -0
  160. package/dist/mcp-ui-simple.js.map +1 -0
  161. package/dist/mcp.js +7 -4
  162. package/dist/mcp.js.map +1 -1
  163. package/dist/services/SchemaParser.d.ts +89 -0
  164. package/dist/services/SchemaParser.d.ts.map +1 -0
  165. package/dist/services/SchemaParser.js +434 -0
  166. package/dist/services/SchemaParser.js.map +1 -0
  167. package/dist/types/crossLanguage.d.ts +267 -0
  168. package/dist/types/crossLanguage.d.ts.map +1 -0
  169. package/dist/types/crossLanguage.js +6 -0
  170. package/dist/types/crossLanguage.js.map +1 -0
  171. package/dist/types.d.ts +128 -0
  172. package/dist/types.d.ts.map +1 -1
  173. package/dist/types.js.map +1 -1
  174. package/dist/utils/fileDiscovery.d.ts +6 -0
  175. package/dist/utils/fileDiscovery.d.ts.map +1 -1
  176. package/dist/utils/fileDiscovery.js +12 -1
  177. package/dist/utils/fileDiscovery.js.map +1 -1
  178. package/examples/schema-example.json +364 -0
  179. package/examples/schema-example.yaml +137 -0
  180. package/package.json +10 -3
@@ -0,0 +1,841 @@
1
+ /**
2
+ * Runtime Manager
3
+ * Detects available language runtimes and manages analyzer processes
4
+ */
5
+ import { exec, spawn } from 'child_process';
6
+ import { promisify } from 'util';
7
+ import * as path from 'path';
8
+ import * as fs from 'fs/promises';
9
+ const execAsync = promisify(exec);
10
+ export class RuntimeManager {
11
+ runtimes = new Map();
12
+ initialized = false;
13
+ config = new Map();
14
+ constructor(config) {
15
+ if (config) {
16
+ for (const [runtime, cfg] of Object.entries(config)) {
17
+ this.config.set(runtime, cfg);
18
+ }
19
+ }
20
+ }
21
+ /**
22
+ * Initialize runtime detection
23
+ */
24
+ async initialize() {
25
+ console.error('[RuntimeManager] Initializing runtime detection...');
26
+ await Promise.all([
27
+ this.detectNodeRuntime(),
28
+ this.detectGoRuntime(),
29
+ this.detectPythonRuntime(),
30
+ this.detectRustRuntime(),
31
+ this.detectDenoRuntime(),
32
+ this.detectBunRuntime()
33
+ ]);
34
+ this.initialized = true;
35
+ console.error('[RuntimeManager] Runtime detection complete');
36
+ this.logRuntimeStatus();
37
+ }
38
+ /**
39
+ * Check if a specific runtime is available
40
+ */
41
+ hasRuntime(name) {
42
+ const runtime = this.runtimes.get(name);
43
+ const config = this.config.get(name);
44
+ return runtime?.available === true &&
45
+ (config?.enabled !== false) &&
46
+ this.checkVersionCompatibility(runtime, config);
47
+ }
48
+ /**
49
+ * Get fallback runtime for a language if the primary is unavailable
50
+ */
51
+ getFallbackRuntime(language) {
52
+ const fallbackMap = {
53
+ 'typescript': ['node', 'deno', 'bun'],
54
+ 'javascript': ['node', 'deno', 'bun'],
55
+ 'go': ['go'],
56
+ 'python': ['python'],
57
+ 'rust': ['rust']
58
+ };
59
+ const fallbacks = fallbackMap[language] || [];
60
+ for (const fallback of fallbacks) {
61
+ if (this.hasRuntime(fallback)) {
62
+ const runtime = this.runtimes.get(fallback);
63
+ if (runtime?.analyzer?.supports.some(ext => this.getLanguageExtensions(language).includes(ext))) {
64
+ return runtime;
65
+ }
66
+ }
67
+ }
68
+ return null;
69
+ }
70
+ /**
71
+ * Get file extensions for a language
72
+ */
73
+ getLanguageExtensions(language) {
74
+ const extensionMap = {
75
+ 'typescript': ['.ts', '.tsx'],
76
+ 'javascript': ['.js', '.jsx'],
77
+ 'go': ['.go'],
78
+ 'python': ['.py'],
79
+ 'rust': ['.rs']
80
+ };
81
+ return extensionMap[language] || [];
82
+ }
83
+ /**
84
+ * Attempt to analyze with fallback runtime if primary fails
85
+ */
86
+ async analyzeWithFallback(language, files, options) {
87
+ // Try primary runtime first
88
+ let result = await this.spawnAnalyzer(language, files, options);
89
+ if (result && result.errors?.length === 0) {
90
+ return result;
91
+ }
92
+ // If primary failed, try fallback
93
+ const fallbackRuntime = this.getFallbackRuntime(language);
94
+ if (fallbackRuntime) {
95
+ console.log(`[RuntimeManager] Primary ${language} runtime failed, trying fallback: ${fallbackRuntime.name}`);
96
+ try {
97
+ const fallbackResult = await fallbackRuntime.analyzer.analyze(files, {
98
+ ...options,
99
+ fallbackMode: true,
100
+ originalLanguage: language
101
+ });
102
+ // Add warning about fallback usage
103
+ fallbackResult.errors = fallbackResult.errors || [];
104
+ fallbackResult.errors.push({
105
+ message: `Analysis completed using fallback runtime ${fallbackRuntime.name} instead of native ${language} runtime`,
106
+ type: 'fallback_warning',
107
+ language
108
+ });
109
+ return fallbackResult;
110
+ }
111
+ catch (fallbackError) {
112
+ console.error(`[RuntimeManager] Fallback runtime also failed:`, fallbackError);
113
+ }
114
+ }
115
+ // No fallback available or fallback also failed
116
+ return {
117
+ violations: [],
118
+ indexEntries: [],
119
+ metrics: { filesAnalyzed: 0, executionTime: 0 },
120
+ errors: [{
121
+ message: `No working runtime available for ${language}. Install ${language} runtime or enable fallback options.`,
122
+ type: 'no_runtime',
123
+ language,
124
+ suggestions: this.getRuntimeInstallationSuggestions(language)
125
+ }]
126
+ };
127
+ }
128
+ /**
129
+ * Get installation suggestions for missing runtimes
130
+ */
131
+ getRuntimeInstallationSuggestions(language) {
132
+ const suggestions = {
133
+ 'go': [
134
+ 'Install Go: https://golang.org/dl/',
135
+ 'Or use package manager: brew install go (macOS), apt install golang (Ubuntu)'
136
+ ],
137
+ 'python': [
138
+ 'Install Python: https://python.org/downloads/',
139
+ 'Or use package manager: brew install python (macOS), apt install python3 (Ubuntu)'
140
+ ],
141
+ 'rust': [
142
+ 'Install Rust: https://rustup.rs/',
143
+ 'Run: curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh'
144
+ ],
145
+ 'node': [
146
+ 'Install Node.js: https://nodejs.org/',
147
+ 'Or use nvm: nvm install node'
148
+ ]
149
+ };
150
+ return suggestions[language] || ['Check the official documentation for installation instructions'];
151
+ }
152
+ /**
153
+ * Get runtime information
154
+ */
155
+ getRuntime(name) {
156
+ return this.runtimes.get(name);
157
+ }
158
+ /**
159
+ * Get all available runtimes
160
+ */
161
+ getAvailableRuntimes() {
162
+ return Array.from(this.runtimes.values()).filter(r => r.available);
163
+ }
164
+ /**
165
+ * Spawn analyzer for a specific language
166
+ */
167
+ async spawnAnalyzer(language, files, options) {
168
+ if (!this.initialized) {
169
+ await this.initialize();
170
+ }
171
+ const runtime = this.runtimes.get(language);
172
+ if (!runtime?.available || !runtime.analyzer) {
173
+ console.warn(`[RuntimeManager] No analyzer available for ${language}`);
174
+ return null;
175
+ }
176
+ console.log(`[RuntimeManager] Spawning ${language} analyzer for ${files.length} files`);
177
+ const startTime = Date.now();
178
+ const processTimeout = options?.timeout || 300000; // 5 minutes default
179
+ try {
180
+ const result = await this.runWithTimeout(() => runtime.analyzer.analyze(files, options), processTimeout);
181
+ const executionTime = Date.now() - startTime;
182
+ result.metrics.executionTime = executionTime;
183
+ console.log(`[RuntimeManager] ${language} analysis complete in ${executionTime}ms: ${result.violations.length} violations`);
184
+ return result;
185
+ }
186
+ catch (error) {
187
+ const executionTime = Date.now() - startTime;
188
+ console.error(`[RuntimeManager] Error in ${language} analyzer after ${executionTime}ms:`, error);
189
+ return {
190
+ violations: [],
191
+ indexEntries: [],
192
+ metrics: { filesAnalyzed: 0, executionTime },
193
+ errors: [{
194
+ message: error instanceof Error ? error.message : String(error),
195
+ language,
196
+ type: error instanceof Error && error.message.includes('timeout') ? 'timeout' : 'runtime_error'
197
+ }]
198
+ };
199
+ }
200
+ }
201
+ /**
202
+ * Run a function with timeout
203
+ */
204
+ async runWithTimeout(fn, timeoutMs) {
205
+ return new Promise((resolve, reject) => {
206
+ const timeoutId = setTimeout(() => {
207
+ reject(new Error(`Analysis timed out after ${timeoutMs}ms`));
208
+ }, timeoutMs);
209
+ fn()
210
+ .then(result => {
211
+ clearTimeout(timeoutId);
212
+ resolve(result);
213
+ })
214
+ .catch(error => {
215
+ clearTimeout(timeoutId);
216
+ reject(error);
217
+ });
218
+ });
219
+ }
220
+ /**
221
+ * Spawn multiple analyzers in parallel with concurrency control
222
+ */
223
+ async spawnMultipleAnalyzers(languageFilePairs, options) {
224
+ const maxConcurrency = options?.maxConcurrency || 3;
225
+ const results = [];
226
+ console.log(`[RuntimeManager] Spawning ${languageFilePairs.length} analyzers with max concurrency ${maxConcurrency}`);
227
+ // Process in batches to control concurrency
228
+ for (let i = 0; i < languageFilePairs.length; i += maxConcurrency) {
229
+ const batch = languageFilePairs.slice(i, i + maxConcurrency);
230
+ const batchPromises = batch.map(async ({ language, files }) => {
231
+ const result = await this.spawnAnalyzer(language, files, options);
232
+ return { language, result };
233
+ });
234
+ const batchResults = await Promise.all(batchPromises);
235
+ results.push(...batchResults);
236
+ }
237
+ return results;
238
+ }
239
+ /**
240
+ * Kill all running analyzer processes (for cleanup)
241
+ */
242
+ async killAllAnalyzers() {
243
+ console.log('[RuntimeManager] Killing all analyzer processes...');
244
+ // This is a placeholder for process management
245
+ // In future implementations, we'll track child processes and kill them here
246
+ // For now, we just log the action since our analyzers run in-process
247
+ console.log('[RuntimeManager] All analyzer processes terminated');
248
+ }
249
+ /**
250
+ * Detect Node.js runtime
251
+ */
252
+ async detectNodeRuntime() {
253
+ try {
254
+ const { stdout } = await execAsync('node --version');
255
+ const version = stdout.trim();
256
+ this.runtimes.set('node', {
257
+ name: 'Node.js',
258
+ command: 'node',
259
+ version,
260
+ available: true,
261
+ minVersion: '16.0.0',
262
+ analyzer: new TypeScriptAnalyzer()
263
+ });
264
+ }
265
+ catch (error) {
266
+ this.runtimes.set('node', {
267
+ name: 'Node.js',
268
+ command: 'node',
269
+ version: 'unknown',
270
+ available: false
271
+ });
272
+ }
273
+ }
274
+ /**
275
+ * Detect Go runtime
276
+ */
277
+ async detectGoRuntime() {
278
+ try {
279
+ console.error('[RuntimeManager] Detecting Go runtime...');
280
+ const { stdout } = await execAsync('go version');
281
+ const versionMatch = stdout.match(/go(\d+\.\d+\.\d+)/);
282
+ const version = versionMatch ? versionMatch[1] : stdout.trim();
283
+ console.error('[RuntimeManager] Go version detected:', version);
284
+ // Check if our Go analyzer exists
285
+ const analyzerPath = path.join(__dirname, 'go', 'analyzer');
286
+ console.error('[RuntimeManager] Looking for Go analyzer at:', analyzerPath);
287
+ const analyzerExists = await this.fileExists(analyzerPath) || await this.fileExists(analyzerPath + '.exe');
288
+ console.error('[RuntimeManager] Go analyzer exists:', analyzerExists);
289
+ this.runtimes.set('go', {
290
+ name: 'Go',
291
+ command: 'go',
292
+ version,
293
+ available: true,
294
+ minVersion: '1.18.0',
295
+ executablePath: analyzerExists ? analyzerPath : undefined,
296
+ analyzer: new GoAnalyzer(analyzerPath)
297
+ });
298
+ console.error('[RuntimeManager] Go runtime configured successfully');
299
+ }
300
+ catch (error) {
301
+ this.runtimes.set('go', {
302
+ name: 'Go',
303
+ command: 'go',
304
+ version: 'unknown',
305
+ available: false
306
+ });
307
+ }
308
+ }
309
+ /**
310
+ * Detect Python runtime
311
+ */
312
+ async detectPythonRuntime() {
313
+ const pythonCommands = ['python3', 'python'];
314
+ for (const cmd of pythonCommands) {
315
+ try {
316
+ const { stdout } = await execAsync(`${cmd} --version`);
317
+ const versionMatch = stdout.match(/Python (\d+\.\d+\.\d+)/);
318
+ const version = versionMatch ? versionMatch[1] : stdout.trim();
319
+ this.runtimes.set('python', {
320
+ name: 'Python',
321
+ command: cmd,
322
+ version,
323
+ available: true,
324
+ minVersion: '3.8.0',
325
+ analyzer: new PythonAnalyzer(cmd)
326
+ });
327
+ return;
328
+ }
329
+ catch (error) {
330
+ // Try next command
331
+ }
332
+ }
333
+ this.runtimes.set('python', {
334
+ name: 'Python',
335
+ command: 'python',
336
+ version: 'unknown',
337
+ available: false
338
+ });
339
+ }
340
+ /**
341
+ * Detect Rust runtime
342
+ */
343
+ async detectRustRuntime() {
344
+ try {
345
+ const { stdout } = await execAsync('rustc --version');
346
+ const versionMatch = stdout.match(/rustc (\d+\.\d+\.\d+)/);
347
+ const version = versionMatch ? versionMatch[1] : stdout.trim();
348
+ this.runtimes.set('rust', {
349
+ name: 'Rust',
350
+ command: 'rustc',
351
+ version,
352
+ available: true,
353
+ minVersion: '1.60.0'
354
+ // Rust analyzer will be implemented in future phases
355
+ });
356
+ }
357
+ catch (error) {
358
+ this.runtimes.set('rust', {
359
+ name: 'Rust',
360
+ command: 'rustc',
361
+ version: 'unknown',
362
+ available: false
363
+ });
364
+ }
365
+ }
366
+ /**
367
+ * Detect Deno runtime
368
+ */
369
+ async detectDenoRuntime() {
370
+ try {
371
+ const { stdout } = await execAsync('deno --version');
372
+ const versionMatch = stdout.match(/deno (\d+\.\d+\.\d+)/);
373
+ const version = versionMatch ? versionMatch[1] : stdout.trim();
374
+ this.runtimes.set('deno', {
375
+ name: 'Deno',
376
+ command: 'deno',
377
+ version,
378
+ available: true,
379
+ minVersion: '1.20.0'
380
+ // Could reuse TypeScript analyzer with Deno-specific adaptations
381
+ });
382
+ }
383
+ catch (error) {
384
+ this.runtimes.set('deno', {
385
+ name: 'Deno',
386
+ command: 'deno',
387
+ version: 'unknown',
388
+ available: false
389
+ });
390
+ }
391
+ }
392
+ /**
393
+ * Detect Bun runtime
394
+ */
395
+ async detectBunRuntime() {
396
+ try {
397
+ const { stdout } = await execAsync('bun --version');
398
+ const version = stdout.trim();
399
+ this.runtimes.set('bun', {
400
+ name: 'Bun',
401
+ command: 'bun',
402
+ version,
403
+ available: true,
404
+ minVersion: '0.5.0'
405
+ // Could reuse TypeScript analyzer with Bun-specific adaptations
406
+ });
407
+ }
408
+ catch (error) {
409
+ this.runtimes.set('bun', {
410
+ name: 'Bun',
411
+ command: 'bun',
412
+ version: 'unknown',
413
+ available: false
414
+ });
415
+ }
416
+ }
417
+ /**
418
+ * Check if a file exists
419
+ */
420
+ async fileExists(filePath) {
421
+ try {
422
+ await fs.access(filePath);
423
+ return true;
424
+ }
425
+ catch {
426
+ return false;
427
+ }
428
+ }
429
+ /**
430
+ * Check version compatibility with detailed reporting
431
+ */
432
+ checkVersionCompatibility(runtime, config) {
433
+ const minVersion = config?.minVersion || runtime.minVersion;
434
+ if (!minVersion || !runtime.version || runtime.version === 'unknown') {
435
+ console.log(`[RuntimeManager] Version compatibility check skipped for ${runtime.name} (version: ${runtime.version})`);
436
+ return true; // If we can't determine version, assume compatible
437
+ }
438
+ const isCompatible = this.compareVersions(runtime.version, minVersion) >= 0;
439
+ if (!isCompatible) {
440
+ console.warn(`[RuntimeManager] ${runtime.name} version ${runtime.version} is below minimum required ${minVersion}`);
441
+ }
442
+ else {
443
+ console.log(`[RuntimeManager] ${runtime.name} version ${runtime.version} meets minimum requirement ${minVersion}`);
444
+ }
445
+ return isCompatible;
446
+ }
447
+ /**
448
+ * Get detailed version compatibility report
449
+ */
450
+ getVersionCompatibilityReport() {
451
+ const report = [];
452
+ for (const [name, runtime] of this.runtimes) {
453
+ const config = this.config.get(name);
454
+ const minVersion = config?.minVersion || runtime.minVersion;
455
+ const compatible = this.checkVersionCompatibility(runtime, config);
456
+ let status;
457
+ let recommendations = [];
458
+ if (!runtime.available) {
459
+ status = 'unknown';
460
+ recommendations.push(`Install ${runtime.name} runtime`);
461
+ recommendations.push(...this.getRuntimeInstallationSuggestions(name));
462
+ }
463
+ else if (runtime.version === 'unknown') {
464
+ status = 'unknown';
465
+ recommendations.push(`Unable to detect ${runtime.name} version`);
466
+ }
467
+ else if (!compatible) {
468
+ status = 'incompatible';
469
+ recommendations.push(`Update ${runtime.name} to version ${minVersion} or higher`);
470
+ recommendations.push(`Current: ${runtime.version}, Required: ${minVersion}`);
471
+ }
472
+ else {
473
+ status = 'compatible';
474
+ }
475
+ report.push({
476
+ runtime: runtime.name,
477
+ currentVersion: runtime.version,
478
+ minVersion,
479
+ compatible: runtime.available && compatible,
480
+ status,
481
+ recommendations: recommendations.length > 0 ? recommendations : undefined
482
+ });
483
+ }
484
+ return report;
485
+ }
486
+ /**
487
+ * Validate all runtime versions and return summary
488
+ */
489
+ async validateRuntimeVersions() {
490
+ if (!this.initialized) {
491
+ await this.initialize();
492
+ }
493
+ const report = this.getVersionCompatibilityReport();
494
+ const summary = {
495
+ compatible: 0,
496
+ incompatible: 0,
497
+ unknown: 0,
498
+ issues: []
499
+ };
500
+ for (const entry of report) {
501
+ switch (entry.status) {
502
+ case 'compatible':
503
+ summary.compatible++;
504
+ break;
505
+ case 'incompatible':
506
+ summary.incompatible++;
507
+ summary.issues.push({
508
+ runtime: entry.runtime,
509
+ issue: `Version ${entry.currentVersion} is below minimum ${entry.minVersion}`,
510
+ recommendations: entry.recommendations || []
511
+ });
512
+ break;
513
+ case 'unknown':
514
+ summary.unknown++;
515
+ summary.issues.push({
516
+ runtime: entry.runtime,
517
+ issue: 'Runtime not available or version unknown',
518
+ recommendations: entry.recommendations || []
519
+ });
520
+ break;
521
+ }
522
+ }
523
+ return summary;
524
+ }
525
+ /**
526
+ * Compare semantic versions with enhanced parsing
527
+ */
528
+ compareVersions(version1, version2) {
529
+ // Handle various version formats: v1.2.3, 1.2.3, go1.19.5, etc.
530
+ const normalizeVersion = (version) => {
531
+ return version
532
+ .replace(/^v/, '') // Remove 'v' prefix
533
+ .replace(/^go/, '') // Remove 'go' prefix
534
+ .replace(/[^\d.]/g, '') // Remove non-digit, non-dot chars
535
+ .split('.')
536
+ .slice(0, 3) // Take only major.minor.patch
537
+ .join('.');
538
+ };
539
+ const v1 = normalizeVersion(version1);
540
+ const v2 = normalizeVersion(version2);
541
+ const v1Parts = v1.split('.').map(Number);
542
+ const v2Parts = v2.split('.').map(Number);
543
+ const maxLength = Math.max(v1Parts.length, v2Parts.length);
544
+ for (let i = 0; i < maxLength; i++) {
545
+ const v1Part = v1Parts[i] || 0;
546
+ const v2Part = v2Parts[i] || 0;
547
+ if (v1Part > v2Part)
548
+ return 1;
549
+ if (v1Part < v2Part)
550
+ return -1;
551
+ }
552
+ return 0;
553
+ }
554
+ /**
555
+ * Log runtime status
556
+ */
557
+ logRuntimeStatus() {
558
+ console.log('\n[RuntimeManager] Runtime Status:');
559
+ for (const [name, runtime] of this.runtimes) {
560
+ const status = runtime.available ? '✅' : '❌';
561
+ const analyzer = runtime.analyzer ? '(analyzer available)' : '(no analyzer)';
562
+ console.log(` ${status} ${runtime.name} ${runtime.version} ${analyzer}`);
563
+ }
564
+ console.log('');
565
+ }
566
+ /**
567
+ * Get runtime statistics
568
+ */
569
+ getStats() {
570
+ const total = this.runtimes.size;
571
+ const available = Array.from(this.runtimes.values()).filter(r => r.available).length;
572
+ const withAnalyzers = Array.from(this.runtimes.values()).filter(r => r.available && r.analyzer).length;
573
+ return {
574
+ total,
575
+ available,
576
+ withAnalyzers,
577
+ runtimes: Object.fromEntries(Array.from(this.runtimes.entries()).map(([name, runtime]) => [
578
+ name,
579
+ {
580
+ available: runtime.available,
581
+ version: runtime.version,
582
+ hasAnalyzer: !!runtime.analyzer
583
+ }
584
+ ]))
585
+ };
586
+ }
587
+ }
588
+ // Enhanced TypeScript analyzer that integrates with existing infrastructure
589
+ class TypeScriptAnalyzer {
590
+ name = 'typescript';
591
+ runtime = 'node';
592
+ command = 'node';
593
+ supports = ['.ts', '.tsx', '.js', '.jsx'];
594
+ async analyze(files, options) {
595
+ console.log(`[TypeScriptAnalyzer] Analyzing ${files.length} TypeScript files`);
596
+ const startTime = Date.now();
597
+ try {
598
+ // Import the existing TypeScript adapter and audit infrastructure
599
+ const { TypeScriptAdapter } = await import('./typescript/TypeScriptAdapter.js');
600
+ const { runAudit } = await import('../auditRunner.js');
601
+ // Run the existing audit process
602
+ const auditResult = await runAudit({
603
+ includePaths: files,
604
+ enabledAnalyzers: options?.analyzers || ['solid', 'dry', 'documentation', 'dataAccess'],
605
+ minSeverity: options?.minSeverity || 'warning',
606
+ verbose: false
607
+ });
608
+ // Extract index entries from the audit process
609
+ const indexEntries = [];
610
+ // Try to get functions from the audit metadata if available
611
+ if (auditResult.metadata?.collectedFunctions) {
612
+ for (const func of auditResult.metadata.collectedFunctions) {
613
+ indexEntries.push({
614
+ id: `typescript:function:${func.filePath}:${func.name}:${func.lineNumber || 0}`,
615
+ name: func.name,
616
+ type: 'function',
617
+ language: 'typescript',
618
+ file: func.filePath,
619
+ signature: func.name, // Basic signature
620
+ parameters: [],
621
+ purpose: func.purpose || '',
622
+ context: func.context || '',
623
+ startLine: func.startLine,
624
+ endLine: func.endLine,
625
+ lineNumber: func.lineNumber,
626
+ metadata: func.metadata
627
+ });
628
+ }
629
+ }
630
+ // Add component information if available
631
+ if (auditResult.metadata?.fileToFunctionsMap) {
632
+ for (const [filePath, funcs] of Object.entries(auditResult.metadata.fileToFunctionsMap)) {
633
+ for (const func of funcs) {
634
+ if (!indexEntries.find(e => e.id === `typescript:function:${func.filePath}:${func.name}:${func.lineNumber || 0}`)) {
635
+ indexEntries.push({
636
+ id: `typescript:function:${func.filePath}:${func.name}:${func.lineNumber || 0}`,
637
+ name: func.name,
638
+ type: 'function',
639
+ language: 'typescript',
640
+ file: func.filePath,
641
+ signature: func.name,
642
+ parameters: [],
643
+ purpose: func.purpose || '',
644
+ context: func.context || '',
645
+ startLine: func.startLine,
646
+ endLine: func.endLine,
647
+ lineNumber: func.lineNumber,
648
+ metadata: func.metadata
649
+ });
650
+ }
651
+ }
652
+ }
653
+ }
654
+ const executionTime = Date.now() - startTime;
655
+ // Extract violations from all analyzer results
656
+ const violations = [];
657
+ for (const [analyzerName, analyzerResult] of Object.entries(auditResult.analyzerResults)) {
658
+ violations.push(...analyzerResult.violations);
659
+ }
660
+ // Extract errors from analyzer results
661
+ const errors = [];
662
+ for (const [analyzerName, analyzerResult] of Object.entries(auditResult.analyzerResults)) {
663
+ if (analyzerResult.errors) {
664
+ errors.push(...analyzerResult.errors);
665
+ }
666
+ }
667
+ return {
668
+ violations,
669
+ indexEntries,
670
+ metrics: {
671
+ filesAnalyzed: files.length,
672
+ executionTime
673
+ },
674
+ errors
675
+ };
676
+ }
677
+ catch (error) {
678
+ const executionTime = Date.now() - startTime;
679
+ console.error(`[TypeScriptAnalyzer] Error during analysis:`, error);
680
+ return {
681
+ violations: [],
682
+ indexEntries: [],
683
+ metrics: {
684
+ filesAnalyzed: 0,
685
+ executionTime
686
+ },
687
+ errors: [{
688
+ message: error instanceof Error ? error.message : String(error),
689
+ type: 'analysis_error'
690
+ }]
691
+ };
692
+ }
693
+ }
694
+ }
695
+ class GoAnalyzer {
696
+ analyzerPath;
697
+ name = 'go';
698
+ runtime = 'go';
699
+ command;
700
+ supports = ['.go'];
701
+ constructor(analyzerPath) {
702
+ this.analyzerPath = analyzerPath;
703
+ this.command = analyzerPath || 'go';
704
+ }
705
+ async analyze(files, options) {
706
+ console.log(`[GoAnalyzer] Analyzing ${files.length} Go files`);
707
+ const startTime = Date.now();
708
+ try {
709
+ // Build the Go analyzer if needed
710
+ const goAnalyzerDir = path.join(__dirname, 'go');
711
+ await this.ensureGoAnalyzerBuilt(goAnalyzerDir);
712
+ // Prepare analysis options
713
+ const analysisOptions = {
714
+ analyzers: options?.analyzers || ['solid', 'imports', 'errors'],
715
+ minSeverity: options?.minSeverity || 'warning',
716
+ timeout: options?.timeout || 30000,
717
+ language: options?.language || 'go',
718
+ verbose: options?.verbose || false
719
+ };
720
+ // Run the Go analyzer via JSON-RPC
721
+ const result = await this.runGoAnalyzer(goAnalyzerDir, files, analysisOptions);
722
+ const executionTime = Date.now() - startTime;
723
+ result.metrics.executionTime = executionTime;
724
+ console.log(`[GoAnalyzer] Analysis complete: ${result.violations.length} violations, ${result.indexEntries.length} entities`);
725
+ return result;
726
+ }
727
+ catch (error) {
728
+ const executionTime = Date.now() - startTime;
729
+ console.error(`[GoAnalyzer] Error during analysis:`, error);
730
+ return {
731
+ violations: [],
732
+ indexEntries: [],
733
+ metrics: {
734
+ filesAnalyzed: 0,
735
+ executionTime
736
+ },
737
+ errors: [{
738
+ message: error instanceof Error ? error.message : String(error),
739
+ type: 'go_analyzer_error'
740
+ }]
741
+ };
742
+ }
743
+ }
744
+ async ensureGoAnalyzerBuilt(goDir) {
745
+ const binaryPath = path.join(goDir, 'analyzer');
746
+ const mainGoPath = path.join(goDir, 'main.go');
747
+ try {
748
+ // Check if binary exists
749
+ await fs.access(binaryPath);
750
+ console.log(`[GoAnalyzer] Binary already exists at ${binaryPath}`);
751
+ }
752
+ catch {
753
+ // Binary doesn't exist, build it
754
+ console.log(`[GoAnalyzer] Building Go analyzer binary...`);
755
+ try {
756
+ const { stdout, stderr } = await execAsync(`cd "${goDir}" && go build -o analyzer main.go`);
757
+ if (stderr) {
758
+ console.warn(`[GoAnalyzer] Build warnings: ${stderr}`);
759
+ }
760
+ console.log(`[GoAnalyzer] Successfully built Go analyzer binary`);
761
+ }
762
+ catch (buildError) {
763
+ throw new Error(`Failed to build Go analyzer: ${buildError}`);
764
+ }
765
+ }
766
+ }
767
+ async runGoAnalyzer(goDir, files, options) {
768
+ const binaryPath = path.join(goDir, 'analyzer');
769
+ return new Promise((resolve, reject) => {
770
+ const child = spawn(binaryPath, [], {
771
+ stdio: ['pipe', 'pipe', 'pipe'],
772
+ cwd: goDir
773
+ });
774
+ let stdout = '';
775
+ let stderr = '';
776
+ child.stdout?.on('data', (data) => {
777
+ stdout += data.toString();
778
+ });
779
+ child.stderr?.on('data', (data) => {
780
+ stderr += data.toString();
781
+ });
782
+ child.on('close', (code) => {
783
+ if (code !== 0) {
784
+ reject(new Error(`Go analyzer exited with code ${code}: ${stderr}`));
785
+ return;
786
+ }
787
+ try {
788
+ // Parse the last line as JSON response
789
+ const lines = stdout.trim().split('\n');
790
+ const lastLine = lines[lines.length - 1];
791
+ const response = JSON.parse(lastLine);
792
+ if (response.error) {
793
+ reject(new Error(`Go analyzer error: ${response.error.message}`));
794
+ }
795
+ else {
796
+ resolve(response.result);
797
+ }
798
+ }
799
+ catch (parseError) {
800
+ reject(new Error(`Failed to parse Go analyzer response: ${parseError}`));
801
+ }
802
+ });
803
+ child.on('error', (error) => {
804
+ reject(new Error(`Failed to spawn Go analyzer: ${error}`));
805
+ });
806
+ // Send JSON-RPC request
807
+ const request = {
808
+ method: 'analyze',
809
+ params: {
810
+ files,
811
+ options
812
+ },
813
+ id: 1
814
+ };
815
+ child.stdin?.write(JSON.stringify(request) + '\n');
816
+ child.stdin?.end();
817
+ });
818
+ }
819
+ }
820
+ class PythonAnalyzer {
821
+ name = 'python';
822
+ runtime = 'python';
823
+ command;
824
+ supports = ['.py'];
825
+ constructor(pythonCommand) {
826
+ this.command = pythonCommand;
827
+ }
828
+ async analyze(files, options) {
829
+ console.log(`[PythonAnalyzer] Analyzing ${files.length} Python files`);
830
+ // This will spawn the Python analyzer process
831
+ return {
832
+ violations: [],
833
+ indexEntries: [],
834
+ metrics: {
835
+ filesAnalyzed: files.length,
836
+ executionTime: 0
837
+ }
838
+ };
839
+ }
840
+ }
841
+ //# sourceMappingURL=RuntimeManager.js.map