claude-flow-multilang
Version:
Revolutionary multilingual AI orchestration framework with cultural awareness and DDD architecture
400 lines (341 loc) • 10.9 kB
JavaScript
// rollback/index.js - Comprehensive rollback system for SPARC initialization
import { BackupManager } from './backup-manager.js';
import { RollbackExecutor } from './rollback-executor.js';
import { StateTracker } from './state-tracker.js';
import { RecoveryManager } from './recovery-manager.js';
import { printSuccess, printError, printWarning } from '../../../utils.js';
/**
* Main rollback orchestrator
*/
export class RollbackSystem {
constructor(workingDir) {
this.workingDir = workingDir;
this.backupManager = new BackupManager(workingDir);
this.rollbackExecutor = new RollbackExecutor(workingDir);
this.stateTracker = new StateTracker(workingDir);
this.recoveryManager = new RecoveryManager(workingDir);
}
/**
* Create backup before initialization
*/
async createPreInitBackup() {
const result = {
success: true,
backupId: null,
errors: [],
warnings: [],
};
try {
console.log('🔄 Creating pre-initialization backup...');
const backup = await this.backupManager.createBackup('pre-init');
result.backupId = backup.id;
result.success = backup.success;
if (backup.success) {
printSuccess(`Backup created: ${backup.id}`);
console.log(` 📁 Backup location: ${backup.location}`);
// Record rollback point
await this.stateTracker.recordRollbackPoint('pre-init', {
backupId: backup.id,
timestamp: Date.now(),
state: 'clean',
});
} else {
result.errors.push(...backup.errors);
printError('Failed to create backup');
}
} catch (error) {
result.success = false;
result.errors.push(`Backup creation failed: ${error.message}`);
printError(`Backup failed: ${error.message}`);
}
return result;
}
/**
* Create checkpoint during initialization
*/
async createCheckpoint(phase, data = {}) {
const result = {
success: true,
checkpointId: null,
errors: [],
};
try {
const checkpoint = await this.stateTracker.createCheckpoint(phase, data);
result.checkpointId = checkpoint.id;
result.success = checkpoint.success;
if (!checkpoint.success) {
result.errors.push(...checkpoint.errors);
}
} catch (error) {
result.success = false;
result.errors.push(`Checkpoint creation failed: ${error.message}`);
}
return result;
}
/**
* Perform full rollback to pre-initialization state
*/
async performFullRollback(backupId = null) {
const result = {
success: true,
errors: [],
warnings: [],
actions: [],
};
try {
console.log('🔄 Performing full rollback...');
// Find the appropriate backup
const targetBackup = backupId || (await this.findLatestPreInitBackup());
if (!targetBackup) {
result.success = false;
result.errors.push('No suitable backup found for rollback');
return result;
}
// Execute rollback
const rollbackResult = await this.rollbackExecutor.executeFullRollback(targetBackup);
result.success = rollbackResult.success;
result.errors.push(...rollbackResult.errors);
result.warnings.push(...rollbackResult.warnings);
result.actions.push(...rollbackResult.actions);
if (rollbackResult.success) {
printSuccess('Full rollback completed successfully');
// Update state tracking
await this.stateTracker.recordRollback(targetBackup, 'full');
} else {
printError('Full rollback failed');
}
} catch (error) {
result.success = false;
result.errors.push(`Rollback failed: ${error.message}`);
printError(`Rollback failed: ${error.message}`);
}
return result;
}
/**
* Perform partial rollback to specific checkpoint
*/
async performPartialRollback(phase, checkpointId = null) {
const result = {
success: true,
errors: [],
warnings: [],
actions: [],
};
try {
console.log(`🔄 Performing partial rollback for phase: ${phase}`);
// Find checkpoint
const checkpoint = checkpointId || (await this.findLatestCheckpoint(phase));
if (!checkpoint) {
result.success = false;
result.errors.push(`No checkpoint found for phase: ${phase}`);
return result;
}
// Execute partial rollback
const rollbackResult = await this.rollbackExecutor.executePartialRollback(phase, checkpoint);
result.success = rollbackResult.success;
result.errors.push(...rollbackResult.errors);
result.warnings.push(...rollbackResult.warnings);
result.actions.push(...rollbackResult.actions);
if (rollbackResult.success) {
printSuccess(`Partial rollback completed for phase: ${phase}`);
// Update state tracking
await this.stateTracker.recordRollback(checkpoint, 'partial', phase);
} else {
printError(`Partial rollback failed for phase: ${phase}`);
}
} catch (error) {
result.success = false;
result.errors.push(`Partial rollback failed: ${error.message}`);
printError(`Partial rollback failed: ${error.message}`);
}
return result;
}
/**
* Auto-recovery from common failures
*/
async performAutoRecovery(failureType, context = {}) {
const result = {
success: true,
errors: [],
warnings: [],
recoveryActions: [],
};
try {
console.log(`🔧 Attempting auto-recovery for: ${failureType}`);
const recoveryResult = await this.recoveryManager.performRecovery(failureType, context);
result.success = recoveryResult.success;
result.errors.push(...recoveryResult.errors);
result.warnings.push(...recoveryResult.warnings);
result.recoveryActions.push(...recoveryResult.actions);
if (recoveryResult.success) {
printSuccess(`Auto-recovery completed for: ${failureType}`);
} else {
printWarning(`Auto-recovery failed for: ${failureType}`);
}
} catch (error) {
result.success = false;
result.errors.push(`Auto-recovery failed: ${error.message}`);
printError(`Auto-recovery failed: ${error.message}`);
}
return result;
}
/**
* List available rollback points
*/
async listRollbackPoints() {
const result = {
success: true,
rollbackPoints: [],
checkpoints: [],
errors: [],
};
try {
// Get rollback points
const rollbackPoints = await this.stateTracker.getRollbackPoints();
result.rollbackPoints = rollbackPoints;
// Get checkpoints
const checkpoints = await this.stateTracker.getCheckpoints();
result.checkpoints = checkpoints;
} catch (error) {
result.success = false;
result.errors.push(`Failed to list rollback points: ${error.message}`);
}
return result;
}
/**
* Clean up old backups and checkpoints
*/
async cleanupOldBackups(keepCount = 5) {
const result = {
success: true,
cleaned: [],
errors: [],
};
try {
const cleanupResult = await this.backupManager.cleanupOldBackups(keepCount);
result.success = cleanupResult.success;
result.cleaned = cleanupResult.cleaned;
result.errors.push(...cleanupResult.errors);
if (cleanupResult.success) {
console.log(`🗑️ Cleaned up ${cleanupResult.cleaned.length} old backups`);
}
} catch (error) {
result.success = false;
result.errors.push(`Cleanup failed: ${error.message}`);
}
return result;
}
/**
* Validate rollback system integrity
*/
async validateRollbackSystem() {
const result = {
success: true,
checks: {},
errors: [],
warnings: [],
};
try {
// Check backup system
const backupCheck = await this.backupManager.validateBackupSystem();
result.checks.backup = backupCheck;
if (!backupCheck.success) {
result.success = false;
result.errors.push(...backupCheck.errors);
}
// Check state tracking
const stateCheck = await this.stateTracker.validateStateTracking();
result.checks.stateTracking = stateCheck;
if (!stateCheck.success) {
result.warnings.push(...stateCheck.errors);
}
// Check recovery system
const recoveryCheck = await this.recoveryManager.validateRecoverySystem();
result.checks.recovery = recoveryCheck;
if (!recoveryCheck.success) {
result.warnings.push(...recoveryCheck.errors);
}
} catch (error) {
result.success = false;
result.errors.push(`Rollback system validation failed: ${error.message}`);
}
return result;
}
// Helper methods
async findLatestPreInitBackup() {
try {
const rollbackPoints = await this.stateTracker.getRollbackPoints();
const preInitPoints = rollbackPoints.filter((point) => point.type === 'pre-init');
if (preInitPoints.length > 0) {
return preInitPoints.sort((a, b) => b.timestamp - a.timestamp)[0].backupId;
}
return null;
} catch {
return null;
}
}
async findLatestCheckpoint(phase) {
try {
const checkpoints = await this.stateTracker.getCheckpoints();
const phaseCheckpoints = checkpoints.filter((checkpoint) => checkpoint.phase === phase);
if (phaseCheckpoints.length > 0) {
return phaseCheckpoints.sort((a, b) => b.timestamp - a.timestamp)[0];
}
return null;
} catch {
return null;
}
}
}
/**
* Atomic operation wrapper
*/
export class AtomicOperation {
constructor(rollbackSystem, operationName) {
this.rollbackSystem = rollbackSystem;
this.operationName = operationName;
this.checkpointId = null;
this.completed = false;
}
/**
* Begin atomic operation
*/
async begin() {
const checkpoint = await this.rollbackSystem.createCheckpoint(`atomic-${this.operationName}`, {
operation: this.operationName,
started: Date.now(),
});
this.checkpointId = checkpoint.checkpointId;
return checkpoint.success;
}
/**
* Commit atomic operation
*/
async commit() {
this.completed = true;
// Mark checkpoint as committed
if (this.checkpointId) {
await this.rollbackSystem.stateTracker.updateCheckpoint(this.checkpointId, {
status: 'committed',
completed: Date.now(),
});
}
}
/**
* Rollback atomic operation
*/
async rollback() {
if (this.checkpointId && !this.completed) {
await this.rollbackSystem.performPartialRollback(
`atomic-${this.operationName}`,
this.checkpointId,
);
}
}
}
/**
* Create and manage atomic operations
*/
export function createAtomicOperation(rollbackSystem, operationName) {
return new AtomicOperation(rollbackSystem, operationName);
}