ruvector-fixed / bin /cli.js
Archie
Fix dimension/dimensions bug and positional insert/search args
40d7073
#!/usr/bin/env node
// Signal CLI context (disables parallel workers - hooks are short-lived)
process.env.RUVECTOR_CLI = '1';
const { Command } = require('commander');
const chalk = require('chalk');
const ora = require('ora');
const fs = require('fs');
const path = require('path');
// Lazy load ruvector (only when needed, not for install/help commands)
let VectorDB, getVersion, getImplementationType;
let ruvectorLoaded = false;
function loadRuvector() {
if (ruvectorLoaded) return true;
try {
const ruvector = require('../dist/index.js');
VectorDB = ruvector.VectorDB;
getVersion = ruvector.getVersion;
getImplementationType = ruvector.getImplementationType;
ruvectorLoaded = true;
return true;
} catch (e) {
return false;
}
}
function requireRuvector() {
if (!loadRuvector()) {
console.error(chalk.red('Error: Failed to load ruvector. Please run: npm run build'));
console.error(chalk.yellow('Or install the package: npm install ruvector'));
process.exit(1);
}
}
// Import GNN (optional - graceful fallback if not available)
let RuvectorLayer, TensorCompress, differentiableSearch, getCompressionLevel, hierarchicalForward;
let gnnAvailable = false;
try {
const gnn = require('@ruvector/gnn');
RuvectorLayer = gnn.RuvectorLayer;
TensorCompress = gnn.TensorCompress;
differentiableSearch = gnn.differentiableSearch;
getCompressionLevel = gnn.getCompressionLevel;
hierarchicalForward = gnn.hierarchicalForward;
gnnAvailable = true;
} catch (e) {
// GNN not available - commands will show helpful message
}
// Import Attention (optional - graceful fallback if not available)
let DotProductAttention, MultiHeadAttention, HyperbolicAttention, FlashAttention, LinearAttention, MoEAttention;
let GraphRoPeAttention, EdgeFeaturedAttention, DualSpaceAttention, LocalGlobalAttention;
let benchmarkAttention, computeAttentionAsync, batchAttentionCompute, parallelAttentionCompute;
let expMap, logMap, mobiusAddition, poincareDistance, projectToPoincareBall;
let attentionInfo, attentionVersion;
let attentionAvailable = false;
try {
const attention = require('@ruvector/attention');
// Core mechanisms
DotProductAttention = attention.DotProductAttention;
MultiHeadAttention = attention.MultiHeadAttention;
HyperbolicAttention = attention.HyperbolicAttention;
FlashAttention = attention.FlashAttention;
LinearAttention = attention.LinearAttention;
MoEAttention = attention.MoEAttention;
// Graph attention
GraphRoPeAttention = attention.GraphRoPeAttention;
EdgeFeaturedAttention = attention.EdgeFeaturedAttention;
DualSpaceAttention = attention.DualSpaceAttention;
LocalGlobalAttention = attention.LocalGlobalAttention;
// Utilities
benchmarkAttention = attention.benchmarkAttention;
computeAttentionAsync = attention.computeAttentionAsync;
batchAttentionCompute = attention.batchAttentionCompute;
parallelAttentionCompute = attention.parallelAttentionCompute;
// Hyperbolic math
expMap = attention.expMap;
logMap = attention.logMap;
mobiusAddition = attention.mobiusAddition;
poincareDistance = attention.poincareDistance;
projectToPoincareBall = attention.projectToPoincareBall;
// Meta
attentionInfo = attention.info;
attentionVersion = attention.version;
attentionAvailable = true;
} catch (e) {
// Attention not available - commands will show helpful message
}
const program = new Command();
// Get package version from package.json
const packageJson = require('../package.json');
// Version and description (lazy load implementation info)
program
.name('ruvector')
.description(`${chalk.cyan('ruvector')} - High-performance vector database CLI`)
.version(packageJson.version);
// Create database
program
.command('create <path>')
.description('Create a new vector database')
.option('-d, --dimension <number>', 'Vector dimension', '384')
.option('-m, --metric <type>', 'Distance metric (cosine|euclidean|dot)', 'cosine')
.action((dbPath, options) => {
requireRuvector();
const spinner = ora('Creating database...').start();
try {
const dimension = parseInt(options.dimension);
const db = new VectorDB({
dimension,
metric: options.metric,
path: dbPath,
autoPersist: true
});
db.save(dbPath);
spinner.succeed(chalk.green(`Database created: ${dbPath}`));
console.log(chalk.gray(` Dimension: ${dimension}`));
console.log(chalk.gray(` Metric: ${options.metric}`));
console.log(chalk.gray(` Implementation: ${getImplementationType()}`));
} catch (error) {
spinner.fail(chalk.red('Failed to create database'));
console.error(chalk.red(error.message));
process.exit(1);
}
});
// Insert vectors
program
.command('insert <database> <file>')
.description('Insert vectors from JSON file')
.option('-b, --batch-size <number>', 'Batch size for insertion', '1000')
.action((dbPath, file, options) => {
requireRuvector();
const spinner = ora('Loading database...').start();
try {
// Read database metadata to get dimension
let dimension = 384; // default
if (fs.existsSync(dbPath)) {
const dbData = fs.readFileSync(dbPath, 'utf8');
const parsed = JSON.parse(dbData);
dimension = parsed.dimension || 384;
}
const db = new VectorDB({ dimension });
if (fs.existsSync(dbPath)) {
db.load(dbPath);
}
spinner.text = 'Reading vectors...';
const data = JSON.parse(fs.readFileSync(file, 'utf8'));
const vectors = Array.isArray(data) ? data : [data];
spinner.text = `Inserting ${vectors.length} vectors...`;
const batchSize = parseInt(options.batchSize);
for (let i = 0; i < vectors.length; i += batchSize) {
const batch = vectors.slice(i, i + batchSize);
db.insertBatch(batch);
spinner.text = `Inserted ${Math.min(i + batchSize, vectors.length)}/${vectors.length} vectors...`;
}
db.save(dbPath);
spinner.succeed(chalk.green(`Inserted ${vectors.length} vectors`));
const stats = db.stats();
console.log(chalk.gray(` Total vectors: ${stats.count}`));
} catch (error) {
spinner.fail(chalk.red('Failed to insert vectors'));
console.error(chalk.red(error.message));
process.exit(1);
}
});
// Search vectors
program
.command('search <database>')
.description('Search for similar vectors')
.requiredOption('-v, --vector <json>', 'Query vector as JSON array')
.option('-k, --top-k <number>', 'Number of results', '10')
.option('-t, --threshold <number>', 'Similarity threshold', '0.0')
.option('-f, --filter <json>', 'Metadata filter as JSON')
.action((dbPath, options) => {
requireRuvector();
const spinner = ora('Loading database...').start();
try {
// Read database metadata
const dbData = fs.readFileSync(dbPath, 'utf8');
const parsed = JSON.parse(dbData);
const dimension = parsed.dimension || 384;
const db = new VectorDB({ dimension });
db.load(dbPath);
spinner.text = 'Searching...';
const vector = JSON.parse(options.vector);
const query = {
vector,
k: parseInt(options.topK),
threshold: parseFloat(options.threshold)
};
if (options.filter) {
query.filter = JSON.parse(options.filter);
}
const results = db.search(query);
spinner.succeed(chalk.green(`Found ${results.length} results`));
console.log(chalk.cyan('\nSearch Results:'));
results.forEach((result, i) => {
console.log(chalk.white(`\n${i + 1}. ID: ${result.id}`));
console.log(chalk.yellow(` Score: ${result.score.toFixed(4)}`));
if (result.metadata) {
console.log(chalk.gray(` Metadata: ${JSON.stringify(result.metadata)}`));
}
});
} catch (error) {
spinner.fail(chalk.red('Failed to search'));
console.error(chalk.red(error.message));
process.exit(1);
}
});
// Show stats
program
.command('stats <database>')
.description('Show database statistics')
.action((dbPath) => {
requireRuvector();
const spinner = ora('Loading database...').start();
try {
const dbData = fs.readFileSync(dbPath, 'utf8');
const parsed = JSON.parse(dbData);
const dimension = parsed.dimension || 384;
const db = new VectorDB({ dimension });
db.load(dbPath);
const stats = db.stats();
spinner.succeed(chalk.green('Database statistics'));
console.log(chalk.cyan('\nDatabase Stats:'));
console.log(chalk.white(` Vector Count: ${chalk.yellow(stats.count)}`));
console.log(chalk.white(` Dimension: ${chalk.yellow(stats.dimension)}`));
console.log(chalk.white(` Metric: ${chalk.yellow(stats.metric)}`));
console.log(chalk.white(` Implementation: ${chalk.yellow(getImplementationType())}`));
if (stats.memoryUsage) {
const mb = (stats.memoryUsage / (1024 * 1024)).toFixed(2);
console.log(chalk.white(` Memory Usage: ${chalk.yellow(mb + ' MB')}`));
}
const fileStats = fs.statSync(dbPath);
const fileMb = (fileStats.size / (1024 * 1024)).toFixed(2);
console.log(chalk.white(` File Size: ${chalk.yellow(fileMb + ' MB')}`));
} catch (error) {
spinner.fail(chalk.red('Failed to load database'));
console.error(chalk.red(error.message));
process.exit(1);
}
});
// Benchmark
program
.command('benchmark')
.description('Run performance benchmarks')
.option('-d, --dimension <number>', 'Vector dimension', '384')
.option('-n, --num-vectors <number>', 'Number of vectors', '10000')
.option('-q, --num-queries <number>', 'Number of queries', '1000')
.action((options) => {
requireRuvector();
console.log(chalk.cyan('\nruvector Performance Benchmark'));
console.log(chalk.gray(`Implementation: ${getImplementationType()}\n`));
const dimension = parseInt(options.dimension);
const numVectors = parseInt(options.numVectors);
const numQueries = parseInt(options.numQueries);
let spinner = ora('Creating database...').start();
try {
const db = new VectorDB({ dimension, metric: 'cosine' });
spinner.succeed();
// Insert benchmark
spinner = ora(`Inserting ${numVectors} vectors...`).start();
const insertStart = Date.now();
const vectors = [];
for (let i = 0; i < numVectors; i++) {
vectors.push({
id: `vec_${i}`,
vector: Array.from({ length: dimension }, () => Math.random()),
metadata: { index: i, batch: Math.floor(i / 1000) }
});
}
db.insertBatch(vectors);
const insertTime = Date.now() - insertStart;
const insertRate = (numVectors / (insertTime / 1000)).toFixed(0);
spinner.succeed(chalk.green(`Inserted ${numVectors} vectors in ${insertTime}ms`));
console.log(chalk.gray(` Rate: ${chalk.yellow(insertRate)} vectors/sec`));
// Search benchmark
spinner = ora(`Running ${numQueries} searches...`).start();
const searchStart = Date.now();
for (let i = 0; i < numQueries; i++) {
const query = {
vector: Array.from({ length: dimension }, () => Math.random()),
k: 10
};
db.search(query);
}
const searchTime = Date.now() - searchStart;
const searchRate = (numQueries / (searchTime / 1000)).toFixed(0);
const avgLatency = (searchTime / numQueries).toFixed(2);
spinner.succeed(chalk.green(`Completed ${numQueries} searches in ${searchTime}ms`));
console.log(chalk.gray(` Rate: ${chalk.yellow(searchRate)} queries/sec`));
console.log(chalk.gray(` Avg Latency: ${chalk.yellow(avgLatency)}ms`));
// Stats
const stats = db.stats();
console.log(chalk.cyan('\nFinal Stats:'));
console.log(chalk.white(` Vector Count: ${chalk.yellow(stats.count)}`));
console.log(chalk.white(` Dimension: ${chalk.yellow(stats.dimension)}`));
console.log(chalk.white(` Implementation: ${chalk.yellow(getImplementationType())}`));
} catch (error) {
spinner.fail(chalk.red('Benchmark failed'));
console.error(chalk.red(error.message));
process.exit(1);
}
});
// Info command
program
.command('info')
.description('Show ruvector information')
.action(() => {
console.log(chalk.cyan('\nruvector Information'));
console.log(chalk.white(` CLI Version: ${chalk.yellow(packageJson.version)}`));
// Try to load ruvector for implementation info
if (loadRuvector()) {
const version = typeof getVersion === 'function' ? getVersion() : 'unknown';
const impl = typeof getImplementationType === 'function' ? getImplementationType() : 'native';
console.log(chalk.white(` Core Version: ${chalk.yellow(version)}`));
console.log(chalk.white(` Implementation: ${chalk.yellow(impl)}`));
} else {
console.log(chalk.white(` Core: ${chalk.gray('Not loaded (install @ruvector/core)')}`));
}
console.log(chalk.white(` GNN Module: ${gnnAvailable ? chalk.green('Available') : chalk.gray('Not installed')}`));
console.log(chalk.white(` Node Version: ${chalk.yellow(process.version)}`));
console.log(chalk.white(` Platform: ${chalk.yellow(process.platform)}`));
console.log(chalk.white(` Architecture: ${chalk.yellow(process.arch)}`));
if (!gnnAvailable) {
console.log(chalk.gray('\n Install GNN with: npx ruvector install gnn'));
}
});
// =============================================================================
// Install Command
// =============================================================================
program
.command('install [packages...]')
.description('Install optional ruvector packages')
.option('-a, --all', 'Install all optional packages')
.option('-l, --list', 'List available packages')
.option('-i, --interactive', 'Interactive package selection')
.action(async (packages, options) => {
const { execSync } = require('child_process');
// Available optional packages - all ruvector npm packages
const availablePackages = {
// Core packages
core: {
name: '@ruvector/core',
description: 'Core vector database with native Rust bindings (HNSW, SIMD)',
installed: true, // Always installed with ruvector
category: 'core'
},
gnn: {
name: '@ruvector/gnn',
description: 'Graph Neural Network layers, tensor compression, differentiable search',
installed: gnnAvailable,
category: 'core'
},
'graph-node': {
name: '@ruvector/graph-node',
description: 'Native Node.js bindings for hypergraph database with Cypher queries',
installed: false,
category: 'core'
},
'agentic-synth': {
name: '@ruvector/agentic-synth',
description: 'Synthetic data generator for AI/ML training, RAG, and agentic workflows',
installed: false,
category: 'tools'
},
extensions: {
name: 'ruvector-extensions',
description: 'Advanced features: embeddings, UI, exports, temporal tracking, persistence',
installed: false,
category: 'tools'
},
// Platform-specific native bindings for @ruvector/core
'node-linux-x64': {
name: '@ruvector/node-linux-x64-gnu',
description: 'Linux x64 native bindings for @ruvector/core',
installed: false,
category: 'platform'
},
'node-linux-arm64': {
name: '@ruvector/node-linux-arm64-gnu',
description: 'Linux ARM64 native bindings for @ruvector/core',
installed: false,
category: 'platform'
},
'node-darwin-x64': {
name: '@ruvector/node-darwin-x64',
description: 'macOS Intel x64 native bindings for @ruvector/core',
installed: false,
category: 'platform'
},
'node-darwin-arm64': {
name: '@ruvector/node-darwin-arm64',
description: 'macOS Apple Silicon native bindings for @ruvector/core',
installed: false,
category: 'platform'
},
'node-win32-x64': {
name: '@ruvector/node-win32-x64-msvc',
description: 'Windows x64 native bindings for @ruvector/core',
installed: false,
category: 'platform'
},
// Platform-specific native bindings for @ruvector/gnn
'gnn-linux-x64': {
name: '@ruvector/gnn-linux-x64-gnu',
description: 'Linux x64 native bindings for @ruvector/gnn',
installed: false,
category: 'platform'
},
'gnn-linux-arm64': {
name: '@ruvector/gnn-linux-arm64-gnu',
description: 'Linux ARM64 native bindings for @ruvector/gnn',
installed: false,
category: 'platform'
},
'gnn-darwin-x64': {
name: '@ruvector/gnn-darwin-x64',
description: 'macOS Intel x64 native bindings for @ruvector/gnn',
installed: false,
category: 'platform'
},
'gnn-darwin-arm64': {
name: '@ruvector/gnn-darwin-arm64',
description: 'macOS Apple Silicon native bindings for @ruvector/gnn',
installed: false,
category: 'platform'
},
'gnn-win32-x64': {
name: '@ruvector/gnn-win32-x64-msvc',
description: 'Windows x64 native bindings for @ruvector/gnn',
installed: false,
category: 'platform'
},
// Legacy/standalone packages
'ruvector-core': {
name: 'ruvector-core',
description: 'Standalone vector database (legacy, use @ruvector/core instead)',
installed: false,
category: 'legacy'
}
};
// Check which packages are actually installed
for (const [key, pkg] of Object.entries(availablePackages)) {
if (key !== 'core' && key !== 'gnn') {
try {
require.resolve(pkg.name);
pkg.installed = true;
} catch (e) {
pkg.installed = false;
}
}
}
// List packages
if (options.list || (packages.length === 0 && !options.all && !options.interactive)) {
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.cyan(' Ruvector Packages'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
const categories = {
core: { title: '📦 Core Packages', packages: [] },
tools: { title: '🔧 Tools & Extensions', packages: [] },
platform: { title: '🖥️ Platform Bindings', packages: [] },
legacy: { title: '📜 Legacy Packages', packages: [] }
};
// Group by category
Object.entries(availablePackages).forEach(([key, pkg]) => {
if (categories[pkg.category]) {
categories[pkg.category].packages.push({ key, ...pkg });
}
});
// Display by category
for (const [catKey, cat] of Object.entries(categories)) {
if (cat.packages.length === 0) continue;
console.log(chalk.cyan(`${cat.title}`));
console.log(chalk.gray('─'.repeat(60)));
cat.packages.forEach(pkg => {
const status = pkg.installed ? chalk.green('✓') : chalk.gray('○');
const statusText = pkg.installed ? chalk.green('installed') : chalk.gray('available');
console.log(chalk.white(` ${status} ${chalk.yellow(pkg.key.padEnd(18))} ${statusText}`));
console.log(chalk.gray(` ${pkg.description}`));
console.log(chalk.gray(` npm: ${chalk.white(pkg.name)}\n`));
});
}
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════'));
console.log(chalk.cyan('Usage:'));
console.log(chalk.white(' npx ruvector install gnn # Install GNN package'));
console.log(chalk.white(' npx ruvector install graph-node # Install graph database'));
console.log(chalk.white(' npx ruvector install agentic-synth # Install data generator'));
console.log(chalk.white(' npx ruvector install --all # Install all core packages'));
console.log(chalk.white(' npx ruvector install -i # Interactive selection'));
console.log(chalk.gray('\n Note: Platform bindings are auto-detected by @ruvector/core'));
return;
}
// Interactive mode
if (options.interactive) {
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
console.log(chalk.cyan('\nSelect packages to install:\n'));
const notInstalled = Object.entries(availablePackages)
.filter(([_, pkg]) => !pkg.installed);
if (notInstalled.length === 0) {
console.log(chalk.green('All packages are already installed!'));
rl.close();
return;
}
notInstalled.forEach(([key, pkg], i) => {
console.log(chalk.white(` ${i + 1}. ${chalk.yellow(key)} - ${pkg.description}`));
});
console.log(chalk.white(` ${notInstalled.length + 1}. ${chalk.yellow('all')} - Install all packages`));
console.log(chalk.white(` 0. ${chalk.gray('cancel')} - Exit without installing`));
rl.question(chalk.cyan('\nEnter selection (comma-separated for multiple): '), (answer) => {
rl.close();
const selections = answer.split(',').map(s => s.trim());
let toInstall = [];
for (const sel of selections) {
if (sel === '0' || sel.toLowerCase() === 'cancel') {
console.log(chalk.yellow('Installation cancelled.'));
return;
}
if (sel === String(notInstalled.length + 1) || sel.toLowerCase() === 'all') {
toInstall = notInstalled.map(([_, pkg]) => pkg.name);
break;
}
const idx = parseInt(sel) - 1;
if (idx >= 0 && idx < notInstalled.length) {
toInstall.push(notInstalled[idx][1].name);
}
}
if (toInstall.length === 0) {
console.log(chalk.yellow('No valid packages selected.'));
return;
}
installPackages(toInstall);
});
return;
}
// Install all (core + tools only, not platform-specific or legacy)
if (options.all) {
const toInstall = Object.values(availablePackages)
.filter(pkg => !pkg.installed && (pkg.category === 'core' || pkg.category === 'tools'))
.map(pkg => pkg.name);
if (toInstall.length === 0) {
console.log(chalk.green('All core packages are already installed!'));
return;
}
console.log(chalk.cyan(`Installing ${toInstall.length} packages...`));
installPackages(toInstall);
return;
}
// Install specific packages
const toInstall = [];
for (const pkg of packages) {
const key = pkg.toLowerCase().replace('@ruvector/', '');
if (availablePackages[key]) {
if (availablePackages[key].installed) {
console.log(chalk.yellow(`${availablePackages[key].name} is already installed`));
} else {
toInstall.push(availablePackages[key].name);
}
} else {
console.log(chalk.red(`Unknown package: ${pkg}`));
console.log(chalk.gray(`Available: ${Object.keys(availablePackages).join(', ')}`));
}
}
if (toInstall.length > 0) {
installPackages(toInstall);
}
function installPackages(pkgs) {
const spinner = ora(`Installing ${pkgs.join(', ')}...`).start();
try {
// Detect package manager
let pm = 'npm';
if (fs.existsSync('yarn.lock')) pm = 'yarn';
else if (fs.existsSync('pnpm-lock.yaml')) pm = 'pnpm';
else if (fs.existsSync('bun.lockb')) pm = 'bun';
const cmd = pm === 'yarn' ? `yarn add ${pkgs.join(' ')}`
: pm === 'pnpm' ? `pnpm add ${pkgs.join(' ')}`
: pm === 'bun' ? `bun add ${pkgs.join(' ')}`
: `npm install ${pkgs.join(' ')}`;
execSync(cmd, { stdio: 'pipe' });
spinner.succeed(chalk.green(`Installed: ${pkgs.join(', ')}`));
console.log(chalk.cyan('\nRun "npx ruvector info" to verify installation.'));
} catch (error) {
spinner.fail(chalk.red('Installation failed'));
console.error(chalk.red(error.message));
console.log(chalk.yellow(`\nTry manually: npm install ${pkgs.join(' ')}`));
process.exit(1);
}
}
});
// =============================================================================
// GNN Commands
// =============================================================================
// Helper to check GNN availability
function requireGnn() {
if (!gnnAvailable) {
console.error(chalk.red('Error: GNN module not available.'));
console.error(chalk.yellow('Install it with: npm install @ruvector/gnn'));
process.exit(1);
}
}
// GNN parent command
const gnnCmd = program
.command('gnn')
.description('Graph Neural Network operations');
// GNN Layer command
gnnCmd
.command('layer')
.description('Create and test a GNN layer')
.requiredOption('-i, --input-dim <number>', 'Input dimension')
.requiredOption('-h, --hidden-dim <number>', 'Hidden dimension')
.option('-a, --heads <number>', 'Number of attention heads', '4')
.option('-d, --dropout <number>', 'Dropout rate', '0.1')
.option('--test', 'Run a test forward pass')
.option('-o, --output <file>', 'Save layer config to JSON file')
.action((options) => {
requireGnn();
const spinner = ora('Creating GNN layer...').start();
try {
const inputDim = parseInt(options.inputDim);
const hiddenDim = parseInt(options.hiddenDim);
const heads = parseInt(options.heads);
const dropout = parseFloat(options.dropout);
const layer = new RuvectorLayer(inputDim, hiddenDim, heads, dropout);
spinner.succeed(chalk.green('GNN Layer created'));
console.log(chalk.cyan('\nLayer Configuration:'));
console.log(chalk.white(` Input Dim: ${chalk.yellow(inputDim)}`));
console.log(chalk.white(` Hidden Dim: ${chalk.yellow(hiddenDim)}`));
console.log(chalk.white(` Heads: ${chalk.yellow(heads)}`));
console.log(chalk.white(` Dropout: ${chalk.yellow(dropout)}`));
if (options.test) {
spinner.start('Running test forward pass...');
// Create test data
const nodeEmbedding = Array.from({ length: inputDim }, () => Math.random());
const neighborEmbeddings = [
Array.from({ length: inputDim }, () => Math.random()),
Array.from({ length: inputDim }, () => Math.random())
];
const edgeWeights = [0.6, 0.4];
const output = layer.forward(nodeEmbedding, neighborEmbeddings, edgeWeights);
spinner.succeed(chalk.green('Forward pass completed'));
console.log(chalk.cyan('\nTest Results:'));
console.log(chalk.white(` Input shape: ${chalk.yellow(`[${inputDim}]`)}`));
console.log(chalk.white(` Output shape: ${chalk.yellow(`[${output.length}]`)}`));
console.log(chalk.white(` Output sample: ${chalk.gray(`[${output.slice(0, 4).map(v => v.toFixed(4)).join(', ')}...]`)}`));
}
if (options.output) {
const config = layer.toJson();
fs.writeFileSync(options.output, config);
console.log(chalk.green(`\nLayer config saved to: ${options.output}`));
}
} catch (error) {
spinner.fail(chalk.red('Failed to create GNN layer'));
console.error(chalk.red(error.message));
process.exit(1);
}
});
// GNN Compress command
gnnCmd
.command('compress')
.description('Compress embeddings using adaptive tensor compression')
.requiredOption('-f, --file <path>', 'Input JSON file with embeddings')
.option('-l, --level <type>', 'Compression level (none|half|pq8|pq4|binary)', 'auto')
.option('-a, --access-freq <number>', 'Access frequency for auto compression (0.0-1.0)', '0.5')
.option('-o, --output <file>', 'Output file for compressed data')
.action((options) => {
requireGnn();
const spinner = ora('Loading embeddings...').start();
try {
const data = JSON.parse(fs.readFileSync(options.file, 'utf8'));
const embeddings = Array.isArray(data) ? data : [data];
spinner.text = 'Compressing embeddings...';
const compressor = new TensorCompress();
const accessFreq = parseFloat(options.accessFreq);
const results = [];
let totalOriginalSize = 0;
let totalCompressedSize = 0;
for (const embedding of embeddings) {
const vec = embedding.vector || embedding;
totalOriginalSize += vec.length * 4; // float32 = 4 bytes
let compressed;
if (options.level === 'auto') {
compressed = compressor.compress(vec, accessFreq);
} else {
const levelConfig = { levelType: options.level };
if (options.level === 'pq8') {
levelConfig.subvectors = 8;
levelConfig.centroids = 256;
} else if (options.level === 'pq4') {
levelConfig.subvectors = 8;
}
compressed = compressor.compressWithLevel(vec, levelConfig);
}
totalCompressedSize += compressed.length;
results.push({
id: embedding.id,
compressed
});
}
const ratio = (totalOriginalSize / totalCompressedSize).toFixed(2);
const savings = ((1 - totalCompressedSize / totalOriginalSize) * 100).toFixed(1);
spinner.succeed(chalk.green(`Compressed ${embeddings.length} embeddings`));
console.log(chalk.cyan('\nCompression Results:'));
console.log(chalk.white(` Embeddings: ${chalk.yellow(embeddings.length)}`));
console.log(chalk.white(` Level: ${chalk.yellow(options.level === 'auto' ? `auto (${getCompressionLevel(accessFreq)})` : options.level)}`));
console.log(chalk.white(` Original: ${chalk.yellow((totalOriginalSize / 1024).toFixed(2) + ' KB')}`));
console.log(chalk.white(` Compressed: ${chalk.yellow((totalCompressedSize / 1024).toFixed(2) + ' KB')}`));
console.log(chalk.white(` Ratio: ${chalk.yellow(ratio + 'x')}`));
console.log(chalk.white(` Savings: ${chalk.yellow(savings + '%')}`));
if (options.output) {
fs.writeFileSync(options.output, JSON.stringify(results, null, 2));
console.log(chalk.green(`\nCompressed data saved to: ${options.output}`));
}
} catch (error) {
spinner.fail(chalk.red('Failed to compress embeddings'));
console.error(chalk.red(error.message));
process.exit(1);
}
});
// GNN Search command
gnnCmd
.command('search')
.description('Differentiable search with soft attention')
.requiredOption('-q, --query <json>', 'Query vector as JSON array')
.requiredOption('-c, --candidates <file>', 'Candidates file (JSON array of vectors)')
.option('-k, --top-k <number>', 'Number of results', '5')
.option('-t, --temperature <number>', 'Softmax temperature (lower=sharper)', '1.0')
.action((options) => {
requireGnn();
const spinner = ora('Loading candidates...').start();
try {
const query = JSON.parse(options.query);
const candidatesData = JSON.parse(fs.readFileSync(options.candidates, 'utf8'));
const candidates = candidatesData.map(c => c.vector || c);
const k = parseInt(options.topK);
const temperature = parseFloat(options.temperature);
spinner.text = 'Running differentiable search...';
const result = differentiableSearch(query, candidates, k, temperature);
spinner.succeed(chalk.green(`Found top-${k} results`));
console.log(chalk.cyan('\nSearch Results:'));
console.log(chalk.white(` Query dim: ${chalk.yellow(query.length)}`));
console.log(chalk.white(` Candidates: ${chalk.yellow(candidates.length)}`));
console.log(chalk.white(` Temperature: ${chalk.yellow(temperature)}`));
console.log(chalk.cyan('\nTop-K Results:'));
for (let i = 0; i < result.indices.length; i++) {
const idx = result.indices[i];
const weight = result.weights[i];
const id = candidatesData[idx]?.id || `candidate_${idx}`;
console.log(chalk.white(` ${i + 1}. ${chalk.yellow(id)} (index: ${idx})`));
console.log(chalk.gray(` Weight: ${weight.toFixed(6)}`));
}
} catch (error) {
spinner.fail(chalk.red('Failed to run search'));
console.error(chalk.red(error.message));
process.exit(1);
}
});
// GNN Info command
gnnCmd
.command('info')
.description('Show GNN module information')
.action(() => {
if (!gnnAvailable) {
console.log(chalk.yellow('\nGNN Module: Not installed'));
console.log(chalk.white('Install with: npm install @ruvector/gnn'));
return;
}
console.log(chalk.cyan('\nGNN Module Information'));
console.log(chalk.white(` Status: ${chalk.green('Available')}`));
console.log(chalk.white(` Platform: ${chalk.yellow(process.platform)}`));
console.log(chalk.white(` Architecture: ${chalk.yellow(process.arch)}`));
console.log(chalk.cyan('\nAvailable Features:'));
console.log(chalk.white(` • RuvectorLayer - GNN layer with multi-head attention`));
console.log(chalk.white(` • TensorCompress - Adaptive tensor compression (5 levels)`));
console.log(chalk.white(` • differentiableSearch - Soft attention-based search`));
console.log(chalk.white(` • hierarchicalForward - Multi-layer GNN processing`));
console.log(chalk.cyan('\nCompression Levels:'));
console.log(chalk.gray(` none (freq > 0.8) - Full precision, hot data`));
console.log(chalk.gray(` half (freq > 0.4) - ~50% savings, warm data`));
console.log(chalk.gray(` pq8 (freq > 0.1) - ~8x compression, cool data`));
console.log(chalk.gray(` pq4 (freq > 0.01) - ~16x compression, cold data`));
console.log(chalk.gray(` binary (freq <= 0.01) - ~32x compression, archive`));
});
// =============================================================================
// Attention Commands
// =============================================================================
// Helper to require attention module
function requireAttention() {
if (!attentionAvailable) {
console.error(chalk.red('Error: @ruvector/attention is not installed'));
console.error(chalk.yellow('Install it with: npm install @ruvector/attention'));
process.exit(1);
}
}
// Attention parent command
const attentionCmd = program
.command('attention')
.description('High-performance attention mechanism operations');
// Attention compute command - run attention on input vectors
attentionCmd
.command('compute')
.description('Compute attention over input vectors')
.requiredOption('-q, --query <json>', 'Query vector as JSON array')
.requiredOption('-k, --keys <file>', 'Keys file (JSON array of vectors)')
.option('-v, --values <file>', 'Values file (JSON array of vectors, defaults to keys)')
.option('-t, --type <type>', 'Attention type (dot|multi-head|flash|hyperbolic|linear)', 'dot')
.option('-h, --heads <number>', 'Number of attention heads (for multi-head)', '4')
.option('-d, --head-dim <number>', 'Head dimension (for multi-head)', '64')
.option('--curvature <number>', 'Curvature for hyperbolic attention', '1.0')
.option('-o, --output <file>', 'Output file for results')
.action((options) => {
requireAttention();
const spinner = ora('Loading keys...').start();
try {
const query = JSON.parse(options.query);
const keysData = JSON.parse(fs.readFileSync(options.keys, 'utf8'));
const keys = keysData.map(k => k.vector || k);
let values = keys;
if (options.values) {
const valuesData = JSON.parse(fs.readFileSync(options.values, 'utf8'));
values = valuesData.map(v => v.vector || v);
}
spinner.text = `Computing ${options.type} attention...`;
let result;
let attentionWeights;
switch (options.type) {
case 'dot': {
const attn = new DotProductAttention();
const queryMat = [query];
const output = attn.forward(queryMat, keys, values);
result = output[0];
attentionWeights = attn.getLastWeights ? attn.getLastWeights()[0] : null;
break;
}
case 'multi-head': {
const numHeads = parseInt(options.heads);
const headDim = parseInt(options.headDim);
const attn = new MultiHeadAttention(query.length, numHeads, headDim);
const queryMat = [query];
const output = attn.forward(queryMat, keys, values);
result = output[0];
break;
}
case 'flash': {
const attn = new FlashAttention(query.length);
const queryMat = [query];
const output = attn.forward(queryMat, keys, values);
result = output[0];
break;
}
case 'hyperbolic': {
const curvature = parseFloat(options.curvature);
const attn = new HyperbolicAttention(query.length, curvature);
const queryMat = [query];
const output = attn.forward(queryMat, keys, values);
result = output[0];
break;
}
case 'linear': {
const attn = new LinearAttention(query.length);
const queryMat = [query];
const output = attn.forward(queryMat, keys, values);
result = output[0];
break;
}
default:
throw new Error(`Unknown attention type: ${options.type}`);
}
spinner.succeed(chalk.green(`Attention computed (${options.type})`));
console.log(chalk.cyan('\nAttention Results:'));
console.log(chalk.white(` Type: ${chalk.yellow(options.type)}`));
console.log(chalk.white(` Query dim: ${chalk.yellow(query.length)}`));
console.log(chalk.white(` Num keys: ${chalk.yellow(keys.length)}`));
console.log(chalk.white(` Output dim: ${chalk.yellow(result.length)}`));
console.log(chalk.white(` Output: ${chalk.gray(`[${result.slice(0, 4).map(v => v.toFixed(4)).join(', ')}...]`)}`));
if (attentionWeights) {
console.log(chalk.cyan('\nAttention Weights:'));
attentionWeights.slice(0, 5).forEach((w, i) => {
console.log(chalk.gray(` Key ${i}: ${w.toFixed(4)}`));
});
if (attentionWeights.length > 5) {
console.log(chalk.gray(` ... and ${attentionWeights.length - 5} more`));
}
}
if (options.output) {
const outputData = { result, attentionWeights };
fs.writeFileSync(options.output, JSON.stringify(outputData, null, 2));
console.log(chalk.green(`\nResults saved to: ${options.output}`));
}
} catch (error) {
spinner.fail(chalk.red('Failed to compute attention'));
console.error(chalk.red(error.message));
process.exit(1);
}
});
// Attention benchmark command
attentionCmd
.command('benchmark')
.description('Benchmark attention mechanisms')
.option('-d, --dimension <number>', 'Vector dimension', '256')
.option('-n, --num-vectors <number>', 'Number of vectors', '100')
.option('-i, --iterations <number>', 'Benchmark iterations', '100')
.option('-t, --types <list>', 'Attention types to benchmark (comma-separated)', 'dot,flash,linear')
.action((options) => {
requireAttention();
const spinner = ora('Setting up benchmark...').start();
try {
const dim = parseInt(options.dimension);
const numVectors = parseInt(options.numVectors);
const iterations = parseInt(options.iterations);
const types = options.types.split(',').map(t => t.trim());
// Generate random test data
spinner.text = 'Generating test data...';
const query = Array.from({ length: dim }, () => Math.random());
const keys = Array.from({ length: numVectors }, () =>
Array.from({ length: dim }, () => Math.random())
);
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.cyan(' Attention Mechanism Benchmark'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
console.log(chalk.white(` Dimension: ${chalk.yellow(dim)}`));
console.log(chalk.white(` Vectors: ${chalk.yellow(numVectors)}`));
console.log(chalk.white(` Iterations: ${chalk.yellow(iterations)}`));
console.log('');
const results = [];
// Convert to Float32Arrays for compute()
const queryF32 = new Float32Array(query);
const keysF32 = keys.map(k => new Float32Array(k));
for (const type of types) {
spinner.text = `Benchmarking ${type} attention...`;
spinner.start();
let attn;
try {
switch (type) {
case 'dot':
attn = new DotProductAttention(dim);
break;
case 'flash':
attn = new FlashAttention(dim, 64); // dim, block_size
break;
case 'linear':
attn = new LinearAttention(dim, 64); // dim, num_features
break;
case 'hyperbolic':
attn = new HyperbolicAttention(dim, 1.0);
break;
case 'multi-head':
attn = new MultiHeadAttention(dim, 4); // dim, num_heads
break;
default:
console.log(chalk.yellow(` Skipping unknown type: ${type}`));
continue;
}
} catch (e) {
console.log(chalk.yellow(` ${type}: not available (${e.message})`));
continue;
}
// Warm up
for (let i = 0; i < 5; i++) {
try {
attn.compute(queryF32, keysF32, keysF32);
} catch (e) {
// Some mechanisms may fail warmup
}
}
// Benchmark
const start = process.hrtime.bigint();
for (let i = 0; i < iterations; i++) {
attn.compute(queryF32, keysF32, keysF32);
}
const end = process.hrtime.bigint();
const totalMs = Number(end - start) / 1_000_000;
const avgMs = totalMs / iterations;
const opsPerSec = 1000 / avgMs;
results.push({ type, avgMs, opsPerSec });
spinner.succeed(chalk.green(`${type}: ${avgMs.toFixed(3)} ms/op (${opsPerSec.toFixed(1)} ops/sec)`));
}
// Summary
if (results.length > 0) {
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.cyan(' Summary'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
const fastest = results.reduce((a, b) => a.avgMs < b.avgMs ? a : b);
console.log(chalk.green(` Fastest: ${fastest.type} (${fastest.avgMs.toFixed(3)} ms/op)\n`));
console.log(chalk.white(' Relative Performance:'));
for (const r of results) {
const relPerf = (fastest.avgMs / r.avgMs * 100).toFixed(1);
const bar = '█'.repeat(Math.round(relPerf / 5));
console.log(chalk.white(` ${r.type.padEnd(12)} ${chalk.cyan(bar)} ${relPerf}%`));
}
}
} catch (error) {
spinner.fail(chalk.red('Benchmark failed'));
console.error(chalk.red(error.message));
process.exit(1);
}
});
// Hyperbolic math command
attentionCmd
.command('hyperbolic')
.description('Hyperbolic geometry operations')
.requiredOption('-a, --action <type>', 'Action: exp-map|log-map|distance|project|mobius-add')
.requiredOption('-v, --vector <json>', 'Input vector(s) as JSON')
.option('-b, --vector-b <json>', 'Second vector for binary operations')
.option('-c, --curvature <number>', 'Poincaré ball curvature', '1.0')
.option('-o, --origin <json>', 'Origin point for exp/log maps')
.action((options) => {
requireAttention();
try {
const vecArray = JSON.parse(options.vector);
const vec = new Float32Array(vecArray);
const curvature = parseFloat(options.curvature);
let result;
let description;
switch (options.action) {
case 'exp-map': {
const originArray = options.origin ? JSON.parse(options.origin) : Array(vec.length).fill(0);
const origin = new Float32Array(originArray);
result = expMap(origin, vec, curvature);
description = 'Exponential map (tangent → Poincaré ball)';
break;
}
case 'log-map': {
const originArray = options.origin ? JSON.parse(options.origin) : Array(vec.length).fill(0);
const origin = new Float32Array(originArray);
result = logMap(origin, vec, curvature);
description = 'Logarithmic map (Poincaré ball → tangent)';
break;
}
case 'distance': {
if (!options.vectorB) {
throw new Error('--vector-b required for distance calculation');
}
const vecBArray = JSON.parse(options.vectorB);
const vecB = new Float32Array(vecBArray);
result = poincareDistance(vec, vecB, curvature);
description = 'Poincaré distance';
break;
}
case 'project': {
result = projectToPoincareBall(vec, curvature);
description = 'Project to Poincaré ball';
break;
}
case 'mobius-add': {
if (!options.vectorB) {
throw new Error('--vector-b required for Möbius addition');
}
const vecBArray = JSON.parse(options.vectorB);
const vecB = new Float32Array(vecBArray);
result = mobiusAddition(vec, vecB, curvature);
description = 'Möbius addition';
break;
}
default:
throw new Error(`Unknown action: ${options.action}`);
}
console.log(chalk.cyan('\nHyperbolic Operation:'));
console.log(chalk.white(` Action: ${chalk.yellow(description)}`));
console.log(chalk.white(` Curvature: ${chalk.yellow(curvature)}`));
if (typeof result === 'number') {
console.log(chalk.white(` Result: ${chalk.green(result.toFixed(6))}`));
} else {
const resultArray = Array.from(result);
console.log(chalk.white(` Input dim: ${chalk.yellow(vec.length)}`));
console.log(chalk.white(` Output dim: ${chalk.yellow(resultArray.length)}`));
console.log(chalk.white(` Result: ${chalk.gray(`[${resultArray.slice(0, 5).map(v => v.toFixed(4)).join(', ')}...]`)}`));
// Compute norm to verify it's in the ball
const norm = Math.sqrt(resultArray.reduce((sum, x) => sum + x * x, 0));
console.log(chalk.white(` Norm: ${chalk.yellow(norm.toFixed(6))} ${norm < 1 ? chalk.green('(inside ball)') : chalk.red('(outside ball)')}`));
}
} catch (error) {
console.error(chalk.red('Hyperbolic operation failed:'), error.message);
process.exit(1);
}
});
// Attention info command
attentionCmd
.command('info')
.description('Show attention module information')
.action(() => {
if (!attentionAvailable) {
console.log(chalk.yellow('\nAttention Module: Not installed'));
console.log(chalk.white('Install with: npm install @ruvector/attention'));
return;
}
console.log(chalk.cyan('\nAttention Module Information'));
console.log(chalk.white(` Status: ${chalk.green('Available')}`));
console.log(chalk.white(` Version: ${chalk.yellow(attentionVersion ? attentionVersion() : 'unknown')}`));
console.log(chalk.white(` Platform: ${chalk.yellow(process.platform)}`));
console.log(chalk.white(` Architecture: ${chalk.yellow(process.arch)}`));
console.log(chalk.cyan('\nCore Attention Mechanisms:'));
console.log(chalk.white(` • DotProductAttention - Scaled dot-product attention`));
console.log(chalk.white(` • MultiHeadAttention - Multi-head self-attention`));
console.log(chalk.white(` • FlashAttention - Memory-efficient IO-aware attention`));
console.log(chalk.white(` • HyperbolicAttention - Poincaré ball attention`));
console.log(chalk.white(` • LinearAttention - O(n) linear complexity attention`));
console.log(chalk.white(` • MoEAttention - Mixture of Experts attention`));
console.log(chalk.cyan('\nGraph Attention:'));
console.log(chalk.white(` • GraphRoPeAttention - Rotary position embeddings for graphs`));
console.log(chalk.white(` • EdgeFeaturedAttention - Edge feature-enhanced attention`));
console.log(chalk.white(` • DualSpaceAttention - Euclidean + hyperbolic dual space`));
console.log(chalk.white(` • LocalGlobalAttention - Local-global graph attention`));
console.log(chalk.cyan('\nHyperbolic Math:'));
console.log(chalk.white(` • expMap, logMap - Exponential/logarithmic maps`));
console.log(chalk.white(` • mobiusAddition - Möbius addition in Poincaré ball`));
console.log(chalk.white(` • poincareDistance - Hyperbolic distance metric`));
console.log(chalk.white(` • projectToPoincareBall - Project vectors to ball`));
console.log(chalk.cyan('\nTraining Utilities:'));
console.log(chalk.white(` • AdamOptimizer, AdamWOptimizer, SgdOptimizer`));
console.log(chalk.white(` • InfoNceLoss, LocalContrastiveLoss`));
console.log(chalk.white(` • CurriculumScheduler, TemperatureAnnealing`));
console.log(chalk.white(` • HardNegativeMiner, InBatchMiner`));
});
// Attention list command - list available mechanisms
attentionCmd
.command('list')
.description('List all available attention mechanisms')
.option('-v, --verbose', 'Show detailed information')
.action((options) => {
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.cyan(' Available Attention Mechanisms'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
const mechanisms = [
{ name: 'DotProductAttention', type: 'core', complexity: 'O(n²)', available: !!DotProductAttention },
{ name: 'MultiHeadAttention', type: 'core', complexity: 'O(n²)', available: !!MultiHeadAttention },
{ name: 'FlashAttention', type: 'core', complexity: 'O(n²) IO-optimized', available: !!FlashAttention },
{ name: 'HyperbolicAttention', type: 'core', complexity: 'O(n²)', available: !!HyperbolicAttention },
{ name: 'LinearAttention', type: 'core', complexity: 'O(n)', available: !!LinearAttention },
{ name: 'MoEAttention', type: 'core', complexity: 'O(n*k)', available: !!MoEAttention },
{ name: 'GraphRoPeAttention', type: 'graph', complexity: 'O(n²)', available: !!GraphRoPeAttention },
{ name: 'EdgeFeaturedAttention', type: 'graph', complexity: 'O(n²)', available: !!EdgeFeaturedAttention },
{ name: 'DualSpaceAttention', type: 'graph', complexity: 'O(n²)', available: !!DualSpaceAttention },
{ name: 'LocalGlobalAttention', type: 'graph', complexity: 'O(n*k)', available: !!LocalGlobalAttention },
];
console.log(chalk.white(' Core Attention:'));
mechanisms.filter(m => m.type === 'core').forEach(m => {
const status = m.available ? chalk.green('✓') : chalk.red('✗');
console.log(chalk.white(` ${status} ${m.name.padEnd(22)} ${chalk.gray(m.complexity)}`));
});
console.log(chalk.white('\n Graph Attention:'));
mechanisms.filter(m => m.type === 'graph').forEach(m => {
const status = m.available ? chalk.green('✓') : chalk.red('✗');
console.log(chalk.white(` ${status} ${m.name.padEnd(22)} ${chalk.gray(m.complexity)}`));
});
if (!attentionAvailable) {
console.log(chalk.yellow('\n Note: @ruvector/attention not installed'));
console.log(chalk.white(' Install with: npm install @ruvector/attention'));
}
if (options.verbose) {
console.log(chalk.cyan('\n Usage Examples:'));
console.log(chalk.gray(' # Compute dot-product attention'));
console.log(chalk.white(' npx ruvector attention compute -q "[1,2,3]" -k keys.json -t dot'));
console.log(chalk.gray('\n # Benchmark attention mechanisms'));
console.log(chalk.white(' npx ruvector attention benchmark -d 256 -n 100'));
console.log(chalk.gray('\n # Hyperbolic distance'));
console.log(chalk.white(' npx ruvector attention hyperbolic -a distance -v "[0.1,0.2]" -b "[0.3,0.4]"'));
}
});
// =============================================================================
// Doctor Command - Check system health and dependencies
// =============================================================================
program
.command('doctor')
.description('Check system health and dependencies')
.option('-v, --verbose', 'Show detailed information')
.action(async (options) => {
const { execSync } = require('child_process');
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.cyan(' RuVector Doctor'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
let issues = 0;
let warnings = 0;
// Helper functions
const check = (name, condition, fix) => {
if (condition) {
console.log(chalk.green(` ✓ ${name}`));
return true;
} else {
console.log(chalk.red(` ✗ ${name}`));
if (fix) console.log(chalk.gray(` Fix: ${fix}`));
issues++;
return false;
}
};
const warn = (name, condition, suggestion) => {
if (condition) {
console.log(chalk.green(` ✓ ${name}`));
return true;
} else {
console.log(chalk.yellow(` ! ${name}`));
if (suggestion) console.log(chalk.gray(` Suggestion: ${suggestion}`));
warnings++;
return false;
}
};
const getVersion = (cmd) => {
try {
return execSync(cmd, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
} catch (e) {
return null;
}
};
// System Information
console.log(chalk.cyan('System Information:'));
console.log(chalk.white(` Platform: ${chalk.yellow(process.platform)}`));
console.log(chalk.white(` Architecture: ${chalk.yellow(process.arch)}`));
console.log(chalk.white(` Node.js: ${chalk.yellow(process.version)}`));
console.log('');
// Node.js Checks
console.log(chalk.cyan('Node.js Environment:'));
const nodeVersion = parseInt(process.version.slice(1).split('.')[0]);
check('Node.js >= 14', nodeVersion >= 14, 'Upgrade Node.js: https://nodejs.org');
const npmVersion = getVersion('npm --version');
if (npmVersion) {
console.log(chalk.green(` ✓ npm ${npmVersion}`));
} else {
check('npm installed', false, 'Install npm or reinstall Node.js');
}
console.log('');
// RuVector Packages
console.log(chalk.cyan('RuVector Packages:'));
// Check @ruvector/core
let coreAvailable = false;
try {
require.resolve('@ruvector/core');
coreAvailable = true;
console.log(chalk.green(` ✓ @ruvector/core installed`));
} catch (e) {
console.log(chalk.yellow(` ! @ruvector/core not found (using WASM fallback)`));
warnings++;
}
// Check if native binding works
if (coreAvailable && loadRuvector()) {
const version = typeof getVersion === 'function' ? getVersion() : null;
const impl = typeof getImplementationType === 'function' ? getImplementationType() : 'native';
const versionStr = version ? `, v${version}` : '';
console.log(chalk.green(` ✓ Native binding working (${impl}${versionStr})`));
} else if (coreAvailable) {
console.log(chalk.yellow(` ! Native binding failed to load`));
warnings++;
}
// Check @ruvector/gnn
if (gnnAvailable) {
console.log(chalk.green(` ✓ @ruvector/gnn installed`));
} else {
console.log(chalk.gray(` ○ @ruvector/gnn not installed (optional)`));
}
// Check @ruvector/attention
if (attentionAvailable) {
console.log(chalk.green(` ✓ @ruvector/attention installed`));
} else {
console.log(chalk.gray(` ○ @ruvector/attention not installed (optional)`));
}
// Check @ruvector/graph-node
try {
require.resolve('@ruvector/graph-node');
console.log(chalk.green(` ✓ @ruvector/graph-node installed`));
} catch (e) {
console.log(chalk.gray(` ○ @ruvector/graph-node not installed (optional)`));
}
console.log('');
// Rust Toolchain (optional for development)
console.log(chalk.cyan('Rust Toolchain (optional):'));
const rustVersion = getVersion('rustc --version');
if (rustVersion) {
console.log(chalk.green(` ✓ ${rustVersion}`));
} else {
console.log(chalk.gray(` ○ Rust not installed (only needed for development)`));
}
const cargoVersion = getVersion('cargo --version');
if (cargoVersion) {
console.log(chalk.green(` ✓ ${cargoVersion}`));
} else if (rustVersion) {
console.log(chalk.yellow(` ! cargo not found`));
warnings++;
}
console.log('');
// Build Tools (optional)
if (options.verbose) {
console.log(chalk.cyan('Build Tools (for native compilation):'));
const hasGcc = getVersion('gcc --version');
const hasClang = getVersion('clang --version');
const hasCc = getVersion('cc --version');
if (hasGcc || hasClang || hasCc) {
console.log(chalk.green(` ✓ C compiler available`));
} else {
console.log(chalk.gray(` ○ No C compiler found (only needed for building from source)`));
}
const hasMake = getVersion('make --version');
if (hasMake) {
console.log(chalk.green(` ✓ make available`));
} else {
console.log(chalk.gray(` ○ make not found`));
}
const hasCmake = getVersion('cmake --version');
if (hasCmake) {
console.log(chalk.green(` ✓ cmake available`));
} else {
console.log(chalk.gray(` ○ cmake not found`));
}
console.log('');
}
// Summary
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════'));
if (issues === 0 && warnings === 0) {
console.log(chalk.green('\n ✓ All checks passed! RuVector is ready to use.\n'));
} else if (issues === 0) {
console.log(chalk.yellow(`\n ! ${warnings} warning(s) found. RuVector should work but may have limited features.\n`));
} else {
console.log(chalk.red(`\n ✗ ${issues} issue(s) and ${warnings} warning(s) found.\n`));
console.log(chalk.white(' Run "npx ruvector setup" for installation instructions.\n'));
}
});
// =============================================================================
// Setup Command - Installation instructions
// =============================================================================
program
.command('setup')
.description('Show installation and setup instructions')
.option('--rust', 'Show Rust installation instructions')
.option('--npm', 'Show npm package installation instructions')
.option('--all', 'Show all installation instructions')
.action((options) => {
const showAll = options.all || (!options.rust && !options.npm);
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.cyan(' RuVector Setup Guide'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
// Quick install
console.log(chalk.cyan('Quick Install (one-liner):'));
console.log(chalk.white(' curl -fsSL https://raw.githubusercontent.com/ruvnet/ruvector/main/install.sh | bash'));
console.log('');
if (showAll || options.npm) {
console.log(chalk.cyan('───────────────────────────────────────────────────────────────'));
console.log(chalk.cyan('npm Packages'));
console.log(chalk.cyan('───────────────────────────────────────────────────────────────\n'));
console.log(chalk.yellow('All-in-one CLI:'));
console.log(chalk.white(' npm install -g ruvector'));
console.log(chalk.white(' npx ruvector'));
console.log('');
console.log(chalk.yellow('Core packages:'));
console.log(chalk.white(' npm install @ruvector/core # Vector database'));
console.log(chalk.white(' npm install @ruvector/gnn # Graph Neural Networks'));
console.log(chalk.white(' npm install @ruvector/graph-node # Hypergraph database'));
console.log('');
console.log(chalk.yellow('Install all optional packages:'));
console.log(chalk.white(' npx ruvector install --all'));
console.log('');
console.log(chalk.yellow('List available packages:'));
console.log(chalk.white(' npx ruvector install'));
console.log('');
}
if (showAll || options.rust) {
console.log(chalk.cyan('───────────────────────────────────────────────────────────────'));
console.log(chalk.cyan('Rust Installation'));
console.log(chalk.cyan('───────────────────────────────────────────────────────────────\n'));
console.log(chalk.yellow('1. Install Rust:'));
console.log(chalk.white(' curl --proto \'=https\' --tlsv1.2 -sSf https://sh.rustup.rs | sh'));
console.log(chalk.gray(' # Follow the prompts, then restart your terminal or run:'));
console.log(chalk.white(' source $HOME/.cargo/env'));
console.log('');
console.log(chalk.yellow('2. Verify installation:'));
console.log(chalk.white(' rustc --version'));
console.log(chalk.white(' cargo --version'));
console.log('');
console.log(chalk.yellow('3. Add RuVector crates to your project:'));
console.log(chalk.white(' cargo add ruvector-core # Vector database'));
console.log(chalk.white(' cargo add ruvector-graph # Hypergraph with Cypher'));
console.log(chalk.white(' cargo add ruvector-gnn # Graph Neural Networks'));
console.log('');
console.log(chalk.yellow('4. Other available crates:'));
console.log(chalk.white(' cargo add ruvector-cluster # Distributed clustering'));
console.log(chalk.white(' cargo add ruvector-raft # Raft consensus'));
console.log(chalk.white(' cargo add ruvector-replication # Data replication'));
console.log(chalk.white(' cargo add ruvector-tiny-dancer-core # AI routing'));
console.log(chalk.white(' cargo add ruvector-router-core # Semantic routing'));
console.log('');
console.log(chalk.yellow('Platform-specific notes:'));
console.log('');
if (process.platform === 'darwin') {
console.log(chalk.cyan(' macOS:'));
console.log(chalk.white(' xcode-select --install # Install command line tools'));
console.log('');
} else if (process.platform === 'linux') {
console.log(chalk.cyan(' Linux (Debian/Ubuntu):'));
console.log(chalk.white(' sudo apt-get update'));
console.log(chalk.white(' sudo apt-get install build-essential pkg-config libssl-dev'));
console.log('');
console.log(chalk.cyan(' Linux (RHEL/CentOS):'));
console.log(chalk.white(' sudo yum groupinstall "Development Tools"'));
console.log(chalk.white(' sudo yum install openssl-devel'));
console.log('');
} else if (process.platform === 'win32') {
console.log(chalk.cyan(' Windows:'));
console.log(chalk.white(' # Install Visual Studio Build Tools'));
console.log(chalk.white(' # https://visualstudio.microsoft.com/visual-cpp-build-tools/'));
console.log(chalk.white(' # Or use WSL2 for best experience'));
console.log('');
}
}
console.log(chalk.cyan('───────────────────────────────────────────────────────────────'));
console.log(chalk.cyan('Documentation & Resources'));
console.log(chalk.cyan('───────────────────────────────────────────────────────────────\n'));
console.log(chalk.white(' GitHub: https://github.com/ruvnet/ruvector'));
console.log(chalk.white(' npm: https://www.npmjs.com/package/ruvector'));
console.log(chalk.white(' crates.io: https://crates.io/crates/ruvector-core'));
console.log(chalk.white(' Issues: https://github.com/ruvnet/ruvector/issues'));
console.log('');
console.log(chalk.cyan('Quick Commands:'));
console.log(chalk.white(' npx ruvector doctor # Check system health'));
console.log(chalk.white(' npx ruvector info # Show version info'));
console.log(chalk.white(' npx ruvector benchmark # Run performance test'));
console.log(chalk.white(' npx ruvector install # List available packages'));
console.log('');
});
// =============================================================================
// Graph Commands - Cypher queries and graph operations
// =============================================================================
program
.command('graph')
.description('Graph database operations (requires @ruvector/graph-node)')
.option('-q, --query <cypher>', 'Execute Cypher query')
.option('-c, --create <label>', 'Create a node with label')
.option('-p, --properties <json>', 'Node properties as JSON')
.option('-r, --relate <spec>', 'Create relationship (from:rel:to)')
.option('--info', 'Show graph info and stats')
.action(async (options) => {
let graphNode;
try {
graphNode = require('@ruvector/graph-node');
} catch (e) {
console.log(chalk.yellow('\n @ruvector/graph-node is not installed.\n'));
console.log(chalk.cyan(' Install with:'));
console.log(chalk.white(' npm install @ruvector/graph-node\n'));
console.log(chalk.cyan(' Features:'));
console.log(chalk.gray(' - Cypher query language support'));
console.log(chalk.gray(' - Hypergraph data structure'));
console.log(chalk.gray(' - Knowledge graph operations'));
console.log(chalk.gray(' - Neo4j-compatible syntax\n'));
console.log(chalk.cyan(' Example usage:'));
console.log(chalk.white(' npx ruvector graph --query "CREATE (n:Person {name: \'Alice\'})"'));
console.log(chalk.white(' npx ruvector graph --query "MATCH (n) RETURN n"'));
console.log('');
return;
}
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.cyan(' RuVector Graph'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
if (options.info) {
console.log(chalk.green(' @ruvector/graph-node is available!'));
console.log(chalk.gray(` Platform: ${process.platform}-${process.arch}`));
console.log('');
console.log(chalk.yellow(' Available operations:'));
console.log(chalk.white(' --query <cypher> Execute Cypher query'));
console.log(chalk.white(' --create <label> Create node with label'));
console.log(chalk.white(' --relate <spec> Create relationship'));
console.log('');
return;
}
if (options.query) {
console.log(chalk.yellow(' Cypher Query:'), chalk.white(options.query));
console.log('');
// Actual implementation would execute the query
console.log(chalk.gray(' Note: Full Cypher execution requires running ruvector-server'));
console.log(chalk.gray(' See: npx ruvector server --help'));
}
if (options.create) {
const label = options.create;
const props = options.properties ? JSON.parse(options.properties) : {};
console.log(chalk.yellow(' Creating node:'), chalk.white(label));
console.log(chalk.gray(' Properties:'), JSON.stringify(props, null, 2));
}
console.log('');
});
// =============================================================================
// Router Commands - AI agent routing
// =============================================================================
program
.command('router')
.description('AI semantic router operations (requires ruvector-router-core)')
.option('--route <text>', 'Route text to best matching intent')
.option('--intents <file>', 'Load intents from JSON file')
.option('--add-intent <name>', 'Add new intent')
.option('--examples <json>', 'Example utterances for intent')
.option('--info', 'Show router info')
.action(async (options) => {
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.cyan(' RuVector Router'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
console.log(chalk.yellow(' Semantic Router for AI Agent Routing\n'));
if (options.info || (!options.route && !options.intents && !options.addIntent)) {
console.log(chalk.cyan(' Features:'));
console.log(chalk.gray(' - Semantic intent matching'));
console.log(chalk.gray(' - Multi-agent routing'));
console.log(chalk.gray(' - Dynamic intent registration'));
console.log(chalk.gray(' - Vector-based similarity matching'));
console.log('');
console.log(chalk.cyan(' Status:'), chalk.yellow('Coming Soon'));
console.log(chalk.gray(' The npm package for router is in development.'));
console.log(chalk.gray(' Rust crate available: cargo add ruvector-router-core'));
console.log('');
console.log(chalk.cyan(' Usage (when available):'));
console.log(chalk.white(' npx ruvector router --route "What is the weather?"'));
console.log(chalk.white(' npx ruvector router --intents intents.json --route "query"'));
console.log('');
return;
}
if (options.route) {
console.log(chalk.yellow(' Input:'), chalk.white(options.route));
console.log(chalk.gray(' Router package not yet available in npm.'));
console.log(chalk.gray(' Check issue #20 for roadmap.'));
}
console.log('');
});
// =============================================================================
// Server Commands - HTTP/gRPC server
// =============================================================================
program
.command('server')
.description('Start RuVector HTTP/gRPC server')
.option('-p, --port <number>', 'HTTP port', '8080')
.option('-g, --grpc-port <number>', 'gRPC port', '50051')
.option('-d, --data-dir <path>', 'Data directory', './ruvector-data')
.option('--http-only', 'Start only HTTP server')
.option('--grpc-only', 'Start only gRPC server')
.option('--cors', 'Enable CORS for all origins')
.option('--info', 'Show server info')
.action(async (options) => {
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.cyan(' RuVector Server'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
if (options.info || Object.keys(options).filter(k => k !== 'port' && k !== 'grpcPort' && k !== 'dataDir').length === 0) {
console.log(chalk.cyan(' Status:'), chalk.yellow('Coming Soon'));
console.log('');
console.log(chalk.cyan(' Planned Features:'));
console.log(chalk.gray(' - REST API for vector operations'));
console.log(chalk.gray(' - gRPC high-performance interface'));
console.log(chalk.gray(' - WebSocket real-time updates'));
console.log(chalk.gray(' - OpenAPI/Swagger documentation'));
console.log(chalk.gray(' - Prometheus metrics endpoint'));
console.log(chalk.gray(' - Health check endpoints'));
console.log('');
console.log(chalk.cyan(' Rust binary available:'));
console.log(chalk.white(' cargo install ruvector-server # When published'));
console.log('');
console.log(chalk.cyan(' Configuration (when available):'));
console.log(chalk.white(` --port ${options.port} # HTTP port`));
console.log(chalk.white(` --grpc-port ${options.grpcPort} # gRPC port`));
console.log(chalk.white(` --data-dir ${options.dataDir} # Data directory`));
console.log('');
console.log(chalk.gray(' Track progress: https://github.com/ruvnet/ruvector/issues/20'));
console.log('');
return;
}
console.log(chalk.yellow(' Server package not yet available.'));
console.log(chalk.gray(' Check issue #20 for roadmap.'));
console.log('');
});
// =============================================================================
// Cluster Commands - Distributed operations
// =============================================================================
program
.command('cluster')
.description('Distributed cluster operations')
.option('--status', 'Show cluster status')
.option('--join <address>', 'Join existing cluster')
.option('--leave', 'Leave cluster')
.option('--nodes', 'List cluster nodes')
.option('--leader', 'Show current leader')
.option('--info', 'Show cluster info')
.action(async (options) => {
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.cyan(' RuVector Cluster'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
console.log(chalk.cyan(' Status:'), chalk.yellow('Coming Soon'));
console.log('');
console.log(chalk.cyan(' Features:'));
console.log(chalk.gray(' - Raft consensus for leader election'));
console.log(chalk.gray(' - Automatic failover'));
console.log(chalk.gray(' - Data replication'));
console.log(chalk.gray(' - Sharding support'));
console.log(chalk.gray(' - Distributed queries'));
console.log('');
console.log(chalk.cyan(' Rust crates available:'));
console.log(chalk.white(' cargo add ruvector-cluster # Clustering'));
console.log(chalk.white(' cargo add ruvector-raft # Raft consensus'));
console.log(chalk.white(' cargo add ruvector-replication # Replication'));
console.log('');
console.log(chalk.cyan(' Commands (when available):'));
console.log(chalk.white(' npx ruvector cluster --status'));
console.log(chalk.white(' npx ruvector cluster --join 192.168.1.10:7000'));
console.log(chalk.white(' npx ruvector cluster --nodes'));
console.log('');
console.log(chalk.gray(' Track progress: https://github.com/ruvnet/ruvector/issues/20'));
console.log('');
});
// =============================================================================
// Export/Import Commands - Database backup/restore
// =============================================================================
program
.command('export <database>')
.description('Export database to file')
.option('-o, --output <file>', 'Output file path')
.option('-f, --format <type>', 'Export format (json|binary|parquet)', 'json')
.option('--compress', 'Compress output')
.option('--vectors-only', 'Export only vectors (no metadata)')
.action(async (dbPath, options) => {
requireRuvector();
const spinner = ora('Exporting database...').start();
try {
const outputFile = options.output || `${dbPath.replace(/\/$/, '')}_export.${options.format}`;
// Load database
const db = new VectorDB({ dimension: 384 }); // Will be overwritten by load
if (fs.existsSync(dbPath)) {
db.load(dbPath);
} else {
spinner.fail(chalk.red(`Database not found: ${dbPath}`));
process.exit(1);
}
const stats = db.getStats();
const data = {
version: packageJson.version,
exportedAt: new Date().toISOString(),
stats: stats,
vectors: [] // Would contain actual vector data
};
if (options.format === 'json') {
fs.writeFileSync(outputFile, JSON.stringify(data, null, 2));
} else {
spinner.fail(chalk.yellow(`Format '${options.format}' not yet supported. Using JSON.`));
fs.writeFileSync(outputFile.replace(/\.[^.]+$/, '.json'), JSON.stringify(data, null, 2));
}
spinner.succeed(chalk.green(`Exported to: ${outputFile}`));
console.log(chalk.gray(` Vectors: ${stats.count || 0}`));
console.log(chalk.gray(` Format: ${options.format}`));
} catch (error) {
spinner.fail(chalk.red('Export failed'));
console.error(chalk.red(error.message));
process.exit(1);
}
});
program
.command('import <file>')
.description('Import database from file')
.option('-d, --database <path>', 'Target database path')
.option('--merge', 'Merge with existing data')
.option('--replace', 'Replace existing data')
.action(async (file, options) => {
requireRuvector();
const spinner = ora('Importing database...').start();
try {
if (!fs.existsSync(file)) {
spinner.fail(chalk.red(`File not found: ${file}`));
process.exit(1);
}
const data = JSON.parse(fs.readFileSync(file, 'utf8'));
const dbPath = options.database || file.replace(/_export\.json$/, '');
spinner.text = 'Creating database...';
const db = new VectorDB({
dimension: data.stats?.dimension || 384,
path: dbPath,
autoPersist: true
});
// Would import actual vectors here
db.save(dbPath);
spinner.succeed(chalk.green(`Imported to: ${dbPath}`));
console.log(chalk.gray(` Source version: ${data.version}`));
console.log(chalk.gray(` Exported at: ${data.exportedAt}`));
} catch (error) {
spinner.fail(chalk.red('Import failed'));
console.error(chalk.red(error.message));
process.exit(1);
}
});
// =============================================================================
// Embed Command - Generate embeddings
// =============================================================================
// =============================================================================
// Embed Command - Generate embeddings (now with ONNX + Adaptive LoRA)
// =============================================================================
const embedCmd = program.command('embed').description('Generate embeddings from text (ONNX + Adaptive LoRA)');
embedCmd
.command('text')
.description('Embed a text string')
.argument('<text>', 'Text to embed')
.option('--adaptive', 'Use adaptive embedder with LoRA')
.option('--domain <domain>', 'Domain for prototype learning')
.option('-o, --output <file>', 'Output file for embedding')
.action(async (text, opts) => {
try {
const { performance } = require('perf_hooks');
const start = performance.now();
if (opts.adaptive) {
const { initAdaptiveEmbedder } = require('../dist/core/adaptive-embedder.js');
const embedder = await initAdaptiveEmbedder();
const embedding = await embedder.embed(text, { domain: opts.domain });
const stats = embedder.getStats();
console.log(chalk.cyan('\n🧠 Adaptive Embedding (ONNX + Micro-LoRA)\n'));
console.log(chalk.dim(`Text: "${text.slice(0, 60)}..."`));
console.log(chalk.dim(`Dimension: ${embedding.length}`));
console.log(chalk.dim(`LoRA rank: ${stats.loraRank} (${stats.loraParams} params)`));
console.log(chalk.dim(`Prototypes: ${stats.prototypes}`));
console.log(chalk.dim(`Time: ${(performance.now() - start).toFixed(1)}ms`));
if (opts.output) {
fs.writeFileSync(opts.output, JSON.stringify({ text, embedding, stats }, null, 2));
console.log(chalk.green(`\nSaved to ${opts.output}`));
}
} else {
const { initOnnxEmbedder, embed } = require('../dist/core/onnx-embedder.js');
await initOnnxEmbedder();
const result = await embed(text);
console.log(chalk.cyan('\n📊 ONNX Embedding (all-MiniLM-L6-v2)\n'));
console.log(chalk.dim(`Text: "${text.slice(0, 60)}..."`));
console.log(chalk.dim(`Dimension: ${result.embedding.length}`));
console.log(chalk.dim(`Time: ${(performance.now() - start).toFixed(1)}ms`));
if (opts.output) {
fs.writeFileSync(opts.output, JSON.stringify({ text, embedding: result.embedding }, null, 2));
console.log(chalk.green(`\nSaved to ${opts.output}`));
}
}
} catch (e) {
console.error(chalk.red('Embedding failed:'), e.message);
}
});
embedCmd
.command('adaptive')
.description('Adaptive embedding with Micro-LoRA optimization')
.option('--stats', 'Show adaptive embedder statistics')
.option('--consolidate', 'Run EWC consolidation')
.option('--reset', 'Reset adaptive weights')
.option('--export <file>', 'Export learned weights')
.option('--import <file>', 'Import learned weights')
.action(async (opts) => {
try {
const { initAdaptiveEmbedder } = require('../dist/core/adaptive-embedder.js');
const embedder = await initAdaptiveEmbedder();
if (opts.stats) {
const stats = embedder.getStats();
console.log(chalk.cyan('\n🧠 Adaptive Embedder Statistics\n'));
console.log(chalk.white('Base Model:'), chalk.dim(stats.baseModel));
console.log(chalk.white('Dimension:'), chalk.dim(stats.dimension));
console.log(chalk.white('LoRA Rank:'), chalk.dim(stats.loraRank));
console.log(chalk.white('LoRA Params:'), chalk.dim(`${stats.loraParams} (~${(stats.loraParams / (stats.dimension * stats.dimension) * 100).toFixed(2)}% of base)`));
console.log(chalk.white('Adaptations:'), chalk.dim(stats.adaptations));
console.log(chalk.white('Prototypes:'), chalk.dim(stats.prototypes));
console.log(chalk.white('Memory Size:'), chalk.dim(stats.memorySize));
console.log(chalk.white('EWC Consolidations:'), chalk.dim(stats.ewcConsolidations));
console.log(chalk.white('Contrastive Updates:'), chalk.dim(stats.contrastiveUpdates));
console.log('');
}
if (opts.consolidate) {
console.log(chalk.yellow('Running EWC consolidation...'));
await embedder.consolidate();
console.log(chalk.green('✓ Consolidation complete'));
}
if (opts.reset) {
embedder.reset();
console.log(chalk.green('✓ Adaptive weights reset'));
}
if (opts.export) {
const data = embedder.export();
fs.writeFileSync(opts.export, JSON.stringify(data, null, 2));
console.log(chalk.green(`✓ Exported to ${opts.export}`));
}
if (opts.import) {
const data = JSON.parse(fs.readFileSync(opts.import, 'utf-8'));
embedder.import(data);
console.log(chalk.green(`✓ Imported from ${opts.import}`));
}
} catch (e) {
console.error(chalk.red('Error:'), e.message);
}
});
embedCmd
.command('benchmark')
.description('Benchmark base vs adaptive embeddings')
.option('--iterations <n>', 'Number of iterations', '10')
.action(async (opts) => {
try {
const { performance } = require('perf_hooks');
const iterations = parseInt(opts.iterations) || 10;
console.log(chalk.cyan('\n🚀 Embedding Benchmark: Base ONNX vs Adaptive LoRA\n'));
const testTexts = [
'This is a test sentence for embedding generation.',
'The quick brown fox jumps over the lazy dog.',
'Machine learning models can learn from data.',
'Vector databases enable semantic search.',
];
// Benchmark base ONNX
const { initOnnxEmbedder, embed, embedBatch } = require('../dist/core/onnx-embedder.js');
await initOnnxEmbedder();
console.log(chalk.yellow('1. Base ONNX Embeddings'));
const baseStart = performance.now();
for (let i = 0; i < iterations; i++) {
await embed(testTexts[i % testTexts.length]);
}
const baseTime = (performance.now() - baseStart) / iterations;
console.log(chalk.dim(` Single: ${baseTime.toFixed(1)}ms avg`));
const baseBatchStart = performance.now();
for (let i = 0; i < Math.ceil(iterations / 4); i++) {
await embedBatch(testTexts);
}
const baseBatchTime = (performance.now() - baseBatchStart) / Math.ceil(iterations / 4);
console.log(chalk.dim(` Batch(4): ${baseBatchTime.toFixed(1)}ms avg (${(4000 / baseBatchTime).toFixed(1)}/s)`));
// Benchmark adaptive
const { initAdaptiveEmbedder } = require('../dist/core/adaptive-embedder.js');
const adaptive = await initAdaptiveEmbedder();
console.log(chalk.yellow('\n2. Adaptive ONNX + LoRA'));
const adaptStart = performance.now();
for (let i = 0; i < iterations; i++) {
await adaptive.embed(testTexts[i % testTexts.length]);
}
const adaptTime = (performance.now() - adaptStart) / iterations;
console.log(chalk.dim(` Single: ${adaptTime.toFixed(1)}ms avg`));
const adaptBatchStart = performance.now();
for (let i = 0; i < Math.ceil(iterations / 4); i++) {
await adaptive.embedBatch(testTexts);
}
const adaptBatchTime = (performance.now() - adaptBatchStart) / Math.ceil(iterations / 4);
console.log(chalk.dim(` Batch(4): ${adaptBatchTime.toFixed(1)}ms avg (${(4000 / adaptBatchTime).toFixed(1)}/s)`));
// Summary
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.bold('Summary'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════'));
const stats = adaptive.getStats();
console.log(chalk.dim(`\nAdaptive overhead: +${(adaptTime - baseTime).toFixed(1)}ms (+${((adaptTime/baseTime - 1) * 100).toFixed(1)}%)`));
console.log(chalk.dim(`LoRA params: ${stats.loraParams} (rank ${stats.loraRank})`));
console.log(chalk.dim(`Memory prototypes: ${stats.prototypes}`));
console.log(chalk.dim(`Episodic memory: ${stats.memorySize} entries`));
console.log(chalk.white('\nBenefits of Adaptive:'));
console.log(chalk.dim(' • Domain-specific fine-tuning via Micro-LoRA'));
console.log(chalk.dim(' • Contrastive learning from co-edit patterns'));
console.log(chalk.dim(' • EWC++ prevents catastrophic forgetting'));
console.log(chalk.dim(' • Prototype-based domain adaptation'));
console.log(chalk.dim(' • Episodic memory augmentation'));
console.log('');
} catch (e) {
console.error(chalk.red('Benchmark failed:'), e.message);
if (e.stack) console.error(chalk.dim(e.stack));
}
});
embedCmd
.command('optimized')
.description('Use optimized ONNX embedder with LRU caching')
.argument('[text]', 'Text to embed (optional)')
.option('--cache-size <n>', 'Embedding cache size', '512')
.option('--stats', 'Show cache statistics')
.option('--clear-cache', 'Clear all caches')
.option('--benchmark', 'Run cache benchmark')
.action(async (text, opts) => {
try {
const { performance } = require('perf_hooks');
const { OptimizedOnnxEmbedder } = require('../dist/core/onnx-optimized.js');
const embedder = new OptimizedOnnxEmbedder({
cacheSize: parseInt(opts.cacheSize) || 512,
lazyInit: false,
});
await embedder.init();
if (opts.clearCache) {
embedder.clearCache();
console.log(chalk.green('✓ Caches cleared'));
return;
}
if (opts.benchmark) {
console.log(chalk.cyan('\n⚡ Optimized ONNX Cache Benchmark\n'));
const testTexts = [
'Machine learning algorithms optimize model parameters',
'Vector databases enable semantic search capabilities',
'Neural networks learn hierarchical representations',
'Code embeddings capture syntax and semantic patterns',
'Transformer models use attention mechanisms',
];
// Cold benchmark
embedder.clearCache();
const coldStart = performance.now();
for (const t of testTexts) await embedder.embed(t);
const coldTime = performance.now() - coldStart;
// Warm benchmark
const warmStart = performance.now();
for (let i = 0; i < 100; i++) {
for (const t of testTexts) await embedder.embed(t);
}
const warmTime = performance.now() - warmStart;
const stats = embedder.getCacheStats();
console.log(chalk.yellow('Performance:'));
console.log(chalk.dim(' Cold (5 unique texts):'), chalk.white(coldTime.toFixed(2) + 'ms'));
console.log(chalk.dim(' Warm (500 cached):'), chalk.white(warmTime.toFixed(2) + 'ms'));
console.log(chalk.dim(' Cache speedup:'), chalk.green((coldTime / warmTime * 100).toFixed(0) + 'x'));
console.log();
console.log(chalk.yellow('Cache Stats:'));
console.log(chalk.dim(' Hit rate:'), chalk.white((stats.embedding.hitRate * 100).toFixed(1) + '%'));
console.log(chalk.dim(' Cache size:'), chalk.white(stats.embedding.size));
console.log(chalk.dim(' Total embeds:'), chalk.white(stats.totalEmbeds));
console.log();
return;
}
if (opts.stats) {
const stats = embedder.getCacheStats();
console.log(chalk.cyan('\n📊 Optimized ONNX Embedder Stats\n'));
console.log(chalk.white('Embedding Cache:'));
console.log(chalk.dim(' Size:'), stats.embedding.size);
console.log(chalk.dim(' Hits:'), stats.embedding.hits);
console.log(chalk.dim(' Misses:'), stats.embedding.misses);
console.log(chalk.dim(' Hit Rate:'), (stats.embedding.hitRate * 100).toFixed(1) + '%');
console.log();
console.log(chalk.white('Performance:'));
console.log(chalk.dim(' Avg Time:'), stats.avgTimeMs.toFixed(2) + 'ms');
console.log(chalk.dim(' Total Embeds:'), stats.totalEmbeds);
console.log();
return;
}
if (text) {
const start = performance.now();
const embedding = await embedder.embed(text);
const elapsed = performance.now() - start;
const stats = embedder.getCacheStats();
console.log(chalk.cyan('\n⚡ Optimized ONNX Embedding\n'));
console.log(chalk.dim(`Text: "${text.slice(0, 60)}${text.length > 60 ? '...' : ''}"`));
console.log(chalk.dim(`Dimension: ${embedding.length}`));
console.log(chalk.dim(`Time: ${elapsed.toFixed(2)}ms`));
console.log(chalk.dim(`Cache hit rate: ${(stats.embedding.hitRate * 100).toFixed(1)}%`));
console.log();
} else {
console.log(chalk.yellow('Usage: ruvector embed optimized <text>'));
console.log(chalk.dim(' --stats Show cache statistics'));
console.log(chalk.dim(' --benchmark Run cache benchmark'));
console.log(chalk.dim(' --clear-cache Clear all caches'));
console.log(chalk.dim(' --cache-size Set cache size (default: 512)'));
}
} catch (e) {
console.error(chalk.red('Error:'), e.message);
}
});
embedCmd
.command('neural')
.description('Neural embedding substrate (frontier AI concepts)')
.option('--health', 'Show neural substrate health')
.option('--consolidate', 'Run memory consolidation (like sleep)')
.option('--calibrate', 'Calibrate coherence baseline')
.option('--swarm-status', 'Show swarm coordination status')
.option('--drift-stats', 'Show semantic drift statistics')
.option('--memory-stats', 'Show memory physics statistics')
.option('--demo', 'Run interactive neural demo')
.option('--dimension <n>', 'Embedding dimension', '384')
.action(async (opts) => {
try {
const { NeuralSubstrate } = require('../dist/core/neural-embeddings.js');
const { initOnnxEmbedder, embed } = require('../dist/core/onnx-embedder.js');
const dimension = parseInt(opts.dimension) || 384;
const substrate = new NeuralSubstrate({ dimension });
if (opts.demo) {
console.log(chalk.cyan('\n🧠 Neural Embedding Substrate Demo\n'));
console.log(chalk.dim('Frontier AI concepts: drift detection, memory physics, swarm coordination\n'));
// Initialize ONNX for real embeddings
await initOnnxEmbedder();
console.log(chalk.yellow('1. Semantic Drift Detection'));
console.log(chalk.dim(' Observing embeddings and detecting semantic movement...\n'));
const texts = [
'Machine learning optimizes neural networks',
'Deep learning uses backpropagation',
'AI models learn from data patterns',
'Quantum computing is completely different', // Should trigger drift
];
for (const text of texts) {
const result = await embed(text);
const driftEvent = substrate.drift.observe(result.embedding, 'demo');
const symbol = driftEvent?.category === 'critical' ? '🚨' :
driftEvent?.category === 'warning' ? '⚠️' : '✓';
console.log(chalk.dim(` ${symbol} "${text.slice(0, 40)}..." → drift: ${driftEvent?.magnitude?.toFixed(3) || '0.000'}`));
}
console.log(chalk.yellow('\n2. Memory Physics (Hippocampal Dynamics)'));
console.log(chalk.dim(' Encoding memories with strength, decay, and consolidation...\n'));
const memories = [
{ id: 'mem1', text: 'Vector databases store embeddings' },
{ id: 'mem2', text: 'HNSW enables fast nearest neighbor search' },
{ id: 'mem3', text: 'Cosine similarity measures semantic closeness' },
];
for (const mem of memories) {
const result = await embed(mem.text);
const entry = substrate.memory.encode(mem.id, result.embedding, mem.text);
console.log(chalk.dim(` 📝 Encoded "${mem.id}": strength=${entry.strength.toFixed(2)}, interference=${entry.interference.toFixed(2)}`));
}
// Query memory
const queryText = 'How do vector databases work?';
const queryEmb = await embed(queryText);
const recalled = substrate.memory.recall(queryEmb.embedding, 2);
console.log(chalk.dim(`\n 🔍 Query: "${queryText}"`));
console.log(chalk.dim(` 📚 Recalled: ${recalled.map(m => m.id).join(', ')}`));
console.log(chalk.yellow('\n3. Agent State Machine (Geometric State)'));
console.log(chalk.dim(' Managing agent state as movement through embedding space...\n'));
// Define mode regions
substrate.state.defineMode('research', queryEmb.embedding, 0.5);
const codeEmb = await embed('Write code and debug programs');
substrate.state.defineMode('coding', codeEmb.embedding, 0.5);
// Update agent state
const agent1State = substrate.state.updateAgent('agent-1', queryEmb.embedding);
console.log(chalk.dim(` 🤖 agent-1 mode: ${agent1State.mode}, energy: ${agent1State.energy.toFixed(2)}`));
const agent2State = substrate.state.updateAgent('agent-2', codeEmb.embedding);
console.log(chalk.dim(` 🤖 agent-2 mode: ${agent2State.mode}, energy: ${agent2State.energy.toFixed(2)}`));
console.log(chalk.yellow('\n4. Swarm Coordination'));
console.log(chalk.dim(' Multi-agent coordination through shared embedding geometry...\n'));
substrate.swarm.register('researcher', queryEmb.embedding, 'research');
substrate.swarm.register('coder', codeEmb.embedding, 'development');
const reviewEmb = await embed('Review code and check quality');
substrate.swarm.register('reviewer', reviewEmb.embedding, 'review');
const coherence = substrate.swarm.getCoherence();
console.log(chalk.dim(` 🌐 Swarm coherence: ${(coherence * 100).toFixed(1)}%`));
const collaborators = substrate.swarm.findCollaborators('researcher', 2);
console.log(chalk.dim(` 🤝 Collaborators for researcher: ${collaborators.map(c => c.id).join(', ')}`));
console.log(chalk.yellow('\n5. Coherence Monitoring (Safety)'));
console.log(chalk.dim(' Detecting degradation, poisoning, misalignment...\n'));
try {
substrate.calibrate();
const report = substrate.coherence.report();
console.log(chalk.dim(` 📊 Overall coherence: ${(report.overallScore * 100).toFixed(1)}%`));
console.log(chalk.dim(` 📊 Stability: ${(report.stabilityScore * 100).toFixed(1)}%`));
console.log(chalk.dim(` 📊 Alignment: ${(report.alignmentScore * 100).toFixed(1)}%`));
} catch {
console.log(chalk.dim(' ℹ️ Need more observations to calibrate coherence'));
}
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.bold(' Neural Substrate: Embeddings as Synthetic Nervous System'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
console.log(chalk.dim('Components:'));
console.log(chalk.dim(' • SemanticDriftDetector - Control signals, reflex triggers'));
console.log(chalk.dim(' • MemoryPhysics - Forgetting, interference, consolidation'));
console.log(chalk.dim(' • EmbeddingStateMachine - Agent state via geometry'));
console.log(chalk.dim(' • SwarmCoordinator - Multi-agent coordination'));
console.log(chalk.dim(' • CoherenceMonitor - Safety/alignment detection'));
console.log(chalk.dim(' • NeuralSubstrate - Unified nervous system layer'));
console.log('');
return;
}
if (opts.health) {
const health = substrate.health();
console.log(chalk.cyan('\n🧠 Neural Substrate Health\n'));
console.log(chalk.yellow('Drift Detection:'));
console.log(chalk.dim(` Current drift: ${health.driftStats.currentDrift.toFixed(4)}`));
console.log(chalk.dim(` Velocity: ${health.driftStats.velocity.toFixed(4)}/s`));
console.log(chalk.dim(` Critical events: ${health.driftStats.criticalEvents}`));
console.log(chalk.dim(` Warning events: ${health.driftStats.warningEvents}`));
console.log(chalk.yellow('\nMemory Physics:'));
console.log(chalk.dim(` Total memories: ${health.memoryStats.totalMemories}`));
console.log(chalk.dim(` Avg strength: ${health.memoryStats.avgStrength.toFixed(3)}`));
console.log(chalk.dim(` Avg consolidation: ${health.memoryStats.avgConsolidation.toFixed(3)}`));
console.log(chalk.dim(` Avg interference: ${health.memoryStats.avgInterference.toFixed(3)}`));
console.log(chalk.yellow('\nSwarm Coordination:'));
console.log(chalk.dim(` Coherence: ${(health.swarmCoherence * 100).toFixed(1)}%`));
console.log(chalk.yellow('\nCoherence Report:'));
console.log(chalk.dim(` Overall: ${(health.coherenceReport.overallScore * 100).toFixed(1)}%`));
console.log(chalk.dim(` Drift: ${(health.coherenceReport.driftScore * 100).toFixed(1)}%`));
console.log(chalk.dim(` Stability: ${(health.coherenceReport.stabilityScore * 100).toFixed(1)}%`));
console.log(chalk.dim(` Alignment: ${(health.coherenceReport.alignmentScore * 100).toFixed(1)}%`));
if (health.coherenceReport.anomalies.length > 0) {
console.log(chalk.yellow('\nAnomalies:'));
for (const a of health.coherenceReport.anomalies) {
console.log(chalk.red(` ⚠️ ${a.type}: ${a.description} (severity: ${a.severity.toFixed(2)})`));
}
}
console.log('');
return;
}
if (opts.consolidate) {
console.log(chalk.yellow('Running memory consolidation...'));
const result = substrate.consolidate();
console.log(chalk.green(`✓ Consolidated: ${result.consolidated} memories`));
console.log(chalk.dim(` Forgotten: ${result.forgotten} weak memories`));
return;
}
if (opts.calibrate) {
try {
substrate.calibrate();
console.log(chalk.green('✓ Coherence baseline calibrated'));
} catch (e) {
console.log(chalk.yellow('Need more observations to calibrate'));
console.log(chalk.dim('Run --demo first to populate the substrate'));
}
return;
}
if (opts.driftStats) {
const stats = substrate.drift.getStats();
console.log(chalk.cyan('\n📊 Semantic Drift Statistics\n'));
console.log(chalk.dim(`Current drift: ${stats.currentDrift.toFixed(4)}`));
console.log(chalk.dim(`Velocity: ${stats.velocity.toFixed(4)} drift/s`));
console.log(chalk.dim(`Critical events: ${stats.criticalEvents}`));
console.log(chalk.dim(`Warning events: ${stats.warningEvents}`));
console.log(chalk.dim(`History size: ${stats.historySize}`));
console.log('');
return;
}
if (opts.memoryStats) {
const stats = substrate.memory.getStats();
console.log(chalk.cyan('\n📊 Memory Physics Statistics\n'));
console.log(chalk.dim(`Total memories: ${stats.totalMemories}`));
console.log(chalk.dim(`Average strength: ${stats.avgStrength.toFixed(3)}`));
console.log(chalk.dim(`Average consolidation: ${stats.avgConsolidation.toFixed(3)}`));
console.log(chalk.dim(`Average interference: ${stats.avgInterference.toFixed(3)}`));
console.log('');
return;
}
if (opts.swarmStatus) {
const coherence = substrate.swarm.getCoherence();
const clusters = substrate.swarm.detectClusters(0.7);
console.log(chalk.cyan('\n📊 Swarm Coordination Status\n'));
console.log(chalk.dim(`Coherence: ${(coherence * 100).toFixed(1)}%`));
console.log(chalk.dim(`Clusters detected: ${clusters.size}`));
for (const [leader, members] of clusters) {
console.log(chalk.dim(` Cluster ${leader}: ${members.join(', ')}`));
}
console.log('');
return;
}
// Default: show help
console.log(chalk.cyan('\n🧠 Neural Embedding Substrate\n'));
console.log(chalk.dim('Frontier AI concepts treating embeddings as a synthetic nervous system.\n'));
console.log(chalk.yellow('Commands:'));
console.log(chalk.dim(' --demo Run interactive neural demo'));
console.log(chalk.dim(' --health Show neural substrate health'));
console.log(chalk.dim(' --consolidate Run memory consolidation (like sleep)'));
console.log(chalk.dim(' --calibrate Calibrate coherence baseline'));
console.log(chalk.dim(' --drift-stats Show semantic drift statistics'));
console.log(chalk.dim(' --memory-stats Show memory physics statistics'));
console.log(chalk.dim(' --swarm-status Show swarm coordination status'));
console.log('');
console.log(chalk.yellow('Components:'));
console.log(chalk.dim(' • SemanticDriftDetector - Embeddings as control signals'));
console.log(chalk.dim(' • MemoryPhysics - Hippocampal memory dynamics'));
console.log(chalk.dim(' • EmbeddingStateMachine - Agent state via geometry'));
console.log(chalk.dim(' • SwarmCoordinator - Multi-agent coordination'));
console.log(chalk.dim(' • CoherenceMonitor - Safety/alignment detection'));
console.log('');
} catch (e) {
console.error(chalk.red('Error:'), e.message);
if (e.stack) console.error(chalk.dim(e.stack));
}
});
// =============================================================================
// Demo Command - Interactive tutorial
// =============================================================================
program
.command('demo')
.description('Run interactive demo and tutorials')
.option('--basic', 'Basic vector operations demo')
.option('--gnn', 'GNN differentiable search demo')
.option('--graph', 'Graph database demo')
.option('--benchmark', 'Performance benchmark demo')
.option('-i, --interactive', 'Interactive mode')
.action(async (options) => {
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.cyan(' RuVector Demo'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════\n'));
const showMenu = !options.basic && !options.gnn && !options.graph && !options.benchmark;
if (showMenu) {
console.log(chalk.yellow(' Available Demos:\n'));
console.log(chalk.white(' --basic '), chalk.gray('Basic vector operations (insert, search, delete)'));
console.log(chalk.white(' --gnn '), chalk.gray('GNN differentiable search with gradients'));
console.log(chalk.white(' --graph '), chalk.gray('Graph database and Cypher queries'));
console.log(chalk.white(' --benchmark '), chalk.gray('Performance benchmark suite'));
console.log('');
console.log(chalk.cyan(' Run a demo:'));
console.log(chalk.white(' npx ruvector demo --basic'));
console.log(chalk.white(' npx ruvector demo --gnn'));
console.log('');
return;
}
if (options.basic) {
requireRuvector();
console.log(chalk.yellow(' Basic Vector Operations Demo\n'));
const spinner = ora('Creating demo database...').start();
try {
const db = new VectorDB({ dimension: 4, metric: 'cosine' });
spinner.text = 'Inserting vectors...';
db.insert('vec1', [1.0, 0.0, 0.0, 0.0], { label: 'x-axis' });
db.insert('vec2', [0.0, 1.0, 0.0, 0.0], { label: 'y-axis' });
db.insert('vec3', [0.0, 0.0, 1.0, 0.0], { label: 'z-axis' });
db.insert('vec4', [0.7, 0.7, 0.0, 0.0], { label: 'xy-diagonal' });
spinner.succeed('Demo database created with 4 vectors');
console.log(chalk.cyan('\n Vectors inserted:'));
console.log(chalk.gray(' vec1: [1,0,0,0] - x-axis'));
console.log(chalk.gray(' vec2: [0,1,0,0] - y-axis'));
console.log(chalk.gray(' vec3: [0,0,1,0] - z-axis'));
console.log(chalk.gray(' vec4: [0.7,0.7,0,0] - xy-diagonal'));
console.log(chalk.cyan('\n Searching for nearest to [0.8, 0.6, 0, 0]:'));
const results = db.search([0.8, 0.6, 0.0, 0.0], 3);
results.forEach((r, i) => {
console.log(chalk.gray(` ${i + 1}. ${r.id} (score: ${r.score.toFixed(4)})`));
});
console.log(chalk.green('\n Demo complete!'));
} catch (error) {
spinner.fail(chalk.red('Demo failed'));
console.error(chalk.red(error.message));
}
}
if (options.gnn) {
if (!gnnAvailable) {
console.log(chalk.yellow(' @ruvector/gnn not installed.'));
console.log(chalk.white(' Install with: npm install @ruvector/gnn'));
console.log('');
return;
}
console.log(chalk.yellow(' GNN Differentiable Search Demo\n'));
try {
console.log(chalk.cyan(' Running differentiable search with gradients...\n'));
const queryVec = [1.0, 0.5, 0.3, 0.1];
const dbVectors = [
[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.5, 0.5, 0.5, 0.5],
[0.9, 0.4, 0.2, 0.1]
];
const result = differentiableSearch(queryVec, dbVectors, 3, 10.0);
console.log(chalk.cyan(' Query:'), JSON.stringify(queryVec));
console.log(chalk.cyan(' Top 3 results:'));
result.indices.forEach((idx, i) => {
console.log(chalk.gray(` ${i + 1}. Index ${idx} (attention: ${result.attention_weights[i].toFixed(4)})`));
});
console.log(chalk.cyan('\n Gradient flow enabled:'), chalk.green('Yes'));
console.log(chalk.gray(' Use for: Neural network training, learned retrieval'));
console.log(chalk.green('\n GNN demo complete!'));
} catch (error) {
console.error(chalk.red('GNN demo failed:', error.message));
}
}
if (options.graph) {
console.log(chalk.yellow(' Graph Database Demo\n'));
let graphNode;
try {
graphNode = require('@ruvector/graph-node');
console.log(chalk.green(' @ruvector/graph-node is available!'));
console.log(chalk.gray(' Full graph demo coming soon.'));
} catch (e) {
console.log(chalk.yellow(' @ruvector/graph-node not installed.'));
console.log(chalk.white(' Install with: npm install @ruvector/graph-node'));
}
console.log('');
}
if (options.benchmark) {
console.log(chalk.yellow(' Redirecting to benchmark command...\n'));
console.log(chalk.white(' Run: npx ruvector benchmark'));
console.log('');
}
});
// ============================================
// Self-Learning Intelligence Hooks
// Full RuVector Stack: VectorDB + SONA + Attention
// ============================================
// LAZY LOADING: IntelligenceEngine is only loaded when first accessed
// This reduces CLI startup from ~1000ms to ~70ms for simple operations
let IntelligenceEngine = null;
let engineLoadAttempted = false;
function loadIntelligenceEngine() {
if (engineLoadAttempted) return IntelligenceEngine;
engineLoadAttempted = true;
try {
const core = require('../dist/core/intelligence-engine.js');
IntelligenceEngine = core.IntelligenceEngine || core.default;
} catch (e) {
// IntelligenceEngine not available, use fallback
}
return IntelligenceEngine;
}
class Intelligence {
constructor(options = {}) {
this.intelPath = this.getIntelPath();
this.data = this.load();
this.alpha = 0.1;
this.lastEditedFile = null;
this.sessionStartTime = null;
this._engine = null;
this._engineInitialized = false;
// Skip engine init for fast operations (trajectory, coedit, error commands)
this._skipEngine = options.skipEngine || false;
}
// Lazy getter for engine - only initializes when first accessed
getEngine() {
if (this._skipEngine) return null;
if (this._engineInitialized) return this._engine;
this._engineInitialized = true;
const EngineClass = loadIntelligenceEngine();
if (EngineClass) {
try {
this._engine = new EngineClass({
maxMemories: 100000,
maxEpisodes: 50000,
enableSona: true,
enableAttention: true,
enableOnnx: true, // Enable ONNX semantic embeddings
learningRate: this.alpha,
});
// Import existing data into engine
if (this.data) {
this._engine.import(this.convertLegacyData(this.data), true);
}
} catch (e) {
this._engine = null;
}
}
return this._engine;
}
// Property alias for backwards compatibility
get engine() {
return this.getEngine();
}
// Check if engine is available WITHOUT triggering initialization
// Use this for optional engine features that have fallbacks
hasEngine() {
return this._engineInitialized && this._engine !== null;
}
// Get engine only if already initialized (doesn't trigger lazy load)
getEngineIfReady() {
return this._engineInitialized ? this._engine : null;
}
// Convert legacy data format to new engine format
convertLegacyData(data) {
const converted = {
memories: [],
routingPatterns: {},
errorPatterns: data.errors || {},
coEditPatterns: {},
agentMappings: {},
};
// Convert memories
if (data.memories) {
converted.memories = data.memories.map(m => ({
id: m.id,
content: m.content,
type: m.memory_type || 'general',
embedding: m.embedding || this.embed(m.content),
created: m.timestamp ? new Date(m.timestamp * 1000).toISOString() : new Date().toISOString(),
accessed: 0,
}));
}
// Convert Q-learning patterns to routing patterns
if (data.patterns) {
for (const [key, value] of Object.entries(data.patterns)) {
const [state, action] = key.split('|');
if (state && action) {
if (!converted.routingPatterns[state]) {
converted.routingPatterns[state] = {};
}
converted.routingPatterns[state][action] = value.q_value || 0.5;
}
}
}
// Convert file sequences to co-edit patterns
if (data.file_sequences) {
for (const seq of data.file_sequences) {
if (!converted.coEditPatterns[seq.from_file]) {
converted.coEditPatterns[seq.from_file] = {};
}
converted.coEditPatterns[seq.from_file][seq.to_file] = seq.count;
}
}
return converted;
}
// Prefer project-local storage, fall back to home directory
getIntelPath() {
const projectPath = path.join(process.cwd(), '.ruvector', 'intelligence.json');
const homePath = path.join(require('os').homedir(), '.ruvector', 'intelligence.json');
if (fs.existsSync(path.dirname(projectPath))) return projectPath;
if (fs.existsSync(path.join(process.cwd(), '.claude'))) return projectPath;
if (fs.existsSync(homePath)) return homePath;
return projectPath;
}
load() {
const defaults = {
patterns: {},
memories: [],
trajectories: [],
errors: {},
file_sequences: [],
agents: {},
edges: [],
stats: { total_patterns: 0, total_memories: 0, total_trajectories: 0, total_errors: 0, session_count: 0, last_session: 0 }
};
try {
if (fs.existsSync(this.intelPath)) {
const data = JSON.parse(fs.readFileSync(this.intelPath, 'utf-8'));
// Merge with defaults to ensure all fields exist
return {
patterns: data.patterns || defaults.patterns,
memories: data.memories || defaults.memories,
trajectories: data.trajectories || defaults.trajectories,
errors: data.errors || defaults.errors,
file_sequences: data.file_sequences || defaults.file_sequences,
agents: data.agents || defaults.agents,
edges: data.edges || defaults.edges,
stats: { ...defaults.stats, ...(data.stats || {}) },
// Preserve learning data if present
learning: data.learning || undefined
};
}
} catch {}
return defaults;
}
save() {
const dir = path.dirname(this.intelPath);
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
// If engine is already initialized, export its data (don't trigger lazy load)
const eng = this.getEngineIfReady();
if (eng) {
try {
const engineData = eng.export();
// Merge engine data with legacy format for compatibility
this.data.patterns = {};
for (const [state, actions] of Object.entries(engineData.routingPatterns || {})) {
for (const [action, value] of Object.entries(actions)) {
this.data.patterns[`${state}|${action}`] = { state, action, q_value: value, visits: 1, last_update: this.now() };
}
}
this.data.stats.total_patterns = Object.keys(this.data.patterns).length;
this.data.stats.total_memories = engineData.stats?.totalMemories || this.data.memories.length;
// Add engine stats
this.data.engineStats = engineData.stats;
} catch (e) {
// Ignore engine export errors
}
}
fs.writeFileSync(this.intelPath, JSON.stringify(this.data, null, 2));
}
now() { return Math.floor(Date.now() / 1000); }
// Use engine embedding if available (256-dim with attention), otherwise fallback (64-dim hash)
embed(text) {
// Only use engine if already initialized (don't trigger lazy load for embeddings)
const eng = this.getEngineIfReady();
if (eng) {
try {
return eng.embed(text);
} catch {}
}
// Fallback: simple 64-dim hash embedding
const embedding = new Array(64).fill(0);
for (let i = 0; i < text.length; i++) {
const idx = (text.charCodeAt(i) + i * 7) % 64;
embedding[idx] += 1.0;
}
const norm = Math.sqrt(embedding.reduce((a, b) => a + b * b, 0));
if (norm > 0) for (let i = 0; i < embedding.length; i++) embedding[i] /= norm;
return embedding;
}
similarity(a, b) {
if (!a || !b || a.length !== b.length) return 0;
const dot = a.reduce((sum, v, i) => sum + v * b[i], 0);
const normA = Math.sqrt(a.reduce((sum, v) => sum + v * v, 0));
const normB = Math.sqrt(b.reduce((sum, v) => sum + v * v, 0));
return normA > 0 && normB > 0 ? dot / (normA * normB) : 0;
}
// Memory operations - use engine's VectorDB for semantic search
async rememberAsync(memoryType, content, metadata = {}) {
if (this.engine) {
try {
const entry = await this.engine.remember(content, memoryType);
// Also store in legacy format for compatibility
this.data.memories.push({
id: entry.id,
memory_type: memoryType,
content,
embedding: entry.embedding,
metadata,
timestamp: this.now()
});
if (this.data.memories.length > 5000) this.data.memories.splice(0, 1000);
this.data.stats.total_memories = this.data.memories.length;
return entry.id;
} catch {}
}
return this.remember(memoryType, content, metadata);
}
remember(memoryType, content, metadata = {}) {
const id = `mem_${this.now()}`;
const embedding = this.embed(content);
this.data.memories.push({ id, memory_type: memoryType, content, embedding, metadata, timestamp: this.now() });
if (this.data.memories.length > 5000) this.data.memories.splice(0, 1000);
this.data.stats.total_memories = this.data.memories.length;
// Also store in engine if already initialized (don't trigger lazy load)
const eng = this.getEngineIfReady();
if (eng) {
eng.remember(content, memoryType).catch(() => {});
}
return id;
}
async recallAsync(query, topK = 5) {
if (this.engine) {
try {
const results = await this.engine.recall(query, topK);
// Return same format as sync recall() - direct memory objects
return results.map(r => ({
id: r.id,
content: r.content || '',
memory_type: r.type || 'general',
timestamp: r.created || new Date().toISOString(),
score: r.score || 0
}));
} catch {}
}
return this.recall(query, topK);
}
recall(query, topK) {
const queryEmbed = this.embed(query);
return this.data.memories
.map(m => ({ score: this.similarity(queryEmbed, m.embedding), memory: m }))
.sort((a, b) => b.score - a.score).slice(0, topK).map(r => r.memory);
}
// Q-learning operations - enhanced with SONA trajectory tracking
getQ(state, action) {
const key = `${state}|${action}`;
if (!this.data.patterns) this.data.patterns = {};
return this.data.patterns[key]?.q_value ?? 0;
}
updateQ(state, action, reward) {
const key = `${state}|${action}`;
if (!this.data.patterns) this.data.patterns = {};
if (!this.data.stats) this.data.stats = { total_patterns: 0, total_memories: 0, total_trajectories: 0, total_errors: 0, session_count: 0, last_session: 0 };
if (!this.data.patterns[key]) {
this.data.patterns[key] = { state, action, q_value: 0, visits: 0, last_update: 0 };
}
const p = this.data.patterns[key];
p.q_value = p.q_value + this.alpha * (reward - p.q_value);
p.visits++;
p.last_update = this.now();
this.data.stats.total_patterns = Object.keys(this.data.patterns).length;
// Record episode in engine if already initialized (don't trigger lazy load)
const eng = this.getEngineIfReady();
if (eng) {
eng.recordEpisode(state, action, reward, state, false).catch(() => {});
}
}
learn(state, action, outcome, reward) {
const id = `traj_${this.now()}`;
this.updateQ(state, action, reward);
if (!this.data.trajectories) this.data.trajectories = [];
if (!this.data.stats) this.data.stats = { total_patterns: 0, total_memories: 0, total_trajectories: 0, total_errors: 0, session_count: 0, last_session: 0 };
this.data.trajectories.push({ id, state, action, outcome, reward, timestamp: this.now() });
if (this.data.trajectories.length > 1000) this.data.trajectories.splice(0, 200);
this.data.stats.total_trajectories = this.data.trajectories.length;
// End trajectory in engine if already initialized (don't trigger lazy load)
const eng = this.getEngineIfReady();
if (eng) {
eng.endTrajectory(reward > 0.5, reward);
}
return id;
}
suggest(state, actions) {
let bestAction = actions[0] ?? '';
let bestQ = -Infinity;
for (const action of actions) {
const q = this.getQ(state, action);
if (q > bestQ) { bestQ = q; bestAction = action; }
}
return { action: bestAction, confidence: bestQ > 0 ? Math.min(bestQ, 1) : 0 };
}
// Agent routing - use engine's SONA-enhanced routing
async routeAsync(task, file, crateName, operation = 'edit') {
if (this.engine) {
try {
const result = await this.engine.route(task, file);
// Begin trajectory for learning
this.engine.beginTrajectory(task, file);
if (result.agent) {
this.engine.setTrajectoryRoute(result.agent);
}
return {
agent: result.agent,
confidence: result.confidence,
reason: result.reason + (result.patterns?.length ? ` (${result.patterns.length} SONA patterns)` : ''),
alternates: result.alternates,
patterns: result.patterns
};
} catch {}
}
return this.route(task, file, crateName, operation);
}
route(task, file, crateName, operation = 'edit') {
const fileType = file ? path.extname(file).slice(1) : 'unknown';
const state = `${operation}_${fileType}_in_${crateName ?? 'project'}`;
const agentMap = {
rs: ['rust-developer', 'coder', 'reviewer', 'tester'],
ts: ['typescript-developer', 'coder', 'frontend-dev'],
tsx: ['react-developer', 'typescript-developer', 'coder'],
js: ['javascript-developer', 'coder', 'frontend-dev'],
jsx: ['react-developer', 'coder'],
py: ['python-developer', 'coder', 'ml-developer'],
go: ['go-developer', 'coder'],
sql: ['database-specialist', 'coder'],
md: ['documentation-specialist', 'coder'],
yml: ['devops-engineer', 'coder'],
yaml: ['devops-engineer', 'coder']
};
const agents = agentMap[fileType] ?? ['coder', 'reviewer'];
const { action, confidence } = this.suggest(state, agents);
const reason = confidence > 0.5 ? 'learned from past success' : confidence > 0 ? 'based on patterns' : `default for ${fileType} files`;
// Begin trajectory in engine (only if already initialized)
const eng = this.getEngineIfReady();
if (eng) {
eng.beginTrajectory(task || operation, file);
}
return { agent: action, confidence, reason };
}
shouldTest(file) {
const ext = path.extname(file).slice(1);
switch (ext) {
case 'rs': {
const crateMatch = file.match(/crates\/([^/]+)/);
return crateMatch ? { suggest: true, command: `cargo test -p ${crateMatch[1]}` } : { suggest: true, command: 'cargo test' };
}
case 'ts': case 'tsx': case 'js': case 'jsx': return { suggest: true, command: 'npm test' };
case 'py': return { suggest: true, command: 'pytest' };
case 'go': return { suggest: true, command: 'go test ./...' };
default: return { suggest: false, command: '' };
}
}
// Co-edit pattern tracking - use engine's co-edit patterns
recordFileSequence(fromFile, toFile) {
const existing = this.data.file_sequences.find(s => s.from_file === fromFile && s.to_file === toFile);
if (existing) existing.count++;
else this.data.file_sequences.push({ from_file: fromFile, to_file: toFile, count: 1 });
this.lastEditedFile = toFile;
// Record in engine (only if already initialized)
const eng = this.getEngineIfReady();
if (eng) {
eng.recordCoEdit(fromFile, toFile);
}
}
suggestNext(file, limit = 3) {
// Try engine first (only if already initialized)
const eng = this.getEngineIfReady();
if (eng) {
try {
const results = eng.getLikelyNextFiles(file, limit);
if (results.length > 0) {
return results.map(r => ({ file: r.file, score: r.count }));
}
} catch {}
}
return this.data.file_sequences
.filter(s => s.from_file === file)
.sort((a, b) => b.count - a.count)
.slice(0, limit)
.map(s => ({ file: s.to_file, score: s.count }));
}
// Error pattern learning
recordErrorFix(errorPattern, fix) {
if (!this.data.errors[errorPattern]) {
this.data.errors[errorPattern] = [];
}
if (!this.data.errors[errorPattern].includes(fix)) {
this.data.errors[errorPattern].push(fix);
}
this.data.stats.total_errors = Object.keys(this.data.errors).length;
// Record in engine (only if already initialized)
const eng = this.getEngineIfReady();
if (eng) {
eng.recordErrorFix(errorPattern, fix);
}
}
getSuggestedFixes(error) {
// Try engine first (only if already initialized)
const eng = this.getEngineIfReady();
if (eng) {
try {
const fixes = eng.getSuggestedFixes(error);
if (fixes.length > 0) return fixes;
} catch {}
}
return this.data.errors[error] || [];
}
classifyCommand(command) {
const cmd = command.toLowerCase();
if (cmd.includes('cargo') || cmd.includes('rustc')) return { category: 'rust', subcategory: cmd.includes('test') ? 'test' : 'build', risk: 'low' };
if (cmd.includes('npm') || cmd.includes('node') || cmd.includes('yarn') || cmd.includes('pnpm')) return { category: 'javascript', subcategory: cmd.includes('test') ? 'test' : 'build', risk: 'low' };
if (cmd.includes('python') || cmd.includes('pip') || cmd.includes('pytest')) return { category: 'python', subcategory: cmd.includes('test') ? 'test' : 'run', risk: 'low' };
if (cmd.includes('go ')) return { category: 'go', subcategory: cmd.includes('test') ? 'test' : 'build', risk: 'low' };
if (cmd.includes('git')) return { category: 'git', subcategory: 'vcs', risk: cmd.includes('push') || cmd.includes('force') ? 'medium' : 'low' };
if (cmd.includes('rm ') || cmd.includes('delete') || cmd.includes('rmdir')) return { category: 'filesystem', subcategory: 'destructive', risk: 'high' };
if (cmd.includes('sudo') || cmd.includes('chmod') || cmd.includes('chown')) return { category: 'system', subcategory: 'privileged', risk: 'high' };
if (cmd.includes('docker') || cmd.includes('kubectl')) return { category: 'container', subcategory: 'orchestration', risk: 'medium' };
return { category: 'shell', subcategory: 'general', risk: 'low' };
}
swarmStats() {
const agents = Object.keys(this.data.agents).length;
const edges = this.data.edges.length;
return { agents, edges };
}
// Enhanced stats with engine metrics
stats() {
const baseStats = this.data.stats;
// Only use engine if already initialized (don't trigger lazy load for optional stats)
const eng = this.getEngineIfReady();
if (eng) {
try {
const engineStats = eng.getStats();
return {
...baseStats,
// Engine stats
engineEnabled: true,
sonaEnabled: engineStats.sonaEnabled,
attentionEnabled: engineStats.attentionEnabled,
embeddingDim: engineStats.memoryDimensions,
totalMemories: engineStats.totalMemories,
totalEpisodes: engineStats.totalEpisodes,
trajectoriesRecorded: engineStats.trajectoriesRecorded,
patternsLearned: engineStats.patternsLearned,
microLoraUpdates: engineStats.microLoraUpdates,
baseLoraUpdates: engineStats.baseLoraUpdates,
ewcConsolidations: engineStats.ewcConsolidations,
};
} catch {}
}
return { ...baseStats, engineEnabled: false };
}
sessionStart() {
this.data.stats.session_count++;
this.data.stats.last_session = this.now();
this.sessionStartTime = this.now();
// Tick engine for background learning (only if already initialized)
const eng = this.getEngineIfReady();
if (eng) {
eng.tick();
}
}
sessionEnd() {
// Ensure data structure exists with defaults
if (!this.data) {
this.data = { patterns: {}, memories: [], trajectories: [], errors: [], agents: {}, edges: [], stats: {} };
}
if (!this.data.stats) {
this.data.stats = { total_patterns: 0, total_memories: 0, total_trajectories: 0, total_errors: 0, session_count: 0, last_session: 0 };
}
if (!this.data.trajectories) {
this.data.trajectories = [];
}
const lastSession = this.data.stats.last_session || 0;
const duration = this.now() - (this.sessionStartTime || lastSession);
const actions = this.data.trajectories.filter(t => t && t.timestamp >= lastSession).length;
// Force learning cycle (only if engine already initialized)
try {
const eng = this.getEngineIfReady();
if (eng) {
eng.forceLearn();
}
} catch (e) {
// Ignore engine errors on session end
}
// Auto-compress patterns if enabled (v2.1)
try {
if (process.env.RUVECTOR_AUTO_COMPRESS === 'true' || process.env.RUVECTOR_TENSOR_COMPRESS === 'true') {
const TensorCompressClass = require('../dist/core/tensor-compress').default;
if (TensorCompressClass && this.data.compressedPatterns) {
const compress = new TensorCompressClass({ autoCompress: false });
compress.import(this.data.compressedPatterns);
const stats = compress.recompressAll();
this.data.compressedPatterns = compress.export();
// Only log if significant savings
if (stats.savingsPercent > 10 && stats.totalTensors > 5) {
// Silently compress, no console output to avoid hook noise
}
}
}
} catch (e) {
// Ignore compression errors on session end
}
// Save all data
try {
this.save();
} catch (e) {
// Ignore save errors on session end
}
return { duration, actions };
}
getLastEditedFile() { return this.lastEditedFile; }
// New: Check if full engine is available
isEngineEnabled() {
return this.engine !== null;
}
// New: Get engine capabilities
getCapabilities() {
if (!this.engine) {
return {
engine: false,
vectorDb: false,
sona: false,
attention: false,
embeddingDim: 64,
};
}
const stats = this.engine.getStats();
return {
engine: true,
vectorDb: true,
sona: stats.sonaEnabled,
attention: stats.attentionEnabled,
embeddingDim: stats.memoryDimensions,
};
}
}
// Hooks command group
const hooksCmd = program.command('hooks').description('Self-learning intelligence hooks for Claude Code');
// Helper: Detect project type
function detectProjectType() {
const cwd = process.cwd();
const types = [];
if (fs.existsSync(path.join(cwd, 'Cargo.toml'))) types.push('rust');
if (fs.existsSync(path.join(cwd, 'package.json'))) types.push('node');
if (fs.existsSync(path.join(cwd, 'requirements.txt')) || fs.existsSync(path.join(cwd, 'pyproject.toml'))) types.push('python');
if (fs.existsSync(path.join(cwd, 'go.mod'))) types.push('go');
if (fs.existsSync(path.join(cwd, 'Gemfile'))) types.push('ruby');
if (fs.existsSync(path.join(cwd, 'pom.xml')) || fs.existsSync(path.join(cwd, 'build.gradle'))) types.push('java');
return types.length > 0 ? types : ['generic'];
}
// Helper: Get permissions for project type
function getPermissionsForProjectType(types) {
const basePermissions = [
'Bash(git status)', 'Bash(git diff:*)', 'Bash(git log:*)', 'Bash(git add:*)',
'Bash(git commit:*)', 'Bash(git push)', 'Bash(git branch:*)', 'Bash(git checkout:*)',
'Bash(ls:*)', 'Bash(pwd)', 'Bash(cat:*)', 'Bash(mkdir:*)', 'Bash(which:*)', 'Bash(ruvector:*)'
];
const typePermissions = {
rust: ['Bash(cargo:*)', 'Bash(rustc:*)', 'Bash(rustfmt:*)', 'Bash(clippy:*)', 'Bash(wasm-pack:*)'],
node: ['Bash(npm:*)', 'Bash(npx:*)', 'Bash(node:*)', 'Bash(yarn:*)', 'Bash(pnpm:*)'],
python: ['Bash(python:*)', 'Bash(pip:*)', 'Bash(pytest:*)', 'Bash(poetry:*)', 'Bash(uv:*)'],
go: ['Bash(go:*)', 'Bash(gofmt:*)'],
ruby: ['Bash(ruby:*)', 'Bash(gem:*)', 'Bash(bundle:*)', 'Bash(rails:*)'],
java: ['Bash(mvn:*)', 'Bash(gradle:*)', 'Bash(java:*)', 'Bash(javac:*)'],
generic: ['Bash(make:*)']
};
let perms = [...basePermissions];
types.forEach(t => { if (typePermissions[t]) perms = perms.concat(typePermissions[t]); });
return [...new Set(perms)];
}
hooksCmd.command('init')
.description('Initialize hooks in current project')
.option('--force', 'Force overwrite existing settings')
.option('--minimal', 'Only basic hooks (no env, permissions, or advanced hooks)')
.option('--fast', 'Use fast local wrapper (20x faster, bypasses npx overhead)')
.option('--no-claude-md', 'Skip CLAUDE.md creation')
.option('--no-permissions', 'Skip permissions configuration')
.option('--no-env', 'Skip environment variables')
.option('--no-gitignore', 'Skip .gitignore update')
.option('--no-mcp', 'Skip MCP server configuration')
.option('--no-statusline', 'Skip statusLine configuration')
.option('--pretrain', 'Run pretrain after init to bootstrap intelligence')
.option('--build-agents [focus]', 'Generate optimized agents (quality|speed|security|testing|fullstack)')
.action(async (opts) => {
const settingsPath = path.join(process.cwd(), '.claude', 'settings.json');
const settingsDir = path.dirname(settingsPath);
const isWindows = process.platform === 'win32';
if (!fs.existsSync(settingsDir)) fs.mkdirSync(settingsDir, { recursive: true });
let settings = {};
if (fs.existsSync(settingsPath) && !opts.force) {
try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8')); } catch {}
}
// Fix schema if present
if (settings.$schema) {
settings.$schema = 'https://json.schemastore.org/claude-code-settings.json';
}
// Clean up invalid hook names
if (settings.hooks) {
if (settings.hooks.Start) { delete settings.hooks.Start; }
if (settings.hooks.End) { delete settings.hooks.End; }
}
// Detect project type
const projectTypes = detectProjectType();
console.log(chalk.blue(` ✓ Detected project type(s): ${projectTypes.join(', ')}`));
// Environment variables for intelligence (unless --minimal or --no-env)
if (!opts.minimal && opts.env !== false) {
settings.env = settings.env || {};
// Core intelligence settings
settings.env.RUVECTOR_INTELLIGENCE_ENABLED = settings.env.RUVECTOR_INTELLIGENCE_ENABLED || 'true';
settings.env.RUVECTOR_LEARNING_RATE = settings.env.RUVECTOR_LEARNING_RATE || '0.1';
settings.env.RUVECTOR_MEMORY_BACKEND = settings.env.RUVECTOR_MEMORY_BACKEND || 'rvlite';
settings.env.INTELLIGENCE_MODE = settings.env.INTELLIGENCE_MODE || 'treatment';
// v2.0 capabilities
settings.env.RUVECTOR_AST_ENABLED = settings.env.RUVECTOR_AST_ENABLED || 'true';
settings.env.RUVECTOR_DIFF_EMBEDDINGS = settings.env.RUVECTOR_DIFF_EMBEDDINGS || 'true';
settings.env.RUVECTOR_COVERAGE_ROUTING = settings.env.RUVECTOR_COVERAGE_ROUTING || 'true';
settings.env.RUVECTOR_GRAPH_ALGORITHMS = settings.env.RUVECTOR_GRAPH_ALGORITHMS || 'true';
settings.env.RUVECTOR_SECURITY_SCAN = settings.env.RUVECTOR_SECURITY_SCAN || 'true';
// v2.1 learning & compression
settings.env.RUVECTOR_MULTI_ALGORITHM = settings.env.RUVECTOR_MULTI_ALGORITHM || 'true';
settings.env.RUVECTOR_DEFAULT_ALGORITHM = settings.env.RUVECTOR_DEFAULT_ALGORITHM || 'double-q';
settings.env.RUVECTOR_TENSOR_COMPRESS = settings.env.RUVECTOR_TENSOR_COMPRESS || 'true';
settings.env.RUVECTOR_AUTO_COMPRESS = settings.env.RUVECTOR_AUTO_COMPRESS || 'true';
console.log(chalk.blue(' ✓ Environment variables configured (v2.1 with multi-algorithm learning)'));
}
// Workers configuration (native ruvector workers + agentic-flow integration)
if (!opts.minimal) {
settings.workers = settings.workers || {
enabled: true,
parallel: true,
maxConcurrent: 10,
native: {
enabled: true,
types: ['security', 'analysis', 'learning'],
defaultTimeout: 120000
},
triggers: {
ultralearn: { priority: 'high', agents: ['researcher', 'coder'] },
optimize: { priority: 'high', agents: ['performance-analyzer'] },
audit: { priority: 'critical', agents: ['security-analyst', 'tester'] },
map: { priority: 'medium', agents: ['architect'] },
security: { priority: 'critical', agents: ['security-analyst'] },
benchmark: { priority: 'low', agents: ['performance-analyzer'] },
document: { priority: 'medium', agents: ['documenter'] },
refactor: { priority: 'medium', agents: ['coder', 'reviewer'] },
testgaps: { priority: 'high', agents: ['tester'] },
deepdive: { priority: 'low', agents: ['researcher'] },
predict: { priority: 'medium', agents: ['analyst'] },
consolidate: { priority: 'low', agents: ['architect'] }
}
};
console.log(chalk.blue(' ✓ Workers configured (native + 12 triggers)'));
}
// Performance configuration with benchmark thresholds
if (!opts.minimal) {
settings.performance = settings.performance || {
modelCache: {
enabled: true,
maxSizeMB: 512,
ttlMinutes: 60
},
benchmarkThresholds: {
triggerDetection: { p95: 5 }, // <5ms
workerRegistry: { p95: 10 }, // <10ms
agentSelection: { p95: 1 }, // <1ms
memoryKeyGen: { p95: 0.1 }, // <0.1ms
concurrent10: { p95: 1000 }, // <1000ms
singleEmbedding: { p95: 500 }, // <500ms (WASM)
batchEmbedding16: { p95: 8000 } // <8000ms (WASM)
},
optimizations: {
parallelDispatch: true,
batchEmbeddings: true,
cacheEmbeddings: true,
simd: true
}
};
console.log(chalk.blue(' ✓ Performance thresholds configured'));
}
// Agent presets configuration
if (!opts.minimal) {
settings.agents = settings.agents || {
presets: {
'quick-scan': {
phases: ['file-discovery', 'summarization'],
timeout: 30000
},
'deep-analysis': {
phases: ['file-discovery', 'pattern-extraction', 'embedding-generation', 'complexity-analysis', 'summarization'],
timeout: 120000,
capabilities: { onnxEmbeddings: true, vectorDb: true }
},
'security-scan': {
phases: ['file-discovery', 'security-scan', 'summarization'],
timeout: 60000
},
'learning': {
phases: ['file-discovery', 'pattern-extraction', 'embedding-generation', 'vector-storage', 'summarization'],
timeout: 180000,
capabilities: { onnxEmbeddings: true, vectorDb: true, intelligenceMemory: true }
}
},
capabilities: {
onnxEmbeddings: true,
vectorDb: true,
intelligenceMemory: true,
parallelProcessing: true
}
};
console.log(chalk.blue(' ✓ Agent presets configured (4 presets)'));
}
// Permissions based on detected project type (unless --minimal or --no-permissions)
if (!opts.minimal && opts.permissions !== false) {
settings.permissions = settings.permissions || {};
settings.permissions.allow = settings.permissions.allow || getPermissionsForProjectType(projectTypes);
settings.permissions.deny = settings.permissions.deny || [
'Bash(rm -rf /)',
'Bash(sudo rm:*)',
'Bash(chmod 777:*)',
'Bash(mkfs:*)',
'Bash(dd if=/dev/zero:*)'
];
console.log(chalk.blue(' ✓ Permissions configured (project-specific)'));
}
// MCP server configuration (unless --minimal or --no-mcp)
if (!opts.minimal && opts.mcp !== false) {
settings.mcpServers = settings.mcpServers || {};
// Only add if not already configured
if (!settings.mcpServers['claude-flow'] && !settings.enabledMcpjsonServers?.includes('claude-flow')) {
settings.enabledMcpjsonServers = settings.enabledMcpjsonServers || [];
if (!settings.enabledMcpjsonServers.includes('claude-flow')) {
settings.enabledMcpjsonServers.push('claude-flow');
}
}
console.log(chalk.blue(' ✓ MCP servers configured'));
}
// StatusLine configuration (unless --minimal or --no-statusline)
if (!opts.minimal && opts.statusline !== false) {
if (!settings.statusLine) {
if (isWindows) {
// Windows: PowerShell statusline
const statuslineScript = path.join(settingsDir, 'statusline-command.ps1');
const statuslineContent = `# RuVector Intelligence Statusline for Windows PowerShell
# Compatible with PowerShell 5.1+ and PowerShell Core
$ErrorActionPreference = "SilentlyContinue"
$e = [char]27
$inputData = [Console]::In.ReadToEnd()
$data = $inputData | ConvertFrom-Json
$Model = if ($data.model.display_name) { $data.model.display_name } else { "Claude" }
$CWD = if ($data.workspace.current_dir) { $data.workspace.current_dir } else { $data.cwd }
$Dir = Split-Path -Leaf $CWD
$Branch = $null
try { Push-Location $CWD -ErrorAction Stop; $Branch = git branch --show-current 2>$null; Pop-Location } catch {}
Write-Host "$e[1m$Model$e[0m in $e[36m$Dir$e[0m$(if($Branch){" on $e[33m$Branch$e[0m"})"
$IntelFile = Join-Path $CWD ".ruvector\intelligence.json"
if (Test-Path $IntelFile) {
$Intel = Get-Content $IntelFile -Raw | ConvertFrom-Json
$Mem = if ($Intel.memories) { $Intel.memories.Count } else { 0 }
$Traj = if ($Intel.trajectories) { $Intel.trajectories.Count } else { 0 }
$Sess = if ($Intel.stats -and $Intel.stats.session_count) { $Intel.stats.session_count } else { 0 }
$Pat = if ($Intel.patterns) { ($Intel.patterns | Get-Member -MemberType NoteProperty).Count } else { 0 }
$Line2 = "$e[35m RuVector$e[0m"
if ($Pat -gt 0) { $Line2 += " $e[32m$Pat patterns$e[0m" } else { $Line2 += " $e[2mlearning$e[0m" }
if ($Mem -gt 0) { $Line2 += " $e[34m$Mem mem$e[0m" }
if ($Traj -gt 0) { $Line2 += " $e[33m$Traj traj$e[0m" }
if ($Sess -gt 0) { $Line2 += " $e[2m#$Sess$e[0m" }
Write-Host $Line2
} else {
Write-Host "$e[2m RuVector: run 'npx ruvector hooks session-start'$e[0m"
}
`;
fs.writeFileSync(statuslineScript, statuslineContent);
settings.statusLine = {
type: 'command',
command: 'powershell -NoProfile -ExecutionPolicy Bypass -File .claude/statusline-command.ps1'
};
} else {
// Unix (macOS, Linux): Bash statusline
const statuslineScript = path.join(settingsDir, 'statusline-command.sh');
const statuslineContent = `#!/bin/bash
# RuVector Intelligence Statusline - Multi-line display
INPUT=\$(cat)
MODEL=\$(echo "\$INPUT" | jq -r '.model.display_name // "Claude"')
CWD=\$(echo "\$INPUT" | jq -r '.workspace.current_dir // .cwd')
DIR=\$(basename "\$CWD")
BRANCH=\$(cd "\$CWD" 2>/dev/null && git branch --show-current 2>/dev/null)
RESET="\\033[0m"; BOLD="\\033[1m"; CYAN="\\033[36m"; YELLOW="\\033[33m"; GREEN="\\033[32m"; MAGENTA="\\033[35m"; BLUE="\\033[34m"; DIM="\\033[2m"; RED="\\033[31m"
printf "\$BOLD\$MODEL\$RESET in \$CYAN\$DIR\$RESET"
[ -n "\$BRANCH" ] && printf " on \$YELLOW⎇ \$BRANCH\$RESET"
echo
INTEL_FILE=""
for P in "\$CWD/.ruvector/intelligence.json" "\$CWD/npm/packages/ruvector/.ruvector/intelligence.json" "\$HOME/.ruvector/intelligence.json"; do
[ -f "\$P" ] && INTEL_FILE="\$P" && break
done
if [ -n "\$INTEL_FILE" ]; then
INTEL=\$(cat "\$INTEL_FILE" 2>/dev/null)
MEMORY_COUNT=\$(echo "\$INTEL" | jq -r '.memories | length // 0' 2>/dev/null)
TRAJ_COUNT=\$(echo "\$INTEL" | jq -r '.trajectories | length // 0' 2>/dev/null)
SESSION_COUNT=\$(echo "\$INTEL" | jq -r '.stats.session_count // 0' 2>/dev/null)
PATTERN_COUNT=\$(echo "\$INTEL" | jq -r '.patterns | length // 0' 2>/dev/null)
printf "\$MAGENTA🧠 RuVector\$RESET"
[ "\$PATTERN_COUNT" != "null" ] && [ "\$PATTERN_COUNT" -gt 0 ] 2>/dev/null && printf " \$GREEN◆\$RESET \$PATTERN_COUNT patterns" || printf " \$DIM◇ learning\$RESET"
[ "\$MEMORY_COUNT" != "null" ] && [ "\$MEMORY_COUNT" -gt 0 ] 2>/dev/null && printf " \$BLUE⬡\$RESET \$MEMORY_COUNT mem"
[ "\$TRAJ_COUNT" != "null" ] && [ "\$TRAJ_COUNT" -gt 0 ] 2>/dev/null && printf " \$YELLOW↝\$RESET\$TRAJ_COUNT"
[ "\$SESSION_COUNT" != "null" ] && [ "\$SESSION_COUNT" -gt 0 ] 2>/dev/null && printf " \$DIM#\$SESSION_COUNT\$RESET"
echo
else
printf "\$DIM🧠 RuVector: run 'npx ruvector hooks session-start' to initialize\$RESET\\n"
fi
`;
fs.writeFileSync(statuslineScript, statuslineContent);
fs.chmodSync(statuslineScript, '755');
settings.statusLine = {
type: 'command',
command: '.claude/statusline-command.sh'
};
}
console.log(chalk.blue(` ✓ StatusLine configured (${isWindows ? 'PowerShell' : 'Bash'})`));
}
}
// Fast wrapper creation (--fast option) - 20x faster than npx
let hookCmd = 'npx ruvector@latest';
let fastTimeouts = { simple: 2000, complex: 2000, session: 5000 };
if (opts.fast && !isWindows) {
const fastWrapperPath = path.join(settingsDir, 'ruvector-fast.sh');
const fastWrapperContent = `#!/bin/bash
# Fast RuVector hooks wrapper - avoids npx overhead (20x faster)
# Usage: .claude/ruvector-fast.sh hooks <command> [args...]
# Find ruvector CLI - check local first, then global
RUVECTOR_CLI=""
# Check local npm package (for development)
if [ -f "$PWD/npm/packages/ruvector/bin/cli.js" ]; then
RUVECTOR_CLI="$PWD/npm/packages/ruvector/bin/cli.js"
# Check node_modules
elif [ -f "$PWD/node_modules/ruvector/bin/cli.js" ]; then
RUVECTOR_CLI="$PWD/node_modules/ruvector/bin/cli.js"
# Check global npm installation
elif [ -f "$PWD/node_modules/.bin/ruvector" ]; then
exec "$PWD/node_modules/.bin/ruvector" "$@"
elif command -v ruvector &> /dev/null; then
exec ruvector "$@"
# Fallback to npx (slow but works)
else
exec npx ruvector@latest "$@"
fi
# Execute with node directly (fast path)
exec node "$RUVECTOR_CLI" "$@"
`;
fs.writeFileSync(fastWrapperPath, fastWrapperContent);
fs.chmodSync(fastWrapperPath, '755');
hookCmd = '.claude/ruvector-fast.sh';
fastTimeouts = { simple: 300, complex: 500, session: 1000 };
// Add permission for fast wrapper
if (settings.permissions && settings.permissions.allow) {
if (!settings.permissions.allow.includes('Bash(.claude/ruvector-fast.sh:*)')) {
settings.permissions.allow.push('Bash(.claude/ruvector-fast.sh:*)');
}
}
console.log(chalk.blue(' ✓ Fast wrapper created (.claude/ruvector-fast.sh) - 20x faster hooks'));
}
// Core hooks (always included) - with timeouts and error suppression
settings.hooks = settings.hooks || {};
settings.hooks.PreToolUse = [
{
matcher: 'Edit|Write|MultiEdit',
hooks: [
{ type: 'command', timeout: fastTimeouts.complex, command: `${hookCmd} hooks pre-edit "$TOOL_INPUT_file_path" 2>/dev/null || true` },
{ type: 'command', timeout: fastTimeouts.complex, command: `${hookCmd} hooks coedit-suggest --file "$TOOL_INPUT_file_path" 2>/dev/null || true` }
]
},
{ matcher: 'Bash', hooks: [{ type: 'command', timeout: fastTimeouts.complex, command: `${hookCmd} hooks pre-command "$TOOL_INPUT_command" 2>/dev/null || true` }] },
{ matcher: 'Read', hooks: [{ type: 'command', timeout: fastTimeouts.simple, command: `${hookCmd} hooks remember "Reading: $TOOL_INPUT_file_path" -t file_access 2>/dev/null || true` }] },
{ matcher: 'Glob|Grep', hooks: [{ type: 'command', timeout: fastTimeouts.simple, command: `${hookCmd} hooks remember "Search: $TOOL_INPUT_pattern" -t search_pattern 2>/dev/null || true` }] },
{ matcher: 'Task', hooks: [{ type: 'command', timeout: fastTimeouts.simple, command: `${hookCmd} hooks remember "Agent: $TOOL_INPUT_subagent_type" -t agent_spawn 2>/dev/null || true` }] }
];
settings.hooks.PostToolUse = [
{ matcher: 'Edit|Write|MultiEdit', hooks: [{ type: 'command', timeout: fastTimeouts.complex, command: `${hookCmd} hooks post-edit "$TOOL_INPUT_file_path" 2>/dev/null || true` }] },
{ matcher: 'Bash', hooks: [{ type: 'command', timeout: fastTimeouts.complex, command: `${hookCmd} hooks post-command "$TOOL_INPUT_command" 2>/dev/null || true` }] }
];
settings.hooks.SessionStart = [{
hooks: [
{ type: 'command', timeout: fastTimeouts.session, command: `${hookCmd} hooks session-start 2>/dev/null || true` },
{ type: 'command', timeout: fastTimeouts.complex, command: `${hookCmd} hooks trajectory-begin -c "claude-session" -a "claude" 2>/dev/null || true` }
]
}];
settings.hooks.Stop = [{
hooks: [
{ type: 'command', timeout: fastTimeouts.complex, command: `${hookCmd} hooks trajectory-end --success --quality 0.8 2>/dev/null || true` },
{ type: 'command', timeout: fastTimeouts.complex, command: `${hookCmd} hooks session-end 2>/dev/null || true` }
]
}];
console.log(chalk.blue(` ✓ Core hooks (PreToolUse, PostToolUse, SessionStart, Stop) ${opts.fast ? 'with fast wrapper' : 'with error handling'}`));
// Advanced hooks (unless --minimal)
if (!opts.minimal) {
// Create agentic-flow fast wrapper for background workers
let workersCmd = 'npx agentic-flow@alpha';
if (opts.fast && !isWindows) {
const agenticFastPath = path.join(settingsDir, 'agentic-flow-fast.sh');
const agenticFastContent = `#!/bin/bash
# Fast agentic-flow wrapper - avoids npx overhead
# Usage: .claude/agentic-flow-fast.sh workers <command> [args...]
# Find agentic-flow CLI
if [ -f "$PWD/node_modules/agentic-flow/bin/cli.js" ]; then
exec node "$PWD/node_modules/agentic-flow/bin/cli.js" "$@"
elif [ -f "$PWD/node_modules/.bin/agentic-flow" ]; then
exec "$PWD/node_modules/.bin/agentic-flow" "$@"
elif command -v agentic-flow &> /dev/null; then
exec agentic-flow "$@"
else
exec npx agentic-flow@alpha "$@"
fi
`;
fs.writeFileSync(agenticFastPath, agenticFastContent);
fs.chmodSync(agenticFastPath, '755');
workersCmd = '.claude/agentic-flow-fast.sh';
// Add permission for agentic-flow fast wrapper
if (settings.permissions && settings.permissions.allow) {
if (!settings.permissions.allow.includes('Bash(.claude/agentic-flow-fast.sh:*)')) {
settings.permissions.allow.push('Bash(.claude/agentic-flow-fast.sh:*)');
}
}
console.log(chalk.blue(' ✓ Background workers wrapper created (.claude/agentic-flow-fast.sh)'));
}
// UserPromptSubmit - context suggestions + background workers dispatch
settings.hooks.UserPromptSubmit = [{
hooks: [
{
type: 'command',
timeout: fastTimeouts.complex,
command: `${hookCmd} hooks suggest-context 2>/dev/null || true`
},
{
type: 'command',
timeout: 2000,
command: `${workersCmd} workers dispatch-prompt "$CLAUDE_USER_PROMPT" 2>/dev/null || true`
},
{
type: 'command',
timeout: 1000,
command: `${workersCmd} workers inject-context "$CLAUDE_USER_PROMPT" 2>/dev/null || true`
}
]
}];
console.log(chalk.blue(' ✓ Background workers integration (ultralearn, optimize, audit, map, etc.)'));
// PreCompact - preserve important context before compaction
settings.hooks.PreCompact = [
{
matcher: 'auto',
hooks: [
{ type: 'command', timeout: fastTimeouts.session, command: `${hookCmd} hooks pre-compact --auto 2>/dev/null || true` },
{ type: 'command', timeout: fastTimeouts.session, command: `${hookCmd} hooks compress 2>/dev/null || true` }
]
},
{
matcher: 'manual',
hooks: [{
type: 'command',
timeout: fastTimeouts.session,
command: `${hookCmd} hooks pre-compact 2>/dev/null || true`
}]
}
];
// Notification - track all notifications for learning
settings.hooks.Notification = [{
matcher: '.*',
hooks: [{
type: 'command',
timeout: fastTimeouts.simple,
command: `${hookCmd} hooks track-notification 2>/dev/null || true`
}]
}];
console.log(chalk.blue(` ✓ Advanced hooks (UserPromptSubmit, PreCompact, Notification, Compress)${opts.fast ? ' - fast mode' : ''}`));
// Extended environment variables for new capabilities
settings.env.RUVECTOR_AST_ENABLED = settings.env.RUVECTOR_AST_ENABLED || 'true';
settings.env.RUVECTOR_DIFF_EMBEDDINGS = settings.env.RUVECTOR_DIFF_EMBEDDINGS || 'true';
settings.env.RUVECTOR_COVERAGE_ROUTING = settings.env.RUVECTOR_COVERAGE_ROUTING || 'true';
settings.env.RUVECTOR_GRAPH_ALGORITHMS = settings.env.RUVECTOR_GRAPH_ALGORITHMS || 'true';
settings.env.RUVECTOR_SECURITY_SCAN = settings.env.RUVECTOR_SECURITY_SCAN || 'true';
console.log(chalk.blue(' ✓ Extended capabilities (AST, Diff, Coverage, Graph, Security)'));
}
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
console.log(chalk.green('\n✅ Hooks initialized in .claude/settings.json'));
// Create CLAUDE.md if it doesn't exist (or force)
const claudeMdPath = path.join(process.cwd(), 'CLAUDE.md');
if (opts.claudeMd !== false && (!fs.existsSync(claudeMdPath) || opts.force)) {
const claudeMdContent = `# Claude Code Project Configuration
## RuVector Self-Learning Intelligence v2.0
This project uses RuVector's self-learning intelligence hooks with advanced capabilities:
- **Q-learning** for agent routing optimization
- **Vector memory** with HNSW indexing (150x faster search)
- **AST parsing** for code complexity analysis
- **Diff embeddings** for change classification and risk scoring
- **Coverage routing** for test-aware agent selection
- **Graph algorithms** for code structure analysis
- **Security scanning** for vulnerability detection
- **10 attention mechanisms** including hyperbolic and graph attention
### Active Hooks
| Hook | Trigger | Purpose |
|------|---------|---------|
| **PreToolUse** | Before Edit/Write/Bash | Agent routing, AST analysis, command risk assessment |
| **PostToolUse** | After Edit/Write/Bash | Q-learning update, diff embeddings, outcome tracking |
| **SessionStart** | Conversation begins | Load intelligence state, display learning stats |
| **Stop** | Conversation ends | Save learning data, export metrics |
| **UserPromptSubmit** | User sends message | RAG context suggestions, pattern recommendations |
| **PreCompact** | Before context compaction | Preserve important context and memories |
| **Notification** | Any notification | Track events for learning |
### Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| \`RUVECTOR_INTELLIGENCE_ENABLED\` | \`true\` | Enable/disable intelligence layer |
| \`RUVECTOR_LEARNING_RATE\` | \`0.1\` | Q-learning rate (0.0-1.0) |
| \`RUVECTOR_MEMORY_BACKEND\` | \`rvlite\` | Memory storage backend |
| \`INTELLIGENCE_MODE\` | \`treatment\` | A/B testing mode (treatment/control) |
| \`RUVECTOR_AST_ENABLED\` | \`true\` | Enable AST parsing and complexity analysis |
| \`RUVECTOR_DIFF_EMBEDDINGS\` | \`true\` | Enable diff embeddings and risk scoring |
| \`RUVECTOR_COVERAGE_ROUTING\` | \`true\` | Enable test coverage-aware routing |
| \`RUVECTOR_GRAPH_ALGORITHMS\` | \`true\` | Enable graph algorithms (MinCut, Louvain) |
| \`RUVECTOR_SECURITY_SCAN\` | \`true\` | Enable security vulnerability scanning |
### Core Commands
\`\`\`bash
# Initialize hooks in a project
npx ruvector hooks init
# View learning statistics
npx ruvector hooks stats
# Route a task to best agent
npx ruvector hooks route "implement feature X"
# Enhanced routing with AST/coverage/diff signals
npx ruvector hooks route-enhanced "fix bug" --file src/api.ts
# Store context in vector memory
npx ruvector hooks remember "important context" -t project
# Recall from memory (semantic search)
npx ruvector hooks recall "context query"
\`\`\`
### AST Analysis Commands
\`\`\`bash
# Analyze file structure, symbols, imports, complexity
npx ruvector hooks ast-analyze src/index.ts
# Get complexity metrics for multiple files
npx ruvector hooks ast-complexity src/*.ts --threshold 15
\`\`\`
### Diff & Risk Analysis Commands
\`\`\`bash
# Analyze commit with semantic embeddings and risk scoring
npx ruvector hooks diff-analyze HEAD
# Classify change type (feature, bugfix, refactor, etc.)
npx ruvector hooks diff-classify
# Find similar past commits
npx ruvector hooks diff-similar -k 5
# Get risk score only
npx ruvector hooks diff-analyze --risk-only
\`\`\`
### Coverage & Testing Commands
\`\`\`bash
# Get coverage-aware routing for a file
npx ruvector hooks coverage-route src/api.ts
# Suggest tests for files based on coverage
npx ruvector hooks coverage-suggest src/*.ts
\`\`\`
### Graph Analysis Commands
\`\`\`bash
# Find optimal code boundaries (MinCut algorithm)
npx ruvector hooks graph-mincut src/*.ts
# Detect code communities (Louvain/Spectral clustering)
npx ruvector hooks graph-cluster src/*.ts --method louvain
\`\`\`
### Security & RAG Commands
\`\`\`bash
# Parallel security vulnerability scan
npx ruvector hooks security-scan src/*.ts
# RAG-enhanced context retrieval
npx ruvector hooks rag-context "how does auth work"
# Git churn analysis (hot spots)
npx ruvector hooks git-churn --days 30
\`\`\`
### MCP Tools (via Claude Code)
When using the RuVector MCP server, these tools are available:
| Tool | Description |
|------|-------------|
| \`hooks_stats\` | Get intelligence statistics |
| \`hooks_route\` | Route task to best agent |
| \`hooks_route_enhanced\` | Enhanced routing with AST/coverage signals |
| \`hooks_remember\` / \`hooks_recall\` | Vector memory operations |
| \`hooks_ast_analyze\` | Parse AST and extract symbols |
| \`hooks_ast_complexity\` | Get complexity metrics |
| \`hooks_diff_analyze\` | Analyze changes with embeddings |
| \`hooks_diff_classify\` | Classify change types |
| \`hooks_coverage_route\` | Coverage-aware routing |
| \`hooks_coverage_suggest\` | Suggest needed tests |
| \`hooks_graph_mincut\` | Find code boundaries |
| \`hooks_graph_cluster\` | Detect communities |
| \`hooks_security_scan\` | Security vulnerability scan |
| \`hooks_rag_context\` | RAG context retrieval |
| \`hooks_git_churn\` | Hot spot analysis |
| \`hooks_attention_info\` | Available attention mechanisms |
| \`hooks_gnn_info\` | GNN layer capabilities |
### Attention Mechanisms
RuVector includes 10 attention mechanisms:
1. **DotProductAttention** - Scaled dot-product attention
2. **MultiHeadAttention** - Parallel attention heads
3. **FlashAttention** - Memory-efficient tiled attention
4. **HyperbolicAttention** - Poincaré ball hyperbolic space
5. **LinearAttention** - O(n) linear complexity
6. **MoEAttention** - Mixture-of-Experts sparse attention
7. **GraphRoPeAttention** - Rotary position for graphs
8. **EdgeFeaturedAttention** - Edge-aware graph attention
9. **DualSpaceAttention** - Euclidean + Hyperbolic hybrid
10. **LocalGlobalAttention** - Sliding window + global tokens
### How It Works
1. **Pre-edit hooks** analyze files via AST and suggest agents based on Q-learned patterns
2. **Post-edit hooks** generate diff embeddings to improve future routing
3. **Coverage routing** adjusts agent weights based on test coverage
4. **Graph algorithms** detect code communities for module boundaries
5. **Security scanning** identifies common vulnerability patterns
6. **RAG context** retrieves relevant memories using HNSW search
7. **Attention mechanisms** provide advanced embedding transformations
### Learning Data
Stored in \`.ruvector/intelligence.json\`:
- **Q-table patterns**: State-action values for agent routing
- **Vector memories**: ONNX embeddings with HNSW indexing
- **Trajectories**: SONA trajectory tracking for meta-learning
- **Co-edit patterns**: File relationship graphs
- **Error patterns**: Known issues and suggested fixes
- **Diff embeddings**: Change classification patterns
### Init Options
\`\`\`bash
npx ruvector hooks init # Full configuration with all capabilities
npx ruvector hooks init --minimal # Basic hooks only
npx ruvector hooks init --fast # Use fast local wrapper (20x faster)
npx ruvector hooks init --pretrain # Initialize + pretrain from git history
npx ruvector hooks init --build-agents quality # Generate optimized agents
npx ruvector hooks init --force # Overwrite existing configuration
\`\`\`
---
*Powered by [RuVector](https://github.com/ruvnet/ruvector) self-learning intelligence v2.0*
`;
fs.writeFileSync(claudeMdPath, claudeMdContent);
console.log(chalk.green('✅ CLAUDE.md created in project root'));
} else if (fs.existsSync(claudeMdPath) && !opts.force) {
console.log(chalk.yellow('ℹ️ CLAUDE.md already exists (use --force to overwrite)'));
}
// Update .gitignore (unless --no-gitignore)
if (opts.gitignore !== false) {
const gitignorePath = path.join(process.cwd(), '.gitignore');
const entriesToAdd = ['.ruvector/', '.claude/statusline.sh'];
let gitignoreContent = '';
if (fs.existsSync(gitignorePath)) {
gitignoreContent = fs.readFileSync(gitignorePath, 'utf-8');
}
const linesToAdd = entriesToAdd.filter(entry => !gitignoreContent.includes(entry));
if (linesToAdd.length > 0) {
const newContent = gitignoreContent.trim() + '\n\n# RuVector intelligence data\n' + linesToAdd.join('\n') + '\n';
fs.writeFileSync(gitignorePath, newContent);
console.log(chalk.blue(' ✓ .gitignore updated'));
}
}
// Create .ruvector directory for intelligence data
const ruvectorDir = path.join(process.cwd(), '.ruvector');
if (!fs.existsSync(ruvectorDir)) {
fs.mkdirSync(ruvectorDir, { recursive: true });
console.log(chalk.blue(' ✓ .ruvector/ directory created'));
}
console.log(chalk.green('\n✅ RuVector hooks initialization complete!'));
// Run pretrain if requested
if (opts.pretrain) {
console.log(chalk.yellow('\n📚 Running pretrain to bootstrap intelligence...\n'));
const { execSync } = require('child_process');
try {
execSync('npx ruvector hooks pretrain', { stdio: 'inherit' });
} catch (e) {
console.log(chalk.yellow('⚠️ Pretrain completed with warnings'));
}
}
// Build agents if requested
if (opts.buildAgents) {
const focus = typeof opts.buildAgents === 'string' ? opts.buildAgents : 'quality';
console.log(chalk.yellow(`\n🏗️ Building optimized agents (focus: ${focus})...\n`));
const { execSync } = require('child_process');
try {
execSync(`npx ruvector hooks build-agents --focus ${focus} --include-prompts`, { stdio: 'inherit' });
} catch (e) {
console.log(chalk.yellow('⚠️ Agent build completed with warnings'));
}
}
if (!opts.pretrain && !opts.buildAgents) {
console.log(chalk.dim(' Run `npx ruvector hooks verify` to test the setup'));
console.log(chalk.dim(' Run `npx ruvector hooks pretrain` to bootstrap intelligence'));
console.log(chalk.dim(' Run `npx ruvector hooks build-agents` to generate optimized agents'));
}
});
hooksCmd.command('stats').description('Show intelligence statistics').action(() => {
const intel = new Intelligence();
const stats = intel.stats();
const swarm = intel.swarmStats();
console.log(chalk.bold.cyan('\n🧠 RuVector Intelligence Stats\n'));
console.log(` ${chalk.green(stats.total_patterns)} Q-learning patterns`);
console.log(` ${chalk.green(stats.total_memories)} vector memories`);
console.log(` ${chalk.green(stats.total_trajectories)} learning trajectories`);
console.log(` ${chalk.green(stats.total_errors)} error patterns\n`);
console.log(chalk.bold('Swarm Status:'));
console.log(` ${chalk.cyan(swarm.agents)} agents registered`);
console.log(` ${chalk.cyan(swarm.edges)} coordination edges`);
});
hooksCmd.command('session-start').description('Session start hook').option('--resume', 'Resume previous session').action(() => {
const intel = new Intelligence();
intel.sessionStart();
intel.save();
console.log(chalk.bold.cyan('🧠 RuVector Intelligence Layer Active'));
console.log('⚡ Intelligence guides: agent routing, error fixes, file sequences');
});
hooksCmd.command('session-end').description('Session end hook').option('--export-metrics', 'Export metrics').action((opts) => {
const intel = new Intelligence();
const sessionInfo = intel.sessionEnd();
intel.save();
console.log('📊 Session ended. Learning data saved.');
if (opts.exportMetrics) console.log(JSON.stringify({ duration_seconds: sessionInfo.duration, actions_recorded: sessionInfo.actions }));
});
hooksCmd.command('pre-edit').description('Pre-edit intelligence').argument('<file>', 'File path').action((file) => {
const intel = new Intelligence();
const fileName = path.basename(file);
const crateMatch = file.match(/crates\/([^/]+)/);
const crate = crateMatch?.[1];
const { agent, confidence, reason } = intel.route(`edit ${fileName}`, file, crate, 'edit');
console.log(chalk.bold('🧠 Intelligence Analysis:'));
console.log(` 📁 ${chalk.cyan(crate ?? 'project')}/${fileName}`);
console.log(` 🤖 Recommended: ${chalk.green.bold(agent)} (${(confidence * 100).toFixed(0)}% confidence)`);
if (reason) console.log(` → ${chalk.dim(reason)}`);
const nextFiles = intel.suggestNext(file, 3);
if (nextFiles.length > 0) {
console.log(' 📎 Likely next files:');
nextFiles.forEach(n => console.log(` - ${n.file} (${n.score} edits)`));
}
});
hooksCmd.command('post-edit').description('Post-edit learning').argument('<file>', 'File path').option('--success', 'Edit succeeded').option('--error <msg>', 'Error message').action((file, opts) => {
const intel = new Intelligence();
const success = opts.error ? false : (opts.success ?? true);
const ext = path.extname(file).slice(1);
const crateMatch = file.match(/crates\/([^/]+)/);
const crate = crateMatch?.[1] ?? 'project';
const state = `edit_${ext}_in_${crate}`;
const lastFile = intel.getLastEditedFile();
if (lastFile && lastFile !== file) intel.recordFileSequence(lastFile, file);
intel.learn(state, success ? 'successful-edit' : 'failed-edit', success ? 'completed' : 'failed', success ? 1.0 : -0.5);
intel.remember('edit', `${success ? 'successful' : 'failed'} edit of ${ext} in ${crate}`);
intel.save();
console.log(`📊 Learning recorded: ${success ? '✅' : '❌'} ${path.basename(file)}`);
const test = intel.shouldTest(file);
if (test.suggest) console.log(` 🧪 Consider: ${chalk.cyan(test.command)}`);
});
hooksCmd.command('pre-command').description('Pre-command intelligence').argument('<command...>', 'Command').action((command) => {
const intel = new Intelligence();
const cmd = command.join(' ');
const classification = intel.classifyCommand(cmd);
console.log(chalk.bold('🧠 Command Analysis:'));
console.log(` 📦 Category: ${chalk.cyan(classification.category)}`);
console.log(` 🏷️ Type: ${classification.subcategory}`);
if (classification.risk === 'high') console.log(` ⚠️ Risk: ${chalk.red('HIGH')} - Review carefully`);
else if (classification.risk === 'medium') console.log(` ⚡ Risk: ${chalk.yellow('MEDIUM')}`);
else console.log(` ✅ Risk: ${chalk.green('LOW')}`);
});
hooksCmd.command('post-command').description('Post-command learning').argument('<command...>', 'Command').option('--success', 'Success').option('--error <msg>', 'Error message').action((command, opts) => {
const intel = new Intelligence();
const cmd = command.join(' ');
const success = opts.error ? false : (opts.success ?? true);
const classification = intel.classifyCommand(cmd);
intel.learn(`cmd_${classification.category}_${classification.subcategory}`, success ? 'success' : 'failure', success ? 'completed' : 'failed', success ? 0.8 : -0.3);
intel.remember('command', `${cmd} ${success ? 'succeeded' : 'failed'}`);
intel.save();
console.log(`📊 Command ${success ? '✅' : '❌'} recorded`);
});
hooksCmd.command('route').description('Route task to agent').argument('<task...>', 'Task').option('--file <file>', 'File').option('--crate <crate>', 'Crate').action((task, opts) => {
const intel = new Intelligence();
const result = intel.route(task.join(' '), opts.file, opts.crate);
console.log(JSON.stringify({ task: task.join(' '), recommended: result.agent, confidence: result.confidence, reasoning: result.reason }, null, 2));
});
hooksCmd.command('suggest-context').description('Suggest relevant context').action(() => {
const intel = new Intelligence();
const stats = intel.stats();
console.log(`RuVector Intelligence: ${stats.total_patterns} learned patterns, ${stats.total_errors} error fixes available. Use 'ruvector hooks route' for agent suggestions.`);
});
hooksCmd.command('remember').description('Store in memory').requiredOption('-t, --type <type>', 'Memory type').option('--silent', 'Suppress output').option('--semantic', 'Use ONNX semantic embeddings (slower, better quality)').argument('<content...>', 'Content').action(async (content, opts) => {
const intel = new Intelligence();
let id;
if (opts.semantic) {
// Use async ONNX embedding
id = await intel.rememberAsync(opts.type, content.join(' '));
} else {
id = intel.remember(opts.type, content.join(' '));
}
intel.save();
if (!opts.silent) {
console.log(JSON.stringify({ success: true, id, semantic: !!opts.semantic }));
}
});
hooksCmd.command('recall').description('Search memory').argument('<query...>', 'Query').option('-k, --top-k <n>', 'Results', '5').option('--semantic', 'Use ONNX semantic search (slower, better quality)').action(async (query, opts) => {
const intel = new Intelligence();
let results;
if (opts.semantic) {
results = await intel.recallAsync(query.join(' '), parseInt(opts.topK));
} else {
results = intel.recall(query.join(' '), parseInt(opts.topK));
}
console.log(JSON.stringify({ query: query.join(' '), semantic: !!opts.semantic, results: results.map(r => ({ type: r.memory_type || 'unknown', content: (r.content || '').slice(0, 200), timestamp: r.timestamp || '', score: r.score })) }, null, 2));
});
hooksCmd.command('pre-compact').description('Pre-compact hook').option('--auto', 'Auto mode').action(() => {
const intel = new Intelligence();
intel.save();
console.log('🗜️ Pre-compact: State saved');
});
hooksCmd.command('swarm-recommend').description('Recommend agent for task').argument('<task-type>', 'Task type').action((taskType) => {
console.log(JSON.stringify({ task_type: taskType, recommended: 'coder', type: 'default', score: 0.8 }));
});
hooksCmd.command('async-agent').description('Async agent hook').option('--action <action>', 'Action').option('--agent-id <id>', 'Agent ID').option('--task <task>', 'Task').action((opts) => {
console.log(JSON.stringify({ action: opts.action, agent_id: opts.agentId, status: 'ok' }));
});
hooksCmd.command('lsp-diagnostic').description('LSP diagnostic hook').option('--file <file>', 'File').option('--severity <sev>', 'Severity').option('--message <msg>', 'Message').action((opts) => {
console.log(JSON.stringify({ file: opts.file, severity: opts.severity, action: 'logged' }));
});
hooksCmd.command('track-notification').description('Track notification').action(() => {
console.log(JSON.stringify({ tracked: true }));
});
// Trajectory tracking commands
hooksCmd.command('trajectory-begin')
.description('Begin tracking a new execution trajectory')
.requiredOption('-c, --context <context>', 'Task or operation context')
.option('-a, --agent <agent>', 'Agent performing the task', 'unknown')
.action((opts) => {
const intel = new Intelligence({ skipEngine: true }); // Fast mode - no engine needed
const trajId = `traj_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
if (!intel.data.activeTrajectories) intel.data.activeTrajectories = {};
intel.data.activeTrajectories[trajId] = {
id: trajId,
context: opts.context,
agent: opts.agent,
steps: [],
startTime: Date.now()
};
intel.save();
console.log(JSON.stringify({ success: true, trajectory_id: trajId, context: opts.context, agent: opts.agent }));
});
hooksCmd.command('trajectory-step')
.description('Add a step to the current trajectory')
.requiredOption('-a, --action <action>', 'Action taken')
.option('-r, --result <result>', 'Result of action')
.option('--reward <reward>', 'Reward signal (0-1)', '0.5')
.action((opts) => {
const intel = new Intelligence({ skipEngine: true }); // Fast mode
const trajectories = intel.data.activeTrajectories || {};
const trajIds = Object.keys(trajectories);
if (trajIds.length === 0) {
console.log(JSON.stringify({ success: false, error: 'No active trajectory' }));
return;
}
const latestTrajId = trajIds[trajIds.length - 1];
trajectories[latestTrajId].steps.push({
action: opts.action,
result: opts.result || '',
reward: parseFloat(opts.reward),
time: Date.now()
});
intel.save();
console.log(JSON.stringify({ success: true, trajectory_id: latestTrajId, step: trajectories[latestTrajId].steps.length }));
});
hooksCmd.command('trajectory-end')
.description('End the current trajectory with a quality score')
.option('--success', 'Task succeeded')
.option('--quality <quality>', 'Quality score (0-1)', '0.5')
.action((opts) => {
const intel = new Intelligence({ skipEngine: true }); // Fast mode
const trajectories = intel.data.activeTrajectories || {};
const trajIds = Object.keys(trajectories);
if (trajIds.length === 0) {
console.log(JSON.stringify({ success: false, error: 'No active trajectory' }));
return;
}
const latestTrajId = trajIds[trajIds.length - 1];
const traj = trajectories[latestTrajId];
const quality = opts.success ? 0.8 : parseFloat(opts.quality);
traj.endTime = Date.now();
traj.quality = quality;
traj.success = opts.success || false;
if (!intel.data.trajectories) intel.data.trajectories = [];
intel.data.trajectories.push(traj);
delete trajectories[latestTrajId];
intel.save();
console.log(JSON.stringify({
success: true,
trajectory_id: latestTrajId,
steps: traj.steps.length,
duration_ms: traj.endTime - traj.startTime,
quality
}));
});
// Co-edit pattern commands
hooksCmd.command('coedit-record')
.description('Record co-edit pattern (files edited together)')
.requiredOption('-p, --primary <file>', 'Primary file being edited')
.requiredOption('-r, --related <files...>', 'Related files edited together')
.action((opts) => {
const intel = new Intelligence({ skipEngine: true }); // Fast mode
if (!intel.data.coEditPatterns) intel.data.coEditPatterns = {};
if (!intel.data.coEditPatterns[opts.primary]) intel.data.coEditPatterns[opts.primary] = {};
for (const related of opts.related) {
intel.data.coEditPatterns[opts.primary][related] = (intel.data.coEditPatterns[opts.primary][related] || 0) + 1;
}
intel.save();
console.log(JSON.stringify({ success: true, primary_file: opts.primary, related_count: opts.related.length }));
});
hooksCmd.command('coedit-suggest')
.description('Get suggested related files based on co-edit patterns')
.requiredOption('-f, --file <file>', 'Current file')
.option('-k, --top-k <n>', 'Number of suggestions', '5')
.action((opts) => {
const intel = new Intelligence({ skipEngine: true }); // Fast mode
let suggestions = [];
if (intel.data.coEditPatterns && intel.data.coEditPatterns[opts.file]) {
suggestions = Object.entries(intel.data.coEditPatterns[opts.file])
.sort((a, b) => b[1] - a[1])
.slice(0, parseInt(opts.topK))
.map(([f, count]) => ({ file: f, count, confidence: Math.min(count / 10, 1) }));
}
console.log(JSON.stringify({ success: true, file: opts.file, suggestions }));
});
// Error pattern commands
hooksCmd.command('error-record')
.description('Record an error and its fix for learning')
.requiredOption('-e, --error <error>', 'Error message or code')
.requiredOption('-x, --fix <fix>', 'Fix that resolved the error')
.option('-f, --file <file>', 'File where error occurred')
.action((opts) => {
const intel = new Intelligence({ skipEngine: true }); // Fast mode
if (!intel.data.errors) intel.data.errors = {};
if (!intel.data.errors[opts.error]) intel.data.errors[opts.error] = [];
intel.data.errors[opts.error].push({ fix: opts.fix, file: opts.file || '', recorded: Date.now() });
intel.save();
console.log(JSON.stringify({ success: true, error: opts.error.substring(0, 50), fixes_recorded: intel.data.errors[opts.error].length }));
});
hooksCmd.command('error-suggest')
.description('Get suggested fixes for an error based on learned patterns')
.requiredOption('-e, --error <error>', 'Error message or code')
.action((opts) => {
const intel = new Intelligence({ skipEngine: true }); // Fast mode
let suggestions = [];
if (intel.data.errors) {
for (const [errKey, fixes] of Object.entries(intel.data.errors)) {
if (opts.error.includes(errKey) || errKey.includes(opts.error)) {
suggestions.push(...fixes.map(f => f.fix));
}
}
}
console.log(JSON.stringify({ success: true, error: opts.error.substring(0, 50), suggestions: [...new Set(suggestions)].slice(0, 5) }));
});
// Force learning command
hooksCmd.command('force-learn')
.description('Force an immediate learning cycle')
.action(() => {
const intel = new Intelligence({ skipEngine: true }); // Fast mode
intel.tick();
console.log(JSON.stringify({ success: true, result: 'Learning cycle triggered', stats: intel.stats() }));
});
// ============================================
// NEW CAPABILITY COMMANDS (AST, Diff, Coverage, Graph, Security, RAG)
// ============================================
// Lazy load new modules
let ASTParser, DiffEmbeddings, CoverageRouter, GraphAlgorithms, ExtendedWorkerPool;
let newModulesLoaded = false;
function loadNewModules() {
if (newModulesLoaded) return true;
try {
const core = require('../dist/core/index.js');
// CodeParser is exported as both CodeParser and ASTParser
ASTParser = core.CodeParser || core.ASTParser;
DiffEmbeddings = core.default?.parseDiff ? core : require('../dist/core/diff-embeddings.js');
CoverageRouter = core.default?.parseIstanbulCoverage ? core : require('../dist/core/coverage-router.js');
GraphAlgorithms = core.default?.minCut ? core : require('../dist/core/graph-algorithms.js');
ExtendedWorkerPool = core.ExtendedWorkerPool;
newModulesLoaded = true;
return true;
} catch (e) {
console.error('loadNewModules error:', e.message);
return false;
}
}
// AST Analysis Commands
hooksCmd.command('ast-analyze')
.description('Parse file AST and extract symbols, imports, complexity')
.argument('<file>', 'File path to analyze')
.option('--json', 'Output as JSON')
.option('--symbols', 'Show only symbols')
.option('--imports', 'Show only imports')
.action(async (file, opts) => {
if (!loadNewModules() || !ASTParser) {
console.log(JSON.stringify({ success: false, error: 'AST parser not available. Run npm run build.' }));
return;
}
try {
const parser = new ASTParser();
// CodeParser uses analyze() which returns FileAnalysis
const analysis = await parser.analyze(file);
// Get symbols list
const symbols = await parser.getSymbols(file);
if (opts.json) {
console.log(JSON.stringify({
success: true,
file,
language: analysis.language,
symbols: symbols.map(s => ({ name: s })),
imports: analysis.imports,
complexity: { cyclomatic: analysis.complexity, lines: analysis.lines },
functions: analysis.functions.length,
classes: analysis.classes.length
}));
} else if (opts.symbols) {
console.log(chalk.bold.cyan(`\n📊 Symbols in ${path.basename(file)}:\n`));
analysis.functions.forEach(f => console.log(` function: ${f.name} (line ${f.startLine})`));
analysis.classes.forEach(c => console.log(` class: ${c.name} (line ${c.startLine})`));
analysis.types.forEach(t => console.log(` type: ${t}`));
} else if (opts.imports) {
console.log(chalk.bold.cyan(`\n📦 Imports in ${path.basename(file)}:\n`));
analysis.imports.forEach(i => console.log(` ${i.source} (${i.type})`));
} else {
console.log(chalk.bold.cyan(`\n📊 AST Analysis: ${path.basename(file)}\n`));
console.log(` Language: ${analysis.language}`);
console.log(` Functions: ${analysis.functions.length}`);
console.log(` Classes: ${analysis.classes.length}`);
console.log(` Imports: ${analysis.imports.length}`);
console.log(` Complexity: ${analysis.complexity}`);
console.log(` Lines: ${analysis.lines}`);
console.log(` Parse time: ${analysis.parseTime.toFixed(2)}ms`);
}
} catch (e) {
console.log(JSON.stringify({ success: false, error: e.message }));
}
});
hooksCmd.command('ast-complexity')
.description('Get complexity metrics for files')
.argument('<files...>', 'Files to analyze')
.option('--threshold <n>', 'Warn if complexity exceeds threshold', '10')
.action(async (files, opts) => {
if (!loadNewModules() || !ASTParser) {
console.log(JSON.stringify({ success: false, error: 'AST parser not available' }));
return;
}
const parser = new ASTParser();
const threshold = parseInt(opts.threshold);
const results = [];
for (const file of files) {
try {
if (!fs.existsSync(file)) continue;
const analysis = await parser.analyze(file);
const warning = analysis.complexity > threshold;
results.push({
file,
cyclomatic: analysis.complexity,
lines: analysis.lines,
functions: analysis.functions.length,
classes: analysis.classes.length,
warning
});
} catch (e) {
results.push({ file, error: e.message });
}
}
console.log(JSON.stringify({ success: true, results, threshold }));
});
// Diff Embedding Commands
hooksCmd.command('diff-analyze')
.description('Analyze git diff with semantic embeddings and risk scoring')
.argument('[commit]', 'Commit hash (defaults to staged changes)')
.option('--json', 'Output as JSON')
.option('--risk-only', 'Show only risk score')
.action(async (commit, opts) => {
if (!loadNewModules()) {
console.log(JSON.stringify({ success: false, error: 'Diff embeddings not available' }));
return;
}
try {
const diffMod = require('../dist/core/diff-embeddings.js');
let analysis;
if (commit) {
analysis = await diffMod.analyzeCommit(commit);
} else {
const stagedDiff = diffMod.getStagedDiff();
if (!stagedDiff) {
console.log(JSON.stringify({ success: false, error: 'No staged changes' }));
return;
}
const hunks = diffMod.parseDiff(stagedDiff);
const files = [...new Set(hunks.map(h => h.file))];
analysis = {
hash: 'staged',
message: 'Staged changes',
files: await Promise.all(files.map(f => diffMod.analyzeFileDiff(f, stagedDiff))),
totalAdditions: hunks.reduce((s, h) => s + h.additions.length, 0),
totalDeletions: hunks.reduce((s, h) => s + h.deletions.length, 0),
riskScore: 0
};
analysis.riskScore = analysis.files.reduce((s, f) => s + f.riskScore, 0) / Math.max(1, analysis.files.length);
}
if (opts.json) {
console.log(JSON.stringify({ success: true, ...analysis }));
} else if (opts.riskOnly) {
const risk = analysis.riskScore;
const level = risk > 0.7 ? 'HIGH' : risk > 0.4 ? 'MEDIUM' : 'LOW';
console.log(JSON.stringify({ success: true, riskScore: risk, riskLevel: level }));
} else {
console.log(chalk.bold.cyan(`\n📊 Diff Analysis: ${analysis.hash}\n`));
console.log(` Message: ${analysis.message || 'N/A'}`);
console.log(` Files: ${analysis.files.length}`);
console.log(` Changes: +${analysis.totalAdditions} -${analysis.totalDeletions}`);
const risk = analysis.riskScore;
const riskColor = risk > 0.7 ? chalk.red : risk > 0.4 ? chalk.yellow : chalk.green;
console.log(` Risk: ${riskColor((risk * 100).toFixed(0) + '%')}`);
analysis.files.forEach(f => {
console.log(` ${f.file}: ${f.category} (+${f.totalAdditions}/-${f.totalDeletions})`);
});
}
} catch (e) {
console.log(JSON.stringify({ success: false, error: e.message }));
}
});
hooksCmd.command('diff-classify')
.description('Classify a change type (feature, bugfix, refactor, etc.)')
.argument('[commit]', 'Commit hash')
.action(async (commit) => {
if (!loadNewModules()) {
console.log(JSON.stringify({ success: false, error: 'Diff embeddings not available' }));
return;
}
try {
const diffMod = require('../dist/core/diff-embeddings.js');
const analysis = await diffMod.analyzeCommit(commit || 'HEAD');
const categories = {};
analysis.files.forEach(f => {
categories[f.category] = (categories[f.category] || 0) + 1;
});
const primary = Object.entries(categories).sort((a, b) => b[1] - a[1])[0];
console.log(JSON.stringify({
success: true,
commit: analysis.hash,
message: analysis.message,
primaryCategory: primary ? primary[0] : 'unknown',
categories
}));
} catch (e) {
console.log(JSON.stringify({ success: false, error: e.message }));
}
});
hooksCmd.command('diff-similar')
.description('Find similar past commits based on diff embeddings')
.option('-k, --top-k <n>', 'Number of results', '5')
.option('--commits <n>', 'How many recent commits to search', '50')
.action(async (opts) => {
if (!loadNewModules()) {
console.log(JSON.stringify({ success: false, error: 'Diff embeddings not available' }));
return;
}
try {
const diffMod = require('../dist/core/diff-embeddings.js');
const stagedDiff = diffMod.getStagedDiff() || diffMod.getUnstagedDiff();
if (!stagedDiff) {
console.log(JSON.stringify({ success: false, error: 'No current changes to compare' }));
return;
}
const similar = await diffMod.findSimilarCommits(stagedDiff, parseInt(opts.commits), parseInt(opts.topK));
console.log(JSON.stringify({ success: true, similar }));
} catch (e) {
console.log(JSON.stringify({ success: false, error: e.message }));
}
});
// Coverage Routing Commands
hooksCmd.command('coverage-route')
.description('Get coverage-aware agent routing for a file')
.argument('<file>', 'File to analyze')
.action((file) => {
if (!loadNewModules()) {
console.log(JSON.stringify({ success: false, error: 'Coverage router not available' }));
return;
}
try {
const covMod = require('../dist/core/coverage-router.js');
const reportPath = covMod.findCoverageReport();
const summary = reportPath ? covMod.parseIstanbulCoverage(reportPath) : null;
const routing = covMod.shouldRouteToTester(file, summary);
const weights = covMod.getCoverageRoutingWeight(file, summary);
console.log(JSON.stringify({
success: true,
file,
coverageReport: reportPath || 'not found',
routeToTester: routing.route,
reason: routing.reason,
coverage: routing.coverage,
agentWeights: weights
}));
} catch (e) {
console.log(JSON.stringify({ success: false, error: e.message }));
}
});
hooksCmd.command('coverage-suggest')
.description('Suggest tests for files based on coverage data')
.argument('<files...>', 'Files to analyze')
.action((files) => {
if (!loadNewModules()) {
console.log(JSON.stringify({ success: false, error: 'Coverage router not available' }));
return;
}
try {
const covMod = require('../dist/core/coverage-router.js');
const suggestions = covMod.suggestTests(files);
console.log(JSON.stringify({ success: true, suggestions }));
} catch (e) {
console.log(JSON.stringify({ success: false, error: e.message }));
}
});
// Graph Algorithm Commands
hooksCmd.command('graph-mincut')
.description('Find optimal code boundaries using MinCut algorithm')
.argument('<files...>', 'Files to analyze')
.option('--partitions <n>', 'Number of partitions', '2')
.action(async (files, opts) => {
if (!loadNewModules()) {
console.log(JSON.stringify({ success: false, error: 'Graph algorithms not available' }));
return;
}
try {
const graphMod = require('../dist/core/graph-algorithms.js');
// Build dependency graph from files
const nodes = files.map(f => path.basename(f, path.extname(f)));
const edges = [];
// Simple edge detection based on imports
for (const file of files) {
if (!fs.existsSync(file)) continue;
const content = fs.readFileSync(file, 'utf-8');
const imports = content.match(/from ['"]\.\/([^'"]+)['"]/g) || [];
imports.forEach(imp => {
const target = imp.match(/from ['"]\.\/([^'"]+)['"]/)?.[1];
if (target && nodes.includes(target)) {
edges.push({ source: path.basename(file, path.extname(file)), target, weight: 1 });
}
});
}
const result = graphMod.minCut(nodes, edges);
console.log(JSON.stringify({ success: true, nodes: nodes.length, edges: edges.length, ...result }));
} catch (e) {
console.log(JSON.stringify({ success: false, error: e.message }));
}
});
hooksCmd.command('graph-cluster')
.description('Detect code communities using spectral/Louvain clustering')
.argument('<files...>', 'Files to analyze')
.option('--method <type>', 'Clustering method: spectral, louvain', 'louvain')
.option('--clusters <n>', 'Number of clusters (spectral only)', '3')
.action(async (files, opts) => {
if (!loadNewModules()) {
console.log(JSON.stringify({ success: false, error: 'Graph algorithms not available' }));
return;
}
try {
const graphMod = require('../dist/core/graph-algorithms.js');
const nodes = files.map(f => path.basename(f, path.extname(f)));
const edges = [];
for (const file of files) {
if (!fs.existsSync(file)) continue;
const content = fs.readFileSync(file, 'utf-8');
const imports = content.match(/from ['"]\.\/([^'"]+)['"]/g) || [];
imports.forEach(imp => {
const target = imp.match(/from ['"]\.\/([^'"]+)['"]/)?.[1];
if (target && nodes.includes(target)) {
edges.push({ source: path.basename(file, path.extname(file)), target, weight: 1 });
}
});
}
let result;
if (opts.method === 'spectral') {
result = graphMod.spectralClustering(nodes, edges, parseInt(opts.clusters));
} else {
result = graphMod.louvainCommunities(nodes, edges);
}
console.log(JSON.stringify({ success: true, method: opts.method, ...result }));
} catch (e) {
console.log(JSON.stringify({ success: false, error: e.message }));
}
});
// Security Scan Command
hooksCmd.command('security-scan')
.description('Parallel security vulnerability scan')
.argument('<files...>', 'Files to scan')
.option('--json', 'Output as JSON')
.action(async (files, opts) => {
if (!loadNewModules() || !ExtendedWorkerPool) {
// Fallback to basic pattern matching
const patterns = [
{ pattern: /eval\s*\(/g, severity: 'high', message: 'eval() usage detected' },
{ pattern: /innerHTML\s*=/g, severity: 'medium', message: 'innerHTML assignment (XSS risk)' },
{ pattern: /document\.write/g, severity: 'medium', message: 'document.write usage' },
{ pattern: /password\s*=\s*['"][^'"]+['"]/gi, severity: 'critical', message: 'Hardcoded password' },
{ pattern: /api[_-]?key\s*=\s*['"][^'"]+['"]/gi, severity: 'critical', message: 'Hardcoded API key' },
{ pattern: /exec\s*\(/g, severity: 'high', message: 'exec() usage (command injection risk)' },
{ pattern: /dangerouslySetInnerHTML/g, severity: 'medium', message: 'React dangerouslySetInnerHTML' },
{ pattern: /SELECT.*FROM.*WHERE.*\+/gi, severity: 'high', message: 'SQL injection risk' },
];
const findings = [];
for (const file of files) {
if (!fs.existsSync(file)) continue;
try {
const content = fs.readFileSync(file, 'utf-8');
const lines = content.split('\n');
patterns.forEach(p => {
let match;
lines.forEach((line, idx) => {
if (p.pattern.test(line)) {
findings.push({ file, line: idx + 1, severity: p.severity, message: p.message });
}
p.pattern.lastIndex = 0;
});
});
} catch (e) {}
}
console.log(JSON.stringify({ success: true, findings, scanned: files.length }));
return;
}
// Use parallel worker if available
try {
const pool = new ExtendedWorkerPool();
const results = await pool.securityScan(files);
console.log(JSON.stringify({ success: true, ...results }));
} catch (e) {
console.log(JSON.stringify({ success: false, error: e.message }));
}
});
// RAG Context Command
hooksCmd.command('rag-context')
.description('Get RAG-enhanced context for a query')
.argument('<query...>', 'Query for context')
.option('-k, --top-k <n>', 'Number of results', '5')
.option('--rerank', 'Rerank results by relevance')
.action(async (query, opts) => {
const intel = new Intelligence();
const queryStr = query.join(' ');
// Use async recall with engine (VectorDB + HNSW)
const memories = await intel.recallAsync(queryStr, parseInt(opts.topK));
// Rerank if requested
let results = memories;
if (opts.rerank && ExtendedWorkerPool) {
try {
const pool = new ExtendedWorkerPool();
results = await pool.rankContext(queryStr, memories.map(m => m.content || m));
} catch (e) {}
}
console.log(JSON.stringify({ success: true, query: queryStr, results }));
});
// Git Churn Analysis Command
hooksCmd.command('git-churn')
.description('Analyze git churn to find hot spots')
.option('--days <n>', 'Number of days to analyze', '30')
.option('--top <n>', 'Top N files', '10')
.action((opts) => {
try {
const { execSync } = require('child_process');
const since = new Date(Date.now() - parseInt(opts.days) * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
const log = execSync(`git log --since="${since}" --name-only --format="" 2>/dev/null`, { encoding: 'utf-8' });
const files = log.trim().split('\n').filter(Boolean);
const counts = {};
files.forEach(f => { counts[f] = (counts[f] || 0) + 1; });
const sorted = Object.entries(counts).sort((a, b) => b[1] - a[1]).slice(0, parseInt(opts.top));
const hotSpots = sorted.map(([file, count]) => ({ file, changes: count }));
console.log(JSON.stringify({ success: true, days: parseInt(opts.days), hotSpots }));
} catch (e) {
console.log(JSON.stringify({ success: false, error: e.message }));
}
});
// Enhanced route command that uses new capabilities
hooksCmd.command('route-enhanced')
.description('Enhanced routing using AST, coverage, and diff analysis')
.argument('<task...>', 'Task description')
.option('--file <file>', 'File context')
.action(async (task, opts) => {
const intel = new Intelligence();
const taskStr = task.join(' ');
// Base routing
const baseRoute = await intel.routeAsync(taskStr, opts.file, null, 'edit');
// Enhance with coverage if available
let coverageWeight = null;
if (opts.file && loadNewModules()) {
try {
const covMod = require('../dist/core/coverage-router.js');
const reportPath = covMod.findCoverageReport();
if (reportPath) {
coverageWeight = covMod.getCoverageRoutingWeight(opts.file);
}
} catch (e) {}
}
// Enhance with AST complexity if available
let complexity = null;
if (opts.file && loadNewModules() && ASTParser) {
try {
const parser = new ASTParser();
const code = fs.readFileSync(opts.file, 'utf-8');
const ext = path.extname(opts.file).slice(1);
const result = parser.parse(code, ext);
complexity = parser.calculateComplexity(result);
} catch (e) {}
}
// Adjust routing based on signals
let finalAgent = baseRoute.agent;
let adjustedConfidence = baseRoute.confidence;
const signals = [];
if (coverageWeight && coverageWeight.tester > 0.4) {
signals.push('low coverage detected');
if (coverageWeight.tester > adjustedConfidence * 0.5) {
finalAgent = 'tester';
adjustedConfidence = coverageWeight.tester;
}
}
if (complexity && complexity.cyclomatic > 15) {
signals.push('high complexity detected');
if (finalAgent === 'coder') {
finalAgent = 'reviewer';
adjustedConfidence = Math.max(adjustedConfidence, 0.7);
}
}
console.log(JSON.stringify({
success: true,
agent: finalAgent,
confidence: adjustedConfidence,
reason: baseRoute.reason,
signals,
coverageWeight,
complexity
}));
});
// ============================================
// LEARNING & COMPRESSION COMMANDS (v2.1)
// ============================================
let TensorCompressClass = null;
let LearningEngineClass = null;
function loadLearningModules() {
if (LearningEngineClass) return true;
try {
const core = require('../dist/core/index.js');
TensorCompressClass = core.TensorCompress;
LearningEngineClass = core.LearningEngine;
return true;
} catch (e) {
return false;
}
}
// Learning algorithm configuration
hooksCmd.command('learning-config')
.description('Configure learning algorithms for different tasks')
.option('-t, --task <type>', 'Task type (agent-routing, error-avoidance, confidence-scoring, trajectory-learning, context-ranking, memory-recall)')
.option('-a, --algorithm <alg>', 'Algorithm (q-learning, sarsa, double-q, actor-critic, ppo, decision-transformer, monte-carlo, td-lambda, dqn)')
.option('-l, --learning-rate <rate>', 'Learning rate (0.0-1.0)', parseFloat)
.option('-g, --gamma <gamma>', 'Discount factor (0.0-1.0)', parseFloat)
.option('-e, --epsilon <epsilon>', 'Exploration rate (0.0-1.0)', parseFloat)
.option('--lambda <lambda>', 'Lambda for TD(λ)', parseFloat)
.option('--list', 'List all algorithms and their descriptions')
.option('--show', 'Show current configuration')
.action(async (opts) => {
if (!loadLearningModules()) {
console.log(JSON.stringify({ success: false, error: 'Learning modules not available. Run npm run build.' }));
return;
}
if (opts.list) {
const algorithms = LearningEngineClass.getAlgorithms();
console.log(JSON.stringify({
success: true,
algorithms: algorithms.map(a => ({
name: a.algorithm,
description: a.description,
bestFor: a.bestFor
}))
}));
return;
}
// Load existing intelligence data
const dataPath = path.join(process.cwd(), '.ruvector', 'intelligence.json');
let data = {};
try {
if (fs.existsSync(dataPath)) {
data = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
}
} catch (e) {}
const engine = new LearningEngineClass();
if (data.learning) {
engine.import(data.learning);
}
if (opts.show) {
const tasks = ['agent-routing', 'error-avoidance', 'confidence-scoring', 'trajectory-learning', 'context-ranking', 'memory-recall'];
const configs = {};
for (const task of tasks) {
configs[task] = engine.getConfig(task);
}
console.log(JSON.stringify({ success: true, configs }));
return;
}
if (!opts.task) {
console.log(JSON.stringify({ success: false, error: 'Specify --task or use --list/--show' }));
return;
}
const config = {};
if (opts.algorithm) config.algorithm = opts.algorithm;
if (opts.learningRate !== undefined) config.learningRate = opts.learningRate;
if (opts.gamma !== undefined) config.discountFactor = opts.gamma;
if (opts.epsilon !== undefined) config.epsilon = opts.epsilon;
if (opts.lambda !== undefined) config.lambda = opts.lambda;
engine.configure(opts.task, config);
// Save
data.learning = engine.export();
fs.mkdirSync(path.dirname(dataPath), { recursive: true });
fs.writeFileSync(dataPath, JSON.stringify(data, null, 2));
console.log(JSON.stringify({
success: true,
task: opts.task,
config: engine.getConfig(opts.task)
}));
});
// Learning statistics
hooksCmd.command('learning-stats')
.description('Show learning algorithm statistics and performance')
.option('--json', 'Output as JSON')
.action(async (opts) => {
if (!loadLearningModules()) {
console.log(JSON.stringify({ success: false, error: 'Learning modules not available' }));
return;
}
const dataPath = path.join(process.cwd(), '.ruvector', 'intelligence.json');
let data = {};
try {
if (fs.existsSync(dataPath)) {
data = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
}
} catch (e) {}
const engine = new LearningEngineClass();
if (data.learning) {
engine.import(data.learning);
}
const summary = engine.getStatsSummary();
if (opts.json) {
console.log(JSON.stringify({ success: true, ...summary }));
} else {
console.log(chalk.bold.cyan('\n📊 Learning Statistics\n'));
console.log(` Best Algorithm: ${chalk.green(summary.bestAlgorithm)}`);
console.log(` Total Updates: ${summary.totalUpdates}`);
console.log(` Avg Reward: ${summary.avgReward.toFixed(4)}`);
if (summary.algorithms.length > 0) {
console.log(chalk.bold('\n Algorithm Performance:'));
for (const alg of summary.algorithms) {
console.log(` ${alg.algorithm.padEnd(20)} updates: ${String(alg.updates).padStart(6)} avgReward: ${alg.avgReward.toFixed(3).padStart(8)} convergence: ${alg.convergenceScore.toFixed(3)}`);
}
}
console.log('');
}
});
// Manual learning update
hooksCmd.command('learning-update')
.description('Manually record a learning experience')
.requiredOption('-t, --task <type>', 'Task type')
.requiredOption('-s, --state <state>', 'Current state')
.requiredOption('-a, --action <action>', 'Action taken')
.requiredOption('-r, --reward <reward>', 'Reward received', parseFloat)
.option('-n, --next-state <state>', 'Next state')
.option('-d, --done', 'Episode is done')
.action(async (opts) => {
if (!loadLearningModules()) {
console.log(JSON.stringify({ success: false, error: 'Learning modules not available' }));
return;
}
const dataPath = path.join(process.cwd(), '.ruvector', 'intelligence.json');
let data = {};
try {
if (fs.existsSync(dataPath)) {
data = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
}
} catch (e) {}
const engine = new LearningEngineClass();
if (data.learning) {
engine.import(data.learning);
}
const experience = {
state: opts.state,
action: opts.action,
reward: opts.reward,
nextState: opts.nextState || opts.state,
done: opts.done || false,
timestamp: Date.now()
};
const delta = engine.update(opts.task, experience);
// Save
data.learning = engine.export();
fs.writeFileSync(dataPath, JSON.stringify(data, null, 2));
console.log(JSON.stringify({
success: true,
task: opts.task,
experience,
delta,
algorithm: engine.getConfig(opts.task).algorithm
}));
});
// TensorCompress commands
hooksCmd.command('compress')
.description('Compress pattern storage using TensorCompress')
.option('--force', 'Force recompression of all patterns')
.option('--stats', 'Show compression statistics only')
.action(async (opts) => {
if (!loadLearningModules()) {
console.log(JSON.stringify({ success: false, error: 'Compression modules not available' }));
return;
}
const dataPath = path.join(process.cwd(), '.ruvector', 'intelligence.json');
let data = {};
try {
if (fs.existsSync(dataPath)) {
data = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
}
} catch (e) {}
const compress = new TensorCompressClass({
autoCompress: false,
hotThreshold: 0.8,
warmThreshold: 0.4,
coolThreshold: 0.1,
coldThreshold: 0.01
});
// Import existing compressed data
if (data.compressedPatterns) {
compress.import(data.compressedPatterns);
}
// Also compress any uncompressed patterns from the regular patterns
if (data.patterns && !data.compressedPatterns) {
for (const [key, value] of Object.entries(data.patterns)) {
if (Array.isArray(value) && value.length > 0 && typeof value[0] === 'number') {
compress.store(key, value);
}
}
}
if (opts.stats) {
const stats = compress.getStats();
console.log(JSON.stringify({ success: true, ...stats }));
return;
}
// Recompress based on access patterns
const stats = compress.recompressAll();
// Save compressed data
data.compressedPatterns = compress.export();
fs.writeFileSync(dataPath, JSON.stringify(data, null, 2));
console.log(JSON.stringify({
success: true,
message: 'Compression complete',
...stats
}));
});
hooksCmd.command('compress-stats')
.description('Show TensorCompress statistics')
.option('--json', 'Output as JSON')
.action(async (opts) => {
if (!loadLearningModules()) {
console.log(JSON.stringify({ success: false, error: 'Compression modules not available' }));
return;
}
const dataPath = path.join(process.cwd(), '.ruvector', 'intelligence.json');
let data = {};
try {
if (fs.existsSync(dataPath)) {
data = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
}
} catch (e) {}
const compress = new TensorCompressClass({ autoCompress: false });
if (data.compressedPatterns) {
compress.import(data.compressedPatterns);
}
const stats = compress.getStats();
if (opts.json) {
console.log(JSON.stringify({ success: true, ...stats }));
} else {
console.log(chalk.bold.cyan('\n📦 TensorCompress Statistics\n'));
console.log(` Total Tensors: ${stats.totalTensors}`);
console.log(` Original Size: ${(stats.originalBytes / 1024).toFixed(2)} KB`);
console.log(` Compressed Size: ${(stats.compressedBytes / 1024).toFixed(2)} KB`);
console.log(` Savings: ${chalk.green(stats.savingsPercent.toFixed(1) + '%')}`);
console.log(chalk.bold('\n By Compression Level:'));
console.log(` none (hot): ${stats.byLevel.none}`);
console.log(` half (warm): ${stats.byLevel.half}`);
console.log(` pq8 (cool): ${stats.byLevel.pq8}`);
console.log(` pq4 (cold): ${stats.byLevel.pq4}`);
console.log(` binary (archive): ${stats.byLevel.binary}`);
console.log('');
}
});
// Store embedding with compression
hooksCmd.command('compress-store')
.description('Store an embedding with adaptive compression')
.requiredOption('-k, --key <key>', 'Storage key')
.requiredOption('-v, --vector <vector>', 'Vector as JSON array')
.option('-l, --level <level>', 'Compression level (none, half, pq8, pq4, binary)')
.action(async (opts) => {
if (!loadLearningModules()) {
console.log(JSON.stringify({ success: false, error: 'Compression modules not available' }));
return;
}
let vector;
try {
vector = JSON.parse(opts.vector);
} catch (e) {
console.log(JSON.stringify({ success: false, error: 'Invalid vector JSON' }));
return;
}
const dataPath = path.join(process.cwd(), '.ruvector', 'intelligence.json');
let data = {};
try {
if (fs.existsSync(dataPath)) {
data = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
}
} catch (e) {}
const compress = new TensorCompressClass({ autoCompress: false });
if (data.compressedPatterns) {
compress.import(data.compressedPatterns);
}
compress.store(opts.key, vector, opts.level);
data.compressedPatterns = compress.export();
fs.mkdirSync(path.dirname(dataPath), { recursive: true });
fs.writeFileSync(dataPath, JSON.stringify(data, null, 2));
const stats = compress.getStats();
console.log(JSON.stringify({
success: true,
key: opts.key,
level: opts.level || 'auto',
originalDim: vector.length,
totalTensors: stats.totalTensors
}));
});
// Retrieve compressed embedding
hooksCmd.command('compress-get')
.description('Retrieve a compressed embedding')
.requiredOption('-k, --key <key>', 'Storage key')
.action(async (opts) => {
if (!loadLearningModules()) {
console.log(JSON.stringify({ success: false, error: 'Compression modules not available' }));
return;
}
const dataPath = path.join(process.cwd(), '.ruvector', 'intelligence.json');
let data = {};
try {
if (fs.existsSync(dataPath)) {
data = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
}
} catch (e) {}
const compress = new TensorCompressClass({ autoCompress: false });
if (data.compressedPatterns) {
compress.import(data.compressedPatterns);
}
const vector = compress.get(opts.key);
if (!vector) {
console.log(JSON.stringify({ success: false, error: 'Key not found' }));
return;
}
console.log(JSON.stringify({
success: true,
key: opts.key,
vector: Array.from(vector),
dimension: vector.length
}));
});
// Combined learning action with best algorithm
hooksCmd.command('learn')
.description('Record learning outcome and get best action recommendation')
.requiredOption('-s, --state <state>', 'Current state (e.g., file extension, task type)')
.option('-a, --action <action>', 'Action taken')
.option('-r, --reward <reward>', 'Reward (-1 to 1)', parseFloat)
.option('--actions <actions>', 'Available actions (comma-separated)')
.option('-t, --task <type>', 'Task type', 'agent-routing')
.action(async (opts) => {
if (!loadLearningModules()) {
console.log(JSON.stringify({ success: false, error: 'Learning modules not available' }));
return;
}
const dataPath = path.join(process.cwd(), '.ruvector', 'intelligence.json');
let data = {};
try {
if (fs.existsSync(dataPath)) {
data = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
}
} catch (e) {}
const engine = new LearningEngineClass();
if (data.learning) {
engine.import(data.learning);
}
let result = { success: true };
// If action and reward provided, record the experience
if (opts.action && opts.reward !== undefined) {
const experience = {
state: opts.state,
action: opts.action,
reward: opts.reward,
nextState: opts.state,
done: true,
timestamp: Date.now()
};
const delta = engine.update(opts.task, experience);
result.recorded = { experience, delta, algorithm: engine.getConfig(opts.task).algorithm };
}
// Get best action recommendation
if (opts.actions) {
const actions = opts.actions.split(',').map(a => a.trim());
const best = engine.getBestAction(opts.task, opts.state, actions);
result.recommendation = best;
}
// Save
data.learning = engine.export();
fs.mkdirSync(path.dirname(dataPath), { recursive: true });
fs.writeFileSync(dataPath, JSON.stringify(data, null, 2));
console.log(JSON.stringify(result));
});
// Batch learn - process multiple experiences at once
hooksCmd.command('batch-learn')
.description('Record multiple learning experiences in batch for efficiency')
.option('-f, --file <file>', 'JSON file with experiences array')
.option('-d, --data <json>', 'Inline JSON array of experiences')
.option('-t, --task <type>', 'Task type for all experiences', 'agent-routing')
.action(async (opts) => {
if (!loadLearningModules()) {
console.log(JSON.stringify({ success: false, error: 'Learning modules not available' }));
return;
}
let experiences = [];
// Load from file or inline
if (opts.file) {
try {
const content = fs.readFileSync(opts.file, 'utf-8');
experiences = JSON.parse(content);
} catch (e) {
console.log(JSON.stringify({ success: false, error: `Failed to read file: ${e.message}` }));
return;
}
} else if (opts.data) {
try {
experiences = JSON.parse(opts.data);
} catch (e) {
console.log(JSON.stringify({ success: false, error: `Invalid JSON: ${e.message}` }));
return;
}
} else {
console.log(JSON.stringify({ success: false, error: 'Provide --file or --data' }));
return;
}
if (!Array.isArray(experiences)) {
experiences = [experiences];
}
const dataPath = path.join(process.cwd(), '.ruvector', 'intelligence.json');
let data = {};
try {
if (fs.existsSync(dataPath)) {
data = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
}
} catch (e) {}
const engine = new LearningEngineClass();
if (data.learning) {
engine.import(data.learning);
}
const results = [];
let totalReward = 0;
for (const exp of experiences) {
const experience = {
state: exp.state,
action: exp.action,
reward: exp.reward ?? 0.5,
nextState: exp.nextState ?? exp.state,
done: exp.done ?? false,
timestamp: exp.timestamp ?? Date.now()
};
const delta = engine.update(opts.task, experience);
totalReward += experience.reward;
results.push({ state: exp.state, action: exp.action, delta });
}
// Save
data.learning = engine.export();
fs.mkdirSync(path.dirname(dataPath), { recursive: true });
fs.writeFileSync(dataPath, JSON.stringify(data, null, 2));
const stats = engine.getStatsSummary();
console.log(JSON.stringify({
success: true,
processed: experiences.length,
avgReward: totalReward / experiences.length,
results,
stats: {
bestAlgorithm: stats.bestAlgorithm,
totalUpdates: stats.totalUpdates,
avgReward: stats.avgReward
}
}));
});
// Subscribe to learning updates - stream real-time learning events
hooksCmd.command('subscribe')
.description('Subscribe to real-time learning updates (streaming)')
.option('-e, --events <types>', 'Event types to subscribe to (learn,compress,route,memory)', 'learn,route')
.option('-f, --format <fmt>', 'Output format (json, text)', 'json')
.option('--poll <ms>', 'Poll interval in ms', parseInt, 1000)
.action(async (opts) => {
const events = opts.events.split(',').map(e => e.trim());
const dataPath = path.join(process.cwd(), '.ruvector', 'intelligence.json');
let lastStats = { patterns: 0, memories: 0, trajectories: 0 };
let lastLearning = { totalUpdates: 0 };
console.error(chalk.cyan('🔴 Subscribed to learning updates. Press Ctrl+C to stop.\n'));
console.error(chalk.dim(` Events: ${events.join(', ')}`));
console.error(chalk.dim(` Poll interval: ${opts.poll}ms\n`));
const emit = (type, data) => {
const event = { type, timestamp: Date.now(), data };
if (opts.format === 'json') {
console.log(JSON.stringify(event));
} else {
const icon = { learn: '🧠', compress: '📦', route: '🎯', memory: '💾' }[type] || '📡';
console.log(`${icon} [${type}] ${JSON.stringify(data)}`);
}
};
const check = () => {
try {
if (!fs.existsSync(dataPath)) return;
const data = JSON.parse(fs.readFileSync(dataPath, 'utf-8'));
const stats = data.stats || {};
const learning = data.learning?.stats || {};
// Check for new patterns (learn events)
if (events.includes('learn')) {
const currentPatterns = stats.total_patterns || 0;
if (currentPatterns > lastStats.patterns) {
emit('learn', {
type: 'pattern',
newPatterns: currentPatterns - lastStats.patterns,
total: currentPatterns
});
lastStats.patterns = currentPatterns;
}
// Check learning engine updates
let totalUpdates = 0;
Object.values(learning).forEach(algo => {
if (algo.updates) totalUpdates += algo.updates;
});
if (totalUpdates > lastLearning.totalUpdates) {
const bestAlgo = Object.entries(learning)
.filter(([, v]) => v.updates > 0)
.sort((a, b) => b[1].avgReward - a[1].avgReward)[0];
emit('learn', {
type: 'algorithm_update',
newUpdates: totalUpdates - lastLearning.totalUpdates,
totalUpdates,
bestAlgorithm: bestAlgo?.[0] || 'none'
});
lastLearning.totalUpdates = totalUpdates;
}
}
// Check for new memories
if (events.includes('memory')) {
const currentMemories = stats.total_memories || 0;
if (currentMemories > lastStats.memories) {
emit('memory', {
newMemories: currentMemories - lastStats.memories,
total: currentMemories
});
lastStats.memories = currentMemories;
}
}
// Check for new trajectories (route events)
if (events.includes('route')) {
const currentTrajectories = stats.total_trajectories || 0;
if (currentTrajectories > lastStats.trajectories) {
emit('route', {
newTrajectories: currentTrajectories - lastStats.trajectories,
total: currentTrajectories
});
lastStats.trajectories = currentTrajectories;
}
}
} catch (e) {
// Ignore read errors during updates
}
};
// Initial state
check();
// Poll for updates
const interval = setInterval(check, opts.poll);
// Handle graceful shutdown
process.on('SIGINT', () => {
clearInterval(interval);
console.error(chalk.dim('\n\n👋 Subscription ended.'));
process.exit(0);
});
// Keep alive
await new Promise(() => {});
});
// Watch and learn - monitor file changes and auto-learn
hooksCmd.command('watch')
.description('Watch for changes and auto-learn patterns in real-time')
.option('-p, --path <dir>', 'Directory to watch', '.')
.option('-i, --ignore <patterns>', 'Patterns to ignore (comma-separated)', 'node_modules,dist,.git')
.option('--dry-run', 'Show what would be learned without saving')
.action(async (opts) => {
const watchDir = path.resolve(opts.path);
const ignorePatterns = opts.ignore.split(',').map(p => p.trim());
console.error(chalk.cyan(`👁️ Watching ${watchDir} for changes...\n`));
console.error(chalk.dim(` Ignoring: ${ignorePatterns.join(', ')}`));
console.error(chalk.dim(` Press Ctrl+C to stop.\n`));
const intel = new Intelligence({ skipEngine: true });
let lastEdit = null;
let editCount = 0;
const shouldIgnore = (filePath) => {
return ignorePatterns.some(pattern => filePath.includes(pattern));
};
const processChange = (eventType, filename) => {
if (!filename || shouldIgnore(filename)) return;
const ext = path.extname(filename);
const state = `edit:${ext || 'unknown'}`;
const now = Date.now();
// Determine likely action based on file type
const agentMapping = {
'.ts': 'typescript-developer',
'.js': 'coder',
'.rs': 'rust-developer',
'.py': 'python-developer',
'.go': 'go-developer',
'.md': 'documentation',
'.json': 'config-manager',
'.yaml': 'devops-engineer',
'.yml': 'devops-engineer',
};
const agent = agentMapping[ext] || 'coder';
// Co-edit pattern detection
if (lastEdit && lastEdit.file !== filename && (now - lastEdit.time) < 60000) {
// Files edited within 1 minute are co-edits
const coEditKey = [lastEdit.file, filename].sort().join('|');
if (!opts.dryRun) {
if (!intel.data.sequences) intel.data.sequences = {};
if (!intel.data.sequences[lastEdit.file]) intel.data.sequences[lastEdit.file] = [];
const existing = intel.data.sequences[lastEdit.file].find(s => s.file === filename);
if (existing) {
existing.score++;
} else {
intel.data.sequences[lastEdit.file].push({ file: filename, score: 1 });
}
}
console.log(chalk.yellow(` 🔗 Co-edit: ${path.basename(lastEdit.file)}${path.basename(filename)}`));
}
// Update Q-value for this file type
if (!opts.dryRun) {
intel.updateQ(state, agent, 0.5);
intel.save();
}
editCount++;
console.log(chalk.green(` ✏️ [${editCount}] ${filename}${agent}`));
lastEdit = { file: filename, time: now };
};
// Use fs.watch for real-time monitoring
const watcher = fs.watch(watchDir, { recursive: true }, processChange);
process.on('SIGINT', () => {
watcher.close();
console.error(chalk.dim(`\n\n📊 Learned from ${editCount} file changes.`));
process.exit(0);
});
// Keep alive
await new Promise(() => {});
});
// ============================================
// END NEW CAPABILITY COMMANDS
// ============================================
// Verify hooks are working
hooksCmd.command('verify')
.description('Verify hooks are working correctly')
.option('--verbose', 'Show detailed output')
.action((opts) => {
console.log(chalk.bold.cyan('\n🔍 RuVector Hooks Verification\n'));
const checks = [];
// Check 1: Settings file exists
const settingsPath = path.join(process.cwd(), '.claude', 'settings.json');
if (fs.existsSync(settingsPath)) {
checks.push({ name: 'Settings file', status: 'pass', detail: '.claude/settings.json exists' });
try {
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
// Check hooks
const requiredHooks = ['PreToolUse', 'PostToolUse', 'SessionStart', 'Stop'];
const missingHooks = requiredHooks.filter(h => !settings.hooks?.[h]);
if (missingHooks.length === 0) {
checks.push({ name: 'Required hooks', status: 'pass', detail: 'All core hooks configured' });
} else {
checks.push({ name: 'Required hooks', status: 'fail', detail: `Missing: ${missingHooks.join(', ')}` });
}
// Check advanced hooks
const advancedHooks = ['UserPromptSubmit', 'PreCompact', 'Notification'];
const hasAdvanced = advancedHooks.filter(h => settings.hooks?.[h]);
if (hasAdvanced.length > 0) {
checks.push({ name: 'Advanced hooks', status: 'pass', detail: `${hasAdvanced.length}/3 configured` });
} else {
checks.push({ name: 'Advanced hooks', status: 'warn', detail: 'None configured (optional)' });
}
// Check env
if (settings.env?.RUVECTOR_INTELLIGENCE_ENABLED) {
checks.push({ name: 'Environment vars', status: 'pass', detail: 'Intelligence enabled' });
} else {
checks.push({ name: 'Environment vars', status: 'warn', detail: 'Not configured' });
}
// Check permissions
if (settings.permissions?.allow?.length > 0) {
checks.push({ name: 'Permissions', status: 'pass', detail: `${settings.permissions.allow.length} allowed patterns` });
} else {
checks.push({ name: 'Permissions', status: 'warn', detail: 'Not configured' });
}
} catch (e) {
checks.push({ name: 'Settings parse', status: 'fail', detail: 'Invalid JSON' });
}
} else {
checks.push({ name: 'Settings file', status: 'fail', detail: 'Run `npx ruvector hooks init` first' });
}
// Check 2: .ruvector directory
const ruvectorDir = path.join(process.cwd(), '.ruvector');
if (fs.existsSync(ruvectorDir)) {
checks.push({ name: 'Data directory', status: 'pass', detail: '.ruvector/ exists' });
const intelFile = path.join(ruvectorDir, 'intelligence.json');
if (fs.existsSync(intelFile)) {
const stats = fs.statSync(intelFile);
checks.push({ name: 'Intelligence file', status: 'pass', detail: `${(stats.size / 1024).toFixed(1)}KB` });
} else {
checks.push({ name: 'Intelligence file', status: 'warn', detail: 'Will be created on first use' });
}
} else {
checks.push({ name: 'Data directory', status: 'warn', detail: 'Will be created on first use' });
}
// Check 3: Hook command execution
try {
const { execSync } = require('child_process');
execSync('npx ruvector hooks stats', { stdio: 'pipe', timeout: 5000 });
checks.push({ name: 'Command execution', status: 'pass', detail: 'Hooks commands work' });
} catch (e) {
checks.push({ name: 'Command execution', status: 'fail', detail: 'Commands failed to execute' });
}
// Display results
let passCount = 0, warnCount = 0, failCount = 0;
checks.forEach(c => {
const icon = c.status === 'pass' ? chalk.green('✓') : c.status === 'warn' ? chalk.yellow('⚠') : chalk.red('✗');
const statusColor = c.status === 'pass' ? chalk.green : c.status === 'warn' ? chalk.yellow : chalk.red;
console.log(` ${icon} ${c.name}: ${statusColor(c.detail)}`);
if (c.status === 'pass') passCount++;
else if (c.status === 'warn') warnCount++;
else failCount++;
});
console.log('');
if (failCount === 0) {
console.log(chalk.green(`✅ Verification passed! ${passCount} checks passed, ${warnCount} warnings`));
} else {
console.log(chalk.red(`❌ Verification failed: ${failCount} issues found`));
console.log(chalk.dim(' Run `npx ruvector hooks doctor` for detailed diagnostics'));
}
});
// Doctor - diagnose setup issues
hooksCmd.command('doctor')
.description('Diagnose and fix setup issues')
.option('--fix', 'Automatically fix issues')
.action((opts) => {
console.log(chalk.bold.cyan('\n🩺 RuVector Hooks Doctor\n'));
const issues = [];
const fixes = [];
// Check settings file
const settingsPath = path.join(process.cwd(), '.claude', 'settings.json');
if (!fs.existsSync(settingsPath)) {
issues.push({ severity: 'error', message: 'No .claude/settings.json found', fix: 'Run `npx ruvector hooks init`' });
} else {
try {
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
// Check for invalid schema
if (settings.$schema && !settings.$schema.includes('schemastore.org')) {
issues.push({ severity: 'warning', message: 'Invalid schema URL', fix: 'Will be corrected' });
if (opts.fix) {
settings.$schema = 'https://json.schemastore.org/claude-code-settings.json';
fixes.push('Fixed schema URL');
}
}
// Check for old hook names
if (settings.hooks?.Start || settings.hooks?.End) {
issues.push({ severity: 'error', message: 'Invalid hook names (Start/End)', fix: 'Should be SessionStart/Stop' });
if (opts.fix) {
delete settings.hooks.Start;
delete settings.hooks.End;
fixes.push('Removed invalid hook names');
}
}
// Check hook format
const hookNames = ['PreToolUse', 'PostToolUse'];
hookNames.forEach(name => {
if (settings.hooks?.[name]) {
settings.hooks[name].forEach((hook, i) => {
if (typeof hook.matcher === 'object') {
issues.push({ severity: 'error', message: `${name}[${i}].matcher should be string, not object`, fix: 'Will be corrected' });
}
});
}
});
// Check for npx vs direct command
const checkCommands = (hooks) => {
if (!hooks) return;
hooks.forEach(h => {
h.hooks?.forEach(hh => {
if (hh.command && hh.command.includes('ruvector') && !hh.command.startsWith('npx ') && !hh.command.includes('/bin/')) {
issues.push({ severity: 'warning', message: `Command should use 'npx ruvector' for portability`, fix: 'Update to use npx' });
}
});
});
};
Object.values(settings.hooks || {}).forEach(checkCommands);
// Save fixes
if (opts.fix && fixes.length > 0) {
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
}
} catch (e) {
issues.push({ severity: 'error', message: 'Invalid JSON in settings file', fix: 'Re-run `npx ruvector hooks init --force`' });
}
}
// Check .gitignore
const gitignorePath = path.join(process.cwd(), '.gitignore');
if (fs.existsSync(gitignorePath)) {
const content = fs.readFileSync(gitignorePath, 'utf-8');
if (!content.includes('.ruvector/')) {
issues.push({ severity: 'warning', message: '.ruvector/ not in .gitignore', fix: 'Add to prevent committing learning data' });
if (opts.fix) {
fs.appendFileSync(gitignorePath, '\n# RuVector intelligence data\n.ruvector/\n');
fixes.push('Added .ruvector/ to .gitignore');
}
}
}
// Display results
if (issues.length === 0) {
console.log(chalk.green(' ✓ No issues found! Your setup looks healthy.'));
} else {
issues.forEach(i => {
const icon = i.severity === 'error' ? chalk.red('✗') : chalk.yellow('⚠');
console.log(` ${icon} ${i.message}`);
console.log(chalk.dim(` Fix: ${i.fix}`));
});
if (opts.fix && fixes.length > 0) {
console.log(chalk.green(`\n✅ Applied ${fixes.length} fix(es):`));
fixes.forEach(f => console.log(chalk.green(` • ${f}`)));
} else if (issues.some(i => i.severity === 'error')) {
console.log(chalk.yellow('\n💡 Run with --fix to automatically fix issues'));
}
}
});
// Export intelligence data
hooksCmd.command('export')
.description('Export intelligence data for backup')
.option('-o, --output <file>', 'Output file path', 'ruvector-export.json')
.option('--include-all', 'Include all data (patterns, memories, trajectories)')
.action((opts) => {
const intel = new Intelligence();
const exportData = {
version: '1.0',
exported_at: new Date().toISOString(),
patterns: intel.data?.patterns || {},
memories: opts.includeAll ? (intel.data?.memories || []) : [],
trajectories: opts.includeAll ? (intel.data?.trajectories || []) : [],
errors: intel.data?.errors || {},
stats: intel.stats()
};
const outputPath = path.resolve(opts.output);
fs.writeFileSync(outputPath, JSON.stringify(exportData, null, 2));
console.log(chalk.green(`✅ Exported intelligence data to ${outputPath}`));
console.log(chalk.dim(` ${Object.keys(exportData.patterns).length} patterns`));
console.log(chalk.dim(` ${exportData.memories.length} memories`));
console.log(chalk.dim(` ${exportData.trajectories.length} trajectories`));
});
// Import intelligence data
hooksCmd.command('import')
.description('Import intelligence data from backup')
.argument('<file>', 'Import file path')
.option('--merge', 'Merge with existing data (default: replace)')
.option('--dry-run', 'Show what would be imported without making changes')
.action((file, opts) => {
const importPath = path.resolve(file);
if (!fs.existsSync(importPath)) {
console.error(chalk.red(`❌ File not found: ${importPath}`));
process.exit(1);
}
try {
const importData = JSON.parse(fs.readFileSync(importPath, 'utf-8'));
if (!importData.version) {
console.error(chalk.red('❌ Invalid export file (missing version)'));
process.exit(1);
}
console.log(chalk.cyan(`📦 Import file: ${file}`));
console.log(chalk.dim(` Version: ${importData.version}`));
console.log(chalk.dim(` Exported: ${importData.exported_at}`));
console.log(chalk.dim(` Patterns: ${Object.keys(importData.patterns || {}).length}`));
console.log(chalk.dim(` Memories: ${(importData.memories || []).length}`));
console.log(chalk.dim(` Trajectories: ${(importData.trajectories || []).length}`));
if (opts.dryRun) {
console.log(chalk.yellow('\n⚠️ Dry run - no changes made'));
return;
}
const intel = new Intelligence();
if (opts.merge) {
// Merge patterns
Object.assign(intel.data.patterns, importData.patterns || {});
// Merge memories (deduplicate by content)
const existingContent = new Set((intel.data.memories || []).map(m => m.content));
(importData.memories || []).forEach(m => {
if (!existingContent.has(m.content)) {
intel.data.memories.push(m);
}
});
// Merge trajectories
intel.data.trajectories = (intel.data.trajectories || []).concat(importData.trajectories || []);
// Merge errors
Object.assign(intel.data.errors, importData.errors || {});
console.log(chalk.green('✅ Merged intelligence data'));
} else {
intel.data.patterns = importData.patterns || {};
intel.data.memories = importData.memories || [];
intel.data.trajectories = importData.trajectories || [];
intel.data.errors = importData.errors || {};
console.log(chalk.green('✅ Replaced intelligence data'));
}
intel.save();
console.log(chalk.dim(' Data saved to .ruvector/intelligence.json'));
} catch (e) {
console.error(chalk.red(`❌ Failed to import: ${e.message}`));
process.exit(1);
}
});
// Pretrain - analyze repo and bootstrap learning with agent swarm
hooksCmd.command('pretrain')
.description('Pretrain intelligence by analyzing the repository with agent swarm')
.option('--depth <n>', 'Git history depth to analyze', '100')
.option('--workers <n>', 'Number of parallel analysis workers', '4')
.option('--skip-git', 'Skip git history analysis')
.option('--skip-files', 'Skip file structure analysis')
.option('--verbose', 'Show detailed progress')
.action(async (opts) => {
const { execSync, spawn } = require('child_process');
console.log(chalk.bold.cyan('\n🧠 RuVector Pretrain - Repository Intelligence Bootstrap\n'));
const intel = new Intelligence();
const startTime = Date.now();
const stats = { files: 0, patterns: 0, memories: 0, coedits: 0 };
// Agent types for different file patterns
const agentMapping = {
// Rust
'.rs': 'rust-developer',
'Cargo.toml': 'rust-developer',
'Cargo.lock': 'rust-developer',
// JavaScript/TypeScript
'.js': 'javascript-developer',
'.jsx': 'react-developer',
'.ts': 'typescript-developer',
'.tsx': 'react-developer',
'.mjs': 'javascript-developer',
'.cjs': 'javascript-developer',
'package.json': 'node-developer',
// Python
'.py': 'python-developer',
'requirements.txt': 'python-developer',
'pyproject.toml': 'python-developer',
'setup.py': 'python-developer',
// Go
'.go': 'go-developer',
'go.mod': 'go-developer',
// Web
'.html': 'frontend-developer',
'.css': 'frontend-developer',
'.scss': 'frontend-developer',
'.vue': 'vue-developer',
'.svelte': 'svelte-developer',
// Config
'.json': 'config-specialist',
'.yaml': 'config-specialist',
'.yml': 'config-specialist',
'.toml': 'config-specialist',
// Docs
'.md': 'documentation-specialist',
'.mdx': 'documentation-specialist',
// Tests
'.test.js': 'test-engineer',
'.test.ts': 'test-engineer',
'.spec.js': 'test-engineer',
'.spec.ts': 'test-engineer',
'_test.go': 'test-engineer',
'_test.rs': 'test-engineer',
// DevOps
'Dockerfile': 'devops-engineer',
'docker-compose.yml': 'devops-engineer',
'.github/workflows': 'cicd-engineer',
'Makefile': 'devops-engineer',
// SQL
'.sql': 'database-specialist',
};
// Phase 1: Analyze file structure
if (!opts.skipFiles) {
console.log(chalk.yellow('📁 Phase 1: Analyzing file structure...\n'));
try {
// Get all files in repo
const files = execSync('git ls-files 2>/dev/null || find . -type f -not -path "./.git/*" -not -path "./node_modules/*" -not -path "./target/*"',
{ encoding: 'utf-8', maxBuffer: 50 * 1024 * 1024 }).trim().split('\n').filter(f => f);
const filesByType = {};
const dirPatterns = {};
files.forEach(file => {
stats.files++;
const ext = path.extname(file);
const basename = path.basename(file);
const dir = path.dirname(file);
// Determine agent for this file
let agent = 'coder'; // default
if (agentMapping[basename]) {
agent = agentMapping[basename];
} else if (agentMapping[ext]) {
agent = agentMapping[ext];
} else if (file.includes('.test.') || file.includes('.spec.') || file.includes('_test.')) {
agent = 'test-engineer';
} else if (file.includes('.github/workflows')) {
agent = 'cicd-engineer';
}
// Track file types
filesByType[ext] = (filesByType[ext] || 0) + 1;
// Track directory patterns
const parts = dir.split('/');
if (parts[0]) {
dirPatterns[parts[0]] = dirPatterns[parts[0]] || { count: 0, agents: {} };
dirPatterns[parts[0]].count++;
dirPatterns[parts[0]].agents[agent] = (dirPatterns[parts[0]].agents[agent] || 0) + 1;
}
// Create Q-learning pattern for this file type
const state = `edit:${ext || 'unknown'}`;
if (!intel.data.patterns[state]) {
intel.data.patterns[state] = {};
}
intel.data.patterns[state][agent] = (intel.data.patterns[state][agent] || 0) + 0.5;
stats.patterns++;
});
// Log summary
if (opts.verbose) {
console.log(chalk.dim(' File types found:'));
Object.entries(filesByType).sort((a, b) => b[1] - a[1]).slice(0, 10).forEach(([ext, count]) => {
console.log(chalk.dim(` ${ext || '(no ext)'}: ${count} files`));
});
}
console.log(chalk.green(` ✓ Analyzed ${stats.files} files`));
console.log(chalk.green(` ✓ Created ${Object.keys(intel.data.patterns).length} routing patterns`));
} catch (e) {
console.log(chalk.yellow(` ⚠ File analysis skipped: ${e.message}`));
}
}
// Phase 2: Analyze git history for co-edit patterns
if (!opts.skipGit) {
console.log(chalk.yellow('\n📜 Phase 2: Analyzing git history for co-edit patterns...\n'));
try {
// Get commits with files changed
const gitLog = execSync(
`git log --name-only --pretty=format:"COMMIT:%H" -n ${opts.depth} 2>/dev/null`,
{ encoding: 'utf-8', maxBuffer: 50 * 1024 * 1024 }
);
const commits = gitLog.split('COMMIT:').filter(c => c.trim());
const coEditMap = {};
commits.forEach(commit => {
const lines = commit.trim().split('\n').filter(l => l && !l.startsWith('COMMIT:'));
const files = lines.slice(1).filter(f => f.trim()); // Skip the hash
// Track which files are edited together
files.forEach(file1 => {
files.forEach(file2 => {
if (file1 !== file2) {
const key = [file1, file2].sort().join('|');
coEditMap[key] = (coEditMap[key] || 0) + 1;
}
});
});
});
// Find strong co-edit patterns (files edited together 3+ times)
const strongPatterns = Object.entries(coEditMap)
.filter(([, count]) => count >= 3)
.sort((a, b) => b[1] - a[1]);
// Store as sequence patterns
strongPatterns.slice(0, 100).forEach(([key, count]) => {
const [file1, file2] = key.split('|');
if (!intel.data.sequences) intel.data.sequences = {};
if (!intel.data.sequences[file1]) intel.data.sequences[file1] = [];
const existing = intel.data.sequences[file1].find(s => s.file === file2);
if (existing) {
existing.score += count;
} else {
intel.data.sequences[file1].push({ file: file2, score: count });
}
stats.coedits++;
});
console.log(chalk.green(` ✓ Analyzed ${commits.length} commits`));
console.log(chalk.green(` ✓ Found ${strongPatterns.length} co-edit patterns`));
if (opts.verbose && strongPatterns.length > 0) {
console.log(chalk.dim(' Top co-edit patterns:'));
strongPatterns.slice(0, 5).forEach(([key, count]) => {
const [f1, f2] = key.split('|');
console.log(chalk.dim(` ${path.basename(f1)}${path.basename(f2)}: ${count} times`));
});
}
} catch (e) {
console.log(chalk.yellow(` ⚠ Git analysis skipped: ${e.message}`));
}
}
// Phase 3: Create vector memories from important files
console.log(chalk.yellow('\n💾 Phase 3: Creating vector memories from key files...\n'));
try {
const importantFiles = [
'README.md', 'CLAUDE.md', 'package.json', 'Cargo.toml',
'pyproject.toml', 'go.mod', '.claude/settings.json'
];
for (const filename of importantFiles) {
const filePath = path.join(process.cwd(), filename);
if (fs.existsSync(filePath)) {
try {
const content = fs.readFileSync(filePath, 'utf-8').slice(0, 2000); // First 2KB
intel.data.memories = intel.data.memories || [];
intel.data.memories.push({
content: `[${filename}] ${content.replace(/\n/g, ' ').slice(0, 500)}`,
type: 'project',
created: new Date().toISOString(),
embedding: intel.simpleEmbed ? intel.simpleEmbed(content) : null
});
stats.memories++;
if (opts.verbose) console.log(chalk.dim(` ✓ ${filename}`));
} catch (e) { /* skip unreadable files */ }
}
}
console.log(chalk.green(` ✓ Created ${stats.memories} memory entries`));
} catch (e) {
console.log(chalk.yellow(` ⚠ Memory creation skipped: ${e.message}`));
}
// Phase 4: Analyze directory structure for agent recommendations
console.log(chalk.yellow('\n🗂️ Phase 4: Building directory-agent mappings...\n'));
try {
const dirs = execSync('find . -type d -maxdepth 2 -not -path "./.git*" -not -path "./node_modules*" -not -path "./target*" 2>/dev/null || echo "."',
{ encoding: 'utf-8' }).trim().split('\n');
const dirAgentMap = {};
dirs.forEach(dir => {
const name = path.basename(dir);
// Infer agent from directory name
if (['src', 'lib', 'core'].includes(name)) dirAgentMap[dir] = 'coder';
else if (['test', 'tests', '__tests__', 'spec'].includes(name)) dirAgentMap[dir] = 'test-engineer';
else if (['docs', 'documentation'].includes(name)) dirAgentMap[dir] = 'documentation-specialist';
else if (['scripts', 'bin'].includes(name)) dirAgentMap[dir] = 'devops-engineer';
else if (['components', 'views', 'pages'].includes(name)) dirAgentMap[dir] = 'frontend-developer';
else if (['api', 'routes', 'handlers'].includes(name)) dirAgentMap[dir] = 'backend-developer';
else if (['models', 'entities', 'schemas'].includes(name)) dirAgentMap[dir] = 'database-specialist';
else if (['.github', '.gitlab', 'ci'].includes(name)) dirAgentMap[dir] = 'cicd-engineer';
});
// Store directory patterns
intel.data.dirPatterns = dirAgentMap;
console.log(chalk.green(` ✓ Mapped ${Object.keys(dirAgentMap).length} directories to agents`));
} catch (e) {
console.log(chalk.yellow(` ⚠ Directory analysis skipped: ${e.message}`));
}
// Phase 5: Analyze code complexity with AST
console.log(chalk.yellow('\n📊 Phase 5: Analyzing code complexity via AST...\n'));
try {
if (loadNewModules() && ASTParser) {
const parser = new ASTParser();
const codeFiles = (intel.data.fileList || []).filter(f =>
['.ts', '.js', '.tsx', '.jsx', '.py', '.rs', '.go'].includes(path.extname(f))
).slice(0, 50); // Analyze up to 50 files
let complexityStats = { high: 0, medium: 0, low: 0, total: 0 };
for (const file of codeFiles) {
try {
if (!fs.existsSync(file)) continue;
const code = fs.readFileSync(file, 'utf-8');
const ext = path.extname(file).slice(1);
const lang = { ts: 'typescript', tsx: 'typescript', js: 'javascript', py: 'python', rs: 'rust', go: 'go' }[ext];
if (!lang) continue;
const result = parser.parse(code, lang);
const complexity = parser.calculateComplexity(result);
// Store complexity data
intel.data.complexity = intel.data.complexity || {};
intel.data.complexity[file] = complexity;
if (complexity.cyclomatic > 15) complexityStats.high++;
else if (complexity.cyclomatic > 8) complexityStats.medium++;
else complexityStats.low++;
complexityStats.total++;
} catch (e) { /* skip errors */ }
}
stats.complexity = complexityStats;
console.log(chalk.green(` ✓ Analyzed ${complexityStats.total} files`));
console.log(chalk.green(` ✓ Complexity: ${complexityStats.high} high, ${complexityStats.medium} medium, ${complexityStats.low} low`));
} else {
console.log(chalk.dim(' ⏭️ AST parser not available, skipping'));
}
} catch (e) {
console.log(chalk.yellow(` ⚠ Complexity analysis skipped: ${e.message}`));
}
// Phase 6: Analyze diff patterns from recent commits
console.log(chalk.yellow('\n🔄 Phase 6: Analyzing diff patterns for change classification...\n'));
try {
const diffMod = require('../dist/core/diff-embeddings.js');
const recentCommits = execSync(`git log --format="%H" -n 20 2>/dev/null`, { encoding: 'utf-8' }).trim().split('\n').filter(h => h);
let changeTypes = { feature: 0, bugfix: 0, refactor: 0, docs: 0, test: 0, config: 0, unknown: 0 };
for (const hash of recentCommits.slice(0, 10)) {
try {
const analysis = await diffMod.analyzeCommit(hash);
analysis.files.forEach(f => {
changeTypes[f.category] = (changeTypes[f.category] || 0) + 1;
});
} catch (e) { /* skip */ }
}
intel.data.changePatterns = changeTypes;
stats.changePatterns = changeTypes;
console.log(chalk.green(` ✓ Analyzed ${recentCommits.length} commits`));
console.log(chalk.green(` ✓ Change types: ${Object.entries(changeTypes).filter(([,v]) => v > 0).map(([k,v]) => `${k}:${v}`).join(', ')}`));
} catch (e) {
console.log(chalk.yellow(` ⚠ Diff analysis skipped: ${e.message}`));
}
// Phase 7: Check test coverage if available
console.log(chalk.yellow('\n🧪 Phase 7: Checking test coverage data...\n'));
try {
const covMod = require('../dist/core/coverage-router.js');
const reportPath = covMod.findCoverageReport();
if (reportPath) {
const summary = covMod.parseIstanbulCoverage(reportPath);
intel.data.coverage = {
overall: summary.overall,
lowCoverageFiles: summary.lowCoverageFiles.slice(0, 20),
uncoveredFiles: summary.uncoveredFiles.slice(0, 10)
};
stats.coverage = summary.overall;
console.log(chalk.green(` ✓ Found coverage report: ${reportPath}`));
console.log(chalk.green(` ✓ Overall: Lines ${summary.overall.lines.toFixed(1)}%, Functions ${summary.overall.functions.toFixed(1)}%`));
console.log(chalk.green(` ✓ ${summary.lowCoverageFiles.length} low-coverage files, ${summary.uncoveredFiles.length} uncovered`));
} else {
console.log(chalk.dim(' ⏭️ No coverage report found'));
}
} catch (e) {
console.log(chalk.yellow(` ⚠ Coverage check skipped: ${e.message}`));
}
// Phase 8: Detect available attention/GNN capabilities
console.log(chalk.yellow('\n🧠 Phase 8: Detecting neural capabilities...\n'));
try {
let capabilities = { attention: false, gnn: false, mechanisms: [] };
try {
const attention = require('@ruvector/attention');
capabilities.attention = true;
capabilities.mechanisms = [
'DotProductAttention', 'MultiHeadAttention', 'FlashAttention',
'HyperbolicAttention', 'LinearAttention', 'MoEAttention',
'GraphRoPeAttention', 'DualSpaceAttention', 'LocalGlobalAttention'
];
console.log(chalk.green(` ✓ Attention: 10 mechanisms available`));
} catch (e) {
console.log(chalk.dim(' ⏭️ @ruvector/attention not installed'));
}
try {
const gnn = require('@ruvector/gnn');
capabilities.gnn = true;
console.log(chalk.green(` ✓ GNN: RuvectorLayer, TensorCompress available`));
} catch (e) {
console.log(chalk.dim(' ⏭️ @ruvector/gnn not installed'));
}
intel.data.neuralCapabilities = capabilities;
stats.neural = capabilities;
} catch (e) {
console.log(chalk.yellow(` ⚠ Neural detection skipped: ${e.message}`));
}
// Phase 9: Build code graph for community detection
console.log(chalk.yellow('\n🔗 Phase 9: Building code relationship graph...\n'));
try {
const graphMod = require('../dist/core/graph-algorithms.js');
const codeFiles = execSync('git ls-files "*.ts" "*.js" 2>/dev/null || echo ""', { encoding: 'utf-8' }).trim().split('\n').filter(f => f);
if (codeFiles.length > 5 && codeFiles.length < 200) {
const nodes = codeFiles.map(f => path.basename(f, path.extname(f)));
const edges = [];
for (const file of codeFiles.slice(0, 100)) {
try {
if (!fs.existsSync(file)) continue;
const content = fs.readFileSync(file, 'utf-8');
const imports = content.match(/from ['"]\.\/([^'"]+)['"]/g) || [];
imports.forEach(imp => {
const target = imp.match(/from ['"]\.\/([^'"]+)['"]/)?.[1];
if (target) {
const targetBase = path.basename(target, path.extname(target));
if (nodes.includes(targetBase)) {
edges.push({ source: path.basename(file, path.extname(file)), target: targetBase, weight: 1 });
}
}
});
} catch (e) { /* skip */ }
}
if (edges.length > 0) {
const communities = graphMod.louvainCommunities(nodes, edges);
intel.data.codeGraph = {
nodes: nodes.length,
edges: edges.length,
communities: communities.numCommunities,
modularity: communities.modularity
};
stats.graph = intel.data.codeGraph;
console.log(chalk.green(` ✓ Built graph: ${nodes.length} nodes, ${edges.length} edges`));
console.log(chalk.green(` ✓ Found ${communities.numCommunities} communities (modularity: ${communities.modularity.toFixed(3)})`));
} else {
console.log(chalk.dim(' ⏭️ Not enough import relationships found'));
}
} else {
console.log(chalk.dim(` ⏭️ Skipped (${codeFiles.length} files - need 5-200)`));
}
} catch (e) {
console.log(chalk.yellow(` ⚠ Graph analysis skipped: ${e.message}`));
}
// Phase 10: Initialize multi-algorithm learning engine
console.log(chalk.yellow('\n🎯 Phase 10: Initializing multi-algorithm learning engine...\n'));
try {
if (loadLearningModules() && LearningEngineClass) {
const engine = new LearningEngineClass();
// Configure optimal algorithms for each task type based on repo analysis
engine.configure('agent-routing', { algorithm: 'double-q', learningRate: 0.1, epsilon: 0.1 });
engine.configure('error-avoidance', { algorithm: 'sarsa', learningRate: 0.05, epsilon: 0.05 });
engine.configure('confidence-scoring', { algorithm: 'actor-critic', learningRate: 0.01 });
engine.configure('trajectory-learning', { algorithm: 'decision-transformer', sequenceLength: 20 });
engine.configure('context-ranking', { algorithm: 'ppo', clipRange: 0.2 });
engine.configure('memory-recall', { algorithm: 'td-lambda', lambda: 0.8 });
// Bootstrap with initial experiences from file patterns
let bootstrapCount = 0;
for (const [state, actions] of Object.entries(intel.data.patterns || {})) {
for (const [action, value] of Object.entries(actions)) {
if (value > 0.3) { // Only strong patterns
engine.update('agent-routing', {
state,
action,
reward: value,
nextState: state,
done: true
});
bootstrapCount++;
}
}
}
intel.data.learning = engine.export();
stats.learningBootstrap = bootstrapCount;
console.log(chalk.green(` ✓ Configured 6 task-specific algorithms`));
console.log(chalk.green(` ✓ Bootstrapped with ${bootstrapCount} initial experiences`));
console.log(chalk.dim(' Algorithms: double-q, sarsa, actor-critic, decision-transformer, ppo, td-lambda'));
} else {
console.log(chalk.dim(' ⏭️ LearningEngine not available'));
}
} catch (e) {
console.log(chalk.yellow(` ⚠ Learning engine init skipped: ${e.message}`));
}
// Phase 11: Initialize TensorCompress for pattern storage
console.log(chalk.yellow('\n📦 Phase 11: Initializing TensorCompress for efficient storage...\n'));
try {
if (loadLearningModules() && TensorCompressClass) {
const compress = new TensorCompressClass({
autoCompress: false,
hotThreshold: 0.8,
warmThreshold: 0.4,
coolThreshold: 0.1,
coldThreshold: 0.01
});
// Store any existing embeddings with compression
let compressed = 0;
if (intel.data.memories) {
for (let i = 0; i < intel.data.memories.length; i++) {
const mem = intel.data.memories[i];
if (mem.embedding && Array.isArray(mem.embedding)) {
compress.store(`memory_${i}`, mem.embedding, 'pq8');
compressed++;
}
}
}
if (compressed > 0) {
const compStats = compress.recompressAll();
intel.data.compressedPatterns = compress.export();
stats.compressed = compressed;
stats.compressionSavings = compStats.savingsPercent;
console.log(chalk.green(` ✓ Compressed ${compressed} embeddings`));
console.log(chalk.green(` ✓ Memory savings: ${compStats.savingsPercent.toFixed(1)}%`));
} else {
intel.data.compressedPatterns = compress.export();
console.log(chalk.green(` ✓ TensorCompress initialized (ready for future embeddings)`));
}
console.log(chalk.dim(' Levels: none (hot), half (warm), pq8 (cool), pq4 (cold), binary (archive)'));
} else {
console.log(chalk.dim(' ⏭️ TensorCompress not available'));
}
} catch (e) {
console.log(chalk.yellow(` ⚠ TensorCompress init skipped: ${e.message}`));
}
// Save all learning data
intel.data.pretrained = {
date: new Date().toISOString(),
version: '2.1',
stats: stats
};
intel.save();
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
console.log(chalk.bold.green(`\n✅ Pretrain complete in ${elapsed}s!\n`));
console.log(chalk.cyan('Summary:'));
console.log(` 📁 ${stats.files} files analyzed`);
console.log(` 🧠 ${stats.patterns} agent routing patterns`);
console.log(` 🔗 ${stats.coedits} co-edit patterns`);
console.log(` 💾 ${stats.memories} memory entries`);
if (stats.complexity) console.log(` 📊 ${stats.complexity.total} files analyzed for complexity`);
if (stats.changePatterns) console.log(` 🔄 Change patterns detected`);
if (stats.coverage) console.log(` 🧪 Coverage: ${stats.coverage.lines.toFixed(1)}% lines`);
if (stats.neural?.attention) console.log(` 🧠 10 attention mechanisms available`);
if (stats.graph) console.log(` 🔗 ${stats.graph.communities} code communities detected`);
if (stats.learningBootstrap) console.log(` 🎯 ${stats.learningBootstrap} learning experiences bootstrapped`);
if (stats.compressionSavings) console.log(` 📦 ${stats.compressionSavings.toFixed(1)}% compression savings`);
console.log(chalk.dim('\nThe intelligence layer will now provide better recommendations.'));
});
// Agent Builder - generate optimized agent configs based on pretrain
hooksCmd.command('build-agents')
.description('Generate optimized agent configurations based on repository analysis')
.option('--focus <type>', 'Focus type: quality, speed, security, testing, fullstack', 'quality')
.option('--output <dir>', 'Output directory', '.claude/agents')
.option('--format <fmt>', 'Format: yaml, json, md', 'yaml')
.option('--include-prompts', 'Include detailed system prompts')
.action((opts) => {
console.log(chalk.bold.cyan('\n🏗️ RuVector Agent Builder\n'));
const intel = new Intelligence();
const outputDir = path.join(process.cwd(), opts.output);
// Check if pretrained
if (!intel.data.pretrained && Object.keys(intel.data.patterns || {}).length === 0) {
console.log(chalk.yellow('⚠️ No pretrain data found. Running quick analysis...\n'));
// Quick file analysis
try {
const { execSync } = require('child_process');
const files = execSync('git ls-files 2>/dev/null', { encoding: 'utf-8' }).trim().split('\n');
files.forEach(f => {
const ext = path.extname(f);
intel.data.patterns = intel.data.patterns || {};
intel.data.patterns[`edit:${ext}`] = intel.data.patterns[`edit:${ext}`] || {};
});
} catch (e) { /* continue without git */ }
}
// Analyze patterns to determine relevant agents
const patterns = intel.data.patterns || {};
const detectedLangs = new Set();
const detectedFrameworks = new Set();
Object.keys(patterns).forEach(state => {
if (state.includes('.rs')) detectedLangs.add('rust');
if (state.includes('.ts') || state.includes('.js')) detectedLangs.add('typescript');
if (state.includes('.tsx') || state.includes('.jsx')) detectedFrameworks.add('react');
if (state.includes('.py')) detectedLangs.add('python');
if (state.includes('.go')) detectedLangs.add('go');
if (state.includes('.vue')) detectedFrameworks.add('vue');
if (state.includes('.sql')) detectedFrameworks.add('database');
});
// Detect project type from files
const projectTypes = detectProjectType();
console.log(chalk.blue(` Detected languages: ${[...detectedLangs].join(', ') || 'generic'}`));
console.log(chalk.blue(` Detected frameworks: ${[...detectedFrameworks].join(', ') || 'none'}`));
console.log(chalk.blue(` Focus mode: ${opts.focus}\n`));
// Focus configurations
const focusConfigs = {
quality: {
description: 'Emphasizes code quality, best practices, and maintainability',
priorities: ['code-review', 'refactoring', 'documentation', 'testing'],
temperature: 0.3
},
speed: {
description: 'Optimized for rapid development and iteration',
priorities: ['implementation', 'prototyping', 'quick-fixes'],
temperature: 0.7
},
security: {
description: 'Security-first development with vulnerability awareness',
priorities: ['security-audit', 'input-validation', 'authentication', 'encryption'],
temperature: 0.2
},
testing: {
description: 'Test-driven development with comprehensive coverage',
priorities: ['unit-tests', 'integration-tests', 'e2e-tests', 'mocking'],
temperature: 0.4
},
fullstack: {
description: 'Balanced full-stack development capabilities',
priorities: ['frontend', 'backend', 'database', 'api-design'],
temperature: 0.5
}
};
const focus = focusConfigs[opts.focus] || focusConfigs.quality;
// Agent templates based on detected stack
const agents = [];
// Core agents based on detected languages
if (detectedLangs.has('rust')) {
agents.push({
name: 'rust-specialist',
type: 'rust-developer',
description: 'Rust development specialist for this codebase',
capabilities: ['cargo', 'unsafe-rust', 'async-rust', 'wasm', 'error-handling'],
focus: focus.priorities,
systemPrompt: opts.includePrompts ? `You are a Rust specialist for this project.
Focus on: memory safety, zero-cost abstractions, idiomatic Rust patterns.
Use cargo conventions, prefer Result over panic, leverage the type system.
${focus.description}` : null
});
}
if (detectedLangs.has('typescript')) {
agents.push({
name: 'typescript-specialist',
type: 'typescript-developer',
description: 'TypeScript development specialist',
capabilities: ['types', 'generics', 'decorators', 'async-await', 'modules'],
focus: focus.priorities,
systemPrompt: opts.includePrompts ? `You are a TypeScript specialist for this project.
Focus on: strict typing, type inference, generic patterns, module organization.
Prefer type safety over any, use discriminated unions, leverage utility types.
${focus.description}` : null
});
}
if (detectedLangs.has('python')) {
agents.push({
name: 'python-specialist',
type: 'python-developer',
description: 'Python development specialist',
capabilities: ['typing', 'async', 'testing', 'packaging', 'data-science'],
focus: focus.priorities,
systemPrompt: opts.includePrompts ? `You are a Python specialist for this project.
Focus on: type hints, PEP standards, pythonic idioms, virtual environments.
Use dataclasses, prefer pathlib, leverage context managers.
${focus.description}` : null
});
}
if (detectedLangs.has('go')) {
agents.push({
name: 'go-specialist',
type: 'go-developer',
description: 'Go development specialist',
capabilities: ['goroutines', 'channels', 'interfaces', 'testing', 'modules'],
focus: focus.priorities,
systemPrompt: opts.includePrompts ? `You are a Go specialist for this project.
Focus on: simplicity, explicit error handling, goroutines, interface composition.
Follow Go conventions, use go fmt, prefer composition over inheritance.
${focus.description}` : null
});
}
// Framework-specific agents
if (detectedFrameworks.has('react')) {
agents.push({
name: 'react-specialist',
type: 'react-developer',
description: 'React/Next.js development specialist',
capabilities: ['hooks', 'state-management', 'components', 'ssr', 'testing'],
focus: focus.priorities,
systemPrompt: opts.includePrompts ? `You are a React specialist for this project.
Focus on: functional components, hooks, state management, performance optimization.
Prefer composition, use memo wisely, follow React best practices.
${focus.description}` : null
});
}
if (detectedFrameworks.has('database')) {
agents.push({
name: 'database-specialist',
type: 'database-specialist',
description: 'Database design and optimization specialist',
capabilities: ['schema-design', 'queries', 'indexing', 'migrations', 'orm'],
focus: focus.priorities,
systemPrompt: opts.includePrompts ? `You are a database specialist for this project.
Focus on: normalized schemas, efficient queries, proper indexing, data integrity.
Consider performance implications, use transactions appropriately.
${focus.description}` : null
});
}
// Focus-specific agents
if (opts.focus === 'testing' || opts.focus === 'quality') {
agents.push({
name: 'test-architect',
type: 'test-engineer',
description: 'Testing and quality assurance specialist',
capabilities: ['unit-tests', 'integration-tests', 'mocking', 'coverage', 'tdd'],
focus: ['testing', 'quality', 'reliability'],
systemPrompt: opts.includePrompts ? `You are a testing specialist for this project.
Focus on: comprehensive test coverage, meaningful assertions, test isolation.
Write tests first when possible, mock external dependencies, aim for >80% coverage.
${focus.description}` : null
});
}
if (opts.focus === 'security') {
agents.push({
name: 'security-auditor',
type: 'security-specialist',
description: 'Security audit and hardening specialist',
capabilities: ['vulnerability-scan', 'auth', 'encryption', 'input-validation', 'owasp'],
focus: ['security', 'compliance', 'hardening'],
systemPrompt: opts.includePrompts ? `You are a security specialist for this project.
Focus on: OWASP top 10, input validation, authentication, authorization, encryption.
Never trust user input, use parameterized queries, implement defense in depth.
${focus.description}` : null
});
}
// Add coordinator agent
agents.push({
name: 'project-coordinator',
type: 'coordinator',
description: 'Coordinates multi-agent workflows for this project',
capabilities: ['task-decomposition', 'agent-routing', 'context-management'],
focus: focus.priorities,
routes: agents.filter(a => a.name !== 'project-coordinator').map(a => ({
pattern: a.capabilities[0],
agent: a.name
}))
});
// Create output directory
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// Generate agent files
agents.forEach(agent => {
let content;
const filename = `${agent.name}.${opts.format}`;
const filepath = path.join(outputDir, filename);
if (opts.format === 'yaml') {
const yaml = [
`# Auto-generated by RuVector Agent Builder`,
`# Focus: ${opts.focus}`,
`# Generated: ${new Date().toISOString()}`,
``,
`name: ${agent.name}`,
`type: ${agent.type}`,
`description: ${agent.description}`,
``,
`capabilities:`,
...agent.capabilities.map(c => ` - ${c}`),
``,
`focus:`,
...agent.focus.map(f => ` - ${f}`),
];
if (agent.systemPrompt) {
yaml.push(``, `system_prompt: |`);
agent.systemPrompt.split('\n').forEach(line => yaml.push(` ${line}`));
}
if (agent.routes) {
yaml.push(``, `routes:`);
agent.routes.forEach(r => yaml.push(` - pattern: "${r.pattern}"`, ` agent: ${r.agent}`));
}
content = yaml.join('\n');
} else if (opts.format === 'json') {
content = JSON.stringify(agent, null, 2);
} else {
// Markdown format
content = [
`# ${agent.name}`,
``,
`**Type:** ${agent.type}`,
`**Description:** ${agent.description}`,
``,
`## Capabilities`,
...agent.capabilities.map(c => `- ${c}`),
``,
`## Focus Areas`,
...agent.focus.map(f => `- ${f}`),
].join('\n');
if (agent.systemPrompt) {
content += `\n\n## System Prompt\n\n\`\`\`\n${agent.systemPrompt}\n\`\`\``;
}
}
fs.writeFileSync(filepath, content);
console.log(chalk.green(` ✓ Created ${filename}`));
});
// Create index file
const indexContent = opts.format === 'yaml'
? `# RuVector Agent Configuration\n# Focus: ${opts.focus}\n\nagents:\n${agents.map(a => ` - ${a.name}`).join('\n')}`
: JSON.stringify({ focus: opts.focus, agents: agents.map(a => a.name) }, null, 2);
fs.writeFileSync(path.join(outputDir, `index.${opts.format === 'md' ? 'json' : opts.format}`), indexContent);
// Update settings to reference agents
const settingsPath = path.join(process.cwd(), '.claude', 'settings.json');
if (fs.existsSync(settingsPath)) {
try {
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
settings.agentConfig = {
directory: opts.output,
focus: opts.focus,
agents: agents.map(a => a.name),
generated: new Date().toISOString()
};
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
console.log(chalk.blue('\n ✓ Updated .claude/settings.json with agent config'));
} catch (e) { /* ignore settings errors */ }
}
console.log(chalk.bold.green(`\n✅ Generated ${agents.length} optimized agents in ${opts.output}/\n`));
console.log(chalk.cyan('Agents created:'));
agents.forEach(a => {
console.log(` 🤖 ${chalk.bold(a.name)}: ${a.description}`);
});
console.log(chalk.dim(`\nFocus mode "${opts.focus}": ${focus.description}`));
});
// Workers command group - Background analysis via agentic-flow
const workersCmd = program.command('workers').description('Background analysis workers (via agentic-flow)');
// Helper to run agentic-flow workers command
async function runAgenticFlow(args) {
const { spawn } = require('child_process');
return new Promise((resolve, reject) => {
const proc = spawn('npx', ['agentic-flow@alpha', ...args], {
stdio: 'inherit',
shell: true
});
proc.on('close', code => code === 0 ? resolve() : reject(new Error(`Exit code ${code}`)));
proc.on('error', reject);
});
}
workersCmd.command('dispatch')
.description('Dispatch background worker for analysis')
.argument('<prompt...>', 'Prompt with trigger keyword (ultralearn, optimize, audit, map, etc.)')
.action(async (prompt) => {
try {
await runAgenticFlow(['workers', 'dispatch', prompt.join(' ')]);
} catch (e) {
console.error(chalk.red('Worker dispatch failed:'), e.message);
}
});
workersCmd.command('status')
.description('Show worker status dashboard')
.argument('[workerId]', 'Specific worker ID')
.action(async (workerId) => {
try {
const args = ['workers', 'status'];
if (workerId) args.push(workerId);
await runAgenticFlow(args);
} catch (e) {
console.error(chalk.red('Status check failed:'), e.message);
}
});
workersCmd.command('results')
.description('Show worker analysis results')
.option('--json', 'Output as JSON')
.action(async (opts) => {
try {
const args = ['workers', 'results'];
if (opts.json) args.push('--json');
await runAgenticFlow(args);
} catch (e) {
console.error(chalk.red('Results fetch failed:'), e.message);
}
});
workersCmd.command('triggers')
.description('List available trigger keywords')
.action(async () => {
try {
await runAgenticFlow(['workers', 'triggers']);
} catch (e) {
console.error(chalk.red('Triggers list failed:'), e.message);
}
});
workersCmd.command('stats')
.description('Show worker statistics (24h)')
.action(async () => {
try {
await runAgenticFlow(['workers', 'stats']);
} catch (e) {
console.error(chalk.red('Stats failed:'), e.message);
}
});
workersCmd.command('cleanup')
.description('Cleanup old worker records')
.option('--keep <days>', 'Keep records for N days', '7')
.action(async (opts) => {
try {
await runAgenticFlow(['workers', 'cleanup', '--keep', opts.keep]);
} catch (e) {
console.error(chalk.red('Cleanup failed:'), e.message);
}
});
workersCmd.command('cancel')
.description('Cancel a running worker')
.argument('<workerId>', 'Worker ID to cancel')
.action(async (workerId) => {
try {
await runAgenticFlow(['workers', 'cancel', workerId]);
} catch (e) {
console.error(chalk.red('Cancel failed:'), e.message);
}
});
// Custom Worker System (agentic-flow@alpha.39+)
workersCmd.command('presets')
.description('List available worker presets (quick-scan, deep-analysis, security-scan, etc.)')
.action(async () => {
try {
await runAgenticFlow(['workers', 'presets']);
} catch (e) {
console.error(chalk.red('Presets list failed:'), e.message);
}
});
workersCmd.command('phases')
.description('List available phase executors (24 phases: file-discovery, security-analysis, etc.)')
.action(async () => {
try {
await runAgenticFlow(['workers', 'phases']);
} catch (e) {
console.error(chalk.red('Phases list failed:'), e.message);
}
});
workersCmd.command('create')
.description('Create a custom worker from preset')
.argument('<name>', 'Worker name')
.option('--preset <preset>', 'Base preset (quick-scan, deep-analysis, security-scan, learning, api-docs, test-analysis)')
.option('--triggers <triggers>', 'Comma-separated trigger keywords')
.action(async (name, opts) => {
try {
const args = ['workers', 'create', name];
if (opts.preset) args.push('--preset', opts.preset);
if (opts.triggers) args.push('--triggers', opts.triggers);
await runAgenticFlow(args);
} catch (e) {
console.error(chalk.red('Worker creation failed:'), e.message);
}
});
workersCmd.command('run')
.description('Run a custom worker')
.argument('<name>', 'Worker name')
.option('--path <path>', 'Target path to analyze', '.')
.action(async (name, opts) => {
try {
const args = ['workers', 'run', name];
if (opts.path) args.push('--path', opts.path);
await runAgenticFlow(args);
} catch (e) {
console.error(chalk.red('Worker run failed:'), e.message);
}
});
workersCmd.command('custom')
.description('List registered custom workers')
.action(async () => {
try {
await runAgenticFlow(['workers', 'custom']);
} catch (e) {
console.error(chalk.red('Custom workers list failed:'), e.message);
}
});
workersCmd.command('init-config')
.description('Generate example workers.yaml config file')
.option('--force', 'Overwrite existing config')
.action(async (opts) => {
try {
const args = ['workers', 'init-config'];
if (opts.force) args.push('--force');
await runAgenticFlow(args);
} catch (e) {
console.error(chalk.red('Config init failed:'), e.message);
}
});
workersCmd.command('load-config')
.description('Load custom workers from workers.yaml')
.option('--file <file>', 'Config file path', 'workers.yaml')
.action(async (opts) => {
try {
const args = ['workers', 'load-config'];
if (opts.file !== 'workers.yaml') args.push('--file', opts.file);
await runAgenticFlow(args);
} catch (e) {
console.error(chalk.red('Config load failed:'), e.message);
}
});
console.log && false; // Force registration
// Native Workers command group - Deep ruvector integration (no agentic-flow delegation)
const nativeCmd = program.command('native').description('Native workers with deep ONNX/VectorDB integration (no external deps)');
nativeCmd.command('run')
.description('Run a native worker type')
.argument('<type>', 'Worker type: security, analysis, learning')
.option('--path <path>', 'Target path to analyze', '.')
.option('--json', 'Output as JSON')
.action(async (type, opts) => {
try {
const { createSecurityWorker, createAnalysisWorker, createLearningWorker } = require('../dist/workers/native-worker.js');
let worker;
switch (type) {
case 'security':
worker = createSecurityWorker();
break;
case 'analysis':
worker = createAnalysisWorker();
break;
case 'learning':
worker = createLearningWorker();
break;
default:
console.error(chalk.red(`Unknown worker type: ${type}`));
console.log(chalk.dim('Available types: security, analysis, learning'));
return;
}
console.log(chalk.cyan(`\n🔧 Running native ${type} worker on ${opts.path}...\n`));
const result = await worker.run(opts.path);
if (opts.json) {
console.log(JSON.stringify(result, null, 2));
} else {
console.log(chalk.bold(`Worker: ${result.worker}`));
console.log(chalk.dim(`Status: ${result.success ? chalk.green('✓ Success') : chalk.red('✗ Failed')}`));
console.log(chalk.dim(`Time: ${result.totalTimeMs.toFixed(0)}ms\n`));
console.log(chalk.bold('Phases:'));
for (const phase of result.phases) {
const status = phase.success ? chalk.green('✓') : chalk.red('✗');
console.log(` ${status} ${phase.phase} (${phase.timeMs.toFixed(0)}ms)`);
if (phase.data) {
const dataStr = JSON.stringify(phase.data);
if (dataStr.length < 100) {
console.log(chalk.dim(` ${dataStr}`));
}
}
}
if (result.summary) {
console.log(chalk.bold('\nSummary:'));
console.log(` Files analyzed: ${result.summary.filesAnalyzed}`);
console.log(` Patterns found: ${result.summary.patternsFound}`);
console.log(` Embeddings: ${result.summary.embeddingsGenerated}`);
console.log(` Vectors stored: ${result.summary.vectorsStored}`);
if (result.summary.findings.length > 0) {
console.log(chalk.bold('\nFindings:'));
const byType = { info: 0, warning: 0, error: 0, security: 0 };
result.summary.findings.forEach(f => byType[f.type]++);
if (byType.security > 0) console.log(chalk.red(` 🔒 Security: ${byType.security}`));
if (byType.error > 0) console.log(chalk.red(` ❌ Errors: ${byType.error}`));
if (byType.warning > 0) console.log(chalk.yellow(` ⚠️ Warnings: ${byType.warning}`));
if (byType.info > 0) console.log(chalk.blue(` ℹ️ Info: ${byType.info}`));
// Show top findings
console.log(chalk.dim('\nTop findings:'));
result.summary.findings.slice(0, 5).forEach(f => {
const icon = f.type === 'security' ? '🔒' : f.type === 'warning' ? '⚠️' : 'ℹ️';
console.log(chalk.dim(` ${icon} ${f.message.slice(0, 60)}${f.file ? ` (${path.basename(f.file)})` : ''}`));
});
}
}
}
} catch (e) {
console.error(chalk.red('Native worker failed:'), e.message);
if (e.stack) console.error(chalk.dim(e.stack));
}
});
nativeCmd.command('benchmark')
.description('Run performance benchmark suite')
.option('--path <path>', 'Target path for worker benchmarks', '.')
.option('--embeddings-only', 'Only benchmark embeddings')
.option('--workers-only', 'Only benchmark workers')
.action(async (opts) => {
try {
const benchmark = require('../dist/workers/benchmark.js');
if (opts.embeddingsOnly) {
console.log(chalk.cyan('\n📊 Benchmarking ONNX Embeddings...\n'));
const results = await benchmark.benchmarkEmbeddings(10);
console.log(benchmark.formatBenchmarkResults(results));
} else if (opts.workersOnly) {
console.log(chalk.cyan('\n🔧 Benchmarking Native Workers...\n'));
const results = await benchmark.benchmarkWorkers(opts.path);
console.log(benchmark.formatBenchmarkResults(results));
} else {
await benchmark.runFullBenchmark(opts.path);
}
} catch (e) {
console.error(chalk.red('Benchmark failed:'), e.message);
if (e.stack) console.error(chalk.dim(e.stack));
}
});
nativeCmd.command('list')
.description('List available native worker types')
.action(() => {
console.log(chalk.cyan('\n🔧 Native Worker Types\n'));
console.log(chalk.bold('security'));
console.log(chalk.dim(' Security vulnerability scanner'));
console.log(chalk.dim(' Phases: file-discovery → security-scan → summarization'));
console.log(chalk.dim(' No ONNX/VectorDB required\n'));
console.log(chalk.bold('analysis'));
console.log(chalk.dim(' Full code analysis with embeddings'));
console.log(chalk.dim(' Phases: file-discovery → pattern-extraction → embedding-generation'));
console.log(chalk.dim(' → vector-storage → complexity-analysis → summarization'));
console.log(chalk.dim(' Requires: ONNX embedder, VectorDB\n'));
console.log(chalk.bold('learning'));
console.log(chalk.dim(' Pattern learning with vector storage'));
console.log(chalk.dim(' Phases: file-discovery → pattern-extraction → embedding-generation'));
console.log(chalk.dim(' → vector-storage → summarization'));
console.log(chalk.dim(' Requires: ONNX embedder, VectorDB, Intelligence memory\n'));
console.log(chalk.bold('Available Phases:'));
const phases = [
'file-discovery', 'pattern-extraction', 'embedding-generation',
'vector-storage', 'similarity-search', 'security-scan',
'complexity-analysis', 'summarization'
];
phases.forEach(p => console.log(chalk.dim(` • ${p}`)));
});
nativeCmd.command('compare')
.description('Compare ruvector native vs agentic-flow workers')
.option('--path <path>', 'Target path for benchmarks', '.')
.option('--iterations <n>', 'Number of iterations', '5')
.action(async (opts) => {
const iterations = parseInt(opts.iterations) || 5;
console.log(chalk.cyan('\n╔════════════════════════════════════════════════════════════════╗'));
console.log(chalk.cyan('║ Worker System Comparison Benchmark ║'));
console.log(chalk.cyan('╚════════════════════════════════════════════════════════════════╝\n'));
try {
const { performance } = require('perf_hooks');
const benchmark = require('../dist/workers/benchmark.js');
const { createSecurityWorker, createAnalysisWorker } = require('../dist/workers/native-worker.js');
// Test 1: Native Security Worker
console.log(chalk.yellow('1. Native Security Worker'));
const securityTimes = [];
const securityWorker = createSecurityWorker();
for (let i = 0; i < iterations; i++) {
const start = performance.now();
await securityWorker.run(opts.path);
securityTimes.push(performance.now() - start);
}
const secAvg = securityTimes.reduce((a, b) => a + b) / securityTimes.length;
console.log(chalk.dim(` Avg: ${secAvg.toFixed(1)}ms (${iterations} runs)`));
// Test 2: Native Analysis Worker
console.log(chalk.yellow('\n2. Native Analysis Worker (ONNX + VectorDB)'));
const analysisTimes = [];
const analysisWorker = createAnalysisWorker();
for (let i = 0; i < Math.min(iterations, 3); i++) {
const start = performance.now();
await analysisWorker.run(opts.path);
analysisTimes.push(performance.now() - start);
}
const anaAvg = analysisTimes.reduce((a, b) => a + b) / analysisTimes.length;
console.log(chalk.dim(` Avg: ${anaAvg.toFixed(1)}ms (${Math.min(iterations, 3)} runs)`));
// Test 3: agentic-flow workers (if available)
let agenticAvailable = false;
let agenticSecAvg = 0;
let agenticAnaAvg = 0;
try {
const agentic = require('agentic-flow');
agenticAvailable = true;
console.log(chalk.yellow('\n3. agentic-flow Security Worker'));
// Note: Would need actual agentic-flow integration here
console.log(chalk.dim(' (Integration pending - use agentic-flow CLI directly)'));
} catch (e) {
console.log(chalk.yellow('\n3. agentic-flow Workers'));
console.log(chalk.dim(' Not installed (npm i agentic-flow@alpha)'));
}
// Summary
console.log(chalk.cyan('\n═══════════════════════════════════════════════════════════════'));
console.log(chalk.bold('Summary'));
console.log(chalk.cyan('═══════════════════════════════════════════════════════════════'));
console.log(chalk.white('\nNative RuVector Workers:'));
console.log(chalk.dim(` Security scan: ${secAvg.toFixed(1)}ms avg`));
console.log(chalk.dim(` Full analysis: ${anaAvg.toFixed(1)}ms avg`));
if (agenticAvailable) {
console.log(chalk.white('\nagentic-flow Workers:'));
console.log(chalk.dim(' Security scan: (run: agentic-flow workers native security)'));
console.log(chalk.dim(' Full analysis: (run: agentic-flow workers native analysis)'));
}
console.log(chalk.white('\nArchitecture Benefits:'));
console.log(chalk.dim(' • Shared ONNX model cache (memory efficient)'));
console.log(chalk.dim(' • 7 native phases with deep integration'));
console.log(chalk.dim(' • SIMD-accelerated WASM embeddings'));
console.log(chalk.dim(' • HNSW vector indexing (150x faster search)'));
console.log('');
} catch (e) {
console.error(chalk.red('Comparison failed:'), e.message);
if (opts.verbose) console.error(chalk.dim(e.stack));
}
});
// RVF (RuVector Format) commands
const rvfCmd = program.command('rvf').description('RuVector Format (.rvf) cognitive container operations');
rvfCmd.command('create <path>')
.description('Create a new .rvf store')
.requiredOption('-d, --dimension <n>', 'Vector dimension', parseInt)
.option('-m, --metric <metric>', 'Distance metric (l2, cosine, dotproduct)', 'cosine')
.action(async (storePath, opts) => {
try {
const { createRvfStore, rvfClose } = require('../dist/core/rvf-wrapper.js');
const store = await createRvfStore(storePath, { dimensions: opts.dimension, metric: opts.metric });
await rvfClose(store);
console.log(chalk.green(`Created ${storePath} (dim=${opts.dimension}, metric=${opts.metric})`));
} catch (e) { console.error(chalk.red(e.message)); process.exit(1); }
});
rvfCmd.command('ingest <path>')
.description('Ingest vectors into an .rvf store')
.requiredOption('-i, --input <file>', 'Input file (JSON array of {id, vector})')
.option('-f, --format <fmt>', 'Input format (json)', 'json')
.action(async (storePath, opts) => {
try {
const { openRvfStore, rvfIngest, rvfClose } = require('../dist/core/rvf-wrapper.js');
const store = await openRvfStore(storePath);
const data = JSON.parse(fs.readFileSync(opts.input, 'utf8'));
const result = await rvfIngest(store, data);
await rvfClose(store);
console.log(chalk.green(`Ingested ${result.accepted} vectors (${result.rejected} rejected)`));
} catch (e) { console.error(chalk.red(e.message)); process.exit(1); }
});
rvfCmd.command('query <path>')
.description('Query nearest neighbors')
.requiredOption('-v, --vector <values>', 'Comma-separated vector values')
.option('-k, --k <n>', 'Number of results', parseInt, 10)
.action(async (storePath, opts) => {
try {
const { openRvfStore, rvfQuery, rvfClose } = require('../dist/core/rvf-wrapper.js');
const store = await openRvfStore(storePath);
const vector = opts.vector.split(',').map(Number);
const results = await rvfQuery(store, vector, opts.k);
await rvfClose(store);
results.forEach((r, i) => console.log(chalk.dim(` ${i+1}. id=${r.id} dist=${r.distance.toFixed(6)}`)));
console.log(chalk.green(`${results.length} results`));
} catch (e) { console.error(chalk.red(e.message)); process.exit(1); }
});
rvfCmd.command('status <path>')
.description('Show store statistics')
.action(async (storePath) => {
try {
const { openRvfStore, rvfStatus, rvfClose } = require('../dist/core/rvf-wrapper.js');
const store = await openRvfStore(storePath);
const s = await rvfStatus(store);
await rvfClose(store);
console.log(chalk.cyan('RVF Store Status'));
Object.entries(s).forEach(([k, v]) => console.log(chalk.dim(` ${k}: ${v}`)));
} catch (e) { console.error(chalk.red(e.message)); process.exit(1); }
});
rvfCmd.command('segments <path>')
.description('List all segments in an .rvf file')
.action(async (storePath) => {
try {
const { openRvfStore, rvfClose } = require('../dist/core/rvf-wrapper.js');
const store = await openRvfStore(storePath);
const segs = await store.segments();
await rvfClose(store);
segs.forEach((seg, i) => console.log(chalk.dim(` [${i}] type=0x${seg.type.toString(16)} size=${seg.size}`)));
console.log(chalk.green(`${segs.length} segments`));
} catch (e) { console.error(chalk.red(e.message)); process.exit(1); }
});
rvfCmd.command('derive <parent> <child>')
.description('Create a derived store with lineage tracking')
.action(async (parentPath, childPath) => {
try {
const { openRvfStore, rvfDerive, rvfClose } = require('../dist/core/rvf-wrapper.js');
const store = await openRvfStore(parentPath);
await rvfDerive(store, childPath);
await rvfClose(store);
console.log(chalk.green(`Derived ${childPath} from ${parentPath}`));
} catch (e) { console.error(chalk.red(e.message)); process.exit(1); }
});
rvfCmd.command('compact <path>')
.description('Compact store, reclaim deleted space')
.action(async (storePath) => {
try {
const { openRvfStore, rvfCompact, rvfClose } = require('../dist/core/rvf-wrapper.js');
const store = await openRvfStore(storePath);
const result = await rvfCompact(store);
await rvfClose(store);
console.log(chalk.green(`Compacted: ${result.segmentsCompacted} segments, ${result.bytesReclaimed} bytes reclaimed`));
} catch (e) { console.error(chalk.red(e.message)); process.exit(1); }
});
rvfCmd.command('export <path>')
.description('Export store data')
.option('-o, --output <file>', 'Output file')
.action(async (storePath, opts) => {
try {
const { openRvfStore, rvfStatus, rvfClose } = require('../dist/core/rvf-wrapper.js');
const store = await openRvfStore(storePath);
const status = await rvfStatus(store);
const segs = await store.segments();
await rvfClose(store);
const data = JSON.stringify({ status, segments: segs }, null, 2);
if (opts.output) { fs.writeFileSync(opts.output, data); console.log(chalk.green(`Exported to ${opts.output}`)); }
else { console.log(data); }
} catch (e) { console.error(chalk.red(e.message)); process.exit(1); }
});
// RVF example download/list commands
const RVF_EXAMPLES = [
{ name: 'basic_store', size: '152 KB', desc: '1,000 vectors, dim 128, cosine metric' },
{ name: 'semantic_search', size: '755 KB', desc: 'Semantic search with HNSW index' },
{ name: 'rag_pipeline', size: '303 KB', desc: 'RAG pipeline with embeddings' },
{ name: 'embedding_cache', size: '755 KB', desc: 'Cached embedding store' },
{ name: 'quantization', size: '1.5 MB', desc: 'PQ-compressed vectors' },
{ name: 'progressive_index', size: '2.5 MB', desc: 'Large-scale progressive HNSW index' },
{ name: 'filtered_search', size: '255 KB', desc: 'Metadata-filtered vector search' },
{ name: 'recommendation', size: '102 KB', desc: 'Recommendation engine vectors' },
{ name: 'agent_memory', size: '32 KB', desc: 'AI agent episodic memory' },
{ name: 'swarm_knowledge', size: '86 KB', desc: 'Multi-agent shared knowledge base' },
{ name: 'experience_replay', size: '27 KB', desc: 'RL experience replay buffer' },
{ name: 'tool_cache', size: '26 KB', desc: 'MCP tool call cache' },
{ name: 'mcp_in_rvf', size: '32 KB', desc: 'MCP server embedded in RVF' },
{ name: 'ruvbot', size: '51 KB', desc: 'Chatbot knowledge store' },
{ name: 'claude_code_appliance', size: '17 KB', desc: 'Claude Code cognitive appliance' },
{ name: 'lineage_parent', size: '52 KB', desc: 'COW parent file' },
{ name: 'lineage_child', size: '26 KB', desc: 'COW child (derived) file' },
{ name: 'self_booting', size: '31 KB', desc: 'Self-booting with KERNEL_SEG' },
{ name: 'linux_microkernel', size: '15 KB', desc: 'Embedded Linux microkernel' },
{ name: 'ebpf_accelerator', size: '153 KB', desc: 'eBPF distance accelerator' },
{ name: 'browser_wasm', size: '14 KB', desc: 'Browser WASM module embedded' },
{ name: 'tee_attestation', size: '102 KB', desc: 'TEE attestation with witnesses' },
{ name: 'zero_knowledge', size: '52 KB', desc: 'ZK-proof witness chain' },
{ name: 'sealed_engine', size: '208 KB', desc: 'Sealed inference engine' },
{ name: 'access_control', size: '77 KB', desc: 'Permission-gated vectors' },
{ name: 'financial_signals', size: '202 KB', desc: 'Financial signal vectors' },
{ name: 'medical_imaging', size: '302 KB', desc: 'Medical imaging embeddings' },
{ name: 'legal_discovery', size: '903 KB', desc: 'Legal document discovery' },
{ name: 'multimodal_fusion', size: '804 KB', desc: 'Multi-modal embedding fusion' },
{ name: 'hyperbolic_taxonomy', size: '23 KB', desc: 'Hyperbolic space taxonomy' },
{ name: 'network_telemetry', size: '16 KB', desc: 'Network telemetry vectors' },
{ name: 'postgres_bridge', size: '152 KB', desc: 'PostgreSQL bridge vectors' },
{ name: 'ruvllm_inference', size: '133 KB', desc: 'RuvLLM inference cache' },
{ name: 'serverless', size: '509 KB', desc: 'Serverless deployment bundle' },
{ name: 'edge_iot', size: '27 KB', desc: 'Edge/IoT lightweight store' },
{ name: 'dedup_detector', size: '153 KB', desc: 'Deduplication detector' },
{ name: 'compacted', size: '77 KB', desc: 'Post-compaction example' },
{ name: 'posix_fileops', size: '52 KB', desc: 'POSIX file operations test' },
{ name: 'network_sync_a', size: '52 KB', desc: 'Network sync peer A' },
{ name: 'network_sync_b', size: '52 KB', desc: 'Network sync peer B' },
{ name: 'agent_handoff_a', size: '31 KB', desc: 'Agent handoff source' },
{ name: 'agent_handoff_b', size: '11 KB', desc: 'Agent handoff target' },
{ name: 'reasoning_parent', size: '5.6 KB', desc: 'Reasoning chain parent' },
{ name: 'reasoning_child', size: '8.1 KB', desc: 'Reasoning chain child' },
{ name: 'reasoning_grandchild', size: '162 B', desc: 'Minimal derived file' },
];
const RVF_BASE_URL = 'https://raw.githubusercontent.com/ruvnet/ruvector/main/examples/rvf/output';
rvfCmd.command('examples')
.description('List available example .rvf files')
.option('--json', 'Output as JSON')
.action((opts) => {
if (opts.json) {
console.log(JSON.stringify(RVF_EXAMPLES, null, 2));
return;
}
console.log(chalk.bold.cyan('\nAvailable RVF Example Files (45 total)\n'));
console.log(chalk.dim(`Download: npx ruvector rvf download <name>\n`));
const maxName = Math.max(...RVF_EXAMPLES.map(e => e.name.length));
const maxSize = Math.max(...RVF_EXAMPLES.map(e => e.size.length));
for (const ex of RVF_EXAMPLES) {
const name = chalk.green(ex.name.padEnd(maxName));
const size = chalk.yellow(ex.size.padStart(maxSize));
console.log(` ${name} ${size} ${chalk.dim(ex.desc)}`);
}
console.log(chalk.dim(`\nFull catalog: https://github.com/ruvnet/ruvector/tree/main/examples/rvf/output\n`));
});
rvfCmd.command('download [names...]')
.description('Download example .rvf files from GitHub')
.option('-a, --all', 'Download all 45 examples (~11 MB)')
.option('-o, --output <dir>', 'Output directory', '.')
.action(async (names, opts) => {
const https = require('https');
const ALLOWED_REDIRECT_HOSTS = ['raw.githubusercontent.com', 'objects.githubusercontent.com', 'github.com'];
const sanitizeFileName = (name) => {
// Strip path separators and parent directory references
const base = path.basename(name);
// Only allow alphanumeric, underscores, hyphens, dots
if (!/^[\w\-.]+$/.test(base)) throw new Error(`Invalid filename: ${base}`);
return base;
};
const downloadFile = (url, dest) => new Promise((resolve, reject) => {
const file = fs.createWriteStream(dest);
https.get(url, (res) => {
if (res.statusCode === 302 || res.statusCode === 301) {
const redirectUrl = res.headers.location;
try {
const redirectHost = new URL(redirectUrl).hostname;
if (!ALLOWED_REDIRECT_HOSTS.includes(redirectHost)) {
file.close();
reject(new Error(`Redirect to untrusted host: ${redirectHost}`));
return;
}
} catch { file.close(); reject(new Error('Invalid redirect URL')); return; }
https.get(redirectUrl, (res2) => { res2.pipe(file); file.on('finish', () => { file.close(); resolve(); }); }).on('error', reject);
return;
}
if (res.statusCode !== 200) { file.close(); fs.unlinkSync(dest); reject(new Error(`HTTP ${res.statusCode}`)); return; }
res.pipe(file);
file.on('finish', () => { file.close(); resolve(); });
}).on('error', reject);
});
let toDownload = [];
if (opts.all) {
toDownload = RVF_EXAMPLES.map(e => e.name);
} else if (names && names.length > 0) {
toDownload = names;
} else {
console.error(chalk.red('Specify example names or use --all. Run `npx ruvector rvf examples` to list.'));
process.exit(1);
}
const outDir = path.resolve(opts.output);
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
console.log(chalk.bold.cyan(`\nDownloading ${toDownload.length} .rvf file(s) to ${outDir}\n`));
let ok = 0, fail = 0;
for (const name of toDownload) {
const rawName = name.endsWith('.rvf') ? name : `${name}.rvf`;
let fileName;
try { fileName = sanitizeFileName(rawName); } catch (e) {
console.log(chalk.red(`SKIPPED: ${e.message}`));
fail++;
continue;
}
// Validate against known examples when not using --all
if (!opts.all) {
const baseName = fileName.replace(/\.rvf$/, '');
if (!RVF_EXAMPLES.some(e => e.name === baseName)) {
console.log(chalk.red(`SKIPPED: Unknown example '${baseName}'. Run 'npx ruvector rvf examples' to list.`));
fail++;
continue;
}
}
const url = `${RVF_BASE_URL}/${encodeURIComponent(fileName)}`;
const dest = path.join(outDir, fileName);
// Path containment check
if (!path.resolve(dest).startsWith(path.resolve(outDir) + path.sep) && path.resolve(dest) !== path.resolve(outDir)) {
console.log(chalk.red(`SKIPPED: Path traversal detected for '${fileName}'`));
fail++;
continue;
}
try {
process.stdout.write(chalk.dim(` ${fileName} ... `));
await downloadFile(url, dest);
const stat = fs.statSync(dest);
console.log(chalk.green(`OK (${(stat.size / 1024).toFixed(0)} KB)`));
ok++;
} catch (e) {
console.log(chalk.red(`FAILED: ${e.message}`));
fail++;
}
}
console.log(chalk.bold(`\nDone: ${ok} downloaded, ${fail} failed\n`));
});
// MCP Server command
const mcpCmd = program.command('mcp').description('MCP (Model Context Protocol) server for Claude Code integration');
mcpCmd.command('start')
.description('Start the RuVector MCP server')
.action(() => {
// Execute the mcp-server.js directly
const mcpServerPath = path.join(__dirname, 'mcp-server.js');
if (!fs.existsSync(mcpServerPath)) {
console.error(chalk.red('Error: MCP server not found at'), mcpServerPath);
process.exit(1);
}
require(mcpServerPath);
});
mcpCmd.command('info')
.description('Show MCP server information and setup instructions')
.action(() => {
console.log(chalk.bold.cyan('\n🔌 RuVector MCP Server\n'));
console.log(chalk.white('The RuVector MCP server provides self-learning intelligence'));
console.log(chalk.white('tools to Claude Code via the Model Context Protocol.\n'));
console.log(chalk.bold('Hooks Tools:'));
console.log(chalk.dim(' hooks_stats - Get intelligence statistics'));
console.log(chalk.dim(' hooks_route - Route task to best agent'));
console.log(chalk.dim(' hooks_remember - Store context in vector memory'));
console.log(chalk.dim(' hooks_recall - Search vector memory'));
console.log(chalk.dim(' hooks_init - Initialize hooks in project'));
console.log(chalk.dim(' hooks_pretrain - Pretrain from repository'));
console.log(chalk.dim(' hooks_build_agents - Generate agent configs'));
console.log(chalk.dim(' hooks_verify - Verify hooks configuration'));
console.log(chalk.dim(' hooks_doctor - Diagnose setup issues'));
console.log(chalk.dim(' hooks_export - Export intelligence data'));
console.log(chalk.bold('\nRVF Vector Store Tools:'));
console.log(chalk.dim(' rvf_create - Create new .rvf vector store'));
console.log(chalk.dim(' rvf_open - Open existing .rvf store'));
console.log(chalk.dim(' rvf_ingest - Insert vectors into store'));
console.log(chalk.dim(' rvf_query - Query nearest neighbors'));
console.log(chalk.dim(' rvf_delete - Delete vectors by ID'));
console.log(chalk.dim(' rvf_status - Get store status'));
console.log(chalk.dim(' rvf_compact - Compact store'));
console.log(chalk.dim(' rvf_derive - COW-branch to child store'));
console.log(chalk.dim(' rvf_segments - List file segments'));
console.log(chalk.dim(' rvf_examples - List example .rvf files'));
console.log(chalk.bold('\nrvlite Query Tools:'));
console.log(chalk.dim(' rvlite_sql - Execute SQL query over rvlite vector DB'));
console.log(chalk.dim(' rvlite_cypher - Execute Cypher graph query'));
console.log(chalk.dim(' rvlite_sparql - Execute SPARQL RDF query'));
console.log(chalk.bold('\n📦 Resources:'));
console.log(chalk.dim(' ruvector://intelligence/stats - Current statistics'));
console.log(chalk.dim(' ruvector://intelligence/patterns - Learned patterns'));
console.log(chalk.dim(' ruvector://intelligence/memories - Vector memories'));
console.log(chalk.bold.yellow('\n⚙️ Setup Instructions:\n'));
console.log(chalk.white('Add to Claude Code:'));
console.log(chalk.cyan(' claude mcp add ruvector npx ruvector mcp start\n'));
console.log(chalk.white('Or add to .claude/settings.json:'));
console.log(chalk.dim(` {
"mcpServers": {
"ruvector": {
"command": "npx",
"args": ["ruvector", "mcp", "start"]
}
}
}`));
console.log();
});
program.parse();