ai-debug-local-mcp
Version:
🎯 ENHANCED AI GUIDANCE v4.1.2: Dramatically improved tool descriptions help AI users choose the right tools instead of 'close enough' options. Ultra-fast keyboard automation (10x speed), universal recording, multi-ecosystem debugging support, and compreh
212 lines (182 loc) • 5.37 kB
text/typescript
import { createHash } from 'crypto';
import fs from 'fs/promises';
import path from 'path';
export interface APIKeyInfo {
key: string;
tier: 'free' | 'pro' | 'enterprise';
usageLimit: number;
usageCount: number;
expiresAt?: Date;
features: string[];
}
export class APIKeyManager {
private apiKeys: Map<string, APIKeyInfo> = new Map();
private configPath: string;
constructor(configPath?: string) {
this.configPath = configPath || path.join(process.env.HOME || '', '.ai-debug-mcp', 'keys.json');
}
async initialize(): Promise<void> {
try {
const data = await fs.readFile(this.configPath, 'utf-8');
const keys = JSON.parse(data);
for (const keyInfo of keys) {
this.apiKeys.set(keyInfo.key, keyInfo);
}
} catch (error) {
// File doesn't exist yet, that's okay
await this.ensureConfigDir();
}
}
private async ensureConfigDir(): Promise<void> {
const dir = path.dirname(this.configPath);
await fs.mkdir(dir, { recursive: true });
}
async validateKey(apiKey: string | undefined): Promise<APIKeyInfo | null> {
if (!apiKey) {
// Return free tier for no API key
return {
key: 'FREE_TIER',
tier: 'free',
usageLimit: 100,
usageCount: 0,
features: ['basic_debugging', 'state_inspection', 'dom_analysis']
};
}
const keyInfo = this.apiKeys.get(apiKey);
if (!keyInfo) {
return null;
}
// Check expiration
if (keyInfo.expiresAt && new Date() > keyInfo.expiresAt) {
return null;
}
// Check usage limit
if (keyInfo.usageCount >= keyInfo.usageLimit) {
return null;
}
return keyInfo;
}
async incrementUsage(apiKey: string): Promise<void> {
const keyInfo = this.apiKeys.get(apiKey);
if (keyInfo && apiKey !== 'FREE_TIER') {
keyInfo.usageCount++;
await this.saveKeys();
}
}
private async saveKeys(): Promise<void> {
await this.ensureConfigDir();
const keys = Array.from(this.apiKeys.values());
await fs.writeFile(this.configPath, JSON.stringify(keys, null, 2));
}
getFeatureTiers(): Record<string, string[]> {
return {
free: [
'basic_debugging',
'state_inspection',
'dom_analysis',
'console_monitoring',
'network_inspection'
],
pro: [
'ai_root_cause_analysis',
'ai_fix_suggestions',
'pattern_detection',
'performance_analysis',
'advanced_correlation',
'unlimited_sessions'
],
enterprise: [
'custom_ai_models',
'priority_support',
'team_collaboration',
'audit_logs',
'sso_integration',
'dedicated_infrastructure'
]
};
}
hasFeature(keyInfo: APIKeyInfo, feature: string): boolean {
const tierFeatures = this.getFeatureTiers();
const allFeatures = [...tierFeatures.free];
if (keyInfo.tier === 'pro' || keyInfo.tier === 'enterprise') {
allFeatures.push(...tierFeatures.pro);
}
if (keyInfo.tier === 'enterprise') {
allFeatures.push(...tierFeatures.enterprise);
}
return allFeatures.includes(feature) || keyInfo.features.includes(feature);
}
hasValidKey(): boolean {
const apiKey = process.env.AI_DEBUG_API_KEY;
if (!apiKey) return false;
const keyInfo = this.apiKeys.get(apiKey);
if (!keyInfo) return false;
// Check expiration
if (keyInfo.expiresAt && new Date() > keyInfo.expiresAt) {
return false;
}
// Check usage limit
return keyInfo.usageCount < keyInfo.usageLimit;
}
getKeyStatus(): { valid: boolean; tier?: string; expiresAt?: string } {
const apiKey = process.env.AI_DEBUG_API_KEY;
if (!apiKey) {
return { valid: false };
}
const keyInfo = this.apiKeys.get(apiKey);
if (!keyInfo) {
return { valid: false };
}
const valid = this.hasValidKey();
return {
valid,
tier: keyInfo.tier,
expiresAt: keyInfo.expiresAt?.toISOString()
};
}
getUsageStats(): {
aiAnalysis: number;
aiReports: number;
premiumFeatures: number;
limits: {
aiAnalysis: number;
aiReports: number;
premiumFeatures: number;
};
} {
const apiKey = process.env.AI_DEBUG_API_KEY;
const keyInfo = apiKey ? this.apiKeys.get(apiKey) : null;
// Default free tier limits
const limits = {
aiAnalysis: 0,
aiReports: 0,
premiumFeatures: 0
};
if (keyInfo) {
switch (keyInfo.tier) {
case 'pro':
limits.aiAnalysis = 100;
limits.aiReports = 50;
limits.premiumFeatures = -1; // unlimited
break;
case 'enterprise':
limits.aiAnalysis = -1; // unlimited
limits.aiReports = -1; // unlimited
limits.premiumFeatures = -1; // unlimited
break;
}
}
return {
aiAnalysis: keyInfo?.usageCount || 0,
aiReports: Math.floor((keyInfo?.usageCount || 0) / 2), // Rough estimate
premiumFeatures: keyInfo?.usageCount || 0,
limits
};
}
async recordUsage(feature: string): Promise<void> {
const apiKey = process.env.AI_DEBUG_API_KEY;
if (apiKey) {
await this.incrementUsage(apiKey);
}
}
}