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

297 lines 14.3 kB
import { BaseToolHandler } from '../base-handler.js'; import { SessionDebugFixes } from '../session-debug-fixes.js'; import { SessionStabilityManager } from '../session-stability-manager.js'; import * as fmt from './nextjs-formatter-utils.js'; /** * Handler for Next.js core information tools (page info, config, app router) */ export class NextJSCoreInfoHandler extends BaseToolHandler { nextjsEngine; constructor(nextjsEngine) { super(); this.nextjsEngine = nextjsEngine; } tools = [ { name: 'nextjs_page_info', description: 'Get information about current Next.js page including rendering type (SSR/SSG/ISR/RSC) and data fetching methods.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'nextjs_config', description: 'Get comprehensive Next.js configuration including version, router type, build mode, and experimental features.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } }, { name: 'nextjs_app_router_info', description: 'Get App Router information including current route, params, search params, layout nesting, parallel routes, and intercepted routes.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Debug session ID' } }, required: ['sessionId'] } } ]; async handle(toolName, args, sessions) { let session; try { // Enhanced session validation with detailed debugging SessionDebugFixes.validateSessionStorage(args.sessionId, sessions); session = this.getSession(args.sessionId, sessions); // P0 FIX: Enhanced session health validation with auto-recovery const healthResult = await SessionStabilityManager.validateSessionWithRecovery(session, sessions, { timeoutMs: 5000, maxRetries: 2 }); if (!healthResult.isHealthy) { return SessionStabilityManager.createRecoveryErrorResponse(args.sessionId, new Error('Session validation failed after recovery attempts'), true); } // Use recovered session if recovery occurred session = healthResult.session; } catch (error) { return SessionDebugFixes.createDetailedErrorResponse(error, 'NextJS Core Info', args.sessionId); } // Framework validation should throw directly (not wrapped in detailed response) this.validateNextJSSession(session); try { switch (toolName) { case 'nextjs_page_info': return this.getPageInfo(args, session); case 'nextjs_config': return this.getConfig(args, session); case 'nextjs_app_router_info': return this.getAppRouterInfo(args, session); default: throw new Error(`Unknown Next.js core info tool: ${toolName}`); } } catch (error) { // Only wrap handler execution errors, not validation errors return SessionDebugFixes.createDetailedErrorResponse(error, 'NextJS Core Info', args.sessionId); } } validateNextJSSession(session) { const { framework, isNextJS } = session; if (framework !== 'nextjs' && framework !== 'next' && !(framework === 'react' && isNextJS)) { throw new Error('This tool only works with Next.js applications'); } } async getPageInfo(args, session) { try { // Use safe page info extraction const safeInfo = await SessionDebugFixes.safePageInfoExtraction(session.page); const info = await this.nextjsEngine.getPageInfo(session); // Merge safe extraction with engine results const mergedInfo = { path: safeInfo.pathname || info?.path || 'Unknown', renderingType: info?.renderingType || 'Unknown', url: safeInfo.url || session.url || 'Unknown', title: safeInfo.title || 'Unknown', ...info, ...safeInfo }; const sections = [ '📄 **Next.js Page Information**', '', fmt.formatKeyValue('Path', mergedInfo.path), fmt.formatKeyValue('URL', mergedInfo.url), fmt.formatKeyValue('Title', mergedInfo.title), fmt.formatKeyValue('Rendering Type', `${mergedInfo.renderingType} (${fmt.RENDERING_DESCRIPTIONS[mergedInfo.renderingType] || 'Unknown'})`), '' ]; // Data fetching if (info.dataFetchingMethods?.length > 0) { sections.push(...fmt.formatSection('**Data Fetching Methods:**', fmt.formatList(info.dataFetchingMethods))); } else if (info.dataFetching?.length > 0) { // Handle alternate property name sections.push(...fmt.formatSection('**Data Fetching:**', fmt.formatList(info.dataFetching))); } // Router type for App Router if (info.isAppRouter) { sections.push('**Router:** App Router'); } // Server component indicator if (info.isServerComponent) { sections.push('**Component Type:** Server Component'); } // Has layout if (info.hasLayout !== undefined) { sections.push(fmt.formatKeyValue('Has Layout', info.hasLayout ? 'Yes' : 'No')); } // Metadata and performance sections.push(...fmt.formatMetadata(info.metadata)); sections.push(...fmt.formatPerformance(info.performance)); // Recommendations const recommendations = []; if (info.renderingType === 'CSR' && !info.hasLayout) { recommendations.push('Consider using SSG or SSR for better SEO and initial load performance'); } if (info.performance?.lcp > 2500) { recommendations.push('LCP is above 2.5s threshold. Optimize largest content paint'); } if (!info.metadata?.description) { recommendations.push('Add meta description for better SEO'); } sections.push(...fmt.formatRecommendations(recommendations)); return this.createTextResponse(sections.join('\n').trim()); } catch (error) { throw new Error(`Failed to get page information: ${error instanceof Error ? error.message : String(error)}`); } } async getConfig(args, session) { try { const config = await this.nextjsEngine.getConfig(); if (!config) { return this.createTextResponse('❌ **Next.js Configuration**\n\nCould not retrieve Next.js configuration.'); } const sections = ['🔧 **Next.js Configuration**', '']; // Basic info if (config.version) sections.push(fmt.formatKeyValue('Version', config.version)); sections.push(fmt.formatKeyValue('Router Type', config.rendering), fmt.formatKeyValue('Build Mode', config.buildMode || 'Unknown'), ''); // Configuration details const configItems = []; // React Strict Mode - show enabled/disabled if (config.config?.reactStrictMode) { configItems.push('React Strict Mode: Enabled'); } else { configItems.push('React Strict Mode: Disabled'); } // Other config items configItems.push(...fmt.formatConfigItems(config.config, [ ['poweredByHeader', 'X-Powered-By header', true], ['compress', 'Compression'], ['swcMinify', 'SWC Minification'] ])); // Experimental features if (config.config?.experimental) { configItems.push(...fmt.formatConfigItems(config.config.experimental, [ ['appDir', 'App Directory: Enabled (experimental)'], ['serverActions', 'Server Actions'], ['ppr', 'Partial Prerendering'] ])); } if (configItems.length > 0) { sections.push(...fmt.formatSection('**Configuration:**', fmt.formatList(configItems))); } // Additional configs this.addImageConfig(sections, config.config?.images); sections.push(...fmt.formatConfigItems(config.config, [ ['basePath', '- Base Path'], ['assetPrefix', '- Asset Prefix'] ])); if (config.config?.i18n) { const locales = config.config.i18n.locales?.join(', ') || config.config.i18n.defaultLocale; sections.push(`- i18n: Enabled (${locales})`); } // Count configurations sections.push(...fmt.formatList(fmt.formatCountItems(config.config, [ ['redirects', 'Redirects'], ['rewrites', 'Rewrites'], ['headers', 'Custom Headers'] ]))); // Note: webpack configuration detection not available in enhanced engine // Recommendations const recommendations = this.getConfigRecommendations(config); sections.push(...fmt.formatRecommendations(recommendations)); return this.createTextResponse(sections.join('\n').trim()); } catch (error) { throw new Error(`Failed to get Next.js config: ${error instanceof Error ? error.message : String(error)}`); } } addImageConfig(sections, images) { if (!images) return; sections.push('- Image Optimization:'); if (images.domains?.length > 0) sections.push(` - Allowed domains: ${images.domains.join(', ')}`); if (images.deviceSizes) sections.push(` - Device sizes: ${images.deviceSizes.join(', ')}`); if (images.imageSizes) sections.push(` - Image sizes: ${images.imageSizes.join(', ')}`); } getConfigRecommendations(config) { const recommendations = []; if (!config.config?.reactStrictMode && config.buildMode === 'development') { recommendations.push('Enable React Strict Mode for better development experience'); } if (config.version) { const versionParts = config.version.split('.').map(Number); if (versionParts[0] < 13) { recommendations.push('Consider upgrading to Next.js 13+ for App Router and improved performance'); } } if (!config.config?.images?.domains) { recommendations.push('Configure image domains for optimized external images'); } return recommendations; } async getAppRouterInfo(args, session) { try { const info = await this.nextjsEngine.getAppRouterInfo(); if (!info) { return this.createTextResponse('🚦 **Next.js App Router Information**\n\n' + '❌ This application is using Pages Router, not App Router.\n\n' + 'App Router is available in Next.js 13.4+ and provides:\n' + '- React Server Components\n- Nested layouts\n- Improved data fetching\n' + '- Built-in loading and error states\n\n' + 'To migrate to App Router, create an `app` directory in your project root.'); } const sections = [ '🚦 **Next.js App Router Information**', '', fmt.formatKeyValue('Current Route', info.currentRoute || 'Unknown'), '' ]; // Route params and search params sections.push(...fmt.formatParams(info.params, 'Route Parameters')); sections.push(...fmt.formatParams(info.searchParams, 'Search Parameters')); // Additional info sections.push(fmt.formatKeyValue('Layout Nesting', `${info.layoutNesting} level${info.layoutNesting !== 1 ? 's' : ''}`)); const routeInfo = [ [info.parallelRoutes, 'Parallel Routes'], [info.routeGroups, 'Route Groups'], [info.dynamicSegments, 'Dynamic Segments'] ]; routeInfo.forEach(([data, label]) => { if (data && data.length > 0) { sections.push(fmt.formatKeyValue(label, data.join(', '))); } }); if (info.interceptedRoutes > 0) { sections.push(fmt.formatKeyValue('Intercepted Routes', info.interceptedRoutes)); } // Recommendations const recommendations = this.getAppRouterRecommendations(info); sections.push(...fmt.formatRecommendations(recommendations)); return this.createTextResponse(sections.join('\n').trim()); } catch (error) { throw new Error(`Failed to get App Router information: ${error instanceof Error ? error.message : String(error)}`); } } getAppRouterRecommendations(info) { return [ ...(info.layoutNesting > 5 ? ['Deep layout nesting detected. Consider flattening for better performance'] : []), ...(info.parallelRoutes?.length > 3 ? ['Many parallel routes detected. Ensure they\'re necessary for UX'] : []), ...(!info.routeGroups?.length ? ['Consider using route groups to organize related routes'] : []) ]; } } //# sourceMappingURL=nextjs-core-info-handler.js.map