UNPKG

claude-flow

Version:

Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration

431 lines 17.1 kB
/** * V3 CLI RuVector Init Command * Initialize RuVector PostgreSQL Bridge */ import { output } from '../../output.js'; import { confirm, input } from '../../prompt.js'; /** * Get PostgreSQL connection config from context flags and environment */ function getConnectionConfig(ctx) { return { host: ctx.flags.host || process.env.PGHOST || 'localhost', port: parseInt(ctx.flags.port || process.env.PGPORT || '5432', 10), database: ctx.flags.database || process.env.PGDATABASE || '', user: ctx.flags.user || process.env.PGUSER || 'postgres', password: ctx.flags.password || process.env.PGPASSWORD || '', ssl: ctx.flags.ssl || process.env.PGSSLMODE === 'require', schema: ctx.flags.schema || 'claude_flow', }; } /** * Initialize RuVector in PostgreSQL */ export const initCommand = { name: 'init', description: 'Initialize RuVector in PostgreSQL', options: [ { name: 'host', short: 'h', description: 'PostgreSQL host', type: 'string', default: 'localhost', }, { name: 'port', short: 'p', description: 'PostgreSQL port', type: 'number', default: 5432, }, { name: 'database', short: 'd', description: 'Database name', type: 'string', required: true, }, { name: 'user', short: 'u', description: 'Database user', type: 'string', default: 'postgres', }, { name: 'password', description: 'Database password (or use PGPASSWORD env)', type: 'string', }, { name: 'ssl', description: 'Enable SSL connection', type: 'boolean', default: false, }, { name: 'schema', short: 's', description: 'Schema name for RuVector tables', type: 'string', default: 'claude_flow', }, { name: 'force', short: 'f', description: 'Force re-initialization (drops existing schema)', type: 'boolean', default: false, }, { name: 'dimensions', description: 'Default vector dimensions', type: 'number', default: 1536, }, { name: 'index-type', description: 'Default index type (hnsw, ivfflat)', type: 'string', default: 'hnsw', choices: ['hnsw', 'ivfflat'], }, ], examples: [ { command: 'claude-flow ruvector init -d mydb', description: 'Initialize with database name' }, { command: 'claude-flow ruvector init -d mydb -h db.example.com --ssl', description: 'Remote with SSL' }, { command: 'claude-flow ruvector init -d mydb --force', description: 'Force re-initialization' }, { command: 'claude-flow ruvector init -d mydb --dimensions 768', description: 'Custom vector dimensions' }, ], action: async (ctx) => { let config = getConnectionConfig(ctx); output.writeln(); output.writeln(output.bold('RuVector PostgreSQL Initialization')); output.writeln(output.dim('='.repeat(60))); output.writeln(); // Interactive mode if database not specified if (!config.database && ctx.interactive) { config.database = await input({ message: 'Database name:', validate: (v) => v.length > 0 || 'Database name is required', }); const useRemote = await confirm({ message: 'Connect to remote PostgreSQL?', default: false, }); if (useRemote) { config.host = await input({ message: 'PostgreSQL host:', default: 'localhost', }); config.port = parseInt(await input({ message: 'PostgreSQL port:', default: '5432', }), 10); config.ssl = await confirm({ message: 'Enable SSL?', default: true, }); } config.user = await input({ message: 'Database user:', default: 'postgres', }); if (!config.password) { config.password = await input({ message: 'Database password (or set PGPASSWORD):', }); } } if (!config.database) { output.printError('Database name is required. Use --database or -d flag.'); return { success: false, exitCode: 1 }; } const force = ctx.flags.force; const dimensions = parseInt(ctx.flags.dimensions || '1536', 10); const indexType = ctx.flags['index-type'] || 'hnsw'; // Show configuration output.writeln(output.highlight('Connection Configuration:')); output.printTable({ columns: [ { key: 'setting', header: 'Setting', width: 20 }, { key: 'value', header: 'Value', width: 40 }, ], data: [ { setting: 'Host', value: config.host }, { setting: 'Port', value: String(config.port) }, { setting: 'Database', value: config.database }, { setting: 'User', value: config.user }, { setting: 'SSL', value: config.ssl ? 'Enabled' : 'Disabled' }, { setting: 'Schema', value: config.schema }, { setting: 'Dimensions', value: String(dimensions) }, { setting: 'Index Type', value: indexType.toUpperCase() }, ], }); output.writeln(); if (force) { output.printWarning('Force mode: existing schema will be dropped!'); if (ctx.interactive) { const confirmDrop = await confirm({ message: `Drop and recreate schema "${config.schema}"?`, default: false, }); if (!confirmDrop) { output.printInfo('Initialization cancelled'); return { success: false, exitCode: 0 }; } } } const spinner = output.createSpinner({ text: 'Connecting to PostgreSQL...', spinner: 'dots' }); spinner.start(); try { // Check for pg module let pg = null; try { pg = await import('pg'); } catch { spinner.fail('PostgreSQL driver not found'); output.printError('Install pg package: npm install pg'); return { success: false, exitCode: 1 }; } // Connect to PostgreSQL const client = new pg.Client({ host: config.host, port: config.port, database: config.database, user: config.user, password: config.password, ssl: config.ssl ? { rejectUnauthorized: false } : false, }); await client.connect(); spinner.succeed('Connected to PostgreSQL'); // Check pgvector extension spinner.setText('Checking pgvector extension...'); spinner.start(); const extensionResult = await client.query(` SELECT extversion FROM pg_extension WHERE extname = 'vector' `); if (extensionResult.rows.length === 0) { spinner.succeed('pgvector not installed, attempting to create...'); try { await client.query('CREATE EXTENSION IF NOT EXISTS vector'); spinner.succeed('pgvector extension created'); } catch (error) { spinner.fail('Failed to create pgvector extension'); output.printError('Please install pgvector manually: https://github.com/pgvector/pgvector'); await client.end(); return { success: false, exitCode: 1 }; } } else { spinner.succeed(`pgvector v${extensionResult.rows[0].extversion} found`); } // Drop schema if force mode if (force) { spinner.setText(`Dropping schema "${config.schema}"...`); spinner.start(); await client.query(`DROP SCHEMA IF EXISTS ${config.schema} CASCADE`); spinner.succeed(`Schema "${config.schema}" dropped`); } // Create schema spinner.setText(`Creating schema "${config.schema}"...`); spinner.start(); await client.query(`CREATE SCHEMA IF NOT EXISTS ${config.schema}`); spinner.succeed(`Schema "${config.schema}" created`); // Create tables spinner.setText('Creating RuVector tables...'); spinner.start(); // Vector embeddings table await client.query(` CREATE TABLE IF NOT EXISTS ${config.schema}.embeddings ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), key VARCHAR(512) NOT NULL, namespace VARCHAR(128) NOT NULL DEFAULT 'default', content TEXT, embedding vector(${dimensions}), metadata JSONB DEFAULT '{}', created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(key, namespace) ) `); // Attention patterns table await client.query(` CREATE TABLE IF NOT EXISTS ${config.schema}.attention_patterns ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), pattern_name VARCHAR(256) NOT NULL, query_embedding vector(${dimensions}), key_embedding vector(${dimensions}), value_embedding vector(${dimensions}), attention_weights JSONB, context TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ) `); // GNN adjacency table await client.query(` CREATE TABLE IF NOT EXISTS ${config.schema}.gnn_edges ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), source_id UUID NOT NULL, target_id UUID NOT NULL, edge_type VARCHAR(64) NOT NULL DEFAULT 'related', weight FLOAT DEFAULT 1.0, metadata JSONB DEFAULT '{}', created_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(source_id, target_id, edge_type) ) `); // Hyperbolic embeddings table (Poincare ball) await client.query(` CREATE TABLE IF NOT EXISTS ${config.schema}.hyperbolic_embeddings ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), entity_id UUID NOT NULL, embedding vector(${dimensions}), curvature FLOAT DEFAULT -1.0, hierarchy_level INTEGER DEFAULT 0, parent_id UUID, created_at TIMESTAMPTZ DEFAULT NOW() ) `); // Migrations tracking table await client.query(` CREATE TABLE IF NOT EXISTS ${config.schema}.migrations ( id SERIAL PRIMARY KEY, version VARCHAR(64) NOT NULL UNIQUE, name VARCHAR(256) NOT NULL, applied_at TIMESTAMPTZ DEFAULT NOW(), checksum VARCHAR(64) ) `); // RuVector metadata table await client.query(` CREATE TABLE IF NOT EXISTS ${config.schema}.metadata ( key VARCHAR(128) PRIMARY KEY, value JSONB NOT NULL, updated_at TIMESTAMPTZ DEFAULT NOW() ) `); // Store initialization metadata await client.query(` INSERT INTO ${config.schema}.metadata (key, value) VALUES ('ruvector_version', '"1.0.0"') ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW() `); await client.query(` INSERT INTO ${config.schema}.metadata (key, value) VALUES ('dimensions', '${dimensions}') ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW() `); await client.query(` INSERT INTO ${config.schema}.metadata (key, value) VALUES ('initialized_at', '"${new Date().toISOString()}"') ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW() `); spinner.succeed('RuVector tables created'); // Create indexes spinner.setText(`Creating ${indexType.toUpperCase()} indexes...`); spinner.start(); if (indexType === 'hnsw') { await client.query(` CREATE INDEX IF NOT EXISTS idx_embeddings_vector_hnsw ON ${config.schema}.embeddings USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64) `); await client.query(` CREATE INDEX IF NOT EXISTS idx_attention_query_hnsw ON ${config.schema}.attention_patterns USING hnsw (query_embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64) `); await client.query(` CREATE INDEX IF NOT EXISTS idx_hyperbolic_embedding_hnsw ON ${config.schema}.hyperbolic_embeddings USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64) `); } else { // IVFFlat indexes await client.query(` CREATE INDEX IF NOT EXISTS idx_embeddings_vector_ivfflat ON ${config.schema}.embeddings USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100) `); await client.query(` CREATE INDEX IF NOT EXISTS idx_attention_query_ivfflat ON ${config.schema}.attention_patterns USING ivfflat (query_embedding vector_cosine_ops) WITH (lists = 100) `); } // Additional standard indexes await client.query(` CREATE INDEX IF NOT EXISTS idx_embeddings_namespace ON ${config.schema}.embeddings (namespace) `); await client.query(` CREATE INDEX IF NOT EXISTS idx_embeddings_key ON ${config.schema}.embeddings (key) `); await client.query(` CREATE INDEX IF NOT EXISTS idx_gnn_source ON ${config.schema}.gnn_edges (source_id) `); await client.query(` CREATE INDEX IF NOT EXISTS idx_gnn_target ON ${config.schema}.gnn_edges (target_id) `); spinner.succeed(`${indexType.toUpperCase()} indexes created`); // Record initial migration await client.query(` INSERT INTO ${config.schema}.migrations (version, name) VALUES ('1.0.0', 'Initial RuVector setup') ON CONFLICT (version) DO NOTHING `); await client.end(); output.writeln(); output.printSuccess('RuVector PostgreSQL Bridge initialized successfully!'); output.writeln(); output.printBox([ 'Created tables:', ` - ${config.schema}.embeddings (vector storage)`, ` - ${config.schema}.attention_patterns (attention mechanism)`, ` - ${config.schema}.gnn_edges (graph neural network)`, ` - ${config.schema}.hyperbolic_embeddings (Poincare ball)`, ` - ${config.schema}.migrations (version tracking)`, ` - ${config.schema}.metadata (configuration)`, '', 'Created indexes:', ` - ${indexType.toUpperCase()} vector similarity index`, ' - B-tree indexes on key, namespace', ' - GNN edge indexes', '', 'Next steps:', ' 1. Run migrations: claude-flow ruvector migrate --up', ' 2. Check status: claude-flow ruvector status --verbose', ' 3. Run benchmark: claude-flow ruvector benchmark', ].join('\n'), 'Initialization Complete'); return { success: true, data: { schema: config.schema, dimensions, indexType, tables: ['embeddings', 'attention_patterns', 'gnn_edges', 'hyperbolic_embeddings', 'migrations', 'metadata'], }, }; } catch (error) { spinner.fail('Initialization failed'); output.printError(error instanceof Error ? error.message : String(error)); return { success: false, exitCode: 1 }; } }, }; export default initCommand; //# sourceMappingURL=init.js.map