@alivault/pico 0.1.5 → 0.1.6

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.
@@ -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-Cvysm_fM.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-h_J1DAp5.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-ClRUX20Q.js
23
+ //#region node_modules/.nitro/vite/services/ssr/assets/router-TRfB0YMJ.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, { payload }, (response) => {
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
- getManualRedirect().reject(/* @__PURE__ */ new Error("Login cancelled"));
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 fetchProviderUsage(provider)
5897
+ usage: await getPicoRuntime().getProviderUsage(request, provider)
5860
5898
  });
5861
5899
  } catch (error) {
5862
5900
  return routeErrorResponse(error, "Failed to read provider usage");
@@ -2,7 +2,7 @@ import { i as __toESM } from "../_runtime.mjs";
2
2
  import { A as Input, C as MenuTrigger, D as MenuPortal, E as MenuPositioner, F as DialogDescription$1, I as DialogClose, K as mergeProps, L as DialogBackdrop, M as DialogRoot, N as DialogPortal$1, O as MenuPopup, P as DialogPopup, R as Button, S as Separator, T as MenuRoot, X as require_react, Y as require_jsx_runtime, _ as AccordionRoot, a as CollapsiblePanel, b as TabsRoot, c as PopoverPopup, d as PopoverTrigger$1, f as PopoverRoot, g as AccordionItem$1, h as AccordionHeader, i as ContextMenuRoot, j as DialogTitle$1, k as MenuItem, l as PopoverPositioner, m as AccordionTrigger$1, n as Toggle, o as CollapsibleTrigger$1, p as AccordionPanel, r as ContextMenuTrigger$1, s as CollapsibleRoot, t as ToggleGroup, u as PopoverPortal, v as TabsList$1, w as MenuSubmenuRoot, x as MenuSubmenuTrigger, y as TabsTab, z as useRender } from "../_libs/@base-ui/react+[...].mjs";
3
3
  import { t as cva } from "../_libs/class-variance-authority+clsx.mjs";
4
4
  import { A as ChevronsUpDown, B as ArrowDown, C as FolderPlus, D as Copy, E as Download, F as Check, I as ArrowUp, L as ArrowUpToLine, M as ChevronUp, N as ChevronRight, O as Command, P as ChevronDown, S as Folder, T as EllipsisVertical, _ as ListEnd, a as Square, b as GitBranch, c as Settings2, d as PanelLeft, f as PanelLeftOpen, g as ListStart, h as OctagonX, j as ChevronsDownUp, l as Search, n as WandSparkles, o as SquarePen, p as PanelLeftClose, r as Upload, s as SquareArrowOutUpRight, t as X, u as PanelRight, w as Ellipsis, x as GitCommitHorizontal, y as ImagePlus, z as ArrowLeft } from "../_libs/lucide-react.mjs";
5
- import { $ as sameContextUsage, B as readStoredAutoScrollEnabled, C as buildItemsFromSync, D as createInitialSessionState, E as createContextId, F as normalizeSessionSelectionKeys, G as readStoredPromptDraft, H as readStoredCollapsedDirectories, I as normalizeStoredDirectoryList, J as readStoredSessionDoneDesktopNotificationsEnabled, K as readStoredRecentDirectories, L as normalizeThemeMode, M as getSessionTitle, P as normalizePromptImage, Q as safeLocalStorageSetItem, R as previewUrlForImage, U as readStoredDraftDirectory, V as readStoredCenterMessages, W as readStoredHideToolBlocks, X as readStoredSidebarDirectories, Y as readStoredSessionDoneSoundEnabled, Z as rememberStoredPromptDraft, _ as Tooltip$1, a as HIDE_TOOL_BLOCKS_STORAGE_KEY, b as TooltipTrigger, c as RECENT_DIRECTORIES_STORAGE_KEY, d as SESSION_DONE_DESKTOP_NOTIFICATIONS_ENABLED_STORAGE_KEY, et as sessionListEntryKey, f as SESSION_DONE_SOUND_ENABLED_STORAGE_KEY, g as TitleTooltip, i as DRAFT_DIRECTORY_STORAGE_KEY, j as flattenTree, l as RIGHT_SIDEBAR_OPEN_STORAGE_KEY, m as Spinner, n as CENTER_MESSAGES_STORAGE_KEY, o as Kbd, p as SIDEBAR_DIRECTORIES_STORAGE_KEY, q as readStoredRightSidebarOpen, r as COLLAPSED_DIRECTORIES_STORAGE_KEY, s as KeyboardShortcutContent, t as AUTO_SCROLL_ENABLED_STORAGE_KEY, tt as thinkingSummaryText, u as Route, v as TooltipContent, w as cn, x as VIEWER_CONTEXT_STORAGE_KEY, z as promptDraftKey } from "./routes-Cvysm_fM.mjs";
5
+ import { $ as sameContextUsage, B as readStoredAutoScrollEnabled, C as buildItemsFromSync, D as createInitialSessionState, E as createContextId, F as normalizeSessionSelectionKeys, G as readStoredPromptDraft, H as readStoredCollapsedDirectories, I as normalizeStoredDirectoryList, J as readStoredSessionDoneDesktopNotificationsEnabled, K as readStoredRecentDirectories, L as normalizeThemeMode, M as getSessionTitle, P as normalizePromptImage, Q as safeLocalStorageSetItem, R as previewUrlForImage, U as readStoredDraftDirectory, V as readStoredCenterMessages, W as readStoredHideToolBlocks, X as readStoredSidebarDirectories, Y as readStoredSessionDoneSoundEnabled, Z as rememberStoredPromptDraft, _ as Tooltip$1, a as HIDE_TOOL_BLOCKS_STORAGE_KEY, b as TooltipTrigger, c as RECENT_DIRECTORIES_STORAGE_KEY, d as SESSION_DONE_DESKTOP_NOTIFICATIONS_ENABLED_STORAGE_KEY, et as sessionListEntryKey, f as SESSION_DONE_SOUND_ENABLED_STORAGE_KEY, g as TitleTooltip, i as DRAFT_DIRECTORY_STORAGE_KEY, j as flattenTree, l as RIGHT_SIDEBAR_OPEN_STORAGE_KEY, m as Spinner, n as CENTER_MESSAGES_STORAGE_KEY, o as Kbd, p as SIDEBAR_DIRECTORIES_STORAGE_KEY, q as readStoredRightSidebarOpen, r as COLLAPSED_DIRECTORIES_STORAGE_KEY, s as KeyboardShortcutContent, t as AUTO_SCROLL_ENABLED_STORAGE_KEY, tt as thinkingSummaryText, u as Route, v as TooltipContent, w as cn, x as VIEWER_CONTEXT_STORAGE_KEY, z as promptDraftKey } from "./routes-h_J1DAp5.mjs";
6
6
  import { i as useQuery, n as useIsMutating, o as useQueryClient, r as useIsFetching, t as useMutation } from "../_libs/tanstack__react-query.mjs";
7
7
  import { t as useHotkeys } from "../_libs/tanstack__react-hotkeys.mjs";
8
8
  import { a as matchesKeyboardEvent, i as batch, o as formatForDisplay, r as createStore } from "../_libs/@tanstack/hotkeys+[...].mjs";
@@ -19,7 +19,7 @@ import { t as remarkGfm } from "../_libs/remark-gfm.mjs";
19
19
  import { a as getBuiltInSpriteSheet, i as getBuiltInFileIconColor, n as FileTree, r as createFileTreeIconResolver, t as useFileTree } from "../_libs/@pierre/trees+[...].mjs";
20
20
  import { a as closestCenter, d as useSensors, f as CSS$1, i as PointerSensor, n as DragOverlay, t as DndContext, u as useSensor } from "../_libs/@dnd-kit/core+[...].mjs";
21
21
  import { a as verticalListSortingStrategy, i as useSortable, n as arrayMove, r as horizontalListSortingStrategy, t as SortableContext } from "../_libs/dnd-kit__sortable.mjs";
22
- //#region node_modules/.nitro/vite/services/ssr/assets/routes-CNruDMyi.js
22
+ //#region node_modules/.nitro/vite/services/ssr/assets/routes-Cmw5XPYv.js
23
23
  var import_react = /* @__PURE__ */ __toESM(require_react());
24
24
  var import_jsx_runtime = require_jsx_runtime();
25
25
  var SIDEBAR_RESIZE_START_THRESHOLD_PX = 4;
@@ -5053,6 +5053,55 @@ function AppShellUiRequestDialog({ pendingUiRequest, pendingUiValue, onPendingUi
5053
5053
  ]
5054
5054
  }));
5055
5055
  }
5056
+ if (pendingUiRequest?.method === "auth_select") {
5057
+ const cancelAuthAndReturn = () => {
5058
+ onResolveUiRequest({ cancelled: true });
5059
+ onAuthBack?.();
5060
+ };
5061
+ const options = pendingUiRequest.options ?? [];
5062
+ return renderAuthSurface(true, (open) => {
5063
+ if (!open) cancelAuthAndReturn();
5064
+ }, pendingUiRequest.title || "Log in to provider", pendingUiRequest.message || "Choose how to continue login.", /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Command$1, {
5065
+ loop: true,
5066
+ shouldFilter: true,
5067
+ children: [
5068
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandInput, {
5069
+ autoFocus: !isMobile,
5070
+ placeholder: "Choose login option",
5071
+ className: "text-base md:text-sm"
5072
+ }),
5073
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandList, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandGroup, {
5074
+ heading: pendingUiRequest.message || "Login options",
5075
+ children: options.map((option) => {
5076
+ const value = typeof option === "string" ? option : option.value;
5077
+ const label = typeof option === "string" ? option : option.label || option.value;
5078
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandItem, {
5079
+ value,
5080
+ keywords: [label],
5081
+ onSelect: () => onResolveUiRequest({ value }),
5082
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
5083
+ className: "truncate font-medium",
5084
+ children: label
5085
+ })
5086
+ }, value);
5087
+ })
5088
+ }) }),
5089
+ isMobile ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
5090
+ className: "border-t border-border/70 p-3",
5091
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
5092
+ type: "button",
5093
+ variant: "outline",
5094
+ className: "w-full",
5095
+ onClick: cancelAuthAndReturn,
5096
+ children: "Cancel login"
5097
+ })
5098
+ }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
5099
+ className: "hidden border-t border-border/70 px-3 py-2 text-xs text-muted-foreground md:block",
5100
+ children: "Use ↑/↓ to select, Enter to continue, and Esc to go back."
5101
+ })
5102
+ ]
5103
+ }));
5104
+ }
5056
5105
  if (pendingUiRequest?.method === "auth_input") {
5057
5106
  const allowEmpty = Boolean(pendingUiRequest.allowEmpty);
5058
5107
  const cancelAuthAndReturn = () => {
@@ -6487,17 +6536,21 @@ function getContextUsageRingGeometry(ringCount) {
6487
6536
  if (ringCount === 2) return CONTEXT_USAGE_RING_GEOMETRY[2];
6488
6537
  return CONTEXT_USAGE_RING_GEOMETRY[1];
6489
6538
  }
6490
- function ComposerContextUsageIndicator({ contextUsageStore = emptyContextUsageStore, disabled = false, modelProvider }) {
6539
+ function ComposerContextUsageIndicator({ activeSessionId, contextUsageStore = emptyContextUsageStore, disabled = false, modelProvider, viewerContextId }) {
6491
6540
  const contextUsage = useComposerContextUsageSnapshot(contextUsageStore);
6492
6541
  const useMobilePopover = useContextUsageMobilePopover();
6493
6542
  const [providerUsageWindows, setProviderUsageWindows] = import_react.useState([]);
6494
6543
  import_react.useEffect(() => {
6495
- if (!modelProvider) {
6544
+ if (!modelProvider || !viewerContextId) {
6496
6545
  setProviderUsageWindows([]);
6497
6546
  return;
6498
6547
  }
6499
6548
  let cancelled = false;
6500
- const url = `/api/provider-usage?provider=${encodeURIComponent(modelProvider)}`;
6549
+ const url = buildRequestUrl("/api/provider-usage", {
6550
+ contextId: viewerContextId,
6551
+ sessionId: activeSessionId,
6552
+ searchParams: { provider: modelProvider }
6553
+ });
6501
6554
  fetch(url).then((response) => response.ok ? response.json() : void 0).then((data) => {
6502
6555
  if (cancelled) return;
6503
6556
  setProviderUsageWindows(Array.isArray(data?.usage?.windows) ? data.usage.windows : []);
@@ -6507,7 +6560,12 @@ function ComposerContextUsageIndicator({ contextUsageStore = emptyContextUsageSt
6507
6560
  return () => {
6508
6561
  cancelled = true;
6509
6562
  };
6510
- }, [modelProvider, contextUsage?.tokens]);
6563
+ }, [
6564
+ activeSessionId,
6565
+ modelProvider,
6566
+ viewerContextId,
6567
+ contextUsage?.tokens
6568
+ ]);
6511
6569
  if (disabled) return null;
6512
6570
  if (!contextUsage) return null;
6513
6571
  const { contextWindow, fiveHourUsage, percent, roundedPercent, tokens, weeklyUsage } = contextUsage;
@@ -6706,11 +6764,13 @@ var ComposerModelPicker = import_react.memo(function ComposerModelPicker({ disab
6706
6764
  })]
6707
6765
  });
6708
6766
  });
6709
- var ComposerContextUsageIndicatorHost = import_react.memo(function ComposerContextUsageIndicatorHost({ contextUsageStore, disabled, sessionStore }) {
6767
+ var ComposerContextUsageIndicatorHost = import_react.memo(function ComposerContextUsageIndicatorHost({ activeSessionId, contextUsageStore, disabled, sessionStore, viewerContextId }) {
6710
6768
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ComposerContextUsageIndicator, {
6769
+ activeSessionId,
6711
6770
  contextUsageStore,
6712
6771
  disabled,
6713
- modelProvider: useSelector(sessionStore, (sessionState) => sessionState.model?.provider)
6772
+ modelProvider: useSelector(sessionStore, (sessionState) => sessionState.model?.provider),
6773
+ viewerContextId
6714
6774
  });
6715
6775
  });
6716
6776
  var ComposerThinkingPicker = import_react.memo(function ComposerThinkingPicker({ disabled, onOpenChange, onSelectThinkingLevel, open, sessionStore }) {
@@ -6755,7 +6815,7 @@ var ComposerThinkingPicker = import_react.memo(function ComposerThinkingPicker({
6755
6815
  })]
6756
6816
  });
6757
6817
  });
6758
- var ComposerPickers = import_react.memo(function ComposerPickers({ modelPickerOpen, onModelPickerOpenChange, thinkingPickerOpen, onThinkingPickerOpenChange, modelQuery, onModelQueryChange, contextUsageStore, sessionStore, disabled = false, onSelectModel, onSelectThinkingLevel }) {
6818
+ var ComposerPickers = import_react.memo(function ComposerPickers({ activeSessionId, modelPickerOpen, onModelPickerOpenChange, thinkingPickerOpen, onThinkingPickerOpenChange, modelQuery, onModelQueryChange, contextUsageStore, sessionStore, disabled = false, viewerContextId, onSelectModel, onSelectThinkingLevel }) {
6759
6819
  const handleModelPickerOpenChange = (open) => {
6760
6820
  if (disabled && open) return;
6761
6821
  onModelPickerOpenChange(open);
@@ -6784,9 +6844,11 @@ var ComposerPickers = import_react.memo(function ComposerPickers({ modelPickerOp
6784
6844
  sessionStore
6785
6845
  })]
6786
6846
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ComposerContextUsageIndicatorHost, {
6847
+ activeSessionId,
6787
6848
  contextUsageStore,
6788
6849
  disabled,
6789
- sessionStore
6850
+ sessionStore,
6851
+ viewerContextId
6790
6852
  })]
6791
6853
  });
6792
6854
  });
@@ -9266,7 +9328,7 @@ function getClipboardImageFiles(data) {
9266
9328
  if (itemFiles.length > 0) return itemFiles;
9267
9329
  return Array.from(data.files).filter((file) => file.type.startsWith("image/"));
9268
9330
  }
9269
- var ComposerPanel = import_react.forwardRef(function ComposerPanelImpl({ currentPendingMessages, composerImages, composerText, composerSkill, composerSyncNonce, centerMessages, contextUsageStore, displaySettingsStore, sessionStore, isSubmitting, isStreaming, awaitingFirstTurn, disabled = false, flush = false, topContent, fileInputRef, onComposerTextChange, onPickImages, onRemoveComposerImage, onSubmitPrompt, onAbort, onEditPendingMessage, onRemovePendingMessage, onReorderPending, onRunBuiltinSlashCommand, onSelectModel, onSelectThinkingLevel, requestPathCompletions, requestFileCompletions }, ref) {
9331
+ var ComposerPanel = import_react.forwardRef(function ComposerPanelImpl({ activeSessionId, currentPendingMessages, composerImages, composerText, composerSkill, composerSyncNonce, centerMessages, contextUsageStore, displaySettingsStore, sessionStore, isSubmitting, isStreaming, awaitingFirstTurn, disabled = false, flush = false, topContent, viewerContextId, fileInputRef, onComposerTextChange, onPickImages, onRemoveComposerImage, onSubmitPrompt, onAbort, onEditPendingMessage, onRemovePendingMessage, onReorderPending, onRunBuiltinSlashCommand, onSelectModel, onSelectThinkingLevel, requestPathCompletions, requestFileCompletions }, ref) {
9270
9332
  const promptRef = import_react.useRef(null);
9271
9333
  const [modelPickerOpen, setModelPickerOpen] = import_react.useState(false);
9272
9334
  const [thinkingPickerOpen, setThinkingPickerOpen] = import_react.useState(false);
@@ -9326,6 +9388,7 @@ var ComposerPanel = import_react.forwardRef(function ComposerPanelImpl({ current
9326
9388
  requestPathCompletions,
9327
9389
  requestFileCompletions
9328
9390
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ComposerPickers, {
9391
+ activeSessionId,
9329
9392
  modelPickerOpen,
9330
9393
  onModelPickerOpenChange: setModelPickerOpen,
9331
9394
  thinkingPickerOpen,
@@ -9335,6 +9398,7 @@ var ComposerPanel = import_react.forwardRef(function ComposerPanelImpl({ current
9335
9398
  contextUsageStore,
9336
9399
  sessionStore,
9337
9400
  disabled,
9401
+ viewerContextId,
9338
9402
  onSelectModel,
9339
9403
  onSelectThinkingLevel
9340
9404
  })]
@@ -18008,6 +18072,7 @@ var AppShellComposerController = import_react.memo(function AppShellComposerCont
18008
18072
  });
18009
18073
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ComposerPanel, {
18010
18074
  ref: composerPanelRef,
18075
+ activeSessionId: snapshot.activeSessionId,
18011
18076
  currentPendingMessages: snapshot.currentPendingMessages,
18012
18077
  composerImages: snapshot.composerImages,
18013
18078
  composerText: snapshot.composerText,
@@ -18023,6 +18088,7 @@ var AppShellComposerController = import_react.memo(function AppShellComposerCont
18023
18088
  disabled: snapshot.disabled,
18024
18089
  flush: Boolean(topContent),
18025
18090
  topContent,
18091
+ viewerContextId: snapshot.viewerContextId,
18026
18092
  fileInputRef,
18027
18093
  onComposerTextChange,
18028
18094
  onPickImages,
@@ -5,7 +5,7 @@ import { n as clsx } from "../_libs/class-variance-authority+clsx.mjs";
5
5
  import { t as twMerge } from "../_libs/tailwind-merge.mjs";
6
6
  import { B as ArrowDown, I as ArrowUp, M as ChevronUp, O as Command, R as ArrowRight, V as ArrowBigUp, m as Option, z as ArrowLeft } from "../_libs/lucide-react.mjs";
7
7
  import { n as string, t as object } from "../_libs/zod.mjs";
8
- //#region node_modules/.nitro/vite/services/ssr/assets/routes-Cvysm_fM.js
8
+ //#region node_modules/.nitro/vite/services/ssr/assets/routes-h_J1DAp5.js
9
9
  var import_react = /* @__PURE__ */ __toESM(require_react());
10
10
  var import_jsx_runtime = require_jsx_runtime();
11
11
  function cn(...inputs) {
@@ -1265,7 +1265,7 @@ function getSessionTitle(summary) {
1265
1265
  if (summary?.name?.trim()) return summary.name.trim();
1266
1266
  return "New session";
1267
1267
  }
1268
- var $$splitComponentImporter = () => import("./routes-CNruDMyi.mjs");
1268
+ var $$splitComponentImporter = () => import("./routes-Cmw5XPYv.mjs");
1269
1269
  var indexSearchSchema = object({ session: string().optional() });
1270
1270
  var Route = createFileRoute("/")({
1271
1271
  validateSearch: indexSearchSchema,
@@ -3813,7 +3813,7 @@ var defaultSerovalPlugins = [
3813
3813
  * the dev styles URL for route-scoped CSS collection.
3814
3814
  */
3815
3815
  async function getStartManifest(matchedRoutes) {
3816
- const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-BByO2avp.mjs");
3816
+ const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-hzhfVHZ4.mjs");
3817
3817
  const startManifest = tsrStartManifest();
3818
3818
  const rootRoute = startManifest.routes[rootRouteId] = startManifest.routes["__root__"] || {};
3819
3819
  rootRoute.assets = rootRoute.assets || [];
@@ -4799,7 +4799,7 @@ var baseManifestPromise;
4799
4799
  var cachedFinalManifestPromise;
4800
4800
  async function loadEntries() {
4801
4801
  const [routerEntry, startEntry, pluginAdapters] = await Promise.all([
4802
- import("./router-ClRUX20Q.mjs"),
4802
+ import("./router-TRfB0YMJ.mjs"),
4803
4803
  import("./start-Captdpmb.mjs"),
4804
4804
  import("../__23tanstack-start-plugin-adapters-y_fshQDY.mjs")
4805
4805
  ]);