UNPKG

woaru

Version:

Universal Project Setup Autopilot - Analyze and automatically configure development tools for ANY programming language

526 lines 21.7 kB
import chalk from 'chalk'; import { t } from '../config/i18n.js'; import { ConfigManager } from '../config/ConfigManager.js'; import { checkAiAvailability, getActiveProviders } from './ai-helpers.js'; import { UsageTracker } from '../ai/UsageTracker.js'; import { AIProviderUtils } from './AIProviderUtils.js'; /** * Main entry point for AI Control Center */ export async function showAiControlCenter() { console.log(chalk.cyan.bold(t('cli.ai_control_center.title'))); console.log(); // Check if any providers are configured const isAvailable = await checkAiAvailability(); if (!isAvailable) { console.log(chalk.yellow(t('ai_control_center.configure_providers_first'))); console.log(chalk.blue('Run: woaru ai setup')); return; } // Show current status await displayCurrentStatus(); console.log(); // Show interactive menu await showInteractiveMenu(); } /** * Display current AI configuration status */ async function displayCurrentStatus() { console.log(chalk.blue(t('cli.ai_control_center.current_status'))); // Use the new visual status system const { displayAiStatus } = await import('./ai-helpers.js'); await displayAiStatus(false); // Show detailed status const configManager = ConfigManager.getInstance(); const aiConfig = (await configManager.loadAiConfig()); const activeProviders = await getActiveProviders(); const usageTracker = UsageTracker.getInstance(); // Show Multi-AI status const multiAiEnabled = aiConfig.multiAi === true; if (multiAiEnabled) { console.log(` • ${chalk.green(t('cli.ai_control_center.multi_ai_enabled'))}`); } else { console.log(` • ${chalk.gray(t('ai_control_center.multi_ai_disabled'))}`); } // Show primary provider if (aiConfig.primaryProvider) { console.log(` • ${chalk.cyan(t('ai_control_center.primary_provider', { provider: aiConfig.primaryProvider }))}`); } else { console.log(` • ${chalk.yellow(t('cli.ai_control_center.no_primary_provider'))}`); } // Show active providers console.log(` • Active Providers: ${chalk.green(activeProviders.length)}`); for (const provider of activeProviders) { const hasApiKey = await configManager.hasApiKey(provider.id); const apiKeyStatus = hasApiKey ? chalk.green(t('ai_control_center.api_key_found')) : chalk.red(t('ai_control_center.api_key_missing')); console.log(` - ${provider.id}: ${apiKeyStatus}`); } // Show usage statistics const totalUsage = await usageTracker.getTotalUsage(); if (totalUsage.totalRequests > 0) { console.log(` • Total Requests: ${chalk.cyan(totalUsage.totalRequests)}`); console.log(` • Total Cost: ${chalk.green('$' + totalUsage.totalCost.toFixed(4))}`); } } /** * Show interactive menu for AI Control Center */ async function showInteractiveMenu() { try { const { default: inquirer } = await import('inquirer'); const configManager = ConfigManager.getInstance(); const aiConfig = (await configManager.loadAiConfig()); while (true) { const choices = [ t('cli.ai_control_center.menu_options.add_edit_provider'), ]; // Add Multi-AI toggle option if (aiConfig.multiAi === true) { choices.push(t('cli.ai_control_center.menu_options.disable_multi_ai')); } else { choices.push(t('cli.ai_control_center.menu_options.enable_multi_ai')); } choices.push(t('cli.ai_control_center.menu_options.select_primary'), t('cli.ai_control_center.menu_options.exit')); const { action } = await inquirer.prompt([ { type: 'list', name: 'action', message: t('cli.ai_control_center.menu_prompt'), choices, }, ]); if (action === t('cli.ai_control_center.menu_options.exit')) { console.log(chalk.cyan(t('ai_control_center.goodbye'))); break; } else if (action === t('cli.ai_control_center.menu_options.add_edit_provider')) { await handleProviderManagement(); } else if (action === t('cli.ai_control_center.menu_options.enable_multi_ai')) { await enableMultiAi(); } else if (action === t('cli.ai_control_center.menu_options.disable_multi_ai')) { await disableMultiAi(); } else if (action === t('cli.ai_control_center.menu_options.select_primary')) { await selectPrimaryProvider(); } // Refresh config after each operation const updatedConfig = (await configManager.loadAiConfig()); Object.assign(aiConfig, updatedConfig); console.log(); // Add spacing between menu iterations } } catch (error) { console.error(chalk.red('Interactive menu failed:'), error); } } /** * Handle provider management (add/edit/remove providers) */ async function handleProviderManagement() { try { const { default: inquirer } = await import('inquirer'); const activeProviders = await getActiveProviders(); // Show existing providers or add new one const choices = [ ...activeProviders.map(p => `${p.id} (configured)`), 'Add new provider', t('cli.provider_management.back_to_menu'), ]; const { selection } = await inquirer.prompt([ { type: 'list', name: 'selection', message: t('cli.provider_management.select_provider'), choices, }, ]); if (selection === t('cli.provider_management.back_to_menu')) { return; } else if (selection === 'Add new provider') { await addNewProvider(); } else { // Edit existing provider const providerId = selection.split(' ')[0]; await editProvider(providerId); } } catch (error) { console.error(chalk.red('Provider management failed:'), error); } } /** * Add a new AI provider */ async function addNewProvider() { try { const { default: inquirer } = await import('inquirer'); const supportedProviders = [ 'openai', 'anthropic', 'google', 'azure', 'deepseek', 'ollama', ]; const { providerId } = await inquirer.prompt([ { type: 'list', name: 'providerId', message: 'Select provider type:', choices: supportedProviders, }, ]); const { apiKey } = await inquirer.prompt([ { type: 'password', name: 'apiKey', message: t('cli.setup.api_key_prompt', { provider: providerId }), validate: (input) => input.length > 0 || 'API key is required', }, ]); // Save API key const configManager = ConfigManager.getInstance(); await configManager.saveApiKey(providerId, apiKey); // Fetch and select model console.log(t('cli.setup.loading_models')); const availableModels = await AIProviderUtils.fetchModelsForProvider(providerId, apiKey); if (availableModels.length === 0) { console.log(chalk.yellow('No models found. Using default configuration.')); return; } const { selectedModel } = await inquirer.prompt([ { type: 'list', name: 'selectedModel', message: t('cli.setup.select_model', { provider: providerId }), choices: availableModels.map(m => ({ name: `${m.name} - ${m.description}`, value: m.id, })), }, ]); const { enabled } = await inquirer.prompt([ { type: 'confirm', name: 'enabled', message: t('cli.setup.enable_for_analysis', { provider: providerId }), default: true, }, ]); // Save provider configuration const aiConfig = (await configManager.loadAiConfig()); aiConfig[providerId] = { enabled, model: selectedModel, id: providerId, providerType: providerId, }; await configManager.saveAiConfig(aiConfig); console.log(chalk.green(t('cli.setup.provider_setup_complete', { provider: providerId }))); } catch (error) { console.error(chalk.red('Failed to add provider:'), error); } } /** * Edit an existing provider */ async function editProvider(providerId) { try { const { default: inquirer } = await import('inquirer'); // Get current status for better UX const configManager = ConfigManager.getInstance(); const aiConfig = (await configManager.loadAiConfig()); const providerConfig = aiConfig[providerId]; const currentStatus = providerConfig?.enabled ? 'enabled' : 'disabled'; const actions = [ t('cli.provider_management.change_model'), t('cli.provider_management.change_api_key'), `🔛 Toggle Code Reviews (Currently: ${currentStatus})`, t('cli.provider_management.remove_provider'), t('cli.provider_management.back_to_menu'), ]; const { action } = await inquirer.prompt([ { type: 'list', name: 'action', message: t('cli.provider_management.provider_actions', { provider: providerId, }), choices: actions, }, ]); // configManager and aiConfig already loaded above if (action === t('cli.provider_management.change_model')) { const { default: inquirer } = await import('inquirer'); const apiKey = await configManager.getApiKey(providerId); if (apiKey) { // First show recommended models with option to see all const allModels = await AIProviderUtils.fetchModelsForProvider(providerId, apiKey); if (allModels.length > 0) { const recommendedModels = allModels.filter(m => m.isRecommended); const showRecommendedFirst = recommendedModels.length > 0; let selectedModel; if (showRecommendedFirst) { // Show recommended models first with option to see all const { modelChoice } = await inquirer.prompt([ { type: 'list', name: 'modelChoice', message: `🎯 Select ${providerId} model (showing ${recommendedModels.length} recommended):`, choices: [ ...recommendedModels.map(m => ({ name: `${m.tier === 'flagship' ? '⭐' : m.tier === 'fast' ? '⚡' : '📊'} ${m.name} - ${m.description}`, value: m.id, })), new inquirer.Separator(), { name: `📋 Show all ${allModels.length} models (including legacy/deprecated)`, value: '__SHOW_ALL__', }, ], }, ]); if (modelChoice === '__SHOW_ALL__') { // Show all models with clear categorization const { newModel } = await inquirer.prompt([ { type: 'list', name: 'newModel', message: `📋 All ${providerId} models (${allModels.length} total):`, choices: allModels .sort((a, b) => { // Sort: recommended first, then by tier, then deprecated last if (a.isRecommended !== b.isRecommended) { return b.isRecommended ? 1 : -1; } if (a.isDeprecated !== b.isDeprecated) { return a.isDeprecated ? 1 : -1; } return a.name.localeCompare(b.name); }) .map(m => ({ name: `${m.isRecommended ? '✅' : m.isDeprecated ? '⚠️ ' : '🔸'} ${m.name} - ${m.description}${m.isDeprecated ? ' (DEPRECATED)' : ''}`, value: m.id, })), }, ]); selectedModel = newModel; } else { selectedModel = modelChoice; } } else { // Fallback: show all models if no recommended models const { newModel } = await inquirer.prompt([ { type: 'list', name: 'newModel', message: 'Select new model:', choices: allModels.map(m => ({ name: `${m.name} - ${m.description}`, value: m.id, })), }, ]); selectedModel = newModel; } providerConfig.model = selectedModel; await configManager.saveAiConfig(aiConfig); console.log(chalk.green(t('cli.provider_management.model_changed', { model: selectedModel, }))); } } } else if (action === t('cli.provider_management.change_api_key')) { const { newApiKey } = await inquirer.prompt([ { type: 'password', name: 'newApiKey', message: t('cli.provider_management.api_key_prompt', { provider: providerId, }), validate: (input) => input.length > 0 || 'API key is required', }, ]); await configManager.saveApiKey(providerId, newApiKey); console.log(chalk.green(t('cli.provider_management.api_key_validation'))); } else if (action.startsWith('🔛 Toggle Code Reviews')) { providerConfig.enabled = !providerConfig.enabled; await configManager.saveAiConfig(aiConfig); const status = providerConfig.enabled ? 'enabled' : 'disabled'; console.log(chalk.green(`✅ Code reviews for ${providerId} are now ${status}`)); console.log(chalk.gray(` This provider ${providerConfig.enabled ? 'will be used' : 'will NOT be used'} for AI code analysis.`)); } else if (action === t('cli.provider_management.remove_provider')) { const { confirmed } = await inquirer.prompt([ { type: 'confirm', name: 'confirmed', message: t('cli.provider_management.confirm_removal', { provider: providerId, }), default: false, }, ]); if (confirmed) { delete aiConfig[providerId]; await configManager.saveAiConfig(aiConfig); await configManager.removeApiKey(providerId); console.log(chalk.green(t('cli.provider_management.provider_removed', { provider: providerId, }))); } else { console.log(chalk.gray(t('cli.provider_management.removal_cancelled'))); } } } catch (error) { console.error(chalk.red('Failed to edit provider:'), error); } } /** * Enable Multi-AI Review mode */ async function enableMultiAi() { try { const configManager = ConfigManager.getInstance(); const aiConfig = (await configManager.loadAiConfig()); aiConfig.multiAi = true; await configManager.saveAiConfig(aiConfig); console.log(chalk.green(t('ai_control_center.multi_ai_enabled_message'))); console.log(chalk.gray(t('cli.ai_control_center.multi_ai_enabled'))); console.log(chalk.gray(t('general.continue_prompt'))); // Wait for user input const { default: inquirer } = await import('inquirer'); await inquirer.prompt([ { type: 'input', name: 'continue', message: '', }, ]); } catch (error) { console.error(chalk.red('Failed to enable Multi-AI:'), error); } } /** * Disable Multi-AI Review mode */ async function disableMultiAi() { try { const configManager = ConfigManager.getInstance(); const aiConfig = (await configManager.loadAiConfig()); aiConfig.multiAi = false; await configManager.saveAiConfig(aiConfig); console.log(chalk.yellow(t('ai_control_center.multi_ai_disabled_message'))); console.log(chalk.gray(t('cli.ai_control_center.disable_multi_ai_explanation'))); console.log(chalk.gray(t('general.continue_prompt'))); // Wait for user input const { default: inquirer } = await import('inquirer'); await inquirer.prompt([ { type: 'input', name: 'continue', message: '', }, ]); } catch (error) { console.error(chalk.red('Failed to disable Multi-AI:'), error); } } /** * Select primary provider for reviews */ async function selectPrimaryProvider() { try { const { default: inquirer } = await import('inquirer'); const activeProviders = await getActiveProviders(); if (activeProviders.length === 0) { console.log(chalk.yellow(t('ai_control_center.no_providers_enabled'))); return; } const { primaryProvider } = await inquirer.prompt([ { type: 'list', name: 'primaryProvider', message: t('cli.provider_management.select_primary'), choices: activeProviders.map(p => p.id), }, ]); const configManager = ConfigManager.getInstance(); const aiConfig = (await configManager.loadAiConfig()); aiConfig.primaryProvider = primaryProvider; await configManager.saveAiConfig(aiConfig); console.log(chalk.green(t('cli.provider_management.primary_selected', { provider: primaryProvider, }))); } catch (error) { console.error(chalk.red('Failed to select primary provider:'), error); } } /** * Show AI Setup interface (standalone command) */ export async function showAiSetup() { console.log(chalk.cyan.bold(t('setup.ai_setup_title'))); console.log(); try { await addNewProvider(); // Ask if user wants to set up another provider const { default: inquirer } = await import('inquirer'); const { setupAnother } = await inquirer.prompt([ { type: 'confirm', name: 'setupAnother', message: t('cli.setup.setup_another'), default: false, }, ]); if (setupAnother) { await showAiSetup(); // Recursive call for multiple setups } else { // Ask about Multi-AI mode const { enableMultiAi } = await inquirer.prompt([ { type: 'confirm', name: 'enableMultiAi', message: t('cli.setup.enable_multi_ai'), default: false, }, ]); if (enableMultiAi) { const configManager = ConfigManager.getInstance(); const aiConfig = (await configManager.loadAiConfig()); aiConfig.multiAi = true; await configManager.saveAiConfig(aiConfig); console.log(chalk.green(t('cli.setup.multi_ai_activated'))); } else { console.log(chalk.gray(t('cli.setup.multi_ai_not_activated'))); } console.log(chalk.green(t('setup.success'))); } } catch (error) { console.error(chalk.red('AI setup failed:'), error); } } //# sourceMappingURL=ai-control-center.js.map