* Footer status line under the input box: model + mode on the left, usage + credit and * key hints on the right. "credit" reads "local · free" for on-device models (cost $0) and * the running dollar amount once a paid API is in play. Updates live as budget events land.
(props: {
width: number;
model: string;
mode: 'normal' | 'plan';
tokens: number;
costUsd: number;
contextTokens: number;
contextWindow: number;
elapsedMs: number;
busy: boolean;
})
| 777 | {props.busy |
| 778 | ? <Text dimColor> · crafting… · Esc to stop</Text> |
| 779 | : props.mode === 'plan' |
| 780 | ? <Text color="yellow"> · plan mode</Text> |
| 781 | : <Text dimColor> · ready</Text>} |
| 782 | </Box> |
| 783 | ); |
| 784 | } |
| 785 | |
| 786 | /** |
| 787 | * Footer status line under the input box: model + mode on the left, usage + credit and |
| 788 | * key hints on the right. "credit" reads "local · free" for on-device models (cost $0) and |
| 789 | * the running dollar amount once a paid API is in play. Updates live as budget events land. |
| 790 | */ |
| 791 | function StatusBar(props: { |
| 792 | width: number; |
| 793 | model: string; |
| 794 | mode: 'normal' | 'plan'; |
| 795 | tokens: number; |
| 796 | costUsd: number; |
| 797 | contextTokens: number; |
| 798 | contextWindow: number; |
| 799 | providerName?: string; |
| 800 | providerIsLocal?: boolean; |
| 801 | elapsedMs: number; |
| 802 | busy: boolean; |
| 803 | }): React.ReactElement { |
| 804 | const { width, model, mode, tokens, costUsd, contextTokens, contextWindow, providerName, providerIsLocal, elapsedMs, busy } = props; |
| 805 | const tok = tokens >= 1000 ? `${(tokens / 1000).toFixed(1)}k` : String(tokens); |
| 806 | // WHERE the model runs, stated — not guessed from cost: 'ollama·local', 'lmstudio·local', |
| 807 | // 'anthropic·api'… A billing API at $0.0000 still shows ·api so cloud is never mistaken |
| 808 | // for free-local; the dollar figure appears the moment real cost accrues. |
| 809 | const source = providerName ? `${providerName}·${providerIsLocal ? 'local' : 'api'}` : ''; |
| 810 | const credit = costUsd > 0 ? `$${costUsd.toFixed(4)}` : providerIsLocal === false ? 'api · $0.0000' : 'local · free'; |
| 811 | // Throughput (token-consumption rate) + elapsed time. Average over the task — |
| 812 | // total tokens / elapsed — which is exactly "how fast tokens are being spent". |
| 813 | const secs = elapsedMs / 1000; |
| 814 | const showTiming = elapsedMs > 0; |
| 815 | const rate = secs > 0.3 ? Math.round(tokens / secs) : 0; |
| 816 | const rateStr = rate >= 1000 ? `${(rate / 1000).toFixed(1)}k` : String(rate); |
| 817 | const elapsedStr = secs >= 60 ? `${Math.floor(secs / 60)}m ${Math.round(secs % 60)}s` : `${secs.toFixed(1)}s`; |
| 818 | const ctxMeter = formatContextMeter(contextTokens, contextWindow); |
| 819 | // Colour the meter by fullness: green < 60%, yellow < 85%, red beyond (approaching |
| 820 | // compaction / the window limit). |
| 821 | const ctxPct = contextWindow > 0 ? (contextTokens / contextWindow) * 100 : 0; |
| 822 | const ctxColor = ctxPct >= 85 ? 'red' : ctxPct >= 60 ? 'yellow' : 'green'; |
| 823 | return ( |
| 824 | <Box width={width} paddingX={1} justifyContent="space-between"> |
| 825 | <Box> |
| 826 | <Text dimColor>{model}</Text> |
| 827 | {source !== '' && ( |
| 828 | <> |
| 829 | <Text dimColor> · </Text> |
| 830 | <Text color={providerIsLocal ? 'cyan' : 'magenta'} dimColor={!busy}>{source}</Text> |
| 831 | </> |
| 832 | )} |
| 833 | <Text dimColor> · </Text> |
| 834 | <Text color={mode === 'plan' ? 'yellow' : 'green'}>{mode}</Text> |
nothing calls this directly
no test coverage detected