v0.6.0: 预设供应商 + 供应商账单查询

## 新增

- 15 条主流供应商预设(Kimi Coding / Moonshot / Anthropic /
  DeepSeek / 智谱 GLM / z.ai / 阿里百炼 / MiniMax / StepFun /
  SiliconFlow / Novita / OpenRouter / OpenAI / Google AI Studio /
  火山方舟),通过 PresetPickerModal 一键填表
- 供应商余额/套餐查询(卡片底部 UsageFooter):余额类
  (DeepSeek / SiliconFlow / OpenRouter / StepFun / Novita) +
  套餐类(Kimi For Coding / 智谱 GLM / MiniMax),5min stale TTL +
  force_refresh + 并发 ≤3
- Rust 端 services/ 模块(balance / coding_plan / usage_types),
  参考 cc-switch(MIT,© Jason Young)实现
- query_provider_usage 命令:Rust 端从 config 加载 key,
  不经 IPC 序列化 API key
- usageKinds 持久化到 SQLite settings(JSON 数组),
  load 时合并回 config,导出 config.toml 时不写
- detect_provider 启发式:旧用户升级后自动获得账单支持
- save-time 校验:未完成供应商(缺 api_key / base_url / 模型)
  保存时弹 confirm 列出原因;新增未提交 back 时静默 drop
- docs/PROPOSAL-presets-and-usage.md(v0.4-draft 实施档)
- docs/VERIFICATION-CHECKLIST.md(70+ 项手动验证清单)

## 修复

- handleDuplicateProvider 的 alias.slice 漏洞:老数据
  非规范 alias 复制不再错位
- handleSelectPreset 不再 auto-save,半成品不会落盘
- handleSwitchProvider 校验取消时自动 refresh 回滚,
  不会出现内存改 / 盘没动的脏态

## 文档

- README / README_EN 致谢段补 cc-switch(预设 + 账单)
- README 已知限制与后续建议段(/reload 上游限制调研结论)
- i18n 补 5 条校验 key + 11 条预设 UI key + 12 条账单 key

详见 docs/PROPOSAL-presets-and-usage.md 与
docs/VERIFICATION-CHECKLIST.md
This commit is contained in:
KimiSwitch Dev committed 2026-07-29 20:59:53 +08:00
1 parent a1fdc6c93d
commit 2614f80d0f
27 files changed
+3442 -67

No files matched your search

+47
View File
@@ -11,6 +11,12 @@ export const enTranslations: Record<TranslationKey, string> = {
reloadConfig: "Reload Config",
openConfigDir: "Open Config Dir",
unsavedConfirm: "You have unsaved changes. Are you sure you want to reload?",
validationNoApiKey: "Missing API key",
validationNoBaseUrl: "Missing base URL",
validationNoModels: "No models configured",
validationBlankModels: "Model entries with empty model id: {aliases}",
saveValidationConfirm:
"The following providers are not fully configured. Save anyway?\n\n{details}\n\n(Click OK to save to config.toml as-is; click Cancel to keep editing.)",
providerNotFound: "Provider not found",
backToList: "Back to list",
syncToOmp: "Sync to OMP",
@@ -316,4 +322,45 @@ export const enTranslations: Record<TranslationKey, string> = {
// Sessions — preview
previewCollapseChars: "Collapse · {n} chars",
previewExpandChars: "Expand · {n} chars",
// Provider presets
presetPickerTitle: "Choose a provider preset",
presetSearchPlaceholder: "Search presets...",
presetSortOriginal: "Default",
presetSortAlpha: "A-Z",
presetNoResults: "No matching presets",
presetCustomConfig: "+ Custom configuration",
presetFooterHint: "Presets only pre-fill the form; every field stays editable afterwards.",
presetCategoryOfficial: "Official",
presetCategoryCnOfficial: "China",
presetCategoryThirdParty: "Third-party",
presetCategoryAggregator: "Aggregator",
presetNameAnthropic: "Anthropic",
presetNameKimiCoding: "Kimi For Coding",
presetNameMoonshot: "Moonshot Platform",
presetNameDeepseek: "DeepSeek",
presetNameZhipu: "Zhipu GLM",
presetNameZai: "z.ai (Zhipu Global)",
presetNameBailian: "Alibaba Bailian",
presetNameMinimax: "MiniMax",
presetNameStepfun: "StepFun",
presetNameSiliconflow: "SiliconFlow",
presetNameNovita: "Novita AI",
presetNameOpenrouter: "OpenRouter",
presetNameOpenai: "OpenAI",
presetNameGoogleGenai: "Google AI Studio",
presetNameVolcengine: "Volcengine Ark",
// Provider usage
usageBalance: "Balance",
usageUsed: "used",
usageRemaining: "left",
usageRefresh: "Refresh",
usageRetry: "Retry",
usageQueryFailed: "Query failed",
usageNetworkError: "Network error",
usageInvalidKey: "Invalid API key",
usageResetIn: "resets in {time}",
usageResetDone: "reset",
usageLoading: "Querying…",
};
+47
View File
@@ -9,6 +9,12 @@ export const zhTranslations = {
reloadConfig: "读取配置",
openConfigDir: "打开配置目录",
unsavedConfirm: "有未保存修改,确定要重新读取配置吗?",
validationNoApiKey: "缺少 API Key",
validationNoBaseUrl: "缺少 Base URL",
validationNoModels: "未配置模型",
validationBlankModels: "存在未填写 model id 的模型:{aliases}",
saveValidationConfirm:
"以下供应商尚未完成配置,仍要保存吗?\n\n{details}\n\n(点击「确定」仍会保存到 config.toml;点击「取消」可继续编辑)",
providerNotFound: "供应商不存在",
backToList: "返回列表",
syncToOmp: "同步到 OMP",
@@ -311,6 +317,47 @@ export const zhTranslations = {
// Sessions — preview
previewCollapseChars: "收起 · {n} 字符",
previewExpandChars: "展开全文 · {n} 字符",
// Provider presets
presetPickerTitle: "选择预设供应商",
presetSearchPlaceholder: "搜索预设供应商...",
presetSortOriginal: "原始",
presetSortAlpha: "A-Z",
presetNoResults: "没有匹配的预设",
presetCustomConfig: "+ 自定义配置",
presetFooterHint: "预设只是一键填表,后续可继续修改所有字段。",
presetCategoryOfficial: "官方",
presetCategoryCnOfficial: "国产",
presetCategoryThirdParty: "第三方",
presetCategoryAggregator: "聚合",
presetNameAnthropic: "Anthropic 官方",
presetNameKimiCoding: "Kimi For Coding",
presetNameMoonshot: "Moonshot 平台",
presetNameDeepseek: "DeepSeek",
presetNameZhipu: "智谱 GLM",
presetNameZai: "z.ai(智谱海外)",
presetNameBailian: "阿里百炼",
presetNameMinimax: "MiniMax",
presetNameStepfun: "阶跃星辰",
presetNameSiliconflow: "硅基流动",
presetNameNovita: "Novita AI",
presetNameOpenrouter: "OpenRouter",
presetNameOpenai: "OpenAI 官方",
presetNameGoogleGenai: "Google AI Studio",
presetNameVolcengine: "火山方舟",
// Provider usage
usageBalance: "余额",
usageUsed: "已使用",
usageRemaining: "剩余",
usageRefresh: "刷新",
usageRetry: "重试",
usageQueryFailed: "查询失败",
usageNetworkError: "网络异常",
usageInvalidKey: "API Key 无效",
usageResetIn: "{time} 后重置",
usageResetDone: "已重置",
usageLoading: "查询中…",
} as const;
export type TranslationKey = keyof typeof zhTranslations;