#!/usr/bin/env node /** * patch-x10-archive-cleanup.js * session-start-restore.js handoff 归档后加清理逻辑: 保留最新 20 个, 删最旧的 * * 幂等: SENTINEL 标记 */ 'use strict'; const fs = require('fs'); const path = require('path'); const SENTINEL = '[PATCH-X10-ARCHIVE-CLEANUP]'; const TARGET = path.join(__dirname, '..', '..', 'hooks', 'session-start-restore.js'); if (!fs.existsSync(TARGET)) { console.log('SKIP: target not found'); process.exit(0); } let src = fs.readFileSync(TARGET, 'utf8'); if (src.includes(SENTINEL)) { console.log('SKIP: already patched'); process.exit(0); } // 在归档 renameSync 之后、messages.push 之前插入清理逻辑 // 规范化换行符后匹配 (兼容 CRLF) const srcNorm = src.replace(/\r\n/g, '\n'); const anchor = " const archiveName = `handoff-${Date.now()}.json`;\n fs.renameSync(HANDOFF_PATH, path.join(SESSION_STATE_DIR, archiveName));"; if (!srcNorm.includes(anchor)) { console.error('FAIL: anchor not found'); process.exit(1); } src = srcNorm; const cleanupBlock = ` const archiveName = \`handoff-\${Date.now()}.json\`; fs.renameSync(HANDOFF_PATH, path.join(SESSION_STATE_DIR, archiveName)); // ${SENTINEL} try { const archives = fs.readdirSync(SESSION_STATE_DIR) .filter(f => /^handoff-(\\d+|expired-\\d+)\\.json$/.test(f)) .sort(); if (archives.length > 20) { for (const old of archives.slice(0, archives.length - 20)) { try { fs.unlinkSync(path.join(SESSION_STATE_DIR, old)); } catch {} } } } catch {}`; src = src.replace(anchor, cleanupBlock); const tmp = TARGET + '.tmp.' + process.pid; fs.writeFileSync(tmp, src, 'utf8'); fs.renameSync(tmp, TARGET); console.log('OK: X10 archive cleanup (keep newest 20) patched');