#!/usr/bin/env node /** * RuVector Intelligence CLI * * Commands: * remember - Store in vector memory * recall - Search memory semantically * learn - Record learning trajectory * suggest - Get best action suggestion * route [--file ] [--crate ] - Route to best agent * stats - Show intelligence stats * pre-edit - Pre-edit intelligence hook * post-edit - Post-edit learning hook */ import RuVectorIntelligence from './index.js'; import SwarmOptimizer from './swarm.js'; import { basename, extname } from 'path'; const intel = new RuVectorIntelligence(); const swarm = new SwarmOptimizer(); async function main() { const args = process.argv.slice(2); const command = args[0]; if (!command) { console.log(` ๐Ÿง  RuVector Intelligence CLI Commands: remember Store in semantic memory recall Search memory learn Record trajectory suggest Get best action route --file --crate Route to agent stats Show system stats Hooks: pre-edit Pre-edit intelligence post-edit Post-edit learning pre-command Pre-command intelligence post-command [stderr] Post-command learning v3 Features: record-error Record error for pattern learning suggest-fix Get suggested fixes for error suggest-next Suggest next files to edit should-test Check if tests should run Swarm (Hive-Mind): swarm-register Register agent in swarm swarm-coordinate Record agent coordination swarm-optimize Optimize task distribution swarm-recommend Get best agent for task swarm-heal Handle agent failure swarm-stats Show swarm statistics `); return; } try { switch (command) { case 'remember': { const [, type, ...contentParts] = args; const content = contentParts.join(' '); const id = await intel.remember(type, content); console.log(JSON.stringify({ success: true, id })); break; } case 'recall': { const query = args.slice(1).join(' '); const results = await intel.recall(query, 5); console.log(JSON.stringify({ query, results: results.map(r => ({ type: r.type, content: r.content?.slice(0, 200), score: r.score?.toFixed(3), timestamp: r.metadata?.timestamp })) }, null, 2)); break; } case 'learn': { const [, state, action, rewardStr] = args; const reward = parseFloat(rewardStr) || 0; const id = intel.learn(state, action, 'recorded', reward); console.log(JSON.stringify({ success: true, id, state, action, reward })); break; } case 'suggest': { const [, state, actionsStr] = args; const actions = actionsStr?.split(',') || ['coder', 'reviewer', 'tester']; const suggestion = intel.suggest(state, actions); console.log(JSON.stringify(suggestion, null, 2)); break; } case 'route': { const task = []; let file = null, crate = null, operation = 'edit'; for (let i = 1; i < args.length; i++) { if (args[i] === '--file' && args[i + 1]) { file = args[++i]; } else if (args[i] === '--crate' && args[i + 1]) { crate = args[++i]; } else if (args[i] === '--op' && args[i + 1]) { operation = args[++i]; } else { task.push(args[i]); } } const fileType = file ? extname(file).slice(1) : 'unknown'; const routing = await intel.route(task.join(' '), { file, fileType, crate, operation }); console.log(JSON.stringify(routing, null, 2)); break; } case 'stats': { const stats = intel.stats(); console.log(JSON.stringify(stats, null, 2)); break; } // === HOOK INTEGRATIONS === case 'pre-edit': { const file = args[1]; if (!file) { console.log('{}'); break; } const fileType = extname(file).slice(1); const fileName = basename(file); const crateMatch = file.match(/crates\/([^/]+)/); const crate = crateMatch ? crateMatch[1] : null; // Build context for routing - use underscore format to match pretrained Q-table const state = `edit_${fileType}_in_${crate || 'project'}`; // Get routing suggestion const routing = await intel.route( `edit ${fileName}`, { file, fileType, crate, operation: 'edit' } ); // Recall similar past edits const similar = await intel.recall(`edit ${fileType} ${crate || ''} ${fileName}`, 3); // Get learned suggestion const actions = ['check-first', 'edit-directly', 'test-first', 'review-first']; const suggestion = intel.suggest(state, actions); const output = { file, fileType, crate, routing: { agent: routing.recommended, confidence: routing.confidence, reason: routing.reasoning }, suggestion: { approach: suggestion.action, confidence: suggestion.confidence }, context: similar.length > 0 ? { similarEdits: similar.slice(0, 2).map(s => ({ what: s.content?.slice(0, 80), when: s.metadata?.timestamp })) } : null }; // Pretty output for hook console.log('๐Ÿง  Intelligence Analysis:'); console.log(` ๐Ÿ“ ${crate || 'project'}/${fileName}`); console.log(` ๐Ÿค– Recommended: ${routing.recommended} (${(routing.confidence * 100).toFixed(0)}% confidence)`); if (suggestion.confidence > 0) { console.log(` ๐Ÿ’ก Approach: ${suggestion.action}`); } if (similar.length > 0) { console.log(` ๐Ÿ“š ${similar.length} similar past edits found`); } break; } case 'post-edit': { const [, file, successStr] = args; const success = successStr === 'true' || successStr === '1'; const reward = success ? 1.0 : -0.5; const fileType = extname(file || '').slice(1); const crateMatch = (file || '').match(/crates\/([^/]+)/); const crate = crateMatch ? crateMatch[1] : null; const state = `edit_${fileType}_in_${crate || 'project'}`; const action = success ? 'successful-edit' : 'failed-edit'; // Record trajectory for learning intel.learn(state, action, success ? 'completed' : 'failed', reward); // v3: Record file edit for sequence learning intel.recordFileEdit(file); // Store in memory await intel.remember( 'edit', `${success ? 'successful' : 'failed'} edit of ${fileType} in ${crate || 'project'}`, { file, success, crate } ); // v3: Check if tests should be suggested const testSuggestion = intel.shouldSuggestTests(file); console.log(`๐Ÿ“Š Learning recorded: ${success ? 'โœ…' : 'โŒ'} ${basename(file || 'unknown')}`); // v3: Suggest next files const nextFiles = intel.suggestNextFiles(file, 2); if (nextFiles.length > 0) { console.log(` ๐Ÿ“ Often edit next: ${nextFiles.map(f => f.file.split('/').pop()).join(', ')}`); } // v3: Suggest running tests if (testSuggestion.suggest) { console.log(` ๐Ÿงช Consider: ${testSuggestion.command}`); } break; } case 'pre-command': { const cmd = args.slice(1).join(' '); // Classify command type let cmdType = 'other'; if (cmd.startsWith('cargo')) cmdType = 'cargo'; else if (cmd.startsWith('npm')) cmdType = 'npm'; else if (cmd.startsWith('git')) cmdType = 'git'; else if (cmd.startsWith('wasm-pack')) cmdType = 'wasm'; const state = `${cmdType}_in_general`; const actions = ['command-succeeded', 'command-failed']; const suggestion = intel.suggest(state, actions); // Recall similar commands const similar = await intel.recall(`command ${cmdType} ${cmd.slice(0, 50)}`, 2); console.log(`๐Ÿง  Command: ${cmdType}`); if (suggestion.confidence > 0.3) { console.log(` ๐Ÿ’ก Suggestion: ${suggestion.action}`); } if (similar.length > 0 && similar[0].score > 0.6) { const lastOutcome = similar[0].metadata?.success ? 'โœ…' : 'โŒ'; console.log(` ๐Ÿ“š Similar command ran before: ${lastOutcome}`); } break; } case 'post-command': { // Parse: post-command [stderr] // Find success flag (true/false/1/0) in args let successIdx = args.findIndex((a, i) => i > 0 && (a === 'true' || a === 'false' || a === '1' || a === '0')); if (successIdx === -1) successIdx = args.length - 1; const success = args[successIdx] === 'true' || args[successIdx] === '1'; const cmd = args.slice(1, successIdx).join(' '); const stderr = args.slice(successIdx + 1).join(' '); let cmdType = 'other'; if (cmd.startsWith('cargo')) cmdType = 'cargo'; else if (cmd.startsWith('npm')) cmdType = 'npm'; else if (cmd.startsWith('git')) cmdType = 'git'; else if (cmd.startsWith('wasm-pack')) cmdType = 'wasm'; const state = `${cmdType}_in_general`; const reward = success ? 1.0 : -0.5; intel.learn(state, success ? 'command-succeeded' : 'command-failed', cmd.slice(0, 100), reward); // v3: Record error patterns if command failed if (!success && stderr) { const crateMatch = cmd.match(/-p\s+(\S+)/) || cmd.match(/crates\/([^/\s]+)/); const crate = crateMatch ? crateMatch[1] : null; const errors = intel.recordError(cmd, stderr, null, crate); if (errors.length > 0) { console.log(`๐Ÿ“Š Command โŒ recorded (${errors.length} error patterns learned)`); for (const e of errors.slice(0, 2)) { const fix = intel.suggestFix(`${e.type}:${e.code}`); if (fix.recentFixes.length > 0) { console.log(` ๐Ÿ’ก ${e.code}: ${fix.recentFixes[0]}`); } } break; } } await intel.remember( 'command', `${cmdType}: ${cmd.slice(0, 100)}`, { success, cmdType } ); console.log(`๐Ÿ“Š Command ${success ? 'โœ…' : 'โŒ'} recorded`); break; } // === SWARM / HIVE-MIND COMMANDS === case 'swarm-register': { const [, id, type, ...caps] = args; const result = swarm.registerAgent(id, type, caps); console.log(JSON.stringify(result, null, 2)); break; } case 'swarm-coordinate': { const [, src, dst, weight] = args; const result = swarm.recordCoordination(src, dst, parseFloat(weight) || 1); console.log(JSON.stringify(result, null, 2)); break; } case 'swarm-optimize': { const tasks = args.slice(1); const result = swarm.optimizeTaskDistribution(tasks); console.log(JSON.stringify(result, null, 2)); break; } case 'swarm-recommend': { const [, taskType, ...caps] = args; const result = swarm.recommendForTask(taskType, caps); console.log(JSON.stringify(result, null, 2)); break; } case 'swarm-heal': { const [, agentId] = args; const result = swarm.handleFailure(agentId); console.log(JSON.stringify(result, null, 2)); break; } case 'swarm-stats': { const stats = swarm.getStats(); console.log(JSON.stringify(stats, null, 2)); break; } // === V3 FEATURES === case 'record-error': { const cmd = args[1] || ''; const stderr = args.slice(2).join(' '); const errors = intel.recordError(cmd, stderr); console.log(JSON.stringify({ recorded: errors.length, errors }, null, 2)); break; } case 'suggest-fix': { const errorCode = args[1]; const suggestion = intel.suggestFix(errorCode); console.log(JSON.stringify(suggestion, null, 2)); break; } case 'suggest-next': { const file = args[1]; const suggestions = intel.suggestNextFiles(file); console.log(JSON.stringify(suggestions, null, 2)); break; } case 'should-test': { const file = args[1]; const suggestion = intel.shouldSuggestTests(file); console.log(JSON.stringify(suggestion, null, 2)); break; } default: console.error(`Unknown command: ${command}`); process.exit(1); } } catch (error) { console.error('Error:', error.message); process.exit(1); } } main();