mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-12 13:52:15 +00:00
opentui(v6): ink-budget follow-up — transparent root canvas; muted stops borrowing banner_dim
This commit is contained in:
parent
a089614451
commit
408789d909
4 changed files with 37 additions and 16 deletions
|
|
@ -12,7 +12,6 @@
|
|||
import { createCliRenderer, type CliRenderer, type KeyEvent, type Selection } from '@opentui/core'
|
||||
import { Deferred, Effect } from 'effect'
|
||||
|
||||
import { DEFAULT_THEME } from '../logic/theme.ts'
|
||||
import { RendererError } from './errors.ts'
|
||||
import { installFfiCoordSafety } from './ffiSafe.ts'
|
||||
import { getLog } from './log.ts'
|
||||
|
|
@ -67,10 +66,10 @@ export const acquireRenderer = Effect.fn('Renderer.acquire')(function* (options:
|
|||
Effect.tryPromise({
|
||||
try: () =>
|
||||
createCliRenderer({
|
||||
// Root canvas (design pass): paint the dark room from the first frame
|
||||
// — true black by default. Skin overrides land reactively via the
|
||||
// header's theme effect (view/header.tsx setBackgroundColor).
|
||||
backgroundColor: DEFAULT_THEME.color.bg,
|
||||
// Root canvas: TRANSPARENT by default — the terminal's own background
|
||||
// shows through (do not paint a "default dark" canvas; glitch hated
|
||||
// it). A skin's explicit ui_bg lands reactively via the header's
|
||||
// theme effect (view/header.tsx setBackgroundColor).
|
||||
// scrollbox clips growing output → no terminal-scrollback corruption (gotcha §8 #2).
|
||||
externalOutputMode: 'passthrough',
|
||||
targetFps: 60,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,12 @@
|
|||
*
|
||||
* Source of truth for the contract: ui-tui/src/theme.ts (+ GatewaySkin in
|
||||
* ui-tui/src/gatewayTypes.ts). Keep this port in sync if that contract changes.
|
||||
*
|
||||
* INTENTIONAL divergences from the Ink port (visual-hierarchy design pass):
|
||||
* - `muted` is a true NEUTRAL grey (not a darker gold) and no longer borrows
|
||||
* the skin's `banner_dim` (a banner-gold shade in the stock skin); skins
|
||||
* override it via the dedicated `ui_muted` key instead.
|
||||
* - a `bg` token paints the root canvas (true black/white; `ui_bg` override).
|
||||
*/
|
||||
|
||||
import { FALSE_RE, TRUE_RE } from './env.ts'
|
||||
|
|
@ -22,9 +28,10 @@ export interface ThemeColors {
|
|||
border: string
|
||||
text: string
|
||||
muted: string
|
||||
/** Root canvas background (design pass: the view is a dark room — true black
|
||||
* by default; skins may override via `ui_bg`). CSS names are valid OpenTUI
|
||||
* ColorInput, so the defaults use `black`/`white`, not invented hexes. */
|
||||
/** Root canvas background. DEFAULT IS `transparent` — the terminal's own
|
||||
* background shows through (glitch rejected a painted "default dark" canvas;
|
||||
* the dark room is the user's terminal, not ours). Skins may opt into a
|
||||
* painted canvas via `ui_bg`. */
|
||||
bg: string
|
||||
completionBg: string
|
||||
completionCurrentBg: string
|
||||
|
|
@ -262,7 +269,7 @@ export const DARK_THEME: Theme = {
|
|||
// step, CSS `gray` — no invented hexes. Grey = everything that merely
|
||||
// happened; gold stays earned.
|
||||
muted: '#808080',
|
||||
bg: 'black',
|
||||
bg: 'transparent',
|
||||
completionBg: '#1a1a2e',
|
||||
completionCurrentBg: '#333355',
|
||||
completionMetaBg: '#1a1a2e',
|
||||
|
|
@ -308,7 +315,7 @@ export const LIGHT_THEME: Theme = {
|
|||
// same disease as dark: muted was `#7A5A0F` (gold-brown). True neutral —
|
||||
// the statusFg `#333333` family's lighter step, CSS `dimgray`.
|
||||
muted: '#696969',
|
||||
bg: 'white',
|
||||
bg: 'transparent',
|
||||
completionBg: '#F5F5F5',
|
||||
completionCurrentBg: mix('#F5F5F5', '#A0651C', 0.25),
|
||||
completionMetaBg: '#F5F5F5',
|
||||
|
|
@ -445,7 +452,13 @@ export function fromSkin(
|
|||
|
||||
const accent = c('ui_accent') ?? c('banner_accent') ?? d.color.accent
|
||||
const bannerAccent = c('banner_accent') ?? c('banner_title') ?? d.color.accent
|
||||
const muted = c('banner_dim') ?? d.color.muted
|
||||
// Design pass (Appendix C precondition): `muted` is the transcript's "merely
|
||||
// happened" NEUTRAL — it must NOT borrow `banner_dim` (the stock skin's dim
|
||||
// GOLD banner shade; the Ink engine still uses it for its banner-tinted dim).
|
||||
// Borrowing it re-golded every dim surface in the live app and made the hero
|
||||
// color the wallpaper. Skins that want a custom transcript dim ship the
|
||||
// dedicated `ui_muted` key; everything else gets the theme's true neutral.
|
||||
const muted = c('ui_muted') ?? d.color.muted
|
||||
const completionBg = c('completion_menu_bg') ?? d.color.completionBg
|
||||
|
||||
const completionCurrentBg =
|
||||
|
|
|
|||
|
|
@ -50,9 +50,9 @@ describe('theme — muted is a true neutral, not darker gold (design-pass precon
|
|||
expect(isAchromatic(DARK_THEME.color.sessionBorder)).toBe(true)
|
||||
})
|
||||
|
||||
test('bg token: true black (dark) / white (light) by CSS name', () => {
|
||||
expect(DARK_THEME.color.bg).toBe('black')
|
||||
expect(LIGHT_THEME.color.bg).toBe('white')
|
||||
test('bg token: TRANSPARENT by default — the terminal owns the canvas (glitch decision)', () => {
|
||||
expect(DARK_THEME.color.bg).toBe('transparent')
|
||||
expect(LIGHT_THEME.color.bg).toBe('transparent')
|
||||
})
|
||||
|
||||
test('fromSkin: skins may override bg via ui_bg; default stays the theme bg', () => {
|
||||
|
|
@ -60,8 +60,14 @@ describe('theme — muted is a true neutral, not darker gold (design-pass precon
|
|||
expect(fromSkin({}, {}).color.bg).toBe(DARK_THEME.color.bg)
|
||||
})
|
||||
|
||||
test('skin mapping intact: banner_dim still re-points muted (skins keep their dim)', () => {
|
||||
expect(fromSkin({ banner_dim: '#445566' }, {}).color.muted).toBe('#445566')
|
||||
test('muted no longer borrows banner_dim (the stock skin ships GOLD there — the live re-gold bug)', () => {
|
||||
// The default Hermes skin sends banner_dim '#B8860B'; borrowing it for
|
||||
// muted re-golded every dim surface in the live app. It must stay neutral.
|
||||
expect(fromSkin({ banner_dim: '#B8860B' }, {}).color.muted).toBe(DARK_THEME.color.muted)
|
||||
})
|
||||
|
||||
test('skins keep a dedicated transcript-dim override: ui_muted', () => {
|
||||
expect(fromSkin({ ui_muted: '#445566' }, {}).color.muted).toBe('#445566')
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ export function Header(props: { store: SessionStore }) {
|
|||
// Root canvas paint — best-effort (a styling miss must never crash chrome).
|
||||
createEffect(() => {
|
||||
const bg = theme().color.bg
|
||||
// Default is `transparent` = leave the terminal's background alone; only a
|
||||
// skin's explicit ui_bg paints the canvas.
|
||||
if (bg === 'transparent') return
|
||||
try {
|
||||
renderer.setBackgroundColor(bg)
|
||||
} catch {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue