@goldensheepai/toknxr-cli 0.2.2 → 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,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
+ }