Overview
The cleanup module removes old GEP prompt artifacts to prevent disk bloat while preserving recent files for debugging.
Location: src/ops/cleanup.js
Function
run()
Clean up old GEP artifacts.
Location: src/ops/cleanup.js:20
Cleanup Policy
Artifact Pattern
Location: src/ops/cleanup.js:24
const files = fs.readdirSync(evoDir)
.filter(f => /^gep_prompt_.*\.(json|txt)$/.test(f))
.map(f => {
const full = path.join(evoDir, f);
const stat = fs.statSync(full);
return { name: f, path: full, mtime: stat.mtimeMs };
})
.sort((a, b) => b.mtime - a.mtime); // newest first
Matched Files:
gep_prompt_*.json
gep_prompt_*.txt
Phase 1: Age-Based Cleanup
Location: src/ops/cleanup.js:9
const MAX_AGE_MS = 24 * 60 * 60 * 1000; // 24 hours
const MIN_KEEP = 10;
const filesToDelete = [];
for (let i = MIN_KEEP; i < files.length; i++) {
if (now - files[i].mtime > MAX_AGE_MS) {
filesToDelete.push(files[i].path);
}
}
if (filesToDelete.length > 0) {
deleted += safeBatchDelete(filesToDelete);
}
Policy:
- Keep at least 10 most recent files
- Delete files older than 24 hours (beyond the first 10)
Phase 2: Size-Based Cap
Location: src/ops/cleanup.js:49
const MAX_FILES = 10;
const remainingFiles = fs.readdirSync(evoDir)
.filter(f => /^gep_prompt_.*\.(json|txt)$/.test(f))
.map(f => {
const full = path.join(evoDir, f);
const stat = fs.statSync(full);
return { name: f, path: full, mtime: stat.mtimeMs };
})
.sort((a, b) => b.mtime - a.mtime); // newest first
if (remainingFiles.length > MAX_FILES) {
const toDelete = remainingFiles.slice(MAX_FILES).map(f => f.path);
deleted += safeBatchDelete(toDelete);
}
Policy:
- Keep maximum 10 files total
- Delete oldest files beyond the cap
Safe Batch Delete
Location: src/ops/cleanup.js:12
function safeBatchDelete(batch) {
let deleted = 0;
for (const file of batch) {
try {
fs.unlinkSync(file);
deleted++;
} catch (_) {}
}
return deleted;
}
Deletion errors are silently ignored to prevent cleanup failures from blocking evolution.
CLI Usage
Example Usage
const { run } = require('./src/ops/cleanup');
const count = run();
if (count > 0) {
console.log('[Cleanup] Deleted', count, 'old artifacts');
} else {
console.log('[Cleanup] No files to delete');
}
Integration with Evolution Cycle
Location: src/evolve.js:781
if (!IS_DRY_RUN) {
performMaintenance();
} else {
console.log('[Maintenance] Skipped (dry-run mode).');
}
function performMaintenance() {
// Auto-update check
checkAndAutoUpdate();
// Clean up evolver's own hand sessions immediately
const evolverFiles = files.filter(f => f.startsWith('evolver_hand_'));
for (const f of evolverFiles) {
try {
fs.unlinkSync(path.join(AGENT_SESSIONS_DIR, f));
} catch (_) {}
}
// Archive old non-evolver sessions when count exceeds threshold
if (remaining < 100) return;
const toArchive = fileStats.slice(0, fileStats.length - 50);
for (const file of toArchive) {
fs.renameSync(oldPath, newPath);
}
// GEP artifact cleanup
require('./ops/cleanup').run();
}
Scheduled Cleanup
const { run } = require('./src/ops/cleanup');
function scheduleCleanup() {
// Run cleanup every hour
setInterval(() => {
const count = run();
if (count > 0) {
console.log('[ScheduledCleanup] Deleted', count, 'artifact(s)');
}
}, 60 * 60 * 1000);
}
scheduleCleanup();
Cleanup Statistics
const fs = require('fs');
const path = require('path');
const { getEvolutionDir } = require('./gep/paths');
function getCleanupStats() {
const evoDir = getEvolutionDir();
const files = fs.readdirSync(evoDir)
.filter(f => /^gep_prompt_.*\.(json|txt)$/.test(f))
.map(f => {
const full = path.join(evoDir, f);
const stat = fs.statSync(full);
return {
name: f,
size: stat.size,
age: Date.now() - stat.mtimeMs
};
});
const totalSize = files.reduce((sum, f) => sum + f.size, 0);
const oldestAge = Math.max(...files.map(f => f.age));
return {
count: files.length,
totalSizeMb: (totalSize / 1024 / 1024).toFixed(2),
oldestAgeDays: (oldestAge / 1000 / 60 / 60 / 24).toFixed(1),
};
}
const stats = getCleanupStats();
console.log('Artifact stats:', stats);
// Output: { count: 8, totalSizeMb: '12.5', oldestAgeDays: '2.3' }