feat(desktop): background needs-input indicator, clarify redesign, Cmd+K palette & UI consistency pass#38631
Merged
Merged
Conversation
…anging clarify.request is a one-shot blocking event: the gateway turn blocks on clarify.respond. The desktop handler dropped it for any non-focused session (`if (!isActiveEvent) return`) and stored at most one request in a single global atom, so a background session that asked a clarifying question hung forever and re-focusing it could never recover (the event was already gone). - store/clarify.ts: key pending requests by runtime session id; expose the active session's request via a focus-scoped computed view (ClarifyTool is unchanged). clearClarifyRequest takes an optional session id for targeted clears, with a request-id fallback. - use-message-stream.ts: park every session's clarify (drop the isActiveEvent early return); toast when one lands for a background session since the row otherwise just keeps spinning like normal work. - clarify-tool.tsx: clear by session id so answering one chat can't wipe another's pending request. - store/clarify.test.ts: concurrent independence, focus-scoped view, targeted/stale/fallback clears.
Contributor
🔎 Lint report:
|
…dation Replace the background-clarify toast (expired on alt-tab, easy to miss) with a persistent, glowing amber "needs input" dot on the session's sidebar row, driven off a new ClientSessionState.needsInput flag mirrored into a $attentionSessionIds store. The flag is set on clarify.request and cleared the moment the turn resumes (tool.complete) or ends. Also: redesign the clarify tool UI (borderless choices, pseudo-radio dots, right-aligned checkmark, arc border, tighter padding), make Button the single source of icon-button styling (4px radius, new icon-titlebar variant, titlebar buttons rendered polymorphically via asChild, Codicons throughout), put the file-tree refresh action first, and .trim() pasted composer text.
Default button sizing was vanilla-shadcn chunky (fixed h-9, 16px padding) and inconsistent with the icon-button radius pass. Size text variants by padding + line-height instead of fixed heights so they stay snug and scale with content, and drop the radius on non-icon buttons (icon buttons keep the shared 4px). Move the update-overlay CTAs off a hardcoded h-10 onto the padding-based lg variant. Composer and the inline approval strip are untouched.
…ze stray buttons - Buttons: smaller default font (14px -> 13px) and tighter padding-driven sizes across every variant; the chunky shadcn scale read as oversized in a dense desktop UI. - Overlay split layout (settings / command center): the shared OverlayView top padding left the card surface showing as a gap above the sidebar. Move the titlebar clearance into each column so the sidebar background runs flush to the card's top edge. - Consolidate buttons that hardcoded size/radius/font onto the proper size variants (tooltip-icon-button, overlay close, cron IconAction, SidebarTrigger, gateway system button, session-row actions radius, title chip radius, release notes link) so styling flows from variant props, not per-call overrides. Composer and the inline approval strip are intentionally left as-is.
… settings titles
- Button base font down to 12px (text-xs) for the dense desktop scale.
- Remove the decorative Sparkles glyph from the model "Apply" button (keep the
spinner while applying).
- Drop the page-level section titles that just restate the left nav ("Main
model", "Appearance", "MCP servers") — the sidebar already labels the pane.
Sub-section headings (Auxiliary models, LLM providers, etc.) stay.
…ctions New reusable `text` variant renders a button as inline label text (no bg/border, muted -> foreground, underline-on-hover affordance). Emphasize the actionable word by adding `font-semibold`/`underline` at the call site. Applied to the auxiliary-model "Set to main" (plain), "Change" and "Reset all to main" (bold + underlined) actions, replacing the boxed ghost/outline buttons.
Bump default/sm vertical padding a step (the 12px pass read too small) and give non-icon buttons a subtle 2.5px radius instead of square corners. Icon buttons keep their 4px.
…ariants Mirror the buttonVariants exercise for non-composer form controls: add a single controlVariants source of truth (2.5px radius, 12px text, padding-driven sizing, chrome via desktop-input-chrome) and consume it from Input, Textarea, and SelectTrigger. Drop per-call radius/height/font overrides that fought the shared look.
Remove the outer card chrome (border/bg/shadow/rounded) wrapping each appearance section so they're flat headings + option grids instead of boxes nested inside boxes, matching the other settings pages.
… swatches Color Mode and Tool Call Display become flat radio-style rows (no tile border/fill, no inner icon box, no filled check badge — just a subtle active bg and a check). Theme drops its outer card wrapper so only the preview swatch shows, with a primary ring marking the active palette.
…lists Add a base-layer rule giving every interactive control (button, select, menu item, switch, tab, summary) cursor:pointer, and strip the now-redundant hardcoded cursor-pointer from those elements (plain clickable divs/labels keep theirs). Remove the divide-y separators from settings list sections so they breathe.
…ontrols Replace the vertical option-row lists with a compact SegmentedControl (grouped pill buttons on a single track), dropping the per-option descriptions since the section subtitle already covers the context.
…itches The switch already communicates state, so the text label was noise.
…ight Add an xs size variant to the Switch primitive and use it for the provider edit submenu toggles. In appearance settings, drop the redundant selection Pills (the UI already shows the active choice), move the Color Mode and Tool Call Display segmented controls into the section header's right side (responsive: stacks under the heading on narrow widths), and shrink the segmented control.
Adds a top-left swap button (replacing the search icon) that mirrors the layout: sessions sidebar ↔ file browser + preview rail. Persisted via $panesFlipped. The left/right sidebar toggles, content inset, and pane borders all follow the active side so the buttons stay accurate after a flip.
Builds on the clarify/needs-input work with a cross-cutting pass to make the desktop surfaces feel like one app. - Global Cmd+K command palette (cmdk): nav, settings deep-links, async API-key / MCP-server / archived-session groups, reusable theme sub-page (light/dark groups, stays open on pick), loop nav, fuzzy match. Replaces per-page settings search. - Shared SearchField: borderless, underline-on-focus, `field-sizing` auto-width. Unifies sessions sidebar, pages, overlays, command center, cron; drops bespoke OverlaySearchInput. - Cron & Profiles converted to OverlayView; flat token-driven panels (no card-in-card / divider borders) matching command center. - `r` refresh hotkey via useRefreshHotkey; drop the visible refresh buttons. - Button text/textStrong link variants applied across settings & views; shared PAGE_INSET_X content gutters. - Math/ascii loaders replace "Loading…" text placeholders; x-icon close over text "Close"; cursor-pointer at the dropdown/select primitive level.
Reload window → text link, Open logs pushed right (ml-auto), and the error message box drops the oversized rounded-2xl for rounded-md.
The full-width `text` New-profile button drew an underline under the + glyph on hover (text-decoration spans the icon). Replace with a proper "PROFILES" section header + ghost add-icon button, matching the chat sidebar's header/new-item pattern.
Tab/focus showed Tailwind's `focus-visible:ring-*` (a box-shadow) plus the native outline. Drop both via an unlayered reset that nulls --tw-ring-*; the composer / input soft-glow is untouched (those use direct box-shadows).
Add a proper shadcn-style Badge (CVA tones, app radius — not a full pill) and use it for the Default/.env tags instead of bespoke rounded-full spans. Drop the oversized text-sm metadata values to text-xs.
…ebar - Sidebar toggles in the titlebar no longer carry an active highlight — they're plain show/hide affordances now. - Replace every bespoke rounded-full status pill (cron, messaging, settings, skills) with the shared Badge (adds a `warn` tone). App radius, one component. - Cron row actions use Codicons (play/debug-pause/zap/edit/trash) to match the rest of the chrome instead of stray lucide glyphs.
Mute/haptics state reads from the icon glyph (and aria-pressed) — no background highlight on any titlebar action.
gap-4 → gap-2.5 between Try again / Reload window.
Empty datasets no longer render a search field. Adds a `searchHidden` prop to PageSearchShell (artifacts/skills/messaging) and gates cron + command center sessions search on a non-empty list. The chat sidebar already did this via showSessionSections.
Long unbroken input ran off horizontally and the stacked layout flipped on a char-count guess (too early). Add wrap rules to the contentEditable and drive expansion off the editor's actual rendered height via the resize observer, so it stacks exactly when the text wraps to a 2nd line.
- Composer single-line row centers (was bottom-aligned); placeholder randomizes per session (starter vs follow-up) without mid-stream flip. - Drop chat header on brand-new sessions (dead label + border). - ⌘N flashes its sidebar hint; ⌘. toggles the command center. - Intro wordmark fills width (drop 8rem fit cap). - Unify error states on a shared ErrorState component (boundary + updates).
- Shared useDeepLinkHighlight hook collapses 3 near-identical settings deep-link effects (keys/mcp); config kept inline (distinct bail-clear). - command-center: table-driven SECTION_ICONS + single errorText helper. - clarify-tool: OPTION_ROW_CLASS + RadioDot extracted from option rows. - desktop-controller: merge Cmd+K / Cmd+. into one keydown handler. - statusbar-controls: hoist shared action class. - Misc: drop redundant cn()/cursor-pointer/dead fields; tidy switch.
Add active sessions to the palette (fuzzy jump-to-chat), remove the low-value per-API-key entries, and move the lazy palette sources (config/sessions/archived) to react-query instead of hand-rolled useState + effect fetching. Hoist the shared nav helper.
austinpickett
approved these changes
Jun 4, 2026
davidgut1982
pushed a commit
to davidgut1982/hermes-agent
that referenced
this pull request
Jun 5, 2026
…d+K palette & UI consistency pass (NousResearch#38631) * fix(desktop): surface background-session clarify prompts instead of hanging clarify.request is a one-shot blocking event: the gateway turn blocks on clarify.respond. The desktop handler dropped it for any non-focused session (`if (!isActiveEvent) return`) and stored at most one request in a single global atom, so a background session that asked a clarifying question hung forever and re-focusing it could never recover (the event was already gone). - store/clarify.ts: key pending requests by runtime session id; expose the active session's request via a focus-scoped computed view (ClarifyTool is unchanged). clearClarifyRequest takes an optional session id for targeted clears, with a request-id fallback. - use-message-stream.ts: park every session's clarify (drop the isActiveEvent early return); toast when one lands for a background session since the row otherwise just keeps spinning like normal work. - clarify-tool.tsx: clear by session id so answering one chat can't wipe another's pending request. - store/clarify.test.ts: concurrent independence, focus-scoped view, targeted/stale/fallback clears. * feat(desktop): persistent needs-input indicator + icon button consolidation Replace the background-clarify toast (expired on alt-tab, easy to miss) with a persistent, glowing amber "needs input" dot on the session's sidebar row, driven off a new ClientSessionState.needsInput flag mirrored into a $attentionSessionIds store. The flag is set on clarify.request and cleared the moment the turn resumes (tool.complete) or ends. Also: redesign the clarify tool UI (borderless choices, pseudo-radio dots, right-aligned checkmark, arc border, tighter padding), make Button the single source of icon-button styling (4px radius, new icon-titlebar variant, titlebar buttons rendered polymorphically via asChild, Codicons throughout), put the file-tree refresh action first, and .trim() pasted composer text. * style(desktop): padding-driven, square non-icon buttons Default button sizing was vanilla-shadcn chunky (fixed h-9, 16px padding) and inconsistent with the icon-button radius pass. Size text variants by padding + line-height instead of fixed heights so they stay snug and scale with content, and drop the radius on non-icon buttons (icon buttons keep the shared 4px). Move the update-overlay CTAs off a hardcoded h-10 onto the padding-based lg variant. Composer and the inline approval strip are untouched. * style(desktop): shrink button scale, flush overlay sidebar, variant-ize stray buttons - Buttons: smaller default font (14px -> 13px) and tighter padding-driven sizes across every variant; the chunky shadcn scale read as oversized in a dense desktop UI. - Overlay split layout (settings / command center): the shared OverlayView top padding left the card surface showing as a gap above the sidebar. Move the titlebar clearance into each column so the sidebar background runs flush to the card's top edge. - Consolidate buttons that hardcoded size/radius/font onto the proper size variants (tooltip-icon-button, overlay close, cron IconAction, SidebarTrigger, gateway system button, session-row actions radius, title chip radius, release notes link) so styling flows from variant props, not per-call overrides. Composer and the inline approval strip are intentionally left as-is. * style(desktop): 12px button text, drop sparkle decoration + redundant settings titles - Button base font down to 12px (text-xs) for the dense desktop scale. - Remove the decorative Sparkles glyph from the model "Apply" button (keep the spinner while applying). - Drop the page-level section titles that just restate the left nav ("Main model", "Appearance", "MCP servers") — the sidebar already labels the pane. Sub-section headings (Auxiliary models, LLM providers, etc.) stay. * feat(desktop): add boxless `text` button variant; use for aux-model actions New reusable `text` variant renders a button as inline label text (no bg/border, muted -> foreground, underline-on-hover affordance). Emphasize the actionable word by adding `font-semibold`/`underline` at the call site. Applied to the auxiliary-model "Set to main" (plain), "Change" and "Reset all to main" (bold + underlined) actions, replacing the boxed ghost/outline buttons. * style(desktop): nudge button scale up + 2.5px radius on non-icon buttons Bump default/sm vertical padding a step (the 12px pass read too small) and give non-icon buttons a subtle 2.5px radius instead of square corners. Icon buttons keep their 4px. * style(desktop): unify Input/Textarea/SelectTrigger on shared controlVariants Mirror the buttonVariants exercise for non-composer form controls: add a single controlVariants source of truth (2.5px radius, 12px text, padding-driven sizing, chrome via desktop-input-chrome) and consume it from Input, Textarea, and SelectTrigger. Drop per-call radius/height/font overrides that fought the shared look. * style(desktop): flatten appearance settings — drop card-in-card sections Remove the outer card chrome (border/bg/shadow/rounded) wrapping each appearance section so they're flat headings + option grids instead of boxes nested inside boxes, matching the other settings pages. * style(desktop): de-box appearance options into flat rows + bare theme swatches Color Mode and Tool Call Display become flat radio-style rows (no tile border/fill, no inner icon box, no filled check badge — just a subtle active bg and a check). Theme drops its outer card wrapper so only the preview swatch shows, with a primary ring marking the active palette. * style(desktop): primitive-level pointer cursor + borderless settings lists Add a base-layer rule giving every interactive control (button, select, menu item, switch, tab, summary) cursor:pointer, and strip the now-redundant hardcoded cursor-pointer from those elements (plain clickable divs/labels keep theirs). Remove the divide-y separators from settings list sections so they breathe. * style(desktop): Color Mode + Tool Call Display as one-row segmented controls Replace the vertical option-row lists with a compact SegmentedControl (grouped pill buttons on a single track), dropping the per-option descriptions since the section subtitle already covers the context. * style(desktop): drop redundant On/Off label next to boolean config switches The switch already communicates state, so the text label was noise. * style(desktop): add Switch xs size; move appearance controls inline-right Add an xs size variant to the Switch primitive and use it for the provider edit submenu toggles. In appearance settings, drop the redundant selection Pills (the UI already shows the active choice), move the Color Mode and Tool Call Display segmented controls into the section header's right side (responsive: stacks under the heading on narrow widths), and shrink the segmented control. * feat(desktop): titlebar toggle to flip sidebar sides Adds a top-left swap button (replacing the search icon) that mirrors the layout: sessions sidebar ↔ file browser + preview rail. Persisted via $panesFlipped. The left/right sidebar toggles, content inset, and pane borders all follow the active side so the buttons stay accurate after a flip. * feat(desktop): global Cmd+K palette + UI consistency overhaul Builds on the clarify/needs-input work with a cross-cutting pass to make the desktop surfaces feel like one app. - Global Cmd+K command palette (cmdk): nav, settings deep-links, async API-key / MCP-server / archived-session groups, reusable theme sub-page (light/dark groups, stays open on pick), loop nav, fuzzy match. Replaces per-page settings search. - Shared SearchField: borderless, underline-on-focus, `field-sizing` auto-width. Unifies sessions sidebar, pages, overlays, command center, cron; drops bespoke OverlaySearchInput. - Cron & Profiles converted to OverlayView; flat token-driven panels (no card-in-card / divider borders) matching command center. - `r` refresh hotkey via useRefreshHotkey; drop the visible refresh buttons. - Button text/textStrong link variants applied across settings & views; shared PAGE_INSET_X content gutters. - Math/ascii loaders replace "Loading…" text placeholders; x-icon close over text "Close"; cursor-pointer at the dropdown/select primitive level. * style(desktop): tidy root error-boundary actions Reload window → text link, Open logs pushed right (ml-auto), and the error message box drops the oversized rounded-2xl for rounded-md. * style(desktop): fix profiles sidebar — header + add-icon, drop text-link The full-width `text` New-profile button drew an underline under the + glyph on hover (text-decoration spans the icon). Replace with a proper "PROFILES" section header + ghost add-icon button, matching the chat sidebar's header/new-item pattern. * style(desktop): kill focus rings globally Tab/focus showed Tailwind's `focus-visible:ring-*` (a box-shadow) plus the native outline. Drop both via an unlayered reset that nulls --tw-ring-*; the composer / input soft-glow is untouched (those use direct box-shadows). * style(desktop): shared Badge component; tidy profile metadata Add a proper shadcn-style Badge (CVA tones, app radius — not a full pill) and use it for the Default/.env tags instead of bespoke rounded-full spans. Drop the oversized text-sm metadata values to text-xs. * style(desktop): migrate bespoke pills to shared Badge; tidy cron/titlebar - Sidebar toggles in the titlebar no longer carry an active highlight — they're plain show/hide affordances now. - Replace every bespoke rounded-full status pill (cron, messaging, settings, skills) with the shared Badge (adds a `warn` tone). App radius, one component. - Cron row actions use Codicons (play/debug-pause/zap/edit/trash) to match the rest of the chrome instead of stray lucide glyphs. * style(desktop): drop active background on titlebar actions Mute/haptics state reads from the icon glyph (and aria-pressed) — no background highlight on any titlebar action. * style(desktop): tighten error-boundary action gap gap-4 → gap-2.5 between Try again / Reload window. * style(desktop): hide search when there's nothing to search Empty datasets no longer render a search field. Adds a `searchHidden` prop to PageSearchShell (artifacts/skills/messaging) and gates cron + command center sessions search on a non-empty list. The chat sidebar already did this via showSessionSections. * fix(desktop): composer wraps long text & expands at the real wrap point Long unbroken input ran off horizontally and the stacked layout flipped on a char-count guess (too early). Add wrap rules to the contentEditable and drive expansion off the editor's actual rendered height via the resize observer, so it stacks exactly when the text wraps to a 2nd line. * feat(desktop): composer/intro polish + shared ErrorState - Composer single-line row centers (was bottom-aligned); placeholder randomizes per session (starter vs follow-up) without mid-stream flip. - Drop chat header on brand-new sessions (dead label + border). - ⌘N flashes its sidebar hint; ⌘. toggles the command center. - Intro wordmark fills width (drop 8rem fit cap). - Unify error states on a shared ErrorState component (boundary + updates). * style(desktop): satisfy lint across PR-touched files * refactor(desktop): DRY/elegance pass over PR-touched files - Shared useDeepLinkHighlight hook collapses 3 near-identical settings deep-link effects (keys/mcp); config kept inline (distinct bail-clear). - command-center: table-driven SECTION_ICONS + single errorText helper. - clarify-tool: OPTION_ROW_CLASS + RadioDot extracted from option rows. - desktop-controller: merge Cmd+K / Cmd+. into one keydown handler. - statusbar-controls: hoist shared action class. - Misc: drop redundant cn()/cursor-pointer/dead fields; tidy switch. * feat(desktop): Cmd+K jumps to sessions; drop API-key entries Add active sessions to the palette (fuzzy jump-to-chat), remove the low-value per-API-key entries, and move the lazy palette sources (config/sessions/archived) to react-query instead of hand-rolled useState + effect fetching. Hoist the shared nav helper.
1 task
OutThisLife
added a commit
that referenced
this pull request
Jun 6, 2026
Overlays/dialogs/toasts share a custom shadow-nous (downward-weighted) and --stroke-nous hairline instead of hard borders: boot-failure, install, notifications, model-picker, onboarding, prompt-overlays, updates, Dialog. - button: outline is a 1px inset ring (no fill/shadow); chrome lives in Button - BrandMark: 256px nous-girl mark replaces sparkle glyphs (updates/onboarding/about) - onboarding: conditional header, lemniscate-bloom loaders, OTP device-code boxes, NOUS CONNECTED hero (ascii decode) + cuneiform easter egg, "Begin" matrix exit - shared LogView + ErrorState; math/ascii loaders over "Loading..." text - appearance-settings flattened to SegmentedControl/ListRow; keybind-panel on shadow-nous + text-variant reset - restore flat-UI clobbered by #38631's stale-squash (4a1907b): command-center, profiles, skills, messaging, cron de-boxed; shared SearchField + PAGE_INSET_X; profiles back on OverlaySplitLayout; skills tabs+search one row, no row dividers
OutThisLife
added a commit
that referenced
this pull request
Jun 6, 2026
…redesign (#40708) * fix(desktop): unify dialog/overlay buttons on shared Button component Replace raw <button> action/text controls across the modal layer (boot failure, install, update, onboarding, clarify, model-visibility, notifications, gateway menu) with the shared Button + its variants (text / ghost / icon-xs). Drops the bespoke square-cornered styling so every dialog matches the app's slightly-rounded button system, and swaps clarify-tool's hardcoded "Skip" for the existing i18n string. * feat(desktop): add dev-only dialog gallery for auditing overlays A code-split, DEV-gated harness (toggle ⌘/Ctrl+Alt+Shift+D) that triggers every dialog/overlay so their buttons can be eyeballed in one place: store-driven overlays (boot failure, updates, notifications, sudo/secret) plus in-place dialogs (confirm, profile create/rename, attach-url, model picker/visibility, clarify, tool approval). Never ships to production. * fix(desktop): use Ctrl+Shift+D for dialog gallery (mac-friendly) The Cmd/Ctrl+Alt+Shift+D chord is impractical on macOS (Option mangles the keypress). Ctrl+Shift+D is the same chord on every platform and uses neither Cmd nor Option. * fix(desktop): stop overriding button icon size to size-4 Action buttons hardcoded size-4 icons, overriding the Button component's built-in size-3.5. That extra 2px is why boot-failure / onboarding / gateway buttons looked chunkier than the settings "Apply" (size-3.5 spinner) despite being the same component+size. Drop the overrides so icons inherit 3.5. * feat(desktop): add BrandMark, use it in the updates overlay hero New BrandMark renders the white logo.png on a hardcoded brand-blue tile (#0000F2 light / #222 dark), replacing the generic Sparkles hero glyph in the "update available" overlay. Trying it here first to iterate on the look. NOTE: apps/desktop/public/logo.png is currently a 1x1 placeholder — the tile renders now; the glyph appears once the real white logo art is dropped in. * feat(desktop): add real logo.png asset, render it white in BrandMark logo.png is blue line-art on transparent, so force it white via filter to read on both the brand-blue (#0000F2) and near-black (#222) tiles. Bump the glyph to 62% of the tile for the portrait aspect. * fix(desktop): BrandMark renders logo as-is, no light bg/radius/padding Drop the white filter, the hardcoded light-mode blue tile, the radius, and the inner padding. Logo now fills the tile over a transparent surface in light mode; dark keeps the #222 tile. * fix(desktop): bump updates-overlay BrandMark to size-16 * feat(desktop): use downscaled karb.webp in BrandMark Swap the BrandMark glyph to karb.webp, downscaled from 1129x1418/888KB to 254x320/81KB for the hero badge. * feat(desktop): use nous-girl mark in BrandMark, invert in dark Key the white background to transparent so only the black line-art remains (384px/20KB webp). Light mode shows black art; dark mode flips it white via dark:invert on the #222 tile. Drop the now-unused karb.webp and logo.png. * fix(desktop): BrandMark uses nous-girl as-is (no transparent/invert) The dark-mode invert read as a creepy negative. Use the opaque black-on-white mark unchanged in both themes; drop the white-key, dark:invert, and #222 tile. * fix(desktop): give BrandMark an explicit white bg tile * fix(desktop): use nous-girl.jpg directly in BrandMark * perf(desktop): downscale nous-girl.jpg to 256x256 (466KB -> 19KB) * style(desktop): bump nous light --theme-secondary to 14% blue * fix(desktop): outline button is transparent, not chrome-filled The outline variant used bg-background (the chrome color), so on cards/overlays with a different surface it rendered as an odd gray-blue fill (visible on the boot overlay's Repair install / Use local gateway). Make it bg-transparent so it inherits the surface like a real outline. Reverts the unrelated --theme-secondary tweak. * fix(desktop): clean outline button — thin border, no shadow/fill Drop shadow-xs and the resting fills (light chrome bg, dark bg-input/30) so outline is just a thin clean border with a subtle hover, in both themes. * fix(desktop): stop forcing tertiary bg on outline buttons A global [data-variant='outline'] rule set background: var(--ui-bg-tertiary), which (attribute-selector specificity) overrode the cva bg-transparent — so outline buttons always showed the pale tertiary fill on cards/overlays regardless of the variant classes. Scope that fill to secondary only; outline is now a true transparent border. * style(desktop): unified overlay design system + restore #38631 flat-UI Overlays/dialogs/toasts share a custom shadow-nous (downward-weighted) and --stroke-nous hairline instead of hard borders: boot-failure, install, notifications, model-picker, onboarding, prompt-overlays, updates, Dialog. - button: outline is a 1px inset ring (no fill/shadow); chrome lives in Button - BrandMark: 256px nous-girl mark replaces sparkle glyphs (updates/onboarding/about) - onboarding: conditional header, lemniscate-bloom loaders, OTP device-code boxes, NOUS CONNECTED hero (ascii decode) + cuneiform easter egg, "Begin" matrix exit - shared LogView + ErrorState; math/ascii loaders over "Loading..." text - appearance-settings flattened to SegmentedControl/ListRow; keybind-panel on shadow-nous + text-variant reset - restore flat-UI clobbered by #38631's stale-squash (4a1907b): command-center, profiles, skills, messaging, cron de-boxed; shared SearchField + PAGE_INSET_X; profiles back on OverlaySplitLayout; skills tabs+search one row, no row dividers * refactor(desktop): clean pass — drop dead code, dedupe, fix stale docs - log-view: drop unused `bare` prop + forwardRef (no caller uses ref) - install-overlay: drop `stateOverride` (only the removed dev gallery used it) - profiles: ProfilesViewProps down to { onClose } (drop vestigial section/titlebar) - onboarding: hoist shared PROVIDER_ROW_CLASS (was duplicated 2x) - brand-mark / error-state: tighten comments, fix stale AlertCircle reference
changman
pushed a commit
to changman/hermes-agent
that referenced
this pull request
Jun 10, 2026
…redesign (NousResearch#40708) * fix(desktop): unify dialog/overlay buttons on shared Button component Replace raw <button> action/text controls across the modal layer (boot failure, install, update, onboarding, clarify, model-visibility, notifications, gateway menu) with the shared Button + its variants (text / ghost / icon-xs). Drops the bespoke square-cornered styling so every dialog matches the app's slightly-rounded button system, and swaps clarify-tool's hardcoded "Skip" for the existing i18n string. * feat(desktop): add dev-only dialog gallery for auditing overlays A code-split, DEV-gated harness (toggle ⌘/Ctrl+Alt+Shift+D) that triggers every dialog/overlay so their buttons can be eyeballed in one place: store-driven overlays (boot failure, updates, notifications, sudo/secret) plus in-place dialogs (confirm, profile create/rename, attach-url, model picker/visibility, clarify, tool approval). Never ships to production. * fix(desktop): use Ctrl+Shift+D for dialog gallery (mac-friendly) The Cmd/Ctrl+Alt+Shift+D chord is impractical on macOS (Option mangles the keypress). Ctrl+Shift+D is the same chord on every platform and uses neither Cmd nor Option. * fix(desktop): stop overriding button icon size to size-4 Action buttons hardcoded size-4 icons, overriding the Button component's built-in size-3.5. That extra 2px is why boot-failure / onboarding / gateway buttons looked chunkier than the settings "Apply" (size-3.5 spinner) despite being the same component+size. Drop the overrides so icons inherit 3.5. * feat(desktop): add BrandMark, use it in the updates overlay hero New BrandMark renders the white logo.png on a hardcoded brand-blue tile (#0000F2 light / NousResearch#222 dark), replacing the generic Sparkles hero glyph in the "update available" overlay. Trying it here first to iterate on the look. NOTE: apps/desktop/public/logo.png is currently a 1x1 placeholder — the tile renders now; the glyph appears once the real white logo art is dropped in. * feat(desktop): add real logo.png asset, render it white in BrandMark logo.png is blue line-art on transparent, so force it white via filter to read on both the brand-blue (#0000F2) and near-black (NousResearch#222) tiles. Bump the glyph to 62% of the tile for the portrait aspect. * fix(desktop): BrandMark renders logo as-is, no light bg/radius/padding Drop the white filter, the hardcoded light-mode blue tile, the radius, and the inner padding. Logo now fills the tile over a transparent surface in light mode; dark keeps the NousResearch#222 tile. * fix(desktop): bump updates-overlay BrandMark to size-16 * feat(desktop): use downscaled karb.webp in BrandMark Swap the BrandMark glyph to karb.webp, downscaled from 1129x1418/888KB to 254x320/81KB for the hero badge. * feat(desktop): use nous-girl mark in BrandMark, invert in dark Key the white background to transparent so only the black line-art remains (384px/20KB webp). Light mode shows black art; dark mode flips it white via dark:invert on the NousResearch#222 tile. Drop the now-unused karb.webp and logo.png. * fix(desktop): BrandMark uses nous-girl as-is (no transparent/invert) The dark-mode invert read as a creepy negative. Use the opaque black-on-white mark unchanged in both themes; drop the white-key, dark:invert, and NousResearch#222 tile. * fix(desktop): give BrandMark an explicit white bg tile * fix(desktop): use nous-girl.jpg directly in BrandMark * perf(desktop): downscale nous-girl.jpg to 256x256 (466KB -> 19KB) * style(desktop): bump nous light --theme-secondary to 14% blue * fix(desktop): outline button is transparent, not chrome-filled The outline variant used bg-background (the chrome color), so on cards/overlays with a different surface it rendered as an odd gray-blue fill (visible on the boot overlay's Repair install / Use local gateway). Make it bg-transparent so it inherits the surface like a real outline. Reverts the unrelated --theme-secondary tweak. * fix(desktop): clean outline button — thin border, no shadow/fill Drop shadow-xs and the resting fills (light chrome bg, dark bg-input/30) so outline is just a thin clean border with a subtle hover, in both themes. * fix(desktop): stop forcing tertiary bg on outline buttons A global [data-variant='outline'] rule set background: var(--ui-bg-tertiary), which (attribute-selector specificity) overrode the cva bg-transparent — so outline buttons always showed the pale tertiary fill on cards/overlays regardless of the variant classes. Scope that fill to secondary only; outline is now a true transparent border. * style(desktop): unified overlay design system + restore NousResearch#38631 flat-UI Overlays/dialogs/toasts share a custom shadow-nous (downward-weighted) and --stroke-nous hairline instead of hard borders: boot-failure, install, notifications, model-picker, onboarding, prompt-overlays, updates, Dialog. - button: outline is a 1px inset ring (no fill/shadow); chrome lives in Button - BrandMark: 256px nous-girl mark replaces sparkle glyphs (updates/onboarding/about) - onboarding: conditional header, lemniscate-bloom loaders, OTP device-code boxes, NOUS CONNECTED hero (ascii decode) + cuneiform easter egg, "Begin" matrix exit - shared LogView + ErrorState; math/ascii loaders over "Loading..." text - appearance-settings flattened to SegmentedControl/ListRow; keybind-panel on shadow-nous + text-variant reset - restore flat-UI clobbered by NousResearch#38631's stale-squash (4a1907b): command-center, profiles, skills, messaging, cron de-boxed; shared SearchField + PAGE_INSET_X; profiles back on OverlaySplitLayout; skills tabs+search one row, no row dividers * refactor(desktop): clean pass — drop dead code, dedupe, fix stale docs - log-view: drop unused `bare` prop + forwardRef (no caller uses ref) - install-overlay: drop `stateOverride` (only the removed dev gallery used it) - profiles: ProfilesViewProps down to { onClose } (drop vestigial section/titlebar) - onboarding: hoist shared PROVIDER_ROW_CLASS (was duplicated 2x) - brand-mark / error-state: tighten comments, fix stale AlertCircle reference
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
Started as a bug — background sessions that hit a blocking
clarifyhung forever in multi-chat — and grew into the cross-cutting desktop cleanup that bug exposed. The surfaces now read like one app: shared primitives, consistent affordances, flat token-driven layouts.Multi-chat & needs-input
clarify/approval/sudo/secret used to hang silently (or fire a toast that died on alt-tab). Prompts are now parked per-session and replayed when you focus that chat, so racing chats never drop one.ClientSessionState.needsInput(mirrored into$attentionSessionIds) drives a steady glowing amber dot on the session's sidebar row — survives window blur, distinct from the active-turn accent pulse. Set onclarify.request, cleared when the turn resumes (tool.complete) or ends.cursor-pointerthroughout.Global Cmd+K command palette
cmdk-based palette summonable anywhere (Cmd/Ctrl+K), centered overlay. Navigation, Command Center deep-links, Settings, and a reusable theme sub-page (light/dark groups, stays open so each pick previews live). Loop navigation, fuzzy matching, uppercase group headings.?field/?server/?session→ scroll + flash via a shareduseDeepLinkHighlighthook).UI consistency pass
Buttonis the single source of button styling — uniform radius acrossicon*sizes, anicon-titlebarvariant, titlebar buttons rendered polymorphically (asChild), Codicons throughout. Added quiettext/ emphasizedtextStronglink variants and applied them across settings & views (no more bespokefont-semibold underlinebuttons).controlVariantsunifies Input / Textarea / SelectTrigger; new sharedSearchField(borderless, underline-on-focus,field-sizingauto-width),SegmentedControl,Badge,ErrorState, and anxsSwitch. Bespoke pills, search inputs, and error fallbacks were migrated onto these.OverlayViews; Command Center (Usage / System / Sessions), appearance settings, messaging, and profiles were de-boxed (no card-in-card or divider borders). SharedPAGE_INSET_Xgutters; math/ascii loaders replace "Loading…" text.cursor-pointerat the dropdown/select primitive level (no hardcoding); global focus-ring reset; titlebar actions dropped their active-background state; refresh buttons removed in favor of anrhotkey (useRefreshHotkey); empty lists hide their search field; x-icon close over text "Close"; Esc closes every dismissable overlay/dialog (install/onboarding excluded).tan(atan2(...))fit-text trick to fill its width.Test plan
tsc -b(type-check) cleaneslintclean on all touched filesviteststore suites pass (session / clarify / prompts — 69 tests)