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