claude-flow
Version:
Enterprise-grade AI agent orchestration with ruv-swarm integration (Alpha Release)
291 lines (250 loc) • 7.8 kB
JavaScript
// pre-init-validator.js - Pre-initialization validation checks
import { printWarning } from '../../../utils.js';
export class PreInitValidator {
constructor(workingDir) {
this.workingDir = workingDir;
}
/**
* Check file system permissions
*/
async checkPermissions() {
const result = {
success: true,
errors: [],
warnings: [],
};
try {
// Test write permission in working directory
const testFile = `${this.workingDir}/.claude-flow-permission-test`;
await Deno.writeTextFile(testFile, 'test');
await Deno.remove(testFile);
// Test directory creation permission
const testDir = `${this.workingDir}/.claude-flow-dir-test`;
await Deno.mkdir(testDir);
await Deno.remove(testDir);
} catch (error) {
result.success = false;
result.errors.push(`Insufficient permissions in ${this.workingDir}: ${error.message}`);
}
return result;
}
/**
* Check available disk space
*/
async checkDiskSpace() {
const result = {
success: true,
errors: [],
warnings: [],
};
try {
// Get disk usage information
const command = new Deno.Command('df', {
args: ['-k', this.workingDir],
stdout: 'piped',
stderr: 'piped',
});
const { stdout, success } = await command.output();
if (success) {
const output = new TextDecoder().decode(stdout);
const lines = output.trim().split('\n');
if (lines.length >= 2) {
const dataLine = lines[1];
const parts = dataLine.split(/\s+/);
if (parts.length >= 4) {
const availableKB = parseInt(parts[3]);
const availableMB = availableKB / 1024;
// Require at least 100MB free space
if (availableMB < 100) {
result.success = false;
result.errors.push(
`Insufficient disk space: ${availableMB.toFixed(2)}MB available (minimum 100MB required)`,
);
} else if (availableMB < 500) {
result.warnings.push(`Low disk space: ${availableMB.toFixed(2)}MB available`);
}
}
}
}
} catch (error) {
// Non-critical - just warn if we can't check disk space
result.warnings.push(`Could not check disk space: ${error.message}`);
}
return result;
}
/**
* Check for existing files and conflicts
*/
async checkConflicts(force = false) {
const result = {
success: true,
errors: [],
warnings: [],
conflicts: [],
};
const criticalFiles = [
'CLAUDE.md',
'memory-bank.md',
'coordination.md',
'.roomodes',
'memory/claude-flow-data.json',
];
const criticalDirs = ['.roo', '.claude', 'memory', 'coordination'];
// Check critical files
for (const file of criticalFiles) {
try {
const stat = await Deno.stat(`${this.workingDir}/${file}`);
if (stat.isFile) {
result.conflicts.push(file);
if (!force) {
result.success = false;
result.errors.push(`File already exists: ${file}`);
} else {
result.warnings.push(`File will be overwritten: ${file}`);
}
}
} catch {
// File doesn't exist - good
}
}
// Check critical directories
for (const dir of criticalDirs) {
try {
const stat = await Deno.stat(`${this.workingDir}/${dir}`);
if (stat.isDirectory) {
// Check if directory has important content
const entries = [];
for await (const entry of Deno.readDir(`${this.workingDir}/${dir}`)) {
entries.push(entry.name);
}
if (entries.length > 0) {
result.conflicts.push(`${dir}/ (${entries.length} items)`);
if (!force) {
result.warnings.push(`Directory exists with content: ${dir}/`);
}
}
}
} catch {
// Directory doesn't exist - good
}
}
return result;
}
/**
* Check for required dependencies
*/
async checkDependencies() {
const result = {
success: true,
errors: [],
warnings: [],
dependencies: {},
};
const dependencies = [
{ name: 'node', command: 'node', args: ['--version'], required: true },
{ name: 'npm', command: 'npm', args: ['--version'], required: true },
{ name: 'git', command: 'git', args: ['--version'], required: false },
{ name: 'npx', command: 'npx', args: ['--version'], required: true },
];
for (const dep of dependencies) {
try {
const command = new Deno.Command(dep.command, {
args: dep.args,
stdout: 'piped',
stderr: 'piped',
});
const { stdout, success } = await command.output();
if (success) {
const version = new TextDecoder().decode(stdout).trim();
result.dependencies[dep.name] = {
available: true,
version,
};
} else {
throw new Error('Command failed');
}
} catch (error) {
result.dependencies[dep.name] = {
available: false,
error: error.message,
};
if (dep.required) {
result.success = false;
result.errors.push(`Required dependency '${dep.name}' is not available`);
} else {
result.warnings.push(`Optional dependency '${dep.name}' is not available`);
}
}
}
return result;
}
/**
* Check environment variables and configuration
*/
async checkEnvironment() {
const result = {
success: true,
errors: [],
warnings: [],
environment: {},
};
// Check for important environment variables
const envVars = [
{ name: 'HOME', required: false },
{ name: 'PATH', required: true },
{ name: 'PWD', required: false },
{ name: 'CLAUDE_FLOW_DEBUG', required: false },
];
for (const envVar of envVars) {
const value = Deno.env.get(envVar.name);
if (value) {
result.environment[envVar.name] = 'set';
} else {
result.environment[envVar.name] = 'not set';
if (envVar.required) {
result.success = false;
result.errors.push(`Required environment variable ${envVar.name} is not set`);
}
}
}
// Check if we're in a git repository
try {
const command = new Deno.Command('git', {
args: ['rev-parse', '--git-dir'],
cwd: this.workingDir,
stdout: 'piped',
stderr: 'piped',
});
const { success } = await command.output();
result.environment.gitRepo = success;
if (!success) {
result.warnings.push('Not in a git repository - version control recommended');
}
} catch {
result.environment.gitRepo = false;
result.warnings.push('Could not check git repository status');
}
return result;
}
/**
* Run all pre-initialization checks
*/
async runAllChecks(options = {}) {
const results = {
permissions: await this.checkPermissions(),
diskSpace: await this.checkDiskSpace(),
conflicts: await this.checkConflicts(options.force),
dependencies: await this.checkDependencies(),
environment: await this.checkEnvironment(),
};
const overallSuccess = Object.values(results).every((r) => r.success);
const allErrors = Object.values(results).flatMap((r) => r.errors || []);
const allWarnings = Object.values(results).flatMap((r) => r.warnings || []);
return {
success: overallSuccess,
results,
errors: allErrors,
warnings: allWarnings,
};
}
}