@goldensheepai/toknxr-cli 0.2.0 → 0.3.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/README.md +270 -9
- package/lib/audit-logger.js +500 -0
- package/lib/cli.js +1850 -129
- 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 +129 -0
- package/lib/utils.js +117 -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/src/code-analysis.ts
DELETED
@@ -1,365 +0,0 @@
|
|
1
|
-
export interface CodeQualityMetrics {
|
2
|
-
syntaxValid: boolean;
|
3
|
-
linesOfCode: number;
|
4
|
-
complexity: number;
|
5
|
-
hasFunctions: boolean;
|
6
|
-
hasClasses: boolean;
|
7
|
-
hasTests: boolean;
|
8
|
-
estimatedReadability: number; // 1-10 scale
|
9
|
-
potentialIssues: string[];
|
10
|
-
language?: string;
|
11
|
-
framework?: string;
|
12
|
-
}
|
13
|
-
|
14
|
-
export interface EffectivenessScore {
|
15
|
-
promptClarityMatch: number; // How well AI understood the request
|
16
|
-
codeCompleteness: number; // How complete the solution is
|
17
|
-
codeCorrectness: number; // Basic syntax and structure correctness
|
18
|
-
codeEfficiency: number; // Potential performance indicators
|
19
|
-
overallEffectiveness: number; // Combined score 0-100
|
20
|
-
}
|
21
|
-
|
22
|
-
/**
|
23
|
-
* Analyzes code quality and provides metrics
|
24
|
-
*/
|
25
|
-
export function analyzeCodeQuality(code: string, language?: string): CodeQualityMetrics {
|
26
|
-
const metrics: CodeQualityMetrics = {
|
27
|
-
syntaxValid: true,
|
28
|
-
linesOfCode: 0,
|
29
|
-
complexity: 0,
|
30
|
-
hasFunctions: false,
|
31
|
-
hasClasses: false,
|
32
|
-
hasTests: false,
|
33
|
-
estimatedReadability: 5,
|
34
|
-
potentialIssues: [],
|
35
|
-
language: detectLanguage(code) || language
|
36
|
-
};
|
37
|
-
|
38
|
-
if (!code || code.trim().length === 0) {
|
39
|
-
return metrics;
|
40
|
-
}
|
41
|
-
|
42
|
-
const lines = code.split('\n').filter(l => l.trim());
|
43
|
-
metrics.linesOfCode = lines.length;
|
44
|
-
|
45
|
-
// Detect language if not provided
|
46
|
-
const detectedLang = metrics.language || 'unknown';
|
47
|
-
|
48
|
-
// Basic complexity analysis
|
49
|
-
metrics.complexity = calculateComplexity(lines, detectedLang);
|
50
|
-
|
51
|
-
// Check for structural elements based on language
|
52
|
-
switch (detectedLang) {
|
53
|
-
case 'javascript':
|
54
|
-
case 'typescript':
|
55
|
-
metrics.hasFunctions = /function\s+\w+|const\s+\w+\s*=.*=>|class\s+\w+/.test(code);
|
56
|
-
metrics.hasClasses = /class\s+\w+/.test(code);
|
57
|
-
metrics.hasTests = /describe|test|it\(/.test(code);
|
58
|
-
|
59
|
-
// Syntax validation (basic)
|
60
|
-
metrics.syntaxValid = validateJSTypescript(code, detectedLang);
|
61
|
-
|
62
|
-
// Readability scoring
|
63
|
-
metrics.estimatedReadability = calculateJSReadability(code);
|
64
|
-
break;
|
65
|
-
|
66
|
-
case 'python':
|
67
|
-
metrics.hasFunctions = /def\s+\w+/.test(code);
|
68
|
-
metrics.hasClasses = /class\s+\w+/.test(code);
|
69
|
-
metrics.hasTests = /def test_|unittest|pytest/.test(code);
|
70
|
-
|
71
|
-
metrics.syntaxValid = validatePython(code);
|
72
|
-
|
73
|
-
metrics.estimatedReadability = calculatePythonReadability(code);
|
74
|
-
break;
|
75
|
-
|
76
|
-
default:
|
77
|
-
metrics.potentialIssues.push('Language not recognized for detailed analysis');
|
78
|
-
}
|
79
|
-
|
80
|
-
// Common issues
|
81
|
-
if (lines.length > 100) {
|
82
|
-
metrics.potentialIssues.push('Very long file - consider splitting');
|
83
|
-
}
|
84
|
-
|
85
|
-
if (!metrics.syntaxValid) {
|
86
|
-
metrics.potentialIssues.push('Potential syntax errors detected');
|
87
|
-
}
|
88
|
-
|
89
|
-
return metrics;
|
90
|
-
}
|
91
|
-
|
92
|
-
/**
|
93
|
-
* Calculate an effectiveness score comparing prompt to code output
|
94
|
-
*/
|
95
|
-
export function scoreEffectiveness(userPrompt: string, aiResponse: string, extractedCode?: string): EffectivenessScore {
|
96
|
-
const code = extractedCode || aiResponse;
|
97
|
-
|
98
|
-
const score: EffectivenessScore = {
|
99
|
-
promptClarityMatch: 0,
|
100
|
-
codeCompleteness: 0,
|
101
|
-
codeCorrectness: 0,
|
102
|
-
codeEfficiency: 0,
|
103
|
-
overallEffectiveness: 0
|
104
|
-
};
|
105
|
-
|
106
|
-
if (!userPrompt || !code) return score;
|
107
|
-
|
108
|
-
const prompt = userPrompt.toLowerCase();
|
109
|
-
const response = aiResponse.toLowerCase();
|
110
|
-
|
111
|
-
// Analyze how well the AI understood the request
|
112
|
-
score.promptClarityMatch = analyzePromptMatch(prompt, response, code);
|
113
|
-
|
114
|
-
// Analyze code quality and completeness
|
115
|
-
const metrics = analyzeCodeQuality(code);
|
116
|
-
score.codeCorrectness = calculateCorrectnessScore(metrics);
|
117
|
-
score.codeCompleteness = analyzeCompleteness(prompt, code);
|
118
|
-
score.codeEfficiency = estimateEfficiencyScore(code, metrics);
|
119
|
-
|
120
|
-
// Calculate overall effectiveness (weighted average)
|
121
|
-
score.overallEffectiveness = Math.round(
|
122
|
-
(score.promptClarityMatch * 0.3) +
|
123
|
-
(score.codeCompleteness * 0.25) +
|
124
|
-
(score.codeCorrectness * 0.25) +
|
125
|
-
(score.codeEfficiency * 0.2)
|
126
|
-
);
|
127
|
-
|
128
|
-
return score;
|
129
|
-
}
|
130
|
-
|
131
|
-
/**
|
132
|
-
* Extract code blocks from AI responses
|
133
|
-
*/
|
134
|
-
export function extractCodeFromResponse(response: string): { code: string; language?: string } | null {
|
135
|
-
// Common code block patterns
|
136
|
-
const codeBlockRegex = /```(\w+)?\n?([\s\S]*?)```/g;
|
137
|
-
const match = codeBlockRegex.exec(response);
|
138
|
-
|
139
|
-
if (match) {
|
140
|
-
return {
|
141
|
-
code: match[2].trim(),
|
142
|
-
language: match[1]?.toLowerCase()
|
143
|
-
};
|
144
|
-
}
|
145
|
-
|
146
|
-
// Look for inline code that might be a complete solution
|
147
|
-
const inlineCodeRegex = /`([^`\n]+)`/g;
|
148
|
-
const inlineMatches = Array.from(response.matchAll(inlineCodeRegex));
|
149
|
-
|
150
|
-
if (inlineMatches.length > 0) {
|
151
|
-
// If multiple inline codes, combine them
|
152
|
-
const combined = inlineMatches.map(m => m[1]).join('\n\n');
|
153
|
-
if (combined.length > 50) { // Arbitrary threshold for "substantial" code
|
154
|
-
return { code: combined };
|
155
|
-
}
|
156
|
-
}
|
157
|
-
|
158
|
-
return null;
|
159
|
-
}
|
160
|
-
|
161
|
-
/**
|
162
|
-
* Detect programming language from code content
|
163
|
-
*/
|
164
|
-
function detectLanguage(code: string): string | undefined {
|
165
|
-
if (/(?:import|export|function|const|let|var)\s+/.test(code)) {
|
166
|
-
return code.includes('interface') || code.includes(': string') ? 'typescript' : 'javascript';
|
167
|
-
}
|
168
|
-
|
169
|
-
if (/def\s+|import\s+|class\s+/.test(code) && /:/.test(code)) {
|
170
|
-
return 'python';
|
171
|
-
}
|
172
|
-
|
173
|
-
// Add more language detection as needed...
|
174
|
-
|
175
|
-
return undefined;
|
176
|
-
}
|
177
|
-
|
178
|
-
/**
|
179
|
-
* Calculate code complexity score
|
180
|
-
*/
|
181
|
-
function calculateComplexity(lines: string[], language: string): number {
|
182
|
-
let complexity = 1; // Base complexity
|
183
|
-
|
184
|
-
for (const line of lines) {
|
185
|
-
// Control flow increases complexity
|
186
|
-
if (/(if|for|while|switch|try|catch)/.test(line)) {
|
187
|
-
complexity += 0.5;
|
188
|
-
}
|
189
|
-
|
190
|
-
// Nested blocks
|
191
|
-
const indentLevel = line.length - line.trimStart().length;
|
192
|
-
complexity += indentLevel * 0.1;
|
193
|
-
|
194
|
-
// Function/class definitions
|
195
|
-
if (/(function|def|class)/.test(line)) {
|
196
|
-
complexity += 1;
|
197
|
-
}
|
198
|
-
}
|
199
|
-
|
200
|
-
return Math.min(complexity, 10); // Cap at 10
|
201
|
-
}
|
202
|
-
|
203
|
-
/**
|
204
|
-
* Basic JavaScript/TypeScript validation
|
205
|
-
*/
|
206
|
-
function validateJSTypescript(code: string, lang: string): boolean {
|
207
|
-
try {
|
208
|
-
// Basic bracket matching
|
209
|
-
const brackets = { '(': 0, '[': 0, '{': 0 };
|
210
|
-
for (const char of code) {
|
211
|
-
if (char === '(') brackets['(']++;
|
212
|
-
if (char === ')') brackets['(']--;
|
213
|
-
if (char === '[') brackets['[']++;
|
214
|
-
if (char === ']') brackets['[']--;
|
215
|
-
if (char === '{') brackets['{']++;
|
216
|
-
if (char === '}') brackets['{']--;
|
217
|
-
|
218
|
-
if (brackets['('] < 0 || brackets['['] < 0 || brackets['{'] < 0) {
|
219
|
-
return false;
|
220
|
-
}
|
221
|
-
}
|
222
|
-
return brackets['('] === 0 && brackets['['] === 0 && brackets['{'] === 0;
|
223
|
-
} catch {
|
224
|
-
return false;
|
225
|
-
}
|
226
|
-
}
|
227
|
-
|
228
|
-
/**
|
229
|
-
* Basic Python validation
|
230
|
-
*/
|
231
|
-
function validatePython(code: string): boolean {
|
232
|
-
// Basic indentation check
|
233
|
-
const lines = code.split('\n');
|
234
|
-
let indentLevel = 0;
|
235
|
-
for (const line of lines) {
|
236
|
-
const trimmed = line.trim();
|
237
|
-
if (!trimmed || trimmed.startsWith('#')) continue;
|
238
|
-
|
239
|
-
const currentIndent = line.length - line.trimStart().length;
|
240
|
-
if (currentIndent > indentLevel + 4) return false; // Too much indentation
|
241
|
-
indentLevel = currentIndent;
|
242
|
-
}
|
243
|
-
return true;
|
244
|
-
}
|
245
|
-
|
246
|
-
/**
|
247
|
-
* Calculate readability for JS/TS
|
248
|
-
*/
|
249
|
-
function calculateJSReadability(code: string): number {
|
250
|
-
let score = 5; // Base score
|
251
|
-
|
252
|
-
// Length factors
|
253
|
-
if (code.length > 2000) score -= 2;
|
254
|
-
if (code.split('\n').length > 50) score -= 1;
|
255
|
-
|
256
|
-
// Good practices
|
257
|
-
if (code.includes('//') || code.includes('/*')) score += 1; // Has comments
|
258
|
-
if (/\w+_\w+/.test(code)) score -= 1; // Poor naming (underscores in JS)
|
259
|
-
if (/[a-z][A-Z]/.test(code.replace(/const|let|var/g, ''))) score += 1; // camelCase
|
260
|
-
|
261
|
-
return Math.max(1, Math.min(10, score));
|
262
|
-
}
|
263
|
-
|
264
|
-
/**
|
265
|
-
* Calculate readability for Python
|
266
|
-
*/
|
267
|
-
function calculatePythonReadability(code: string): number {
|
268
|
-
let score = 7; // Python typically more readable
|
269
|
-
|
270
|
-
// Length factors
|
271
|
-
if (code.length > 1500) score -= 1.5;
|
272
|
-
if (code.split('\n').length > 40) score -= 1;
|
273
|
-
|
274
|
-
// Good practices
|
275
|
-
if (code.includes('#')) score += 0.5; // Has comments
|
276
|
-
if (/"""[\s\S]*?"""/.test(code)) score += 1; // Has docstrings
|
277
|
-
if (/_/.test(code.replace(/__\w+__/g, ''))) score -= 0.5; // Uses underscores (good)
|
278
|
-
|
279
|
-
return Math.max(1, Math.min(10, score));
|
280
|
-
}
|
281
|
-
|
282
|
-
/**
|
283
|
-
* Analyze how well AI response matches the user's prompt
|
284
|
-
*/
|
285
|
-
function analyzePromptMatch(prompt: string, response: string, code: string): number {
|
286
|
-
let match = 0;
|
287
|
-
|
288
|
-
// Keywords from prompt appearing in code
|
289
|
-
const promptWords = prompt.split(/\s+/).filter(w => w.length > 3);
|
290
|
-
const codeContent = code.toLowerCase();
|
291
|
-
const matchingWords = promptWords.filter(word =>
|
292
|
-
codeContent.includes(word.toLowerCase())
|
293
|
-
);
|
294
|
-
match += (matchingWords.length / Math.max(promptWords.length, 1)) * 40;
|
295
|
-
|
296
|
-
// Check if response acknowledges the request
|
297
|
-
if (response.includes('here') || response.includes('below') || response.includes('code')) {
|
298
|
-
match += 20;
|
299
|
-
}
|
300
|
-
|
301
|
-
// Has explanation or context
|
302
|
-
if (response.length > code.length * 2) {
|
303
|
-
match += 15;
|
304
|
-
}
|
305
|
-
|
306
|
-
return Math.min(100, match);
|
307
|
-
}
|
308
|
-
|
309
|
-
/**
|
310
|
-
* Calculate correctness score from metrics
|
311
|
-
*/
|
312
|
-
function calculateCorrectnessScore(metrics: CodeQualityMetrics): number {
|
313
|
-
let score = 50; // Base score
|
314
|
-
|
315
|
-
if (metrics.syntaxValid) score += 25;
|
316
|
-
else score -= 20;
|
317
|
-
|
318
|
-
if (metrics.estimatedReadability > 6) score += 15;
|
319
|
-
else if (metrics.estimatedReadability < 4) score -= 10;
|
320
|
-
|
321
|
-
if (metrics.potentialIssues.length === 0) score += 10;
|
322
|
-
|
323
|
-
return Math.max(0, Math.min(100, score));
|
324
|
-
}
|
325
|
-
|
326
|
-
/**
|
327
|
-
* Analyze code completeness
|
328
|
-
*/
|
329
|
-
function analyzeCompleteness(prompt: string, code: string): number {
|
330
|
-
let completeness = 50; // Base
|
331
|
-
|
332
|
-
// Look for completion indicators
|
333
|
-
if (/(function|def|class)\s+\w+/.test(code)) completeness += 20;
|
334
|
-
|
335
|
-
if (/(return|yield|export)/.test(code)) completeness += 15;
|
336
|
-
|
337
|
-
// Check if code has implementation (not just skeleton)
|
338
|
-
const lines = code.split('\n').length;
|
339
|
-
if (lines > 10) completeness += 10;
|
340
|
-
|
341
|
-
if (/(todo|fixme|implement)/i.test(code)) completeness -= 15;
|
342
|
-
|
343
|
-
return Math.max(0, Math.min(100, completeness));
|
344
|
-
}
|
345
|
-
|
346
|
-
/**
|
347
|
-
* Estimate efficiency score
|
348
|
-
*/
|
349
|
-
function estimateEfficiencyScore(code: string, metrics: CodeQualityMetrics): number {
|
350
|
-
let score = 60; // Base
|
351
|
-
|
352
|
-
// Complexity affects efficiency
|
353
|
-
if (metrics.complexity < 3) score += 20;
|
354
|
-
else if (metrics.complexity > 7) score -= 20;
|
355
|
-
|
356
|
-
// Length considerations
|
357
|
-
if (metrics.linesOfCode > 100) score -= 10;
|
358
|
-
|
359
|
-
// Look for inefficient patterns
|
360
|
-
if (/while.*true|for.*;.*;.*\+\+/.test(code)) {
|
361
|
-
if (!/(break|return)/.test(code)) score -= 15; // Potential infinite loops
|
362
|
-
}
|
363
|
-
|
364
|
-
return Math.max(0, Math.min(100, score));
|
365
|
-
}
|
package/src/config.ts
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
import { createClient } from '@supabase/supabase-js';
|
2
|
-
|
3
|
-
export const supabaseUrl = process.env.SUPABASE_URL || 'https://pkdytotoptkknghtsomn.supabase.co';
|
4
|
-
export const supabaseAnonKey = process.env.SUPABASE_ANON_KEY || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBrZHl0b3RvcHRra25naHRzb21uIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTk3MjI1OTgsImV4cCI6MjA3NTI5ODU5OH0.Y3RVJvx7w-eGD4Nv2aVv8jnkUKhmA2vpkBs7_rFzEoQ';
|
5
|
-
|
6
|
-
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
|
7
|
-
|
8
|
-
export const setAuthToken = (token: string) => {
|
9
|
-
supabase.auth.setSession({ access_token: token, refresh_token: '' });
|
10
|
-
};
|