dsh-codex-subscription 1.2.2 → 1.3.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
@@ -176,6 +176,28 @@ window.__ModuleLoader__.load({
176
176
  monthlyCreditLimit: "Credits 月度消费上限",
177
177
  resetCredits: "可用额度重置次数",
178
178
  resetCreditsValue: "{count} 次",
179
+ resetUse: "使用一次重置",
180
+ resetUnavailable: "仅当至少一个 Codex 模型额度已用尽时可使用。",
181
+ resetPreparing: "正在读取重置详情…",
182
+ resetConfirmTitle: "确认使用额度重置",
183
+ resetWarning: "此操作会立即消耗 1 次额度重置,且无法撤销。请确认你确实需要恢复已用尽的模型额度。",
184
+ resetAcknowledge: "我知道这会消耗 1 次额度重置",
185
+ resetTypeHint: "输入 {phrase} 以继续",
186
+ resetWait: "请再等待 {count} 秒",
187
+ resetFinal: "消耗 1 次并重置额度",
188
+ resetUsing: "正在重置…",
189
+ resetSuccess: "额度重置已完成。",
190
+ resetNothing: "当前没有可重置的额度,未消耗新的重置次数。",
191
+ resetNoCredit: "没有可用的额度重置。",
192
+ resetAlready: "这次重置请求已处理。",
193
+ resetFailed: "无法使用额度重置。",
194
+ resetRenewLogin: "登录状态已失效,请重新登录。",
195
+ resetExpired: "本次确认已失效,请重新开始。",
196
+ resetInProgress: "额度重置正在处理中。",
197
+ resetTooEarly: "请等待冷静期结束后再确认。",
198
+ resetPhraseMismatch: "确认短语不一致。",
199
+ resetNotExhausted: "当前 Codex 模型额度尚未用尽。",
200
+ resetAccountChanged: "登录账号已变更,请重新开始。",
179
201
  creditsNote: "仅显示 Codex 为此账户或工作区实际返回的额外 Credits、消费上限或额度重置次数;三者不是同一项。",
180
202
  creditsUsed: "已用 {used} / {limit} credits",
181
203
  spendReached: "Credits 月度消费上限已用尽。",
@@ -265,6 +287,28 @@ window.__ModuleLoader__.load({
265
287
  monthlyCreditLimit: "Monthly Credits spending cap",
266
288
  resetCredits: "Available quota resets",
267
289
  resetCreditsValue: "{count} available",
290
+ resetUse: "Use one reset",
291
+ resetUnavailable: "Available only when at least one Codex model quota is exhausted.",
292
+ resetPreparing: "Reading reset details…",
293
+ resetConfirmTitle: "Confirm quota reset",
294
+ resetWarning: "This immediately consumes one quota reset and cannot be undone. Continue only if you intend to restore an exhausted model quota.",
295
+ resetAcknowledge: "I understand this consumes one quota reset",
296
+ resetTypeHint: "Type {phrase} to continue",
297
+ resetWait: "Wait {count} more seconds",
298
+ resetFinal: "Consume one reset",
299
+ resetUsing: "Resetting…",
300
+ resetSuccess: "Quota reset completed.",
301
+ resetNothing: "There is currently nothing to reset; no new reset was consumed.",
302
+ resetNoCredit: "No quota reset is available.",
303
+ resetAlready: "This reset request was already processed.",
304
+ resetFailed: "Could not use the quota reset.",
305
+ resetRenewLogin: "Your sign-in expired. Sign in again.",
306
+ resetExpired: "This confirmation expired. Start again.",
307
+ resetInProgress: "A quota reset is already in progress.",
308
+ resetTooEarly: "Wait for the cooldown before confirming.",
309
+ resetPhraseMismatch: "The confirmation phrase does not match.",
310
+ resetNotExhausted: "The current Codex model quota is not exhausted.",
311
+ resetAccountChanged: "The signed-in account changed. Start again.",
268
312
  creditsNote: "Shows only extra Credits, spending caps, or quota resets returned for this account or workspace; these are separate items.",
269
313
  creditsUsed: "{used} / {limit} credits used",
270
314
  spendReached: "The monthly Credits spending cap has been reached.",
@@ -326,6 +370,7 @@ window.__ModuleLoader__.load({
326
370
  .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)}
327
371
  .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)}
328
372
  .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}
373
+ .codexSubscriptionResetSummary{display:flex;align-items:center;justify-content:space-between;gap:10px}.codexSubscriptionResetBalance{display:flex;flex-direction:column;gap:8px}.codexSubscriptionResetBalance .codexSubscriptionActions{justify-content:flex-start}.codexSubscriptionResetFlow{display:flex;flex-direction:column;gap:9px;border:1px solid var(--dsw-alias-state-warning-border,var(--dsw-alias-border-l2));border-radius:10px;padding:11px 12px;background:var(--dsw-alias-bg-module-platform)}.codexSubscriptionResetFlow h4{margin:0;font-size:13px;line-height:20px;font-weight:600}.codexSubscriptionResetWarning{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}.codexSubscriptionResetCheck{display:flex;align-items:flex-start;gap:8px;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)}.codexSubscriptionResetPhrase{font:600 12px/18px ui-monospace,SFMono-Regular,Consolas,monospace}.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)}
329
374
  .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}
330
375
  .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}
331
376
  .codexModelSelect{position:relative;min-width:0}.codexModelSelectTrigger{display:flex;align-items:center;gap:4px;min-width:0;max-width:min(360px,45cqw);height:28px;padding:0 4px 0 8px;border:0;border-radius:24px;outline:0;background:transparent;color:var(--dsw-alias-label-secondary);font-size:13px;font-weight:500;line-height:20px;cursor:pointer}.codexModelSelectTrigger:hover:not(:disabled),.codexModelSelectTrigger[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover)}.codexModelSelectTrigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.codexModelSelectTrigger:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.codexModelSelectBolt{display:block;flex:none;width:14px;height:14px;color:var(--dsw-alias-label-primary)}.codexModelSelectLabel{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.codexModelSelectEffort{flex:none;color:var(--dsw-alias-label-caption)}.codexModelSelectChevron{flex:none;color:var(--dsw-alias-label-caption);transition:transform 120ms}.codexModelSelectTrigger[aria-expanded=true] .codexModelSelectChevron{transform:rotate(180deg)}
@@ -1283,6 +1328,171 @@ window.__ModuleLoader__.load({
1283
1328
  children: fill(t("resets"), { value })
1284
1329
  });
1285
1330
  }
1331
+ function ResetCreditControl({ rpc, t, count, exhausted, onConsumed }) {
1332
+ const [challenge, setChallenge] = (0, react.useState)();
1333
+ const [resetBusy, setResetBusy] = (0, react.useState)(false);
1334
+ const [resetAcknowledged, setResetAcknowledged] = (0, react.useState)(false);
1335
+ const [resetPhrase, setResetPhrase] = (0, react.useState)("");
1336
+ const [resetCountdown, setResetCountdown] = (0, react.useState)(0);
1337
+ const [resetError, setResetError] = (0, react.useState)();
1338
+ const [resetResult, setResetResult] = (0, react.useState)();
1339
+ (0, react.useEffect)(() => {
1340
+ if (challenge === void 0) {
1341
+ setResetCountdown(0);
1342
+ return;
1343
+ }
1344
+ const update = () => setResetCountdown(Math.max(0, Math.ceil((challenge.readyAt - Date.now()) / 1e3)));
1345
+ update();
1346
+ const timer = window.setInterval(update, 250);
1347
+ return () => window.clearInterval(timer);
1348
+ }, [challenge]);
1349
+ const prepareReset = () => {
1350
+ if (resetBusy || !exhausted) return;
1351
+ setResetBusy(true);
1352
+ setResetError(void 0);
1353
+ setResetResult(void 0);
1354
+ rpc.call(CHANNEL, "reset-credit/prepare", {}).then(unwrap).then((next) => {
1355
+ setChallenge(next);
1356
+ setResetAcknowledged(false);
1357
+ setResetPhrase("");
1358
+ }).catch((error) => setResetError(resetCreditErrorText(error, t))).finally(() => setResetBusy(false));
1359
+ };
1360
+ const cancelReset = () => {
1361
+ if (resetBusy) return;
1362
+ setChallenge(void 0);
1363
+ setResetAcknowledged(false);
1364
+ setResetPhrase("");
1365
+ setResetError(void 0);
1366
+ };
1367
+ const resetReady = challenge !== void 0 && resetAcknowledged && resetPhrase === challenge.confirmPhrase && resetCountdown === 0;
1368
+ const consumeReset = () => {
1369
+ if (resetBusy) return;
1370
+ if (!resetReady) return;
1371
+ setResetBusy(true);
1372
+ setResetError(void 0);
1373
+ setResetResult(void 0);
1374
+ rpc.call(CHANNEL, "reset-credit/consume", {
1375
+ challengeId: challenge.challengeId,
1376
+ phrase: resetPhrase
1377
+ }).then(unwrap).then((result) => {
1378
+ setChallenge(void 0);
1379
+ setResetAcknowledged(false);
1380
+ setResetPhrase("");
1381
+ const message = result.code === "reset" ? t("resetSuccess") : result.code === "nothing_to_reset" ? t("resetNothing") : result.code === "no_credit" ? t("resetNoCredit") : t("resetAlready");
1382
+ setResetResult(message);
1383
+ onConsumed();
1384
+ }).catch((error) => setResetError(resetCreditErrorText(error, t))).finally(() => setResetBusy(false));
1385
+ };
1386
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1387
+ className: "codexSubscriptionResetBalance",
1388
+ children: [
1389
+ challenge === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1390
+ className: "codexSubscriptionResetSummary",
1391
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: fill(t("resetCreditsValue"), { count }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1392
+ className: "codexSubscriptionActions",
1393
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1394
+ type: "button",
1395
+ variant: "outline",
1396
+ disabled: !exhausted || resetBusy,
1397
+ "aria-busy": resetBusy,
1398
+ title: !exhausted ? t("resetUnavailable") : void 0,
1399
+ onClick: prepareReset,
1400
+ children: resetBusy ? t("resetPreparing") : t("resetUse")
1401
+ })
1402
+ })]
1403
+ }) }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1404
+ className: "codexSubscriptionResetFlow",
1405
+ role: "group",
1406
+ "aria-labelledby": "codex-reset-confirm-title",
1407
+ children: [
1408
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
1409
+ id: "codex-reset-confirm-title",
1410
+ children: challenge.title ?? t("resetConfirmTitle")
1411
+ }),
1412
+ challenge.description ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1413
+ className: "codexSubscriptionResetWarning",
1414
+ children: challenge.description
1415
+ }) : null,
1416
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1417
+ className: "codexSubscriptionResetWarning",
1418
+ children: t("resetWarning")
1419
+ }),
1420
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1421
+ className: "codexSubscriptionResetCheck",
1422
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1423
+ type: "checkbox",
1424
+ checked: resetAcknowledged,
1425
+ disabled: resetBusy,
1426
+ onChange: (event) => setResetAcknowledged(event.target.checked)
1427
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetAcknowledge") })]
1428
+ }),
1429
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1430
+ className: "codexSubscriptionPreferenceCopy",
1431
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1432
+ className: "codexSubscriptionCreditLabel",
1433
+ children: fill(t("resetTypeHint"), { phrase: challenge.confirmPhrase })
1434
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
1435
+ className: "codexSubscriptionInput codexSubscriptionResetPhrase",
1436
+ value: resetPhrase,
1437
+ disabled: resetBusy,
1438
+ autoComplete: "off",
1439
+ spellCheck: false,
1440
+ onChange: (event) => setResetPhrase(event.target.value)
1441
+ })]
1442
+ }),
1443
+ resetCountdown > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1444
+ className: "codexSubscriptionCreditNote",
1445
+ role: "status",
1446
+ children: fill(t("resetWait"), { count: resetCountdown })
1447
+ }) : null,
1448
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1449
+ className: "codexSubscriptionActions",
1450
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1451
+ type: "button",
1452
+ variant: "outline",
1453
+ disabled: resetBusy,
1454
+ onClick: cancelReset,
1455
+ children: t("cancel")
1456
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1457
+ className: "codexSubscriptionResetFinal",
1458
+ type: "button",
1459
+ variant: "outline",
1460
+ disabled: !resetReady || resetBusy,
1461
+ "aria-busy": resetBusy,
1462
+ onClick: consumeReset,
1463
+ children: resetBusy ? t("resetUsing") : t("resetFinal")
1464
+ })]
1465
+ })
1466
+ ]
1467
+ }),
1468
+ resetResult ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1469
+ className: "codexSubscriptionResetResult",
1470
+ role: "status",
1471
+ children: resetResult
1472
+ }) : null,
1473
+ resetError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1474
+ className: "codexSubscriptionError",
1475
+ role: "alert",
1476
+ children: resetError || t("resetFailed")
1477
+ }) : null
1478
+ ]
1479
+ });
1480
+ }
1481
+ function resetCreditErrorText(error, t) {
1482
+ return t((/* @__PURE__ */ new Map([
1483
+ ["ChatGPT subscription is not signed in", "resetRenewLogin"],
1484
+ ["ChatGPT sign-in needs to be renewed", "resetRenewLogin"],
1485
+ ["No quota reset is available", "resetNoCredit"],
1486
+ ["No usable quota reset is available", "resetNoCredit"],
1487
+ ["The available quota reset expires too soon", "resetExpired"],
1488
+ ["This quota reset confirmation is no longer valid", "resetExpired"],
1489
+ ["This quota reset is already in progress", "resetInProgress"],
1490
+ ["Wait before confirming this quota reset", "resetTooEarly"],
1491
+ ["The quota reset confirmation phrase does not match", "resetPhraseMismatch"],
1492
+ ["The current Codex quota is not exhausted", "resetNotExhausted"],
1493
+ ["The signed-in ChatGPT account changed", "resetAccountChanged"]
1494
+ ])).get(error instanceof Error ? error.message : "") ?? "resetFailed");
1495
+ }
1286
1496
  function UsageCard({ rpc, t, signedIn, resetKey }) {
1287
1497
  const [usage, setUsage] = (0, react.useState)();
1288
1498
  const [busy, setBusy] = (0, react.useState)(false);
@@ -1318,6 +1528,7 @@ window.__ModuleLoader__.load({
1318
1528
  }, [signedIn, resetKey]);
1319
1529
  const visibleUsage = signedIn ? usage : void 0;
1320
1530
  const limits = visibleUsage?.rateLimits ?? [];
1531
+ const exhausted = limits.some((limit) => limit.id !== "code_review" && limit.windows.some((window) => window.usedPercent >= 100));
1321
1532
  const hasUsageDetails = limits.length > 0 || visibleUsage?.credits !== void 0 || visibleUsage?.individualLimit !== void 0 || visibleUsage?.resetCredits?.availableCount > 0;
1322
1533
  const fetchedAt = typeof visibleUsage?.fetchedAt === "number" ? validDate(visibleUsage.fetchedAt) : void 0;
1323
1534
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -1412,7 +1623,13 @@ window.__ModuleLoader__.load({
1412
1623
  }) : null,
1413
1624
  visibleUsage?.resetCredits?.availableCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1414
1625
  className: "codexSubscriptionCreditBalance",
1415
- 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 }) })]
1626
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetCredits") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditControl, {
1627
+ rpc,
1628
+ t,
1629
+ count: visibleUsage.resetCredits.availableCount,
1630
+ exhausted,
1631
+ onConsumed: () => load(true)
1632
+ })]
1416
1633
  }) : null,
1417
1634
  visibleUsage?.individualLimit ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1418
1635
  className: "codexSubscriptionSpendLimit",