@ottocode/web-sdk 0.1.277 → 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.
- package/dist/components/dashboard/UsageDashboard.d.ts +6 -0
- package/dist/components/dashboard/UsageDashboard.d.ts.map +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1042 -5
- package/dist/components/index.js.map +10 -8
- package/dist/components/settings/SettingsSidebar.d.ts +11 -1
- package/dist/components/settings/SettingsSidebar.d.ts.map +1 -1
- package/dist/hooks/index.js +43 -3
- package/dist/hooks/index.js.map +7 -6
- package/dist/hooks/usePreferences.d.ts +1 -0
- package/dist/hooks/usePreferences.d.ts.map +1 -1
- package/dist/index.js +1088 -39
- package/dist/index.js.map +11 -8
- package/dist/lib/api-client/index.d.ts +2 -0
- package/dist/lib/api-client/index.d.ts.map +1 -1
- package/dist/lib/api-client/usage.d.ts +8 -0
- package/dist/lib/api-client/usage.d.ts.map +1 -0
- package/dist/lib/index.js +37 -1
- package/dist/lib/index.js.map +6 -5
- package/dist/lib/platform.d.ts +1 -0
- package/dist/lib/platform.d.ts.map +1 -1
- package/dist/stores/index.d.ts +1 -0
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/index.js +12 -1
- package/dist/stores/index.js.map +5 -4
- package/dist/stores/rightRailStore.d.ts +20 -0
- package/dist/stores/rightRailStore.d.ts.map +1 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -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,8 +31575,966 @@ 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
|
// src/hooks/useClientEvents.ts
|
|
31501
|
-
import { useEffect as
|
|
32537
|
+
import { useEffect as useEffect59, useRef as useRef39 } from "react";
|
|
31502
32538
|
import { useQueryClient as useQueryClient22 } from "@tanstack/react-query";
|
|
31503
32539
|
import {
|
|
31504
32540
|
buildClientEventsStreamUrl,
|
|
@@ -31686,10 +32722,10 @@ async function maybeShowLocalAccessToast(baseUrl) {
|
|
|
31686
32722
|
function useClientEvents(activeSessionId) {
|
|
31687
32723
|
const queryClient = useQueryClient22();
|
|
31688
32724
|
const activeSessionIdRef = useRef39(activeSessionId);
|
|
31689
|
-
|
|
32725
|
+
useEffect59(() => {
|
|
31690
32726
|
activeSessionIdRef.current = activeSessionId;
|
|
31691
32727
|
}, [activeSessionId]);
|
|
31692
|
-
|
|
32728
|
+
useEffect59(() => {
|
|
31693
32729
|
if (typeof window === "undefined" || window.parent !== window)
|
|
31694
32730
|
return;
|
|
31695
32731
|
if (!("Notification" in window))
|
|
@@ -31718,7 +32754,7 @@ function useClientEvents(activeSessionId) {
|
|
|
31718
32754
|
}
|
|
31719
32755
|
});
|
|
31720
32756
|
}, []);
|
|
31721
|
-
|
|
32757
|
+
useEffect59(() => {
|
|
31722
32758
|
const controller = new AbortController;
|
|
31723
32759
|
const baseUrl = getBaseUrl();
|
|
31724
32760
|
createClientEventsStream({
|
|
@@ -31768,7 +32804,7 @@ function useClientEvents(activeSessionId) {
|
|
|
31768
32804
|
return buildClientEventsStreamUrl({ baseUrl: getBaseUrl() });
|
|
31769
32805
|
}
|
|
31770
32806
|
// src/hooks/useTheme.ts
|
|
31771
|
-
import { useEffect as
|
|
32807
|
+
import { useEffect as useEffect60, useState as useState52, useCallback as useCallback36, useMemo as useMemo32 } from "react";
|
|
31772
32808
|
var STORAGE_KEY3 = "otto-theme";
|
|
31773
32809
|
function resolveInitialTheme() {
|
|
31774
32810
|
if (typeof window === "undefined") {
|
|
@@ -31784,8 +32820,8 @@ function resolveInitialTheme() {
|
|
|
31784
32820
|
return "dark";
|
|
31785
32821
|
}
|
|
31786
32822
|
function useTheme() {
|
|
31787
|
-
const [theme, setTheme] =
|
|
31788
|
-
|
|
32823
|
+
const [theme, setTheme] = useState52(() => resolveInitialTheme());
|
|
32824
|
+
useEffect60(() => {
|
|
31789
32825
|
if (typeof document === "undefined")
|
|
31790
32826
|
return;
|
|
31791
32827
|
const root = document.documentElement;
|
|
@@ -31803,7 +32839,7 @@ function useTheme() {
|
|
|
31803
32839
|
window.parent.postMessage({ type: "otto-set-theme", theme }, "*");
|
|
31804
32840
|
}
|
|
31805
32841
|
}, [theme]);
|
|
31806
|
-
|
|
32842
|
+
useEffect60(() => {
|
|
31807
32843
|
if (typeof window === "undefined")
|
|
31808
32844
|
return;
|
|
31809
32845
|
const handler = (e) => {
|
|
@@ -31814,17 +32850,17 @@ function useTheme() {
|
|
|
31814
32850
|
window.addEventListener("message", handler);
|
|
31815
32851
|
return () => window.removeEventListener("message", handler);
|
|
31816
32852
|
}, []);
|
|
31817
|
-
const toggleTheme =
|
|
32853
|
+
const toggleTheme = useCallback36(() => {
|
|
31818
32854
|
setTheme((prev) => prev === "dark" ? "light" : "dark");
|
|
31819
32855
|
}, []);
|
|
31820
|
-
return
|
|
32856
|
+
return useMemo32(() => ({ theme, setTheme, toggleTheme }), [theme, toggleTheme]);
|
|
31821
32857
|
}
|
|
31822
32858
|
// src/hooks/useWorkingDirectory.ts
|
|
31823
|
-
import { useEffect as
|
|
32859
|
+
import { useEffect as useEffect61, useState as useState53 } from "react";
|
|
31824
32860
|
import { getCwd } from "@ottocode/api";
|
|
31825
32861
|
function useWorkingDirectory() {
|
|
31826
|
-
const [dirName, setDirName] =
|
|
31827
|
-
|
|
32862
|
+
const [dirName, setDirName] = useState53(null);
|
|
32863
|
+
useEffect61(() => {
|
|
31828
32864
|
const fetchWorkingDirectory = async () => {
|
|
31829
32865
|
try {
|
|
31830
32866
|
const response = await getCwd({ baseURL: getBaseUrl() });
|
|
@@ -31848,7 +32884,7 @@ function useWorkingDirectory() {
|
|
|
31848
32884
|
return dirName;
|
|
31849
32885
|
}
|
|
31850
32886
|
// src/hooks/useKeyboardShortcuts.ts
|
|
31851
|
-
import { useEffect as
|
|
32887
|
+
import { useEffect as useEffect62, useCallback as useCallback37 } from "react";
|
|
31852
32888
|
|
|
31853
32889
|
// src/stores/sidebarStore.ts
|
|
31854
32890
|
import { create as create24 } from "zustand";
|
|
@@ -31902,7 +32938,7 @@ function useKeyboardShortcuts({
|
|
|
31902
32938
|
const toggleResearch = useResearchStore((state) => state.toggleSidebar);
|
|
31903
32939
|
const toggleTerminalPanel = useTerminalStore((state) => state.togglePanel);
|
|
31904
32940
|
const currentSessionIndex = sessionIds.indexOf(activeSessionId || "");
|
|
31905
|
-
const handleKeyDown =
|
|
32941
|
+
const handleKeyDown = useCallback37((e) => {
|
|
31906
32942
|
const target = e.target;
|
|
31907
32943
|
const isInInput = target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable;
|
|
31908
32944
|
const isInTerminal = !!target.closest("[data-terminal-viewer]");
|
|
@@ -32152,7 +33188,7 @@ function useKeyboardShortcuts({
|
|
|
32152
33188
|
onReturnToInput,
|
|
32153
33189
|
closeDiff
|
|
32154
33190
|
]);
|
|
32155
|
-
|
|
33191
|
+
useEffect62(() => {
|
|
32156
33192
|
window.addEventListener("keydown", handleKeyDown, true);
|
|
32157
33193
|
return () => window.removeEventListener("keydown", handleKeyDown, true);
|
|
32158
33194
|
}, [handleKeyDown]);
|
|
@@ -32164,9 +33200,9 @@ function useKeyboardShortcuts({
|
|
|
32164
33200
|
}
|
|
32165
33201
|
// src/hooks/useImageUpload.ts
|
|
32166
33202
|
import {
|
|
32167
|
-
useState as
|
|
32168
|
-
useCallback as
|
|
32169
|
-
useEffect as
|
|
33203
|
+
useState as useState54,
|
|
33204
|
+
useCallback as useCallback38,
|
|
33205
|
+
useEffect as useEffect63
|
|
32170
33206
|
} from "react";
|
|
32171
33207
|
var SUPPORTED_TYPES2 = ["image/png", "image/jpeg", "image/gif", "image/webp"];
|
|
32172
33208
|
function generateId2() {
|
|
@@ -32194,11 +33230,11 @@ async function fileToPreview2(file) {
|
|
|
32194
33230
|
}
|
|
32195
33231
|
function useImageUpload(options = {}) {
|
|
32196
33232
|
const { maxImages = 5, maxSizeMB = 5, pageWide = true } = options;
|
|
32197
|
-
const [images, setImages] =
|
|
32198
|
-
const [isDragging, setIsDragging] =
|
|
32199
|
-
const [error, setError] =
|
|
33233
|
+
const [images, setImages] = useState54([]);
|
|
33234
|
+
const [isDragging, setIsDragging] = useState54(false);
|
|
33235
|
+
const [error, setError] = useState54(null);
|
|
32200
33236
|
const maxSizeBytes = maxSizeMB * 1024 * 1024;
|
|
32201
|
-
const validateFile =
|
|
33237
|
+
const validateFile = useCallback38((file) => {
|
|
32202
33238
|
if (!SUPPORTED_TYPES2.includes(file.type)) {
|
|
32203
33239
|
return `Unsupported file type: ${file.type}. Supported: PNG, JPEG, GIF, WebP`;
|
|
32204
33240
|
}
|
|
@@ -32207,7 +33243,7 @@ function useImageUpload(options = {}) {
|
|
|
32207
33243
|
}
|
|
32208
33244
|
return null;
|
|
32209
33245
|
}, [maxSizeBytes, maxSizeMB]);
|
|
32210
|
-
const addImages =
|
|
33246
|
+
const addImages = useCallback38(async (files) => {
|
|
32211
33247
|
setError(null);
|
|
32212
33248
|
const fileArray = Array.from(files);
|
|
32213
33249
|
const remaining = maxImages - images.length;
|
|
@@ -32243,22 +33279,22 @@ function useImageUpload(options = {}) {
|
|
|
32243
33279
|
setImages((prev) => [...prev, ...newImages]);
|
|
32244
33280
|
}
|
|
32245
33281
|
}, [images.length, maxImages, validateFile]);
|
|
32246
|
-
const removeImage =
|
|
33282
|
+
const removeImage = useCallback38((id) => {
|
|
32247
33283
|
setImages((prev) => prev.filter((img) => img.id !== id));
|
|
32248
33284
|
setError(null);
|
|
32249
33285
|
}, []);
|
|
32250
|
-
const clearImages =
|
|
33286
|
+
const clearImages = useCallback38(() => {
|
|
32251
33287
|
setImages([]);
|
|
32252
33288
|
setError(null);
|
|
32253
33289
|
}, []);
|
|
32254
|
-
const handleDragEnter =
|
|
33290
|
+
const handleDragEnter = useCallback38((e) => {
|
|
32255
33291
|
e.preventDefault();
|
|
32256
33292
|
e.stopPropagation();
|
|
32257
33293
|
if (e.dataTransfer.types.includes("Files")) {
|
|
32258
33294
|
setIsDragging(true);
|
|
32259
33295
|
}
|
|
32260
33296
|
}, []);
|
|
32261
|
-
const handleDragLeave =
|
|
33297
|
+
const handleDragLeave = useCallback38((e) => {
|
|
32262
33298
|
e.preventDefault();
|
|
32263
33299
|
e.stopPropagation();
|
|
32264
33300
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
@@ -32268,11 +33304,11 @@ function useImageUpload(options = {}) {
|
|
|
32268
33304
|
setIsDragging(false);
|
|
32269
33305
|
}
|
|
32270
33306
|
}, []);
|
|
32271
|
-
const handleDragOver =
|
|
33307
|
+
const handleDragOver = useCallback38((e) => {
|
|
32272
33308
|
e.preventDefault();
|
|
32273
33309
|
e.stopPropagation();
|
|
32274
33310
|
}, []);
|
|
32275
|
-
const handleDrop =
|
|
33311
|
+
const handleDrop = useCallback38((e) => {
|
|
32276
33312
|
e.preventDefault();
|
|
32277
33313
|
e.stopPropagation();
|
|
32278
33314
|
setIsDragging(false);
|
|
@@ -32284,7 +33320,7 @@ function useImageUpload(options = {}) {
|
|
|
32284
33320
|
}
|
|
32285
33321
|
}
|
|
32286
33322
|
}, [addImages]);
|
|
32287
|
-
const handlePaste =
|
|
33323
|
+
const handlePaste = useCallback38((e) => {
|
|
32288
33324
|
const items = e.clipboardData?.items;
|
|
32289
33325
|
if (!items)
|
|
32290
33326
|
return;
|
|
@@ -32302,7 +33338,7 @@ function useImageUpload(options = {}) {
|
|
|
32302
33338
|
addImages(imageFiles);
|
|
32303
33339
|
}
|
|
32304
33340
|
}, [addImages]);
|
|
32305
|
-
|
|
33341
|
+
useEffect63(() => {
|
|
32306
33342
|
if (!pageWide)
|
|
32307
33343
|
return;
|
|
32308
33344
|
let dragCounter = 0;
|
|
@@ -32363,7 +33399,7 @@ function useImageUpload(options = {}) {
|
|
|
32363
33399
|
};
|
|
32364
33400
|
}
|
|
32365
33401
|
// src/hooks/useSetuPayments.ts
|
|
32366
|
-
import { useEffect as
|
|
33402
|
+
import { useEffect as useEffect64, useRef as useRef40 } from "react";
|
|
32367
33403
|
function useSetuPayments(sessionId) {
|
|
32368
33404
|
const clientRef = useRef40(null);
|
|
32369
33405
|
const loadingToastIdRef = useRef40(null);
|
|
@@ -32373,7 +33409,7 @@ function useSetuPayments(sessionId) {
|
|
|
32373
33409
|
const updateToast = useToastStore((s) => s.updateToast);
|
|
32374
33410
|
const setPendingTopup = useTopupApprovalStore((s) => s.setPendingTopup);
|
|
32375
33411
|
const clearPendingTopup = useTopupApprovalStore((s) => s.clearPendingTopup);
|
|
32376
|
-
|
|
33412
|
+
useEffect64(() => {
|
|
32377
33413
|
if (!sessionId)
|
|
32378
33414
|
return;
|
|
32379
33415
|
const client5 = new SSEClient;
|
|
@@ -32502,6 +33538,16 @@ function useSetuPayments(sessionId) {
|
|
|
32502
33538
|
clearPendingTopup
|
|
32503
33539
|
]);
|
|
32504
33540
|
}
|
|
33541
|
+
// src/stores/rightRailStore.ts
|
|
33542
|
+
import { create as create25 } from "zustand";
|
|
33543
|
+
import { persist as persist3 } from "zustand/middleware";
|
|
33544
|
+
var useRightRailStore = create25()(persist3((set) => ({
|
|
33545
|
+
isPinned: false,
|
|
33546
|
+
togglePinned: () => set((state) => ({ isPinned: !state.isPinned })),
|
|
33547
|
+
setPinned: (pinned) => set({ isPinned: pinned })
|
|
33548
|
+
}), {
|
|
33549
|
+
name: "right-rail-storage"
|
|
33550
|
+
}));
|
|
32505
33551
|
export {
|
|
32506
33552
|
useWorkingDirectory,
|
|
32507
33553
|
useViewerTabsStore,
|
|
@@ -32542,6 +33588,7 @@ export {
|
|
|
32542
33588
|
useSessionFiles,
|
|
32543
33589
|
useSession,
|
|
32544
33590
|
useSendMessage,
|
|
33591
|
+
useRightRailStore,
|
|
32545
33592
|
useRevokeMCPAuth,
|
|
32546
33593
|
useRestoreFiles,
|
|
32547
33594
|
useResearchStore,
|
|
@@ -32614,6 +33661,7 @@ export {
|
|
|
32614
33661
|
notifyPlatformFontFamilyChanged,
|
|
32615
33662
|
normalizeQueueState,
|
|
32616
33663
|
listPlatformSystemFonts,
|
|
33664
|
+
isPlatformDesktop,
|
|
32617
33665
|
hasPlatformSystemFonts,
|
|
32618
33666
|
hasPlatformOpenUrl,
|
|
32619
33667
|
getRuntimeApiBaseUrl,
|
|
@@ -32625,6 +33673,7 @@ export {
|
|
|
32625
33673
|
UserMessageGroup,
|
|
32626
33674
|
UsageRing,
|
|
32627
33675
|
UsageModal,
|
|
33676
|
+
UsageDashboard,
|
|
32628
33677
|
TunnelSidebarToggle,
|
|
32629
33678
|
TunnelSidebar,
|
|
32630
33679
|
ToolResultRenderer,
|
|
@@ -32698,4 +33747,4 @@ export {
|
|
|
32698
33747
|
API_BASE_URL
|
|
32699
33748
|
};
|
|
32700
33749
|
|
|
32701
|
-
//# debugId=
|
|
33750
|
+
//# debugId=C84305701420A48C64756E2164756E21
|