@tokentop/ttop 0.2.2 → 0.3.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 +32 -32
- 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 +29 -23
- package/src/plugins/notifications/visual-flash.ts +21 -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 +66 -57
- package/src/plugins/registry.ts +47 -43
- 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/repos/agentSessions.ts +33 -23
- package/src/storage/repos/providerSnapshots.ts +5 -5
- package/src/storage/repos/usageEvents.ts +40 -28
- 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 +295 -177
- 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 +313 -166
- package/src/tui/components/SettingsModal.tsx +231 -214
- 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 +193 -144
- 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 +232 -183
- package/src/tui/contexts/RealTimeActivityContext.tsx +70 -36
- package/src/tui/contexts/StorageContext.tsx +151 -117
- 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 +3 -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 +127 -102
- package/src/tui/views/HistoricalTrendsView.tsx +579 -250
- package/src/tui/views/ProjectsView.tsx +466 -237
- package/src/tui/views/RealTimeDashboard.tsx +150 -111
- package/src/tui/views/SettingsView.tsx +222 -191
- 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,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
+
|
|
2
3
|
/**
|
|
3
4
|
* Headless Snapshot Script for Component Isolation Testing
|
|
4
|
-
*
|
|
5
|
+
*
|
|
5
6
|
* Renders components in a headless environment and captures the output.
|
|
6
7
|
* Useful for debugging layout issues without running the full app.
|
|
7
|
-
*
|
|
8
|
+
*
|
|
8
9
|
* Usage:
|
|
9
10
|
* bun src/tui/debug/snapshot.tsx [component] [options]
|
|
10
|
-
*
|
|
11
|
+
*
|
|
11
12
|
* Examples:
|
|
12
13
|
* bun src/tui/debug/snapshot.tsx --list # List all available components
|
|
13
14
|
* bun src/tui/debug/snapshot.tsx header # Snapshot Header
|
|
@@ -15,49 +16,48 @@
|
|
|
15
16
|
* bun src/tui/debug/snapshot.tsx kpi-strip # Snapshot KpiStrip
|
|
16
17
|
* bun src/tui/debug/snapshot.tsx --width 120 --height 40 # Custom dimensions
|
|
17
18
|
* bun src/tui/debug/snapshot.tsx toast --output frame.txt # Custom output file
|
|
18
|
-
*
|
|
19
|
+
*
|
|
19
20
|
* Adding New Components:
|
|
20
21
|
* 1. Create a mock data factory function: createMock<ComponentName>Props()
|
|
21
22
|
* 2. Register it in COMPONENT_REGISTRY with render function
|
|
22
23
|
* 3. That's it! The component will be available via CLI
|
|
23
24
|
*/
|
|
24
25
|
|
|
25
|
-
import
|
|
26
|
-
import * as
|
|
27
|
-
import
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
45
|
-
import {
|
|
46
|
-
import {
|
|
47
|
-
import { TimeWindowProvider } from
|
|
48
|
-
import {
|
|
49
|
-
import {
|
|
50
|
-
import {
|
|
51
|
-
import {
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
54
|
-
import { createDriver } from '../driver/driver.ts';
|
|
26
|
+
import { testRender } from "@opentui/react/test-utils";
|
|
27
|
+
import * as fs from "fs/promises";
|
|
28
|
+
import * as path from "path";
|
|
29
|
+
import type { ReactNode } from "react";
|
|
30
|
+
import { DEFAULT_CONFIG } from "@/config/schema.ts";
|
|
31
|
+
import { DebugConsole } from "../components/DebugConsole.tsx";
|
|
32
|
+
import { Header } from "../components/Header.tsx";
|
|
33
|
+
import { KpiStrip } from "../components/KpiStrip.tsx";
|
|
34
|
+
import { ProviderCard } from "../components/ProviderCard.tsx";
|
|
35
|
+
import { SessionDetailsDrawer } from "../components/SessionDetailsDrawer.tsx";
|
|
36
|
+
import { SkeletonGauge, SkeletonProviderContent, SkeletonText } from "../components/Skeleton.tsx";
|
|
37
|
+
import { Spinner } from "../components/Spinner.tsx";
|
|
38
|
+
import { StatusBar } from "../components/StatusBar.tsx";
|
|
39
|
+
import { Toast } from "../components/Toast.tsx";
|
|
40
|
+
import { UsageGauge } from "../components/UsageGauge.tsx";
|
|
41
|
+
import { AgentSessionProvider } from "../contexts/AgentSessionContext.tsx";
|
|
42
|
+
import { ConfigProvider } from "../contexts/ConfigContext.tsx";
|
|
43
|
+
import { InputProvider } from "../contexts/InputContext.tsx";
|
|
44
|
+
import { LogProvider } from "../contexts/LogContext.tsx";
|
|
45
|
+
import { PluginProvider } from "../contexts/PluginContext.tsx";
|
|
46
|
+
import { StorageProvider } from "../contexts/StorageContext.tsx";
|
|
47
|
+
import { ThemeProvider } from "../contexts/ThemeContext.tsx";
|
|
48
|
+
import { TimeWindowProvider } from "../contexts/TimeWindowContext.tsx";
|
|
49
|
+
import { ToastProvider } from "../contexts/ToastContext.tsx";
|
|
50
|
+
import { createDriver } from "../driver/driver.ts";
|
|
51
|
+
import { HistoricalTrendsView } from "../views/HistoricalTrendsView.tsx";
|
|
52
|
+
import { ProjectsView } from "../views/ProjectsView.tsx";
|
|
53
|
+
import { SettingsView } from "../views/SettingsView.tsx";
|
|
54
|
+
import { getFramesDir } from "./captureFrame.ts";
|
|
55
55
|
|
|
56
56
|
function createMockHeaderProps() {
|
|
57
57
|
return {
|
|
58
|
-
title:
|
|
59
|
-
subtitle:
|
|
60
|
-
activeView:
|
|
58
|
+
title: "tokentop",
|
|
59
|
+
subtitle: "v0.1.0",
|
|
60
|
+
activeView: "dashboard" as const,
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -66,38 +66,38 @@ function createMockStatusBarProps() {
|
|
|
66
66
|
return {
|
|
67
67
|
lastRefresh: now - 30000,
|
|
68
68
|
nextRefresh: now + 30000,
|
|
69
|
-
message:
|
|
69
|
+
message: "tokentop - htop for AI usage",
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
function createMockProviderCardProps() {
|
|
74
74
|
const now = Date.now();
|
|
75
75
|
return {
|
|
76
|
-
name:
|
|
76
|
+
name: "Anthropic",
|
|
77
77
|
configured: true,
|
|
78
78
|
loading: false,
|
|
79
|
-
color:
|
|
79
|
+
color: "#D97706",
|
|
80
80
|
focused: false,
|
|
81
81
|
usage: {
|
|
82
|
-
planType:
|
|
82
|
+
planType: "Claude Pro",
|
|
83
83
|
limitReached: false,
|
|
84
84
|
limits: {
|
|
85
85
|
primary: {
|
|
86
86
|
usedPercent: 65,
|
|
87
|
-
label:
|
|
87
|
+
label: "Daily Messages",
|
|
88
88
|
windowMinutes: 1440,
|
|
89
89
|
resetsAt: now + 3600000,
|
|
90
90
|
},
|
|
91
91
|
secondary: {
|
|
92
92
|
usedPercent: 23,
|
|
93
|
-
label:
|
|
93
|
+
label: "Weekly Tokens",
|
|
94
94
|
windowMinutes: 10080,
|
|
95
95
|
},
|
|
96
96
|
},
|
|
97
97
|
credits: {
|
|
98
98
|
hasCredits: true,
|
|
99
99
|
unlimited: false,
|
|
100
|
-
balance:
|
|
100
|
+
balance: "$42.50",
|
|
101
101
|
},
|
|
102
102
|
fetchedAt: now,
|
|
103
103
|
},
|
|
@@ -106,10 +106,10 @@ function createMockProviderCardProps() {
|
|
|
106
106
|
|
|
107
107
|
function createMockProviderCardLoadingProps() {
|
|
108
108
|
return {
|
|
109
|
-
name:
|
|
109
|
+
name: "OpenAI",
|
|
110
110
|
configured: true,
|
|
111
111
|
loading: true,
|
|
112
|
-
color:
|
|
112
|
+
color: "#10A37F",
|
|
113
113
|
focused: false,
|
|
114
114
|
usage: null,
|
|
115
115
|
};
|
|
@@ -117,10 +117,10 @@ function createMockProviderCardLoadingProps() {
|
|
|
117
117
|
|
|
118
118
|
function createMockProviderCardUnconfiguredProps() {
|
|
119
119
|
return {
|
|
120
|
-
name:
|
|
120
|
+
name: "Google",
|
|
121
121
|
configured: false,
|
|
122
122
|
loading: false,
|
|
123
|
-
color:
|
|
123
|
+
color: "#4285F4",
|
|
124
124
|
focused: false,
|
|
125
125
|
usage: null,
|
|
126
126
|
};
|
|
@@ -129,13 +129,13 @@ function createMockProviderCardUnconfiguredProps() {
|
|
|
129
129
|
function createMockProviderCardErrorProps() {
|
|
130
130
|
const now = Date.now();
|
|
131
131
|
return {
|
|
132
|
-
name:
|
|
132
|
+
name: "Mistral",
|
|
133
133
|
configured: true,
|
|
134
134
|
loading: false,
|
|
135
|
-
color:
|
|
135
|
+
color: "#FF7000",
|
|
136
136
|
focused: false,
|
|
137
137
|
usage: {
|
|
138
|
-
error:
|
|
138
|
+
error: "API rate limit exceeded",
|
|
139
139
|
fetchedAt: now,
|
|
140
140
|
},
|
|
141
141
|
};
|
|
@@ -144,19 +144,19 @@ function createMockProviderCardErrorProps() {
|
|
|
144
144
|
function createMockUsageGaugeProps() {
|
|
145
145
|
const now = Date.now();
|
|
146
146
|
return {
|
|
147
|
-
label:
|
|
147
|
+
label: "Daily Tokens",
|
|
148
148
|
usedPercent: 73,
|
|
149
|
-
windowLabel:
|
|
149
|
+
windowLabel: "24-hour window",
|
|
150
150
|
resetsAt: now + 7200000,
|
|
151
151
|
width: 40,
|
|
152
|
-
color:
|
|
152
|
+
color: "#7C3AED",
|
|
153
153
|
};
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
function createMockToastProps() {
|
|
157
157
|
return {
|
|
158
|
-
message:
|
|
159
|
-
type:
|
|
158
|
+
message: "Settings saved successfully!",
|
|
159
|
+
type: "success" as const,
|
|
160
160
|
duration: 999999,
|
|
161
161
|
onDismiss: () => {},
|
|
162
162
|
};
|
|
@@ -164,8 +164,8 @@ function createMockToastProps() {
|
|
|
164
164
|
|
|
165
165
|
function createMockToastErrorProps() {
|
|
166
166
|
return {
|
|
167
|
-
message:
|
|
168
|
-
type:
|
|
167
|
+
message: "Failed to connect to API",
|
|
168
|
+
type: "error" as const,
|
|
169
169
|
duration: 999999,
|
|
170
170
|
onDismiss: () => {},
|
|
171
171
|
};
|
|
@@ -173,8 +173,8 @@ function createMockToastErrorProps() {
|
|
|
173
173
|
|
|
174
174
|
function createMockToastWarningProps() {
|
|
175
175
|
return {
|
|
176
|
-
message:
|
|
177
|
-
type:
|
|
176
|
+
message: "Rate limit approaching",
|
|
177
|
+
type: "warning" as const,
|
|
178
178
|
duration: 999999,
|
|
179
179
|
onDismiss: () => {},
|
|
180
180
|
};
|
|
@@ -196,14 +196,14 @@ function createMockKpiStripProps() {
|
|
|
196
196
|
isSpike: false,
|
|
197
197
|
},
|
|
198
198
|
sparkData: [
|
|
199
|
-
4, 6, 8, 12, 18, 22, 28, 36, 32, 40, 44, 48, 52, 48, 44, 40, 36, 32,
|
|
200
|
-
|
|
199
|
+
4, 6, 8, 12, 18, 22, 28, 36, 32, 40, 44, 48, 52, 48, 44, 40, 36, 32, 28, 24, 22, 20, 18, 16,
|
|
200
|
+
14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54,
|
|
201
201
|
],
|
|
202
202
|
budget: {
|
|
203
203
|
limit: 25,
|
|
204
204
|
budgetCost: 12.43,
|
|
205
|
-
budgetType:
|
|
206
|
-
budgetTypeLabel:
|
|
205
|
+
budgetType: "daily" as const,
|
|
206
|
+
budgetTypeLabel: "Daily",
|
|
207
207
|
warningPercent: 80,
|
|
208
208
|
criticalPercent: 90,
|
|
209
209
|
},
|
|
@@ -213,7 +213,7 @@ function createMockKpiStripProps() {
|
|
|
213
213
|
|
|
214
214
|
function createMockSpinnerProps() {
|
|
215
215
|
return {
|
|
216
|
-
color:
|
|
216
|
+
color: "#7C3AED",
|
|
217
217
|
};
|
|
218
218
|
}
|
|
219
219
|
|
|
@@ -221,14 +221,14 @@ function createMockSessionDetailsDrawerProps() {
|
|
|
221
221
|
const now = Date.now();
|
|
222
222
|
return {
|
|
223
223
|
session: {
|
|
224
|
-
sessionId:
|
|
225
|
-
sessionName:
|
|
226
|
-
agentId:
|
|
227
|
-
agentName:
|
|
228
|
-
projectPath:
|
|
224
|
+
sessionId: "ses_39c52c5b5ffe4D0eUfUnnCdNw4",
|
|
225
|
+
sessionName: "test-smoke done",
|
|
226
|
+
agentId: "opencode",
|
|
227
|
+
agentName: "OpenCode",
|
|
228
|
+
projectPath: "/Users/nigel/development/opencode-mission-control",
|
|
229
229
|
startedAt: now - 10000000,
|
|
230
230
|
lastActivityAt: now,
|
|
231
|
-
status:
|
|
231
|
+
status: "active" as const,
|
|
232
232
|
totals: {
|
|
233
233
|
input: 1500000,
|
|
234
234
|
output: 200000,
|
|
@@ -239,8 +239,8 @@ function createMockSessionDetailsDrawerProps() {
|
|
|
239
239
|
requestCount: 150,
|
|
240
240
|
streams: [
|
|
241
241
|
{
|
|
242
|
-
providerId:
|
|
243
|
-
modelId:
|
|
242
|
+
providerId: "anthropic",
|
|
243
|
+
modelId: "claude-3-opus-20240229",
|
|
244
244
|
tokens: {
|
|
245
245
|
input: 1500000,
|
|
246
246
|
output: 200000,
|
|
@@ -254,7 +254,19 @@ function createMockSessionDetailsDrawerProps() {
|
|
|
254
254
|
input: 0.01,
|
|
255
255
|
output: 1.01,
|
|
256
256
|
cacheRead: 10.03,
|
|
257
|
-
cacheWrite: 5.
|
|
257
|
+
cacheWrite: 5.0,
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
providerId: "openai",
|
|
262
|
+
modelId: "gpt-4o",
|
|
263
|
+
tokens: { input: 50000, output: 12000 },
|
|
264
|
+
requestCount: 8,
|
|
265
|
+
costUsd: 0.42,
|
|
266
|
+
costBreakdown: {
|
|
267
|
+
total: 0.42,
|
|
268
|
+
input: 0.13,
|
|
269
|
+
output: 0.29,
|
|
258
270
|
},
|
|
259
271
|
},
|
|
260
272
|
],
|
|
@@ -275,128 +287,128 @@ interface ComponentEntry {
|
|
|
275
287
|
}
|
|
276
288
|
|
|
277
289
|
const COMPONENT_REGISTRY: Record<string, ComponentEntry> = {
|
|
278
|
-
|
|
279
|
-
name:
|
|
280
|
-
description:
|
|
290
|
+
header: {
|
|
291
|
+
name: "Header",
|
|
292
|
+
description: "Top navigation header with title and view tabs",
|
|
281
293
|
defaultWidth: 100,
|
|
282
294
|
defaultHeight: 3,
|
|
283
295
|
render: () => <Header {...createMockHeaderProps()} />,
|
|
284
296
|
},
|
|
285
|
-
|
|
286
|
-
name:
|
|
287
|
-
description:
|
|
297
|
+
"status-bar": {
|
|
298
|
+
name: "StatusBar",
|
|
299
|
+
description: "Bottom status bar with refresh timing",
|
|
288
300
|
defaultWidth: 100,
|
|
289
301
|
defaultHeight: 3,
|
|
290
302
|
render: () => <StatusBar {...createMockStatusBarProps()} />,
|
|
291
303
|
},
|
|
292
|
-
|
|
293
|
-
name:
|
|
294
|
-
description:
|
|
304
|
+
"provider-card": {
|
|
305
|
+
name: "ProviderCard",
|
|
306
|
+
description: "Provider usage card with gauges (configured state)",
|
|
295
307
|
defaultWidth: 50,
|
|
296
308
|
defaultHeight: 20,
|
|
297
309
|
render: () => <ProviderCard {...createMockProviderCardProps()} />,
|
|
298
310
|
},
|
|
299
|
-
|
|
300
|
-
name:
|
|
301
|
-
description:
|
|
311
|
+
"provider-card-loading": {
|
|
312
|
+
name: "ProviderCard (Loading)",
|
|
313
|
+
description: "Provider card in loading state with skeleton",
|
|
302
314
|
defaultWidth: 50,
|
|
303
315
|
defaultHeight: 20,
|
|
304
316
|
render: () => <ProviderCard {...createMockProviderCardLoadingProps()} />,
|
|
305
317
|
},
|
|
306
|
-
|
|
307
|
-
name:
|
|
308
|
-
description:
|
|
318
|
+
"provider-card-unconfigured": {
|
|
319
|
+
name: "ProviderCard (Unconfigured)",
|
|
320
|
+
description: "Provider card not configured state",
|
|
309
321
|
defaultWidth: 50,
|
|
310
322
|
defaultHeight: 20,
|
|
311
323
|
render: () => <ProviderCard {...createMockProviderCardUnconfiguredProps()} />,
|
|
312
324
|
},
|
|
313
|
-
|
|
314
|
-
name:
|
|
315
|
-
description:
|
|
325
|
+
"provider-card-error": {
|
|
326
|
+
name: "ProviderCard (Error)",
|
|
327
|
+
description: "Provider card with error state",
|
|
316
328
|
defaultWidth: 50,
|
|
317
329
|
defaultHeight: 20,
|
|
318
330
|
render: () => <ProviderCard {...createMockProviderCardErrorProps()} />,
|
|
319
331
|
},
|
|
320
|
-
|
|
321
|
-
name:
|
|
322
|
-
description:
|
|
332
|
+
"usage-gauge": {
|
|
333
|
+
name: "UsageGauge",
|
|
334
|
+
description: "Single usage gauge with progress bar",
|
|
323
335
|
defaultWidth: 45,
|
|
324
336
|
defaultHeight: 5,
|
|
325
337
|
render: () => <UsageGauge {...createMockUsageGaugeProps()} />,
|
|
326
338
|
},
|
|
327
|
-
|
|
328
|
-
name:
|
|
329
|
-
description:
|
|
339
|
+
toast: {
|
|
340
|
+
name: "Toast (Success)",
|
|
341
|
+
description: "Toast notification - success variant",
|
|
330
342
|
defaultWidth: 50,
|
|
331
343
|
defaultHeight: 8,
|
|
332
344
|
render: () => <Toast {...createMockToastProps()} />,
|
|
333
345
|
},
|
|
334
|
-
|
|
335
|
-
name:
|
|
336
|
-
description:
|
|
346
|
+
"toast-error": {
|
|
347
|
+
name: "Toast (Error)",
|
|
348
|
+
description: "Toast notification - error variant",
|
|
337
349
|
defaultWidth: 50,
|
|
338
350
|
defaultHeight: 8,
|
|
339
351
|
render: () => <Toast {...createMockToastErrorProps()} />,
|
|
340
352
|
},
|
|
341
|
-
|
|
342
|
-
name:
|
|
343
|
-
description:
|
|
353
|
+
"toast-warning": {
|
|
354
|
+
name: "Toast (Warning)",
|
|
355
|
+
description: "Toast notification - warning variant",
|
|
344
356
|
defaultWidth: 50,
|
|
345
357
|
defaultHeight: 8,
|
|
346
358
|
render: () => <Toast {...createMockToastWarningProps()} />,
|
|
347
359
|
},
|
|
348
|
-
|
|
349
|
-
name:
|
|
350
|
-
description:
|
|
360
|
+
spinner: {
|
|
361
|
+
name: "Spinner",
|
|
362
|
+
description: "Animated loading spinner",
|
|
351
363
|
defaultWidth: 10,
|
|
352
364
|
defaultHeight: 3,
|
|
353
365
|
render: () => <Spinner {...createMockSpinnerProps()} />,
|
|
354
366
|
},
|
|
355
|
-
|
|
356
|
-
name:
|
|
357
|
-
description:
|
|
367
|
+
"skeleton-text": {
|
|
368
|
+
name: "SkeletonText",
|
|
369
|
+
description: "Shimmer loading placeholder for text",
|
|
358
370
|
defaultWidth: 20,
|
|
359
371
|
defaultHeight: 3,
|
|
360
372
|
render: () => <SkeletonText width={15} />,
|
|
361
373
|
},
|
|
362
|
-
|
|
363
|
-
name:
|
|
364
|
-
description:
|
|
374
|
+
"skeleton-gauge": {
|
|
375
|
+
name: "SkeletonGauge",
|
|
376
|
+
description: "Shimmer loading placeholder for gauge",
|
|
365
377
|
defaultWidth: 45,
|
|
366
378
|
defaultHeight: 5,
|
|
367
379
|
render: () => <SkeletonGauge barWidth={30} />,
|
|
368
380
|
},
|
|
369
|
-
|
|
370
|
-
name:
|
|
371
|
-
description:
|
|
381
|
+
"skeleton-provider": {
|
|
382
|
+
name: "SkeletonProviderContent",
|
|
383
|
+
description: "Full skeleton for provider card content",
|
|
372
384
|
defaultWidth: 45,
|
|
373
385
|
defaultHeight: 12,
|
|
374
386
|
render: () => <SkeletonProviderContent />,
|
|
375
387
|
},
|
|
376
|
-
|
|
377
|
-
name:
|
|
378
|
-
description:
|
|
388
|
+
"debug-console": {
|
|
389
|
+
name: "DebugConsole",
|
|
390
|
+
description: "Debug console with log entries",
|
|
379
391
|
defaultWidth: 100,
|
|
380
392
|
defaultHeight: 20,
|
|
381
393
|
render: () => <DebugConsole height={15} follow={true} />,
|
|
382
394
|
},
|
|
383
|
-
|
|
384
|
-
name:
|
|
385
|
-
description:
|
|
395
|
+
"kpi-strip": {
|
|
396
|
+
name: "KpiStrip",
|
|
397
|
+
description: "KPI strip with activity sparkline ramp",
|
|
386
398
|
defaultWidth: 120,
|
|
387
399
|
defaultHeight: 6,
|
|
388
400
|
render: () => <KpiStrip {...createMockKpiStripProps()} />,
|
|
389
401
|
},
|
|
390
|
-
|
|
391
|
-
name:
|
|
392
|
-
description:
|
|
402
|
+
"historical-trends": {
|
|
403
|
+
name: "HistoricalTrendsView",
|
|
404
|
+
description: "ASCII chart showing cost trends over time",
|
|
393
405
|
defaultWidth: 80,
|
|
394
406
|
defaultHeight: 20,
|
|
395
407
|
render: () => <HistoricalTrendsView />,
|
|
396
408
|
},
|
|
397
|
-
|
|
398
|
-
name:
|
|
399
|
-
description:
|
|
409
|
+
"projects-view": {
|
|
410
|
+
name: "ProjectsView",
|
|
411
|
+
description: "Sessions grouped by project with cost breakdown",
|
|
400
412
|
defaultWidth: 100,
|
|
401
413
|
defaultHeight: 25,
|
|
402
414
|
render: () => (
|
|
@@ -413,9 +425,9 @@ const COMPONENT_REGISTRY: Record<string, ComponentEntry> = {
|
|
|
413
425
|
</InputProvider>
|
|
414
426
|
),
|
|
415
427
|
},
|
|
416
|
-
|
|
417
|
-
name:
|
|
418
|
-
description:
|
|
428
|
+
"settings-view": {
|
|
429
|
+
name: "SettingsView",
|
|
430
|
+
description: "Application settings with categories",
|
|
419
431
|
defaultWidth: 80,
|
|
420
432
|
defaultHeight: 25,
|
|
421
433
|
render: () => (
|
|
@@ -426,9 +438,9 @@ const COMPONENT_REGISTRY: Record<string, ComponentEntry> = {
|
|
|
426
438
|
</ConfigProvider>
|
|
427
439
|
),
|
|
428
440
|
},
|
|
429
|
-
|
|
430
|
-
name:
|
|
431
|
-
description:
|
|
441
|
+
"session-details": {
|
|
442
|
+
name: "SessionDetailsDrawer",
|
|
443
|
+
description: "Detailed view of a session",
|
|
432
444
|
defaultWidth: 100,
|
|
433
445
|
defaultHeight: 30,
|
|
434
446
|
render: () => <SessionDetailsDrawer {...createMockSessionDetailsDrawerProps()} />,
|
|
@@ -447,39 +459,39 @@ interface SnapshotOptions {
|
|
|
447
459
|
function parseArgs(): SnapshotOptions {
|
|
448
460
|
const args = process.argv.slice(2);
|
|
449
461
|
const options: SnapshotOptions = {
|
|
450
|
-
component:
|
|
462
|
+
component: "debug-inspector",
|
|
451
463
|
list: false,
|
|
452
464
|
all: false,
|
|
453
465
|
};
|
|
454
466
|
|
|
455
467
|
for (let i = 0; i < args.length; i++) {
|
|
456
468
|
const arg = args[i]!;
|
|
457
|
-
if (arg ===
|
|
469
|
+
if (arg === "--list" || arg === "-l") {
|
|
458
470
|
options.list = true;
|
|
459
|
-
} else if (arg ===
|
|
471
|
+
} else if (arg === "--all" || arg === "-a") {
|
|
460
472
|
options.all = true;
|
|
461
|
-
} else if (arg ===
|
|
473
|
+
} else if (arg === "--width" || arg === "-w") {
|
|
462
474
|
const val = args[i + 1];
|
|
463
475
|
if (val) {
|
|
464
476
|
options.width = parseInt(val, 10);
|
|
465
477
|
i++;
|
|
466
478
|
}
|
|
467
|
-
} else if (arg ===
|
|
479
|
+
} else if (arg === "--height" || arg === "-h") {
|
|
468
480
|
const val = args[i + 1];
|
|
469
481
|
if (val) {
|
|
470
482
|
options.height = parseInt(val, 10);
|
|
471
483
|
i++;
|
|
472
484
|
}
|
|
473
|
-
} else if (arg ===
|
|
485
|
+
} else if (arg === "--output" || arg === "-o") {
|
|
474
486
|
const val = args[i + 1];
|
|
475
487
|
if (val) {
|
|
476
488
|
options.output = val;
|
|
477
489
|
i++;
|
|
478
490
|
}
|
|
479
|
-
} else if (arg ===
|
|
491
|
+
} else if (arg === "--help") {
|
|
480
492
|
printHelp();
|
|
481
493
|
process.exit(0);
|
|
482
|
-
} else if (!arg.startsWith(
|
|
494
|
+
} else if (!arg.startsWith("-")) {
|
|
483
495
|
options.component = arg;
|
|
484
496
|
}
|
|
485
497
|
}
|
|
@@ -512,22 +524,22 @@ Examples:
|
|
|
512
524
|
}
|
|
513
525
|
|
|
514
526
|
function printComponentList(): void {
|
|
515
|
-
console.log(
|
|
516
|
-
console.log(
|
|
517
|
-
console.log(
|
|
518
|
-
|
|
527
|
+
console.log("\nAvailable Components:\n");
|
|
528
|
+
console.log(" ID Description");
|
|
529
|
+
console.log(" " + "-".repeat(70));
|
|
530
|
+
|
|
519
531
|
for (const [id, entry] of Object.entries(COMPONENT_REGISTRY)) {
|
|
520
532
|
const paddedId = id.padEnd(28);
|
|
521
533
|
console.log(` ${paddedId}${entry.description}`);
|
|
522
534
|
}
|
|
523
|
-
|
|
524
|
-
console.log(
|
|
535
|
+
|
|
536
|
+
console.log("\nUsage: bun src/tui/debug/snapshot.tsx <component-id>\n");
|
|
525
537
|
}
|
|
526
538
|
|
|
527
539
|
async function snapshotComponent(
|
|
528
540
|
componentId: string,
|
|
529
541
|
width?: number,
|
|
530
|
-
height?: number
|
|
542
|
+
height?: number,
|
|
531
543
|
): Promise<string> {
|
|
532
544
|
const entry = COMPONENT_REGISTRY[componentId];
|
|
533
545
|
if (!entry) {
|
|
@@ -537,7 +549,7 @@ async function snapshotComponent(
|
|
|
537
549
|
const finalWidth = width ?? entry.defaultWidth;
|
|
538
550
|
const finalHeight = height ?? entry.defaultHeight;
|
|
539
551
|
|
|
540
|
-
if (componentId ===
|
|
552
|
+
if (componentId === "kpi-strip") {
|
|
541
553
|
const driver = await createDriver({ width: finalWidth, height: finalHeight });
|
|
542
554
|
await driver.launch();
|
|
543
555
|
await driver.waitForStable();
|
|
@@ -573,15 +585,17 @@ async function snapshotComponent(
|
|
|
573
585
|
async function saveSnapshot(
|
|
574
586
|
componentId: string,
|
|
575
587
|
frame: string,
|
|
576
|
-
outputPath?: string
|
|
588
|
+
outputPath?: string,
|
|
577
589
|
): Promise<string> {
|
|
578
|
-
const finalPath =
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
590
|
+
const finalPath =
|
|
591
|
+
outputPath ??
|
|
592
|
+
path.join(
|
|
593
|
+
getFramesDir(),
|
|
594
|
+
`snapshot-${componentId}-${new Date().toISOString().replace(/[:.]/g, "-")}.txt`,
|
|
595
|
+
);
|
|
582
596
|
|
|
583
597
|
await fs.mkdir(path.dirname(finalPath), { recursive: true });
|
|
584
|
-
await fs.writeFile(finalPath, frame,
|
|
598
|
+
await fs.writeFile(finalPath, frame, "utf-8");
|
|
585
599
|
|
|
586
600
|
return finalPath;
|
|
587
601
|
}
|
|
@@ -595,16 +609,19 @@ async function main() {
|
|
|
595
609
|
}
|
|
596
610
|
|
|
597
611
|
if (options.all) {
|
|
598
|
-
console.log(
|
|
612
|
+
console.log("Capturing all components...\n");
|
|
599
613
|
const framesDir = getFramesDir();
|
|
600
|
-
const allDir = path.join(
|
|
614
|
+
const allDir = path.join(
|
|
615
|
+
framesDir,
|
|
616
|
+
`snapshot-all-${new Date().toISOString().replace(/[:.]/g, "-")}`,
|
|
617
|
+
);
|
|
601
618
|
await fs.mkdir(allDir, { recursive: true });
|
|
602
619
|
|
|
603
620
|
for (const [id, entry] of Object.entries(COMPONENT_REGISTRY)) {
|
|
604
621
|
try {
|
|
605
622
|
const frame = await snapshotComponent(id, options.width, options.height);
|
|
606
623
|
const outputPath = path.join(allDir, `${id}.txt`);
|
|
607
|
-
await fs.writeFile(outputPath, frame,
|
|
624
|
+
await fs.writeFile(outputPath, frame, "utf-8");
|
|
608
625
|
console.log(` ✓ ${entry.name} -> ${id}.txt`);
|
|
609
626
|
} catch (err) {
|
|
610
627
|
console.error(` ✗ ${entry.name}: ${err}`);
|
|
@@ -618,7 +635,7 @@ async function main() {
|
|
|
618
635
|
const entry = COMPONENT_REGISTRY[options.component];
|
|
619
636
|
if (!entry) {
|
|
620
637
|
console.error(`Unknown component: ${options.component}`);
|
|
621
|
-
console.error(
|
|
638
|
+
console.error("\nAvailable components:");
|
|
622
639
|
for (const id of Object.keys(COMPONENT_REGISTRY)) {
|
|
623
640
|
console.error(` - ${id}`);
|
|
624
641
|
}
|
|
@@ -634,11 +651,11 @@ async function main() {
|
|
|
634
651
|
const outputPath = await saveSnapshot(options.component, frame, options.output);
|
|
635
652
|
|
|
636
653
|
console.log(`Snapshot saved to: ${outputPath}`);
|
|
637
|
-
console.log(
|
|
654
|
+
console.log("\n--- Preview ---");
|
|
638
655
|
console.log(frame);
|
|
639
656
|
}
|
|
640
657
|
|
|
641
658
|
main().catch((err) => {
|
|
642
|
-
console.error(
|
|
659
|
+
console.error("Snapshot failed:", err);
|
|
643
660
|
process.exit(1);
|
|
644
661
|
});
|