embedia
Version:
Zero-configuration AI chatbot integration CLI - direct file copy with embedded API keys
223 lines (183 loc) ⢠8.17 kB
JavaScript
const chalk = require('chalk');
const ora = require('ora');
const fs = require('fs-extra');
const path = require('path');
// Import diagnostic tools
const HealthChecker = require('../health/healthChecker');
const BuildVerifier = require('../validation/buildVerifier');
const ConflictScanner = require('../conflicts/conflictScanner');
const ProjectAnalyzer = require('../analysis/projectAnalyzer');
/**
* Doctor command - Comprehensive diagnostics and auto-fix for Embedia installations
*/
async function doctorCommand(options = {}) {
console.log(chalk.bold.blue('\n𩺠Embedia Doctor - Diagnostic & Repair Tool\n'));
const projectPath = process.cwd();
try {
// Phase 1: Project Analysis
if (!options.skipAnalysis) {
console.log(chalk.bold('š Phase 1: Project Analysis\n'));
const spinner = ora('Analyzing project structure...').start();
const analyzer = new ProjectAnalyzer();
const analysis = await analyzer.analyze(projectPath);
spinner.succeed('Project analysis complete');
console.log(chalk.gray(` Framework: ${analysis.framework.name} ${analysis.framework.version}`));
console.log(chalk.gray(` Router: ${analysis.routerType}`));
console.log(chalk.gray(` TypeScript: ${analysis.typescript.isTypeScript ? 'Yes' : 'No'}`));
}
// Phase 2: Health Check
console.log(chalk.bold('\nš„ Phase 2: Health Check\n'));
const healthChecker = new HealthChecker(projectPath);
const healthResults = await healthChecker.runHealthCheck();
if (healthResults.score === 100) {
console.log(chalk.green('ā
All health checks passed!'));
} else {
console.log(chalk.yellow(`ā ļø Health Score: ${healthResults.score}%`));
if (healthResults.issues.length > 0) {
console.log(chalk.yellow('\nIssues Found:'));
healthResults.issues.forEach(issue => {
console.log(chalk.red(` ā ${issue.name}`));
console.log(chalk.gray(` ${issue.error}`));
if (issue.solution) {
console.log(chalk.blue(` ā ${issue.solution}`));
}
});
}
}
// Phase 3: Build Verification (for Next.js projects)
if (analysis?.framework?.name === 'next') {
console.log(chalk.bold('\nšØ Phase 3: Build Verification\n'));
const buildVerifier = new BuildVerifier(projectPath);
const buildResults = await buildVerifier.quickVerify();
if (buildResults.passed) {
console.log(chalk.green('ā
Build integrity verified'));
} else {
console.log(chalk.red('ā Build issues detected:'));
buildResults.issues.forEach(issue => {
console.log(chalk.red(` - ${issue}`));
});
if (options.fix) {
console.log(chalk.blue('\nš§ Attempting auto-fix...'));
const fixes = await buildVerifier.attemptAutoFix();
if (fixes.length > 0) {
console.log(chalk.green('ā
Applied fixes:'));
fixes.forEach(fix => {
console.log(chalk.green(` - ${fix}`));
});
}
}
}
}
// Phase 4: Conflict Detection
if (options.conflicts) {
console.log(chalk.bold('\nš Phase 4: Conflict Detection\n'));
const spinner = ora('Scanning for conflicts...').start();
const scanner = new ConflictScanner();
const conflicts = await scanner.scanProject(projectPath);
if (conflicts.length === 0) {
spinner.succeed('No conflicts found');
} else {
spinner.warn(`Found ${conflicts.length} potential conflicts`);
// Group conflicts by type
const conflictTypes = {};
conflicts.forEach(conflict => {
if (!conflictTypes[conflict.type]) {
conflictTypes[conflict.type] = [];
}
conflictTypes[conflict.type].push(conflict);
});
// Display conflicts by type
Object.entries(conflictTypes).forEach(([type, typeConflicts]) => {
console.log(chalk.yellow(`\n${type} Conflicts (${typeConflicts.length}):`));
const displayLimit = 5;
typeConflicts.slice(0, displayLimit).forEach(conflict => {
console.log(chalk.gray(` - ${conflict.file}`));
if (conflict.pattern) {
console.log(chalk.gray(` Pattern: ${conflict.pattern}`));
}
});
if (typeConflicts.length > displayLimit) {
console.log(chalk.gray(` ... and ${typeConflicts.length - displayLimit} more`));
}
});
}
}
// Phase 5: Auto-fix
if (options.fix) {
console.log(chalk.bold('\nš§ Phase 5: Auto-Fix\n'));
const fixes = [];
// Fix 1: Missing dependencies
if (healthResults.issues.some(i => i.name === 'Dependencies Installed' && !i.success)) {
const spinner = ora('Installing missing dependencies...').start();
try {
const { execSync } = require('child_process');
execSync('npm install @google/generative-ai', {
cwd: projectPath,
stdio: 'pipe'
});
spinner.succeed('Dependencies installed');
fixes.push('Installed missing dependencies');
} catch (error) {
spinner.fail('Failed to install dependencies');
}
}
// Fix 2: Missing environment variables
if (healthResults.issues.some(i => i.name === 'Environment Variables' && !i.success)) {
const spinner = ora('Setting up environment files...').start();
try {
const envPath = path.join(projectPath, '.env.local');
const envExamplePath = path.join(projectPath, '.env.example');
if (!await fs.pathExists(envPath)) {
await fs.writeFile(envPath, 'GEMINI_API_KEY=your_api_key_here\n');
fixes.push('Created .env.local file');
}
if (!await fs.pathExists(envExamplePath)) {
await fs.writeFile(envExamplePath, 'GEMINI_API_KEY=your_api_key_here\n');
fixes.push('Created .env.example file');
}
spinner.succeed('Environment files set up');
} catch (error) {
spinner.fail('Failed to set up environment files');
}
}
// Fix 3: Integration issues
if (healthResults.issues.some(i => i.name === 'Integration Status' && !i.success)) {
console.log(chalk.yellow('\nā ļø Integration issues require manual intervention'));
console.log(chalk.blue('Please follow the integration instructions provided during installation'));
}
if (fixes.length > 0) {
console.log(chalk.green(`\nā
Applied ${fixes.length} fixes:`));
fixes.forEach(fix => {
console.log(chalk.green(` - ${fix}`));
});
console.log(chalk.blue('\nš” Run "npx embedia doctor" again to verify fixes'));
} else {
console.log(chalk.gray('\nNo automatic fixes available'));
}
}
// Summary
console.log(chalk.bold('\nš Summary\n'));
if (healthResults.score === 100 && (!buildResults || buildResults.passed)) {
console.log(chalk.green('ā
Your Embedia installation is healthy!'));
} else {
console.log(chalk.yellow('ā ļø Some issues need attention'));
if (!options.fix) {
console.log(chalk.blue('\nš” Run "npx embedia doctor --fix" to attempt automatic fixes'));
}
}
// Recommendations
if (healthResults.recommendations && healthResults.recommendations.length > 0) {
console.log(chalk.bold('\nš” Recommendations:\n'));
healthResults.recommendations.forEach(rec => {
console.log(chalk.blue(` ⢠${rec}`));
});
}
} catch (error) {
console.error(chalk.red(`\nā Doctor encountered an error: ${error.message}\n`));
if (process.env.DEBUG) {
console.error(chalk.gray(error.stack));
}
process.exit(1);
}
}
module.exports = doctorCommand;