#!/usr/bin/env node 'use strict'; // 默认预览;--apply 才会让服务端在 idle 状态下备份并原子迁移。 // CC_WEB_PASSWORD=... node scripts/migrate-session-history.js <会话 ID> [--apply] const WebSocket = require('ws'); const sessionId = process.argv.slice(2).find((arg) => !arg.startsWith('--')); if (!sessionId || !/^[0-9a-f-]{36}$/i.test(sessionId)) { console.error('用法:node scripts/migrate-session-history.js <会话 ID> [--apply]'); process.exit(1); } const serverUrl = process.env.CC_WEB_SERVER_URL || `ws://127.0.0.1:${process.env.PORT || '8002'}/ws`; const ws = new WebSocket(serverUrl); const timer = setTimeout(() => finish({ ok: false, code: 'timeout' }), 15000); let finished = false; function finish(result) { if (finished) return; finished = true; clearTimeout(timer); console.log(JSON.stringify(result, null, 2)); process.exitCode = result.ok ? 0 : 1; ws.terminate(); } ws.on('open', () => ws.send(JSON.stringify({ type: 'auth', password: process.env.CC_WEB_PASSWORD || '' }))); ws.on('error', (error) => finish({ ok: false, code: 'connection_failed', message: error.message })); ws.on('close', () => { if (!finished) finish({ ok: false, code: 'connection_closed' }); }); ws.on('message', (raw) => { let msg; try { msg = JSON.parse(String(raw)); } catch { return; } if (msg.type === 'auth_result') { if (!msg.success) return finish({ ok: false, code: 'authentication_failed' }); ws.send(JSON.stringify({ type: 'migrate_session_history', sessionId, apply: process.argv.includes('--apply') })); } else if (msg.type === 'migrate_session_history_result' || msg.type === 'error') { finish(msg); } });