mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-28 06:51:16 +08:00
refactor(tui): move last-msg elapsed from status bar to prompt right-edge
Status bar ticker was too hot in peripheral vision. The moment the elapsed value matters is when the prompt returns — so surface it there. Dim `fmtDuration` next to the GoodVibesHeart, idle-only (hidden while busy), so quick turns and active streaming stay quiet.
This commit is contained in:
@@ -55,7 +55,7 @@ function ctxBar(pct: number | undefined, w = 10) {
|
||||
return '█'.repeat(filled) + '░'.repeat(w - filled)
|
||||
}
|
||||
|
||||
function SessionDuration({ lastUserAt, startedAt }: { lastUserAt?: null | number; startedAt: number }) {
|
||||
function SessionDuration({ startedAt }: { startedAt: number }) {
|
||||
const [now, setNow] = useState(() => Date.now())
|
||||
|
||||
useEffect(() => {
|
||||
@@ -65,9 +65,20 @@ function SessionDuration({ lastUserAt, startedAt }: { lastUserAt?: null | number
|
||||
return () => clearInterval(id)
|
||||
}, [startedAt])
|
||||
|
||||
const total = fmtDuration(now - startedAt)
|
||||
return fmtDuration(now - startedAt)
|
||||
}
|
||||
|
||||
return lastUserAt ? `${fmtDuration(now - lastUserAt)}/${total}` : total
|
||||
export function IdleSinceLastMsg({ lastUserAt, t }: { lastUserAt: number; t: Theme }) {
|
||||
const [now, setNow] = useState(() => Date.now())
|
||||
|
||||
useEffect(() => {
|
||||
setNow(Date.now())
|
||||
const id = setInterval(() => setNow(Date.now()), 1000)
|
||||
|
||||
return () => clearInterval(id)
|
||||
}, [lastUserAt])
|
||||
|
||||
return <Text color={t.color.dim}>{fmtDuration(now - lastUserAt)} </Text>
|
||||
}
|
||||
|
||||
export function GoodVibesHeart({ tick, t }: { tick: number; t: Theme }) {
|
||||
@@ -100,7 +111,6 @@ export function StatusRule({
|
||||
model,
|
||||
usage,
|
||||
bgCount,
|
||||
lastUserAt,
|
||||
sessionStartedAt,
|
||||
showCost,
|
||||
voiceLabel,
|
||||
@@ -135,7 +145,7 @@ export function StatusRule({
|
||||
{sessionStartedAt ? (
|
||||
<Text color={t.color.dim}>
|
||||
{' │ '}
|
||||
<SessionDuration lastUserAt={lastUserAt} startedAt={sessionStartedAt} />
|
||||
<SessionDuration startedAt={sessionStartedAt} />
|
||||
</Text>
|
||||
) : null}
|
||||
{voiceLabel ? <Text color={t.color.dim}> │ {voiceLabel}</Text> : null}
|
||||
@@ -290,7 +300,6 @@ interface StatusRuleProps {
|
||||
busy: boolean
|
||||
cols: number
|
||||
cwdLabel: string
|
||||
lastUserAt?: null | number
|
||||
model: string
|
||||
sessionStartedAt?: null | number
|
||||
showCost: boolean
|
||||
|
||||
@@ -9,7 +9,7 @@ import { PLACEHOLDER } from '../content/placeholders.js'
|
||||
import type { Theme } from '../theme.js'
|
||||
import type { DetailsMode } from '../types.js'
|
||||
|
||||
import { GoodVibesHeart, StatusRule, StickyPromptTracker, TranscriptScrollbar } from './appChrome.js'
|
||||
import { GoodVibesHeart, IdleSinceLastMsg, StatusRule, StickyPromptTracker, TranscriptScrollbar } from './appChrome.js'
|
||||
import { FloatingOverlays, PromptZone } from './appOverlays.js'
|
||||
import { Banner, Panel, SessionPanel } from './branding.js'
|
||||
import { MessageLine } from './messageLine.js'
|
||||
@@ -188,7 +188,6 @@ const ComposerPane = memo(function ComposerPane({
|
||||
busy={ui.busy}
|
||||
cols={composer.cols}
|
||||
cwdLabel={status.cwdLabel}
|
||||
lastUserAt={status.lastUserAt}
|
||||
model={ui.info?.model?.split('/').pop() ?? ''}
|
||||
sessionStartedAt={status.sessionStartedAt}
|
||||
showCost={ui.showCost}
|
||||
@@ -243,7 +242,9 @@ const ComposerPane = memo(function ComposerPane({
|
||||
value={composer.input}
|
||||
/>
|
||||
|
||||
<Box position="absolute" right={0}>
|
||||
<Box flexDirection="row" position="absolute" right={0}>
|
||||
{!ui.busy && status.lastUserAt ? <IdleSinceLastMsg lastUserAt={status.lastUserAt} t={ui.theme} /> : null}
|
||||
|
||||
<GoodVibesHeart t={ui.theme} tick={status.goodVibesTick} />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user