const fs = require("fs"); const path = require("path"); const AdmZip = require("adm-zip"); const { resolveData, ensureDataDirs } = require("./paths"); function redact(value) { if (Array.isArray(value)) return value.map(redact); if (!value || typeof value !== "object") return value; const output = {}; for (const [key, item] of Object.entries(value)) { output[key] = /token|secret|password|cookie|authorization|session/i.test(key) ? "[REDACTED]" : redact(item); } return output; } function createDiagnostic(input) { return redact({ timestamp: new Date().toISOString(), severity: "error", can_retry: true, requires_admin_action: true, should_auto_resume: false, platform: process.platform, ...input }); } function persistDiagnostic(input) { ensureDataDirs(); const diagnostic = createDiagnostic(input); fs.writeFileSync(resolveData("diagnostics", "latest_runtime_diagnostic.json"), `${JSON.stringify(diagnostic, null, 2)}\n`); fs.appendFileSync(resolveData("diagnostics", "runtime_diagnostics.jsonl"), `${JSON.stringify(diagnostic)}\n`); return diagnostic; } function getLatestDiagnostic() { try { return JSON.parse(fs.readFileSync(resolveData("diagnostics", "latest_runtime_diagnostic.json"), "utf8")); } catch { return null; } } function createDiagnosticsBundle({ config, runtimeState, manifest, metrics }) { ensureDataDirs(); const destination = resolveData("diagnostics", `lumi-ai-diagnostics-${Date.now()}.zip`); const zip = new AdmZip(); const addJson = (name, value) => zip.addFile(name, Buffer.from(`${JSON.stringify(redact(value), null, 2)}\n`)); addJson("config.json", config); addJson("runtime_state.json", runtimeState); addJson("latest_runtime_diagnostic.json", getLatestDiagnostic()); addJson("runtime_manifest.json", manifest); addJson("metrics_summary.json", metrics); for (const name of ["runtime-selftest.log"]) { const file = resolveData("logs", name); if (fs.existsSync(file)) zip.addLocalFile(file, "logs"); } const logs = fs.readdirSync(resolveData("logs")).filter((name) => name.startsWith("runtime-")).sort().slice(-2); for (const name of logs) zip.addLocalFile(resolveData("logs", name), "logs"); zip.writeZip(destination); return destination; } function tail(value, length = 4000) { return String(value || "").slice(-length); } module.exports = { redact, createDiagnostic, persistDiagnostic, getLatestDiagnostic, createDiagnosticsBundle, tail };