@endlessblink/like-i-said-v2
Version:
Task Management & Memory for Claude - Track tasks, remember context, and maintain continuity across sessions with 27 powerful tools. Works with Claude Desktop and Claude Code.
156 lines (127 loc) ⢠4.93 kB
JavaScript
const fs = require('fs-extra');
const path = require('path');
const { execSync } = require('child_process');
/**
* Memory Backup Script - Phase 1 of Migration Plan
* Creates a complete backup of the memories folder with verification
*/
async function createBackup() {
const memoriesPath = path.join(__dirname, '..', 'memories');
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
const backupPath = path.join(__dirname, '..', `memory-backup-${timestamp}`);
console.log('š Starting memory backup process...');
console.log(`š Source: ${memoriesPath}`);
console.log(`š¾ Destination: ${backupPath}`);
try {
// Check if memories folder exists
if (!await fs.pathExists(memoriesPath)) {
throw new Error('Memories folder not found!');
}
// Get statistics
const stats = await getDirectoryStats(memoriesPath);
console.log(`\nš Backup Statistics:`);
console.log(` Total files: ${stats.fileCount}`);
console.log(` Total size: ${formatBytes(stats.totalSize)}`);
console.log(` Folders: ${stats.folderCount}`);
// Create backup
console.log('\nš Creating backup...');
await fs.copy(memoriesPath, backupPath, {
preserveTimestamps: true,
errorOnExist: true
});
// Verify backup
console.log('\nā
Verifying backup integrity...');
const backupStats = await getDirectoryStats(backupPath);
if (backupStats.fileCount !== stats.fileCount) {
throw new Error(`File count mismatch! Original: ${stats.fileCount}, Backup: ${backupStats.fileCount}`);
}
// Create backup manifest
const manifest = {
timestamp,
originalPath: memoriesPath,
backupPath,
statistics: stats,
files: await getFileList(memoriesPath)
};
await fs.writeJson(path.join(backupPath, 'backup-manifest.json'), manifest, { spaces: 2 });
console.log('\nā
Backup completed successfully!');
console.log(`š Manifest created: ${path.join(backupPath, 'backup-manifest.json')}`);
return backupPath;
} catch (error) {
console.error('ā Backup failed:', error.message);
// Clean up partial backup if it exists
if (await fs.pathExists(backupPath)) {
await fs.remove(backupPath);
}
throw error;
}
}
async function getDirectoryStats(dirPath) {
const stats = {
fileCount: 0,
folderCount: 0,
totalSize: 0
};
async function walkDir(currentPath) {
const items = await fs.readdir(currentPath);
for (const item of items) {
const itemPath = path.join(currentPath, item);
const itemStats = await fs.stat(itemPath);
if (itemStats.isDirectory()) {
stats.folderCount++;
await walkDir(itemPath);
} else {
stats.fileCount++;
stats.totalSize += itemStats.size;
}
}
}
await walkDir(dirPath);
return stats;
}
async function getFileList(dirPath) {
const files = [];
async function walkDir(currentPath, relativePath = '') {
const items = await fs.readdir(currentPath);
for (const item of items) {
const itemPath = path.join(currentPath, item);
const itemRelativePath = path.join(relativePath, item);
const itemStats = await fs.stat(itemPath);
if (itemStats.isDirectory()) {
await walkDir(itemPath, itemRelativePath);
} else {
files.push({
path: itemRelativePath,
size: itemStats.size,
modified: itemStats.mtime
});
}
}
}
await walkDir(dirPath);
return files;
}
function formatBytes(bytes) {
const units = ['B', 'KB', 'MB', 'GB'];
let size = bytes;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(2)} ${units[unitIndex]}`;
}
// Run the backup
if (require.main === module) {
createBackup()
.then(backupPath => {
console.log(`\nš Backup location: ${backupPath}`);
process.exit(0);
})
.catch(error => {
console.error('\nā Backup failed:', error);
process.exit(1);
});
}
module.exports = { createBackup };