code-auditor-mcp 3.4.12 → 3.4.13

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 (245) hide show
  1. package/CHANGELOG.md +46 -1
  2. package/dist/analyzers/__verify_self_probe.d.ts +2 -0
  3. package/dist/analyzers/__verify_self_probe.d.ts.map +1 -0
  4. package/dist/analyzers/__verify_self_probe.js +5 -0
  5. package/dist/analyzers/__verify_self_probe.js.map +1 -0
  6. package/dist/analyzers/analyzerUtils.d.ts +34 -1
  7. package/dist/analyzers/analyzerUtils.d.ts.map +1 -1
  8. package/dist/analyzers/analyzerUtils.js +61 -22
  9. package/dist/analyzers/analyzerUtils.js.map +1 -1
  10. package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts +18 -23
  11. package/dist/analyzers/cross-language/APIContractAnalyzer.d.ts.map +1 -1
  12. package/dist/analyzers/cross-language/APIContractAnalyzer.js +198 -186
  13. package/dist/analyzers/cross-language/APIContractAnalyzer.js.map +1 -1
  14. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts +78 -55
  15. package/dist/analyzers/cross-language/DependencyGraphBuilder.d.ts.map +1 -1
  16. package/dist/analyzers/cross-language/DependencyGraphBuilder.js +244 -243
  17. package/dist/analyzers/cross-language/DependencyGraphBuilder.js.map +1 -1
  18. package/dist/analyzers/cross-language/SchemaValidator.d.ts +27 -37
  19. package/dist/analyzers/cross-language/SchemaValidator.d.ts.map +1 -1
  20. package/dist/analyzers/cross-language/SchemaValidator.js +314 -275
  21. package/dist/analyzers/cross-language/SchemaValidator.js.map +1 -1
  22. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts +17 -46
  23. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.d.ts.map +1 -1
  24. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js +620 -523
  25. package/dist/analyzers/crossDomain/CrossDomainAnalyzer.js.map +1 -1
  26. package/dist/analyzers/documentationAnalyzer.d.ts +7 -2
  27. package/dist/analyzers/documentationAnalyzer.d.ts.map +1 -1
  28. package/dist/analyzers/documentationAnalyzer.js +259 -198
  29. package/dist/analyzers/documentationAnalyzer.js.map +1 -1
  30. package/dist/analyzers/invariantsAnalyzer.d.ts.map +1 -1
  31. package/dist/analyzers/invariantsAnalyzer.js +57 -50
  32. package/dist/analyzers/invariantsAnalyzer.js.map +1 -1
  33. package/dist/analyzers/orm/adapterRegistry.d.ts +10 -0
  34. package/dist/analyzers/orm/adapterRegistry.d.ts.map +1 -1
  35. package/dist/analyzers/orm/adapterRegistry.js +10 -0
  36. package/dist/analyzers/orm/adapterRegistry.js.map +1 -1
  37. package/dist/analyzers/orm/drizzleAdapter.d.ts +22 -0
  38. package/dist/analyzers/orm/drizzleAdapter.d.ts.map +1 -1
  39. package/dist/analyzers/orm/drizzleAdapter.js +42 -44
  40. package/dist/analyzers/orm/drizzleAdapter.js.map +1 -1
  41. package/dist/analyzers/orm/prismaAdapter.d.ts +30 -0
  42. package/dist/analyzers/orm/prismaAdapter.d.ts.map +1 -1
  43. package/dist/analyzers/orm/prismaAdapter.js +30 -0
  44. package/dist/analyzers/orm/prismaAdapter.js.map +1 -1
  45. package/dist/analyzers/provenance.d.ts +62 -2
  46. package/dist/analyzers/provenance.d.ts.map +1 -1
  47. package/dist/analyzers/provenance.js +443 -349
  48. package/dist/analyzers/provenance.js.map +1 -1
  49. package/dist/analyzers/reactAnalyzer.d.ts +11 -0
  50. package/dist/analyzers/reactAnalyzer.d.ts.map +1 -1
  51. package/dist/analyzers/reactAnalyzer.js +188 -125
  52. package/dist/analyzers/reactAnalyzer.js.map +1 -1
  53. package/dist/analyzers/ruleRegistry.d.ts +110 -1
  54. package/dist/analyzers/ruleRegistry.d.ts.map +1 -1
  55. package/dist/analyzers/ruleRegistry.js +1714 -124
  56. package/dist/analyzers/ruleRegistry.js.map +1 -1
  57. package/dist/analyzers/ruleTiming.d.ts +54 -0
  58. package/dist/analyzers/ruleTiming.d.ts.map +1 -0
  59. package/dist/analyzers/ruleTiming.js +71 -0
  60. package/dist/analyzers/ruleTiming.js.map +1 -0
  61. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts +13 -0
  62. package/dist/analyzers/universal/UniversalConventionsAnalyzer.d.ts.map +1 -1
  63. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js +362 -283
  64. package/dist/analyzers/universal/UniversalConventionsAnalyzer.js.map +1 -1
  65. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts +26 -68
  66. package/dist/analyzers/universal/UniversalDRYAnalyzer.d.ts.map +1 -1
  67. package/dist/analyzers/universal/UniversalDRYAnalyzer.js +430 -391
  68. package/dist/analyzers/universal/UniversalDRYAnalyzer.js.map +1 -1
  69. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts +17 -202
  70. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.d.ts.map +1 -1
  71. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js +1073 -1121
  72. package/dist/analyzers/universal/UniversalDataAccessAnalyzer.js.map +1 -1
  73. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts +3 -49
  74. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.d.ts.map +1 -1
  75. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js +414 -340
  76. package/dist/analyzers/universal/UniversalDocumentationAnalyzer.js.map +1 -1
  77. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts +48 -5
  78. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.d.ts.map +1 -1
  79. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js +262 -134
  80. package/dist/analyzers/universal/UniversalSOLIDAnalyzer.js.map +1 -1
  81. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts +23 -214
  82. package/dist/analyzers/universal/UniversalSchemaAnalyzer.d.ts.map +1 -1
  83. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js +139 -1521
  84. package/dist/analyzers/universal/UniversalSchemaAnalyzer.js.map +1 -1
  85. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts +78 -79
  86. package/dist/analyzers/universal/UniversalStylesAnalyzer.d.ts.map +1 -1
  87. package/dist/analyzers/universal/UniversalStylesAnalyzer.js +613 -480
  88. package/dist/analyzers/universal/UniversalStylesAnalyzer.js.map +1 -1
  89. package/dist/analyzers/universal/schema/codeAnalysis.d.ts +307 -0
  90. package/dist/analyzers/universal/schema/codeAnalysis.d.ts.map +1 -0
  91. package/dist/analyzers/universal/schema/codeAnalysis.js +965 -0
  92. package/dist/analyzers/universal/schema/codeAnalysis.js.map +1 -0
  93. package/dist/analyzers/universal/schema/config.d.ts +31 -0
  94. package/dist/analyzers/universal/schema/config.d.ts.map +1 -0
  95. package/dist/analyzers/universal/schema/config.js +57 -0
  96. package/dist/analyzers/universal/schema/config.js.map +1 -0
  97. package/dist/analyzers/universal/schema/discovery.d.ts +167 -0
  98. package/dist/analyzers/universal/schema/discovery.d.ts.map +1 -0
  99. package/dist/analyzers/universal/schema/discovery.js +616 -0
  100. package/dist/analyzers/universal/schema/discovery.js.map +1 -0
  101. package/dist/analyzers/universal/schema/jsonSchema.d.ts +27 -0
  102. package/dist/analyzers/universal/schema/jsonSchema.d.ts.map +1 -0
  103. package/dist/analyzers/universal/schema/jsonSchema.js +368 -0
  104. package/dist/analyzers/universal/schema/jsonSchema.js.map +1 -0
  105. package/dist/analyzers/universal/schema/migrations.d.ts +90 -0
  106. package/dist/analyzers/universal/schema/migrations.d.ts.map +1 -0
  107. package/dist/analyzers/universal/schema/migrations.js +238 -0
  108. package/dist/analyzers/universal/schema/migrations.js.map +1 -0
  109. package/dist/analyzers/universal/schema/types.d.ts +131 -0
  110. package/dist/analyzers/universal/schema/types.d.ts.map +1 -0
  111. package/dist/analyzers/universal/schema/types.js +10 -0
  112. package/dist/analyzers/universal/schema/types.js.map +1 -0
  113. package/dist/analyzers/universal/schema/violations.d.ts +44 -0
  114. package/dist/analyzers/universal/schema/violations.d.ts.map +1 -0
  115. package/dist/analyzers/universal/schema/violations.js +54 -0
  116. package/dist/analyzers/universal/schema/violations.js.map +1 -0
  117. package/dist/auditRunner.d.ts.map +1 -1
  118. package/dist/auditRunner.js +89 -13
  119. package/dist/auditRunner.js.map +1 -1
  120. package/dist/cli.js +315 -40
  121. package/dist/cli.js.map +1 -1
  122. package/dist/config/configLoader.d.ts.map +1 -1
  123. package/dist/config/configLoader.js +9 -7
  124. package/dist/config/configLoader.js.map +1 -1
  125. package/dist/config/defaults.d.ts +12 -3
  126. package/dist/config/defaults.d.ts.map +1 -1
  127. package/dist/config/defaults.js +15 -5
  128. package/dist/config/defaults.js.map +1 -1
  129. package/dist/config/effectiveConfig.d.ts +75 -0
  130. package/dist/config/effectiveConfig.d.ts.map +1 -0
  131. package/dist/config/effectiveConfig.js +213 -0
  132. package/dist/config/effectiveConfig.js.map +1 -0
  133. package/dist/config/pathProfiles.d.ts +7 -4
  134. package/dist/config/pathProfiles.d.ts.map +1 -1
  135. package/dist/config/pathProfiles.js +8 -10
  136. package/dist/config/pathProfiles.js.map +1 -1
  137. package/dist/config/thresholdRationales.d.ts +45 -0
  138. package/dist/config/thresholdRationales.d.ts.map +1 -0
  139. package/dist/config/thresholdRationales.js +67 -0
  140. package/dist/config/thresholdRationales.js.map +1 -0
  141. package/dist/conventions/conventionMiner.d.ts.map +1 -1
  142. package/dist/conventions/conventionMiner.js +6 -2
  143. package/dist/conventions/conventionMiner.js.map +1 -1
  144. package/dist/enforcement/diffGate.d.ts +55 -0
  145. package/dist/enforcement/diffGate.d.ts.map +1 -0
  146. package/dist/enforcement/diffGate.js +136 -0
  147. package/dist/enforcement/diffGate.js.map +1 -0
  148. package/dist/enforcement/gate.d.ts +36 -0
  149. package/dist/enforcement/gate.d.ts.map +1 -0
  150. package/dist/enforcement/gate.js +72 -0
  151. package/dist/enforcement/gate.js.map +1 -0
  152. package/dist/enforcement/suppressions.d.ts +41 -0
  153. package/dist/enforcement/suppressions.d.ts.map +1 -0
  154. package/dist/enforcement/suppressions.js +170 -0
  155. package/dist/enforcement/suppressions.js.map +1 -0
  156. package/dist/fingerprint.d.ts.map +1 -1
  157. package/dist/fingerprint.js +4 -1
  158. package/dist/fingerprint.js.map +1 -1
  159. package/dist/invariants/ruleEngine.d.ts +3 -4
  160. package/dist/invariants/ruleEngine.d.ts.map +1 -1
  161. package/dist/invariants/ruleEngine.js +2 -2
  162. package/dist/invariants/ruleEngine.js.map +1 -1
  163. package/dist/languages/LanguageOrchestrator.d.ts +14 -0
  164. package/dist/languages/LanguageOrchestrator.d.ts.map +1 -1
  165. package/dist/languages/LanguageOrchestrator.js +93 -55
  166. package/dist/languages/LanguageOrchestrator.js.map +1 -1
  167. package/dist/languages/LanguageRegistry.d.ts +8 -0
  168. package/dist/languages/LanguageRegistry.d.ts.map +1 -1
  169. package/dist/languages/LanguageRegistry.js +8 -0
  170. package/dist/languages/LanguageRegistry.js.map +1 -1
  171. package/dist/languages/RuntimeManager.d.ts +82 -60
  172. package/dist/languages/RuntimeManager.d.ts.map +1 -1
  173. package/dist/languages/RuntimeManager.js +404 -349
  174. package/dist/languages/RuntimeManager.js.map +1 -1
  175. package/dist/languages/UniversalAnalyzer.d.ts +51 -6
  176. package/dist/languages/UniversalAnalyzer.d.ts.map +1 -1
  177. package/dist/languages/UniversalAnalyzer.js +127 -88
  178. package/dist/languages/UniversalAnalyzer.js.map +1 -1
  179. package/dist/languages/adapterBridge.d.ts +36 -0
  180. package/dist/languages/adapterBridge.d.ts.map +1 -1
  181. package/dist/languages/adapterBridge.js +89 -35
  182. package/dist/languages/adapterBridge.js.map +1 -1
  183. package/dist/languages/go/GoAdapter.d.ts +66 -23
  184. package/dist/languages/go/GoAdapter.d.ts.map +1 -1
  185. package/dist/languages/go/GoAdapter.js +553 -474
  186. package/dist/languages/go/GoAdapter.js.map +1 -1
  187. package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts +33 -4
  188. package/dist/languages/tree-sitter/TreeSitterCssAdapter.d.ts.map +1 -1
  189. package/dist/languages/tree-sitter/TreeSitterCssAdapter.js +101 -66
  190. package/dist/languages/tree-sitter/TreeSitterCssAdapter.js.map +1 -1
  191. package/dist/languages/tree-sitter/converter.d.ts +18 -0
  192. package/dist/languages/tree-sitter/converter.d.ts.map +1 -1
  193. package/dist/languages/tree-sitter/converter.js +18 -0
  194. package/dist/languages/tree-sitter/converter.js.map +1 -1
  195. package/dist/languages/tree-sitter/parser.d.ts +39 -2
  196. package/dist/languages/tree-sitter/parser.d.ts.map +1 -1
  197. package/dist/languages/tree-sitter/parser.js +93 -12
  198. package/dist/languages/tree-sitter/parser.js.map +1 -1
  199. package/dist/languages/types.d.ts +67 -2
  200. package/dist/languages/types.d.ts.map +1 -1
  201. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts +253 -72
  202. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.d.ts.map +1 -1
  203. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js +1419 -923
  204. package/dist/languages/typescript/TreeSitterTypeScriptAdapter.js.map +1 -1
  205. package/dist/mcp-tools-shared.d.ts.map +1 -1
  206. package/dist/mcp-tools-shared.js.map +1 -1
  207. package/dist/pipeline.d.ts +13 -5
  208. package/dist/pipeline.d.ts.map +1 -1
  209. package/dist/pipeline.js +381 -200
  210. package/dist/pipeline.js.map +1 -1
  211. package/dist/pipelineAdapters.d.ts +3 -8
  212. package/dist/pipelineAdapters.d.ts.map +1 -1
  213. package/dist/pipelineAdapters.js +149 -94
  214. package/dist/pipelineAdapters.js.map +1 -1
  215. package/dist/presets/presets.d.ts +54 -0
  216. package/dist/presets/presets.d.ts.map +1 -0
  217. package/dist/presets/presets.js +181 -0
  218. package/dist/presets/presets.js.map +1 -0
  219. package/dist/reporting/sarifReportGenerator.d.ts.map +1 -1
  220. package/dist/reporting/sarifReportGenerator.js +0 -2
  221. package/dist/reporting/sarifReportGenerator.js.map +1 -1
  222. package/dist/ruleAliases.d.ts +67 -0
  223. package/dist/ruleAliases.d.ts.map +1 -0
  224. package/dist/ruleAliases.js +79 -0
  225. package/dist/ruleAliases.js.map +1 -0
  226. package/dist/styles/cssAstExtractor.d.ts.map +1 -1
  227. package/dist/styles/cssAstExtractor.js +78 -18
  228. package/dist/styles/cssAstExtractor.js.map +1 -1
  229. package/dist/styles/styleIndexer.js +10 -1
  230. package/dist/styles/styleIndexer.js.map +1 -1
  231. package/dist/styles/tailwindConfigLoader.d.ts +8 -6
  232. package/dist/styles/tailwindConfigLoader.d.ts.map +1 -1
  233. package/dist/styles/tailwindConfigLoader.js +61 -15
  234. package/dist/styles/tailwindConfigLoader.js.map +1 -1
  235. package/dist/styles/tailwindUtilityExpander.d.ts.map +1 -1
  236. package/dist/styles/tailwindUtilityExpander.js +13 -1
  237. package/dist/styles/tailwindUtilityExpander.js.map +1 -1
  238. package/dist/types.d.ts +181 -1
  239. package/dist/types.d.ts.map +1 -1
  240. package/dist/types.js +8 -0
  241. package/dist/types.js.map +1 -1
  242. package/package.json +5 -3
  243. package/plugin/hooks/hooks.json +1 -1
  244. package/plugin/scripts/hook-audit.sh +25 -7
  245. package/plugin/skills/code-auditor/SKILL.md +5 -5
@@ -7,7 +7,10 @@ import { promisify } from 'util';
7
7
  import * as path from 'path';
8
8
  import * as fs from 'fs/promises';
9
9
  const execAsync = promisify(exec);
10
- export class RuntimeManager {
10
+ // ---------------------------------------------------------------------------
11
+ // Detection layer: shared state + runtime discovery (leaf — no cross-layer calls)
12
+ // ---------------------------------------------------------------------------
13
+ class RuntimeManagerDetection {
11
14
  runtimes = new Map();
12
15
  initialized = false;
13
16
  config = new Map();
@@ -35,217 +38,6 @@ export class RuntimeManager {
35
38
  console.error('[RuntimeManager] Runtime detection complete');
36
39
  this.logRuntimeStatus();
37
40
  }
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
41
  /**
250
42
  * Detect Node.js runtime
251
43
  */
@@ -426,6 +218,23 @@ export class RuntimeManager {
426
218
  return false;
427
219
  }
428
220
  }
221
+ /**
222
+ * Log runtime status
223
+ */
224
+ logRuntimeStatus() {
225
+ console.log('\n[RuntimeManager] Runtime Status:');
226
+ for (const [name, runtime] of this.runtimes) {
227
+ const status = runtime.available ? '✅' : '❌';
228
+ const analyzer = runtime.analyzer ? '(analyzer available)' : '(no analyzer)';
229
+ console.log(` ${status} ${runtime.name} ${runtime.version} ${analyzer}`);
230
+ }
231
+ console.log('');
232
+ }
233
+ }
234
+ // ---------------------------------------------------------------------------
235
+ // Version layer: semantic-version comparison and compatibility reporting
236
+ // ---------------------------------------------------------------------------
237
+ class RuntimeManagerVersion extends RuntimeManagerDetection {
429
238
  /**
430
239
  * Check version compatibility with detailed reporting
431
240
  */
@@ -453,25 +262,14 @@ export class RuntimeManager {
453
262
  const config = this.config.get(name);
454
263
  const minVersion = config?.minVersion || runtime.minVersion;
455
264
  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
- }
265
+ const { status, recommendations } = deriveCompatibilityStatus({
266
+ name,
267
+ available: runtime.available,
268
+ version: runtime.version,
269
+ compatible,
270
+ minVersion,
271
+ installSuggestions: this.getRuntimeInstallationSuggestions(name)
272
+ });
475
273
  report.push({
476
274
  runtime: runtime.name,
477
275
  currentVersion: runtime.version,
@@ -552,16 +350,90 @@ export class RuntimeManager {
552
350
  return 0;
553
351
  }
554
352
  /**
555
- * Log runtime status
353
+ * Get installation suggestions for missing runtimes
556
354
  */
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}`);
355
+ getRuntimeInstallationSuggestions(language) {
356
+ const suggestions = {
357
+ 'go': [
358
+ 'Install Go: https://golang.org/dl/',
359
+ 'Or use package manager: brew install go (macOS), apt install golang (Ubuntu)'
360
+ ],
361
+ 'python': [
362
+ 'Install Python: https://python.org/downloads/',
363
+ 'Or use package manager: brew install python (macOS), apt install python3 (Ubuntu)'
364
+ ],
365
+ 'rust': [
366
+ 'Install Rust: https://rustup.rs/',
367
+ 'Run: curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh'
368
+ ],
369
+ 'node': [
370
+ 'Install Node.js: https://nodejs.org/',
371
+ 'Or use nvm: nvm install node'
372
+ ]
373
+ };
374
+ return suggestions[language] || ['Check the official documentation for installation instructions'];
375
+ }
376
+ }
377
+ // ---------------------------------------------------------------------------
378
+ // Access layer: runtime lookup, fallback resolution, and statistics
379
+ // ---------------------------------------------------------------------------
380
+ class RuntimeManagerAccess extends RuntimeManagerVersion {
381
+ /**
382
+ * Check if a specific runtime is available
383
+ */
384
+ hasRuntime(name) {
385
+ const runtime = this.runtimes.get(name);
386
+ const config = this.config.get(name);
387
+ return runtime?.available === true &&
388
+ (config?.enabled !== false) &&
389
+ this.checkVersionCompatibility(runtime, config);
390
+ }
391
+ /**
392
+ * Get fallback runtime for a language if the primary is unavailable
393
+ */
394
+ getFallbackRuntime(language) {
395
+ const fallbackMap = {
396
+ 'typescript': ['node', 'deno', 'bun'],
397
+ 'javascript': ['node', 'deno', 'bun'],
398
+ 'go': ['go'],
399
+ 'python': ['python'],
400
+ 'rust': ['rust']
401
+ };
402
+ const fallbacks = fallbackMap[language] || [];
403
+ for (const fallback of fallbacks) {
404
+ if (this.hasRuntime(fallback)) {
405
+ const runtime = this.runtimes.get(fallback);
406
+ if (runtime?.analyzer?.supports.some(ext => this.getLanguageExtensions(language).includes(ext))) {
407
+ return runtime;
408
+ }
409
+ }
563
410
  }
564
- console.log('');
411
+ return null;
412
+ }
413
+ /**
414
+ * Get file extensions for a language
415
+ */
416
+ getLanguageExtensions(language) {
417
+ const extensionMap = {
418
+ 'typescript': ['.ts', '.tsx'],
419
+ 'javascript': ['.js', '.jsx'],
420
+ 'go': ['.go'],
421
+ 'python': ['.py'],
422
+ 'rust': ['.rs']
423
+ };
424
+ return extensionMap[language] || [];
425
+ }
426
+ /**
427
+ * Get runtime information
428
+ */
429
+ getRuntime(name) {
430
+ return this.runtimes.get(name);
431
+ }
432
+ /**
433
+ * Get all available runtimes
434
+ */
435
+ getAvailableRuntimes() {
436
+ return Array.from(this.runtimes.values()).filter(r => r.available);
565
437
  }
566
438
  /**
567
439
  * Get runtime statistics
@@ -585,6 +457,156 @@ export class RuntimeManager {
585
457
  };
586
458
  }
587
459
  }
460
+ // ---------------------------------------------------------------------------
461
+ // Spawning layer: analyzer process orchestration (public top layer)
462
+ // ---------------------------------------------------------------------------
463
+ /**
464
+ * Runtime manager.
465
+ */
466
+ export class RuntimeManager extends RuntimeManagerAccess {
467
+ /**
468
+ * Attempt to analyze with fallback runtime if primary fails
469
+ * @param files
470
+ * @param language
471
+ * @param options
472
+ * @returns
473
+ */
474
+ async analyzeWithFallback(language, files, options) {
475
+ // Try primary runtime first
476
+ let result = await this.spawnAnalyzer(language, files, options);
477
+ if (result && result.errors?.length === 0) {
478
+ return result;
479
+ }
480
+ // If primary failed, try fallback
481
+ const fallbackRuntime = this.getFallbackRuntime(language);
482
+ if (fallbackRuntime) {
483
+ console.log(`[RuntimeManager] Primary ${language} runtime failed, trying fallback: ${fallbackRuntime.name}`);
484
+ try {
485
+ const fallbackResult = await fallbackRuntime.analyzer.analyze(files, {
486
+ ...options,
487
+ fallbackMode: true,
488
+ originalLanguage: language
489
+ });
490
+ // Add warning about fallback usage
491
+ fallbackResult.errors = fallbackResult.errors || [];
492
+ fallbackResult.errors.push({
493
+ message: `Analysis completed using fallback runtime ${fallbackRuntime.name} instead of native ${language} runtime`,
494
+ type: 'fallback_warning',
495
+ language
496
+ });
497
+ return fallbackResult;
498
+ }
499
+ catch (fallbackError) {
500
+ console.error(`[RuntimeManager] Fallback runtime also failed:`, fallbackError);
501
+ }
502
+ }
503
+ // No fallback available or fallback also failed
504
+ return {
505
+ violations: [],
506
+ indexEntries: [],
507
+ metrics: { filesAnalyzed: 0, executionTime: 0 },
508
+ errors: [{
509
+ message: `No working runtime available for ${language}. Install ${language} runtime or enable fallback options.`,
510
+ type: 'no_runtime',
511
+ language,
512
+ suggestions: this.getRuntimeInstallationSuggestions(language)
513
+ }]
514
+ };
515
+ }
516
+ /**
517
+ * Spawn analyzer for a specific language
518
+ * @param files
519
+ * @param language
520
+ * @param options
521
+ * @returns
522
+ */
523
+ async spawnAnalyzer(language, files, options) {
524
+ if (!this.initialized) {
525
+ await this.initialize();
526
+ }
527
+ const runtime = this.runtimes.get(language);
528
+ if (!runtime?.available || !runtime.analyzer) {
529
+ console.warn(`[RuntimeManager] No analyzer available for ${language}`);
530
+ return null;
531
+ }
532
+ console.log(`[RuntimeManager] Spawning ${language} analyzer for ${files.length} files`);
533
+ const startTime = Date.now();
534
+ const processTimeout = options?.timeout || 300000; // 5 minutes default
535
+ try {
536
+ const result = await this.runWithTimeout(() => runtime.analyzer.analyze(files, options), processTimeout);
537
+ const executionTime = Date.now() - startTime;
538
+ result.metrics.executionTime = executionTime;
539
+ console.log(`[RuntimeManager] ${language} analysis complete in ${executionTime}ms: ${result.violations.length} violations`);
540
+ return result;
541
+ }
542
+ catch (error) {
543
+ const executionTime = Date.now() - startTime;
544
+ console.error(`[RuntimeManager] Error in ${language} analyzer after ${executionTime}ms:`, error);
545
+ return {
546
+ violations: [],
547
+ indexEntries: [],
548
+ metrics: { filesAnalyzed: 0, executionTime },
549
+ errors: [{
550
+ message: error instanceof Error ? error.message : String(error),
551
+ language,
552
+ type: error instanceof Error && error.message.includes('timeout') ? 'timeout' : 'runtime_error'
553
+ }]
554
+ };
555
+ }
556
+ }
557
+ /**
558
+ * Run a function with timeout
559
+ */
560
+ async runWithTimeout(fn, timeoutMs) {
561
+ return new Promise((resolve, reject) => {
562
+ const timeoutId = setTimeout(() => {
563
+ reject(new Error(`Analysis timed out after ${timeoutMs}ms`));
564
+ }, timeoutMs);
565
+ fn()
566
+ .then(result => {
567
+ clearTimeout(timeoutId);
568
+ resolve(result);
569
+ })
570
+ .catch(error => {
571
+ clearTimeout(timeoutId);
572
+ reject(error);
573
+ });
574
+ });
575
+ }
576
+ /**
577
+ * Spawn multiple analyzers in parallel with concurrency control
578
+ * @param languageFilePairs
579
+ * @param options
580
+ * @returns
581
+ */
582
+ async spawnMultipleAnalyzers(languageFilePairs, options) {
583
+ const maxConcurrency = options?.maxConcurrency || 3;
584
+ const results = [];
585
+ console.log(`[RuntimeManager] Spawning ${languageFilePairs.length} analyzers with max concurrency ${maxConcurrency}`);
586
+ // Process in batches to control concurrency
587
+ for (let i = 0; i < languageFilePairs.length; i += maxConcurrency) {
588
+ const batch = languageFilePairs.slice(i, i + maxConcurrency);
589
+ const batchPromises = batch.map(async ({ language, files }) => {
590
+ const result = await this.spawnAnalyzer(language, files, options);
591
+ return { language, result };
592
+ });
593
+ const batchResults = await Promise.all(batchPromises);
594
+ results.push(...batchResults);
595
+ }
596
+ return results;
597
+ }
598
+ /**
599
+ * Kill all running analyzer processes (for cleanup)
600
+ * @returns
601
+ */
602
+ async killAllAnalyzers() {
603
+ console.log('[RuntimeManager] Killing all analyzer processes...');
604
+ // This is a placeholder for process management
605
+ // In future implementations, we'll track child processes and kill them here
606
+ // For now, we just log the action since our analyzers run in-process
607
+ console.log('[RuntimeManager] All analyzer processes terminated');
608
+ }
609
+ }
588
610
  // Enhanced TypeScript analyzer that integrates with existing infrastructure
589
611
  class TypeScriptAnalyzer {
590
612
  name = 'typescript';
@@ -605,73 +627,15 @@ class TypeScriptAnalyzer {
605
627
  minSeverity: options?.minSeverity || 'warning',
606
628
  verbose: false
607
629
  });
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
630
  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
631
  return {
668
- violations,
669
- indexEntries,
632
+ violations: extractViolations(auditResult),
633
+ indexEntries: collectIndexEntries(auditResult.metadata),
670
634
  metrics: {
671
635
  filesAnalyzed: files.length,
672
636
  executionTime
673
637
  },
674
- errors
638
+ errors: extractErrors(auditResult)
675
639
  };
676
640
  }
677
641
  catch (error) {
@@ -692,6 +656,63 @@ class TypeScriptAnalyzer {
692
656
  }
693
657
  }
694
658
  }
659
+ /** Build a single function index entry from a collected-function record. */
660
+ function toFunctionIndexEntry(func) {
661
+ return {
662
+ id: `typescript:function:${func.filePath}:${func.name}:${func.lineNumber || 0}`,
663
+ name: func.name,
664
+ type: 'function',
665
+ language: 'typescript',
666
+ file: func.filePath,
667
+ signature: func.name,
668
+ parameters: [],
669
+ purpose: func.purpose || '',
670
+ context: func.context || '',
671
+ startLine: func.startLine,
672
+ endLine: func.endLine,
673
+ lineNumber: func.lineNumber,
674
+ metadata: func.metadata
675
+ };
676
+ }
677
+ /** Extract function index entries from audit metadata (dedup across both maps). */
678
+ function collectIndexEntries(metadata) {
679
+ const indexEntries = [];
680
+ // Try to get functions from the audit metadata if available
681
+ if (metadata?.collectedFunctions) {
682
+ for (const func of metadata.collectedFunctions) {
683
+ indexEntries.push(toFunctionIndexEntry(func));
684
+ }
685
+ }
686
+ // Add component information if available
687
+ if (metadata?.fileToFunctionsMap) {
688
+ for (const funcs of Object.values(metadata.fileToFunctionsMap)) {
689
+ for (const func of funcs) {
690
+ if (!indexEntries.find(e => e.id === `typescript:function:${func.filePath}:${func.name}:${func.lineNumber || 0}`)) {
691
+ indexEntries.push(toFunctionIndexEntry(func));
692
+ }
693
+ }
694
+ }
695
+ }
696
+ return indexEntries;
697
+ }
698
+ /** Flatten violations from all analyzer results. */
699
+ function extractViolations(auditResult) {
700
+ const violations = [];
701
+ for (const analyzerResult of Object.values(auditResult.analyzerResults ?? {})) {
702
+ violations.push(...analyzerResult.violations);
703
+ }
704
+ return violations;
705
+ }
706
+ /** Flatten errors from all analyzer results. */
707
+ function extractErrors(auditResult) {
708
+ const errors = [];
709
+ for (const analyzerResult of Object.values(auditResult.analyzerResults ?? {})) {
710
+ if (analyzerResult.errors) {
711
+ errors.push(...analyzerResult.errors);
712
+ }
713
+ }
714
+ return errors;
715
+ }
695
716
  class GoAnalyzer {
696
717
  analyzerPath;
697
718
  name = 'go';
@@ -766,55 +787,7 @@ class GoAnalyzer {
766
787
  }
767
788
  async runGoAnalyzer(goDir, files, options) {
768
789
  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
- });
790
+ return spawnGoAnalyzer(binaryPath, goDir, files, options);
818
791
  }
819
792
  }
820
793
  class PythonAnalyzer {
@@ -838,4 +811,86 @@ class PythonAnalyzer {
838
811
  };
839
812
  }
840
813
  }
814
+ /**
815
+ * Derive compatibility status + recommendations for a single runtime.
816
+ */
817
+ function deriveCompatibilityStatus(input) {
818
+ const recommendations = [];
819
+ if (!input.available) {
820
+ recommendations.push(`Install ${input.name} runtime`);
821
+ recommendations.push(...input.installSuggestions);
822
+ return { status: 'unknown', recommendations };
823
+ }
824
+ if (input.version === 'unknown') {
825
+ recommendations.push(`Unable to detect ${input.name} version`);
826
+ return { status: 'unknown', recommendations };
827
+ }
828
+ if (!input.compatible) {
829
+ recommendations.push(`Update ${input.name} to version ${input.minVersion} or higher`);
830
+ recommendations.push(`Current: ${input.version}, Required: ${input.minVersion}`);
831
+ return { status: 'incompatible', recommendations };
832
+ }
833
+ return { status: 'compatible', recommendations };
834
+ }
835
+ /**
836
+ * Spawn the Go analyzer binary and stream a JSON-RPC analyze request.
837
+ */
838
+ function spawnGoAnalyzer(binaryPath, goDir, files, options) {
839
+ return new Promise((resolve, reject) => {
840
+ const child = spawn(binaryPath, [], {
841
+ stdio: ['pipe', 'pipe', 'pipe'],
842
+ cwd: goDir
843
+ });
844
+ let stdout = '';
845
+ let stderr = '';
846
+ child.stdout?.on('data', (data) => {
847
+ stdout += data.toString();
848
+ });
849
+ child.stderr?.on('data', (data) => {
850
+ stderr += data.toString();
851
+ });
852
+ child.on('close', (code) => {
853
+ handleGoAnalyzerClose(code, { stdout, stderr }, resolve, reject);
854
+ });
855
+ child.on('error', (error) => {
856
+ reject(new Error(`Failed to spawn Go analyzer: ${error}`));
857
+ });
858
+ // Send JSON-RPC request
859
+ const request = {
860
+ method: 'analyze',
861
+ params: { files, options },
862
+ id: 1
863
+ };
864
+ child.stdin?.write(JSON.stringify(request) + '\n');
865
+ child.stdin?.end();
866
+ });
867
+ }
868
+ /**
869
+ * Handle the `close` event of the Go analyzer child process: reject on a
870
+ * non-zero exit code, otherwise resolve with the parsed JSON-RPC result.
871
+ */
872
+ function handleGoAnalyzerClose(code, streams, resolve, reject) {
873
+ if (code !== 0) {
874
+ reject(new Error(`Go analyzer exited with code ${code}: ${streams.stderr}`));
875
+ return;
876
+ }
877
+ try {
878
+ resolve(parseGoAnalyzerResponse(streams.stdout));
879
+ }
880
+ catch (parseError) {
881
+ reject(new Error(`Failed to parse Go analyzer response: ${parseError}`));
882
+ }
883
+ }
884
+ /**
885
+ * Parse the last line of Go analyzer stdout as a JSON-RPC result.
886
+ */
887
+ function parseGoAnalyzerResponse(stdout) {
888
+ const lines = stdout.trim().split('\n');
889
+ const lastLine = lines[lines.length - 1];
890
+ const response = JSON.parse(lastLine);
891
+ if (response.error) {
892
+ throw new Error(`Go analyzer error: ${response.error.message}`);
893
+ }
894
+ return response.result;
895
+ }
841
896
  //# sourceMappingURL=RuntimeManager.js.map