fix(ui): rebuild the tool detail panel — one surface, one type scale, real diff colours - #2227
Merged
Merged
Conversation
Expanding a Bash row drew the same command three different ways. While streaming it went into an Astryx CodeBlock card with the output as loose text beside it; once a foreground run settled the command moved into that block's `title` slot, where it rendered comment-coloured and tucked against the body with no rule, reading as a commented-out first line rather than a header; a background run used the panel. So a command changed shape as it finished, and none of the three could be copied on its own — CodeBlock's copy button takes the code, not the title. One `ToolOutputSurface` now owns all three: command on top in foreground mono, a hairline, then the body, with an icon-only action that copies the command. The settled shell body drops its nested CodeBlock (a second border inside the panel) for the same `<pre>` well the live stream already used, which also makes live and settled render identically. Diff and JSON results keep Astryx's CodeBlock title — those are file paths and headlines, not commands, and folding them in is a separate question about who owns block headers.
Moving the shell path onto the product's `<pre>` well left a tool detail rendering two type scales side by side: the command surface at 14px/20px against a diff or JSON block at 12px/17px, with the block's title at 12px on a 20px line box. The cause was a single pin. `ToolCodeBlock` asked for Astryx `size="sm"`, which is the supporting tier; Astryx's `md` is `--text-code-size`, and that token already resolves to the same 0.875rem the product's `--maka-text-code` does. Dropping the pin lines the code up exactly. The block's title hard-codes the supporting size and leading, so rebind those two role tokens on the detail scope — the move chat-message.css already makes on the tool and reasoning rows. Size and leading only: `medium` on a header is Astryx's intent, and the command surface carries the same emphasis through its foreground colour instead. Measured in the live Storybook: command, output, block title and block code all report 14px / 20.0004px / Geist Mono Variable.
The diff preview passed `language="diff"` to Astryx's CodeBlock, which has no such language: `buildLanguagePatterns` has no `diff` case and returns null, so every line fell through to `--color-syntax-variable` and the whole hunk painted one colour. Astryx ships no diff component either, so there was nothing upstream to adopt. The product already had the answer. `previewVariants` has always declared `diff-body` and `diff-line`, and styles.css has always carried the add/del/hunk/meta/ctx tints — green additions, red deletions, a tinted hunk header, the treatment Codex and Claude use. Only the call site had gone missing; `FileDiffPreview`'s own doc comment still described the scheme it had stopped rendering. Wire it back up, inside the same surface a command uses, with the changed paths as its heading. `+++`/`---` are file markers, not an addition and a deletion, so they are classified before the single-character cases — otherwise every diff opens with a meaningless green line and a red one. Two adjustments so the reconnected CSS belongs in a panel rather than the standalone card it was written for: the body takes the panel's code tier (it was the supporting tier, which the previous commit just moved off), and the line tints bleed to the panel edge through a negative inline margin instead of stopping short at the padding. Also disable ligatures on CodeBlock inside a tool detail. Geist Mono ligates `--` and `!==` into single glyphs that sit outside the cell they started in, which made a `---` line look like it had escaped the block's left edge — measured, its box starts on the same x as every other line. The product's own wells already disable this.
Astro-Han
force-pushed
the
fix/tool-detail-command-surface
branch
from
August 5, 2026 11:44
10e0188 to
da353d6
Compare
The shell body moved from an Astryx CodeBlock to a plain <pre>, and the block's own copy button went with it — the panel's button reached only the command, so one-click copy of a failing command's output was gone. One function owns the body's text now, and both the render and the copy read it, so the two cannot diverge. The copy key was derived from the heading to keep two surfaces apart, but each surface owns its own feedback hook and its own single button, so the key never had that job.
`diffLineKind` was written a second time next to the chat call site, one package away from the copy `apps/desktop`'s artifact pane has used all along — and the two had already diverged on `diff --git` / `index` headers. It rides the `previewVariants` seam now, for the reason that export already states: it decides the `data-line` values those classes select on. Three defects it shipped with, each measured against the live cascade: - `---`/`+++` matched without their trailing space, so removing a YAML document separator or an SQL `--` comment painted the deletion as a file header — the one line a reader most needs to see as red. - A newline-terminated diff drew a blank tinted row at the end. Flat text hid the trailing empty field; one element per line does not. - `.maka-tool-diff-line`'s negative margin never reached past the body's own `overflow: auto` clip, so it bought no bleed to the panel edge — only a 12px permanent horizontal overflow and the loss of the text's inset. The code tier belongs to `.maka-tool-output-panel`, not to the shared class: `apps/desktop`'s pane still draws this as a standalone card and keeps the supporting tier its container asks for.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three problems in the panel a tool row reveals when expanded, each found by the one before it.
1. A command had three shapes
Expanding a Bash row drew the same command differently depending on which branch it landed in:
ToolCodeBlock(command)+ a bare<pre>terminal)CodeBlock'stitleshell_run).maka-tool-output-panelSo a command changed shape at the moment it finished, and in none of the three could it be copied on its own — Astryx's
CodeBlockcopy button reaches the code, not the title.One
ToolOutputSurfacenow owns all of them: heading on top in foreground mono, a hairline, then the body, plus an icon-only action that copies the heading. The settled shell body drops its nestedCodeBlock— a second border inside the panel — for the same<pre>well the live stream already used, so live and settled render identically. No tokenization is lost: shell output was already passed with nolanguage.2. Two type scales in one panel
That move exposed a second problem: a detail then rendered the command surface at 14px/20px beside a diff or JSON block at 12px/17px, with that block's title at 12px on a 20px line box.
One pin caused it.
ToolCodeBlockasked for Astryxsize="sm", the supporting tier; Astryx'smdis--text-code-size, which already resolves to the same0.875remthe product's--maka-text-codedoes. Dropping the pin lines them up. The block title hard-codes the supporting size and leading, so those two role tokens are rebound on the detail scope — the movechat-message.cssalready makes on the tool and reasoning rows. Size and leading only:mediumon a header is Astryx's intent.3. The diff was not coloured at all
FileDiffPreviewpassedlanguage="diff"toCodeBlock, which has no such language —buildLanguagePatternshas nodiffcase and returns null, so every line fell through to--color-syntax-variableand the hunk painted one colour. Astryx ships no diff component either.The product already had the answer:
previewVariantshas always declareddiff-bodyanddiff-line, andstyles.csshas always carried the add/del/hunk/meta/ctx tints — green additions, red deletions, a tinted hunk header. Only the call site had gone missing;FileDiffPreview's own doc comment still described the scheme it had stopped rendering. It is wired back up inside the same surface, with the changed paths as its heading.+++/---are classified as file markers before the single-character cases, so a diff no longer opens with a meaningless green line and a red one.Ligatures are also disabled on
CodeBlockinside a tool detail: Geist Mono ligates--and!==into glyphs that sit outside the cell they started in, which made a---line look like it had escaped the block's left edge. Measured, its box starts on the same x as every other line — the overflow was the ligature, not layout.Verification
14px / 20.0004px / Geist Mono Variable. Before, the four were 14/14/12/12px with three different leadings.@maka/uitests: 343 passing. Two new:gives a command and its output one surface in every phasepins one[data-slot="tool-output"]per phase with the command in the header and the shell path offCodeBlock;tints a diff by line kind instead of painting it one colourpins the full classification sequence, above all that---/+++aremetarather thandel/add.@maka/ui+@maka/desktoptypecheck,npm run format,npm run lint,check-dead-css,check-story-annotations— all clean.disclosure-output.spec.tspassing: the on-demand mount and tail-follow contract for a collapsed live tool is unchanged.Product/Tool Activity → ShellCommandSurfaceputs live, foreground, background and failed side by side. The backgroundshell_runstate had no story before this. Diff colours checked inDenseMixedResultsin both light and dark.Live-app before/after for the streaming case, captured from the
disclosure-outputE2E window onmainand on this branch and composed with ImageMagick, is attached in a comment below.Review focus
The file-diff rendering reworked here is currently unreachable in the product: no runtime tool produces a
file_diffresult, so only the e2e and Storybook fixtures exercise it. Tracked in #2232 — this PR fixes the rendering that issue would make visible.Diff and JSON results keep Astryx's
CodeBlocktitle rather than the command surface — those are file paths and headlines, not commands. They now share the type scale, so the two headers read as one system, but whether the product should own block headers outright is a separate question this PR does not settle.