@eddyskywalker/dsh-chatgpt-subscription 0.28.0 → 0.29.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 (48) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/lib/client.js +274 -149
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +125 -21
  5. package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
  6. package/lib/types/client/antigravity/locales.d.ts +11 -2
  7. package/lib/types/client/antigravity/locales.d.ts.map +1 -1
  8. package/lib/types/client/claude/locales.d.ts +11 -2
  9. package/lib/types/client/claude/locales.d.ts.map +1 -1
  10. package/lib/types/client/command-code/locales.d.ts +11 -2
  11. package/lib/types/client/command-code/locales.d.ts.map +1 -1
  12. package/lib/types/client/common/AccountPoolSection.d.ts +10 -2
  13. package/lib/types/client/common/AccountPoolSection.d.ts.map +1 -1
  14. package/lib/types/client/common/account-pool-labels.d.ts +17 -0
  15. package/lib/types/client/common/account-pool-labels.d.ts.map +1 -1
  16. package/lib/types/client/common/format.d.ts +14 -0
  17. package/lib/types/client/common/format.d.ts.map +1 -1
  18. package/lib/types/client/common/styles.d.ts.map +1 -1
  19. package/lib/types/client/glm-coding-plan/locales.d.ts +11 -2
  20. package/lib/types/client/glm-coding-plan/locales.d.ts.map +1 -1
  21. package/lib/types/client/glm-coding-plan/useGlmCodingPlanSection.d.ts.map +1 -1
  22. package/lib/types/client/kimi-code/locales.d.ts +11 -2
  23. package/lib/types/client/kimi-code/locales.d.ts.map +1 -1
  24. package/lib/types/client/locales.d.ts +7 -1
  25. package/lib/types/client/locales.d.ts.map +1 -1
  26. package/lib/types/client/minimax-code/locales.d.ts +11 -2
  27. package/lib/types/client/minimax-code/locales.d.ts.map +1 -1
  28. package/lib/types/client/minimax-code/useMinimaxCodeSection.d.ts.map +1 -1
  29. package/lib/types/client/ollama/locales.d.ts +18 -0
  30. package/lib/types/client/ollama/locales.d.ts.map +1 -1
  31. package/lib/types/client/progress-updates/index.d.ts.map +1 -1
  32. package/lib/types/client/step-code/locales.d.ts +11 -2
  33. package/lib/types/client/step-code/locales.d.ts.map +1 -1
  34. package/lib/types/client/step-code/useStepCodeSection.d.ts.map +1 -1
  35. package/lib/types/client/workbuddy/locales.d.ts +6 -0
  36. package/lib/types/client/workbuddy/locales.d.ts.map +1 -1
  37. package/lib/types/client/workbuddy/useWorkBuddySection.d.ts.map +1 -1
  38. package/lib/types/host/antigravity/account-pool.d.ts +17 -3
  39. package/lib/types/host/antigravity/account-pool.d.ts.map +1 -1
  40. package/lib/types/host/antigravity/adapter.d.ts +7 -2
  41. package/lib/types/host/antigravity/adapter.d.ts.map +1 -1
  42. package/lib/types/host/workbuddy/account-pool.d.ts +24 -0
  43. package/lib/types/host/workbuddy/account-pool.d.ts.map +1 -1
  44. package/lib/types/index.d.ts +2 -2
  45. package/lib/types/index.d.ts.map +1 -1
  46. package/lib/types/shared/account-pool-contracts.d.ts +24 -0
  47. package/lib/types/shared/account-pool-contracts.d.ts.map +1 -1
  48. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -292,6 +292,9 @@ window.__ModuleLoader__.load({
292
292
  deleteAccount: "删除",
293
293
  cooling: "冷却中",
294
294
  cooldownLeft: "剩 {minutes} 分",
295
+ cooldownRemaining: "剩 {minutes} 分 {seconds} 秒",
296
+ cooldownRemainingSeconds: "剩 {seconds} 秒",
297
+ modelCooldown: "模型冷却",
295
298
  clearCooldown: "重置冷却",
296
299
  needsRelogin: "需重新登录",
297
300
  relogin: "重新登录",
@@ -325,6 +328,9 @@ window.__ModuleLoader__.load({
325
328
  deleteAccount: "Delete",
326
329
  cooling: "In Cooldown",
327
330
  cooldownLeft: "{minutes} min left",
331
+ cooldownRemaining: "{minutes} min {seconds}s left",
332
+ cooldownRemainingSeconds: "{seconds}s left",
333
+ modelCooldown: "Model cooldown",
328
334
  clearCooldown: "Clear Cooldown",
329
335
  needsRelogin: "Sign-in required",
330
336
  relogin: "Sign in again",
@@ -1048,6 +1054,84 @@ window.__ModuleLoader__.load({
1048
1054
  });
1049
1055
  }
1050
1056
  //#endregion
1057
+ //#region src/client/common/format.ts
1058
+ /**
1059
+ * The capacity, date and countdown formatting every provider settings card shares.
1060
+ *
1061
+ * Each card used to carry its own copy of the capacity pair. The five copies
1062
+ * were byte-identical except Antigravity's `formatCapacity`, which had lost the
1063
+ * 1K floor and so rendered a zero as "0K" while its siblings rendered "0". The
1064
+ * parse has to mean the same thing on every line — it takes free-text user input
1065
+ * that feeds the overflow judgement — so this is the one place it lives. The
1066
+ * date helpers were copied the same way; WorkBuddy's countdown is here for the
1067
+ * same reason.
1068
+ */
1069
+ /**
1070
+ * Parse "1M", "512K", "200000" into a positive integer token count.
1071
+ *
1072
+ * Anything that is not a plain capacity — including `0`, which no model has —
1073
+ * returns null rather than a coerced number, so the caller can leave the draft
1074
+ * uncommitted instead of storing a length that would silently break compaction.
1075
+ */
1076
+ function parsePositiveCapacity$1(value) {
1077
+ const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
1078
+ if (matched === null) return null;
1079
+ const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
1080
+ const parsed = Number(matched[1]) * multiplier;
1081
+ return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
1082
+ }
1083
+ /** Render a token capacity the way the capacity field seeds itself. */
1084
+ function formatCapacity$1(value) {
1085
+ if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
1086
+ if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
1087
+ return String(value);
1088
+ }
1089
+ /** A stamp in the reader's own locale, or an em dash when there is none. */
1090
+ function formatDate$1(ms) {
1091
+ if (ms === void 0 || ms === null || !Number.isFinite(ms) || ms <= 0) return "—";
1092
+ try {
1093
+ return new Intl.DateTimeFormat(void 0, {
1094
+ dateStyle: "medium",
1095
+ timeStyle: "short"
1096
+ }).format(ms);
1097
+ } catch {
1098
+ return "—";
1099
+ }
1100
+ }
1101
+ /**
1102
+ * The remaining part of a cooldown, split into whole minutes and seconds.
1103
+ *
1104
+ * A cooldown counted in whole minutes only is frozen for a whole minute at a
1105
+ * time: the badge says "剩 5 分" while the wait drops from 5:00 to 4:01, and
1106
+ * the user is left watching a number that does not move. The seconds are what
1107
+ * make the wait legible, so they are carried separately - and rounded UP,
1108
+ * because a cooldown with 30.2 seconds left is still 31 seconds of waiting, and
1109
+ * rounding down would announce "0 seconds left" while the wait is not over.
1110
+ */
1111
+ function cooldownRemainingParts(remainingMs) {
1112
+ const totalSeconds = Math.max(0, Math.ceil(remainingMs / 1e3));
1113
+ return {
1114
+ minutes: Math.floor(totalSeconds / 60),
1115
+ seconds: totalSeconds % 60
1116
+ };
1117
+ }
1118
+ /**
1119
+ * Countdown to a reset instant ("3d 4h"), empty when there is nothing to count
1120
+ * down to. Empty rather than "—" because callers append it to a date they have
1121
+ * already rendered, and a dash there would read as a second missing value.
1122
+ */
1123
+ function formatReset$1(resetsAt) {
1124
+ if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
1125
+ const diff = resetsAt - Date.now();
1126
+ if (diff <= 0) return "now";
1127
+ const mins = Math.floor(diff / 6e4);
1128
+ const hours = Math.floor(mins / 60);
1129
+ const days = Math.floor(hours / 24);
1130
+ if (days > 0) return `${days}d ${hours % 24}h`;
1131
+ if (hours > 0) return `${hours}h ${mins % 60}m`;
1132
+ return `${mins}m`;
1133
+ }
1134
+ //#endregion
1051
1135
  //#region src/client/common/AccountPoolSection.tsx
1052
1136
  /** Format one account timestamp the way every tab renders it. */
1053
1137
  function formatAccountDate(ms) {
@@ -1061,9 +1145,21 @@ window.__ModuleLoader__.load({
1061
1145
  return "—";
1062
1146
  }
1063
1147
  }
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));
1148
+ /**
1149
+ * The remaining cooldown, in the reader's own words.
1150
+ *
1151
+ * Whole minutes while a minute or more is left, minutes and seconds below
1152
+ * that, and the seconds alone under a minute: "剩 1 分" for the last 59
1153
+ * seconds is a lie, and "剩 0 分 42 秒" is unreadable.
1154
+ */
1155
+ function formatCooldownRemaining(remainingMs, labels) {
1156
+ const { minutes, seconds } = cooldownRemainingParts(remainingMs);
1157
+ if (minutes === 0) return formatPoolLabel(labels.cooldownRemainingSeconds, { seconds });
1158
+ if (seconds === 0) return formatPoolLabel(labels.cooldownLeft, { minutes });
1159
+ return formatPoolLabel(labels.cooldownRemaining, {
1160
+ minutes,
1161
+ seconds
1162
+ });
1067
1163
  }
1068
1164
  /** Whether one account currently carries a live 429 cooldown. */
1069
1165
  function isCoolingDown(account, now = Date.now()) {
@@ -1084,8 +1180,15 @@ window.__ModuleLoader__.load({
1084
1180
  function AccountPoolSection(props) {
1085
1181
  const t = props.labels;
1086
1182
  const accounts = props.accounts;
1087
- const now = Date.now();
1183
+ const [now, setNow] = (0, react.useState)(() => Date.now());
1088
1184
  const anyQuota = accounts.some((account) => account.quota !== void 0);
1185
+ const counting = accounts.some((account) => isCoolingDown(account, now) || (account.modelCooldowns ?? []).some((park) => park.cooldownUntil > now));
1186
+ (0, react.useEffect)(() => {
1187
+ if (!counting) return;
1188
+ setNow(Date.now());
1189
+ const timer = window.setInterval(() => setNow(Date.now()), 1e3);
1190
+ return () => window.clearInterval(timer);
1191
+ }, [counting]);
1089
1192
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1090
1193
  className: "dsha-group",
1091
1194
  children: [
@@ -1148,6 +1251,7 @@ window.__ModuleLoader__.load({
1148
1251
  children: accounts.map((account) => {
1149
1252
  const isActive = account.id === props.activeAccountId;
1150
1253
  const cooling = isCoolingDown(account, now);
1254
+ const modelParks = (account.modelCooldowns ?? []).filter((park) => park.cooldownUntil > now);
1151
1255
  const needsRelogin = account.authStatus !== void 0 && account.authStatus !== "ok";
1152
1256
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1153
1257
  className: `dsha-account-card ${isActive ? "active" : ""}`,
@@ -1175,7 +1279,7 @@ window.__ModuleLoader__.load({
1175
1279
  children: [
1176
1280
  t.cooling,
1177
1281
  "(",
1178
- formatPoolLabel(t.cooldownLeft, { minutes: cooldownMinutesLeft(account.cooldownUntil, now) }),
1282
+ formatCooldownRemaining(account.cooldownUntil - now, t),
1179
1283
  ")"
1180
1284
  ]
1181
1285
  }),
@@ -1237,6 +1341,27 @@ window.__ModuleLoader__.load({
1237
1341
  ] })
1238
1342
  ]
1239
1343
  }),
1344
+ modelParks.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1345
+ className: "dsha-account-model-cooldowns",
1346
+ children: modelParks.map((park) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1347
+ className: "dsha-account-model-cooldown-row",
1348
+ children: [
1349
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1350
+ className: "dsha-account-model-cooldown-tag",
1351
+ children: t.modelCooldown
1352
+ }),
1353
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1354
+ className: "dsha-account-model-cooldown-name",
1355
+ title: park.model,
1356
+ children: park.model
1357
+ }),
1358
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1359
+ className: "dsha-account-model-cooldown-time",
1360
+ children: formatCooldownRemaining(park.cooldownUntil - now, t)
1361
+ })
1362
+ ]
1363
+ }, park.model))
1364
+ }),
1240
1365
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountQuota, {
1241
1366
  quota: account.quota,
1242
1367
  labels: t,
@@ -1560,7 +1685,7 @@ window.__ModuleLoader__.load({
1560
1685
  await updatePreferences({ contextWindowOverrides: { [model]: null } });
1561
1686
  setContextDrafts((drafts) => ({
1562
1687
  ...drafts,
1563
- [model]: formatCapacity$1(resolveCodexCatalogEntry(model).contextWindow)
1688
+ [model]: formatCapacity(resolveCodexCatalogEntry(model).contextWindow)
1564
1689
  }));
1565
1690
  };
1566
1691
  /** Clear every stored override, including models the picker no longer shows. */
@@ -1591,6 +1716,9 @@ window.__ModuleLoader__.load({
1591
1716
  deleteAccount: t("deleteAccount"),
1592
1717
  cooling: t("cooling"),
1593
1718
  cooldownLeft: t("cooldownLeft"),
1719
+ cooldownRemaining: t("cooldownRemaining"),
1720
+ cooldownRemainingSeconds: t("cooldownRemainingSeconds"),
1721
+ modelCooldown: t("modelCooldown"),
1594
1722
  clearCooldown: t("clearCooldown"),
1595
1723
  needsRelogin: t("needsRelogin"),
1596
1724
  relogin: t("relogin"),
@@ -1801,7 +1929,7 @@ window.__ModuleLoader__.load({
1801
1929
  children: [
1802
1930
  connection !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoRow, {
1803
1931
  label: t("latency"),
1804
- value: `${connection.latencyMs} ms · ${formatDate$1(connection.checkedAt)}`
1932
+ value: `${connection.latencyMs} ms · ${formatDate(connection.checkedAt)}`
1805
1933
  }) : null,
1806
1934
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1807
1935
  className: "dsha-muted dsha-models-hint",
@@ -1811,7 +1939,7 @@ window.__ModuleLoader__.load({
1811
1939
  items: CODEX_MODEL_CATALOG.map((model) => ({
1812
1940
  id: model.id,
1813
1941
  name: model.name,
1814
- hint: `${formatCapacity$1(model.contextWindow)} ${t("tokens")}`,
1942
+ hint: `${formatCapacity(model.contextWindow)} ${t("tokens")}`,
1815
1943
  enabled: visibleModelIds.some((id) => id === model.id)
1816
1944
  })),
1817
1945
  busy: busy !== null,
@@ -2069,7 +2197,7 @@ window.__ModuleLoader__.load({
2069
2197
  id: inputId,
2070
2198
  type: "text",
2071
2199
  inputMode: "numeric",
2072
- value: draft ?? formatCapacity$1(fallback),
2200
+ value: draft ?? formatCapacity(fallback),
2073
2201
  disabled: busy !== null,
2074
2202
  "aria-label": entry.name + " " + t("contextWindow"),
2075
2203
  onChange: (event) => {
@@ -2205,7 +2333,7 @@ window.__ModuleLoader__.load({
2205
2333
  children: [
2206
2334
  t("updated"),
2207
2335
  ": ",
2208
- formatDate$1(quota.fetchedAt)
2336
+ formatDate(quota.fetchedAt)
2209
2337
  ]
2210
2338
  }) : null
2211
2339
  ]
@@ -2344,7 +2472,7 @@ window.__ModuleLoader__.load({
2344
2472
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("small", { children: [
2345
2473
  t("resetCreditExpires"),
2346
2474
  ": ",
2347
- resetCredits.expiresAt == null ? t("unknown") : formatReset$1(resetCredits.expiresAt)
2475
+ resetCredits.expiresAt == null ? t("unknown") : formatReset(resetCredits.expiresAt)
2348
2476
  ] })
2349
2477
  ]
2350
2478
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
@@ -2363,7 +2491,7 @@ window.__ModuleLoader__.load({
2363
2491
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {})]
2364
2492
  });
2365
2493
  }
2366
- function parsePositiveCapacity$1(value) {
2494
+ function parsePositiveCapacity(value) {
2367
2495
  const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
2368
2496
  if (matched === null) return null;
2369
2497
  const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
@@ -2371,10 +2499,10 @@ window.__ModuleLoader__.load({
2371
2499
  return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
2372
2500
  }
2373
2501
  function parseCapacity(value, maxContextWindow = GPT_56_MAX_CONTEXT_WINDOW) {
2374
- const parsed = parsePositiveCapacity$1(value);
2502
+ const parsed = parsePositiveCapacity(value);
2375
2503
  return parsed !== null && parsed <= maxContextWindow ? parsed : null;
2376
2504
  }
2377
- function formatCapacity$1(value) {
2505
+ function formatCapacity(value) {
2378
2506
  if (value % 1e3 === 0) return `${value / 1e3}K`;
2379
2507
  return String(value);
2380
2508
  }
@@ -2391,11 +2519,11 @@ window.__ModuleLoader__.load({
2391
2519
  limit.remainingPercent !== null && limit.remainingPercent !== void 0 ? `${formatPercent(limit.remainingPercent)} ${t("remaining")}` : null,
2392
2520
  limit.limit !== null && limit.limit !== void 0 ? `${t("limit")}: ${limit.limit}` : null,
2393
2521
  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
2522
+ limit.resetsAt !== null && limit.resetsAt !== void 0 ? `${t("resets")}: ${formatReset(limit.resetsAt)}` : null
2395
2523
  ].filter((part) => part !== null);
2396
2524
  return parts.length > 0 ? parts.join(" · ") : t("unknown");
2397
2525
  }
2398
- function formatDate$1(seconds) {
2526
+ function formatDate(seconds) {
2399
2527
  if (seconds === void 0 || seconds === null || typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) return "—";
2400
2528
  const ms = seconds > 1e10 ? seconds : seconds * 1e3;
2401
2529
  try {
@@ -2407,10 +2535,10 @@ window.__ModuleLoader__.load({
2407
2535
  return "—";
2408
2536
  }
2409
2537
  }
2410
- function formatReset$1(seconds) {
2538
+ function formatReset(seconds) {
2411
2539
  if (seconds === void 0 || seconds === null || typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) return "—";
2412
2540
  const ms = seconds > 1e10 ? seconds : seconds * 1e3;
2413
- const absolute = formatDate$1(seconds);
2541
+ const absolute = formatDate(seconds);
2414
2542
  const diff = ms - Date.now();
2415
2543
  const abs = Math.abs(diff);
2416
2544
  const [amount, unit] = abs >= 864e5 ? [Math.round(diff / 864e5), "day"] : abs >= 36e5 ? [Math.round(diff / 36e5), "hour"] : [Math.round(diff / 6e4), "minute"];
@@ -2424,67 +2552,6 @@ window.__ModuleLoader__.load({
2424
2552
  return error instanceof Error ? error.message : String(error);
2425
2553
  }
2426
2554
  //#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
2555
  //#region src/client/common/ContextWindowEditor.tsx
2489
2556
  /**
2490
2557
  * The shared "model context windows" block every provider settings card renders.
@@ -2516,7 +2583,7 @@ window.__ModuleLoader__.load({
2516
2583
  */
2517
2584
  function contextDraftsFor(status) {
2518
2585
  const drafts = {};
2519
- for (const model of status.models) drafts[model.id] = formatCapacity(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
2586
+ for (const model of status.models) drafts[model.id] = formatCapacity$1(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
2520
2587
  return drafts;
2521
2588
  }
2522
2589
  function ContextWindowEditor({ rows, labels, busy, overrideCount, metaClassName, onDraftChange, onCommit, onReset, onResetAll }) {
@@ -3033,7 +3100,7 @@ window.__ModuleLoader__.load({
3033
3100
  };
3034
3101
  const handleSaveContextWindow = async (modelId) => {
3035
3102
  const raw = contextDrafts[modelId] || "";
3036
- const parsed = parsePositiveCapacity(raw);
3103
+ const parsed = parsePositiveCapacity$1(raw);
3037
3104
  if (parsed === null) {
3038
3105
  setError(`无效的上下文容量值: ${raw}`);
3039
3106
  return;
@@ -3048,7 +3115,7 @@ window.__ModuleLoader__.load({
3048
3115
  setStatus(updated);
3049
3116
  setContextDrafts((prev) => ({
3050
3117
  ...prev,
3051
- [modelId]: formatCapacity(parsed)
3118
+ [modelId]: formatCapacity$1(parsed)
3052
3119
  }));
3053
3120
  notifyChange();
3054
3121
  } catch (err) {
@@ -3071,7 +3138,7 @@ window.__ModuleLoader__.load({
3071
3138
  const model = updated.models.find((candidate) => candidate.id === modelId);
3072
3139
  return model === void 0 ? prev : {
3073
3140
  ...prev,
3074
- [modelId]: formatCapacity(model.defaultContextWindow)
3141
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
3075
3142
  };
3076
3143
  });
3077
3144
  notifyChange();
@@ -3151,7 +3218,7 @@ window.__ModuleLoader__.load({
3151
3218
  items: (status?.models ?? []).map((model) => ({
3152
3219
  id: model.id,
3153
3220
  name: model.name,
3154
- hint: model.defaultContextWindow ? formatCapacity(model.defaultContextWindow) : void 0,
3221
+ hint: model.defaultContextWindow ? formatCapacity$1(model.defaultContextWindow) : void 0,
3155
3222
  enabled: model.enabled
3156
3223
  })),
3157
3224
  busy: busy !== null,
@@ -3791,7 +3858,7 @@ window.__ModuleLoader__.load({
3791
3858
  };
3792
3859
  const handleSaveContextWindow = async (modelId) => {
3793
3860
  const raw = contextDrafts[modelId] || "";
3794
- const parsed = parsePositiveCapacity(raw);
3861
+ const parsed = parsePositiveCapacity$1(raw);
3795
3862
  if (parsed === null) {
3796
3863
  setError(`Invalid context capacity: ${raw}`);
3797
3864
  return;
@@ -3806,7 +3873,7 @@ window.__ModuleLoader__.load({
3806
3873
  setStatus(updated);
3807
3874
  setContextDrafts((prev) => ({
3808
3875
  ...prev,
3809
- [modelId]: formatCapacity(parsed)
3876
+ [modelId]: formatCapacity$1(parsed)
3810
3877
  }));
3811
3878
  notifyChange();
3812
3879
  } catch (err) {
@@ -3829,7 +3896,7 @@ window.__ModuleLoader__.load({
3829
3896
  const model = updated.models.find((candidate) => candidate.id === modelId);
3830
3897
  return model === void 0 ? prev : {
3831
3898
  ...prev,
3832
- [modelId]: formatCapacity(model.defaultContextWindow)
3899
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
3833
3900
  };
3834
3901
  });
3835
3902
  notifyChange();
@@ -3966,7 +4033,7 @@ window.__ModuleLoader__.load({
3966
4033
  children: [
3967
4034
  status.catalogStale ? t.catalogStale : t.catalogFresh,
3968
4035
  " · ",
3969
- formatDate(status.catalogFetchedAt)
4036
+ formatDate$1(status.catalogFetchedAt)
3970
4037
  ]
3971
4038
  }),
3972
4039
  status?.zeroDataRetention === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -4759,7 +4826,7 @@ window.__ModuleLoader__.load({
4759
4826
  };
4760
4827
  const handleSaveContextWindow = async (modelId) => {
4761
4828
  const raw = contextDrafts[modelId] || "";
4762
- const parsed = parsePositiveCapacity(raw);
4829
+ const parsed = parsePositiveCapacity$1(raw);
4763
4830
  if (parsed === null) {
4764
4831
  setError(`Invalid context capacity: ${raw}`);
4765
4832
  return;
@@ -4774,7 +4841,7 @@ window.__ModuleLoader__.load({
4774
4841
  setStatus(updated);
4775
4842
  setContextDrafts((prev) => ({
4776
4843
  ...prev,
4777
- [modelId]: formatCapacity(parsed)
4844
+ [modelId]: formatCapacity$1(parsed)
4778
4845
  }));
4779
4846
  notifyChange();
4780
4847
  } catch (err) {
@@ -4797,7 +4864,7 @@ window.__ModuleLoader__.load({
4797
4864
  const model = updated.models.find((candidate) => candidate.id === modelId);
4798
4865
  return model === void 0 ? prev : {
4799
4866
  ...prev,
4800
- [modelId]: formatCapacity(model.defaultContextWindow)
4867
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
4801
4868
  };
4802
4869
  });
4803
4870
  notifyChange();
@@ -4900,7 +4967,7 @@ window.__ModuleLoader__.load({
4900
4967
  children: t.codeExpires
4901
4968
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4902
4969
  className: "dsha-value",
4903
- children: formatDate(flow?.expiresAt)
4970
+ children: formatDate$1(flow?.expiresAt)
4904
4971
  })]
4905
4972
  }),
4906
4973
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -5162,7 +5229,7 @@ window.__ModuleLoader__.load({
5162
5229
  id: model.id,
5163
5230
  name: model.name,
5164
5231
  draft: contextDrafts[model.id] ?? "",
5165
- meta: model.defaultContextWindow < model.contextWindow ? formatCapacity(model.contextWindow) : void 0,
5232
+ meta: model.defaultContextWindow < model.contextWindow ? formatCapacity$1(model.contextWindow) : void 0,
5166
5233
  inputLabel: `${model.name} context window`,
5167
5234
  hasOverride: status?.contextWindowOverrides[model.id] !== void 0,
5168
5235
  saving: savingModel === model.id
@@ -5298,6 +5365,7 @@ window.__ModuleLoader__.load({
5298
5365
  rescan: "重新扫描",
5299
5366
  rescanning: "扫描中...",
5300
5367
  accounts: "账号管理",
5368
+ modelCooldown: "模型限流",
5301
5369
  addCnAccount: "添加国区账号",
5302
5370
  addIntlAccount: "添加国际区账号",
5303
5371
  authorizing: "授权中…",
@@ -5402,6 +5470,7 @@ window.__ModuleLoader__.load({
5402
5470
  rescan: "Rescan",
5403
5471
  rescanning: "Scanning...",
5404
5472
  accounts: "Account Management",
5473
+ modelCooldown: "Model rate limit",
5405
5474
  addCnAccount: "Add China account",
5406
5475
  addIntlAccount: "Add international account",
5407
5476
  authorizing: "Authorizing…",
@@ -5518,7 +5587,8 @@ window.__ModuleLoader__.load({
5518
5587
  return {
5519
5588
  ...accountPoolZh,
5520
5589
  noAccounts: t.noAccounts,
5521
- email: t.nickname
5590
+ email: t.nickname,
5591
+ modelCooldown: t.modelCooldown
5522
5592
  };
5523
5593
  }
5524
5594
  /**
@@ -5620,7 +5690,9 @@ window.__ModuleLoader__.load({
5620
5690
  if (document.visibilityState === "visible") loadStatus(true);
5621
5691
  };
5622
5692
  document.addEventListener("visibilitychange", refreshWhenVisible);
5693
+ const timer = window.setInterval(refreshWhenVisible, 6e4);
5623
5694
  return () => {
5695
+ window.clearInterval(timer);
5624
5696
  document.removeEventListener("visibilitychange", refreshWhenVisible);
5625
5697
  quotaFollowUp.current?.cancel();
5626
5698
  if (loginIntervalRef.current !== null) window.clearInterval(loginIntervalRef.current);
@@ -5919,7 +5991,7 @@ window.__ModuleLoader__.load({
5919
5991
  };
5920
5992
  const saveContextWindow = async (modelId) => {
5921
5993
  const raw = contextDrafts[modelId] || "";
5922
- const parsed = parsePositiveCapacity(raw);
5994
+ const parsed = parsePositiveCapacity$1(raw);
5923
5995
  if (parsed === null) {
5924
5996
  setError(`Invalid context capacity: ${raw}`);
5925
5997
  return;
@@ -5934,7 +6006,7 @@ window.__ModuleLoader__.load({
5934
6006
  setStatus(updated);
5935
6007
  setContextDrafts((prev) => ({
5936
6008
  ...prev,
5937
- [modelId]: formatCapacity(parsed)
6009
+ [modelId]: formatCapacity$1(parsed)
5938
6010
  }));
5939
6011
  notifyChange();
5940
6012
  } catch (err) {
@@ -5957,7 +6029,7 @@ window.__ModuleLoader__.load({
5957
6029
  const model = updated.models.find((candidate) => candidate.id === modelId);
5958
6030
  return model === void 0 ? prev : {
5959
6031
  ...prev,
5960
- [modelId]: formatCapacity(model.defaultContextWindow)
6032
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
5961
6033
  };
5962
6034
  });
5963
6035
  notifyChange();
@@ -6462,7 +6534,7 @@ window.__ModuleLoader__.load({
6462
6534
  id: model.id,
6463
6535
  name: model.name,
6464
6536
  hint: [
6465
- formatCapacity(model.contextWindow),
6537
+ formatCapacity$1(model.contextWindow),
6466
6538
  model.supportsImage ? t.imageSupport : t.textOnly,
6467
6539
  ...model.reasoningEfforts && model.reasoningEfforts.length > 0 ? [model.reasoningEfforts.join("/")] : [],
6468
6540
  ...multiplier === null ? [] : [multiplier]
@@ -6622,7 +6694,7 @@ window.__ModuleLoader__.load({
6622
6694
  children: t.quotaReset
6623
6695
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6624
6696
  className: "dsha-value",
6625
- children: [formatDate(quota.cycleEndsAt), formatReset(quota.cycleEndsAt) ? ` · ${formatReset(quota.cycleEndsAt)}` : ""]
6697
+ children: [formatDate$1(quota.cycleEndsAt), formatReset$1(quota.cycleEndsAt) ? ` · ${formatReset$1(quota.cycleEndsAt)}` : ""]
6626
6698
  })]
6627
6699
  }),
6628
6700
  quota.meters.filter((meter) => meter.remainingFraction === null).map((meter) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -6641,7 +6713,7 @@ window.__ModuleLoader__.load({
6641
6713
  ] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6642
6714
  t.quotaReset,
6643
6715
  ": ",
6644
- formatReset(meter.resetsAt)
6716
+ formatReset$1(meter.resetsAt)
6645
6717
  ] })]
6646
6718
  }),
6647
6719
  meter.description !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -6974,6 +7046,9 @@ window.__ModuleLoader__.load({
6974
7046
  deleteAccount: t("deleteAccount"),
6975
7047
  cooling: t("cooling"),
6976
7048
  cooldownLeft: t("cooldownLeft"),
7049
+ cooldownRemaining: t("cooldownRemaining"),
7050
+ cooldownRemainingSeconds: t("cooldownRemainingSeconds"),
7051
+ modelCooldown: t("modelCooldown"),
6977
7052
  clearCooldown: t("clearCooldown"),
6978
7053
  needsRelogin: t("needsRelogin"),
6979
7054
  relogin: t("relogin"),
@@ -7365,7 +7440,7 @@ window.__ModuleLoader__.load({
7365
7440
  };
7366
7441
  const saveContextWindow = async (modelId) => {
7367
7442
  const raw = contextDrafts[modelId] ?? "";
7368
- const parsed = parsePositiveCapacity(raw);
7443
+ const parsed = parsePositiveCapacity$1(raw);
7369
7444
  if (parsed === null) {
7370
7445
  setError(t("invalidCapacity").replace("{value}", raw));
7371
7446
  return;
@@ -7377,7 +7452,7 @@ window.__ModuleLoader__.load({
7377
7452
  setStatus(updated);
7378
7453
  setContextDrafts((prev) => ({
7379
7454
  ...prev,
7380
- [modelId]: formatCapacity(parsed)
7455
+ [modelId]: formatCapacity$1(parsed)
7381
7456
  }));
7382
7457
  onModelChange?.();
7383
7458
  } catch (cause) {
@@ -7395,7 +7470,7 @@ window.__ModuleLoader__.load({
7395
7470
  const model = updated.models.find((entry) => entry.id === modelId);
7396
7471
  if (model !== void 0) setContextDrafts((prev) => ({
7397
7472
  ...prev,
7398
- [modelId]: formatCapacity(model.defaultContextWindow)
7473
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
7399
7474
  }));
7400
7475
  onModelChange?.();
7401
7476
  } catch (cause) {
@@ -7610,7 +7685,7 @@ window.__ModuleLoader__.load({
7610
7685
  status.checkin.failedToday > 0 ? ` · ${t("checkinFailed").replace("{count}", String(status.checkin.failedToday))}` : "",
7611
7686
  status.checkin.streakDays !== void 0 ? ` · ${t("checkinStreak").replace("{days}", String(status.checkin.streakDays))}` : "",
7612
7687
  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))}`
7688
+ ` · ${status.checkin.lastRunAt === null ? t("checkinNever") : t("checkinLastRun").replace("{time}", formatDate$1(status.checkin.lastRunAt))}`
7614
7689
  ]
7615
7690
  })]
7616
7691
  }),
@@ -7673,7 +7748,7 @@ window.__ModuleLoader__.load({
7673
7748
  children: t("expiresAt")
7674
7749
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7675
7750
  className: "dsha-value",
7676
- children: [formatDate(account?.expiresAtMs), hours === null ? ` · ${t("expiresExpired")}` : ` · ${t("expiresRemaining").replace("{hours}", hours)}`]
7751
+ children: [formatDate$1(account?.expiresAtMs), hours === null ? ` · ${t("expiresExpired")}` : ` · ${t("expiresRemaining").replace("{hours}", hours)}`]
7677
7752
  })]
7678
7753
  })
7679
7754
  ] }),
@@ -7871,7 +7946,7 @@ window.__ModuleLoader__.load({
7871
7946
  id: model.id,
7872
7947
  name: model.name,
7873
7948
  draft: contextDrafts[model.id] ?? "",
7874
- meta: model.defaultContextWindow < model.contextWindow ? formatCapacity(model.contextWindow) : void 0,
7949
+ meta: model.defaultContextWindow < model.contextWindow ? formatCapacity$1(model.contextWindow) : void 0,
7875
7950
  inputLabel: `${model.name} ${t("contextWindowSection")}`,
7876
7951
  hasOverride: status?.contextWindowOverrides[model.id] !== void 0,
7877
7952
  saving: savingModel === model.id
@@ -7948,7 +8023,7 @@ window.__ModuleLoader__.load({
7948
8023
  children: t("resetAvailable").replace("{count}", String(resetCardList.length))
7949
8024
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7950
8025
  className: "dsha-value",
7951
- children: formatDate(resetCards.fetchedAtMs)
8026
+ children: formatDate$1(resetCards.fetchedAtMs)
7952
8027
  })]
7953
8028
  }),
7954
8029
  resetCardList.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -7970,7 +8045,7 @@ window.__ModuleLoader__.load({
7970
8045
  })
7971
8046
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7972
8047
  className: "dsha-value",
7973
- children: t("resetExpires").replace("{time}", formatDate(card.expiresAtMs))
8048
+ children: t("resetExpires").replace("{time}", formatDate$1(card.expiresAtMs))
7974
8049
  })]
7975
8050
  }, card.cardId))
7976
8051
  }),
@@ -8011,7 +8086,7 @@ window.__ModuleLoader__.load({
8011
8086
  children: [
8012
8087
  entry.cardId,
8013
8088
  " · ",
8014
- formatDate(entry.createdAtMs)
8089
+ formatDate$1(entry.createdAtMs)
8015
8090
  ]
8016
8091
  })]
8017
8092
  }, `${entry.cardId}:${entry.createdAtMs}:${index}`))
@@ -8325,6 +8400,9 @@ window.__ModuleLoader__.load({
8325
8400
  deleteAccount: t("deleteAccount"),
8326
8401
  cooling: t("cooling"),
8327
8402
  cooldownLeft: t("cooldownLeft"),
8403
+ cooldownRemaining: t("cooldownRemaining"),
8404
+ cooldownRemainingSeconds: t("cooldownRemainingSeconds"),
8405
+ modelCooldown: t("modelCooldown"),
8328
8406
  clearCooldown: t("clearCooldown"),
8329
8407
  needsRelogin: t("needsRelogin"),
8330
8408
  relogin: t("relogin"),
@@ -8563,7 +8641,7 @@ window.__ModuleLoader__.load({
8563
8641
  };
8564
8642
  const saveContextWindow = async (modelId) => {
8565
8643
  const raw = contextDrafts[modelId] ?? "";
8566
- const parsed = parsePositiveCapacity(raw);
8644
+ const parsed = parsePositiveCapacity$1(raw);
8567
8645
  if (parsed === null) {
8568
8646
  setError(t("invalidCapacity").replace("{value}", raw));
8569
8647
  return;
@@ -8574,7 +8652,7 @@ window.__ModuleLoader__.load({
8574
8652
  setStatus(await post$2("/settings", { contextWindowOverrides: { [modelId]: parsed } }));
8575
8653
  setContextDrafts((previous) => ({
8576
8654
  ...previous,
8577
- [modelId]: formatCapacity(parsed)
8655
+ [modelId]: formatCapacity$1(parsed)
8578
8656
  }));
8579
8657
  onModelChange?.();
8580
8658
  } catch (cause) {
@@ -8592,7 +8670,7 @@ window.__ModuleLoader__.load({
8592
8670
  const model = updated.models.find((entry) => entry.id === modelId);
8593
8671
  if (model !== void 0) setContextDrafts((previous) => ({
8594
8672
  ...previous,
8595
- [modelId]: formatCapacity(model.defaultContextWindow)
8673
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
8596
8674
  }));
8597
8675
  onModelChange?.();
8598
8676
  } catch (cause) {
@@ -8859,7 +8937,7 @@ window.__ModuleLoader__.load({
8859
8937
  }),
8860
8938
  login.expiresAt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8861
8939
  className: "dsha-muted",
8862
- children: t.loginExpiresAt.replace("{time}", formatDate(login.expiresAt))
8940
+ children: t.loginExpiresAt.replace("{time}", formatDate$1(login.expiresAt))
8863
8941
  })
8864
8942
  ] }),
8865
8943
  login.status === "complete" && !authenticated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -8871,7 +8949,7 @@ window.__ModuleLoader__.load({
8871
8949
  children: [t.loginComplete, login.email !== void 0 && login.email !== "" ? ` ${login.email}` : ""]
8872
8950
  }), login.completedAt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8873
8951
  className: "dsha-muted",
8874
- children: t.loginCompletedAt.replace("{time}", formatDate(login.completedAt))
8952
+ children: t.loginCompletedAt.replace("{time}", formatDate$1(login.completedAt))
8875
8953
  })] }),
8876
8954
  login.status === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8877
8955
  className: "dsha-error",
@@ -9031,7 +9109,7 @@ window.__ModuleLoader__.load({
9031
9109
  id: model.id,
9032
9110
  name: model.name,
9033
9111
  draft: contextDrafts[model.id] ?? "",
9034
- meta: model.defaultContextWindow < model.contextWindow ? formatCapacity(model.contextWindow) : void 0,
9112
+ meta: model.defaultContextWindow < model.contextWindow ? formatCapacity$1(model.contextWindow) : void 0,
9035
9113
  inputLabel: `${model.name} ${t.contextWindowSection}`,
9036
9114
  hasOverride: status?.contextWindowOverrides[model.id] !== void 0,
9037
9115
  saving: savingModel === model.id
@@ -9120,7 +9198,7 @@ window.__ModuleLoader__.load({
9120
9198
  children: t.quotaRenews
9121
9199
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9122
9200
  className: "dsha-value",
9123
- children: formatDate(quota.renewsAt)
9201
+ children: formatDate$1(quota.renewsAt)
9124
9202
  })]
9125
9203
  }),
9126
9204
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -9130,7 +9208,7 @@ window.__ModuleLoader__.load({
9130
9208
  children: t.quotaReadAt
9131
9209
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9132
9210
  className: "dsha-value",
9133
- children: formatDate(quota.fetchedAt)
9211
+ children: formatDate$1(quota.fetchedAt)
9134
9212
  })]
9135
9213
  }),
9136
9214
  quota.sources.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -9764,7 +9842,7 @@ window.__ModuleLoader__.load({
9764
9842
  };
9765
9843
  const saveContextWindow = async (modelId) => {
9766
9844
  const raw = contextDrafts[modelId] || "";
9767
- const parsed = parsePositiveCapacity(raw);
9845
+ const parsed = parsePositiveCapacity$1(raw);
9768
9846
  if (parsed === null) {
9769
9847
  setError(t.contextWindowInvalid.replace("{value}", raw));
9770
9848
  return;
@@ -9779,7 +9857,7 @@ window.__ModuleLoader__.load({
9779
9857
  setStatus(updated);
9780
9858
  setContextDrafts((prev) => ({
9781
9859
  ...prev,
9782
- [modelId]: formatCapacity(parsed)
9860
+ [modelId]: formatCapacity$1(parsed)
9783
9861
  }));
9784
9862
  notifyChange();
9785
9863
  } catch (err) {
@@ -9808,7 +9886,7 @@ window.__ModuleLoader__.load({
9808
9886
  const model = updated.models.find((candidate) => candidate.id === modelId);
9809
9887
  return model === void 0 ? prev : {
9810
9888
  ...prev,
9811
- [modelId]: formatCapacity(model.defaultContextWindow)
9889
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
9812
9890
  };
9813
9891
  });
9814
9892
  notifyChange();
@@ -10264,7 +10342,7 @@ window.__ModuleLoader__.load({
10264
10342
  id: model.id,
10265
10343
  name: model.name,
10266
10344
  draft: contextDrafts[model.id] ?? "",
10267
- meta: model.defaultContextWindow < model.contextWindow ? formatCapacity(model.contextWindow) : void 0,
10345
+ meta: model.defaultContextWindow < model.contextWindow ? formatCapacity$1(model.contextWindow) : void 0,
10268
10346
  inputLabel: `${model.name} context window`,
10269
10347
  hasOverride: status?.contextWindowOverrides[model.id] !== void 0,
10270
10348
  saving: savingModel === model.id
@@ -10384,7 +10462,7 @@ window.__ModuleLoader__.load({
10384
10462
  }),
10385
10463
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
10386
10464
  className: "dsha-timestamp",
10387
- children: quota.fetchedAt === null ? t.observedAt.replace("{time}", formatDate(quota.observedAt)) : t.updatedAt.replace("{time}", formatDate(quota.fetchedAt))
10465
+ children: quota.fetchedAt === null ? t.observedAt.replace("{time}", formatDate$1(quota.observedAt)) : t.updatedAt.replace("{time}", formatDate$1(quota.fetchedAt))
10388
10466
  })
10389
10467
  ]
10390
10468
  })
@@ -11476,6 +11554,9 @@ window.__ModuleLoader__.load({
11476
11554
  deleteAccount: t("deleteAccount"),
11477
11555
  cooling: t("cooling"),
11478
11556
  cooldownLeft: t("cooldownLeft"),
11557
+ cooldownRemaining: t("cooldownRemaining"),
11558
+ cooldownRemainingSeconds: t("cooldownRemainingSeconds"),
11559
+ modelCooldown: t("modelCooldown"),
11479
11560
  clearCooldown: t("clearCooldown"),
11480
11561
  needsRelogin: t("needsRelogin"),
11481
11562
  relogin: t("relogin"),
@@ -11790,7 +11871,7 @@ window.__ModuleLoader__.load({
11790
11871
  };
11791
11872
  const saveContextWindow = async (modelId) => {
11792
11873
  const raw = contextDrafts[modelId] ?? "";
11793
- const parsed = parsePositiveCapacity(raw);
11874
+ const parsed = parsePositiveCapacity$1(raw);
11794
11875
  if (parsed === null) {
11795
11876
  setError(t("invalidCapacity").replace("{value}", raw));
11796
11877
  return;
@@ -11801,7 +11882,7 @@ window.__ModuleLoader__.load({
11801
11882
  setStatus(await post("/settings", { contextWindowOverrides: { [modelId]: parsed } }));
11802
11883
  setContextDrafts((previous) => ({
11803
11884
  ...previous,
11804
- [modelId]: formatCapacity(parsed)
11885
+ [modelId]: formatCapacity$1(parsed)
11805
11886
  }));
11806
11887
  onModelChange?.();
11807
11888
  } catch (cause) {
@@ -11819,7 +11900,7 @@ window.__ModuleLoader__.load({
11819
11900
  const model = updated.models.find((entry) => entry.id === modelId);
11820
11901
  if (model !== void 0) setContextDrafts((previous) => ({
11821
11902
  ...previous,
11822
- [modelId]: formatCapacity(model.defaultContextWindow)
11903
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
11823
11904
  }));
11824
11905
  onModelChange?.();
11825
11906
  } catch (cause) {
@@ -12132,7 +12213,7 @@ window.__ModuleLoader__.load({
12132
12213
  }),
12133
12214
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12134
12215
  className: "dshsc-quota-meta",
12135
- children: window.resetsAt !== null && window.resetsAt > 0 ? `${t.quotaResets} ${formatDate(window.resetsAt)}` : t.quotaNoReset
12216
+ children: window.resetsAt !== null && window.resetsAt > 0 ? `${t.quotaResets} ${formatDate$1(window.resetsAt)}` : t.quotaNoReset
12136
12217
  })
12137
12218
  ]
12138
12219
  }, `${window.key}:${index}`);
@@ -12283,7 +12364,7 @@ window.__ModuleLoader__.load({
12283
12364
  }),
12284
12365
  login.expiresAt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
12285
12366
  className: "dsha-muted",
12286
- children: t.loginExpiresAt.replace("{time}", formatDate(login.expiresAt))
12367
+ children: t.loginExpiresAt.replace("{time}", formatDate$1(login.expiresAt))
12287
12368
  })
12288
12369
  ] }),
12289
12370
  login.status === "complete" && !authenticated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -12295,7 +12376,7 @@ window.__ModuleLoader__.load({
12295
12376
  children: [t.loginComplete, login.uid !== void 0 && login.uid !== "" ? ` ${login.uid}` : ""]
12296
12377
  }), login.completedAt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
12297
12378
  className: "dsha-muted",
12298
- children: t.loginCompletedAt.replace("{time}", formatDate(login.completedAt))
12379
+ children: t.loginCompletedAt.replace("{time}", formatDate$1(login.completedAt))
12299
12380
  })] }),
12300
12381
  login.status === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
12301
12382
  className: "dsha-error",
@@ -12590,7 +12671,7 @@ window.__ModuleLoader__.load({
12590
12671
  id: model.id,
12591
12672
  name: model.name,
12592
12673
  draft: contextDrafts[model.id] ?? "",
12593
- meta: model.defaultContextWindow < model.contextWindow ? formatCapacity(model.contextWindow) : void 0,
12674
+ meta: model.defaultContextWindow < model.contextWindow ? formatCapacity$1(model.contextWindow) : void 0,
12594
12675
  inputLabel: `${model.name} ${t.contextWindowSection}`,
12595
12676
  hasOverride: status?.contextWindowOverrides[model.id] !== void 0,
12596
12677
  saving: savingModel === model.id
@@ -12656,11 +12737,11 @@ window.__ModuleLoader__.load({
12656
12737
  children: [
12657
12738
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
12658
12739
  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) })]
12740
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.quotaRenews }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatDate$1(quota.renewsAt) })]
12660
12741
  }),
12661
12742
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
12662
12743
  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) })]
12744
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.quotaReadAt }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatDate$1(quota.fetchedAt) })]
12664
12745
  }),
12665
12746
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
12666
12747
  className: "dshsc-fact",
@@ -12700,7 +12781,7 @@ window.__ModuleLoader__.load({
12700
12781
  children: [
12701
12782
  t.quotaBucketExpires,
12702
12783
  ": ",
12703
- formatDate(bucket.expiresAt)
12784
+ formatDate$1(bucket.expiresAt)
12704
12785
  ]
12705
12786
  }),
12706
12787
  bucket.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -12708,7 +12789,7 @@ window.__ModuleLoader__.load({
12708
12789
  children: [
12709
12790
  t.quotaBucketResets,
12710
12791
  ": ",
12711
- formatDate(bucket.resetsAt)
12792
+ formatDate$1(bucket.resetsAt)
12712
12793
  ]
12713
12794
  })
12714
12795
  ]
@@ -12770,7 +12851,7 @@ window.__ModuleLoader__.load({
12770
12851
  children: t.quotaCredentialExpires
12771
12852
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
12772
12853
  className: "dsha-value",
12773
- children: formatDate(quotaCredential.expiresAt)
12854
+ children: formatDate$1(quotaCredential.expiresAt)
12774
12855
  })]
12775
12856
  }),
12776
12857
  quotaCredential.error !== void 0 && quotaCredential.error !== null && quotaCredential.error !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -13898,6 +13979,14 @@ window.__ModuleLoader__.load({
13898
13979
  .dsha-account-quota-row[data-level=danger] .dsha-account-quota-fill{background:var(--dsw-alias-label-danger,#d94b4b)}
13899
13980
  .dsha-account-quota-value{color:var(--dsw-alias-label-primary);flex:none;font-variant-numeric:tabular-nums;min-width:40px;text-align:right}
13900
13981
  .dsha-account-quota-meta{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;font-variant-numeric:tabular-nums}
13982
+ /* Models parked on one account. A model park is not the account's own
13983
+ cooldown - the account keeps serving every other model it has - so the row
13984
+ names the model and gives that park a countdown of its own. */
13985
+ .dsha-account-model-cooldowns{display:flex;flex-direction:column;gap:4px;margin-top:9px}
13986
+ .dsha-account-model-cooldown-row{align-items:center;display:flex;font-size:12px;gap:8px}
13987
+ .dsha-account-model-cooldown-tag{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px}
13988
+ .dsha-account-model-cooldown-name{color:var(--dsw-alias-label-secondary);flex:none;max-width:38%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
13989
+ .dsha-account-model-cooldown-time{color:var(--dsw-alias-label-primary);flex:none;font-variant-numeric:tabular-nums}
13901
13990
  @media(max-width:560px){.dsha-account-quota-meta{display:none}}
13902
13991
  `, POOL_STYLE_ID);
13903
13992
  }
@@ -16122,7 +16211,7 @@ window.__ModuleLoader__.load({
16122
16211
  const [failure, setFailure] = (0, react.useState)(void 0);
16123
16212
  const value = snapshot.value ?? {};
16124
16213
  const writable = settings !== void 0 && snapshot.status === "ready" && snapshot.writable;
16125
- const enabled = value.progressUpdates === true;
16214
+ const enabled = value.progressUpdates !== false;
16126
16215
  const threshold = typeof value.progressUpdatesNudgeThreshold === "number" ? value.progressUpdatesNudgeThreshold : 8;
16127
16216
  const [draft, setDraft] = (0, react.useState)(() => String(threshold));
16128
16217
  (0, react.useEffect)(() => {
@@ -16750,15 +16839,23 @@ window.__ModuleLoader__.load({
16750
16839
  * 设置表单通道。
16751
16840
  *
16752
16841
  * 调用方给了就用它;否则从 `ctx.configForms` 现取一份,并登记到本插件的 effect
16753
- * 上(插件卸载时释放镜像订阅)。服务缺席时是 undefined——卡片据此渲染成只读。
16842
+ * 上(插件卸载时释放镜像订阅)。若 `configForms` 晚于本插件挂载,设置页渲染时
16843
+ * 再次按需获取;服务始终缺席时是 undefined——卡片据此渲染成只读。
16754
16844
  */
16755
- const settings = options.settings ?? (() => {
16845
+ let settings = options.settings;
16846
+ const resolveSettings = () => {
16847
+ if (settings !== void 0) return settings;
16756
16848
  const form = createProgressSettingsForm(ctx);
16757
- if (form !== void 0) ctx.effect(() => () => {
16758
- form.dispose();
16759
- }, "dsh-progress-updates: settings form");
16760
- return form;
16761
- })();
16849
+ if (form !== void 0) {
16850
+ settings = form;
16851
+ ctx.effect(() => () => {
16852
+ form.dispose();
16853
+ if (settings === form) settings = void 0;
16854
+ }, "dsh-progress-updates: settings form");
16855
+ }
16856
+ return settings;
16857
+ };
16858
+ resolveSettings();
16762
16859
  ctx.effect(() => () => {
16763
16860
  for (const source of hostSources.values()) try {
16764
16861
  source.stop();
@@ -16766,13 +16863,32 @@ window.__ModuleLoader__.load({
16766
16863
  hostSources.clear();
16767
16864
  }, "dsh-progress-updates: poll lifecycle");
16768
16865
  /**
16866
+ * 取侧栏页签类型注册表。
16867
+ *
16868
+ * 属性读只在服务名确实在当前 scope 的 inject 名单里时合法——本插件自己的
16869
+ * 静态 `inject` 没有 `sidebarRightTabs`,属性读会被 Cordis 拒绝,所以先试
16870
+ * 属性、失败再退回 `get()`(服务缺席时按缺失处理)。
16871
+ *
16872
+ * @param scope - 浏览器根上下文,或 `ctx.inject(['sidebarRightTabs'], ...)` 交来的 scope。
16873
+ * @returns 注册表实例,或 undefined。
16874
+ */
16875
+ const tabsOf = (scope) => {
16876
+ try {
16877
+ const direct = scope.sidebarRightTabs;
16878
+ if (direct !== void 0) return direct;
16879
+ } catch {}
16880
+ return serviceOf(scope, "sidebarRightTabs");
16881
+ };
16882
+ /**
16769
16883
  * 阶段一:声明页签**类型**。
16770
16884
  *
16771
16885
  * 这一步是面板能打开的前提。`patterns` 省略 = 页面型页签,按 kind 打开。
16772
- * 服务不存在(没装 ui-sidebar-right)时整段跳过:对话流行与设置页照常挂上。
16886
+ * 服务不存在(没装 ui-sidebar-right)时整段跳过:对话流行与设置页照常挂上;
16887
+ * 若 `sidebarRightTabs` 晚于本插件挂载,通过 `ctx.inject(['sidebarRightTabs'], ...)`
16888
+ * 在服务就绪时自动补注册。
16773
16889
  */
16774
- ctx.effect(() => {
16775
- const tabs = serviceOf(ctx, "sidebarRightTabs");
16890
+ const registerTabDefinition = (targetCtx) => {
16891
+ const tabs = tabsOf(targetCtx);
16776
16892
  if (typeof tabs?.register !== "function") return () => {};
16777
16893
  try {
16778
16894
  const definition = {
@@ -16809,7 +16925,13 @@ window.__ModuleLoader__.load({
16809
16925
  } catch {
16810
16926
  return () => {};
16811
16927
  }
16812
- }, "dsh-progress-updates: tab type");
16928
+ };
16929
+ const immediateTabs = tabsOf(ctx);
16930
+ const injectService = ctx.inject;
16931
+ if (typeof immediateTabs?.register === "function" || typeof injectService !== "function") ctx.effect(() => registerTabDefinition(ctx), "dsh-progress-updates: tab type");
16932
+ else injectService.call(ctx, ["sidebarRightTabs"], (scope) => {
16933
+ scope.effect(() => registerTabDefinition(scope), "dsh-progress-updates: tab type");
16934
+ });
16813
16935
  /**
16814
16936
  * 对话流里的进展行:`progress_update` 每次调用渲染成一行。
16815
16937
  *
@@ -16871,9 +16993,12 @@ window.__ModuleLoader__.load({
16871
16993
  }
16872
16994
  },
16873
16995
  locale: NS_PROGRESS_UPDATES,
16874
- inject: () => settings === void 0 ? { openPanel } : {
16875
- openPanel,
16876
- settings
16996
+ inject: () => {
16997
+ const currentSettings = resolveSettings();
16998
+ return currentSettings === void 0 ? { openPanel } : {
16999
+ openPanel,
17000
+ settings: currentSettings
17001
+ };
16877
17002
  }
16878
17003
  }, ProgressUpdatesSettingsSection);
16879
17004
  } catch {