- Extract parseA2UIBlocks() from A2UIRenderer.tsx into its own
frontend/src/lib/a2ui.ts module to satisfy react-refresh/only-export-
components ESLint rule (A2UIRenderer should only export React components)
- Update ChatPanel.tsx and test files to import from lib/a2ui
- Split ChatPanel.test.tsx mock: separate vi.mock for lib/a2ui
(parseA2UIBlocks) and A2UIRenderer (component only)
- Remove unused 'import re' from tests/test_runtime_html.py (ruff F401)
All 216 frontend tests and 242 bash tests still pass. TypeScript and
Vite builds are clean. Remaining ESLint warnings (react-hooks/set-state-
in-effect in MCPAppRenderer and useSessions) are pre-existing patterns
not introduced by Phase 3.
- RightPanel: replace placeholder content with BrowserPanel + ArtifactsPanel
components, routing sessionId to whichever tab is active
- ChatPanel: import A2UIRenderer + parseA2UIBlocks; render A2UI blocks between
markdown and tool-call cards in assistant messages; onAction sends
'[action] {json}' back via onSend
- ChatPanel: add parseVisualBlocks() helper, VisualBlock wrapper component
(loads runtime.html via MCPAppRenderer, view-source toggle, pop-out),
rendered after A2UI blocks in assistant messages
- MCPAppRenderer: on ui/initialize route runtime='visual-artifact' data to a
render dispatch instead of tool/input; add render forwarding case
- Fix pre-existing TS6133 unused-import errors in A2UIRenderer + BrowserPanel test
- All 216 tests pass; npm run build succeeds