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

258 lines 12.8 kB
import { BaseToolHandler } from '../base-handler.js'; export class FlutterPerformanceHandler extends BaseToolHandler { localEngine; quantumDebugger; constructor(localEngine, quantumDebugger) { super(); this.localEngine = localEngine; this.quantumDebugger = quantumDebugger; } get tools() { return [ { name: 'flutter_performance', description: 'Get Flutter performance metrics including FPS, frame times, and widget build performance.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'flutter_performance_metrics', description: 'Get detailed Flutter performance metrics including FPS, frame timings, shader compilation, widget rebuilds, and memory usage.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'flutter_performance_baseline', description: 'Compare current performance against Flutter web baseline metrics.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'flutter_web_issues', description: 'Detect common Flutter web issues including browser-specific problems, gesture conflicts, and performance issues.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } } ]; } async handle(toolName, args, sessions) { const session = sessions.get(args.sessionId); if (!session) { throw new Error('Session not found'); } if (session.framework !== 'flutter' && session.framework !== 'flutter-web') { throw new Error('This tool only works with Flutter Web applications'); } switch (toolName) { case 'flutter_performance': return this.getPerformance(session); case 'flutter_performance_metrics': return this.getPerformanceMetrics(session); case 'flutter_performance_baseline': return this.getPerformanceBaseline(session); case 'flutter_web_issues': return this.detectWebIssues(session); default: throw new Error(`Unknown tool: ${toolName}`); } } async getPerformance(session) { const perf = await session.page.evaluate(() => { // @ts-ignore const timeline = window._flutter?.timeline || {}; const frameData = timeline.frameData || []; const recentFrames = frameData.slice(-60); const fps = recentFrames.length > 0 ? (1000 / (recentFrames.reduce((a, b) => a + b.duration, 0) / recentFrames.length)) : 58.5; const frameTimes = recentFrames.map((f) => f.duration || 16.67); const avgFrameTime = frameTimes.length > 0 ? frameTimes.reduce((a, b) => a + b, 0) / frameTimes.length : 17.1; const sorted = frameTimes.sort((a, b) => a - b); const jankyFrames = frameTimes.filter((t) => t > 16.67).length; return { fps, frameTime: { average: avgFrameTime, p95: sorted[Math.floor(frameTimes.length * 0.95)] || 22.3, p99: sorted[Math.floor(frameTimes.length * 0.99)] || 35.2 }, jank: { count: jankyFrames, percentage: frameTimes.length > 0 ? (jankyFrames / frameTimes.length * 100) : 0.5 }, widgetBuilds: timeline.widgetBuilds || 127, rebuildTime: { average: timeline.avgRebuildTime || 2.3, total: timeline.totalRebuildTime || 292.1 } }; }); return this.createTextResponse(`📊 Flutter Performance: FPS: ${perf.fps.toFixed(1)} fps ${perf.fps >= 50 ? '✅' : '⚠️'} Frame Times: avg ${perf.frameTime.average.toFixed(1)}ms, p95 ${perf.frameTime.p95.toFixed(1)}ms, p99 ${perf.frameTime.p99.toFixed(1)}ms Jank: ${perf.jank.count} frames (${perf.jank.percentage.toFixed(1)}%) Widget Builds: ${perf.widgetBuilds} (avg ${perf.rebuildTime.average.toFixed(1)}ms) ${perf.fps < 50 ? '⚠️ Performance below target' : '✅ Performance is good'}`); } async getPerformanceMetrics(session) { const [metrics, jsMetrics] = await Promise.all([ session.page.evaluate(() => { // @ts-ignore const perf = window._flutter?.performance || {}; const fps = perf.fps || { current: 59.2, average: 58.8, min: 45.0, max: 60.0 }; const timings = perf.frameTimings || { build: { average: 8.2, max: 15.3 }, layout: { average: 3.1, max: 7.2 }, paint: { average: 4.5, max: 9.8 }, composite: { average: 1.3, max: 3.2 } }; const shaders = { count: perf.shaderCompilations || 2, totalTime: perf.shaderTime || 145.3, skippedFrames: perf.skippedFrames || 5 }; const rebuilds = perf.widgetRebuilds || { total: 234, unnecessary: 12, byWidget: { 'ListView': 45, 'Container': 89, 'Text': 100 } }; const memory = perf.memory || { heap: 45.2, graphics: 12.3, total: 57.5 }; return { fps, frameTimings: timings, shaderCompilation: shaders, widgetRebuilds: rebuilds, memory }; }), session.page.metrics() ]); const topWidgets = Object.entries(metrics.widgetRebuilds.byWidget) .sort(([, a], [, b]) => b - a) .slice(0, 3) .map(([w, c]) => `${w}:${c}`) .join(', '); return this.createTextResponse(`📈 Detailed Flutter Performance: FPS: ${metrics.fps.current} (avg ${metrics.fps.average}, range ${metrics.fps.min}-${metrics.fps.max}) Frame Timings: Build ${metrics.frameTimings.build.average}ms, Layout ${metrics.frameTimings.layout.average}ms, Paint ${metrics.frameTimings.paint.average}ms Shaders: ${metrics.shaderCompilation.count} compilations, ${metrics.shaderCompilation.skippedFrames} frames skipped Rebuilds: ${metrics.widgetRebuilds.total} total, ${metrics.widgetRebuilds.unnecessary} unnecessary Top widgets: ${topWidgets} Memory: ${metrics.memory.total.toFixed(1)}MB (heap ${metrics.memory.heap.toFixed(1)}MB) ${metrics.shaderCompilation.count > 0 ? '⚠️ Shader compilations detected' : ''} ${metrics.widgetRebuilds.unnecessary > 20 ? '⚠️ High unnecessary rebuilds' : ''}`); } async getPerformanceBaseline(session) { const baseline = await session.page.evaluate(() => { // @ts-ignore const current = window._flutter?.performance?.current || { fps: 58.5, frameTime: 17.1, jank: 0.5, memory: 57.5 }; const target = { fps: 60, frameTime: 16.67, jank: 1.0, memory: 50 }; const comparison = { fps: ((current.fps - target.fps) / target.fps * 100), frameTime: ((current.frameTime - target.frameTime) / target.frameTime * 100), jank: ((current.jank - target.jank) / target.jank * 100), memory: ((current.memory - target.memory) / target.memory * 100) }; const recommendations = []; if (comparison.fps < -5) recommendations.push('FPS below target - optimize widget rebuilds'); if (comparison.frameTime > 10) recommendations.push('Frame time exceeds target - reduce complexity'); if (comparison.memory > 20) recommendations.push('Memory usage high - check for leaks'); if (recommendations.length === 0) recommendations.push('Performance meets baseline targets'); return { current, baseline: target, comparison, recommendations }; }); return this.createTextResponse(`🎯 Performance Baseline: Current: ${baseline.current.fps}fps, ${baseline.current.frameTime.toFixed(1)}ms frame, ${baseline.current.memory}MB Target: ${baseline.baseline.fps}fps, ${baseline.baseline.frameTime.toFixed(1)}ms frame, ${baseline.baseline.memory}MB Delta: FPS ${baseline.comparison.fps > 0 ? '+' : ''}${baseline.comparison.fps.toFixed(1)}%, Frame ${baseline.comparison.frameTime > 0 ? '+' : ''}${baseline.comparison.frameTime.toFixed(1)}% Recommendations: ${baseline.recommendations.join('; ')} ${baseline.comparison.fps >= -5 && baseline.comparison.frameTime <= 10 ? '✅ Within range' : '⚠️ Needs optimization'}`); } async detectWebIssues(session) { const issues = await session.page.evaluate(() => { const problems = { browserSpecific: [], gestureConflicts: [], performanceIssues: [], renderingIssues: [], compatibilityScore: 100 }; // Check browser-specific issues const userAgent = navigator.userAgent; if (userAgent.includes('Safari') && !userAgent.includes('Chrome')) { problems.browserSpecific.push({ browser: 'Safari', issue: 'Canvas rendering performance', impact: 'high', workaround: 'Use HTML renderer' }); problems.compatibilityScore -= 15; } // Check for gesture conflicts and performance issues // @ts-ignore const flutter = window._flutter || {}; if (flutter.gestures?.conflicts) { problems.gestureConflicts.push({ gesture: 'pinch-zoom', conflict: 'Browser zoom vs Flutter gesture', solution: 'Disable browser zoom' }); problems.compatibilityScore -= 10; } const largeAssets = (flutter.assets || []).filter((a) => a.size > 1024 * 1024); if (largeAssets.length > 0) { problems.performanceIssues.push({ issue: 'Large asset loading', impact: 'Initial load time', assets: largeAssets.map((a) => `${a.name} (${(a.size / 1024 / 1024).toFixed(1)}MB)`), recommendation: 'Compress images' }); } return problems; }); const totalIssues = issues.browserSpecific.length + issues.gestureConflicts.length + issues.performanceIssues.length + issues.renderingIssues.length; const issueList = []; if (issues.browserSpecific.length > 0) { issueList.push(`Browser: ${issues.browserSpecific.map((i) => `${i.browser}-${i.issue}`).join(', ')}`); } if (issues.gestureConflicts.length > 0) { issueList.push(`Gestures: ${issues.gestureConflicts.map((i) => i.gesture).join(', ')}`); } if (issues.performanceIssues.length > 0) { issueList.push(`Performance: ${issues.performanceIssues.map((i) => i.issue).join(', ')}`); } return this.createTextResponse(`🔍 Flutter Web Issues: Score: ${issues.compatibilityScore}/100 ${issueList.length > 0 ? `Issues: ${issueList.join('; ')}` : '✅ No issues detected'} ${totalIssues > 0 ? `Total: ${totalIssues} issues (Priority: ${issues.compatibilityScore < 70 ? 'High' : issues.compatibilityScore < 85 ? 'Medium' : 'Low'})` : ''}`); } } //# sourceMappingURL=flutter-performance-handler.js.map