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
222 lines • 7.24 kB
JavaScript
/**
* V3 Configuration Loader
* Load configuration from various sources
*/
import { readFile } from 'fs/promises';
import { join, resolve } from 'path';
import { existsSync } from 'fs';
import { validateSystemConfig } from './validator.js';
import { defaultSystemConfig, mergeWithDefaults } from './defaults.js';
/**
* Configuration file names to search for
*/
const CONFIG_FILE_NAMES = [
'claude-flow.config.json',
'claude-flow.config.js',
'claude-flow.json',
'.claude-flow.json',
];
/**
* Find configuration file in directory
*/
async function findConfigFile(directory) {
for (const name of CONFIG_FILE_NAMES) {
const path = join(directory, name);
if (existsSync(path)) {
return path;
}
}
return null;
}
/**
* Load configuration from JSON file
*/
async function loadJsonConfig(path) {
const content = await readFile(path, 'utf8');
return JSON.parse(content);
}
/**
* Load configuration from environment variables
*/
function loadEnvConfig() {
const config = {};
// Orchestrator settings
if (process.env.CLAUDE_FLOW_MAX_AGENTS) {
config.orchestrator = {
...defaultSystemConfig.orchestrator,
lifecycle: {
...defaultSystemConfig.orchestrator.lifecycle,
maxConcurrentAgents: parseInt(process.env.CLAUDE_FLOW_MAX_AGENTS, 10),
},
};
}
// Data directory
if (process.env.CLAUDE_FLOW_DATA_DIR) {
config.orchestrator = {
...config.orchestrator,
...defaultSystemConfig.orchestrator,
session: {
...defaultSystemConfig.orchestrator.session,
dataDir: process.env.CLAUDE_FLOW_DATA_DIR,
},
};
}
// Memory type
if (process.env.CLAUDE_FLOW_MEMORY_TYPE) {
const memoryType = process.env.CLAUDE_FLOW_MEMORY_TYPE;
if (['sqlite', 'agentdb', 'hybrid', 'redis', 'memory'].includes(memoryType)) {
config.memory = {
...(defaultSystemConfig.memory ?? { type: 'hybrid' }),
type: memoryType,
};
}
}
// MCP transport
const defaultMcp = defaultSystemConfig.mcp ?? { name: 'claude-flow', version: '3.0.0', transport: { type: 'stdio' } };
if (process.env.CLAUDE_FLOW_MCP_TRANSPORT) {
const transport = process.env.CLAUDE_FLOW_MCP_TRANSPORT;
if (['stdio', 'http', 'websocket'].includes(transport)) {
config.mcp = {
...defaultMcp,
transport: {
...defaultMcp.transport,
type: transport,
},
};
}
}
if (process.env.CLAUDE_FLOW_MCP_PORT) {
config.mcp = {
...config.mcp,
...defaultMcp,
transport: {
...config.mcp?.transport,
...defaultMcp.transport,
port: parseInt(process.env.CLAUDE_FLOW_MCP_PORT, 10),
},
};
}
// Swarm topology
const defaultSwarm = defaultSystemConfig.swarm ?? { topology: 'hierarchical-mesh', maxAgents: 20 };
if (process.env.CLAUDE_FLOW_SWARM_TOPOLOGY) {
const topology = process.env.CLAUDE_FLOW_SWARM_TOPOLOGY;
if (['hierarchical', 'mesh', 'ring', 'star', 'adaptive', 'hierarchical-mesh'].includes(topology)) {
config.swarm = {
...defaultSwarm,
topology,
};
}
}
return config;
}
/**
* Configuration loader class
*/
export class ConfigLoader {
searchPaths = [];
constructor(additionalPaths) {
// Default search paths
this.searchPaths = [
process.cwd(),
resolve(process.cwd(), '..'),
resolve(process.env.HOME ?? '', '.claude-flow'),
];
if (additionalPaths) {
this.searchPaths.push(...additionalPaths);
}
}
/**
* Load configuration from all sources
*/
async load() {
const warnings = [];
// Start with defaults
let config = { ...defaultSystemConfig };
let source = 'default';
let path;
// Try to load from file
for (const searchPath of this.searchPaths) {
const configPath = await findConfigFile(searchPath);
if (configPath) {
try {
const fileConfig = await loadJsonConfig(configPath);
const validation = validateSystemConfig(fileConfig);
if (validation.success) {
config = mergeWithDefaults(validation.data, defaultSystemConfig);
source = 'file';
path = configPath;
break;
}
else {
warnings.push(`Invalid config at ${configPath}: ${validation.errors?.map(e => e.message).join(', ')}`);
}
}
catch (error) {
warnings.push(`Failed to load config from ${configPath}: ${error.message}`);
}
}
}
// Merge with environment variables
const envConfig = loadEnvConfig();
if (Object.keys(envConfig).length > 0) {
config = this.deepMerge(config, envConfig);
source = source === 'default' ? 'env' : 'merged';
}
return {
config,
source,
path,
warnings: warnings.length > 0 ? warnings : undefined,
};
}
/**
* Load configuration from specific file
*/
async loadFromFile(filePath) {
const absolutePath = resolve(filePath);
const fileConfig = await loadJsonConfig(absolutePath);
const validation = validateSystemConfig(fileConfig);
if (!validation.success) {
throw new Error(`Invalid configuration: ${validation.errors?.map(e => e.message).join(', ')}`);
}
const config = mergeWithDefaults(validation.data, defaultSystemConfig);
return {
config,
source: 'file',
path: absolutePath,
};
}
/**
* Deep merge objects
*/
deepMerge(target, source) {
const result = { ...target };
for (const key of Object.keys(source)) {
const sourceValue = source[key];
const targetValue = target[key];
if (sourceValue &&
typeof sourceValue === 'object' &&
!Array.isArray(sourceValue) &&
targetValue &&
typeof targetValue === 'object' &&
!Array.isArray(targetValue)) {
result[key] = this.deepMerge(targetValue, sourceValue);
}
else if (sourceValue !== undefined) {
result[key] = sourceValue;
}
}
return result;
}
}
/**
* Load configuration (convenience function)
*/
export async function loadConfig(options) {
const loader = new ConfigLoader(options?.paths);
if (options?.file) {
return loader.loadFromFile(options.file);
}
return loader.load();
}
//# sourceMappingURL=loader.js.map