opencode-visual-cache 1.6.2 → 1.7.0-beta.1

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 +12 -818
  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 +223 -209
  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 +72 -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 -2120
  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
@@ -0,0 +1,17 @@
1
+ import type { BalanceEntry } from "../balance-providers";
2
+ export declare const CURRENCIES: Record<string, string>;
3
+ /** Approximate USD exchange rates — used as defaults when switching currency.
4
+ * Users can override via /cache-rate. Last updated 2026-05. */
5
+ export declare const DEFAULT_RATES: Record<string, number>;
6
+ /**
7
+ * 将余额从来源币种换算为目标币种。
8
+ * DEFAULT_RATES 以 USD=1 为基准:先折算为 USD,再换算到目标币种。
9
+ */
10
+ export declare function convertBalance(target: string, targetRate: number, amount: number, from: string): number;
11
+ /** 货币符号:优先取 /cache-currency 内置映射,未知币种回退为代码。 */
12
+ export declare function balanceSymbol(currency: string): string;
13
+ /**
14
+ * 将余额列表格式化为单行文本。
15
+ * 优先直接显示偏好币种(CNY/USD…);偏好币种为换算币种时按汇率折算第一条余额。
16
+ */
17
+ export declare function formatBalanceText(list: BalanceEntry[], pref: string, rate: number): string;
@@ -0,0 +1,43 @@
1
+ import { formatBalanceAmount } from "./format";
2
+ export const CURRENCIES = {
3
+ USD: "$", CNY: "¥", EUR: "€", JPY: "JP¥", GBP: "£", KRW: "₩",
4
+ };
5
+ /** Approximate USD exchange rates — used as defaults when switching currency.
6
+ * Users can override via /cache-rate. Last updated 2026-05. */
7
+ export const DEFAULT_RATES = {
8
+ USD: 1, CNY: 7.2, EUR: 0.92, JPY: 150, GBP: 0.79, KRW: 1350,
9
+ };
10
+ /**
11
+ * 将余额从来源币种换算为目标币种。
12
+ * DEFAULT_RATES 以 USD=1 为基准:先折算为 USD,再换算到目标币种。
13
+ */
14
+ export function convertBalance(target, targetRate, amount, from) {
15
+ if (from === target)
16
+ return amount;
17
+ const fromRate = DEFAULT_RATES[from] ?? 1;
18
+ const usd = from === "USD" ? amount : amount / fromRate;
19
+ return target === "USD" ? usd : usd * targetRate;
20
+ }
21
+ /** 货币符号:优先取 /cache-currency 内置映射,未知币种回退为代码。 */
22
+ export function balanceSymbol(currency) {
23
+ const sym = CURRENCIES[currency];
24
+ return sym ?? currency + " ";
25
+ }
26
+ /**
27
+ * 将余额列表格式化为单行文本。
28
+ * 优先直接显示偏好币种(CNY/USD…);偏好币种为换算币种时按汇率折算第一条余额。
29
+ */
30
+ export function formatBalanceText(list, pref, rate) {
31
+ const native = pref ? list.find((x) => x.currency === pref) : undefined;
32
+ if (native)
33
+ return balanceSymbol(native.currency) + formatBalanceAmount(native.total);
34
+ const base = list[0];
35
+ const baseAmt = parseFloat(base.total);
36
+ const converted = Number.isFinite(baseAmt)
37
+ ? convertBalance(pref || base.currency, rate, baseAmt, base.currency)
38
+ : baseAmt;
39
+ const shown = pref && base.currency !== pref
40
+ ? converted.toLocaleString("en-US", { maximumFractionDigits: 2 })
41
+ : formatBalanceAmount(base.total);
42
+ return balanceSymbol(pref || base.currency) + shown;
43
+ }
@@ -0,0 +1 @@
1
+ export declare function estimateTokens(text: string): number;
@@ -0,0 +1,40 @@
1
+ // ── token estimation ──
2
+ // Character-based BPE approximation. Default ratios (~4 ASCII or ~1.5 CJK
3
+ // chars per token) work well for natural language but systematically
4
+ // under-count tokens in JSON and source code where every punctuation mark
5
+ // tends to be its own token. Detect these cases and tighten the ratio.
6
+ // See: GPT-4 / Claude tokenizer behaviour with structured text.
7
+ export function estimateTokens(text) {
8
+ if (!text || text.length === 0)
9
+ return 0;
10
+ let ascii = 0;
11
+ let cjk = 0;
12
+ for (const c of text) {
13
+ const code = c.codePointAt(0) ?? 0;
14
+ if (code >= 0x4E00 && code <= 0x9FFF)
15
+ cjk++; // CJK Unified
16
+ else if (code >= 0x3040 && code <= 0x30FF)
17
+ cjk++; // Hiragana/Katakana
18
+ else if (code >= 0xAC00 && code <= 0xD7A3)
19
+ cjk++; // Hangul
20
+ else if (code >= 0x1100 && code <= 0x11FF)
21
+ cjk++; // Hangul Jamo
22
+ else if (code >= 0x2E80 && code <= 0x2EFF)
23
+ cjk++; // CJK Radicals
24
+ else
25
+ ascii++;
26
+ }
27
+ // Real BPE tokenizers (cl100k_base, o200k_base) average ~3.5-4.0
28
+ // ASCII chars/token for both JSON and source code — close to prose.
29
+ // The old 2.0 / 2.5 ratios matched minified-JS extremes, not typical
30
+ // payloads, and systematically over-estimated token counts.
31
+ const trimmed = text.trimStart();
32
+ // Strip markdown code-fence prefix so that ```json … is detected as JSON
33
+ const strippedFence = trimmed.replace(/^\x60{3}\w*\s*\n?/, "");
34
+ const jsonLike = (strippedFence.startsWith("{") || strippedFence.startsWith("["))
35
+ && /"[^"]+"\s*:/.test(text);
36
+ const codeLike = !jsonLike
37
+ && /```|^import |^export |^function |^const |^let |^var |^class |^interface |^type |^def |^fn |^pub |^use |^mod |^package /m.test(text);
38
+ const asciiPerToken = jsonLike ? 3.5 : codeLike ? 3.5 : 4;
39
+ return Math.max(1, Math.ceil(ascii / asciiPerToken + cjk / 1.0));
40
+ }
@@ -0,0 +1,15 @@
1
+ /** CJK characters occupy 2 terminal columns; padEnd/padStart count
2
+ * string length (=1 per char), which breaks alignment with mixed text. */
3
+ export declare function charColumns(c: string): number;
4
+ export declare function visualWidth(s: string): number;
5
+ export declare function visualPadEnd(s: string, cols: number): string;
6
+ /** Truncate `s` to fit within `maxCols` visual columns, appending "…" when cut. */
7
+ export declare function truncateVisual(s: string, maxCols: number): string;
8
+ export declare function progressBar(percent: number, width: number): string;
9
+ export declare function fmt(n: number): string;
10
+ export declare function num(v: unknown): number;
11
+ export declare function fmtCost(n: number, symbol?: string, rate?: number): string;
12
+ /** 紧凑数字缩写(底部状态栏用):1234 → "1.2K",1234567 → "1.2M"。 */
13
+ export declare function fmtCompact(n: number): string;
14
+ /** 余额数值格式化:≥1 或 0 显示固定 2 位小数;小额(<1)保留精度(最多 6 位),避免抹成 0.00。 */
15
+ export declare function formatBalanceAmount(total: string): string;
@@ -0,0 +1,90 @@
1
+ /** CJK characters occupy 2 terminal columns; padEnd/padStart count
2
+ * string length (=1 per char), which breaks alignment with mixed text. */
3
+ export function charColumns(c) {
4
+ const code = c.codePointAt(0) ?? 0;
5
+ if (code < 0x20)
6
+ return 0; // control
7
+ if (code < 0x7F)
8
+ return 1; // ASCII
9
+ if (code < 0xA0)
10
+ return 0; // C1 controls
11
+ // East-Asian wide / fullwidth ranges
12
+ if ((code >= 0x1100 && code <= 0x115F) || // Hangul Jamo
13
+ (code >= 0x2E80 && code <= 0xA4CF) || // CJK Radicals … Yi
14
+ (code >= 0xAC00 && code <= 0xD7A3) || // Hangul
15
+ (code >= 0xF900 && code <= 0xFAFF) || // CJK Compat
16
+ (code >= 0xFE10 && code <= 0xFE6F) || // Vertical / Compat
17
+ (code >= 0xFF01 && code <= 0xFF60) || // Fullwidth
18
+ (code >= 0xFFE0 && code <= 0xFFE6) || // Fullwidth signs
19
+ (code >= 0x1F300 && code <= 0x1F64F) || // Misc Symbols (emoji)
20
+ (code >= 0x20000 && code <= 0x3FFFD)) // SIP / TIP
21
+ return 2;
22
+ return 1;
23
+ }
24
+ export function visualWidth(s) {
25
+ let w = 0;
26
+ for (const c of s)
27
+ w += charColumns(c);
28
+ return w;
29
+ }
30
+ export function visualPadEnd(s, cols) {
31
+ const pad = cols - visualWidth(s);
32
+ return pad > 0 ? s + " ".repeat(pad) : s;
33
+ }
34
+ /** Truncate `s` to fit within `maxCols` visual columns, appending "…" when cut. */
35
+ export function truncateVisual(s, maxCols) {
36
+ if (visualWidth(s) <= maxCols)
37
+ return s;
38
+ let result = "", w = 0;
39
+ for (const c of s) {
40
+ const cw = charColumns(c);
41
+ if (w + cw > maxCols - 1) {
42
+ result += "\u2026";
43
+ break;
44
+ }
45
+ result += c;
46
+ w += cw;
47
+ }
48
+ return result;
49
+ }
50
+ export function progressBar(percent, width) {
51
+ const clamped = Math.max(0, Math.min(100, percent));
52
+ const filled = Math.round((clamped / 100) * width);
53
+ const empty = Math.max(0, width - filled);
54
+ return "\u2588".repeat(filled) + "\u2591".repeat(empty);
55
+ }
56
+ export function fmt(n) {
57
+ if (n >= 1_000_000)
58
+ return (n / 1_000_000).toFixed(1) + "M";
59
+ if (n >= 10_000)
60
+ return (n / 1_000).toFixed(1) + "K";
61
+ return n.toLocaleString("en-US");
62
+ }
63
+ export function num(v) {
64
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
65
+ }
66
+ export function fmtCost(n, symbol = "$", rate = 1) {
67
+ const v = n * rate;
68
+ if (v >= 1)
69
+ return symbol + v.toFixed(2);
70
+ if (v >= 0.01)
71
+ return symbol + v.toFixed(3);
72
+ return symbol + v.toFixed(4);
73
+ }
74
+ /** 紧凑数字缩写(底部状态栏用):1234 → "1.2K",1234567 → "1.2M"。 */
75
+ export function fmtCompact(n) {
76
+ if (n >= 1e6)
77
+ return (n / 1e6).toFixed(1) + "M";
78
+ if (n >= 1e3)
79
+ return (n / 1e3).toFixed(1) + "K";
80
+ return String(Math.round(n));
81
+ }
82
+ /** 余额数值格式化:≥1 或 0 显示固定 2 位小数;小额(<1)保留精度(最多 6 位),避免抹成 0.00。 */
83
+ export function formatBalanceAmount(total) {
84
+ const n = parseFloat(total);
85
+ if (!Number.isFinite(n))
86
+ return total;
87
+ if (n === 0 || n >= 1)
88
+ return n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
89
+ return n.toLocaleString("en-US", { maximumFractionDigits: 6 });
90
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./color";
2
+ export * from "./currency";
3
+ export * from "./estimate";
4
+ export * from "./format";
5
+ export * from "./types";
@@ -0,0 +1,5 @@
1
+ export * from "./color";
2
+ export * from "./currency";
3
+ export * from "./estimate";
4
+ export * from "./format";
5
+ export * from "./types";
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Token distribution breakdown for a session round.
3
+ * Pure data model shared by V1/V2 shells.
4
+ */
5
+ export interface TokenDist {
6
+ system: number;
7
+ user: number;
8
+ agent: number;
9
+ toolCall: number;
10
+ toolResult: number;
11
+ output: number;
12
+ reasoning: number;
13
+ apiOutput: number;
14
+ apiInput: number;
15
+ stepCost: number;
16
+ stepCount: number;
17
+ }
@@ -0,0 +1 @@
1
+ export {};