@ottocode/web-sdk 0.1.278 → 0.1.279

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.
@@ -326,6 +326,15 @@ function hasPlatformOpenUrl() {
326
326
  function hasPlatformSystemFonts() {
327
327
  return !!getPlatformWindow()?.OTTO_LIST_SYSTEM_FONTS;
328
328
  }
329
+ function isPlatformDesktop() {
330
+ if (typeof window === "undefined")
331
+ return false;
332
+ try {
333
+ return "__TAURI__" in window || "__TAURI_INTERNALS__" in window || "__TAURI_METADATA__" in window;
334
+ } catch {
335
+ return false;
336
+ }
337
+ }
329
338
 
330
339
  // src/lib/open-url.ts
331
340
  function openUrl(url) {
@@ -1941,6 +1950,30 @@ var skillsMixin = {
1941
1950
  }
1942
1951
  };
1943
1952
 
1953
+ // src/lib/api-client/usage.ts
1954
+ import {
1955
+ getUsageStats as apiGetUsageStats,
1956
+ getGlobalUsageStats as apiGetGlobalUsageStats
1957
+ } from "@ottocode/api";
1958
+ var usageMixin = {
1959
+ async getUsageStats() {
1960
+ const { data, error } = await apiGetUsageStats();
1961
+ if (error)
1962
+ throw new Error(extractErrorMessage(error));
1963
+ if (!data)
1964
+ throw new Error("Empty response from /v1/usage/stats");
1965
+ return data;
1966
+ },
1967
+ async getGlobalUsageStats() {
1968
+ const { data, error } = await apiGetGlobalUsageStats();
1969
+ if (error)
1970
+ throw new Error(extractErrorMessage(error));
1971
+ if (!data)
1972
+ throw new Error("Empty response from /v1/usage/stats/global");
1973
+ return data;
1974
+ }
1975
+ };
1976
+
1944
1977
  // src/lib/api-client/index.ts
1945
1978
  class ApiClient {
1946
1979
  getSessions = sessionsMixin.getSessions;
@@ -2031,6 +2064,8 @@ class ApiClient {
2031
2064
  getSkillFileContent = skillsMixin.getSkillFileContent;
2032
2065
  getSkillsConfig = skillsMixin.getSkillsConfig;
2033
2066
  updateSkillsConfig = skillsMixin.updateSkillsConfig;
2067
+ getUsageStats = usageMixin.getUsageStats;
2068
+ getGlobalUsageStats = usageMixin.getGlobalUsageStats;
2034
2069
  }
2035
2070
  var apiClient = new ApiClient;
2036
2071
 
@@ -2092,7 +2127,8 @@ var DEFAULT_FONT_FAMILY = "IBM Plex Mono";
2092
2127
  var DEFAULT_STORED_PREFERENCES = {
2093
2128
  vimMode: false,
2094
2129
  compactThread: true,
2095
- fontFamily: DEFAULT_FONT_FAMILY
2130
+ fontFamily: DEFAULT_FONT_FAMILY,
2131
+ smartEdges: true
2096
2132
  };
2097
2133
  function cssFontFamily(fontFamily) {
2098
2134
  const trimmed = fontFamily.trim();
@@ -2125,7 +2161,8 @@ function resolveInitialPreferences() {
2125
2161
  return {
2126
2162
  vimMode: typeof parsed.vimMode === "boolean" ? parsed.vimMode : DEFAULT_STORED_PREFERENCES.vimMode,
2127
2163
  compactThread: typeof parsed.compactThread === "boolean" ? parsed.compactThread : DEFAULT_STORED_PREFERENCES.compactThread,
2128
- fontFamily: typeof parsed.fontFamily === "string" && parsed.fontFamily.trim() ? parsed.fontFamily.trim() : DEFAULT_STORED_PREFERENCES.fontFamily
2164
+ fontFamily: typeof parsed.fontFamily === "string" && parsed.fontFamily.trim() ? parsed.fontFamily.trim() : DEFAULT_STORED_PREFERENCES.fontFamily,
2165
+ smartEdges: typeof parsed.smartEdges === "boolean" ? parsed.smartEdges : DEFAULT_STORED_PREFERENCES.smartEdges
2129
2166
  };
2130
2167
  }
2131
2168
  } catch (error) {
@@ -2180,6 +2217,9 @@ function usePreferences() {
2180
2217
  if (updates.fontFamily !== undefined) {
2181
2218
  localUpdates.fontFamily = updates.fontFamily.trim() || DEFAULT_FONT_FAMILY;
2182
2219
  }
2220
+ if (updates.smartEdges !== undefined) {
2221
+ localUpdates.smartEdges = updates.smartEdges;
2222
+ }
2183
2223
  if (Object.keys(localUpdates).length > 0) {
2184
2224
  updateStore(localUpdates);
2185
2225
  }
@@ -23748,7 +23788,8 @@ import {
23748
23788
  Check as Check11,
23749
23789
  Key,
23750
23790
  Type,
23751
- Sparkles as Sparkles6
23791
+ Sparkles as Sparkles6,
23792
+ BarChart3
23752
23793
  } from "lucide-react";
23753
23794
  import { QRCodeSVG } from "qrcode.react";
23754
23795
 
@@ -24580,6 +24621,7 @@ function PreferencesModal({ isOpen, onClose }) {
24580
24621
  const { data: config2 } = useConfig();
24581
24622
  const { preferences: preferences2, updatePreferences } = usePreferences();
24582
24623
  const updateDefaults = useUpdateDefaults();
24624
+ const isDesktop = isPlatformDesktop();
24583
24625
  return /* @__PURE__ */ jsx96(Modal, {
24584
24626
  isOpen,
24585
24627
  onClose,
@@ -24609,6 +24651,11 @@ function PreferencesModal({ isOpen, onClose }) {
24609
24651
  checked: preferences2.fullWidthContent,
24610
24652
  onChange: (checked) => updatePreferences({ fullWidthContent: checked })
24611
24653
  }),
24654
+ isDesktop ? /* @__PURE__ */ jsx96(ToggleRow, {
24655
+ label: "Smart Sidebar Edges",
24656
+ checked: preferences2.smartEdges,
24657
+ onChange: (checked) => updatePreferences({ smartEdges: checked })
24658
+ }) : null,
24612
24659
  /* @__PURE__ */ jsx96(FontPickerRow, {
24613
24660
  value: preferences2.fontFamily,
24614
24661
  onChange: (fontFamily) => updatePreferences({ fontFamily })
@@ -24693,7 +24740,9 @@ function PreferencesModal({ isOpen, onClose }) {
24693
24740
  })
24694
24741
  });
24695
24742
  }
24696
- var SettingsSidebar = memo34(function SettingsSidebar2() {
24743
+ var SettingsSidebar = memo34(function SettingsSidebar2({
24744
+ onOpenDashboard
24745
+ } = {}) {
24697
24746
  const isExpanded = useSettingsStore((state) => state.isExpanded);
24698
24747
  const collapseSidebar = useSettingsStore((state) => state.collapseSidebar);
24699
24748
  const [isPreferencesOpen, setIsPreferencesOpen] = useState43(false);
@@ -24850,6 +24899,35 @@ var SettingsSidebar = memo34(function SettingsSidebar2() {
24850
24899
  /* @__PURE__ */ jsx96(OttoRouterTopupModal, {})
24851
24900
  ]
24852
24901
  }),
24902
+ /* @__PURE__ */ jsxs84("button", {
24903
+ type: "button",
24904
+ onClick: () => {
24905
+ if (onOpenDashboard) {
24906
+ onOpenDashboard();
24907
+ return;
24908
+ }
24909
+ if (typeof window === "undefined")
24910
+ return;
24911
+ const basePathRaw = globalThis.OTTO_ROUTER_BASEPATH ?? "/";
24912
+ const basePath = basePathRaw.replace(/\/+$/, "");
24913
+ const target = `${basePath}/dashboard`.replace(/\/+/g, "/");
24914
+ window.location.assign(target || "/dashboard");
24915
+ },
24916
+ title: "Open usage dashboard",
24917
+ className: "group shrink-0 w-full h-12 px-3 flex items-center gap-2 bg-muted/20 hover:bg-muted/60 border-t border-border transition-colors text-left cursor-pointer",
24918
+ children: [
24919
+ /* @__PURE__ */ jsx96(BarChart3, {
24920
+ className: "w-4 h-4 text-muted-foreground group-hover:text-foreground transition-colors"
24921
+ }),
24922
+ /* @__PURE__ */ jsx96("span", {
24923
+ className: "text-sm flex-1 text-muted-foreground group-hover:text-foreground transition-colors",
24924
+ children: "Usage Dashboard"
24925
+ }),
24926
+ /* @__PURE__ */ jsx96(ChevronRight13, {
24927
+ className: "w-4 h-4 text-muted-foreground group-hover:text-foreground group-hover:translate-x-0.5 transition-all"
24928
+ })
24929
+ ]
24930
+ }),
24853
24931
  /* @__PURE__ */ jsxs84("button", {
24854
24932
  type: "button",
24855
24933
  onClick: () => setIsPreferencesOpen(true),
@@ -31497,11 +31575,970 @@ var OnboardingModal = memo52(function OnboardingModal2({
31497
31575
  ]
31498
31576
  });
31499
31577
  });
31578
+ // src/components/dashboard/UsageDashboard.tsx
31579
+ import { useCallback as useCallback35, useEffect as useEffect58, useMemo as useMemo31, useState as useState51 } from "react";
31580
+ import { AlertTriangle as AlertTriangle3, ArrowLeft as ArrowLeft2, Globe2 as Globe22, RefreshCw as RefreshCw12 } from "lucide-react";
31581
+ import { jsx as jsx116, jsxs as jsxs103, Fragment as Fragment44 } from "react/jsx-runtime";
31582
+ function formatNumber(n) {
31583
+ if (!Number.isFinite(n) || n === 0)
31584
+ return "0";
31585
+ if (Math.abs(n) >= 1e9)
31586
+ return `${(n / 1e9).toFixed(1)}B`;
31587
+ if (Math.abs(n) >= 1e6)
31588
+ return `${(n / 1e6).toFixed(1)}M`;
31589
+ if (Math.abs(n) >= 1000)
31590
+ return `${(n / 1000).toFixed(1)}k`;
31591
+ return n.toLocaleString();
31592
+ }
31593
+ function formatUsd(n) {
31594
+ if (!Number.isFinite(n) || n === 0)
31595
+ return "$0";
31596
+ if (n < 0.01)
31597
+ return `$${n.toFixed(4)}`;
31598
+ if (n < 1)
31599
+ return `$${n.toFixed(3)}`;
31600
+ if (n < 100)
31601
+ return `$${n.toFixed(2)}`;
31602
+ return `$${n.toFixed(0)}`;
31603
+ }
31604
+ function authLabel(t) {
31605
+ if (t === "oauth")
31606
+ return "oauth";
31607
+ if (t === "subscription")
31608
+ return "sub";
31609
+ if (t === "wallet")
31610
+ return "wallet";
31611
+ if (t === "api")
31612
+ return "api";
31613
+ return "—";
31614
+ }
31615
+ function authColor(t) {
31616
+ if (t === "oauth")
31617
+ return "text-emerald-400";
31618
+ if (t === "subscription")
31619
+ return "text-violet-400";
31620
+ if (t === "wallet")
31621
+ return "text-fuchsia-400";
31622
+ if (t === "api")
31623
+ return "text-sky-400";
31624
+ return "text-muted-foreground";
31625
+ }
31626
+ function DailyChart({ data }) {
31627
+ const [tab, setTab] = useState51("cost");
31628
+ const [hover, setHover] = useState51(null);
31629
+ const max = useMemo31(() => {
31630
+ if (tab === "tokens") {
31631
+ return data.reduce((m, d) => Math.max(m, d.inputTokens + d.outputTokens), 0);
31632
+ }
31633
+ return data.reduce((m, d) => Math.max(m, d.notionalCostUsd), 0);
31634
+ }, [data, tab]);
31635
+ if (data.length === 0) {
31636
+ return /* @__PURE__ */ jsx116("div", {
31637
+ className: "h-44 flex items-center justify-center text-xs text-muted-foreground",
31638
+ children: "No activity yet"
31639
+ });
31640
+ }
31641
+ const focus = hover != null ? data[hover] : data[data.length - 1];
31642
+ const focusValue = tab === "tokens" ? formatNumber(focus.inputTokens + focus.outputTokens) : formatUsd(focus.notionalCostUsd);
31643
+ const focusSub = tab === "tokens" ? `${formatNumber(focus.inputTokens)} in · ${formatNumber(focus.outputTokens)} out` : focus.costUsd > 0 ? `${formatUsd(focus.costUsd)} pay-as-you-go · ${formatUsd(focus.notionalCostUsd - focus.costUsd)} via plans` : `${formatUsd(focus.notionalCostUsd)} via plans`;
31644
+ return /* @__PURE__ */ jsxs103("div", {
31645
+ children: [
31646
+ /* @__PURE__ */ jsxs103("div", {
31647
+ className: "flex items-baseline justify-between gap-4 mb-4",
31648
+ children: [
31649
+ /* @__PURE__ */ jsxs103("div", {
31650
+ className: "min-w-0",
31651
+ children: [
31652
+ /* @__PURE__ */ jsx116("div", {
31653
+ className: "text-[10px] uppercase tracking-[0.12em] text-muted-foreground",
31654
+ children: focus.date
31655
+ }),
31656
+ /* @__PURE__ */ jsx116("div", {
31657
+ className: "text-xl font-semibold tabular-nums mt-0.5 truncate",
31658
+ children: focusValue
31659
+ }),
31660
+ /* @__PURE__ */ jsx116("div", {
31661
+ className: "text-[11px] text-muted-foreground tabular-nums mt-0.5 truncate",
31662
+ children: focusSub
31663
+ })
31664
+ ]
31665
+ }),
31666
+ /* @__PURE__ */ jsxs103("div", {
31667
+ className: "shrink-0 inline-flex p-0.5 rounded-md border border-border bg-muted/30 text-[11px]",
31668
+ children: [
31669
+ /* @__PURE__ */ jsx116("button", {
31670
+ type: "button",
31671
+ onClick: () => setTab("cost"),
31672
+ className: `px-2.5 py-1 rounded transition-colors ${tab === "cost" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
31673
+ children: "Cost"
31674
+ }),
31675
+ /* @__PURE__ */ jsx116("button", {
31676
+ type: "button",
31677
+ onClick: () => setTab("tokens"),
31678
+ className: `px-2.5 py-1 rounded transition-colors ${tab === "tokens" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
31679
+ children: "Tokens"
31680
+ })
31681
+ ]
31682
+ })
31683
+ ]
31684
+ }),
31685
+ tab === "cost" ? /* @__PURE__ */ jsx116(CostChart, {
31686
+ data,
31687
+ max,
31688
+ hover,
31689
+ onHover: setHover
31690
+ }) : /* @__PURE__ */ jsx116(TokenChart, {
31691
+ data,
31692
+ max,
31693
+ hover,
31694
+ onHover: setHover
31695
+ }),
31696
+ /* @__PURE__ */ jsxs103("div", {
31697
+ className: "mt-3 flex items-center justify-between text-[10px] text-muted-foreground font-mono",
31698
+ children: [
31699
+ /* @__PURE__ */ jsx116("span", {
31700
+ children: data[0]?.date
31701
+ }),
31702
+ tab === "cost" ? /* @__PURE__ */ jsxs103("span", {
31703
+ className: "flex items-center gap-3",
31704
+ children: [
31705
+ /* @__PURE__ */ jsx116(Dot, {
31706
+ color: "bg-sky-400",
31707
+ label: "api"
31708
+ }),
31709
+ /* @__PURE__ */ jsx116(Dot, {
31710
+ color: "bg-emerald-400/70",
31711
+ label: "oauth"
31712
+ }),
31713
+ /* @__PURE__ */ jsx116(Dot, {
31714
+ color: "bg-violet-400/70",
31715
+ label: "sub"
31716
+ })
31717
+ ]
31718
+ }) : /* @__PURE__ */ jsxs103("span", {
31719
+ className: "flex items-center gap-3",
31720
+ children: [
31721
+ /* @__PURE__ */ jsx116(Dot, {
31722
+ color: "bg-muted-foreground/60",
31723
+ label: "input"
31724
+ }),
31725
+ /* @__PURE__ */ jsx116(Dot, {
31726
+ color: "bg-foreground/80",
31727
+ label: "output"
31728
+ })
31729
+ ]
31730
+ }),
31731
+ /* @__PURE__ */ jsx116("span", {
31732
+ children: data[data.length - 1]?.date
31733
+ })
31734
+ ]
31735
+ })
31736
+ ]
31737
+ });
31738
+ }
31739
+ function CostChart({ data, max, hover, onHover }) {
31740
+ return /* @__PURE__ */ jsx116("div", {
31741
+ role: "img",
31742
+ "aria-label": "Daily cost chart",
31743
+ className: "flex items-end gap-[3px] h-44 select-none",
31744
+ onMouseLeave: () => onHover(null),
31745
+ children: data.map((d, i) => {
31746
+ const notional = d.notionalCostUsd;
31747
+ const heightPct = max > 0 ? Math.max(2, notional / max * 100) : 2;
31748
+ const apiPct = notional > 0 ? d.notionalByAuth.api / notional * 100 : 0;
31749
+ const oauthPct = notional > 0 ? d.notionalByAuth.oauth / notional * 100 : 0;
31750
+ const subPct = notional > 0 ? d.notionalByAuth.subscription / notional * 100 : 0;
31751
+ const active = hover === i;
31752
+ return /* @__PURE__ */ jsx116("button", {
31753
+ type: "button",
31754
+ onMouseEnter: () => onHover(i),
31755
+ onFocus: () => onHover(i),
31756
+ className: "flex-1 h-full flex flex-col justify-end min-w-0 group cursor-default",
31757
+ children: /* @__PURE__ */ jsxs103("div", {
31758
+ className: `w-full rounded-sm overflow-hidden flex flex-col-reverse transition-all ${active ? "opacity-100" : "opacity-90 group-hover:opacity-100"}`,
31759
+ style: { height: `${heightPct}%` },
31760
+ children: [
31761
+ apiPct > 0 && /* @__PURE__ */ jsx116("div", {
31762
+ className: "bg-sky-400",
31763
+ style: { height: `${apiPct}%` }
31764
+ }),
31765
+ oauthPct > 0 && /* @__PURE__ */ jsx116("div", {
31766
+ className: "bg-emerald-400/70",
31767
+ style: {
31768
+ height: `${oauthPct}%`,
31769
+ backgroundImage: "repeating-linear-gradient(45deg, rgba(255,255,255,0.08) 0 2px, transparent 2px 4px)"
31770
+ }
31771
+ }),
31772
+ subPct > 0 && /* @__PURE__ */ jsx116("div", {
31773
+ className: "bg-violet-400/70",
31774
+ style: {
31775
+ height: `${subPct}%`,
31776
+ backgroundImage: "repeating-linear-gradient(45deg, rgba(255,255,255,0.08) 0 2px, transparent 2px 4px)"
31777
+ }
31778
+ }),
31779
+ notional === 0 && d.messages > 0 && /* @__PURE__ */ jsx116("div", {
31780
+ className: "bg-muted-foreground/30 h-full"
31781
+ })
31782
+ ]
31783
+ })
31784
+ }, d.date);
31785
+ })
31786
+ });
31787
+ }
31788
+ function TokenChart({ data, max, hover, onHover }) {
31789
+ return /* @__PURE__ */ jsx116("div", {
31790
+ role: "img",
31791
+ "aria-label": "Daily tokens chart",
31792
+ className: "flex items-end gap-[3px] h-44 select-none",
31793
+ onMouseLeave: () => onHover(null),
31794
+ children: data.map((d, i) => {
31795
+ const total = d.inputTokens + d.outputTokens;
31796
+ const heightPct = max > 0 ? Math.max(2, total / max * 100) : 2;
31797
+ const inputPct = total > 0 ? d.inputTokens / total * 100 : 0;
31798
+ const outputPct = total > 0 ? d.outputTokens / total * 100 : 0;
31799
+ const active = hover === i;
31800
+ return /* @__PURE__ */ jsx116("button", {
31801
+ type: "button",
31802
+ onMouseEnter: () => onHover(i),
31803
+ onFocus: () => onHover(i),
31804
+ className: "flex-1 h-full flex flex-col justify-end min-w-0 group cursor-default",
31805
+ children: /* @__PURE__ */ jsxs103("div", {
31806
+ className: `w-full rounded-sm overflow-hidden flex flex-col-reverse transition-all ${active ? "opacity-100" : "opacity-90 group-hover:opacity-100"}`,
31807
+ style: { height: `${heightPct}%` },
31808
+ children: [
31809
+ inputPct > 0 && /* @__PURE__ */ jsx116("div", {
31810
+ className: "bg-muted-foreground/60",
31811
+ style: { height: `${inputPct}%` }
31812
+ }),
31813
+ outputPct > 0 && /* @__PURE__ */ jsx116("div", {
31814
+ className: "bg-foreground/80",
31815
+ style: { height: `${outputPct}%` }
31816
+ })
31817
+ ]
31818
+ })
31819
+ }, d.date);
31820
+ })
31821
+ });
31822
+ }
31823
+ function Dot({ color, label }) {
31824
+ return /* @__PURE__ */ jsxs103("span", {
31825
+ className: "flex items-center gap-1",
31826
+ children: [
31827
+ /* @__PURE__ */ jsx116("span", {
31828
+ className: `size-1.5 rounded-full ${color}`
31829
+ }),
31830
+ /* @__PURE__ */ jsx116("span", {
31831
+ children: label
31832
+ })
31833
+ ]
31834
+ });
31835
+ }
31836
+ function SplitRow({
31837
+ color,
31838
+ label,
31839
+ msgs,
31840
+ value,
31841
+ total
31842
+ }) {
31843
+ const pct = total > 0 ? msgs / total * 100 : 0;
31844
+ return /* @__PURE__ */ jsxs103("div", {
31845
+ className: "flex items-center gap-3 py-2",
31846
+ children: [
31847
+ /* @__PURE__ */ jsx116("span", {
31848
+ className: "text-xs text-muted-foreground w-20 shrink-0",
31849
+ children: label
31850
+ }),
31851
+ /* @__PURE__ */ jsx116("div", {
31852
+ className: "flex-1 h-1.5 rounded-full bg-muted/40 overflow-hidden",
31853
+ children: /* @__PURE__ */ jsx116("div", {
31854
+ className: `h-full ${color} transition-all duration-500`,
31855
+ style: { width: `${pct}%` }
31856
+ })
31857
+ }),
31858
+ /* @__PURE__ */ jsxs103("span", {
31859
+ className: "text-[11px] text-muted-foreground tabular-nums w-20 text-right shrink-0",
31860
+ children: [
31861
+ formatNumber(msgs),
31862
+ " msgs"
31863
+ ]
31864
+ }),
31865
+ /* @__PURE__ */ jsx116("span", {
31866
+ className: "text-sm font-medium tabular-nums w-20 text-right shrink-0 text-foreground",
31867
+ children: formatUsd(value)
31868
+ })
31869
+ ]
31870
+ });
31871
+ }
31872
+ function AuthSplit({ stats }) {
31873
+ const total = stats.totals.messagesByAuth.api + stats.totals.messagesByAuth.oauth + stats.totals.messagesByAuth.subscription;
31874
+ if (total === 0)
31875
+ return /* @__PURE__ */ jsx116("div", {
31876
+ className: "text-xs text-muted-foreground",
31877
+ children: "No activity yet."
31878
+ });
31879
+ const notionalByAuth = { oauth: 0, api: 0, subscription: 0 };
31880
+ for (const p of stats.providers) {
31881
+ if (p.authType === "oauth")
31882
+ notionalByAuth.oauth += p.notionalCostUsd;
31883
+ else if (p.authType === "subscription" || p.authType === "wallet")
31884
+ notionalByAuth.subscription += p.notionalCostUsd;
31885
+ else if (p.authType === "api")
31886
+ notionalByAuth.api += p.notionalCostUsd;
31887
+ }
31888
+ const rows = [
31889
+ {
31890
+ key: "api",
31891
+ color: "bg-sky-400",
31892
+ label: "API key",
31893
+ msgs: stats.totals.messagesByAuth.api,
31894
+ value: notionalByAuth.api
31895
+ },
31896
+ {
31897
+ key: "oauth",
31898
+ color: "bg-emerald-400",
31899
+ label: "OAuth",
31900
+ msgs: stats.totals.messagesByAuth.oauth,
31901
+ value: notionalByAuth.oauth
31902
+ },
31903
+ {
31904
+ key: "subscription",
31905
+ color: "bg-violet-400",
31906
+ label: "Subscription",
31907
+ msgs: stats.totals.messagesByAuth.subscription,
31908
+ value: notionalByAuth.subscription
31909
+ }
31910
+ ].sort((a, b) => b.value - a.value || b.msgs - a.msgs);
31911
+ return /* @__PURE__ */ jsx116("div", {
31912
+ className: "space-y-0.5",
31913
+ children: rows.map((r) => /* @__PURE__ */ jsx116(SplitRow, {
31914
+ total,
31915
+ color: r.color,
31916
+ label: r.label,
31917
+ msgs: r.msgs,
31918
+ value: r.value
31919
+ }, r.key))
31920
+ });
31921
+ }
31922
+ function ProviderList({ providers }) {
31923
+ if (providers.length === 0) {
31924
+ return /* @__PURE__ */ jsx116("div", {
31925
+ className: "py-10 text-center text-xs text-muted-foreground",
31926
+ children: "No usage yet"
31927
+ });
31928
+ }
31929
+ return /* @__PURE__ */ jsx116("div", {
31930
+ className: "divide-y divide-border/60",
31931
+ children: providers.map((p) => /* @__PURE__ */ jsxs103("div", {
31932
+ className: "flex items-center gap-3 py-2.5 px-1 hover:bg-muted/20 transition-colors",
31933
+ children: [
31934
+ /* @__PURE__ */ jsx116("div", {
31935
+ className: "size-7 shrink-0 rounded-md bg-muted/30 flex items-center justify-center text-muted-foreground",
31936
+ children: /* @__PURE__ */ jsx116(ProviderLogo, {
31937
+ provider: p.provider,
31938
+ size: 16
31939
+ })
31940
+ }),
31941
+ /* @__PURE__ */ jsxs103("div", {
31942
+ className: "flex-1 min-w-0",
31943
+ children: [
31944
+ /* @__PURE__ */ jsx116("div", {
31945
+ className: "text-sm text-foreground truncate capitalize",
31946
+ children: p.provider
31947
+ }),
31948
+ /* @__PURE__ */ jsxs103("div", {
31949
+ className: "text-[10px] text-muted-foreground tabular-nums",
31950
+ children: [
31951
+ formatNumber(p.messages),
31952
+ " msgs ·",
31953
+ " ",
31954
+ /* @__PURE__ */ jsx116("span", {
31955
+ className: authColor(p.authType),
31956
+ children: authLabel(p.authType)
31957
+ })
31958
+ ]
31959
+ })
31960
+ ]
31961
+ }),
31962
+ /* @__PURE__ */ jsxs103("div", {
31963
+ className: "text-right tabular-nums shrink-0",
31964
+ children: [
31965
+ /* @__PURE__ */ jsx116("div", {
31966
+ className: "text-sm font-medium text-foreground",
31967
+ children: formatUsd(p.notionalCostUsd)
31968
+ }),
31969
+ /* @__PURE__ */ jsxs103("div", {
31970
+ className: "text-[10px] text-muted-foreground",
31971
+ children: [
31972
+ formatNumber(p.inputTokens + p.outputTokens),
31973
+ " tok"
31974
+ ]
31975
+ })
31976
+ ]
31977
+ })
31978
+ ]
31979
+ }, p.provider))
31980
+ });
31981
+ }
31982
+ function ModelList({ models }) {
31983
+ if (models.length === 0) {
31984
+ return /* @__PURE__ */ jsx116("div", {
31985
+ className: "py-10 text-center text-xs text-muted-foreground",
31986
+ children: "No model usage yet"
31987
+ });
31988
+ }
31989
+ return /* @__PURE__ */ jsx116("div", {
31990
+ className: "divide-y divide-border/60",
31991
+ children: models.slice(0, 12).map((m) => /* @__PURE__ */ jsxs103("div", {
31992
+ className: "flex items-center gap-3 py-2.5 px-1 hover:bg-muted/20 transition-colors",
31993
+ children: [
31994
+ /* @__PURE__ */ jsx116("div", {
31995
+ className: "size-7 shrink-0 rounded-md bg-muted/30 flex items-center justify-center text-muted-foreground",
31996
+ children: /* @__PURE__ */ jsx116(ProviderLogo, {
31997
+ provider: m.provider,
31998
+ size: 14
31999
+ })
32000
+ }),
32001
+ /* @__PURE__ */ jsxs103("div", {
32002
+ className: "flex-1 min-w-0",
32003
+ children: [
32004
+ /* @__PURE__ */ jsx116("div", {
32005
+ className: "text-sm text-foreground truncate font-mono",
32006
+ children: m.model
32007
+ }),
32008
+ /* @__PURE__ */ jsxs103("div", {
32009
+ className: "text-[10px] text-muted-foreground tabular-nums",
32010
+ children: [
32011
+ formatNumber(m.messages),
32012
+ " msgs ·",
32013
+ " ",
32014
+ formatNumber(m.inputTokens + m.outputTokens),
32015
+ " tok"
32016
+ ]
32017
+ })
32018
+ ]
32019
+ }),
32020
+ /* @__PURE__ */ jsxs103("div", {
32021
+ className: "text-right tabular-nums shrink-0",
32022
+ children: [
32023
+ /* @__PURE__ */ jsx116("div", {
32024
+ className: "text-sm font-medium text-foreground",
32025
+ children: formatUsd(m.notionalCostUsd)
32026
+ }),
32027
+ /* @__PURE__ */ jsx116("div", {
32028
+ className: `text-[10px] ${authColor(m.authType)}`,
32029
+ children: authLabel(m.authType)
32030
+ })
32031
+ ]
32032
+ })
32033
+ ]
32034
+ }, `${m.provider}-${m.model}`))
32035
+ });
32036
+ }
32037
+ function ProjectList({
32038
+ projects
32039
+ }) {
32040
+ if (projects.included.length === 0 && projects.unavailable.length === 0) {
32041
+ return /* @__PURE__ */ jsx116("div", {
32042
+ className: "py-10 text-center text-xs text-muted-foreground",
32043
+ children: "No projects registered yet"
32044
+ });
32045
+ }
32046
+ return /* @__PURE__ */ jsxs103("div", {
32047
+ className: "divide-y divide-border/60",
32048
+ children: [
32049
+ projects.included.map((p) => /* @__PURE__ */ jsxs103("div", {
32050
+ className: "flex items-center gap-3 py-2.5 px-1 hover:bg-muted/20 transition-colors",
32051
+ children: [
32052
+ /* @__PURE__ */ jsxs103("div", {
32053
+ className: "flex-1 min-w-0",
32054
+ children: [
32055
+ /* @__PURE__ */ jsx116("div", {
32056
+ className: "text-sm text-foreground truncate",
32057
+ children: p.name
32058
+ }),
32059
+ /* @__PURE__ */ jsx116("div", {
32060
+ className: "text-[10px] text-muted-foreground tabular-nums truncate font-mono",
32061
+ children: p.path
32062
+ })
32063
+ ]
32064
+ }),
32065
+ /* @__PURE__ */ jsxs103("div", {
32066
+ className: "text-right tabular-nums shrink-0",
32067
+ children: [
32068
+ /* @__PURE__ */ jsx116("div", {
32069
+ className: "text-sm font-medium text-foreground",
32070
+ children: formatUsd(p.notionalCostUsd)
32071
+ }),
32072
+ /* @__PURE__ */ jsxs103("div", {
32073
+ className: "text-[10px] text-muted-foreground",
32074
+ children: [
32075
+ formatNumber(p.messages),
32076
+ " msgs"
32077
+ ]
32078
+ })
32079
+ ]
32080
+ })
32081
+ ]
32082
+ }, p.id)),
32083
+ projects.unavailable.map((p) => /* @__PURE__ */ jsxs103("div", {
32084
+ className: "flex items-center gap-3 py-2.5 px-1 opacity-60",
32085
+ title: p.reason,
32086
+ children: [
32087
+ /* @__PURE__ */ jsx116(AlertTriangle3, {
32088
+ className: "size-3.5 text-amber-400 shrink-0"
32089
+ }),
32090
+ /* @__PURE__ */ jsxs103("div", {
32091
+ className: "flex-1 min-w-0",
32092
+ children: [
32093
+ /* @__PURE__ */ jsx116("div", {
32094
+ className: "text-sm text-foreground/80 truncate",
32095
+ children: p.name
32096
+ }),
32097
+ /* @__PURE__ */ jsxs103("div", {
32098
+ className: "text-[10px] text-muted-foreground truncate font-mono",
32099
+ children: [
32100
+ p.path,
32101
+ " · ",
32102
+ p.reason
32103
+ ]
32104
+ })
32105
+ ]
32106
+ }),
32107
+ /* @__PURE__ */ jsx116("div", {
32108
+ className: "text-[10px] text-amber-400 shrink-0",
32109
+ children: "unavailable"
32110
+ })
32111
+ ]
32112
+ }, p.id))
32113
+ ]
32114
+ });
32115
+ }
32116
+ function Section({
32117
+ title,
32118
+ subtitle,
32119
+ right,
32120
+ children,
32121
+ className = ""
32122
+ }) {
32123
+ return /* @__PURE__ */ jsxs103("section", {
32124
+ className: `rounded-2xl border border-border bg-card/60 backdrop-blur-sm ${className}`,
32125
+ children: [
32126
+ (title || right) && /* @__PURE__ */ jsxs103("header", {
32127
+ className: "px-5 pt-4 pb-3 flex items-center justify-between gap-3",
32128
+ children: [
32129
+ /* @__PURE__ */ jsxs103("div", {
32130
+ className: "min-w-0",
32131
+ children: [
32132
+ title && /* @__PURE__ */ jsx116("h2", {
32133
+ className: "text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground",
32134
+ children: title
32135
+ }),
32136
+ subtitle && /* @__PURE__ */ jsx116("p", {
32137
+ className: "text-xs text-muted-foreground/70 mt-0.5",
32138
+ children: subtitle
32139
+ })
32140
+ ]
32141
+ }),
32142
+ right
32143
+ ]
32144
+ }),
32145
+ /* @__PURE__ */ jsx116("div", {
32146
+ className: "px-5 pb-5",
32147
+ children
32148
+ })
32149
+ ]
32150
+ });
32151
+ }
32152
+ function UsageDashboard({ onBack }) {
32153
+ const [stats, setStats] = useState51(null);
32154
+ const [loading, setLoading] = useState51(false);
32155
+ const [error, setError] = useState51(null);
32156
+ const [scope, setScope] = useState51("project");
32157
+ const fetchStats = useCallback35(async () => {
32158
+ setLoading(true);
32159
+ setError(null);
32160
+ try {
32161
+ const data = scope === "global" ? await apiClient.getGlobalUsageStats() : await apiClient.getUsageStats();
32162
+ setStats(data);
32163
+ } catch (e) {
32164
+ setError(e instanceof Error ? e.message : "Failed to load usage stats");
32165
+ } finally {
32166
+ setLoading(false);
32167
+ }
32168
+ }, [scope]);
32169
+ useEffect58(() => {
32170
+ fetchStats();
32171
+ }, [fetchStats]);
32172
+ const handleBack = useCallback35(() => {
32173
+ if (onBack)
32174
+ return onBack();
32175
+ if (typeof window === "undefined")
32176
+ return;
32177
+ if (window.history.length > 1)
32178
+ window.history.back();
32179
+ else
32180
+ window.location.assign("/");
32181
+ }, [onBack]);
32182
+ const projectName = useMemo31(() => {
32183
+ if (scope === "global") {
32184
+ const included = stats?.projects?.included.length ?? 0;
32185
+ const unavailable = stats?.projects?.unavailable.length ?? 0;
32186
+ const total = included + unavailable;
32187
+ if (total === 0)
32188
+ return "all projects";
32189
+ return unavailable > 0 ? `${included} of ${total} projects` : `${total} project${total === 1 ? "" : "s"}`;
32190
+ }
32191
+ if (!stats?.project)
32192
+ return "";
32193
+ const parts = stats.project.split("/").filter(Boolean);
32194
+ return parts[parts.length - 1] ?? stats.project;
32195
+ }, [scope, stats?.project, stats?.projects]);
32196
+ const totalSpend = stats?.totals.costUsd ?? 0;
32197
+ const totalMessages = stats?.totals.messages ?? 0;
32198
+ const totalTokens = (stats?.totals.inputTokens ?? 0) + (stats?.totals.outputTokens ?? 0);
32199
+ return /* @__PURE__ */ jsxs103("div", {
32200
+ className: "fixed inset-0 flex flex-col bg-background text-foreground",
32201
+ children: [
32202
+ /* @__PURE__ */ jsx116("header", {
32203
+ className: "shrink-0 h-10 border-b border-border/60 bg-background/80 backdrop-blur",
32204
+ children: /* @__PURE__ */ jsxs103("div", {
32205
+ className: "h-full max-w-5xl mx-auto px-6 flex items-center justify-between gap-3",
32206
+ children: [
32207
+ /* @__PURE__ */ jsxs103("div", {
32208
+ className: "flex items-center gap-2 min-w-0",
32209
+ children: [
32210
+ /* @__PURE__ */ jsx116("button", {
32211
+ type: "button",
32212
+ onClick: handleBack,
32213
+ className: "inline-flex items-center justify-center size-6 rounded text-muted-foreground hover:text-foreground hover:bg-muted/40 transition-colors",
32214
+ title: "Back",
32215
+ "aria-label": "Back",
32216
+ children: /* @__PURE__ */ jsx116(ArrowLeft2, {
32217
+ className: "size-3.5"
32218
+ })
32219
+ }),
32220
+ /* @__PURE__ */ jsxs103("div", {
32221
+ className: "min-w-0 flex items-baseline gap-1.5 text-xs",
32222
+ children: [
32223
+ /* @__PURE__ */ jsx116("span", {
32224
+ className: "text-muted-foreground/70 uppercase tracking-[0.1em] text-[10px]",
32225
+ children: "Usage"
32226
+ }),
32227
+ /* @__PURE__ */ jsx116("span", {
32228
+ className: "text-muted-foreground/40",
32229
+ children: "/"
32230
+ }),
32231
+ /* @__PURE__ */ jsx116("span", {
32232
+ className: "font-medium truncate text-foreground",
32233
+ children: projectName || "—"
32234
+ })
32235
+ ]
32236
+ })
32237
+ ]
32238
+ }),
32239
+ /* @__PURE__ */ jsxs103("div", {
32240
+ className: "flex items-center gap-1.5",
32241
+ children: [
32242
+ /* @__PURE__ */ jsxs103("div", {
32243
+ className: "inline-flex p-0.5 rounded-md border border-border bg-muted/30 text-[11px]",
32244
+ children: [
32245
+ /* @__PURE__ */ jsx116("button", {
32246
+ type: "button",
32247
+ onClick: () => setScope("project"),
32248
+ className: `px-2 py-0.5 rounded transition-colors ${scope === "project" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
32249
+ children: "Project"
32250
+ }),
32251
+ /* @__PURE__ */ jsxs103("button", {
32252
+ type: "button",
32253
+ onClick: () => setScope("global"),
32254
+ className: `px-2 py-0.5 rounded transition-colors inline-flex items-center gap-1 ${scope === "global" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
32255
+ children: [
32256
+ /* @__PURE__ */ jsx116(Globe22, {
32257
+ className: "size-3"
32258
+ }),
32259
+ "Global"
32260
+ ]
32261
+ })
32262
+ ]
32263
+ }),
32264
+ /* @__PURE__ */ jsx116("button", {
32265
+ type: "button",
32266
+ onClick: () => void fetchStats(),
32267
+ disabled: loading,
32268
+ className: "inline-flex items-center justify-center size-6 rounded text-muted-foreground hover:text-foreground hover:bg-muted/40 transition-colors disabled:opacity-50",
32269
+ title: "Refresh",
32270
+ "aria-label": "Refresh",
32271
+ children: /* @__PURE__ */ jsx116(RefreshCw12, {
32272
+ className: `size-3.5 ${loading ? "animate-spin" : ""}`
32273
+ })
32274
+ })
32275
+ ]
32276
+ })
32277
+ ]
32278
+ })
32279
+ }),
32280
+ /* @__PURE__ */ jsx116("main", {
32281
+ className: "flex-1 min-h-0 overflow-y-auto overscroll-contain",
32282
+ children: /* @__PURE__ */ jsxs103("div", {
32283
+ className: "max-w-5xl mx-auto px-6 py-8 space-y-5",
32284
+ children: [
32285
+ error && /* @__PURE__ */ jsx116("div", {
32286
+ className: "rounded-xl border border-destructive/40 bg-destructive/10 p-3 text-xs text-destructive",
32287
+ children: error
32288
+ }),
32289
+ loading && !stats && /* @__PURE__ */ jsx116("div", {
32290
+ className: "py-24 text-center text-xs text-muted-foreground",
32291
+ children: "loading…"
32292
+ }),
32293
+ stats && /* @__PURE__ */ jsxs103(Fragment44, {
32294
+ children: [
32295
+ /* @__PURE__ */ jsxs103("div", {
32296
+ className: "rounded-2xl border border-border bg-gradient-to-br from-card to-card/40 px-6 py-7",
32297
+ children: [
32298
+ /* @__PURE__ */ jsxs103("div", {
32299
+ className: "grid grid-cols-1 md:grid-cols-[1.4fr_1fr_1fr] gap-6 md:gap-10 items-center",
32300
+ children: [
32301
+ /* @__PURE__ */ jsxs103("div", {
32302
+ children: [
32303
+ /* @__PURE__ */ jsx116("div", {
32304
+ className: "text-[10px] uppercase tracking-[0.18em] text-muted-foreground",
32305
+ children: "Token value · API rates"
32306
+ }),
32307
+ /* @__PURE__ */ jsx116("div", {
32308
+ className: "mt-2 text-5xl font-semibold tabular-nums tracking-tight",
32309
+ children: formatUsd(stats.totals.notionalCostUsd)
32310
+ }),
32311
+ /* @__PURE__ */ jsxs103("div", {
32312
+ className: "mt-2 text-[11px] text-muted-foreground tabular-nums",
32313
+ children: [
32314
+ "all ",
32315
+ formatNumber(stats.totals.messages),
32316
+ " msgs valued at catalog API pricing"
32317
+ ]
32318
+ })
32319
+ ]
32320
+ }),
32321
+ /* @__PURE__ */ jsxs103("div", {
32322
+ className: "md:border-l md:border-border/60 md:pl-6",
32323
+ children: [
32324
+ /* @__PURE__ */ jsx116("div", {
32325
+ className: "text-[10px] uppercase tracking-[0.18em] text-muted-foreground",
32326
+ children: "API spend"
32327
+ }),
32328
+ /* @__PURE__ */ jsx116("div", {
32329
+ className: "mt-2 text-3xl font-semibold tabular-nums tracking-tight",
32330
+ children: formatUsd(totalSpend)
32331
+ }),
32332
+ /* @__PURE__ */ jsxs103("div", {
32333
+ className: "mt-2 text-[11px] text-muted-foreground tabular-nums",
32334
+ children: [
32335
+ formatNumber(stats.totals.messagesByAuth.api),
32336
+ " ",
32337
+ "pay-as-you-go msgs"
32338
+ ]
32339
+ })
32340
+ ]
32341
+ }),
32342
+ /* @__PURE__ */ jsxs103("div", {
32343
+ className: "md:border-l md:border-border/60 md:pl-6",
32344
+ children: [
32345
+ /* @__PURE__ */ jsx116("div", {
32346
+ className: "text-[10px] uppercase tracking-[0.18em] text-emerald-400/80",
32347
+ children: "OAuth · plan value"
32348
+ }),
32349
+ /* @__PURE__ */ jsx116("div", {
32350
+ className: "mt-2 text-3xl font-semibold tabular-nums tracking-tight text-emerald-400",
32351
+ children: formatUsd(stats.providers.filter((p) => p.authType === "oauth").reduce((s, p) => s + p.notionalCostUsd, 0))
32352
+ }),
32353
+ /* @__PURE__ */ jsxs103("div", {
32354
+ className: "mt-2 text-[11px] text-muted-foreground tabular-nums",
32355
+ children: [
32356
+ formatNumber(stats.totals.messagesByAuth.oauth),
32357
+ " msgs via plan subscriptions"
32358
+ ]
32359
+ })
32360
+ ]
32361
+ })
32362
+ ]
32363
+ }),
32364
+ /* @__PURE__ */ jsxs103("div", {
32365
+ className: "mt-6 pt-5 border-t border-border/40 grid grid-cols-3 gap-6 text-[11px] text-muted-foreground",
32366
+ children: [
32367
+ /* @__PURE__ */ jsxs103("div", {
32368
+ children: [
32369
+ /* @__PURE__ */ jsx116("div", {
32370
+ className: "uppercase tracking-[0.14em] text-muted-foreground/70",
32371
+ children: "Messages"
32372
+ }),
32373
+ /* @__PURE__ */ jsxs103("div", {
32374
+ className: "mt-1 text-sm text-foreground tabular-nums",
32375
+ children: [
32376
+ formatNumber(totalMessages),
32377
+ " ",
32378
+ /* @__PURE__ */ jsxs103("span", {
32379
+ className: "text-muted-foreground/70",
32380
+ children: [
32381
+ "· ",
32382
+ formatNumber(stats.totals.sessions),
32383
+ " sessions"
32384
+ ]
32385
+ })
32386
+ ]
32387
+ })
32388
+ ]
32389
+ }),
32390
+ /* @__PURE__ */ jsxs103("div", {
32391
+ children: [
32392
+ /* @__PURE__ */ jsx116("div", {
32393
+ className: "uppercase tracking-[0.14em] text-muted-foreground/70",
32394
+ children: "Tokens"
32395
+ }),
32396
+ /* @__PURE__ */ jsxs103("div", {
32397
+ className: "mt-1 text-sm text-foreground tabular-nums",
32398
+ children: [
32399
+ formatNumber(totalTokens),
32400
+ " ",
32401
+ /* @__PURE__ */ jsxs103("span", {
32402
+ className: "text-muted-foreground/70",
32403
+ children: [
32404
+ "· ",
32405
+ formatNumber(stats.totals.inputTokens),
32406
+ " in /",
32407
+ " ",
32408
+ formatNumber(stats.totals.outputTokens),
32409
+ " out"
32410
+ ]
32411
+ })
32412
+ ]
32413
+ })
32414
+ ]
32415
+ }),
32416
+ /* @__PURE__ */ jsxs103("div", {
32417
+ children: [
32418
+ /* @__PURE__ */ jsx116("div", {
32419
+ className: "uppercase tracking-[0.14em] text-muted-foreground/70",
32420
+ children: "Mix"
32421
+ }),
32422
+ /* @__PURE__ */ jsxs103("div", {
32423
+ className: "mt-1 text-sm tabular-nums",
32424
+ children: [
32425
+ /* @__PURE__ */ jsxs103("span", {
32426
+ className: authColor("api"),
32427
+ children: [
32428
+ formatNumber(stats.totals.messagesByAuth.api),
32429
+ " api"
32430
+ ]
32431
+ }),
32432
+ stats.totals.messagesByAuth.oauth > 0 && /* @__PURE__ */ jsxs103(Fragment44, {
32433
+ children: [
32434
+ /* @__PURE__ */ jsx116("span", {
32435
+ className: "text-muted-foreground/40",
32436
+ children: " · "
32437
+ }),
32438
+ /* @__PURE__ */ jsxs103("span", {
32439
+ className: authColor("oauth"),
32440
+ children: [
32441
+ formatNumber(stats.totals.messagesByAuth.oauth),
32442
+ " ",
32443
+ "oauth"
32444
+ ]
32445
+ })
32446
+ ]
32447
+ }),
32448
+ stats.totals.messagesByAuth.subscription > 0 && /* @__PURE__ */ jsxs103(Fragment44, {
32449
+ children: [
32450
+ /* @__PURE__ */ jsx116("span", {
32451
+ className: "text-muted-foreground/40",
32452
+ children: " · "
32453
+ }),
32454
+ /* @__PURE__ */ jsxs103("span", {
32455
+ className: authColor("subscription"),
32456
+ children: [
32457
+ formatNumber(stats.totals.messagesByAuth.subscription),
32458
+ " ",
32459
+ "sub"
32460
+ ]
32461
+ })
32462
+ ]
32463
+ })
32464
+ ]
32465
+ })
32466
+ ]
32467
+ })
32468
+ ]
32469
+ })
32470
+ ]
32471
+ }),
32472
+ /* @__PURE__ */ jsx116(Section, {
32473
+ title: "How you're paying",
32474
+ subtitle: "OAuth & Subscription are flat-rate · not per-token",
32475
+ children: /* @__PURE__ */ jsx116(AuthSplit, {
32476
+ stats
32477
+ })
32478
+ }),
32479
+ /* @__PURE__ */ jsx116(Section, {
32480
+ title: "Daily activity",
32481
+ children: /* @__PURE__ */ jsx116(DailyChart, {
32482
+ data: stats.daily
32483
+ })
32484
+ }),
32485
+ /* @__PURE__ */ jsxs103("div", {
32486
+ className: "grid grid-cols-1 md:grid-cols-2 gap-5",
32487
+ children: [
32488
+ /* @__PURE__ */ jsx116(Section, {
32489
+ title: "By provider",
32490
+ children: /* @__PURE__ */ jsx116(ProviderList, {
32491
+ providers: stats.providers
32492
+ })
32493
+ }),
32494
+ /* @__PURE__ */ jsx116(Section, {
32495
+ title: "Top models",
32496
+ subtitle: stats.models.length > 12 ? `Showing 12 of ${stats.models.length}` : undefined,
32497
+ children: /* @__PURE__ */ jsx116(ModelList, {
32498
+ models: stats.models
32499
+ })
32500
+ })
32501
+ ]
32502
+ }),
32503
+ scope === "global" && stats.projects && /* @__PURE__ */ jsx116(Section, {
32504
+ title: "Projects",
32505
+ subtitle: stats.projects.unavailable.length > 0 ? `${stats.projects.included.length} included · ${stats.projects.unavailable.length} unavailable` : `${stats.projects.included.length} included`,
32506
+ children: /* @__PURE__ */ jsx116(ProjectList, {
32507
+ projects: stats.projects
32508
+ })
32509
+ }),
32510
+ stats.notes.missingPricing.length > 0 && /* @__PURE__ */ jsxs103("div", {
32511
+ className: "text-[10px] text-muted-foreground/70 text-center font-mono py-2",
32512
+ children: [
32513
+ "pricing missing for ",
32514
+ stats.notes.missingPricing.length,
32515
+ " model",
32516
+ stats.notes.missingPricing.length === 1 ? "" : "s",
32517
+ " · cost shown as $0"
32518
+ ]
32519
+ }),
32520
+ /* @__PURE__ */ jsxs103("div", {
32521
+ className: "text-[10px] text-muted-foreground/60 text-center pt-2 pb-4",
32522
+ children: [
32523
+ "estimated from catalog pricing · generated",
32524
+ " ",
32525
+ new Date(stats.generatedAt).toLocaleString()
32526
+ ]
32527
+ })
32528
+ ]
32529
+ })
32530
+ ]
32531
+ })
32532
+ })
32533
+ ]
32534
+ });
32535
+ }
31500
32536
  export {
31501
32537
  ViewerTabs,
31502
32538
  UserMessageGroup,
31503
32539
  UsageRing,
31504
32540
  UsageModal,
32541
+ UsageDashboard,
31505
32542
  TunnelSidebarToggle,
31506
32543
  TunnelSidebar,
31507
32544
  ToolResultRenderer,
@@ -31573,4 +32610,4 @@ export {
31573
32610
  AssistantMessageGroup
31574
32611
  };
31575
32612
 
31576
- //# debugId=83646DAB6C1728A064756E2164756E21
32613
+ //# debugId=4C1FF6CB288F864964756E2164756E21