- Updated all fs, path, crypto, os, url, util, events, http, https, net, child_process, stream, and zlib imports
- Changed both static imports and dynamic imports to use node: protocol
- This makes Brainy more bundler-friendly by explicitly marking Node.js built-ins
- Prevents bundlers from attempting to polyfill or bundle these modules
- Reduces bundle size for web applications using Brainy
- Improves tree-shaking and dead code elimination
Benefits for external bundlers:
- Clear distinction between Node.js built-ins and external dependencies
- No ambiguity about what needs polyfilling
- Smaller bundles for browser builds
- Better compatibility with modern bundlers (Webpack 5, Vite, Rollup, esbuild)
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
440 lines
No EOL
13 KiB
TypeScript
440 lines
No EOL
13 KiB
TypeScript
/**
|
|
* Augmentation Catalog for CLI
|
|
*
|
|
* Displays available augmentations catalog
|
|
* Local catalog with caching support
|
|
*/
|
|
|
|
import chalk from 'chalk'
|
|
import { readFileSync, writeFileSync, existsSync } from 'node:fs'
|
|
import { join } from 'node:path'
|
|
import { homedir } from 'node: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
|
|
|
|
interface Augmentation {
|
|
id: string
|
|
name: string
|
|
description: string
|
|
category: string
|
|
status: 'available' | 'coming_soon' | 'deprecated'
|
|
popular?: boolean
|
|
eta?: string
|
|
}
|
|
|
|
interface Category {
|
|
id: string
|
|
name: string
|
|
icon: string
|
|
description: string
|
|
}
|
|
|
|
interface Catalog {
|
|
version: string
|
|
categories: Category[]
|
|
augmentations: Augmentation[]
|
|
}
|
|
|
|
/**
|
|
* Fetch catalog from API with caching
|
|
*/
|
|
export async function fetchCatalog(): Promise<Catalog | null> {
|
|
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: {
|
|
category?: string
|
|
search?: string
|
|
detailed?: boolean
|
|
}) {
|
|
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 <name>" for details'))
|
|
}
|
|
|
|
/**
|
|
* Show detailed info about an augmentation
|
|
*/
|
|
export async function showAugmentationInfo(id: string) {
|
|
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: string) => 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: string) => console.log(` • ${c}`))
|
|
console.log('')
|
|
}
|
|
|
|
if (details.pricing) {
|
|
console.log(chalk.bold('Available in:'))
|
|
details.pricing.tiers.forEach((t: string) => 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?: string) {
|
|
// 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): Catalog | null {
|
|
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: Catalog): void {
|
|
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: Augmentation[], categories: Category[]) {
|
|
const grouped: Record<string, Augmentation[]> = {}
|
|
|
|
for (const aug of augmentations) {
|
|
if (!grouped[aug.category]) {
|
|
grouped[aug.category] = []
|
|
}
|
|
grouped[aug.category].push(aug)
|
|
}
|
|
|
|
// Sort by category order
|
|
const ordered: Record<string, Augmentation[]> = {}
|
|
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: string): string {
|
|
switch (status) {
|
|
case 'available': return chalk.green('✅')
|
|
case 'coming_soon': return chalk.yellow('🔜')
|
|
case 'deprecated': return chalk.red('⚠️')
|
|
default: return '❓'
|
|
}
|
|
}
|
|
|
|
function getStatusText(status: string): string {
|
|
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: string, categories: Category[]): string {
|
|
const cat = categories.find(c => c.id === categoryId)
|
|
return cat ? `${cat.icon} ${cat.name}` : categoryId
|
|
}
|
|
|
|
function readLicenseFile(): string | null {
|
|
try {
|
|
const licensePath = join(homedir(), '.brainy', 'license')
|
|
if (existsSync(licensePath)) {
|
|
return readFileSync(licensePath, 'utf8').trim()
|
|
}
|
|
} catch (error) {
|
|
// License file read failed, return null
|
|
console.debug('Failed to read license file:', error)
|
|
}
|
|
return null
|
|
}
|
|
|
|
function getDefaultCatalog(): Catalog {
|
|
// 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: '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'
|
|
}
|
|
]
|
|
}
|
|
} |