codecritique 1.2.4 → 2.0.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/src/index.js CHANGED
@@ -103,11 +103,13 @@ program
103
103
  await embeddingsSystem.clearAllEmbeddings();
104
104
  console.log(chalk.green('All embeddings have been cleared.'));
105
105
  await embeddingsSystem.databaseManager.cleanup();
106
- } catch (err) {
106
+ }
107
+ catch (err) {
107
108
  console.error(chalk.red('Error clearing all embeddings:'), err.message);
108
109
  try {
109
110
  await embeddingsSystem.databaseManager.cleanup();
110
- } catch (cleanupErr) {
111
+ }
112
+ catch (cleanupErr) {
111
113
  console.error(chalk.red('Error during cleanup:'), cleanupErr.message);
112
114
  }
113
115
  process.exit(1);
@@ -203,7 +205,8 @@ const hasCommand = process.argv
203
205
  if (!hasCommand && process.argv.length > 2) {
204
206
  // If no command is specified but there are arguments, default to 'analyze'
205
207
  program.parse(['node', 'index.js', 'analyze', ...process.argv.slice(2)]);
206
- } else {
208
+ }
209
+ else {
207
210
  program.parse();
208
211
  }
209
212
 
@@ -223,7 +226,8 @@ process.on('SIGINT', async () => {
223
226
  clearTimeout(forceExitTimeout); // Cleanup finished, clear the timeout
224
227
  console.log(chalk.cyan('SIGINT handler: Exiting normally (code 0).'));
225
228
  process.exit(0); // Exit normally
226
- } catch (err) {
229
+ }
230
+ catch (err) {
227
231
  console.error(chalk.red('Error during embeddingsSystem.cleanup():'), err.message);
228
232
  clearTimeout(forceExitTimeout);
229
233
  console.log(chalk.cyan('SIGINT handler: Exiting after error (code 1).'));
@@ -246,7 +250,8 @@ process.on('SIGTERM', async () => {
246
250
  clearTimeout(forceExitTimeout); // Cleanup finished, clear the timeout
247
251
  console.log(chalk.cyan('SIGTERM handler: Exiting normally (code 0).'));
248
252
  process.exit(0); // Exit normally
249
- } catch (err) {
253
+ }
254
+ catch (err) {
250
255
  console.error(chalk.red('Error during embeddingsSystem.cleanup():'), err.message);
251
256
  clearTimeout(forceExitTimeout);
252
257
  console.log(chalk.cyan('SIGTERM handler: Exiting after error (code 1).'));
@@ -366,13 +371,15 @@ async function runCodeReview(options) {
366
371
  diffWith: options.diffWith,
367
372
  };
368
373
  reviewTask = reviewPullRequest(changedFiles, enhancedReviewOptions);
369
- } else if (options.file) {
374
+ }
375
+ else if (options.file) {
370
376
  operationDescription = `single file: ${options.file}`;
371
377
  if (!fs.existsSync(options.file)) {
372
378
  throw new Error(`File not found: ${options.file}`);
373
379
  }
374
380
  reviewTask = reviewFile(options.file, reviewOptions);
375
- } else if (options.files && options.files.length > 0) {
381
+ }
382
+ else if (options.files && options.files.length > 0) {
376
383
  const filesToAnalyze = await expandFilePatterns(options.files);
377
384
  if (filesToAnalyze.length === 0) {
378
385
  console.log(chalk.yellow('No files found matching the specified patterns. Exiting.'));
@@ -380,7 +387,8 @@ async function runCodeReview(options) {
380
387
  }
381
388
  operationDescription = `${filesToAnalyze.length} specific files/patterns`;
382
389
  reviewTask = reviewFiles(filesToAnalyze, reviewOptions);
383
- } else {
390
+ }
391
+ else {
384
392
  // No valid options provided - show error and exit
385
393
  console.error(chalk.red('Error: You must specify one of the following:'));
386
394
  console.error(chalk.yellow(' --file <file> Analyze a single file'));
@@ -418,7 +426,8 @@ async function runCodeReview(options) {
418
426
  // Pass the detailed results array to the output function
419
427
  outputFn(reviewResult.results, options);
420
428
  console.log(chalk.bold.green(`\nAnalysis complete for ${operationDescription}! (${duration}s)`));
421
- } else {
429
+ }
430
+ else {
422
431
  // No results to display (e.g., all files were excluded/skipped)
423
432
  const message = reviewResult.message || 'All files were excluded from review (e.g., config files, lock files).';
424
433
  console.log(chalk.yellow(message));
@@ -432,7 +441,8 @@ async function runCodeReview(options) {
432
441
 
433
442
  console.log(chalk.bold.yellow(`\nReview complete for ${operationDescription} - no reviewable files found (${duration}s)`));
434
443
  }
435
- } else {
444
+ }
445
+ else {
436
446
  console.error(chalk.red('\nCode review process failed.'));
437
447
  if (reviewResult && reviewResult.error) {
438
448
  console.error(chalk.red(`Error: ${reviewResult.error}`));
@@ -445,11 +455,13 @@ async function runCodeReview(options) {
445
455
  await embeddingsSystem.cleanup();
446
456
  await cleanupClassifier();
447
457
  console.log(chalk.green('All resources cleaned up successfully'));
448
- } catch (cleanupErr) {
458
+ }
459
+ catch (cleanupErr) {
449
460
  console.error(chalk.yellow('Error during cleanup:'), cleanupErr.message);
450
461
  process.exit(1);
451
462
  }
452
- } catch (err) {
463
+ }
464
+ catch (err) {
453
465
  console.error(chalk.red(`\nError during code review (${operationDescription}):`), err.message);
454
466
  console.error(err.stack);
455
467
  // Clean up resources even on error
@@ -457,7 +469,8 @@ async function runCodeReview(options) {
457
469
  await embeddingsSystem.cleanup();
458
470
  await cleanupClassifier();
459
471
  console.log(chalk.green('All resources cleaned up successfully'));
460
- } catch (cleanupErr) {
472
+ }
473
+ catch (cleanupErr) {
461
474
  console.error(chalk.red('Error during cleanup:'), cleanupErr.message);
462
475
  }
463
476
  process.exit(1);
@@ -500,7 +513,8 @@ async function generateEmbeddings(options) {
500
513
  .map((line) => line.trim())
501
514
  .filter((line) => line && !line.startsWith('#'));
502
515
  excludePatterns = [...excludePatterns, ...filePatterns];
503
- } else {
516
+ }
517
+ else {
504
518
  console.warn(chalk.yellow(`Exclude file not found: ${excludeFilePath}`));
505
519
  }
506
520
  }
@@ -512,7 +526,8 @@ async function generateEmbeddings(options) {
512
526
  // Log gitignore status
513
527
  if (options.gitignore === false) {
514
528
  console.log(chalk.yellow('Automatic .gitignore exclusion is disabled.'));
515
- } else {
529
+ }
530
+ else {
516
531
  console.log(chalk.cyan('Respecting .gitignore patterns (if present).'));
517
532
  }
518
533
  console.log(chalk.green('Exclusion pattern processing complete.'));
@@ -525,7 +540,8 @@ async function generateEmbeddings(options) {
525
540
  console.log(chalk.cyan('Processing specified files/patterns...'));
526
541
  filesToProcess = await expandFilePatterns(options.files, baseDir);
527
542
  console.log(chalk.green(`Expanded specified files/patterns to ${filesToProcess.length} files.`));
528
- } else {
543
+ }
544
+ else {
529
545
  console.log(chalk.cyan(`Scanning directory for supported files: ${baseDir}`));
530
546
  // Show spinner during file discovery
531
547
  const scanSpinner = new Spinner('Scanning files... %s');
@@ -591,11 +607,14 @@ async function generateEmbeddings(options) {
591
607
  // Update counters based on status
592
608
  if (status === 'processed') {
593
609
  processedCount++;
594
- } else if (status === 'skipped') {
610
+ }
611
+ else if (status === 'skipped') {
595
612
  skippedCount++;
596
- } else if (status === 'failed') {
613
+ }
614
+ else if (status === 'failed') {
597
615
  failedCount++;
598
- } else if (status === 'excluded') {
616
+ }
617
+ else if (status === 'excluded') {
599
618
  excludedCount++;
600
619
  }
601
620
 
@@ -603,7 +622,8 @@ async function generateEmbeddings(options) {
603
622
  updateSpinner();
604
623
  },
605
624
  });
606
- } finally {
625
+ }
626
+ finally {
607
627
  // Clean up the progress display even if embedding generation fails.
608
628
  clearInterval(progressInterval);
609
629
  spinner.stop(true);
@@ -636,7 +656,8 @@ async function generateEmbeddings(options) {
636
656
  )
637
657
  );
638
658
  verboseLog(options, chalk.gray(` Key patterns: ${projectSummary.keyPatterns.length}`));
639
- } catch (error) {
659
+ }
660
+ catch (error) {
640
661
  console.error(chalk.red('⚠️ Project analysis failed but continuing:'), error.message);
641
662
  }
642
663
 
@@ -644,7 +665,8 @@ async function generateEmbeddings(options) {
644
665
  console.log(chalk.cyan('Cleaning up resources...'));
645
666
  await embeddingsSystem.cleanup();
646
667
  console.log(chalk.green('Cleanup successful.'));
647
- } catch (err) {
668
+ }
669
+ catch (err) {
648
670
  console.error(chalk.red('Error generating embeddings:'), err.message);
649
671
  console.error(err.stack);
650
672
  // Clean up resources even on error
@@ -652,7 +674,8 @@ async function generateEmbeddings(options) {
652
674
  console.log(chalk.cyan('Cleaning up resources after error...'));
653
675
  await embeddingsSystem.cleanup();
654
676
  console.log(chalk.green('Cleanup successful.'));
655
- } catch (cleanupErr) {
677
+ }
678
+ catch (cleanupErr) {
656
679
  console.error(chalk.red('Error during cleanup:'), cleanupErr.message);
657
680
  }
658
681
  process.exit(1);
@@ -678,13 +701,15 @@ async function clearEmbeddings(options) {
678
701
  // Clean up resources (only database connection since we skipped full initialization)
679
702
  console.log(chalk.cyan('Cleaning up resources...'));
680
703
  await embeddingsSystem.databaseManager.cleanup();
681
- } catch (err) {
704
+ }
705
+ catch (err) {
682
706
  console.error(chalk.red('Error clearing embeddings:'), err.message);
683
707
  console.error(err.stack);
684
708
  // Clean up resources even on error (only database connection)
685
709
  try {
686
710
  await embeddingsSystem.databaseManager.cleanup();
687
- } catch (cleanupErr) {
711
+ }
712
+ catch (cleanupErr) {
688
713
  console.error(chalk.red('Error during cleanup:'), cleanupErr.message);
689
714
  }
690
715
  process.exit(1);
@@ -703,7 +728,8 @@ async function showEmbeddingStats(options) {
703
728
 
704
729
  if (options.directory) {
705
730
  console.log(chalk.cyan(`Fetching embedding statistics for project: ${projectDir}`));
706
- } else {
731
+ }
732
+ else {
707
733
  console.log(chalk.cyan('Fetching embedding statistics for all projects...'));
708
734
  }
709
735
 
@@ -714,7 +740,8 @@ async function showEmbeddingStats(options) {
714
740
 
715
741
  if (!stats || Object.keys(stats).length === 0 || stats.totalCount === 0) {
716
742
  console.log(chalk.yellow('No embeddings found or database is empty.'));
717
- } else {
743
+ }
744
+ else {
718
745
  console.log(` ${chalk.cyan('Total Embeddings:')} ${chalk.green(stats.totalCount)}`);
719
746
  if (stats.dimensions) {
720
747
  console.log(` ${chalk.cyan('Vector Dimensions:')} ${chalk.green(stats.dimensions)}`);
@@ -733,7 +760,8 @@ async function showEmbeddingStats(options) {
733
760
  // Clean up resources
734
761
  // console.log(chalk.cyan('Cleaning up resources...'));
735
762
  // await embeddingsSystem.cleanup();
736
- } catch (err) {
763
+ }
764
+ catch (err) {
737
765
  console.error(chalk.red('Error fetching embedding statistics:'), err.message);
738
766
  console.error(err.stack);
739
767
  // Clean up resources even on error
@@ -869,10 +897,12 @@ async function findSupportedFiles(directory, options = {}) {
869
897
  // Add log after the filtering loop (now just assignment)
870
898
  verboseLog(options, chalk.green(`Finished filtering glob results. ${finalFiles.length} files remain.`));
871
899
  return finalFiles;
872
- } catch (err) {
900
+ }
901
+ catch (err) {
873
902
  if (err.name === 'AbortError') {
874
903
  console.error(chalk.red('Glob operation timed out. The directory might be too large or complex.'));
875
- } else {
904
+ }
905
+ else {
876
906
  console.error(chalk.red(`Error during glob file search: ${err.message}`));
877
907
  }
878
908
  console.error(err.stack); // Log stack for debugging
@@ -897,7 +927,8 @@ async function expandFilePatterns(patterns, baseDir = process.cwd()) {
897
927
  // Check if it's a direct file path first
898
928
  if (fs.existsSync(absolutePattern) && fs.statSync(absolutePattern).isFile()) {
899
929
  files.add(absolutePattern);
900
- } else {
930
+ }
931
+ else {
901
932
  // Treat as a glob pattern
902
933
  // Use the original pattern with baseDir as cwd for correct globbing
903
934
  const matchedFiles = await glob.glob(pattern, { cwd: baseDir, absolute: true, nodir: true });
@@ -910,7 +941,8 @@ async function expandFilePatterns(patterns, baseDir = process.cwd()) {
910
941
  }
911
942
  }
912
943
  return Array.from(files);
913
- } catch (err) {
944
+ }
945
+ catch (err) {
914
946
  console.error(chalk.red('Error expanding file patterns:'), err.message);
915
947
  return [];
916
948
  }
@@ -939,7 +971,8 @@ function getChangedFiles(branch, workingDir = process.cwd()) {
939
971
  // Ensure the base branch exists locally as well (crucial for diff operations)
940
972
  try {
941
973
  ensureBranchExists(baseBranch, workingDir);
942
- } catch (error) {
974
+ }
975
+ catch (error) {
943
976
  console.warn(chalk.yellow(`Warning: Could not ensure base branch '${baseBranch}' exists locally: ${error.message}`));
944
977
  // Continue with the original baseBranch name, it might work with remote refs
945
978
  }
@@ -962,7 +995,8 @@ function getChangedFiles(branch, workingDir = process.cwd()) {
962
995
  }
963
996
 
964
997
  return changedFiles;
965
- } catch (err) {
998
+ }
999
+ catch (err) {
966
1000
  console.error(chalk.red('Error getting git diff:'), err.message);
967
1001
  return [];
968
1002
  }
@@ -988,7 +1022,9 @@ function outputJson(reviewResults, options) {
988
1022
  filesWithIssues: reviewResults.filter((r) => r.success && !r.skipped && r.results?.issues?.length > 0).length,
989
1023
  totalIssues: reviewResults.reduce((sum, r) => sum + (r.results?.issues?.length || 0), 0),
990
1024
  issuesWithCodeSuggestions: reviewResults.reduce((sum, r) => {
991
- if (!r.success || r.skipped || !r.results?.issues) return sum;
1025
+ if (!r.success || r.skipped || !r.results?.issues) {
1026
+ return sum;
1027
+ }
992
1028
  return sum + r.results.issues.filter((issue) => issue.codeSuggestion).length;
993
1029
  }, 0),
994
1030
  skippedFiles: reviewResults.filter((r) => r.skipped).length,
@@ -1019,7 +1055,8 @@ function outputJson(reviewResults, options) {
1019
1055
  if (options && options.outputFile) {
1020
1056
  fs.writeFileSync(options.outputFile, jsonOutput, 'utf8');
1021
1057
  console.log(chalk.green(`JSON output saved to: ${options.outputFile}`));
1022
- } else {
1058
+ }
1059
+ else {
1023
1060
  // Write JSON output to stdout (process.stdout is not buffered)
1024
1061
  process.stdout.write(jsonOutput);
1025
1062
  }
@@ -1048,8 +1085,12 @@ function outputMarkdown(reviewResults, options) {
1048
1085
  `- **Total Issues Found:** ${totalIssues}`,
1049
1086
  ];
1050
1087
 
1051
- if (skippedFiles > 0) lines.push(`- **Files Skipped:** ${skippedFiles}`);
1052
- if (errorFiles > 0) lines.push(`- **Errors:** ${errorFiles}`);
1088
+ if (skippedFiles > 0) {
1089
+ lines.push(`- **Files Skipped:** ${skippedFiles}`);
1090
+ }
1091
+ if (errorFiles > 0) {
1092
+ lines.push(`- **Errors:** ${errorFiles}`);
1093
+ }
1053
1094
 
1054
1095
  lines.push('', '## Detailed Review per File', '');
1055
1096
 
@@ -1128,8 +1169,12 @@ function outputText(reviewResults, cliOptions) {
1128
1169
  console.log(`Files Analyzed: ${chalk.bold(totalFiles)}`);
1129
1170
  console.log(`Files with Issues: ${chalk.bold(filesWithIssues)}`);
1130
1171
  console.log(`Total Issues Found: ${chalk.bold(totalIssues)}`);
1131
- if (skippedFiles > 0) console.log(`Files Skipped: ${chalk.yellow(skippedFiles)}`);
1132
- if (errorFiles > 0) console.log(`Errors: ${chalk.red(errorFiles)}`);
1172
+ if (skippedFiles > 0) {
1173
+ console.log(`Files Skipped: ${chalk.yellow(skippedFiles)}`);
1174
+ }
1175
+ if (errorFiles > 0) {
1176
+ console.log(`Errors: ${chalk.red(errorFiles)}`);
1177
+ }
1133
1178
  console.log(chalk.bold.blue('================================================'));
1134
1179
 
1135
1180
  reviewResults.forEach((fileResult) => {
@@ -1289,7 +1334,8 @@ async function analyzePRHistory(options) {
1289
1334
  // Display results using utility function
1290
1335
  displayAnalysisResults(results, duration);
1291
1336
  console.log(chalk.bold.green(`\nPR history analysis complete for ${repository}!`));
1292
- } catch (error) {
1337
+ }
1338
+ catch (error) {
1293
1339
  const endTime = Date.now();
1294
1340
  const duration = ((endTime - startTime) / 1000).toFixed(2);
1295
1341
  console.error(chalk.red(`\nError during PR history analysis (${duration}s):`), error.message);
@@ -1323,10 +1369,12 @@ async function getPRHistoryStatus(options) {
1323
1369
  if (hasComments) {
1324
1370
  const stats = await getPRCommentsStats(repository, projectPath);
1325
1371
  displayDatabaseStats(stats, hasComments);
1326
- } else {
1372
+ }
1373
+ else {
1327
1374
  displayDatabaseStats(null, hasComments);
1328
1375
  }
1329
- } catch (error) {
1376
+ }
1377
+ catch (error) {
1330
1378
  console.error(chalk.red('Error getting PR history status:'), error.message);
1331
1379
  process.exit(1);
1332
1380
  }
@@ -1387,10 +1435,12 @@ async function clearPRHistory(options) {
1387
1435
 
1388
1436
  if (cleared) {
1389
1437
  console.log(chalk.bold.green(`\nPR analysis data cleared successfully for ${repository}`));
1390
- } else {
1438
+ }
1439
+ else {
1391
1440
  console.log(chalk.yellow('No data was found to clear.'));
1392
1441
  }
1393
- } catch (error) {
1442
+ }
1443
+ catch (error) {
1394
1444
  console.error(chalk.red('Error clearing PR history data:'), error.message);
1395
1445
  verboseLog(options, error.stack);
1396
1446
  process.exit(1);
package/src/llm.js CHANGED
@@ -27,7 +27,9 @@ let anthropic = null;
27
27
  * @returns {Anthropic} The Anthropic client
28
28
  */
29
29
  function getAnthropicClient() {
30
- if (anthropic) return anthropic;
30
+ if (anthropic) {
31
+ return anthropic;
32
+ }
31
33
  const apiKey = process.env.ANTHROPIC_API_KEY;
32
34
  if (!apiKey) {
33
35
  throw new Error('ANTHROPIC_API_KEY is required for analysis. Set it in env or .env before running analyze.');
@@ -127,14 +129,16 @@ async function sendPromptToClaude(prompt, options = {}) {
127
129
  usage: response.usage,
128
130
  json: toolUse.input,
129
131
  };
130
- } else {
132
+ }
133
+ else {
131
134
  return {
132
135
  content: response.content[0]?.text || '',
133
136
  model: response.model,
134
137
  usage: response.usage,
135
138
  };
136
139
  }
137
- } catch (error) {
140
+ }
141
+ catch (error) {
138
142
  console.error(chalk.red(`Error sending prompt to Claude: ${error.message}`));
139
143
  throw error;
140
144
  }
@@ -212,7 +212,8 @@ export class ProjectAnalyzer {
212
212
  const currentEmbeddingInventoryHash = await this.calculateEmbeddingInventoryHash(projectPath);
213
213
  if (existingSummary.embeddingInventoryHash !== currentEmbeddingInventoryHash) {
214
214
  verboseLog(verbose, chalk.yellow('🔄 Embedding inventory changed, regenerating analysis...'));
215
- } else {
215
+ }
216
+ else {
216
217
  const currentHash = await this.calculateKeyFilesHash(existingSummary.keyFiles);
217
218
  if (existingSummary.keyFilesHash === currentHash) {
218
219
  verboseLog(verbose, chalk.green('✅ Project analysis up-to-date (no key file changes detected)'));
@@ -220,7 +221,8 @@ export class ProjectAnalyzer {
220
221
  }
221
222
  verboseLog(verbose, chalk.yellow('🔄 Key files changed, regenerating analysis...'));
222
223
  }
223
- } else {
224
+ }
225
+ else {
224
226
  verboseLog(
225
227
  verbose,
226
228
  chalk.cyan(
@@ -260,7 +262,8 @@ export class ProjectAnalyzer {
260
262
  verboseLog(verbose, chalk.gray(` Key files tracked: ${keyFiles.length}`));
261
263
 
262
264
  return projectSummary;
263
- } catch (error) {
265
+ }
266
+ catch (error) {
264
267
  console.error(chalk.red('Error analyzing project:'), error.message);
265
268
  return this.createFallbackSummary(projectPath);
266
269
  }
@@ -285,7 +288,8 @@ export class ProjectAnalyzer {
285
288
  return { ...summary, keyFiles };
286
289
  }
287
290
  return null;
288
- } catch (error) {
291
+ }
292
+ catch (error) {
289
293
  console.error(chalk.yellow('Warning: Could not load existing analysis:'), error.message);
290
294
  return null;
291
295
  }
@@ -299,7 +303,8 @@ export class ProjectAnalyzer {
299
303
  const embeddingsSystem = getDefaultEmbeddingsSystem();
300
304
  await embeddingsSystem.storeProjectSummary(projectPath, projectSummary);
301
305
  verboseLog({}, chalk.green('✅ Project analysis stored in database'));
302
- } catch (error) {
306
+ }
307
+ catch (error) {
303
308
  console.error(chalk.yellow('Warning: Could not store analysis:'), error.message);
304
309
  }
305
310
  }
@@ -358,10 +363,12 @@ export class ProjectAnalyzer {
358
363
  // Optimize table to sync indices with data and prevent TakeExec panics
359
364
  try {
360
365
  await table.optimize();
361
- } catch (optimizeError) {
366
+ }
367
+ catch (optimizeError) {
362
368
  if (optimizeError.message && optimizeError.message.includes('legacy format')) {
363
369
  console.warn(chalk.yellow(`Skipping optimization due to legacy index format - will be auto-upgraded during normal operations`));
364
- } else {
370
+ }
371
+ else {
365
372
  console.warn(chalk.yellow(`Warning: Failed to optimize file embeddings table: ${optimizeError.message}`));
366
373
  }
367
374
  }
@@ -378,7 +385,8 @@ export class ProjectAnalyzer {
378
385
 
379
386
  if (config.whereClause) {
380
387
  query = query.where(`project_path = '${projectPath}' AND (${config.whereClause})`);
381
- } else if (config.terms) {
388
+ }
389
+ else if (config.terms) {
382
390
  // For term-based searches, query ALL files and sort by depth to prioritize shallow config files
383
391
  const allFiles = await table
384
392
  .query()
@@ -406,12 +414,14 @@ export class ProjectAnalyzer {
406
414
 
407
415
  return matches;
408
416
  });
409
- } else {
417
+ }
418
+ else {
410
419
  query = query.where(`project_path = '${projectPath}'`);
411
420
  }
412
421
 
413
422
  return await query.limit(config.limit || 30).toArray();
414
- } catch (error) {
423
+ }
424
+ catch (error) {
415
425
  verboseLog({}, chalk.yellow(` ⚠️ Query failed for ${config.category}: ${error.message}`));
416
426
  return [];
417
427
  }
@@ -430,7 +440,8 @@ export class ProjectAnalyzer {
430
440
  }
431
441
  });
432
442
  }
433
- } catch (error) {
443
+ }
444
+ catch (error) {
434
445
  console.error(chalk.red('Error mining embeddings:'), error.message);
435
446
  return [];
436
447
  }
@@ -444,11 +455,17 @@ export class ProjectAnalyzer {
444
455
  * Unified file type matching using consolidated patterns
445
456
  */
446
457
  matchesFileType(filePath, fileName, type) {
447
- if (type === 'docs') return isDocumentationFile(filePath);
448
- if (type === 'tests') return isTestFile(filePath);
458
+ if (type === 'docs') {
459
+ return isDocumentationFile(filePath);
460
+ }
461
+ if (type === 'tests') {
462
+ return isTestFile(filePath);
463
+ }
449
464
 
450
465
  const config = FILE_PATTERNS[type];
451
- if (!config) return false;
466
+ if (!config) {
467
+ return false;
468
+ }
452
469
 
453
470
  const fileNameLower = fileName.toLowerCase();
454
471
  const filePathLower = filePath.toLowerCase();
@@ -546,10 +563,12 @@ Select files following the criteria in the system instructions.`;
546
563
 
547
564
  verboseLog({}, chalk.cyan(`🎯 LLM selected ${keyFiles.length} final key files`));
548
565
  return keyFiles;
549
- } else {
566
+ }
567
+ else {
550
568
  throw new Error(`Failed to extract valid JSON array from LLM response`);
551
569
  }
552
- } catch (error) {
570
+ }
571
+ catch (error) {
553
572
  console.error(chalk.red('Error in LLM selection:'), error.message);
554
573
  verboseLog({}, chalk.yellow(' 🔄 Falling back to automatic selection...'));
555
574
  return this.fallbackFileSelection(candidates, projectPath);
@@ -611,7 +630,8 @@ Select files following the criteria in the system instructions.`;
611
630
  const content = fs.readFileSync(fullPath, 'utf8');
612
631
  hash.update(content.substring(0, 1000));
613
632
  }
614
- } catch {
633
+ }
634
+ catch {
615
635
  hash.update(file.relativePath || file.path || '');
616
636
  }
617
637
  }
@@ -646,7 +666,8 @@ Select files following the criteria in the system instructions.`;
646
666
  }
647
667
 
648
668
  return hash.digest('hex');
649
- } catch (error) {
669
+ }
670
+ catch (error) {
650
671
  verboseLog({}, chalk.yellow(`Warning: Could not calculate embedding inventory hash: ${error.message}`));
651
672
  return 'embedding-inventory-unavailable';
652
673
  }
@@ -816,12 +837,14 @@ Follow the analysis guidelines from the system instructions to identify custom i
816
837
  validatedSummary.projectPath = projectPath;
817
838
  validatedSummary.keyFilesCount = keyFiles.length;
818
839
  return validatedSummary;
819
- } else {
840
+ }
841
+ else {
820
842
  console.error(chalk.red('Failed to parse LLM response as JSON'));
821
843
  console.error(chalk.gray('Response content preview:'), response.content.substring(0, 500));
822
844
  throw new Error('Failed to parse LLM response as JSON');
823
845
  }
824
- } catch (error) {
846
+ }
847
+ catch (error) {
825
848
  console.error(chalk.red('Error generating project summary:'), error.message);
826
849
  const fallback = this.createFallbackSummary(projectPath, keyFiles);
827
850
  verboseLog({}, chalk.yellow('Using fallback summary with technologies:'), fallback.technologies);
@@ -839,7 +862,9 @@ Follow the analysis guidelines from the system instructions to identify custom i
839
862
 
840
863
  for (const file of keyFiles.slice(0, 25)) {
841
864
  // Max 25 files
842
- if (totalSize >= maxTotalSize) break;
865
+ if (totalSize >= maxTotalSize) {
866
+ break;
867
+ }
843
868
 
844
869
  try {
845
870
  const fileContent = fs.readFileSync(file.fullPath, 'utf8');
@@ -848,7 +873,8 @@ Follow the analysis guidelines from the system instructions to identify custom i
848
873
 
849
874
  content += `\n\n=== ${file.relativePath} (${file.category}) ===\n${contentToAdd}`;
850
875
  totalSize += contentToAdd.length;
851
- } catch (error) {
876
+ }
877
+ catch (error) {
852
878
  content += `\n\n=== ${file.relativePath} (${file.category}) ===\n[Could not read file: ${error.message}]`;
853
879
  }
854
880
  }
@@ -912,7 +938,8 @@ Follow the analysis guidelines from the system instructions to identify custom i
912
938
  projectName = packageJson.name || projectName;
913
939
  const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
914
940
  technologies = Object.keys(deps).slice(0, 10);
915
- } catch {
941
+ }
942
+ catch {
916
943
  // Continue with defaults
917
944
  }
918
945
  }