@tokscale/cli 1.0.4 → 1.0.6
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/dist/cli.js +11 -3
- package/dist/cli.js.map +1 -1
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +3 -2
- package/dist/native.js.map +1 -1
- package/dist/tui/{App.jsx → App.js} +3 -35
- package/dist/tui/{App.jsx.map → App.js.map} +1 -1
- package/dist/tui/components/{BarChart.jsx → BarChart.js} +14 -37
- package/dist/tui/components/{BarChart.jsx.map → BarChart.js.map} +1 -1
- package/dist/tui/components/{DailyView.jsx → DailyView.js} +7 -23
- package/dist/tui/components/{DailyView.jsx.map → DailyView.js.map} +1 -1
- package/dist/tui/components/DateBreakdownPanel.js +36 -0
- package/dist/tui/components/DateBreakdownPanel.js.map +1 -0
- package/dist/tui/components/Footer.js +87 -0
- package/dist/tui/components/Footer.js.map +1 -0
- package/dist/tui/components/Header.js +20 -0
- package/dist/tui/components/Header.js.map +1 -0
- package/dist/tui/components/Legend.js +16 -0
- package/dist/tui/components/Legend.js.map +1 -0
- package/dist/tui/components/{LoadingSpinner.jsx → LoadingSpinner.js} +6 -12
- package/dist/tui/components/{LoadingSpinner.jsx.map → LoadingSpinner.js.map} +1 -1
- package/dist/tui/components/ModelRow.js +15 -0
- package/dist/tui/components/ModelRow.js.map +1 -0
- package/dist/tui/components/{ModelView.jsx → ModelView.js} +7 -24
- package/dist/tui/components/{ModelView.jsx.map → ModelView.js.map} +1 -1
- package/dist/tui/components/{OverviewView.jsx → OverviewView.js} +11 -35
- package/dist/tui/components/{OverviewView.jsx.map → OverviewView.js.map} +1 -1
- package/dist/tui/components/StatsView.js +86 -0
- package/dist/tui/components/StatsView.js.map +1 -0
- package/dist/tui/components/TokenBreakdown.js +10 -0
- package/dist/tui/components/TokenBreakdown.js.map +1 -0
- package/dist/tui/{index.jsx → index.js} +3 -2
- package/dist/tui/{index.jsx.map → index.js.map} +1 -1
- package/package.json +6 -4
- package/src/tui/App.tsx +339 -0
- package/src/tui/components/BarChart.tsx +198 -0
- package/src/tui/components/DailyView.tsx +113 -0
- package/src/tui/components/DateBreakdownPanel.tsx +79 -0
- package/src/tui/components/Footer.tsx +225 -0
- package/src/tui/components/Header.tsx +68 -0
- package/src/tui/components/Legend.tsx +39 -0
- package/src/tui/components/LoadingSpinner.tsx +82 -0
- package/src/tui/components/ModelRow.tsx +47 -0
- package/src/tui/components/ModelView.tsx +145 -0
- package/src/tui/components/OverviewView.tsx +108 -0
- package/{dist/tui/components/StatsView.jsx → src/tui/components/StatsView.tsx} +128 -83
- package/{dist/tui/components/TokenBreakdown.jsx → src/tui/components/TokenBreakdown.tsx} +28 -9
- package/src/tui/components/index.ts +15 -0
- package/src/tui/config/settings.ts +130 -0
- package/src/tui/config/themes.ts +115 -0
- package/src/tui/hooks/useData.ts +518 -0
- package/src/tui/index.tsx +44 -0
- package/src/tui/opentui.d.ts +137 -0
- package/src/tui/types/index.ts +165 -0
- package/src/tui/utils/cleanup.ts +65 -0
- package/src/tui/utils/colors.ts +65 -0
- package/src/tui/utils/format.ts +36 -0
- package/src/tui/utils/responsive.ts +8 -0
- package/dist/tui/components/DateBreakdownPanel.jsx +0 -61
- package/dist/tui/components/DateBreakdownPanel.jsx.map +0 -1
- package/dist/tui/components/Footer.jsx +0 -158
- package/dist/tui/components/Footer.jsx.map +0 -1
- package/dist/tui/components/Header.jsx +0 -38
- package/dist/tui/components/Header.jsx.map +0 -1
- package/dist/tui/components/Legend.jsx +0 -27
- package/dist/tui/components/Legend.jsx.map +0 -1
- package/dist/tui/components/ModelRow.jsx +0 -28
- package/dist/tui/components/ModelRow.jsx.map +0 -1
- package/dist/tui/components/StatsView.jsx.map +0 -1
- package/dist/tui/components/TokenBreakdown.jsx.map +0 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import type { ColorPaletteName } from "../config/themes.js";
|
|
2
|
+
|
|
3
|
+
export type TabType = "overview" | "model" | "daily" | "stats";
|
|
4
|
+
export type SortType = "cost" | "tokens";
|
|
5
|
+
export type SourceType = "opencode" | "claude" | "codex" | "cursor" | "gemini";
|
|
6
|
+
|
|
7
|
+
export type { ColorPaletteName };
|
|
8
|
+
|
|
9
|
+
export interface ModelEntry {
|
|
10
|
+
source: string;
|
|
11
|
+
model: string;
|
|
12
|
+
input: number;
|
|
13
|
+
output: number;
|
|
14
|
+
cacheWrite: number;
|
|
15
|
+
cacheRead: number;
|
|
16
|
+
reasoning: number;
|
|
17
|
+
total: number;
|
|
18
|
+
cost: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface DailyEntry {
|
|
22
|
+
date: string;
|
|
23
|
+
input: number;
|
|
24
|
+
output: number;
|
|
25
|
+
cache: number;
|
|
26
|
+
total: number;
|
|
27
|
+
cost: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ContributionDay {
|
|
31
|
+
date: string;
|
|
32
|
+
cost: number;
|
|
33
|
+
level: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface GridCell {
|
|
37
|
+
date: string | null;
|
|
38
|
+
level: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface TotalBreakdown {
|
|
42
|
+
input: number;
|
|
43
|
+
output: number;
|
|
44
|
+
cacheWrite: number;
|
|
45
|
+
cacheRead: number;
|
|
46
|
+
reasoning: number;
|
|
47
|
+
total: number;
|
|
48
|
+
cost: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface Stats {
|
|
52
|
+
favoriteModel: string;
|
|
53
|
+
totalTokens: number;
|
|
54
|
+
sessions: number;
|
|
55
|
+
longestSession: string;
|
|
56
|
+
currentStreak: number;
|
|
57
|
+
longestStreak: number;
|
|
58
|
+
activeDays: number;
|
|
59
|
+
totalDays: number;
|
|
60
|
+
peakHour: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface ModelWithPercentage {
|
|
64
|
+
modelId: string;
|
|
65
|
+
percentage: number;
|
|
66
|
+
inputTokens: number;
|
|
67
|
+
outputTokens: number;
|
|
68
|
+
cacheReadTokens: number;
|
|
69
|
+
cacheWriteTokens: number;
|
|
70
|
+
totalTokens: number;
|
|
71
|
+
cost: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface ChartModelData {
|
|
75
|
+
modelId: string;
|
|
76
|
+
tokens: number;
|
|
77
|
+
color: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface ChartDataPoint {
|
|
81
|
+
date: string;
|
|
82
|
+
models: ChartModelData[];
|
|
83
|
+
total: number;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface TUIData {
|
|
87
|
+
modelEntries: ModelEntry[];
|
|
88
|
+
dailyEntries: DailyEntry[];
|
|
89
|
+
contributions: ContributionDay[];
|
|
90
|
+
contributionGrid: GridCell[][];
|
|
91
|
+
stats: Stats;
|
|
92
|
+
totalCost: number;
|
|
93
|
+
totals: TotalBreakdown;
|
|
94
|
+
modelCount: number;
|
|
95
|
+
chartData: ChartDataPoint[];
|
|
96
|
+
topModels: ModelWithPercentage[];
|
|
97
|
+
dailyBreakdowns: Map<string, DailyModelBreakdown>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface TUISettings {
|
|
101
|
+
colorPalette: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export type LoadingPhase =
|
|
105
|
+
| "idle"
|
|
106
|
+
| "loading-pricing"
|
|
107
|
+
| "syncing-cursor"
|
|
108
|
+
| "parsing-sources"
|
|
109
|
+
| "finalizing-report"
|
|
110
|
+
| "complete";
|
|
111
|
+
|
|
112
|
+
export interface DailyModelBreakdown {
|
|
113
|
+
date: string;
|
|
114
|
+
cost: number;
|
|
115
|
+
totalTokens: number;
|
|
116
|
+
models: Array<{
|
|
117
|
+
modelId: string;
|
|
118
|
+
source: string;
|
|
119
|
+
tokens: {
|
|
120
|
+
input: number;
|
|
121
|
+
output: number;
|
|
122
|
+
cacheRead: number;
|
|
123
|
+
cacheWrite: number;
|
|
124
|
+
reasoning: number;
|
|
125
|
+
};
|
|
126
|
+
cost: number;
|
|
127
|
+
messages: number;
|
|
128
|
+
}>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface TUIOptions {
|
|
132
|
+
initialTab?: TabType;
|
|
133
|
+
enabledSources?: SourceType[];
|
|
134
|
+
sortBy?: SortType;
|
|
135
|
+
sortDesc?: boolean;
|
|
136
|
+
since?: string;
|
|
137
|
+
until?: string;
|
|
138
|
+
year?: string;
|
|
139
|
+
colorPalette?: ColorPaletteName;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
export const LAYOUT = {
|
|
145
|
+
HEADER_HEIGHT: 2,
|
|
146
|
+
FOOTER_HEIGHT: 4,
|
|
147
|
+
MIN_CONTENT_HEIGHT: 12,
|
|
148
|
+
CHART_HEIGHT_RATIO: 0.35,
|
|
149
|
+
MIN_CHART_HEIGHT: 5,
|
|
150
|
+
MIN_LIST_HEIGHT: 4,
|
|
151
|
+
CHART_AXIS_WIDTH: 8,
|
|
152
|
+
MIN_CHART_WIDTH: 20,
|
|
153
|
+
MAX_VISIBLE_BARS: 52,
|
|
154
|
+
} as const;
|
|
155
|
+
|
|
156
|
+
export const SOURCE_LABELS: Record<SourceType, string> = {
|
|
157
|
+
opencode: "OC",
|
|
158
|
+
claude: "CC",
|
|
159
|
+
codex: "CX",
|
|
160
|
+
cursor: "CR",
|
|
161
|
+
gemini: "GM",
|
|
162
|
+
} as const;
|
|
163
|
+
|
|
164
|
+
export const TABS: readonly TabType[] = ["overview", "model", "daily", "stats"] as const;
|
|
165
|
+
export const ALL_SOURCES: readonly SourceType[] = ["opencode", "claude", "codex", "cursor", "gemini"] as const;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal cleanup utility for restoring terminal state when TUI exits.
|
|
3
|
+
* Provides fallback cleanup for crash scenarios where OpenTUI's destroy() may not run.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Complete terminal state restoration sequences.
|
|
8
|
+
* Based on research from xterm, kitty keyboard protocol, and popular TUI libraries.
|
|
9
|
+
*/
|
|
10
|
+
export const TERMINAL_CLEANUP_SEQUENCES = [
|
|
11
|
+
// Disable all mouse tracking modes
|
|
12
|
+
'\x1b[?1016l', // SGR Pixel Mode
|
|
13
|
+
'\x1b[?1015l', // URXVT Mouse
|
|
14
|
+
'\x1b[?1006l', // SGR Mouse (produces "51;77;17M" sequences)
|
|
15
|
+
'\x1b[?1005l', // UTF-8 Mouse
|
|
16
|
+
'\x1b[?1004l', // Focus Events
|
|
17
|
+
'\x1b[?1003l', // Any Event Mouse (motion tracking)
|
|
18
|
+
'\x1b[?1002l', // Button Event Mouse (drag tracking)
|
|
19
|
+
'\x1b[?1001l', // Highlight Mouse
|
|
20
|
+
'\x1b[?1000l', // VT200 Mouse
|
|
21
|
+
'\x1b[?9l', // X10 Mouse
|
|
22
|
+
|
|
23
|
+
// Disable kitty keyboard protocol (produces "9;5u" sequences)
|
|
24
|
+
'\x1b[<u', // Disable kitty keyboard progressive enhancement
|
|
25
|
+
'\x1b[>4;0m', // Disable modifyOtherKeys (xterm)
|
|
26
|
+
|
|
27
|
+
// Disable synchronized updates
|
|
28
|
+
'\x1b[?2026l',
|
|
29
|
+
|
|
30
|
+
// Restore cursor and attributes
|
|
31
|
+
'\x1b[?25h', // Show cursor (DECTCEM)
|
|
32
|
+
'\x1b[0m', // Reset all text attributes (SGR 0)
|
|
33
|
+
|
|
34
|
+
// Exit alternate screen buffer
|
|
35
|
+
'\x1b[?1049l', // Exit alt screen + restore cursor
|
|
36
|
+
'\x1b[?47l', // Legacy: exit alt screen
|
|
37
|
+
'\x1b[?1047l', // Legacy: another alt screen mode
|
|
38
|
+
].join('');
|
|
39
|
+
|
|
40
|
+
let hasCleanedUp = false;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Write terminal restoration sequences to stdout.
|
|
44
|
+
* Idempotent - safe to call multiple times.
|
|
45
|
+
*
|
|
46
|
+
* This is a FALLBACK for crash scenarios. Normal exit should use
|
|
47
|
+
* renderer.destroy() which handles cleanup properly.
|
|
48
|
+
*/
|
|
49
|
+
export function restoreTerminalState(): void {
|
|
50
|
+
if (hasCleanedUp) return;
|
|
51
|
+
hasCleanedUp = true;
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
process.stdout.write(TERMINAL_CLEANUP_SEQUENCES);
|
|
55
|
+
} catch {
|
|
56
|
+
// Ignore write errors (stdout may be closed)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Reset cleanup state (for testing purposes).
|
|
62
|
+
*/
|
|
63
|
+
export function resetCleanupState(): void {
|
|
64
|
+
hasCleanedUp = false;
|
|
65
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { SourceType } from "../types/index.js";
|
|
2
|
+
|
|
3
|
+
export const PROVIDER_COLORS = {
|
|
4
|
+
anthropic: "#FF6B35",
|
|
5
|
+
openai: "#10B981",
|
|
6
|
+
google: "#3B82F6",
|
|
7
|
+
cursor: "#8B5CF6",
|
|
8
|
+
opencode: "#6B7280",
|
|
9
|
+
deepseek: "#06B6D4",
|
|
10
|
+
xai: "#EAB308",
|
|
11
|
+
meta: "#6366F1",
|
|
12
|
+
unknown: "#FFFFFF",
|
|
13
|
+
} as const;
|
|
14
|
+
|
|
15
|
+
export type ProviderType = keyof typeof PROVIDER_COLORS;
|
|
16
|
+
|
|
17
|
+
const PROVIDER_PATTERNS: readonly [RegExp, ProviderType][] = [
|
|
18
|
+
[/claude|sonnet|opus|haiku/i, "anthropic"],
|
|
19
|
+
[/gpt|^o1|^o3|codex|text-embedding|dall-e|whisper|tts/i, "openai"],
|
|
20
|
+
[/gemini/i, "google"],
|
|
21
|
+
[/deepseek/i, "deepseek"],
|
|
22
|
+
[/grok/i, "xai"],
|
|
23
|
+
[/llama|mixtral/i, "meta"],
|
|
24
|
+
[/^auto$|cursor/i, "cursor"],
|
|
25
|
+
] as const;
|
|
26
|
+
|
|
27
|
+
const providerCache = new Map<string, ProviderType>();
|
|
28
|
+
const colorCache = new Map<string, string>();
|
|
29
|
+
|
|
30
|
+
export function getProviderFromModel(modelId: string): ProviderType {
|
|
31
|
+
const cached = providerCache.get(modelId);
|
|
32
|
+
if (cached) return cached;
|
|
33
|
+
|
|
34
|
+
let provider: ProviderType = "unknown";
|
|
35
|
+
for (const [pattern, type] of PROVIDER_PATTERNS) {
|
|
36
|
+
if (pattern.test(modelId)) {
|
|
37
|
+
provider = type;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
providerCache.set(modelId, provider);
|
|
43
|
+
return provider;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getModelColor(modelId: string): string {
|
|
47
|
+
const cached = colorCache.get(modelId);
|
|
48
|
+
if (cached) return cached;
|
|
49
|
+
|
|
50
|
+
const color = PROVIDER_COLORS[getProviderFromModel(modelId)];
|
|
51
|
+
colorCache.set(modelId, color);
|
|
52
|
+
return color;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const SOURCE_COLORS: Record<SourceType, string> = {
|
|
56
|
+
opencode: "#22c55e",
|
|
57
|
+
claude: "#f97316",
|
|
58
|
+
codex: "#3b82f6",
|
|
59
|
+
cursor: "#a855f7",
|
|
60
|
+
gemini: "#06b6d4",
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export function getSourceColor(source: SourceType | string): string {
|
|
64
|
+
return SOURCE_COLORS[source as SourceType] || "#888888";
|
|
65
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function formatTokens(n: number): string {
|
|
2
|
+
if (!Number.isFinite(n) || n < 0) return "0";
|
|
3
|
+
return n.toLocaleString();
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function formatTokensShort(n: number): string {
|
|
7
|
+
if (!Number.isFinite(n) || n < 0) return "0";
|
|
8
|
+
if (n >= 1_000_000_000) return `${(n / 1_000_000_000).toFixed(1)}B`;
|
|
9
|
+
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
|
10
|
+
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;
|
|
11
|
+
return n.toLocaleString();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function formatTokensCompact(n: number): string {
|
|
15
|
+
if (!Number.isFinite(n) || n < 0) return "0";
|
|
16
|
+
if (n >= 1_000_000_000) return `${(n / 1_000_000_000).toFixed(1)}B`;
|
|
17
|
+
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
|
18
|
+
if (n >= 1_000) return `${(n / 1_000).toFixed(0)}K`;
|
|
19
|
+
return n.toLocaleString();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function formatCost(cost: number): string {
|
|
23
|
+
if (!Number.isFinite(cost) || cost < 0) return "$0.00";
|
|
24
|
+
if (cost >= 1000) return `$${(cost / 1000).toFixed(1)}K`;
|
|
25
|
+
return `$${cost.toFixed(2)}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function formatCostFull(cost: number): string {
|
|
29
|
+
if (!Number.isFinite(cost) || cost < 0) return "$0.00";
|
|
30
|
+
return `$${cost.toFixed(2)}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function formatPercentage(value: number): string {
|
|
34
|
+
if (!Number.isFinite(value)) return "0.0%";
|
|
35
|
+
return `${value.toFixed(1)}%`;
|
|
36
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const NARROW_TERMINAL_WIDTH = 80;
|
|
2
|
+
export const VERY_NARROW_TERMINAL_WIDTH = 60;
|
|
3
|
+
|
|
4
|
+
export const isNarrow = (width: number | undefined): boolean =>
|
|
5
|
+
(width ?? 100) < NARROW_TERMINAL_WIDTH;
|
|
6
|
+
|
|
7
|
+
export const isVeryNarrow = (width: number | undefined): boolean =>
|
|
8
|
+
(width ?? 100) < VERY_NARROW_TERMINAL_WIDTH;
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { For, createMemo } from "solid-js";
|
|
2
|
-
import { getSourceColor } from "../utils/colors.js";
|
|
3
|
-
import { formatTokens, formatCost } from "../utils/format.js";
|
|
4
|
-
import { ModelRow } from "./ModelRow.js";
|
|
5
|
-
function formatDateDisplay(dateStr) {
|
|
6
|
-
const date = new Date(dateStr + "T00:00:00");
|
|
7
|
-
return date.toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric", year: "numeric" });
|
|
8
|
-
}
|
|
9
|
-
export function DateBreakdownPanel(props) {
|
|
10
|
-
const groupedBySource = createMemo(() => {
|
|
11
|
-
if (!props.breakdown?.models)
|
|
12
|
-
return new Map();
|
|
13
|
-
const groups = new Map();
|
|
14
|
-
for (const model of props.breakdown.models) {
|
|
15
|
-
const existing = groups.get(model.source) || [];
|
|
16
|
-
existing.push(model);
|
|
17
|
-
groups.set(model.source, existing);
|
|
18
|
-
}
|
|
19
|
-
for (const [, models] of groups) {
|
|
20
|
-
models.sort((a, b) => {
|
|
21
|
-
const totalA = a.tokens.input + a.tokens.output + (a.tokens.cacheRead || 0) + (a.tokens.cacheWrite || 0);
|
|
22
|
-
const totalB = b.tokens.input + b.tokens.output + (b.tokens.cacheRead || 0) + (b.tokens.cacheWrite || 0);
|
|
23
|
-
return totalB - totalA;
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
return groups;
|
|
27
|
-
});
|
|
28
|
-
return (<box flexDirection="column" marginTop={1} paddingX={1}>
|
|
29
|
-
<box flexDirection="row" justifyContent="space-between">
|
|
30
|
-
<text bold fg="white">{formatDateDisplay(props.breakdown.date)}</text>
|
|
31
|
-
<box flexDirection="row" gap={2}>
|
|
32
|
-
<text fg="cyan">{formatTokens(props.breakdown.totalTokens)}</text>
|
|
33
|
-
<text fg="green" bold>{formatCost(props.breakdown.cost)}</text>
|
|
34
|
-
</box>
|
|
35
|
-
</box>
|
|
36
|
-
|
|
37
|
-
<box flexDirection="column" marginTop={1}>
|
|
38
|
-
<For each={Array.from(groupedBySource().entries())}>
|
|
39
|
-
{([source, models]) => (<box flexDirection="column">
|
|
40
|
-
<box flexDirection="row" gap={1}>
|
|
41
|
-
<text fg={getSourceColor(source)} bold>{`● ${source.toUpperCase()}`}</text>
|
|
42
|
-
<text dim>{`(${models.length} model${models.length > 1 ? "s" : ""})`}</text>
|
|
43
|
-
</box>
|
|
44
|
-
<For each={models}>
|
|
45
|
-
{(model) => (<ModelRow modelId={model.modelId} tokens={{
|
|
46
|
-
input: model.tokens.input,
|
|
47
|
-
output: model.tokens.output,
|
|
48
|
-
cacheRead: model.tokens.cacheRead,
|
|
49
|
-
cacheWrite: model.tokens.cacheWrite,
|
|
50
|
-
}} compact={props.isNarrow} indent={2}/>)}
|
|
51
|
-
</For>
|
|
52
|
-
</box>)}
|
|
53
|
-
</For>
|
|
54
|
-
</box>
|
|
55
|
-
|
|
56
|
-
<box flexDirection="row" marginTop={1}>
|
|
57
|
-
<text dim>Click another day or same day to close</text>
|
|
58
|
-
</box>
|
|
59
|
-
</box>);
|
|
60
|
-
}
|
|
61
|
-
//# sourceMappingURL=DateBreakdownPanel.jsx.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DateBreakdownPanel.jsx","sourceRoot":"","sources":["../../../src/tui/components/DateBreakdownPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { Show, createSignal, onMount, onCleanup } from "solid-js";
|
|
2
|
-
import { getPalette } from "../config/themes.js";
|
|
3
|
-
import { formatTokens } from "../utils/format.js";
|
|
4
|
-
import { isVeryNarrow } from "../utils/responsive.js";
|
|
5
|
-
function formatTimeAgo(timestamp) {
|
|
6
|
-
const seconds = Math.floor((Date.now() - timestamp) / 1000);
|
|
7
|
-
if (seconds < 60)
|
|
8
|
-
return `${seconds}s ago`;
|
|
9
|
-
const minutes = Math.floor(seconds / 60);
|
|
10
|
-
if (minutes < 60)
|
|
11
|
-
return `${minutes}m ago`;
|
|
12
|
-
const hours = Math.floor(minutes / 60);
|
|
13
|
-
if (hours < 24)
|
|
14
|
-
return `${hours}h ago`;
|
|
15
|
-
const days = Math.floor(hours / 24);
|
|
16
|
-
return `${days}d ago`;
|
|
17
|
-
}
|
|
18
|
-
export function Footer(props) {
|
|
19
|
-
const palette = () => getPalette(props.colorPalette);
|
|
20
|
-
const isVeryNarrowTerminal = () => isVeryNarrow(props.width);
|
|
21
|
-
const showScrollInfo = () => props.activeTab === "overview" &&
|
|
22
|
-
props.totalItems &&
|
|
23
|
-
props.scrollStart !== undefined &&
|
|
24
|
-
props.scrollEnd !== undefined;
|
|
25
|
-
const totals = () => props.totals || { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, reasoning: 0, total: 0, cost: 0 };
|
|
26
|
-
return (<box flexDirection="column" paddingX={1}>
|
|
27
|
-
<box flexDirection="row" justifyContent="space-between">
|
|
28
|
-
<box flexDirection="row" gap={1}>
|
|
29
|
-
<SourceBadge name={isVeryNarrowTerminal() ? "1" : "1:OC"} source="opencode" enabled={props.enabledSources.has("opencode")} onToggle={props.onSourceToggle}/>
|
|
30
|
-
<SourceBadge name={isVeryNarrowTerminal() ? "2" : "2:CC"} source="claude" enabled={props.enabledSources.has("claude")} onToggle={props.onSourceToggle}/>
|
|
31
|
-
<SourceBadge name={isVeryNarrowTerminal() ? "3" : "3:CX"} source="codex" enabled={props.enabledSources.has("codex")} onToggle={props.onSourceToggle}/>
|
|
32
|
-
<SourceBadge name={isVeryNarrowTerminal() ? "4" : "4:CR"} source="cursor" enabled={props.enabledSources.has("cursor")} onToggle={props.onSourceToggle}/>
|
|
33
|
-
<SourceBadge name={isVeryNarrowTerminal() ? "5" : "5:GM"} source="gemini" enabled={props.enabledSources.has("gemini")} onToggle={props.onSourceToggle}/>
|
|
34
|
-
<Show when={!isVeryNarrowTerminal()}>
|
|
35
|
-
<text dim>|</text>
|
|
36
|
-
<SortButton label="Cost" sortType="cost" active={props.sortBy === "cost"} onClick={props.onSortChange}/>
|
|
37
|
-
<SortButton label="Tokens" sortType="tokens" active={props.sortBy === "tokens"} onClick={props.onSortChange}/>
|
|
38
|
-
</Show>
|
|
39
|
-
<Show when={showScrollInfo() && !isVeryNarrowTerminal()}>
|
|
40
|
-
<text dim>|</text>
|
|
41
|
-
<text dim>{`↓ ${props.scrollStart + 1}-${props.scrollEnd} of ${props.totalItems}`}</text>
|
|
42
|
-
</Show>
|
|
43
|
-
</box>
|
|
44
|
-
<box flexDirection="row" gap={1}>
|
|
45
|
-
<text fg="cyan">{formatTokens(totals().total)}</text>
|
|
46
|
-
<text dim>tokens</text>
|
|
47
|
-
<text dim>|</text>
|
|
48
|
-
<text fg="green" bold>{`$${totals().cost.toFixed(2)}`}</text>
|
|
49
|
-
<Show when={!isVeryNarrowTerminal()}>
|
|
50
|
-
<text dim>({props.modelCount} models)</text>
|
|
51
|
-
</Show>
|
|
52
|
-
</box>
|
|
53
|
-
</box>
|
|
54
|
-
<box flexDirection="row" gap={1}>
|
|
55
|
-
<Show when={props.statusMessage} fallback={<Show when={isVeryNarrowTerminal()} fallback={<>
|
|
56
|
-
<text dim>↑↓ scroll • ←→/tab view • y copy •</text>
|
|
57
|
-
<box onMouseDown={props.onPaletteChange}>
|
|
58
|
-
<text fg="magenta">{`[p:${palette().name}]`}</text>
|
|
59
|
-
</box>
|
|
60
|
-
<box onMouseDown={props.onRefresh}>
|
|
61
|
-
<text fg="yellow">[r:refresh]</text>
|
|
62
|
-
</box>
|
|
63
|
-
<text dim>• e export • q quit</text>
|
|
64
|
-
</>}>
|
|
65
|
-
<text dim>↑↓•←→•y•</text>
|
|
66
|
-
<box onMouseDown={props.onPaletteChange}>
|
|
67
|
-
<text fg="magenta">[p]</text>
|
|
68
|
-
</box>
|
|
69
|
-
<box onMouseDown={props.onRefresh}>
|
|
70
|
-
<text fg="yellow">[r]</text>
|
|
71
|
-
</box>
|
|
72
|
-
<text dim>•e•q</text>
|
|
73
|
-
</Show>}>
|
|
74
|
-
<text fg="green" bold>{props.statusMessage}</text>
|
|
75
|
-
</Show>
|
|
76
|
-
</box>
|
|
77
|
-
<Show when={props.isRefreshing}>
|
|
78
|
-
<LoadingStatusLine phase={props.loadingPhase}/>
|
|
79
|
-
</Show>
|
|
80
|
-
<Show when={!props.isRefreshing && props.cacheTimestamp}>
|
|
81
|
-
<box flexDirection="row">
|
|
82
|
-
<text dim>{`Last updated: ${formatTimeAgo(props.cacheTimestamp)}`}</text>
|
|
83
|
-
</box>
|
|
84
|
-
</Show>
|
|
85
|
-
</box>);
|
|
86
|
-
}
|
|
87
|
-
function SourceBadge(props) {
|
|
88
|
-
const handleClick = () => props.onToggle?.(props.source);
|
|
89
|
-
return (<box onMouseDown={handleClick}>
|
|
90
|
-
<text fg={props.enabled ? "green" : "gray"}>
|
|
91
|
-
{`[${props.enabled ? "●" : "○"}${props.name}]`}
|
|
92
|
-
</text>
|
|
93
|
-
</box>);
|
|
94
|
-
}
|
|
95
|
-
function SortButton(props) {
|
|
96
|
-
const handleClick = () => props.onClick?.(props.sortType);
|
|
97
|
-
return (<box onMouseDown={handleClick}>
|
|
98
|
-
<text fg={props.active ? "white" : "gray"} bold={props.active}>
|
|
99
|
-
{props.label}
|
|
100
|
-
</text>
|
|
101
|
-
</box>);
|
|
102
|
-
}
|
|
103
|
-
const SPINNER_COLORS = ["#00FFFF", "#00D7D7", "#00AFAF", "#008787", "#666666", "#666666"];
|
|
104
|
-
const SPINNER_WIDTH = 6;
|
|
105
|
-
const SPINNER_HOLD_START = 20;
|
|
106
|
-
const SPINNER_HOLD_END = 6;
|
|
107
|
-
const SPINNER_TRAIL = 3;
|
|
108
|
-
const SPINNER_INTERVAL = 40;
|
|
109
|
-
const PHASE_MESSAGES = {
|
|
110
|
-
"idle": "Initializing...",
|
|
111
|
-
"loading-pricing": "Loading pricing data...",
|
|
112
|
-
"syncing-cursor": "Syncing Cursor data...",
|
|
113
|
-
"parsing-sources": "Parsing session files...",
|
|
114
|
-
"finalizing-report": "Finalizing report...",
|
|
115
|
-
"complete": "Complete",
|
|
116
|
-
};
|
|
117
|
-
function LoadingStatusLine(props) {
|
|
118
|
-
const [frame, setFrame] = createSignal(0);
|
|
119
|
-
onMount(() => {
|
|
120
|
-
const id = setInterval(() => setFrame(f => f + 1), SPINNER_INTERVAL);
|
|
121
|
-
onCleanup(() => clearInterval(id));
|
|
122
|
-
});
|
|
123
|
-
const getSpinnerState = () => {
|
|
124
|
-
const forwardFrames = SPINNER_WIDTH;
|
|
125
|
-
const backwardFrames = SPINNER_WIDTH - 1;
|
|
126
|
-
const totalCycle = forwardFrames + SPINNER_HOLD_END + backwardFrames + SPINNER_HOLD_START;
|
|
127
|
-
const normalized = frame() % totalCycle;
|
|
128
|
-
if (normalized < forwardFrames) {
|
|
129
|
-
return { position: normalized, forward: true };
|
|
130
|
-
}
|
|
131
|
-
else if (normalized < forwardFrames + SPINNER_HOLD_END) {
|
|
132
|
-
return { position: SPINNER_WIDTH - 1, forward: true };
|
|
133
|
-
}
|
|
134
|
-
else if (normalized < forwardFrames + SPINNER_HOLD_END + backwardFrames) {
|
|
135
|
-
return { position: SPINNER_WIDTH - 2 - (normalized - forwardFrames - SPINNER_HOLD_END), forward: false };
|
|
136
|
-
}
|
|
137
|
-
return { position: 0, forward: false };
|
|
138
|
-
};
|
|
139
|
-
const getCharProps = (index) => {
|
|
140
|
-
const { position, forward } = getSpinnerState();
|
|
141
|
-
const distance = forward ? position - index : index - position;
|
|
142
|
-
if (distance >= 0 && distance < SPINNER_TRAIL) {
|
|
143
|
-
return { char: "■", color: SPINNER_COLORS[distance] };
|
|
144
|
-
}
|
|
145
|
-
return { char: "⬝", color: "#444444" };
|
|
146
|
-
};
|
|
147
|
-
const message = () => props.phase ? PHASE_MESSAGES[props.phase] : "Refreshing...";
|
|
148
|
-
return (<box flexDirection="row" gap={1}>
|
|
149
|
-
<box flexDirection="row" gap={0}>
|
|
150
|
-
{Array.from({ length: SPINNER_WIDTH }, (_, i) => {
|
|
151
|
-
const { char, color } = getCharProps(i);
|
|
152
|
-
return <text fg={color}>{char}</text>;
|
|
153
|
-
})}
|
|
154
|
-
</box>
|
|
155
|
-
<text dim>{message()}</text>
|
|
156
|
-
</box>);
|
|
157
|
-
}
|
|
158
|
-
//# sourceMappingURL=Footer.jsx.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Footer.jsx","sourceRoot":"","sources":["../../../src/tui/components/Footer.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { Show } from "solid-js";
|
|
2
|
-
import { exec } from "child_process";
|
|
3
|
-
import { isNarrow, isVeryNarrow } from "../utils/responsive.js";
|
|
4
|
-
const REPO_URL = "https://github.com/junhoyeo/tokscale";
|
|
5
|
-
function openUrl(url) {
|
|
6
|
-
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
7
|
-
exec(`${cmd} ${url}`);
|
|
8
|
-
}
|
|
9
|
-
export function Header(props) {
|
|
10
|
-
const isNarrowTerminal = () => isNarrow(props.width);
|
|
11
|
-
const isVeryNarrowTerminal = () => isVeryNarrow(props.width);
|
|
12
|
-
const getTabName = (fullName, shortName) => isVeryNarrowTerminal() ? shortName : fullName;
|
|
13
|
-
return (<box flexDirection="row" paddingX={1} paddingY={0} justifyContent="space-between">
|
|
14
|
-
<box flexDirection="row" gap={isVeryNarrowTerminal() ? 1 : 2}>
|
|
15
|
-
<Tab name={getTabName("Overview", "Ovw")} tabId="overview" active={props.activeTab === "overview"} onClick={props.onTabClick}/>
|
|
16
|
-
<Tab name={getTabName("Models", "Mod")} tabId="model" active={props.activeTab === "model"} onClick={props.onTabClick}/>
|
|
17
|
-
<Tab name={getTabName("Daily", "Day")} tabId="daily" active={props.activeTab === "daily"} onClick={props.onTabClick}/>
|
|
18
|
-
<Tab name={getTabName("Stats", "Sta")} tabId="stats" active={props.activeTab === "stats"} onClick={props.onTabClick}/>
|
|
19
|
-
</box>
|
|
20
|
-
<Show when={!isNarrowTerminal()}>
|
|
21
|
-
<box flexDirection="row" onMouseDown={() => openUrl(REPO_URL)}>
|
|
22
|
-
<text fg="cyan" bold>tokscale</text>
|
|
23
|
-
<text fg="#666666">{" | GitHub"}</text>
|
|
24
|
-
</box>
|
|
25
|
-
</Show>
|
|
26
|
-
</box>);
|
|
27
|
-
}
|
|
28
|
-
function Tab(props) {
|
|
29
|
-
const handleClick = () => props.onClick?.(props.tabId);
|
|
30
|
-
return (<Show when={props.active} fallback={<box onMouseDown={handleClick}>
|
|
31
|
-
<text dim>{props.name}</text>
|
|
32
|
-
</box>}>
|
|
33
|
-
<box onMouseDown={handleClick}>
|
|
34
|
-
<text bg="cyan" fg="black" bold>{` ${props.name} `}</text>
|
|
35
|
-
</box>
|
|
36
|
-
</Show>);
|
|
37
|
-
}
|
|
38
|
-
//# sourceMappingURL=Header.jsx.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Header.jsx","sourceRoot":"","sources":["../../../src/tui/components/Header.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { For, Show } from "solid-js";
|
|
2
|
-
import { getModelColor } from "../utils/colors.js";
|
|
3
|
-
import { isNarrow, isVeryNarrow } from "../utils/responsive.js";
|
|
4
|
-
export function Legend(props) {
|
|
5
|
-
const isNarrowTerminal = () => isNarrow(props.width);
|
|
6
|
-
const isVeryNarrowTerminal = () => isVeryNarrow(props.width);
|
|
7
|
-
const maxModelNameWidth = () => isVeryNarrowTerminal() ? 12 : isNarrowTerminal() ? 18 : 30;
|
|
8
|
-
const truncateModelName = (name) => {
|
|
9
|
-
const max = maxModelNameWidth();
|
|
10
|
-
return name.length > max ? name.slice(0, max - 1) + "…" : name;
|
|
11
|
-
};
|
|
12
|
-
const models = () => props.models;
|
|
13
|
-
return (<Show when={models().length > 0}>
|
|
14
|
-
<box flexDirection="row" gap={1} flexWrap="wrap">
|
|
15
|
-
<For each={models()}>
|
|
16
|
-
{(modelId, i) => (<box flexDirection="row" gap={0}>
|
|
17
|
-
<text fg={getModelColor(modelId)}>●</text>
|
|
18
|
-
<text>{` ${truncateModelName(modelId)}`}</text>
|
|
19
|
-
<Show when={i() < models().length - 1}>
|
|
20
|
-
<text dim>{isVeryNarrowTerminal() ? " " : " ·"}</text>
|
|
21
|
-
</Show>
|
|
22
|
-
</box>)}
|
|
23
|
-
</For>
|
|
24
|
-
</box>
|
|
25
|
-
</Show>);
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=Legend.jsx.map
|