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,423 @@
1
+ /**
2
+ * @fileoverview Consolidation Service for Multi-Pass Reviews
3
+ *
4
+ * This service handles the consolidation of multi-pass review results into
5
+ * a single cohesive report. It manages both AI-powered consolidation and
6
+ * fallback consolidation when AI services are unavailable.
7
+ */
8
+
9
+ import type { ReviewResult } from '../types/review';
10
+ import logger from '../utils/logger';
11
+ import { consolidateReview } from '../utils/review/consolidateReview';
12
+ import type { ApiClientConfig } from './ApiClientSelector';
13
+
14
+ /**
15
+ * Service for consolidating multi-pass review results
16
+ */
17
+ export class ConsolidationService {
18
+ /**
19
+ * Generate a consolidated report from multi-pass review results
20
+ * @param multiPassResult Combined result from all passes
21
+ * @param apiClientConfig API client configuration
22
+ * @param options Consolidation options
23
+ * @returns Promise resolving to consolidated content
24
+ */
25
+ async generateConsolidatedReport(
26
+ multiPassResult: ReviewResult,
27
+ apiClientConfig: ApiClientConfig,
28
+ options: {
29
+ projectName: string;
30
+ modelName: string;
31
+ totalPasses: number;
32
+ passResults: ReviewResult[];
33
+ },
34
+ ): Promise<string> {
35
+ const { projectName, modelName, totalPasses, passResults } = options;
36
+
37
+ try {
38
+ logger.info(`Generating consolidated report for ${projectName} using ${modelName}...`);
39
+
40
+ // Attempt AI-powered consolidation
41
+ const consolidatedContent = await this.attemptAiConsolidation(
42
+ multiPassResult,
43
+ apiClientConfig,
44
+ options,
45
+ );
46
+
47
+ if (consolidatedContent) {
48
+ logger.info('Successfully generated AI-powered consolidated report');
49
+ return consolidatedContent;
50
+ }
51
+
52
+ // Fall back to manual consolidation
53
+ logger.warn('AI consolidation failed, falling back to enhanced manual consolidation');
54
+ return this.createEnhancedFallbackConsolidation(multiPassResult, modelName, options);
55
+ } catch (error) {
56
+ logger.error('Error during consolidation:', error);
57
+ logger.info('Creating fallback consolidation due to error');
58
+ return this.createFallbackConsolidation(multiPassResult, modelName);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Attempt AI-powered consolidation
64
+ * @param multiPassResult Combined result from all passes
65
+ * @param apiClientConfig API client configuration
66
+ * @param options Consolidation options
67
+ * @returns Promise resolving to consolidated content or null if failed
68
+ */
69
+ private async attemptAiConsolidation(
70
+ multiPassResult: ReviewResult,
71
+ apiClientConfig: ApiClientConfig,
72
+ options: {
73
+ projectName: string;
74
+ modelName: string;
75
+ totalPasses: number;
76
+ passResults: ReviewResult[];
77
+ },
78
+ ): Promise<string | null> {
79
+ try {
80
+ // Set the project name in the result for consolidation
81
+ const reviewForConsolidation = {
82
+ ...multiPassResult,
83
+ projectName: options.projectName,
84
+ };
85
+
86
+ const consolidationResult = await consolidateReview(reviewForConsolidation);
87
+
88
+ if (consolidationResult && consolidationResult.trim() !== '') {
89
+ return consolidationResult;
90
+ }
91
+
92
+ logger.warn('AI consolidation returned empty content');
93
+ return null;
94
+ } catch (error) {
95
+ logger.error('AI consolidation failed:', error);
96
+ return null;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Creates an enhanced fallback consolidation with better error handling
102
+ * @param multiPassResult The combined result from all passes
103
+ * @param modelName The model name used for the review
104
+ * @param options Additional consolidation options
105
+ * @returns Enhanced fallback consolidation content
106
+ */
107
+ private createEnhancedFallbackConsolidation(
108
+ multiPassResult: ReviewResult,
109
+ modelName: string,
110
+ options: {
111
+ projectName: string;
112
+ totalPasses: number;
113
+ passResults: ReviewResult[];
114
+ },
115
+ ): string {
116
+ logger.info('Creating enhanced fallback consolidation from multi-pass results...');
117
+
118
+ const { projectName, totalPasses, passResults } = options;
119
+ const timestamp = new Date().toISOString();
120
+
121
+ // Extract findings from all passes
122
+ const findings = this.extractFindingsFromPasses(passResults);
123
+
124
+ // Calculate grades and recommendations
125
+ const overallGrade = this.calculateOverallGrade(findings);
126
+ const recommendations = this.generateRecommendations(findings, false);
127
+
128
+ // Build the consolidated report
129
+ const sections = [
130
+ `# Code Review: ${projectName}`,
131
+ '',
132
+ `**Review Type:** Multi-Pass Analysis (${totalPasses} passes)`,
133
+ `**Model:** ${modelName}`,
134
+ `**Generated:** ${timestamp}`,
135
+ '',
136
+ '## Executive Summary',
137
+ '',
138
+ `This multi-pass review analyzed the ${projectName} codebase across ${totalPasses} passes, ` +
139
+ `identifying ${findings.high.size + findings.medium.size + findings.low.size} total issues.`,
140
+ '',
141
+ `**Overall Grade:** ${overallGrade}`,
142
+ '',
143
+ '## Key Findings',
144
+ '',
145
+ this.formatFindings(findings),
146
+ '',
147
+ '## Recommendations',
148
+ '',
149
+ ...recommendations.map((rec) => `- ${rec}`),
150
+ '',
151
+ '## Pass Summary',
152
+ '',
153
+ this.generatePassSummary(passResults),
154
+ '',
155
+ '---',
156
+ '',
157
+ '*This report was generated using enhanced fallback consolidation due to AI service limitations.*',
158
+ ];
159
+
160
+ return sections.join('\n');
161
+ }
162
+
163
+ /**
164
+ * Creates a basic fallback consolidation when AI consolidation fails
165
+ * @param multiPassResult The combined result from all passes
166
+ * @param modelName The model name used for the review
167
+ * @returns Basic fallback consolidation content
168
+ */
169
+ private createFallbackConsolidation(multiPassResult: ReviewResult, modelName: string): string {
170
+ logger.info('Creating basic fallback consolidation from multi-pass results...');
171
+
172
+ const timestamp = new Date().toISOString();
173
+ const content = multiPassResult.content || 'No content available';
174
+
175
+ return [
176
+ `# Multi-Pass Code Review`,
177
+ '',
178
+ `**Model:** ${modelName}`,
179
+ `**Generated:** ${timestamp}`,
180
+ `**Note:** This is a fallback consolidation due to service limitations.`,
181
+ '',
182
+ '## Review Content',
183
+ '',
184
+ content,
185
+ '',
186
+ '---',
187
+ '',
188
+ '*This report was generated using basic fallback consolidation.*',
189
+ ].join('\n');
190
+ }
191
+
192
+ /**
193
+ * Extract findings from valid passes
194
+ * @param passResults Array of pass results
195
+ * @returns Categorized findings
196
+ */
197
+ private extractFindingsFromPasses(passResults: Array<{ content: string }>) {
198
+ const highPriorityFindings = new Set<string>();
199
+ const mediumPriorityFindings = new Set<string>();
200
+ const lowPriorityFindings = new Set<string>();
201
+
202
+ for (const pass of passResults) {
203
+ if (!pass.content) continue;
204
+
205
+ const content = pass.content.toLowerCase();
206
+ const issueTexts = this.extractIssueTexts(pass.content);
207
+
208
+ for (const issue of issueTexts) {
209
+ const lowerIssue = issue.toLowerCase();
210
+
211
+ // Categorize by priority keywords
212
+ if (this.isHighPriority(lowerIssue)) {
213
+ highPriorityFindings.add(issue);
214
+ } else if (this.isMediumPriority(lowerIssue)) {
215
+ mediumPriorityFindings.add(issue);
216
+ } else {
217
+ lowPriorityFindings.add(issue);
218
+ }
219
+ }
220
+ }
221
+
222
+ return {
223
+ high: highPriorityFindings,
224
+ medium: mediumPriorityFindings,
225
+ low: lowPriorityFindings,
226
+ };
227
+ }
228
+
229
+ /**
230
+ * Extract individual issue texts from content
231
+ * @param content Review content
232
+ * @returns Array of issue descriptions
233
+ */
234
+ private extractIssueTexts(content: string): string[] {
235
+ const issues: string[] = [];
236
+
237
+ // Extract bullet points and numbered items
238
+ const bulletRegex = /^[\s]*[-*•]\s+(.+)$/gm;
239
+ const numberedRegex = /^[\s]*\d+\.\s+(.+)$/gm;
240
+
241
+ let match;
242
+ while ((match = bulletRegex.exec(content)) !== null) {
243
+ issues.push(match[1].trim());
244
+ }
245
+
246
+ while ((match = numberedRegex.exec(content)) !== null) {
247
+ issues.push(match[1].trim());
248
+ }
249
+
250
+ return issues;
251
+ }
252
+
253
+ /**
254
+ * Check if an issue is high priority
255
+ * @param issue Issue text (lowercase)
256
+ * @returns True if high priority
257
+ */
258
+ private isHighPriority(issue: string): boolean {
259
+ const highPriorityKeywords = [
260
+ 'security',
261
+ 'vulnerability',
262
+ 'critical',
263
+ 'error',
264
+ 'bug',
265
+ 'crash',
266
+ 'memory leak',
267
+ 'performance',
268
+ 'sql injection',
269
+ 'xss',
270
+ ];
271
+ return highPriorityKeywords.some((keyword) => issue.includes(keyword));
272
+ }
273
+
274
+ /**
275
+ * Check if an issue is medium priority
276
+ * @param issue Issue text (lowercase)
277
+ * @returns True if medium priority
278
+ */
279
+ private isMediumPriority(issue: string): boolean {
280
+ const mediumPriorityKeywords = [
281
+ 'warning',
282
+ 'deprecated',
283
+ 'inefficient',
284
+ 'refactor',
285
+ 'improve',
286
+ 'optimization',
287
+ 'maintainability',
288
+ 'readability',
289
+ ];
290
+ return mediumPriorityKeywords.some((keyword) => issue.includes(keyword));
291
+ }
292
+
293
+ /**
294
+ * Calculate overall grade based on findings
295
+ * @param findings Categorized findings
296
+ * @returns Overall grade string
297
+ */
298
+ private calculateOverallGrade(findings: {
299
+ high: Set<string>;
300
+ medium: Set<string>;
301
+ low: Set<string>;
302
+ }): string {
303
+ const totalIssues = findings.high.size + findings.medium.size + findings.low.size;
304
+
305
+ if (findings.high.size > 5) return 'D';
306
+ if (findings.high.size > 2) return 'C';
307
+ if (findings.medium.size > 10) return 'C+';
308
+ if (findings.medium.size > 5) return 'B';
309
+ if (totalIssues > 10) return 'B+';
310
+ if (totalIssues > 5) return 'A-';
311
+ if (totalIssues > 0) return 'A';
312
+ return 'A+';
313
+ }
314
+
315
+ /**
316
+ * Generate recommendations based on findings
317
+ * @param findings Categorized findings
318
+ * @param hasErrors Whether there are compilation errors
319
+ * @returns Array of recommendation strings
320
+ */
321
+ private generateRecommendations(
322
+ findings: { high: Set<string>; medium: Set<string>; low: Set<string> },
323
+ hasErrors: boolean,
324
+ ): string[] {
325
+ const recommendations: string[] = [];
326
+
327
+ if (hasErrors) {
328
+ recommendations.push('Fix compilation errors before proceeding with other improvements');
329
+ }
330
+
331
+ if (findings.high.size > 0) {
332
+ recommendations.push(
333
+ `Address ${findings.high.size} high-priority security and critical issues immediately`,
334
+ );
335
+ }
336
+
337
+ if (findings.medium.size > 5) {
338
+ recommendations.push(
339
+ `Review and address ${findings.medium.size} medium-priority maintainability issues`,
340
+ );
341
+ }
342
+
343
+ if (findings.low.size > 10) {
344
+ recommendations.push(
345
+ `Consider addressing ${findings.low.size} low-priority style and minor issues`,
346
+ );
347
+ }
348
+
349
+ if (recommendations.length === 0) {
350
+ recommendations.push('Code quality is good. Continue following current best practices.');
351
+ }
352
+
353
+ return recommendations;
354
+ }
355
+
356
+ /**
357
+ * Format findings for display
358
+ * @param findings Categorized findings
359
+ * @returns Formatted findings string
360
+ */
361
+ private formatFindings(findings: {
362
+ high: Set<string>;
363
+ medium: Set<string>;
364
+ low: Set<string>;
365
+ }): string {
366
+ const sections: string[] = [];
367
+
368
+ if (findings.high.size > 0) {
369
+ sections.push(`**High Priority (${findings.high.size}):**`);
370
+ sections.push(
371
+ ...Array.from(findings.high)
372
+ .slice(0, 5)
373
+ .map((f) => `- ${f}`),
374
+ );
375
+ if (findings.high.size > 5) {
376
+ sections.push(`- ... and ${findings.high.size - 5} more`);
377
+ }
378
+ sections.push('');
379
+ }
380
+
381
+ if (findings.medium.size > 0) {
382
+ sections.push(`**Medium Priority (${findings.medium.size}):**`);
383
+ sections.push(
384
+ ...Array.from(findings.medium)
385
+ .slice(0, 3)
386
+ .map((f) => `- ${f}`),
387
+ );
388
+ if (findings.medium.size > 3) {
389
+ sections.push(`- ... and ${findings.medium.size - 3} more`);
390
+ }
391
+ sections.push('');
392
+ }
393
+
394
+ if (findings.low.size > 0) {
395
+ sections.push(`**Low Priority (${findings.low.size}):**`);
396
+ sections.push(
397
+ ...Array.from(findings.low)
398
+ .slice(0, 2)
399
+ .map((f) => `- ${f}`),
400
+ );
401
+ if (findings.low.size > 2) {
402
+ sections.push(`- ... and ${findings.low.size - 2} more`);
403
+ }
404
+ }
405
+
406
+ return sections.join('\n');
407
+ }
408
+
409
+ /**
410
+ * Generate a summary of all passes
411
+ * @param passResults Array of pass results
412
+ * @returns Pass summary string
413
+ */
414
+ private generatePassSummary(passResults: ReviewResult[]): string {
415
+ return passResults
416
+ .map((result, index) => {
417
+ const passNum = index + 1;
418
+ const wordCount = result.content ? result.content.split(/\s+/).length : 0;
419
+ return `**Pass ${passNum}:** ${wordCount} words of analysis`;
420
+ })
421
+ .join('\n');
422
+ }
423
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @fileoverview Interactive display manager module.
3
+ *
4
+ * This module is responsible for handling the interactive display of review results.
5
+ * It centralizes the logic for displaying review results and handling user interaction.
6
+ */
7
+
8
+ import fs from 'node:fs/promises';
9
+ import type { ReviewOptions } from '../types/review';
10
+ import type { PriorityFilter } from '../types/common';
11
+ import logger from '../utils/logger';
12
+ import { displayReviewResults } from '../utils/reviewActionHandler';
13
+
14
+ /**
15
+ * Display review results in interactive mode
16
+ * @param reviewPath Path to the review file
17
+ * @param projectPath Path to the project
18
+ * @param options Review options
19
+ * @returns Promise resolving when the display is complete
20
+ */
21
+ export async function displayReviewInteractively(
22
+ reviewPath: string,
23
+ projectPath: string,
24
+ options: ReviewOptions,
25
+ ): Promise<void> {
26
+ try {
27
+ logger.info('\nDisplaying review results in interactive mode...');
28
+
29
+ // Read the review content
30
+ const reviewContent = await fs.readFile(reviewPath, 'utf-8');
31
+
32
+ // Get the priority filter from the options
33
+ const priorityFilter = getPriorityFilterFromOptions(options);
34
+
35
+ // Display the review results
36
+ const results = await displayReviewResults(reviewContent, projectPath, priorityFilter);
37
+
38
+ // Print summary
39
+ logger.info('\n--- Review Summary ---');
40
+ logger.info(`Total issues found: ${results.totalSuggestions}`);
41
+ logger.info(`High priority issues: ${results.highPrioritySuggestions.length}`);
42
+ logger.info(`Medium priority issues: ${results.mediumPrioritySuggestions.length}`);
43
+ logger.info(`Low priority issues: ${results.lowPrioritySuggestions.length}`);
44
+ logger.info('----------------------');
45
+ } catch (error) {
46
+ logger.error(
47
+ `Error displaying review results: ${error instanceof Error ? error.message : String(error)}`,
48
+ );
49
+ throw error;
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Get the priority filter from review options
55
+ * @param options Review options that may contain the priority filter
56
+ * @returns The priority filter (h, m, l, or a) or undefined if not specified
57
+ */
58
+ export function getPriorityFilterFromOptions(options?: ReviewOptions): PriorityFilter | undefined {
59
+ // First check if the interactive option is a string (priority filter)
60
+ if (
61
+ options &&
62
+ typeof options.interactive === 'string' &&
63
+ ['h', 'm', 'l', 'a'].includes(options.interactive)
64
+ ) {
65
+ return options.interactive as PriorityFilter;
66
+ }
67
+
68
+ // Otherwise check if there's a priority filter argument after --interactive
69
+ const args = process.argv;
70
+ const interactiveIndex = args.findIndex((arg) => arg === '--interactive' || arg === '-i');
71
+
72
+ if (interactiveIndex !== -1 && interactiveIndex < args.length - 1) {
73
+ const nextArg = args[interactiveIndex + 1];
74
+ // Check if the next argument is a priority filter and not another option
75
+ if (['h', 'm', 'l', 'a'].includes(nextArg) && !nextArg.startsWith('-')) {
76
+ return nextArg as PriorityFilter;
77
+ }
78
+ }
79
+
80
+ return undefined;
81
+ }