dsh-bottom-info-bar 1.16.4 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/README.zh-CN.md +5 -3
- package/lib/client.js +134 -85
- package/lib/constants.js +1 -1
- package/lib/index.js +59 -4
- package/lib/locales.js +44 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ A DeepSeek Harness plugin that replaces the stats row under the composer with on
|
|
|
20
20
|
| Spend | this session (including subagents), today, last 30 days, all time |
|
|
21
21
|
| Extras | main time, world time, custom text |
|
|
22
22
|
|
|
23
|
-
The bar has two densities — click it to switch. **
|
|
23
|
+
The bar has two densities — click it to switch. **Compact** shows only the provider, model, and one essential account detail: balance, the shortest useful quota window, or this billing period's spend. **Full** shows every enabled detail, including DSH's native stats row. Both follow DSH's light or dark theme.
|
|
24
24
|
|
|
25
25
|
## Compact mode
|
|
26
26
|
|
|
@@ -52,7 +52,7 @@ Shows the real balance from the provider's own API. It refetches when the bar op
|
|
|
52
52
|
|
|
53
53
|
### Subscription quota
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
Full mode shows each available quota window (5-hour / weekly / monthly) and a countdown to the next reset — both always come from the same window, so they can never disagree. Windows show **remaining** percent by default and can be switched to **used** in settings; the low-quota warning always follows the remaining ≤ 20% rule. Compact mode keeps only the shortest available window (5-hour → weekly → monthly), without a reset countdown.
|
|
56
56
|
|
|
57
57
|
### Cloud billing
|
|
58
58
|
|
|
@@ -96,7 +96,9 @@ Everything lives on the plugin page — **Plugins → bottom-info-bar**. Changes
|
|
|
96
96
|
|
|
97
97
|

|
|
98
98
|
|
|
99
|
-
**
|
|
99
|
+
**Information display** — choose **Compact** or **Full** and the choice is saved. Compact does not erase any field choices; switch back to Full whenever you need the extra detail.
|
|
100
|
+
|
|
101
|
+
**Fields and colors** — one switch and one color per field, in two groups. Turn a field off and the bar drops it. The plugin information group opens first; native stats only appear in Full mode.
|
|
100
102
|
|
|
101
103
|
- **Native information** — the fields DSH's own stats row already showed.
|
|
102
104
|
- **Plugin information** — everything this bar adds: provider and model, subscriptions, spend, balance, pricing and quota.
|
package/README.zh-CN.md
CHANGED
|
@@ -20,7 +20,7 @@ DeepSeek Harness 插件:把输入框下方那行统计栏换成一行信息栏
|
|
|
20
20
|
| 花费 | 本会话(含子代理)、今天、近 30 天、累计 |
|
|
21
21
|
| 其它 | 主时间、世界时间、自定义文字 |
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
信息栏有两种显示方式,点击即可切换:**简洁**只保留服务商、模型和一项核心账户信息——余额、最短的有效额度窗口,或本计费周期花费;**完整**显示所有已启用细节,并保留 DSH 原生统计行。两种方式都跟随 DSH 的深色/浅色主题。
|
|
24
24
|
|
|
25
25
|
## 简洁模式
|
|
26
26
|
|
|
@@ -52,7 +52,7 @@ DeepSeek Harness 插件:把输入框下方那行统计栏换成一行信息栏
|
|
|
52
52
|
|
|
53
53
|
### 订阅额度制
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
完整模式显示各窗口剩余额度(5 小时 / 周 / 月)与距下次重置的倒计时——两者始终取自同一个窗口,不会互相矛盾。窗口默认按**剩余**显示百分比,可在设置里切换为**已用**;低额度告警始终按剩余 ≤ 20% 判定。简洁模式只保留时长最短的可用窗口(5 小时 → 周 → 月),不显示重置倒计时。
|
|
56
56
|
|
|
57
57
|
### 云账单制
|
|
58
58
|
|
|
@@ -96,7 +96,9 @@ cd dsh-bottom-info-bar
|
|
|
96
96
|
|
|
97
97
|

|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
**信息显示方式** —— 选择**简洁**或**完整**,选择会自动保存。简洁模式不会改掉字段开关,切回完整模式即可查看已启用的全部细节。
|
|
100
|
+
|
|
101
|
+
**字段与配色** —— 每个字段一个开关、一个颜色,分两组。关掉哪个字段,信息栏就不再显示它。插件信息默认展开;原生统计只在完整模式出现。
|
|
100
102
|
|
|
101
103
|
- **原生信息** —— DSH 原生统计栏本来就有的字段。
|
|
102
104
|
- **插件信息** —— 信息栏新增的全部内容:服务商与模型、订阅、花费、余额、定价与额度。
|
package/lib/client.js
CHANGED
|
@@ -59,7 +59,7 @@ const BIB_SET_NATIVE_MENU = bibSetNative('Menu');
|
|
|
59
59
|
// 与上面同一条铁律:取不到时退回插件内等价实现,绝不把 undefined 交给 React.createElement。
|
|
60
60
|
const BIB_SET_NATIVE_RISK_CONFIRM = bibSetNative('RiskConfirmation');
|
|
61
61
|
const LOCALE_NAMESPACE = 'dsh-bottom-info-bar';
|
|
62
|
-
const LOCALES = {"zh":{"meta.title":"底部信息栏","meta.description":"在输入框下方显示当前模型、余额和花费。","ui.requestTimedOut":"请求超时","ui.requestCanceled":"请求已取消","ui.couldNotParseResponse":"响应解析失败","ui.rpcFailed":"RPC 失败","ui.refreshFailed":"刷新失败","color.red":"红","color.green":"绿","color.blue":"蓝","color.purple":"紫","color.orange":"橙","color.neutral":"中性","mode.balance":"余额制","mode.subscription":"订阅制","mode.billing":"账单制","mode.native":"原生统计行","mode.common":"通用","ui.nativeStatsField":"原生统计行字段","ui.shownIn":"出现于","ui.pleaseTryAgainLater":"请稍后再试","ui.restoreDefaultColor":"恢复默认颜色","ui.infoBarSettings":"信息栏","ui.settingsAreTemporarilyUnavailable":"暂时无法读取设置","ui.loadingInfoBarSettings":"正在加载设置…","ui.couldNotLoadInfoBar":"无法读取信息栏设置:","ui.changesAppliedButCouldNot":"已应用,但无法保存到本地:","ui.unknownReason":"未知原因","ui.couldNotSave":"{errorPrefix}保存失败:{value}","ui.color":"“{value}”颜色:","ui.hasAnInvalidColorEnter":"“{value}”的颜色格式不正确,请输入 #RRGGBB(例如 #0044CC)。","ui.defaultColorsRestored":"已恢复默认颜色","ui.defaultLabelsRestored":"已恢复默认显示设置","ui.couldNotReset":"重置失败:{value}","ui.identifiesTheProviderAndModel":"显示当前会话使用的服务商和模型。","ui.show":"显示{label}","ui.clickToHide":"点击隐藏","ui.clickToShow":"点击显示","ui.presetColor":"{label}的预设颜色","ui.customColor":"{label}的自定义颜色","ui.customColorOpenColorPicker":"自定义颜色(打开系统取色器)","ui.customColorItem":"自定义…","ui.colorSwatchLabel":"{label}的颜色","ui.hexColor":"{label}的十六进制颜色","ui.expand":"展开","ui.collapse":"收起","ui.saving":"正在保存…","ui.processing":"正在处理…","ui.visibleFields":"显示内容","ui.timeDateTitle":"时间与日期","ui.timeDateDesc":"主时间和世界时间的时区与显示格式。","ui.customTextSectionDesc":"显示在信息栏中。","ui.resetConfirmTitle":"重置信息栏设置","ui.resetConfirmDescFields":"将把全部字段的显示开关恢复为默认状态(全部显示),自定义颜色不受影响。该操作会直接应用到信息栏。","ui.resetConfirmDescColors":"将清除全部自定义颜色并恢复默认配色,字段显示开关不受影响。该操作会直接应用到信息栏。","ui.resetConfirmAcknowledge":"我了解这次重置不可撤销","ui.resetConfirmCancel":"取消","ui.resetConfirmConfirm":"确认重置","ui.resetLabels":"恢复显示","ui.resetColors":"恢复颜色","ui.resetRowTitle":"恢复默认","ui.resetRowDesc":"恢复显示和颜色设置。","ui.customTextCount":"已输入 {value}/64 个字符","ui.couldNotDisplayInfoBar":"无法显示信息栏设置:{value}","ui.dataAndBilling":"账单数据","ui.dataAndBillingDesc":"导出或清除记录。","ui.exportBillingRecords":"导出账单","ui.exportBillingRecordsDesc":"导出为 CSV 或 JSON。","ui.exportBillingCsv":"导出 CSV","ui.exportBillingJson":"导出 JSON","ui.clearBillingRecords":"清除账单","ui.clearBillingRecordsDesc":"清除后无法恢复。","ui.clearBillingRecordsConfirm":"确定清除本插件保存的全部账单记录吗?建议先导出。清除后无法恢复,但不会影响设置或登录信息。","ui.exportedBillingRecords":"已导出 {count} 条账单记录({format})","ui.noBillingRecordsToExport":"目前没有可导出的账单记录。","ui.exportFailed":"导出失败:{value}","ui.exportIncomplete":"历史账单读取不完整:{value}。本次未导出,请稍后再试。","ui.clearFailed":"清除失败:{value}","ui.clearFailedWithoutDetails":"账单记录未能全部清除","ui.clearedBillingRecords":"已清除 {count} 条账单记录","ui.clearCanceled":"已取消","ui.exportNotSupported":"当前环境不支持下载文件。","ui.infoBar":"信息栏","ui.weekly":"周","ui.monthly":"月","ui.window":"窗口","ui.quotaDisplayUsed":"已用","ui.quotaDisplayRemaining":"剩余","ui.quotaDisplayModeTitle":"订阅窗口百分比方向","ui.quotaDisplayModeDesc":"订阅额度窗口按剩余或已用显示;告警阈值始终按剩余 20% 判定。","ui.windowUsedRemaining":"{label}窗口:已用 {usedPercent}%(剩余 {value}%)","ui.windowUsedRemainingResets":"{label}窗口 已用 {usedPercent}%(剩余 {value}%) · 重置 {value4}","ui.minimax":"MiniMax","ui.supportsImageInput":"支持图像输入。","ui.vision":"视觉","ui.unknown":"未知","ui.unknownModel":"未知模型","ui.modelSelectionPending":"正在读取当前模型","ui.modelCapabilityPending":"正在确认是否支持图像输入","ui.pluginVersion":"\n插件版本:{current}","ui.provider":"服务商:{provLabel} {modelLabel}\n","ui.pricingPeakOffPeakBeijing":"定价:峰谷价(工作日高峰 9-12、14-18 点;周末全天空闲)","ui.pricingFixed":"定价:固定价","ui.pricingNotListedUsingDefaults":"定价:暂未收录,不计算花费","ui.zhipu":"智谱","ui.xiaomiMiMo":"小米 MiMo","ui.commandCode":"Command Code","ui.subscription":"订阅","ui.cloudBilling":"云账单","ui.plan":"\n套餐:{plan}","ui.expiresLocalTime":"\n到期:{value}(本地时区)","ui.subscriptionServiceModel":"订阅服务:{serviceName}\n模型:{rawModelLabel}{planLine}{expiryLine}{versionLine}","ui.balanceLookupIsNotYet":"暂时无法读取该服务商的余额。","ui.notSupported":"未适配","ui.notConfigured":"未配置 ","ui.notConfiguredConfigureItIn":"未配置 {credName}。请在\"设置 → 模型\"中填写。","ui.notConfiguredSettingsModels":"未配置 {credName}。请在设置 → 模型中填写。","ui.estimatedBalance":"估算余额:{symbol}{value}","ui.balance":"余额:{symbol}{value}","ui.balance.pushBalanceGroups":"余额","ui.low":"低","ui.estimated":"(估算)","ui.balanceIsTemporarilyUnavailableShowing":"余额暂不可用;正在显示上次数据并自动重试。","ui.couldNotLoadBalanceCheck":"余额获取失败。请检查网络和 API Key。","ui.balanceUnavailable":"余额获取失败","ui.beijingTime":"北京时间 ","ui.peakPrice":"高峰价","ui.offPeakPrice":"空闲价","ui.input":":输入 ¥","ui.mCachedInput":"/M · 缓存 ¥","ui.mOutput":"/M · 输出 ¥","ui.beijingTimeSwitchesTo":"北京时间 {atLabel} 切换为","ui.until":"距","ui.offPeak":"空闲","ui.peak":"高峰","ui.today":"今天 {symbol}{value}","ui.lastDays":"近一月 {symbol}{value}","ui.allTime":"全部 {symbol}{value}","ui.sessionIncludingSubagents":"本会话 {costTxt}(含子代理){value}","ui.session":"本会话","ui.spendIsTemporarilyUnavailableChat":"花费暂不可用;不会影响对话。","ui.spendUnavailable":"花费获取失败","ui.noSignInCredentialsFound":"未找到 {serviceName} 登录凭证。请重新授权。","ui.credentialsHaveExpiredPleaseReauthorize":"{serviceName} 登录凭证已失效。请重新授权。","ui.deniedAccessReauthorizeOrTry":"{serviceName} 拒绝访问。请重新授权或稍后再试。","ui.rateLimitReachedPleaseTry":"{serviceName} 请求过于频繁。请稍后再试。","ui.timedOutCheckYourConnection":"{serviceName} 响应超时。请检查网络后再试。","ui.returnedAnUnrecognizedResponsePlease":"{serviceName} 返回的数据暂时无法识别。请稍后再试。","ui.isTemporarilyUnavailableCheckYour":"{serviceName} 暂不可用。请检查网络后再试。","ui.subscriptionExpiresLocalTime":"订阅到期:{value}(本地时区)","ui.expires":"到期","ui.subscriptionSource":"订阅源:{value}(","ui.prepaidBalance":"充值余额","ui.availableBalance":"可用余额:{balTxt}","ui.availableCredits":"剩余 credits:{value}","ui.credits":"积分","ui.subscriptionSource.titleLines":"订阅源:{value}","ui.windowRemainingUsed":"{label}窗口:剩余 {value}%(已用 {usedPercent}%)","ui.resetsResetsIn":" · 重置 {value} · 距重置 {value2}","ui.windowRemainingUsedResets":"{label}窗口 剩余 {value}%(已用 {usedPercent}%) · 重置 {value4}","ui.resetsIn":"距重置","ui.configureItInSettingsModels":"。请在\"设置 → 模型\"中填写。","ui.deniedAccessTheTokenMay":"{serviceName} 拒绝访问:Token 可能缺少账单读取权限。","ui.billingIsTemporarilyUnavailableCheck":"{serviceName} 账单暂不可用。请检查网络与权限后再试。","ui.billingSource":"账单源:{value}","ui.thisMonthSSpend":"本月花费:{symbol}{value}","ui.budgetUsed":"预算使用:{value}%","ui.dailyFreeQuotaRemaining":"每日免费额度剩余:{value}","ui.thisMonth":"本月","ui.thisMonthSUsage":"本月用量","ui.budget":"预算","ui.free":"免费","ui.resetsIn.pushBillingGroups":"{value} · 距重置 {value2}","ui.billingServiceModel":"账单服务:{serviceName}\n模型:{modelLabel}{versionLine}","ui.pricing":"定价","ui.spend":"花费","ui.mode":"模式","ui.subscriptionQuota":"订阅额度","ui.billing":"账单","ui.temporarilyUnavailableKeepingTheLast":"暂不可用;正在保留上次数据并自动重试。","ui.spendJournalSavedButThe":"账单流水已保存,但可直接查看的账单文件暂未更新:","ui.thisSpendRecordWasNot":"本次账单未保存,不会计入金额:","ui.ledgerUpdatePending":"账单待整理","ui.spendNotSaved":"账单未保存","ui.askYourAgentToUpdate":"请告知你的 Agent 将本插件更新到“{latest}”版本。\n或者点击本标签复制更新命令,到终端粘贴执行,重启 DSH 后生效。","ui.updateAvailable":"新版本提醒","ui.updateCommandCopied":"更新命令已复制","ui.tools":"工具调用","ui.avgTTFT":"首 token 平均","ui.cacheHit":"缓存命中","ui.input.BottomInfoBar":"输入","ui.output":"输出","ui.savingView":"正在保存切换…","ui.clickToSwitchFullCompact":"单击切换 完整/简洁","ui.pressEnterOrSpaceFor":"按 Enter 或空格切换为简洁模式。","ui.pressEnterOrSpaceFor.BottomInfoBar":"按 Enter 或空格切换为完整模式。","host.hour":"5 小时","host.unknownProvider":"未知服务商","error.subscription.request-failed":"订阅额度请求未知异常","host.settingsFileCouldNotBe":"设置文件写入未完成","host.everydayQuestions":"日常问答","host.mediumCodingTask":"中等编码任务","host.longDocumentAnalysisCodeReview":"长文档分析/代码审查","host.largeProjectRefactorAcrossMultiple":"大工程重构(多轮)","host.subagentWorkflow":"子代理工作流","error.settings.save-failed":"settings.json 落盘失败:{value}","error.balance.credentials":"凭据读取失败","error.balance.not-configured":"未配置 {credential}","error.request.http":"请求失败(HTTP {status})","error.request.parse":"响应格式异常","error.subscription.not-connected":"未找到 ChatGPT 订阅登录凭证(~/.codex/auth.json),请安装 dsh-chatgpt-subscription 插件绑定","error.subscription.credentials-missing":"ChatGPT 订阅登录凭证缺少 id_token,请安装 dsh-chatgpt-subscription 插件重新绑定","error.subscription.opencode-not-configured":"未配置 OpenCode Go(OPENCODE_GO_API_KEY 或 opencode auth.json)","error.subscription.commandcode-not-configured":"未配置 Command Code(COMMAND_CODE_API_KEY、CMD_API_KEY 或 ~/.commandcode/auth.json)","error.subscription.commandcode-auth-failed":"Command Code 登录凭证已失效。请重新登录或更新 API Key","error.subscription.commandcode-unrecognized":"Command Code 返回了无法识别的额度格式(接口可能已变更),已保留上次数据","host.zhipu":"智谱 {mapped}","host.zhipu.parseZaiQuota":"智谱 {value}{value2}","error.subscription.zhipu-not-configured":"未配置智谱 API Key(ZAI_API_KEY 或 ZAI_CODING_CN_API_KEY)","error.subscription.zhipu-auth-failed":"智谱 API 认证失败(密钥过期或不正确)","error.subscription.zhipu-unrecognized":"智谱返回了无法识别的额度格式(接口可能已变更),已保留上次数据","error.request.failed":"请求失败({value} {msg})","error.subscription.xiaomi-not-configured":"未配置小米 MiMo Token Plan 凭据({credName} 或 XIAOMI_API_KEY)","error.subscription.xiaomi-http":"请求失败(HTTP {value})","error.subscription.minimax-not-configured":"未配置 MiniMax 凭据(MINIMAX_API_KEY 或 MINIMAX_CN_API_KEY)。查询 Token Plan 必须使用 Subscription Key,按量 API Key 会被服务端拒绝","error.subscription.minimax-auth-failed":"MiniMax 拒绝了当前 API Key:查询 Token Plan 必须使用 Subscription Key(在 Token Plan 订阅页生成),按量 API Key 会被服务端拒绝(status_code=1004 / HTTP 401)","error.subscription.minimax-unrecognized":"MiniMax 返回了无法识别的额度格式(接口可能已变更),已保留上次数据","error.billing.together-not-configured":"未配置 TOGETHER_API_KEY","host.actualMonthlyBillFromThe":"本月真实账单(Together 官方 Usage API)","error.billing.fireworks-not-configured":"未配置 FIREWORKS_API_KEY","error.billing.fireworks-account":"账户解析失败(未取得 account_id)","host.actualBillForThisPeriod":"本周期真实账单(Fireworks Billing Summary)","host.actualUsageForThisPeriod":"本周期真实用量(billingUsage 回退端点,无金额)","error.billing.aws-not-configured":"未配置 AWS 凭据(AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY)","error.billing.aws-http":"请求失败(HTTP {status}),可能缺少 ce:GetCostAndUsage 权限","host.actualMonthlyBillFromAWS":"AWS Cost Explorer 本月真实账单(账单延迟约 24 小时)","error.billing.cloudflare-not-configured":"未配置 CLOUDFLARE_API_KEY(需账号级 Token 并授予 Billing 读权限)","error.billing.cloudflare-account":"未配置 CLOUDFLARE_ACCOUNT_ID","error.billing.cloudflare-http":"请求失败(HTTP {status}),Token 需 Billing 读权限","host.actualMonthlyUsageFromThe":"Cloudflare Billable Usage API(Alpha),本月真实用量","error.billing.request-failed":"账单请求未知异常","host.spendSummaryFileMissingArchived":"账单汇总文件缺失:折叠期间的历史金额暂未计入显示(明细仍在冷归档 usage-archive/,可人工恢复)","host.spendLedgerCouldNotBe":"账单文件写入未完成","host.usageLedgerBusy":"当前仍有回答正在进行,完成后再清除账单记录","error.ledger.clear-failed":"账单记录清理未完成:{value}","error.ledger.snapshot-stale":"折叠汇总落盘失败:{value}","host.basedOnYourLastSessions":"基于你最近 {count} 次会话","host.estimatedFromSpendingOverThe":"基于过去 {SPEND_DAYS} 天消耗速度的估算","host.yourTypicalSession":"你的典型会话","host.patchMustIncludeFieldsOr":"patch 需包含 fields、colors、timeFormat、timeZones 或 customText 之一","host.timeFormatMustBeAnObject":"timeFormat 必须是对象","host.timeFieldMustBeABoolean":"时间格式字段必须是布尔值: {key}","host.timeZonesMustBeAnObject":"timeZones 必须是对象","host.timeZoneMustBeAValid":"时区必须是有效的 IANA 时区: {key}","host.customTextMustBeAString":"自定义文本必须是字符串","host.customTextTooLong":"自定义文本不能超过64字符","host.quotaDisplayModeInvalid":"订阅窗口百分比方向必须是 used 或 remaining","host.fieldsMustBeAnObject":"fields 必须是对象","host.unknownFieldId":"未知字段 id: {key}","host.fieldVisibilityMustBeA":"字段开关必须是布尔值: {key}","host.colorsMustBeAnObject":"colors 必须是对象","host.colorMustBeAPreset":"颜色只接受预设色名或 #RRGGBB: {key}","field.anchorGroup.label":"服务商与模型","field.anchorGroup.note":"显示当前会话使用的服务商和模型。","field.subServiceGroup.label":"订阅服务与模型","field.subServiceGroup.note":"显示订阅服务和当前模型或套餐。","field.billingServiceGroup.label":"账单服务与模型","field.billingServiceGroup.note":"显示账单服务和当前模型。","field.customText.label":"自定义文字","field.customText.note":"显示一段自定义文字,可用作备注或签名。","field.mainTime.label":"主时间","field.mainTime.note":"显示主时区的时间;时区与格式在「时间与日期」中调整。","field.worldTime.label":"世界时间","field.worldTime.note":"显示另一时区的时间;格式与主时间相同。","field.sessionCost.label":"本次会话花费","field.sessionCost.note":"显示本次会话的实际花费,包含子代理。","field.balance.note":"显示账户余额;余额过低时会标红。","field.period.label":"当前时段","field.period.note":"显示当前是高峰还是空闲时段。","field.countdown.label":"下次价格切换","field.countdown.note":"显示距离下次价格切换还有多久。","field.expiry.label":"订阅到期日","field.expiry.note":"服务商提供到期时间时显示。","field.subWindow5h.label":"5 小时额度","field.subWindow5h.note":"显示滚动 5 小时额度的剩余比例。","field.subWindowWeek.label":"每周额度","field.subWindowWeek.note":"显示每周额度的剩余比例。","field.subWindowMonth.label":"每月额度","field.subWindowMonth.note":"显示每月额度的剩余比例。","field.resetCountdown.label":"距额度重置","field.resetCountdown.note":"显示当前额度何时重置。","field.subBalance.note":"充值账户显示余额;credits 型订阅在没有可显示窗口时显示剩余额度。","field.billingSpend.label":"本月用量","field.billingSpend.note":"显示本计费周期的实际用量或花费。","field.budget.label":"预算使用情况","field.budget.note":"服务商支持时显示已使用的预算比例。","field.freeQuota.label":"免费额度","field.freeQuota.note":"服务商明确提供时显示免费额度和重置时间。","field.turnsSteps.label":"轮次与步数","field.turnsSteps.note":"显示对话的轮次和步数。","field.llmTime.label":"模型耗时","field.llmTime.note":"显示模型推理耗时。","field.toolTime.label":"工具耗时","field.toolTime.note":"显示工具调用耗时。","field.cacheHit.note":"显示提示词缓存命中率。","field.tokensIO.label":"输入/输出 Token","field.tokensIO.note":"显示本次会话的输入和输出用量。","field.contextUsage.label":"上下文用量","field.contextUsage.note":"显示上下文占用情况。","ui.contextAria":"上下文已用 {percent}","ui.contextUsed":"上下文已用","ui.contextSystem":"系统提示词","ui.contextTools":"工具定义","ui.contextMessages":"对话消息","ui.contextFigures":"~{used} / {window}","field.unmapped.label":"暂不支持提示","field.unmapped.note":"当前服务商暂不支持余额查询时显示。","field.noKeyHint.label":"缺少密钥提示","field.noKeyHint.note":"缺少 API Key 时显示设置提示。","field.balanceError.label":"余额更新失败提示","field.balanceError.note":"余额更新失败时显示。","field.usageError.label":"用量更新失败提示","field.usageError.note":"花费暂时不可用时显示。","field.refreshFailure.label":"更新失败提示","field.refreshFailure.note":"任一数据更新失败时显示提醒。","field.persistWarning.label":"记录未保存提醒","field.persistWarning.note":"账单保存失败时显示提醒,建议保留。","field.updateNotice.note":"有新版本时显示提醒。","group.native":"原生信息","group.plugin":"插件信息","ui.listSeparator":"、","ui.sentenceEnd":"。","ui.fieldErrorPrefix":"「{label}」:","ui.turnCount":"{count} 轮","ui.turnCountPlural":"{count} 轮","ui.stepCount":"{count} 步","ui.stepCountPlural":"{count} 步","ui.mainTimeZone":"主时间时区","ui.worldTimeZone":"世界时间时区","ui.timeFormat":"时间格式","ui.year":"年","ui.month":"月","ui.day":"日","ui.hour":"时","ui.minute":"分","ui.second":"秒","ui.customTextTitle":"自定义文本","ui.customTextPlaceholder":"输入文字(最多 64 个字符)","ui.searchPlaceholder":"搜索内容…","ui.searchFieldsLabel":"搜索显示内容","ui.searchResultCount":"找到 {count} 项","ui.enabledFieldsCount":"已启用 {count} 项","ui.noSearchResults":"没有找到匹配内容","ui.timePreview":"预览:","ui.mainTime":"主时间","ui.worldTime":"世界时间","ui.customText":"自定义文本"},"en":{"meta.title":"Bottom Info Bar","meta.description":"Shows the current model, balance and spend under the composer.","ui.requestTimedOut":"Request timed out","ui.requestCanceled":"Request canceled","ui.couldNotParseResponse":"Could not parse response","ui.rpcFailed":"RPC failed","ui.refreshFailed":"Refresh failed","color.red":"Red","color.green":"Green","color.blue":"Blue","color.purple":"Purple","color.orange":"Orange","color.neutral":"Neutral","mode.balance":"Balance","mode.subscription":"Subscription","mode.billing":"Billing","mode.native":"Native stats","mode.common":"General","ui.nativeStatsField":"Native stats field","ui.shownIn":"Shown in: ","ui.pleaseTryAgainLater":"Please try again later","ui.restoreDefaultColor":"Restore default color","ui.infoBarSettings":"Info Bar","ui.settingsAreTemporarilyUnavailable":"Settings are temporarily unavailable","ui.loadingInfoBarSettings":"Loading settings…","ui.couldNotLoadInfoBar":"Could not load Info Bar settings: ","ui.changesAppliedButCouldNot":"Applied, but could not save locally: ","ui.unknownReason":"Unknown reason","ui.couldNotSave":"{errorPrefix}Could not save: {value}","ui.color":"\"{value}\" color: ","ui.hasAnInvalidColorEnter":"\"{value}\" has an invalid color. Enter #RRGGBB (for example, #0044CC).","ui.defaultColorsRestored":"Default colors restored","ui.defaultLabelsRestored":"Default display restored","ui.couldNotReset":"Could not reset: {value}","ui.identifiesTheProviderAndModel":"Shows the provider and model used in this conversation.","ui.show":"Show {label}","ui.clickToHide":"Click to hide","ui.clickToShow":"Click to show","ui.presetColor":"{label} preset color","ui.customColor":"{label} custom color","ui.customColorOpenColorPicker":"Custom color (open color picker)","ui.customColorItem":"Custom…","ui.colorSwatchLabel":"{label} color","ui.hexColor":"{label} hex color","ui.expand":"Expand","ui.collapse":"Collapse","ui.saving":"Saving…","ui.processing":"Working…","ui.visibleFields":"Visible content","ui.timeDateTitle":"Time and date","ui.timeDateDesc":"Time zones and display format for main and world time.","ui.customTextSectionDesc":"Shown in the Info Bar.","ui.resetConfirmTitle":"Reset Info Bar settings","ui.resetConfirmDescFields":"All field switches will be restored to their defaults (all shown). Custom colors are not affected. This applies to the Info Bar right away.","ui.resetConfirmDescColors":"All custom colors will be cleared and defaults restored. Field switches are not affected. This applies to the Info Bar right away.","ui.resetConfirmAcknowledge":"I understand this reset cannot be undone","ui.resetConfirmCancel":"Cancel","ui.resetConfirmConfirm":"Reset","ui.resetLabels":"Restore display","ui.resetColors":"Restore colors","ui.resetRowTitle":"Reset to defaults","ui.resetRowDesc":"Restore display and color settings.","ui.customTextCount":"{value}/64 characters","ui.couldNotDisplayInfoBar":"Could not display Info Bar settings: {value}","ui.dataAndBilling":"Billing data","ui.dataAndBillingDesc":"Export or clear records.","ui.exportBillingRecords":"Export billing","ui.exportBillingRecordsDesc":"Export as CSV or JSON.","ui.exportBillingCsv":"Export CSV","ui.exportBillingJson":"Export JSON","ui.clearBillingRecords":"Clear billing","ui.clearBillingRecordsDesc":"This cannot be undone.","ui.clearBillingRecordsConfirm":"Clear all billing records saved by this plugin? Export first. This cannot be undone, but settings and sign-in information will stay unchanged.","ui.exportedBillingRecords":"Exported {count} billing records ({format})","ui.noBillingRecordsToExport":"There are no billing records to export.","ui.exportFailed":"Export failed: {value}","ui.exportIncomplete":"Some historical billing records could not be read: {value}. Nothing was exported; try again later.","ui.clearFailed":"Could not clear billing records: {value}","ui.clearFailedWithoutDetails":"Billing records could not be fully cleared","ui.clearedBillingRecords":"Cleared {count} billing records","ui.clearCanceled":"Canceled","ui.exportNotSupported":"File downloads are not supported in this environment.","ui.infoBar":"Info Bar","ui.weekly":"Weekly","ui.monthly":"Monthly","ui.window":"Window","ui.quotaDisplayUsed":"Used","ui.quotaDisplayRemaining":"Remaining","ui.quotaDisplayModeTitle":"Subscription window percentage","ui.quotaDisplayModeDesc":"Show subscription quota windows as remaining or used. The warning threshold always follows the remaining 20% rule.","ui.windowUsedRemaining":"{label} window: used {usedPercent}% (remaining {value}%)","ui.windowUsedRemainingResets":"{label} window: used {usedPercent}% (remaining {value}%) · Resets {value4}","ui.minimax":"MiniMax","ui.supportsImageInput":"Supports image input.","ui.vision":"Vision","ui.unknown":"Unknown","ui.unknownModel":"Unknown model","ui.modelSelectionPending":"Reading current model","ui.modelCapabilityPending":"Checking image-input support","ui.pluginVersion":"\nPlugin version: {current}","ui.provider":"Provider: {provLabel} {modelLabel}\n","ui.pricingPeakOffPeakBeijing":"Pricing: peak/off-peak (Beijing time; weekday peaks 09:00-12:00 and 14:00-18:00; weekends off-peak)","ui.pricingFixed":"Pricing: fixed","ui.pricingNotListedUsingDefaults":"Pricing: not listed; spend is not calculated","ui.zhipu":"Zhipu","ui.xiaomiMiMo":"Xiaomi MiMo","ui.commandCode":"Command Code","ui.subscription":"Subscription","ui.cloudBilling":"Cloud billing","ui.plan":"\nPlan: {plan}","ui.expiresLocalTime":"\nExpires: {value} (local time)","ui.subscriptionServiceModel":"Subscription service: {serviceName}\nModel: {rawModelLabel}{planLine}{expiryLine}{versionLine}","ui.balanceLookupIsNotYet":"This provider's balance is not available yet.","ui.notSupported":"Not supported","ui.notConfigured":"Not configured: ","ui.notConfiguredConfigureItIn":"Not configured: {credName}. Configure it in Settings → Models.","ui.notConfiguredSettingsModels":"{credName} is not configured. Add it in Settings → Models.","ui.estimatedBalance":"Estimated balance: {symbol}{value}","ui.balance":"Balance: {symbol}{value}","ui.balance.pushBalanceGroups":"Balance","ui.low":"Low","ui.estimated":"(estimated)","ui.balanceIsTemporarilyUnavailableShowing":"Balance is temporarily unavailable. Showing the last data and retrying automatically.","ui.couldNotLoadBalanceCheck":"Could not load balance. Check your connection and API key.","ui.balanceUnavailable":"Balance unavailable","ui.beijingTime":"Beijing time: ","ui.peakPrice":"Peak price","ui.offPeakPrice":"Off-peak price","ui.input":": input ¥","ui.mCachedInput":"/M · cached input ¥","ui.mOutput":"/M · output ¥","ui.beijingTimeSwitchesTo":"Beijing time: {atLabel} switches to ","ui.until":"Until ","ui.offPeak":"off-peak","ui.peak":"peak","ui.today":"Today {symbol}{value}","ui.lastDays":"Last 30 days {symbol}{value}","ui.allTime":"All time {symbol}{value}","ui.sessionIncludingSubagents":"Session {costTxt} (including subagents){value}","ui.session":"Session","ui.spendIsTemporarilyUnavailableChat":"Spend is temporarily unavailable. Chat is unaffected.","ui.spendUnavailable":"Spend unavailable","ui.noSignInCredentialsFound":"No sign-in credentials found for {serviceName}. Please reauthorize.","ui.credentialsHaveExpiredPleaseReauthorize":"{serviceName} credentials have expired. Please reauthorize.","ui.deniedAccessReauthorizeOrTry":"{serviceName} denied access. Reauthorize or try again later.","ui.rateLimitReachedPleaseTry":"{serviceName} rate limit reached. Please try again later.","ui.timedOutCheckYourConnection":"{serviceName} timed out. Check your connection and try again.","ui.returnedAnUnrecognizedResponsePlease":"{serviceName} returned an unrecognized response. Please try again later.","ui.isTemporarilyUnavailableCheckYour":"{serviceName} is temporarily unavailable. Check your connection and try again.","ui.subscriptionExpiresLocalTime":"Subscription expires: {value} (local time)","ui.expires":"Expires","ui.subscriptionSource":"Subscription source: {value} (","ui.prepaidBalance":"Prepaid balance","ui.availableBalance":"Available balance: {balTxt}","ui.availableCredits":"Credits remaining: {value}","ui.credits":"credits","ui.subscriptionSource.titleLines":"Subscription source: {value}","ui.windowRemainingUsed":"{label} window: remaining {value}% (used {usedPercent}%)","ui.resetsResetsIn":" · Resets {value} · Resets in {value2}","ui.windowRemainingUsedResets":"{label} window: remaining {value}% (used {usedPercent}%) · Resets {value4}","ui.resetsIn":"Resets in","ui.configureItInSettingsModels":". Configure it in Settings → Models.","ui.deniedAccessTheTokenMay":"{serviceName} denied access: the token may lack billing read permissions.","ui.billingIsTemporarilyUnavailableCheck":"{serviceName} billing is temporarily unavailable. Check your connection and permissions, then try again.","ui.billingSource":"Billing source: {value}","ui.thisMonthSSpend":"This month’s spend: {symbol}{value}","ui.budgetUsed":"Budget used: {value}%","ui.dailyFreeQuotaRemaining":"Daily free quota remaining: {value}","ui.thisMonth":"This month","ui.thisMonthSUsage":"This month’s usage","ui.budget":"Budget","ui.free":"Free","ui.resetsIn.pushBillingGroups":"{value} · Resets in {value2}","ui.billingServiceModel":"Billing service: {serviceName}\nModel: {modelLabel}{versionLine}","ui.pricing":"Pricing","ui.spend":"Spend","ui.mode":"Mode","ui.subscriptionQuota":"Subscription quota","ui.billing":"Billing","ui.temporarilyUnavailableKeepingTheLast":": temporarily unavailable. Keeping the last data and retrying automatically.","ui.spendJournalSavedButThe":"Spend journal saved, but the readable ledger has not been updated: ","ui.thisSpendRecordWasNot":"This spend record was not saved and will not be added to totals: ","ui.ledgerUpdatePending":"Ledger update pending","ui.spendNotSaved":"Spend not saved","ui.askYourAgentToUpdate":"Ask your agent to update this plugin to version {latest}.\nOr click this label to copy the update command, paste it in a terminal, then restart DSH.","ui.updateAvailable":"Update available","ui.updateCommandCopied":"Update command copied","ui.tools":"Tools","ui.avgTTFT":"Avg. TTFT","ui.cacheHit":"Cache hit","ui.input.BottomInfoBar":"Input","ui.output":"Output","ui.savingView":"Saving view…","ui.clickToSwitchFullCompact":"Click to switch full/compact view","ui.pressEnterOrSpaceFor":"Press Enter or Space for compact view.","ui.pressEnterOrSpaceFor.BottomInfoBar":"Press Enter or Space for full view.","host.hour":"5-hour","host.unknownProvider":"Unknown provider","error.subscription.request-failed":"Unexpected subscription quota request failure","host.settingsFileCouldNotBe":"Settings file could not be saved","host.everydayQuestions":"Everyday questions","host.mediumCodingTask":"Medium coding task","host.longDocumentAnalysisCodeReview":"Long document analysis / code review","host.largeProjectRefactorAcrossMultiple":"Large project refactor across multiple turns","host.subagentWorkflow":"Subagent workflow","error.settings.save-failed":"Could not save settings.json: {value}","error.balance.credentials":"Could not read credentials","error.balance.not-configured":"Not configured: {credential}","error.request.http":"Request failed: HTTP {status}.","error.request.parse":"Unexpected response format","error.subscription.not-connected":"ChatGPT subscription is not connected: credentials not found in ~/.codex/auth.json. Install dsh-chatgpt-subscription and sign in.","error.subscription.credentials-missing":"ChatGPT subscription credentials are missing id_token. Install dsh-chatgpt-subscription and reauthorize.","error.subscription.opencode-not-configured":"OpenCode Go is not configured. Set OPENCODE_GO_API_KEY or use opencode auth.json.","error.subscription.commandcode-not-configured":"Command Code is not configured. Set COMMAND_CODE_API_KEY, CMD_API_KEY, or sign in with the Command Code CLI.","error.subscription.commandcode-auth-failed":"Command Code credentials were rejected. Sign in again or update the API key.","error.subscription.commandcode-unrecognized":"Command Code returned an unrecognized quota format; the previous snapshot was kept.","host.zhipu":"Zhipu {mapped}","host.zhipu.parseZaiQuota":"Zhipu {value}{value2}","error.subscription.zhipu-not-configured":"Zhipu API key is not configured. Set ZAI_API_KEY or ZAI_CODING_CN_API_KEY.","error.subscription.zhipu-auth-failed":"Zhipu API authentication failed: the key is expired or invalid.","error.subscription.zhipu-unrecognized":"Zhipu returned an unrecognized quota format (the API may have changed); the last known data is kept.","error.request.failed":"Request failed: {value} {msg}.","error.subscription.xiaomi-not-configured":"Xiaomi MiMo Token Plan credentials are not configured: {credName} or XIAOMI_API_KEY.","error.subscription.xiaomi-http":"Request failed: HTTP {value}.","error.subscription.minimax-not-configured":"MiniMax is not configured. Set MINIMAX_API_KEY or MINIMAX_CN_API_KEY. Token Plan queries require a Subscription Key; pay-as-you-go API keys are rejected by the server.","error.subscription.minimax-auth-failed":"MiniMax rejected the API key: Token Plan queries require a Subscription Key (generated on the Token Plan subscription page). Pay-as-you-go keys are rejected (status_code=1004 / HTTP 401).","error.subscription.minimax-unrecognized":"MiniMax returned an unrecognized quota format (the API may have changed); the last known data is kept.","error.billing.together-not-configured":"Not configured: TOGETHER_API_KEY","host.actualMonthlyBillFromThe":"Actual monthly bill from the Together Usage API","error.billing.fireworks-not-configured":"Not configured: FIREWORKS_API_KEY","error.billing.fireworks-account":"Could not read account (account_id missing)","host.actualBillForThisPeriod":"Actual bill for this period (Fireworks Billing Summary)","host.actualUsageForThisPeriod":"Actual usage for this period (billingUsage fallback; no spend amount)","error.billing.aws-not-configured":"Not configured: AWS credentials (AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY)","error.billing.aws-http":"Request failed: HTTP {status}. The token may lack ce:GetCostAndUsage permission","host.actualMonthlyBillFromAWS":"Actual monthly bill from AWS Cost Explorer (about 24 hours behind)","error.billing.cloudflare-not-configured":"Not configured: CLOUDFLARE_API_KEY (requires an account-level token with Billing read permission)","error.billing.cloudflare-account":"Not configured: CLOUDFLARE_ACCOUNT_ID","error.billing.cloudflare-http":"Request failed: HTTP {status}. The token requires Billing read permission","host.actualMonthlyUsageFromThe":"Actual monthly usage from the Cloudflare Billable Usage API (Alpha)","error.billing.request-failed":"Unexpected billing request failure","host.spendSummaryFileMissingArchived":"Spend summary file missing: archived amounts are not included in displayed totals. Details remain in usage-archive/ for manual recovery.","host.spendLedgerCouldNotBe":"Spend ledger could not be saved","host.usageLedgerBusy":"A response is still in progress. Clear billing records after it finishes.","error.ledger.clear-failed":"Billing records could not be fully cleared: {value}","error.ledger.snapshot-stale":"Could not save archived spend summaries: {value}","host.basedOnYourLastSessions":"Based on your last {count} sessions","host.estimatedFromSpendingOverThe":"Estimated from spending over the last {SPEND_DAYS} days","host.yourTypicalSession":"Your typical session","host.patchMustIncludeFieldsOr":"patch must include fields, colors, timeFormat, timeZones or customText","host.timeFormatMustBeAnObject":"timeFormat must be an object","host.timeFieldMustBeABoolean":"Time format field must be a boolean: {key}","host.timeZonesMustBeAnObject":"timeZones must be an object","host.timeZoneMustBeAValid":"Time zone must be a valid IANA zone: {key}","host.customTextMustBeAString":"Custom text must be a string","host.customTextTooLong":"Custom text must not exceed 64 characters","host.quotaDisplayModeInvalid":"Subscription window percentage mode must be \"used\" or \"remaining\"","host.fieldsMustBeAnObject":"fields must be an object","host.unknownFieldId":"Unknown field id: {key}","host.fieldVisibilityMustBeA":"Field visibility must be a boolean: {key}","host.colorsMustBeAnObject":"colors must be an object","host.colorMustBeAPreset":"Color must be a preset name or #RRGGBB: {key}","field.anchorGroup.label":"Provider and model","field.anchorGroup.note":"Shows the provider and model used in this conversation.","field.subServiceGroup.label":"Subscription service and model","field.subServiceGroup.note":"Shows the subscription service and current model or plan.","field.billingServiceGroup.label":"Billing service and model","field.billingServiceGroup.note":"Shows the billing service and current model.","field.customText.label":"Custom text","field.customText.note":"Shows custom text for a note or signature.","field.mainTime.label":"Main time","field.mainTime.note":"Shows the main time zone; adjust zone and format in Time and date.","field.worldTime.label":"World time","field.worldTime.note":"Shows another time zone; it shares the main time format.","field.sessionCost.label":"Session spend","field.sessionCost.note":"Shows actual spend for this session, including subagents.","field.balance.note":"Shows the account balance; a low balance appears in red.","field.period.label":"Current period","field.period.note":"Shows whether the current period is peak or off-peak.","field.countdown.label":"Next price change","field.countdown.note":"Shows the time until the next price change.","field.expiry.label":"Subscription expiry","field.expiry.note":"Shown when the provider supplies an expiry date.","field.subWindow5h.label":"5-hour quota","field.subWindow5h.note":"Shows the remaining rolling 5-hour quota.","field.subWindowWeek.label":"Weekly quota","field.subWindowWeek.note":"Shows the remaining weekly quota.","field.subWindowMonth.label":"Monthly quota","field.subWindowMonth.note":"Shows the remaining monthly quota.","field.resetCountdown.label":"Quota reset","field.resetCountdown.note":"Shows when the current quota resets.","field.subBalance.note":"Shows prepaid balance, or remaining credits when a credits subscription has no visible quota window.","field.billingSpend.label":"Monthly usage","field.billingSpend.note":"Shows actual usage or spend for the current billing period.","field.budget.label":"Budget status","field.budget.note":"Shown when the provider reports a budget percentage.","field.freeQuota.label":"Free quota","field.freeQuota.note":"Shown when the provider reports a free allowance and reset time.","field.turnsSteps.label":"Turns and steps","field.turnsSteps.note":"Shows conversation turns and steps.","field.llmTime.label":"Model time","field.llmTime.note":"Shows model inference time.","field.toolTime.label":"Tool time","field.toolTime.note":"Shows tool execution time.","field.cacheHit.note":"Shows the prompt cache hit rate.","field.tokensIO.label":"Input / output tokens","field.tokensIO.note":"Shows this session’s input and output usage.","field.contextUsage.label":"Context usage","field.contextUsage.note":"Shows context usage.","ui.contextAria":"{percent} of context used","ui.contextUsed":"Context used","ui.contextSystem":"System prompt","ui.contextTools":"Tool definitions","ui.contextMessages":"Conversation messages","ui.contextFigures":"~{used} / {window}","field.unmapped.label":"Unsupported hint","field.unmapped.note":"Shown when balance lookup is not supported.","field.noKeyHint.label":"Missing key hint","field.noKeyHint.note":"Shown when an API key is missing.","field.balanceError.label":"Balance update error","field.balanceError.note":"Shown when balance update fails.","field.usageError.label":"Usage update error","field.usageError.note":"Shown when spend data is temporarily unavailable.","field.refreshFailure.label":"Update error","field.refreshFailure.note":"Shown when any data update fails.","field.persistWarning.label":"Unsaved record alert","field.persistWarning.note":"Shown when billing records cannot be saved; recommended.","field.updateNotice.note":"Shown when a new version is available.","group.native":"Native information","group.plugin":"Plugin information","ui.listSeparator":", ","ui.sentenceEnd":".","ui.fieldErrorPrefix":"\"{label}\": ","ui.turnCount":"{count} turn","ui.turnCountPlural":"{count} turns","ui.stepCount":"{count} step","ui.stepCountPlural":"{count} steps","ui.mainTimeZone":"Main time zone","ui.worldTimeZone":"World time zone","ui.timeFormat":"Time format","ui.year":"Year","ui.month":"Month","ui.day":"Day","ui.hour":"Hour","ui.minute":"Minute","ui.second":"Second","ui.customTextTitle":"Custom text","ui.customTextPlaceholder":"Enter text (up to 64 characters)","ui.searchPlaceholder":"Search content…","ui.searchFieldsLabel":"Search visible content","ui.searchResultCount":"{count} found","ui.enabledFieldsCount":"{count} enabled","ui.noSearchResults":"No matching content","ui.timePreview":"Preview: ","ui.mainTime":"Main time","ui.worldTime":"World time","ui.customText":"Custom text"}};
|
|
62
|
+
const LOCALES = {"zh":{"meta.title":"底部信息栏","meta.description":"在输入框下方显示当前模型、余额和花费。","ui.requestTimedOut":"请求超时","ui.requestCanceled":"请求已取消","ui.couldNotParseResponse":"响应解析失败","ui.rpcFailed":"RPC 失败","ui.refreshFailed":"刷新失败","color.red":"红","color.green":"绿","color.blue":"蓝","color.purple":"紫","color.orange":"橙","color.neutral":"中性","mode.balance":"余额制","mode.subscription":"订阅制","mode.billing":"账单制","mode.native":"原生统计行","mode.common":"通用","ui.nativeStatsField":"原生统计行字段","ui.shownIn":"出现于","ui.pleaseTryAgainLater":"请稍后再试","ui.restoreDefaultColor":"恢复默认颜色","ui.infoBarSettings":"信息栏","ui.settingsAreTemporarilyUnavailable":"暂时无法读取设置","ui.loadingInfoBarSettings":"正在加载设置…","ui.couldNotLoadInfoBar":"无法读取信息栏设置:","ui.changesAppliedButCouldNot":"已应用,但无法保存到本地:","ui.unknownReason":"未知原因","ui.couldNotSave":"{errorPrefix}保存失败:{value}","ui.color":"“{value}”颜色:","ui.hasAnInvalidColorEnter":"“{value}”的颜色格式不正确,请输入 #RRGGBB(例如 #0044CC)。","ui.defaultColorsRestored":"已恢复默认颜色","ui.defaultLabelsRestored":"已恢复默认显示设置","ui.couldNotReset":"重置失败:{value}","ui.identifiesTheProviderAndModel":"显示当前会话使用的服务商和模型。","ui.show":"显示{label}","ui.clickToHide":"点击隐藏","ui.clickToShow":"点击显示","ui.presetColor":"{label}的预设颜色","ui.customColor":"{label}的自定义颜色","ui.customColorOpenColorPicker":"自定义颜色(打开系统取色器)","ui.customColorItem":"自定义…","ui.colorSwatchLabel":"{label}的颜色","ui.hexColor":"{label}的十六进制颜色","ui.expand":"展开","ui.collapse":"收起","ui.saving":"正在保存…","ui.processing":"正在处理…","ui.visibleFields":"显示内容","ui.displayModeTitle":"信息显示方式","ui.displayModeDesc":"简洁只显示服务商、模型和一项关键账户信息;完整才显示更多细节。也可以直接点击底部信息栏切换。","ui.compactMode":"简洁","ui.fullMode":"完整","ui.fullModeContentTitle":"完整模式内容","ui.fullModeContentDesc":"这些内容只在完整模式显示,不影响简洁模式。","ui.accountDetailsTitle":"账户详情","ui.accountDetailsDesc":"显示重置时间、订阅到期、会话花费、预算和免费额度。","ui.conversationStatsTitle":"对话统计","ui.conversationStatsDesc":"显示轮次、耗时、缓存、Token 和上下文用量。","ui.advancedSettingsTitle":"高级设置","ui.advancedSettingsDesc":"逐项显示、时间、自定义文字和颜色只适合有明确需求时调整。","ui.timeDateTitle":"时间与日期","ui.timeDateDesc":"主时间和世界时间的时区与显示格式。","ui.customTextSectionDesc":"显示在信息栏中。","ui.resetConfirmTitle":"重置信息栏设置","ui.resetConfirmDescFields":"将恢复信息显示方式、完整模式内容和高级显示设置;自定义颜色不受影响。该操作会直接应用到信息栏。","ui.resetConfirmDescColors":"将清除全部自定义颜色并恢复默认配色,字段显示开关不受影响。该操作会直接应用到信息栏。","ui.resetConfirmAcknowledge":"我了解这次重置不可撤销","ui.resetConfirmCancel":"取消","ui.resetConfirmConfirm":"确认重置","ui.resetLabels":"恢复显示","ui.resetColors":"恢复颜色","ui.resetRowTitle":"恢复默认","ui.resetRowDesc":"恢复显示偏好或颜色设置。","ui.customTextCount":"已输入 {value}/64 个字符","ui.couldNotDisplayInfoBar":"无法显示信息栏设置:{value}","ui.dataAndBilling":"账单数据","ui.dataAndBillingDesc":"导出或清除记录。","ui.exportBillingRecords":"导出账单","ui.exportBillingRecordsDesc":"导出为 CSV 或 JSON。","ui.exportBillingCsv":"导出 CSV","ui.exportBillingJson":"导出 JSON","ui.clearBillingRecords":"清除账单","ui.clearBillingRecordsDesc":"清除后无法恢复。","ui.clearBillingRecordsConfirm":"确定清除本插件保存的全部账单记录吗?建议先导出。清除后无法恢复,但不会影响设置或登录信息。","ui.exportedBillingRecords":"已导出 {count} 条账单记录({format})","ui.noBillingRecordsToExport":"目前没有可导出的账单记录。","ui.exportFailed":"导出失败:{value}","ui.exportIncomplete":"历史账单读取不完整:{value}。本次未导出,请稍后再试。","ui.clearFailed":"清除失败:{value}","ui.clearFailedWithoutDetails":"账单记录未能全部清除","ui.clearedBillingRecords":"已清除 {count} 条账单记录","ui.clearCanceled":"已取消","ui.exportNotSupported":"当前环境不支持下载文件。","ui.infoBar":"信息栏","ui.weekly":"周","ui.monthly":"月","ui.window":"窗口","ui.quotaDisplayUsed":"已用","ui.quotaDisplayRemaining":"剩余","ui.quotaDisplayModeTitle":"订阅窗口百分比方向","ui.quotaDisplayModeDesc":"订阅额度窗口按剩余或已用显示;告警阈值始终按剩余 20% 判定。","ui.windowUsedRemaining":"{label}窗口:已用 {usedPercent}%(剩余 {value}%)","ui.windowUsedRemainingResets":"{label}窗口 已用 {usedPercent}%(剩余 {value}%) · 重置 {value4}","ui.minimax":"MiniMax","ui.supportsImageInput":"支持图像输入。","ui.vision":"视觉","ui.unknown":"未知","ui.unknownModel":"未知模型","ui.modelSelectionPending":"正在读取当前模型","ui.modelCapabilityPending":"正在确认是否支持图像输入","ui.pluginVersion":"\n插件版本:{current}","ui.provider":"服务商:{provLabel} {modelLabel}\n","ui.pricingPeakOffPeakBeijing":"定价:峰谷价(工作日高峰 9-12、14-18 点;周末全天空闲)","ui.pricingFixed":"定价:固定价","ui.pricingNotListedUsingDefaults":"定价:暂未收录,不计算花费","ui.zhipu":"智谱","ui.xiaomiMiMo":"小米 MiMo","ui.commandCode":"Command Code","ui.subscription":"订阅","ui.cloudBilling":"云账单","ui.plan":"\n套餐:{plan}","ui.expiresLocalTime":"\n到期:{value}(本地时区)","ui.subscriptionServiceModel":"订阅服务:{serviceName}\n模型:{rawModelLabel}{planLine}{expiryLine}{versionLine}","ui.balanceLookupIsNotYet":"暂时无法读取该服务商的余额。","ui.notSupported":"未适配","ui.notConfigured":"未配置 ","ui.notConfiguredConfigureItIn":"未配置 {credName}。请在\"设置 → 模型\"中填写。","ui.notConfiguredSettingsModels":"未配置 {credName}。请在设置 → 模型中填写。","ui.estimatedBalance":"估算余额:{symbol}{value}","ui.balance":"余额:{symbol}{value}","ui.balance.pushBalanceGroups":"余额","ui.low":"低","ui.estimated":"(估算)","ui.balanceIsTemporarilyUnavailableShowing":"余额暂不可用;正在显示上次数据并自动重试。","ui.couldNotLoadBalanceCheck":"余额获取失败。请检查网络和 API Key。","ui.balanceUnavailable":"余额获取失败","ui.beijingTime":"北京时间 ","ui.peakPrice":"高峰价","ui.offPeakPrice":"空闲价","ui.input":":输入 ¥","ui.mCachedInput":"/M · 缓存 ¥","ui.mOutput":"/M · 输出 ¥","ui.beijingTimeSwitchesTo":"北京时间 {atLabel} 切换为","ui.until":"距","ui.offPeak":"空闲","ui.peak":"高峰","ui.today":"今天 {symbol}{value}","ui.lastDays":"近一月 {symbol}{value}","ui.allTime":"全部 {symbol}{value}","ui.sessionIncludingSubagents":"本会话 {costTxt}(含子代理){value}","ui.session":"本会话","ui.spendIsTemporarilyUnavailableChat":"花费暂不可用;不会影响对话。","ui.spendUnavailable":"花费获取失败","ui.noSignInCredentialsFound":"未找到 {serviceName} 登录凭证。请重新授权。","ui.credentialsHaveExpiredPleaseReauthorize":"{serviceName} 登录凭证已失效。请重新授权。","ui.deniedAccessReauthorizeOrTry":"{serviceName} 拒绝访问。请重新授权或稍后再试。","ui.rateLimitReachedPleaseTry":"{serviceName} 请求过于频繁。请稍后再试。","ui.timedOutCheckYourConnection":"{serviceName} 响应超时。请检查网络后再试。","ui.returnedAnUnrecognizedResponsePlease":"{serviceName} 返回的数据暂时无法识别。请稍后再试。","ui.isTemporarilyUnavailableCheckYour":"{serviceName} 暂不可用。请检查网络后再试。","ui.subscriptionExpiresLocalTime":"订阅到期:{value}(本地时区)","ui.expires":"到期","ui.subscriptionSource":"订阅源:{value}(","ui.prepaidBalance":"可用余额","ui.availableBalanceLabel":"可用余额","ui.remainingCredits":"剩余额度","ui.availableBalance":"可用余额:{balTxt}","ui.availableCredits":"剩余 credits:{value}","ui.credits":"积分","ui.subscriptionSource.titleLines":"订阅源:{value}","ui.windowRemainingUsed":"{label}窗口:剩余 {value}%(已用 {usedPercent}%)","ui.resetsResetsIn":" · 重置 {value} · 距重置 {value2}","ui.windowRemainingUsedResets":"{label}窗口 剩余 {value}%(已用 {usedPercent}%) · 重置 {value4}","ui.resetsIn":"距重置","ui.configureItInSettingsModels":"。请在\"设置 → 模型\"中填写。","ui.deniedAccessTheTokenMay":"{serviceName} 拒绝访问:Token 可能缺少账单读取权限。","ui.billingIsTemporarilyUnavailableCheck":"{serviceName} 账单暂不可用。请检查网络与权限后再试。","ui.billingSource":"账单源:{value}","ui.thisMonthSSpend":"本月花费:{symbol}{value}","ui.budgetUsed":"预算使用:{value}%","ui.dailyFreeQuotaRemaining":"每日免费额度剩余:{value}","ui.thisMonth":"本月","ui.thisMonthSUsage":"本月用量","ui.budget":"预算","ui.free":"免费","ui.resetsIn.pushBillingGroups":"{value} · 距重置 {value2}","ui.billingServiceModel":"账单服务:{serviceName}\n模型:{modelLabel}{versionLine}","ui.pricing":"定价","ui.spend":"花费","ui.mode":"模式","ui.subscriptionQuota":"订阅额度","ui.billing":"账单","ui.temporarilyUnavailableKeepingTheLast":"暂不可用;正在保留上次数据并自动重试。","ui.spendJournalSavedButThe":"账单流水已保存,但可直接查看的账单文件暂未更新:","ui.thisSpendRecordWasNot":"本次账单未保存,不会计入金额:","ui.ledgerUpdatePending":"账单待整理","ui.spendNotSaved":"账单未保存","ui.askYourAgentToUpdate":"发现插件新版本 {latest}。桌面端更新请在插件管理中完成。","ui.updateAvailable":"新版本提醒","ui.updateCommandCopied":"更新命令已复制","ui.tools":"工具调用","ui.avgTTFT":"首 token 平均","ui.cacheHit":"缓存命中","ui.input.BottomInfoBar":"输入","ui.output":"输出","ui.savingView":"正在保存切换…","ui.clickToSwitchFullCompact":"单击切换 完整/简洁","ui.pressEnterOrSpaceFor":"按 Enter 或空格切换为简洁模式。","ui.pressEnterOrSpaceFor.BottomInfoBar":"按 Enter 或空格切换为完整模式。","host.hour":"5 小时","host.unknownProvider":"未知服务商","error.subscription.request-failed":"订阅额度请求未知异常","host.settingsFileCouldNotBe":"设置文件写入未完成","host.everydayQuestions":"日常问答","host.mediumCodingTask":"中等编码任务","host.longDocumentAnalysisCodeReview":"长文档分析/代码审查","host.largeProjectRefactorAcrossMultiple":"大工程重构(多轮)","host.subagentWorkflow":"子代理工作流","error.settings.save-failed":"settings.json 落盘失败:{value}","error.balance.credentials":"凭据读取失败","error.balance.not-configured":"未配置 {credential}","error.request.http":"请求失败(HTTP {status})","error.request.parse":"响应格式异常","error.subscription.not-connected":"未找到 ChatGPT 订阅登录凭证(~/.codex/auth.json),请安装 dsh-chatgpt-subscription 插件绑定","error.subscription.credentials-missing":"ChatGPT 订阅登录凭证缺少 id_token,请安装 dsh-chatgpt-subscription 插件重新绑定","error.subscription.opencode-not-configured":"未配置 OpenCode Go(OPENCODE_GO_API_KEY 或 opencode auth.json)","error.subscription.commandcode-not-configured":"未配置 Command Code(COMMAND_CODE_API_KEY、CMD_API_KEY 或 ~/.commandcode/auth.json)","error.subscription.commandcode-auth-failed":"Command Code 登录凭证已失效。请重新登录或更新 API Key","error.subscription.commandcode-unrecognized":"Command Code 返回了无法识别的额度格式(接口可能已变更),已保留上次数据","host.zhipu":"智谱 {mapped}","host.zhipu.parseZaiQuota":"智谱 {value}{value2}","error.subscription.zhipu-not-configured":"未配置智谱 API Key(ZAI_API_KEY 或 ZAI_CODING_CN_API_KEY)","error.subscription.zhipu-auth-failed":"智谱 API 认证失败(密钥过期或不正确)","error.subscription.zhipu-unrecognized":"智谱返回了无法识别的额度格式(接口可能已变更),已保留上次数据","error.request.failed":"请求失败({value} {msg})","error.subscription.xiaomi-not-configured":"未配置小米 MiMo Token Plan 凭据({credName} 或 XIAOMI_API_KEY)","error.subscription.xiaomi-http":"请求失败(HTTP {value})","error.subscription.minimax-not-configured":"未配置 MiniMax 凭据(MINIMAX_API_KEY 或 MINIMAX_CN_API_KEY)。查询 Token Plan 必须使用 Subscription Key,按量 API Key 会被服务端拒绝","error.subscription.minimax-auth-failed":"MiniMax 拒绝了当前 API Key:查询 Token Plan 必须使用 Subscription Key(在 Token Plan 订阅页生成),按量 API Key 会被服务端拒绝(status_code=1004 / HTTP 401)","error.subscription.minimax-unrecognized":"MiniMax 返回了无法识别的额度格式(接口可能已变更),已保留上次数据","error.billing.together-not-configured":"未配置 TOGETHER_API_KEY","host.actualMonthlyBillFromThe":"本月真实账单(Together 官方 Usage API)","error.billing.fireworks-not-configured":"未配置 FIREWORKS_API_KEY","error.billing.fireworks-account":"账户解析失败(未取得 account_id)","host.actualBillForThisPeriod":"本周期真实账单(Fireworks Billing Summary)","host.actualUsageForThisPeriod":"本周期真实用量(billingUsage 回退端点,无金额)","error.billing.aws-not-configured":"未配置 AWS 凭据(AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY)","error.billing.aws-http":"请求失败(HTTP {status}),可能缺少 ce:GetCostAndUsage 权限","host.actualMonthlyBillFromAWS":"AWS Cost Explorer 本月真实账单(账单延迟约 24 小时)","error.billing.cloudflare-not-configured":"未配置 CLOUDFLARE_API_KEY(需账号级 Token 并授予 Billing 读权限)","error.billing.cloudflare-account":"未配置 CLOUDFLARE_ACCOUNT_ID","error.billing.cloudflare-http":"请求失败(HTTP {status}),Token 需 Billing 读权限","host.actualMonthlyUsageFromThe":"Cloudflare Billable Usage API(Alpha),本月真实用量","error.billing.request-failed":"账单请求未知异常","host.spendSummaryFileMissingArchived":"账单汇总文件缺失:折叠期间的历史金额暂未计入显示(明细仍在冷归档 usage-archive/,可人工恢复)","host.spendLedgerCouldNotBe":"账单文件写入未完成","host.usageLedgerBusy":"当前仍有回答正在进行,完成后再清除账单记录","error.ledger.clear-failed":"账单记录清理未完成:{value}","error.ledger.snapshot-stale":"折叠汇总落盘失败:{value}","host.basedOnYourLastSessions":"基于你最近 {count} 次会话","host.estimatedFromSpendingOverThe":"基于过去 {SPEND_DAYS} 天消耗速度的估算","host.yourTypicalSession":"你的典型会话","host.patchMustIncludeFieldsOr":"patch 需包含 fields、colors、timeFormat、timeZones 或 customText 之一","host.timeFormatMustBeAnObject":"timeFormat 必须是对象","host.timeFieldMustBeABoolean":"时间格式字段必须是布尔值: {key}","host.timeZonesMustBeAnObject":"timeZones 必须是对象","host.timeZoneMustBeAValid":"时区必须是有效的 IANA 时区: {key}","host.customTextMustBeAString":"自定义文本必须是字符串","host.customTextTooLong":"自定义文本不能超过64字符","host.quotaDisplayModeInvalid":"订阅窗口百分比方向必须是 used 或 remaining","host.infoDensityMustBeFullOrCompact":"信息显示方式必须是完整或简洁","host.displayPreferencesMustBeAnObject":"显示偏好必须是有效的开关对象","host.fieldsMustBeAnObject":"fields 必须是对象","host.unknownFieldId":"未知字段 id: {key}","host.fieldVisibilityMustBeA":"字段开关必须是布尔值: {key}","host.colorsMustBeAnObject":"colors 必须是对象","host.colorMustBeAPreset":"颜色只接受预设色名或 #RRGGBB: {key}","field.anchorGroup.label":"服务商与模型","field.anchorGroup.note":"显示当前会话使用的服务商和模型。","field.subServiceGroup.label":"订阅服务与模型","field.subServiceGroup.note":"显示订阅服务和当前模型或套餐。","field.billingServiceGroup.label":"账单服务与模型","field.billingServiceGroup.note":"显示账单服务和当前模型。","field.customText.label":"自定义文字","field.customText.note":"显示一段自定义文字,可用作备注或签名。","field.mainTime.label":"主时间","field.mainTime.note":"显示主时区的时间;时区与格式在「时间与日期」中调整。","field.worldTime.label":"世界时间","field.worldTime.note":"显示另一时区的时间;格式与主时间相同。","field.sessionCost.label":"本次会话花费","field.sessionCost.note":"显示本次会话的实际花费,包含子代理。","field.balance.note":"显示账户余额;余额过低时会标红。","field.period.label":"当前时段","field.period.note":"显示当前是高峰还是空闲时段。","field.countdown.label":"下次价格切换","field.countdown.note":"显示距离下次价格切换还有多久。","field.expiry.label":"订阅到期日","field.expiry.note":"服务商提供到期时间时显示。","field.subWindow5h.label":"5 小时额度","field.subWindow5h.note":"显示滚动 5 小时额度的剩余比例。","field.subWindowWeek.label":"每周额度","field.subWindowWeek.note":"显示每周额度的剩余比例。","field.subWindowMonth.label":"每月额度","field.subWindowMonth.note":"显示每月额度的剩余比例。","field.resetCountdown.label":"距额度重置","field.resetCountdown.note":"显示当前额度何时重置。","field.subBalance.label":"可用余额或剩余额度","field.subBalance.note":"按量账户显示可用余额;没有额度窗口的 credits 订阅显示剩余额度。","field.billingSpend.label":"本月用量","field.billingSpend.note":"显示本计费周期的实际用量或花费。","field.budget.label":"预算使用情况","field.budget.note":"服务商支持时显示已使用的预算比例。","field.freeQuota.label":"免费额度","field.freeQuota.note":"服务商明确提供时显示免费额度和重置时间。","field.turnsSteps.label":"轮次与步数","field.turnsSteps.note":"显示对话的轮次和步数。","field.llmTime.label":"模型耗时","field.llmTime.note":"显示模型推理耗时。","field.toolTime.label":"工具耗时","field.toolTime.note":"显示工具调用耗时。","field.cacheHit.note":"显示提示词缓存命中率。","field.tokensIO.label":"输入/输出 Token","field.tokensIO.note":"显示本次会话的输入和输出用量。","field.contextUsage.label":"上下文用量","field.contextUsage.note":"显示上下文占用情况。","ui.contextAria":"上下文已用 {percent}","ui.contextUsed":"上下文已用","ui.contextSystem":"系统提示词","ui.contextTools":"工具定义","ui.contextMessages":"对话消息","ui.contextFigures":"~{used} / {window}","field.unmapped.label":"暂不支持提示","field.unmapped.note":"当前服务商暂不支持余额查询时显示。","field.noKeyHint.label":"缺少密钥提示","field.noKeyHint.note":"缺少 API Key 时显示设置提示。","field.balanceError.label":"余额更新失败提示","field.balanceError.note":"余额更新失败时显示。","field.usageError.label":"用量更新失败提示","field.usageError.note":"花费暂时不可用时显示。","field.refreshFailure.label":"更新失败提示","field.refreshFailure.note":"任一数据更新失败时显示提醒。","field.persistWarning.label":"记录未保存提醒","field.persistWarning.note":"账单保存失败时显示提醒,建议保留。","field.updateNotice.note":"有新版本时显示提醒。","group.native":"原生信息","group.plugin":"插件信息","ui.listSeparator":"、","ui.sentenceEnd":"。","ui.fieldErrorPrefix":"「{label}」:","ui.turnCount":"{count} 轮","ui.turnCountPlural":"{count} 轮","ui.stepCount":"{count} 步","ui.stepCountPlural":"{count} 步","ui.mainTimeZone":"主时间时区","ui.worldTimeZone":"世界时间时区","ui.timeFormat":"时间格式","ui.year":"年","ui.month":"月","ui.day":"日","ui.hour":"时","ui.minute":"分","ui.second":"秒","ui.customTextTitle":"自定义文本","ui.customTextPlaceholder":"输入文字(最多 64 个字符)","ui.searchPlaceholder":"搜索内容…","ui.searchFieldsLabel":"搜索显示内容","ui.searchResultCount":"找到 {count} 项","ui.enabledFieldsCount":"已启用 {count} 项","ui.noSearchResults":"没有找到匹配内容","ui.timePreview":"预览:","ui.mainTime":"主时间","ui.worldTime":"世界时间","ui.customText":"自定义文本"},"en":{"meta.title":"Bottom Info Bar","meta.description":"Shows the current model, balance and spend under the composer.","ui.requestTimedOut":"Request timed out","ui.requestCanceled":"Request canceled","ui.couldNotParseResponse":"Could not parse response","ui.rpcFailed":"RPC failed","ui.refreshFailed":"Refresh failed","color.red":"Red","color.green":"Green","color.blue":"Blue","color.purple":"Purple","color.orange":"Orange","color.neutral":"Neutral","mode.balance":"Balance","mode.subscription":"Subscription","mode.billing":"Billing","mode.native":"Native stats","mode.common":"General","ui.nativeStatsField":"Native stats field","ui.shownIn":"Shown in: ","ui.pleaseTryAgainLater":"Please try again later","ui.restoreDefaultColor":"Restore default color","ui.infoBarSettings":"Info Bar","ui.settingsAreTemporarilyUnavailable":"Settings are temporarily unavailable","ui.loadingInfoBarSettings":"Loading settings…","ui.couldNotLoadInfoBar":"Could not load Info Bar settings: ","ui.changesAppliedButCouldNot":"Applied, but could not save locally: ","ui.unknownReason":"Unknown reason","ui.couldNotSave":"{errorPrefix}Could not save: {value}","ui.color":"\"{value}\" color: ","ui.hasAnInvalidColorEnter":"\"{value}\" has an invalid color. Enter #RRGGBB (for example, #0044CC).","ui.defaultColorsRestored":"Default colors restored","ui.defaultLabelsRestored":"Default display restored","ui.couldNotReset":"Could not reset: {value}","ui.identifiesTheProviderAndModel":"Shows the provider and model used in this conversation.","ui.show":"Show {label}","ui.clickToHide":"Click to hide","ui.clickToShow":"Click to show","ui.presetColor":"{label} preset color","ui.customColor":"{label} custom color","ui.customColorOpenColorPicker":"Custom color (open color picker)","ui.customColorItem":"Custom…","ui.colorSwatchLabel":"{label} color","ui.hexColor":"{label} hex color","ui.expand":"Expand","ui.collapse":"Collapse","ui.saving":"Saving…","ui.processing":"Working…","ui.visibleFields":"Visible content","ui.displayModeTitle":"Information display","ui.displayModeDesc":"Compact shows the provider, model, and one essential account detail. Full shows more detail. You can also click the bottom bar to switch.","ui.compactMode":"Compact","ui.fullMode":"Full","ui.fullModeContentTitle":"Full-mode content","ui.fullModeContentDesc":"These options affect Full only, not Compact.","ui.accountDetailsTitle":"Account details","ui.accountDetailsDesc":"Show reset times, subscription expiry, session spend, budgets, and free quota.","ui.conversationStatsTitle":"Conversation stats","ui.conversationStatsDesc":"Show turns, timings, cache, tokens, and context usage.","ui.advancedSettingsTitle":"Advanced settings","ui.advancedSettingsDesc":"Use individual visibility, time, custom text, and colors only when you have a specific need.","ui.timeDateTitle":"Time and date","ui.timeDateDesc":"Time zones and display format for main and world time.","ui.customTextSectionDesc":"Shown in the Info Bar.","ui.resetConfirmTitle":"Reset Info Bar settings","ui.resetConfirmDescFields":"Restore display mode, full-mode content, and advanced display settings. Custom colors are not affected. This applies right away.","ui.resetConfirmDescColors":"All custom colors will be cleared and defaults restored. Field switches are not affected. This applies to the Info Bar right away.","ui.resetConfirmAcknowledge":"I understand this reset cannot be undone","ui.resetConfirmCancel":"Cancel","ui.resetConfirmConfirm":"Reset","ui.resetLabels":"Restore display","ui.resetColors":"Restore colors","ui.resetRowTitle":"Reset to defaults","ui.resetRowDesc":"Restore display preferences or colors.","ui.customTextCount":"{value}/64 characters","ui.couldNotDisplayInfoBar":"Could not display Info Bar settings: {value}","ui.dataAndBilling":"Billing data","ui.dataAndBillingDesc":"Export or clear records.","ui.exportBillingRecords":"Export billing","ui.exportBillingRecordsDesc":"Export as CSV or JSON.","ui.exportBillingCsv":"Export CSV","ui.exportBillingJson":"Export JSON","ui.clearBillingRecords":"Clear billing","ui.clearBillingRecordsDesc":"This cannot be undone.","ui.clearBillingRecordsConfirm":"Clear all billing records saved by this plugin? Export first. This cannot be undone, but settings and sign-in information will stay unchanged.","ui.exportedBillingRecords":"Exported {count} billing records ({format})","ui.noBillingRecordsToExport":"There are no billing records to export.","ui.exportFailed":"Export failed: {value}","ui.exportIncomplete":"Some historical billing records could not be read: {value}. Nothing was exported; try again later.","ui.clearFailed":"Could not clear billing records: {value}","ui.clearFailedWithoutDetails":"Billing records could not be fully cleared","ui.clearedBillingRecords":"Cleared {count} billing records","ui.clearCanceled":"Canceled","ui.exportNotSupported":"File downloads are not supported in this environment.","ui.infoBar":"Info Bar","ui.weekly":"Weekly","ui.monthly":"Monthly","ui.window":"Window","ui.quotaDisplayUsed":"Used","ui.quotaDisplayRemaining":"Remaining","ui.quotaDisplayModeTitle":"Subscription window percentage","ui.quotaDisplayModeDesc":"Show subscription quota windows as remaining or used. The warning threshold always follows the remaining 20% rule.","ui.windowUsedRemaining":"{label} window: used {usedPercent}% (remaining {value}%)","ui.windowUsedRemainingResets":"{label} window: used {usedPercent}% (remaining {value}%) · Resets {value4}","ui.minimax":"MiniMax","ui.supportsImageInput":"Supports image input.","ui.vision":"Vision","ui.unknown":"Unknown","ui.unknownModel":"Unknown model","ui.modelSelectionPending":"Reading current model","ui.modelCapabilityPending":"Checking image-input support","ui.pluginVersion":"\nPlugin version: {current}","ui.provider":"Provider: {provLabel} {modelLabel}\n","ui.pricingPeakOffPeakBeijing":"Pricing: peak/off-peak (Beijing time; weekday peaks 09:00-12:00 and 14:00-18:00; weekends off-peak)","ui.pricingFixed":"Pricing: fixed","ui.pricingNotListedUsingDefaults":"Pricing: not listed; spend is not calculated","ui.zhipu":"Zhipu","ui.xiaomiMiMo":"Xiaomi MiMo","ui.commandCode":"Command Code","ui.subscription":"Subscription","ui.cloudBilling":"Cloud billing","ui.plan":"\nPlan: {plan}","ui.expiresLocalTime":"\nExpires: {value} (local time)","ui.subscriptionServiceModel":"Subscription service: {serviceName}\nModel: {rawModelLabel}{planLine}{expiryLine}{versionLine}","ui.balanceLookupIsNotYet":"This provider's balance is not available yet.","ui.notSupported":"Not supported","ui.notConfigured":"Not configured: ","ui.notConfiguredConfigureItIn":"Not configured: {credName}. Configure it in Settings → Models.","ui.notConfiguredSettingsModels":"{credName} is not configured. Add it in Settings → Models.","ui.estimatedBalance":"Estimated balance: {symbol}{value}","ui.balance":"Balance: {symbol}{value}","ui.balance.pushBalanceGroups":"Balance","ui.low":"Low","ui.estimated":"(estimated)","ui.balanceIsTemporarilyUnavailableShowing":"Balance is temporarily unavailable. Showing the last data and retrying automatically.","ui.couldNotLoadBalanceCheck":"Could not load balance. Check your connection and API key.","ui.balanceUnavailable":"Balance unavailable","ui.beijingTime":"Beijing time: ","ui.peakPrice":"Peak price","ui.offPeakPrice":"Off-peak price","ui.input":": input ¥","ui.mCachedInput":"/M · cached input ¥","ui.mOutput":"/M · output ¥","ui.beijingTimeSwitchesTo":"Beijing time: {atLabel} switches to ","ui.until":"Until ","ui.offPeak":"off-peak","ui.peak":"peak","ui.today":"Today {symbol}{value}","ui.lastDays":"Last 30 days {symbol}{value}","ui.allTime":"All time {symbol}{value}","ui.sessionIncludingSubagents":"Session {costTxt} (including subagents){value}","ui.session":"Session","ui.spendIsTemporarilyUnavailableChat":"Spend is temporarily unavailable. Chat is unaffected.","ui.spendUnavailable":"Spend unavailable","ui.noSignInCredentialsFound":"No sign-in credentials found for {serviceName}. Please reauthorize.","ui.credentialsHaveExpiredPleaseReauthorize":"{serviceName} credentials have expired. Please reauthorize.","ui.deniedAccessReauthorizeOrTry":"{serviceName} denied access. Reauthorize or try again later.","ui.rateLimitReachedPleaseTry":"{serviceName} rate limit reached. Please try again later.","ui.timedOutCheckYourConnection":"{serviceName} timed out. Check your connection and try again.","ui.returnedAnUnrecognizedResponsePlease":"{serviceName} returned an unrecognized response. Please try again later.","ui.isTemporarilyUnavailableCheckYour":"{serviceName} is temporarily unavailable. Check your connection and try again.","ui.subscriptionExpiresLocalTime":"Subscription expires: {value} (local time)","ui.expires":"Expires","ui.subscriptionSource":"Subscription source: {value} (","ui.prepaidBalance":"Available balance","ui.availableBalanceLabel":"Available balance","ui.remainingCredits":"Credits remaining","ui.availableBalance":"Available balance: {balTxt}","ui.availableCredits":"Credits remaining: {value}","ui.credits":"credits","ui.subscriptionSource.titleLines":"Subscription source: {value}","ui.windowRemainingUsed":"{label} window: remaining {value}% (used {usedPercent}%)","ui.resetsResetsIn":" · Resets {value} · Resets in {value2}","ui.windowRemainingUsedResets":"{label} window: remaining {value}% (used {usedPercent}%) · Resets {value4}","ui.resetsIn":"Resets in","ui.configureItInSettingsModels":". Configure it in Settings → Models.","ui.deniedAccessTheTokenMay":"{serviceName} denied access: the token may lack billing read permissions.","ui.billingIsTemporarilyUnavailableCheck":"{serviceName} billing is temporarily unavailable. Check your connection and permissions, then try again.","ui.billingSource":"Billing source: {value}","ui.thisMonthSSpend":"This month’s spend: {symbol}{value}","ui.budgetUsed":"Budget used: {value}%","ui.dailyFreeQuotaRemaining":"Daily free quota remaining: {value}","ui.thisMonth":"This month","ui.thisMonthSUsage":"This month’s usage","ui.budget":"Budget","ui.free":"Free","ui.resetsIn.pushBillingGroups":"{value} · Resets in {value2}","ui.billingServiceModel":"Billing service: {serviceName}\nModel: {modelLabel}{versionLine}","ui.pricing":"Pricing","ui.spend":"Spend","ui.mode":"Mode","ui.subscriptionQuota":"Subscription quota","ui.billing":"Billing","ui.temporarilyUnavailableKeepingTheLast":": temporarily unavailable. Keeping the last data and retrying automatically.","ui.spendJournalSavedButThe":"Spend journal saved, but the readable ledger has not been updated: ","ui.thisSpendRecordWasNot":"This spend record was not saved and will not be added to totals: ","ui.ledgerUpdatePending":"Ledger update pending","ui.spendNotSaved":"Spend not saved","ui.askYourAgentToUpdate":"Plugin version {latest} is available. Update it from plugin management on desktop.","ui.updateAvailable":"Update available","ui.updateCommandCopied":"Update command copied","ui.tools":"Tools","ui.avgTTFT":"Avg. TTFT","ui.cacheHit":"Cache hit","ui.input.BottomInfoBar":"Input","ui.output":"Output","ui.savingView":"Saving view…","ui.clickToSwitchFullCompact":"Click to switch full/compact view","ui.pressEnterOrSpaceFor":"Press Enter or Space for compact view.","ui.pressEnterOrSpaceFor.BottomInfoBar":"Press Enter or Space for full view.","host.hour":"5-hour","host.unknownProvider":"Unknown provider","error.subscription.request-failed":"Unexpected subscription quota request failure","host.settingsFileCouldNotBe":"Settings file could not be saved","host.everydayQuestions":"Everyday questions","host.mediumCodingTask":"Medium coding task","host.longDocumentAnalysisCodeReview":"Long document analysis / code review","host.largeProjectRefactorAcrossMultiple":"Large project refactor across multiple turns","host.subagentWorkflow":"Subagent workflow","error.settings.save-failed":"Could not save settings.json: {value}","error.balance.credentials":"Could not read credentials","error.balance.not-configured":"Not configured: {credential}","error.request.http":"Request failed: HTTP {status}.","error.request.parse":"Unexpected response format","error.subscription.not-connected":"ChatGPT subscription is not connected: credentials not found in ~/.codex/auth.json. Install dsh-chatgpt-subscription and sign in.","error.subscription.credentials-missing":"ChatGPT subscription credentials are missing id_token. Install dsh-chatgpt-subscription and reauthorize.","error.subscription.opencode-not-configured":"OpenCode Go is not configured. Set OPENCODE_GO_API_KEY or use opencode auth.json.","error.subscription.commandcode-not-configured":"Command Code is not configured. Set COMMAND_CODE_API_KEY, CMD_API_KEY, or sign in with the Command Code CLI.","error.subscription.commandcode-auth-failed":"Command Code credentials were rejected. Sign in again or update the API key.","error.subscription.commandcode-unrecognized":"Command Code returned an unrecognized quota format; the previous snapshot was kept.","host.zhipu":"Zhipu {mapped}","host.zhipu.parseZaiQuota":"Zhipu {value}{value2}","error.subscription.zhipu-not-configured":"Zhipu API key is not configured. Set ZAI_API_KEY or ZAI_CODING_CN_API_KEY.","error.subscription.zhipu-auth-failed":"Zhipu API authentication failed: the key is expired or invalid.","error.subscription.zhipu-unrecognized":"Zhipu returned an unrecognized quota format (the API may have changed); the last known data is kept.","error.request.failed":"Request failed: {value} {msg}.","error.subscription.xiaomi-not-configured":"Xiaomi MiMo Token Plan credentials are not configured: {credName} or XIAOMI_API_KEY.","error.subscription.xiaomi-http":"Request failed: HTTP {value}.","error.subscription.minimax-not-configured":"MiniMax is not configured. Set MINIMAX_API_KEY or MINIMAX_CN_API_KEY. Token Plan queries require a Subscription Key; pay-as-you-go API keys are rejected by the server.","error.subscription.minimax-auth-failed":"MiniMax rejected the API key: Token Plan queries require a Subscription Key (generated on the Token Plan subscription page). Pay-as-you-go keys are rejected (status_code=1004 / HTTP 401).","error.subscription.minimax-unrecognized":"MiniMax returned an unrecognized quota format (the API may have changed); the last known data is kept.","error.billing.together-not-configured":"Not configured: TOGETHER_API_KEY","host.actualMonthlyBillFromThe":"Actual monthly bill from the Together Usage API","error.billing.fireworks-not-configured":"Not configured: FIREWORKS_API_KEY","error.billing.fireworks-account":"Could not read account (account_id missing)","host.actualBillForThisPeriod":"Actual bill for this period (Fireworks Billing Summary)","host.actualUsageForThisPeriod":"Actual usage for this period (billingUsage fallback; no spend amount)","error.billing.aws-not-configured":"Not configured: AWS credentials (AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY)","error.billing.aws-http":"Request failed: HTTP {status}. The token may lack ce:GetCostAndUsage permission","host.actualMonthlyBillFromAWS":"Actual monthly bill from AWS Cost Explorer (about 24 hours behind)","error.billing.cloudflare-not-configured":"Not configured: CLOUDFLARE_API_KEY (requires an account-level token with Billing read permission)","error.billing.cloudflare-account":"Not configured: CLOUDFLARE_ACCOUNT_ID","error.billing.cloudflare-http":"Request failed: HTTP {status}. The token requires Billing read permission","host.actualMonthlyUsageFromThe":"Actual monthly usage from the Cloudflare Billable Usage API (Alpha)","error.billing.request-failed":"Unexpected billing request failure","host.spendSummaryFileMissingArchived":"Spend summary file missing: archived amounts are not included in displayed totals. Details remain in usage-archive/ for manual recovery.","host.spendLedgerCouldNotBe":"Spend ledger could not be saved","host.usageLedgerBusy":"A response is still in progress. Clear billing records after it finishes.","error.ledger.clear-failed":"Billing records could not be fully cleared: {value}","error.ledger.snapshot-stale":"Could not save archived spend summaries: {value}","host.basedOnYourLastSessions":"Based on your last {count} sessions","host.estimatedFromSpendingOverThe":"Estimated from spending over the last {SPEND_DAYS} days","host.yourTypicalSession":"Your typical session","host.patchMustIncludeFieldsOr":"patch must include fields, colors, timeFormat, timeZones or customText","host.timeFormatMustBeAnObject":"timeFormat must be an object","host.timeFieldMustBeABoolean":"Time format field must be a boolean: {key}","host.timeZonesMustBeAnObject":"timeZones must be an object","host.timeZoneMustBeAValid":"Time zone must be a valid IANA zone: {key}","host.customTextMustBeAString":"Custom text must be a string","host.customTextTooLong":"Custom text must not exceed 64 characters","host.quotaDisplayModeInvalid":"Subscription window percentage mode must be \"used\" or \"remaining\"","host.infoDensityMustBeFullOrCompact":"Information display must be full or compact","host.displayPreferencesMustBeAnObject":"Display preferences must be a valid switch object","host.fieldsMustBeAnObject":"fields must be an object","host.unknownFieldId":"Unknown field id: {key}","host.fieldVisibilityMustBeA":"Field visibility must be a boolean: {key}","host.colorsMustBeAnObject":"colors must be an object","host.colorMustBeAPreset":"Color must be a preset name or #RRGGBB: {key}","field.anchorGroup.label":"Provider and model","field.anchorGroup.note":"Shows the provider and model used in this conversation.","field.subServiceGroup.label":"Subscription service and model","field.subServiceGroup.note":"Shows the subscription service and current model or plan.","field.billingServiceGroup.label":"Billing service and model","field.billingServiceGroup.note":"Shows the billing service and current model.","field.customText.label":"Custom text","field.customText.note":"Shows custom text for a note or signature.","field.mainTime.label":"Main time","field.mainTime.note":"Shows the main time zone; adjust zone and format in Time and date.","field.worldTime.label":"World time","field.worldTime.note":"Shows another time zone; it shares the main time format.","field.sessionCost.label":"Session spend","field.sessionCost.note":"Shows actual spend for this session, including subagents.","field.balance.note":"Shows the account balance; a low balance appears in red.","field.period.label":"Current period","field.period.note":"Shows whether the current period is peak or off-peak.","field.countdown.label":"Next price change","field.countdown.note":"Shows the time until the next price change.","field.expiry.label":"Subscription expiry","field.expiry.note":"Shown when the provider supplies an expiry date.","field.subWindow5h.label":"5-hour quota","field.subWindow5h.note":"Shows the remaining rolling 5-hour quota.","field.subWindowWeek.label":"Weekly quota","field.subWindowWeek.note":"Shows the remaining weekly quota.","field.subWindowMonth.label":"Monthly quota","field.subWindowMonth.note":"Shows the remaining monthly quota.","field.resetCountdown.label":"Quota reset","field.resetCountdown.note":"Shows when the current quota resets.","field.subBalance.label":"Available balance or credits","field.subBalance.note":"Shows available balance for pay-as-you-go accounts, or remaining credits when a subscription has no visible quota window.","field.billingSpend.label":"Monthly usage","field.billingSpend.note":"Shows actual usage or spend for the current billing period.","field.budget.label":"Budget status","field.budget.note":"Shown when the provider reports a budget percentage.","field.freeQuota.label":"Free quota","field.freeQuota.note":"Shown when the provider reports a free allowance and reset time.","field.turnsSteps.label":"Turns and steps","field.turnsSteps.note":"Shows conversation turns and steps.","field.llmTime.label":"Model time","field.llmTime.note":"Shows model inference time.","field.toolTime.label":"Tool time","field.toolTime.note":"Shows tool execution time.","field.cacheHit.note":"Shows the prompt cache hit rate.","field.tokensIO.label":"Input / output tokens","field.tokensIO.note":"Shows this session’s input and output usage.","field.contextUsage.label":"Context usage","field.contextUsage.note":"Shows context usage.","ui.contextAria":"{percent} of context used","ui.contextUsed":"Context used","ui.contextSystem":"System prompt","ui.contextTools":"Tool definitions","ui.contextMessages":"Conversation messages","ui.contextFigures":"~{used} / {window}","field.unmapped.label":"Unsupported hint","field.unmapped.note":"Shown when balance lookup is not supported.","field.noKeyHint.label":"Missing key hint","field.noKeyHint.note":"Shown when an API key is missing.","field.balanceError.label":"Balance update error","field.balanceError.note":"Shown when balance update fails.","field.usageError.label":"Usage update error","field.usageError.note":"Shown when spend data is temporarily unavailable.","field.refreshFailure.label":"Update error","field.refreshFailure.note":"Shown when any data update fails.","field.persistWarning.label":"Unsaved record alert","field.persistWarning.note":"Shown when billing records cannot be saved; recommended.","field.updateNotice.note":"Shown when a new version is available.","group.native":"Native information","group.plugin":"Plugin information","ui.listSeparator":", ","ui.sentenceEnd":".","ui.fieldErrorPrefix":"\"{label}\": ","ui.turnCount":"{count} turn","ui.turnCountPlural":"{count} turns","ui.stepCount":"{count} step","ui.stepCountPlural":"{count} steps","ui.mainTimeZone":"Main time zone","ui.worldTimeZone":"World time zone","ui.timeFormat":"Time format","ui.year":"Year","ui.month":"Month","ui.day":"Day","ui.hour":"Hour","ui.minute":"Minute","ui.second":"Second","ui.customTextTitle":"Custom text","ui.customTextPlaceholder":"Enter text (up to 64 characters)","ui.searchPlaceholder":"Search content…","ui.searchFieldsLabel":"Search visible content","ui.searchResultCount":"{count} found","ui.enabledFieldsCount":"{count} enabled","ui.noSearchResults":"No matching content","ui.timePreview":"Preview: ","ui.mainTime":"Main time","ui.worldTime":"World time","ui.customText":"Custom text"}};
|
|
63
63
|
let t;
|
|
64
64
|
let localeService;
|
|
65
65
|
// 文案取值(跟随宿主界面语言):优先 DSH 的 locale 服务;服务缺席、未授权或 bind 失效时
|
|
@@ -162,41 +162,6 @@ const FORCE_REFRESH_WINDOW_MS = 6000;
|
|
|
162
162
|
// 60 秒一次足够让「本地副本更新完」的提醒自己消失,也不会给宿主添负担。
|
|
163
163
|
const UPDATE_INFO_REFRESH_MS = 60000;
|
|
164
164
|
|
|
165
|
-
// 复制文本到剪贴板。
|
|
166
|
-
// 优先用异步剪贴板 API——它只在「安全上下文」可用:本 GUI 走 http://127.0.0.1 属安全上下文,
|
|
167
|
-
// 但从局域网 IP(http://192.168.x.x)访问时不是,API 会直接缺席。故必须有兜底路径,
|
|
168
|
-
// 否则用户点了「复制」却没反应、也看不到任何错误。
|
|
169
|
-
function copyTextToClipboard(text) {
|
|
170
|
-
if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
|
|
171
|
-
return navigator.clipboard.writeText(text);
|
|
172
|
-
}
|
|
173
|
-
return new Promise(function (resolve, reject) {
|
|
174
|
-
try {
|
|
175
|
-
const area = document.createElement('textarea');
|
|
176
|
-
area.value = text;
|
|
177
|
-
area.setAttribute('readonly', '');
|
|
178
|
-
// 固定定位并移出视口:避免复制瞬间页面滚动或闪动
|
|
179
|
-
area.style.position = 'fixed';
|
|
180
|
-
area.style.top = '-1000px';
|
|
181
|
-
area.style.opacity = '0';
|
|
182
|
-
document.body.appendChild(area);
|
|
183
|
-
let ok = false;
|
|
184
|
-
try {
|
|
185
|
-
area.select();
|
|
186
|
-
area.setSelectionRange(0, text.length);
|
|
187
|
-
ok = document.execCommand('copy');
|
|
188
|
-
} finally {
|
|
189
|
-
// 卸载自检:无论复制成功还是抛错,临时 textarea 都必须从 body 摘掉,
|
|
190
|
-
// 否则会在页面上留下一个游离节点。
|
|
191
|
-
if (area.parentNode) area.parentNode.removeChild(area);
|
|
192
|
-
}
|
|
193
|
-
if (ok) resolve(); else reject(new Error('copy rejected'));
|
|
194
|
-
} catch (err) {
|
|
195
|
-
reject(err);
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
|
|
200
165
|
// rpc(method, args, externalSignal):
|
|
201
166
|
// - 超时:20s 未响应 → abort 并以"请求超时"失败(fetch 挂起不阻塞界面)
|
|
202
167
|
// - 可中止:传入外部 AbortSignal(组件卸载时 abort)→ 立即取消并拒绝"请求已取消"
|
|
@@ -291,7 +256,7 @@ const FIELD_REGISTRY = [
|
|
|
291
256
|
{ id: 'subWindowWeek', label: "field.subWindowWeek.label", group: 'plugin', modes: ['subscription'], colorKind: 'inherit', note: "field.subWindowWeek.note" },
|
|
292
257
|
{ id: 'subWindowMonth', label: "field.subWindowMonth.label", group: 'plugin', modes: ['subscription'], colorKind: 'inherit', note: "field.subWindowMonth.note" },
|
|
293
258
|
{ id: 'resetCountdown', label: "field.resetCountdown.label", group: 'plugin', modes: ['subscription'], colorKind: 'inherit', note: "field.resetCountdown.note" },
|
|
294
|
-
{ id: 'subBalance', label: "
|
|
259
|
+
{ id: 'subBalance', label: "field.subBalance.label", group: 'plugin', modes: ['subscription'], colorKind: 'inherit', note: "field.subBalance.note" },
|
|
295
260
|
// 插件字段 · 账单制
|
|
296
261
|
{ id: 'billingSpend', label: "field.billingSpend.label", group: 'plugin', modes: ['billing'], colorKind: 'inherit', note: "field.billingSpend.note" },
|
|
297
262
|
{ id: 'budget', label: "field.budget.label", group: 'plugin', modes: ['billing'], colorKind: 'inherit', note: "field.budget.note" },
|
|
@@ -315,6 +280,12 @@ const FIELD_REGISTRY = [
|
|
|
315
280
|
{ id: 'persistWarning', label: "field.persistWarning.label", group: 'plugin', modes: ['balance', 'subscription', 'billing'], suggestKeep: true, colorKind: 'alert', note: "field.persistWarning.note" },
|
|
316
281
|
{ id: 'updateNotice', label: "ui.updateAvailable", group: 'plugin', modes: ['balance', 'subscription', 'billing'], suggestKeep: true, colorKind: 'alert', note: "field.updateNotice.note" },
|
|
317
282
|
];
|
|
283
|
+
// 不是每一条渲染片段都应该成为用户的决策。身份、关键账户数值和故障状态是
|
|
284
|
+
// 信息栏的最低承诺;完整模式的“账户详情 / 对话统计”才是两个有意义的总开关。
|
|
285
|
+
// 旧字段开关继续保留在高级设置中,升级不会覆盖既有个性化配置。
|
|
286
|
+
const CORE_FIELD_IDS = new Set(['anchorGroup', 'subServiceGroup', 'billingServiceGroup', 'balance', 'subWindow5h', 'subWindowWeek', 'subWindowMonth', 'subBalance', 'billingSpend', 'unmapped', 'noKeyHint', 'balanceError', 'usageError', 'refreshFailure', 'persistWarning']);
|
|
287
|
+
const ACCOUNT_DETAIL_FIELD_IDS = new Set(['period', 'countdown', 'sessionCost', 'expiry', 'resetCountdown', 'budget', 'freeQuota']);
|
|
288
|
+
const CONVERSATION_STAT_FIELD_IDS = new Set(['turnsSteps', 'llmTime', 'toolTime', 'cacheHit', 'tokensIO', 'contextUsage']);
|
|
318
289
|
const PRESET_COLORS = ['red', 'green', 'blue', 'purple', 'orange', 'neutral'];
|
|
319
290
|
const PRESET_COLOR_SET = new Set(PRESET_COLORS);
|
|
320
291
|
|
|
@@ -330,7 +301,7 @@ function activeQuotaDisplayMode() {
|
|
|
330
301
|
return normalizeQuotaDisplayMode(fieldConfig.quotaDisplayMode);
|
|
331
302
|
}
|
|
332
303
|
|
|
333
|
-
let fieldConfig = { fields: {}, colors: {}, timeFormat: { year: true, month: true, day: true, hour: true, minute: true, second: false }, timeZones: { main: 'Asia/Shanghai', world: 'UTC' }, customText: '', quotaDisplayMode: DEFAULT_QUOTA_DISPLAY_MODE };
|
|
304
|
+
let fieldConfig = { fields: {}, colors: {}, displayPreferences: { accountDetails: true, conversationStats: true }, timeFormat: { year: true, month: true, day: true, hour: true, minute: true, second: false }, timeZones: { main: 'Asia/Shanghai', world: 'UTC' }, customText: '', quotaDisplayMode: DEFAULT_QUOTA_DISPLAY_MODE };
|
|
334
305
|
let fieldConfigVersion = 0;
|
|
335
306
|
let fieldConfigServerVersion = -1; // 宿主 configVersion(-1=尚未取得);过期响应据此丢弃(D3)
|
|
336
307
|
const fieldConfigListeners = new Set();
|
|
@@ -341,6 +312,7 @@ function applyFieldConfigSnapshot(next) {
|
|
|
341
312
|
fieldConfig = {
|
|
342
313
|
fields: next && next.fields && typeof next.fields === 'object' ? next.fields : {},
|
|
343
314
|
colors: next && next.colors && typeof next.colors === 'object' ? next.colors : {},
|
|
315
|
+
displayPreferences: Object.assign({ accountDetails: true, conversationStats: true }, next && next.displayPreferences && typeof next.displayPreferences === 'object' ? next.displayPreferences : {}),
|
|
344
316
|
timeFormat: next && next.timeFormat && typeof next.timeFormat === 'object' ? next.timeFormat : { year: true, month: true, day: true, hour: true, minute: true, second: false },
|
|
345
317
|
timeZones: next && next.timeZones && typeof next.timeZones === 'object' ? next.timeZones : { main: 'Asia/Shanghai', world: 'UTC' },
|
|
346
318
|
customText: typeof (next && next.customText) === 'string' ? next.customText : '',
|
|
@@ -388,6 +360,9 @@ function refreshFieldConfig() {
|
|
|
388
360
|
|
|
389
361
|
// 未知/缺省 id 一律视为显示:与历史行为一致(默认值全部=显示),前向兼容新字段
|
|
390
362
|
function fieldVisible(id) {
|
|
363
|
+
if (CORE_FIELD_IDS.has(id)) return true;
|
|
364
|
+
if (ACCOUNT_DETAIL_FIELD_IDS.has(id) && fieldConfig.displayPreferences.accountDetails === false) return false;
|
|
365
|
+
if (CONVERSATION_STAT_FIELD_IDS.has(id) && fieldConfig.displayPreferences.conversationStats === false) return false;
|
|
391
366
|
return fieldConfig.fields[id] !== false;
|
|
392
367
|
}
|
|
393
368
|
|
|
@@ -1725,7 +1700,7 @@ function bibSetFieldGroups(props) {
|
|
|
1725
1700
|
const groups = [];
|
|
1726
1701
|
for (let g = 0; g < FIELD_GROUP_ORDER.length; g++) {
|
|
1727
1702
|
const group = FIELD_GROUP_ORDER[g];
|
|
1728
|
-
const groupFields = FIELD_REGISTRY.filter(function (field) { return field.group === group; });
|
|
1703
|
+
const groupFields = FIELD_REGISTRY.filter(function (field) { return field.group === group && (!props.includeField || props.includeField(field)); });
|
|
1729
1704
|
if (groupFields.length === 0) continue;
|
|
1730
1705
|
const visibleFields = groupFields.filter(function (field) { return props.matchesSearch(field, props.query); });
|
|
1731
1706
|
// 搜索无命中的组整组不渲染(空状态由上层统一给出)
|
|
@@ -1830,7 +1805,7 @@ function bibSetCustomTextSection(props) {
|
|
|
1830
1805
|
// hover 仍保持该深档、不跟随主题变浅。真实色值由 tests/test-quota-display-mode.js 做真实
|
|
1831
1806
|
// sRGB 相对亮度计算锁定(不用字符串断言代替)。
|
|
1832
1807
|
function bibSetQuotaMode(props) {
|
|
1833
|
-
const options = [
|
|
1808
|
+
const options = props.options || [
|
|
1834
1809
|
{ value: 'remaining', label: t('ui.quotaDisplayRemaining') },
|
|
1835
1810
|
{ value: 'used', label: t('ui.quotaDisplayUsed') },
|
|
1836
1811
|
];
|
|
@@ -1863,7 +1838,7 @@ function bibSetQuotaMode(props) {
|
|
|
1863
1838
|
key: option.value,
|
|
1864
1839
|
type: 'button',
|
|
1865
1840
|
ref: function (node) { refs.current[option.value] = node; },
|
|
1866
|
-
className: 'bib-set-quota-mode-opt' + (selected ? ' bib-set-quota-mode-opt--on' : ''),
|
|
1841
|
+
className: (props.optionClassName || 'bib-set-quota-mode-opt') + (selected ? ' bib-set-quota-mode-opt--on' : ''),
|
|
1867
1842
|
role: 'radio',
|
|
1868
1843
|
'aria-checked': selected,
|
|
1869
1844
|
tabIndex: selected ? 0 : -1,
|
|
@@ -1894,6 +1869,58 @@ function bibSetQuotaDisplaySection(props) {
|
|
|
1894
1869
|
}))));
|
|
1895
1870
|
}
|
|
1896
1871
|
|
|
1872
|
+
// 显示模式是“看多少”的总开关:用户先选信息密度,再决定完整模式中哪些细节需要出现。
|
|
1873
|
+
// 简洁模式不修改任何字段开关,随时可切回完整模式查看全部已启用内容。
|
|
1874
|
+
function bibSetDensitySection(props) {
|
|
1875
|
+
return React.createElement('section', { className: 'bib-set-card', 'aria-labelledby': 'bib-set-density-title' },
|
|
1876
|
+
bibSetCardHeader({
|
|
1877
|
+
static: true,
|
|
1878
|
+
titleId: 'bib-set-density-title',
|
|
1879
|
+
title: t('ui.displayModeTitle'),
|
|
1880
|
+
description: t('ui.displayModeDesc'),
|
|
1881
|
+
}),
|
|
1882
|
+
React.createElement('div', { className: 'bib-set-fieldblocks' },
|
|
1883
|
+
React.createElement('div', { className: 'bib-set-fieldblock' },
|
|
1884
|
+
React.createElement(bibSetQuotaMode, {
|
|
1885
|
+
label: t('ui.displayModeTitle'),
|
|
1886
|
+
value: props.value,
|
|
1887
|
+
options: [
|
|
1888
|
+
{ value: 'compact', label: t('ui.compactMode') },
|
|
1889
|
+
{ value: 'full', label: t('ui.fullMode') },
|
|
1890
|
+
],
|
|
1891
|
+
optionClassName: 'bib-set-density-mode-opt bib-set-quota-mode-opt',
|
|
1892
|
+
onSelect: props.onSelect,
|
|
1893
|
+
}))));
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
// 完整模式只保留两项真正需要用户判断的内容开关。其余逐条字段仍可在高级设置中调整,
|
|
1897
|
+
// 但不再把渲染实现细节伪装成第一次使用就必须理解的选择。
|
|
1898
|
+
function bibSetFullModeContentSection(props) {
|
|
1899
|
+
function row(key, title, description, checked) {
|
|
1900
|
+
return React.createElement('div', { key: key, className: 'bib-set-row bib-set-row--preference' },
|
|
1901
|
+
React.createElement('div', { className: 'bib-set-row-main' },
|
|
1902
|
+
React.createElement('div', { className: 'bib-set-rowText' },
|
|
1903
|
+
React.createElement('div', { className: 'bib-set-rowTitle' }, title),
|
|
1904
|
+
React.createElement('div', { className: 'bib-set-rowDesc' }, description)),
|
|
1905
|
+
bibSetSwitch({
|
|
1906
|
+
label: t('ui.show', { label: title }),
|
|
1907
|
+
checked: checked,
|
|
1908
|
+
title: checked ? t('ui.clickToHide') : t('ui.clickToShow'),
|
|
1909
|
+
onToggle: function (next) { props.onToggle(key, next); },
|
|
1910
|
+
})));
|
|
1911
|
+
}
|
|
1912
|
+
return React.createElement('section', { className: 'bib-set-card', 'aria-labelledby': 'bib-set-full-content-title' },
|
|
1913
|
+
bibSetCardHeader({
|
|
1914
|
+
static: true,
|
|
1915
|
+
titleId: 'bib-set-full-content-title',
|
|
1916
|
+
title: t('ui.fullModeContentTitle'),
|
|
1917
|
+
description: t('ui.fullModeContentDesc'),
|
|
1918
|
+
}),
|
|
1919
|
+
React.createElement('div', { className: 'bib-set-body' },
|
|
1920
|
+
row('accountDetails', t('ui.accountDetailsTitle'), t('ui.accountDetailsDesc'), props.value.accountDetails !== false),
|
|
1921
|
+
row('conversationStats', t('ui.conversationStatsTitle'), t('ui.conversationStatsDesc'), props.value.conversationStats !== false)));
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1897
1924
|
const USAGE_EXPORT_COLUMNS = [
|
|
1898
1925
|
['timestamp', function (record) { return usageExportTimestamp(record.ts); }],
|
|
1899
1926
|
['provider', function (record) { return record.provider; }],
|
|
@@ -2007,9 +2034,10 @@ function InfoBarSettingsSection() {
|
|
|
2007
2034
|
});
|
|
2008
2035
|
}, []);
|
|
2009
2036
|
const [searchQuery, setSearchQuery] = React.useState('');
|
|
2010
|
-
//
|
|
2037
|
+
// 首屏先展示真正影响信息栏的插件内容;原生统计只在完整模式出现,按需再展开。
|
|
2011
2038
|
// 用户随后仍可手动折叠,箭头与 aria-expanded 始终反映真实状态。
|
|
2012
|
-
const [groupOpen, setGroupOpen] = React.useState({ native:
|
|
2039
|
+
const [groupOpen, setGroupOpen] = React.useState({ native: false, plugin: false });
|
|
2040
|
+
const [advancedOpen, setAdvancedOpen] = React.useState(false);
|
|
2013
2041
|
// 决策 4:重置的二次确认。null=未在确认;'fields'/'colors'=待确认的重置类别。
|
|
2014
2042
|
const [resetConfirm, setResetConfirm] = React.useState(null);
|
|
2015
2043
|
const [resetAcknowledged, setResetAcknowledged] = React.useState(false);
|
|
@@ -2028,7 +2056,7 @@ function InfoBarSettingsSection() {
|
|
|
2028
2056
|
rpc('getFieldConfig').then(function (cfg) {
|
|
2029
2057
|
if (!active) return;
|
|
2030
2058
|
if (cfg && typeof cfg === 'object' && cfg.fields) {
|
|
2031
|
-
setSnapshot({ fields: cfg.fields, colors: cfg.colors || {}, timeFormat: cfg.timeFormat || { year: true, month: true, day: true, hour: true, minute: true, second: false }, timeZones: cfg.timeZones || { main: 'Asia/Shanghai', world: 'UTC' }, customText: typeof cfg.customText === 'string' ? cfg.customText : '', quotaDisplayMode: normalizeQuotaDisplayMode(cfg.quotaDisplayMode), configVersion: cfg.configVersion || 0 });
|
|
2059
|
+
setSnapshot({ fields: cfg.fields, colors: cfg.colors || {}, displayPreferences: Object.assign({ accountDetails: true, conversationStats: true }, cfg.displayPreferences || {}), infoDensity: cfg.infoDensity === 'compact' ? 'compact' : 'full', timeFormat: cfg.timeFormat || { year: true, month: true, day: true, hour: true, minute: true, second: false }, timeZones: cfg.timeZones || { main: 'Asia/Shanghai', world: 'UTC' }, customText: typeof cfg.customText === 'string' ? cfg.customText : '', quotaDisplayMode: normalizeQuotaDisplayMode(cfg.quotaDisplayMode), configVersion: cfg.configVersion || 0 });
|
|
2032
2060
|
setStatus('ready');
|
|
2033
2061
|
} else {
|
|
2034
2062
|
setLoadError(t('ui.settingsAreTemporarilyUnavailable')); setStatus('error');
|
|
@@ -2082,6 +2110,8 @@ function InfoBarSettingsSection() {
|
|
|
2082
2110
|
return {
|
|
2083
2111
|
fields: res.fields || (prev && prev.fields) || {},
|
|
2084
2112
|
colors: res.colors || (prev && prev.colors) || {},
|
|
2113
|
+
displayPreferences: Object.assign({ accountDetails: true, conversationStats: true }, (prev && prev.displayPreferences) || {}, res.displayPreferences || {}),
|
|
2114
|
+
infoDensity: res.infoDensity === 'compact' ? 'compact' : ((res.infoDensity === 'full') ? 'full' : ((prev && prev.infoDensity) || 'full')),
|
|
2085
2115
|
timeFormat: res.timeFormat || (prev && prev.timeFormat) || { year: true, month: true, day: true, hour: true, minute: true, second: false },
|
|
2086
2116
|
timeZones: res.timeZones || (prev && prev.timeZones) || { main: 'Asia/Shanghai', world: 'UTC' },
|
|
2087
2117
|
customText: typeof res.customText === 'string' ? res.customText : ((prev && prev.customText) || ''),
|
|
@@ -2165,6 +2195,26 @@ function InfoBarSettingsSection() {
|
|
|
2165
2195
|
function timeZonesOf() { return snapshot.timeZones || { main: 'Asia/Shanghai', world: 'UTC' }; }
|
|
2166
2196
|
function customTextOf() { return typeof snapshot.customText === 'string' ? snapshot.customText : ''; }
|
|
2167
2197
|
function quotaDisplayModeOf() { return normalizeQuotaDisplayMode(snapshot.quotaDisplayMode); }
|
|
2198
|
+
function displayPreferencesOf() { return Object.assign({ accountDetails: true, conversationStats: true }, snapshot.displayPreferences || {}); }
|
|
2199
|
+
function infoDensityOf() { return snapshot.infoDensity === 'compact' ? 'compact' : 'full'; }
|
|
2200
|
+
function setInfoDensityFromSettings(next) {
|
|
2201
|
+
const value = next === 'compact' ? 'compact' : 'full';
|
|
2202
|
+
const previous = infoDensityOf();
|
|
2203
|
+
if (previous === value) return;
|
|
2204
|
+
commit({ infoDensity: value },
|
|
2205
|
+
function () { setSnapshot(function (s) { return Object.assign({}, s, { infoDensity: value }); }); },
|
|
2206
|
+
function () { setSnapshot(function (s) { return Object.assign({}, s, { infoDensity: previous }); }); },
|
|
2207
|
+
function () { return t('ui.displayModeTitle'); });
|
|
2208
|
+
}
|
|
2209
|
+
function setDisplayPreference(key, next) {
|
|
2210
|
+
const current = displayPreferencesOf();
|
|
2211
|
+
if (current[key] === next) return;
|
|
2212
|
+
const previous = current[key];
|
|
2213
|
+
commit({ displayPreferences: makePair(key, next) },
|
|
2214
|
+
function () { setSnapshot(function (s) { return Object.assign({}, s, { displayPreferences: Object.assign({}, displayPreferencesOf(), makePair(key, next)) }); }); },
|
|
2215
|
+
function () { setSnapshot(function (s) { return Object.assign({}, s, { displayPreferences: Object.assign({}, displayPreferencesOf(), makePair(key, previous)) }); }); },
|
|
2216
|
+
function () { return key === 'accountDetails' ? t('ui.accountDetailsTitle') : t('ui.conversationStatsTitle'); });
|
|
2217
|
+
}
|
|
2168
2218
|
function setTimeFormatPart(key, next) {
|
|
2169
2219
|
const current = timeFormatOf();
|
|
2170
2220
|
if (current[key] === next) return;
|
|
@@ -2297,14 +2347,16 @@ function InfoBarSettingsSection() {
|
|
|
2297
2347
|
// 搜索只负责筛选;输入时两分组自动展开(决策 2),但用户随后仍可明确折叠,
|
|
2298
2348
|
// 箭头和 aria-expanded 始终反映真实 DOM 状态。
|
|
2299
2349
|
const searchActive = searchQuery.trim().length > 0;
|
|
2300
|
-
const
|
|
2301
|
-
const
|
|
2350
|
+
const advancedFields = FIELD_REGISTRY.filter(function (field) { return !CORE_FIELD_IDS.has(field.id) && field.id !== 'updateNotice'; });
|
|
2351
|
+
const fieldsEnabledCount = advancedFields.filter(function (f) { return fieldOn(f.id); }).length;
|
|
2352
|
+
const fieldsMatchCount = advancedFields.filter(function (f) { return matchesSearch(f, searchQuery); }).length;
|
|
2302
2353
|
const groupsChildren = bibSetFieldGroups({
|
|
2303
2354
|
query: searchQuery,
|
|
2304
2355
|
searchActive: searchActive,
|
|
2305
2356
|
matchesSearch: matchesSearch,
|
|
2306
2357
|
groupOpenOf: function (group) { return groupOpen && groupOpen[group] === true; },
|
|
2307
2358
|
onGroupToggle: toggleGroup,
|
|
2359
|
+
includeField: function (field) { return !CORE_FIELD_IDS.has(field.id) && field.id !== 'updateNotice'; },
|
|
2308
2360
|
fieldOn: fieldOn,
|
|
2309
2361
|
colorOf: colorOf,
|
|
2310
2362
|
hexDraftOf: hexDraftOf,
|
|
@@ -2364,7 +2416,23 @@ function InfoBarSettingsSection() {
|
|
|
2364
2416
|
: null;
|
|
2365
2417
|
return React.createElement('div', { ref: settingsRootRef, className: 'bib-set-root bib-settings' },
|
|
2366
2418
|
React.createElement('div', { className: 'bib-set-page-head' }, bibSetPageTitle()),
|
|
2367
|
-
|
|
2419
|
+
bibSetDensitySection({ value: infoDensityOf(), onSelect: setInfoDensityFromSettings }),
|
|
2420
|
+
bibSetFullModeContentSection({ value: displayPreferencesOf(), onToggle: setDisplayPreference }),
|
|
2421
|
+
React.createElement('section', { className: 'bib-set-card', 'aria-labelledby': 'bib-set-advanced-title' },
|
|
2422
|
+
bibSetCardHeader({
|
|
2423
|
+
titleId: 'bib-set-advanced-title',
|
|
2424
|
+
title: t('ui.advancedSettingsTitle'),
|
|
2425
|
+
description: t('ui.advancedSettingsDesc'),
|
|
2426
|
+
expanded: advancedOpen,
|
|
2427
|
+
contentId: 'bib-set-advanced-content',
|
|
2428
|
+
onToggle: function () { setAdvancedOpen(function (open) { return !open; }); },
|
|
2429
|
+
}),
|
|
2430
|
+
React.createElement('div', {
|
|
2431
|
+
id: 'bib-set-advanced-content',
|
|
2432
|
+
className: 'bib-set-collapse' + (advancedOpen ? ' bib-set-collapse--expanded' : ' bib-set-collapse--collapsed'),
|
|
2433
|
+
'aria-hidden': advancedOpen ? undefined : 'true',
|
|
2434
|
+
inert: advancedOpen ? undefined : true,
|
|
2435
|
+
}, React.createElement('div', { className: 'bib-set-collapse-inner' },
|
|
2368
2436
|
React.createElement('div', { className: 'bib-set-toolbar' },
|
|
2369
2437
|
React.createElement('div', { className: 'bib-set-search-row' },
|
|
2370
2438
|
React.createElement('div', { className: 'bib-set-search-shell' },
|
|
@@ -2399,7 +2467,7 @@ function InfoBarSettingsSection() {
|
|
|
2399
2467
|
disabled: saving || dataBusy,
|
|
2400
2468
|
onClick: function () { requestReset('colors'); },
|
|
2401
2469
|
children: t('ui.resetColors'),
|
|
2402
|
-
})))),
|
|
2470
|
+
})))))),
|
|
2403
2471
|
bibSetTimeDateSection({
|
|
2404
2472
|
fieldOn: fieldOn,
|
|
2405
2473
|
timeFormatOf: timeFormatOf,
|
|
@@ -2578,8 +2646,6 @@ module.exports = {
|
|
|
2578
2646
|
});
|
|
2579
2647
|
// 版本信息由 host 在启动时从 package.json 读取;无论是否有新版,都用于服务商/模型 hover 展示。
|
|
2580
2648
|
const [updateInfo, setUpdateInfo] = React.useState(null);
|
|
2581
|
-
// 「更新命令已复制」的短暂反馈:复制成功后标签文字临时切换,2 秒后复原。
|
|
2582
|
-
const [updateCopied, setUpdateCopied] = React.useState(false);
|
|
2583
2649
|
const [now, setNow] = React.useState(Date.now());
|
|
2584
2650
|
// This state is owned by DSH's per-session model selector, not by the
|
|
2585
2651
|
// process-wide default for newly-created Agents.
|
|
@@ -3094,12 +3160,12 @@ module.exports = {
|
|
|
3094
3160
|
const errors = renderedState.errors || {};
|
|
3095
3161
|
if (bal && bal.selectionPending) return;
|
|
3096
3162
|
const alertActive = !!(bal && bal.alert && bal.alert.active);
|
|
3097
|
-
pushCustomText(groups);
|
|
3163
|
+
if (full) pushCustomText(groups);
|
|
3098
3164
|
if (fieldVisible('anchorGroup')) {
|
|
3099
3165
|
const anchor = providerGroup();
|
|
3100
3166
|
groups.push(React.cloneElement(anchor, { 'data-field': 'anchorGroup', style: fieldStyle('anchorGroup') }));
|
|
3101
3167
|
}
|
|
3102
|
-
pushTimeGroups(groups);
|
|
3168
|
+
if (full) pushTimeGroups(groups);
|
|
3103
3169
|
|
|
3104
3170
|
// v1.6 T7:未适配账户渲染"未适配"弱提示
|
|
3105
3171
|
if (bal && bal.unmapped) {
|
|
@@ -3152,7 +3218,7 @@ module.exports = {
|
|
|
3152
3218
|
|
|
3153
3219
|
// 时段:仅峰谷价服务商显示"高峰价/空闲价"(flat/unknown 服务商不显示;hover 展示具体价格)
|
|
3154
3220
|
const pr = visiblePricing;
|
|
3155
|
-
if (pr && pr.mode === 'peak-valley' && fieldVisible('period')) {
|
|
3221
|
+
if (full && pr && pr.mode === 'peak-valley' && fieldVisible('period')) {
|
|
3156
3222
|
const peakNow = pr.period === 'peak';
|
|
3157
3223
|
const p = pr.prices || {};
|
|
3158
3224
|
const periodTitle = t('ui.beijingTime') + (peakNow ? t('ui.peakPrice') : t('ui.offPeakPrice')) + t('ui.input') + (p.inputCacheMiss != null ? p.inputCacheMiss : '?')
|
|
@@ -3163,7 +3229,7 @@ module.exports = {
|
|
|
3163
3229
|
}
|
|
3164
3230
|
|
|
3165
3231
|
// 倒计时:仅峰谷价服务商显示"距高峰/距空闲"(hover 展示下次切换时刻;数字加粗)
|
|
3166
|
-
if (pr && pr.mode === 'peak-valley' && pr.nextSwitch && fieldVisible('countdown')) {
|
|
3232
|
+
if (full && pr && pr.mode === 'peak-valley' && pr.nextSwitch && fieldVisible('countdown')) {
|
|
3167
3233
|
const peakNow = pr.period === 'peak';
|
|
3168
3234
|
const countdownTitle = t('ui.beijingTimeSwitchesTo', { atLabel: pr.nextSwitch.atLabel }) + (peakNow ? t('ui.offPeakPrice') : t('ui.peakPrice')) + t('ui.sentenceEnd');
|
|
3169
3235
|
groups.push(fieldSpan('countdown', 'countdown', React.createElement('span', { title: countdownTitle },
|
|
@@ -3172,7 +3238,7 @@ module.exports = {
|
|
|
3172
3238
|
|
|
3173
3239
|
// 本会话花费(公共小部件 pushSessionCost:只显示钱;hover 显示 今天/近一月/全部)
|
|
3174
3240
|
// 始终显示:新会话/对话刚开始尚无记账时显示 ¥0.000,hover 仍可查看持久化的 今天/近一月/全部
|
|
3175
|
-
pushSessionCost(groups, trailingErrorGroups, !!(bal && bal.currency === 'USD'));
|
|
3241
|
+
if (full) pushSessionCost(groups, trailingErrorGroups, !!(bal && bal.currency === 'USD'));
|
|
3176
3242
|
}
|
|
3177
3243
|
|
|
3178
3244
|
// 本会话花费块(余额制 与 订阅·充值余额 形态共用的小部件):
|
|
@@ -3224,16 +3290,16 @@ module.exports = {
|
|
|
3224
3290
|
}
|
|
3225
3291
|
|
|
3226
3292
|
function pushSubscriptionGroups(groups, trailingErrorGroups) {
|
|
3227
|
-
pushCustomText(groups);
|
|
3293
|
+
if (full) pushCustomText(groups);
|
|
3228
3294
|
if (fieldVisible('subServiceGroup')) {
|
|
3229
3295
|
const subAnchor = subscriptionProviderGroup();
|
|
3230
3296
|
groups.push(React.cloneElement(subAnchor, { 'data-field': 'subServiceGroup', style: fieldStyle('subServiceGroup') }));
|
|
3231
3297
|
}
|
|
3232
|
-
pushTimeGroups(groups);
|
|
3298
|
+
if (full) pushTimeGroups(groups);
|
|
3233
3299
|
const sub = renderedState.sub;
|
|
3234
3300
|
const errors = renderedState.errors || {};
|
|
3235
3301
|
// v1.7 FR-8:JWT 订阅卡——真实套餐到期日(纯本地解码;无登录态/解析失败不显示此处)
|
|
3236
|
-
if (sub && sub.planType && sub.expiryAt && fieldVisible('expiry')) {
|
|
3302
|
+
if (full && sub && sub.planType && sub.expiryAt && fieldVisible('expiry')) {
|
|
3237
3303
|
groups.push(fieldSpan('expiry', 'subexp', React.createElement('span', { title: t('ui.subscriptionExpiresLocalTime', { value: formatDate(sub.expiryAt) }) },
|
|
3238
3304
|
metric(t('ui.expires'), formatDate(sub.expiryAt)))));
|
|
3239
3305
|
}
|
|
@@ -3270,10 +3336,10 @@ module.exports = {
|
|
|
3270
3336
|
const titleLines = [t('ui.subscriptionSource', { value: subscriptionServiceName(visibleBillingMode && visibleBillingMode.provider) }) + (hostText(sub.plan) || (isCreditsBalance ? t('ui.commandCode') : t('ui.prepaidBalance'))) + ')',
|
|
3271
3337
|
isCreditsBalance ? t('ui.availableCredits', { value: balanceValue }) : t('ui.availableBalance', { balTxt: balanceValue })];
|
|
3272
3338
|
groups.push(fieldSpan('subBalance', 'subbal', React.createElement('span', { title: titleLines.join('\n') },
|
|
3273
|
-
metric(isCreditsBalance ? t('ui.
|
|
3339
|
+
metric(isCreditsBalance ? t('ui.remainingCredits') : t('ui.availableBalanceLabel'), balanceValue))));
|
|
3274
3340
|
}
|
|
3275
3341
|
// 充值余额用户按量付费,花销与余额同等重要 → 追加公共花费块(含子代理聚合)
|
|
3276
|
-
if (!isCreditsBalance) pushSessionCost(groups, trailingErrorGroups, false);
|
|
3342
|
+
if (full && !isCreditsBalance) pushSessionCost(groups, trailingErrorGroups, false);
|
|
3277
3343
|
// host 快照失败(sub.error)或本次 RPC 失败(errors.sub)→ 保留旧数据 + 降级标记
|
|
3278
3344
|
if (fieldVisible('refreshFailure') && (sub.error || errors.sub)) {
|
|
3279
3345
|
trailingErrorGroups.push(fieldSpan('refreshFailure', 'substale',
|
|
@@ -3333,7 +3399,7 @@ module.exports = {
|
|
|
3333
3399
|
React.createElement('span', { className: 'bi-stale', title: subscriptionFailureHint(sub.error || { kind: 'exception', message: String(errors.sub || '') }, sub.source || (visibleBillingMode && visibleBillingMode.provider)) }, t('ui.refreshFailed'))));
|
|
3334
3400
|
}
|
|
3335
3401
|
// 距重置倒计时(与显示的窗口一致,确保额度与倒计时匹配)
|
|
3336
|
-
if (displayWindow && displayWindow.resetsAt && fieldVisible('resetCountdown')) {
|
|
3402
|
+
if (full && displayWindow && displayWindow.resetsAt && fieldVisible('resetCountdown')) {
|
|
3337
3403
|
const cdTitle = windowMode === 'used'
|
|
3338
3404
|
? t('ui.windowUsedRemainingResets', { label: quotaWindowLabel(displayWindow), value: remainingPercent(displayWindow), usedPercent: displayWindow.usedPercent, value4: formatDateTime(displayWindow.resetsAt) })
|
|
3339
3405
|
: t('ui.windowRemainingUsedResets', { label: quotaWindowLabel(displayWindow), value: remainingPercent(displayWindow), usedPercent: displayWindow.usedPercent, value4: formatDateTime(displayWindow.resetsAt) });
|
|
@@ -3358,12 +3424,12 @@ module.exports = {
|
|
|
3358
3424
|
}
|
|
3359
3425
|
|
|
3360
3426
|
function pushBillingGroups(groups, trailingErrorGroups) {
|
|
3361
|
-
pushCustomText(groups);
|
|
3427
|
+
if (full) pushCustomText(groups);
|
|
3362
3428
|
if (fieldVisible('billingServiceGroup')) {
|
|
3363
3429
|
const billAnchor = billingProviderGroup();
|
|
3364
3430
|
groups.push(React.cloneElement(billAnchor, { 'data-field': 'billingServiceGroup', style: fieldStyle('billingServiceGroup') }));
|
|
3365
3431
|
}
|
|
3366
|
-
pushTimeGroups(groups);
|
|
3432
|
+
if (full) pushTimeGroups(groups);
|
|
3367
3433
|
const bill = renderedState.billing;
|
|
3368
3434
|
const errors = renderedState.errors || {};
|
|
3369
3435
|
if (!bill) {
|
|
@@ -3396,12 +3462,12 @@ module.exports = {
|
|
|
3396
3462
|
} else if (d.usage != null && fieldVisible('billingSpend')) {
|
|
3397
3463
|
nodes.push(fieldSpan('billingSpend', 'billspend', metric(t('ui.thisMonthSUsage'), fmt(d.usage, 2) + (d.usageUnit ? ' ' + d.usageUnit : ''))));
|
|
3398
3464
|
}
|
|
3399
|
-
if (d.budgetPercent != null && fieldVisible('budget')) {
|
|
3465
|
+
if (full && d.budgetPercent != null && fieldVisible('budget')) {
|
|
3400
3466
|
if (nodes.length > 0) nodes.push(' · ');
|
|
3401
3467
|
nodes.push(fieldSpan('budget', 'billbudget', metric(t('ui.budget'), fmt(d.budgetPercent, 0) + '%')));
|
|
3402
3468
|
}
|
|
3403
3469
|
// 免费额度仅当接口显式给出(freeRemaining/resetsAt 同时存在)才显示,绝不编造
|
|
3404
|
-
if (d.freeRemaining != null && d.resetsAt && fieldVisible('freeQuota')) {
|
|
3470
|
+
if (full && d.freeRemaining != null && d.resetsAt && fieldVisible('freeQuota')) {
|
|
3405
3471
|
if (nodes.length > 0) nodes.push(' · ');
|
|
3406
3472
|
nodes.push(fieldSpan('freeQuota', 'billfree', metric(t('ui.free'), t('ui.resetsIn.pushBillingGroups', { value: fmt(d.freeRemaining, 0), value2: fmtResetCountdown(d.resetsAt - now) }))));
|
|
3407
3473
|
}
|
|
@@ -3478,31 +3544,14 @@ module.exports = {
|
|
|
3478
3544
|
}, snapshotOnly ? t('ui.ledgerUpdatePending') : t('ui.spendNotSaved'))));
|
|
3479
3545
|
}
|
|
3480
3546
|
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
// 必须 stopPropagation —— 信息栏根节点自带 onClick(切换简洁/完整模式),
|
|
3484
|
-
// 不拦下冒泡的话,用户点一下复制会顺带把界面切走。
|
|
3485
|
-
const updateCommand = typeof updateInfo.updateCommand === 'string' ? updateInfo.updateCommand : '';
|
|
3486
|
-
const copyUpdateCommand = function (event) {
|
|
3487
|
-
event.stopPropagation();
|
|
3488
|
-
if (updateCommand.length === 0) return;
|
|
3489
|
-
copyTextToClipboard(updateCommand).then(function () {
|
|
3490
|
-
setUpdateCopied(true);
|
|
3491
|
-
window.setTimeout(function () { setUpdateCopied(false); }, 2000);
|
|
3492
|
-
}).catch(function () { /* 复制失败不谎报成功;命令仍写在 hover 提示里可手抄 */ });
|
|
3493
|
-
};
|
|
3494
|
-
groups.push(fieldSpan('updateNotice', 'update', React.createElement('span', {
|
|
3495
|
-
className: 'bi-update',
|
|
3496
|
-
title: t('ui.askYourAgentToUpdate', { latest: updateInfo.latest }),
|
|
3497
|
-
onClick: copyUpdateCommand,
|
|
3498
|
-
}, updateCopied ? t('ui.updateCommandCopied') : t('ui.updateAvailable'))));
|
|
3499
|
-
}
|
|
3547
|
+
// 新版本是低频维护事件,不是这次对话的状态。桌面客户端也不能可靠执行
|
|
3548
|
+
// Web/终端安装命令,因此这里不再塞入“更新”标签或复制命令。
|
|
3500
3549
|
|
|
3501
3550
|
// ---- 组装(分隔符收合与「刷新失败」去重见模块级 assembleInfoBarRow) ----
|
|
3502
3551
|
const nodes = assembleInfoBarRow(groups, trailingErrorGroups, React.createElement);
|
|
3503
3552
|
// 上下文占用圆环(DSH 原生信息,由本插件接管):挂在主行最右端——即「简洁模式」可见的那一行里的最后一个元素。
|
|
3504
3553
|
// 与其它字段同源:fields.contextUsage 管显隐、colors.contextUsage 管配色;数据不足时整块不渲染。
|
|
3505
|
-
const contextInfo = fieldVisible('contextUsage') ? contextOccupancy(pressureProj) : null;
|
|
3554
|
+
const contextInfo = full && fieldVisible('contextUsage') ? contextOccupancy(pressureProj) : null;
|
|
3506
3555
|
const contextNode = contextInfo === null ? null : React.createElement(ContextMeterRing, {
|
|
3507
3556
|
key: 'ctx',
|
|
3508
3557
|
context: contextInfo,
|
package/lib/constants.js
CHANGED
|
@@ -42,7 +42,7 @@ export const FIELD_REGISTRY = [
|
|
|
42
42
|
{ id: 'subWindowWeek', label: "field.subWindowWeek.label", group: 'plugin', modes: ['subscription'], colorKind: 'inherit', note: "field.subWindowWeek.note" },
|
|
43
43
|
{ id: 'subWindowMonth', label: "field.subWindowMonth.label", group: 'plugin', modes: ['subscription'], colorKind: 'inherit', note: "field.subWindowMonth.note" },
|
|
44
44
|
{ id: 'resetCountdown', label: "field.resetCountdown.label", group: 'plugin', modes: ['subscription'], colorKind: 'inherit', note: "field.resetCountdown.note" },
|
|
45
|
-
{ id: 'subBalance', label: "
|
|
45
|
+
{ id: 'subBalance', label: "field.subBalance.label", group: 'plugin', modes: ['subscription'], colorKind: 'inherit', note: "field.subBalance.note" },
|
|
46
46
|
// 插件字段 · 账单制
|
|
47
47
|
{ id: 'billingSpend', label: "field.billingSpend.label", group: 'plugin', modes: ['billing'], colorKind: 'inherit', note: "field.billingSpend.note" },
|
|
48
48
|
{ id: 'budget', label: "field.budget.label", group: 'plugin', modes: ['billing'], colorKind: 'inherit', note: "field.budget.note" },
|
package/lib/index.js
CHANGED
|
@@ -1455,8 +1455,22 @@ const QUOTA_DISPLAY_MODES = ['used', 'remaining']
|
|
|
1455
1455
|
function normalizeQuotaDisplayMode(value) {
|
|
1456
1456
|
return value === 'used' || value === 'remaining' ? value : null
|
|
1457
1457
|
}
|
|
1458
|
+
// 这两项是设置页的主要决定:普通用户不需要逐条理解轮次、倒计时或缓存。
|
|
1459
|
+
// 旧 fields 仍完整保留,既有自定义不会在升级时被重写;displayPreferences 只是一层
|
|
1460
|
+
// 更高的显示边界,用来一次控制“完整模式里的账户细节”和“对话统计”。
|
|
1461
|
+
const DEFAULT_DISPLAY_PREFERENCES = Object.freeze({ accountDetails: true, conversationStats: true })
|
|
1462
|
+
function normalizeDisplayPreferences(value) {
|
|
1463
|
+
if (!isPlainSettingsObject(value)) return undefined
|
|
1464
|
+
const out = {}
|
|
1465
|
+
for (const key of Object.keys(DEFAULT_DISPLAY_PREFERENCES)) {
|
|
1466
|
+
if (!Object.hasOwn(value, key)) continue
|
|
1467
|
+
if (typeof value[key] !== 'boolean') return undefined
|
|
1468
|
+
out[key] = value[key]
|
|
1469
|
+
}
|
|
1470
|
+
return out
|
|
1471
|
+
}
|
|
1458
1472
|
function defaultFieldSettings() {
|
|
1459
|
-
const settings = { version: SETTINGS_FORMAT_VERSION, infoDensity: '
|
|
1473
|
+
const settings = { version: SETTINGS_FORMAT_VERSION, infoDensity: 'compact', displayPreferences: { ...DEFAULT_DISPLAY_PREFERENCES }, fields: {}, colors: {}, timeFormat: { ...DEFAULT_TIME_FORMAT }, timeZones: { ...DEFAULT_TIME_ZONES }, customText: '', quotaDisplayMode: 'remaining' }
|
|
1460
1474
|
for (const field of FIELD_REGISTRY) {
|
|
1461
1475
|
const isNewField = field.id === 'mainTime' || field.id === 'worldTime' || field.id === 'customText'
|
|
1462
1476
|
settings.fields[field.id] = isNewField ? false : true
|
|
@@ -1482,8 +1496,15 @@ function sanitizeSettings(raw) {
|
|
|
1482
1496
|
const dropped = []
|
|
1483
1497
|
if (!isPlainSettingsObject(raw)) return { settings: settings, dropped: ['整个文件'] }
|
|
1484
1498
|
if (raw.version !== SETTINGS_FORMAT_VERSION) dropped.push('version')
|
|
1499
|
+
// 旧设置没有 infoDensity 时沿用旧版完整模式,避免一次升级突然收起用户正在看的内容。
|
|
1485
1500
|
if (raw.infoDensity === 'full' || raw.infoDensity === 'compact') settings.infoDensity = raw.infoDensity
|
|
1486
|
-
else dropped.push('infoDensity')
|
|
1501
|
+
else if (Object.hasOwn(raw, 'infoDensity')) dropped.push('infoDensity')
|
|
1502
|
+
else settings.infoDensity = 'full'
|
|
1503
|
+
if (Object.hasOwn(raw, 'displayPreferences')) {
|
|
1504
|
+
const normalized = normalizeDisplayPreferences(raw.displayPreferences)
|
|
1505
|
+
if (normalized === undefined) dropped.push('displayPreferences')
|
|
1506
|
+
else settings.displayPreferences = { ...settings.displayPreferences, ...normalized }
|
|
1507
|
+
}
|
|
1487
1508
|
if (isPlainSettingsObject(raw.fields)) {
|
|
1488
1509
|
for (const key of Object.keys(raw.fields)) {
|
|
1489
1510
|
const value = raw.fields[key]
|
|
@@ -2017,6 +2038,7 @@ export default {
|
|
|
2017
2038
|
return {
|
|
2018
2039
|
version: fieldSettings.version,
|
|
2019
2040
|
infoDensity: config.infoDensity,
|
|
2041
|
+
displayPreferences: { ...fieldSettings.displayPreferences },
|
|
2020
2042
|
fields: shallowSettingsCopy(fieldSettings.fields),
|
|
2021
2043
|
colors: shallowSettingsCopy(fieldSettings.colors),
|
|
2022
2044
|
timeFormat: { ...fieldSettings.timeFormat },
|
|
@@ -4615,7 +4637,7 @@ export default {
|
|
|
4615
4637
|
},
|
|
4616
4638
|
setFieldConfig: function (args) {
|
|
4617
4639
|
const patch = isPlainSettingsObject(args) ? args : null;
|
|
4618
|
-
if (!patch || (!Object.hasOwn(patch, 'fields') && !Object.hasOwn(patch, 'colors') && !Object.hasOwn(patch, 'timeFormat') && !Object.hasOwn(patch, 'timeZones') && !Object.hasOwn(patch, 'customText') && !Object.hasOwn(patch, 'customTextValue') && !Object.hasOwn(patch, 'quotaDisplayMode'))) {
|
|
4640
|
+
if (!patch || (!Object.hasOwn(patch, 'fields') && !Object.hasOwn(patch, 'colors') && !Object.hasOwn(patch, 'infoDensity') && !Object.hasOwn(patch, 'displayPreferences') && !Object.hasOwn(patch, 'timeFormat') && !Object.hasOwn(patch, 'timeZones') && !Object.hasOwn(patch, 'customText') && !Object.hasOwn(patch, 'customTextValue') && !Object.hasOwn(patch, 'quotaDisplayMode'))) {
|
|
4619
4641
|
throw invalidArgument(t('host.patchMustIncludeFieldsOr'));
|
|
4620
4642
|
}
|
|
4621
4643
|
// 先整包校验再应用:非法 patch 一个字段都不落,避免半新半旧
|
|
@@ -4627,6 +4649,21 @@ export default {
|
|
|
4627
4649
|
let hasCustomTextPatch = false;
|
|
4628
4650
|
let normalizedQuotaDisplayMode = null;
|
|
4629
4651
|
let hasQuotaDisplayModePatch = false;
|
|
4652
|
+
let normalizedInfoDensity = null;
|
|
4653
|
+
let hasInfoDensityPatch = false;
|
|
4654
|
+
let normalizedDisplayPreferences = null;
|
|
4655
|
+
let hasDisplayPreferencesPatch = false;
|
|
4656
|
+
if (Object.hasOwn(patch, 'infoDensity')) {
|
|
4657
|
+
if (patch.infoDensity !== 'full' && patch.infoDensity !== 'compact') throw invalidArgument(t('host.infoDensityMustBeFullOrCompact'));
|
|
4658
|
+
normalizedInfoDensity = patch.infoDensity;
|
|
4659
|
+
hasInfoDensityPatch = true;
|
|
4660
|
+
}
|
|
4661
|
+
if (Object.hasOwn(patch, 'displayPreferences')) {
|
|
4662
|
+
const normalized = normalizeDisplayPreferences(patch.displayPreferences)
|
|
4663
|
+
if (normalized === undefined || Object.keys(normalized).length === 0) throw invalidArgument(t('host.displayPreferencesMustBeAnObject'))
|
|
4664
|
+
normalizedDisplayPreferences = normalized
|
|
4665
|
+
hasDisplayPreferencesPatch = true
|
|
4666
|
+
}
|
|
4630
4667
|
if (Object.hasOwn(patch, 'fields')) {
|
|
4631
4668
|
const patchFields = patch.fields;
|
|
4632
4669
|
if (!isPlainSettingsObject(patchFields)) throw invalidArgument(t('host.fieldsMustBeAnObject'));
|
|
@@ -4729,6 +4766,21 @@ export default {
|
|
|
4729
4766
|
changed = true;
|
|
4730
4767
|
}
|
|
4731
4768
|
}
|
|
4769
|
+
if (hasInfoDensityPatch) {
|
|
4770
|
+
if (fieldSettings.infoDensity !== normalizedInfoDensity) {
|
|
4771
|
+
fieldSettings.infoDensity = normalizedInfoDensity
|
|
4772
|
+
config.infoDensity = normalizedInfoDensity
|
|
4773
|
+
changed = true;
|
|
4774
|
+
}
|
|
4775
|
+
}
|
|
4776
|
+
if (hasDisplayPreferencesPatch) {
|
|
4777
|
+
for (const key of Object.keys(normalizedDisplayPreferences)) {
|
|
4778
|
+
if (fieldSettings.displayPreferences[key] !== normalizedDisplayPreferences[key]) {
|
|
4779
|
+
fieldSettings.displayPreferences[key] = normalizedDisplayPreferences[key]
|
|
4780
|
+
changed = true
|
|
4781
|
+
}
|
|
4782
|
+
}
|
|
4783
|
+
}
|
|
4732
4784
|
if (changed) {
|
|
4733
4785
|
settingsConfigVersion += 1;
|
|
4734
4786
|
persistError = persistSettings();
|
|
@@ -4736,13 +4788,16 @@ export default {
|
|
|
4736
4788
|
return settingsPayload(persistError);
|
|
4737
4789
|
},
|
|
4738
4790
|
resetFieldConfig: function () {
|
|
4739
|
-
// 只重置标签显隐 + 时间格式/时区/自定义文本/订阅窗口百分比方向;颜色保持不动(两个重置按钮彼此独立)
|
|
4791
|
+
// 只重置标签显隐 + 显示模式 + 时间格式/时区/自定义文本/订阅窗口百分比方向;颜色保持不动(两个重置按钮彼此独立)
|
|
4740
4792
|
const defaults = defaultFieldSettings()
|
|
4741
4793
|
fieldSettings.fields = shallowSettingsCopy(defaults.fields);
|
|
4742
4794
|
fieldSettings.timeFormat = { ...defaults.timeFormat }
|
|
4743
4795
|
fieldSettings.timeZones = { ...defaults.timeZones }
|
|
4744
4796
|
fieldSettings.customText = defaults.customText
|
|
4745
4797
|
fieldSettings.quotaDisplayMode = defaults.quotaDisplayMode
|
|
4798
|
+
fieldSettings.infoDensity = defaults.infoDensity
|
|
4799
|
+
fieldSettings.displayPreferences = { ...defaults.displayPreferences }
|
|
4800
|
+
config.infoDensity = defaults.infoDensity
|
|
4746
4801
|
// 自定义文本重置后为空,开关已为 false,无需额外修正
|
|
4747
4802
|
settingsConfigVersion += 1;
|
|
4748
4803
|
const persistError = persistSettings();
|
package/lib/locales.js
CHANGED
|
@@ -50,11 +50,23 @@ export const LOCALES = {
|
|
|
50
50
|
"ui.saving": "正在保存…",
|
|
51
51
|
"ui.processing": "正在处理…",
|
|
52
52
|
"ui.visibleFields": "显示内容",
|
|
53
|
+
"ui.displayModeTitle": "信息显示方式",
|
|
54
|
+
"ui.displayModeDesc": "简洁只显示服务商、模型和一项关键账户信息;完整才显示更多细节。也可以直接点击底部信息栏切换。",
|
|
55
|
+
"ui.compactMode": "简洁",
|
|
56
|
+
"ui.fullMode": "完整",
|
|
57
|
+
"ui.fullModeContentTitle": "完整模式内容",
|
|
58
|
+
"ui.fullModeContentDesc": "这些内容只在完整模式显示,不影响简洁模式。",
|
|
59
|
+
"ui.accountDetailsTitle": "账户详情",
|
|
60
|
+
"ui.accountDetailsDesc": "显示重置时间、订阅到期、会话花费、预算和免费额度。",
|
|
61
|
+
"ui.conversationStatsTitle": "对话统计",
|
|
62
|
+
"ui.conversationStatsDesc": "显示轮次、耗时、缓存、Token 和上下文用量。",
|
|
63
|
+
"ui.advancedSettingsTitle": "高级设置",
|
|
64
|
+
"ui.advancedSettingsDesc": "逐项显示、时间、自定义文字和颜色只适合有明确需求时调整。",
|
|
53
65
|
"ui.timeDateTitle": "时间与日期",
|
|
54
66
|
"ui.timeDateDesc": "主时间和世界时间的时区与显示格式。",
|
|
55
67
|
"ui.customTextSectionDesc": "显示在信息栏中。",
|
|
56
68
|
"ui.resetConfirmTitle": "重置信息栏设置",
|
|
57
|
-
"ui.resetConfirmDescFields": "
|
|
69
|
+
"ui.resetConfirmDescFields": "将恢复信息显示方式、完整模式内容和高级显示设置;自定义颜色不受影响。该操作会直接应用到信息栏。",
|
|
58
70
|
"ui.resetConfirmDescColors": "将清除全部自定义颜色并恢复默认配色,字段显示开关不受影响。该操作会直接应用到信息栏。",
|
|
59
71
|
"ui.resetConfirmAcknowledge": "我了解这次重置不可撤销",
|
|
60
72
|
"ui.resetConfirmCancel": "取消",
|
|
@@ -62,7 +74,7 @@ export const LOCALES = {
|
|
|
62
74
|
"ui.resetLabels": "恢复显示",
|
|
63
75
|
"ui.resetColors": "恢复颜色",
|
|
64
76
|
"ui.resetRowTitle": "恢复默认",
|
|
65
|
-
"ui.resetRowDesc": "
|
|
77
|
+
"ui.resetRowDesc": "恢复显示偏好或颜色设置。",
|
|
66
78
|
"ui.customTextCount": "已输入 {value}/64 个字符",
|
|
67
79
|
"ui.couldNotDisplayInfoBar": "无法显示信息栏设置:{value}",
|
|
68
80
|
"ui.dataAndBilling": "账单数据",
|
|
@@ -153,7 +165,9 @@ export const LOCALES = {
|
|
|
153
165
|
"ui.subscriptionExpiresLocalTime": "订阅到期:{value}(本地时区)",
|
|
154
166
|
"ui.expires": "到期",
|
|
155
167
|
"ui.subscriptionSource": "订阅源:{value}(",
|
|
156
|
-
"ui.prepaidBalance": "
|
|
168
|
+
"ui.prepaidBalance": "可用余额",
|
|
169
|
+
"ui.availableBalanceLabel": "可用余额",
|
|
170
|
+
"ui.remainingCredits": "剩余额度",
|
|
157
171
|
"ui.availableBalance": "可用余额:{balTxt}",
|
|
158
172
|
"ui.availableCredits": "剩余 credits:{value}",
|
|
159
173
|
"ui.credits": "积分",
|
|
@@ -185,7 +199,7 @@ export const LOCALES = {
|
|
|
185
199
|
"ui.thisSpendRecordWasNot": "本次账单未保存,不会计入金额:",
|
|
186
200
|
"ui.ledgerUpdatePending": "账单待整理",
|
|
187
201
|
"ui.spendNotSaved": "账单未保存",
|
|
188
|
-
"ui.askYourAgentToUpdate": "
|
|
202
|
+
"ui.askYourAgentToUpdate": "发现插件新版本 {latest}。桌面端更新请在插件管理中完成。",
|
|
189
203
|
"ui.updateAvailable": "新版本提醒",
|
|
190
204
|
"ui.updateCommandCopied": "更新命令已复制",
|
|
191
205
|
"ui.tools": "工具调用",
|
|
@@ -258,6 +272,8 @@ export const LOCALES = {
|
|
|
258
272
|
"host.customTextMustBeAString": "自定义文本必须是字符串",
|
|
259
273
|
"host.customTextTooLong": "自定义文本不能超过64字符",
|
|
260
274
|
"host.quotaDisplayModeInvalid": "订阅窗口百分比方向必须是 used 或 remaining",
|
|
275
|
+
"host.infoDensityMustBeFullOrCompact": "信息显示方式必须是完整或简洁",
|
|
276
|
+
"host.displayPreferencesMustBeAnObject": "显示偏好必须是有效的开关对象",
|
|
261
277
|
"host.fieldsMustBeAnObject": "fields 必须是对象",
|
|
262
278
|
"host.unknownFieldId": "未知字段 id: {key}",
|
|
263
279
|
"host.fieldVisibilityMustBeA": "字段开关必须是布尔值: {key}",
|
|
@@ -292,7 +308,8 @@ export const LOCALES = {
|
|
|
292
308
|
"field.subWindowMonth.note": "显示每月额度的剩余比例。",
|
|
293
309
|
"field.resetCountdown.label": "距额度重置",
|
|
294
310
|
"field.resetCountdown.note": "显示当前额度何时重置。",
|
|
295
|
-
"field.subBalance.
|
|
311
|
+
"field.subBalance.label": "可用余额或剩余额度",
|
|
312
|
+
"field.subBalance.note": "按量账户显示可用余额;没有额度窗口的 credits 订阅显示剩余额度。",
|
|
296
313
|
"field.billingSpend.label": "本月用量",
|
|
297
314
|
"field.billingSpend.note": "显示本计费周期的实际用量或花费。",
|
|
298
315
|
"field.budget.label": "预算使用情况",
|
|
@@ -409,11 +426,23 @@ export const LOCALES = {
|
|
|
409
426
|
"ui.saving": "Saving…",
|
|
410
427
|
"ui.processing": "Working…",
|
|
411
428
|
"ui.visibleFields": "Visible content",
|
|
429
|
+
"ui.displayModeTitle": "Information display",
|
|
430
|
+
"ui.displayModeDesc": "Compact shows the provider, model, and one essential account detail. Full shows more detail. You can also click the bottom bar to switch.",
|
|
431
|
+
"ui.compactMode": "Compact",
|
|
432
|
+
"ui.fullMode": "Full",
|
|
433
|
+
"ui.fullModeContentTitle": "Full-mode content",
|
|
434
|
+
"ui.fullModeContentDesc": "These options affect Full only, not Compact.",
|
|
435
|
+
"ui.accountDetailsTitle": "Account details",
|
|
436
|
+
"ui.accountDetailsDesc": "Show reset times, subscription expiry, session spend, budgets, and free quota.",
|
|
437
|
+
"ui.conversationStatsTitle": "Conversation stats",
|
|
438
|
+
"ui.conversationStatsDesc": "Show turns, timings, cache, tokens, and context usage.",
|
|
439
|
+
"ui.advancedSettingsTitle": "Advanced settings",
|
|
440
|
+
"ui.advancedSettingsDesc": "Use individual visibility, time, custom text, and colors only when you have a specific need.",
|
|
412
441
|
"ui.timeDateTitle": "Time and date",
|
|
413
442
|
"ui.timeDateDesc": "Time zones and display format for main and world time.",
|
|
414
443
|
"ui.customTextSectionDesc": "Shown in the Info Bar.",
|
|
415
444
|
"ui.resetConfirmTitle": "Reset Info Bar settings",
|
|
416
|
-
"ui.resetConfirmDescFields": "
|
|
445
|
+
"ui.resetConfirmDescFields": "Restore display mode, full-mode content, and advanced display settings. Custom colors are not affected. This applies right away.",
|
|
417
446
|
"ui.resetConfirmDescColors": "All custom colors will be cleared and defaults restored. Field switches are not affected. This applies to the Info Bar right away.",
|
|
418
447
|
"ui.resetConfirmAcknowledge": "I understand this reset cannot be undone",
|
|
419
448
|
"ui.resetConfirmCancel": "Cancel",
|
|
@@ -421,7 +450,7 @@ export const LOCALES = {
|
|
|
421
450
|
"ui.resetLabels": "Restore display",
|
|
422
451
|
"ui.resetColors": "Restore colors",
|
|
423
452
|
"ui.resetRowTitle": "Reset to defaults",
|
|
424
|
-
"ui.resetRowDesc": "Restore display
|
|
453
|
+
"ui.resetRowDesc": "Restore display preferences or colors.",
|
|
425
454
|
"ui.customTextCount": "{value}/64 characters",
|
|
426
455
|
"ui.couldNotDisplayInfoBar": "Could not display Info Bar settings: {value}",
|
|
427
456
|
"ui.dataAndBilling": "Billing data",
|
|
@@ -512,7 +541,9 @@ export const LOCALES = {
|
|
|
512
541
|
"ui.subscriptionExpiresLocalTime": "Subscription expires: {value} (local time)",
|
|
513
542
|
"ui.expires": "Expires",
|
|
514
543
|
"ui.subscriptionSource": "Subscription source: {value} (",
|
|
515
|
-
"ui.prepaidBalance": "
|
|
544
|
+
"ui.prepaidBalance": "Available balance",
|
|
545
|
+
"ui.availableBalanceLabel": "Available balance",
|
|
546
|
+
"ui.remainingCredits": "Credits remaining",
|
|
516
547
|
"ui.availableBalance": "Available balance: {balTxt}",
|
|
517
548
|
"ui.availableCredits": "Credits remaining: {value}",
|
|
518
549
|
"ui.credits": "credits",
|
|
@@ -544,7 +575,7 @@ export const LOCALES = {
|
|
|
544
575
|
"ui.thisSpendRecordWasNot": "This spend record was not saved and will not be added to totals: ",
|
|
545
576
|
"ui.ledgerUpdatePending": "Ledger update pending",
|
|
546
577
|
"ui.spendNotSaved": "Spend not saved",
|
|
547
|
-
"ui.askYourAgentToUpdate": "
|
|
578
|
+
"ui.askYourAgentToUpdate": "Plugin version {latest} is available. Update it from plugin management on desktop.",
|
|
548
579
|
"ui.updateAvailable": "Update available",
|
|
549
580
|
"ui.updateCommandCopied": "Update command copied",
|
|
550
581
|
"ui.tools": "Tools",
|
|
@@ -617,6 +648,8 @@ export const LOCALES = {
|
|
|
617
648
|
"host.customTextMustBeAString": "Custom text must be a string",
|
|
618
649
|
"host.customTextTooLong": "Custom text must not exceed 64 characters",
|
|
619
650
|
"host.quotaDisplayModeInvalid": "Subscription window percentage mode must be \"used\" or \"remaining\"",
|
|
651
|
+
"host.infoDensityMustBeFullOrCompact": "Information display must be full or compact",
|
|
652
|
+
"host.displayPreferencesMustBeAnObject": "Display preferences must be a valid switch object",
|
|
620
653
|
"host.fieldsMustBeAnObject": "fields must be an object",
|
|
621
654
|
"host.unknownFieldId": "Unknown field id: {key}",
|
|
622
655
|
"host.fieldVisibilityMustBeA": "Field visibility must be a boolean: {key}",
|
|
@@ -651,7 +684,8 @@ export const LOCALES = {
|
|
|
651
684
|
"field.subWindowMonth.note": "Shows the remaining monthly quota.",
|
|
652
685
|
"field.resetCountdown.label": "Quota reset",
|
|
653
686
|
"field.resetCountdown.note": "Shows when the current quota resets.",
|
|
654
|
-
"field.subBalance.
|
|
687
|
+
"field.subBalance.label": "Available balance or credits",
|
|
688
|
+
"field.subBalance.note": "Shows available balance for pay-as-you-go accounts, or remaining credits when a subscription has no visible quota window.",
|
|
655
689
|
"field.billingSpend.label": "Monthly usage",
|
|
656
690
|
"field.billingSpend.note": "Shows actual usage or spend for the current billing period.",
|
|
657
691
|
"field.budget.label": "Budget status",
|