@tokentop/ttop 0.2.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -5
- package/package.json +8 -5
- package/src/agents/aggregator.ts +39 -19
- package/src/agents/costing.ts +11 -9
- package/src/agents/index.ts +7 -9
- package/src/agents/types.ts +2 -2
- package/src/cli.ts +28 -23
- package/src/config/schema.test.ts +42 -40
- package/src/config/schema.ts +26 -26
- package/src/demo/simulator.ts +161 -122
- package/src/plugins/agents/index.ts +2 -2
- package/src/plugins/auth-sources.ts +42 -38
- package/src/plugins/lifecycle.ts +42 -38
- package/src/plugins/loader.test.ts +49 -49
- package/src/plugins/loader.ts +67 -63
- package/src/plugins/notification-bus.ts +21 -16
- package/src/plugins/notifications/index.ts +2 -2
- package/src/plugins/notifications/terminal-bell.ts +36 -23
- package/src/plugins/notifications/visual-flash.ts +31 -19
- package/src/plugins/npm-installer.ts +23 -25
- package/src/plugins/plugin-context-factory.ts +10 -10
- package/src/plugins/plugin-host.ts +12 -5
- package/src/plugins/providers/anthropic.ts +64 -57
- package/src/plugins/providers/antigravity.ts +81 -69
- package/src/plugins/providers/codex.ts +42 -42
- package/src/plugins/providers/gemini.ts +106 -87
- package/src/plugins/providers/github-copilot.ts +49 -45
- package/src/plugins/providers/index.ts +10 -12
- package/src/plugins/providers/minimax.ts +50 -44
- package/src/plugins/providers/openai-api.ts +82 -62
- package/src/plugins/providers/opencode-zen.ts +46 -39
- package/src/plugins/providers/perplexity.ts +55 -46
- package/src/plugins/providers/zai.ts +68 -57
- package/src/plugins/registry.ts +80 -71
- package/src/plugins/sandbox-guard.test.ts +45 -48
- package/src/plugins/sandbox-guard.ts +20 -25
- package/src/plugins/sandbox.ts +26 -48
- package/src/plugins/themes/catppuccin-latte.ts +29 -29
- package/src/plugins/themes/catppuccin-mocha.ts +29 -29
- package/src/plugins/themes/claude-code.ts +29 -29
- package/src/plugins/themes/dracula.ts +29 -29
- package/src/plugins/themes/github-light.ts +29 -29
- package/src/plugins/themes/gruvbox-dark.ts +29 -29
- package/src/plugins/themes/gruvbox-light.ts +29 -29
- package/src/plugins/themes/index.ts +15 -15
- package/src/plugins/themes/kanagawa.ts +29 -29
- package/src/plugins/themes/nord.ts +29 -29
- package/src/plugins/themes/one-dark.ts +29 -29
- package/src/plugins/themes/opencode.ts +31 -31
- package/src/plugins/themes/rose-pine-dawn.ts +29 -29
- package/src/plugins/themes/rose-pine.ts +29 -29
- package/src/plugins/themes/solarized-light.ts +29 -29
- package/src/plugins/themes/tokyo-night.ts +29 -29
- package/src/plugins/types/agent.ts +5 -5
- package/src/plugins/types/base.ts +35 -24
- package/src/plugins/types/index.ts +9 -9
- package/src/plugins/types/notification.ts +12 -12
- package/src/plugins/types/provider.ts +12 -8
- package/src/plugins/types/theme.ts +31 -23
- package/src/plugins/update-checker.ts +6 -6
- package/src/pricing/estimator.test.ts +39 -44
- package/src/pricing/estimator.ts +7 -13
- package/src/pricing/fallback.test.ts +30 -34
- package/src/pricing/fallback.ts +54 -27
- package/src/pricing/index.ts +18 -12
- package/src/pricing/models-dev.ts +6 -6
- package/src/storage/database.ts +56 -46
- package/src/storage/db.ts +12 -12
- package/src/storage/index.ts +44 -45
- package/src/storage/migrations/index.ts +2 -2
- package/src/storage/paths.ts +13 -13
- package/src/storage/persistence-service.ts +206 -0
- package/src/storage/repos/agentSessions.ts +33 -23
- package/src/storage/repos/providerSnapshots.ts +5 -5
- package/src/storage/repos/usageEvents.ts +40 -28
- package/src/storage/retention.ts +146 -0
- package/src/storage/types.ts +5 -5
- package/src/tui/App.tsx +180 -137
- package/src/tui/components/CommandPalette.tsx +46 -34
- package/src/tui/components/DebugConsole.tsx +39 -33
- package/src/tui/components/DebugPanel.tsx +314 -183
- package/src/tui/components/FooterHints.tsx +2 -2
- package/src/tui/components/GhostProviderCard.tsx +37 -35
- package/src/tui/components/Header.tsx +68 -35
- package/src/tui/components/HelpOverlay.tsx +99 -29
- package/src/tui/components/InlineGauge.tsx +10 -7
- package/src/tui/components/InlineSparkline.tsx +17 -11
- package/src/tui/components/KpiStrip.tsx +128 -98
- package/src/tui/components/LimitGauge.tsx +96 -59
- package/src/tui/components/ModalBackdrop.tsx +4 -4
- package/src/tui/components/ProviderAggregateStrip.tsx +69 -38
- package/src/tui/components/ProviderCard.tsx +232 -226
- package/src/tui/components/ProviderDetailPanel.tsx +133 -58
- package/src/tui/components/ProviderLimitsPanel.tsx +126 -89
- package/src/tui/components/ProvidersList.tsx +215 -126
- package/src/tui/components/SessionDetailsDrawer.tsx +191 -94
- package/src/tui/components/SessionsTable.tsx +320 -169
- package/src/tui/components/SettingsModal.tsx +593 -269
- package/src/tui/components/SidebarBreakdown.tsx +30 -16
- package/src/tui/components/Skeleton.tsx +24 -17
- package/src/tui/components/SmartSidebar.tsx +360 -258
- package/src/tui/components/Sparkline.tsx +64 -52
- package/src/tui/components/Spinner.tsx +3 -3
- package/src/tui/components/StatusBar.tsx +27 -27
- package/src/tui/components/ThemePicker.tsx +67 -66
- package/src/tui/components/Toast.tsx +9 -6
- package/src/tui/components/UsageGauge.tsx +10 -13
- package/src/tui/components/index.ts +5 -5
- package/src/tui/contexts/AgentSessionContext.tsx +164 -151
- package/src/tui/contexts/ConfigContext.tsx +15 -13
- package/src/tui/contexts/DashboardRuntimeContext.tsx +26 -26
- package/src/tui/contexts/DemoModeContext.tsx +22 -15
- package/src/tui/contexts/DrawerContext.tsx +11 -9
- package/src/tui/contexts/InputContext.tsx +2 -2
- package/src/tui/contexts/LogContext.tsx +62 -47
- package/src/tui/contexts/PluginContext.tsx +238 -183
- package/src/tui/contexts/RealTimeActivityContext.tsx +70 -36
- package/src/tui/contexts/StorageContext.tsx +95 -149
- package/src/tui/contexts/ThemeContext.tsx +21 -16
- package/src/tui/contexts/TimeWindowContext.tsx +72 -61
- package/src/tui/contexts/ToastContext.tsx +10 -7
- package/src/tui/contexts/index.ts +9 -5
- package/src/tui/createApp.tsx +8 -12
- package/src/tui/debug/captureFrame.ts +25 -28
- package/src/tui/debug/snapshot.tsx +179 -162
- package/src/tui/driver/assertions.ts +30 -22
- package/src/tui/driver/cli.ts +231 -221
- package/src/tui/driver/coverage.ts +27 -44
- package/src/tui/driver/demo-snapshot.ts +33 -33
- package/src/tui/driver/diff.ts +26 -32
- package/src/tui/driver/driver.ts +43 -48
- package/src/tui/driver/index.ts +36 -40
- package/src/tui/driver/recorder.ts +37 -48
- package/src/tui/driver/test-workflow.ts +51 -51
- package/src/tui/driver/test.ts +25 -25
- package/src/tui/hooks/index.ts +24 -20
- package/src/tui/hooks/useAnimatedValue.ts +13 -18
- package/src/tui/hooks/useDashboardKeyboard.ts +118 -98
- package/src/tui/hooks/useDashboardState.ts +26 -24
- package/src/tui/hooks/useEmaActivity.ts +82 -74
- package/src/tui/hooks/useEntranceAnimation.ts +11 -11
- package/src/tui/hooks/useExitAnimation.ts +7 -3
- package/src/tui/hooks/usePulse.ts +4 -4
- package/src/tui/hooks/useSafeRenderer.ts +5 -5
- package/src/tui/hooks/useSessionEnrichedProviders.ts +150 -0
- package/src/tui/hooks/useValueFlash.ts +10 -14
- package/src/tui/index.tsx +29 -6
- package/src/tui/shutdown.ts +19 -0
- package/src/tui/utils/providerColor.ts +1 -1
- package/src/tui/views/Dashboard.tsx +164 -102
- package/src/tui/views/HistoricalTrendsView.tsx +579 -250
- package/src/tui/views/ProjectsView.tsx +495 -243
- package/src/tui/views/RealTimeDashboard.tsx +176 -116
- package/src/tui/views/SettingsView.tsx +225 -189
- package/src/tui/views/index.ts +2 -2
- package/src/types/opentui-test-utils.d.ts +7 -7
- package/src/utils/clipboard.ts +29 -29
- package/src/utils/currency.test.ts +53 -53
- package/src/utils/currency.ts +35 -32
- package/src/version.ts +1 -1
|
@@ -1,15 +1,53 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import type { UsageLimit } from "@/plugins/types/provider.ts";
|
|
2
|
+
import type { ProviderState } from "../contexts/PluginContext.tsx";
|
|
3
|
+
import { useColors } from "../contexts/ThemeContext.tsx";
|
|
4
|
+
import { Sparkline } from "./Sparkline.tsx";
|
|
5
|
+
import { UsageGauge } from "./UsageGauge.tsx";
|
|
6
6
|
|
|
7
7
|
function pad(str: string, len: number): string {
|
|
8
|
-
return str.length >= len ? str.slice(0, len) : str +
|
|
8
|
+
return str.length >= len ? str.slice(0, len) : str + " ".repeat(len - str.length);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Single-line compact gauge: "Label ████████···· 67%" */
|
|
12
|
+
function InlineGauge({
|
|
13
|
+
label,
|
|
14
|
+
usedPercent,
|
|
15
|
+
color,
|
|
16
|
+
}: {
|
|
17
|
+
label: string;
|
|
18
|
+
usedPercent: number | null;
|
|
19
|
+
color?: string;
|
|
20
|
+
}) {
|
|
21
|
+
const colors = useColors();
|
|
22
|
+
const providerColor = color ?? colors.primary;
|
|
23
|
+
const percent = usedPercent ?? 0;
|
|
24
|
+
|
|
25
|
+
const labelWidth = 18;
|
|
26
|
+
const barWidth = 15;
|
|
27
|
+
const filledWidth = Math.round((percent / 100) * barWidth);
|
|
28
|
+
const emptyWidth = barWidth - filledWidth;
|
|
29
|
+
|
|
30
|
+
const fillColor =
|
|
31
|
+
percent >= 90 ? colors.gaugeDanger : percent >= 70 ? colors.gaugeWarning : providerColor;
|
|
32
|
+
|
|
33
|
+
const truncLabel = label.length > labelWidth ? label.slice(0, labelWidth - 1) + "…" : label;
|
|
34
|
+
const paddedLabel = pad(truncLabel, labelWidth);
|
|
35
|
+
const filledBar = "█".repeat(filledWidth);
|
|
36
|
+
const emptyBar = "·".repeat(emptyWidth);
|
|
37
|
+
const pctStr = usedPercent !== null ? `${Math.round(percent)}%`.padStart(4) : " --";
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<text height={1}>
|
|
41
|
+
<span fg={colors.textMuted}>{paddedLabel}</span>
|
|
42
|
+
<span fg={fillColor}>{filledBar}</span>
|
|
43
|
+
<span fg={colors.gaugeBackground}>{emptyBar}</span>
|
|
44
|
+
<span fg={colors.text}>{" " + pctStr}</span>
|
|
45
|
+
</text>
|
|
46
|
+
);
|
|
9
47
|
}
|
|
10
48
|
|
|
11
49
|
function padStart(str: string, len: number): string {
|
|
12
|
-
return str.length >= len ? str.slice(0, len) :
|
|
50
|
+
return str.length >= len ? str.slice(0, len) : " ".repeat(len - str.length) + str;
|
|
13
51
|
}
|
|
14
52
|
|
|
15
53
|
function formatTokenCount(val: number): string {
|
|
@@ -26,9 +64,9 @@ function formatCost(val: number): string {
|
|
|
26
64
|
|
|
27
65
|
function formatTimestamp(ts: number): string {
|
|
28
66
|
const d = new Date(ts);
|
|
29
|
-
const h = d.getHours().toString().padStart(2,
|
|
30
|
-
const m = d.getMinutes().toString().padStart(2,
|
|
31
|
-
const s = d.getSeconds().toString().padStart(2,
|
|
67
|
+
const h = d.getHours().toString().padStart(2, "0");
|
|
68
|
+
const m = d.getMinutes().toString().padStart(2, "0");
|
|
69
|
+
const s = d.getSeconds().toString().padStart(2, "0");
|
|
32
70
|
return `${h}:${m}:${s}`;
|
|
33
71
|
}
|
|
34
72
|
|
|
@@ -61,19 +99,23 @@ export function ProviderDetailPanel({ provider }: ProviderDetailPanelProps) {
|
|
|
61
99
|
);
|
|
62
100
|
}
|
|
63
101
|
|
|
64
|
-
const
|
|
102
|
+
const rawLimits: UsageLimit[] = [];
|
|
65
103
|
if (usage.limits?.items && usage.limits.items.length > 0) {
|
|
66
|
-
|
|
104
|
+
rawLimits.push(...usage.limits.items);
|
|
67
105
|
} else {
|
|
68
|
-
if (usage.limits?.primary)
|
|
69
|
-
if (usage.limits?.secondary)
|
|
106
|
+
if (usage.limits?.primary) rawLimits.push(usage.limits.primary);
|
|
107
|
+
if (usage.limits?.secondary) rawLimits.push(usage.limits.secondary);
|
|
70
108
|
}
|
|
109
|
+
const sortedLimits = [...rawLimits].sort((a, b) => (b.usedPercent ?? 0) - (a.usedPercent ?? 0));
|
|
110
|
+
const compactMode = sortedLimits.length > 3;
|
|
111
|
+
const maxVisibleLimits = 5;
|
|
112
|
+
const allLimits = sortedLimits.slice(0, maxVisibleLimits);
|
|
113
|
+
const hiddenLimitCount = sortedLimits.length - allLimits.length;
|
|
71
114
|
|
|
72
|
-
const historyValues = provider.history.map(s => s.usedPercent ?? 0);
|
|
115
|
+
const historyValues = provider.history.map((s) => s.usedPercent ?? 0);
|
|
73
116
|
const peak = historyValues.length > 0 ? Math.max(...historyValues) : 0;
|
|
74
|
-
const avg =
|
|
75
|
-
? historyValues.reduce((a, b) => a + b, 0) / historyValues.length
|
|
76
|
-
: 0;
|
|
117
|
+
const avg =
|
|
118
|
+
historyValues.length > 0 ? historyValues.reduce((a, b) => a + b, 0) / historyValues.length : 0;
|
|
77
119
|
|
|
78
120
|
const tokens = usage.tokens;
|
|
79
121
|
const cost = usage.cost;
|
|
@@ -93,61 +135,82 @@ export function ProviderDetailPanel({ provider }: ProviderDetailPanelProps) {
|
|
|
93
135
|
<box flexDirection="row" justifyContent="space-between" height={1}>
|
|
94
136
|
<text fg={providerColor} height={1}>
|
|
95
137
|
<strong>{provider.plugin.name}</strong>
|
|
96
|
-
{usage.planType ? ` · ${usage.planType}` :
|
|
138
|
+
{usage.planType ? ` · ${usage.planType}` : ""}
|
|
97
139
|
</text>
|
|
98
140
|
<text fg={colors.textMuted} height={1}>
|
|
99
141
|
{`Last: ${formatTimestamp(lastRefreshed)}`}
|
|
100
142
|
</text>
|
|
101
143
|
</box>
|
|
102
144
|
|
|
103
|
-
<box flexDirection="row" gap={2} paddingTop={1}>
|
|
104
|
-
<box flexDirection="column" flexGrow={1} gap={1}>
|
|
145
|
+
<box flexDirection="row" gap={2} paddingTop={compactMode ? 0 : 1}>
|
|
146
|
+
<box flexDirection="column" flexGrow={1} gap={compactMode ? 0 : 1}>
|
|
105
147
|
{allLimits.length > 0 && (
|
|
106
|
-
<box flexDirection="column" gap={1}>
|
|
107
|
-
{
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
label.toLowerCase().includes('day');
|
|
113
|
-
return (
|
|
114
|
-
<box key={idx} flexDirection="column">
|
|
115
|
-
<UsageGauge
|
|
116
|
-
label={label}
|
|
148
|
+
<box flexDirection="column" gap={compactMode ? 0 : 1}>
|
|
149
|
+
{compactMode
|
|
150
|
+
? allLimits.map((limit, idx) => (
|
|
151
|
+
<InlineGauge
|
|
152
|
+
key={idx}
|
|
153
|
+
label={limit.label ?? "Usage"}
|
|
117
154
|
usedPercent={limit.usedPercent}
|
|
118
155
|
color={providerColor}
|
|
119
|
-
width={40}
|
|
120
|
-
{...(windowStr && !labelHasWindow ? { windowLabel: windowStr } : {})}
|
|
121
|
-
{...(limit.resetsAt ? { resetsAt: limit.resetsAt } : {})}
|
|
122
156
|
/>
|
|
123
|
-
|
|
124
|
-
)
|
|
125
|
-
|
|
157
|
+
))
|
|
158
|
+
: allLimits.map((limit, idx) => {
|
|
159
|
+
const label = limit.label ?? "Usage";
|
|
160
|
+
const windowStr = limit.windowMinutes
|
|
161
|
+
? formatWindow(limit.windowMinutes)
|
|
162
|
+
: undefined;
|
|
163
|
+
const labelHasWindow =
|
|
164
|
+
label.toLowerCase().includes("window") ||
|
|
165
|
+
label.toLowerCase().includes("hour") ||
|
|
166
|
+
label.toLowerCase().includes("day");
|
|
167
|
+
return (
|
|
168
|
+
<box key={idx} flexDirection="column">
|
|
169
|
+
<UsageGauge
|
|
170
|
+
label={label}
|
|
171
|
+
usedPercent={limit.usedPercent}
|
|
172
|
+
color={providerColor}
|
|
173
|
+
width={40}
|
|
174
|
+
{...(windowStr && !labelHasWindow ? { windowLabel: windowStr } : {})}
|
|
175
|
+
{...(limit.resetsAt ? { resetsAt: limit.resetsAt } : {})}
|
|
176
|
+
/>
|
|
177
|
+
</box>
|
|
178
|
+
);
|
|
179
|
+
})}
|
|
180
|
+
{hiddenLimitCount > 0 && (
|
|
181
|
+
<text fg={colors.textSubtle} height={1}>
|
|
182
|
+
+{hiddenLimitCount} more limit{hiddenLimitCount > 1 ? "s" : ""}
|
|
183
|
+
</text>
|
|
184
|
+
)}
|
|
126
185
|
</box>
|
|
127
186
|
)}
|
|
128
187
|
|
|
129
188
|
{tokens && (
|
|
130
189
|
<box flexDirection="column">
|
|
131
|
-
<text fg={colors.textMuted} height={1}>
|
|
190
|
+
<text fg={colors.textMuted} height={1}>
|
|
191
|
+
TOKEN BREAKDOWN
|
|
192
|
+
</text>
|
|
132
193
|
<box flexDirection="column">
|
|
133
194
|
<text height={1}>
|
|
134
|
-
<span fg={colors.textMuted}>{pad(
|
|
195
|
+
<span fg={colors.textMuted}>{pad("Input:", 14)}</span>
|
|
135
196
|
<span fg={colors.text}>{padStart(formatTokenCount(tokens.input), 10)}</span>
|
|
136
197
|
</text>
|
|
137
198
|
<text height={1}>
|
|
138
|
-
<span fg={colors.textMuted}>{pad(
|
|
199
|
+
<span fg={colors.textMuted}>{pad("Output:", 14)}</span>
|
|
139
200
|
<span fg={colors.text}>{padStart(formatTokenCount(tokens.output), 10)}</span>
|
|
140
201
|
</text>
|
|
141
202
|
{tokens.cacheRead !== undefined && tokens.cacheRead > 0 && (
|
|
142
203
|
<text height={1}>
|
|
143
|
-
<span fg={colors.textMuted}>{pad(
|
|
204
|
+
<span fg={colors.textMuted}>{pad("Cache Read:", 14)}</span>
|
|
144
205
|
<span fg={colors.text}>{padStart(formatTokenCount(tokens.cacheRead), 10)}</span>
|
|
145
206
|
</text>
|
|
146
207
|
)}
|
|
147
208
|
{tokens.cacheWrite !== undefined && tokens.cacheWrite > 0 && (
|
|
148
209
|
<text height={1}>
|
|
149
|
-
<span fg={colors.textMuted}>{pad(
|
|
150
|
-
<span fg={colors.text}>
|
|
210
|
+
<span fg={colors.textMuted}>{pad("Cache Write:", 14)}</span>
|
|
211
|
+
<span fg={colors.text}>
|
|
212
|
+
{padStart(formatTokenCount(tokens.cacheWrite), 10)}
|
|
213
|
+
</span>
|
|
151
214
|
</text>
|
|
152
215
|
)}
|
|
153
216
|
</box>
|
|
@@ -158,22 +221,24 @@ export function ProviderDetailPanel({ provider }: ProviderDetailPanelProps) {
|
|
|
158
221
|
<box flexDirection="column" flexGrow={1} gap={1}>
|
|
159
222
|
{cost && (
|
|
160
223
|
<box flexDirection="column">
|
|
161
|
-
<text fg={colors.textMuted} height={1}>
|
|
224
|
+
<text fg={colors.textMuted} height={1}>
|
|
225
|
+
COST BREAKDOWN
|
|
226
|
+
</text>
|
|
162
227
|
{cost.actual && (
|
|
163
228
|
<box flexDirection="column">
|
|
164
229
|
<text height={1}>
|
|
165
|
-
<span fg={colors.textMuted}>{pad(
|
|
230
|
+
<span fg={colors.textMuted}>{pad("Total:", 14)}</span>
|
|
166
231
|
<span fg={colors.success}>{padStart(formatCost(cost.actual.total), 10)}</span>
|
|
167
232
|
</text>
|
|
168
233
|
{cost.actual.input !== undefined && (
|
|
169
234
|
<text height={1}>
|
|
170
|
-
<span fg={colors.textMuted}>{pad(
|
|
235
|
+
<span fg={colors.textMuted}>{pad("Input:", 14)}</span>
|
|
171
236
|
<span fg={colors.text}>{padStart(formatCost(cost.actual.input), 10)}</span>
|
|
172
237
|
</text>
|
|
173
238
|
)}
|
|
174
239
|
{cost.actual.output !== undefined && (
|
|
175
240
|
<text height={1}>
|
|
176
|
-
<span fg={colors.textMuted}>{pad(
|
|
241
|
+
<span fg={colors.textMuted}>{pad("Output:", 14)}</span>
|
|
177
242
|
<span fg={colors.text}>{padStart(formatCost(cost.actual.output), 10)}</span>
|
|
178
243
|
</text>
|
|
179
244
|
)}
|
|
@@ -182,19 +247,25 @@ export function ProviderDetailPanel({ provider }: ProviderDetailPanelProps) {
|
|
|
182
247
|
{!cost.actual && cost.estimated && (
|
|
183
248
|
<box flexDirection="column">
|
|
184
249
|
<text height={1}>
|
|
185
|
-
<span fg={colors.textMuted}>{pad(
|
|
186
|
-
<span fg={colors.textMuted}>
|
|
250
|
+
<span fg={colors.textMuted}>{pad("Total:", 14)}</span>
|
|
251
|
+
<span fg={colors.textMuted}>
|
|
252
|
+
{padStart(`~${formatCost(cost.estimated.total)}`, 10)}
|
|
253
|
+
</span>
|
|
187
254
|
</text>
|
|
188
255
|
{cost.estimated.input !== undefined && (
|
|
189
256
|
<text height={1}>
|
|
190
|
-
<span fg={colors.textMuted}>{pad(
|
|
191
|
-
<span fg={colors.textMuted}>
|
|
257
|
+
<span fg={colors.textMuted}>{pad("Input:", 14)}</span>
|
|
258
|
+
<span fg={colors.textMuted}>
|
|
259
|
+
{padStart(`~${formatCost(cost.estimated.input)}`, 10)}
|
|
260
|
+
</span>
|
|
192
261
|
</text>
|
|
193
262
|
)}
|
|
194
263
|
{cost.estimated.output !== undefined && (
|
|
195
264
|
<text height={1}>
|
|
196
|
-
<span fg={colors.textMuted}>{pad(
|
|
197
|
-
<span fg={colors.textMuted}>
|
|
265
|
+
<span fg={colors.textMuted}>{pad("Output:", 14)}</span>
|
|
266
|
+
<span fg={colors.textMuted}>
|
|
267
|
+
{padStart(`~${formatCost(cost.estimated.output)}`, 10)}
|
|
268
|
+
</span>
|
|
198
269
|
</text>
|
|
199
270
|
)}
|
|
200
271
|
</box>
|
|
@@ -204,19 +275,23 @@ export function ProviderDetailPanel({ provider }: ProviderDetailPanelProps) {
|
|
|
204
275
|
|
|
205
276
|
{credits && (
|
|
206
277
|
<box flexDirection="row" gap={1} height={1}>
|
|
207
|
-
<text fg={colors.textMuted} height={1}>
|
|
278
|
+
<text fg={colors.textMuted} height={1}>
|
|
279
|
+
Credits:
|
|
280
|
+
</text>
|
|
208
281
|
<text fg={credits.unlimited ? colors.success : colors.text} height={1}>
|
|
209
|
-
{credits.unlimited ?
|
|
282
|
+
{credits.unlimited ? "Unlimited" : (credits.balance ?? "—")}
|
|
210
283
|
</text>
|
|
211
284
|
</box>
|
|
212
285
|
)}
|
|
213
286
|
</box>
|
|
214
287
|
</box>
|
|
215
288
|
|
|
216
|
-
{historyValues.length >= 2 && (
|
|
289
|
+
{!compactMode && historyValues.length >= 2 && (
|
|
217
290
|
<box flexDirection="column" paddingTop={1}>
|
|
218
291
|
<box flexDirection="row" justifyContent="space-between" height={1}>
|
|
219
|
-
<text fg={colors.textMuted} height={1}>
|
|
292
|
+
<text fg={colors.textMuted} height={1}>
|
|
293
|
+
USAGE TREND
|
|
294
|
+
</text>
|
|
220
295
|
<text fg={colors.textSubtle} height={1}>
|
|
221
296
|
{`peak:${Math.round(peak)}% avg:${Math.round(avg)}%`}
|
|
222
297
|
</text>
|