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 db2f8e4035
commit b265d6f7d0
3 changed files with 896 additions and 12 deletions

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}`))
}
})
})
}