/** * Augmentation Catalog for CLI * * Displays available augmentations catalog * Local catalog with caching support */ import chalk from 'chalk'; import { readFileSync, writeFileSync, existsSync } from 'fs'; import { join } from 'path'; import { homedir } from 'os'; const CATALOG_API = process.env.BRAINY_CATALOG_URL || null; const CACHE_PATH = join(homedir(), '.brainy', 'catalog-cache.json'); const CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours /** * Fetch catalog from API with caching */ export async function fetchCatalog() { try { // Check cache first const cached = loadCache(); if (cached) return cached; // If external catalog API is configured, try to fetch if (CATALOG_API) { const response = await fetch(`${CATALOG_API}/api/catalog/cli`); if (!response.ok) throw new Error('API unavailable'); const catalog = await response.json(); // Save to cache saveCache(catalog); return catalog; } // Fall back to local catalog return getDefaultCatalog(); } catch (error) { // Try loading from cache even if expired const cached = loadCache(true); if (cached) { console.log(chalk.yellow('📡 Using cached catalog')); return cached; } // Fall back to hardcoded catalog return getDefaultCatalog(); } } /** * Display catalog in CLI */ export async function showCatalog(options) { const catalog = await fetchCatalog(); if (!catalog) { console.log(chalk.red('❌ Could not load augmentation catalog')); return; } console.log(chalk.cyan.bold('🧠 Brainy Augmentation Catalog')); console.log(chalk.gray(`Version ${catalog.version}`)); console.log(''); // Filter augmentations let augmentations = catalog.augmentations; if (options.category) { augmentations = augmentations.filter(a => a.category === options.category); } if (options.search) { const query = options.search.toLowerCase(); augmentations = augmentations.filter(a => a.name.toLowerCase().includes(query) || a.description.toLowerCase().includes(query)); } // Group by category const grouped = groupByCategory(augmentations, catalog.categories); // Display for (const [category, augs] of Object.entries(grouped)) { if (augs.length === 0) continue; const cat = catalog.categories.find(c => c.id === category); console.log(chalk.bold(`${cat?.icon || '📦'} ${cat?.name || category}`)); for (const aug of augs) { const status = getStatusIcon(aug.status); const popular = aug.popular ? chalk.yellow(' ⭐') : ''; const eta = aug.eta ? chalk.gray(` (${aug.eta})`) : ''; console.log(` ${status} ${aug.name}${popular}${eta}`); if (options.detailed) { console.log(chalk.gray(` ${aug.description}`)); } } console.log(''); } // Show summary const available = augmentations.filter(a => a.status === 'available').length; const coming = augmentations.filter(a => a.status === 'coming_soon').length; console.log(chalk.gray('─'.repeat(50))); console.log(chalk.green(`✅ ${available} available`) + chalk.gray(` • `) + chalk.yellow(`🔜 ${coming} coming soon`)); console.log(''); console.log(chalk.dim('Configure augmentations with "brainy augment"')); console.log(chalk.dim('Run "brainy augment info " for details')); } /** * Show detailed info about an augmentation */ export async function showAugmentationInfo(id) { const catalog = await fetchCatalog(); if (!catalog) { console.log(chalk.red('❌ Could not load augmentation catalog')); return; } const aug = catalog.augmentations.find(a => a.id === id); if (!aug) { console.log(chalk.red(`❌ Augmentation not found: ${id}`)); console.log(''); console.log('Available augmentations:'); catalog.augmentations.forEach(a => { console.log(` • ${a.id}`); }); return; } // Fetch full details from API if available try { if (!CATALOG_API) throw new Error('No external catalog configured'); const response = await fetch(`${CATALOG_API}/api/catalog/augmentation/${id}`); const details = await response.json(); console.log(chalk.cyan.bold(`📦 ${details.name}`)); if (details.popular) console.log(chalk.yellow('⭐ Popular')); console.log(''); console.log(chalk.bold('Category:'), getCategoryName(details.category, catalog.categories)); console.log(chalk.bold('Status:'), getStatusText(details.status)); if (details.eta) console.log(chalk.bold('Expected:'), details.eta); console.log(''); console.log(chalk.bold('Description:')); console.log(details.longDescription || details.description); console.log(''); if (details.features) { console.log(chalk.bold('Features:')); details.features.forEach((f) => console.log(` ✓ ${f}`)); console.log(''); } if (details.example) { console.log(chalk.bold('Example:')); console.log(chalk.gray('─'.repeat(50))); console.log(details.example.code); console.log(chalk.gray('─'.repeat(50))); console.log(''); } if (details.requirements?.config) { console.log(chalk.bold('Required Configuration:')); details.requirements.config.forEach((c) => console.log(` • ${c}`)); console.log(''); } if (details.pricing) { console.log(chalk.bold('Available in:')); details.pricing.tiers.forEach((t) => console.log(` • ${t}`)); console.log(''); } console.log(chalk.dim('To activate: brainy augment activate')); } catch (error) { // Show basic info if API fails console.log(chalk.cyan.bold(`📦 ${aug.name}`)); console.log(aug.description); console.log(''); console.log(chalk.dim('Full details unavailable (no external catalog configured)')); } } /** * Show user's available augmentations */ export async function showAvailable(licenseKey) { // Show local catalog as default const catalog = await fetchCatalog(); if (!catalog) { console.log(chalk.red('❌ Could not load augmentation catalog')); return; } console.log(chalk.cyan.bold('🧠 Available Augmentations')); console.log(''); const available = catalog.augmentations.filter(a => a.status === 'available'); const grouped = groupByCategory(available, catalog.categories); for (const [category, augs] of Object.entries(grouped)) { if (augs.length === 0) continue; const cat = catalog.categories.find(c => c.id === category); console.log(chalk.bold(`${cat?.icon || '📦'} ${cat?.name || category}`)); augs.forEach(aug => { console.log(` ✅ ${aug.name}`); console.log(chalk.gray(` ${aug.description}`)); }); console.log(''); } console.log(chalk.green(`✅ ${available.length} augmentations available`)); // If external API is configured and license key provided, try to fetch personalized data if (CATALOG_API && licenseKey) { try { const response = await fetch(`${CATALOG_API}/api/catalog/available`, { headers: { 'x-license-key': licenseKey } }); if (response.ok) { const data = await response.json(); console.log(chalk.gray(`Plan: ${data.plan || 'Standard'}`)); if (data.operations) { const used = data.operations.used || 0; const limit = data.operations.limit; const percent = limit === 'unlimited' ? 0 : Math.round((used / limit) * 100); console.log(chalk.bold('Usage:')); if (limit === 'unlimited') { console.log(` Unlimited operations`); } else { console.log(` ${used.toLocaleString()} / ${limit.toLocaleString()} operations (${percent}%)`); } } } } catch (error) { // Ignore external API errors - local catalog is sufficient } } } // Helper functions function loadCache(ignoreExpiry = false) { try { if (!existsSync(CACHE_PATH)) return null; const data = JSON.parse(readFileSync(CACHE_PATH, 'utf8')); if (!ignoreExpiry && Date.now() - data.timestamp > CACHE_TTL) { return null; } return data.catalog; } catch { return null; } } function saveCache(catalog) { try { const dir = join(homedir(), '.brainy'); if (!existsSync(dir)) { require('fs').mkdirSync(dir, { recursive: true }); } writeFileSync(CACHE_PATH, JSON.stringify({ catalog, timestamp: Date.now() })); } catch { // Ignore cache save errors } } function groupByCategory(augmentations, categories) { const grouped = {}; for (const aug of augmentations) { if (!grouped[aug.category]) { grouped[aug.category] = []; } grouped[aug.category].push(aug); } // Sort by category order const ordered = {}; const categoryOrder = ['memory', 'coordination', 'enterprise', 'perception', 'dialog', 'activation', 'cognition', 'websocket']; for (const cat of categoryOrder) { if (grouped[cat]) { ordered[cat] = grouped[cat]; } } return ordered; } function getStatusIcon(status) { switch (status) { case 'available': return chalk.green('✅'); case 'coming_soon': return chalk.yellow('🔜'); case 'deprecated': return chalk.red('⚠️'); default: return '❓'; } } function getStatusText(status) { switch (status) { case 'available': return chalk.green('Available'); case 'coming_soon': return chalk.yellow('Coming Soon'); case 'deprecated': return chalk.red('Deprecated'); default: return 'Unknown'; } } function getCategoryName(categoryId, categories) { const cat = categories.find(c => c.id === categoryId); return cat ? `${cat.icon} ${cat.name}` : categoryId; } function readLicenseFile() { try { const licensePath = join(homedir(), '.brainy', 'license'); if (existsSync(licensePath)) { return readFileSync(licensePath, 'utf8').trim(); } } catch { } return null; } function getDefaultCatalog() { // Local catalog with current features return { version: '1.5.0', categories: [ { id: 'core', name: 'Core Features', icon: '🧠', description: 'Essential brainy functionality' }, { id: 'neural', name: 'Neural API', icon: '🔗', description: 'Semantic similarity and clustering' }, { id: 'enterprise', name: 'Enterprise', icon: '🏢', description: 'Business integrations' }, { id: 'storage', name: 'Storage', icon: '💾', description: 'Data persistence and caching' } ], augmentations: [ { id: 'vector-search', name: 'Vector Search', category: 'core', description: 'High-performance semantic search with HNSW indexing', status: 'available', popular: true }, { id: 'neural-similarity', name: 'Neural Similarity API', category: 'neural', description: 'Advanced semantic similarity, clustering, and hierarchy detection', status: 'available', popular: true }, { id: 'intelligent-verb-scoring', name: 'Intelligent Verb Scoring', category: 'neural', description: 'Smart relationship scoring with taxonomy understanding', status: 'available' }, { id: 'wal-augmentation', name: 'WAL-based Augmentation', category: 'enterprise', description: 'Write-ahead log for reliable augmentation processing', status: 'available' }, { id: 'connection-pooling', name: 'Connection Pooling', category: 'enterprise', description: 'Efficient database connection management', status: 'available' }, { id: 'batch-processing', name: 'Batch Processing', category: 'enterprise', description: 'High-throughput batch operations with deduplication', status: 'available' }, { id: 's3-storage', name: 'S3 Compatible Storage', category: 'storage', description: 'Cloud storage with optimized batch operations', status: 'available' }, { id: 'opfs-storage', name: 'OPFS Storage', category: 'storage', description: 'Browser-based persistent storage', status: 'available' } ] }; } //# sourceMappingURL=catalog.js.map