mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-28 18:19:28 +00:00
Merge pull request #72523 from NousResearch/bb/tui-resize-color
fix(tui): paint the OSC-10 default foreground on quantizing terminals
This commit is contained in:
commit
d7311b586c
3 changed files with 57 additions and 2 deletions
|
|
@ -653,3 +653,31 @@ describe('background-aware adaptation (OSC-11 light terminals)', () => {
|
|||
expect(color.statusCritical).toBe(fromSkin({ ui_error: '#dd2222' }, {}).color.error)
|
||||
})
|
||||
})
|
||||
|
||||
describe('themeToneHex', () => {
|
||||
it('resolves a tone to the literal color it paints as', async () => {
|
||||
const { themeToneHex } = await importThemeWithCleanEnv()
|
||||
|
||||
// 232+ is the grayscale ramp (8 + (n-232)*10); 16-231 is the 6x6x6 cube.
|
||||
expect(themeToneHex('ansi256(238)')).toBe('#444444')
|
||||
expect(themeToneHex('ansi256(161)')).toBe('#d7005f')
|
||||
// An authored hex is already literal.
|
||||
expect(themeToneHex('#e77fa3')).toBe('#e77fa3')
|
||||
// No paintable color ⇒ '', which releases the terminal default.
|
||||
expect(themeToneHex('')).toBe('')
|
||||
expect(themeToneHex('ansi256(999)')).toBe('')
|
||||
expect(themeToneHex('inherit')).toBe('')
|
||||
})
|
||||
|
||||
it('makes every tone paintable on a quantizing terminal', async () => {
|
||||
// The contract OSC-10 depends on: whatever the palette normalizer does to
|
||||
// a tone, themeToneHex still yields a literal `#rrggbb`. Asserted over the
|
||||
// whole palette so a new tone can't silently regress the default paint.
|
||||
const { fromSkin, themeToneHex } = await importThemeWithEnv({ TERM_PROGRAM: 'Apple_Terminal' })
|
||||
const { color } = fromSkin({ background: '#f6f9fd', ui_text: '#4a4550' }, {})
|
||||
|
||||
for (const tone of Object.values(color)) {
|
||||
expect(themeToneHex(tone)).toMatch(/^#[0-9a-f]{6}$/i)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import { topLevelSubagents } from '../lib/subagentTree.js'
|
|||
import { isPaintableHex, setTerminalBackground, setTerminalForeground } from '../lib/terminalModes.js'
|
||||
import { formatAbandonedClarify, formatToolCall, stripAnsi } from '../lib/text.js'
|
||||
import { bootSeededPin, invalidateBootBackground, writeBootTheme } from '../lib/themeBoot.js'
|
||||
import { defaultThemeForCurrentBackground, fromSkin, skinIsLight, type Theme } from '../theme.js'
|
||||
import { defaultThemeForCurrentBackground, fromSkin, skinIsLight, type Theme, themeToneHex } from '../theme.js'
|
||||
import type { Msg, SubagentProgress, SubagentStatus } from '../types.js'
|
||||
|
||||
import { applyDelegationStatus, getDelegationState } from './delegationStore.js'
|
||||
|
|
@ -126,11 +126,13 @@ const themesEqual = (a: Theme, b: Theme) => {
|
|||
// the theme's text color. Without the pair, a dark skin on a light terminal
|
||||
// leaves default-fg text at the HOST's near-black: invisible. Opt-in stays
|
||||
// intact: no `background` ⇒ both defaults restore to the terminal's own.
|
||||
// The text tone resolves through themeToneHex because a limited-palette
|
||||
// terminal quantizes it to `ansi256(N)`, which OSC-10 cannot speak.
|
||||
const paintTerminalDefaults = (theme: Theme) => {
|
||||
const background = lastSkin?.colors?.background ?? ''
|
||||
|
||||
setTerminalBackground(background)
|
||||
setTerminalForeground(isPaintableHex(background) ? theme.color.text : '')
|
||||
setTerminalForeground(isPaintableHex(background) ? themeToneHex(theme.color.text) : '')
|
||||
}
|
||||
|
||||
const applySkin = (s: GatewaySkin) => {
|
||||
|
|
|
|||
|
|
@ -222,6 +222,31 @@ function normalizeAnsiForeground(color: string): string {
|
|||
return `ansi256(${ansi})`
|
||||
}
|
||||
|
||||
const ANSI256_RE = /^ansi256\((\d{1,3})\)$/
|
||||
|
||||
/**
|
||||
* The literal `#rrggbb` a theme tone paints as, or '' when it has none.
|
||||
*
|
||||
* The inverse of `normalizeAnsiForeground`: tones are not uniformly hex, since
|
||||
* a limited-palette terminal rewrites the foregrounds to `ansi256(N)`.
|
||||
* Consumers needing a real color — OSC 10/11, which only speak `#rrggbb` —
|
||||
* resolve through here rather than hex-testing the tone, which would silently
|
||||
* skip exactly the terminals that did the quantizing.
|
||||
*/
|
||||
export function themeToneHex(tone: string): string {
|
||||
const ansi = ANSI256_RE.exec(tone.trim())
|
||||
|
||||
if (ansi) {
|
||||
const n = Number(ansi[1])
|
||||
|
||||
return n <= 255 ? toHex(xtermEightBitRgb(n)) : ''
|
||||
}
|
||||
|
||||
const rgb = parseColor(tone)
|
||||
|
||||
return rgb ? toHex(rgb) : ''
|
||||
}
|
||||
|
||||
// ── Defaults ─────────────────────────────────────────────────────────
|
||||
|
||||
const BRAND: ThemeBrand = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue