@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.
@@ -0,0 +1,266 @@
1
+ /**
2
+ * Plugin System for TokNxr Code Analysis
3
+ * Allows extensible analysis capabilities for custom analyzers
4
+ */
5
+ /**
6
+ * Plugin registry and management
7
+ */
8
+ export class PluginManager {
9
+ constructor() {
10
+ this.plugins = new Map();
11
+ }
12
+ /**
13
+ * Register a new plugin
14
+ */
15
+ register(plugin) {
16
+ this.plugins.set(plugin.name, plugin);
17
+ }
18
+ /**
19
+ * Unregister a plugin
20
+ */
21
+ unregister(name) {
22
+ return this.plugins.delete(name);
23
+ }
24
+ /**
25
+ * Get all registered plugins
26
+ */
27
+ getPlugins() {
28
+ return Array.from(this.plugins.values());
29
+ }
30
+ /**
31
+ * Get plugins that support a specific language
32
+ */
33
+ getPluginsForLanguage(language) {
34
+ return Array.from(this.plugins.values())
35
+ .filter(plugin => plugin.supportedLanguages.includes(language));
36
+ }
37
+ /**
38
+ * Analyze code using all applicable plugins
39
+ */
40
+ analyzeWithPlugins(code, baseMetrics, plugins) {
41
+ const applicablePlugins = plugins || this.getPluginsForLanguage(baseMetrics.language || 'unknown');
42
+ // Apply plugin analyses
43
+ for (const plugin of applicablePlugins) {
44
+ if (plugin.analyzeQuality && plugin.validateSyntax && plugin.calculateReadability) {
45
+ try {
46
+ const pluginResults = plugin.analyzeQuality(code, baseMetrics.language || 'unknown');
47
+ // Merge plugin results
48
+ if (pluginResults.pluginMetrics) {
49
+ baseMetrics.pluginMetrics = {
50
+ ...baseMetrics.pluginMetrics,
51
+ [plugin.name]: pluginResults.pluginMetrics
52
+ };
53
+ }
54
+ // Override base metrics if plugin provides better validation
55
+ if (pluginResults.syntaxValid !== undefined) {
56
+ const pluginValid = plugin.validateSyntax(code, baseMetrics.language || 'unknown');
57
+ if (!pluginValid && baseMetrics.syntaxValid) {
58
+ // Plugin detected issues that base validation missed
59
+ baseMetrics.syntaxValid = false;
60
+ baseMetrics.potentialIssues.push(`${plugin.name}: syntax validation failed`);
61
+ }
62
+ }
63
+ // Enhance readability if plugin provides better calculation
64
+ if (pluginResults.estimatedReadability !== undefined) {
65
+ const pluginReadability = plugin.calculateReadability(code, baseMetrics.language || 'unknown');
66
+ // Use the better (higher) readability score
67
+ if (pluginReadability > baseMetrics.estimatedReadability) {
68
+ baseMetrics.estimatedReadability = pluginReadability;
69
+ }
70
+ }
71
+ // Add potential issues from plugin
72
+ if (pluginResults.potentialIssues && pluginResults.potentialIssues.length > 0) {
73
+ baseMetrics.potentialIssues.push(...pluginResults.potentialIssues.map(issue => `${plugin.name}: ${issue}`));
74
+ }
75
+ }
76
+ catch (error) {
77
+ console.warn(`Plugin ${plugin.name} failed during analysis:`, error);
78
+ }
79
+ }
80
+ }
81
+ return baseMetrics;
82
+ }
83
+ /**
84
+ * Score effectiveness using plugins
85
+ */
86
+ scoreEffectivenessWithPlugins(userPrompt, aiResponse, baseScore, extractedCode, plugins) {
87
+ const code = extractedCode || aiResponse;
88
+ const codeMetrics = { language: this.detectLanguageFromCode(code) };
89
+ const applicablePlugins = plugins || this.getPluginsForLanguage(codeMetrics.language || 'unknown');
90
+ // Apply plugin effectiveness analysis
91
+ for (const plugin of applicablePlugins) {
92
+ if (plugin.analyzeEffectiveness) {
93
+ try {
94
+ const pluginResults = plugin.analyzeEffectiveness(userPrompt, aiResponse, extractedCode);
95
+ // Apply hallucination detection
96
+ if (plugin.detectHallucinations) {
97
+ const hallucinations = plugin.detectHallucinations(code, codeMetrics.language || 'unknown');
98
+ if (hallucinations.length > 0) {
99
+ const avgConfidence = hallucinations.reduce((sum, h) => sum + h.confidence, 0) / hallucinations.length;
100
+ baseScore.hallucinationRisk = (baseScore.hallucinationRisk || 0) + (avgConfidence * 0.3);
101
+ }
102
+ }
103
+ // Merge other effectiveness metrics
104
+ Object.assign(baseScore, pluginResults);
105
+ }
106
+ catch (error) {
107
+ console.warn(`Plugin ${plugin.name} failed during effectiveness scoring:`, error);
108
+ }
109
+ }
110
+ }
111
+ return baseScore;
112
+ }
113
+ /**
114
+ * Detect language from code (helper method)
115
+ */
116
+ detectLanguageFromCode(code) {
117
+ if (/(?:import|export|function|const|let|var)\s+/.test(code)) {
118
+ return code.includes('interface') || code.includes(': string') ? 'typescript' : 'javascript';
119
+ }
120
+ if (/package\s+\w+|func\s+\w+\(/.test(code))
121
+ return 'go';
122
+ if (/fn\s+\w+|use\s+std::/.test(code))
123
+ return 'rust';
124
+ if (/public\s+class|import\s+java\./.test(code))
125
+ return 'java';
126
+ if (/#include\s+<|std::|cout\s+<<|int\s+main\(/.test(code))
127
+ return 'cpp';
128
+ return undefined;
129
+ }
130
+ }
131
+ /**
132
+ * Built-in security analyzer plugin
133
+ */
134
+ export const SecurityAnalyzerPlugin = {
135
+ name: 'security-analyzer',
136
+ version: '1.0.0',
137
+ description: 'Analyzes code for security vulnerabilities',
138
+ supportedLanguages: ['javascript', 'typescript', 'python', 'go', 'rust', 'java', 'cpp'],
139
+ analyzeQuality(code, language) {
140
+ const issues = [];
141
+ let securityScore = 100;
142
+ // Common security issues across languages
143
+ if (code.includes('eval(') || code.includes('Function(')) {
144
+ issues.push('Use of eval() or Function() constructor - potential code injection');
145
+ securityScore -= 30;
146
+ }
147
+ if (code.includes('innerHTML') || code.includes('outerHTML')) {
148
+ issues.push('Direct HTML manipulation - potential XSS vulnerability');
149
+ securityScore -= 20;
150
+ }
151
+ if (/(password|secret|key).*=\s*["'][^"']*["']/.test(code)) {
152
+ issues.push('Hardcoded credentials detected');
153
+ securityScore -= 40;
154
+ }
155
+ // Language-specific checks
156
+ switch (language) {
157
+ case 'javascript':
158
+ case 'typescript':
159
+ if (code.includes('document.cookie')) {
160
+ issues.push('Direct cookie manipulation without secure flags');
161
+ securityScore -= 15;
162
+ }
163
+ break;
164
+ case 'python':
165
+ if (code.includes('exec(') || code.includes('eval(')) {
166
+ issues.push('Use of exec() or eval() in Python - code injection risk');
167
+ securityScore -= 30;
168
+ }
169
+ break;
170
+ }
171
+ return {
172
+ potentialIssues: issues,
173
+ securityScore: Math.max(0, securityScore)
174
+ };
175
+ },
176
+ detectHallucinations(code, language) {
177
+ const detections = [];
178
+ // Check for obviously incorrect API usage patterns
179
+ if (language === 'javascript' && code.includes('fs.readFile') && !code.includes('import fs')) {
180
+ detections.push({
181
+ confidence: 85,
182
+ type: 'missing_import',
183
+ message: 'Using fs.readFile without importing fs module'
184
+ });
185
+ }
186
+ if (language === 'python' && code.includes('import requests') && code.includes('requests.get') && !code.includes('response.raise_for_status()')) {
187
+ detections.push({
188
+ confidence: 60,
189
+ type: 'missing_error_handling',
190
+ message: 'HTTP request without proper error handling'
191
+ });
192
+ }
193
+ return detections;
194
+ }
195
+ };
196
+ /**
197
+ * Performance analyzer plugin
198
+ */
199
+ export const PerformanceAnalyzerPlugin = {
200
+ name: 'performance-analyzer',
201
+ version: '1.0.0',
202
+ description: 'Analyzes code for performance bottlenecks',
203
+ supportedLanguages: ['javascript', 'typescript', 'python', 'go', 'rust', 'java', 'cpp'],
204
+ analyzeQuality(code, language) {
205
+ const issues = [];
206
+ let performanceScore = 100;
207
+ // Detect performance anti-patterns
208
+ if (/(for.*for|while.*while)/.test(code)) {
209
+ issues.push('Nested loops detected - potential O(n²) complexity');
210
+ performanceScore -= 15;
211
+ }
212
+ // Memory leaks in JavaScript
213
+ if (/(setInterval|setTimeout)/.test(code) && !code.includes('clearInterval') && !code.includes('clearTimeout')) {
214
+ issues.push('Timer without cleanup - potential memory leak');
215
+ performanceScore -= 20;
216
+ }
217
+ // Inefficient string concatenation
218
+ if (/(\w+\s*\+\s*\w+.*){3,}/.test(code) && !code.includes('join(')) {
219
+ issues.push('Inefficient string concatenation - consider using array join');
220
+ performanceScore -= 10;
221
+ }
222
+ return {
223
+ potentialIssues: issues,
224
+ performanceScore: Math.max(0, performanceScore)
225
+ };
226
+ }
227
+ };
228
+ /**
229
+ * Framework detector plugin
230
+ */
231
+ export const FrameworkDetectorPlugin = {
232
+ name: 'framework-detector',
233
+ version: '1.0.0',
234
+ description: 'Detects and analyzes framework-specific code',
235
+ supportedLanguages: ['javascript', 'typescript', 'python'],
236
+ analyzeQuality(code, language) {
237
+ let framework;
238
+ if (code.includes('import React') || code.includes('from "react"')) {
239
+ framework = 'react';
240
+ }
241
+ else if (code.includes('import Vue') || code.includes('from "vue"')) {
242
+ framework = 'vue';
243
+ }
244
+ else if (code.includes('import { Component }') && code.includes('@Component')) {
245
+ framework = 'angular';
246
+ }
247
+ else if (code.includes('from flask import') || code.includes('import flask')) {
248
+ framework = 'flask';
249
+ }
250
+ else if (code.includes('from django') || code.includes('import django')) {
251
+ framework = 'django';
252
+ }
253
+ else if (code.includes('from fastapi import') || code.includes('import fastapi')) {
254
+ framework = 'fastapi';
255
+ }
256
+ return {
257
+ framework
258
+ };
259
+ }
260
+ };
261
+ // Export default plugin manager instance
262
+ export const pluginManager = new PluginManager();
263
+ // Register built-in plugins
264
+ pluginManager.register(SecurityAnalyzerPlugin);
265
+ pluginManager.register(PerformanceAnalyzerPlugin);
266
+ pluginManager.register(FrameworkDetectorPlugin);
package/lib/sync.js CHANGED
@@ -13,9 +13,16 @@ export async function syncInteractions(supabase, options) {
13
13
  }
14
14
  // Set auth in Supabase
15
15
  setAuthToken(token);
16
- const logFilePath = path.resolve(process.cwd(), 'interactions.log');
16
+ // Resolve interactions.log robustly across run contexts (repo root vs toknxr-cli)
17
+ const candidatePaths = [
18
+ path.resolve(process.cwd(), 'interactions.log'),
19
+ path.resolve(process.cwd(), 'toknxr-cli', 'interactions.log'),
20
+ // When executed from built JS in lib/, __dirname points to lib; go up one
21
+ path.resolve(__dirname, '../interactions.log'),
22
+ ];
23
+ const logFilePath = candidatePaths.find(p => fs.existsSync(p)) || candidatePaths[0];
17
24
  if (!fs.existsSync(logFilePath)) {
18
- console.log(chalk.yellow('No interactions.log file found. Nothing to sync.'));
25
+ console.log(chalk.yellow('No interactions.log file found in current directory or toknxr-cli/. Nothing to sync.'));
19
26
  return;
20
27
  }
21
28
  const fileContent = fs.readFileSync(logFilePath, 'utf8');
@@ -30,7 +37,7 @@ export async function syncInteractions(supabase, options) {
30
37
  const log = JSON.parse(line);
31
38
  logs.push(log);
32
39
  }
33
- catch (error) {
40
+ catch {
34
41
  console.warn(`Skipping invalid log entry: ${line}`);
35
42
  }
36
43
  }
@@ -71,6 +78,16 @@ export async function syncInteractions(supabase, options) {
71
78
  timestamp: new Date(log.timestamp).toISOString(),
72
79
  request_details: log.userPrompt || '',
73
80
  response_details: log.aiResponse || log.extractedCode || '',
81
+ // Rich metrics from CLI analysis
82
+ code_quality_score: log.codeQualityScore,
83
+ effectiveness_score: log.effectivenessScore,
84
+ language: log.codeQualityMetrics?.language,
85
+ syntax_valid: log.codeQualityMetrics?.syntaxValid,
86
+ readability_score: log.codeQualityMetrics?.estimatedReadability,
87
+ hallucination_detected: log.hallucinationDetection?.isLikelyHallucination,
88
+ hallucination_confidence: log.hallucinationDetection?.confidence,
89
+ prompt_clarity_match: log.hallucinationDetection?.promptClarityMatch,
90
+ task_type: log.taskType,
74
91
  };
75
92
  interactions.push(interaction);
76
93
  }
@@ -89,7 +106,12 @@ export async function syncInteractions(supabase, options) {
89
106
  console.log(`Successfully synced ${interactions.length} interactions.`);
90
107
  }
91
108
  if (options.clear) {
92
- fs.writeFileSync(logFilePath, '');
93
- console.log(chalk.gray('Local interactions.log has been cleared.'));
109
+ try {
110
+ fs.writeFileSync(logFilePath, '');
111
+ console.log(chalk.gray('Local interactions.log has been cleared.'));
112
+ }
113
+ catch {
114
+ console.log(chalk.yellow('Could not clear interactions.log. Proceeding without clearing.'));
115
+ }
94
116
  }
95
117
  }
package/lib/ui.js ADDED
@@ -0,0 +1,132 @@
1
+ import chalk from 'chalk';
2
+ import readline from 'readline';
3
+ export const createStatsOverview = (cost, requests, waste, hallucinations) => `
4
+ ${chalk.bold.blue('📊 TokNXR Analytics Overview')}
5
+ ${chalk.gray('------------------------------------')}
6
+ ${chalk.cyan('Total Cost:')} ${chalk.green(`$${cost.toFixed(2)}`)}
7
+ ${chalk.cyan('Total Requests:')} ${chalk.green(requests)}
8
+ ${chalk.cyan('Estimated Waste:')} ${chalk.yellow(`${waste.toFixed(2)}%`)}
9
+ ${chalk.cyan('Hallucination Rate:')} ${chalk.red(`${hallucinations.toFixed(2)}%`)}
10
+ `;
11
+ export const createProviderTable = async (stats) => {
12
+ let table = `${chalk.bold.blue('🤖 Provider Performance')}\n`;
13
+ table += `${chalk.gray('----------------------------------------------------------------')}\n`;
14
+ table += `${chalk.bold('Provider')} | ${chalk.bold('Tokens')} | ${chalk.bold('Cost')} | ${chalk.bold('Quality')} | ${chalk.bold('Effectiveness')}\n`;
15
+ table += `${chalk.gray('----------------------------------------------------------------')}\n`;
16
+ for (const provider in stats) {
17
+ const { totalTokens, costUSD, avgQualityScore, avgEffectivenessScore } = stats[provider];
18
+ table += `${provider.padEnd(15)} | ${totalTokens.toLocaleString().padEnd(10)} | ${`$${costUSD.toFixed(2)}`.padEnd(8)} | ${`${avgQualityScore}/100`.padEnd(10)} | ${`${avgEffectivenessScore}/100`}\n`;
19
+ }
20
+ return table;
21
+ };
22
+ export const createQualityBreakdown = (interactions) => {
23
+ const qualityScores = interactions.map(i => i.codeQualityScore || 0);
24
+ const averageQuality = qualityScores.reduce((a, b) => a + b, 0) / qualityScores.length;
25
+ return `
26
+ ${chalk.bold.magenta('🔍 Code Quality Breakdown')}
27
+ ${chalk.gray('------------------------------------')}
28
+ ${chalk.cyan('Average Quality Score:')} ${chalk.green(`${averageQuality.toFixed(2)}/100`)}
29
+ `;
30
+ };
31
+ export const createOperationProgress = (title, steps) => {
32
+ let currentStep = 0;
33
+ const spinner = {
34
+ updateProgress: (step) => {
35
+ currentStep = step;
36
+ console.log(`${chalk.blue(`[${currentStep + 1}/${steps.length}]`)} ${steps[currentStep]}`);
37
+ },
38
+ succeed: (message) => {
39
+ console.log(chalk.green(message));
40
+ },
41
+ fail: (message) => {
42
+ console.log(chalk.red(message));
43
+ },
44
+ };
45
+ console.log(chalk.bold.blue(title));
46
+ return spinner;
47
+ };
48
+ export const createInteractiveMenu = (options) => {
49
+ return new Promise(resolve => {
50
+ console.log(chalk.bold.blue('MENU'));
51
+ options.forEach(option => console.log(option.name));
52
+ const rl = readline.createInterface({
53
+ input: process.stdin,
54
+ output: process.stdout,
55
+ });
56
+ rl.question('Choose an option: ', answer => {
57
+ rl.close();
58
+ resolve(answer);
59
+ });
60
+ });
61
+ };
62
+ export const createBox = (title, content, options) => {
63
+ const { borderColor, titleColor } = options;
64
+ const color = chalk[borderColor] || chalk.gray;
65
+ const titleColored = chalk[titleColor] || chalk.white;
66
+ let box = color('┌' + '─'.repeat(title.length + 2) + '┐\n');
67
+ box += color('│ ') + titleColored(title) + color(' │\n');
68
+ box += color('├' + '─'.repeat(title.length + 2) + '┤\n');
69
+ content.forEach(line => {
70
+ box +=
71
+ color('│ ') +
72
+ line +
73
+ color(' '.repeat(Math.max(0, title.length - line.length + 2))) +
74
+ color(' │\n');
75
+ });
76
+ box += color('└' + '─'.repeat(title.length + 2) + '┘');
77
+ return box;
78
+ };
79
+ export const createCostChart = (data) => {
80
+ // Basic chart for demonstration
81
+ let chart = `${chalk.bold.blue('Cost Trend (Last 7 Days)')}\n`;
82
+ const max = Math.max(...data);
83
+ data.forEach(value => {
84
+ const bar = '█'.repeat(Math.round((value / max) * 20));
85
+ chart += `${chalk.green(bar)}\n`;
86
+ });
87
+ return chart;
88
+ };
89
+ export const createPaginatedDisplay = (data, pageSize, currentPage, render, title) => {
90
+ let display = title ? `${chalk.bold.blue(title)}\n` : '';
91
+ data.forEach((item, index) => {
92
+ display += render(item, (currentPage - 1) * pageSize + index);
93
+ });
94
+ return display;
95
+ };
96
+ export const createFilterInterface = (currentFilters) => {
97
+ return new Promise(resolve => {
98
+ console.log('Filtering interface is not implemented in this mock.');
99
+ resolve(currentFilters);
100
+ });
101
+ };
102
+ export const createSearchInterface = (fields) => {
103
+ return new Promise(resolve => {
104
+ console.log('Search interface is not implemented in this mock.');
105
+ resolve({ query: 'test', fields });
106
+ });
107
+ };
108
+ export class InteractiveDataExplorer {
109
+ constructor(data) {
110
+ this.data = data;
111
+ }
112
+ setPageSize(_size) { } // Mock implementation
113
+ setPage(_page) { } // Mock implementation
114
+ getCurrentPageData() {
115
+ return this.data;
116
+ }
117
+ getPaginationInfo() {
118
+ return { totalItems: this.data.length, totalPages: 1 };
119
+ }
120
+ }
121
+ export class CliStateManager {
122
+ static getPreferences() {
123
+ return {};
124
+ }
125
+ static updateSessionBudget(_amount, _provider) { } // Mock implementation
126
+ static loadState() {
127
+ return { budgets: {} };
128
+ }
129
+ }
130
+ export const filterAndSearchInteractions = (interactions, _filters, _search) => {
131
+ return interactions;
132
+ };
package/package.json CHANGED
@@ -1,38 +1,71 @@
1
1
  {
2
2
  "name": "@goldensheepai/toknxr-cli",
3
- "version": "0.2.0",
4
- "license": "ISC",
3
+ "version": "0.2.2",
4
+ "description": "CLI-powered AI effectiveness & code quality analysis tool - 100% Local",
5
+ "license": "MIT",
5
6
  "type": "module",
7
+ "private": false,
6
8
  "bin": {
7
9
  "toknxr": "lib/cli.js"
8
10
  },
11
+ "main": "lib/cli.js",
12
+ "files": [
13
+ "lib/**/*",
14
+ "package.json",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "publishConfig": {
19
+ "access": "public",
20
+ "registry": "https://registry.npmjs.org/"
21
+ },
22
+ "keywords": [
23
+ "ai",
24
+ "cli",
25
+ "code-quality",
26
+ "analytics",
27
+ "token-tracking",
28
+ "developer-tools",
29
+ "local-first",
30
+ "proxy",
31
+ "gemini",
32
+ "openai",
33
+ "anthropic"
34
+ ],
9
35
  "scripts": {
10
- "start": "tsx src/cli.ts start",
11
- "cli": "tsx src/cli.ts",
12
36
  "build": "tsc",
13
- "test": "echo \"Error: no test specified\" && exit 1"
37
+ "dev": "tsx watch src/cli.ts",
38
+ "lint": "echo 'Lint CLI code with root ESLint config'",
39
+ "typecheck": "tsc --noEmit",
40
+ "cli": "tsx src/cli.ts",
41
+ "start": "tsx src/cli.ts start",
42
+ "test": "tsx --test --test-reporter=verbose src/**/*.test.ts",
43
+ "test:watch": "tsx --test --watch src/**/*.test.ts"
14
44
  },
15
45
  "dependencies": {
16
- "@supabase/supabase-js": "^2.47.1",
17
- "commander": "^14.0.1",
18
- "chalk": "^5.6.2",
19
46
  "axios": "^1.12.2",
20
- "open": "^10.2.0",
21
- "keytar": "^7.9.0",
22
- "ora": "^9.0.0",
23
- "cli-spinners": "^3.3.0",
47
+ "boxen": "^7.1.1",
48
+ "chalk": "^5.6.2",
24
49
  "cli-cursor": "^5.0.0",
25
- "onetime": "^7.0.0",
50
+ "cli-progress": "^3.12.0",
51
+ "cli-spinners": "^3.3.0",
52
+ "cli-table3": "^0.6.4",
53
+ "commander": "^14.0.1",
54
+ "dotenv": "^16.4.5",
55
+ "inquirer": "^12.0.0",
26
56
  "is-interactive": "^2.0.0",
27
- "@types/keytar": "^4.4.0",
28
- "dotenv": "^16.4.5"
57
+ "onetime": "^7.0.0",
58
+ "open": "^10.2.0",
59
+ "ora": "^9.0.0"
29
60
  },
30
61
  "devDependencies": {
31
- "@types/node": "^24.6.2",
32
62
  "@types/chalk": "^2.2.4",
63
+ "@types/node": "^24.6.2",
33
64
  "@types/open": "^6.2.1",
34
- "typescript": "^5.9.3",
65
+ "@vitest/ui": "^3.2.4",
66
+ "esbuild": "^0.25.10",
35
67
  "tsx": "^4.20.6",
36
- "esbuild": "^0.25.10"
68
+ "typescript": "^5.9.3",
69
+ "vitest": "^3.2.4"
37
70
  }
38
71
  }
package/.env DELETED
@@ -1,21 +0,0 @@
1
- # TokNXR Environment Variables
2
- # Copy this file to .env and fill in your actual API keys
3
-
4
- # Google AI API Key (used for both Gemini-Pro and Gemini-Free)
5
- GEMINI_API_KEY=AIzaSyCtrQ8e5H66vbrAozWlWUmCcObJmrI2ovg
6
-
7
- # OpenAI API Key
8
- OPENAI_API_KEY=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
9
-
10
- # Anthropic Claude API Key
11
- ANTHROPIC_API_KEY=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
12
-
13
- # Supabase Configuration
14
- SUPABASE_URL=https://your-project.supabase.co
15
- SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
16
- # Optional: Webhook URL for budget alerts
17
- # WEBHOOK_URL=https://your-webhook-url.com/alerts
18
- SUPABASE_URL=https://pkdytotoptkknghtsomn.supabase.co
19
- SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBrZHl0b3RvcHRra25naHRzb21uIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTk3MjI1OTgsImV4cCI6MjA3NTI5ODU5OH0.Y3RVJvx7w-eGD4Nv2aVv8jnkUKhmA2vpkBs7_rFzEoQ
20
- # Optional: Custom port for the proxy server (default: 8788)
21
- # PORT=8788
package/.env.example DELETED
@@ -1,21 +0,0 @@
1
- # TokNXR Environment Variables
2
- # Copy this file to .env and fill in your actual API keys
3
-
4
- # Google AI API Key (used for both Gemini-Pro and Gemini-Free)
5
- GEMINI_API_KEY=AIzaSyCtrQ8e5H66vbrAozWlWUmCcObJmrI2ovg
6
-
7
- # OpenAI API Key
8
- OPENAI_API_KEY=your-openai-api-key-here
9
-
10
- # Anthropic Claude API Key
11
- ANTHROPIC_API_KEY=your-anthropic-api-key-here
12
-
13
- # Optional: Webhook URL for budget alerts
14
- # WEBHOOK_URL=https://your-webhook-url.com/alerts
15
- SUPABASE_URL=your-supabase-url
16
- SUPABASE_ANON_KEY=your-anon-key
17
- SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
18
- SUPABASE_JWT_SECRET=your-jwt-secret
19
-
20
- # Optional: Custom port for the proxy server (default: 8787)
21
- PORT=8787
package/interactions.log DELETED
@@ -1,8 +0,0 @@
1
- {"timestamp":"2025-10-05T20:14:35.420Z","provider":"Gemini-Pro","model":"unknown","promptTokens":9,"completionTokens":2056,"totalTokens":3506,"costUSD":0,"taskType":"chat"}
2
- {"timestamp":"2025-10-05T20:18:24.093Z","provider":"Gemini-Pro","model":"unknown","promptTokens":9,"completionTokens":2236,"totalTokens":3564,"costUSD":0,"taskType":"chat"}
3
- {"timestamp":"2025-10-05T20:21:58.826Z","provider":"Gemini-Pro","model":"unknown","promptTokens":9,"completionTokens":2054,"totalTokens":3322,"costUSD":0,"taskType":"chat"}
4
- {"requestId":"84870610-70c2-4b31-834f-6c55f92c8495","timestamp":"2025-10-05T20:49:46.035Z","provider":"Gemini-Pro","model":"gemini-2.5-flash","promptTokens":2,"completionTokens":519,"totalTokens":1930,"costUSD":0.3117,"taskType":"chat"}
5
- {"timestamp":"2025-10-05T21:44:57.972Z","provider":"Gemini-Pro","model":"gemini-2.5-flash","promptTokens":150,"completionTokens":200,"totalTokens":350,"costUSD":0.05,"taskType":"coding","userPrompt":"Create a React component for a todo list","aiResponse":"Here's a React todo component...","extractedCode":"function TodoList() {\n const [todos, setTodos] = useState([]);\n return (\n <div>\n <h1>My Todos</h1>\n {/* Todo implementation */}\n </div>\n );\n}","codeQualityScore":85,"codeQualityMetrics":{"syntaxValid":true,"estimatedReadability":0.8,"hasFunctions":true,"hasClasses":false,"linesOfCode":12,"potentialIssues":[]},"effectivenessScore":88}
6
- {"timestamp":"2025-10-05T21:59:57.974Z","provider":"OpenAI-GPT4","model":"gpt-4","promptTokens":80,"completionTokens":120,"totalTokens":200,"costUSD":0.02,"taskType":"coding","userPrompt":"Write a Python function to calculate fibonacci","aiResponse":"def fibonacci(n):...","extractedCode":"def fibonacci(n):\n if n <= 1:\n return n\n return fibonacci(n-1) + fibonacci(n-2)","codeQualityScore":92,"codeQualityMetrics":{"syntaxValid":true,"estimatedReadability":0.9,"hasFunctions":true,"hasClasses":false,"linesOfCode":4,"potentialIssues":[]},"effectivenessScore":95}
7
- {"timestamp":"2025-10-05T22:09:57.974Z","provider":"Gemini-Pro","model":"gemini-2.5-flash","promptTokens":200,"completionTokens":300,"totalTokens":500,"costUSD":0.08,"taskType":"coding","userPrompt":"Create a TypeScript API endpoint","aiResponse":"Here's a TypeScript API endpoint...","extractedCode":"import express from 'express';\n\nconst app = express();\n\napp.get('/api/users', async (req, res) => {\n // Implementation here\n});\n\nexport default app;","codeQualityScore":78,"codeQualityMetrics":{"syntaxValid":true,"estimatedReadability":0.7,"hasFunctions":true,"hasClasses":false,"linesOfCode":8,"potentialIssues":["Missing error handling"]},"effectivenessScore":82}
8
- {"requestId":"b8d3c1cc-c3c5-427a-b9f3-0af12b7e8e8d","timestamp":"2025-10-05T22:19:07.944Z","provider":"Gemini-Pro","model":"gemini-2.5-flash","promptTokens":13,"completionTokens":1133,"totalTokens":2206,"costUSD":0.68175,"taskType":"coding","extractedCode":"/**\n * Calculates the factorial of a non-negative integer using recursion.\n *\n * @param {number} n The non-negative integer for which to calculate the factorial.\n * @returns {number} The factorial of n.\n * @throws {Error} If n is a negative number.\n * @throws {Error} If n is not an integer.\n */\nfunction factorial(n) {\n // Input validation: Factorial is traditionally defined for non-negative integers.\n if (n < 0) {\n throw new Error(\"Factorial is not defined for negative numbers.\");\n }\n if (!Number.isInteger(n)) {\n throw new Error(\"Factorial is only defined for integer numbers.\");\n }\n\n // Base Case: This is where the recursion stops.\n // The factorial of 0 is 1, and the factorial of 1 is 1.\n if (n === 0 || n === 1) {\n return 1;\n }\n\n // Recursive Step: The function calls itself with a smaller input.\n // n! = n * (n-1)!\n return n * factorial(n - 1);\n}\n\n// --- Examples ---\nconsole.log(`Factorial of 0: ${factorial(0)}`); // Expected: 1\nconsole.log(`Factorial of 1: ${factorial(1)}`); // Expected: 1\nconsole.log(`Factorial of 5: ${factorial(5)}`); // Expected: 120 (5 * 4 * 3 * 2 * 1)\nconsole.log(`Factorial of 7: ${factorial(7)}`); // Expected: 5040 (7 * 6 * 5 * 4 * 3 * 2 * 1)\nconsole.log(`Factorial of 10: ${factorial(10)}`); // Expected: 3628800\n\n// --- Error Handling Examples ---\ntry {\n console.log(`Factorial of -3: ${factorial(-3)}`);\n} catch (error) {\n console.error(`Error: ${error.message}`); // Expected: Error: Factorial is not defined for negative numbers.\n}\n\ntry {\n console.log(`Factorial of 3.5: ${factorial(3.5)}`);\n} catch (error) {\n console.error(`Error: ${error.message}`); // Expected: Error: Factorial is only defined for integer numbers.\n}\n\ntry {\n console.log(`Factorial of \"abc\": ${factorial(\"abc\")}`);\n} catch (error) {\n console.error(`Error: ${error.message}`); // Expected: Error: Factorial is only defined for integer numbers.\n}","codeQualityMetrics":{"syntaxValid":true,"linesOfCode":47,"complexity":10,"hasFunctions":true,"hasClasses":false,"hasTests":false,"estimatedReadability":6,"potentialIssues":[],"language":"javascript"},"codeQualityScore":100,"effectivenessScore":68,"userPrompt":"Write a JavaScript function to calculate the factorial of a number using recursion","aiResponse":"Here's a JavaScript function to calculate the factorial of a number using recursion, along with explanations and examples:\n\n```javascript\n/**\n * Calculates the factorial of a non-negative integer using recursion.\n *\n * @param {number} n The non-negative integer for which to calculate the factorial.\n * @returns {number} The factorial of n.\n * @throws {Error} If n is a negative number.\n * @throws {Error} If n is not an integer.\n */\nfunction factorial(n) {\n // Input validation: Factorial is traditionally defined for non-negative integers.\n if (n < 0) {\n throw new Error(\"Factorial is not defined for negative numbers.\");\n }\n if (!Number.isInteger(n)) {\n throw new Error(\"Factorial is only defined for integer numbers.\");\n }\n\n // Base Case: This is where the recursion stops.\n // The factorial of 0 is 1, and the factorial of 1 is 1.\n if (n === 0 || n === 1) {\n return 1;\n }\n\n // Recursive Step: The function calls itself with a smaller input.\n // n! = n * (n-1)!\n return n * factorial(n - 1);\n}\n\n// --- Examples ---\nconsole.log(`Factorial of 0: ${factorial(0)}`); // Expected: 1\nconsole.log(`Factorial of 1: ${factorial(1)}`); // Expected: 1\nconsole.log(`Factorial of 5: ${factorial(5)}`); // Expected: 120 (5 * 4 * 3 * 2 * 1)\nconsole.log(`Factorial of 7: ${factorial(7)}`); // Expected: 5040 (7 * 6 * 5 * 4 * 3 * 2 * 1)\nconsole.log(`Factorial of 10: ${factorial(10)}`); // Expected: 3628800\n\n// --- Error Handling Examples ---\ntry {\n console.log(`Factorial of -3: ${factorial(-3)}`);\n} catch (error) {\n console.error(`Error: ${error.message}`); // Expected: Error: Factorial is not defined for negative numbers.\n}\n\ntry {\n console.log(`Factorial of 3.5: ${factorial(3.5)}`);\n} catch (error) {\n console.error(`Error: ${error.message}`); // Expected: Error: Factorial is only defined for integer numbers.\n}\n\ntry {\n console.log(`Factorial of \"abc\": ${factorial(\"abc\")}`);\n} catch (error) {\n console.error(`Error: ${error.message}`); // Expected: Error: Factorial is only defined for integer numbers.\n}\n```\n\n### How it works (Recursive Breakdown):\n\nLet's trace `factorial(3)`:\n\n1. `factorial(3)` is called.\n * `n` is 3. It's not 0 or 1.\n * It returns `3 * factorial(2)`.\n\n2. `factorial(2)` is called (from inside the first call).\n * `n` is 2. It's not 0 or 1.\n * It returns `2 * factorial(1)`.\n\n3. `factorial(1)` is called (from inside the second call).\n * `n` is 1. **This hits the base case!**\n * It returns `1`.\n\n4. Now, the execution unwinds:\n * The `factorial(2)` call receives `1` from `factorial(1)`.\n * It calculates `2 * 1 = 2`.\n * It returns `2`.\n\n5. Finally, the `factorial(3)` call receives `2` from `factorial(2)`.\n * It calculates `3 * 2 = 6`.\n * It returns `6`.\n\nThe result `6` is then printed.\n\n### Key Concepts:\n\n1. **Base Case:** Every recursive function *must* have one or more base cases. This is a condition where the function stops calling itself and returns a direct value. Without a base case, the function would call itself indefinitely, leading to a \"Stack Overflow\" error. For factorial, `factorial(0) = 1` and `factorial(1) = 1` are the base cases.\n2. **Recursive Step:** This is where the function calls itself with a modified (usually smaller or simpler) input. The idea is to break down the problem into a smaller instance of the *same* problem. For factorial, `n! = n * (n-1)!` is the recursive step. The problem `n!` is solved by using the solution to `(n-1)!`.\n3. **Input Validation:** It's good practice to add checks for invalid inputs (like negative numbers or non-integers for factorial) to make the function more robust."}