@alivault/pico 0.1.5 → 0.1.7
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/.output/nitro.json +1 -1
- package/.output/public/assets/{index-D-sz4gTz.js → index-BWtOMO0B.js} +2 -2
- package/.output/public/assets/{routes-DSOVCxRf.js → routes-5c_6T6hK.js} +118 -115
- package/.output/server/_ssr/{router-ClRUX20Q.mjs → router-CvoH1TXL.mjs} +199 -161
- package/.output/server/_ssr/{routes-CNruDMyi.mjs → routes-DJqUmK-U.mjs} +196 -29
- package/.output/server/_ssr/{routes-Cvysm_fM.mjs → routes-Di-eYVLe.mjs} +2 -2
- package/.output/server/_ssr/ssr.mjs +2 -2
- package/.output/server/{_tanstack-start-manifest_v-BByO2avp.mjs → _tanstack-start-manifest_v-f3QaV5ex.mjs} +4 -4
- package/.output/server/index.mjs +496 -496
- package/README.md +6 -0
- package/bin/pico.mjs +103 -7
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import { i as __toESM } from "../_runtime.mjs";
|
|
|
2
2
|
import { X as require_react, Y as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
|
|
3
3
|
import { a as createRouter, c as createRootRoute, n as Scripts, r as HeadContent, s as createFileRoute } from "../_libs/@tanstack/react-router+[...].mjs";
|
|
4
4
|
import { h as OctagonX, i as TriangleAlert, k as CircleCheck, v as Info } from "../_libs/lucide-react.mjs";
|
|
5
|
-
import { A as extractToolText, C as buildItemsFromSync, N as mergeAssistantBlocksForStreaming, O as extractMessageImages, S as assistantBlocksFromMessage, T as createCompactionSummaryItem, h as THEME_STORAGE_KEY, k as extractMessageText$1, m as Spinner, nt as toolCategoryFromTool, u as Route$46, y as TooltipProvider } from "./routes-
|
|
5
|
+
import { A as extractToolText, C as buildItemsFromSync, N as mergeAssistantBlocksForStreaming, O as extractMessageImages, S as assistantBlocksFromMessage, T as createCompactionSummaryItem, h as THEME_STORAGE_KEY, k as extractMessageText$1, m as Spinner, nt as toolCategoryFromTool, u as Route$46, y as TooltipProvider } from "./routes-Di-eYVLe.mjs";
|
|
6
6
|
import { t as QueryClient } from "../_libs/tanstack__query-core.mjs";
|
|
7
7
|
import { t as setupRouterSsrQueryIntegration } from "../_libs/@tanstack/react-router-ssr-query+[...].mjs";
|
|
8
8
|
import { n as HotkeysProvider } from "../_libs/tanstack__react-hotkeys.mjs";
|
|
@@ -20,7 +20,7 @@ import os, { homedir } from "node:os";
|
|
|
20
20
|
import { performance } from "node:perf_hooks";
|
|
21
21
|
import { isMainThread } from "node:worker_threads";
|
|
22
22
|
import { execSync, spawn } from "node:child_process";
|
|
23
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/router-
|
|
23
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/router-CvoH1TXL.js
|
|
24
24
|
var import_react = /* @__PURE__ */ __toESM(require_react());
|
|
25
25
|
var import_jsx_runtime = require_jsx_runtime();
|
|
26
26
|
var Toaster$1 = ({ ...props }) => {
|
|
@@ -2727,6 +2727,167 @@ var GitWatchManager = class {
|
|
|
2727
2727
|
state.watchers.clear();
|
|
2728
2728
|
}
|
|
2729
2729
|
};
|
|
2730
|
+
var PROVIDER_MAP = {
|
|
2731
|
+
anthropic: "claude",
|
|
2732
|
+
"openai-codex": "codex"
|
|
2733
|
+
};
|
|
2734
|
+
async function getOAuthAccessToken(authStorage, provider) {
|
|
2735
|
+
const credential = authStorage?.get(provider);
|
|
2736
|
+
if (credential?.type !== "oauth") return void 0;
|
|
2737
|
+
let token = credential.access;
|
|
2738
|
+
if (typeof authStorage?.getApiKey === "function") try {
|
|
2739
|
+
token = await authStorage.getApiKey(provider, { includeFallback: false }) || token;
|
|
2740
|
+
} catch {}
|
|
2741
|
+
const refreshedCredential = authStorage?.get(provider);
|
|
2742
|
+
return {
|
|
2743
|
+
token,
|
|
2744
|
+
credential: refreshedCredential?.type === "oauth" ? refreshedCredential : credential
|
|
2745
|
+
};
|
|
2746
|
+
}
|
|
2747
|
+
async function getClaudeToken(authStorage) {
|
|
2748
|
+
const result = await getOAuthAccessToken(authStorage, "anthropic");
|
|
2749
|
+
if (result?.token) return result.token;
|
|
2750
|
+
try {
|
|
2751
|
+
const keychainData = execSync("security find-generic-password -s \"Claude Code-credentials\" -w 2>/dev/null", {
|
|
2752
|
+
encoding: "utf-8",
|
|
2753
|
+
stdio: [
|
|
2754
|
+
"pipe",
|
|
2755
|
+
"pipe",
|
|
2756
|
+
"pipe"
|
|
2757
|
+
]
|
|
2758
|
+
}).trim();
|
|
2759
|
+
if (keychainData) {
|
|
2760
|
+
const parsed = JSON.parse(keychainData);
|
|
2761
|
+
if (parsed.claudeAiOauth?.accessToken) return String(parsed.claudeAiOauth.accessToken);
|
|
2762
|
+
}
|
|
2763
|
+
} catch {}
|
|
2764
|
+
}
|
|
2765
|
+
async function getCodexToken(authStorage) {
|
|
2766
|
+
const result = await getOAuthAccessToken(authStorage, "openai-codex");
|
|
2767
|
+
if (result) return {
|
|
2768
|
+
token: result.token,
|
|
2769
|
+
accountId: typeof result.credential.accountId === "string" ? result.credential.accountId : void 0
|
|
2770
|
+
};
|
|
2771
|
+
const codexPath = join(process.env.CODEX_HOME || join(homedir(), ".codex"), "auth.json");
|
|
2772
|
+
try {
|
|
2773
|
+
if (existsSync(codexPath)) {
|
|
2774
|
+
const data = JSON.parse(readFileSync(codexPath, "utf-8"));
|
|
2775
|
+
if (data.OPENAI_API_KEY) return { token: String(data.OPENAI_API_KEY) };
|
|
2776
|
+
if (data.tokens?.access_token) return {
|
|
2777
|
+
token: String(data.tokens.access_token),
|
|
2778
|
+
accountId: data.tokens.account_id ? String(data.tokens.account_id) : void 0
|
|
2779
|
+
};
|
|
2780
|
+
}
|
|
2781
|
+
} catch {}
|
|
2782
|
+
}
|
|
2783
|
+
function clampPercent(value) {
|
|
2784
|
+
if (!Number.isFinite(value)) return 0;
|
|
2785
|
+
return Math.max(0, Math.min(100, value));
|
|
2786
|
+
}
|
|
2787
|
+
function normalizePercent(value) {
|
|
2788
|
+
if (!Number.isFinite(value)) return 0;
|
|
2789
|
+
return clampPercent(value <= 1 && value >= 0 ? value * 100 : value);
|
|
2790
|
+
}
|
|
2791
|
+
function formatResetTime(date) {
|
|
2792
|
+
const diffMs = date.getTime() - Date.now();
|
|
2793
|
+
if (diffMs < 0) return "now";
|
|
2794
|
+
const diffMins = Math.floor(diffMs / 6e4);
|
|
2795
|
+
if (diffMins < 60) return `${diffMins}m`;
|
|
2796
|
+
const hours = Math.floor(diffMins / 60);
|
|
2797
|
+
const mins = diffMins % 60;
|
|
2798
|
+
if (hours < 24) return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
|
|
2799
|
+
const days = Math.floor(hours / 24);
|
|
2800
|
+
const remainingHours = hours % 24;
|
|
2801
|
+
return remainingHours > 0 ? `${days}d ${remainingHours}h` : `${days}d`;
|
|
2802
|
+
}
|
|
2803
|
+
function getWindowLabel(durationMs, fallback) {
|
|
2804
|
+
if (!durationMs || !Number.isFinite(durationMs) || durationMs <= 0) return fallback;
|
|
2805
|
+
const hourMs = 3600 * 1e3;
|
|
2806
|
+
const weekMs = 168 * hourMs;
|
|
2807
|
+
const isCloseToWeek = Math.abs(durationMs - weekMs) <= hourMs * 2;
|
|
2808
|
+
const isCloseTo5h = Math.abs(durationMs - 5 * hourMs) <= hourMs * 2;
|
|
2809
|
+
if (isCloseToWeek || fallback === "Week") return "Week";
|
|
2810
|
+
if (isCloseTo5h || fallback === "5h") return fallback;
|
|
2811
|
+
const hours = Math.round(durationMs / hourMs);
|
|
2812
|
+
if (hours >= 1 && hours < 48) return `${hours}h`;
|
|
2813
|
+
return fallback;
|
|
2814
|
+
}
|
|
2815
|
+
async function fetchWithTimeout(url, init) {
|
|
2816
|
+
const controller = new AbortController();
|
|
2817
|
+
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
2818
|
+
try {
|
|
2819
|
+
return await fetch(url, {
|
|
2820
|
+
...init,
|
|
2821
|
+
signal: controller.signal
|
|
2822
|
+
});
|
|
2823
|
+
} finally {
|
|
2824
|
+
clearTimeout(timeout);
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
async function fetchClaudeUsage(authStorage) {
|
|
2828
|
+
const token = await getClaudeToken(authStorage);
|
|
2829
|
+
if (!token) return { windows: [] };
|
|
2830
|
+
try {
|
|
2831
|
+
const res = await fetchWithTimeout("https://api.anthropic.com/api/oauth/usage", { headers: {
|
|
2832
|
+
Authorization: `Bearer ${token}`,
|
|
2833
|
+
"anthropic-beta": "oauth-2025-04-20"
|
|
2834
|
+
} });
|
|
2835
|
+
if (!res.ok) return { windows: [] };
|
|
2836
|
+
const data = await res.json();
|
|
2837
|
+
const windows = [];
|
|
2838
|
+
if (data.five_hour?.utilization !== void 0) windows.push({
|
|
2839
|
+
label: "5h",
|
|
2840
|
+
usedPercent: normalizePercent(data.five_hour.utilization),
|
|
2841
|
+
resetsIn: data.five_hour.resets_at ? formatResetTime(new Date(data.five_hour.resets_at)) : void 0
|
|
2842
|
+
});
|
|
2843
|
+
if (data.seven_day?.utilization !== void 0) windows.push({
|
|
2844
|
+
label: "Week",
|
|
2845
|
+
usedPercent: normalizePercent(data.seven_day.utilization),
|
|
2846
|
+
resetsIn: data.seven_day.resets_at ? formatResetTime(new Date(data.seven_day.resets_at)) : void 0
|
|
2847
|
+
});
|
|
2848
|
+
return { windows };
|
|
2849
|
+
} catch {
|
|
2850
|
+
return { windows: [] };
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
async function fetchCodexUsage(authStorage) {
|
|
2854
|
+
const creds = await getCodexToken(authStorage);
|
|
2855
|
+
if (!creds) return { windows: [] };
|
|
2856
|
+
try {
|
|
2857
|
+
const headers = {
|
|
2858
|
+
Authorization: `Bearer ${creds.token}`,
|
|
2859
|
+
"User-Agent": "pico",
|
|
2860
|
+
Accept: "application/json"
|
|
2861
|
+
};
|
|
2862
|
+
if (creds.accountId) headers["ChatGPT-Account-Id"] = creds.accountId;
|
|
2863
|
+
const res = await fetchWithTimeout("https://chatgpt.com/backend-api/wham/usage", { headers });
|
|
2864
|
+
if (!res.ok) return { windows: [] };
|
|
2865
|
+
const data = await res.json();
|
|
2866
|
+
const windows = [];
|
|
2867
|
+
const primary = data.rate_limit?.primary_window;
|
|
2868
|
+
if (primary) windows.push({
|
|
2869
|
+
label: getWindowLabel(typeof primary.limit_window_seconds === "number" ? primary.limit_window_seconds * 1e3 : void 0, "5h"),
|
|
2870
|
+
usedPercent: clampPercent(primary.used_percent || 0),
|
|
2871
|
+
resetsIn: primary.reset_at ? formatResetTime(/* @__PURE__ */ new Date(primary.reset_at * 1e3)) : void 0
|
|
2872
|
+
});
|
|
2873
|
+
const secondary = data.rate_limit?.secondary_window;
|
|
2874
|
+
if (secondary) windows.push({
|
|
2875
|
+
label: getWindowLabel(typeof secondary.limit_window_seconds === "number" ? secondary.limit_window_seconds * 1e3 : void 0, "Week"),
|
|
2876
|
+
usedPercent: clampPercent(secondary.used_percent || 0),
|
|
2877
|
+
resetsIn: secondary.reset_at ? formatResetTime(/* @__PURE__ */ new Date(secondary.reset_at * 1e3)) : void 0
|
|
2878
|
+
});
|
|
2879
|
+
return { windows };
|
|
2880
|
+
} catch {
|
|
2881
|
+
return { windows: [] };
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
async function fetchProviderUsage(modelProvider, authStorage) {
|
|
2885
|
+
switch (modelProvider ? PROVIDER_MAP[modelProvider] : void 0) {
|
|
2886
|
+
case "claude": return fetchClaudeUsage(authStorage);
|
|
2887
|
+
case "codex": return fetchCodexUsage(authStorage);
|
|
2888
|
+
default: return { windows: [] };
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2730
2891
|
var VALID_THINKING_LEVELS = new Set([
|
|
2731
2892
|
"off",
|
|
2732
2893
|
"minimal",
|
|
@@ -5460,6 +5621,10 @@ var PicoRuntime = class {
|
|
|
5460
5621
|
this.requireAuthStorage(activeEntry).logout(provider);
|
|
5461
5622
|
return await this.finishAuthMutation(activeEntry, provider);
|
|
5462
5623
|
}
|
|
5624
|
+
async getProviderUsage(request, provider) {
|
|
5625
|
+
const { activeEntry } = await this.resolveRequest(request);
|
|
5626
|
+
return await fetchProviderUsage(provider, activeEntry.services.modelRegistry.authStorage);
|
|
5627
|
+
}
|
|
5463
5628
|
async loginProviderOAuth(request, body) {
|
|
5464
5629
|
const { activeEntry } = await this.resolveRequest(request);
|
|
5465
5630
|
const provider = typeof body.provider === "string" ? body.provider.trim() : "";
|
|
@@ -5474,14 +5639,28 @@ var PicoRuntime = class {
|
|
|
5474
5639
|
createRequestId: () => randomUUID(),
|
|
5475
5640
|
broadcastToViewers: (sessionKey, payload) => this.broadcastToViewers(sessionKey, payload)
|
|
5476
5641
|
});
|
|
5642
|
+
const loginAbortController = new AbortController();
|
|
5643
|
+
const loginSignal = loginAbortController.signal;
|
|
5477
5644
|
const requestInput = async (payload) => {
|
|
5478
|
-
const value = await ui.createDialogPromise(void 0, {
|
|
5645
|
+
const value = await ui.createDialogPromise(void 0, {
|
|
5646
|
+
payload,
|
|
5647
|
+
signal: loginSignal
|
|
5648
|
+
}, (response) => {
|
|
5479
5649
|
if (response.cancelled) return void 0;
|
|
5480
5650
|
return typeof response.value === "string" ? response.value : void 0;
|
|
5481
5651
|
});
|
|
5482
5652
|
if (value === void 0) throw new Error("Login cancelled");
|
|
5483
5653
|
return value;
|
|
5484
5654
|
};
|
|
5655
|
+
const requestSelection = async (payload) => {
|
|
5656
|
+
return await ui.createDialogPromise(void 0, {
|
|
5657
|
+
payload,
|
|
5658
|
+
signal: loginSignal
|
|
5659
|
+
}, (response) => {
|
|
5660
|
+
if (response.cancelled) return void 0;
|
|
5661
|
+
return typeof response.value === "string" ? response.value : void 0;
|
|
5662
|
+
});
|
|
5663
|
+
};
|
|
5485
5664
|
let manualRedirect;
|
|
5486
5665
|
const getManualRedirect = () => {
|
|
5487
5666
|
if (!manualRedirect) {
|
|
@@ -5504,7 +5683,8 @@ var PicoRuntime = class {
|
|
|
5504
5683
|
throw new Error(`Cancelled the existing ${providerInfo.name} login. Try login again.`);
|
|
5505
5684
|
}
|
|
5506
5685
|
this.activeOAuthLogins.set(loginKey, () => {
|
|
5507
|
-
|
|
5686
|
+
loginAbortController.abort();
|
|
5687
|
+
manualRedirect?.reject(/* @__PURE__ */ new Error("Login cancelled"));
|
|
5508
5688
|
});
|
|
5509
5689
|
try {
|
|
5510
5690
|
await authStorage.login(provider, {
|
|
@@ -5517,6 +5697,7 @@ var PicoRuntime = class {
|
|
|
5517
5697
|
authUrl: info.url,
|
|
5518
5698
|
authManualAllowed: Boolean(providerInfo.usesCallbackServer)
|
|
5519
5699
|
},
|
|
5700
|
+
signal: loginSignal,
|
|
5520
5701
|
timeout: 600 * 1e3
|
|
5521
5702
|
}, (response) => {
|
|
5522
5703
|
if (typeof response.value === "string") return {
|
|
@@ -5547,7 +5728,19 @@ var PicoRuntime = class {
|
|
|
5547
5728
|
},
|
|
5548
5729
|
onManualCodeInput: async () => {
|
|
5549
5730
|
return await getManualRedirect().promise;
|
|
5550
|
-
}
|
|
5731
|
+
},
|
|
5732
|
+
onSelect: async (prompt) => {
|
|
5733
|
+
return await requestSelection({
|
|
5734
|
+
method: "auth_select",
|
|
5735
|
+
title: `Log in to ${providerInfo.name}`,
|
|
5736
|
+
message: prompt.message,
|
|
5737
|
+
options: prompt.options.map((option) => ({
|
|
5738
|
+
value: option.id,
|
|
5739
|
+
label: option.label
|
|
5740
|
+
}))
|
|
5741
|
+
});
|
|
5742
|
+
},
|
|
5743
|
+
signal: loginSignal
|
|
5551
5744
|
});
|
|
5552
5745
|
return await this.finishAuthMutation(activeEntry, provider);
|
|
5553
5746
|
} finally {
|
|
@@ -5696,167 +5889,12 @@ var Route$42 = createFileRoute("/api/slash-command")({ server: { handlers: { POS
|
|
|
5696
5889
|
return routeErrorResponse(error, "Failed to run slash command");
|
|
5697
5890
|
}
|
|
5698
5891
|
} } } });
|
|
5699
|
-
var PROVIDER_MAP = {
|
|
5700
|
-
anthropic: "claude",
|
|
5701
|
-
"openai-codex": "codex"
|
|
5702
|
-
};
|
|
5703
|
-
function loadAuthJson() {
|
|
5704
|
-
const authPath = join(homedir(), ".pi", "agent", "auth.json");
|
|
5705
|
-
try {
|
|
5706
|
-
if (existsSync(authPath)) return JSON.parse(readFileSync(authPath, "utf-8"));
|
|
5707
|
-
} catch {}
|
|
5708
|
-
return {};
|
|
5709
|
-
}
|
|
5710
|
-
function getClaudeToken() {
|
|
5711
|
-
const auth = loadAuthJson();
|
|
5712
|
-
if (auth.anthropic?.access) return String(auth.anthropic.access);
|
|
5713
|
-
try {
|
|
5714
|
-
const keychainData = execSync("security find-generic-password -s \"Claude Code-credentials\" -w 2>/dev/null", {
|
|
5715
|
-
encoding: "utf-8",
|
|
5716
|
-
stdio: [
|
|
5717
|
-
"pipe",
|
|
5718
|
-
"pipe",
|
|
5719
|
-
"pipe"
|
|
5720
|
-
]
|
|
5721
|
-
}).trim();
|
|
5722
|
-
if (keychainData) {
|
|
5723
|
-
const parsed = JSON.parse(keychainData);
|
|
5724
|
-
if (parsed.claudeAiOauth?.accessToken) return String(parsed.claudeAiOauth.accessToken);
|
|
5725
|
-
}
|
|
5726
|
-
} catch {}
|
|
5727
|
-
}
|
|
5728
|
-
function getCodexToken() {
|
|
5729
|
-
const auth = loadAuthJson();
|
|
5730
|
-
if (auth["openai-codex"]?.access) return {
|
|
5731
|
-
token: String(auth["openai-codex"].access),
|
|
5732
|
-
accountId: auth["openai-codex"]?.accountId ? String(auth["openai-codex"].accountId) : void 0
|
|
5733
|
-
};
|
|
5734
|
-
const codexPath = join(process.env.CODEX_HOME || join(homedir(), ".codex"), "auth.json");
|
|
5735
|
-
try {
|
|
5736
|
-
if (existsSync(codexPath)) {
|
|
5737
|
-
const data = JSON.parse(readFileSync(codexPath, "utf-8"));
|
|
5738
|
-
if (data.OPENAI_API_KEY) return { token: String(data.OPENAI_API_KEY) };
|
|
5739
|
-
if (data.tokens?.access_token) return {
|
|
5740
|
-
token: String(data.tokens.access_token),
|
|
5741
|
-
accountId: data.tokens.account_id ? String(data.tokens.account_id) : void 0
|
|
5742
|
-
};
|
|
5743
|
-
}
|
|
5744
|
-
} catch {}
|
|
5745
|
-
}
|
|
5746
|
-
function clampPercent(value) {
|
|
5747
|
-
if (!Number.isFinite(value)) return 0;
|
|
5748
|
-
return Math.max(0, Math.min(100, value));
|
|
5749
|
-
}
|
|
5750
|
-
function normalizePercent(value) {
|
|
5751
|
-
if (!Number.isFinite(value)) return 0;
|
|
5752
|
-
return clampPercent(value <= 1 && value >= 0 ? value * 100 : value);
|
|
5753
|
-
}
|
|
5754
|
-
function formatResetTime(date) {
|
|
5755
|
-
const diffMs = date.getTime() - Date.now();
|
|
5756
|
-
if (diffMs < 0) return "now";
|
|
5757
|
-
const diffMins = Math.floor(diffMs / 6e4);
|
|
5758
|
-
if (diffMins < 60) return `${diffMins}m`;
|
|
5759
|
-
const hours = Math.floor(diffMins / 60);
|
|
5760
|
-
const mins = diffMins % 60;
|
|
5761
|
-
if (hours < 24) return mins > 0 ? `${hours}h ${mins}m` : `${hours}h`;
|
|
5762
|
-
const days = Math.floor(hours / 24);
|
|
5763
|
-
const remainingHours = hours % 24;
|
|
5764
|
-
return remainingHours > 0 ? `${days}d ${remainingHours}h` : `${days}d`;
|
|
5765
|
-
}
|
|
5766
|
-
function getWindowLabel(durationMs, fallback) {
|
|
5767
|
-
if (!durationMs || !Number.isFinite(durationMs) || durationMs <= 0) return fallback;
|
|
5768
|
-
const hourMs = 3600 * 1e3;
|
|
5769
|
-
const weekMs = 168 * hourMs;
|
|
5770
|
-
const isCloseToWeek = Math.abs(durationMs - weekMs) <= hourMs * 2;
|
|
5771
|
-
const isCloseTo5h = Math.abs(durationMs - 5 * hourMs) <= hourMs * 2;
|
|
5772
|
-
if (isCloseToWeek || fallback === "Week") return "Week";
|
|
5773
|
-
if (isCloseTo5h || fallback === "5h") return fallback;
|
|
5774
|
-
const hours = Math.round(durationMs / hourMs);
|
|
5775
|
-
if (hours >= 1 && hours < 48) return `${hours}h`;
|
|
5776
|
-
return fallback;
|
|
5777
|
-
}
|
|
5778
|
-
async function fetchWithTimeout(url, init) {
|
|
5779
|
-
const controller = new AbortController();
|
|
5780
|
-
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
5781
|
-
try {
|
|
5782
|
-
return await fetch(url, {
|
|
5783
|
-
...init,
|
|
5784
|
-
signal: controller.signal
|
|
5785
|
-
});
|
|
5786
|
-
} finally {
|
|
5787
|
-
clearTimeout(timeout);
|
|
5788
|
-
}
|
|
5789
|
-
}
|
|
5790
|
-
async function fetchClaudeUsage() {
|
|
5791
|
-
const token = getClaudeToken();
|
|
5792
|
-
if (!token) return { windows: [] };
|
|
5793
|
-
try {
|
|
5794
|
-
const res = await fetchWithTimeout("https://api.anthropic.com/api/oauth/usage", { headers: {
|
|
5795
|
-
Authorization: `Bearer ${token}`,
|
|
5796
|
-
"anthropic-beta": "oauth-2025-04-20"
|
|
5797
|
-
} });
|
|
5798
|
-
if (!res.ok) return { windows: [] };
|
|
5799
|
-
const data = await res.json();
|
|
5800
|
-
const windows = [];
|
|
5801
|
-
if (data.five_hour?.utilization !== void 0) windows.push({
|
|
5802
|
-
label: "5h",
|
|
5803
|
-
usedPercent: normalizePercent(data.five_hour.utilization),
|
|
5804
|
-
resetsIn: data.five_hour.resets_at ? formatResetTime(new Date(data.five_hour.resets_at)) : void 0
|
|
5805
|
-
});
|
|
5806
|
-
if (data.seven_day?.utilization !== void 0) windows.push({
|
|
5807
|
-
label: "Week",
|
|
5808
|
-
usedPercent: normalizePercent(data.seven_day.utilization),
|
|
5809
|
-
resetsIn: data.seven_day.resets_at ? formatResetTime(new Date(data.seven_day.resets_at)) : void 0
|
|
5810
|
-
});
|
|
5811
|
-
return { windows };
|
|
5812
|
-
} catch {
|
|
5813
|
-
return { windows: [] };
|
|
5814
|
-
}
|
|
5815
|
-
}
|
|
5816
|
-
async function fetchCodexUsage() {
|
|
5817
|
-
const creds = getCodexToken();
|
|
5818
|
-
if (!creds) return { windows: [] };
|
|
5819
|
-
try {
|
|
5820
|
-
const headers = {
|
|
5821
|
-
Authorization: `Bearer ${creds.token}`,
|
|
5822
|
-
"User-Agent": "pico",
|
|
5823
|
-
Accept: "application/json"
|
|
5824
|
-
};
|
|
5825
|
-
if (creds.accountId) headers["ChatGPT-Account-Id"] = creds.accountId;
|
|
5826
|
-
const res = await fetchWithTimeout("https://chatgpt.com/backend-api/wham/usage", { headers });
|
|
5827
|
-
if (!res.ok) return { windows: [] };
|
|
5828
|
-
const data = await res.json();
|
|
5829
|
-
const windows = [];
|
|
5830
|
-
const primary = data.rate_limit?.primary_window;
|
|
5831
|
-
if (primary) windows.push({
|
|
5832
|
-
label: getWindowLabel(typeof primary.limit_window_seconds === "number" ? primary.limit_window_seconds * 1e3 : void 0, "5h"),
|
|
5833
|
-
usedPercent: clampPercent(primary.used_percent || 0),
|
|
5834
|
-
resetsIn: primary.reset_at ? formatResetTime(/* @__PURE__ */ new Date(primary.reset_at * 1e3)) : void 0
|
|
5835
|
-
});
|
|
5836
|
-
const secondary = data.rate_limit?.secondary_window;
|
|
5837
|
-
if (secondary) windows.push({
|
|
5838
|
-
label: getWindowLabel(typeof secondary.limit_window_seconds === "number" ? secondary.limit_window_seconds * 1e3 : void 0, "Week"),
|
|
5839
|
-
usedPercent: clampPercent(secondary.used_percent || 0),
|
|
5840
|
-
resetsIn: secondary.reset_at ? formatResetTime(/* @__PURE__ */ new Date(secondary.reset_at * 1e3)) : void 0
|
|
5841
|
-
});
|
|
5842
|
-
return { windows };
|
|
5843
|
-
} catch {
|
|
5844
|
-
return { windows: [] };
|
|
5845
|
-
}
|
|
5846
|
-
}
|
|
5847
|
-
async function fetchProviderUsage(modelProvider) {
|
|
5848
|
-
switch (modelProvider ? PROVIDER_MAP[modelProvider] : void 0) {
|
|
5849
|
-
case "claude": return fetchClaudeUsage();
|
|
5850
|
-
case "codex": return fetchCodexUsage();
|
|
5851
|
-
default: return { windows: [] };
|
|
5852
|
-
}
|
|
5853
|
-
}
|
|
5854
5892
|
var Route$41 = createFileRoute("/api/provider-usage")({ server: { handlers: { GET: async ({ request }) => {
|
|
5855
5893
|
const provider = new URL(request.url).searchParams.get("provider") || void 0;
|
|
5856
5894
|
try {
|
|
5857
5895
|
return jsonResponse({
|
|
5858
5896
|
ok: true,
|
|
5859
|
-
usage: await
|
|
5897
|
+
usage: await getPicoRuntime().getProviderUsage(request, provider)
|
|
5860
5898
|
});
|
|
5861
5899
|
} catch (error) {
|
|
5862
5900
|
return routeErrorResponse(error, "Failed to read provider usage");
|