@claude-vector/cli
Version:
CLI for Claude-integrated vector search
298 lines (258 loc) • 10.7 kB
JavaScript
/**
* 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();
}