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
JavaScript
/**
* 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