opencode-visual-cache 1.6.3 → 1.6.5

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/tui.js CHANGED
@@ -13,7 +13,7 @@ import { createElement as _$createElement } from "@opentui/solid";
13
13
  import { createMemo, createSignal, createEffect, onMount, onCleanup, Show, For, untrack } from "solid-js";
14
14
 
15
15
  // src/_version.ts
16
- var PLUGIN_VERSION = "1.6.3";
16
+ var PLUGIN_VERSION = "1.6.5";
17
17
 
18
18
  // src/balance-providers.ts
19
19
  var BalanceError = class extends Error {
@@ -101,7 +101,221 @@ var moonshotProvider = {
101
101
  return [{ currency: "CNY", total: String(balance) }];
102
102
  }
103
103
  };
104
- var balanceProviders = [deepseekProvider, siliconflowProvider, openrouterProvider, moonshotProvider];
104
+ var hyperProvider = {
105
+ id: "hyper",
106
+ name: "Charm Hyper",
107
+ keyPlaceholder: "sk-hyper-...",
108
+ async fetchBalance(apiKey, signal) {
109
+ const res = await fetch("https://hyper.charm.land/v1/credits", {
110
+ headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
111
+ signal
112
+ });
113
+ if (!res.ok) {
114
+ if (res.status === 401) throw new BalanceError("401");
115
+ if (res.status === 403) throw new BalanceError("403");
116
+ throw new BalanceError(String(res.status));
117
+ }
118
+ const json = await res.json();
119
+ const balance = json.balance;
120
+ if (typeof balance === "undefined" || balance === null) throw new BalanceError("EMPTY");
121
+ const usd = (Number(balance) * 0.05).toFixed(2);
122
+ return [{ currency: "USD", total: usd }];
123
+ }
124
+ };
125
+ function decodeJwtPayload(token) {
126
+ try {
127
+ const encoded = token.split(".")[1];
128
+ if (!encoded || typeof atob !== "function") return void 0;
129
+ const binary = atob(encoded.replace(/-/g, "+").replace(/_/g, "/"));
130
+ const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
131
+ return JSON.parse(new TextDecoder().decode(bytes));
132
+ } catch {
133
+ return void 0;
134
+ }
135
+ }
136
+ function getChatGPTAccountId(token) {
137
+ const payload = decodeJwtPayload(token);
138
+ const auth = payload?.["https://api.openai.com/auth"];
139
+ if (auth && typeof auth === "object") {
140
+ const accountId2 = auth.chatgpt_account_id;
141
+ if (typeof accountId2 === "string" && accountId2) return accountId2;
142
+ }
143
+ const accountId = payload?.chatgpt_account_id;
144
+ return typeof accountId === "string" && accountId ? accountId : void 0;
145
+ }
146
+ function asRecord(value) {
147
+ return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
148
+ }
149
+ function asFiniteNumber(value) {
150
+ const number = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : NaN;
151
+ return Number.isFinite(number) ? number : void 0;
152
+ }
153
+ function clampPercent(value) {
154
+ return Math.max(0, Math.min(100, value));
155
+ }
156
+ function formatPercent(value) {
157
+ return Number.isInteger(value) ? value.toFixed(0) : value.toFixed(1);
158
+ }
159
+ function formatCreditAmount(value) {
160
+ if (Number.isInteger(value)) return String(value);
161
+ return value.toFixed(2).replace(/\.?0+$/, "");
162
+ }
163
+ function getPercentages(snapshot) {
164
+ const explicitUsed = asFiniteNumber(snapshot.used_percent);
165
+ const explicitRemaining = asFiniteNumber(snapshot.remaining_percent);
166
+ if (explicitUsed !== void 0 || explicitRemaining !== void 0) {
167
+ const used = clampPercent(explicitUsed ?? 100 - explicitRemaining);
168
+ const remaining = clampPercent(explicitRemaining ?? 100 - used);
169
+ return { used, remaining };
170
+ }
171
+ const limit = asFiniteNumber(snapshot.limit);
172
+ const usedAmount = asFiniteNumber(snapshot.used);
173
+ const remainingAmount = asFiniteNumber(snapshot.remaining);
174
+ if (limit !== void 0 && limit > 0 && (usedAmount !== void 0 || remainingAmount !== void 0)) {
175
+ const used = usedAmount !== void 0 ? usedAmount / limit * 100 : 100 - remainingAmount / limit * 100;
176
+ const remaining = remainingAmount !== void 0 ? remainingAmount / limit * 100 : 100 - used;
177
+ return { used: clampPercent(used), remaining: clampPercent(remaining) };
178
+ }
179
+ const amountTotal = (usedAmount ?? 0) + (remainingAmount ?? 0);
180
+ if (amountTotal > 0 && (usedAmount !== void 0 || remainingAmount !== void 0)) {
181
+ const used = usedAmount !== void 0 ? usedAmount / amountTotal * 100 : 0;
182
+ return { used: clampPercent(used), remaining: clampPercent(100 - used) };
183
+ }
184
+ return void 0;
185
+ }
186
+ function getRateWindows(rateLimit) {
187
+ const record = asRecord(rateLimit);
188
+ if (!record) return [];
189
+ return Object.entries(record).map(([name, value], order) => {
190
+ const data = asRecord(value);
191
+ if (!data) return void 0;
192
+ const normalizedName = name.toLowerCase();
193
+ if (normalizedName.includes("individual")) return void 0;
194
+ const windowSeconds = asFiniteNumber(data.limit_window_seconds);
195
+ const looksLikeWindow = normalizedName.includes("window") || windowSeconds !== void 0 || "used_percent" in data || "remaining_percent" in data;
196
+ if (!looksLikeWindow) return void 0;
197
+ return { data, windowSeconds, order };
198
+ }).filter((window) => window !== void 0).sort((a, b) => (a.windowSeconds ?? Number.MAX_SAFE_INTEGER) - (b.windowSeconds ?? Number.MAX_SAFE_INTEGER) || a.order - b.order);
199
+ }
200
+ function getResetAfterSeconds(snapshot, nowMs) {
201
+ const relative = asFiniteNumber(snapshot.reset_after_seconds);
202
+ if (relative !== void 0) return Math.max(0, Math.round(relative));
203
+ for (const key of ["reset_at", "resets_at", "resetAt", "resetsAt"]) {
204
+ const timestamp = asFiniteNumber(snapshot[key]);
205
+ if (timestamp === void 0) continue;
206
+ const timestampSeconds = timestamp > 1e12 ? timestamp / 1e3 : timestamp;
207
+ return Math.max(0, Math.round(timestampSeconds - nowMs / 1e3));
208
+ }
209
+ return void 0;
210
+ }
211
+ function appendQuotaDetails(details, percentages, windowSeconds) {
212
+ const scope = windowSeconds === void 0 ? {} : { windowSeconds };
213
+ details.push({ key: "used", value: `${formatPercent(percentages.used)}%`, ...scope });
214
+ details.push({ key: "remaining", value: `${formatPercent(percentages.remaining)}%`, ...scope });
215
+ }
216
+ function parseOpenAIUsage(raw, nowMs = Date.now()) {
217
+ const json = asRecord(raw);
218
+ if (!json) throw new BalanceError("EMPTY");
219
+ const details = [];
220
+ if (typeof json.plan_type === "string" && json.plan_type) {
221
+ details.push({ key: "plan", value: json.plan_type.toUpperCase() });
222
+ }
223
+ const rateLimit = asRecord(json.rate_limit);
224
+ const remainingValues = [];
225
+ let hasRateQuota = false;
226
+ for (const window of getRateWindows(rateLimit)) {
227
+ const percentages = getPercentages(window.data);
228
+ if (percentages) {
229
+ appendQuotaDetails(details, percentages, window.windowSeconds);
230
+ remainingValues.push(percentages.remaining);
231
+ hasRateQuota = true;
232
+ }
233
+ const resetAfter = getResetAfterSeconds(window.data, nowMs);
234
+ if (resetAfter !== void 0) {
235
+ details.push({
236
+ key: "reset",
237
+ value: String(resetAfter),
238
+ ...window.windowSeconds === void 0 ? {} : { windowSeconds: window.windowSeconds }
239
+ });
240
+ }
241
+ }
242
+ const spendControl = asRecord(asRecord(json.spend_control)?.individual_limit);
243
+ const individualLimit = asRecord(json.individual_limit) ?? asRecord(rateLimit?.individual_limit) ?? spendControl;
244
+ const individualPercentages = individualLimit ? getPercentages(individualLimit) : void 0;
245
+ if (individualPercentages) {
246
+ remainingValues.push(individualPercentages.remaining);
247
+ if (!hasRateQuota) appendQuotaDetails(details, individualPercentages);
248
+ }
249
+ if (individualLimit) {
250
+ const resetAfter = getResetAfterSeconds(individualLimit, nowMs);
251
+ if (resetAfter !== void 0) details.push({ key: "reset", value: String(resetAfter) });
252
+ }
253
+ const codeReviewWindow = asRecord(asRecord(json.code_review_rate_limit)?.primary_window);
254
+ const codeReviewUsed = asFiniteNumber(codeReviewWindow?.used_percent);
255
+ if (codeReviewUsed !== void 0) {
256
+ details.push({ key: "codeReview", value: `${formatPercent(clampPercent(100 - codeReviewUsed))}%` });
257
+ }
258
+ const credits = asRecord(json.credits);
259
+ let hasCreditDetail = false;
260
+ if (credits?.unlimited === true) {
261
+ details.push({ key: "credits", value: "unlimited" });
262
+ hasCreditDetail = true;
263
+ } else {
264
+ const creditBalance = asFiniteNumber(credits?.balance);
265
+ if (creditBalance !== void 0) {
266
+ details.push({ key: "credits", value: `$${creditBalance.toFixed(2)}` });
267
+ hasCreditDetail = true;
268
+ } else if (individualLimit) {
269
+ const remaining = asFiniteNumber(individualLimit.remaining);
270
+ const limit = asFiniteNumber(individualLimit.limit);
271
+ const amounts = [remaining, limit].filter((value) => value !== void 0);
272
+ if (amounts.length > 0) {
273
+ details.push({ key: "credits", value: amounts.map(formatCreditAmount).join(" / ") });
274
+ hasCreditDetail = true;
275
+ }
276
+ }
277
+ }
278
+ const resetCredits = asFiniteNumber(asRecord(json.rate_limit_reset_credits)?.available_count);
279
+ if (resetCredits !== void 0) details.push({ key: "resetCredits", value: String(resetCredits) });
280
+ if (details.length === 0 || !hasRateQuota && !individualPercentages && !hasCreditDetail && resetCredits === void 0) {
281
+ throw new BalanceError("EMPTY");
282
+ }
283
+ const summaryRemaining = remainingValues.length > 0 ? Math.min(...remainingValues) : void 0;
284
+ const summary = summaryRemaining === void 0 ? void 0 : formatPercent(summaryRemaining);
285
+ return [{
286
+ currency: "CODEX",
287
+ total: summary === void 0 ? "0" : `${summary}%`,
288
+ display: summary === void 0 ? "Codex" : `Codex ${summary}%`,
289
+ details
290
+ }];
291
+ }
292
+ var openaiProvider = {
293
+ id: "openai",
294
+ name: "OpenAI Codex",
295
+ keyPlaceholder: "OAuth access token (eyJ...)",
296
+ async fetchBalance(accessToken, signal) {
297
+ const headers = {
298
+ Authorization: `Bearer ${accessToken}`,
299
+ Accept: "application/json",
300
+ Referer: "https://chatgpt.com/",
301
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/147.0.0.0 Safari/537.36",
302
+ "OpenAI-Beta": "codex-1",
303
+ "oai-language": "zh-CN",
304
+ originator: "Codex Desktop"
305
+ };
306
+ const accountId = getChatGPTAccountId(accessToken);
307
+ if (accountId) headers["ChatGPT-Account-Id"] = accountId;
308
+ const res = await fetch("https://chatgpt.com/backend-api/wham/usage", { headers, signal });
309
+ if (!res.ok) {
310
+ if (res.status === 401) throw new BalanceError("401");
311
+ if (res.status === 403) throw new BalanceError("403");
312
+ throw new BalanceError(String(res.status));
313
+ }
314
+ const json = await res.json();
315
+ return parseOpenAIUsage(json);
316
+ }
317
+ };
318
+ var balanceProviders = [deepseekProvider, siliconflowProvider, openrouterProvider, moonshotProvider, hyperProvider, openaiProvider];
105
319
  function getBalanceProvider(id) {
106
320
  return balanceProviders.find((p) => p.id === id) ?? balanceProviders[0] ?? deepseekProvider;
107
321
  }
@@ -157,6 +371,19 @@ var ZH_T = {
157
371
  balErrEmpty: "\u672A\u83B7\u53D6\u5230\u4F59\u989D\u6570\u636E",
158
372
  balErrTimeout: "\u67E5\u8BE2\u8D85\u65F6",
159
373
  balUnsupported: "\u5F53\u524D\u63D0\u4F9B\u5546\u4E0D\u652F\u6301\u4F59\u989D\u67E5\u8BE2",
374
+ balDetailPlan: "\u5957\u9910",
375
+ balDetailUsed: "\u5DF2\u7528",
376
+ balDetailRemaining: "\u5269\u4F59",
377
+ balDetailWindow: "\u5468\u671F",
378
+ balDetailReset: "\u91CD\u7F6E",
379
+ balDetailCodeReview: "Code Review",
380
+ balDetailCredits: "Credits",
381
+ balDetailResetCredits: "\u91CD\u7F6E\u6B21\u6570",
382
+ balUnlimited: "\u65E0\u9650",
383
+ balDay: "\u5929",
384
+ balHour: "\u5C0F\u65F6",
385
+ balMinute: "\u5206\u949F",
386
+ balResetSoon: "\u5373\u5C06\u91CD\u7F6E",
160
387
  barHit: "\u547D\u4E2D\u7387",
161
388
  barBal: "\u4F59\u989D",
162
389
  barTok: "Tokens",
@@ -238,6 +465,19 @@ var EN_T = {
238
465
  balErrEmpty: "No balance data",
239
466
  balErrTimeout: "Request timed out",
240
467
  balUnsupported: "Balance query unsupported",
468
+ balDetailPlan: "Plan",
469
+ balDetailUsed: "Used",
470
+ balDetailRemaining: "Remaining",
471
+ balDetailWindow: "Window",
472
+ balDetailReset: "Reset",
473
+ balDetailCodeReview: "Code Review",
474
+ balDetailCredits: "Credits",
475
+ balDetailResetCredits: "Reset credits",
476
+ balUnlimited: "Unlimited",
477
+ balDay: "d",
478
+ balHour: "h",
479
+ balMinute: "m",
480
+ balResetSoon: "soon",
241
481
  barHit: "Hit",
242
482
  barBal: "Balance",
243
483
  barTok: "Tokens",
@@ -319,6 +559,19 @@ var JA_T = {
319
559
  balErrEmpty: "\u6B8B\u9AD8\u30C7\u30FC\u30BF\u306A\u3057",
320
560
  balErrTimeout: "\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8",
321
561
  balUnsupported: "\u3053\u306E\u30D7\u30ED\u30D0\u30A4\u30C0\u306F\u6B8B\u9AD8\u7167\u4F1A\u975E\u5BFE\u5FDC",
562
+ balDetailPlan: "\u30D7\u30E9\u30F3",
563
+ balDetailUsed: "\u4F7F\u7528\u6E08\u307F",
564
+ balDetailRemaining: "\u6B8B\u308A",
565
+ balDetailWindow: "\u671F\u9593",
566
+ balDetailReset: "\u30EA\u30BB\u30C3\u30C8",
567
+ balDetailCodeReview: "Code Review",
568
+ balDetailCredits: "Credits",
569
+ balDetailResetCredits: "\u30EA\u30BB\u30C3\u30C8\u56DE\u6570",
570
+ balUnlimited: "\u7121\u5236\u9650",
571
+ balDay: "\u65E5",
572
+ balHour: "\u6642\u9593",
573
+ balMinute: "\u5206",
574
+ balResetSoon: "\u307E\u3082\u306A\u304F",
322
575
  barHit: "\u30D2\u30C3\u30C8\u7387",
323
576
  barBal: "\u6B8B\u9AD8",
324
577
  barTok: "Tokens",
@@ -400,6 +653,19 @@ var KO_T = {
400
653
  balErrEmpty: "\uC794\uC561 \uB370\uC774\uD130 \uC5C6\uC74C",
401
654
  balErrTimeout: "\uC2DC\uAC04 \uCD08\uACFC",
402
655
  balUnsupported: "\uC774 \uD504\uB85C\uBC14\uC774\uB354\uB294 \uC794\uC561 \uC870\uD68C \uBBF8\uC9C0\uC6D0",
656
+ balDetailPlan: "\uD50C\uB79C",
657
+ balDetailUsed: "\uC0AC\uC6A9",
658
+ balDetailRemaining: "\uC794\uC5EC",
659
+ balDetailWindow: "\uC8FC\uAE30",
660
+ balDetailReset: "\uC7AC\uC124\uC815",
661
+ balDetailCodeReview: "Code Review",
662
+ balDetailCredits: "Credits",
663
+ balDetailResetCredits: "\uC7AC\uC124\uC815 \uD69F\uC218",
664
+ balUnlimited: "\uBB34\uC81C\uD55C",
665
+ balDay: "\uC77C",
666
+ balHour: "\uC2DC\uAC04",
667
+ balMinute: "\uBD84",
668
+ balResetSoon: "\uACE7 \uC7AC\uC124\uC815",
403
669
  barHit: "\uD788\uD2B8\uC728",
404
670
  barBal: "\uC794\uC561",
405
671
  barTok: "Tokens",
@@ -631,11 +897,42 @@ function convertBalance(target, targetRate, amount, from) {
631
897
  const usd = from === "USD" ? amount : amount / fromRate;
632
898
  return target === "USD" ? usd : usd * targetRate;
633
899
  }
900
+ function readOpenAIOAuthToken(api) {
901
+ try {
902
+ const loader = typeof process !== "undefined" ? process?.getBuiltinModule : void 0;
903
+ const fs = loader?.("node:fs");
904
+ if (!fs) return "";
905
+ const stateDir = api.state.path.state.replace(/[\\/]+$/, "");
906
+ const home = typeof process !== "undefined" ? process?.env.HOME || process?.env.USERPROFILE || "" : "";
907
+ const dataHome = typeof process !== "undefined" ? process?.env.XDG_DATA_HOME : void 0;
908
+ const paths = [stateDir ? `${stateDir}/auth.json` : "", dataHome ? `${dataHome}/opencode/auth.json` : "", home ? `${home}/.local/share/opencode/auth.json` : ""];
909
+ for (const path of paths) {
910
+ if (!path) continue;
911
+ try {
912
+ const auth = JSON.parse(fs.readFileSync(path, "utf8"));
913
+ const openai = auth.openai;
914
+ if (openai && typeof openai === "object") {
915
+ const record = openai;
916
+ if (record.type === "oauth" && typeof record.access === "string") return record.access;
917
+ }
918
+ } catch {
919
+ }
920
+ }
921
+ return "";
922
+ } catch {
923
+ return "";
924
+ }
925
+ }
634
926
  function findOpencodeKey(api, provider) {
635
927
  try {
636
928
  const provs = api.state.provider;
637
929
  const id = provider.id.toLowerCase();
638
930
  const hit = provs.find((p) => p.id.toLowerCase() === id) ?? provs.find((p) => p.id.toLowerCase().startsWith(id));
931
+ const isOpenAI = id === "openai";
932
+ if (isOpenAI) {
933
+ const oauth = readOpenAIOAuthToken(api);
934
+ if (oauth) return oauth;
935
+ }
639
936
  if (!hit) return "";
640
937
  const k = typeof hit.key === "string" ? hit.key : "";
641
938
  if (k) return k;
@@ -665,6 +962,8 @@ function formatBalanceAmount(total) {
665
962
  });
666
963
  }
667
964
  function formatBalanceText(list, pref, rate) {
965
+ const custom = list.find((x) => x.display);
966
+ if (custom?.display) return custom.display;
668
967
  const native = pref ? list.find((x) => x.currency === pref) : void 0;
669
968
  if (native) return balanceSymbol(native.currency) + formatBalanceAmount(native.total);
670
969
  const base = list[0];
@@ -675,6 +974,16 @@ function formatBalanceText(list, pref, rate) {
675
974
  }) : formatBalanceAmount(base.total);
676
975
  return balanceSymbol(pref || base.currency) + shown;
677
976
  }
977
+ var BALANCE_DETAIL_LABELS = {
978
+ plan: "balDetailPlan",
979
+ used: "balDetailUsed",
980
+ remaining: "balDetailRemaining",
981
+ window: "balDetailWindow",
982
+ reset: "balDetailReset",
983
+ codeReview: "balDetailCodeReview",
984
+ credits: "balDetailCredits",
985
+ resetCredits: "balDetailResetCredits"
986
+ };
678
987
  var CURRENCIES = {
679
988
  USD: "$",
680
989
  CNY: "\xA5",
@@ -706,6 +1015,7 @@ function TokenCachePanel(props) {
706
1015
  const [modelOpen, setModelOpen] = createSignal(true);
707
1016
  const [distOpen, setDistOpen] = createSignal(false);
708
1017
  const [skillsOpen, setSkillsOpen] = createSignal(true);
1018
+ const [balanceOpen, setBalanceOpen] = createSignal(false);
709
1019
  let boxEl;
710
1020
  createEffect(() => {
711
1021
  props.signals.setSidebarVisible(true);
@@ -741,6 +1051,31 @@ function TokenCachePanel(props) {
741
1051
  setBorderVisible
742
1052
  } = props.signals;
743
1053
  const t = createT(() => langCode());
1054
+ const formatBalanceDuration = (seconds, fallback = "") => {
1055
+ if (!Number.isFinite(seconds)) return "";
1056
+ let remaining = Math.max(0, Math.round(seconds));
1057
+ const days = Math.floor(remaining / 86400);
1058
+ remaining %= 86400;
1059
+ const hours = Math.floor(remaining / 3600);
1060
+ remaining %= 3600;
1061
+ const minutes = Math.floor(remaining / 60);
1062
+ const parts = [];
1063
+ if (days > 0) parts.push(`${days}${t("balDay")}`);
1064
+ if (hours > 0 && parts.length < 2) parts.push(`${hours}${t("balHour")}`);
1065
+ if (minutes > 0 && parts.length < 2) parts.push(`${minutes}${t("balMinute")}`);
1066
+ return parts.join(langCode() === "en" ? " " : "") || fallback;
1067
+ };
1068
+ const formatBalanceDetailValue = (detail) => {
1069
+ if (detail.value === "unlimited") return t("balUnlimited");
1070
+ if (detail.key !== "reset") return detail.value;
1071
+ return formatBalanceDuration(Number(detail.value), t("balResetSoon")) || detail.value;
1072
+ };
1073
+ const formatBalanceDetailLabel = (detail) => {
1074
+ const label = t(BALANCE_DETAIL_LABELS[detail.key]);
1075
+ if (detail.windowSeconds === void 0) return label;
1076
+ const window = formatBalanceDuration(detail.windowSeconds);
1077
+ return window ? `${label} (${window})` : label;
1078
+ };
744
1079
  const [lastDist, setLastDist] = createSignal({
745
1080
  system: 0,
746
1081
  user: 0,
@@ -1054,6 +1389,7 @@ function TokenCachePanel(props) {
1054
1389
  const data = createMemo(() => {
1055
1390
  return dataSignal();
1056
1391
  });
1392
+ const balanceDetails = createMemo(() => balanceState().data?.find((entry) => entry.details)?.details ?? []);
1057
1393
  createEffect(() => {
1058
1394
  const d = data();
1059
1395
  if (d.hasDistData) {
@@ -1085,6 +1421,7 @@ function TokenCachePanel(props) {
1085
1421
  setModelOpen(Boolean(props.api.kv.get(`${KV_PREFIX}.model`, true)));
1086
1422
  setDistOpen(Boolean(props.api.kv.get(`${KV_PREFIX}.dist`, false)));
1087
1423
  setSkillsOpen(Boolean(props.api.kv.get(`${KV_PREFIX}.skills`, true)));
1424
+ setBalanceOpen(Boolean(props.api.kv.get(`${KV_PREFIX}.balance.open`, false)));
1088
1425
  } catch {
1089
1426
  }
1090
1427
  const doRestore = () => {
@@ -1214,6 +1551,19 @@ function TokenCachePanel(props) {
1214
1551
  const gap = Math.max(1, gauge - used);
1215
1552
  return label + " ".repeat(gap) + value + (unit ? " " + unit : "");
1216
1553
  };
1554
+ const balanceHeader = () => {
1555
+ const arrow = balanceDetails().length > 0 ? balanceOpen() ? "\u25BC " : "\u25B6 " : "";
1556
+ const title = t("secBalance");
1557
+ const summary = balanceState().data ? formatBalanceText(balanceState().data, balanceCurrency(), exchangeRate()) : "";
1558
+ const gauge = panelWidth() - gutter();
1559
+ const dividerLength = Math.max(1, gauge - visualWidth(arrow + title) - visualWidth(summary) - 1);
1560
+ return {
1561
+ arrow,
1562
+ title,
1563
+ summary,
1564
+ divider: sep().slice(0, dividerLength)
1565
+ };
1566
+ };
1217
1567
  return (() => {
1218
1568
  var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("span"), _el$4 = _$createElement("span"), _el$5 = _$createElement("b");
1219
1569
  _$insertNode(_el$, _el$2);
@@ -1335,25 +1685,25 @@ function TokenCachePanel(props) {
1335
1685
  const prefix = " \u21B3 " + t("subPrefix");
1336
1686
  const maxSidW = Math.max(6, panelWidth() - visualWidth(prefix));
1337
1687
  return (() => {
1338
- var _el$70 = _$createElement("text"), _el$71 = _$createElement("span"), _el$72 = _$createElement("span");
1339
- _$insertNode(_el$70, _el$71);
1340
- _$insertNode(_el$70, _el$72);
1341
- _$insert(_el$71, prefix);
1342
- _$insert(_el$72, () => truncateVisual(props.signals.overrideSessionId(), maxSidW));
1688
+ var _el$76 = _$createElement("text"), _el$77 = _$createElement("span"), _el$78 = _$createElement("span");
1689
+ _$insertNode(_el$76, _el$77);
1690
+ _$insertNode(_el$76, _el$78);
1691
+ _$insert(_el$77, prefix);
1692
+ _$insert(_el$78, () => truncateVisual(props.signals.overrideSessionId(), maxSidW));
1343
1693
  _$effect((_p$) => {
1344
- var _v$17 = {
1694
+ var _v$21 = {
1345
1695
  fg: pal().muted
1346
- }, _v$18 = {
1696
+ }, _v$22 = {
1347
1697
  fg: pal().text
1348
1698
  };
1349
- _v$17 !== _p$.e && (_p$.e = _$setProp(_el$71, "style", _v$17, _p$.e));
1350
- _v$18 !== _p$.t && (_p$.t = _$setProp(_el$72, "style", _v$18, _p$.t));
1699
+ _v$21 !== _p$.e && (_p$.e = _$setProp(_el$77, "style", _v$21, _p$.e));
1700
+ _v$22 !== _p$.t && (_p$.t = _$setProp(_el$78, "style", _v$22, _p$.t));
1351
1701
  return _p$;
1352
1702
  }, {
1353
1703
  e: void 0,
1354
1704
  t: void 0
1355
1705
  });
1356
- return _el$70;
1706
+ return _el$76;
1357
1707
  })();
1358
1708
  })();
1359
1709
  }
@@ -1363,30 +1713,30 @@ function TokenCachePanel(props) {
1363
1713
  },
1364
1714
  get fallback() {
1365
1715
  return [(() => {
1366
- var _el$73 = _$createElement("text");
1367
- _$insert(_el$73, sep);
1368
- _$effect((_$p) => _$setProp(_el$73, "fg", pal().muted, _$p));
1369
- return _el$73;
1716
+ var _el$79 = _$createElement("text");
1717
+ _$insert(_el$79, sep);
1718
+ _$effect((_$p) => _$setProp(_el$79, "fg", pal().muted, _$p));
1719
+ return _el$79;
1370
1720
  })(), (() => {
1371
- var _el$74 = _$createElement("text"), _el$75 = _$createElement("span"), _el$77 = _$createElement("span");
1372
- _$insertNode(_el$74, _el$75);
1373
- _$insertNode(_el$74, _el$77);
1374
- _$insertNode(_el$75, _$createTextNode(`> `));
1375
- _$insert(_el$77, () => t("noData"));
1721
+ var _el$80 = _$createElement("text"), _el$81 = _$createElement("span"), _el$83 = _$createElement("span");
1722
+ _$insertNode(_el$80, _el$81);
1723
+ _$insertNode(_el$80, _el$83);
1724
+ _$insertNode(_el$81, _$createTextNode(`> `));
1725
+ _$insert(_el$83, () => t("noData"));
1376
1726
  _$effect((_p$) => {
1377
- var _v$19 = {
1727
+ var _v$23 = {
1378
1728
  fg: pal().muted
1379
- }, _v$20 = {
1729
+ }, _v$24 = {
1380
1730
  fg: pal().muted
1381
1731
  };
1382
- _v$19 !== _p$.e && (_p$.e = _$setProp(_el$75, "style", _v$19, _p$.e));
1383
- _v$20 !== _p$.t && (_p$.t = _$setProp(_el$77, "style", _v$20, _p$.t));
1732
+ _v$23 !== _p$.e && (_p$.e = _$setProp(_el$81, "style", _v$23, _p$.e));
1733
+ _v$24 !== _p$.t && (_p$.t = _$setProp(_el$83, "style", _v$24, _p$.t));
1384
1734
  return _p$;
1385
1735
  }, {
1386
1736
  e: void 0,
1387
1737
  t: void 0
1388
1738
  });
1389
- return _el$74;
1739
+ return _el$80;
1390
1740
  })()];
1391
1741
  },
1392
1742
  get children() {
@@ -1565,37 +1915,37 @@ function TokenCachePanel(props) {
1565
1915
  },
1566
1916
  get children() {
1567
1917
  return [_$memo(() => (() => {
1568
- var _el$78 = _$createElement("text"), _el$79 = _$createElement("span"), _el$80 = _$createElement("span"), _el$81 = _$createElement("b"), _el$82 = _$createElement("span");
1569
- _$insertNode(_el$78, _el$79);
1570
- _$insertNode(_el$78, _el$80);
1571
- _$insertNode(_el$78, _el$82);
1572
- _$setProp(_el$78, "onMouseUp", () => setModelOpen((o) => {
1918
+ var _el$84 = _$createElement("text"), _el$85 = _$createElement("span"), _el$86 = _$createElement("span"), _el$87 = _$createElement("b"), _el$88 = _$createElement("span");
1919
+ _$insertNode(_el$84, _el$85);
1920
+ _$insertNode(_el$84, _el$86);
1921
+ _$insertNode(_el$84, _el$88);
1922
+ _$setProp(_el$84, "onMouseUp", () => setModelOpen((o) => {
1573
1923
  const n = !o;
1574
1924
  persistFold("model", n);
1575
1925
  return n;
1576
1926
  }));
1577
- _$insert(_el$79, () => modelOpen() ? "\u25BC " : "\u25B6 ");
1578
- _$insertNode(_el$80, _el$81);
1579
- _$insert(_el$81, () => t("secModel"));
1580
- _$insert(_el$82, () => sep().slice(visualWidth((modelOpen() ? "\u25BC " : "\u25B6 ") + t("secModel"))));
1927
+ _$insert(_el$85, () => modelOpen() ? "\u25BC " : "\u25B6 ");
1928
+ _$insertNode(_el$86, _el$87);
1929
+ _$insert(_el$87, () => t("secModel"));
1930
+ _$insert(_el$88, () => sep().slice(visualWidth((modelOpen() ? "\u25BC " : "\u25B6 ") + t("secModel"))));
1581
1931
  _$effect((_p$) => {
1582
- var _v$21 = {
1932
+ var _v$25 = {
1583
1933
  fg: pal().muted
1584
- }, _v$22 = {
1934
+ }, _v$26 = {
1585
1935
  fg: pal().primary
1586
- }, _v$23 = {
1936
+ }, _v$27 = {
1587
1937
  fg: pal().muted
1588
1938
  };
1589
- _v$21 !== _p$.e && (_p$.e = _$setProp(_el$79, "style", _v$21, _p$.e));
1590
- _v$22 !== _p$.t && (_p$.t = _$setProp(_el$80, "style", _v$22, _p$.t));
1591
- _v$23 !== _p$.a && (_p$.a = _$setProp(_el$82, "style", _v$23, _p$.a));
1939
+ _v$25 !== _p$.e && (_p$.e = _$setProp(_el$85, "style", _v$25, _p$.e));
1940
+ _v$26 !== _p$.t && (_p$.t = _$setProp(_el$86, "style", _v$26, _p$.t));
1941
+ _v$27 !== _p$.a && (_p$.a = _$setProp(_el$88, "style", _v$27, _p$.a));
1592
1942
  return _p$;
1593
1943
  }, {
1594
1944
  e: void 0,
1595
1945
  t: void 0,
1596
1946
  a: void 0
1597
1947
  });
1598
- return _el$78;
1948
+ return _el$84;
1599
1949
  })()), _$createComponent(Show, {
1600
1950
  get when() {
1601
1951
  return modelOpen();
@@ -1668,37 +2018,37 @@ function TokenCachePanel(props) {
1668
2018
  },
1669
2019
  get children() {
1670
2020
  return [_$memo(() => (() => {
1671
- var _el$83 = _$createElement("text"), _el$84 = _$createElement("span"), _el$85 = _$createElement("span"), _el$86 = _$createElement("b"), _el$87 = _$createElement("span");
1672
- _$insertNode(_el$83, _el$84);
1673
- _$insertNode(_el$83, _el$85);
1674
- _$insertNode(_el$83, _el$87);
1675
- _$setProp(_el$83, "onMouseUp", () => setDistOpen((o) => {
2021
+ var _el$89 = _$createElement("text"), _el$90 = _$createElement("span"), _el$91 = _$createElement("span"), _el$92 = _$createElement("b"), _el$93 = _$createElement("span");
2022
+ _$insertNode(_el$89, _el$90);
2023
+ _$insertNode(_el$89, _el$91);
2024
+ _$insertNode(_el$89, _el$93);
2025
+ _$setProp(_el$89, "onMouseUp", () => setDistOpen((o) => {
1676
2026
  const n = !o;
1677
2027
  persistFold("dist", n);
1678
2028
  return n;
1679
2029
  }));
1680
- _$insert(_el$84, () => distOpen() ? "\u25BC " : "\u25B6 ");
1681
- _$insertNode(_el$85, _el$86);
1682
- _$insert(_el$86, () => t("distTitle"));
1683
- _$insert(_el$87, () => sep().slice(visualWidth((distOpen() ? "\u25BC " : "\u25B6 ") + t("distTitle"))));
2030
+ _$insert(_el$90, () => distOpen() ? "\u25BC " : "\u25B6 ");
2031
+ _$insertNode(_el$91, _el$92);
2032
+ _$insert(_el$92, () => t("distTitle"));
2033
+ _$insert(_el$93, () => sep().slice(visualWidth((distOpen() ? "\u25BC " : "\u25B6 ") + t("distTitle"))));
1684
2034
  _$effect((_p$) => {
1685
- var _v$24 = {
2035
+ var _v$28 = {
1686
2036
  fg: pal().muted
1687
- }, _v$25 = {
2037
+ }, _v$29 = {
1688
2038
  fg: pal().primary
1689
- }, _v$26 = {
2039
+ }, _v$30 = {
1690
2040
  fg: pal().muted
1691
2041
  };
1692
- _v$24 !== _p$.e && (_p$.e = _$setProp(_el$84, "style", _v$24, _p$.e));
1693
- _v$25 !== _p$.t && (_p$.t = _$setProp(_el$85, "style", _v$25, _p$.t));
1694
- _v$26 !== _p$.a && (_p$.a = _$setProp(_el$87, "style", _v$26, _p$.a));
2042
+ _v$28 !== _p$.e && (_p$.e = _$setProp(_el$90, "style", _v$28, _p$.e));
2043
+ _v$29 !== _p$.t && (_p$.t = _$setProp(_el$91, "style", _v$29, _p$.t));
2044
+ _v$30 !== _p$.a && (_p$.a = _$setProp(_el$93, "style", _v$30, _p$.a));
1695
2045
  return _p$;
1696
2046
  }, {
1697
2047
  e: void 0,
1698
2048
  t: void 0,
1699
2049
  a: void 0
1700
2050
  });
1701
- return _el$83;
2051
+ return _el$89;
1702
2052
  })()), _$createComponent(Show, {
1703
2053
  get when() {
1704
2054
  return distOpen();
@@ -1781,37 +2131,37 @@ function TokenCachePanel(props) {
1781
2131
  },
1782
2132
  get children() {
1783
2133
  return [_$memo(() => (() => {
1784
- var _el$88 = _$createElement("text"), _el$89 = _$createElement("span"), _el$90 = _$createElement("span"), _el$91 = _$createElement("b"), _el$92 = _$createElement("span"), _el$93 = _$createTextNode(` (`), _el$94 = _$createTextNode(`)`), _el$95 = _$createElement("span");
1785
- _$insertNode(_el$88, _el$89);
1786
- _$insertNode(_el$88, _el$90);
1787
- _$insertNode(_el$88, _el$92);
1788
- _$insertNode(_el$88, _el$95);
1789
- _$setProp(_el$88, "onMouseUp", () => setSkillsOpen((o) => {
2134
+ var _el$94 = _$createElement("text"), _el$95 = _$createElement("span"), _el$96 = _$createElement("span"), _el$97 = _$createElement("b"), _el$98 = _$createElement("span"), _el$99 = _$createTextNode(` (`), _el$100 = _$createTextNode(`)`), _el$101 = _$createElement("span");
2135
+ _$insertNode(_el$94, _el$95);
2136
+ _$insertNode(_el$94, _el$96);
2137
+ _$insertNode(_el$94, _el$98);
2138
+ _$insertNode(_el$94, _el$101);
2139
+ _$setProp(_el$94, "onMouseUp", () => setSkillsOpen((o) => {
1790
2140
  const n = !o;
1791
2141
  persistFold("skills", n);
1792
2142
  return n;
1793
2143
  }));
1794
- _$insert(_el$89, () => skillsOpen() ? "\u25BC " : "\u25B6 ");
1795
- _$insertNode(_el$90, _el$91);
1796
- _$insert(_el$91, () => t("secSkills"));
1797
- _$insertNode(_el$92, _el$93);
1798
- _$insertNode(_el$92, _el$94);
1799
- _$insert(_el$92, () => data().skills.length, _el$94);
1800
- _$insert(_el$95, () => sep().slice(visualWidth((skillsOpen() ? "\u25BC " : "\u25B6 ") + t("secSkills") + ` (${data().skills.length})`)));
2144
+ _$insert(_el$95, () => skillsOpen() ? "\u25BC " : "\u25B6 ");
2145
+ _$insertNode(_el$96, _el$97);
2146
+ _$insert(_el$97, () => t("secSkills"));
2147
+ _$insertNode(_el$98, _el$99);
2148
+ _$insertNode(_el$98, _el$100);
2149
+ _$insert(_el$98, () => data().skills.length, _el$100);
2150
+ _$insert(_el$101, () => sep().slice(visualWidth((skillsOpen() ? "\u25BC " : "\u25B6 ") + t("secSkills") + ` (${data().skills.length})`)));
1801
2151
  _$effect((_p$) => {
1802
- var _v$27 = {
2152
+ var _v$31 = {
1803
2153
  fg: pal().muted
1804
- }, _v$28 = {
2154
+ }, _v$32 = {
1805
2155
  fg: pal().primary
1806
- }, _v$29 = {
2156
+ }, _v$33 = {
1807
2157
  fg: pal().muted
1808
- }, _v$30 = {
2158
+ }, _v$34 = {
1809
2159
  fg: pal().muted
1810
2160
  };
1811
- _v$27 !== _p$.e && (_p$.e = _$setProp(_el$89, "style", _v$27, _p$.e));
1812
- _v$28 !== _p$.t && (_p$.t = _$setProp(_el$90, "style", _v$28, _p$.t));
1813
- _v$29 !== _p$.a && (_p$.a = _$setProp(_el$92, "style", _v$29, _p$.a));
1814
- _v$30 !== _p$.o && (_p$.o = _$setProp(_el$95, "style", _v$30, _p$.o));
2161
+ _v$31 !== _p$.e && (_p$.e = _$setProp(_el$95, "style", _v$31, _p$.e));
2162
+ _v$32 !== _p$.t && (_p$.t = _$setProp(_el$96, "style", _v$32, _p$.t));
2163
+ _v$33 !== _p$.a && (_p$.a = _$setProp(_el$98, "style", _v$33, _p$.a));
2164
+ _v$34 !== _p$.o && (_p$.o = _$setProp(_el$101, "style", _v$34, _p$.o));
1815
2165
  return _p$;
1816
2166
  }, {
1817
2167
  e: void 0,
@@ -1819,7 +2169,7 @@ function TokenCachePanel(props) {
1819
2169
  a: void 0,
1820
2170
  o: void 0
1821
2171
  });
1822
- return _el$88;
2172
+ return _el$94;
1823
2173
  })()), _$createComponent(Show, {
1824
2174
  get when() {
1825
2175
  return skillsOpen();
@@ -1830,10 +2180,10 @@ function TokenCachePanel(props) {
1830
2180
  const maxLabel = Math.max(4, panelWidth() - gutter() - rightW - 1);
1831
2181
  const label = truncateVisual(sk.name, maxLabel);
1832
2182
  return (() => {
1833
- var _el$96 = _$createElement("text");
1834
- _$insert(_el$96, () => justify(label, fmt(sk.tokens), t("tok")));
1835
- _$effect((_$p) => _$setProp(_el$96, "fg", pal().muted, _$p));
1836
- return _el$96;
2183
+ var _el$102 = _$createElement("text");
2184
+ _$insert(_el$102, () => justify(label, fmt(sk.tokens), t("tok")));
2185
+ _$effect((_$p) => _$setProp(_el$102, "fg", pal().muted, _$p));
2186
+ return _el$102;
1837
2187
  })();
1838
2188
  });
1839
2189
  }
@@ -1846,33 +2196,28 @@ function TokenCachePanel(props) {
1846
2196
  return sectionBalance();
1847
2197
  },
1848
2198
  get children() {
1849
- return [(() => {
1850
- var _el$52 = _$createElement("text");
1851
- _$insert(_el$52, sep);
1852
- _$effect((_$p) => _$setProp(_el$52, "fg", pal().muted, _$p));
1853
- return _el$52;
1854
- })(), _$createComponent(Show, {
2199
+ return [_$createComponent(Show, {
1855
2200
  get when() {
1856
2201
  return balanceUnsupported();
1857
2202
  },
1858
2203
  get children() {
1859
- var _el$53 = _$createElement("text"), _el$54 = _$createElement("span"), _el$56 = _$createElement("span");
1860
- _$insertNode(_el$53, _el$54);
1861
- _$insertNode(_el$53, _el$56);
1862
- _$insertNode(_el$54, _$createTextNode(`> `));
1863
- _$insert(_el$56, () => t("balUnsupported"));
2204
+ var _el$52 = _$createElement("text"), _el$53 = _$createElement("span"), _el$55 = _$createElement("span");
2205
+ _$insertNode(_el$52, _el$53);
2206
+ _$insertNode(_el$52, _el$55);
2207
+ _$insertNode(_el$53, _$createTextNode(`> `));
2208
+ _$insert(_el$55, () => t("balUnsupported"));
1864
2209
  _$effect((_p$) => {
1865
2210
  var _v$9 = pal().muted, _v$0 = {
1866
2211
  fg: pal().muted
1867
2212
  };
1868
- _v$9 !== _p$.e && (_p$.e = _$setProp(_el$53, "fg", _v$9, _p$.e));
1869
- _v$0 !== _p$.t && (_p$.t = _$setProp(_el$54, "style", _v$0, _p$.t));
2213
+ _v$9 !== _p$.e && (_p$.e = _$setProp(_el$52, "fg", _v$9, _p$.e));
2214
+ _v$0 !== _p$.t && (_p$.t = _$setProp(_el$53, "style", _v$0, _p$.t));
1870
2215
  return _p$;
1871
2216
  }, {
1872
2217
  e: void 0,
1873
2218
  t: void 0
1874
2219
  });
1875
- return _el$53;
2220
+ return _el$52;
1876
2221
  }
1877
2222
  }), _$createComponent(Show, {
1878
2223
  get when() {
@@ -1884,59 +2229,59 @@ function TokenCachePanel(props) {
1884
2229
  return balanceState().status === "idle";
1885
2230
  },
1886
2231
  get children() {
1887
- var _el$57 = _$createElement("text"), _el$58 = _$createElement("span"), _el$60 = _$createElement("span");
1888
- _$insertNode(_el$57, _el$58);
1889
- _$insertNode(_el$57, _el$60);
1890
- _$insertNode(_el$58, _$createTextNode(`> `));
1891
- _$insert(_el$60, () => t("balNoKey", {
2232
+ var _el$56 = _$createElement("text"), _el$57 = _$createElement("span"), _el$59 = _$createElement("span");
2233
+ _$insertNode(_el$56, _el$57);
2234
+ _$insertNode(_el$56, _el$59);
2235
+ _$insertNode(_el$57, _$createTextNode(`> `));
2236
+ _$insert(_el$59, () => t("balNoKey", {
1892
2237
  p: providerName()
1893
2238
  }));
1894
2239
  _$effect((_p$) => {
1895
2240
  var _v$1 = pal().muted, _v$10 = {
1896
2241
  fg: pal().muted
1897
2242
  };
1898
- _v$1 !== _p$.e && (_p$.e = _$setProp(_el$57, "fg", _v$1, _p$.e));
1899
- _v$10 !== _p$.t && (_p$.t = _$setProp(_el$58, "style", _v$10, _p$.t));
2243
+ _v$1 !== _p$.e && (_p$.e = _$setProp(_el$56, "fg", _v$1, _p$.e));
2244
+ _v$10 !== _p$.t && (_p$.t = _$setProp(_el$57, "style", _v$10, _p$.t));
1900
2245
  return _p$;
1901
2246
  }, {
1902
2247
  e: void 0,
1903
2248
  t: void 0
1904
2249
  });
1905
- return _el$57;
2250
+ return _el$56;
1906
2251
  }
1907
2252
  }), _$createComponent(Show, {
1908
2253
  get when() {
1909
2254
  return balanceState().status === "loading";
1910
2255
  },
1911
2256
  get children() {
1912
- var _el$61 = _$createElement("text"), _el$62 = _$createElement("span"), _el$64 = _$createElement("span");
1913
- _$insertNode(_el$61, _el$62);
1914
- _$insertNode(_el$61, _el$64);
1915
- _$insertNode(_el$62, _$createTextNode(`> `));
1916
- _$insert(_el$64, () => t("balLoading"));
2257
+ var _el$60 = _$createElement("text"), _el$61 = _$createElement("span"), _el$63 = _$createElement("span");
2258
+ _$insertNode(_el$60, _el$61);
2259
+ _$insertNode(_el$60, _el$63);
2260
+ _$insertNode(_el$61, _$createTextNode(`> `));
2261
+ _$insert(_el$63, () => t("balLoading"));
1917
2262
  _$effect((_p$) => {
1918
2263
  var _v$11 = pal().muted, _v$12 = {
1919
2264
  fg: pal().muted
1920
2265
  };
1921
- _v$11 !== _p$.e && (_p$.e = _$setProp(_el$61, "fg", _v$11, _p$.e));
1922
- _v$12 !== _p$.t && (_p$.t = _$setProp(_el$62, "style", _v$12, _p$.t));
2266
+ _v$11 !== _p$.e && (_p$.e = _$setProp(_el$60, "fg", _v$11, _p$.e));
2267
+ _v$12 !== _p$.t && (_p$.t = _$setProp(_el$61, "style", _v$12, _p$.t));
1923
2268
  return _p$;
1924
2269
  }, {
1925
2270
  e: void 0,
1926
2271
  t: void 0
1927
2272
  });
1928
- return _el$61;
2273
+ return _el$60;
1929
2274
  }
1930
2275
  }), _$createComponent(Show, {
1931
2276
  get when() {
1932
2277
  return balanceState().status === "error";
1933
2278
  },
1934
2279
  get children() {
1935
- var _el$65 = _$createElement("text"), _el$66 = _$createElement("span"), _el$68 = _$createElement("span");
1936
- _$insertNode(_el$65, _el$66);
1937
- _$insertNode(_el$65, _el$68);
1938
- _$insertNode(_el$66, _$createTextNode(`> `));
1939
- _$insert(_el$68, () => {
2280
+ var _el$64 = _$createElement("text"), _el$65 = _$createElement("span"), _el$67 = _$createElement("span");
2281
+ _$insertNode(_el$64, _el$65);
2282
+ _$insertNode(_el$64, _el$67);
2283
+ _$insertNode(_el$65, _$createTextNode(`> `));
2284
+ _$insert(_el$67, () => {
1940
2285
  const code = balanceState().error;
1941
2286
  if (code === "401") return t("balErr401");
1942
2287
  if (code === "403") return t("balErr403");
@@ -1948,24 +2293,93 @@ function TokenCachePanel(props) {
1948
2293
  var _v$13 = pal().error, _v$14 = {
1949
2294
  fg: pal().muted
1950
2295
  };
1951
- _v$13 !== _p$.e && (_p$.e = _$setProp(_el$65, "fg", _v$13, _p$.e));
1952
- _v$14 !== _p$.t && (_p$.t = _$setProp(_el$66, "style", _v$14, _p$.t));
2296
+ _v$13 !== _p$.e && (_p$.e = _$setProp(_el$64, "fg", _v$13, _p$.e));
2297
+ _v$14 !== _p$.t && (_p$.t = _$setProp(_el$65, "style", _v$14, _p$.t));
1953
2298
  return _p$;
1954
2299
  }, {
1955
2300
  e: void 0,
1956
2301
  t: void 0
1957
2302
  });
1958
- return _el$65;
2303
+ return _el$64;
1959
2304
  }
1960
2305
  }), _$createComponent(Show, {
1961
2306
  get when() {
1962
2307
  return _$memo(() => balanceState().status === "ok")() && balanceState().data;
1963
2308
  },
1964
2309
  get children() {
1965
- var _el$69 = _$createElement("text");
1966
- _$insert(_el$69, () => justify(t("balTotal"), formatBalanceText(balanceState().data, balanceCurrency(), exchangeRate())));
1967
- _$effect((_$p) => _$setProp(_el$69, "fg", pal().text, _$p));
1968
- return _el$69;
2310
+ return [_$createComponent(Show, {
2311
+ get when() {
2312
+ return balanceDetails().length > 0;
2313
+ },
2314
+ get children() {
2315
+ return [(() => {
2316
+ var _el$68 = _$createElement("text"), _el$69 = _$createElement("span"), _el$70 = _$createElement("span"), _el$71 = _$createElement("b"), _el$72 = _$createElement("span"), _el$73 = _$createElement("span");
2317
+ _$insertNode(_el$68, _el$69);
2318
+ _$insertNode(_el$68, _el$70);
2319
+ _$insertNode(_el$68, _el$72);
2320
+ _$insertNode(_el$68, _el$73);
2321
+ _$setProp(_el$68, "onMouseUp", () => {
2322
+ const next = !balanceOpen();
2323
+ setBalanceOpen(next);
2324
+ persistFold("balance.open", next);
2325
+ });
2326
+ _$insert(_el$69, () => balanceHeader().arrow);
2327
+ _$insertNode(_el$70, _el$71);
2328
+ _$insert(_el$71, () => balanceHeader().title);
2329
+ _$insert(_el$72, () => balanceHeader().divider);
2330
+ _$insert(_el$73, () => " " + balanceHeader().summary);
2331
+ _$effect((_p$) => {
2332
+ var _v$15 = pal().text, _v$16 = {
2333
+ fg: pal().muted
2334
+ }, _v$17 = {
2335
+ fg: pal().primary
2336
+ }, _v$18 = {
2337
+ fg: pal().muted
2338
+ };
2339
+ _v$15 !== _p$.e && (_p$.e = _$setProp(_el$68, "fg", _v$15, _p$.e));
2340
+ _v$16 !== _p$.t && (_p$.t = _$setProp(_el$69, "style", _v$16, _p$.t));
2341
+ _v$17 !== _p$.a && (_p$.a = _$setProp(_el$70, "style", _v$17, _p$.a));
2342
+ _v$18 !== _p$.o && (_p$.o = _$setProp(_el$72, "style", _v$18, _p$.o));
2343
+ return _p$;
2344
+ }, {
2345
+ e: void 0,
2346
+ t: void 0,
2347
+ a: void 0,
2348
+ o: void 0
2349
+ });
2350
+ return _el$68;
2351
+ })(), _$createComponent(Show, {
2352
+ get when() {
2353
+ return balanceOpen();
2354
+ },
2355
+ get children() {
2356
+ return balanceDetails().map((detail) => (() => {
2357
+ var _el$103 = _$createElement("text");
2358
+ _$insert(_el$103, () => justify(formatBalanceDetailLabel(detail) + ":", formatBalanceDetailValue(detail)));
2359
+ _$effect((_$p) => _$setProp(_el$103, "fg", pal().muted, _$p));
2360
+ return _el$103;
2361
+ })());
2362
+ }
2363
+ })];
2364
+ }
2365
+ }), _$createComponent(Show, {
2366
+ get when() {
2367
+ return balanceDetails().length === 0;
2368
+ },
2369
+ get children() {
2370
+ return [(() => {
2371
+ var _el$74 = _$createElement("text");
2372
+ _$insert(_el$74, sep);
2373
+ _$effect((_$p) => _$setProp(_el$74, "fg", pal().muted, _$p));
2374
+ return _el$74;
2375
+ })(), (() => {
2376
+ var _el$75 = _$createElement("text");
2377
+ _$insert(_el$75, () => justify(t("balTotal"), formatBalanceText(balanceState().data, balanceCurrency(), exchangeRate())));
2378
+ _$effect((_$p) => _$setProp(_el$75, "fg", pal().text, _$p));
2379
+ return _el$75;
2380
+ })()];
2381
+ }
2382
+ })];
1969
2383
  }
1970
2384
  })];
1971
2385
  }
@@ -1977,13 +2391,13 @@ function TokenCachePanel(props) {
1977
2391
  }
1978
2392
  }), null);
1979
2393
  _$effect((_p$) => {
1980
- var _v$15 = {
2394
+ var _v$19 = {
1981
2395
  fg: pal().muted
1982
- }, _v$16 = {
2396
+ }, _v$20 = {
1983
2397
  fg: pal().primary
1984
2398
  };
1985
- _v$15 !== _p$.e && (_p$.e = _$setProp(_el$3, "style", _v$15, _p$.e));
1986
- _v$16 !== _p$.t && (_p$.t = _$setProp(_el$4, "style", _v$16, _p$.t));
2399
+ _v$19 !== _p$.e && (_p$.e = _$setProp(_el$3, "style", _v$19, _p$.e));
2400
+ _v$20 !== _p$.t && (_p$.t = _$setProp(_el$4, "style", _v$20, _p$.t));
1987
2401
  return _p$;
1988
2402
  }, {
1989
2403
  e: void 0,
@@ -2247,39 +2661,39 @@ function BottomStatusBar(props) {
2247
2661
  },
2248
2662
  get fallback() {
2249
2663
  return (() => {
2250
- var _el$101 = _$createElement("text");
2251
- _$insert(_el$101, dirFallback);
2252
- _$effect((_$p) => _$setProp(_el$101, "fg", pal().muted, _$p));
2253
- return _el$101;
2664
+ var _el$108 = _$createElement("text");
2665
+ _$insert(_el$108, dirFallback);
2666
+ _$effect((_$p) => _$setProp(_el$108, "fg", pal().muted, _$p));
2667
+ return _el$108;
2254
2668
  })();
2255
2669
  },
2256
2670
  get children() {
2257
- var _el$97 = _$createElement("box"), _el$98 = _$createElement("text"), _el$99 = _$createElement("box"), _el$100 = _$createElement("text");
2258
- _$insertNode(_el$97, _el$98);
2259
- _$insertNode(_el$97, _el$99);
2260
- _$setProp(_el$97, "marginLeft", 1);
2261
- _$setProp(_el$97, "flexGrow", 1);
2262
- _$setProp(_el$97, "flexShrink", 0);
2263
- _$setProp(_el$97, "flexDirection", "row");
2264
- _$setProp(_el$97, "justifyContent", "space-between");
2265
- _$insert(_el$98, dirDisplay);
2266
- _$insertNode(_el$99, _el$100);
2267
- _$setProp(_el$99, "flexDirection", "row");
2268
- _$insert(_el$100, _$createComponent(For, {
2671
+ var _el$104 = _$createElement("box"), _el$105 = _$createElement("text"), _el$106 = _$createElement("box"), _el$107 = _$createElement("text");
2672
+ _$insertNode(_el$104, _el$105);
2673
+ _$insertNode(_el$104, _el$106);
2674
+ _$setProp(_el$104, "marginLeft", 1);
2675
+ _$setProp(_el$104, "flexGrow", 1);
2676
+ _$setProp(_el$104, "flexShrink", 0);
2677
+ _$setProp(_el$104, "flexDirection", "row");
2678
+ _$setProp(_el$104, "justifyContent", "space-between");
2679
+ _$insert(_el$105, dirDisplay);
2680
+ _$insertNode(_el$106, _el$107);
2681
+ _$setProp(_el$106, "flexDirection", "row");
2682
+ _$insert(_el$107, _$createComponent(For, {
2269
2683
  get each() {
2270
2684
  return statsSegs();
2271
2685
  },
2272
2686
  children: (sg) => (() => {
2273
- var _el$102 = _$createElement("span");
2274
- _$insert(_el$102, () => sg.text);
2275
- _$effect((_$p) => _$setProp(_el$102, "style", {
2687
+ var _el$109 = _$createElement("span");
2688
+ _$insert(_el$109, () => sg.text);
2689
+ _$effect((_$p) => _$setProp(_el$109, "style", {
2276
2690
  fg: sg.color
2277
2691
  }, _$p));
2278
- return _el$102;
2692
+ return _el$109;
2279
2693
  })()
2280
2694
  }));
2281
- _$effect((_$p) => _$setProp(_el$98, "fg", pal().muted, _$p));
2282
- return _el$97;
2695
+ _$effect((_$p) => _$setProp(_el$105, "fg", pal().muted, _$p));
2696
+ return _el$104;
2283
2697
  }
2284
2698
  });
2285
2699
  }
@@ -2520,11 +2934,11 @@ var tui = async (api) => {
2520
2934
  return provider.name;
2521
2935
  },
2522
2936
  description: () => (() => {
2523
- var _el$103 = _$createElement("text");
2524
- _$insert(_el$103, () => t("balKeyPrompt", {
2937
+ var _el$110 = _$createElement("text");
2938
+ _$insert(_el$110, () => t("balKeyPrompt", {
2525
2939
  p: provider.name
2526
2940
  }));
2527
- return _el$103;
2941
+ return _el$110;
2528
2942
  })(),
2529
2943
  get placeholder() {
2530
2944
  return provider.keyPlaceholder ?? "sk-...";
@@ -2604,9 +3018,9 @@ var tui = async (api) => {
2604
3018
  dialog?.replace(() => _$createComponent(api.ui.DialogPrompt, {
2605
3019
  title: "Exchange Rate",
2606
3020
  description: () => (() => {
2607
- var _el$104 = _$createElement("text");
2608
- _$insertNode(_el$104, _$createTextNode(`Enter the exchange rate from USD to your currency (e.g. 7.2 for CNY)`));
2609
- return _el$104;
3021
+ var _el$111 = _$createElement("text");
3022
+ _$insertNode(_el$111, _$createTextNode(`Enter the exchange rate from USD to your currency (e.g. 7.2 for CNY)`));
3023
+ return _el$111;
2610
3024
  })(),
2611
3025
  placeholder: "1.0",
2612
3026
  get value() {
@@ -3018,9 +3432,9 @@ var tui = async (api) => {
3018
3432
  return _$memo(() => !!signals.overrideSessionId())() ? t("subSwitchTitle") : t("subViewTitle");
3019
3433
  },
3020
3434
  description: () => (() => {
3021
- var _el$106 = _$createElement("text");
3022
- _$insert(_el$106, () => t("subNoFound"));
3023
- return _el$106;
3435
+ var _el$113 = _$createElement("text");
3436
+ _$insert(_el$113, () => t("subNoFound"));
3437
+ return _el$113;
3024
3438
  })(),
3025
3439
  placeholder: "ses_...",
3026
3440
  get value() {