@sethdouglasford/claude-flow
Version:
Claude Code Flow - Advanced AI-powered development workflows with SPARC methodology
280 lines • 11.3 kB
JavaScript
/**
* Migration Validator - Validates successful migration
*/
import * as fs from "fs-extra";
import * as path from "node:path";
import chalk from "chalk";
import { readFile } from "node:fs/promises";
import glob from "glob";
export class MigrationValidator {
requiredFiles = [
".claude/commands/sparc.md",
".claude/commands/claude-flow-help.md",
".claude/commands/claude-flow-memory.md",
".claude/BATCHTOOLS_GUIDE.md",
".claude/BATCHTOOLS_BEST_PRACTICES.md",
];
requiredCommands = [
"sparc",
"sparc-architect",
"sparc-code",
"sparc-tdd",
"claude-flow-help",
"claude-flow-memory",
"claude-flow-swarm",
];
async validate(projectPath) {
const result = {
valid: true,
checks: [],
errors: [],
warnings: [],
};
// Check file structure
await this.validateFileStructure(projectPath, result);
// Check command files
await this.validateCommandFiles(projectPath, result);
// Check configuration files
await this.validateConfiguration(projectPath, result);
// Check file integrity
await this.validateFileIntegrity(projectPath, result);
// Check functionality
await this.validateFunctionality(projectPath, result);
// Overall validation
result.valid = result.errors.length === 0;
return result;
}
async validateFileStructure(projectPath, result) {
const check = {
name: "File Structure",
passed: true,
};
// Check .claude directory exists
const claudePath = path.join(projectPath, ".claude");
if (!await fs.pathExists(claudePath)) {
check.passed = false;
result.errors.push(".claude directory not found");
}
// Check commands directory
const commandsPath = path.join(claudePath, "commands");
if (!await fs.pathExists(commandsPath)) {
check.passed = false;
result.errors.push(".claude/commands directory not found");
}
// Check required files
for (const file of this.requiredFiles) {
const filePath = path.join(projectPath, file);
if (!await fs.pathExists(filePath)) {
check.passed = false;
result.errors.push(`Required file missing: ${file}`);
}
}
result.checks.push(check);
}
async validateCommandFiles(projectPath, result) {
const check = {
name: "Command Files",
passed: true,
};
const commandsPath = path.join(projectPath, ".claude/commands");
if (await fs.pathExists(commandsPath)) {
for (const command of this.requiredCommands) {
const commandFile = path.join(commandsPath, `${command}.md`);
const sparcCommandFile = path.join(commandsPath, "sparc", `${command.replace("sparc-", "")}.md`);
const hasMainFile = await fs.pathExists(commandFile);
const hasSparcFile = await fs.pathExists(sparcCommandFile);
if (!hasMainFile && !hasSparcFile) {
check.passed = false;
result.errors.push(`Command file missing: ${command}.md`);
}
else {
// Validate file content
const filePath = hasMainFile ? commandFile : sparcCommandFile;
await this.validateCommandFileContent(filePath, command, result);
}
}
}
else {
check.passed = false;
result.errors.push("Commands directory not found");
}
result.checks.push(check);
}
async validateCommandFileContent(filePath, command, result) {
try {
const content = await readFile(filePath, "utf-8");
// Check for minimum content requirements
const hasDescription = content.includes("description") || content.includes("Description");
const hasInstructions = content.length > 100; // Minimum content length
if (!hasDescription) {
result.warnings.push(`Command ${command} may be missing description`);
}
if (!hasInstructions) {
result.warnings.push(`Command ${command} may have insufficient content`);
}
// Check for optimization indicators
const hasOptimizedContent = content.includes("optimization") ||
content.includes("performance") ||
content.includes("efficient");
if (!hasOptimizedContent && command.includes("sparc")) {
result.warnings.push(`SPARC command ${command} may not be optimized`);
}
}
catch (error) {
result.errors.push(`Failed to validate ${command}: ${error.message}`);
}
}
async validateConfiguration(projectPath, result) {
const check = {
name: "Configuration Files",
passed: true,
};
// Check CLAUDE.md
const claudeMdPath = path.join(projectPath, "CLAUDE.md");
if (await fs.pathExists(claudeMdPath)) {
const content = await readFile(claudeMdPath, "utf-8");
// Check for SPARC configuration
if (!content.includes("SPARC")) {
result.warnings.push("CLAUDE.md may not include SPARC configuration");
}
// Check for key sections
const requiredSections = [
"Project Overview",
"SPARC Development",
"Memory Integration",
];
for (const section of requiredSections) {
if (!content.includes(section)) {
result.warnings.push(`CLAUDE.md missing section: ${section}`);
}
}
}
else {
result.warnings.push("CLAUDE.md not found");
}
// Check .roomodes
const roomodesPath = path.join(projectPath, ".roomodes");
if (await fs.pathExists(roomodesPath)) {
try {
const roomodes = await fs.readJson(roomodesPath);
const requiredModes = ["architect", "code", "tdd", "debug"];
for (const mode of requiredModes) {
if (!roomodes[mode]) {
result.warnings.push(`Missing SPARC mode: ${mode}`);
}
}
}
catch (error) {
result.errors.push(`Invalid .roomodes file: ${error.message}`);
check.passed = false;
}
}
result.checks.push(check);
}
async validateFileIntegrity(projectPath, result) {
const check = {
name: "File Integrity",
passed: true,
};
// Check for corrupted files
const claudePath = path.join(projectPath, ".claude");
if (await fs.pathExists(claudePath)) {
const files = glob.sync("**/*.md", {
cwd: claudePath,
absolute: true,
});
for (const file of files) {
try {
const content = await readFile(file, "utf-8");
// Basic integrity checks
if (content.length === 0) {
result.errors.push(`Empty file: ${file}`);
check.passed = false;
}
// Check for binary data in text files
if (content.includes("\0")) {
result.errors.push(`Corrupted text file: ${file}`);
check.passed = false;
}
}
catch (error) {
result.errors.push(`Cannot read file ${file}: ${error.message}`);
check.passed = false;
}
}
}
result.checks.push(check);
}
async validateFunctionality(projectPath, result) {
const check = {
name: "Functionality",
passed: true,
};
// Check directory permissions
const claudePath = path.join(projectPath, ".claude");
if (await fs.pathExists(claudePath)) {
try {
// Test write permissions
const testFile = path.join(claudePath, ".test-write");
await fs.writeFile(testFile, "test");
await fs.remove(testFile);
}
catch (error) {
result.warnings.push(".claude directory may not be writable");
}
}
// Check for potential conflicts
const packageJsonPath = path.join(projectPath, "package.json");
if (await fs.pathExists(packageJsonPath)) {
try {
const packageJson = await fs.readJson(packageJsonPath);
// Check for script conflicts
const scripts = packageJson.scripts || {};
const conflictingScripts = Object.keys(scripts).filter(script => script.startsWith("claude-flow") || script.startsWith("sparc"));
if (conflictingScripts.length > 0) {
result.warnings.push(`Potential script conflicts: ${conflictingScripts.join(", ")}`);
}
}
catch (error) {
result.warnings.push("Could not validate package.json");
}
}
result.checks.push(check);
}
printValidation(validation) {
console.log(chalk.bold("\n✅ Migration Validation Report"));
console.log(chalk.gray("─".repeat(50)));
console.log(`\n${chalk.bold("Overall Status:")} ${validation.valid ? chalk.green("✓ Valid") : chalk.red("✗ Invalid")}`);
// Show checks
console.log(chalk.bold("\n📋 Validation Checks:"));
validation.checks.forEach(check => {
const status = check.passed ? chalk.green("✓") : chalk.red("✗");
console.log(` ${status} ${check.name}`);
if (check.message) {
console.log(` ${chalk.gray(check.message)}`);
}
});
// Show errors
if (validation.errors.length > 0) {
console.log(chalk.bold("\n❌ Errors:"));
validation.errors.forEach(error => {
console.log(` • ${chalk.red(error)}`);
});
}
// Show warnings
if (validation.warnings.length > 0) {
console.log(chalk.bold("\n⚠️ Warnings:"));
validation.warnings.forEach(warning => {
console.log(` • ${chalk.yellow(warning)}`);
});
}
console.log(chalk.gray(`\n${"─".repeat(50)}`));
if (validation.valid) {
console.log(chalk.green("\n🎉 Migration validation passed! Your project is ready to use optimized prompts."));
}
else {
console.log(chalk.red("\n⚠️ Migration validation failed. Please address the errors above."));
}
}
}
//# sourceMappingURL=migration-validator.js.map