dsh-codex-subscription 1.12.1 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -220,6 +220,148 @@ window.__ModuleLoader__.load({
220
220
  }
221
221
  }
222
222
  //#endregion
223
+ //#region src/preference-controller.js
224
+ const CHANNEL$1 = "/codex-subscription";
225
+ const unwrap$1 = (response) => {
226
+ if (!response?.ok) throw new Error(response?.error?.message ?? "Codex RPC failed");
227
+ return response.value;
228
+ };
229
+ function createPreferenceController(scope, rpc) {
230
+ let updating = false;
231
+ let error = false;
232
+ let fallbackStatus = "loading";
233
+ let fallback;
234
+ let pendingPatch;
235
+ let failedPatch;
236
+ let generation = 0;
237
+ let contextModels = [];
238
+ let verbosityModels = [];
239
+ const nativeSnapshot = () => scope.getSnapshot();
240
+ const read = () => {
241
+ const native = nativeSnapshot();
242
+ const current = native.status === "ready" ? native : fallbackStatus === "ready" ? fallback : native;
243
+ const value = pendingPatch === void 0 ? current.value : {
244
+ ...current.value,
245
+ ...pendingPatch
246
+ };
247
+ return Object.freeze({
248
+ status: current.status,
249
+ quickQuotaMode: normalizeQuickQuotaMode(value?.[QUICK_QUOTA_MODE_FIELD], value?.[LEGACY_QUICK_QUOTA_FIELD]),
250
+ searchProvider: normalizeSearchProvider(value?.[SEARCH_PROVIDER_FIELD]),
251
+ speedMode: normalizeSpeedMode(value?.[SPEED_MODE_FIELD]),
252
+ outputVerbosity: normalizeOutputVerbosity(value?.[OUTPUT_VERBOSITY_FIELD]),
253
+ contextMode: normalizeContextMode(value?.[CONTEXT_MODE_FIELD]),
254
+ customContextWindow: normalizeCustomContextWindow(value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
255
+ customContextWindows: Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [modelKey, normalizeCustomContextWindow(value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])])),
256
+ contextModels,
257
+ verbosityModels,
258
+ writable: !updating && current.status === "ready" && current.writable === true,
259
+ saving: updating,
260
+ error
261
+ });
262
+ };
263
+ let snapshot = read();
264
+ const listeners = /* @__PURE__ */ new Set();
265
+ const publish = () => {
266
+ snapshot = read();
267
+ for (const listener of listeners) listener();
268
+ };
269
+ const disposeScope = scope.subscribe(() => {
270
+ error = false;
271
+ if (!updating) failedPatch = void 0;
272
+ publish();
273
+ });
274
+ const acceptFallback = (value) => {
275
+ contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
276
+ verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
277
+ fallbackStatus = "ready";
278
+ fallback = {
279
+ status: "ready",
280
+ value: {
281
+ [QUICK_QUOTA_MODE_FIELD]: normalizeQuickQuotaMode(value?.[QUICK_QUOTA_MODE_FIELD], value?.[LEGACY_QUICK_QUOTA_FIELD]),
282
+ [SEARCH_PROVIDER_FIELD]: normalizeSearchProvider(value?.[SEARCH_PROVIDER_FIELD]),
283
+ [SPEED_MODE_FIELD]: normalizeSpeedMode(value?.[SPEED_MODE_FIELD]),
284
+ [OUTPUT_VERBOSITY_FIELD]: normalizeOutputVerbosity(value?.[OUTPUT_VERBOSITY_FIELD]),
285
+ [CONTEXT_MODE_FIELD]: normalizeContextMode(value?.[CONTEXT_MODE_FIELD]),
286
+ [CUSTOM_CONTEXT_WINDOW_FIELD]: normalizeCustomContextWindow(value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
287
+ ...Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [field, normalizeCustomContextWindow(value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])]))
288
+ },
289
+ writable: value?.writable === true
290
+ };
291
+ };
292
+ const load = async () => {
293
+ const current = ++generation;
294
+ updating = false;
295
+ pendingPatch = void 0;
296
+ fallbackStatus = "loading";
297
+ fallback = void 0;
298
+ error = false;
299
+ publish();
300
+ try {
301
+ const value = unwrap$1(await rpc.call(CHANNEL$1, "preferences/status", {}));
302
+ if (current !== generation) return;
303
+ if (nativeSnapshot().status === "ready") {
304
+ contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
305
+ verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
306
+ } else acceptFallback(value);
307
+ publish();
308
+ } catch {
309
+ if (current !== generation || nativeSnapshot().status === "ready") return;
310
+ fallbackStatus = "unavailable";
311
+ publish();
312
+ }
313
+ };
314
+ const set = async (patch) => {
315
+ if (snapshot.status !== "ready" || snapshot.writable !== true) return;
316
+ const current = ++generation;
317
+ const entries = Object.entries(patch);
318
+ updating = true;
319
+ pendingPatch = patch;
320
+ error = false;
321
+ failedPatch = void 0;
322
+ publish();
323
+ try {
324
+ if (nativeSnapshot().status === "ready") {
325
+ for (const [field, value] of entries) {
326
+ if (current !== generation) return;
327
+ await scope.set(field, value);
328
+ }
329
+ if (current !== generation) return;
330
+ const accepted = nativeSnapshot().value;
331
+ error = entries.some(([field, value]) => accepted?.[field] !== value);
332
+ pendingPatch = void 0;
333
+ } else {
334
+ const value = unwrap$1(await rpc.call(CHANNEL$1, "preferences/update", patch));
335
+ if (current !== generation) return;
336
+ acceptFallback(value);
337
+ pendingPatch = void 0;
338
+ }
339
+ } catch {
340
+ if (current === generation) {
341
+ pendingPatch = void 0;
342
+ error = true;
343
+ failedPatch = patch;
344
+ }
345
+ } finally {
346
+ if (current === generation) {
347
+ updating = false;
348
+ publish();
349
+ }
350
+ }
351
+ };
352
+ return {
353
+ getSnapshot: () => snapshot,
354
+ subscribe: (listener) => {
355
+ listeners.add(listener);
356
+ return () => listeners.delete(listener);
357
+ },
358
+ load,
359
+ set,
360
+ retry: () => failedPatch === void 0 ? load() : set(failedPatch),
361
+ dispose: disposeScope
362
+ };
363
+ }
364
+ //#endregion
223
365
  //#region src/client.jsx
224
366
  const inject = [
225
367
  "slots",
@@ -246,7 +388,6 @@ window.__ModuleLoader__.load({
246
388
  deviceLogin: "设备代码登录",
247
389
  logout: "退出登录",
248
390
  addAccount: "添加账号",
249
- accountLabel: "账号名称",
250
391
  switchAccount: "切换",
251
392
  removeAccount: "移除",
252
393
  removeConfirm: "确认移除",
@@ -262,12 +403,17 @@ window.__ModuleLoader__.load({
262
403
  loadFailed: "无法读取账户状态。",
263
404
  accountRetry: "重试",
264
405
  diagnostics: "支持诊断",
265
- diagnosticsHint: "生成不含凭据、账号标识和授权时间的诊断信息。",
406
+ diagnosticsHint: "仅含环境与请求状态,不含凭据。",
407
+ diagnosticsOpen: "展开",
408
+ diagnosticsClose: "收起",
266
409
  diagnosticsLoad: "生成诊断",
267
410
  diagnosticsCopy: "复制诊断",
268
411
  diagnosticsCopied: "已复制",
269
412
  diagnosticsFailed: "无法生成诊断信息。",
270
413
  feedbackOpen: "反馈问题",
414
+ showEmail: "显示完整邮箱",
415
+ hideEmail: "隐藏邮箱",
416
+ emailUnavailable: "邮箱不可用",
271
417
  searchTitle: "搜索来源",
272
418
  searchScope: "自动按当前会话模型分流;手动选择会覆盖所有模型和会话。",
273
419
  searchAuto: "自动",
@@ -299,21 +445,22 @@ window.__ModuleLoader__.load({
299
445
  creditsUnit: "credits",
300
446
  unlimited: "不限额",
301
447
  monthlyCreditLimit: "Credits 月度消费上限",
302
- resetCredits: "可用额度重置次数",
303
- resetCreditsValue: "{count} ",
304
- resetUse: "使用重置",
305
- resetPreparing: "正在读取重置详情…",
448
+ resetCredits: "额度重置",
449
+ resetCreditsValue: "{count} 次可用",
450
+ resetCreditDefaultName: "额度重置",
451
+ resetUse: "使用",
452
+ resetPreparing: "准备中…",
306
453
  resetConfirmTitle: "确认使用额度重置",
307
- resetWarning: " ChatGPT 执行重置,将立即消耗 1 次且无法撤销。",
308
- resetEarlyWarning: "当前模型额度尚未用尽;ChatGPT 可能执行重置,也可能判定暂无需重置且不消耗次数。",
454
+ resetWarning: "执行后会消耗 1 次,且无法撤销。",
455
+ resetEarlyWarning: "当前额度未用尽,服务可能不执行重置。",
309
456
  resetAcknowledge: "我知道这次操作可能立即消耗 1 次重置",
310
457
  resetCreditExpires: "到期:{value}",
311
458
  resetCreditExpiryUnknown: "到期时间未提供",
312
459
  resetCreditExpiryLoading: "正在读取到期时间…",
313
460
  resetCreditExpiryFailed: "无法读取到期时间",
314
- resetWait: "请再等待 {count} 秒",
315
- resetFinal: "消耗 1 次并重置额度",
316
- resetUsing: "正在重置…",
461
+ resetWait: "请等待 {count} 秒",
462
+ resetFinal: "确认使用",
463
+ resetUsing: "使用中…",
317
464
  resetSuccess: "额度重置已完成。",
318
465
  resetNothing: "当前没有可重置的额度,未消耗新的重置次数。",
319
466
  resetNoCredit: "没有可用的额度重置。",
@@ -326,7 +473,7 @@ window.__ModuleLoader__.load({
326
473
  resetAcknowledgeRequired: "请先确认已了解这次操作可能消耗重置次数。",
327
474
  resetAccountChanged: "登录账号已变更,请重新开始。",
328
475
  resetUncertain: "服务端返回结果不确定。请再次确认,插件会复用同一个请求,不会另外发起一次重置。",
329
- creditsNote: "仅显示 Codex 为此账户或工作区实际返回的额外 Credits、消费上限或额度重置次数;三者不是同一项。",
476
+ creditsNote: "额外 Credits、消费上限、重置次数分别显示。",
330
477
  creditsUsed: "已用 {used} / {limit} credits",
331
478
  spendReached: "Credits 月度消费上限已用尽。",
332
479
  unavailable: "暂无数据",
@@ -429,7 +576,6 @@ window.__ModuleLoader__.load({
429
576
  deviceLogin: "Device-code sign-in",
430
577
  logout: "Sign out",
431
578
  addAccount: "Add account",
432
- accountLabel: "Account name",
433
579
  switchAccount: "Switch",
434
580
  removeAccount: "Remove",
435
581
  removeConfirm: "Confirm remove",
@@ -445,12 +591,17 @@ window.__ModuleLoader__.load({
445
591
  loadFailed: "Could not read account status.",
446
592
  accountRetry: "Retry",
447
593
  diagnostics: "Support diagnostics",
448
- diagnosticsHint: "Create a report without credentials, account identifiers, or authorization timestamps.",
594
+ diagnosticsHint: "Environment and request status only; no credentials.",
595
+ diagnosticsOpen: "Show",
596
+ diagnosticsClose: "Hide",
449
597
  diagnosticsLoad: "Create report",
450
598
  diagnosticsCopy: "Copy report",
451
599
  diagnosticsCopied: "Copied",
452
600
  diagnosticsFailed: "Could not create diagnostics.",
453
601
  feedbackOpen: "Report a problem",
602
+ showEmail: "Show full email",
603
+ hideEmail: "Hide email",
604
+ emailUnavailable: "Email unavailable",
454
605
  searchTitle: "Search source",
455
606
  searchScope: "Auto follows the current session model; an explicit choice overrides every model and session.",
456
607
  searchAuto: "Auto",
@@ -482,21 +633,22 @@ window.__ModuleLoader__.load({
482
633
  creditsUnit: "credits",
483
634
  unlimited: "Unlimited",
484
635
  monthlyCreditLimit: "Monthly Credits spending cap",
485
- resetCredits: "Available quota resets",
636
+ resetCredits: "Quota resets",
486
637
  resetCreditsValue: "{count} available",
487
- resetUse: "Use reset",
488
- resetPreparing: "Reading reset details…",
638
+ resetCreditDefaultName: "Quota reset",
639
+ resetUse: "Use",
640
+ resetPreparing: "Preparing…",
489
641
  resetConfirmTitle: "Confirm quota reset",
490
- resetWarning: "If ChatGPT performs the reset, one reset is consumed immediately and cannot be restored.",
491
- resetEarlyWarning: "No model quota is exhausted. ChatGPT may reset it, or report that nothing needs resetting without consuming a reset.",
642
+ resetWarning: "This consumes one reset and cannot be undone.",
643
+ resetEarlyWarning: "Quota remains. The service may decline the reset.",
492
644
  resetAcknowledge: "I understand this may consume one reset now",
493
645
  resetCreditExpires: "Expires {value}",
494
646
  resetCreditExpiryUnknown: "Expiration time not provided",
495
647
  resetCreditExpiryLoading: "Reading expiration…",
496
648
  resetCreditExpiryFailed: "Could not read expiration",
497
- resetWait: "Wait {count} more seconds",
498
- resetFinal: "Consume one reset",
499
- resetUsing: "Resetting…",
649
+ resetWait: "Wait {count} seconds",
650
+ resetFinal: "Confirm use",
651
+ resetUsing: "Using…",
500
652
  resetSuccess: "Quota reset completed.",
501
653
  resetNothing: "There is currently nothing to reset; no new reset was consumed.",
502
654
  resetNoCredit: "No quota reset is available.",
@@ -509,7 +661,7 @@ window.__ModuleLoader__.load({
509
661
  resetAcknowledgeRequired: "Confirm that you understand this may consume a reset.",
510
662
  resetAccountChanged: "The signed-in account changed. Start again.",
511
663
  resetUncertain: "The server result is uncertain. Confirm again to check the same request; the plugin will not start a separate reset.",
512
- creditsNote: "Shows only extra Credits, spending caps, or quota resets returned for this account or workspace; these are separate items.",
664
+ creditsNote: "Extra Credits, spending caps, and resets are separate items.",
513
665
  creditsUsed: "{used} / {limit} credits used",
514
666
  spendReached: "The monthly Credits spending cap has been reached.",
515
667
  unavailable: "No data yet",
@@ -615,14 +767,15 @@ window.__ModuleLoader__.load({
615
767
  .codexSubscriptionContext{display:flex;flex-direction:column;gap:8px}.codexSubscriptionContextHead{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.codexSubscriptionContextCopy{display:flex;min-width:0;flex:1;flex-direction:column;gap:2px}.codexSubscriptionContextHint{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionContextTrigger{height:32px;min-width:108px;display:inline-flex;align-items:center;justify-content:space-between;gap:10px;padding:0 10px 0 12px;border:0;border-radius:999px;outline:0;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;cursor:pointer}.codexSubscriptionContextTrigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.codexSubscriptionContextTrigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.codexSubscriptionContextTrigger:disabled{color:var(--dsw-alias-label-dimmed);cursor:not-allowed}.codexSubscriptionContextTrigger svg{color:var(--dsw-alias-label-tertiary);transition:transform 120ms var(--ds-ease-in-out)}.codexSubscriptionContextTrigger[aria-expanded=true] svg{transform:rotate(180deg)}.codexSubscriptionContextModels{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionContextModel{min-height:42px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-bottom:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionContextModel:last-child{border-bottom:0}.codexSubscriptionContextModelCopy{display:flex;min-width:0;flex-direction:column}.codexSubscriptionContextModelCopy strong{font-size:12px;line-height:18px;font-weight:500}.codexSubscriptionContextModelCopy span{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionContextInput{width:116px}
616
768
  .codexSubscriptionSwitch{position:relative;flex:0 0 auto;width:32px;height:18px;padding:0;border:1px solid var(--dsw-alias-border-l3);border-radius:999px;background:var(--dsw-alias-bg-module-platform);cursor:pointer}.codexSubscriptionSwitch:disabled{cursor:not-allowed;opacity:.5}.codexSubscriptionSwitch[aria-checked=true]{background:var(--dsw-alias-label-secondary);border-color:var(--dsw-alias-label-secondary)}.codexSubscriptionSwitchKnob{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:var(--dsw-alias-bg-layer-1);transition:transform 120ms var(--ds-ease-in-out)}.codexSubscriptionSwitch[aria-checked=true] .codexSubscriptionSwitchKnob{transform:translateX(14px)}
617
769
  .codexSubscriptionSearch{display:flex;flex-direction:column;gap:7px}.codexSubscriptionSearchChoices{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:6px}.codexSubscriptionSearchChoice{display:grid;grid-template-columns:14px minmax(0,1fr);align-items:center;column-gap:8px;min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);padding:9px 10px;text-align:left;cursor:pointer}.codexSubscriptionSearchChoice:has(input:disabled){cursor:not-allowed;opacity:.5}.codexSubscriptionSearchChoice:has(input:checked){border-color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.codexSubscriptionSearchChoice:has(input:focus-visible){outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}.codexSubscriptionSearchInput{width:14px;height:14px;margin:0;accent-color:var(--dsw-alias-label-primary);cursor:inherit}.codexSubscriptionSearchCopy{display:block;min-width:0;pointer-events:none}.codexSubscriptionSearchCopy strong,.codexSubscriptionSearchCopy span{display:block}.codexSubscriptionSearchCopy strong{font-size:12px;line-height:18px;font-weight:500;color:var(--dsw-alias-label-secondary)}.codexSubscriptionSearchChoice:has(input:checked) strong{color:var(--dsw-alias-label-primary)}.codexSubscriptionSearchCopy span{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionDivider{height:1px;background:var(--dsw-alias-border-l2)}
770
+ .codexSubscriptionQuotaModes[data-saving=true] .codexSubscriptionQuotaMode:has(input:disabled){cursor:wait;opacity:1}.codexSubscriptionSearchChoices[data-saving=true] .codexSubscriptionSearchChoice:has(input:disabled){cursor:wait;opacity:1}
618
771
  .codexSubscriptionAccountRow,.codexSubscriptionSectionHead{display:flex;align-items:center;justify-content:space-between;gap:12px}.codexSubscriptionStatus{display:flex;align-items:center;gap:8px;font-size:14px;line-height:22px;font-weight:500}
619
- .codexSubscriptionAccounts{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionAccount{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:42px;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:13px}.codexSubscriptionAccount:last-child{border-bottom:0}.codexSubscriptionAccount[data-active=true]>span{font-weight:600}.codexSubscriptionFlow label{display:flex;flex-direction:column;gap:6px;font-size:12px;color:var(--dsw-alias-label-secondary)}
772
+ .codexSubscriptionAccounts{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionAccount{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:42px;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:13px}.codexSubscriptionAccount:last-child{border-bottom:0}.codexSubscriptionAccount[data-active=true] .codexSubscriptionEmail,.codexSubscriptionAccount[data-active=true]>span{font-weight:600}.codexSubscriptionEmail{max-width:100%;overflow:hidden;padding:2px 4px;border:0;border-radius:5px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.codexSubscriptionEmail:hover{background:var(--dsw-alias-interactive-bg-hover)}.codexSubscriptionEmail:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:1px}.codexSubscriptionFlow label{display:flex;flex-direction:column;gap:6px;font-size:12px;color:var(--dsw-alias-label-secondary)}
620
773
  .codexSubscriptionDot{width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-label-dimmed)}.codexSubscriptionDot[data-state=connected]{background:var(--dsw-alias-state-success-primary)}.codexSubscriptionDot[data-state=disconnected]{background:var(--dsw-alias-state-error-primary)}
621
774
  .codexSubscriptionActions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.codexSubscriptionFlow{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border-radius:10px;background:var(--dsw-alias-bg-module-platform)}
622
775
  .codexSubscriptionFlow p{font-size:13px;line-height:20px;color:var(--dsw-alias-label-secondary)}.codexSubscriptionCode{width:max-content;max-width:100%;font:600 16px/22px ui-monospace,SFMono-Regular,Consolas,monospace;letter-spacing:.08em;overflow-wrap:anywhere}
623
776
  .codexSubscriptionError{font-size:13px;line-height:20px;color:var(--dsw-alias-state-error-primary)}.codexSubscriptionInput{width:100%;box-sizing:border-box}
624
777
  .codexSubscriptionRecover{display:flex;align-items:center;justify-content:space-between;gap:12px}.codexSubscriptionRecover .codexSubscriptionError{flex:1}.codexSubscriptionRecover button{flex:0 0 auto}
625
- .codexSubscriptionDiagnostics pre{max-height:240px;margin:0;padding:10px 12px;border-radius:8px;background:var(--dsw-alias-bg-module-platform);overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font:11px/17px ui-monospace,SFMono-Regular,Consolas,monospace;color:var(--dsw-alias-label-secondary)}.codexSubscriptionLink{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:32px;padding:0 13px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;text-decoration:none;white-space:nowrap}.codexSubscriptionLink:hover{background:var(--dsw-alias-bg-module-platform)}.codexSubscriptionLink:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}
778
+ .codexSubscriptionDiagnostics{padding:10px 12px;gap:8px;background:transparent;color:var(--dsw-alias-label-secondary)}.codexSubscriptionDiagnostics pre{max-height:240px;margin:0;padding:10px 12px;border-radius:8px;background:var(--dsw-alias-bg-module-platform);overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font:11px/17px ui-monospace,SFMono-Regular,Consolas,monospace;color:var(--dsw-alias-label-secondary)}.codexSubscriptionDiagnostics .codexSubscriptionNote{font-size:11px;line-height:17px}.codexSubscriptionDiagnosticsToggle{min-height:28px!important;padding:0 8px!important;border:0!important;color:var(--dsw-alias-label-tertiary)!important}.codexSubscriptionDiagnosticsToggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.codexSubscriptionLink{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:32px;padding:0 13px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;text-decoration:none;white-space:nowrap}.codexSubscriptionLink:hover{background:var(--dsw-alias-bg-module-platform)}.codexSubscriptionLink:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}
626
779
  .codexSubscriptionSectionTitle{display:flex;flex:1;min-width:0;flex-direction:column;gap:2px}.codexSubscriptionFreshness{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
627
780
  .codexSubscriptionRefresh{flex:0 0 auto;min-width:72px;width:max-content;white-space:nowrap!important;word-break:keep-all!important;overflow-wrap:normal!important;writing-mode:horizontal-tb!important}.codexSubscriptionRefresh *{white-space:nowrap!important;word-break:keep-all!important;writing-mode:horizontal-tb!important}
628
781
  .codexSubscriptionEmpty{padding:18px;border:1px dashed var(--dsw-alias-border-l3);border-radius:10px;text-align:center;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}
@@ -632,7 +785,7 @@ window.__ModuleLoader__.load({
632
785
  .codexSubscriptionLimit progress::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.codexSubscriptionLimit progress::-webkit-progress-value{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}.codexSubscriptionLimit progress::-moz-progress-bar{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}.codexSubscriptionLimitMeta{display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
633
786
  .codexSubscriptionCreditSection{display:flex;flex-direction:column;gap:7px}.codexSubscriptionCreditNote{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionCreditRows{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px}.codexSubscriptionCreditBalance,.codexSubscriptionSpendLimit{min-width:0;border-radius:10px;padding:12px 14px;background:var(--dsw-alias-bg-module-platform)}
634
787
  .codexSubscriptionCreditBalance{display:flex;flex-direction:column;gap:6px}.codexSubscriptionCreditBalance span,.codexSubscriptionCreditLabel{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}.codexSubscriptionCreditBalance strong{font:600 18px/24px ui-monospace,SFMono-Regular,Consolas,monospace;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
635
- .codexSubscriptionResetSummary{display:flex;align-items:center;justify-content:space-between;gap:10px}.codexSubscriptionResetMeta{display:flex;min-width:0;flex-direction:column;gap:1px}.codexSubscriptionResetBalance{display:flex;flex-direction:column;gap:8px}.codexSubscriptionResetBalance .codexSubscriptionActions{justify-content:flex-start}.codexSubscriptionResetFlow{display:flex;flex-direction:column;gap:10px;border-top:1px solid var(--dsw-alias-border-l2);padding-top:10px}.codexSubscriptionResetFlow h4{margin:0;font-size:13px;line-height:20px;font-weight:500}.codexSubscriptionResetWarning{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}.codexSubscriptionResetExpiry{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionResetCheck{display:flex;align-items:flex-start;gap:8px;padding:9px 10px;border-radius:8px;background:var(--dsw-alias-bg-module-platform);font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary);cursor:pointer}.codexSubscriptionResetCheck input{margin:3px 0 0;accent-color:var(--dsw-alias-label-primary)}.codexSubscriptionResetFinal{border-color:var(--dsw-alias-state-error-primary)!important;color:var(--dsw-alias-state-error-primary)!important}.codexSubscriptionResetResult{font-size:12px;line-height:18px;color:var(--dsw-alias-state-success-primary)}
788
+ .codexSubscriptionCreditRows{display:flex;flex-direction:column;gap:6px}.codexSubscriptionResetSummary{display:flex;align-items:center;justify-content:space-between;gap:10px}.codexSubscriptionResetMeta{display:flex;min-width:0;flex-direction:column;gap:1px}.codexSubscriptionResetBalance{display:flex;flex-direction:column;gap:8px}.codexSubscriptionResetCard{display:flex;align-items:center;justify-content:space-between;gap:10px;min-width:0;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-bg-module-platform)}.codexSubscriptionResetCard .codexSubscriptionResetMeta{flex:1}.codexSubscriptionResetCard strong{overflow:hidden;font-size:12px;line-height:18px;font-weight:500;text-overflow:ellipsis;white-space:nowrap}.codexSubscriptionResetCard .codexSubscriptionActions{flex:0 0 auto}.codexSubscriptionResetCard .codexSubscriptionResetUse{min-height:28px;padding:0 10px}.codexSubscriptionResetBalance .codexSubscriptionActions{justify-content:flex-start}.codexSubscriptionResetFlow{display:flex;flex-direction:column;gap:10px;border-top:1px solid var(--dsw-alias-border-l2);padding-top:10px}.codexSubscriptionResetFlow h4{margin:0;font-size:13px;line-height:20px;font-weight:500}.codexSubscriptionResetWarning{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}.codexSubscriptionResetExpiry{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionResetCheck{display:flex;align-items:flex-start;gap:8px;padding:9px 10px;border-radius:8px;background:var(--dsw-alias-bg-module-platform);font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary);cursor:pointer}.codexSubscriptionResetCheck input{margin:3px 0 0;accent-color:var(--dsw-alias-label-primary)}.codexSubscriptionResetFinal{border-color:var(--dsw-alias-state-error-primary)!important;color:var(--dsw-alias-state-error-primary)!important}.codexSubscriptionResetResult{font-size:12px;line-height:18px;color:var(--dsw-alias-state-success-primary)}
636
789
  .codexSubscriptionResetUse:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.codexSubscriptionResetUse:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:1px}
637
790
  .codexSubscriptionSpendLimit{display:flex;flex-direction:column;gap:8px}.codexSubscriptionSpendTop{display:flex;align-items:baseline;justify-content:space-between;gap:12px}.codexSubscriptionSpendTop strong{font:600 16px/22px ui-monospace,SFMono-Regular,Consolas,monospace;font-variant-numeric:tabular-nums}.codexSubscriptionSpendLimit progress{width:100%;height:6px;border:0;border-radius:999px;overflow:hidden;background:var(--dsw-alias-border-l3);accent-color:var(--dsw-alias-brand-primary,#3964fe);-webkit-appearance:none;appearance:none}.codexSubscriptionSpendLimit progress::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.codexSubscriptionSpendLimit progress::-webkit-progress-value{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}.codexSubscriptionSpendLimit progress::-moz-progress-bar{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}
638
791
  .codexComposerQuota{display:inline-flex;align-items:center;flex:0 0 auto;height:28px;box-sizing:border-box;padding:0;color:var(--dsw-alias-label-secondary);font-family:inherit;font-size:12px;line-height:20px;font-weight:500;font-variant-numeric:tabular-nums;white-space:nowrap;user-select:none}.codexComposerQuotaBar{display:block;width:40px;height:4px;border:0;border-radius:999px;overflow:hidden;background:var(--dsw-alias-border-l3);accent-color:var(--dsw-alias-label-secondary);-webkit-appearance:none;appearance:none}.codexComposerQuotaBar::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.codexComposerQuotaBar::-webkit-progress-value{background:var(--dsw-alias-label-secondary);border-radius:999px}.codexComposerQuotaBar::-moz-progress-bar{background:var(--dsw-alias-label-secondary);border-radius:999px}
@@ -664,6 +817,12 @@ window.__ModuleLoader__.load({
664
817
  return response.value;
665
818
  };
666
819
  const fill = (text, values) => Object.entries(values).reduce((next, [key, value]) => next.replace(`{${key}}`, String(value)), text);
820
+ const maskEmail = (value) => {
821
+ if (typeof value !== "string" || !value.includes("@")) return "••••";
822
+ const [local, domain] = value.split("@", 2);
823
+ if (local.length <= 2) return `${local.slice(0, 1)}••@${domain}`;
824
+ return `${local[0]}•••${local.at(-1)}@${domain}`;
825
+ };
667
826
  const hours = (seconds) => Math.round(seconds / 3600 * 10) / 10;
668
827
  const percent = (value) => Number(value).toLocaleString(void 0, { maximumFractionDigits: 1 });
669
828
  const isApproximateWindow = (seconds, expected) => seconds >= expected * .95 && seconds <= expected * 1.05;
@@ -1108,131 +1267,6 @@ window.__ModuleLoader__.load({
1108
1267
  ]
1109
1268
  });
1110
1269
  }
1111
- function createPreferenceController(scope, rpc) {
1112
- let updating = false;
1113
- let error = false;
1114
- let fallbackStatus = "loading";
1115
- let fallback;
1116
- let failedPatch;
1117
- let generation = 0;
1118
- let contextModels = [];
1119
- let verbosityModels = [];
1120
- const nativeSnapshot = () => scope.getSnapshot();
1121
- const read = () => {
1122
- const native = nativeSnapshot();
1123
- const current = native.status === "ready" ? native : fallbackStatus === "ready" ? fallback : native;
1124
- return Object.freeze({
1125
- status: updating ? "updating" : current.status,
1126
- quickQuotaMode: normalizeQuickQuotaMode(current.value?.[QUICK_QUOTA_MODE_FIELD], current.value?.[LEGACY_QUICK_QUOTA_FIELD]),
1127
- searchProvider: normalizeSearchProvider(current.value?.[SEARCH_PROVIDER_FIELD]),
1128
- speedMode: normalizeSpeedMode(current.value?.[SPEED_MODE_FIELD]),
1129
- outputVerbosity: normalizeOutputVerbosity(current.value?.[OUTPUT_VERBOSITY_FIELD]),
1130
- contextMode: normalizeContextMode(current.value?.[CONTEXT_MODE_FIELD]),
1131
- customContextWindow: normalizeCustomContextWindow(current.value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
1132
- customContextWindows: Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [modelKey, normalizeCustomContextWindow(current.value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])])),
1133
- contextModels,
1134
- verbosityModels,
1135
- writable: !updating && current.status === "ready" && current.writable === true,
1136
- error
1137
- });
1138
- };
1139
- let snapshot = read();
1140
- const listeners = /* @__PURE__ */ new Set();
1141
- const publish = () => {
1142
- snapshot = read();
1143
- for (const listener of listeners) listener();
1144
- };
1145
- const disposeScope = scope.subscribe(() => {
1146
- error = false;
1147
- failedPatch = void 0;
1148
- publish();
1149
- });
1150
- const acceptFallback = (value) => {
1151
- contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
1152
- verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
1153
- fallbackStatus = "ready";
1154
- fallback = {
1155
- status: "ready",
1156
- value: {
1157
- [QUICK_QUOTA_MODE_FIELD]: normalizeQuickQuotaMode(value?.[QUICK_QUOTA_MODE_FIELD], value?.[LEGACY_QUICK_QUOTA_FIELD]),
1158
- [SEARCH_PROVIDER_FIELD]: normalizeSearchProvider(value?.[SEARCH_PROVIDER_FIELD]),
1159
- [SPEED_MODE_FIELD]: normalizeSpeedMode(value?.[SPEED_MODE_FIELD]),
1160
- [OUTPUT_VERBOSITY_FIELD]: normalizeOutputVerbosity(value?.[OUTPUT_VERBOSITY_FIELD]),
1161
- [CONTEXT_MODE_FIELD]: normalizeContextMode(value?.[CONTEXT_MODE_FIELD]),
1162
- [CUSTOM_CONTEXT_WINDOW_FIELD]: normalizeCustomContextWindow(value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
1163
- ...Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [field, normalizeCustomContextWindow(value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])]))
1164
- },
1165
- writable: value?.writable === true
1166
- };
1167
- };
1168
- const load = async () => {
1169
- const current = ++generation;
1170
- updating = false;
1171
- fallbackStatus = "loading";
1172
- fallback = void 0;
1173
- error = false;
1174
- publish();
1175
- nativeSnapshot();
1176
- try {
1177
- const value = unwrap(await rpc.call(CHANNEL, "preferences/status", {}));
1178
- if (current !== generation) return;
1179
- if (nativeSnapshot().status === "ready") {
1180
- contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
1181
- verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
1182
- } else acceptFallback(value);
1183
- publish();
1184
- } catch {
1185
- if (current !== generation || nativeSnapshot().status === "ready") return;
1186
- fallbackStatus = "unavailable";
1187
- publish();
1188
- }
1189
- };
1190
- const set = async (patch) => {
1191
- if (snapshot.status !== "ready" || snapshot.writable !== true) return;
1192
- const current = ++generation;
1193
- const entries = Object.entries(patch);
1194
- updating = true;
1195
- error = false;
1196
- failedPatch = void 0;
1197
- publish();
1198
- try {
1199
- if (nativeSnapshot().status === "ready") {
1200
- for (const [field, value] of entries) {
1201
- if (current !== generation) return;
1202
- await scope.set(field, value);
1203
- }
1204
- if (current !== generation) return;
1205
- const accepted = nativeSnapshot().value;
1206
- error = entries.some(([field, value]) => accepted?.[field] !== value);
1207
- } else {
1208
- const value = unwrap(await rpc.call(CHANNEL, "preferences/update", patch));
1209
- if (current !== generation) return;
1210
- acceptFallback(value);
1211
- }
1212
- } catch {
1213
- if (current === generation) {
1214
- error = true;
1215
- failedPatch = patch;
1216
- }
1217
- } finally {
1218
- if (current === generation) {
1219
- updating = false;
1220
- publish();
1221
- }
1222
- }
1223
- };
1224
- return {
1225
- getSnapshot: () => snapshot,
1226
- subscribe: (listener) => {
1227
- listeners.add(listener);
1228
- return () => listeners.delete(listener);
1229
- },
1230
- load,
1231
- set,
1232
- retry: () => failedPatch === void 0 ? load() : set(failedPatch),
1233
- dispose: disposeScope
1234
- };
1235
- }
1236
1270
  const usePreferenceSnapshot = (preference) => (0, react.useSyncExternalStore)(preference.subscribe, preference.getSnapshot);
1237
1271
  const notifyQuickQuota = () => window.dispatchEvent(new Event(QUICK_QUOTA_REFRESH_EVENT));
1238
1272
  const formatRunway = (seconds, t) => {
@@ -1331,6 +1365,8 @@ window.__ModuleLoader__.load({
1331
1365
  }) : null]
1332
1366
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1333
1367
  className: "codexSubscriptionQuotaModes",
1368
+ "data-saving": snapshot.saving || void 0,
1369
+ "aria-busy": snapshot.saving || void 0,
1334
1370
  role: "radiogroup",
1335
1371
  "aria-label": t("quickQuotaSetting"),
1336
1372
  children: [
@@ -1375,6 +1411,8 @@ window.__ModuleLoader__.load({
1375
1411
  })]
1376
1412
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1377
1413
  className: "codexSubscriptionSearchChoices",
1414
+ "data-saving": snapshot.saving || void 0,
1415
+ "aria-busy": snapshot.saving || void 0,
1378
1416
  role: "radiogroup",
1379
1417
  "aria-label": t("searchTitle"),
1380
1418
  children: [
@@ -1885,15 +1923,37 @@ window.__ModuleLoader__.load({
1885
1923
  }) : null]
1886
1924
  });
1887
1925
  }
1926
+ function AccountEmail({ candidate, fallback, t, emailVisible, onClick }) {
1927
+ if (typeof candidate?.email !== "string" || candidate.email.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1928
+ title: t("emailUnavailable"),
1929
+ children: fallback ?? candidate?.label ?? t("emailUnavailable")
1930
+ });
1931
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1932
+ type: "button",
1933
+ className: "codexSubscriptionEmail",
1934
+ "aria-label": t(emailVisible ? "hideEmail" : "showEmail"),
1935
+ "aria-pressed": emailVisible,
1936
+ onClick,
1937
+ children: emailVisible ? candidate.email : maskEmail(candidate.email)
1938
+ });
1939
+ }
1888
1940
  function AccountCard({ rpc, t, account, setAccount, onSignedOut }) {
1889
1941
  const [flow, setFlow] = (0, react.useState)();
1890
1942
  const [manualCode, setManualCode] = (0, react.useState)("");
1891
1943
  const [adding, setAdding] = (0, react.useState)(false);
1892
- const [accountLabel, setAccountLabel] = (0, react.useState)("");
1893
1944
  const [removeId, setRemoveId] = (0, react.useState)();
1945
+ const [emailVisible, setEmailVisible] = (0, react.useState)(false);
1946
+ const accounts = account?.accounts ?? [];
1947
+ const accountVisibilityKey = `${account?.authenticated === true ? "signed-in" : "signed-out"}:${accounts.map((candidate) => `${candidate.id ?? ""}:${candidate.active === true}:${candidate.email ?? ""}`).join("|")}`;
1948
+ const [emailVisibilityKey, setEmailVisibilityKey] = (0, react.useState)(accountVisibilityKey);
1894
1949
  const [busy, setBusy] = (0, react.useState)(false);
1895
1950
  const [error, setError] = (0, react.useState)();
1896
1951
  const call = (endpoint, payload = {}) => rpc.call(CHANNEL, endpoint, payload).then(unwrap);
1952
+ (0, react.useEffect)(() => {
1953
+ if (emailVisibilityKey === accountVisibilityKey) return;
1954
+ setEmailVisible(false);
1955
+ setEmailVisibilityKey(accountVisibilityKey);
1956
+ }, [accountVisibilityKey, emailVisibilityKey]);
1897
1957
  (0, react.useEffect)(() => {
1898
1958
  if (flow?.id === void 0 || [
1899
1959
  "authenticated",
@@ -1915,7 +1975,6 @@ window.__ModuleLoader__.load({
1915
1975
  setAccount(next.account);
1916
1976
  onSignedOut();
1917
1977
  setAdding(false);
1918
- setAccountLabel("");
1919
1978
  setFlow(void 0);
1920
1979
  notifyQuickQuota();
1921
1980
  }
@@ -1931,10 +1990,11 @@ window.__ModuleLoader__.load({
1931
1990
  setFlow(void 0);
1932
1991
  setBusy(true);
1933
1992
  setError(void 0);
1993
+ const loginLabel = adding && label === void 0 ? `Account ${accounts.length + 1}` : label;
1934
1994
  call("login/start", {
1935
1995
  method,
1936
1996
  openExternal: true,
1937
- ...label === void 0 ? {} : { label }
1997
+ ...loginLabel === void 0 ? {} : { label: loginLabel }
1938
1998
  }).then(setFlow).catch(() => setError(t("failed"))).finally(() => setBusy(false));
1939
1999
  };
1940
2000
  const cancel = () => {
@@ -1942,10 +2002,7 @@ window.__ModuleLoader__.load({
1942
2002
  setBusy(true);
1943
2003
  call("login/cancel", { id: flow.id }).then((next) => {
1944
2004
  setFlow(adding ? void 0 : next);
1945
- if (adding) {
1946
- setAdding(false);
1947
- setAccountLabel("");
1948
- }
2005
+ if (adding) setAdding(false);
1949
2006
  if (adding) return void 0;
1950
2007
  return call("status").then((account) => {
1951
2008
  if (account.authenticated === true) {
@@ -2008,13 +2065,16 @@ window.__ModuleLoader__.load({
2008
2065
  };
2009
2066
  const signedIn = account?.authenticated === true;
2010
2067
  const accountReady = account !== void 0;
2011
- const accounts = account?.accounts ?? [];
2012
- const activeAccount = accounts.find((candidate) => candidate.active);
2013
2068
  const loginVisible = flow !== void 0 && ![
2014
2069
  "authenticated",
2015
2070
  "failed",
2016
2071
  "cancelled"
2017
2072
  ].includes(flow.phase);
2073
+ const toggleEmail = () => {
2074
+ setEmailVisibilityKey(accountVisibilityKey);
2075
+ setEmailVisible((value) => emailVisibilityKey === accountVisibilityKey ? !value : true);
2076
+ };
2077
+ const emailVisibleForAccount = emailVisible && emailVisibilityKey === accountVisibilityKey;
2018
2078
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2019
2079
  className: "codexSubscriptionCard",
2020
2080
  children: [
@@ -2028,7 +2088,7 @@ window.__ModuleLoader__.load({
2028
2088
  className: "codexSubscriptionDot",
2029
2089
  "data-state": accountReady ? signedIn ? "connected" : "disconnected" : "loading",
2030
2090
  "aria-hidden": "true"
2031
- }), accountReady ? signedIn ? activeAccount?.label ?? t("connected") : t("disconnected") : t("accountLoading")]
2091
+ }), accountReady ? signedIn ? t("connected") : t("disconnected") : t("accountLoading")]
2032
2092
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2033
2093
  className: "codexSubscriptionActions",
2034
2094
  children: signedIn ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
@@ -2038,7 +2098,6 @@ window.__ModuleLoader__.load({
2038
2098
  onClick: () => {
2039
2099
  setFlow(void 0);
2040
2100
  setAdding(true);
2041
- setAccountLabel(`Account ${accounts.length + 1}`);
2042
2101
  },
2043
2102
  children: t("addAccount")
2044
2103
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
@@ -2067,7 +2126,13 @@ window.__ModuleLoader__.load({
2067
2126
  children: accounts.map((candidate) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2068
2127
  className: "codexSubscriptionAccount",
2069
2128
  "data-active": candidate.active,
2070
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: candidate.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2129
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountEmail, {
2130
+ candidate,
2131
+ fallback: candidate.label,
2132
+ t,
2133
+ emailVisible: emailVisibleForAccount,
2134
+ onClick: toggleEmail
2135
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2071
2136
  className: "codexSubscriptionActions",
2072
2137
  children: [
2073
2138
  candidate.active ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
@@ -2095,42 +2160,34 @@ window.__ModuleLoader__.load({
2095
2160
  })]
2096
2161
  }, candidate.id))
2097
2162
  }) : null,
2098
- signedIn && adding && flow === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2163
+ signedIn && adding && flow === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2099
2164
  className: "codexSubscriptionFlow",
2100
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [t("accountLabel"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
2101
- className: "codexSubscriptionInput",
2102
- value: accountLabel,
2103
- maxLength: 48,
2104
- onChange: (event) => setAccountLabel(event.currentTarget.value)
2105
- })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2165
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2106
2166
  className: "codexSubscriptionActions",
2107
2167
  children: [
2108
2168
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2109
2169
  type: "button",
2110
2170
  variant: "primary",
2111
- disabled: busy || accountLabel.trim() === "",
2112
- onClick: () => begin("browser", accountLabel.trim()),
2171
+ disabled: busy,
2172
+ onClick: () => begin("browser"),
2113
2173
  children: t("browserLogin")
2114
2174
  }),
2115
2175
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2116
2176
  type: "button",
2117
2177
  variant: "outline",
2118
- disabled: busy || accountLabel.trim() === "",
2119
- onClick: () => begin("device_code", accountLabel.trim()),
2178
+ disabled: busy,
2179
+ onClick: () => begin("device_code"),
2120
2180
  children: t("deviceLogin")
2121
2181
  }),
2122
2182
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2123
2183
  type: "button",
2124
2184
  variant: "outline",
2125
2185
  disabled: busy,
2126
- onClick: () => {
2127
- setAdding(false);
2128
- setAccountLabel("");
2129
- },
2186
+ onClick: () => setAdding(false),
2130
2187
  children: t("cancel")
2131
2188
  })
2132
2189
  ]
2133
- })]
2190
+ })
2134
2191
  }) : null,
2135
2192
  flow?.phase === "waiting_device" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2136
2193
  className: "codexSubscriptionFlow",
@@ -2221,6 +2278,7 @@ window.__ModuleLoader__.load({
2221
2278
  });
2222
2279
  }
2223
2280
  function DiagnosticsCard({ rpc, t }) {
2281
+ const [diagnosticsOpen, setDiagnosticsOpen] = (0, react.useState)(false);
2224
2282
  const [report, setReport] = (0, react.useState)();
2225
2283
  const [busy, setBusy] = (0, react.useState)(false);
2226
2284
  const [copied, setCopied] = (0, react.useState)(false);
@@ -2237,39 +2295,46 @@ window.__ModuleLoader__.load({
2237
2295
  };
2238
2296
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2239
2297
  className: "codexSubscriptionCard codexSubscriptionDiagnostics",
2240
- children: [
2298
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2299
+ className: "codexSubscriptionSectionHead",
2300
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2301
+ className: "codexSubscriptionSectionTitle",
2302
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("diagnostics") })
2303
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2304
+ className: "codexSubscriptionActions",
2305
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2306
+ className: "codexSubscriptionDiagnosticsToggle",
2307
+ type: "button",
2308
+ variant: "outline",
2309
+ "aria-expanded": diagnosticsOpen,
2310
+ onClick: () => setDiagnosticsOpen((value) => !value),
2311
+ children: t(diagnosticsOpen ? "diagnosticsClose" : "diagnosticsOpen")
2312
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
2313
+ className: "codexSubscriptionLink",
2314
+ href: SUPPORT_ISSUE_URL,
2315
+ target: "_blank",
2316
+ rel: "noreferrer",
2317
+ children: t("feedbackOpen")
2318
+ })]
2319
+ })]
2320
+ }), diagnosticsOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2321
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2322
+ className: "codexSubscriptionNote",
2323
+ children: t("diagnosticsHint")
2324
+ }),
2241
2325
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2242
- className: "codexSubscriptionSectionHead",
2243
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2244
- className: "codexSubscriptionSectionTitle",
2245
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("diagnostics") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2246
- className: "codexSubscriptionNote",
2247
- children: t("diagnosticsHint")
2248
- })]
2249
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2250
- className: "codexSubscriptionActions",
2251
- children: [
2252
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2253
- type: "button",
2254
- variant: "outline",
2255
- disabled: busy,
2256
- onClick: load,
2257
- children: t("diagnosticsLoad")
2258
- }),
2259
- report === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2260
- type: "button",
2261
- variant: "outline",
2262
- onClick: copy,
2263
- children: copied ? t("diagnosticsCopied") : t("diagnosticsCopy")
2264
- }),
2265
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
2266
- className: "codexSubscriptionLink",
2267
- href: SUPPORT_ISSUE_URL,
2268
- target: "_blank",
2269
- rel: "noreferrer",
2270
- children: t("feedbackOpen")
2271
- })
2272
- ]
2326
+ className: "codexSubscriptionActions",
2327
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2328
+ type: "button",
2329
+ variant: "outline",
2330
+ disabled: busy,
2331
+ onClick: load,
2332
+ children: busy ? t("resetPreparing") : t("diagnosticsLoad")
2333
+ }), report === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2334
+ type: "button",
2335
+ variant: "outline",
2336
+ onClick: copy,
2337
+ children: copied ? t("diagnosticsCopied") : t("diagnosticsCopy")
2273
2338
  })]
2274
2339
  }),
2275
2340
  report === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: JSON.stringify(report, null, 2) }),
@@ -2278,7 +2343,7 @@ window.__ModuleLoader__.load({
2278
2343
  role: "alert",
2279
2344
  children: t("diagnosticsFailed")
2280
2345
  }) : null
2281
- ]
2346
+ ] }) : null]
2282
2347
  });
2283
2348
  }
2284
2349
  function ResetTime({ resetsAt, t }) {
@@ -2307,29 +2372,19 @@ window.__ModuleLoader__.load({
2307
2372
  })
2308
2373
  });
2309
2374
  }
2310
- function ResetCreditControl({ rpc, t, count, nextExpiresAt, hasExhaustedQuota, onConsumed }) {
2311
- const [challenge, setChallenge] = (0, react.useState)();
2312
- const [resetBusy, setResetBusy] = (0, react.useState)(false);
2313
- const [resetAcknowledged, setResetAcknowledged] = (0, react.useState)(false);
2314
- const [resetCountdown, setResetCountdown] = (0, react.useState)(0);
2315
- const [resetError, setResetError] = (0, react.useState)();
2316
- const [resetResult, setResetResult] = (0, react.useState)();
2317
- const [inspectedExpiry, setInspectedExpiry] = (0, react.useState)(nextExpiresAt);
2318
- const [expiryState, setExpiryState] = (0, react.useState)(nextExpiresAt === void 0 ? "loading" : "ready");
2375
+ function ResetCreditList({ rpc, t, count, nextExpiresAt, initialCredits, refreshKey, hasExhaustedQuota, onConsumed }) {
2376
+ const [credits, setCredits] = (0, react.useState)(initialCredits ?? (nextExpiresAt === void 0 ? [] : [{ expiresAt: nextExpiresAt }]));
2377
+ const [state, setState] = (0, react.useState)("loading");
2319
2378
  (0, react.useEffect)(() => {
2320
- if (nextExpiresAt !== void 0) {
2321
- setInspectedExpiry(nextExpiresAt);
2322
- setExpiryState("ready");
2323
- return;
2324
- }
2325
2379
  let live = true;
2326
- setExpiryState("loading");
2380
+ setState("loading");
2381
+ setCredits([]);
2327
2382
  rpc.call(CHANNEL, "reset-credit/inspect", {}).then(unwrap).then((value) => {
2328
2383
  if (!live) return;
2329
- setInspectedExpiry(value.nextExpiresAt);
2330
- setExpiryState("ready");
2384
+ setCredits(Array.isArray(value.credits) ? value.credits : []);
2385
+ setState("ready");
2331
2386
  }).catch(() => {
2332
- if (live) setExpiryState("error");
2387
+ if (live) setState("error");
2333
2388
  });
2334
2389
  return () => {
2335
2390
  live = false;
@@ -2337,8 +2392,35 @@ window.__ModuleLoader__.load({
2337
2392
  }, [
2338
2393
  rpc,
2339
2394
  count,
2340
- nextExpiresAt
2395
+ refreshKey
2341
2396
  ]);
2397
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2398
+ className: "codexSubscriptionResetBalance",
2399
+ "aria-label": t("resetCredits"),
2400
+ children: [credits.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2401
+ className: "codexSubscriptionCreditNote",
2402
+ role: "status",
2403
+ children: state === "loading" ? t("resetCreditExpiryLoading") : t("resetCreditExpiryFailed")
2404
+ }) : credits.map((credit, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditControl, {
2405
+ rpc,
2406
+ t,
2407
+ credit,
2408
+ hasExhaustedQuota,
2409
+ onConsumed
2410
+ }, credit.ref ?? `pending-${index}`)), state === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2411
+ className: "codexSubscriptionCreditNote",
2412
+ role: "status",
2413
+ children: t("resetCreditExpiryFailed")
2414
+ }) : null]
2415
+ });
2416
+ }
2417
+ function ResetCreditControl({ rpc, t, credit, hasExhaustedQuota, onConsumed }) {
2418
+ const [challenge, setChallenge] = (0, react.useState)();
2419
+ const [resetBusy, setResetBusy] = (0, react.useState)(false);
2420
+ const [resetAcknowledged, setResetAcknowledged] = (0, react.useState)(false);
2421
+ const [resetCountdown, setResetCountdown] = (0, react.useState)(0);
2422
+ const [resetError, setResetError] = (0, react.useState)();
2423
+ const [resetResult, setResetResult] = (0, react.useState)();
2342
2424
  (0, react.useEffect)(() => {
2343
2425
  if (challenge === void 0) {
2344
2426
  setResetCountdown(0);
@@ -2350,11 +2432,11 @@ window.__ModuleLoader__.load({
2350
2432
  return () => window.clearInterval(timer);
2351
2433
  }, [challenge]);
2352
2434
  const prepareReset = () => {
2353
- if (resetBusy) return;
2435
+ if (resetBusy || typeof credit.ref !== "string") return;
2354
2436
  setResetBusy(true);
2355
2437
  setResetError(void 0);
2356
2438
  setResetResult(void 0);
2357
- rpc.call(CHANNEL, "reset-credit/prepare", {}).then(unwrap).then((next) => {
2439
+ rpc.call(CHANNEL, "reset-credit/prepare", { creditRef: credit.ref }).then(unwrap).then((next) => {
2358
2440
  setChallenge(next);
2359
2441
  setResetAcknowledged(false);
2360
2442
  }).catch((error) => setResetError(resetCreditErrorText(error, t))).finally(() => setResetBusy(false));
@@ -2384,36 +2466,26 @@ window.__ModuleLoader__.load({
2384
2466
  }).catch((error) => setResetError(resetCreditErrorText(error, t))).finally(() => setResetBusy(false));
2385
2467
  };
2386
2468
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2387
- className: "codexSubscriptionResetBalance",
2469
+ className: "codexSubscriptionResetCard",
2388
2470
  children: [
2389
- challenge === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2390
- className: "codexSubscriptionResetSummary",
2391
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2392
- className: "codexSubscriptionResetMeta",
2393
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: fill(t("resetCreditsValue"), { count }) }), expiryState === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2394
- className: "codexSubscriptionResetExpiry",
2395
- role: "status",
2396
- children: t("resetCreditExpiryLoading")
2397
- }) : expiryState === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2398
- className: "codexSubscriptionResetExpiry",
2399
- children: t("resetCreditExpiryFailed")
2400
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditExpiry, {
2401
- expiresAt: inspectedExpiry,
2402
- t
2403
- })]
2404
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2405
- className: "codexSubscriptionActions",
2406
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2407
- className: "codexSubscriptionResetUse",
2408
- type: "button",
2409
- variant: "outline",
2410
- disabled: resetBusy,
2411
- "aria-busy": resetBusy,
2412
- onClick: prepareReset,
2413
- children: resetBusy ? t("resetPreparing") : t("resetUse")
2414
- })
2471
+ challenge === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2472
+ className: "codexSubscriptionResetMeta",
2473
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: credit.name ?? t("resetCreditDefaultName") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditExpiry, {
2474
+ expiresAt: credit.expiresAt,
2475
+ t
2415
2476
  })]
2416
- }) }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2477
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2478
+ className: "codexSubscriptionActions",
2479
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2480
+ className: "codexSubscriptionResetUse",
2481
+ type: "button",
2482
+ variant: "outline",
2483
+ disabled: resetBusy || typeof credit.ref !== "string",
2484
+ "aria-busy": resetBusy,
2485
+ onClick: prepareReset,
2486
+ children: resetBusy ? t("resetPreparing") : t("resetUse")
2487
+ })
2488
+ })] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2417
2489
  className: "codexSubscriptionResetFlow",
2418
2490
  role: "group",
2419
2491
  "aria-labelledby": "codex-reset-confirm-title",
@@ -2498,6 +2570,7 @@ window.__ModuleLoader__.load({
2498
2570
  }
2499
2571
  function UsageCard({ rpc, t, signedIn, resetKey }) {
2500
2572
  const [usage, setUsage] = (0, react.useState)();
2573
+ const [usageRefreshGeneration, setUsageRefreshGeneration] = (0, react.useState)(0);
2501
2574
  const [busy, setBusy] = (0, react.useState)(false);
2502
2575
  const [error, setError] = (0, react.useState)();
2503
2576
  const request = (0, react.useRef)(0);
@@ -2509,6 +2582,7 @@ window.__ModuleLoader__.load({
2509
2582
  rpc.call(CHANNEL, "usage", { force }).then(unwrap).then((next) => {
2510
2583
  if (request.current === id) {
2511
2584
  setUsage(next);
2585
+ setUsageRefreshGeneration((value) => value + 1);
2512
2586
  if (force) notifyQuickQuota();
2513
2587
  }
2514
2588
  }).catch((error) => {
@@ -2626,11 +2700,16 @@ window.__ModuleLoader__.load({
2626
2700
  }) : null,
2627
2701
  visibleUsage?.resetCredits?.availableCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2628
2702
  className: "codexSubscriptionCreditBalance",
2629
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetCredits") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditControl, {
2703
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2704
+ className: "codexSubscriptionResetSummary",
2705
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetCredits") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: fill(t("resetCreditsValue"), { count: visibleUsage.resetCredits.availableCount }) })]
2706
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditList, {
2630
2707
  rpc,
2631
2708
  t,
2632
2709
  count: visibleUsage.resetCredits.availableCount,
2633
2710
  nextExpiresAt: visibleUsage.resetCredits.nextExpiresAt,
2711
+ initialCredits: visibleUsage.resetCredits.credits,
2712
+ refreshKey: `${resetKey}:${usageRefreshGeneration}`,
2634
2713
  hasExhaustedQuota: exhausted,
2635
2714
  onConsumed: () => load(true)
2636
2715
  })]