dsh-subscriptions 0.1.3 → 0.1.4

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 (58) hide show
  1. package/README.md +64 -0
  2. package/lib/auth/rpc.d.ts +3 -1
  3. package/lib/auth/rpc.js +10 -1
  4. package/lib/client/ProviderAccountManager.js +34 -41
  5. package/lib/client/ProviderModelEditor.js +5 -9
  6. package/lib/client/SpeedSelect.js +8 -7
  7. package/lib/client/SubscriptionUsageBadge.js +6 -5
  8. package/lib/client/SubscriptionsSection.d.ts +22 -0
  9. package/lib/client/SubscriptionsSection.js +128 -38
  10. package/lib/client/UsageBadgeDisplaySetting.js +4 -8
  11. package/lib/client/host-contract.d.ts +1 -1
  12. package/lib/client/host-contract.js +22 -0
  13. package/lib/client/locales.d.ts +58 -0
  14. package/lib/client/locales.js +58 -0
  15. package/lib/client/provider-settings-styles.d.ts +3 -0
  16. package/lib/client/provider-settings-styles.js +206 -0
  17. package/lib/client/reset-action.d.ts +14 -0
  18. package/lib/client/reset-action.js +15 -0
  19. package/lib/client/reset-credits-view.d.ts +53 -0
  20. package/lib/client/reset-credits-view.js +103 -0
  21. package/lib/client.js +937 -310
  22. package/lib/client.js.map +1 -1
  23. package/lib/index.d.ts +9 -0
  24. package/lib/index.js +1099 -608
  25. package/lib/providers/account-preferences.js +3 -2
  26. package/lib/providers/catalog-store.d.ts +3 -2
  27. package/lib/providers/catalog-store.js +57 -26
  28. package/lib/providers/claude.d.ts +22 -3
  29. package/lib/providers/claude.js +113 -15
  30. package/lib/providers/codex.d.ts +15 -2
  31. package/lib/providers/codex.js +72 -4
  32. package/lib/providers/common.d.ts +25 -0
  33. package/lib/providers/common.js +22 -18
  34. package/lib/providers/copilot.d.ts +2 -1
  35. package/lib/providers/copilot.js +10 -3
  36. package/lib/providers/grok.d.ts +2 -2
  37. package/lib/providers/grok.js +2 -2
  38. package/lib/providers/pool-health.d.ts +2 -0
  39. package/lib/providers/pool-health.js +9 -0
  40. package/lib/providers/pool-usage.d.ts +13 -1
  41. package/lib/providers/pool-usage.js +39 -7
  42. package/lib/providers/pool.d.ts +7 -5
  43. package/lib/providers/pool.js +89 -12
  44. package/lib/providers/rate-limit.d.ts +0 -14
  45. package/lib/providers/rate-limit.js +0 -26
  46. package/lib/providers/replay.d.ts +4 -0
  47. package/lib/providers/replay.js +50 -0
  48. package/lib/providers/reset-redemption.d.ts +51 -0
  49. package/lib/providers/reset-redemption.js +102 -0
  50. package/lib/translate/anthropic.d.ts +21 -2
  51. package/lib/translate/anthropic.js +35 -11
  52. package/lib/translate/antigravity.js +13 -6
  53. package/lib/translate/chat-completions.js +1 -1
  54. package/lib/translate/resolved.d.ts +21 -0
  55. package/lib/translate/resolved.js +63 -3
  56. package/lib/translate/responses.js +8 -6
  57. package/lib/translate/sse.js +8 -0
  58. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -139,6 +139,35 @@ const en = {
139
139
  usageColorPaceHint: "Yellow when usage leads elapsed time by {allowance} points; red at 90% used takes priority. Saved in this browser; only colors change.",
140
140
  usageColorRemainingHint: "Red at 90% used; no yellow pace warnings. Reliable time markers remain visible. Saved in this browser.",
141
141
  usagePlan: "Plan: {plan}",
142
+ resetCreditsTitle: "Usage limit resets",
143
+ resetCreditsAvailable: "{count} available",
144
+ resetCreditsError: "Usage limit resets unavailable: {message}",
145
+ resetCreditsErrorFixed: "Usage limit resets are unavailable. Refresh usage to try again.",
146
+ resetCreditReadOnly: "Read only. This page cannot spend a Claude reset.",
147
+ resetCreditReadOnlyLabel: "Read only",
148
+ resetCreditAvailable: "Available",
149
+ resetCreditNotUsable: "Not yet usable",
150
+ resetCreditPaused: "Paused",
151
+ resetCreditExhausted: "Exhausted",
152
+ resetCreditExpired: "Expired",
153
+ resetCreditRemaining: "{left} of {total} left",
154
+ resetCreditLeft: "{left} left",
155
+ resetCreditRemainingUnknown: "Remaining count unavailable",
156
+ resetCreditCooldownUntil: "Usable after {date}",
157
+ resetUseButton: "Use…",
158
+ resetUseChecking: "Checking…",
159
+ resetUseGuard: "You can use this reset when weekly usage reaches at least 80%.",
160
+ resetUseRestart: "Reset details are missing. Restart DSH, reload this page, then refresh usage.",
161
+ resetUseRefresh: "Refresh usage to verify current limits and reset availability.",
162
+ resetUseReady: "Use this reset — the earliest-expiring credit. Confirmation required.",
163
+ resetUseConfirmTitle: "Confirm full reset",
164
+ resetUseWarning: "This consumes one credit and resets weekly + 5-hour limits. This interface cannot undo it. Confirmation expires in 60 seconds.",
165
+ resetUseAcknowledge: "I understand that one credit will be consumed.",
166
+ resetUseConfirm: "Consume 1 reset",
167
+ resetUseSuccess: "Reset confirmed. Usage refreshed.",
168
+ resetCreditFull: "Full reset",
169
+ resetCreditExpires: "Expires {date}",
170
+ resetCreditExpiryUnknown: "Expiry date unavailable",
142
171
  externalUsageTitle: "Built-in provider usage",
143
172
  externalUsageConnected: "API key configured",
144
173
  externalUsageNotConfigured: "Not configured",
@@ -311,6 +340,35 @@ const zh = {
311
340
  usageColorPaceHint: "用量领先时间进度 {allowance} 个百分点时变黄;已用达到 90% 时优先变红。自动保存到当前浏览器,仅改变配色。",
312
341
  usageColorRemainingHint: "已用达到 90% 时变红,不显示黄色节奏警告。可靠的时间标记仍保留,自动保存到当前浏览器。",
313
342
  usagePlan: "计划:{plan}",
343
+ resetCreditsTitle: "用量限制重置",
344
+ resetCreditsAvailable: "可用 {count} 次",
345
+ resetCreditsError: "用量限制重置查询失败:{message}",
346
+ resetCreditsErrorFixed: "用量限制重置暂不可用,请刷新用量后重试。",
347
+ resetCreditReadOnly: "只读。此页面不能消耗 Claude 的重置额度。",
348
+ resetCreditReadOnlyLabel: "只读",
349
+ resetCreditAvailable: "可用",
350
+ resetCreditNotUsable: "暂不可用",
351
+ resetCreditPaused: "已暂停",
352
+ resetCreditExhausted: "已用尽",
353
+ resetCreditExpired: "已过期",
354
+ resetCreditRemaining: "剩余 {left} / {total}",
355
+ resetCreditLeft: "剩余 {left}",
356
+ resetCreditRemainingUnknown: "剩余次数不可用",
357
+ resetCreditCooldownUntil: "{date} 后可用",
358
+ resetUseButton: "使用…",
359
+ resetUseChecking: "正在检查…",
360
+ resetUseGuard: "每周用量达到 80% 后才可使用此重置。",
361
+ resetUseRestart: "缺少重置详情。请重启 DSH、重新加载页面并刷新用量。",
362
+ resetUseRefresh: "请刷新用量以验证当前限制和重置可用性。",
363
+ resetUseReady: "使用此最早到期的重置额度,操作前需要确认。",
364
+ resetUseConfirmTitle: "确认完整重置",
365
+ resetUseWarning: "将消耗一次额度并重置每周和 5 小时限制,无法撤销。确认将在 60 秒后过期。",
366
+ resetUseAcknowledge: "我理解将消耗一次额度。",
367
+ resetUseConfirm: "消耗一次重置",
368
+ resetUseSuccess: "重置已确认,用量已刷新。",
369
+ resetCreditFull: "完整重置",
370
+ resetCreditExpires: "{date} 到期",
371
+ resetCreditExpiryUnknown: "到期时间不可用",
314
372
  externalUsageTitle: "内置供应商用量",
315
373
  externalUsageConnected: "已配置 API 密钥",
316
374
  externalUsageNotConfigured: "未配置",
@@ -379,6 +437,18 @@ const zh = {
379
437
  commandFastUnavailable: "当前模型不支持快速档;/fast 仅对目录声明了 fast tier 的 Codex 模型可用"
380
438
  };
381
439
 
440
+ //#endregion
441
+ //#region src/client/reset-action.ts
442
+ /** Explain client-side gating; the server independently revalidates before spending. */
443
+ function resetActionBlock(usage, now = Date.now()) {
444
+ const weekly = usage.windows?.find((w) => w.kind === "weekly" && w.scope === void 0);
445
+ if (!weekly || !Number.isFinite(weekly.usedPercent)) return "resetUseRefresh";
446
+ if (weekly.usedPercent < 80) return "resetUseGuard";
447
+ if (weekly.resetsAt === void 0 || weekly.resetsAt <= now || usage.resetCreditsError) return "resetUseRefresh";
448
+ if (!usage.resetCredits?.some((c) => c.id)) return "resetUseRestart";
449
+ if (!usage.resetCredits.some((c) => c.id && (c.expiresAt === void 0 || c.expiresAt > now))) return "resetUseRefresh";
450
+ }
451
+
382
452
  //#endregion
383
453
  //#region src/client/subscriptions-rpc.ts
384
454
  /**
@@ -451,16 +521,7 @@ function mergeAccountChanges(latest, changes) {
451
521
 
452
522
  //#endregion
453
523
  //#region src/client/ProviderModelEditor.tsx
454
- const border$1 = "1px solid var(--dsw-alias-border-l2, #ddd)";
455
- const control$1 = {
456
- font: "inherit",
457
- color: "inherit",
458
- background: "transparent",
459
- border: border$1,
460
- borderRadius: 8,
461
- padding: "6px 10px",
462
- minWidth: 0
463
- };
524
+ const border$1 = "0.5px solid var(--dsw-alias-border-l2, #ddd)";
464
525
  const actions$1 = {
465
526
  display: "flex",
466
527
  flexWrap: "wrap",
@@ -569,10 +630,7 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
569
630
  paddingTop: 12
570
631
  },
571
632
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
572
- style: {
573
- margin: 0,
574
- fontSize: 15
575
- },
633
+ style: { margin: 0 },
576
634
  children: t("modelsEdit")
577
635
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
578
636
  style: {
@@ -582,22 +640,18 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
582
640
  },
583
641
  children: [
584
642
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
585
- style: { margin: 0 },
643
+ className: "dsh-subscription-hint",
586
644
  children: t(provider === "cursor-subscription" ? "cursorManageHint" : "modelsHint")
587
645
  }),
588
646
  error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
589
647
  role: "alert",
590
- style: {
591
- margin: 0,
592
- color: "var(--dsw-alias-state-error-primary, #b42318)"
593
- },
594
648
  children: error
595
649
  }),
596
650
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
597
651
  style: actions$1,
598
652
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
599
653
  type: "button",
600
- style: control$1,
654
+ className: "dsh-subscription-quiet",
601
655
  disabled: busy || disabled || dirty,
602
656
  onClick: () => {
603
657
  load(true);
@@ -637,10 +691,7 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
637
691
  style: actions$1,
638
692
  children: [
639
693
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
640
- style: {
641
- ...control$1,
642
- flex: "1 1 180px"
643
- },
694
+ style: { flex: "1 1 180px" },
644
695
  value: query,
645
696
  onChange: (event) => setQuery(event.target.value),
646
697
  placeholder: t("modelDefaultsFilterPlaceholder"),
@@ -648,7 +699,6 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
648
699
  }),
649
700
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
650
701
  type: "button",
651
- style: control$1,
652
702
  onClick: () => edit({
653
703
  ...draft,
654
704
  visibleModels: allModels.map((model) => model.id)
@@ -657,7 +707,6 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
657
707
  }),
658
708
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
659
709
  type: "button",
660
- style: control$1,
661
710
  onClick: () => edit({
662
711
  ...draft,
663
712
  visibleModels: []
@@ -705,7 +754,6 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
705
754
  children: [(model.efforts?.length ?? 0) > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
706
755
  style: actions$1,
707
756
  children: [t("modelDefaultsTitle"), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
708
- style: control$1,
709
757
  "aria-label": `${model.name} ${t("modelDefaultsTitle")}`,
710
758
  value: efforts[model.id] ?? "",
711
759
  onChange: (event) => {
@@ -741,10 +789,7 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
741
789
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
742
790
  style: actions$1,
743
791
  children: [t("modelsContext"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
744
- style: {
745
- ...control$1,
746
- width: 140
747
- },
792
+ style: { width: 140 },
748
793
  inputMode: "numeric",
749
794
  value: contexts[model.id] ?? "",
750
795
  "aria-label": `${model.name} ${t("modelsContext")}`,
@@ -798,28 +843,218 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
798
843
  });
799
844
  });
800
845
 
846
+ //#endregion
847
+ //#region src/client/provider-settings-styles.ts
848
+ /**
849
+ * The host loads one JS client bundle, so keep this small, scoped stylesheet
850
+ * with the dialog instead of relying on a separate CSS asset. Geometry and
851
+ * theme tokens follow the host's settings-form and ui-primitives controls.
852
+ *
853
+ * `color-scheme` is left to the host deliberately. Its boot script sets the
854
+ * property on `:root`, and it inherits, so native controls inside these panels
855
+ * follow the theme. Upstream also pins `color-scheme: light` here and flips it
856
+ * back under `body[data-ds-dark-theme]`; without that flip our scoped rules are
857
+ * more specific than `:root` and would force every native control light inside
858
+ * a dark theme.
859
+ */
860
+ const formScope = ":is(.dsh-subscription-manager, .dsh-subscriptions-settings)";
861
+ const providerSettingsCss = `
862
+ .dsh-subscription-manager {
863
+ box-sizing: border-box;
864
+ padding: 0;
865
+ border: 0;
866
+ border-radius: var(--dsw-radius-panel, 16px);
867
+ background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1));
868
+ color: var(--dsw-alias-label-primary);
869
+ box-shadow: var(--dsw-elevation-prominent, 0 20px 70px #0004);
870
+ font-family: inherit;
871
+ font-size: 13px;
872
+ line-height: 1.5;
873
+ }
874
+ .dsh-subscriptions-settings {
875
+ font-family: inherit;
876
+ font-size: 13px;
877
+ line-height: 1.5;
878
+ }
879
+ .dsh-subscription-manager::backdrop {
880
+ background: var(--dsw-alias-bg-mask-1, #0006);
881
+ backdrop-filter: var(--dsw-mask-blur, none);
882
+ }
883
+ ${formScope} h2 {
884
+ font-size: 16px;
885
+ line-height: 24px;
886
+ font-weight: 500;
887
+ }
888
+ ${formScope} h3 {
889
+ font-size: 14px;
890
+ line-height: 22px;
891
+ font-weight: 500;
892
+ }
893
+ ${formScope} strong,
894
+ ${formScope} .dsh-subscription-label {
895
+ font-size: 13px;
896
+ line-height: 1.5;
897
+ font-weight: 500;
898
+ }
899
+ ${formScope} legend {
900
+ font-size: 14px;
901
+ line-height: 22px;
902
+ font-weight: 500;
903
+ }
904
+ ${formScope} small,
905
+ ${formScope} .dsh-subscription-hint,
906
+ ${formScope} [role="status"] {
907
+ margin: 0;
908
+ font-size: 12px;
909
+ line-height: 1.5;
910
+ color: var(--dsw-alias-label-tertiary);
911
+ }
912
+ ${formScope} [role="alert"] {
913
+ margin: 0;
914
+ font-size: 12px;
915
+ line-height: 1.5;
916
+ color: var(--dsw-alias-state-error-primary, #b42318);
917
+ }
918
+ ${formScope} input:not([type="checkbox"]),
919
+ ${formScope} select {
920
+ box-sizing: border-box;
921
+ min-width: 0;
922
+ height: 34px;
923
+ padding: 0 12px;
924
+ border: 0.5px solid var(--dsw-alias-border-l4, var(--dsw-alias-border-l2));
925
+ border-radius: var(--dsw-radius-md, 8px);
926
+ background: var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-1));
927
+ color: var(--dsw-alias-label-primary);
928
+ font: inherit;
929
+ font-size: 13px;
930
+ font-weight: 400;
931
+ line-height: 1.5;
932
+ }
933
+ ${formScope} input::placeholder {
934
+ color: var(--dsw-alias-label-tertiary);
935
+ opacity: 1;
936
+ }
937
+ ${formScope} input:not([type="checkbox"]):focus-visible,
938
+ ${formScope} select:focus-visible {
939
+ outline: none;
940
+ border-color: var(--dsw-alias-state-business-primary, var(--dsw-alias-brand-primary));
941
+ }
942
+ ${formScope} input:not([type="checkbox"]):disabled,
943
+ ${formScope} select:disabled {
944
+ color: var(--dsw-alias-label-tertiary);
945
+ cursor: default;
946
+ }
947
+ ${formScope} input[aria-invalid="true"] {
948
+ border-color: var(--dsw-alias-state-error-primary, #b42318);
949
+ }
950
+ ${formScope} option {
951
+ background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1));
952
+ color: var(--dsw-alias-label-primary);
953
+ }
954
+ ${formScope} label:has(> input[type="checkbox"]) {
955
+ display: flex;
956
+ align-items: flex-start;
957
+ gap: 6px;
958
+ font-size: 14px;
959
+ line-height: 20px;
960
+ cursor: pointer;
961
+ }
962
+ ${formScope} input[type="checkbox"] {
963
+ flex: 0 0 auto;
964
+ width: 16px;
965
+ height: 16px;
966
+ margin: 2px 0;
967
+ accent-color: var(--dsw-alias-brand-primary);
968
+ cursor: inherit;
969
+ }
970
+ ${formScope} label:has(> input[type="checkbox"]:disabled) {
971
+ cursor: default;
972
+ opacity: 0.5;
973
+ }
974
+ ${formScope} button {
975
+ box-sizing: border-box;
976
+ display: inline-flex;
977
+ align-items: center;
978
+ justify-content: center;
979
+ flex-shrink: 0;
980
+ min-height: 28px;
981
+ padding: 0 10px;
982
+ border: 0.5px solid var(--dsw-alias-border-l3, var(--dsw-alias-border-l2));
983
+ border-radius: var(--dsw-radius-sm, 6px);
984
+ background: transparent;
985
+ color: var(--dsw-alias-label-primary);
986
+ font: inherit;
987
+ font-size: 12px;
988
+ line-height: 18px;
989
+ cursor: pointer;
990
+ }
991
+ ${formScope} button:hover:not(:disabled) {
992
+ background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-3));
993
+ }
994
+ ${formScope} button:active:not(:disabled) {
995
+ background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-bg-layer-3));
996
+ }
997
+ ${formScope} button:disabled {
998
+ opacity: 0.4;
999
+ cursor: default;
1000
+ }
1001
+ ${formScope} button.dsh-subscription-quiet {
1002
+ border-color: transparent;
1003
+ color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));
1004
+ }
1005
+ ${formScope} :is(footer, .dsh-subscription-dialog-actions) button {
1006
+ min-height: 34px;
1007
+ padding: 0 14px;
1008
+ border-radius: var(--dsw-radius-md, 8px);
1009
+ font-size: 13px;
1010
+ line-height: 1.5;
1011
+ }
1012
+ ${formScope} button.dsh-subscription-primary {
1013
+ border-color: transparent;
1014
+ background: var(--dsw-alias-button-primary-fill, var(--dsw-alias-label-primary));
1015
+ color: var(--dsw-alias-label-primary-foreground, var(--dsw-alias-bg-layer-1));
1016
+ font-weight: 500;
1017
+ }
1018
+ ${formScope} button.dsh-subscription-primary:hover:not(:disabled) {
1019
+ background: var(--dsw-alias-button-primary-hover, var(--dsw-alias-label-secondary));
1020
+ }
1021
+ ${formScope} button:focus-visible,
1022
+ ${formScope} input[type="checkbox"]:focus-visible,
1023
+ ${formScope} summary:focus-visible {
1024
+ outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
1025
+ outline-offset: 2px;
1026
+ }
1027
+ ${formScope} summary {
1028
+ border-radius: var(--dsw-radius-sm, 6px);
1029
+ }
1030
+ ${formScope} summary:hover {
1031
+ color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));
1032
+ }
1033
+ `;
1034
+ /** Composer controls retain their own geometry, separate from settings forms. */
1035
+ const subscriptionChromeCss = `
1036
+ .dsh-subscription-usage-pill { corner-shape: round; }
1037
+ .dsh-subscription-usage-panel {
1038
+ --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
1039
+ backdrop-filter: var(--dsw-menu-backdrop-filter, none);
1040
+ }
1041
+ .dsh-subscription-speed button:hover:not(:disabled) {
1042
+ --dsh-subscription-speed-hover: var(--dsw-alias-interactive-bg-hover);
1043
+ }
1044
+ .dsh-subscription-speed button:active:not(:disabled) {
1045
+ --dsh-subscription-speed-hover: var(--dsw-alias-interactive-bg-active);
1046
+ }
1047
+ .dsh-subscription-speed button:disabled { opacity: 0.4; cursor: default; }
1048
+ .dsh-subscription-speed button:focus-visible,
1049
+ .dsh-subscription-usage-pill:focus-visible {
1050
+ outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
1051
+ outline-offset: 2px;
1052
+ }
1053
+ `;
1054
+
801
1055
  //#endregion
802
1056
  //#region src/client/ProviderAccountManager.tsx
803
- const border = "1px solid var(--dsw-alias-border-l2)";
804
- const control = {
805
- font: "inherit",
806
- color: "inherit",
807
- background: "var(--dsw-alias-bg-layer-1)",
808
- border,
809
- borderRadius: 8,
810
- padding: "7px 12px",
811
- minWidth: 0
812
- };
813
- const button = {
814
- ...control,
815
- cursor: "pointer"
816
- };
817
- const hint = {
818
- margin: 0,
819
- fontSize: 12,
820
- lineHeight: 1.6,
821
- color: "var(--dsw-alias-label-tertiary)"
822
- };
1057
+ const border = "0.5px solid var(--dsw-alias-border-l2)";
823
1058
  const stack = {
824
1059
  display: "grid",
825
1060
  gap: 12,
@@ -924,7 +1159,8 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
924
1159
  if (alive.current) setSaving(false);
925
1160
  }
926
1161
  }
927
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dialog", {
1162
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dialog", {
1163
+ className: "dsh-subscription-manager",
928
1164
  ref: dialog,
929
1165
  "aria-labelledby": title,
930
1166
  "aria-describedby": description,
@@ -936,16 +1172,9 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
936
1172
  width: 620,
937
1173
  maxWidth: "calc(100vw - 32px)",
938
1174
  maxHeight: "calc(100dvh - 32px)",
939
- boxSizing: "border-box",
940
- padding: 0,
941
- border,
942
- borderRadius: 16,
943
- color: "var(--dsw-alias-label-primary)",
944
- background: "var(--dsw-alias-bg-layer-1)",
945
- boxShadow: "0 20px 70px #0004",
946
1175
  overflow: "auto"
947
1176
  },
948
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1177
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: providerSettingsCss }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
949
1178
  style: {
950
1179
  ...stack,
951
1180
  padding: 20
@@ -958,15 +1187,11 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
958
1187
  },
959
1188
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
960
1189
  id: title,
961
- style: {
962
- margin: 0,
963
- fontSize: 18
964
- },
1190
+ style: { margin: 0 },
965
1191
  children: t("accountsTitle", { provider: name })
966
1192
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
967
1193
  type: "button",
968
1194
  autoFocus: true,
969
- style: button,
970
1195
  disabled: saving,
971
1196
  onClick: onClose,
972
1197
  children: t("imageClose")
@@ -974,25 +1199,20 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
974
1199
  }),
975
1200
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
976
1201
  id: description,
977
- style: hint,
1202
+ className: "dsh-subscription-hint",
978
1203
  children: t(provider === "cursor-subscription" ? "cursorAccountsHint" : "accountsHint")
979
1204
  }),
980
1205
  error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
981
1206
  role: "alert",
982
- style: {
983
- ...hint,
984
- color: "var(--dsw-alias-state-error-primary)"
985
- },
986
1207
  children: error
987
1208
  }),
988
1209
  loading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
989
1210
  role: "status",
990
- style: hint,
1211
+ className: "dsh-subscription-hint",
991
1212
  children: t("accountsLoading")
992
1213
  }),
993
1214
  !loading && !catalog && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
994
1215
  type: "button",
995
- style: button,
996
1216
  onClick: () => setAttempt((value) => value + 1),
997
1217
  children: t("modelDefaultsRetry")
998
1218
  }),
@@ -1006,24 +1226,20 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1006
1226
  },
1007
1227
  children: [
1008
1228
  catalog.accounts.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1009
- style: hint,
1229
+ className: "dsh-subscription-hint",
1010
1230
  children: t(provider === "cursor-subscription" ? "cursorManageSignIn" : "accountsEmpty")
1011
1231
  }),
1012
1232
  provider === "cursor-subscription" && catalog.accounts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
1013
1233
  style: {
1014
1234
  border,
1015
- borderRadius: 12,
1235
+ borderRadius: "var(--dsw-radius-lg, 12px)",
1016
1236
  padding: 14
1017
1237
  },
1018
1238
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", {
1019
- style: {
1020
- padding: "0 6px",
1021
- fontWeight: 600,
1022
- fontSize: 14
1023
- },
1239
+ style: { padding: "0 6px" },
1024
1240
  children: name
1025
1241
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1026
- style: hint,
1242
+ className: "dsh-subscription-hint",
1027
1243
  children: t("cursorConnected")
1028
1244
  })]
1029
1245
  }),
@@ -1035,7 +1251,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1035
1251
  style: {
1036
1252
  ...stack,
1037
1253
  border,
1038
- borderRadius: 12,
1254
+ borderRadius: "var(--dsw-radius-lg, 12px)",
1039
1255
  padding: 14,
1040
1256
  margin: 0
1041
1257
  },
@@ -1043,15 +1259,13 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1043
1259
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", {
1044
1260
  style: {
1045
1261
  padding: "0 6px",
1046
- fontWeight: 600,
1047
- fontSize: 14,
1048
1262
  overflowWrap: "anywhere",
1049
1263
  maxWidth: "100%"
1050
1264
  },
1051
1265
  children: account.label
1052
1266
  }),
1053
1267
  account.unavailable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1054
- style: hint,
1268
+ className: "dsh-subscription-hint",
1055
1269
  children: t("accountsCatalogUnavailable")
1056
1270
  }),
1057
1271
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
@@ -1060,10 +1274,9 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1060
1274
  gap: 6
1061
1275
  },
1062
1276
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1063
- style: { fontSize: 12 },
1277
+ className: "dsh-subscription-label",
1064
1278
  children: t("accountsAlias")
1065
1279
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1066
- style: control,
1067
1280
  value: preferences.alias ?? "",
1068
1281
  placeholder: account.label,
1069
1282
  onChange: (event) => {
@@ -1099,7 +1312,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1099
1312
  t("accountsIndependent")
1100
1313
  ] }),
1101
1314
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1102
- style: hint,
1315
+ className: "dsh-subscription-hint",
1103
1316
  children: t("accountsIndependentHint")
1104
1317
  }),
1105
1318
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
@@ -1119,7 +1332,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1119
1332
  },
1120
1333
  children: [
1121
1334
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1122
- style: hint,
1335
+ className: "dsh-subscription-hint",
1123
1336
  children: t("accountsModelsHint")
1124
1337
  }),
1125
1338
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
@@ -1140,7 +1353,6 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1140
1353
  style: actions,
1141
1354
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1142
1355
  type: "button",
1143
- style: button,
1144
1356
  onClick: () => edit(account.key, {
1145
1357
  ...preferences,
1146
1358
  poolModels: models.map((model) => model.id)
@@ -1148,7 +1360,6 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1148
1360
  children: t("modelsSelectAll")
1149
1361
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1150
1362
  type: "button",
1151
- style: button,
1152
1363
  onClick: () => edit(account.key, {
1153
1364
  ...preferences,
1154
1365
  poolModels: []
@@ -1164,10 +1375,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1164
1375
  overflowY: "auto"
1165
1376
  },
1166
1377
  children: [models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1167
- style: {
1168
- fontSize: 13,
1169
- overflowWrap: "anywhere"
1170
- },
1378
+ style: { overflowWrap: "anywhere" },
1171
1379
  children: [
1172
1380
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1173
1381
  type: "checkbox",
@@ -1187,7 +1395,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1187
1395
  model.unavailable && ` (${t("modelsUnavailable")})`
1188
1396
  ]
1189
1397
  }, model.id)), models.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1190
- style: hint,
1398
+ className: "dsh-subscription-hint",
1191
1399
  children: t("accountsNoModels")
1192
1400
  })]
1193
1401
  })
@@ -1211,17 +1419,13 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1211
1419
  ...stack,
1212
1420
  gap: 8,
1213
1421
  borderTop: border,
1214
- padding: "14px 0 0",
1422
+ padding: "14px 0 8px",
1215
1423
  position: "sticky",
1216
1424
  bottom: 0,
1217
- background: "var(--dsw-alias-bg-layer-1)"
1425
+ background: "var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1))"
1218
1426
  },
1219
1427
  children: [saveError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1220
1428
  role: "alert",
1221
- style: {
1222
- ...hint,
1223
- color: "var(--dsw-alias-state-error-primary)"
1224
- },
1225
1429
  children: saveError
1226
1430
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1227
1431
  style: {
@@ -1230,16 +1434,12 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1230
1434
  },
1231
1435
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1232
1436
  type: "button",
1233
- style: button,
1234
1437
  disabled: saving,
1235
1438
  onClick: onClose,
1236
1439
  children: t("cancel")
1237
1440
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1238
1441
  type: "button",
1239
- style: {
1240
- ...button,
1241
- fontWeight: 600
1242
- },
1442
+ className: "dsh-subscription-primary",
1243
1443
  disabled: loading || saving || !Object.keys(changes).length && !modelsDirty,
1244
1444
  onClick: () => {
1245
1445
  save();
@@ -1249,7 +1449,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1249
1449
  })]
1250
1450
  })
1251
1451
  ]
1252
- })
1452
+ })]
1253
1453
  });
1254
1454
  }
1255
1455
 
@@ -2064,6 +2264,216 @@ function CursorCard({ rpc, t }) {
2064
2264
  });
2065
2265
  }
2066
2266
 
2267
+ //#endregion
2268
+ //#region src/client/reset-credits-view.tsx
2269
+ const STATE_KEYS = {
2270
+ available: "resetCreditAvailable",
2271
+ notUsable: "resetCreditNotUsable",
2272
+ paused: "resetCreditPaused",
2273
+ exhausted: "resetCreditExhausted",
2274
+ expired: "resetCreditExpired"
2275
+ };
2276
+ /**
2277
+ * Classify one grant. Expired outranks every other flag. A future
2278
+ * `cooldownUntil` or `usableNow: false` is not usable even when `claimable`
2279
+ * is true. `claimable` does not change the word: it is not an action.
2280
+ */
2281
+ function resetCreditState(credit, now) {
2282
+ if (credit.expiresAt !== void 0 && credit.expiresAt <= now) return "expired";
2283
+ if (credit.paused === true) return "paused";
2284
+ if (credit.resetsLeft === 0) return "exhausted";
2285
+ if (credit.cooldownUntil !== void 0 && credit.cooldownUntil > now || credit.usableNow === false) return "notUsable";
2286
+ return "available";
2287
+ }
2288
+ /**
2289
+ * Headline count. Codex passes one entry per credit, so the count is the
2290
+ * list length. Claude passes one entry per grant, so the count is the sum of
2291
+ * `resetsLeft` on grants that are neither expired nor paused. A missing
2292
+ * `resetsLeft` adds nothing; the row says the count is unavailable.
2293
+ */
2294
+ function resetCreditsAvailableCount(credits, now, mode) {
2295
+ if (mode === "credits") return credits.length;
2296
+ let sum = 0;
2297
+ for (const credit of credits) {
2298
+ const state = resetCreditState(credit, now);
2299
+ if (state === "expired" || state === "paused") continue;
2300
+ if (typeof credit.resetsLeft === "number" && Number.isFinite(credit.resetsLeft) && credit.resetsLeft > 0) sum += credit.resetsLeft;
2301
+ }
2302
+ return sum;
2303
+ }
2304
+ function expiryText(t, credit) {
2305
+ return credit.expiresAt === void 0 ? t("resetCreditExpiryUnknown") : t("resetCreditExpires", { date: new Date(credit.expiresAt).toLocaleString() });
2306
+ }
2307
+ function remainingText(t, credit) {
2308
+ const left = credit.resetsLeft;
2309
+ const total = credit.resetsTotal;
2310
+ const hasLeft = typeof left === "number" && Number.isFinite(left);
2311
+ if (hasLeft && typeof total === "number" && Number.isFinite(total)) return t("resetCreditRemaining", {
2312
+ left,
2313
+ total
2314
+ });
2315
+ if (hasLeft) return t("resetCreditLeft", { left });
2316
+ return t("resetCreditRemainingUnknown");
2317
+ }
2318
+ /** Accessible name of one Claude grant row: state, remaining, and expiry, not a control name. */
2319
+ function resetCreditRowName(t, credit, now) {
2320
+ const state = resetCreditState(credit, now);
2321
+ const parts = [
2322
+ t("resetCreditFull"),
2323
+ t(STATE_KEYS[state]),
2324
+ remainingText(t, credit),
2325
+ expiryText(t, credit)
2326
+ ];
2327
+ if (state === "notUsable" && credit.cooldownUntil !== void 0 && credit.cooldownUntil > now) parts.push(t("resetCreditCooldownUntil", { date: new Date(credit.cooldownUntil).toLocaleString() }));
2328
+ return parts.join(", ");
2329
+ }
2330
+ /** Claude omits an empty grant list; Codex still shows a defined, possibly empty, list. */
2331
+ function showsResetCredits(provider, credits) {
2332
+ if (provider === "codex") return credits !== void 0;
2333
+ return (credits?.length ?? 0) > 0;
2334
+ }
2335
+ /** The error line the settings card mounts. Claude never interpolates provider text. */
2336
+ function ResetCreditsErrorLine({ provider, message: message$1, t }) {
2337
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2338
+ style: subscriptionCardStyles.error,
2339
+ children: resetCreditsErrorText(provider, message$1, t)
2340
+ });
2341
+ }
2342
+ /** Fixed sentence for Claude. Codex may include the lookup message; Claude must not. */
2343
+ function resetCreditsErrorText(provider, message$1, t) {
2344
+ return provider === "claude" ? t("resetCreditsErrorFixed") : t("resetCreditsError", { message: message$1 });
2345
+ }
2346
+ const summaryStyle = {
2347
+ ...subscriptionCardStyles.usageMeta,
2348
+ cursor: "pointer",
2349
+ listStyle: "none",
2350
+ justifyContent: "flex-start",
2351
+ gap: 6
2352
+ };
2353
+ /**
2354
+ * The closed disclosure both providers share. Claude rows are plain text:
2355
+ * no button, no `role="button"`, and `cursor: default`, including when
2356
+ * `claimable` is true.
2357
+ */
2358
+ function ResetCreditsDisclosure({ mode, credits, t, now = Date.now(), nextCredit, useAction, statusMessage }) {
2359
+ const count = resetCreditsAvailableCount(credits, now, mode);
2360
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
2361
+ className: "subscriptions-reset-credits",
2362
+ style: subscriptionCardStyles.usageRow,
2363
+ children: [
2364
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
2365
+ style: summaryStyle,
2366
+ children: [
2367
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
2368
+ "aria-hidden": "true",
2369
+ width: "12",
2370
+ height: "12",
2371
+ viewBox: "0 0 16 16",
2372
+ style: { flexShrink: 0 },
2373
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
2374
+ d: "m6 3 5 5-5 5",
2375
+ fill: "none",
2376
+ stroke: "currentColor",
2377
+ strokeWidth: "1.5",
2378
+ strokeLinecap: "round",
2379
+ strokeLinejoin: "round"
2380
+ })
2381
+ }),
2382
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetCreditsTitle") }),
2383
+ mode === "grants" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetCreditReadOnlyLabel") }),
2384
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2385
+ style: { marginLeft: "auto" },
2386
+ children: t("resetCreditsAvailable", { count })
2387
+ })
2388
+ ]
2389
+ }),
2390
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: ".subscriptions-reset-credits > summary::-webkit-details-marker { display: none; }.subscriptions-reset-credits[open] > summary > svg { transform: rotate(90deg); }" }),
2391
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2392
+ style: {
2393
+ paddingLeft: 18,
2394
+ marginTop: 6
2395
+ },
2396
+ children: [
2397
+ mode === "grants" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2398
+ style: subscriptionCardStyles.status,
2399
+ children: t("resetCreditReadOnly")
2400
+ }),
2401
+ credits.map((credit, index) => {
2402
+ const state = resetCreditState(credit, now);
2403
+ const showUse = mode === "credits" && useAction !== void 0 && credit === nextCredit;
2404
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2405
+ "data-reset-state": mode === "grants" ? state : void 0,
2406
+ "data-reset-claimable": mode === "grants" && credit.claimable === true ? "true" : void 0,
2407
+ role: mode === "grants" ? "group" : void 0,
2408
+ "aria-label": mode === "grants" ? resetCreditRowName(t, credit, now) : void 0,
2409
+ style: {
2410
+ ...subscriptionCardStyles.usageMeta,
2411
+ minHeight: 28,
2412
+ gap: 12,
2413
+ cursor: mode === "grants" ? "default" : void 0
2414
+ },
2415
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2416
+ style: {
2417
+ display: "inline-flex",
2418
+ alignItems: "center",
2419
+ gap: 8,
2420
+ flexShrink: 0
2421
+ },
2422
+ children: [
2423
+ t("resetCreditFull"),
2424
+ mode === "grants" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2425
+ "aria-hidden": "true",
2426
+ "data-reset-state-word": state,
2427
+ children: t(STATE_KEYS[state])
2428
+ }),
2429
+ showUse && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2430
+ type: "button",
2431
+ "aria-disabled": useAction.disabled,
2432
+ title: useAction.title,
2433
+ style: {
2434
+ minHeight: 22,
2435
+ height: 22,
2436
+ padding: "0 7px",
2437
+ borderRadius: 6,
2438
+ opacity: useAction.disabled ? .35 : 1,
2439
+ cursor: useAction.disabled ? "not-allowed" : "pointer"
2440
+ },
2441
+ onClick: () => {
2442
+ if (!useAction.disabled) useAction.onUse();
2443
+ },
2444
+ children: useAction.busy ? t("resetUseChecking") : useAction.label
2445
+ })
2446
+ ]
2447
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2448
+ style: { textAlign: "right" },
2449
+ children: [
2450
+ mode === "grants" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2451
+ "aria-hidden": "true",
2452
+ children: [remainingText(t, credit), " · "]
2453
+ }),
2454
+ mode === "grants" && state === "notUsable" && credit.cooldownUntil !== void 0 && credit.cooldownUntil > now && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2455
+ "aria-hidden": "true",
2456
+ children: [t("resetCreditCooldownUntil", { date: new Date(credit.cooldownUntil).toLocaleString() }), " · "]
2457
+ }),
2458
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2459
+ "aria-hidden": mode === "grants" ? true : void 0,
2460
+ children: expiryText(t, credit)
2461
+ })
2462
+ ]
2463
+ })]
2464
+ }, credit.id ?? index);
2465
+ }),
2466
+ statusMessage !== void 0 && statusMessage !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2467
+ role: "status",
2468
+ style: subscriptionCardStyles.status,
2469
+ children: statusMessage
2470
+ })
2471
+ ]
2472
+ })
2473
+ ]
2474
+ });
2475
+ }
2476
+
2067
2477
  //#endregion
2068
2478
  //#region src/client/UsageBadgeDisplaySetting.tsx
2069
2479
  /** Browser-local display preference; never changes provider or account settings. */
@@ -2161,8 +2571,9 @@ function UsageBadgeDisplaySetting({ t }) {
2161
2571
  }
2162
2572
  const styles$6 = {
2163
2573
  card: {
2164
- border: "1px solid var(--dsw-alias-border-l2)",
2165
- borderRadius: 12,
2574
+ border: "0.5px solid var(--dsw-alias-settings-card-stroke, var(--dsw-alias-border-l4))",
2575
+ borderRadius: "var(--dsw-radius-xl, 20px)",
2576
+ background: "var(--dsw-alias-settings-card-fill, var(--dsw-alias-bg-layer-2))",
2166
2577
  padding: "12px 14px",
2167
2578
  display: "flex",
2168
2579
  flexDirection: "column",
@@ -2171,21 +2582,12 @@ const styles$6 = {
2171
2582
  field: {
2172
2583
  display: "flex",
2173
2584
  flexDirection: "column",
2174
- gap: 4,
2175
- fontSize: 14,
2176
- lineHeight: "22px"
2177
- },
2178
- select: {
2179
- height: 32,
2180
- width: "100%",
2181
- boxSizing: "border-box",
2182
- border: "1px solid var(--dsw-alias-border-l2)",
2183
- borderRadius: 8,
2184
- padding: "0 10px",
2185
- font: "inherit",
2186
- background: "var(--dsw-alias-bg-layer-1)",
2187
- color: "var(--dsw-alias-label-primary)"
2585
+ gap: 6,
2586
+ fontSize: 13,
2587
+ fontWeight: 500,
2588
+ lineHeight: "20px"
2188
2589
  },
2590
+ select: { width: "100%" },
2189
2591
  hint: {
2190
2592
  margin: 0,
2191
2593
  fontSize: 12,
@@ -2265,7 +2667,12 @@ const styles$5 = {
2265
2667
  fontSize: 14,
2266
2668
  lineHeight: "22px"
2267
2669
  },
2268
- card: subscriptionCardStyles.card,
2670
+ card: {
2671
+ ...subscriptionCardStyles.card,
2672
+ border: "0.5px solid var(--dsw-alias-settings-card-stroke, var(--dsw-alias-border-l4))",
2673
+ borderRadius: "var(--dsw-radius-xl, 20px)",
2674
+ background: "var(--dsw-alias-settings-card-fill, var(--dsw-alias-bg-layer-2))"
2675
+ },
2269
2676
  cardHeader: subscriptionCardStyles.header,
2270
2677
  dot: subscriptionCardStyles.dot,
2271
2678
  name: subscriptionCardStyles.name,
@@ -2278,21 +2685,32 @@ const styles$5 = {
2278
2685
  },
2279
2686
  errorLine: subscriptionCardStyles.error,
2280
2687
  actions: subscriptionCardStyles.actions,
2281
- button: subscriptionCardStyles.button,
2282
- usage: subscriptionCardStyles.usage,
2688
+ usage: {
2689
+ ...subscriptionCardStyles.usage,
2690
+ borderTop: "0.5px solid var(--dsw-alias-border-l2)"
2691
+ },
2283
2692
  usageHeader: subscriptionCardStyles.usageHeader,
2284
2693
  usageTitle: subscriptionCardStyles.usageTitle,
2285
2694
  usagePlan: subscriptionCardStyles.usagePlan,
2286
- usageRefresh: subscriptionCardStyles.usageRefresh,
2695
+ usageRefresh: {
2696
+ minHeight: 22,
2697
+ height: 22,
2698
+ padding: "0 8px",
2699
+ marginLeft: "auto"
2700
+ },
2287
2701
  usageRow: subscriptionCardStyles.usageRow,
2288
2702
  usageMeta: subscriptionCardStyles.usageMeta,
2289
- accountRow: subscriptionCardStyles.account,
2703
+ accountRow: {
2704
+ ...subscriptionCardStyles.account,
2705
+ border: "0.5px solid var(--dsw-alias-border-l2)",
2706
+ borderRadius: "var(--dsw-radius-lg, 16px)"
2707
+ },
2290
2708
  accountHeader: subscriptionCardStyles.accountHeader,
2291
2709
  accountName: subscriptionCardStyles.accountName,
2292
2710
  starButton: {
2293
2711
  border: "none",
2294
- background: "transparent",
2295
2712
  padding: 0,
2713
+ width: 28,
2296
2714
  font: "inherit",
2297
2715
  fontSize: 14,
2298
2716
  lineHeight: "20px",
@@ -2304,8 +2722,8 @@ const styles$5 = {
2304
2722
  display: "flex",
2305
2723
  flexDirection: "column",
2306
2724
  gap: 6,
2307
- border: "1px solid var(--dsw-alias-border-l2)",
2308
- borderRadius: 8,
2725
+ border: "0.5px solid var(--dsw-alias-border-l2)",
2726
+ borderRadius: "var(--dsw-radius-lg, 16px)",
2309
2727
  padding: "10px 12px",
2310
2728
  background: "var(--dsw-alias-bg-layer-1)"
2311
2729
  },
@@ -2317,6 +2735,21 @@ const styles$5 = {
2317
2735
  color: "var(--dsw-alias-label-primary)",
2318
2736
  userSelect: "all"
2319
2737
  },
2738
+ manual: {
2739
+ fontSize: 13,
2740
+ lineHeight: "20px"
2741
+ },
2742
+ manualRow: {
2743
+ display: "flex",
2744
+ flexWrap: "wrap",
2745
+ gap: 8,
2746
+ alignItems: "center",
2747
+ marginTop: 8
2748
+ },
2749
+ manualInput: {
2750
+ flex: "1 1 200px",
2751
+ minWidth: 0
2752
+ },
2320
2753
  modalOverlay: {
2321
2754
  position: "fixed",
2322
2755
  inset: 0,
@@ -2325,7 +2758,8 @@ const styles$5 = {
2325
2758
  alignItems: "center",
2326
2759
  justifyContent: "center",
2327
2760
  padding: 16,
2328
- background: "rgba(0, 0, 0, 0.45)"
2761
+ background: "var(--dsw-alias-bg-mask-1, #0006)",
2762
+ backdropFilter: "var(--dsw-mask-blur, none)"
2329
2763
  },
2330
2764
  modal: {
2331
2765
  width: 460,
@@ -2337,9 +2771,10 @@ const styles$5 = {
2337
2771
  flexDirection: "column",
2338
2772
  gap: 12,
2339
2773
  padding: "16px 18px",
2340
- borderRadius: 12,
2341
- background: "var(--dsw-alias-bg-layer-1)",
2342
- border: "1px solid var(--dsw-alias-border-l2)"
2774
+ borderRadius: "var(--dsw-radius-panel, 28px)",
2775
+ background: "var(--dsw-alias-bg-layer-2)",
2776
+ border: 0,
2777
+ boxShadow: "var(--dsw-elevation-prominent)"
2343
2778
  },
2344
2779
  modalHeader: {
2345
2780
  display: "flex",
@@ -2347,9 +2782,9 @@ const styles$5 = {
2347
2782
  gap: 8
2348
2783
  },
2349
2784
  modalTitle: {
2350
- fontWeight: 600,
2351
- fontSize: 15,
2352
- lineHeight: "22px",
2785
+ fontWeight: 500,
2786
+ fontSize: 16,
2787
+ lineHeight: "24px",
2353
2788
  color: "var(--dsw-alias-label-primary)"
2354
2789
  }
2355
2790
  };
@@ -2419,10 +2854,22 @@ function SubscriptionsSection(props) {
2419
2854
  const [observedAt, setObservedAt] = (0, react.useState)({});
2420
2855
  const [usageErrors, setUsageErrors] = (0, react.useState)({});
2421
2856
  const [usageLoading, setUsageLoading] = (0, react.useState)({});
2857
+ const [resetConfirmation, setResetConfirmation] = (0, react.useState)();
2858
+ const [resetBusy, setResetBusy] = (0, react.useState)(false);
2859
+ const [resetAcknowledged, setResetAcknowledged] = (0, react.useState)(false);
2860
+ const [resetMessage, setResetMessage] = (0, react.useState)("");
2861
+ const [resetAccount, setResetAccount] = (0, react.useState)();
2862
+ const resetDialogRef = (0, react.useRef)(null);
2863
+ (0, react.useEffect)(() => {
2864
+ if (resetConfirmation) resetDialogRef.current?.showModal();
2865
+ else resetDialogRef.current?.close();
2866
+ }, [resetConfirmation]);
2867
+ const resetInflight = (0, react.useRef)(false);
2422
2868
  const mountedRef = (0, react.useRef)(true);
2423
2869
  const pollersRef = (0, react.useRef)(/* @__PURE__ */ new Map());
2424
2870
  /** Accounts with a `usage` call in flight; guards the auto-fetch effect against re-entry. */
2425
- const usageInflightRef = (0, react.useRef)(/* @__PURE__ */ new Set());
2871
+ /** In-flight usage reads per key, holding the promise so a forced read can wait one out. */
2872
+ const usageInflightRef = (0, react.useRef)(/* @__PURE__ */ new Map());
2426
2873
  const usageRosterSignatureRef = (0, react.useRef)();
2427
2874
  const [managedProvider, setManagedProvider] = (0, react.useState)();
2428
2875
  const setProviderError = (0, react.useCallback)((provider, message$1) => {
@@ -2499,47 +2946,97 @@ function SubscriptionsSection(props) {
2499
2946
  };
2500
2947
  }, [refresh, startPolling]);
2501
2948
  const loadUsage = (0, react.useCallback)(async (provider, account, force = false) => {
2949
+ if (rpc === void 0) return;
2502
2950
  const key = `${provider}:${account}`;
2951
+ const pending = usageInflightRef.current.get(key);
2952
+ if (pending !== void 0) {
2953
+ if (!force) return;
2954
+ await pending;
2955
+ }
2503
2956
  if (rpc === void 0 || usageInflightRef.current.has(key)) return;
2504
- usageInflightRef.current.add(key);
2505
- setUsageLoading((prev) => ({
2506
- ...prev,
2507
- [key]: true
2508
- }));
2509
- try {
2510
- const usage = await callSubscriptionsAuth(rpc, "usage", {
2511
- provider,
2512
- account,
2513
- ...force ? { force: true } : {}
2514
- });
2515
- if (!mountedRef.current) return;
2516
- setUsages((prev) => ({
2957
+ const read = (async () => {
2958
+ setUsageLoading((prev) => ({
2517
2959
  ...prev,
2518
- [key]: usage
2960
+ [key]: true
2519
2961
  }));
2520
- setObservedAt((prev) => ({
2521
- ...prev,
2522
- [key]: usage.observedAt ?? Date.now()
2523
- }));
2524
- window.dispatchEvent(new Event(USAGE_BADGE_REFRESH_EVENT));
2525
- setUsageErrors((prev) => {
2526
- const next = { ...prev };
2527
- delete next[key];
2528
- return next;
2962
+ try {
2963
+ const usage = await callSubscriptionsAuth(rpc, "usage", {
2964
+ provider,
2965
+ account,
2966
+ ...force ? { force: true } : {}
2967
+ });
2968
+ if (!mountedRef.current) return;
2969
+ setUsages((prev) => ({
2970
+ ...prev,
2971
+ [key]: usage
2972
+ }));
2973
+ setObservedAt((prev) => ({
2974
+ ...prev,
2975
+ [key]: usage.observedAt ?? Date.now()
2976
+ }));
2977
+ window.dispatchEvent(new Event(USAGE_BADGE_REFRESH_EVENT));
2978
+ setUsageErrors((prev) => {
2979
+ const next = { ...prev };
2980
+ delete next[key];
2981
+ return next;
2982
+ });
2983
+ } catch (error) {
2984
+ if (mountedRef.current) setUsageErrors((prev) => ({
2985
+ ...prev,
2986
+ [key]: messageOf(error)
2987
+ }));
2988
+ } finally {
2989
+ usageInflightRef.current.delete(key);
2990
+ if (mountedRef.current) setUsageLoading((prev) => ({
2991
+ ...prev,
2992
+ [key]: false
2993
+ }));
2994
+ }
2995
+ })();
2996
+ usageInflightRef.current.set(key, read);
2997
+ await read;
2998
+ }, [rpc]);
2999
+ async function prepareReset(account) {
3000
+ if (!rpc || resetInflight.current) return;
3001
+ resetInflight.current = true;
3002
+ setResetBusy(true);
3003
+ setResetAccount(account);
3004
+ setResetConfirmation(void 0);
3005
+ setResetMessage("");
3006
+ try {
3007
+ const result = await callSubscriptionsAuth(rpc, "prepareReset", { account });
3008
+ setResetAcknowledged(false);
3009
+ setResetConfirmation({
3010
+ ...result,
3011
+ account
2529
3012
  });
2530
3013
  } catch (error) {
2531
- if (mountedRef.current) setUsageErrors((prev) => ({
2532
- ...prev,
2533
- [key]: messageOf(error)
2534
- }));
3014
+ setResetMessage(messageOf(error));
2535
3015
  } finally {
2536
- usageInflightRef.current.delete(key);
2537
- if (mountedRef.current) setUsageLoading((prev) => ({
2538
- ...prev,
2539
- [key]: false
2540
- }));
3016
+ resetInflight.current = false;
3017
+ setResetBusy(false);
2541
3018
  }
2542
- }, [rpc]);
3019
+ }
3020
+ async function consumeReset() {
3021
+ if (!rpc || !resetConfirmation || !resetAcknowledged || resetInflight.current) return;
3022
+ const { account, ticket } = resetConfirmation;
3023
+ resetInflight.current = true;
3024
+ setResetBusy(true);
3025
+ setResetConfirmation(void 0);
3026
+ try {
3027
+ await callSubscriptionsAuth(rpc, "consumeReset", {
3028
+ account,
3029
+ ticket
3030
+ });
3031
+ setResetMessage(t("resetUseSuccess"));
3032
+ } catch (error) {
3033
+ setResetMessage(messageOf(error));
3034
+ } finally {
3035
+ await loadUsage("codex", account, true);
3036
+ resetInflight.current = false;
3037
+ setResetBusy(false);
3038
+ }
3039
+ }
2543
3040
  (0, react.useEffect)(() => {
2544
3041
  const live = /* @__PURE__ */ new Set();
2545
3042
  for (const { id } of PROVIDERS) for (const account of statuses[id]?.accounts ?? []) {
@@ -2687,8 +3184,10 @@ function SubscriptionsSection(props) {
2687
3184
  children: t("unavailable")
2688
3185
  });
2689
3186
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3187
+ className: "dsh-subscriptions-settings",
2690
3188
  style: styles$5.section,
2691
3189
  children: [
3190
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: providerSettingsCss }),
2692
3191
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2693
3192
  style: styles$5.intro,
2694
3193
  children: t("intro")
@@ -2737,6 +3236,10 @@ function SubscriptionsSection(props) {
2737
3236
  const usage = usages[usageKey];
2738
3237
  const usageError = usageErrors[usageKey];
2739
3238
  const display = account.account ?? account.key;
3239
+ const sortedCredits = [...usage?.resetCredits ?? []].sort((a, b) => (a.expiresAt ?? Infinity) - (b.expiresAt ?? Infinity));
3240
+ const nextReset = sortedCredits.find((c) => c.expiresAt === void 0 || c.expiresAt > Date.now());
3241
+ const resetBlock = usage ? resetActionBlock(usage) : "resetUseRefresh";
3242
+ const resetDisabled = resetBusy || resetBlock !== void 0;
2740
3243
  const showUsage = usage?.supported !== false && (usage !== void 0 || usageError !== void 0 || usageLoading[usageKey] === true);
2741
3244
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2742
3245
  style: styles$5.accountRow,
@@ -2767,7 +3270,6 @@ function SubscriptionsSection(props) {
2767
3270
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2768
3271
  type: "button",
2769
3272
  style: {
2770
- ...styles$5.button,
2771
3273
  marginLeft: "auto",
2772
3274
  flexShrink: 0
2773
3275
  },
@@ -2793,13 +3295,7 @@ function SubscriptionsSection(props) {
2793
3295
  }),
2794
3296
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2795
3297
  type: "button",
2796
- style: {
2797
- ...styles$5.usageRefresh,
2798
- ...usageLoading[usageKey] === true ? {
2799
- opacity: .5,
2800
- cursor: "default"
2801
- } : {}
2802
- },
3298
+ style: styles$5.usageRefresh,
2803
3299
  disabled: usageLoading[usageKey] === true,
2804
3300
  onClick: () => {
2805
3301
  loadUsage(id, account.key, true);
@@ -2834,6 +3330,28 @@ function SubscriptionsSection(props) {
2834
3330
  stale: usageError !== void 0 || usage.stale === true
2835
3331
  })]
2836
3332
  }, index);
3333
+ }),
3334
+ (id === "codex" || id === "claude") && usage?.resetCreditsError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditsErrorLine, {
3335
+ provider: id,
3336
+ message: usage.resetCreditsError,
3337
+ t
3338
+ }),
3339
+ (id === "codex" || id === "claude") && showsResetCredits(id, usage?.resetCredits) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditsDisclosure, {
3340
+ mode: id === "claude" ? "grants" : "credits",
3341
+ credits: sortedCredits,
3342
+ t,
3343
+ ...nextReset !== void 0 ? { nextCredit: nextReset } : {},
3344
+ ...id === "codex" ? { useAction: {
3345
+ accountKey: account.key,
3346
+ busy: resetBusy && resetAccount === account.key,
3347
+ disabled: resetDisabled,
3348
+ title: t(resetBusy ? "resetUseChecking" : resetBlock ?? "resetUseReady"),
3349
+ label: t("resetUseButton"),
3350
+ onUse: () => {
3351
+ if (!resetDisabled) prepareReset(account.key);
3352
+ }
3353
+ } } : {},
3354
+ ...resetAccount === account.key && resetMessage !== "" ? { statusMessage: resetMessage } : {}
2837
3355
  })
2838
3356
  ]
2839
3357
  })]
@@ -2844,7 +3362,6 @@ function SubscriptionsSection(props) {
2844
3362
  children: [
2845
3363
  !busy && accounts.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2846
3364
  type: "button",
2847
- style: styles$5.button,
2848
3365
  onClick: () => {
2849
3366
  login(id);
2850
3367
  },
@@ -2852,14 +3369,12 @@ function SubscriptionsSection(props) {
2852
3369
  }),
2853
3370
  !busy && accounts.length > 0 && id === "claude" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2854
3371
  type: "button",
2855
- style: styles$5.button,
2856
3372
  onClick: () => {
2857
3373
  login(id, "oauth");
2858
3374
  },
2859
3375
  children: t("addAccountOAuth")
2860
3376
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2861
3377
  type: "button",
2862
- style: styles$5.button,
2863
3378
  onClick: () => {
2864
3379
  login(id, "keychain");
2865
3380
  },
@@ -2867,7 +3382,6 @@ function SubscriptionsSection(props) {
2867
3382
  })] }),
2868
3383
  !busy && accounts.length > 0 && id !== "claude" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2869
3384
  type: "button",
2870
- style: styles$5.button,
2871
3385
  onClick: () => {
2872
3386
  login(id);
2873
3387
  },
@@ -2875,7 +3389,6 @@ function SubscriptionsSection(props) {
2875
3389
  }),
2876
3390
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2877
3391
  type: "button",
2878
- style: styles$5.button,
2879
3392
  "aria-haspopup": "dialog",
2880
3393
  onClick: () => setManagedProvider({
2881
3394
  id,
@@ -2885,7 +3398,6 @@ function SubscriptionsSection(props) {
2885
3398
  }),
2886
3399
  busy && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2887
3400
  type: "button",
2888
- style: styles$5.button,
2889
3401
  onClick: () => {
2890
3402
  cancel(id);
2891
3403
  },
@@ -2912,14 +3424,12 @@ function SubscriptionsSection(props) {
2912
3424
  style: styles$5.actions,
2913
3425
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2914
3426
  type: "button",
2915
- style: styles$5.button,
2916
3427
  onClick: () => {
2917
3428
  copyDeviceCode(id, deviceCode.userCode);
2918
3429
  },
2919
3430
  children: copiedCode === id ? t("deviceCodeCopied") : t("deviceCodeCopy")
2920
3431
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2921
3432
  type: "button",
2922
- style: styles$5.button,
2923
3433
  onClick: () => {
2924
3434
  window.open(deviceCode.verificationUrl, "_blank", "noopener");
2925
3435
  },
@@ -2942,7 +3452,6 @@ function SubscriptionsSection(props) {
2942
3452
  }))
2943
3453
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2944
3454
  type: "button",
2945
- style: styles$5.button,
2946
3455
  onClick: () => {
2947
3456
  submitManual(id);
2948
3457
  },
@@ -2967,6 +3476,90 @@ function SubscriptionsSection(props) {
2967
3476
  rpc,
2968
3477
  t,
2969
3478
  onClose: () => setManagedProvider(void 0)
3479
+ }),
3480
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: ".subscriptions-reset-dialog::backdrop { background: var(--dsw-alias-bg-mask-1, #0006); backdrop-filter: var(--dsw-mask-blur, none); }" }),
3481
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dialog", {
3482
+ ref: resetDialogRef,
3483
+ className: "subscriptions-reset-dialog",
3484
+ "aria-labelledby": "subscriptions-reset-title",
3485
+ onCancel: () => setResetConfirmation(void 0),
3486
+ onClose: () => setResetConfirmation(void 0),
3487
+ style: {
3488
+ ...styles$5.modal,
3489
+ display: resetConfirmation ? "flex" : "none",
3490
+ margin: "auto",
3491
+ color: "var(--dsw-alias-label-primary)"
3492
+ },
3493
+ children: resetConfirmation && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3494
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
3495
+ id: "subscriptions-reset-title",
3496
+ style: {
3497
+ ...styles$5.modalTitle,
3498
+ margin: 0
3499
+ },
3500
+ children: t("resetUseConfirmTitle")
3501
+ }),
3502
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3503
+ style: {
3504
+ ...styles$5.statusLine,
3505
+ overflowWrap: "anywhere"
3506
+ },
3507
+ children: statuses.codex?.accounts.find((a) => a.key === resetConfirmation.account)?.account ?? resetConfirmation.account
3508
+ }),
3509
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3510
+ style: {
3511
+ ...styles$5.usageMeta,
3512
+ gap: 12
3513
+ },
3514
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageWeekly") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: [Math.round(resetConfirmation.weeklyUsedPercent), "%"] })]
3515
+ }),
3516
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3517
+ style: styles$5.usageMeta,
3518
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: resetConfirmation.creditExpiresAt === void 0 ? t("resetCreditExpiryUnknown") : t("resetCreditExpires", { date: new Date(resetConfirmation.creditExpiresAt).toLocaleString() }) })
3519
+ }),
3520
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3521
+ style: {
3522
+ ...styles$5.statusLine,
3523
+ margin: "4px 0"
3524
+ },
3525
+ children: t("resetUseWarning")
3526
+ }),
3527
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3528
+ style: {
3529
+ display: "flex",
3530
+ gap: 8,
3531
+ alignItems: "flex-start",
3532
+ fontSize: 12
3533
+ },
3534
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3535
+ type: "checkbox",
3536
+ checked: resetAcknowledged,
3537
+ onChange: (e) => setResetAcknowledged(e.target.checked)
3538
+ }), t("resetUseAcknowledge")]
3539
+ }),
3540
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3541
+ className: "dsh-subscription-dialog-actions",
3542
+ style: {
3543
+ ...styles$5.actions,
3544
+ justifyContent: "flex-end",
3545
+ marginTop: 8
3546
+ },
3547
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3548
+ type: "button",
3549
+ autoFocus: true,
3550
+ onClick: () => setResetConfirmation(void 0),
3551
+ children: t("cancel")
3552
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3553
+ type: "button",
3554
+ className: "dsh-subscription-primary",
3555
+ disabled: !resetAcknowledged || resetBusy,
3556
+ onClick: () => {
3557
+ consumeReset();
3558
+ },
3559
+ children: t("resetUseConfirm")
3560
+ })]
3561
+ })
3562
+ ] })
2970
3563
  })
2971
3564
  ]
2972
3565
  });
@@ -3253,20 +3846,42 @@ const HOST_CONTRACT = {
3253
3846
  package: "@deepseek-ai/dsh-client-ui-theme",
3254
3847
  names: [
3255
3848
  "--dsw-alias-bg-layer-1",
3849
+ "--dsw-alias-bg-layer-2",
3850
+ "--dsw-alias-bg-layer-3",
3851
+ "--dsw-alias-bg-mask-1",
3256
3852
  "--dsw-alias-bg-skeleton",
3853
+ "--dsw-alias-border-l1",
3257
3854
  "--dsw-alias-border-l2",
3258
3855
  "--dsw-alias-border-l2-darkmode-thin",
3856
+ "--dsw-alias-border-l3",
3857
+ "--dsw-alias-border-l4",
3858
+ "--dsw-alias-brand-primary",
3859
+ "--dsw-alias-button-primary-fill",
3860
+ "--dsw-alias-button-primary-hover",
3861
+ "--dsw-alias-interactive-bg-active",
3259
3862
  "--dsw-alias-interactive-bg-hover",
3260
3863
  "--dsw-alias-interactive-bg-hover-solid",
3261
3864
  "--dsw-alias-label-dimmed",
3262
3865
  "--dsw-alias-label-primary",
3866
+ "--dsw-alias-label-primary-foreground",
3263
3867
  "--dsw-alias-label-secondary",
3264
3868
  "--dsw-alias-label-tertiary",
3869
+ "--dsw-alias-settings-card-fill",
3870
+ "--dsw-alias-settings-card-stroke",
3871
+ "--dsw-alias-state-business-primary",
3265
3872
  "--dsw-alias-state-error-primary",
3266
3873
  "--dsw-alias-state-success-primary",
3267
3874
  "--dsw-alias-state-warn-label",
3268
3875
  "--dsw-elevation-prominent",
3876
+ "--dsw-focus-ring-color",
3877
+ "--dsw-focus-ring-width",
3878
+ "--dsw-mask-blur",
3269
3879
  "--dsw-menu-backdrop-filter",
3880
+ "--dsw-radius-lg",
3881
+ "--dsw-radius-md",
3882
+ "--dsw-radius-panel",
3883
+ "--dsw-radius-sm",
3884
+ "--dsw-radius-xl",
3270
3885
  "--dsw-specific-menu"
3271
3886
  ]
3272
3887
  }
@@ -3804,6 +4419,7 @@ function SpeedSelect({ loadSpeed, setSpeed, t }) {
3804
4419
  const triggerLabel = `${translate("speed")} · ${tierName(state.tier)}`;
3805
4420
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3806
4421
  ref: rootRef,
4422
+ className: "dsh-subscription-speed",
3807
4423
  style: styles$1.root,
3808
4424
  onKeyDown: (event) => {
3809
4425
  if (event.key === "Escape" && open) {
@@ -3811,46 +4427,50 @@ function SpeedSelect({ loadSpeed, setSpeed, t }) {
3811
4427
  setOpen(false);
3812
4428
  }
3813
4429
  },
3814
- children: [open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3815
- style: styles$1.menu,
3816
- role: "menu",
3817
- "aria-label": translate("speed"),
3818
- children: TIERS.map((tier) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4430
+ children: [
4431
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: subscriptionChromeCss }),
4432
+ open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4433
+ style: styles$1.menu,
4434
+ role: "menu",
4435
+ "aria-label": translate("speed"),
4436
+ children: TIERS.map((tier) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4437
+ type: "button",
4438
+ role: "menuitemradio",
4439
+ "aria-checked": tier === state.tier,
4440
+ style: styles$1.item,
4441
+ disabled: busy,
4442
+ onClick: () => {
4443
+ choose(tier);
4444
+ },
4445
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4446
+ style: styles$1.itemCheck,
4447
+ children: tier === state.tier ? "✓" : ""
4448
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4449
+ style: styles$1.itemText,
4450
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4451
+ style: styles$1.itemName,
4452
+ children: tierName(tier)
4453
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4454
+ style: styles$1.itemDescription,
4455
+ children: tierDescription(tier)
4456
+ })]
4457
+ })]
4458
+ }, tier))
4459
+ }),
4460
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3819
4461
  type: "button",
3820
- role: "menuitemradio",
3821
- "aria-checked": tier === state.tier,
3822
- style: styles$1.item,
4462
+ style: styles$1.trigger,
4463
+ "aria-haspopup": "menu",
4464
+ "aria-expanded": open,
4465
+ title: triggerLabel,
3823
4466
  disabled: busy,
3824
4467
  onClick: () => {
3825
- choose(tier);
4468
+ if (open) setOpen(false);
4469
+ else show();
3826
4470
  },
3827
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3828
- style: styles$1.itemCheck,
3829
- children: tier === state.tier ? "✓" : ""
3830
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3831
- style: styles$1.itemText,
3832
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3833
- style: styles$1.itemName,
3834
- children: tierName(tier)
3835
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3836
- style: styles$1.itemDescription,
3837
- children: tierDescription(tier)
3838
- })]
3839
- })]
3840
- }, tier))
3841
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3842
- type: "button",
3843
- style: styles$1.trigger,
3844
- "aria-haspopup": "menu",
3845
- "aria-expanded": open,
3846
- title: triggerLabel,
3847
- disabled: busy,
3848
- onClick: () => {
3849
- if (open) setOpen(false);
3850
- else show();
3851
- },
3852
- children: triggerLabel
3853
- })]
4471
+ children: triggerLabel
4472
+ })
4473
+ ]
3854
4474
  });
3855
4475
  }
3856
4476
  const styles$1 = {
@@ -3859,9 +4479,9 @@ const styles$1 = {
3859
4479
  display: "inline-flex"
3860
4480
  },
3861
4481
  trigger: {
3862
- border: "1px solid var(--dsw-alias-border-l2)",
3863
- borderRadius: 8,
3864
- background: "transparent",
4482
+ border: "0.5px solid var(--dsw-alias-border-l3)",
4483
+ borderRadius: "var(--dsw-radius-sm, 8px)",
4484
+ background: "var(--dsh-subscription-speed-hover, transparent)",
3865
4485
  color: "var(--dsw-alias-label-secondary)",
3866
4486
  font: "inherit",
3867
4487
  fontSize: 12,
@@ -3878,9 +4498,10 @@ const styles$1 = {
3878
4498
  minWidth: 180,
3879
4499
  padding: 4,
3880
4500
  zIndex: 20,
3881
- background: "var(--dsw-alias-bg-layer-1)",
3882
- border: "1px solid var(--dsw-alias-border-l2)",
3883
- borderRadius: 8,
4501
+ background: "var(--dsw-specific-menu, var(--dsw-alias-bg-layer-2))",
4502
+ border: 0,
4503
+ boxShadow: "var(--dsw-elevation-prominent)",
4504
+ borderRadius: "var(--dsw-radius-lg, 16px)",
3884
4505
  display: "flex",
3885
4506
  flexDirection: "column",
3886
4507
  gap: 2
@@ -3891,8 +4512,8 @@ const styles$1 = {
3891
4512
  gap: 6,
3892
4513
  width: "100%",
3893
4514
  border: "none",
3894
- borderRadius: 6,
3895
- background: "transparent",
4515
+ borderRadius: "var(--dsw-radius-sm, 8px)",
4516
+ background: "var(--dsh-subscription-speed-hover, transparent)",
3896
4517
  padding: "6px 8px",
3897
4518
  cursor: "pointer",
3898
4519
  font: "inherit",
@@ -4391,81 +5012,87 @@ function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
4391
5012
  const pill = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4392
5013
  ref: rootRef,
4393
5014
  style: styles.anchor,
4394
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4395
- type: "button",
4396
- style: {
4397
- ...styles.pill,
4398
- ...hover || open ? styles.pillActive : {}
4399
- },
4400
- "aria-haspopup": "dialog",
4401
- "aria-expanded": open,
4402
- "aria-label": `${title} · ${label}`,
4403
- title,
4404
- onMouseEnter: () => {
4405
- setHover(true);
4406
- },
4407
- onMouseLeave: () => {
4408
- setHover(false);
4409
- },
4410
- onClick: toggle,
4411
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageBadgeIcon, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4412
- style: styles.label,
4413
- children: label
4414
- })]
4415
- }), open && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4416
- ref: panelRef,
4417
- role: "dialog",
4418
- "aria-label": title,
4419
- style: {
4420
- ...styles.panel,
4421
- ...pos ?? MEASURE_STYLE
4422
- },
4423
- children: [
4424
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4425
- style: styles.title,
4426
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4427
- style: styles.titleLabel,
4428
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageBadgeIcon, {}), title]
4429
- })
4430
- }),
4431
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4432
- style: styles.titleRule,
4433
- "aria-hidden": true
4434
- }),
4435
- expanded.map((d, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
4436
- style: index === 0 ? void 0 : styles.section,
4437
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4438
- style: styles.providerRow,
4439
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4440
- style: styles.providerName,
4441
- children: [d.name, d.provider === current && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4442
- style: styles.currentTag,
4443
- children: translate("usageBadgeCurrent")
5015
+ children: [
5016
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: subscriptionChromeCss }),
5017
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
5018
+ type: "button",
5019
+ className: "dsh-subscription-usage-pill",
5020
+ style: {
5021
+ ...styles.pill,
5022
+ ...hover || open ? styles.pillActive : {}
5023
+ },
5024
+ "aria-haspopup": "dialog",
5025
+ "aria-expanded": open,
5026
+ "aria-label": `${title} · ${label}`,
5027
+ title,
5028
+ onMouseEnter: () => {
5029
+ setHover(true);
5030
+ },
5031
+ onMouseLeave: () => {
5032
+ setHover(false);
5033
+ },
5034
+ onClick: toggle,
5035
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageBadgeIcon, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5036
+ style: styles.label,
5037
+ children: label
5038
+ })]
5039
+ }),
5040
+ open && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5041
+ ref: panelRef,
5042
+ role: "dialog",
5043
+ "aria-label": title,
5044
+ className: "dsh-subscription-usage-panel",
5045
+ style: {
5046
+ ...styles.panel,
5047
+ ...pos ?? MEASURE_STYLE
5048
+ },
5049
+ children: [
5050
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5051
+ style: styles.title,
5052
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5053
+ style: styles.titleLabel,
5054
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageBadgeIcon, {}), title]
5055
+ })
5056
+ }),
5057
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5058
+ style: styles.titleRule,
5059
+ "aria-hidden": true
5060
+ }),
5061
+ expanded.map((d, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5062
+ style: index === 0 ? void 0 : styles.section,
5063
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5064
+ style: styles.providerRow,
5065
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5066
+ style: styles.providerName,
5067
+ children: [d.name, d.provider === current && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5068
+ style: styles.currentTag,
5069
+ children: translate("usageBadgeCurrent")
5070
+ })]
5071
+ }), d.accounts.length === 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountMeta, {
5072
+ account: d.accounts[0],
5073
+ translate
4444
5074
  })]
4445
- }), d.accounts.length === 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountMeta, {
4446
- account: d.accounts[0],
4447
- translate
4448
- })]
4449
- }), d.accounts.map((account, accountIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4450
- style: accountIndex === 0 ? void 0 : styles.accountBlock,
4451
- children: [d.accounts.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4452
- style: styles.accountRow,
4453
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountMeta, {
4454
- account,
5075
+ }), d.accounts.map((account, accountIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5076
+ style: accountIndex === 0 ? void 0 : styles.accountBlock,
5077
+ children: [d.accounts.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5078
+ style: styles.accountRow,
5079
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountMeta, {
5080
+ account,
5081
+ translate
5082
+ })
5083
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountWindows, {
5084
+ windows: account.windows,
5085
+ observedAt: account.observedAt,
5086
+ stale: account.stale,
5087
+ model: d.provider === dialogProvider ? dialogModel : void 0,
5088
+ provider: d.provider,
4455
5089
  translate
4456
- })
4457
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountWindows, {
4458
- windows: account.windows,
4459
- observedAt: account.observedAt,
4460
- stale: account.stale,
4461
- model: d.provider === dialogProvider ? dialogModel : void 0,
4462
- provider: d.provider,
4463
- translate
4464
- }, `${d.provider}:${dialogModel ?? ""}`)]
4465
- }, account.key))]
4466
- }, d.provider))
4467
- ]
4468
- }), document.body)]
5090
+ }, `${d.provider}:${dialogModel ?? ""}`)]
5091
+ }, account.key))]
5092
+ }, d.provider))
5093
+ ]
5094
+ }), document.body)
5095
+ ]
4469
5096
  });
4470
5097
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [seat, statsRow !== null && statsRow.isConnected ? (0, react_dom.createPortal)(pill, statsRow) : pill] });
4471
5098
  }
@@ -4565,13 +5192,13 @@ const styles = {
4565
5192
  maxWidth: "100%",
4566
5193
  color: "var(--dsw-alias-label-tertiary)",
4567
5194
  font: "inherit",
4568
- fontSize: "var(--dsh-content-font-size-secondary, 13px)",
5195
+ fontSize: "calc(var(--dsh-content-font-size-secondary, 13px) - 1px)",
4569
5196
  fontVariantNumeric: "tabular-nums",
4570
- lineHeight: "20px",
5197
+ lineHeight: "calc(20px + var(--dsh-content-font-delta-secondary, 0px))",
4571
5198
  whiteSpace: "nowrap",
4572
5199
  background: "transparent",
4573
5200
  border: "none",
4574
- borderRadius: 24,
5201
+ borderRadius: 999,
4575
5202
  alignItems: "center",
4576
5203
  gap: 6,
4577
5204
  padding: "1px 8px",
@@ -4603,7 +5230,7 @@ const styles = {
4603
5230
  color: "var(--dsw-alias-label-secondary)",
4604
5231
  cursor: "default",
4605
5232
  border: 0,
4606
- borderRadius: 12,
5233
+ borderRadius: "var(--dsw-radius-lg, 16px)",
4607
5234
  padding: 16,
4608
5235
  fontSize: 12,
4609
5236
  lineHeight: "18px"