opencode-visual-cache 1.5.0 → 1.6.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.
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, untrack } from "solid-js";
14
14
 
15
15
  // src/_version.ts
16
- var PLUGIN_VERSION = "1.5.0";
16
+ var PLUGIN_VERSION = "1.6.1";
17
17
 
18
18
  // src/balance-providers.ts
19
19
  var BalanceError = class extends Error {
@@ -117,51 +117,7 @@ function maskKey(k) {
117
117
  return k.slice(0, 5) + "*".repeat(Math.max(3, k.length - 10)) + k.slice(-5);
118
118
  }
119
119
 
120
- // src/index.tsx
121
- function charColumns(c) {
122
- const code = c.codePointAt(0) ?? 0;
123
- if (code < 32) return 0;
124
- if (code < 127) return 1;
125
- if (code < 160) return 0;
126
- if (code >= 4352 && code <= 4447 || // Hangul Jamo
127
- code >= 11904 && code <= 42191 || // CJK Radicals … Yi
128
- code >= 44032 && code <= 55203 || // Hangul
129
- code >= 63744 && code <= 64255 || // CJK Compat
130
- code >= 65040 && code <= 65135 || // Vertical / Compat
131
- code >= 65281 && code <= 65376 || // Fullwidth
132
- code >= 65504 && code <= 65510 || // Fullwidth signs
133
- code >= 127744 && code <= 128591 || // Misc Symbols (emoji)
134
- code >= 131072 && code <= 262141)
135
- return 2;
136
- return 1;
137
- }
138
- function visualWidth(s) {
139
- let w = 0;
140
- for (const c of s) w += charColumns(c);
141
- return w;
142
- }
143
- function truncateVisual(s, maxCols) {
144
- if (visualWidth(s) <= maxCols) return s;
145
- let result = "", w = 0;
146
- for (const c of s) {
147
- const cw = charColumns(c);
148
- if (w + cw > maxCols - 1) {
149
- result += "\u2026";
150
- break;
151
- }
152
- result += c;
153
- w += cw;
154
- }
155
- return result;
156
- }
157
- var DEBUG_LANG = typeof process !== "undefined" ? process.env?.CACHE_TUI_LANG : void 0;
158
- var LANG_ZH = DEBUG_LANG ? DEBUG_LANG === "zh" : (() => {
159
- try {
160
- return Intl.DateTimeFormat().resolvedOptions().locale.startsWith("zh");
161
- } catch {
162
- return false;
163
- }
164
- })();
120
+ // src/i18n.ts
165
121
  var ZH_T = {
166
122
  title: "\u7F13\u5B58\u7EDF\u8BA1",
167
123
  hit: "\u547D\u4E2D\u7387",
@@ -184,11 +140,11 @@ var ZH_T = {
184
140
  distTitle: "\u4F30\u7B97 Token \u5206\u5E03",
185
141
  distSys: "\u7CFB\u7EDF\u63D0\u793A:",
186
142
  distUser: "\u7528\u6237:",
187
- distAgent: "Agent \u6307\u4EE4:",
143
+ distAgent: "\u5B50\u4EE3\u7406\u6307\u4EE4:",
188
144
  distTool: "Tool \u8C03\u7528:",
189
145
  distRes: "Tool \u7ED3\u679C:",
190
- distTotal: "\u603B\u8BA1:",
191
- distOut: "\u8F93\u51FA:",
146
+ distReason: "\u63A8\u7406:",
147
+ stepsCount: "\u672C\u56DE\u5408 {n} \u6B21\u8C03\u7528:",
192
148
  secDetail: "\u660E\u7EC6",
193
149
  secModel: "\u6A21\u578B",
194
150
  secSkills: "\u5DF2\u52A0\u8F7D\u6280\u80FD",
@@ -199,7 +155,49 @@ var ZH_T = {
199
155
  balErr401: "API Key \u65E0\u6548",
200
156
  balErr403: "\u4F59\u989D\u67E5\u8BE2\u88AB\u62D2\u7EDD",
201
157
  balErrEmpty: "\u672A\u83B7\u53D6\u5230\u4F59\u989D\u6570\u636E",
202
- balErrTimeout: "\u67E5\u8BE2\u8D85\u65F6"
158
+ balErrTimeout: "\u67E5\u8BE2\u8D85\u65F6",
159
+ balUnsupported: "\u5F53\u524D\u63D0\u4F9B\u5546\u4E0D\u652F\u6301\u4F59\u989D\u67E5\u8BE2",
160
+ barHit: "\u547D\u4E2D\u7387",
161
+ barBal: "\u4F59\u989D",
162
+ barTok: "Tokens",
163
+ // ── /cache-section 面板 ──
164
+ secToggle: "\u5207\u6362\u533A\u5757",
165
+ secBalance: "\u4F59\u989D",
166
+ secBottom: "\u5E95\u90E8\u72B6\u6001\u680F",
167
+ secBorder: "\u9762\u677F\u8FB9\u6846",
168
+ // ── toast ──
169
+ keySaved: "API Key \u5DF2\u4FDD\u5B58\uFF0C\u6B63\u5728\u67E5\u8BE2\u4F59\u989D...",
170
+ keyCleared: "API Key \u5DF2\u6E05\u9664",
171
+ currencySet: "\u5E01\u79CD: {v} ({s}), \u6C47\u7387: {r}",
172
+ rateSet: "\u6C47\u7387\u5DF2\u8BBE\u4E3A {r}",
173
+ panelConfigTitle: "\u7F13\u5B58\u9762\u677F\u914D\u7F6E",
174
+ panelConfigMsg: "\u5E01\u79CD: {c} | \u6C47\u7387: {r} | \u660E\u7EC6: {d} | \u6A21\u578B: {m} | \u5206\u5E03: {t} | \u6280\u80FD: {k} | \u4F59\u989D: {b} | \u5E95\u90E8: {f}",
175
+ borderShown: "\u9762\u677F\u8FB9\u6846 \u5DF2\u663E\u793A",
176
+ borderHidden: "\u9762\u677F\u8FB9\u6846 \u5DF2\u9690\u85CF",
177
+ sectionShown: "{s} \u5DF2\u663E\u793A",
178
+ sectionHidden: "{s} \u5DF2\u9690\u85CF",
179
+ langSwitched: "\u8BED\u8A00\u5DF2\u5207\u6362\u4E3A\u4E2D\u6587",
180
+ autoSwitchOn: "\u81EA\u52A8\u5207\u6362\u4F59\u989D\u63D0\u4F9B\u5546: \u5F00",
181
+ autoSwitchOff: "\u81EA\u52A8\u5207\u6362\u4F59\u989D\u63D0\u4F9B\u5546: \u5173",
182
+ providerManual: "\u4F59\u989D\u63D0\u4F9B\u5546: {p}\uFF08\u81EA\u52A8\u5207\u6362\u5DF2\u5173\u95ED\uFF09",
183
+ runInSession: "\u8BF7\u5728\u4F1A\u8BDD\u5185\u8FD0\u884C\u6B64\u547D\u4EE4",
184
+ backToMain: "\u5DF2\u5207\u56DE\u4E3B\u4F1A\u8BDD",
185
+ subAgentSwitched: "\u5DF2\u5207\u6362\u81F3\u5B50\u4EE3\u7406: {s}",
186
+ // ── 对话框 / 菜单 ──
187
+ langTitle: "\u663E\u793A\u8BED\u8A00",
188
+ subPrefix: "\u5B50\u4EE3\u7406: ",
189
+ keyUser: "\uFF08\u7528\u6237 key\uFF09",
190
+ keyOpenCode: "\uFF08OpenCode\uFF09",
191
+ keyNotSet: "\uFF08\u672A\u914D\u7F6E\uFF09",
192
+ balKeyPrompt: "\u8F93\u5165 {p} API Key \u4EE5\u663E\u793A\u8D26\u6237\u4F59\u989D\uFF08\u7559\u7A7A\u6E05\u9664\uFF09",
193
+ balProvTitle: "\u4F59\u989D\u63D0\u4F9B\u5546 / \u81EA\u52A8\u5207\u6362",
194
+ autoSwitchOpt: "\u81EA\u52A8\u5207\u6362\u63D0\u4F9B\u5546",
195
+ balSelectTitle: "\u9009\u62E9\u4F59\u989D\u63D0\u4F9B\u5546",
196
+ backToMainTitle: "\u56DE\u5230\u4E3B\u4F1A\u8BDD",
197
+ subSelectTitle: "\u9009\u62E9\u5B50\u4EE3\u7406",
198
+ subSwitchTitle: "\u5207\u6362\u5B50\u4EE3\u7406",
199
+ subViewTitle: "\u67E5\u770B\u5B50\u4EE3\u7406\u7F13\u5B58",
200
+ subNoFound: "\u672A\u627E\u5230\u5B50\u4EE3\u7406\uFF0C\u8BF7\u624B\u52A8\u7C98\u8D34 Session ID"
203
201
  };
204
202
  var EN_T = {
205
203
  title: "Token Cache",
@@ -223,11 +221,11 @@ var EN_T = {
223
221
  distTitle: "Estimated Token Dist.",
224
222
  distSys: "System:",
225
223
  distUser: "User:",
226
- distAgent: "Agent Instr:",
224
+ distAgent: "Sub-Agent Instr:",
227
225
  distTool: "Tool Call:",
228
226
  distRes: "Tool Result:",
229
- distTotal: "Total:",
230
- distOut: "Output:",
227
+ distReason: "Reasoning:",
228
+ stepsCount: "Turn #{n} calls:",
231
229
  secDetail: "Detail",
232
230
  secModel: "Model",
233
231
  secSkills: "Loaded Skills",
@@ -238,8 +236,284 @@ var EN_T = {
238
236
  balErr401: "Invalid API Key",
239
237
  balErr403: "Balance request rejected",
240
238
  balErrEmpty: "No balance data",
241
- balErrTimeout: "Request timed out"
239
+ balErrTimeout: "Request timed out",
240
+ balUnsupported: "Balance query unsupported",
241
+ barHit: "Hit",
242
+ barBal: "Balance",
243
+ barTok: "Tokens",
244
+ // ── /cache-section panel ──
245
+ secToggle: "Toggle Section",
246
+ secBalance: "Balance",
247
+ secBottom: "Bottom Bar",
248
+ secBorder: "Panel Border",
249
+ // ── toasts ──
250
+ keySaved: "API Key saved, fetching balance...",
251
+ keyCleared: "API Key cleared",
252
+ currencySet: "Currency: {v} ({s}), rate: {r}",
253
+ rateSet: "Exchange rate set to {r}",
254
+ panelConfigTitle: "Cache Panel Config",
255
+ panelConfigMsg: "Currency: {c} | Rate: {r} | Detail: {d} | Model: {m} | Dist: {t} | Skills: {k} | Balance: {b} | Bottom: {f}",
256
+ borderShown: "Panel border shown",
257
+ borderHidden: "Panel border hidden",
258
+ sectionShown: "{s} section shown",
259
+ sectionHidden: "{s} section hidden",
260
+ langSwitched: "Switched to English",
261
+ autoSwitchOn: "Auto-switch balance provider: ON",
262
+ autoSwitchOff: "Auto-switch balance provider: OFF",
263
+ providerManual: "Balance provider: {p} (auto-switch off)",
264
+ runInSession: "Please run this command inside a session",
265
+ backToMain: "Switched to main session",
266
+ subAgentSwitched: "Showing sub-agent: {s}",
267
+ // ── dialogs / menus ──
268
+ langTitle: "Display Language",
269
+ subPrefix: "Sub: ",
270
+ keyUser: " (user key)",
271
+ keyOpenCode: " (OpenCode)",
272
+ keyNotSet: " (not set)",
273
+ balKeyPrompt: "Enter your {p} API key to show account balance (leave empty to clear)",
274
+ balProvTitle: "Balance Provider / Auto-switch",
275
+ autoSwitchOpt: "Auto-switch provider",
276
+ balSelectTitle: "Select Balance Provider",
277
+ backToMainTitle: "Back to Main",
278
+ subSelectTitle: "Select Sub-Agent",
279
+ subSwitchTitle: "Switch Sub",
280
+ subViewTitle: "View Sub Cache",
281
+ subNoFound: "No sub-agents found. Paste a Session ID manually"
282
+ };
283
+ var JA_T = {
284
+ title: "\u30AD\u30E3\u30C3\u30B7\u30E5\u7D71\u8A08",
285
+ hit: "\u30D2\u30C3\u30C8\u7387",
286
+ totalHit: "\u7DCF\u30D2\u30C3\u30C8:",
287
+ read: "\u30AD\u30E3\u30C3\u30B7\u30E5\u8AAD\u8FBC:",
288
+ write: "\u30AD\u30E3\u30C3\u30B7\u30E5\u66F8\u8FBC:",
289
+ miss: "\u672A\u30D2\u30C3\u30C8:",
290
+ out: "\u51FA\u529B:",
291
+ cost: "\u8CBB\u7528:",
292
+ saved: "\u7D2F\u8A08\u7BC0\u7D04:",
293
+ model: "\u30E2\u30C7\u30EB:",
294
+ provider: "\u30D7\u30ED\u30D0\u30A4\u30C0:",
295
+ rate: "\u5358\u4FA1:",
296
+ hitFolded: "\u30D2\u30C3\u30C8",
297
+ inputRate: "\u5165\u529B",
298
+ cacheRate: "\u30AD\u30E3\u30C3\u30B7\u30E5",
299
+ writeRate: "\u66F8\u8FBC",
300
+ noData: "\u30AD\u30E3\u30C3\u30B7\u30E5\u30C7\u30FC\u30BF\u5F85\u6A5F\u4E2D...",
301
+ tok: "tok",
302
+ distTitle: "Token \u5206\u5E03\uFF08\u63A8\u5B9A\uFF09",
303
+ distSys: "\u30B7\u30B9\u30C6\u30E0:",
304
+ distUser: "\u30E6\u30FC\u30B6\u30FC:",
305
+ distAgent: "\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u6307\u793A:",
306
+ distTool: "Tool \u547C\u3073\u51FA\u3057:",
307
+ distRes: "Tool \u7D50\u679C:",
308
+ distReason: "\u63A8\u8AD6:",
309
+ stepsCount: "\u4ECA\u56DE {n} \u56DE\u547C\u51FA:",
310
+ secDetail: "\u660E\u7D30",
311
+ secModel: "\u30E2\u30C7\u30EB",
312
+ secSkills: "\u8AAD\u307F\u8FBC\u307F\u6E08\u307F\u30B9\u30AD\u30EB",
313
+ balTotal: "\u7DCF\u6B8B\u9AD8:",
314
+ balNoKey: "{p} \u306E API Key \u672A\u8A2D\u5B9A",
315
+ balLoading: "\u53D6\u5F97\u4E2D...",
316
+ balError: "\u53D6\u5F97\u5931\u6557",
317
+ balErr401: "API Key \u7121\u52B9",
318
+ balErr403: "\u6B8B\u9AD8\u7167\u4F1A\u304C\u62D2\u5426\u3055\u308C\u307E\u3057\u305F",
319
+ balErrEmpty: "\u6B8B\u9AD8\u30C7\u30FC\u30BF\u306A\u3057",
320
+ balErrTimeout: "\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8",
321
+ balUnsupported: "\u3053\u306E\u30D7\u30ED\u30D0\u30A4\u30C0\u306F\u6B8B\u9AD8\u7167\u4F1A\u975E\u5BFE\u5FDC",
322
+ barHit: "\u30D2\u30C3\u30C8\u7387",
323
+ barBal: "\u6B8B\u9AD8",
324
+ barTok: "Tokens",
325
+ // ── /cache-section パネル ──
326
+ secToggle: "\u30BB\u30AF\u30B7\u30E7\u30F3\u5207\u66FF",
327
+ secBalance: "\u6B8B\u9AD8",
328
+ secBottom: "\u4E0B\u90E8\u30B9\u30C6\u30FC\u30BF\u30B9\u30D0\u30FC",
329
+ secBorder: "\u30D1\u30CD\u30EB\u67A0\u7DDA",
330
+ // ── toast ──
331
+ keySaved: "API Key \u4FDD\u5B58\u6E08\u307F\u3001\u6B8B\u9AD8\u3092\u53D6\u5F97\u4E2D...",
332
+ keyCleared: "API Key \u3092\u30AF\u30EA\u30A2\u3057\u307E\u3057\u305F",
333
+ currencySet: "\u901A\u8CA8: {v} ({s}), \u30EC\u30FC\u30C8: {r}",
334
+ rateSet: "\u30EC\u30FC\u30C8\u3092 {r} \u306B\u8A2D\u5B9A\u3057\u307E\u3057\u305F",
335
+ panelConfigTitle: "\u30D1\u30CD\u30EB\u8A2D\u5B9A",
336
+ panelConfigMsg: "\u901A\u8CA8: {c} | \u30EC\u30FC\u30C8: {r} | \u660E\u7D30: {d} | \u30E2\u30C7\u30EB: {m} | \u5206\u5E03: {t} | \u30B9\u30AD\u30EB: {k} | \u6B8B\u9AD8: {b} | \u4E0B\u90E8: {f}",
337
+ borderShown: "\u30D1\u30CD\u30EB\u67A0\u7DDA \u8868\u793A",
338
+ borderHidden: "\u30D1\u30CD\u30EB\u67A0\u7DDA \u975E\u8868\u793A",
339
+ sectionShown: "{s} \u8868\u793A",
340
+ sectionHidden: "{s} \u975E\u8868\u793A",
341
+ langSwitched: "\u65E5\u672C\u8A9E\u306B\u5207\u308A\u66FF\u3048\u307E\u3057\u305F",
342
+ autoSwitchOn: "\u6B8B\u9AD8\u30D7\u30ED\u30D0\u30A4\u30C0\u81EA\u52D5\u5207\u66FF: \u30AA\u30F3",
343
+ autoSwitchOff: "\u6B8B\u9AD8\u30D7\u30ED\u30D0\u30A4\u30C0\u81EA\u52D5\u5207\u66FF: \u30AA\u30D5",
344
+ providerManual: "\u6B8B\u9AD8\u30D7\u30ED\u30D0\u30A4\u30C0: {p}\uFF08\u81EA\u52D5\u5207\u66FF\u30AA\u30D5\uFF09",
345
+ runInSession: "\u30BB\u30C3\u30B7\u30E7\u30F3\u5185\u3067\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044",
346
+ backToMain: "\u30E1\u30A4\u30F3\u30BB\u30C3\u30B7\u30E7\u30F3\u306B\u623B\u308A\u307E\u3057\u305F",
347
+ subAgentSwitched: "\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u3078\u5207\u66FF: {s}",
348
+ // ── ダイアログ / メニュー ──
349
+ langTitle: "\u8868\u793A\u8A00\u8A9E",
350
+ subPrefix: "\u30B5\u30D6: ",
351
+ keyUser: "\uFF08\u30E6\u30FC\u30B6\u30FC key\uFF09",
352
+ keyOpenCode: "\uFF08OpenCode\uFF09",
353
+ keyNotSet: "\uFF08\u672A\u8A2D\u5B9A\uFF09",
354
+ balKeyPrompt: "{p} \u306E API Key \u3092\u5165\u529B\u3057\u3066\u6B8B\u9AD8\u3092\u8868\u793A\uFF08\u7A7A\u6B04\u3067\u30AF\u30EA\u30A2\uFF09",
355
+ balProvTitle: "\u6B8B\u9AD8\u30D7\u30ED\u30D0\u30A4\u30C0 / \u81EA\u52D5\u5207\u66FF",
356
+ autoSwitchOpt: "\u81EA\u52D5\u5207\u66FF\u30D7\u30ED\u30D0\u30A4\u30C0",
357
+ balSelectTitle: "\u6B8B\u9AD8\u30D7\u30ED\u30D0\u30A4\u30C0\u9078\u629E",
358
+ backToMainTitle: "\u30E1\u30A4\u30F3\u306B\u623B\u308B",
359
+ subSelectTitle: "\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u9078\u629E",
360
+ subSwitchTitle: "\u30B5\u30D6\u5207\u66FF",
361
+ subViewTitle: "\u30B5\u30D6\u30AD\u30E3\u30C3\u30B7\u30E5\u8868\u793A",
362
+ subNoFound: "\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002Session ID \u3092\u624B\u52D5\u3067\u8CBC\u308A\u4ED8\u3051\u3066\u304F\u3060\u3055\u3044"
363
+ };
364
+ var KO_T = {
365
+ title: "\uCE90\uC2DC \uD1B5\uACC4",
366
+ hit: "\uD788\uD2B8\uC728",
367
+ totalHit: "\uCD1D \uD788\uD2B8:",
368
+ read: "\uCE90\uC2DC \uC77D\uAE30:",
369
+ write: "\uCE90\uC2DC \uC4F0\uAE30:",
370
+ miss: "\uBBF8\uD788\uD2B8:",
371
+ out: "\uCD9C\uB825:",
372
+ cost: "\uBE44\uC6A9:",
373
+ saved: "\uB204\uC801 \uC808\uC57D:",
374
+ model: "\uBAA8\uB378:",
375
+ provider: "\uD504\uB85C\uBC14\uC774\uB354:",
376
+ rate: "\uB2E8\uAC00:",
377
+ hitFolded: "\uD788\uD2B8",
378
+ inputRate: "\uC785\uB825",
379
+ cacheRate: "\uCE90\uC2DC",
380
+ writeRate: "\uC4F0\uAE30",
381
+ noData: "\uCE90\uC2DC \uB370\uC774\uD130 \uB300\uAE30 \uC911...",
382
+ tok: "tok",
383
+ distTitle: "Token \uBD84\uD3EC(\uCD94\uC815)",
384
+ distSys: "\uC2DC\uC2A4\uD15C:",
385
+ distUser: "\uC0AC\uC6A9\uC790:",
386
+ distAgent: "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8 \uC9C0\uC2DC:",
387
+ distTool: "Tool \uD638\uCD9C:",
388
+ distRes: "Tool \uACB0\uACFC:",
389
+ distReason: "\uCD94\uB860:",
390
+ stepsCount: "\uC774\uBC88 \uD134 {n}\uD68C \uD638\uCD9C:",
391
+ secDetail: "\uC0C1\uC138",
392
+ secModel: "\uBAA8\uB378",
393
+ secSkills: "\uB85C\uB4DC\uB41C \uC2A4\uD0AC",
394
+ balTotal: "\uCD1D \uC794\uC561:",
395
+ balNoKey: "{p} API Key \uBBF8\uC124\uC815",
396
+ balLoading: "\uC870\uD68C \uC911...",
397
+ balError: "\uC870\uD68C \uC2E4\uD328",
398
+ balErr401: "API Key \uBB34\uD6A8",
399
+ balErr403: "\uC794\uC561 \uC870\uD68C\uAC00 \uAC70\uBD80\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
400
+ balErrEmpty: "\uC794\uC561 \uB370\uC774\uD130 \uC5C6\uC74C",
401
+ balErrTimeout: "\uC2DC\uAC04 \uCD08\uACFC",
402
+ balUnsupported: "\uC774 \uD504\uB85C\uBC14\uC774\uB354\uB294 \uC794\uC561 \uC870\uD68C \uBBF8\uC9C0\uC6D0",
403
+ barHit: "\uD788\uD2B8\uC728",
404
+ barBal: "\uC794\uC561",
405
+ barTok: "Tokens",
406
+ // ── /cache-section 패널 ──
407
+ secToggle: "\uC139\uC158 \uC804\uD658",
408
+ secBalance: "\uC794\uC561",
409
+ secBottom: "\uD558\uB2E8 \uC0C1\uD0DC\uBC14",
410
+ secBorder: "\uD328\uB110 \uD14C\uB450\uB9AC",
411
+ // ── toast ──
412
+ keySaved: "API Key \uC800\uC7A5\uB428, \uC794\uC561 \uC870\uD68C \uC911...",
413
+ keyCleared: "API Key \uC0AD\uC81C\uB428",
414
+ currencySet: "\uD1B5\uD654: {v} ({s}), \uD658\uC728: {r}",
415
+ rateSet: "\uD658\uC728\uC744 {r}(\uC73C)\uB85C \uC124\uC815\uD588\uC2B5\uB2C8\uB2E4",
416
+ panelConfigTitle: "\uD328\uB110 \uC124\uC815",
417
+ panelConfigMsg: "\uD1B5\uD654: {c} | \uD658\uC728: {r} | \uC0C1\uC138: {d} | \uBAA8\uB378: {m} | \uBD84\uD3EC: {t} | \uC2A4\uD0AC: {k} | \uC794\uC561: {b} | \uD558\uB2E8: {f}",
418
+ borderShown: "\uD328\uB110 \uD14C\uB450\uB9AC \uD45C\uC2DC",
419
+ borderHidden: "\uD328\uB110 \uD14C\uB450\uB9AC \uC228\uAE40",
420
+ sectionShown: "{s} \uD45C\uC2DC",
421
+ sectionHidden: "{s} \uC228\uAE40",
422
+ langSwitched: "\uD55C\uAD6D\uC5B4\uB85C \uC804\uD658\uD588\uC2B5\uB2C8\uB2E4",
423
+ autoSwitchOn: "\uC794\uC561 \uD504\uB85C\uBC14\uC774\uB354 \uC790\uB3D9 \uC804\uD658: \uCF1C\uC9D0",
424
+ autoSwitchOff: "\uC794\uC561 \uD504\uB85C\uBC14\uC774\uB354 \uC790\uB3D9 \uC804\uD658: \uAEBC\uC9D0",
425
+ providerManual: "\uC794\uC561 \uD504\uB85C\uBC14\uC774\uB354: {p}(\uC790\uB3D9 \uC804\uD658 \uAEBC\uC9D0)",
426
+ runInSession: "\uC138\uC158 \uB0B4\uC5D0\uC11C \uC2E4\uD589\uD574 \uC8FC\uC138\uC694",
427
+ backToMain: "\uBA54\uC778 \uC138\uC158\uC73C\uB85C \uB3CC\uC544\uAC14\uC2B5\uB2C8\uB2E4",
428
+ subAgentSwitched: "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8\uB85C \uC804\uD658: {s}",
429
+ // ── 다이얼로그 / 메뉴 ──
430
+ langTitle: "\uD45C\uC2DC \uC5B8\uC5B4",
431
+ subPrefix: "\uC11C\uBE0C: ",
432
+ keyUser: "(\uC0AC\uC6A9\uC790 key)",
433
+ keyOpenCode: "(OpenCode)",
434
+ keyNotSet: "(\uBBF8\uC124\uC815)",
435
+ balKeyPrompt: "{p} API Key\uB97C \uC785\uB825\uD558\uC5EC \uC794\uC561 \uD45C\uC2DC(\uBE44\uC6B0\uBA74 \uC0AD\uC81C)",
436
+ balProvTitle: "\uC794\uC561 \uD504\uB85C\uBC14\uC774\uB354 / \uC790\uB3D9 \uC804\uD658",
437
+ autoSwitchOpt: "\uC790\uB3D9 \uC804\uD658 \uD504\uB85C\uBC14\uC774\uB354",
438
+ balSelectTitle: "\uC794\uC561 \uD504\uB85C\uBC14\uC774\uB354 \uC120\uD0DD",
439
+ backToMainTitle: "\uBA54\uC778\uC73C\uB85C \uB3CC\uC544\uAC00\uAE30",
440
+ subSelectTitle: "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8 \uC120\uD0DD",
441
+ subSwitchTitle: "\uC11C\uBE0C \uC804\uD658",
442
+ subViewTitle: "\uC11C\uBE0C \uCE90\uC2DC \uBCF4\uAE30",
443
+ subNoFound: "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. Session ID\uB97C \uC9C1\uC811 \uBD99\uC5EC\uB123\uC73C\uC138\uC694"
242
444
  };
445
+ var LANGS = { zh: ZH_T, en: EN_T, ja: JA_T, ko: KO_T };
446
+ var LANG_META = [
447
+ { code: "zh", label: "\u4E2D\u6587" },
448
+ { code: "en", label: "English" },
449
+ { code: "ja", label: "\u65E5\u672C\u8A9E" },
450
+ { code: "ko", label: "\uD55C\uAD6D\uC5B4" }
451
+ ];
452
+ function applyParams(tpl, params) {
453
+ if (!params) return tpl;
454
+ return tpl.replace(
455
+ /\{(\w+)\}/g,
456
+ (m, k) => k in params ? String(params[k]) : m
457
+ );
458
+ }
459
+ function createT(getCode) {
460
+ return (key, params) => applyParams(LANGS[getCode()][key], params);
461
+ }
462
+ function detectLang() {
463
+ try {
464
+ const loc = Intl.DateTimeFormat().resolvedOptions().locale.toLowerCase();
465
+ if (loc.startsWith("zh")) return "zh";
466
+ if (loc.startsWith("ja")) return "ja";
467
+ if (loc.startsWith("ko")) return "ko";
468
+ return "en";
469
+ } catch {
470
+ return "en";
471
+ }
472
+ }
473
+
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();
243
517
  function rgb(raw) {
244
518
  if (typeof raw === "string" && raw.startsWith("#")) {
245
519
  const h = raw.slice(1);
@@ -374,6 +648,33 @@ function balanceSymbol(currency) {
374
648
  const sym = CURRENCIES[currency];
375
649
  return sym ?? currency + " ";
376
650
  }
651
+ function fmtCompact(n) {
652
+ if (n >= 1e6) return (n / 1e6).toFixed(1) + "M";
653
+ if (n >= 1e3) return (n / 1e3).toFixed(1) + "K";
654
+ return String(Math.round(n));
655
+ }
656
+ function formatBalanceAmount(total) {
657
+ const n = parseFloat(total);
658
+ 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;
677
+ }
377
678
  var CURRENCIES = {
378
679
  USD: "$",
379
680
  CNY: "\xA5",
@@ -411,8 +712,7 @@ function TokenCachePanel(props) {
411
712
  setCurrencySymbol,
412
713
  exchangeRate,
413
714
  setExchangeRate,
414
- langZH,
415
- setLangZH,
715
+ langCode,
416
716
  sectionDetail,
417
717
  setSectionDetail,
418
718
  sectionModel,
@@ -428,12 +728,15 @@ function TokenCachePanel(props) {
428
728
  setBalanceProviderId,
429
729
  autoBalance,
430
730
  setAutoBalance,
731
+ balanceUnsupported,
732
+ setBalanceUnsupported,
733
+ balanceState,
431
734
  balanceCurrency,
432
735
  setBalanceCurrency,
433
736
  borderVisible,
434
737
  setBorderVisible
435
738
  } = props.signals;
436
- const t = createMemo(() => langZH() ? ZH_T : EN_T);
739
+ const t = createT(() => langCode());
437
740
  const [lastDist, setLastDist] = createSignal({
438
741
  system: 0,
439
742
  user: 0,
@@ -441,9 +744,11 @@ function TokenCachePanel(props) {
441
744
  toolCall: 0,
442
745
  toolResult: 0,
443
746
  output: 0,
747
+ reasoning: 0,
444
748
  apiOutput: 0,
445
749
  apiInput: 0,
446
- stepCost: 0
750
+ stepCost: 0,
751
+ stepCount: 0
447
752
  });
448
753
  const [lastHasDist, setLastHasDist] = createSignal(false);
449
754
  const [dataSignal, setDataSignal] = createSignal({
@@ -471,81 +776,18 @@ function TokenCachePanel(props) {
471
776
  toolCall: 0,
472
777
  toolResult: 0,
473
778
  output: 0,
779
+ reasoning: 0,
474
780
  apiOutput: 0,
475
781
  apiInput: 0,
476
- stepCost: 0
782
+ stepCost: 0,
783
+ stepCount: 0
477
784
  },
478
785
  hasDistData: false,
479
786
  skills: [],
480
787
  hasSkills: false
481
788
  });
482
789
  const [refreshTick, setRefreshTick] = createSignal(0);
483
- const [balanceState, setBalanceState] = createSignal({
484
- status: "idle",
485
- data: null,
486
- lastFetch: 0
487
- });
488
- let balanceSeq = 0;
489
790
  const providerName = createMemo(() => getBalanceProvider(balanceProviderId()).name);
490
- const pollBalance = async () => {
491
- const provider = getBalanceProvider(balanceProviderId());
492
- const key = props.api.kv.get(`${KV_PREFIX}.balance.${provider.id}.key`, "") || findOpencodeKey(props.api, provider);
493
- if (!key) {
494
- setBalanceState({
495
- status: "idle",
496
- data: null,
497
- lastFetch: 0,
498
- error: void 0,
499
- key: void 0
500
- });
501
- return;
502
- }
503
- const now = Date.now();
504
- const prev = balanceState();
505
- if (prev.status === "ok" && prev.key === key && now - prev.lastFetch < BALANCE_POLL_MS) return;
506
- const seq = ++balanceSeq;
507
- setBalanceState({
508
- ...prev,
509
- status: "loading",
510
- error: void 0,
511
- key
512
- });
513
- const controller = new AbortController();
514
- let timedOut = false;
515
- const timer = setTimeout(() => {
516
- timedOut = true;
517
- controller.abort();
518
- }, 1e4);
519
- try {
520
- const data2 = await provider.fetchBalance(key, controller.signal);
521
- clearTimeout(timer);
522
- if (seq !== balanceSeq) return;
523
- setBalanceState({
524
- status: "ok",
525
- data: data2,
526
- lastFetch: Date.now(),
527
- error: void 0,
528
- key
529
- });
530
- } catch (err) {
531
- clearTimeout(timer);
532
- if (seq !== balanceSeq) return;
533
- const code = timedOut ? "TIMEOUT" : err instanceof Error ? err.message : "";
534
- setBalanceState({
535
- status: "error",
536
- data: null,
537
- lastFetch: 0,
538
- error: code,
539
- key
540
- });
541
- }
542
- };
543
- createEffect(() => {
544
- void balanceRefresh();
545
- untrack(() => {
546
- void pollBalance();
547
- });
548
- });
549
791
  createEffect(() => {
550
792
  if (!autoBalance()) return;
551
793
  const sid = props.signals.overrideSessionId() ?? props.sessionId;
@@ -567,9 +809,14 @@ function TokenCachePanel(props) {
567
809
  }
568
810
  if (!pid) return;
569
811
  const hit = matchBalanceProvider(pid);
570
- if (hit && hit.id !== balanceProviderId()) {
571
- setBalanceProviderId(hit.id);
572
- props.signals.setBalanceRefresh(props.signals.balanceRefresh() + 1);
812
+ if (hit) {
813
+ setBalanceUnsupported(false);
814
+ if (hit.id !== balanceProviderId()) {
815
+ setBalanceProviderId(hit.id);
816
+ props.signals.setBalanceRefresh(props.signals.balanceRefresh() + 1);
817
+ }
818
+ } else {
819
+ setBalanceUnsupported(true);
573
820
  }
574
821
  });
575
822
  let lastMainSid = props.sessionId;
@@ -602,18 +849,18 @@ function TokenCachePanel(props) {
602
849
  let prevMsgHitRate = -1, lastMsgHitRate = -1;
603
850
  for (const msg of msgs) {
604
851
  if (msg.role !== "assistant") continue;
605
- const t2 = msg.tokens;
606
- if (!t2) continue;
607
- const mit = num(t2.input) + num(t2.cache?.read), mrt = num(t2.cache?.read);
852
+ const tok = msg.tokens;
853
+ if (!tok) continue;
854
+ const mit = num(tok.input) + num(tok.cache?.read) + num(tok.cache?.write), mrt = num(tok.cache?.read);
608
855
  if (mit > 0) {
609
856
  prevMsgHitRate = lastMsgHitRate;
610
857
  lastMsgHitRate = mrt / mit * 100;
611
858
  }
612
859
  if (fallbackTokens) {
613
- input += num(t2.input);
614
- read += num(t2.cache?.read);
615
- write += num(t2.cache?.write);
616
- output += num(t2.output);
860
+ input += num(tok.input);
861
+ read += num(tok.cache?.read);
862
+ write += num(tok.cache?.write);
863
+ output += num(tok.output);
617
864
  }
618
865
  if (fallbackCost) {
619
866
  cost += num(msg.cost);
@@ -635,7 +882,7 @@ function TokenCachePanel(props) {
635
882
  break;
636
883
  }
637
884
  const hitRate = lastMsgHitRate >= 0 ? lastMsgHitRate : 0;
638
- const freshTotal = input + read, sessionHitRate = freshTotal > 0 ? read / freshTotal * 100 : 0;
885
+ const freshTotal = input + read + write, sessionHitRate = freshTotal > 0 ? read / freshTotal * 100 : 0;
639
886
  const model = mid.split("/").pop() ?? mid, hasPricing = inputRate > 0 || cacheReadRate > 0 || cacheWriteRate > 0;
640
887
  const hasTrendData = prevMsgHitRate >= 0 && lastMsgHitRate >= 0;
641
888
  const trend = hasTrendData ? lastMsgHitRate - prevMsgHitRate : 0, providerName2 = pid || "";
@@ -647,9 +894,11 @@ function TokenCachePanel(props) {
647
894
  toolCall: 0,
648
895
  toolResult: 0,
649
896
  output: 0,
897
+ reasoning: 0,
650
898
  apiOutput: 0,
651
899
  apiInput: 0,
652
- stepCost: 0
900
+ stepCost: 0,
901
+ stepCount: 0
653
902
  };
654
903
  let hasDistData = false;
655
904
  const loadedSkills = /* @__PURE__ */ new Map();
@@ -680,6 +929,7 @@ function TokenCachePanel(props) {
680
929
  } else if (msg.role === "assistant") {
681
930
  const am = msg;
682
931
  dist.output += num(am.tokens?.output);
932
+ dist.reasoning += num(am.tokens?.reasoning);
683
933
  let parts = [];
684
934
  try {
685
935
  parts = props.api.state.part(msg.id);
@@ -694,6 +944,12 @@ function TokenCachePanel(props) {
694
944
  } catch {
695
945
  }
696
946
  if (rawInput) dist.toolCall += estimateTokens(rawInput);
947
+ if (tp.tool === "task" && tp.state?.input) {
948
+ const ti = tp.state.input;
949
+ const prompt = typeof ti.prompt === "string" ? ti.prompt : "";
950
+ const desc = typeof ti.description === "string" ? ti.description : "";
951
+ dist.agent += estimateTokens(prompt || desc);
952
+ }
697
953
  if (tp.state.status === "completed") {
698
954
  const c = tp.state;
699
955
  if (c.output) dist.toolResult += estimateTokens(c.output);
@@ -718,8 +974,7 @@ function TokenCachePanel(props) {
718
974
  }
719
975
  }
720
976
  }
721
- } else if (p.type === "reasoning") dist.agent += estimateTokens(p.text);
722
- else if (p.type === "subtask") {
977
+ } else if (p.type === "subtask") {
723
978
  const sub = p;
724
979
  dist.agent += estimateTokens(sub.prompt || sub.description || "");
725
980
  }
@@ -728,15 +983,36 @@ function TokenCachePanel(props) {
728
983
  }
729
984
  for (let i = msgs.length - 1; i >= 0; i--) {
730
985
  if (msgs[i].role !== "assistant") continue;
731
- const t2 = msgs[i].tokens;
732
- if (t2 && (t2.input > 0 || (t2.cache?.read ?? 0) > 0)) {
986
+ const tok = msgs[i].tokens;
987
+ if (tok && ((tok.input ?? 0) > 0 || (tok.cache?.read ?? 0) > 0 || (tok.cache?.write ?? 0) > 0)) {
733
988
  lastAssMsg = msgs[i];
734
989
  break;
735
990
  }
736
991
  }
737
- dist.apiInput = num(lastAssMsg?.tokens?.input) + num(lastAssMsg?.tokens?.cache?.read);
992
+ dist.apiInput = num(lastAssMsg?.tokens?.input) + num(lastAssMsg?.tokens?.cache?.read) + num(lastAssMsg?.tokens?.cache?.write);
738
993
  dist.apiOutput = num(lastAssMsg?.tokens?.output);
739
- hasDistData = dist.system + dist.user + dist.agent + dist.toolCall + dist.toolResult > 0 || dist.apiOutput > 0 || dist.apiInput > 0;
994
+ if (lastAssMsg) {
995
+ const roundParent = lastAssMsg.parentID;
996
+ let lastCost;
997
+ for (let i = msgs.length - 1; i >= 0; i--) {
998
+ const m = msgs[i];
999
+ if (m.role !== "assistant") continue;
1000
+ if (m.parentID !== roundParent) break;
1001
+ let parts = [];
1002
+ try {
1003
+ parts = props.api.state.part(m.id);
1004
+ } catch {
1005
+ }
1006
+ for (const p of parts) {
1007
+ if (p.type !== "step-finish") continue;
1008
+ dist.stepCount++;
1009
+ const sc = p.cost;
1010
+ if (lastCost === void 0 && typeof sc === "number" && Number.isFinite(sc)) lastCost = sc;
1011
+ }
1012
+ }
1013
+ if (lastCost !== void 0) dist.stepCost = lastCost;
1014
+ }
1015
+ hasDistData = dist.system + dist.user + dist.agent + dist.toolCall + dist.toolResult > 0 || dist.apiOutput > 0 || dist.apiInput > 0 || dist.reasoning > 0;
740
1016
  } catch {
741
1017
  }
742
1018
  const finalDist = hasDistData ? dist : lastDist(), finalHasDist = hasDistData || lastHasDist();
@@ -818,6 +1094,7 @@ function TokenCachePanel(props) {
818
1094
  const savedProvider = props.api.kv.get(`${KV_PREFIX}.balance.provider`);
819
1095
  if (typeof savedProvider === "string" && balanceProviders.some((p) => p.id === savedProvider)) {
820
1096
  setBalanceProviderId(savedProvider);
1097
+ setBalanceUnsupported(false);
821
1098
  }
822
1099
  const savedAuto = props.api.kv.get(`${KV_PREFIX}.balance.auto`);
823
1100
  if (typeof savedAuto === "boolean") setAutoBalance(savedAuto);
@@ -835,10 +1112,6 @@ function TokenCachePanel(props) {
835
1112
  setSectionBalance(Boolean(props.api.kv.get(`${KV_PREFIX}.section.balance`, true)));
836
1113
  const bv = props.api.kv.get(`${KV_PREFIX}.border`, true);
837
1114
  setBorderVisible(bv !== false);
838
- const savedLang = props.api.kv.get(`${KV_PREFIX}.lang`);
839
- if (savedLang === "zh" || savedLang === "en") {
840
- setLangZH(savedLang === "zh");
841
- }
842
1115
  const cachedDist = props.api.kv.get(`${KV_PREFIX}.dist_snapshot`);
843
1116
  if (cachedDist) {
844
1117
  setLastDist(cachedDist);
@@ -885,10 +1158,8 @@ function TokenCachePanel(props) {
885
1158
  setRefreshTick((v) => v + 1);
886
1159
  });
887
1160
  setRefreshTick((v) => v + 1);
888
- const balanceTimer = setInterval(pollBalance, BALANCE_POLL_MS);
889
1161
  onCleanup(() => {
890
1162
  clearTimeout(partTimer);
891
- clearInterval(balanceTimer);
892
1163
  unsubPart();
893
1164
  unsubMsg();
894
1165
  unsubSession();
@@ -916,11 +1187,12 @@ function TokenCachePanel(props) {
916
1187
  const gutter = createMemo(() => borderVisible() ? 6 : 0);
917
1188
  const sep = createMemo(() => "\u2500".repeat(Math.max(1, panelWidth() - gutter())));
918
1189
  function trendLabel(t2) {
919
- return (t2 > 0 ? "\u2191" : t2 < 0 ? "\u2193" : "-") + (t2 !== 0 ? Math.abs(t2).toFixed(1) + "%" : "");
1190
+ if (Math.abs(t2) < 0.05) return "-";
1191
+ return (t2 > 0 ? "\u2191" : "\u2193") + Math.abs(t2).toFixed(1) + "%";
920
1192
  }
921
1193
  const barW = createMemo(() => {
922
1194
  const trendSpace = data().hasTrendData ? LABEL_GAP + visualWidth(trendLabel(data().trend)) : 0;
923
- const overhead = visualWidth(t().hit) + LABEL_GAP + BAR_BRACKETS + BAR_GAP + PCT_FIXED_WIDTH + trendSpace + gutter();
1195
+ const overhead = visualWidth(t("hit")) + LABEL_GAP + BAR_BRACKETS + BAR_GAP + PCT_FIXED_WIDTH + trendSpace + gutter();
924
1196
  return Math.max(3, panelWidth() - overhead);
925
1197
  });
926
1198
  const bar = createMemo(() => progressBar(data().hitRate, barW()));
@@ -974,7 +1246,7 @@ function TokenCachePanel(props) {
974
1246
  }));
975
1247
  _$insert(_el$3, () => open() ? "\u25BC " : "\u25B6 ");
976
1248
  _$insertNode(_el$4, _el$5);
977
- _$insert(_el$5, () => t().title);
1249
+ _$insert(_el$5, () => t("title"));
978
1250
  _$insert(_el$4, _$createComponent(Show, {
979
1251
  get when() {
980
1252
  return open();
@@ -1001,13 +1273,13 @@ function TokenCachePanel(props) {
1001
1273
  get children() {
1002
1274
  return [(() => {
1003
1275
  var _el$8 = _$createElement("span");
1004
- _$insert(_el$8, () => " ".repeat(Math.max(1, panelWidth() - gutter() - HEADER_PREFIX - visualWidth(t().title) - visualWidth(pct() + " " + t().hitFolded + " " + trendLabel(data().trend)))));
1276
+ _$insert(_el$8, () => " ".repeat(Math.max(1, panelWidth() - gutter() - HEADER_PREFIX - visualWidth(t("title")) - visualWidth(pct() + " " + t("hitFolded") + " " + trendLabel(data().trend)))));
1005
1277
  return _el$8;
1006
1278
  })(), (() => {
1007
1279
  var _el$9 = _$createElement("span"), _el$0 = _$createTextNode(` `);
1008
1280
  _$insertNode(_el$9, _el$0);
1009
1281
  _$insert(_el$9, pct, _el$0);
1010
- _$insert(_el$9, () => t().hitFolded, null);
1282
+ _$insert(_el$9, () => t("hitFolded"), null);
1011
1283
  _$effect((_$p) => _$setProp(_el$9, "style", {
1012
1284
  fg: hitColor()
1013
1285
  }, _$p));
@@ -1017,7 +1289,7 @@ function TokenCachePanel(props) {
1017
1289
  _$insertNode(_el$1, _el$10);
1018
1290
  _$insert(_el$1, () => trendLabel(data().trend), null);
1019
1291
  _$effect((_$p) => _$setProp(_el$1, "style", {
1020
- fg: data().trend !== 0 ? data().trend > 0 ? pal().success : pal().error : pal().text
1292
+ fg: Math.abs(data().trend) >= 0.05 ? data().trend > 0 ? pal().success : pal().error : pal().text
1021
1293
  }, _$p));
1022
1294
  return _el$1;
1023
1295
  })()];
@@ -1029,13 +1301,13 @@ function TokenCachePanel(props) {
1029
1301
  get children() {
1030
1302
  return [(() => {
1031
1303
  var _el$11 = _$createElement("span");
1032
- _$insert(_el$11, () => " ".repeat(Math.max(1, panelWidth() - gutter() - HEADER_PREFIX - visualWidth(t().title) - visualWidth(pct() + " " + t().hitFolded))));
1304
+ _$insert(_el$11, () => " ".repeat(Math.max(1, panelWidth() - gutter() - HEADER_PREFIX - visualWidth(t("title")) - visualWidth(pct() + " " + t("hitFolded")))));
1033
1305
  return _el$11;
1034
1306
  })(), (() => {
1035
1307
  var _el$12 = _$createElement("span"), _el$13 = _$createTextNode(` `);
1036
1308
  _$insertNode(_el$12, _el$13);
1037
1309
  _$insert(_el$12, pct, _el$13);
1038
- _$insert(_el$12, () => t().hitFolded, null);
1310
+ _$insert(_el$12, () => t("hitFolded"), null);
1039
1311
  _$effect((_$p) => _$setProp(_el$12, "style", {
1040
1312
  fg: hitColor()
1041
1313
  }, _$p));
@@ -1056,28 +1328,28 @@ function TokenCachePanel(props) {
1056
1328
  },
1057
1329
  get children() {
1058
1330
  return (() => {
1059
- const prefix = " \u21B3 " + (langZH() ? "\u5B50\u4EE3\u7406: " : "Sub: ");
1331
+ const prefix = " \u21B3 " + t("subPrefix");
1060
1332
  const maxSidW = Math.max(6, panelWidth() - visualWidth(prefix));
1061
1333
  return (() => {
1062
- var _el$64 = _$createElement("text"), _el$65 = _$createElement("span"), _el$66 = _$createElement("span");
1063
- _$insertNode(_el$64, _el$65);
1064
- _$insertNode(_el$64, _el$66);
1065
- _$insert(_el$65, prefix);
1066
- _$insert(_el$66, () => truncateVisual(props.signals.overrideSessionId(), maxSidW));
1334
+ var _el$70 = _$createElement("text"), _el$71 = _$createElement("span"), _el$72 = _$createElement("span");
1335
+ _$insertNode(_el$70, _el$71);
1336
+ _$insertNode(_el$70, _el$72);
1337
+ _$insert(_el$71, prefix);
1338
+ _$insert(_el$72, () => truncateVisual(props.signals.overrideSessionId(), maxSidW));
1067
1339
  _$effect((_p$) => {
1068
- var _v$15 = {
1340
+ var _v$17 = {
1069
1341
  fg: pal().muted
1070
- }, _v$16 = {
1342
+ }, _v$18 = {
1071
1343
  fg: pal().text
1072
1344
  };
1073
- _v$15 !== _p$.e && (_p$.e = _$setProp(_el$65, "style", _v$15, _p$.e));
1074
- _v$16 !== _p$.t && (_p$.t = _$setProp(_el$66, "style", _v$16, _p$.t));
1345
+ _v$17 !== _p$.e && (_p$.e = _$setProp(_el$71, "style", _v$17, _p$.e));
1346
+ _v$18 !== _p$.t && (_p$.t = _$setProp(_el$72, "style", _v$18, _p$.t));
1075
1347
  return _p$;
1076
1348
  }, {
1077
1349
  e: void 0,
1078
1350
  t: void 0
1079
1351
  });
1080
- return _el$64;
1352
+ return _el$70;
1081
1353
  })();
1082
1354
  })();
1083
1355
  }
@@ -1087,30 +1359,30 @@ function TokenCachePanel(props) {
1087
1359
  },
1088
1360
  get fallback() {
1089
1361
  return [(() => {
1090
- var _el$67 = _$createElement("text");
1091
- _$insert(_el$67, sep);
1092
- _$effect((_$p) => _$setProp(_el$67, "fg", pal().muted, _$p));
1093
- return _el$67;
1362
+ var _el$73 = _$createElement("text");
1363
+ _$insert(_el$73, sep);
1364
+ _$effect((_$p) => _$setProp(_el$73, "fg", pal().muted, _$p));
1365
+ return _el$73;
1094
1366
  })(), (() => {
1095
- var _el$68 = _$createElement("text"), _el$69 = _$createElement("span"), _el$71 = _$createElement("span");
1096
- _$insertNode(_el$68, _el$69);
1097
- _$insertNode(_el$68, _el$71);
1098
- _$insertNode(_el$69, _$createTextNode(`> `));
1099
- _$insert(_el$71, () => t().noData);
1367
+ var _el$74 = _$createElement("text"), _el$75 = _$createElement("span"), _el$77 = _$createElement("span");
1368
+ _$insertNode(_el$74, _el$75);
1369
+ _$insertNode(_el$74, _el$77);
1370
+ _$insertNode(_el$75, _$createTextNode(`> `));
1371
+ _$insert(_el$77, () => t("noData"));
1100
1372
  _$effect((_p$) => {
1101
- var _v$17 = {
1373
+ var _v$19 = {
1102
1374
  fg: pal().muted
1103
- }, _v$18 = {
1375
+ }, _v$20 = {
1104
1376
  fg: pal().muted
1105
1377
  };
1106
- _v$17 !== _p$.e && (_p$.e = _$setProp(_el$69, "style", _v$17, _p$.e));
1107
- _v$18 !== _p$.t && (_p$.t = _$setProp(_el$71, "style", _v$18, _p$.t));
1378
+ _v$19 !== _p$.e && (_p$.e = _$setProp(_el$75, "style", _v$19, _p$.e));
1379
+ _v$20 !== _p$.t && (_p$.t = _$setProp(_el$77, "style", _v$20, _p$.t));
1108
1380
  return _p$;
1109
1381
  }, {
1110
1382
  e: void 0,
1111
1383
  t: void 0
1112
1384
  });
1113
- return _el$68;
1385
+ return _el$74;
1114
1386
  })()];
1115
1387
  },
1116
1388
  get children() {
@@ -1125,7 +1397,7 @@ function TokenCachePanel(props) {
1125
1397
  _$insertNode(_el$15, _el$18);
1126
1398
  _$insertNode(_el$15, _el$21);
1127
1399
  _$insertNode(_el$16, _el$17);
1128
- _$insert(_el$16, () => t().hit, _el$17);
1400
+ _$insert(_el$16, () => t("hit"), _el$17);
1129
1401
  _$insertNode(_el$18, _el$19);
1130
1402
  _$insertNode(_el$18, _el$20);
1131
1403
  _$insert(_el$18, bar, _el$20);
@@ -1139,7 +1411,7 @@ function TokenCachePanel(props) {
1139
1411
  _$insertNode(_el$22, _el$23);
1140
1412
  _$insert(_el$22, () => trendLabel(data().trend), null);
1141
1413
  _$effect((_$p) => _$setProp(_el$22, "style", {
1142
- fg: data().trend !== 0 ? data().trend > 0 ? pal().success : pal().error : pal().text
1414
+ fg: Math.abs(data().trend) >= 0.05 ? data().trend > 0 ? pal().success : pal().error : pal().text
1143
1415
  }, _$p));
1144
1416
  return _el$22;
1145
1417
  }
@@ -1164,7 +1436,7 @@ function TokenCachePanel(props) {
1164
1436
  return _el$15;
1165
1437
  })(), (() => {
1166
1438
  var _el$24 = _$createElement("text");
1167
- _$insert(_el$24, () => justify(t().totalHit, (Math.floor(data().sessionHitRate * 10) / 10).toFixed(1) + "%"));
1439
+ _$insert(_el$24, () => justify(t("totalHit"), (Math.floor(data().sessionHitRate * 10) / 10).toFixed(1) + "%"));
1168
1440
  _$effect((_$p) => _$setProp(_el$24, "fg", pal().muted, _$p));
1169
1441
  return _el$24;
1170
1442
  })(), _$createComponent(Show, {
@@ -1184,8 +1456,8 @@ function TokenCachePanel(props) {
1184
1456
  }));
1185
1457
  _$insert(_el$26, () => detailOpen() ? "\u25BC " : "\u25B6 ");
1186
1458
  _$insertNode(_el$27, _el$28);
1187
- _$insert(_el$28, () => t().secDetail);
1188
- _$insert(_el$29, () => sep().slice(visualWidth((detailOpen() ? "\u25BC " : "\u25B6 ") + t().secDetail)));
1459
+ _$insert(_el$28, () => t("secDetail"));
1460
+ _$insert(_el$29, () => sep().slice(visualWidth((detailOpen() ? "\u25BC " : "\u25B6 ") + t("secDetail"))));
1189
1461
  _$effect((_p$) => {
1190
1462
  var _v$4 = {
1191
1463
  fg: pal().muted
@@ -1215,7 +1487,7 @@ function TokenCachePanel(props) {
1215
1487
  },
1216
1488
  get children() {
1217
1489
  var _el$30 = _$createElement("text");
1218
- _$insert(_el$30, () => justify(t().read, fmt(data().read), t().tok));
1490
+ _$insert(_el$30, () => justify(t("read"), fmt(data().read), t("tok")));
1219
1491
  _$effect((_$p) => _$setProp(_el$30, "fg", pal().muted, _$p));
1220
1492
  return _el$30;
1221
1493
  }
@@ -1225,47 +1497,59 @@ function TokenCachePanel(props) {
1225
1497
  },
1226
1498
  get children() {
1227
1499
  var _el$31 = _$createElement("text");
1228
- _$insert(_el$31, () => justify(t().write, fmt(data().write), t().tok));
1500
+ _$insert(_el$31, () => justify(t("write"), fmt(data().write), t("tok")));
1229
1501
  _$effect((_$p) => _$setProp(_el$31, "fg", pal().muted, _$p));
1230
1502
  return _el$31;
1231
1503
  }
1232
1504
  }), (() => {
1233
1505
  var _el$32 = _$createElement("text");
1234
- _$insert(_el$32, () => justify(t().miss, fmt(data().freshInput), t().tok));
1506
+ _$insert(_el$32, () => justify(t("miss"), fmt(data().freshInput + data().write), t("tok")));
1235
1507
  _$effect((_$p) => _$setProp(_el$32, "fg", pal().muted, _$p));
1236
1508
  return _el$32;
1237
1509
  })(), (() => {
1238
1510
  var _el$33 = _$createElement("text");
1239
- _$insert(_el$33, () => justify(t().out, fmt(data().output), t().tok));
1511
+ _$insert(_el$33, () => justify(t("out"), fmt(data().output), t("tok")));
1240
1512
  _$effect((_$p) => _$setProp(_el$33, "fg", pal().muted, _$p));
1241
1513
  return _el$33;
1242
1514
  })(), _$createComponent(Show, {
1515
+ get when() {
1516
+ return data().dist.stepCount >= 2;
1517
+ },
1518
+ get children() {
1519
+ var _el$34 = _$createElement("text");
1520
+ _$insert(_el$34, () => justify(t("stepsCount", {
1521
+ n: data().dist.stepCount
1522
+ }), fmtCost(data().dist.stepCost, currencySymbol(), exchangeRate())));
1523
+ _$effect((_$p) => _$setProp(_el$34, "fg", pal().muted, _$p));
1524
+ return _el$34;
1525
+ }
1526
+ }), _$createComponent(Show, {
1243
1527
  get when() {
1244
1528
  return data().saved > 0;
1245
1529
  },
1246
1530
  get children() {
1247
- var _el$34 = _$createElement("text"), _el$35 = _$createElement("span"), _el$36 = _$createElement("span"), _el$37 = _$createElement("span"), _el$38 = _$createTextNode(`~`);
1248
- _$insertNode(_el$34, _el$35);
1249
- _$insertNode(_el$34, _el$36);
1250
- _$insertNode(_el$34, _el$37);
1251
- _$insert(_el$35, () => t().saved);
1252
- _$insert(_el$36, () => " ".repeat(Math.max(1, panelWidth() - gutter() - visualWidth(t().saved) - visualWidth("~" + fmtCost(data().saved, currencySymbol(), exchangeRate())))));
1253
- _$insertNode(_el$37, _el$38);
1254
- _$insert(_el$37, () => fmtCost(data().saved, currencySymbol(), exchangeRate()), null);
1531
+ var _el$35 = _$createElement("text"), _el$36 = _$createElement("span"), _el$37 = _$createElement("span"), _el$38 = _$createElement("span"), _el$39 = _$createTextNode(`~`);
1532
+ _$insertNode(_el$35, _el$36);
1533
+ _$insertNode(_el$35, _el$37);
1534
+ _$insertNode(_el$35, _el$38);
1535
+ _$insert(_el$36, () => t("saved"));
1536
+ _$insert(_el$37, () => " ".repeat(Math.max(1, panelWidth() - gutter() - visualWidth(t("saved")) - visualWidth("~" + fmtCost(data().saved, currencySymbol(), exchangeRate())))));
1537
+ _$insertNode(_el$38, _el$39);
1538
+ _$insert(_el$38, () => fmtCost(data().saved, currencySymbol(), exchangeRate()), null);
1255
1539
  _$effect((_p$) => {
1256
1540
  var _v$7 = {
1257
1541
  fg: pal().muted
1258
1542
  }, _v$8 = {
1259
1543
  fg: pal().success
1260
1544
  };
1261
- _v$7 !== _p$.e && (_p$.e = _$setProp(_el$35, "style", _v$7, _p$.e));
1262
- _v$8 !== _p$.t && (_p$.t = _$setProp(_el$37, "style", _v$8, _p$.t));
1545
+ _v$7 !== _p$.e && (_p$.e = _$setProp(_el$36, "style", _v$7, _p$.e));
1546
+ _v$8 !== _p$.t && (_p$.t = _$setProp(_el$38, "style", _v$8, _p$.t));
1263
1547
  return _p$;
1264
1548
  }, {
1265
1549
  e: void 0,
1266
1550
  t: void 0
1267
1551
  });
1268
- return _el$34;
1552
+ return _el$35;
1269
1553
  }
1270
1554
  })];
1271
1555
  }
@@ -1277,91 +1561,91 @@ function TokenCachePanel(props) {
1277
1561
  },
1278
1562
  get children() {
1279
1563
  return [_$memo(() => (() => {
1280
- var _el$72 = _$createElement("text"), _el$73 = _$createElement("span"), _el$74 = _$createElement("span"), _el$75 = _$createElement("b"), _el$76 = _$createElement("span");
1281
- _$insertNode(_el$72, _el$73);
1282
- _$insertNode(_el$72, _el$74);
1283
- _$insertNode(_el$72, _el$76);
1284
- _$setProp(_el$72, "onMouseUp", () => setModelOpen((o) => {
1564
+ var _el$78 = _$createElement("text"), _el$79 = _$createElement("span"), _el$80 = _$createElement("span"), _el$81 = _$createElement("b"), _el$82 = _$createElement("span");
1565
+ _$insertNode(_el$78, _el$79);
1566
+ _$insertNode(_el$78, _el$80);
1567
+ _$insertNode(_el$78, _el$82);
1568
+ _$setProp(_el$78, "onMouseUp", () => setModelOpen((o) => {
1285
1569
  const n = !o;
1286
1570
  persistFold("model", n);
1287
1571
  return n;
1288
1572
  }));
1289
- _$insert(_el$73, () => modelOpen() ? "\u25BC " : "\u25B6 ");
1290
- _$insertNode(_el$74, _el$75);
1291
- _$insert(_el$75, () => t().secModel);
1292
- _$insert(_el$76, () => sep().slice(visualWidth((modelOpen() ? "\u25BC " : "\u25B6 ") + t().secModel)));
1573
+ _$insert(_el$79, () => modelOpen() ? "\u25BC " : "\u25B6 ");
1574
+ _$insertNode(_el$80, _el$81);
1575
+ _$insert(_el$81, () => t("secModel"));
1576
+ _$insert(_el$82, () => sep().slice(visualWidth((modelOpen() ? "\u25BC " : "\u25B6 ") + t("secModel"))));
1293
1577
  _$effect((_p$) => {
1294
- var _v$19 = {
1578
+ var _v$21 = {
1295
1579
  fg: pal().muted
1296
- }, _v$20 = {
1580
+ }, _v$22 = {
1297
1581
  fg: pal().primary
1298
- }, _v$21 = {
1582
+ }, _v$23 = {
1299
1583
  fg: pal().muted
1300
1584
  };
1301
- _v$19 !== _p$.e && (_p$.e = _$setProp(_el$73, "style", _v$19, _p$.e));
1302
- _v$20 !== _p$.t && (_p$.t = _$setProp(_el$74, "style", _v$20, _p$.t));
1303
- _v$21 !== _p$.a && (_p$.a = _$setProp(_el$76, "style", _v$21, _p$.a));
1585
+ _v$21 !== _p$.e && (_p$.e = _$setProp(_el$79, "style", _v$21, _p$.e));
1586
+ _v$22 !== _p$.t && (_p$.t = _$setProp(_el$80, "style", _v$22, _p$.t));
1587
+ _v$23 !== _p$.a && (_p$.a = _$setProp(_el$82, "style", _v$23, _p$.a));
1304
1588
  return _p$;
1305
1589
  }, {
1306
1590
  e: void 0,
1307
1591
  t: void 0,
1308
1592
  a: void 0
1309
1593
  });
1310
- return _el$72;
1594
+ return _el$78;
1311
1595
  })()), _$createComponent(Show, {
1312
1596
  get when() {
1313
1597
  return modelOpen();
1314
1598
  },
1315
1599
  get children() {
1316
1600
  return [(() => {
1317
- var _el$39 = _$createElement("text");
1318
- _$insert(_el$39, () => justify(t().cost, fmtCost(data().cost, currencySymbol(), exchangeRate())));
1319
- _$effect((_$p) => _$setProp(_el$39, "fg", pal().text, _$p));
1320
- return _el$39;
1601
+ var _el$40 = _$createElement("text");
1602
+ _$insert(_el$40, () => justify(t("cost"), fmtCost(data().cost, currencySymbol(), exchangeRate())));
1603
+ _$effect((_$p) => _$setProp(_el$40, "fg", pal().text, _$p));
1604
+ return _el$40;
1321
1605
  })(), _$createComponent(Show, {
1322
1606
  get when() {
1323
1607
  return data().providerName;
1324
1608
  },
1325
1609
  get children() {
1326
- var _el$40 = _$createElement("text");
1327
- _$insert(_el$40, () => justify(t().provider, data().providerName));
1328
- _$effect((_$p) => _$setProp(_el$40, "fg", pal().muted, _$p));
1329
- return _el$40;
1610
+ var _el$41 = _$createElement("text");
1611
+ _$insert(_el$41, () => justify(t("provider"), data().providerName));
1612
+ _$effect((_$p) => _$setProp(_el$41, "fg", pal().muted, _$p));
1613
+ return _el$41;
1330
1614
  }
1331
1615
  }), (() => {
1332
- var _el$41 = _$createElement("text");
1333
- _$insert(_el$41, () => justify(t().model, data().model));
1334
- _$effect((_$p) => _$setProp(_el$41, "fg", pal().muted, _$p));
1335
- return _el$41;
1616
+ var _el$42 = _$createElement("text");
1617
+ _$insert(_el$42, () => justify(t("model"), data().model));
1618
+ _$effect((_$p) => _$setProp(_el$42, "fg", pal().muted, _$p));
1619
+ return _el$42;
1336
1620
  })(), _$createComponent(Show, {
1337
1621
  get when() {
1338
1622
  return data().hasPricing;
1339
1623
  },
1340
1624
  get children() {
1341
1625
  return [(() => {
1342
- var _el$42 = _$createElement("text");
1343
- _$insert(_el$42, () => justify(t().rate, currencySymbol() + (data().inputRate * exchangeRate()).toFixed(2) + "/M " + t().inputRate));
1344
- _$effect((_$p) => _$setProp(_el$42, "fg", pal().muted, _$p));
1345
- return _el$42;
1626
+ var _el$43 = _$createElement("text");
1627
+ _$insert(_el$43, () => justify(t("rate"), currencySymbol() + (data().inputRate * exchangeRate()).toFixed(2) + "/M " + t("inputRate")));
1628
+ _$effect((_$p) => _$setProp(_el$43, "fg", pal().muted, _$p));
1629
+ return _el$43;
1346
1630
  })(), _$createComponent(Show, {
1347
1631
  get when() {
1348
1632
  return data().cacheReadRate > 0;
1349
1633
  },
1350
1634
  get children() {
1351
- var _el$43 = _$createElement("text");
1352
- _$insert(_el$43, () => justify("", currencySymbol() + (data().cacheReadRate * exchangeRate()).toFixed(2) + "/M " + t().cacheRate));
1353
- _$effect((_$p) => _$setProp(_el$43, "fg", pal().muted, _$p));
1354
- return _el$43;
1635
+ var _el$44 = _$createElement("text");
1636
+ _$insert(_el$44, () => justify("", currencySymbol() + (data().cacheReadRate * exchangeRate()).toFixed(2) + "/M " + t("cacheRate")));
1637
+ _$effect((_$p) => _$setProp(_el$44, "fg", pal().muted, _$p));
1638
+ return _el$44;
1355
1639
  }
1356
1640
  }), _$createComponent(Show, {
1357
1641
  get when() {
1358
1642
  return data().cacheWriteRate > 0;
1359
1643
  },
1360
1644
  get children() {
1361
- var _el$44 = _$createElement("text");
1362
- _$insert(_el$44, () => justify("", currencySymbol() + (data().cacheWriteRate * exchangeRate()).toFixed(2) + "/M " + t().writeRate));
1363
- _$effect((_$p) => _$setProp(_el$44, "fg", pal().muted, _$p));
1364
- return _el$44;
1645
+ var _el$45 = _$createElement("text");
1646
+ _$insert(_el$45, () => justify("", currencySymbol() + (data().cacheWriteRate * exchangeRate()).toFixed(2) + "/M " + t("writeRate")));
1647
+ _$effect((_$p) => _$setProp(_el$45, "fg", pal().muted, _$p));
1648
+ return _el$45;
1365
1649
  }
1366
1650
  })];
1367
1651
  }
@@ -1380,37 +1664,37 @@ function TokenCachePanel(props) {
1380
1664
  },
1381
1665
  get children() {
1382
1666
  return [_$memo(() => (() => {
1383
- var _el$77 = _$createElement("text"), _el$78 = _$createElement("span"), _el$79 = _$createElement("span"), _el$80 = _$createElement("b"), _el$81 = _$createElement("span");
1384
- _$insertNode(_el$77, _el$78);
1385
- _$insertNode(_el$77, _el$79);
1386
- _$insertNode(_el$77, _el$81);
1387
- _$setProp(_el$77, "onMouseUp", () => setDistOpen((o) => {
1667
+ var _el$83 = _$createElement("text"), _el$84 = _$createElement("span"), _el$85 = _$createElement("span"), _el$86 = _$createElement("b"), _el$87 = _$createElement("span");
1668
+ _$insertNode(_el$83, _el$84);
1669
+ _$insertNode(_el$83, _el$85);
1670
+ _$insertNode(_el$83, _el$87);
1671
+ _$setProp(_el$83, "onMouseUp", () => setDistOpen((o) => {
1388
1672
  const n = !o;
1389
1673
  persistFold("dist", n);
1390
1674
  return n;
1391
1675
  }));
1392
- _$insert(_el$78, () => distOpen() ? "\u25BC " : "\u25B6 ");
1393
- _$insertNode(_el$79, _el$80);
1394
- _$insert(_el$80, () => t().distTitle);
1395
- _$insert(_el$81, () => sep().slice(visualWidth((distOpen() ? "\u25BC " : "\u25B6 ") + t().distTitle)));
1676
+ _$insert(_el$84, () => distOpen() ? "\u25BC " : "\u25B6 ");
1677
+ _$insertNode(_el$85, _el$86);
1678
+ _$insert(_el$86, () => t("distTitle"));
1679
+ _$insert(_el$87, () => sep().slice(visualWidth((distOpen() ? "\u25BC " : "\u25B6 ") + t("distTitle"))));
1396
1680
  _$effect((_p$) => {
1397
- var _v$22 = {
1681
+ var _v$24 = {
1398
1682
  fg: pal().muted
1399
- }, _v$23 = {
1683
+ }, _v$25 = {
1400
1684
  fg: pal().primary
1401
- }, _v$24 = {
1685
+ }, _v$26 = {
1402
1686
  fg: pal().muted
1403
1687
  };
1404
- _v$22 !== _p$.e && (_p$.e = _$setProp(_el$78, "style", _v$22, _p$.e));
1405
- _v$23 !== _p$.t && (_p$.t = _$setProp(_el$79, "style", _v$23, _p$.t));
1406
- _v$24 !== _p$.a && (_p$.a = _$setProp(_el$81, "style", _v$24, _p$.a));
1688
+ _v$24 !== _p$.e && (_p$.e = _$setProp(_el$84, "style", _v$24, _p$.e));
1689
+ _v$25 !== _p$.t && (_p$.t = _$setProp(_el$85, "style", _v$25, _p$.t));
1690
+ _v$26 !== _p$.a && (_p$.a = _$setProp(_el$87, "style", _v$26, _p$.a));
1407
1691
  return _p$;
1408
1692
  }, {
1409
1693
  e: void 0,
1410
1694
  t: void 0,
1411
1695
  a: void 0
1412
1696
  });
1413
- return _el$77;
1697
+ return _el$83;
1414
1698
  })()), _$createComponent(Show, {
1415
1699
  get when() {
1416
1700
  return distOpen();
@@ -1420,58 +1704,63 @@ function TokenCachePanel(props) {
1420
1704
  get when() {
1421
1705
  return data().dist.system > 0;
1422
1706
  },
1423
- get children() {
1424
- var _el$45 = _$createElement("text");
1425
- _$insert(_el$45, () => justify(t().distSys, fmt(data().dist.system), t().tok));
1426
- _$effect((_$p) => _$setProp(_el$45, "fg", pal().muted, _$p));
1427
- return _el$45;
1428
- }
1429
- }), _$createComponent(Show, {
1430
- get when() {
1431
- return data().dist.user > 0;
1432
- },
1433
1707
  get children() {
1434
1708
  var _el$46 = _$createElement("text");
1435
- _$insert(_el$46, () => justify(t().distUser, fmt(data().dist.user), t().tok));
1709
+ _$insert(_el$46, () => justify(t("distSys"), fmt(data().dist.system), t("tok")));
1436
1710
  _$effect((_$p) => _$setProp(_el$46, "fg", pal().muted, _$p));
1437
1711
  return _el$46;
1438
1712
  }
1439
1713
  }), _$createComponent(Show, {
1440
1714
  get when() {
1441
- return data().dist.agent > 0;
1715
+ return data().dist.user > 0;
1442
1716
  },
1443
1717
  get children() {
1444
1718
  var _el$47 = _$createElement("text");
1445
- _$insert(_el$47, () => justify(t().distAgent, fmt(data().dist.agent), t().tok));
1719
+ _$insert(_el$47, () => justify(t("distUser"), fmt(data().dist.user), t("tok")));
1446
1720
  _$effect((_$p) => _$setProp(_el$47, "fg", pal().muted, _$p));
1447
1721
  return _el$47;
1448
1722
  }
1449
1723
  }), _$createComponent(Show, {
1450
1724
  get when() {
1451
- return data().dist.toolCall > 0;
1725
+ return data().dist.agent > 0;
1452
1726
  },
1453
1727
  get children() {
1454
1728
  var _el$48 = _$createElement("text");
1455
- _$insert(_el$48, () => justify(t().distTool, fmt(data().dist.toolCall), t().tok));
1729
+ _$insert(_el$48, () => justify(t("distAgent"), fmt(data().dist.agent), t("tok")));
1456
1730
  _$effect((_$p) => _$setProp(_el$48, "fg", pal().muted, _$p));
1457
1731
  return _el$48;
1458
1732
  }
1459
1733
  }), _$createComponent(Show, {
1460
1734
  get when() {
1461
- return data().dist.toolResult > 0;
1735
+ return data().dist.toolCall > 0;
1462
1736
  },
1463
1737
  get children() {
1464
1738
  var _el$49 = _$createElement("text");
1465
- _$insert(_el$49, () => justify(t().distRes, fmt(data().dist.toolResult), t().tok));
1739
+ _$insert(_el$49, () => justify(t("distTool"), fmt(data().dist.toolCall), t("tok")));
1466
1740
  _$effect((_$p) => _$setProp(_el$49, "fg", pal().muted, _$p));
1467
1741
  return _el$49;
1468
1742
  }
1469
- }), (() => {
1470
- var _el$50 = _$createElement("text");
1471
- _$insert(_el$50, () => justify(t().distTotal, fmt(data().dist.apiInput), t().tok));
1472
- _$effect((_$p) => _$setProp(_el$50, "fg", pal().text, _$p));
1473
- return _el$50;
1474
- })()];
1743
+ }), _$createComponent(Show, {
1744
+ get when() {
1745
+ return data().dist.toolResult > 0;
1746
+ },
1747
+ get children() {
1748
+ var _el$50 = _$createElement("text");
1749
+ _$insert(_el$50, () => justify(t("distRes"), fmt(data().dist.toolResult), t("tok")));
1750
+ _$effect((_$p) => _$setProp(_el$50, "fg", pal().muted, _$p));
1751
+ return _el$50;
1752
+ }
1753
+ }), _$createComponent(Show, {
1754
+ get when() {
1755
+ return data().dist.reasoning > 0;
1756
+ },
1757
+ get children() {
1758
+ var _el$51 = _$createElement("text");
1759
+ _$insert(_el$51, () => justify(t("distReason"), fmt(data().dist.reasoning), t("tok")));
1760
+ _$effect((_$p) => _$setProp(_el$51, "fg", pal().muted, _$p));
1761
+ return _el$51;
1762
+ }
1763
+ })];
1475
1764
  }
1476
1765
  })];
1477
1766
  }
@@ -1488,37 +1777,37 @@ function TokenCachePanel(props) {
1488
1777
  },
1489
1778
  get children() {
1490
1779
  return [_$memo(() => (() => {
1491
- var _el$82 = _$createElement("text"), _el$83 = _$createElement("span"), _el$84 = _$createElement("span"), _el$85 = _$createElement("b"), _el$86 = _$createElement("span"), _el$87 = _$createTextNode(` (`), _el$88 = _$createTextNode(`)`), _el$89 = _$createElement("span");
1492
- _$insertNode(_el$82, _el$83);
1493
- _$insertNode(_el$82, _el$84);
1494
- _$insertNode(_el$82, _el$86);
1495
- _$insertNode(_el$82, _el$89);
1496
- _$setProp(_el$82, "onMouseUp", () => setSkillsOpen((o) => {
1780
+ 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");
1781
+ _$insertNode(_el$88, _el$89);
1782
+ _$insertNode(_el$88, _el$90);
1783
+ _$insertNode(_el$88, _el$92);
1784
+ _$insertNode(_el$88, _el$95);
1785
+ _$setProp(_el$88, "onMouseUp", () => setSkillsOpen((o) => {
1497
1786
  const n = !o;
1498
1787
  persistFold("skills", n);
1499
1788
  return n;
1500
1789
  }));
1501
- _$insert(_el$83, () => skillsOpen() ? "\u25BC " : "\u25B6 ");
1502
- _$insertNode(_el$84, _el$85);
1503
- _$insert(_el$85, () => t().secSkills);
1504
- _$insertNode(_el$86, _el$87);
1505
- _$insertNode(_el$86, _el$88);
1506
- _$insert(_el$86, () => data().skills.length, _el$88);
1507
- _$insert(_el$89, () => sep().slice(visualWidth((skillsOpen() ? "\u25BC " : "\u25B6 ") + t().secSkills + ` (${data().skills.length})`)));
1790
+ _$insert(_el$89, () => skillsOpen() ? "\u25BC " : "\u25B6 ");
1791
+ _$insertNode(_el$90, _el$91);
1792
+ _$insert(_el$91, () => t("secSkills"));
1793
+ _$insertNode(_el$92, _el$93);
1794
+ _$insertNode(_el$92, _el$94);
1795
+ _$insert(_el$92, () => data().skills.length, _el$94);
1796
+ _$insert(_el$95, () => sep().slice(visualWidth((skillsOpen() ? "\u25BC " : "\u25B6 ") + t("secSkills") + ` (${data().skills.length})`)));
1508
1797
  _$effect((_p$) => {
1509
- var _v$25 = {
1798
+ var _v$27 = {
1510
1799
  fg: pal().muted
1511
- }, _v$26 = {
1800
+ }, _v$28 = {
1512
1801
  fg: pal().primary
1513
- }, _v$27 = {
1802
+ }, _v$29 = {
1514
1803
  fg: pal().muted
1515
- }, _v$28 = {
1804
+ }, _v$30 = {
1516
1805
  fg: pal().muted
1517
1806
  };
1518
- _v$25 !== _p$.e && (_p$.e = _$setProp(_el$83, "style", _v$25, _p$.e));
1519
- _v$26 !== _p$.t && (_p$.t = _$setProp(_el$84, "style", _v$26, _p$.t));
1520
- _v$27 !== _p$.a && (_p$.a = _$setProp(_el$86, "style", _v$27, _p$.a));
1521
- _v$28 !== _p$.o && (_p$.o = _$setProp(_el$89, "style", _v$28, _p$.o));
1807
+ _v$27 !== _p$.e && (_p$.e = _$setProp(_el$89, "style", _v$27, _p$.e));
1808
+ _v$28 !== _p$.t && (_p$.t = _$setProp(_el$90, "style", _v$28, _p$.t));
1809
+ _v$29 !== _p$.a && (_p$.a = _$setProp(_el$92, "style", _v$29, _p$.a));
1810
+ _v$30 !== _p$.o && (_p$.o = _$setProp(_el$95, "style", _v$30, _p$.o));
1522
1811
  return _p$;
1523
1812
  }, {
1524
1813
  e: void 0,
@@ -1526,21 +1815,21 @@ function TokenCachePanel(props) {
1526
1815
  a: void 0,
1527
1816
  o: void 0
1528
1817
  });
1529
- return _el$82;
1818
+ return _el$88;
1530
1819
  })()), _$createComponent(Show, {
1531
1820
  get when() {
1532
1821
  return skillsOpen();
1533
1822
  },
1534
1823
  get children() {
1535
1824
  return data().skills.map((sk) => {
1536
- const rightW = visualWidth(fmt(sk.tokens)) + UNIT_GAP + visualWidth(t().tok);
1825
+ const rightW = visualWidth(fmt(sk.tokens)) + UNIT_GAP + visualWidth(t("tok"));
1537
1826
  const maxLabel = Math.max(4, panelWidth() - gutter() - rightW - 1);
1538
1827
  const label = truncateVisual(sk.name, maxLabel);
1539
1828
  return (() => {
1540
- var _el$90 = _$createElement("text");
1541
- _$insert(_el$90, () => justify(label, fmt(sk.tokens), t().tok));
1542
- _$effect((_$p) => _$setProp(_el$90, "fg", pal().muted, _$p));
1543
- return _el$90;
1829
+ var _el$96 = _$createElement("text");
1830
+ _$insert(_el$96, () => justify(label, fmt(sk.tokens), t("tok")));
1831
+ _$effect((_$p) => _$setProp(_el$96, "fg", pal().muted, _$p));
1832
+ return _el$96;
1544
1833
  })();
1545
1834
  });
1546
1835
  }
@@ -1554,116 +1843,127 @@ function TokenCachePanel(props) {
1554
1843
  },
1555
1844
  get children() {
1556
1845
  return [(() => {
1557
- var _el$51 = _$createElement("text");
1558
- _$insert(_el$51, sep);
1559
- _$effect((_$p) => _$setProp(_el$51, "fg", pal().muted, _$p));
1560
- return _el$51;
1846
+ var _el$52 = _$createElement("text");
1847
+ _$insert(_el$52, sep);
1848
+ _$effect((_$p) => _$setProp(_el$52, "fg", pal().muted, _$p));
1849
+ return _el$52;
1561
1850
  })(), _$createComponent(Show, {
1562
1851
  get when() {
1563
- return balanceState().status === "idle";
1852
+ return balanceUnsupported();
1564
1853
  },
1565
1854
  get children() {
1566
- var _el$52 = _$createElement("text"), _el$53 = _$createElement("span"), _el$55 = _$createElement("span");
1567
- _$insertNode(_el$52, _el$53);
1568
- _$insertNode(_el$52, _el$55);
1569
- _$insertNode(_el$53, _$createTextNode(`> `));
1570
- _$insert(_el$55, () => t().balNoKey.replace("{p}", providerName()));
1855
+ var _el$53 = _$createElement("text"), _el$54 = _$createElement("span"), _el$56 = _$createElement("span");
1856
+ _$insertNode(_el$53, _el$54);
1857
+ _$insertNode(_el$53, _el$56);
1858
+ _$insertNode(_el$54, _$createTextNode(`> `));
1859
+ _$insert(_el$56, () => t("balUnsupported"));
1571
1860
  _$effect((_p$) => {
1572
1861
  var _v$9 = pal().muted, _v$0 = {
1573
1862
  fg: pal().muted
1574
1863
  };
1575
- _v$9 !== _p$.e && (_p$.e = _$setProp(_el$52, "fg", _v$9, _p$.e));
1576
- _v$0 !== _p$.t && (_p$.t = _$setProp(_el$53, "style", _v$0, _p$.t));
1577
- return _p$;
1578
- }, {
1579
- e: void 0,
1580
- t: void 0
1581
- });
1582
- return _el$52;
1583
- }
1584
- }), _$createComponent(Show, {
1585
- get when() {
1586
- return balanceState().status === "loading";
1587
- },
1588
- get children() {
1589
- var _el$56 = _$createElement("text"), _el$57 = _$createElement("span"), _el$59 = _$createElement("span");
1590
- _$insertNode(_el$56, _el$57);
1591
- _$insertNode(_el$56, _el$59);
1592
- _$insertNode(_el$57, _$createTextNode(`> `));
1593
- _$insert(_el$59, () => t().balLoading);
1594
- _$effect((_p$) => {
1595
- var _v$1 = pal().muted, _v$10 = {
1596
- fg: pal().muted
1597
- };
1598
- _v$1 !== _p$.e && (_p$.e = _$setProp(_el$56, "fg", _v$1, _p$.e));
1599
- _v$10 !== _p$.t && (_p$.t = _$setProp(_el$57, "style", _v$10, _p$.t));
1600
- return _p$;
1601
- }, {
1602
- e: void 0,
1603
- t: void 0
1604
- });
1605
- return _el$56;
1606
- }
1607
- }), _$createComponent(Show, {
1608
- get when() {
1609
- return balanceState().status === "error";
1610
- },
1611
- get children() {
1612
- var _el$60 = _$createElement("text"), _el$61 = _$createElement("span"), _el$63 = _$createElement("span");
1613
- _$insertNode(_el$60, _el$61);
1614
- _$insertNode(_el$60, _el$63);
1615
- _$insertNode(_el$61, _$createTextNode(`> `));
1616
- _$insert(_el$63, () => {
1617
- const code = balanceState().error;
1618
- if (code === "401") return t().balErr401;
1619
- if (code === "403") return t().balErr403;
1620
- if (code === "EMPTY") return t().balErrEmpty;
1621
- if (code === "TIMEOUT") return t().balErrTimeout;
1622
- return t().balError + (code ? ` (${code})` : "");
1623
- });
1624
- _$effect((_p$) => {
1625
- var _v$11 = pal().error, _v$12 = {
1626
- fg: pal().muted
1627
- };
1628
- _v$11 !== _p$.e && (_p$.e = _$setProp(_el$60, "fg", _v$11, _p$.e));
1629
- _v$12 !== _p$.t && (_p$.t = _$setProp(_el$61, "style", _v$12, _p$.t));
1864
+ _v$9 !== _p$.e && (_p$.e = _$setProp(_el$53, "fg", _v$9, _p$.e));
1865
+ _v$0 !== _p$.t && (_p$.t = _$setProp(_el$54, "style", _v$0, _p$.t));
1630
1866
  return _p$;
1631
1867
  }, {
1632
1868
  e: void 0,
1633
1869
  t: void 0
1634
1870
  });
1635
- return _el$60;
1871
+ return _el$53;
1636
1872
  }
1637
1873
  }), _$createComponent(Show, {
1638
1874
  get when() {
1639
- return _$memo(() => balanceState().status === "ok")() && balanceState().data;
1875
+ return !balanceUnsupported();
1640
1876
  },
1641
1877
  get children() {
1642
- return (() => {
1643
- const list = balanceState().data;
1644
- const pref = balanceCurrency();
1645
- const native = pref ? list.find((x) => x.currency === pref) : void 0;
1646
- if (native) {
1647
- return (() => {
1648
- var _el$91 = _$createElement("text");
1649
- _$insert(_el$91, () => justify(t().balTotal, balanceSymbol(native.currency) + native.total));
1650
- _$effect((_$p) => _$setProp(_el$91, "fg", pal().text, _$p));
1651
- return _el$91;
1652
- })();
1878
+ return [_$createComponent(Show, {
1879
+ get when() {
1880
+ return balanceState().status === "idle";
1881
+ },
1882
+ get children() {
1883
+ var _el$57 = _$createElement("text"), _el$58 = _$createElement("span"), _el$60 = _$createElement("span");
1884
+ _$insertNode(_el$57, _el$58);
1885
+ _$insertNode(_el$57, _el$60);
1886
+ _$insertNode(_el$58, _$createTextNode(`> `));
1887
+ _$insert(_el$60, () => t("balNoKey", {
1888
+ p: providerName()
1889
+ }));
1890
+ _$effect((_p$) => {
1891
+ var _v$1 = pal().muted, _v$10 = {
1892
+ fg: pal().muted
1893
+ };
1894
+ _v$1 !== _p$.e && (_p$.e = _$setProp(_el$57, "fg", _v$1, _p$.e));
1895
+ _v$10 !== _p$.t && (_p$.t = _$setProp(_el$58, "style", _v$10, _p$.t));
1896
+ return _p$;
1897
+ }, {
1898
+ e: void 0,
1899
+ t: void 0
1900
+ });
1901
+ return _el$57;
1653
1902
  }
1654
- const base = list[0];
1655
- const baseAmt = parseFloat(base.total);
1656
- const converted = Number.isFinite(baseAmt) ? convertBalance(pref || base.currency, exchangeRate(), baseAmt, base.currency) : baseAmt;
1657
- const shown = pref && base.currency !== pref ? converted.toLocaleString("en-US", {
1658
- maximumFractionDigits: 2
1659
- }) : base.total;
1660
- return (() => {
1661
- var _el$92 = _$createElement("text");
1662
- _$insert(_el$92, () => justify(t().balTotal, balanceSymbol(pref || base.currency) + shown));
1663
- _$effect((_$p) => _$setProp(_el$92, "fg", pal().text, _$p));
1664
- return _el$92;
1665
- })();
1666
- })();
1903
+ }), _$createComponent(Show, {
1904
+ get when() {
1905
+ return balanceState().status === "loading";
1906
+ },
1907
+ get children() {
1908
+ var _el$61 = _$createElement("text"), _el$62 = _$createElement("span"), _el$64 = _$createElement("span");
1909
+ _$insertNode(_el$61, _el$62);
1910
+ _$insertNode(_el$61, _el$64);
1911
+ _$insertNode(_el$62, _$createTextNode(`> `));
1912
+ _$insert(_el$64, () => t("balLoading"));
1913
+ _$effect((_p$) => {
1914
+ var _v$11 = pal().muted, _v$12 = {
1915
+ fg: pal().muted
1916
+ };
1917
+ _v$11 !== _p$.e && (_p$.e = _$setProp(_el$61, "fg", _v$11, _p$.e));
1918
+ _v$12 !== _p$.t && (_p$.t = _$setProp(_el$62, "style", _v$12, _p$.t));
1919
+ return _p$;
1920
+ }, {
1921
+ e: void 0,
1922
+ t: void 0
1923
+ });
1924
+ return _el$61;
1925
+ }
1926
+ }), _$createComponent(Show, {
1927
+ get when() {
1928
+ return balanceState().status === "error";
1929
+ },
1930
+ get children() {
1931
+ var _el$65 = _$createElement("text"), _el$66 = _$createElement("span"), _el$68 = _$createElement("span");
1932
+ _$insertNode(_el$65, _el$66);
1933
+ _$insertNode(_el$65, _el$68);
1934
+ _$insertNode(_el$66, _$createTextNode(`> `));
1935
+ _$insert(_el$68, () => {
1936
+ const code = balanceState().error;
1937
+ if (code === "401") return t("balErr401");
1938
+ if (code === "403") return t("balErr403");
1939
+ if (code === "EMPTY") return t("balErrEmpty");
1940
+ if (code === "TIMEOUT") return t("balErrTimeout");
1941
+ return t("balError") + (code ? ` (${code})` : "");
1942
+ });
1943
+ _$effect((_p$) => {
1944
+ var _v$13 = pal().error, _v$14 = {
1945
+ fg: pal().muted
1946
+ };
1947
+ _v$13 !== _p$.e && (_p$.e = _$setProp(_el$65, "fg", _v$13, _p$.e));
1948
+ _v$14 !== _p$.t && (_p$.t = _$setProp(_el$66, "style", _v$14, _p$.t));
1949
+ return _p$;
1950
+ }, {
1951
+ e: void 0,
1952
+ t: void 0
1953
+ });
1954
+ return _el$65;
1955
+ }
1956
+ }), _$createComponent(Show, {
1957
+ get when() {
1958
+ return _$memo(() => balanceState().status === "ok")() && balanceState().data;
1959
+ },
1960
+ get children() {
1961
+ var _el$69 = _$createElement("text");
1962
+ _$insert(_el$69, () => justify(t("balTotal"), formatBalanceText(balanceState().data, balanceCurrency(), exchangeRate())));
1963
+ _$effect((_$p) => _$setProp(_el$69, "fg", pal().text, _$p));
1964
+ return _el$69;
1965
+ }
1966
+ })];
1667
1967
  }
1668
1968
  })];
1669
1969
  }
@@ -1673,13 +1973,13 @@ function TokenCachePanel(props) {
1673
1973
  }
1674
1974
  }), null);
1675
1975
  _$effect((_p$) => {
1676
- var _v$13 = {
1976
+ var _v$15 = {
1677
1977
  fg: pal().muted
1678
- }, _v$14 = {
1978
+ }, _v$16 = {
1679
1979
  fg: pal().primary
1680
1980
  };
1681
- _v$13 !== _p$.e && (_p$.e = _$setProp(_el$3, "style", _v$13, _p$.e));
1682
- _v$14 !== _p$.t && (_p$.t = _$setProp(_el$4, "style", _v$14, _p$.t));
1981
+ _v$15 !== _p$.e && (_p$.e = _$setProp(_el$3, "style", _v$15, _p$.e));
1982
+ _v$16 !== _p$.t && (_p$.t = _$setProp(_el$4, "style", _v$16, _p$.t));
1683
1983
  return _p$;
1684
1984
  }, {
1685
1985
  e: void 0,
@@ -1688,6 +1988,233 @@ function TokenCachePanel(props) {
1688
1988
  return _el$;
1689
1989
  })();
1690
1990
  }
1991
+ function BottomStatusBar(props) {
1992
+ const KV_PREFIX = "cache_panel";
1993
+ const t = createT(() => props.signals.langCode());
1994
+ const sid = props.sessionId;
1995
+ const stats = createMemo(() => {
1996
+ const id = sid;
1997
+ if (!id) return null;
1998
+ const msgs = props.api.state.session.messages(id);
1999
+ const session = typeof props.api.state.session.get === "function" ? props.api.state.session.get(id) : void 0;
2000
+ let input = session?.tokens?.input ?? 0;
2001
+ let read = session?.tokens?.cache?.read ?? 0;
2002
+ let write = session?.tokens?.cache?.write ?? 0;
2003
+ if (session?.tokens == null) {
2004
+ for (const m of msgs) {
2005
+ if (m.role !== "assistant") continue;
2006
+ const tk = m.tokens;
2007
+ if (!tk) continue;
2008
+ input += num(tk.input);
2009
+ read += num(tk.cache?.read);
2010
+ write += num(tk.cache?.write);
2011
+ }
2012
+ }
2013
+ let hitRate = -1, prevHitRate = -1;
2014
+ for (let i = msgs.length - 1; i >= 0; i--) {
2015
+ const m = msgs[i];
2016
+ if (m.role !== "assistant") continue;
2017
+ const tk = m.tokens;
2018
+ if (!tk) continue;
2019
+ const mit = num(tk.input) + num(tk.cache?.read) + num(tk.cache?.write);
2020
+ const mrt = num(tk.cache?.read);
2021
+ if (mit <= 0) continue;
2022
+ const rate = mrt / mit * 100;
2023
+ if (hitRate < 0) {
2024
+ hitRate = rate;
2025
+ continue;
2026
+ }
2027
+ prevHitRate = rate;
2028
+ break;
2029
+ }
2030
+ return {
2031
+ hitRate,
2032
+ prevHitRate,
2033
+ input,
2034
+ read,
2035
+ write
2036
+ };
2037
+ });
2038
+ createEffect(() => {
2039
+ if (!props.signals.autoBalance()) return;
2040
+ const id = sid;
2041
+ if (!id) return;
2042
+ const msgs = props.api.state.session.messages(id);
2043
+ let pid = "";
2044
+ for (let i = msgs.length - 1; i >= 0; i--) {
2045
+ const m = msgs[i];
2046
+ if (m.role === "assistant" && m.providerID) {
2047
+ pid = m.providerID;
2048
+ break;
2049
+ }
2050
+ }
2051
+ if (!pid) {
2052
+ try {
2053
+ pid = props.api.state.session.get(id)?.model?.providerID ?? "";
2054
+ } catch {
2055
+ }
2056
+ }
2057
+ if (!pid) return;
2058
+ const hit = matchBalanceProvider(pid);
2059
+ if (hit) {
2060
+ props.signals.setBalanceUnsupported(false);
2061
+ if (hit.id !== props.signals.balanceProviderId()) {
2062
+ props.signals.setBalanceProviderId(hit.id);
2063
+ props.signals.setBalanceRefresh(props.signals.balanceRefresh() + 1);
2064
+ }
2065
+ } else {
2066
+ props.signals.setBalanceUnsupported(true);
2067
+ }
2068
+ });
2069
+ const pal = createMemo(() => {
2070
+ const th = props.api.theme.current;
2071
+ const sat = (k, fb) => desaturateTo(th[k], MAX_SAT, fb);
2072
+ return {
2073
+ text: sat("text", FALLBACK.text),
2074
+ muted: sat("textMuted", FALLBACK.muted),
2075
+ success: sat("success", FALLBACK.success),
2076
+ warning: sat("warning", FALLBACK.warning),
2077
+ error: sat("error", FALLBACK.error)
2078
+ };
2079
+ });
2080
+ const hitColor = createMemo(() => {
2081
+ const r = stats()?.hitRate ?? -1;
2082
+ if (r >= 85) return pal().success;
2083
+ if (r >= 70) return pal().warning;
2084
+ return pal().error;
2085
+ });
2086
+ const trend = createMemo(() => {
2087
+ const s = stats();
2088
+ if (!s || s.prevHitRate < 0 || s.hitRate < 0) return null;
2089
+ const d = s.hitRate - s.prevHitRate;
2090
+ return Math.abs(d) < 0.05 ? null : d;
2091
+ });
2092
+ const balanceText = createMemo(() => {
2093
+ const s = props.signals.balanceState();
2094
+ if (s.status === "ok" && s.data) return formatBalanceText(s.data, props.signals.balanceCurrency(), props.signals.exchangeRate());
2095
+ if (s.status === "loading") return "\u2026";
2096
+ if (s.status === "error") return "\u26A0";
2097
+ return "-";
2098
+ });
2099
+ const directory = createMemo(() => {
2100
+ try {
2101
+ return props.api.state.path.directory;
2102
+ } catch {
2103
+ return "";
2104
+ }
2105
+ });
2106
+ onMount(() => {
2107
+ try {
2108
+ const v = props.api.kv.get(`${KV_PREFIX}.section.bottom`, true);
2109
+ props.signals.setSectionBottom(v !== false);
2110
+ } catch {
2111
+ }
2112
+ });
2113
+ return _$createComponent(Show, {
2114
+ get when() {
2115
+ return props.signals.sectionBottom();
2116
+ },
2117
+ get fallback() {
2118
+ 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;
2123
+ })();
2124
+ },
2125
+ 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;
2151
+ },
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
2157
+ }, _$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;
2215
+ }
2216
+ });
2217
+ }
1691
2218
  function createSidebarSlot(api, signals) {
1692
2219
  let lastSlotSid = "";
1693
2220
  return {
@@ -1723,20 +2250,28 @@ var tui = async (api) => {
1723
2250
  const [sectionDist, setSectionDist] = createSignal(true);
1724
2251
  const [sectionSkills, setSectionSkills] = createSignal(true);
1725
2252
  const [sectionBalance, setSectionBalance] = createSignal(true);
2253
+ const [sectionBottom, setSectionBottom] = createSignal(true);
1726
2254
  const [balanceRefresh, setBalanceRefresh] = createSignal(0);
1727
2255
  const [balanceProviderId, setBalanceProviderId] = createSignal("deepseek");
1728
2256
  const [autoBalance, setAutoBalance] = createSignal(true);
2257
+ const [balanceUnsupported, setBalanceUnsupported] = createSignal(false);
1729
2258
  const [balanceCurrency, setBalanceCurrency] = createSignal("");
1730
2259
  const [borderVisible, setBorderVisible] = createSignal(true);
1731
- const [langZH, setLangZH] = createSignal(LANG_ZH);
2260
+ const [langCode, setLangCode] = createSignal(INIT_LANG);
1732
2261
  const [overrideSessionId, setOverrideSessionId] = createSignal(void 0);
2262
+ const [balanceState, setBalanceState] = createSignal({
2263
+ status: "idle",
2264
+ data: null,
2265
+ lastFetch: 0
2266
+ });
2267
+ let balanceSeq = 0;
1733
2268
  const signals = {
1734
2269
  currencySymbol,
1735
2270
  setCurrencySymbol,
1736
2271
  exchangeRate,
1737
2272
  setExchangeRate,
1738
- langZH,
1739
- setLangZH,
2273
+ langCode,
2274
+ setLangCode,
1740
2275
  sectionDetail,
1741
2276
  setSectionDetail,
1742
2277
  sectionModel,
@@ -1747,12 +2282,17 @@ var tui = async (api) => {
1747
2282
  setSectionSkills,
1748
2283
  sectionBalance,
1749
2284
  setSectionBalance,
2285
+ sectionBottom,
2286
+ setSectionBottom,
1750
2287
  balanceRefresh,
1751
2288
  setBalanceRefresh,
1752
2289
  balanceProviderId,
1753
2290
  setBalanceProviderId,
1754
2291
  autoBalance,
1755
2292
  setAutoBalance,
2293
+ balanceUnsupported,
2294
+ setBalanceUnsupported,
2295
+ balanceState,
1756
2296
  balanceCurrency,
1757
2297
  setBalanceCurrency,
1758
2298
  borderVisible,
@@ -1761,16 +2301,139 @@ var tui = async (api) => {
1761
2301
  setOverrideSessionId
1762
2302
  };
1763
2303
  api.slots.register(createSidebarSlot(api, signals));
2304
+ api.slots.register({
2305
+ order: 55,
2306
+ slots: {
2307
+ session_prompt(_ctx, input) {
2308
+ return _$createComponent(api.ui.Prompt, {
2309
+ get sessionID() {
2310
+ return input.session_id;
2311
+ },
2312
+ get visible() {
2313
+ return input.visible;
2314
+ },
2315
+ get disabled() {
2316
+ return input.disabled;
2317
+ },
2318
+ get onSubmit() {
2319
+ return input.on_submit;
2320
+ },
2321
+ ref(r$) {
2322
+ var _ref$2 = input.ref;
2323
+ typeof _ref$2 === "function" ? _ref$2(r$) : input.ref = r$;
2324
+ },
2325
+ get hint() {
2326
+ return _$createComponent(BottomStatusBar, {
2327
+ api,
2328
+ signals,
2329
+ get sessionId() {
2330
+ return input.session_id;
2331
+ }
2332
+ });
2333
+ }
2334
+ });
2335
+ }
2336
+ }
2337
+ });
1764
2338
  const KV_PREFIX = "cache_panel";
2339
+ const restoreLang = () => {
2340
+ try {
2341
+ const saved = api.kv.get(`${KV_PREFIX}.lang`);
2342
+ if (saved && LANG_META.some((m) => m.code === saved)) setLangCode(saved);
2343
+ } catch {
2344
+ }
2345
+ };
2346
+ if (api.kv.ready) {
2347
+ restoreLang();
2348
+ } else {
2349
+ const langTimer = setInterval(() => {
2350
+ if (api.kv.ready) {
2351
+ clearInterval(langTimer);
2352
+ restoreLang();
2353
+ }
2354
+ }, 10);
2355
+ api.lifecycle.onDispose(() => clearInterval(langTimer));
2356
+ }
2357
+ const pollBalance = async () => {
2358
+ const provider = getBalanceProvider(balanceProviderId());
2359
+ const key = api.kv.get(`${KV_PREFIX}.balance.${provider.id}.key`, "") || findOpencodeKey(api, provider);
2360
+ if (balanceUnsupported()) {
2361
+ setBalanceState({
2362
+ status: "idle",
2363
+ data: null,
2364
+ lastFetch: 0,
2365
+ error: void 0,
2366
+ key: void 0
2367
+ });
2368
+ return;
2369
+ }
2370
+ if (!key) {
2371
+ setBalanceState({
2372
+ status: "idle",
2373
+ data: null,
2374
+ lastFetch: 0,
2375
+ error: void 0,
2376
+ key: void 0
2377
+ });
2378
+ return;
2379
+ }
2380
+ const now = Date.now();
2381
+ const prev = balanceState();
2382
+ if (prev.status === "ok" && prev.key === key && now - prev.lastFetch < BALANCE_POLL_MS) return;
2383
+ const seq = ++balanceSeq;
2384
+ setBalanceState({
2385
+ ...prev,
2386
+ status: "loading",
2387
+ error: void 0,
2388
+ key
2389
+ });
2390
+ const controller = new AbortController();
2391
+ let timedOut = false;
2392
+ const timer = setTimeout(() => {
2393
+ timedOut = true;
2394
+ controller.abort();
2395
+ }, 1e4);
2396
+ try {
2397
+ const data = await provider.fetchBalance(key, controller.signal);
2398
+ clearTimeout(timer);
2399
+ if (seq !== balanceSeq) return;
2400
+ setBalanceState({
2401
+ status: "ok",
2402
+ data,
2403
+ lastFetch: Date.now(),
2404
+ error: void 0,
2405
+ key
2406
+ });
2407
+ } catch (err) {
2408
+ clearTimeout(timer);
2409
+ if (seq !== balanceSeq) return;
2410
+ const code = timedOut ? "TIMEOUT" : err instanceof Error ? err.message : "";
2411
+ setBalanceState({
2412
+ status: "error",
2413
+ data: null,
2414
+ lastFetch: 0,
2415
+ error: code,
2416
+ key
2417
+ });
2418
+ }
2419
+ };
2420
+ createEffect(() => {
2421
+ void balanceRefresh();
2422
+ untrack(() => {
2423
+ void pollBalance();
2424
+ });
2425
+ });
2426
+ const balanceTimer = setInterval(pollBalance, BALANCE_POLL_MS);
2427
+ api.lifecycle.onDispose(() => clearInterval(balanceTimer));
1765
2428
  const providerOptionTitle = (p, current) => {
1766
- const zh = langZH();
2429
+ const t = createT(() => langCode());
1767
2430
  const hasManual = !!api.kv.get(`${KV_PREFIX}.balance.${p.id}.key`, "");
1768
2431
  const hasAuto = !hasManual && !!findOpencodeKey(api, p);
1769
- const mark = hasManual ? zh ? "\uFF08\u7528\u6237 key\uFF09" : " (user key)" : hasAuto ? zh ? "\uFF08OpenCode\uFF09" : " (OpenCode)" : zh ? "\uFF08\u672A\u914D\u7F6E\uFF09" : " (not set)";
2432
+ const mark = hasManual ? t("keyUser") : hasAuto ? t("keyOpenCode") : t("keyNotSet");
1770
2433
  return p.name + mark + (current && p.id === current ? " *" : "");
1771
2434
  };
1772
2435
  const promptBalanceKey = (dialog, provider) => {
1773
- const zh = langZH();
2436
+ const t = createT(() => langCode());
1774
2437
  const current = api.kv.get(`${KV_PREFIX}.balance.${provider.id}.key`, "");
1775
2438
  const masked = maskKey(current);
1776
2439
  dialog?.replace(() => _$createComponent(api.ui.DialogPrompt, {
@@ -1778,9 +2441,11 @@ var tui = async (api) => {
1778
2441
  return provider.name;
1779
2442
  },
1780
2443
  description: () => (() => {
1781
- var _el$93 = _$createElement("text");
1782
- _$insert(_el$93, () => zh ? `\u8F93\u5165 ${provider.name} API Key \u4EE5\u663E\u793A\u8D26\u6237\u4F59\u989D\uFF08\u7559\u7A7A\u6E05\u9664\uFF09` : `Enter your ${provider.name} API key to show account balance (leave empty to clear)`);
1783
- return _el$93;
2444
+ var _el$112 = _$createElement("text");
2445
+ _$insert(_el$112, () => t("balKeyPrompt", {
2446
+ p: provider.name
2447
+ }));
2448
+ return _el$112;
1784
2449
  })(),
1785
2450
  get placeholder() {
1786
2451
  return provider.keyPlaceholder ?? "sk-...";
@@ -1800,11 +2465,11 @@ var tui = async (api) => {
1800
2465
  setBalanceRefresh((v) => v + 1);
1801
2466
  if (key) {
1802
2467
  api.ui.toast({
1803
- message: zh ? "API Key \u5DF2\u4FDD\u5B58\uFF0C\u6B63\u5728\u67E5\u8BE2\u4F59\u989D..." : "API Key saved, fetching balance..."
2468
+ message: t("keySaved")
1804
2469
  });
1805
2470
  } else {
1806
2471
  api.ui.toast({
1807
- message: zh ? "API Key \u5DF2\u6E05\u9664" : "API Key cleared"
2472
+ message: t("keyCleared")
1808
2473
  });
1809
2474
  }
1810
2475
  dialog?.clear();
@@ -1829,6 +2494,7 @@ var tui = async (api) => {
1829
2494
  }));
1830
2495
  },
1831
2496
  onSelect: (opt) => {
2497
+ const t = createT(() => langCode());
1832
2498
  const sym = CURRENCIES[opt.value] ?? "$";
1833
2499
  const defRate = DEFAULT_RATES[opt.value] ?? 1;
1834
2500
  api.kv.set(`${KV_PREFIX}.currency`, sym);
@@ -1838,7 +2504,11 @@ var tui = async (api) => {
1838
2504
  signals.setCurrencySymbol(sym);
1839
2505
  signals.setExchangeRate(defRate);
1840
2506
  api.ui.toast({
1841
- message: `Currency: ${opt.value} (${sym}), rate: ${defRate}`
2507
+ message: t("currencySet", {
2508
+ v: opt.value,
2509
+ s: sym,
2510
+ r: defRate
2511
+ })
1842
2512
  });
1843
2513
  dialog?.clear();
1844
2514
  }
@@ -1855,21 +2525,24 @@ var tui = async (api) => {
1855
2525
  dialog?.replace(() => _$createComponent(api.ui.DialogPrompt, {
1856
2526
  title: "Exchange Rate",
1857
2527
  description: () => (() => {
1858
- var _el$94 = _$createElement("text");
1859
- _$insertNode(_el$94, _$createTextNode(`Enter the exchange rate from USD to your currency (e.g. 7.2 for CNY)`));
1860
- return _el$94;
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;
1861
2531
  })(),
1862
2532
  placeholder: "1.0",
1863
2533
  get value() {
1864
2534
  return String(api.kv.get(`${KV_PREFIX}.rate`, 1));
1865
2535
  },
1866
2536
  onConfirm: (val) => {
2537
+ const t = createT(() => langCode());
1867
2538
  const n = parseFloat(val);
1868
2539
  if (n > 0) {
1869
2540
  api.kv.set(`${KV_PREFIX}.rate`, n);
1870
2541
  signals.setExchangeRate(n);
1871
2542
  api.ui.toast({
1872
- message: `Exchange rate set to ${n}`
2543
+ message: t("rateSet", {
2544
+ r: n
2545
+ })
1873
2546
  });
1874
2547
  }
1875
2548
  dialog?.clear();
@@ -1884,40 +2557,59 @@ var tui = async (api) => {
1884
2557
  name: "cache-section"
1885
2558
  },
1886
2559
  onSelect: (dialog) => {
2560
+ const t = createT(() => langCode());
1887
2561
  const detailOn = Boolean(api.kv.get(`${KV_PREFIX}.section.detail`, true));
1888
2562
  const modelOn = Boolean(api.kv.get(`${KV_PREFIX}.section.model`, true));
1889
2563
  const distOn = Boolean(api.kv.get(`${KV_PREFIX}.section.dist`, true));
1890
2564
  const skillsOn = Boolean(api.kv.get(`${KV_PREFIX}.section.skills`, true));
1891
2565
  const balanceOn = Boolean(api.kv.get(`${KV_PREFIX}.section.balance`, true));
2566
+ const bottomOn = Boolean(api.kv.get(`${KV_PREFIX}.section.bottom`, true));
1892
2567
  const borderOn = Boolean(api.kv.get(`${KV_PREFIX}.border`, true));
2568
+ const labels = {
2569
+ detail: t("secDetail"),
2570
+ model: t("secModel"),
2571
+ dist: t("distTitle"),
2572
+ skills: t("secSkills"),
2573
+ balance: t("secBalance"),
2574
+ bottom: t("secBottom"),
2575
+ border: t("secBorder")
2576
+ };
2577
+ const optTitle = (label, on) => `${visualPadEnd(label, 15)}[${on ? "ON" : "OFF"}]`;
1893
2578
  dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
1894
- title: "Toggle Section",
1895
- options: [{
1896
- title: `Token Detail [${detailOn ? "ON" : "OFF"}]`,
1897
- value: "detail"
1898
- }, {
1899
- title: `Model & Pricing [${modelOn ? "ON" : "OFF"}]`,
1900
- value: "model"
1901
- }, {
1902
- title: `Token Dist. [${distOn ? "ON" : "OFF"}]`,
1903
- value: "dist"
1904
- }, {
1905
- title: `Loaded Skills [${skillsOn ? "ON" : "OFF"}]`,
1906
- value: "skills"
1907
- }, {
1908
- title: `Balance [${balanceOn ? "ON" : "OFF"}]`,
1909
- value: "balance"
1910
- }, {
1911
- title: `Panel Border [${borderOn ? "ON" : "OFF"}]`,
1912
- value: "border"
1913
- }],
2579
+ get title() {
2580
+ return t("secToggle");
2581
+ },
2582
+ get options() {
2583
+ return [{
2584
+ title: optTitle(labels.detail, detailOn),
2585
+ value: "detail"
2586
+ }, {
2587
+ title: optTitle(labels.model, modelOn),
2588
+ value: "model"
2589
+ }, {
2590
+ title: optTitle(labels.dist, distOn),
2591
+ value: "dist"
2592
+ }, {
2593
+ title: optTitle(labels.skills, skillsOn),
2594
+ value: "skills"
2595
+ }, {
2596
+ title: optTitle(labels.balance, balanceOn),
2597
+ value: "balance"
2598
+ }, {
2599
+ title: optTitle(labels.bottom, bottomOn),
2600
+ value: "bottom"
2601
+ }, {
2602
+ title: optTitle(labels.border, borderOn),
2603
+ value: "border"
2604
+ }];
2605
+ },
1914
2606
  onSelect: (opt) => {
1915
2607
  if (opt.value === "border") {
1916
2608
  const cur = Boolean(api.kv.get(`${KV_PREFIX}.border`, true));
1917
2609
  api.kv.set(`${KV_PREFIX}.border`, !cur);
1918
2610
  signals.setBorderVisible(!cur);
1919
2611
  api.ui.toast({
1920
- message: `Panel border ${!cur ? "shown" : "hidden"}`
2612
+ message: !cur ? t("borderShown") : t("borderHidden")
1921
2613
  });
1922
2614
  } else {
1923
2615
  const key = `${KV_PREFIX}.section.${opt.value}`;
@@ -1928,8 +2620,12 @@ var tui = async (api) => {
1928
2620
  if (opt.value === "dist") signals.setSectionDist(!cur);
1929
2621
  if (opt.value === "skills") signals.setSectionSkills(!cur);
1930
2622
  if (opt.value === "balance") signals.setSectionBalance(!cur);
2623
+ if (opt.value === "bottom") signals.setSectionBottom(!cur);
2624
+ const name = labels[opt.value] ?? opt.value;
1931
2625
  api.ui.toast({
1932
- message: `${opt.value} section ${!cur ? "shown" : "hidden"}`
2626
+ message: t(!cur ? "sectionShown" : "sectionHidden", {
2627
+ s: name
2628
+ })
1933
2629
  });
1934
2630
  }
1935
2631
  dialog?.clear();
@@ -1944,6 +2640,7 @@ var tui = async (api) => {
1944
2640
  name: "cache-config"
1945
2641
  },
1946
2642
  onSelect: (dialog) => {
2643
+ const t = createT(() => langCode());
1947
2644
  const sym = api.kv.get(`${KV_PREFIX}.currency`) ?? "$";
1948
2645
  const rate = api.kv.get(`${KV_PREFIX}.rate`) ?? 1;
1949
2646
  const detail = Boolean(api.kv.get(`${KV_PREFIX}.section.detail`, true));
@@ -1951,9 +2648,20 @@ var tui = async (api) => {
1951
2648
  const dist = Boolean(api.kv.get(`${KV_PREFIX}.section.dist`, true));
1952
2649
  const skills = Boolean(api.kv.get(`${KV_PREFIX}.section.skills`, true));
1953
2650
  const balance = Boolean(api.kv.get(`${KV_PREFIX}.section.balance`, true));
2651
+ const bottom = Boolean(api.kv.get(`${KV_PREFIX}.section.bottom`, true));
2652
+ const on = (v) => v ? "ON" : "OFF";
1954
2653
  api.ui.toast({
1955
- title: "Cache Panel Config",
1956
- message: `Currency: ${sym} | Rate: ${rate} | Detail: ${detail ? "ON" : "OFF"} | Model: ${model ? "ON" : "OFF"} | Dist: ${dist ? "ON" : "OFF"} | Skills: ${skills ? "ON" : "OFF"} | Balance: ${balance ? "ON" : "OFF"}`,
2654
+ title: t("panelConfigTitle"),
2655
+ message: t("panelConfigMsg", {
2656
+ c: sym,
2657
+ r: rate,
2658
+ d: on(detail),
2659
+ m: on(model),
2660
+ t: on(dist),
2661
+ k: on(skills),
2662
+ b: on(balance),
2663
+ f: on(bottom)
2664
+ }),
1957
2665
  duration: 8e3
1958
2666
  });
1959
2667
  dialog?.clear();
@@ -1966,22 +2674,24 @@ var tui = async (api) => {
1966
2674
  name: "cache-lang"
1967
2675
  },
1968
2676
  onSelect: (dialog) => {
1969
- const cur = langZH();
2677
+ const t = createT(() => langCode());
2678
+ const cur = langCode();
1970
2679
  dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
1971
- title: "Display Language",
1972
- options: [{
1973
- title: `\u4E2D\u6587 ${cur ? "\u2713" : ""}`,
1974
- value: "zh"
1975
- }, {
1976
- title: `English ${cur ? "" : "\u2713"}`,
1977
- value: "en"
1978
- }],
2680
+ get title() {
2681
+ return t("langTitle");
2682
+ },
2683
+ get options() {
2684
+ return LANG_META.map((m) => ({
2685
+ title: `${visualPadEnd(m.label, 9)}${cur === m.code ? "\u2713" : ""}`,
2686
+ value: m.code
2687
+ }));
2688
+ },
1979
2689
  onSelect: (opt) => {
1980
- const zh = opt.value === "zh";
1981
- api.kv.set(`${KV_PREFIX}.lang`, opt.value);
1982
- setLangZH(zh);
2690
+ const code = opt.value;
2691
+ api.kv.set(`${KV_PREFIX}.lang`, code);
2692
+ setLangCode(code);
1983
2693
  api.ui.toast({
1984
- message: zh ? "\u8BED\u8A00\u5DF2\u5207\u6362\u4E3A\u4E2D\u6587" : "Switched to English"
2694
+ message: t("langSwitched")
1985
2695
  });
1986
2696
  dialog?.clear();
1987
2697
  }
@@ -1995,12 +2705,14 @@ var tui = async (api) => {
1995
2705
  name: "cache-balance"
1996
2706
  },
1997
2707
  onSelect: (dialog) => {
1998
- const zh = langZH();
2708
+ const t = createT(() => langCode());
1999
2709
  const current = signals.balanceProviderId();
2000
2710
  const auto = signals.autoBalance();
2001
- const autoLabel = auto ? zh ? "\u81EA\u52A8\u5207\u6362\u63D0\u4F9B\u5546 [\u5F00]" : "Auto-switch provider [ON]" : zh ? "\u81EA\u52A8\u5207\u6362\u63D0\u4F9B\u5546 [\u5173]" : "Auto-switch provider [OFF]";
2711
+ const autoLabel = `${t("autoSwitchOpt")} [${auto ? "ON" : "OFF"}]`;
2002
2712
  dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2003
- title: zh ? "\u4F59\u989D\u63D0\u4F9B\u5546 / \u81EA\u52A8\u5207\u6362" : "Balance Provider / Auto-switch",
2713
+ get title() {
2714
+ return t("balProvTitle");
2715
+ },
2004
2716
  get options() {
2005
2717
  return [{
2006
2718
  title: autoLabel,
@@ -2016,7 +2728,7 @@ var tui = async (api) => {
2016
2728
  api.kv.set(`${KV_PREFIX}.balance.auto`, next);
2017
2729
  signals.setAutoBalance(next);
2018
2730
  api.ui.toast({
2019
- message: zh ? `\u81EA\u52A8\u5207\u6362\u4F59\u989D\u63D0\u4F9B\u5546: ${next ? "\u5F00" : "\u5173"}` : `Auto-switch balance provider: ${next ? "ON" : "OFF"}`
2731
+ message: next ? t("autoSwitchOn") : t("autoSwitchOff")
2020
2732
  });
2021
2733
  dialog?.clear();
2022
2734
  } else {
@@ -2025,13 +2737,16 @@ var tui = async (api) => {
2025
2737
  api.kv.set(`${KV_PREFIX}.balance.auto`, false);
2026
2738
  signals.setBalanceProviderId(provider.id);
2027
2739
  signals.setAutoBalance(false);
2740
+ signals.setBalanceUnsupported(false);
2028
2741
  signals.setBalanceRefresh(signals.balanceRefresh() + 1);
2029
2742
  const hasKey = !!api.kv.get(`${KV_PREFIX}.balance.${provider.id}.key`, "");
2030
2743
  if (!hasKey) {
2031
2744
  promptBalanceKey(dialog, provider);
2032
2745
  } else {
2033
2746
  api.ui.toast({
2034
- message: zh ? `\u4F59\u989D\u63D0\u4F9B\u5546: ${provider.name}\uFF08\u81EA\u52A8\u5207\u6362\u5DF2\u5173\u95ED\uFF09` : `Balance provider: ${provider.name} (auto-switch off)`
2747
+ message: t("providerManual", {
2748
+ p: provider.name
2749
+ })
2035
2750
  });
2036
2751
  dialog?.clear();
2037
2752
  }
@@ -2047,9 +2762,11 @@ var tui = async (api) => {
2047
2762
  name: "cache-balance-key"
2048
2763
  },
2049
2764
  onSelect: (dialog) => {
2050
- const zh = langZH();
2765
+ const t = createT(() => langCode());
2051
2766
  dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2052
- title: zh ? "\u9009\u62E9\u4F59\u989D\u63D0\u4F9B\u5546" : "Select Balance Provider",
2767
+ get title() {
2768
+ return t("balSelectTitle");
2769
+ },
2053
2770
  get options() {
2054
2771
  return balanceProviders.map((p) => ({
2055
2772
  title: providerOptionTitle(p),
@@ -2075,10 +2792,11 @@ var tui = async (api) => {
2075
2792
  name: "cache-debug-skills"
2076
2793
  },
2077
2794
  onSelect: () => {
2795
+ const t = createT(() => langCode());
2078
2796
  const rt = api.route.current;
2079
2797
  if (rt.name !== "session" || !rt.params) {
2080
2798
  api.ui.toast({
2081
- message: "Please run this command inside a session",
2799
+ message: t("runInSession"),
2082
2800
  variant: "warning"
2083
2801
  });
2084
2802
  return;
@@ -2096,9 +2814,9 @@ var tui = async (api) => {
2096
2814
  }
2097
2815
  for (const p of parts) {
2098
2816
  if (p.type === "tool") {
2099
- const t = String(p.tool ?? "?");
2100
- byTool[t] = (byTool[t] ?? 0) + 1;
2101
- if (t === "skill") {
2817
+ const t2 = String(p.tool ?? "?");
2818
+ byTool[t2] = (byTool[t2] ?? 0) + 1;
2819
+ if (t2 === "skill") {
2102
2820
  const meta = p.state?.metadata;
2103
2821
  const rootMeta = p.metadata;
2104
2822
  skillParts.push(`state.metadata=${JSON.stringify(meta)} | root.metadata=${JSON.stringify(rootMeta)} | state.title="${p.state?.title}" | state.output[:80]="${String(p.state?.output ?? "").slice(0, 80)}"`);
@@ -2167,7 +2885,7 @@ var tui = async (api) => {
2167
2885
  return true;
2168
2886
  });
2169
2887
  if (unique.length > 0) {
2170
- const zh = langZH();
2888
+ const t = createT(() => langCode());
2171
2889
  const currentSid = signals.overrideSessionId() ?? api.kv.get(`${KV_PREFIX}.session`, "");
2172
2890
  const options = unique.map((c, i) => ({
2173
2891
  title: `${i + 1}. ${c.title}`,
@@ -2175,7 +2893,7 @@ var tui = async (api) => {
2175
2893
  description: c.description
2176
2894
  }));
2177
2895
  const backValue = "__main__";
2178
- const backTitle = `\u2500 ${zh ? "\u56DE\u5230\u4E3B\u4F1A\u8BDD" : "Back to Main"}`;
2896
+ const backTitle = `\u2500 ${t("backToMainTitle")}`;
2179
2897
  options.unshift({
2180
2898
  title: backTitle,
2181
2899
  value: backValue,
@@ -2188,7 +2906,9 @@ var tui = async (api) => {
2188
2906
  });
2189
2907
  const currentIdx = currentSid ? options.findIndex((o) => o.value === currentSid) : -1;
2190
2908
  dialog?.replace(() => _$createComponent(api.ui.DialogSelect, {
2191
- title: zh ? "\u9009\u62E9\u5B50\u4EE3\u7406" : "Select Sub-Agent",
2909
+ get title() {
2910
+ return t("subSelectTitle");
2911
+ },
2192
2912
  options,
2193
2913
  get current() {
2194
2914
  return currentIdx >= 0 ? options[currentIdx].value : void 0;
@@ -2198,28 +2918,30 @@ var tui = async (api) => {
2198
2918
  signals.setOverrideSessionId(void 0);
2199
2919
  api.kv.set(`${KV_PREFIX}.session`, "");
2200
2920
  api.ui.toast({
2201
- message: zh ? "\u5DF2\u5207\u56DE\u4E3B\u4F1A\u8BDD" : "Switched to main session"
2921
+ message: t("backToMain")
2202
2922
  });
2203
2923
  } else {
2204
2924
  signals.setOverrideSessionId(opt.value);
2205
2925
  api.kv.set(`${KV_PREFIX}.session`, opt.value);
2206
2926
  api.ui.toast({
2207
- message: (zh ? "\u5DF2\u5207\u6362\u81F3\u5B50\u4EE3\u7406: " : "Showing sub-agent: ") + opt.value.slice(0, 24) + "\u2026"
2927
+ message: t("subAgentSwitched", {
2928
+ s: opt.value.slice(0, 24) + "\u2026"
2929
+ })
2208
2930
  });
2209
2931
  }
2210
2932
  dialog?.clear();
2211
2933
  }
2212
2934
  }));
2213
2935
  } else {
2214
- const zh = langZH();
2936
+ const t = createT(() => langCode());
2215
2937
  dialog?.replace(() => _$createComponent(api.ui.DialogPrompt, {
2216
2938
  get title() {
2217
- return signals.overrideSessionId() ? zh ? "\u5207\u6362\u5B50\u4EE3\u7406" : "Switch Sub" : zh ? "\u67E5\u770B\u5B50\u4EE3\u7406\u7F13\u5B58" : "View Sub Cache";
2939
+ return _$memo(() => !!signals.overrideSessionId())() ? t("subSwitchTitle") : t("subViewTitle");
2218
2940
  },
2219
2941
  description: () => (() => {
2220
- var _el$96 = _$createElement("text");
2221
- _$insert(_el$96, zh ? "\u672A\u627E\u5230\u5B50\u4EE3\u7406\uFF0C\u8BF7\u624B\u52A8\u7C98\u8D34 Session ID" : "No sub-agents found. Paste a Session ID manually");
2222
- return _el$96;
2942
+ var _el$115 = _$createElement("text");
2943
+ _$insert(_el$115, () => t("subNoFound"));
2944
+ return _el$115;
2223
2945
  })(),
2224
2946
  placeholder: "ses_...",
2225
2947
  get value() {
@@ -2231,7 +2953,9 @@ var tui = async (api) => {
2231
2953
  signals.setOverrideSessionId(sid);
2232
2954
  api.kv.set(`${KV_PREFIX}.session`, sid);
2233
2955
  api.ui.toast({
2234
- message: (langZH() ? "\u5DF2\u5207\u6362\u81F3\u5B50\u4EE3\u7406: " : "Showing sub-agent: ") + sid.slice(0, 24) + "\u2026"
2956
+ message: t("subAgentSwitched", {
2957
+ s: sid.slice(0, 24) + "\u2026"
2958
+ })
2235
2959
  });
2236
2960
  }
2237
2961
  dialog?.clear();
@@ -2248,10 +2972,11 @@ var tui = async (api) => {
2248
2972
  name: "cache-session-back"
2249
2973
  },
2250
2974
  onSelect: (dialog) => {
2975
+ const t = createT(() => langCode());
2251
2976
  signals.setOverrideSessionId(void 0);
2252
2977
  api.kv.set(`${KV_PREFIX}.session`, "");
2253
2978
  api.ui.toast({
2254
- message: langZH() ? "\u5DF2\u5207\u56DE\u4E3B\u4F1A\u8BDD" : "Switched to main session"
2979
+ message: t("backToMain")
2255
2980
  });
2256
2981
  dialog?.clear();
2257
2982
  }