@goldensheepai/toknxr-cli 0.2.0 → 0.2.2
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/README.md +270 -9
- package/lib/audit-logger.js +500 -0
- package/lib/cli.js +1309 -112
- package/lib/cli.test.js +49 -0
- package/lib/code-analysis.js +349 -4
- package/lib/dashboard.js +4 -17
- package/lib/fixtures/canary-interaction.js +18 -0
- package/lib/plugin-system.js +266 -0
- package/lib/sync.js +27 -5
- package/lib/ui.js +132 -0
- package/package.json +51 -18
- package/.env +0 -21
- package/.env.example +0 -21
- package/interactions.log +0 -8
- package/src/ai-analytics.ts +0 -418
- package/src/auth.ts +0 -80
- package/src/cli.ts +0 -447
- package/src/code-analysis.ts +0 -365
- package/src/config.ts +0 -10
- package/src/dashboard.tsx +0 -391
- package/src/hallucination-detector.ts +0 -368
- package/src/policy.ts +0 -55
- package/src/pricing.ts +0 -21
- package/src/proxy.ts +0 -438
- package/src/sync.ts +0 -129
- package/start.sh +0 -56
- package/test-analysis.mjs +0 -77
- package/test-coding.mjs +0 -27
- package/test-generate-sample-data.js +0 -118
- package/test-proxy.mjs +0 -25
- package/toknxr.config.json +0 -63
- package/toknxr.policy.json +0 -18
- package/tsconfig.json +0 -19
package/lib/cli.test.js
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
2
|
+
import { spawn } from 'node:child_process';
|
3
|
+
import path from 'node:path';
|
4
|
+
const CLI = path.resolve(process.cwd(), 'toknxr-cli', 'lib', 'cli.js');
|
5
|
+
function runCli(args, env = {}, timeoutMs = 8000) {
|
6
|
+
return new Promise(resolve => {
|
7
|
+
const child = spawn('node', [CLI, ...args], {
|
8
|
+
env: {
|
9
|
+
...process.env,
|
10
|
+
SUPABASE_URL: process.env.SUPABASE_URL || 'http://localhost',
|
11
|
+
SUPABASE_KEY: process.env.SUPABASE_KEY || 'dummy',
|
12
|
+
...env,
|
13
|
+
},
|
14
|
+
});
|
15
|
+
let stdout = '';
|
16
|
+
let stderr = '';
|
17
|
+
const timer = setTimeout(() => {
|
18
|
+
child.kill('SIGKILL');
|
19
|
+
}, timeoutMs);
|
20
|
+
child.stdout.on('data', d => (stdout += String(d)));
|
21
|
+
child.stderr.on('data', d => (stderr += String(d)));
|
22
|
+
child.on('close', code => {
|
23
|
+
clearTimeout(timer);
|
24
|
+
resolve({ code, stdout, stderr });
|
25
|
+
});
|
26
|
+
});
|
27
|
+
}
|
28
|
+
describe('TokNXR CLI smoke tests', () => {
|
29
|
+
it('--help renders', async () => {
|
30
|
+
const res = await runCli(['--help']);
|
31
|
+
expect(res.code).toBe(0);
|
32
|
+
expect(res.stdout).toContain('Usage: toknxr');
|
33
|
+
});
|
34
|
+
it('budget --view runs', async () => {
|
35
|
+
const res = await runCli(['budget', '--view']);
|
36
|
+
expect(res.code).toBe(0);
|
37
|
+
expect(res.stdout).toContain('Budget Configuration');
|
38
|
+
});
|
39
|
+
it('audit:view --help renders', async () => {
|
40
|
+
const res = await runCli(['audit:view', '--help']);
|
41
|
+
expect(res.code).toBe(0);
|
42
|
+
expect(res.stdout).toContain('--to <date>');
|
43
|
+
});
|
44
|
+
it('audit:export --help renders', async () => {
|
45
|
+
const res = await runCli(['audit:export', '--help']);
|
46
|
+
expect(res.code).toBe(0);
|
47
|
+
expect(res.stdout).toContain('--to <date>');
|
48
|
+
});
|
49
|
+
});
|
package/lib/code-analysis.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import { pluginManager } from './plugin-system.js';
|
1
2
|
/**
|
2
3
|
* Analyzes code quality and provides metrics
|
3
4
|
*/
|
@@ -41,6 +42,34 @@ export function analyzeCodeQuality(code, language) {
|
|
41
42
|
metrics.syntaxValid = validatePython(code);
|
42
43
|
metrics.estimatedReadability = calculatePythonReadability(code);
|
43
44
|
break;
|
45
|
+
case 'go':
|
46
|
+
metrics.hasFunctions = /func\s+\w+\(/.test(code);
|
47
|
+
metrics.hasClasses = /type\s+\w+\s+struct/.test(code);
|
48
|
+
metrics.hasTests = /func\s+Test\w+/.test(code);
|
49
|
+
metrics.syntaxValid = validateGo(code);
|
50
|
+
metrics.estimatedReadability = calculateGoReadability(code);
|
51
|
+
break;
|
52
|
+
case 'rust':
|
53
|
+
metrics.hasFunctions = /fn\s+\w+\(/.test(code);
|
54
|
+
metrics.hasClasses = /(struct|enum)\s+\w+/.test(code);
|
55
|
+
metrics.hasTests = /#\[test\]/.test(code);
|
56
|
+
metrics.syntaxValid = validateRust(code);
|
57
|
+
metrics.estimatedReadability = calculateRustReadability(code);
|
58
|
+
break;
|
59
|
+
case 'java':
|
60
|
+
metrics.hasFunctions = /public\s+(\w+)\s+\w+\(/.test(code);
|
61
|
+
metrics.hasClasses = /public\s+class\s+\w+/.test(code);
|
62
|
+
metrics.hasTests = /@Test/.test(code);
|
63
|
+
metrics.syntaxValid = validateJava(code);
|
64
|
+
metrics.estimatedReadability = calculateJavaReadability(code);
|
65
|
+
break;
|
66
|
+
case 'cpp':
|
67
|
+
metrics.hasFunctions = /(\w+)\s+\w+\(/.test(code) && !/class\s+/.test(code);
|
68
|
+
metrics.hasClasses = /class\s+\w+/.test(code);
|
69
|
+
metrics.hasTests = /(TEST|TEST_F)/.test(code);
|
70
|
+
metrics.syntaxValid = validateCpp(code);
|
71
|
+
metrics.estimatedReadability = calculateCppReadability(code);
|
72
|
+
break;
|
44
73
|
default:
|
45
74
|
metrics.potentialIssues.push('Language not recognized for detailed analysis');
|
46
75
|
}
|
@@ -51,7 +80,15 @@ export function analyzeCodeQuality(code, language) {
|
|
51
80
|
if (!metrics.syntaxValid) {
|
52
81
|
metrics.potentialIssues.push('Potential syntax errors detected');
|
53
82
|
}
|
54
|
-
|
83
|
+
// Apply plugin enhancements
|
84
|
+
try {
|
85
|
+
const enhancedMetrics = pluginManager.analyzeWithPlugins(code, metrics);
|
86
|
+
return enhancedMetrics;
|
87
|
+
}
|
88
|
+
catch (error) {
|
89
|
+
console.warn('Plugin analysis failed, returning base metrics:', error);
|
90
|
+
return metrics;
|
91
|
+
}
|
55
92
|
}
|
56
93
|
/**
|
57
94
|
* Calculate an effectiveness score comparing prompt to code output
|
@@ -81,7 +118,15 @@ export function scoreEffectiveness(userPrompt, aiResponse, extractedCode) {
|
|
81
118
|
(score.codeCompleteness * 0.25) +
|
82
119
|
(score.codeCorrectness * 0.25) +
|
83
120
|
(score.codeEfficiency * 0.2));
|
84
|
-
|
121
|
+
// Apply plugin enhancements for effectiveness scoring
|
122
|
+
try {
|
123
|
+
const enhancedScore = pluginManager.scoreEffectivenessWithPlugins(userPrompt, aiResponse, score, extractedCode);
|
124
|
+
return enhancedScore;
|
125
|
+
}
|
126
|
+
catch (error) {
|
127
|
+
console.warn('Plugin effectiveness scoring failed, returning base score:', error);
|
128
|
+
return score;
|
129
|
+
}
|
85
130
|
}
|
86
131
|
/**
|
87
132
|
* Extract code blocks from AI responses
|
@@ -113,12 +158,27 @@ export function extractCodeFromResponse(response) {
|
|
113
158
|
*/
|
114
159
|
function detectLanguage(code) {
|
115
160
|
if (/(?:import|export|function|const|let|var)\s+/.test(code)) {
|
116
|
-
return code.includes('interface') || code.includes(': string') ? 'typescript' : 'javascript';
|
161
|
+
return code.includes('interface') || code.includes(': string') || code.includes('<') ? 'typescript' : 'javascript';
|
117
162
|
}
|
118
163
|
if (/def\s+|import\s+|class\s+/.test(code) && /:/.test(code)) {
|
119
164
|
return 'python';
|
120
165
|
}
|
121
|
-
//
|
166
|
+
// Go detection
|
167
|
+
if (/package\s+\w+|import\s+\(|func\s+\w+\(/.test(code) && /\.\w+\(/.test(code)) {
|
168
|
+
return 'go';
|
169
|
+
}
|
170
|
+
// Rust detection
|
171
|
+
if (/fn\s+\w+|let\s+mut|println!|use\s+std::/.test(code) && /::/.test(code)) {
|
172
|
+
return 'rust';
|
173
|
+
}
|
174
|
+
// Java detection
|
175
|
+
if (/public\s+class|import\s+java\.|public\s+static\s+void\s+main/.test(code) && /System\.out\.println/.test(code)) {
|
176
|
+
return 'java';
|
177
|
+
}
|
178
|
+
// C++ detection
|
179
|
+
if (/#include\s+<|std::|cout\s+<<|int\s+main\(/.test(code) && /namespace\s+std/.test(code)) {
|
180
|
+
return 'cpp';
|
181
|
+
}
|
122
182
|
return undefined;
|
123
183
|
}
|
124
184
|
/**
|
@@ -302,3 +362,288 @@ function estimateEfficiencyScore(code, metrics) {
|
|
302
362
|
}
|
303
363
|
return Math.max(0, Math.min(100, score));
|
304
364
|
}
|
365
|
+
/**
|
366
|
+
* Basic Go validation
|
367
|
+
*/
|
368
|
+
function validateGo(code) {
|
369
|
+
try {
|
370
|
+
// Basic bracket matching for Go
|
371
|
+
const brackets = { '(': 0, '{': 0 };
|
372
|
+
let inString = false;
|
373
|
+
let inComment = false;
|
374
|
+
for (let i = 0; i < code.length; i++) {
|
375
|
+
const char = code[i];
|
376
|
+
const nextChar = code[i + 1] || '';
|
377
|
+
// Handle strings
|
378
|
+
if (char === '"' && (i === 0 || code[i - 1] !== '\\')) {
|
379
|
+
inString = !inString;
|
380
|
+
continue;
|
381
|
+
}
|
382
|
+
if (inString)
|
383
|
+
continue;
|
384
|
+
// Handle comments
|
385
|
+
if (char === '/' && nextChar === '/') {
|
386
|
+
inComment = true;
|
387
|
+
continue;
|
388
|
+
}
|
389
|
+
if (char === '\n') {
|
390
|
+
inComment = false;
|
391
|
+
continue;
|
392
|
+
}
|
393
|
+
if (inComment)
|
394
|
+
continue;
|
395
|
+
if (char === '(')
|
396
|
+
brackets['(']++;
|
397
|
+
if (char === ')')
|
398
|
+
brackets['(']--;
|
399
|
+
if (char === '{')
|
400
|
+
brackets['{']++;
|
401
|
+
if (char === '}')
|
402
|
+
brackets['{']--;
|
403
|
+
if (brackets['('] < 0 || brackets['{'] < 0) {
|
404
|
+
return false;
|
405
|
+
}
|
406
|
+
}
|
407
|
+
return brackets['('] === 0 && brackets['{'] === 0;
|
408
|
+
}
|
409
|
+
catch {
|
410
|
+
return false;
|
411
|
+
}
|
412
|
+
}
|
413
|
+
/**
|
414
|
+
* Basic Rust validation
|
415
|
+
*/
|
416
|
+
function validateRust(code) {
|
417
|
+
try {
|
418
|
+
// Basic bracket matching for Rust
|
419
|
+
const brackets = { '(': 0, '[': 0, '{': 0 };
|
420
|
+
let inString = false;
|
421
|
+
let inChar = false;
|
422
|
+
for (let i = 0; i < code.length; i++) {
|
423
|
+
const char = code[i];
|
424
|
+
// Handle strings and characters
|
425
|
+
if (char === '"' && (i === 0 || code[i - 1] !== '\\')) {
|
426
|
+
inString = !inString;
|
427
|
+
continue;
|
428
|
+
}
|
429
|
+
if (char === "'" && code[i + 1] && code[i + 1] !== "\\") {
|
430
|
+
inChar = !inChar;
|
431
|
+
continue;
|
432
|
+
}
|
433
|
+
if (inString || inChar)
|
434
|
+
continue;
|
435
|
+
if (char === '(')
|
436
|
+
brackets['(']++;
|
437
|
+
if (char === ')')
|
438
|
+
brackets['(']--;
|
439
|
+
if (char === '[')
|
440
|
+
brackets['[']++;
|
441
|
+
if (char === ']')
|
442
|
+
brackets['[']--;
|
443
|
+
if (char === '{')
|
444
|
+
brackets['{']++;
|
445
|
+
if (char === '}')
|
446
|
+
brackets['{']--;
|
447
|
+
if (brackets['('] < 0 || brackets['['] < 0 || brackets['{'] < 0) {
|
448
|
+
return false;
|
449
|
+
}
|
450
|
+
}
|
451
|
+
return brackets['('] === 0 && brackets['['] === 0 && brackets['{'] === 0;
|
452
|
+
}
|
453
|
+
catch {
|
454
|
+
return false;
|
455
|
+
}
|
456
|
+
}
|
457
|
+
/**
|
458
|
+
* Basic Java validation
|
459
|
+
*/
|
460
|
+
function validateJava(code) {
|
461
|
+
try {
|
462
|
+
// Basic bracket matching for Java
|
463
|
+
const brackets = { '(': 0, '[': 0, '{': 0 };
|
464
|
+
let inString = false;
|
465
|
+
for (let i = 0; i < code.length; i++) {
|
466
|
+
const char = code[i];
|
467
|
+
// Handle strings
|
468
|
+
if (char === '"' && (i === 0 || code[i - 1] !== '\\')) {
|
469
|
+
inString = !inString;
|
470
|
+
continue;
|
471
|
+
}
|
472
|
+
if (inString)
|
473
|
+
continue;
|
474
|
+
if (char === '(')
|
475
|
+
brackets['(']++;
|
476
|
+
if (char === ')')
|
477
|
+
brackets['(']--;
|
478
|
+
if (char === '[')
|
479
|
+
brackets['[']++;
|
480
|
+
if (char === ']')
|
481
|
+
brackets['[']--;
|
482
|
+
if (char === '{')
|
483
|
+
brackets['{']++;
|
484
|
+
if (char === '}')
|
485
|
+
brackets['{']--;
|
486
|
+
if (brackets['('] < 0 || brackets['['] < 0 || brackets['{'] < 0) {
|
487
|
+
return false;
|
488
|
+
}
|
489
|
+
}
|
490
|
+
return brackets['('] === 0 && brackets['['] === 0 && brackets['{'] === 0;
|
491
|
+
}
|
492
|
+
catch {
|
493
|
+
return false;
|
494
|
+
}
|
495
|
+
}
|
496
|
+
/**
|
497
|
+
* Basic C++ validation
|
498
|
+
*/
|
499
|
+
function validateCpp(code) {
|
500
|
+
try {
|
501
|
+
// Basic bracket matching for C++
|
502
|
+
const brackets = { '(': 0, '[': 0, '{': 0 };
|
503
|
+
let inString = false;
|
504
|
+
let inComment = false;
|
505
|
+
for (let i = 0; i < code.length; i++) {
|
506
|
+
const char = code[i];
|
507
|
+
const nextChar = code[i + 1] || '';
|
508
|
+
// Handle strings
|
509
|
+
if (char === '"' && (i === 0 || code[i - 1] !== '\\')) {
|
510
|
+
inString = !inString;
|
511
|
+
continue;
|
512
|
+
}
|
513
|
+
if (inString)
|
514
|
+
continue;
|
515
|
+
// Handle comments
|
516
|
+
if (char === '/' && (nextChar === '/' || nextChar === '*')) {
|
517
|
+
inComment = true;
|
518
|
+
if (nextChar === '*') {
|
519
|
+
// Multi-line comment
|
520
|
+
const endComment = code.indexOf('*/', i + 2);
|
521
|
+
if (endComment !== -1) {
|
522
|
+
i = endComment + 1;
|
523
|
+
}
|
524
|
+
continue;
|
525
|
+
}
|
526
|
+
}
|
527
|
+
if (inComment && char === '\n') {
|
528
|
+
inComment = false;
|
529
|
+
}
|
530
|
+
if (inComment)
|
531
|
+
continue;
|
532
|
+
if (char === '(')
|
533
|
+
brackets['(']++;
|
534
|
+
if (char === ')')
|
535
|
+
brackets['(']--;
|
536
|
+
if (char === '[')
|
537
|
+
brackets['[']++;
|
538
|
+
if (char === ']')
|
539
|
+
brackets['[']--;
|
540
|
+
if (char === '{')
|
541
|
+
brackets['{']++;
|
542
|
+
if (char === '}')
|
543
|
+
brackets['{']--;
|
544
|
+
if (brackets['('] < 0 || brackets['['] < 0 || brackets['{'] < 0) {
|
545
|
+
return false;
|
546
|
+
}
|
547
|
+
}
|
548
|
+
return brackets['('] === 0 && brackets['['] === 0 && brackets['{'] === 0;
|
549
|
+
}
|
550
|
+
catch {
|
551
|
+
return false;
|
552
|
+
}
|
553
|
+
}
|
554
|
+
/**
|
555
|
+
* Calculate readability for Go
|
556
|
+
*/
|
557
|
+
function calculateGoReadability(code) {
|
558
|
+
let score = 6; // Go is generally readable
|
559
|
+
// Length factors
|
560
|
+
if (code.length > 2000)
|
561
|
+
score -= 2;
|
562
|
+
if (code.split('\n').length > 50)
|
563
|
+
score -= 1;
|
564
|
+
// Good practices
|
565
|
+
if (code.includes('//'))
|
566
|
+
score += 1; // Has comments
|
567
|
+
if (/^\s*\w+\./.test(code))
|
568
|
+
score += 0.5; // Uses qualified names
|
569
|
+
if (/err\s*!=\s*nil/.test(code))
|
570
|
+
score += 0.5; // Error handling
|
571
|
+
// Poor practices
|
572
|
+
if (/\w+\s*:=\s*[^;]*;/.test(code))
|
573
|
+
score -= 1; // Short variable declarations with semicolon
|
574
|
+
return Math.max(1, Math.min(10, score));
|
575
|
+
}
|
576
|
+
/**
|
577
|
+
* Calculate readability for Rust
|
578
|
+
*/
|
579
|
+
function calculateRustReadability(code) {
|
580
|
+
let score = 5; // Rust can be complex but expressive
|
581
|
+
// Length factors
|
582
|
+
if (code.length > 2500)
|
583
|
+
score -= 2;
|
584
|
+
if (code.split('\n').length > 60)
|
585
|
+
score -= 1;
|
586
|
+
// Good practices
|
587
|
+
if (code.includes('//'))
|
588
|
+
score += 1; // Has comments
|
589
|
+
if (/let\s+/.test(code))
|
590
|
+
score += 0.5; // Explicit variable declarations
|
591
|
+
if (/->/.test(code))
|
592
|
+
score += 0.5; // Return type annotations
|
593
|
+
if (/\?/m.test(code))
|
594
|
+
score += 0.5; // Error propagation
|
595
|
+
// Code organization
|
596
|
+
if (/impl\s+\w+/.test(code))
|
597
|
+
score += 0.5; // Has implementations
|
598
|
+
if (/trait\s+\w+/.test(code))
|
599
|
+
score += 0.5; // Has traits
|
600
|
+
return Math.max(1, Math.min(10, score));
|
601
|
+
}
|
602
|
+
/**
|
603
|
+
* Calculate readability for Java
|
604
|
+
*/
|
605
|
+
function calculateJavaReadability(code) {
|
606
|
+
let score = 4; // Java can be verbose
|
607
|
+
// Length factors
|
608
|
+
if (code.length > 3000)
|
609
|
+
score -= 2;
|
610
|
+
if (code.split('\n').length > 70)
|
611
|
+
score -= 1;
|
612
|
+
// Good practices
|
613
|
+
if (code.includes('//') || code.includes('/*'))
|
614
|
+
score += 1; // Has comments
|
615
|
+
if (/public\s+class\s+\w+/.test(code))
|
616
|
+
score += 0.5; // Proper class declaration
|
617
|
+
if (/throws\s+\w+/.test(code))
|
618
|
+
score += 0.5; // Exception declarations
|
619
|
+
// Code organization
|
620
|
+
if (/@Override/.test(code))
|
621
|
+
score += 0.5; // Uses annotations properly
|
622
|
+
if (/import\s+java\./.test(code))
|
623
|
+
score += 0.5; // Proper imports
|
624
|
+
return Math.max(1, Math.min(10, score));
|
625
|
+
}
|
626
|
+
/**
|
627
|
+
* Calculate readability for C++
|
628
|
+
*/
|
629
|
+
function calculateCppReadability(code) {
|
630
|
+
let score = 3; // C++ can be complex
|
631
|
+
// Length factors
|
632
|
+
if (code.length > 2500)
|
633
|
+
score -= 2;
|
634
|
+
if (code.split('\n').length > 80)
|
635
|
+
score -= 1;
|
636
|
+
// Good practices
|
637
|
+
if (code.includes('//'))
|
638
|
+
score += 1; // Has comments
|
639
|
+
if (/std::/.test(code))
|
640
|
+
score += 0.5; // Uses standard library
|
641
|
+
if (/const\s+/.test(code))
|
642
|
+
score += 0.5; // Uses const
|
643
|
+
// Code organization
|
644
|
+
if (/namespace\s+\w+/.test(code))
|
645
|
+
score += 0.5; // Uses namespaces
|
646
|
+
if (/#include\s+<[\w\/]+>/.test(code))
|
647
|
+
score += 0.5; // Proper includes
|
648
|
+
return Math.max(1, Math.min(10, score));
|
649
|
+
}
|
package/lib/dashboard.js
CHANGED
@@ -13,22 +13,7 @@ function createDashboard() {
|
|
13
13
|
text: '#F8FAFC',
|
14
14
|
textMuted: '#94A3B8'
|
15
15
|
};
|
16
|
-
let stats = null;
|
17
16
|
let lastUpdated = new Date();
|
18
|
-
// Create stat card HTML
|
19
|
-
function createStatCard(title, value, icon, color = COLORS.primary) {
|
20
|
-
return `
|
21
|
-
<div style="background: ${COLORS.surface}; border-radius: 12px; padding: 24px; border: 1px solid ${color}20; box-shadow: 0 4px 6px -1px ${color}10;">
|
22
|
-
<div style="display: flex; align-items: center; justify-content: space-between;">
|
23
|
-
<div>
|
24
|
-
<p style="color: ${COLORS.textMuted}; font-size: 14px; margin: 0 0 8px 0;">${title}</p>
|
25
|
-
<p style="font-size: 32px; font-weight: bold; margin: 0; color: ${COLORS.text};">${value}</p>
|
26
|
-
</div>
|
27
|
-
<div style="font-size: 24px; color: ${color}; opacity: 0.8;">${icon}</div>
|
28
|
-
</div>
|
29
|
-
</div>
|
30
|
-
`;
|
31
|
-
}
|
32
17
|
// Create provider card HTML
|
33
18
|
function createProviderChart(name, data) {
|
34
19
|
return `
|
@@ -132,8 +117,8 @@ function createDashboard() {
|
|
132
117
|
const providerHTML = Object.entries(data.totals.byProvider).map(([name, providerData]) => createProviderChart(name, {
|
133
118
|
cost: providerData.costUSD || 0,
|
134
119
|
interactions: providerData.requestCount || 0,
|
135
|
-
avgQuality: providerData.
|
136
|
-
avgEffectiveness: providerData.
|
120
|
+
avgQuality: providerData.avgQuality,
|
121
|
+
avgEffectiveness: providerData.avgEffectiveness
|
137
122
|
})).join('');
|
138
123
|
providerContainer.innerHTML = providerHTML;
|
139
124
|
}
|
@@ -265,6 +250,7 @@ function createDashboard() {
|
|
265
250
|
}
|
266
251
|
}
|
267
252
|
// Modal for showing prompt details
|
253
|
+
// @ts-ignore
|
268
254
|
function showPromptDetails(provider, model, userPrompt, aiResponse, qualityScore, effectivenessScore, taskType, cost) {
|
269
255
|
const modal = document.createElement('div');
|
270
256
|
modal.id = 'prompt-modal';
|
@@ -341,6 +327,7 @@ function closePromptModal() {
|
|
341
327
|
}
|
342
328
|
}
|
343
329
|
// Filter prompts based on search and provider filter
|
330
|
+
// @ts-ignore
|
344
331
|
function filterPrompts() {
|
345
332
|
const searchTermValue = document.getElementById('prompt-search')?.value.toLowerCase() || '';
|
346
333
|
const providerFilterValue = document.getElementById('provider-filter')?.value || '';
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import fs from 'node:fs';
|
2
|
+
import path from 'node:path';
|
3
|
+
export function appendFixtureInteraction() {
|
4
|
+
const logPath = path.resolve(process.cwd(), 'interactions.log');
|
5
|
+
const entry = {
|
6
|
+
timestamp: new Date().toISOString(),
|
7
|
+
provider: 'fixture',
|
8
|
+
model: 'fixture-model',
|
9
|
+
promptTokens: 5,
|
10
|
+
completionTokens: 10,
|
11
|
+
totalTokens: 15,
|
12
|
+
costUSD: 0,
|
13
|
+
taskType: 'chat',
|
14
|
+
userPrompt: 'Fixture entry used to validate tooling path',
|
15
|
+
aiResponse: 'This is a fixture interaction entry.',
|
16
|
+
};
|
17
|
+
fs.appendFileSync(logPath, JSON.stringify(entry) + '\n');
|
18
|
+
}
|