// 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(
{lang && (
{lang}
)}
            {code}
          
) continue } // Skip empty lines (add spacing) if (line.trim() === '') { elements.push(
) i++; continue } // H1 if (line.startsWith('# ')) { elements.push(

{parseLine(line.slice(2))}

) i++; continue } // H2 if (line.startsWith('## ')) { elements.push(

{parseLine(line.slice(3))}

) i++; continue } // H3 if (line.startsWith('### ')) { elements.push(

{parseLine(line.slice(4))}

) i++; continue } // Unordered list item if (line.match(/^[-*] /)) { const listItems = [] while (i < lines.length && lines[i].match(/^[-*] /)) { listItems.push(
  • {parseLine(lines[i].slice(2))}
  • ) i++ } elements.push( ) continue } // Numbered list item if (line.match(/^\d+\. /)) { const listItems = [] while (i < lines.length && lines[i].match(/^\d+\. /)) { listItems.push(
  • {parseLine(lines[i].replace(/^\d+\. /, ''))}
  • ) i++ } elements.push(
      {listItems}
    ) continue } // Horizontal rule if (line.match(/^---+$/)) { elements.push(
    ) i++; continue } // Normal paragraph elements.push(

    {parseLine(line)}

    ) i++ } return
    {elements}
    }