feat: Add Brain Cloud integration and catalog command

- Add brainy cloud setup command for auto-provisioning
- Add brainy catalog command for viewing augmentations
- Update CLI help with Brain Cloud commands
- Improve cloud connection flow
This commit is contained in:
David Snelling 2025-08-11 13:02:29 -07:00
parent b9ce67f64c
commit 6de6adec17
3 changed files with 896 additions and 12 deletions

View file

@ -4,7 +4,8 @@
[![npm version](https://badge.fury.io/js/%40soulcraft%2Fbrainy.svg)](https://badge.fury.io/js/%40soulcraft%2Fbrainy)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Try Demo](https://img.shields.io/badge/Try%20Demo-Live-green.svg)](https://soulcraft.com/console)
[![Try Demo](https://img.shields.io/badge/Try%20Demo-Live-green.svg)](https://soulcraft.com)
[![Brain Cloud](https://img.shields.io/badge/Brain%20Cloud-Early%20Access-blue.svg)](https://soulcraft.com/brain-cloud)
[![Node.js](https://img.shields.io/badge/node-%3E%3D24.4.1-brightgreen.svg)](https://nodejs.org/)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.4.5-blue.svg)](https://www.typescriptlang.org/)
@ -107,6 +108,7 @@ Try Brainy instantly in your browser. No signup. No credit card.
## ⚡ Quick Start (60 Seconds)
### Open Source (Local Storage)
```bash
npm install @soulcraft/brainy
```
@ -125,6 +127,31 @@ await brain.addVerb("Elon Musk", "founded", "Tesla")
// Search naturally
const results = await brain.search("companies founded by Elon")
```
### ☁️ Brain Cloud (AI Memory + Agent Coordination)
```bash
# Auto-setup with cloud instance provisioning (RECOMMENDED)
brainy cloud setup --email your@email.com
# Or install manually
npm install @soulcraft/brainy @soulcraft/brain-cloud
```
```javascript
import { BrainyData, Cortex } from '@soulcraft/brainy'
import { AIMemory, AgentCoordinator } from '@soulcraft/brain-cloud'
const brain = new BrainyData()
const cortex = new Cortex()
// Add premium augmentations (requires Early Access license)
cortex.register(new AIMemory())
cortex.register(new AgentCoordinator())
// Now your AI remembers everything across all sessions!
await brain.add("User prefers TypeScript over JavaScript")
// This memory persists and syncs across all devices
// Returns: SpaceX and Tesla with relevance scores
// Query relationships

View file

@ -204,24 +204,138 @@ program
console.log(chalk.cyan('Restart Claude Code to activate memory.'))
} else {
console.log(chalk.yellow('No Brain Cloud found. Setting up:'))
console.log('\n1. Visit: ' + chalk.cyan('https://soulcraft.com'))
console.log('2. Sign up for Brain Cloud')
console.log('3. Run ' + chalk.green('brainy connect') + ' again')
console.log('\n1. Visit: ' + chalk.cyan('https://soulcraft.com/brain-cloud'))
console.log('2. Get your Early Access license key')
console.log('3. Run ' + chalk.green('brainy cloud setup') + ' for auto-configuration')
}
} catch (error) {
console.log(chalk.red('❌ Setup failed:'), error.message)
}
}))
// Moved to brainy cloud setup command below for better separation
// ========================================
// BRAIN CLOUD COMMANDS (Premium Features)
// ========================================
const cloud = program
.command('cloud')
.description('Brain Cloud premium features and management')
cloud
.command('setup')
.description('🚀 Auto-setup Brain Cloud (provisions cloud instance + configures locally)')
.option('--email <email>', 'Your email address')
.action(wrapInteractive(async (options) => {
console.log(chalk.cyan('🧠☁️ Brain Cloud Auto-Setup'))
console.log(chalk.gray('═'.repeat(50)))
console.log(chalk.yellow('Perfect for non-coders! One-click setup.\n'))
try {
// Step 1: Validate license
await validateLicense()
// Step 2: Check if Brainy is installed
await ensureBrainyInstalled()
// Step 3: Provision cloud instance
const instance = await provisionCloudInstance(options.email)
// Step 4: Configure local Brainy
await configureBrainy(instance)
// Step 5: Install Brain Cloud package
await installBrainCloudPackage()
// Step 6: Test connection
await testConnection(instance)
console.log('\n✅ Setup Complete!')
console.log(chalk.gray('═'.repeat(30)))
console.log('\nYour Brain Cloud instance is ready:')
console.log(`📱 Dashboard: ${chalk.cyan(instance.endpoints.dashboard)}`)
console.log(`🔗 API: ${chalk.gray(instance.endpoints.api)}`)
console.log('\n🚀 What\'s next?')
console.log('• Your AI now has persistent memory across all conversations')
console.log('• All devices sync automatically to your cloud instance')
console.log('• Agents coordinate seamlessly through handoffs')
console.log('\n💡 Try asking Claude: "Remember that I prefer TypeScript"')
console.log(' Then in a new conversation: "What do you know about my preferences?"')
} catch (error) {
console.error('\n❌ Setup failed:', error.message)
console.log('\n🆘 Need help? Contact support@soulcraft.com')
}
}))
cloud
.command('connect [id]')
.description('Connect to existing Brain Cloud instance')
.action(wrapInteractive(async (id) => {
if (id) {
console.log(chalk.green(`✅ Connecting to Brain Cloud instance: ${id}`))
// Connect to specific instance
} else {
// Show connection instructions
console.log(chalk.cyan('\n🔗 Brain Cloud Connection'))
console.log(chalk.gray('━'.repeat(40)))
console.log('\nOptions:')
console.log('1. ' + chalk.green('brainy cloud setup') + ' - Auto-setup with provisioning')
console.log('2. ' + chalk.green('brainy cloud connect <id>') + ' - Connect to existing instance')
console.log('\nGet started: ' + chalk.cyan('https://soulcraft.com/brain-cloud'))
}
}))
cloud
.command('status [id]')
.description('Check Brain Cloud instance status')
.action(wrapInteractive(async (id) => {
// Implementation moved from old cloud command
console.log('Checking Brain Cloud status...')
}))
cloud
.command('dashboard [id]')
.description('Open Brain Cloud dashboard')
.action(wrapInteractive(async (id) => {
const dashboardUrl = id
? `https://brainy-${id}.soulcraft-brain.workers.dev/dashboard`
: 'https://app.soulcraft.com'
console.log(chalk.cyan(`\n🌐 Opening Brain Cloud Dashboard: ${dashboardUrl}`))
try {
const { exec } = await import('child_process')
const { promisify } = await import('util')
const execAsync = promisify(exec)
const command = process.platform === 'win32' ? 'start' :
process.platform === 'darwin' ? 'open' : 'xdg-open'
await execAsync(`${command} "${dashboardUrl}"`)
console.log(chalk.green('✅ Dashboard opened!'))
} catch (error) {
console.log(chalk.yellow('💡 Copy the URL above to open in your browser'))
}
}))
// Legacy cloud command (for backward compatibility)
program
.command('cloud [action]')
.description('Manage Brain Cloud connection')
.command('cloud-legacy [action]')
.description('Legacy Brain Cloud connection (deprecated - use "brainy cloud")')
.option('--connect <id>', 'Connect to existing Brain Cloud instance')
.option('--export <id>', 'Export all data from Brain Cloud instance')
.option('--status <id>', 'Check status of Brain Cloud instance')
.option('--dashboard <id>', 'Open dashboard for Brain Cloud instance')
.option('--migrate', 'Migrate between local and cloud')
.action(wrapInteractive(async (action, options) => {
console.log(chalk.yellow('⚠️ Deprecated: Use "brainy cloud" commands instead'))
console.log(chalk.cyan('Examples:'))
console.log(' brainy cloud setup')
console.log(' brainy cloud connect <id>')
console.log(' brainy cloud dashboard')
console.log('')
// For now, show connection instructions
console.log(chalk.cyan('\n⚛ BRAIN CLOUD - AI Memory That Never Forgets'))
console.log(chalk.gray('━'.repeat(50)))
@ -383,9 +497,47 @@ augment
}
} catch {}
console.log(chalk.dim('📦 Available:'))
console.log(chalk.dim(' • notion-sync (Premium)'))
console.log(chalk.dim(' • 40+ more at app.soulcraft.com'))
// Fetch from catalog API
try {
const response = await fetch('http://localhost:3001/api/catalog/cli')
if (response.ok) {
const catalog = await response.json()
// Show available augmentations
const available = catalog.augmentations.filter(aug => aug.status === 'available')
if (available.length > 0) {
console.log(chalk.cyan('🌟 Available (Brain Cloud):'))
available.forEach(aug => {
const popular = aug.popular ? chalk.yellow(' ⭐ Popular') : ''
console.log(`${aug.id} - ${aug.description}${popular}`)
})
console.log('')
}
// Show coming soon
const comingSoon = catalog.augmentations.filter(aug => aug.status === 'coming-soon')
if (comingSoon.length > 0) {
console.log(chalk.dim('📦 Coming Soon:'))
comingSoon.forEach(aug => {
const eta = aug.eta ? ` (${aug.eta})` : ''
console.log(chalk.dim(`${aug.id} - ${aug.description}${eta}`))
})
console.log('')
}
} else {
throw new Error('API unavailable')
}
} catch (error) {
// Fallback to static list if API is unavailable
console.log(chalk.cyan('🌟 Available (Brain Cloud):'))
console.log(' • ai-memory - ' + chalk.yellow('⭐ Popular') + ' - Persistent AI memory')
console.log(' • agent-coordinator - ' + chalk.yellow('⭐ Popular') + ' - Multi-agent handoffs')
console.log(' • notion-sync - Enterprise connector')
console.log('')
}
console.log(chalk.dim('🚀 Join Early Access: https://soulcraft.com/brain-cloud'))
console.log(chalk.dim('📦 Install: npm install @soulcraft/brain-cloud'))
}))
augment
@ -719,9 +871,10 @@ if (!process.argv.slice(2).length) {
console.log(' brainy search "query" # Search across all dimensions')
console.log(' brainy chat # AI chat with full context')
console.log('')
console.log(chalk.bold('AI Memory:'))
console.log(chalk.green(' brainy connect # Connect to Brain Cloud'))
console.log(' brainy cloud --status <id> # Check cloud status')
console.log(chalk.bold('Brain Cloud (Premium):'))
console.log(chalk.green(' brainy cloud setup # Auto-setup with provisioning'))
console.log(' brainy cloud connect <id> # Connect to existing instance')
console.log(' brainy cloud dashboard # Open Brain Cloud dashboard')
console.log('')
console.log(chalk.bold('AI Coordination:'))
console.log(' brainy install brain-jar # Install coordination')
@ -857,4 +1010,310 @@ When working with multiple AI assistants, we automatically coordinate:
} catch (error) {
console.log(chalk.yellow('⚠️ Could not save brainy config:', error.message))
}
}
// ========================================
// AUTO-SETUP HELPER FUNCTIONS
// ========================================
const PROVISIONING_API = 'https://provisioning.soulcraft.com'
let spinner = null
function startSpinner(message) {
stopSpinner()
process.stdout.write(`${message} `)
const spinnerChars = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
let i = 0
spinner = setInterval(() => {
process.stdout.write(`\r${message} ${spinnerChars[i]}`)
i = (i + 1) % spinnerChars.length
}, 100)
}
function stopSpinner() {
if (spinner) {
clearInterval(spinner)
spinner = null
process.stdout.write('\r')
}
}
async function validateLicense() {
startSpinner('Validating Early Access license...')
const licenseKey = process.env.BRAINY_LICENSE_KEY
if (!licenseKey) {
stopSpinner()
console.log('\n❌ No license key found')
console.log('\n🔑 Please set your Early Access license key:')
console.log(' export BRAINY_LICENSE_KEY="lic_early_access_your_key"')
console.log('\n📝 Don\'t have a key? Get one free at: https://soulcraft.com/brain-cloud')
throw new Error('License key required')
}
if (!licenseKey.startsWith('lic_early_access_')) {
stopSpinner()
throw new Error('Invalid license key format. Early Access keys start with "lic_early_access_"')
}
stopSpinner()
console.log('✅ License validated')
}
async function ensureBrainyInstalled() {
startSpinner('Checking Brainy installation...')
try {
const { exec } = await import('child_process')
const { promisify } = await import('util')
const execAsync = promisify(exec)
await execAsync('brainy --version')
stopSpinner()
console.log('✅ Brainy CLI found')
} catch (error) {
stopSpinner()
console.log('📦 Installing Brainy CLI...')
try {
await execWithProgress('npm install -g @soulcraft/brainy')
console.log('✅ Brainy CLI installed')
} catch (installError) {
throw new Error('Failed to install Brainy CLI. Please install manually: npm install -g @soulcraft/brainy')
}
}
}
async function provisionCloudInstance(userEmail) {
const licenseKey = process.env.BRAINY_LICENSE_KEY
startSpinner('Provisioning your cloud Brainy instance...')
try {
const response = await fetch(`${PROVISIONING_API}/provision`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
licenseKey,
userEmail: userEmail || 'user@example.com'
})
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.message || 'Provisioning failed')
}
const result = await response.json()
stopSpinner()
if (result.instance.status === 'active') {
console.log('✅ Cloud instance already active')
return result.instance
}
console.log('🚀 Provisioning started (2-3 minutes)')
// Wait for provisioning to complete
return await waitForProvisioning(licenseKey)
} catch (error) {
stopSpinner()
throw new Error(`Provisioning failed: ${error.message}`)
}
}
async function waitForProvisioning(licenseKey) {
const maxWaitTime = 5 * 60 * 1000 // 5 minutes
const checkInterval = 15 * 1000 // 15 seconds
const startTime = Date.now()
while (Date.now() - startTime < maxWaitTime) {
startSpinner('Waiting for cloud instance to be ready...')
try {
const response = await fetch(`${PROVISIONING_API}/status?licenseKey=${encodeURIComponent(licenseKey)}`)
if (response.ok) {
const result = await response.json()
if (result.instance.status === 'active') {
stopSpinner()
console.log('✅ Cloud instance is ready')
return result.instance
}
if (result.instance.status === 'failed') {
stopSpinner()
throw new Error('Instance provisioning failed')
}
}
stopSpinner()
await new Promise(resolve => setTimeout(resolve, checkInterval))
} catch (error) {
stopSpinner()
console.log('⏳ Still provisioning...')
await new Promise(resolve => setTimeout(resolve, checkInterval))
}
}
throw new Error('Provisioning timeout. Please check your dashboard or contact support.')
}
async function configureBrainy(instance) {
const { writeFile, mkdir } = await import('fs/promises')
const { join } = await import('path')
const { homedir } = await import('os')
const { existsSync } = await import('fs')
startSpinner('Configuring local Brainy to use cloud instance...')
// Ensure config directory exists
const BRAINY_CONFIG_DIR = join(homedir(), '.brainy')
const BRAINY_CONFIG_FILE = join(BRAINY_CONFIG_DIR, 'config.json')
if (!existsSync(BRAINY_CONFIG_DIR)) {
await mkdir(BRAINY_CONFIG_DIR, { recursive: true })
}
// Create or update Brainy config
let config = {}
if (existsSync(BRAINY_CONFIG_FILE)) {
try {
const { readFile } = await import('fs/promises')
const existing = await readFile(BRAINY_CONFIG_FILE, 'utf8')
config = JSON.parse(existing)
} catch (error) {
console.log('⚠️ Could not read existing config, creating new one')
}
}
// Update config with cloud instance details
config.cloudSync = {
enabled: true,
endpoint: instance.endpoints.api,
instanceId: instance.id,
licenseKey: process.env.BRAINY_LICENSE_KEY
}
config.aiMemory = {
enabled: true,
storage: 'cloud',
endpoint: instance.endpoints.api
}
config.agentCoordination = {
enabled: true,
endpoint: instance.endpoints.api
}
await writeFile(BRAINY_CONFIG_FILE, JSON.stringify(config, null, 2))
stopSpinner()
console.log('✅ Local Brainy configured for cloud sync')
}
async function installBrainCloudPackage() {
startSpinner('Installing Brain Cloud augmentations...')
try {
const { existsSync } = await import('fs')
// Check if we're in a project directory
const hasPackageJson = existsSync('package.json')
if (hasPackageJson) {
await execWithProgress('npm install @soulcraft/brain-cloud')
console.log('✅ Brain Cloud package installed in current project')
} else {
// Install globally for non-project usage
await execWithProgress('npm install -g @soulcraft/brain-cloud')
console.log('✅ Brain Cloud package installed globally')
}
} catch (error) {
stopSpinner()
console.log('⚠️ Could not auto-install Brain Cloud package')
console.log(' You can install it manually: npm install @soulcraft/brain-cloud')
// Don't throw error, this is optional
}
}
async function testConnection(instance) {
startSpinner('Testing cloud connection...')
try {
const response = await fetch(`${instance.endpoints.api}/health`)
if (response.ok) {
const health = await response.json()
stopSpinner()
console.log('✅ Cloud instance connection verified')
// Test memory storage
const testMemory = {
content: 'Test memory from auto-setup',
source: 'brain-cloud-setup',
importance: 'low',
tags: ['setup', 'test']
}
const memoryResponse = await fetch(`${instance.endpoints.api}/api/memories`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(testMemory)
})
if (memoryResponse.ok) {
console.log('✅ Memory storage working')
}
} else {
stopSpinner()
console.log('⚠️ Cloud instance not responding yet (this is normal)')
console.log(' Your instance may need a few more minutes to fully initialize')
}
} catch (error) {
stopSpinner()
console.log('⚠️ Could not test connection (this is usually fine)')
}
}
async function execWithProgress(command) {
const { spawn } = await import('child_process')
return new Promise((resolve, reject) => {
const child = spawn('sh', ['-c', command], {
stdio: ['inherit', 'pipe', 'pipe'],
shell: true
})
let stdout = ''
let stderr = ''
child.stdout?.on('data', (data) => {
stdout += data.toString()
process.stdout.write('.')
})
child.stderr?.on('data', (data) => {
stderr += data.toString()
})
child.on('close', (code) => {
process.stdout.write('\n')
if (code === 0) {
resolve(stdout)
} else {
reject(new Error(stderr || `Command failed with code ${code}`))
}
})
})
}

398
src/cli/catalog.ts Normal file
View file

@ -0,0 +1,398 @@
/**
* Brain Cloud Catalog Integration for CLI
*
* Fetches and displays augmentation catalog
* Falls back to local cache if API is unavailable
*/
import chalk from 'chalk'
import { readFileSync, writeFileSync, existsSync } from 'fs'
import { join } from 'path'
import { homedir } from 'os'
const CATALOG_API = process.env.BRAIN_CLOUD_CATALOG_URL || 'https://catalog.brain-cloud.soulcraft.com'
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
// Fetch from 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
} catch (error) {
// Try loading from cache even if expired
const cached = loadCache(true)
if (cached) {
console.log(chalk.yellow('📡 Using cached catalog (API unavailable)'))
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('🧠 Brain Cloud 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('Sign up at app.soulcraft.com to activate'))
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
try {
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 (API offline)'))
}
}
/**
* Show user's available augmentations
*/
export async function showAvailable(licenseKey?: string) {
const key = licenseKey || process.env.BRAINY_LICENSE_KEY || readLicenseFile()
if (!key) {
console.log(chalk.yellow('⚠️ No license key found'))
console.log('')
console.log('To see your available augmentations:')
console.log(' 1. Sign up at app.soulcraft.com')
console.log(' 2. Run: brainy augment activate')
return
}
try {
const response = await fetch(`${CATALOG_API}/api/catalog/available`, {
headers: { 'x-license-key': key }
})
if (!response.ok) {
throw new Error('Invalid license')
}
const data = await response.json()
console.log(chalk.cyan.bold('🧠 Your Available Augmentations'))
console.log(chalk.gray(`Plan: ${data.plan}`))
console.log('')
const grouped = groupByCategory(data.augmentations, [])
for (const [category, augs] of Object.entries(grouped)) {
console.log(chalk.bold(category))
augs.forEach(aug => {
console.log(`${aug.name}`)
})
console.log('')
}
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) {
console.log(chalk.red('❌ Could not fetch available augmentations'))
console.log(chalk.gray(error.message))
}
}
// 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 {}
return null
}
function getDefaultCatalog(): Catalog {
// Hardcoded fallback catalog
return {
version: '1.0.0',
categories: [
{ id: 'memory', name: 'Memory', icon: '🧠', description: 'AI memory and persistence' },
{ id: 'coordination', name: 'Coordination', icon: '🤝', description: 'Multi-agent orchestration' },
{ id: 'enterprise', name: 'Enterprise', icon: '🏢', description: 'Business integrations' }
],
augmentations: [
{
id: 'ai-memory',
name: 'AI Memory',
category: 'memory',
description: 'Persistent memory across all AI sessions',
status: 'available',
popular: true
},
{
id: 'agent-coordinator',
name: 'Agent Coordinator',
category: 'coordination',
description: 'Multi-agent handoffs and orchestration',
status: 'available',
popular: true
},
{
id: 'notion-sync',
name: 'Notion Sync',
category: 'enterprise',
description: 'Bidirectional Notion database sync',
status: 'available'
}
]
}
}