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

254 lines • 10.8 kB
/** * Live Svelte Debugger - Specialized tool for Phoenix LiveView + Svelte debugging * * Handles the unique challenges of debugging live_svelte components */ export class LiveSvelteDebugger { page = null; async attachToPage(page) { this.page = page; // Inject debugging helpers await page.evaluate(() => { // Create global debug helper window.__liveSvelteDebug = { components: new Map(), hooks: new Map(), events: [], // Track Svelte component lifecycle trackComponent: function (name, component) { this.components.set(name, { component, props: component.$$.props, state: component.$$.ctx, timestamp: Date.now() }); }, // Track LiveView hooks trackHook: function (el, hook) { const hookName = el.getAttribute('phx-hook'); this.hooks.set(hookName, { element: el, hook, mounted: hook.mounted ? true : false, updated: hook.updated ? true : false }); }, // Track events between LiveView and Svelte trackEvent: function (type, data) { this.events.push({ type, data, timestamp: Date.now(), stack: new Error().stack }); } }; // Override console methods to capture errors const originalError = console.error; const originalWarn = console.warn; const debugErrors = []; console.error = function (...args) { debugErrors.push({ type: 'error', message: args.join(' '), timestamp: Date.now(), stack: new Error().stack }); originalError.apply(console, args); }; console.warn = function (...args) { debugErrors.push({ type: 'warning', message: args.join(' '), timestamp: Date.now(), stack: new Error().stack }); originalWarn.apply(console, args); }; window.__liveSvelteDebug.errors = debugErrors; }); } async getDebugInfo() { if (!this.page) { throw new Error('No page attached'); } const debugData = await this.page.evaluate(() => { const debug = window.__liveSvelteDebug || {}; // Get LiveView state const liveViewState = (() => { try { const liveSocket = window.liveSocket; if (!liveSocket) return null; // Get all LiveView components const views = []; const viewEls = document.querySelectorAll('[data-phx-view]'); viewEls.forEach((el) => { const viewId = el.getAttribute('data-phx-view'); const session = el.getAttribute('data-phx-session'); const main = el.getAttribute('data-phx-main') === 'true'; views.push({ id: viewId, session, main, element: el.tagName, hooks: Array.from(el.querySelectorAll('[phx-hook]')).map((hookEl) => ({ hook: hookEl.getAttribute('phx-hook'), element: hookEl.tagName })) }); }); return { connected: liveSocket.isConnected(), views, transport: liveSocket.transport?.name || 'unknown' }; } catch (e) { return { error: e instanceof Error ? e.message : String(e) }; } })(); // Get Svelte components const svelteComponents = (() => { const components = []; // From our debug tracking if (debug.components) { debug.components.forEach((data, name) => { components.push({ name, props: data.props, state: data.state, timestamp: data.timestamp }); }); } // Also check for live_svelte containers document.querySelectorAll('[phx-hook="LiveSvelte"]').forEach((el) => { const componentName = el.getAttribute('data-name') || 'Unknown'; const props = el.getAttribute('data-props'); components.push({ name: componentName, element: el.tagName, props: props ? JSON.parse(props) : {}, container: true }); }); return components; })(); // Get hooks info const hooks = (() => { const hooksList = []; if (debug.hooks) { debug.hooks.forEach((data, name) => { hooksList.push({ name, mounted: data.mounted, updated: data.updated, element: data.element?.tagName }); }); } return hooksList; })(); // Get props passed from LiveView to Svelte const props = (() => { const propsData = {}; document.querySelectorAll('[data-props]').forEach((el) => { const name = el.getAttribute('data-name') || el.id || 'unknown'; const props = el.getAttribute('data-props'); if (props) { try { propsData[name] = JSON.parse(props); } catch (e) { propsData[name] = { error: 'Failed to parse props', raw: props }; } } }); return propsData; })(); // Get tracked events const events = debug.events || []; // Get console errors/warnings const consoleErrors = debug.errors || []; return { liveViewState, svelteComponents, hooks, props, events, consoleErrors }; }); return debugData; } async debugLiveSvelteIssue() { const info = await this.getDebugInfo(); const issues = []; const suggestions = []; let mainIssue = 'No specific issue detected'; const details = {}; // Check for LiveView connection issues if (!info.liveViewState?.connected) { mainIssue = 'LiveView is not connected'; issues.push('LiveView WebSocket connection is down'); suggestions.push('Check if Phoenix server is running'); suggestions.push('Verify WebSocket endpoint configuration'); suggestions.push('Check browser console for connection errors'); } // Check for Svelte component issues if (info.svelteComponents.length === 0) { issues.push('No Svelte components detected'); suggestions.push('Ensure live_svelte is properly installed'); suggestions.push('Check if LiveView is rendering the live_component correctly'); suggestions.push('Verify Svelte component files are being compiled'); } // Check for prop passing issues const emptyProps = Object.entries(info.props).filter(([_, props]) => Object.keys(props).length === 0); if (emptyProps.length > 0) { issues.push(`${emptyProps.length} components have no props`); suggestions.push('Verify props are being passed from LiveView: assigns |> Map.take([:your_prop])'); suggestions.push('Check live_svelte component call syntax'); } // Check for console errors if (info.consoleErrors.length > 0) { mainIssue = 'JavaScript errors detected'; issues.push(`${info.consoleErrors.length} console errors found`); details.errors = info.consoleErrors; // Analyze common error patterns info.consoleErrors.forEach(error => { if (error.message.includes('live is not defined')) { suggestions.push('The "live" prop might not be passed to Svelte component'); suggestions.push('Ensure LiveView is passing the socket binding'); } if (error.message.includes('Cannot read properties of undefined')) { suggestions.push('Check if all required props are being passed'); suggestions.push('Add prop validation in Svelte component'); } }); } // Check for hook issues const unmountedHooks = info.hooks.filter(h => !h.mounted); if (unmountedHooks.length > 0) { issues.push(`${unmountedHooks.length} hooks failed to mount`); suggestions.push('Check if hooks are registered in app.js'); suggestions.push('Verify hook implementation has mounted() method'); } if (issues.length === 0) { mainIssue = 'Components detected but may have internal issues'; suggestions.push('Check Svelte component internal logic'); suggestions.push('Add console.log statements to trace prop flow'); suggestions.push('Verify event handlers are properly bound'); } return { issue: mainIssue, details: { ...details, allIssues: issues, debugInfo: info }, suggestions }; } } //# sourceMappingURL=live-svelte-debugger.js.map