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.
Files changed (153) hide show
  1. package/.cr-aia.yml +23 -0
  2. package/.crignore +0 -0
  3. package/dist/index.js +27 -0
  4. package/package.json +85 -0
  5. package/src/analysis/FindingsExtractor.ts +431 -0
  6. package/src/analysis/ai-detection/analyzers/BaseAnalyzer.ts +267 -0
  7. package/src/analysis/ai-detection/analyzers/DocumentationAnalyzer.ts +622 -0
  8. package/src/analysis/ai-detection/analyzers/GitHistoryAnalyzer.ts +430 -0
  9. package/src/analysis/ai-detection/core/AIDetectionEngine.ts +467 -0
  10. package/src/analysis/ai-detection/types/DetectionTypes.ts +406 -0
  11. package/src/analysis/ai-detection/utils/SubmissionConverter.ts +390 -0
  12. package/src/analysis/context/ReviewContext.ts +378 -0
  13. package/src/analysis/context/index.ts +7 -0
  14. package/src/analysis/index.ts +8 -0
  15. package/src/analysis/tokens/TokenAnalysisFormatter.ts +154 -0
  16. package/src/analysis/tokens/TokenAnalyzer.ts +747 -0
  17. package/src/analysis/tokens/index.ts +8 -0
  18. package/src/clients/base/abstractClient.ts +190 -0
  19. package/src/clients/base/httpClient.ts +160 -0
  20. package/src/clients/base/index.ts +12 -0
  21. package/src/clients/base/modelDetection.ts +107 -0
  22. package/src/clients/base/responseProcessor.ts +586 -0
  23. package/src/clients/factory/clientFactory.ts +55 -0
  24. package/src/clients/factory/index.ts +8 -0
  25. package/src/clients/implementations/index.ts +8 -0
  26. package/src/clients/implementations/openRouterClient.ts +411 -0
  27. package/src/clients/openRouterClient.ts +863 -0
  28. package/src/clients/openRouterClientWrapper.ts +44 -0
  29. package/src/clients/utils/directoryStructure.ts +52 -0
  30. package/src/clients/utils/index.ts +11 -0
  31. package/src/clients/utils/languageDetection.ts +44 -0
  32. package/src/clients/utils/promptFormatter.ts +105 -0
  33. package/src/clients/utils/promptLoader.ts +53 -0
  34. package/src/clients/utils/tokenCounter.ts +297 -0
  35. package/src/core/ApiClientSelector.ts +37 -0
  36. package/src/core/ConfigurationService.ts +591 -0
  37. package/src/core/ConsolidationService.ts +423 -0
  38. package/src/core/InteractiveDisplayManager.ts +81 -0
  39. package/src/core/OutputManager.ts +275 -0
  40. package/src/core/ReviewGenerator.ts +140 -0
  41. package/src/core/fileDiscovery.ts +237 -0
  42. package/src/core/handlers/EstimationHandler.ts +104 -0
  43. package/src/core/handlers/FileProcessingHandler.ts +204 -0
  44. package/src/core/handlers/OutputHandler.ts +125 -0
  45. package/src/core/handlers/ReviewExecutor.ts +104 -0
  46. package/src/core/reviewOrchestrator.ts +333 -0
  47. package/src/core/utils/ModelInfoUtils.ts +56 -0
  48. package/src/formatters/outputFormatter.ts +62 -0
  49. package/src/formatters/utils/IssueFormatters.ts +83 -0
  50. package/src/formatters/utils/JsonFormatter.ts +77 -0
  51. package/src/formatters/utils/MarkdownFormatters.ts +609 -0
  52. package/src/formatters/utils/MetadataFormatter.ts +269 -0
  53. package/src/formatters/utils/ModelInfoExtractor.ts +115 -0
  54. package/src/index.ts +27 -0
  55. package/src/plugins/PluginInterface.ts +50 -0
  56. package/src/plugins/PluginManager.ts +126 -0
  57. package/src/prompts/PromptManager.ts +69 -0
  58. package/src/prompts/cache/PromptCache.ts +50 -0
  59. package/src/prompts/promptText/common/variables/css-frameworks.json +33 -0
  60. package/src/prompts/promptText/common/variables/framework-versions.json +45 -0
  61. package/src/prompts/promptText/frameworks/react/comprehensive.hbs +19 -0
  62. package/src/prompts/promptText/languages/css/comprehensive.hbs +18 -0
  63. package/src/prompts/promptText/languages/generic/comprehensive.hbs +20 -0
  64. package/src/prompts/promptText/languages/html/comprehensive.hbs +18 -0
  65. package/src/prompts/promptText/languages/javascript/comprehensive.hbs +18 -0
  66. package/src/prompts/promptText/languages/python/comprehensive.hbs +18 -0
  67. package/src/prompts/promptText/languages/typescript/comprehensive.hbs +18 -0
  68. package/src/runtime/auth/service.ts +58 -0
  69. package/src/runtime/auth/session.ts +103 -0
  70. package/src/runtime/auth/types.ts +11 -0
  71. package/src/runtime/cliEntry.ts +196 -0
  72. package/src/runtime/errors.ts +13 -0
  73. package/src/runtime/fileCollector.ts +188 -0
  74. package/src/runtime/manifest.ts +64 -0
  75. package/src/runtime/openrouterProxy.ts +45 -0
  76. package/src/runtime/proxyConfig.ts +94 -0
  77. package/src/runtime/proxyEnvironment.ts +71 -0
  78. package/src/runtime/reportMerge.ts +102 -0
  79. package/src/runtime/reporting/markdownReportBuilder.ts +138 -0
  80. package/src/runtime/reporting/reportDataCollector.ts +234 -0
  81. package/src/runtime/reporting/summaryGenerator.ts +86 -0
  82. package/src/runtime/reviewPipeline.ts +155 -0
  83. package/src/runtime/runAiCodeReview.ts +153 -0
  84. package/src/runtime/runtimeConfig.ts +5 -0
  85. package/src/runtime/ui/Layout.tsx +57 -0
  86. package/src/runtime/ui/RuntimeApp.tsx +150 -0
  87. package/src/runtime/ui/inkModules.ts +73 -0
  88. package/src/runtime/ui/screens/AuthScreen.tsx +128 -0
  89. package/src/runtime/ui/screens/ModeSelection.tsx +52 -0
  90. package/src/runtime/ui/screens/ProgressScreen.tsx +55 -0
  91. package/src/runtime/ui/screens/ResultsScreen.tsx +76 -0
  92. package/src/strategies/ArchitecturalReviewStrategy.ts +54 -0
  93. package/src/strategies/CodingTestReviewStrategy.ts +920 -0
  94. package/src/strategies/ConsolidatedReviewStrategy.ts +59 -0
  95. package/src/strategies/ExtractPatternsReviewStrategy.ts +64 -0
  96. package/src/strategies/MultiPassReviewStrategy.ts +785 -0
  97. package/src/strategies/ReviewStrategy.ts +64 -0
  98. package/src/strategies/StrategyFactory.ts +79 -0
  99. package/src/strategies/index.ts +14 -0
  100. package/src/tokenizers/baseTokenizer.ts +61 -0
  101. package/src/tokenizers/gptTokenizer.ts +27 -0
  102. package/src/tokenizers/index.ts +8 -0
  103. package/src/types/apiResponses.ts +40 -0
  104. package/src/types/cli.ts +24 -0
  105. package/src/types/common.ts +39 -0
  106. package/src/types/configuration.ts +201 -0
  107. package/src/types/handlebars.d.ts +5 -0
  108. package/src/types/patch.d.ts +25 -0
  109. package/src/types/review.ts +294 -0
  110. package/src/types/reviewContext.d.ts +65 -0
  111. package/src/types/reviewSchema.ts +181 -0
  112. package/src/types/structuredReview.ts +167 -0
  113. package/src/types/tokenAnalysis.ts +56 -0
  114. package/src/utils/FileReader.ts +93 -0
  115. package/src/utils/FileWriter.ts +76 -0
  116. package/src/utils/PathGenerator.ts +97 -0
  117. package/src/utils/api/apiUtils.ts +14 -0
  118. package/src/utils/api/index.ts +1 -0
  119. package/src/utils/apiErrorHandler.ts +287 -0
  120. package/src/utils/ciDataCollector.ts +252 -0
  121. package/src/utils/codingTestConfigLoader.ts +466 -0
  122. package/src/utils/dependencies/aiDependencyAnalyzer.ts +454 -0
  123. package/src/utils/detection/frameworkDetector.ts +879 -0
  124. package/src/utils/detection/index.ts +10 -0
  125. package/src/utils/detection/projectTypeDetector.ts +518 -0
  126. package/src/utils/diagramGenerator.ts +206 -0
  127. package/src/utils/errorLogger.ts +60 -0
  128. package/src/utils/estimationUtils.ts +407 -0
  129. package/src/utils/fileFilters.ts +373 -0
  130. package/src/utils/fileSystem.ts +57 -0
  131. package/src/utils/index.ts +36 -0
  132. package/src/utils/logger.ts +240 -0
  133. package/src/utils/pathValidator.ts +98 -0
  134. package/src/utils/priorityFilter.ts +59 -0
  135. package/src/utils/projectDocs.ts +189 -0
  136. package/src/utils/promptPaths.ts +29 -0
  137. package/src/utils/promptTemplateManager.ts +157 -0
  138. package/src/utils/review/consolidateReview.ts +553 -0
  139. package/src/utils/review/fixDisplay.ts +100 -0
  140. package/src/utils/review/fixImplementation.ts +61 -0
  141. package/src/utils/review/index.ts +36 -0
  142. package/src/utils/review/interactiveProcessing.ts +294 -0
  143. package/src/utils/review/progressTracker.ts +296 -0
  144. package/src/utils/review/reviewExtraction.ts +382 -0
  145. package/src/utils/review/types.ts +46 -0
  146. package/src/utils/reviewActionHandler.ts +18 -0
  147. package/src/utils/reviewParser.ts +253 -0
  148. package/src/utils/sanitizer.ts +238 -0
  149. package/src/utils/smartFileSelector.ts +255 -0
  150. package/src/utils/templateLoader.ts +514 -0
  151. package/src/utils/treeGenerator.ts +153 -0
  152. package/tsconfig.build.json +14 -0
  153. 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
+ }