@claude-vector/cli
Version:
CLI for Claude-integrated vector search
295 lines (248 loc) ⢠10.4 kB
JavaScript
/**
* 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();
}