UNPKG

@diazpolanco13/context-control-mcp

Version:

🔥 Context Control MCP v5.0 PORTABLE EDITION - Análisis universal de proyectos que funciona en CUALQUIER entorno. Contexto completo automático para IA.

504 lines (428 loc) 17.4 kB
#!/usr/bin/env node // 🔥 Context Control MCP v5.0 - PORTABLE EDITION // Funciona en CUALQUIER proyecto, CUALQUIER entorno, CUALQUIER estructura const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); console.error('🔥 Context Control MCP v5.0 "PORTABLE EDITION" - Análisis Universal'); console.error('=================================================================='); console.error('✅ Funciona en cualquier proyecto, cualquier entorno, cualquier estructura'); console.error('=================================================================='); // 🛡️ UTILIDADES DE SEGURIDAD - Nunca fallan function safeReadFile(filePath) { try { return fs.readFileSync(filePath, 'utf8'); } catch { return null; } } function safeExecSync(command) { try { return execSync(command, { encoding: 'utf8', stdio: 'pipe' }); } catch { return null; } } function safeFileExists(filePath) { try { return fs.existsSync(filePath); } catch { return false; } } function safeReadDir(dirPath) { try { return fs.readdirSync(dirPath, { withFileTypes: true }); } catch { return []; } } // 🌍 ANÁLISIS DE ENTORNO function analyzeEnvironment() { return { nodeVersion: process.version, platform: process.platform, os: process.platform === 'win32' ? 'Windows' : process.platform === 'darwin' ? 'macOS' : 'Linux', cwd: process.cwd(), hasGit: safeExecSync('git --version') !== null, hasNpm: safeExecSync('npm --version') !== null, hasYarn: safeExecSync('yarn --version') !== null }; } // 📦 ANÁLISIS DE PROYECTO (múltiples estrategias) function analyzeProjectInfo() { const project = { name: 'Unknown Project', version: '0.0.0', description: '', type: 'unknown', allDependencies: {}, scripts: [] }; // Estrategia 1: package.json const packageJson = safeReadFile('package.json'); if (packageJson) { try { const pkg = JSON.parse(packageJson); project.name = pkg.name || path.basename(process.cwd()); project.version = pkg.version || '0.0.0'; project.description = pkg.description || ''; project.allDependencies = { ...pkg.dependencies, ...pkg.devDependencies } || {}; project.scripts = Object.keys(pkg.scripts || {}); project.type = detectProjectType(pkg); } catch (e) { console.error('⚠️ package.json existe pero tiene formato inválido'); } } else { // Estrategia 2: Sin package.json - detectar por archivos project.name = path.basename(process.cwd()); project.type = detectProjectTypeByFiles(); } return project; } // 🔍 DETECCIÓN DE TIPO DE PROYECTO function detectProjectType(pkg) { const deps = { ...pkg.dependencies, ...pkg.devDependencies } || {}; if (deps.next || deps['@next/core']) return 'Next.js App'; if (deps.react) return 'React App'; if (deps.vue) return 'Vue App'; if (deps.angular) return 'Angular App'; if (deps.express) return 'Express API'; if (deps.fastify) return 'Fastify API'; if (deps['@modelcontextprotocol/sdk']) return 'MCP Server'; if (pkg.bin) return 'CLI Tool'; if (pkg.main && !deps.react && !deps.vue) return 'Node.js Library'; return 'Node.js Project'; } function detectProjectTypeByFiles() { if (safeFileExists('next.config.js') || safeFileExists('next.config.ts')) return 'Next.js App'; if (safeFileExists('vue.config.js') || safeFileExists('vite.config.js')) return 'Vue App'; if (safeFileExists('angular.json')) return 'Angular App'; if (safeFileExists('Dockerfile')) return 'Docker Project'; if (safeFileExists('requirements.txt')) return 'Python Project'; if (safeFileExists('Cargo.toml')) return 'Rust Project'; if (safeFileExists('go.mod')) return 'Go Project'; if (safeFileExists('pom.xml')) return 'Java Project'; if (safeFileExists('index.html')) return 'Static Website'; return 'Generic Project'; } // 🏗️ ANÁLISIS DE ARQUITECTURA PORTABLE function analyzeArchitecturePortable() { const arch = { framework: 'Unknown', database: 'None', auth: 'None', testing: 'None', styling: 'None', deployment: 'None' }; // Leer package.json si existe const packageJson = safeReadFile('package.json'); if (packageJson) { try { const pkg = JSON.parse(packageJson); const deps = { ...pkg.dependencies, ...pkg.devDependencies } || {}; // Framework detection if (deps.next) arch.framework = `Next.js ${deps.next}`; else if (deps.react) arch.framework = `React ${deps.react}`; else if (deps.vue) arch.framework = `Vue ${deps.vue}`; else if (deps.express) arch.framework = `Express ${deps.express}`; else if (deps['@modelcontextprotocol/sdk']) arch.framework = 'MCP Server'; // Database detection if (deps['@prisma/client'] || deps.prisma) arch.database = 'Prisma'; else if (deps.mongoose) arch.database = 'MongoDB'; else if (deps.mysql2) arch.database = 'MySQL'; else if (deps.pg) arch.database = 'PostgreSQL'; // Auth detection if (deps['@supabase/supabase-js']) arch.auth = 'Supabase'; else if (deps['next-auth']) arch.auth = 'NextAuth'; else if (deps.firebase) arch.auth = 'Firebase'; // Testing detection if (deps.jest) arch.testing = 'Jest'; else if (deps.vitest) arch.testing = 'Vitest'; else if (deps.mocha) arch.testing = 'Mocha'; // Styling detection if (deps.tailwindcss) arch.styling = 'Tailwind CSS'; else if (deps['styled-components']) arch.styling = 'Styled Components'; // Deployment detection if (safeFileExists('vercel.json')) arch.deployment = 'Vercel'; else if (safeFileExists('.netlify')) arch.deployment = 'Netlify'; else if (safeFileExists('Dockerfile')) arch.deployment = 'Docker'; } catch (e) { console.error('⚠️ Error analizando arquitectura desde package.json'); } } // Detección por archivos si no hay package.json if (arch.framework === 'Unknown') { if (safeFileExists('next.config.js')) arch.framework = 'Next.js'; else if (safeFileExists('vite.config.js')) arch.framework = 'Vite'; else if (safeFileExists('webpack.config.js')) arch.framework = 'Webpack'; } return arch; } // 📁 ANÁLISIS UNIVERSAL DE ESTRUCTURA function analyzeUniversalStructure() { const metrics = { totalFiles: 0, codeFiles: 0, configFiles: 0, docFiles: 0, components: 0, pages: 0, apis: 0, tests: 0, directories: [], fileTypes: {}, largestFiles: [] }; // Extensiones de código comunes const codeExtensions = ['.js', '.jsx', '.ts', '.tsx', '.vue', '.py', '.go', '.rs', '.java', '.cpp', '.c', '.php', '.rb']; const configExtensions = ['.json', '.yaml', '.yml', '.toml', '.ini', '.env']; const docExtensions = ['.md', '.txt', '.rst', '.adoc']; // Escanear directorio actual (no recursivo para evitar node_modules) function scanDirectory(dir, maxDepth = 2, currentDepth = 0) { if (currentDepth > maxDepth) return; const items = safeReadDir(dir); for (const item of items) { const fullPath = path.join(dir, item.name); if (item.isDirectory()) { // Skip directorios problemáticos if (['node_modules', '.git', '.next', 'dist', 'build', '.cache'].includes(item.name)) { continue; } metrics.directories.push(item.name); // Detectar tipos especiales de directorios if (item.name === 'components' || item.name.includes('component')) { metrics.components += countFilesInDir(fullPath, codeExtensions); } else if (item.name === 'pages' || item.name === 'app') { metrics.pages += countFilesInDir(fullPath, codeExtensions); } else if (item.name === 'api' || item.name.includes('api')) { metrics.apis += countFilesInDir(fullPath, codeExtensions); } else if (item.name.includes('test') || item.name.includes('spec')) { metrics.tests += countFilesInDir(fullPath, codeExtensions); } // Recursión limitada if (currentDepth < maxDepth) { scanDirectory(fullPath, maxDepth, currentDepth + 1); } } else if (item.isFile()) { metrics.totalFiles++; const ext = path.extname(item.name); metrics.fileTypes[ext] = (metrics.fileTypes[ext] || 0) + 1; if (codeExtensions.includes(ext)) { metrics.codeFiles++; } else if (configExtensions.includes(ext)) { metrics.configFiles++; } else if (docExtensions.includes(ext)) { metrics.docFiles++; } // Detectar archivos especiales if (item.name.includes('test') || item.name.includes('spec')) { metrics.tests++; } } } } scanDirectory('.'); return metrics; } function countFilesInDir(dir, extensions) { let count = 0; const items = safeReadDir(dir); for (const item of items) { if (item.isFile()) { const ext = path.extname(item.name); if (extensions.includes(ext)) { count++; } } } return count; } // 🚨 DETECCIÓN DE PROBLEMAS CRÍTICOS function detectCriticalGaps(project, architecture, metrics) { const gaps = []; // Gap 1: Proyecto sin archivos de código if (metrics.codeFiles === 0) { gaps.push({ type: 'HIGH', issue: 'No se detectaron archivos de código', impact: 'Proyecto podría estar incompleto o en estructura no estándar', action: 'Verificar estructura de directorios o añadir archivos de código' }); } // Gap 2: Proyecto Node.js sin package.json if (metrics.fileTypes['.js'] > 0 && !safeFileExists('package.json')) { gaps.push({ type: 'MEDIUM', issue: 'Archivos JavaScript sin package.json', impact: 'Dependencias no gestionadas, difícil de mantener', action: 'Inicializar proyecto con npm init' }); } // Gap 3: Muchos archivos pero sin tests if (metrics.codeFiles > 10 && metrics.tests === 0) { gaps.push({ type: 'MEDIUM', issue: `${metrics.codeFiles} archivos de código sin tests`, impact: 'Calidad del código no verificada', action: 'Implementar testing con Jest, Vitest o similar' }); } // Gap 4: Base de datos configurada pero sin APIs if (architecture.database !== 'None' && metrics.apis === 0) { gaps.push({ type: 'HIGH', issue: 'Base de datos configurada pero sin APIs detectadas', impact: 'Backend incompleto, frontend desconectado', action: 'Implementar endpoints API para conectar con la base de datos' }); } return gaps; } // 💡 DETERMINACIÓN DE PRÓXIMO PASO function determineIntelligentNextAction(project, architecture, metrics, gaps) { const criticalGaps = gaps.filter(g => g.type === 'CRITICAL'); const highGaps = gaps.filter(g => g.type === 'HIGH'); if (criticalGaps.length > 0) { return { priority: 'CRÍTICA', action: criticalGaps[0].action, reasoning: criticalGaps[0].impact, estimatedHours: criticalGaps.length * 4, blocksProduction: true }; } if (highGaps.length > 0) { return { priority: 'ALTA', action: highGaps[0].action, reasoning: highGaps[0].impact, estimatedHours: highGaps.length * 2, blocksProduction: false }; } // Sugerencias basadas en tipo de proyecto if (project.type.includes('MCP')) { return { priority: 'MEDIA', action: 'Mejorar compatibilidad y documentación del MCP', reasoning: 'Proyecto MCP detectado, enfocar en usabilidad', estimatedHours: 4, blocksProduction: false }; } if (metrics.codeFiles > 0 && metrics.tests === 0) { return { priority: 'MEDIA', action: 'Implementar testing para mejorar calidad', reasoning: `${metrics.codeFiles} archivos sin cobertura de tests`, estimatedHours: metrics.codeFiles * 0.5, blocksProduction: false }; } return { priority: 'BAJA', action: 'Continuar desarrollo según roadmap', reasoning: 'Proyecto en buen estado técnico', estimatedHours: 0, blocksProduction: false }; } // 🚀 FUNCIÓN PRINCIPAL function analyzeProject() { const results = { project: {}, architecture: {}, metrics: {}, criticalGaps: [], nextAction: {}, environment: {} }; console.error('🔍 Iniciando análisis portable...'); try { // FASE 0: Entorno results.environment = analyzeEnvironment(); console.error(`📍 Entorno: ${results.environment.os} | Node: ${results.environment.nodeVersion}`); // FASE 1: Proyecto results.project = analyzeProjectInfo(); console.error(`📊 Proyecto: ${results.project.name} detectado como ${results.project.type}`); // FASE 2: Arquitectura results.architecture = analyzeArchitecturePortable(); console.error(`🏗️ Stack: ${results.architecture.framework} + ${results.architecture.database}`); // FASE 3: Estructura results.metrics = analyzeUniversalStructure(); console.error(`📁 Archivos: ${results.metrics.totalFiles} total, ${results.metrics.codeFiles} código`); // FASE 4: Gaps críticos results.criticalGaps = detectCriticalGaps(results.project, results.architecture, results.metrics); console.error(`🚨 Gaps: ${results.criticalGaps.length} problemas detectados`); // FASE 5: Próximo paso results.nextAction = determineIntelligentNextAction( results.project, results.architecture, results.metrics, results.criticalGaps ); console.error(`💡 Próximo paso: ${results.nextAction.action}`); } catch (error) { console.error('❌ Error en análisis:', error.message); return null; } return results; } // 📊 EJECUCIÓN Y DISPLAY const analysis = analyzeProject(); if (analysis) { console.log('\n🔥 **ANÁLISIS PORTABLE COMPLETADO**'); console.log('═══════════════════════════════════════════════'); console.log(`\n🌍 **ENTORNO DETECTADO**:`); console.log(`• Sistema: ${analysis.environment.os} (${analysis.environment.platform})`); console.log(`• Node.js: ${analysis.environment.nodeVersion}`); console.log(`• Git: ${analysis.environment.hasGit ? 'Disponible' : 'No disponible'}`); console.log(`• NPM: ${analysis.environment.hasNpm ? 'Disponible' : 'No disponible'}`); console.log(`\n📊 **PROYECTO DETECTADO**:`); console.log(`• Nombre: ${analysis.project.name} v${analysis.project.version}`); console.log(`• Tipo: ${analysis.project.type}`); console.log(`• Descripción: ${analysis.project.description || 'Sin descripción'}`); console.log(`• Scripts: ${analysis.project.scripts.length} comandos disponibles`); console.log(`\n🏗️ **ARQUITECTURA DETECTADA**:`); console.log(`• Framework: ${analysis.architecture.framework}`); console.log(`• Base de datos: ${analysis.architecture.database}`); console.log(`• Autenticación: ${analysis.architecture.auth}`); console.log(`• Testing: ${analysis.architecture.testing}`); console.log(`• Styling: ${analysis.architecture.styling}`); console.log(`• Deployment: ${analysis.architecture.deployment}`); console.log(`\n📁 **ESTRUCTURA ANALIZADA**:`); console.log(`• Total archivos: ${analysis.metrics.totalFiles}`); console.log(`• Archivos de código: ${analysis.metrics.codeFiles}`); console.log(`• Archivos de config: ${analysis.metrics.configFiles}`); console.log(`• Documentación: ${analysis.metrics.docFiles}`); console.log(`• Componentes: ${analysis.metrics.components}`); console.log(`• Páginas: ${analysis.metrics.pages}`); console.log(`• APIs: ${analysis.metrics.apis}`); console.log(`• Tests: ${analysis.metrics.tests}`); console.log(`• Directorios: ${analysis.metrics.directories.join(', ')}`); if (analysis.criticalGaps.length > 0) { console.log(`\n🚨 **PROBLEMAS DETECTADOS** (${analysis.criticalGaps.length}):`); analysis.criticalGaps.forEach((gap, i) => { const icon = gap.type === 'CRITICAL' ? '❌' : gap.type === 'HIGH' ? '⚠️' : 'ℹ️'; console.log(`${i+1}. ${icon} [${gap.type}] ${gap.issue}`); console.log(` 💥 Impacto: ${gap.impact}`); console.log(` 🔧 Acción: ${gap.action}`); }); } else { console.log('\n✅ **No hay problemas críticos detectados**'); } console.log(`\n💡 **PRÓXIMO PASO INTELIGENTE**:`); console.log(`• **Prioridad**: ${analysis.nextAction.priority}`); console.log(`• **Acción**: ${analysis.nextAction.action}`); console.log(`• **Razón**: ${analysis.nextAction.reasoning}`); console.log(`• **Tiempo estimado**: ${analysis.nextAction.estimatedHours} horas`); console.log(`• **Bloquea producción**: ${analysis.nextAction.blocksProduction ? 'SÍ' : 'NO'}`); console.log('\n🏆 **ANÁLISIS PORTABLE v5.0 COMPLETADO**'); console.log('✅ Funciona en CUALQUIER proyecto, CUALQUIER entorno, CUALQUIER estructura'); console.log('🚀 Context Control MCP v5.0 "PORTABLE EDITION" - Análisis 100% universal'); } else { console.error('❌ No se pudo completar el análisis'); process.exit(1); }