@claude-vector/cli
Version:
CLI for Claude-integrated vector search
246 lines (214 loc) • 7.43 kB
JavaScript
/**
* Initialize command - Set up Claude Vector Search in a project
*/
import chalk from 'chalk';
import ora from 'ora';
import inquirer from 'inquirer';
import { writeFileSync, readFileSync, existsSync, mkdirSync } from 'fs';
import { join } from 'path';
import { ProjectAdapter } from '@claude-vector/core';
export async function initCommand(options) {
console.log(chalk.bold('\n🚀 Initializing Claude Vector Search\n'));
const spinner = ora('Analyzing project...').start();
try {
// Analyze project
const adapter = new ProjectAdapter(process.cwd());
const projectInfo = await adapter.analyzeProject();
spinner.succeed(`Detected ${projectInfo.type} project (${projectInfo.language})`);
// Check for existing config
const configPath = join(process.cwd(), '.claude-search.config.js');
if (existsSync(configPath) && !options.force) {
const { overwrite } = await inquirer.prompt([{
type: 'confirm',
name: 'overwrite',
message: 'Configuration already exists. Overwrite?',
default: false
}]);
if (!overwrite) {
console.log(chalk.yellow('\n⚠️ Initialization cancelled'));
return;
}
}
// Get configuration preferences
const answers = await inquirer.prompt([
{
type: 'confirm',
name: 'useDefaults',
message: 'Use recommended settings for your project?',
default: true
},
{
type: 'list',
name: 'embeddingModel',
message: 'Select embedding model:',
choices: [
{ name: 'text-embedding-3-small (Fast, recommended)', value: 'text-embedding-3-small' },
{ name: 'text-embedding-3-large (More accurate)', value: 'text-embedding-3-large' },
{ name: 'text-embedding-ada-002 (Legacy)', value: 'text-embedding-ada-002' }
],
when: (answers) => !answers.useDefaults
},
{
type: 'number',
name: 'chunkSize',
message: 'Maximum chunk size (tokens):',
default: 1000,
when: (answers) => !answers.useDefaults
},
{
type: 'checkbox',
name: 'features',
message: 'Select features to enable:',
choices: [
{ name: 'Auto-indexing on file changes', value: 'autoIndex', checked: true },
{ name: 'Search result caching', value: 'cache', checked: true },
{ name: 'Context persistence', value: 'persistence', checked: true },
{ name: 'Error analysis', value: 'errorAnalysis', checked: true },
{ name: 'Workflow automation', value: 'workflow', checked: true }
],
when: (answers) => !answers.useDefaults
}
]);
// Generate configuration
const config = generateConfig(projectInfo, answers);
// Write configuration file
spinner.start('Creating configuration...');
writeFileSync(configPath, config);
spinner.succeed('Configuration created');
// Create directories
spinner.start('Creating directories...');
const dirs = [
'.claude-vector-index',
'.claude-vector-cache',
'.claude-sessions'
];
for (const dir of dirs) {
const dirPath = join(process.cwd(), dir);
if (!existsSync(dirPath)) {
mkdirSync(dirPath, { recursive: true });
}
}
spinner.succeed('Directories created');
// Update .gitignore
spinner.start('Updating .gitignore...');
updateGitignore();
spinner.succeed('.gitignore updated');
// Check for API key
if (!process.env.OPENAI_API_KEY) {
console.log(chalk.yellow('\n⚠️ OpenAI API key not found'));
console.log(chalk.gray('Set your API key with: export OPENAI_API_KEY=your-key'));
}
// Success message
console.log(chalk.green('\n✅ Claude Vector Search initialized successfully!\n'));
console.log(chalk.bold('Next steps:'));
console.log(chalk.gray('1.'), 'Build the search index:', chalk.cyan('claude-search index'));
console.log(chalk.gray('2.'), 'Start searching:', chalk.cyan('claude-search search "your query"'));
console.log(chalk.gray('3.'), 'Start a task:', chalk.cyan('claude-search start "your task"'));
// 正常終了
process.exit(0);
} catch (error) {
spinner.fail(`Initialization failed: ${error.message}`);
process.exit(1);
}
}
function generateConfig(projectInfo, answers) {
const useDefaults = answers.useDefaults !== false;
const config = `/**
* Claude Vector Search Configuration
* Generated for: ${projectInfo.type} project
*/
export default {
// Project information
project: {
type: '${projectInfo.type}',
language: '${projectInfo.language}',
framework: ${projectInfo.framework ? `'${projectInfo.framework}'` : null}
},
// File patterns
patterns: {
include: [
${projectInfo.language === 'typescript' ? "'**/*.{ts,tsx}',\n " : ''}'**/*.{js,jsx}',
'**/*.{md,mdx}',
${projectInfo.type === 'nextjs' ? "'app/**/*',\n 'pages/**/*',\n " : ''}'**/*.json'
],
exclude: [
'**/node_modules/**',
'**/dist/**',
'**/build/**',
'**/.next/**',
'**/coverage/**',
'**/.git/**',
'**/tmp/**',
'**/*.min.js'
]
},
// Embedding settings
embeddings: {
model: '${useDefaults ? 'text-embedding-3-small' : answers.embeddingModel}',
batchSize: 100,
dimensions: ${useDefaults || answers.embeddingModel === 'text-embedding-3-small' ? 1536 : 3072}
},
// Chunk processing
chunks: {
maxSize: ${useDefaults ? 1000 : answers.chunkSize},
minSize: 100,
overlap: 200,
splitByParagraph: true,
preserveCodeBlocks: true
},
// Search settings
search: {
threshold: 0.7,
maxResults: 10,
includeMetadata: true
},
// Features
features: {
autoIndex: ${useDefaults || answers.features?.includes('autoIndex')},
cache: ${useDefaults || answers.features?.includes('cache')},
persistence: ${useDefaults || answers.features?.includes('persistence')},
errorAnalysis: ${useDefaults || answers.features?.includes('errorAnalysis')},
workflow: ${useDefaults || answers.features?.includes('workflow')}
},
// Cache settings
cache: {
enabled: ${useDefaults || answers.features?.includes('cache')},
ttl: 3600, // 1 hour
maxSize: '100MB'
},
// Index settings
index: {
path: '.claude-vector-index',
autoUpdate: ${useDefaults || answers.features?.includes('autoIndex')},
updateInterval: 300000 // 5 minutes
}
};
`;
return config;
}
function updateGitignore() {
const gitignorePath = join(process.cwd(), '.gitignore');
const ignorePatterns = [
'\n# Claude Vector Search',
'.claude-vector-index/',
'.claude-vector-cache/',
'.claude-sessions/',
'.env.local'
];
try {
let content = '';
if (existsSync(gitignorePath)) {
content = readFileSync(gitignorePath, 'utf-8');
}
// Check if patterns already exist
const patternsToAdd = ignorePatterns.filter(pattern =>
!content.includes(pattern.replace('\n# Claude Vector Search', ''))
);
if (patternsToAdd.length > 0) {
content += '\n' + patternsToAdd.join('\n') + '\n';
writeFileSync(gitignorePath, content);
}
} catch (error) {
console.warn(chalk.yellow('Warning: Could not update .gitignore'));
}
}