Skip to main content

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
function run()
deleted
number
Number of files deleted

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

node src/ops/cleanup.js

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' }

Build docs developers (and LLMs) love