@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
package/src/tui/App.tsx
CHANGED
|
@@ -1,39 +1,46 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { useKeyboard } from "@opentui/react";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
|
+
import * as builtinThemeExports from "@/plugins/themes/index.ts";
|
|
4
|
+
import type { ThemePlugin } from "@/plugins/types/theme.ts";
|
|
5
|
+
import { resolveTheme, ThemeProvider, useColors, useTheme } from "./contexts/ThemeContext.tsx";
|
|
6
|
+
import {
|
|
7
|
+
type BurstRecorder,
|
|
8
|
+
captureFrameToFile,
|
|
9
|
+
createBurstRecorder,
|
|
10
|
+
} from "./debug/captureFrame.ts";
|
|
9
11
|
|
|
10
12
|
const builtinThemeList = Object.values(builtinThemeExports) as ThemePlugin[];
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import
|
|
36
|
-
import {
|
|
13
|
+
|
|
14
|
+
import type { DemoPreset } from "@/demo/simulator.ts";
|
|
15
|
+
import { copyToClipboard } from "@/utils/clipboard.ts";
|
|
16
|
+
import { type CommandAction, CommandPalette } from "./components/CommandPalette.tsx";
|
|
17
|
+
import { DebugPanel } from "./components/DebugPanel.tsx";
|
|
18
|
+
import { Header } from "./components/Header.tsx";
|
|
19
|
+
import { SessionDetailsDrawer } from "./components/SessionDetailsDrawer.tsx";
|
|
20
|
+
import { SettingsModal } from "./components/SettingsModal.tsx";
|
|
21
|
+
import { StatusBar } from "./components/StatusBar.tsx";
|
|
22
|
+
import { Toast } from "./components/Toast.tsx";
|
|
23
|
+
import { AgentSessionProvider, useAgentSessions } from "./contexts/AgentSessionContext.tsx";
|
|
24
|
+
import { ConfigProvider, useConfig } from "./contexts/ConfigContext.tsx";
|
|
25
|
+
import {
|
|
26
|
+
DashboardRuntimeProvider,
|
|
27
|
+
useDashboardRuntime,
|
|
28
|
+
} from "./contexts/DashboardRuntimeContext.tsx";
|
|
29
|
+
import { DemoModeProvider, useDemoMode } from "./contexts/DemoModeContext.tsx";
|
|
30
|
+
import { DrawerProvider, useDrawer } from "./contexts/DrawerContext.tsx";
|
|
31
|
+
import { InputProvider, useInputFocus } from "./contexts/InputContext.tsx";
|
|
32
|
+
import { LogProvider, useLogs } from "./contexts/LogContext.tsx";
|
|
33
|
+
import { PluginProvider, usePlugins } from "./contexts/PluginContext.tsx";
|
|
34
|
+
import { RealTimeActivityProvider } from "./contexts/RealTimeActivityContext.tsx";
|
|
35
|
+
import { StorageProvider } from "./contexts/StorageContext.tsx";
|
|
36
|
+
import { TimeWindowProvider } from "./contexts/TimeWindowContext.tsx";
|
|
37
|
+
import { ToastProvider, useToastContext } from "./contexts/ToastContext.tsx";
|
|
38
|
+
import { useSafeRenderer } from "./hooks/useSafeRenderer.ts";
|
|
39
|
+
import { triggerShutdown } from "./shutdown.ts";
|
|
40
|
+
import { Dashboard } from "./views/Dashboard.tsx";
|
|
41
|
+
import { HistoricalTrendsView } from "./views/HistoricalTrendsView.tsx";
|
|
42
|
+
import { ProjectsView } from "./views/ProjectsView.tsx";
|
|
43
|
+
import { RealTimeDashboard } from "./views/RealTimeDashboard.tsx";
|
|
37
44
|
|
|
38
45
|
interface AppProps {
|
|
39
46
|
debug?: boolean;
|
|
@@ -43,7 +50,7 @@ interface AppProps {
|
|
|
43
50
|
cliPlugins?: string[];
|
|
44
51
|
}
|
|
45
52
|
|
|
46
|
-
type View =
|
|
53
|
+
type View = "dashboard" | "providers" | "trends" | "projects";
|
|
47
54
|
|
|
48
55
|
function AppContent() {
|
|
49
56
|
const renderer = useSafeRenderer();
|
|
@@ -63,53 +70,47 @@ function AppContent() {
|
|
|
63
70
|
const refreshInterval = config.refresh.pauseAutoRefresh ? 0 : config.refresh.intervalMs;
|
|
64
71
|
|
|
65
72
|
const [lastRefresh, setLastRefresh] = useState<number | null>(null);
|
|
66
|
-
const [activeView, setActiveView] = useState<View>(
|
|
73
|
+
const [activeView, setActiveView] = useState<View>("dashboard");
|
|
67
74
|
const [showCommandPalette, setShowCommandPalette] = useState(false);
|
|
68
75
|
const [showSettings, setShowSettings] = useState(false);
|
|
69
76
|
const [showDebugPanel, setShowDebugPanel] = useState(false);
|
|
70
77
|
|
|
71
78
|
const isModalOpen = showCommandPalette || showSettings || showDebugPanel || isDrawerOpen;
|
|
72
79
|
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
lastActivityAt: s.lastActivityAt,
|
|
91
|
-
})),
|
|
92
|
-
debugData: debugDataRef.current,
|
|
93
|
-
activity,
|
|
94
|
-
sparkData,
|
|
95
|
-
}), [sessions, debugDataRef, activity, sparkData]);
|
|
80
|
+
const gracefulShutdown = useCallback(() => triggerShutdown(), []);
|
|
81
|
+
|
|
82
|
+
const inspectorData = useMemo(
|
|
83
|
+
() => ({
|
|
84
|
+
sessions: sessions.map((s) => ({
|
|
85
|
+
sessionId: s.sessionId,
|
|
86
|
+
agentName: s.agentName,
|
|
87
|
+
status: s.status,
|
|
88
|
+
totals: s.totals,
|
|
89
|
+
lastActivityAt: s.lastActivityAt,
|
|
90
|
+
})),
|
|
91
|
+
debugData: debugDataRef.current,
|
|
92
|
+
activity,
|
|
93
|
+
sparkData,
|
|
94
|
+
}),
|
|
95
|
+
[sessions, debugDataRef, activity, sparkData],
|
|
96
|
+
);
|
|
96
97
|
|
|
97
98
|
const handleCaptureFrame = useCallback(async () => {
|
|
98
99
|
if (!renderer) {
|
|
99
|
-
showToast(
|
|
100
|
+
showToast("No renderer available", "error");
|
|
100
101
|
return;
|
|
101
102
|
}
|
|
102
103
|
try {
|
|
103
|
-
const result = await captureFrameToFile(renderer,
|
|
104
|
+
const result = await captureFrameToFile(renderer, "manual");
|
|
104
105
|
info(`Frame captured: ${result.framePath}`);
|
|
105
106
|
if (config.notifications.toastsEnabled) {
|
|
106
|
-
showToast(
|
|
107
|
+
showToast("Frame captured");
|
|
107
108
|
}
|
|
108
109
|
} catch (err) {
|
|
109
|
-
const msg = err instanceof Error ? err.message :
|
|
110
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
110
111
|
info(`Frame capture failed: ${msg}`);
|
|
111
112
|
if (config.notifications.toastsEnabled) {
|
|
112
|
-
showToast(
|
|
113
|
+
showToast("Capture failed", "error");
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
116
|
}, [renderer, info, showToast, config.notifications.toastsEnabled]);
|
|
@@ -127,13 +128,15 @@ function AppContent() {
|
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
burstRecorderRef.current = createBurstRecorder(renderer, { frameCount: 10, minInterval: 200 });
|
|
130
|
-
info(
|
|
131
|
+
info("Burst recording started (10 frames)");
|
|
131
132
|
if (config.notifications.toastsEnabled) {
|
|
132
|
-
showToast(
|
|
133
|
+
showToast("Recording burst...");
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
const frames = await burstRecorderRef.current.start();
|
|
136
|
-
info(
|
|
137
|
+
info(
|
|
138
|
+
`Burst complete: ${frames.length} frames in ${frames[0]?.framePath.split("/").slice(0, -1).join("/")}`,
|
|
139
|
+
);
|
|
137
140
|
if (config.notifications.toastsEnabled) {
|
|
138
141
|
showToast(`Burst: ${frames.length} frames`);
|
|
139
142
|
}
|
|
@@ -148,11 +151,11 @@ function AppContent() {
|
|
|
148
151
|
try {
|
|
149
152
|
await copyToClipboard(text);
|
|
150
153
|
if (config.notifications.toastsEnabled) {
|
|
151
|
-
showToast(
|
|
154
|
+
showToast("Copied to clipboard");
|
|
152
155
|
}
|
|
153
156
|
} catch {
|
|
154
157
|
if (config.notifications.toastsEnabled) {
|
|
155
|
-
showToast(
|
|
158
|
+
showToast("Copy failed", "error");
|
|
156
159
|
}
|
|
157
160
|
}
|
|
158
161
|
renderer.clearSelection();
|
|
@@ -161,37 +164,87 @@ function AppContent() {
|
|
|
161
164
|
|
|
162
165
|
const commands: CommandAction[] = useMemo(() => {
|
|
163
166
|
const base: CommandAction[] = [
|
|
164
|
-
{
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
{
|
|
177
|
-
|
|
167
|
+
{
|
|
168
|
+
id: "view-dashboard",
|
|
169
|
+
label: "Go to Dashboard",
|
|
170
|
+
shortcut: "1",
|
|
171
|
+
action: () => setActiveView("dashboard"),
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
id: "view-providers",
|
|
175
|
+
label: "Go to Providers",
|
|
176
|
+
shortcut: "2",
|
|
177
|
+
action: () => setActiveView("providers"),
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: "view-trends",
|
|
181
|
+
label: "Go to Trends",
|
|
182
|
+
shortcut: "3",
|
|
183
|
+
action: () => setActiveView("trends"),
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
id: "view-projects",
|
|
187
|
+
label: "Go to Projects",
|
|
188
|
+
shortcut: "4",
|
|
189
|
+
action: () => setActiveView("projects"),
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: "open-settings",
|
|
193
|
+
label: "Open Settings",
|
|
194
|
+
shortcut: ",",
|
|
195
|
+
action: () => setShowSettings(true),
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
id: "refresh",
|
|
199
|
+
label: "Refresh Data",
|
|
200
|
+
shortcut: "r",
|
|
201
|
+
action: () => {
|
|
202
|
+
if (isInitialized) {
|
|
203
|
+
info("Manual refresh triggered");
|
|
204
|
+
refreshAllProviders().then(() => setLastRefresh(Date.now()));
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
id: "toggle-debug",
|
|
210
|
+
label: "Toggle Debug Panel",
|
|
211
|
+
shortcut: "~",
|
|
212
|
+
action: () => setShowDebugPanel((prev) => !prev),
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
id: "capture-frame",
|
|
216
|
+
label: "Capture Frame",
|
|
217
|
+
shortcut: "Ctrl+P",
|
|
218
|
+
action: () => handleCaptureFrame(),
|
|
219
|
+
},
|
|
220
|
+
{ id: "quit", label: "Quit", shortcut: "q", action: () => void gracefulShutdown() },
|
|
178
221
|
];
|
|
179
222
|
|
|
180
|
-
const themeCommands: CommandAction[] = themes.map(t => ({
|
|
223
|
+
const themeCommands: CommandAction[] = themes.map((t) => ({
|
|
181
224
|
id: `theme-${t.id}`,
|
|
182
225
|
label: `Theme: ${t.name}`,
|
|
183
226
|
action: () => updateConfig({ ...config, display: { ...config.display, theme: t.id } }),
|
|
184
227
|
}));
|
|
185
228
|
|
|
186
229
|
return [...base, ...themeCommands];
|
|
187
|
-
}, [
|
|
230
|
+
}, [
|
|
231
|
+
isInitialized,
|
|
232
|
+
refreshAllProviders,
|
|
233
|
+
info,
|
|
234
|
+
handleCaptureFrame,
|
|
235
|
+
renderer,
|
|
236
|
+
gracefulShutdown,
|
|
237
|
+
themes,
|
|
238
|
+
config,
|
|
239
|
+
updateConfig,
|
|
240
|
+
]);
|
|
188
241
|
|
|
189
242
|
useKeyboard((key) => {
|
|
190
|
-
if (key.ctrl && key.name ===
|
|
243
|
+
if (key.ctrl && key.name === "p") {
|
|
191
244
|
handleCaptureFrame();
|
|
192
245
|
return;
|
|
193
246
|
}
|
|
194
|
-
if (key.ctrl && key.shift && key.name ===
|
|
247
|
+
if (key.ctrl && key.shift && key.name === "p") {
|
|
195
248
|
handleBurstRecord();
|
|
196
249
|
return;
|
|
197
250
|
}
|
|
@@ -204,35 +257,35 @@ function AppContent() {
|
|
|
204
257
|
return;
|
|
205
258
|
}
|
|
206
259
|
|
|
207
|
-
if (key.name ===
|
|
208
|
-
setActiveView(
|
|
260
|
+
if (key.name === "1") {
|
|
261
|
+
setActiveView("dashboard");
|
|
209
262
|
}
|
|
210
|
-
if (key.name ===
|
|
211
|
-
setActiveView(
|
|
263
|
+
if (key.name === "2") {
|
|
264
|
+
setActiveView("providers");
|
|
212
265
|
}
|
|
213
|
-
if (key.name ===
|
|
214
|
-
setActiveView(
|
|
266
|
+
if (key.name === "3") {
|
|
267
|
+
setActiveView("trends");
|
|
215
268
|
}
|
|
216
|
-
if (key.name ===
|
|
217
|
-
setActiveView(
|
|
269
|
+
if (key.name === "4") {
|
|
270
|
+
setActiveView("projects");
|
|
218
271
|
}
|
|
219
|
-
if (key.sequence ===
|
|
272
|
+
if (key.sequence === ",") {
|
|
220
273
|
setShowSettings(true);
|
|
221
274
|
}
|
|
222
275
|
|
|
223
|
-
if (key.sequence ===
|
|
276
|
+
if (key.sequence === ":" || (key.shift && key.name === ";")) {
|
|
224
277
|
setShowCommandPalette(true);
|
|
225
278
|
return;
|
|
226
279
|
}
|
|
227
280
|
|
|
228
|
-
if (key.name ===
|
|
281
|
+
if (key.name === "q" || (key.ctrl && key.name === "c")) {
|
|
229
282
|
void gracefulShutdown();
|
|
230
283
|
}
|
|
231
|
-
if (key.name ===
|
|
232
|
-
info(
|
|
284
|
+
if (key.name === "r" && isInitialized) {
|
|
285
|
+
info("Manual refresh triggered");
|
|
233
286
|
refreshAllProviders().then(() => setLastRefresh(Date.now()));
|
|
234
287
|
}
|
|
235
|
-
if (key.sequence ===
|
|
288
|
+
if (key.sequence === "~" || (key.shift && key.name === "d")) {
|
|
236
289
|
setShowDebugPanel(true);
|
|
237
290
|
}
|
|
238
291
|
});
|
|
@@ -252,7 +305,7 @@ function AppContent() {
|
|
|
252
305
|
|
|
253
306
|
useEffect(() => {
|
|
254
307
|
if (isInitialized) {
|
|
255
|
-
info(
|
|
308
|
+
info("Application initialized");
|
|
256
309
|
refreshAllProviders().then(() => setLastRefresh(Date.now()));
|
|
257
310
|
}
|
|
258
311
|
}, [isInitialized]);
|
|
@@ -261,7 +314,7 @@ function AppContent() {
|
|
|
261
314
|
if (!isInitialized || refreshInterval <= 0) return;
|
|
262
315
|
|
|
263
316
|
const interval = setInterval(() => {
|
|
264
|
-
info(
|
|
317
|
+
info("Auto-refresh triggered");
|
|
265
318
|
refreshAllProviders().then(() => setLastRefresh(Date.now()));
|
|
266
319
|
}, refreshInterval);
|
|
267
320
|
|
|
@@ -277,15 +330,12 @@ function AppContent() {
|
|
|
277
330
|
onMouseUp={handleMouseUp}
|
|
278
331
|
position="relative"
|
|
279
332
|
>
|
|
280
|
-
<Header
|
|
281
|
-
activeView={activeView}
|
|
282
|
-
demoMode={demoMode}
|
|
283
|
-
/>
|
|
333
|
+
<Header activeView={activeView} demoMode={demoMode} />
|
|
284
334
|
|
|
285
|
-
{activeView ===
|
|
286
|
-
{activeView ===
|
|
287
|
-
{activeView ===
|
|
288
|
-
{activeView ===
|
|
335
|
+
{activeView === "dashboard" && <RealTimeDashboard />}
|
|
336
|
+
{activeView === "providers" && <Dashboard />}
|
|
337
|
+
{activeView === "trends" && <HistoricalTrendsView />}
|
|
338
|
+
{activeView === "projects" && <ProjectsView />}
|
|
289
339
|
|
|
290
340
|
<StatusBar
|
|
291
341
|
lastRefresh={lastRefresh ?? 0}
|
|
@@ -294,36 +344,21 @@ function AppContent() {
|
|
|
294
344
|
/>
|
|
295
345
|
|
|
296
346
|
{toast && config.notifications.toastsEnabled && (
|
|
297
|
-
<Toast
|
|
298
|
-
message={toast.message}
|
|
299
|
-
type={toast.type}
|
|
300
|
-
onDismiss={dismissToast}
|
|
301
|
-
/>
|
|
347
|
+
<Toast message={toast.message} type={toast.type} onDismiss={dismissToast} />
|
|
302
348
|
)}
|
|
303
349
|
|
|
304
350
|
{showCommandPalette && (
|
|
305
|
-
<CommandPalette
|
|
306
|
-
commands={commands}
|
|
307
|
-
onClose={() => setShowCommandPalette(false)}
|
|
308
|
-
/>
|
|
351
|
+
<CommandPalette commands={commands} onClose={() => setShowCommandPalette(false)} />
|
|
309
352
|
)}
|
|
310
353
|
|
|
311
|
-
{showSettings && (
|
|
312
|
-
<SettingsModal onClose={() => setShowSettings(false)} />
|
|
313
|
-
)}
|
|
354
|
+
{showSettings && <SettingsModal onClose={() => setShowSettings(false)} />}
|
|
314
355
|
|
|
315
356
|
{showDebugPanel && (
|
|
316
|
-
<DebugPanel
|
|
317
|
-
onClose={() => setShowDebugPanel(false)}
|
|
318
|
-
inspectorData={inspectorData}
|
|
319
|
-
/>
|
|
357
|
+
<DebugPanel onClose={() => setShowDebugPanel(false)} inspectorData={inspectorData} />
|
|
320
358
|
)}
|
|
321
359
|
|
|
322
360
|
{isDrawerOpen && selectedSession && (
|
|
323
|
-
<SessionDetailsDrawer
|
|
324
|
-
session={selectedSession}
|
|
325
|
-
onClose={hideDrawer}
|
|
326
|
-
/>
|
|
361
|
+
<SessionDetailsDrawer session={selectedSession} onClose={hideDrawer} />
|
|
327
362
|
)}
|
|
328
363
|
</box>
|
|
329
364
|
);
|
|
@@ -336,7 +371,7 @@ function ConfiguredApp({ cliPlugins }: { cliPlugins?: string[] }) {
|
|
|
336
371
|
return null;
|
|
337
372
|
}
|
|
338
373
|
|
|
339
|
-
const initialTheme = builtinThemeList.find(t => t.id === config.display.theme);
|
|
374
|
+
const initialTheme = builtinThemeList.find((t) => t.id === config.display.theme);
|
|
340
375
|
const themeProps = initialTheme ? { initialTheme } : {};
|
|
341
376
|
|
|
342
377
|
return (
|
|
@@ -347,9 +382,9 @@ function ConfiguredApp({ cliPlugins }: { cliPlugins?: string[] }) {
|
|
|
347
382
|
<RealTimeActivityProvider>
|
|
348
383
|
<AgentSessionProvider autoRefresh={true} refreshInterval={1000}>
|
|
349
384
|
<DashboardRuntimeProvider>
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
385
|
+
<DrawerProvider>
|
|
386
|
+
<AppContent />
|
|
387
|
+
</DrawerProvider>
|
|
353
388
|
</DashboardRuntimeProvider>
|
|
354
389
|
</AgentSessionProvider>
|
|
355
390
|
</RealTimeActivityProvider>
|
|
@@ -360,8 +395,16 @@ function ConfiguredApp({ cliPlugins }: { cliPlugins?: string[] }) {
|
|
|
360
395
|
);
|
|
361
396
|
}
|
|
362
397
|
|
|
363
|
-
export function App({
|
|
364
|
-
|
|
398
|
+
export function App({
|
|
399
|
+
debug = false,
|
|
400
|
+
demoMode = false,
|
|
401
|
+
demoSeed,
|
|
402
|
+
demoPreset,
|
|
403
|
+
cliPlugins,
|
|
404
|
+
}: AppProps) {
|
|
405
|
+
const demoProviderProps: { demoMode: boolean; demoSeed?: number; demoPreset?: DemoPreset } = {
|
|
406
|
+
demoMode,
|
|
407
|
+
};
|
|
365
408
|
if (demoSeed !== undefined) demoProviderProps.demoSeed = demoSeed;
|
|
366
409
|
if (demoPreset !== undefined) demoProviderProps.demoPreset = demoPreset;
|
|
367
410
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useKeyboard, useTerminalDimensions } from
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { RGBA } from "@opentui/core";
|
|
2
|
+
import { useKeyboard, useTerminalDimensions } from "@opentui/react";
|
|
3
|
+
import { useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { useInputFocus } from "../contexts/InputContext.tsx";
|
|
5
|
+
import { useColors } from "../contexts/ThemeContext.tsx";
|
|
6
6
|
|
|
7
7
|
const OVERLAY_BG = RGBA.fromValues(0.0, 0.0, 0.0, 0.5);
|
|
8
8
|
|
|
@@ -22,7 +22,7 @@ export function CommandPalette({ commands, onClose }: CommandPaletteProps) {
|
|
|
22
22
|
const colors = useColors();
|
|
23
23
|
const { width: termWidth, height: termHeight } = useTerminalDimensions();
|
|
24
24
|
const { setInputFocused } = useInputFocus();
|
|
25
|
-
const [query, setQuery] = useState(
|
|
25
|
+
const [query, setQuery] = useState("");
|
|
26
26
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
27
27
|
|
|
28
28
|
useEffect(() => {
|
|
@@ -33,9 +33,9 @@ export function CommandPalette({ commands, onClose }: CommandPaletteProps) {
|
|
|
33
33
|
const filteredCommands = useMemo(() => {
|
|
34
34
|
if (!query) return commands;
|
|
35
35
|
const lowerQuery = query.toLowerCase();
|
|
36
|
-
return commands.filter(
|
|
37
|
-
cmd
|
|
38
|
-
|
|
36
|
+
return commands.filter(
|
|
37
|
+
(cmd) =>
|
|
38
|
+
cmd.label.toLowerCase().includes(lowerQuery) || cmd.id.toLowerCase().includes(lowerQuery),
|
|
39
39
|
);
|
|
40
40
|
}, [commands, query]);
|
|
41
41
|
|
|
@@ -49,12 +49,12 @@ export function CommandPalette({ commands, onClose }: CommandPaletteProps) {
|
|
|
49
49
|
}, [query]);
|
|
50
50
|
|
|
51
51
|
useKeyboard((key) => {
|
|
52
|
-
if (key.name ===
|
|
52
|
+
if (key.name === "escape") {
|
|
53
53
|
onClose();
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
if (key.name ===
|
|
57
|
+
if (key.name === "return") {
|
|
58
58
|
const selected = filteredCommands[selectedIndex];
|
|
59
59
|
if (selected) {
|
|
60
60
|
onClose();
|
|
@@ -63,9 +63,9 @@ export function CommandPalette({ commands, onClose }: CommandPaletteProps) {
|
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
if (query ===
|
|
67
|
-
const keyStr = key.sequence ||
|
|
68
|
-
const matchingCmd = commands.find(cmd => cmd.shortcut === keyStr);
|
|
66
|
+
if (query === "" && !key.ctrl && !key.meta) {
|
|
67
|
+
const keyStr = key.sequence || "";
|
|
68
|
+
const matchingCmd = commands.find((cmd) => cmd.shortcut === keyStr);
|
|
69
69
|
if (matchingCmd) {
|
|
70
70
|
onClose();
|
|
71
71
|
matchingCmd.action();
|
|
@@ -73,23 +73,31 @@ export function CommandPalette({ commands, onClose }: CommandPaletteProps) {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
if (
|
|
77
|
-
|
|
76
|
+
if (
|
|
77
|
+
key.name === "down" ||
|
|
78
|
+
(key.ctrl && key.name === "n") ||
|
|
79
|
+
(query === "" && key.name === "j")
|
|
80
|
+
) {
|
|
81
|
+
setSelectedIndex((i) => Math.min(i + 1, filteredCommands.length - 1));
|
|
78
82
|
return;
|
|
79
83
|
}
|
|
80
84
|
|
|
81
|
-
if (key.name ===
|
|
82
|
-
setSelectedIndex(i => Math.max(i - 1, 0));
|
|
85
|
+
if (key.name === "up" || (key.ctrl && key.name === "p") || (query === "" && key.name === "k")) {
|
|
86
|
+
setSelectedIndex((i) => Math.max(i - 1, 0));
|
|
83
87
|
return;
|
|
84
88
|
}
|
|
85
89
|
|
|
86
|
-
if (key.name ===
|
|
87
|
-
setQuery(q => q.slice(0, -1));
|
|
90
|
+
if (key.name === "backspace") {
|
|
91
|
+
setQuery((q) => q.slice(0, -1));
|
|
88
92
|
return;
|
|
89
93
|
}
|
|
90
94
|
|
|
91
|
-
if (
|
|
92
|
-
|
|
95
|
+
if (
|
|
96
|
+
key.sequence &&
|
|
97
|
+
key.sequence.length === 1 &&
|
|
98
|
+
/^[\w\-_., ~:;!@#$%^&*()]$/.test(key.sequence)
|
|
99
|
+
) {
|
|
100
|
+
setQuery((q) => q + key.sequence);
|
|
93
101
|
return;
|
|
94
102
|
}
|
|
95
103
|
});
|
|
@@ -128,20 +136,22 @@ export function CommandPalette({ commands, onClose }: CommandPaletteProps) {
|
|
|
128
136
|
<box flexDirection="column">
|
|
129
137
|
{filteredCommands.length === 0 ? (
|
|
130
138
|
<box padding={1} height={1}>
|
|
131
|
-
<text height={1} fg={colors.textMuted}>
|
|
139
|
+
<text height={1} fg={colors.textMuted}>
|
|
140
|
+
No matching commands
|
|
141
|
+
</text>
|
|
132
142
|
</box>
|
|
133
143
|
) : (
|
|
134
144
|
filteredCommands.map((cmd, idx) => {
|
|
135
145
|
const isSelected = idx === selectedIndex;
|
|
136
146
|
return (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
147
|
+
<box
|
|
148
|
+
key={cmd.id}
|
|
149
|
+
flexDirection="row"
|
|
150
|
+
justifyContent="space-between"
|
|
151
|
+
paddingX={1}
|
|
152
|
+
height={1}
|
|
153
|
+
{...(isSelected ? { backgroundColor: colors.primary } : {})}
|
|
154
|
+
>
|
|
145
155
|
<text height={1} fg={isSelected ? colors.background : colors.text}>
|
|
146
156
|
{cmd.label}
|
|
147
157
|
</text>
|
|
@@ -157,9 +167,11 @@ export function CommandPalette({ commands, onClose }: CommandPaletteProps) {
|
|
|
157
167
|
</box>
|
|
158
168
|
</scrollbox>
|
|
159
169
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
170
|
+
<box paddingX={1} height={1}>
|
|
171
|
+
<text height={1} fg={colors.textSubtle}>
|
|
172
|
+
↑↓ navigate Enter select Esc close
|
|
173
|
+
</text>
|
|
174
|
+
</box>
|
|
163
175
|
</box>
|
|
164
176
|
</box>
|
|
165
177
|
);
|