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

165 lines โ€ข 6.89 kB
/** * Flutter Smart Navigation * Analyzes page with overlay, extracts data, then navigates without overlay */ import { FlutterComprehensiveDetector } from './flutter-comprehensive-detector.js'; import { FlutterNavigationHelper } from './flutter-navigation-helper.js'; import { FlutterClickHandler } from './flutter-click-handler.js'; export class FlutterSmartNavigation { /** * Analyze page, find target, remove overlay, then click */ static async analyzeAndNavigate(page, targetText, options = {}) { try { // console.log(`๐Ÿ” Analyzing page to find "${targetText}"...`); // Step 1: Analyze with overlay const elements = await FlutterComprehensiveDetector.detectAllElements(page); // console.log(`โœ… Found ${elements.length} elements`); // Step 2: Find target element const target = this.findTargetElement(elements, targetText); if (!target) { return { success: false, error: `Could not find element matching "${targetText}"` }; } // console.log(`๐ŸŽฏ Found target: "${target.label}" at (${target.x}, ${target.y}) with ${Math.round(target.confidence * 100)}% confidence`); // Step 3: Take screenshot with overlay if requested if (options.screenshotPath) { await page.screenshot({ path: `${options.screenshotPath}-with-overlay.png` }); // console.log(`๐Ÿ“ธ Screenshot with overlay saved`); } // Step 4: Wait a moment to ensure overlay is fully rendered await page.waitForTimeout(1000); // Step 5: Remove overlay // console.log('๐Ÿงน Removing visual overlay...'); await FlutterNavigationHelper.removeVisualOverlays(page); // Step 6: Take screenshot without overlay if requested if (options.screenshotPath) { await page.screenshot({ path: `${options.screenshotPath}-without-overlay.png` }); // console.log(`๐Ÿ“ธ Screenshot without overlay saved`); } // Step 7: Capture initial state for navigation detection const initialUrl = page.url(); const initialContent = await page.evaluate(() => document.body.textContent?.trim() || ''); // Step 8: Click the target // console.log(`๐Ÿ–ฑ๏ธ Clicking "${target.label}" at (${target.x}, ${target.y})...`); const clickSuccess = await FlutterClickHandler.performClick(page, { x: target.x, y: target.y, verbose: true }); if (!clickSuccess) { return { success: false, target, error: 'Click failed' }; } // Step 9: Check for navigation if requested let navigationOccurred = false; if (options.waitForNavigation) { await page.waitForTimeout(3000); const navigationChanges = await FlutterNavigationHelper.checkForNavigationChanges(page, initialUrl, initialContent); navigationOccurred = navigationChanges.urlChanged || navigationChanges.contentChanged; if (options.screenshotPath) { await page.screenshot({ path: `${options.screenshotPath}-after-click.png` }); // console.log(`๐Ÿ“ธ Screenshot after click saved`); } } return { success: true, target, navigationOccurred }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : String(error) }; } } /** * Find target element from detected elements */ static findTargetElement(elements, targetText) { const searchLower = targetText.toLowerCase(); // First try exact match let found = elements.find(el => el.label.toLowerCase() === searchLower && el.clickable); // Then try contains match if (!found) { found = elements.find(el => el.label.toLowerCase().includes(searchLower) && el.clickable); } // Then try fuzzy match if (!found) { found = elements.find(el => { const label = el.label.toLowerCase(); const words = searchLower.split(' '); return words.every(word => label.includes(word)) && el.clickable; }); } if (!found) { return null; } return { label: found.label, x: Math.round(found.bounds.x + found.bounds.width / 2), y: Math.round(found.bounds.y + found.bounds.height / 2), confidence: found.confidence, element: found }; } /** * Analyze page and extract all clickable targets */ static async analyzeClickableTargets(page) { const elements = await FlutterComprehensiveDetector.detectAllElements(page); const targets = elements .filter(el => el.clickable && el.label) .map(el => ({ label: el.label, x: Math.round(el.bounds.x + el.bounds.width / 2), y: Math.round(el.bounds.y + el.bounds.height / 2), confidence: el.confidence, element: el })) .sort((a, b) => b.confidence - a.confidence); // Remove overlay after analysis await FlutterNavigationHelper.removeVisualOverlays(page); return targets; } /** * Smart form flow navigation */ static async navigateFormFlow(page, steps) { let completedSteps = 0; for (const step of steps) { // console.log(`\n๐Ÿ“‹ Step ${completedSteps + 1}: ${step.action} "${step.target}"`); if (step.action === 'click') { const result = await this.analyzeAndNavigate(page, step.target, { waitForNavigation: true }); if (!result.success) { return { success: false, completedSteps, error: result.error }; } } else { // For type/select actions, we need different handling // console.log(`โš ๏ธ ${step.action} action not yet implemented`); } completedSteps++; // Wait between steps await page.waitForTimeout(2000); } return { success: true, completedSteps }; } } //# sourceMappingURL=flutter-smart-navigation.js.map