From e23ec053ae0432eaf44b84f19093a444a5a1ca1b Mon Sep 17 00:00:00 2001 From: Muhammad Zakir Ramadhan <61570975+zakirkun@users.noreply.github.com> Date: Sat, 5 Sep 2026 17:31:19 +0700 Subject: [PATCH] Show elapsed working time, a compaction warning, and dismiss hints Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/ui/Panels.tsx | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/ui/Panels.tsx b/src/ui/Panels.tsx index b088aef..b43f351 100644 --- a/src/ui/Panels.tsx +++ b/src/ui/Panels.tsx @@ -107,6 +107,31 @@ export function SubagentPanel({ agents, steps = 4 }: { agents: SubagentView[]; s ); } +/** Elapsed time in the shortest form that still reads as a duration. */ +const elapsed = (seconds: number) => + seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m ${seconds % 60}s`; + +/** Seconds before the count appears: a timer starting at 0s is noise, not feedback. */ +const SLOW_AFTER = 10; + +/** + * The spinner line while the model works. + * + * The elapsed count starts only once a turn is slow enough to wonder about. Before + * that it is a number nobody reads; after it, it is the difference between "this is + * taking a while" and "has this hung?". + */ +export function Working({ seconds }: { seconds: number }) { + return ( + + {' '} + + {seconds >= SLOW_AFTER ? `working ${elapsed(seconds)}... esc to interrupt` : 'working... esc to interrupt'} + + + ); +} + /** Live tail of a running shell command. */ export function OutputPanel({ text, lines = 8 }: { text: string; lines?: number }) { if (text.length === 0) return null; @@ -259,7 +284,8 @@ export function StatusBar({ }) { const pct = contextLimit ? Math.min(100, Math.round((contextTokens / contextLimit) * 100)) : undefined; // Amber from two thirds, red once compaction is imminent: the point is to warn - // before a turn silently loses its history, not after. + // before a turn silently loses its history, not after. Past 90 the colour is + // backed by words, because a reader watching the transcript is not watching this. const contextColor = pct === undefined ? undefined : pct >= 90 ? 'red' : pct >= 66 ? 'yellow' : undefined; return ( @@ -270,6 +296,7 @@ export function StatusBar({ {pct === undefined ? `~${contextTokens} ctx` : `${pct}% ctx`} + {pct !== undefined && pct >= 90 && {' compacting soon'}} {` ${cost}`} ); @@ -295,6 +322,7 @@ export function InfoPanel({ title, hint, lines }: { title: string; hint?: string )) )} + esc to dismiss ); } @@ -344,7 +372,7 @@ export function RegistryPanel({ {r.installed && {' installed'}} ))} - {'S skill P plugin | /registry add '} + {'S skill P plugin | /registry add | esc to dismiss'} ); }