/** * Cortex Commands Implementation * * All CLI commands for managing Brainy through Cortex */ import { CortexConfig } from '../config.js' import { BrainyData } from '../../brainyData.js' import * as fs from 'fs/promises' import * as path from 'path' import * as readline from 'readline/promises' import { stdin as input, stdout as output } from 'process' import chalk from 'chalk' import Table from 'cli-table3' export class CortexCommands { /** * Initialize Cortex in a project */ static async init(options: any): Promise { const config = CortexConfig.getInstance() if (options.interactive) { const rl = readline.createInterface({ input, output }) console.log(chalk.cyan('\n🧠 Welcome to Cortex - Brainy Command Center\n')) // Storage type const storageType = await rl.question( 'Storage type (s3/filesystem/memory/opfs) [s3]: ' ) || 's3' let storageConfig: any = { type: storageType } // Storage-specific configuration if (storageType === 's3') { storageConfig.bucket = await rl.question('S3 bucket name: ') storageConfig.region = await rl.question('AWS region [us-east-1]: ') || 'us-east-1' const useEnvCreds = await rl.question( 'Use AWS credentials from environment? (y/n) [y]: ' ) || 'y' if (useEnvCreds !== 'y') { storageConfig.accessKeyId = await rl.question('AWS Access Key ID: ') storageConfig.secretAccessKey = await rl.question('AWS Secret Access Key: ') } } else if (storageType === 'filesystem') { storageConfig.path = await rl.question( `Storage path [${path.join(process.cwd(), '.brainy-data')}]: ` ) || path.join(process.cwd(), '.brainy-data') } // Encryption const enableEncryption = await rl.question( 'Enable encrypted configuration? (y/n) [y]: ' ) || 'y' // Coordination const enableCoordination = await rl.question( 'Enable distributed coordination? (y/n) [y]: ' ) || 'y' rl.close() await config.init({ storage: storageConfig, encryption: { enabled: enableEncryption === 'y', keyDerivation: 'pbkdf2' }, coordination: { enabled: enableCoordination === 'y', realtime: false, pollInterval: 30000 } }) console.log(chalk.green('\nāœ… Cortex initialized successfully!')) console.log(chalk.gray('Configuration saved to .brainy/cortex.json')) console.log(chalk.gray('Master key saved to .brainy/cortex.key')) console.log(chalk.yellow('\nāš ļø Keep your master key safe!')) } else { // Non-interactive mode await config.init({ storage: options.storage ? { type: options.storage } : undefined }) } } /** * Set a configuration value */ static async configSet(key: string, value: string | undefined, options: any): Promise { const config = CortexConfig.getInstance() await config.load() // If no value provided, prompt for it if (!value) { const rl = readline.createInterface({ input, output }) value = await rl.question(`Enter value for ${key}: `) rl.close() } await config.set(key, value, { encrypt: options.encrypt }) console.log(chalk.green(`āœ… Set ${key}`)) } /** * Get a configuration value */ static async configGet(key: string): Promise { const config = CortexConfig.getInstance() await config.load() const value = await config.get(key) if (value === undefined) { console.log(chalk.yellow(`Configuration key '${key}' not found`)) } else { console.log(value) } } /** * List all configuration keys */ static async configList(options: any): Promise { const config = CortexConfig.getInstance() await config.load() const configs = await config.list() if (configs.length === 0) { console.log(chalk.yellow('No configurations found')) return } const table = new Table({ head: ['Key', 'Encrypted', 'Environment'], style: { head: ['cyan'] } }) for (const cfg of configs) { const row = [ cfg.key, cfg.encrypted ? chalk.green('āœ“') : chalk.gray('-'), cfg.environment ] if (options.showValues) { const value = await config.get(cfg.key) row.push(value ? String(value).substring(0, 50) : '') } table.push(row) } console.log(table.toString()) } /** * Import configuration from .env file */ static async configImport(file: string): Promise { const config = CortexConfig.getInstance() await config.load() await config.importEnv(file) console.log(chalk.green(`āœ… Imported configuration from ${file}`)) } /** * Load environment variables */ static async envLoad(options: any): Promise { const config = CortexConfig.getInstance() await config.load() const env = await config.loadEnvironment() if (options.export) { // Output as shell export commands for (const [key, value] of Object.entries(env)) { console.log(`export ${key}="${value}"`) } } else { // Set in current process Object.assign(process.env, env) console.log(chalk.green(`āœ… Loaded ${Object.keys(env).length} environment variables`)) } } /** * Migrate to new storage */ static async migrate(options: any): Promise { const config = CortexConfig.getInstance() await config.load() const brainy = config.getBrainy() // Parse target storage URL const targetUrl = new URL(options.to) let targetConfig: any = {} if (targetUrl.protocol === 's3:') { targetConfig = { type: 's3', bucket: targetUrl.hostname, region: targetUrl.searchParams.get('region') || 'us-east-1' } } else if (targetUrl.protocol === 'file:') { targetConfig = { type: 'filesystem', path: targetUrl.pathname } } // Create coordination plan const coordinationPlan = { version: 1, timestamp: new Date().toISOString(), migration: { enabled: true, target: targetConfig, strategy: options.strategy, dryRun: options.dryRun || false } } // Store coordination plan in current storage await brainy.addNoun({ id: '_system/coordination', type: 'cortex_coordination', metadata: coordinationPlan }) console.log(chalk.cyan('šŸ“‹ Migration plan created:')) console.log(JSON.stringify(coordinationPlan, null, 2)) if (!options.dryRun) { console.log(chalk.yellow('\nā³ Migration will begin shortly...')) console.log(chalk.gray('All services will automatically detect and execute the migration')) } } /** * Synchronize services */ static async sync(options: any): Promise { const config = CortexConfig.getInstance() await config.load() const brainy = config.getBrainy() // Trigger sync by updating coordination timestamp await brainy.addNoun({ id: '_system/sync', type: 'cortex_sync', metadata: { timestamp: new Date().toISOString(), force: options.force || false } }) console.log(chalk.green('āœ… Sync signal sent to all services')) } /** * Query data with advanced filtering */ static async query(pattern: string, options: any): Promise { const config = CortexConfig.getInstance() await config.load() const brainy = config.getBrainy() // Parse metadata filter if provided let metadataFilter = null if (options.filter || options.metadata) { try { metadataFilter = JSON.parse(options.filter || options.metadata) } catch (error) { console.log(chalk.red(`Invalid filter JSON: ${error.message}`)) return } } // Show query plan if requested if (options.explain) { console.log(chalk.cyan('\nšŸ“‹ Query Plan:')) console.log(`Pattern: "${pattern}"`) if (metadataFilter) { console.log(`Filter: ${JSON.stringify(metadataFilter, null, 2)}`) } console.log(`Limit: ${options.limit || 10}\n`) } // Perform search with metadata filtering const results = await brainy.searchNouns(pattern, { limit: parseInt(options.limit) || 10, metadata: metadataFilter }) if (options.json) { console.log(JSON.stringify(results, null, 2)) } else { if (results.length === 0) { console.log(chalk.yellow('No results found')) return } const table = new Table({ head: ['ID', 'Type', 'Score', 'Sample Metadata'], style: { head: ['cyan'] }, colWidths: [30, 15, 10, 40] }) for (const result of results) { // Show a sample of metadata let metaSample = '' if (result.metadata) { const keys = Object.keys(result.metadata).slice(0, 3) metaSample = keys.map(k => `${k}: ${JSON.stringify(result.metadata[k])}`).join(', ') if (Object.keys(result.metadata).length > 3) { metaSample += ', ...' } } table.push([ result.id.substring(0, 28), result.type || '-', result.score?.toFixed(3) || '-', metaSample.substring(0, 38) ]) } console.log(table.toString()) console.log(chalk.gray(`\nFound ${results.length} results`)) } } /** * Show statistics */ static async stats(options: any): Promise { const config = CortexConfig.getInstance() await config.load() const brainy = config.getBrainy() const stats = await brainy.getStatistics() if (options.json) { console.log(JSON.stringify(stats, null, 2)) } else { console.log(chalk.cyan('\nšŸ“Š Brainy Statistics\n')) console.log(`Nouns: ${chalk.green(stats.totalNouns)}`) console.log(`Verbs: ${chalk.green(stats.totalVerbs)}`) console.log(`Storage Used: ${chalk.green(this.formatBytes(stats.storageUsed || 0))}`) console.log(`Index Size: ${chalk.green(this.formatBytes(stats.indexSize || 0))}`) if (stats.metadata) { console.log(`\nMetadata:`) for (const [key, value] of Object.entries(stats.metadata)) { console.log(` ${key}: ${chalk.gray(JSON.stringify(value))}`) } } } } /** * Create backup */ static async backup(destination: string | undefined, options: any): Promise { const config = CortexConfig.getInstance() await config.load() const timestamp = new Date().toISOString().replace(/[:.]/g, '-') const backupName = `brainy-backup-${timestamp}` const backupPath = destination || path.join(process.cwd(), `${backupName}.json`) const brainy = config.getBrainy() // Export all data const backup: any = { version: 1, timestamp: new Date().toISOString(), data: { nouns: [], verbs: [] } } // Export nouns with pagination let offset = 0 let hasMore = true while (hasMore) { const result = await brainy.getNouns({ pagination: { offset, limit: 100 } }) backup.data.nouns.push(...result.items) hasMore = result.hasMore offset += 100 } // Export verbs with pagination offset = 0 hasMore = true while (hasMore) { const result = await brainy.getVerbs({ pagination: { offset, limit: 100 } }) backup.data.verbs.push(...result.items) hasMore = result.hasMore offset += 100 } // Include configuration if requested if (options.includeConfig) { backup.config = await config.list() } // Save backup const backupContent = JSON.stringify(backup, null, 2) if (options.compress) { const zlib = await import('zlib') const compressed = await new Promise((resolve, reject) => { zlib.gzip(Buffer.from(backupContent), (err, result) => { if (err) reject(err) else resolve(result) }) }) await fs.writeFile(`${backupPath}.gz`, compressed) return `${backupPath}.gz` } else { await fs.writeFile(backupPath, backupContent) return backupPath } } /** * Restore from backup */ static async restore(source: string, options: any): Promise { const config = CortexConfig.getInstance() await config.load() let backupContent: string if (source.endsWith('.gz')) { const zlib = await import('zlib') const compressed = await fs.readFile(source) backupContent = await new Promise((resolve, reject) => { zlib.gunzip(compressed, (err, result) => { if (err) reject(err) else resolve(result.toString()) }) }) } else { backupContent = await fs.readFile(source, 'utf-8') } const backup = JSON.parse(backupContent) const brainy = config.getBrainy() if (!options.force) { const rl = readline.createInterface({ input, output }) const confirm = await rl.question( chalk.yellow('āš ļø This will overwrite existing data. Continue? (y/n): ') ) rl.close() if (confirm !== 'y') { console.log('Restore cancelled') return } } // Restore nouns for (const noun of backup.data.nouns) { await brainy.addNoun(noun) } // Restore verbs for (const verb of backup.data.verbs) { await brainy.addVerb(verb) } console.log(chalk.green(`āœ… Restored ${backup.data.nouns.length} nouns and ${backup.data.verbs.length} verbs`)) } /** * Inspect an item */ static async inspect(id: string, options: any): Promise { const config = CortexConfig.getInstance() await config.load() const brainy = config.getBrainy() try { // Try as noun first const noun = await brainy.getNoun(id) if (noun) { if (options.raw) { console.log(JSON.stringify(noun, null, 2)) } else { console.log(chalk.cyan(`\nšŸ“¦ Noun: ${id}\n`)) console.log(`Type: ${chalk.green(noun.type || 'unknown')}`) if (noun.metadata) { console.log(`Metadata:`) console.log(JSON.stringify(noun.metadata, null, 2)) } } return } } catch (e) { // Not a noun, try verb } try { // Try as verb const verb = await brainy.getVerb(id) if (verb) { if (options.raw) { console.log(JSON.stringify(verb, null, 2)) } else { console.log(chalk.cyan(`\nšŸ”— Verb: ${id}\n`)) console.log(`Type: ${chalk.green(verb.type)}`) console.log(`Source: ${chalk.blue(verb.source)}`) console.log(`Target: ${chalk.blue(verb.target)}`) if (verb.metadata) { console.log(`Metadata:`) console.log(JSON.stringify(verb.metadata, null, 2)) } } return } } catch (e) { // Not found } console.log(chalk.red(`Item '${id}' not found`)) } /** * Reindex database */ static async reindex(options: any): Promise { const config = CortexConfig.getInstance() await config.load() const brainy = config.getBrainy() if (options.type === 'metadata' || options.type === 'all') { await brainy.rebuildMetadataIndex() } if (options.type === 'hnsw' || options.type === 'all') { // HNSW reindex would go here console.log(chalk.yellow('HNSW reindexing not yet implemented')) } } /** * Health check */ static async health(options: any): Promise { const config = CortexConfig.getInstance() try { await config.load() const brainy = config.getBrainy() const stats = await brainy.getStatistics() console.log(chalk.green('āœ… Cortex: Healthy')) console.log(chalk.green('āœ… Brainy: Connected')) console.log(chalk.green(`āœ… Storage: Active (${stats.totalNouns} nouns, ${stats.totalVerbs} verbs)`)) if (options.verbose) { console.log('\nDetailed Health:') console.log(`- Config Path: ${path.join(process.cwd(), '.brainy/cortex.json')}`) console.log(`- Storage Type: ${config.getStorageConfig()?.type}`) console.log(`- Environment: ${config.getCurrentEnvironment()}`) } } catch (error: any) { console.log(chalk.red('āŒ Cortex: Error')) console.log(chalk.red(` ${error.message}`)) process.exit(1) } } /** * Interactive shell */ static async shell(): Promise { const config = CortexConfig.getInstance() await config.load() console.log(chalk.cyan('\n🧠 Cortex Interactive Shell\n')) console.log(chalk.gray('Type "help" for commands, "exit" to quit\n')) const rl = readline.createInterface({ input, output }) while (true) { const command = await rl.question(chalk.cyan('cortex> ')) if (command === 'exit' || command === 'quit') { break } if (command === 'help') { console.log(` Available commands: query - Search for data get - Get config value set - Set config value stats - Show statistics health - Check health exit - Exit shell `) continue } // Parse and execute command const [cmd, ...args] = command.split(' ') try { switch (cmd) { case 'query': await this.query(args.join(' '), { limit: 5 }) break case 'get': await this.configGet(args[0]) break case 'set': await this.configSet(args[0], args.slice(1).join(' '), { encrypt: true }) break case 'stats': await this.stats({}) break case 'health': await this.health({}) break default: console.log(chalk.yellow(`Unknown command: ${cmd}`)) } } catch (error: any) { console.log(chalk.red(`Error: ${error.message}`)) } } rl.close() console.log(chalk.gray('\nGoodbye!\n')) } /** * Show status */ static async status(): Promise { const config = CortexConfig.getInstance() try { await config.load() const brainy = config.getBrainy() const stats = await brainy.getStatistics() console.log(chalk.cyan('\n🧠 Cortex Status\n')) const table = new Table({ style: { head: ['cyan'] } }) table.push( { 'Configuration': chalk.green('āœ“ Loaded') }, { 'Storage': `${config.getStorageConfig()?.type}` }, { 'Environment': config.getCurrentEnvironment() }, { 'Encryption': chalk.green('āœ“ Enabled') }, { 'Total Nouns': stats.totalNouns.toString() }, { 'Total Verbs': stats.totalVerbs.toString() }, { 'Storage Used': this.formatBytes(stats.storageUsed || 0) } ) console.log(table.toString()) // Check for active migrations const coordinationNoun = await brainy.getNoun('_system/coordination') if (coordinationNoun?.metadata?.migration?.enabled) { console.log(chalk.yellow('\nāš ļø Active Migration:')) console.log(` Target: ${coordinationNoun.metadata.migration.target.type}`) console.log(` Strategy: ${coordinationNoun.metadata.migration.strategy}`) } } catch (error: any) { console.log(chalk.red('āŒ Cortex not initialized')) console.log(chalk.gray('Run "cortex init" to get started')) } } /** * Format bytes to human readable */ private static formatBytes(bytes: number): string { if (bytes === 0) return '0 B' const k = 1024 const sizes = ['B', 'KB', 'MB', 'GB', 'TB'] const i = Math.floor(Math.log(bytes) / Math.log(k)) return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}` } }