@goldensheepai/toknxr-cli 0.3.0 → 0.4.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/lib/cli.js CHANGED
@@ -20,11 +20,14 @@ process.stderr.on('error', (err) => {
20
20
  process.exit(0);
21
21
  });
22
22
  const program = new Command();
23
+ // Simple rainbow color function
24
+ function applyRainbow(text) {
25
+ const colors = [chalk.red, chalk.yellow, chalk.green, chalk.cyan, chalk.blue, chalk.magenta];
26
+ return text.split('').map((char, i) => colors[i % colors.length](char)).join('');
27
+ }
23
28
  // ASCII Art Welcome Screen with gradient colors
24
29
  const welcomeMessage = `
25
- ${chalk.bold.hex('#FFD700')('šŸ‘ Welcome to TokNXR by Golden Sheep AI šŸ‘')}
26
-
27
- ${chalk.bold.cyan('Your AI Effectiveness & Code Quality Analysis CLI')}
30
+ ${chalk.bold.cyan('TokNXR CLI - AI Effectiveness & Code Quality Analysis')}
28
31
 
29
32
  ${chalk.bold.underline('Getting Started Guide:')}
30
33
 
@@ -48,7 +51,6 @@ ${chalk.bold.white('Chapter 3: Need Assistance?')}
48
51
 
49
52
  ${chalk.gray('------------------------------------------------------------')}
50
53
  `;
51
- console.log(welcomeMessage);
52
54
  /**
53
55
  * Generate weekly cost trends for the cost chart visualization
54
56
  */
@@ -84,7 +86,7 @@ function generateWeeklyCostTrends(interactions) {
84
86
  }
85
87
  return dailyCosts;
86
88
  }
87
- program.name('toknxr').description('AI Effectiveness & Code Quality Analysis CLI').version('0.3.0');
89
+ program.name('toknxr').description('AI Effectiveness & Code Quality Analysis CLI').version('0.4.0');
88
90
  program
89
91
  .command('menu')
90
92
  .description('Interactive menu system for TokNXR operations')
@@ -107,6 +109,10 @@ program
107
109
  name: chalk.yellow('🧠 AI Analysis') + chalk.gray(' - Hallucination detection'),
108
110
  value: 'hallucinations',
109
111
  },
112
+ {
113
+ name: chalk.cyan('šŸ”¬ Enhanced Detection') + chalk.gray(' - CodeHalu analysis'),
114
+ value: 'enhanced_detection',
115
+ },
110
116
  { name: chalk.red('āš™ļø Initialize') + chalk.gray(' - Set up configuration'), value: 'init' },
111
117
  ]);
112
118
  try {
@@ -123,6 +129,9 @@ program
123
129
  case 'hallucinations':
124
130
  await program.parseAsync(['node', 'toknxr', 'hallucinations']);
125
131
  break;
132
+ case 'enhanced_detection':
133
+ await program.parseAsync(['node', 'toknxr', 'hallucinations-detailed']);
134
+ break;
126
135
  case 'init':
127
136
  await program.parseAsync(['node', 'toknxr', 'init']);
128
137
  break;
@@ -791,23 +800,23 @@ program
791
800
  break;
792
801
  case '2':
793
802
  console.log(chalk.magenta('\n🧠 Opening hallucination analysis...'));
794
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr hallucinations'));
803
+ await program.parseAsync(['node', 'toknxr', 'hallucinations']);
795
804
  break;
796
805
  case '3':
797
806
  console.log(chalk.yellow('\nšŸ”„ Opening provider comparison...'));
798
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr providers'));
807
+ await program.parseAsync(['node', 'toknxr', 'providers']);
799
808
  break;
800
809
  case '4':
801
810
  console.log(chalk.green('\nšŸ“ˆ Opening comprehensive analytics...'));
802
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr stats'));
811
+ await program.parseAsync(['node', 'toknxr', 'stats']);
803
812
  break;
804
813
  case '5':
805
814
  console.log(chalk.blue('\nšŸ” Opening interaction browser...'));
806
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr browse'));
815
+ await program.parseAsync(['node', 'toknxr', 'browse']);
807
816
  break;
808
817
  case 'm':
809
818
  console.log(chalk.gray('\nšŸ“‹ Opening main menu...'));
810
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr menu'));
819
+ await program.parseAsync(['node', 'toknxr', 'menu']);
811
820
  break;
812
821
  case 'q':
813
822
  console.log(chalk.gray('\nšŸ‘‹ Exiting code analysis...'));
@@ -821,6 +830,9 @@ import { hallucinationDetector } from './hallucination-detector.js';
821
830
  import { analyzeCodeQuality, scoreEffectiveness, extractCodeFromResponse, } from './code-analysis.js';
822
831
  import { aiAnalytics } from './ai-analytics.js';
823
832
  import { auditLogger, AuditEventType, initializeAuditLogging } from './audit-logger.js';
833
+ // Import enhanced hallucination detection commands
834
+ import { hallucinationsDetailedCommand, codeQualityReportCommand } from './commands/hallucination-commands.js';
835
+ import { detectCodeHallucinations } from './enhanced-hallucination-detector.js';
824
836
  program
825
837
  .command('analyze')
826
838
  .description('Analyze an AI response for hallucinations and quality issues')
@@ -925,6 +937,65 @@ program
925
937
  console.log(chalk.red(' āŒ Poor quality - significant issues detected'));
926
938
  }
927
939
  });
940
+ // Enhanced hallucination detection commands
941
+ program
942
+ .command('hallucinations-detailed')
943
+ .description('Detailed hallucination analysis with CodeHalu categories')
944
+ .option('-c, --category <category>', 'Filter by hallucination category')
945
+ .option('-p, --provider <provider>', 'Filter by AI provider')
946
+ .option('-f, --file <file>', 'Analyze code from file')
947
+ .option('--code <code>', 'Analyze code directly')
948
+ .option('-l, --language <language>', 'Programming language (default: python)')
949
+ .option('--no-execution', 'Disable execution analysis')
950
+ .option('-o, --output <file>', 'Export results to file')
951
+ .action(hallucinationsDetailedCommand);
952
+ program
953
+ .command('code-quality-report')
954
+ .description('Generate comprehensive code quality report')
955
+ .option('-o, --output <file>', 'Output file path')
956
+ .option('--format <format>', 'Output format (json|html)', 'json')
957
+ .option('--include-execution', 'Include execution analysis in report')
958
+ .action(codeQualityReportCommand);
959
+ program
960
+ .command('detect-hallucinations')
961
+ .description('Quick hallucination detection for code snippet')
962
+ .argument('<code>', 'Code to analyze')
963
+ .option('-l, --language <language>', 'Programming language (default: python)', 'python')
964
+ .option('--no-execution', 'Disable execution analysis')
965
+ .option('--confidence <threshold>', 'Confidence threshold (0.0-1.0)', '0.6')
966
+ .action(async (code, options) => {
967
+ console.log(chalk.bold.blue('šŸ” Quick Hallucination Detection'));
968
+ console.log(chalk.gray('━'.repeat(50)));
969
+ try {
970
+ const result = await detectCodeHallucinations(code, options.language, {
971
+ enableExecution: !options.noExecution,
972
+ confidenceThreshold: parseFloat(options.confidence),
973
+ });
974
+ const rateColor = result.overallHallucinationRate > 0.7 ? chalk.red :
975
+ result.overallHallucinationRate > 0.4 ? chalk.yellow : chalk.green;
976
+ console.log(`\nšŸŽÆ Hallucination Rate: ${rateColor(`${(result.overallHallucinationRate * 100).toFixed(1)}%`)}`);
977
+ console.log(`šŸ“Š Issues Found: ${result.categories.length}`);
978
+ console.log(`ā±ļø Analysis Time: ${result.analysisMetadata.detectionTimeMs}ms`);
979
+ if (result.categories.length > 0) {
980
+ console.log(chalk.yellow('\nāš ļø Top Issues:'));
981
+ result.categories.slice(0, 3).forEach((category, index) => {
982
+ console.log(` ${index + 1}. ${category.type}/${category.subtype} - ${category.description}`);
983
+ });
984
+ }
985
+ else {
986
+ console.log(chalk.green('\nāœ… No significant hallucinations detected!'));
987
+ }
988
+ if (result.recommendations.length > 0) {
989
+ console.log(chalk.blue('\nšŸ’” Quick Recommendations:'));
990
+ result.recommendations.slice(0, 2).forEach(rec => {
991
+ console.log(` • ${rec.title}`);
992
+ });
993
+ }
994
+ }
995
+ catch (error) {
996
+ console.error(chalk.red('āŒ Detection failed:'), error);
997
+ }
998
+ });
928
999
  program
929
1000
  .command('hallucinations')
930
1001
  .description('Show hallucination statistics and trends')
@@ -1019,11 +1090,11 @@ program
1019
1090
  switch (choice) {
1020
1091
  case '1':
1021
1092
  console.log(chalk.cyan('\nšŸ“Š Opening detailed hallucination analysis...'));
1022
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr code-analysis'));
1093
+ await program.parseAsync(['node', 'toknxr', 'code-analysis']);
1023
1094
  break;
1024
1095
  case '2':
1025
1096
  console.log(chalk.magenta('\nšŸ”„ Opening provider comparison...'));
1026
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr providers'));
1097
+ await program.parseAsync(['node', 'toknxr', 'providers']);
1027
1098
  break;
1028
1099
  case '3':
1029
1100
  console.log(chalk.yellow('\nšŸ’° Analyzing business impact...'));
@@ -1036,11 +1107,11 @@ program
1036
1107
  break;
1037
1108
  case '4':
1038
1109
  console.log(chalk.green('\nšŸ“ˆ Opening comprehensive analytics...'));
1039
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr stats'));
1110
+ await program.parseAsync(['node', 'toknxr', 'stats']);
1040
1111
  break;
1041
1112
  case 'm':
1042
1113
  console.log(chalk.gray('\nšŸ“‹ Opening main menu...'));
1043
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr menu'));
1114
+ await program.parseAsync(['node', 'toknxr', 'menu']);
1044
1115
  break;
1045
1116
  case 'q':
1046
1117
  console.log(chalk.gray('\nšŸ‘‹ Exiting hallucination analysis...'));
@@ -1184,7 +1255,7 @@ program
1184
1255
  break;
1185
1256
  case '2':
1186
1257
  console.log(chalk.magenta('\n🧠 Opening hallucination comparison...'));
1187
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr hallucinations'));
1258
+ await program.parseAsync(['node', 'toknxr', 'hallucinations']);
1188
1259
  break;
1189
1260
  case '3':
1190
1261
  console.log(chalk.yellow('\nšŸ’° Analyzing cost optimization...'));
@@ -1197,11 +1268,11 @@ program
1197
1268
  break;
1198
1269
  case '4':
1199
1270
  console.log(chalk.green('\nšŸ“ˆ Opening comprehensive analytics...'));
1200
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr stats'));
1271
+ await program.parseAsync(['node', 'toknxr', 'stats']);
1201
1272
  break;
1202
1273
  case 'm':
1203
1274
  console.log(chalk.gray('\nšŸ“‹ Opening main menu...'));
1204
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr menu'));
1275
+ await program.parseAsync(['node', 'toknxr', 'menu']);
1205
1276
  break;
1206
1277
  case 'q':
1207
1278
  console.log(chalk.gray('\nšŸ‘‹ Exiting provider comparison...'));
@@ -1404,15 +1475,88 @@ program
1404
1475
  break;
1405
1476
  case 'f':
1406
1477
  console.log(chalk.magenta('\nšŸ” Opening filter interface...'));
1407
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr filter'));
1478
+ await program.parseAsync(['node', 'toknxr', 'filter']);
1408
1479
  break;
1409
1480
  case 's':
1410
1481
  console.log(chalk.yellow('\nšŸ” Opening search interface...'));
1411
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr search --query "your terms"'));
1482
+ // Load interactions to generate relevant search suggestions
1483
+ const logFilePath = path.resolve(process.cwd(), 'interactions.log');
1484
+ let searchSuggestions = [];
1485
+ if (fs.existsSync(logFilePath)) {
1486
+ const fileContent = fs.readFileSync(logFilePath, 'utf8');
1487
+ const lines = fileContent.trim().split('\n');
1488
+ const interactions = lines
1489
+ .map(line => {
1490
+ try {
1491
+ return JSON.parse(line);
1492
+ }
1493
+ catch {
1494
+ return null;
1495
+ }
1496
+ })
1497
+ .filter((interaction) => interaction !== null);
1498
+ // Extract unique search suggestions from actual data
1499
+ const suggestions = new Set();
1500
+ interactions.forEach(interaction => {
1501
+ // Add providers
1502
+ if (interaction.provider)
1503
+ suggestions.add(interaction.provider);
1504
+ // Add models
1505
+ if (interaction.model && interaction.model !== 'unknown')
1506
+ suggestions.add(interaction.model);
1507
+ // Add task types
1508
+ if (interaction.taskType)
1509
+ suggestions.add(interaction.taskType);
1510
+ // Add key words from prompts
1511
+ if (interaction.userPrompt) {
1512
+ const words = interaction.userPrompt.toLowerCase().split(/\s+/);
1513
+ words.forEach(word => {
1514
+ if (word.length >= 3 && !['the', 'and', 'for', 'with', 'this', 'that', 'from', 'they', 'have', 'been', 'will', 'are', 'was', 'were'].includes(word)) {
1515
+ suggestions.add(word);
1516
+ }
1517
+ });
1518
+ }
1519
+ });
1520
+ searchSuggestions = Array.from(suggestions).slice(0, 15); // Limit to 15 suggestions
1521
+ }
1522
+ // Show search options
1523
+ const searchChoices = [
1524
+ { name: chalk.cyan('šŸ” Custom Search') + chalk.gray(' - Enter your own search terms'), value: 'custom' },
1525
+ ...searchSuggestions.map(suggestion => ({
1526
+ name: `šŸ”Ž "${suggestion}"`,
1527
+ value: suggestion
1528
+ }))
1529
+ ];
1530
+ const { searchChoice } = await inquirer.prompt([
1531
+ {
1532
+ type: 'list',
1533
+ name: 'searchChoice',
1534
+ message: 'What would you like to search for?',
1535
+ choices: searchChoices,
1536
+ pageSize: 10
1537
+ }
1538
+ ]);
1539
+ let searchQuery;
1540
+ if (searchChoice === 'custom') {
1541
+ const { customQuery } = await inquirer.prompt([
1542
+ {
1543
+ type: 'input',
1544
+ name: 'customQuery',
1545
+ message: 'Enter your search terms:',
1546
+ validate: (input) => input.trim().length >= 2 || 'Please enter at least 2 characters'
1547
+ }
1548
+ ]);
1549
+ searchQuery = customQuery;
1550
+ }
1551
+ else {
1552
+ searchQuery = searchChoice;
1553
+ }
1554
+ // Execute search command
1555
+ await program.parseAsync(['node', 'toknxr', 'search', '--query', searchQuery]);
1412
1556
  break;
1413
1557
  case 'a':
1414
1558
  console.log(chalk.green('\nšŸ“Š Opening analytics view...'));
1415
- console.log(chalk.gray('Run: ') + chalk.yellow('toknxr stats'));
1559
+ await program.parseAsync(['node', 'toknxr', 'stats']);
1416
1560
  break;
1417
1561
  case 'm':
1418
1562
  console.log(chalk.gray('\nšŸ“‹ Opening main menu...'));
@@ -1459,6 +1603,8 @@ program
1459
1603
  console.log(chalk.blue.bold(`\nšŸ” Searching for: "${query}"`));
1460
1604
  const availableFields = ['provider', 'model', 'userPrompt', 'taskType', 'requestId'];
1461
1605
  const searchOptions = await createSearchInterface(availableFields);
1606
+ // Set the query from the command line option
1607
+ searchOptions.query = query;
1462
1608
  if (!searchOptions) {
1463
1609
  console.log(chalk.gray('Search cancelled.'));
1464
1610
  return;
@@ -1506,20 +1652,33 @@ program
1506
1652
  let highlightColor;
1507
1653
  if (score >= 0.8)
1508
1654
  highlightColor = 'green';
1509
- else if (score >= 0.6)
1655
+ else if (score >= 0.5)
1510
1656
  highlightColor = 'yellow';
1511
1657
  else
1512
1658
  highlightColor = 'red';
1659
+ // Show which fields matched
1660
+ const matchedFields = [];
1661
+ searchOptions.fields.forEach(field => {
1662
+ const value = interaction[field];
1663
+ if (typeof value === 'string' && value.toLowerCase().includes(searchOptions.query.toLowerCase())) {
1664
+ matchedFields.push(field);
1665
+ }
1666
+ });
1513
1667
  const highlightedPrompt = highlightMatch(interaction.userPrompt || '', searchOptions.query);
1668
+ const highlightedModel = highlightMatch(interaction.model || '', searchOptions.query);
1669
+ const highlightedProvider = highlightMatch(interaction.provider || '', searchOptions.query);
1514
1670
  const colorFn = highlightColor === 'green'
1515
1671
  ? chalk.green
1516
1672
  : highlightColor === 'yellow'
1517
1673
  ? chalk.yellow
1518
1674
  : chalk.red;
1519
- return createBox(`#${num} ${interaction.provider} (${colorFn('ā˜…'.repeat(Math.ceil(score * 5)))})`, [
1675
+ const starCount = Math.max(1, Math.ceil(score * 5));
1676
+ const stars = colorFn('ā˜…'.repeat(starCount) + 'ā˜†'.repeat(5 - starCount));
1677
+ return createBox(`#${num} ${highlightedProvider} • ${highlightedModel} (${stars})`, [
1520
1678
  `šŸ“… ${chalk.gray(new Date(interaction.timestamp || Date.now()).toLocaleDateString())}`,
1521
1679
  `šŸŽÆ ${highlightedPrompt || 'No prompt available'}`,
1522
- `šŸ’° $${interaction.costUSD?.toFixed(4) || '0.0000'} • ⭐ ${interaction.codeQualityScore || 'N/A'}/100`,
1680
+ `šŸ’° ${interaction.costUSD?.toFixed(4) || '0.0000'} • ⭐ ${interaction.codeQualityScore || 'N/A'}/100`,
1681
+ `šŸ” Matched: ${chalk.cyan(matchedFields.join(', '))}`,
1523
1682
  ], {
1524
1683
  borderColor: highlightColor,
1525
1684
  titleColor: 'cyan',