UNPKG

cerberus-claude-cli

Version:

CLI tool for preparing files and projects for Claude AI. Collect, organize, and analyze source code files to create comprehensive project contexts.

171 lines (145 loc) 5.35 kB
#!/usr/bin/env node const { program } = require('commander'); const { displayBanner } = require('../src/cli/index'); const projectCommands = require('../src/commands/project'); const menuController = require('../src/controllers/menuController'); const logger = require('../src/utils/logger'); const config = require('../src/utils/config'); const { clearTerminal } = require('../src/utils/terminal'); const { getVersion } = require('../src/utils/version'); // Global options program .name('cerberus') .description('CLI tool for preparing files and projects for Claude AI') .version(getVersion()) .option('-d, --debug', 'Enable debug mode') .option('-c, --config', 'Show current configuration') .option('-n, --no-clear', 'Do not clear terminal on startup') .hook('preAction', (thisCommand /* _actionCommand */) => { // Set debug mode if flag is provided if (thisCommand.opts().debug) { logger.setDebugMode(true); config.setDebugMode(true); logger.debug('Debug mode enabled'); } }); // Process options program.parse(process.argv); const options = program.opts(); // Clear the terminal screen (unless --no-clear is provided) if (options.clear !== false) { clearTerminal(); } // Display banner displayBanner(); // Register commands projectCommands(program); // Configuration command program .command('configure') .description('Configure Cerberus settings') .action(menuController.configureSettings); // If --config flag is set, show configuration if (options.config) { menuController.showConfiguration(); } // Always start the interactive menu FIRST, regardless of arguments // Only parse arguments if the user specifically requests to bypass the menu system const shouldParseArgs = process.argv.includes('--no-interactive'); if (shouldParseArgs) { program.parse(process.argv); } else { const fs = require('fs'); const path = require('path'); const configPath = path.join(__dirname, '../config/default.json'); async function runInitialSetup() { console.log("Welcome to Cerberus! Let's set up your configuration."); // First ask if the user wants to configure or skip const inquirer = require('inquirer'); const { setupChoice } = await inquirer.prompt([ { type: 'list', name: 'setupChoice', message: 'Do you want to configure API keys now or skip?', choices: [ { name: 'Configure now', value: 'configure' }, { name: 'Skip configuration (some features may not work)', value: 'skip' }, ], }, ]); if (setupChoice === 'skip') { console.log( '\nConfiguration skipped. You can configure later using the Configure option in the main menu.' ); return false; } // Setup Claude API console.log('\n=== Claude AI Configuration ==='); const { claudeApiKey } = await inquirer.prompt([ { type: 'password', name: 'claudeApiKey', message: 'Enter your Claude API key (or leave empty to skip):', }, ]); const { claudeModel } = await inquirer.prompt([ { type: 'list', name: 'claudeModel', message: 'Select Claude model:', choices: [ { name: 'Claude 3 Opus', value: 'claude-3-opus-20240229' }, { name: 'Claude 3 Sonnet', value: 'claude-3-sonnet-20240229' }, { name: 'Claude 3 Haiku', value: 'claude-3-haiku-20240307' }, ], default: 'claude-3-sonnet-20240229', }, ]); // Update configuration const aiServiceProvider = require('../src/services/AIServiceFactory'); const claudeAdapter = aiServiceProvider.getAdapter('claude'); if (claudeApiKey.trim() !== '') { claudeAdapter.updateApiKey(claudeApiKey); } claudeAdapter.updateConfig({ model: claudeModel }); console.log('\nConfiguration saved successfully!'); return true; } // Start the interactive CLI (async () => { try { // Initialize debug mode from config after logger and config are loaded try { const appConfig = config.getAppConfig(); logger.initializeFromConfig(appConfig); } catch (err) { // Config might not exist yet, continue without debug mode logger.debug('Could not initialize debug mode from config'); } // Check if this is first run by looking for a config file const configFileExists = fs.existsSync(configPath); if (!configFileExists) { // First time running the app, offer setup await runInitialSetup(); } else { // Check if we have API keys, but don't force setup try { const claudeApiKey = config.getClaudeApiKey(); if (!claudeApiKey) { console.log( 'Claude API key is missing. You can configure it later from the main menu.' ); } } catch (err) { // Config exists but might be corrupted - don't interrupt the flow console.log('Note: Some configuration may be missing or invalid.'); } } // Always start the interactive menu, even with missing configuration await menuController.startInteractiveMenu(); } catch (error) { console.error('Failed to start Cerberus:', error); throw new Error('Failed to start Cerberus: ' + error); } })(); }