@eddyskywalker/dsh-chatgpt-subscription 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/README.md +67 -1
  3. package/lib/client.js +1566 -222
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +4882 -1114
  6. package/lib/types/client/ProviderHubSection.d.ts.map +1 -1
  7. package/lib/types/client/common/AccountPoolSection.d.ts +14 -0
  8. package/lib/types/client/common/AccountPoolSection.d.ts.map +1 -1
  9. package/lib/types/client/index.d.ts +1 -0
  10. package/lib/types/client/index.d.ts.map +1 -1
  11. package/lib/types/client/workbuddy/WorkBuddyComposerQuota.d.ts +26 -0
  12. package/lib/types/client/workbuddy/WorkBuddyComposerQuota.d.ts.map +1 -0
  13. package/lib/types/client/workbuddy/WorkBuddySection.d.ts +41 -0
  14. package/lib/types/client/workbuddy/WorkBuddySection.d.ts.map +1 -0
  15. package/lib/types/client/workbuddy/locales.d.ts +563 -0
  16. package/lib/types/client/workbuddy/locales.d.ts.map +1 -0
  17. package/lib/types/client/workbuddy/styles.d.ts +11 -0
  18. package/lib/types/client/workbuddy/styles.d.ts.map +1 -0
  19. package/lib/types/host/common/account-pool.d.ts +18 -0
  20. package/lib/types/host/common/account-pool.d.ts.map +1 -1
  21. package/lib/types/host/workbuddy/account-pool.d.ts +106 -0
  22. package/lib/types/host/workbuddy/account-pool.d.ts.map +1 -0
  23. package/lib/types/host/workbuddy/adapter.d.ts +97 -0
  24. package/lib/types/host/workbuddy/adapter.d.ts.map +1 -0
  25. package/lib/types/host/workbuddy/client.d.ts +90 -0
  26. package/lib/types/host/workbuddy/client.d.ts.map +1 -0
  27. package/lib/types/host/workbuddy/mapper.d.ts +114 -0
  28. package/lib/types/host/workbuddy/mapper.d.ts.map +1 -0
  29. package/lib/types/host/workbuddy/model-catalog.d.ts +108 -0
  30. package/lib/types/host/workbuddy/model-catalog.d.ts.map +1 -0
  31. package/lib/types/host/workbuddy/oauth.d.ts +38 -0
  32. package/lib/types/host/workbuddy/oauth.d.ts.map +1 -0
  33. package/lib/types/host/workbuddy/routes.d.ts +33 -0
  34. package/lib/types/host/workbuddy/routes.d.ts.map +1 -0
  35. package/lib/types/host/workbuddy/token-store.d.ts +216 -0
  36. package/lib/types/host/workbuddy/token-store.d.ts.map +1 -0
  37. package/lib/types/host/workbuddy/types.d.ts +127 -0
  38. package/lib/types/host/workbuddy/types.d.ts.map +1 -0
  39. package/lib/types/index.d.ts +5 -0
  40. package/lib/types/index.d.ts.map +1 -1
  41. package/lib/types/shared/account-pool-contracts.d.ts +8 -0
  42. package/lib/types/shared/account-pool-contracts.d.ts.map +1 -1
  43. package/lib/types/shared/workbuddy-contracts.d.ts +204 -0
  44. package/lib/types/shared/workbuddy-contracts.d.ts.map +1 -0
  45. package/package.json +1 -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$3(directory);
59
+ const modelState = useStore$4(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$3(store) {
106
+ function useStore$4(store) {
107
107
  return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
108
108
  }
109
109
  function formatPercent$1(value) {
@@ -479,7 +479,7 @@ window.__ModuleLoader__.load({
479
479
  formatPoolLabel(t.accountCount, { count: accounts.length }),
480
480
  ")"
481
481
  ]
482
- })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
482
+ })] }), props.renderLoginActions !== void 0 ? props.renderLoginActions() : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
483
483
  className: "dsha-btn dsha-btn-primary",
484
484
  disabled: props.busy !== null,
485
485
  onClick: props.onLogin,
@@ -565,6 +565,7 @@ window.__ModuleLoader__.load({
565
565
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
566
566
  className: "dsha-account-actions",
567
567
  children: [
568
+ props.renderAccountActions?.(account),
568
569
  !account.isPrimary && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
569
570
  className: "dsha-btn",
570
571
  disabled: props.busy !== null,
@@ -583,7 +584,7 @@ window.__ModuleLoader__.load({
583
584
  onClick: () => props.onRelogin(account.id),
584
585
  children: t.relogin
585
586
  }),
586
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
587
+ account.removable !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
587
588
  className: "dsha-btn",
588
589
  disabled: props.busy !== null,
589
590
  onClick: () => props.onDelete(account.id),
@@ -1008,7 +1009,7 @@ window.__ModuleLoader__.load({
1008
1009
  }),
1009
1010
  connection !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoRow, {
1010
1011
  label: t("latency"),
1011
- value: `${connection.latencyMs} ms · ${formatDate$2(connection.checkedAt)}`
1012
+ value: `${connection.latencyMs} ms · ${formatDate$3(connection.checkedAt)}`
1012
1013
  }) : null,
1013
1014
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1014
1015
  className: "dsha-muted dsha-models-hint",
@@ -1281,7 +1282,7 @@ window.__ModuleLoader__.load({
1281
1282
  id: inputId,
1282
1283
  type: "text",
1283
1284
  inputMode: "numeric",
1284
- value: draft ?? formatCapacity$3(fallback),
1285
+ value: draft ?? formatCapacity$4(fallback),
1285
1286
  disabled: busy !== null,
1286
1287
  "aria-label": entry.name + " " + t("contextWindow"),
1287
1288
  onChange: (event) => {
@@ -1395,7 +1396,7 @@ window.__ModuleLoader__.load({
1395
1396
  children: [
1396
1397
  t("updated"),
1397
1398
  ": ",
1398
- formatDate$2(quota.fetchedAt)
1399
+ formatDate$3(quota.fetchedAt)
1399
1400
  ]
1400
1401
  }) : null
1401
1402
  ]
@@ -1487,7 +1488,7 @@ window.__ModuleLoader__.load({
1487
1488
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("small", { children: [
1488
1489
  t("resetCreditExpires"),
1489
1490
  ": ",
1490
- resetCredits.expiresAt == null ? t("unknown") : formatReset$2(resetCredits.expiresAt)
1491
+ resetCredits.expiresAt == null ? t("unknown") : formatReset$3(resetCredits.expiresAt)
1491
1492
  ] })
1492
1493
  ]
1493
1494
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
@@ -1520,7 +1521,7 @@ window.__ModuleLoader__.load({
1520
1521
  }),
1521
1522
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1522
1523
  className: "dsh-codex-meter-meta",
1523
- 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$2(window.resetsAt)}` })]
1524
+ 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)}` })]
1524
1525
  })
1525
1526
  ]
1526
1527
  });
@@ -1546,7 +1547,7 @@ window.__ModuleLoader__.load({
1546
1547
  return `${value} ${t("limitWindow")}`;
1547
1548
  }
1548
1549
  }
1549
- function parsePositiveCapacity$3(value) {
1550
+ function parsePositiveCapacity$4(value) {
1550
1551
  const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
1551
1552
  if (matched === null) return null;
1552
1553
  const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
@@ -1554,10 +1555,10 @@ window.__ModuleLoader__.load({
1554
1555
  return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
1555
1556
  }
1556
1557
  function parseCapacity(value, maxContextWindow = GPT_56_MAX_CONTEXT_WINDOW) {
1557
- const parsed = parsePositiveCapacity$3(value);
1558
+ const parsed = parsePositiveCapacity$4(value);
1558
1559
  return parsed !== null && parsed <= maxContextWindow ? parsed : null;
1559
1560
  }
1560
- function formatCapacity$3(value) {
1561
+ function formatCapacity$4(value) {
1561
1562
  if (value % 1e3 === 0) return `${value / 1e3}K`;
1562
1563
  return String(value);
1563
1564
  }
@@ -1574,11 +1575,11 @@ window.__ModuleLoader__.load({
1574
1575
  limit.remainingPercent !== null && limit.remainingPercent !== void 0 ? `${formatPercent(limit.remainingPercent)} ${t("remaining")}` : null,
1575
1576
  limit.limit !== null && limit.limit !== void 0 ? `${t("limit")}: ${limit.limit}` : null,
1576
1577
  limit.used !== null && limit.used !== void 0 ? `${t("used")}: ${limit.used}` : null,
1577
- limit.resetsAt !== null && limit.resetsAt !== void 0 ? `${t("resets")}: ${formatReset$2(limit.resetsAt)}` : null
1578
+ limit.resetsAt !== null && limit.resetsAt !== void 0 ? `${t("resets")}: ${formatReset$3(limit.resetsAt)}` : null
1578
1579
  ].filter((part) => part !== null);
1579
1580
  return parts.length > 0 ? parts.join(" · ") : t("unknown");
1580
1581
  }
1581
- function formatDate$2(seconds) {
1582
+ function formatDate$3(seconds) {
1582
1583
  if (seconds === void 0 || seconds === null || typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) return "—";
1583
1584
  const ms = seconds > 1e10 ? seconds : seconds * 1e3;
1584
1585
  try {
@@ -1590,10 +1591,10 @@ window.__ModuleLoader__.load({
1590
1591
  return "—";
1591
1592
  }
1592
1593
  }
1593
- function formatReset$2(seconds) {
1594
+ function formatReset$3(seconds) {
1594
1595
  if (seconds === void 0 || seconds === null || typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) return "—";
1595
1596
  const ms = seconds > 1e10 ? seconds : seconds * 1e3;
1596
- const absolute = formatDate$2(seconds);
1597
+ const absolute = formatDate$3(seconds);
1597
1598
  const diff = ms - Date.now();
1598
1599
  const abs = Math.abs(diff);
1599
1600
  const [amount, unit] = abs >= 864e5 ? [Math.round(diff / 864e5), "day"] : abs >= 36e5 ? [Math.round(diff / 36e5), "hour"] : [Math.round(diff / 6e4), "minute"];
@@ -1609,7 +1610,7 @@ window.__ModuleLoader__.load({
1609
1610
  //#endregion
1610
1611
  //#region src/client/antigravity/locales.ts
1611
1612
  const NS_ANTIGRAVITY = "dsh-antigravity";
1612
- const zh$3 = {
1613
+ const zh$4 = {
1613
1614
  ...accountPoolZh,
1614
1615
  title: "Antigravity",
1615
1616
  pageDesc: "登录 Google Antigravity / Cloud Code Assist,并查看当前账号的共享额度。",
@@ -1675,7 +1676,7 @@ window.__ModuleLoader__.load({
1675
1676
  loginFailed: "登录失败",
1676
1677
  tokens: "tokens"
1677
1678
  };
1678
- const en$3 = {
1679
+ const en$4 = {
1679
1680
  ...accountPoolEn,
1680
1681
  title: "Antigravity",
1681
1682
  pageDesc: "Sign in to Google Antigravity / Cloud Code Assist and view shared quotas.",
@@ -1741,17 +1742,17 @@ window.__ModuleLoader__.load({
1741
1742
  loginFailed: "Login failed",
1742
1743
  tokens: "tokens"
1743
1744
  };
1744
- const dictionaries$3 = {
1745
- zh: zh$3,
1746
- "zh-CN": zh$3,
1747
- en: en$3,
1748
- "en-US": en$3
1745
+ const dictionaries$4 = {
1746
+ zh: zh$4,
1747
+ "zh-CN": zh$4,
1748
+ en: en$4,
1749
+ "en-US": en$4
1749
1750
  };
1750
1751
  //#endregion
1751
1752
  //#region src/client/antigravity/AntigravitySection.tsx
1752
- const API$5 = "/antigravity/api";
1753
- async function fetchApi$5(path, options) {
1754
- const res = await fetch(`${API$5}${path}`, {
1753
+ const API$7 = "/antigravity/api";
1754
+ async function fetchApi$7(path, options) {
1755
+ const res = await fetch(`${API$7}${path}`, {
1755
1756
  ...options,
1756
1757
  headers: {
1757
1758
  "Content-Type": "application/json",
@@ -1762,14 +1763,14 @@ window.__ModuleLoader__.load({
1762
1763
  if (!res.ok || !json.ok) throw new Error(json.error || `HTTP ${res.status}`);
1763
1764
  return json.value;
1764
1765
  }
1765
- function parsePositiveCapacity$2(value) {
1766
+ function parsePositiveCapacity$3(value) {
1766
1767
  const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
1767
1768
  if (matched === null) return null;
1768
1769
  const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
1769
1770
  const parsed = Number(matched[1]) * multiplier;
1770
1771
  return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
1771
1772
  }
1772
- function formatCapacity$2(value) {
1773
+ function formatCapacity$3(value) {
1773
1774
  if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
1774
1775
  if (value % 1e3 === 0) return `${value / 1e3}K`;
1775
1776
  return String(value);
@@ -1785,7 +1786,7 @@ window.__ModuleLoader__.load({
1785
1786
  if (hours > 0) return `${hours}h ${mins % 60}m`;
1786
1787
  return `${mins}m`;
1787
1788
  }
1788
- function formatDate$1(ms) {
1789
+ function formatDate$2(ms) {
1789
1790
  if (!ms || ms <= 0) return "—";
1790
1791
  try {
1791
1792
  return new Intl.DateTimeFormat(void 0, {
@@ -1805,7 +1806,7 @@ window.__ModuleLoader__.load({
1805
1806
  const [loginProgress, setLoginProgress] = (0, react.useState)(null);
1806
1807
  const [contextDrafts, setContextDrafts] = (0, react.useState)({});
1807
1808
  const [savingModel, setSavingModel] = (0, react.useState)(null);
1808
- const t = zh$3;
1809
+ const t = zh$4;
1809
1810
  const notifyChange = (0, react.useCallback)(() => {
1810
1811
  onModelChange?.();
1811
1812
  loadModelDirectory?.();
@@ -1816,12 +1817,12 @@ window.__ModuleLoader__.load({
1816
1817
  setValidationUrl(null);
1817
1818
  }
1818
1819
  try {
1819
- const data = await fetchApi$5("/status");
1820
+ const data = await fetchApi$7("/status");
1820
1821
  setStatus(data);
1821
1822
  const drafts = {};
1822
1823
  for (const m of data.models) {
1823
1824
  const val = data.contextWindowOverrides[m.id] || m.defaultContextWindow;
1824
- drafts[m.id] = formatCapacity$2(val);
1825
+ drafts[m.id] = formatCapacity$3(val);
1825
1826
  }
1826
1827
  setContextDrafts(drafts);
1827
1828
  } catch (err) {
@@ -1848,11 +1849,11 @@ window.__ModuleLoader__.load({
1848
1849
  setError(null);
1849
1850
  setValidationUrl(null);
1850
1851
  setLoginProgress(null);
1851
- const flow = await fetchApi$5("/login", { method: "POST" });
1852
+ const flow = await fetchApi$7("/login", { method: "POST" });
1852
1853
  if (flow.authUrl) window.open(flow.authUrl, "_blank");
1853
1854
  const pollTimer = setInterval(async () => {
1854
1855
  try {
1855
- const pollStatus = await fetchApi$5("/login/status");
1856
+ const pollStatus = await fetchApi$7("/login/status");
1856
1857
  if (pollStatus.progress) setLoginProgress(pollStatus.progress);
1857
1858
  if (pollStatus.status === "complete") {
1858
1859
  clearInterval(pollTimer);
@@ -1884,7 +1885,7 @@ window.__ModuleLoader__.load({
1884
1885
  try {
1885
1886
  setBusy("quota");
1886
1887
  setError(null);
1887
- const updated = await fetchApi$5("/quota", { method: "POST" });
1888
+ const updated = await fetchApi$7("/quota", { method: "POST" });
1888
1889
  setStatus(updated);
1889
1890
  } catch (err) {
1890
1891
  setError(err instanceof Error ? err.message : String(err));
@@ -1896,7 +1897,7 @@ window.__ModuleLoader__.load({
1896
1897
  try {
1897
1898
  setBusy(`primary-${accountId}`);
1898
1899
  setError(null);
1899
- const updated = await fetchApi$5("/accounts", {
1900
+ const updated = await fetchApi$7("/accounts", {
1900
1901
  method: "POST",
1901
1902
  body: JSON.stringify({
1902
1903
  action: "set-primary",
@@ -1915,7 +1916,7 @@ window.__ModuleLoader__.load({
1915
1916
  try {
1916
1917
  setBusy(`delete-${accountId}`);
1917
1918
  setError(null);
1918
- const updated = await fetchApi$5("/accounts", {
1919
+ const updated = await fetchApi$7("/accounts", {
1919
1920
  method: "POST",
1920
1921
  body: JSON.stringify({
1921
1922
  action: "delete",
@@ -1934,7 +1935,7 @@ window.__ModuleLoader__.load({
1934
1935
  try {
1935
1936
  setBusy(`cooldown-${accountId}`);
1936
1937
  setError(null);
1937
- const updated = await fetchApi$5("/accounts", {
1938
+ const updated = await fetchApi$7("/accounts", {
1938
1939
  method: "POST",
1939
1940
  body: JSON.stringify({
1940
1941
  action: "clear-cooldown",
@@ -1952,7 +1953,7 @@ window.__ModuleLoader__.load({
1952
1953
  try {
1953
1954
  setBusy("strategy");
1954
1955
  setError(null);
1955
- const updated = await fetchApi$5("/accounts", {
1956
+ const updated = await fetchApi$7("/accounts", {
1956
1957
  method: "POST",
1957
1958
  body: JSON.stringify({
1958
1959
  action: "strategy",
@@ -1972,7 +1973,7 @@ window.__ModuleLoader__.load({
1972
1973
  enabled
1973
1974
  } : prev);
1974
1975
  try {
1975
- const updated = await fetchApi$5("/settings", {
1976
+ const updated = await fetchApi$7("/settings", {
1976
1977
  method: "POST",
1977
1978
  body: JSON.stringify({ enabled })
1978
1979
  });
@@ -1988,7 +1989,7 @@ window.__ModuleLoader__.load({
1988
1989
  const currentEnabled = status.models.filter((m) => m.enabled).map((m) => m.id);
1989
1990
  const nextEnabled = checked ? [.../* @__PURE__ */ new Set([...currentEnabled, modelId])] : currentEnabled.filter((id) => id !== modelId);
1990
1991
  try {
1991
- const updated = await fetchApi$5("/models", {
1992
+ const updated = await fetchApi$7("/models", {
1992
1993
  method: "POST",
1993
1994
  body: JSON.stringify({ enabledModelIds: nextEnabled })
1994
1995
  });
@@ -2002,7 +2003,7 @@ window.__ModuleLoader__.load({
2002
2003
  if (!status) return;
2003
2004
  const nextEnabled = selectAll ? status.models.map((m) => m.id) : [];
2004
2005
  try {
2005
- const updated = await fetchApi$5("/models", {
2006
+ const updated = await fetchApi$7("/models", {
2006
2007
  method: "POST",
2007
2008
  body: JSON.stringify({ enabledModelIds: nextEnabled })
2008
2009
  });
@@ -2014,7 +2015,7 @@ window.__ModuleLoader__.load({
2014
2015
  };
2015
2016
  const handleUpdateEffort = async (effort) => {
2016
2017
  try {
2017
- const updated = await fetchApi$5("/settings", {
2018
+ const updated = await fetchApi$7("/settings", {
2018
2019
  method: "POST",
2019
2020
  body: JSON.stringify({ defaultReasoningEffort: effort })
2020
2021
  });
@@ -2026,7 +2027,7 @@ window.__ModuleLoader__.load({
2026
2027
  };
2027
2028
  const handleSaveContextWindow = async (modelId) => {
2028
2029
  const raw = contextDrafts[modelId] || "";
2029
- const parsed = parsePositiveCapacity$2(raw);
2030
+ const parsed = parsePositiveCapacity$3(raw);
2030
2031
  if (parsed === null) {
2031
2032
  setError(`无效的上下文容量值: ${raw}`);
2032
2033
  return;
@@ -2034,14 +2035,14 @@ window.__ModuleLoader__.load({
2034
2035
  try {
2035
2036
  setSavingModel(modelId);
2036
2037
  setError(null);
2037
- const updated = await fetchApi$5("/settings", {
2038
+ const updated = await fetchApi$7("/settings", {
2038
2039
  method: "POST",
2039
2040
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
2040
2041
  });
2041
2042
  setStatus(updated);
2042
2043
  setContextDrafts((prev) => ({
2043
2044
  ...prev,
2044
- [modelId]: formatCapacity$2(parsed)
2045
+ [modelId]: formatCapacity$3(parsed)
2045
2046
  }));
2046
2047
  notifyChange();
2047
2048
  } catch (err) {
@@ -2089,12 +2090,12 @@ window.__ModuleLoader__.load({
2089
2090
  account.expiresAt && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
2090
2091
  t.expires,
2091
2092
  ": ",
2092
- formatDate$1(account.expiresAt)
2093
+ formatDate$2(account.expiresAt)
2093
2094
  ] }),
2094
2095
  account.lastUsedAt && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
2095
2096
  t.lastUsed,
2096
2097
  ": ",
2097
- formatDate$1(account.lastUsedAt)
2098
+ formatDate$2(account.lastUsedAt)
2098
2099
  ] })
2099
2100
  ] })
2100
2101
  }),
@@ -2350,7 +2351,7 @@ window.__ModuleLoader__.load({
2350
2351
  //#endregion
2351
2352
  //#region src/client/command-code/locales.ts
2352
2353
  const NS_COMMAND_CODE = "dsh-command-code";
2353
- const zh$2 = {
2354
+ const zh$3 = {
2354
2355
  ...accountPoolZh,
2355
2356
  title: "Command Code",
2356
2357
  pageDesc: "登录 Command Code,管理可用模型、上下文窗口与额度。",
@@ -2418,7 +2419,7 @@ window.__ModuleLoader__.load({
2418
2419
  loginFailed: "登录失败",
2419
2420
  tokens: "tokens"
2420
2421
  };
2421
- const en$2 = {
2422
+ const en$3 = {
2422
2423
  ...accountPoolEn,
2423
2424
  title: "Command Code",
2424
2425
  pageDesc: "Sign in to Command Code and manage models, context windows, and quota.",
@@ -2486,11 +2487,11 @@ window.__ModuleLoader__.load({
2486
2487
  loginFailed: "Sign-in failed",
2487
2488
  tokens: "tokens"
2488
2489
  };
2489
- const dictionaries$2 = {
2490
- zh: zh$2,
2491
- "zh-CN": zh$2,
2492
- en: en$2,
2493
- "en-US": en$2
2490
+ const dictionaries$3 = {
2491
+ zh: zh$3,
2492
+ "zh-CN": zh$3,
2493
+ en: en$3,
2494
+ "en-US": en$3
2494
2495
  };
2495
2496
  //#endregion
2496
2497
  //#region src/client/command-code/CommandCodeSection.tsx
@@ -2498,7 +2499,7 @@ window.__ModuleLoader__.load({
2498
2499
  * Display label per reasoning level. The locale dictionary only accepts flat
2499
2500
  * string values, so this nested table lives with the control that renders it.
2500
2501
  */
2501
- const EFFORT_LABELS = {
2502
+ const EFFORT_LABELS$1 = {
2502
2503
  minimal: "Minimal",
2503
2504
  low: "Low",
2504
2505
  medium: "Medium",
@@ -2506,9 +2507,9 @@ window.__ModuleLoader__.load({
2506
2507
  xhigh: "X-High",
2507
2508
  max: "Max"
2508
2509
  };
2509
- const API$4 = "/command-code/api";
2510
- async function fetchApi$4(path, options) {
2511
- const res = await fetch(`${API$4}${path}`, {
2510
+ const API$6 = "/command-code/api";
2511
+ async function fetchApi$6(path, options) {
2512
+ const res = await fetch(`${API$6}${path}`, {
2512
2513
  ...options,
2513
2514
  headers: {
2514
2515
  "Content-Type": "application/json",
@@ -2520,19 +2521,19 @@ window.__ModuleLoader__.load({
2520
2521
  return json.value;
2521
2522
  }
2522
2523
  /** Parse "1M", "512K", "200000" into a positive integer token count. */
2523
- function parsePositiveCapacity$1(value) {
2524
+ function parsePositiveCapacity$2(value) {
2524
2525
  const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
2525
2526
  if (matched === null) return null;
2526
2527
  const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
2527
2528
  const parsed = Number(matched[1]) * multiplier;
2528
2529
  return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
2529
2530
  }
2530
- function formatCapacity$1(value) {
2531
+ function formatCapacity$2(value) {
2531
2532
  if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
2532
2533
  if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
2533
2534
  return String(value);
2534
2535
  }
2535
- function formatReset$1(resetsAt) {
2536
+ function formatReset$2(resetsAt) {
2536
2537
  if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
2537
2538
  const diff = resetsAt - Date.now();
2538
2539
  if (diff <= 0) return "now";
@@ -2552,7 +2553,7 @@ window.__ModuleLoader__.load({
2552
2553
  const [contextDrafts, setContextDrafts] = (0, react.useState)({});
2553
2554
  const [savingModel, setSavingModel] = (0, react.useState)(null);
2554
2555
  const [apiKey, setApiKey] = (0, react.useState)("");
2555
- const t = zh$2;
2556
+ const t = zh$3;
2556
2557
  const notifyChange = (0, react.useCallback)(() => {
2557
2558
  onModelChange?.();
2558
2559
  loadModelDirectory?.();
@@ -2560,10 +2561,10 @@ window.__ModuleLoader__.load({
2560
2561
  const loadStatus = (0, react.useCallback)(async (quiet = false) => {
2561
2562
  if (!quiet) setError(null);
2562
2563
  try {
2563
- const data = await fetchApi$4("/status");
2564
+ const data = await fetchApi$6("/status");
2564
2565
  setStatus(data);
2565
2566
  const drafts = {};
2566
- for (const model of data.models) drafts[model.id] = formatCapacity$1(data.contextWindowOverrides[model.id] || model.defaultContextWindow);
2567
+ for (const model of data.models) drafts[model.id] = formatCapacity$2(data.contextWindowOverrides[model.id] || model.defaultContextWindow);
2567
2568
  setContextDrafts(drafts);
2568
2569
  } catch (err) {
2569
2570
  if (!quiet) setError(err instanceof Error ? err.message : String(err));
@@ -2588,12 +2589,12 @@ window.__ModuleLoader__.load({
2588
2589
  setBusy("login");
2589
2590
  setError(null);
2590
2591
  setLoginProgress(null);
2591
- const flow = await fetchApi$4("/login", { method: "POST" });
2592
+ const flow = await fetchApi$6("/login", { method: "POST" });
2592
2593
  if (flow.authUrl) window.open(flow.authUrl, "_blank");
2593
2594
  const pollTimer = window.setInterval(() => {
2594
2595
  (async () => {
2595
2596
  try {
2596
- const poll = await fetchApi$4("/login/status");
2597
+ const poll = await fetchApi$6("/login/status");
2597
2598
  if (poll.progress) setLoginProgress(poll.progress);
2598
2599
  if (poll.status === "complete") {
2599
2600
  window.clearInterval(pollTimer);
@@ -2625,7 +2626,7 @@ window.__ModuleLoader__.load({
2625
2626
  try {
2626
2627
  setBusy("apikey");
2627
2628
  setError(null);
2628
- const updated = await fetchApi$4("/login/apikey", {
2629
+ const updated = await fetchApi$6("/login/apikey", {
2629
2630
  method: "POST",
2630
2631
  body: JSON.stringify({ apiKey })
2631
2632
  });
@@ -2643,7 +2644,7 @@ window.__ModuleLoader__.load({
2643
2644
  try {
2644
2645
  setBusy(`${action}-${accountId}`);
2645
2646
  setError(null);
2646
- const updated = await fetchApi$4("/accounts", {
2647
+ const updated = await fetchApi$6("/accounts", {
2647
2648
  method: "POST",
2648
2649
  body: JSON.stringify({
2649
2650
  action,
@@ -2662,7 +2663,7 @@ window.__ModuleLoader__.load({
2662
2663
  try {
2663
2664
  setBusy("strategy");
2664
2665
  setError(null);
2665
- const updated = await fetchApi$4("/accounts", {
2666
+ const updated = await fetchApi$6("/accounts", {
2666
2667
  method: "POST",
2667
2668
  body: JSON.stringify({
2668
2669
  action: "strategy",
@@ -2685,7 +2686,7 @@ window.__ModuleLoader__.load({
2685
2686
  const handleRelogin = (accountId) => {
2686
2687
  (async () => {
2687
2688
  try {
2688
- const updated = await fetchApi$4("/accounts", {
2689
+ const updated = await fetchApi$6("/accounts", {
2689
2690
  method: "POST",
2690
2691
  body: JSON.stringify({
2691
2692
  action: "relogin",
@@ -2704,7 +2705,7 @@ window.__ModuleLoader__.load({
2704
2705
  try {
2705
2706
  setBusy("quota");
2706
2707
  setError(null);
2707
- const updated = await fetchApi$4("/quota", { method: "POST" });
2708
+ const updated = await fetchApi$6("/quota", { method: "POST" });
2708
2709
  setStatus(updated);
2709
2710
  } catch (err) {
2710
2711
  setError(err instanceof Error ? err.message : String(err));
@@ -2716,10 +2717,10 @@ window.__ModuleLoader__.load({
2716
2717
  try {
2717
2718
  setBusy("catalog");
2718
2719
  setError(null);
2719
- const updated = await fetchApi$4("/catalog/refresh", { method: "POST" });
2720
+ const updated = await fetchApi$6("/catalog/refresh", { method: "POST" });
2720
2721
  setStatus(updated);
2721
2722
  const drafts = {};
2722
- for (const model of updated.models) drafts[model.id] = formatCapacity$1(updated.contextWindowOverrides[model.id] || model.defaultContextWindow);
2723
+ for (const model of updated.models) drafts[model.id] = formatCapacity$2(updated.contextWindowOverrides[model.id] || model.defaultContextWindow);
2723
2724
  setContextDrafts(drafts);
2724
2725
  notifyChange();
2725
2726
  } catch (err) {
@@ -2732,7 +2733,7 @@ window.__ModuleLoader__.load({
2732
2733
  try {
2733
2734
  setBusy("connection");
2734
2735
  setError(null);
2735
- await fetchApi$4("/connection/test", { method: "POST" });
2736
+ await fetchApi$6("/connection/test", { method: "POST" });
2736
2737
  await loadStatus(true);
2737
2738
  } catch (err) {
2738
2739
  setError(err instanceof Error ? err.message : String(err));
@@ -2742,7 +2743,7 @@ window.__ModuleLoader__.load({
2742
2743
  };
2743
2744
  const applyEnabled = async (enabledModelIds) => {
2744
2745
  try {
2745
- const updated = await fetchApi$4("/models", {
2746
+ const updated = await fetchApi$6("/models", {
2746
2747
  method: "POST",
2747
2748
  body: JSON.stringify({ enabledModelIds })
2748
2749
  });
@@ -2758,7 +2759,7 @@ window.__ModuleLoader__.load({
2758
2759
  enabled
2759
2760
  } : prev);
2760
2761
  try {
2761
- const updated = await fetchApi$4("/settings", {
2762
+ const updated = await fetchApi$6("/settings", {
2762
2763
  method: "POST",
2763
2764
  body: JSON.stringify({ enabled })
2764
2765
  });
@@ -2781,7 +2782,7 @@ window.__ModuleLoader__.load({
2781
2782
  };
2782
2783
  const handleUpdateEffort = async (effort) => {
2783
2784
  try {
2784
- const updated = await fetchApi$4("/settings", {
2785
+ const updated = await fetchApi$6("/settings", {
2785
2786
  method: "POST",
2786
2787
  body: JSON.stringify({ defaultReasoningEffort: effort })
2787
2788
  });
@@ -2793,7 +2794,7 @@ window.__ModuleLoader__.load({
2793
2794
  };
2794
2795
  const handleSaveContextWindow = async (modelId) => {
2795
2796
  const raw = contextDrafts[modelId] || "";
2796
- const parsed = parsePositiveCapacity$1(raw);
2797
+ const parsed = parsePositiveCapacity$2(raw);
2797
2798
  if (parsed === null) {
2798
2799
  setError(`Invalid context capacity: ${raw}`);
2799
2800
  return;
@@ -2801,14 +2802,14 @@ window.__ModuleLoader__.load({
2801
2802
  try {
2802
2803
  setSavingModel(modelId);
2803
2804
  setError(null);
2804
- const updated = await fetchApi$4("/settings", {
2805
+ const updated = await fetchApi$6("/settings", {
2805
2806
  method: "POST",
2806
2807
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
2807
2808
  });
2808
2809
  setStatus(updated);
2809
2810
  setContextDrafts((prev) => ({
2810
2811
  ...prev,
2811
- [modelId]: formatCapacity$1(parsed)
2812
+ [modelId]: formatCapacity$2(parsed)
2812
2813
  }));
2813
2814
  notifyChange();
2814
2815
  } catch (err) {
@@ -3004,7 +3005,7 @@ window.__ModuleLoader__.load({
3004
3005
  children: t.defaultEffortAuto
3005
3006
  }), COMMAND_CODE_REASONING_EFFORTS.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3006
3007
  value: effort,
3007
- children: EFFORT_LABELS[effort]
3008
+ children: EFFORT_LABELS$1[effort]
3008
3009
  }, effort))]
3009
3010
  })]
3010
3011
  })]
@@ -3098,7 +3099,7 @@ window.__ModuleLoader__.load({
3098
3099
  }),
3099
3100
  window.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3100
3101
  className: "dsha-meter-meta",
3101
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$1(window.resetsAt)] })
3102
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$2(window.resetsAt)] })
3102
3103
  })
3103
3104
  ]
3104
3105
  }, window.id)),
@@ -3123,7 +3124,7 @@ window.__ModuleLoader__.load({
3123
3124
  meter.used ?? "—",
3124
3125
  " / ",
3125
3126
  meter.limit ?? "—"
3126
- ] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$1(meter.resetsAt)] })]
3127
+ ] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$2(meter.resetsAt)] })]
3127
3128
  }) : meter.description !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3128
3129
  className: "dsha-meter-meta",
3129
3130
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: meter.description })
@@ -3162,7 +3163,7 @@ window.__ModuleLoader__.load({
3162
3163
  //#endregion
3163
3164
  //#region src/client/kimi-code/locales.ts
3164
3165
  const NS_KIMI_CODE = "dsh-kimi-code";
3165
- const zh$1 = {
3166
+ const zh$2 = {
3166
3167
  ...accountPoolZh,
3167
3168
  title: "Kimi Code",
3168
3169
  pageDesc: "登录 Kimi Code 订阅,管理模型、思考档位、上下文窗口与额度。",
@@ -3275,7 +3276,7 @@ window.__ModuleLoader__.load({
3275
3276
  requests: "次请求",
3276
3277
  tokens: "tokens"
3277
3278
  };
3278
- const en$1 = {
3279
+ const en$2 = {
3279
3280
  ...accountPoolEn,
3280
3281
  title: "Kimi Code",
3281
3282
  pageDesc: "Sign in to the Kimi Code subscription and manage models, thinking level, context windows, and quota.",
@@ -3388,11 +3389,11 @@ window.__ModuleLoader__.load({
3388
3389
  requests: "requests",
3389
3390
  tokens: "tokens"
3390
3391
  };
3391
- const dictionaries$1 = {
3392
- zh: zh$1,
3393
- "zh-CN": zh$1,
3394
- en: en$1,
3395
- "en-US": en$1
3392
+ const dictionaries$2 = {
3393
+ zh: zh$2,
3394
+ "zh-CN": zh$2,
3395
+ en: en$2,
3396
+ "en-US": en$2
3396
3397
  };
3397
3398
  //#endregion
3398
3399
  //#region src/client/kimi-code/KimiModelCapabilities.tsx
@@ -3405,7 +3406,7 @@ window.__ModuleLoader__.load({
3405
3406
  * Capabilities are now short tags in their own columns, with the per-model
3406
3407
  * detail kept in a hover title.
3407
3408
  */
3408
- const t = zh$1;
3409
+ const t = zh$2;
3409
3410
  function KimiModelCapabilities({ models }) {
3410
3411
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3411
3412
  className: "dsha-cap-table",
@@ -3449,9 +3450,9 @@ window.__ModuleLoader__.load({
3449
3450
  }
3450
3451
  //#endregion
3451
3452
  //#region src/client/kimi-code/KimiCodeSection.tsx
3452
- const API$3 = "/kimi-code/api";
3453
- async function fetchApi$3(path, options) {
3454
- const res = await fetch(`${API$3}${path}`, {
3453
+ const API$5 = "/kimi-code/api";
3454
+ async function fetchApi$5(path, options) {
3455
+ const res = await fetch(`${API$5}${path}`, {
3455
3456
  ...options,
3456
3457
  headers: {
3457
3458
  "Content-Type": "application/json",
@@ -3463,19 +3464,19 @@ window.__ModuleLoader__.load({
3463
3464
  return json.value;
3464
3465
  }
3465
3466
  /** Parse "1M", "512K", "200000" into a positive integer token count. */
3466
- function parsePositiveCapacity(value) {
3467
+ function parsePositiveCapacity$1(value) {
3467
3468
  const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
3468
3469
  if (matched === null) return null;
3469
3470
  const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
3470
3471
  const parsed = Number(matched[1]) * multiplier;
3471
3472
  return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
3472
3473
  }
3473
- function formatCapacity(value) {
3474
+ function formatCapacity$1(value) {
3474
3475
  if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
3475
3476
  if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
3476
3477
  return String(value);
3477
3478
  }
3478
- function formatDate(ms) {
3479
+ function formatDate$1(ms) {
3479
3480
  if (ms === void 0 || ms === null || ms <= 0) return "—";
3480
3481
  try {
3481
3482
  return new Intl.DateTimeFormat(void 0, {
@@ -3486,7 +3487,7 @@ window.__ModuleLoader__.load({
3486
3487
  return "—";
3487
3488
  }
3488
3489
  }
3489
- function formatReset(resetsAt) {
3490
+ function formatReset$1(resetsAt) {
3490
3491
  if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
3491
3492
  const diff = resetsAt - Date.now();
3492
3493
  if (diff <= 0) return "now";
@@ -3511,10 +3512,10 @@ window.__ModuleLoader__.load({
3511
3512
  }
3512
3513
  }
3513
3514
  const EFFORT_LABEL = {
3514
- low: zh$1.effortLow,
3515
- high: zh$1.effortHigh,
3516
- max: zh$1.effortMax,
3517
- none: zh$1.effortNone
3515
+ low: zh$2.effortLow,
3516
+ high: zh$2.effortHigh,
3517
+ max: zh$2.effortMax,
3518
+ none: zh$2.effortNone
3518
3519
  };
3519
3520
  function KimiCodeSection({ onModelChange, loadModelDirectory }) {
3520
3521
  const [status, setStatus] = (0, react.useState)(null);
@@ -3526,7 +3527,7 @@ window.__ModuleLoader__.load({
3526
3527
  const [savingModel, setSavingModel] = (0, react.useState)(null);
3527
3528
  const [copied, setCopied] = (0, react.useState)(false);
3528
3529
  const [connectionNotice, setConnectionNotice] = (0, react.useState)(null);
3529
- const t = zh$1;
3530
+ const t = zh$2;
3530
3531
  const notifyChange = (0, react.useCallback)(() => {
3531
3532
  onModelChange?.();
3532
3533
  loadModelDirectory?.();
@@ -3534,10 +3535,10 @@ window.__ModuleLoader__.load({
3534
3535
  const loadStatus = (0, react.useCallback)(async (quiet = false) => {
3535
3536
  if (!quiet) setError(null);
3536
3537
  try {
3537
- const data = await fetchApi$3("/status");
3538
+ const data = await fetchApi$5("/status");
3538
3539
  setStatus(data);
3539
3540
  const drafts = {};
3540
- for (const model of data.models) drafts[model.id] = formatCapacity(data.contextWindowOverrides[model.id] || model.defaultContextWindow);
3541
+ for (const model of data.models) drafts[model.id] = formatCapacity$1(data.contextWindowOverrides[model.id] || model.defaultContextWindow);
3541
3542
  setContextDrafts(drafts);
3542
3543
  } catch (err) {
3543
3544
  if (!quiet) setError(err instanceof Error ? err.message : String(err));
@@ -3562,7 +3563,7 @@ window.__ModuleLoader__.load({
3562
3563
  const timer = window.setInterval(() => {
3563
3564
  (async () => {
3564
3565
  try {
3565
- const poll = await fetchApi$3("/login/status");
3566
+ const poll = await fetchApi$5("/login/status");
3566
3567
  setFlow(poll);
3567
3568
  if (poll.status === "complete") {
3568
3569
  await loadStatus();
@@ -3583,7 +3584,7 @@ window.__ModuleLoader__.load({
3583
3584
  setBusy("login");
3584
3585
  setError(null);
3585
3586
  setCopied(false);
3586
- const next = await fetchApi$3("/login", {
3587
+ const next = await fetchApi$5("/login", {
3587
3588
  method: "POST",
3588
3589
  body: JSON.stringify({})
3589
3590
  });
@@ -3596,7 +3597,7 @@ window.__ModuleLoader__.load({
3596
3597
  };
3597
3598
  const handleCancelLogin = async () => {
3598
3599
  try {
3599
- await fetchApi$3("/login/cancel", { method: "POST" });
3600
+ await fetchApi$5("/login/cancel", { method: "POST" });
3600
3601
  setFlow({ status: "idle" });
3601
3602
  } catch (err) {
3602
3603
  setError(err instanceof Error ? err.message : String(err));
@@ -3616,7 +3617,7 @@ window.__ModuleLoader__.load({
3616
3617
  try {
3617
3618
  setBusy(`${action}-${accountId}`);
3618
3619
  setError(null);
3619
- const updated = await fetchApi$3("/accounts", {
3620
+ const updated = await fetchApi$5("/accounts", {
3620
3621
  method: "POST",
3621
3622
  body: JSON.stringify({
3622
3623
  action,
@@ -3636,7 +3637,7 @@ window.__ModuleLoader__.load({
3636
3637
  try {
3637
3638
  setBusy("strategy");
3638
3639
  setError(null);
3639
- const updated = await fetchApi$3("/accounts", {
3640
+ const updated = await fetchApi$5("/accounts", {
3640
3641
  method: "POST",
3641
3642
  body: JSON.stringify({
3642
3643
  action: "strategy",
@@ -3659,7 +3660,7 @@ window.__ModuleLoader__.load({
3659
3660
  const handleRelogin = (accountId) => {
3660
3661
  (async () => {
3661
3662
  try {
3662
- const updated = await fetchApi$3("/accounts", {
3663
+ const updated = await fetchApi$5("/accounts", {
3663
3664
  method: "POST",
3664
3665
  body: JSON.stringify({
3665
3666
  action: "relogin",
@@ -3678,7 +3679,7 @@ window.__ModuleLoader__.load({
3678
3679
  try {
3679
3680
  setBusy("quota");
3680
3681
  setError(null);
3681
- const updated = await fetchApi$3("/quota", { method: "POST" });
3682
+ const updated = await fetchApi$5("/quota", { method: "POST" });
3682
3683
  setStatus(updated);
3683
3684
  } catch (err) {
3684
3685
  setError(err instanceof Error ? err.message : String(err));
@@ -3691,10 +3692,10 @@ window.__ModuleLoader__.load({
3691
3692
  try {
3692
3693
  setBusy("catalog");
3693
3694
  setError(null);
3694
- const updated = await fetchApi$3("/catalog/refresh", { method: "POST" });
3695
+ const updated = await fetchApi$5("/catalog/refresh", { method: "POST" });
3695
3696
  setStatus(updated);
3696
3697
  const drafts = {};
3697
- for (const model of updated.models) drafts[model.id] = formatCapacity(updated.contextWindowOverrides[model.id] || model.defaultContextWindow);
3698
+ for (const model of updated.models) drafts[model.id] = formatCapacity$1(updated.contextWindowOverrides[model.id] || model.defaultContextWindow);
3698
3699
  setContextDrafts(drafts);
3699
3700
  notifyChange();
3700
3701
  } catch (err) {
@@ -3708,7 +3709,7 @@ window.__ModuleLoader__.load({
3708
3709
  setBusy("connection");
3709
3710
  setError(null);
3710
3711
  setConnectionNotice(null);
3711
- const result = await fetchApi$3("/connection/test", { method: "POST" });
3712
+ const result = await fetchApi$5("/connection/test", { method: "POST" });
3712
3713
  setConnectionNotice(result.connected ? `${t.testSuccess} · ${result.latencyMs} ms` : t.testFailed);
3713
3714
  await loadStatus(true);
3714
3715
  } catch (err) {
@@ -3719,7 +3720,7 @@ window.__ModuleLoader__.load({
3719
3720
  };
3720
3721
  const applyEnabled = async (enabledModelIds) => {
3721
3722
  try {
3722
- const updated = await fetchApi$3("/models", {
3723
+ const updated = await fetchApi$5("/models", {
3723
3724
  method: "POST",
3724
3725
  body: JSON.stringify({ enabledModelIds })
3725
3726
  });
@@ -3735,7 +3736,7 @@ window.__ModuleLoader__.load({
3735
3736
  enabled
3736
3737
  } : prev);
3737
3738
  try {
3738
- const updated = await fetchApi$3("/settings", {
3739
+ const updated = await fetchApi$5("/settings", {
3739
3740
  method: "POST",
3740
3741
  body: JSON.stringify({ enabled })
3741
3742
  });
@@ -3758,7 +3759,7 @@ window.__ModuleLoader__.load({
3758
3759
  };
3759
3760
  const handleUpdateEffort = async (effort) => {
3760
3761
  try {
3761
- const updated = await fetchApi$3("/settings", {
3762
+ const updated = await fetchApi$5("/settings", {
3762
3763
  method: "POST",
3763
3764
  body: JSON.stringify({ defaultReasoningEffort: effort })
3764
3765
  });
@@ -3770,7 +3771,7 @@ window.__ModuleLoader__.load({
3770
3771
  };
3771
3772
  const handleSaveContextWindow = async (modelId) => {
3772
3773
  const raw = contextDrafts[modelId] || "";
3773
- const parsed = parsePositiveCapacity(raw);
3774
+ const parsed = parsePositiveCapacity$1(raw);
3774
3775
  if (parsed === null) {
3775
3776
  setError(`Invalid context capacity: ${raw}`);
3776
3777
  return;
@@ -3778,14 +3779,14 @@ window.__ModuleLoader__.load({
3778
3779
  try {
3779
3780
  setSavingModel(modelId);
3780
3781
  setError(null);
3781
- const updated = await fetchApi$3("/settings", {
3782
+ const updated = await fetchApi$5("/settings", {
3782
3783
  method: "POST",
3783
3784
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
3784
3785
  });
3785
3786
  setStatus(updated);
3786
3787
  setContextDrafts((prev) => ({
3787
3788
  ...prev,
3788
- [modelId]: formatCapacity(parsed)
3789
+ [modelId]: formatCapacity$1(parsed)
3789
3790
  }));
3790
3791
  notifyChange();
3791
3792
  } catch (err) {
@@ -3872,7 +3873,7 @@ window.__ModuleLoader__.load({
3872
3873
  children: t.codeExpires
3873
3874
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3874
3875
  className: "dsha-value",
3875
- children: formatDate(flow?.expiresAt)
3876
+ children: formatDate$1(flow?.expiresAt)
3876
3877
  })]
3877
3878
  }),
3878
3879
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -4075,7 +4076,7 @@ window.__ModuleLoader__.load({
4075
4076
  title: model.id,
4076
4077
  children: [model.name, model.defaultContextWindow < model.contextWindow && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4077
4078
  className: "dsha-model-meta",
4078
- children: formatCapacity(model.contextWindow)
4079
+ children: formatCapacity$1(model.contextWindow)
4079
4080
  })]
4080
4081
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4081
4082
  className: "dsha-capacity-control",
@@ -4160,7 +4161,7 @@ window.__ModuleLoader__.load({
4160
4161
  window.limit ?? "—",
4161
4162
  " ",
4162
4163
  t.requests
4163
- ] }), window.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.resetAt.replace("{time}", formatReset(window.resetsAt)) })]
4164
+ ] }), window.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.resetAt.replace("{time}", formatReset$1(window.resetsAt)) })]
4164
4165
  })
4165
4166
  ]
4166
4167
  }, window.id);
@@ -4199,71 +4200,1256 @@ window.__ModuleLoader__.load({
4199
4200
  });
4200
4201
  }
4201
4202
  //#endregion
4202
- //#region src/client/ProviderHubSection.tsx
4203
- const HUB_TABS = [
4204
- {
4205
- id: "chatgpt",
4206
- label: "ChatGPT"
4207
- },
4208
- {
4209
- id: "antigravity",
4210
- label: "Antigravity"
4211
- },
4212
- {
4213
- id: "command-code",
4214
- label: "Command Code"
4215
- },
4216
- {
4217
- id: "kimi-code",
4218
- label: "Kimi Code"
4219
- }
4203
+ //#region src/shared/workbuddy-contracts.ts
4204
+ /** Every level this route can name, in escalating order (the card's sort key). */
4205
+ const WORKBUDDY_REASONING_EFFORTS = [
4206
+ "minimal",
4207
+ "low",
4208
+ "medium",
4209
+ "high",
4210
+ "xhigh",
4211
+ "max"
4220
4212
  ];
4213
+ //#endregion
4214
+ //#region src/client/workbuddy/locales.ts
4215
+ const NS_WORKBUDDY = "dsh-workbuddy";
4216
+ const zh$1 = {
4217
+ title: "WorkBuddy",
4218
+ pageDesc: "复用本机 CodeBuddy 桌面端登录态,管理 WorkBuddy(CodeBuddy 订阅)模型、上下文窗口与额度。",
4219
+ account: "账号",
4220
+ noAccounts: "暂无账号,点击「添加国区账号 / 添加国际区账号」完成浏览器授权,或登录 CodeBuddy 桌面端后重新扫描。",
4221
+ signedIn: "已找到凭据",
4222
+ signedOut: "未找到凭据",
4223
+ nickname: "昵称",
4224
+ uid: "账号 ID",
4225
+ uin: "UIN",
4226
+ region: "区域",
4227
+ regionCn: "国区",
4228
+ regionIntl: "国际区",
4229
+ accountType: "账号类型",
4230
+ backend: "后端地址",
4231
+ domain: "认证域名",
4232
+ tokenExpires: "登录态有效期",
4233
+ tokenExpired: "已过期",
4234
+ sourceFile: "凭据文件",
4235
+ authDirectory: "凭据目录",
4236
+ storage: "凭据存储",
4237
+ storageNotice: "桌面端账号仍读取 CodeBuddy 自己的凭据文件,插件不会删除这些文件;通过这里添加的账号保存在系统加密存储中(Windows DPAPI / macOS Keychain / Linux Secret Service),token 不进入浏览器。",
4238
+ notFoundTitle: "未找到 WorkBuddy 账号",
4239
+ notFoundHint: "可安装并登录 CodeBuddy 后重新扫描,也可以直接点击下方「添加国区账号」或「添加国际区账号」完成浏览器授权。",
4240
+ routeUnreachable: "无法读取 WorkBuddy 设置路由",
4241
+ routeUnreachableHint: "浏览器里加载的插件版本可能比 Host 进程里运行的新(客户端资源是现读磁盘的,Host 只在启动时加载)。请重启 DSH,让两端来自同一份构建。",
4242
+ rescan: "重新扫描",
4243
+ rescanning: "扫描中...",
4244
+ accounts: "本机凭据",
4245
+ accountsHint: "按账号地区分组。插件添加的账号可删除;CodeBuddy 桌面账号只能从本插件隐藏,绝不删除桌面端原凭据。点击账号会切换模型目录、额度和后续对话。",
4246
+ useAccount: "使用此账号",
4247
+ selectedAccount: "当前账号",
4248
+ addCnAccount: "添加国区账号",
4249
+ addIntlAccount: "添加国际区账号",
4250
+ authorizing: "授权中…",
4251
+ loginWaiting: "请在新打开的浏览器页面完成登录与授权。",
4252
+ loginFailed: "账号授权失败",
4253
+ pluginAccount: "插件账号",
4254
+ desktopAccount: "桌面账号",
4255
+ encryptedStorage: "系统加密存储",
4256
+ hiddenAccount: "已隐藏",
4257
+ hideAccount: "从插件隐藏",
4258
+ restoreAccount: "恢复显示",
4259
+ deleteAccount: "删除账号",
4260
+ deleteConfirm: "确定删除这个插件托管的账号吗?加密存储中的登录凭据会被移除。",
4261
+ connection: "连接",
4262
+ provider: "Provider",
4263
+ providerValue: "WorkBuddy Subscription · workbuddy-subscription",
4264
+ connectionState: "连接状态",
4265
+ connected: "已连接",
4266
+ untested: "未测试",
4267
+ testConnection: "测试连接",
4268
+ testingConnection: "测试中...",
4269
+ latency: "延迟",
4270
+ routeOwned: "模型路由由本插件提供",
4271
+ routeConflict: "模型路由已被其他 Provider 占用:{detail}。请在 DSH 设置中移除重复的 Provider 配置后重试。",
4272
+ modelsSection: "模型",
4273
+ enableProvider: "启用此供应商",
4274
+ modelsHint: "勾选后模型才会出现在对话页的模型选择列表中;未勾选或关闭上方开关可在列表中隐藏该供应商。目录与上下文窗口来自订阅网关的模型目录,并按账号所在区域过滤——跨区调用会被上游拒绝。",
4275
+ refreshCatalog: "刷新模型目录",
4276
+ refreshingCatalog: "刷新中...",
4277
+ selectAll: "全选",
4278
+ unselectAll: "全不选",
4279
+ imageSupport: "图片",
4280
+ textOnly: "纯文本",
4281
+ regionBadge: "区域",
4282
+ unavailableHere: "当前区域不可用",
4283
+ enhanced: "增强功能",
4284
+ defaultReasoningEffort: "默认思考深度",
4285
+ defaultReasoningEffortHint: "控制支持推理的模型在未单独指定时的思考强度。",
4286
+ defaultEffortAuto: "使用模型默认值",
4287
+ effortUnsupported: "当前模型不支持",
4288
+ noReasoningModels: "当前账号的模型都没有声明可用的思考档位,因此没有可选的默认档位。",
4289
+ defaultEffortKept: "已保存的档位不被当前任何模型支持,已保留但不会生效。",
4290
+ contextWindowSection: "模型上下文窗口",
4291
+ contextWindowHint: "默认值来自订阅网关的模型目录(每个模型的真实上下文上限);可覆盖为自定义容量,该值用于 DSH 的压缩与溢出判断,可输入 1M、512K、200K 等容量。",
4292
+ save: "保存",
4293
+ saved: "已保存",
4294
+ saving: "保存中...",
4295
+ quotaSection: "用量与配额",
4296
+ quotaDesc: "数据来自订阅的计费接口,页面可见时最多每 60 秒刷新一次。",
4297
+ refreshQuota: "刷新用量",
4298
+ refreshingQuota: "刷新中...",
4299
+ quotaEmpty: "暂无配额数据,点击「刷新用量」重试。",
4300
+ quotaPackage: "套餐",
4301
+ quotaRemaining: "剩余额度",
4302
+ quotaCycle: "本周期已用",
4303
+ quotaReset: "重置时间",
4304
+ updatedAt: "更新时间:{time}",
4305
+ loading: "加载中...",
4306
+ credits: "credits",
4307
+ composerLabel: "额度"
4308
+ };
4309
+ const en$1 = {
4310
+ title: "WorkBuddy",
4311
+ pageDesc: "Reuse the local CodeBuddy desktop sign-in to manage WorkBuddy (CodeBuddy subscription) models, context windows, and quota.",
4312
+ account: "Account",
4313
+ noAccounts: "No accounts yet. Add a China or international account, or sign in with the CodeBuddy desktop client and rescan.",
4314
+ signedIn: "Credential found",
4315
+ signedOut: "No credential found",
4316
+ nickname: "Nickname",
4317
+ uid: "Account ID",
4318
+ uin: "UIN",
4319
+ region: "Region",
4320
+ regionCn: "China",
4321
+ regionIntl: "International",
4322
+ accountType: "Account type",
4323
+ backend: "Backend",
4324
+ domain: "Auth domain",
4325
+ tokenExpires: "Sign-in valid until",
4326
+ tokenExpired: "Expired",
4327
+ sourceFile: "Credential file",
4328
+ authDirectory: "Credential directory",
4329
+ storage: "Credential storage",
4330
+ storageNotice: "Desktop accounts continue to use CodeBuddy’s credential files, which this plugin never deletes. Accounts added here use encrypted OS storage (Windows DPAPI, macOS Keychain, or Linux Secret Service); tokens never enter the browser.",
4331
+ notFoundTitle: "No WorkBuddy account found",
4332
+ notFoundHint: "Install and sign in to CodeBuddy and rescan, or use “Add China account” / “Add international account” below to authorize in the browser.",
4333
+ routeUnreachable: "The WorkBuddy settings route could not be read",
4334
+ routeUnreachableHint: "The plugin loaded in the browser may be newer than the one running in the Host: client assets are read from disk on demand, while the Host loads them only at startup. Restart DSH so both halves come from the same build.",
4335
+ rescan: "Rescan",
4336
+ rescanning: "Scanning...",
4337
+ accounts: "Local credentials",
4338
+ accountsHint: "Accounts are grouped by region. Plugin-managed accounts can be deleted; CodeBuddy desktop accounts can only be hidden from this plugin and their source files are never deleted. Selecting one switches models, quota, and chats.",
4339
+ useAccount: "Use this account",
4340
+ selectedAccount: "Selected account",
4341
+ addCnAccount: "Add China account",
4342
+ addIntlAccount: "Add international account",
4343
+ authorizing: "Authorizing…",
4344
+ loginWaiting: "Complete sign-in and authorization in the newly opened browser page.",
4345
+ loginFailed: "Account authorization failed",
4346
+ pluginAccount: "Plugin account",
4347
+ desktopAccount: "Desktop account",
4348
+ encryptedStorage: "Encrypted OS storage",
4349
+ hiddenAccount: "Hidden",
4350
+ hideAccount: "Hide from plugin",
4351
+ restoreAccount: "Restore",
4352
+ deleteAccount: "Delete account",
4353
+ deleteConfirm: "Delete this plugin-managed account? Its encrypted credential will be removed.",
4354
+ connection: "Connection",
4355
+ provider: "Provider",
4356
+ providerValue: "WorkBuddy Subscription · workbuddy-subscription",
4357
+ connectionState: "Connection state",
4358
+ connected: "Connected",
4359
+ untested: "Untested",
4360
+ testConnection: "Test connection",
4361
+ testingConnection: "Testing...",
4362
+ latency: "Latency",
4363
+ routeOwned: "This plugin serves the model route",
4364
+ routeConflict: "Another provider already owns the model route: {detail}. Remove the duplicate provider configuration in DSH settings and reload.",
4365
+ modelsSection: "Models",
4366
+ enableProvider: "Enable this provider",
4367
+ modelsHint: "Checked models appear in the DSH conversation model list. The catalog and its context windows come from the subscription gateway and are filtered by the account’s region — the upstream rejects a model asked of the wrong region.",
4368
+ refreshCatalog: "Refresh catalog",
4369
+ refreshingCatalog: "Refreshing...",
4370
+ selectAll: "Select all",
4371
+ unselectAll: "Deselect all",
4372
+ imageSupport: "Images",
4373
+ textOnly: "Text only",
4374
+ regionBadge: "Regions",
4375
+ unavailableHere: "Unavailable in this region",
4376
+ enhanced: "Enhanced features",
4377
+ defaultReasoningEffort: "Default reasoning effort",
4378
+ defaultReasoningEffortHint: "Reasoning effort for models that support it when the conversation does not specify one.",
4379
+ defaultEffortAuto: "Use the model default",
4380
+ effortUnsupported: "unsupported by the current models",
4381
+ noReasoningModels: "None of this account’s models declare a reasoning level, so there is no default to choose.",
4382
+ defaultEffortKept: "The saved level is not supported by any current model; it is kept but has no effect.",
4383
+ contextWindowSection: "Model context window",
4384
+ contextWindowHint: "Defaults come from the subscription gateway’s own catalog (each model’s real context cap); override one with the capacity DSH should use for compaction and overflow decisions (e.g., 1M, 512K, 200K).",
4385
+ save: "Save",
4386
+ saved: "Saved",
4387
+ saving: "Saving...",
4388
+ quotaSection: "Usage & quota",
4389
+ quotaDesc: "Read from the subscription billing endpoint; refreshes at most once every 60 seconds while visible.",
4390
+ refreshQuota: "Refresh quota",
4391
+ refreshingQuota: "Refreshing...",
4392
+ quotaEmpty: "No quota data yet — use “Refresh quota” to retry.",
4393
+ quotaPackage: "Package",
4394
+ quotaRemaining: "Remaining credits",
4395
+ quotaCycle: "Used this cycle",
4396
+ quotaReset: "Resets",
4397
+ updatedAt: "Updated at: {time}",
4398
+ loading: "Loading...",
4399
+ credits: "credits",
4400
+ composerLabel: "Quota"
4401
+ };
4402
+ const dictionaries$1 = {
4403
+ zh: zh$1,
4404
+ "zh-CN": zh$1,
4405
+ en: en$1,
4406
+ "en-US": en$1
4407
+ };
4408
+ //#endregion
4409
+ //#region src/client/workbuddy/WorkBuddySection.tsx
4221
4410
  /**
4222
- * Single settings page that hosts every subscription provider behind tabs,
4223
- * so the settings sidebar shows one entry instead of one per provider. Only
4224
- * the active tab is mounted, mirroring the shell's previous behavior of
4225
- * mounting just the selected settings page (each provider section refetches
4226
- * its status on mount).
4411
+ * Display label per reasoning level. The locale dictionary only accepts flat
4412
+ * string values, so this nested table lives with the control that renders it.
4227
4413
  */
4228
- function ProviderHubSection({ t, onModelChange, ...runtime }) {
4229
- const [active, setActive] = (0, react.useState)("chatgpt");
4230
- const onTabKeyDown = (0, react.useCallback)((event) => {
4231
- if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
4232
- event.preventDefault();
4233
- const index = HUB_TABS.findIndex((tab) => tab.id === active);
4234
- const delta = event.key === "ArrowRight" ? 1 : -1;
4235
- const next = HUB_TABS[(index + delta + HUB_TABS.length) % HUB_TABS.length];
4236
- setActive(next.id);
4237
- document.getElementById(`dsh-hub-tab-${next.id}`)?.focus();
4238
- }, [active]);
4239
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
4240
- className: "dsh-codex-page",
4241
- "aria-labelledby": "dsh-hub-title",
4242
- children: [
4243
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("header", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
4244
- id: "dsh-hub-title",
4245
- className: "dsh-codex-title",
4246
- children: t("hubTitle")
4247
- }) }),
4248
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4249
- className: "dsh-codex-segments dsh-hub-tabs",
4250
- role: "tablist",
4251
- "aria-label": t("hubTitle"),
4252
- children: HUB_TABS.map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4253
- type: "button",
4254
- role: "tab",
4255
- id: `dsh-hub-tab-${tab.id}`,
4256
- "aria-selected": active === tab.id,
4257
- "aria-controls": `dsh-hub-panel-${tab.id}`,
4258
- className: active === tab.id ? "active" : void 0,
4259
- tabIndex: active === tab.id ? 0 : -1,
4260
- onClick: () => setActive(tab.id),
4261
- onKeyDown: onTabKeyDown,
4262
- children: tab.label
4263
- }, tab.id))
4264
- }),
4265
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4266
- role: "tabpanel",
4414
+ const EFFORT_LABELS = {
4415
+ minimal: "Minimal",
4416
+ low: "Low",
4417
+ medium: "Medium",
4418
+ high: "High",
4419
+ xhigh: "X-High",
4420
+ max: "Max"
4421
+ };
4422
+ const API$4 = "/workbuddy/api";
4423
+ /**
4424
+ * Call one settings route and unwrap its `{ ok, value }` envelope.
4425
+ *
4426
+ * The response body is read as text first, because a route that is not mounted
4427
+ * answers with an empty body — and `res.json()` on that throws a bare
4428
+ * "Unexpected end of JSON input" that says nothing about what actually failed.
4429
+ * That is exactly what happens when the client bundle is newer than the Host
4430
+ * process (a stale Host has no route to answer), so the error is reported as
4431
+ * such instead of as a credential problem.
4432
+ */
4433
+ async function fetchApi$4(path, options) {
4434
+ const res = await fetch(`${API$4}${path}`, {
4435
+ ...options,
4436
+ headers: {
4437
+ "Content-Type": "application/json",
4438
+ ...options?.headers
4439
+ }
4440
+ });
4441
+ const text = await res.text();
4442
+ if (text.trim() === "") throw new Error(`The WorkBuddy settings route did not answer (HTTP ${res.status} ${res.statusText || "no body"}). The plugin loaded in the browser may be newer than the one running in the Host — restart DSH so both halves come from the same build.`);
4443
+ let json;
4444
+ try {
4445
+ json = JSON.parse(text);
4446
+ } catch {
4447
+ throw new Error(`The WorkBuddy settings route returned a non-JSON response (HTTP ${res.status}): ${text.slice(0, 200)}`);
4448
+ }
4449
+ if (!res.ok || json.ok !== true) throw new Error(json.error || `HTTP ${res.status}`);
4450
+ return json.value;
4451
+ }
4452
+ /** Parse "1M", "512K", "200000" into a positive integer token count. */
4453
+ function parsePositiveCapacity(value) {
4454
+ const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
4455
+ if (matched === null) return null;
4456
+ const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
4457
+ const parsed = Number(matched[1]) * multiplier;
4458
+ return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
4459
+ }
4460
+ function formatCapacity(value) {
4461
+ if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
4462
+ if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
4463
+ return String(value);
4464
+ }
4465
+ function formatDate(ms) {
4466
+ if (ms === void 0 || ms === null || ms <= 0) return "—";
4467
+ try {
4468
+ return new Intl.DateTimeFormat(void 0, {
4469
+ dateStyle: "medium",
4470
+ timeStyle: "short"
4471
+ }).format(ms);
4472
+ } catch {
4473
+ return "—";
4474
+ }
4475
+ }
4476
+ function formatReset(resetsAt) {
4477
+ if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
4478
+ const diff = resetsAt - Date.now();
4479
+ if (diff <= 0) return "now";
4480
+ const mins = Math.floor(diff / 6e4);
4481
+ const hours = Math.floor(mins / 60);
4482
+ const days = Math.floor(hours / 24);
4483
+ if (days > 0) return `${days}d ${hours % 24}h`;
4484
+ if (hours > 0) return `${hours}h ${mins % 60}m`;
4485
+ return `${mins}m`;
4486
+ }
4487
+ /** Mask a UIN so the card shows identity without publishing the full number. */
4488
+ function maskUin(uin) {
4489
+ if (uin === void 0 || uin === null || uin === "") return "—";
4490
+ if (uin.length <= 6) return uin;
4491
+ return `${uin.slice(0, 4)}****${uin.slice(-2)}`;
4492
+ }
4493
+ /** Shorten an absolute credential path to its file name for display. */
4494
+ function displayFile(file) {
4495
+ if (file === void 0 || file === null || file === "") return "—";
4496
+ const parts = file.split(/[\\/]/);
4497
+ return parts[parts.length - 1] || file;
4498
+ }
4499
+ /**
4500
+ * Reasoning levels the default-effort control may offer.
4501
+ *
4502
+ * The levels come from what this account's models actually declare — never from
4503
+ * the shipped enum alone. The setting is one global default applied to whichever
4504
+ * model a conversation uses, so the list is their union; each entry carries the
4505
+ * models behind it, and a level only some models accept is labelled as such.
4506
+ * Order follows {@link WORKBUDDY_REASONING_EFFORTS}, which is the escalating
4507
+ * order the upstream ladder uses.
4508
+ */
4509
+ function reasoningEffortChoices(models) {
4510
+ const declared = /* @__PURE__ */ new Map();
4511
+ for (const model of models) for (const effort of model.reasoningEfforts ?? []) {
4512
+ const names = declared.get(effort);
4513
+ if (names === void 0) declared.set(effort, [model.name]);
4514
+ else names.push(model.name);
4515
+ }
4516
+ return WORKBUDDY_REASONING_EFFORTS.filter((effort) => declared.has(effort)).map((effort) => ({
4517
+ value: effort,
4518
+ models: declared.get(effort)
4519
+ }));
4520
+ }
4521
+ /**
4522
+ * Whether a saved default is unusable for every model on this account.
4523
+ *
4524
+ * The adapter drops a level the chosen model does not accept instead of sending
4525
+ * it, so a value that no model declares silently does nothing. Reporting it is
4526
+ * what keeps that from looking like the setting was applied.
4527
+ */
4528
+ function unsupportedReasoningEffort(configured, models) {
4529
+ if (configured === null || configured === void 0) return null;
4530
+ return models.some((model) => (model.reasoningEfforts ?? []).includes(configured)) ? null : configured;
4531
+ }
4532
+ /** Defend against a response that omits the arrays the card renders. */
4533
+ function normalizeStatus(data) {
4534
+ return {
4535
+ ...data,
4536
+ models: Array.isArray(data?.models) ? data.models : [],
4537
+ contextWindowOverrides: data?.contextWindowOverrides ?? {},
4538
+ accounts: Array.isArray(data?.accounts) ? data.accounts : []
4539
+ };
4540
+ }
4541
+ /**
4542
+ * The shared card's label set, taken from this tab's dictionary.
4543
+ *
4544
+ * Wording is the shared one so the five provider tabs cannot drift apart; the
4545
+ * couple of WorkBuddy-specific words are supplied here.
4546
+ */
4547
+ function accountPoolLabels(t) {
4548
+ return {
4549
+ ...accountPoolZh,
4550
+ accountPool: t.accounts,
4551
+ noAccounts: t.noAccounts,
4552
+ storage: t.storage,
4553
+ storageNotice: t.storageNotice,
4554
+ deleteAccount: t.deleteAccount,
4555
+ email: t.nickname,
4556
+ accountId: t.uid
4557
+ };
4558
+ }
4559
+ function WorkBuddySection({ onModelChange, loadModelDirectory }) {
4560
+ const [status, setStatus] = (0, react.useState)(null);
4561
+ const [loading, setLoading] = (0, react.useState)(true);
4562
+ const [busy, setBusy] = (0, react.useState)(null);
4563
+ const [error, setError] = (0, react.useState)(null);
4564
+ const [statusFailed, setStatusFailed] = (0, react.useState)(false);
4565
+ const [connection, setConnection] = (0, react.useState)(null);
4566
+ const [accounts, setAccounts] = (0, react.useState)(null);
4567
+ const [loginProgress, setLoginProgress] = (0, react.useState)(null);
4568
+ const loginIntervalRef = (0, react.useRef)(null);
4569
+ const loginTimeoutRef = (0, react.useRef)(null);
4570
+ const [contextDrafts, setContextDrafts] = (0, react.useState)({});
4571
+ const [savingModel, setSavingModel] = (0, react.useState)(null);
4572
+ const t = zh$1;
4573
+ const notifyChange = (0, react.useCallback)(() => {
4574
+ onModelChange?.();
4575
+ loadModelDirectory?.();
4576
+ }, [onModelChange, loadModelDirectory]);
4577
+ const effortChoices = (0, react.useMemo)(() => reasoningEffortChoices(status?.models ?? []), [status?.models]);
4578
+ const allModels = status?.models ?? [];
4579
+ const poolAccounts = (0, react.useMemo)(() => Array.isArray(status?.accounts) ? status.accounts : [], [status?.accounts]);
4580
+ const strayEffort = unsupportedReasoningEffort(status?.defaultReasoningEffort, allModels);
4581
+ const loadStatus = (0, react.useCallback)(async (quiet = false) => {
4582
+ if (!quiet) setError(null);
4583
+ try {
4584
+ const normalized = normalizeStatus(await fetchApi$4("/status"));
4585
+ setStatus(normalized);
4586
+ setStatusFailed(false);
4587
+ const drafts = {};
4588
+ for (const model of normalized.models) drafts[model.id] = formatCapacity(normalized.contextWindowOverrides[model.id] || model.defaultContextWindow);
4589
+ setContextDrafts(drafts);
4590
+ } catch (err) {
4591
+ setStatusFailed(true);
4592
+ if (!quiet) setError(err instanceof Error ? err.message : String(err));
4593
+ } finally {
4594
+ setLoading(false);
4595
+ }
4596
+ }, []);
4597
+ const loadAccounts = (0, react.useCallback)(async () => {
4598
+ try {
4599
+ const payload = await fetchApi$4("/accounts");
4600
+ setAccounts({
4601
+ authDirectory: payload?.authDirectory ?? "",
4602
+ managedStoragePath: payload?.managedStoragePath,
4603
+ accounts: Array.isArray(payload?.accounts) ? payload.accounts : []
4604
+ });
4605
+ } catch {}
4606
+ }, []);
4607
+ (0, react.useEffect)(() => {
4608
+ loadStatus();
4609
+ loadAccounts();
4610
+ const refreshWhenVisible = () => {
4611
+ if (document.visibilityState === "visible") {
4612
+ loadStatus(true);
4613
+ loadAccounts();
4614
+ }
4615
+ };
4616
+ document.addEventListener("visibilitychange", refreshWhenVisible);
4617
+ return () => {
4618
+ document.removeEventListener("visibilitychange", refreshWhenVisible);
4619
+ if (loginIntervalRef.current !== null) window.clearInterval(loginIntervalRef.current);
4620
+ if (loginTimeoutRef.current !== null) window.clearTimeout(loginTimeoutRef.current);
4621
+ };
4622
+ }, [loadStatus, loadAccounts]);
4623
+ const handleRescan = async () => {
4624
+ try {
4625
+ setBusy("rescan");
4626
+ setError(null);
4627
+ const updated = await fetchApi$4("/rescan", { method: "POST" });
4628
+ setStatus(updated);
4629
+ await loadAccounts();
4630
+ notifyChange();
4631
+ } catch (err) {
4632
+ setError(err instanceof Error ? err.message : String(err));
4633
+ } finally {
4634
+ setBusy(null);
4635
+ }
4636
+ };
4637
+ const handleAddAccount = async (region) => {
4638
+ try {
4639
+ setBusy(`login:${region}`);
4640
+ setError(null);
4641
+ setLoginProgress(t.loginWaiting);
4642
+ const flow = await fetchApi$4("/accounts/login", {
4643
+ method: "POST",
4644
+ body: JSON.stringify({ region })
4645
+ });
4646
+ if (flow.authUrl) window.open(flow.authUrl, "_blank", "noopener,noreferrer");
4647
+ if (loginIntervalRef.current !== null) window.clearInterval(loginIntervalRef.current);
4648
+ if (loginTimeoutRef.current !== null) window.clearTimeout(loginTimeoutRef.current);
4649
+ const timer = window.setInterval(() => {
4650
+ (async () => {
4651
+ try {
4652
+ const poll = await fetchApi$4("/accounts/login/status");
4653
+ if (poll.progress) setLoginProgress(poll.progress);
4654
+ if (poll.status === "complete") {
4655
+ window.clearInterval(timer);
4656
+ loginIntervalRef.current = null;
4657
+ if (loginTimeoutRef.current !== null) window.clearTimeout(loginTimeoutRef.current);
4658
+ loginTimeoutRef.current = null;
4659
+ setBusy(null);
4660
+ setLoginProgress(null);
4661
+ if (poll.accountId) await fetchApi$4("/settings", {
4662
+ method: "POST",
4663
+ body: JSON.stringify({ selectedAccountId: poll.accountId })
4664
+ });
4665
+ await loadStatus();
4666
+ await loadAccounts();
4667
+ notifyChange();
4668
+ } else if (poll.status === "error") {
4669
+ window.clearInterval(timer);
4670
+ loginIntervalRef.current = null;
4671
+ if (loginTimeoutRef.current !== null) window.clearTimeout(loginTimeoutRef.current);
4672
+ loginTimeoutRef.current = null;
4673
+ setBusy(null);
4674
+ setLoginProgress(null);
4675
+ setError(poll.error || t.loginFailed);
4676
+ }
4677
+ } catch {}
4678
+ })();
4679
+ }, 1500);
4680
+ loginIntervalRef.current = timer;
4681
+ loginTimeoutRef.current = window.setTimeout(() => {
4682
+ window.clearInterval(timer);
4683
+ loginIntervalRef.current = null;
4684
+ loginTimeoutRef.current = null;
4685
+ setBusy(null);
4686
+ setLoginProgress(null);
4687
+ }, 300 * 1e3);
4688
+ } catch (err) {
4689
+ setBusy(null);
4690
+ setLoginProgress(null);
4691
+ setError(err instanceof Error ? err.message : String(err));
4692
+ }
4693
+ };
4694
+ /**
4695
+ * One account action, whether it is a pool action (`set-primary`, `hide`) or a
4696
+ * credential action (`delete`). The host route dispatches on `action`.
4697
+ */
4698
+ const handlePoolAction = async (action, accountId) => {
4699
+ try {
4700
+ setBusy(`${action}:${accountId}`);
4701
+ setError(null);
4702
+ const updated = await fetchApi$4("/accounts/action", {
4703
+ method: "POST",
4704
+ body: JSON.stringify({
4705
+ action,
4706
+ accountId
4707
+ })
4708
+ });
4709
+ setStatus(normalizeStatus(updated));
4710
+ await loadAccounts();
4711
+ notifyChange();
4712
+ } catch (err) {
4713
+ setError(err instanceof Error ? err.message : String(err));
4714
+ } finally {
4715
+ setBusy(null);
4716
+ }
4717
+ };
4718
+ const handleDeleteAccount = async (accountId) => {
4719
+ if (!window.confirm(t.deleteConfirm)) return;
4720
+ await handlePoolAction("delete", accountId);
4721
+ };
4722
+ const handleSetStrategy = async (strategy) => {
4723
+ try {
4724
+ setBusy("strategy");
4725
+ setError(null);
4726
+ const updated = await fetchApi$4("/accounts/strategy", {
4727
+ method: "POST",
4728
+ body: JSON.stringify({ strategy })
4729
+ });
4730
+ setStatus(normalizeStatus(updated));
4731
+ await loadAccounts();
4732
+ } catch (err) {
4733
+ setError(err instanceof Error ? err.message : String(err));
4734
+ } finally {
4735
+ setBusy(null);
4736
+ }
4737
+ };
4738
+ const handleTestConnection = async () => {
4739
+ try {
4740
+ setBusy("connection");
4741
+ setError(null);
4742
+ setConnection(await fetchApi$4("/connection/test", { method: "POST" }));
4743
+ } catch (err) {
4744
+ setError(err instanceof Error ? err.message : String(err));
4745
+ } finally {
4746
+ setBusy(null);
4747
+ }
4748
+ };
4749
+ const handleRefreshQuota = async () => {
4750
+ try {
4751
+ setBusy("quota");
4752
+ setError(null);
4753
+ const updated = await fetchApi$4("/quota", { method: "POST" });
4754
+ setStatus(updated);
4755
+ } catch (err) {
4756
+ setError(err instanceof Error ? err.message : String(err));
4757
+ } finally {
4758
+ setBusy(null);
4759
+ }
4760
+ };
4761
+ const toggleEnabled = async (enabled) => {
4762
+ try {
4763
+ setBusy("enabled");
4764
+ setError(null);
4765
+ const updated = await fetchApi$4("/settings", {
4766
+ method: "POST",
4767
+ body: JSON.stringify({ enabled })
4768
+ });
4769
+ setStatus(updated);
4770
+ notifyChange();
4771
+ } catch (err) {
4772
+ setError(err instanceof Error ? err.message : String(err));
4773
+ } finally {
4774
+ setBusy(null);
4775
+ }
4776
+ };
4777
+ const toggleModel = async (modelId, enabled) => {
4778
+ if (status === null) return;
4779
+ const current = status.models.filter((model) => model.enabled).map((model) => model.id);
4780
+ const next = enabled ? [.../* @__PURE__ */ new Set([...current, modelId])] : current.filter((id) => id !== modelId);
4781
+ try {
4782
+ setBusy(`model:${modelId}`);
4783
+ setError(null);
4784
+ const updated = await fetchApi$4("/settings", {
4785
+ method: "POST",
4786
+ body: JSON.stringify({ enabledModelIds: next })
4787
+ });
4788
+ setStatus(updated);
4789
+ notifyChange();
4790
+ } catch (err) {
4791
+ setError(err instanceof Error ? err.message : String(err));
4792
+ } finally {
4793
+ setBusy(null);
4794
+ }
4795
+ };
4796
+ const setAllModels = async (enabled) => {
4797
+ if (status === null) return;
4798
+ try {
4799
+ setBusy("models-all");
4800
+ setError(null);
4801
+ const updated = await fetchApi$4("/settings", {
4802
+ method: "POST",
4803
+ body: JSON.stringify({ enabledModelIds: enabled ? status.models.map((model) => model.id) : [] })
4804
+ });
4805
+ setStatus(updated);
4806
+ notifyChange();
4807
+ } catch (err) {
4808
+ setError(err instanceof Error ? err.message : String(err));
4809
+ } finally {
4810
+ setBusy(null);
4811
+ }
4812
+ };
4813
+ const handleUpdateEffort = async (effort) => {
4814
+ try {
4815
+ setBusy("effort");
4816
+ setError(null);
4817
+ const updated = await fetchApi$4("/settings", {
4818
+ method: "POST",
4819
+ body: JSON.stringify({ defaultReasoningEffort: effort })
4820
+ });
4821
+ setStatus(updated);
4822
+ notifyChange();
4823
+ } catch (err) {
4824
+ setError(err instanceof Error ? err.message : String(err));
4825
+ } finally {
4826
+ setBusy(null);
4827
+ }
4828
+ };
4829
+ const handleRefreshCatalog = async () => {
4830
+ try {
4831
+ setBusy("catalog");
4832
+ setError(null);
4833
+ const updated = await fetchApi$4("/catalog/refresh", { method: "POST" });
4834
+ const normalized = {
4835
+ ...updated,
4836
+ models: Array.isArray(updated?.models) ? updated.models : [],
4837
+ contextWindowOverrides: updated?.contextWindowOverrides ?? {}
4838
+ };
4839
+ setStatus(normalized);
4840
+ const drafts = {};
4841
+ for (const model of normalized.models) drafts[model.id] = formatCapacity(normalized.contextWindowOverrides[model.id] || model.defaultContextWindow);
4842
+ setContextDrafts(drafts);
4843
+ notifyChange();
4844
+ } catch (err) {
4845
+ setError(err instanceof Error ? err.message : String(err));
4846
+ } finally {
4847
+ setBusy(null);
4848
+ }
4849
+ };
4850
+ const handleSaveContextWindow = async (modelId) => {
4851
+ const raw = contextDrafts[modelId] || "";
4852
+ const parsed = parsePositiveCapacity(raw);
4853
+ if (parsed === null) {
4854
+ setError(`Invalid context capacity: ${raw}`);
4855
+ return;
4856
+ }
4857
+ try {
4858
+ setSavingModel(modelId);
4859
+ setError(null);
4860
+ const updated = await fetchApi$4("/settings", {
4861
+ method: "POST",
4862
+ body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
4863
+ });
4864
+ setStatus(updated);
4865
+ setContextDrafts((prev) => ({
4866
+ ...prev,
4867
+ [modelId]: formatCapacity(parsed)
4868
+ }));
4869
+ notifyChange();
4870
+ } catch (err) {
4871
+ setError(err instanceof Error ? err.message : String(err));
4872
+ } finally {
4873
+ setSavingModel(null);
4874
+ }
4875
+ };
4876
+ if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4877
+ className: "dsha-page",
4878
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4879
+ className: "dsha-empty",
4880
+ children: t.loading
4881
+ })
4882
+ });
4883
+ const quota = status?.quota;
4884
+ const account = status?.account;
4885
+ const authenticated = status?.authenticated === true;
4886
+ const unreachable = statusFailed && status === null;
4887
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4888
+ className: "dsha-page",
4889
+ children: [
4890
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
4891
+ className: "dsha-group",
4892
+ children: [
4893
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4894
+ className: "dsha-grouphead",
4895
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: authenticated ? t.account : t.signedOut }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4896
+ className: "dsha-btn",
4897
+ disabled: busy !== null,
4898
+ onClick: () => void handleRescan(),
4899
+ children: busy === "rescan" ? t.rescanning : t.rescan
4900
+ })]
4901
+ }),
4902
+ unreachable ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4903
+ className: "dsha-empty",
4904
+ children: t.routeUnreachable
4905
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4906
+ className: "dsha-notice",
4907
+ children: t.routeUnreachableHint
4908
+ })] }) : !authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4909
+ className: "dsha-empty",
4910
+ children: t.notFoundTitle
4911
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4912
+ className: "dsha-notice",
4913
+ children: t.notFoundHint
4914
+ })] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
4915
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4916
+ className: "dsha-row",
4917
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4918
+ className: "dsha-label",
4919
+ children: t.nickname
4920
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4921
+ className: "dsha-value",
4922
+ children: account?.nickname || "—"
4923
+ })]
4924
+ }),
4925
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4926
+ className: "dsha-row",
4927
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4928
+ className: "dsha-label",
4929
+ children: t.uid
4930
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4931
+ className: "dsha-value dshwb-mono",
4932
+ children: account?.uid || "—"
4933
+ })]
4934
+ }),
4935
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4936
+ className: "dsha-row",
4937
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4938
+ className: "dsha-label",
4939
+ children: t.uin
4940
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4941
+ className: "dsha-value dshwb-mono",
4942
+ children: maskUin(account?.uin)
4943
+ })]
4944
+ }),
4945
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4946
+ className: "dsha-row",
4947
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4948
+ className: "dsha-label",
4949
+ children: t.region
4950
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4951
+ className: "dsha-value",
4952
+ children: [account?.region === "intl" ? t.regionIntl : t.regionCn, account?.accountType ? ` · ${account.accountType}` : ""]
4953
+ })]
4954
+ }),
4955
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4956
+ className: "dsha-row",
4957
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4958
+ className: "dsha-label",
4959
+ children: t.domain
4960
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4961
+ className: "dsha-value dshwb-mono",
4962
+ children: account?.domain || "—"
4963
+ })]
4964
+ }),
4965
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4966
+ className: "dsha-row",
4967
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4968
+ className: "dsha-label",
4969
+ children: t.backend
4970
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4971
+ className: "dsha-value dshwb-mono",
4972
+ children: account?.backend || "—"
4973
+ })]
4974
+ }),
4975
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4976
+ className: "dsha-row",
4977
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4978
+ className: "dsha-label",
4979
+ children: t.tokenExpires
4980
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4981
+ className: "dsha-value",
4982
+ children: account?.expiresAt === null || account?.expiresAt === void 0 ? "—" : account.expiresAt <= Date.now() ? t.tokenExpired : formatDate(account.expiresAt)
4983
+ })]
4984
+ }),
4985
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4986
+ className: "dsha-row",
4987
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4988
+ className: "dsha-label",
4989
+ children: t.sourceFile
4990
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4991
+ className: "dsha-value dshwb-mono",
4992
+ title: account?.sourceFile ?? status?.managedStoragePath ?? "",
4993
+ children: account?.source === "managed" ? t.encryptedStorage : displayFile(account?.sourceFile)
4994
+ })]
4995
+ })
4996
+ ] }),
4997
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4998
+ className: "dsha-row",
4999
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5000
+ className: "dsha-label",
5001
+ children: t.authDirectory
5002
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5003
+ className: "dsha-value dshwb-mono",
5004
+ children: status?.authDirectory || "—"
5005
+ })]
5006
+ }),
5007
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5008
+ className: "dsha-notice",
5009
+ children: t.storageNotice
5010
+ })
5011
+ ]
5012
+ }),
5013
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountPoolSection, {
5014
+ accounts: poolAccounts,
5015
+ activeAccountId: status?.activeAccountId,
5016
+ rotationStrategy: status?.rotationStrategy ?? "sequential",
5017
+ labels: accountPoolLabels(t),
5018
+ busy,
5019
+ onLogin: () => void handleAddAccount("cn"),
5020
+ onSetPrimary: (id) => void handlePoolAction("set-primary", id),
5021
+ onDelete: (id) => void handleDeleteAccount(id),
5022
+ onClearCooldown: (id) => void handlePoolAction("clear-cooldown", id),
5023
+ onRelogin: (id) => void handlePoolAction("relogin", id),
5024
+ onSetStrategy: (strategy) => void handleSetStrategy(strategy),
5025
+ storageValue: status?.managedStoragePath,
5026
+ renderLoginActions: () => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5027
+ className: "dsha-account-add-actions",
5028
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5029
+ className: "dsha-btn",
5030
+ disabled: busy !== null,
5031
+ onClick: () => void handleAddAccount("cn"),
5032
+ children: busy === "login:cn" ? t.authorizing : t.addCnAccount
5033
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5034
+ className: "dsha-btn",
5035
+ disabled: busy !== null,
5036
+ onClick: () => void handleAddAccount("intl"),
5037
+ children: busy === "login:intl" ? t.authorizing : t.addIntlAccount
5038
+ })]
5039
+ }),
5040
+ renderAccountActions: (candidate) => candidate.removable ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [candidate.hidden === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5041
+ className: "dsha-btn",
5042
+ disabled: busy !== null,
5043
+ onClick: () => void handlePoolAction("restore", candidate.id),
5044
+ children: t.restoreAccount
5045
+ }), candidate.hidden !== true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5046
+ className: "dsha-btn",
5047
+ disabled: busy !== null,
5048
+ onClick: () => void handlePoolAction("hide", candidate.id),
5049
+ children: t.hideAccount
5050
+ })] }),
5051
+ renderDetails: (candidate) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
5052
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5053
+ t.region,
5054
+ ": ",
5055
+ candidate.region === "intl" ? t.regionIntl : t.regionCn
5056
+ ] }),
5057
+ candidate.uin ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5058
+ t.uin,
5059
+ ": ",
5060
+ maskUin(candidate.uin)
5061
+ ] }) : null,
5062
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5063
+ className: "dshwb-mono",
5064
+ children: candidate.source === "managed" ? t.encryptedStorage : displayFile(candidate.sourceFile)
5065
+ }),
5066
+ candidate.hidden === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.hiddenAccount }) : null
5067
+ ] })
5068
+ }),
5069
+ loginProgress ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5070
+ className: "dsha-notice",
5071
+ children: loginProgress
5072
+ }) : null,
5073
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5074
+ className: "dsha-group",
5075
+ children: [
5076
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5077
+ className: "dsha-grouphead",
5078
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.connection })
5079
+ }),
5080
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5081
+ className: "dsha-row",
5082
+ style: { marginBottom: 12 },
5083
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5084
+ className: "dsha-label",
5085
+ style: { fontWeight: 600 },
5086
+ children: t.enableProvider
5087
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5088
+ type: "checkbox",
5089
+ checked: status?.enabled !== false,
5090
+ disabled: busy !== null,
5091
+ onChange: (e) => void toggleEnabled(e.currentTarget.checked)
5092
+ })]
5093
+ }),
5094
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5095
+ className: "dsha-row",
5096
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5097
+ className: "dsha-label",
5098
+ children: t.provider
5099
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5100
+ className: "dsha-value",
5101
+ children: t.providerValue
5102
+ })]
5103
+ }),
5104
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5105
+ className: "dsha-row",
5106
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5107
+ className: "dsha-label",
5108
+ children: t.connectionState
5109
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5110
+ className: "dsha-value",
5111
+ children: [connection?.connected ? t.connected : authenticated ? t.untested : t.signedOut, connection?.connected ? ` · ${connection.latencyMs}ms · ${connection.model}` : ""]
5112
+ })]
5113
+ }),
5114
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5115
+ className: "dsha-notice",
5116
+ children: status?.serving === false && status.conflict ? t.routeConflict.replace("{detail}", status.conflict) : t.routeOwned
5117
+ }),
5118
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5119
+ className: "dsha-actions",
5120
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5121
+ className: "dsha-btn",
5122
+ disabled: busy !== null || !authenticated,
5123
+ onClick: () => void handleTestConnection(),
5124
+ children: busy === "connection" ? t.testingConnection : t.testConnection
5125
+ })
5126
+ })
5127
+ ]
5128
+ }),
5129
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5130
+ className: "dsha-group",
5131
+ children: [
5132
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5133
+ className: "dsha-grouphead",
5134
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.modelsSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5135
+ className: "dsha-btn",
5136
+ disabled: busy !== null || !authenticated,
5137
+ onClick: () => void handleRefreshCatalog(),
5138
+ children: busy === "catalog" ? t.refreshingCatalog : t.refreshCatalog
5139
+ })]
5140
+ }),
5141
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5142
+ className: "dsha-muted dsha-models-hint",
5143
+ children: t.modelsHint
5144
+ }),
5145
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5146
+ className: "dsha-models",
5147
+ "aria-label": "WorkBuddy Models",
5148
+ children: status?.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
5149
+ title: model.description ?? model.id,
5150
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5151
+ type: "checkbox",
5152
+ checked: model.enabled,
5153
+ disabled: busy !== null,
5154
+ onChange: (event) => void toggleModel(model.id, event.currentTarget.checked)
5155
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5156
+ className: "dshwb-model",
5157
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5158
+ className: "dshwb-model-meta",
5159
+ children: [
5160
+ formatCapacity(model.contextWindow),
5161
+ " · ",
5162
+ model.supportsImage ? t.imageSupport : t.textOnly,
5163
+ model.reasoningEfforts && model.reasoningEfforts.length > 0 ? ` · ${model.reasoningEfforts.join("/")}` : ""
5164
+ ]
5165
+ })]
5166
+ })]
5167
+ }, model.id))
5168
+ }),
5169
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5170
+ className: "dsha-actions",
5171
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5172
+ className: "dsha-btn",
5173
+ disabled: busy !== null,
5174
+ onClick: () => void setAllModels(true),
5175
+ children: t.selectAll
5176
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5177
+ className: "dsha-btn",
5178
+ disabled: busy !== null,
5179
+ onClick: () => void setAllModels(false),
5180
+ children: t.unselectAll
5181
+ })]
5182
+ })
5183
+ ]
5184
+ }),
5185
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5186
+ className: "dsha-group",
5187
+ children: [
5188
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5189
+ className: "dsha-grouphead",
5190
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.enhanced })
5191
+ }),
5192
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5193
+ className: "dsha-pref-row",
5194
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
5195
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.defaultReasoningEffort }),
5196
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5197
+ className: "dsha-muted",
5198
+ children: t.defaultReasoningEffortHint
5199
+ }),
5200
+ strayEffort !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5201
+ className: "dsha-muted",
5202
+ children: t.defaultEffortKept
5203
+ }) : null
5204
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
5205
+ className: "dsha-select",
5206
+ "aria-label": t.defaultReasoningEffort,
5207
+ value: status?.defaultReasoningEffort ?? "",
5208
+ disabled: busy !== null,
5209
+ onChange: (event) => {
5210
+ const value = event.currentTarget.value;
5211
+ handleUpdateEffort(value === "" ? null : value);
5212
+ },
5213
+ children: [
5214
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5215
+ value: "",
5216
+ children: t.defaultEffortAuto
5217
+ }),
5218
+ strayEffort !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5219
+ value: strayEffort,
5220
+ children: `${EFFORT_LABELS[strayEffort]} (${t.effortUnsupported})`
5221
+ }) : null,
5222
+ effortChoices.map((choice) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5223
+ value: choice.value,
5224
+ children: choice.models.length === allModels.length ? EFFORT_LABELS[choice.value] : `${EFFORT_LABELS[choice.value]} (${choice.models.length}/${allModels.length})`
5225
+ }, choice.value))
5226
+ ]
5227
+ })]
5228
+ }),
5229
+ effortChoices.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5230
+ className: "dsha-muted",
5231
+ children: t.noReasoningModels
5232
+ }) : null
5233
+ ]
5234
+ }),
5235
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5236
+ className: "dsha-group",
5237
+ children: [
5238
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5239
+ className: "dsha-grouphead",
5240
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.contextWindowSection })
5241
+ }),
5242
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5243
+ className: "dsha-muted",
5244
+ children: t.contextWindowHint
5245
+ }),
5246
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5247
+ className: "dsha-context-settings",
5248
+ children: status?.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5249
+ className: "dsha-context-row",
5250
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5251
+ title: model.id,
5252
+ children: model.name
5253
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5254
+ className: "dsha-capacity-control",
5255
+ children: [
5256
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
5257
+ type: "text",
5258
+ "aria-label": `${model.name} context window`,
5259
+ value: contextDrafts[model.id] ?? "",
5260
+ onChange: (event) => setContextDrafts({
5261
+ ...contextDrafts,
5262
+ [model.id]: event.currentTarget.value
5263
+ }),
5264
+ onKeyDown: (event) => {
5265
+ if (event.key === "Enter") handleSaveContextWindow(model.id);
5266
+ }
5267
+ }),
5268
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "tokens" }),
5269
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5270
+ type: "button",
5271
+ className: "dsha-context-save",
5272
+ disabled: savingModel === model.id,
5273
+ onClick: () => void handleSaveContextWindow(model.id),
5274
+ children: savingModel === model.id ? t.saving : t.save
5275
+ })
5276
+ ]
5277
+ })]
5278
+ }, model.id))
5279
+ })
5280
+ ]
5281
+ }),
5282
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5283
+ className: "dsha-group",
5284
+ children: [
5285
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5286
+ className: "dsha-grouphead",
5287
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.quotaSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5288
+ className: "dsha-btn",
5289
+ disabled: busy !== null || !authenticated,
5290
+ onClick: () => void handleRefreshQuota(),
5291
+ children: busy === "quota" ? t.refreshingQuota : t.refreshQuota
5292
+ })]
5293
+ }),
5294
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5295
+ className: "dsha-muted",
5296
+ children: t.quotaDesc
5297
+ }),
5298
+ !authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5299
+ className: "dsha-empty",
5300
+ children: t.signedOut
5301
+ }) : quota === null || quota === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5302
+ className: "dsha-empty",
5303
+ children: busy === "quota" ? t.refreshingQuota : t.quotaEmpty
5304
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5305
+ className: "dsha-quota-card",
5306
+ children: [
5307
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5308
+ className: "dsha-quota-title",
5309
+ 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}` : "—" })]
5310
+ }),
5311
+ quota.cycleUsedCredits !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5312
+ className: "dsha-row",
5313
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5314
+ className: "dsha-label",
5315
+ children: t.quotaCycle
5316
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5317
+ className: "dsha-value",
5318
+ children: [
5319
+ quota.cycleUsedCredits,
5320
+ quota.cycleCredits !== null ? ` / ${quota.cycleCredits}` : "",
5321
+ ` ${t.credits}`
5322
+ ]
5323
+ })]
5324
+ }),
5325
+ quota.cycleEndsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5326
+ className: "dsha-row",
5327
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5328
+ className: "dsha-label",
5329
+ children: t.quotaReset
5330
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5331
+ className: "dsha-value",
5332
+ children: [formatDate(quota.cycleEndsAt), formatReset(quota.cycleEndsAt) ? ` · ${formatReset(quota.cycleEndsAt)}` : ""]
5333
+ })]
5334
+ }),
5335
+ quota.meters.map((meter) => {
5336
+ const remaining = meter.remainingFraction;
5337
+ const percent = remaining === null ? null : Math.round(remaining * 100);
5338
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5339
+ className: "dsha-meter-wrap",
5340
+ children: [
5341
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5342
+ className: "dsha-meter-label",
5343
+ 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` })]
5344
+ }),
5345
+ percent !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5346
+ className: "dsha-meter dsha-meter-green",
5347
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: { width: `${percent}%` } })
5348
+ }),
5349
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5350
+ className: "dsha-meter-meta",
5351
+ children: [meter.used !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5352
+ meter.used,
5353
+ " / ",
5354
+ meter.limit ?? "—"
5355
+ ] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5356
+ t.quotaReset,
5357
+ ": ",
5358
+ formatReset(meter.resetsAt)
5359
+ ] })]
5360
+ })
5361
+ ]
5362
+ }, meter.id);
5363
+ }),
5364
+ quota.meters.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5365
+ className: "dsha-empty",
5366
+ children: t.quotaEmpty
5367
+ }),
5368
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5369
+ className: "dsha-timestamp",
5370
+ children: t.updatedAt.replace("{time}", new Date(quota.fetchedAt).toLocaleString())
5371
+ })
5372
+ ]
5373
+ })
5374
+ ]
5375
+ }),
5376
+ error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5377
+ className: "dsha-error",
5378
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: error })
5379
+ })
5380
+ ]
5381
+ });
5382
+ }
5383
+ //#endregion
5384
+ //#region src/client/ProviderHubSection.tsx
5385
+ const HUB_TABS = [
5386
+ {
5387
+ id: "chatgpt",
5388
+ label: "ChatGPT"
5389
+ },
5390
+ {
5391
+ id: "antigravity",
5392
+ label: "Antigravity"
5393
+ },
5394
+ {
5395
+ id: "command-code",
5396
+ label: "Command Code"
5397
+ },
5398
+ {
5399
+ id: "kimi-code",
5400
+ label: "Kimi Code"
5401
+ },
5402
+ {
5403
+ id: "workbuddy",
5404
+ label: "WorkBuddy"
5405
+ }
5406
+ ];
5407
+ /**
5408
+ * Single settings page that hosts every subscription provider behind tabs,
5409
+ * so the settings sidebar shows one entry instead of one per provider. Only
5410
+ * the active tab is mounted, mirroring the shell's previous behavior of
5411
+ * mounting just the selected settings page (each provider section refetches
5412
+ * its status on mount).
5413
+ */
5414
+ function ProviderHubSection({ t, onModelChange, ...runtime }) {
5415
+ const [active, setActive] = (0, react.useState)("chatgpt");
5416
+ const onTabKeyDown = (0, react.useCallback)((event) => {
5417
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
5418
+ event.preventDefault();
5419
+ const index = HUB_TABS.findIndex((tab) => tab.id === active);
5420
+ const delta = event.key === "ArrowRight" ? 1 : -1;
5421
+ const next = HUB_TABS[(index + delta + HUB_TABS.length) % HUB_TABS.length];
5422
+ setActive(next.id);
5423
+ document.getElementById(`dsh-hub-tab-${next.id}`)?.focus();
5424
+ }, [active]);
5425
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5426
+ className: "dsh-codex-page",
5427
+ "aria-labelledby": "dsh-hub-title",
5428
+ children: [
5429
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("header", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
5430
+ id: "dsh-hub-title",
5431
+ className: "dsh-codex-title",
5432
+ children: t("hubTitle")
5433
+ }) }),
5434
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5435
+ className: "dsh-codex-segments dsh-hub-tabs",
5436
+ role: "tablist",
5437
+ "aria-label": t("hubTitle"),
5438
+ children: HUB_TABS.map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5439
+ type: "button",
5440
+ role: "tab",
5441
+ id: `dsh-hub-tab-${tab.id}`,
5442
+ "aria-selected": active === tab.id,
5443
+ "aria-controls": `dsh-hub-panel-${tab.id}`,
5444
+ className: active === tab.id ? "active" : void 0,
5445
+ tabIndex: active === tab.id ? 0 : -1,
5446
+ onClick: () => setActive(tab.id),
5447
+ onKeyDown: onTabKeyDown,
5448
+ children: tab.label
5449
+ }, tab.id))
5450
+ }),
5451
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5452
+ role: "tabpanel",
4267
5453
  id: `dsh-hub-panel-${active}`,
4268
5454
  "aria-labelledby": `dsh-hub-tab-${active}`,
4269
5455
  children: [
@@ -4273,7 +5459,8 @@ window.__ModuleLoader__.load({
4273
5459
  }) : null,
4274
5460
  active === "antigravity" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AntigravitySection, { onModelChange }) : null,
4275
5461
  active === "command-code" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CommandCodeSection, { onModelChange }) : null,
4276
- active === "kimi-code" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KimiCodeSection, { onModelChange }) : null
5462
+ active === "kimi-code" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KimiCodeSection, { onModelChange }) : null,
5463
+ active === "workbuddy" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkBuddySection, { onModelChange }) : null
4277
5464
  ]
4278
5465
  })
4279
5466
  ]
@@ -4544,7 +5731,7 @@ window.__ModuleLoader__.load({
4544
5731
  };
4545
5732
  //#endregion
4546
5733
  //#region src/client/styles.ts
4547
- const STYLE_ID$2 = "@eddyskywalker/dsh-chatgpt-subscription/main";
5734
+ const STYLE_ID$3 = "@eddyskywalker/dsh-chatgpt-subscription/main";
4548
5735
  const CSS = `
4549
5736
  .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}
4550
5737
  .dsh-codex-page *{box-sizing:border-box}
@@ -4653,21 +5840,21 @@ window.__ModuleLoader__.load({
4653
5840
  @media(prefers-reduced-motion:reduce){.dsh-codex-meter>span{transition:none}.dsh-codex-skeleton span{animation:none}}
4654
5841
  `;
4655
5842
  function installStyles() {
4656
- if (document.querySelector(`style[data-plugin-css="${STYLE_ID$2}"]`) !== null) return () => void 0;
5843
+ if (document.querySelector(`style[data-plugin-css="${STYLE_ID$3}"]`) !== null) return () => void 0;
4657
5844
  const element = document.createElement("style");
4658
5845
  element.dataset.plugin = "@eddyskywalker/dsh-chatgpt-subscription";
4659
- element.dataset.pluginCss = STYLE_ID$2;
5846
+ element.dataset.pluginCss = STYLE_ID$3;
4660
5847
  element.textContent = CSS;
4661
5848
  document.head.appendChild(element);
4662
5849
  return () => element.remove();
4663
5850
  }
4664
5851
  //#endregion
4665
5852
  //#region src/client/antigravity/styles.ts
4666
- const STYLE_ID$1 = "dsh-antigravity-settings-style";
5853
+ const STYLE_ID$2 = "dsh-antigravity-settings-style";
4667
5854
  function installAntigravityStyles() {
4668
5855
  if (typeof document === "undefined" || document.getElementById("dsh-antigravity-settings-style")) return;
4669
5856
  const style = document.createElement("style");
4670
- style.id = STYLE_ID$1;
5857
+ style.id = STYLE_ID$2;
4671
5858
  style.textContent = `
4672
5859
  .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}
4673
5860
  .dsha-page *{box-sizing:border-box}
@@ -4690,7 +5877,7 @@ window.__ModuleLoader__.load({
4690
5877
  .dsha-models{display:flex;flex-wrap:wrap;gap:7px;padding-top:8px}
4691
5878
  .dsha-models label{cursor:pointer;display:block;position:relative}
4692
5879
  .dsha-models input{position:absolute;opacity:0;pointer-events:none}
4693
- .dsha-models span{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:5px 8px;transition:all .15s ease}
5880
+ .dsha-models>label>span{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:5px 8px;transition:all .15s ease}
4694
5881
  .dsha-models input:checked+span{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 14%,var(--dsw-alias-bg-layer-2));border-color:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 55%,var(--dsw-alias-border-l2));color:var(--dsw-alias-label-primary);font-weight:600}
4695
5882
  .dsha-models input:disabled+span{cursor:default;opacity:.5}
4696
5883
  .dsha-pref-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:16px;justify-content:space-between;min-height:58px;padding:10px 0}
@@ -4766,9 +5953,9 @@ window.__ModuleLoader__.load({
4766
5953
  }
4767
5954
  //#endregion
4768
5955
  //#region src/client/antigravity/AntigravityComposerQuota.tsx
4769
- const API$2 = "/antigravity/api";
4770
- async function fetchApi$2(path, options) {
4771
- const res = await fetch(`${API$2}${path}`, {
5956
+ const API$3 = "/antigravity/api";
5957
+ async function fetchApi$3(path, options) {
5958
+ const res = await fetch(`${API$3}${path}`, {
4772
5959
  ...options,
4773
5960
  headers: {
4774
5961
  "Content-Type": "application/json",
@@ -4809,7 +5996,7 @@ window.__ModuleLoader__.load({
4809
5996
  }
4810
5997
  }
4811
5998
  function AntigravityComposerQuota({ directory, loadModelDirectory }) {
4812
- const modelState = useStore$2(directory);
5999
+ const modelState = useStore$3(directory);
4813
6000
  const [status, setStatus] = (0, react.useState)(null);
4814
6001
  const [loading, setLoading] = (0, react.useState)(false);
4815
6002
  const mountedRef = (0, react.useRef)(false);
@@ -4828,7 +6015,7 @@ window.__ModuleLoader__.load({
4828
6015
  if (!mountedRef.current) return;
4829
6016
  setLoading(true);
4830
6017
  try {
4831
- const data = refresh ? await fetchApi$2("/quota", { method: "POST" }) : await fetchApi$2("/status");
6018
+ const data = refresh ? await fetchApi$3("/quota", { method: "POST" }) : await fetchApi$3("/status");
4832
6019
  if (mountedRef.current) setStatus(data);
4833
6020
  } catch {} finally {
4834
6021
  if (mountedRef.current) setLoading(false);
@@ -4866,14 +6053,14 @@ window.__ModuleLoader__.load({
4866
6053
  })]
4867
6054
  });
4868
6055
  }
4869
- function useStore$2(store) {
6056
+ function useStore$3(store) {
4870
6057
  return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
4871
6058
  }
4872
6059
  //#endregion
4873
6060
  //#region src/client/command-code/CommandCodeComposerQuota.tsx
4874
- const API$1 = "/command-code/api";
4875
- async function fetchApi$1(path, options) {
4876
- const res = await fetch(`${API$1}${path}`, {
6061
+ const API$2 = "/command-code/api";
6062
+ async function fetchApi$2(path, options) {
6063
+ const res = await fetch(`${API$2}${path}`, {
4877
6064
  ...options,
4878
6065
  headers: {
4879
6066
  "Content-Type": "application/json",
@@ -4890,7 +6077,7 @@ window.__ModuleLoader__.load({
4890
6077
  * A bounded usage window is the number a user actually spends down, so it wins
4891
6078
  * over a credit balance; the balance shows only when no window is reported.
4892
6079
  */
4893
- function selectBadgeFacts$1(status) {
6080
+ function selectBadgeFacts$2(status) {
4894
6081
  const quota = status?.quota;
4895
6082
  if (quota === null || quota === void 0) return {
4896
6083
  text: "—",
@@ -4932,7 +6119,7 @@ window.__ModuleLoader__.load({
4932
6119
  };
4933
6120
  }
4934
6121
  function CommandCodeComposerQuota({ directory, loadModelDirectory }) {
4935
- const modelState = useStore$1(directory);
6122
+ const modelState = useStore$2(directory);
4936
6123
  const [status, setStatus] = (0, react.useState)(null);
4937
6124
  const [loading, setLoading] = (0, react.useState)(false);
4938
6125
  const mountedRef = (0, react.useRef)(false);
@@ -4950,7 +6137,7 @@ window.__ModuleLoader__.load({
4950
6137
  if (!mountedRef.current) return;
4951
6138
  setLoading(true);
4952
6139
  try {
4953
- const data = refresh ? await fetchApi$1("/quota", { method: "POST" }) : await fetchApi$1("/status");
6140
+ const data = refresh ? await fetchApi$2("/quota", { method: "POST" }) : await fetchApi$2("/status");
4954
6141
  if (mountedRef.current) setStatus(data);
4955
6142
  } catch {} finally {
4956
6143
  if (mountedRef.current) setLoading(false);
@@ -4966,7 +6153,7 @@ window.__ModuleLoader__.load({
4966
6153
  window.clearInterval(timer);
4967
6154
  };
4968
6155
  }, [fetchStatus, isCommandCode]);
4969
- const facts = (0, react.useMemo)(() => selectBadgeFacts$1(status), [status]);
6156
+ const facts = (0, react.useMemo)(() => selectBadgeFacts$2(status), [status]);
4970
6157
  if (!isCommandCode || !status?.authenticated || facts === null) return null;
4971
6158
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4972
6159
  className: "dsha-composer-quota",
@@ -4983,14 +6170,14 @@ window.__ModuleLoader__.load({
4983
6170
  })]
4984
6171
  });
4985
6172
  }
4986
- function useStore$1(store) {
6173
+ function useStore$2(store) {
4987
6174
  return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
4988
6175
  }
4989
6176
  //#endregion
4990
6177
  //#region src/client/kimi-code/KimiCodeComposerQuota.tsx
4991
- const API = "/kimi-code/api";
4992
- async function fetchApi(path, options) {
4993
- const res = await fetch(`${API}${path}`, {
6178
+ const API$1 = "/kimi-code/api";
6179
+ async function fetchApi$1(path, options) {
6180
+ const res = await fetch(`${API$1}${path}`, {
4994
6181
  ...options,
4995
6182
  headers: {
4996
6183
  "Content-Type": "application/json",
@@ -5008,7 +6195,7 @@ window.__ModuleLoader__.load({
5008
6195
  * blocks work soonest, so it wins over the longer pools; the 7-day allowance
5009
6196
  * shows only when no 5-hour window is reported.
5010
6197
  */
5011
- function selectBadgeFacts(status) {
6198
+ function selectBadgeFacts$1(status) {
5012
6199
  const quota = status?.quota;
5013
6200
  if (quota === null || quota === void 0) return {
5014
6201
  text: "—",
@@ -5040,7 +6227,7 @@ window.__ModuleLoader__.load({
5040
6227
  };
5041
6228
  }
5042
6229
  function KimiCodeComposerQuota({ directory, loadModelDirectory }) {
5043
- const modelState = useStore(directory);
6230
+ const modelState = useStore$1(directory);
5044
6231
  const [status, setStatus] = (0, react.useState)(null);
5045
6232
  const [loading, setLoading] = (0, react.useState)(false);
5046
6233
  const mountedRef = (0, react.useRef)(false);
@@ -5058,7 +6245,7 @@ window.__ModuleLoader__.load({
5058
6245
  if (!mountedRef.current) return;
5059
6246
  setLoading(true);
5060
6247
  try {
5061
- const data = refresh ? await fetchApi("/quota", { method: "POST" }) : await fetchApi("/status");
6248
+ const data = refresh ? await fetchApi$1("/quota", { method: "POST" }) : await fetchApi$1("/status");
5062
6249
  if (mountedRef.current) setStatus(data);
5063
6250
  } catch {} finally {
5064
6251
  if (mountedRef.current) setLoading(false);
@@ -5074,7 +6261,7 @@ window.__ModuleLoader__.load({
5074
6261
  window.clearInterval(timer);
5075
6262
  };
5076
6263
  }, [fetchStatus, isKimiCode]);
5077
- const facts = (0, react.useMemo)(() => selectBadgeFacts(status), [status]);
6264
+ const facts = (0, react.useMemo)(() => selectBadgeFacts$1(status), [status]);
5078
6265
  if (!isKimiCode || !status?.authenticated || facts === null) return null;
5079
6266
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5080
6267
  className: "dsha-composer-quota",
@@ -5091,12 +6278,12 @@ window.__ModuleLoader__.load({
5091
6278
  })]
5092
6279
  });
5093
6280
  }
5094
- function useStore(store) {
6281
+ function useStore$1(store) {
5095
6282
  return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
5096
6283
  }
5097
6284
  //#endregion
5098
6285
  //#region src/client/kimi-code/styles.ts
5099
- const STYLE_ID = "dsh-kimi-code-settings-style";
6286
+ const STYLE_ID$1 = "dsh-kimi-code-settings-style";
5100
6287
  /**
5101
6288
  * Node the base control styles come from.
5102
6289
  *
@@ -5126,7 +6313,7 @@ window.__ModuleLoader__.load({
5126
6313
  .dsha-models{display:flex;flex-wrap:wrap;gap:7px;padding-top:8px}
5127
6314
  .dsha-models label{cursor:pointer;display:block;position:relative}
5128
6315
  .dsha-models input{position:absolute;opacity:0;pointer-events:none}
5129
- .dsha-models span{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:5px 8px;transition:all .15s ease}
6316
+ .dsha-models>label>span{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:5px 8px;transition:all .15s ease}
5130
6317
  .dsha-models input:checked+span{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 14%,var(--dsw-alias-bg-layer-2));border-color:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 55%,var(--dsw-alias-border-l2));color:var(--dsw-alias-label-primary);font-weight:600}
5131
6318
  .dsha-models input:disabled+span{cursor:default;opacity:.5}
5132
6319
  .dsha-pref-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:16px;justify-content:space-between;min-height:58px;padding:10px 0}
@@ -5186,11 +6373,148 @@ window.__ModuleLoader__.load({
5186
6373
  function installKimiCodeStyles() {
5187
6374
  if (typeof document === "undefined" || document.getElementById("dsh-kimi-code-settings-style")) return;
5188
6375
  const style = document.createElement("style");
5189
- style.id = STYLE_ID;
6376
+ style.id = STYLE_ID$1;
5190
6377
  style.textContent = BASE;
5191
6378
  document.head.appendChild(style);
5192
6379
  }
5193
6380
  //#endregion
6381
+ //#region src/client/workbuddy/WorkBuddyComposerQuota.tsx
6382
+ const API = "/workbuddy/api";
6383
+ async function fetchApi(path, options) {
6384
+ const res = await fetch(`${API}${path}`, {
6385
+ ...options,
6386
+ headers: {
6387
+ "Content-Type": "application/json",
6388
+ ...options?.headers
6389
+ }
6390
+ });
6391
+ const json = await res.json();
6392
+ if (!res.ok || !json.ok) throw new Error(json.error || `HTTP ${res.status}`);
6393
+ return json.value;
6394
+ }
6395
+ /**
6396
+ * Pick the most meaningful number for the badge.
6397
+ *
6398
+ * A bounded allowance is what a user spends down, so it wins over a bare credit
6399
+ * balance; the balance shows only when no percentage is reported. The billing
6400
+ * payload reports both a cycle meter and a package meter, and the cycle meter
6401
+ * is the one that actually resets, so it is preferred when both exist.
6402
+ */
6403
+ function selectBadgeFacts(status) {
6404
+ const quota = status?.quota;
6405
+ if (quota === null || quota === void 0) return {
6406
+ text: "—",
6407
+ tooltip: "WorkBuddy quota unavailable — click to refresh",
6408
+ level: "normal"
6409
+ };
6410
+ const meter = (quota.meters ?? []).find((candidate) => candidate.id === "cycle" && candidate.remainingFraction !== null) ?? (quota.meters ?? []).find((candidate) => candidate.remainingFraction !== null);
6411
+ if (meter !== void 0 && meter.remainingFraction !== null) {
6412
+ const remaining = Math.round(meter.remainingFraction * 100);
6413
+ return {
6414
+ text: `${remaining}%`,
6415
+ tooltip: `[WorkBuddy] ${meter.label}: ${remaining}% left`,
6416
+ level: remaining <= 5 ? "danger" : remaining <= 20 ? "warning" : "normal"
6417
+ };
6418
+ }
6419
+ if (quota.remainingCredits !== null) return {
6420
+ text: String(quota.remainingCredits),
6421
+ tooltip: `[WorkBuddy] Remaining credits: ${quota.remainingCredits}`,
6422
+ level: "normal"
6423
+ };
6424
+ return {
6425
+ text: "—",
6426
+ tooltip: "WorkBuddy quota unavailable — click to refresh",
6427
+ level: "normal"
6428
+ };
6429
+ }
6430
+ function WorkBuddyComposerQuota({ directory, loadModelDirectory }) {
6431
+ const modelState = useStore(directory);
6432
+ const [status, setStatus] = (0, react.useState)(null);
6433
+ const [loading, setLoading] = (0, react.useState)(false);
6434
+ const mountedRef = (0, react.useRef)(false);
6435
+ const isWorkBuddy = modelState.current?.provider === "workbuddy-subscription";
6436
+ (0, react.useEffect)(() => {
6437
+ loadModelDirectory();
6438
+ }, [loadModelDirectory]);
6439
+ (0, react.useEffect)(() => {
6440
+ mountedRef.current = true;
6441
+ return () => {
6442
+ mountedRef.current = false;
6443
+ };
6444
+ }, []);
6445
+ const fetchStatus = (0, react.useCallback)(async (refresh = false) => {
6446
+ if (!mountedRef.current) return;
6447
+ setLoading(true);
6448
+ try {
6449
+ const data = refresh ? await fetchApi("/quota", { method: "POST" }) : await fetchApi("/status");
6450
+ if (mountedRef.current) setStatus(data);
6451
+ } catch {} finally {
6452
+ if (mountedRef.current) setLoading(false);
6453
+ }
6454
+ }, []);
6455
+ (0, react.useEffect)(() => {
6456
+ if (!isWorkBuddy) return;
6457
+ fetchStatus(false);
6458
+ const timer = window.setInterval(() => {
6459
+ if (document.visibilityState === "visible") fetchStatus(false);
6460
+ }, 6e4);
6461
+ return () => {
6462
+ window.clearInterval(timer);
6463
+ };
6464
+ }, [fetchStatus, isWorkBuddy]);
6465
+ const facts = (0, react.useMemo)(() => selectBadgeFacts(status), [status]);
6466
+ if (!isWorkBuddy || !status?.authenticated || facts === null) return null;
6467
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6468
+ className: "dsha-composer-quota",
6469
+ "data-level": facts.level,
6470
+ title: facts.tooltip,
6471
+ "aria-label": facts.tooltip,
6472
+ onClick: () => void fetchStatus(true),
6473
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6474
+ className: "dsha-composer-quota-label",
6475
+ children: "额度"
6476
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
6477
+ className: "dsha-composer-quota-val",
6478
+ children: loading ? "…" : facts.text
6479
+ })]
6480
+ });
6481
+ }
6482
+ function useStore(store) {
6483
+ return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
6484
+ }
6485
+ //#endregion
6486
+ //#region src/client/workbuddy/styles.ts
6487
+ const STYLE_ID = "dsh-workbuddy-settings-style";
6488
+ /**
6489
+ * WorkBuddy-only additions to the shared settings design system.
6490
+ *
6491
+ * The base control styles (`.dsha-page`, `.dsha-group`, `.dsha-models`, …) come
6492
+ * from the stylesheet the sibling routes install, so this file declares only
6493
+ * what is unique to this card: the per-model capability line and the
6494
+ * "unavailable in this region" treatment.
6495
+ */
6496
+ function installWorkBuddyStyles() {
6497
+ if (typeof document === "undefined" || document.getElementById("dsh-workbuddy-settings-style")) return;
6498
+ const style = document.createElement("style");
6499
+ style.id = STYLE_ID;
6500
+ style.textContent = `
6501
+ .dshwb-model{display:flex;flex-direction:column;gap:2px;min-width:0}
6502
+ .dshwb-model-meta{color:var(--dsw-alias-label-tertiary);font-size:10px;font-weight:400;line-height:1.3;white-space:nowrap}
6503
+ .dsha-models input:checked+span .dshwb-model-meta{color:var(--dsw-alias-label-secondary)}
6504
+ .dshwb-region{display:inline-flex;align-items:center;gap:4px}
6505
+ .dshwb-muted-note{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5;margin:8px 0 0}
6506
+ .dshwb-mono{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px}
6507
+ .dsha-account-region{margin-top:14px}
6508
+ .dsha-account-region h4{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:650;margin:0 0 8px}
6509
+ .dsha-account-add-actions{display:flex;flex-wrap:wrap;gap:8px}
6510
+ .dsha-account-card.hidden{opacity:.68}
6511
+ .dshwb-account-select{appearance:none;background:transparent;border:0;color:inherit;cursor:pointer;font:inherit;padding:0;text-align:left;width:100%}
6512
+ .dshwb-account-select:disabled{cursor:default}
6513
+ .dshwb-account-select:hover:not(:disabled) .dsha-account-title{color:var(--dsw-alias-label-link,#397ee8)}
6514
+ `;
6515
+ document.head.append(style);
6516
+ }
6517
+ //#endregion
5194
6518
  //#region src/client/mermaid/sanitize.ts
5195
6519
  const STRIP_ELEMENTS = /* @__PURE__ */ new Set([
5196
6520
  "foreignobject",
@@ -5530,17 +6854,22 @@ window.__ModuleLoader__.load({
5530
6854
  function apply(ctx) {
5531
6855
  ctx.effect(() => ctx.locale.register(NS, dictionaries), "dsh-chatgpt-subscription: dictionaries");
5532
6856
  ctx.effect(() => installStyles(), "dsh-chatgpt-subscription: styles");
5533
- ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries$3), "dsh-antigravity: dictionaries");
6857
+ ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries$4), "dsh-antigravity: dictionaries");
5534
6858
  ctx.effect(() => {
5535
6859
  installAntigravityStyles();
5536
6860
  return () => {};
5537
6861
  }, "dsh-antigravity: styles");
5538
- ctx.effect(() => ctx.locale.register(NS_COMMAND_CODE, dictionaries$2), "dsh-command-code: dictionaries");
5539
- ctx.effect(() => ctx.locale.register(NS_KIMI_CODE, dictionaries$1), "dsh-kimi-code: dictionaries");
6862
+ ctx.effect(() => ctx.locale.register(NS_COMMAND_CODE, dictionaries$3), "dsh-command-code: dictionaries");
6863
+ ctx.effect(() => ctx.locale.register(NS_KIMI_CODE, dictionaries$2), "dsh-kimi-code: dictionaries");
5540
6864
  ctx.effect(() => {
5541
6865
  installKimiCodeStyles();
5542
6866
  return () => {};
5543
6867
  }, "dsh-kimi-code: styles");
6868
+ ctx.effect(() => ctx.locale.register(NS_WORKBUDDY, dictionaries$1), "dsh-workbuddy: dictionaries");
6869
+ ctx.effect(() => {
6870
+ installWorkBuddyStyles();
6871
+ return () => {};
6872
+ }, "dsh-workbuddy: styles");
5544
6873
  ctx.effect(() => {
5545
6874
  installPoolStyles();
5546
6875
  return () => {};
@@ -5628,6 +6957,21 @@ window.__ModuleLoader__.load({
5628
6957
  };
5629
6958
  }
5630
6959
  }, KimiCodeComposerQuota));
6960
+ ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
6961
+ name: "conversation.input.right",
6962
+ id: "workbuddy-quota",
6963
+ order: 39,
6964
+ locale: NS_WORKBUDDY,
6965
+ inject: (sessionId) => {
6966
+ const directory = ctx.modelDirectories.directoryFor(sessionId);
6967
+ return {
6968
+ directory: directory.store,
6969
+ loadModelDirectory: () => {
6970
+ directory.load().catch(() => void 0);
6971
+ }
6972
+ };
6973
+ }
6974
+ }, WorkBuddyComposerQuota));
5631
6975
  ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
5632
6976
  name: "tool.call.toolview",
5633
6977
  key: CODEX_IMAGE_TOOL_NAME,