import fs from 'node:fs'; import path from 'node:path'; const DEFAULT_MAX_LOG_BYTES = 2 * 1024 * 1024; export function resolvePageDataLogDir(workspaceRoot) { return path.join(workspaceRoot, '.mindspace', 'page-data-logs'); } export function resolvePageDataLogPath(workspaceRoot, pageId) { const safePageId = String(pageId ?? '').trim(); if (!safePageId || /[\\/]/.test(safePageId)) { throw Object.assign(new Error('pageId 无效'), { code: 'invalid_page_id' }); } return path.join(resolvePageDataLogDir(workspaceRoot), `${safePageId}.jsonl`); } export function appendPageDataLog(workspaceRoot, pageId, entry, { maxBytes = DEFAULT_MAX_LOG_BYTES } = {}) { const logPath = resolvePageDataLogPath(workspaceRoot, pageId); fs.mkdirSync(path.dirname(logPath), { recursive: true }); const line = `${JSON.stringify({ ...entry, at: entry.at ?? new Date().toISOString() })}\n`; fs.appendFileSync(logPath, line, 'utf8'); if (maxBytes > 0 && fs.existsSync(logPath) && fs.statSync(logPath).size > maxBytes) { const raw = fs.readFileSync(logPath, 'utf8').trim().split('\n'); const trimmed = raw.slice(-Math.max(50, Math.floor(raw.length / 2))); fs.writeFileSync(logPath, `${trimmed.join('\n')}\n`, 'utf8'); } return line; } export function listPageDataLogs(workspaceRoot, pageId, { limit = 100, offset = 0 } = {}) { const logPath = resolvePageDataLogPath(workspaceRoot, pageId); if (!fs.existsSync(logPath)) return []; const lines = fs.readFileSync(logPath, 'utf8').trim().split('\n').filter(Boolean); const parsed = lines .map((line) => { try { return JSON.parse(line); } catch { return null; } }) .filter(Boolean); const safeOffset = Math.max(0, Number(offset ?? 0)); const safeLimit = Math.min(Math.max(1, Number(limit ?? 100)), 500); return parsed.slice(safeOffset, safeOffset + safeLimit); }