@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
@@ -0,0 +1,447 @@
|
|
1
|
+
/**
|
2
|
+
* Hallucination Database Service
|
3
|
+
* Handles all database operations for hallucination analysis data
|
4
|
+
*/
|
5
|
+
/**
|
6
|
+
* Mock implementation of the hallucination database service
|
7
|
+
* In a real implementation, this would connect to Supabase/PostgreSQL
|
8
|
+
*/
|
9
|
+
export class MockHallucinationDatabaseService {
|
10
|
+
constructor() {
|
11
|
+
this.analyses = new Map();
|
12
|
+
this.categories = new Map();
|
13
|
+
this.executionResults = new Map();
|
14
|
+
this.recommendations = new Map();
|
15
|
+
this.historicalPatterns = new Map();
|
16
|
+
}
|
17
|
+
/**
|
18
|
+
* Create a new hallucination analysis record
|
19
|
+
*/
|
20
|
+
async createAnalysis(input) {
|
21
|
+
const id = this.generateId();
|
22
|
+
const now = new Date().toISOString();
|
23
|
+
const analysis = {
|
24
|
+
id,
|
25
|
+
...input,
|
26
|
+
created_at: now,
|
27
|
+
updated_at: now,
|
28
|
+
};
|
29
|
+
this.analyses.set(id, analysis);
|
30
|
+
return analysis;
|
31
|
+
}
|
32
|
+
/**
|
33
|
+
* Get complete hallucination analysis with all related data
|
34
|
+
*/
|
35
|
+
async getAnalysis(id) {
|
36
|
+
const analysis = this.analyses.get(id);
|
37
|
+
if (!analysis)
|
38
|
+
return null;
|
39
|
+
const categories = this.categories.get(id) || [];
|
40
|
+
const executionResult = this.executionResults.get(id);
|
41
|
+
const recommendations = this.recommendations.get(id) || [];
|
42
|
+
return {
|
43
|
+
analysis,
|
44
|
+
categories,
|
45
|
+
execution_result: executionResult,
|
46
|
+
execution_errors: [], // Would be populated from execution_errors table
|
47
|
+
recommendations,
|
48
|
+
};
|
49
|
+
}
|
50
|
+
/**
|
51
|
+
* Get analyses by interaction ID
|
52
|
+
*/
|
53
|
+
async getAnalysesByInteraction(interactionId) {
|
54
|
+
return Array.from(this.analyses.values()).filter(analysis => analysis.interaction_id === interactionId);
|
55
|
+
}
|
56
|
+
/**
|
57
|
+
* List analyses with optional filtering and pagination
|
58
|
+
*/
|
59
|
+
async listAnalyses(filters, pagination) {
|
60
|
+
let results = Array.from(this.analyses.values());
|
61
|
+
// Apply filters
|
62
|
+
if (filters) {
|
63
|
+
if (filters.overall_risk) {
|
64
|
+
results = results.filter(a => a.overall_risk === filters.overall_risk);
|
65
|
+
}
|
66
|
+
if (filters.has_critical_issues !== undefined) {
|
67
|
+
results = results.filter(a => a.has_critical_issues === filters.has_critical_issues);
|
68
|
+
}
|
69
|
+
if (filters.min_hallucination_rate !== undefined) {
|
70
|
+
results = results.filter(a => a.overall_hallucination_rate >= filters.min_hallucination_rate);
|
71
|
+
}
|
72
|
+
if (filters.max_hallucination_rate !== undefined) {
|
73
|
+
results = results.filter(a => a.overall_hallucination_rate <= filters.max_hallucination_rate);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
// Apply pagination
|
77
|
+
if (pagination) {
|
78
|
+
const page = pagination.page || 1;
|
79
|
+
const limit = pagination.limit || 10;
|
80
|
+
const offset = (page - 1) * limit;
|
81
|
+
// Sort if specified
|
82
|
+
if (pagination.sort_by) {
|
83
|
+
results.sort((a, b) => {
|
84
|
+
const aVal = a[pagination.sort_by];
|
85
|
+
const bVal = b[pagination.sort_by];
|
86
|
+
const order = pagination.sort_order === 'desc' ? -1 : 1;
|
87
|
+
return aVal < bVal ? -order : aVal > bVal ? order : 0;
|
88
|
+
});
|
89
|
+
}
|
90
|
+
results = results.slice(offset, offset + limit);
|
91
|
+
}
|
92
|
+
return results;
|
93
|
+
}
|
94
|
+
/**
|
95
|
+
* Create a new hallucination category
|
96
|
+
*/
|
97
|
+
async createCategory(input) {
|
98
|
+
const id = this.generateId();
|
99
|
+
const now = new Date().toISOString();
|
100
|
+
const category = {
|
101
|
+
id,
|
102
|
+
analysis_id: input.analysis_id,
|
103
|
+
category_type: input.category_type,
|
104
|
+
category_subtype: input.category_subtype, // Type assertion for subtype
|
105
|
+
severity: input.severity,
|
106
|
+
confidence: input.confidence,
|
107
|
+
detection_method: input.detection_method,
|
108
|
+
evidence: input.evidence,
|
109
|
+
line_numbers: input.line_numbers || null,
|
110
|
+
error_message: input.error_message || null,
|
111
|
+
suggested_fix: input.suggested_fix || null,
|
112
|
+
estimated_dev_time_wasted: input.estimated_dev_time_wasted,
|
113
|
+
cost_multiplier: input.cost_multiplier,
|
114
|
+
quality_impact: input.quality_impact,
|
115
|
+
estimated_cost_usd: input.estimated_cost_usd || null,
|
116
|
+
created_at: now,
|
117
|
+
};
|
118
|
+
// Add to categories map
|
119
|
+
const existingCategories = this.categories.get(input.analysis_id) || [];
|
120
|
+
existingCategories.push(category);
|
121
|
+
this.categories.set(input.analysis_id, existingCategories);
|
122
|
+
return category;
|
123
|
+
}
|
124
|
+
/**
|
125
|
+
* Get categories by analysis ID
|
126
|
+
*/
|
127
|
+
async getCategoriesByAnalysis(analysisId) {
|
128
|
+
return this.categories.get(analysisId) || [];
|
129
|
+
}
|
130
|
+
/**
|
131
|
+
* List categories with optional filtering
|
132
|
+
*/
|
133
|
+
async listCategories(filters, pagination) {
|
134
|
+
let results = [];
|
135
|
+
// Flatten all categories
|
136
|
+
for (const categories of this.categories.values()) {
|
137
|
+
results.push(...categories);
|
138
|
+
}
|
139
|
+
// Apply filters
|
140
|
+
if (filters) {
|
141
|
+
if (filters.category_type) {
|
142
|
+
results = results.filter(c => c.category_type === filters.category_type);
|
143
|
+
}
|
144
|
+
if (filters.severity) {
|
145
|
+
results = results.filter(c => c.severity === filters.severity);
|
146
|
+
}
|
147
|
+
if (filters.min_confidence !== undefined) {
|
148
|
+
results = results.filter(c => c.confidence >= filters.min_confidence);
|
149
|
+
}
|
150
|
+
if (filters.detection_method) {
|
151
|
+
results = results.filter(c => c.detection_method === filters.detection_method);
|
152
|
+
}
|
153
|
+
}
|
154
|
+
// Apply pagination (similar to listAnalyses)
|
155
|
+
if (pagination) {
|
156
|
+
const page = pagination.page || 1;
|
157
|
+
const limit = pagination.limit || 10;
|
158
|
+
const offset = (page - 1) * limit;
|
159
|
+
results = results.slice(offset, offset + limit);
|
160
|
+
}
|
161
|
+
return results;
|
162
|
+
}
|
163
|
+
/**
|
164
|
+
* Create execution result
|
165
|
+
*/
|
166
|
+
async createExecutionResult(input) {
|
167
|
+
const id = this.generateId();
|
168
|
+
const now = new Date().toISOString();
|
169
|
+
const executionResult = {
|
170
|
+
id,
|
171
|
+
...input,
|
172
|
+
exit_code: input.exit_code || null,
|
173
|
+
output: input.output || null,
|
174
|
+
stderr: input.stderr || null,
|
175
|
+
peak_memory_mb: input.peak_memory_mb || null,
|
176
|
+
system_calls: input.system_calls || null,
|
177
|
+
created_at: now,
|
178
|
+
};
|
179
|
+
this.executionResults.set(input.analysis_id, executionResult);
|
180
|
+
return executionResult;
|
181
|
+
}
|
182
|
+
/**
|
183
|
+
* Get execution result by analysis ID
|
184
|
+
*/
|
185
|
+
async getExecutionResult(analysisId) {
|
186
|
+
return this.executionResults.get(analysisId) || null;
|
187
|
+
}
|
188
|
+
/**
|
189
|
+
* Create recommendation
|
190
|
+
*/
|
191
|
+
async createRecommendation(input) {
|
192
|
+
const id = this.generateId();
|
193
|
+
const now = new Date().toISOString();
|
194
|
+
const recommendation = {
|
195
|
+
id,
|
196
|
+
...input,
|
197
|
+
estimated_time_to_fix: input.estimated_time_to_fix || null,
|
198
|
+
resources: input.resources || null,
|
199
|
+
created_at: now,
|
200
|
+
};
|
201
|
+
// Add to recommendations map
|
202
|
+
const existingRecommendations = this.recommendations.get(input.analysis_id) || [];
|
203
|
+
existingRecommendations.push(recommendation);
|
204
|
+
this.recommendations.set(input.analysis_id, existingRecommendations);
|
205
|
+
return recommendation;
|
206
|
+
}
|
207
|
+
/**
|
208
|
+
* Get recommendations by analysis ID
|
209
|
+
*/
|
210
|
+
async getRecommendationsByAnalysis(analysisId) {
|
211
|
+
return this.recommendations.get(analysisId) || [];
|
212
|
+
}
|
213
|
+
/**
|
214
|
+
* Get provider summary (mock implementation)
|
215
|
+
*/
|
216
|
+
async getProviderSummary() {
|
217
|
+
// In a real implementation, this would query the database view
|
218
|
+
return [
|
219
|
+
{
|
220
|
+
provider: 'Gemini-Pro',
|
221
|
+
total_analyses: 15,
|
222
|
+
avg_hallucination_rate: 0.65,
|
223
|
+
total_critical: 3,
|
224
|
+
total_high: 8,
|
225
|
+
total_medium: 4,
|
226
|
+
total_low: 0,
|
227
|
+
avg_quality_impact: 28.5,
|
228
|
+
},
|
229
|
+
{
|
230
|
+
provider: 'OpenAI-GPT4',
|
231
|
+
total_analyses: 8,
|
232
|
+
avg_hallucination_rate: 0.45,
|
233
|
+
total_critical: 1,
|
234
|
+
total_high: 3,
|
235
|
+
total_medium: 3,
|
236
|
+
total_low: 1,
|
237
|
+
avg_quality_impact: 18.2,
|
238
|
+
},
|
239
|
+
];
|
240
|
+
}
|
241
|
+
/**
|
242
|
+
* Get category breakdown (mock implementation)
|
243
|
+
*/
|
244
|
+
async getCategoryBreakdown() {
|
245
|
+
return [
|
246
|
+
{
|
247
|
+
category_type: 'naming',
|
248
|
+
category_subtype: 'identity',
|
249
|
+
occurrence_count: 12,
|
250
|
+
avg_confidence: 0.85,
|
251
|
+
avg_dev_time_wasted: 2.1,
|
252
|
+
avg_quality_impact: 22.0,
|
253
|
+
},
|
254
|
+
{
|
255
|
+
category_type: 'mapping',
|
256
|
+
category_subtype: 'data_compliance',
|
257
|
+
occurrence_count: 8,
|
258
|
+
avg_confidence: 0.78,
|
259
|
+
avg_dev_time_wasted: 2.8,
|
260
|
+
avg_quality_impact: 26.5,
|
261
|
+
},
|
262
|
+
{
|
263
|
+
category_type: 'resource',
|
264
|
+
category_subtype: 'computational_boundary',
|
265
|
+
occurrence_count: 5,
|
266
|
+
avg_confidence: 0.92,
|
267
|
+
avg_dev_time_wasted: 4.2,
|
268
|
+
avg_quality_impact: 38.0,
|
269
|
+
},
|
270
|
+
];
|
271
|
+
}
|
272
|
+
/**
|
273
|
+
* Get recent trends (mock implementation)
|
274
|
+
*/
|
275
|
+
async getRecentTrends(days = 30) {
|
276
|
+
const trends = [];
|
277
|
+
const now = new Date();
|
278
|
+
for (let i = 0; i < Math.min(days, 7); i++) {
|
279
|
+
const date = new Date(now);
|
280
|
+
date.setDate(date.getDate() - i);
|
281
|
+
trends.push({
|
282
|
+
analysis_date: date.toISOString().split('T')[0],
|
283
|
+
total_analyses: Math.floor(Math.random() * 10) + 1,
|
284
|
+
avg_rate: Math.random() * 0.8 + 0.2,
|
285
|
+
critical_issues: Math.floor(Math.random() * 3),
|
286
|
+
critical_analyses: Math.floor(Math.random() * 2),
|
287
|
+
});
|
288
|
+
}
|
289
|
+
return trends.reverse(); // Oldest first
|
290
|
+
}
|
291
|
+
/**
|
292
|
+
* Update historical pattern
|
293
|
+
*/
|
294
|
+
async updateHistoricalPattern(patternId, categories) {
|
295
|
+
const existing = this.historicalPatterns.get(patternId);
|
296
|
+
const now = new Date().toISOString();
|
297
|
+
if (existing) {
|
298
|
+
existing.frequency += 1;
|
299
|
+
existing.last_seen = now;
|
300
|
+
existing.updated_at = now;
|
301
|
+
// Update reliability based on frequency
|
302
|
+
existing.reliability = Math.min(0.95, existing.frequency / 20);
|
303
|
+
}
|
304
|
+
else {
|
305
|
+
const newPattern = {
|
306
|
+
id: this.generateId(),
|
307
|
+
pattern_id: patternId,
|
308
|
+
frequency: 1,
|
309
|
+
categories,
|
310
|
+
success_rate: 0.5, // Initial estimate
|
311
|
+
reliability: 0.1, // Low initial reliability
|
312
|
+
first_seen: now,
|
313
|
+
last_seen: now,
|
314
|
+
updated_at: now,
|
315
|
+
};
|
316
|
+
this.historicalPatterns.set(patternId, newPattern);
|
317
|
+
}
|
318
|
+
}
|
319
|
+
/**
|
320
|
+
* Get historical patterns
|
321
|
+
*/
|
322
|
+
async getHistoricalPatterns(minReliability = 0.5) {
|
323
|
+
return Array.from(this.historicalPatterns.values()).filter(pattern => pattern.reliability >= minReliability);
|
324
|
+
}
|
325
|
+
/**
|
326
|
+
* Helper method to generate unique IDs
|
327
|
+
*/
|
328
|
+
generateId() {
|
329
|
+
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
330
|
+
}
|
331
|
+
}
|
332
|
+
/**
|
333
|
+
* Factory function to create database service
|
334
|
+
* In production, this would create a real Supabase-connected service
|
335
|
+
*/
|
336
|
+
export function createHallucinationDatabaseService() {
|
337
|
+
// For now, return mock service
|
338
|
+
// In production: return new SupabaseHallucinationDatabaseService();
|
339
|
+
return new MockHallucinationDatabaseService();
|
340
|
+
}
|
341
|
+
/**
|
342
|
+
* Utility functions for database operations
|
343
|
+
*/
|
344
|
+
/**
|
345
|
+
* Convert CodeHaluResult to database records
|
346
|
+
*/
|
347
|
+
export function convertCodeHaluResultToDbRecords(result, interactionId) {
|
348
|
+
const analysisId = `analysis-${Date.now()}`;
|
349
|
+
// Helper functions
|
350
|
+
const getMostCommonCategory = (categories) => {
|
351
|
+
if (categories.length === 0)
|
352
|
+
return null;
|
353
|
+
const counts = categories.reduce((acc, cat) => {
|
354
|
+
acc[cat.type] = (acc[cat.type] || 0) + 1;
|
355
|
+
return acc;
|
356
|
+
}, {});
|
357
|
+
return Object.keys(counts).reduce((a, b) => counts[a] > counts[b] ? a : b);
|
358
|
+
};
|
359
|
+
const calculateOverallRisk = (rate) => {
|
360
|
+
if (rate > 0.8)
|
361
|
+
return 'critical';
|
362
|
+
if (rate > 0.6)
|
363
|
+
return 'high';
|
364
|
+
if (rate > 0.3)
|
365
|
+
return 'medium';
|
366
|
+
return 'low';
|
367
|
+
};
|
368
|
+
// Create analysis record
|
369
|
+
const analysis = {
|
370
|
+
interaction_id: interactionId,
|
371
|
+
overall_hallucination_rate: result.overallHallucinationRate,
|
372
|
+
analysis_version: result.analysisMetadata.analysisVersion,
|
373
|
+
detection_time_ms: result.analysisMetadata.detectionTimeMs,
|
374
|
+
code_length: result.analysisMetadata.codeLength,
|
375
|
+
language: result.analysisMetadata.language,
|
376
|
+
execution_verified: result.executionResult ? true : false,
|
377
|
+
has_critical_issues: result.categories.some(c => c.severity === 'critical'),
|
378
|
+
code_quality_impact: result.businessImpact.qualityImpact,
|
379
|
+
total_hallucinations: result.categories.length,
|
380
|
+
critical_count: result.categories.filter(c => c.severity === 'critical').length,
|
381
|
+
high_severity_count: result.categories.filter(c => c.severity === 'high').length,
|
382
|
+
medium_severity_count: result.categories.filter(c => c.severity === 'medium').length,
|
383
|
+
low_severity_count: result.categories.filter(c => c.severity === 'low').length,
|
384
|
+
most_common_category: getMostCommonCategory(result.categories),
|
385
|
+
overall_risk: calculateOverallRisk(result.overallHallucinationRate),
|
386
|
+
};
|
387
|
+
// Create category records
|
388
|
+
const categories = result.categories.map(category => ({
|
389
|
+
analysis_id: analysisId,
|
390
|
+
category_type: category.type,
|
391
|
+
category_subtype: category.subtype,
|
392
|
+
severity: category.severity,
|
393
|
+
confidence: category.confidence,
|
394
|
+
detection_method: 'static',
|
395
|
+
evidence: category.evidence.map(e => e.content),
|
396
|
+
line_numbers: category.lineNumbers,
|
397
|
+
error_message: category.errorMessage,
|
398
|
+
suggested_fix: category.suggestedFix,
|
399
|
+
estimated_dev_time_wasted: category.businessImpact.estimatedDevTimeWasted,
|
400
|
+
cost_multiplier: category.businessImpact.costMultiplier,
|
401
|
+
quality_impact: category.businessImpact.qualityImpact,
|
402
|
+
estimated_cost_usd: category.businessImpact.costOfHallucinations,
|
403
|
+
}));
|
404
|
+
// Create execution result if available
|
405
|
+
let executionResult;
|
406
|
+
if (result.executionResult) {
|
407
|
+
executionResult = {
|
408
|
+
analysis_id: analysisId,
|
409
|
+
success: result.executionResult.success,
|
410
|
+
exit_code: result.executionResult.exitCode,
|
411
|
+
timed_out: result.executionResult.timedOut,
|
412
|
+
output: result.executionResult.output,
|
413
|
+
stderr: result.executionResult.stderr,
|
414
|
+
errors: result.executionResult.errors.map(error => ({
|
415
|
+
type: error.type,
|
416
|
+
message: error.message,
|
417
|
+
line_number: error.lineNumber,
|
418
|
+
column_number: error.columnNumber,
|
419
|
+
stack_trace: error.stackTrace,
|
420
|
+
})),
|
421
|
+
memory_mb: result.executionResult.resourceUsage.memoryMB,
|
422
|
+
execution_time_ms: result.executionResult.resourceUsage.executionTimeMs,
|
423
|
+
cpu_usage: result.executionResult.resourceUsage.cpuUsage,
|
424
|
+
peak_memory_mb: result.executionResult.resourceUsage.peakMemoryMB,
|
425
|
+
system_calls: result.executionResult.resourceUsage.systemCalls,
|
426
|
+
security_flags: result.executionResult.securityFlags,
|
427
|
+
};
|
428
|
+
}
|
429
|
+
// Create recommendation records
|
430
|
+
const recommendations = result.recommendations.map(rec => ({
|
431
|
+
analysis_id: analysisId,
|
432
|
+
category_type: 'mapping',
|
433
|
+
priority: rec.priority,
|
434
|
+
title: rec.title,
|
435
|
+
description: rec.description,
|
436
|
+
action_items: rec.actionItems,
|
437
|
+
expected_impact: rec.expectedImpact,
|
438
|
+
estimated_time_to_fix: rec.estimatedTimeToFix,
|
439
|
+
resources: rec.resources,
|
440
|
+
}));
|
441
|
+
return {
|
442
|
+
analysis,
|
443
|
+
categories,
|
444
|
+
executionResult,
|
445
|
+
recommendations,
|
446
|
+
};
|
447
|
+
}
|