import { loadConfig } from './config.js'; import { closePool, withTransaction } from './db.js'; import { writeEmergencyDiagnostic } from './diagnostics.js'; export async function runRetention(): Promise<{ archivedTasks: number; deletedTasks: number; deletedAuditEvents: number; deletedSessions: number; }> { const config = loadConfig(); if (!config.DATA_RETENTION_ENABLED) { return { archivedTasks: 0, deletedTasks: 0, deletedAuditEvents: 0, deletedSessions: 0 }; } return withTransaction(config, async (client) => { const archivedTasks = await client.query( `UPDATE tasks SET archived_at = now(), archived_by = NULL, archive_reason = 'retention_policy', updated_at = now() WHERE created_at < now() - ($1 * interval '1 day') AND status IN ('completed', 'cancelled', 'parse_failed') AND archived_at IS NULL`, [config.DATA_RETENTION_DAYS] ); const deletedSessions = await client.query( `DELETE FROM sessions WHERE (revoked_at IS NOT NULL AND revoked_at < now() - interval '30 days') OR (expires_at IS NOT NULL AND expires_at < now() - interval '30 days')`, [] ); return { archivedTasks: archivedTasks.rowCount || 0, deletedTasks: 0, deletedAuditEvents: 0, deletedSessions: deletedSessions.rowCount || 0 }; }); } if (process.argv[1]?.endsWith('/retention.ts') || process.argv[1]?.endsWith('/retention.js')) { runRetention() .then((result) => console.log(JSON.stringify({ ok: true, diagnostic_event: 'retention.completed', diagnostic_stage: 'data_retention', ...result }))) .catch((error) => { writeEmergencyDiagnostic('retention.failed', error, { diagnostic_stage: 'data_retention' }); process.exitCode = 1; }) .finally(() => closePool()); }