@eddyskywalker/dsh-chatgpt-subscription 0.8.1 → 0.8.3

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 (97) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/README.md +66 -1
  3. package/lib/client.js +1580 -287
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +5432 -1757
  6. package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
  7. package/lib/types/client/ProviderHubSection.d.ts.map +1 -1
  8. package/lib/types/client/antigravity/AntigravitySection.d.ts.map +1 -1
  9. package/lib/types/client/antigravity/locales.d.ts +2 -2
  10. package/lib/types/client/command-code/CommandCodeSection.d.ts.map +1 -1
  11. package/lib/types/client/command-code/locales.d.ts +2 -2
  12. package/lib/types/client/common/quota-follow-up.d.ts +30 -0
  13. package/lib/types/client/common/quota-follow-up.d.ts.map +1 -0
  14. package/lib/types/client/index.d.ts +1 -0
  15. package/lib/types/client/index.d.ts.map +1 -1
  16. package/lib/types/client/kimi-code/KimiCodeSection.d.ts.map +1 -1
  17. package/lib/types/client/kimi-code/locales.d.ts +2 -2
  18. package/lib/types/client/locales.d.ts +1 -1
  19. package/lib/types/client/workbuddy/WorkBuddySection.d.ts.map +1 -1
  20. package/lib/types/client/workbuddy/locales.d.ts +60 -0
  21. package/lib/types/client/workbuddy/locales.d.ts.map +1 -1
  22. package/lib/types/client/zhipu/ZhipuComposerQuota.d.ts +26 -0
  23. package/lib/types/client/zhipu/ZhipuComposerQuota.d.ts.map +1 -0
  24. package/lib/types/client/zhipu/ZhipuSection.d.ts +11 -0
  25. package/lib/types/client/zhipu/ZhipuSection.d.ts.map +1 -0
  26. package/lib/types/client/zhipu/locales.d.ts +275 -0
  27. package/lib/types/client/zhipu/locales.d.ts.map +1 -0
  28. package/lib/types/client/zhipu/styles.d.ts +12 -0
  29. package/lib/types/client/zhipu/styles.d.ts.map +1 -0
  30. package/lib/types/host/antigravity/oauth.d.ts +15 -1
  31. package/lib/types/host/antigravity/oauth.d.ts.map +1 -1
  32. package/lib/types/host/antigravity/port-constants.d.ts +20 -0
  33. package/lib/types/host/antigravity/port-constants.d.ts.map +1 -0
  34. package/lib/types/host/antigravity/routes.d.ts.map +1 -1
  35. package/lib/types/host/command-code/client.d.ts +9 -1
  36. package/lib/types/host/command-code/client.d.ts.map +1 -1
  37. package/lib/types/host/command-code/routes.d.ts.map +1 -1
  38. package/lib/types/host/common/catalog-snapshot.d.ts +61 -0
  39. package/lib/types/host/common/catalog-snapshot.d.ts.map +1 -0
  40. package/lib/types/host/common/credential-read-cache.d.ts +73 -0
  41. package/lib/types/host/common/credential-read-cache.d.ts.map +1 -0
  42. package/lib/types/host/common/quota-refresh.d.ts +35 -0
  43. package/lib/types/host/common/quota-refresh.d.ts.map +1 -0
  44. package/lib/types/host/common/same-origin.d.ts +30 -0
  45. package/lib/types/host/common/same-origin.d.ts.map +1 -0
  46. package/lib/types/host/credential-store-secret-service.d.ts +1 -0
  47. package/lib/types/host/credential-store-secret-service.d.ts.map +1 -1
  48. package/lib/types/host/kimi-code/client.d.ts.map +1 -1
  49. package/lib/types/host/kimi-code/routes.d.ts.map +1 -1
  50. package/lib/types/host/routes.d.ts.map +1 -1
  51. package/lib/types/host/token-store-macos.d.ts +9 -0
  52. package/lib/types/host/token-store-macos.d.ts.map +1 -1
  53. package/lib/types/host/token-store-windows.d.ts +8 -0
  54. package/lib/types/host/token-store-windows.d.ts.map +1 -1
  55. package/lib/types/host/usage-service.d.ts +19 -1
  56. package/lib/types/host/usage-service.d.ts.map +1 -1
  57. package/lib/types/host/workbuddy/checkin.d.ts +134 -0
  58. package/lib/types/host/workbuddy/checkin.d.ts.map +1 -0
  59. package/lib/types/host/workbuddy/client.d.ts +9 -1
  60. package/lib/types/host/workbuddy/client.d.ts.map +1 -1
  61. package/lib/types/host/workbuddy/routes.d.ts +3 -0
  62. package/lib/types/host/workbuddy/routes.d.ts.map +1 -1
  63. package/lib/types/host/workbuddy/token-store.d.ts +24 -1
  64. package/lib/types/host/workbuddy/token-store.d.ts.map +1 -1
  65. package/lib/types/host/zhipu/account-pool.d.ts +43 -0
  66. package/lib/types/host/zhipu/account-pool.d.ts.map +1 -0
  67. package/lib/types/host/zhipu/adapter.d.ts +93 -0
  68. package/lib/types/host/zhipu/adapter.d.ts.map +1 -0
  69. package/lib/types/host/zhipu/client.d.ts +153 -0
  70. package/lib/types/host/zhipu/client.d.ts.map +1 -0
  71. package/lib/types/host/zhipu/mapper.d.ts +111 -0
  72. package/lib/types/host/zhipu/mapper.d.ts.map +1 -0
  73. package/lib/types/host/zhipu/model-catalog.d.ts +73 -0
  74. package/lib/types/host/zhipu/model-catalog.d.ts.map +1 -0
  75. package/lib/types/host/zhipu/routes.d.ts +33 -0
  76. package/lib/types/host/zhipu/routes.d.ts.map +1 -0
  77. package/lib/types/host/zhipu/token-store.d.ts +112 -0
  78. package/lib/types/host/zhipu/token-store.d.ts.map +1 -0
  79. package/lib/types/host/zhipu/types.d.ts +125 -0
  80. package/lib/types/host/zhipu/types.d.ts.map +1 -0
  81. package/lib/types/index.d.ts +8 -0
  82. package/lib/types/index.d.ts.map +1 -1
  83. package/lib/types/shared/antigravity-contracts.d.ts +8 -0
  84. package/lib/types/shared/antigravity-contracts.d.ts.map +1 -1
  85. package/lib/types/shared/command-code-contracts.d.ts +8 -0
  86. package/lib/types/shared/command-code-contracts.d.ts.map +1 -1
  87. package/lib/types/shared/contracts.d.ts +8 -0
  88. package/lib/types/shared/contracts.d.ts.map +1 -1
  89. package/lib/types/shared/kimi-code-contracts.d.ts +8 -0
  90. package/lib/types/shared/kimi-code-contracts.d.ts.map +1 -1
  91. package/lib/types/shared/workbuddy-contracts.d.ts +48 -0
  92. package/lib/types/shared/workbuddy-contracts.d.ts.map +1 -1
  93. package/lib/types/shared/zhipu-contracts.d.ts +164 -0
  94. package/lib/types/shared/zhipu-contracts.d.ts.map +1 -0
  95. package/package.json +32 -33
  96. package/lib/types/host/compaction-patch.d.ts +0 -17
  97. package/lib/types/host/compaction-patch.d.ts.map +0 -1
package/lib/client.js CHANGED
@@ -56,7 +56,7 @@ window.__ModuleLoader__.load({
56
56
  //#endregion
57
57
  //#region src/client/CodexComposerQuota.tsx
58
58
  function CodexComposerQuota({ api, directory, loadModelDirectory, t }) {
59
- const modelState = useStore$4(directory);
59
+ const modelState = useStore$5(directory);
60
60
  const [status, setStatus] = (0, react.useState)(null);
61
61
  const [loading, setLoading] = (0, react.useState)(false);
62
62
  const mountedRef = (0, react.useRef)(false);
@@ -103,7 +103,7 @@ window.__ModuleLoader__.load({
103
103
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("quickQuotaLabel") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: quota === null ? loading ? t("quickQuotaLoading") : "—" : formatPercent$1(quota.remainingPercent) })]
104
104
  });
105
105
  }
106
- function useStore$4(store) {
106
+ function useStore$5(store) {
107
107
  return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
108
108
  }
109
109
  function formatPercent$1(value) {
@@ -179,7 +179,7 @@ window.__ModuleLoader__.load({
179
179
  });
180
180
  }
181
181
  function promptFromBlock(block) {
182
- const raw = "kind" in block ? block.call?.argsRaw : block.argsRaw;
182
+ const raw = "kind" in block ? block.call?.argsRaw : dispatchedArgsRaw(block);
183
183
  if (typeof raw !== "string" || raw.trim() === "") return null;
184
184
  try {
185
185
  const value = JSON.parse(raw);
@@ -188,6 +188,16 @@ window.__ModuleLoader__.load({
188
188
  return null;
189
189
  }
190
190
  }
191
+ /**
192
+ * Arguments of a dispatched call that has no result yet.
193
+ *
194
+ * Harness 0.1.7-rc.1 dispatches a view as soon as its call starts *preparing*,
195
+ * before the arguments exist, so the preparing shape carries no `argsRaw` at
196
+ * all. Older generations only ever sent the dispatched shape.
197
+ */
198
+ function dispatchedArgsRaw(block) {
199
+ return "argsRaw" in block ? block.argsRaw : void 0;
200
+ }
191
201
  function imageBlocks(blocks) {
192
202
  const result = [];
193
203
  for (const block of blocks) {
@@ -668,10 +678,55 @@ window.__ModuleLoader__.load({
668
678
  });
669
679
  }
670
680
  //#endregion
681
+ //#region src/client/common/quota-follow-up.ts
682
+ /**
683
+ * One follow-up poll after a status answer that carried a background refresh.
684
+ *
685
+ * The host answers a status card from the snapshot it already has and refreshes
686
+ * the quota behind that answer, so a tab renders immediately instead of waiting
687
+ * on the upstream request. The refreshed numbers would otherwise only appear on
688
+ * the next 60 s poll, so an answer that reports a refresh in flight schedules
689
+ * one short follow-up.
690
+ *
691
+ * The chain is bounded. A refresh that keeps failing leaves the snapshot aged,
692
+ * so every answer would keep asking for a follow-up; after a few consecutive
693
+ * attempts the surface falls back to its ordinary polling and stops hammering
694
+ * the host.
695
+ */
696
+ const FOLLOW_UP_DELAY_MS = 1500;
697
+ const MAX_ATTEMPTS = 3;
698
+ function createQuotaFollowUp(options = {}) {
699
+ const delayMs = options.delayMs ?? FOLLOW_UP_DELAY_MS;
700
+ const maxAttempts = options.maxAttempts ?? MAX_ATTEMPTS;
701
+ let attempts = 0;
702
+ let timer;
703
+ return {
704
+ observe(refreshing, reload) {
705
+ if (!refreshing) {
706
+ attempts = 0;
707
+ return;
708
+ }
709
+ if (timer !== void 0 || attempts >= maxAttempts) return;
710
+ attempts += 1;
711
+ timer = setTimeout(() => {
712
+ timer = void 0;
713
+ reload();
714
+ }, delayMs);
715
+ },
716
+ cancel() {
717
+ if (timer !== void 0) clearTimeout(timer);
718
+ timer = void 0;
719
+ attempts = 0;
720
+ }
721
+ };
722
+ }
723
+ //#endregion
671
724
  //#region src/client/CodexSubscriptionSection.tsx
672
725
  function CodexSubscriptionSection({ t }) {
673
726
  const apiRef = (0, react.useRef)(new SubscriptionApi());
674
727
  const eventSourceRef = (0, react.useRef)(null);
728
+ /** Follow-up poll owed while the host refreshes the quota behind an answer. */
729
+ const quotaFollowUp = (0, react.useRef)(null);
675
730
  const [status, setStatus] = (0, react.useState)(null);
676
731
  const [busy, setBusy] = (0, react.useState)(null);
677
732
  const [error, setError] = (0, react.useState)(null);
@@ -687,6 +742,10 @@ window.__ModuleLoader__.load({
687
742
  const next = await apiRef.current.status();
688
743
  setStatus(next);
689
744
  if (next.error !== void 0) setError(next.error.message);
745
+ quotaFollowUp.current ??= createQuotaFollowUp();
746
+ quotaFollowUp.current.observe(next.quotaRefreshing === true, () => {
747
+ load(true);
748
+ });
690
749
  } catch (cause) {
691
750
  if (!quiet) setError(messageOf(cause));
692
751
  }
@@ -701,6 +760,7 @@ window.__ModuleLoader__.load({
701
760
  return () => {
702
761
  window.clearInterval(timer);
703
762
  document.removeEventListener("visibilitychange", refreshWhenVisible);
763
+ quotaFollowUp.current?.cancel();
704
764
  eventSourceRef.current?.close();
705
765
  };
706
766
  }, [load]);
@@ -839,7 +899,7 @@ window.__ModuleLoader__.load({
839
899
  await updatePreferences({ contextWindowOverrides: { [model]: null } });
840
900
  setContextDrafts((drafts) => ({
841
901
  ...drafts,
842
- [model]: formatCapacity$4(resolveCodexCatalogEntry(model).contextWindow)
902
+ [model]: formatCapacity$5(resolveCodexCatalogEntry(model).contextWindow)
843
903
  }));
844
904
  };
845
905
  /** Clear every stored override, including models the picker no longer shows. */
@@ -1053,7 +1113,7 @@ window.__ModuleLoader__.load({
1053
1113
  }),
1054
1114
  connection !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoRow, {
1055
1115
  label: t("latency"),
1056
- value: `${connection.latencyMs} ms · ${formatDate$3(connection.checkedAt)}`
1116
+ value: `${connection.latencyMs} ms · ${formatDate$4(connection.checkedAt)}`
1057
1117
  }) : null,
1058
1118
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1059
1119
  className: "dsha-muted dsha-models-hint",
@@ -1333,7 +1393,7 @@ window.__ModuleLoader__.load({
1333
1393
  id: inputId,
1334
1394
  type: "text",
1335
1395
  inputMode: "numeric",
1336
- value: draft ?? formatCapacity$4(fallback),
1396
+ value: draft ?? formatCapacity$5(fallback),
1337
1397
  disabled: busy !== null,
1338
1398
  "aria-label": entry.name + " " + t("contextWindow"),
1339
1399
  onChange: (event) => {
@@ -1465,7 +1525,7 @@ window.__ModuleLoader__.load({
1465
1525
  children: [
1466
1526
  t("updated"),
1467
1527
  ": ",
1468
- formatDate$3(quota.fetchedAt)
1528
+ formatDate$4(quota.fetchedAt)
1469
1529
  ]
1470
1530
  }) : null
1471
1531
  ]
@@ -1557,7 +1617,7 @@ window.__ModuleLoader__.load({
1557
1617
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("small", { children: [
1558
1618
  t("resetCreditExpires"),
1559
1619
  ": ",
1560
- resetCredits.expiresAt == null ? t("unknown") : formatReset$3(resetCredits.expiresAt)
1620
+ resetCredits.expiresAt == null ? t("unknown") : formatReset$4(resetCredits.expiresAt)
1561
1621
  ] })
1562
1622
  ]
1563
1623
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
@@ -1590,7 +1650,7 @@ window.__ModuleLoader__.load({
1590
1650
  }),
1591
1651
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1592
1652
  className: "dsh-codex-meter-meta",
1593
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: percent >= 100 ? `${t("exhausted")} · ${formatPercent(remaining)} ${t("remaining")}` : `${formatPercent(percent)} ${t("used")} · ${formatPercent(remaining)} ${t("remaining")}` }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: window?.resetsAt == null ? "—" : `${t("resets")}: ${formatReset$3(window.resetsAt)}` })]
1653
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: percent >= 100 ? `${t("exhausted")} · ${formatPercent(remaining)} ${t("remaining")}` : `${formatPercent(percent)} ${t("used")} · ${formatPercent(remaining)} ${t("remaining")}` }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: window?.resetsAt == null ? "—" : `${t("resets")}: ${formatReset$4(window.resetsAt)}` })]
1594
1654
  })
1595
1655
  ]
1596
1656
  });
@@ -1616,7 +1676,7 @@ window.__ModuleLoader__.load({
1616
1676
  return `${value} ${t("limitWindow")}`;
1617
1677
  }
1618
1678
  }
1619
- function parsePositiveCapacity$4(value) {
1679
+ function parsePositiveCapacity$5(value) {
1620
1680
  const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
1621
1681
  if (matched === null) return null;
1622
1682
  const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
@@ -1624,10 +1684,10 @@ window.__ModuleLoader__.load({
1624
1684
  return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
1625
1685
  }
1626
1686
  function parseCapacity(value, maxContextWindow = GPT_56_MAX_CONTEXT_WINDOW) {
1627
- const parsed = parsePositiveCapacity$4(value);
1687
+ const parsed = parsePositiveCapacity$5(value);
1628
1688
  return parsed !== null && parsed <= maxContextWindow ? parsed : null;
1629
1689
  }
1630
- function formatCapacity$4(value) {
1690
+ function formatCapacity$5(value) {
1631
1691
  if (value % 1e3 === 0) return `${value / 1e3}K`;
1632
1692
  return String(value);
1633
1693
  }
@@ -1644,11 +1704,11 @@ window.__ModuleLoader__.load({
1644
1704
  limit.remainingPercent !== null && limit.remainingPercent !== void 0 ? `${formatPercent(limit.remainingPercent)} ${t("remaining")}` : null,
1645
1705
  limit.limit !== null && limit.limit !== void 0 ? `${t("limit")}: ${limit.limit}` : null,
1646
1706
  limit.used !== null && limit.used !== void 0 ? `${t("used")}: ${limit.used}` : null,
1647
- limit.resetsAt !== null && limit.resetsAt !== void 0 ? `${t("resets")}: ${formatReset$3(limit.resetsAt)}` : null
1707
+ limit.resetsAt !== null && limit.resetsAt !== void 0 ? `${t("resets")}: ${formatReset$4(limit.resetsAt)}` : null
1648
1708
  ].filter((part) => part !== null);
1649
1709
  return parts.length > 0 ? parts.join(" · ") : t("unknown");
1650
1710
  }
1651
- function formatDate$3(seconds) {
1711
+ function formatDate$4(seconds) {
1652
1712
  if (seconds === void 0 || seconds === null || typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) return "—";
1653
1713
  const ms = seconds > 1e10 ? seconds : seconds * 1e3;
1654
1714
  try {
@@ -1660,10 +1720,10 @@ window.__ModuleLoader__.load({
1660
1720
  return "—";
1661
1721
  }
1662
1722
  }
1663
- function formatReset$3(seconds) {
1723
+ function formatReset$4(seconds) {
1664
1724
  if (seconds === void 0 || seconds === null || typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) return "—";
1665
1725
  const ms = seconds > 1e10 ? seconds : seconds * 1e3;
1666
- const absolute = formatDate$3(seconds);
1726
+ const absolute = formatDate$4(seconds);
1667
1727
  const diff = ms - Date.now();
1668
1728
  const abs = Math.abs(diff);
1669
1729
  const [amount, unit] = abs >= 864e5 ? [Math.round(diff / 864e5), "day"] : abs >= 36e5 ? [Math.round(diff / 36e5), "hour"] : [Math.round(diff / 6e4), "minute"];
@@ -1679,7 +1739,7 @@ window.__ModuleLoader__.load({
1679
1739
  //#endregion
1680
1740
  //#region src/client/antigravity/locales.ts
1681
1741
  const NS_ANTIGRAVITY = "dsh-antigravity";
1682
- const zh$4 = {
1742
+ const zh$5 = {
1683
1743
  ...accountPoolZh,
1684
1744
  title: "Antigravity",
1685
1745
  pageDesc: "登录 Google Antigravity / Cloud Code Assist,并查看当前账号的共享额度。",
@@ -1749,7 +1809,7 @@ window.__ModuleLoader__.load({
1749
1809
  loginFailed: "登录失败",
1750
1810
  tokens: "tokens"
1751
1811
  };
1752
- const en$4 = {
1812
+ const en$5 = {
1753
1813
  ...accountPoolEn,
1754
1814
  title: "Antigravity",
1755
1815
  pageDesc: "Sign in to Google Antigravity / Cloud Code Assist and view shared quotas.",
@@ -1819,17 +1879,17 @@ window.__ModuleLoader__.load({
1819
1879
  loginFailed: "Login failed",
1820
1880
  tokens: "tokens"
1821
1881
  };
1822
- const dictionaries$4 = {
1823
- zh: zh$4,
1824
- "zh-CN": zh$4,
1825
- en: en$4,
1826
- "en-US": en$4
1882
+ const dictionaries$5 = {
1883
+ zh: zh$5,
1884
+ "zh-CN": zh$5,
1885
+ en: en$5,
1886
+ "en-US": en$5
1827
1887
  };
1828
1888
  //#endregion
1829
1889
  //#region src/client/antigravity/AntigravitySection.tsx
1830
- const API$7 = "/antigravity/api";
1831
- async function fetchApi$7(path, options) {
1832
- const res = await fetch(`${API$7}${path}`, {
1890
+ const API$9 = "/antigravity/api";
1891
+ async function fetchApi$9(path, options) {
1892
+ const res = await fetch(`${API$9}${path}`, {
1833
1893
  ...options,
1834
1894
  headers: {
1835
1895
  "Content-Type": "application/json",
@@ -1840,14 +1900,14 @@ window.__ModuleLoader__.load({
1840
1900
  if (!res.ok || !json.ok) throw new Error(json.error || `HTTP ${res.status}`);
1841
1901
  return json.value;
1842
1902
  }
1843
- function parsePositiveCapacity$3(value) {
1903
+ function parsePositiveCapacity$4(value) {
1844
1904
  const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
1845
1905
  if (matched === null) return null;
1846
1906
  const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
1847
1907
  const parsed = Number(matched[1]) * multiplier;
1848
1908
  return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
1849
1909
  }
1850
- function formatCapacity$3(value) {
1910
+ function formatCapacity$4(value) {
1851
1911
  if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
1852
1912
  if (value % 1e3 === 0) return `${value / 1e3}K`;
1853
1913
  return String(value);
@@ -1857,9 +1917,9 @@ window.__ModuleLoader__.load({
1857
1917
  * toggle: a model that was just enabled has no draft yet, and the context
1858
1918
  * window section only renders enabled models.
1859
1919
  */
1860
- function contextDraftsFor$3(status) {
1920
+ function contextDraftsFor$4(status) {
1861
1921
  const drafts = {};
1862
- for (const model of status.models) drafts[model.id] = formatCapacity$3(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
1922
+ for (const model of status.models) drafts[model.id] = formatCapacity$4(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
1863
1923
  return drafts;
1864
1924
  }
1865
1925
  function formatResetTime(resetTime) {
@@ -1873,7 +1933,7 @@ window.__ModuleLoader__.load({
1873
1933
  if (hours > 0) return `${hours}h ${mins % 60}m`;
1874
1934
  return `${mins}m`;
1875
1935
  }
1876
- function formatDate$2(ms) {
1936
+ function formatDate$3(ms) {
1877
1937
  if (!ms || ms <= 0) return "—";
1878
1938
  try {
1879
1939
  return new Intl.DateTimeFormat(void 0, {
@@ -1893,7 +1953,9 @@ window.__ModuleLoader__.load({
1893
1953
  const [loginProgress, setLoginProgress] = (0, react.useState)(null);
1894
1954
  const [contextDrafts, setContextDrafts] = (0, react.useState)({});
1895
1955
  const [savingModel, setSavingModel] = (0, react.useState)(null);
1896
- const t = zh$4;
1956
+ /** Follow-up poll owed while the host refreshes the quota behind an answer. */
1957
+ const quotaFollowUp = (0, react.useRef)(null);
1958
+ const t = zh$5;
1897
1959
  const notifyChange = (0, react.useCallback)(() => {
1898
1960
  onModelChange?.();
1899
1961
  loadModelDirectory?.();
@@ -1904,9 +1966,13 @@ window.__ModuleLoader__.load({
1904
1966
  setValidationUrl(null);
1905
1967
  }
1906
1968
  try {
1907
- const data = await fetchApi$7("/status");
1969
+ const data = await fetchApi$9("/status");
1908
1970
  setStatus(data);
1909
- setContextDrafts(contextDraftsFor$3(data));
1971
+ setContextDrafts(contextDraftsFor$4(data));
1972
+ quotaFollowUp.current ??= createQuotaFollowUp();
1973
+ quotaFollowUp.current.observe(data.quotaRefreshing === true, () => {
1974
+ loadStatus(true);
1975
+ });
1910
1976
  } catch (err) {
1911
1977
  if (!quiet) setError(err instanceof Error ? err.message : String(err));
1912
1978
  } finally {
@@ -1923,6 +1989,7 @@ window.__ModuleLoader__.load({
1923
1989
  return () => {
1924
1990
  window.clearInterval(timer);
1925
1991
  document.removeEventListener("visibilitychange", refreshWhenVisible);
1992
+ quotaFollowUp.current?.cancel();
1926
1993
  };
1927
1994
  }, [loadStatus]);
1928
1995
  const handleLogin = async () => {
@@ -1931,11 +1998,11 @@ window.__ModuleLoader__.load({
1931
1998
  setError(null);
1932
1999
  setValidationUrl(null);
1933
2000
  setLoginProgress(null);
1934
- const flow = await fetchApi$7("/login", { method: "POST" });
2001
+ const flow = await fetchApi$9("/login", { method: "POST" });
1935
2002
  if (flow.authUrl) window.open(flow.authUrl, "_blank");
1936
2003
  const pollTimer = setInterval(async () => {
1937
2004
  try {
1938
- const pollStatus = await fetchApi$7("/login/status");
2005
+ const pollStatus = await fetchApi$9("/login/status");
1939
2006
  if (pollStatus.progress) setLoginProgress(pollStatus.progress);
1940
2007
  if (pollStatus.status === "complete") {
1941
2008
  clearInterval(pollTimer);
@@ -1967,7 +2034,7 @@ window.__ModuleLoader__.load({
1967
2034
  try {
1968
2035
  setBusy("quota");
1969
2036
  setError(null);
1970
- const updated = await fetchApi$7("/quota", { method: "POST" });
2037
+ const updated = await fetchApi$9("/quota", { method: "POST" });
1971
2038
  setStatus(updated);
1972
2039
  } catch (err) {
1973
2040
  setError(err instanceof Error ? err.message : String(err));
@@ -1979,7 +2046,7 @@ window.__ModuleLoader__.load({
1979
2046
  try {
1980
2047
  setBusy(`primary-${accountId}`);
1981
2048
  setError(null);
1982
- const updated = await fetchApi$7("/accounts", {
2049
+ const updated = await fetchApi$9("/accounts", {
1983
2050
  method: "POST",
1984
2051
  body: JSON.stringify({
1985
2052
  action: "set-primary",
@@ -1998,7 +2065,7 @@ window.__ModuleLoader__.load({
1998
2065
  try {
1999
2066
  setBusy(`delete-${accountId}`);
2000
2067
  setError(null);
2001
- const updated = await fetchApi$7("/accounts", {
2068
+ const updated = await fetchApi$9("/accounts", {
2002
2069
  method: "POST",
2003
2070
  body: JSON.stringify({
2004
2071
  action: "delete",
@@ -2017,7 +2084,7 @@ window.__ModuleLoader__.load({
2017
2084
  try {
2018
2085
  setBusy(`cooldown-${accountId}`);
2019
2086
  setError(null);
2020
- const updated = await fetchApi$7("/accounts", {
2087
+ const updated = await fetchApi$9("/accounts", {
2021
2088
  method: "POST",
2022
2089
  body: JSON.stringify({
2023
2090
  action: "clear-cooldown",
@@ -2035,7 +2102,7 @@ window.__ModuleLoader__.load({
2035
2102
  try {
2036
2103
  setBusy("strategy");
2037
2104
  setError(null);
2038
- const updated = await fetchApi$7("/accounts", {
2105
+ const updated = await fetchApi$9("/accounts", {
2039
2106
  method: "POST",
2040
2107
  body: JSON.stringify({
2041
2108
  action: "strategy",
@@ -2055,7 +2122,7 @@ window.__ModuleLoader__.load({
2055
2122
  enabled
2056
2123
  } : prev);
2057
2124
  try {
2058
- const updated = await fetchApi$7("/settings", {
2125
+ const updated = await fetchApi$9("/settings", {
2059
2126
  method: "POST",
2060
2127
  body: JSON.stringify({ enabled })
2061
2128
  });
@@ -2071,12 +2138,12 @@ window.__ModuleLoader__.load({
2071
2138
  const currentEnabled = status.models.filter((m) => m.enabled).map((m) => m.id);
2072
2139
  const nextEnabled = checked ? [.../* @__PURE__ */ new Set([...currentEnabled, modelId])] : currentEnabled.filter((id) => id !== modelId);
2073
2140
  try {
2074
- const updated = await fetchApi$7("/models", {
2141
+ const updated = await fetchApi$9("/models", {
2075
2142
  method: "POST",
2076
2143
  body: JSON.stringify({ enabledModelIds: nextEnabled })
2077
2144
  });
2078
2145
  setStatus(updated);
2079
- setContextDrafts(contextDraftsFor$3(updated));
2146
+ setContextDrafts(contextDraftsFor$4(updated));
2080
2147
  notifyChange();
2081
2148
  } catch (err) {
2082
2149
  setError(err instanceof Error ? err.message : String(err));
@@ -2086,12 +2153,12 @@ window.__ModuleLoader__.load({
2086
2153
  if (!status) return;
2087
2154
  const nextEnabled = selectAll ? status.models.map((m) => m.id) : [];
2088
2155
  try {
2089
- const updated = await fetchApi$7("/models", {
2156
+ const updated = await fetchApi$9("/models", {
2090
2157
  method: "POST",
2091
2158
  body: JSON.stringify({ enabledModelIds: nextEnabled })
2092
2159
  });
2093
2160
  setStatus(updated);
2094
- setContextDrafts(contextDraftsFor$3(updated));
2161
+ setContextDrafts(contextDraftsFor$4(updated));
2095
2162
  notifyChange();
2096
2163
  } catch (err) {
2097
2164
  setError(err instanceof Error ? err.message : String(err));
@@ -2099,7 +2166,7 @@ window.__ModuleLoader__.load({
2099
2166
  };
2100
2167
  const handleUpdateEffort = async (effort) => {
2101
2168
  try {
2102
- const updated = await fetchApi$7("/settings", {
2169
+ const updated = await fetchApi$9("/settings", {
2103
2170
  method: "POST",
2104
2171
  body: JSON.stringify({ defaultReasoningEffort: effort })
2105
2172
  });
@@ -2111,7 +2178,7 @@ window.__ModuleLoader__.load({
2111
2178
  };
2112
2179
  const handleSaveContextWindow = async (modelId) => {
2113
2180
  const raw = contextDrafts[modelId] || "";
2114
- const parsed = parsePositiveCapacity$3(raw);
2181
+ const parsed = parsePositiveCapacity$4(raw);
2115
2182
  if (parsed === null) {
2116
2183
  setError(`无效的上下文容量值: ${raw}`);
2117
2184
  return;
@@ -2119,14 +2186,14 @@ window.__ModuleLoader__.load({
2119
2186
  try {
2120
2187
  setSavingModel(modelId);
2121
2188
  setError(null);
2122
- const updated = await fetchApi$7("/settings", {
2189
+ const updated = await fetchApi$9("/settings", {
2123
2190
  method: "POST",
2124
2191
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
2125
2192
  });
2126
2193
  setStatus(updated);
2127
2194
  setContextDrafts((prev) => ({
2128
2195
  ...prev,
2129
- [modelId]: formatCapacity$3(parsed)
2196
+ [modelId]: formatCapacity$4(parsed)
2130
2197
  }));
2131
2198
  notifyChange();
2132
2199
  } catch (err) {
@@ -2140,7 +2207,7 @@ window.__ModuleLoader__.load({
2140
2207
  try {
2141
2208
  setSavingModel(modelId);
2142
2209
  setError(null);
2143
- const updated = await fetchApi$7("/settings", {
2210
+ const updated = await fetchApi$9("/settings", {
2144
2211
  method: "POST",
2145
2212
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
2146
2213
  });
@@ -2149,7 +2216,7 @@ window.__ModuleLoader__.load({
2149
2216
  const model = updated.models.find((candidate) => candidate.id === modelId);
2150
2217
  return model === void 0 ? prev : {
2151
2218
  ...prev,
2152
- [modelId]: formatCapacity$3(model.defaultContextWindow)
2219
+ [modelId]: formatCapacity$4(model.defaultContextWindow)
2153
2220
  };
2154
2221
  });
2155
2222
  notifyChange();
@@ -2167,12 +2234,12 @@ window.__ModuleLoader__.load({
2167
2234
  try {
2168
2235
  setBusy("context");
2169
2236
  setError(null);
2170
- const updated = await fetchApi$7("/settings", {
2237
+ const updated = await fetchApi$9("/settings", {
2171
2238
  method: "POST",
2172
2239
  body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
2173
2240
  });
2174
2241
  setStatus(updated);
2175
- setContextDrafts(contextDraftsFor$3(updated));
2242
+ setContextDrafts(contextDraftsFor$4(updated));
2176
2243
  notifyChange();
2177
2244
  } catch (err) {
2178
2245
  setError(err instanceof Error ? err.message : String(err));
@@ -2221,12 +2288,12 @@ window.__ModuleLoader__.load({
2221
2288
  account.expiresAt && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
2222
2289
  t.expires,
2223
2290
  ": ",
2224
- formatDate$2(account.expiresAt)
2291
+ formatDate$3(account.expiresAt)
2225
2292
  ] }),
2226
2293
  account.lastUsedAt && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
2227
2294
  t.lastUsed,
2228
2295
  ": ",
2229
- formatDate$2(account.lastUsedAt)
2296
+ formatDate$3(account.lastUsedAt)
2230
2297
  ] })
2231
2298
  ] })
2232
2299
  }),
@@ -2505,7 +2572,7 @@ window.__ModuleLoader__.load({
2505
2572
  //#endregion
2506
2573
  //#region src/client/command-code/locales.ts
2507
2574
  const NS_COMMAND_CODE = "dsh-command-code";
2508
- const zh$3 = {
2575
+ const zh$4 = {
2509
2576
  ...accountPoolZh,
2510
2577
  title: "Command Code",
2511
2578
  pageDesc: "登录 Command Code,管理可用模型、上下文窗口与额度。",
@@ -2577,7 +2644,7 @@ window.__ModuleLoader__.load({
2577
2644
  loginFailed: "登录失败",
2578
2645
  tokens: "tokens"
2579
2646
  };
2580
- const en$3 = {
2647
+ const en$4 = {
2581
2648
  ...accountPoolEn,
2582
2649
  title: "Command Code",
2583
2650
  pageDesc: "Sign in to Command Code and manage models, context windows, and quota.",
@@ -2649,11 +2716,11 @@ window.__ModuleLoader__.load({
2649
2716
  loginFailed: "Sign-in failed",
2650
2717
  tokens: "tokens"
2651
2718
  };
2652
- const dictionaries$3 = {
2653
- zh: zh$3,
2654
- "zh-CN": zh$3,
2655
- en: en$3,
2656
- "en-US": en$3
2719
+ const dictionaries$4 = {
2720
+ zh: zh$4,
2721
+ "zh-CN": zh$4,
2722
+ en: en$4,
2723
+ "en-US": en$4
2657
2724
  };
2658
2725
  //#endregion
2659
2726
  //#region src/client/command-code/CommandCodeSection.tsx
@@ -2661,7 +2728,7 @@ window.__ModuleLoader__.load({
2661
2728
  * Display label per reasoning level. The locale dictionary only accepts flat
2662
2729
  * string values, so this nested table lives with the control that renders it.
2663
2730
  */
2664
- const EFFORT_LABELS$1 = {
2731
+ const EFFORT_LABELS$2 = {
2665
2732
  minimal: "Minimal",
2666
2733
  low: "Low",
2667
2734
  medium: "Medium",
@@ -2669,9 +2736,9 @@ window.__ModuleLoader__.load({
2669
2736
  xhigh: "X-High",
2670
2737
  max: "Max"
2671
2738
  };
2672
- const API$6 = "/command-code/api";
2673
- async function fetchApi$6(path, options) {
2674
- const res = await fetch(`${API$6}${path}`, {
2739
+ const API$8 = "/command-code/api";
2740
+ async function fetchApi$8(path, options) {
2741
+ const res = await fetch(`${API$8}${path}`, {
2675
2742
  ...options,
2676
2743
  headers: {
2677
2744
  "Content-Type": "application/json",
@@ -2683,14 +2750,14 @@ window.__ModuleLoader__.load({
2683
2750
  return json.value;
2684
2751
  }
2685
2752
  /** Parse "1M", "512K", "200000" into a positive integer token count. */
2686
- function parsePositiveCapacity$2(value) {
2753
+ function parsePositiveCapacity$3(value) {
2687
2754
  const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
2688
2755
  if (matched === null) return null;
2689
2756
  const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
2690
2757
  const parsed = Number(matched[1]) * multiplier;
2691
2758
  return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
2692
2759
  }
2693
- function formatCapacity$2(value) {
2760
+ function formatCapacity$3(value) {
2694
2761
  if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
2695
2762
  if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
2696
2763
  return String(value);
@@ -2700,12 +2767,12 @@ window.__ModuleLoader__.load({
2700
2767
  * toggle: a model that was just enabled has no draft yet, and the context
2701
2768
  * window section only renders enabled models.
2702
2769
  */
2703
- function contextDraftsFor$2(status) {
2770
+ function contextDraftsFor$3(status) {
2704
2771
  const drafts = {};
2705
- for (const model of status.models) drafts[model.id] = formatCapacity$2(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
2772
+ for (const model of status.models) drafts[model.id] = formatCapacity$3(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
2706
2773
  return drafts;
2707
2774
  }
2708
- function formatReset$2(resetsAt) {
2775
+ function formatReset$3(resetsAt) {
2709
2776
  if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
2710
2777
  const diff = resetsAt - Date.now();
2711
2778
  if (diff <= 0) return "now";
@@ -2725,7 +2792,9 @@ window.__ModuleLoader__.load({
2725
2792
  const [contextDrafts, setContextDrafts] = (0, react.useState)({});
2726
2793
  const [savingModel, setSavingModel] = (0, react.useState)(null);
2727
2794
  const [apiKey, setApiKey] = (0, react.useState)("");
2728
- const t = zh$3;
2795
+ /** Follow-up poll owed while the host refreshes the quota behind an answer. */
2796
+ const quotaFollowUp = (0, react.useRef)(null);
2797
+ const t = zh$4;
2729
2798
  const notifyChange = (0, react.useCallback)(() => {
2730
2799
  onModelChange?.();
2731
2800
  loadModelDirectory?.();
@@ -2733,9 +2802,13 @@ window.__ModuleLoader__.load({
2733
2802
  const loadStatus = (0, react.useCallback)(async (quiet = false) => {
2734
2803
  if (!quiet) setError(null);
2735
2804
  try {
2736
- const data = await fetchApi$6("/status");
2805
+ const data = await fetchApi$8("/status");
2737
2806
  setStatus(data);
2738
- setContextDrafts(contextDraftsFor$2(data));
2807
+ setContextDrafts(contextDraftsFor$3(data));
2808
+ quotaFollowUp.current ??= createQuotaFollowUp();
2809
+ quotaFollowUp.current.observe(data.quotaRefreshing === true, () => {
2810
+ loadStatus(true);
2811
+ });
2739
2812
  } catch (err) {
2740
2813
  if (!quiet) setError(err instanceof Error ? err.message : String(err));
2741
2814
  } finally {
@@ -2752,6 +2825,7 @@ window.__ModuleLoader__.load({
2752
2825
  return () => {
2753
2826
  window.clearInterval(timer);
2754
2827
  document.removeEventListener("visibilitychange", refreshWhenVisible);
2828
+ quotaFollowUp.current?.cancel();
2755
2829
  };
2756
2830
  }, [loadStatus]);
2757
2831
  const handleLogin = async () => {
@@ -2759,12 +2833,12 @@ window.__ModuleLoader__.load({
2759
2833
  setBusy("login");
2760
2834
  setError(null);
2761
2835
  setLoginProgress(null);
2762
- const flow = await fetchApi$6("/login", { method: "POST" });
2836
+ const flow = await fetchApi$8("/login", { method: "POST" });
2763
2837
  if (flow.authUrl) window.open(flow.authUrl, "_blank");
2764
2838
  const pollTimer = window.setInterval(() => {
2765
2839
  (async () => {
2766
2840
  try {
2767
- const poll = await fetchApi$6("/login/status");
2841
+ const poll = await fetchApi$8("/login/status");
2768
2842
  if (poll.progress) setLoginProgress(poll.progress);
2769
2843
  if (poll.status === "complete") {
2770
2844
  window.clearInterval(pollTimer);
@@ -2796,7 +2870,7 @@ window.__ModuleLoader__.load({
2796
2870
  try {
2797
2871
  setBusy("apikey");
2798
2872
  setError(null);
2799
- const updated = await fetchApi$6("/login/apikey", {
2873
+ const updated = await fetchApi$8("/login/apikey", {
2800
2874
  method: "POST",
2801
2875
  body: JSON.stringify({ apiKey })
2802
2876
  });
@@ -2814,7 +2888,7 @@ window.__ModuleLoader__.load({
2814
2888
  try {
2815
2889
  setBusy(`${action}-${accountId}`);
2816
2890
  setError(null);
2817
- const updated = await fetchApi$6("/accounts", {
2891
+ const updated = await fetchApi$8("/accounts", {
2818
2892
  method: "POST",
2819
2893
  body: JSON.stringify({
2820
2894
  action,
@@ -2833,7 +2907,7 @@ window.__ModuleLoader__.load({
2833
2907
  try {
2834
2908
  setBusy("strategy");
2835
2909
  setError(null);
2836
- const updated = await fetchApi$6("/accounts", {
2910
+ const updated = await fetchApi$8("/accounts", {
2837
2911
  method: "POST",
2838
2912
  body: JSON.stringify({
2839
2913
  action: "strategy",
@@ -2856,7 +2930,7 @@ window.__ModuleLoader__.load({
2856
2930
  const handleRelogin = (accountId) => {
2857
2931
  (async () => {
2858
2932
  try {
2859
- const updated = await fetchApi$6("/accounts", {
2933
+ const updated = await fetchApi$8("/accounts", {
2860
2934
  method: "POST",
2861
2935
  body: JSON.stringify({
2862
2936
  action: "relogin",
@@ -2875,7 +2949,7 @@ window.__ModuleLoader__.load({
2875
2949
  try {
2876
2950
  setBusy("quota");
2877
2951
  setError(null);
2878
- const updated = await fetchApi$6("/quota", { method: "POST" });
2952
+ const updated = await fetchApi$8("/quota", { method: "POST" });
2879
2953
  setStatus(updated);
2880
2954
  } catch (err) {
2881
2955
  setError(err instanceof Error ? err.message : String(err));
@@ -2887,9 +2961,9 @@ window.__ModuleLoader__.load({
2887
2961
  try {
2888
2962
  setBusy("catalog");
2889
2963
  setError(null);
2890
- const updated = await fetchApi$6("/catalog/refresh", { method: "POST" });
2964
+ const updated = await fetchApi$8("/catalog/refresh", { method: "POST" });
2891
2965
  setStatus(updated);
2892
- setContextDrafts(contextDraftsFor$2(updated));
2966
+ setContextDrafts(contextDraftsFor$3(updated));
2893
2967
  notifyChange();
2894
2968
  } catch (err) {
2895
2969
  setError(err instanceof Error ? err.message : String(err));
@@ -2901,7 +2975,7 @@ window.__ModuleLoader__.load({
2901
2975
  try {
2902
2976
  setBusy("connection");
2903
2977
  setError(null);
2904
- await fetchApi$6("/connection/test", { method: "POST" });
2978
+ await fetchApi$8("/connection/test", { method: "POST" });
2905
2979
  await loadStatus(true);
2906
2980
  } catch (err) {
2907
2981
  setError(err instanceof Error ? err.message : String(err));
@@ -2911,12 +2985,12 @@ window.__ModuleLoader__.load({
2911
2985
  };
2912
2986
  const applyEnabled = async (enabledModelIds) => {
2913
2987
  try {
2914
- const updated = await fetchApi$6("/models", {
2988
+ const updated = await fetchApi$8("/models", {
2915
2989
  method: "POST",
2916
2990
  body: JSON.stringify({ enabledModelIds })
2917
2991
  });
2918
2992
  setStatus(updated);
2919
- setContextDrafts(contextDraftsFor$2(updated));
2993
+ setContextDrafts(contextDraftsFor$3(updated));
2920
2994
  notifyChange();
2921
2995
  } catch (err) {
2922
2996
  setError(err instanceof Error ? err.message : String(err));
@@ -2928,7 +3002,7 @@ window.__ModuleLoader__.load({
2928
3002
  enabled
2929
3003
  } : prev);
2930
3004
  try {
2931
- const updated = await fetchApi$6("/settings", {
3005
+ const updated = await fetchApi$8("/settings", {
2932
3006
  method: "POST",
2933
3007
  body: JSON.stringify({ enabled })
2934
3008
  });
@@ -2951,7 +3025,7 @@ window.__ModuleLoader__.load({
2951
3025
  };
2952
3026
  const handleUpdateEffort = async (effort) => {
2953
3027
  try {
2954
- const updated = await fetchApi$6("/settings", {
3028
+ const updated = await fetchApi$8("/settings", {
2955
3029
  method: "POST",
2956
3030
  body: JSON.stringify({ defaultReasoningEffort: effort })
2957
3031
  });
@@ -2963,7 +3037,7 @@ window.__ModuleLoader__.load({
2963
3037
  };
2964
3038
  const handleSaveContextWindow = async (modelId) => {
2965
3039
  const raw = contextDrafts[modelId] || "";
2966
- const parsed = parsePositiveCapacity$2(raw);
3040
+ const parsed = parsePositiveCapacity$3(raw);
2967
3041
  if (parsed === null) {
2968
3042
  setError(`Invalid context capacity: ${raw}`);
2969
3043
  return;
@@ -2971,14 +3045,14 @@ window.__ModuleLoader__.load({
2971
3045
  try {
2972
3046
  setSavingModel(modelId);
2973
3047
  setError(null);
2974
- const updated = await fetchApi$6("/settings", {
3048
+ const updated = await fetchApi$8("/settings", {
2975
3049
  method: "POST",
2976
3050
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
2977
3051
  });
2978
3052
  setStatus(updated);
2979
3053
  setContextDrafts((prev) => ({
2980
3054
  ...prev,
2981
- [modelId]: formatCapacity$2(parsed)
3055
+ [modelId]: formatCapacity$3(parsed)
2982
3056
  }));
2983
3057
  notifyChange();
2984
3058
  } catch (err) {
@@ -2992,7 +3066,7 @@ window.__ModuleLoader__.load({
2992
3066
  try {
2993
3067
  setSavingModel(modelId);
2994
3068
  setError(null);
2995
- const updated = await fetchApi$6("/settings", {
3069
+ const updated = await fetchApi$8("/settings", {
2996
3070
  method: "POST",
2997
3071
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
2998
3072
  });
@@ -3001,7 +3075,7 @@ window.__ModuleLoader__.load({
3001
3075
  const model = updated.models.find((candidate) => candidate.id === modelId);
3002
3076
  return model === void 0 ? prev : {
3003
3077
  ...prev,
3004
- [modelId]: formatCapacity$2(model.defaultContextWindow)
3078
+ [modelId]: formatCapacity$3(model.defaultContextWindow)
3005
3079
  };
3006
3080
  });
3007
3081
  notifyChange();
@@ -3019,12 +3093,12 @@ window.__ModuleLoader__.load({
3019
3093
  try {
3020
3094
  setBusy("context");
3021
3095
  setError(null);
3022
- const updated = await fetchApi$6("/settings", {
3096
+ const updated = await fetchApi$8("/settings", {
3023
3097
  method: "POST",
3024
3098
  body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
3025
3099
  });
3026
3100
  setStatus(updated);
3027
- setContextDrafts(contextDraftsFor$2(updated));
3101
+ setContextDrafts(contextDraftsFor$3(updated));
3028
3102
  notifyChange();
3029
3103
  } catch (err) {
3030
3104
  setError(err instanceof Error ? err.message : String(err));
@@ -3221,7 +3295,7 @@ window.__ModuleLoader__.load({
3221
3295
  children: t.defaultEffortAuto
3222
3296
  }), COMMAND_CODE_REASONING_EFFORTS.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3223
3297
  value: effort,
3224
- children: EFFORT_LABELS$1[effort]
3298
+ children: EFFORT_LABELS$2[effort]
3225
3299
  }, effort))]
3226
3300
  })]
3227
3301
  })]
@@ -3338,7 +3412,7 @@ window.__ModuleLoader__.load({
3338
3412
  }),
3339
3413
  window.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3340
3414
  className: "dsha-meter-meta",
3341
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$2(window.resetsAt)] })
3415
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$3(window.resetsAt)] })
3342
3416
  })
3343
3417
  ]
3344
3418
  }, window.id)),
@@ -3363,7 +3437,7 @@ window.__ModuleLoader__.load({
3363
3437
  meter.used ?? "—",
3364
3438
  " / ",
3365
3439
  meter.limit ?? "—"
3366
- ] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$2(meter.resetsAt)] })]
3440
+ ] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$3(meter.resetsAt)] })]
3367
3441
  }) : meter.description !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3368
3442
  className: "dsha-meter-meta",
3369
3443
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: meter.description })
@@ -3402,7 +3476,7 @@ window.__ModuleLoader__.load({
3402
3476
  //#endregion
3403
3477
  //#region src/client/kimi-code/locales.ts
3404
3478
  const NS_KIMI_CODE = "dsh-kimi-code";
3405
- const zh$2 = {
3479
+ const zh$3 = {
3406
3480
  ...accountPoolZh,
3407
3481
  title: "Kimi Code",
3408
3482
  pageDesc: "登录 Kimi Code 订阅,管理模型、思考档位、上下文窗口与额度。",
@@ -3526,7 +3600,7 @@ window.__ModuleLoader__.load({
3526
3600
  requests: "次请求",
3527
3601
  tokens: "tokens"
3528
3602
  };
3529
- const en$2 = {
3603
+ const en$3 = {
3530
3604
  ...accountPoolEn,
3531
3605
  title: "Kimi Code",
3532
3606
  pageDesc: "Sign in to the Kimi Code subscription and manage models, thinking level, context windows, and quota.",
@@ -3650,11 +3724,11 @@ window.__ModuleLoader__.load({
3650
3724
  requests: "requests",
3651
3725
  tokens: "tokens"
3652
3726
  };
3653
- const dictionaries$2 = {
3654
- zh: zh$2,
3655
- "zh-CN": zh$2,
3656
- en: en$2,
3657
- "en-US": en$2
3727
+ const dictionaries$3 = {
3728
+ zh: zh$3,
3729
+ "zh-CN": zh$3,
3730
+ en: en$3,
3731
+ "en-US": en$3
3658
3732
  };
3659
3733
  //#endregion
3660
3734
  //#region src/client/kimi-code/KimiModelCapabilities.tsx
@@ -3667,7 +3741,7 @@ window.__ModuleLoader__.load({
3667
3741
  * Capabilities are now short tags in their own columns, with the per-model
3668
3742
  * detail kept in a hover title.
3669
3743
  */
3670
- const t = zh$2;
3744
+ const t = zh$3;
3671
3745
  function KimiModelCapabilities({ models }) {
3672
3746
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3673
3747
  className: "dsha-cap-table",
@@ -3711,9 +3785,9 @@ window.__ModuleLoader__.load({
3711
3785
  }
3712
3786
  //#endregion
3713
3787
  //#region src/client/kimi-code/KimiCodeSection.tsx
3714
- const API$5 = "/kimi-code/api";
3715
- async function fetchApi$5(path, options) {
3716
- const res = await fetch(`${API$5}${path}`, {
3788
+ const API$7 = "/kimi-code/api";
3789
+ async function fetchApi$7(path, options) {
3790
+ const res = await fetch(`${API$7}${path}`, {
3717
3791
  ...options,
3718
3792
  headers: {
3719
3793
  "Content-Type": "application/json",
@@ -3725,14 +3799,14 @@ window.__ModuleLoader__.load({
3725
3799
  return json.value;
3726
3800
  }
3727
3801
  /** Parse "1M", "512K", "200000" into a positive integer token count. */
3728
- function parsePositiveCapacity$1(value) {
3802
+ function parsePositiveCapacity$2(value) {
3729
3803
  const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
3730
3804
  if (matched === null) return null;
3731
3805
  const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
3732
3806
  const parsed = Number(matched[1]) * multiplier;
3733
3807
  return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
3734
3808
  }
3735
- function formatCapacity$1(value) {
3809
+ function formatCapacity$2(value) {
3736
3810
  if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
3737
3811
  if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
3738
3812
  return String(value);
@@ -3742,12 +3816,12 @@ window.__ModuleLoader__.load({
3742
3816
  * toggle: a model that was just enabled has no draft yet, and the context
3743
3817
  * window section only renders enabled models.
3744
3818
  */
3745
- function contextDraftsFor$1(status) {
3819
+ function contextDraftsFor$2(status) {
3746
3820
  const drafts = {};
3747
- for (const model of status.models) drafts[model.id] = formatCapacity$1(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
3821
+ for (const model of status.models) drafts[model.id] = formatCapacity$2(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
3748
3822
  return drafts;
3749
3823
  }
3750
- function formatDate$1(ms) {
3824
+ function formatDate$2(ms) {
3751
3825
  if (ms === void 0 || ms === null || ms <= 0) return "—";
3752
3826
  try {
3753
3827
  return new Intl.DateTimeFormat(void 0, {
@@ -3758,7 +3832,7 @@ window.__ModuleLoader__.load({
3758
3832
  return "—";
3759
3833
  }
3760
3834
  }
3761
- function formatReset$1(resetsAt) {
3835
+ function formatReset$2(resetsAt) {
3762
3836
  if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
3763
3837
  const diff = resetsAt - Date.now();
3764
3838
  if (diff <= 0) return "now";
@@ -3783,10 +3857,10 @@ window.__ModuleLoader__.load({
3783
3857
  }
3784
3858
  }
3785
3859
  const EFFORT_LABEL = {
3786
- low: zh$2.effortLow,
3787
- high: zh$2.effortHigh,
3788
- max: zh$2.effortMax,
3789
- none: zh$2.effortNone
3860
+ low: zh$3.effortLow,
3861
+ high: zh$3.effortHigh,
3862
+ max: zh$3.effortMax,
3863
+ none: zh$3.effortNone
3790
3864
  };
3791
3865
  /** Human label for the last request's prefix-drift cause. */
3792
3866
  function driftLabel(cause, t) {
@@ -3810,7 +3884,9 @@ window.__ModuleLoader__.load({
3810
3884
  const [savingModel, setSavingModel] = (0, react.useState)(null);
3811
3885
  const [copied, setCopied] = (0, react.useState)(false);
3812
3886
  const [connectionNotice, setConnectionNotice] = (0, react.useState)(null);
3813
- const t = zh$2;
3887
+ /** Follow-up poll owed while the host refreshes the quota behind an answer. */
3888
+ const quotaFollowUp = (0, react.useRef)(null);
3889
+ const t = zh$3;
3814
3890
  const notifyChange = (0, react.useCallback)(() => {
3815
3891
  onModelChange?.();
3816
3892
  loadModelDirectory?.();
@@ -3818,9 +3894,13 @@ window.__ModuleLoader__.load({
3818
3894
  const loadStatus = (0, react.useCallback)(async (quiet = false) => {
3819
3895
  if (!quiet) setError(null);
3820
3896
  try {
3821
- const data = await fetchApi$5("/status");
3897
+ const data = await fetchApi$7("/status");
3822
3898
  setStatus(data);
3823
- setContextDrafts(contextDraftsFor$1(data));
3899
+ setContextDrafts(contextDraftsFor$2(data));
3900
+ quotaFollowUp.current ??= createQuotaFollowUp();
3901
+ quotaFollowUp.current.observe(data.quotaRefreshing === true, () => {
3902
+ loadStatus(true);
3903
+ });
3824
3904
  } catch (err) {
3825
3905
  if (!quiet) setError(err instanceof Error ? err.message : String(err));
3826
3906
  } finally {
@@ -3837,6 +3917,7 @@ window.__ModuleLoader__.load({
3837
3917
  return () => {
3838
3918
  window.clearInterval(timer);
3839
3919
  document.removeEventListener("visibilitychange", refreshWhenVisible);
3920
+ quotaFollowUp.current?.cancel();
3840
3921
  };
3841
3922
  }, [loadStatus]);
3842
3923
  (0, react.useEffect)(() => {
@@ -3844,7 +3925,7 @@ window.__ModuleLoader__.load({
3844
3925
  const timer = window.setInterval(() => {
3845
3926
  (async () => {
3846
3927
  try {
3847
- const poll = await fetchApi$5("/login/status");
3928
+ const poll = await fetchApi$7("/login/status");
3848
3929
  setFlow(poll);
3849
3930
  if (poll.status === "complete") {
3850
3931
  await loadStatus();
@@ -3865,7 +3946,7 @@ window.__ModuleLoader__.load({
3865
3946
  setBusy("login");
3866
3947
  setError(null);
3867
3948
  setCopied(false);
3868
- const next = await fetchApi$5("/login", {
3949
+ const next = await fetchApi$7("/login", {
3869
3950
  method: "POST",
3870
3951
  body: JSON.stringify({})
3871
3952
  });
@@ -3878,7 +3959,7 @@ window.__ModuleLoader__.load({
3878
3959
  };
3879
3960
  const handleCancelLogin = async () => {
3880
3961
  try {
3881
- await fetchApi$5("/login/cancel", { method: "POST" });
3962
+ await fetchApi$7("/login/cancel", { method: "POST" });
3882
3963
  setFlow({ status: "idle" });
3883
3964
  } catch (err) {
3884
3965
  setError(err instanceof Error ? err.message : String(err));
@@ -3898,7 +3979,7 @@ window.__ModuleLoader__.load({
3898
3979
  try {
3899
3980
  setBusy(`${action}-${accountId}`);
3900
3981
  setError(null);
3901
- const updated = await fetchApi$5("/accounts", {
3982
+ const updated = await fetchApi$7("/accounts", {
3902
3983
  method: "POST",
3903
3984
  body: JSON.stringify({
3904
3985
  action,
@@ -3918,7 +3999,7 @@ window.__ModuleLoader__.load({
3918
3999
  try {
3919
4000
  setBusy("strategy");
3920
4001
  setError(null);
3921
- const updated = await fetchApi$5("/accounts", {
4002
+ const updated = await fetchApi$7("/accounts", {
3922
4003
  method: "POST",
3923
4004
  body: JSON.stringify({
3924
4005
  action: "strategy",
@@ -3941,7 +4022,7 @@ window.__ModuleLoader__.load({
3941
4022
  const handleRelogin = (accountId) => {
3942
4023
  (async () => {
3943
4024
  try {
3944
- const updated = await fetchApi$5("/accounts", {
4025
+ const updated = await fetchApi$7("/accounts", {
3945
4026
  method: "POST",
3946
4027
  body: JSON.stringify({
3947
4028
  action: "relogin",
@@ -3960,7 +4041,7 @@ window.__ModuleLoader__.load({
3960
4041
  try {
3961
4042
  setBusy("quota");
3962
4043
  setError(null);
3963
- const updated = await fetchApi$5("/quota", { method: "POST" });
4044
+ const updated = await fetchApi$7("/quota", { method: "POST" });
3964
4045
  setStatus(updated);
3965
4046
  } catch (err) {
3966
4047
  setError(err instanceof Error ? err.message : String(err));
@@ -3973,9 +4054,9 @@ window.__ModuleLoader__.load({
3973
4054
  try {
3974
4055
  setBusy("catalog");
3975
4056
  setError(null);
3976
- const updated = await fetchApi$5("/catalog/refresh", { method: "POST" });
4057
+ const updated = await fetchApi$7("/catalog/refresh", { method: "POST" });
3977
4058
  setStatus(updated);
3978
- setContextDrafts(contextDraftsFor$1(updated));
4059
+ setContextDrafts(contextDraftsFor$2(updated));
3979
4060
  notifyChange();
3980
4061
  } catch (err) {
3981
4062
  setError(err instanceof Error ? err.message : String(err));
@@ -3988,7 +4069,7 @@ window.__ModuleLoader__.load({
3988
4069
  setBusy("connection");
3989
4070
  setError(null);
3990
4071
  setConnectionNotice(null);
3991
- const result = await fetchApi$5("/connection/test", { method: "POST" });
4072
+ const result = await fetchApi$7("/connection/test", { method: "POST" });
3992
4073
  setConnectionNotice(result.connected ? `${t.testSuccess} · ${result.latencyMs} ms` : t.testFailed);
3993
4074
  await loadStatus(true);
3994
4075
  } catch (err) {
@@ -3999,12 +4080,12 @@ window.__ModuleLoader__.load({
3999
4080
  };
4000
4081
  const applyEnabled = async (enabledModelIds) => {
4001
4082
  try {
4002
- const updated = await fetchApi$5("/models", {
4083
+ const updated = await fetchApi$7("/models", {
4003
4084
  method: "POST",
4004
4085
  body: JSON.stringify({ enabledModelIds })
4005
4086
  });
4006
4087
  setStatus(updated);
4007
- setContextDrafts(contextDraftsFor$1(updated));
4088
+ setContextDrafts(contextDraftsFor$2(updated));
4008
4089
  notifyChange();
4009
4090
  } catch (err) {
4010
4091
  setError(err instanceof Error ? err.message : String(err));
@@ -4016,7 +4097,7 @@ window.__ModuleLoader__.load({
4016
4097
  enabled
4017
4098
  } : prev);
4018
4099
  try {
4019
- const updated = await fetchApi$5("/settings", {
4100
+ const updated = await fetchApi$7("/settings", {
4020
4101
  method: "POST",
4021
4102
  body: JSON.stringify({ enabled })
4022
4103
  });
@@ -4039,7 +4120,7 @@ window.__ModuleLoader__.load({
4039
4120
  };
4040
4121
  const handleUpdateEffort = async (effort) => {
4041
4122
  try {
4042
- const updated = await fetchApi$5("/settings", {
4123
+ const updated = await fetchApi$7("/settings", {
4043
4124
  method: "POST",
4044
4125
  body: JSON.stringify({ defaultReasoningEffort: effort })
4045
4126
  });
@@ -4051,7 +4132,7 @@ window.__ModuleLoader__.load({
4051
4132
  };
4052
4133
  const handleSaveContextWindow = async (modelId) => {
4053
4134
  const raw = contextDrafts[modelId] || "";
4054
- const parsed = parsePositiveCapacity$1(raw);
4135
+ const parsed = parsePositiveCapacity$2(raw);
4055
4136
  if (parsed === null) {
4056
4137
  setError(`Invalid context capacity: ${raw}`);
4057
4138
  return;
@@ -4059,14 +4140,14 @@ window.__ModuleLoader__.load({
4059
4140
  try {
4060
4141
  setSavingModel(modelId);
4061
4142
  setError(null);
4062
- const updated = await fetchApi$5("/settings", {
4143
+ const updated = await fetchApi$7("/settings", {
4063
4144
  method: "POST",
4064
4145
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
4065
4146
  });
4066
4147
  setStatus(updated);
4067
4148
  setContextDrafts((prev) => ({
4068
4149
  ...prev,
4069
- [modelId]: formatCapacity$1(parsed)
4150
+ [modelId]: formatCapacity$2(parsed)
4070
4151
  }));
4071
4152
  notifyChange();
4072
4153
  } catch (err) {
@@ -4080,7 +4161,7 @@ window.__ModuleLoader__.load({
4080
4161
  try {
4081
4162
  setSavingModel(modelId);
4082
4163
  setError(null);
4083
- const updated = await fetchApi$5("/settings", {
4164
+ const updated = await fetchApi$7("/settings", {
4084
4165
  method: "POST",
4085
4166
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
4086
4167
  });
@@ -4089,7 +4170,7 @@ window.__ModuleLoader__.load({
4089
4170
  const model = updated.models.find((candidate) => candidate.id === modelId);
4090
4171
  return model === void 0 ? prev : {
4091
4172
  ...prev,
4092
- [modelId]: formatCapacity$1(model.defaultContextWindow)
4173
+ [modelId]: formatCapacity$2(model.defaultContextWindow)
4093
4174
  };
4094
4175
  });
4095
4176
  notifyChange();
@@ -4107,12 +4188,12 @@ window.__ModuleLoader__.load({
4107
4188
  try {
4108
4189
  setBusy("context");
4109
4190
  setError(null);
4110
- const updated = await fetchApi$5("/settings", {
4191
+ const updated = await fetchApi$7("/settings", {
4111
4192
  method: "POST",
4112
4193
  body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
4113
4194
  });
4114
4195
  setStatus(updated);
4115
- setContextDrafts(contextDraftsFor$1(updated));
4196
+ setContextDrafts(contextDraftsFor$2(updated));
4116
4197
  notifyChange();
4117
4198
  } catch (err) {
4118
4199
  setError(err instanceof Error ? err.message : String(err));
@@ -4200,7 +4281,7 @@ window.__ModuleLoader__.load({
4200
4281
  children: t.codeExpires
4201
4282
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4202
4283
  className: "dsha-value",
4203
- children: formatDate$1(flow?.expiresAt)
4284
+ children: formatDate$2(flow?.expiresAt)
4204
4285
  })]
4205
4286
  }),
4206
4287
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -4481,7 +4562,7 @@ window.__ModuleLoader__.load({
4481
4562
  title: model.id,
4482
4563
  children: [model.name, model.defaultContextWindow < model.contextWindow && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4483
4564
  className: "dsha-model-meta",
4484
- children: formatCapacity$1(model.contextWindow)
4565
+ children: formatCapacity$2(model.contextWindow)
4485
4566
  })]
4486
4567
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4487
4568
  className: "dsha-capacity-control",
@@ -4584,7 +4665,7 @@ window.__ModuleLoader__.load({
4584
4665
  window.limit ?? "—",
4585
4666
  " ",
4586
4667
  t.requests
4587
- ] }), window.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.resetAt.replace("{time}", formatReset$1(window.resetsAt)) })]
4668
+ ] }), window.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.resetAt.replace("{time}", formatReset$2(window.resetsAt)) })]
4588
4669
  })
4589
4670
  ]
4590
4671
  }, window.id);
@@ -4636,7 +4717,7 @@ window.__ModuleLoader__.load({
4636
4717
  //#endregion
4637
4718
  //#region src/client/workbuddy/locales.ts
4638
4719
  const NS_WORKBUDDY = "dsh-workbuddy";
4639
- const zh$1 = {
4720
+ const zh$2 = {
4640
4721
  title: "WorkBuddy",
4641
4722
  pageDesc: "复用本机 CodeBuddy 桌面端登录态,管理 WorkBuddy(CodeBuddy 订阅)模型、上下文窗口与额度。",
4642
4723
  account: "账号",
@@ -4718,9 +4799,19 @@ window.__ModuleLoader__.load({
4718
4799
  updatedAt: "更新时间:{time}",
4719
4800
  loading: "加载中...",
4720
4801
  credits: "credits",
4721
- composerLabel: "额度"
4802
+ composerLabel: "额度",
4803
+ dailyCheckin: "每日签到",
4804
+ checkinHint: "仅国区账号参与;DSH 启动时自动签到一次,运行期间每 10 分钟补检,进程关闭的当天不会签到。",
4805
+ checkinAuto: "自动签到",
4806
+ checkinToday: "今日已签 {done}/{total}",
4807
+ checkinSkipped: "{count} 个无签到活动",
4808
+ checkinFailed: "{count} 个失败",
4809
+ checkinLastRun: "上次运行:{time}",
4810
+ checkinNever: "尚未运行",
4811
+ checkinNow: "立即签到",
4812
+ checkinRunning: "签到中…"
4722
4813
  };
4723
- const en$1 = {
4814
+ const en$2 = {
4724
4815
  title: "WorkBuddy",
4725
4816
  pageDesc: "Reuse the local CodeBuddy desktop sign-in to manage WorkBuddy (CodeBuddy subscription) models, context windows, and quota.",
4726
4817
  account: "Account",
@@ -4802,13 +4893,23 @@ window.__ModuleLoader__.load({
4802
4893
  updatedAt: "Updated at: {time}",
4803
4894
  loading: "Loading...",
4804
4895
  credits: "credits",
4805
- composerLabel: "Quota"
4896
+ composerLabel: "Quota",
4897
+ dailyCheckin: "Daily check-in",
4898
+ checkinHint: "CN-region accounts only. The host signs in once at startup and re-checks every 10 minutes while running; a day the process never runs is not signed.",
4899
+ checkinAuto: "Auto check-in",
4900
+ checkinToday: "Checked in today {done}/{total}",
4901
+ checkinSkipped: "{count} with no activity",
4902
+ checkinFailed: "{count} failed",
4903
+ checkinLastRun: "Last run: {time}",
4904
+ checkinNever: "Never run",
4905
+ checkinNow: "Check in now",
4906
+ checkinRunning: "Checking in…"
4806
4907
  };
4807
- const dictionaries$1 = {
4808
- zh: zh$1,
4809
- "zh-CN": zh$1,
4810
- en: en$1,
4811
- "en-US": en$1
4908
+ const dictionaries$2 = {
4909
+ zh: zh$2,
4910
+ "zh-CN": zh$2,
4911
+ en: en$2,
4912
+ "en-US": en$2
4812
4913
  };
4813
4914
  //#endregion
4814
4915
  //#region src/client/workbuddy/WorkBuddySection.tsx
@@ -4816,7 +4917,7 @@ window.__ModuleLoader__.load({
4816
4917
  * Display label per reasoning level. The locale dictionary only accepts flat
4817
4918
  * string values, so this nested table lives with the control that renders it.
4818
4919
  */
4819
- const EFFORT_LABELS = {
4920
+ const EFFORT_LABELS$1 = {
4820
4921
  minimal: "Minimal",
4821
4922
  low: "Low",
4822
4923
  medium: "Medium",
@@ -4824,7 +4925,7 @@ window.__ModuleLoader__.load({
4824
4925
  xhigh: "X-High",
4825
4926
  max: "Max"
4826
4927
  };
4827
- const API$4 = "/workbuddy/api";
4928
+ const API$6 = "/workbuddy/api";
4828
4929
  /**
4829
4930
  * The shared card's label set.
4830
4931
  *
@@ -4850,8 +4951,8 @@ window.__ModuleLoader__.load({
4850
4951
  * process (a stale Host has no route to answer), so the error is reported as
4851
4952
  * such instead of as a credential problem.
4852
4953
  */
4853
- async function fetchApi$4(path, options) {
4854
- const res = await fetch(`${API$4}${path}`, {
4954
+ async function fetchApi$6(path, options) {
4955
+ const res = await fetch(`${API$6}${path}`, {
4855
4956
  ...options,
4856
4957
  headers: {
4857
4958
  "Content-Type": "application/json",
@@ -4870,14 +4971,14 @@ window.__ModuleLoader__.load({
4870
4971
  return json.value;
4871
4972
  }
4872
4973
  /** Parse "1M", "512K", "200000" into a positive integer token count. */
4873
- function parsePositiveCapacity(value) {
4974
+ function parsePositiveCapacity$1(value) {
4874
4975
  const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
4875
4976
  if (matched === null) return null;
4876
4977
  const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
4877
4978
  const parsed = Number(matched[1]) * multiplier;
4878
4979
  return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
4879
4980
  }
4880
- function formatCapacity(value) {
4981
+ function formatCapacity$1(value) {
4881
4982
  if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
4882
4983
  if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
4883
4984
  return String(value);
@@ -4887,12 +4988,12 @@ window.__ModuleLoader__.load({
4887
4988
  * toggle: a model that was just enabled has no draft yet, and the context
4888
4989
  * window section only renders enabled models.
4889
4990
  */
4890
- function contextDraftsFor(status) {
4991
+ function contextDraftsFor$1(status) {
4891
4992
  const drafts = {};
4892
- for (const model of status.models) drafts[model.id] = formatCapacity(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
4993
+ for (const model of status.models) drafts[model.id] = formatCapacity$1(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
4893
4994
  return drafts;
4894
4995
  }
4895
- function formatDate(ms) {
4996
+ function formatDate$1(ms) {
4896
4997
  if (ms === void 0 || ms === null || ms <= 0) return "—";
4897
4998
  try {
4898
4999
  return new Intl.DateTimeFormat(void 0, {
@@ -4903,7 +5004,7 @@ window.__ModuleLoader__.load({
4903
5004
  return "—";
4904
5005
  }
4905
5006
  }
4906
- function formatReset(resetsAt) {
5007
+ function formatReset$1(resetsAt) {
4907
5008
  if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
4908
5009
  const diff = resetsAt - Date.now();
4909
5010
  if (diff <= 0) return "now";
@@ -4978,9 +5079,11 @@ window.__ModuleLoader__.load({
4978
5079
  const [loginProgress, setLoginProgress] = (0, react.useState)(null);
4979
5080
  const loginIntervalRef = (0, react.useRef)(null);
4980
5081
  const loginTimeoutRef = (0, react.useRef)(null);
5082
+ /** Follow-up poll owed while the host refreshes the quota behind an answer. */
5083
+ const quotaFollowUp = (0, react.useRef)(null);
4981
5084
  const [contextDrafts, setContextDrafts] = (0, react.useState)({});
4982
5085
  const [savingModel, setSavingModel] = (0, react.useState)(null);
4983
- const t = zh$1;
5086
+ const t = zh$2;
4984
5087
  const notifyChange = (0, react.useCallback)(() => {
4985
5088
  onModelChange?.();
4986
5089
  loadModelDirectory?.();
@@ -4992,10 +5095,15 @@ window.__ModuleLoader__.load({
4992
5095
  const loadStatus = (0, react.useCallback)(async (quiet = false) => {
4993
5096
  if (!quiet) setError(null);
4994
5097
  try {
4995
- const normalized = normalizeStatus(await fetchApi$4("/status"));
5098
+ const data = await fetchApi$6("/status");
5099
+ const normalized = normalizeStatus(data);
4996
5100
  setStatus(normalized);
4997
5101
  setStatusFailed(false);
4998
- setContextDrafts(contextDraftsFor(normalized));
5102
+ setContextDrafts(contextDraftsFor$1(normalized));
5103
+ quotaFollowUp.current ??= createQuotaFollowUp();
5104
+ quotaFollowUp.current.observe(data.quotaRefreshing === true, () => {
5105
+ loadStatus(true);
5106
+ });
4999
5107
  } catch (err) {
5000
5108
  setStatusFailed(true);
5001
5109
  if (!quiet) setError(err instanceof Error ? err.message : String(err));
@@ -5011,6 +5119,7 @@ window.__ModuleLoader__.load({
5011
5119
  document.addEventListener("visibilitychange", refreshWhenVisible);
5012
5120
  return () => {
5013
5121
  document.removeEventListener("visibilitychange", refreshWhenVisible);
5122
+ quotaFollowUp.current?.cancel();
5014
5123
  if (loginIntervalRef.current !== null) window.clearInterval(loginIntervalRef.current);
5015
5124
  if (loginTimeoutRef.current !== null) window.clearTimeout(loginTimeoutRef.current);
5016
5125
  };
@@ -5019,7 +5128,7 @@ window.__ModuleLoader__.load({
5019
5128
  try {
5020
5129
  setBusy("rescan");
5021
5130
  setError(null);
5022
- const updated = await fetchApi$4("/rescan", { method: "POST" });
5131
+ const updated = await fetchApi$6("/rescan", { method: "POST" });
5023
5132
  setStatus(normalizeStatus(updated));
5024
5133
  notifyChange();
5025
5134
  } catch (err) {
@@ -5033,7 +5142,7 @@ window.__ModuleLoader__.load({
5033
5142
  setBusy(`login:${region}`);
5034
5143
  setError(null);
5035
5144
  setLoginProgress(t.loginWaiting);
5036
- const flow = await fetchApi$4("/accounts/login", {
5145
+ const flow = await fetchApi$6("/accounts/login", {
5037
5146
  method: "POST",
5038
5147
  body: JSON.stringify({ region })
5039
5148
  });
@@ -5043,7 +5152,7 @@ window.__ModuleLoader__.load({
5043
5152
  const timer = window.setInterval(() => {
5044
5153
  (async () => {
5045
5154
  try {
5046
- const poll = await fetchApi$4("/accounts/login/status");
5155
+ const poll = await fetchApi$6("/accounts/login/status");
5047
5156
  if (poll.progress) setLoginProgress(poll.progress);
5048
5157
  if (poll.status === "complete") {
5049
5158
  window.clearInterval(timer);
@@ -5052,7 +5161,7 @@ window.__ModuleLoader__.load({
5052
5161
  loginTimeoutRef.current = null;
5053
5162
  setBusy(null);
5054
5163
  setLoginProgress(null);
5055
- if (poll.accountId) await fetchApi$4("/settings", {
5164
+ if (poll.accountId) await fetchApi$6("/settings", {
5056
5165
  method: "POST",
5057
5166
  body: JSON.stringify({ selectedAccountId: poll.accountId })
5058
5167
  });
@@ -5092,7 +5201,7 @@ window.__ModuleLoader__.load({
5092
5201
  try {
5093
5202
  setBusy(`${action}:${accountId}`);
5094
5203
  setError(null);
5095
- const updated = await fetchApi$4("/accounts/action", {
5204
+ const updated = await fetchApi$6("/accounts/action", {
5096
5205
  method: "POST",
5097
5206
  body: JSON.stringify({
5098
5207
  action,
@@ -5115,7 +5224,7 @@ window.__ModuleLoader__.load({
5115
5224
  try {
5116
5225
  setBusy("strategy");
5117
5226
  setError(null);
5118
- const updated = await fetchApi$4("/accounts/strategy", {
5227
+ const updated = await fetchApi$6("/accounts/strategy", {
5119
5228
  method: "POST",
5120
5229
  body: JSON.stringify({ strategy })
5121
5230
  });
@@ -5130,7 +5239,7 @@ window.__ModuleLoader__.load({
5130
5239
  try {
5131
5240
  setBusy("connection");
5132
5241
  setError(null);
5133
- setConnection(await fetchApi$4("/connection/test", { method: "POST" }));
5242
+ setConnection(await fetchApi$6("/connection/test", { method: "POST" }));
5134
5243
  } catch (err) {
5135
5244
  setError(err instanceof Error ? err.message : String(err));
5136
5245
  } finally {
@@ -5141,7 +5250,7 @@ window.__ModuleLoader__.load({
5141
5250
  try {
5142
5251
  setBusy("quota");
5143
5252
  setError(null);
5144
- const updated = await fetchApi$4("/quota", { method: "POST" });
5253
+ const updated = await fetchApi$6("/quota", { method: "POST" });
5145
5254
  setStatus(updated);
5146
5255
  } catch (err) {
5147
5256
  setError(err instanceof Error ? err.message : String(err));
@@ -5149,11 +5258,38 @@ window.__ModuleLoader__.load({
5149
5258
  setBusy(null);
5150
5259
  }
5151
5260
  };
5261
+ const handleCheckinNow = async () => {
5262
+ try {
5263
+ setBusy("checkin");
5264
+ setError(null);
5265
+ const updated = await fetchApi$6("/checkin/now", { method: "POST" });
5266
+ setStatus(normalizeStatus(updated));
5267
+ } catch (err) {
5268
+ setError(err instanceof Error ? err.message : String(err));
5269
+ } finally {
5270
+ setBusy(null);
5271
+ }
5272
+ };
5273
+ const handleCheckinPatch = async (checkin) => {
5274
+ try {
5275
+ setBusy("checkin");
5276
+ setError(null);
5277
+ const updated = await fetchApi$6("/settings", {
5278
+ method: "POST",
5279
+ body: JSON.stringify({ checkin })
5280
+ });
5281
+ setStatus(normalizeStatus(updated));
5282
+ } catch (err) {
5283
+ setError(err instanceof Error ? err.message : String(err));
5284
+ } finally {
5285
+ setBusy(null);
5286
+ }
5287
+ };
5152
5288
  const toggleEnabled = async (enabled) => {
5153
5289
  try {
5154
5290
  setBusy("enabled");
5155
5291
  setError(null);
5156
- const updated = await fetchApi$4("/settings", {
5292
+ const updated = await fetchApi$6("/settings", {
5157
5293
  method: "POST",
5158
5294
  body: JSON.stringify({ enabled })
5159
5295
  });
@@ -5172,12 +5308,12 @@ window.__ModuleLoader__.load({
5172
5308
  try {
5173
5309
  setBusy(`model:${modelId}`);
5174
5310
  setError(null);
5175
- const normalized = normalizeStatus(await fetchApi$4("/settings", {
5311
+ const normalized = normalizeStatus(await fetchApi$6("/settings", {
5176
5312
  method: "POST",
5177
5313
  body: JSON.stringify({ enabledModelIds: next })
5178
5314
  }));
5179
5315
  setStatus(normalized);
5180
- setContextDrafts(contextDraftsFor(normalized));
5316
+ setContextDrafts(contextDraftsFor$1(normalized));
5181
5317
  notifyChange();
5182
5318
  } catch (err) {
5183
5319
  setError(err instanceof Error ? err.message : String(err));
@@ -5190,12 +5326,12 @@ window.__ModuleLoader__.load({
5190
5326
  try {
5191
5327
  setBusy("models-all");
5192
5328
  setError(null);
5193
- const normalized = normalizeStatus(await fetchApi$4("/settings", {
5329
+ const normalized = normalizeStatus(await fetchApi$6("/settings", {
5194
5330
  method: "POST",
5195
5331
  body: JSON.stringify({ enabledModelIds: enabled ? status.models.map((model) => model.id) : [] })
5196
5332
  }));
5197
5333
  setStatus(normalized);
5198
- setContextDrafts(contextDraftsFor(normalized));
5334
+ setContextDrafts(contextDraftsFor$1(normalized));
5199
5335
  notifyChange();
5200
5336
  } catch (err) {
5201
5337
  setError(err instanceof Error ? err.message : String(err));
@@ -5207,7 +5343,7 @@ window.__ModuleLoader__.load({
5207
5343
  try {
5208
5344
  setBusy("effort");
5209
5345
  setError(null);
5210
- const updated = await fetchApi$4("/settings", {
5346
+ const updated = await fetchApi$6("/settings", {
5211
5347
  method: "POST",
5212
5348
  body: JSON.stringify({ defaultReasoningEffort: effort })
5213
5349
  });
@@ -5223,9 +5359,9 @@ window.__ModuleLoader__.load({
5223
5359
  try {
5224
5360
  setBusy("catalog");
5225
5361
  setError(null);
5226
- const normalized = normalizeStatus(await fetchApi$4("/catalog/refresh", { method: "POST" }));
5362
+ const normalized = normalizeStatus(await fetchApi$6("/catalog/refresh", { method: "POST" }));
5227
5363
  setStatus(normalized);
5228
- setContextDrafts(contextDraftsFor(normalized));
5364
+ setContextDrafts(contextDraftsFor$1(normalized));
5229
5365
  notifyChange();
5230
5366
  } catch (err) {
5231
5367
  setError(err instanceof Error ? err.message : String(err));
@@ -5235,7 +5371,7 @@ window.__ModuleLoader__.load({
5235
5371
  };
5236
5372
  const handleSaveContextWindow = async (modelId) => {
5237
5373
  const raw = contextDrafts[modelId] || "";
5238
- const parsed = parsePositiveCapacity(raw);
5374
+ const parsed = parsePositiveCapacity$1(raw);
5239
5375
  if (parsed === null) {
5240
5376
  setError(`Invalid context capacity: ${raw}`);
5241
5377
  return;
@@ -5243,14 +5379,14 @@ window.__ModuleLoader__.load({
5243
5379
  try {
5244
5380
  setSavingModel(modelId);
5245
5381
  setError(null);
5246
- const updated = await fetchApi$4("/settings", {
5382
+ const updated = await fetchApi$6("/settings", {
5247
5383
  method: "POST",
5248
5384
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
5249
5385
  });
5250
5386
  setStatus(updated);
5251
5387
  setContextDrafts((prev) => ({
5252
5388
  ...prev,
5253
- [modelId]: formatCapacity(parsed)
5389
+ [modelId]: formatCapacity$1(parsed)
5254
5390
  }));
5255
5391
  notifyChange();
5256
5392
  } catch (err) {
@@ -5264,7 +5400,7 @@ window.__ModuleLoader__.load({
5264
5400
  try {
5265
5401
  setSavingModel(modelId);
5266
5402
  setError(null);
5267
- const updated = normalizeStatus(await fetchApi$4("/settings", {
5403
+ const updated = normalizeStatus(await fetchApi$6("/settings", {
5268
5404
  method: "POST",
5269
5405
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
5270
5406
  }));
@@ -5273,7 +5409,7 @@ window.__ModuleLoader__.load({
5273
5409
  const model = updated.models.find((candidate) => candidate.id === modelId);
5274
5410
  return model === void 0 ? prev : {
5275
5411
  ...prev,
5276
- [modelId]: formatCapacity(model.defaultContextWindow)
5412
+ [modelId]: formatCapacity$1(model.defaultContextWindow)
5277
5413
  };
5278
5414
  });
5279
5415
  notifyChange();
@@ -5291,12 +5427,12 @@ window.__ModuleLoader__.load({
5291
5427
  try {
5292
5428
  setBusy("context");
5293
5429
  setError(null);
5294
- const updated = normalizeStatus(await fetchApi$4("/settings", {
5430
+ const updated = normalizeStatus(await fetchApi$6("/settings", {
5295
5431
  method: "POST",
5296
5432
  body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
5297
5433
  }));
5298
5434
  setStatus(updated);
5299
- setContextDrafts(contextDraftsFor(updated));
5435
+ setContextDrafts(contextDraftsFor$1(updated));
5300
5436
  notifyChange();
5301
5437
  } catch (err) {
5302
5438
  setError(err instanceof Error ? err.message : String(err));
@@ -5419,36 +5555,87 @@ window.__ModuleLoader__.load({
5419
5555
  })
5420
5556
  ]
5421
5557
  }),
5422
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5558
+ status?.checkin != null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5423
5559
  className: "dsha-group",
5424
5560
  children: [
5425
5561
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5426
5562
  className: "dsha-grouphead",
5427
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.connection })
5563
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.dailyCheckin })
5564
+ }),
5565
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5566
+ className: "dsha-muted",
5567
+ children: t.checkinHint
5428
5568
  }),
5429
5569
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5430
5570
  className: "dsha-row",
5431
- style: { marginBottom: 12 },
5571
+ style: { marginBottom: 8 },
5432
5572
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5433
5573
  className: "dsha-label",
5434
5574
  style: { fontWeight: 600 },
5435
- children: t.enableProvider
5575
+ children: t.checkinAuto
5436
5576
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5437
5577
  type: "checkbox",
5438
- checked: status?.enabled !== false,
5578
+ checked: status.checkin.enabled,
5439
5579
  disabled: busy !== null,
5440
- onChange: (e) => void toggleEnabled(e.currentTarget.checked)
5580
+ onChange: (event) => void handleCheckinPatch({ enabled: event.currentTarget.checked })
5441
5581
  })]
5442
5582
  }),
5443
5583
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5444
5584
  className: "dsha-row",
5445
5585
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5446
5586
  className: "dsha-label",
5447
- children: t.provider
5448
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5587
+ children: t.dailyCheckin
5588
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5449
5589
  className: "dsha-value",
5450
- children: t.providerValue
5451
- })]
5590
+ children: [
5591
+ t.checkinToday.replace("{done}", String(status.checkin.doneToday)).replace("{total}", String(status.checkin.totalAccounts)),
5592
+ status.checkin.skippedToday > 0 ? ` · ${t.checkinSkipped.replace("{count}", String(status.checkin.skippedToday))}` : "",
5593
+ status.checkin.failedToday > 0 ? ` · ${t.checkinFailed.replace("{count}", String(status.checkin.failedToday))}` : "",
5594
+ ` · ${status.checkin.lastRunAt === null ? t.checkinNever : t.checkinLastRun.replace("{time}", new Date(status.checkin.lastRunAt).toLocaleString())}`
5595
+ ]
5596
+ })]
5597
+ }),
5598
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5599
+ className: "dsha-actions",
5600
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5601
+ className: "dsha-btn",
5602
+ disabled: busy !== null,
5603
+ onClick: () => void handleCheckinNow(),
5604
+ children: busy === "checkin" ? t.checkinRunning : t.checkinNow
5605
+ })
5606
+ })
5607
+ ]
5608
+ }) : null,
5609
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5610
+ className: "dsha-group",
5611
+ children: [
5612
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5613
+ className: "dsha-grouphead",
5614
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.connection })
5615
+ }),
5616
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5617
+ className: "dsha-row",
5618
+ style: { marginBottom: 12 },
5619
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5620
+ className: "dsha-label",
5621
+ style: { fontWeight: 600 },
5622
+ children: t.enableProvider
5623
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5624
+ type: "checkbox",
5625
+ checked: status?.enabled !== false,
5626
+ disabled: busy !== null,
5627
+ onChange: (e) => void toggleEnabled(e.currentTarget.checked)
5628
+ })]
5629
+ }),
5630
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5631
+ className: "dsha-row",
5632
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5633
+ className: "dsha-label",
5634
+ children: t.provider
5635
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5636
+ className: "dsha-value",
5637
+ children: t.providerValue
5638
+ })]
5452
5639
  }),
5453
5640
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5454
5641
  className: "dsha-row",
@@ -5498,7 +5685,7 @@ window.__ModuleLoader__.load({
5498
5685
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
5499
5686
  title: [
5500
5687
  model.id,
5501
- formatCapacity(model.contextWindow),
5688
+ formatCapacity$1(model.contextWindow),
5502
5689
  model.supportsImage ? t.imageSupport : t.textOnly,
5503
5690
  ...model.reasoningEfforts && model.reasoningEfforts.length > 0 ? [model.reasoningEfforts.join("/")] : []
5504
5691
  ].join(" · "),
@@ -5562,11 +5749,11 @@ window.__ModuleLoader__.load({
5562
5749
  }),
5563
5750
  strayEffort !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5564
5751
  value: strayEffort,
5565
- children: `${EFFORT_LABELS[strayEffort]} (${t.effortUnsupported})`
5752
+ children: `${EFFORT_LABELS$1[strayEffort]} (${t.effortUnsupported})`
5566
5753
  }) : null,
5567
5754
  effortChoices.map((choice) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5568
5755
  value: choice.value,
5569
- children: choice.models.length === allModels.length ? EFFORT_LABELS[choice.value] : `${EFFORT_LABELS[choice.value]} (${choice.models.length}/${allModels.length})`
5756
+ children: choice.models.length === allModels.length ? EFFORT_LABELS$1[choice.value] : `${EFFORT_LABELS$1[choice.value]} (${choice.models.length}/${allModels.length})`
5570
5757
  }, choice.value))
5571
5758
  ]
5572
5759
  })]
@@ -5615,7 +5802,940 @@ window.__ModuleLoader__.load({
5615
5802
  if (event.key === "Enter") handleSaveContextWindow(model.id);
5616
5803
  }
5617
5804
  }),
5618
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "tokens" }),
5805
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "tokens" }),
5806
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5807
+ type: "button",
5808
+ className: "dsha-context-save",
5809
+ disabled: savingModel === model.id,
5810
+ onClick: () => void handleSaveContextWindow(model.id),
5811
+ children: savingModel === model.id ? t.saving : t.save
5812
+ }),
5813
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5814
+ type: "button",
5815
+ className: "dsha-context-save dsha-context-reset",
5816
+ "aria-label": `${model.name} ${t.contextWindowReset}`,
5817
+ disabled: savingModel === model.id || status?.contextWindowOverrides[model.id] === void 0,
5818
+ onClick: () => void handleResetContextWindow(model.id),
5819
+ children: t.contextWindowReset
5820
+ })
5821
+ ]
5822
+ })]
5823
+ }, model.id)),
5824
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5825
+ className: "dsha-actions",
5826
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5827
+ className: "dsha-btn",
5828
+ disabled: busy !== null || overrideCount === 0,
5829
+ onClick: () => void handleResetAllContextWindows(),
5830
+ children: t.contextWindowResetAll
5831
+ })
5832
+ })
5833
+ ]
5834
+ })
5835
+ ]
5836
+ }),
5837
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5838
+ className: "dsha-group",
5839
+ children: [
5840
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5841
+ className: "dsha-grouphead",
5842
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.quotaSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5843
+ className: "dsha-btn",
5844
+ disabled: busy !== null || !authenticated,
5845
+ onClick: () => void handleRefreshQuota(),
5846
+ children: busy === "quota" ? t.refreshingQuota : t.refreshQuota
5847
+ })]
5848
+ }),
5849
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5850
+ className: "dsha-muted",
5851
+ children: t.quotaDesc
5852
+ }),
5853
+ !authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5854
+ className: "dsha-empty",
5855
+ children: t.signedOut
5856
+ }) : quota === null || quota === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5857
+ className: "dsha-empty",
5858
+ children: busy === "quota" ? t.refreshingQuota : t.quotaEmpty
5859
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5860
+ className: "dsha-quota-card",
5861
+ children: [
5862
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5863
+ className: "dsha-quota-title",
5864
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: quota.packageName || t.quotaPackage }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: quota.remainingCredits !== null ? `${quota.remainingCredits} ${t.credits}` : "—" })]
5865
+ }),
5866
+ quota.cycleUsedCredits !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5867
+ className: "dsha-row",
5868
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5869
+ className: "dsha-label",
5870
+ children: t.quotaCycle
5871
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5872
+ className: "dsha-value",
5873
+ children: [
5874
+ quota.cycleUsedCredits,
5875
+ quota.cycleCredits !== null ? ` / ${quota.cycleCredits}` : "",
5876
+ ` ${t.credits}`
5877
+ ]
5878
+ })]
5879
+ }),
5880
+ quota.cycleEndsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5881
+ className: "dsha-row",
5882
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5883
+ className: "dsha-label",
5884
+ children: t.quotaReset
5885
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5886
+ className: "dsha-value",
5887
+ children: [formatDate$1(quota.cycleEndsAt), formatReset$1(quota.cycleEndsAt) ? ` · ${formatReset$1(quota.cycleEndsAt)}` : ""]
5888
+ })]
5889
+ }),
5890
+ quota.meters.map((meter) => {
5891
+ const remaining = meter.remainingFraction;
5892
+ const percent = remaining === null ? null : Math.round(remaining * 100);
5893
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5894
+ className: "dsha-meter-wrap",
5895
+ children: [
5896
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5897
+ className: "dsha-meter-label",
5898
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: meter.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: percent === null ? meter.limit ?? "—" : `${percent}% left` })]
5899
+ }),
5900
+ percent !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5901
+ className: "dsha-meter dsha-meter-green",
5902
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: { width: `${percent}%` } })
5903
+ }),
5904
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5905
+ className: "dsha-meter-meta",
5906
+ children: [meter.used !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5907
+ meter.used,
5908
+ " / ",
5909
+ meter.limit ?? "—"
5910
+ ] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5911
+ t.quotaReset,
5912
+ ": ",
5913
+ formatReset$1(meter.resetsAt)
5914
+ ] })]
5915
+ })
5916
+ ]
5917
+ }, meter.id);
5918
+ }),
5919
+ quota.meters.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5920
+ className: "dsha-empty",
5921
+ children: t.quotaEmpty
5922
+ }),
5923
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5924
+ className: "dsha-timestamp",
5925
+ children: t.updatedAt.replace("{time}", new Date(quota.fetchedAt).toLocaleString())
5926
+ })
5927
+ ]
5928
+ })
5929
+ ]
5930
+ }),
5931
+ error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5932
+ className: "dsha-error",
5933
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: error })
5934
+ })
5935
+ ]
5936
+ });
5937
+ }
5938
+ //#endregion
5939
+ //#region src/shared/zhipu-contracts.ts
5940
+ /** Every level this route can name, in escalating order (the card's sort key). */
5941
+ const ZHIPU_REASONING_EFFORTS = [
5942
+ "low",
5943
+ "high",
5944
+ "max"
5945
+ ];
5946
+ ({
5947
+ none: 0,
5948
+ minimal: 1,
5949
+ low: 2,
5950
+ medium: 3,
5951
+ high: 4,
5952
+ xhigh: 5,
5953
+ max: 6
5954
+ }).high;
5955
+ //#endregion
5956
+ //#region src/client/zhipu/locales.ts
5957
+ const NS_ZHIPU = "dsh-zhipu";
5958
+ const zh$1 = {
5959
+ ...accountPoolZh,
5960
+ title: "GLM(智谱 Coding Plan)",
5961
+ pageDesc: "添加智谱 / Z.ai 的 GLM Coding Plan API Key,管理可用模型、上下文窗口与额度。",
5962
+ account: "账号",
5963
+ signedIn: "已登录",
5964
+ signedOut: "未登录",
5965
+ region: "区域",
5966
+ regionIntl: "国际区 (api.z.ai)",
5967
+ regionCn: "国区 (open.bigmodel.cn)",
5968
+ keyHint: "Key 尾号",
5969
+ plan: "套餐",
5970
+ planUnknown: "—",
5971
+ renews: "续费于",
5972
+ authenticatedAt: "添加时间",
5973
+ storage: "凭据存储",
5974
+ storageNotice: "API Key 由 Host 保存于本地加密存储,不会进入浏览器。",
5975
+ signOut: "注销",
5976
+ addKeySection: "添加 API Key",
5977
+ addKeyHint: "在对应开放平台的「API Keys」页创建 Key 后粘贴到此处。它必须来自你订阅 Coding Plan 的那个平台:国区 Key 与国际区 Key 互不通用,开放平台(/api/paas/v4)的通用 Key 在订阅接口上会被拒绝。",
5978
+ keyPlaceholder: "粘贴 GLM Coding Plan API Key",
5979
+ keySave: "保存并验证",
5980
+ keySaving: "验证中...",
5981
+ keySaved: "已保存",
5982
+ connection: "连接",
5983
+ provider: "Provider",
5984
+ providerValue: "GLM(智谱 Coding Plan)· zhipu-coding-plan",
5985
+ connectionState: "连接状态",
5986
+ connected: "已连接",
5987
+ untested: "未测试",
5988
+ testConnection: "测试连接",
5989
+ testingConnection: "测试中...",
5990
+ routeOwned: "模型路由由本插件提供",
5991
+ routeConflict: "模型路由已被其他 Provider 占用:{detail}。请在 DSH 设置中移除重复的 Provider 配置后重试。",
5992
+ modelsSection: "模型",
5993
+ enableProvider: "启用此供应商",
5994
+ modelsHint: "勾选后模型才会出现在对话页的模型选择列表中;全部取消勾选或关闭上方开关可在列表中隐藏该供应商。",
5995
+ refreshCatalog: "刷新模型目录",
5996
+ refreshingCatalog: "刷新中...",
5997
+ selectAll: "全选",
5998
+ unselectAll: "全不选",
5999
+ effectiveWindow: "有效窗口",
6000
+ enhanced: "增强功能",
6001
+ defaultReasoningEffort: "默认思考深度",
6002
+ defaultReasoningEffortHint: "仅对声明了思考档位的模型生效。上游只接受 low / high / max,其余档位会收敛到最近的可用档位后发出(不支持的档位会直接报错)。",
6003
+ defaultEffortAuto: "使用 Provider 默认值",
6004
+ contextWindowSection: "模型上下文窗口",
6005
+ contextWindowHint: "默认取该模型官方声明的上下文窗口;可覆盖为自定义容量,该值用于 DSH 的压缩与溢出判断,可输入 1M、512K、200K 等容量。",
6006
+ contextWindowReset: "恢复默认",
6007
+ contextWindowResetAll: "全部恢复默认",
6008
+ contextWindowResetAllConfirm: "确定把已改过的模型上下文窗口全部恢复为默认值吗?",
6009
+ contextWindowNoneEnabled: "还没有勾选任何模型。在上方勾选后,这里会出现该模型的上下文窗口设置。",
6010
+ save: "保存",
6011
+ saved: "已保存",
6012
+ saving: "保存中...",
6013
+ quotaSection: "用量与配额",
6014
+ quotaDesc: "数据来自 GLM Coding Plan 的用量接口,页面可见时最多每 60 秒刷新一次。Coding Plan 同时受 5 小时额度与每周额度限制。",
6015
+ refreshQuota: "刷新用量",
6016
+ refreshingQuota: "刷新中...",
6017
+ quotaEmpty: "暂无配额数据,点击「刷新用量」重试。",
6018
+ quotaUnavailable: "该账号没有可用的配额数据(通常是套餐未生效,或 Key 不属于 Coding Plan)。",
6019
+ quotaError: "配额读取失败",
6020
+ updatedAt: "更新时间:{time}",
6021
+ loading: "加载中...",
6022
+ tokens: "tokens",
6023
+ left: "剩余",
6024
+ resetAt: "重置于",
6025
+ now: "即将重置"
6026
+ };
6027
+ const en$1 = {
6028
+ ...accountPoolEn,
6029
+ title: "GLM (Zhipu Coding Plan)",
6030
+ pageDesc: "Add a GLM Coding Plan API key for Zhipu / Z.ai and manage models, context windows, and quota.",
6031
+ account: "Account",
6032
+ signedIn: "Signed in",
6033
+ signedOut: "Not signed in",
6034
+ region: "Region",
6035
+ regionIntl: "International (api.z.ai)",
6036
+ regionCn: "China (open.bigmodel.cn)",
6037
+ keyHint: "Key suffix",
6038
+ plan: "Plan",
6039
+ planUnknown: "—",
6040
+ renews: "renews",
6041
+ authenticatedAt: "Added at",
6042
+ storage: "Credential storage",
6043
+ storageNotice: "The API key is stored locally by the Host in encrypted storage and never reaches the browser.",
6044
+ signOut: "Sign out",
6045
+ addKeySection: "Add an API key",
6046
+ addKeyHint: "Create a key on the console’s API Keys page and paste it here. It must come from the platform your Coding Plan was bought on: China and international keys are not interchangeable, and a general open-platform key (/api/paas/v4) is rejected by the subscription surface.",
6047
+ keyPlaceholder: "Paste a GLM Coding Plan API key",
6048
+ keySave: "Save and verify",
6049
+ keySaving: "Verifying...",
6050
+ keySaved: "Saved",
6051
+ connection: "Connection",
6052
+ provider: "Provider",
6053
+ providerValue: "GLM (Zhipu Coding Plan) · zhipu-coding-plan",
6054
+ connectionState: "Connection state",
6055
+ connected: "Connected",
6056
+ untested: "Untested",
6057
+ testConnection: "Test connection",
6058
+ testingConnection: "Testing...",
6059
+ routeOwned: "This plugin serves the model route",
6060
+ routeConflict: "Another provider already owns the model route: {detail}. Remove the duplicate provider configuration in DSH settings and reload.",
6061
+ modelsSection: "Models",
6062
+ enableProvider: "Enable this provider",
6063
+ modelsHint: "Checked models appear in the DSH conversation model list; unchecking all or turning off the switch hides this provider.",
6064
+ refreshCatalog: "Refresh catalog",
6065
+ refreshingCatalog: "Refreshing...",
6066
+ selectAll: "Select all",
6067
+ unselectAll: "Deselect all",
6068
+ effectiveWindow: "Effective window",
6069
+ enhanced: "Enhanced features",
6070
+ defaultReasoningEffort: "Default reasoning effort",
6071
+ defaultReasoningEffortHint: "Applies only to models that declare a reasoning ladder. The provider accepts low / high / max; any other level is converged onto the nearest supported one before it is sent, because an unsupported level is rejected outright.",
6072
+ defaultEffortAuto: "Use provider default",
6073
+ contextWindowSection: "Model context window",
6074
+ contextWindowHint: "Defaults to the window the model itself declares; override it with the capacity DSH should use for compaction and overflow decisions (e.g., 1M, 512K, 200K).",
6075
+ contextWindowReset: "Restore default",
6076
+ contextWindowResetAll: "Restore all defaults",
6077
+ contextWindowResetAllConfirm: "Restore every changed model context window to its default?",
6078
+ contextWindowNoneEnabled: "No model is checked yet. Check one above and its context window setting appears here.",
6079
+ save: "Save",
6080
+ saved: "Saved",
6081
+ saving: "Saving...",
6082
+ quotaSection: "Usage & quota",
6083
+ quotaDesc: "Read from the GLM Coding Plan usage endpoints; refreshes at most once every 60 seconds while visible. A Coding Plan is bounded by both a 5-hour and a weekly allowance.",
6084
+ refreshQuota: "Refresh quota",
6085
+ refreshingQuota: "Refreshing...",
6086
+ quotaEmpty: "No quota data yet — use “Refresh quota” to retry.",
6087
+ quotaUnavailable: "This account reports no usable quota (usually an inactive plan, or a key that is not a Coding Plan key).",
6088
+ quotaError: "Quota lookup failed",
6089
+ updatedAt: "Updated at: {time}",
6090
+ loading: "Loading...",
6091
+ tokens: "tokens",
6092
+ left: "left",
6093
+ resetAt: "Resets at",
6094
+ now: "resetting now"
6095
+ };
6096
+ const dictionaries$1 = {
6097
+ zh: zh$1,
6098
+ "zh-CN": zh$1,
6099
+ en: en$1,
6100
+ "en-US": en$1
6101
+ };
6102
+ //#endregion
6103
+ //#region src/client/zhipu/ZhipuSection.tsx
6104
+ /**
6105
+ * Display label per reasoning level. The locale dictionary only accepts flat
6106
+ * string values, so this table lives with the control that renders it.
6107
+ */
6108
+ const EFFORT_LABELS = {
6109
+ low: "Low",
6110
+ high: "High",
6111
+ max: "Max"
6112
+ };
6113
+ const API$5 = "/zhipu/api";
6114
+ async function fetchApi$5(path, options) {
6115
+ const res = await fetch(`${API$5}${path}`, {
6116
+ ...options,
6117
+ headers: {
6118
+ "Content-Type": "application/json",
6119
+ ...options?.headers
6120
+ }
6121
+ });
6122
+ const json = await res.json();
6123
+ if (!res.ok || !json.ok) throw new Error(json.error || `HTTP ${res.status}`);
6124
+ return json.value;
6125
+ }
6126
+ /** Parse "1M", "512K", "200000" into a positive integer token count. */
6127
+ function parsePositiveCapacity(value) {
6128
+ const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
6129
+ if (matched === null) return null;
6130
+ const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
6131
+ const parsed = Number(matched[1]) * multiplier;
6132
+ return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
6133
+ }
6134
+ function formatCapacity(value) {
6135
+ if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
6136
+ if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
6137
+ return String(value);
6138
+ }
6139
+ /**
6140
+ * Seed one draft per model from a status payload. Also run after a model
6141
+ * toggle: a model that was just enabled has no draft yet, and the context
6142
+ * window section only renders enabled models.
6143
+ */
6144
+ function contextDraftsFor(status) {
6145
+ const drafts = {};
6146
+ for (const model of status.models) drafts[model.id] = formatCapacity(status.contextWindowOverrides[model.id] || model.defaultContextWindow);
6147
+ return drafts;
6148
+ }
6149
+ function formatDate(ms) {
6150
+ if (ms === void 0 || ms === null || ms <= 0) return "—";
6151
+ try {
6152
+ return new Intl.DateTimeFormat(void 0, {
6153
+ dateStyle: "medium",
6154
+ timeStyle: "short"
6155
+ }).format(ms);
6156
+ } catch {
6157
+ return "—";
6158
+ }
6159
+ }
6160
+ function formatReset(resetsAt, nowLabel = "now") {
6161
+ if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
6162
+ const diff = resetsAt - Date.now();
6163
+ if (diff <= 0) return nowLabel;
6164
+ const mins = Math.floor(diff / 6e4);
6165
+ const hours = Math.floor(mins / 60);
6166
+ const days = Math.floor(hours / 24);
6167
+ if (days > 0) return `${days}d ${hours % 24}h`;
6168
+ if (hours > 0) return `${hours}h ${mins % 60}m`;
6169
+ return `${mins}m`;
6170
+ }
6171
+ function ZhipuSection({ onModelChange, loadModelDirectory }) {
6172
+ const [status, setStatus] = (0, react.useState)(null);
6173
+ const [loading, setLoading] = (0, react.useState)(true);
6174
+ const [busy, setBusy] = (0, react.useState)(null);
6175
+ const [error, setError] = (0, react.useState)(null);
6176
+ const [contextDrafts, setContextDrafts] = (0, react.useState)({});
6177
+ const [savingModel, setSavingModel] = (0, react.useState)(null);
6178
+ const [apiKey, setApiKey] = (0, react.useState)("");
6179
+ const [region, setRegion] = (0, react.useState)("intl");
6180
+ /** Follow-up poll owed while the host refreshes the quota behind an answer. */
6181
+ const quotaFollowUp = (0, react.useRef)(null);
6182
+ const t = zh$1;
6183
+ const notifyChange = (0, react.useCallback)(() => {
6184
+ onModelChange?.();
6185
+ loadModelDirectory?.();
6186
+ }, [onModelChange, loadModelDirectory]);
6187
+ const loadStatus = (0, react.useCallback)(async (quiet = false) => {
6188
+ if (!quiet) setError(null);
6189
+ try {
6190
+ const data = await fetchApi$5("/status");
6191
+ setStatus(data);
6192
+ setContextDrafts(contextDraftsFor(data));
6193
+ quotaFollowUp.current ??= createQuotaFollowUp();
6194
+ quotaFollowUp.current.observe(data.quotaRefreshing === true, () => {
6195
+ loadStatus(true);
6196
+ });
6197
+ } catch (err) {
6198
+ if (!quiet) setError(err instanceof Error ? err.message : String(err));
6199
+ } finally {
6200
+ setLoading(false);
6201
+ }
6202
+ }, []);
6203
+ (0, react.useEffect)(() => {
6204
+ loadStatus();
6205
+ const refreshWhenVisible = () => {
6206
+ if (document.visibilityState === "visible") loadStatus(true);
6207
+ };
6208
+ document.addEventListener("visibilitychange", refreshWhenVisible);
6209
+ const timer = window.setInterval(refreshWhenVisible, 6e4);
6210
+ return () => {
6211
+ window.clearInterval(timer);
6212
+ document.removeEventListener("visibilitychange", refreshWhenVisible);
6213
+ quotaFollowUp.current?.cancel();
6214
+ };
6215
+ }, [loadStatus]);
6216
+ /**
6217
+ * Save one pasted key.
6218
+ *
6219
+ * The host verifies it against the deployment before persisting, so a key
6220
+ * from the wrong console fails here with a message naming the console it
6221
+ * belongs to rather than inside a conversation later.
6222
+ */
6223
+ const handleAddKey = async () => {
6224
+ try {
6225
+ setBusy("apikey");
6226
+ setError(null);
6227
+ const updated = await fetchApi$5("/accounts/add", {
6228
+ method: "POST",
6229
+ body: JSON.stringify({
6230
+ apiKey,
6231
+ region
6232
+ })
6233
+ });
6234
+ setStatus(updated);
6235
+ setContextDrafts(contextDraftsFor(updated));
6236
+ setApiKey("");
6237
+ notifyChange();
6238
+ } catch (err) {
6239
+ setError(err instanceof Error ? err.message : String(err));
6240
+ } finally {
6241
+ setBusy(null);
6242
+ }
6243
+ };
6244
+ /** One account-level action on the shared pool card. */
6245
+ const handleAccountAction = async (action, accountId) => {
6246
+ try {
6247
+ setBusy(`${action}-${accountId}`);
6248
+ setError(null);
6249
+ const updated = await fetchApi$5("/accounts/action", {
6250
+ method: "POST",
6251
+ body: JSON.stringify({
6252
+ action,
6253
+ accountId
6254
+ })
6255
+ });
6256
+ setStatus(updated);
6257
+ notifyChange();
6258
+ } catch (err) {
6259
+ setError(err instanceof Error ? err.message : String(err));
6260
+ } finally {
6261
+ setBusy(null);
6262
+ }
6263
+ };
6264
+ const handleSetStrategy = async (strategy) => {
6265
+ try {
6266
+ setBusy("strategy");
6267
+ setError(null);
6268
+ const updated = await fetchApi$5("/accounts/action", {
6269
+ method: "POST",
6270
+ body: JSON.stringify({
6271
+ action: "strategy",
6272
+ strategy
6273
+ })
6274
+ });
6275
+ setStatus(updated);
6276
+ } catch (err) {
6277
+ setError(err instanceof Error ? err.message : String(err));
6278
+ } finally {
6279
+ setBusy(null);
6280
+ }
6281
+ };
6282
+ const handleRefreshQuota = async () => {
6283
+ try {
6284
+ setBusy("quota");
6285
+ setError(null);
6286
+ const updated = await fetchApi$5("/quota", { method: "POST" });
6287
+ setStatus(updated);
6288
+ } catch (err) {
6289
+ setError(err instanceof Error ? err.message : String(err));
6290
+ } finally {
6291
+ setBusy(null);
6292
+ }
6293
+ };
6294
+ const handleRefreshCatalog = async () => {
6295
+ try {
6296
+ setBusy("catalog");
6297
+ setError(null);
6298
+ const updated = await fetchApi$5("/catalog/refresh", { method: "POST" });
6299
+ setStatus(updated);
6300
+ setContextDrafts(contextDraftsFor(updated));
6301
+ notifyChange();
6302
+ } catch (err) {
6303
+ setError(err instanceof Error ? err.message : String(err));
6304
+ } finally {
6305
+ setBusy(null);
6306
+ }
6307
+ };
6308
+ const handleTestConnection = async () => {
6309
+ try {
6310
+ setBusy("connection");
6311
+ setError(null);
6312
+ await fetchApi$5("/connection/test", { method: "POST" });
6313
+ await loadStatus(true);
6314
+ } catch (err) {
6315
+ setError(err instanceof Error ? err.message : String(err));
6316
+ } finally {
6317
+ setBusy(null);
6318
+ }
6319
+ };
6320
+ const applyEnabled = async (enabledModelIds) => {
6321
+ try {
6322
+ const updated = await fetchApi$5("/models", {
6323
+ method: "POST",
6324
+ body: JSON.stringify({ enabledModelIds })
6325
+ });
6326
+ setStatus(updated);
6327
+ setContextDrafts(contextDraftsFor(updated));
6328
+ notifyChange();
6329
+ } catch (err) {
6330
+ setError(err instanceof Error ? err.message : String(err));
6331
+ }
6332
+ };
6333
+ const toggleEnabled = async (enabled) => {
6334
+ setStatus((prev) => prev ? {
6335
+ ...prev,
6336
+ enabled
6337
+ } : prev);
6338
+ try {
6339
+ const updated = await fetchApi$5("/settings", {
6340
+ method: "POST",
6341
+ body: JSON.stringify({ enabled })
6342
+ });
6343
+ setStatus(updated);
6344
+ notifyChange();
6345
+ } catch (err) {
6346
+ setError(err instanceof Error ? err.message : String(err));
6347
+ loadStatus(true);
6348
+ }
6349
+ };
6350
+ const toggleModel = (modelId, checked) => {
6351
+ if (!status) return;
6352
+ const current = status.models.filter((model) => model.enabled).map((model) => model.id);
6353
+ const next = checked ? [.../* @__PURE__ */ new Set([...current, modelId])] : current.filter((id) => id !== modelId);
6354
+ applyEnabled(next);
6355
+ };
6356
+ const setAllModels = (selectAll) => {
6357
+ if (!status || status.models.length === 0) return;
6358
+ applyEnabled(selectAll ? status.models.map((model) => model.id) : []);
6359
+ };
6360
+ const handleUpdateEffort = async (effort) => {
6361
+ try {
6362
+ const updated = await fetchApi$5("/settings", {
6363
+ method: "POST",
6364
+ body: JSON.stringify({ defaultReasoningEffort: effort })
6365
+ });
6366
+ setStatus(updated);
6367
+ notifyChange();
6368
+ } catch (err) {
6369
+ setError(err instanceof Error ? err.message : String(err));
6370
+ }
6371
+ };
6372
+ const handleSaveContextWindow = async (modelId) => {
6373
+ const raw = contextDrafts[modelId] || "";
6374
+ const parsed = parsePositiveCapacity(raw);
6375
+ if (parsed === null) {
6376
+ setError(`Invalid context capacity: ${raw}`);
6377
+ return;
6378
+ }
6379
+ try {
6380
+ setSavingModel(modelId);
6381
+ setError(null);
6382
+ const updated = await fetchApi$5("/settings", {
6383
+ method: "POST",
6384
+ body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
6385
+ });
6386
+ setStatus(updated);
6387
+ setContextDrafts((prev) => ({
6388
+ ...prev,
6389
+ [modelId]: formatCapacity(parsed)
6390
+ }));
6391
+ notifyChange();
6392
+ } catch (err) {
6393
+ setError(err instanceof Error ? err.message : String(err));
6394
+ } finally {
6395
+ setSavingModel(null);
6396
+ }
6397
+ };
6398
+ /** Clear one override; the row falls back to the declared window. */
6399
+ const handleResetContextWindow = async (modelId) => {
6400
+ try {
6401
+ setSavingModel(modelId);
6402
+ setError(null);
6403
+ const updated = await fetchApi$5("/settings", {
6404
+ method: "POST",
6405
+ body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
6406
+ });
6407
+ setStatus(updated);
6408
+ setContextDrafts((prev) => {
6409
+ const model = updated.models.find((candidate) => candidate.id === modelId);
6410
+ return model === void 0 ? prev : {
6411
+ ...prev,
6412
+ [modelId]: formatCapacity(model.defaultContextWindow)
6413
+ };
6414
+ });
6415
+ notifyChange();
6416
+ } catch (err) {
6417
+ setError(err instanceof Error ? err.message : String(err));
6418
+ } finally {
6419
+ setSavingModel(null);
6420
+ }
6421
+ };
6422
+ /** Clear every stored override, including models the picker no longer shows. */
6423
+ const handleResetAllContextWindows = async () => {
6424
+ const models = Object.keys(status?.contextWindowOverrides ?? {});
6425
+ if (models.length === 0) return;
6426
+ if (typeof window !== "undefined" && !window.confirm(t.contextWindowResetAllConfirm)) return;
6427
+ try {
6428
+ setBusy("context");
6429
+ setError(null);
6430
+ const updated = await fetchApi$5("/settings", {
6431
+ method: "POST",
6432
+ body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
6433
+ });
6434
+ setStatus(updated);
6435
+ setContextDrafts(contextDraftsFor(updated));
6436
+ notifyChange();
6437
+ } catch (err) {
6438
+ setError(err instanceof Error ? err.message : String(err));
6439
+ } finally {
6440
+ setBusy(null);
6441
+ }
6442
+ };
6443
+ if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6444
+ className: "dsha-page",
6445
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6446
+ className: "dsha-empty",
6447
+ children: t.loading
6448
+ })
6449
+ });
6450
+ const contextModels = status?.models.filter((model) => model.enabled) ?? [];
6451
+ const overrideCount = Object.keys(status?.contextWindowOverrides ?? {}).length;
6452
+ const quota = status?.quota;
6453
+ const account = status?.account;
6454
+ const hasMeters = (quota?.meters.length ?? 0) > 0;
6455
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6456
+ className: "dsha-page",
6457
+ children: [
6458
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(AccountPoolSection, {
6459
+ accounts: status?.accounts ?? [],
6460
+ activeAccountId: status?.activeAccountId,
6461
+ rotationStrategy: status?.rotationStrategy ?? "sequential",
6462
+ busy,
6463
+ labels: t,
6464
+ onLogin: () => {
6465
+ document.querySelector(`.dsha-page input[type=password]`)?.focus();
6466
+ },
6467
+ onSetPrimary: (accountId) => void handleAccountAction("set-primary", accountId),
6468
+ onDelete: (accountId) => void handleAccountAction("delete", accountId),
6469
+ onClearCooldown: (accountId) => void handleAccountAction("clear-cooldown", accountId),
6470
+ onSetStrategy: (strategy) => void handleSetStrategy(strategy),
6471
+ storageValue: status?.storagePath || "—",
6472
+ renderDetails: (entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
6473
+ entry.keyHint && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6474
+ t.keyHint,
6475
+ ": ",
6476
+ entry.keyHint
6477
+ ] }),
6478
+ entry.region && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6479
+ t.region,
6480
+ ": ",
6481
+ entry.region === "cn" ? t.regionCn : t.regionIntl
6482
+ ] }),
6483
+ entry.planLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6484
+ t.plan,
6485
+ ": ",
6486
+ entry.planLabel
6487
+ ] })
6488
+ ] }),
6489
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6490
+ className: "dsha-muted",
6491
+ style: { paddingTop: 12 },
6492
+ children: t.addKeyHint
6493
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6494
+ className: "dsha-capacity-control dshzp-keyrow",
6495
+ children: [
6496
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
6497
+ className: "dsha-select",
6498
+ "aria-label": t.region,
6499
+ value: region,
6500
+ onChange: (event) => setRegion(event.currentTarget.value === "cn" ? "cn" : "intl"),
6501
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6502
+ value: "intl",
6503
+ children: t.regionIntl
6504
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6505
+ value: "cn",
6506
+ children: t.regionCn
6507
+ })]
6508
+ }),
6509
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6510
+ type: "password",
6511
+ "aria-label": t.addKeySection,
6512
+ placeholder: t.keyPlaceholder,
6513
+ value: apiKey,
6514
+ onChange: (event) => setApiKey(event.currentTarget.value),
6515
+ onKeyDown: (event) => {
6516
+ if (event.key === "Enter" && apiKey.trim() !== "") handleAddKey();
6517
+ }
6518
+ }),
6519
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6520
+ type: "button",
6521
+ className: "dsha-context-save",
6522
+ disabled: busy !== null || apiKey.trim() === "",
6523
+ onClick: () => void handleAddKey(),
6524
+ children: busy === "apikey" ? t.keySaving : t.keySave
6525
+ })
6526
+ ]
6527
+ })]
6528
+ }),
6529
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
6530
+ className: "dsha-group",
6531
+ children: [
6532
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6533
+ className: "dsha-grouphead",
6534
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.connection })
6535
+ }),
6536
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6537
+ className: "dsha-row",
6538
+ style: { marginBottom: 12 },
6539
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6540
+ className: "dsha-label",
6541
+ style: { fontWeight: 600 },
6542
+ children: t.enableProvider
6543
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6544
+ type: "checkbox",
6545
+ checked: status?.enabled !== false,
6546
+ disabled: busy !== null,
6547
+ onChange: (e) => void toggleEnabled(e.currentTarget.checked)
6548
+ })]
6549
+ }),
6550
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6551
+ className: "dsha-row",
6552
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6553
+ className: "dsha-label",
6554
+ children: t.provider
6555
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6556
+ className: "dsha-value",
6557
+ children: t.providerValue
6558
+ })]
6559
+ }),
6560
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6561
+ className: "dsha-row",
6562
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6563
+ className: "dsha-label",
6564
+ children: t.connectionState
6565
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6566
+ className: "dsha-value",
6567
+ children: status?.authenticated ? t.connected : t.untested
6568
+ })]
6569
+ }),
6570
+ account && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6571
+ className: "dsha-row",
6572
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6573
+ className: "dsha-label",
6574
+ children: t.account
6575
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6576
+ className: "dsha-value",
6577
+ children: [
6578
+ account.keyHint,
6579
+ " · ",
6580
+ account.region === "cn" ? t.regionCn : t.regionIntl
6581
+ ]
6582
+ })]
6583
+ }),
6584
+ account?.planLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6585
+ className: "dsha-row",
6586
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6587
+ className: "dsha-label",
6588
+ children: t.plan
6589
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6590
+ className: "dsha-value",
6591
+ children: account.planLabel
6592
+ })]
6593
+ }),
6594
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6595
+ className: "dsha-row",
6596
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6597
+ className: "dsha-label",
6598
+ children: t.storage
6599
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6600
+ className: "dsha-value",
6601
+ children: status?.storagePath ?? "—"
6602
+ })]
6603
+ }),
6604
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6605
+ className: "dsha-notice",
6606
+ children: status?.serving === false && status.conflict ? t.routeConflict.replace("{detail}", status.conflict) : t.routeOwned
6607
+ }),
6608
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6609
+ className: "dsha-actions",
6610
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6611
+ className: "dsha-btn",
6612
+ disabled: busy !== null || !status?.authenticated,
6613
+ onClick: () => void handleTestConnection(),
6614
+ children: busy === "connection" ? t.testingConnection : t.testConnection
6615
+ })
6616
+ })
6617
+ ]
6618
+ }),
6619
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
6620
+ className: "dsha-group",
6621
+ children: [
6622
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6623
+ className: "dsha-grouphead",
6624
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.modelsSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6625
+ className: "dsha-btn",
6626
+ disabled: busy !== null,
6627
+ onClick: () => void handleRefreshCatalog(),
6628
+ children: busy === "catalog" ? t.refreshingCatalog : t.refreshCatalog
6629
+ })]
6630
+ }),
6631
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6632
+ className: "dsha-muted dsha-models-hint",
6633
+ children: t.modelsHint
6634
+ }),
6635
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6636
+ className: "dsha-models",
6637
+ "aria-label": "GLM Coding Plan Models",
6638
+ children: status?.models.map((model) => {
6639
+ const capabilities = [
6640
+ model.supportsImage ? "image" : null,
6641
+ model.reasoningEfforts.length > 0 ? model.reasoningEfforts.join("/") : null,
6642
+ `${t.effectiveWindow} ${formatCapacity(model.contextWindow)}`
6643
+ ].filter((part) => part !== null).join(" · ");
6644
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
6645
+ title: `${model.id} · ${capabilities}`,
6646
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6647
+ type: "checkbox",
6648
+ checked: model.enabled,
6649
+ disabled: busy !== null,
6650
+ onChange: (event) => toggleModel(model.id, event.currentTarget.checked)
6651
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name })]
6652
+ }, model.id);
6653
+ })
6654
+ }),
6655
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6656
+ className: "dsha-actions",
6657
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6658
+ className: "dsha-btn",
6659
+ disabled: busy !== null,
6660
+ onClick: () => setAllModels(true),
6661
+ children: t.selectAll
6662
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6663
+ className: "dsha-btn",
6664
+ disabled: busy !== null,
6665
+ onClick: () => setAllModels(false),
6666
+ children: t.unselectAll
6667
+ })]
6668
+ })
6669
+ ]
6670
+ }),
6671
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
6672
+ className: "dsha-group",
6673
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6674
+ className: "dsha-grouphead",
6675
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.enhanced })
6676
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6677
+ className: "dsha-pref-row",
6678
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.defaultReasoningEffort }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6679
+ className: "dsha-muted",
6680
+ children: t.defaultReasoningEffortHint
6681
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
6682
+ className: "dsha-select",
6683
+ "aria-label": t.defaultReasoningEffort,
6684
+ value: status?.defaultReasoningEffort ?? "",
6685
+ disabled: busy !== null,
6686
+ onChange: (event) => {
6687
+ const value = event.currentTarget.value;
6688
+ handleUpdateEffort(value === "" ? null : value);
6689
+ },
6690
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6691
+ value: "",
6692
+ children: t.defaultEffortAuto
6693
+ }), ZHIPU_REASONING_EFFORTS.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6694
+ value: effort,
6695
+ children: EFFORT_LABELS[effort]
6696
+ }, effort))]
6697
+ })]
6698
+ })]
6699
+ }),
6700
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
6701
+ className: "dsha-group",
6702
+ children: [
6703
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6704
+ className: "dsha-grouphead",
6705
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.contextWindowSection })
6706
+ }),
6707
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6708
+ className: "dsha-muted",
6709
+ children: t.contextWindowHint
6710
+ }),
6711
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6712
+ className: "dsha-context-settings",
6713
+ children: [
6714
+ contextModels.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6715
+ className: "dsha-muted",
6716
+ children: t.contextWindowNoneEnabled
6717
+ }),
6718
+ contextModels.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6719
+ className: "dsha-context-row",
6720
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6721
+ title: model.id,
6722
+ children: model.name
6723
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6724
+ className: "dsha-capacity-control",
6725
+ children: [
6726
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6727
+ type: "text",
6728
+ "aria-label": `${model.name} context window`,
6729
+ value: contextDrafts[model.id] ?? "",
6730
+ onChange: (event) => setContextDrafts({
6731
+ ...contextDrafts,
6732
+ [model.id]: event.currentTarget.value
6733
+ }),
6734
+ onKeyDown: (event) => {
6735
+ if (event.key === "Enter") handleSaveContextWindow(model.id);
6736
+ }
6737
+ }),
6738
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t.tokens }),
5619
6739
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5620
6740
  type: "button",
5621
6741
  className: "dsha-context-save",
@@ -5654,7 +6774,7 @@ window.__ModuleLoader__.load({
5654
6774
  className: "dsha-grouphead",
5655
6775
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.quotaSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5656
6776
  className: "dsha-btn",
5657
- disabled: busy !== null || !authenticated,
6777
+ disabled: busy !== null || !status?.authenticated,
5658
6778
  onClick: () => void handleRefreshQuota(),
5659
6779
  children: busy === "quota" ? t.refreshingQuota : t.refreshQuota
5660
6780
  })]
@@ -5663,81 +6783,100 @@ window.__ModuleLoader__.load({
5663
6783
  className: "dsha-muted",
5664
6784
  children: t.quotaDesc
5665
6785
  }),
5666
- !authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6786
+ !status?.authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5667
6787
  className: "dsha-empty",
5668
6788
  children: t.signedOut
5669
6789
  }) : quota === null || quota === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5670
6790
  className: "dsha-empty",
5671
- children: busy === "quota" ? t.refreshingQuota : t.quotaEmpty
6791
+ children: busy === "quota" ? t.refreshingQuota : status.quotaError ?? t.quotaEmpty
5672
6792
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5673
6793
  className: "dsha-quota-card",
5674
6794
  children: [
5675
6795
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5676
6796
  className: "dsha-quota-title",
5677
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: quota.packageName || t.quotaPackage }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: quota.remainingCredits !== null ? `${quota.remainingCredits} ${t.credits}` : "—" })]
6797
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: quota.planName ?? t.quotaSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: quota.planLevel ?? t.planUnknown })]
5678
6798
  }),
5679
- quota.cycleUsedCredits !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5680
- className: "dsha-row",
5681
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5682
- className: "dsha-label",
5683
- children: t.quotaCycle
5684
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5685
- className: "dsha-value",
6799
+ quota.renewsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6800
+ className: "dsha-meter-meta",
6801
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6802
+ t.renews,
6803
+ ": ",
6804
+ formatDate(quota.renewsAt)
6805
+ ] })
6806
+ }),
6807
+ quota.windows.map((window) => {
6808
+ const percent = window.remainingFraction === null ? null : Math.round(window.remainingFraction * 100);
6809
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6810
+ className: "dsha-meter-wrap",
5686
6811
  children: [
5687
- quota.cycleUsedCredits,
5688
- quota.cycleCredits !== null ? ` / ${quota.cycleCredits}` : "",
5689
- ` ${t.credits}`
6812
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6813
+ className: "dsha-meter-label",
6814
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: window.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: percent === null ? "—" : `${percent}% ${t.left}` })]
6815
+ }),
6816
+ percent !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6817
+ className: "dsha-meter dsha-meter-green",
6818
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: { width: `${Math.max(0, percent)}%` } })
6819
+ }),
6820
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6821
+ className: "dsha-meter-meta",
6822
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6823
+ window.used ?? "—",
6824
+ " / ",
6825
+ window.limit ?? "—"
6826
+ ] }), window.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6827
+ t.resetAt,
6828
+ ": ",
6829
+ formatReset(window.resetsAt, t.now)
6830
+ ] })]
6831
+ })
5690
6832
  ]
5691
- })]
5692
- }),
5693
- quota.cycleEndsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5694
- className: "dsha-row",
5695
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5696
- className: "dsha-label",
5697
- children: t.quotaReset
5698
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5699
- className: "dsha-value",
5700
- children: [formatDate(quota.cycleEndsAt), formatReset(quota.cycleEndsAt) ? ` · ${formatReset(quota.cycleEndsAt)}` : ""]
5701
- })]
6833
+ }, window.id);
5702
6834
  }),
5703
- quota.meters.map((meter) => {
5704
- const remaining = meter.remainingFraction;
5705
- const percent = remaining === null ? null : Math.round(remaining * 100);
6835
+ quota.meters.filter((meter) => !quota.windows.some((window) => window.id === meter.id)).map((meter) => {
6836
+ const percent = meter.remainingFraction === null ? null : Math.round(meter.remainingFraction * 100);
5706
6837
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5707
6838
  className: "dsha-meter-wrap",
5708
6839
  children: [
5709
6840
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5710
6841
  className: "dsha-meter-label",
5711
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: meter.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: percent === null ? meter.limit ?? "—" : `${percent}% left` })]
6842
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: meter.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: percent === null ? "—" : `${percent}% ${t.left}` })]
5712
6843
  }),
5713
6844
  percent !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5714
- className: "dsha-meter dsha-meter-green",
5715
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: { width: `${percent}%` } })
6845
+ className: "dsha-meter dsha-meter-cyan",
6846
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: { width: `${Math.max(0, percent)}%` } })
5716
6847
  }),
5717
6848
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5718
6849
  className: "dsha-meter-meta",
5719
- children: [meter.used !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5720
- meter.used,
6850
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6851
+ meter.used ?? "—",
5721
6852
  " / ",
5722
6853
  meter.limit ?? "—"
5723
6854
  ] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5724
- t.quotaReset,
6855
+ t.resetAt,
5725
6856
  ": ",
5726
- formatReset(meter.resetsAt)
6857
+ formatReset(meter.resetsAt, t.now)
5727
6858
  ] })]
5728
6859
  })
5729
6860
  ]
5730
6861
  }, meter.id);
5731
6862
  }),
5732
- quota.meters.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6863
+ !hasMeters && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5733
6864
  className: "dsha-empty",
5734
- children: t.quotaEmpty
6865
+ children: t.quotaUnavailable
5735
6866
  }),
5736
6867
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5737
6868
  className: "dsha-timestamp",
5738
6869
  children: t.updatedAt.replace("{time}", new Date(quota.fetchedAt).toLocaleString())
5739
6870
  })
5740
6871
  ]
6872
+ }),
6873
+ status?.quotaError && quota !== null && quota !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
6874
+ className: "dsha-muted",
6875
+ children: [
6876
+ t.quotaError,
6877
+ ": ",
6878
+ status.quotaError
6879
+ ]
5741
6880
  })
5742
6881
  ]
5743
6882
  }),
@@ -5770,6 +6909,10 @@ window.__ModuleLoader__.load({
5770
6909
  {
5771
6910
  id: "workbuddy",
5772
6911
  label: "WorkBuddy"
6912
+ },
6913
+ {
6914
+ id: "zhipu",
6915
+ label: "GLM"
5773
6916
  }
5774
6917
  ];
5775
6918
  /**
@@ -5828,7 +6971,8 @@ window.__ModuleLoader__.load({
5828
6971
  active === "antigravity" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AntigravitySection, { onModelChange }) : null,
5829
6972
  active === "command-code" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CommandCodeSection, { onModelChange }) : null,
5830
6973
  active === "kimi-code" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KimiCodeSection, { onModelChange }) : null,
5831
- active === "workbuddy" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkBuddySection, { onModelChange }) : null
6974
+ active === "workbuddy" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkBuddySection, { onModelChange }) : null,
6975
+ active === "zhipu" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZhipuSection, { onModelChange }) : null
5832
6976
  ]
5833
6977
  })
5834
6978
  ]
@@ -6107,7 +7251,7 @@ window.__ModuleLoader__.load({
6107
7251
  };
6108
7252
  //#endregion
6109
7253
  //#region src/client/styles.ts
6110
- const STYLE_ID$3 = "@eddyskywalker/dsh-chatgpt-subscription/main";
7254
+ const STYLE_ID$4 = "@eddyskywalker/dsh-chatgpt-subscription/main";
6111
7255
  const CSS = `
6112
7256
  .dsh-codex-page{box-sizing:border-box;color:var(--dsw-alias-label-primary);display:flex;flex-direction:column;gap:20px;max-width:780px;min-width:0;padding:2px 0 30px}
6113
7257
  .dsh-codex-page *{box-sizing:border-box}
@@ -6216,21 +7360,21 @@ window.__ModuleLoader__.load({
6216
7360
  @media(prefers-reduced-motion:reduce){.dsh-codex-meter>span{transition:none}.dsh-codex-skeleton span{animation:none}}
6217
7361
  `;
6218
7362
  function installStyles() {
6219
- if (document.querySelector(`style[data-plugin-css="${STYLE_ID$3}"]`) !== null) return () => void 0;
7363
+ if (document.querySelector(`style[data-plugin-css="${STYLE_ID$4}"]`) !== null) return () => void 0;
6220
7364
  const element = document.createElement("style");
6221
7365
  element.dataset.plugin = "@eddyskywalker/dsh-chatgpt-subscription";
6222
- element.dataset.pluginCss = STYLE_ID$3;
7366
+ element.dataset.pluginCss = STYLE_ID$4;
6223
7367
  element.textContent = CSS;
6224
7368
  document.head.appendChild(element);
6225
7369
  return () => element.remove();
6226
7370
  }
6227
7371
  //#endregion
6228
7372
  //#region src/client/antigravity/styles.ts
6229
- const STYLE_ID$2 = "dsh-antigravity-settings-style";
7373
+ const STYLE_ID$3 = "dsh-antigravity-settings-style";
6230
7374
  function installAntigravityStyles() {
6231
7375
  if (typeof document === "undefined" || document.getElementById("dsh-antigravity-settings-style")) return;
6232
7376
  const style = document.createElement("style");
6233
- style.id = STYLE_ID$2;
7377
+ style.id = STYLE_ID$3;
6234
7378
  style.textContent = `
6235
7379
  .dsha-page{box-sizing:border-box;color:var(--dsw-alias-label-primary);display:flex;flex-direction:column;gap:20px;max-width:780px;min-width:0;padding:2px 0 30px}
6236
7380
  .dsha-page *{box-sizing:border-box}
@@ -6331,9 +7475,9 @@ window.__ModuleLoader__.load({
6331
7475
  }
6332
7476
  //#endregion
6333
7477
  //#region src/client/antigravity/AntigravityComposerQuota.tsx
6334
- const API$3 = "/antigravity/api";
6335
- async function fetchApi$3(path, options) {
6336
- const res = await fetch(`${API$3}${path}`, {
7478
+ const API$4 = "/antigravity/api";
7479
+ async function fetchApi$4(path, options) {
7480
+ const res = await fetch(`${API$4}${path}`, {
6337
7481
  ...options,
6338
7482
  headers: {
6339
7483
  "Content-Type": "application/json",
@@ -6374,7 +7518,7 @@ window.__ModuleLoader__.load({
6374
7518
  }
6375
7519
  }
6376
7520
  function AntigravityComposerQuota({ directory, loadModelDirectory }) {
6377
- const modelState = useStore$3(directory);
7521
+ const modelState = useStore$4(directory);
6378
7522
  const [status, setStatus] = (0, react.useState)(null);
6379
7523
  const [loading, setLoading] = (0, react.useState)(false);
6380
7524
  const mountedRef = (0, react.useRef)(false);
@@ -6393,7 +7537,7 @@ window.__ModuleLoader__.load({
6393
7537
  if (!mountedRef.current) return;
6394
7538
  setLoading(true);
6395
7539
  try {
6396
- const data = refresh ? await fetchApi$3("/quota", { method: "POST" }) : await fetchApi$3("/status");
7540
+ const data = refresh ? await fetchApi$4("/quota", { method: "POST" }) : await fetchApi$4("/status");
6397
7541
  if (mountedRef.current) setStatus(data);
6398
7542
  } catch {} finally {
6399
7543
  if (mountedRef.current) setLoading(false);
@@ -6431,14 +7575,14 @@ window.__ModuleLoader__.load({
6431
7575
  })]
6432
7576
  });
6433
7577
  }
6434
- function useStore$3(store) {
7578
+ function useStore$4(store) {
6435
7579
  return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
6436
7580
  }
6437
7581
  //#endregion
6438
7582
  //#region src/client/command-code/CommandCodeComposerQuota.tsx
6439
- const API$2 = "/command-code/api";
6440
- async function fetchApi$2(path, options) {
6441
- const res = await fetch(`${API$2}${path}`, {
7583
+ const API$3 = "/command-code/api";
7584
+ async function fetchApi$3(path, options) {
7585
+ const res = await fetch(`${API$3}${path}`, {
6442
7586
  ...options,
6443
7587
  headers: {
6444
7588
  "Content-Type": "application/json",
@@ -6455,7 +7599,7 @@ window.__ModuleLoader__.load({
6455
7599
  * A bounded usage window is the number a user actually spends down, so it wins
6456
7600
  * over a credit balance; the balance shows only when no window is reported.
6457
7601
  */
6458
- function selectBadgeFacts$2(status) {
7602
+ function selectBadgeFacts$3(status) {
6459
7603
  const quota = status?.quota;
6460
7604
  if (quota === null || quota === void 0) return {
6461
7605
  text: "—",
@@ -6497,7 +7641,7 @@ window.__ModuleLoader__.load({
6497
7641
  };
6498
7642
  }
6499
7643
  function CommandCodeComposerQuota({ directory, loadModelDirectory }) {
6500
- const modelState = useStore$2(directory);
7644
+ const modelState = useStore$3(directory);
6501
7645
  const [status, setStatus] = (0, react.useState)(null);
6502
7646
  const [loading, setLoading] = (0, react.useState)(false);
6503
7647
  const mountedRef = (0, react.useRef)(false);
@@ -6515,7 +7659,7 @@ window.__ModuleLoader__.load({
6515
7659
  if (!mountedRef.current) return;
6516
7660
  setLoading(true);
6517
7661
  try {
6518
- const data = refresh ? await fetchApi$2("/quota", { method: "POST" }) : await fetchApi$2("/status");
7662
+ const data = refresh ? await fetchApi$3("/quota", { method: "POST" }) : await fetchApi$3("/status");
6519
7663
  if (mountedRef.current) setStatus(data);
6520
7664
  } catch {} finally {
6521
7665
  if (mountedRef.current) setLoading(false);
@@ -6531,7 +7675,7 @@ window.__ModuleLoader__.load({
6531
7675
  window.clearInterval(timer);
6532
7676
  };
6533
7677
  }, [fetchStatus, isCommandCode]);
6534
- const facts = (0, react.useMemo)(() => selectBadgeFacts$2(status), [status]);
7678
+ const facts = (0, react.useMemo)(() => selectBadgeFacts$3(status), [status]);
6535
7679
  if (!isCommandCode || !status?.authenticated || facts === null) return null;
6536
7680
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6537
7681
  className: "dsha-composer-quota",
@@ -6548,14 +7692,14 @@ window.__ModuleLoader__.load({
6548
7692
  })]
6549
7693
  });
6550
7694
  }
6551
- function useStore$2(store) {
7695
+ function useStore$3(store) {
6552
7696
  return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
6553
7697
  }
6554
7698
  //#endregion
6555
7699
  //#region src/client/kimi-code/KimiCodeComposerQuota.tsx
6556
- const API$1 = "/kimi-code/api";
6557
- async function fetchApi$1(path, options) {
6558
- const res = await fetch(`${API$1}${path}`, {
7700
+ const API$2 = "/kimi-code/api";
7701
+ async function fetchApi$2(path, options) {
7702
+ const res = await fetch(`${API$2}${path}`, {
6559
7703
  ...options,
6560
7704
  headers: {
6561
7705
  "Content-Type": "application/json",
@@ -6573,7 +7717,7 @@ window.__ModuleLoader__.load({
6573
7717
  * blocks work soonest, so it wins over the longer pools; the 7-day allowance
6574
7718
  * shows only when no 5-hour window is reported.
6575
7719
  */
6576
- function selectBadgeFacts$1(status) {
7720
+ function selectBadgeFacts$2(status) {
6577
7721
  const quota = status?.quota;
6578
7722
  if (quota === null || quota === void 0) return {
6579
7723
  text: "—",
@@ -6605,7 +7749,7 @@ window.__ModuleLoader__.load({
6605
7749
  };
6606
7750
  }
6607
7751
  function KimiCodeComposerQuota({ directory, loadModelDirectory }) {
6608
- const modelState = useStore$1(directory);
7752
+ const modelState = useStore$2(directory);
6609
7753
  const [status, setStatus] = (0, react.useState)(null);
6610
7754
  const [loading, setLoading] = (0, react.useState)(false);
6611
7755
  const mountedRef = (0, react.useRef)(false);
@@ -6623,7 +7767,7 @@ window.__ModuleLoader__.load({
6623
7767
  if (!mountedRef.current) return;
6624
7768
  setLoading(true);
6625
7769
  try {
6626
- const data = refresh ? await fetchApi$1("/quota", { method: "POST" }) : await fetchApi$1("/status");
7770
+ const data = refresh ? await fetchApi$2("/quota", { method: "POST" }) : await fetchApi$2("/status");
6627
7771
  if (mountedRef.current) setStatus(data);
6628
7772
  } catch {} finally {
6629
7773
  if (mountedRef.current) setLoading(false);
@@ -6639,7 +7783,7 @@ window.__ModuleLoader__.load({
6639
7783
  window.clearInterval(timer);
6640
7784
  };
6641
7785
  }, [fetchStatus, isKimiCode]);
6642
- const facts = (0, react.useMemo)(() => selectBadgeFacts$1(status), [status]);
7786
+ const facts = (0, react.useMemo)(() => selectBadgeFacts$2(status), [status]);
6643
7787
  if (!isKimiCode || !status?.authenticated || facts === null) return null;
6644
7788
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6645
7789
  className: "dsha-composer-quota",
@@ -6656,12 +7800,12 @@ window.__ModuleLoader__.load({
6656
7800
  })]
6657
7801
  });
6658
7802
  }
6659
- function useStore$1(store) {
7803
+ function useStore$2(store) {
6660
7804
  return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
6661
7805
  }
6662
7806
  //#endregion
6663
7807
  //#region src/client/kimi-code/styles.ts
6664
- const STYLE_ID$1 = "dsh-kimi-code-settings-style";
7808
+ const STYLE_ID$2 = "dsh-kimi-code-settings-style";
6665
7809
  /**
6666
7810
  * Node the base control styles come from.
6667
7811
  *
@@ -6753,15 +7897,15 @@ window.__ModuleLoader__.load({
6753
7897
  function installKimiCodeStyles() {
6754
7898
  if (typeof document === "undefined" || document.getElementById("dsh-kimi-code-settings-style")) return;
6755
7899
  const style = document.createElement("style");
6756
- style.id = STYLE_ID$1;
7900
+ style.id = STYLE_ID$2;
6757
7901
  style.textContent = BASE;
6758
7902
  document.head.appendChild(style);
6759
7903
  }
6760
7904
  //#endregion
6761
7905
  //#region src/client/workbuddy/WorkBuddyComposerQuota.tsx
6762
- const API = "/workbuddy/api";
6763
- async function fetchApi(path, options) {
6764
- const res = await fetch(`${API}${path}`, {
7906
+ const API$1 = "/workbuddy/api";
7907
+ async function fetchApi$1(path, options) {
7908
+ const res = await fetch(`${API$1}${path}`, {
6765
7909
  ...options,
6766
7910
  headers: {
6767
7911
  "Content-Type": "application/json",
@@ -6780,7 +7924,7 @@ window.__ModuleLoader__.load({
6780
7924
  * payload reports both a cycle meter and a package meter, and the cycle meter
6781
7925
  * is the one that actually resets, so it is preferred when both exist.
6782
7926
  */
6783
- function selectBadgeFacts(status) {
7927
+ function selectBadgeFacts$1(status) {
6784
7928
  const quota = status?.quota;
6785
7929
  if (quota === null || quota === void 0) return {
6786
7930
  text: "—",
@@ -6808,7 +7952,7 @@ window.__ModuleLoader__.load({
6808
7952
  };
6809
7953
  }
6810
7954
  function WorkBuddyComposerQuota({ directory, loadModelDirectory }) {
6811
- const modelState = useStore(directory);
7955
+ const modelState = useStore$1(directory);
6812
7956
  const [status, setStatus] = (0, react.useState)(null);
6813
7957
  const [loading, setLoading] = (0, react.useState)(false);
6814
7958
  const mountedRef = (0, react.useRef)(false);
@@ -6826,7 +7970,7 @@ window.__ModuleLoader__.load({
6826
7970
  if (!mountedRef.current) return;
6827
7971
  setLoading(true);
6828
7972
  try {
6829
- const data = refresh ? await fetchApi("/quota", { method: "POST" }) : await fetchApi("/status");
7973
+ const data = refresh ? await fetchApi$1("/quota", { method: "POST" }) : await fetchApi$1("/status");
6830
7974
  if (mountedRef.current) setStatus(data);
6831
7975
  } catch {} finally {
6832
7976
  if (mountedRef.current) setLoading(false);
@@ -6842,7 +7986,7 @@ window.__ModuleLoader__.load({
6842
7986
  window.clearInterval(timer);
6843
7987
  };
6844
7988
  }, [fetchStatus, isWorkBuddy]);
6845
- const facts = (0, react.useMemo)(() => selectBadgeFacts(status), [status]);
7989
+ const facts = (0, react.useMemo)(() => selectBadgeFacts$1(status), [status]);
6846
7990
  if (!isWorkBuddy || !status?.authenticated || facts === null) return null;
6847
7991
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6848
7992
  className: "dsha-composer-quota",
@@ -6859,12 +8003,12 @@ window.__ModuleLoader__.load({
6859
8003
  })]
6860
8004
  });
6861
8005
  }
6862
- function useStore(store) {
8006
+ function useStore$1(store) {
6863
8007
  return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
6864
8008
  }
6865
8009
  //#endregion
6866
8010
  //#region src/client/workbuddy/styles.ts
6867
- const STYLE_ID = "dsh-workbuddy-settings-style";
8011
+ const STYLE_ID$1 = "dsh-workbuddy-settings-style";
6868
8012
  /**
6869
8013
  * WorkBuddy-only additions to the shared settings design system.
6870
8014
  *
@@ -6880,12 +8024,141 @@ window.__ModuleLoader__.load({
6880
8024
  function installWorkBuddyStyles() {
6881
8025
  if (typeof document === "undefined" || document.getElementById("dsh-workbuddy-settings-style")) return;
6882
8026
  const style = document.createElement("style");
6883
- style.id = STYLE_ID;
8027
+ style.id = STYLE_ID$1;
6884
8028
  style.textContent = `
6885
8029
  .dshwb-mono{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px}
6886
8030
  .dsha-account-add-actions{display:flex;flex-wrap:wrap;gap:8px}
6887
8031
  .dsha-account-add-actions .dsha-btn{background:var(--dsw-alias-button-info-fill,#397ee8);border-color:transparent;color:var(--dsw-alias-button-info-label,#fff)}
6888
8032
  .dsha-account-add-actions .dsha-btn:hover:not(:disabled){opacity:.9;background:var(--dsw-alias-button-info-fill,#397ee8)}
8033
+ `;
8034
+ document.head.append(style);
8035
+ }
8036
+ //#endregion
8037
+ //#region src/client/zhipu/ZhipuComposerQuota.tsx
8038
+ const API = "/zhipu/api";
8039
+ async function fetchApi(path, options) {
8040
+ const res = await fetch(`${API}${path}`, {
8041
+ ...options,
8042
+ headers: {
8043
+ "Content-Type": "application/json",
8044
+ ...options?.headers
8045
+ }
8046
+ });
8047
+ const json = await res.json();
8048
+ if (!res.ok || !json.ok) throw new Error(json.error || `HTTP ${res.status}`);
8049
+ return json.value;
8050
+ }
8051
+ /**
8052
+ * Pick the most meaningful number for the badge.
8053
+ *
8054
+ * A Coding Plan is bounded by two windows at once, and the one closer to
8055
+ * exhaustion is what the user needs to see: the 5-hour window can be spent
8056
+ * while the weekly one has room, and the reverse. So the tightest *remaining*
8057
+ * fraction wins, and its window names the tooltip.
8058
+ */
8059
+ function selectBadgeFacts(status) {
8060
+ const quota = status?.quota;
8061
+ if (quota === null || quota === void 0) return {
8062
+ text: "—",
8063
+ tooltip: "GLM Coding Plan quota unavailable — click to refresh",
8064
+ level: "normal"
8065
+ };
8066
+ let tightest = null;
8067
+ for (const window of quota.windows) {
8068
+ if (window.remainingFraction === null) continue;
8069
+ if (tightest === null || window.remainingFraction < tightest.remaining) tightest = {
8070
+ label: window.label,
8071
+ remaining: window.remainingFraction
8072
+ };
8073
+ }
8074
+ if (tightest === null) return {
8075
+ text: "—",
8076
+ tooltip: "GLM Coding Plan quota unavailable — click to refresh",
8077
+ level: "normal"
8078
+ };
8079
+ const remaining = Math.round(tightest.remaining * 100);
8080
+ return {
8081
+ text: `${remaining}%`,
8082
+ tooltip: `[GLM Coding Plan] ${tightest.label}: ${remaining}% left`,
8083
+ level: remaining <= 5 ? "danger" : remaining <= 20 ? "warning" : "normal"
8084
+ };
8085
+ }
8086
+ function ZhipuComposerQuota({ directory, loadModelDirectory }) {
8087
+ const modelState = useStore(directory);
8088
+ const [status, setStatus] = (0, react.useState)(null);
8089
+ const [loading, setLoading] = (0, react.useState)(false);
8090
+ const mountedRef = (0, react.useRef)(false);
8091
+ const isZhipu = modelState.current?.provider === "zhipu-coding-plan";
8092
+ (0, react.useEffect)(() => {
8093
+ loadModelDirectory();
8094
+ }, [loadModelDirectory]);
8095
+ (0, react.useEffect)(() => {
8096
+ mountedRef.current = true;
8097
+ return () => {
8098
+ mountedRef.current = false;
8099
+ };
8100
+ }, []);
8101
+ const fetchStatus = (0, react.useCallback)(async (refresh = false) => {
8102
+ if (!mountedRef.current) return;
8103
+ setLoading(true);
8104
+ try {
8105
+ const data = refresh ? await fetchApi("/quota", { method: "POST" }) : await fetchApi("/status");
8106
+ if (mountedRef.current) setStatus(data);
8107
+ } catch {} finally {
8108
+ if (mountedRef.current) setLoading(false);
8109
+ }
8110
+ }, []);
8111
+ (0, react.useEffect)(() => {
8112
+ if (!isZhipu) return;
8113
+ fetchStatus(false);
8114
+ const timer = window.setInterval(() => {
8115
+ if (document.visibilityState === "visible") fetchStatus(false);
8116
+ }, 6e4);
8117
+ return () => {
8118
+ window.clearInterval(timer);
8119
+ };
8120
+ }, [fetchStatus, isZhipu]);
8121
+ const facts = (0, react.useMemo)(() => selectBadgeFacts(status), [status]);
8122
+ if (!isZhipu || !status?.authenticated || facts === null) return null;
8123
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8124
+ className: "dsha-composer-quota",
8125
+ "data-level": facts.level,
8126
+ title: facts.tooltip,
8127
+ "aria-label": facts.tooltip,
8128
+ onClick: () => void fetchStatus(true),
8129
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8130
+ className: "dsha-composer-quota-label",
8131
+ children: "额度"
8132
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
8133
+ className: "dsha-composer-quota-val",
8134
+ children: loading ? "…" : facts.text
8135
+ })]
8136
+ });
8137
+ }
8138
+ function useStore(store) {
8139
+ return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
8140
+ }
8141
+ //#endregion
8142
+ //#region src/client/zhipu/styles.ts
8143
+ const STYLE_ID = "dsh-zhipu-settings-style";
8144
+ /**
8145
+ * GLM Coding Plan additions to the shared settings design system.
8146
+ *
8147
+ * The base control styles (`.dsha-page`, `.dsha-group`, `.dsha-models`, the
8148
+ * account card, the meters, …) come from the stylesheets the sibling routes
8149
+ * install, in the same order the client installs them, so this file declares
8150
+ * only what stays unique to this card: the key-hint line and the region
8151
+ * selector that sits beside the key input.
8152
+ */
8153
+ function installZhipuStyles() {
8154
+ if (typeof document === "undefined" || document.getElementById("dsh-zhipu-settings-style")) return;
8155
+ const style = document.createElement("style");
8156
+ style.id = STYLE_ID;
8157
+ style.textContent = `
8158
+ .dshzp-mono{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px}
8159
+ .dshzp-keyrow{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
8160
+ .dshzp-keyrow .dsha-select{min-width:190px}
8161
+ .dshzp-keyrow input[type=password]{flex:1 1 260px;min-width:200px}
6889
8162
  `;
6890
8163
  document.head.append(style);
6891
8164
  }
@@ -7232,22 +8505,27 @@ window.__ModuleLoader__.load({
7232
8505
  function apply(ctx) {
7233
8506
  ctx.effect(() => ctx.locale.register(NS, dictionaries), "dsh-chatgpt-subscription: dictionaries");
7234
8507
  ctx.effect(() => installStyles(), "dsh-chatgpt-subscription: styles");
7235
- ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries$4), "dsh-antigravity: dictionaries");
8508
+ ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries$5), "dsh-antigravity: dictionaries");
7236
8509
  ctx.effect(() => {
7237
8510
  installAntigravityStyles();
7238
8511
  return () => {};
7239
8512
  }, "dsh-antigravity: styles");
7240
- ctx.effect(() => ctx.locale.register(NS_COMMAND_CODE, dictionaries$3), "dsh-command-code: dictionaries");
7241
- ctx.effect(() => ctx.locale.register(NS_KIMI_CODE, dictionaries$2), "dsh-kimi-code: dictionaries");
8513
+ ctx.effect(() => ctx.locale.register(NS_COMMAND_CODE, dictionaries$4), "dsh-command-code: dictionaries");
8514
+ ctx.effect(() => ctx.locale.register(NS_KIMI_CODE, dictionaries$3), "dsh-kimi-code: dictionaries");
7242
8515
  ctx.effect(() => {
7243
8516
  installKimiCodeStyles();
7244
8517
  return () => {};
7245
8518
  }, "dsh-kimi-code: styles");
7246
- ctx.effect(() => ctx.locale.register(NS_WORKBUDDY, dictionaries$1), "dsh-workbuddy: dictionaries");
8519
+ ctx.effect(() => ctx.locale.register(NS_WORKBUDDY, dictionaries$2), "dsh-workbuddy: dictionaries");
7247
8520
  ctx.effect(() => {
7248
8521
  installWorkBuddyStyles();
7249
8522
  return () => {};
7250
8523
  }, "dsh-workbuddy: styles");
8524
+ ctx.effect(() => ctx.locale.register(NS_ZHIPU, dictionaries$1), "dsh-zhipu: dictionaries");
8525
+ ctx.effect(() => {
8526
+ installZhipuStyles();
8527
+ return () => {};
8528
+ }, "dsh-zhipu: styles");
7251
8529
  ctx.effect(() => {
7252
8530
  installPoolStyles();
7253
8531
  return () => {};
@@ -7350,6 +8628,21 @@ window.__ModuleLoader__.load({
7350
8628
  };
7351
8629
  }
7352
8630
  }, WorkBuddyComposerQuota));
8631
+ ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
8632
+ name: "conversation.input.right",
8633
+ id: "zhipu-quota",
8634
+ order: 40,
8635
+ locale: NS_ZHIPU,
8636
+ inject: (sessionId) => {
8637
+ const directory = ctx.modelDirectories.directoryFor(sessionId);
8638
+ return {
8639
+ directory: directory.store,
8640
+ loadModelDirectory: () => {
8641
+ directory.load().catch(() => void 0);
8642
+ }
8643
+ };
8644
+ }
8645
+ }, ZhipuComposerQuota));
7353
8646
  ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
7354
8647
  name: "tool.call.toolview",
7355
8648
  key: CODEX_IMAGE_TOOL_NAME,