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