@tokscale/cli 1.0.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/dist/auth.d.ts +17 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +162 -0
- package/dist/auth.js.map +1 -0
- package/dist/claudecode.d.ts +39 -0
- package/dist/claudecode.d.ts.map +1 -0
- package/dist/claudecode.js +375 -0
- package/dist/claudecode.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +761 -0
- package/dist/cli.js.map +1 -0
- package/dist/credentials.d.ts +36 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +109 -0
- package/dist/credentials.js.map +1 -0
- package/dist/cursor.d.ts +132 -0
- package/dist/cursor.d.ts.map +1 -0
- package/dist/cursor.js +432 -0
- package/dist/cursor.js.map +1 -0
- package/dist/gemini.d.ts +36 -0
- package/dist/gemini.d.ts.map +1 -0
- package/dist/gemini.js +125 -0
- package/dist/gemini.js.map +1 -0
- package/dist/graph-types.d.ts +152 -0
- package/dist/graph-types.d.ts.map +1 -0
- package/dist/graph-types.js +6 -0
- package/dist/graph-types.js.map +1 -0
- package/dist/graph.d.ts +29 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +383 -0
- package/dist/graph.js.map +1 -0
- package/dist/native-runner.d.ts +12 -0
- package/dist/native-runner.d.ts.map +1 -0
- package/dist/native-runner.js +89 -0
- package/dist/native-runner.js.map +1 -0
- package/dist/native.d.ts +116 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +359 -0
- package/dist/native.js.map +1 -0
- package/dist/opencode.d.ts +40 -0
- package/dist/opencode.d.ts.map +1 -0
- package/dist/opencode.js +69 -0
- package/dist/opencode.js.map +1 -0
- package/dist/pricing.d.ts +58 -0
- package/dist/pricing.d.ts.map +1 -0
- package/dist/pricing.js +232 -0
- package/dist/pricing.js.map +1 -0
- package/dist/sessions/claudecode.d.ts +8 -0
- package/dist/sessions/claudecode.d.ts.map +1 -0
- package/dist/sessions/claudecode.js +84 -0
- package/dist/sessions/claudecode.js.map +1 -0
- package/dist/sessions/codex.d.ts +8 -0
- package/dist/sessions/codex.d.ts.map +1 -0
- package/dist/sessions/codex.js +158 -0
- package/dist/sessions/codex.js.map +1 -0
- package/dist/sessions/gemini.d.ts +8 -0
- package/dist/sessions/gemini.d.ts.map +1 -0
- package/dist/sessions/gemini.js +66 -0
- package/dist/sessions/gemini.js.map +1 -0
- package/dist/sessions/index.d.ts +32 -0
- package/dist/sessions/index.d.ts.map +1 -0
- package/dist/sessions/index.js +96 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/sessions/opencode.d.ts +8 -0
- package/dist/sessions/opencode.d.ts.map +1 -0
- package/dist/sessions/opencode.js +54 -0
- package/dist/sessions/opencode.js.map +1 -0
- package/dist/sessions/reports.d.ts +58 -0
- package/dist/sessions/reports.d.ts.map +1 -0
- package/dist/sessions/reports.js +337 -0
- package/dist/sessions/reports.js.map +1 -0
- package/dist/sessions/types.d.ts +30 -0
- package/dist/sessions/types.d.ts.map +1 -0
- package/dist/sessions/types.js +29 -0
- package/dist/sessions/types.js.map +1 -0
- package/dist/spinner.d.ts +75 -0
- package/dist/spinner.d.ts.map +1 -0
- package/dist/spinner.js +203 -0
- package/dist/spinner.js.map +1 -0
- package/dist/submit.d.ts +21 -0
- package/dist/submit.d.ts.map +1 -0
- package/dist/submit.js +128 -0
- package/dist/submit.js.map +1 -0
- package/dist/table.d.ts +42 -0
- package/dist/table.d.ts.map +1 -0
- package/dist/table.js +181 -0
- package/dist/table.js.map +1 -0
- package/dist/test-selection.d.ts +2 -0
- package/dist/test-selection.d.ts.map +1 -0
- package/dist/test-selection.jsx +32 -0
- package/dist/test-selection.jsx.map +1 -0
- package/dist/tui/App.d.ts +4 -0
- package/dist/tui/App.d.ts.map +1 -0
- package/dist/tui/App.js +167 -0
- package/dist/tui/App.js.map +1 -0
- package/dist/tui/App.jsx +281 -0
- package/dist/tui/App.jsx.map +1 -0
- package/dist/tui/components/BarChart.d.ts +17 -0
- package/dist/tui/components/BarChart.d.ts.map +1 -0
- package/dist/tui/components/BarChart.js +63 -0
- package/dist/tui/components/BarChart.js.map +1 -0
- package/dist/tui/components/BarChart.jsx +163 -0
- package/dist/tui/components/BarChart.jsx.map +1 -0
- package/dist/tui/components/DailyView.d.ts +13 -0
- package/dist/tui/components/DailyView.d.ts.map +1 -0
- package/dist/tui/components/DailyView.js +32 -0
- package/dist/tui/components/DailyView.js.map +1 -0
- package/dist/tui/components/DailyView.jsx +84 -0
- package/dist/tui/components/DailyView.jsx.map +1 -0
- package/dist/tui/components/DateBreakdownPanel.d.ts +7 -0
- package/dist/tui/components/DateBreakdownPanel.d.ts.map +1 -0
- package/dist/tui/components/DateBreakdownPanel.jsx +61 -0
- package/dist/tui/components/DateBreakdownPanel.jsx.map +1 -0
- package/dist/tui/components/Footer.d.ts +26 -0
- package/dist/tui/components/Footer.d.ts.map +1 -0
- package/dist/tui/components/Footer.js +15 -0
- package/dist/tui/components/Footer.js.map +1 -0
- package/dist/tui/components/Footer.jsx +158 -0
- package/dist/tui/components/Footer.jsx.map +1 -0
- package/dist/tui/components/Header.d.ts +9 -0
- package/dist/tui/components/Header.d.ts.map +1 -0
- package/dist/tui/components/Header.js +12 -0
- package/dist/tui/components/Header.js.map +1 -0
- package/dist/tui/components/Header.jsx +38 -0
- package/dist/tui/components/Header.jsx.map +1 -0
- package/dist/tui/components/Legend.d.ts +7 -0
- package/dist/tui/components/Legend.d.ts.map +1 -0
- package/dist/tui/components/Legend.js +9 -0
- package/dist/tui/components/Legend.js.map +1 -0
- package/dist/tui/components/Legend.jsx +27 -0
- package/dist/tui/components/Legend.jsx.map +1 -0
- package/dist/tui/components/LoadingSpinner.d.ts +8 -0
- package/dist/tui/components/LoadingSpinner.d.ts.map +1 -0
- package/dist/tui/components/LoadingSpinner.jsx +62 -0
- package/dist/tui/components/LoadingSpinner.jsx.map +1 -0
- package/dist/tui/components/ModelListItem.d.ts +11 -0
- package/dist/tui/components/ModelListItem.d.ts.map +1 -0
- package/dist/tui/components/ModelListItem.js +18 -0
- package/dist/tui/components/ModelListItem.js.map +1 -0
- package/dist/tui/components/ModelListItem.jsx +17 -0
- package/dist/tui/components/ModelListItem.jsx.map +1 -0
- package/dist/tui/components/ModelRow.d.ts +13 -0
- package/dist/tui/components/ModelRow.d.ts.map +1 -0
- package/dist/tui/components/ModelRow.jsx +28 -0
- package/dist/tui/components/ModelRow.jsx.map +1 -0
- package/dist/tui/components/ModelView.d.ts +13 -0
- package/dist/tui/components/ModelView.d.ts.map +1 -0
- package/dist/tui/components/ModelView.js +34 -0
- package/dist/tui/components/ModelView.js.map +1 -0
- package/dist/tui/components/ModelView.jsx +111 -0
- package/dist/tui/components/ModelView.jsx.map +1 -0
- package/dist/tui/components/OverviewView.d.ts +14 -0
- package/dist/tui/components/OverviewView.d.ts.map +1 -0
- package/dist/tui/components/OverviewView.js +24 -0
- package/dist/tui/components/OverviewView.js.map +1 -0
- package/dist/tui/components/OverviewView.jsx +79 -0
- package/dist/tui/components/OverviewView.jsx.map +1 -0
- package/dist/tui/components/StatsView.d.ts +12 -0
- package/dist/tui/components/StatsView.d.ts.map +1 -0
- package/dist/tui/components/StatsView.js +43 -0
- package/dist/tui/components/StatsView.js.map +1 -0
- package/dist/tui/components/StatsView.jsx +180 -0
- package/dist/tui/components/StatsView.jsx.map +1 -0
- package/dist/tui/components/TokenBreakdown.d.ts +14 -0
- package/dist/tui/components/TokenBreakdown.d.ts.map +1 -0
- package/dist/tui/components/TokenBreakdown.jsx +27 -0
- package/dist/tui/components/TokenBreakdown.jsx.map +1 -0
- package/dist/tui/components/index.d.ts +16 -0
- package/dist/tui/components/index.d.ts.map +1 -0
- package/dist/tui/components/index.js +13 -0
- package/dist/tui/components/index.js.map +1 -0
- package/dist/tui/config/settings.d.ts +12 -0
- package/dist/tui/config/settings.d.ts.map +1 -0
- package/dist/tui/config/settings.js +105 -0
- package/dist/tui/config/settings.js.map +1 -0
- package/dist/tui/config/themes.d.ts +15 -0
- package/dist/tui/config/themes.d.ts.map +1 -0
- package/dist/tui/config/themes.js +82 -0
- package/dist/tui/config/themes.js.map +1 -0
- package/dist/tui/hooks/useData.d.ts +17 -0
- package/dist/tui/hooks/useData.d.ts.map +1 -0
- package/dist/tui/hooks/useData.js +430 -0
- package/dist/tui/hooks/useData.js.map +1 -0
- package/dist/tui/index.d.ts +4 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +8 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/index.jsx +35 -0
- package/dist/tui/index.jsx.map +1 -0
- package/dist/tui/types/index.d.ts +133 -0
- package/dist/tui/types/index.d.ts.map +1 -0
- package/dist/tui/types/index.js +21 -0
- package/dist/tui/types/index.js.map +1 -0
- package/dist/tui/utils/cleanup.d.ts +22 -0
- package/dist/tui/utils/cleanup.d.ts.map +1 -0
- package/dist/tui/utils/cleanup.js +59 -0
- package/dist/tui/utils/cleanup.js.map +1 -0
- package/dist/tui/utils/colors.d.ts +18 -0
- package/dist/tui/utils/colors.d.ts.map +1 -0
- package/dist/tui/utils/colors.js +55 -0
- package/dist/tui/utils/colors.js.map +1 -0
- package/dist/tui/utils/format.d.ts +7 -0
- package/dist/tui/utils/format.d.ts.map +1 -0
- package/dist/tui/utils/format.js +45 -0
- package/dist/tui/utils/format.js.map +1 -0
- package/dist/tui/utils/responsive.d.ts +5 -0
- package/dist/tui/utils/responsive.d.ts.map +1 -0
- package/dist/tui/utils/responsive.js +5 -0
- package/dist/tui/utils/responsive.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { For, Show, createMemo } from "solid-js";
|
|
2
|
+
import { formatTokensCompact } from "../utils/format.js";
|
|
3
|
+
import { isNarrow, isVeryNarrow } from "../utils/responsive.js";
|
|
4
|
+
const BLOCKS = [" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"];
|
|
5
|
+
const MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
6
|
+
const REPEAT_CACHE_MAX_SIZE = 256;
|
|
7
|
+
const repeatCache = new Map();
|
|
8
|
+
function getRepeatedString(char, count) {
|
|
9
|
+
const key = `${char}:${count}`;
|
|
10
|
+
let cached = repeatCache.get(key);
|
|
11
|
+
if (!cached) {
|
|
12
|
+
if (repeatCache.size >= REPEAT_CACHE_MAX_SIZE) {
|
|
13
|
+
const firstKey = repeatCache.keys().next().value;
|
|
14
|
+
if (firstKey)
|
|
15
|
+
repeatCache.delete(firstKey);
|
|
16
|
+
}
|
|
17
|
+
cached = char.repeat(count);
|
|
18
|
+
repeatCache.set(key, cached);
|
|
19
|
+
}
|
|
20
|
+
return cached;
|
|
21
|
+
}
|
|
22
|
+
export function BarChart(props) {
|
|
23
|
+
const data = () => props.data;
|
|
24
|
+
const width = () => props.width;
|
|
25
|
+
const height = () => props.height;
|
|
26
|
+
const isNarrowTerminal = () => isNarrow(width());
|
|
27
|
+
const isVeryNarrowTerminal = () => isVeryNarrow(width());
|
|
28
|
+
const safeHeight = () => Math.max(height(), 1);
|
|
29
|
+
const maxTotal = createMemo(() => {
|
|
30
|
+
const arr = data();
|
|
31
|
+
if (arr.length === 0)
|
|
32
|
+
return 1;
|
|
33
|
+
let max = arr[0].total;
|
|
34
|
+
for (let i = 1; i < arr.length; i++) {
|
|
35
|
+
if (arr[i].total > max)
|
|
36
|
+
max = arr[i].total;
|
|
37
|
+
}
|
|
38
|
+
return Math.max(max, 1);
|
|
39
|
+
});
|
|
40
|
+
const chartWidth = () => Math.max(width() - 8, 20);
|
|
41
|
+
const barWidth = () => Math.max(1, Math.floor(chartWidth() / Math.min(data().length, 52)));
|
|
42
|
+
const visibleBars = () => Math.min(data().length, Math.floor(chartWidth() / barWidth()));
|
|
43
|
+
const visibleData = createMemo(() => data().slice(-visibleBars()));
|
|
44
|
+
const sortedModelsMap = createMemo(() => {
|
|
45
|
+
const vd = visibleData();
|
|
46
|
+
const map = new Map();
|
|
47
|
+
for (const point of vd) {
|
|
48
|
+
const models = point.models ?? [];
|
|
49
|
+
const sorted = [...models].sort((a, b) => a.modelId.localeCompare(b.modelId));
|
|
50
|
+
map.set(point.date, sorted);
|
|
51
|
+
}
|
|
52
|
+
return map;
|
|
53
|
+
});
|
|
54
|
+
const rowIndices = createMemo(() => {
|
|
55
|
+
const sh = safeHeight();
|
|
56
|
+
const indices = new Array(sh);
|
|
57
|
+
for (let i = 0; i < sh; i++) {
|
|
58
|
+
indices[i] = sh - 1 - i;
|
|
59
|
+
}
|
|
60
|
+
return indices;
|
|
61
|
+
});
|
|
62
|
+
const dateLabels = createMemo(() => {
|
|
63
|
+
const vd = visibleData();
|
|
64
|
+
if (vd.length === 0)
|
|
65
|
+
return [];
|
|
66
|
+
const labelInterval = Math.max(1, Math.floor(vd.length / (isVeryNarrowTerminal() ? 2 : 3)));
|
|
67
|
+
const labels = [];
|
|
68
|
+
for (let i = 0; i < vd.length; i += labelInterval) {
|
|
69
|
+
const dateStr = vd[i].date;
|
|
70
|
+
const parts = dateStr.split("-");
|
|
71
|
+
if (parts.length === 3) {
|
|
72
|
+
const month = parseInt(parts[1], 10);
|
|
73
|
+
const day = parseInt(parts[2], 10);
|
|
74
|
+
labels.push(isVeryNarrowTerminal() ? `${month}/${day}` : `${MONTH_NAMES[month - 1]} ${day}`);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
labels.push(dateStr.slice(5));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return labels;
|
|
81
|
+
});
|
|
82
|
+
const axisWidth = () => Math.min(chartWidth(), visibleBars() * barWidth());
|
|
83
|
+
const labelPadding = () => {
|
|
84
|
+
const labels = dateLabels();
|
|
85
|
+
return labels.length > 0 ? Math.floor(axisWidth() / labels.length) : 0;
|
|
86
|
+
};
|
|
87
|
+
const chartTitle = () => isVeryNarrowTerminal() ? "Tokens" : "Tokens per Day";
|
|
88
|
+
const getBarContent = (point, row) => {
|
|
89
|
+
const mt = maxTotal();
|
|
90
|
+
const sh = safeHeight();
|
|
91
|
+
const rowThreshold = ((row + 1) / sh) * mt;
|
|
92
|
+
const prevThreshold = (row / sh) * mt;
|
|
93
|
+
const thresholdDiff = rowThreshold - prevThreshold;
|
|
94
|
+
const bw = barWidth();
|
|
95
|
+
if (point.total <= prevThreshold) {
|
|
96
|
+
return { char: getRepeatedString(" ", bw), color: "dim" };
|
|
97
|
+
}
|
|
98
|
+
const sortedModels = sortedModelsMap().get(point.date) ?? [];
|
|
99
|
+
if (sortedModels.length === 0) {
|
|
100
|
+
return { char: getRepeatedString(" ", bw), color: "dim" };
|
|
101
|
+
}
|
|
102
|
+
let currentHeight = 0;
|
|
103
|
+
let maxOverlap = 0;
|
|
104
|
+
let color = sortedModels[0].color;
|
|
105
|
+
const rowStart = prevThreshold;
|
|
106
|
+
const rowEnd = rowThreshold;
|
|
107
|
+
for (const m of sortedModels) {
|
|
108
|
+
const mStart = currentHeight;
|
|
109
|
+
const mEnd = currentHeight + m.tokens;
|
|
110
|
+
currentHeight += m.tokens;
|
|
111
|
+
const overlapStart = Math.max(mStart, rowStart);
|
|
112
|
+
const overlapEnd = Math.min(mEnd, rowEnd);
|
|
113
|
+
const overlap = Math.max(0, overlapEnd - overlapStart);
|
|
114
|
+
if (overlap > maxOverlap) {
|
|
115
|
+
maxOverlap = overlap;
|
|
116
|
+
color = m.color;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (point.total >= rowThreshold) {
|
|
120
|
+
return { char: getRepeatedString("█", bw), color };
|
|
121
|
+
}
|
|
122
|
+
const ratio = thresholdDiff > 0 ? (point.total - prevThreshold) / thresholdDiff : 1;
|
|
123
|
+
const blockIndex = Math.min(8, Math.max(1, Math.floor(ratio * 8)));
|
|
124
|
+
return { char: getRepeatedString(BLOCKS[blockIndex], bw), color };
|
|
125
|
+
};
|
|
126
|
+
return (<Show when={data().length > 0} fallback={<text dim>No chart data</text>}>
|
|
127
|
+
<box flexDirection="column">
|
|
128
|
+
<text bold>{chartTitle()}</text>
|
|
129
|
+
<For each={rowIndices()}>
|
|
130
|
+
{(row) => {
|
|
131
|
+
const yLabelWidth = isVeryNarrowTerminal() ? 5 : 6;
|
|
132
|
+
const yLabel = row === safeHeight() - 1
|
|
133
|
+
? formatTokensCompact(maxTotal()).padStart(yLabelWidth)
|
|
134
|
+
: " ".repeat(yLabelWidth);
|
|
135
|
+
return (<box flexDirection="row">
|
|
136
|
+
<text dim>{yLabel}│</text>
|
|
137
|
+
<For each={visibleData()}>
|
|
138
|
+
{(point) => {
|
|
139
|
+
const bar = getBarContent(point, row);
|
|
140
|
+
return bar.color === "dim"
|
|
141
|
+
? <text dim>{bar.char}</text>
|
|
142
|
+
: <text fg={bar.color}>{bar.char}</text>;
|
|
143
|
+
}}
|
|
144
|
+
</For>
|
|
145
|
+
</box>);
|
|
146
|
+
}}
|
|
147
|
+
</For>
|
|
148
|
+
<box flexDirection="row">
|
|
149
|
+
<text dim>{isVeryNarrowTerminal() ? " 0│" : " 0│"}</text>
|
|
150
|
+
<text dim>{getRepeatedString("─", axisWidth())}</text>
|
|
151
|
+
</box>
|
|
152
|
+
<Show when={dateLabels().length > 0}>
|
|
153
|
+
<box flexDirection="row">
|
|
154
|
+
<text dim>{isVeryNarrowTerminal() ? " " : " "}</text>
|
|
155
|
+
<text dim>
|
|
156
|
+
{dateLabels().map((l) => l.padEnd(labelPadding())).join("")}
|
|
157
|
+
</text>
|
|
158
|
+
</box>
|
|
159
|
+
</Show>
|
|
160
|
+
</box>
|
|
161
|
+
</Show>);
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=BarChart.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BarChart.jsx","sourceRoot":"","sources":["../../../src/tui/components/BarChart.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Accessor } from "solid-js";
|
|
2
|
+
import type { TUIData, SortType } from "../hooks/useData.js";
|
|
3
|
+
interface DailyViewProps {
|
|
4
|
+
data: TUIData;
|
|
5
|
+
sortBy: SortType;
|
|
6
|
+
sortDesc: boolean;
|
|
7
|
+
selectedIndex: Accessor<number>;
|
|
8
|
+
height: number;
|
|
9
|
+
width?: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function DailyView(props: DailyViewProps): any;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=DailyView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DailyView.d.ts","sourceRoot":"","sources":["../../../src/tui/components/DailyView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAgB7D,UAAU,cAAc;IACtB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,QAAQ,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,OAsF9C"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
export function DailyView({ data, sortBy, sortDesc, selectedIndex, height }) {
|
|
4
|
+
if (!data)
|
|
5
|
+
return null;
|
|
6
|
+
const sortedEntries = [...data.dailyEntries].sort((a, b) => {
|
|
7
|
+
let cmp = 0;
|
|
8
|
+
if (sortBy === "cost")
|
|
9
|
+
cmp = a.cost - b.cost;
|
|
10
|
+
else if (sortBy === "tokens")
|
|
11
|
+
cmp = a.total - b.total;
|
|
12
|
+
else
|
|
13
|
+
cmp = a.date.localeCompare(b.date);
|
|
14
|
+
return sortDesc ? -cmp : cmp;
|
|
15
|
+
});
|
|
16
|
+
const visibleEntries = sortedEntries.slice(0, height - 3);
|
|
17
|
+
const formatNum = (n) => {
|
|
18
|
+
if (n >= 1_000_000_000)
|
|
19
|
+
return `${(n / 1_000_000_000).toFixed(1)}B`;
|
|
20
|
+
if (n >= 1_000_000)
|
|
21
|
+
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
22
|
+
if (n >= 1_000)
|
|
23
|
+
return `${Math.floor(n / 1_000).toLocaleString()},${String(n % 1000).padStart(3, "0")}`;
|
|
24
|
+
return n.toLocaleString();
|
|
25
|
+
};
|
|
26
|
+
const formatCost = (cost) => `$${cost.toFixed(2)}`;
|
|
27
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { children: _jsxs(Text, { color: "cyan", bold: true, children: [" Date".padEnd(14), "Input".padStart(14), "Output".padStart(14), "Cache".padStart(14), "Total".padStart(16), "Cost".padStart(12)] }) }), _jsx(Box, { borderStyle: "single", borderTop: false, borderLeft: false, borderRight: false, borderBottom: true, borderColor: "gray" }), visibleEntries.map((entry, i) => {
|
|
28
|
+
const isSelected = i === selectedIndex;
|
|
29
|
+
return (_jsxs(Box, { children: [_jsxs(Text, { backgroundColor: isSelected ? "blue" : undefined, color: isSelected ? "white" : undefined, children: [entry.date.padEnd(14), formatNum(entry.input).padStart(14), formatNum(entry.output).padStart(14), formatNum(entry.cache).padStart(14), formatNum(entry.total).padStart(16)] }), _jsx(Text, { color: "green", backgroundColor: isSelected ? "blue" : undefined, children: formatCost(entry.cost).padStart(12) })] }, entry.date));
|
|
30
|
+
})] }));
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=DailyView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DailyView.js","sourceRoot":"","sources":["../../../src/tui/components/DailyView.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { For, createMemo } from "solid-js";
|
|
2
|
+
import { formatTokensCompact, formatCostFull } from "../utils/format.js";
|
|
3
|
+
import { isNarrow } from "../utils/responsive.js";
|
|
4
|
+
const STRIPE_BG = "#232328";
|
|
5
|
+
const INPUT_COL_WIDTH = 12;
|
|
6
|
+
const OUTPUT_COL_WIDTH = 12;
|
|
7
|
+
const CACHE_COL_WIDTH = 12;
|
|
8
|
+
const TOTAL_COL_WIDTH = 14;
|
|
9
|
+
const COST_COL_WIDTH = 12;
|
|
10
|
+
const METRIC_COLUMNS_WIDTH_FULL = INPUT_COL_WIDTH + OUTPUT_COL_WIDTH + CACHE_COL_WIDTH + TOTAL_COL_WIDTH + COST_COL_WIDTH;
|
|
11
|
+
const METRIC_COLUMNS_WIDTH_NARROW = TOTAL_COL_WIDTH + COST_COL_WIDTH;
|
|
12
|
+
const SIDE_PADDING = 0;
|
|
13
|
+
const MIN_DATE_COLUMN = 14;
|
|
14
|
+
export function DailyView(props) {
|
|
15
|
+
const isNarrowTerminal = () => isNarrow(props.width);
|
|
16
|
+
const terminalWidth = () => props.width ?? process.stdout.columns ?? 80;
|
|
17
|
+
const dateColumnWidths = createMemo(() => {
|
|
18
|
+
const metricWidth = isNarrowTerminal() ? METRIC_COLUMNS_WIDTH_NARROW : METRIC_COLUMNS_WIDTH_FULL;
|
|
19
|
+
const minDate = MIN_DATE_COLUMN;
|
|
20
|
+
const available = Math.max(terminalWidth() - SIDE_PADDING - metricWidth, minDate);
|
|
21
|
+
const dateColumn = Math.max(minDate, available);
|
|
22
|
+
return {
|
|
23
|
+
column: dateColumn,
|
|
24
|
+
text: dateColumn,
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
const sortedEntries = createMemo(() => {
|
|
28
|
+
const entries = props.data.dailyEntries;
|
|
29
|
+
const sortBy = props.sortBy;
|
|
30
|
+
const sortDesc = props.sortDesc;
|
|
31
|
+
return [...entries].sort((a, b) => {
|
|
32
|
+
let cmp = 0;
|
|
33
|
+
if (sortBy === "cost")
|
|
34
|
+
cmp = a.cost - b.cost;
|
|
35
|
+
else if (sortBy === "tokens")
|
|
36
|
+
cmp = a.total - b.total;
|
|
37
|
+
else
|
|
38
|
+
cmp = a.date.localeCompare(b.date);
|
|
39
|
+
return sortDesc ? -cmp : cmp;
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
const visibleEntries = createMemo(() => sortedEntries().slice(0, props.height - 3));
|
|
43
|
+
const sortArrow = () => (props.sortDesc ? "▼" : "▲");
|
|
44
|
+
const dateHeader = () => "Date";
|
|
45
|
+
const totalHeader = () => (props.sortBy === "tokens" ? `${sortArrow()} Total` : "Total");
|
|
46
|
+
const costHeader = () => (props.sortBy === "cost" ? `${sortArrow()} Cost` : "Cost");
|
|
47
|
+
const renderHeader = () => {
|
|
48
|
+
const dateColWidth = dateColumnWidths().column;
|
|
49
|
+
if (isNarrowTerminal()) {
|
|
50
|
+
return `${"Date".padEnd(dateColWidth)}${totalHeader().padStart(TOTAL_COL_WIDTH)}${costHeader().padStart(COST_COL_WIDTH)}`;
|
|
51
|
+
}
|
|
52
|
+
return `${(" " + dateHeader()).padEnd(dateColWidth)}${"Input".padStart(INPUT_COL_WIDTH)}${"Output".padStart(OUTPUT_COL_WIDTH)}${"Cache".padStart(CACHE_COL_WIDTH)}${totalHeader().padStart(TOTAL_COL_WIDTH)}${costHeader().padStart(COST_COL_WIDTH)}`;
|
|
53
|
+
};
|
|
54
|
+
const renderRow = (entry) => {
|
|
55
|
+
const dateColWidth = dateColumnWidths().column;
|
|
56
|
+
if (isNarrowTerminal()) {
|
|
57
|
+
return `${entry.date.padEnd(dateColWidth)}${formatTokensCompact(entry.total).padStart(TOTAL_COL_WIDTH)}`;
|
|
58
|
+
}
|
|
59
|
+
return `${entry.date.padEnd(dateColWidth)}${formatTokensCompact(entry.input).padStart(INPUT_COL_WIDTH)}${formatTokensCompact(entry.output).padStart(OUTPUT_COL_WIDTH)}${formatTokensCompact(entry.cache).padStart(CACHE_COL_WIDTH)}${formatTokensCompact(entry.total).padStart(TOTAL_COL_WIDTH)}`;
|
|
60
|
+
};
|
|
61
|
+
return (<box flexDirection="column">
|
|
62
|
+
<box flexDirection="row">
|
|
63
|
+
<text fg="cyan" bold>
|
|
64
|
+
{renderHeader()}
|
|
65
|
+
</text>
|
|
66
|
+
</box>
|
|
67
|
+
|
|
68
|
+
<For each={visibleEntries()}>
|
|
69
|
+
{(entry, i) => {
|
|
70
|
+
const isActive = createMemo(() => i() === props.selectedIndex());
|
|
71
|
+
const rowBg = createMemo(() => isActive() ? "blue" : (i() % 2 === 1 ? STRIPE_BG : undefined));
|
|
72
|
+
return (<box flexDirection="row">
|
|
73
|
+
<text bg={rowBg()} fg={isActive() ? "white" : undefined}>
|
|
74
|
+
{renderRow(entry)}
|
|
75
|
+
</text>
|
|
76
|
+
<text fg="green" bg={rowBg()}>
|
|
77
|
+
{formatCostFull(entry.cost).padStart(COST_COL_WIDTH)}
|
|
78
|
+
</text>
|
|
79
|
+
</box>);
|
|
80
|
+
}}
|
|
81
|
+
</For>
|
|
82
|
+
</box>);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=DailyView.jsx.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DailyView.jsx","sourceRoot":"","sources":["../../../src/tui/components/DailyView.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DailyModelBreakdown } from "../types/index.js";
|
|
2
|
+
export interface DateBreakdownPanelProps {
|
|
3
|
+
breakdown: DailyModelBreakdown;
|
|
4
|
+
isNarrow: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function DateBreakdownPanel(props: DateBreakdownPanelProps): any;
|
|
7
|
+
//# sourceMappingURL=DateBreakdownPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DateBreakdownPanel.d.ts","sourceRoot":"","sources":["../../../src/tui/components/DateBreakdownPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAU7D,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,mBAAmB,CAAC;IAC/B,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,OA8DhE"}
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DateBreakdownPanel.jsx","sourceRoot":"","sources":["../../../src/tui/components/DateBreakdownPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SourceType, SortType, TabType, LoadingPhase } from "../types/index.js";
|
|
2
|
+
import type { ColorPaletteName } from "../config/themes.js";
|
|
3
|
+
import type { TotalBreakdown } from "../hooks/useData.js";
|
|
4
|
+
interface FooterProps {
|
|
5
|
+
enabledSources: Set<SourceType>;
|
|
6
|
+
sortBy: SortType;
|
|
7
|
+
totals?: TotalBreakdown;
|
|
8
|
+
modelCount: number;
|
|
9
|
+
activeTab: TabType;
|
|
10
|
+
scrollStart?: number;
|
|
11
|
+
scrollEnd?: number;
|
|
12
|
+
totalItems?: number;
|
|
13
|
+
colorPalette: ColorPaletteName;
|
|
14
|
+
statusMessage?: string | null;
|
|
15
|
+
isRefreshing?: boolean;
|
|
16
|
+
loadingPhase?: LoadingPhase;
|
|
17
|
+
cacheTimestamp?: number | null;
|
|
18
|
+
width?: number;
|
|
19
|
+
onSourceToggle?: (source: SourceType) => void;
|
|
20
|
+
onSortChange?: (sort: SortType) => void;
|
|
21
|
+
onPaletteChange?: () => void;
|
|
22
|
+
onRefresh?: () => void;
|
|
23
|
+
}
|
|
24
|
+
export declare function Footer(props: FooterProps): any;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=Footer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Footer.d.ts","sourceRoot":"","sources":["../../../src/tui/components/Footer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAK1D,UAAU,WAAW;IACnB,cAAc,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAChC,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,gBAAgB,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC9C,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAaD,wBAAgB,MAAM,CAAC,KAAK,EAAE,WAAW,OA8ExC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
export function Footer({ enabledSources, sortBy, totalCost, modelCount, activeTab, scrollStart, scrollEnd, totalItems, }) {
|
|
4
|
+
const formatCost = (cost) => {
|
|
5
|
+
if (cost >= 1000)
|
|
6
|
+
return `$${(cost / 1000).toFixed(1)}K`;
|
|
7
|
+
return `$${cost.toFixed(2)}`;
|
|
8
|
+
};
|
|
9
|
+
const showScrollInfo = activeTab === "overview" && totalItems && scrollStart !== undefined && scrollEnd !== undefined;
|
|
10
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Box, { gap: 1, children: [_jsx(SourceBadge, { name: "1:OC", enabled: enabledSources.has("opencode") }), _jsx(SourceBadge, { name: "2:CC", enabled: enabledSources.has("claude") }), _jsx(SourceBadge, { name: "3:CX", enabled: enabledSources.has("codex") }), _jsx(SourceBadge, { name: "4:CR", enabled: enabledSources.has("cursor") }), _jsx(SourceBadge, { name: "5:GM", enabled: enabledSources.has("gemini") }), _jsx(Text, { dimColor: true, children: "|" }), _jsx(Text, { dimColor: true, children: "Sort:" }), _jsx(Text, { color: "white", children: sortBy === "cost" ? "Cost" : sortBy === "name" ? "Name" : "Tokens" }), showScrollInfo && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: "|" }), _jsxs(Text, { dimColor: true, children: ["\u2193 ", scrollStart + 1, "-", scrollEnd, " of ", totalItems, " models"] })] }))] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { dimColor: true, children: "Total:" }), _jsx(Text, { color: "green", bold: true, children: formatCost(totalCost) }), _jsxs(Text, { dimColor: true, children: ["(", modelCount, ")"] })] })] }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "\u2191\u2193 scroll \u2022 tab/d view \u2022 c/n/t sort \u2022 1-5 filter \u2022 r refresh \u2022 q quit" }) })] }));
|
|
11
|
+
}
|
|
12
|
+
function SourceBadge({ name, enabled }) {
|
|
13
|
+
return (_jsxs(Text, { color: enabled ? "green" : "gray", children: ["[", enabled ? "●" : "○", name, "]"] }));
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=Footer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Footer.js","sourceRoot":"","sources":["../../../src/tui/components/Footer.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAchC,MAAM,UAAU,MAAM,CAAC,EACrB,cAAc,EACd,MAAM,EACN,SAAS,EACT,UAAU,EACV,SAAS,EACT,WAAW,EACX,SAAS,EACT,UAAU,GACE;IACZ,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE;QAClC,IAAI,IAAI,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;QACzD,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/B,CAAC,CAAC;IAEF,MAAM,cAAc,GAAG,SAAS,KAAK,UAAU,IAAI,UAAU,IAAI,WAAW,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS,CAAC;IAEtH,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,aACrC,MAAC,GAAG,IAAC,cAAc,EAAC,eAAe,aACjC,MAAC,GAAG,IAAC,GAAG,EAAE,CAAC,aACT,KAAC,WAAW,IAAC,IAAI,EAAC,MAAM,EAAC,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,GAAI,EACpE,KAAC,WAAW,IAAC,IAAI,EAAC,MAAM,EAAC,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAI,EAClE,KAAC,WAAW,IAAC,IAAI,EAAC,MAAM,EAAC,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,GAAI,EACjE,KAAC,WAAW,IAAC,IAAI,EAAC,MAAM,EAAC,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAI,EAClE,KAAC,WAAW,IAAC,IAAI,EAAC,MAAM,EAAC,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAI,EAClE,KAAC,IAAI,IAAC,QAAQ,wBAAS,EACvB,KAAC,IAAI,IAAC,QAAQ,4BAAa,EAC3B,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,YAAE,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,GAAQ,EAC9F,cAAc,IAAI,CACjB,8BACE,KAAC,IAAI,IAAC,QAAQ,wBAAS,EACvB,MAAC,IAAI,IAAC,QAAQ,8BAAI,WAAW,GAAG,CAAC,OAAG,SAAS,UAAM,UAAU,eAAe,IAC3E,CACJ,IACG,EACN,MAAC,GAAG,IAAC,GAAG,EAAE,CAAC,aACT,KAAC,IAAI,IAAC,QAAQ,6BAAc,EAC5B,KAAC,IAAI,IAAC,KAAK,EAAC,OAAO,EAAC,IAAI,kBAAE,UAAU,CAAC,SAAS,CAAC,GAAQ,EACvD,MAAC,IAAI,IAAC,QAAQ,wBAAG,UAAU,SAAS,IAChC,IACF,EACN,KAAC,GAAG,cACF,KAAC,IAAI,IAAC,QAAQ,+HAEP,GACH,IACF,CACP,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAsC;IACxE,OAAO,CACL,MAAC,IAAI,IAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,kBACnC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,SACtB,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
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
|