Skip to content

fix(ui): rebuild the tool detail panel — one surface, one type scale, real diff colours - #2227

Merged
Astro-Han merged 6 commits into
mainfrom
fix/tool-detail-command-surface
Aug 5, 2026
Merged

fix(ui): rebuild the tool detail panel — one surface, one type scale, real diff colours#2227
Astro-Han merged 6 commits into
mainfrom
fix/tool-detail-command-surface

Conversation

@Astro-Han

@Astro-Han Astro-Han commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

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:

Phase Rendering Result
Streaming ToolCodeBlock(command) + a bare <pre> command in its own bordered card, output loose beside it
Foreground settled (terminal) command passed as CodeBlock's title comment-coloured mono with no rule, tucked against the body — reads as a commented-out first line, not a header
Background settled (shell_run) .maka-tool-output-panel command and output in one bordered panel

So a command changed shape at the moment it finished, and in none of the three could it be copied on its own — Astryx's CodeBlock copy button reaches the code, not the title.

One ToolOutputSurface now 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 nested CodeBlock — 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 no language.

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. ToolCodeBlock asked for Astryx size="sm", the supporting tier; Astryx's md is --text-code-size, which already resolves to the same 0.875rem the product's --maka-text-code does. 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 move chat-message.css already makes on the tool and reasoning rows. Size and leading only: medium on a header is Astryx's intent.

3. The diff was not coloured at all

FileDiffPreview passed language="diff" to 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 hunk painted one colour. Astryx ships no diff component either.

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. 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 CodeBlock inside 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

  • Computed styles in the live Storybook: command, output, block title and block code all report 14px / 20.0004px / Geist Mono Variable. Before, the four were 14/14/12/12px with three different leadings.
  • @maka/ui tests: 343 passing. Two new: gives a command and its output one surface in every phase pins one [data-slot="tool-output"] per phase with the command in the header and the shell path off CodeBlock; tints a diff by line kind instead of painting it one colour pins the full classification sequence, above all that ---/+++ are meta rather than del/add.
  • @maka/ui + @maka/desktop typecheck, npm run format, npm run lint, check-dead-css, check-story-annotations — all clean.
  • E2E disclosure-output.spec.ts passing: the on-demand mount and tail-follow contract for a collapsed live tool is unchanged.
  • New story Product/Tool Activity → ShellCommandSurface puts live, foreground, background and failed side by side. The background shell_run state had no story before this. Diff colours checked in DenseMixedResults in both light and dark.

Live-app before/after for the streaming case, captured from the disclosure-output E2E window on main and 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_diff result, 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 CodeBlock title 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.

@Astro-Han Astro-Han changed the title fix(ui): give a command and its output one surface fix(ui): rebuild the tool detail panel — one surface, one type scale, real diff colours Aug 5, 2026
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
Astro-Han force-pushed the fix/tool-detail-command-surface branch from 10e0188 to da353d6 Compare August 5, 2026 11:44
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.
@Astro-Han
Astro-Han marked this pull request as ready for review August 5, 2026 12:13
@Astro-Han
Astro-Han merged commit 17367dc into main Aug 5, 2026
12 checks passed
@Astro-Han
Astro-Han deleted the fix/tool-detail-command-surface branch August 5, 2026 12:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant