@eddyskywalker/dsh-chatgpt-subscription 0.28.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +11 -2
  3. package/lib/client.js +291 -164
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +694 -157
  6. package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
  7. package/lib/types/client/antigravity/locales.d.ts +11 -2
  8. package/lib/types/client/antigravity/locales.d.ts.map +1 -1
  9. package/lib/types/client/claude/locales.d.ts +11 -2
  10. package/lib/types/client/claude/locales.d.ts.map +1 -1
  11. package/lib/types/client/command-code/locales.d.ts +11 -2
  12. package/lib/types/client/command-code/locales.d.ts.map +1 -1
  13. package/lib/types/client/common/AccountPoolSection.d.ts +10 -2
  14. package/lib/types/client/common/AccountPoolSection.d.ts.map +1 -1
  15. package/lib/types/client/common/account-pool-labels.d.ts +17 -0
  16. package/lib/types/client/common/account-pool-labels.d.ts.map +1 -1
  17. package/lib/types/client/common/format.d.ts +14 -0
  18. package/lib/types/client/common/format.d.ts.map +1 -1
  19. package/lib/types/client/common/styles.d.ts.map +1 -1
  20. package/lib/types/client/glm-coding-plan/locales.d.ts +11 -2
  21. package/lib/types/client/glm-coding-plan/locales.d.ts.map +1 -1
  22. package/lib/types/client/glm-coding-plan/useGlmCodingPlanSection.d.ts.map +1 -1
  23. package/lib/types/client/kimi-code/locales.d.ts +11 -2
  24. package/lib/types/client/kimi-code/locales.d.ts.map +1 -1
  25. package/lib/types/client/locales.d.ts +7 -1
  26. package/lib/types/client/locales.d.ts.map +1 -1
  27. package/lib/types/client/minimax-code/MinimaxCodeSection.d.ts +8 -5
  28. package/lib/types/client/minimax-code/MinimaxCodeSection.d.ts.map +1 -1
  29. package/lib/types/client/minimax-code/locales.d.ts +17 -8
  30. package/lib/types/client/minimax-code/locales.d.ts.map +1 -1
  31. package/lib/types/client/minimax-code/useMinimaxCodeSection.d.ts.map +1 -1
  32. package/lib/types/client/ollama/locales.d.ts +18 -0
  33. package/lib/types/client/ollama/locales.d.ts.map +1 -1
  34. package/lib/types/client/progress-updates/index.d.ts.map +1 -1
  35. package/lib/types/client/step-code/locales.d.ts +11 -2
  36. package/lib/types/client/step-code/locales.d.ts.map +1 -1
  37. package/lib/types/client/step-code/useStepCodeSection.d.ts.map +1 -1
  38. package/lib/types/client/workbuddy/locales.d.ts +6 -0
  39. package/lib/types/client/workbuddy/locales.d.ts.map +1 -1
  40. package/lib/types/client/workbuddy/useWorkBuddySection.d.ts.map +1 -1
  41. package/lib/types/host/antigravity/account-pool.d.ts +17 -3
  42. package/lib/types/host/antigravity/account-pool.d.ts.map +1 -1
  43. package/lib/types/host/antigravity/adapter.d.ts +7 -2
  44. package/lib/types/host/antigravity/adapter.d.ts.map +1 -1
  45. package/lib/types/host/common/context-overflow.d.ts.map +1 -1
  46. package/lib/types/host/minimax-code/adapter.d.ts +14 -0
  47. package/lib/types/host/minimax-code/adapter.d.ts.map +1 -1
  48. package/lib/types/host/minimax-code/checkin-gateway.d.ts +36 -0
  49. package/lib/types/host/minimax-code/checkin-gateway.d.ts.map +1 -1
  50. package/lib/types/host/minimax-code/checkin.d.ts +60 -2
  51. package/lib/types/host/minimax-code/checkin.d.ts.map +1 -1
  52. package/lib/types/host/minimax-code/mapper.d.ts +51 -19
  53. package/lib/types/host/minimax-code/mapper.d.ts.map +1 -1
  54. package/lib/types/host/minimax-code/model-catalog.d.ts +40 -15
  55. package/lib/types/host/minimax-code/model-catalog.d.ts.map +1 -1
  56. package/lib/types/host/minimax-code/token-store.d.ts.map +1 -1
  57. package/lib/types/host/minimax-code/types.d.ts.map +1 -1
  58. package/lib/types/host/proxy-manager.d.ts.map +1 -1
  59. package/lib/types/host/workbuddy/account-pool.d.ts +24 -0
  60. package/lib/types/host/workbuddy/account-pool.d.ts.map +1 -1
  61. package/lib/types/index.d.ts +2 -2
  62. package/lib/types/index.d.ts.map +1 -1
  63. package/lib/types/shared/account-pool-contracts.d.ts +24 -0
  64. package/lib/types/shared/account-pool-contracts.d.ts.map +1 -1
  65. package/lib/types/shared/minimax-code-contracts.d.ts +17 -3
  66. package/lib/types/shared/minimax-code-contracts.d.ts.map +1 -1
  67. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -36,10 +36,9 @@ window.__ModuleLoader__.load({
36
36
  * 设置卡片只渲染这一份列表:档位是线路级的词汇表(`isMinimaxCodeReasoningEffort`
37
37
  * 就是按它校验的),而不是单个模型的能力表。某个模型实际接受哪些档位由
38
38
  * `MinimaxCodeModelOption.reasoningEfforts` 单独给出——把两者合成一份会让卡片
39
- * 在给一个只认 `default` 的模型显示 `max` 时无从判断是模型不支持还是文案没写。
39
+ * 在给一个只认 high 的模型显示 max 时无从判断是模型不支持还是文案没写。
40
40
  */
41
41
  const MINIMAX_CODE_REASONING_EFFORTS = [
42
- "default",
43
42
  "low",
44
43
  "medium",
45
44
  "high",
@@ -292,6 +291,9 @@ window.__ModuleLoader__.load({
292
291
  deleteAccount: "删除",
293
292
  cooling: "冷却中",
294
293
  cooldownLeft: "剩 {minutes} 分",
294
+ cooldownRemaining: "剩 {minutes} 分 {seconds} 秒",
295
+ cooldownRemainingSeconds: "剩 {seconds} 秒",
296
+ modelCooldown: "模型冷却",
295
297
  clearCooldown: "重置冷却",
296
298
  needsRelogin: "需重新登录",
297
299
  relogin: "重新登录",
@@ -325,6 +327,9 @@ window.__ModuleLoader__.load({
325
327
  deleteAccount: "Delete",
326
328
  cooling: "In Cooldown",
327
329
  cooldownLeft: "{minutes} min left",
330
+ cooldownRemaining: "{minutes} min {seconds}s left",
331
+ cooldownRemainingSeconds: "{seconds}s left",
332
+ modelCooldown: "Model cooldown",
328
333
  clearCooldown: "Clear Cooldown",
329
334
  needsRelogin: "Sign-in required",
330
335
  relogin: "Sign in again",
@@ -1048,6 +1053,84 @@ window.__ModuleLoader__.load({
1048
1053
  });
1049
1054
  }
1050
1055
  //#endregion
1056
+ //#region src/client/common/format.ts
1057
+ /**
1058
+ * The capacity, date and countdown formatting every provider settings card shares.
1059
+ *
1060
+ * Each card used to carry its own copy of the capacity pair. The five copies
1061
+ * were byte-identical except Antigravity's `formatCapacity`, which had lost the
1062
+ * 1K floor and so rendered a zero as "0K" while its siblings rendered "0". The
1063
+ * parse has to mean the same thing on every line — it takes free-text user input
1064
+ * that feeds the overflow judgement — so this is the one place it lives. The
1065
+ * date helpers were copied the same way; WorkBuddy's countdown is here for the
1066
+ * same reason.
1067
+ */
1068
+ /**
1069
+ * Parse "1M", "512K", "200000" into a positive integer token count.
1070
+ *
1071
+ * Anything that is not a plain capacity — including `0`, which no model has —
1072
+ * returns null rather than a coerced number, so the caller can leave the draft
1073
+ * uncommitted instead of storing a length that would silently break compaction.
1074
+ */
1075
+ function parsePositiveCapacity$1(value) {
1076
+ const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
1077
+ if (matched === null) return null;
1078
+ const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
1079
+ const parsed = Number(matched[1]) * multiplier;
1080
+ return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
1081
+ }
1082
+ /** Render a token capacity the way the capacity field seeds itself. */
1083
+ function formatCapacity$1(value) {
1084
+ if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
1085
+ if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
1086
+ return String(value);
1087
+ }
1088
+ /** A stamp in the reader's own locale, or an em dash when there is none. */
1089
+ function formatDate$1(ms) {
1090
+ if (ms === void 0 || ms === null || !Number.isFinite(ms) || ms <= 0) return "—";
1091
+ try {
1092
+ return new Intl.DateTimeFormat(void 0, {
1093
+ dateStyle: "medium",
1094
+ timeStyle: "short"
1095
+ }).format(ms);
1096
+ } catch {
1097
+ return "—";
1098
+ }
1099
+ }
1100
+ /**
1101
+ * The remaining part of a cooldown, split into whole minutes and seconds.
1102
+ *
1103
+ * A cooldown counted in whole minutes only is frozen for a whole minute at a
1104
+ * time: the badge says "剩 5 分" while the wait drops from 5:00 to 4:01, and
1105
+ * the user is left watching a number that does not move. The seconds are what
1106
+ * make the wait legible, so they are carried separately - and rounded UP,
1107
+ * because a cooldown with 30.2 seconds left is still 31 seconds of waiting, and
1108
+ * rounding down would announce "0 seconds left" while the wait is not over.
1109
+ */
1110
+ function cooldownRemainingParts(remainingMs) {
1111
+ const totalSeconds = Math.max(0, Math.ceil(remainingMs / 1e3));
1112
+ return {
1113
+ minutes: Math.floor(totalSeconds / 60),
1114
+ seconds: totalSeconds % 60
1115
+ };
1116
+ }
1117
+ /**
1118
+ * Countdown to a reset instant ("3d 4h"), empty when there is nothing to count
1119
+ * down to. Empty rather than "—" because callers append it to a date they have
1120
+ * already rendered, and a dash there would read as a second missing value.
1121
+ */
1122
+ function formatReset$1(resetsAt) {
1123
+ if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
1124
+ const diff = resetsAt - Date.now();
1125
+ if (diff <= 0) return "now";
1126
+ const mins = Math.floor(diff / 6e4);
1127
+ const hours = Math.floor(mins / 60);
1128
+ const days = Math.floor(hours / 24);
1129
+ if (days > 0) return `${days}d ${hours % 24}h`;
1130
+ if (hours > 0) return `${hours}h ${mins % 60}m`;
1131
+ return `${mins}m`;
1132
+ }
1133
+ //#endregion
1051
1134
  //#region src/client/common/AccountPoolSection.tsx
1052
1135
  /** Format one account timestamp the way every tab renders it. */
1053
1136
  function formatAccountDate(ms) {
@@ -1061,9 +1144,21 @@ window.__ModuleLoader__.load({
1061
1144
  return "—";
1062
1145
  }
1063
1146
  }
1064
- /** Whole minutes left in a cooldown, never below one. */
1065
- function cooldownMinutesLeft(cooldownUntil, now = Date.now()) {
1066
- return Math.max(1, Math.ceil((cooldownUntil - now) / 6e4));
1147
+ /**
1148
+ * The remaining cooldown, in the reader's own words.
1149
+ *
1150
+ * Whole minutes while a minute or more is left, minutes and seconds below
1151
+ * that, and the seconds alone under a minute: "剩 1 分" for the last 59
1152
+ * seconds is a lie, and "剩 0 分 42 秒" is unreadable.
1153
+ */
1154
+ function formatCooldownRemaining(remainingMs, labels) {
1155
+ const { minutes, seconds } = cooldownRemainingParts(remainingMs);
1156
+ if (minutes === 0) return formatPoolLabel(labels.cooldownRemainingSeconds, { seconds });
1157
+ if (seconds === 0) return formatPoolLabel(labels.cooldownLeft, { minutes });
1158
+ return formatPoolLabel(labels.cooldownRemaining, {
1159
+ minutes,
1160
+ seconds
1161
+ });
1067
1162
  }
1068
1163
  /** Whether one account currently carries a live 429 cooldown. */
1069
1164
  function isCoolingDown(account, now = Date.now()) {
@@ -1084,8 +1179,15 @@ window.__ModuleLoader__.load({
1084
1179
  function AccountPoolSection(props) {
1085
1180
  const t = props.labels;
1086
1181
  const accounts = props.accounts;
1087
- const now = Date.now();
1182
+ const [now, setNow] = (0, react.useState)(() => Date.now());
1088
1183
  const anyQuota = accounts.some((account) => account.quota !== void 0);
1184
+ const counting = accounts.some((account) => isCoolingDown(account, now) || (account.modelCooldowns ?? []).some((park) => park.cooldownUntil > now));
1185
+ (0, react.useEffect)(() => {
1186
+ if (!counting) return;
1187
+ setNow(Date.now());
1188
+ const timer = window.setInterval(() => setNow(Date.now()), 1e3);
1189
+ return () => window.clearInterval(timer);
1190
+ }, [counting]);
1089
1191
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1090
1192
  className: "dsha-group",
1091
1193
  children: [
@@ -1148,6 +1250,7 @@ window.__ModuleLoader__.load({
1148
1250
  children: accounts.map((account) => {
1149
1251
  const isActive = account.id === props.activeAccountId;
1150
1252
  const cooling = isCoolingDown(account, now);
1253
+ const modelParks = (account.modelCooldowns ?? []).filter((park) => park.cooldownUntil > now);
1151
1254
  const needsRelogin = account.authStatus !== void 0 && account.authStatus !== "ok";
1152
1255
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1153
1256
  className: `dsha-account-card ${isActive ? "active" : ""}`,
@@ -1175,7 +1278,7 @@ window.__ModuleLoader__.load({
1175
1278
  children: [
1176
1279
  t.cooling,
1177
1280
  "(",
1178
- formatPoolLabel(t.cooldownLeft, { minutes: cooldownMinutesLeft(account.cooldownUntil, now) }),
1281
+ formatCooldownRemaining(account.cooldownUntil - now, t),
1179
1282
  ")"
1180
1283
  ]
1181
1284
  }),
@@ -1237,6 +1340,27 @@ window.__ModuleLoader__.load({
1237
1340
  ] })
1238
1341
  ]
1239
1342
  }),
1343
+ modelParks.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1344
+ className: "dsha-account-model-cooldowns",
1345
+ children: modelParks.map((park) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1346
+ className: "dsha-account-model-cooldown-row",
1347
+ children: [
1348
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1349
+ className: "dsha-account-model-cooldown-tag",
1350
+ children: t.modelCooldown
1351
+ }),
1352
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1353
+ className: "dsha-account-model-cooldown-name",
1354
+ title: park.model,
1355
+ children: park.model
1356
+ }),
1357
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1358
+ className: "dsha-account-model-cooldown-time",
1359
+ children: formatCooldownRemaining(park.cooldownUntil - now, t)
1360
+ })
1361
+ ]
1362
+ }, park.model))
1363
+ }),
1240
1364
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountQuota, {
1241
1365
  quota: account.quota,
1242
1366
  labels: t,
@@ -1560,7 +1684,7 @@ window.__ModuleLoader__.load({
1560
1684
  await updatePreferences({ contextWindowOverrides: { [model]: null } });
1561
1685
  setContextDrafts((drafts) => ({
1562
1686
  ...drafts,
1563
- [model]: formatCapacity$1(resolveCodexCatalogEntry(model).contextWindow)
1687
+ [model]: formatCapacity(resolveCodexCatalogEntry(model).contextWindow)
1564
1688
  }));
1565
1689
  };
1566
1690
  /** Clear every stored override, including models the picker no longer shows. */
@@ -1591,6 +1715,9 @@ window.__ModuleLoader__.load({
1591
1715
  deleteAccount: t("deleteAccount"),
1592
1716
  cooling: t("cooling"),
1593
1717
  cooldownLeft: t("cooldownLeft"),
1718
+ cooldownRemaining: t("cooldownRemaining"),
1719
+ cooldownRemainingSeconds: t("cooldownRemainingSeconds"),
1720
+ modelCooldown: t("modelCooldown"),
1594
1721
  clearCooldown: t("clearCooldown"),
1595
1722
  needsRelogin: t("needsRelogin"),
1596
1723
  relogin: t("relogin"),
@@ -1801,7 +1928,7 @@ window.__ModuleLoader__.load({
1801
1928
  children: [
1802
1929
  connection !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoRow, {
1803
1930
  label: t("latency"),
1804
- value: `${connection.latencyMs} ms · ${formatDate$1(connection.checkedAt)}`
1931
+ value: `${connection.latencyMs} ms · ${formatDate(connection.checkedAt)}`
1805
1932
  }) : null,
1806
1933
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1807
1934
  className: "dsha-muted dsha-models-hint",
@@ -1811,7 +1938,7 @@ window.__ModuleLoader__.load({
1811
1938
  items: CODEX_MODEL_CATALOG.map((model) => ({
1812
1939
  id: model.id,
1813
1940
  name: model.name,
1814
- hint: `${formatCapacity$1(model.contextWindow)} ${t("tokens")}`,
1941
+ hint: `${formatCapacity(model.contextWindow)} ${t("tokens")}`,
1815
1942
  enabled: visibleModelIds.some((id) => id === model.id)
1816
1943
  })),
1817
1944
  busy: busy !== null,
@@ -2069,7 +2196,7 @@ window.__ModuleLoader__.load({
2069
2196
  id: inputId,
2070
2197
  type: "text",
2071
2198
  inputMode: "numeric",
2072
- value: draft ?? formatCapacity$1(fallback),
2199
+ value: draft ?? formatCapacity(fallback),
2073
2200
  disabled: busy !== null,
2074
2201
  "aria-label": entry.name + " " + t("contextWindow"),
2075
2202
  onChange: (event) => {
@@ -2205,7 +2332,7 @@ window.__ModuleLoader__.load({
2205
2332
  children: [
2206
2333
  t("updated"),
2207
2334
  ": ",
2208
- formatDate$1(quota.fetchedAt)
2335
+ formatDate(quota.fetchedAt)
2209
2336
  ]
2210
2337
  }) : null
2211
2338
  ]
@@ -2344,7 +2471,7 @@ window.__ModuleLoader__.load({
2344
2471
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("small", { children: [
2345
2472
  t("resetCreditExpires"),
2346
2473
  ": ",
2347
- resetCredits.expiresAt == null ? t("unknown") : formatReset$1(resetCredits.expiresAt)
2474
+ resetCredits.expiresAt == null ? t("unknown") : formatReset(resetCredits.expiresAt)
2348
2475
  ] })
2349
2476
  ]
2350
2477
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
@@ -2363,7 +2490,7 @@ window.__ModuleLoader__.load({
2363
2490
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {})]
2364
2491
  });
2365
2492
  }
2366
- function parsePositiveCapacity$1(value) {
2493
+ function parsePositiveCapacity(value) {
2367
2494
  const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
2368
2495
  if (matched === null) return null;
2369
2496
  const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
@@ -2371,10 +2498,10 @@ window.__ModuleLoader__.load({
2371
2498
  return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
2372
2499
  }
2373
2500
  function parseCapacity(value, maxContextWindow = GPT_56_MAX_CONTEXT_WINDOW) {
2374
- const parsed = parsePositiveCapacity$1(value);
2501
+ const parsed = parsePositiveCapacity(value);
2375
2502
  return parsed !== null && parsed <= maxContextWindow ? parsed : null;
2376
2503
  }
2377
- function formatCapacity$1(value) {
2504
+ function formatCapacity(value) {
2378
2505
  if (value % 1e3 === 0) return `${value / 1e3}K`;
2379
2506
  return String(value);
2380
2507
  }
@@ -2391,11 +2518,11 @@ window.__ModuleLoader__.load({
2391
2518
  limit.remainingPercent !== null && limit.remainingPercent !== void 0 ? `${formatPercent(limit.remainingPercent)} ${t("remaining")}` : null,
2392
2519
  limit.limit !== null && limit.limit !== void 0 ? `${t("limit")}: ${limit.limit}` : null,
2393
2520
  limit.used !== null && limit.used !== void 0 ? `${t("used")}: ${limit.used}` : null,
2394
- limit.resetsAt !== null && limit.resetsAt !== void 0 ? `${t("resets")}: ${formatReset$1(limit.resetsAt)}` : null
2521
+ limit.resetsAt !== null && limit.resetsAt !== void 0 ? `${t("resets")}: ${formatReset(limit.resetsAt)}` : null
2395
2522
  ].filter((part) => part !== null);
2396
2523
  return parts.length > 0 ? parts.join(" · ") : t("unknown");
2397
2524
  }
2398
- function formatDate$1(seconds) {
2525
+ function formatDate(seconds) {
2399
2526
  if (seconds === void 0 || seconds === null || typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) return "—";
2400
2527
  const ms = seconds > 1e10 ? seconds : seconds * 1e3;
2401
2528
  try {
@@ -2407,10 +2534,10 @@ window.__ModuleLoader__.load({
2407
2534
  return "—";
2408
2535
  }
2409
2536
  }
2410
- function formatReset$1(seconds) {
2537
+ function formatReset(seconds) {
2411
2538
  if (seconds === void 0 || seconds === null || typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) return "—";
2412
2539
  const ms = seconds > 1e10 ? seconds : seconds * 1e3;
2413
- const absolute = formatDate$1(seconds);
2540
+ const absolute = formatDate(seconds);
2414
2541
  const diff = ms - Date.now();
2415
2542
  const abs = Math.abs(diff);
2416
2543
  const [amount, unit] = abs >= 864e5 ? [Math.round(diff / 864e5), "day"] : abs >= 36e5 ? [Math.round(diff / 36e5), "hour"] : [Math.round(diff / 6e4), "minute"];
@@ -2424,67 +2551,6 @@ window.__ModuleLoader__.load({
2424
2551
  return error instanceof Error ? error.message : String(error);
2425
2552
  }
2426
2553
  //#endregion
2427
- //#region src/client/common/format.ts
2428
- /**
2429
- * The capacity, date and countdown formatting every provider settings card shares.
2430
- *
2431
- * Each card used to carry its own copy of the capacity pair. The five copies
2432
- * were byte-identical except Antigravity's `formatCapacity`, which had lost the
2433
- * 1K floor and so rendered a zero as "0K" while its siblings rendered "0". The
2434
- * parse has to mean the same thing on every line — it takes free-text user input
2435
- * that feeds the overflow judgement — so this is the one place it lives. The
2436
- * date helpers were copied the same way; WorkBuddy's countdown is here for the
2437
- * same reason.
2438
- */
2439
- /**
2440
- * Parse "1M", "512K", "200000" into a positive integer token count.
2441
- *
2442
- * Anything that is not a plain capacity — including `0`, which no model has —
2443
- * returns null rather than a coerced number, so the caller can leave the draft
2444
- * uncommitted instead of storing a length that would silently break compaction.
2445
- */
2446
- function parsePositiveCapacity(value) {
2447
- const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
2448
- if (matched === null) return null;
2449
- const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
2450
- const parsed = Number(matched[1]) * multiplier;
2451
- return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
2452
- }
2453
- /** Render a token capacity the way the capacity field seeds itself. */
2454
- function formatCapacity(value) {
2455
- if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
2456
- if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
2457
- return String(value);
2458
- }
2459
- /** A stamp in the reader's own locale, or an em dash when there is none. */
2460
- function formatDate(ms) {
2461
- if (ms === void 0 || ms === null || !Number.isFinite(ms) || ms <= 0) return "—";
2462
- try {
2463
- return new Intl.DateTimeFormat(void 0, {
2464
- dateStyle: "medium",
2465
- timeStyle: "short"
2466
- }).format(ms);
2467
- } catch {
2468
- return "—";
2469
- }
2470
- }
2471
- /**
2472
- * Countdown to a reset instant ("3d 4h"), empty when there is nothing to count
2473
- * down to. Empty rather than "—" because callers append it to a date they have
2474
- * already rendered, and a dash there would read as a second missing value.
2475
- */
2476
- function formatReset(resetsAt) {
2477
- if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
2478
- const diff = resetsAt - Date.now();
2479
- if (diff <= 0) return "now";
2480
- const mins = Math.floor(diff / 6e4);
2481
- const hours = Math.floor(mins / 60);
2482
- const days = Math.floor(hours / 24);
2483
- if (days > 0) return `${days}d ${hours % 24}h`;
2484
- if (hours > 0) return `${hours}h ${mins % 60}m`;
2485
- return `${mins}m`;
2486
- }
2487
- //#endregion
2488
2554
  //#region src/client/common/ContextWindowEditor.tsx
2489
2555
  /**
2490
2556
  * The shared "model context windows" block every provider settings card renders.
@@ -2516,7 +2582,7 @@ window.__ModuleLoader__.load({
2516
2582
  */
2517
2583
  function contextDraftsFor(status) {
2518
2584
  const drafts = {};
2519
- for (const model of status.models) drafts[model.id] = formatCapacity(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
2585
+ for (const model of status.models) drafts[model.id] = formatCapacity$1(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
2520
2586
  return drafts;
2521
2587
  }
2522
2588
  function ContextWindowEditor({ rows, labels, busy, overrideCount, metaClassName, onDraftChange, onCommit, onReset, onResetAll }) {
@@ -3033,7 +3099,7 @@ window.__ModuleLoader__.load({
3033
3099
  };
3034
3100
  const handleSaveContextWindow = async (modelId) => {
3035
3101
  const raw = contextDrafts[modelId] || "";
3036
- const parsed = parsePositiveCapacity(raw);
3102
+ const parsed = parsePositiveCapacity$1(raw);
3037
3103
  if (parsed === null) {
3038
3104
  setError(`无效的上下文容量值: ${raw}`);
3039
3105
  return;
@@ -3048,7 +3114,7 @@ window.__ModuleLoader__.load({
3048
3114
  setStatus(updated);
3049
3115
  setContextDrafts((prev) => ({
3050
3116
  ...prev,
3051
- [modelId]: formatCapacity(parsed)
3117
+ [modelId]: formatCapacity$1(parsed)
3052
3118
  }));
3053
3119
  notifyChange();
3054
3120
  } catch (err) {
@@ -3071,7 +3137,7 @@ window.__ModuleLoader__.load({
3071
3137
  const model = updated.models.find((candidate) => candidate.id === modelId);
3072
3138
  return model === void 0 ? prev : {
3073
3139
  ...prev,
3074
- [modelId]: formatCapacity(model.defaultContextWindow)
3140
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
3075
3141
  };
3076
3142
  });
3077
3143
  notifyChange();
@@ -3151,7 +3217,7 @@ window.__ModuleLoader__.load({
3151
3217
  items: (status?.models ?? []).map((model) => ({
3152
3218
  id: model.id,
3153
3219
  name: model.name,
3154
- hint: model.defaultContextWindow ? formatCapacity(model.defaultContextWindow) : void 0,
3220
+ hint: model.defaultContextWindow ? formatCapacity$1(model.defaultContextWindow) : void 0,
3155
3221
  enabled: model.enabled
3156
3222
  })),
3157
3223
  busy: busy !== null,
@@ -3791,7 +3857,7 @@ window.__ModuleLoader__.load({
3791
3857
  };
3792
3858
  const handleSaveContextWindow = async (modelId) => {
3793
3859
  const raw = contextDrafts[modelId] || "";
3794
- const parsed = parsePositiveCapacity(raw);
3860
+ const parsed = parsePositiveCapacity$1(raw);
3795
3861
  if (parsed === null) {
3796
3862
  setError(`Invalid context capacity: ${raw}`);
3797
3863
  return;
@@ -3806,7 +3872,7 @@ window.__ModuleLoader__.load({
3806
3872
  setStatus(updated);
3807
3873
  setContextDrafts((prev) => ({
3808
3874
  ...prev,
3809
- [modelId]: formatCapacity(parsed)
3875
+ [modelId]: formatCapacity$1(parsed)
3810
3876
  }));
3811
3877
  notifyChange();
3812
3878
  } catch (err) {
@@ -3829,7 +3895,7 @@ window.__ModuleLoader__.load({
3829
3895
  const model = updated.models.find((candidate) => candidate.id === modelId);
3830
3896
  return model === void 0 ? prev : {
3831
3897
  ...prev,
3832
- [modelId]: formatCapacity(model.defaultContextWindow)
3898
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
3833
3899
  };
3834
3900
  });
3835
3901
  notifyChange();
@@ -3966,7 +4032,7 @@ window.__ModuleLoader__.load({
3966
4032
  children: [
3967
4033
  status.catalogStale ? t.catalogStale : t.catalogFresh,
3968
4034
  " · ",
3969
- formatDate(status.catalogFetchedAt)
4035
+ formatDate$1(status.catalogFetchedAt)
3970
4036
  ]
3971
4037
  }),
3972
4038
  status?.zeroDataRetention === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -4759,7 +4825,7 @@ window.__ModuleLoader__.load({
4759
4825
  };
4760
4826
  const handleSaveContextWindow = async (modelId) => {
4761
4827
  const raw = contextDrafts[modelId] || "";
4762
- const parsed = parsePositiveCapacity(raw);
4828
+ const parsed = parsePositiveCapacity$1(raw);
4763
4829
  if (parsed === null) {
4764
4830
  setError(`Invalid context capacity: ${raw}`);
4765
4831
  return;
@@ -4774,7 +4840,7 @@ window.__ModuleLoader__.load({
4774
4840
  setStatus(updated);
4775
4841
  setContextDrafts((prev) => ({
4776
4842
  ...prev,
4777
- [modelId]: formatCapacity(parsed)
4843
+ [modelId]: formatCapacity$1(parsed)
4778
4844
  }));
4779
4845
  notifyChange();
4780
4846
  } catch (err) {
@@ -4797,7 +4863,7 @@ window.__ModuleLoader__.load({
4797
4863
  const model = updated.models.find((candidate) => candidate.id === modelId);
4798
4864
  return model === void 0 ? prev : {
4799
4865
  ...prev,
4800
- [modelId]: formatCapacity(model.defaultContextWindow)
4866
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
4801
4867
  };
4802
4868
  });
4803
4869
  notifyChange();
@@ -4900,7 +4966,7 @@ window.__ModuleLoader__.load({
4900
4966
  children: t.codeExpires
4901
4967
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4902
4968
  className: "dsha-value",
4903
- children: formatDate(flow?.expiresAt)
4969
+ children: formatDate$1(flow?.expiresAt)
4904
4970
  })]
4905
4971
  }),
4906
4972
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -5162,7 +5228,7 @@ window.__ModuleLoader__.load({
5162
5228
  id: model.id,
5163
5229
  name: model.name,
5164
5230
  draft: contextDrafts[model.id] ?? "",
5165
- meta: model.defaultContextWindow < model.contextWindow ? formatCapacity(model.contextWindow) : void 0,
5231
+ meta: model.defaultContextWindow < model.contextWindow ? formatCapacity$1(model.contextWindow) : void 0,
5166
5232
  inputLabel: `${model.name} context window`,
5167
5233
  hasOverride: status?.contextWindowOverrides[model.id] !== void 0,
5168
5234
  saving: savingModel === model.id
@@ -5298,6 +5364,7 @@ window.__ModuleLoader__.load({
5298
5364
  rescan: "重新扫描",
5299
5365
  rescanning: "扫描中...",
5300
5366
  accounts: "账号管理",
5367
+ modelCooldown: "模型限流",
5301
5368
  addCnAccount: "添加国区账号",
5302
5369
  addIntlAccount: "添加国际区账号",
5303
5370
  authorizing: "授权中…",
@@ -5402,6 +5469,7 @@ window.__ModuleLoader__.load({
5402
5469
  rescan: "Rescan",
5403
5470
  rescanning: "Scanning...",
5404
5471
  accounts: "Account Management",
5472
+ modelCooldown: "Model rate limit",
5405
5473
  addCnAccount: "Add China account",
5406
5474
  addIntlAccount: "Add international account",
5407
5475
  authorizing: "Authorizing…",
@@ -5518,7 +5586,8 @@ window.__ModuleLoader__.load({
5518
5586
  return {
5519
5587
  ...accountPoolZh,
5520
5588
  noAccounts: t.noAccounts,
5521
- email: t.nickname
5589
+ email: t.nickname,
5590
+ modelCooldown: t.modelCooldown
5522
5591
  };
5523
5592
  }
5524
5593
  /**
@@ -5620,7 +5689,9 @@ window.__ModuleLoader__.load({
5620
5689
  if (document.visibilityState === "visible") loadStatus(true);
5621
5690
  };
5622
5691
  document.addEventListener("visibilitychange", refreshWhenVisible);
5692
+ const timer = window.setInterval(refreshWhenVisible, 6e4);
5623
5693
  return () => {
5694
+ window.clearInterval(timer);
5624
5695
  document.removeEventListener("visibilitychange", refreshWhenVisible);
5625
5696
  quotaFollowUp.current?.cancel();
5626
5697
  if (loginIntervalRef.current !== null) window.clearInterval(loginIntervalRef.current);
@@ -5919,7 +5990,7 @@ window.__ModuleLoader__.load({
5919
5990
  };
5920
5991
  const saveContextWindow = async (modelId) => {
5921
5992
  const raw = contextDrafts[modelId] || "";
5922
- const parsed = parsePositiveCapacity(raw);
5993
+ const parsed = parsePositiveCapacity$1(raw);
5923
5994
  if (parsed === null) {
5924
5995
  setError(`Invalid context capacity: ${raw}`);
5925
5996
  return;
@@ -5934,7 +6005,7 @@ window.__ModuleLoader__.load({
5934
6005
  setStatus(updated);
5935
6006
  setContextDrafts((prev) => ({
5936
6007
  ...prev,
5937
- [modelId]: formatCapacity(parsed)
6008
+ [modelId]: formatCapacity$1(parsed)
5938
6009
  }));
5939
6010
  notifyChange();
5940
6011
  } catch (err) {
@@ -5957,7 +6028,7 @@ window.__ModuleLoader__.load({
5957
6028
  const model = updated.models.find((candidate) => candidate.id === modelId);
5958
6029
  return model === void 0 ? prev : {
5959
6030
  ...prev,
5960
- [modelId]: formatCapacity(model.defaultContextWindow)
6031
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
5961
6032
  };
5962
6033
  });
5963
6034
  notifyChange();
@@ -6462,7 +6533,7 @@ window.__ModuleLoader__.load({
6462
6533
  id: model.id,
6463
6534
  name: model.name,
6464
6535
  hint: [
6465
- formatCapacity(model.contextWindow),
6536
+ formatCapacity$1(model.contextWindow),
6466
6537
  model.supportsImage ? t.imageSupport : t.textOnly,
6467
6538
  ...model.reasoningEfforts && model.reasoningEfforts.length > 0 ? [model.reasoningEfforts.join("/")] : [],
6468
6539
  ...multiplier === null ? [] : [multiplier]
@@ -6622,7 +6693,7 @@ window.__ModuleLoader__.load({
6622
6693
  children: t.quotaReset
6623
6694
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6624
6695
  className: "dsha-value",
6625
- children: [formatDate(quota.cycleEndsAt), formatReset(quota.cycleEndsAt) ? ` · ${formatReset(quota.cycleEndsAt)}` : ""]
6696
+ children: [formatDate$1(quota.cycleEndsAt), formatReset$1(quota.cycleEndsAt) ? ` · ${formatReset$1(quota.cycleEndsAt)}` : ""]
6626
6697
  })]
6627
6698
  }),
6628
6699
  quota.meters.filter((meter) => meter.remainingFraction === null).map((meter) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -6641,7 +6712,7 @@ window.__ModuleLoader__.load({
6641
6712
  ] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6642
6713
  t.quotaReset,
6643
6714
  ": ",
6644
- formatReset(meter.resetsAt)
6715
+ formatReset$1(meter.resetsAt)
6645
6716
  ] })]
6646
6717
  }),
6647
6718
  meter.description !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -6728,9 +6799,9 @@ window.__ModuleLoader__.load({
6728
6799
  regionCn: "中国大陆 (minimax.cn)",
6729
6800
  regionGlobal: "国际 (minimax.io)",
6730
6801
  expiresAt: "令牌到期",
6731
- expiresRemaining: "剩余 {hours} 小时",
6802
+ expiresRemaining: "剩余 {minutes} 分钟",
6732
6803
  expiresExpired: "已过期",
6733
- expiresHint: "访问令牌约 24 小时有效;Host 会在令牌过期或上游返回 401 时自动刷新。刷新被拒绝时请回到 MiniMax Code 重新登录。",
6804
+ expiresHint: "访问令牌约 1 小时有效;Host 会在令牌过期或上游返回 401 时自动刷新。刷新被拒绝时请回到 MiniMax Code 重新登录。",
6734
6805
  signIn: "登录 MiniMax Code",
6735
6806
  signingIn: "正在申请设备码...",
6736
6807
  signOut: "登出",
@@ -6838,9 +6909,9 @@ window.__ModuleLoader__.load({
6838
6909
  regionCn: "Mainland China (minimax.cn)",
6839
6910
  regionGlobal: "Global (minimax.io)",
6840
6911
  expiresAt: "Token expires",
6841
- expiresRemaining: "{hours} h left",
6912
+ expiresRemaining: "{minutes} min left",
6842
6913
  expiresExpired: "Expired",
6843
- expiresHint: "The access token lives about 24 hours; the Host refreshes it once it expires or the upstream answers 401. When a refresh is rejected, sign in again from MiniMax Code.",
6914
+ expiresHint: "The access token lives about 1 hour; the Host refreshes it once it expires or the upstream answers 401. When a refresh is rejected, sign in again from MiniMax Code.",
6844
6915
  signIn: "Sign in to MiniMax Code",
6845
6916
  signingIn: "Requesting a device code...",
6846
6917
  signOut: "Sign out",
@@ -6974,6 +7045,9 @@ window.__ModuleLoader__.load({
6974
7045
  deleteAccount: t("deleteAccount"),
6975
7046
  cooling: t("cooling"),
6976
7047
  cooldownLeft: t("cooldownLeft"),
7048
+ cooldownRemaining: t("cooldownRemaining"),
7049
+ cooldownRemainingSeconds: t("cooldownRemainingSeconds"),
7050
+ modelCooldown: t("modelCooldown"),
6977
7051
  clearCooldown: t("clearCooldown"),
6978
7052
  needsRelogin: t("needsRelogin"),
6979
7053
  relogin: t("relogin"),
@@ -7365,7 +7439,7 @@ window.__ModuleLoader__.load({
7365
7439
  };
7366
7440
  const saveContextWindow = async (modelId) => {
7367
7441
  const raw = contextDrafts[modelId] ?? "";
7368
- const parsed = parsePositiveCapacity(raw);
7442
+ const parsed = parsePositiveCapacity$1(raw);
7369
7443
  if (parsed === null) {
7370
7444
  setError(t("invalidCapacity").replace("{value}", raw));
7371
7445
  return;
@@ -7377,7 +7451,7 @@ window.__ModuleLoader__.load({
7377
7451
  setStatus(updated);
7378
7452
  setContextDrafts((prev) => ({
7379
7453
  ...prev,
7380
- [modelId]: formatCapacity(parsed)
7454
+ [modelId]: formatCapacity$1(parsed)
7381
7455
  }));
7382
7456
  onModelChange?.();
7383
7457
  } catch (cause) {
@@ -7395,7 +7469,7 @@ window.__ModuleLoader__.load({
7395
7469
  const model = updated.models.find((entry) => entry.id === modelId);
7396
7470
  if (model !== void 0) setContextDrafts((prev) => ({
7397
7471
  ...prev,
7398
- [modelId]: formatCapacity(model.defaultContextWindow)
7472
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
7399
7473
  }));
7400
7474
  onModelChange?.();
7401
7475
  } catch (cause) {
@@ -7525,17 +7599,20 @@ window.__ModuleLoader__.load({
7525
7599
  return t("thinkingToggle");
7526
7600
  }
7527
7601
  /**
7528
- * Hours still left on the access token, or null once it has run out.
7602
+ * Minutes still left on the access token, or null once it has run out.
7529
7603
  *
7530
- * MiniMax Code's token lives about 24 hours, so hours are the unit the card
7531
- * reports; a value worth a fraction of an hour keeps one decimal instead of
7532
- * rounding down to 0.
7604
+ * MiniMax Code's token lives about ONE HOUR — measured, not the day an earlier
7605
+ * note assumed — so minutes are the unit the card reports: hours would turn the
7606
+ * whole remaining life into a single digit and hide the point at which the Host
7607
+ * renews the credential. One decimal is kept, so a countdown that is running
7608
+ * out reads as 0.4 rather than as nothing; below one minute the token is
7609
+ * treated as already gone.
7533
7610
  */
7534
- function remainingHours(expiresAtMs) {
7611
+ function remainingMinutes(expiresAtMs) {
7535
7612
  if (expiresAtMs === void 0 || !Number.isFinite(expiresAtMs) || expiresAtMs <= 0) return null;
7536
- const hours = (expiresAtMs - Date.now()) / 36e5;
7537
- if (hours <= 0) return null;
7538
- return hours >= 10 ? hours.toFixed(0) : hours.toFixed(1);
7613
+ const minutes = (expiresAtMs - Date.now()) / 6e4;
7614
+ if (minutes < 1) return null;
7615
+ return minutes.toFixed(1);
7539
7616
  }
7540
7617
  function MinimaxCodeSection({ onModelChange }) {
7541
7618
  const { state, derived, actions } = useMinimaxCodeSection({ onModelChange });
@@ -7550,7 +7627,7 @@ window.__ModuleLoader__.load({
7550
7627
  children: t("loading")
7551
7628
  })
7552
7629
  });
7553
- const hours = remainingHours(account?.expiresAtMs);
7630
+ const minutes = remainingMinutes(account?.expiresAtMs);
7554
7631
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7555
7632
  className: "dsha-page",
7556
7633
  children: [
@@ -7610,7 +7687,7 @@ window.__ModuleLoader__.load({
7610
7687
  status.checkin.failedToday > 0 ? ` · ${t("checkinFailed").replace("{count}", String(status.checkin.failedToday))}` : "",
7611
7688
  status.checkin.streakDays !== void 0 ? ` · ${t("checkinStreak").replace("{days}", String(status.checkin.streakDays))}` : "",
7612
7689
  status.checkin.claimedPoints !== void 0 ? ` · ${t("checkinClaimed").replace("{points}", String(status.checkin.claimedPoints))}` : "",
7613
- ` · ${status.checkin.lastRunAt === null ? t("checkinNever") : t("checkinLastRun").replace("{time}", formatDate(status.checkin.lastRunAt))}`
7690
+ ` · ${status.checkin.lastRunAt === null ? t("checkinNever") : t("checkinLastRun").replace("{time}", formatDate$1(status.checkin.lastRunAt))}`
7614
7691
  ]
7615
7692
  })]
7616
7693
  }),
@@ -7673,7 +7750,7 @@ window.__ModuleLoader__.load({
7673
7750
  children: t("expiresAt")
7674
7751
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7675
7752
  className: "dsha-value",
7676
- children: [formatDate(account?.expiresAtMs), hours === null ? ` · ${t("expiresExpired")}` : ` · ${t("expiresRemaining").replace("{hours}", hours)}`]
7753
+ children: [formatDate$1(account?.expiresAtMs), minutes === null ? ` · ${t("expiresExpired")}` : ` · ${t("expiresRemaining").replace("{minutes}", minutes)}`]
7677
7754
  })]
7678
7755
  })
7679
7756
  ] }),
@@ -7871,7 +7948,7 @@ window.__ModuleLoader__.load({
7871
7948
  id: model.id,
7872
7949
  name: model.name,
7873
7950
  draft: contextDrafts[model.id] ?? "",
7874
- meta: model.defaultContextWindow < model.contextWindow ? formatCapacity(model.contextWindow) : void 0,
7951
+ meta: model.defaultContextWindow < model.contextWindow ? formatCapacity$1(model.contextWindow) : void 0,
7875
7952
  inputLabel: `${model.name} ${t("contextWindowSection")}`,
7876
7953
  hasOverride: status?.contextWindowOverrides[model.id] !== void 0,
7877
7954
  saving: savingModel === model.id
@@ -7948,7 +8025,7 @@ window.__ModuleLoader__.load({
7948
8025
  children: t("resetAvailable").replace("{count}", String(resetCardList.length))
7949
8026
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7950
8027
  className: "dsha-value",
7951
- children: formatDate(resetCards.fetchedAtMs)
8028
+ children: formatDate$1(resetCards.fetchedAtMs)
7952
8029
  })]
7953
8030
  }),
7954
8031
  resetCardList.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -7970,7 +8047,7 @@ window.__ModuleLoader__.load({
7970
8047
  })
7971
8048
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7972
8049
  className: "dsha-value",
7973
- children: t("resetExpires").replace("{time}", formatDate(card.expiresAtMs))
8050
+ children: t("resetExpires").replace("{time}", formatDate$1(card.expiresAtMs))
7974
8051
  })]
7975
8052
  }, card.cardId))
7976
8053
  }),
@@ -8011,7 +8088,7 @@ window.__ModuleLoader__.load({
8011
8088
  children: [
8012
8089
  entry.cardId,
8013
8090
  " · ",
8014
- formatDate(entry.createdAtMs)
8091
+ formatDate$1(entry.createdAtMs)
8015
8092
  ]
8016
8093
  })]
8017
8094
  }, `${entry.cardId}:${entry.createdAtMs}:${index}`))
@@ -8325,6 +8402,9 @@ window.__ModuleLoader__.load({
8325
8402
  deleteAccount: t("deleteAccount"),
8326
8403
  cooling: t("cooling"),
8327
8404
  cooldownLeft: t("cooldownLeft"),
8405
+ cooldownRemaining: t("cooldownRemaining"),
8406
+ cooldownRemainingSeconds: t("cooldownRemainingSeconds"),
8407
+ modelCooldown: t("modelCooldown"),
8328
8408
  clearCooldown: t("clearCooldown"),
8329
8409
  needsRelogin: t("needsRelogin"),
8330
8410
  relogin: t("relogin"),
@@ -8563,7 +8643,7 @@ window.__ModuleLoader__.load({
8563
8643
  };
8564
8644
  const saveContextWindow = async (modelId) => {
8565
8645
  const raw = contextDrafts[modelId] ?? "";
8566
- const parsed = parsePositiveCapacity(raw);
8646
+ const parsed = parsePositiveCapacity$1(raw);
8567
8647
  if (parsed === null) {
8568
8648
  setError(t("invalidCapacity").replace("{value}", raw));
8569
8649
  return;
@@ -8574,7 +8654,7 @@ window.__ModuleLoader__.load({
8574
8654
  setStatus(await post$2("/settings", { contextWindowOverrides: { [modelId]: parsed } }));
8575
8655
  setContextDrafts((previous) => ({
8576
8656
  ...previous,
8577
- [modelId]: formatCapacity(parsed)
8657
+ [modelId]: formatCapacity$1(parsed)
8578
8658
  }));
8579
8659
  onModelChange?.();
8580
8660
  } catch (cause) {
@@ -8592,7 +8672,7 @@ window.__ModuleLoader__.load({
8592
8672
  const model = updated.models.find((entry) => entry.id === modelId);
8593
8673
  if (model !== void 0) setContextDrafts((previous) => ({
8594
8674
  ...previous,
8595
- [modelId]: formatCapacity(model.defaultContextWindow)
8675
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
8596
8676
  }));
8597
8677
  onModelChange?.();
8598
8678
  } catch (cause) {
@@ -8859,7 +8939,7 @@ window.__ModuleLoader__.load({
8859
8939
  }),
8860
8940
  login.expiresAt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8861
8941
  className: "dsha-muted",
8862
- children: t.loginExpiresAt.replace("{time}", formatDate(login.expiresAt))
8942
+ children: t.loginExpiresAt.replace("{time}", formatDate$1(login.expiresAt))
8863
8943
  })
8864
8944
  ] }),
8865
8945
  login.status === "complete" && !authenticated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -8871,7 +8951,7 @@ window.__ModuleLoader__.load({
8871
8951
  children: [t.loginComplete, login.email !== void 0 && login.email !== "" ? ` ${login.email}` : ""]
8872
8952
  }), login.completedAt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8873
8953
  className: "dsha-muted",
8874
- children: t.loginCompletedAt.replace("{time}", formatDate(login.completedAt))
8954
+ children: t.loginCompletedAt.replace("{time}", formatDate$1(login.completedAt))
8875
8955
  })] }),
8876
8956
  login.status === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8877
8957
  className: "dsha-error",
@@ -9031,7 +9111,7 @@ window.__ModuleLoader__.load({
9031
9111
  id: model.id,
9032
9112
  name: model.name,
9033
9113
  draft: contextDrafts[model.id] ?? "",
9034
- meta: model.defaultContextWindow < model.contextWindow ? formatCapacity(model.contextWindow) : void 0,
9114
+ meta: model.defaultContextWindow < model.contextWindow ? formatCapacity$1(model.contextWindow) : void 0,
9035
9115
  inputLabel: `${model.name} ${t.contextWindowSection}`,
9036
9116
  hasOverride: status?.contextWindowOverrides[model.id] !== void 0,
9037
9117
  saving: savingModel === model.id
@@ -9120,7 +9200,7 @@ window.__ModuleLoader__.load({
9120
9200
  children: t.quotaRenews
9121
9201
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9122
9202
  className: "dsha-value",
9123
- children: formatDate(quota.renewsAt)
9203
+ children: formatDate$1(quota.renewsAt)
9124
9204
  })]
9125
9205
  }),
9126
9206
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -9130,7 +9210,7 @@ window.__ModuleLoader__.load({
9130
9210
  children: t.quotaReadAt
9131
9211
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9132
9212
  className: "dsha-value",
9133
- children: formatDate(quota.fetchedAt)
9213
+ children: formatDate$1(quota.fetchedAt)
9134
9214
  })]
9135
9215
  }),
9136
9216
  quota.sources.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -9764,7 +9844,7 @@ window.__ModuleLoader__.load({
9764
9844
  };
9765
9845
  const saveContextWindow = async (modelId) => {
9766
9846
  const raw = contextDrafts[modelId] || "";
9767
- const parsed = parsePositiveCapacity(raw);
9847
+ const parsed = parsePositiveCapacity$1(raw);
9768
9848
  if (parsed === null) {
9769
9849
  setError(t.contextWindowInvalid.replace("{value}", raw));
9770
9850
  return;
@@ -9779,7 +9859,7 @@ window.__ModuleLoader__.load({
9779
9859
  setStatus(updated);
9780
9860
  setContextDrafts((prev) => ({
9781
9861
  ...prev,
9782
- [modelId]: formatCapacity(parsed)
9862
+ [modelId]: formatCapacity$1(parsed)
9783
9863
  }));
9784
9864
  notifyChange();
9785
9865
  } catch (err) {
@@ -9808,7 +9888,7 @@ window.__ModuleLoader__.load({
9808
9888
  const model = updated.models.find((candidate) => candidate.id === modelId);
9809
9889
  return model === void 0 ? prev : {
9810
9890
  ...prev,
9811
- [modelId]: formatCapacity(model.defaultContextWindow)
9891
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
9812
9892
  };
9813
9893
  });
9814
9894
  notifyChange();
@@ -10264,7 +10344,7 @@ window.__ModuleLoader__.load({
10264
10344
  id: model.id,
10265
10345
  name: model.name,
10266
10346
  draft: contextDrafts[model.id] ?? "",
10267
- meta: model.defaultContextWindow < model.contextWindow ? formatCapacity(model.contextWindow) : void 0,
10347
+ meta: model.defaultContextWindow < model.contextWindow ? formatCapacity$1(model.contextWindow) : void 0,
10268
10348
  inputLabel: `${model.name} context window`,
10269
10349
  hasOverride: status?.contextWindowOverrides[model.id] !== void 0,
10270
10350
  saving: savingModel === model.id
@@ -10384,7 +10464,7 @@ window.__ModuleLoader__.load({
10384
10464
  }),
10385
10465
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
10386
10466
  className: "dsha-timestamp",
10387
- children: quota.fetchedAt === null ? t.observedAt.replace("{time}", formatDate(quota.observedAt)) : t.updatedAt.replace("{time}", formatDate(quota.fetchedAt))
10467
+ children: quota.fetchedAt === null ? t.observedAt.replace("{time}", formatDate$1(quota.observedAt)) : t.updatedAt.replace("{time}", formatDate$1(quota.fetchedAt))
10388
10468
  })
10389
10469
  ]
10390
10470
  })
@@ -11476,6 +11556,9 @@ window.__ModuleLoader__.load({
11476
11556
  deleteAccount: t("deleteAccount"),
11477
11557
  cooling: t("cooling"),
11478
11558
  cooldownLeft: t("cooldownLeft"),
11559
+ cooldownRemaining: t("cooldownRemaining"),
11560
+ cooldownRemainingSeconds: t("cooldownRemainingSeconds"),
11561
+ modelCooldown: t("modelCooldown"),
11479
11562
  clearCooldown: t("clearCooldown"),
11480
11563
  needsRelogin: t("needsRelogin"),
11481
11564
  relogin: t("relogin"),
@@ -11790,7 +11873,7 @@ window.__ModuleLoader__.load({
11790
11873
  };
11791
11874
  const saveContextWindow = async (modelId) => {
11792
11875
  const raw = contextDrafts[modelId] ?? "";
11793
- const parsed = parsePositiveCapacity(raw);
11876
+ const parsed = parsePositiveCapacity$1(raw);
11794
11877
  if (parsed === null) {
11795
11878
  setError(t("invalidCapacity").replace("{value}", raw));
11796
11879
  return;
@@ -11801,7 +11884,7 @@ window.__ModuleLoader__.load({
11801
11884
  setStatus(await post("/settings", { contextWindowOverrides: { [modelId]: parsed } }));
11802
11885
  setContextDrafts((previous) => ({
11803
11886
  ...previous,
11804
- [modelId]: formatCapacity(parsed)
11887
+ [modelId]: formatCapacity$1(parsed)
11805
11888
  }));
11806
11889
  onModelChange?.();
11807
11890
  } catch (cause) {
@@ -11819,7 +11902,7 @@ window.__ModuleLoader__.load({
11819
11902
  const model = updated.models.find((entry) => entry.id === modelId);
11820
11903
  if (model !== void 0) setContextDrafts((previous) => ({
11821
11904
  ...previous,
11822
- [modelId]: formatCapacity(model.defaultContextWindow)
11905
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
11823
11906
  }));
11824
11907
  onModelChange?.();
11825
11908
  } catch (cause) {
@@ -12132,7 +12215,7 @@ window.__ModuleLoader__.load({
12132
12215
  }),
12133
12216
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12134
12217
  className: "dshsc-quota-meta",
12135
- children: window.resetsAt !== null && window.resetsAt > 0 ? `${t.quotaResets} ${formatDate(window.resetsAt)}` : t.quotaNoReset
12218
+ children: window.resetsAt !== null && window.resetsAt > 0 ? `${t.quotaResets} ${formatDate$1(window.resetsAt)}` : t.quotaNoReset
12136
12219
  })
12137
12220
  ]
12138
12221
  }, `${window.key}:${index}`);
@@ -12283,7 +12366,7 @@ window.__ModuleLoader__.load({
12283
12366
  }),
12284
12367
  login.expiresAt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
12285
12368
  className: "dsha-muted",
12286
- children: t.loginExpiresAt.replace("{time}", formatDate(login.expiresAt))
12369
+ children: t.loginExpiresAt.replace("{time}", formatDate$1(login.expiresAt))
12287
12370
  })
12288
12371
  ] }),
12289
12372
  login.status === "complete" && !authenticated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -12295,7 +12378,7 @@ window.__ModuleLoader__.load({
12295
12378
  children: [t.loginComplete, login.uid !== void 0 && login.uid !== "" ? ` ${login.uid}` : ""]
12296
12379
  }), login.completedAt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
12297
12380
  className: "dsha-muted",
12298
- children: t.loginCompletedAt.replace("{time}", formatDate(login.completedAt))
12381
+ children: t.loginCompletedAt.replace("{time}", formatDate$1(login.completedAt))
12299
12382
  })] }),
12300
12383
  login.status === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
12301
12384
  className: "dsha-error",
@@ -12590,7 +12673,7 @@ window.__ModuleLoader__.load({
12590
12673
  id: model.id,
12591
12674
  name: model.name,
12592
12675
  draft: contextDrafts[model.id] ?? "",
12593
- meta: model.defaultContextWindow < model.contextWindow ? formatCapacity(model.contextWindow) : void 0,
12676
+ meta: model.defaultContextWindow < model.contextWindow ? formatCapacity$1(model.contextWindow) : void 0,
12594
12677
  inputLabel: `${model.name} ${t.contextWindowSection}`,
12595
12678
  hasOverride: status?.contextWindowOverrides[model.id] !== void 0,
12596
12679
  saving: savingModel === model.id
@@ -12656,11 +12739,11 @@ window.__ModuleLoader__.load({
12656
12739
  children: [
12657
12740
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
12658
12741
  className: "dshsc-fact",
12659
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.quotaRenews }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatDate(quota.renewsAt) })]
12742
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.quotaRenews }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatDate$1(quota.renewsAt) })]
12660
12743
  }),
12661
12744
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
12662
12745
  className: "dshsc-fact",
12663
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.quotaReadAt }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatDate(quota.fetchedAt) })]
12746
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.quotaReadAt }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatDate$1(quota.fetchedAt) })]
12664
12747
  }),
12665
12748
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
12666
12749
  className: "dshsc-fact",
@@ -12700,7 +12783,7 @@ window.__ModuleLoader__.load({
12700
12783
  children: [
12701
12784
  t.quotaBucketExpires,
12702
12785
  ": ",
12703
- formatDate(bucket.expiresAt)
12786
+ formatDate$1(bucket.expiresAt)
12704
12787
  ]
12705
12788
  }),
12706
12789
  bucket.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -12708,7 +12791,7 @@ window.__ModuleLoader__.load({
12708
12791
  children: [
12709
12792
  t.quotaBucketResets,
12710
12793
  ": ",
12711
- formatDate(bucket.resetsAt)
12794
+ formatDate$1(bucket.resetsAt)
12712
12795
  ]
12713
12796
  })
12714
12797
  ]
@@ -12770,7 +12853,7 @@ window.__ModuleLoader__.load({
12770
12853
  children: t.quotaCredentialExpires
12771
12854
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12772
12855
  className: "dsha-value",
12773
- children: formatDate(quotaCredential.expiresAt)
12856
+ children: formatDate$1(quotaCredential.expiresAt)
12774
12857
  })]
12775
12858
  }),
12776
12859
  quotaCredential.error !== void 0 && quotaCredential.error !== null && quotaCredential.error !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -13898,6 +13981,14 @@ window.__ModuleLoader__.load({
13898
13981
  .dsha-account-quota-row[data-level=danger] .dsha-account-quota-fill{background:var(--dsw-alias-label-danger,#d94b4b)}
13899
13982
  .dsha-account-quota-value{color:var(--dsw-alias-label-primary);flex:none;font-variant-numeric:tabular-nums;min-width:40px;text-align:right}
13900
13983
  .dsha-account-quota-meta{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;font-variant-numeric:tabular-nums}
13984
+ /* Models parked on one account. A model park is not the account's own
13985
+ cooldown - the account keeps serving every other model it has - so the row
13986
+ names the model and gives that park a countdown of its own. */
13987
+ .dsha-account-model-cooldowns{display:flex;flex-direction:column;gap:4px;margin-top:9px}
13988
+ .dsha-account-model-cooldown-row{align-items:center;display:flex;font-size:12px;gap:8px}
13989
+ .dsha-account-model-cooldown-tag{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px}
13990
+ .dsha-account-model-cooldown-name{color:var(--dsw-alias-label-secondary);flex:none;max-width:38%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
13991
+ .dsha-account-model-cooldown-time{color:var(--dsw-alias-label-primary);flex:none;font-variant-numeric:tabular-nums}
13901
13992
  @media(max-width:560px){.dsha-account-quota-meta{display:none}}
13902
13993
  `, POOL_STYLE_ID);
13903
13994
  }
@@ -16122,7 +16213,7 @@ window.__ModuleLoader__.load({
16122
16213
  const [failure, setFailure] = (0, react.useState)(void 0);
16123
16214
  const value = snapshot.value ?? {};
16124
16215
  const writable = settings !== void 0 && snapshot.status === "ready" && snapshot.writable;
16125
- const enabled = value.progressUpdates === true;
16216
+ const enabled = value.progressUpdates !== false;
16126
16217
  const threshold = typeof value.progressUpdatesNudgeThreshold === "number" ? value.progressUpdatesNudgeThreshold : 8;
16127
16218
  const [draft, setDraft] = (0, react.useState)(() => String(threshold));
16128
16219
  (0, react.useEffect)(() => {
@@ -16750,15 +16841,23 @@ window.__ModuleLoader__.load({
16750
16841
  * 设置表单通道。
16751
16842
  *
16752
16843
  * 调用方给了就用它;否则从 `ctx.configForms` 现取一份,并登记到本插件的 effect
16753
- * 上(插件卸载时释放镜像订阅)。服务缺席时是 undefined——卡片据此渲染成只读。
16844
+ * 上(插件卸载时释放镜像订阅)。若 `configForms` 晚于本插件挂载,设置页渲染时
16845
+ * 再次按需获取;服务始终缺席时是 undefined——卡片据此渲染成只读。
16754
16846
  */
16755
- const settings = options.settings ?? (() => {
16847
+ let settings = options.settings;
16848
+ const resolveSettings = () => {
16849
+ if (settings !== void 0) return settings;
16756
16850
  const form = createProgressSettingsForm(ctx);
16757
- if (form !== void 0) ctx.effect(() => () => {
16758
- form.dispose();
16759
- }, "dsh-progress-updates: settings form");
16760
- return form;
16761
- })();
16851
+ if (form !== void 0) {
16852
+ settings = form;
16853
+ ctx.effect(() => () => {
16854
+ form.dispose();
16855
+ if (settings === form) settings = void 0;
16856
+ }, "dsh-progress-updates: settings form");
16857
+ }
16858
+ return settings;
16859
+ };
16860
+ resolveSettings();
16762
16861
  ctx.effect(() => () => {
16763
16862
  for (const source of hostSources.values()) try {
16764
16863
  source.stop();
@@ -16766,13 +16865,32 @@ window.__ModuleLoader__.load({
16766
16865
  hostSources.clear();
16767
16866
  }, "dsh-progress-updates: poll lifecycle");
16768
16867
  /**
16868
+ * 取侧栏页签类型注册表。
16869
+ *
16870
+ * 属性读只在服务名确实在当前 scope 的 inject 名单里时合法——本插件自己的
16871
+ * 静态 `inject` 没有 `sidebarRightTabs`,属性读会被 Cordis 拒绝,所以先试
16872
+ * 属性、失败再退回 `get()`(服务缺席时按缺失处理)。
16873
+ *
16874
+ * @param scope - 浏览器根上下文,或 `ctx.inject(['sidebarRightTabs'], ...)` 交来的 scope。
16875
+ * @returns 注册表实例,或 undefined。
16876
+ */
16877
+ const tabsOf = (scope) => {
16878
+ try {
16879
+ const direct = scope.sidebarRightTabs;
16880
+ if (direct !== void 0) return direct;
16881
+ } catch {}
16882
+ return serviceOf(scope, "sidebarRightTabs");
16883
+ };
16884
+ /**
16769
16885
  * 阶段一:声明页签**类型**。
16770
16886
  *
16771
16887
  * 这一步是面板能打开的前提。`patterns` 省略 = 页面型页签,按 kind 打开。
16772
- * 服务不存在(没装 ui-sidebar-right)时整段跳过:对话流行与设置页照常挂上。
16888
+ * 服务不存在(没装 ui-sidebar-right)时整段跳过:对话流行与设置页照常挂上;
16889
+ * 若 `sidebarRightTabs` 晚于本插件挂载,通过 `ctx.inject(['sidebarRightTabs'], ...)`
16890
+ * 在服务就绪时自动补注册。
16773
16891
  */
16774
- ctx.effect(() => {
16775
- const tabs = serviceOf(ctx, "sidebarRightTabs");
16892
+ const registerTabDefinition = (targetCtx) => {
16893
+ const tabs = tabsOf(targetCtx);
16776
16894
  if (typeof tabs?.register !== "function") return () => {};
16777
16895
  try {
16778
16896
  const definition = {
@@ -16809,7 +16927,13 @@ window.__ModuleLoader__.load({
16809
16927
  } catch {
16810
16928
  return () => {};
16811
16929
  }
16812
- }, "dsh-progress-updates: tab type");
16930
+ };
16931
+ const immediateTabs = tabsOf(ctx);
16932
+ const injectService = ctx.inject;
16933
+ if (typeof immediateTabs?.register === "function" || typeof injectService !== "function") ctx.effect(() => registerTabDefinition(ctx), "dsh-progress-updates: tab type");
16934
+ else injectService.call(ctx, ["sidebarRightTabs"], (scope) => {
16935
+ scope.effect(() => registerTabDefinition(scope), "dsh-progress-updates: tab type");
16936
+ });
16813
16937
  /**
16814
16938
  * 对话流里的进展行:`progress_update` 每次调用渲染成一行。
16815
16939
  *
@@ -16871,9 +16995,12 @@ window.__ModuleLoader__.load({
16871
16995
  }
16872
16996
  },
16873
16997
  locale: NS_PROGRESS_UPDATES,
16874
- inject: () => settings === void 0 ? { openPanel } : {
16875
- openPanel,
16876
- settings
16998
+ inject: () => {
16999
+ const currentSettings = resolveSettings();
17000
+ return currentSettings === void 0 ? { openPanel } : {
17001
+ openPanel,
17002
+ settings: currentSettings
17003
+ };
16877
17004
  }
16878
17005
  }, ProgressUpdatesSettingsSection);
16879
17006
  } catch {