UNPKG

@claude-vector/cli

Version:

CLI for Claude-integrated vector search

295 lines (248 loc) • 10.4 kB
/** * Status command - Show system and session status */ import chalk from 'chalk'; import { SessionManager, ContextManager, QueryOptimizer } from '@claude-vector/claude-tools'; import { VectorSearchEngine, SimpleCache } from '@claude-vector/core'; import { existsSync, readFileSync } from 'fs'; import { join } from 'path'; export async function statusCommand(options) { console.log(chalk.bold('\nšŸ“Š Claude Vector Search Status\n')); try { // Show index status if (options.index || (!options.sessions && !options.cache)) { await showIndexStatus(); } // Show session status if (options.sessions || (!options.index && !options.cache)) { await showSessionStatus(); } // Show cache status if (options.cache) { await showCacheStatus(); } // Show learning status if (options.learning) { await showLearningStatus(); } // Show current context if (!options.sessions && !options.cache && !options.index && !options.learning) { await showCurrentContext(); } // 正常終了 process.exit(0); } catch (error) { console.error(chalk.red(`Error: ${error.message}`)); process.exit(1); } } async function showIndexStatus() { console.log(chalk.bold('šŸ—‚ļø Index Status:')); const indexPath = join(process.cwd(), '.claude-vector-index'); const metadataPath = join(indexPath, 'metadata.json'); if (!existsSync(metadataPath)) { console.log(chalk.yellow('No index found')); console.log(chalk.gray('Run'), chalk.cyan('claude-search index'), chalk.gray('to build the index')); return; } try { const metadata = JSON.parse(readFileSync(metadataPath, 'utf-8')); console.log(chalk.gray('Version:'), metadata.version); console.log(chalk.gray('Created:'), new Date(metadata.created).toLocaleString()); console.log(chalk.gray('Project type:'), metadata.projectType); console.log(chalk.gray('Language:'), metadata.language); console.log(chalk.gray('Files indexed:'), metadata.files); console.log(chalk.gray('Chunks:'), metadata.chunks); console.log(chalk.gray('Embedding model:'), metadata.model); // Check if index is stale const created = new Date(metadata.created); const age = Date.now() - created.getTime(); const days = Math.floor(age / (1000 * 60 * 60 * 24)); if (days > 7) { console.log(chalk.yellow(`\nāš ļø Index is ${days} days old. Consider rebuilding.`)); } } catch (error) { console.log(chalk.red('Error reading index metadata')); } console.log(); } async function showSessionStatus() { console.log(chalk.bold('šŸ”„ Session Status:')); try { const sessionManager = new SessionManager(); const currentSession = await sessionManager.getCurrentSessionStatus(); const allSessions = await sessionManager.getAllSessions(); if (currentSession) { console.log(chalk.gray('Current session:'), currentSession.sessionId); console.log(chalk.gray('Task:'), currentSession.task); console.log(chalk.gray('Type:'), currentSession.taskType); console.log(chalk.gray('Duration:'), `${currentSession.duration}s`); console.log(chalk.gray('Activities:'), currentSession.activities); console.log(chalk.gray('Searches:'), currentSession.searches); if (currentSession.contextStats) { console.log(chalk.gray('Context:'), `${currentSession.contextStats.totalItems} items, ${currentSession.contextStats.usedTokens} tokens`); } } else { console.log(chalk.yellow('No active session')); } console.log(chalk.gray('Total sessions:'), allSessions.length); if (allSessions.length > 0) { console.log(chalk.bold('\nRecent Sessions:')); allSessions.slice(0, 5).forEach(session => { const status = session.id === currentSession?.sessionId ? chalk.green('[ACTIVE]') : ''; console.log(chalk.gray(`- ${session.id.slice(0, 8)}...`), session.task.slice(0, 50), status); }); } } catch (error) { console.log(chalk.yellow('Session information unavailable')); } console.log(); } async function showCacheStatus() { console.log(chalk.bold('šŸ’¾ Cache Status:')); try { const cachePath = join(process.cwd(), '.claude-vector-cache'); const cache = new SimpleCache(join(cachePath, 'queries')); const stats = await cache.getStats(); console.log(chalk.gray('Total entries:'), stats.total); console.log(chalk.gray('Valid entries:'), stats.valid); console.log(chalk.gray('Expired entries:'), stats.expired); console.log(chalk.gray('Total size:'), stats.totalSize); console.log(chalk.gray('TTL:'), `${stats.ttl}s`); if (stats.expired > 0) { console.log(chalk.yellow(`\nāš ļø ${stats.expired} expired entries. Run cleanup to free space.`)); } } catch (error) { console.log(chalk.yellow('Cache unavailable or empty')); } console.log(); } async function showCurrentContext() { console.log(chalk.bold('šŸ“„ Current Context:')); try { const contextManager = new ContextManager(); const stats = contextManager.getStatistics(); const context = contextManager.getContext(); console.log(chalk.gray('Items:'), stats.totalItems); console.log(chalk.gray('Tokens:'), `${stats.currentTokens}/${stats.maxTokens}`); console.log(chalk.gray('Usage:'), `${stats.utilizationPercentage}%`); if (context.length > 0) { console.log(chalk.bold('\nContext Items:')); context.slice(0, 5).forEach(item => { const tokens = item.tokens || 0; console.log(chalk.gray(`- [${item.type}]`), item.source || 'Unknown', chalk.dim(`(${tokens} tokens)`)); }); if (context.length > 5) { console.log(chalk.gray(` ... and ${context.length - 5} more items`)); } } else { console.log(chalk.yellow('\nNo items in context')); } } catch (error) { console.log(chalk.yellow('Context unavailable')); } } async function showLearningStatus() { console.log(chalk.bold('🧠 Learning Status:')); try { const queryOptimizer = new QueryOptimizer(); const history = await queryOptimizer.getHistory(); // Calculate statistics const totalQueries = Object.keys(history.queries || {}).length; const totalFeedback = Object.values(history.queries || {}) .reduce((sum, queryData) => { // queryData could be an array of feedback entries if (Array.isArray(queryData)) { return sum + queryData.length; } // Or it could have a feedback property return sum + (queryData.feedback?.length || 0); }, 0); // Get successful patterns const successfulPatterns = Object.entries(history.queries || {}) .filter(([_, data]) => { // Handle array format const feedback = Array.isArray(data) ? data : (data.feedback || []); const avgRating = feedback.length > 0 ? feedback.reduce((sum, f) => sum + (f.rating || (f.useful ? 5 : 1)), 0) / feedback.length : 0; return avgRating >= 4; }) .map(([query, data]) => { // Handle array format const feedback = Array.isArray(data) ? data : (data.feedback || []); const avgRating = feedback.length > 0 ? feedback.reduce((sum, f) => sum + (f.rating || (f.useful ? 5 : 1)), 0) / feedback.length : 0; return { query, count: feedback.length, avgRating }; }) .sort((a, b) => b.avgRating - a.avgRating) .slice(0, 5); // Get task type distribution const taskTypes = {}; Object.values(history.queries || {}).forEach(data => { // Handle array format const feedback = Array.isArray(data) ? data : (data.feedback || []); feedback.forEach(f => { const type = f.taskType || 'general'; taskTypes[type] = (taskTypes[type] || 0) + 1; }); }); // Display statistics console.log(chalk.gray('Total queries processed:'), totalQueries); console.log(chalk.gray('Feedback entries:'), totalFeedback); console.log(chalk.gray('Learning data size:'), `${JSON.stringify(history).length} bytes`); // Display successful patterns if (successfulPatterns.length > 0) { console.log(chalk.bold('\n🌟 Most Successful Patterns:')); successfulPatterns.forEach((pattern, i) => { const stars = '⭐'.repeat(Math.round(pattern.avgRating)); console.log(chalk.gray(`${i + 1}.`), pattern.query.slice(0, 50), chalk.dim(`(${pattern.count} uses, ${stars})`)); }); } // Display task type distribution if (Object.keys(taskTypes).length > 0) { console.log(chalk.bold('\nšŸ“Š Task Type Distribution:')); Object.entries(taskTypes) .sort((a, b) => b[1] - a[1]) .forEach(([type, count]) => { const percentage = ((count / totalFeedback) * 100).toFixed(1); console.log(chalk.gray(`- ${type}:`), `${count} (${percentage}%)`); }); } // Display expansion mappings const expansions = Object.entries(history.expansions || {}) .sort((a, b) => (b[1].uses || 0) - (a[1].uses || 0)) .slice(0, 5); if (expansions.length > 0) { console.log(chalk.bold('\nšŸ”¤ Common Abbreviations:')); expansions.forEach(([abbr, data]) => { console.log(chalk.gray(`- "${abbr}" →`), `"${data.expanded}"`, chalk.dim(`(${data.uses || 0} uses)`)); }); } // Learning insights console.log(chalk.bold('\nšŸ’” Learning Insights:')); if (totalQueries === 0) { console.log(chalk.yellow('• No learning data yet - use search and provide feedback')); } else if (totalFeedback < totalQueries * 0.2) { console.log(chalk.yellow('• Low feedback rate - use "claude-search feedback" after searches')); } else { console.log(chalk.green('• Active learning from user feedback')); if (successfulPatterns.length > 0) { console.log(chalk.green(`• ${successfulPatterns.length} highly effective search patterns identified`)); } } } catch (error) { console.log(chalk.yellow('Learning data unavailable')); if (process.env.DEBUG) { console.error(chalk.gray(error.stack)); } } console.log(); }