dsh-bottom-info-bar 1.19.3 → 1.19.4
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 +9 -9
- package/README.zh-CN.md +9 -9
- package/lib/client.js +95 -96
- package/lib/constants.js +81 -62
- package/lib/index.js +3 -2
- package/lib/locales.js +8 -8
- package/lib/self-update.js +10 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,11 +20,11 @@ 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, and they differ in exactly one way: **Full** keeps DSH's native stats row above the main row, **Compact** collapses it. Both show every enabled plugin field and notice — a field's own switch is the only thing that decides whether it appears. Both follow DSH's light or dark theme.
|
|
24
24
|
|
|
25
25
|
## Compact mode
|
|
26
26
|
|
|
27
|
-
Four real states — light and dark, balance and subscription quota.
|
|
27
|
+
Compact mode collapses the native stats row only; the main row keeps showing your enabled plugin fields. Four real states — light and dark, balance and subscription quota.
|
|
28
28
|
|
|
29
29
|
**Light · balance**
|
|
30
30
|
|
|
@@ -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
|
+
Every available quota window (5-hour / weekly / monthly) and its countdown to the next reset are shown together — 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. Turn off any window you do not want; Compact mode will not hide it for you.
|
|
56
56
|
|
|
57
57
|
### Cloud billing
|
|
58
58
|
|
|
@@ -96,15 +96,15 @@ Everything lives on the plugin page — **Plugins → bottom-info-bar**. Changes
|
|
|
96
96
|
|
|
97
97
|

|
|
98
98
|
|
|
99
|
-
**Information display** — choose **Compact** or **Full** and the choice is saved. Compact
|
|
99
|
+
**Information display** — choose **Compact** or **Full** and the choice is saved. They differ in exactly one place: Full also keeps DSH's native stats row, Compact collapses it. No field choice is affected, so switching back and forth never loses your setup.
|
|
100
100
|
|
|
101
|
-
**Fields and colors** — one switch and one color per field, in three groups. Turn a field off and the bar drops it
|
|
101
|
+
**Fields and colors** — one switch and one color per field, in three groups. Turn a field off and the bar drops it — **identically in Compact and Full**. All three groups start collapsed; click a group to open it (typing in the search box opens all three).
|
|
102
102
|
|
|
103
|
-
- **Native information** — the fields DSH's own stats row already showed. They
|
|
104
|
-
- **Plugin information** — everything this bar adds: provider and model, subscriptions, spend, balance, pricing and quota
|
|
105
|
-
- **Notices** — update and failure badges, plus the "could not refresh" style warnings. Shown in both modes; each one has its own switch.
|
|
103
|
+
- **Native information** — the fields DSH's own stats row already showed. They live in the native row, which only Full mode keeps.
|
|
104
|
+
- **Plugin information** — everything this bar adds: provider and model, subscriptions, spend, balance, pricing and quota, the adopted context ring included. Shown in both modes.
|
|
105
|
+
- **Notices** — update and failure badges, plus the "could not refresh" style warnings. Shown in both modes; each one has its own switch, and a one-off notice simply appears whenever there is really something to say, regardless of density.
|
|
106
106
|
|
|
107
|
-
The context ring sits at the right end of the main row, which
|
|
107
|
+
The context ring sits at the right end of the main row, which exists in both modes — so it stays visible either way.
|
|
108
108
|
|
|
109
109
|

|
|
110
110
|

|
package/README.zh-CN.md
CHANGED
|
@@ -20,11 +20,11 @@ DeepSeek Harness 插件:把输入框下方那行统计栏换成一行信息栏
|
|
|
20
20
|
| 花费 | 本会话(含子代理)、今天、近 30 天、累计 |
|
|
21
21
|
| 其它 | 主时间、世界时间、自定义文字 |
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
信息栏有两种显示方式,点击即可切换,区别只有一处:**完整**在主行之上保留 DSH 原生统计行,**简洁**把它收起。两种方式都显示已启用的全部插件信息与提醒——看哪个字段,只由该字段自己的开关决定。两种方式都跟随 DSH 的深色/浅色主题。
|
|
24
24
|
|
|
25
25
|
## 简洁模式
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
简洁模式只收起原生统计行,主行照常显示已启用的插件信息。四种真实状态:浅色与深色、余额制与订阅额度制。
|
|
28
28
|
|
|
29
29
|
**浅色 · 余额制**
|
|
30
30
|
|
|
@@ -52,7 +52,7 @@ DeepSeek Harness 插件:把输入框下方那行统计栏换成一行信息栏
|
|
|
52
52
|
|
|
53
53
|
### 订阅额度制
|
|
54
54
|
|
|
55
|
-
完整模式显示各窗口剩余额度(5 小时 / 周 / 月)与距下次重置的倒计时——两者始终取自同一个窗口,不会互相矛盾。窗口默认按**剩余**显示百分比,可在设置里切换为**已用**;低额度告警始终按剩余 ≤ 20%
|
|
55
|
+
完整模式显示各窗口剩余额度(5 小时 / 周 / 月)与距下次重置的倒计时——两者始终取自同一个窗口,不会互相矛盾。窗口默认按**剩余**显示百分比,可在设置里切换为**已用**;低额度告警始终按剩余 ≤ 20% 判定。不想要的窗口在设置里单独关掉即可,简洁模式不会替你隐藏它们。
|
|
56
56
|
|
|
57
57
|
### 云账单制
|
|
58
58
|
|
|
@@ -96,15 +96,15 @@ cd dsh-bottom-info-bar
|
|
|
96
96
|
|
|
97
97
|

|
|
98
98
|
|
|
99
|
-
**信息显示方式** ——
|
|
99
|
+
**信息显示方式** —— 选择**简洁**或**完整**,选择会自动保存。两者只差一处:完整模式额外保留 DSH 原生统计行,简洁模式把它收起。字段开关不受影响,切来切去不会丢配置。
|
|
100
100
|
|
|
101
|
-
**字段与配色** ——
|
|
101
|
+
**字段与配色** —— 每个字段一个开关、一个颜色,分三组。关掉哪个字段,信息栏就不再显示它——**简洁与完整完全一致**。三组默认都收起,想看哪组点哪组(在搜索框里打字会把三组一起展开)。
|
|
102
102
|
|
|
103
|
-
- **原生信息** —— DSH
|
|
104
|
-
- **插件信息** ——
|
|
105
|
-
- **提醒信息** ——
|
|
103
|
+
- **原生信息** —— DSH 原生统计栏本来就有的字段,归在原生行里;只有完整模式才看得到这一行。
|
|
104
|
+
- **插件信息** —— 信息栏新增的全部内容:服务商与模型、订阅、花费、余额、定价与额度,以及接管过来的上下文圆环。简洁与完整都显示。
|
|
105
|
+
- **提醒信息** —— 更新与失败短标记,以及「刷新失败」这类一次性提醒。两种模式都显示,每条单独开关;只要当下真的有事要提醒就出现,与模式无关。
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
上下文圆环固定在主行最右端,而主行在两种模式下都在,所以它始终可见。
|
|
108
108
|
|
|
109
109
|

|
|
110
110
|

|
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.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.versionAndUpdateTitle":"版本与更新","ui.versionAndUpdateDesc":"更新只替换插件自己的程序文件,账单记录和设置不受影响。","ui.versionUnavailable":"当前运行的 DSH 还没载入这一版插件的更新功能,所以这里暂时只显示这一行。重启 DSH 后,下面就会出现当前版本、更新方式与「检查更新」。","ui.versionRunning":"运行中版本 {version}","ui.versionLatest":"最新版本 {version}","ui.versionLastCheck":"上次检查:{time}","ui.versionUnknown":"未知","ui.timeJustNow":"刚刚","ui.timeMinutesAgo":"{n} 分钟前","ui.timeHoursAgo":"{n} 小时前","ui.timeDaysAgo":"{n} 天前","ui.autoUpdateTitle":"更新方式","ui.updateModeAutoDesc":"有新版本就自己下载好,你重启一次 DSH 就生效。","ui.updateModeManualDesc":"只提示不下载。你想装的时候点右边的「检查更新」。","ui.updateModeAuto":"全自动更新","ui.updateModeManual":"手动更新","ui.autoUpdateOn":"已开启","ui.autoUpdateOff":"已关闭","ui.updateCheckNow":"检查更新","ui.updateChecking":"检查中…","ui.updateRetrying":"重试","ui.updateUpToDate":"已是最新版本。","ui.updateDisabled":"当前环境不支持自动更新","ui.updateDisabledWhy":"自动更新只在插件装进 DSH 插件目录后可用。这一份是从源码或链接装进来的,升级请用原来的命令。","ui.updatePendingRestart":"已更新到 {version},重启 DSH 后生效。","ui.updateInProgress":"发现新版本 {version},正在自动更新…","ui.updateAutoOffPending":"有新版本 {version},当前是手动更新方式。","ui.updateFailed":"上次更新没成功","ui.updateFallbackWhy":"万一新版有问题,可以退回上一版。","ui.updateHoldWhy":"这个版本被你暂缓过,不会自己装回来。","ui.updateErrorIncompleteDownload":"更新包没下完整(网络中途断了),这次已放弃,你现在用的版本没受影响。","ui.updateErrorIntegrityMismatch":"更新包没通过安全校验,这次已放弃,你现在用的版本没受影响。","ui.updateErrorDownloadFailed":"连不上更新服务器,稍后再试。","ui.updateErrorTooLarge":"更新包大得反常,出于安全已放弃。","ui.updateErrorPayloadMismatch":"更新包的内容和版本号对不上,已放弃。","ui.updateErrorPayloadUnsafe":"更新包里出现了不该有的文件路径,已放弃。","ui.updateErrorCheckFailed":"检查更新没成功,可能是网络问题。","ui.updateErrorUnknown":"更新没成功,详细原因记在更新日志里。","ui.updateRollback":"回滚到上一版","ui.updateRolledBack":"已回滚到上一版 {version}。","ui.updateHeld":"新版 {version} 已被你暂缓,不会自动装回来。","ui.updateAllowHeld":"允许更新到 {version}","ui.updateRestartBadge":"重启生效","ui.updateFailedBadge":"更新失败","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.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}","number.thousand":"{value}K","number.million":"{value}M","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.label":"更新提醒","field.updateNotice.note":"有新版本可下载、或新版已下载待重启时显示短标记。","field.updateFailure.label":"更新失败提醒","field.updateFailure.note":"自动更新失败时显示短标记。","group.native":"原生信息","group.plugin":"插件信息","group.notice":"提醒信息","group.native.desc":"DeepSeek 原生底栏原有的字段,只在完整模式显示。开关只决定开和关,与模式不冲突。","group.plugin.desc":"本插件新增的字段(含接管过来的上下文圆环),简洁模式与完整模式都会显示。","group.notice.desc":"更新、失败等一次性提醒。可整组关掉,不影响上面的信息显示。","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":"Information to show","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 all display choices. Custom colors are not affected and the change 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 displayed items 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.versionAndUpdateTitle":"Version and updates","ui.versionAndUpdateDesc":"Updates replace only the plugin's own files; billing records and settings are untouched.","ui.versionUnavailable":"The DSH currently running has not loaded this version of the plugin yet, so only this line can be shown here. Restart DSH and the running version, the update mode and the check button will appear.","ui.versionRunning":"Running version {version}","ui.versionLatest":"Latest version {version}","ui.versionLastCheck":"Last checked {time}","ui.versionUnknown":"Unknown","ui.timeJustNow":"just now","ui.timeMinutesAgo":"{n} min ago","ui.timeHoursAgo":"{n} h ago","ui.timeDaysAgo":"{n} d ago","ui.autoUpdateTitle":"Update method","ui.updateModeAutoDesc":"A new version is downloaded for you; restart DSH once to apply it.","ui.updateModeManualDesc":"Only checked, not downloaded. Press Check now when you want to install it.","ui.updateModeAuto":"Automatic","ui.updateModeManual":"Manual","ui.autoUpdateOn":"On","ui.autoUpdateOff":"Off","ui.updateCheckNow":"Check now","ui.updateChecking":"Checking…","ui.updateRetrying":"Retry","ui.updateUpToDate":"Up to date.","ui.updateDisabled":"Automatic updates are unavailable here","ui.updateDisabledWhy":"Automatic updates need the plugin installed into the DSH plugin directory. This copy came from a source checkout or a link, so use the original update command.","ui.updatePendingRestart":"Updated to {version}. Restart DSH to activate.","ui.updateInProgress":"Version {version} found; updating automatically…","ui.updateAutoOffPending":"Version {version} is available. Updates are set to manual.","ui.updateFailed":"The last update did not succeed","ui.updateFallbackWhy":"If the new version misbehaves, you can go back to the previous one.","ui.updateHoldWhy":"You held this version back, so it will not be installed automatically.","ui.updateErrorIncompleteDownload":"The download was incomplete (the connection dropped). This update was abandoned and the version you have is untouched.","ui.updateErrorIntegrityMismatch":"The update package failed its safety check, so it was abandoned. The version you have is untouched.","ui.updateErrorDownloadFailed":"Could not reach the update server. Try again later.","ui.updateErrorTooLarge":"The update package was unusually large, so it was abandoned.","ui.updateErrorPayloadMismatch":"The update package did not match its version number, so it was abandoned.","ui.updateErrorPayloadUnsafe":"The update package contained an unexpected file path, so it was abandoned.","ui.updateErrorCheckFailed":"The version check did not succeed, possibly a network problem.","ui.updateErrorUnknown":"The update did not succeed. Details are in the update log.","ui.updateRollback":"Roll back to previous version","ui.updateRolledBack":"Rolled back to the previous version {version}.","ui.updateHeld":"Version {version} is held back and will not be installed automatically.","ui.updateAllowHeld":"Allow updating to {version}","ui.updateRestartBadge":"Restart to apply","ui.updateFailedBadge":"Update failed","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.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. Full mode only.","field.llmTime.label":"Model time","field.llmTime.note":"Shows model inference time. Full mode only.","field.toolTime.label":"Tool time","field.toolTime.note":"Shows tool execution time. Full mode only.","field.cacheHit.note":"Shows the prompt cache hit rate. Full mode only.","field.tokensIO.label":"Input / output tokens","field.tokensIO.note":"Shows this session’s input and output usage. Full mode only.","field.contextUsage.label":"Context usage","field.contextUsage.note":"Shows context usage. Full mode only.","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}","number.thousand":"{value}K","number.million":"{value}M","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.label":"Update notice","field.updateNotice.note":"Shows a short marker when a new version is available or a downloaded version is waiting for a restart.","field.updateFailure.label":"Update failure notice","field.updateFailure.note":"Shows a short marker when the automatic update failed.","group.native":"Native information","group.plugin":"Plugin information","group.notice":"Notices","group.native.desc":"Fields the DeepSeek bar already had. Full mode only. The switch only turns a field on or off; it never changes the mode.","group.plugin.desc":"Fields this plugin adds, the adopted context ring included. Shown in both compact and full mode.","group.notice.desc":"One-off notices such as updates and failures. Turn the whole list off without touching the information above.","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.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.versionAndUpdateTitle":"版本与更新","ui.versionAndUpdateDesc":"更新只替换插件自己的程序文件,账单记录和设置不受影响。","ui.versionUnavailable":"当前运行的 DSH 还没载入这一版插件的更新功能,所以这里暂时只显示这一行。重启 DSH 后,下面就会出现当前版本、更新方式与「检查更新」。","ui.versionRunning":"运行中版本 {version}","ui.versionLatest":"最新版本 {version}","ui.versionLastCheck":"上次检查:{time}","ui.versionUnknown":"未知","ui.timeJustNow":"刚刚","ui.timeMinutesAgo":"{n} 分钟前","ui.timeHoursAgo":"{n} 小时前","ui.timeDaysAgo":"{n} 天前","ui.autoUpdateTitle":"更新方式","ui.updateModeAutoDesc":"有新版本就自己下载好,你重启一次 DSH 就生效。","ui.updateModeManualDesc":"只提示不下载。你想装的时候点右边的「检查更新」。","ui.updateModeAuto":"全自动更新","ui.updateModeManual":"手动更新","ui.autoUpdateOn":"已开启","ui.autoUpdateOff":"已关闭","ui.updateCheckNow":"检查更新","ui.updateChecking":"检查中…","ui.updateRetrying":"重试","ui.updateUpToDate":"已是最新版本。","ui.updateDisabled":"当前环境不支持自动更新","ui.updateDisabledWhy":"自动更新只在插件装进 DSH 插件目录后可用。这一份是从源码或链接装进来的,升级请用原来的命令。","ui.updatePendingRestart":"已更新到 {version},重启 DSH 后生效。","ui.updateInProgress":"发现新版本 {version},正在自动更新…","ui.updateAutoOffPending":"有新版本 {version},当前是手动更新方式。","ui.updateFailed":"上次更新没成功","ui.updateFallbackWhy":"万一新版有问题,可以退回上一版。","ui.updateHoldWhy":"这个版本被你暂缓过,不会自己装回来。","ui.updateErrorIncompleteDownload":"更新包没下完整(网络中途断了),这次已放弃,你现在用的版本没受影响。","ui.updateErrorIntegrityMismatch":"更新包没通过安全校验,这次已放弃,你现在用的版本没受影响。","ui.updateErrorDownloadFailed":"连不上更新服务器,稍后再试。","ui.updateErrorTooLarge":"更新包大得反常,出于安全已放弃。","ui.updateErrorPayloadMismatch":"更新包的内容和版本号对不上,已放弃。","ui.updateErrorPayloadUnsafe":"更新包里出现了不该有的文件路径,已放弃。","ui.updateErrorCheckFailed":"检查更新没成功,可能是网络问题。","ui.updateErrorUnknown":"更新没成功,详细原因记在更新日志里。","ui.updateRollback":"回滚到上一版","ui.updateRolledBack":"已回滚到上一版 {version}。","ui.updateHeld":"新版 {version} 已被你暂缓,不会自动装回来。","ui.updateAllowHeld":"允许更新到 {version}","ui.updateRestartBadge":"重启生效","ui.updateFailedBadge":"更新失败","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.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}","number.thousand":"{value}K","number.million":"{value}M","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.label":"更新提醒","field.updateNotice.note":"有新版本可下载、或新版已下载待重启时显示短标记。","field.updateFailure.label":"更新失败提醒","field.updateFailure.note":"自动更新失败时显示短标记。","group.native":"原生信息","group.plugin":"插件信息","group.notice":"提醒信息","group.native.desc":"DeepSeek 原生底栏原有的字段,归在原生行里;只有完整模式保留那一行。每条一个开关。","group.plugin.desc":"本插件新增的字段(含接管过来的上下文圆环),归在主行里;简洁与完整都显示。每条一个开关。","group.notice.desc":"更新、失败等一次性提醒。当下真有事要提醒就出现,与模式无关;每条一个开关。","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":"Information to show","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 all display choices. Custom colors are not affected and the change 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 displayed items 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.versionAndUpdateTitle":"Version and updates","ui.versionAndUpdateDesc":"Updates replace only the plugin's own files; billing records and settings are untouched.","ui.versionUnavailable":"The DSH currently running has not loaded this version of the plugin yet, so only this line can be shown here. Restart DSH and the running version, the update mode and the check button will appear.","ui.versionRunning":"Running version {version}","ui.versionLatest":"Latest version {version}","ui.versionLastCheck":"Last checked {time}","ui.versionUnknown":"Unknown","ui.timeJustNow":"just now","ui.timeMinutesAgo":"{n} min ago","ui.timeHoursAgo":"{n} h ago","ui.timeDaysAgo":"{n} d ago","ui.autoUpdateTitle":"Update method","ui.updateModeAutoDesc":"A new version is downloaded for you; restart DSH once to apply it.","ui.updateModeManualDesc":"Only checked, not downloaded. Press Check now when you want to install it.","ui.updateModeAuto":"Automatic","ui.updateModeManual":"Manual","ui.autoUpdateOn":"On","ui.autoUpdateOff":"Off","ui.updateCheckNow":"Check now","ui.updateChecking":"Checking…","ui.updateRetrying":"Retry","ui.updateUpToDate":"Up to date.","ui.updateDisabled":"Automatic updates are unavailable here","ui.updateDisabledWhy":"Automatic updates need the plugin installed into the DSH plugin directory. This copy came from a source checkout or a link, so use the original update command.","ui.updatePendingRestart":"Updated to {version}. Restart DSH to activate.","ui.updateInProgress":"Version {version} found; updating automatically…","ui.updateAutoOffPending":"Version {version} is available. Updates are set to manual.","ui.updateFailed":"The last update did not succeed","ui.updateFallbackWhy":"If the new version misbehaves, you can go back to the previous one.","ui.updateHoldWhy":"You held this version back, so it will not be installed automatically.","ui.updateErrorIncompleteDownload":"The download was incomplete (the connection dropped). This update was abandoned and the version you have is untouched.","ui.updateErrorIntegrityMismatch":"The update package failed its safety check, so it was abandoned. The version you have is untouched.","ui.updateErrorDownloadFailed":"Could not reach the update server. Try again later.","ui.updateErrorTooLarge":"The update package was unusually large, so it was abandoned.","ui.updateErrorPayloadMismatch":"The update package did not match its version number, so it was abandoned.","ui.updateErrorPayloadUnsafe":"The update package contained an unexpected file path, so it was abandoned.","ui.updateErrorCheckFailed":"The version check did not succeed, possibly a network problem.","ui.updateErrorUnknown":"The update did not succeed. Details are in the update log.","ui.updateRollback":"Roll back to previous version","ui.updateRolledBack":"Rolled back to the previous version {version}.","ui.updateHeld":"Version {version} is held back and will not be installed automatically.","ui.updateAllowHeld":"Allow updating to {version}","ui.updateRestartBadge":"Restart to apply","ui.updateFailedBadge":"Update failed","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.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. Full mode only.","field.llmTime.label":"Model time","field.llmTime.note":"Shows model inference time. Full mode only.","field.toolTime.label":"Tool time","field.toolTime.note":"Shows tool execution time. Full mode only.","field.cacheHit.note":"Shows the prompt cache hit rate. Full mode only.","field.tokensIO.label":"Input / output tokens","field.tokensIO.note":"Shows this session’s input and output usage. Full mode only.","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}","number.thousand":"{value}K","number.million":"{value}M","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.label":"Update notice","field.updateNotice.note":"Shows a short marker when a new version is available or a downloaded version is waiting for a restart.","field.updateFailure.label":"Update failure notice","field.updateFailure.note":"Shows a short marker when the automatic update failed.","group.native":"Native information","group.plugin":"Plugin information","group.notice":"Notices","group.native.desc":"Fields the DeepSeek bar already had. They live in the native row, which only Full mode keeps. One switch each.","group.plugin.desc":"Fields this plugin adds, the adopted context ring included. They live in the main row, shown in both modes. One switch each.","group.notice.desc":"One-off notices such as updates and failures. They appear whenever there is really something to say, whatever the mode. One switch each.","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 失效时
|
|
@@ -235,59 +235,57 @@ function mergeLoadResults(prev, results, selectionKey) {
|
|
|
235
235
|
// ---------- v1.9.0 PR2:字段显隐/颜色配置(宿主落盘,设置页变更后经 CustomEvent 即时同步) ----------
|
|
236
236
|
// 字段注册表/预设色板由构建从 constants.js 注入(单一来源,宿主白名单同源)
|
|
237
237
|
const FIELD_REGISTRY = [
|
|
238
|
-
//
|
|
239
|
-
{ id: 'anchorGroup', label: "field.anchorGroup.label", group: 'plugin',
|
|
240
|
-
{ id: 'subServiceGroup', label: "field.subServiceGroup.label", group: 'plugin',
|
|
241
|
-
{ id: 'billingServiceGroup', label: "field.billingServiceGroup.label", group: 'plugin',
|
|
242
|
-
//
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
{ id: '
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
//
|
|
250
|
-
{ id: '
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
{ id: '
|
|
255
|
-
{ id: '
|
|
256
|
-
{ id: '
|
|
257
|
-
|
|
258
|
-
{ id: '
|
|
259
|
-
{ id: '
|
|
260
|
-
|
|
261
|
-
{ id: '
|
|
262
|
-
{ id: '
|
|
263
|
-
{ id: '
|
|
264
|
-
//
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
{ id: '
|
|
271
|
-
{ id: '
|
|
272
|
-
{ id: '
|
|
273
|
-
{ id: '
|
|
274
|
-
|
|
275
|
-
// ---------- 提醒字段(第三个列表「提醒信息」,2026-09-25 用户拍板从插件组独立) ----------
|
|
238
|
+
// ---------- 插件信息 · 身份锚点(服务商 · 模型;三种计费形态各一个,用户可隐藏) ----------
|
|
239
|
+
{ id: 'anchorGroup', label: "field.anchorGroup.label", group: 'plugin', anchor: true, colorKind: 'provider', note: "field.anchorGroup.note" },
|
|
240
|
+
{ id: 'subServiceGroup', label: "field.subServiceGroup.label", group: 'plugin', anchor: true, colorKind: 'provider', note: "field.subServiceGroup.note" },
|
|
241
|
+
{ id: 'billingServiceGroup', label: "field.billingServiceGroup.label", group: 'plugin', anchor: true, colorKind: 'provider', note: "field.billingServiceGroup.note" },
|
|
242
|
+
// ---------- 插件信息 · 通用(任何计费形态都可能出现) ----------
|
|
243
|
+
// 自定义文字:纯自定义,位于服务商/模型左侧;为空时不渲染(开关可保持开启,无内容就无占位)
|
|
244
|
+
{ id: 'customText', label: "field.customText.label", group: 'plugin', defaultOff: true, colorKind: 'inherit', note: "field.customText.note" },
|
|
245
|
+
// 主/世界时间:时区与格式在设置页「时间与日期」中独立配置
|
|
246
|
+
{ id: 'mainTime', label: "field.mainTime.label", group: 'plugin', defaultOff: true, colorKind: 'inherit', note: "field.mainTime.note" },
|
|
247
|
+
{ id: 'worldTime', label: "field.worldTime.label", group: 'plugin', defaultOff: true, colorKind: 'inherit', note: "field.worldTime.note" },
|
|
248
|
+
// 上下文占用圆环(DSH 原生 ContextMeter 的接管版):外观、几何与交互面板与原生一致,显隐/配色并入本插件字段体系;
|
|
249
|
+
// 固定在主行最右端,原生那一份由样式隐藏。归 plugin 组是结论而非笔误:它住在主行,而主行两种模式都可见。
|
|
250
|
+
{ id: 'contextUsage', label: "field.contextUsage.label", group: 'plugin', colorKind: 'meter', note: "field.contextUsage.note" },
|
|
251
|
+
// ---------- 插件信息 · 余额制(balance) ----------
|
|
252
|
+
// 本会话花费:余额制与"订阅 · 充值余额"形态共用(见 pushSessionCost)
|
|
253
|
+
{ id: 'sessionCost', label: "field.sessionCost.label", group: 'plugin', colorKind: 'inherit', note: "field.sessionCost.note" },
|
|
254
|
+
{ id: 'balance', label: "ui.balance.pushBalanceGroups", group: 'plugin', colorKind: 'inherit', note: "field.balance.note" },
|
|
255
|
+
{ id: 'period', label: "field.period.label", group: 'plugin', colorKind: 'period', note: "field.period.note" },
|
|
256
|
+
{ id: 'countdown', label: "field.countdown.label", group: 'plugin', colorKind: 'inherit', note: "field.countdown.note" },
|
|
257
|
+
// ---------- 插件信息 · 订阅制(subscription) ----------
|
|
258
|
+
{ id: 'expiry', label: "field.expiry.label", group: 'plugin', colorKind: 'inherit', note: "field.expiry.note" },
|
|
259
|
+
{ id: 'subWindow5h', label: "field.subWindow5h.label", group: 'plugin', colorKind: 'inherit', note: "field.subWindow5h.note" },
|
|
260
|
+
{ id: 'subWindowWeek', label: "field.subWindowWeek.label", group: 'plugin', colorKind: 'inherit', note: "field.subWindowWeek.note" },
|
|
261
|
+
{ id: 'subWindowMonth', label: "field.subWindowMonth.label", group: 'plugin', colorKind: 'inherit', note: "field.subWindowMonth.note" },
|
|
262
|
+
{ id: 'resetCountdown', label: "field.resetCountdown.label", group: 'plugin', colorKind: 'inherit', note: "field.resetCountdown.note" },
|
|
263
|
+
{ id: 'subBalance', label: "field.subBalance.label", group: 'plugin', colorKind: 'inherit', note: "field.subBalance.note" },
|
|
264
|
+
// ---------- 插件信息 · 账单制(billing) ----------
|
|
265
|
+
{ id: 'billingSpend', label: "field.billingSpend.label", group: 'plugin', colorKind: 'inherit', note: "field.billingSpend.note" },
|
|
266
|
+
{ id: 'budget', label: "field.budget.label", group: 'plugin', colorKind: 'inherit', note: "field.budget.note" },
|
|
267
|
+
{ id: 'freeQuota', label: "field.freeQuota.label", group: 'plugin', colorKind: 'inherit', note: "field.freeQuota.note" },
|
|
268
|
+
// ---------- 原生信息(DSH 原生统计行原有字段;整组只在完整模式可见) ----------
|
|
269
|
+
{ id: 'turnsSteps', label: "field.turnsSteps.label", group: 'native', colorKind: 'inherit', note: "field.turnsSteps.note" },
|
|
270
|
+
{ id: 'llmTime', label: "field.llmTime.label", group: 'native', colorKind: 'inherit', note: "field.llmTime.note" },
|
|
271
|
+
{ id: 'toolTime', label: "field.toolTime.label", group: 'native', colorKind: 'inherit', note: "field.toolTime.note" },
|
|
272
|
+
{ id: 'cacheHit', label: "ui.cacheHit", group: 'native', colorKind: 'inherit', note: "field.cacheHit.note" },
|
|
273
|
+
{ id: 'tokensIO', label: "field.tokensIO.label", group: 'native', colorKind: 'inherit', note: "field.tokensIO.note" },
|
|
274
|
+
// ---------- 提醒信息(第三个列表,2026-09-25 用户拍板从插件组独立) ----------
|
|
276
275
|
// 独立成组的理由:提醒是「一次性事件」而不是「常驻信息」,诉求与插件信息相反 ——
|
|
277
276
|
// 想看花费但不想被红字打扰的人,必须能只关提醒而不动信息。
|
|
278
|
-
//
|
|
279
|
-
// 开关与显示模式互不读写,关掉开关也不会去改模式 —— 这是 2026-09-25 用户明确要求的解耦。
|
|
277
|
+
// 三条铁律:① 两种模式都显示(主行右端);② 只在真有事时出现,没事零占位;③ 开关只管开与关,与模式互不读写。
|
|
280
278
|
// 更新提醒 / 更新失败提醒(自更新体系,见 docs/DECISIONS-AUTO-UPDATE.md)
|
|
281
|
-
{ id: 'updateNotice', label: "field.updateNotice.label", group: 'notice',
|
|
282
|
-
{ id: 'updateFailure', label: "field.updateFailure.label", group: 'notice',
|
|
279
|
+
{ id: 'updateNotice', label: "field.updateNotice.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.updateNotice.note" },
|
|
280
|
+
{ id: 'updateFailure', label: "field.updateFailure.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.updateFailure.note" },
|
|
283
281
|
// 数据类提醒
|
|
284
|
-
{ id: 'balanceError', label: "field.balanceError.label", group: 'notice',
|
|
285
|
-
{ id: 'usageError', label: "field.usageError.label", group: 'notice',
|
|
286
|
-
{ id: 'refreshFailure', label: "field.refreshFailure.label", group: 'notice',
|
|
287
|
-
{ id: 'persistWarning', label: "field.persistWarning.label", group: 'notice',
|
|
282
|
+
{ id: 'balanceError', label: "field.balanceError.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.balanceError.note" },
|
|
283
|
+
{ id: 'usageError', label: "field.usageError.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.usageError.note" },
|
|
284
|
+
{ id: 'refreshFailure', label: "field.refreshFailure.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.refreshFailure.note" },
|
|
285
|
+
{ id: 'persistWarning', label: "field.persistWarning.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.persistWarning.note" },
|
|
288
286
|
// 配置类提醒
|
|
289
|
-
{ id: 'noKeyHint', label: "field.noKeyHint.label", group: 'notice',
|
|
290
|
-
{ id: 'unmapped', label: "field.unmapped.label", group: 'notice',
|
|
287
|
+
{ id: 'noKeyHint', label: "field.noKeyHint.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.noKeyHint.note" },
|
|
288
|
+
{ id: 'unmapped', label: "field.unmapped.label", group: 'notice', colorKind: 'muted', note: "field.unmapped.note" },
|
|
291
289
|
];
|
|
292
290
|
const PRESET_COLORS = ['red', 'green', 'blue', 'purple', 'orange', 'neutral'];
|
|
293
291
|
const PRESET_COLOR_SET = new Set(PRESET_COLORS);
|
|
@@ -518,7 +516,7 @@ function buildFieldColorCss() {
|
|
|
518
516
|
return rules.join('\n');
|
|
519
517
|
}
|
|
520
518
|
const FIELD_COLOR_CSS = buildFieldColorCss();
|
|
521
|
-
// 订阅窗口 key → 字段 id
|
|
519
|
+
// 订阅窗口 key → 字段 id:三个窗口是三个独立字段,各自开关、各自着色,两种模式一视同仁
|
|
522
520
|
const WINDOW_FIELD_IDS = { five_hour: 'subWindow5h', seven_day: 'subWindowWeek', monthly: 'subWindowMonth' };
|
|
523
521
|
function windowFieldVisible(key) {
|
|
524
522
|
const id = WINDOW_FIELD_IDS[key];
|
|
@@ -638,12 +636,12 @@ function installStyles() {
|
|
|
638
636
|
.bi-low-status { margin-left: 3px; color: var(--bi-state-alert); font-weight: 600; }
|
|
639
637
|
.bi-root b.bi-alert-num, .bi-root b.bi-quota-low { color: var(--bi-state-alert); font-weight: 700; }
|
|
640
638
|
/* 新版本需要用户处理:与其它提醒统一用鲜红警示色,不伪装成链接。
|
|
641
|
-
|
|
642
|
-
|
|
639
|
+
只用手型光标作提示——不加下划线、不改颜色,保持「告警」而非「链接」的语义
|
|
640
|
+
(test-update-check 有「无下划线」的专项断言)。 */
|
|
643
641
|
.bi-update{ color: var(--bi-state-alert); font-weight: 600; cursor: pointer; }
|
|
644
642
|
/* 自更新状态短标记:只在「已下载待重启」或「上次自动更新失败」时出现,重启/修复后自动消失。
|
|
645
|
-
与 .bi-update
|
|
646
|
-
|
|
643
|
+
与 .bi-update 区分:它不需要用户点击,所以用默认光标 + 1px currentColor 描边成胶囊,
|
|
644
|
+
明确「这是状态标签,不是可点链接」。
|
|
647
645
|
反色铁律:只描边、不加背景色,文字仍落在信息栏自身底色上(与 .bi-err 同色同底),
|
|
648
646
|
不引入任何新的前景/背景配对,明暗主题都沿用既有已验证的对比度。 */
|
|
649
647
|
.bi-update-badge{ margin-left: 6px; padding: 0 5px; border: 1px solid currentColor; border-radius: 4px; font-weight: 600; color: var(--bi-state-alert); cursor: default; }
|
|
@@ -3310,6 +3308,17 @@ module.exports = {
|
|
|
3310
3308
|
}
|
|
3311
3309
|
}
|
|
3312
3310
|
|
|
3311
|
+
// 主行开头的「身份区」:自定义文字 → 服务锚点 → 主/世界时间。三种计费形态完全同型,
|
|
3312
|
+
// 共用这一个入口 —— 以前三处各抄一遍,还各带一个 `if (full)` 门控,同一个 bug 抄了三遍。
|
|
3313
|
+
// 门控只有「锚点字段是否存在」一条;自定义文字与时间各自在自己的函数里判开关,与模式无关。
|
|
3314
|
+
function pushIdentityGroups(groups, anchorId, buildAnchor) {
|
|
3315
|
+
pushCustomText(groups);
|
|
3316
|
+
if (fieldVisible(anchorId)) {
|
|
3317
|
+
groups.push(React.cloneElement(buildAnchor(), { 'data-field': anchorId, style: fieldStyle(anchorId) }));
|
|
3318
|
+
}
|
|
3319
|
+
pushTimeGroups(groups);
|
|
3320
|
+
}
|
|
3321
|
+
|
|
3313
3322
|
// ---- 余额制模式(v1.0.0 现状,完全不动):服务商+模型 → 余额 → 时段 → 倒计时 → 本会话花费 ----
|
|
3314
3323
|
// v1.9.0 PR2:每个渲染片段按设置过滤(fieldVisible);隐藏不占位,组间分隔符由组装层自动收合
|
|
3315
3324
|
function pushBalanceGroups(groups, trailingErrorGroups) {
|
|
@@ -3317,12 +3326,7 @@ module.exports = {
|
|
|
3317
3326
|
const errors = renderedState.errors || {};
|
|
3318
3327
|
if (bal && bal.selectionPending) return;
|
|
3319
3328
|
const alertActive = !!(bal && bal.alert && bal.alert.active);
|
|
3320
|
-
|
|
3321
|
-
if (fieldVisible('anchorGroup')) {
|
|
3322
|
-
const anchor = providerGroup();
|
|
3323
|
-
groups.push(React.cloneElement(anchor, { 'data-field': 'anchorGroup', style: fieldStyle('anchorGroup') }));
|
|
3324
|
-
}
|
|
3325
|
-
if (full) pushTimeGroups(groups);
|
|
3329
|
+
pushIdentityGroups(groups, 'anchorGroup', providerGroup);
|
|
3326
3330
|
|
|
3327
3331
|
// v1.6 T7:未适配账户渲染"未适配"弱提示
|
|
3328
3332
|
if (bal && bal.unmapped) {
|
|
@@ -3375,7 +3379,7 @@ module.exports = {
|
|
|
3375
3379
|
|
|
3376
3380
|
// 时段:仅峰谷价服务商显示"高峰价/空闲价"(flat/unknown 服务商不显示;hover 展示具体价格)
|
|
3377
3381
|
const pr = visiblePricing;
|
|
3378
|
-
if (
|
|
3382
|
+
if (pr && pr.mode === 'peak-valley' && fieldVisible('period')) {
|
|
3379
3383
|
const peakNow = pr.period === 'peak';
|
|
3380
3384
|
const p = pr.prices || {};
|
|
3381
3385
|
const periodTitle = t('ui.beijingTime') + (peakNow ? t('ui.peakPrice') : t('ui.offPeakPrice')) + t('ui.input') + (p.inputCacheMiss != null ? p.inputCacheMiss : '?')
|
|
@@ -3386,7 +3390,7 @@ module.exports = {
|
|
|
3386
3390
|
}
|
|
3387
3391
|
|
|
3388
3392
|
// 倒计时:仅峰谷价服务商显示"距高峰/距空闲"(hover 展示下次切换时刻;数字加粗)
|
|
3389
|
-
if (
|
|
3393
|
+
if (pr && pr.mode === 'peak-valley' && pr.nextSwitch && fieldVisible('countdown')) {
|
|
3390
3394
|
const peakNow = pr.period === 'peak';
|
|
3391
3395
|
const countdownTitle = t('ui.beijingTimeSwitchesTo', { atLabel: pr.nextSwitch.atLabel }) + (peakNow ? t('ui.offPeakPrice') : t('ui.peakPrice')) + t('ui.sentenceEnd');
|
|
3392
3396
|
groups.push(fieldSpan('countdown', 'countdown', React.createElement('span', { title: countdownTitle },
|
|
@@ -3395,7 +3399,7 @@ module.exports = {
|
|
|
3395
3399
|
|
|
3396
3400
|
// 本会话花费(公共小部件 pushSessionCost:只显示钱;hover 显示 今天/近一月/全部)
|
|
3397
3401
|
// 始终显示:新会话/对话刚开始尚无记账时显示 ¥0.000,hover 仍可查看持久化的 今天/近一月/全部
|
|
3398
|
-
|
|
3402
|
+
pushSessionCost(groups, trailingErrorGroups, !!(bal && bal.currency === 'USD'));
|
|
3399
3403
|
}
|
|
3400
3404
|
|
|
3401
3405
|
// 本会话花费块(余额制 与 订阅·充值余额 形态共用的小部件):
|
|
@@ -3447,16 +3451,11 @@ module.exports = {
|
|
|
3447
3451
|
}
|
|
3448
3452
|
|
|
3449
3453
|
function pushSubscriptionGroups(groups, trailingErrorGroups) {
|
|
3450
|
-
|
|
3451
|
-
if (fieldVisible('subServiceGroup')) {
|
|
3452
|
-
const subAnchor = subscriptionProviderGroup();
|
|
3453
|
-
groups.push(React.cloneElement(subAnchor, { 'data-field': 'subServiceGroup', style: fieldStyle('subServiceGroup') }));
|
|
3454
|
-
}
|
|
3455
|
-
if (full) pushTimeGroups(groups);
|
|
3454
|
+
pushIdentityGroups(groups, 'subServiceGroup', subscriptionProviderGroup);
|
|
3456
3455
|
const sub = renderedState.sub;
|
|
3457
3456
|
const errors = renderedState.errors || {};
|
|
3458
3457
|
// v1.7 FR-8:JWT 订阅卡——真实套餐到期日(纯本地解码;无登录态/解析失败不显示此处)
|
|
3459
|
-
if (
|
|
3458
|
+
if (sub && sub.planType && sub.expiryAt && fieldVisible('expiry')) {
|
|
3460
3459
|
groups.push(fieldSpan('expiry', 'subexp', React.createElement('span', { title: t('ui.subscriptionExpiresLocalTime', { value: formatDate(sub.expiryAt) }) },
|
|
3461
3460
|
metric(t('ui.expires'), formatDate(sub.expiryAt)))));
|
|
3462
3461
|
}
|
|
@@ -3496,7 +3495,7 @@ module.exports = {
|
|
|
3496
3495
|
metric(isCreditsBalance ? t('ui.remainingCredits') : t('ui.availableBalanceLabel'), balanceValue))));
|
|
3497
3496
|
}
|
|
3498
3497
|
// 充值余额用户按量付费,花销与余额同等重要 → 追加公共花费块(含子代理聚合)
|
|
3499
|
-
if (
|
|
3498
|
+
if (!isCreditsBalance) pushSessionCost(groups, trailingErrorGroups, false);
|
|
3500
3499
|
// host 快照失败(sub.error)或本次 RPC 失败(errors.sub)→ 保留旧数据 + 降级标记
|
|
3501
3500
|
if (fieldVisible('refreshFailure') && (sub.error || errors.sub)) {
|
|
3502
3501
|
trailingErrorGroups.push(fieldSpan('refreshFailure', 'substale',
|
|
@@ -3506,8 +3505,9 @@ module.exports = {
|
|
|
3506
3505
|
}
|
|
3507
3506
|
// 窗口缺失(如 Codex 无 5 小时窗口)→ 跳过窗口组,不占位、不报错
|
|
3508
3507
|
if (hasData) {
|
|
3509
|
-
//
|
|
3510
|
-
// 优先级:5小时 > 周 >
|
|
3508
|
+
// 重置倒计时挂在哪个窗口上?取"时间最短且有重置时刻"的那个(刷新最快,用户最需关注):
|
|
3509
|
+
// 优先级:5小时 > 周 > 月(按窗口时长排序,而非已用百分比)。
|
|
3510
|
+
// 窗口组本身按各自的开关全部列出(见下),倒计时只可能挂一个窗口,故单独挑一个。
|
|
3511
3511
|
const windowPriority = { five_hour: 1, seven_day: 2, monthly: 3 };
|
|
3512
3512
|
const byPriority = function (a, b) {
|
|
3513
3513
|
const pa = Object.hasOwn(windowPriority, a.key) ? windowPriority[a.key] : 99;
|
|
@@ -3515,13 +3515,13 @@ module.exports = {
|
|
|
3515
3515
|
return pa - pb;
|
|
3516
3516
|
};
|
|
3517
3517
|
const windowsWithReset = windows.filter(function (w) { return w.resetsAt; });
|
|
3518
|
-
//
|
|
3519
|
-
// 否则 resetsAt
|
|
3520
|
-
const
|
|
3518
|
+
// 有重置时刻的窗口优先(倒计时才有意义);全都没有时退回按时长取最短窗口 ——
|
|
3519
|
+
// 否则 resetsAt 缺失会让整组额度静默丢失倒计时(接口不返回 nextResetTime 时)
|
|
3520
|
+
const resetWindow = (windowsWithReset.length > 0 ? windowsWithReset : windows)
|
|
3521
3521
|
.slice().sort(byPriority)[0] || null;
|
|
3522
3522
|
|
|
3523
|
-
//
|
|
3524
|
-
const visible =
|
|
3523
|
+
// 窗口组:开着的窗口全部列出,简洁模式与完整模式一致(2026-09-26 用户拍板:模式不参与字段显隐)
|
|
3524
|
+
const visible = windows;
|
|
3525
3525
|
|
|
3526
3526
|
// 预警触发条件:已用 ≥80%(= 剩余 ≤20%)→ 鲜红色文字;正常额度使用中性文字。
|
|
3527
3527
|
// 该判定与 quotaDisplayMode 无关(used 模式下即「已用 ≥ 80%」),两种方向语义严格等价。
|
|
@@ -3555,13 +3555,13 @@ module.exports = {
|
|
|
3555
3555
|
trailingErrorGroups.push(fieldSpan('refreshFailure', 'substale',
|
|
3556
3556
|
React.createElement('span', { className: 'bi-stale', title: subscriptionFailureHint(sub.error || { kind: 'exception', message: String(errors.sub || '') }, sub.source || (visibleBillingMode && visibleBillingMode.provider)) }, t('ui.refreshFailed'))));
|
|
3557
3557
|
}
|
|
3558
|
-
//
|
|
3559
|
-
if (
|
|
3558
|
+
// 距重置倒计时(挂在上面挑出的那个窗口上,与它显示的额度匹配)
|
|
3559
|
+
if (resetWindow && resetWindow.resetsAt && fieldVisible('resetCountdown')) {
|
|
3560
3560
|
const cdTitle = windowMode === 'used'
|
|
3561
|
-
? t('ui.windowUsedRemainingResets', { label: quotaWindowLabel(
|
|
3562
|
-
: t('ui.windowRemainingUsedResets', { label: quotaWindowLabel(
|
|
3561
|
+
? t('ui.windowUsedRemainingResets', { label: quotaWindowLabel(resetWindow), value: remainingPercent(resetWindow), usedPercent: resetWindow.usedPercent, value4: formatDateTime(resetWindow.resetsAt) })
|
|
3562
|
+
: t('ui.windowRemainingUsedResets', { label: quotaWindowLabel(resetWindow), value: remainingPercent(resetWindow), usedPercent: resetWindow.usedPercent, value4: formatDateTime(resetWindow.resetsAt) });
|
|
3563
3563
|
groups.push(fieldSpan('resetCountdown', 'subcd', React.createElement('span', { title: cdTitle },
|
|
3564
|
-
metric(t('ui.resetsIn'), fmtResetCountdown(
|
|
3564
|
+
metric(t('ui.resetsIn'), fmtResetCountdown(resetWindow.resetsAt - now)))));
|
|
3565
3565
|
}
|
|
3566
3566
|
}
|
|
3567
3567
|
}
|
|
@@ -3581,12 +3581,7 @@ module.exports = {
|
|
|
3581
3581
|
}
|
|
3582
3582
|
|
|
3583
3583
|
function pushBillingGroups(groups, trailingErrorGroups) {
|
|
3584
|
-
|
|
3585
|
-
if (fieldVisible('billingServiceGroup')) {
|
|
3586
|
-
const billAnchor = billingProviderGroup();
|
|
3587
|
-
groups.push(React.cloneElement(billAnchor, { 'data-field': 'billingServiceGroup', style: fieldStyle('billingServiceGroup') }));
|
|
3588
|
-
}
|
|
3589
|
-
if (full) pushTimeGroups(groups);
|
|
3584
|
+
pushIdentityGroups(groups, 'billingServiceGroup', billingProviderGroup);
|
|
3590
3585
|
const bill = renderedState.billing;
|
|
3591
3586
|
const errors = renderedState.errors || {};
|
|
3592
3587
|
if (!bill) {
|
|
@@ -3619,12 +3614,12 @@ module.exports = {
|
|
|
3619
3614
|
} else if (d.usage != null && fieldVisible('billingSpend')) {
|
|
3620
3615
|
nodes.push(fieldSpan('billingSpend', 'billspend', metric(t('ui.thisMonthSUsage'), fmt(d.usage, 2) + (d.usageUnit ? ' ' + d.usageUnit : ''))));
|
|
3621
3616
|
}
|
|
3622
|
-
if (
|
|
3617
|
+
if (d.budgetPercent != null && fieldVisible('budget')) {
|
|
3623
3618
|
if (nodes.length > 0) nodes.push(' · ');
|
|
3624
3619
|
nodes.push(fieldSpan('budget', 'billbudget', metric(t('ui.budget'), fmt(d.budgetPercent, 0) + '%')));
|
|
3625
3620
|
}
|
|
3626
3621
|
// 免费额度仅当接口显式给出(freeRemaining/resetsAt 同时存在)才显示,绝不编造
|
|
3627
|
-
if (
|
|
3622
|
+
if (d.freeRemaining != null && d.resetsAt && fieldVisible('freeQuota')) {
|
|
3628
3623
|
if (nodes.length > 0) nodes.push(' · ');
|
|
3629
3624
|
nodes.push(fieldSpan('freeQuota', 'billfree', metric(t('ui.free'), t('ui.resetsIn.pushBillingGroups', { value: fmt(d.freeRemaining, 0), value2: fmtResetCountdown(d.resetsAt - now) }))));
|
|
3630
3625
|
}
|
|
@@ -3657,7 +3652,10 @@ module.exports = {
|
|
|
3657
3652
|
const groups = [];
|
|
3658
3653
|
// 报错不打断主要信息的阅读顺序:统一延后到整行最右侧。
|
|
3659
3654
|
const trailingErrorGroups = [];
|
|
3660
|
-
// 两态严格判定:density 只能是 'full' 或 'compact'(host 校验 +
|
|
3655
|
+
// 两态严格判定:density 只能是 'full' 或 'compact'(host 校验 + 本地防抖保证)。
|
|
3656
|
+
// 注意:这个变量唯一的语义是「原生统计行是否参与」——它的全部读取点只有下面构造 row1 之后的
|
|
3657
|
+
// nativeRowShown 与 aria(pressed / 无障碍说明)。字段显隐一律不读它,读它就是设计被破坏
|
|
3658
|
+
// (见 constants.js 的「显示模型」;tests/test-density-toggle.cjs 有硬断言)。
|
|
3661
3659
|
const full = displayDensity === 'full';
|
|
3662
3660
|
// 模式互斥:订阅制渲染订阅版 row2,账单制渲染账单版 row2,余额制渲染 v1.0.0 现状——三态绝不叠加(FR-14)
|
|
3663
3661
|
const isSub = !!(visibleBillingMode && visibleBillingMode.mode === 'subscription');
|
|
@@ -3733,10 +3731,9 @@ module.exports = {
|
|
|
3733
3731
|
|
|
3734
3732
|
// ---- 组装(分隔符收合与「刷新失败」去重见模块级 assembleInfoBarRow) ----
|
|
3735
3733
|
const nodes = assembleInfoBarRow(groups, trailingErrorGroups, React.createElement);
|
|
3736
|
-
// 上下文占用圆环(原型是 DSH
|
|
3734
|
+
// 上下文占用圆环(原型是 DSH 原生信息,已由本插件接管):挂在主行最右端。
|
|
3737
3735
|
// 与其它字段同源:fields.contextUsage 管显隐、colors.contextUsage 管配色;数据不足时整块不渲染。
|
|
3738
|
-
//
|
|
3739
|
-
// 之前写成 full && fieldVisible(...),结果是简洁模式下圆环整块消失,而它恰恰属于主行。
|
|
3736
|
+
// 归 plugin 组、门控只有 fieldVisible 一条 —— 它住在主行,而主行两种模式都可见(见 constants.js 显示模型)。
|
|
3740
3737
|
const contextInfo = fieldVisible('contextUsage') ? contextOccupancy(pressureProj) : null;
|
|
3741
3738
|
const contextNode = contextInfo === null ? null : React.createElement(ContextMeterRing, {
|
|
3742
3739
|
key: 'ctx',
|
|
@@ -3820,6 +3817,8 @@ module.exports = {
|
|
|
3820
3817
|
// · 绝不依赖 fr 轨道或容器自由空间,因此祖先被拉伸/定高时也不会在两行之间冒出空隙。
|
|
3821
3818
|
// ResizeObserver 跟随折行、字号与缩放变化;缺失该 API 的环境退回「只测一次」。
|
|
3822
3819
|
const row1Present = row1 !== null;
|
|
3820
|
+
// `full` 的唯一去处:原生统计行是否参与(可见 + 无障碍名称)。字段显隐与它无关。
|
|
3821
|
+
const nativeRowShown = row1Present && full;
|
|
3823
3822
|
// 优先 layout effect(首帧前测量,折行时不会闪一下裁切);React shim 只提供 useEffect
|
|
3824
3823
|
// 时退回它——功能等价,只是晚一帧对齐高度。
|
|
3825
3824
|
const measureEffect = typeof React.useLayoutEffect === 'function' ? React.useLayoutEffect : React.useEffect;
|
|
@@ -3860,7 +3859,7 @@ module.exports = {
|
|
|
3860
3859
|
},
|
|
3861
3860
|
role: 'button',
|
|
3862
3861
|
tabIndex: 0,
|
|
3863
|
-
'aria-labelledby':
|
|
3862
|
+
'aria-labelledby': nativeRowShown ? 'dsh-bottom-info-bar-native dsh-bottom-info-bar-primary' : 'dsh-bottom-info-bar-primary',
|
|
3864
3863
|
'aria-describedby': 'dsh-bottom-info-bar-action',
|
|
3865
3864
|
'aria-pressed': full,
|
|
3866
3865
|
'aria-busy': isDensitySaving,
|
package/lib/constants.js
CHANGED
|
@@ -6,83 +6,102 @@ export const SUBSCRIPTION_PROVIDERS = ['codex', 'chatgpt', 'opencode-go', 'openc
|
|
|
6
6
|
// 云账单 provider 集合:这些 provider 走"账单型"显示(本月真实花费 / 预算%),与余额型/额度型互斥(FR-14)
|
|
7
7
|
export const BILLING_PROVIDERS = ['together', 'fireworks', 'amazon-bedrock', 'cloudflare-ai-gateway', 'cloudflare-workers-ai']
|
|
8
8
|
|
|
9
|
-
//
|
|
10
|
-
//
|
|
9
|
+
// ============================================================================================
|
|
10
|
+
// 显示模型(唯一一套逻辑,2026-09-26 用户拍板定型 —— 动任何显示相关的代码前先读完这一段)
|
|
11
|
+
// ============================================================================================
|
|
12
|
+
// 一个字段「出现还是不出现」只由两件事决定,没有第三件:
|
|
13
|
+
// ① 字段开关(settings.json 的 fields.<id>)—— 用户唯一要管的东西,开=出现、关=消失;
|
|
14
|
+
// ② 数据条件(当前 provider 有没有这项数据)—— 由 provider 决定,用户在设置页看不到。
|
|
15
|
+
//
|
|
16
|
+
// 字段「属于谁」(group)只决定它出现在哪里、列在设置页哪个列表里:
|
|
17
|
+
// native 原生信息:DSH 原生底栏原有的字段 → 渲染进「原生统计行」→ **只在完整模式可见**
|
|
18
|
+
// plugin 插件信息:本插件新增的字段(含接管过来的上下文圆环)→ 渲染进主行 → **两种模式都可见**
|
|
19
|
+
// notice 提醒信息:一次性提醒 → 渲染在**主行右端** → **两种模式都可见**,只在真有事时出现
|
|
20
|
+
//
|
|
21
|
+
// 模式(简洁 / 完整)的全部职责只有一条:**原生统计行显示不显示**。
|
|
22
|
+
// 它绝不参与任何字段的显隐判定 —— 因此「这个字段在简洁模式下能不能出现」不是独立问题,看 group 就够了。
|
|
23
|
+
// group = native → 进原生统计行(.bi-native-row),随 data-density 收合到 0 高度
|
|
24
|
+
// group = plugin / notice → 进主行(.bi-row2),门控只有 fieldVisible(id) 一条
|
|
25
|
+
//
|
|
26
|
+
// 反面教训(严禁复发):2026-09 曾出现 11 处 `if (full) …` / `full && fieldVisible(…)` 的散落门控,
|
|
27
|
+
// 等于给插件字段偷偷加了第二套规则 —— 开关明明开着、简洁模式下却整块消失。用户报的
|
|
28
|
+
// 「自定义文字打开了却在简洁模式看不到」就是这么来的。tests/test-density-toggle.cjs 里有硬断言:
|
|
29
|
+
// 源码中不允许再出现 `if (full` 分支或 `full && fieldVisible` 门控。
|
|
30
|
+
//
|
|
31
|
+
// 字段对象的键:
|
|
11
32
|
// - id:settings.json fields/colors 的键(稳定英文 id,宿主白名单校验来源)
|
|
12
|
-
// - label
|
|
13
|
-
// -
|
|
14
|
-
// -
|
|
15
|
-
//
|
|
16
|
-
// | notice 提醒字段(更新与失败等一次性提醒;2026-09-25 用户拍板从 plugin 组独立成第三个列表)
|
|
17
|
-
// 2026-09-25 用户再次澄清组别的含义:组别就是「它属于谁」——**简洁模式只显示 plugin 组,
|
|
18
|
-
// 完整模式显示 native + plugin**。因此一个字段归哪一组,直接决定它在简洁模式下能不能出现。
|
|
19
|
-
// 上下文圆环虽然原型来自 DSH 原生底部栏,但已经被本插件接管、且始终渲染在主行(简洁模式可见的
|
|
20
|
-
// 那一行最右端),所以按 plugin 组对待 —— 否则它在简洁模式下会整块消失。
|
|
21
|
-
// 排序:原生信息 → 插件信息 → 提醒信息,与设置页三张折叠卡的顺序一致
|
|
22
|
-
// - note:出现条件说明(设置页每行的小字说明)
|
|
33
|
+
// - label:设置页显示文案的字典键
|
|
34
|
+
// - group:见上(native | plugin | notice)
|
|
35
|
+
// - defaultOff:新装默认关闭(默认缺省=开启)。只有"用户不主动打开就不该出现"的字段才标它。
|
|
36
|
+
// - note:设置页每行的小字说明(只讲"这是什么/什么条件下有数据",不讲模式 —— 模式已由 group 表达)
|
|
23
37
|
// - suggestKeep:错误/提醒类字段,页面标注「建议保留」(用户拍板:允许关闭但劝留)
|
|
24
38
|
// - anchor:身份锚点语义标记(服务商/模型标识)。D6 用户拍板:锚点与其他字段同等可隐藏(无恒开/禁用逻辑),
|
|
25
39
|
// 仅用于设置页说明文字与颜色语义(provider 色回退)。
|
|
26
40
|
// - colorKind:颜色回退语义(客户端生成 CSS 用):inherit 继承正文色 | alert 警示红 | period 峰红/谷绿 |
|
|
27
41
|
// provider 锚点组(正文 + 服务商名主色)| muted 弱提示灰 | meter 原生圆环类(回退原生同款弱提示色 --bi-separator)。
|
|
28
42
|
// 未自定义颜色时回退这些原语义色,默认外观零变化。
|
|
43
|
+
//
|
|
44
|
+
// 关于「计费形态」(余额制 balance / 订阅制 subscription / 账单制 billing):它由 provider 决定,
|
|
45
|
+
// 不是字段属性,因此不写进注册表 —— 一个字段属于哪种计费形态,看它在 src/client-bundle.js 里由哪个
|
|
46
|
+
// push*Groups 函数渲染即可(pushBalanceGroups / pushSubscriptionGroups / pushBillingGroups),
|
|
47
|
+
// 不存在第二份需要手工同步的清单。下面的注释按形态分组,仅为阅读方便。
|
|
48
|
+
// ============================================================================================
|
|
29
49
|
export const FIELD_REGISTRY = [
|
|
30
|
-
//
|
|
31
|
-
{ id: 'anchorGroup', label: "field.anchorGroup.label", group: 'plugin',
|
|
32
|
-
{ id: 'subServiceGroup', label: "field.subServiceGroup.label", group: 'plugin',
|
|
33
|
-
{ id: 'billingServiceGroup', label: "field.billingServiceGroup.label", group: 'plugin',
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
{ id: '
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
//
|
|
42
|
-
{ id: '
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
{ id: '
|
|
47
|
-
{ id: '
|
|
48
|
-
{ id: '
|
|
49
|
-
|
|
50
|
-
{ id: '
|
|
51
|
-
{ id: '
|
|
52
|
-
|
|
53
|
-
{ id: '
|
|
54
|
-
{ id: '
|
|
55
|
-
{ id: '
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
{ id: '
|
|
63
|
-
{ id: '
|
|
64
|
-
{ id: '
|
|
65
|
-
{ id: '
|
|
66
|
-
|
|
67
|
-
// ---------- 提醒字段(第三个列表「提醒信息」,2026-09-25 用户拍板从插件组独立) ----------
|
|
50
|
+
// ---------- 插件信息 · 身份锚点(服务商 · 模型;三种计费形态各一个,用户可隐藏) ----------
|
|
51
|
+
{ id: 'anchorGroup', label: "field.anchorGroup.label", group: 'plugin', anchor: true, colorKind: 'provider', note: "field.anchorGroup.note" },
|
|
52
|
+
{ id: 'subServiceGroup', label: "field.subServiceGroup.label", group: 'plugin', anchor: true, colorKind: 'provider', note: "field.subServiceGroup.note" },
|
|
53
|
+
{ id: 'billingServiceGroup', label: "field.billingServiceGroup.label", group: 'plugin', anchor: true, colorKind: 'provider', note: "field.billingServiceGroup.note" },
|
|
54
|
+
// ---------- 插件信息 · 通用(任何计费形态都可能出现) ----------
|
|
55
|
+
// 自定义文字:纯自定义,位于服务商/模型左侧;为空时不渲染(开关可保持开启,无内容就无占位)
|
|
56
|
+
{ id: 'customText', label: "field.customText.label", group: 'plugin', defaultOff: true, colorKind: 'inherit', note: "field.customText.note" },
|
|
57
|
+
// 主/世界时间:时区与格式在设置页「时间与日期」中独立配置
|
|
58
|
+
{ id: 'mainTime', label: "field.mainTime.label", group: 'plugin', defaultOff: true, colorKind: 'inherit', note: "field.mainTime.note" },
|
|
59
|
+
{ id: 'worldTime', label: "field.worldTime.label", group: 'plugin', defaultOff: true, colorKind: 'inherit', note: "field.worldTime.note" },
|
|
60
|
+
// 上下文占用圆环(DSH 原生 ContextMeter 的接管版):外观、几何与交互面板与原生一致,显隐/配色并入本插件字段体系;
|
|
61
|
+
// 固定在主行最右端,原生那一份由样式隐藏。归 plugin 组是结论而非笔误:它住在主行,而主行两种模式都可见。
|
|
62
|
+
{ id: 'contextUsage', label: "field.contextUsage.label", group: 'plugin', colorKind: 'meter', note: "field.contextUsage.note" },
|
|
63
|
+
// ---------- 插件信息 · 余额制(balance) ----------
|
|
64
|
+
// 本会话花费:余额制与"订阅 · 充值余额"形态共用(见 pushSessionCost)
|
|
65
|
+
{ id: 'sessionCost', label: "field.sessionCost.label", group: 'plugin', colorKind: 'inherit', note: "field.sessionCost.note" },
|
|
66
|
+
{ id: 'balance', label: "ui.balance.pushBalanceGroups", group: 'plugin', colorKind: 'inherit', note: "field.balance.note" },
|
|
67
|
+
{ id: 'period', label: "field.period.label", group: 'plugin', colorKind: 'period', note: "field.period.note" },
|
|
68
|
+
{ id: 'countdown', label: "field.countdown.label", group: 'plugin', colorKind: 'inherit', note: "field.countdown.note" },
|
|
69
|
+
// ---------- 插件信息 · 订阅制(subscription) ----------
|
|
70
|
+
{ id: 'expiry', label: "field.expiry.label", group: 'plugin', colorKind: 'inherit', note: "field.expiry.note" },
|
|
71
|
+
{ id: 'subWindow5h', label: "field.subWindow5h.label", group: 'plugin', colorKind: 'inherit', note: "field.subWindow5h.note" },
|
|
72
|
+
{ id: 'subWindowWeek', label: "field.subWindowWeek.label", group: 'plugin', colorKind: 'inherit', note: "field.subWindowWeek.note" },
|
|
73
|
+
{ id: 'subWindowMonth', label: "field.subWindowMonth.label", group: 'plugin', colorKind: 'inherit', note: "field.subWindowMonth.note" },
|
|
74
|
+
{ id: 'resetCountdown', label: "field.resetCountdown.label", group: 'plugin', colorKind: 'inherit', note: "field.resetCountdown.note" },
|
|
75
|
+
{ id: 'subBalance', label: "field.subBalance.label", group: 'plugin', colorKind: 'inherit', note: "field.subBalance.note" },
|
|
76
|
+
// ---------- 插件信息 · 账单制(billing) ----------
|
|
77
|
+
{ id: 'billingSpend', label: "field.billingSpend.label", group: 'plugin', colorKind: 'inherit', note: "field.billingSpend.note" },
|
|
78
|
+
{ id: 'budget', label: "field.budget.label", group: 'plugin', colorKind: 'inherit', note: "field.budget.note" },
|
|
79
|
+
{ id: 'freeQuota', label: "field.freeQuota.label", group: 'plugin', colorKind: 'inherit', note: "field.freeQuota.note" },
|
|
80
|
+
// ---------- 原生信息(DSH 原生统计行原有字段;整组只在完整模式可见) ----------
|
|
81
|
+
{ id: 'turnsSteps', label: "field.turnsSteps.label", group: 'native', colorKind: 'inherit', note: "field.turnsSteps.note" },
|
|
82
|
+
{ id: 'llmTime', label: "field.llmTime.label", group: 'native', colorKind: 'inherit', note: "field.llmTime.note" },
|
|
83
|
+
{ id: 'toolTime', label: "field.toolTime.label", group: 'native', colorKind: 'inherit', note: "field.toolTime.note" },
|
|
84
|
+
{ id: 'cacheHit', label: "ui.cacheHit", group: 'native', colorKind: 'inherit', note: "field.cacheHit.note" },
|
|
85
|
+
{ id: 'tokensIO', label: "field.tokensIO.label", group: 'native', colorKind: 'inherit', note: "field.tokensIO.note" },
|
|
86
|
+
// ---------- 提醒信息(第三个列表,2026-09-25 用户拍板从插件组独立) ----------
|
|
68
87
|
// 独立成组的理由:提醒是「一次性事件」而不是「常驻信息」,诉求与插件信息相反 ——
|
|
69
88
|
// 想看花费但不想被红字打扰的人,必须能只关提醒而不动信息。
|
|
70
|
-
//
|
|
71
|
-
// 开关与显示模式互不读写,关掉开关也不会去改模式 —— 这是 2026-09-25 用户明确要求的解耦。
|
|
89
|
+
// 三条铁律:① 两种模式都显示(主行右端);② 只在真有事时出现,没事零占位;③ 开关只管开与关,与模式互不读写。
|
|
72
90
|
// 更新提醒 / 更新失败提醒(自更新体系,见 docs/DECISIONS-AUTO-UPDATE.md)
|
|
73
|
-
{ id: 'updateNotice', label: "field.updateNotice.label", group: 'notice',
|
|
74
|
-
{ id: 'updateFailure', label: "field.updateFailure.label", group: 'notice',
|
|
91
|
+
{ id: 'updateNotice', label: "field.updateNotice.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.updateNotice.note" },
|
|
92
|
+
{ id: 'updateFailure', label: "field.updateFailure.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.updateFailure.note" },
|
|
75
93
|
// 数据类提醒
|
|
76
|
-
{ id: 'balanceError', label: "field.balanceError.label", group: 'notice',
|
|
77
|
-
{ id: 'usageError', label: "field.usageError.label", group: 'notice',
|
|
78
|
-
{ id: 'refreshFailure', label: "field.refreshFailure.label", group: 'notice',
|
|
79
|
-
{ id: 'persistWarning', label: "field.persistWarning.label", group: 'notice',
|
|
94
|
+
{ id: 'balanceError', label: "field.balanceError.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.balanceError.note" },
|
|
95
|
+
{ id: 'usageError', label: "field.usageError.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.usageError.note" },
|
|
96
|
+
{ id: 'refreshFailure', label: "field.refreshFailure.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.refreshFailure.note" },
|
|
97
|
+
{ id: 'persistWarning', label: "field.persistWarning.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.persistWarning.note" },
|
|
80
98
|
// 配置类提醒
|
|
81
|
-
{ id: 'noKeyHint', label: "field.noKeyHint.label", group: 'notice',
|
|
82
|
-
{ id: 'unmapped', label: "field.unmapped.label", group: 'notice',
|
|
99
|
+
{ id: 'noKeyHint', label: "field.noKeyHint.label", group: 'notice', suggestKeep: true, colorKind: 'alert', note: "field.noKeyHint.note" },
|
|
100
|
+
{ id: 'unmapped', label: "field.unmapped.label", group: 'notice', colorKind: 'muted', note: "field.unmapped.note" },
|
|
83
101
|
]
|
|
84
102
|
|
|
85
|
-
//
|
|
103
|
+
// 字段分组在设置页的展示顺序与标题(经构建注入客户端)。
|
|
104
|
+
// 顺序与信息栏的实际版式一致:原生行在上、主行在下、提醒贴主行右端。
|
|
86
105
|
export const FIELD_GROUP_ORDER = ['native', 'plugin', 'notice']
|
|
87
106
|
export const FIELD_GROUP_LABELS = {
|
|
88
107
|
native: "group.native",
|
package/lib/index.js
CHANGED
|
@@ -1473,11 +1473,12 @@ const QUOTA_DISPLAY_MODES = ['used', 'remaining']
|
|
|
1473
1473
|
function normalizeQuotaDisplayMode(value) {
|
|
1474
1474
|
return value === 'used' || value === 'remaining' ? value : null
|
|
1475
1475
|
}
|
|
1476
|
+
// 默认开关取自注册表的 defaultOff(单一真相源:新增字段只改 constants.js,不必在这里再抄一份名单 ——
|
|
1477
|
+
// 抄一份名单就意味着一处漏改会让新字段静默变成"默认打开",谁也发现不了)。
|
|
1476
1478
|
function defaultFieldSettings() {
|
|
1477
1479
|
const settings = { version: SETTINGS_FORMAT_VERSION, infoDensity: 'full', fields: {}, colors: {}, timeFormat: { ...DEFAULT_TIME_FORMAT }, timeZones: { ...DEFAULT_TIME_ZONES }, customText: '', quotaDisplayMode: 'remaining' }
|
|
1478
1480
|
for (const field of FIELD_REGISTRY) {
|
|
1479
|
-
|
|
1480
|
-
settings.fields[field.id] = isNewField ? false : true
|
|
1481
|
+
settings.fields[field.id] = field.defaultOff !== true
|
|
1481
1482
|
settings.colors[field.id] = null // null=未自定义 → 客户端沿用原语义色(零回归)
|
|
1482
1483
|
}
|
|
1483
1484
|
return settings
|
package/lib/locales.js
CHANGED
|
@@ -360,7 +360,7 @@ export const LOCALES = {
|
|
|
360
360
|
"field.tokensIO.label": "输入/输出 Token",
|
|
361
361
|
"field.tokensIO.note": "显示本次会话的输入和输出用量,只在完整模式出现。",
|
|
362
362
|
"field.contextUsage.label": "上下文用量",
|
|
363
|
-
"field.contextUsage.note": "
|
|
363
|
+
"field.contextUsage.note": "显示上下文占用情况。",
|
|
364
364
|
"ui.contextAria": "上下文已用 {percent}",
|
|
365
365
|
"ui.contextUsed": "上下文已用",
|
|
366
366
|
"ui.contextSystem": "系统提示词",
|
|
@@ -388,9 +388,9 @@ export const LOCALES = {
|
|
|
388
388
|
"group.native": "原生信息",
|
|
389
389
|
"group.plugin": "插件信息",
|
|
390
390
|
"group.notice": "提醒信息",
|
|
391
|
-
"group.native.desc": "DeepSeek
|
|
392
|
-
"group.plugin.desc": "
|
|
393
|
-
"group.notice.desc": "
|
|
391
|
+
"group.native.desc": "DeepSeek 原生底栏原有的字段,归在原生行里;只有完整模式保留那一行。每条一个开关。",
|
|
392
|
+
"group.plugin.desc": "本插件新增的字段(含接管过来的上下文圆环),归在主行里;简洁与完整都显示。每条一个开关。",
|
|
393
|
+
"group.notice.desc": "更新、失败等一次性提醒。当下真有事要提醒就出现,与模式无关;每条一个开关。",
|
|
394
394
|
"ui.listSeparator": "、",
|
|
395
395
|
"ui.sentenceEnd": "。",
|
|
396
396
|
"ui.fieldErrorPrefix": "「{label}」:",
|
|
@@ -776,7 +776,7 @@ export const LOCALES = {
|
|
|
776
776
|
"field.tokensIO.label": "Input / output tokens",
|
|
777
777
|
"field.tokensIO.note": "Shows this session’s input and output usage. Full mode only.",
|
|
778
778
|
"field.contextUsage.label": "Context usage",
|
|
779
|
-
"field.contextUsage.note": "Shows context usage.
|
|
779
|
+
"field.contextUsage.note": "Shows context usage.",
|
|
780
780
|
"ui.contextAria": "{percent} of context used",
|
|
781
781
|
"ui.contextUsed": "Context used",
|
|
782
782
|
"ui.contextSystem": "System prompt",
|
|
@@ -804,9 +804,9 @@ export const LOCALES = {
|
|
|
804
804
|
"group.native": "Native information",
|
|
805
805
|
"group.plugin": "Plugin information",
|
|
806
806
|
"group.notice": "Notices",
|
|
807
|
-
"group.native.desc": "Fields the DeepSeek bar already had.
|
|
808
|
-
"group.plugin.desc": "Fields this plugin adds, the adopted context ring included.
|
|
809
|
-
"group.notice.desc": "One-off notices such as updates and failures.
|
|
807
|
+
"group.native.desc": "Fields the DeepSeek bar already had. They live in the native row, which only Full mode keeps. One switch each.",
|
|
808
|
+
"group.plugin.desc": "Fields this plugin adds, the adopted context ring included. They live in the main row, shown in both modes. One switch each.",
|
|
809
|
+
"group.notice.desc": "One-off notices such as updates and failures. They appear whenever there is really something to say, whatever the mode. One switch each.",
|
|
810
810
|
"ui.listSeparator": ", ",
|
|
811
811
|
"ui.sentenceEnd": ".",
|
|
812
812
|
"ui.fieldErrorPrefix": "\"{label}\": ",
|
package/lib/self-update.js
CHANGED
|
@@ -194,10 +194,10 @@ export function verifyPayload(files, options) {
|
|
|
194
194
|
if (parseSemver(manifest.version) === null) throw new Error('payload version is not semver: ' + String(manifest.version))
|
|
195
195
|
if (typeof integrity === 'string' && integrity.length > 0) {
|
|
196
196
|
const [algorithm, expected] = integrity.split('-')
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
197
|
+
// 给了校验值就必须验得动:算法不是 sha512 一律拒绝,绝不「看不懂就跳过校验」。
|
|
198
|
+
if (algorithm !== 'sha512' || !expected) throw new Error('payload integrity uses an unsupported algorithm: ' + String(algorithm))
|
|
199
|
+
const digest = createHash('sha512').update(options.tarball).digest('base64')
|
|
200
|
+
if (digest !== expected) throw new Error('payload integrity mismatch')
|
|
201
201
|
}
|
|
202
202
|
for (const file of files) {
|
|
203
203
|
if (!isAllowedPayloadPath(file.path)) throw new Error('payload path not allowed: ' + file.path)
|
|
@@ -367,7 +367,13 @@ export function createSelfUpdater(options) {
|
|
|
367
367
|
if (!response.ok) return null
|
|
368
368
|
const body = await response.json()
|
|
369
369
|
if (!body || typeof body.version !== 'string') return null
|
|
370
|
+
// 纵深防御:版本号会被拼进下载地址、写进状态文件、并参与版本比对,只接受规范 x.y.z。
|
|
371
|
+
if (parseSemver(body.version) === null) return null
|
|
370
372
|
const integrity = body.dist && typeof body.dist.integrity === 'string' ? body.dist.integrity : null
|
|
373
|
+
// 拿不到校验值就不更新:宁可停在当前版本,也不去装一个无法验证的包 ——
|
|
374
|
+
// 本模块会替换自己的全部文件,校验链上不允许有"静默跳过"的分支。
|
|
375
|
+
// npm 对已发布版本始终提供 dist.integrity,缺失只可能是应答被动了手脚。
|
|
376
|
+
if (!integrity) return null
|
|
371
377
|
return { version: body.version, integrity }
|
|
372
378
|
} catch {
|
|
373
379
|
return null
|