import type { ChatMessage } from "../types/message"; import { escHtml } from "./format"; function roleLabel(role: ChatMessage["role"]): string { switch (role) { case "user": return "用户"; case "assistant": return "助手"; case "thinking": return "思考"; case "tool_call": return "工具"; case "system": return "系统"; case "bash": return "Shell"; case "compaction_summary": return "压缩摘要"; case "branch_summary": return "分支摘要"; default: return "消息"; } } function exportableMessages(messages: ChatMessage[]): ChatMessage[] { return messages.filter((m) => !m.streaming && m.content.trim()); } export function messagesToMarkdown(title: string, messages: ChatMessage[]): string { const lines = [`# ${title}`, ""]; for (const m of exportableMessages(messages)) { switch (m.role) { case "user": lines.push("## 用户", "", m.content, ""); break; case "assistant": lines.push("## 助手", "", m.content, ""); break; case "thinking": lines.push("## 思考", "", m.content, ""); break; case "tool_call": lines.push("## 工具", "", "```", m.content, "```", ""); break; case "system": lines.push(`> ${m.content}`, ""); break; case "bash": { const cmd = m.bashCommand ? `$ ${m.bashCommand}` : "Shell"; lines.push(`## Shell (${cmd})`, "", "```", m.content, "```", ""); break; } case "compaction_summary": lines.push("## 压缩摘要", "", m.content, ""); break; case "branch_summary": lines.push("## 分支摘要", "", m.content, ""); break; } } return `${lines.join("\n").trimEnd()}\n`; } export function messagesToMinimalHtml(title: string, messages: ChatMessage[]): string { const sections = exportableMessages(messages) .map((m) => { const label = roleLabel(m.role); return `

${escHtml(label)}

${escHtml(m.content)}
`; }) .join("\n"); return ` ${escHtml(title)}

${escHtml(title)}

${sections} `; } export function safeExportFilename(title: string): string { const cleaned = title.replace(/[\\/:*?"<>|]/g, "_").trim(); return cleaned || "conversation"; } export function downloadTextFile(filename: string, content: string, mime: string): void { const blob = new Blob([content], { type: `${mime};charset=utf-8` }); const url = URL.createObjectURL(blob); const anchor = document.createElement("a"); anchor.href = url; anchor.download = filename; anchor.click(); URL.revokeObjectURL(url); } export function singleAssistantMarkdown(content: string): string { return content.trimEnd() + (content.endsWith("\n") ? "" : "\n"); } export function messageMarkdownFilename(content: string): string { const snippet = content .replace(/\s+/g, " ") .trim() .slice(0, 24) .replace(/[\\/:*?"<>|]/g, "_") || "message"; return `${snippet}.md`; }