refactor(desktop): migrate integration tool details onto the design system
D25 of the design-system migration (Desktop stack, base feature/desktop-d24-integration-directory, #3403).
What
The integration tool list and tool page (apps/desktop/src/renderer/integration-tool-list.tsx) are shared by Settings āŗ Integrations, the MCP popover and a server's hover card. This PR moves them onto @luke/ui:
- Row badge (Read-only / Destructive): the bespoke
.integration-tool-badgespan is nowBadge. Read-only uses the neutral tone and Destructive uses danger. - Tool-page hints: each hint is a
Badgeinside its list item. Destructive uses danger; every other hint uses neutral. - "No description.": now
Text(caption, subtle) instead of.integration-tool-silent. - Type and colour tokens:
- Row title: body size and leading.
- Row summary: caption size and leading, subtle ink.
- Page title: section role (13/18, 600).
- Page description: caption size, muted ink.
- The Settings tools panel (
settings.css) uses--luke-space-*,--luke-color-border,--luke-color-fill-strongand--luke-color-textinstead of the legacy aliases.
- Container layout only:
.integration-tool-name > .luke-badgekeeps the badge from shrinking and centres it on the title.
No caller here imported @luke/ui/compat.
Left for D79 (agent server picker): the tool page's back button only appears in the MCP popover. It uses onMouseDown + preventDefault to keep focus in the popover's filter. IconButton only forwards onPointerDown, which can't stop that focus change, so moving the button would mean changing a shared API. D79 owns that navigation.
Selectors removed (no callers left)
.integration-tool-badge, .integration-tool-badge[data-destructive], .integration-tool-hint (and its data-tone danger/quiet variants), .integration-tool-silent.
Visible changes
- The row badge and the hints are the shared Badge: a full-radius capsule, 12/16 caption type, weight 500, tone tint. Before they were 10.5px, 4px-radius chips.
- The open-world and closed-world hints ("Reaches outside Vercel", "Only Vercel's own data") were hairline-outlined. They are now neutral like the other non-destructive hints, because Badge has no outlined tone. Their words still say what they mean.
- Row titles are 13px on a 20px line (were 12.5px). Every row is the same height whether or not it has a badge.
- Row summaries are 12/16 (were 12px/1.35).
Tests
- Existing behaviour tests still pass:
integrations-page.test.ts,agent-servers.test.tsandserver-card.test.ts(59 tests). They cover tool selection, expansion, arrows/Home/End/Enter/Escape and Tab stops. - Their locators moved from
.integration-tool-badgeand.integration-tool-hintto.luke-badgeand.integration-tool-hints li. The silent page is now read through the body's text. - No new tests, because no user-visible behaviour changed.
pnpm check:affectedexits 0.
Evidence
Captured on Linux with headless Chrome at 1280Ć840, animations held still, using the same method as #3403:
- A throwaway, uncommitted copy of the page's test rendered the real
IntegrationsSectionin jsdom with synthetic tools. - That output was framed in
SettingsPagemarkup with the built desktop stylesheet. - The ā in the chord shows as a missing glyph only because Linux has no font for it.
| Light | Dark | |
|---|---|---|
| Read-only tool held: hints, markdown, parameters | ![]() | ![]() |
| Destructive tool held | ![]() | ![]() |
| A tool its server said nothing of | ![]() | ![]() |
Not verified on a Mac
- SF Pro rendering of the badges and rows.
- The MCP popover and the server hover card in the real window. They share this component, but they weren't captured.
- Scrolling and focus of the tool page in the real window. Only the jsdom tests cover these.
š¤ Generated with Claude Code





