import { promises as fs } from 'fs' import path from 'path' import { randomUUID } from 'crypto' export interface EmailAttachment { filename: string content: Buffer cid: string } interface AgentEmailParams { agentName: string content: string appUrl: string userName?: string } /** * Read a local image file from the public directory. */ async function readLocalImage(relativePath: string): Promise { try { const filePath = path.join(process.cwd(), 'public', relativePath) return await fs.readFile(filePath) } catch { return null } } /** * Convert markdown to simple HTML suitable for email clients. * Replaces local image references with cid: placeholders for inline attachments. * Returns the HTML and a list of attachments to include. */ export async function markdownToEmailHtml(md: string, appUrl: string): Promise<{ html: string; attachments: EmailAttachment[] }> { let html = md const attachments: EmailAttachment[] = [] const baseUrl = appUrl.replace(/\/$/, '') // Remove the execution footer (agent trace) html = html.replace(/\n---\n\n_\$Agent execution:[\s\S]*$/, '') html = html.replace(/\n---\n\n_Agent execution:[\s\S]*$/, '') // Horizontal rules html = html.replace(/^---+$/gm, '
') // Headings html = html.replace(/^### (.+)$/gm, '

$1

') html = html.replace(/^## (.+)$/gm, '

$1

') html = html.replace(/^# (.+)$/gm, '

$1

') // Bold and italic html = html.replace(/\*\*(.+?)\*\*/g, '$1') html = html.replace(/\*(.+?)\*/g, '$1') // Unordered list items html = html.replace(/^(\s*)[-*] (.+)$/gm, '$1
  • $2
  • ') // Wrap consecutive
  • in