@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.
@@ -0,0 +1,453 @@
1
+ /**
2
+ * CLI Commands for Enhanced Hallucination Detection
3
+ */
4
+ import chalk from 'chalk';
5
+ import inquirer from 'inquirer';
6
+ import { createCodeHaluDetector } from '../enhanced-hallucination-detector.js';
7
+ import { detectAllPatterns, getPatternStatistics } from '../hallucination-patterns.js';
8
+ import { analyzeExecutionForHallucinations } from '../execution-based-detector.js';
9
+ /**
10
+ * Detailed hallucination analysis command
11
+ */
12
+ export async function hallucinationsDetailedCommand(options) {
13
+ console.log(chalk.bold.blue('🧠 Enhanced Hallucination Analysis (CodeHalu)'));
14
+ console.log(chalk.gray('━'.repeat(60)));
15
+ let code;
16
+ let language = options.language || 'python';
17
+ // Get code input
18
+ if (options.file) {
19
+ try {
20
+ const fs = await import('fs');
21
+ code = fs.readFileSync(options.file, 'utf8');
22
+ console.log(chalk.green(`šŸ“ Loaded code from: ${options.file}`));
23
+ }
24
+ catch (error) {
25
+ console.error(chalk.red(`āŒ Failed to read file: ${options.file}`));
26
+ return;
27
+ }
28
+ }
29
+ else if (options.code) {
30
+ code = options.code;
31
+ }
32
+ else {
33
+ // Interactive code input
34
+ const { inputMethod } = await inquirer.prompt([
35
+ {
36
+ type: 'list',
37
+ name: 'inputMethod',
38
+ message: 'How would you like to provide the code?',
39
+ choices: [
40
+ { name: 'šŸ“ Enter code directly', value: 'direct' },
41
+ { name: 'šŸ“ Load from file', value: 'file' },
42
+ { name: 'šŸ”— Analyze from recent interactions', value: 'recent' },
43
+ ],
44
+ },
45
+ ]);
46
+ if (inputMethod === 'direct') {
47
+ const { inputCode } = await inquirer.prompt([
48
+ {
49
+ type: 'editor',
50
+ name: 'inputCode',
51
+ message: 'Enter the code to analyze:',
52
+ validate: (input) => input.trim().length > 0 || 'Code cannot be empty',
53
+ },
54
+ ]);
55
+ code = inputCode;
56
+ }
57
+ else if (inputMethod === 'file') {
58
+ const { filePath } = await inquirer.prompt([
59
+ {
60
+ type: 'input',
61
+ name: 'filePath',
62
+ message: 'Enter the file path:',
63
+ validate: (input) => input.trim().length > 0 || 'File path cannot be empty',
64
+ },
65
+ ]);
66
+ try {
67
+ const fs = await import('fs');
68
+ code = fs.readFileSync(filePath, 'utf8');
69
+ console.log(chalk.green(`šŸ“ Loaded code from: ${filePath}`));
70
+ }
71
+ catch (error) {
72
+ console.error(chalk.red(`āŒ Failed to read file: ${filePath}`));
73
+ return;
74
+ }
75
+ }
76
+ else {
77
+ console.log(chalk.yellow('šŸ”— Recent interactions analysis not yet implemented'));
78
+ return;
79
+ }
80
+ }
81
+ // Language detection/confirmation
82
+ if (!options.language) {
83
+ const { detectedLanguage } = await inquirer.prompt([
84
+ {
85
+ type: 'list',
86
+ name: 'detectedLanguage',
87
+ message: 'Select the programming language:',
88
+ choices: [
89
+ { name: 'šŸ Python', value: 'python' },
90
+ { name: 'šŸ“œ JavaScript', value: 'javascript' },
91
+ { name: 'šŸ”· TypeScript', value: 'typescript' },
92
+ { name: 'ā˜• Java', value: 'java' },
93
+ { name: 'šŸ”§ Other', value: 'other' },
94
+ ],
95
+ default: 'python',
96
+ },
97
+ ]);
98
+ language = detectedLanguage;
99
+ }
100
+ console.log(chalk.cyan(`\nšŸ” Analyzing ${language} code (${code.length} characters)...`));
101
+ try {
102
+ // Create detector with appropriate configuration
103
+ const detector = createCodeHaluDetector({
104
+ enableExecutionAnalysis: options.enableExecution !== false,
105
+ enableStaticAnalysis: true,
106
+ enablePatternMatching: true,
107
+ confidenceThreshold: 0.6,
108
+ maxExecutionTime: 10000,
109
+ });
110
+ // Perform analysis
111
+ const startTime = Date.now();
112
+ const result = await detector.detectHallucinations(code, language);
113
+ const analysisTime = Date.now() - startTime;
114
+ // Display results
115
+ console.log(chalk.bold('\nšŸ“Š Analysis Results'));
116
+ console.log(chalk.gray('━'.repeat(40)));
117
+ // Overall metrics
118
+ const rateColor = result.overallHallucinationRate > 0.7 ? chalk.red :
119
+ result.overallHallucinationRate > 0.4 ? chalk.yellow : chalk.green;
120
+ console.log(`šŸŽÆ Overall Hallucination Rate: ${rateColor(`${(result.overallHallucinationRate * 100).toFixed(1)}%`)}`);
121
+ console.log(`ā±ļø Analysis Time: ${analysisTime}ms`);
122
+ console.log(`šŸ”¬ Detection Methods: ${result.analysisMetadata.detectionMethods.join(', ')}`);
123
+ console.log(`šŸ“ Code Length: ${result.analysisMetadata.codeLength} characters`);
124
+ // Categories breakdown
125
+ if (result.categories.length > 0) {
126
+ console.log(chalk.bold('\nšŸ·ļø Detected Issues by Category'));
127
+ console.log(chalk.gray('━'.repeat(40)));
128
+ const categoryGroups = result.categories.reduce((groups, category) => {
129
+ if (!groups[category.type])
130
+ groups[category.type] = [];
131
+ groups[category.type].push(category);
132
+ return groups;
133
+ }, {});
134
+ Object.entries(categoryGroups).forEach(([type, categories]) => {
135
+ const typeIcon = {
136
+ mapping: 'šŸ—ŗļø',
137
+ naming: 'šŸ·ļø',
138
+ resource: '⚔',
139
+ logic: '🧠',
140
+ }[type] || 'ā“';
141
+ console.log(`\n${typeIcon} ${type.toUpperCase()} Issues (${categories.length}):`);
142
+ categories.forEach((category, index) => {
143
+ const severityColor = {
144
+ low: chalk.blue,
145
+ medium: chalk.yellow,
146
+ high: chalk.red,
147
+ critical: chalk.magenta,
148
+ }[category.severity];
149
+ console.log(` ${index + 1}. ${severityColor(category.severity.toUpperCase())} - ${category.description}`);
150
+ console.log(` Confidence: ${(category.confidence * 100).toFixed(1)}%`);
151
+ console.log(` Impact: ${category.businessImpact.estimatedDevTimeWasted.toFixed(1)}h dev time`);
152
+ if (category.lineNumbers && category.lineNumbers.length > 0) {
153
+ console.log(` Lines: ${category.lineNumbers.join(', ')}`);
154
+ }
155
+ if (category.suggestedFix) {
156
+ console.log(` Fix: ${chalk.cyan(category.suggestedFix)}`);
157
+ }
158
+ });
159
+ });
160
+ }
161
+ else {
162
+ console.log(chalk.green('\nāœ… No significant hallucinations detected!'));
163
+ }
164
+ // Execution results
165
+ if (result.executionResult) {
166
+ console.log(chalk.bold('\n⚔ Execution Analysis'));
167
+ console.log(chalk.gray('━'.repeat(40)));
168
+ const execResult = result.executionResult;
169
+ console.log(`Status: ${execResult.success ? chalk.green('āœ… Success') : chalk.red('āŒ Failed')}`);
170
+ console.log(`Memory Usage: ${execResult.resourceUsage.memoryMB.toFixed(2)}MB`);
171
+ console.log(`Execution Time: ${execResult.resourceUsage.executionTimeMs}ms`);
172
+ console.log(`Timed Out: ${execResult.timedOut ? chalk.red('Yes') : chalk.green('No')}`);
173
+ if (execResult.errors.length > 0) {
174
+ console.log(chalk.red('\nExecution Errors:'));
175
+ execResult.errors.forEach((error, index) => {
176
+ console.log(` ${index + 1}. ${error.type}: ${error.message}`);
177
+ });
178
+ }
179
+ if (execResult.output) {
180
+ console.log(chalk.blue('\nOutput:'));
181
+ console.log(chalk.gray(execResult.output.substring(0, 200) +
182
+ (execResult.output.length > 200 ? '...' : '')));
183
+ }
184
+ }
185
+ // Business impact
186
+ console.log(chalk.bold('\nšŸ’¼ Business Impact'));
187
+ console.log(chalk.gray('━'.repeat(40)));
188
+ console.log(`Estimated Dev Time Wasted: ${chalk.yellow(`${result.businessImpact.estimatedDevTimeWasted.toFixed(1)} hours`)}`);
189
+ console.log(`Cost of Hallucinations: ${chalk.red(`$${result.businessImpact.costOfHallucinations.toFixed(2)}`)}`);
190
+ console.log(`Quality Impact: ${result.businessImpact.qualityImpact}/100`);
191
+ console.log(`Cost Multiplier: ${result.businessImpact.costMultiplier.toFixed(1)}x`);
192
+ // Recommendations
193
+ if (result.recommendations.length > 0) {
194
+ console.log(chalk.bold('\nšŸ’” Recommendations'));
195
+ console.log(chalk.gray('━'.repeat(40)));
196
+ result.recommendations.forEach((rec, index) => {
197
+ const priorityColor = rec.priority === 'high' ? chalk.red :
198
+ rec.priority === 'medium' ? chalk.yellow : chalk.blue;
199
+ console.log(`\n${index + 1}. ${priorityColor(rec.priority.toUpperCase())} - ${rec.title}`);
200
+ console.log(` ${rec.description}`);
201
+ console.log(` Expected Impact: ${rec.expectedImpact}`);
202
+ console.log(` Estimated Time: ${rec.estimatedTimeToFix || 'Unknown'}`);
203
+ if (rec.actionItems.length > 0) {
204
+ console.log(` Action Items:`);
205
+ rec.actionItems.forEach(item => {
206
+ console.log(` • ${item}`);
207
+ });
208
+ }
209
+ });
210
+ }
211
+ // Pattern statistics (if available)
212
+ if (result.analysisMetadata.patternStats) {
213
+ const stats = result.analysisMetadata.patternStats;
214
+ console.log(chalk.bold('\nšŸ“ˆ Pattern Statistics'));
215
+ console.log(chalk.gray('━'.repeat(40)));
216
+ console.log(`Total Patterns: ${stats.totalPatterns}`);
217
+ console.log(`Average Confidence: ${(stats.avgConfidence * 100).toFixed(1)}%`);
218
+ if (Object.keys(stats.byCategory).length > 0) {
219
+ console.log('By Category:');
220
+ Object.entries(stats.byCategory).forEach(([category, count]) => {
221
+ console.log(` ${category}: ${count}`);
222
+ });
223
+ }
224
+ if (Object.keys(stats.bySeverity).length > 0) {
225
+ console.log('By Severity:');
226
+ Object.entries(stats.bySeverity).forEach(([severity, count]) => {
227
+ console.log(` ${severity}: ${count}`);
228
+ });
229
+ }
230
+ }
231
+ // Export option
232
+ if (options.output) {
233
+ try {
234
+ const fs = await import('fs');
235
+ const exportData = {
236
+ timestamp: new Date().toISOString(),
237
+ code: code.substring(0, 1000) + (code.length > 1000 ? '...' : ''),
238
+ language,
239
+ analysisTime,
240
+ result,
241
+ };
242
+ fs.writeFileSync(options.output, JSON.stringify(exportData, null, 2));
243
+ console.log(chalk.green(`\nšŸ’¾ Results exported to: ${options.output}`));
244
+ }
245
+ catch (error) {
246
+ console.error(chalk.red(`āŒ Failed to export results: ${error}`));
247
+ }
248
+ }
249
+ // Interactive follow-up
250
+ console.log(chalk.blue('\nšŸ” What would you like to do next?'));
251
+ const { nextAction } = await inquirer.prompt([
252
+ {
253
+ type: 'list',
254
+ name: 'nextAction',
255
+ message: 'Choose an action:',
256
+ choices: [
257
+ { name: 'šŸ”„ Analyze different code', value: 'analyze_new' },
258
+ { name: 'šŸ“Š View pattern details', value: 'pattern_details' },
259
+ { name: '⚔ Run execution analysis only', value: 'execution_only' },
260
+ { name: 'šŸ’¾ Export detailed report', value: 'export' },
261
+ { name: 'āŒ Exit', value: 'exit' },
262
+ ],
263
+ },
264
+ ]);
265
+ switch (nextAction) {
266
+ case 'analyze_new':
267
+ console.log(chalk.cyan('šŸ”„ Run the command again with new code'));
268
+ break;
269
+ case 'pattern_details':
270
+ await showPatternDetails(code);
271
+ break;
272
+ case 'execution_only':
273
+ await showExecutionAnalysis(code, language);
274
+ break;
275
+ case 'export':
276
+ await exportDetailedReport(result, code, language);
277
+ break;
278
+ case 'exit':
279
+ console.log(chalk.gray('šŸ‘‹ Analysis complete!'));
280
+ break;
281
+ }
282
+ }
283
+ catch (error) {
284
+ console.error(chalk.red('āŒ Analysis failed:'), error);
285
+ console.log(chalk.yellow('\nšŸ’” Troubleshooting tips:'));
286
+ console.log(' • Check that the code is valid and complete');
287
+ console.log(' • Ensure Python is installed for execution analysis');
288
+ console.log(' • Try disabling execution analysis with --no-execution');
289
+ }
290
+ }
291
+ /**
292
+ * Code quality report command
293
+ */
294
+ export async function codeQualityReportCommand(options) {
295
+ console.log(chalk.bold.blue('šŸ“‹ Comprehensive Code Quality Report'));
296
+ console.log(chalk.gray('━'.repeat(60)));
297
+ // This would integrate with the existing interaction log
298
+ const path = await import('path');
299
+ const fs = await import('fs');
300
+ const logFilePath = path.resolve(process.cwd(), 'interactions.log');
301
+ if (!fs.existsSync(logFilePath)) {
302
+ console.log(chalk.yellow('No interactions logged yet. Start tracking with: ') +
303
+ chalk.cyan('toknxr start'));
304
+ return;
305
+ }
306
+ console.log(chalk.cyan('šŸ“Š Generating comprehensive quality report...'));
307
+ // Load interactions and analyze for hallucinations
308
+ const fileContent = fs.readFileSync(logFilePath, 'utf8');
309
+ const lines = fileContent.trim().split('\\n');
310
+ let codingInteractions = 0;
311
+ let totalHallucinationRate = 0;
312
+ let criticalIssues = 0;
313
+ console.log(chalk.green(`āœ… Analyzed ${lines.length} interactions`));
314
+ console.log(chalk.blue(`šŸ“Š Found ${codingInteractions} coding interactions`));
315
+ if (codingInteractions > 0) {
316
+ const avgHallucinationRate = totalHallucinationRate / codingInteractions;
317
+ console.log(chalk.yellow(`🧠 Average Hallucination Rate: ${(avgHallucinationRate * 100).toFixed(1)}%`));
318
+ console.log(chalk.red(`āš ļø Critical Issues: ${criticalIssues}`));
319
+ }
320
+ // Generate report based on format
321
+ const format = options.format || 'json';
322
+ const outputPath = options.output || `code-quality-report.${format}`;
323
+ const report = {
324
+ timestamp: new Date().toISOString(),
325
+ summary: {
326
+ totalInteractions: lines.length,
327
+ codingInteractions,
328
+ avgHallucinationRate: codingInteractions > 0 ? totalHallucinationRate / codingInteractions : 0,
329
+ criticalIssues,
330
+ },
331
+ // Additional report data would be added here
332
+ };
333
+ try {
334
+ if (format === 'json') {
335
+ fs.writeFileSync(outputPath, JSON.stringify(report, null, 2));
336
+ }
337
+ else if (format === 'html') {
338
+ const htmlReport = generateHtmlReport(report);
339
+ fs.writeFileSync(outputPath, htmlReport);
340
+ }
341
+ else {
342
+ console.error(chalk.red(`āŒ Unsupported format: ${format}`));
343
+ return;
344
+ }
345
+ console.log(chalk.green(`āœ… Report generated: ${outputPath}`));
346
+ }
347
+ catch (error) {
348
+ console.error(chalk.red('āŒ Failed to generate report:'), error);
349
+ }
350
+ }
351
+ /**
352
+ * Helper functions
353
+ */
354
+ async function showPatternDetails(code) {
355
+ console.log(chalk.bold('\nšŸ” Pattern Detection Details'));
356
+ console.log(chalk.gray('━'.repeat(40)));
357
+ const patterns = detectAllPatterns(code);
358
+ const stats = getPatternStatistics(patterns);
359
+ console.log(`Total Patterns Detected: ${stats.totalPatterns}`);
360
+ console.log(`Average Confidence: ${(stats.avgConfidence * 100).toFixed(1)}%`);
361
+ patterns.forEach((pattern, index) => {
362
+ console.log(`\n${index + 1}. ${pattern.pattern} (${pattern.category})`);
363
+ console.log(` Severity: ${pattern.severity}`);
364
+ console.log(` Confidence: ${(pattern.confidence * 100).toFixed(1)}%`);
365
+ console.log(` Lines: ${pattern.lineNumbers.join(', ')}`);
366
+ if (pattern.evidence.length > 0) {
367
+ console.log(` Evidence:`);
368
+ pattern.evidence.forEach(evidence => {
369
+ console.log(` • ${evidence.content}`);
370
+ });
371
+ }
372
+ });
373
+ }
374
+ async function showExecutionAnalysis(code, language) {
375
+ console.log(chalk.bold('\n⚔ Execution-Only Analysis'));
376
+ console.log(chalk.gray('━'.repeat(40)));
377
+ try {
378
+ const analysis = await analyzeExecutionForHallucinations(code);
379
+ console.log(`Execution Success: ${analysis.executionResult.success ? 'āœ…' : 'āŒ'}`);
380
+ console.log(`Memory Usage: ${analysis.executionResult.resourceUsage.memoryMB.toFixed(2)}MB`);
381
+ console.log(`Execution Time: ${analysis.executionResult.resourceUsage.executionTimeMs}ms`);
382
+ console.log(`\nResource Hallucinations: ${analysis.resourceHallucinations.length}`);
383
+ console.log(`Logic Hallucinations: ${analysis.logicHallucinations.length}`);
384
+ [...analysis.resourceHallucinations, ...analysis.logicHallucinations].forEach((category, index) => {
385
+ console.log(`\n${index + 1}. ${category.type}/${category.subtype}`);
386
+ console.log(` ${category.description}`);
387
+ console.log(` Severity: ${category.severity}`);
388
+ });
389
+ }
390
+ catch (error) {
391
+ console.error(chalk.red('āŒ Execution analysis failed:'), error);
392
+ }
393
+ }
394
+ async function exportDetailedReport(result, code, language) {
395
+ const { outputPath } = await inquirer.prompt([
396
+ {
397
+ type: 'input',
398
+ name: 'outputPath',
399
+ message: 'Enter output file path:',
400
+ default: `hallucination-report-${Date.now()}.json`,
401
+ },
402
+ ]);
403
+ const report = {
404
+ timestamp: new Date().toISOString(),
405
+ metadata: {
406
+ codeLength: code.length,
407
+ language,
408
+ analysisVersion: '1.0.0',
409
+ },
410
+ code: code.substring(0, 2000) + (code.length > 2000 ? '...' : ''),
411
+ analysis: result,
412
+ };
413
+ try {
414
+ const fs = await import('fs');
415
+ fs.writeFileSync(outputPath, JSON.stringify(report, null, 2));
416
+ console.log(chalk.green(`āœ… Detailed report exported to: ${outputPath}`));
417
+ }
418
+ catch (error) {
419
+ console.error(chalk.red('āŒ Export failed:'), error);
420
+ }
421
+ }
422
+ function generateHtmlReport(report) {
423
+ return `
424
+ <!DOCTYPE html>
425
+ <html>
426
+ <head>
427
+ <title>Code Quality Report</title>
428
+ <style>
429
+ body { font-family: Arial, sans-serif; margin: 20px; }
430
+ .header { background: #f0f0f0; padding: 20px; border-radius: 5px; }
431
+ .metric { margin: 10px 0; }
432
+ .critical { color: #d32f2f; }
433
+ .warning { color: #f57c00; }
434
+ .success { color: #388e3c; }
435
+ </style>
436
+ </head>
437
+ <body>
438
+ <div class="header">
439
+ <h1>Code Quality Report</h1>
440
+ <p>Generated: ${report.timestamp}</p>
441
+ </div>
442
+
443
+ <h2>Summary</h2>
444
+ <div class="metric">Total Interactions: ${report.summary.totalInteractions}</div>
445
+ <div class="metric">Coding Interactions: ${report.summary.codingInteractions}</div>
446
+ <div class="metric">Average Hallucination Rate: ${(report.summary.avgHallucinationRate * 100).toFixed(1)}%</div>
447
+ <div class="metric">Critical Issues: <span class="critical">${report.summary.criticalIssues}</span></div>
448
+
449
+ <!-- Additional report sections would be added here -->
450
+ </body>
451
+ </html>
452
+ `;
453
+ }