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
@@ -10,15 +10,17 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
10
10
  * design-platform.css values flip under `body[data-ds-dark-theme]`), and
11
11
  * every user-visible string goes through the locale-bound `t` of the
12
12
  * 'settings.subscriptions' namespace. Buttons and inputs take the
13
- * ModelsSection vocabulary minus hover rules, which inline styles cannot
14
- * express.
13
+ * native settings vocabulary with shared, scoped control states.
15
14
  */
16
15
  import { useCallback, useEffect, useRef, useState } from 'react';
17
16
  import { en } from './locales.js';
17
+ import { resetActionBlock } from './reset-action.js';
18
18
  import { ProviderAccountManager } from './ProviderAccountManager.js';
19
+ import { providerSettingsCss } from './provider-settings-styles.js';
19
20
  import { ExternalUsageCards } from './ExternalUsageCards.js';
20
21
  import { CursorCard } from './CursorCard.js';
21
22
  import { UsageMeter } from './UsageMeter.js';
23
+ import { ResetCreditsDisclosure, ResetCreditsErrorLine, showsResetCredits } from './reset-credits-view.js';
22
24
  import { displayUsedPercent } from './usage-pace.js';
23
25
  import { UsageBadgeDisplaySetting } from './UsageBadgeDisplaySetting.js';
24
26
  import { USAGE_BADGE_REFRESH_EVENT } from './usage-badge-preferences.js';
@@ -80,7 +82,10 @@ const styles = {
80
82
  color: 'var(--dsw-alias-label-primary)',
81
83
  },
82
84
  intro: { margin: 0, color: 'var(--dsw-alias-label-tertiary)', fontSize: 14, lineHeight: '22px' },
83
- card: cardStyles.card,
85
+ card: { ...cardStyles.card,
86
+ border: '0.5px solid var(--dsw-alias-settings-card-stroke, var(--dsw-alias-border-l4))',
87
+ borderRadius: 'var(--dsw-radius-xl, 20px)', background: 'var(--dsw-alias-settings-card-fill, var(--dsw-alias-bg-layer-2))',
88
+ },
84
89
  cardHeader: cardStyles.header,
85
90
  dot: cardStyles.dot,
86
91
  name: cardStyles.name,
@@ -88,44 +93,46 @@ const styles = {
88
93
  clientVersion: { fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)', fontVariantNumeric: 'tabular-nums' },
89
94
  errorLine: cardStyles.error,
90
95
  actions: cardStyles.actions,
91
- button: cardStyles.button,
92
- usage: cardStyles.usage,
96
+ usage: { ...cardStyles.usage, borderTop: '0.5px solid var(--dsw-alias-border-l2)' },
93
97
  usageHeader: cardStyles.usageHeader,
94
98
  usageTitle: cardStyles.usageTitle,
95
99
  usagePlan: cardStyles.usagePlan,
96
- usageRefresh: cardStyles.usageRefresh,
100
+ usageRefresh: { minHeight: 22, height: 22, padding: '0 8px', marginLeft: 'auto' },
97
101
  usageRow: cardStyles.usageRow,
98
102
  usageMeta: cardStyles.usageMeta,
99
- accountRow: cardStyles.account,
103
+ accountRow: { ...cardStyles.account, border: '0.5px solid var(--dsw-alias-border-l2)', borderRadius: 'var(--dsw-radius-lg, 16px)' },
100
104
  accountHeader: cardStyles.accountHeader,
101
105
  accountName: cardStyles.accountName,
102
106
  starButton: {
103
- border: 'none', background: 'transparent', padding: 0,
107
+ border: 'none', padding: 0, width: 28,
104
108
  font: 'inherit', fontSize: 14, lineHeight: '20px', cursor: 'pointer',
105
109
  color: 'var(--dsw-alias-state-warn-label)',
106
110
  },
107
111
  deviceCode: {
108
112
  marginTop: 4, display: 'flex', flexDirection: 'column', gap: 6,
109
- border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 8,
113
+ border: '0.5px solid var(--dsw-alias-border-l2)', borderRadius: 'var(--dsw-radius-lg, 16px)',
110
114
  padding: '10px 12px', background: 'var(--dsw-alias-bg-layer-1)',
111
115
  },
112
116
  deviceCodeText: {
113
117
  fontFamily: 'monospace', fontSize: 18, lineHeight: '24px', letterSpacing: 2,
114
118
  color: 'var(--dsw-alias-label-primary)', userSelect: 'all',
115
119
  },
120
+ manual: { fontSize: 13, lineHeight: '20px' },
121
+ manualRow: { display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center', marginTop: 8 },
122
+ manualInput: { flex: '1 1 200px', minWidth: 0 },
116
123
  modalOverlay: {
117
124
  position: 'fixed', inset: 0, zIndex: 1000,
118
125
  display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 16,
119
- background: 'rgba(0, 0, 0, 0.45)',
126
+ background: 'var(--dsw-alias-bg-mask-1, #0006)', backdropFilter: 'var(--dsw-mask-blur, none)',
120
127
  },
121
128
  modal: {
122
129
  width: 460, maxWidth: '100%', maxHeight: '90vh', overflowY: 'auto',
123
130
  boxSizing: 'border-box', display: 'flex', flexDirection: 'column', gap: 12,
124
- padding: '16px 18px', borderRadius: 12,
125
- background: 'var(--dsw-alias-bg-layer-1)', border: '1px solid var(--dsw-alias-border-l2)',
131
+ padding: '16px 18px', borderRadius: 'var(--dsw-radius-panel, 28px)',
132
+ background: 'var(--dsw-alias-bg-layer-2)', border: 0, boxShadow: 'var(--dsw-elevation-prominent)',
126
133
  },
127
134
  modalHeader: { display: 'flex', alignItems: 'center', gap: 8 },
128
- modalTitle: { fontWeight: 600, fontSize: 15, lineHeight: '22px', color: 'var(--dsw-alias-label-primary)' },
135
+ modalTitle: { fontWeight: 500, fontSize: 16, lineHeight: '24px', color: 'var(--dsw-alias-label-primary)' },
129
136
  };
130
137
  /** Status dot color for one provider state. */
131
138
  function dotColor(status) {
@@ -265,10 +272,24 @@ export function SubscriptionsSection(props) {
265
272
  const [observedAt, setObservedAt] = useState({});
266
273
  const [usageErrors, setUsageErrors] = useState({});
267
274
  const [usageLoading, setUsageLoading] = useState({});
275
+ const [resetConfirmation, setResetConfirmation] = useState();
276
+ const [resetBusy, setResetBusy] = useState(false);
277
+ const [resetAcknowledged, setResetAcknowledged] = useState(false);
278
+ const [resetMessage, setResetMessage] = useState('');
279
+ const [resetAccount, setResetAccount] = useState();
280
+ const resetDialogRef = useRef(null);
281
+ useEffect(() => {
282
+ if (resetConfirmation)
283
+ resetDialogRef.current?.showModal();
284
+ else
285
+ resetDialogRef.current?.close();
286
+ }, [resetConfirmation]);
287
+ const resetInflight = useRef(false);
268
288
  const mountedRef = useRef(true);
269
289
  const pollersRef = useRef(new Map());
270
290
  /** Accounts with a `usage` call in flight; guards the auto-fetch effect against re-entry. */
271
- const usageInflightRef = useRef(new Set());
291
+ /** In-flight usage reads per key, holding the promise so a forced read can wait one out. */
292
+ const usageInflightRef = useRef(new Map());
272
293
  const usageRosterSignatureRef = useRef();
273
294
  const [managedProvider, setManagedProvider] = useState();
274
295
  const setProviderError = useCallback((provider, message) => {
@@ -362,34 +383,91 @@ export function SubscriptionsSection(props) {
362
383
  };
363
384
  }, [refresh, startPolling]);
364
385
  const loadUsage = useCallback(async (provider, account, force = false) => {
386
+ if (rpc === undefined)
387
+ return;
365
388
  const key = `${provider}:${account}`;
389
+ const pending = usageInflightRef.current.get(key);
390
+ // A forced read must never be dropped behind a poll that started before the
391
+ // state changed. The refresh after a credit redemption is the only thing
392
+ // that picks up the new numbers, and the next automatic poll is minutes
393
+ // away, so waiting the earlier read out is cheaper than showing a stale
394
+ // percentage next to a success message.
395
+ if (pending !== undefined) {
396
+ if (!force)
397
+ return;
398
+ await pending;
399
+ }
366
400
  if (rpc === undefined || usageInflightRef.current.has(key))
367
401
  return;
368
- usageInflightRef.current.add(key);
369
- setUsageLoading(prev => ({ ...prev, [key]: true }));
402
+ const read = (async () => {
403
+ setUsageLoading(prev => ({ ...prev, [key]: true }));
404
+ try {
405
+ const usage = await callSubscriptionsAuth(rpc, 'usage', { provider, account, ...force ? { force: true } : {} });
406
+ if (!mountedRef.current)
407
+ return;
408
+ setUsages(prev => ({ ...prev, [key]: usage }));
409
+ setObservedAt(prev => ({ ...prev, [key]: usage.observedAt ?? Date.now() }));
410
+ window.dispatchEvent(new Event(USAGE_BADGE_REFRESH_EVENT));
411
+ setUsageErrors((prev) => {
412
+ const next = { ...prev };
413
+ delete next[key];
414
+ return next;
415
+ });
416
+ }
417
+ catch (error) {
418
+ if (mountedRef.current)
419
+ setUsageErrors(prev => ({ ...prev, [key]: messageOf(error) }));
420
+ }
421
+ finally {
422
+ usageInflightRef.current.delete(key);
423
+ if (mountedRef.current)
424
+ setUsageLoading(prev => ({ ...prev, [key]: false }));
425
+ }
426
+ })();
427
+ usageInflightRef.current.set(key, read);
428
+ await read;
429
+ }, [rpc]);
430
+ async function prepareReset(account) {
431
+ if (!rpc || resetInflight.current)
432
+ return;
433
+ resetInflight.current = true;
434
+ setResetBusy(true);
435
+ setResetAccount(account);
436
+ setResetConfirmation(undefined);
437
+ setResetMessage('');
370
438
  try {
371
- const usage = await callSubscriptionsAuth(rpc, 'usage', { provider, account, ...force ? { force: true } : {} });
372
- if (!mountedRef.current)
373
- return;
374
- setUsages(prev => ({ ...prev, [key]: usage }));
375
- setObservedAt(prev => ({ ...prev, [key]: usage.observedAt ?? Date.now() }));
376
- window.dispatchEvent(new Event(USAGE_BADGE_REFRESH_EVENT));
377
- setUsageErrors((prev) => {
378
- const next = { ...prev };
379
- delete next[key];
380
- return next;
381
- });
439
+ const result = await callSubscriptionsAuth(rpc, 'prepareReset', { account });
440
+ setResetAcknowledged(false);
441
+ setResetConfirmation({ ...result, account });
382
442
  }
383
443
  catch (error) {
384
- if (mountedRef.current)
385
- setUsageErrors(prev => ({ ...prev, [key]: messageOf(error) }));
444
+ setResetMessage(messageOf(error));
386
445
  }
387
446
  finally {
388
- usageInflightRef.current.delete(key);
389
- if (mountedRef.current)
390
- setUsageLoading(prev => ({ ...prev, [key]: false }));
447
+ resetInflight.current = false;
448
+ setResetBusy(false);
391
449
  }
392
- }, [rpc]);
450
+ }
451
+ async function consumeReset() {
452
+ if (!rpc || !resetConfirmation || !resetAcknowledged || resetInflight.current)
453
+ return;
454
+ const { account, ticket } = resetConfirmation;
455
+ resetInflight.current = true;
456
+ setResetBusy(true);
457
+ setResetConfirmation(undefined);
458
+ try {
459
+ await callSubscriptionsAuth(rpc, 'consumeReset', { account, ticket });
460
+ setResetMessage(t('resetUseSuccess'));
461
+ }
462
+ catch (error) {
463
+ setResetMessage(messageOf(error));
464
+ }
465
+ finally {
466
+ await loadUsage('codex', account, true);
467
+ resetInflight.current = false;
468
+ setResetBusy(false);
469
+ }
470
+ }
393
471
  // Fetch usage once an account is logged in; drop the snapshots of accounts
394
472
  // that vanished so a re-login refetches. A failed lookup does not auto-retry
395
473
  // — the per-account Refresh button is the retry path.
@@ -514,7 +592,7 @@ export function SubscriptionsSection(props) {
514
592
  if (rpc === undefined) {
515
593
  return _jsx("p", { style: styles.intro, children: t('unavailable') });
516
594
  }
517
- return (_jsxs("div", { style: styles.section, children: [_jsx("p", { style: styles.intro, children: t('intro') }), _jsx(UsageBadgeDisplaySetting, { t: t }), PROVIDERS.map(({ id, name }) => {
595
+ return (_jsxs("div", { className: "dsh-subscriptions-settings", style: styles.section, children: [_jsx("style", { children: providerSettingsCss }), _jsx("p", { style: styles.intro, children: t('intro') }), _jsx(UsageBadgeDisplaySetting, { t: t }), PROVIDERS.map(({ id, name }) => {
518
596
  const status = statuses[id];
519
597
  const busy = status?.busy === true;
520
598
  const deviceCode = deviceCodes[id];
@@ -524,17 +602,29 @@ export function SubscriptionsSection(props) {
524
602
  const usage = usages[usageKey];
525
603
  const usageError = usageErrors[usageKey];
526
604
  const display = account.account ?? account.key;
605
+ const sortedCredits = [...(usage?.resetCredits ?? [])].sort((a, b) => (a.expiresAt ?? Infinity) - (b.expiresAt ?? Infinity));
606
+ const nextReset = sortedCredits.find(c => c.expiresAt === undefined || c.expiresAt > Date.now());
607
+ const resetBlock = usage ? resetActionBlock(usage) : 'resetUseRefresh';
608
+ const resetDisabled = resetBusy || resetBlock !== undefined;
527
609
  // Providers without a usage endpoint answer supported:false — no block.
528
610
  const showUsage = usage?.supported !== false
529
611
  && (usage !== undefined || usageError !== undefined || usageLoading[usageKey] === true);
530
612
  return (_jsxs("div", { style: styles.accountRow, children: [_jsxs("div", { style: styles.accountHeader, children: [_jsx("button", { type: "button", style: styles.starButton, title: account.isDefault ? t('defaultBadge') : t('setDefault'), onClick: () => {
531
613
  if (!account.isDefault)
532
614
  void setDefault(id, account.key);
533
- }, children: account.isDefault ? '★' : '☆' }), _jsx("span", { style: styles.accountName, children: display }), account.plan !== undefined && (_jsx("span", { style: styles.usagePlan, children: account.plan })), account.expiresAt !== undefined && (_jsx("span", { style: styles.statusLine, children: t('accountExpires', { date: new Date(account.expiresAt).toLocaleString() }) })), _jsx("button", { type: "button", style: { ...styles.button, marginLeft: 'auto', flexShrink: 0 }, onClick: () => { void logout(id, account.key, display, name); }, children: t('logout') })] }), showUsage && (_jsxs("div", { style: styles.usage, children: [_jsxs("div", { style: styles.usageHeader, children: [_jsx("span", { style: styles.usageTitle, children: t('usageTitle') }), usage?.plan !== undefined && (_jsx("span", { style: styles.usagePlan, children: t('usagePlan', { plan: usage.plan }) })), _jsx("button", { type: "button", style: { ...styles.usageRefresh, ...usageLoading[usageKey] === true ? { opacity: 0.5, cursor: 'default' } : {} }, disabled: usageLoading[usageKey] === true, onClick: () => { void loadUsage(id, account.key, true); }, children: t('usageRefresh') })] }), usage === undefined && usageError === undefined && (_jsx("p", { style: styles.statusLine, children: t('usageLoading') })), usageError !== undefined && (_jsx("p", { style: styles.errorLine, children: t('usageError', { message: usageError }) })), usage?.windows !== undefined && usage.windows.length === 0 && (_jsx("p", { style: styles.statusLine, children: t('usageEmpty') })), (usage?.windows ?? []).map((window, index) => {
615
+ }, children: account.isDefault ? '★' : '☆' }), _jsx("span", { style: styles.accountName, children: display }), account.plan !== undefined && (_jsx("span", { style: styles.usagePlan, children: account.plan })), account.expiresAt !== undefined && (_jsx("span", { style: styles.statusLine, children: t('accountExpires', { date: new Date(account.expiresAt).toLocaleString() }) })), _jsx("button", { type: "button", style: { marginLeft: 'auto', flexShrink: 0 }, onClick: () => { void logout(id, account.key, display, name); }, children: t('logout') })] }), showUsage && (_jsxs("div", { style: styles.usage, children: [_jsxs("div", { style: styles.usageHeader, children: [_jsx("span", { style: styles.usageTitle, children: t('usageTitle') }), usage?.plan !== undefined && (_jsx("span", { style: styles.usagePlan, children: t('usagePlan', { plan: usage.plan }) })), _jsx("button", { type: "button", style: styles.usageRefresh, disabled: usageLoading[usageKey] === true, onClick: () => { void loadUsage(id, account.key, true); }, children: t('usageRefresh') })] }), usage === undefined && usageError === undefined && (_jsx("p", { style: styles.statusLine, children: t('usageLoading') })), usageError !== undefined && (_jsx("p", { style: styles.errorLine, children: t('usageError', { message: usageError }) })), usage?.windows !== undefined && usage.windows.length === 0 && (_jsx("p", { style: styles.statusLine, children: t('usageEmpty') })), (usage?.windows ?? []).map((window, index) => {
534
616
  const percent = displayUsedPercent(window.usedPercent);
535
617
  return (_jsxs("div", { style: styles.usageRow, children: [_jsxs("div", { style: styles.usageMeta, children: [_jsx("span", { children: usageWindowLabel(t, window) }), _jsxs("span", { children: [percent === undefined ? t('usageMeterInvalid') : `${percent}%`, window.resetsAt !== undefined
536
618
  && ` · ${t('usageResets', { date: new Date(window.resetsAt).toLocaleString() })}`] })] }), _jsx(UsageMeter, { window: window, t: t, observedAt: observedAt[usageKey], stale: usageError !== undefined || usage.stale === true })] }, index));
537
- })] }))] }, account.key));
538
- }), _jsxs("div", { style: styles.actions, children: [!busy && accounts.length === 0 && (_jsx("button", { type: "button", style: styles.button, onClick: () => { void login(id); }, children: t('login') })), !busy && accounts.length > 0 && id === 'claude' && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", style: styles.button, onClick: () => { void login(id, 'oauth'); }, children: t('addAccountOAuth') }), _jsx("button", { type: "button", style: styles.button, onClick: () => { void login(id, 'keychain'); }, children: t('addAccountKeychain') })] })), !busy && accounts.length > 0 && id !== 'claude' && (_jsx("button", { type: "button", style: styles.button, onClick: () => { void login(id); }, children: t('addAccount') })), _jsx("button", { type: "button", style: styles.button, "aria-haspopup": "dialog", onClick: () => setManagedProvider({ id, name }), children: t('accountsManage') }), busy && (_jsx("button", { type: "button", style: styles.button, onClick: () => { void cancel(id); }, children: t('cancel') }))] }), !busy && accounts.length > 0 && (_jsx("p", { style: styles.statusLine, children: t('addAccountHint') })), busy && deviceCode !== undefined && (_jsxs("div", { style: styles.deviceCode, children: [_jsx("span", { style: styles.statusLine, children: t('deviceCodePrompt') }), _jsx("span", { style: styles.deviceCodeText, children: deviceCode.userCode }), _jsxs("div", { style: styles.actions, children: [_jsx("button", { type: "button", style: styles.button, onClick: () => { copyDeviceCode(id, deviceCode.userCode); }, children: copiedCode === id ? t('deviceCodeCopied') : t('deviceCodeCopy') }), _jsx("button", { type: "button", style: styles.button, onClick: () => { window.open(deviceCode.verificationUrl, '_blank', 'noopener'); }, children: t('deviceCodeOpenPage') })] })] })), busy && deviceCode === undefined && (_jsxs("details", { style: styles.manual, children: [_jsx("summary", { children: t('manualSummary') }), _jsxs("div", { style: styles.manualRow, children: [_jsx("input", { style: styles.manualInput, value: manualDrafts[id], placeholder: t('manualPlaceholder'), onChange: event => setManualDrafts(prev => ({ ...prev, [id]: event.target.value })) }), _jsx("button", { type: "button", style: styles.button, onClick: () => { void submitManual(id); }, children: t('submit') })] })] }))] }, id));
539
- }), _jsx(CursorCard, { rpc: rpc, t: t }), _jsx(ExternalUsageCards, { rpc: rpc, t: t }), managedProvider && _jsx(ProviderAccountManager, { provider: managedProvider.id, name: managedProvider.name, rpc: rpc, t: t, onClose: () => setManagedProvider(undefined) })] }));
619
+ }), (id === 'codex' || id === 'claude') && usage?.resetCreditsError !== undefined && (_jsx(ResetCreditsErrorLine, { provider: id, message: usage.resetCreditsError, t: t })), (id === 'codex' || id === 'claude') && showsResetCredits(id, usage?.resetCredits) && (_jsx(ResetCreditsDisclosure, { mode: id === 'claude' ? 'grants' : 'credits', credits: sortedCredits, t: t, ...nextReset !== undefined ? { nextCredit: nextReset } : {}, ...id === 'codex' ? { useAction: {
620
+ accountKey: account.key,
621
+ busy: resetBusy && resetAccount === account.key,
622
+ disabled: resetDisabled,
623
+ title: t(resetBusy ? 'resetUseChecking' : resetBlock ?? 'resetUseReady'),
624
+ label: t('resetUseButton'),
625
+ onUse: () => { if (!resetDisabled)
626
+ void prepareReset(account.key); },
627
+ } } : {}, ...resetAccount === account.key && resetMessage !== '' ? { statusMessage: resetMessage } : {} }))] }))] }, account.key));
628
+ }), _jsxs("div", { style: styles.actions, children: [!busy && accounts.length === 0 && (_jsx("button", { type: "button", onClick: () => { void login(id); }, children: t('login') })), !busy && accounts.length > 0 && id === 'claude' && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: () => { void login(id, 'oauth'); }, children: t('addAccountOAuth') }), _jsx("button", { type: "button", onClick: () => { void login(id, 'keychain'); }, children: t('addAccountKeychain') })] })), !busy && accounts.length > 0 && id !== 'claude' && (_jsx("button", { type: "button", onClick: () => { void login(id); }, children: t('addAccount') })), _jsx("button", { type: "button", "aria-haspopup": "dialog", onClick: () => setManagedProvider({ id, name }), children: t('accountsManage') }), busy && (_jsx("button", { type: "button", onClick: () => { void cancel(id); }, children: t('cancel') }))] }), !busy && accounts.length > 0 && (_jsx("p", { style: styles.statusLine, children: t('addAccountHint') })), busy && deviceCode !== undefined && (_jsxs("div", { style: styles.deviceCode, children: [_jsx("span", { style: styles.statusLine, children: t('deviceCodePrompt') }), _jsx("span", { style: styles.deviceCodeText, children: deviceCode.userCode }), _jsxs("div", { style: styles.actions, children: [_jsx("button", { type: "button", onClick: () => { copyDeviceCode(id, deviceCode.userCode); }, children: copiedCode === id ? t('deviceCodeCopied') : t('deviceCodeCopy') }), _jsx("button", { type: "button", onClick: () => { window.open(deviceCode.verificationUrl, '_blank', 'noopener'); }, children: t('deviceCodeOpenPage') })] })] })), busy && deviceCode === undefined && (_jsxs("details", { style: styles.manual, children: [_jsx("summary", { children: t('manualSummary') }), _jsxs("div", { style: styles.manualRow, children: [_jsx("input", { style: styles.manualInput, value: manualDrafts[id], placeholder: t('manualPlaceholder'), onChange: event => setManualDrafts(prev => ({ ...prev, [id]: event.target.value })) }), _jsx("button", { type: "button", onClick: () => { void submitManual(id); }, children: t('submit') })] })] }))] }, id));
629
+ }), _jsx(CursorCard, { rpc: rpc, t: t }), _jsx(ExternalUsageCards, { rpc: rpc, t: t }), managedProvider && _jsx(ProviderAccountManager, { provider: managedProvider.id, name: managedProvider.name, rpc: rpc, t: t, onClose: () => setManagedProvider(undefined) }), _jsx("style", { children: '.subscriptions-reset-dialog::backdrop { background: var(--dsw-alias-bg-mask-1, #0006); backdrop-filter: var(--dsw-mask-blur, none); }' }), _jsx("dialog", { ref: resetDialogRef, className: "subscriptions-reset-dialog", "aria-labelledby": "subscriptions-reset-title", onCancel: () => setResetConfirmation(undefined), onClose: () => setResetConfirmation(undefined), style: { ...styles.modal, display: resetConfirmation ? 'flex' : 'none', margin: 'auto', color: 'var(--dsw-alias-label-primary)' }, children: resetConfirmation && _jsxs(_Fragment, { children: [_jsx("h3", { id: "subscriptions-reset-title", style: { ...styles.modalTitle, margin: 0 }, children: t('resetUseConfirmTitle') }), _jsx("p", { style: { ...styles.statusLine, overflowWrap: 'anywhere' }, children: statuses.codex?.accounts.find(a => a.key === resetConfirmation.account)?.account ?? resetConfirmation.account }), _jsxs("div", { style: { ...styles.usageMeta, gap: 12 }, children: [_jsx("span", { children: t('usageWeekly') }), _jsxs("strong", { children: [Math.round(resetConfirmation.weeklyUsedPercent), "%"] })] }), _jsx("div", { style: styles.usageMeta, children: _jsx("span", { children: resetConfirmation.creditExpiresAt === undefined ? t('resetCreditExpiryUnknown') : t('resetCreditExpires', { date: new Date(resetConfirmation.creditExpiresAt).toLocaleString() }) }) }), _jsx("p", { style: { ...styles.statusLine, margin: '4px 0' }, children: t('resetUseWarning') }), _jsxs("label", { style: { display: 'flex', gap: 8, alignItems: 'flex-start', fontSize: 12 }, children: [_jsx("input", { type: "checkbox", checked: resetAcknowledged, onChange: e => setResetAcknowledged(e.target.checked) }), t('resetUseAcknowledge')] }), _jsxs("div", { className: "dsh-subscription-dialog-actions", style: { ...styles.actions, justifyContent: 'flex-end', marginTop: 8 }, children: [_jsx("button", { type: "button", autoFocus: true, onClick: () => setResetConfirmation(undefined), children: t('cancel') }), _jsx("button", { type: "button", className: "dsh-subscription-primary", disabled: !resetAcknowledged || resetBusy, onClick: () => { void consumeReset(); }, children: t('resetUseConfirm') })] })] }) })] }));
540
630
  }
@@ -39,15 +39,11 @@ export function UsageBadgeDisplaySetting({ t }) {
39
39
  }
40
40
  const styles = {
41
41
  card: {
42
- border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 12,
42
+ border: '0.5px solid var(--dsw-alias-settings-card-stroke, var(--dsw-alias-border-l4))',
43
+ borderRadius: 'var(--dsw-radius-xl, 20px)', background: 'var(--dsw-alias-settings-card-fill, var(--dsw-alias-bg-layer-2))',
43
44
  padding: '12px 14px', display: 'flex', flexDirection: 'column', gap: 6,
44
45
  },
45
- field: { display: 'flex', flexDirection: 'column', gap: 4, fontSize: 14, lineHeight: '22px' },
46
- select: {
47
- height: 32, width: '100%', boxSizing: 'border-box',
48
- border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 8,
49
- padding: '0 10px', font: 'inherit',
50
- background: 'var(--dsw-alias-bg-layer-1)', color: 'var(--dsw-alias-label-primary)',
51
- },
46
+ field: { display: 'flex', flexDirection: 'column', gap: 6, fontSize: 13, fontWeight: 500, lineHeight: '20px' },
47
+ select: { width: '100%' },
52
48
  hint: { margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)' },
53
49
  };
@@ -83,7 +83,7 @@ export declare const HOST_CONTRACT: {
83
83
  /** Design tokens the client styles with; the host theme must define each one. */
84
84
  readonly tokens: {
85
85
  readonly package: "@deepseek-ai/dsh-client-ui-theme";
86
- readonly names: readonly ["--dsw-alias-bg-layer-1", "--dsw-alias-bg-skeleton", "--dsw-alias-border-l2", "--dsw-alias-border-l2-darkmode-thin", "--dsw-alias-interactive-bg-hover", "--dsw-alias-interactive-bg-hover-solid", "--dsw-alias-label-dimmed", "--dsw-alias-label-primary", "--dsw-alias-label-secondary", "--dsw-alias-label-tertiary", "--dsw-alias-state-error-primary", "--dsw-alias-state-success-primary", "--dsw-alias-state-warn-label", "--dsw-elevation-prominent", "--dsw-menu-backdrop-filter", "--dsw-specific-menu"];
86
+ readonly names: readonly ["--dsw-alias-bg-layer-1", "--dsw-alias-bg-layer-2", "--dsw-alias-bg-layer-3", "--dsw-alias-bg-mask-1", "--dsw-alias-bg-skeleton", "--dsw-alias-border-l1", "--dsw-alias-border-l2", "--dsw-alias-border-l2-darkmode-thin", "--dsw-alias-border-l3", "--dsw-alias-border-l4", "--dsw-alias-brand-primary", "--dsw-alias-button-primary-fill", "--dsw-alias-button-primary-hover", "--dsw-alias-interactive-bg-active", "--dsw-alias-interactive-bg-hover", "--dsw-alias-interactive-bg-hover-solid", "--dsw-alias-label-dimmed", "--dsw-alias-label-primary", "--dsw-alias-label-primary-foreground", "--dsw-alias-label-secondary", "--dsw-alias-label-tertiary", "--dsw-alias-settings-card-fill", "--dsw-alias-settings-card-stroke", "--dsw-alias-state-business-primary", "--dsw-alias-state-error-primary", "--dsw-alias-state-success-primary", "--dsw-alias-state-warn-label", "--dsw-elevation-prominent", "--dsw-focus-ring-color", "--dsw-focus-ring-width", "--dsw-mask-blur", "--dsw-menu-backdrop-filter", "--dsw-radius-lg", "--dsw-radius-md", "--dsw-radius-panel", "--dsw-radius-sm", "--dsw-radius-xl", "--dsw-specific-menu"];
87
87
  };
88
88
  };
89
89
  /** A glyph name listed in {@link HOST_CONTRACT}; hostIcon() accepts no other. */
@@ -82,20 +82,42 @@ export const HOST_CONTRACT = {
82
82
  package: '@deepseek-ai/dsh-client-ui-theme',
83
83
  names: [
84
84
  '--dsw-alias-bg-layer-1',
85
+ '--dsw-alias-bg-layer-2',
86
+ '--dsw-alias-bg-layer-3',
87
+ '--dsw-alias-bg-mask-1',
85
88
  '--dsw-alias-bg-skeleton',
89
+ '--dsw-alias-border-l1',
86
90
  '--dsw-alias-border-l2',
87
91
  '--dsw-alias-border-l2-darkmode-thin',
92
+ '--dsw-alias-border-l3',
93
+ '--dsw-alias-border-l4',
94
+ '--dsw-alias-brand-primary',
95
+ '--dsw-alias-button-primary-fill',
96
+ '--dsw-alias-button-primary-hover',
97
+ '--dsw-alias-interactive-bg-active',
88
98
  '--dsw-alias-interactive-bg-hover',
89
99
  '--dsw-alias-interactive-bg-hover-solid',
90
100
  '--dsw-alias-label-dimmed',
91
101
  '--dsw-alias-label-primary',
102
+ '--dsw-alias-label-primary-foreground',
92
103
  '--dsw-alias-label-secondary',
93
104
  '--dsw-alias-label-tertiary',
105
+ '--dsw-alias-settings-card-fill',
106
+ '--dsw-alias-settings-card-stroke',
107
+ '--dsw-alias-state-business-primary',
94
108
  '--dsw-alias-state-error-primary',
95
109
  '--dsw-alias-state-success-primary',
96
110
  '--dsw-alias-state-warn-label',
97
111
  '--dsw-elevation-prominent',
112
+ '--dsw-focus-ring-color',
113
+ '--dsw-focus-ring-width',
114
+ '--dsw-mask-blur',
98
115
  '--dsw-menu-backdrop-filter',
116
+ '--dsw-radius-lg',
117
+ '--dsw-radius-md',
118
+ '--dsw-radius-panel',
119
+ '--dsw-radius-sm',
120
+ '--dsw-radius-xl',
99
121
  '--dsw-specific-menu',
100
122
  ],
101
123
  },
@@ -104,6 +104,35 @@ export declare const en: {
104
104
  usageColorPaceHint: string;
105
105
  usageColorRemainingHint: string;
106
106
  usagePlan: string;
107
+ resetCreditsTitle: string;
108
+ resetCreditsAvailable: string;
109
+ resetCreditsError: string;
110
+ resetCreditsErrorFixed: string;
111
+ resetCreditReadOnly: string;
112
+ resetCreditReadOnlyLabel: string;
113
+ resetCreditAvailable: string;
114
+ resetCreditNotUsable: string;
115
+ resetCreditPaused: string;
116
+ resetCreditExhausted: string;
117
+ resetCreditExpired: string;
118
+ resetCreditRemaining: string;
119
+ resetCreditLeft: string;
120
+ resetCreditRemainingUnknown: string;
121
+ resetCreditCooldownUntil: string;
122
+ resetUseButton: string;
123
+ resetUseChecking: string;
124
+ resetUseGuard: string;
125
+ resetUseRestart: string;
126
+ resetUseRefresh: string;
127
+ resetUseReady: string;
128
+ resetUseConfirmTitle: string;
129
+ resetUseWarning: string;
130
+ resetUseAcknowledge: string;
131
+ resetUseConfirm: string;
132
+ resetUseSuccess: string;
133
+ resetCreditFull: string;
134
+ resetCreditExpires: string;
135
+ resetCreditExpiryUnknown: string;
107
136
  externalUsageTitle: string;
108
137
  externalUsageConnected: string;
109
138
  externalUsageNotConfigured: string;
@@ -276,6 +305,35 @@ export declare const zh: {
276
305
  usageColorPaceHint: string;
277
306
  usageColorRemainingHint: string;
278
307
  usagePlan: string;
308
+ resetCreditsTitle: string;
309
+ resetCreditsAvailable: string;
310
+ resetCreditsError: string;
311
+ resetCreditsErrorFixed: string;
312
+ resetCreditReadOnly: string;
313
+ resetCreditReadOnlyLabel: string;
314
+ resetCreditAvailable: string;
315
+ resetCreditNotUsable: string;
316
+ resetCreditPaused: string;
317
+ resetCreditExhausted: string;
318
+ resetCreditExpired: string;
319
+ resetCreditRemaining: string;
320
+ resetCreditLeft: string;
321
+ resetCreditRemainingUnknown: string;
322
+ resetCreditCooldownUntil: string;
323
+ resetUseButton: string;
324
+ resetUseChecking: string;
325
+ resetUseGuard: string;
326
+ resetUseRestart: string;
327
+ resetUseRefresh: string;
328
+ resetUseReady: string;
329
+ resetUseConfirmTitle: string;
330
+ resetUseWarning: string;
331
+ resetUseAcknowledge: string;
332
+ resetUseConfirm: string;
333
+ resetUseSuccess: string;
334
+ resetCreditFull: string;
335
+ resetCreditExpires: string;
336
+ resetCreditExpiryUnknown: string;
279
337
  externalUsageTitle: string;
280
338
  externalUsageConnected: string;
281
339
  externalUsageNotConfigured: string;
@@ -104,6 +104,35 @@ export const en = {
104
104
  usageColorPaceHint: 'Yellow when usage leads elapsed time by {allowance} points; red at 90% used takes priority. Saved in this browser; only colors change.',
105
105
  usageColorRemainingHint: 'Red at 90% used; no yellow pace warnings. Reliable time markers remain visible. Saved in this browser.',
106
106
  usagePlan: 'Plan: {plan}',
107
+ resetCreditsTitle: 'Usage limit resets',
108
+ resetCreditsAvailable: '{count} available',
109
+ resetCreditsError: 'Usage limit resets unavailable: {message}',
110
+ resetCreditsErrorFixed: 'Usage limit resets are unavailable. Refresh usage to try again.',
111
+ resetCreditReadOnly: 'Read only. This page cannot spend a Claude reset.',
112
+ resetCreditReadOnlyLabel: 'Read only',
113
+ resetCreditAvailable: 'Available',
114
+ resetCreditNotUsable: 'Not yet usable',
115
+ resetCreditPaused: 'Paused',
116
+ resetCreditExhausted: 'Exhausted',
117
+ resetCreditExpired: 'Expired',
118
+ resetCreditRemaining: '{left} of {total} left',
119
+ resetCreditLeft: '{left} left',
120
+ resetCreditRemainingUnknown: 'Remaining count unavailable',
121
+ resetCreditCooldownUntil: 'Usable after {date}',
122
+ resetUseButton: 'Use…',
123
+ resetUseChecking: 'Checking…',
124
+ resetUseGuard: 'You can use this reset when weekly usage reaches at least 80%.',
125
+ resetUseRestart: 'Reset details are missing. Restart DSH, reload this page, then refresh usage.',
126
+ resetUseRefresh: 'Refresh usage to verify current limits and reset availability.',
127
+ resetUseReady: 'Use this reset — the earliest-expiring credit. Confirmation required.',
128
+ resetUseConfirmTitle: 'Confirm full reset',
129
+ resetUseWarning: 'This consumes one credit and resets weekly + 5-hour limits. This interface cannot undo it. Confirmation expires in 60 seconds.',
130
+ resetUseAcknowledge: 'I understand that one credit will be consumed.',
131
+ resetUseConfirm: 'Consume 1 reset',
132
+ resetUseSuccess: 'Reset confirmed. Usage refreshed.',
133
+ resetCreditFull: 'Full reset',
134
+ resetCreditExpires: 'Expires {date}',
135
+ resetCreditExpiryUnknown: 'Expiry date unavailable',
107
136
  externalUsageTitle: 'Built-in provider usage',
108
137
  externalUsageConnected: 'API key configured',
109
138
  externalUsageNotConfigured: 'Not configured',
@@ -276,6 +305,35 @@ export const zh = {
276
305
  usageColorPaceHint: '用量领先时间进度 {allowance} 个百分点时变黄;已用达到 90% 时优先变红。自动保存到当前浏览器,仅改变配色。',
277
306
  usageColorRemainingHint: '已用达到 90% 时变红,不显示黄色节奏警告。可靠的时间标记仍保留,自动保存到当前浏览器。',
278
307
  usagePlan: '计划:{plan}',
308
+ resetCreditsTitle: '用量限制重置',
309
+ resetCreditsAvailable: '可用 {count} 次',
310
+ resetCreditsError: '用量限制重置查询失败:{message}',
311
+ resetCreditsErrorFixed: '用量限制重置暂不可用,请刷新用量后重试。',
312
+ resetCreditReadOnly: '只读。此页面不能消耗 Claude 的重置额度。',
313
+ resetCreditReadOnlyLabel: '只读',
314
+ resetCreditAvailable: '可用',
315
+ resetCreditNotUsable: '暂不可用',
316
+ resetCreditPaused: '已暂停',
317
+ resetCreditExhausted: '已用尽',
318
+ resetCreditExpired: '已过期',
319
+ resetCreditRemaining: '剩余 {left} / {total}',
320
+ resetCreditLeft: '剩余 {left}',
321
+ resetCreditRemainingUnknown: '剩余次数不可用',
322
+ resetCreditCooldownUntil: '{date} 后可用',
323
+ resetUseButton: '使用…',
324
+ resetUseChecking: '正在检查…',
325
+ resetUseGuard: '每周用量达到 80% 后才可使用此重置。',
326
+ resetUseRestart: '缺少重置详情。请重启 DSH、重新加载页面并刷新用量。',
327
+ resetUseRefresh: '请刷新用量以验证当前限制和重置可用性。',
328
+ resetUseReady: '使用此最早到期的重置额度,操作前需要确认。',
329
+ resetUseConfirmTitle: '确认完整重置',
330
+ resetUseWarning: '将消耗一次额度并重置每周和 5 小时限制,无法撤销。确认将在 60 秒后过期。',
331
+ resetUseAcknowledge: '我理解将消耗一次额度。',
332
+ resetUseConfirm: '消耗一次重置',
333
+ resetUseSuccess: '重置已确认,用量已刷新。',
334
+ resetCreditFull: '完整重置',
335
+ resetCreditExpires: '{date} 到期',
336
+ resetCreditExpiryUnknown: '到期时间不可用',
279
337
  externalUsageTitle: '内置供应商用量',
280
338
  externalUsageConnected: '已配置 API 密钥',
281
339
  externalUsageNotConfigured: '未配置',
@@ -0,0 +1,3 @@
1
+ export declare const providerSettingsCss = "\n.dsh-subscription-manager {\n box-sizing: border-box;\n padding: 0;\n border: 0;\n border-radius: var(--dsw-radius-panel, 16px);\n background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1));\n color: var(--dsw-alias-label-primary);\n box-shadow: var(--dsw-elevation-prominent, 0 20px 70px #0004);\n font-family: inherit;\n font-size: 13px;\n line-height: 1.5;\n}\n.dsh-subscriptions-settings {\n font-family: inherit;\n font-size: 13px;\n line-height: 1.5;\n}\n.dsh-subscription-manager::backdrop {\n background: var(--dsw-alias-bg-mask-1, #0006);\n backdrop-filter: var(--dsw-mask-blur, none);\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) h2 {\n font-size: 16px;\n line-height: 24px;\n font-weight: 500;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) h3 {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) strong,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) .dsh-subscription-label {\n font-size: 13px;\n line-height: 1.5;\n font-weight: 500;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) legend {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) small,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) .dsh-subscription-hint,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) [role=\"status\"] {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) [role=\"alert\"] {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary, #b42318);\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input:not([type=\"checkbox\"]),\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) select {\n box-sizing: border-box;\n min-width: 0;\n height: 34px;\n padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4, var(--dsw-alias-border-l2));\n border-radius: var(--dsw-radius-md, 8px);\n background: var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-1));\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 13px;\n font-weight: 400;\n line-height: 1.5;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input::placeholder {\n color: var(--dsw-alias-label-tertiary);\n opacity: 1;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input:not([type=\"checkbox\"]):focus-visible,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) select:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-state-business-primary, var(--dsw-alias-brand-primary));\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input:not([type=\"checkbox\"]):disabled,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) select:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input[aria-invalid=\"true\"] {\n border-color: var(--dsw-alias-state-error-primary, #b42318);\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) option {\n background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1));\n color: var(--dsw-alias-label-primary);\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) label:has(> input[type=\"checkbox\"]) {\n display: flex;\n align-items: flex-start;\n gap: 6px;\n font-size: 14px;\n line-height: 20px;\n cursor: pointer;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input[type=\"checkbox\"] {\n flex: 0 0 auto;\n width: 16px;\n height: 16px;\n margin: 2px 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: inherit;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) label:has(> input[type=\"checkbox\"]:disabled) {\n cursor: default;\n opacity: 0.5;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n min-height: 28px;\n padding: 0 10px;\n border: 0.5px solid var(--dsw-alias-border-l3, var(--dsw-alias-border-l2));\n border-radius: var(--dsw-radius-sm, 6px);\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n line-height: 18px;\n cursor: pointer;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-3));\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button:active:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-bg-layer-3));\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button:disabled {\n opacity: 0.4;\n cursor: default;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button.dsh-subscription-quiet {\n border-color: transparent;\n color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) :is(footer, .dsh-subscription-dialog-actions) button {\n min-height: 34px;\n padding: 0 14px;\n border-radius: var(--dsw-radius-md, 8px);\n font-size: 13px;\n line-height: 1.5;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button.dsh-subscription-primary {\n border-color: transparent;\n background: var(--dsw-alias-button-primary-fill, var(--dsw-alias-label-primary));\n color: var(--dsw-alias-label-primary-foreground, var(--dsw-alias-bg-layer-1));\n font-weight: 500;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button.dsh-subscription-primary:hover:not(:disabled) {\n background: var(--dsw-alias-button-primary-hover, var(--dsw-alias-label-secondary));\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) button:focus-visible,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) input[type=\"checkbox\"]:focus-visible,\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) summary:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: 2px;\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) summary {\n border-radius: var(--dsw-radius-sm, 6px);\n}\n:is(.dsh-subscription-manager, .dsh-subscriptions-settings) summary:hover {\n color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));\n}\n";
2
+ /** Composer controls retain their own geometry, separate from settings forms. */
3
+ export declare const subscriptionChromeCss = "\n.dsh-subscription-usage-pill { corner-shape: round; }\n.dsh-subscription-usage-panel {\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n backdrop-filter: var(--dsw-menu-backdrop-filter, none);\n}\n.dsh-subscription-speed button:hover:not(:disabled) {\n --dsh-subscription-speed-hover: var(--dsw-alias-interactive-bg-hover);\n}\n.dsh-subscription-speed button:active:not(:disabled) {\n --dsh-subscription-speed-hover: var(--dsw-alias-interactive-bg-active);\n}\n.dsh-subscription-speed button:disabled { opacity: 0.4; cursor: default; }\n.dsh-subscription-speed button:focus-visible,\n.dsh-subscription-usage-pill:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));\n outline-offset: 2px;\n}\n";