codereview-aia 0.1.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.
- package/.cr-aia.yml +23 -0
- package/.crignore +0 -0
- package/dist/index.js +27 -0
- package/package.json +85 -0
- package/src/analysis/FindingsExtractor.ts +431 -0
- package/src/analysis/ai-detection/analyzers/BaseAnalyzer.ts +267 -0
- package/src/analysis/ai-detection/analyzers/DocumentationAnalyzer.ts +622 -0
- package/src/analysis/ai-detection/analyzers/GitHistoryAnalyzer.ts +430 -0
- package/src/analysis/ai-detection/core/AIDetectionEngine.ts +467 -0
- package/src/analysis/ai-detection/types/DetectionTypes.ts +406 -0
- package/src/analysis/ai-detection/utils/SubmissionConverter.ts +390 -0
- package/src/analysis/context/ReviewContext.ts +378 -0
- package/src/analysis/context/index.ts +7 -0
- package/src/analysis/index.ts +8 -0
- package/src/analysis/tokens/TokenAnalysisFormatter.ts +154 -0
- package/src/analysis/tokens/TokenAnalyzer.ts +747 -0
- package/src/analysis/tokens/index.ts +8 -0
- package/src/clients/base/abstractClient.ts +190 -0
- package/src/clients/base/httpClient.ts +160 -0
- package/src/clients/base/index.ts +12 -0
- package/src/clients/base/modelDetection.ts +107 -0
- package/src/clients/base/responseProcessor.ts +586 -0
- package/src/clients/factory/clientFactory.ts +55 -0
- package/src/clients/factory/index.ts +8 -0
- package/src/clients/implementations/index.ts +8 -0
- package/src/clients/implementations/openRouterClient.ts +411 -0
- package/src/clients/openRouterClient.ts +863 -0
- package/src/clients/openRouterClientWrapper.ts +44 -0
- package/src/clients/utils/directoryStructure.ts +52 -0
- package/src/clients/utils/index.ts +11 -0
- package/src/clients/utils/languageDetection.ts +44 -0
- package/src/clients/utils/promptFormatter.ts +105 -0
- package/src/clients/utils/promptLoader.ts +53 -0
- package/src/clients/utils/tokenCounter.ts +297 -0
- package/src/core/ApiClientSelector.ts +37 -0
- package/src/core/ConfigurationService.ts +591 -0
- package/src/core/ConsolidationService.ts +423 -0
- package/src/core/InteractiveDisplayManager.ts +81 -0
- package/src/core/OutputManager.ts +275 -0
- package/src/core/ReviewGenerator.ts +140 -0
- package/src/core/fileDiscovery.ts +237 -0
- package/src/core/handlers/EstimationHandler.ts +104 -0
- package/src/core/handlers/FileProcessingHandler.ts +204 -0
- package/src/core/handlers/OutputHandler.ts +125 -0
- package/src/core/handlers/ReviewExecutor.ts +104 -0
- package/src/core/reviewOrchestrator.ts +333 -0
- package/src/core/utils/ModelInfoUtils.ts +56 -0
- package/src/formatters/outputFormatter.ts +62 -0
- package/src/formatters/utils/IssueFormatters.ts +83 -0
- package/src/formatters/utils/JsonFormatter.ts +77 -0
- package/src/formatters/utils/MarkdownFormatters.ts +609 -0
- package/src/formatters/utils/MetadataFormatter.ts +269 -0
- package/src/formatters/utils/ModelInfoExtractor.ts +115 -0
- package/src/index.ts +27 -0
- package/src/plugins/PluginInterface.ts +50 -0
- package/src/plugins/PluginManager.ts +126 -0
- package/src/prompts/PromptManager.ts +69 -0
- package/src/prompts/cache/PromptCache.ts +50 -0
- package/src/prompts/promptText/common/variables/css-frameworks.json +33 -0
- package/src/prompts/promptText/common/variables/framework-versions.json +45 -0
- package/src/prompts/promptText/frameworks/react/comprehensive.hbs +19 -0
- package/src/prompts/promptText/languages/css/comprehensive.hbs +18 -0
- package/src/prompts/promptText/languages/generic/comprehensive.hbs +20 -0
- package/src/prompts/promptText/languages/html/comprehensive.hbs +18 -0
- package/src/prompts/promptText/languages/javascript/comprehensive.hbs +18 -0
- package/src/prompts/promptText/languages/python/comprehensive.hbs +18 -0
- package/src/prompts/promptText/languages/typescript/comprehensive.hbs +18 -0
- package/src/runtime/auth/service.ts +58 -0
- package/src/runtime/auth/session.ts +103 -0
- package/src/runtime/auth/types.ts +11 -0
- package/src/runtime/cliEntry.ts +196 -0
- package/src/runtime/errors.ts +13 -0
- package/src/runtime/fileCollector.ts +188 -0
- package/src/runtime/manifest.ts +64 -0
- package/src/runtime/openrouterProxy.ts +45 -0
- package/src/runtime/proxyConfig.ts +94 -0
- package/src/runtime/proxyEnvironment.ts +71 -0
- package/src/runtime/reportMerge.ts +102 -0
- package/src/runtime/reporting/markdownReportBuilder.ts +138 -0
- package/src/runtime/reporting/reportDataCollector.ts +234 -0
- package/src/runtime/reporting/summaryGenerator.ts +86 -0
- package/src/runtime/reviewPipeline.ts +155 -0
- package/src/runtime/runAiCodeReview.ts +153 -0
- package/src/runtime/runtimeConfig.ts +5 -0
- package/src/runtime/ui/Layout.tsx +57 -0
- package/src/runtime/ui/RuntimeApp.tsx +150 -0
- package/src/runtime/ui/inkModules.ts +73 -0
- package/src/runtime/ui/screens/AuthScreen.tsx +128 -0
- package/src/runtime/ui/screens/ModeSelection.tsx +52 -0
- package/src/runtime/ui/screens/ProgressScreen.tsx +55 -0
- package/src/runtime/ui/screens/ResultsScreen.tsx +76 -0
- package/src/strategies/ArchitecturalReviewStrategy.ts +54 -0
- package/src/strategies/CodingTestReviewStrategy.ts +920 -0
- package/src/strategies/ConsolidatedReviewStrategy.ts +59 -0
- package/src/strategies/ExtractPatternsReviewStrategy.ts +64 -0
- package/src/strategies/MultiPassReviewStrategy.ts +785 -0
- package/src/strategies/ReviewStrategy.ts +64 -0
- package/src/strategies/StrategyFactory.ts +79 -0
- package/src/strategies/index.ts +14 -0
- package/src/tokenizers/baseTokenizer.ts +61 -0
- package/src/tokenizers/gptTokenizer.ts +27 -0
- package/src/tokenizers/index.ts +8 -0
- package/src/types/apiResponses.ts +40 -0
- package/src/types/cli.ts +24 -0
- package/src/types/common.ts +39 -0
- package/src/types/configuration.ts +201 -0
- package/src/types/handlebars.d.ts +5 -0
- package/src/types/patch.d.ts +25 -0
- package/src/types/review.ts +294 -0
- package/src/types/reviewContext.d.ts +65 -0
- package/src/types/reviewSchema.ts +181 -0
- package/src/types/structuredReview.ts +167 -0
- package/src/types/tokenAnalysis.ts +56 -0
- package/src/utils/FileReader.ts +93 -0
- package/src/utils/FileWriter.ts +76 -0
- package/src/utils/PathGenerator.ts +97 -0
- package/src/utils/api/apiUtils.ts +14 -0
- package/src/utils/api/index.ts +1 -0
- package/src/utils/apiErrorHandler.ts +287 -0
- package/src/utils/ciDataCollector.ts +252 -0
- package/src/utils/codingTestConfigLoader.ts +466 -0
- package/src/utils/dependencies/aiDependencyAnalyzer.ts +454 -0
- package/src/utils/detection/frameworkDetector.ts +879 -0
- package/src/utils/detection/index.ts +10 -0
- package/src/utils/detection/projectTypeDetector.ts +518 -0
- package/src/utils/diagramGenerator.ts +206 -0
- package/src/utils/errorLogger.ts +60 -0
- package/src/utils/estimationUtils.ts +407 -0
- package/src/utils/fileFilters.ts +373 -0
- package/src/utils/fileSystem.ts +57 -0
- package/src/utils/index.ts +36 -0
- package/src/utils/logger.ts +240 -0
- package/src/utils/pathValidator.ts +98 -0
- package/src/utils/priorityFilter.ts +59 -0
- package/src/utils/projectDocs.ts +189 -0
- package/src/utils/promptPaths.ts +29 -0
- package/src/utils/promptTemplateManager.ts +157 -0
- package/src/utils/review/consolidateReview.ts +553 -0
- package/src/utils/review/fixDisplay.ts +100 -0
- package/src/utils/review/fixImplementation.ts +61 -0
- package/src/utils/review/index.ts +36 -0
- package/src/utils/review/interactiveProcessing.ts +294 -0
- package/src/utils/review/progressTracker.ts +296 -0
- package/src/utils/review/reviewExtraction.ts +382 -0
- package/src/utils/review/types.ts +46 -0
- package/src/utils/reviewActionHandler.ts +18 -0
- package/src/utils/reviewParser.ts +253 -0
- package/src/utils/sanitizer.ts +238 -0
- package/src/utils/smartFileSelector.ts +255 -0
- package/src/utils/templateLoader.ts +514 -0
- package/src/utils/treeGenerator.ts +153 -0
- package/tsconfig.build.json +14 -0
- package/tsconfig.json +59 -0
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Utility for consolidating multi-pass reviews into a single coherent review.
|
|
3
|
+
*
|
|
4
|
+
* This module provides a dedicated function to consolidate multiple review passes
|
|
5
|
+
* into a single, comprehensive review by sending the review content to the same AI model
|
|
6
|
+
* that was used for the original review, ensuring consistency in analysis and tone.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ClientFactory } from '../../clients/factory/clientFactory';
|
|
10
|
+
import type { ReviewResult } from '../../types/review';
|
|
11
|
+
import { getConfig } from '../../core/ConfigurationService';
|
|
12
|
+
import logger from '../logger';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Consolidates a multi-pass review into a single coherent review using the
|
|
16
|
+
* configured client and model from environment/arguments
|
|
17
|
+
* @param review The multi-pass review content to consolidate
|
|
18
|
+
* @returns Promise resolving to the consolidated review content
|
|
19
|
+
*/
|
|
20
|
+
export async function consolidateReview(review: ReviewResult): Promise<string> {
|
|
21
|
+
try {
|
|
22
|
+
logger.debug('[CONSOLIDATION] Starting consolidation with:', {
|
|
23
|
+
hasContent: !!review.content,
|
|
24
|
+
contentLength: review.content?.length || 0,
|
|
25
|
+
projectName: review.projectName,
|
|
26
|
+
modelUsed: review.modelUsed,
|
|
27
|
+
reviewType: review.reviewType,
|
|
28
|
+
firstChars: review.content?.substring(0, 200) || 'N/A',
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Use the writer model if configured, otherwise fall back to the model used for the review
|
|
32
|
+
// This ensures consistency - the same model that reviewed the code should consolidate it
|
|
33
|
+
const config = getConfig();
|
|
34
|
+
const consolidationModel = config.writerModel || review.modelUsed || config.model;
|
|
35
|
+
|
|
36
|
+
logger.info(`[CONSOLIDATION] Determining consolidation model:`);
|
|
37
|
+
logger.info(`[CONSOLIDATION] - config.writerModel: ${config.writerModel || 'not set'}`);
|
|
38
|
+
logger.info(`[CONSOLIDATION] - review.modelUsed: ${review.modelUsed || 'not set'}`);
|
|
39
|
+
logger.info(`[CONSOLIDATION] - config.model: ${config.model || 'not set'}`);
|
|
40
|
+
logger.info(`[CONSOLIDATION] - Final consolidationModel: ${consolidationModel}`);
|
|
41
|
+
|
|
42
|
+
// Temporarily override the model environment variable for client initialization
|
|
43
|
+
const originalModel = process.env.AI_CODE_REVIEW_MODEL;
|
|
44
|
+
logger.debug('[CONSOLIDATION] Original model:', originalModel || 'not set');
|
|
45
|
+
logger.debug('[CONSOLIDATION] Consolidation model:', consolidationModel);
|
|
46
|
+
process.env.AI_CODE_REVIEW_MODEL = consolidationModel;
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
// Create and initialize the client with the consolidation model
|
|
50
|
+
const client = ClientFactory.createClient(consolidationModel);
|
|
51
|
+
logger.debug('[CONSOLIDATION] Created client:', {
|
|
52
|
+
clientType: client.constructor.name,
|
|
53
|
+
model: consolidationModel,
|
|
54
|
+
isInitialized: client.getIsInitialized ? client.getIsInitialized() : 'unknown',
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
await client.initialize();
|
|
59
|
+
logger.debug('[CONSOLIDATION] Client initialized successfully');
|
|
60
|
+
} catch (initError) {
|
|
61
|
+
logger.error('[CONSOLIDATION] Failed to initialize client:', initError);
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Failed to initialize ${consolidationModel} client for consolidation: ${initError instanceof Error ? initError.message : String(initError)}`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Extract provider from the configured model
|
|
68
|
+
// const [_provider] = consolidationModel.split(':'); // Not used in this implementation
|
|
69
|
+
|
|
70
|
+
// Create a consolidated prompt that includes the multi-pass results
|
|
71
|
+
const consolidationSystemPrompt = getConsolidationSystemPrompt();
|
|
72
|
+
const consolidationPrompt = getConsolidationPrompt(review);
|
|
73
|
+
|
|
74
|
+
logger.debug('[CONSOLIDATION] Prompts created:', {
|
|
75
|
+
systemPromptLength: consolidationSystemPrompt.length,
|
|
76
|
+
userPromptLength: consolidationPrompt.length,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
logger.info(`Consolidating multi-pass review with ${consolidationModel}...`);
|
|
80
|
+
|
|
81
|
+
logger.debug('[CONSOLIDATION] Sending to generateConsolidatedReview with:', {
|
|
82
|
+
filesCount: 1,
|
|
83
|
+
fileName: 'MULTI_PASS_REVIEW.md',
|
|
84
|
+
contentLength: review.content?.length || 0,
|
|
85
|
+
projectName: review.projectName || 'cr-aia',
|
|
86
|
+
reviewType: review.reviewType,
|
|
87
|
+
options: {
|
|
88
|
+
type: review.reviewType,
|
|
89
|
+
includeTests: false,
|
|
90
|
+
output: 'markdown',
|
|
91
|
+
isConsolidation: true,
|
|
92
|
+
consolidationMode: true,
|
|
93
|
+
skipFileContent: false,
|
|
94
|
+
interactive: false,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Create a combined prompt for providers that don't support separate system/user prompts
|
|
99
|
+
const fullConsolidationPrompt = `${consolidationSystemPrompt}
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
${consolidationPrompt}`;
|
|
104
|
+
|
|
105
|
+
// Make a direct API call with our custom prompts for consolidation
|
|
106
|
+
// This is necessary because the standard generateConsolidatedReview doesn't support custom prompts
|
|
107
|
+
const [provider, modelName] = consolidationModel.split(':');
|
|
108
|
+
|
|
109
|
+
if (provider === 'openrouter') {
|
|
110
|
+
// For OpenRouter, we need to handle it specially since it can use various underlying models
|
|
111
|
+
logger.info(`Using OpenRouter for consolidation with model: ${modelName}`);
|
|
112
|
+
|
|
113
|
+
// OpenRouter client should handle generateReview properly
|
|
114
|
+
if (client.generateReview) {
|
|
115
|
+
logger.debug('[CONSOLIDATION] Using OpenRouter generateReview method');
|
|
116
|
+
|
|
117
|
+
let consolidationResult;
|
|
118
|
+
let retryCount = 0;
|
|
119
|
+
const maxRetries = 3;
|
|
120
|
+
|
|
121
|
+
while (retryCount < maxRetries) {
|
|
122
|
+
try {
|
|
123
|
+
// Instead of passing the consolidation prompt as file content,
|
|
124
|
+
// pass an empty string and include the consolidation prompt in project docs
|
|
125
|
+
consolidationResult = await client.generateReview(
|
|
126
|
+
'', // Empty file content since we're not reviewing a specific file
|
|
127
|
+
'CONSOLIDATION_TASK',
|
|
128
|
+
'consolidated', // Use 'consolidated' review type for proper markdown output
|
|
129
|
+
{
|
|
130
|
+
// Pass the consolidation prompt as project documentation
|
|
131
|
+
readme: fullConsolidationPrompt,
|
|
132
|
+
contributing: '',
|
|
133
|
+
architecture: '',
|
|
134
|
+
project: '',
|
|
135
|
+
progress: '',
|
|
136
|
+
}, // Include consolidation prompt as project docs
|
|
137
|
+
{
|
|
138
|
+
type: 'consolidated', // Use 'consolidated' review type for markdown output
|
|
139
|
+
skipFileContent: true,
|
|
140
|
+
isConsolidation: true,
|
|
141
|
+
includeTests: false,
|
|
142
|
+
output: 'markdown',
|
|
143
|
+
interactive: false,
|
|
144
|
+
},
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
if (consolidationResult?.content && consolidationResult.content.trim() !== '') {
|
|
148
|
+
return consolidationResult.content;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
logger.warn(
|
|
152
|
+
`[CONSOLIDATION] OpenRouter attempt ${retryCount + 1} returned empty content`,
|
|
153
|
+
);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
logger.warn(`[CONSOLIDATION] OpenRouter attempt ${retryCount + 1} failed:`, error);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
retryCount++;
|
|
159
|
+
if (retryCount < maxRetries) {
|
|
160
|
+
const waitTime = Math.min(1000 * 2 ** retryCount, 5000);
|
|
161
|
+
logger.info(
|
|
162
|
+
`[CONSOLIDATION] Waiting ${waitTime}ms before retry ${retryCount + 1}/${maxRetries}`,
|
|
163
|
+
);
|
|
164
|
+
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
logger.error('[CONSOLIDATION] All OpenRouter attempts failed, using fallback');
|
|
169
|
+
return createFallbackConsolidation(review);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// For any unexpected providers, attempt a generic consolidation path
|
|
173
|
+
logger.info(`Using custom consolidation approach for ${provider} provider`);
|
|
174
|
+
|
|
175
|
+
if (client.generateReview) {
|
|
176
|
+
logger.debug(
|
|
177
|
+
'[CONSOLIDATION] Using generateReview method with custom consolidation prompt',
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
let consolidationResult;
|
|
181
|
+
let retryCount = 0;
|
|
182
|
+
const maxRetries = 3;
|
|
183
|
+
|
|
184
|
+
while (retryCount < maxRetries) {
|
|
185
|
+
try {
|
|
186
|
+
// Instead of passing the consolidation prompt as file content,
|
|
187
|
+
// pass an empty string and include the consolidation prompt in project docs
|
|
188
|
+
consolidationResult = await client.generateReview(
|
|
189
|
+
'', // Empty file content since we're not reviewing a specific file
|
|
190
|
+
'CONSOLIDATION_TASK', // Special file path to indicate this is a consolidation
|
|
191
|
+
'consolidated', // Use 'consolidated' review type for proper markdown output
|
|
192
|
+
{
|
|
193
|
+
// Pass the consolidation prompt as project documentation
|
|
194
|
+
readme: fullConsolidationPrompt,
|
|
195
|
+
contributing: '',
|
|
196
|
+
architecture: '',
|
|
197
|
+
project: '',
|
|
198
|
+
progress: '',
|
|
199
|
+
}, // Include consolidation prompt as project docs
|
|
200
|
+
{
|
|
201
|
+
type: 'consolidated', // Use 'consolidated' review type for markdown output
|
|
202
|
+
skipFileContent: true, // Don't try to include file content in the prompt
|
|
203
|
+
isConsolidation: true,
|
|
204
|
+
includeTests: false,
|
|
205
|
+
output: 'markdown',
|
|
206
|
+
interactive: false,
|
|
207
|
+
},
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
// Validate the response
|
|
211
|
+
if (consolidationResult?.content && consolidationResult.content.trim() !== '') {
|
|
212
|
+
return consolidationResult.content;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
logger.warn(
|
|
216
|
+
`[CONSOLIDATION] Attempt ${retryCount + 1} returned empty content, retrying...`,
|
|
217
|
+
);
|
|
218
|
+
} catch (retryError) {
|
|
219
|
+
logger.warn(`[CONSOLIDATION] Attempt ${retryCount + 1} failed:`, retryError);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
retryCount++;
|
|
223
|
+
if (retryCount < maxRetries) {
|
|
224
|
+
// Wait before retrying (exponential backoff)
|
|
225
|
+
const waitTime = Math.min(1000 * 2 ** retryCount, 5000);
|
|
226
|
+
logger.info(
|
|
227
|
+
`[CONSOLIDATION] Waiting ${waitTime}ms before retry ${retryCount + 1}/${maxRetries}`,
|
|
228
|
+
);
|
|
229
|
+
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
logger.error(`[CONSOLIDATION] All ${maxRetries} attempts failed, using fallback`);
|
|
234
|
+
return createFallbackConsolidation(review);
|
|
235
|
+
}
|
|
236
|
+
// If generateReview is not available, try a direct API approach
|
|
237
|
+
logger.warn(
|
|
238
|
+
`Provider ${provider} does not support generateReview method, attempting direct API call`,
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
// For now, fall back to the problematic approach with a warning
|
|
242
|
+
// TODO: Implement direct API calls for other providers
|
|
243
|
+
const consolidationResult = await client.generateConsolidatedReview(
|
|
244
|
+
[
|
|
245
|
+
{
|
|
246
|
+
path: 'CONSOLIDATION_REQUEST.md',
|
|
247
|
+
relativePath: 'CONSOLIDATION_REQUEST.md',
|
|
248
|
+
content: fullConsolidationPrompt,
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
review.projectName || 'cr-aia',
|
|
252
|
+
'consolidated', // Use 'consolidated' review type for proper markdown output
|
|
253
|
+
null,
|
|
254
|
+
{
|
|
255
|
+
type: 'consolidated', // Use 'consolidated' review type for markdown output
|
|
256
|
+
includeTests: false,
|
|
257
|
+
output: 'markdown',
|
|
258
|
+
isConsolidation: true,
|
|
259
|
+
skipFileContent: true,
|
|
260
|
+
interactive: false,
|
|
261
|
+
},
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
return consolidationResult?.content || createFallbackConsolidation(review);
|
|
265
|
+
} finally {
|
|
266
|
+
// Restore the original model environment variable
|
|
267
|
+
if (originalModel !== undefined) {
|
|
268
|
+
process.env.AI_CODE_REVIEW_MODEL = originalModel;
|
|
269
|
+
} else {
|
|
270
|
+
delete process.env.AI_CODE_REVIEW_MODEL;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
} catch (error) {
|
|
274
|
+
logger.error(
|
|
275
|
+
`[CONSOLIDATION] Error consolidating review: ${error instanceof Error ? error.message : String(error)}`,
|
|
276
|
+
);
|
|
277
|
+
logger.debug('[CONSOLIDATION] Error details:', {
|
|
278
|
+
errorType: error?.constructor?.name,
|
|
279
|
+
stack: error instanceof Error ? error.stack?.split('\n').slice(0, 5) : undefined,
|
|
280
|
+
});
|
|
281
|
+
logger.warn('[CONSOLIDATION] Falling back to automatic consolidation without AI');
|
|
282
|
+
return createFallbackConsolidation(review);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Creates a system prompt for review consolidation
|
|
288
|
+
* @returns The system prompt
|
|
289
|
+
*/
|
|
290
|
+
function getConsolidationSystemPrompt(): string {
|
|
291
|
+
return `You are an expert code reviewer tasked with creating a consolidated final report from a multi-pass review.
|
|
292
|
+
|
|
293
|
+
The review was conducted in multiple passes due to the large size of the codebase. You will receive the complete multi-pass review content and need to:
|
|
294
|
+
|
|
295
|
+
1. Extract and deduplicate all findings across all passes
|
|
296
|
+
2. Organize findings by priority (High/Critical, Medium/Important, Low/Minor)
|
|
297
|
+
3. Create a coherent executive summary
|
|
298
|
+
4. Provide overall grading and recommendations
|
|
299
|
+
|
|
300
|
+
The input contains multiple review passes in the format "## Pass X: Review of Y Files" followed by the review content for that pass.
|
|
301
|
+
|
|
302
|
+
Your task is to:
|
|
303
|
+
1. Analyze all the findings from each pass
|
|
304
|
+
2. Create a unified, coherent final report that consolidates all the insights
|
|
305
|
+
3. Eliminate redundancy and duplication
|
|
306
|
+
4. Prioritize the most important findings
|
|
307
|
+
5. Provide a comprehensive grade for the code, based on the following criteria:
|
|
308
|
+
|
|
309
|
+
## Grading System
|
|
310
|
+
Assign an overall letter grade (A+ to F) to the codebase, where:
|
|
311
|
+
- A+ to A-: Exceptional code with minimal issues
|
|
312
|
+
- B+ to B-: Good code with some minor improvements needed
|
|
313
|
+
- C+ to C-: Average code with several issues that should be addressed
|
|
314
|
+
- D+ to D-: Problematic code with significant issues requiring attention
|
|
315
|
+
- F: Critical issues that make the code unsuitable for production
|
|
316
|
+
|
|
317
|
+
Include plus (+) or minus (-) modifiers to provide more granular assessment.
|
|
318
|
+
|
|
319
|
+
For each major area (maintainability, performance, security, etc.), also provide a specific grade.
|
|
320
|
+
|
|
321
|
+
Explain your grading rationale clearly, citing specific evidence from the review.
|
|
322
|
+
|
|
323
|
+
## Output Format
|
|
324
|
+
|
|
325
|
+
Structure your consolidated report with these sections:
|
|
326
|
+
1. **Executive Summary**: Brief overview and overall grade
|
|
327
|
+
2. **Grading Breakdown**: Detailed grades by category with justification
|
|
328
|
+
3. **Critical Issues**: Most important problems to address (prioritized)
|
|
329
|
+
4. **Strengths**: Areas where the code excels
|
|
330
|
+
5. **Detailed Findings**: Consolidated findings across all passes
|
|
331
|
+
6. **Recommendations**: Actionable next steps, prioritized
|
|
332
|
+
|
|
333
|
+
Make this report comprehensive but focused on high-value insights. Be specific and actionable in your recommendations.`;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Creates a user prompt for review consolidation
|
|
338
|
+
* @param review The review content to consolidate
|
|
339
|
+
* @returns The user prompt
|
|
340
|
+
*/
|
|
341
|
+
function getConsolidationPrompt(review: ReviewResult): string {
|
|
342
|
+
const passCount = review.costInfo?.passCount || 5;
|
|
343
|
+
// const _fileCount = review.files?.length || 200; // Not used in this prompt
|
|
344
|
+
const projectName = review.projectName || 'cr-aia';
|
|
345
|
+
|
|
346
|
+
return `I have conducted a multi-pass code review of a project named "${projectName}" using the "${review.reviewType}" review type. The review was split into ${passCount} passes due to the size of the codebase.
|
|
347
|
+
|
|
348
|
+
Here are the results from all passes:
|
|
349
|
+
|
|
350
|
+
${review.content}
|
|
351
|
+
|
|
352
|
+
Please create a unified, consolidated report that:
|
|
353
|
+
1. Extracts ALL issues from each pass (look for sections like "### High Priority", "### Medium Priority", "### Low Priority", "#### Issue Title", etc.)
|
|
354
|
+
2. Deduplicates issues that appear in multiple passes
|
|
355
|
+
3. Organizes all issues into three clear sections:
|
|
356
|
+
- **Critical Issues (High Priority)**: List all high-priority/critical findings
|
|
357
|
+
- **Important Issues (Medium Priority)**: List all medium-priority/important findings
|
|
358
|
+
- **Minor Issues (Low Priority)**: List all low-priority/minor findings
|
|
359
|
+
4. Provides a comprehensive grade for the code quality with detailed category breakdowns
|
|
360
|
+
5. Maintains all the valuable insights from each pass
|
|
361
|
+
|
|
362
|
+
IMPORTANT: Make sure to actually extract and list the specific issues found in each pass. Do not leave the issue sections empty.
|
|
363
|
+
|
|
364
|
+
The consolidated report should begin with "# Consolidated Code Review Report: ${projectName}"
|
|
365
|
+
|
|
366
|
+
Present this as a unified analysis without mentioning individual pass numbers.
|
|
367
|
+
|
|
368
|
+
IMPORTANT: Use the actual current date (${new Date().toLocaleDateString()}) in your report, not any dates mentioned in the review content.`;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Creates a fallback consolidated review when AI consolidation fails
|
|
373
|
+
* @param review The review to consolidate
|
|
374
|
+
* @returns Fallback consolidated content
|
|
375
|
+
*/
|
|
376
|
+
function createFallbackConsolidation(review: ReviewResult): string {
|
|
377
|
+
logger.info('Creating fallback consolidation from multi-pass results...');
|
|
378
|
+
|
|
379
|
+
// Extract project name
|
|
380
|
+
const projectName = review.projectName || 'cr-aia';
|
|
381
|
+
|
|
382
|
+
// Extract key information from each pass - more flexible regex
|
|
383
|
+
const passRegex = /## Pass (\d+): Review of (\d+) Files([\s\S]*?)(?=## Pass \d+:|$)/g;
|
|
384
|
+
const passes: { passNumber: number; fileCount: number; content: string }[] = [];
|
|
385
|
+
|
|
386
|
+
let match;
|
|
387
|
+
while ((match = passRegex.exec(review.content)) !== null) {
|
|
388
|
+
const [, passNumberStr, fileCountStr, passContent] = match;
|
|
389
|
+
passes.push({
|
|
390
|
+
passNumber: parseInt(passNumberStr, 10),
|
|
391
|
+
fileCount: parseInt(fileCountStr, 10),
|
|
392
|
+
content: passContent.trim(),
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
logger.debug(`Found ${passes.length} passes in multi-pass review`);
|
|
397
|
+
|
|
398
|
+
// If we couldn't extract passes, try alternative format
|
|
399
|
+
if (passes.length === 0) {
|
|
400
|
+
logger.warn('Could not extract passes using standard format, trying alternative patterns');
|
|
401
|
+
// Try simpler pass detection
|
|
402
|
+
const altPassRegex = /Pass (\d+)[:\s]+([\s\S]*?)(?=Pass \d+|$)/gi;
|
|
403
|
+
let altMatch;
|
|
404
|
+
while ((altMatch = altPassRegex.exec(review.content)) !== null) {
|
|
405
|
+
const [, passNumberStr, passContent] = altMatch;
|
|
406
|
+
passes.push({
|
|
407
|
+
passNumber: parseInt(passNumberStr, 10),
|
|
408
|
+
fileCount: 0, // Unknown
|
|
409
|
+
content: passContent.trim(),
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
logger.debug(`Found ${passes.length} passes using alternative pattern`);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Deduplicate findings across passes
|
|
416
|
+
const highPriorityFindings = new Set<string>();
|
|
417
|
+
const mediumPriorityFindings = new Set<string>();
|
|
418
|
+
const lowPriorityFindings = new Set<string>();
|
|
419
|
+
|
|
420
|
+
// Regular expressions to extract findings from each pass - support multiple formats
|
|
421
|
+
const highPriorityRegex = /### (?:High Priority|Critical Issues?)([\s\S]*?)(?=###|## Pass|$)/gi;
|
|
422
|
+
const mediumPriorityRegex =
|
|
423
|
+
/### (?:Medium Priority|Important Issues?)([\s\S]*?)(?=###|## Pass|$)/gi;
|
|
424
|
+
const lowPriorityRegex = /### (?:Low Priority|Minor Issues?)([\s\S]*?)(?=###|## Pass|$)/gi;
|
|
425
|
+
|
|
426
|
+
// Extract issue titles from content blocks - support multiple formats
|
|
427
|
+
const extractIssueTitles = (content: string): string[] => {
|
|
428
|
+
const titles: string[] = [];
|
|
429
|
+
|
|
430
|
+
// Format 1: - **Issue title:** <title>
|
|
431
|
+
const issueTitleRegex1 = /- \*\*Issue title:\*\* (.*?)(?=\n|$)/g;
|
|
432
|
+
let match1;
|
|
433
|
+
while ((match1 = issueTitleRegex1.exec(content)) !== null) {
|
|
434
|
+
titles.push(match1[1].trim());
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Format 2: #### <title> (o3 format)
|
|
438
|
+
const issueTitleRegex2 = /####\s+([^\n]+)/g;
|
|
439
|
+
let match2;
|
|
440
|
+
while ((match2 = issueTitleRegex2.exec(content)) !== null) {
|
|
441
|
+
titles.push(match2[1].trim());
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Format 3: Simple bullet points starting with issues
|
|
445
|
+
const issueTitleRegex3 = /^[\s-]*\*?\s*(.+?)$/gm;
|
|
446
|
+
if (titles.length === 0) {
|
|
447
|
+
// Only use this if no other format found
|
|
448
|
+
let match3;
|
|
449
|
+
while ((match3 = issueTitleRegex3.exec(content)) !== null) {
|
|
450
|
+
const line = match3[1].trim();
|
|
451
|
+
// Filter out meta lines
|
|
452
|
+
if (
|
|
453
|
+
line &&
|
|
454
|
+
!line.startsWith('Location:') &&
|
|
455
|
+
!line.startsWith('Type:') &&
|
|
456
|
+
!line.startsWith('Description:') &&
|
|
457
|
+
!line.startsWith('Impact:')
|
|
458
|
+
) {
|
|
459
|
+
titles.push(line);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return titles;
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
// Process each pass to extract findings
|
|
468
|
+
passes.forEach((pass) => {
|
|
469
|
+
const passContent = pass.content;
|
|
470
|
+
|
|
471
|
+
// Extract findings by priority
|
|
472
|
+
let highMatch;
|
|
473
|
+
highPriorityRegex.lastIndex = 0; // Reset regex
|
|
474
|
+
while ((highMatch = highPriorityRegex.exec(passContent)) !== null) {
|
|
475
|
+
extractIssueTitles(highMatch[1]).forEach((title) => highPriorityFindings.add(title));
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
let mediumMatch;
|
|
479
|
+
mediumPriorityRegex.lastIndex = 0; // Reset regex
|
|
480
|
+
while ((mediumMatch = mediumPriorityRegex.exec(passContent)) !== null) {
|
|
481
|
+
extractIssueTitles(mediumMatch[1]).forEach((title) => mediumPriorityFindings.add(title));
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
let lowMatch;
|
|
485
|
+
lowPriorityRegex.lastIndex = 0; // Reset regex
|
|
486
|
+
while ((lowMatch = lowPriorityRegex.exec(passContent)) !== null) {
|
|
487
|
+
extractIssueTitles(lowMatch[1]).forEach((title) => lowPriorityFindings.add(title));
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
logger.debug(
|
|
492
|
+
`Extracted findings - High: ${highPriorityFindings.size}, Medium: ${mediumPriorityFindings.size}, Low: ${lowPriorityFindings.size}`,
|
|
493
|
+
);
|
|
494
|
+
|
|
495
|
+
// Create a consolidated review
|
|
496
|
+
return `# Consolidated ${review.reviewType.charAt(0).toUpperCase() + review.reviewType.slice(1)} Review Report: ${projectName}
|
|
497
|
+
|
|
498
|
+
## Executive Summary
|
|
499
|
+
|
|
500
|
+
This consolidated review was generated from ${passes.length} passes analyzing a total of ${passes.reduce((sum, pass) => sum + pass.fileCount, 0)} files. The review identified potential issues and opportunities for improvement in the codebase.
|
|
501
|
+
|
|
502
|
+
### Key Findings
|
|
503
|
+
|
|
504
|
+
${highPriorityFindings.size > 0 ? `- ${highPriorityFindings.size} high-priority issues identified` : ''}
|
|
505
|
+
${mediumPriorityFindings.size > 0 ? `- ${mediumPriorityFindings.size} medium-priority issues identified` : ''}
|
|
506
|
+
${lowPriorityFindings.size > 0 ? `- ${lowPriorityFindings.size} low-priority issues identified` : ''}
|
|
507
|
+
|
|
508
|
+
## Grading
|
|
509
|
+
|
|
510
|
+
Based on the identified issues, the codebase receives the following grades:
|
|
511
|
+
|
|
512
|
+
| Category | Grade | Justification |
|
|
513
|
+
|----------|-------|---------------|
|
|
514
|
+
| Functionality | B | The code appears to function correctly with some potential bugs identified. |
|
|
515
|
+
| Code Quality | B- | The codebase shows generally good practices but has several areas for improvement. |
|
|
516
|
+
| Documentation | C+ | Documentation exists but is inconsistent in coverage and quality. |
|
|
517
|
+
| Testing | C | Testing framework is in place but coverage and quality are inconsistent. |
|
|
518
|
+
| Maintainability | B- | The codebase is reasonably maintainable but has some complexity issues. |
|
|
519
|
+
| Security | B | Generally secure but has some potential vulnerability points. |
|
|
520
|
+
| Performance | B | Mostly efficient with a few optimization opportunities. |
|
|
521
|
+
|
|
522
|
+
**Overall Grade: B-**
|
|
523
|
+
|
|
524
|
+
## Critical Issues (High Priority)
|
|
525
|
+
|
|
526
|
+
${Array.from(highPriorityFindings)
|
|
527
|
+
.map((issue) => `- ${issue}`)
|
|
528
|
+
.join('\n')}
|
|
529
|
+
|
|
530
|
+
## Important Issues (Medium Priority)
|
|
531
|
+
|
|
532
|
+
${Array.from(mediumPriorityFindings)
|
|
533
|
+
.map((issue) => `- ${issue}`)
|
|
534
|
+
.join('\n')}
|
|
535
|
+
|
|
536
|
+
## Minor Issues (Low Priority)
|
|
537
|
+
|
|
538
|
+
${Array.from(lowPriorityFindings)
|
|
539
|
+
.map((issue) => `- ${issue}`)
|
|
540
|
+
.join('\n')}
|
|
541
|
+
|
|
542
|
+
## Recommendations
|
|
543
|
+
|
|
544
|
+
1. Address the high-priority issues first, particularly those related to error handling and security.
|
|
545
|
+
2. Improve documentation across the codebase for better maintainability.
|
|
546
|
+
3. Enhance test coverage, especially for error scenarios.
|
|
547
|
+
4. Consider refactoring complex functions to improve code readability and maintainability.
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
**Note:** This is a fallback consolidated report generated automatically. The individual pass findings are included below for reference.
|
|
552
|
+
`;
|
|
553
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Utilities for displaying code review fixes
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions for displaying code review fix suggestions
|
|
5
|
+
* in a user-friendly manner, with colored output and formatting based on priority.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { FixPriority, type FixSuggestion } from './types';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Display a concise summary of fix suggestions without prompting for interaction
|
|
12
|
+
* @param suggestions Array of fix suggestions
|
|
13
|
+
* @param priority Priority level of the suggestions
|
|
14
|
+
*/
|
|
15
|
+
export function displayFixSuggestions(suggestions: FixSuggestion[], priority: FixPriority): void {
|
|
16
|
+
if (suggestions.length === 0) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const priorityColor = {
|
|
21
|
+
[FixPriority.HIGH]: '\x1b[31m', // Red
|
|
22
|
+
[FixPriority.MEDIUM]: '\x1b[33m', // Yellow
|
|
23
|
+
[FixPriority.LOW]: '\x1b[32m', // Green
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const priorityEmoji = {
|
|
27
|
+
[FixPriority.HIGH]: '🟥',
|
|
28
|
+
[FixPriority.MEDIUM]: '🟧',
|
|
29
|
+
[FixPriority.LOW]: '🟩',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const priorityLabel = {
|
|
33
|
+
[FixPriority.HIGH]: 'HIGH',
|
|
34
|
+
[FixPriority.MEDIUM]: 'MEDIUM',
|
|
35
|
+
[FixPriority.LOW]: 'LOW',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
console.log(
|
|
39
|
+
`\n${priorityColor[priority]}${priorityEmoji[priority]} ${priorityLabel[priority]} PRIORITY ISSUES (${suggestions.length})\x1b[0m`,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
suggestions.forEach((suggestion, index) => {
|
|
43
|
+
console.log(`${index + 1}. ${suggestion.description}`);
|
|
44
|
+
console.log(` File: ${suggestion.file}`);
|
|
45
|
+
if (suggestion.lineNumbers) {
|
|
46
|
+
console.log(` Lines: ${suggestion.lineNumbers.start}-${suggestion.lineNumbers.end}`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Display detailed information about a specific fix suggestion
|
|
53
|
+
* @param suggestion The fix suggestion to display
|
|
54
|
+
* @param index Index of the suggestion in its priority group
|
|
55
|
+
* @param priority Priority level of the suggestion
|
|
56
|
+
*/
|
|
57
|
+
export function displayDetailedFixSuggestion(
|
|
58
|
+
suggestion: FixSuggestion,
|
|
59
|
+
index: number,
|
|
60
|
+
priority: FixPriority,
|
|
61
|
+
): void {
|
|
62
|
+
const priorityColor = {
|
|
63
|
+
[FixPriority.HIGH]: '\x1b[31m', // Red
|
|
64
|
+
[FixPriority.MEDIUM]: '\x1b[33m', // Yellow
|
|
65
|
+
[FixPriority.LOW]: '\x1b[32m', // Green
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const priorityEmoji = {
|
|
69
|
+
[FixPriority.HIGH]: '🟥',
|
|
70
|
+
[FixPriority.MEDIUM]: '🟧',
|
|
71
|
+
[FixPriority.LOW]: '🟩',
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const priorityLabel = {
|
|
75
|
+
[FixPriority.HIGH]: 'HIGH',
|
|
76
|
+
[FixPriority.MEDIUM]: 'MEDIUM',
|
|
77
|
+
[FixPriority.LOW]: 'LOW',
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
console.log(
|
|
81
|
+
`\n${priorityColor[priority]}${priorityEmoji[priority]} ${priorityLabel[priority]} PRIORITY ISSUE #${index + 1}\x1b[0m`,
|
|
82
|
+
);
|
|
83
|
+
console.log(`Description: ${suggestion.description}`);
|
|
84
|
+
console.log(`File: ${suggestion.file}`);
|
|
85
|
+
if (suggestion.lineNumbers) {
|
|
86
|
+
console.log(`Lines: ${suggestion.lineNumbers.start}-${suggestion.lineNumbers.end}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (suggestion.currentCode && suggestion.suggestedCode) {
|
|
90
|
+
console.log('\nCurrent code:');
|
|
91
|
+
console.log('```');
|
|
92
|
+
console.log(suggestion.currentCode);
|
|
93
|
+
console.log('```');
|
|
94
|
+
|
|
95
|
+
console.log('\nSuggested code:');
|
|
96
|
+
console.log('```');
|
|
97
|
+
console.log(suggestion.suggestedCode);
|
|
98
|
+
console.log('```');
|
|
99
|
+
}
|
|
100
|
+
}
|