@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.
Files changed (211) hide show
  1. package/dist/auth.d.ts +17 -0
  2. package/dist/auth.d.ts.map +1 -0
  3. package/dist/auth.js +162 -0
  4. package/dist/auth.js.map +1 -0
  5. package/dist/claudecode.d.ts +39 -0
  6. package/dist/claudecode.d.ts.map +1 -0
  7. package/dist/claudecode.js +375 -0
  8. package/dist/claudecode.js.map +1 -0
  9. package/dist/cli.d.ts +9 -0
  10. package/dist/cli.d.ts.map +1 -0
  11. package/dist/cli.js +761 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/credentials.d.ts +36 -0
  14. package/dist/credentials.d.ts.map +1 -0
  15. package/dist/credentials.js +109 -0
  16. package/dist/credentials.js.map +1 -0
  17. package/dist/cursor.d.ts +132 -0
  18. package/dist/cursor.d.ts.map +1 -0
  19. package/dist/cursor.js +432 -0
  20. package/dist/cursor.js.map +1 -0
  21. package/dist/gemini.d.ts +36 -0
  22. package/dist/gemini.d.ts.map +1 -0
  23. package/dist/gemini.js +125 -0
  24. package/dist/gemini.js.map +1 -0
  25. package/dist/graph-types.d.ts +152 -0
  26. package/dist/graph-types.d.ts.map +1 -0
  27. package/dist/graph-types.js +6 -0
  28. package/dist/graph-types.js.map +1 -0
  29. package/dist/graph.d.ts +29 -0
  30. package/dist/graph.d.ts.map +1 -0
  31. package/dist/graph.js +383 -0
  32. package/dist/graph.js.map +1 -0
  33. package/dist/native-runner.d.ts +12 -0
  34. package/dist/native-runner.d.ts.map +1 -0
  35. package/dist/native-runner.js +89 -0
  36. package/dist/native-runner.js.map +1 -0
  37. package/dist/native.d.ts +116 -0
  38. package/dist/native.d.ts.map +1 -0
  39. package/dist/native.js +359 -0
  40. package/dist/native.js.map +1 -0
  41. package/dist/opencode.d.ts +40 -0
  42. package/dist/opencode.d.ts.map +1 -0
  43. package/dist/opencode.js +69 -0
  44. package/dist/opencode.js.map +1 -0
  45. package/dist/pricing.d.ts +58 -0
  46. package/dist/pricing.d.ts.map +1 -0
  47. package/dist/pricing.js +232 -0
  48. package/dist/pricing.js.map +1 -0
  49. package/dist/sessions/claudecode.d.ts +8 -0
  50. package/dist/sessions/claudecode.d.ts.map +1 -0
  51. package/dist/sessions/claudecode.js +84 -0
  52. package/dist/sessions/claudecode.js.map +1 -0
  53. package/dist/sessions/codex.d.ts +8 -0
  54. package/dist/sessions/codex.d.ts.map +1 -0
  55. package/dist/sessions/codex.js +158 -0
  56. package/dist/sessions/codex.js.map +1 -0
  57. package/dist/sessions/gemini.d.ts +8 -0
  58. package/dist/sessions/gemini.d.ts.map +1 -0
  59. package/dist/sessions/gemini.js +66 -0
  60. package/dist/sessions/gemini.js.map +1 -0
  61. package/dist/sessions/index.d.ts +32 -0
  62. package/dist/sessions/index.d.ts.map +1 -0
  63. package/dist/sessions/index.js +96 -0
  64. package/dist/sessions/index.js.map +1 -0
  65. package/dist/sessions/opencode.d.ts +8 -0
  66. package/dist/sessions/opencode.d.ts.map +1 -0
  67. package/dist/sessions/opencode.js +54 -0
  68. package/dist/sessions/opencode.js.map +1 -0
  69. package/dist/sessions/reports.d.ts +58 -0
  70. package/dist/sessions/reports.d.ts.map +1 -0
  71. package/dist/sessions/reports.js +337 -0
  72. package/dist/sessions/reports.js.map +1 -0
  73. package/dist/sessions/types.d.ts +30 -0
  74. package/dist/sessions/types.d.ts.map +1 -0
  75. package/dist/sessions/types.js +29 -0
  76. package/dist/sessions/types.js.map +1 -0
  77. package/dist/spinner.d.ts +75 -0
  78. package/dist/spinner.d.ts.map +1 -0
  79. package/dist/spinner.js +203 -0
  80. package/dist/spinner.js.map +1 -0
  81. package/dist/submit.d.ts +21 -0
  82. package/dist/submit.d.ts.map +1 -0
  83. package/dist/submit.js +128 -0
  84. package/dist/submit.js.map +1 -0
  85. package/dist/table.d.ts +42 -0
  86. package/dist/table.d.ts.map +1 -0
  87. package/dist/table.js +181 -0
  88. package/dist/table.js.map +1 -0
  89. package/dist/test-selection.d.ts +2 -0
  90. package/dist/test-selection.d.ts.map +1 -0
  91. package/dist/test-selection.jsx +32 -0
  92. package/dist/test-selection.jsx.map +1 -0
  93. package/dist/tui/App.d.ts +4 -0
  94. package/dist/tui/App.d.ts.map +1 -0
  95. package/dist/tui/App.js +167 -0
  96. package/dist/tui/App.js.map +1 -0
  97. package/dist/tui/App.jsx +281 -0
  98. package/dist/tui/App.jsx.map +1 -0
  99. package/dist/tui/components/BarChart.d.ts +17 -0
  100. package/dist/tui/components/BarChart.d.ts.map +1 -0
  101. package/dist/tui/components/BarChart.js +63 -0
  102. package/dist/tui/components/BarChart.js.map +1 -0
  103. package/dist/tui/components/BarChart.jsx +163 -0
  104. package/dist/tui/components/BarChart.jsx.map +1 -0
  105. package/dist/tui/components/DailyView.d.ts +13 -0
  106. package/dist/tui/components/DailyView.d.ts.map +1 -0
  107. package/dist/tui/components/DailyView.js +32 -0
  108. package/dist/tui/components/DailyView.js.map +1 -0
  109. package/dist/tui/components/DailyView.jsx +84 -0
  110. package/dist/tui/components/DailyView.jsx.map +1 -0
  111. package/dist/tui/components/DateBreakdownPanel.d.ts +7 -0
  112. package/dist/tui/components/DateBreakdownPanel.d.ts.map +1 -0
  113. package/dist/tui/components/DateBreakdownPanel.jsx +61 -0
  114. package/dist/tui/components/DateBreakdownPanel.jsx.map +1 -0
  115. package/dist/tui/components/Footer.d.ts +26 -0
  116. package/dist/tui/components/Footer.d.ts.map +1 -0
  117. package/dist/tui/components/Footer.js +15 -0
  118. package/dist/tui/components/Footer.js.map +1 -0
  119. package/dist/tui/components/Footer.jsx +158 -0
  120. package/dist/tui/components/Footer.jsx.map +1 -0
  121. package/dist/tui/components/Header.d.ts +9 -0
  122. package/dist/tui/components/Header.d.ts.map +1 -0
  123. package/dist/tui/components/Header.js +12 -0
  124. package/dist/tui/components/Header.js.map +1 -0
  125. package/dist/tui/components/Header.jsx +38 -0
  126. package/dist/tui/components/Header.jsx.map +1 -0
  127. package/dist/tui/components/Legend.d.ts +7 -0
  128. package/dist/tui/components/Legend.d.ts.map +1 -0
  129. package/dist/tui/components/Legend.js +9 -0
  130. package/dist/tui/components/Legend.js.map +1 -0
  131. package/dist/tui/components/Legend.jsx +27 -0
  132. package/dist/tui/components/Legend.jsx.map +1 -0
  133. package/dist/tui/components/LoadingSpinner.d.ts +8 -0
  134. package/dist/tui/components/LoadingSpinner.d.ts.map +1 -0
  135. package/dist/tui/components/LoadingSpinner.jsx +62 -0
  136. package/dist/tui/components/LoadingSpinner.jsx.map +1 -0
  137. package/dist/tui/components/ModelListItem.d.ts +11 -0
  138. package/dist/tui/components/ModelListItem.d.ts.map +1 -0
  139. package/dist/tui/components/ModelListItem.js +18 -0
  140. package/dist/tui/components/ModelListItem.js.map +1 -0
  141. package/dist/tui/components/ModelListItem.jsx +17 -0
  142. package/dist/tui/components/ModelListItem.jsx.map +1 -0
  143. package/dist/tui/components/ModelRow.d.ts +13 -0
  144. package/dist/tui/components/ModelRow.d.ts.map +1 -0
  145. package/dist/tui/components/ModelRow.jsx +28 -0
  146. package/dist/tui/components/ModelRow.jsx.map +1 -0
  147. package/dist/tui/components/ModelView.d.ts +13 -0
  148. package/dist/tui/components/ModelView.d.ts.map +1 -0
  149. package/dist/tui/components/ModelView.js +34 -0
  150. package/dist/tui/components/ModelView.js.map +1 -0
  151. package/dist/tui/components/ModelView.jsx +111 -0
  152. package/dist/tui/components/ModelView.jsx.map +1 -0
  153. package/dist/tui/components/OverviewView.d.ts +14 -0
  154. package/dist/tui/components/OverviewView.d.ts.map +1 -0
  155. package/dist/tui/components/OverviewView.js +24 -0
  156. package/dist/tui/components/OverviewView.js.map +1 -0
  157. package/dist/tui/components/OverviewView.jsx +79 -0
  158. package/dist/tui/components/OverviewView.jsx.map +1 -0
  159. package/dist/tui/components/StatsView.d.ts +12 -0
  160. package/dist/tui/components/StatsView.d.ts.map +1 -0
  161. package/dist/tui/components/StatsView.js +43 -0
  162. package/dist/tui/components/StatsView.js.map +1 -0
  163. package/dist/tui/components/StatsView.jsx +180 -0
  164. package/dist/tui/components/StatsView.jsx.map +1 -0
  165. package/dist/tui/components/TokenBreakdown.d.ts +14 -0
  166. package/dist/tui/components/TokenBreakdown.d.ts.map +1 -0
  167. package/dist/tui/components/TokenBreakdown.jsx +27 -0
  168. package/dist/tui/components/TokenBreakdown.jsx.map +1 -0
  169. package/dist/tui/components/index.d.ts +16 -0
  170. package/dist/tui/components/index.d.ts.map +1 -0
  171. package/dist/tui/components/index.js +13 -0
  172. package/dist/tui/components/index.js.map +1 -0
  173. package/dist/tui/config/settings.d.ts +12 -0
  174. package/dist/tui/config/settings.d.ts.map +1 -0
  175. package/dist/tui/config/settings.js +105 -0
  176. package/dist/tui/config/settings.js.map +1 -0
  177. package/dist/tui/config/themes.d.ts +15 -0
  178. package/dist/tui/config/themes.d.ts.map +1 -0
  179. package/dist/tui/config/themes.js +82 -0
  180. package/dist/tui/config/themes.js.map +1 -0
  181. package/dist/tui/hooks/useData.d.ts +17 -0
  182. package/dist/tui/hooks/useData.d.ts.map +1 -0
  183. package/dist/tui/hooks/useData.js +430 -0
  184. package/dist/tui/hooks/useData.js.map +1 -0
  185. package/dist/tui/index.d.ts +4 -0
  186. package/dist/tui/index.d.ts.map +1 -0
  187. package/dist/tui/index.js +8 -0
  188. package/dist/tui/index.js.map +1 -0
  189. package/dist/tui/index.jsx +35 -0
  190. package/dist/tui/index.jsx.map +1 -0
  191. package/dist/tui/types/index.d.ts +133 -0
  192. package/dist/tui/types/index.d.ts.map +1 -0
  193. package/dist/tui/types/index.js +21 -0
  194. package/dist/tui/types/index.js.map +1 -0
  195. package/dist/tui/utils/cleanup.d.ts +22 -0
  196. package/dist/tui/utils/cleanup.d.ts.map +1 -0
  197. package/dist/tui/utils/cleanup.js +59 -0
  198. package/dist/tui/utils/cleanup.js.map +1 -0
  199. package/dist/tui/utils/colors.d.ts +18 -0
  200. package/dist/tui/utils/colors.d.ts.map +1 -0
  201. package/dist/tui/utils/colors.js +55 -0
  202. package/dist/tui/utils/colors.js.map +1 -0
  203. package/dist/tui/utils/format.d.ts +7 -0
  204. package/dist/tui/utils/format.d.ts.map +1 -0
  205. package/dist/tui/utils/format.js +45 -0
  206. package/dist/tui/utils/format.js.map +1 -0
  207. package/dist/tui/utils/responsive.d.ts +5 -0
  208. package/dist/tui/utils/responsive.d.ts.map +1 -0
  209. package/dist/tui/utils/responsive.js +5 -0
  210. package/dist/tui/utils/responsive.js.map +1 -0
  211. 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