Lumi/plugins/lumi_ai/backend/assistant_panel_diagnostics.js
2026-06-12 11:54:46 +02:00

90 lines
2.7 KiB
JavaScript

const fs = require("fs");
const path = require("path");
const { resolveData } = require("./paths");
const LOG_FILE = "assistant-panel.log";
class AssistantPanelDiagnostics {
constructor(templatePath) {
this.templatePath = path.resolve(templatePath);
this.state = {
panel_endpoint_status: null,
panel_html_length: 0,
panel_html_error: null,
panel_template_path: this.templatePath,
missing_locals: [],
mount_error: null,
updated_at: null
};
}
templateCheck(requiredLocals = [], locals = {}) {
const missing = requiredLocals.filter((key) => locals[key] === undefined || locals[key] === null);
let error = null;
try {
fs.accessSync(this.templatePath, fs.constants.R_OK);
} catch {
error = "Assistant panel template is missing or unreadable.";
}
this.update({ missing_locals: missing, panel_html_error: error });
return { valid: !error && missing.length === 0, missing, error };
}
rendered(html) {
const content = String(html || "");
const marker = 'data-assistant-panel-id="lumi_ai"';
const error = !content.trim()
? "Assistant panel rendered empty HTML."
: !content.includes(marker)
? `Assistant panel HTML is missing ${marker}.`
: null;
this.update({
panel_endpoint_status: error ? 500 : 200,
panel_html_length: content.length,
panel_html_error: error
});
return { valid: !error, error, length: content.length };
}
renderFailed(error) {
this.update({
panel_endpoint_status: 500,
panel_html_length: 0,
panel_html_error: error?.message || String(error)
}, "render_failure");
}
frontend(report = {}) {
this.update({
panel_endpoint_status: numberOrNull(report.panel_endpoint_status) ?? this.state.panel_endpoint_status,
panel_html_length: numberOrNull(report.panel_html_length) ?? this.state.panel_html_length,
panel_html_error: report.panel_html_error || this.state.panel_html_error,
mount_error: report.mount_error || null
}, report.mount_error ? "mount_failure" : null);
}
snapshot() {
return { ...this.state };
}
update(values, event = null) {
this.state = { ...this.state, ...values, updated_at: new Date().toISOString() };
if (event || values.panel_html_error || values.mount_error) {
this.log(event || "diagnostic", values);
}
}
log(event, details) {
const target = resolveData("logs", LOG_FILE);
const line = JSON.stringify({ at: new Date().toISOString(), event, ...details });
fs.appendFileSync(target, `${line}\n`, "utf8");
}
}
function numberOrNull(value) {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : null;
}
module.exports = { AssistantPanelDiagnostics, LOG_FILE };