UNPKG

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

459 lines 18.7 kB
/** * Handler for meta-framework debugging tools * Supports Rails, Remix, Astro, Nuxt, Qwik, SvelteKit, and more */ export class MetaFrameworkHandler { engine; engineAttachedToSession = new Set(); tools = [ { name: 'rails_turbo_analysis', description: 'Analyze Rails Turbo/Hotwire performance: cache hit rates, frame loading, navigation timing.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'csrf_security_check', description: 'Check CSRF token configuration for Rails/Django apps. Detects missing tokens in forms and AJAX requests.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'stimulus_controllers', description: 'List and analyze Stimulus controllers in Rails applications. Shows actions, targets, and potential issues.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'meta_framework_info', description: 'Get information about detected meta-framework (Remix, Astro, Nuxt, Qwik, SolidJS, SvelteKit) including version, features, and build tool.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'remix_loader_analysis', description: 'Analyze Remix loader performance including execution times, data sizes, and caching behavior.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'astro_islands_audit', description: 'Audit Astro islands for hydration strategies, component usage, and performance optimization opportunities.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'nuxt_payload_analysis', description: 'Analyze Nuxt payload size, hydration state, and server-side data to identify optimization opportunities.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'qwik_resumability_check', description: 'Check Qwik resumability performance including serialized state size, QRL loading, and lazy execution metrics.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'vite_hmr_monitor', description: 'Monitor Vite HMR (Hot Module Replacement) events, update times, and errors during development.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'detect_meta_framework_issues', description: 'Detect framework-specific issues in Remix, Astro, Nuxt, Qwik, SolidJS, or SvelteKit applications.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } } ]; constructor(engine) { this.engine = engine; } async handle(toolName, args, sessions) { const { sessionId } = args; const session = sessions.get(sessionId); if (!session) { throw new Error(`Debug session ${sessionId} not found`); } // Attach engine to page if not already attached if (session.page && !this.engineAttachedToSession.has(sessionId)) { await this.engine.attachToPage(session.page); this.engineAttachedToSession.add(sessionId); } switch (toolName) { case 'rails_turbo_analysis': return await this.handleRailsTurboAnalysis(); case 'csrf_security_check': return await this.handleCSRFSecurityCheck(); case 'stimulus_controllers': return await this.handleStimulusControllers(); case 'meta_framework_info': return await this.handleMetaFrameworkInfo(); case 'remix_loader_analysis': return await this.handleRemixLoaderAnalysis(); case 'astro_islands_audit': return await this.handleAstroIslandsAudit(); case 'nuxt_payload_analysis': return await this.handleNuxtPayloadAnalysis(); case 'qwik_resumability_check': return await this.handleQwikResumabilityCheck(); case 'vite_hmr_monitor': return await this.handleViteHMRMonitor(); case 'detect_meta_framework_issues': return await this.handleDetectMetaFrameworkIssues(); default: throw new Error(`Unknown tool: ${toolName}`); } } async handleRailsTurboAnalysis() { try { const analysis = await this.engine.analyzeRailsTurbo(); let report = `## Rails Turbo/Hotwire Analysis\n\n`; // Turbo Frames report += `### Turbo Frames\n`; report += `- **Count:** ${analysis.turboFrames.count} Turbo Frames\n`; report += `- **Avg Load Time:** ${analysis.turboFrames.avgLoadTime}ms\n`; report += `- **Cache Hit Rate:** ${(analysis.turboFrames.cacheHitRate * 100).toFixed(1)}% cache hit rate\n\n`; // Turbo Streams report += `### Turbo Streams\n`; report += `- **Active Streams:** ${analysis.turboStreams.count}\n`; report += `- **Total Updates:** ${analysis.turboStreams.totalUpdates}\n\n`; // Navigation Timing report += `### Navigation Performance\n`; report += `- **Avg Navigation:** ${analysis.navigationTiming.avgNavigationTime}ms\n`; report += `- **95th Percentile:** ${analysis.navigationTiming.p95NavigationTime}ms\n\n`; // Issues if (analysis.issues && analysis.issues.length > 0) { report += `### Issues Found\n`; analysis.issues.forEach((issue) => { report += `- ⚠️ ${issue.message}\n`; }); } else { report += `✅ No performance issues detected\n`; } return { content: [{ type: 'text', text: report }] }; } catch (error) { throw new Error(`Failed to analyze Rails Turbo: ${error.message}`); } } async handleCSRFSecurityCheck() { try { const check = await this.engine.checkCSRFSecurity(); let report = `## CSRF Security Check\n\n`; report += `**Framework:** ${check.framework}\n\n`; if (check.csrfConfigured && check.issues.length === 0) { report += `✅ **CSRF Protection Properly Configured**\n\n`; report += `### Forms\n`; report += `- Total: ${check.forms.total}\n`; report += `- With CSRF Token: ${check.forms.withToken}\n`; report += `- Without Token: ${check.forms.withoutToken}\n\n`; report += `### AJAX Requests\n`; report += `- Total: ${check.ajaxRequests.total}\n`; report += `- With CSRF Token: ${check.ajaxRequests.withToken}\n`; report += `- Without Token: ${check.ajaxRequests.withoutToken}\n\n`; report += `All forms have CSRF tokens ✅\n`; report += `All AJAX requests include CSRF tokens ✅\n`; } else { report += `🚨 **CSRF Security Issues Detected**\n\n`; if (check.forms.withoutToken > 0) { report += `- **${check.forms.withoutToken} form(s) missing CSRF tokens**\n`; } if (check.ajaxRequests.withoutToken > 0) { report += `- **${check.ajaxRequests.withoutToken} AJAX request(s) missing CSRF tokens**\n`; } report += `\n### Vulnerabilities\n`; check.issues.forEach((issue) => { report += `\n#### ${issue.severity.toUpperCase()}: ${issue.type}\n`; report += `- **Element:** \`${issue.element}\`\n`; report += `- **Location:** ${issue.location}\n`; }); } return { content: [{ type: 'text', text: report }] }; } catch (error) { throw new Error(`Failed to check CSRF security: ${error.message}`); } } async handleStimulusControllers() { try { const result = await this.engine.listStimulusControllers(); let report = `## Stimulus Controllers Analysis\n\n`; report += `${result.total} controllers found\n`; if (result.withIssues > 0) { report += `⚠️ ${result.withIssues} controller(s) with issues\n`; } report += `\n`; result.controllers.forEach((controller) => { report += `### ${controller.name} Controller\n`; report += `- **Identifier:** \`${controller.identifier}\`\n`; if (controller.targets.length > 0) { report += `- **Targets:** ${controller.targets.join(', ')}\n`; } if (controller.actions.length > 0) { report += `- **Actions:** ${controller.actions.join(', ')}\n`; } if (Object.keys(controller.values).length > 0) { report += `- **Values:** ${Object.entries(controller.values).map(([k, v]) => `${k}: ${v}`).join(', ')}\n`; } if (controller.classes.length > 0) { report += `- **Classes:** ${controller.classes.join(', ')}\n`; } if (controller.issues.length > 0) { report += `\n**Issues:**\n`; controller.issues.forEach((issue) => { report += `- ⚠️ ${issue}\n`; }); } report += `\n`; }); return { content: [{ type: 'text', text: report }] }; } catch (error) { throw new Error(`Failed to analyze Stimulus controllers: ${error.message}`); } } async handleMetaFrameworkInfo() { try { const info = await this.engine.getMetaFrameworkInfo(); let report = `## Meta-Framework Information\n\n`; if (!info.detected) { report += `No meta-framework detected. This appears to be a vanilla JavaScript application.\n`; } else { report += `**Framework:** ${info.framework.charAt(0).toUpperCase() + info.framework.slice(1)}\n`; report += `**Version:** ${info.version}\n`; report += `**Build Tool:** ${info.buildTool}\n\n`; report += `### Features\n`; Object.entries(info.features).forEach(([feature, enabled]) => { const icon = enabled ? '✅' : '❌'; const featureName = feature.replace(/([A-Z])/g, ' $1').trim(); report += `- ${icon} ${featureName.charAt(0).toUpperCase() + featureName.slice(1)}\n`; }); report += `\n### Configuration\n`; Object.entries(info.config).forEach(([key, value]) => { const configName = key.replace(/([A-Z])/g, ' $1').trim(); report += `- **${configName.charAt(0).toUpperCase() + configName.slice(1)}:** ${value}\n`; }); } return { content: [{ type: 'text', text: report }] }; } catch (error) { throw new Error(`Failed to get meta-framework info: ${error.message}`); } } async handleRemixLoaderAnalysis() { try { const analysis = await this.engine.analyzeRemixLoaders(); let report = `## Remix Loader Performance Analysis\n\n`; report += `${analysis.totalLoaders} loaders analyzed\n`; report += `**Average Execution Time:** ${analysis.avgExecutionTime}ms\n`; report += `**Total Data Transferred:** ${this.formatSize(analysis.totalDataTransferred)}\n\n`; report += `### Loader Details\n`; analysis.loaders.forEach((loader) => { report += `\n#### ${loader.route}\n`; report += `- **Avg Execution:** ${loader.avgExecutionTime}ms\n`; report += `- **95th Percentile:** ${loader.p95ExecutionTime}ms\n`; report += `- **Avg Data Size:** ${this.formatSize(loader.avgDataSize)}\n`; report += `- **Total Calls:** ${loader.calls}\n`; report += `- **Cache Hit Rate:** ${(loader.cacheHitRate * 100).toFixed(1)}% cache hit rate\n`; }); if (analysis.recommendations && analysis.recommendations.length > 0) { report += `\n### Recommendations\n`; analysis.recommendations.forEach((rec) => { report += `- ${rec}\n`; }); } return { content: [{ type: 'text', text: report }] }; } catch (error) { throw new Error(`Failed to analyze Remix loaders: ${error.message}`); } } async handleAstroIslandsAudit() { try { const audit = await this.engine.auditAstroIslands(); return { content: [{ type: 'text', text: `## Astro Islands Audit\n\nAnalysis complete.` }] }; } catch (error) { throw new Error(`Failed to audit Astro islands: ${error.message}`); } } async handleNuxtPayloadAnalysis() { try { const analysis = await this.engine.analyzeNuxtPayload(); return { content: [{ type: 'text', text: `## Nuxt Payload Analysis\n\nAnalysis complete.` }] }; } catch (error) { throw new Error(`Failed to analyze Nuxt payload: ${error.message}`); } } async handleQwikResumabilityCheck() { try { const check = await this.engine.checkQwikResumability(); return { content: [{ type: 'text', text: `## Qwik Resumability Check\n\nAnalysis complete.` }] }; } catch (error) { throw new Error(`Failed to check Qwik resumability: ${error.message}`); } } async handleViteHMRMonitor() { try { const monitor = await this.engine.monitorViteHMR(); return { content: [{ type: 'text', text: `## Vite HMR Monitor\n\nMonitoring complete.` }] }; } catch (error) { throw new Error(`Failed to monitor Vite HMR: ${error.message}`); } } async handleDetectMetaFrameworkIssues() { try { const issues = await this.engine.detectMetaFrameworkIssues(); return { content: [{ type: 'text', text: `## Meta-Framework Issues\n\nDetection complete.` }] }; } catch (error) { throw new Error(`Failed to detect meta-framework issues: ${error.message}`); } } formatSize(bytes) { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; } } //# sourceMappingURL=meta-framework-handler.js.map