@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,490 @@
|
|
1
|
+
/**
|
2
|
+
* Hallucination Pattern Detection
|
3
|
+
* Static analysis patterns for detecting common code hallucinations
|
4
|
+
*/
|
5
|
+
/**
|
6
|
+
* Hallucination pattern detection engine
|
7
|
+
*/
|
8
|
+
export class HallucinationPatterns {
|
9
|
+
/**
|
10
|
+
* Detect mapping hallucinations (data type and structure issues)
|
11
|
+
*/
|
12
|
+
static detectMappingHallucinations(code) {
|
13
|
+
const results = [];
|
14
|
+
const lines = code.split('\n');
|
15
|
+
// Check TypeError patterns
|
16
|
+
for (const [patternName, config] of Object.entries(this.MAPPING_PATTERNS)) {
|
17
|
+
for (const pattern of config.patterns) {
|
18
|
+
lines.forEach((line, index) => {
|
19
|
+
const match = pattern.exec(line);
|
20
|
+
if (match) {
|
21
|
+
const confidence = this.calculatePatternConfidence(match, line, patternName);
|
22
|
+
const evidence = this.extractEvidence(match, line, index + 1);
|
23
|
+
results.push({
|
24
|
+
pattern: patternName,
|
25
|
+
confidence,
|
26
|
+
evidence,
|
27
|
+
lineNumbers: [index + 1],
|
28
|
+
category: 'mapping',
|
29
|
+
subtype: config.subtype,
|
30
|
+
severity: config.severity,
|
31
|
+
});
|
32
|
+
}
|
33
|
+
});
|
34
|
+
}
|
35
|
+
}
|
36
|
+
return results;
|
37
|
+
}
|
38
|
+
/**
|
39
|
+
* Detect naming hallucinations (identifier and reference issues)
|
40
|
+
*/
|
41
|
+
static detectNamingHallucinations(code) {
|
42
|
+
const results = [];
|
43
|
+
const lines = code.split('\n');
|
44
|
+
for (const [patternName, config] of Object.entries(this.NAMING_PATTERNS)) {
|
45
|
+
for (const pattern of config.patterns) {
|
46
|
+
lines.forEach((line, index) => {
|
47
|
+
const match = pattern.exec(line);
|
48
|
+
if (match) {
|
49
|
+
const confidence = this.calculatePatternConfidence(match, line, patternName);
|
50
|
+
const evidence = this.extractEvidence(match, line, index + 1);
|
51
|
+
results.push({
|
52
|
+
pattern: patternName,
|
53
|
+
confidence,
|
54
|
+
evidence,
|
55
|
+
lineNumbers: [index + 1],
|
56
|
+
category: 'naming',
|
57
|
+
subtype: config.subtype,
|
58
|
+
severity: config.severity,
|
59
|
+
});
|
60
|
+
}
|
61
|
+
});
|
62
|
+
}
|
63
|
+
}
|
64
|
+
return results;
|
65
|
+
}
|
66
|
+
/**
|
67
|
+
* Detect resource hallucinations (memory, file, network issues)
|
68
|
+
*/
|
69
|
+
static detectResourceHallucinations(code) {
|
70
|
+
const results = [];
|
71
|
+
const lines = code.split('\n');
|
72
|
+
for (const [patternName, config] of Object.entries(this.RESOURCE_PATTERNS)) {
|
73
|
+
for (const pattern of config.patterns) {
|
74
|
+
lines.forEach((line, index) => {
|
75
|
+
const match = pattern.exec(line);
|
76
|
+
if (match) {
|
77
|
+
const confidence = this.calculatePatternConfidence(match, line, patternName);
|
78
|
+
const evidence = this.extractEvidence(match, line, index + 1);
|
79
|
+
results.push({
|
80
|
+
pattern: patternName,
|
81
|
+
confidence,
|
82
|
+
evidence,
|
83
|
+
lineNumbers: [index + 1],
|
84
|
+
category: 'resource',
|
85
|
+
subtype: config.subtype,
|
86
|
+
severity: config.severity,
|
87
|
+
});
|
88
|
+
}
|
89
|
+
});
|
90
|
+
}
|
91
|
+
}
|
92
|
+
return results;
|
93
|
+
}
|
94
|
+
/**
|
95
|
+
* Detect logic hallucinations (logical inconsistencies)
|
96
|
+
*/
|
97
|
+
static detectLogicHallucinations(code) {
|
98
|
+
const results = [];
|
99
|
+
const lines = code.split('\n');
|
100
|
+
for (const [patternName, config] of Object.entries(this.LOGIC_PATTERNS)) {
|
101
|
+
for (const pattern of config.patterns) {
|
102
|
+
lines.forEach((line, index) => {
|
103
|
+
const match = pattern.exec(line);
|
104
|
+
if (match) {
|
105
|
+
const confidence = this.calculatePatternConfidence(match, line, patternName);
|
106
|
+
const evidence = this.extractEvidence(match, line, index + 1);
|
107
|
+
results.push({
|
108
|
+
pattern: patternName,
|
109
|
+
confidence,
|
110
|
+
evidence,
|
111
|
+
lineNumbers: [index + 1],
|
112
|
+
category: 'logic',
|
113
|
+
subtype: config.subtype,
|
114
|
+
severity: config.severity,
|
115
|
+
});
|
116
|
+
}
|
117
|
+
});
|
118
|
+
}
|
119
|
+
}
|
120
|
+
return results;
|
121
|
+
}
|
122
|
+
/**
|
123
|
+
* Analyze code structure for complexity and patterns
|
124
|
+
*/
|
125
|
+
static analyzeCodeStructure(code) {
|
126
|
+
const lines = code.split('\n');
|
127
|
+
const analysis = {
|
128
|
+
functions: [],
|
129
|
+
classes: [],
|
130
|
+
imports: [],
|
131
|
+
variables: [],
|
132
|
+
complexity: 0,
|
133
|
+
linesOfCode: lines.filter(line => line.trim() && !line.trim().startsWith('#')).length,
|
134
|
+
hasAsyncCode: false,
|
135
|
+
hasErrorHandling: false,
|
136
|
+
};
|
137
|
+
// Extract functions
|
138
|
+
const functionPattern = /def\s+(\w+)\s*\(/g;
|
139
|
+
let match;
|
140
|
+
while ((match = functionPattern.exec(code)) !== null) {
|
141
|
+
analysis.functions.push(match[1]);
|
142
|
+
}
|
143
|
+
// Extract classes
|
144
|
+
const classPattern = /class\s+(\w+)\s*[:(]/g;
|
145
|
+
while ((match = classPattern.exec(code)) !== null) {
|
146
|
+
analysis.classes.push(match[1]);
|
147
|
+
}
|
148
|
+
// Extract imports
|
149
|
+
const importPattern = /(?:import|from)\s+(\w+)/g;
|
150
|
+
while ((match = importPattern.exec(code)) !== null) {
|
151
|
+
analysis.imports.push(match[1]);
|
152
|
+
}
|
153
|
+
// Extract variables
|
154
|
+
const variablePattern = /(\w+)\s*=/g;
|
155
|
+
while ((match = variablePattern.exec(code)) !== null) {
|
156
|
+
if (!analysis.variables.includes(match[1])) {
|
157
|
+
analysis.variables.push(match[1]);
|
158
|
+
}
|
159
|
+
}
|
160
|
+
// Check for async code
|
161
|
+
analysis.hasAsyncCode = /async\s+def|await\s+/.test(code);
|
162
|
+
// Check for error handling
|
163
|
+
analysis.hasErrorHandling = /try:|except|finally:|raise/.test(code);
|
164
|
+
// Calculate complexity (simplified cyclomatic complexity)
|
165
|
+
const complexityPatterns = [
|
166
|
+
/if\s+/g,
|
167
|
+
/elif\s+/g,
|
168
|
+
/else:/g,
|
169
|
+
/for\s+/g,
|
170
|
+
/while\s+/g,
|
171
|
+
/except/g,
|
172
|
+
/and\s+/g,
|
173
|
+
/or\s+/g,
|
174
|
+
];
|
175
|
+
analysis.complexity = complexityPatterns.reduce((total, pattern) => {
|
176
|
+
const matches = code.match(pattern);
|
177
|
+
return total + (matches ? matches.length : 0);
|
178
|
+
}, 1); // Base complexity of 1
|
179
|
+
return analysis;
|
180
|
+
}
|
181
|
+
/**
|
182
|
+
* Extract evidence from pattern match
|
183
|
+
*/
|
184
|
+
static extractEvidence(match, line, lineNumber) {
|
185
|
+
const evidence = [];
|
186
|
+
// Add the matched line as primary evidence
|
187
|
+
evidence.push({
|
188
|
+
type: 'code_line',
|
189
|
+
content: line.trim(),
|
190
|
+
lineNumber,
|
191
|
+
confidence: 0.9,
|
192
|
+
});
|
193
|
+
// Add specific match groups as evidence
|
194
|
+
if (match.length > 1) {
|
195
|
+
for (let i = 1; i < match.length; i++) {
|
196
|
+
if (match[i]) {
|
197
|
+
evidence.push({
|
198
|
+
type: 'identifier',
|
199
|
+
content: match[i],
|
200
|
+
lineNumber,
|
201
|
+
confidence: 0.8,
|
202
|
+
});
|
203
|
+
}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
// Add context if there's a comment indicating the issue
|
207
|
+
const commentMatch = line.match(/#\s*(.+)$/);
|
208
|
+
if (commentMatch) {
|
209
|
+
evidence.push({
|
210
|
+
type: 'error_message',
|
211
|
+
content: commentMatch[1].trim(),
|
212
|
+
lineNumber,
|
213
|
+
confidence: 0.95,
|
214
|
+
});
|
215
|
+
}
|
216
|
+
return evidence;
|
217
|
+
}
|
218
|
+
/**
|
219
|
+
* Calculate confidence score for a pattern match
|
220
|
+
*/
|
221
|
+
static calculatePatternConfidence(match, line, patternName) {
|
222
|
+
let confidence = 0.7; // Base confidence
|
223
|
+
// Increase confidence if there's an error comment
|
224
|
+
if (line.includes('#') && /error|exception|fail|wrong|issue/i.test(line)) {
|
225
|
+
confidence += 0.2;
|
226
|
+
}
|
227
|
+
// Increase confidence for specific error types in comments
|
228
|
+
const errorKeywords = {
|
229
|
+
typeError: /type.*error|cannot.*add|not.*callable/i,
|
230
|
+
indexError: /index.*out.*of.*range|list.*index/i,
|
231
|
+
keyError: /key.*error|key.*not.*found/i,
|
232
|
+
nameError: /name.*not.*defined|undefined.*variable/i,
|
233
|
+
attributeError: /has.*no.*attribute|attribute.*error/i,
|
234
|
+
importError: /no.*module.*named|import.*error/i,
|
235
|
+
memoryError: /memory.*error|out.*of.*memory/i,
|
236
|
+
recursionError: /recursion.*limit|maximum.*recursion/i,
|
237
|
+
ioError: /file.*not.*found|permission.*denied/i,
|
238
|
+
};
|
239
|
+
if (errorKeywords[patternName]?.test(line)) {
|
240
|
+
confidence += 0.15;
|
241
|
+
}
|
242
|
+
// Decrease confidence for common variable names that might be false positives
|
243
|
+
const commonNames = ['data', 'result', 'value', 'item', 'temp', 'x', 'y', 'i', 'j'];
|
244
|
+
if (match[1] && commonNames.includes(match[1].toLowerCase())) {
|
245
|
+
confidence -= 0.1;
|
246
|
+
}
|
247
|
+
// Ensure confidence is within bounds
|
248
|
+
return Math.max(0.1, Math.min(1.0, confidence));
|
249
|
+
}
|
250
|
+
/**
|
251
|
+
* Convert pattern match results to hallucination categories
|
252
|
+
*/
|
253
|
+
static convertToHallucinationCategories(results) {
|
254
|
+
return results.map(result => ({
|
255
|
+
type: result.category,
|
256
|
+
subtype: result.subtype,
|
257
|
+
severity: result.severity,
|
258
|
+
confidence: result.confidence,
|
259
|
+
description: this.generateDescription(result),
|
260
|
+
evidence: result.evidence,
|
261
|
+
lineNumbers: result.lineNumbers,
|
262
|
+
suggestedFix: this.generateSuggestedFix(result),
|
263
|
+
businessImpact: this.calculateBusinessImpact(result),
|
264
|
+
}));
|
265
|
+
}
|
266
|
+
/**
|
267
|
+
* Generate human-readable description for a pattern match
|
268
|
+
*/
|
269
|
+
static generateDescription(result) {
|
270
|
+
const descriptions = {
|
271
|
+
typeError: 'Potential type mismatch or incorrect type assumption',
|
272
|
+
indexError: 'Array or list index may be out of bounds',
|
273
|
+
keyError: 'Dictionary key may not exist',
|
274
|
+
nameError: 'Variable or function may not be defined',
|
275
|
+
attributeError: 'Object may not have the specified attribute or method',
|
276
|
+
importError: 'Module or package may not be available',
|
277
|
+
memoryError: 'Code may consume excessive memory',
|
278
|
+
recursionError: 'Infinite recursion or stack overflow risk',
|
279
|
+
ioError: 'File or I/O operation may fail',
|
280
|
+
logicDeviation: 'Logical inconsistency or contradiction detected',
|
281
|
+
logicBreakdown: 'Code logic may be fundamentally flawed',
|
282
|
+
};
|
283
|
+
return descriptions[result.pattern] ||
|
284
|
+
`Potential ${result.category} hallucination detected`;
|
285
|
+
}
|
286
|
+
/**
|
287
|
+
* Generate suggested fix for a pattern match
|
288
|
+
*/
|
289
|
+
static generateSuggestedFix(result) {
|
290
|
+
const fixes = {
|
291
|
+
typeError: 'Verify data types and add type checking or conversion',
|
292
|
+
indexError: 'Add bounds checking before accessing array elements',
|
293
|
+
keyError: 'Use .get() method or check if key exists before access',
|
294
|
+
nameError: 'Define the variable or function before using it',
|
295
|
+
attributeError: 'Verify object type and available methods/attributes',
|
296
|
+
importError: 'Install required package or check import statement',
|
297
|
+
memoryError: 'Optimize data structures or add memory limits',
|
298
|
+
recursionError: 'Add base case or use iterative approach',
|
299
|
+
ioError: 'Add file existence check and error handling',
|
300
|
+
logicDeviation: 'Review and fix logical contradictions',
|
301
|
+
logicBreakdown: 'Restructure the logic flow',
|
302
|
+
};
|
303
|
+
return fixes[result.pattern] ||
|
304
|
+
'Review and test the code thoroughly';
|
305
|
+
}
|
306
|
+
/**
|
307
|
+
* Calculate business impact score for a pattern match
|
308
|
+
*/
|
309
|
+
static calculateBusinessImpact(result) {
|
310
|
+
const severityMultipliers = {
|
311
|
+
low: { time: 0.5, cost: 1.1, quality: 5 },
|
312
|
+
medium: { time: 2.0, cost: 1.3, quality: 15 },
|
313
|
+
high: { time: 4.0, cost: 1.6, quality: 30 },
|
314
|
+
critical: { time: 8.0, cost: 2.0, quality: 50 },
|
315
|
+
};
|
316
|
+
const multiplier = severityMultipliers[result.severity];
|
317
|
+
const devTimeWasted = multiplier.time * result.confidence;
|
318
|
+
return {
|
319
|
+
estimatedDevTimeWasted: devTimeWasted,
|
320
|
+
costMultiplier: multiplier.cost,
|
321
|
+
qualityImpact: Math.round(multiplier.quality * result.confidence),
|
322
|
+
costOfHallucinations: devTimeWasted * 100, // $100/hour dev rate
|
323
|
+
};
|
324
|
+
}
|
325
|
+
}
|
326
|
+
HallucinationPatterns.MAPPING_PATTERNS = {
|
327
|
+
// TypeError patterns - incorrect type assumptions
|
328
|
+
typeError: {
|
329
|
+
patterns: [
|
330
|
+
/(\w+)\s*\+\s*(\w+).*#.*(?:string|str).*(?:int|integer|number)/i,
|
331
|
+
/(\w+)\.(\w+)\s*\(.*\).*#.*(?:not callable|has no attribute)/i,
|
332
|
+
/(\w+)\[(\w+)\].*#.*(?:not subscriptable|unhashable)/i,
|
333
|
+
/len\s*\(\s*(\w+)\s*\).*#.*(?:has no len|object of type)/i,
|
334
|
+
/for\s+\w+\s+in\s+(\w+).*#.*(?:not iterable|object is not iterable)/i,
|
335
|
+
],
|
336
|
+
severity: 'high',
|
337
|
+
subtype: 'data_compliance',
|
338
|
+
},
|
339
|
+
// IndexError patterns - incorrect array/list access
|
340
|
+
indexError: {
|
341
|
+
patterns: [
|
342
|
+
/(\w+)\[(\d+)\].*#.*(?:index out of range|list index)/i,
|
343
|
+
/(\w+)\[(\w+)\].*#.*(?:index out of range|string index)/i,
|
344
|
+
/(\w+)\[(-\d+)\].*#.*(?:index out of range)/i,
|
345
|
+
/(\w+)\.pop\s*\(\s*(\d+)\s*\).*#.*(?:index out of range)/i,
|
346
|
+
],
|
347
|
+
severity: 'medium',
|
348
|
+
subtype: 'structure_access',
|
349
|
+
},
|
350
|
+
// KeyError patterns - incorrect dictionary access
|
351
|
+
keyError: {
|
352
|
+
patterns: [
|
353
|
+
/(\w+)\[['"](\w+)['"]\].*#.*(?:key error|keyerror)/i,
|
354
|
+
/(\w+)\.get\s*\(\s*['"](\w+)['"]\s*\).*#.*(?:none|missing)/i,
|
355
|
+
/(\w+)\[(\w+)\].*#.*(?:key error|keyerror)/i,
|
356
|
+
/del\s+(\w+)\[['"](\w+)['"]\].*#.*(?:key error)/i,
|
357
|
+
],
|
358
|
+
severity: 'medium',
|
359
|
+
subtype: 'structure_access',
|
360
|
+
},
|
361
|
+
};
|
362
|
+
HallucinationPatterns.NAMING_PATTERNS = {
|
363
|
+
// NameError patterns - undefined variables/functions
|
364
|
+
nameError: {
|
365
|
+
patterns: [
|
366
|
+
/(\w+)\s*=.*#.*(?:name.*not defined|undefined)/i,
|
367
|
+
/(\w+)\s*\(.*\).*#.*(?:name.*not defined|undefined)/i,
|
368
|
+
/print\s*\(\s*(\w+)\s*\).*#.*(?:name.*not defined)/i,
|
369
|
+
/return\s+(\w+).*#.*(?:name.*not defined)/i,
|
370
|
+
/if\s+(\w+).*#.*(?:name.*not defined)/i,
|
371
|
+
],
|
372
|
+
severity: 'high',
|
373
|
+
subtype: 'identity',
|
374
|
+
},
|
375
|
+
// AttributeError patterns - incorrect method/property access
|
376
|
+
attributeError: {
|
377
|
+
patterns: [
|
378
|
+
/(\w+)\.(\w+).*#.*(?:has no attribute|attribute error)/i,
|
379
|
+
/(\w+)\.(\w+)\s*\(.*\).*#.*(?:has no attribute)/i,
|
380
|
+
/(\w+)\.(\w+)\s*=.*#.*(?:has no attribute)/i,
|
381
|
+
/del\s+(\w+)\.(\w+).*#.*(?:has no attribute)/i,
|
382
|
+
],
|
383
|
+
severity: 'medium',
|
384
|
+
subtype: 'identity',
|
385
|
+
},
|
386
|
+
// ImportError patterns - incorrect module imports
|
387
|
+
importError: {
|
388
|
+
patterns: [
|
389
|
+
/import\s+(\w+).*#.*(?:no module named|import error)/i,
|
390
|
+
/from\s+(\w+)\s+import\s+(\w+).*#.*(?:cannot import|import error)/i,
|
391
|
+
/import\s+(\w+)\.(\w+).*#.*(?:no module named)/i,
|
392
|
+
/__import__\s*\(\s*['"](\w+)['"]\s*\).*#.*(?:no module)/i,
|
393
|
+
],
|
394
|
+
severity: 'critical',
|
395
|
+
subtype: 'external_source',
|
396
|
+
},
|
397
|
+
};
|
398
|
+
HallucinationPatterns.RESOURCE_PATTERNS = {
|
399
|
+
// Memory-related patterns
|
400
|
+
memoryError: {
|
401
|
+
patterns: [
|
402
|
+
/\[\s*\w+\s*for\s+\w+\s+in\s+range\s*\(\s*\d{6,}\s*\)\s*\].*#.*(?:memory|out of memory)/i,
|
403
|
+
/\*\s*\[\s*\d+\s*\]\s*\*\s*\d{4,}.*#.*(?:memory)/i,
|
404
|
+
/(\w+)\s*=\s*\[\s*\]\s*\*\s*\d{6,}.*#.*(?:memory)/i,
|
405
|
+
],
|
406
|
+
severity: 'high',
|
407
|
+
subtype: 'physical_constraint',
|
408
|
+
},
|
409
|
+
// Recursion-related patterns
|
410
|
+
recursionError: {
|
411
|
+
patterns: [
|
412
|
+
/def\s+(\w+)\s*\([^)]*\):\s*[^{]*\1\s*\([^)]*\).*#.*(?:recursion|stack)/i,
|
413
|
+
/(\w+)\s*\([^)]*\).*\1\s*\([^)]*\).*#.*(?:maximum recursion)/i,
|
414
|
+
],
|
415
|
+
severity: 'critical',
|
416
|
+
subtype: 'computational_boundary',
|
417
|
+
},
|
418
|
+
// File/IO patterns
|
419
|
+
ioError: {
|
420
|
+
patterns: [
|
421
|
+
/open\s*\(\s*['"]([^'"]+)['"]\s*\).*#.*(?:no such file|permission denied)/i,
|
422
|
+
/with\s+open\s*\(\s*['"]([^'"]+)['"]\s*\).*#.*(?:file not found)/i,
|
423
|
+
/(\w+)\.read\s*\(\s*\).*#.*(?:closed file|io error)/i,
|
424
|
+
],
|
425
|
+
severity: 'medium',
|
426
|
+
subtype: 'physical_constraint',
|
427
|
+
},
|
428
|
+
};
|
429
|
+
HallucinationPatterns.LOGIC_PATTERNS = {
|
430
|
+
// Logic deviation patterns
|
431
|
+
logicDeviation: {
|
432
|
+
patterns: [
|
433
|
+
/if\s+(\w+)\s*==\s*(\w+)\s*and\s+\1\s*!=\s*\2.*#.*(?:contradiction|impossible)/i,
|
434
|
+
/while\s+True:\s*[^{]*(?!break).*#.*(?:infinite|endless)/i,
|
435
|
+
/(\w+)\s*=\s*(\w+)\s*\/\s*0.*#.*(?:division by zero)/i,
|
436
|
+
/return\s+(\w+)\s*and\s+not\s+\1.*#.*(?:contradiction)/i,
|
437
|
+
],
|
438
|
+
severity: 'high',
|
439
|
+
subtype: 'logic_deviation',
|
440
|
+
},
|
441
|
+
// Logic breakdown patterns
|
442
|
+
logicBreakdown: {
|
443
|
+
patterns: [
|
444
|
+
/if\s+(\w+):\s*[^{]*else:\s*[^{]*\1.*#.*(?:unreachable|dead code)/i,
|
445
|
+
/(\w+)\s*=\s*None\s*[^{]*\1\.(\w+).*#.*(?:none type|attribute)/i,
|
446
|
+
/assert\s+False.*#.*(?:assertion|always fails)/i,
|
447
|
+
],
|
448
|
+
severity: 'critical',
|
449
|
+
subtype: 'logic_breakdown',
|
450
|
+
},
|
451
|
+
};
|
452
|
+
/**
|
453
|
+
* Factory function to create pattern detection results
|
454
|
+
*/
|
455
|
+
export function detectAllPatterns(code) {
|
456
|
+
const results = [];
|
457
|
+
results.push(...HallucinationPatterns.detectMappingHallucinations(code));
|
458
|
+
results.push(...HallucinationPatterns.detectNamingHallucinations(code));
|
459
|
+
results.push(...HallucinationPatterns.detectResourceHallucinations(code));
|
460
|
+
results.push(...HallucinationPatterns.detectLogicHallucinations(code));
|
461
|
+
// Sort by severity and confidence
|
462
|
+
return results.sort((a, b) => {
|
463
|
+
const severityOrder = { critical: 4, high: 3, medium: 2, low: 1 };
|
464
|
+
const severityDiff = severityOrder[b.severity] - severityOrder[a.severity];
|
465
|
+
if (severityDiff !== 0)
|
466
|
+
return severityDiff;
|
467
|
+
return b.confidence - a.confidence;
|
468
|
+
});
|
469
|
+
}
|
470
|
+
/**
|
471
|
+
* Utility function to get pattern statistics
|
472
|
+
*/
|
473
|
+
export function getPatternStatistics(results) {
|
474
|
+
const stats = {
|
475
|
+
totalPatterns: results.length,
|
476
|
+
byCategory: {},
|
477
|
+
bySeverity: {},
|
478
|
+
avgConfidence: 0,
|
479
|
+
};
|
480
|
+
if (results.length === 0)
|
481
|
+
return stats;
|
482
|
+
// Count by category
|
483
|
+
results.forEach(result => {
|
484
|
+
stats.byCategory[result.category] = (stats.byCategory[result.category] || 0) + 1;
|
485
|
+
stats.bySeverity[result.severity] = (stats.bySeverity[result.severity] || 0) + 1;
|
486
|
+
});
|
487
|
+
// Calculate average confidence
|
488
|
+
stats.avgConfidence = results.reduce((sum, result) => sum + result.confidence, 0) / results.length;
|
489
|
+
return stats;
|
490
|
+
}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
/**
|
2
|
+
* Enhanced Hallucination Detection Types
|
3
|
+
* Based on CodeHalu research methodology for systematic code hallucination detection
|
4
|
+
*
|
5
|
+
* @see https://github.com/yuchen814/CodeHalu
|
6
|
+
* @version 1.0.0
|
7
|
+
*/
|
8
|
+
/**
|
9
|
+
* Error mapping for categorizing execution errors
|
10
|
+
*/
|
11
|
+
export const ERROR_CATEGORY_MAP = {
|
12
|
+
// Mapping Hallucinations
|
13
|
+
'TypeError': { type: 'mapping', subtype: 'data_compliance' },
|
14
|
+
'ValueError': { type: 'mapping', subtype: 'data_compliance' },
|
15
|
+
'IndexError': { type: 'mapping', subtype: 'structure_access' },
|
16
|
+
'KeyError': { type: 'mapping', subtype: 'structure_access' },
|
17
|
+
'AttributeError': { type: 'mapping', subtype: 'structure_access' },
|
18
|
+
// Naming Hallucinations
|
19
|
+
'NameError': { type: 'naming', subtype: 'identity' },
|
20
|
+
'UnboundLocalError': { type: 'naming', subtype: 'identity' },
|
21
|
+
'ImportError': { type: 'naming', subtype: 'external_source' },
|
22
|
+
'ModuleNotFoundError': { type: 'naming', subtype: 'external_source' },
|
23
|
+
// Resource Hallucinations
|
24
|
+
'MemoryError': { type: 'resource', subtype: 'physical_constraint' },
|
25
|
+
'RecursionError': { type: 'resource', subtype: 'physical_constraint' },
|
26
|
+
'OverflowError': { type: 'resource', subtype: 'computational_boundary' },
|
27
|
+
'TimeoutError': { type: 'resource', subtype: 'computational_boundary' },
|
28
|
+
// Logic Hallucinations (detected through execution analysis)
|
29
|
+
'AssertionError': { type: 'logic', subtype: 'logic_deviation' },
|
30
|
+
'SyntaxError': { type: 'logic', subtype: 'logic_breakdown' },
|
31
|
+
'IndentationError': { type: 'logic', subtype: 'logic_breakdown' },
|
32
|
+
};
|
33
|
+
/**
|
34
|
+
* Default business impact values by hallucination category
|
35
|
+
*/
|
36
|
+
export const DEFAULT_BUSINESS_IMPACT = {
|
37
|
+
mapping: {
|
38
|
+
estimatedDevTimeWasted: 2.5,
|
39
|
+
costMultiplier: 1.3,
|
40
|
+
qualityImpact: 25,
|
41
|
+
costOfHallucinations: 125.0,
|
42
|
+
},
|
43
|
+
naming: {
|
44
|
+
estimatedDevTimeWasted: 1.8,
|
45
|
+
costMultiplier: 1.2,
|
46
|
+
qualityImpact: 20,
|
47
|
+
costOfHallucinations: 90.0,
|
48
|
+
},
|
49
|
+
resource: {
|
50
|
+
estimatedDevTimeWasted: 4.0,
|
51
|
+
costMultiplier: 1.8,
|
52
|
+
qualityImpact: 40,
|
53
|
+
costOfHallucinations: 200.0,
|
54
|
+
},
|
55
|
+
logic: {
|
56
|
+
estimatedDevTimeWasted: 3.2,
|
57
|
+
costMultiplier: 1.5,
|
58
|
+
qualityImpact: 35,
|
59
|
+
costOfHallucinations: 160.0,
|
60
|
+
},
|
61
|
+
};
|
62
|
+
/**
|
63
|
+
* Default detection options
|
64
|
+
*/
|
65
|
+
export const DEFAULT_DETECTION_OPTIONS = {
|
66
|
+
enableExecution: true,
|
67
|
+
executionTimeoutMs: 5000,
|
68
|
+
memoryLimitMB: 128,
|
69
|
+
confidenceThreshold: 0.7,
|
70
|
+
includeLowSeverity: true,
|
71
|
+
focusCategories: ['mapping', 'naming', 'resource', 'logic'],
|
72
|
+
generateRecommendations: true,
|
73
|
+
codeContext: {},
|
74
|
+
};
|
@@ -0,0 +1,8 @@
|
|
1
|
+
/**
|
2
|
+
* TokNXR Type Definitions
|
3
|
+
* Centralized exports for all TypeScript types and interfaces
|
4
|
+
*/
|
5
|
+
// Enhanced Hallucination Detection Types
|
6
|
+
export * from './hallucination-types.js';
|
7
|
+
// Database Types for Hallucination Analysis
|
8
|
+
export * from './database-types.js';
|
package/lib/ui.js
CHANGED
@@ -96,11 +96,20 @@ export const createFilterInterface = (currentFilters) => {
|
|
96
96
|
resolve(currentFilters);
|
97
97
|
});
|
98
98
|
};
|
99
|
-
export const createSearchInterface = (fields) => {
|
100
|
-
|
101
|
-
|
102
|
-
|
99
|
+
export const createSearchInterface = async (fields) => {
|
100
|
+
const { selectedFields } = await inquirer.prompt({
|
101
|
+
type: 'checkbox',
|
102
|
+
name: 'selectedFields',
|
103
|
+
message: 'Which fields would you like to search in?',
|
104
|
+
choices: fields.map(field => ({ name: field, value: field, checked: true })),
|
105
|
+
validate: (answer) => {
|
106
|
+
if (!answer || answer.length < 1) {
|
107
|
+
return 'You must choose at least one field.';
|
108
|
+
}
|
109
|
+
return true;
|
110
|
+
}
|
103
111
|
});
|
112
|
+
return { query: '', fields: selectedFields };
|
104
113
|
};
|
105
114
|
export class InteractiveDataExplorer {
|
106
115
|
constructor(data) {
|
@@ -124,6 +133,64 @@ export class CliStateManager {
|
|
124
133
|
return { budgets: {} };
|
125
134
|
}
|
126
135
|
}
|
127
|
-
export const filterAndSearchInteractions = (interactions, _filters,
|
128
|
-
|
136
|
+
export const filterAndSearchInteractions = (interactions, _filters, search) => {
|
137
|
+
if (!search.query || search.query.trim().length === 0) {
|
138
|
+
return interactions;
|
139
|
+
}
|
140
|
+
const query = search.query.toLowerCase();
|
141
|
+
return interactions.filter(interaction => {
|
142
|
+
return search.fields.some(field => {
|
143
|
+
const value = interaction[field];
|
144
|
+
if (typeof value === 'string') {
|
145
|
+
return value.toLowerCase().includes(query);
|
146
|
+
}
|
147
|
+
return false;
|
148
|
+
});
|
149
|
+
});
|
150
|
+
};
|
151
|
+
// Helper functions for search results
|
152
|
+
export const calcRelevanceScore = (interaction, query, fields) => {
|
153
|
+
const queryLower = query.toLowerCase();
|
154
|
+
let totalScore = 0;
|
155
|
+
let matchingFields = 0;
|
156
|
+
fields.forEach(field => {
|
157
|
+
const value = interaction[field];
|
158
|
+
if (typeof value === 'string') {
|
159
|
+
const valueLower = value.toLowerCase();
|
160
|
+
if (valueLower.includes(queryLower)) {
|
161
|
+
matchingFields++;
|
162
|
+
// Exact match gets highest score
|
163
|
+
if (valueLower === queryLower) {
|
164
|
+
totalScore += 1.0;
|
165
|
+
}
|
166
|
+
else if (valueLower.startsWith(queryLower)) {
|
167
|
+
totalScore += 0.8;
|
168
|
+
}
|
169
|
+
else if (valueLower.endsWith(queryLower)) {
|
170
|
+
totalScore += 0.7;
|
171
|
+
}
|
172
|
+
else {
|
173
|
+
// Partial match - score based on how much of the string matches
|
174
|
+
const matchRatio = queryLower.length / valueLower.length;
|
175
|
+
totalScore += 0.3 + (matchRatio * 0.3);
|
176
|
+
}
|
177
|
+
}
|
178
|
+
}
|
179
|
+
});
|
180
|
+
// Calculate final score
|
181
|
+
if (matchingFields === 0)
|
182
|
+
return 0;
|
183
|
+
const baseScore = totalScore / matchingFields;
|
184
|
+
const multiFieldBonus = matchingFields > 1 ? 0.2 : 0;
|
185
|
+
// Ensure exact matches get high scores
|
186
|
+
const finalScore = Math.min(1.0, baseScore + multiFieldBonus);
|
187
|
+
// Debug: log the score calculation for troubleshooting
|
188
|
+
// console.log(`Debug: query="${query}", baseScore=${baseScore}, finalScore=${finalScore}`);
|
189
|
+
return finalScore;
|
190
|
+
};
|
191
|
+
export const highlightMatch = (text, query) => {
|
192
|
+
if (!text || !query)
|
193
|
+
return text;
|
194
|
+
const regex = new RegExp(`(${query})`, 'gi');
|
195
|
+
return text.replace(regex, chalk.yellow.bold('$1'));
|
129
196
|
};
|