opencode-visual-cache 1.6.1 → 1.7.0-beta.0

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.
Files changed (62) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +247 -247
  3. package/README_EN.md +247 -247
  4. package/dist/_version.d.ts +1 -1
  5. package/dist/_version.js +1 -1
  6. package/dist/core/color.d.ts +37 -0
  7. package/dist/core/color.js +108 -0
  8. package/dist/core/currency.d.ts +17 -0
  9. package/dist/core/currency.js +43 -0
  10. package/dist/core/estimate.d.ts +1 -0
  11. package/dist/core/estimate.js +40 -0
  12. package/dist/core/format.d.ts +15 -0
  13. package/dist/core/format.js +90 -0
  14. package/dist/core/index.d.ts +5 -0
  15. package/dist/core/index.js +5 -0
  16. package/dist/core/types.d.ts +17 -0
  17. package/dist/core/types.js +1 -0
  18. package/dist/index.js +159 -815
  19. package/dist/panel/TokenCachePanel.d.ts +10 -0
  20. package/dist/panel/TokenCachePanel.js +549 -0
  21. package/dist/panel/panel-api.d.ts +119 -0
  22. package/dist/panel/panel-api.js +1 -0
  23. package/dist/tui.js +349 -264
  24. package/dist/v2/commands.d.ts +10 -0
  25. package/dist/v2/commands.js +490 -0
  26. package/dist/v2/data.d.ts +27 -0
  27. package/dist/v2/data.js +103 -0
  28. package/dist/v2/index.d.ts +4 -0
  29. package/dist/v2/index.js +163 -0
  30. package/dist/v2/sidebar.d.ts +6 -0
  31. package/dist/v2/sidebar.js +36 -0
  32. package/dist/v2/status.d.ts +14 -0
  33. package/dist/v2/status.js +83 -0
  34. package/dist/v2/theme.d.ts +8 -0
  35. package/dist/v2/theme.js +16 -0
  36. package/dist/v2/types.d.ts +219 -0
  37. package/dist/v2/types.js +6 -0
  38. package/dist/v2/v2-panel-api.d.ts +8 -0
  39. package/dist/v2/v2-panel-api.js +176 -0
  40. package/dist/v2.js +2941 -0
  41. package/package.json +70 -67
  42. package/src/_version.ts +1 -1
  43. package/src/balance-providers.ts +153 -153
  44. package/src/core/color.ts +108 -0
  45. package/src/core/currency.ts +46 -0
  46. package/src/core/estimate.ts +36 -0
  47. package/src/core/format.ts +81 -0
  48. package/src/core/index.ts +5 -0
  49. package/src/core/types.ts +17 -0
  50. package/src/i18n.ts +380 -380
  51. package/src/index.tsx +1035 -1980
  52. package/src/panel/TokenCachePanel.tsx +776 -0
  53. package/src/panel/panel-api.ts +104 -0
  54. package/src/server.ts +10 -10
  55. package/src/v2/commands.ts +471 -0
  56. package/src/v2/data.ts +112 -0
  57. package/src/v2/index.tsx +184 -0
  58. package/src/v2/sidebar.tsx +69 -0
  59. package/src/v2/status.tsx +96 -0
  60. package/src/v2/theme.ts +19 -0
  61. package/src/v2/types.ts +159 -0
  62. package/src/v2/v2-panel-api.ts +177 -0
package/dist/tui.js CHANGED
@@ -1,19 +1,13 @@
1
1
  // src/index.tsx
2
- import { createComponent as _$createComponent } from "@opentui/solid";
3
- import { effect as _$effect } from "@opentui/solid";
4
- import { createTextNode as _$createTextNode } from "@opentui/solid";
5
- import { insertNode as _$insertNode } from "@opentui/solid";
6
- import { insert as _$insert } from "@opentui/solid";
7
- import { setProp as _$setProp } from "@opentui/solid";
8
- import { use as _$use } from "@opentui/solid";
9
- import { spread as _$spread } from "@opentui/solid";
10
- import { mergeProps as _$mergeProps } from "@opentui/solid";
11
- import { memo as _$memo } from "@opentui/solid";
12
- import { createElement as _$createElement } from "@opentui/solid";
13
- import { createMemo, createSignal, createEffect, onMount, onCleanup, Show, untrack } from "solid-js";
14
-
15
- // src/_version.ts
16
- var PLUGIN_VERSION = "1.6.1";
2
+ import { createTextNode as _$createTextNode2 } from "@opentui/solid";
3
+ import { memo as _$memo2 } from "@opentui/solid";
4
+ import { effect as _$effect2 } from "@opentui/solid";
5
+ import { insertNode as _$insertNode2 } from "@opentui/solid";
6
+ import { createComponent as _$createComponent2 } from "@opentui/solid";
7
+ import { insert as _$insert2 } from "@opentui/solid";
8
+ import { setProp as _$setProp2 } from "@opentui/solid";
9
+ import { createElement as _$createElement2 } from "@opentui/solid";
10
+ import { createMemo as createMemo2, createSignal as createSignal2, createEffect as createEffect2, onMount as onMount2, onCleanup as onCleanup2, Show as Show2, For, untrack as untrack2 } from "solid-js";
17
11
 
18
12
  // src/balance-providers.ts
19
13
  var BalanceError = class extends Error {
@@ -471,49 +465,7 @@ function detectLang() {
471
465
  }
472
466
  }
473
467
 
474
- // src/index.tsx
475
- function charColumns(c) {
476
- const code = c.codePointAt(0) ?? 0;
477
- if (code < 32) return 0;
478
- if (code < 127) return 1;
479
- if (code < 160) return 0;
480
- if (code >= 4352 && code <= 4447 || // Hangul Jamo
481
- code >= 11904 && code <= 42191 || // CJK Radicals … Yi
482
- code >= 44032 && code <= 55203 || // Hangul
483
- code >= 63744 && code <= 64255 || // CJK Compat
484
- code >= 65040 && code <= 65135 || // Vertical / Compat
485
- code >= 65281 && code <= 65376 || // Fullwidth
486
- code >= 65504 && code <= 65510 || // Fullwidth signs
487
- code >= 127744 && code <= 128591 || // Misc Symbols (emoji)
488
- code >= 131072 && code <= 262141)
489
- return 2;
490
- return 1;
491
- }
492
- function visualWidth(s) {
493
- let w = 0;
494
- for (const c of s) w += charColumns(c);
495
- return w;
496
- }
497
- function visualPadEnd(s, cols) {
498
- const pad = cols - visualWidth(s);
499
- return pad > 0 ? s + " ".repeat(pad) : s;
500
- }
501
- function truncateVisual(s, maxCols) {
502
- if (visualWidth(s) <= maxCols) return s;
503
- let result = "", w = 0;
504
- for (const c of s) {
505
- const cw = charColumns(c);
506
- if (w + cw > maxCols - 1) {
507
- result += "\u2026";
508
- break;
509
- }
510
- result += c;
511
- w += cw;
512
- }
513
- return result;
514
- }
515
- var DEBUG_LANG = typeof process !== "undefined" ? process.env?.CACHE_TUI_LANG : void 0;
516
- var INIT_LANG = DEBUG_LANG !== void 0 && LANG_META.some((m) => m.code === DEBUG_LANG) ? DEBUG_LANG : detectLang();
468
+ // src/core/color.ts
517
469
  function rgb(raw) {
518
470
  if (typeof raw === "string" && raw.startsWith("#")) {
519
471
  const h = raw.slice(1);
@@ -584,6 +536,48 @@ var FALLBACK = {
584
536
  border: "#6B6B63"
585
537
  };
586
538
  var MAX_SAT = 0.28;
539
+
540
+ // src/core/format.ts
541
+ function charColumns(c) {
542
+ const code = c.codePointAt(0) ?? 0;
543
+ if (code < 32) return 0;
544
+ if (code < 127) return 1;
545
+ if (code < 160) return 0;
546
+ if (code >= 4352 && code <= 4447 || // Hangul Jamo
547
+ code >= 11904 && code <= 42191 || // CJK Radicals … Yi
548
+ code >= 44032 && code <= 55203 || // Hangul
549
+ code >= 63744 && code <= 64255 || // CJK Compat
550
+ code >= 65040 && code <= 65135 || // Vertical / Compat
551
+ code >= 65281 && code <= 65376 || // Fullwidth
552
+ code >= 65504 && code <= 65510 || // Fullwidth signs
553
+ code >= 127744 && code <= 128591 || // Misc Symbols (emoji)
554
+ code >= 131072 && code <= 262141)
555
+ return 2;
556
+ return 1;
557
+ }
558
+ function visualWidth(s) {
559
+ let w = 0;
560
+ for (const c of s) w += charColumns(c);
561
+ return w;
562
+ }
563
+ function visualPadEnd(s, cols) {
564
+ const pad = cols - visualWidth(s);
565
+ return pad > 0 ? s + " ".repeat(pad) : s;
566
+ }
567
+ function truncateVisual(s, maxCols) {
568
+ if (visualWidth(s) <= maxCols) return s;
569
+ let result = "", w = 0;
570
+ for (const c of s) {
571
+ const cw = charColumns(c);
572
+ if (w + cw > maxCols - 1) {
573
+ result += "\u2026";
574
+ break;
575
+ }
576
+ result += c;
577
+ w += cw;
578
+ }
579
+ return result;
580
+ }
587
581
  function progressBar(percent, width) {
588
582
  const clamped = Math.max(0, Math.min(100, percent));
589
583
  const filled = Math.round(clamped / 100 * width);
@@ -604,50 +598,6 @@ function fmtCost(n, symbol = "$", rate = 1) {
604
598
  if (v >= 0.01) return symbol + v.toFixed(3);
605
599
  return symbol + v.toFixed(4);
606
600
  }
607
- function estimateTokens(text) {
608
- if (!text || text.length === 0) return 0;
609
- let ascii = 0;
610
- let cjk = 0;
611
- for (const c of text) {
612
- const code = c.codePointAt(0) ?? 0;
613
- if (code >= 19968 && code <= 40959) cjk++;
614
- else if (code >= 12352 && code <= 12543) cjk++;
615
- else if (code >= 44032 && code <= 55203) cjk++;
616
- else if (code >= 4352 && code <= 4607) cjk++;
617
- else if (code >= 11904 && code <= 12031) cjk++;
618
- else ascii++;
619
- }
620
- const trimmed = text.trimStart();
621
- const strippedFence = trimmed.replace(/^\x60{3}\w*\s*\n?/, "");
622
- const jsonLike = (strippedFence.startsWith("{") || strippedFence.startsWith("[")) && /"[^"]+"\s*:/.test(text);
623
- const codeLike = !jsonLike && /```|^import |^export |^function |^const |^let |^var |^class |^interface |^type |^def |^fn |^pub |^use |^mod |^package /m.test(text);
624
- const asciiPerToken = jsonLike ? 3.5 : codeLike ? 3.5 : 4;
625
- return Math.max(1, Math.ceil(ascii / asciiPerToken + cjk / 1));
626
- }
627
- var BALANCE_POLL_MS = 5 * 60 * 1e3;
628
- function convertBalance(target, targetRate, amount, from) {
629
- if (from === target) return amount;
630
- const fromRate = DEFAULT_RATES[from] ?? 1;
631
- const usd = from === "USD" ? amount : amount / fromRate;
632
- return target === "USD" ? usd : usd * targetRate;
633
- }
634
- function findOpencodeKey(api, provider) {
635
- try {
636
- const provs = api.state.provider;
637
- const id = provider.id.toLowerCase();
638
- const hit = provs.find((p) => p.id.toLowerCase() === id) ?? provs.find((p) => p.id.toLowerCase().startsWith(id));
639
- if (!hit) return "";
640
- const k = typeof hit.key === "string" ? hit.key : "";
641
- if (k) return k;
642
- return typeof hit.options?.apiKey === "string" ? hit.options.apiKey : "";
643
- } catch {
644
- return "";
645
- }
646
- }
647
- function balanceSymbol(currency) {
648
- const sym = CURRENCIES[currency];
649
- return sym ?? currency + " ";
650
- }
651
601
  function fmtCompact(n) {
652
602
  if (n >= 1e6) return (n / 1e6).toFixed(1) + "M";
653
603
  if (n >= 1e3) return (n / 1e3).toFixed(1) + "K";
@@ -656,25 +606,11 @@ function fmtCompact(n) {
656
606
  function formatBalanceAmount(total) {
657
607
  const n = parseFloat(total);
658
608
  if (!Number.isFinite(n)) return total;
659
- if (n === 0 || n >= 1) return n.toLocaleString("en-US", {
660
- minimumFractionDigits: 2,
661
- maximumFractionDigits: 2
662
- });
663
- return n.toLocaleString("en-US", {
664
- maximumFractionDigits: 6
665
- });
666
- }
667
- function formatBalanceText(list, pref, rate) {
668
- const native = pref ? list.find((x) => x.currency === pref) : void 0;
669
- if (native) return balanceSymbol(native.currency) + formatBalanceAmount(native.total);
670
- const base = list[0];
671
- const baseAmt = parseFloat(base.total);
672
- const converted = Number.isFinite(baseAmt) ? convertBalance(pref || base.currency, rate, baseAmt, base.currency) : baseAmt;
673
- const shown = pref && base.currency !== pref ? converted.toLocaleString("en-US", {
674
- maximumFractionDigits: 2
675
- }) : formatBalanceAmount(base.total);
676
- return balanceSymbol(pref || base.currency) + shown;
609
+ if (n === 0 || n >= 1) return n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
610
+ return n.toLocaleString("en-US", { maximumFractionDigits: 6 });
677
611
  }
612
+
613
+ // src/core/currency.ts
678
614
  var CURRENCIES = {
679
615
  USD: "$",
680
616
  CNY: "\xA5",
@@ -691,6 +627,66 @@ var DEFAULT_RATES = {
691
627
  GBP: 0.79,
692
628
  KRW: 1350
693
629
  };
630
+ function convertBalance(target, targetRate, amount, from) {
631
+ if (from === target) return amount;
632
+ const fromRate = DEFAULT_RATES[from] ?? 1;
633
+ const usd = from === "USD" ? amount : amount / fromRate;
634
+ return target === "USD" ? usd : usd * targetRate;
635
+ }
636
+ function balanceSymbol(currency) {
637
+ const sym = CURRENCIES[currency];
638
+ return sym ?? currency + " ";
639
+ }
640
+ function formatBalanceText(list, pref, rate) {
641
+ const native = pref ? list.find((x) => x.currency === pref) : void 0;
642
+ if (native) return balanceSymbol(native.currency) + formatBalanceAmount(native.total);
643
+ const base = list[0];
644
+ const baseAmt = parseFloat(base.total);
645
+ const converted = Number.isFinite(baseAmt) ? convertBalance(pref || base.currency, rate, baseAmt, base.currency) : baseAmt;
646
+ const shown = pref && base.currency !== pref ? converted.toLocaleString("en-US", { maximumFractionDigits: 2 }) : formatBalanceAmount(base.total);
647
+ return balanceSymbol(pref || base.currency) + shown;
648
+ }
649
+
650
+ // src/core/estimate.ts
651
+ function estimateTokens(text) {
652
+ if (!text || text.length === 0) return 0;
653
+ let ascii = 0;
654
+ let cjk = 0;
655
+ for (const c of text) {
656
+ const code = c.codePointAt(0) ?? 0;
657
+ if (code >= 19968 && code <= 40959) cjk++;
658
+ else if (code >= 12352 && code <= 12543) cjk++;
659
+ else if (code >= 44032 && code <= 55203) cjk++;
660
+ else if (code >= 4352 && code <= 4607) cjk++;
661
+ else if (code >= 11904 && code <= 12031) cjk++;
662
+ else ascii++;
663
+ }
664
+ const trimmed = text.trimStart();
665
+ const strippedFence = trimmed.replace(/^\x60{3}\w*\s*\n?/, "");
666
+ const jsonLike = (strippedFence.startsWith("{") || strippedFence.startsWith("[")) && /"[^"]+"\s*:/.test(text);
667
+ const codeLike = !jsonLike && /```|^import |^export |^function |^const |^let |^var |^class |^interface |^type |^def |^fn |^pub |^use |^mod |^package /m.test(text);
668
+ const asciiPerToken = jsonLike ? 3.5 : codeLike ? 3.5 : 4;
669
+ return Math.max(1, Math.ceil(ascii / asciiPerToken + cjk / 1));
670
+ }
671
+
672
+ // src/panel/TokenCachePanel.tsx
673
+ import { createComponent as _$createComponent } from "@opentui/solid";
674
+ import { effect as _$effect } from "@opentui/solid";
675
+ import { createTextNode as _$createTextNode } from "@opentui/solid";
676
+ import { insertNode as _$insertNode } from "@opentui/solid";
677
+ import { insert as _$insert } from "@opentui/solid";
678
+ import { setProp as _$setProp } from "@opentui/solid";
679
+ import { use as _$use } from "@opentui/solid";
680
+ import { spread as _$spread } from "@opentui/solid";
681
+ import { mergeProps as _$mergeProps } from "@opentui/solid";
682
+ import { memo as _$memo } from "@opentui/solid";
683
+ import { createElement as _$createElement } from "@opentui/solid";
684
+ import { createMemo, createSignal, createEffect, onMount, onCleanup, Show, untrack } from "solid-js";
685
+
686
+ // src/_version.ts
687
+ var PLUGIN_VERSION = "1.7.0-beta.0";
688
+
689
+ // src/panel/TokenCachePanel.tsx
694
690
  var MIN_PANEL_WIDTH = 20;
695
691
  var DEFAULT_PANEL_WIDTH = 26;
696
692
  var LABEL_GAP = 1;
@@ -707,6 +703,10 @@ function TokenCachePanel(props) {
707
703
  const [distOpen, setDistOpen] = createSignal(false);
708
704
  const [skillsOpen, setSkillsOpen] = createSignal(true);
709
705
  let boxEl;
706
+ createEffect(() => {
707
+ props.signals.setSidebarVisible(true);
708
+ onCleanup(() => props.signals.setSidebarVisible(false));
709
+ });
710
710
  const {
711
711
  currencySymbol,
712
712
  setCurrencySymbol,
@@ -1988,11 +1988,43 @@ function TokenCachePanel(props) {
1988
1988
  return _el$;
1989
1989
  })();
1990
1990
  }
1991
+
1992
+ // src/index.tsx
1993
+ var DEBUG_LANG = typeof process !== "undefined" ? process.env?.CACHE_TUI_LANG : void 0;
1994
+ var INIT_LANG = DEBUG_LANG !== void 0 && LANG_META.some((m) => m.code === DEBUG_LANG) ? DEBUG_LANG : detectLang();
1995
+ var BALANCE_POLL_MS = 5 * 60 * 1e3;
1996
+ function findOpencodeKey(api, provider) {
1997
+ try {
1998
+ const provs = api.state.provider;
1999
+ const id = provider.id.toLowerCase();
2000
+ const hit = provs.find((p) => p.id.toLowerCase() === id) ?? provs.find((p) => p.id.toLowerCase().startsWith(id));
2001
+ if (!hit) return "";
2002
+ const k = typeof hit.key === "string" ? hit.key : "";
2003
+ if (k) return k;
2004
+ return typeof hit.options?.apiKey === "string" ? hit.options.apiKey : "";
2005
+ } catch {
2006
+ return "";
2007
+ }
2008
+ }
2009
+ var PATH_CHROME = 2;
2010
+ var HIDE_PATH_BELOW = 14;
2011
+ function keyShortcut(api, command, fallback) {
2012
+ try {
2013
+ const binds = api.tuiConfig.keybinds.get(command);
2014
+ const seq = binds?.map((b) => ({
2015
+ key: b.key
2016
+ }));
2017
+ const s = api.keys.formatBindings(seq);
2018
+ return s || fallback;
2019
+ } catch {
2020
+ return fallback;
2021
+ }
2022
+ }
1991
2023
  function BottomStatusBar(props) {
1992
2024
  const KV_PREFIX = "cache_panel";
1993
2025
  const t = createT(() => props.signals.langCode());
1994
2026
  const sid = props.sessionId;
1995
- const stats = createMemo(() => {
2027
+ const stats = createMemo2(() => {
1996
2028
  const id = sid;
1997
2029
  if (!id) return null;
1998
2030
  const msgs = props.api.state.session.messages(id);
@@ -2035,7 +2067,7 @@ function BottomStatusBar(props) {
2035
2067
  write
2036
2068
  };
2037
2069
  });
2038
- createEffect(() => {
2070
+ createEffect2(() => {
2039
2071
  if (!props.signals.autoBalance()) return;
2040
2072
  const id = sid;
2041
2073
  if (!id) return;
@@ -2066,7 +2098,7 @@ function BottomStatusBar(props) {
2066
2098
  props.signals.setBalanceUnsupported(true);
2067
2099
  }
2068
2100
  });
2069
- const pal = createMemo(() => {
2101
+ const pal = createMemo2(() => {
2070
2102
  const th = props.api.theme.current;
2071
2103
  const sat = (k, fb) => desaturateTo(th[k], MAX_SAT, fb);
2072
2104
  return {
@@ -2077,141 +2109,191 @@ function BottomStatusBar(props) {
2077
2109
  error: sat("error", FALLBACK.error)
2078
2110
  };
2079
2111
  });
2080
- const hitColor = createMemo(() => {
2112
+ const hitColor = createMemo2(() => {
2081
2113
  const r = stats()?.hitRate ?? -1;
2082
2114
  if (r >= 85) return pal().success;
2083
2115
  if (r >= 70) return pal().warning;
2084
2116
  return pal().error;
2085
2117
  });
2086
- const trend = createMemo(() => {
2118
+ const trend = createMemo2(() => {
2087
2119
  const s = stats();
2088
2120
  if (!s || s.prevHitRate < 0 || s.hitRate < 0) return null;
2089
2121
  const d = s.hitRate - s.prevHitRate;
2090
2122
  return Math.abs(d) < 0.05 ? null : d;
2091
2123
  });
2092
- const balanceText = createMemo(() => {
2124
+ const balanceText = createMemo2(() => {
2093
2125
  const s = props.signals.balanceState();
2094
2126
  if (s.status === "ok" && s.data) return formatBalanceText(s.data, props.signals.balanceCurrency(), props.signals.exchangeRate());
2095
2127
  if (s.status === "loading") return "\u2026";
2096
2128
  if (s.status === "error") return "\u26A0";
2097
2129
  return "-";
2098
2130
  });
2099
- const directory = createMemo(() => {
2131
+ const directory = createMemo2(() => {
2100
2132
  try {
2101
2133
  return props.api.state.path.directory;
2102
2134
  } catch {
2103
2135
  return "";
2104
2136
  }
2105
2137
  });
2106
- onMount(() => {
2138
+ const [termW, setTermW] = createSignal2(props.api.renderer.terminalWidth);
2139
+ createEffect2(() => {
2140
+ const r = props.api.renderer;
2141
+ if (typeof r.on !== "function" || typeof r.off !== "function") return;
2142
+ const onResize = () => setTermW(props.api.renderer.terminalWidth);
2143
+ r.on("resize", onResize);
2144
+ onCleanup2(() => r.off("resize", onResize));
2145
+ });
2146
+ createEffect2(() => {
2147
+ const timer = setInterval(() => setTermW(props.api.renderer.terminalWidth), 500);
2148
+ onCleanup2(() => clearInterval(timer));
2149
+ });
2150
+ const statsSegs = createMemo2(() => {
2151
+ const s = stats();
2152
+ const hr = s && s.hitRate >= 0 ? (Math.floor(s.hitRate * 10) / 10).toFixed(1) + "%" : "--";
2153
+ const segs = [{
2154
+ text: t("barHit") + " ",
2155
+ color: pal().muted
2156
+ }, {
2157
+ text: hr,
2158
+ color: hitColor()
2159
+ }];
2160
+ const tr = trend();
2161
+ if (tr !== null) {
2162
+ segs.push({
2163
+ text: " " + (tr > 0 ? "\u2191" : "\u2193") + Math.abs(tr).toFixed(1) + "%",
2164
+ color: tr > 0 ? pal().success : pal().error
2165
+ });
2166
+ }
2167
+ segs.push({
2168
+ text: " \xB7 " + t("barTok") + " ",
2169
+ color: pal().muted
2170
+ });
2171
+ segs.push({
2172
+ text: s ? fmtCompact(s.input + s.read + s.write) : "--",
2173
+ color: pal().text
2174
+ });
2175
+ if (!props.signals.balanceUnsupported()) {
2176
+ segs.push({
2177
+ text: " \xB7 " + t("barBal") + " ",
2178
+ color: pal().muted
2179
+ });
2180
+ segs.push({
2181
+ text: balanceText(),
2182
+ color: pal().text
2183
+ });
2184
+ }
2185
+ segs.push({
2186
+ text: " \xB7 ",
2187
+ color: pal().muted
2188
+ });
2189
+ return segs;
2190
+ });
2191
+ const statsW = createMemo2(() => {
2192
+ let w = 0;
2193
+ for (const sg of statsSegs()) w += visualWidth(sg.text);
2194
+ return w;
2195
+ });
2196
+ const sessionCost = createMemo2(() => {
2197
+ try {
2198
+ return num(props.api.state.session.get(sid)?.cost);
2199
+ } catch {
2200
+ return 0;
2201
+ }
2202
+ });
2203
+ const usageText = createMemo2(() => {
2204
+ const id = sid;
2205
+ if (!id) return "";
2206
+ const msgs = props.api.state.session.messages(id);
2207
+ let last;
2208
+ for (let i = msgs.length - 1; i >= 0; i--) {
2209
+ const m = msgs[i];
2210
+ if (m.role !== "assistant") continue;
2211
+ const tk2 = m.tokens;
2212
+ if (tk2 && num(tk2.output) > 0) {
2213
+ last = m;
2214
+ break;
2215
+ }
2216
+ }
2217
+ if (!last) return "";
2218
+ const tk = last.tokens;
2219
+ if (!tk) return "";
2220
+ const tokens = num(tk.input) + num(tk.output) + num(tk.reasoning) + num(tk.cache?.read) + num(tk.cache?.write);
2221
+ if (tokens <= 0) return "";
2222
+ let pct = "";
2223
+ try {
2224
+ const p = props.api.state.provider.find((x) => x.id === last.providerID);
2225
+ const limit = p?.models?.[last.modelID]?.limit?.context;
2226
+ if (typeof limit === "number" && limit > 0) pct = ` (${Math.round(tokens / limit * 100)}%)`;
2227
+ } catch {
2228
+ }
2229
+ const context = fmtCompact(tokens) + pct;
2230
+ const cost = sessionCost();
2231
+ return cost > 0 ? context + " \xB7 " + fmtCost(cost) : context;
2232
+ });
2233
+ const rightText = createMemo2(() => {
2234
+ const cmds = keyShortcut(props.api, "command.palette.show", "ctrl+p") + " commands";
2235
+ const u = usageText();
2236
+ if (u) return u + " " + cmds;
2237
+ return keyShortcut(props.api, "agent.cycle", "") + " agents " + cmds;
2238
+ });
2239
+ const rightW = createMemo2(() => visualWidth(rightText()));
2240
+ const inputW = createMemo2(() => termW() - (props.signals.sidebarVisible() ? 42 : 0) - 4);
2241
+ const dirDisplay = createMemo2(() => {
2242
+ const avail = inputW() - statsW() - rightW() - PATH_CHROME;
2243
+ if (avail < HIDE_PATH_BELOW) return "";
2244
+ return truncateVisual(directory(), avail);
2245
+ });
2246
+ const dirFallback = createMemo2(() => {
2247
+ const avail = inputW() - rightW() - PATH_CHROME;
2248
+ if (avail < HIDE_PATH_BELOW) return "";
2249
+ return truncateVisual(directory(), avail);
2250
+ });
2251
+ onMount2(() => {
2107
2252
  try {
2108
2253
  const v = props.api.kv.get(`${KV_PREFIX}.section.bottom`, true);
2109
2254
  props.signals.setSectionBottom(v !== false);
2110
2255
  } catch {
2111
2256
  }
2112
2257
  });
2113
- return _$createComponent(Show, {
2258
+ return _$createComponent2(Show2, {
2114
2259
  get when() {
2115
2260
  return props.signals.sectionBottom();
2116
2261
  },
2117
2262
  get fallback() {
2118
2263
  return (() => {
2119
- var _el$111 = _$createElement("text");
2120
- _$insert(_el$111, directory);
2121
- _$effect((_$p) => _$setProp(_el$111, "fg", pal().muted, _$p));
2122
- return _el$111;
2264
+ var _el$5 = _$createElement2("text");
2265
+ _$insert2(_el$5, dirFallback);
2266
+ _$effect2((_$p) => _$setProp2(_el$5, "fg", pal().muted, _$p));
2267
+ return _el$5;
2123
2268
  })();
2124
2269
  },
2125
2270
  get children() {
2126
- var _el$97 = _$createElement("box"), _el$98 = _$createElement("text"), _el$99 = _$createElement("box"), _el$100 = _$createElement("text"), _el$101 = _$createElement("span"), _el$102 = _$createTextNode(` `), _el$103 = _$createElement("span"), _el$105 = _$createElement("span"), _el$106 = _$createElement("span"), _el$109 = _$createElement("text");
2127
- _$insertNode(_el$97, _el$98);
2128
- _$insertNode(_el$97, _el$99);
2129
- _$setProp(_el$97, "marginLeft", 1);
2130
- _$setProp(_el$97, "flexGrow", 1);
2131
- _$setProp(_el$97, "flexShrink", 0);
2132
- _$setProp(_el$97, "flexDirection", "row");
2133
- _$setProp(_el$97, "justifyContent", "space-between");
2134
- _$insert(_el$98, directory);
2135
- _$insertNode(_el$99, _el$100);
2136
- _$insertNode(_el$99, _el$109);
2137
- _$setProp(_el$99, "flexDirection", "row");
2138
- _$insertNode(_el$100, _el$101);
2139
- _$insertNode(_el$100, _el$103);
2140
- _$insertNode(_el$100, _el$105);
2141
- _$insertNode(_el$100, _el$106);
2142
- _$insertNode(_el$101, _el$102);
2143
- _$insert(_el$101, () => t("barHit"), _el$102);
2144
- _$insert(_el$103, (() => {
2145
- var _c$ = _$memo(() => (stats()?.hitRate ?? -1) >= 0);
2146
- return () => _c$() ? (Math.floor(stats().hitRate * 10) / 10).toFixed(1) + "%" : "--";
2147
- })());
2148
- _$insert(_el$100, _$createComponent(Show, {
2149
- get when() {
2150
- return trend() !== null;
2271
+ var _el$ = _$createElement2("box"), _el$2 = _$createElement2("text"), _el$3 = _$createElement2("box"), _el$4 = _$createElement2("text");
2272
+ _$insertNode2(_el$, _el$2);
2273
+ _$insertNode2(_el$, _el$3);
2274
+ _$setProp2(_el$, "marginLeft", 1);
2275
+ _$setProp2(_el$, "flexGrow", 1);
2276
+ _$setProp2(_el$, "flexShrink", 0);
2277
+ _$setProp2(_el$, "flexDirection", "row");
2278
+ _$setProp2(_el$, "justifyContent", "space-between");
2279
+ _$insert2(_el$2, dirDisplay);
2280
+ _$insertNode2(_el$3, _el$4);
2281
+ _$setProp2(_el$3, "flexDirection", "row");
2282
+ _$insert2(_el$4, _$createComponent2(For, {
2283
+ get each() {
2284
+ return statsSegs();
2151
2285
  },
2152
- get children() {
2153
- var _el$104 = _$createElement("span");
2154
- _$insert(_el$104, () => " " + (trend() > 0 ? "\u2191" : "\u2193") + Math.abs(trend()).toFixed(1) + "%");
2155
- _$effect((_$p) => _$setProp(_el$104, "style", {
2156
- fg: trend() > 0 ? pal().success : pal().error
2286
+ children: (sg) => (() => {
2287
+ var _el$6 = _$createElement2("span");
2288
+ _$insert2(_el$6, () => sg.text);
2289
+ _$effect2((_$p) => _$setProp2(_el$6, "style", {
2290
+ fg: sg.color
2157
2291
  }, _$p));
2158
- return _el$104;
2159
- }
2160
- }), _el$105);
2161
- _$insert(_el$105, () => " \xB7 " + t("barTok") + " ");
2162
- _$insert(_el$106, (() => {
2163
- var _c$2 = _$memo(() => !!stats());
2164
- return () => _c$2() ? fmtCompact(stats().input + stats().read + stats().write) : "--";
2165
- })());
2166
- _$insert(_el$100, _$createComponent(Show, {
2167
- get when() {
2168
- return !props.signals.balanceUnsupported();
2169
- },
2170
- get children() {
2171
- return [(() => {
2172
- var _el$107 = _$createElement("span");
2173
- _$insert(_el$107, () => " \xB7 " + t("barBal") + " ");
2174
- _$effect((_$p) => _$setProp(_el$107, "style", {
2175
- fg: pal().muted
2176
- }, _$p));
2177
- return _el$107;
2178
- })(), (() => {
2179
- var _el$108 = _$createElement("span");
2180
- _$insert(_el$108, balanceText);
2181
- _$effect((_$p) => _$setProp(_el$108, "style", {
2182
- fg: pal().text
2183
- }, _$p));
2184
- return _el$108;
2185
- })()];
2186
- }
2187
- }), null);
2188
- _$insertNode(_el$109, _$createTextNode(` \xB7 `));
2189
- _$effect((_p$) => {
2190
- var _v$31 = pal().muted, _v$32 = {
2191
- fg: pal().muted
2192
- }, _v$33 = {
2193
- fg: hitColor()
2194
- }, _v$34 = {
2195
- fg: pal().muted
2196
- }, _v$35 = {
2197
- fg: pal().text
2198
- }, _v$36 = pal().muted;
2199
- _v$31 !== _p$.e && (_p$.e = _$setProp(_el$98, "fg", _v$31, _p$.e));
2200
- _v$32 !== _p$.t && (_p$.t = _$setProp(_el$101, "style", _v$32, _p$.t));
2201
- _v$33 !== _p$.a && (_p$.a = _$setProp(_el$103, "style", _v$33, _p$.a));
2202
- _v$34 !== _p$.o && (_p$.o = _$setProp(_el$105, "style", _v$34, _p$.o));
2203
- _v$35 !== _p$.i && (_p$.i = _$setProp(_el$106, "style", _v$35, _p$.i));
2204
- _v$36 !== _p$.n && (_p$.n = _$setProp(_el$109, "fg", _v$36, _p$.n));
2205
- return _p$;
2206
- }, {
2207
- e: void 0,
2208
- t: void 0,
2209
- a: void 0,
2210
- o: void 0,
2211
- i: void 0,
2212
- n: void 0
2213
- });
2214
- return _el$97;
2292
+ return _el$6;
2293
+ })()
2294
+ }));
2295
+ _$effect2((_$p) => _$setProp2(_el$2, "fg", pal().muted, _$p));
2296
+ return _el$;
2215
2297
  }
2216
2298
  });
2217
2299
  }
@@ -2228,7 +2310,7 @@ function createSidebarSlot(api, signals) {
2228
2310
  api.kv.set("cache_panel.session", "");
2229
2311
  }
2230
2312
  }
2231
- return _$createComponent(TokenCachePanel, {
2313
+ return _$createComponent2(TokenCachePanel, {
2232
2314
  get theme() {
2233
2315
  return ctx.theme.current;
2234
2316
  },
@@ -2243,23 +2325,24 @@ function createSidebarSlot(api, signals) {
2243
2325
  };
2244
2326
  }
2245
2327
  var tui = async (api) => {
2246
- const [currencySymbol, setCurrencySymbol] = createSignal("$");
2247
- const [exchangeRate, setExchangeRate] = createSignal(1);
2248
- const [sectionDetail, setSectionDetail] = createSignal(true);
2249
- const [sectionModel, setSectionModel] = createSignal(true);
2250
- const [sectionDist, setSectionDist] = createSignal(true);
2251
- const [sectionSkills, setSectionSkills] = createSignal(true);
2252
- const [sectionBalance, setSectionBalance] = createSignal(true);
2253
- const [sectionBottom, setSectionBottom] = createSignal(true);
2254
- const [balanceRefresh, setBalanceRefresh] = createSignal(0);
2255
- const [balanceProviderId, setBalanceProviderId] = createSignal("deepseek");
2256
- const [autoBalance, setAutoBalance] = createSignal(true);
2257
- const [balanceUnsupported, setBalanceUnsupported] = createSignal(false);
2258
- const [balanceCurrency, setBalanceCurrency] = createSignal("");
2259
- const [borderVisible, setBorderVisible] = createSignal(true);
2260
- const [langCode, setLangCode] = createSignal(INIT_LANG);
2261
- const [overrideSessionId, setOverrideSessionId] = createSignal(void 0);
2262
- const [balanceState, setBalanceState] = createSignal({
2328
+ const [currencySymbol, setCurrencySymbol] = createSignal2("$");
2329
+ const [exchangeRate, setExchangeRate] = createSignal2(1);
2330
+ const [sectionDetail, setSectionDetail] = createSignal2(true);
2331
+ const [sectionModel, setSectionModel] = createSignal2(true);
2332
+ const [sectionDist, setSectionDist] = createSignal2(true);
2333
+ const [sectionSkills, setSectionSkills] = createSignal2(true);
2334
+ const [sectionBalance, setSectionBalance] = createSignal2(true);
2335
+ const [sectionBottom, setSectionBottom] = createSignal2(true);
2336
+ const [balanceRefresh, setBalanceRefresh] = createSignal2(0);
2337
+ const [balanceProviderId, setBalanceProviderId] = createSignal2("deepseek");
2338
+ const [autoBalance, setAutoBalance] = createSignal2(true);
2339
+ const [balanceUnsupported, setBalanceUnsupported] = createSignal2(false);
2340
+ const [balanceCurrency, setBalanceCurrency] = createSignal2("");
2341
+ const [borderVisible, setBorderVisible] = createSignal2(true);
2342
+ const [langCode, setLangCode] = createSignal2(INIT_LANG);
2343
+ const [overrideSessionId, setOverrideSessionId] = createSignal2(void 0);
2344
+ const [sidebarVisible, setSidebarVisible] = createSignal2(false);
2345
+ const [balanceState, setBalanceState] = createSignal2({
2263
2346
  status: "idle",
2264
2347
  data: null,
2265
2348
  lastFetch: 0
@@ -2298,14 +2381,16 @@ var tui = async (api) => {
2298
2381
  borderVisible,
2299
2382
  setBorderVisible,
2300
2383
  overrideSessionId,
2301
- setOverrideSessionId
2384
+ setOverrideSessionId,
2385
+ sidebarVisible,
2386
+ setSidebarVisible
2302
2387
  };
2303
2388
  api.slots.register(createSidebarSlot(api, signals));
2304
2389
  api.slots.register({
2305
2390
  order: 55,
2306
2391
  slots: {
2307
2392
  session_prompt(_ctx, input) {
2308
- return _$createComponent(api.ui.Prompt, {
2393
+ return _$createComponent2(api.ui.Prompt, {
2309
2394
  get sessionID() {
2310
2395
  return input.session_id;
2311
2396
  },
@@ -2319,11 +2404,11 @@ var tui = async (api) => {
2319
2404
  return input.on_submit;
2320
2405
  },
2321
2406
  ref(r$) {
2322
- var _ref$2 = input.ref;
2323
- typeof _ref$2 === "function" ? _ref$2(r$) : input.ref = r$;
2407
+ var _ref$ = input.ref;
2408
+ typeof _ref$ === "function" ? _ref$(r$) : input.ref = r$;
2324
2409
  },
2325
2410
  get hint() {
2326
- return _$createComponent(BottomStatusBar, {
2411
+ return _$createComponent2(BottomStatusBar, {
2327
2412
  api,
2328
2413
  signals,
2329
2414
  get sessionId() {
@@ -2417,9 +2502,9 @@ var tui = async (api) => {
2417
2502
  });
2418
2503
  }
2419
2504
  };
2420
- createEffect(() => {
2505
+ createEffect2(() => {
2421
2506
  void balanceRefresh();
2422
- untrack(() => {
2507
+ untrack2(() => {
2423
2508
  void pollBalance();
2424
2509
  });
2425
2510
  });
@@ -2436,16 +2521,16 @@ var tui = async (api) => {
2436
2521
  const t = createT(() => langCode());
2437
2522
  const current = api.kv.get(`${KV_PREFIX}.balance.${provider.id}.key`, "");
2438
2523
  const masked = maskKey(current);
2439
- dialog?.replace(() => _$createComponent(api.ui.DialogPrompt, {
2524
+ dialog?.replace(() => _$createComponent2(api.ui.DialogPrompt, {
2440
2525
  get title() {
2441
2526
  return provider.name;
2442
2527
  },
2443
2528
  description: () => (() => {
2444
- var _el$112 = _$createElement("text");
2445
- _$insert(_el$112, () => t("balKeyPrompt", {
2529
+ var _el$7 = _$createElement2("text");
2530
+ _$insert2(_el$7, () => t("balKeyPrompt", {
2446
2531
  p: provider.name
2447
2532
  }));
2448
- return _el$112;
2533
+ return _el$7;
2449
2534
  })(),
2450
2535
  get placeholder() {
2451
2536
  return provider.keyPlaceholder ?? "sk-...";
@@ -2485,7 +2570,7 @@ var tui = async (api) => {
2485
2570
  name: "cache-currency"
2486
2571
  },
2487
2572
  onSelect: (dialog) => {
2488
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2573
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2489
2574
  title: "Select Currency",
2490
2575
  get options() {
2491
2576
  return Object.entries(CURRENCIES).map(([code, sym]) => ({
@@ -2522,12 +2607,12 @@ var tui = async (api) => {
2522
2607
  name: "cache-rate"
2523
2608
  },
2524
2609
  onSelect: (dialog) => {
2525
- dialog?.replace(() => _$createComponent(api.ui.DialogPrompt, {
2610
+ dialog?.replace(() => _$createComponent2(api.ui.DialogPrompt, {
2526
2611
  title: "Exchange Rate",
2527
2612
  description: () => (() => {
2528
- var _el$113 = _$createElement("text");
2529
- _$insertNode(_el$113, _$createTextNode(`Enter the exchange rate from USD to your currency (e.g. 7.2 for CNY)`));
2530
- return _el$113;
2613
+ var _el$8 = _$createElement2("text");
2614
+ _$insertNode2(_el$8, _$createTextNode2(`Enter the exchange rate from USD to your currency (e.g. 7.2 for CNY)`));
2615
+ return _el$8;
2531
2616
  })(),
2532
2617
  placeholder: "1.0",
2533
2618
  get value() {
@@ -2575,7 +2660,7 @@ var tui = async (api) => {
2575
2660
  border: t("secBorder")
2576
2661
  };
2577
2662
  const optTitle = (label, on) => `${visualPadEnd(label, 15)}[${on ? "ON" : "OFF"}]`;
2578
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2663
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2579
2664
  get title() {
2580
2665
  return t("secToggle");
2581
2666
  },
@@ -2676,7 +2761,7 @@ var tui = async (api) => {
2676
2761
  onSelect: (dialog) => {
2677
2762
  const t = createT(() => langCode());
2678
2763
  const cur = langCode();
2679
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2764
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2680
2765
  get title() {
2681
2766
  return t("langTitle");
2682
2767
  },
@@ -2709,7 +2794,7 @@ var tui = async (api) => {
2709
2794
  const current = signals.balanceProviderId();
2710
2795
  const auto = signals.autoBalance();
2711
2796
  const autoLabel = `${t("autoSwitchOpt")} [${auto ? "ON" : "OFF"}]`;
2712
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2797
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2713
2798
  get title() {
2714
2799
  return t("balProvTitle");
2715
2800
  },
@@ -2763,7 +2848,7 @@ var tui = async (api) => {
2763
2848
  },
2764
2849
  onSelect: (dialog) => {
2765
2850
  const t = createT(() => langCode());
2766
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2851
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2767
2852
  get title() {
2768
2853
  return t("balSelectTitle");
2769
2854
  },
@@ -2905,7 +2990,7 @@ var tui = async (api) => {
2905
2990
  description: ""
2906
2991
  });
2907
2992
  const currentIdx = currentSid ? options.findIndex((o) => o.value === currentSid) : -1;
2908
- dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2993
+ dialog?.replace(() => _$createComponent2(api.ui.DialogSelect, {
2909
2994
  get title() {
2910
2995
  return t("subSelectTitle");
2911
2996
  },
@@ -2934,14 +3019,14 @@ var tui = async (api) => {
2934
3019
  }));
2935
3020
  } else {
2936
3021
  const t = createT(() => langCode());
2937
- dialog?.replace(() => _$createComponent(api.ui.DialogPrompt, {
3022
+ dialog?.replace(() => _$createComponent2(api.ui.DialogPrompt, {
2938
3023
  get title() {
2939
- return _$memo(() => !!signals.overrideSessionId())() ? t("subSwitchTitle") : t("subViewTitle");
3024
+ return _$memo2(() => !!signals.overrideSessionId())() ? t("subSwitchTitle") : t("subViewTitle");
2940
3025
  },
2941
3026
  description: () => (() => {
2942
- var _el$115 = _$createElement("text");
2943
- _$insert(_el$115, () => t("subNoFound"));
2944
- return _el$115;
3027
+ var _el$0 = _$createElement2("text");
3028
+ _$insert2(_el$0, () => t("subNoFound"));
3029
+ return _el$0;
2945
3030
  })(),
2946
3031
  placeholder: "ses_...",
2947
3032
  get value() {