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,373 @@
1
+ /**
2
+ * @fileoverview Utilities for filtering and selecting files for code review.
3
+ *
4
+ * This module provides functions for identifying, filtering, and selecting files
5
+ * for code review based on various criteria. It handles file discovery, gitignore
6
+ * pattern matching, file extension filtering, and test file identification.
7
+ * Supported file types include TypeScript, JavaScript, JSON, and Markdown.
8
+ */
9
+
10
+ import fs from 'node:fs/promises';
11
+ import path from 'node:path';
12
+ import type { FileInfo } from '../types/review';
13
+ import logger from './logger';
14
+
15
+ // import { promises as fsPromises } from 'fs'; // TODO: Remove if not needed
16
+
17
+ /**
18
+ * Supported file extensions for code review - focus on executable code only
19
+ * Exclude non-executable files like .md, .txt, .log, .tgz, .json, and .svg
20
+ */
21
+ const SUPPORTED_EXTENSIONS = [
22
+ '.ts',
23
+ '.tsx',
24
+ '.js',
25
+ '.jsx',
26
+ '.py',
27
+ '.pyc',
28
+ '.pyi',
29
+ '.pyx',
30
+ '.pyd',
31
+ '.php',
32
+ '.java',
33
+ '.rb',
34
+ '.rake',
35
+ '.gemspec',
36
+ '.ru',
37
+ '.erb',
38
+ '.go',
39
+ '.rs',
40
+ '.c',
41
+ '.cpp',
42
+ '.h',
43
+ '.hpp',
44
+ '.cs',
45
+ '.swift',
46
+ '.kt',
47
+ '.dart',
48
+ ];
49
+
50
+ /**
51
+ * Check if a file is a test file
52
+ * @param filePath File path
53
+ * @returns True if the file is a test file
54
+ */
55
+ export function isTestFile(filePath: string): boolean {
56
+ const fileName = path.basename(filePath);
57
+ return (
58
+ fileName.includes('.test.') ||
59
+ fileName.includes('.spec.') ||
60
+ fileName.startsWith('test-') ||
61
+ fileName.endsWith('.test.ts') ||
62
+ fileName.endsWith('.test.js') ||
63
+ fileName.endsWith('.spec.ts') ||
64
+ fileName.endsWith('.spec.js') ||
65
+ filePath.includes('/__tests__/') ||
66
+ filePath.includes('/test/') ||
67
+ filePath.includes('/tests/')
68
+ );
69
+ }
70
+
71
+ /**
72
+ * Load gitignore patterns from a project directory
73
+ * @param projectDir Project directory path
74
+ * @returns Array of gitignore patterns
75
+ */
76
+ export async function loadGitignorePatterns(projectDir: string): Promise<string[]> {
77
+ try {
78
+ const gitignorePath = path.join(projectDir, '.gitignore');
79
+
80
+ // Check if .gitignore exists
81
+ try {
82
+ await fs.access(gitignorePath);
83
+ } catch (_error) {
84
+ // File doesn't exist
85
+ logger.debug(`No .gitignore file found at ${gitignorePath}`);
86
+ return [];
87
+ }
88
+
89
+ // Read and parse .gitignore
90
+ const content = await fs.readFile(gitignorePath, 'utf-8');
91
+ return content
92
+ .split('\n')
93
+ .map((line) => line.trim())
94
+ .filter((line) => line && !line.startsWith('#'));
95
+ } catch (error) {
96
+ logger.error(`Error reading .gitignore: ${error}`);
97
+ return [];
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Check if a file should be excluded based on gitignore patterns
103
+ * @param filePath File path
104
+ * @param gitignorePatterns Array of gitignore patterns
105
+ * @returns True if the file should be excluded
106
+ */
107
+ export function shouldExcludeFile(filePath: string, gitignorePatterns: string[]): boolean {
108
+ // Convert Windows paths to Unix-style for consistent pattern matching
109
+ const normalizedPath = filePath.replace(/\\/g, '/');
110
+
111
+ for (const pattern of gitignorePatterns) {
112
+ // Skip empty lines and comments
113
+ if (!pattern || pattern.startsWith('#')) {
114
+ continue;
115
+ }
116
+
117
+ // Handle negation patterns (those starting with !)
118
+ const isNegation = pattern.startsWith('!');
119
+ const actualPattern = isNegation ? pattern.slice(1) : pattern;
120
+
121
+ // Convert glob pattern to regex
122
+ let regexPattern = actualPattern
123
+ // Escape special regex characters
124
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
125
+ // Convert glob ** to regex
126
+ .replace(/\*\*/g, '.*')
127
+ // Convert glob * to regex
128
+ .replace(/\*/g, '[^/]*')
129
+ // Convert glob ? to regex
130
+ .replace(/\?/g, '[^/]');
131
+
132
+ // Handle directory-specific patterns (those ending with /)
133
+ if (regexPattern.endsWith('/')) {
134
+ regexPattern = `${regexPattern}.*`;
135
+ }
136
+
137
+ // Create the regex
138
+ const regex = new RegExp(
139
+ `^${regexPattern}$|^${regexPattern}/|/${regexPattern}$|/${regexPattern}/`,
140
+ );
141
+
142
+ // Check if the path matches the pattern
143
+ const matches = regex.test(normalizedPath);
144
+
145
+ if (matches) {
146
+ // If it's a negation pattern and matches, don't exclude
147
+ if (isNegation) {
148
+ return false;
149
+ }
150
+ // If it's a regular pattern and matches, exclude
151
+ return true;
152
+ }
153
+ }
154
+
155
+ // If no patterns matched, don't exclude
156
+ return false;
157
+ }
158
+
159
+ /**
160
+ * Get the language for a file based on its extension
161
+ * @param filePath File path
162
+ * @returns Language identifier
163
+ */
164
+ export function getLanguageForFile(filePath: string): string {
165
+ const ext = path.extname(filePath).toLowerCase();
166
+
167
+ switch (ext) {
168
+ case '.ts':
169
+ case '.tsx':
170
+ return 'typescript';
171
+ case '.js':
172
+ case '.jsx':
173
+ return 'javascript';
174
+ case '.py':
175
+ case '.pyi':
176
+ case '.pyx':
177
+ return 'python';
178
+ case '.php':
179
+ return 'php';
180
+ case '.rb':
181
+ case '.rake':
182
+ case '.gemspec':
183
+ case '.ru':
184
+ case '.erb':
185
+ return 'ruby';
186
+ case '.go':
187
+ return 'go';
188
+ case '.java':
189
+ return 'java';
190
+ case '.rs':
191
+ return 'rust';
192
+ case '.c':
193
+ case '.h':
194
+ return 'c';
195
+ case '.cpp':
196
+ case '.hpp':
197
+ return 'cpp';
198
+ case '.cs':
199
+ return 'csharp';
200
+ case '.swift':
201
+ return 'swift';
202
+ case '.kt':
203
+ return 'kotlin';
204
+ case '.dart':
205
+ return 'dart';
206
+ case '.json':
207
+ return 'json';
208
+ case '.md':
209
+ return 'markdown';
210
+ default:
211
+ return 'unknown';
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Check if a file is supported for code review
217
+ * @param filePath File path
218
+ * @returns True if the file is supported
219
+ */
220
+ export function isSupportedFile(filePath: string): boolean {
221
+ // Skip files that start with a dot (hidden files)
222
+ const fileName = path.basename(filePath);
223
+ if (fileName.startsWith('.')) {
224
+ return false;
225
+ }
226
+
227
+ const ext = path.extname(filePath).toLowerCase();
228
+ return SUPPORTED_EXTENSIONS.includes(ext);
229
+ }
230
+
231
+ /**
232
+ * Discover files in a directory recursively
233
+ * @param dirPath Directory path
234
+ * @param options Options for file discovery
235
+ * @returns Array of file paths
236
+ */
237
+ export async function discoverFiles(
238
+ dirPath: string,
239
+ options: {
240
+ excludePatterns?: string[];
241
+ includeTests?: boolean;
242
+ maxDepth?: number;
243
+ currentDepth?: number;
244
+ } = {},
245
+ ): Promise<string[]> {
246
+ const { excludePatterns = [], includeTests = false, maxDepth = 10, currentDepth = 0 } = options;
247
+
248
+ // Check max depth
249
+ if (currentDepth > maxDepth) {
250
+ return [];
251
+ }
252
+
253
+ try {
254
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
255
+ const files: string[] = [];
256
+
257
+ for (const entry of entries) {
258
+ const entryPath = path.join(dirPath, entry.name);
259
+
260
+ // Skip excluded files (from .gitignore)
261
+ if (shouldExcludeFile(entryPath, excludePatterns)) {
262
+ logger.debug(`Skipping path: ${entryPath} (matched by .gitignore pattern)`);
263
+ continue;
264
+ }
265
+
266
+ if (entry.isDirectory()) {
267
+ // Skip node_modules, .git directories, and directories starting with '.'
268
+ if (entry.name === 'node_modules' || entry.name === '.git' || entry.name.startsWith('.')) {
269
+ logger.debug(`Skipping directory: ${entry.name} (hidden or excluded)`);
270
+ continue;
271
+ }
272
+
273
+ // Recursively discover files in subdirectories
274
+ const subFiles = await discoverFiles(entryPath, {
275
+ excludePatterns,
276
+ includeTests,
277
+ maxDepth,
278
+ currentDepth: currentDepth + 1,
279
+ });
280
+
281
+ files.push(...subFiles);
282
+ } else if (entry.isFile()) {
283
+ // Skip dot files
284
+ if (entry.name.startsWith('.')) {
285
+ logger.debug(`Skipping file: ${entry.name} (hidden file)`);
286
+ continue;
287
+ }
288
+
289
+ // Skip test files if not including tests
290
+ if (!includeTests && isTestFile(entryPath)) {
291
+ logger.debug(`Skipping file: ${entryPath} (test file)`);
292
+ continue;
293
+ }
294
+
295
+ // Skip unsupported files
296
+ if (!isSupportedFile(entryPath)) {
297
+ logger.debug(`Skipping file: ${entryPath} (unsupported file type)`);
298
+ continue;
299
+ }
300
+
301
+ files.push(entryPath);
302
+ }
303
+ }
304
+
305
+ return files;
306
+ } catch (error) {
307
+ logger.error(`Error discovering files in ${dirPath}:`, error);
308
+ return [];
309
+ }
310
+ }
311
+
312
+ /**
313
+ * Read file content and create a FileInfo object
314
+ * @param filePath File path
315
+ * @returns FileInfo object
316
+ */
317
+ export async function readFileInfo(filePath: string): Promise<FileInfo> {
318
+ try {
319
+ const content = await fs.readFile(filePath, 'utf-8');
320
+ // const language = getLanguageForFile(filePath); // TODO: Remove if not needed
321
+
322
+ return {
323
+ path: filePath,
324
+ relativePath: filePath,
325
+ content,
326
+ };
327
+ } catch (error) {
328
+ logger.error(`Error reading file ${filePath}:`, error);
329
+ throw error;
330
+ }
331
+ }
332
+
333
+ /**
334
+ * Read multiple files and create FileInfo objects
335
+ * @param filePaths Array of file paths
336
+ * @returns Array of FileInfo objects
337
+ */
338
+ export async function readMultipleFiles(filePaths: string[]): Promise<FileInfo[]> {
339
+ const filePromises = filePaths.map((filePath) => readFileInfo(filePath));
340
+ return Promise.all(filePromises);
341
+ }
342
+
343
+ /**
344
+ * Get files to review based on the target path
345
+ * @param targetPath The target file or directory path
346
+ * @param isFile Whether the target is a file
347
+ * @param includeTests Whether to include test files
348
+ * @returns Array of file paths to review
349
+ */
350
+ export async function getFilesToReview(
351
+ targetPath: string,
352
+ isFile: boolean,
353
+ includeTests = false,
354
+ excludePatterns: string[] = [],
355
+ ): Promise<string[]> {
356
+ if (isFile) {
357
+ // If the target is a file, just return it
358
+ return [targetPath];
359
+ }
360
+ // If it's a directory, load .gitignore patterns if not already provided
361
+ let patterns = excludePatterns;
362
+ if (patterns.length === 0) {
363
+ patterns = await loadGitignorePatterns(targetPath);
364
+ logger.debug(`Loaded ${patterns.length} patterns from .gitignore`);
365
+ }
366
+
367
+ // If the target is a directory, discover files
368
+ return discoverFiles(targetPath, {
369
+ excludePatterns: patterns,
370
+ includeTests,
371
+ maxDepth: 10,
372
+ });
373
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @fileoverview File system utilities for the code review tool.
3
+ *
4
+ * This module re-exports utilities from more specialized modules to maintain
5
+ * backward compatibility while adhering to the Single Responsibility Principle.
6
+ *
7
+ * The original functionality has been split into:
8
+ * - pathValidator: For path validation and security checks
9
+ * - fileReader: For reading file operations
10
+ * - fileWriter: For writing file operations
11
+ * - pathGenerator: For generating output paths
12
+ */
13
+
14
+ // Import from pathValidator for aliases
15
+ import {
16
+ isDirectory,
17
+ isFile,
18
+ isPathWithinCwd,
19
+ pathExists,
20
+ validateTargetPath,
21
+ } from './pathValidator';
22
+
23
+ // Re-export from pathValidator
24
+ export { validateTargetPath, pathExists, isDirectory, isFile, isPathWithinCwd };
25
+
26
+ // Aliases for backward compatibility
27
+ export const fileExists = pathExists;
28
+ export const directoryExists = isDirectory;
29
+ export const validatePath = validateTargetPath;
30
+
31
+ // Re-export from fileReader
32
+ export {
33
+ readFile,
34
+ readFilesInDirectory as findFilesInDirectory,
35
+ readFilesWithInfo,
36
+ readFileWithInfo,
37
+ } from './FileReader';
38
+
39
+ // Import from fileWriter for aliases
40
+ import {
41
+ appendFile as appendFileImpl,
42
+ ensureDirectoryExists,
43
+ writeFile as writeFileImpl,
44
+ } from './FileWriter';
45
+
46
+ // Re-export from fileWriter
47
+ export { ensureDirectoryExists, writeFileImpl as writeFile, appendFileImpl as appendFile };
48
+
49
+ // Alias for backward compatibility
50
+ export const createDirectory = ensureDirectoryExists;
51
+
52
+ // Re-export from pathGenerator
53
+ export {
54
+ generateTempFilePath,
55
+ generateUniqueOutputPath,
56
+ generateVersionedOutputPath,
57
+ } from './PathGenerator';
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @fileoverview Index file for utility modules.
3
+ *
4
+ * This module re-exports utilities from subdirectories for easy importing.
5
+ * It provides a centralized entry point for all utility functions used
6
+ * throughout the application.
7
+ */
8
+
9
+ // API utilities
10
+ export * from './api';
11
+ // Config utilities moved to core/ConfigurationService
12
+ export { getConfig, configurationService } from '../core/ConfigurationService';
13
+ export * from './fileFilters';
14
+ export * from './fileSystem';
15
+ // Core utilities
16
+ export * from './logger';
17
+ export * from './pathValidator';
18
+ export * from './priorityFilter';
19
+ // export * from './fileSystemUtils'; // Commented out due to conflicts with fileSystem.ts
20
+ export * from './projectDocs';
21
+ export * from './smartFileSelector';
22
+
23
+ // File utilities (moved to main utils directory)
24
+ // export * from './files'; // Deprecated - files moved to main utils
25
+
26
+ // Re-export types
27
+ export * from '../types/review';
28
+ // Detection utilities
29
+ export * from './detection';
30
+
31
+ // Template utilities (moved from templates directory)
32
+ export * from './promptTemplateManager';
33
+ // Parsing utilities (moved to main utils directory)
34
+ export * from './reviewParser';
35
+ export * from './sanitizer';
36
+ export * from './templateLoader';
@@ -0,0 +1,240 @@
1
+ /**
2
+ * @fileoverview Centralized logging system for the cr-aia tool.
3
+ *
4
+ * This module provides a standardized logging interface with support for
5
+ * different log levels, colored output, and log level control via environment
6
+ * variables. It's designed to be used throughout the codebase to ensure
7
+ * consistent logging behavior.
8
+ */
9
+
10
+ // Define log levels with numeric values for comparison
11
+ export enum LogLevel {
12
+ DEBUG = 0,
13
+ INFO = 1,
14
+ WARN = 2,
15
+ ERROR = 3,
16
+ NONE = 4,
17
+ }
18
+
19
+ // Map string log level names to enum values
20
+ const LOG_LEVEL_MAP: Record<string, LogLevel> = {
21
+ debug: LogLevel.DEBUG,
22
+ info: LogLevel.INFO,
23
+ warn: LogLevel.WARN,
24
+ error: LogLevel.ERROR,
25
+ none: LogLevel.NONE,
26
+ };
27
+
28
+ // ANSI color codes for terminal output
29
+ const COLORS = {
30
+ reset: '\x1b[0m',
31
+ dim: '\x1b[2m',
32
+ bright: '\x1b[1m',
33
+ debug: '\x1b[36m', // Cyan
34
+ info: '\x1b[32m', // Green
35
+ warn: '\x1b[33m', // Yellow
36
+ error: '\x1b[31m', // Red
37
+ time: '\x1b[90m', // Gray
38
+ };
39
+
40
+ // Track if we're initializing to avoid circular dependencies
41
+ const isInitializing = false;
42
+
43
+ // Get the current log level from environment variables
44
+ function getCurrentLogLevel(): LogLevel {
45
+ // Avoid debug logs during initialization to prevent overwhelming output
46
+ const shouldLog = process.argv.includes('--trace-logger') && !isInitializing;
47
+
48
+ if (shouldLog) {
49
+ // Only print when explicitly requested with --trace-logger
50
+ console.error(
51
+ `Debug: getCurrentLogLevel called, AI_CODE_REVIEW_LOG_LEVEL=${process.env.AI_CODE_REVIEW_LOG_LEVEL}`,
52
+ );
53
+ }
54
+
55
+ // Always check CLI flags first - highest priority
56
+ if (process.argv.includes('--debug')) {
57
+ if (shouldLog) {
58
+ console.error('Debug: Debug flag found in process.argv, forcing DEBUG level');
59
+ }
60
+ return LogLevel.DEBUG;
61
+ }
62
+
63
+ // Next check environment variable
64
+ const envLogLevel = process.env.AI_CODE_REVIEW_LOG_LEVEL?.toLowerCase();
65
+
66
+ if (envLogLevel) {
67
+ if (shouldLog) {
68
+ console.error(`Debug: Found AI_CODE_REVIEW_LOG_LEVEL environment variable: ${envLogLevel}`);
69
+ }
70
+
71
+ if (envLogLevel in LOG_LEVEL_MAP) {
72
+ if (shouldLog) {
73
+ console.error(`Debug: Mapped log level ${envLogLevel} -> ${LOG_LEVEL_MAP[envLogLevel]}`);
74
+ }
75
+ return LOG_LEVEL_MAP[envLogLevel];
76
+ }
77
+ if (shouldLog) {
78
+ console.error(
79
+ `Debug: Invalid log level: ${envLogLevel}, valid options are: ${Object.keys(LOG_LEVEL_MAP).join(', ')}`,
80
+ );
81
+ }
82
+ } else if (shouldLog) {
83
+ console.error('Debug: AI_CODE_REVIEW_LOG_LEVEL environment variable not found');
84
+ }
85
+
86
+ // Default to INFO if not specified
87
+ if (shouldLog) {
88
+ console.error('Debug: No valid log level found, defaulting to INFO');
89
+ }
90
+ return LogLevel.INFO;
91
+ }
92
+
93
+ // The current log level
94
+ let currentLogLevel = getCurrentLogLevel();
95
+
96
+ /**
97
+ * Set the current log level
98
+ * @param level The log level to set
99
+ */
100
+ export function setLogLevel(level: LogLevel | string): void {
101
+ // Only log when explicitly requested with --trace-logger
102
+ const shouldLog = process.argv.includes('--trace-logger');
103
+
104
+ if (shouldLog) {
105
+ console.error(`Debug: setLogLevel called with ${level}`);
106
+ }
107
+
108
+ if (typeof level === 'string') {
109
+ const levelLower = level.toLowerCase();
110
+ if (levelLower in LOG_LEVEL_MAP) {
111
+ currentLogLevel = LOG_LEVEL_MAP[levelLower];
112
+ if (shouldLog) {
113
+ console.error(`Debug: Log level set to ${levelLower} -> ${currentLogLevel}`);
114
+ }
115
+ } else {
116
+ console.warn(`Invalid log level: ${level}. Using default.`);
117
+ }
118
+ } else {
119
+ currentLogLevel = level;
120
+ if (shouldLog) {
121
+ console.error(`Debug: Log level set to numeric value ${level}`);
122
+ }
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Get the current log level
128
+ * @returns The current log level
129
+ */
130
+ export function getLogLevel(): LogLevel {
131
+ return currentLogLevel;
132
+ }
133
+
134
+ /**
135
+ * Format a log message with timestamp and level
136
+ * @param level The log level
137
+ * @param message The message to log
138
+ * @returns The formatted message
139
+ */
140
+ function formatLogMessage(level: string, message: string): string {
141
+ const timestamp = new Date().toISOString();
142
+ const levelUpper = level.toUpperCase().padEnd(5);
143
+
144
+ return `${COLORS.time}[${timestamp}]${COLORS.reset} ${COLORS[level as keyof typeof COLORS]}${levelUpper}${COLORS.reset} ${message}`;
145
+ }
146
+
147
+ /**
148
+ * Log a message if the current log level allows it
149
+ * @param level The log level
150
+ * @param message The message to log
151
+ * @param args Additional arguments to log
152
+ */
153
+ function log(level: LogLevel, levelName: string, message: string, ...args: any[]): void {
154
+ // Only log if the current log level is less than or equal to the specified level
155
+ if (level >= currentLogLevel) {
156
+ const formattedMessage = formatLogMessage(levelName, message);
157
+
158
+ switch (level) {
159
+ case LogLevel.DEBUG:
160
+ console.debug(formattedMessage, ...args);
161
+ break;
162
+ case LogLevel.INFO:
163
+ console.log(formattedMessage, ...args);
164
+ break;
165
+ case LogLevel.WARN:
166
+ console.warn(formattedMessage, ...args);
167
+ break;
168
+ case LogLevel.ERROR:
169
+ console.error(formattedMessage, ...args);
170
+ break;
171
+ }
172
+ } else if (level === LogLevel.DEBUG && process.argv.includes('--trace-logger')) {
173
+ // Only show debug suppression messages when explicitly requested
174
+ console.error(
175
+ `Suppressing DEBUG log because currentLogLevel=${currentLogLevel}, message was: ${message}`,
176
+ );
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Log a debug message
182
+ * @param message The message to log
183
+ * @param args Additional arguments to log
184
+ */
185
+ export function debug(message: string, ...args: any[]): void {
186
+ log(LogLevel.DEBUG, 'debug', message, ...args);
187
+ }
188
+
189
+ /**
190
+ * Log an info message
191
+ * @param message The message to log
192
+ * @param args Additional arguments to log
193
+ */
194
+ export function info(message: string, ...args: any[]): void {
195
+ log(LogLevel.INFO, 'info', message, ...args);
196
+ }
197
+
198
+ /**
199
+ * Log a warning message
200
+ * @param message The message to log
201
+ * @param args Additional arguments to log
202
+ */
203
+ export function warn(message: string, ...args: any[]): void {
204
+ log(LogLevel.WARN, 'warn', message, ...args);
205
+ }
206
+
207
+ /**
208
+ * Log an error message
209
+ * @param message The message to log
210
+ * @param args Additional arguments to log
211
+ */
212
+ export function error(message: string, ...args: any[]): void {
213
+ log(LogLevel.ERROR, 'error', message, ...args);
214
+ }
215
+
216
+ /**
217
+ * Create a logger instance with a specific prefix
218
+ * @param prefix The prefix to add to all log messages
219
+ * @returns An object with debug, info, warn, and error methods
220
+ */
221
+ export function createLogger(prefix: string) {
222
+ return {
223
+ debug: (message: string, ...args: any[]) => debug(`[${prefix}] ${message}`, ...args),
224
+ info: (message: string, ...args: any[]) => info(`[${prefix}] ${message}`, ...args),
225
+ warn: (message: string, ...args: any[]) => warn(`[${prefix}] ${message}`, ...args),
226
+ error: (message: string, ...args: any[]) => error(`[${prefix}] ${message}`, ...args),
227
+ };
228
+ }
229
+
230
+ // Export a default logger instance
231
+ export default {
232
+ debug,
233
+ info,
234
+ warn,
235
+ error,
236
+ setLogLevel,
237
+ getLogLevel,
238
+ createLogger,
239
+ LogLevel,
240
+ };