@eddyskywalker/dsh-chatgpt-subscription 0.10.7 → 0.10.8
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/CHANGELOG.md +22 -0
- package/README.md +2 -1
- package/lib/client.js +36 -24
- package/lib/client.js.map +1 -1
- package/lib/index.js +730 -62
- package/lib/types/client/minimax-code/MinimaxCodeSection.d.ts.map +1 -1
- package/lib/types/client/minimax-code/locales.d.ts +8 -2
- package/lib/types/client/minimax-code/locales.d.ts.map +1 -1
- package/lib/types/host/common/account-pool.d.ts +20 -0
- package/lib/types/host/common/account-pool.d.ts.map +1 -1
- package/lib/types/host/minimax-code/account-pool.d.ts +59 -0
- package/lib/types/host/minimax-code/account-pool.d.ts.map +1 -1
- package/lib/types/host/minimax-code/checkin.d.ts.map +1 -1
- package/lib/types/host/minimax-code/client.d.ts +27 -1
- package/lib/types/host/minimax-code/client.d.ts.map +1 -1
- package/lib/types/host/minimax-code/oauth.d.ts +23 -7
- package/lib/types/host/minimax-code/oauth.d.ts.map +1 -1
- package/lib/types/host/minimax-code/routes.d.ts.map +1 -1
- package/lib/types/host/minimax-code/token-store.d.ts +75 -0
- package/lib/types/host/minimax-code/token-store.d.ts.map +1 -1
- package/lib/types/host/minimax-code/types.d.ts +37 -6
- package/lib/types/host/minimax-code/types.d.ts.map +1 -1
- package/lib/types/host/reasoning-collapse-guard/index.d.ts +130 -0
- package/lib/types/host/reasoning-collapse-guard/index.d.ts.map +1 -0
- package/lib/types/index.d.ts +8 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/minimax-code-contracts.d.ts +6 -1
- package/lib/types/shared/minimax-code-contracts.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- **修复 MiniMax Code 线路「每小时自己掉线、然后要求重新登录」**(用户报告)。根因不是服务端把登录踢掉,而是本插件在**同一枚单次使用的刷新令牌上并发轮换**,而输掉竞态的一方拿到的 `invalid_grant` 被记成了「该账号已失效」。
|
|
6
|
+
- **实测事实**:access token 只有 **1 小时**(`09:40` 签发 → `10:40:51` 到期),而续期阈值是「到期前 **60 秒**」。也就是说这一小时里唯一允许轮换的窗口,正好是并发调用最容易同时到达、且令牌已经会被服务端拒收的那一个瞬间。
|
|
7
|
+
- **竞态的两条来源**:① 号池 `MinimaxCodeAccountPool` **没有任何单飞**,`getEffectiveAccount` / `credentialFor` / `renewCredential` 各自独立刷新(对照 Claude 线路的 `inFlight` map 与它为此写的注释);② 用量/签到路径走的是 `ensureAccessToken`,它的单飞是**模块级单变量**,号池完全看不见——而设置卡片每 60 秒轮询一次 `/status` 就会后台触发一次用量读取。桌面端也在刷新同一个文件,所以输家还可能是插件自己。
|
|
8
|
+
- **失败被当成终局**:`oauth.ts` 把 `invalid_grant` / 400 / 401 / 403 一律判为「刷新令牌已死」,于是 ① `rememberRejected` 进程级墓碑 5 分钟内对所有调用者生效;② 号池把该账号写死 `authStatus: expired`(DPAPI 池文件,重启仍在);③ 卡片渲染「需要重新登录」——而磁盘上的令牌其实是好的。
|
|
9
|
+
- **修法(六处,全部带回归测试)**:
|
|
10
|
+
- **提前 5 分钟续期**(`PRE_EXPIRY_REFRESH_MS`、`credentialNeedsRefresh`):把轮换挪出「已经被拒收」的边界窗口。仍保留 `REFRESH_MARGIN_MS` 作为「能不能用」的判据,两个问题分开回答;
|
|
11
|
+
- **全进程一次轮换**(`rotateMinimaxCodeCredential` + `token-store.ts` 的按身份注册表):键是**身份**(`recordKey` / `loginEpoch`)而不是路径或令牌,所以号池与用量路径这两条不同 `store` 实例也共用同一次轮换;后到的调用者要么加入在途轮换、要么等待并采纳结果;等待期间只轮询文件,**不创建、不删除、不等待桌面端的 `auth.lock`**;
|
|
12
|
+
- **先看 storage 再相信终局判定**:轮换前、轮换成功写回后、以及收到 `invalid_grant` 时,都会重新读一次文件;只要磁盘上的凭证**已属于同一会话且已经前进**(换过刷新令牌,或同一令牌的到期时间显著变晚),就采纳它——**不记 tombstone、不报「重新登录」**;
|
|
13
|
+
- **号池行自我修复**(`healStaleAuthFailures`):遗留的 `authStatus: expired` 会在下一次 `listAccounts()` / `getEffectiveAccount()` 时对照当前凭证核对并清除,因此修复对**已经卡住的账号**立刻生效,不需要等用户重新登录。会话身份不匹配(读到的其实是被镜像的**另一个**账号)时绝不采纳,这条有专门的测试;
|
|
14
|
+
- **用量读取改走号池**(`routes.ts`):不再让 `ensureAccessToken` 成为第二条独立的轮换权威;并且当 401 到达时若发现凭证已经被换掉(`isCredentialStale`),就不再报 `token-expired`——宁可这一轮没有数字,也不误导用户去重新登录;
|
|
15
|
+
- **卡片补上「重新登录」按钮**:`MinimaxCodeSection` 此前只传了字典键 `relogin` 而没有传 `onRelogin`,而按钮的渲染条件是 `needsRelogin && props.onRelogin`——徽章出现过,按钮从未出现过;
|
|
16
|
+
- 另修正一处会误伤:刷新响应**未返回**新的 refresh token 时沿用旧值而不是抛错(RFC 6749 允许不返回)。
|
|
17
|
+
- 结构:`src/host/minimax-code/{types,token-store,oauth,account-pool,routes,client}.ts`、`src/host/common/account-pool.ts`(新增可选钩子 `liveCredentialsFor`)、`src/client/minimax-code/MinimaxCodeSection.tsx`。
|
|
18
|
+
- **测试**:新增 13 条(`test/minimax-code-token-contention.test.ts`),每条对应上面的一环,且 fixture **不依赖墙钟先后**——「发生过轮换」用磁盘上的凭证表达,而不是靠谁先跑。全套 **1759 passed / 7 skipped / 12 failed**,12 条全部属于**回调端口无法绑定**这一类,与本次改动无关:antigravity-callback-port 1 条报 EACCES 127.0.0.1:50999,claude-oauth 11 条报 No bindable loopback port in the probe range。本机实测 53692–53819 这 128 个端口**一个都绑不上**(直接跑 node 对整段返回 bindable=0),所以这不是端口被占用而是本机对该区间的限制;这两条线路的代码与测试本次一行未动。强制 typecheck(host + client)与 build 全净。
|
|
19
|
+
- **新增 reasoning-collapse guard:推理流重复坍缩时熔断并自动恢复**。一段长 reasoning 流可能退化成反复循环少数几个短语(`Let me call. Go. Calling. Go.`),既不调用工具也不得出结论,一路跑到输出上限被截断。本机归档里 `session-9764f957` / `seq1626` 就是这样烧掉 **128,000 output tokens** 后交回空答案的。守卫按 n-gram 唯一率给尾部窗口打分(`1 - 唯一 n-gram / 总 n-gram`),越过阈值就停止继续 yield 该流并让 turn 在新的 step 上继续。
|
|
20
|
+
- **触发证据**(全部来自本机归档,非推测):坍缩段 46,252 行只剩 29 种唯一内容(`Go.`×19819、`Let me call.`×11882);该 step 工具调用数为 **0**,没有任何外部观测能打断它,所以只能烧到上限。对全部 **2,336 个** 归档 reasoning 块实测,坍缩样本得分 **0.98**,最差健康块 **0.59**,典型健康长思考 **≤0.28**——默认阈值 `0.85` 落在间隙里,对真实坍缩流在字符 1,497 处即触发。
|
|
21
|
+
- **接缝选择是这一轮的关键结论**。守卫包的是 `llm/stream` 而不是 `agent/assistant-stream`:后者是 `@mode emit`(只能观测、**无法中止流**),且 **0.1.5 之前根本不存在**,用它会让守卫在本插件支持的每一个更老世代上静默失效。`llm/stream` 是 waterfall,签名 `(options, next) => AsyncIterable<StreamChunk>` 从 `0.1.2-alpha.5` 到 `0.2.0-rc.1` **逐字节相同**(8 个 tag 全部核过),而从 wrapper 提前 return 正是真正结束流的动作。恢复所需的 live Agent 由 `agent/created`(同样 8 个世代一致)取得,每 turn 的熔断预算挂在请求自带的 abort signal 上——它覆盖整个 turn,新 turn 自然重置。
|
|
22
|
+
- **只做旁路,不改上下文 / 不改输出长度 / 不动思考参数**:不改写流、不注入 `additionalContexts`、不碰 `maxTokens` / `reasoningEffort` / 任何请求字段。唯一模型可见输入是中止后新 turn 上的那一条恢复消息。恢复分三档:第一次静默续跑,第二次明确要求「别第三次重新推导」,第三次**不再续跑**让 turn 干净结束(`hooks-claude-code` 自己留的 TODO 也要求强制续跑必须自限)。
|
|
23
|
+
- 结构:`src/host/reasoning-collapse-guard/index.ts`(检测器 + 熔断 + 恢复),默认启用,`config.reasoningCollapseGuard: false` 可关;沿用本仓库既有风格——Context 接口结构化声明、不 import 世代绑定类型、无该接缝时安装返回 `undefined` 而不是让插件装载失败。
|
|
24
|
+
- **测试**:新增 29 条(`test/reasoning-collapse-guard.test.ts`)——坍缩 fixture 必触发、三个健康长思考 fixture 必不触发、短重复控制样本不触发(低于最小窗口)、三档升级、预算耗尽后不再续跑、跨 turn 预算重置、按内容块独立打分、模型白名单、冷却前后、无 agent 时仍截断、dispose 还原原始 stream、七条 fail-loud 配置校验。fixture 是**真实归档文本**。全套 **1746 passed / 7 skipped**,仅剩 6 条既有 Windows Antigravity 回调端口失败(与本次改动无关,该文件未被触碰);`tsc -b --force`、`tsc -p test/tsconfig.json`、build 全净。
|
|
25
|
+
- ⚠️ **已知残留**:中止会把部分 reasoning 经 `interruptedBlocks()` 落盘成 `interrupted: true` 的 assistant message,插件无法删除它。这正是把检测做得足够灵敏的理由——在 1.5KB 处触发,残留就只有 1.5KB 而不是 385KB。
|
|
26
|
+
|
|
5
27
|
- **MiniMax Code 线路新增每日自动签到(用户要求「类似 workbuddy」)**。桌面端「每日签到」积分(400/800/…/2000 的七日循环)现在可以本线路自动领取:设置卡片新增「每日签到」组(自动开关、今日已签 x/y、连签天数、本轮积分、上次运行、「立即签到」手动补签),语义与 workbuddy 调度器逐条对齐——启动即签、运行期每 10 分钟补检、幂等(已签只记录)、当日格未开放按小时复查、失败每日每账号至多 3 次、手动运行忽略开关与上限。
|
|
6
28
|
- **关键事实:官方客户端是开源的,签到用的就是本线路的 OAuth 凭据**。`MiniMax-AI/minimax-code`(MIT)里 `packages/tui/src/checkin/http-gateway.ts` 就是签到实现,`runtime/public-gateway.ts` 是请求构造:`GET /minimax-cloud/api/v1/signin/status` 读七日面板、今日格 `status=2`(可领)时 `POST .../signin/claim`,`claim_result: 1` 新签 / `2` 已签;源站按账号 region 走 `agent.minimaxi.com` / `agent.minimax.io`(**两区都签**,不像 workbuddy 只限国区);`user_id` 需要的 realUserID 由 `/v1/api/user/info` 解析并缓存进状态文件。响应校验(七日、day_no 1–7 不重复、可领/今日格至多各一)与连签算法逐行对齐官方 `shared/daily-signin.ts`。
|
|
7
29
|
- **签名头是网关强制项,这一点如实记录**。`yy` / `x-timestamp` / `x-signature` 就是本插件在配额功能里默认拒绝伪造的那组第一方标识头——官方源码自己的注释称它们是「标记请求来自第一方客户端的字面量」「不是凭据也不是安全边界」。配额读取没有它们也能诚实失败,**签到没有它们就是 400,没有绕行路径**,因此本功能必然发送它们(用户已在知晓这一点的前提下确认要做)。但两条诚实线仍守住:`User-Agent` 仍是插件自报家门(未伪造 `MiniMaxCode`),`desktop_version` 报插件自己的版本号而不是官方应用的版本号。
|
package/README.md
CHANGED
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
**MiniMax Code(编程订阅)线路**
|
|
89
89
|
|
|
90
90
|
- 注册 `minimax-code` Provider,接入 **MiniMax Code 编程订阅**。它与 MiniMax 开放平台(按量计费的 API Key)是两套互不通用的系统:订阅的模型接口是 Anthropic Messages 协议(`https://agent.minimax.cn/mavis/api/v1/llm/v1/messages`),且**只用 `authorization: Bearer <accessToken>` 认证**——实测 `x-api-key` 一律返回 401 `{"code":401,"message":"token is required"}`,因此本线路**没有** x-api-key 回退分支(回退只会在每次请求上白花一个往返);
|
|
91
|
-
- **复用桌面端登录态,而不是让你再登录一次**:凭据就是 MiniMax Code 自己写的 `~/.minimax/auth/<buildEnv>/<region>/mcode-public/auth.json
|
|
91
|
+
- **复用桌面端登录态,而不是让你再登录一次**:凭据就是 MiniMax Code 自己写的 `~/.minimax/auth/<buildEnv>/<region>/mcode-public/auth.json`。**只读优先**:仍在有效期内(且距离到期还有 5 分钟以上)的令牌原样使用;进入续期窗口才轮换,并走**原子替换**(临时文件 + `rename`),失败或中断都让原文件保持逐字节不变,**不创建、不删除、不等待** `auth.lock`(那是桌面端自己的刷新锁,第二方碰它就可能打断官方客户端的刷新);
|
|
92
92
|
- **两种登录来源互不覆盖**:桌面端的 `auth.json` 归桌面端所有,本插件只读;若本机没有它,才在设置页用 **RFC 8628 设备码流程**(PKCE S256)登录,凭据存到本插件自己的 `$DSH_HOME/storages/minimax-code-credentials.json`。**登出只作用于本插件自己那份凭据**:桌面端的登录态会被续期写回(只读优先),但**绝不撤销、绝不删除**,登出请求对它会被拒绝并说明原因(撤销它等于把你从正在跑的 MiniMax Code 里踢下线),这也是 WorkBuddy 对桌面账号的既有做法;
|
|
93
93
|
- **区域是凭据属性**:`cn` 用 `account.minimax.cn` / `agent.minimax.cn`,`global` 用对应 `.io` 域名。两个区域的目录都会被探测,因此国际区账号不会因为没有国区文件而「未登录」;读回凭据时**以记录里存的区域为准**,而不是拿默认区域覆盖它;
|
|
94
94
|
- **模型目录是硬编码的**(`src/host/minimax-code/model-catalog.ts`):该端点的 `GET /v1/models` **未对订阅流量开放**(503 `{"errorCode":50115,"errorReason":"direct_route_not_configured"}`),所以任何「实时目录」都只会是一个必然失败的请求。四款模型(M2.7 / M2.7 HighSpeed / M3 / M3.1 Flash Preview)的上下文、输出上限与思考形态都取自本机 `~/.minimax/config.yaml` 的模型表,**不从不存在的接口推断**;
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
- **视频不在能力声明里**:模型表虽然给 M3 / M3.1 标了视频输入,但 DSH 的附件服务只存图片、本线路也没有安装视频字节读取器,映射器只能把它替换成一条说明文本。**声明一个做不到的能力比不声明更糟**(DSH 的能力闸门、模型选择器与子代理委派都会当它成立),所以这里只声明 `text` 与 `image`;要加 `video` 必须先有真正的读取器(对照 Kimi Code 线路的 `video-store.ts`);
|
|
97
97
|
- **瞬时失败按错误类别重试**(`src/host/minimax-code/adapter.ts`):上游模型供应商临时不可用(5xx)归为 `SERVER`、429 归为 `RATE_LIMIT`、连接未产出响应归为 `TRANSPORT`,走 DSH retry policy 的有界退避(最多 3 次,1.5s 起步、15s 上限、0.2 抖动);**但 429 的正文若说的是余额/额度耗尽,则判为终局**——重试只会推迟用户真正需要看到的提示;
|
|
98
98
|
- **401 会强制续期一次再重试**:本地时钟看着还有效、服务端却拒收的令牌(在桌面端被撤销、时钟偏移、桌面端已轮换)与「真的需要重新登录」在状态码上无法区分,所以第一次 401 会**强制刷新一次并原样重试同一个请求体**;重试再被拒才是终局;
|
|
99
|
+
- **刷新令牌是单次使用的,因此续期提前 5 分钟、并全进程共用一次轮换**(这是「每小时自己掉线、然后要求重新登录」的根因修复):实测 access token 只有 **1 小时**,而原先的续期阈值是「到期前 60 秒」——等于每次都在令牌已经会被拒收的那一个瞬间才去轮换,并发请求(状态卡轮询、签到、用量读取、模型请求)会各自拿同一枚刷新令牌去换,除第一个之外的调用全部拿到 `invalid_grant`,而这条终局判定会被记成「该账号需要重新登录」并写进号池(重启也在)。现在:① 续期窗口是 `PRE_EXPIRY_REFRESH_MS`(5 分钟),轮换发生在服务端还没有拒收之前;② 同一份凭证的轮换**注册在一张按身份(recordKey / loginEpoch)索引的进程内表上**,后到的调用者要么加入在途轮换、要么等待并采纳结果,绝不二次花费同一枚令牌;③ 轮换会**先看 storage 再相信终局判定**——如果磁盘上的凭证已经前进了(另一个持有者刚刚成功轮换,也可能是桌面端自己刷新过),就直接采纳它,**不记 tombstone、不报「重新登录」**;④ 号池行上遗留的过期标记会在下一次读取或请求时被**自动核对并清除**(凭证已前进即视为误判);⑤ 卡片此前根本没有「重新登录」按钮(`onRelogin` 未接线),现已补上;⑥ 响应未返回新的 refresh token 时沿用旧值,不再当作失败;
|
|
99
100
|
- **请求体超过 2 MB 本地即拒绝**(与 Kimi 线路同一个守卫与上限,因为两条线路上游都是同一族端点);额度面板**有配额条了**:Token Plan 的用量端点**不在 MiniMax 的 API 文档里**(文档只说"用量显示在控制台的用量条上",这大概就是最初判定"没有端点"的原因),它来自官方 CLI——`mmx quota show` 读 `GET {apiHost}/v1/token_plan/remains`。返回的每个 `model_remains` 行带**两个窗口**(5 小时滚动 + 每周),因此卡片两根条分别显示,还能看到每根条的重置时刻与"已用/总量"。三个必须照抄官方实现的细节:① **`*_usage_count` 的语义是模糊的**(老响应是"剩余"、新响应是"已用"),官方用显式百分比消歧——照抄否则进度条会**反过来**;② **周窗口带显示倍率**(返回的是百分比 × `weekly_boost_permille`,可超过 100%);③ `status: 3` 通常表示"不限量",但**两个总量都为 0 时**它表示"当前套餐不含该模型",渲染成不限量会凭空许诺额度。**有两套用量端点,第一轮打错了那一套**。① **平台端点** `/v1/token_plan/remains`(`api.minimax.cn` / `api.minimaxi.com` / `api.minimax.io`,实测都返回 JSON)只接受**平台 API 密钥**:`mcode-public` 登录态在四种认证写法(`Bearer` / 原始 / `x-api-key` / 两者都带)下全部被拒,且是 **HTTP 200 + `base_resp.status_code: 1004`**。官方 `mmx` CLI 能用,是因为它的 OAuth 是**平台**登录,与本线路的 mcode 登录是两套身份。② **mcode 自己的端点在官方客户端源码里**(`packages/tui/src/account/matrix-account-client.ts`):`GET https://agent.minimaxi.com/v1/api/openplatform/coding_plan/remains`(国际 `agent.minimax.io`),路径与平台端点**完全不同**——本插件现在用的就是这条(本线路自己的 `agent.minimax.cn` 优先、官方主机兜底)。⚠️ **但它带 `yy` / `x-timestamp` / `x-signature` / `User-Agent: MiniMaxCode` 四个"官方客户端标识头"**:官方注释自己写明这些是"把请求标记为来自 MiniMax 第一方客户端"的字面量。本插件 `types.ts` 已明确决定**不伪造官方客户端身份**(伪造既失信,也可能是封号理由),所以**默认不发**,宁可拿到一个拒绝让卡片如实说明;确实要数字的用户可以设 `DSH_MINIMAX_CODE_QUOTA_ATTRIBUTION=1` 显式选择该取舍。三处防护:① `base_resp` 非 0 视为凭据被拒,**只试一台就停**并记住 30 分钟;② 其它失败按 `unreachable` 区分、记住 10 分钟;③ `/status` **只读缓存、绝不在轮询里发网络请求**。读用量**永远不影响对话**:独立只读路径,失败只让卡片换一句话;
|
|
100
101
|
- **设置面与其余各线路逐项对齐**(该 PR 最初缺失这一整块,用户明确指出):① **「启用此供应商」总开关**——关闭后适配器**不暴露任何模型**(包括已勾选的),因为「关掉」如果还能用就等于没关;② **模型勾选**——只有勾选的模型进入对话页的模型选择列表,另有「全选 / 全不选」;③ **模型上下文窗口覆盖**——每个已勾选模型可填自定义容量(接受 `1M` / `512K` / `200000`),「恢复默认」以 `null` 语义在 host 侧**删除**该键而不是写入 0;④ **默认思考深度**——全局档位只在模型确实列了该档时生效,否则回落到该模型自己的默认档(广告一个模型会拒绝的档位只会让服务端拒掉请求),且「关闭思考」只对**可关闭**的模型生效;⑤ **号池管理**(见下条)。目录仍然硬编码,但「这一安装当前怎么用它」是用户设置:两者分开存储(目录随代码发布、设置随用户数据保存),因此一份用户数据不会看起来像一条已发布的目录项;
|
|
101
102
|
- **号池与多账号登录**:复用与其它线路**同一个**号池内核(`src/host/common/account-pool.ts`)与**同一张**共享账号卡片,具备顺序耗尽 / 轮询 / 粘性调度、429 冷却换号、设为主账号与备注。**身份键不是令牌**:桌面端凭据用它自己的 `recordKey`(同一个记录槽每次轮换都是同一账号,因此在池里原地更新),插件自持凭据用 `loginEpoch`(每次设备码登录就是一次独立会话)——用刷新令牌做键在每次轮换后都会把同一账号看成新账号;
|
package/lib/client.js
CHANGED
|
@@ -6228,6 +6228,8 @@ window.__ModuleLoader__.load({
|
|
|
6228
6228
|
quotaUnavailable: "暂时没有用量数据。",
|
|
6229
6229
|
quotaNeedsApiKey: "上游拒绝了这个登录态读取用量(官方客户端的用量端点要求带官方客户端标识头,本插件默认不伪造)。请在 MiniMax 控制台的用量条里查看 Token Plan 用量;如果你接受该取舍,可设 DSH_MINIMAX_CODE_QUOTA_ATTRIBUTION=1 后重试。",
|
|
6230
6230
|
quotaUnreachable: "暂时读不到用量(用量端点未应答),稍后会自动重试。",
|
|
6231
|
+
quotaTokenExpired: "读取用量时令牌刚好过期,正在自动续期——账号仍然是登录状态,无需重新登录。",
|
|
6232
|
+
quotaStale: "下面是上一次成功读取到的用量(本次刷新未成功),稍后会自动重试。",
|
|
6231
6233
|
quotaUsed: "已用 {percent}%",
|
|
6232
6234
|
quotaRemaining: "剩余 {percent}%",
|
|
6233
6235
|
quotaReset: "重置:{time}",
|
|
@@ -6332,6 +6334,8 @@ window.__ModuleLoader__.load({
|
|
|
6332
6334
|
quotaUnavailable: "No usage data yet.",
|
|
6333
6335
|
quotaNeedsApiKey: "The service refused this sign-in for the usage read (the official client's endpoint expects first-party attribution headers, which this plugin does not forge by default). Check the usage bar in the MiniMax console; if you accept that trade, set DSH_MINIMAX_CODE_QUOTA_ATTRIBUTION=1 and retry.",
|
|
6334
6336
|
quotaUnreachable: "Usage is temporarily unreadable (the usage endpoint did not answer); this retries on its own.",
|
|
6337
|
+
quotaTokenExpired: "The token expired just as usage was being read, and is being renewed automatically. The account is still signed in; no action needed.",
|
|
6338
|
+
quotaStale: "Below is the last usage read that succeeded (this refresh failed); it retries on its own.",
|
|
6335
6339
|
quotaUsed: "{percent}% used",
|
|
6336
6340
|
quotaRemaining: "{percent}% left",
|
|
6337
6341
|
quotaReset: "Resets: {time}",
|
|
@@ -6886,6 +6890,7 @@ window.__ModuleLoader__.load({
|
|
|
6886
6890
|
onSetPrimary: (accountId) => void poolAction("set-primary", accountId),
|
|
6887
6891
|
onDelete: (accountId) => void poolAction("delete", accountId),
|
|
6888
6892
|
onClearCooldown: (accountId) => void poolAction("clear-cooldown", accountId),
|
|
6893
|
+
onRelogin: (accountId) => void poolAction("relogin", accountId),
|
|
6889
6894
|
onSetStrategy: (strategy) => void poolSetStrategy(strategy)
|
|
6890
6895
|
}),
|
|
6891
6896
|
status?.checkin != null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
@@ -7330,32 +7335,39 @@ window.__ModuleLoader__.load({
|
|
|
7330
7335
|
})]
|
|
7331
7336
|
}), quota === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7332
7337
|
className: "dsha-notice dshm-quota-note",
|
|
7333
|
-
children: status?.quotaUnavailable === "credential-not-accepted" ? t("quotaNeedsApiKey") : status?.quotaUnavailable === "unreachable" ? t("quotaUnreachable") : t("quotaUnavailable")
|
|
7338
|
+
children: status?.quotaUnavailable === "credential-not-accepted" ? t("quotaNeedsApiKey") : status?.quotaUnavailable === "unreachable" ? t("quotaUnreachable") : status?.quotaUnavailable === "token-expired" ? t("quotaTokenExpired") : t("quotaUnavailable")
|
|
7334
7339
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7335
7340
|
className: "dsha-quota-card",
|
|
7336
|
-
children: [
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
7341
|
+
children: [
|
|
7342
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7343
|
+
className: "dsha-quota-title",
|
|
7344
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: quota.label }), quota.usedPercent !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("quotaUsed").replace("{percent}", String(Math.round(quota.usedPercent))) })]
|
|
7345
|
+
}),
|
|
7346
|
+
quotaWindows.map((window) => {
|
|
7347
|
+
const remaining = window.remainingPercent;
|
|
7348
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7349
|
+
className: "dsha-meter-wrap",
|
|
7350
|
+
children: [
|
|
7351
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7352
|
+
className: "dsha-meter-label",
|
|
7353
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: window.key === "weekly" ? t("quotaWindowWeekly") : t("quotaWindowInterval") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: window.unlimited === true ? t("quotaUnlimited") : remaining === null ? t("unknown") : t("quotaRemaining").replace("{percent}", String(Math.max(0, Math.round(remaining)))) })]
|
|
7354
|
+
}),
|
|
7355
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7356
|
+
className: `dsha-meter ${(remaining ?? 100) <= 10 ? "dsha-meter-cyan" : "dsha-meter-green"}`,
|
|
7357
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: { width: `${Math.min(100, Math.max(0, Math.round(remaining ?? 100)))}%` } })
|
|
7358
|
+
}),
|
|
7359
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7360
|
+
className: "dsha-meter-meta",
|
|
7361
|
+
children: [window.used !== void 0 && window.total !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("quotaCounts").replace("{used}", window.used.toLocaleString()).replace("{total}", window.total.toLocaleString()) }), window.resetsAtMs !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("quotaReset").replace("{time}", formatDate$1(window.resetsAtMs)) })]
|
|
7362
|
+
})
|
|
7363
|
+
]
|
|
7364
|
+
}, window.key);
|
|
7365
|
+
}),
|
|
7366
|
+
status?.quotaUnavailable === "stale" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
7367
|
+
className: "dsha-notice dshm-quota-note",
|
|
7368
|
+
children: t("quotaStale")
|
|
7369
|
+
})
|
|
7370
|
+
]
|
|
7359
7371
|
})]
|
|
7360
7372
|
}),
|
|
7361
7373
|
error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|