@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 +182 -23
- package/lib/commands/hallucination-commands.js +453 -0
- package/lib/enhanced-hallucination-detector.js +622 -0
- package/lib/execution-based-detector.js +538 -0
- package/lib/execution-sandbox.js +602 -0
- package/lib/hallucination-database-service.js +447 -0
- package/lib/hallucination-patterns.js +490 -0
- package/lib/types/database-types.js +5 -0
- package/lib/types/hallucination-types.js +74 -0
- package/lib/types/index.js +8 -0
- package/lib/ui.js +73 -6
- package/package.json +1 -1
- package/lib/auth.js +0 -73
- package/lib/cli.test.js +0 -49
- package/lib/code-review.js +0 -319
- package/lib/config.js +0 -7
- package/lib/sync.js +0 -117
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.
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
|
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
|
-
`š°
|
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',
|