Repository navigation
feat(ui): govern chat conversation-flow display onto @maka/ui Base UI primitives #332
Description
Context
The renderer's interactive primitives (packages/ui/src/primitives/*) are already on the shadcn Base UI + Tailwind substrate (cva, data-slot, @base-ui/react). The chat conversation-flow display layer is the last bespoke island: packages/ui/src/components.tsx (MessageBody ~L4441, TurnSummary ~L4618, TurnView ~L4697, ToolActivity ~L6165) renders hand-written maka-* classNames whose CSS is spread across: styles/tool-output.css, styles/tool-stream.css, chat selectors in maka-tokens.css, .maka-turn-* in styles/settings/models.css (model-catalog preview), and .maka-bubble-truncated in styles/reasoning-panel.css. (styles/chat-message.css is the empty/hero state, not the main flow.)
Goal: migrate the conversation flow (bubbles, status/tool markers, tool/result/preview surfaces) onto a small set of @maka/ui chat primitives (Message/Bubble/Marker/Attachment), retiring the bespoke shell CSS, with zero visual change. This is governance (one substrate + a test net), not a redesign; the visual refresh is a separate follow-up.
Invariants (every slice)
- Zero visual change, locked by computed-style/cascade contract tests + before/after screenshots.
- Keep the neutral user-bubble token path (
--chat-user-bg/--user-message-bubble); never switch it toprimary/accent. - Replace only the bubble/row shell. Markdown prose under
.maka-bubble-assistant(task lists, code blocks, tables, blockquotes, links;maka-tokens.css:1088+) is OUT of scope and must be preserved. Do not touch.messages(chat scroll container). - No change to runtime, streaming, Markdown rendering, permission, turn model, tool output, attachment IPC.
- New primitives live in
packages/ui/src/primitives/chat*and are exported frompackages/ui/src/index.ts; do not grow thecomponents.tsxsink. - Each slice deletes its retired CSS.
scripts/check-dead-css.mjs --checkonly scansstyles/+reference-shell.css(NOTmaka-tokens.css); therenderer-style-pruning-contracttest does reach tokens viastyles.cssimports. Lean on contract tests + manual grep ofmaka-tokens.css.
Slices (flat PRs off main, landed in order)
- PR1 (feat(ui): govern chat bubble/row shell onto @maka/ui chat primitives #334) — Bubble/Message: add
chat.tsxMessage+Bubble + contract; wireMessageBody; delete the bubble/row shell (.maka-bubble-user, assistant wrapper layout,.message.user/.assistant/.system,.maka-bubble-truncated). Keep Markdown prose. - PR2 (feat(ui): migrate chat turn markers onto @maka/ui Marker primitive (#332) #337) — Marker: turn summary / failed / aborted / lineage / footer (+ decide
maka-turn-thinking: include or explicitly defer) →Marker; delete.maka-turn-*in BOTHmaka-tokens.css/tool-output.cssANDstyles/settings/models.css. - PR3a (feat(ui): migrate tool live-output stream onto @maka/ui chat primitives (#332 PR3) #348) — Tool live-output stream:
ToolOutputStream+ the live dot (LiveIndicator) onto chat primitives; deleted.maka-tool-output-stream-*+ its per-feature@keyframes. Added canonical@keyframes maka-pulse(shared motion home) +npm run check:chat-visualfor the zero-visual diff.LiveIndicator/streamVariantskept internal (off-barrel) until a 2nd consumer. - PR3b (feat(ui): migrate ToolActivity card shell onto @maka/ui chat primitives (#332 PR3b) #350) — Tool activity:
ToolActivitycard shell onto internaltoolVariants; deleted the.maka-tool*card CSS (+.toolInline/.toolItem/.toolArgs) and re-keyed the entrance /<summary>marker / pulse-ring residue onto[data-slot="tool"]. The error-banner half was carved out → PR3c.toolVariantskept internal (off-barrel) until a 2nd consumer. - PR3c (feat(ui): retire ToolErrorBanner bespoke CSS onto the @maka/ui Alert primitive (#332 PR3c) #355) — Tool error banner: retire
.maka-tool-error*(ToolErrorBanneralready renders on theAlertprimitive — this is CSS retirement, not a new primitive). Delete the dead-icon/-body/-title; literalize the live container /-text/-copytints; syncvisible-copy-hygiene-contract. - PR4 (feat(ui): govern tool-result preview surfaces onto @maka/ui previewVariants (#332 PR4) #362) — Preview surfaces: terminal / diff / web-search / office / explore / subagent overlay previews + the shared
.maka-overlay-previewbase and the.maka-load-tool-*card. Resolved the shared-.maka-tool-diff*note by co-migratingartifact-preview.tsxonto the barrel-exportedpreviewVariantsdiff parts (no temporary shared layer).@keyframes maka-tool-card-entermoved to maka-tokens.css. - Later — MessageScroller: scroll/virtualization (
overlay-scroll-area) is a behavioral concern, evaluated separately.
Next component after this batch
- Composer — input-side component. CSS spans
styles/composer.cssAND a chunk instyles/tool-output.css.
Out of scope (stays hand-written)
Design tokens (maka-tokens.css), Markdown prose, feature-page layout CSS (sidebar / settings / module-pages / onboarding / etc.), and no-equivalent primitives (overlay-scroll-area, frame, kbd, skeleton, spinner, empty, alert, input-group).
Activity
refactor(ui): harden chat primitives against data-* override and pin …
feat(ui): govern chat bubble/row shell onto @maka/ui chat primitives (#…
refactor(ui): pin pending-copy opacity by specificity, scope markerVa…
test(ui): pin the non-leaf marker merge resolution for footer-action …
refactor(ui): drop inert secondary footer-action branch; commit compu…
refactor(ui): inline footer priority, pin focus-visible, scope render…
fix(ui): make the chat-marker computed-style proof actually load CSS;…
feat(ui): migrate chat turn markers onto @maka/ui Marker primitive (#337
refactor(ui): keep PR3 minimal — de-publicize LiveIndicator, thin tes…
chore(scripts): point check:chat-visual usage at the npm alias (#332)
feat(ui): migrate tool live-output stream onto @maka/ui chat primitiv…
test(ui): cover the collapsed tool-card default in the zero-visual pr…
docs(ui): trim the waiting_permission escape comment to its technical…
test(ui): cover the pending tool-card status in the zero-visual proof (…
test(ui): derive the tool-card fixture from one status list (#332 PR3b)
feat(ui): migrate ToolActivity card shell onto @maka/ui chat primitiv…
refactor(ui): address PR3c review on the ToolErrorBanner Alert migration
feat(ui): retire ToolErrorBanner bespoke CSS onto the @maka/ui Alert …
fix(ui): keep web-search error tint collapse-safe so the destructive …
chore(ui): stop docstring utility examples from leaking dead CSS (#332 …
feat(ui): govern tool-result preview surfaces onto @maka/ui previewVa…
Astro-Han commentedon Jun 29, 2026
Closing: the conversation-flow display migration is complete. All six display slices landed on main — PR1 #334 (Bubble/Message), PR2 #337 (Marker), PR3a #348 (ToolOutputStream/LiveIndicator), PR3b #350 (ToolActivity), PR3c #355 (ToolErrorBanner→Alert), PR4 #362 (preview surfaces +
previewVariants). The titled goal — govern the chat conversation-flow display (bubbles / status·tool markers / tool·result·preview surfaces) onto @maka/ui primitives with zero visual change — is fully delivered, with a per-slice cascade/computed-style test net.The two trailing items were always scoped outside this issue's goal (
Later/Next component after this batch) and are not part of the conversation-flow display layer:styles/composer.css+ a chunk intool-output.css). The genuine last bespoke chat surface; worth a follow-up governance slice using the same literalize pattern. To be tracked separately.overlay-scroll-areaprimitive is in this issue's own 'no-equivalent / stays hand-written' out-of-scope list, so there is little shell to migrate and any change would be behavioral (no zero-visual safety net). Revisit only if a concrete scroll need arises.refactor(ui): converge layout-surface & sizing tokens (#520 PR4) (#539)
refactor(ui): extend typography/line-height converge contracts to TSX (…
refactor(chat-message): polish code-block tier, alpha tokens, uniform…
docs: correct retired stream-shell coverage claims in computed-style …
docs: drop stale stream-substrate cross-references from comments (#742)
refactor(ui): move the turn markers out of Tailwind