@eddyskywalker/dsh-chatgpt-subscription 0.3.8 → 0.4.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 (59) hide show
  1. package/CHANGELOG.md +28 -1
  2. package/lib/client.js +386 -99
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +853 -119
  5. package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
  6. package/lib/types/client/antigravity/AntigravitySection.d.ts.map +1 -1
  7. package/lib/types/client/antigravity/locales.d.ts +78 -0
  8. package/lib/types/client/antigravity/locales.d.ts.map +1 -1
  9. package/lib/types/client/antigravity/styles.d.ts.map +1 -1
  10. package/lib/types/client/command-code/CommandCodeSection.d.ts.map +1 -1
  11. package/lib/types/client/command-code/locales.d.ts +12 -6
  12. package/lib/types/client/command-code/locales.d.ts.map +1 -1
  13. package/lib/types/client/kimi-code/KimiCodeSection.d.ts.map +1 -1
  14. package/lib/types/client/kimi-code/locales.d.ts +12 -6
  15. package/lib/types/client/kimi-code/locales.d.ts.map +1 -1
  16. package/lib/types/client/locales.d.ts +9 -3
  17. package/lib/types/client/locales.d.ts.map +1 -1
  18. package/lib/types/host/antigravity/account-pool.d.ts +50 -0
  19. package/lib/types/host/antigravity/account-pool.d.ts.map +1 -0
  20. package/lib/types/host/antigravity/adapter.d.ts +3 -1
  21. package/lib/types/host/antigravity/adapter.d.ts.map +1 -1
  22. package/lib/types/host/antigravity/mapper.d.ts +1 -0
  23. package/lib/types/host/antigravity/mapper.d.ts.map +1 -1
  24. package/lib/types/host/antigravity/oauth.d.ts +1 -1
  25. package/lib/types/host/antigravity/oauth.d.ts.map +1 -1
  26. package/lib/types/host/antigravity/routes.d.ts +3 -2
  27. package/lib/types/host/antigravity/routes.d.ts.map +1 -1
  28. package/lib/types/host/antigravity/token-store.d.ts +3 -0
  29. package/lib/types/host/antigravity/token-store.d.ts.map +1 -1
  30. package/lib/types/host/antigravity/types.d.ts +2 -1
  31. package/lib/types/host/antigravity/types.d.ts.map +1 -1
  32. package/lib/types/host/command-code/adapter.d.ts.map +1 -1
  33. package/lib/types/host/command-code/mapper.d.ts.map +1 -1
  34. package/lib/types/host/command-code/routes.d.ts +1 -1
  35. package/lib/types/host/command-code/routes.d.ts.map +1 -1
  36. package/lib/types/host/command-code/token-store.d.ts +3 -0
  37. package/lib/types/host/command-code/token-store.d.ts.map +1 -1
  38. package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
  39. package/lib/types/host/kimi-code/mapper.d.ts +9 -4
  40. package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
  41. package/lib/types/host/kimi-code/routes.d.ts +1 -1
  42. package/lib/types/host/kimi-code/routes.d.ts.map +1 -1
  43. package/lib/types/host/kimi-code/token-store.d.ts +3 -0
  44. package/lib/types/host/kimi-code/token-store.d.ts.map +1 -1
  45. package/lib/types/host/model-catalog.d.ts.map +1 -1
  46. package/lib/types/host/preferences.d.ts.map +1 -1
  47. package/lib/types/host/token-store-windows.d.ts.map +1 -1
  48. package/lib/types/index.d.ts +1 -0
  49. package/lib/types/index.d.ts.map +1 -1
  50. package/lib/types/shared/antigravity-contracts.d.ts +18 -0
  51. package/lib/types/shared/antigravity-contracts.d.ts.map +1 -1
  52. package/lib/types/shared/command-code-contracts.d.ts +2 -0
  53. package/lib/types/shared/command-code-contracts.d.ts.map +1 -1
  54. package/lib/types/shared/contracts.d.ts +2 -0
  55. package/lib/types/shared/contracts.d.ts.map +1 -1
  56. package/lib/types/shared/kimi-code-contracts.d.ts +2 -0
  57. package/lib/types/shared/kimi-code-contracts.d.ts.map +1 -1
  58. package/lib/types/shared/preferences.d.ts.map +1 -1
  59. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -507,7 +507,10 @@ window.__ModuleLoader__.load({
507
507
  const toggleVisibleModel = async (modelId, checked) => {
508
508
  const current = status?.preferences.visibleModelIds ?? [...DEFAULT_VISIBLE_CODEX_MODEL_IDS];
509
509
  const visibleModelIds = checked ? [...current, modelId] : current.filter((id) => id !== modelId);
510
- if (visibleModelIds.length === 0) return;
510
+ await updatePreferences({ visibleModelIds });
511
+ };
512
+ const setAllVisibleModels = async (selectAll) => {
513
+ const visibleModelIds = selectAll ? CODEX_MODEL_CATALOG.map((m) => m.id) : [];
511
514
  await updatePreferences({ visibleModelIds });
512
515
  };
513
516
  const updateContextWindow = async (model) => {
@@ -647,6 +650,26 @@ window.__ModuleLoader__.load({
647
650
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Section, {
648
651
  title: t("connection"),
649
652
  children: [
653
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
654
+ className: "dsh-codex-pref-row",
655
+ style: { marginBottom: 12 },
656
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("enableProvider") }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
657
+ type: "checkbox",
658
+ checked: preferences?.enabled ?? true,
659
+ disabled: busy !== null,
660
+ onChange: (event) => {
661
+ const enabled = event.currentTarget.checked;
662
+ setStatus((cur) => cur === null ? cur : {
663
+ ...cur,
664
+ preferences: {
665
+ ...cur.preferences,
666
+ enabled
667
+ }
668
+ });
669
+ updatePreferences({ enabled });
670
+ }
671
+ })]
672
+ }),
650
673
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoRow, {
651
674
  label: t("provider"),
652
675
  value: "Codex(ChatGPT 订阅) · codex-chatgpt"
@@ -668,18 +691,34 @@ window.__ModuleLoader__.load({
668
691
  "aria-label": t("models"),
669
692
  children: CODEX_MODEL_CATALOG.map((model) => {
670
693
  const checked = visibleModelIds.some((id) => id === model.id);
671
- const lastVisible = checked && visibleModelIds.length === 1;
672
694
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
673
695
  title: model.id,
674
696
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
675
697
  type: "checkbox",
676
698
  checked,
677
- disabled: busy !== null || lastVisible,
699
+ disabled: busy !== null,
678
700
  onChange: (event) => void toggleVisibleModel(model.id, event.currentTarget.checked)
679
701
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name })]
680
702
  }, model.id);
681
703
  })
682
704
  }),
705
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
706
+ style: {
707
+ display: "flex",
708
+ gap: 8,
709
+ marginTop: 8,
710
+ marginBottom: 12
711
+ },
712
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
713
+ disabled: busy !== null,
714
+ onClick: () => void setAllVisibleModels(true),
715
+ children: t("selectAll")
716
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
717
+ disabled: busy !== null,
718
+ onClick: () => void setAllVisibleModels(false),
719
+ children: t("unselectAll")
720
+ })]
721
+ }),
683
722
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
684
723
  className: "dsh-codex-actions",
685
724
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
@@ -1248,6 +1287,18 @@ window.__ModuleLoader__.load({
1248
1287
  account: "已登录",
1249
1288
  signedIn: "已登录",
1250
1289
  signedOut: "未登录",
1290
+ accountPool: "账号管理",
1291
+ addAccount: "添加账号",
1292
+ primaryAccount: "主账号",
1293
+ activeAccount: "当前使用",
1294
+ setPrimary: "设为主账号",
1295
+ deleteAccount: "删除",
1296
+ cooling: "冷却中",
1297
+ clearCooldown: "重置冷却",
1298
+ rotationStrategy: "调度策略",
1299
+ strategySequential: "顺序耗尽(当前优先,遇限流自动切号)",
1300
+ strategyRoundRobin: "轮询调度(按账号循环均匀分摊)",
1301
+ noAccounts: "暂无账号,点击「添加账号」完成登录授权。",
1251
1302
  plan: "套餐",
1252
1303
  accountId: "账号 ID",
1253
1304
  expires: "令牌到期",
@@ -1264,7 +1315,8 @@ window.__ModuleLoader__.load({
1264
1315
  connectionState: "连接状态",
1265
1316
  connected: "已连接",
1266
1317
  untested: "未测试",
1267
- modelsHint: "勾选后模型才会显示在对话页的模型选择列表中;至少保留一个。",
1318
+ enableProvider: "启用此供应商",
1319
+ modelsHint: "勾选后模型才会显示在对话页的模型选择列表中;全部取消勾选或关闭上方开关可在列表中隐藏该供应商。",
1268
1320
  selectAll: "全选",
1269
1321
  unselectAll: "全不选",
1270
1322
  enhanced: "增强功能",
@@ -1299,6 +1351,18 @@ window.__ModuleLoader__.load({
1299
1351
  account: "Signed in",
1300
1352
  signedIn: "Signed in",
1301
1353
  signedOut: "Not signed in",
1354
+ accountPool: "Account Management",
1355
+ addAccount: "Add Account",
1356
+ primaryAccount: "Primary",
1357
+ activeAccount: "In Use",
1358
+ setPrimary: "Set as Primary",
1359
+ deleteAccount: "Delete",
1360
+ cooling: "In Cooldown",
1361
+ clearCooldown: "Clear Cooldown",
1362
+ rotationStrategy: "Scheduling Strategy",
1363
+ strategySequential: "Sequential Drain (Primary first, failover on 429)",
1364
+ strategyRoundRobin: "Round-Robin (Evenly rotate across accounts)",
1365
+ noAccounts: "No accounts yet. Click \"Add Account\" to authorize.",
1302
1366
  plan: "Plan",
1303
1367
  accountId: "Account ID",
1304
1368
  expires: "Token expires",
@@ -1315,7 +1379,8 @@ window.__ModuleLoader__.load({
1315
1379
  connectionState: "Connection state",
1316
1380
  connected: "Connected",
1317
1381
  untested: "Untested",
1318
- modelsHint: "Checked models will appear in DSH conversation model list; keep at least one.",
1382
+ enableProvider: "Enable this provider",
1383
+ modelsHint: "Checked models will appear in DSH conversation model list; unchecking all or turning off the switch hides this provider.",
1319
1384
  selectAll: "Select all",
1320
1385
  unselectAll: "Deselect all",
1321
1386
  enhanced: "Enhanced Features",
@@ -1495,11 +1560,36 @@ window.__ModuleLoader__.load({
1495
1560
  setBusy(null);
1496
1561
  }
1497
1562
  };
1498
- const handleLogout = async () => {
1563
+ const handleSetPrimary = async (accountId) => {
1499
1564
  try {
1500
- setBusy("logout");
1565
+ setBusy(`primary-${accountId}`);
1566
+ setError(null);
1567
+ const updated = await fetchApi$5("/accounts", {
1568
+ method: "POST",
1569
+ body: JSON.stringify({
1570
+ action: "set-primary",
1571
+ accountId
1572
+ })
1573
+ });
1574
+ setStatus(updated);
1575
+ notifyChange();
1576
+ } catch (err) {
1577
+ setError(err instanceof Error ? err.message : String(err));
1578
+ } finally {
1579
+ setBusy(null);
1580
+ }
1581
+ };
1582
+ const handleDeleteAccount = async (accountId) => {
1583
+ try {
1584
+ setBusy(`delete-${accountId}`);
1501
1585
  setError(null);
1502
- const updated = await fetchApi$5("/logout", { method: "POST" });
1586
+ const updated = await fetchApi$5("/accounts", {
1587
+ method: "POST",
1588
+ body: JSON.stringify({
1589
+ action: "delete",
1590
+ accountId
1591
+ })
1592
+ });
1503
1593
  setStatus(updated);
1504
1594
  notifyChange();
1505
1595
  } catch (err) {
@@ -1508,11 +1598,63 @@ window.__ModuleLoader__.load({
1508
1598
  setBusy(null);
1509
1599
  }
1510
1600
  };
1601
+ const handleClearCooldown = async (accountId) => {
1602
+ try {
1603
+ setBusy(`cooldown-${accountId}`);
1604
+ setError(null);
1605
+ const updated = await fetchApi$5("/accounts", {
1606
+ method: "POST",
1607
+ body: JSON.stringify({
1608
+ action: "clear-cooldown",
1609
+ accountId
1610
+ })
1611
+ });
1612
+ setStatus(updated);
1613
+ } catch (err) {
1614
+ setError(err instanceof Error ? err.message : String(err));
1615
+ } finally {
1616
+ setBusy(null);
1617
+ }
1618
+ };
1619
+ const handleSetStrategy = async (strategy) => {
1620
+ try {
1621
+ setBusy("strategy");
1622
+ setError(null);
1623
+ const updated = await fetchApi$5("/accounts", {
1624
+ method: "POST",
1625
+ body: JSON.stringify({
1626
+ action: "strategy",
1627
+ strategy
1628
+ })
1629
+ });
1630
+ setStatus(updated);
1631
+ } catch (err) {
1632
+ setError(err instanceof Error ? err.message : String(err));
1633
+ } finally {
1634
+ setBusy(null);
1635
+ }
1636
+ };
1637
+ const toggleEnabled = async (enabled) => {
1638
+ setStatus((prev) => prev ? {
1639
+ ...prev,
1640
+ enabled
1641
+ } : prev);
1642
+ try {
1643
+ const updated = await fetchApi$5("/settings", {
1644
+ method: "POST",
1645
+ body: JSON.stringify({ enabled })
1646
+ });
1647
+ setStatus(updated);
1648
+ notifyChange();
1649
+ } catch (err) {
1650
+ setError(err instanceof Error ? err.message : String(err));
1651
+ loadStatus(true);
1652
+ }
1653
+ };
1511
1654
  const toggleModel = async (modelId, checked) => {
1512
1655
  if (!status) return;
1513
1656
  const currentEnabled = status.models.filter((m) => m.enabled).map((m) => m.id);
1514
1657
  const nextEnabled = checked ? [.../* @__PURE__ */ new Set([...currentEnabled, modelId])] : currentEnabled.filter((id) => id !== modelId);
1515
- if (nextEnabled.length === 0) return;
1516
1658
  try {
1517
1659
  const updated = await fetchApi$5("/models", {
1518
1660
  method: "POST",
@@ -1526,7 +1668,7 @@ window.__ModuleLoader__.load({
1526
1668
  };
1527
1669
  const setAllModels = async (selectAll) => {
1528
1670
  if (!status) return;
1529
- const nextEnabled = selectAll ? status.models.map((m) => m.id) : [status.models[0].id];
1671
+ const nextEnabled = selectAll ? status.models.map((m) => m.id) : [];
1530
1672
  try {
1531
1673
  const updated = await fetchApi$5("/models", {
1532
1674
  method: "POST",
@@ -1585,100 +1727,150 @@ window.__ModuleLoader__.load({
1585
1727
  });
1586
1728
  const quota = status?.quota;
1587
1729
  const groups = quota?.groups || [];
1588
- const visibleCount = status?.models.filter((m) => m.enabled).length || 0;
1730
+ status?.models.filter((m) => m.enabled).length;
1589
1731
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1590
1732
  className: "dsha-page",
1591
1733
  children: [
1592
1734
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1593
1735
  className: "dsha-group",
1594
1736
  children: [
1595
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1596
- className: "dsha-grouphead",
1597
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: status?.authenticated ? t.account : t.signedOut })
1598
- }),
1599
1737
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1600
- className: "dsha-row",
1601
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1602
- className: "dsha-label",
1603
- children: status?.authenticated ? t.signedIn : t.signedOut
1604
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1605
- className: "dsha-value",
1606
- children: status?.email || "—"
1738
+ className: "dsha-grouphead",
1739
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h3", { children: [t.accountPool, status?.accounts && status.accounts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1740
+ className: "dsha-muted",
1741
+ style: {
1742
+ fontWeight: 400,
1743
+ marginLeft: 8
1744
+ },
1745
+ children: [
1746
+ "(已登录 ",
1747
+ status.accounts.length,
1748
+ " 个账号)"
1749
+ ]
1750
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1751
+ className: "dsha-btn dsha-btn-primary",
1752
+ disabled: busy !== null,
1753
+ onClick: handleLogin,
1754
+ children: busy === "login" ? loginProgress || t.signingIn : t.addAccount
1607
1755
  })]
1608
1756
  }),
1609
- status?.authenticated && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1610
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1611
- className: "dsha-row",
1612
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1613
- className: "dsha-label",
1614
- children: t.plan
1615
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1616
- className: "dsha-value",
1617
- children: quota?.planLabel || "Google AI Ultra"
1618
- })]
1619
- }),
1620
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1621
- className: "dsha-row",
1622
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1623
- className: "dsha-label",
1624
- children: t.accountId
1625
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1626
- className: "dsha-value",
1627
- children: status.projectId || "antigravity-default"
1628
- })]
1629
- }),
1630
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1631
- className: "dsha-row",
1632
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1633
- className: "dsha-label",
1634
- children: t.expires
1635
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1636
- className: "dsha-value",
1637
- children: formatDate$2(Date.now() + 864e5 * 30)
1757
+ status?.accounts && status.accounts.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1758
+ className: "dsha-pref-row",
1759
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.rotationStrategy }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1760
+ className: "dsha-muted",
1761
+ style: {
1762
+ fontSize: 12,
1763
+ marginTop: 2
1764
+ },
1765
+ children: status.rotationStrategy === "round-robin" ? t.strategyRoundRobin : t.strategySequential
1766
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1767
+ className: "dsha-select",
1768
+ value: status.rotationStrategy || "sequential",
1769
+ disabled: busy !== null,
1770
+ onChange: (e) => void handleSetStrategy(e.target.value),
1771
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1772
+ value: "sequential",
1773
+ children: "顺序耗尽"
1774
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1775
+ value: "round-robin",
1776
+ children: "轮询调度"
1638
1777
  })]
1778
+ })]
1779
+ }),
1780
+ !status?.accounts || status.accounts.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1781
+ className: "dsha-empty",
1782
+ children: t.noAccounts
1783
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1784
+ className: "dsha-accounts-list",
1785
+ children: status.accounts.map((acc) => {
1786
+ const isCurrentActive = acc.id === status.activeAccountId;
1787
+ const isCooling = typeof acc.cooldownUntil === "number" && acc.cooldownUntil > Date.now();
1788
+ const cooldownLeftSec = isCooling ? Math.ceil((acc.cooldownUntil - Date.now()) / 1e3) : 0;
1789
+ const cooldownLeftMin = Math.ceil(cooldownLeftSec / 60);
1790
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1791
+ className: `dsha-account-card ${isCurrentActive ? "active" : ""}`,
1792
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1793
+ className: "dsha-account-header",
1794
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1795
+ className: "dsha-account-identity",
1796
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1797
+ className: "dsha-account-title",
1798
+ children: acc.alias || acc.email || acc.id
1799
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1800
+ className: "dsha-badges",
1801
+ children: [
1802
+ acc.isPrimary && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1803
+ className: "dsha-badge primary",
1804
+ children: t.primaryAccount
1805
+ }),
1806
+ isCurrentActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1807
+ className: "dsha-badge active",
1808
+ children: t.activeAccount
1809
+ }),
1810
+ isCooling && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1811
+ className: "dsha-badge cooldown",
1812
+ children: [
1813
+ t.cooling,
1814
+ "(剩 ",
1815
+ cooldownLeftMin,
1816
+ " 分)"
1817
+ ]
1818
+ })
1819
+ ]
1820
+ })]
1821
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1822
+ className: "dsha-account-actions",
1823
+ children: [
1824
+ !acc.isPrimary && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1825
+ className: "dsha-btn",
1826
+ disabled: busy !== null,
1827
+ onClick: () => void handleSetPrimary(acc.id),
1828
+ children: t.setPrimary
1829
+ }),
1830
+ isCooling && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1831
+ className: "dsha-btn",
1832
+ disabled: busy !== null,
1833
+ onClick: () => void handleClearCooldown(acc.id),
1834
+ children: t.clearCooldown
1835
+ }),
1836
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1837
+ className: "dsha-btn",
1838
+ disabled: busy !== null,
1839
+ onClick: () => void handleDeleteAccount(acc.id),
1840
+ children: t.deleteAccount
1841
+ })
1842
+ ]
1843
+ })]
1844
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1845
+ className: "dsha-account-details",
1846
+ children: [
1847
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
1848
+ t.accountId,
1849
+ ": ",
1850
+ acc.projectId || "antigravity-default"
1851
+ ] }),
1852
+ acc.email && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["邮箱: ", acc.email] }),
1853
+ acc.expiresAt && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["令牌到期: ", formatDate$2(acc.expiresAt)] }),
1854
+ acc.lastUsedAt && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["上次调用: ", formatDate$2(acc.lastUsedAt)] })
1855
+ ]
1856
+ })]
1857
+ }, acc.id);
1639
1858
  })
1640
- ] }),
1859
+ }),
1641
1860
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1642
1861
  className: "dsha-row",
1862
+ style: { marginTop: 12 },
1643
1863
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1644
1864
  className: "dsha-label",
1645
1865
  children: t.storage
1646
1866
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1647
1867
  className: "dsha-value",
1648
- children: "本地安全存储 (JSON)"
1868
+ children: "本地安全存储 (JSON/DPAPI)"
1649
1869
  })]
1650
1870
  }),
1651
1871
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1652
1872
  className: "dsha-notice",
1653
1873
  children: t.storageNotice
1654
- }),
1655
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1656
- className: "dsha-actions",
1657
- children: !status?.authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1658
- className: "dsha-btn dsha-btn-primary",
1659
- disabled: busy !== null,
1660
- onClick: handleLogin,
1661
- children: busy === "login" ? loginProgress || t.signingIn : t.signIn
1662
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
1663
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1664
- className: "dsha-btn dsha-btn-primary",
1665
- disabled: busy !== null,
1666
- onClick: handleLogin,
1667
- children: busy === "login" ? loginProgress || t.signingIn : t.signInAgain
1668
- }),
1669
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1670
- className: "dsha-btn",
1671
- disabled: busy !== null,
1672
- onClick: handleRefreshQuota,
1673
- children: busy === "quota" ? t.refreshingQuota : t.refreshToken
1674
- }),
1675
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1676
- className: "dsha-btn",
1677
- disabled: busy !== null,
1678
- onClick: handleLogout,
1679
- children: t.signOut
1680
- })
1681
- ] })
1682
1874
  })
1683
1875
  ]
1684
1876
  }),
@@ -1689,6 +1881,20 @@ window.__ModuleLoader__.load({
1689
1881
  className: "dsha-grouphead",
1690
1882
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.connection })
1691
1883
  }),
1884
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1885
+ className: "dsha-row",
1886
+ style: { marginBottom: 12 },
1887
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1888
+ className: "dsha-label",
1889
+ style: { fontWeight: 600 },
1890
+ children: t.enableProvider
1891
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1892
+ type: "checkbox",
1893
+ checked: status?.enabled !== false,
1894
+ disabled: busy !== null,
1895
+ onChange: (e) => void toggleEnabled(e.currentTarget.checked)
1896
+ })]
1897
+ }),
1692
1898
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1693
1899
  className: "dsha-row",
1694
1900
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -1718,13 +1924,12 @@ window.__ModuleLoader__.load({
1718
1924
  "aria-label": "Antigravity Models",
1719
1925
  children: status?.models.map((model) => {
1720
1926
  const checked = model.enabled;
1721
- const lastVisible = checked && visibleCount === 1;
1722
1927
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1723
1928
  title: model.id,
1724
1929
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1725
1930
  type: "checkbox",
1726
1931
  checked,
1727
- disabled: busy !== null || lastVisible,
1932
+ disabled: busy !== null,
1728
1933
  onChange: (e) => void toggleModel(model.id, e.currentTarget.checked)
1729
1934
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name })]
1730
1935
  }, model.id);
@@ -1959,7 +2164,8 @@ window.__ModuleLoader__.load({
1959
2164
  routeOwned: "模型路由由本插件提供",
1960
2165
  routeConflict: "模型路由已被其他 Provider 占用:{detail}。请在 DSH 设置中移除重复的 Provider 配置后重试。",
1961
2166
  modelsSection: "模型",
1962
- modelsHint: "勾选后模型才会出现在对话页的模型选择列表中;至少保留一个。",
2167
+ enableProvider: "启用此供应商",
2168
+ modelsHint: "勾选后模型才会出现在对话页的模型选择列表中;全部取消勾选或关闭上方开关可在列表中隐藏该供应商。",
1963
2169
  refreshCatalog: "刷新模型目录",
1964
2170
  refreshingCatalog: "刷新中...",
1965
2171
  selectAll: "全选",
@@ -2025,7 +2231,8 @@ window.__ModuleLoader__.load({
2025
2231
  routeOwned: "This plugin serves the model route",
2026
2232
  routeConflict: "Another provider already owns the model route: {detail}. Remove the duplicate provider configuration in DSH settings and reload.",
2027
2233
  modelsSection: "Models",
2028
- modelsHint: "Checked models appear in the DSH conversation model list; keep at least one.",
2234
+ enableProvider: "Enable this provider",
2235
+ modelsHint: "Checked models appear in the DSH conversation model list; unchecking all or turning off the switch hides this provider.",
2029
2236
  refreshCatalog: "Refresh catalog",
2030
2237
  refreshingCatalog: "Refreshing...",
2031
2238
  selectAll: "Select all",
@@ -2281,16 +2488,32 @@ window.__ModuleLoader__.load({
2281
2488
  setError(err instanceof Error ? err.message : String(err));
2282
2489
  }
2283
2490
  };
2491
+ const toggleEnabled = async (enabled) => {
2492
+ setStatus((prev) => prev ? {
2493
+ ...prev,
2494
+ enabled
2495
+ } : prev);
2496
+ try {
2497
+ const updated = await fetchApi$4("/settings", {
2498
+ method: "POST",
2499
+ body: JSON.stringify({ enabled })
2500
+ });
2501
+ setStatus(updated);
2502
+ notifyChange();
2503
+ } catch (err) {
2504
+ setError(err instanceof Error ? err.message : String(err));
2505
+ loadStatus(true);
2506
+ }
2507
+ };
2284
2508
  const toggleModel = (modelId, checked) => {
2285
2509
  if (!status) return;
2286
2510
  const current = status.models.filter((model) => model.enabled).map((model) => model.id);
2287
2511
  const next = checked ? [.../* @__PURE__ */ new Set([...current, modelId])] : current.filter((id) => id !== modelId);
2288
- if (next.length === 0) return;
2289
2512
  applyEnabled(next);
2290
2513
  };
2291
2514
  const setAllModels = (selectAll) => {
2292
2515
  if (!status || status.models.length === 0) return;
2293
- applyEnabled(selectAll ? status.models.map((model) => model.id) : [status.models[0].id]);
2516
+ applyEnabled(selectAll ? status.models.map((model) => model.id) : []);
2294
2517
  };
2295
2518
  const handleUpdateEffort = async (effort) => {
2296
2519
  try {
@@ -2339,7 +2562,7 @@ window.__ModuleLoader__.load({
2339
2562
  });
2340
2563
  const quota = status?.quota;
2341
2564
  const account = status?.account;
2342
- const visibleCount = status?.models.filter((model) => model.enabled).length || 0;
2565
+ status?.models.filter((model) => model.enabled).length;
2343
2566
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2344
2567
  className: "dsha-page",
2345
2568
  children: [
@@ -2495,6 +2718,20 @@ window.__ModuleLoader__.load({
2495
2718
  className: "dsha-grouphead",
2496
2719
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.connection })
2497
2720
  }),
2721
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2722
+ className: "dsha-row",
2723
+ style: { marginBottom: 12 },
2724
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2725
+ className: "dsha-label",
2726
+ style: { fontWeight: 600 },
2727
+ children: t.enableProvider
2728
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2729
+ type: "checkbox",
2730
+ checked: status?.enabled !== false,
2731
+ disabled: busy !== null,
2732
+ onChange: (e) => void toggleEnabled(e.currentTarget.checked)
2733
+ })]
2734
+ }),
2498
2735
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2499
2736
  className: "dsha-row",
2500
2737
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -2550,13 +2787,12 @@ window.__ModuleLoader__.load({
2550
2787
  className: "dsha-models",
2551
2788
  "aria-label": "Command Code Models",
2552
2789
  children: status?.models.map((model) => {
2553
- const lastVisible = model.enabled && visibleCount === 1;
2554
2790
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2555
2791
  title: `${model.id} · ${model.wire === "anthropic" ? t.wireAnthropic : t.wireOpenai}`,
2556
2792
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2557
2793
  type: "checkbox",
2558
2794
  checked: model.enabled,
2559
- disabled: busy !== null || lastVisible,
2795
+ disabled: busy !== null,
2560
2796
  onChange: (event) => toggleModel(model.id, event.currentTarget.checked)
2561
2797
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name })]
2562
2798
  }, model.id);
@@ -2806,7 +3042,8 @@ window.__ModuleLoader__.load({
2806
3042
  routeOwned: "模型路由由本插件提供",
2807
3043
  routeConflict: "模型路由已被其他 Provider 占用:{detail}。请在 DSH 设置中移除重复的 Provider 配置后重试。",
2808
3044
  modelsSection: "模型",
2809
- modelsHint: "勾选后模型才会出现在对话页的模型选择列表中;至少保留一个。",
3045
+ enableProvider: "启用此供应商",
3046
+ modelsHint: "勾选后模型才会出现在对话页的模型选择列表中;全部取消勾选或关闭上方开关可在列表中隐藏该供应商。",
2810
3047
  refreshCatalog: "刷新模型目录",
2811
3048
  refreshingCatalog: "刷新中...",
2812
3049
  selectAll: "全选",
@@ -2917,7 +3154,8 @@ window.__ModuleLoader__.load({
2917
3154
  routeOwned: "This plugin serves the model route",
2918
3155
  routeConflict: "Another provider already owns the model route: {detail}. Remove the duplicate provider configuration in DSH settings and reload.",
2919
3156
  modelsSection: "Models",
2920
- modelsHint: "Checked models appear in the DSH conversation model list; keep at least one.",
3157
+ enableProvider: "Enable this provider",
3158
+ modelsHint: "Checked models appear in the DSH conversation model list; unchecking all or turning off the switch hides this provider.",
2921
3159
  refreshCatalog: "Refresh catalog",
2922
3160
  refreshingCatalog: "Refreshing...",
2923
3161
  selectAll: "Select all",
@@ -3274,16 +3512,32 @@ window.__ModuleLoader__.load({
3274
3512
  setError(err instanceof Error ? err.message : String(err));
3275
3513
  }
3276
3514
  };
3515
+ const toggleEnabled = async (enabled) => {
3516
+ setStatus((prev) => prev ? {
3517
+ ...prev,
3518
+ enabled
3519
+ } : prev);
3520
+ try {
3521
+ const updated = await fetchApi$3("/settings", {
3522
+ method: "POST",
3523
+ body: JSON.stringify({ enabled })
3524
+ });
3525
+ setStatus(updated);
3526
+ notifyChange();
3527
+ } catch (err) {
3528
+ setError(err instanceof Error ? err.message : String(err));
3529
+ loadStatus(true);
3530
+ }
3531
+ };
3277
3532
  const toggleModel = (modelId, checked) => {
3278
3533
  if (!status) return;
3279
3534
  const current = status.models.filter((model) => model.enabled).map((model) => model.id);
3280
3535
  const next = checked ? [.../* @__PURE__ */ new Set([...current, modelId])] : current.filter((id) => id !== modelId);
3281
- if (next.length === 0) return;
3282
3536
  applyEnabled(next);
3283
3537
  };
3284
3538
  const setAllModels = (selectAll) => {
3285
3539
  if (!status || status.models.length === 0) return;
3286
- applyEnabled(selectAll ? status.models.map((model) => model.id) : [status.models[0].id]);
3540
+ applyEnabled(selectAll ? status.models.map((model) => model.id) : []);
3287
3541
  };
3288
3542
  const handleUpdateEffort = async (effort) => {
3289
3543
  try {
@@ -3332,7 +3586,7 @@ window.__ModuleLoader__.load({
3332
3586
  });
3333
3587
  const quota = status?.quota;
3334
3588
  const account = status?.account;
3335
- const visibleCount = status?.models.filter((model) => model.enabled).length || 0;
3589
+ status?.models.filter((model) => model.enabled).length;
3336
3590
  const loginPending = flow?.status === "pending";
3337
3591
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3338
3592
  className: "dsha-page",
@@ -3504,6 +3758,20 @@ window.__ModuleLoader__.load({
3504
3758
  className: "dsha-grouphead",
3505
3759
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.connection })
3506
3760
  }),
3761
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3762
+ className: "dsha-row",
3763
+ style: { marginBottom: 12 },
3764
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3765
+ className: "dsha-label",
3766
+ style: { fontWeight: 600 },
3767
+ children: t.enableProvider
3768
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3769
+ type: "checkbox",
3770
+ checked: status?.enabled !== false,
3771
+ disabled: busy !== null,
3772
+ onChange: (e) => void toggleEnabled(e.currentTarget.checked)
3773
+ })]
3774
+ }),
3507
3775
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3508
3776
  className: "dsha-row",
3509
3777
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -3583,7 +3851,6 @@ window.__ModuleLoader__.load({
3583
3851
  className: "dsha-models",
3584
3852
  "aria-label": "Kimi Code Models",
3585
3853
  children: status?.models.map((model) => {
3586
- const lastVisible = model.enabled && visibleCount === 1;
3587
3854
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3588
3855
  title: [
3589
3856
  model.id,
@@ -3595,7 +3862,7 @@ window.__ModuleLoader__.load({
3595
3862
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3596
3863
  type: "checkbox",
3597
3864
  checked: model.enabled,
3598
- disabled: busy !== null || lastVisible,
3865
+ disabled: busy !== null,
3599
3866
  onChange: (event) => toggleModel(model.id, event.currentTarget.checked)
3600
3867
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name })]
3601
3868
  }, model.id);
@@ -3912,8 +4179,11 @@ window.__ModuleLoader__.load({
3912
4179
  testConnection: "测试连接",
3913
4180
  testing: "测试中…",
3914
4181
  latency: "最近延迟",
4182
+ enableProvider: "启用此供应商",
4183
+ selectAll: "全选",
4184
+ unselectAll: "全不选",
3915
4185
  models: "可用模型",
3916
- modelsHint: "勾选后模型才会显示在对话页的模型选择列表中;至少保留一个。",
4186
+ modelsHint: "勾选后模型才会显示在对话页的模型选择列表中;全部取消勾选或关闭上方开关可在列表中隐藏该供应商。",
3917
4187
  proxySettings: "网络代理",
3918
4188
  proxyMode: "代理模式",
3919
4189
  proxyModeHint: "GPT 与 Antigravity(Gemini)共用此代理设置;支持自动读取系统代理,修改后对后续请求生效。",
@@ -4037,8 +4307,11 @@ window.__ModuleLoader__.load({
4037
4307
  testConnection: "Test connection",
4038
4308
  testing: "Testing…",
4039
4309
  latency: "Last latency",
4310
+ enableProvider: "Enable this provider",
4311
+ selectAll: "Select all",
4312
+ unselectAll: "Unselect all",
4040
4313
  models: "Available models",
4041
- modelsHint: "Checked models appear in the conversation model picker; at least one must remain enabled.",
4314
+ modelsHint: "Checked models appear in the conversation model picker; unchecking all or turning off the switch hides this provider from the picker.",
4042
4315
  proxySettings: "Network Proxy",
4043
4316
  proxyMode: "Proxy Mode",
4044
4317
  proxyModeHint: "GPT and Antigravity (Gemini) share these proxy settings. Supports system proxy detection; changes apply to subsequent requests.",
@@ -4309,6 +4582,20 @@ window.__ModuleLoader__.load({
4309
4582
  .dsha-composer-quota strong{color:var(--dsw-alias-label-primary);font-size:11px;font-weight:650}
4310
4583
  .dsha-composer-quota[data-level=warning] strong{color:var(--dsw-alias-label-warning,#d58a24)}
4311
4584
  .dsha-composer-quota[data-level=danger] strong{color:var(--dsw-alias-label-danger,#d94b4b)}
4585
+ .dsha-accounts-list{display:flex;flex-direction:column;gap:10px;margin-top:10px}
4586
+ .dsha-account-card{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;padding:12px 14px;display:flex;flex-direction:column;gap:8px;transition:border-color .15s ease}
4587
+ .dsha-account-card.active{border-color:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 60%,var(--dsw-alias-border-l2))}
4588
+ .dsha-account-header{display:flex;align-items:center;justify-content:space-between;gap:8px}
4589
+ .dsha-account-identity{display:flex;align-items:center;gap:8px;min-width:0}
4590
+ .dsha-account-title{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
4591
+ .dsha-badges{display:flex;align-items:center;gap:6px}
4592
+ .dsha-badge{font-size:11px;line-height:1;padding:3px 7px;border-radius:4px;font-weight:550;white-space:nowrap}
4593
+ .dsha-badge.primary{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 18%,var(--dsw-alias-bg-layer-1));color:var(--dsw-alias-button-info-fill,#397ee8);border:0.5px solid color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 40%,transparent)}
4594
+ .dsha-badge.active{background:color-mix(in srgb,var(--dsw-alias-label-success,#10b981) 18%,var(--dsw-alias-bg-layer-1));color:var(--dsw-alias-label-success,#10b981);border:0.5px solid color-mix(in srgb,var(--dsw-alias-label-success,#10b981) 40%,transparent)}
4595
+ .dsha-badge.cooldown{background:color-mix(in srgb,var(--dsw-alias-label-warning,#d58a24) 18%,var(--dsw-alias-bg-layer-1));color:var(--dsw-alias-label-warning,#d58a24);border:0.5px solid color-mix(in srgb,var(--dsw-alias-label-warning,#d58a24) 40%,transparent)}
4596
+ .dsha-account-details{display:flex;flex-wrap:wrap;gap:14px;font-size:12px;color:var(--dsw-alias-label-secondary)}
4597
+ .dsha-account-actions{display:flex;flex-wrap:wrap;gap:6px;margin-top:2px}
4598
+ .dsha-account-actions .dsha-btn{padding:5px 10px;font-size:12px}
4312
4599
  `;
4313
4600
  document.head.append(style);
4314
4601
  }