2025-08-26 12:32:21 -07:00
#!/usr/bin/env node
/ * *
* Brainy CLI - Cleaned Up & Beautiful
* 🧠 ⚛ ️ ONE way to do everything
*
* After the Great Cleanup of 2025 :
* - 5 commands total ( was 40 + )
* - Clear , obvious naming
* - Interactive mode for beginners
* /
// @ts-ignore
import { program } from 'commander'
import { BrainyData } from '../dist/brainyData.js'
// @ts-ignore
import chalk from 'chalk'
import { readFileSync } from 'fs'
import { dirname , join } from 'path'
import { fileURLToPath } from 'url'
import { createInterface } from 'readline'
// @ts-ignore
import Table from 'cli-table3'
const _ _dirname = dirname ( fileURLToPath ( import . meta . url ) )
const packageJson = JSON . parse ( readFileSync ( join ( _ _dirname , '..' , 'package.json' ) , 'utf8' ) )
// Create single BrainyData instance (the ONE data orchestrator)
let brainy = null
const getBrainy = async ( ) => {
if ( ! brainy ) {
brainy = new BrainyData ( )
await brainy . init ( )
}
return brainy
}
// Beautiful colors matching brainy.png logo
const colors = {
primary : chalk . hex ( '#3A5F4A' ) , // Teal container (from logo)
success : chalk . hex ( '#2D4A3A' ) , // Deep teal frame (from logo)
info : chalk . hex ( '#4A6B5A' ) , // Medium teal
warning : chalk . hex ( '#D67441' ) , // Orange (from logo)
error : chalk . hex ( '#B85C35' ) , // Deep orange
brain : chalk . hex ( '#D67441' ) , // Brain orange (from logo)
cream : chalk . hex ( '#F5E6A3' ) , // Cream background (from logo)
dim : chalk . dim ,
blue : chalk . blue ,
green : chalk . green ,
yellow : chalk . yellow ,
cyan : chalk . cyan
}
// Helper functions
const exitProcess = ( code = 0 ) => {
setTimeout ( ( ) => process . exit ( code ) , 100 )
}
// Initialize Brainy instance
const initBrainy = async ( ) => {
return new BrainyData ( )
}
2025-08-28 12:37:07 -07:00
/ * *
* Enhanced result formatting using display augmentation
* @ param { any } result - The result object from search / get / find
* @ param { number } index - Result index for numbering
* @ returns { Promise < string > } Formatted result string
* /
const formatResultWithDisplay = async ( result , index ) => {
try {
// Check if result has display capabilities (enhanced by display augmentation)
if ( result . getDisplay && typeof result . getDisplay === 'function' ) {
const displayFields = await result . getDisplay ( )
// Format with enhanced display fields (clean, no icons)
let output = colors . primary ( ` \n ${ index + 1 } . ${ displayFields . title } ` )
if ( displayFields . type ) {
output += colors . dim ( ` ( ${ displayFields . type } ) ` )
}
if ( result . score ) {
output += colors . info ( ` \n 🎯 Relevance: ${ ( result . score * 100 ) . toFixed ( 1 ) } % ` )
}
if ( result . fusionScore ) {
output += colors . info ( ` \n 🧠 AI Score: ${ ( result . fusionScore * 100 ) . toFixed ( 1 ) } % ` )
}
if ( displayFields . description && displayFields . description !== displayFields . title ) {
output += colors . info ( ` \n 📄 ${ displayFields . description } ` )
}
if ( displayFields . tags && displayFields . tags . length > 0 ) {
output += colors . cyan ( ` \n 🏷️ ${ displayFields . tags . join ( ', ' ) } ` )
}
// Show relationship info for verbs
if ( displayFields . relationship ) {
output += colors . yellow ( ` \n 🔗 ${ displayFields . relationship } ` )
}
// Show metadata only if there's additional useful info
if ( result . metadata && Object . keys ( result . metadata ) . length > 0 ) {
const filteredMetadata = Object . fromEntries (
Object . entries ( result . metadata ) . filter ( ( [ key ] ) =>
! key . startsWith ( '_' ) && ! [ 'type' , 'title' , 'description' , 'icon' ] . includes ( key )
)
)
if ( Object . keys ( filteredMetadata ) . length > 0 ) {
output += colors . dim ( ` \n 📝 ${ JSON . stringify ( filteredMetadata ) } ` )
}
}
return output
}
} catch ( error ) {
// Fallback silently to basic formatting if display augmentation fails
}
// Fallback: Basic formatting without display augmentation
let output = colors . primary ( ` \n ${ index + 1 } . ${ result . content || result . id } ` )
if ( result . score ) {
output += colors . info ( ` \n Relevance: ${ ( result . score * 100 ) . toFixed ( 1 ) } % ` )
}
if ( result . fusionScore ) {
output += colors . info ( ` \n AI Score: ${ ( result . fusionScore * 100 ) . toFixed ( 1 ) } % ` )
}
if ( result . type ) {
output += colors . info ( ` \n Type: ${ result . type } ` )
}
if ( result . metadata && Object . keys ( result . metadata ) . length > 0 ) {
output += colors . dim ( ` \n Metadata: ${ JSON . stringify ( result . metadata ) } ` )
}
return output
}
/ * *
* Enhanced single item formatting for get command
* @ param { any } item - The item object
* @ param { string } format - Output format ( json , table , plain )
* @ returns { Promise < string > } Formatted item string
* /
const formatItemWithDisplay = async ( item , format = 'plain' ) => {
if ( format === 'json' ) {
return JSON . stringify ( item , null , 2 )
}
try {
// Check if item has display capabilities
if ( item . getDisplay && typeof item . getDisplay === 'function' ) {
const displayFields = await item . getDisplay ( )
if ( format === 'table' ) {
const table = new Table ( {
head : [ colors . brain ( 'Property' ) , colors . brain ( 'Value' ) ] ,
style : { head : [ ] , border : [ ] }
} )
table . push ( [ 'ID' , colors . primary ( item . id ) ] )
table . push ( [ 'Title' , colors . primary ( displayFields . title ) ] )
table . push ( [ 'Type' , colors . info ( displayFields . type ) ] )
table . push ( [ 'Description' , colors . info ( displayFields . description ) ] )
if ( displayFields . tags && displayFields . tags . length > 0 ) {
table . push ( [ 'Tags' , colors . cyan ( displayFields . tags . join ( ', ' ) ) ] )
}
if ( displayFields . relationship ) {
table . push ( [ 'Relationship' , colors . yellow ( displayFields . relationship ) ] )
}
if ( item . content && item . content !== displayFields . title ) {
table . push ( [ 'Content' , colors . dim ( item . content ) ] )
}
// Add non-internal metadata
if ( item . metadata ) {
Object . entries ( item . metadata ) . forEach ( ( [ key , value ] ) => {
if ( ! key . startsWith ( '_' ) && ! [ 'type' , 'title' , 'description' , 'icon' ] . includes ( key ) ) {
table . push ( [ key , colors . dim ( JSON . stringify ( value ) ) ] )
}
} )
}
return table . toString ( )
} else {
// Plain format with display enhancement
let output = colors . primary ( ` ID: ${ item . id } ` )
output += colors . primary ( ` \n Title: ${ displayFields . title } ` )
output += colors . info ( ` \n Type: ${ displayFields . type } ` )
output += colors . info ( ` \n Description: ${ displayFields . description } ` )
if ( displayFields . tags && displayFields . tags . length > 0 ) {
output += colors . cyan ( ` \n Tags: ${ displayFields . tags . join ( ', ' ) } ` )
}
if ( displayFields . relationship ) {
output += colors . yellow ( ` \n Relationship: ${ displayFields . relationship } ` )
}
if ( item . content && item . content !== displayFields . title ) {
output += colors . dim ( ` \n Original Content: ${ item . content } ` )
}
// Show additional metadata
if ( item . metadata ) {
const additionalMetadata = Object . fromEntries (
Object . entries ( item . metadata ) . filter ( ( [ key ] ) =>
! key . startsWith ( '_' ) && ! [ 'type' , 'title' , 'description' , 'icon' ] . includes ( key )
)
)
if ( Object . keys ( additionalMetadata ) . length > 0 ) {
output += colors . dim ( ` \n Additional Metadata: ${ JSON . stringify ( additionalMetadata , null , 2 ) } ` )
}
}
return output
}
}
} catch ( error ) {
// Fallback silently to basic formatting
}
// Fallback: Basic formatting
if ( format === 'table' ) {
const table = new Table ( {
head : [ colors . brain ( 'Property' ) , colors . brain ( 'Value' ) ] ,
style : { head : [ ] , border : [ ] }
} )
table . push ( [ 'ID' , colors . primary ( item . id ) ] )
table . push ( [ 'Content' , colors . info ( item . content || 'N/A' ) ] )
if ( item . metadata ) {
Object . entries ( item . metadata ) . forEach ( ( [ key , value ] ) => {
table . push ( [ key , colors . dim ( JSON . stringify ( value ) ) ] )
} )
}
return table . toString ( )
} else {
let output = colors . primary ( ` ID: ${ item . id } ` )
if ( item . content ) {
output += colors . info ( ` \n Content: ${ item . content } ` )
}
if ( item . metadata && Object . keys ( item . metadata ) . length > 0 ) {
output += colors . info ( ` \n Metadata: ${ JSON . stringify ( item . metadata , null , 2 ) } ` )
}
return output
}
}
2025-08-26 12:32:21 -07:00
const wrapAction = ( fn ) => {
return async ( ... args ) => {
try {
await fn ( ... args )
exitProcess ( 0 )
} catch ( error ) {
console . error ( colors . error ( 'Error:' ) , error . message )
exitProcess ( 1 )
}
}
}
// AI Response Generation with multiple model support
async function generateAIResponse ( message , brainy , options ) {
const model = options . model || 'local'
// Get relevant context from user's data
const contextResults = await brainy . search ( message , {
limit : 5 ,
includeContent : true ,
scoreThreshold : 0.3
} )
const context = contextResults . map ( r => r . content ) . join ( '\n' )
const prompt = ` Based on the following context from the user's data, answer their question:
Context :
$ { context }
Question : $ { message }
Answer : `
switch ( model ) {
case 'local' :
case 'ollama' :
return await callOllamaModel ( prompt , options )
case 'openai' :
case 'gpt-3.5-turbo' :
case 'gpt-4' :
return await callOpenAI ( prompt , options )
case 'claude' :
case 'claude-3' :
return await callClaude ( prompt , options )
default :
return await callOllamaModel ( prompt , options )
}
}
// Ollama (local) integration
async function callOllamaModel ( prompt , options ) {
const baseUrl = options . baseUrl || 'http://localhost:11434'
const model = options . model === 'local' ? 'llama2' : options . model
try {
const response = await fetch ( ` ${ baseUrl } /api/generate ` , {
method : 'POST' ,
headers : { 'Content-Type' : 'application/json' } ,
body : JSON . stringify ( {
model : model ,
prompt : prompt ,
stream : false
} )
} )
if ( ! response . ok ) {
throw new Error ( ` Ollama error: ${ response . statusText } . Make sure Ollama is running: ollama serve ` )
}
const data = await response . json ( )
return data . response || 'No response from local model'
} catch ( error ) {
throw new Error ( ` Local model error: ${ error . message } . Try: ollama run llama2 ` )
}
}
// OpenAI integration
async function callOpenAI ( prompt , options ) {
if ( ! options . apiKey ) {
throw new Error ( 'OpenAI API key required. Use --api-key <key> or set OPENAI_API_KEY environment variable' )
}
const model = options . model === 'openai' ? 'gpt-3.5-turbo' : options . model
try {
const response = await fetch ( 'https://api.openai.com/v1/chat/completions' , {
method : 'POST' ,
headers : {
'Authorization' : ` Bearer ${ options . apiKey } ` ,
'Content-Type' : 'application/json'
} ,
body : JSON . stringify ( {
model : model ,
messages : [ { role : 'user' , content : prompt } ] ,
max _tokens : 500
} )
} )
if ( ! response . ok ) {
throw new Error ( ` OpenAI error: ${ response . statusText } ` )
}
const data = await response . json ( )
return data . choices [ 0 ] ? . message ? . content || 'No response from OpenAI'
} catch ( error ) {
throw new Error ( ` OpenAI error: ${ error . message } ` )
}
}
// Claude integration
async function callClaude ( prompt , options ) {
if ( ! options . apiKey ) {
throw new Error ( 'Anthropic API key required. Use --api-key <key> or set ANTHROPIC_API_KEY environment variable' )
}
try {
const response = await fetch ( 'https://api.anthropic.com/v1/messages' , {
method : 'POST' ,
headers : {
'x-api-key' : options . apiKey ,
'Content-Type' : 'application/json' ,
'anthropic-version' : '2023-06-01'
} ,
body : JSON . stringify ( {
model : 'claude-3-haiku-20240307' ,
max _tokens : 500 ,
messages : [ { role : 'user' , content : prompt } ]
} )
} )
if ( ! response . ok ) {
throw new Error ( ` Claude error: ${ response . statusText } ` )
}
const data = await response . json ( )
return data . content [ 0 ] ? . text || 'No response from Claude'
} catch ( error ) {
throw new Error ( ` Claude error: ${ error . message } ` )
}
}
// ========================================
// MAIN PROGRAM - CLEAN & SIMPLE
// ========================================
program
. name ( 'brainy' )
. description ( '🧠⚛️ Brainy - Your AI-Powered Second Brain' )
. version ( packageJson . version )
. option ( '-i, --interactive' , 'Start interactive mode' )
. addHelpText ( 'after' , `
$ { colors . dim ( 'Examples:' ) }
$ { colors . success ( 'brainy add "Meeting notes from today"' ) }
$ { colors . success ( 'brainy search "project deadline"' ) }
$ { colors . success ( 'brainy chat' ) } $ { colors . dim ( '# Interactive AI chat' ) }
$ { colors . success ( 'brainy -i' ) } $ { colors . dim ( '# Interactive mode' ) }
$ { colors . dim ( 'For more help:' ) }
$ { colors . info ( 'brainy <command> --help' ) } $ { colors . dim ( '# Command-specific help' ) }
$ { colors . info ( 'https://github.com/TimeSoul/brainy' ) } $ { colors . dim ( '# Documentation' ) } ` )
// ========================================
// THE 5 COMMANDS (ONE WAY TO DO EVERYTHING)
// ========================================
// Command 0: INIT - Initialize brainy (essential setup)
program
. command ( 'init' )
. description ( 'Initialize Brainy in current directory' )
. option ( '-s, --storage <type>' , 'Storage type (filesystem, memory, s3, r2, gcs)' )
. option ( '-e, --encryption' , 'Enable encryption for sensitive data' )
. option ( '--s3-bucket <bucket>' , 'S3 bucket name' )
. option ( '--s3-region <region>' , 'S3 region' )
. option ( '--access-key <key>' , 'Storage access key' )
. option ( '--secret-key <key>' , 'Storage secret key' )
. action ( wrapAction ( async ( options ) => {
console . log ( colors . primary ( '🧠 Initializing Brainy' ) )
console . log ( )
const { BrainyData } = await import ( '../dist/brainyData.js' )
const config = {
storage : options . storage || 'filesystem' ,
encryption : options . encryption || false
}
// Storage-specific configuration
if ( options . storage === 's3' || options . storage === 'r2' || options . storage === 'gcs' ) {
if ( ! options . accessKey || ! options . secretKey ) {
console . log ( colors . warning ( '⚠️ Cloud storage requires access credentials' ) )
console . log ( colors . info ( 'Use: --access-key <key> --secret-key <secret>' ) )
console . log ( colors . info ( 'Or set environment variables: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY' ) )
process . exit ( 1 )
}
config . storageOptions = {
bucket : options . s3Bucket ,
region : options . s3Region || 'us-east-1' ,
accessKeyId : options . accessKey ,
secretAccessKey : options . secretKey
}
}
try {
const brainy = new BrainyData ( config )
await brainy . init ( )
console . log ( colors . success ( '✅ Brainy initialized successfully!' ) )
console . log ( colors . info ( ` 📁 Storage: ${ config . storage } ` ) )
console . log ( colors . info ( ` 🔒 Encryption: ${ config . encryption ? 'Enabled' : 'Disabled' } ` ) )
if ( config . encryption ) {
console . log ( colors . warning ( '🔐 Encryption enabled - keep your keys secure!' ) )
}
console . log ( )
console . log ( colors . success ( '🚀 Ready to go! Try:' ) )
console . log ( colors . info ( ' brainy add "Hello, World!"' ) )
console . log ( colors . info ( ' brainy search "hello"' ) )
} catch ( error ) {
console . log ( colors . error ( '❌ Initialization failed:' ) )
console . log ( colors . error ( error . message ) )
process . exit ( 1 )
}
} ) )
// Command 1: ADD - Add data (smart by default)
program
. command ( 'add [data]' )
. description ( 'Add data to your brain (smart auto-detection)' )
. option ( '-m, --metadata <json>' , 'Metadata as JSON' )
. option ( '-i, --id <id>' , 'Custom ID' )
. option ( '--literal' , 'Skip AI processing (literal storage)' )
. option ( '--encrypt' , 'Encrypt this data (for sensitive information)' )
. action ( wrapAction ( async ( data , options ) => {
if ( ! data ) {
console . log ( colors . info ( '🧠 Interactive add mode' ) )
const rl = createInterface ( {
input : process . stdin ,
output : process . stdout
} )
data = await new Promise ( resolve => {
rl . question ( colors . primary ( 'What would you like to add? ' ) , ( answer ) => {
rl . close ( )
resolve ( answer )
} )
} )
}
let metadata = { }
if ( options . metadata ) {
try {
metadata = JSON . parse ( options . metadata )
} catch {
console . error ( colors . error ( 'Invalid JSON metadata' ) )
process . exit ( 1 )
}
}
if ( options . id ) {
metadata . id = options . id
}
if ( options . encrypt ) {
metadata . encrypted = true
}
console . log ( options . literal
? colors . info ( '🔒 Literal storage' )
: colors . success ( '🧠 Smart mode (auto-detects types)' )
)
if ( options . encrypt ) {
console . log ( colors . warning ( '🔐 Encrypting sensitive data...' ) )
}
const brainyInstance = await getBrainy ( )
// Handle encryption at data level if requested
let processedData = data
if ( options . encrypt ) {
processedData = await brainyInstance . encryptData ( data )
metadata . encrypted = true
}
const id = await brainyInstance . addNoun ( processedData , metadata )
console . log ( colors . success ( ` ✅ Added successfully! ID: ${ id } ` ) )
} ) )
// Command 2: CHAT - Talk to your data with AI
program
. command ( 'chat [message]' )
. description ( 'AI chat with your brain data (supports local & cloud models)' )
. option ( '-s, --session <id>' , 'Use specific chat session' )
. option ( '-n, --new' , 'Start a new session' )
. option ( '-l, --list' , 'List all chat sessions' )
. option ( '-h, --history [limit]' , 'Show conversation history (default: 10)' )
. option ( '--search <query>' , 'Search all conversations' )
. option ( '-m, --model <model>' , 'LLM model (local/openai/claude/ollama)' , 'local' )
. option ( '--api-key <key>' , 'API key for cloud models' )
. option ( '--base-url <url>' , 'Base URL for local models (default: http://localhost:11434)' )
. action ( wrapAction ( async ( message , options ) => {
const { BrainyData } = await import ( '../dist/brainyData.js' )
const { BrainyChat } = await import ( '../dist/chat/BrainyChat.js' )
console . log ( colors . primary ( '🧠💬 Brainy Chat - AI-Powered Conversation with Your Data' ) )
console . log ( colors . info ( 'Talk to your brain using your data as context' ) )
console . log ( )
// Initialize brainy and chat
const brainy = new BrainyData ( )
await brainy . init ( )
const chat = new BrainyChat ( brainy )
// Handle different options
if ( options . list ) {
console . log ( colors . primary ( '📋 Chat Sessions' ) )
const sessions = await chat . getSessions ( 20 )
if ( sessions . length === 0 ) {
console . log ( colors . warning ( 'No chat sessions found. Start chatting to create your first session!' ) )
} else {
sessions . forEach ( ( session , i ) => {
console . log ( colors . success ( ` ${ i + 1 } . ${ session . id } ` ) )
if ( session . title ) console . log ( colors . info ( ` Title: ${ session . title } ` ) )
console . log ( colors . info ( ` Messages: ${ session . messageCount } ` ) )
console . log ( colors . info ( ` Last active: ${ session . lastMessageAt . toLocaleDateString ( ) } ` ) )
} )
}
return
}
if ( options . search ) {
console . log ( colors . primary ( ` 🔍 Searching conversations for: " ${ options . search } " ` ) )
const results = await chat . searchMessages ( options . search , { limit : 10 } )
if ( results . length === 0 ) {
console . log ( colors . warning ( 'No messages found' ) )
} else {
results . forEach ( ( msg , i ) => {
console . log ( colors . success ( ` \n ${ i + 1 } . [ ${ msg . sessionId } ] ${ colors . info ( msg . speaker ) } : ` ) )
console . log ( ` ${ msg . content . substring ( 0 , 200 ) } ${ msg . content . length > 200 ? '...' : '' } ` )
} )
}
return
}
if ( options . history ) {
const limit = parseInt ( options . history ) || 10
console . log ( colors . primary ( ` 📜 Recent Chat History ( ${ limit } messages) ` ) )
const history = await chat . getHistory ( limit )
if ( history . length === 0 ) {
console . log ( colors . warning ( 'No chat history found' ) )
} else {
history . forEach ( msg => {
const speaker = msg . speaker === 'user' ? colors . success ( 'You' ) : colors . info ( 'AI' )
console . log ( ` ${ speaker } : ${ msg . content } ` )
console . log ( colors . info ( ` ${ msg . timestamp . toLocaleString ( ) } ` ) )
console . log ( )
} )
}
return
}
// Start interactive chat or process single message
if ( ! message ) {
console . log ( colors . success ( '🎯 Interactive mode - type messages or "exit" to quit' ) )
console . log ( colors . info ( ` Model: ${ options . model } ` ) )
console . log ( )
// Auto-discover previous session
const session = options . new ? null : await chat . initialize ( )
if ( session ) {
console . log ( colors . success ( ` 📋 Resumed session: ${ session . id } ` ) )
console . log ( )
} else {
const newSession = await chat . startNewSession ( )
console . log ( colors . success ( ` 🆕 Started new session: ${ newSession . id } ` ) )
console . log ( )
}
// Interactive chat loop
const rl = createInterface ( {
input : process . stdin ,
output : process . stdout ,
prompt : colors . primary ( 'You: ' )
} )
rl . prompt ( )
rl . on ( 'line' , async ( input ) => {
if ( input . trim ( ) . toLowerCase ( ) === 'exit' ) {
console . log ( colors . success ( '👋 Chat session saved to your brain!' ) )
rl . close ( )
return
}
if ( input . trim ( ) ) {
// Store user message
await chat . addMessage ( input . trim ( ) , 'user' )
// Generate AI response
try {
const response = await generateAIResponse ( input . trim ( ) , brainy , options )
console . log ( colors . info ( 'AI: ' ) + response )
// Store AI response
await chat . addMessage ( response , 'assistant' , { model : options . model } )
console . log ( )
} catch ( error ) {
console . log ( colors . error ( 'AI Error: ' ) + error . message )
console . log ( colors . warning ( '💡 Tip: Try setting --model local or providing --api-key' ) )
console . log ( )
}
}
rl . prompt ( )
} )
rl . on ( 'close' , ( ) => {
exitProcess ( 0 )
} )
} else {
// Single message mode
console . log ( colors . success ( 'You: ' ) + message )
try {
const response = await generateAIResponse ( message , brainy , options )
console . log ( colors . info ( 'AI: ' ) + response )
// Store conversation
await chat . addMessage ( message , 'user' )
await chat . addMessage ( response , 'assistant' , { model : options . model } )
} catch ( error ) {
console . log ( colors . error ( 'Error: ' ) + error . message )
console . log ( colors . info ( '💡 Try: brainy chat --model local or provide --api-key' ) )
}
}
} ) )
// Command 3: IMPORT - Bulk/external data
program
. command ( 'import [source]' )
. description ( 'Import bulk data from files, URLs, or streams' )
. option ( '-t, --type <type>' , 'Source type (file, url, stream)' )
. option ( '-c, --chunk-size <size>' , 'Chunk size for large imports' , '1000' )
. action ( wrapAction ( async ( source , options ) => {
// Interactive mode if no source provided
if ( ! source ) {
console . log ( colors . primary ( '📥 Interactive Import Mode' ) )
console . log ( colors . dim ( 'Import data from various sources\n' ) )
const rl = createInterface ( {
input : process . stdin ,
output : process . stdout
} )
// Ask for source type first
console . log ( colors . cyan ( 'Source types:' ) )
console . log ( colors . info ( ' 1. Local file' ) )
console . log ( colors . info ( ' 2. URL' ) )
console . log ( colors . info ( ' 3. Direct input' ) )
console . log ( )
const sourceType = await new Promise ( resolve => {
rl . question ( colors . cyan ( 'Select source type (1-3): ' ) , ( answer ) => {
resolve ( answer )
} )
} )
if ( sourceType === '3' ) {
// Direct input mode
console . log ( colors . info ( '\nEnter your data (type END on a new line when done):\n' ) )
let data = ''
let line = ''
while ( ( line = await new Promise ( resolve => {
rl . question ( '' , resolve )
} ) ) !== 'END' ) {
data += line + '\n'
}
rl . close ( )
// Save to temp file
const fs = require ( 'fs' )
source = ` /tmp/brainy-import- ${ Date . now ( ) } .json `
fs . writeFileSync ( source , data . trim ( ) )
console . log ( colors . info ( ` \n Saved to temporary file: ${ source } ` ) )
} else {
// File or URL
source = await new Promise ( resolve => {
const prompt = sourceType === '2' ? 'Enter URL: ' : 'Enter file path: '
rl . question ( colors . cyan ( prompt ) , ( answer ) => {
rl . close ( )
resolve ( answer )
} )
} )
if ( ! source . trim ( ) ) {
console . log ( colors . warning ( 'No source provided' ) )
process . exit ( 1 )
}
}
}
console . log ( colors . info ( '📥 Starting neural import...' ) )
console . log ( colors . info ( ` Source: ${ source } ` ) )
// Read and prepare data for import
const fs = require ( 'fs' )
let data
try {
if ( source . startsWith ( 'http' ) ) {
// Handle URL import
const response = await fetch ( source )
data = await response . text ( )
} else {
// Handle file import
data = fs . readFileSync ( source , 'utf8' )
}
// Parse data if JSON
try {
data = JSON . parse ( data )
} catch {
// Keep as string if not JSON
}
} catch ( error ) {
console . log ( colors . error ( ` Failed to read source: ${ error . message } ` ) )
process . exit ( 1 )
}
const brainyInstance = await getBrainy ( )
const result = await brainyInstance . import ( data , {
batchSize : parseInt ( options . chunkSize ) || 50
} )
console . log ( colors . success ( ` ✅ Imported ${ result . length } items ` ) )
} ) )
// Command 3: FIND - Intelligent search using Triple Intelligence
program
. command ( 'find [query]' )
. description ( 'Intelligent search using natural language and structured queries' )
. option ( '-l, --limit <number>' , 'Results limit' , '10' )
. option ( '-m, --mode <mode>' , 'Search mode (auto, semantic, structured)' , 'auto' )
. option ( '--like <term>' , 'Vector similarity search term' )
. option ( '--where <json>' , 'Metadata filters as JSON' )
. action ( wrapAction ( async ( query , options ) => {
if ( ! query && ! options . like ) {
console . log ( colors . primary ( '🧠 Intelligent Find Mode' ) )
console . log ( colors . dim ( 'Use natural language or structured queries\n' ) )
const rl = createInterface ( {
input : process . stdin ,
output : process . stdout
} )
query = await new Promise ( resolve => {
rl . question ( colors . cyan ( 'What would you like to find? ' ) , ( answer ) => {
rl . close ( )
resolve ( answer )
} )
} )
if ( ! query . trim ( ) ) {
console . log ( colors . warning ( 'No query provided' ) )
process . exit ( 1 )
}
}
console . log ( colors . info ( ` 🧠 Finding: " ${ query || options . like } " ` ) )
const brainyInstance = await getBrainy ( )
// Build query object for find() API
let findQuery = query
// Handle structured queries
if ( options . like || options . where ) {
findQuery = { }
if ( options . like ) findQuery . like = options . like
if ( options . where ) {
try {
findQuery . where = JSON . parse ( options . where )
} catch {
console . error ( colors . error ( 'Invalid JSON in --where option' ) )
process . exit ( 1 )
}
}
}
const findOptions = {
limit : parseInt ( options . limit ) ,
mode : options . mode
}
const results = await brainyInstance . find ( findQuery , findOptions )
if ( results . length === 0 ) {
console . log ( colors . warning ( 'No results found' ) )
return
}
console . log ( colors . success ( ` ✅ Found ${ results . length } intelligent results: ` ) )
2025-08-28 12:37:07 -07:00
// Use enhanced formatting with display augmentation
for ( let i = 0 ; i < results . length ; i ++ ) {
const formattedResult = await formatResultWithDisplay ( results [ i ] , i )
console . log ( formattedResult )
}
2025-08-26 12:32:21 -07:00
} ) )
// Command 4: SEARCH - Triple-power search
program
. command ( 'search [query]' )
. description ( 'Search your brain (vector + graph + facets)' )
. option ( '-l, --limit <number>' , 'Results limit' , '10' )
. option ( '-f, --filter <json>' , 'Metadata filters (see "brainy fields" for available fields)' )
. option ( '-d, --depth <number>' , 'Relationship depth' , '2' )
. option ( '--fields' , 'Show available filter fields and exit' )
. action ( wrapAction ( async ( query , options ) => {
// Interactive mode if no query provided
if ( ! query ) {
console . log ( colors . primary ( '🔍 Interactive Search Mode' ) )
console . log ( colors . dim ( 'Search your neural database with natural language\n' ) )
const rl = createInterface ( {
input : process . stdin ,
output : process . stdout
} )
query = await new Promise ( resolve => {
rl . question ( colors . cyan ( 'What would you like to search for? ' ) , ( answer ) => {
rl . close ( )
resolve ( answer )
} )
} )
if ( ! query . trim ( ) ) {
console . log ( colors . warning ( 'No search query provided' ) )
process . exit ( 1 )
}
}
// Handle --fields option
if ( options . fields ) {
console . log ( colors . primary ( '🔍 Available Filter Fields' ) )
console . log ( colors . primary ( '=' . repeat ( 30 ) ) )
try {
const { BrainyData } = await import ( '../dist/brainyData.js' )
const brainy = new BrainyData ( )
await brainy . init ( )
const filterFields = await brainy . getFilterFields ( )
if ( filterFields . length > 0 ) {
console . log ( colors . success ( 'Available fields for --filter option:' ) )
filterFields . forEach ( field => {
console . log ( colors . info ( ` ${ field } ` ) )
} )
console . log ( )
console . log ( colors . primary ( 'Usage Examples:' ) )
console . log ( colors . info ( ` brainy search "query" --filter '{"type":"person"}' ` ) )
console . log ( colors . info ( ` brainy search "query" --filter '{"category":"work","status":"active"}' ` ) )
} else {
console . log ( colors . warning ( 'No indexed fields available yet.' ) )
console . log ( colors . info ( 'Add some data with metadata to see available fields.' ) )
}
} catch ( error ) {
console . log ( colors . error ( ` Error: ${ error . message } ` ) )
}
return
}
console . log ( colors . info ( ` 🔍 Searching: " ${ query } " ` ) )
const searchOptions = {
limit : parseInt ( options . limit ) ,
depth : parseInt ( options . depth )
}
if ( options . filter ) {
try {
searchOptions . filter = JSON . parse ( options . filter )
} catch {
console . error ( colors . error ( 'Invalid filter JSON' ) )
process . exit ( 1 )
}
}
const brainyInstance = await getBrainy ( )
const results = await brainyInstance . search ( query , searchOptions )
if ( results . length === 0 ) {
console . log ( colors . warning ( 'No results found' ) )
return
}
console . log ( colors . success ( ` ✅ Found ${ results . length } results: ` ) )
2025-08-28 12:37:07 -07:00
// Use enhanced formatting with display augmentation
for ( let i = 0 ; i < results . length ; i ++ ) {
const formattedResult = await formatResultWithDisplay ( results [ i ] , i )
console . log ( formattedResult )
}
2025-08-26 12:32:21 -07:00
} ) )
// Command 4: GET - Retrieve specific data by ID
program
. command ( 'get [id]' )
. description ( 'Get a specific item by ID' )
. option ( '-f, --format <format>' , 'Output format (json, table, plain)' , 'plain' )
2025-08-28 12:37:07 -07:00
. option ( '--display-debug' , 'Show debug information about display augmentation' )
2025-08-26 12:32:21 -07:00
. action ( wrapAction ( async ( id , options ) => {
if ( ! id ) {
console . log ( colors . primary ( '🔍 Interactive Get Mode' ) )
console . log ( colors . dim ( 'Retrieve a specific item by ID\n' ) )
const rl = createInterface ( {
input : process . stdin ,
output : process . stdout
} )
id = await new Promise ( resolve => {
rl . question ( colors . cyan ( 'Enter item ID: ' ) , ( answer ) => {
rl . close ( )
resolve ( answer )
} )
} )
if ( ! id . trim ( ) ) {
console . log ( colors . warning ( 'No ID provided' ) )
process . exit ( 1 )
}
}
console . log ( colors . info ( ` 🔍 Getting item: " ${ id } " ` ) )
const brainyInstance = await getBrainy ( )
const item = await brainyInstance . getNoun ( id )
if ( ! item ) {
console . log ( colors . warning ( 'Item not found' ) )
return
}
2025-08-28 12:37:07 -07:00
// Show display debug information if requested
if ( options . displayDebug ) {
console . log ( colors . primary ( '🔍 Display Augmentation Debug Information' ) )
console . log ( '=' . repeat ( 50 ) )
2025-08-26 12:32:21 -07:00
2025-08-28 12:37:07 -07:00
try {
if ( item . getDisplay && typeof item . getDisplay === 'function' ) {
console . log ( colors . success ( '✅ Display augmentation active' ) )
const displayFields = await item . getDisplay ( )
console . log ( colors . info ( '\n🎨 Computed Display Fields:' ) )
Object . entries ( displayFields ) . forEach ( ( [ key , value ] ) => {
console . log ( colors . cyan ( ` ${ key } : ${ JSON . stringify ( value ) } ` ) )
} )
// Show available fields
if ( item . getAvailableFields && typeof item . getAvailableFields === 'function' ) {
const availableFields = item . getAvailableFields ( 'display' )
console . log ( colors . info ( '\n📋 Available Display Fields:' ) )
availableFields . forEach ( field => {
console . log ( colors . dim ( ` - ${ field } ` ) )
} )
}
// Show augmentation info
if ( item . getAvailableAugmentations && typeof item . getAvailableAugmentations === 'function' ) {
const augs = item . getAvailableAugmentations ( )
console . log ( colors . info ( '\n🔌 Available Augmentations:' ) )
augs . forEach ( aug => {
console . log ( colors . dim ( ` - ${ aug } ` ) )
} )
}
} else {
console . log ( colors . warning ( '⚠️ Display augmentation not active or not enhanced' ) )
console . log ( colors . dim ( ' Item does not have getDisplay() method' ) )
}
} catch ( error ) {
console . log ( colors . error ( ` ❌ Display debug error: ${ error . message } ` ) )
2025-08-26 12:32:21 -07:00
}
2025-08-28 12:37:07 -07:00
console . log ( '\n' + '=' . repeat ( 50 ) )
2025-08-26 12:32:21 -07:00
}
2025-08-28 12:37:07 -07:00
// Use enhanced formatting with display augmentation
const formattedItem = await formatItemWithDisplay ( item , options . format )
console . log ( formattedItem )
2025-08-26 12:32:21 -07:00
} ) )
// Command 5: UPDATE - Update existing data
program
. command ( 'update [id]' )
. description ( 'Update existing data with new content or metadata' )
. option ( '-d, --data <data>' , 'New data content' )
. option ( '-m, --metadata <json>' , 'New metadata as JSON' )
. option ( '--no-merge' , 'Replace metadata instead of merging' )
. option ( '--no-reindex' , 'Skip reindexing (faster but less accurate search)' )
. option ( '--cascade' , 'Update related verbs' )
. action ( wrapAction ( async ( id , options ) => {
// Interactive mode if no ID provided
if ( ! id ) {
console . log ( colors . primary ( '🔄 Interactive Update Mode' ) )
console . log ( colors . dim ( 'Select an item to update\n' ) )
// Show recent items
const brainyInstance = await getBrainy ( )
const recent = await brainyInstance . search ( '*' , { limit : 10 , sortBy : 'timestamp' } )
if ( recent . length > 0 ) {
console . log ( colors . cyan ( 'Recent items:' ) )
2025-08-28 12:37:07 -07:00
// Enhanced display for recent items
for ( let i = 0 ; i < Math . min ( recent . length , 10 ) ; i ++ ) {
const item = recent [ i ]
try {
if ( item . getDisplay && typeof item . getDisplay === 'function' ) {
const displayFields = await item . getDisplay ( )
console . log ( colors . info ( ` ${ i + 1 } . ${ item . id } - ${ displayFields . title } ` ) )
} else {
console . log ( colors . info ( ` ${ i + 1 } . ${ item . id } - ${ item . content ? . substring ( 0 , 50 ) } ... ` ) )
}
} catch {
console . log ( colors . info ( ` ${ i + 1 } . ${ item . id } - ${ item . content ? . substring ( 0 , 50 ) } ... ` ) )
}
}
2025-08-26 12:32:21 -07:00
console . log ( )
}
const rl = createInterface ( {
input : process . stdin ,
output : process . stdout
} )
id = await new Promise ( resolve => {
rl . question ( colors . cyan ( 'Enter ID to update: ' ) , ( answer ) => {
rl . close ( )
resolve ( answer )
} )
} )
if ( ! id . trim ( ) ) {
console . log ( colors . warning ( 'No ID provided' ) )
process . exit ( 1 )
}
}
console . log ( colors . info ( ` 🔄 Updating: " ${ id } " ` ) )
if ( ! options . data && ! options . metadata ) {
console . error ( colors . error ( 'Error: Must provide --data or --metadata' ) )
process . exit ( 1 )
}
let metadata = undefined
if ( options . metadata ) {
try {
metadata = JSON . parse ( options . metadata )
} catch {
console . error ( colors . error ( 'Invalid JSON metadata' ) )
process . exit ( 1 )
}
}
const brainyInstance = await getBrainy ( )
const success = await brainyInstance . updateNoun ( id , options . data , metadata , {
merge : options . merge !== false , // Default true unless --no-merge
reindex : options . reindex !== false , // Default true unless --no-reindex
cascade : options . cascade || false
} )
if ( success ) {
console . log ( colors . success ( '✅ Updated successfully!' ) )
if ( options . cascade ) {
console . log ( colors . info ( '📎 Related verbs updated' ) )
}
} else {
console . log ( colors . error ( '❌ Update failed' ) )
}
} ) )
// Command 5: DELETE - Remove data (soft delete by default)
program
. command ( 'delete [id]' )
. description ( 'Delete data (soft delete by default, preserves indexes)' )
. option ( '--hard' , 'Permanent deletion (removes from indexes)' )
. option ( '--cascade' , 'Delete related verbs' )
. option ( '--force' , 'Force delete even if has relationships' )
. action ( wrapAction ( async ( id , options ) => {
// Interactive mode if no ID provided
if ( ! id ) {
console . log ( colors . warning ( '🗑️ Interactive Delete Mode' ) )
console . log ( colors . dim ( 'Select an item to delete\n' ) )
// Show recent items for selection
const brainyInstance = await getBrainy ( )
const recent = await brainyInstance . search ( '*' , { limit : 10 , sortBy : 'timestamp' } )
if ( recent . length > 0 ) {
console . log ( colors . cyan ( 'Recent items:' ) )
2025-08-28 12:37:07 -07:00
// Enhanced display for recent items
for ( let i = 0 ; i < Math . min ( recent . length , 10 ) ; i ++ ) {
const item = recent [ i ]
try {
if ( item . getDisplay && typeof item . getDisplay === 'function' ) {
const displayFields = await item . getDisplay ( )
console . log ( colors . info ( ` ${ i + 1 } . ${ item . id } - ${ displayFields . title } ` ) )
} else {
console . log ( colors . info ( ` ${ i + 1 } . ${ item . id } - ${ item . content ? . substring ( 0 , 50 ) } ... ` ) )
}
} catch {
console . log ( colors . info ( ` ${ i + 1 } . ${ item . id } - ${ item . content ? . substring ( 0 , 50 ) } ... ` ) )
}
}
2025-08-26 12:32:21 -07:00
console . log ( )
}
const rl = createInterface ( {
input : process . stdin ,
output : process . stdout
} )
id = await new Promise ( resolve => {
rl . question ( colors . warning ( 'Enter ID to delete (or "cancel"): ' ) , ( answer ) => {
rl . close ( )
resolve ( answer )
} )
} )
if ( ! id . trim ( ) || id . toLowerCase ( ) === 'cancel' ) {
console . log ( colors . info ( 'Delete cancelled' ) )
process . exit ( 0 )
}
// Confirm deletion in interactive mode
const confirmRl = createInterface ( {
input : process . stdin ,
output : process . stdout
} )
const confirm = await new Promise ( resolve => {
const deleteType = options . hard ? 'permanently delete' : 'soft delete'
confirmRl . question ( colors . warning ( ` Are you sure you want to ${ deleteType } " ${ id } "? (yes/no): ` ) , ( answer ) => {
confirmRl . close ( )
resolve ( answer . toLowerCase ( ) === 'yes' || answer . toLowerCase ( ) === 'y' )
} )
} )
if ( ! confirm ) {
console . log ( colors . info ( 'Delete cancelled' ) )
process . exit ( 0 )
}
}
console . log ( colors . info ( ` 🗑️ Deleting: " ${ id } " ` ) )
if ( options . hard ) {
console . log ( colors . warning ( '⚠️ Hard delete - data will be permanently removed' ) )
} else {
console . log ( colors . info ( '🔒 Soft delete - data marked as deleted but preserved' ) )
}
const brainyInstance = await getBrainy ( )
try {
const success = await brainyInstance . deleteNoun ( id , {
soft : ! options . hard , // Soft delete unless --hard specified
cascade : options . cascade || false ,
force : options . force || false
} )
if ( success ) {
console . log ( colors . success ( '✅ Deleted successfully!' ) )
if ( options . cascade ) {
console . log ( colors . info ( '📎 Related verbs also deleted' ) )
}
} else {
console . log ( colors . error ( '❌ Delete failed' ) )
}
} catch ( error ) {
console . error ( colors . error ( ` ❌ Delete failed: ${ error . message } ` ) )
if ( error . message . includes ( 'has relationships' ) ) {
console . log ( colors . info ( '💡 Try: --cascade to delete relationships or --force to ignore them' ) )
}
}
} ) )
// Command 6A: ADD-NOUN - Create typed entities (Method #4)
program
. command ( 'add-noun [name]' )
. description ( 'Add a typed entity to your knowledge graph' )
. option ( '-t, --type <type>' , 'Noun type (Person, Organization, Project, Event, Concept, Location, Product)' , 'Concept' )
. option ( '-m, --metadata <json>' , 'Metadata as JSON' )
. option ( '--encrypt' , 'Encrypt this entity' )
. action ( wrapAction ( async ( name , options ) => {
// Interactive mode if no name provided
if ( ! name ) {
console . log ( colors . primary ( '👤 Interactive Entity Creation' ) )
console . log ( colors . dim ( 'Create a typed entity in your knowledge graph\n' ) )
const rl = createInterface ( {
input : process . stdin ,
output : process . stdout
} )
name = await new Promise ( resolve => {
rl . question ( colors . cyan ( 'Enter entity name: ' ) , ( answer ) => {
resolve ( answer )
} )
} )
if ( ! name . trim ( ) ) {
rl . close ( )
console . log ( colors . warning ( 'No name provided' ) )
process . exit ( 1 )
}
// Interactive type selection if not provided
if ( ! options . type || options . type === 'Concept' ) {
console . log ( colors . cyan ( '\nSelect entity type:' ) )
const types = [ 'Person' , 'Organization' , 'Project' , 'Event' , 'Concept' , 'Location' , 'Product' ]
types . forEach ( ( t , i ) => {
console . log ( colors . info ( ` ${ i + 1 } . ${ t } ` ) )
} )
console . log ( )
const typeIndex = await new Promise ( resolve => {
rl . question ( colors . cyan ( 'Select type (1-7): ' ) , ( answer ) => {
resolve ( parseInt ( answer ) - 1 )
} )
} )
if ( typeIndex >= 0 && typeIndex < types . length ) {
options . type = types [ typeIndex ]
}
}
rl . close ( )
}
const brainy = await getBrainy ( )
// Validate noun type
const validTypes = [ 'Person' , 'Organization' , 'Project' , 'Event' , 'Concept' , 'Location' , 'Product' ]
if ( ! validTypes . includes ( options . type ) ) {
console . log ( colors . error ( ` ❌ Invalid noun type: ${ options . type } ` ) )
console . log ( colors . info ( ` Valid types: ${ validTypes . join ( ', ' ) } ` ) )
process . exit ( 1 )
}
let metadata = { }
if ( options . metadata ) {
try {
metadata = JSON . parse ( options . metadata )
} catch {
console . error ( colors . error ( '❌ Invalid JSON metadata' ) )
process . exit ( 1 )
}
}
if ( options . encrypt ) {
metadata . encrypted = true
}
try {
// In 2.0 API, addNoun takes (data, metadata) - type goes in metadata
metadata . type = options . type
const id = await brainy . addNoun ( name , metadata )
console . log ( colors . success ( '✅ Noun added successfully!' ) )
console . log ( colors . info ( ` 🆔 ID: ${ id } ` ) )
console . log ( colors . info ( ` 👤 Name: ${ name } ` ) )
console . log ( colors . info ( ` 🏷️ Type: ${ options . type } ` ) )
if ( Object . keys ( metadata ) . length > 0 ) {
console . log ( colors . info ( ` 📝 Metadata: ${ JSON . stringify ( metadata , null , 2 ) } ` ) )
}
} catch ( error ) {
console . log ( colors . error ( '❌ Failed to add noun:' ) )
console . log ( colors . error ( error . message ) )
process . exit ( 1 )
}
} ) )
// Command 6B: ADD-VERB - Create relationships (Method #5)
program
. command ( 'add-verb [source] [target]' )
. description ( 'Create a relationship between two entities' )
. option ( '-t, --type <type>' , 'Verb type (WorksFor, Knows, CreatedBy, BelongsTo, Uses, etc.)' , 'RelatedTo' )
. option ( '-m, --metadata <json>' , 'Relationship metadata as JSON' )
. option ( '--encrypt' , 'Encrypt this relationship' )
. action ( wrapAction ( async ( source , target , options ) => {
// Interactive mode if parameters missing
if ( ! source || ! target ) {
console . log ( colors . primary ( '🔗 Interactive Relationship Builder' ) )
console . log ( colors . dim ( 'Connect two entities with a semantic relationship\n' ) )
const brainyInstance = await getBrainy ( )
const rl = createInterface ( {
input : process . stdin ,
output : process . stdout
} )
// Get source if not provided
if ( ! source ) {
// Show recent items
const recent = await brainyInstance . search ( '*' , { limit : 10 , sortBy : 'timestamp' } )
if ( recent . length > 0 ) {
console . log ( colors . cyan ( 'Recent items (source):' ) )
2025-08-28 12:37:07 -07:00
// Enhanced display for recent items
for ( let i = 0 ; i < Math . min ( recent . length , 10 ) ; i ++ ) {
const item = recent [ i ]
try {
if ( item . getDisplay && typeof item . getDisplay === 'function' ) {
const displayFields = await item . getDisplay ( )
console . log ( colors . info ( ` ${ i + 1 } . ${ displayFields . icon } ${ item . id } - ${ displayFields . title } ` ) )
} else {
console . log ( colors . info ( ` ${ i + 1 } . ${ item . id } - ${ item . content ? . substring ( 0 , 40 ) } ... ` ) )
}
} catch {
console . log ( colors . info ( ` ${ i + 1 } . ${ item . id } - ${ item . content ? . substring ( 0 , 40 ) } ... ` ) )
}
}
2025-08-26 12:32:21 -07:00
console . log ( )
}
source = await new Promise ( resolve => {
rl . question ( colors . cyan ( 'Enter source entity ID: ' ) , ( answer ) => {
resolve ( answer )
} )
} )
if ( ! source . trim ( ) ) {
rl . close ( )
console . log ( colors . warning ( 'No source provided' ) )
process . exit ( 1 )
}
}
// Interactive verb type selection
if ( ! options . type || options . type === 'RelatedTo' ) {
console . log ( colors . cyan ( '\nSelect relationship type:' ) )
const verbs = [ 'WorksFor' , 'Knows' , 'CreatedBy' , 'BelongsTo' , 'Uses' , 'Manages' , 'LocatedIn' , 'RelatedTo' , 'Custom...' ]
verbs . forEach ( ( v , i ) => {
console . log ( colors . info ( ` ${ i + 1 } . ${ v } ` ) )
} )
console . log ( )
const verbIndex = await new Promise ( resolve => {
rl . question ( colors . cyan ( 'Select type (1-9): ' ) , ( answer ) => {
resolve ( parseInt ( answer ) - 1 )
} )
} )
if ( verbIndex >= 0 && verbIndex < verbs . length - 1 ) {
options . type = verbs [ verbIndex ]
} else if ( verbIndex === verbs . length - 1 ) {
// Custom verb
options . type = await new Promise ( resolve => {
rl . question ( colors . cyan ( 'Enter custom relationship: ' ) , ( answer ) => {
resolve ( answer )
} )
} )
}
}
// Get target if not provided
if ( ! target ) {
// Show recent items again
const recent = await brainyInstance . search ( '*' , { limit : 10 , sortBy : 'timestamp' } )
if ( recent . length > 0 ) {
console . log ( colors . cyan ( '\nRecent items (target):' ) )
2025-08-28 12:37:07 -07:00
// Enhanced display for recent items
for ( let i = 0 ; i < Math . min ( recent . length , 10 ) ; i ++ ) {
const item = recent [ i ]
try {
if ( item . getDisplay && typeof item . getDisplay === 'function' ) {
const displayFields = await item . getDisplay ( )
console . log ( colors . info ( ` ${ i + 1 } . ${ displayFields . icon } ${ item . id } - ${ displayFields . title } ` ) )
} else {
console . log ( colors . info ( ` ${ i + 1 } . ${ item . id } - ${ item . content ? . substring ( 0 , 40 ) } ... ` ) )
}
} catch {
console . log ( colors . info ( ` ${ i + 1 } . ${ item . id } - ${ item . content ? . substring ( 0 , 40 ) } ... ` ) )
}
}
2025-08-26 12:32:21 -07:00
console . log ( )
}
target = await new Promise ( resolve => {
rl . question ( colors . cyan ( 'Enter target entity ID: ' ) , ( answer ) => {
resolve ( answer )
} )
} )
if ( ! target . trim ( ) ) {
rl . close ( )
console . log ( colors . warning ( 'No target provided' ) )
process . exit ( 1 )
}
}
rl . close ( )
}
const brainy = await getBrainy ( )
// Common verb types for validation
const commonTypes = [ 'WorksFor' , 'Knows' , 'CreatedBy' , 'BelongsTo' , 'Uses' , 'LeadsProject' , 'MemberOf' , 'RelatedTo' , 'InteractedWith' ]
if ( ! commonTypes . includes ( options . type ) ) {
console . log ( colors . warning ( ` ⚠️ Uncommon verb type: ${ options . type } ` ) )
console . log ( colors . info ( ` Common types: ${ commonTypes . join ( ', ' ) } ` ) )
}
let metadata = { }
if ( options . metadata ) {
try {
metadata = JSON . parse ( options . metadata )
} catch {
console . error ( colors . error ( '❌ Invalid JSON metadata' ) )
process . exit ( 1 )
}
}
if ( options . encrypt ) {
metadata . encrypted = true
}
try {
const { VerbType } = await import ( '../dist/types/graphTypes.js' )
// Use the provided type or fall back to RelatedTo
const verbType = VerbType [ options . type ] || options . type
const id = await brainy . addVerb ( source , target , verbType , metadata )
console . log ( colors . success ( '✅ Relationship added successfully!' ) )
console . log ( colors . info ( ` 🆔 ID: ${ id } ` ) )
console . log ( colors . info ( ` 🔗 ${ source } --[ ${ options . type } ]--> ${ target } ` ) )
if ( Object . keys ( metadata ) . length > 0 ) {
console . log ( colors . info ( ` 📝 Metadata: ${ JSON . stringify ( metadata , null , 2 ) } ` ) )
}
} catch ( error ) {
console . log ( colors . error ( '❌ Failed to add relationship:' ) )
console . log ( colors . error ( error . message ) )
process . exit ( 1 )
}
} ) )
// Command 7: STATUS - Database health & info
program
. command ( 'status' )
. description ( 'Show brain status and comprehensive statistics' )
. option ( '-v, --verbose' , 'Show raw JSON statistics' )
. option ( '-s, --simple' , 'Show only basic info' )
. action ( wrapAction ( async ( options ) => {
console . log ( colors . primary ( '🧠 Brain Status & Statistics' ) )
console . log ( colors . primary ( '=' . repeat ( 50 ) ) )
try {
const { BrainyData } = await import ( '../dist/brainyData.js' )
const brainy = new BrainyData ( )
await brainy . init ( )
// Get comprehensive stats
const stats = await brainy . getStatistics ( )
const memUsage = process . memoryUsage ( )
// Basic Health Status
console . log ( colors . success ( '💚 Status: Healthy' ) )
console . log ( colors . info ( ` 🚀 Version: ${ packageJson . version } ` ) )
console . log ( )
if ( options . simple ) {
console . log ( colors . info ( ` 📊 Total Items: ${ stats . total || 0 } ` ) )
console . log ( colors . info ( ` 🧠 Memory: ${ ( memUsage . heapUsed / 1024 / 1024 ) . toFixed ( 1 ) } MB ` ) )
return
}
// Core Statistics
console . log ( colors . primary ( '📊 Core Database Statistics' ) )
console . log ( colors . info ( ` Total Items: ${ colors . success ( stats . total || 0 ) } ` ) )
console . log ( colors . info ( ` Nouns: ${ colors . success ( stats . nounCount || 0 ) } ` ) )
console . log ( colors . info ( ` Verbs (Relationships): ${ colors . success ( stats . verbCount || 0 ) } ` ) )
console . log ( colors . info ( ` Metadata Records: ${ colors . success ( stats . metadataCount || 0 ) } ` ) )
console . log ( )
// Per-Service Breakdown (if available)
if ( stats . serviceBreakdown && Object . keys ( stats . serviceBreakdown ) . length > 0 ) {
console . log ( colors . primary ( '🔧 Per-Service Breakdown' ) )
Object . entries ( stats . serviceBreakdown ) . forEach ( ( [ service , serviceStats ] ) => {
console . log ( colors . info ( ` ${ colors . success ( service ) } : ` ) )
console . log ( colors . info ( ` Nouns: ${ serviceStats . nounCount } ` ) )
console . log ( colors . info ( ` Verbs: ${ serviceStats . verbCount } ` ) )
console . log ( colors . info ( ` Metadata: ${ serviceStats . metadataCount } ` ) )
} )
console . log ( )
}
// Storage Information
if ( stats . storage ) {
console . log ( colors . primary ( '💾 Storage Information' ) )
console . log ( colors . info ( ` Type: ${ colors . success ( stats . storage . type || 'Unknown' ) } ` ) )
if ( stats . storage . size ) {
const sizeInMB = ( stats . storage . size / 1024 / 1024 ) . toFixed ( 2 )
console . log ( colors . info ( ` Size: ${ colors . success ( sizeInMB ) } MB ` ) )
}
if ( stats . storage . location ) {
console . log ( colors . info ( ` Location: ${ colors . success ( stats . storage . location ) } ` ) )
}
console . log ( )
}
// Performance Metrics
if ( stats . performance ) {
console . log ( colors . primary ( '⚡ Performance Metrics' ) )
if ( stats . performance . avgQueryTime ) {
console . log ( colors . info ( ` Avg Query Time: ${ colors . success ( stats . performance . avgQueryTime . toFixed ( 2 ) ) } ms ` ) )
}
if ( stats . performance . totalQueries ) {
console . log ( colors . info ( ` Total Queries: ${ colors . success ( stats . performance . totalQueries ) } ` ) )
}
if ( stats . performance . cacheHitRate ) {
console . log ( colors . info ( ` Cache Hit Rate: ${ colors . success ( ( stats . performance . cacheHitRate * 100 ) . toFixed ( 1 ) ) } % ` ) )
}
console . log ( )
}
// Vector Index Information
if ( stats . index ) {
console . log ( colors . primary ( '🎯 Vector Index' ) )
console . log ( colors . info ( ` Dimensions: ${ colors . success ( stats . index . dimensions || 'N/A' ) } ` ) )
console . log ( colors . info ( ` Indexed Vectors: ${ colors . success ( stats . index . vectorCount || 0 ) } ` ) )
if ( stats . index . indexSize ) {
console . log ( colors . info ( ` Index Size: ${ colors . success ( ( stats . index . indexSize / 1024 / 1024 ) . toFixed ( 2 ) ) } MB ` ) )
}
console . log ( )
}
// Memory Usage Breakdown
console . log ( colors . primary ( '🧠 Memory Usage' ) )
console . log ( colors . info ( ` Heap Used: ${ colors . success ( ( memUsage . heapUsed / 1024 / 1024 ) . toFixed ( 1 ) ) } MB ` ) )
console . log ( colors . info ( ` Heap Total: ${ colors . success ( ( memUsage . heapTotal / 1024 / 1024 ) . toFixed ( 1 ) ) } MB ` ) )
console . log ( colors . info ( ` RSS: ${ colors . success ( ( memUsage . rss / 1024 / 1024 ) . toFixed ( 1 ) ) } MB ` ) )
console . log ( )
// Active Augmentations
console . log ( colors . primary ( '🔌 Active Augmentations' ) )
2025-08-28 12:37:07 -07:00
try {
// Check for display augmentation specifically
const displayAugmentation = ( brainy as any ) . augmentations ? . get ( 'display' )
if ( displayAugmentation ) {
console . log ( colors . success ( ` ✅ display - Universal Display Augmentation ` ) )
console . log ( colors . info ( ` 🎨 AI-powered titles and descriptions ` ) )
// Get display augmentation stats if available
if ( displayAugmentation . getStats ) {
const stats = displayAugmentation . getStats ( )
if ( stats . totalComputations > 0 ) {
console . log ( colors . dim ( ` 📊 ${ stats . totalComputations } computations, ${ ( stats . cacheHitRatio * 100 ) . toFixed ( 1 ) } % cache hit rate ` ) )
}
}
}
// Show other augmentations
const otherAugs = ( brainy as any ) . augmentations ?
Array . from ( ( brainy as any ) . augmentations . values ( ) ) . filter ( ( aug : any ) => aug . name !== 'display' ) :
[ ]
otherAugs . forEach ( ( aug : any ) => {
2025-08-26 12:32:21 -07:00
console . log ( colors . success ( ` ✅ ${ aug . name } ` ) )
2025-08-28 12:37:07 -07:00
if ( aug . version ) {
console . log ( colors . info ( ` v ${ aug . version } - ${ aug . description || 'No description' } ` ) )
2025-08-26 12:32:21 -07:00
}
} )
2025-08-28 12:37:07 -07:00
if ( ! displayAugmentation && otherAugs . length === 0 ) {
console . log ( colors . warning ( ' No augmentations currently active' ) )
}
} catch ( error ) {
console . log ( colors . warning ( ' Augmentation status unavailable' ) )
2025-08-26 12:32:21 -07:00
}
console . log ( )
// Configuration Summary
if ( stats . config ) {
console . log ( colors . primary ( '⚙️ Configuration' ) )
Object . entries ( stats . config ) . forEach ( ( [ key , value ] ) => {
// Don't show sensitive values
if ( key . toLowerCase ( ) . includes ( 'key' ) || key . toLowerCase ( ) . includes ( 'secret' ) ) {
console . log ( colors . info ( ` ${ key } : ${ colors . warning ( '[HIDDEN]' ) } ` ) )
} else {
console . log ( colors . info ( ` ${ key } : ${ colors . success ( value ) } ` ) )
}
} )
console . log ( )
}
// Available Fields for Advanced Search
console . log ( colors . primary ( '🔍 Available Search Fields' ) )
try {
const filterFields = await brainy . getFilterFields ( )
if ( filterFields . length > 0 ) {
console . log ( colors . info ( ' Use these fields for advanced filtering:' ) )
filterFields . forEach ( field => {
console . log ( colors . success ( ` ${ field } ` ) )
} )
console . log ( colors . info ( '\n Example: brainy search "query" --filter \'{"type":"person"}\'' ) )
} else {
console . log ( colors . warning ( ' No indexed fields available yet' ) )
console . log ( colors . info ( ' Add some data to see available fields' ) )
}
} catch ( error ) {
console . log ( colors . warning ( ' Field discovery not available' ) )
}
console . log ( )
// Show raw JSON if verbose
if ( options . verbose ) {
console . log ( colors . primary ( '📋 Raw Statistics (JSON)' ) )
console . log ( colors . info ( JSON . stringify ( stats , null , 2 ) ) )
}
} catch ( error ) {
console . log ( colors . error ( '❌ Status: Error' ) )
console . log ( colors . error ( ` Error: ${ error . message } ` ) )
if ( options . verbose ) {
console . log ( colors . error ( 'Stack trace:' ) )
console . log ( error . stack )
}
}
} ) )
// Command 5: CONFIG - Essential configuration
program
. command ( 'config <action> [key] [value]' )
. description ( 'Configure brainy (get, set, list)' )
. action ( wrapAction ( async ( action , key , value ) => {
const configActions = {
get : async ( ) => {
if ( ! key ) {
console . error ( colors . error ( 'Please specify a key: brainy config get <key>' ) )
process . exit ( 1 )
}
const result = await cortex . configGet ( key )
console . log ( colors . success ( ` ${ key } : ${ result || 'not set' } ` ) )
} ,
set : async ( ) => {
if ( ! key || ! value ) {
console . error ( colors . error ( 'Usage: brainy config set <key> <value>' ) )
process . exit ( 1 )
}
await cortex . configSet ( key , value )
console . log ( colors . success ( ` ✅ Set ${ key } = ${ value } ` ) )
} ,
list : async ( ) => {
const config = await cortex . configList ( )
console . log ( colors . primary ( '🔧 Current Configuration:' ) )
Object . entries ( config ) . forEach ( ( [ k , v ] ) => {
console . log ( colors . info ( ` ${ k } : ${ v } ` ) )
} )
}
}
if ( configActions [ action ] ) {
await configActions [ action ] ( )
} else {
console . error ( colors . error ( 'Valid actions: get, set, list' ) )
process . exit ( 1 )
}
} ) )
// Command 6: AUGMENT - Manage augmentations (The 8th Unified Method!)
program
. command ( 'augment <action>' )
. description ( 'Manage augmentations to extend Brainy\'s capabilities' )
. option ( '-n, --name <name>' , 'Augmentation name' )
. option ( '-t, --type <type>' , 'Augmentation type (sense, conduit, cognition, memory)' )
. option ( '-p, --path <path>' , 'Path to augmentation module' )
. option ( '-l, --list' , 'List all augmentations' )
. action ( wrapAction ( async ( action , options ) => {
const brainy = await initBrainy ( )
console . log ( colors . brain ( '🧩 Augmentation Management' ) )
const actions = {
list : async ( ) => {
try {
// Use soulcraft.com registry API
const REGISTRY _URL = 'https://api.soulcraft.com/v1/augmentations'
const response = await fetch ( REGISTRY _URL )
if ( response && response . ok ) {
console . log ( colors . brain ( '🏢 SOULCRAFT PROFESSIONAL SUITE\n' ) )
const data = await response . json ( )
const augmentations = data . data || [ ] // NEW: data is in .data array
// Get local augmentations to check what's installed
const localAugmentations = brainy . listAugmentations ( )
const localPackageNames = localAugmentations . map ( aug => aug . package || aug . name ) . filter ( Boolean )
// Find installed registry augmentations
const installed = augmentations . filter ( aug =>
aug . package && localPackageNames . includes ( aug . package )
)
// Display installed augmentations first
if ( installed . length > 0 ) {
console . log ( colors . success ( '✅ INSTALLED AUGMENTATIONS' ) )
installed . forEach ( aug => {
const pricing = aug . price
? ` $ ${ aug . price . monthly } /mo `
: ( aug . tier === 'free' ? 'FREE' : 'TBD' )
const pricingColor = aug . tier === 'free' ? colors . success ( pricing ) : colors . yellow ( pricing )
console . log ( ` ${ aug . name . padEnd ( 20 ) } ${ pricingColor . padEnd ( 15 ) } ${ colors . success ( '✅ ACTIVE' ) } ` )
console . log ( ` ${ colors . dim ( aug . description ) } ` )
console . log ( '' )
} )
console . log ( '' ) // Extra space before available augmentations
}
// Filter out installed ones from the available lists
const availableAugmentations = augmentations . filter ( aug =>
! installed . find ( inst => inst . id === aug . id )
)
// NEW: Use new tier names - "premium" instead of "professional"
const premium = availableAugmentations . filter ( a => a . tier === 'premium' )
const free = availableAugmentations . filter ( a => a . tier === 'free' )
const community = availableAugmentations . filter ( a => a . tier === 'community' )
const comingSoon = availableAugmentations . filter ( a => a . status === 'coming_soon' )
// Display premium augmentations
if ( premium . length > 0 ) {
console . log ( colors . primary ( '🚀 PREMIUM AUGMENTATIONS' ) )
premium . forEach ( aug => {
// NEW: price object format
const pricing = aug . price
? ` $ ${ aug . price . monthly } /mo `
: ( aug . tier === 'free' ? 'FREE' : 'TBD' )
const pricingColor = aug . tier === 'free' ? colors . success ( pricing ) : colors . yellow ( pricing )
// NEW: status instead of verified
const status = aug . status === 'available' ? colors . blue ( '✓' ) :
aug . status === 'coming_soon' ? colors . yellow ( '⏳' ) :
colors . dim ( '•' )
console . log ( ` ${ aug . name . padEnd ( 20 ) } ${ pricingColor . padEnd ( 15 ) } ${ status } ` )
console . log ( ` ${ colors . dim ( aug . description ) } ` )
if ( aug . status === 'coming_soon' && aug . eta ) {
console . log ( ` ${ colors . cyan ( '→ Coming ' + aug . eta ) } ` )
}
if ( aug . features && aug . features . length > 0 ) {
console . log ( ` ${ colors . cyan ( '→ ' + aug . features . join ( ', ' ) ) } ` )
}
console . log ( '' )
} )
}
// Display free augmentations
if ( free . length > 0 ) {
console . log ( colors . primary ( '🆓 FREE AUGMENTATIONS' ) )
free . forEach ( aug => {
const status = aug . status === 'available' ? colors . blue ( '✓' ) :
aug . status === 'coming_soon' ? colors . yellow ( '⏳' ) :
colors . dim ( '•' )
console . log ( ` ${ aug . name . padEnd ( 20 ) } ${ colors . success ( 'FREE' ) . padEnd ( 15 ) } ${ status } ` )
console . log ( ` ${ colors . dim ( aug . description ) } ` )
if ( aug . status === 'coming_soon' && aug . eta ) {
console . log ( ` ${ colors . cyan ( '→ Coming ' + aug . eta ) } ` )
}
console . log ( '' )
} )
}
// Display community augmentations
if ( community . length > 0 ) {
console . log ( colors . primary ( '👥 COMMUNITY AUGMENTATIONS' ) )
community . forEach ( aug => {
const status = aug . status === 'available' ? colors . blue ( '✓' ) :
aug . status === 'coming_soon' ? colors . yellow ( '⏳' ) :
colors . dim ( '•' )
console . log ( ` ${ aug . name . padEnd ( 20 ) } ${ colors . success ( 'COMMUNITY' ) . padEnd ( 15 ) } ${ status } ` )
console . log ( ` ${ colors . dim ( aug . description ) } ` )
console . log ( '' )
} )
}
// Display truly local (non-registry) augmentations
const localOnly = localAugmentations . filter ( aug =>
! aug . package || ! augmentations . find ( regAug => regAug . package === aug . package )
)
if ( localOnly . length > 0 ) {
console . log ( colors . primary ( '📦 CUSTOM AUGMENTATIONS' ) )
localOnly . forEach ( aug => {
const status = aug . enabled ? colors . success ( '✅ Enabled' ) : colors . dim ( '⚪ Disabled' )
console . log ( ` ${ aug . name . padEnd ( 20 ) } ${ status } ` )
console . log ( ` ${ colors . dim ( aug . description || 'Custom augmentation' ) } ` )
console . log ( '' )
} )
}
console . log ( colors . cyan ( '🎯 GET STARTED' ) )
console . log ( ' brainy install <name> Install augmentation' )
console . log ( ' brainy cloud Access Brain Cloud features' )
console . log ( ` ${ colors . blue ( 'Learn more:' ) } https://soulcraft.com/augmentations ` )
} else {
throw new Error ( 'Registry unavailable' )
}
} catch ( error ) {
// Fallback to local augmentations only
console . log ( colors . warning ( '⚠ Professional catalog unavailable, showing local augmentations' ) )
const augmentations = brainy . listAugmentations ( )
if ( augmentations . length === 0 ) {
console . log ( colors . warning ( 'No augmentations registered' ) )
return
}
const table = new Table ( {
head : [ colors . brain ( 'Name' ) , colors . brain ( 'Type' ) , colors . brain ( 'Status' ) , colors . brain ( 'Description' ) ] ,
style : { head : [ ] , border : [ ] }
} )
augmentations . forEach ( aug => {
table . push ( [
colors . primary ( aug . name ) ,
colors . info ( aug . type ) ,
aug . enabled ? colors . success ( '✅ Enabled' ) : colors . dim ( '⚪ Disabled' ) ,
colors . dim ( aug . description || '' )
] )
} )
console . log ( table . toString ( ) )
console . log ( colors . info ( ` \n Total: ${ augmentations . length } augmentations ` ) )
}
} ,
enable : async ( ) => {
if ( ! options . name ) {
console . log ( colors . error ( 'Name required: --name <augmentation-name>' ) )
return
}
const success = brainy . enableAugmentation ( options . name )
if ( success ) {
console . log ( colors . success ( ` ✅ Enabled augmentation: ${ options . name } ` ) )
} else {
console . log ( colors . error ( ` Failed to enable: ${ options . name } (not found) ` ) )
}
} ,
disable : async ( ) => {
if ( ! options . name ) {
console . log ( colors . error ( 'Name required: --name <augmentation-name>' ) )
return
}
const success = brainy . disableAugmentation ( options . name )
if ( success ) {
console . log ( colors . warning ( ` ⚪ Disabled augmentation: ${ options . name } ` ) )
} else {
console . log ( colors . error ( ` Failed to disable: ${ options . name } (not found) ` ) )
}
} ,
register : async ( ) => {
if ( ! options . path ) {
console . log ( colors . error ( 'Path required: --path <augmentation-module>' ) )
return
}
try {
// Dynamic import of custom augmentation
const customModule = await import ( options . path )
const AugmentationClass = customModule . default || customModule [ Object . keys ( customModule ) [ 0 ] ]
if ( ! AugmentationClass ) {
console . log ( colors . error ( 'No augmentation class found in module' ) )
return
}
const augmentation = new AugmentationClass ( )
brainy . register ( augmentation )
console . log ( colors . success ( ` ✅ Registered augmentation: ${ augmentation . name } ` ) )
console . log ( colors . info ( ` Type: ${ augmentation . type } ` ) )
if ( augmentation . description ) {
console . log ( colors . dim ( ` Description: ${ augmentation . description } ` ) )
}
} catch ( error ) {
console . log ( colors . error ( ` Failed to register augmentation: ${ error . message } ` ) )
}
} ,
unregister : async ( ) => {
if ( ! options . name ) {
console . log ( colors . error ( 'Name required: --name <augmentation-name>' ) )
return
}
brainy . unregister ( options . name )
console . log ( colors . warning ( ` 🗑️ Unregistered augmentation: ${ options . name } ` ) )
} ,
'enable-type' : async ( ) => {
if ( ! options . type ) {
console . log ( colors . error ( 'Type required: --type <augmentation-type>' ) )
console . log ( colors . info ( 'Valid types: sense, conduit, cognition, memory, perception, dialog, activation' ) )
return
}
const count = brainy . enableAugmentationType ( options . type )
console . log ( colors . success ( ` ✅ Enabled ${ count } ${ options . type } augmentations ` ) )
} ,
'disable-type' : async ( ) => {
if ( ! options . type ) {
console . log ( colors . error ( 'Type required: --type <augmentation-type>' ) )
console . log ( colors . info ( 'Valid types: sense, conduit, cognition, memory, perception, dialog, activation' ) )
return
}
const count = brainy . disableAugmentationType ( options . type )
console . log ( colors . warning ( ` ⚪ Disabled ${ count } ${ options . type } augmentations ` ) )
}
}
if ( actions [ action ] ) {
await actions [ action ] ( )
} else {
console . log ( colors . error ( 'Valid actions: list, enable, disable, register, unregister, enable-type, disable-type' ) )
console . log ( colors . info ( '\nExamples:' ) )
console . log ( colors . dim ( ' brainy augment list # List all augmentations' ) )
console . log ( colors . dim ( ' brainy augment enable --name neural-import # Enable an augmentation' ) )
console . log ( colors . dim ( ' brainy augment register --path ./my-augmentation.js # Register custom augmentation' ) )
console . log ( colors . dim ( ' brainy augment enable-type --type sense # Enable all sense augmentations' ) )
}
} ) )
// Command 7: CLEAR - Clear all data
program
. command ( 'clear' )
. description ( 'Clear all data from your brain (with safety prompt)' )
. option ( '--force' , 'Force clear without confirmation' )
. option ( '--backup' , 'Create backup before clearing' )
. action ( wrapAction ( async ( options ) => {
if ( ! options . force ) {
console . log ( colors . warning ( '🚨 This will delete ALL data in your brain!' ) )
const rl = createInterface ( {
input : process . stdin ,
output : process . stdout
} )
const confirmed = await new Promise ( resolve => {
rl . question ( colors . warning ( 'Type "DELETE EVERYTHING" to confirm: ' ) , ( answer ) => {
rl . close ( )
resolve ( answer === 'DELETE EVERYTHING' )
} )
} )
if ( ! confirmed ) {
console . log ( colors . info ( 'Clear operation cancelled' ) )
return
}
}
const brainyInstance = await getBrainy ( )
if ( options . backup ) {
console . log ( colors . info ( '💾 Creating backup...' ) )
// Future: implement backup functionality
console . log ( colors . success ( '✅ Backup created' ) )
}
console . log ( colors . info ( '🗑️ Clearing all data...' ) )
await brainyInstance . clear ( { force : true } )
console . log ( colors . success ( '✅ All data cleared successfully' ) )
} ) )
// Command 8: EXPORT - Export your data
program
. command ( 'export' )
. description ( 'Export your brain data in various formats' )
. option ( '-f, --format <format>' , 'Export format (json, csv, graph, embeddings)' , 'json' )
. option ( '-o, --output <file>' , 'Output file path' )
. option ( '--vectors' , 'Include vector embeddings' )
. option ( '--no-metadata' , 'Exclude metadata' )
. option ( '--no-relationships' , 'Exclude relationships' )
. option ( '--filter <json>' , 'Filter by metadata' )
. option ( '-l, --limit <number>' , 'Limit number of items' )
. action ( wrapAction ( async ( options ) => {
const brainy = await initBrainy ( )
console . log ( colors . brain ( '📤 Exporting Brain Data' ) )
const spinner = ora ( 'Exporting data...' ) . start ( )
try {
const exportOptions = {
format : options . format ,
includeVectors : options . vectors || false ,
includeMetadata : options . metadata !== false ,
includeRelationships : options . relationships !== false ,
filter : options . filter ? JSON . parse ( options . filter ) : { } ,
limit : options . limit ? parseInt ( options . limit ) : undefined
}
const data = await brainy . export ( exportOptions )
spinner . succeed ( 'Export complete' )
if ( options . output ) {
// Write to file
const fs = require ( 'fs' )
const content = typeof data === 'string' ? data : JSON . stringify ( data , null , 2 )
fs . writeFileSync ( options . output , content )
console . log ( colors . success ( ` ✅ Exported to: ${ options . output } ` ) )
// Show summary
const items = Array . isArray ( data ) ? data . length : ( data . nodes ? data . nodes . length : 1 )
console . log ( colors . info ( ` 📊 Format: ${ options . format } ` ) )
console . log ( colors . info ( ` 📁 Items: ${ items } ` ) )
if ( options . vectors ) {
console . log ( colors . info ( ` 🔢 Vectors: Included ` ) )
}
} else {
// Output to console
if ( typeof data === 'string' ) {
console . log ( data )
} else {
console . log ( JSON . stringify ( data , null , 2 ) )
}
}
} catch ( error ) {
spinner . fail ( 'Export failed' )
console . error ( colors . error ( error . message ) )
process . exit ( 1 )
}
} ) )
// Command 8: CLOUD - Premium features connection
program
. command ( 'cloud <action>' )
. description ( '☁️ Brain Cloud - AI Memory, Team Sync, Enterprise Connectors (FREE TRIAL!)' )
. option ( '-i, --instance <id>' , 'Brain Cloud instance ID' )
. option ( '-e, --email <email>' , 'Your email for signup' )
. action ( wrapAction ( async ( action , options ) => {
console . log ( boxen (
colors . brain ( '☁️ BRAIN CLOUD - SUPERCHARGE YOUR BRAIN! 🚀\n\n' ) +
colors . success ( '✨ FREE TRIAL: First 100GB FREE!\n' ) +
colors . info ( '💰 Then just $9/month (individuals) or $49/month (teams)\n\n' ) +
colors . primary ( 'Features:\n' ) +
colors . dim ( ' • AI Memory that persists across sessions\n' ) +
colors . dim ( ' • Multi-agent coordination\n' ) +
colors . dim ( ' • Automatic backups & sync\n' ) +
colors . dim ( ' • Premium connectors (Notion, Slack, etc.)' ) ,
{ padding : 1 , borderStyle : 'round' , borderColor : 'cyan' }
) )
const cloudActions = {
setup : async ( ) => {
console . log ( colors . brain ( '\n🚀 Quick Setup - 30 seconds to superpowers!\n' ) )
if ( ! options . email ) {
const { email } = await prompts ( {
type : 'text' ,
name : 'email' ,
message : 'Enter your email for FREE trial:' ,
validate : ( value ) => value . includes ( '@' ) || 'Please enter a valid email'
} )
options . email = email
}
console . log ( colors . success ( ` \n ✅ Setting up Brain Cloud for: ${ options . email } ` ) )
console . log ( colors . info ( '\n📧 Check your email for activation link!' ) )
console . log ( colors . dim ( '\nOr visit: https://app.soulcraft.com/activate\n' ) )
// Cloud features planned for future release
console . log ( colors . brain ( '🎉 Your Brain Cloud trial is ready!' ) )
console . log ( colors . success ( '\nNext steps:' ) )
console . log ( colors . dim ( ' 1. Check your email for API key' ) )
console . log ( colors . dim ( ' 2. Run: brainy cloud connect --key YOUR_KEY' ) )
console . log ( colors . dim ( ' 3. Start using persistent AI memory!' ) )
} ,
connect : async ( ) => {
console . log ( colors . info ( '🔗 Connecting to Brain Cloud...' ) )
// Dynamic import to avoid loading premium code unnecessarily
console . log ( colors . info ( '🔗 Cloud features coming soon...' ) )
console . log ( colors . info ( 'Brainy works offline by default' ) )
} ,
status : async ( ) => {
console . log ( colors . info ( '☁️ Cloud Status: Available in future release' ) )
console . log ( colors . info ( 'Current version works offline' ) )
} ,
augmentations : async ( ) => {
console . log ( colors . info ( '🧩 Cloud augmentations coming in future release' ) )
console . log ( colors . info ( 'Local augmentations available now' ) )
}
}
if ( cloudActions [ action ] ) {
await cloudActions [ action ] ( )
} else {
console . log ( colors . error ( 'Valid actions: connect, status, augmentations' ) )
console . log ( colors . info ( 'Example: brainy cloud connect --instance demo-test-auto' ) )
}
} ) )
// Command 7: MIGRATE - Migration tools
program
. command ( 'migrate <action>' )
. description ( 'Migration tools for upgrades' )
. option ( '-f, --from <version>' , 'Migrate from version' )
. option ( '-b, --backup' , 'Create backup before migration' )
. action ( wrapAction ( async ( action , options ) => {
console . log ( colors . primary ( '🔄 Brainy Migration Tools' ) )
const migrateActions = {
check : async ( ) => {
console . log ( colors . info ( '🔍 Checking for migration needs...' ) )
// Check for deprecated methods, old config, etc.
const issues = [ ]
try {
const { BrainyData } = await import ( '../dist/brainyData.js' )
const brainy = new BrainyData ( )
// Check for old API usage
console . log ( colors . success ( '✅ No migration issues found' ) )
} catch ( error ) {
console . log ( colors . warning ( ` ⚠️ Found issues: ${ error . message } ` ) )
}
} ,
backup : async ( ) => {
console . log ( colors . info ( '💾 Creating backup...' ) )
const { BrainyData } = await import ( '../dist/brainyData.js' )
const brainy = new BrainyData ( )
const backup = await brainy . createBackup ( )
console . log ( colors . success ( ` ✅ Backup created: ${ backup . path } ` ) )
} ,
restore : async ( ) => {
if ( ! options . from ) {
console . error ( colors . error ( 'Please specify backup file: --from <path>' ) )
process . exit ( 1 )
}
console . log ( colors . info ( ` 📥 Restoring from: ${ options . from } ` ) )
const { BrainyData } = await import ( '../dist/brainyData.js' )
const brainy = new BrainyData ( )
await brainy . restoreBackup ( options . from )
console . log ( colors . success ( '✅ Restore complete' ) )
}
}
if ( migrateActions [ action ] ) {
await migrateActions [ action ] ( )
} else {
console . log ( colors . error ( 'Valid actions: check, backup, restore' ) )
console . log ( colors . info ( 'Example: brainy migrate check' ) )
}
} ) )
// Command 8: HELP - Interactive guidance
program
. command ( 'help [command]' )
. description ( 'Get help or enter interactive mode' )
. action ( wrapAction ( async ( command ) => {
if ( command ) {
program . help ( )
return
}
// Interactive mode for beginners
console . log ( colors . primary ( '🧠⚛️ Welcome to Brainy!' ) )
console . log ( colors . info ( 'Your AI-powered second brain' ) )
console . log ( )
const rl = createInterface ( {
input : process . stdin ,
output : process . stdout
} )
console . log ( colors . primary ( 'What would you like to do?' ) )
console . log ( colors . info ( '1. Add some data' ) )
console . log ( colors . info ( '2. Chat with AI using your data' ) )
console . log ( colors . info ( '3. Search your brain' ) )
console . log ( colors . info ( '4. Update existing data' ) )
console . log ( colors . info ( '5. Delete data' ) )
console . log ( colors . info ( '6. Import a file' ) )
console . log ( colors . info ( '7. Check status' ) )
console . log ( colors . info ( '8. Connect to Brain Cloud' ) )
console . log ( colors . info ( '9. Configuration' ) )
console . log ( colors . info ( '10. Show all commands' ) )
console . log ( )
const choice = await new Promise ( resolve => {
rl . question ( colors . primary ( 'Enter your choice (1-10): ' ) , ( answer ) => {
rl . close ( )
resolve ( answer )
} )
} )
switch ( choice ) {
case '1' :
console . log ( colors . success ( '\n🧠 Use: brainy add "your data here"' ) )
console . log ( colors . info ( 'Example: brainy add "John works at Google"' ) )
break
case '2' :
console . log ( colors . success ( '\n💬 Use: brainy chat "your question"' ) )
console . log ( colors . info ( 'Example: brainy chat "Tell me about my data"' ) )
console . log ( colors . info ( 'Supports: local (Ollama), OpenAI, Claude' ) )
break
case '3' :
console . log ( colors . success ( '\n🔍 Use: brainy search "your query"' ) )
console . log ( colors . info ( 'Example: brainy search "Google employees"' ) )
break
case '4' :
console . log ( colors . success ( '\n📥 Use: brainy import <file-or-url>' ) )
console . log ( colors . info ( 'Example: brainy import data.txt' ) )
break
case '5' :
console . log ( colors . success ( '\n📊 Use: brainy status' ) )
console . log ( colors . info ( 'Shows comprehensive brain statistics' ) )
console . log ( colors . info ( 'Options: --simple (quick) or --verbose (detailed)' ) )
break
case '6' :
console . log ( colors . success ( '\n☁️ Use: brainy cloud connect' ) )
console . log ( colors . info ( 'Example: brainy cloud connect --instance demo-test-auto' ) )
break
case '7' :
console . log ( colors . success ( '\n🔧 Use: brainy config <action>' ) )
console . log ( colors . info ( 'Example: brainy config list' ) )
break
case '8' :
program . help ( )
break
default :
console . log ( colors . warning ( 'Invalid choice. Use "brainy --help" for all commands.' ) )
}
} ) )
// ========================================
// FALLBACK - Show interactive help if no command
// ========================================
// Handle --interactive flag
if ( process . argv . includes ( '-i' ) || process . argv . includes ( '--interactive' ) ) {
// Start full interactive mode
console . log ( colors . primary ( '🧠 Starting Interactive Mode...' ) )
import ( './brainy-interactive.js' ) . then ( module => {
module . startInteractiveMode ( )
} ) . catch ( error => {
console . error ( colors . error ( 'Failed to start interactive mode:' ) , error . message )
// Fallback to simple interactive prompt
program . parse ( [ 'node' , 'brainy' , 'help' ] )
} )
} else if ( process . argv . length === 2 ) {
// No arguments - show interactive help
program . parse ( [ 'node' , 'brainy' , 'help' ] )
} else {
// Parse normally
program . parse ( process . argv )
}