Files
hermes-agent/ui-tui/src/app/uiStore.ts
T
Teknium 77fcc2ea31 feat(display): honor display.timestamps across desktop transcript and TUI
One config key everywhere (#41531): the same display.timestamps that stamps
[HH:MM] on classic-CLI labels now gates the desktop transcript's timeline
timestamps and renders dim [HH:MM] labels on TUI user/assistant rows.

- desktop: $displayTimestamps store fed from config.yaml via
  use-hermes-config; TimelineTimestamp renders nothing while the key is off
  (the default). Hover tooltips with the exact time stay ungated (#70450).
- TUI: tui_gateway forwards each persisted row's timestamp in the display
  projection; toTranscriptMessages threads it as Msg.createdAt; live rows
  are stamped at append (the #82840 rule); MessageLine shows a dim [HH:MM]
  above user/assistant rows when display.timestamps is on.
- No new config keys, no HERMES_* env vars; display-only, prompt-cache safe.
2026-08-15 01:04:19 -07:00

54 lines
1.6 KiB
TypeScript

import { atom, computed } from 'nanostores'
import { MOUSE_TRACKING } from '../config/env.js'
import { ZERO } from '../domain/usage.js'
import { bootTheme } from '../lib/themeBoot.js'
import { DEFAULT_THEME } from '../theme.js'
import { DEFAULT_INDICATOR_STYLE, type UiState } from './interfaces.js'
const buildUiState = (): UiState => ({
battery: false,
batteryStatus: null,
bgTasks: new Set(),
busy: false,
busyInputMode: 'queue',
compact: false,
destructiveSlashConfirm: true,
detailsMode: 'collapsed',
detailsModeCommandOverride: false,
focusView: false,
indicatorStyle: DEFAULT_INDICATOR_STYLE,
info: null,
liveSessionCount: 0,
inlineDiffs: true,
mouseTracking: MOUSE_TRACKING,
notice: null,
pasteCollapseLines: 5,
pasteCollapseChars: 2000,
sections: {},
sessionTitle: '',
showReasoning: false,
sid: null,
status: 'summoning hermes…',
statusBar: 'top',
streaming: true,
timestamps: false,
// Last session's resolved theme paints frame one (flash-free boot, like
// the desktop's hermes-boot-* keys); DEFAULT_THEME only on first launch.
theme: bootTheme ?? DEFAULT_THEME,
usage: ZERO
})
export const $uiState = atom<UiState>(buildUiState())
export const $uiTheme = computed($uiState, state => state.theme)
export const $uiSessionId = computed($uiState, state => state.sid)
export const getUiState = () => $uiState.get()
export const patchUiState = (next: Partial<UiState> | ((state: UiState) => UiState)) =>
$uiState.set(typeof next === 'function' ? next($uiState.get()) : { ...$uiState.get(), ...next })
export const resetUiState = () => $uiState.set(buildUiState())