claude-flow
Version:
Enterprise-grade AI agent orchestration with ruv-swarm integration (Alpha Release)
1,476 lines (1,297 loc) ⢠83.1 kB
JavaScript
/**
* Hive Mind command for Claude-Flow v2.0.0
* Advanced swarm intelligence with collective decision-making
*/
import { spawn } from 'child_process';
import { existsSync, mkdirSync } from 'fs';
import { writeFile, readFile } from 'fs/promises';
import path from 'path';
import readline from 'readline';
import inquirer from 'inquirer';
import chalk from 'chalk';
import ora from 'ora';
import { args, cwd, exit, writeTextFile, readTextFile, mkdirAsync } from '../node-compat.js';
import { isInteractive, isRawModeSupported, warnNonInteractive, checkNonInteractiveAuth } from '../utils/interactive-detector.js';
import { safeInteractive, nonInteractiveProgress, nonInteractiveSelect } from '../utils/safe-interactive.js';
// Import SQLite for persistence
import Database from 'better-sqlite3';
// Import MCP tool wrappers
import { MCPToolWrapper } from './hive-mind/mcp-wrapper.js';
import { HiveMindCore } from './hive-mind/core.js';
import { QueenCoordinator } from './hive-mind/queen.js';
import { CollectiveMemory } from './hive-mind/memory.js';
import { SwarmCommunication } from './hive-mind/communication.js';
import { HiveMindSessionManager } from './hive-mind/session-manager.js';
import { createAutoSaveMiddleware } from './hive-mind/auto-save-middleware.js';
function showHiveMindHelp() {
console.log(`
${chalk.yellow('š§ Claude Flow Hive Mind System')}
${chalk.bold('USAGE:')}
claude-flow hive-mind [subcommand] [options]
${chalk.bold('SUBCOMMANDS:')}
${chalk.green('init')} Initialize hive mind system
${chalk.green('spawn')} Spawn hive mind swarm for a task
${chalk.green('status')} Show hive mind status
${chalk.green('resume')} Resume a paused hive mind session
${chalk.green('sessions')} List all hive mind sessions
${chalk.green('consensus')} View consensus decisions
${chalk.green('memory')} Manage collective memory
${chalk.green('metrics')} View performance metrics
${chalk.green('wizard')} Interactive hive mind wizard
${chalk.bold('EXAMPLES:')}
${chalk.gray('# Initialize hive mind')}
claude-flow hive-mind init
${chalk.gray('# Spawn swarm with interactive wizard')}
claude-flow hive-mind spawn
${chalk.gray('# Quick spawn with objective')}
claude-flow hive-mind spawn "Build microservices architecture"
${chalk.gray('# View current status')}
claude-flow hive-mind status
${chalk.gray('# Interactive wizard')}
claude-flow hive-mind wizard
${chalk.gray('# Spawn with Claude Code coordination')}
claude-flow hive-mind spawn "Build REST API" --claude
${chalk.gray('# Auto-spawn coordinated Claude Code instances')}
claude-flow hive-mind spawn "Research AI trends" --auto-spawn --verbose
${chalk.gray('# List all sessions')}
claude-flow hive-mind sessions
${chalk.gray('# Resume a paused session')}
claude-flow hive-mind resume session-1234567890-abc123
${chalk.bold('KEY FEATURES:')}
${chalk.cyan('š')} Queen-led coordination with worker specialization
${chalk.cyan('š§ ')} Collective memory and knowledge sharing
${chalk.cyan('š¤')} Consensus building for critical decisions
${chalk.cyan('ā”')} Parallel task execution with auto-scaling
${chalk.cyan('š')} Work stealing and load balancing
${chalk.cyan('š')} Real-time metrics and performance tracking
${chalk.cyan('š”ļø')} Fault tolerance and self-healing
${chalk.cyan('š')} Secure communication between agents
${chalk.bold('OPTIONS:')}
--queen-type <type> Queen coordinator type (strategic, tactical, adaptive)
--max-workers <n> Maximum worker agents (default: 8)
--consensus <type> Consensus algorithm (majority, weighted, byzantine)
--memory-size <mb> Collective memory size in MB (default: 100)
--auto-scale Enable auto-scaling based on workload
--encryption Enable encrypted communication
--monitor Real-time monitoring dashboard
--verbose Detailed logging
--claude Generate Claude Code spawn commands with coordination
--spawn Alias for --claude
--auto-spawn Automatically spawn Claude Code instances
--execute Execute Claude Code spawn commands immediately
--auto (Deprecated: auto-permissions enabled by default)
--no-auto-permissions Disable automatic --dangerously-skip-permissions
${chalk.bold('For more information:')}
${chalk.blue('https://github.com/ruvnet/claude-flow/tree/main/docs/hive-mind')}
`);
}
/**
* Initialize hive mind system
*/
async function initHiveMind(flags) {
const spinner = ora('Initializing Hive Mind system...').start();
try {
// Create hive mind directory structure
const hiveMindDir = path.join(cwd(), '.hive-mind');
if (!existsSync(hiveMindDir)) {
mkdirSync(hiveMindDir, { recursive: true });
}
// Initialize SQLite database
const dbPath = path.join(hiveMindDir, 'hive.db');
const db = new Database(dbPath);
// Create tables
db.exec(`
CREATE TABLE IF NOT EXISTS swarms (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
objective TEXT,
status TEXT DEFAULT 'active',
queen_type TEXT DEFAULT 'strategic',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS agents (
id TEXT PRIMARY KEY,
swarm_id TEXT,
name TEXT NOT NULL,
type TEXT NOT NULL,
role TEXT,
status TEXT DEFAULT 'idle',
capabilities TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (swarm_id) REFERENCES swarms(id)
);
CREATE TABLE IF NOT EXISTS tasks (
id TEXT PRIMARY KEY,
swarm_id TEXT,
agent_id TEXT,
description TEXT,
status TEXT DEFAULT 'pending',
priority INTEGER DEFAULT 5,
result TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
completed_at DATETIME,
FOREIGN KEY (swarm_id) REFERENCES swarms(id),
FOREIGN KEY (agent_id) REFERENCES agents(id)
);
CREATE TABLE IF NOT EXISTS collective_memory (
id TEXT PRIMARY KEY,
swarm_id TEXT,
key TEXT NOT NULL,
value TEXT,
type TEXT DEFAULT 'knowledge',
confidence REAL DEFAULT 1.0,
created_by TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
accessed_at DATETIME,
access_count INTEGER DEFAULT 0,
compressed INTEGER DEFAULT 0,
size INTEGER DEFAULT 0,
FOREIGN KEY (swarm_id) REFERENCES swarms(id)
);
CREATE TABLE IF NOT EXISTS consensus_decisions (
id TEXT PRIMARY KEY,
swarm_id TEXT,
topic TEXT NOT NULL,
decision TEXT,
votes TEXT,
algorithm TEXT DEFAULT 'majority',
confidence REAL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (swarm_id) REFERENCES swarms(id)
);
`);
db.close();
// Create configuration file
const config = {
version: '2.0.0',
initialized: new Date().toISOString(),
defaults: {
queenType: 'strategic',
maxWorkers: 8,
consensusAlgorithm: 'majority',
memorySize: 100,
autoScale: true,
encryption: false
},
mcpTools: {
enabled: true,
parallel: true,
timeout: 60000
}
};
await writeFile(
path.join(hiveMindDir, 'config.json'),
JSON.stringify(config, null, 2)
);
spinner.succeed('Hive Mind system initialized successfully!');
console.log('\n' + chalk.green('ā') + ' Created .hive-mind directory');
console.log(chalk.green('ā') + ' Initialized SQLite database');
console.log(chalk.green('ā') + ' Created configuration file');
console.log('\n' + chalk.yellow('Next steps:'));
console.log(' 1. Run ' + chalk.cyan('claude-flow hive-mind spawn') + ' to create your first swarm');
console.log(' 2. Use ' + chalk.cyan('claude-flow hive-mind wizard') + ' for interactive setup');
} catch (error) {
spinner.fail('Failed to initialize Hive Mind system');
console.error(chalk.red('Error:'), error.message);
exit(1);
}
}
/**
* Interactive wizard for hive mind operations
*/
// Wrapped wizard function that handles non-interactive environments
const hiveMindWizard = safeInteractive(
// Interactive version
async function(flags = {}) {
console.log(chalk.yellow('\nš§ Hive Mind Interactive Wizard\n'));
const { action } = await inquirer.prompt([
{
type: 'list',
name: 'action',
message: 'What would you like to do?',
choices: [
{ name: 'š Create new swarm', value: 'spawn' },
{ name: 'š View swarm status', value: 'status' },
{ name: 'š§ Manage collective memory', value: 'memory' },
{ name: 'š¤ View consensus decisions', value: 'consensus' },
{ name: 'š Performance metrics', value: 'metrics' },
{ name: 'š§ Configure hive mind', value: 'config' },
{ name: 'ā Exit', value: 'exit' }
]
}
]);
switch (action) {
case 'spawn':
await spawnSwarmWizard();
break;
case 'status':
await showStatus({});
break;
case 'memory':
await manageMemoryWizard();
break;
case 'consensus':
await showConsensus({});
break;
case 'metrics':
await showMetrics({});
break;
case 'config':
await configureWizard();
break;
case 'exit':
console.log(chalk.gray('Exiting wizard...'));
break;
}
},
// Non-interactive fallback
async function(flags = {}) {
console.log(chalk.yellow('\nš§ Hive Mind - Non-Interactive Mode\n'));
// Default to creating a swarm with sensible defaults
console.log(chalk.cyan('Creating new swarm with default settings...'));
console.log(chalk.gray('Use command-line flags to customize:'));
console.log(chalk.gray(' --objective "Your task" Set swarm objective'));
console.log(chalk.gray(' --queen-type strategic Set queen type'));
console.log(chalk.gray(' --max-workers 8 Set worker count'));
console.log();
const objective = flags.objective || 'General task coordination';
const config = {
name: flags.name || `swarm-${Date.now()}`,
queenType: flags.queenType || flags['queen-type'] || 'strategic',
maxWorkers: parseInt(flags.maxWorkers || flags['max-workers'] || '8'),
consensusAlgorithm: flags.consensus || 'majority',
autoScale: flags.autoScale || flags['auto-scale'] || false,
encryption: flags.encryption || false
};
await spawnSwarm([objective], {
...flags,
name: config.name,
queenType: config.queenType,
maxWorkers: config.maxWorkers,
consensusAlgorithm: config.consensusAlgorithm,
autoScale: config.autoScale,
encryption: config.encryption,
nonInteractive: true
});
}
);
/**
* Spawn swarm wizard
*/
async function spawnSwarmWizard() {
const answers = await inquirer.prompt([
{
type: 'input',
name: 'objective',
message: 'What is the swarm objective?',
validate: input => input.trim().length > 0 || 'Please enter an objective'
},
{
type: 'input',
name: 'name',
message: 'Swarm name (optional):',
default: answers => `swarm-${Date.now()}`
},
{
type: 'list',
name: 'queenType',
message: 'Select queen coordinator type:',
choices: [
{ name: 'Strategic - High-level planning and coordination', value: 'strategic' },
{ name: 'Tactical - Detailed task management', value: 'tactical' },
{ name: 'Adaptive - Learns and adapts strategies', value: 'adaptive' }
],
default: 'strategic'
},
{
type: 'number',
name: 'maxWorkers',
message: 'Maximum number of worker agents:',
default: 8,
validate: input => input > 0 && input <= 20 || 'Please enter a number between 1 and 20'
},
{
type: 'checkbox',
name: 'workerTypes',
message: 'Select worker agent types:',
choices: [
{ name: 'Researcher', value: 'researcher', checked: true },
{ name: 'Coder', value: 'coder', checked: true },
{ name: 'Analyst', value: 'analyst', checked: true },
{ name: 'Tester', value: 'tester', checked: true },
{ name: 'Architect', value: 'architect' },
{ name: 'Reviewer', value: 'reviewer' },
{ name: 'Optimizer', value: 'optimizer' },
{ name: 'Documenter', value: 'documenter' }
]
},
{
type: 'list',
name: 'consensusAlgorithm',
message: 'Consensus algorithm for decisions:',
choices: [
{ name: 'Majority - Simple majority voting', value: 'majority' },
{ name: 'Weighted - Expertise-weighted voting', value: 'weighted' },
{ name: 'Byzantine - Fault-tolerant consensus', value: 'byzantine' }
],
default: 'majority'
},
{
type: 'confirm',
name: 'autoScale',
message: 'Enable auto-scaling?',
default: true
},
{
type: 'confirm',
name: 'monitor',
message: 'Launch monitoring dashboard?',
default: true
}
]);
// Spawn the swarm with collected parameters
await spawnSwarm([answers.objective], {
name: answers.name,
queenType: answers.queenType,
maxWorkers: answers.maxWorkers,
workerTypes: answers.workerTypes.join(','),
consensus: answers.consensusAlgorithm,
autoScale: answers.autoScale,
monitor: answers.monitor
});
}
/**
* Spawn a hive mind swarm
*/
async function spawnSwarm(args, flags) {
const objective = args.join(' ').trim();
if (!objective && !flags.wizard) {
console.error(chalk.red('Error: Please provide an objective or use --wizard flag'));
console.log('Example: claude-flow hive-mind spawn "Build REST API"');
return;
}
const spinner = ora('Spawning Hive Mind swarm...').start();
try {
// Initialize hive mind core with error handling
let hiveMind;
try {
spinner.text = 'Initializing Hive Mind Core...';
hiveMind = new HiveMindCore({
objective,
name: flags.name || `hive-${Date.now()}`,
queenType: flags.queenType || 'strategic',
maxWorkers: flags.maxWorkers || 8,
consensusAlgorithm: flags.consensus || 'majority',
autoScale: flags.autoScale !== false,
encryption: flags.encryption || false
});
} catch (error) {
console.error('HiveMindCore initialization failed:', error);
throw new Error(`Failed to initialize HiveMindCore: ${error.message}`);
}
spinner.text = 'Setting up database connection...';
// Initialize database connection
const dbDir = path.join(cwd(), '.hive-mind');
const dbPath = path.join(dbDir, 'hive.db');
// Ensure .hive-mind directory exists
if (!existsSync(dbDir)) {
mkdirSync(dbDir, { recursive: true });
}
// Check if database file exists and try to create a clean one if needed
let db;
try {
spinner.text = 'Creating database connection...';
db = new Database(dbPath);
// Test the database with a simple query
db.prepare('SELECT 1').get();
spinner.text = 'Database connection established';
} catch (error) {
console.warn('Database issue detected, recreating...', error.message);
spinner.text = 'Recreating database...';
// Remove corrupted database
if (existsSync(dbPath)) {
try {
const fs = await import('fs');
fs.unlinkSync(dbPath);
} catch (e) {
console.warn('Could not remove corrupted database:', e.message);
}
}
// Create new database
db = new Database(dbPath);
}
// Initialize database schema if not exists
spinner.text = 'Creating database schema...';
try {
db.exec(`
CREATE TABLE IF NOT EXISTS swarms (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
objective TEXT,
queen_type TEXT,
status TEXT DEFAULT 'active',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME
);
CREATE TABLE IF NOT EXISTS agents (
id TEXT PRIMARY KEY,
swarm_id TEXT NOT NULL,
name TEXT NOT NULL,
type TEXT NOT NULL,
role TEXT NOT NULL,
status TEXT DEFAULT 'idle',
capabilities TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (swarm_id) REFERENCES swarms(id)
);
CREATE TABLE IF NOT EXISTS tasks (
id TEXT PRIMARY KEY,
swarm_id TEXT NOT NULL,
agent_id TEXT,
description TEXT,
status TEXT DEFAULT 'pending',
priority INTEGER DEFAULT 5,
result TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
completed_at DATETIME,
FOREIGN KEY (swarm_id) REFERENCES swarms(id),
FOREIGN KEY (agent_id) REFERENCES agents(id)
);
CREATE TABLE IF NOT EXISTS collective_memory (
id TEXT PRIMARY KEY,
swarm_id TEXT,
key TEXT NOT NULL,
value TEXT,
type TEXT DEFAULT 'knowledge',
confidence REAL DEFAULT 1.0,
created_by TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
accessed_at DATETIME,
access_count INTEGER DEFAULT 0,
compressed INTEGER DEFAULT 0,
size INTEGER DEFAULT 0,
FOREIGN KEY (swarm_id) REFERENCES swarms(id)
);
CREATE TABLE IF NOT EXISTS consensus_decisions (
id TEXT PRIMARY KEY,
swarm_id TEXT,
topic TEXT NOT NULL,
decision TEXT,
votes TEXT,
algorithm TEXT DEFAULT 'majority',
confidence REAL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (swarm_id) REFERENCES swarms(id)
);
`);
spinner.text = 'Database schema created successfully';
} catch (error) {
console.error('Database schema creation failed:', error);
throw new Error(`Failed to create database schema: ${error.message}`);
}
// Create swarm record with safe ID generation
spinner.text = 'Creating swarm record...';
const timestamp = Date.now();
const randomPart = Math.random().toString(36).substring(2, 11); // Use substring instead of substr
const swarmId = `swarm-${timestamp}-${randomPart}`;
try {
db.prepare(`
INSERT INTO swarms (id, name, objective, queen_type)
VALUES (?, ?, ?, ?)
`).run(swarmId, hiveMind.config.name, objective, hiveMind.config.queenType);
} catch (error) {
console.error('Failed to create swarm record:', error);
throw new Error(`Failed to create swarm record: ${error.message}`);
}
// Create session for this swarm
spinner.text = 'Creating session tracking...';
const sessionManager = new HiveMindSessionManager();
const sessionId = sessionManager.createSession(swarmId, hiveMind.config.name, objective, {
queenType: hiveMind.config.queenType,
maxWorkers: hiveMind.config.maxWorkers,
consensusAlgorithm: hiveMind.config.consensusAlgorithm,
autoScale: hiveMind.config.autoScale,
encryption: hiveMind.config.encryption,
workerTypes: flags.workerTypes
});
spinner.text = 'Session tracking established...';
sessionManager.close();
// Initialize auto-save middleware
const autoSave = createAutoSaveMiddleware(sessionId, {
saveInterval: 30000, // Save every 30 seconds
autoStart: true
});
// Track initial swarm creation
autoSave.trackChange('swarm_created', {
swarmId,
swarmName: hiveMind.config.name,
objective,
workerCount: hiveMind.config.maxWorkers
});
spinner.text = 'Initializing Queen coordinator...';
// Initialize Queen
const queen = new QueenCoordinator({
swarmId,
type: hiveMind.config.queenType,
objective
});
// Spawn Queen agent
const queenAgent = {
id: `queen-${swarmId}`,
swarmId,
name: 'Queen Coordinator',
type: 'coordinator',
role: 'queen',
status: 'active',
capabilities: JSON.stringify(['coordination', 'planning', 'decision-making'])
};
db.prepare(`
INSERT INTO agents (id, swarm_id, name, type, role, status, capabilities)
VALUES (?, ?, ?, ?, ?, ?, ?)
`).run(...Object.values(queenAgent));
spinner.text = 'Spawning worker agents...';
// Determine worker types
const workerTypes = flags.workerTypes
? flags.workerTypes.split(',')
: ['researcher', 'coder', 'analyst', 'tester'];
// Spawn worker agents
const workers = [];
for (let i = 0; i < Math.min(workerTypes.length, hiveMind.config.maxWorkers); i++) {
const workerType = workerTypes[i % workerTypes.length];
const workerId = `worker-${swarmId}-${i}`;
const worker = {
id: workerId,
swarmId,
name: `${workerType.charAt(0).toUpperCase() + workerType.slice(1)} Worker ${i + 1}`,
type: workerType,
role: 'worker',
status: 'idle',
capabilities: JSON.stringify(getAgentCapabilities(workerType))
};
workers.push(worker);
db.prepare(`
INSERT INTO agents (id, swarm_id, name, type, role, status, capabilities)
VALUES (?, ?, ?, ?, ?, ?, ?)
`).run(...Object.values(worker));
// Track agent spawning for auto-save
autoSave.trackAgentActivity(workerId, 'spawned', {
type: workerType,
name: worker.name
});
}
spinner.text = 'Initializing collective memory...';
// Initialize collective memory
const memory = new CollectiveMemory({
swarmId,
maxSize: flags.memorySize || 100
});
// Store initial context
memory.store('objective', objective, 'context');
memory.store('queen_type', hiveMind.config.queenType, 'config');
memory.store('worker_count', workers.length, 'metrics');
memory.store('session_id', sessionId, 'system');
spinner.text = 'Establishing communication channels...';
// Initialize communication system
const communication = new SwarmCommunication({
swarmId,
encryption: hiveMind.config.encryption
});
db.close();
spinner.succeed('Hive Mind swarm spawned successfully!');
// Display swarm summary
console.log('\n' + chalk.bold('š Swarm Summary:'));
console.log(chalk.gray('ā'.repeat(50)));
console.log(chalk.cyan('Swarm ID:'), swarmId);
console.log(chalk.cyan('Session ID:'), sessionId);
console.log(chalk.cyan('Name:'), hiveMind.config.name);
console.log(chalk.cyan('Objective:'), objective);
console.log(chalk.cyan('Queen Type:'), hiveMind.config.queenType);
console.log(chalk.cyan('Workers:'), workers.length);
console.log(chalk.cyan('Worker Types:'), workerTypes.join(', '));
console.log(chalk.cyan('Consensus:'), hiveMind.config.consensusAlgorithm);
console.log(chalk.cyan('Auto-scaling:'), hiveMind.config.autoScale ? 'Enabled' : 'Disabled');
console.log(chalk.gray('ā'.repeat(50)));
// Launch monitoring if requested
if (flags.monitor) {
console.log('\n' + chalk.yellow('Launching monitoring dashboard...'));
// TODO: Implement monitoring dashboard
}
// Enhanced coordination instructions with MCP tools
console.log('\n' + chalk.green('ā') + ' Swarm is ready for coordination');
console.log(chalk.gray('Use "claude-flow hive-mind status" to view swarm activity'));
console.log(chalk.gray('Session auto-save enabled - progress saved every 30 seconds'));
console.log(chalk.blue('š” To pause:') + ' Press Ctrl+C to safely pause and resume later');
console.log(chalk.blue('š” To resume:') + ' claude-flow hive-mind resume ' + sessionId);
// Offer to spawn Claude Code instances with coordination instructions
if (flags.claude || flags.spawn) {
await spawnClaudeCodeInstances(swarmId, hiveMind.config.name, objective, workers, flags);
} else {
console.log('\n' + chalk.blue('š” Pro Tip:') + ' Add --claude to spawn coordinated Claude Code instances');
console.log(chalk.gray(' claude-flow hive-mind spawn "objective" --claude'));
}
} catch (error) {
spinner.fail('Failed to spawn Hive Mind swarm');
console.error(chalk.red('Error:'), error.message);
// If error contains "sha3", provide specific guidance
if (error.message.includes('sha3') || error.message.includes('SHA3')) {
console.error('\nš SHA3 Function Error Detected');
console.error('This appears to be a SQLite extension or better-sqlite3 configuration issue.');
console.error('\nPossible solutions:');
console.error('1. Try removing the corrupted database: rm -rf .hive-mind/');
console.error('2. Reinstall better-sqlite3: npm reinstall better-sqlite3');
console.error('3. Check if any SQLite extensions are conflicting');
console.error('\nšØ Detailed error:');
console.error(error.stack || error.message);
}
exit(1);
}
}
/**
* Get agent capabilities based on type
*/
function getAgentCapabilities(type) {
const capabilities = {
researcher: ['web-search', 'data-gathering', 'analysis', 'synthesis'],
coder: ['code-generation', 'implementation', 'refactoring', 'debugging'],
analyst: ['data-analysis', 'pattern-recognition', 'reporting', 'visualization'],
tester: ['test-generation', 'quality-assurance', 'bug-detection', 'validation'],
architect: ['system-design', 'architecture', 'planning', 'documentation'],
reviewer: ['code-review', 'quality-check', 'feedback', 'improvement'],
optimizer: ['performance-tuning', 'optimization', 'profiling', 'enhancement'],
documenter: ['documentation', 'explanation', 'tutorial-creation', 'knowledge-base']
};
return capabilities[type] || ['general'];
}
/**
* Show hive mind status
*/
async function showStatus(flags) {
try {
const dbPath = path.join(cwd(), '.hive-mind', 'hive.db');
if (!existsSync(dbPath)) {
console.error(chalk.red('Error: Hive Mind not initialized'));
console.log('Run "claude-flow hive-mind init" first');
return;
}
const db = new Database(dbPath);
// Get active swarms
const swarms = db.prepare(`
SELECT * FROM swarms
WHERE status = 'active'
ORDER BY created_at DESC
`).all();
if (swarms.length === 0) {
console.log(chalk.gray('No active swarms found'));
db.close();
return;
}
console.log(chalk.bold('\nš Active Hive Mind Swarms\n'));
for (const swarm of swarms) {
console.log(chalk.yellow('ā'.repeat(60)));
console.log(chalk.cyan('Swarm:'), swarm.name);
console.log(chalk.cyan('ID:'), swarm.id);
console.log(chalk.cyan('Objective:'), swarm.objective);
console.log(chalk.cyan('Queen Type:'), swarm.queen_type);
console.log(chalk.cyan('Status:'), chalk.green(swarm.status));
console.log(chalk.cyan('Created:'), new Date(swarm.created_at).toLocaleString());
// Get agents
const agents = db.prepare(`
SELECT * FROM agents
WHERE swarm_id = ?
`).all(swarm.id);
console.log('\n' + chalk.bold('Agents:'));
// Group by role
const queen = agents.find(a => a.role === 'queen');
const workers = agents.filter(a => a.role === 'worker');
if (queen) {
console.log(' ' + chalk.magenta('š Queen:'), queen.name, chalk.gray(`(${queen.status})`));
}
console.log(' ' + chalk.blue('š Workers:'));
workers.forEach(worker => {
const statusColor = worker.status === 'active' ? 'green' :
worker.status === 'busy' ? 'yellow' : 'gray';
console.log(` - ${worker.name} (${worker.type}) ${chalk[statusColor](worker.status)}`);
});
// Get task statistics
const taskStats = db.prepare(`
SELECT
COUNT(*) as total,
SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed,
SUM(CASE WHEN status = 'in_progress' THEN 1 ELSE 0 END) as in_progress,
SUM(CASE WHEN status = 'pending' THEN 1 ELSE 0 END) as pending
FROM tasks
WHERE swarm_id = ?
`).get(swarm.id);
console.log('\n' + chalk.bold('Tasks:'));
console.log(` Total: ${taskStats.total}`);
console.log(` Completed: ${chalk.green(taskStats.completed)}`);
console.log(` In Progress: ${chalk.yellow(taskStats.in_progress)}`);
console.log(` Pending: ${chalk.gray(taskStats.pending)}`);
// Get memory stats
const memoryCount = db.prepare(`
SELECT COUNT(*) as count FROM collective_memory
WHERE swarm_id = ?
`).get(swarm.id);
console.log('\n' + chalk.bold('Collective Memory:'));
console.log(` Entries: ${memoryCount.count}`);
// Get consensus stats
const consensusCount = db.prepare(`
SELECT COUNT(*) as count FROM consensus_decisions
WHERE swarm_id = ?
`).get(swarm.id);
console.log('\n' + chalk.bold('Consensus Decisions:'));
console.log(` Total: ${consensusCount.count}`);
}
console.log(chalk.yellow('ā'.repeat(60)) + '\n');
db.close();
} catch (error) {
console.error(chalk.red('Error:'), error.message);
exit(1);
}
}
/**
* Show consensus decisions
*/
async function showConsensus(flags) {
try {
const dbPath = path.join(cwd(), '.hive-mind', 'hive.db');
const db = new Database(dbPath);
const decisions = db.prepare(`
SELECT cd.*, s.name as swarm_name
FROM consensus_decisions cd
JOIN swarms s ON cd.swarm_id = s.id
ORDER BY cd.created_at DESC
LIMIT 20
`).all();
if (decisions.length === 0) {
console.log(chalk.gray('No consensus decisions found'));
db.close();
return;
}
console.log(chalk.bold('\nš¤ Recent Consensus Decisions\n'));
decisions.forEach(decision => {
console.log(chalk.yellow('ā'.repeat(50)));
console.log(chalk.cyan('Swarm:'), decision.swarm_name);
console.log(chalk.cyan('Topic:'), decision.topic);
console.log(chalk.cyan('Decision:'), decision.decision);
console.log(chalk.cyan('Algorithm:'), decision.algorithm);
console.log(chalk.cyan('Confidence:'), `${(decision.confidence * 100).toFixed(1)}%`);
console.log(chalk.cyan('Time:'), new Date(decision.created_at).toLocaleString());
if (decision.votes) {
const votes = JSON.parse(decision.votes);
console.log(chalk.cyan('Votes:'));
// Handle vote summary format (for/against/abstain/details)
if (votes.for !== undefined || votes.against !== undefined || votes.abstain !== undefined) {
console.log(` - for: ${votes.for || 0}`);
console.log(` - against: ${votes.against || 0}`);
console.log(` - abstain: ${votes.abstain || 0}`);
// Display vote details properly if they exist
if (votes.details && Array.isArray(votes.details)) {
console.log(' - details:');
votes.details.forEach((detail, index) => {
if (typeof detail === 'object') {
// Extract available fields
const agent = detail.agentId || detail.agent || detail.id || detail.name || `agent-${index + 1}`;
const vote = detail.vote || detail.choice || detail.decision || 'unknown';
const reason = detail.reason || detail.justification || detail.rationale;
// Build display string
let displayString = ` ${index + 1}. Agent: ${agent}, Vote: ${vote}`;
// Add reason if available
if (reason && reason !== 'N/A' && reason !== '') {
displayString += `, Reason: ${reason}`;
}
console.log(displayString);
} else {
console.log(` ${index + 1}. ${detail}`);
}
});
}
} else {
// Handle individual agent votes format
Object.entries(votes).forEach(([agent, vote]) => {
console.log(` - ${agent}: ${vote}`);
});
}
}
});
console.log(chalk.yellow('ā'.repeat(50)) + '\n');
db.close();
} catch (error) {
console.error(chalk.red('Error:'), error.message);
exit(1);
}
}
/**
* Show performance metrics
*/
async function showMetrics(flags) {
try {
const dbPath = path.join(cwd(), '.hive-mind', 'hive.db');
const db = new Database(dbPath);
// Get overall metrics
const overallStats = db.prepare(`
SELECT
(SELECT COUNT(*) FROM swarms) as total_swarms,
(SELECT COUNT(*) FROM agents) as total_agents,
(SELECT COUNT(*) FROM tasks) as total_tasks,
(SELECT COUNT(*) FROM tasks WHERE status = 'completed') as completed_tasks
`).get();
console.log(chalk.bold('\nš Hive Mind Performance Metrics\n'));
// Get task status breakdown
const taskBreakdown = db.prepare(`
SELECT
status,
COUNT(*) as count
FROM tasks
GROUP BY status
ORDER BY count DESC
`).all();
console.log(chalk.cyan('Overall Statistics:'));
console.log(` Total Swarms: ${overallStats.total_swarms}`);
console.log(` Total Agents: ${overallStats.total_agents}`);
console.log(` Total Tasks: ${overallStats.total_tasks}`);
console.log(` Completed Tasks: ${overallStats.completed_tasks}`);
console.log(` Success Rate: ${overallStats.total_tasks > 0
? ((overallStats.completed_tasks / overallStats.total_tasks) * 100).toFixed(1) + '%'
: 'N/A'}`);
if (taskBreakdown.length > 0) {
console.log('\n' + chalk.cyan('Task Status Breakdown:'));
taskBreakdown.forEach(status => {
const percentage = overallStats.total_tasks > 0
? ((status.count / overallStats.total_tasks) * 100).toFixed(1)
: '0';
const statusColor =
status.status === 'completed' ? 'green' :
status.status === 'in_progress' ? 'yellow' :
status.status === 'failed' ? 'red' : 'gray';
console.log(` ${chalk[statusColor](status.status.charAt(0).toUpperCase() + status.status.slice(1))}: ${status.count} (${percentage}%)`);
});
}
// Get agent performance (check for completed_at column)
let agentPerf = [];
try {
// Check if completed_at exists
const hasCompletedAt = db.prepare(`
SELECT COUNT(*) as count FROM pragma_table_info('tasks')
WHERE name = 'completed_at'
`).get();
if (hasCompletedAt && hasCompletedAt.count > 0) {
agentPerf = db.prepare(`
SELECT
a.name,
a.type,
COUNT(t.id) as tasks_assigned,
SUM(CASE WHEN t.status = 'completed' THEN 1 ELSE 0 END) as tasks_completed,
AVG(CASE WHEN t.completed_at IS NOT NULL
THEN (julianday(t.completed_at) - julianday(t.created_at)) * 24 * 60
ELSE NULL END) as avg_completion_minutes
FROM agents a
LEFT JOIN tasks t ON a.id = t.agent_id
GROUP BY a.id
HAVING tasks_assigned > 0
ORDER BY tasks_completed DESC
LIMIT 10
`).all();
} else {
// Simpler query without completed_at
agentPerf = db.prepare(`
SELECT
a.name,
a.type,
COUNT(t.id) as tasks_assigned,
SUM(CASE WHEN t.status = 'completed' THEN 1 ELSE 0 END) as tasks_completed,
NULL as avg_completion_minutes
FROM agents a
LEFT JOIN tasks t ON a.id = t.agent_id
GROUP BY a.id
HAVING tasks_assigned > 0
ORDER BY tasks_completed DESC
LIMIT 10
`).all();
}
} catch (error) {
console.warn('Could not get agent performance:', error.message);
}
if (agentPerf.length > 0) {
console.log('\n' + chalk.cyan('Top Performing Agents:'));
agentPerf.forEach((agent, index) => {
const successRate = agent.tasks_assigned > 0
? ((agent.tasks_completed / agent.tasks_assigned) * 100).toFixed(1)
: '0';
console.log(` ${index + 1}. ${agent.name} (${agent.type})`);
console.log(` Tasks: ${agent.tasks_completed}/${agent.tasks_assigned} (${successRate}%)`);
if (agent.avg_completion_minutes) {
console.log(` Avg Time: ${agent.avg_completion_minutes.toFixed(1)} minutes`);
}
});
}
// Get swarm performance
const swarmPerf = db.prepare(`
SELECT
s.name,
s.objective,
(SELECT COUNT(*) FROM agents a WHERE a.swarm_id = s.id) as agent_count,
(SELECT COUNT(*) FROM tasks t WHERE t.swarm_id = s.id) as task_count,
(SELECT COUNT(*) FROM tasks t WHERE t.swarm_id = s.id AND t.status = 'completed') as completed_count,
(SELECT COUNT(*) FROM collective_memory cm WHERE cm.swarm_id = s.id) as memory_entries,
(SELECT COUNT(*) FROM consensus_decisions cd WHERE cd.swarm_id = s.id) as consensus_count
FROM swarms s
WHERE s.status = 'active'
ORDER BY s.created_at DESC
LIMIT 5
`).all();
if (swarmPerf.length > 0) {
console.log('\n' + chalk.cyan('Active Swarm Performance:'));
swarmPerf.forEach(swarm => {
const successRate = swarm.task_count > 0
? ((swarm.completed_count / swarm.task_count) * 100).toFixed(1)
: '0';
console.log(`\n ${chalk.yellow(swarm.name)}`);
console.log(` Objective: ${swarm.objective.substring(0, 50)}...`);
console.log(` Agents: ${swarm.agent_count}, Tasks: ${swarm.completed_count}/${swarm.task_count} (${successRate}%)`);
console.log(` Memory: ${swarm.memory_entries} entries, Consensus: ${swarm.consensus_count} decisions`);
});
}
// Get performance insights
let avgTaskTime = { avg_minutes: null };
try {
// Check if completed_at exists
const hasCompletedAt = db.prepare(`
SELECT COUNT(*) as count FROM pragma_table_info('tasks')
WHERE name = 'completed_at'
`).get();
if (hasCompletedAt && hasCompletedAt.count > 0) {
avgTaskTime = db.prepare(`
SELECT
AVG(CASE WHEN completed_at IS NOT NULL
THEN (julianday(completed_at) - julianday(created_at)) * 24 * 60
ELSE NULL END) as avg_minutes
FROM tasks
WHERE status = 'completed'
`).get();
}
} catch (error) {
console.warn('Could not calculate average task time:', error.message);
}
// Get agent type performance
let agentTypePerf = [];
try {
// Check if completed_at exists
const hasCompletedAt = db.prepare(`
SELECT COUNT(*) as count FROM pragma_table_info('tasks')
WHERE name = 'completed_at'
`).get();
if (hasCompletedAt && hasCompletedAt.count > 0) {
agentTypePerf = db.prepare(`
SELECT
a.type,
COUNT(t.id) as total_tasks,
SUM(CASE WHEN t.status = 'completed' THEN 1 ELSE 0 END) as completed_tasks,
AVG(CASE WHEN t.completed_at IS NOT NULL
THEN (julianday(t.completed_at) - julianday(t.created_at)) * 24 * 60
ELSE NULL END) as avg_completion_minutes
FROM agents a
LEFT JOIN tasks t ON a.id = t.agent_id
GROUP BY a.type
HAVING total_tasks > 0
ORDER BY completed_tasks DESC
`).all();
} else {
// Simpler query without completed_at
agentTypePerf = db.prepare(`
SELECT
a.type,
COUNT(t.id) as total_tasks,
SUM(CASE WHEN t.status = 'completed' THEN 1 ELSE 0 END) as completed_tasks,
NULL as avg_completion_minutes
FROM agents a
LEFT JOIN tasks t ON a.id = t.agent_id
GROUP BY a.type
HAVING total_tasks > 0
ORDER BY completed_tasks DESC
`).all();
}
} catch (error) {
console.warn('Could not get agent type performance:', error.message);
}
if (avgTaskTime.avg_minutes) {
console.log('\n' + chalk.cyan('Performance Insights:'));
console.log(` Average Task Completion Time: ${avgTaskTime.avg_minutes.toFixed(1)} minutes`);
if (agentTypePerf.length > 0) {
console.log('\n' + chalk.cyan('Agent Type Performance:'));
agentTypePerf.forEach(type => {
const successRate = type.total_tasks > 0
? ((type.completed_tasks / type.total_tasks) * 100).toFixed(1)
: '0';
console.log(` ${type.type.charAt(0).toUpperCase() + type.type.slice(1)}: ${type.completed_tasks}/${type.total_tasks} (${successRate}%)`);
if (type.avg_completion_minutes) {
console.log(` Average time: ${type.avg_completion_minutes.toFixed(1)} minutes`);
}
});
}
}
console.log('\n');
db.close();
} catch (error) {
console.error(chalk.red('Error:'), error.message);
exit(1);
}
}
/**
* Manage collective memory wizard
*/
async function manageMemoryWizard() {
console.log(chalk.blue('\nš§ Collective Memory Management\n'));
const { action } = await inquirer.prompt([
{
type: 'list',
name: 'action',
message: 'What would you like to do with collective memory?',
choices: [
{ name: 'š View all memories', value: 'list' },
{ name: 'š Search memories', value: 'search' },
{ name: 'š¾ Store new memory', value: 'store' },
{ name: 'š Memory statistics', value: 'stats' },
{ name: 'šļø Clean old memories', value: 'clean' },
{ name: 'š¤ Export memory backup', value: 'export' },
{ name: 'ā¬
ļø Back to main menu', value: 'back' }
]
}
]);
switch (action) {
case 'list':
await listMemories();
break;
case 'search':
await searchMemories();
break;
case 'store':
await storeMemoryWizard();
break;
case 'stats':
await showMemoryStats();
break;
case 'clean':
await cleanMemories();
break;
case 'export':
await exportMemoryBackup();
break;
case 'back':
await hiveMindWizard();
return;
}
// Ask if user wants to continue
const { continue: continueAction } = await inquirer.prompt([
{
type: 'confirm',
name: 'continue',
message: 'Would you like to perform another memory operation?',
default: true
}
]);
if (continueAction) {
await manageMemoryWizard();
}
}
/**
* Configure hive mind wizard
*/
async function configureWizard() {
// TODO: Implement configuration wizard
console.log(chalk.yellow('Configuration wizard coming soon...'));
}
/**
* Main hive mind command handler
*/
export async function hiveMindCommand(args, flags) {
const subcommand = args[0];
const subArgs = args.slice(1);
// If no subcommand, show help
if (!subcommand) {
showHiveMindHelp();
return;
}
// Warn about non-interactive environments for certain commands
if ((subcommand === 'spawn' && (flags.claude || flags.spawn)) || subcommand === 'wizard') {
warnNonInteractive('hive-mind ' + subcommand);
}
switch (subcommand) {
case 'init':
await initHiveMind(flags);
break;
case 'spawn':
if (flags.wizard || subArgs.length === 0) {
await spawnSwarmWizard();
} else {
await spawnSwarm(subArgs, flags);
}
break;
case 'status':
await showStatus(flags);
break;
case 'sessions':
await showSessions(flags);
break;
case 'resume':
await resumeSession(subArgs, flags);
break;
case 'consensus':
await showConsensus(flags);
break;
case 'memory':
await manageMemoryWizard();
break;
case 'metrics':
await showMetrics(flags);
break;
case 'wizard':
await hiveMindWizard(flags);
break;
case 'help':
case '--help':
case '-h':
showHiveMindHelp();
break;
default:
console.error(chalk.red(`Unknown subcommand: ${subcommand}`));
console.log('Run "claude-flow hive-mind help" for usage information');
exit(1);
}
}
/**
* List all memories in the collective memory store
*/
async function listMemories() {
try {
console.log(chalk.blue('\nš Collective Memory Store\n'));
// Use MCP wrapper to search for all memories (empty pattern matches all)
const mcpWrapper = await getMcpWrapper();
const searchResult = await mcpWrapper.searchMemory('hive-mind', '');
// Handle different possible response structures
let memories = [];
if (searchResult && Array.isArray(searchResult.results)) {
memories = searchResult.results;
} else if (searchResult && Array.isArray(searchResult)) {
memories = searchResult;
} else if (searchResult && searchResult.data && Array.isArray(searchResult.data)) {
memories = searchResult.data;
}
if (!memories || memories.length === 0) {
console.log(chalk.yellow('No memories found in the collective store.'));
console.log(chalk.gray('Try storing some memories first using the "š¾ Store new memory" option.'));
return;
}
memories.forEach((memory, index) => {
console.log(chalk.cyan(`${index + 1}. ${memory.key || `memory-${index}`}`));
console.log(` Category: ${memory.type || 'general'}`);
console.log(` Created: ${new Date(memory.timestamp || Date.now()).toLocaleString()}`);
if (memory.value && typeof memory.value === 'object') {
console.log(` Preview: ${JSON.stringify(memory.value).substring(0, 100)}...`);
} else {
console.log(` Value: ${String(memory.value || memory).substring(0, 100)}...`);
}
console.log('');
});
} catch (error) {
console.error(chalk.red('Error listing memories:'), error.message);
console.log(chalk.gray('This might be because no memories have been stored yet.'));
}
}
/**
* Search memories by keyword
*/
async function searchMemories() {
try {
const { searchTerm } = await inquirer.prompt([
{
type: 'input',
name: 'searchTerm',
message: 'Enter search term:',
validate: input => input.length > 0
}
]);
console.log(chalk.blue(`\nš Searching for: "${searchTerm}"\n`));
const mcpWrapper = await getMcpWrapper();
const searchResult = await mcpWrapper.searchMemory('hive-mind', searchTerm);
// Handle different possible response structures
let memories = [];
if (searchResult && Array.isArray(searchResult.results)) {
memories = searchResult.results;
} else if (searchResult && Array.isArray(searchResult)) {
memories = searchResult;
} else if (searchResult && searchResult.data && Array.isArray(searchResult.data)) {
memories = searchResult.data;
}
if (!memories || memories.length === 0) {
console.log(chalk.yellow('No memories found matching your search.'));
return;
}
memories.forEach((memory, index) => {
console.log(chalk.green(`${index + 1}. ${memory.key || `result-${index}`}`));
console.log(` Category: ${memory.type || 'general'}`);
console.log(` Created: ${new Date(memory.timestamp || Date.now()).toLocaleString()}`);
console.log(` Value: ${JSON.stringify(memory.value || memory, null, 2)}`);
console.log('');
});
} catch (error) {
console.error(chalk.red('Error searching memories:'), error.message);
}
}
/**
* Store new memory wizard
*/
async function storeMemoryWizard() {
try {
const answers = await inquirer.prompt([
{
type: 'input',
name: 'key',
message: 'Memory key (identifier):',
validate: input => input.length > 0
},
{
type: 'list',
name: 'category',
message: 'Memory category:',
choices: [
'consensus',
'decision',
'pattern',
'learning',
'coordination',
'performance',
'configuration',
'general'
]
},
{
type: 'editor',
name: 'value',
message: 'Memory content (JSON or text):'
}
]);
const mcpWrapper = await getMcpWrapper();
let memoryValue;
// Try to parse as JSON, fall back to string
try {
memoryValue = JSON.parse(answers.value);
} catch {
memoryValue = answers.value;
}
await mcpWrapper.storeMemory('hive-mind', answers.key, memoryValue, answers.category);
console.log(chalk.green(`\nā
Memory stored successfully!`));
console.log(`Key: ${answers.key}`);
console.log(`Category: ${answers.category}`);
} catch (error) {
console.error(chalk.red('Error storing memory:'), error.message);
}
}
/**
* Show memory statistics
*/
async function showMemoryStats() {
try {
console.log(chalk.blue('\nš Memory Statistics\n'));
const mcpWrapper = await getMcpWrap