import "dotenv/config"; import { existsSync, readFileSync, readdirSync } from "node:fs"; import { join } from "node:path"; import { loadConfig } from "../src/config.js"; import { createLogger } from "../src/logger.js"; import { MySqlSessionStore } from "../src/sessions/mysql_store.js"; import type { SessionMessage, SessionMeta } from "../src/sessions/store.js"; interface SessionIndexFile { sessions?: Record; } const config = loadConfig(); const logger = createLogger(config.logLevel); const dryRun = process.argv.includes("--dry-run"); async function main(): Promise { const store = new MySqlSessionStore(config.mysql, logger); await store.init(); let sessionCount = 0; let messageCount = 0; let skipped = 0; if (existsSync(config.sessionsFile)) { const parsed = JSON.parse(readFileSync(config.sessionsFile, "utf8")) as SessionIndexFile; const sessions = Object.values(parsed.sessions ?? {}); for (const meta of sessions) { if (!meta.session_id) { skipped += 1; continue; } if (!dryRun) await store.upsertSession(meta); sessionCount += 1; } } if (existsSync(config.messagesDir)) { for (const file of readdirSync(config.messagesDir)) { if (!file.endsWith(".jsonl")) continue; const sessionId = file.slice(0, -".jsonl".length); const lines = readFileSync(join(config.messagesDir, file), "utf8").split("\n"); for (const line of lines) { const trimmed = line.trim(); if (!trimmed) continue; let message: SessionMessage; try { message = JSON.parse(trimmed) as SessionMessage; } catch { skipped += 1; continue; } if (!message.id || !message.session_id) { message.id = message.id || `${sessionId}-${messageCount}`; message.session_id = message.session_id || sessionId; } if (!dryRun) await store.insertMessage(message); messageCount += 1; } } } console.log( `${dryRun ? "[dry-run] " : ""}migrated sessions=${sessionCount} messages=${messageCount} skipped=${skipped}`, ); await store.close(); } main().catch((error) => { console.error("migration failed:", error); process.exit(1); });