/** * Utility CLI Commands - TypeScript Implementation * * Database maintenance, statistics, and benchmarking */ import chalk from 'chalk'; import ora from 'ora'; import Table from 'cli-table3'; import { BrainyData } from '../../brainyData.js'; let brainyInstance = null; const getBrainy = async () => { if (!brainyInstance) { brainyInstance = new BrainyData(); await brainyInstance.init(); } return brainyInstance; }; const formatBytes = (bytes) => { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; const formatOutput = (data, options) => { if (options.json) { console.log(options.pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data)); } }; export const utilityCommands = { /** * Show database statistics */ async stats(options) { const spinner = ora('Gathering statistics...').start(); try { const brain = await getBrainy(); const stats = await brain.getStatistics(); const memUsage = process.memoryUsage(); spinner.succeed('Statistics gathered'); if (options.json) { formatOutput(stats, options); return; } console.log(chalk.cyan('\nšŸ“Š Database Statistics\n')); // Core stats table const coreTable = new Table({ head: [chalk.cyan('Metric'), chalk.cyan('Value')], style: { head: [], border: [] } }); coreTable.push(['Total Items', chalk.green(stats.nounCount + stats.verbCount + stats.metadataCount || 0)], ['Nouns', chalk.green(stats.nounCount || 0)], ['Verbs (Relationships)', chalk.green(stats.verbCount || 0)], ['Metadata Records', chalk.green(stats.metadataCount || 0)]); console.log(coreTable.toString()); // Service breakdown if available if (options.byService && stats.serviceBreakdown) { console.log(chalk.cyan('\nšŸ”§ Service Breakdown\n')); const serviceTable = new Table({ head: [chalk.cyan('Service'), chalk.cyan('Nouns'), chalk.cyan('Verbs'), chalk.cyan('Metadata')], style: { head: [], border: [] } }); Object.entries(stats.serviceBreakdown).forEach(([service, serviceStats]) => { serviceTable.push([ service, serviceStats.nounCount || 0, serviceStats.verbCount || 0, serviceStats.metadataCount || 0 ]); }); console.log(serviceTable.toString()); } // Storage info if (stats.storage) { console.log(chalk.cyan('\nšŸ’¾ Storage\n')); const storageTable = new Table({ head: [chalk.cyan('Property'), chalk.cyan('Value')], style: { head: [], border: [] } }); storageTable.push(['Type', stats.storage.type || 'Unknown'], ['Size', stats.storage.size ? formatBytes(stats.storage.size) : 'N/A'], ['Location', stats.storage.location || 'N/A']); console.log(storageTable.toString()); } // Performance metrics if (stats.performance && options.detailed) { console.log(chalk.cyan('\n⚔ Performance\n')); const perfTable = new Table({ head: [chalk.cyan('Metric'), chalk.cyan('Value')], style: { head: [], border: [] } }); if (stats.performance.avgQueryTime) { perfTable.push(['Avg Query Time', `${stats.performance.avgQueryTime.toFixed(2)} ms`]); } if (stats.performance.totalQueries) { perfTable.push(['Total Queries', stats.performance.totalQueries]); } if (stats.performance.cacheHitRate) { perfTable.push(['Cache Hit Rate', `${(stats.performance.cacheHitRate * 100).toFixed(1)}%`]); } console.log(perfTable.toString()); } // Memory usage console.log(chalk.cyan('\n🧠 Memory Usage\n')); const memTable = new Table({ head: [chalk.cyan('Type'), chalk.cyan('Size')], style: { head: [], border: [] } }); memTable.push(['Heap Used', formatBytes(memUsage.heapUsed)], ['Heap Total', formatBytes(memUsage.heapTotal)], ['RSS', formatBytes(memUsage.rss)], ['External', formatBytes(memUsage.external)]); console.log(memTable.toString()); // Index info if (stats.index && options.detailed) { console.log(chalk.cyan('\nšŸŽÆ Vector Index\n')); const indexTable = new Table({ head: [chalk.cyan('Property'), chalk.cyan('Value')], style: { head: [], border: [] } }); indexTable.push(['Dimensions', stats.index.dimensions || 'N/A'], ['Indexed Vectors', stats.index.vectorCount || 0], ['Index Size', stats.index.indexSize ? formatBytes(stats.index.indexSize) : 'N/A']); console.log(indexTable.toString()); } } catch (error) { spinner.fail('Failed to gather statistics'); console.error(chalk.red(error.message)); process.exit(1); } }, /** * Clean and optimize database */ async clean(options) { const spinner = ora('Cleaning database...').start(); try { const brain = await getBrainy(); const tasks = []; if (options.removeOrphans) { spinner.text = 'Removing orphaned items...'; tasks.push('Removed orphaned items'); // Implementation would go here await new Promise(resolve => setTimeout(resolve, 500)); // Simulate work } if (options.rebuildIndex) { spinner.text = 'Rebuilding search index...'; tasks.push('Rebuilt search index'); // Implementation would go here await new Promise(resolve => setTimeout(resolve, 1000)); // Simulate work } if (tasks.length === 0) { spinner.text = 'Running general cleanup...'; tasks.push('General cleanup completed'); // Run general cleanup tasks await new Promise(resolve => setTimeout(resolve, 500)); // Simulate work } spinner.succeed('Database cleaned'); if (!options.json) { console.log(chalk.green('\nāœ“ Cleanup completed:')); tasks.forEach(task => { console.log(chalk.dim(` • ${task}`)); }); // Get new stats const stats = await brain.getStatistics(); console.log(chalk.cyan('\nDatabase Status:')); console.log(` Total items: ${stats.nounCount + stats.verbCount}`); console.log(` Index status: ${chalk.green('Healthy')}`); } else { formatOutput({ tasks, success: true }, options); } } catch (error) { spinner.fail('Cleanup failed'); console.error(chalk.red(error.message)); process.exit(1); } }, /** * Run performance benchmarks */ async benchmark(options) { const operations = options.operations || 'all'; const iterations = parseInt(options.iterations || '100'); console.log(chalk.cyan(`\nšŸš€ Running Benchmarks (${iterations} iterations)\n`)); const results = { operations: {}, summary: {} }; try { const brain = await getBrainy(); // Benchmark different operations const benchmarks = [ { name: 'add', enabled: operations === 'all' || operations.includes('add') }, { name: 'search', enabled: operations === 'all' || operations.includes('search') }, { name: 'similarity', enabled: operations === 'all' || operations.includes('similarity') }, { name: 'cluster', enabled: operations === 'all' || operations.includes('cluster') } ]; for (const bench of benchmarks) { if (!bench.enabled) continue; const spinner = ora(`Benchmarking ${bench.name}...`).start(); const times = []; for (let i = 0; i < iterations; i++) { const start = Date.now(); switch (bench.name) { case 'add': await brain.add(`Test item ${i}`, { benchmark: true }); break; case 'search': await brain.search('test', 10); break; case 'similarity': const neural = brain.neural; await neural.similar('test1', 'test2'); break; case 'cluster': const neuralApi = brain.neural; await neuralApi.clusters(); break; } times.push(Date.now() - start); } // Calculate statistics const avg = times.reduce((a, b) => a + b, 0) / times.length; const min = Math.min(...times); const max = Math.max(...times); const median = times.sort((a, b) => a - b)[Math.floor(times.length / 2)]; results.operations[bench.name] = { avg: avg.toFixed(2), min, max, median, ops: (1000 / avg).toFixed(2) }; spinner.succeed(`${bench.name}: ${avg.toFixed(2)}ms avg (${(1000 / avg).toFixed(2)} ops/sec)`); } // Calculate summary const totalOps = Object.values(results.operations).reduce((sum, op) => sum + parseFloat(op.ops), 0); results.summary = { totalOperations: Object.keys(results.operations).length, averageOpsPerSec: (totalOps / Object.keys(results.operations).length).toFixed(2) }; if (!options.json) { // Display results table console.log(chalk.cyan('\nšŸ“Š Benchmark Results\n')); const table = new Table({ head: [ chalk.cyan('Operation'), chalk.cyan('Avg (ms)'), chalk.cyan('Min (ms)'), chalk.cyan('Max (ms)'), chalk.cyan('Median (ms)'), chalk.cyan('Ops/sec') ], style: { head: [], border: [] } }); Object.entries(results.operations).forEach(([op, stats]) => { table.push([ op, stats.avg, stats.min, stats.max, stats.median, chalk.green(stats.ops) ]); }); console.log(table.toString()); console.log(chalk.cyan('\nšŸ“ˆ Summary')); console.log(` Operations tested: ${results.summary.totalOperations}`); console.log(` Average throughput: ${chalk.green(results.summary.averageOpsPerSec)} ops/sec`); } else { formatOutput(results, options); } } catch (error) { console.error(chalk.red('Benchmark failed:'), error.message); process.exit(1); } } }; //# sourceMappingURL=utility.js.map