@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,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,5 @@
1
+ /**
2
+ * Database Types for Hallucination Analysis
3
+ * TypeScript interfaces matching the PostgreSQL schema
4
+ */
5
+ export {};
@@ -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
- return new Promise(resolve => {
101
- console.log('Search interface is not implemented in this mock.');
102
- resolve({ query: 'test', fields });
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, _search) => {
128
- return interactions;
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goldensheepai/toknxr-cli",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "CLI-powered AI effectiveness & code quality analysis tool - 100% Local",
5
5
  "license": "MIT",
6
6
  "type": "module",