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/README.md +12 -6
- package/README_EN.md +13 -5
- package/dist/_version.d.ts +1 -1
- package/dist/_version.js +1 -1
- package/dist/i18n.d.ts +102 -0
- package/dist/i18n.js +368 -0
- package/dist/index.js +461 -260
- package/dist/tui.js +1203 -478
- package/package.json +6 -3
- package/src/_version.ts +1 -1
- package/src/i18n.ts +380 -0
- package/src/index.tsx +547 -315
package/README.md
CHANGED
|
@@ -46,14 +46,15 @@
|
|
|
46
46
|
- **模型定价**:显示当前模型的输入 / 缓存读 / 缓存写单价(从 provider 配置动态读取)
|
|
47
47
|
- **折叠面板**:主标题默认折叠,点击展开;明细、模型、分布各自独立折叠
|
|
48
48
|
- **颜色自适应**:命中率 ≥85% 绿 · ≥70% 橙 · <70% 红,颜色从主题色自动去饱和
|
|
49
|
-
- **Token 分布**:按角色(系统提示 / 用户 /
|
|
49
|
+
- **Token 分布**:按角色(系统提示 / 用户 / 子代理指令 / Tool 调用 / Tool 结果)展示估算 Token 占比
|
|
50
50
|
- **折叠记忆**:折叠状态持久化,重启后保持
|
|
51
|
-
-
|
|
51
|
+
- **语言适配**:支持 中文 / English / 日本語 / 한국어,自动检测系统语言,`/cache-lang` 运行时切换,偏好持久化优先
|
|
52
52
|
- **多币种**:通过 `/cache-currency` 切换货币,费用和节省同步换算
|
|
53
53
|
- **余额查询**:查询多家 AI 提供商的账户余额,支持自动切换跟随当前会话提供商
|
|
54
54
|
- **斜杠命令**:`/cache-session` `/cache-session-back` `/cache-rate` `/cache-section` `/cache-config` `/cache-lang` 动态配置面板
|
|
55
55
|
- **子代理缓存查看**:`/cache-session` 自动扫描并列出子代理,选择一个即可切换面板显示其缓存统计,支持 `/cache-session-back` 返回主会话
|
|
56
56
|
- **已加载技能**:检测 session 中 LLM 调用 `skill` tool 的记录,展示已加载技能名及估算 Token 占用
|
|
57
|
+
- **底部状态栏**:输入框提示行单行显示 命中率(含趋势)· Tokens · 余额,关闭侧边栏也能随时看到缓存统计,可经 `/cache-section` 隐藏
|
|
57
58
|
|
|
58
59
|
---
|
|
59
60
|
|
|
@@ -106,7 +107,7 @@ npm install -g opencode-visual-cache@latest
|
|
|
106
107
|
| `/cache-session-back` | 返回主会话统计 | 从子代理缓存视图切回主会话 |
|
|
107
108
|
| `/cache-currency` | 切换货币单位 | 从列表选择货币(USD / CNY / EUR / JPY / GBP / KRW),自动填入默认汇率 |
|
|
108
109
|
| `/cache-rate` | 调整汇率乘数 | 输入自定义汇率(如 `7.2`),用于费用换算 |
|
|
109
|
-
| `/cache-section` | 开关区块与边框 | 独立控制 Token 明细 / 模型与定价 / 估算 Token 分布 / 已加载技能 / 余额 / 面板边框的显隐 |
|
|
110
|
+
| `/cache-section` | 开关区块与边框 | 独立控制 Token 明细 / 模型与定价 / 估算 Token 分布 / 已加载技能 / 余额 / 底部状态栏 / 面板边框的显隐 |
|
|
110
111
|
| `/cache-config` | 查看当前配置 | 弹出当前货币、汇率、区块可见性状态 |
|
|
111
112
|
| `/cache-lang` | 切换显示语言 | 从列表选择中文或 English,界面即时切换,无需重启 |
|
|
112
113
|
| `/cache-balance` | 余额查询设置 | 选择余额提供商(菜单标注 Key 来源:用户 key / OpenCode / 未配置)/ 开关自动切换 |
|
|
@@ -145,10 +146,11 @@ npm install -g opencode-visual-cache@latest
|
|
|
145
146
|
- **估算 Token 分布**:按角色拆分的 Token 估算
|
|
146
147
|
- **已加载技能**:session 中 LLM 实际调用过的 Skill 名及估算 Token 占用
|
|
147
148
|
- **余额**:当前提供商账户余额(多提供商 + 自动切换)
|
|
149
|
+
- **底部状态栏**:输入框提示行的 命中率 · Tokens · 余额 单行统计
|
|
148
150
|
|
|
149
151
|
通过 `/cache-section` 切换后即时生效,无需重启。此外,该命令还可以开关面板的**外边框**——关闭后内容会顶格显示,释放额外空间。
|
|
150
152
|
|
|
151
|
-
> **关于 Token 分布数值**:分布面板中"
|
|
153
|
+
> **关于 Token 分布数值**:分布面板中"推理"为 API 返回的**精确值**;"系统提示"/"用户"/"子代理指令"/"Tool 调用"/"Tool 结果"为**估算值**——API 仅返回 token 总量,无法拆分各内容类型,插件按内容类型收集文本后基于字符计数近似估算,数值仅供参考。OpenCode 运行时注入的系统提示内容(环境信息、Skill 目录、工具 Schema 定义等,详见 [`system.ts`](https://github.com/anomalyco/opencode/blob/dev/packages/opencode/src/session/system.ts)、[`tools.ts`](https://github.com/anomalyco/opencode/blob/dev/packages/opencode/src/session/tools.ts))不在此估算范围内。
|
|
152
154
|
|
|
153
155
|
### 4.4 余额查询
|
|
154
156
|
|
|
@@ -172,6 +174,10 @@ npm install -g opencode-visual-cache@latest
|
|
|
172
174
|
> **自动切换**:默认开启;手动选择提供商后自动关闭,可在 `/cache-balance` 中重新开启。自动切换按当前会话的模型提供商匹配,未配置 Key 的提供商被选中时显示「未配置」提示。
|
|
173
175
|
>
|
|
174
176
|
> **希望支持**:已调研确认具备可行性的候选提供商,尚未实现。智谱 GLM 仅有社区逆向的非官方端点(无稳定性保障)。
|
|
177
|
+
>
|
|
178
|
+
> **统计口径**:命中率 = 缓存读 /(新鲜输入 + 缓存读 + 缓存写),与业界(OpenAI / Anthropic / Bedrock)口径一致;明细中「未命中」= 新鲜输入 + 缓存写。底部栏的 Tokens 为输入侧总量(不含输出)。未单独报告缓存写的提供商(如 DeepSeek)自动退化为 hit/miss 口径。
|
|
179
|
+
>
|
|
180
|
+
> **余额显示**:侧边栏与底部栏共享同一份余额数据,两处显示一致。当前提供商不支持余额查询时,侧边栏显示提示、底部栏隐藏余额项。
|
|
175
181
|
|
|
176
182
|
---
|
|
177
183
|
|
|
@@ -207,11 +213,11 @@ rm -rf ~/.cache/opencode/packages/opencode-visual-cache@latest
|
|
|
207
213
|
|
|
208
214
|
### 6.1 运行时切换(推荐)
|
|
209
215
|
|
|
210
|
-
在 TUI 中输入 `/cache-lang
|
|
216
|
+
在 TUI 中输入 `/cache-lang`,从弹窗选择 中文 / English / 日本語 / 한국어 即可即时切换,无需重启。偏好会自动持久化,下次启动优先恢复用户选择。
|
|
211
217
|
|
|
212
218
|
### 6.2 环境变量覆盖
|
|
213
219
|
|
|
214
|
-
启动前设置 `CACHE_TUI_LANG`
|
|
220
|
+
启动前设置 `CACHE_TUI_LANG` 环境变量可强制指定语言(`zh` / `en` / `ja` / `ko`):
|
|
215
221
|
|
|
216
222
|
```powershell
|
|
217
223
|
# Windows PowerShell
|
package/README_EN.md
CHANGED
|
@@ -46,14 +46,15 @@ Interested in sub-agent monitoring? Check out [opencode-subagent-magazine](https
|
|
|
46
46
|
- **Model Pricing**: Input / cache-read / cache-write per-million rates (read from provider config dynamically)
|
|
47
47
|
- **Collapsible**: Main title collapsed by default; click to expand. Detail, model, and distribution sections fold independently
|
|
48
48
|
- **Adaptive Colors**: ≥85% green · ≥70% orange · <70% red, auto-desaturated from current theme
|
|
49
|
-
- **Token Distribution**: Per-role (system / user / agent instr / tool call / tool result) estimated token breakdown
|
|
49
|
+
- **Token Distribution**: Per-role (system / user / sub-agent instr / tool call / tool result) estimated token breakdown
|
|
50
50
|
- **Persistent State**: Fold preferences and config remembered across restarts via api.kv
|
|
51
|
-
- **Language**:
|
|
51
|
+
- **Language**: Chinese / English / 日本語 / 한국어, auto-detects system locale, with `/cache-lang` for runtime switching — user preference takes priority over auto-detection
|
|
52
52
|
- **Multi-currency**: Switch via `/cache-currency` — costs, savings, and per-million rates convert in real time
|
|
53
53
|
- **Balance Query**: Query account balance across multiple AI providers, with auto-switch following the current session's provider
|
|
54
54
|
- **Slash Commands**: `/cache-session` `/cache-session-back` `/cache-rate` `/cache-section` `/cache-config` `/cache-lang` for live panel configuration
|
|
55
55
|
- **Sub-Agent Cache View**: `/cache-session` auto-scans and lists sub-agents; select one to switch the panel stats. Use `/cache-session-back` to return to the main session
|
|
56
56
|
- **Loaded Skills**: Detects `skill` tool calls in the session and displays loaded skill names with estimated token footprint
|
|
57
|
+
- **Bottom Status Bar**: single-line hit rate (with trend) · Tokens · Balance in the prompt hint row — visible even with the sidebar closed; hide it anytime via `/cache-section`
|
|
57
58
|
|
|
58
59
|
---
|
|
59
60
|
|
|
@@ -106,7 +107,7 @@ The plugin supports slash commands and command palette (`Ctrl + P`) for runtime
|
|
|
106
107
|
| `/cache-session-back` | Return to main session | Switch back to main session from sub-agent cache view |
|
|
107
108
|
| `/cache-currency` | Switch currency | Pick from a list (USD / CNY / EUR / JPY / GBP / KRW); default exchange rate auto-filled |
|
|
108
109
|
| `/cache-rate` | Adjust exchange rate | Enter a custom rate (e.g. `7.2` for CNY) |
|
|
109
|
-
| `/cache-section` | Toggle sections & border | Independently show/hide Detail, Model & Pricing, Token Distribution, Loaded Skills, Balance, or the panel border |
|
|
110
|
+
| `/cache-section` | Toggle sections & border | Independently show/hide Detail, Model & Pricing, Token Distribution, Loaded Skills, Balance, Bottom Bar, or the panel border |
|
|
110
111
|
| `/cache-config` | View current config | Displays currency, rate, and section visibility |
|
|
111
112
|
| `/cache-lang` | Switch display language | Pick Chinese or English from the dialog — takes effect immediately, no restart needed |
|
|
112
113
|
| `/cache-balance` | Balance query settings | Pick a balance provider (menu shows key source: user key / OpenCode / not set) / toggle auto-switch |
|
|
@@ -145,9 +146,12 @@ Three sub-sections can be toggled independently to save sidebar space:
|
|
|
145
146
|
- **Estimated Token Dist.**: per-role token breakdown
|
|
146
147
|
- **Loaded Skills**: skill names the LLM actually loaded via the `skill` tool, with estimated token counts
|
|
147
148
|
- **Balance**: the selected provider's account balance (multi-provider with auto-switch)
|
|
149
|
+
- **Bottom Status Bar**: the single-line hit rate · Tokens · Balance stats in the prompt hint row
|
|
148
150
|
|
|
149
151
|
Toggled via `/cache-section` — takes effect instantly, no restart required. The same command also toggles the panel **border**; turning it off removes the outline and padding so content fills the full width.
|
|
150
152
|
|
|
153
|
+
> **About Token Dist. values**: "Reasoning" is an exact value from the API; the other rows (system / user / sub-agent instr / tool call / tool result) are **estimates** — the API only reports total token counts, not how they split across content types, so the plugin collects text per content type and approximates via character counting. Values are indicative only. OpenCode runtime-injected system prompt content (environment info, skill catalog, tool schema definitions — see [`system.ts`](https://github.com/anomalyco/opencode/blob/dev/packages/opencode/src/session/system.ts), [`tools.ts`](https://github.com/anomalyco/opencode/blob/dev/packages/opencode/src/session/tools.ts)) is not covered by these estimates.
|
|
154
|
+
|
|
151
155
|
### 4.4 Balance Query
|
|
152
156
|
|
|
153
157
|
The panel can display account balance from multiple AI providers. With **auto-switch** enabled, the balance query follows the model provider of the current session automatically.
|
|
@@ -170,6 +174,10 @@ Supported balance providers:
|
|
|
170
174
|
> **Auto-switch**: enabled by default; picking a provider manually disables it — re-enable anytime via `/cache-balance`. Auto-switch matches the current session's model provider; a provider without a key shows a "not set" hint when selected.
|
|
171
175
|
>
|
|
172
176
|
> **Planned**: candidates confirmed feasible by research, not yet implemented. Zhipu GLM only has a community-reversed unofficial endpoint (no stability guarantee).
|
|
177
|
+
>
|
|
178
|
+
> **Metric semantics**: hit rate = cache read / (fresh input + cache read + cache write), consistent with the industry (OpenAI / Anthropic / Bedrock). "Miss" in the detail view = fresh input + cache write. The bottom-bar Tokens is the input-side total (output excluded). Providers that do not report cache writes separately (e.g. DeepSeek) automatically fall back to the hit/miss formula.
|
|
179
|
+
>
|
|
180
|
+
> **Balance display**: the sidebar and bottom bar share the same balance data, so both show identical values. When the current provider has no balance adapter, the sidebar shows a hint and the bottom bar hides the balance segment.
|
|
173
181
|
|
|
174
182
|
---
|
|
175
183
|
|
|
@@ -205,11 +213,11 @@ The plugin provides three ways to control the display language, listed by priori
|
|
|
205
213
|
|
|
206
214
|
### 6.1 Runtime Switching (recommended)
|
|
207
215
|
|
|
208
|
-
Type `/cache-lang` in the TUI and select
|
|
216
|
+
Type `/cache-lang` in the TUI and select Chinese / English / 日本語 / 한국어 from the dialog. The panel switches immediately without restarting. Your preference is persisted and takes priority over auto-detection on the next launch.
|
|
209
217
|
|
|
210
218
|
### 6.2 Environment Variable Override
|
|
211
219
|
|
|
212
|
-
Set the `CACHE_TUI_LANG` environment variable before launching to force a specific language:
|
|
220
|
+
Set the `CACHE_TUI_LANG` environment variable before launching to force a specific language (`zh` / `en` / `ja` / `ko`):
|
|
213
221
|
|
|
214
222
|
```powershell
|
|
215
223
|
# Windows PowerShell
|
package/dist/_version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PLUGIN_VERSION = "1.
|
|
1
|
+
export declare const PLUGIN_VERSION = "1.6.1";
|
package/dist/_version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// auto-generated
|
|
2
|
-
export const PLUGIN_VERSION = "1.
|
|
2
|
+
export const PLUGIN_VERSION = "1.6.1";
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export type LangCode = "zh" | "en" | "ja" | "ko";
|
|
2
|
+
declare const ZH_T: {
|
|
3
|
+
readonly title: "缓存统计";
|
|
4
|
+
readonly hit: "命中率";
|
|
5
|
+
readonly totalHit: "总命中:";
|
|
6
|
+
readonly read: "缓存读:";
|
|
7
|
+
readonly write: "缓存写:";
|
|
8
|
+
readonly miss: "未命中:";
|
|
9
|
+
readonly out: "输出:";
|
|
10
|
+
readonly cost: "费用:";
|
|
11
|
+
readonly saved: "累计节省:";
|
|
12
|
+
readonly model: "模型:";
|
|
13
|
+
readonly provider: "提供商:";
|
|
14
|
+
readonly rate: "单价:";
|
|
15
|
+
readonly hitFolded: "命中";
|
|
16
|
+
readonly inputRate: "输入";
|
|
17
|
+
readonly cacheRate: "缓存";
|
|
18
|
+
readonly writeRate: "写入";
|
|
19
|
+
readonly noData: "等待缓存数据...";
|
|
20
|
+
readonly tok: "tok";
|
|
21
|
+
readonly distTitle: "估算 Token 分布";
|
|
22
|
+
readonly distSys: "系统提示:";
|
|
23
|
+
readonly distUser: "用户:";
|
|
24
|
+
readonly distAgent: "子代理指令:";
|
|
25
|
+
readonly distTool: "Tool 调用:";
|
|
26
|
+
readonly distRes: "Tool 结果:";
|
|
27
|
+
readonly distReason: "推理:";
|
|
28
|
+
readonly stepsCount: "本回合 {n} 次调用:";
|
|
29
|
+
readonly secDetail: "明细";
|
|
30
|
+
readonly secModel: "模型";
|
|
31
|
+
readonly secSkills: "已加载技能";
|
|
32
|
+
readonly balTotal: "总余额:";
|
|
33
|
+
readonly balNoKey: "未配置 {p} API Key";
|
|
34
|
+
readonly balLoading: "查询中...";
|
|
35
|
+
readonly balError: "查询失败";
|
|
36
|
+
readonly balErr401: "API Key 无效";
|
|
37
|
+
readonly balErr403: "余额查询被拒绝";
|
|
38
|
+
readonly balErrEmpty: "未获取到余额数据";
|
|
39
|
+
readonly balErrTimeout: "查询超时";
|
|
40
|
+
readonly balUnsupported: "当前提供商不支持余额查询";
|
|
41
|
+
readonly barHit: "命中率";
|
|
42
|
+
readonly barBal: "余额";
|
|
43
|
+
readonly barTok: "Tokens";
|
|
44
|
+
readonly secToggle: "切换区块";
|
|
45
|
+
readonly secBalance: "余额";
|
|
46
|
+
readonly secBottom: "底部状态栏";
|
|
47
|
+
readonly secBorder: "面板边框";
|
|
48
|
+
readonly keySaved: "API Key 已保存,正在查询余额...";
|
|
49
|
+
readonly keyCleared: "API Key 已清除";
|
|
50
|
+
readonly currencySet: "币种: {v} ({s}), 汇率: {r}";
|
|
51
|
+
readonly rateSet: "汇率已设为 {r}";
|
|
52
|
+
readonly panelConfigTitle: "缓存面板配置";
|
|
53
|
+
readonly panelConfigMsg: "币种: {c} | 汇率: {r} | 明细: {d} | 模型: {m} | 分布: {t} | 技能: {k} | 余额: {b} | 底部: {f}";
|
|
54
|
+
readonly borderShown: "面板边框 已显示";
|
|
55
|
+
readonly borderHidden: "面板边框 已隐藏";
|
|
56
|
+
readonly sectionShown: "{s} 已显示";
|
|
57
|
+
readonly sectionHidden: "{s} 已隐藏";
|
|
58
|
+
readonly langSwitched: "语言已切换为中文";
|
|
59
|
+
readonly autoSwitchOn: "自动切换余额提供商: 开";
|
|
60
|
+
readonly autoSwitchOff: "自动切换余额提供商: 关";
|
|
61
|
+
readonly providerManual: "余额提供商: {p}(自动切换已关闭)";
|
|
62
|
+
readonly runInSession: "请在会话内运行此命令";
|
|
63
|
+
readonly backToMain: "已切回主会话";
|
|
64
|
+
readonly subAgentSwitched: "已切换至子代理: {s}";
|
|
65
|
+
readonly langTitle: "显示语言";
|
|
66
|
+
readonly subPrefix: "子代理: ";
|
|
67
|
+
readonly keyUser: "(用户 key)";
|
|
68
|
+
readonly keyOpenCode: "(OpenCode)";
|
|
69
|
+
readonly keyNotSet: "(未配置)";
|
|
70
|
+
readonly balKeyPrompt: "输入 {p} API Key 以显示账户余额(留空清除)";
|
|
71
|
+
readonly balProvTitle: "余额提供商 / 自动切换";
|
|
72
|
+
readonly autoSwitchOpt: "自动切换提供商";
|
|
73
|
+
readonly balSelectTitle: "选择余额提供商";
|
|
74
|
+
readonly backToMainTitle: "回到主会话";
|
|
75
|
+
readonly subSelectTitle: "选择子代理";
|
|
76
|
+
readonly subSwitchTitle: "切换子代理";
|
|
77
|
+
readonly subViewTitle: "查看子代理缓存";
|
|
78
|
+
readonly subNoFound: "未找到子代理,请手动粘贴 Session ID";
|
|
79
|
+
};
|
|
80
|
+
/** 结构约束:值放宽为 string,键集合来自中文表(新增语言缺 key 会编译报错)。 */
|
|
81
|
+
export type Translation = {
|
|
82
|
+
[K in keyof typeof ZH_T]: string;
|
|
83
|
+
};
|
|
84
|
+
export declare const LANGS: Record<LangCode, Translation>;
|
|
85
|
+
/** 语言元数据:/cache-lang 选项与自动检测共用。 */
|
|
86
|
+
export declare const LANG_META: {
|
|
87
|
+
code: LangCode;
|
|
88
|
+
label: string;
|
|
89
|
+
}[];
|
|
90
|
+
/**
|
|
91
|
+
* 模板参数替换:`{key}` 占位符统一在此处理。
|
|
92
|
+
* 未提供的参数保留原占位符,避免静默丢失。
|
|
93
|
+
*/
|
|
94
|
+
export declare function applyParams(tpl: string, params?: Record<string, string | number>): string;
|
|
95
|
+
/**
|
|
96
|
+
* 翻译查找函数工厂:`t("key")` 返回当前语言的文本,`t("key", { p })` 附带模板参数。
|
|
97
|
+
* `getCode` 读取语言信号——在 SolidJS 渲染/memo 上下文中调用时自动建立响应式依赖。
|
|
98
|
+
*/
|
|
99
|
+
export declare function createT(getCode: () => LangCode): (key: keyof Translation, params?: Record<string, string | number>) => string;
|
|
100
|
+
/** 按系统 locale 自动检测语言(zh → 中文,ja → 日语,ko → 韩语,其余 → 英文)。 */
|
|
101
|
+
export declare function detectLang(): LangCode;
|
|
102
|
+
export {};
|
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// i18n — centralized translations. Add a language by appending a table that
|
|
3
|
+
// satisfies `Translation`; the compiler enforces key completeness.
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
const ZH_T = {
|
|
6
|
+
title: "缓存统计",
|
|
7
|
+
hit: "命中率",
|
|
8
|
+
totalHit: "总命中:",
|
|
9
|
+
read: "缓存读:",
|
|
10
|
+
write: "缓存写:",
|
|
11
|
+
miss: "未命中:",
|
|
12
|
+
out: "输出:",
|
|
13
|
+
cost: "费用:",
|
|
14
|
+
saved: "累计节省:",
|
|
15
|
+
model: "模型:",
|
|
16
|
+
provider: "提供商:",
|
|
17
|
+
rate: "单价:",
|
|
18
|
+
hitFolded: "命中",
|
|
19
|
+
inputRate: "输入",
|
|
20
|
+
cacheRate: "缓存",
|
|
21
|
+
writeRate: "写入",
|
|
22
|
+
noData: "等待缓存数据...",
|
|
23
|
+
tok: "tok",
|
|
24
|
+
distTitle: "估算 Token 分布",
|
|
25
|
+
distSys: "系统提示:",
|
|
26
|
+
distUser: "用户:",
|
|
27
|
+
distAgent: "子代理指令:",
|
|
28
|
+
distTool: "Tool 调用:",
|
|
29
|
+
distRes: "Tool 结果:",
|
|
30
|
+
distReason: "推理:",
|
|
31
|
+
stepsCount: "本回合 {n} 次调用:",
|
|
32
|
+
secDetail: "明细",
|
|
33
|
+
secModel: "模型",
|
|
34
|
+
secSkills: "已加载技能",
|
|
35
|
+
balTotal: "总余额:",
|
|
36
|
+
balNoKey: "未配置 {p} API Key",
|
|
37
|
+
balLoading: "查询中...",
|
|
38
|
+
balError: "查询失败",
|
|
39
|
+
balErr401: "API Key 无效",
|
|
40
|
+
balErr403: "余额查询被拒绝",
|
|
41
|
+
balErrEmpty: "未获取到余额数据",
|
|
42
|
+
balErrTimeout: "查询超时",
|
|
43
|
+
balUnsupported: "当前提供商不支持余额查询",
|
|
44
|
+
barHit: "命中率",
|
|
45
|
+
barBal: "余额",
|
|
46
|
+
barTok: "Tokens",
|
|
47
|
+
// ── /cache-section 面板 ──
|
|
48
|
+
secToggle: "切换区块",
|
|
49
|
+
secBalance: "余额",
|
|
50
|
+
secBottom: "底部状态栏",
|
|
51
|
+
secBorder: "面板边框",
|
|
52
|
+
// ── toast ──
|
|
53
|
+
keySaved: "API Key 已保存,正在查询余额...",
|
|
54
|
+
keyCleared: "API Key 已清除",
|
|
55
|
+
currencySet: "币种: {v} ({s}), 汇率: {r}",
|
|
56
|
+
rateSet: "汇率已设为 {r}",
|
|
57
|
+
panelConfigTitle: "缓存面板配置",
|
|
58
|
+
panelConfigMsg: "币种: {c} | 汇率: {r} | 明细: {d} | 模型: {m} | 分布: {t} | 技能: {k} | 余额: {b} | 底部: {f}",
|
|
59
|
+
borderShown: "面板边框 已显示",
|
|
60
|
+
borderHidden: "面板边框 已隐藏",
|
|
61
|
+
sectionShown: "{s} 已显示",
|
|
62
|
+
sectionHidden: "{s} 已隐藏",
|
|
63
|
+
langSwitched: "语言已切换为中文",
|
|
64
|
+
autoSwitchOn: "自动切换余额提供商: 开",
|
|
65
|
+
autoSwitchOff: "自动切换余额提供商: 关",
|
|
66
|
+
providerManual: "余额提供商: {p}(自动切换已关闭)",
|
|
67
|
+
runInSession: "请在会话内运行此命令",
|
|
68
|
+
backToMain: "已切回主会话",
|
|
69
|
+
subAgentSwitched: "已切换至子代理: {s}",
|
|
70
|
+
// ── 对话框 / 菜单 ──
|
|
71
|
+
langTitle: "显示语言",
|
|
72
|
+
subPrefix: "子代理: ",
|
|
73
|
+
keyUser: "(用户 key)",
|
|
74
|
+
keyOpenCode: "(OpenCode)",
|
|
75
|
+
keyNotSet: "(未配置)",
|
|
76
|
+
balKeyPrompt: "输入 {p} API Key 以显示账户余额(留空清除)",
|
|
77
|
+
balProvTitle: "余额提供商 / 自动切换",
|
|
78
|
+
autoSwitchOpt: "自动切换提供商",
|
|
79
|
+
balSelectTitle: "选择余额提供商",
|
|
80
|
+
backToMainTitle: "回到主会话",
|
|
81
|
+
subSelectTitle: "选择子代理",
|
|
82
|
+
subSwitchTitle: "切换子代理",
|
|
83
|
+
subViewTitle: "查看子代理缓存",
|
|
84
|
+
subNoFound: "未找到子代理,请手动粘贴 Session ID",
|
|
85
|
+
};
|
|
86
|
+
const EN_T = {
|
|
87
|
+
title: "Token Cache",
|
|
88
|
+
hit: "Hit",
|
|
89
|
+
totalHit: "Total Hit:",
|
|
90
|
+
read: "Read:",
|
|
91
|
+
write: "Write:",
|
|
92
|
+
miss: "Miss:",
|
|
93
|
+
out: "Out:",
|
|
94
|
+
cost: "Cost:",
|
|
95
|
+
saved: "Total Saved:",
|
|
96
|
+
model: "Model:",
|
|
97
|
+
provider: "Provider:",
|
|
98
|
+
rate: "Rate:",
|
|
99
|
+
hitFolded: "hit",
|
|
100
|
+
inputRate: "in",
|
|
101
|
+
cacheRate: "cache",
|
|
102
|
+
writeRate: "write",
|
|
103
|
+
noData: "Waiting for cache data...",
|
|
104
|
+
tok: "tok",
|
|
105
|
+
distTitle: "Estimated Token Dist.",
|
|
106
|
+
distSys: "System:",
|
|
107
|
+
distUser: "User:",
|
|
108
|
+
distAgent: "Sub-Agent Instr:",
|
|
109
|
+
distTool: "Tool Call:",
|
|
110
|
+
distRes: "Tool Result:",
|
|
111
|
+
distReason: "Reasoning:",
|
|
112
|
+
stepsCount: "Turn #{n} calls:",
|
|
113
|
+
secDetail: "Detail",
|
|
114
|
+
secModel: "Model",
|
|
115
|
+
secSkills: "Loaded Skills",
|
|
116
|
+
balTotal: "Total:",
|
|
117
|
+
balNoKey: "{p} API Key not set",
|
|
118
|
+
balLoading: "Fetching...",
|
|
119
|
+
balError: "Fetch failed",
|
|
120
|
+
balErr401: "Invalid API Key",
|
|
121
|
+
balErr403: "Balance request rejected",
|
|
122
|
+
balErrEmpty: "No balance data",
|
|
123
|
+
balErrTimeout: "Request timed out",
|
|
124
|
+
balUnsupported: "Balance query unsupported",
|
|
125
|
+
barHit: "Hit",
|
|
126
|
+
barBal: "Balance",
|
|
127
|
+
barTok: "Tokens",
|
|
128
|
+
// ── /cache-section panel ──
|
|
129
|
+
secToggle: "Toggle Section",
|
|
130
|
+
secBalance: "Balance",
|
|
131
|
+
secBottom: "Bottom Bar",
|
|
132
|
+
secBorder: "Panel Border",
|
|
133
|
+
// ── toasts ──
|
|
134
|
+
keySaved: "API Key saved, fetching balance...",
|
|
135
|
+
keyCleared: "API Key cleared",
|
|
136
|
+
currencySet: "Currency: {v} ({s}), rate: {r}",
|
|
137
|
+
rateSet: "Exchange rate set to {r}",
|
|
138
|
+
panelConfigTitle: "Cache Panel Config",
|
|
139
|
+
panelConfigMsg: "Currency: {c} | Rate: {r} | Detail: {d} | Model: {m} | Dist: {t} | Skills: {k} | Balance: {b} | Bottom: {f}",
|
|
140
|
+
borderShown: "Panel border shown",
|
|
141
|
+
borderHidden: "Panel border hidden",
|
|
142
|
+
sectionShown: "{s} section shown",
|
|
143
|
+
sectionHidden: "{s} section hidden",
|
|
144
|
+
langSwitched: "Switched to English",
|
|
145
|
+
autoSwitchOn: "Auto-switch balance provider: ON",
|
|
146
|
+
autoSwitchOff: "Auto-switch balance provider: OFF",
|
|
147
|
+
providerManual: "Balance provider: {p} (auto-switch off)",
|
|
148
|
+
runInSession: "Please run this command inside a session",
|
|
149
|
+
backToMain: "Switched to main session",
|
|
150
|
+
subAgentSwitched: "Showing sub-agent: {s}",
|
|
151
|
+
// ── dialogs / menus ──
|
|
152
|
+
langTitle: "Display Language",
|
|
153
|
+
subPrefix: "Sub: ",
|
|
154
|
+
keyUser: " (user key)",
|
|
155
|
+
keyOpenCode: " (OpenCode)",
|
|
156
|
+
keyNotSet: " (not set)",
|
|
157
|
+
balKeyPrompt: "Enter your {p} API key to show account balance (leave empty to clear)",
|
|
158
|
+
balProvTitle: "Balance Provider / Auto-switch",
|
|
159
|
+
autoSwitchOpt: "Auto-switch provider",
|
|
160
|
+
balSelectTitle: "Select Balance Provider",
|
|
161
|
+
backToMainTitle: "Back to Main",
|
|
162
|
+
subSelectTitle: "Select Sub-Agent",
|
|
163
|
+
subSwitchTitle: "Switch Sub",
|
|
164
|
+
subViewTitle: "View Sub Cache",
|
|
165
|
+
subNoFound: "No sub-agents found. Paste a Session ID manually",
|
|
166
|
+
};
|
|
167
|
+
const JA_T = {
|
|
168
|
+
title: "キャッシュ統計",
|
|
169
|
+
hit: "ヒット率",
|
|
170
|
+
totalHit: "総ヒット:",
|
|
171
|
+
read: "キャッシュ読込:",
|
|
172
|
+
write: "キャッシュ書込:",
|
|
173
|
+
miss: "未ヒット:",
|
|
174
|
+
out: "出力:",
|
|
175
|
+
cost: "費用:",
|
|
176
|
+
saved: "累計節約:",
|
|
177
|
+
model: "モデル:",
|
|
178
|
+
provider: "プロバイダ:",
|
|
179
|
+
rate: "単価:",
|
|
180
|
+
hitFolded: "ヒット",
|
|
181
|
+
inputRate: "入力",
|
|
182
|
+
cacheRate: "キャッシュ",
|
|
183
|
+
writeRate: "書込",
|
|
184
|
+
noData: "キャッシュデータ待機中...",
|
|
185
|
+
tok: "tok",
|
|
186
|
+
distTitle: "Token 分布(推定)",
|
|
187
|
+
distSys: "システム:",
|
|
188
|
+
distUser: "ユーザー:",
|
|
189
|
+
distAgent: "サブエージェント指示:",
|
|
190
|
+
distTool: "Tool 呼び出し:",
|
|
191
|
+
distRes: "Tool 結果:",
|
|
192
|
+
distReason: "推論:",
|
|
193
|
+
stepsCount: "今回 {n} 回呼出:",
|
|
194
|
+
secDetail: "明細",
|
|
195
|
+
secModel: "モデル",
|
|
196
|
+
secSkills: "読み込み済みスキル",
|
|
197
|
+
balTotal: "総残高:",
|
|
198
|
+
balNoKey: "{p} の API Key 未設定",
|
|
199
|
+
balLoading: "取得中...",
|
|
200
|
+
balError: "取得失敗",
|
|
201
|
+
balErr401: "API Key 無効",
|
|
202
|
+
balErr403: "残高照会が拒否されました",
|
|
203
|
+
balErrEmpty: "残高データなし",
|
|
204
|
+
balErrTimeout: "タイムアウト",
|
|
205
|
+
balUnsupported: "このプロバイダは残高照会非対応",
|
|
206
|
+
barHit: "ヒット率",
|
|
207
|
+
barBal: "残高",
|
|
208
|
+
barTok: "Tokens",
|
|
209
|
+
// ── /cache-section パネル ──
|
|
210
|
+
secToggle: "セクション切替",
|
|
211
|
+
secBalance: "残高",
|
|
212
|
+
secBottom: "下部ステータスバー",
|
|
213
|
+
secBorder: "パネル枠線",
|
|
214
|
+
// ── toast ──
|
|
215
|
+
keySaved: "API Key 保存済み、残高を取得中...",
|
|
216
|
+
keyCleared: "API Key をクリアしました",
|
|
217
|
+
currencySet: "通貨: {v} ({s}), レート: {r}",
|
|
218
|
+
rateSet: "レートを {r} に設定しました",
|
|
219
|
+
panelConfigTitle: "パネル設定",
|
|
220
|
+
panelConfigMsg: "通貨: {c} | レート: {r} | 明細: {d} | モデル: {m} | 分布: {t} | スキル: {k} | 残高: {b} | 下部: {f}",
|
|
221
|
+
borderShown: "パネル枠線 表示",
|
|
222
|
+
borderHidden: "パネル枠線 非表示",
|
|
223
|
+
sectionShown: "{s} 表示",
|
|
224
|
+
sectionHidden: "{s} 非表示",
|
|
225
|
+
langSwitched: "日本語に切り替えました",
|
|
226
|
+
autoSwitchOn: "残高プロバイダ自動切替: オン",
|
|
227
|
+
autoSwitchOff: "残高プロバイダ自動切替: オフ",
|
|
228
|
+
providerManual: "残高プロバイダ: {p}(自動切替オフ)",
|
|
229
|
+
runInSession: "セッション内で実行してください",
|
|
230
|
+
backToMain: "メインセッションに戻りました",
|
|
231
|
+
subAgentSwitched: "サブエージェントへ切替: {s}",
|
|
232
|
+
// ── ダイアログ / メニュー ──
|
|
233
|
+
langTitle: "表示言語",
|
|
234
|
+
subPrefix: "サブ: ",
|
|
235
|
+
keyUser: "(ユーザー key)",
|
|
236
|
+
keyOpenCode: "(OpenCode)",
|
|
237
|
+
keyNotSet: "(未設定)",
|
|
238
|
+
balKeyPrompt: "{p} の API Key を入力して残高を表示(空欄でクリア)",
|
|
239
|
+
balProvTitle: "残高プロバイダ / 自動切替",
|
|
240
|
+
autoSwitchOpt: "自動切替プロバイダ",
|
|
241
|
+
balSelectTitle: "残高プロバイダ選択",
|
|
242
|
+
backToMainTitle: "メインに戻る",
|
|
243
|
+
subSelectTitle: "サブエージェント選択",
|
|
244
|
+
subSwitchTitle: "サブ切替",
|
|
245
|
+
subViewTitle: "サブキャッシュ表示",
|
|
246
|
+
subNoFound: "サブエージェントが見つかりません。Session ID を手動で貼り付けてください",
|
|
247
|
+
};
|
|
248
|
+
const KO_T = {
|
|
249
|
+
title: "캐시 통계",
|
|
250
|
+
hit: "히트율",
|
|
251
|
+
totalHit: "총 히트:",
|
|
252
|
+
read: "캐시 읽기:",
|
|
253
|
+
write: "캐시 쓰기:",
|
|
254
|
+
miss: "미히트:",
|
|
255
|
+
out: "출력:",
|
|
256
|
+
cost: "비용:",
|
|
257
|
+
saved: "누적 절약:",
|
|
258
|
+
model: "모델:",
|
|
259
|
+
provider: "프로바이더:",
|
|
260
|
+
rate: "단가:",
|
|
261
|
+
hitFolded: "히트",
|
|
262
|
+
inputRate: "입력",
|
|
263
|
+
cacheRate: "캐시",
|
|
264
|
+
writeRate: "쓰기",
|
|
265
|
+
noData: "캐시 데이터 대기 중...",
|
|
266
|
+
tok: "tok",
|
|
267
|
+
distTitle: "Token 분포(추정)",
|
|
268
|
+
distSys: "시스템:",
|
|
269
|
+
distUser: "사용자:",
|
|
270
|
+
distAgent: "서브 에이전트 지시:",
|
|
271
|
+
distTool: "Tool 호출:",
|
|
272
|
+
distRes: "Tool 결과:",
|
|
273
|
+
distReason: "추론:",
|
|
274
|
+
stepsCount: "이번 턴 {n}회 호출:",
|
|
275
|
+
secDetail: "상세",
|
|
276
|
+
secModel: "모델",
|
|
277
|
+
secSkills: "로드된 스킬",
|
|
278
|
+
balTotal: "총 잔액:",
|
|
279
|
+
balNoKey: "{p} API Key 미설정",
|
|
280
|
+
balLoading: "조회 중...",
|
|
281
|
+
balError: "조회 실패",
|
|
282
|
+
balErr401: "API Key 무효",
|
|
283
|
+
balErr403: "잔액 조회가 거부되었습니다",
|
|
284
|
+
balErrEmpty: "잔액 데이터 없음",
|
|
285
|
+
balErrTimeout: "시간 초과",
|
|
286
|
+
balUnsupported: "이 프로바이더는 잔액 조회 미지원",
|
|
287
|
+
barHit: "히트율",
|
|
288
|
+
barBal: "잔액",
|
|
289
|
+
barTok: "Tokens",
|
|
290
|
+
// ── /cache-section 패널 ──
|
|
291
|
+
secToggle: "섹션 전환",
|
|
292
|
+
secBalance: "잔액",
|
|
293
|
+
secBottom: "하단 상태바",
|
|
294
|
+
secBorder: "패널 테두리",
|
|
295
|
+
// ── toast ──
|
|
296
|
+
keySaved: "API Key 저장됨, 잔액 조회 중...",
|
|
297
|
+
keyCleared: "API Key 삭제됨",
|
|
298
|
+
currencySet: "통화: {v} ({s}), 환율: {r}",
|
|
299
|
+
rateSet: "환율을 {r}(으)로 설정했습니다",
|
|
300
|
+
panelConfigTitle: "패널 설정",
|
|
301
|
+
panelConfigMsg: "통화: {c} | 환율: {r} | 상세: {d} | 모델: {m} | 분포: {t} | 스킬: {k} | 잔액: {b} | 하단: {f}",
|
|
302
|
+
borderShown: "패널 테두리 표시",
|
|
303
|
+
borderHidden: "패널 테두리 숨김",
|
|
304
|
+
sectionShown: "{s} 표시",
|
|
305
|
+
sectionHidden: "{s} 숨김",
|
|
306
|
+
langSwitched: "한국어로 전환했습니다",
|
|
307
|
+
autoSwitchOn: "잔액 프로바이더 자동 전환: 켜짐",
|
|
308
|
+
autoSwitchOff: "잔액 프로바이더 자동 전환: 꺼짐",
|
|
309
|
+
providerManual: "잔액 프로바이더: {p}(자동 전환 꺼짐)",
|
|
310
|
+
runInSession: "세션 내에서 실행해 주세요",
|
|
311
|
+
backToMain: "메인 세션으로 돌아갔습니다",
|
|
312
|
+
subAgentSwitched: "서브 에이전트로 전환: {s}",
|
|
313
|
+
// ── 다이얼로그 / 메뉴 ──
|
|
314
|
+
langTitle: "표시 언어",
|
|
315
|
+
subPrefix: "서브: ",
|
|
316
|
+
keyUser: "(사용자 key)",
|
|
317
|
+
keyOpenCode: "(OpenCode)",
|
|
318
|
+
keyNotSet: "(미설정)",
|
|
319
|
+
balKeyPrompt: "{p} API Key를 입력하여 잔액 표시(비우면 삭제)",
|
|
320
|
+
balProvTitle: "잔액 프로바이더 / 자동 전환",
|
|
321
|
+
autoSwitchOpt: "자동 전환 프로바이더",
|
|
322
|
+
balSelectTitle: "잔액 프로바이더 선택",
|
|
323
|
+
backToMainTitle: "메인으로 돌아가기",
|
|
324
|
+
subSelectTitle: "서브 에이전트 선택",
|
|
325
|
+
subSwitchTitle: "서브 전환",
|
|
326
|
+
subViewTitle: "서브 캐시 보기",
|
|
327
|
+
subNoFound: "서브 에이전트를 찾을 수 없습니다. Session ID를 직접 붙여넣으세요",
|
|
328
|
+
};
|
|
329
|
+
export const LANGS = { zh: ZH_T, en: EN_T, ja: JA_T, ko: KO_T };
|
|
330
|
+
/** 语言元数据:/cache-lang 选项与自动检测共用。 */
|
|
331
|
+
export const LANG_META = [
|
|
332
|
+
{ code: "zh", label: "中文" },
|
|
333
|
+
{ code: "en", label: "English" },
|
|
334
|
+
{ code: "ja", label: "日本語" },
|
|
335
|
+
{ code: "ko", label: "한국어" },
|
|
336
|
+
];
|
|
337
|
+
/**
|
|
338
|
+
* 模板参数替换:`{key}` 占位符统一在此处理。
|
|
339
|
+
* 未提供的参数保留原占位符,避免静默丢失。
|
|
340
|
+
*/
|
|
341
|
+
export function applyParams(tpl, params) {
|
|
342
|
+
if (!params)
|
|
343
|
+
return tpl;
|
|
344
|
+
return tpl.replace(/\{(\w+)\}/g, (m, k) => k in params ? String(params[k]) : m);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* 翻译查找函数工厂:`t("key")` 返回当前语言的文本,`t("key", { p })` 附带模板参数。
|
|
348
|
+
* `getCode` 读取语言信号——在 SolidJS 渲染/memo 上下文中调用时自动建立响应式依赖。
|
|
349
|
+
*/
|
|
350
|
+
export function createT(getCode) {
|
|
351
|
+
return (key, params) => applyParams(LANGS[getCode()][key], params);
|
|
352
|
+
}
|
|
353
|
+
/** 按系统 locale 自动检测语言(zh → 中文,ja → 日语,ko → 韩语,其余 → 英文)。 */
|
|
354
|
+
export function detectLang() {
|
|
355
|
+
try {
|
|
356
|
+
const loc = Intl.DateTimeFormat().resolvedOptions().locale.toLowerCase();
|
|
357
|
+
if (loc.startsWith("zh"))
|
|
358
|
+
return "zh";
|
|
359
|
+
if (loc.startsWith("ja"))
|
|
360
|
+
return "ja";
|
|
361
|
+
if (loc.startsWith("ko"))
|
|
362
|
+
return "ko";
|
|
363
|
+
return "en";
|
|
364
|
+
}
|
|
365
|
+
catch {
|
|
366
|
+
return "en";
|
|
367
|
+
}
|
|
368
|
+
}
|