diff --git a/diagnostic/index.html b/diagnostic/index.html
index 555446b..0f5c3d4 100644
--- a/diagnostic/index.html
+++ b/diagnostic/index.html
@@ -891,6 +891,18 @@
else alert('Loeschen fehlgeschlagen: ' + (msg.error || '?'));
return;
}
+ if (msg.type === 'session_export') {
+ if (!msg.ok) { alert('Export fehlgeschlagen: ' + (msg.error || '?')); return; }
+ const blob = new Blob([msg.markdown], { type: 'text/markdown;charset=utf-8' });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = msg.filename;
+ document.body.appendChild(a);
+ a.click();
+ setTimeout(() => { URL.revokeObjectURL(url); a.remove(); }, 100);
+ return;
+ }
if (msg.type === 'active_session') {
updateActiveSessionBar(msg.sessionKey);
loadSessions(); // Tabelle neu rendern
@@ -1679,7 +1691,8 @@
+ `
${date} | `
+ ``
+ (isActive ? '' : ``)
- + ``
+ + ``
+ + ``
+ ` | `;
}
html += '';
@@ -1743,6 +1756,10 @@
send({ action: 'delete_session', sessionPath: path });
}
+ function exportSession(path, sessionKey) {
+ send({ action: 'export_session', sessionPath: path, sessionKey });
+ }
+
function activateSession(sessionKey) {
send({ action: 'set_active_session', sessionKey });
}
diff --git a/diagnostic/server.js b/diagnostic/server.js
index cfc1fb7..222f785 100644
--- a/diagnostic/server.js
+++ b/diagnostic/server.js
@@ -1274,6 +1274,8 @@ wss.on("connection", (ws) => {
handleListSessions(ws);
} else if (msg.action === "read_session") {
handleReadSession(ws, msg.sessionPath);
+ } else if (msg.action === "export_session") {
+ handleExportSession(ws, msg.sessionPath, msg.sessionKey);
} else if (msg.action === "delete_session") {
handleDeleteSession(ws, msg.sessionPath);
} else if (msg.action === "set_active_session") {
@@ -1656,6 +1658,68 @@ async function handleReadSession(clientWs, sessionPath) {
}
}
+async function handleExportSession(clientWs, sessionPath, sessionKey) {
+ if (!sessionPath || sessionPath.includes("..") || !sessionPath.startsWith(SESSIONS_DIR)) {
+ clientWs.send(JSON.stringify({ type: "session_export", ok: false, error: "Ungueltiger Pfad" }));
+ return;
+ }
+ try {
+ const safePath = sessionPath.replace(/'/g, "");
+ const raw = await dockerExec("aria-core", `cat '${safePath}'`);
+ const lines = raw.split("\n").filter(l => l.trim());
+
+ const blocks = [];
+ for (const line of lines) {
+ let obj;
+ try { obj = JSON.parse(line); } catch { continue; }
+ if (obj.type !== "message" || !obj.message) continue;
+ const role = obj.message.role;
+ if (role !== "user" && role !== "assistant") continue;
+
+ let text = "";
+ const content = obj.message.content;
+ if (typeof content === "string") text = content;
+ else if (Array.isArray(content)) text = content.filter(c => c.type === "text").map(c => c.text || "").join("\n");
+ if (!text) continue;
+
+ if (role === "user") {
+ text = text.replace(/^Sender \(untrusted metadata\):[\s\S]*?```[\s\S]*?```\s*\n*/m, "").trim();
+ text = text.replace(/^\[.*?\]\s*/, "").trim();
+ } else {
+ text = text.replace(/^\[\[reply_to_\w+\]\]\s*/g, "").trim();
+ }
+ if (!text) continue;
+
+ const ts = obj.message.timestamp || obj.timestamp || 0;
+ const when = ts ? new Date(ts).toISOString().replace("T", " ").slice(0, 19) : "";
+ const heading = role === "user" ? "## 🧑 User" : "## 🤖 ARIA";
+ blocks.push(`${heading}${when ? ` — ${when}` : ""}\n\n${text}`);
+ }
+
+ const exportedAt = new Date().toISOString().replace("T", " ").slice(0, 19);
+ const title = sessionKey || sessionPath.split("/").pop().replace(".jsonl", "");
+ const markdown = [
+ `# Session: ${title}`,
+ ``,
+ `Exportiert: ${exportedAt} `,
+ `Quelle: ${sessionPath}`,
+ ``,
+ `---`,
+ ``,
+ blocks.join("\n\n---\n\n"),
+ ``,
+ ].join("\n");
+
+ const safeKey = (sessionKey || "session").replace(/[^a-zA-Z0-9_-]/g, "_");
+ const filename = `${exportedAt.slice(0, 10)}_${safeKey}.md`;
+ clientWs.send(JSON.stringify({ type: "session_export", ok: true, filename, markdown }));
+ log("info", "server", `Session exportiert: ${filename} (${blocks.length} Nachrichten)`);
+ } catch (err) {
+ log("error", "server", `Session-Export fehlgeschlagen: ${err.message}`);
+ clientWs.send(JSON.stringify({ type: "session_export", ok: false, error: err.message }));
+ }
+}
+
async function handleDeleteSession(clientWs, sessionPath) {
if (!sessionPath || sessionPath.includes("..") || !sessionPath.startsWith(SESSIONS_DIR)) {
clientWs.send(JSON.stringify({ type: "session_deleted", ok: false, error: "Ungueltiger Pfad" }));
diff --git a/issue.md b/issue.md
index 1c0ad39..4702870 100644
--- a/issue.md
+++ b/issue.md
@@ -30,6 +30,7 @@
- [x] Paste-Support fuer Bilder in Diagnostic Chat
- [x] Markdown-Bereinigung fuer TTS (fett, kursiv, code, links, etc.)
- [x] SSH Volume read-write fuer Proxy (kein -F Workaround mehr)
+- [x] Diagnostic: Sessions als Markdown exportieren (Download-Button)
## Offen