@@ -7851,26 +7851,40 @@ mcpCmd.command('test')
78517851 } ) ;
78527852
78537853// ============================================================================
7854- // Brain Commands — Shared intelligence via @ruvector/pi-brain (lazy-loaded )
7854+ // Brain Commands — Shared intelligence via pi.ruv.io REST API (direct fetch )
78557855// ============================================================================
78567856
7857- async function requirePiBrain ( ) {
7858- try {
7859- return require ( '@ruvector/pi-brain' ) ;
7860- } catch {
7861- console . error ( chalk . red ( 'Brain commands require @ruvector/pi-brain' ) ) ;
7862- console . error ( chalk . yellow ( ' npm install @ruvector/pi-brain' ) ) ;
7863- process . exit ( 1 ) ;
7864- }
7865- }
7866-
78677857function getBrainConfig ( opts ) {
78687858 return {
78697859 url : opts . url || process . env . BRAIN_URL || 'https://pi.ruv.io' ,
78707860 key : opts . key || process . env . PI
78717861 } ;
78727862}
78737863
7864+ function brainHeaders ( config ) {
7865+ const h = { 'Content-Type' : 'application/json' } ;
7866+ if ( config . key ) h [ 'Authorization' ] = `Bearer ${ config . key } ` ;
7867+ return h ;
7868+ }
7869+
7870+ async function brainFetch ( config , endpoint , opts = { } ) {
7871+ const url = new URL ( endpoint , config . url ) ;
7872+ if ( opts . params ) {
7873+ for ( const [ k , v ] of Object . entries ( opts . params ) ) {
7874+ if ( v !== undefined && v !== null ) url . searchParams . set ( k , String ( v ) ) ;
7875+ }
7876+ }
7877+ const fetchOpts = { headers : brainHeaders ( config ) , signal : AbortSignal . timeout ( 30000 ) } ;
7878+ if ( opts . method ) fetchOpts . method = opts . method ;
7879+ if ( opts . body ) { fetchOpts . method = opts . method || 'POST' ; fetchOpts . body = JSON . stringify ( opts . body ) ; }
7880+ const resp = await fetch ( url . toString ( ) , fetchOpts ) ;
7881+ if ( ! resp . ok ) {
7882+ const errText = await resp . text ( ) . catch ( ( ) => resp . statusText ) ;
7883+ throw new Error ( `${ resp . status } ${ errText } ` ) ;
7884+ }
7885+ return resp . json ( ) ;
7886+ }
7887+
78747888const brainCmd = program . command ( 'brain' ) . description ( 'Shared intelligence — search, share, and manage collective knowledge' ) ;
78757889
78767890brainCmd . command ( 'search <query>' )
@@ -7882,11 +7896,9 @@ brainCmd.command('search <query>')
78827896 . option ( '--json' , 'Output as JSON' )
78837897 . option ( '--verbose' , 'Show detailed scoring and metadata per result' )
78847898 . action ( async ( query , opts ) => {
7885- const piBrain = await requirePiBrain ( ) ;
78867899 const config = getBrainConfig ( opts ) ;
78877900 try {
7888- const client = new piBrain . PiBrainClient ( config ) ;
7889- const results = await client . search ( query , { category : opts . category , limit : parseInt ( opts . limit ) } ) ;
7901+ const results = await brainFetch ( config , '/v1/memories/search' , { params : { q : query , category : opts . category , limit : opts . limit } } ) ;
78907902 if ( opts . json || ! process . stdout . isTTY ) { console . log ( JSON . stringify ( results , null , 2 ) ) ; return ; }
78917903 console . log ( chalk . bold . cyan ( `\nBrain Search: "${ query } "\n` ) ) ;
78927904 if ( ! results . length ) { console . log ( chalk . dim ( ' No results found.\n' ) ) ; return ; }
@@ -7916,11 +7928,9 @@ brainCmd.command('share <title>')
79167928 . option ( '--url <url>' , 'Brain server URL' )
79177929 . option ( '--key <key>' , 'Pi key' )
79187930 . action ( async ( title , opts ) => {
7919- const piBrain = await requirePiBrain ( ) ;
79207931 const config = getBrainConfig ( opts ) ;
79217932 try {
7922- const client = new piBrain . PiBrainClient ( config ) ;
7923- const result = await client . share ( { title, content : opts . content || title , category : opts . category , tags : opts . tags ? opts . tags . split ( ',' ) . map ( t => t . trim ( ) ) : [ ] , code_snippet : opts . code } ) ;
7933+ const result = await brainFetch ( config , '/v1/memories' , { body : { title, content : opts . content || title , category : opts . category , tags : opts . tags ? opts . tags . split ( ',' ) . map ( t => t . trim ( ) ) : [ ] , code_snippet : opts . code } } ) ;
79247934 console . log ( chalk . green ( `Shared: ${ result . id || 'OK' } ` ) ) ;
79257935 } catch ( e ) { console . error ( chalk . red ( `Error: ${ e . message } ` ) ) ; process . exit ( 1 ) ; }
79267936 } ) ;
@@ -7931,11 +7941,9 @@ brainCmd.command('get <id>')
79317941 . option ( '--key <key>' , 'Pi key' )
79327942 . option ( '--json' , 'Output as JSON' )
79337943 . action ( async ( id , opts ) => {
7934- const piBrain = await requirePiBrain ( ) ;
79357944 const config = getBrainConfig ( opts ) ;
79367945 try {
7937- const client = new piBrain . PiBrainClient ( config ) ;
7938- const result = await client . get ( id ) ;
7946+ const result = await brainFetch ( config , `/v1/memories/${ id } ` ) ;
79397947 if ( opts . json || ! process . stdout . isTTY ) { console . log ( JSON . stringify ( result , null , 2 ) ) ; return ; }
79407948 console . log ( chalk . bold . cyan ( `\nMemory: ${ id } \n` ) ) ;
79417949 if ( result . title ) console . log ( ` ${ chalk . bold ( 'Title:' ) } ${ result . title } ` ) ;
@@ -7950,11 +7958,9 @@ brainCmd.command('vote <id> <direction>')
79507958 . option ( '--url <url>' , 'Brain server URL' )
79517959 . option ( '--key <key>' , 'Pi key' )
79527960 . action ( async ( id , direction , opts ) => {
7953- const piBrain = await requirePiBrain ( ) ;
79547961 const config = getBrainConfig ( opts ) ;
79557962 try {
7956- const client = new piBrain . PiBrainClient ( config ) ;
7957- await client . vote ( id , direction ) ;
7963+ await brainFetch ( config , `/v1/memories/${ id } /vote` , { body : { direction } } ) ;
79587964 console . log ( chalk . green ( `Voted ${ direction } on ${ id } ` ) ) ;
79597965 } catch ( e ) { console . error ( chalk . red ( `Error: ${ e . message } ` ) ) ; process . exit ( 1 ) ; }
79607966 } ) ;
@@ -7967,11 +7973,9 @@ brainCmd.command('list')
79677973 . option ( '--key <key>' , 'Pi key' )
79687974 . option ( '--json' , 'Output as JSON' )
79697975 . action ( async ( opts ) => {
7970- const piBrain = await requirePiBrain ( ) ;
79717976 const config = getBrainConfig ( opts ) ;
79727977 try {
7973- const client = new piBrain . PiBrainClient ( config ) ;
7974- const results = await client . list ( { category : opts . category , limit : parseInt ( opts . limit ) } ) ;
7978+ const results = await brainFetch ( config , '/v1/memories/list' , { params : { category : opts . category , limit : opts . limit } } ) ;
79757979 if ( opts . json || ! process . stdout . isTTY ) { console . log ( JSON . stringify ( results , null , 2 ) ) ; return ; }
79767980 console . log ( chalk . bold . cyan ( '\nShared Brain Memories\n' ) ) ;
79777981 if ( ! results . length ) { console . log ( chalk . dim ( ' No memories found.\n' ) ) ; return ; }
@@ -7987,11 +7991,9 @@ brainCmd.command('delete <id>')
79877991 . option ( '--url <url>' , 'Brain server URL' )
79887992 . option ( '--key <key>' , 'Pi key' )
79897993 . action ( async ( id , opts ) => {
7990- const piBrain = await requirePiBrain ( ) ;
79917994 const config = getBrainConfig ( opts ) ;
79927995 try {
7993- const client = new piBrain . PiBrainClient ( config ) ;
7994- await client . delete ( id ) ;
7996+ await brainFetch ( config , `/v1/memories/${ id } ` , { method : 'DELETE' } ) ;
79957997 console . log ( chalk . green ( `Deleted: ${ id } ` ) ) ;
79967998 } catch ( e ) { console . error ( chalk . red ( `Error: ${ e . message } ` ) ) ; process . exit ( 1 ) ; }
79977999 } ) ;
@@ -8002,11 +8004,9 @@ brainCmd.command('status')
80028004 . option ( '--key <key>' , 'Pi key' )
80038005 . option ( '--json' , 'Output as JSON' )
80048006 . action ( async ( opts ) => {
8005- const piBrain = await requirePiBrain ( ) ;
80068007 const config = getBrainConfig ( opts ) ;
80078008 try {
8008- const client = new piBrain . PiBrainClient ( config ) ;
8009- const status = await client . status ( ) ;
8009+ const status = await brainFetch ( config , '/v1/status' ) ;
80108010 if ( opts . json || ! process . stdout . isTTY ) { console . log ( JSON . stringify ( status , null , 2 ) ) ; return ; }
80118011 console . log ( chalk . bold . cyan ( '\nBrain Status\n' ) ) ;
80128012 Object . entries ( status ) . forEach ( ( [ k , v ] ) => {
@@ -8037,11 +8037,9 @@ brainCmd.command('drift')
80378037 . option ( '--key <key>' , 'Pi key' )
80388038 . option ( '--json' , 'Output as JSON' )
80398039 . action ( async ( opts ) => {
8040- const piBrain = await requirePiBrain ( ) ;
80418040 const config = getBrainConfig ( opts ) ;
80428041 try {
8043- const client = new piBrain . PiBrainClient ( config ) ;
8044- const report = await client . drift ( { domain : opts . domain } ) ;
8042+ const report = await brainFetch ( config , '/v1/drift' , { params : { domain : opts . domain } } ) ;
80458043 if ( opts . json || ! process . stdout . isTTY ) { console . log ( JSON . stringify ( report , null , 2 ) ) ; return ; }
80468044 console . log ( chalk . bold . cyan ( '\nDrift Report\n' ) ) ;
80478045 console . log ( ` ${ chalk . bold ( 'Drifting:' ) } ${ report . is_drifting ? chalk . red ( 'Yes' ) : chalk . green ( 'No' ) } ` ) ;
@@ -8058,11 +8056,9 @@ brainCmd.command('partition')
80588056 . option ( '--key <key>' , 'Pi key' )
80598057 . option ( '--json' , 'Output as JSON' )
80608058 . action ( async ( opts ) => {
8061- const piBrain = await requirePiBrain ( ) ;
80628059 const config = getBrainConfig ( opts ) ;
80638060 try {
8064- const client = new piBrain . PiBrainClient ( config ) ;
8065- const result = await client . partition ( { domain : opts . domain , min_cluster_size : parseInt ( opts . minSize ) } ) ;
8061+ const result = await brainFetch ( config , '/v1/partition' , { params : { domain : opts . domain , min_cluster_size : opts . minSize } } ) ;
80668062 if ( opts . json || ! process . stdout . isTTY ) { console . log ( JSON . stringify ( result , null , 2 ) ) ; return ; }
80678063 console . log ( chalk . bold . cyan ( '\nKnowledge Partitions\n' ) ) ;
80688064 if ( result . clusters ) {
@@ -8080,11 +8076,9 @@ brainCmd.command('transfer <source> <target>')
80808076 . option ( '--key <key>' , 'Pi key' )
80818077 . option ( '--json' , 'Output as JSON' )
80828078 . action ( async ( source , target , opts ) => {
8083- const piBrain = await requirePiBrain ( ) ;
80848079 const config = getBrainConfig ( opts ) ;
80858080 try {
8086- const client = new piBrain . PiBrainClient ( config ) ;
8087- const result = await client . transfer ( source , target ) ;
8081+ const result = await brainFetch ( config , '/v1/transfer' , { body : { source_domain : source , target_domain : target } } ) ;
80888082 if ( opts . json || ! process . stdout . isTTY ) { console . log ( JSON . stringify ( result , null , 2 ) ) ; return ; }
80898083 console . log ( chalk . green ( `Transfer ${ source } -> ${ target } : ${ result . status || 'OK' } ` ) ) ;
80908084 } catch ( e ) { console . error ( chalk . red ( `Error: ${ e . message } ` ) ) ; process . exit ( 1 ) ; }
@@ -8095,11 +8089,9 @@ brainCmd.command('sync [direction]')
80958089 . option ( '--url <url>' , 'Brain server URL' )
80968090 . option ( '--key <key>' , 'Pi key' )
80978091 . action ( async ( direction , opts ) => {
8098- const piBrain = await requirePiBrain ( ) ;
80998092 const config = getBrainConfig ( opts ) ;
81008093 try {
8101- const client = new piBrain . PiBrainClient ( config ) ;
8102- const result = await client . sync ( direction || 'both' ) ;
8094+ const result = await brainFetch ( config , '/v1/lora/latest' , { params : { direction : direction || 'both' } } ) ;
81038095 console . log ( chalk . green ( `Sync ${ direction || 'both' } : ${ result . status || 'OK' } ` ) ) ;
81048096 } catch ( e ) { console . error ( chalk . red ( `Error: ${ e . message } ` ) ) ; process . exit ( 1 ) ; }
81058097 } ) ;
@@ -8110,30 +8102,28 @@ brainCmd.command('page <action> [args...]')
81108102 . option ( '--key <key>' , 'Pi key' )
81118103 . option ( '--json' , 'Output as JSON' )
81128104 . action ( async ( action , args , opts ) => {
8113- const piBrain = await requirePiBrain ( ) ;
81148105 const config = getBrainConfig ( opts ) ;
81158106 try {
8116- const client = new piBrain . PiBrainClient ( config ) ;
81178107 let result ;
81188108 switch ( action ) {
81198109 case 'list' :
8120- result = await client . listPages ? client . listPages ( { limit : 20 } ) : { pages : [ ] , message : 'Brainpedia not yet available on this server ' } ;
8110+ result = await brainFetch ( config , '/v1/pages' , { params : { limit : 20 } } ) . catch ( ( ) => ( { pages : [ ] , message : 'Brainpedia endpoint not available' } ) ) ;
81218111 break ;
81228112 case 'get' :
81238113 if ( ! args [ 0 ] ) { console . error ( chalk . red ( 'Usage: brain page get <slug>' ) ) ; process . exit ( 1 ) ; }
8124- result = await client . getPage ? client . getPage ( args [ 0 ] ) : { error : 'Brainpedia not yet available' } ;
8114+ result = await brainFetch ( config , `/v1/pages/ ${ args [ 0 ] } ` ) ;
81258115 break ;
81268116 case 'create' :
81278117 if ( ! args [ 0 ] ) { console . error ( chalk . red ( 'Usage: brain page create <title> [--content <text>]' ) ) ; process . exit ( 1 ) ; }
8128- result = await client . createPage ? client . createPage ( { title : args [ 0 ] , content : opts . content || '' } ) : { error : 'Brainpedia not yet available' } ;
8118+ result = await brainFetch ( config , '/v1/pages' , { body : { title : args [ 0 ] , content : opts . content || '' } } ) ;
81298119 break ;
81308120 case 'update' :
81318121 if ( ! args [ 0 ] ) { console . error ( chalk . red ( 'Usage: brain page update <slug> [--content <text>]' ) ) ; process . exit ( 1 ) ; }
8132- result = await client . updatePage ? client . updatePage ( args [ 0 ] , { content : opts . content || '' } ) : { error : 'Brainpedia not yet available' } ;
8122+ result = await brainFetch ( config , `/v1/pages/ ${ args [ 0 ] } /deltas` , { body : { content : opts . content || '' } } ) ;
81338123 break ;
81348124 case 'delete' :
81358125 if ( ! args [ 0 ] ) { console . error ( chalk . red ( 'Usage: brain page delete <slug>' ) ) ; process . exit ( 1 ) ; }
8136- result = await client . deletePage ? client . deletePage ( args [ 0 ] ) : { error : 'Brainpedia not yet available' } ;
8126+ result = await brainFetch ( config , `/v1/pages/ ${ args [ 0 ] } ` , { method : 'DELETE' } ) . catch ( ( ) => ( { error : 'Delete not available' } ) ) ;
81378127 break ;
81388128 default :
81398129 console . error ( chalk . red ( `Unknown page action: ${ action } . Use: list, get, create, update, delete` ) ) ;
@@ -8159,25 +8149,23 @@ brainCmd.command('node <action> [args...]')
81598149 . option ( '--key <key>' , 'Pi key' )
81608150 . option ( '--json' , 'Output as JSON' )
81618151 . action ( async ( action , args , opts ) => {
8162- const piBrain = await requirePiBrain ( ) ;
81638152 const config = getBrainConfig ( opts ) ;
81648153 try {
8165- const client = new piBrain . PiBrainClient ( config ) ;
81668154 let result ;
81678155 switch ( action ) {
81688156 case 'publish' :
81698157 if ( ! args [ 0 ] ) { console . error ( chalk . red ( 'Usage: brain node publish <wasm-file>' ) ) ; process . exit ( 1 ) ; }
81708158 const wasmPath = path . resolve ( args [ 0 ] ) ;
81718159 if ( ! fs . existsSync ( wasmPath ) ) { console . error ( chalk . red ( `File not found: ${ wasmPath } ` ) ) ; process . exit ( 1 ) ; }
81728160 const wasmBytes = fs . readFileSync ( wasmPath ) ;
8173- result = await client . publishNode ? client . publishNode ( { wasm : wasmBytes , name : path . basename ( wasmPath , '.wasm' ) } ) : { error : 'WASM node publish not yet available on this server' } ;
8161+ result = await brainFetch ( config , '/v1/nodes' , { body : { name : path . basename ( wasmPath , '.wasm' ) , wasm_base64 : wasmBytes . toString ( 'base64' ) } } ) ;
81748162 break ;
81758163 case 'list' :
8176- result = await client . listNodes ? client . listNodes ( { limit : 20 } ) : { nodes : [ ] , message : 'WASM node listing not yet available' } ;
8164+ result = await brainFetch ( config , '/v1/nodes' , { params : { limit : 20 } } ) . catch ( ( ) => ( { nodes : [ ] , message : 'WASM node listing not available' } ) ) ;
81778165 break ;
81788166 case 'status' :
81798167 if ( ! args [ 0 ] ) { console . error ( chalk . red ( 'Usage: brain node status <node-id>' ) ) ; process . exit ( 1 ) ; }
8180- result = await client . nodeStatus ? client . nodeStatus ( args [ 0 ] ) : { error : 'WASM node status not yet available' } ;
8168+ result = await brainFetch ( config , `/v1/nodes/ ${ args [ 0 ] } ` ) ;
81818169 break ;
81828170 default :
81838171 console . error ( chalk . red ( `Unknown node action: ${ action } . Use: publish, list, status` ) ) ;
0 commit comments