@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.
Files changed (160) hide show
  1. package/README.md +2 -5
  2. package/package.json +8 -5
  3. package/src/agents/aggregator.ts +39 -19
  4. package/src/agents/costing.ts +11 -9
  5. package/src/agents/index.ts +7 -9
  6. package/src/agents/types.ts +2 -2
  7. package/src/cli.ts +28 -23
  8. package/src/config/schema.test.ts +42 -40
  9. package/src/config/schema.ts +26 -26
  10. package/src/demo/simulator.ts +161 -122
  11. package/src/plugins/agents/index.ts +2 -2
  12. package/src/plugins/auth-sources.ts +42 -38
  13. package/src/plugins/lifecycle.ts +42 -38
  14. package/src/plugins/loader.test.ts +49 -49
  15. package/src/plugins/loader.ts +67 -63
  16. package/src/plugins/notification-bus.ts +21 -16
  17. package/src/plugins/notifications/index.ts +2 -2
  18. package/src/plugins/notifications/terminal-bell.ts +36 -23
  19. package/src/plugins/notifications/visual-flash.ts +31 -19
  20. package/src/plugins/npm-installer.ts +23 -25
  21. package/src/plugins/plugin-context-factory.ts +10 -10
  22. package/src/plugins/plugin-host.ts +12 -5
  23. package/src/plugins/providers/anthropic.ts +64 -57
  24. package/src/plugins/providers/antigravity.ts +81 -69
  25. package/src/plugins/providers/codex.ts +42 -42
  26. package/src/plugins/providers/gemini.ts +106 -87
  27. package/src/plugins/providers/github-copilot.ts +49 -45
  28. package/src/plugins/providers/index.ts +10 -12
  29. package/src/plugins/providers/minimax.ts +50 -44
  30. package/src/plugins/providers/openai-api.ts +82 -62
  31. package/src/plugins/providers/opencode-zen.ts +46 -39
  32. package/src/plugins/providers/perplexity.ts +55 -46
  33. package/src/plugins/providers/zai.ts +68 -57
  34. package/src/plugins/registry.ts +80 -71
  35. package/src/plugins/sandbox-guard.test.ts +45 -48
  36. package/src/plugins/sandbox-guard.ts +20 -25
  37. package/src/plugins/sandbox.ts +26 -48
  38. package/src/plugins/themes/catppuccin-latte.ts +29 -29
  39. package/src/plugins/themes/catppuccin-mocha.ts +29 -29
  40. package/src/plugins/themes/claude-code.ts +29 -29
  41. package/src/plugins/themes/dracula.ts +29 -29
  42. package/src/plugins/themes/github-light.ts +29 -29
  43. package/src/plugins/themes/gruvbox-dark.ts +29 -29
  44. package/src/plugins/themes/gruvbox-light.ts +29 -29
  45. package/src/plugins/themes/index.ts +15 -15
  46. package/src/plugins/themes/kanagawa.ts +29 -29
  47. package/src/plugins/themes/nord.ts +29 -29
  48. package/src/plugins/themes/one-dark.ts +29 -29
  49. package/src/plugins/themes/opencode.ts +31 -31
  50. package/src/plugins/themes/rose-pine-dawn.ts +29 -29
  51. package/src/plugins/themes/rose-pine.ts +29 -29
  52. package/src/plugins/themes/solarized-light.ts +29 -29
  53. package/src/plugins/themes/tokyo-night.ts +29 -29
  54. package/src/plugins/types/agent.ts +5 -5
  55. package/src/plugins/types/base.ts +35 -24
  56. package/src/plugins/types/index.ts +9 -9
  57. package/src/plugins/types/notification.ts +12 -12
  58. package/src/plugins/types/provider.ts +12 -8
  59. package/src/plugins/types/theme.ts +31 -23
  60. package/src/plugins/update-checker.ts +6 -6
  61. package/src/pricing/estimator.test.ts +39 -44
  62. package/src/pricing/estimator.ts +7 -13
  63. package/src/pricing/fallback.test.ts +30 -34
  64. package/src/pricing/fallback.ts +54 -27
  65. package/src/pricing/index.ts +18 -12
  66. package/src/pricing/models-dev.ts +6 -6
  67. package/src/storage/database.ts +56 -46
  68. package/src/storage/db.ts +12 -12
  69. package/src/storage/index.ts +44 -45
  70. package/src/storage/migrations/index.ts +2 -2
  71. package/src/storage/paths.ts +13 -13
  72. package/src/storage/persistence-service.ts +206 -0
  73. package/src/storage/repos/agentSessions.ts +33 -23
  74. package/src/storage/repos/providerSnapshots.ts +5 -5
  75. package/src/storage/repos/usageEvents.ts +40 -28
  76. package/src/storage/retention.ts +146 -0
  77. package/src/storage/types.ts +5 -5
  78. package/src/tui/App.tsx +180 -137
  79. package/src/tui/components/CommandPalette.tsx +46 -34
  80. package/src/tui/components/DebugConsole.tsx +39 -33
  81. package/src/tui/components/DebugPanel.tsx +314 -183
  82. package/src/tui/components/FooterHints.tsx +2 -2
  83. package/src/tui/components/GhostProviderCard.tsx +37 -35
  84. package/src/tui/components/Header.tsx +68 -35
  85. package/src/tui/components/HelpOverlay.tsx +99 -29
  86. package/src/tui/components/InlineGauge.tsx +10 -7
  87. package/src/tui/components/InlineSparkline.tsx +17 -11
  88. package/src/tui/components/KpiStrip.tsx +128 -98
  89. package/src/tui/components/LimitGauge.tsx +96 -59
  90. package/src/tui/components/ModalBackdrop.tsx +4 -4
  91. package/src/tui/components/ProviderAggregateStrip.tsx +69 -38
  92. package/src/tui/components/ProviderCard.tsx +232 -226
  93. package/src/tui/components/ProviderDetailPanel.tsx +133 -58
  94. package/src/tui/components/ProviderLimitsPanel.tsx +126 -89
  95. package/src/tui/components/ProvidersList.tsx +215 -126
  96. package/src/tui/components/SessionDetailsDrawer.tsx +191 -94
  97. package/src/tui/components/SessionsTable.tsx +320 -169
  98. package/src/tui/components/SettingsModal.tsx +593 -269
  99. package/src/tui/components/SidebarBreakdown.tsx +30 -16
  100. package/src/tui/components/Skeleton.tsx +24 -17
  101. package/src/tui/components/SmartSidebar.tsx +360 -258
  102. package/src/tui/components/Sparkline.tsx +64 -52
  103. package/src/tui/components/Spinner.tsx +3 -3
  104. package/src/tui/components/StatusBar.tsx +27 -27
  105. package/src/tui/components/ThemePicker.tsx +67 -66
  106. package/src/tui/components/Toast.tsx +9 -6
  107. package/src/tui/components/UsageGauge.tsx +10 -13
  108. package/src/tui/components/index.ts +5 -5
  109. package/src/tui/contexts/AgentSessionContext.tsx +164 -151
  110. package/src/tui/contexts/ConfigContext.tsx +15 -13
  111. package/src/tui/contexts/DashboardRuntimeContext.tsx +26 -26
  112. package/src/tui/contexts/DemoModeContext.tsx +22 -15
  113. package/src/tui/contexts/DrawerContext.tsx +11 -9
  114. package/src/tui/contexts/InputContext.tsx +2 -2
  115. package/src/tui/contexts/LogContext.tsx +62 -47
  116. package/src/tui/contexts/PluginContext.tsx +238 -183
  117. package/src/tui/contexts/RealTimeActivityContext.tsx +70 -36
  118. package/src/tui/contexts/StorageContext.tsx +95 -149
  119. package/src/tui/contexts/ThemeContext.tsx +21 -16
  120. package/src/tui/contexts/TimeWindowContext.tsx +72 -61
  121. package/src/tui/contexts/ToastContext.tsx +10 -7
  122. package/src/tui/contexts/index.ts +9 -5
  123. package/src/tui/createApp.tsx +8 -12
  124. package/src/tui/debug/captureFrame.ts +25 -28
  125. package/src/tui/debug/snapshot.tsx +179 -162
  126. package/src/tui/driver/assertions.ts +30 -22
  127. package/src/tui/driver/cli.ts +231 -221
  128. package/src/tui/driver/coverage.ts +27 -44
  129. package/src/tui/driver/demo-snapshot.ts +33 -33
  130. package/src/tui/driver/diff.ts +26 -32
  131. package/src/tui/driver/driver.ts +43 -48
  132. package/src/tui/driver/index.ts +36 -40
  133. package/src/tui/driver/recorder.ts +37 -48
  134. package/src/tui/driver/test-workflow.ts +51 -51
  135. package/src/tui/driver/test.ts +25 -25
  136. package/src/tui/hooks/index.ts +24 -20
  137. package/src/tui/hooks/useAnimatedValue.ts +13 -18
  138. package/src/tui/hooks/useDashboardKeyboard.ts +118 -98
  139. package/src/tui/hooks/useDashboardState.ts +26 -24
  140. package/src/tui/hooks/useEmaActivity.ts +82 -74
  141. package/src/tui/hooks/useEntranceAnimation.ts +11 -11
  142. package/src/tui/hooks/useExitAnimation.ts +7 -3
  143. package/src/tui/hooks/usePulse.ts +4 -4
  144. package/src/tui/hooks/useSafeRenderer.ts +5 -5
  145. package/src/tui/hooks/useSessionEnrichedProviders.ts +150 -0
  146. package/src/tui/hooks/useValueFlash.ts +10 -14
  147. package/src/tui/index.tsx +29 -6
  148. package/src/tui/shutdown.ts +19 -0
  149. package/src/tui/utils/providerColor.ts +1 -1
  150. package/src/tui/views/Dashboard.tsx +164 -102
  151. package/src/tui/views/HistoricalTrendsView.tsx +579 -250
  152. package/src/tui/views/ProjectsView.tsx +495 -243
  153. package/src/tui/views/RealTimeDashboard.tsx +176 -116
  154. package/src/tui/views/SettingsView.tsx +225 -189
  155. package/src/tui/views/index.ts +2 -2
  156. package/src/types/opentui-test-utils.d.ts +7 -7
  157. package/src/utils/clipboard.ts +29 -29
  158. package/src/utils/currency.test.ts +53 -53
  159. package/src/utils/currency.ts +35 -32
  160. package/src/version.ts +1 -1
@@ -1,15 +1,53 @@
1
- import { useColors } from '../contexts/ThemeContext.tsx';
2
- import { UsageGauge } from './UsageGauge.tsx';
3
- import { Sparkline } from './Sparkline.tsx';
4
- import type { ProviderState } from '../contexts/PluginContext.tsx';
5
- import type { UsageLimit } from '@/plugins/types/provider.ts';
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 + ' '.repeat(len - str.length);
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) : ' '.repeat(len - str.length) + str;
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, '0');
30
- const m = d.getMinutes().toString().padStart(2, '0');
31
- const s = d.getSeconds().toString().padStart(2, '0');
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 allLimits: UsageLimit[] = [];
102
+ const rawLimits: UsageLimit[] = [];
65
103
  if (usage.limits?.items && usage.limits.items.length > 0) {
66
- allLimits.push(...usage.limits.items);
104
+ rawLimits.push(...usage.limits.items);
67
105
  } else {
68
- if (usage.limits?.primary) allLimits.push(usage.limits.primary);
69
- if (usage.limits?.secondary) allLimits.push(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 = historyValues.length > 0
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
- {allLimits.map((limit, idx) => {
108
- const label = limit.label ?? 'Usage';
109
- const windowStr = limit.windowMinutes ? formatWindow(limit.windowMinutes) : undefined;
110
- const labelHasWindow = label.toLowerCase().includes('window') ||
111
- label.toLowerCase().includes('hour') ||
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
- </box>
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}>TOKEN BREAKDOWN</text>
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('Input:', 14)}</span>
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('Output:', 14)}</span>
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('Cache Read:', 14)}</span>
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('Cache Write:', 14)}</span>
150
- <span fg={colors.text}>{padStart(formatTokenCount(tokens.cacheWrite), 10)}</span>
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}>COST BREAKDOWN</text>
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('Total:', 14)}</span>
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('Input:', 14)}</span>
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('Output:', 14)}</span>
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('Total:', 14)}</span>
186
- <span fg={colors.textMuted}>{padStart(`~${formatCost(cost.estimated.total)}`, 10)}</span>
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('Input:', 14)}</span>
191
- <span fg={colors.textMuted}>{padStart(`~${formatCost(cost.estimated.input)}`, 10)}</span>
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('Output:', 14)}</span>
197
- <span fg={colors.textMuted}>{padStart(`~${formatCost(cost.estimated.output)}`, 10)}</span>
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}>Credits:</text>
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 ? 'Unlimited' : credits.balance ?? '—'}
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}>USAGE TREND</text>
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>