UNPKG

@claude-vector/cli

Version:

CLI for Claude-integrated vector search

298 lines (258 loc) 10.7 kB
#!/usr/bin/env node /** * Claude Vector Search CLI */ import { program } from 'commander'; import chalk from 'chalk'; import ora from 'ora'; import { readFileSync } from 'fs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; import dotenv from 'dotenv'; // Load environment variables dotenv.config(); // Get package info const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8')); // Import commands import { initCommand } from '../src/commands/init.js'; import { searchCommand } from '../src/commands/search.js'; import { indexCommand } from '../src/commands/index.js'; import { startCommand } from '../src/commands/start.js'; import { statusCommand } from '../src/commands/status.js'; import { configCommand } from '../src/commands/config.js'; import { contextCommand } from '../src/commands/context.js'; // ASCII art banner const banner = ` ${chalk.cyan('╔═══════════════════════════════════════╗')} ${chalk.cyan('║')} ${chalk.bold.white('Claude Vector Search')} ${chalk.cyan('║')} ${chalk.cyan('║')} ${chalk.gray('AI-powered code intelligence')} ${chalk.cyan('║')} ${chalk.cyan('╚═══════════════════════════════════════╝')} `; // Main program program .name('claude-search') .description('Claude-integrated vector search for code intelligence') .version(packageJson.version) .addHelpText('before', banner); // Initialize command program .command('init') .description('Initialize vector search in current project') .option('-f, --force', 'Force re-initialization') .option('-c, --config <path>', 'Use custom config file') .action(initCommand); // Search command program .command('search <query>') .description('Search for code, patterns, or solutions') .option('-l, --limit <n>', 'Maximum results', parseInt, 10) .option('-t, --threshold <n>', 'Similarity threshold (0-1)', parseFloat) .option('--type <type>', 'Filter by type (code, docs, etc.)') .option('--json', 'Output as JSON') .option('--no-cache', 'Disable cache') .option('--add-to-context', 'Add relevant results to current session context') .option('--auto', 'Automatically add results to context and optimize query') .option('--optimize', 'Enable query optimization (expand abbreviations)') .option('--no-optimize', 'Disable query optimization') .action(searchCommand); // Index command program .command('index') .description('Build or rebuild search index') .option('-f, --force', 'Force rebuild index from scratch') .option('-r, --resume', 'Resume interrupted indexing') .option('--stats', 'Show index statistics') .action(indexCommand); // Start command (workflow) program .command('start <task>') .description('Start a new development task with AI assistance') .option('-t, --type <type>', 'Task type (bug-fix, feature, refactor, debug, explore)') .option('--no-auto', 'Disable automatic context building') .option('--no-learning', 'Disable query optimization learning') .action(startCommand); // Status command program .command('status') .description('Show current session and system status') .option('--sessions', 'List all sessions') .option('--cache', 'Show cache statistics') .option('--index', 'Show index statistics') .option('--learning', 'Show learning statistics') .action(statusCommand); // Config command program .command('config') .description('Manage configuration') .option('--show', 'Show current configuration') .option('--edit', 'Open config in editor') .option('--reset', 'Reset to defaults') .option('--set <key=value>', 'Set configuration value') .action(configCommand); // Error command (shortcut) program .command('error <message>') .description('Analyze error and get solutions') .option('--context', 'Include current context') .action(async (message, options) => { const { ErrorAssistant, SessionManager, ContextManager } = await import('@claude-vector/claude-tools'); const { VectorSearchEngine } = await import('@claude-vector/core'); const spinner = ora('Analyzing error...').start(); try { // Initialize modules const assistant = new ErrorAssistant(); const sessionManager = new SessionManager(); const contextManager = new ContextManager(); // Try to initialize search engine let searchEngine = null; try { searchEngine = new VectorSearchEngine(); const indexPath = '.claude-vector-index'; await searchEngine.loadIndex( `${indexPath}/embeddings.json`, `${indexPath}/chunks.json` ); } catch (error) { // Search engine is optional for error analysis } // Connect modules assistant.setModules({ searchEngine, contextManager: options.context ? contextManager : null, sessionManager }); spinner.text = 'Analyzing error and searching for solutions...'; const analysis = await assistant.analyzeError(message, { addToContext: options.context }); spinner.succeed('Error analyzed'); console.log(chalk.bold('\n📊 Error Analysis:')); console.log(chalk.gray('Category:'), analysis.category); console.log(chalk.gray('Type:'), analysis.type); console.log(chalk.gray('Component:'), analysis.component); console.log(chalk.gray('Severity:'), analysis.severity); console.log(chalk.gray('Urgency:'), analysis.urgency); if (analysis.lineNumber) { console.log(chalk.gray('Line:'), analysis.lineNumber); } console.log(chalk.bold('\n💡 Solutions:')); analysis.solutions.forEach((solution, i) => { console.log(chalk.cyan(`${i + 1}.`), solution); }); console.log(chalk.bold('\n🔍 Debug Steps:')); analysis.debugSteps.forEach((step, i) => { console.log(chalk.gray(`${i + 1}.`), step); }); // Show related solutions if found if (analysis.relatedSolutions && analysis.relatedSolutions.length > 0) { console.log(chalk.bold('\n🔗 Related Code Patterns:')); analysis.relatedSolutions.forEach((solution, i) => { console.log(chalk.yellow(`${i + 1}.`), `${solution.file || 'Unknown file'} (score: ${(solution.score * 100).toFixed(1)}%)`); if (solution.content && solution.content.length > 0) { console.log(chalk.dim(` ${solution.content.substring(0, 80)}...`)); } }); } // Show suggestions if (analysis.suggestions && analysis.suggestions.length > 0) { console.log(chalk.bold('\n💭 Suggestions:')); analysis.suggestions.forEach((suggestion, i) => { console.log(chalk.magenta(`${i + 1}.`), suggestion); }); } // Show context addition confirmation if (options.context) { console.log(chalk.bold('\n📝 Context:')); console.log(chalk.green('✓'), 'Error analysis added to current session context'); } // 正常終了 process.exit(0); } catch (error) { spinner.fail(`Error analysis failed: ${error.message}`); console.error(chalk.red('\nError details:'), error.message); process.exit(1); } }); // Context command program .command('context') .description('Show and manage current context') .option('--detailed', 'Show detailed context information') .option('--full', 'Show full context content') .option('--summary', 'Show only summary') .option('--activities', 'Show recent activities') .option('--quiet', 'Hide suggestions') .option('--debug', 'Show debug information') .action(contextCommand); // Feedback command program .command('feedback [rating]') .description('Provide feedback on last search results') .option('--useful <indices>', 'Mark specific results as useful (comma-separated)') .option('--session', 'Provide feedback for entire session') .action(async (rating, options) => { const { feedbackCommand } = await import('../src/commands/feedback.js'); await feedbackCommand(rating, options); }); // Open command program .command('open <index>') .description('Open a file from last search results') .option('--editor <editor>', 'Specify editor to use') .action(async (index, options) => { const { openCommand } = await import('../src/commands/open.js'); await openCommand(index, options); }); // Complete command program .command('complete') .description('Complete current session with evaluation') .option('--rating <rating>', 'Overall session rating (1-5)') .option('--notes <notes>', 'Additional notes about the session') .action(async (options) => { const { completeCommand } = await import('../src/commands/complete.js'); await completeCommand(options); }); // Agent command (AI Agent API server) // 動的にロードしてccvectorに影響を与えない if (process.argv[2] === 'agent') { program .command('agent') .description('Start AI agent API server') .option('-p, --port <port>', 'Port to listen on', '3000') .option('-h, --host <host>', 'Host to bind to', 'localhost') .option('--no-open', 'Do not open browser automatically') .action(async (options) => { const { agentCommand } = await import('../src/commands/agent.js'); await agentCommand.execute(options); }); } // Help improvements program .addHelpText('after', ` ${chalk.bold('Examples:')} ${chalk.gray('# Initialize in current project')} $ claude-search init ${chalk.gray('# Search for code')} $ claude-search search "user authentication" ${chalk.gray('# Start a new task')} $ claude-search start "Fix login bug" ${chalk.gray('# Analyze an error')} $ claude-search error "TypeError: Cannot read property 'id' of undefined" ${chalk.bold('Quick Start:')} 1. Set your OpenAI API key: ${chalk.cyan('export OPENAI_API_KEY=your-key')} 2. Initialize: ${chalk.cyan('claude-search init')} 3. Build index: ${chalk.cyan('claude-search index')} 4. Start searching: ${chalk.cyan('claude-search search "your query"')} ${chalk.bold('More Info:')} GitHub: ${chalk.cyan('https://github.com/your-username/claude-vector-search')} Docs: ${chalk.cyan('https://claude-vector-search.dev')} `); // Parse arguments program.parse(process.argv); // Show help if no command if (!process.argv.slice(2).length) { program.outputHelp(); }