Files
2025-11-29 18:17:04 +08:00

142 lines
5.1 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* TDD Automation Rollback Utility
*
* Restores previous CLAUDE.md from backup and optionally removes all TDD automation.
*/
const fs = require('fs');
const path = require('path');
// Import utilities from parent directory
const projectRoot = process.cwd();
const skillRoot = path.join(__dirname, '..');
// Try to load ClaudeMdValidator from skill location
let ClaudeMdValidator;
try {
ClaudeMdValidator = require(path.join(skillRoot, 'utils', 'validate-claude-md.js'));
} catch {
// If skill utils not available, use local copy in .tdd-automation
try {
ClaudeMdValidator = require(path.join(projectRoot, '.tdd-automation', 'utils', 'validate-claude-md.js'));
} catch {
console.error('❌ Error: ClaudeMdValidator not found');
console.error(' This script must be run from project root or .tdd-automation directory');
process.exit(1);
}
}
async function rollbackTddAutomation() {
console.log('🔄 TDD Automation Rollback Utility\n');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
const validator = new ClaudeMdValidator(projectRoot);
// List available backups
const backups = validator.listBackups();
if (backups.length === 0) {
console.log('❌ No backup files found');
console.log(' Cannot rollback without backup');
console.log('');
console.log(' Backup files should be in: .claude/CLAUDE.md.backup.*');
console.log('');
process.exit(1);
}
console.log(`📋 Found ${backups.length} backup(s):\n`);
backups.forEach((backup, i) => {
const age = getTimeAgo(backup.created);
console.log(`${i + 1}. ${backup.name}`);
console.log(` Created: ${backup.created.toISOString()} (${age})`);
console.log(` Size: ${formatBytes(backup.size)}\n`);
});
// Use most recent backup
const latestBackup = backups[0];
console.log(`🔄 Rolling back to most recent backup:\n`);
console.log(` ${latestBackup.name}`);
console.log(` Created: ${latestBackup.created.toISOString()}\n`);
// Create backup of current state before rollback
console.log('🔒 Creating safety backup of current state...');
const currentBackup = validator.createBackup();
if (currentBackup.success) {
console.log(`✅ Current state backed up to:`);
console.log(` ${path.basename(currentBackup.path)}\n`);
} else {
console.log(`⚠️ Could not backup current state: ${currentBackup.reason}`);
console.log(` Proceeding with rollback anyway...\n`);
}
// Perform rollback
console.log('🔄 Performing rollback...');
const result = validator.rollback(latestBackup.path);
if (result.success) {
console.log('✅ Rollback successful!\n');
console.log(' CLAUDE.md has been restored from:');
console.log(` ${path.basename(result.restoredFrom)}`);
console.log(` Size: ${formatBytes(result.size)}\n`);
if (currentBackup.success) {
console.log(' Your previous state was saved to:');
console.log(` ${path.basename(currentBackup.path)}\n`);
}
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
console.log('⚠️ TDD automation configuration has been removed from CLAUDE.md\n');
console.log(' Other TDD automation components remain:');
console.log(' • .tdd-automation/ directory');
console.log(' • npm scripts (test:tdd, validate:tdd, etc.)');
console.log(' • git hooks (.git/hooks/pre-commit)');
console.log(' • Claude hooks (.claude/hooks/tdd-auto-enforcer.sh)\n');
console.log(' To remove all TDD automation components:');
console.log(' node .tdd-automation/scripts/uninstall-tdd.js\n');
console.log(' To reinstall TDD automation:');
console.log(' Run the tdd-automation skill again\n');
} else {
console.error('❌ Rollback failed:', result.reason);
console.error('');
console.error(' You may need to manually restore CLAUDE.md from backup');
console.error(` Backup location: ${latestBackup.path}`);
console.error('');
process.exit(1);
}
}
function getTimeAgo(date) {
const now = new Date();
const diff = now - date;
const seconds = Math.floor(diff / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
if (days > 0) return `${days} day${days > 1 ? 's' : ''} ago`;
if (hours > 0) return `${hours} hour${hours > 1 ? 's' : ''} ago`;
if (minutes > 0) return `${minutes} minute${minutes > 1 ? 's' : ''} ago`;
return `${seconds} second${seconds > 1 ? 's' : ''} ago`;
}
function formatBytes(bytes) {
if (bytes < 1024) return `${bytes} bytes`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}
// Run if called directly
if (require.main === module) {
rollbackTddAutomation().catch(error => {
console.error('❌ Unexpected error:', error.message);
process.exit(1);
});
}
module.exports = { rollbackTddAutomation };