import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { resolveSessionTranscriptPath } from "../config/sessions.js"; export function readSessionMessages( sessionId: string, storePath: string | undefined, sessionFile?: string, ): unknown[] { const candidates = resolveSessionTranscriptCandidates( sessionId, storePath, sessionFile, ); const filePath = candidates.find((p) => fs.existsSync(p)); if (!filePath) return []; const lines = fs.readFileSync(filePath, "utf-8").split(/\r?\n/); const messages: unknown[] = []; for (const line of lines) { if (!line.trim()) continue; try { const parsed = JSON.parse(line); if (parsed?.message) { messages.push(parsed.message); } } catch { // ignore bad lines } } return messages; } export function resolveSessionTranscriptCandidates( sessionId: string, storePath: string | undefined, sessionFile?: string, agentId?: string, ): string[] { const candidates: string[] = []; if (sessionFile) candidates.push(sessionFile); if (storePath) { const dir = path.dirname(storePath); candidates.push(path.join(dir, `${sessionId}.jsonl`)); } if (agentId) { candidates.push(resolveSessionTranscriptPath(sessionId, agentId)); } candidates.push( path.join(os.homedir(), ".clawdbot", "sessions", `${sessionId}.jsonl`), ); return candidates; } export function archiveFileOnDisk(filePath: string, reason: string): string { const ts = new Date().toISOString().replaceAll(":", "-"); const archived = `${filePath}.${reason}.${ts}`; fs.renameSync(filePath, archived); return archived; } function jsonUtf8Bytes(value: unknown): number { try { return Buffer.byteLength(JSON.stringify(value), "utf8"); } catch { return Buffer.byteLength(String(value), "utf8"); } } export function capArrayByJsonBytes( items: T[], maxBytes: number, ): { items: T[]; bytes: number } { if (items.length === 0) return { items, bytes: 2 }; const parts = items.map((item) => jsonUtf8Bytes(item)); let bytes = 2 + parts.reduce((a, b) => a + b, 0) + (items.length - 1); let start = 0; while (bytes > maxBytes && start < items.length - 1) { bytes -= parts[start] + 1; start += 1; } const next = start > 0 ? items.slice(start) : items; return { items: next, bytes }; }