import * as plugins from '../plugins.js'; import * as paths from '../paths.js'; import type { IProcessLog } from '../shared/protocol/ipc.types.js'; import type { ProcessId } from '../shared/protocol/id.js'; /** * Manages persistent log storage for processes */ export class LogPersistence { private logsDir: string; constructor() { this.logsDir = plugins.path.join(paths.tspmDir, 'logs'); } /** * Get the log file path for a process */ private getLogFilePath(processId: ProcessId): string { return plugins.path.join(this.logsDir, `process-${processId}.json`); } /** * Ensure the logs directory exists */ private async ensureLogsDir(): Promise { await plugins.smartfile.fs.ensureDir(this.logsDir); } /** * Save logs to disk */ public async saveLogs(processId: ProcessId, logs: IProcessLog[]): Promise { await this.ensureLogsDir(); const filePath = this.getLogFilePath(processId); // Write logs as JSON await plugins.smartfile.memory.toFs( JSON.stringify(logs, null, 2), filePath ); } /** * Load logs from disk */ public async loadLogs(processId: ProcessId): Promise { const filePath = this.getLogFilePath(processId); try { const exists = await plugins.smartfile.fs.fileExists(filePath); if (!exists) { return []; } const content = await plugins.smartfile.fs.toStringSync(filePath); const logs = JSON.parse(content) as IProcessLog[]; // Convert date strings back to Date objects return logs.map(log => ({ ...log, timestamp: new Date(log.timestamp) })); } catch (error) { console.error(`Failed to load logs for process ${processId}:`, error); return []; } } /** * Delete logs from disk after loading */ public async deleteLogs(processId: ProcessId): Promise { const filePath = this.getLogFilePath(processId); try { const exists = await plugins.smartfile.fs.fileExists(filePath); if (exists) { await plugins.smartfile.fs.remove(filePath); } } catch (error) { console.error(`Failed to delete logs for process ${processId}:`, error); } } /** * Calculate approximate memory size of logs in bytes */ public static calculateLogMemorySize(logs: IProcessLog[]): number { // Estimate based on JSON string size // This is an approximation but good enough for our purposes return JSON.stringify(logs).length; } /** * Clean up old log files (for maintenance) */ public async cleanupOldLogs(): Promise { try { await this.ensureLogsDir(); const files = await plugins.smartfile.fs.listFileTree(this.logsDir, '*.json'); for (const file of files) { const filePath = plugins.path.join(this.logsDir, file); const stats = await plugins.smartfile.fs.stat(filePath); // Delete files older than 7 days const ageInDays = (Date.now() - stats.mtime.getTime()) / (1000 * 60 * 60 * 24); if (ageInDays > 7) { await plugins.smartfile.fs.remove(filePath); } } } catch (error) { console.error('Failed to cleanup old logs:', error); } } }