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

274 lines • 11.9 kB
import { FlutterDebugEngine } from '../flutter-debug-engine.js'; import { FlutterDebugEngineEnhanced } from '../flutter-debug-engine-enhanced-modular.js'; import { NextJSDebugEngine } from '../nextjs-debug-engine.js'; import { NextJSDebugEngineEnhanced } from '../nextjs-debug-engine-enhanced-modular.js'; import { ServerFrameworkDebugEngine } from '../server-framework-debug-engine.js'; import { MetaFrameworkDebugEngine } from '../meta-framework-debug-engine-modular.js'; import { StateCapture } from './state-capture.js'; export class FrameworkDetector { reactStateEngine; jsExecutionEngine; stateCapture; page; metaFrameworkEngine; nextjsEngine; nextjsEnhancedEngine; serverFrameworkEngine; flutterEngine; flutterEnhancedEngine; constructor(reactStateEngine, jsExecutionEngine, stateCapture) { this.reactStateEngine = reactStateEngine; this.jsExecutionEngine = jsExecutionEngine; this.stateCapture = stateCapture; } /** * Detect the framework used by the current page and initialize appropriate engines */ async detectFramework(page) { this.page = page; // Check for meta-frameworks first (they might also be React/Vue/etc) this.metaFrameworkEngine = new MetaFrameworkDebugEngine(); await this.metaFrameworkEngine.attachToPage(page); const metaFrameworkInfo = await this.metaFrameworkEngine.getMetaFrameworkInfo(); if (metaFrameworkInfo?.framework) { return { framework: metaFrameworkInfo.framework, engines: { metaFrameworkEngine: this.metaFrameworkEngine } }; } // Check for Next.js (if not detected by meta-framework engine) this.nextjsEngine = new NextJSDebugEngine(); const isNextJS = await this.nextjsEngine.detectNextJS(page); if (isNextJS) { await this.nextjsEngine.attachToPage(page); // Also initialize enhanced engine this.nextjsEnhancedEngine = new NextJSDebugEngineEnhanced(); await this.nextjsEnhancedEngine.attachToPage(page); return { framework: 'nextjs', engines: { nextjsEngine: this.nextjsEngine, nextjsEnhancedEngine: this.nextjsEnhancedEngine } }; } // Check for server frameworks this.serverFrameworkEngine = new ServerFrameworkDebugEngine(); const serverFramework = await this.serverFrameworkEngine.detectServerFramework(page); if (serverFramework) { await this.serverFrameworkEngine.attachToPage(page); return { framework: serverFramework, engines: { serverFrameworkEngine: this.serverFrameworkEngine } }; } // Check for Flutter Web this.flutterEngine = new FlutterDebugEngine(); const isFlutter = await this.flutterEngine.detectFlutterWeb(page); if (isFlutter) { // Try to connect to Flutter DevTools const port = await this.flutterEngine.findDebugPort(page); if (port) { await this.flutterEngine.connect(port); } // Also initialize enhanced engine for comprehensive Flutter debugging this.flutterEnhancedEngine = new FlutterDebugEngineEnhanced(); await this.flutterEnhancedEngine.attachToPage(page); // Update StateCapture with Flutter engine const updatedStateCapture = new StateCapture(this.reactStateEngine, this.jsExecutionEngine, this.flutterEnhancedEngine); await updatedStateCapture.attachToPage(page); return { framework: 'flutter-web', engines: { flutterEngine: this.flutterEngine, flutterEnhancedEngine: this.flutterEnhancedEngine } }; } // Check for Elixir/Phoenix applications (comprehensive detection) const elixirDetection = await this.detectElixirFramework(page); if (elixirDetection.framework) { return { framework: elixirDetection.framework, engines: elixirDetection.engines || {} }; } // Check for React const reactComponents = await this.findReactComponents(); if (reactComponents.length > 0) { return { framework: 'react', engines: {} }; } // Check for Vue const hasVue = await page.evaluate(() => { return !!window.Vue || document.querySelector('[data-v-]'); }); if (hasVue) { return { framework: 'vue', engines: {} }; } // Check for Angular const hasAngular = await page.evaluate(() => { return !!window.ng || document.querySelector('[ng-version]'); }); if (hasAngular) { return { framework: 'angular', engines: {} }; } // Check for Svelte const hasSvelte = await page.evaluate(() => { return document.querySelector('[data-svelte]') !== null; }); if (hasSvelte) { return { framework: 'svelte', engines: {} }; } return { framework: 'unknown', engines: {} }; } /** * Get initialized engines for access by LocalDebugEngine */ getEngines() { return { metaFrameworkEngine: this.metaFrameworkEngine, nextjsEngine: this.nextjsEngine, nextjsEnhancedEngine: this.nextjsEnhancedEngine, serverFrameworkEngine: this.serverFrameworkEngine, flutterEngine: this.flutterEngine, flutterEnhancedEngine: this.flutterEnhancedEngine }; } /** * Helper method to find Phoenix LiveView state */ async findPhoenixLiveViewState() { if (!this.page) { throw new Error('No page attached'); } return await this.stateCapture.findPhoenixLiveViewState(); } /** * Helper method to find React components */ async findReactComponents() { if (!this.page) { throw new Error('No page attached'); } return await this.stateCapture.findReactComponents(); } /** * Comprehensive Elixir framework detection * Detects Phoenix LiveView, traditional Phoenix, pure Elixir, and Nerves */ async detectElixirFramework(page) { try { // Check for Phoenix LiveView (highest priority) const hasLiveView = await page.evaluate(() => { // Look for LiveView JavaScript return !!(window.liveSocket || window.Phoenix?.LiveView || document.querySelector('[phx-hook]') || document.querySelector('[data-phx-link]') || document.querySelector('[phx-click]') || document.querySelector('[phx-submit]') || document.querySelector('div[data-phx-main]') || document.querySelector('script[src*="phoenix_live_view"]')); }); if (hasLiveView) { return { framework: 'phoenix' }; // Phoenix LiveView } // Check for traditional Phoenix (without LiveView) const hasPhoenix = await page.evaluate(() => { return !!(window.Phoenix || document.querySelector('script[src*="phoenix"]') || document.querySelector('meta[name="csrf-token"]') || document.querySelector('input[name="_csrf_token"]') || // Check for Phoenix channel syntax in script tags document.documentElement.innerHTML.includes('channel.join()') || document.documentElement.innerHTML.includes('socket.connect()')); }); if (hasPhoenix) { return { framework: 'phoenix-traditional' }; } // Check for pure Elixir by examining the URL and response headers const response = await page.goto(page.url(), { waitUntil: 'domcontentloaded' }); const headers = response?.headers() || {}; // Look for Elixir/Erlang server signatures const serverHeader = headers['server'] || ''; const hasElixirSignature = serverHeader.includes('Cowboy') || serverHeader.includes('Plug') || serverHeader.includes('Phoenix') || headers['x-powered-by']?.includes('Elixir') || headers['x-frame-options'] === 'SAMEORIGIN'; // Common Phoenix default // Check for Nerves/embedded Elixir indicators const userAgent = headers['user-agent'] || ''; const hasNervesIndicators = await page.evaluate(() => { return !!( // Nerves-specific meta tags or content document.querySelector('meta[name="nerves"]') || document.querySelector('meta[name="embedded-elixir"]') || // GPIO or hardware control interfaces document.documentElement.innerHTML.includes('GPIO') || document.documentElement.innerHTML.includes('hardware') || document.documentElement.innerHTML.includes('sensor') || // Embedded system patterns window.location.hostname.match(/^\d+\.\d+\.\d+\.\d+$/) || // IP address window.location.hostname.includes('.local') // mDNS ); }); if (hasNervesIndicators || userAgent.includes('Nerves')) { return { framework: 'nerves' }; } // Check for pure Elixir API endpoints or Elixir-specific patterns const hasPureElixir = await page.evaluate(() => { // Look for Elixir/OTP patterns in JSON responses or error messages const bodyText = document.body?.textContent || ''; return !!(bodyText.includes('GenServer') || bodyText.includes('Supervisor') || bodyText.includes('Process') || bodyText.includes('OTP') || // Check for Elixir-style error messages bodyText.includes('** (') || bodyText.includes('no function clause matching') || // Phoenix API patterns (but not full Phoenix) document.querySelector('script[type="application/json"]')); }); if (hasElixirSignature || hasPureElixir) { // Determine if it's API-only Elixir or has some web interface const hasWebInterface = await page.evaluate(() => { return (document.querySelector('html')?.innerHTML.length || 0) > 100; }); if (hasWebInterface) { return { framework: 'elixir' }; // Pure Elixir with web interface } else { return { framework: 'elixir' }; // Pure Elixir API } } } catch (error) { console.warn('Failed to detect Elixir framework:', error); } return { framework: null }; } /** * Legacy method for compatibility - engines are attached during detection */ async attachFrameworkEngines(page) { // This is called after framework detection in detectFramework // Engines are already attached there this.page = page; } } //# sourceMappingURL=framework-detector.js.map