codecritique 1.2.1 → 1.2.3

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
@@ -30,6 +30,7 @@ import { ProjectAnalyzer } from './project-analyzer.js';
30
30
  import { reviewFile, reviewFiles, reviewPullRequest } from './rag-review.js';
31
31
  import { execGitSafe } from './utils/command.js';
32
32
  import { ensureBranchExists, findBaseBranch } from './utils/git.js';
33
+ import { verboseLog } from './utils/logging.js';
33
34
 
34
35
  // Create a default embeddings system instance
35
36
  const embeddingsSystem = getDefaultEmbeddingsSystem();
@@ -406,9 +407,7 @@ async function runCodeReview(options) {
406
407
  const endTime = Date.now();
407
408
  const duration = ((endTime - startTime) / 1000).toFixed(2);
408
409
 
409
- if (options.verbose) {
410
- console.log(chalk.blue(`Review process took ${duration} seconds.`));
411
- }
410
+ verboseLog(options, chalk.blue(`Review process took ${duration} seconds.`));
412
411
 
413
412
  // Process and output results
414
413
  if (reviewResult && reviewResult.success) {
@@ -576,35 +575,37 @@ async function generateEmbeddings(options) {
576
575
 
577
576
  // Start the progress update interval
578
577
  const progressInterval = setInterval(updateSpinner, 100);
578
+ let results;
579
+ try {
580
+ results = await embeddingsSystem.processBatchEmbeddings(filesToProcess, {
581
+ concurrency,
582
+ verbose: options.verbose,
583
+ excludePatterns,
584
+ respectGitignore: options.gitignore !== false,
585
+ baseDir: baseDir,
586
+ batchSize: 100, // Set a reasonable batch size
587
+ maxLines: parseInt(options.maxLines || '1000', 10),
588
+ onProgress: (status) => {
589
+ // Update counters based on status
590
+ if (status === 'processed') {
591
+ processedCount++;
592
+ } else if (status === 'skipped') {
593
+ skippedCount++;
594
+ } else if (status === 'failed') {
595
+ failedCount++;
596
+ } else if (status === 'excluded') {
597
+ excludedCount++;
598
+ }
579
599
 
580
- const results = await embeddingsSystem.processBatchEmbeddings(filesToProcess, {
581
- concurrency,
582
- verbose: options.verbose,
583
- excludePatterns,
584
- respectGitignore: options.gitignore !== false,
585
- baseDir: baseDir,
586
- batchSize: 100, // Set a reasonable batch size
587
- maxLines: parseInt(options.maxLines || '1000', 10),
588
- onProgress: (status) => {
589
- // Update counters based on status
590
- if (status === 'processed') {
591
- processedCount++;
592
- } else if (status === 'skipped') {
593
- skippedCount++;
594
- } else if (status === 'failed') {
595
- failedCount++;
596
- } else if (status === 'excluded') {
597
- excludedCount++;
598
- }
599
-
600
- // Update the spinner with new progress information
601
- updateSpinner();
602
- },
603
- });
604
-
605
- // Clean up the progress display
606
- clearInterval(progressInterval);
607
- spinner.stop(true);
600
+ // Update the spinner with new progress information
601
+ updateSpinner();
602
+ },
603
+ });
604
+ } finally {
605
+ // Clean up the progress display even if embedding generation fails.
606
+ clearInterval(progressInterval);
607
+ spinner.stop(true);
608
+ }
608
609
 
609
610
  console.log(chalk.green(`\nEmbedding generation complete!`));
610
611
  console.log(chalk.cyan(`Processed: ${results.processed} files`));
@@ -628,15 +629,14 @@ async function generateEmbeddings(options) {
628
629
  await embeddingsSystem.storeProjectSummary(projectDir, projectSummary);
629
630
 
630
631
  console.log(chalk.green('✅ Project analysis complete and stored'));
631
- if (options.verbose) {
632
- console.log(chalk.gray(` Project: ${projectSummary.projectName}`));
633
- console.log(
634
- chalk.gray(
635
- ` Technologies: ${projectSummary.technologies.slice(0, 5).join(', ')}${projectSummary.technologies.length > 5 ? '...' : ''}`
636
- )
637
- );
638
- console.log(chalk.gray(` Key patterns: ${projectSummary.keyPatterns.length}`));
639
- }
632
+ verboseLog(options, chalk.gray(` Project: ${projectSummary.projectName}`));
633
+ verboseLog(
634
+ options,
635
+ chalk.gray(
636
+ ` Technologies: ${projectSummary.technologies.slice(0, 5).join(', ')}${projectSummary.technologies.length > 5 ? '...' : ''}`
637
+ )
638
+ );
639
+ verboseLog(options, chalk.gray(` Key patterns: ${projectSummary.keyPatterns.length}`));
640
640
  } catch (error) {
641
641
  console.error(chalk.red('⚠️ Project analysis failed but continuing:'), error.message);
642
642
  }
@@ -754,10 +754,12 @@ async function showEmbeddingStats(options) {
754
754
  *
755
755
  * @param {string} directory - Directory to search
756
756
  * @param {object} options - Options from generateEmbeddings command
757
+ * @param {boolean} [options.verbose=false] - Enable verbose glob and filtering logs
758
+ * @param {string} [options.filePattern] - Optional override pattern instead of the default supported-file patterns
759
+ * @param {string[]} [options.excludePatterns] - Additional glob exclusion patterns
757
760
  * @returns {Promise<Array<string>>} Array of file paths
758
761
  */
759
762
  async function findSupportedFiles(directory, options = {}) {
760
- const verbose = options.verbose || false;
761
763
  const baseDir = path.resolve(directory);
762
764
 
763
765
  // Default patterns match common code files - adjust as needed
@@ -833,19 +835,15 @@ async function findSupportedFiles(directory, options = {}) {
833
835
  // Instead, we rely on the shouldProcessFile check in embeddings.js which uses git check-ignore
834
836
  globOptions.ignore = [...excludePatterns]; // Use only explicit excludes
835
837
 
836
- if (verbose) {
837
- console.log(chalk.cyan('Using async glob to find files...'));
838
- console.log(chalk.gray(` Patterns: ${patternsToUse.join(', ')}`));
839
- console.log(chalk.gray(` Options:`), globOptions);
840
- }
838
+ verboseLog(options, chalk.cyan('Using async glob to find files...'));
839
+ verboseLog(options, chalk.gray(` Patterns: ${patternsToUse.join(', ')}`));
840
+ verboseLog(options, chalk.gray(` Options:`), globOptions);
841
841
 
842
842
  try {
843
843
  // Use asynchronous glob
844
844
  const files = await glob.glob(patternsToUse, globOptions);
845
845
 
846
- if (verbose) {
847
- console.log(chalk.green(`Glob found ${files.length} potential files.`));
848
- }
846
+ verboseLog(options, chalk.green(`Glob found ${files.length} potential files.`));
849
847
 
850
848
  // Filter results to ensure they are actual files (glob with stat should mostly handle this)
851
849
  // And apply the final utilsShouldProcessFile check (e.g., for binary content if needed)
@@ -862,9 +860,7 @@ async function findSupportedFiles(directory, options = {}) {
862
860
  // finalFiles.push(file);
863
861
  // }
864
862
  // } catch (statError) {
865
- // if (verbose) {
866
- // console.warn(chalk.yellow(`Skipping file due to stat error ${path.relative(baseDir, file)}: ${statError.message}`));
867
- // }
863
+ // console.warn(chalk.yellow(`Skipping file due to stat error ${path.relative(baseDir, file)}: ${statError.message}`));
868
864
  // }
869
865
  // }
870
866
 
@@ -872,9 +868,7 @@ async function findSupportedFiles(directory, options = {}) {
872
868
  const finalFiles = files;
873
869
 
874
870
  // Add log after the filtering loop (now just assignment)
875
- if (verbose) {
876
- console.log(chalk.green(`Finished filtering glob results. ${finalFiles.length} files remain.`));
877
- }
871
+ verboseLog(options, chalk.green(`Finished filtering glob results. ${finalFiles.length} files remain.`));
878
872
  return finalFiles;
879
873
  } catch (err) {
880
874
  if (err.name === 'AbortError') {
@@ -979,13 +973,13 @@ function getChangedFiles(branch, workingDir = process.cwd()) {
979
973
  // REMOVED: checkBranchExists function - Moved to utils.js
980
974
 
981
975
  // --- Output Formatting Functions --- //
982
- // These need to be adapted to the structure returned by cag-review.js functions
976
+ // These consume the normalized results returned by the RAG review pipeline
983
977
 
984
978
  /**
985
979
  * Output results in JSON format
986
980
  *
987
- * @param {Array<Object>} reviewResults - Array of individual file review results from cag-review
988
- * @param {Object} cliOptions - Command line options
981
+ * @param {Array<Object>} reviewResults - Array of individual file review results
982
+ * @param {Object} options - Command line options
989
983
  */
990
984
  function outputJson(reviewResults, options) {
991
985
  // Structure the output to be informative
@@ -1013,7 +1007,7 @@ function outputJson(reviewResults, options) {
1013
1007
  filePath: r.filePath,
1014
1008
  success: true,
1015
1009
  language: r.language,
1016
- review: r.results, // Contains summary, issues (with optional codeSuggestion), positives from LLM
1010
+ review: r.results, // Contains summary and actionable issues (with optional codeSuggestion)
1017
1011
  // Optionally include similar examples if needed
1018
1012
  // similarExamplesUsed: r.similarExamples
1019
1013
  };
@@ -1036,86 +1030,86 @@ function outputJson(reviewResults, options) {
1036
1030
  * Output results in Markdown format
1037
1031
  *
1038
1032
  * @param {Array<Object>} reviewResults - Array of individual file review results
1039
- * @param {Object} cliOptions - Command line options
1033
+ * @param {Object} options - Command line options
1040
1034
  */
1041
- function outputMarkdown(reviewResults) {
1042
- console.log('# AI Code Review Results (RAG Approach)\n');
1043
-
1035
+ function outputMarkdown(reviewResults, options) {
1044
1036
  const totalFiles = reviewResults.length;
1045
1037
  const filesWithIssues = reviewResults.filter((r) => r.success && !r.skipped && r.results?.issues?.length > 0).length;
1046
1038
  const totalIssues = reviewResults.reduce((sum, r) => sum + (r.results?.issues?.length || 0), 0);
1047
1039
  const skippedFiles = reviewResults.filter((r) => r.skipped).length;
1048
1040
  const errorFiles = reviewResults.filter((r) => !r.success).length;
1049
1041
 
1050
- console.log('## Summary\n');
1051
- console.log(`- **Files Analyzed:** ${totalFiles}`);
1052
- console.log(`- **Files with Issues:** ${filesWithIssues}`);
1053
- console.log(`- **Total Issues Found:** ${totalIssues}`);
1054
- if (skippedFiles > 0) console.log(`- **Files Skipped:** ${skippedFiles}`);
1055
- if (errorFiles > 0) console.log(`- **Errors:** ${errorFiles}`);
1056
- console.log('\n');
1042
+ const lines = [
1043
+ '# AI Code Review Results (RAG Approach)',
1044
+ '',
1045
+ '## Summary',
1046
+ '',
1047
+ `- **Files Analyzed:** ${totalFiles}`,
1048
+ `- **Files with Issues:** ${filesWithIssues}`,
1049
+ `- **Total Issues Found:** ${totalIssues}`,
1050
+ ];
1057
1051
 
1058
- console.log('## Detailed Review per File\n');
1052
+ if (skippedFiles > 0) lines.push(`- **Files Skipped:** ${skippedFiles}`);
1053
+ if (errorFiles > 0) lines.push(`- **Errors:** ${errorFiles}`);
1054
+
1055
+ lines.push('', '## Detailed Review per File', '');
1059
1056
 
1060
1057
  reviewResults.forEach((fileResult) => {
1061
- console.log(`### ${fileResult.filePath}\n`);
1058
+ lines.push(`### ${fileResult.filePath}`, '');
1062
1059
  if (!fileResult.success) {
1063
- console.log(`**Error:** ${fileResult.error}\n`);
1060
+ lines.push(`**Error:** ${fileResult.error}`, '');
1064
1061
  return;
1065
1062
  }
1066
1063
  if (fileResult.skipped) {
1067
- console.log(`*Skipped (based on exclusion patterns or file type).*\n`);
1064
+ lines.push('*Skipped (based on exclusion patterns or file type).*', '');
1068
1065
  return;
1069
1066
  }
1070
- if (!fileResult.results || (!fileResult.results.issues?.length && !fileResult.results.positives?.length)) {
1071
- console.log(`*No significant findings or issues reported.*\n`);
1067
+ if (!fileResult.results || !fileResult.results.issues?.length) {
1068
+ lines.push('*No actionable issues reported.*', '');
1072
1069
  if (fileResult.results?.summary) {
1073
- console.log(`**Summary:** ${fileResult.results.summary}\n`);
1070
+ lines.push(`**Summary:** ${fileResult.results.summary}`, '');
1074
1071
  }
1075
1072
  return;
1076
1073
  }
1077
1074
 
1078
1075
  const review = fileResult.results;
1079
1076
  if (review.summary) {
1080
- console.log(`**Summary:** ${review.summary}\n`);
1077
+ lines.push(`**Summary:** ${review.summary}`, '');
1081
1078
  }
1082
1079
 
1083
1080
  if (review.issues && review.issues.length > 0) {
1084
- console.log(`**Issues Found (${review.issues.length}):**\n`);
1081
+ lines.push(`**Issues Found (${review.issues.length}):**`, '');
1085
1082
  review.issues.forEach((issue) => {
1086
1083
  const severityEmoji = getSeverityEmoji(issue.severity);
1087
- console.log(
1084
+ lines.push(
1088
1085
  `- **[${issue.severity.toUpperCase()}] ${severityEmoji} (Lines: ${issue.lineNumbers?.join(', ') || 'N/A'})**: ${
1089
1086
  issue.description
1090
1087
  }`
1091
1088
  );
1092
1089
  if (issue.suggestion) {
1093
- console.log(`\n *Suggestion:* ${issue.suggestion}\n`);
1090
+ lines.push('', ` *Suggestion:* ${issue.suggestion}`, '');
1094
1091
  }
1095
1092
  // Include code suggestion if available
1096
1093
  if (issue.codeSuggestion) {
1097
1094
  const { startLine, endLine, newCode } = issue.codeSuggestion;
1098
1095
  const lineRange = endLine ? `${startLine}-${endLine}` : `${startLine}`;
1099
- console.log(`\n **Suggested change (lines ${lineRange}):**\n`);
1100
- console.log(' ```suggestion');
1101
- console.log(
1102
- newCode
1103
- .split('\n')
1104
- .map((line) => ` ${line}`)
1105
- .join('\n')
1106
- );
1107
- console.log(' ```\n');
1096
+ lines.push('', ` **Suggested change (lines ${lineRange}):**`, '', ' ```suggestion');
1097
+ lines.push(...newCode.split('\n').map((line) => ` ${line}`));
1098
+ lines.push(' ```', '');
1108
1099
  }
1109
1100
  });
1110
1101
  }
1111
-
1112
- if (review.positives && review.positives.length > 0) {
1113
- console.log(`**Positives Found (${review.positives.length}):**\n`);
1114
- review.positives.forEach((positive) => {
1115
- console.log(` - ${positive}\n`);
1116
- });
1117
- }
1118
1102
  });
1103
+
1104
+ const markdownOutput = `${lines.join('\n')}\n`;
1105
+
1106
+ if (options?.outputFile) {
1107
+ fs.writeFileSync(options.outputFile, markdownOutput, 'utf8');
1108
+ console.log(chalk.green(`Markdown output saved to: ${options.outputFile}`));
1109
+ return;
1110
+ }
1111
+
1112
+ process.stdout.write(markdownOutput);
1119
1113
  }
1120
1114
 
1121
1115
  /**
@@ -1147,17 +1141,13 @@ function outputText(reviewResults, cliOptions) {
1147
1141
  return;
1148
1142
  }
1149
1143
  if (fileResult.skipped) {
1150
- if (cliOptions.verbose) {
1151
- console.log(chalk.yellow(`\nSkipped: ${fileResult.filePath}`));
1152
- }
1144
+ verboseLog(cliOptions, chalk.yellow(`\nSkipped: ${fileResult.filePath}`));
1153
1145
  return;
1154
1146
  }
1155
- if (!fileResult.results || (!fileResult.results.issues?.length && !fileResult.results.positives?.length)) {
1156
- if (cliOptions.verbose) {
1157
- console.log(chalk.green(`\nNo findings for: ${fileResult.filePath}`));
1158
- if (fileResult.results?.summary) {
1159
- console.log(chalk.green(` Summary: ${fileResult.results.summary}`));
1160
- }
1147
+ if (!fileResult.results || !fileResult.results.issues?.length) {
1148
+ verboseLog(cliOptions, chalk.green(`\nNo findings for: ${fileResult.filePath}`));
1149
+ if (fileResult.results?.summary) {
1150
+ verboseLog(cliOptions, chalk.green(` Summary: ${fileResult.results.summary}`));
1161
1151
  }
1162
1152
  return;
1163
1153
  }
@@ -1192,13 +1182,6 @@ function outputText(reviewResults, cliOptions) {
1192
1182
  });
1193
1183
  }
1194
1184
 
1195
- if (review.positives && review.positives.length > 0) {
1196
- console.log(chalk.bold.green('\nPositives:'));
1197
- review.positives.forEach((positive) => {
1198
- console.log(` - ${positive}`);
1199
- });
1200
- console.log('');
1201
- }
1202
1185
  console.log(chalk.gray(`========================================${'='.repeat(fileResult.filePath.length)}`));
1203
1186
  });
1204
1187
  }
@@ -1292,6 +1275,7 @@ async function analyzePRHistory(options) {
1292
1275
  resume: options.resume,
1293
1276
  clearExisting: options.clear,
1294
1277
  projectPath,
1278
+ verbose: options.verbose,
1295
1279
  onProgress: (progress) => displayProgress(progress, options.verbose),
1296
1280
  };
1297
1281
 
@@ -1310,9 +1294,7 @@ async function analyzePRHistory(options) {
1310
1294
  const endTime = Date.now();
1311
1295
  const duration = ((endTime - startTime) / 1000).toFixed(2);
1312
1296
  console.error(chalk.red(`\nError during PR history analysis (${duration}s):`), error.message);
1313
- if (options.verbose) {
1314
- console.error(error.stack);
1315
- }
1297
+ verboseLog(options, error.stack);
1316
1298
  process.exit(1);
1317
1299
  }
1318
1300
  }
@@ -1411,9 +1393,7 @@ async function clearPRHistory(options) {
1411
1393
  }
1412
1394
  } catch (error) {
1413
1395
  console.error(chalk.red('Error clearing PR history data:'), error.message);
1414
- if (options.verbose) {
1415
- console.error(error.stack);
1416
- }
1396
+ verboseLog(options, error.stack);
1417
1397
  process.exit(1);
1418
1398
  }
1419
1399
  }
package/src/llm.js CHANGED
@@ -15,6 +15,7 @@
15
15
  import { Anthropic } from '@anthropic-ai/sdk';
16
16
  import chalk from 'chalk';
17
17
  import dotenv from 'dotenv';
18
+ import { verboseLog } from './utils/logging.js';
18
19
 
19
20
  // Load env variables if present; do not enforce key at import time
20
21
  dotenv.config();
@@ -56,7 +57,7 @@ async function sendPromptToClaude(prompt, options = {}) {
56
57
  const { model = DEFAULT_MODEL, maxTokens = MAX_TOKENS, temperature = 0.7, system = '', jsonSchema = null, cacheTtl = '5m' } = options;
57
58
 
58
59
  try {
59
- console.log(chalk.cyan('Sending prompt to Claude...'));
60
+ verboseLog(options, chalk.cyan('Sending prompt to Claude...'));
60
61
 
61
62
  const client = getAnthropicClient();
62
63
 
@@ -104,8 +105,8 @@ async function sendPromptToClaude(prompt, options = {}) {
104
105
  const response = await client.messages.create(requestParams);
105
106
 
106
107
  // Log response structure for debugging
107
- console.log(chalk.gray(` Response stop_reason: ${response.stop_reason}`));
108
- console.log(chalk.gray(` Response content blocks: ${response.content?.length || 0}`));
108
+ verboseLog(options, chalk.gray(` Response stop_reason: ${response.stop_reason}`));
109
+ verboseLog(options, chalk.gray(` Response content blocks: ${response.content?.length || 0}`));
109
110
 
110
111
  // Process response based on whether we used tool calling
111
112
  if (jsonSchema) {
@@ -13,6 +13,7 @@ import { getDefaultEmbeddingsSystem } from './embeddings/factory.js';
13
13
  import * as llm from './llm.js';
14
14
  import { FILE_SELECTION_SYSTEM_PROMPT, PROJECT_SUMMARY_SYSTEM_PROMPT } from './prompt-cache.js';
15
15
  import { isDocumentationFile, isTestFile } from './utils/file-validation.js';
16
+ import { verboseLog } from './utils/logging.js';
16
17
 
17
18
  // Consolidated file classification configuration
18
19
  const FILE_PATTERNS = {
@@ -198,9 +199,7 @@ export class ProjectAnalyzer {
198
199
  const { verbose = false, forceAnalysis = false } = options;
199
200
 
200
201
  try {
201
- if (verbose) {
202
- console.log(chalk.cyan('🔍 Starting project architecture analysis...'));
203
- }
202
+ verboseLog(verbose, chalk.cyan('🔍 Starting project architecture analysis...'));
204
203
 
205
204
  // Initialize LLM client
206
205
  if (!this.llm) {
@@ -212,16 +211,13 @@ export class ProjectAnalyzer {
212
211
  if (existingSummary && !forceAnalysis) {
213
212
  const currentHash = await this.calculateKeyFilesHash(existingSummary.keyFiles);
214
213
  if (existingSummary.keyFilesHash === currentHash) {
215
- if (verbose) {
216
- console.log(chalk.green('✅ Project analysis up-to-date (no key file changes detected)'));
217
- }
214
+ verboseLog(verbose, chalk.green('✅ Project analysis up-to-date (no key file changes detected)'));
218
215
  return existingSummary;
219
216
  }
220
- if (verbose) {
221
- console.log(chalk.yellow('🔄 Key files changed, regenerating analysis...'));
222
- }
223
- } else if (verbose) {
224
- console.log(
217
+ verboseLog(verbose, chalk.yellow('🔄 Key files changed, regenerating analysis...'));
218
+ } else {
219
+ verboseLog(
220
+ verbose,
225
221
  chalk.cyan(
226
222
  forceAnalysis
227
223
  ? '🔄 Force analysis requested - regenerating from scratch...'
@@ -235,10 +231,8 @@ export class ProjectAnalyzer {
235
231
  ? await this.validateAndUpdateKeyFiles(existingSummary.keyFiles, projectPath)
236
232
  : await this.discoverKeyFilesWithLLM(projectPath);
237
233
 
238
- if (verbose) {
239
- console.log(chalk.gray(` Found ${keyFiles.length} key architectural files`));
240
- console.log(chalk.cyan('🧠 Generating LLM-based project analysis...'));
241
- }
234
+ verboseLog(verbose, chalk.gray(` Found ${keyFiles.length} key architectural files`));
235
+ verboseLog(verbose, chalk.cyan('🧠 Generating LLM-based project analysis...'));
242
236
 
243
237
  // Generate summary
244
238
  const projectSummary = await this.generateProjectSummary(keyFiles, projectPath);
@@ -254,12 +248,10 @@ export class ProjectAnalyzer {
254
248
  this.keyFiles = keyFiles;
255
249
  this.lastAnalysisHash = currentHash;
256
250
 
257
- if (verbose) {
258
- console.log(chalk.green('✅ Project analysis complete'));
259
- console.log(chalk.gray(` Technologies: ${(projectSummary.technologies || []).join(', ')}`));
260
- console.log(chalk.gray(` Key patterns: ${(projectSummary.keyPatterns || []).length} identified`));
261
- console.log(chalk.gray(` Key files tracked: ${keyFiles.length}`));
262
- }
251
+ verboseLog(verbose, chalk.green('✅ Project analysis complete'));
252
+ verboseLog(verbose, chalk.gray(` Technologies: ${(projectSummary.technologies || []).join(', ')}`));
253
+ verboseLog(verbose, chalk.gray(` Key patterns: ${(projectSummary.keyPatterns || []).length} identified`));
254
+ verboseLog(verbose, chalk.gray(` Key files tracked: ${keyFiles.length}`));
263
255
 
264
256
  return projectSummary;
265
257
  } catch (error) {
@@ -300,7 +292,7 @@ export class ProjectAnalyzer {
300
292
  try {
301
293
  const embeddingsSystem = getDefaultEmbeddingsSystem();
302
294
  await embeddingsSystem.storeProjectSummary(projectPath, projectSummary);
303
- console.log(chalk.green('✅ Project analysis stored in database'));
295
+ verboseLog({}, chalk.green('✅ Project analysis stored in database'));
304
296
  } catch (error) {
305
297
  console.error(chalk.yellow('Warning: Could not store analysis:'), error.message);
306
298
  }
@@ -328,7 +320,7 @@ export class ProjectAnalyzer {
328
320
 
329
321
  // If we lost more than 30% of key files, trigger fresh discovery
330
322
  if (validatedFiles.length < existingKeyFiles.length * 0.7) {
331
- console.log(chalk.yellow('⚠️ Many key files missing, performing fresh discovery...'));
323
+ verboseLog({}, chalk.yellow('⚠️ Many key files missing, performing fresh discovery...'));
332
324
  return await this.discoverKeyFilesWithLLM(projectPath);
333
325
  }
334
326
 
@@ -339,10 +331,10 @@ export class ProjectAnalyzer {
339
331
  * Discover key architectural files using LanceDB hybrid search
340
332
  */
341
333
  async discoverKeyFilesWithLLM(projectPath) {
342
- console.log(chalk.cyan('🔍 Mining codebase embeddings with LanceDB hybrid search...'));
334
+ verboseLog({}, chalk.cyan('🔍 Mining codebase embeddings with LanceDB hybrid search...'));
343
335
 
344
336
  const keyFilesByCategory = await this.mineKeyFilesFromEmbeddings(projectPath);
345
- console.log(chalk.cyan(`🧠 LLM analyzing ${keyFilesByCategory.length} candidates from embedding search...`));
337
+ verboseLog({}, chalk.cyan(`🧠 LLM analyzing ${keyFilesByCategory.length} candidates from embedding search...`));
346
338
 
347
339
  const keyFiles = await this.selectFinalKeyFiles(keyFilesByCategory, projectPath);
348
340
  return keyFiles;
@@ -362,7 +354,7 @@ export class ProjectAnalyzer {
362
354
  await table.optimize();
363
355
  } catch (optimizeError) {
364
356
  if (optimizeError.message && optimizeError.message.includes('legacy format')) {
365
- console.log(chalk.yellow(`Skipping optimization due to legacy index format - will be auto-upgraded during normal operations`));
357
+ console.warn(chalk.yellow(`Skipping optimization due to legacy index format - will be auto-upgraded during normal operations`));
366
358
  } else {
367
359
  console.warn(chalk.yellow(`Warning: Failed to optimize file embeddings table: ${optimizeError.message}`));
368
360
  }
@@ -371,7 +363,7 @@ export class ProjectAnalyzer {
371
363
  const keyFiles = new Map();
372
364
 
373
365
  try {
374
- console.log(chalk.gray(` 📊 Using LanceDB hybrid search for project: ${projectPath}`));
366
+ verboseLog({}, chalk.gray(` 📊 Using LanceDB hybrid search for project: ${projectPath}`));
375
367
 
376
368
  // Unified query function
377
369
  const queryFiles = async (config) => {
@@ -414,17 +406,17 @@ export class ProjectAnalyzer {
414
406
 
415
407
  return await query.limit(config.limit || 30).toArray();
416
408
  } catch (error) {
417
- console.log(chalk.yellow(` ⚠️ Query failed for ${config.category}: ${error.message}`));
409
+ verboseLog({}, chalk.yellow(` ⚠️ Query failed for ${config.category}: ${error.message}`));
418
410
  return [];
419
411
  }
420
412
  };
421
413
 
422
414
  // Execute all searches
423
415
  for (const config of DB_SEARCH_CONFIGS) {
424
- console.log(chalk.gray(` 🔍 Searching for ${config.category} files...`));
416
+ verboseLog({}, chalk.gray(` 🔍 Searching for ${config.category} files...`));
425
417
 
426
418
  const results = await queryFiles(config);
427
- console.log(chalk.gray(` 📦 Found ${results.length} ${config.category} file candidates`));
419
+ verboseLog({}, chalk.gray(` 📦 Found ${results.length} ${config.category} file candidates`));
428
420
 
429
421
  results.forEach((result) => {
430
422
  if (this.matchesFileType(result.path, result.name, config.matcher)) {
@@ -438,7 +430,7 @@ export class ProjectAnalyzer {
438
430
  }
439
431
 
440
432
  const results = Array.from(keyFiles.values());
441
- console.log(chalk.cyan(`🗃️ Found ${results.length} key files from embeddings database`));
433
+ verboseLog({}, chalk.cyan(`🗃️ Found ${results.length} key files from embeddings database`));
442
434
  return results;
443
435
  }
444
436
 
@@ -475,11 +467,11 @@ export class ProjectAnalyzer {
475
467
  */
476
468
  async selectFinalKeyFiles(candidates, projectPath) {
477
469
  if (candidates.length === 0) {
478
- console.log(chalk.yellow('⚠️ No candidates found from embeddings search'));
470
+ verboseLog({}, chalk.yellow('⚠️ No candidates found from embeddings search'));
479
471
  return [];
480
472
  }
481
473
 
482
- console.log(chalk.cyan(`🤖 LLM analyzing ${candidates.length} candidates...`));
474
+ verboseLog({}, chalk.cyan(`🤖 LLM analyzing ${candidates.length} candidates...`));
483
475
 
484
476
  const candidatesSummary = candidates
485
477
  .map((file, index) => {
@@ -520,7 +512,7 @@ Select files following the criteria in the system instructions.`;
520
512
  jsonSchema: fileSelectionSchema,
521
513
  });
522
514
 
523
- console.log(chalk.gray(' 📄 LLM Response preview:'), response.content.substring(0, 200));
515
+ verboseLog({}, chalk.gray(' 📄 LLM Response preview:'), response.content.substring(0, 200));
524
516
 
525
517
  const selectedPaths = response.json.selectedFiles;
526
518
 
@@ -546,14 +538,14 @@ Select files following the criteria in the system instructions.`;
546
538
  })
547
539
  .filter(Boolean);
548
540
 
549
- console.log(chalk.cyan(`🎯 LLM selected ${keyFiles.length} final key files`));
541
+ verboseLog({}, chalk.cyan(`🎯 LLM selected ${keyFiles.length} final key files`));
550
542
  return keyFiles;
551
543
  } else {
552
544
  throw new Error(`Failed to extract valid JSON array from LLM response`);
553
545
  }
554
546
  } catch (error) {
555
547
  console.error(chalk.red('Error in LLM selection:'), error.message);
556
- console.log(chalk.yellow(' 🔄 Falling back to automatic selection...'));
548
+ verboseLog({}, chalk.yellow(' 🔄 Falling back to automatic selection...'));
557
549
  return this.fallbackFileSelection(candidates, projectPath);
558
550
  }
559
551
  }
@@ -588,7 +580,7 @@ Select files following the criteria in the system instructions.`;
588
580
  }
589
581
  }
590
582
 
591
- console.log(chalk.yellow(`⚠️ Used fallback selection: ${fallbackFiles.length} files`));
583
+ verboseLog({}, chalk.yellow(`⚠️ Used fallback selection: ${fallbackFiles.length} files`));
592
584
  return fallbackFiles;
593
585
  }
594
586
 
@@ -793,7 +785,7 @@ Follow the analysis guidelines from the system instructions to identify custom i
793
785
  } catch (error) {
794
786
  console.error(chalk.red('Error generating project summary:'), error.message);
795
787
  const fallback = this.createFallbackSummary(projectPath, keyFiles);
796
- console.log(chalk.yellow('Using fallback summary with technologies:'), fallback.technologies);
788
+ verboseLog({}, chalk.yellow('Using fallback summary with technologies:'), fallback.technologies);
797
789
  return fallback;
798
790
  }
799
791
  }
@@ -857,7 +849,8 @@ Follow the analysis guidelines from the system instructions to identify custom i
857
849
  };
858
850
  }
859
851
 
860
- console.log(
852
+ verboseLog(
853
+ {},
861
854
  chalk.cyan(
862
855
  `✅ Project summary validated - Technologies: ${validatedSummary.technologies.length}, Frameworks: ${validatedSummary.mainFrameworks.length}`
863
856
  )