// Lightweight Markdown renderer – handles the subset used by the AI: // ## Headings, **bold**, bullet lists, numbered lists, fenced ``` code ```, line breaks export default function Markdown({ text }) { if (!text) return null const lines = text.split('\n') const elements = [] let i = 0 let blockId = 0 const codeBlockStyle = { margin: '10px 0', padding: 12, background: 'var(--surface2)', borderRadius: 8, border: '1px solid var(--border)', overflow: 'auto', fontSize: 12, lineHeight: 1.5, fontFamily: 'ui-monospace, Consolas, monospace' } const parseLine = (line) => { // Parse inline **bold** and *italic* const parts = [] let remaining = line let key = 0 while (remaining.length > 0) { const boldMatch = remaining.match(/^(.*?)\*\*(.*?)\*\*(.*)$/) if (boldMatch) { if (boldMatch[1]) parts.push({boldMatch[1]}) parts.push({boldMatch[2]}) remaining = boldMatch[3] continue } const italicMatch = remaining.match(/^(.*?)\*(.*?)\*(.*)$/) if (italicMatch) { if (italicMatch[1]) parts.push({italicMatch[1]}) parts.push({italicMatch[2]}) remaining = italicMatch[3] continue } parts.push({remaining}) break } return parts.length === 1 && typeof parts[0].props?.children === 'string' ? parts[0].props.children : parts } while (i < lines.length) { const line = lines[i] // Fenced code block: ``` or ```lang const trimmedStart = line.trimStart() if (trimmedStart.startsWith('```')) { const lang = trimmedStart.slice(3).trim() || null i++ const codeLines = [] while (i < lines.length) { if (lines[i].trim().startsWith('```')) { i++ break } codeLines.push(lines[i]) i++ } const code = codeLines.join('\n') elements.push(
{code}
{parseLine(line)}
) i++ } return