@eddyskywalker/dsh-chatgpt-subscription 0.34.0 → 0.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/CHANGELOG.md +51 -110
  2. package/lib/client.js +781 -2041
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +3104 -9297
  5. package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
  6. package/lib/types/client/ProviderHubSection.d.ts.map +1 -1
  7. package/lib/types/client/antigravity/locales.d.ts +2 -5
  8. package/lib/types/client/antigravity/locales.d.ts.map +1 -1
  9. package/lib/types/client/claude/locales.d.ts +2 -5
  10. package/lib/types/client/claude/locales.d.ts.map +1 -1
  11. package/lib/types/client/claude/styles.d.ts +2 -2
  12. package/lib/types/client/cline-pass/locales.d.ts +0 -6
  13. package/lib/types/client/cline-pass/locales.d.ts.map +1 -1
  14. package/lib/types/client/command-code/locales.d.ts +2 -5
  15. package/lib/types/client/command-code/locales.d.ts.map +1 -1
  16. package/lib/types/client/common/AccountPoolSection.d.ts +3 -2
  17. package/lib/types/client/common/AccountPoolSection.d.ts.map +1 -1
  18. package/lib/types/client/common/account-pool-labels.d.ts +0 -2
  19. package/lib/types/client/common/account-pool-labels.d.ts.map +1 -1
  20. package/lib/types/client/common/format.d.ts +2 -2
  21. package/lib/types/client/common/styles.d.ts.map +1 -1
  22. package/lib/types/client/glm-coding-plan/GlmCodingPlanSection.d.ts +1 -1
  23. package/lib/types/client/glm-coding-plan/locales.d.ts +2 -5
  24. package/lib/types/client/glm-coding-plan/locales.d.ts.map +1 -1
  25. package/lib/types/client/glm-coding-plan/styles.d.ts +3 -2
  26. package/lib/types/client/glm-coding-plan/styles.d.ts.map +1 -1
  27. package/lib/types/client/glm-coding-plan/useGlmCodingPlanSection.d.ts.map +1 -1
  28. package/lib/types/client/hub/UpdateCheck.d.ts +9 -0
  29. package/lib/types/client/hub/UpdateCheck.d.ts.map +1 -0
  30. package/lib/types/client/hub/brand-icons.d.ts +1 -1
  31. package/lib/types/client/hub/brand-icons.d.ts.map +1 -1
  32. package/lib/types/client/hub/brand-svg.d.ts +0 -4
  33. package/lib/types/client/hub/brand-svg.d.ts.map +1 -1
  34. package/lib/types/client/hub/hub-styles.d.ts.map +1 -1
  35. package/lib/types/client/hub/providers.d.ts.map +1 -1
  36. package/lib/types/client/index.d.ts +0 -2
  37. package/lib/types/client/index.d.ts.map +1 -1
  38. package/lib/types/client/kimi-code/locales.d.ts +2 -5
  39. package/lib/types/client/kimi-code/locales.d.ts.map +1 -1
  40. package/lib/types/client/locales.d.ts +39 -3
  41. package/lib/types/client/locales.d.ts.map +1 -1
  42. package/lib/types/client/minimax-code/locales.d.ts +2 -5
  43. package/lib/types/client/minimax-code/locales.d.ts.map +1 -1
  44. package/lib/types/client/minimax-code/useMinimaxCodeSection.d.ts +2 -2
  45. package/lib/types/client/minimax-code/useMinimaxCodeSection.d.ts.map +1 -1
  46. package/lib/types/client/ollama/locales.d.ts +0 -6
  47. package/lib/types/client/ollama/locales.d.ts.map +1 -1
  48. package/lib/types/client/opendesign/locales.d.ts +0 -6
  49. package/lib/types/client/opendesign/locales.d.ts.map +1 -1
  50. package/lib/types/client/qoder/QoderSection.d.ts +1 -1
  51. package/lib/types/client/qoder/locales.d.ts +1 -3
  52. package/lib/types/client/qoder/locales.d.ts.map +1 -1
  53. package/lib/types/client/qoder/useQoderSection.d.ts.map +1 -1
  54. package/lib/types/client/step-code/StepCodeComposerQuota.d.ts +2 -2
  55. package/lib/types/client/step-code/StepCodeSection.d.ts +1 -1
  56. package/lib/types/client/step-code/locales.d.ts +2 -5
  57. package/lib/types/client/step-code/locales.d.ts.map +1 -1
  58. package/lib/types/client/step-code/styles.d.ts +1 -1
  59. package/lib/types/client/step-code/useStepCodeSection.d.ts.map +1 -1
  60. package/lib/types/host/claude/account-pool.d.ts +2 -2
  61. package/lib/types/host/claude/account-pool.d.ts.map +1 -1
  62. package/lib/types/host/claude/routes.d.ts +1 -1
  63. package/lib/types/host/common/capabilities.d.ts.map +1 -1
  64. package/lib/types/host/common/credential-read-cache.d.ts +2 -3
  65. package/lib/types/host/common/credential-read-cache.d.ts.map +1 -1
  66. package/lib/types/host/common/model-request-control.d.ts +1 -1
  67. package/lib/types/host/common/model-request-control.d.ts.map +1 -1
  68. package/lib/types/host/common/request-diagnostics.d.ts +2 -2
  69. package/lib/types/host/common/request-diagnostics.d.ts.map +1 -1
  70. package/lib/types/host/glm-coding-plan/mapper-openai.d.ts +1 -1
  71. package/lib/types/host/glm-coding-plan/model-catalog.d.ts +4 -4
  72. package/lib/types/host/minimax-code/account-pool.d.ts +6 -7
  73. package/lib/types/host/minimax-code/account-pool.d.ts.map +1 -1
  74. package/lib/types/host/minimax-code/checkin.d.ts +7 -8
  75. package/lib/types/host/minimax-code/checkin.d.ts.map +1 -1
  76. package/lib/types/host/minimax-code/routes.d.ts +1 -1
  77. package/lib/types/host/step-code/adapter.d.ts +1 -1
  78. package/lib/types/host/step-code/client.d.ts +1 -1
  79. package/lib/types/host/step-code/mapper.d.ts +3 -3
  80. package/lib/types/host/step-code/oauth.d.ts +1 -1
  81. package/lib/types/host/update-check.d.ts +118 -0
  82. package/lib/types/host/update-check.d.ts.map +1 -0
  83. package/lib/types/index.d.ts +0 -6
  84. package/lib/types/index.d.ts.map +1 -1
  85. package/lib/types/shared/account-pool-contracts.d.ts +0 -24
  86. package/lib/types/shared/account-pool-contracts.d.ts.map +1 -1
  87. package/lib/types/shared/hub-contracts.d.ts +1 -1
  88. package/lib/types/shared/hub-contracts.d.ts.map +1 -1
  89. package/lib/types/shared/minimax-code-contracts.d.ts +2 -2
  90. package/lib/types/shared/update-contracts.d.ts +124 -0
  91. package/lib/types/shared/update-contracts.d.ts.map +1 -0
  92. package/package.json +1 -1
  93. package/lib/types/client/workbuddy/WorkBuddyComposerQuota.d.ts +0 -22
  94. package/lib/types/client/workbuddy/WorkBuddyComposerQuota.d.ts.map +0 -1
  95. package/lib/types/client/workbuddy/WorkBuddySection.d.ts +0 -50
  96. package/lib/types/client/workbuddy/WorkBuddySection.d.ts.map +0 -1
  97. package/lib/types/client/workbuddy/locales.d.ts +0 -635
  98. package/lib/types/client/workbuddy/locales.d.ts.map +0 -1
  99. package/lib/types/client/workbuddy/styles.d.ts +0 -15
  100. package/lib/types/client/workbuddy/styles.d.ts.map +0 -1
  101. package/lib/types/client/workbuddy/useWorkBuddySection.d.ts +0 -149
  102. package/lib/types/client/workbuddy/useWorkBuddySection.d.ts.map +0 -1
  103. package/lib/types/host/workbuddy/account-pool.d.ts +0 -235
  104. package/lib/types/host/workbuddy/account-pool.d.ts.map +0 -1
  105. package/lib/types/host/workbuddy/adapter.d.ts +0 -129
  106. package/lib/types/host/workbuddy/adapter.d.ts.map +0 -1
  107. package/lib/types/host/workbuddy/atrest.d.ts +0 -98
  108. package/lib/types/host/workbuddy/atrest.d.ts.map +0 -1
  109. package/lib/types/host/workbuddy/checkin.d.ts +0 -150
  110. package/lib/types/host/workbuddy/checkin.d.ts.map +0 -1
  111. package/lib/types/host/workbuddy/client.d.ts +0 -169
  112. package/lib/types/host/workbuddy/client.d.ts.map +0 -1
  113. package/lib/types/host/workbuddy/dsml.d.ts +0 -55
  114. package/lib/types/host/workbuddy/dsml.d.ts.map +0 -1
  115. package/lib/types/host/workbuddy/guardrails.d.ts +0 -111
  116. package/lib/types/host/workbuddy/guardrails.d.ts.map +0 -1
  117. package/lib/types/host/workbuddy/identity.d.ts +0 -71
  118. package/lib/types/host/workbuddy/identity.d.ts.map +0 -1
  119. package/lib/types/host/workbuddy/mapper.d.ts +0 -131
  120. package/lib/types/host/workbuddy/mapper.d.ts.map +0 -1
  121. package/lib/types/host/workbuddy/model-catalog.d.ts +0 -217
  122. package/lib/types/host/workbuddy/model-catalog.d.ts.map +0 -1
  123. package/lib/types/host/workbuddy/oauth.d.ts +0 -47
  124. package/lib/types/host/workbuddy/oauth.d.ts.map +0 -1
  125. package/lib/types/host/workbuddy/outbound-identity.d.ts +0 -66
  126. package/lib/types/host/workbuddy/outbound-identity.d.ts.map +0 -1
  127. package/lib/types/host/workbuddy/routes.d.ts +0 -56
  128. package/lib/types/host/workbuddy/routes.d.ts.map +0 -1
  129. package/lib/types/host/workbuddy/token-store.d.ts +0 -360
  130. package/lib/types/host/workbuddy/token-store.d.ts.map +0 -1
  131. package/lib/types/host/workbuddy/types.d.ts +0 -161
  132. package/lib/types/host/workbuddy/types.d.ts.map +0 -1
  133. package/lib/types/shared/workbuddy-contracts.d.ts +0 -353
  134. package/lib/types/shared/workbuddy-contracts.d.ts.map +0 -1
package/lib/client.js CHANGED
@@ -50,7 +50,7 @@ window.__ModuleLoader__.load({
50
50
  * 路由前缀(host 暴露、client 消费)。
51
51
  *
52
52
  * 与其余各订阅线路一致:每条线路把自己的设置面挂在 `/<line>/api` 下
53
- * (antigravity / claude / command-code / kimi-code / workbuddy 都是如此),
53
+ * (antigravity / claude / command-code / kimi-code 都是如此),
54
54
  * 而不是挂到 Codex 那条线路的 `/api/dsh-chatgpt-subscription` 前缀下面。
55
55
  * 唯一的 `/api/dsh-chatgpt-subscription` 前缀属于 Codex 自己的路由表。
56
56
  */
@@ -294,7 +294,6 @@ window.__ModuleLoader__.load({
294
294
  cooldownLeft: "剩 {minutes} 分",
295
295
  cooldownRemaining: "剩 {minutes} 分 {seconds} 秒",
296
296
  cooldownRemainingSeconds: "剩 {seconds} 秒",
297
- modelCooldown: "模型冷却",
298
297
  clearCooldown: "重置冷却",
299
298
  needsRelogin: "需重新登录",
300
299
  relogin: "重新登录",
@@ -330,7 +329,6 @@ window.__ModuleLoader__.load({
330
329
  cooldownLeft: "{minutes} min left",
331
330
  cooldownRemaining: "{minutes} min {seconds}s left",
332
331
  cooldownRemainingSeconds: "{seconds}s left",
333
- modelCooldown: "Model cooldown",
334
332
  clearCooldown: "Clear Cooldown",
335
333
  needsRelogin: "Sign-in required",
336
334
  relogin: "Sign in again",
@@ -376,10 +374,6 @@ window.__ModuleLoader__.load({
376
374
  viewBox: "0 -0.225 1.45 1.45",
377
375
  body: "<g transform=\"translate(-0.0000 -0.2250) scale(0.060417)\"><g><defs><linearGradient id=\"lobe-icons-minimax-_R_0_\" x1=\"0%\" x2=\"100.182%\" y1=\"50.057%\" y2=\"50.057%\"><stop offset=\"0%\" stop-color=\"#E2167E\"></stop><stop offset=\"100%\" stop-color=\"#FE603C\"></stop></linearGradient></defs><path d=\"M16.278 2c1.156 0 2.093.927 2.093 2.07v12.501a.74.74 0 00.744.709.74.74 0 00.743-.709V9.099a2.06 2.06 0 012.071-2.049A2.06 2.06 0 0124 9.1v6.561a.649.649 0 01-.652.645.649.649 0 01-.653-.645V9.1a.762.762 0 00-.766-.758.762.762 0 00-.766.758v7.472a2.037 2.037 0 01-2.048 2.026 2.037 2.037 0 01-2.048-2.026v-12.5a.785.785 0 00-.788-.753.785.785 0 00-.789.752l-.001 15.904A2.037 2.037 0 0113.441 22a2.037 2.037 0 01-2.048-2.026V18.04c0-.356.292-.645.652-.645.36 0 .652.289.652.645v1.934c0 .263.142.506.372.638.23.131.514.131.744 0a.734.734 0 00.372-.638V4.07c0-1.143.937-2.07 2.093-2.07zm-5.674 0c1.156 0 2.093.927 2.093 2.07v11.523a.648.648 0 01-.652.645.648.648 0 01-.652-.645V4.07a.785.785 0 00-.789-.78.785.785 0 00-.789.78v14.013a2.06 2.06 0 01-2.07 2.048 2.06 2.06 0 01-2.071-2.048V9.1a.762.762 0 00-.766-.758.762.762 0 00-.766.758v3.8a2.06 2.06 0 01-2.071 2.049A2.06 2.06 0 010 12.9v-1.378c0-.357.292-.646.652-.646.36 0 .653.29.653.646V12.9c0 .418.343.757.766.757s.766-.339.766-.757V9.099a2.06 2.06 0 012.07-2.048 2.06 2.06 0 012.071 2.048v8.984c0 .419.343.758.767.758.423 0 .766-.339.766-.758V4.07c0-1.143.937-2.07 2.093-2.07z\" fill=\"url(#lobe-icons-minimax-_R_0_)\" fill-rule=\"nonzero\"></path></g></g>"
378
376
  },
379
- "tencent": {
380
- viewBox: "0 -0.225 1.45 1.45",
381
- body: "<g transform=\"translate(-0.0000 -0.2250) scale(0.060417)\"><g><circle cx=\"12\" cy=\"12\" fill=\"#0055E9\" r=\"12\"></circle><path d=\"M12 0c.518 0 1.028.033 1.528.096A6.188 6.188 0 0112.12 12.28l-.12.001c-2.99 0-5.242 2.179-5.554 5.11-.223 2.086.353 4.412 2.242 6.146C3.672 22.1 0 17.479 0 12 0 5.373 5.373 0 12 0z\" fill=\"currentColor\"></path><path d=\"M5.286 5a2.438 2.438 0 01.682 3.38c-3.962 5.966-3.215 10.743 2.648 15.136C3.636 22.056 0 17.452 0 12c0-1.787.39-3.482 1.09-5.006.253-.435.525-.872.817-1.311A2.438 2.438 0 015.286 5z\" fill=\"#0055E9\"></path><path d=\"M12.98.04c.272.021.543.053.81.093.583.106 1.117.254 1.538.44 6.638 2.927 8.07 10.052 1.748 15.642a4.125 4.125 0 01-5.822-.358c-1.51-1.706-1.3-4.184.357-5.822.858-.848 3.108-1.223 4.045-2.441 1.257-1.634 2.122-6.009-2.523-7.506L12.98.039z\" fill=\"#00BCFF\"></path><path d=\"M13.528.096A6.187 6.187 0 0112 12.281a5.75 5.75 0 00-1.71.255c.147-.905.595-1.784 1.321-2.501.858-.848 3.108-1.223 4.045-2.441 1.27-1.651 2.14-6.104-2.676-7.554.184.014.367.033.548.056z\" fill=\"#ECECEE\"></path></g></g>"
382
- },
383
377
  "qwen": {
384
378
  viewBox: "-0.0125 -0.1646 1.3417 1.3417",
385
379
  body: "<g transform=\"translate(-0.0604 -0.2250) scale(0.060417)\"><g><path d=\"M12.604 1.34c.393.69.784 1.382 1.174 2.075a.18.18 0 00.157.091h5.552c.174 0 .322.11.446.327l1.454 2.57c.19.337.24.478.024.837-.26.43-.513.864-.76 1.3l-.367.658c-.106.196-.223.28-.04.512l2.652 4.637c.172.301.111.494-.043.77-.437.785-.882 1.564-1.335 2.34-.159.272-.352.375-.68.37-.777-.016-1.552-.01-2.327.016a.099.099 0 00-.081.05 575.097 575.097 0 01-2.705 4.74c-.169.293-.38.363-.725.364-.997.003-2.002.004-3.017.002a.537.537 0 01-.465-.271l-1.335-2.323a.09.09 0 00-.083-.049H4.982c-.285.03-.553-.001-.805-.092l-1.603-2.77a.543.543 0 01-.002-.54l1.207-2.12a.198.198 0 000-.197 550.951 550.951 0 01-1.875-3.272l-.79-1.395c-.16-.31-.173-.496.095-.965.465-.813.927-1.625 1.387-2.436.132-.234.304-.334.584-.335a338.3 338.3 0 012.589-.001.124.124 0 00.107-.063l2.806-4.895a.488.488 0 01.422-.246c.524-.001 1.053 0 1.583-.006L11.704 1c.341-.003.724.032.9.34zm-3.432.403a.06.06 0 00-.052.03L6.254 6.788a.157.157 0 01-.135.078H3.253c-.056 0-.07.025-.041.074l5.81 10.156c.025.042.013.062-.034.063l-2.795.015a.218.218 0 00-.2.116l-1.32 2.31c-.044.078-.021.118.068.118l5.716.008c.046 0 .08.02.104.061l1.403 2.454c.046.081.092.082.139 0l5.006-8.76.783-1.382a.055.055 0 01.096 0l1.424 2.53a.122.122 0 00.107.062l2.763-.02a.04.04 0 00.035-.02.041.041 0 000-.04l-2.9-5.086a.108.108 0 010-.113l.293-.507 1.12-1.977c.024-.041.012-.062-.035-.062H9.2c-.059 0-.073-.026-.043-.077l1.434-2.505a.107.107 0 000-.114L9.225 1.774a.06.06 0 00-.053-.031zm6.29 8.02c.046 0 .058.02.034.06l-.832 1.465-2.613 4.585a.056.056 0 01-.05.029.058.058 0 01-.05-.029L8.498 9.841c-.02-.034-.01-.052.028-.054l.216-.012 6.722-.012z\" fill=\"url(#lobe-icons-qwen-_R_0_)\" fill-rule=\"nonzero\"></path><defs><linearGradient id=\"lobe-icons-qwen-_R_0_\" x1=\"0%\" x2=\"100%\" y1=\"0%\" y2=\"0%\"><stop offset=\"0%\" stop-color=\"#6336E7\" stop-opacity=\".84\"></stop><stop offset=\"100%\" stop-color=\"#6F69F7\" stop-opacity=\".84\"></stop></linearGradient></defs></g></g>"
@@ -452,10 +446,6 @@ window.__ModuleLoader__.load({
452
446
  color: "#1F1F1F",
453
447
  tile: "#1783FF"
454
448
  },
455
- workbuddy: {
456
- mark: "tencent",
457
- tile: "#0055E9"
458
- },
459
449
  "minimax-code": {
460
450
  mark: "minimax",
461
451
  tile: "#E2167E"
@@ -1095,8 +1085,8 @@ window.__ModuleLoader__.load({
1095
1085
  * 1K floor and so rendered a zero as "0K" while its siblings rendered "0". The
1096
1086
  * parse has to mean the same thing on every line — it takes free-text user input
1097
1087
  * that feeds the overflow judgement — so this is the one place it lives. The
1098
- * date helpers were copied the same way; WorkBuddy's countdown is here for the
1099
- * same reason.
1088
+ * date helpers were copied the same way; the countdown to a reset instant is
1089
+ * here for the same reason.
1100
1090
  */
1101
1091
  /**
1102
1092
  * Parse "1M", "512K", "200000" into a positive integer token count.
@@ -1163,22 +1153,6 @@ window.__ModuleLoader__.load({
1163
1153
  seconds: totalSeconds % 60
1164
1154
  };
1165
1155
  }
1166
- /**
1167
- * Countdown to a reset instant ("3d 4h"), empty when there is nothing to count
1168
- * down to. Empty rather than "—" because callers append it to a date they have
1169
- * already rendered, and a dash there would read as a second missing value.
1170
- */
1171
- function formatReset$1(resetsAt) {
1172
- if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
1173
- const diff = resetsAt - Date.now();
1174
- if (diff <= 0) return "now";
1175
- const mins = Math.floor(diff / 6e4);
1176
- const hours = Math.floor(mins / 60);
1177
- const days = Math.floor(hours / 24);
1178
- if (days > 0) return `${days}d ${hours % 24}h`;
1179
- if (hours > 0) return `${hours}h ${mins % 60}m`;
1180
- return `${mins}m`;
1181
- }
1182
1156
  //#endregion
1183
1157
  //#region src/client/common/AccountPoolSection.tsx
1184
1158
  /** Format one account timestamp the way every tab renders it. */
@@ -1230,7 +1204,7 @@ window.__ModuleLoader__.load({
1230
1204
  const accounts = props.accounts;
1231
1205
  const [now, setNow] = (0, react.useState)(() => Date.now());
1232
1206
  const anyQuota = accounts.some((account) => account.quota !== void 0);
1233
- const counting = accounts.some((account) => isCoolingDown(account, now) || (account.modelCooldowns ?? []).some((park) => park.cooldownUntil > now));
1207
+ const counting = accounts.some((account) => isCoolingDown(account, now));
1234
1208
  (0, react.useEffect)(() => {
1235
1209
  if (!counting) return;
1236
1210
  setNow(Date.now());
@@ -1299,7 +1273,6 @@ window.__ModuleLoader__.load({
1299
1273
  children: accounts.map((account) => {
1300
1274
  const isActive = account.id === props.activeAccountId;
1301
1275
  const cooling = isCoolingDown(account, now);
1302
- const modelParks = (account.modelCooldowns ?? []).filter((park) => park.cooldownUntil > now);
1303
1276
  const needsRelogin = account.authStatus !== void 0 && account.authStatus !== "ok";
1304
1277
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1305
1278
  className: `dsha-account-card ${isActive ? "active" : ""}`,
@@ -1389,27 +1362,6 @@ window.__ModuleLoader__.load({
1389
1362
  ] })
1390
1363
  ]
1391
1364
  }),
1392
- modelParks.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1393
- className: "dsha-account-model-cooldowns",
1394
- children: modelParks.map((park) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1395
- className: "dsha-account-model-cooldown-row",
1396
- children: [
1397
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1398
- className: "dsha-account-model-cooldown-tag",
1399
- children: t.modelCooldown
1400
- }),
1401
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1402
- className: "dsha-account-model-cooldown-name",
1403
- title: park.model,
1404
- children: park.model
1405
- }),
1406
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1407
- className: "dsha-account-model-cooldown-time",
1408
- children: formatCooldownRemaining(park.cooldownUntil - now, t)
1409
- })
1410
- ]
1411
- }, park.model))
1412
- }),
1413
1365
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountQuota, {
1414
1366
  quota: account.quota,
1415
1367
  labels: t,
@@ -1766,7 +1718,6 @@ window.__ModuleLoader__.load({
1766
1718
  cooldownLeft: t("cooldownLeft"),
1767
1719
  cooldownRemaining: t("cooldownRemaining"),
1768
1720
  cooldownRemainingSeconds: t("cooldownRemainingSeconds"),
1769
- modelCooldown: t("modelCooldown"),
1770
1721
  clearCooldown: t("clearCooldown"),
1771
1722
  needsRelogin: t("needsRelogin"),
1772
1723
  relogin: t("relogin"),
@@ -2608,14 +2559,14 @@ window.__ModuleLoader__.load({
2608
2559
  * model, a free-text capacity input, a save button, a restore button, and a
2609
2560
  * batch restore. Only these things ever differed between them —
2610
2561
  *
2611
- * - the words (each card's dictionary, plus WorkBuddy's hardcoded `tokens`
2612
- * and the hardcoded English `context window` input label four of them carry);
2562
+ * - the words (each card's dictionary, plus a hardcoded `tokens` unit and the
2563
+ * hardcoded English `context window` input label four of them carry);
2613
2564
  * - whether a row shows the model's effective window beside the name when it
2614
2565
  * exceeds the model's default, and which stylesheet class that figure wears;
2615
2566
  * - whether the capacity input carries an `aria-label` at all (Antigravity's
2616
2567
  * does not);
2617
2568
  * - how a save or a restore is carried out, which stays in each card because
2618
- * WorkBuddy normalizes its status payload and Antigravity confirms the batch
2569
+ * one line normalizes its status payload and Antigravity confirms the batch
2619
2570
  * restore first.
2620
2571
  *
2621
2572
  * Everything the rows and callbacks need is therefore the whole interface: the
@@ -2746,7 +2697,7 @@ window.__ModuleLoader__.load({
2746
2697
  //#endregion
2747
2698
  //#region src/client/antigravity/locales.ts
2748
2699
  const NS_ANTIGRAVITY = "dsh-antigravity";
2749
- const zh$13 = {
2700
+ const zh$12 = {
2750
2701
  ...accountPoolZh,
2751
2702
  title: "Antigravity",
2752
2703
  pageDesc: "登录 Google Antigravity / Cloud Code Assist,并查看当前账号的共享额度。",
@@ -2824,7 +2775,7 @@ window.__ModuleLoader__.load({
2824
2775
  loginFailed: "登录失败",
2825
2776
  tokens: "tokens"
2826
2777
  };
2827
- const en$13 = {
2778
+ const en$12 = {
2828
2779
  ...accountPoolEn,
2829
2780
  title: "Antigravity",
2830
2781
  pageDesc: "Sign in to Google Antigravity / Cloud Code Assist and view shared quotas.",
@@ -2902,15 +2853,15 @@ window.__ModuleLoader__.load({
2902
2853
  loginFailed: "Login failed",
2903
2854
  tokens: "tokens"
2904
2855
  };
2905
- const dictionaries$13 = {
2906
- zh: zh$13,
2907
- "zh-CN": zh$13,
2908
- en: en$13,
2909
- "en-US": en$13
2856
+ const dictionaries$12 = {
2857
+ zh: zh$12,
2858
+ "zh-CN": zh$12,
2859
+ en: en$12,
2860
+ "en-US": en$12
2910
2861
  };
2911
2862
  //#endregion
2912
2863
  //#region src/client/antigravity/AntigravitySection.tsx
2913
- const api$16 = createLineApi("/antigravity/api", "Antigravity");
2864
+ const api$14 = createLineApi("/antigravity/api", "Antigravity");
2914
2865
  /** A gap in human units, so the idle reading is legible without arithmetic. */
2915
2866
  function idleLabel(ms) {
2916
2867
  const seconds = Math.round(ms / 1e3);
@@ -2942,7 +2893,7 @@ window.__ModuleLoader__.load({
2942
2893
  const [savingModel, setSavingModel] = (0, react.useState)(null);
2943
2894
  /** Follow-up poll owed while the host refreshes the quota behind an answer. */
2944
2895
  const quotaFollowUp = (0, react.useRef)(null);
2945
- const t = zh$13;
2896
+ const t = zh$12;
2946
2897
  const notifyChange = (0, react.useCallback)(() => {
2947
2898
  onModelChange?.();
2948
2899
  loadModelDirectory?.();
@@ -2953,7 +2904,7 @@ window.__ModuleLoader__.load({
2953
2904
  setValidationUrl(null);
2954
2905
  }
2955
2906
  try {
2956
- const data = await api$16.request("/status");
2907
+ const data = await api$14.request("/status");
2957
2908
  setStatus(data);
2958
2909
  setContextDrafts(contextDraftsFor(data));
2959
2910
  quotaFollowUp.current ??= createQuotaFollowUp();
@@ -2985,11 +2936,11 @@ window.__ModuleLoader__.load({
2985
2936
  setError(null);
2986
2937
  setValidationUrl(null);
2987
2938
  setLoginProgress(null);
2988
- const flow = await api$16.request("/login", { method: "POST" });
2939
+ const flow = await api$14.request("/login", { method: "POST" });
2989
2940
  if (flow.authUrl) window.open(flow.authUrl, "_blank");
2990
2941
  const pollTimer = setInterval(async () => {
2991
2942
  try {
2992
- const pollStatus = await api$16.request("/login/status");
2943
+ const pollStatus = await api$14.request("/login/status");
2993
2944
  if (pollStatus.progress) setLoginProgress(pollStatus.progress);
2994
2945
  if (pollStatus.status === "complete") {
2995
2946
  clearInterval(pollTimer);
@@ -3021,7 +2972,7 @@ window.__ModuleLoader__.load({
3021
2972
  try {
3022
2973
  setBusy("quota");
3023
2974
  setError(null);
3024
- const updated = await api$16.request("/quota", { method: "POST" });
2975
+ const updated = await api$14.request("/quota", { method: "POST" });
3025
2976
  setStatus(updated);
3026
2977
  } catch (err) {
3027
2978
  setError(err instanceof Error ? err.message : String(err));
@@ -3033,7 +2984,7 @@ window.__ModuleLoader__.load({
3033
2984
  try {
3034
2985
  setBusy(`primary-${accountId}`);
3035
2986
  setError(null);
3036
- const updated = await api$16.request("/accounts", {
2987
+ const updated = await api$14.request("/accounts", {
3037
2988
  method: "POST",
3038
2989
  body: JSON.stringify({
3039
2990
  action: "set-primary",
@@ -3052,7 +3003,7 @@ window.__ModuleLoader__.load({
3052
3003
  try {
3053
3004
  setBusy(`delete-${accountId}`);
3054
3005
  setError(null);
3055
- const updated = await api$16.request("/accounts", {
3006
+ const updated = await api$14.request("/accounts", {
3056
3007
  method: "POST",
3057
3008
  body: JSON.stringify({
3058
3009
  action: "delete",
@@ -3071,7 +3022,7 @@ window.__ModuleLoader__.load({
3071
3022
  try {
3072
3023
  setBusy(`cooldown-${accountId}`);
3073
3024
  setError(null);
3074
- const updated = await api$16.request("/accounts", {
3025
+ const updated = await api$14.request("/accounts", {
3075
3026
  method: "POST",
3076
3027
  body: JSON.stringify({
3077
3028
  action: "clear-cooldown",
@@ -3089,7 +3040,7 @@ window.__ModuleLoader__.load({
3089
3040
  try {
3090
3041
  setBusy("strategy");
3091
3042
  setError(null);
3092
- const updated = await api$16.request("/accounts", {
3043
+ const updated = await api$14.request("/accounts", {
3093
3044
  method: "POST",
3094
3045
  body: JSON.stringify({
3095
3046
  action: "strategy",
@@ -3108,7 +3059,7 @@ window.__ModuleLoader__.load({
3108
3059
  const currentEnabled = status.models.filter((m) => m.enabled).map((m) => m.id);
3109
3060
  const nextEnabled = checked ? [.../* @__PURE__ */ new Set([...currentEnabled, modelId])] : currentEnabled.filter((id) => id !== modelId);
3110
3061
  try {
3111
- const updated = await api$16.request("/models", {
3062
+ const updated = await api$14.request("/models", {
3112
3063
  method: "POST",
3113
3064
  body: JSON.stringify({ enabledModelIds: nextEnabled })
3114
3065
  });
@@ -3123,7 +3074,7 @@ window.__ModuleLoader__.load({
3123
3074
  if (!status) return;
3124
3075
  const nextEnabled = selectAll ? status.models.map((m) => m.id) : [];
3125
3076
  try {
3126
- const updated = await api$16.request("/models", {
3077
+ const updated = await api$14.request("/models", {
3127
3078
  method: "POST",
3128
3079
  body: JSON.stringify({ enabledModelIds: nextEnabled })
3129
3080
  });
@@ -3136,7 +3087,7 @@ window.__ModuleLoader__.load({
3136
3087
  };
3137
3088
  const handleUpdateEffort = async (effort) => {
3138
3089
  try {
3139
- const updated = await api$16.request("/settings", {
3090
+ const updated = await api$14.request("/settings", {
3140
3091
  method: "POST",
3141
3092
  body: JSON.stringify({ defaultReasoningEffort: effort })
3142
3093
  });
@@ -3156,7 +3107,7 @@ window.__ModuleLoader__.load({
3156
3107
  try {
3157
3108
  setSavingModel(modelId);
3158
3109
  setError(null);
3159
- const updated = await api$16.request("/settings", {
3110
+ const updated = await api$14.request("/settings", {
3160
3111
  method: "POST",
3161
3112
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
3162
3113
  });
@@ -3177,7 +3128,7 @@ window.__ModuleLoader__.load({
3177
3128
  try {
3178
3129
  setSavingModel(modelId);
3179
3130
  setError(null);
3180
- const updated = await api$16.request("/settings", {
3131
+ const updated = await api$14.request("/settings", {
3181
3132
  method: "POST",
3182
3133
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
3183
3134
  });
@@ -3204,7 +3155,7 @@ window.__ModuleLoader__.load({
3204
3155
  try {
3205
3156
  setBusy("context");
3206
3157
  setError(null);
3207
- const updated = await api$16.request("/settings", {
3158
+ const updated = await api$14.request("/settings", {
3208
3159
  method: "POST",
3209
3160
  body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
3210
3161
  });
@@ -3499,7 +3450,7 @@ window.__ModuleLoader__.load({
3499
3450
  //#endregion
3500
3451
  //#region src/client/command-code/locales.ts
3501
3452
  const NS_COMMAND_CODE = "dsh-command-code";
3502
- const zh$12 = {
3453
+ const zh$11 = {
3503
3454
  ...accountPoolZh,
3504
3455
  title: "Command Code",
3505
3456
  pageDesc: "登录 Command Code,管理可用模型、上下文窗口与额度。",
@@ -3567,7 +3518,7 @@ window.__ModuleLoader__.load({
3567
3518
  loginFailed: "登录失败",
3568
3519
  tokens: "tokens"
3569
3520
  };
3570
- const en$12 = {
3521
+ const en$11 = {
3571
3522
  ...accountPoolEn,
3572
3523
  title: "Command Code",
3573
3524
  pageDesc: "Sign in to Command Code and manage models, context windows, and quota.",
@@ -3635,11 +3586,11 @@ window.__ModuleLoader__.load({
3635
3586
  loginFailed: "Sign-in failed",
3636
3587
  tokens: "tokens"
3637
3588
  };
3638
- const dictionaries$12 = {
3639
- zh: zh$12,
3640
- "zh-CN": zh$12,
3641
- en: en$12,
3642
- "en-US": en$12
3589
+ const dictionaries$11 = {
3590
+ zh: zh$11,
3591
+ "zh-CN": zh$11,
3592
+ en: en$11,
3593
+ "en-US": en$11
3643
3594
  };
3644
3595
  //#endregion
3645
3596
  //#region src/client/command-code/CommandCodeSection.tsx
@@ -3647,7 +3598,7 @@ window.__ModuleLoader__.load({
3647
3598
  * Display label per reasoning level. The locale dictionary only accepts flat
3648
3599
  * string values, so this nested table lives with the control that renders it.
3649
3600
  */
3650
- const EFFORT_LABELS$3 = {
3601
+ const EFFORT_LABELS$2 = {
3651
3602
  none: "Off",
3652
3603
  minimal: "Minimal",
3653
3604
  low: "Low",
@@ -3656,7 +3607,7 @@ window.__ModuleLoader__.load({
3656
3607
  xhigh: "X-High",
3657
3608
  max: "Max"
3658
3609
  };
3659
- const api$15 = createLineApi("/command-code/api", "Command Code");
3610
+ const api$13 = createLineApi("/command-code/api", "Command Code");
3660
3611
  /**
3661
3612
  * Route name shown next to a model.
3662
3613
  *
@@ -3680,7 +3631,7 @@ window.__ModuleLoader__.load({
3680
3631
  const [apiKey, setApiKey] = (0, react.useState)("");
3681
3632
  /** Follow-up poll owed while the host refreshes the quota behind an answer. */
3682
3633
  const quotaFollowUp = (0, react.useRef)(null);
3683
- const t = zh$12;
3634
+ const t = zh$11;
3684
3635
  const notifyChange = (0, react.useCallback)(() => {
3685
3636
  onModelChange?.();
3686
3637
  loadModelDirectory?.();
@@ -3688,7 +3639,7 @@ window.__ModuleLoader__.load({
3688
3639
  const loadStatus = (0, react.useCallback)(async (quiet = false) => {
3689
3640
  if (!quiet) setError(null);
3690
3641
  try {
3691
- const data = await api$15.request("/status");
3642
+ const data = await api$13.request("/status");
3692
3643
  setStatus(data);
3693
3644
  setContextDrafts(contextDraftsFor(data));
3694
3645
  quotaFollowUp.current ??= createQuotaFollowUp();
@@ -3719,12 +3670,12 @@ window.__ModuleLoader__.load({
3719
3670
  setBusy("login");
3720
3671
  setError(null);
3721
3672
  setLoginProgress(null);
3722
- const flow = await api$15.request("/login", { method: "POST" });
3673
+ const flow = await api$13.request("/login", { method: "POST" });
3723
3674
  if (flow.authUrl) window.open(flow.authUrl, "_blank");
3724
3675
  const pollTimer = window.setInterval(() => {
3725
3676
  (async () => {
3726
3677
  try {
3727
- const poll = await api$15.request("/login/status");
3678
+ const poll = await api$13.request("/login/status");
3728
3679
  if (poll.progress) setLoginProgress(poll.progress);
3729
3680
  if (poll.status === "complete") {
3730
3681
  window.clearInterval(pollTimer);
@@ -3756,7 +3707,7 @@ window.__ModuleLoader__.load({
3756
3707
  try {
3757
3708
  setBusy("apikey");
3758
3709
  setError(null);
3759
- const updated = await api$15.request("/login/apikey", {
3710
+ const updated = await api$13.request("/login/apikey", {
3760
3711
  method: "POST",
3761
3712
  body: JSON.stringify({ apiKey })
3762
3713
  });
@@ -3774,7 +3725,7 @@ window.__ModuleLoader__.load({
3774
3725
  try {
3775
3726
  setBusy(`${action}-${accountId}`);
3776
3727
  setError(null);
3777
- const updated = await api$15.request("/accounts", {
3728
+ const updated = await api$13.request("/accounts", {
3778
3729
  method: "POST",
3779
3730
  body: JSON.stringify({
3780
3731
  action,
@@ -3793,7 +3744,7 @@ window.__ModuleLoader__.load({
3793
3744
  try {
3794
3745
  setBusy("strategy");
3795
3746
  setError(null);
3796
- const updated = await api$15.request("/accounts", {
3747
+ const updated = await api$13.request("/accounts", {
3797
3748
  method: "POST",
3798
3749
  body: JSON.stringify({
3799
3750
  action: "strategy",
@@ -3816,7 +3767,7 @@ window.__ModuleLoader__.load({
3816
3767
  const handleRelogin = (accountId) => {
3817
3768
  (async () => {
3818
3769
  try {
3819
- const updated = await api$15.request("/accounts", {
3770
+ const updated = await api$13.request("/accounts", {
3820
3771
  method: "POST",
3821
3772
  body: JSON.stringify({
3822
3773
  action: "relogin",
@@ -3835,7 +3786,7 @@ window.__ModuleLoader__.load({
3835
3786
  try {
3836
3787
  setBusy("quota");
3837
3788
  setError(null);
3838
- const updated = await api$15.request("/quota", { method: "POST" });
3789
+ const updated = await api$13.request("/quota", { method: "POST" });
3839
3790
  setStatus(updated);
3840
3791
  } catch (err) {
3841
3792
  setError(err instanceof Error ? err.message : String(err));
@@ -3847,7 +3798,7 @@ window.__ModuleLoader__.load({
3847
3798
  try {
3848
3799
  setBusy("catalog");
3849
3800
  setError(null);
3850
- const updated = await api$15.request("/catalog/refresh", { method: "POST" });
3801
+ const updated = await api$13.request("/catalog/refresh", { method: "POST" });
3851
3802
  setStatus(updated);
3852
3803
  setContextDrafts(contextDraftsFor(updated));
3853
3804
  notifyChange();
@@ -3861,7 +3812,7 @@ window.__ModuleLoader__.load({
3861
3812
  try {
3862
3813
  setBusy("connection");
3863
3814
  setError(null);
3864
- await api$15.post("/connection/test");
3815
+ await api$13.post("/connection/test");
3865
3816
  await loadStatus(true);
3866
3817
  } catch (err) {
3867
3818
  setError(err instanceof Error ? err.message : String(err));
@@ -3871,7 +3822,7 @@ window.__ModuleLoader__.load({
3871
3822
  };
3872
3823
  const applyEnabled = async (enabledModelIds) => {
3873
3824
  try {
3874
- const updated = await api$15.request("/models", {
3825
+ const updated = await api$13.request("/models", {
3875
3826
  method: "POST",
3876
3827
  body: JSON.stringify({ enabledModelIds })
3877
3828
  });
@@ -3894,7 +3845,7 @@ window.__ModuleLoader__.load({
3894
3845
  };
3895
3846
  const handleUpdateEffort = async (effort) => {
3896
3847
  try {
3897
- const updated = await api$15.request("/settings", {
3848
+ const updated = await api$13.request("/settings", {
3898
3849
  method: "POST",
3899
3850
  body: JSON.stringify({ defaultReasoningEffort: effort })
3900
3851
  });
@@ -3914,7 +3865,7 @@ window.__ModuleLoader__.load({
3914
3865
  try {
3915
3866
  setSavingModel(modelId);
3916
3867
  setError(null);
3917
- const updated = await api$15.request("/settings", {
3868
+ const updated = await api$13.request("/settings", {
3918
3869
  method: "POST",
3919
3870
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
3920
3871
  });
@@ -3935,7 +3886,7 @@ window.__ModuleLoader__.load({
3935
3886
  try {
3936
3887
  setSavingModel(modelId);
3937
3888
  setError(null);
3938
- const updated = await api$15.request("/settings", {
3889
+ const updated = await api$13.request("/settings", {
3939
3890
  method: "POST",
3940
3891
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
3941
3892
  });
@@ -3962,7 +3913,7 @@ window.__ModuleLoader__.load({
3962
3913
  try {
3963
3914
  setBusy("context");
3964
3915
  setError(null);
3965
- const updated = await api$15.request("/settings", {
3916
+ const updated = await api$13.request("/settings", {
3966
3917
  method: "POST",
3967
3918
  body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
3968
3919
  });
@@ -4131,7 +4082,7 @@ window.__ModuleLoader__.load({
4131
4082
  children: t.defaultEffortAuto
4132
4083
  }), COMMAND_CODE_REASONING_EFFORTS.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
4133
4084
  value: effort,
4134
- children: EFFORT_LABELS$3[effort]
4085
+ children: EFFORT_LABELS$2[effort]
4135
4086
  }, effort))]
4136
4087
  })]
4137
4088
  })]
@@ -4261,7 +4212,7 @@ window.__ModuleLoader__.load({
4261
4212
  //#endregion
4262
4213
  //#region src/client/kimi-code/locales.ts
4263
4214
  const NS_KIMI_CODE = "dsh-kimi-code";
4264
- const zh$11 = {
4215
+ const zh$10 = {
4265
4216
  ...accountPoolZh,
4266
4217
  title: "Kimi Code",
4267
4218
  pageDesc: "登录 Kimi Code 订阅,管理模型、思考档位、上下文窗口与额度。",
@@ -4384,7 +4335,7 @@ window.__ModuleLoader__.load({
4384
4335
  requests: "次请求",
4385
4336
  tokens: "tokens"
4386
4337
  };
4387
- const en$11 = {
4338
+ const en$10 = {
4388
4339
  ...accountPoolEn,
4389
4340
  title: "Kimi Code",
4390
4341
  pageDesc: "Sign in to the Kimi Code subscription and manage models, thinking level, context windows, and quota.",
@@ -4507,11 +4458,11 @@ window.__ModuleLoader__.load({
4507
4458
  requests: "requests",
4508
4459
  tokens: "tokens"
4509
4460
  };
4510
- const dictionaries$11 = {
4511
- zh: zh$11,
4512
- "zh-CN": zh$11,
4513
- en: en$11,
4514
- "en-US": en$11
4461
+ const dictionaries$10 = {
4462
+ zh: zh$10,
4463
+ "zh-CN": zh$10,
4464
+ en: en$10,
4465
+ "en-US": en$10
4515
4466
  };
4516
4467
  //#endregion
4517
4468
  //#region src/client/kimi-code/KimiModelCapabilities.tsx
@@ -4524,7 +4475,7 @@ window.__ModuleLoader__.load({
4524
4475
  * Capabilities are now short tags in their own columns, with the per-model
4525
4476
  * detail kept in a hover title.
4526
4477
  */
4527
- const t = zh$11;
4478
+ const t = zh$10;
4528
4479
  /**
4529
4480
  * Render one quota multiplier the way the official table states it: "2x", "3x".
4530
4481
  *
@@ -4589,7 +4540,7 @@ window.__ModuleLoader__.load({
4589
4540
  }
4590
4541
  //#endregion
4591
4542
  //#region src/client/kimi-code/KimiCodeSection.tsx
4592
- const api$14 = createLineApi("/kimi-code/api", "Kimi Code");
4543
+ const api$12 = createLineApi("/kimi-code/api", "Kimi Code");
4593
4544
  /** Money the service reports in minor units, rendered in its own currency. */
4594
4545
  function formatMoney(cents, currency) {
4595
4546
  if (cents === null) return "—";
@@ -4604,10 +4555,10 @@ window.__ModuleLoader__.load({
4604
4555
  }
4605
4556
  }
4606
4557
  const EFFORT_LABEL = {
4607
- low: zh$11.effortLow,
4608
- high: zh$11.effortHigh,
4609
- max: zh$11.effortMax,
4610
- none: zh$11.effortNone
4558
+ low: zh$10.effortLow,
4559
+ high: zh$10.effortHigh,
4560
+ max: zh$10.effortMax,
4561
+ none: zh$10.effortNone
4611
4562
  };
4612
4563
  /** Human label for the last request's prefix-drift cause. */
4613
4564
  function driftLabel(cause, t) {
@@ -4633,7 +4584,7 @@ window.__ModuleLoader__.load({
4633
4584
  const [connectionNotice, setConnectionNotice] = (0, react.useState)(null);
4634
4585
  /** Follow-up poll owed while the host refreshes the quota behind an answer. */
4635
4586
  const quotaFollowUp = (0, react.useRef)(null);
4636
- const t = zh$11;
4587
+ const t = zh$10;
4637
4588
  const notifyChange = (0, react.useCallback)(() => {
4638
4589
  onModelChange?.();
4639
4590
  loadModelDirectory?.();
@@ -4641,7 +4592,7 @@ window.__ModuleLoader__.load({
4641
4592
  const loadStatus = (0, react.useCallback)(async (quiet = false) => {
4642
4593
  if (!quiet) setError(null);
4643
4594
  try {
4644
- const data = await api$14.request("/status");
4595
+ const data = await api$12.request("/status");
4645
4596
  setStatus(data);
4646
4597
  setContextDrafts(contextDraftsFor(data));
4647
4598
  quotaFollowUp.current ??= createQuotaFollowUp();
@@ -4672,7 +4623,7 @@ window.__ModuleLoader__.load({
4672
4623
  const timer = window.setInterval(() => {
4673
4624
  (async () => {
4674
4625
  try {
4675
- const poll = await api$14.request("/login/status");
4626
+ const poll = await api$12.request("/login/status");
4676
4627
  setFlow(poll);
4677
4628
  if (poll.status === "complete") {
4678
4629
  await loadStatus();
@@ -4693,7 +4644,7 @@ window.__ModuleLoader__.load({
4693
4644
  setBusy("login");
4694
4645
  setError(null);
4695
4646
  setCopied(false);
4696
- const next = await api$14.request("/login", {
4647
+ const next = await api$12.request("/login", {
4697
4648
  method: "POST",
4698
4649
  body: JSON.stringify({})
4699
4650
  });
@@ -4706,7 +4657,7 @@ window.__ModuleLoader__.load({
4706
4657
  };
4707
4658
  const handleCancelLogin = async () => {
4708
4659
  try {
4709
- await api$14.request("/login/cancel", { method: "POST" });
4660
+ await api$12.request("/login/cancel", { method: "POST" });
4710
4661
  setFlow({ status: "idle" });
4711
4662
  } catch (err) {
4712
4663
  setError(err instanceof Error ? err.message : String(err));
@@ -4726,7 +4677,7 @@ window.__ModuleLoader__.load({
4726
4677
  try {
4727
4678
  setBusy(`${action}-${accountId}`);
4728
4679
  setError(null);
4729
- const updated = await api$14.request("/accounts", {
4680
+ const updated = await api$12.request("/accounts", {
4730
4681
  method: "POST",
4731
4682
  body: JSON.stringify({
4732
4683
  action,
@@ -4746,7 +4697,7 @@ window.__ModuleLoader__.load({
4746
4697
  try {
4747
4698
  setBusy("strategy");
4748
4699
  setError(null);
4749
- const updated = await api$14.request("/accounts", {
4700
+ const updated = await api$12.request("/accounts", {
4750
4701
  method: "POST",
4751
4702
  body: JSON.stringify({
4752
4703
  action: "strategy",
@@ -4769,7 +4720,7 @@ window.__ModuleLoader__.load({
4769
4720
  const handleRelogin = (accountId) => {
4770
4721
  (async () => {
4771
4722
  try {
4772
- const updated = await api$14.request("/accounts", {
4723
+ const updated = await api$12.request("/accounts", {
4773
4724
  method: "POST",
4774
4725
  body: JSON.stringify({
4775
4726
  action: "relogin",
@@ -4788,7 +4739,7 @@ window.__ModuleLoader__.load({
4788
4739
  try {
4789
4740
  setBusy("quota");
4790
4741
  setError(null);
4791
- const updated = await api$14.request("/quota", { method: "POST" });
4742
+ const updated = await api$12.request("/quota", { method: "POST" });
4792
4743
  setStatus(updated);
4793
4744
  } catch (err) {
4794
4745
  setError(err instanceof Error ? err.message : String(err));
@@ -4801,7 +4752,7 @@ window.__ModuleLoader__.load({
4801
4752
  try {
4802
4753
  setBusy("catalog");
4803
4754
  setError(null);
4804
- const updated = await api$14.request("/catalog/refresh", { method: "POST" });
4755
+ const updated = await api$12.request("/catalog/refresh", { method: "POST" });
4805
4756
  setStatus(updated);
4806
4757
  setContextDrafts(contextDraftsFor(updated));
4807
4758
  notifyChange();
@@ -4816,7 +4767,7 @@ window.__ModuleLoader__.load({
4816
4767
  setBusy("connection");
4817
4768
  setError(null);
4818
4769
  setConnectionNotice(null);
4819
- const result = await api$14.request("/connection/test", { method: "POST" });
4770
+ const result = await api$12.request("/connection/test", { method: "POST" });
4820
4771
  setConnectionNotice(result.connected ? `${t.testSuccess} · ${result.latencyMs} ms` : t.testFailed);
4821
4772
  await loadStatus(true);
4822
4773
  } catch (err) {
@@ -4827,7 +4778,7 @@ window.__ModuleLoader__.load({
4827
4778
  };
4828
4779
  const applyEnabled = async (enabledModelIds) => {
4829
4780
  try {
4830
- const updated = await api$14.request("/models", {
4781
+ const updated = await api$12.request("/models", {
4831
4782
  method: "POST",
4832
4783
  body: JSON.stringify({ enabledModelIds })
4833
4784
  });
@@ -4850,7 +4801,7 @@ window.__ModuleLoader__.load({
4850
4801
  };
4851
4802
  const handleUpdateEffort = async (effort) => {
4852
4803
  try {
4853
- const updated = await api$14.request("/settings", {
4804
+ const updated = await api$12.request("/settings", {
4854
4805
  method: "POST",
4855
4806
  body: JSON.stringify({ defaultReasoningEffort: effort })
4856
4807
  });
@@ -4862,7 +4813,7 @@ window.__ModuleLoader__.load({
4862
4813
  };
4863
4814
  const handleUpdateCacheTtl = async (ttl) => {
4864
4815
  try {
4865
- const updated = await api$14.request("/settings", {
4816
+ const updated = await api$12.request("/settings", {
4866
4817
  method: "POST",
4867
4818
  body: JSON.stringify({ cacheTtl: ttl })
4868
4819
  });
@@ -4882,7 +4833,7 @@ window.__ModuleLoader__.load({
4882
4833
  try {
4883
4834
  setSavingModel(modelId);
4884
4835
  setError(null);
4885
- const updated = await api$14.request("/settings", {
4836
+ const updated = await api$12.request("/settings", {
4886
4837
  method: "POST",
4887
4838
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
4888
4839
  });
@@ -4903,7 +4854,7 @@ window.__ModuleLoader__.load({
4903
4854
  try {
4904
4855
  setSavingModel(modelId);
4905
4856
  setError(null);
4906
- const updated = await api$14.request("/settings", {
4857
+ const updated = await api$12.request("/settings", {
4907
4858
  method: "POST",
4908
4859
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
4909
4860
  });
@@ -4930,7 +4881,7 @@ window.__ModuleLoader__.load({
4930
4881
  try {
4931
4882
  setBusy("context");
4932
4883
  setError(null);
4933
- const updated = await api$14.request("/settings", {
4884
+ const updated = await api$12.request("/settings", {
4934
4885
  method: "POST",
4935
4886
  body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
4936
4887
  });
@@ -4946,1612 +4897,216 @@ window.__ModuleLoader__.load({
4946
4897
  const contextModels = status?.models.filter((model) => model.enabled) ?? [];
4947
4898
  const overrideCount = Object.keys(status?.contextWindowOverrides ?? {}).length;
4948
4899
  if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4949
- className: "dsha-page",
4950
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4951
- className: "dsha-empty",
4952
- children: t.loading
4953
- })
4954
- });
4955
- const quota = status?.quota;
4956
- status?.account;
4957
- status?.models.filter((model) => model.enabled).length;
4958
- const loginPending = flow?.status === "pending";
4959
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4960
- className: "dsha-page",
4961
- children: [
4962
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountPoolSection, {
4963
- accounts: status?.accounts ?? [],
4964
- activeAccountId: status?.activeAccountId,
4965
- rotationStrategy: status?.rotationStrategy ?? "sequential",
4966
- busy,
4967
- labels: t,
4968
- loginBusyLabel: loginPending ? t.waitingAuthorization : busy === "login" ? t.requestingCode : void 0,
4969
- onLogin: () => void handleLogin(),
4970
- onSetPrimary: (accountId) => void handleAccountAction("set-primary", accountId),
4971
- onDelete: (accountId) => void handleAccountAction("delete", accountId),
4972
- onClearCooldown: (accountId) => void handleAccountAction("clear-cooldown", accountId),
4973
- onRelogin: (accountId) => handleRelogin(accountId),
4974
- onSetStrategy: (strategy) => void handleSetStrategy(strategy),
4975
- showQuota: true,
4976
- renderDetails: (entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [entry.planName && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
4977
- t.plan,
4978
- ": ",
4979
- entry.planName
4980
- ] }), entry.region && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
4981
- t.region,
4982
- ": ",
4983
- entry.region === "global" ? t.regionGlobal : t.regionMainland
4984
- ] })] }),
4985
- children: loginPending && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4986
- className: "dsha-device-box",
4987
- children: [
4988
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.deviceCodeSection }),
4989
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4990
- className: "dsha-muted",
4991
- children: t.deviceCodeHint
4992
- }),
4993
- flow?.userCode && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4994
- className: "dsha-code-row",
4995
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4996
- className: "dsha-code",
4997
- children: flow.userCode
4998
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4999
- className: "dsha-btn",
5000
- onClick: () => void handleCopyCode(),
5001
- children: copied ? t.copied : t.copyCode
5002
- })]
5003
- }),
5004
- flow?.verificationUriComplete && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
5005
- className: "dsha-link",
5006
- href: flow.verificationUriComplete,
5007
- target: "_blank",
5008
- rel: "noreferrer noopener",
5009
- children: flow.verificationUriComplete
5010
- }),
5011
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5012
- className: "dsha-row",
5013
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5014
- className: "dsha-label",
5015
- children: t.codeExpires
5016
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5017
- className: "dsha-value",
5018
- children: formatDate$1(flow?.expiresAt)
5019
- })]
5020
- }),
5021
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5022
- className: "dsha-actions",
5023
- children: [flow?.verificationUriComplete && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
5024
- className: "dsha-btn",
5025
- href: flow.verificationUriComplete,
5026
- target: "_blank",
5027
- rel: "noreferrer noopener",
5028
- children: t.openSignInPage
5029
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5030
- className: "dsha-btn",
5031
- disabled: busy !== null,
5032
- onClick: () => void handleCancelLogin(),
5033
- children: t.cancelSignIn
5034
- })]
5035
- })
5036
- ]
5037
- })
5038
- }),
5039
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5040
- className: "dsha-group",
5041
- children: [
5042
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5043
- className: "dsha-grouphead",
5044
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.connection })
5045
- }),
5046
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5047
- className: "dsha-row",
5048
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5049
- className: "dsha-label",
5050
- children: t.oauthHost
5051
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5052
- className: "dsha-value",
5053
- children: status?.oauthHost || "—"
5054
- })]
5055
- }),
5056
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5057
- className: "dsha-row",
5058
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5059
- className: "dsha-label",
5060
- children: t.codingEndpoint
5061
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5062
- className: "dsha-value",
5063
- children: status?.codingBaseUrl || "—"
5064
- })]
5065
- }),
5066
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5067
- className: "dsha-notice",
5068
- children: status?.serving === false && status.conflict ? t.routeConflict.replace("{detail}", status.conflict) : t.routeOwned
5069
- }),
5070
- connectionNotice && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5071
- className: "dsha-muted",
5072
- children: connectionNotice
5073
- }),
5074
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5075
- className: "dsha-actions",
5076
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5077
- className: "dsha-btn",
5078
- disabled: busy !== null || !status?.authenticated,
5079
- onClick: () => void handleTestConnection(),
5080
- children: busy === "connection" ? t.testingConnection : t.testConnection
5081
- })
5082
- })
5083
- ]
5084
- }),
5085
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5086
- className: "dsha-group",
5087
- children: [
5088
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5089
- className: "dsha-grouphead",
5090
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.cacheSection })
5091
- }),
5092
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5093
- className: "dsha-muted",
5094
- children: t.cacheDesc
5095
- }),
5096
- status?.cacheHint != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5097
- className: "dsha-warn",
5098
- children: t.cacheExpired.replace("{tokens}", status.cacheHint.totalTokens.toLocaleString())
5099
- }),
5100
- status?.cache == null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5101
- className: "dsha-empty",
5102
- children: t.cacheEmpty
5103
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5104
- className: "dsha-quota-card",
5105
- children: [
5106
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5107
- className: "dsha-meter-wrap",
5108
- children: [
5109
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5110
- className: "dsha-meter-label",
5111
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.cacheHitRatio }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: status.cache.hitRatio === null ? "—" : `${(status.cache.hitRatio * 100).toFixed(1)}%` })]
5112
- }),
5113
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5114
- className: `dsha-meter ${(status.cache.hitRatio ?? 0) >= .9 ? "dsha-meter-green" : "dsha-meter-cyan"}`,
5115
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: { width: `${Math.round((status.cache.hitRatio ?? 0) * 100)}%` } })
5116
- }),
5117
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5118
- className: "dsha-meter-meta",
5119
- children: [
5120
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5121
- t.cacheCached,
5122
- ": ",
5123
- status.cache.cachedTokens.toLocaleString()
5124
- ] }),
5125
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5126
- t.cacheFresh,
5127
- ": ",
5128
- status.cache.freshTokens.toLocaleString()
5129
- ] }),
5130
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5131
- t.cacheOutput,
5132
- ": ",
5133
- status.cache.outputTokens.toLocaleString()
5134
- ] }),
5135
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5136
- t.cacheRequests,
5137
- ": ",
5138
- status.cache.requests
5139
- ] })
5140
- ]
5141
- })
5142
- ]
5143
- }),
5144
- status.cache.lastDrift !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5145
- className: "dsha-row",
5146
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5147
- className: "dsha-label",
5148
- children: t.cacheDrift
5149
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5150
- className: "dsha-value",
5151
- children: driftLabel(status.cache.lastDrift, t)
5152
- })]
5153
- }),
5154
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5155
- className: "dsha-muted",
5156
- children: t.cacheHint
5157
- })
5158
- ]
5159
- })
5160
- ]
5161
- }),
5162
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5163
- className: "dsha-group",
5164
- children: [
5165
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5166
- className: "dsha-grouphead",
5167
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.modelsSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5168
- className: "dsha-btn",
5169
- disabled: busy !== null,
5170
- onClick: () => void handleRefreshCatalog(),
5171
- children: busy === "catalog" ? t.refreshingCatalog : t.refreshCatalog
5172
- })]
5173
- }),
5174
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5175
- className: "dsha-muted dsha-models-hint",
5176
- children: t.modelsHint
5177
- }),
5178
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelChecklist, {
5179
- items: (status?.models ?? []).map((model) => ({
5180
- id: model.id,
5181
- name: model.name,
5182
- hint: [
5183
- model.wire === "anthropic" ? t.wireAnthropic : t.wireOpenai,
5184
- ...model.supportsVideo ? [t.capVideo] : [],
5185
- ...model.supportsDynamicTools ? [t.capDynamicTools] : [],
5186
- ...model.minimumPlan ? [t.capPlan.replace("{plan}", model.minimumPlan)] : []
5187
- ].join(" · "),
5188
- enabled: model.enabled
5189
- })),
5190
- busy: busy !== null,
5191
- onToggle: toggleModel,
5192
- onToggleAll: setAllModels,
5193
- labels: {
5194
- selectAll: t.selectAll,
5195
- clearAll: t.unselectAll,
5196
- list: t.modelsSection
5197
- }
5198
- }),
5199
- status !== null && status.models.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KimiModelCapabilities, { models: status.models })
5200
- ]
5201
- }),
5202
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5203
- className: "dsha-group",
5204
- children: [
5205
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5206
- className: "dsha-grouphead",
5207
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.enhanced })
5208
- }),
5209
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5210
- className: "dsha-pref-row",
5211
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.defaultReasoningEffort }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5212
- className: "dsha-muted",
5213
- children: t.defaultReasoningEffortHint
5214
- })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
5215
- className: "dsha-select",
5216
- "aria-label": t.defaultReasoningEffort,
5217
- value: status?.defaultReasoningEffort ?? "",
5218
- disabled: busy !== null,
5219
- onChange: (event) => {
5220
- const value = event.currentTarget.value;
5221
- handleUpdateEffort(value === "" ? null : value);
5222
- },
5223
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5224
- value: "",
5225
- children: t.defaultEffortAuto
5226
- }), KIMI_CODE_REASONING_EFFORTS.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5227
- value: effort,
5228
- children: EFFORT_LABEL[effort]
5229
- }, effort))]
5230
- })]
5231
- }),
5232
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5233
- className: "dsha-pref-row",
5234
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.cacheTtl }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5235
- className: "dsha-muted",
5236
- children: t.cacheTtlHint
5237
- })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
5238
- className: "dsha-select",
5239
- "aria-label": t.cacheTtl,
5240
- value: status?.cacheTtl ?? "",
5241
- disabled: busy !== null,
5242
- onChange: (event) => {
5243
- const value = event.currentTarget.value;
5244
- handleUpdateCacheTtl(value === "" ? null : value);
5245
- },
5246
- children: [
5247
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5248
- value: "",
5249
- children: t.cacheTtlDefault
5250
- }),
5251
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5252
- value: "5m",
5253
- children: t.cacheTtl5m
5254
- }),
5255
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5256
- value: "1h",
5257
- children: t.cacheTtl1h
5258
- })
5259
- ]
5260
- })]
5261
- })
5262
- ]
5263
- }),
5264
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5265
- className: "dsha-group",
5266
- children: [
5267
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5268
- className: "dsha-grouphead",
5269
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.contextWindowSection })
5270
- }),
5271
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5272
- className: "dsha-muted",
5273
- children: t.contextWindowHint
5274
- }),
5275
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextWindowEditor, {
5276
- rows: contextModels.map((model) => ({
5277
- id: model.id,
5278
- name: model.name,
5279
- draft: contextDrafts[model.id] ?? "",
5280
- meta: model.defaultContextWindow < model.contextWindow ? formatCapacity$1(model.contextWindow) : void 0,
5281
- inputLabel: `${model.name} context window`,
5282
- hasOverride: status?.contextWindowOverrides[model.id] !== void 0,
5283
- saving: savingModel === model.id
5284
- })),
5285
- labels: {
5286
- tokens: t.tokens,
5287
- save: t.save,
5288
- saving: t.saving,
5289
- reset: t.contextWindowReset,
5290
- resetAll: t.contextWindowResetAll,
5291
- empty: t.contextWindowNoneEnabled
5292
- },
5293
- busy: busy !== null,
5294
- overrideCount,
5295
- metaClassName: "dsha-model-meta",
5296
- onDraftChange: (id, draft) => setContextDrafts((prev) => ({
5297
- ...prev,
5298
- [id]: draft
5299
- })),
5300
- onCommit: (id) => void handleSaveContextWindow(id),
5301
- onReset: (id) => void handleResetContextWindow(id),
5302
- onResetAll: () => void handleResetAllContextWindows()
5303
- })
5304
- ]
5305
- }),
5306
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
5307
- className: "dsha-group",
5308
- children: [
5309
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5310
- className: "dsha-grouphead",
5311
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.quotaSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5312
- className: "dsha-btn",
5313
- disabled: busy !== null || !status?.authenticated,
5314
- onClick: () => void handleRefreshQuota(),
5315
- children: busy === "quota" ? t.refreshingQuota : t.refreshQuota
5316
- })]
5317
- }),
5318
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5319
- className: "dsha-muted",
5320
- children: t.quotaDesc
5321
- }),
5322
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5323
- className: "dsha-muted",
5324
- children: t.quotaFactsScope
5325
- }),
5326
- status?.quotaError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5327
- className: "dsha-notice",
5328
- children: status.quotaError
5329
- }),
5330
- !status?.authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5331
- className: "dsha-empty",
5332
- children: t.signedOut
5333
- }) : quota === null || quota === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5334
- className: "dsha-empty",
5335
- children: busy === "quota" ? t.refreshingQuota : t.quotaEmpty
5336
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5337
- className: "dsha-quota-card",
5338
- children: [
5339
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5340
- className: "dsha-quota-title",
5341
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.quotaPlan }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: quota.planName || t.planUnknown })]
5342
- }),
5343
- quota.extraUsage !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5344
- className: "dsha-meter-wrap",
5345
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5346
- className: "dsha-meter-label",
5347
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.quotaWallet }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: formatMoney(quota.extraUsage.balanceCents, quota.extraUsage.currency) })]
5348
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5349
- className: "dsha-meter-meta",
5350
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatMoney(quota.extraUsage.totalCents, quota.extraUsage.currency) }), quota.extraUsage.monthlyChargeLimitEnabled && quota.extraUsage.monthlyChargeLimitCents !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5351
- t.quotaWalletLimit,
5352
- ": ",
5353
- formatMoney(quota.extraUsage.monthlyChargeLimitCents, quota.extraUsage.currency)
5354
- ] })]
5355
- })]
5356
- }),
5357
- quota.windows.length === 0 && quota.extraUsage === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5358
- className: "dsha-empty",
5359
- children: t.quotaEmpty
5360
- }),
5361
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5362
- className: "dsha-timestamp",
5363
- children: t.updatedAt.replace("{time}", new Date(quota.fetchedAt).toLocaleString())
5364
- })
5365
- ]
5366
- })
5367
- ]
5368
- }),
5369
- error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5370
- className: "dsha-error",
5371
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: error })
5372
- })
5373
- ]
5374
- });
5375
- }
5376
- //#endregion
5377
- //#region src/shared/workbuddy-contracts.ts
5378
- /**
5379
- * Every level this route can name, in escalating order (the card's sort key).
5380
- *
5381
- * `none` is the one level that is not a rung of any ladder: it is the measured
5382
- * spelling that turns the reasoning trace OFF upstream (`reasoning_effort:
5383
- * "none"`, the value the sibling gateway sends on its own cheap calls). It is
5384
- * only ever offered on a model the catalog marks `canDisableThinking`, so it
5385
- * sorts below everything and is never used to converge a level onto a ladder.
5386
- */
5387
- const WORKBUDDY_REASONING_EFFORTS = [
5388
- "none",
5389
- "minimal",
5390
- "low",
5391
- "medium",
5392
- "high",
5393
- "xhigh",
5394
- "max"
5395
- ];
5396
- //#endregion
5397
- //#region src/client/workbuddy/locales.ts
5398
- const NS_WORKBUDDY = "dsh-workbuddy";
5399
- const zh$10 = {
5400
- title: "WorkBuddy",
5401
- pageDesc: "复用本机 CodeBuddy 桌面端登录态,管理 WorkBuddy(CodeBuddy 订阅)模型、上下文窗口与额度。",
5402
- account: "账号",
5403
- noAccounts: "暂无账号。点击右上角「添加账号」完成浏览器授权,或登录 CodeBuddy 桌面端后重新扫描;桌面账号只能从本插件隐藏,绝不删除 CodeBuddy 的原凭据。",
5404
- signedOut: "未找到凭据",
5405
- nickname: "昵称",
5406
- uin: "UIN",
5407
- region: "区域",
5408
- regionCn: "国区",
5409
- regionIntl: "国际区",
5410
- accountType: "账号类型",
5411
- routeUnreachable: "无法读取 WorkBuddy 设置路由",
5412
- routeUnreachableHint: "浏览器里加载的插件版本可能比 Host 进程里运行的新(客户端资源是现读磁盘的,Host 只在启动时加载)。请重启 DSH,让两端来自同一份构建。",
5413
- rescan: "重新扫描",
5414
- rescanning: "扫描中...",
5415
- accounts: "账号管理",
5416
- modelCooldown: "模型限流",
5417
- addCnAccount: "添加国区账号",
5418
- addIntlAccount: "添加国际区账号",
5419
- authorizing: "授权中…",
5420
- loginWaiting: "请在新打开的浏览器页面完成登录与授权。",
5421
- loginFailed: "账号授权失败",
5422
- hiddenAccount: "已隐藏",
5423
- hideAccount: "从插件隐藏",
5424
- restoreAccount: "恢复显示",
5425
- deleteAccount: "删除账号",
5426
- deleteConfirm: "确定删除这个插件托管的账号吗?加密存储中的登录凭据会被移除。",
5427
- connection: "连接",
5428
- testConnection: "测试连接",
5429
- testingConnection: "测试中...",
5430
- latency: "延迟",
5431
- routeOwned: "模型路由由本插件提供",
5432
- routeConflict: "模型路由已被其他 Provider 占用:{detail}。请在 DSH 设置中移除重复的 Provider 配置后重试。",
5433
- modelsSection: "模型",
5434
- modelsHint: "勾选后模型才会出现在对话页的模型选择列表中;未勾选或关闭上方开关可在列表中隐藏该供应商。目录与上下文窗口来自订阅网关的模型目录,并按账号所在区域过滤——跨区调用会被上游拒绝。",
5435
- refreshCatalog: "刷新模型目录",
5436
- refreshingCatalog: "刷新中...",
5437
- selectAll: "全选",
5438
- unselectAll: "全不选",
5439
- imageSupport: "图片",
5440
- textOnly: "纯文本",
5441
- creditMultiplier: "倍率",
5442
- creditMultiplierRegion: "{value}({region})",
5443
- creditMultiplierPair: "{first} / {second}",
5444
- regionBadge: "区域",
5445
- unavailableHere: "当前区域不可用",
5446
- enhanced: "增强功能",
5447
- defaultReasoningEffort: "默认思考深度",
5448
- defaultReasoningEffortHint: "控制支持推理的模型在未单独指定时的思考强度。",
5449
- defaultEffortAuto: "使用模型默认值",
5450
- effortUnsupported: "当前模型不支持",
5451
- noReasoningModels: "当前账号的模型都没有声明可用的思考档位,因此没有可选的默认档位。",
5452
- defaultEffortKept: "已保存的档位不被当前任何模型支持,已保留但不会生效。",
5453
- contextWindowSection: "模型上下文窗口",
5454
- contextWindowHint: "默认值来自订阅网关的模型目录(每个模型的真实上下文上限);可覆盖为自定义容量,该值用于 DSH 的压缩与溢出判断,可输入 1M、512K、200K 等容量。",
5455
- contextWindowReset: "恢复默认",
5456
- contextWindowResetAll: "全部恢复默认",
5457
- contextWindowResetAllConfirm: "确定把已改过的模型上下文窗口全部恢复为默认值吗?",
5458
- contextWindowNoneEnabled: "还没有勾选任何模型。在上方勾选后,这里会出现该模型的上下文窗口设置。",
5459
- save: "保存",
5460
- saved: "已保存",
5461
- saving: "保存中...",
5462
- quotaSection: "用量与配额",
5463
- quotaDesc: "数据来自订阅的计费接口,页面可见时最多每 60 秒刷新一次。",
5464
- refreshQuota: "刷新用量",
5465
- refreshingQuota: "刷新中...",
5466
- quotaEmpty: "暂无配额数据,点击「刷新用量」重试。",
5467
- quotaPackage: "套餐",
5468
- quotaRemaining: "剩余额度",
5469
- quotaCycle: "本周期已用",
5470
- quotaReset: "重置时间",
5471
- updatedAt: "更新时间:{time}",
5472
- loading: "加载中...",
5473
- credits: "credits",
5474
- composerLabel: "额度",
5475
- dailyCheckin: "每日签到",
5476
- checkinHint: "仅国区账号参与;DSH 启动时自动签到一次,运行期间每 10 分钟补检,进程关闭的当天不会签到。",
5477
- checkinAuto: "自动签到",
5478
- checkinToday: "今日已签 {done}/{total}",
5479
- checkinSkipped: "{count} 个无签到活动",
5480
- checkinFailed: "{count} 个失败",
5481
- checkinLastRun: "上次运行:{time}",
5482
- checkinNever: "尚未运行",
5483
- checkinNow: "立即签到",
5484
- checkinRunning: "签到中…",
5485
- outboundSection: "出站身份",
5486
- outboundHint: "决定请求以哪种客户端身份发出。cli 是本线路一直使用、实测可用的身份;auto 会按账号稳定分配一种(同一账号永不漂移)。换身份不会增加额度——额度按账号 × 模型的 24 小时窗口计算。",
5487
- outboundAuto: "自动(按账号分配)",
5488
- outboundCli: "CLI(默认,实测可用)",
5489
- outboundWorkbuddy: "WorkBuddy 桌面端",
5490
- outboundVscode: "VSCode 插件",
5491
- atRestSection: "桌面凭据解密",
5492
- atRestHint: "桌面客户端自 2026-09-24 起把 token 存成 $wbEncrypted 加密信封。粘贴一次密钥即可读取这些账号;密钥只写入系统加密存储(DPAPI / Keychain / Secret Service),不落明文、不进日志。",
5493
- atRestPlaceholder: "64 位 hex 保护密钥,或 44 字符 base64 的 atRestSecretKey",
5494
- atRestSave: "保存密钥",
5495
- atRestClear: "清除密钥",
5496
- atRestSaved: "已保存密钥",
5497
- atRestSealed: "检测到 {count} 个加密凭据,未保存密钥前无法使用。",
5498
- guardrailsSection: "本地额度护栏",
5499
- guardrailsHint: "在撞上游 429 之前先停手:剩余积分低于阈值、账号当日 token 达额、或单个模型当日 token 达额时,请求会切到池里其他账号。三项都填 0 = 关闭,计数按本地 0 点重置。",
5500
- guardrailsReserve: "保留积分",
5501
- guardrailsDaily: "账号日 token",
5502
- guardrailsModelDaily: "模型日 token"
5503
- };
5504
- const en$10 = {
5505
- title: "WorkBuddy",
5506
- pageDesc: "Reuse the local CodeBuddy desktop sign-in to manage WorkBuddy (CodeBuddy subscription) models, context windows, and quota.",
5507
- account: "Account",
5508
- noAccounts: "No accounts yet. Use “Add account” above to authorize, or sign in with the CodeBuddy desktop client and rescan; desktop accounts can only be hidden here, never removed from CodeBuddy.",
5509
- signedOut: "No credential found",
5510
- nickname: "Nickname",
5511
- uin: "UIN",
5512
- region: "Region",
5513
- regionCn: "China",
5514
- regionIntl: "International",
5515
- accountType: "Account type",
5516
- routeUnreachable: "The WorkBuddy settings route could not be read",
5517
- routeUnreachableHint: "The plugin loaded in the browser may be newer than the one running in the Host: client assets are read from disk on demand, while the Host loads them only at startup. Restart DSH so both halves come from the same build.",
5518
- rescan: "Rescan",
5519
- rescanning: "Scanning...",
5520
- accounts: "Account Management",
5521
- modelCooldown: "Model rate limit",
5522
- addCnAccount: "Add China account",
5523
- addIntlAccount: "Add international account",
5524
- authorizing: "Authorizing…",
5525
- loginWaiting: "Complete sign-in and authorization in the newly opened browser page.",
5526
- loginFailed: "Account authorization failed",
5527
- hiddenAccount: "Hidden",
5528
- hideAccount: "Hide from plugin",
5529
- restoreAccount: "Restore",
5530
- deleteAccount: "Delete account",
5531
- deleteConfirm: "Delete this plugin-managed account? Its encrypted credential will be removed.",
5532
- connection: "Connection",
5533
- testConnection: "Test connection",
5534
- testingConnection: "Testing...",
5535
- latency: "Latency",
5536
- routeOwned: "This plugin serves the model route",
5537
- routeConflict: "Another provider already owns the model route: {detail}. Remove the duplicate provider configuration in DSH settings and reload.",
5538
- modelsSection: "Models",
5539
- modelsHint: "Checked models appear in the DSH conversation model list. The catalog and its context windows come from the subscription gateway and are filtered by the account’s region — the upstream rejects a model asked of the wrong region.",
5540
- refreshCatalog: "Refresh catalog",
5541
- refreshingCatalog: "Refreshing...",
5542
- selectAll: "Select all",
5543
- unselectAll: "Deselect all",
5544
- imageSupport: "Images",
5545
- textOnly: "Text only",
5546
- creditMultiplier: "Multiplier",
5547
- creditMultiplierRegion: "{value} ({region})",
5548
- creditMultiplierPair: "{first} / {second}",
5549
- regionBadge: "Regions",
5550
- unavailableHere: "Unavailable in this region",
5551
- enhanced: "Enhanced features",
5552
- defaultReasoningEffort: "Default reasoning effort",
5553
- defaultReasoningEffortHint: "Reasoning effort for models that support it when the conversation does not specify one.",
5554
- defaultEffortAuto: "Use the model default",
5555
- effortUnsupported: "unsupported by the current models",
5556
- noReasoningModels: "None of this account’s models declare a reasoning level, so there is no default to choose.",
5557
- defaultEffortKept: "The saved level is not supported by any current model; it is kept but has no effect.",
5558
- contextWindowSection: "Model context window",
5559
- contextWindowHint: "Defaults come from the subscription gateway’s own catalog (each model’s real context cap); override one with the capacity DSH should use for compaction and overflow decisions (e.g., 1M, 512K, 200K).",
5560
- contextWindowReset: "Restore default",
5561
- contextWindowResetAll: "Restore all defaults",
5562
- contextWindowResetAllConfirm: "Restore every changed model context window to its default?",
5563
- contextWindowNoneEnabled: "No model is checked yet. Check one above and its context window setting appears here.",
5564
- save: "Save",
5565
- saved: "Saved",
5566
- saving: "Saving...",
5567
- quotaSection: "Usage & quota",
5568
- quotaDesc: "Read from the subscription billing endpoint; refreshes at most once every 60 seconds while visible.",
5569
- refreshQuota: "Refresh quota",
5570
- refreshingQuota: "Refreshing...",
5571
- quotaEmpty: "No quota data yet — use “Refresh quota” to retry.",
5572
- quotaPackage: "Package",
5573
- quotaRemaining: "Remaining credits",
5574
- quotaCycle: "Used this cycle",
5575
- quotaReset: "Resets",
5576
- updatedAt: "Updated at: {time}",
5577
- loading: "Loading...",
5578
- credits: "credits",
5579
- composerLabel: "Quota",
5580
- dailyCheckin: "Daily check-in",
5581
- checkinHint: "CN-region accounts only. The host signs in once at startup and re-checks every 10 minutes while running; a day the process never runs is not signed.",
5582
- checkinAuto: "Auto check-in",
5583
- checkinToday: "Checked in today {done}/{total}",
5584
- checkinSkipped: "{count} with no activity",
5585
- checkinFailed: "{count} failed",
5586
- checkinLastRun: "Last run: {time}",
5587
- checkinNever: "Never run",
5588
- checkinNow: "Check in now",
5589
- checkinRunning: "Checking in…",
5590
- outboundSection: "Outbound identity",
5591
- outboundHint: "Which client identity requests present. cli is what this route has always sent and was measured working; auto assigns one product per account and never drifts. Switching identity does not create allowance — quota is metered per account × model over a 24h window.",
5592
- outboundAuto: "Auto (per account)",
5593
- outboundCli: "CLI (default, measured working)",
5594
- outboundWorkbuddy: "WorkBuddy desktop",
5595
- outboundVscode: "VSCode extension",
5596
- atRestSection: "Desktop credential decryption",
5597
- atRestHint: "Since 2026-09-24 the desktop client seals its tokens as $wbEncrypted envelopes. Paste the key once to read those accounts; it is stored only in the platform credential store, never in plaintext and never logged.",
5598
- atRestPlaceholder: "64-character hex protector key, or the 44-character base64 atRestSecretKey",
5599
- atRestSave: "Save key",
5600
- atRestClear: "Clear key",
5601
- atRestSaved: "Key saved",
5602
- atRestSealed: "{count} sealed credentials found; they stay unreadable until a key is saved.",
5603
- guardrailsSection: "Local quota guardrails",
5604
- guardrailsHint: "Stop before the upstream 429: below a credit floor, at the account daily token cap, or at a per-model daily token cap, the request moves to another account in the pool. 0 disables a rail; counters reset at local midnight.",
5605
- guardrailsReserve: "Reserve credits",
5606
- guardrailsDaily: "Account daily tokens",
5607
- guardrailsModelDaily: "Model daily tokens"
5608
- };
5609
- const dictionaries$10 = {
5610
- zh: zh$10,
5611
- "zh-CN": zh$10,
5612
- en: en$10,
5613
- "en-US": en$10
5614
- };
5615
- //#endregion
5616
- //#region src/client/workbuddy/useWorkBuddySection.ts
5617
- /**
5618
- * The WorkBuddy card's state, effects and actions.
5619
- *
5620
- * Split out of 'WorkBuddySection.tsx' so that file is markup and this one is
5621
- * behaviour: what the card tracks, what it derives from a status answer, and
5622
- * every request a control can make. The view reads one named shape — see
5623
- * `WorkBuddySectionView` — so the contract between the two is visible here
5624
- * rather than inferred from the JSX.
5625
- */
5626
- const API$6 = "/workbuddy/api";
5627
- /**
5628
- * The shared card's label set.
5629
- *
5630
- * Only the three labels WorkBuddy genuinely words differently are taken from
5631
- * this tab's dictionary; everything else is the shared set, so the five
5632
- * provider tabs cannot drift apart in wording.
5633
- */
5634
- function accountPoolLabels(t) {
5635
- return {
5636
- ...accountPoolZh,
5637
- noAccounts: t.noAccounts,
5638
- email: t.nickname,
5639
- modelCooldown: t.modelCooldown
5640
- };
5641
- }
5642
- /**
5643
- * Call one settings route through the shared reader.
5644
- *
5645
- * This line is where the shared reader's tolerance came from: reading the body
5646
- * as text first is what lets a route that is not mounted (an empty body, which
5647
- * is exactly what a stale host half produces) be reported as such instead of as
5648
- * a bare "Unexpected end of JSON input".
5649
- */
5650
- const api$13 = createLineApi(API$6, "WorkBuddy");
5651
- /**
5652
- * Reasoning levels the default-effort control may offer.
5653
- *
5654
- * The levels come from what this account's models actually declare — never from
5655
- * the shipped enum alone. The setting is one global default applied to whichever
5656
- * model a conversation uses, so the list is their union; each entry carries the
5657
- * models behind it, and a level only some models accept is labelled as such.
5658
- * Order follows {@link WORKBUDDY_REASONING_EFFORTS}, which is the escalating
5659
- * order the upstream ladder uses.
5660
- */
5661
- function reasoningEffortChoices(models) {
5662
- const declared = /* @__PURE__ */ new Map();
5663
- for (const model of models) for (const effort of model.reasoningEfforts ?? []) {
5664
- const names = declared.get(effort);
5665
- if (names === void 0) declared.set(effort, [model.name]);
5666
- else names.push(model.name);
5667
- }
5668
- return WORKBUDDY_REASONING_EFFORTS.filter((effort) => declared.has(effort)).map((effort) => ({
5669
- value: effort,
5670
- models: declared.get(effort)
5671
- }));
5672
- }
5673
- /**
5674
- * Whether a saved default is unusable for every model on this account.
5675
- *
5676
- * The adapter drops a level the chosen model does not accept instead of sending
5677
- * it, so a value that no model declares silently does nothing. Reporting it is
5678
- * what keeps that from looking like the setting was applied.
5679
- */
5680
- function unsupportedReasoningEffort(configured, models) {
5681
- if (configured === null || configured === void 0) return null;
5682
- return models.some((model) => (model.reasoningEfforts ?? []).includes(configured)) ? null : configured;
5683
- }
5684
- /** Defend against a response that omits the arrays the card renders. */
5685
- function normalizeStatus(data) {
5686
- return {
5687
- ...data,
5688
- models: Array.isArray(data?.models) ? data.models : [],
5689
- contextWindowOverrides: data?.contextWindowOverrides ?? {},
5690
- accounts: Array.isArray(data?.accounts) ? data.accounts : []
5691
- };
5692
- }
5693
- function useWorkBuddySection({ onModelChange, loadModelDirectory }) {
5694
- const [status, setStatus] = (0, react.useState)(null);
5695
- const [loading, setLoading] = (0, react.useState)(true);
5696
- const [busy, setBusy] = (0, react.useState)(null);
5697
- const [error, setError] = (0, react.useState)(null);
5698
- const [statusFailed, setStatusFailed] = (0, react.useState)(false);
5699
- const [connection, setConnection] = (0, react.useState)(null);
5700
- const [loginProgress, setLoginProgress] = (0, react.useState)(null);
5701
- const loginIntervalRef = (0, react.useRef)(null);
5702
- const loginTimeoutRef = (0, react.useRef)(null);
5703
- /** Follow-up poll owed while the host refreshes the quota behind an answer. */
5704
- const quotaFollowUp = (0, react.useRef)(null);
5705
- const [contextDrafts, setContextDrafts] = (0, react.useState)({});
5706
- const [savingModel, setSavingModel] = (0, react.useState)(null);
5707
- const t = zh$10;
5708
- const notifyChange = (0, react.useCallback)(() => {
5709
- onModelChange?.();
5710
- loadModelDirectory?.();
5711
- }, [onModelChange, loadModelDirectory]);
5712
- const effortChoices = (0, react.useMemo)(() => reasoningEffortChoices(status?.models ?? []), [status?.models]);
5713
- const allModels = status?.models ?? [];
5714
- const poolAccounts = (0, react.useMemo)(() => Array.isArray(status?.accounts) ? status.accounts : [], [status?.accounts]);
5715
- const strayEffort = unsupportedReasoningEffort(status?.defaultReasoningEffort, allModels);
5716
- const loadStatus = (0, react.useCallback)(async (quiet = false) => {
5717
- if (!quiet) setError(null);
5718
- try {
5719
- const data = await api$13.request("/status");
5720
- const normalized = normalizeStatus(data);
5721
- setStatus(normalized);
5722
- setStatusFailed(false);
5723
- setContextDrafts(contextDraftsFor(normalized));
5724
- quotaFollowUp.current ??= createQuotaFollowUp();
5725
- quotaFollowUp.current.observe(data.quotaRefreshing === true, () => {
5726
- loadStatus(true);
5727
- });
5728
- } catch (err) {
5729
- setStatusFailed(true);
5730
- if (!quiet) setError(err instanceof Error ? err.message : String(err));
5731
- } finally {
5732
- setLoading(false);
5733
- }
5734
- }, []);
5735
- (0, react.useEffect)(() => {
5736
- loadStatus();
5737
- const refreshWhenVisible = () => {
5738
- if (document.visibilityState === "visible") loadStatus(true);
5739
- };
5740
- document.addEventListener("visibilitychange", refreshWhenVisible);
5741
- const timer = window.setInterval(refreshWhenVisible, 6e4);
5742
- return () => {
5743
- window.clearInterval(timer);
5744
- document.removeEventListener("visibilitychange", refreshWhenVisible);
5745
- quotaFollowUp.current?.cancel();
5746
- if (loginIntervalRef.current !== null) window.clearInterval(loginIntervalRef.current);
5747
- if (loginTimeoutRef.current !== null) window.clearTimeout(loginTimeoutRef.current);
5748
- };
5749
- }, [loadStatus]);
5750
- const rescan = async () => {
5751
- try {
5752
- setBusy("rescan");
5753
- setError(null);
5754
- const updated = await api$13.request("/rescan", { method: "POST" });
5755
- setStatus(normalizeStatus(updated));
5756
- notifyChange();
5757
- } catch (err) {
5758
- setError(err instanceof Error ? err.message : String(err));
5759
- } finally {
5760
- setBusy(null);
5761
- }
5762
- };
5763
- const login = async (region) => {
5764
- try {
5765
- setBusy(`login:${region}`);
5766
- setError(null);
5767
- setLoginProgress(t.loginWaiting);
5768
- const flow = await api$13.request("/accounts/login", {
5769
- method: "POST",
5770
- body: JSON.stringify({ region })
5771
- });
5772
- if (flow.authUrl) window.open(flow.authUrl, "_blank", "noopener,noreferrer");
5773
- if (loginIntervalRef.current !== null) window.clearInterval(loginIntervalRef.current);
5774
- if (loginTimeoutRef.current !== null) window.clearTimeout(loginTimeoutRef.current);
5775
- const timer = window.setInterval(() => {
5776
- (async () => {
5777
- try {
5778
- const poll = await api$13.request("/accounts/login/status");
5779
- if (poll.progress) setLoginProgress(poll.progress);
5780
- if (poll.status === "complete") {
5781
- window.clearInterval(timer);
5782
- loginIntervalRef.current = null;
5783
- if (loginTimeoutRef.current !== null) window.clearTimeout(loginTimeoutRef.current);
5784
- loginTimeoutRef.current = null;
5785
- setBusy(null);
5786
- setLoginProgress(null);
5787
- if (poll.accountId) await api$13.request("/settings", {
5788
- method: "POST",
5789
- body: JSON.stringify({ selectedAccountId: poll.accountId })
5790
- });
5791
- await loadStatus();
5792
- notifyChange();
5793
- } else if (poll.status === "error") {
5794
- window.clearInterval(timer);
5795
- loginIntervalRef.current = null;
5796
- if (loginTimeoutRef.current !== null) window.clearTimeout(loginTimeoutRef.current);
5797
- loginTimeoutRef.current = null;
5798
- setBusy(null);
5799
- setLoginProgress(null);
5800
- setError(poll.error || t.loginFailed);
5801
- }
5802
- } catch {}
5803
- })();
5804
- }, 1500);
5805
- loginIntervalRef.current = timer;
5806
- loginTimeoutRef.current = window.setTimeout(() => {
5807
- window.clearInterval(timer);
5808
- loginIntervalRef.current = null;
5809
- loginTimeoutRef.current = null;
5810
- setBusy(null);
5811
- setLoginProgress(null);
5812
- }, 300 * 1e3);
5813
- } catch (err) {
5814
- setBusy(null);
5815
- setLoginProgress(null);
5816
- setError(err instanceof Error ? err.message : String(err));
5817
- }
5818
- };
5819
- /**
5820
- * One account action, whether it is a pool action (`set-primary`, `hide`) or a
5821
- * credential action (`delete`). The host route dispatches on `action`.
5822
- */
5823
- const accountAction = async (action, accountId) => {
5824
- try {
5825
- setBusy(`${action}:${accountId}`);
5826
- setError(null);
5827
- const updated = await api$13.request("/accounts/action", {
5828
- method: "POST",
5829
- body: JSON.stringify({
5830
- action,
5831
- accountId
5832
- })
5833
- });
5834
- setStatus(normalizeStatus(updated));
5835
- notifyChange();
5836
- } catch (err) {
5837
- setError(err instanceof Error ? err.message : String(err));
5838
- } finally {
5839
- setBusy(null);
5840
- }
5841
- };
5842
- const deleteAccount = async (accountId) => {
5843
- if (!window.confirm(t.deleteConfirm)) return;
5844
- await accountAction("delete", accountId);
5845
- };
5846
- const setStrategy = async (strategy) => {
5847
- try {
5848
- setBusy("strategy");
5849
- setError(null);
5850
- const updated = await api$13.request("/accounts/strategy", {
5851
- method: "POST",
5852
- body: JSON.stringify({ strategy })
5853
- });
5854
- setStatus(normalizeStatus(updated));
5855
- } catch (err) {
5856
- setError(err instanceof Error ? err.message : String(err));
5857
- } finally {
5858
- setBusy(null);
5859
- }
5860
- };
5861
- const testConnection = async () => {
5862
- try {
5863
- setBusy("connection");
5864
- setError(null);
5865
- setConnection(await api$13.request("/connection/test", { method: "POST" }));
5866
- } catch (err) {
5867
- setError(err instanceof Error ? err.message : String(err));
5868
- } finally {
5869
- setBusy(null);
5870
- }
5871
- };
5872
- const refreshQuota = async () => {
5873
- try {
5874
- setBusy("quota");
5875
- setError(null);
5876
- const updated = await api$13.request("/quota", { method: "POST" });
5877
- setStatus(updated);
5878
- } catch (err) {
5879
- setError(err instanceof Error ? err.message : String(err));
5880
- } finally {
5881
- setBusy(null);
5882
- }
5883
- };
5884
- const checkinNow = async () => {
5885
- try {
5886
- setBusy("checkin");
5887
- setError(null);
5888
- const updated = await api$13.request("/checkin/now", { method: "POST" });
5889
- setStatus(normalizeStatus(updated));
5890
- } catch (err) {
5891
- setError(err instanceof Error ? err.message : String(err));
5892
- } finally {
5893
- setBusy(null);
5894
- }
5895
- };
5896
- const updateCheckin = async (checkin) => {
5897
- try {
5898
- setBusy("checkin");
5899
- setError(null);
5900
- const updated = await api$13.request("/settings", {
5901
- method: "POST",
5902
- body: JSON.stringify({ checkin })
5903
- });
5904
- setStatus(normalizeStatus(updated));
5905
- } catch (err) {
5906
- setError(err instanceof Error ? err.message : String(err));
5907
- } finally {
5908
- setBusy(null);
5909
- }
5910
- };
5911
- /** Switch which client identity chat requests present. */
5912
- const updateOutboundIdentity = async (outboundIdentity) => {
5913
- try {
5914
- setBusy("outbound");
5915
- setError(null);
5916
- const updated = await api$13.request("/settings", {
5917
- method: "POST",
5918
- body: JSON.stringify({ outboundIdentity })
5919
- });
5920
- setStatus(normalizeStatus(updated));
5921
- } catch (err) {
5922
- setError(err instanceof Error ? err.message : String(err));
5923
- } finally {
5924
- setBusy(null);
5925
- }
5926
- };
5927
- /** Arm, change or clear the local quota guardrails. */
5928
- const updateGuardrails = async (guardrails) => {
5929
- try {
5930
- setBusy("guardrails");
5931
- setError(null);
5932
- const updated = await api$13.request("/settings", {
5933
- method: "POST",
5934
- body: JSON.stringify({ guardrails })
5935
- });
5936
- setStatus(normalizeStatus(updated));
5937
- } catch (err) {
5938
- setError(err instanceof Error ? err.message : String(err));
5939
- } finally {
5940
- setBusy(null);
5941
- }
5942
- };
5943
- /** Store the desktop client's at-rest key, which unlocks sealed credentials. */
5944
- const saveAtRestKey = async (key) => {
5945
- try {
5946
- setBusy("atrest");
5947
- setError(null);
5948
- const updated = await api$13.request("/at-rest-key", {
5949
- method: "POST",
5950
- body: JSON.stringify({ key })
5951
- });
5952
- setStatus(normalizeStatus(updated));
5953
- } catch (err) {
5954
- setError(err instanceof Error ? err.message : String(err));
5955
- } finally {
5956
- setBusy(null);
5957
- }
5958
- };
5959
- /** Forget the at-rest key; sealed accounts become unreadable again. */
5960
- const clearAtRestKey = async () => {
5961
- try {
5962
- setBusy("atrest");
5963
- setError(null);
5964
- const updated = await api$13.request("/at-rest-key", { method: "DELETE" });
5965
- setStatus(normalizeStatus(updated));
5966
- } catch (err) {
5967
- setError(err instanceof Error ? err.message : String(err));
5968
- } finally {
5969
- setBusy(null);
5970
- }
5971
- };
5972
- const toggleModel = async (modelId, enabled) => {
5973
- if (status === null) return;
5974
- const current = status.models.filter((model) => model.enabled).map((model) => model.id);
5975
- const next = enabled ? [.../* @__PURE__ */ new Set([...current, modelId])] : current.filter((id) => id !== modelId);
5976
- try {
5977
- setBusy(`model:${modelId}`);
5978
- setError(null);
5979
- const normalized = normalizeStatus(await api$13.request("/settings", {
5980
- method: "POST",
5981
- body: JSON.stringify({ enabledModelIds: next })
5982
- }));
5983
- setStatus(normalized);
5984
- setContextDrafts(contextDraftsFor(normalized));
5985
- notifyChange();
5986
- } catch (err) {
5987
- setError(err instanceof Error ? err.message : String(err));
5988
- } finally {
5989
- setBusy(null);
5990
- }
5991
- };
5992
- const setAllModels = async (enabled) => {
5993
- if (status === null) return;
5994
- try {
5995
- setBusy("models-all");
5996
- setError(null);
5997
- const normalized = normalizeStatus(await api$13.request("/settings", {
5998
- method: "POST",
5999
- body: JSON.stringify({ enabledModelIds: enabled ? status.models.map((model) => model.id) : [] })
6000
- }));
6001
- setStatus(normalized);
6002
- setContextDrafts(contextDraftsFor(normalized));
6003
- notifyChange();
6004
- } catch (err) {
6005
- setError(err instanceof Error ? err.message : String(err));
6006
- } finally {
6007
- setBusy(null);
6008
- }
6009
- };
6010
- const updateEffort = async (effort) => {
6011
- try {
6012
- setBusy("effort");
6013
- setError(null);
6014
- const updated = await api$13.request("/settings", {
6015
- method: "POST",
6016
- body: JSON.stringify({ defaultReasoningEffort: effort })
6017
- });
6018
- setStatus(updated);
6019
- notifyChange();
6020
- } catch (err) {
6021
- setError(err instanceof Error ? err.message : String(err));
6022
- } finally {
6023
- setBusy(null);
6024
- }
6025
- };
6026
- const refreshCatalog = async () => {
6027
- try {
6028
- setBusy("catalog");
6029
- setError(null);
6030
- const normalized = normalizeStatus(await api$13.request("/catalog/refresh", { method: "POST" }));
6031
- setStatus(normalized);
6032
- setContextDrafts(contextDraftsFor(normalized));
6033
- notifyChange();
6034
- } catch (err) {
6035
- setError(err instanceof Error ? err.message : String(err));
6036
- } finally {
6037
- setBusy(null);
6038
- }
6039
- };
6040
- const saveContextWindow = async (modelId) => {
6041
- const raw = contextDrafts[modelId] || "";
6042
- const parsed = parsePositiveCapacity$1(raw);
6043
- if (parsed === null) {
6044
- setError(`Invalid context capacity: ${raw}`);
6045
- return;
6046
- }
6047
- try {
6048
- setSavingModel(modelId);
6049
- setError(null);
6050
- const updated = await api$13.request("/settings", {
6051
- method: "POST",
6052
- body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
6053
- });
6054
- setStatus(updated);
6055
- setContextDrafts((prev) => ({
6056
- ...prev,
6057
- [modelId]: formatCapacity$1(parsed)
6058
- }));
6059
- notifyChange();
6060
- } catch (err) {
6061
- setError(err instanceof Error ? err.message : String(err));
6062
- } finally {
6063
- setSavingModel(null);
6064
- }
6065
- };
6066
- /** Clear one override; the row falls back to the catalog length. */
6067
- const resetContextWindow = async (modelId) => {
6068
- try {
6069
- setSavingModel(modelId);
6070
- setError(null);
6071
- const updated = normalizeStatus(await api$13.request("/settings", {
6072
- method: "POST",
6073
- body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
6074
- }));
6075
- setStatus(updated);
6076
- setContextDrafts((prev) => {
6077
- const model = updated.models.find((candidate) => candidate.id === modelId);
6078
- return model === void 0 ? prev : {
6079
- ...prev,
6080
- [modelId]: formatCapacity$1(model.defaultContextWindow)
6081
- };
6082
- });
6083
- notifyChange();
6084
- } catch (err) {
6085
- setError(err instanceof Error ? err.message : String(err));
6086
- } finally {
6087
- setSavingModel(null);
6088
- }
6089
- };
6090
- /** Clear every stored override, including models the picker no longer shows. */
6091
- const resetAllContextWindows = async () => {
6092
- const models = Object.keys(status?.contextWindowOverrides ?? {});
6093
- if (models.length === 0) return;
6094
- if (!window.confirm(t.contextWindowResetAllConfirm)) return;
6095
- try {
6096
- setBusy("context");
6097
- setError(null);
6098
- const updated = normalizeStatus(await api$13.request("/settings", {
6099
- method: "POST",
6100
- body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
6101
- }));
6102
- setStatus(updated);
6103
- setContextDrafts(contextDraftsFor(updated));
6104
- notifyChange();
6105
- } catch (err) {
6106
- setError(err instanceof Error ? err.message : String(err));
6107
- } finally {
6108
- setBusy(null);
6109
- }
6110
- };
6111
- const updateContextDraft = (modelId, draft) => {
6112
- setContextDrafts((prev) => ({
6113
- ...prev,
6114
- [modelId]: draft
6115
- }));
6116
- };
6117
- const contextModels = status?.models.filter((model) => model.enabled) ?? [];
6118
- const overrideCount = Object.keys(status?.contextWindowOverrides ?? {}).length;
6119
- const quota = status?.quota;
6120
- const authenticated = status?.authenticated === true;
6121
- return {
6122
- state: {
6123
- status,
6124
- loading,
6125
- busy,
6126
- error,
6127
- connection,
6128
- loginProgress,
6129
- contextDrafts,
6130
- savingModel
6131
- },
6132
- derived: {
6133
- poolAccounts,
6134
- effortChoices,
6135
- allModels,
6136
- strayEffort,
6137
- contextModels,
6138
- overrideCount,
6139
- quota,
6140
- authenticated,
6141
- unreachable: statusFailed && status === null,
6142
- poolLabels: accountPoolLabels(t)
6143
- },
6144
- actions: {
6145
- login,
6146
- rescan,
6147
- accountAction,
6148
- deleteAccount,
6149
- setStrategy,
6150
- testConnection,
6151
- refreshQuota,
6152
- checkinNow,
6153
- updateCheckin,
6154
- toggleModel,
6155
- setAllModels,
6156
- updateEffort,
6157
- refreshCatalog,
6158
- saveContextWindow,
6159
- resetContextWindow,
6160
- resetAllContextWindows,
6161
- updateContextDraft,
6162
- updateOutboundIdentity,
6163
- updateGuardrails,
6164
- saveAtRestKey,
6165
- clearAtRestKey
6166
- }
6167
- };
6168
- }
6169
- //#endregion
6170
- //#region src/client/workbuddy/WorkBuddySection.tsx
6171
- /**
6172
- * The WorkBuddy subscription settings card.
6173
- *
6174
- * Markup only: every piece of state, every effect and every request this card
6175
- * makes lives in 'useWorkBuddySection.ts', which returns one named shape the JSX
6176
- * below reads. The two files are the split of a single 885-line component — the
6177
- * behaviour is unchanged, and this one should stay render-shaped.
6178
- */
6179
- /**
6180
- * Display label per reasoning level. The locale dictionary only accepts flat
6181
- * string values, so this nested table lives with the control that renders it.
6182
- */
6183
- const EFFORT_LABELS$2 = {
6184
- none: "Off",
6185
- minimal: "Minimal",
6186
- low: "Low",
6187
- medium: "Medium",
6188
- high: "High",
6189
- xhigh: "X-High",
6190
- max: "Max"
6191
- };
6192
- /**
6193
- * The consumption rate of one model, as the settings row states it.
6194
- *
6195
- * The gateway publishes one rate per region and the official CodeBuddy picker
6196
- * spells it beside a model as `6.67x`; the row uses the same shape behind the
6197
- * section's own label. Which rates reach the row depends on what the card knows
6198
- * about the account, and the two cases are deliberately different:
6199
- *
6200
- * - A KNOWN region shows that region's rate and nothing else. Borrowing the
6201
- * sibling region's number would state a price this account never pays —
6202
- * measured 2026-10-09, `deepseek-v4.1-flash` is `0.11` on cn against `0.00`
6203
- * on intl, and the backends reject a model asked of the wrong region anyway.
6204
- * - An UNKNOWN region (no account read back yet) shows both rates when the
6205
- * backends disagree, so the row is honest about the range instead of picking
6206
- * one of them. When they agree there is nothing to disambiguate.
6207
- *
6208
- * The two-region form is assembled entirely from the caller's labels: the
6209
- * qualifier comes from `labels.region(value, key)` and the join from
6210
- * `labels.pair(first, second)`, so the dictionary owns the region nouns, the
6211
- * bracket glyphs AND the separator. Nothing about the two-region string is
6212
- * spelled in this file, which is the point — the glyphs differ per language
6213
- * (`倍率 0.11x(国区) / 0.00x(国际区)` in Chinese,
6214
- * `Multiplier 0.11x (China) / 0.00x (International)` in English) and a
6215
- * separator chosen here would be right in at most one of them.
6216
- *
6217
- * `null` means "this row states no rate"; the caller drops it from the hint
6218
- * array rather than rendering a placeholder, because a guessed rate on a spend
6219
- * figure is worse than a missing one. `'0.00'` is a declaration — this model
6220
- * consumes no allowance — so it renders like any other value.
6221
- */
6222
- function creditMultiplierHint(credits, region, labels) {
6223
- const rate = (key) => {
6224
- const value = credits?.[key];
6225
- return typeof value === "string" && value !== "" ? value : null;
6226
- };
6227
- if (region !== null) {
6228
- const value = rate(region);
6229
- return value === null ? null : `${labels.multiplier} ${value}x`;
6230
- }
6231
- const cn = rate("cn");
6232
- const intl = rate("intl");
6233
- if (cn === null) return intl === null ? null : `${labels.multiplier} ${intl}x`;
6234
- if (intl === null || intl === cn) return `${labels.multiplier} ${cn}x`;
6235
- return `${labels.multiplier} ${labels.pair(labels.region(`${cn}x`, "cn"), labels.region(`${intl}x`, "intl"))}`;
6236
- }
6237
- /** Mask a UIN so the card shows identity without publishing the full number. */
6238
- function maskUin(uin) {
6239
- if (uin === void 0 || uin === null || uin === "") return "—";
6240
- if (uin.length <= 6) return uin;
6241
- return `${uin.slice(0, 4)}****${uin.slice(-2)}`;
6242
- }
6243
- function WorkBuddySection({ onModelChange, loadModelDirectory }) {
6244
- const { state, derived, actions } = useWorkBuddySection({
6245
- onModelChange,
6246
- loadModelDirectory
6247
- });
6248
- const { status, loading, busy, error, connection, loginProgress, contextDrafts, savingModel } = state;
6249
- const { poolAccounts, effortChoices, allModels, strayEffort, contextModels, overrideCount, quota, authenticated, unreachable, poolLabels } = derived;
6250
- const sealedCount = status?.sealedAccounts ?? 0;
6251
- const { login, rescan, accountAction, deleteAccount, setStrategy, testConnection, refreshQuota, checkinNow, updateCheckin, toggleModel, setAllModels, updateEffort, refreshCatalog, saveContextWindow, resetContextWindow, resetAllContextWindows, updateContextDraft, updateOutboundIdentity, saveAtRestKey, clearAtRestKey, updateGuardrails } = actions;
6252
- const [keyDraft, setKeyDraft] = (0, react.useState)("");
6253
- const [guardrailDrafts, setGuardrailDrafts] = (0, react.useState)({});
6254
- const t = zh$10;
6255
- if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6256
- className: "dsha-page",
6257
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6258
- className: "dsha-empty",
6259
- children: t.loading
6260
- })
6261
- });
6262
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6263
- className: "dsha-page",
6264
- children: [
6265
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(AccountPoolSection, {
6266
- accounts: poolAccounts,
6267
- activeAccountId: status?.activeAccountId,
6268
- rotationStrategy: status?.rotationStrategy ?? "sequential",
6269
- labels: poolLabels,
6270
- busy,
6271
- showQuota: true,
6272
- onLogin: () => void login("cn"),
6273
- onSetPrimary: (id) => void accountAction("set-primary", id),
6274
- onDelete: (id) => void deleteAccount(id),
6275
- onClearCooldown: (id) => void accountAction("clear-cooldown", id),
6276
- onRelogin: (id) => void accountAction("relogin", id),
6277
- onSetStrategy: (strategy) => void setStrategy(strategy),
6278
- renderLoginActions: () => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6279
- className: "dsha-account-add-actions",
6280
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6281
- className: "dsha-btn dsha-btn-primary",
6282
- disabled: busy !== null,
6283
- onClick: () => void login("cn"),
6284
- children: busy === "login:cn" ? t.authorizing : t.addCnAccount
6285
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6286
- className: "dsha-btn dsha-btn-primary",
6287
- disabled: busy !== null,
6288
- onClick: () => void login("intl"),
6289
- children: busy === "login:intl" ? t.authorizing : t.addIntlAccount
6290
- })]
6291
- }),
6292
- renderAccountActions: (candidate) => candidate.removable ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [candidate.hidden === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6293
- className: "dsha-btn",
6294
- disabled: busy !== null,
6295
- onClick: () => void accountAction("restore", candidate.id),
6296
- children: t.restoreAccount
6297
- }), candidate.hidden !== true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6298
- className: "dsha-btn",
6299
- disabled: busy !== null,
6300
- onClick: () => void accountAction("hide", candidate.id),
6301
- children: t.hideAccount
6302
- })] }),
6303
- renderDetails: (candidate) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
6304
- candidate.uin ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6305
- t.uin,
6306
- ": ",
6307
- maskUin(candidate.uin)
6308
- ] }) : null,
6309
- candidate.accountType ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6310
- t.accountType,
6311
- ": ",
6312
- candidate.accountType
6313
- ] }) : null,
6314
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6315
- t.region,
6316
- ": ",
6317
- candidate.region === "intl" ? t.regionIntl : t.regionCn
6318
- ] }),
6319
- candidate.domain ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6320
- className: "dshwb-mono",
6321
- title: `${candidate.domain} · ${candidate.backend ?? ""}`,
6322
- children: candidate.domain
6323
- }) : null,
6324
- candidate.hidden === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.hiddenAccount }) : null
6325
- ] }),
6326
- children: [
6327
- unreachable ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6328
- className: "dsha-empty",
6329
- children: t.routeUnreachable
6330
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6331
- className: "dsha-notice",
6332
- children: t.routeUnreachableHint
6333
- })] }) : null,
6334
- loginProgress ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6335
- className: "dsha-notice",
6336
- children: loginProgress
6337
- }) : null,
6338
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6339
- className: "dsha-actions",
6340
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6341
- className: "dsha-btn",
6342
- disabled: busy !== null,
6343
- onClick: () => void rescan(),
6344
- children: busy === "rescan" ? t.rescanning : t.rescan
6345
- })
6346
- })
6347
- ]
6348
- }),
6349
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
6350
- className: "dsha-group",
6351
- children: [
6352
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6353
- className: "dsha-label",
6354
- style: { fontWeight: 600 },
6355
- children: t.outboundSection
6356
- }),
6357
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6358
- className: "dsha-muted",
6359
- children: t.outboundHint
6360
- }),
6361
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6362
- style: { margin: "10px 0 14px" },
6363
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
6364
- className: "dsha-select",
6365
- value: status?.outboundIdentity ?? "cli",
6366
- disabled: busy !== null,
6367
- onChange: (event) => void updateOutboundIdentity(event.currentTarget.value),
6368
- children: [
6369
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6370
- value: "cli",
6371
- children: t.outboundCli
6372
- }),
6373
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6374
- value: "auto",
6375
- children: t.outboundAuto
6376
- }),
6377
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6378
- value: "workbuddy",
6379
- children: t.outboundWorkbuddy
6380
- }),
6381
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6382
- value: "vscode",
6383
- children: t.outboundVscode
6384
- })
6385
- ]
6386
- })
6387
- }),
6388
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6389
- className: "dsha-label",
6390
- style: {
6391
- fontWeight: 600,
6392
- marginTop: 12
6393
- },
6394
- children: t.guardrailsSection
6395
- }),
6396
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6397
- className: "dsha-muted",
6398
- children: t.guardrailsHint
6399
- }),
6400
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6401
- className: "dshwb-fields",
6402
- children: [
6403
- ["reserveCredits", t.guardrailsReserve],
6404
- ["dailyTokens", t.guardrailsDaily],
6405
- ["modelDailyTokens", t.guardrailsModelDaily]
6406
- ].map(([field, label]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
6407
- className: "dshwb-field",
6408
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6409
- className: "dshwb-control",
6410
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6411
- type: "number",
6412
- min: 0,
6413
- step: 1,
6414
- disabled: busy !== null,
6415
- value: guardrailDrafts[field] ?? String(status?.guardrails?.[field] ?? 0),
6416
- onChange: (event) => setGuardrailDrafts((prev) => ({
6417
- ...prev,
6418
- [field]: event.currentTarget.value
6419
- })),
6420
- onBlur: () => {
6421
- const draft = guardrailDrafts[field];
6422
- if (draft === void 0) return;
6423
- setGuardrailDrafts((prev) => {
6424
- const next = { ...prev };
6425
- delete next[field];
6426
- return next;
6427
- });
6428
- const value = Math.floor(Number(draft));
6429
- if (!Number.isFinite(value) || value < 0) return;
6430
- updateGuardrails({ [field]: value });
6431
- }
6432
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: field === "reserveCredits" ? "credits" : "tokens" })]
4900
+ className: "dsha-page",
4901
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4902
+ className: "dsha-empty",
4903
+ children: t.loading
4904
+ })
4905
+ });
4906
+ const quota = status?.quota;
4907
+ status?.account;
4908
+ status?.models.filter((model) => model.enabled).length;
4909
+ const loginPending = flow?.status === "pending";
4910
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4911
+ className: "dsha-page",
4912
+ children: [
4913
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountPoolSection, {
4914
+ accounts: status?.accounts ?? [],
4915
+ activeAccountId: status?.activeAccountId,
4916
+ rotationStrategy: status?.rotationStrategy ?? "sequential",
4917
+ busy,
4918
+ labels: t,
4919
+ loginBusyLabel: loginPending ? t.waitingAuthorization : busy === "login" ? t.requestingCode : void 0,
4920
+ onLogin: () => void handleLogin(),
4921
+ onSetPrimary: (accountId) => void handleAccountAction("set-primary", accountId),
4922
+ onDelete: (accountId) => void handleAccountAction("delete", accountId),
4923
+ onClearCooldown: (accountId) => void handleAccountAction("clear-cooldown", accountId),
4924
+ onRelogin: (accountId) => handleRelogin(accountId),
4925
+ onSetStrategy: (strategy) => void handleSetStrategy(strategy),
4926
+ showQuota: true,
4927
+ renderDetails: (entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [entry.planName && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
4928
+ t.plan,
4929
+ ": ",
4930
+ entry.planName
4931
+ ] }), entry.region && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
4932
+ t.region,
4933
+ ": ",
4934
+ entry.region === "global" ? t.regionGlobal : t.regionMainland
4935
+ ] })] }),
4936
+ children: loginPending && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4937
+ className: "dsha-device-box",
4938
+ children: [
4939
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.deviceCodeSection }),
4940
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4941
+ className: "dsha-muted",
4942
+ children: t.deviceCodeHint
4943
+ }),
4944
+ flow?.userCode && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4945
+ className: "dsha-code-row",
4946
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4947
+ className: "dsha-code",
4948
+ children: flow.userCode
4949
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4950
+ className: "dsha-btn",
4951
+ onClick: () => void handleCopyCode(),
4952
+ children: copied ? t.copied : t.copyCode
6433
4953
  })]
6434
- }, field))
6435
- }),
6436
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6437
- className: "dsha-label",
6438
- style: {
6439
- fontWeight: 600,
6440
- marginTop: 12
6441
- },
6442
- children: t.atRestSection
6443
- }),
6444
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6445
- className: "dsha-muted",
6446
- children: t.atRestHint
6447
- }),
6448
- sealedCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6449
- className: "dsha-notice",
6450
- children: t.atRestSealed.replace("{count}", String(sealedCount))
6451
- }) : null,
6452
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6453
- className: "dshwb-inputrow",
6454
- children: [
6455
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6456
- type: "password",
6457
- autoComplete: "off",
6458
- spellCheck: false,
6459
- placeholder: t.atRestPlaceholder,
6460
- value: keyDraft,
6461
- disabled: busy !== null,
6462
- onChange: (event) => setKeyDraft(event.currentTarget.value)
6463
- }),
6464
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6465
- className: "dsha-btn dsha-btn-primary",
6466
- disabled: busy !== null || keyDraft.trim() === "",
6467
- onClick: () => {
6468
- saveAtRestKey(keyDraft.trim()).then(() => setKeyDraft(""));
6469
- },
6470
- children: busy === "atrest" ? t.saving : t.atRestSave
6471
- }),
6472
- status?.atRestKeySet === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6473
- className: "dsha-muted",
6474
- children: t.atRestSaved
4954
+ }),
4955
+ flow?.verificationUriComplete && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
4956
+ className: "dsha-link",
4957
+ href: flow.verificationUriComplete,
4958
+ target: "_blank",
4959
+ rel: "noreferrer noopener",
4960
+ children: flow.verificationUriComplete
4961
+ }),
4962
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4963
+ className: "dsha-row",
4964
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4965
+ className: "dsha-label",
4966
+ children: t.codeExpires
4967
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4968
+ className: "dsha-value",
4969
+ children: formatDate$1(flow?.expiresAt)
4970
+ })]
4971
+ }),
4972
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4973
+ className: "dsha-actions",
4974
+ children: [flow?.verificationUriComplete && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
4975
+ className: "dsha-btn",
4976
+ href: flow.verificationUriComplete,
4977
+ target: "_blank",
4978
+ rel: "noreferrer noopener",
4979
+ children: t.openSignInPage
6475
4980
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6476
4981
  className: "dsha-btn",
6477
4982
  disabled: busy !== null,
6478
- onClick: () => void clearAtRestKey(),
6479
- children: t.atRestClear
6480
- })] }) : null
6481
- ]
6482
- })
6483
- ]
4983
+ onClick: () => void handleCancelLogin(),
4984
+ children: t.cancelSignIn
4985
+ })]
4986
+ })
4987
+ ]
4988
+ })
6484
4989
  }),
6485
- status?.checkin != null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
4990
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
6486
4991
  className: "dsha-group",
6487
4992
  children: [
6488
4993
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6489
4994
  className: "dsha-grouphead",
6490
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.dailyCheckin })
6491
- }),
6492
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6493
- className: "dsha-muted",
6494
- children: t.checkinHint
4995
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.connection })
6495
4996
  }),
6496
4997
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6497
4998
  className: "dsha-row",
6498
- style: { marginBottom: 8 },
6499
4999
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6500
5000
  className: "dsha-label",
6501
- style: { fontWeight: 600 },
6502
- children: t.checkinAuto
6503
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
6504
- type: "checkbox",
6505
- checked: status.checkin.enabled,
6506
- disabled: busy !== null,
6507
- onChange: (event) => void updateCheckin({ enabled: event.currentTarget.checked })
5001
+ children: t.oauthHost
5002
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5003
+ className: "dsha-value",
5004
+ children: status?.oauthHost || "—"
6508
5005
  })]
6509
5006
  }),
6510
5007
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6511
5008
  className: "dsha-row",
6512
5009
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6513
5010
  className: "dsha-label",
6514
- children: t.dailyCheckin
6515
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5011
+ children: t.codingEndpoint
5012
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6516
5013
  className: "dsha-value",
6517
- children: [
6518
- t.checkinToday.replace("{done}", String(status.checkin.doneToday)).replace("{total}", String(status.checkin.totalAccounts)),
6519
- status.checkin.skippedToday > 0 ? ` · ${t.checkinSkipped.replace("{count}", String(status.checkin.skippedToday))}` : "",
6520
- status.checkin.failedToday > 0 ? ` · ${t.checkinFailed.replace("{count}", String(status.checkin.failedToday))}` : "",
6521
- ` · ${status.checkin.lastRunAt === null ? t.checkinNever : t.checkinLastRun.replace("{time}", new Date(status.checkin.lastRunAt).toLocaleString())}`
6522
- ]
5014
+ children: status?.codingBaseUrl || "—"
6523
5015
  })]
6524
5016
  }),
5017
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5018
+ className: "dsha-notice",
5019
+ children: status?.serving === false && status.conflict ? t.routeConflict.replace("{detail}", status.conflict) : t.routeOwned
5020
+ }),
5021
+ connectionNotice && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5022
+ className: "dsha-muted",
5023
+ children: connectionNotice
5024
+ }),
6525
5025
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6526
5026
  className: "dsha-actions",
6527
5027
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6528
5028
  className: "dsha-btn",
6529
- disabled: busy !== null,
6530
- onClick: () => void checkinNow(),
6531
- children: busy === "checkin" ? t.checkinRunning : t.checkinNow
5029
+ disabled: busy !== null || !status?.authenticated,
5030
+ onClick: () => void handleTestConnection(),
5031
+ children: busy === "connection" ? t.testingConnection : t.testConnection
6532
5032
  })
6533
5033
  })
6534
5034
  ]
6535
- }) : null,
5035
+ }),
6536
5036
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
6537
5037
  className: "dsha-group",
6538
5038
  children: [
6539
5039
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6540
5040
  className: "dsha-grouphead",
6541
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.connection })
5041
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.cacheSection })
6542
5042
  }),
6543
5043
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6544
- className: "dsha-notice",
6545
- children: status?.serving === false && status.conflict ? t.routeConflict.replace("{detail}", status.conflict) : t.routeOwned
5044
+ className: "dsha-muted",
5045
+ children: t.cacheDesc
6546
5046
  }),
6547
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6548
- className: "dsha-actions",
6549
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6550
- className: "dsha-btn",
6551
- disabled: busy !== null || !authenticated,
6552
- onClick: () => void testConnection(),
6553
- children: busy === "connection" ? t.testingConnection : t.testConnection
6554
- })
5047
+ status?.cacheHint != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5048
+ className: "dsha-warn",
5049
+ children: t.cacheExpired.replace("{tokens}", status.cacheHint.totalTokens.toLocaleString())
5050
+ }),
5051
+ status?.cache == null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5052
+ className: "dsha-empty",
5053
+ children: t.cacheEmpty
5054
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5055
+ className: "dsha-quota-card",
5056
+ children: [
5057
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5058
+ className: "dsha-meter-wrap",
5059
+ children: [
5060
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5061
+ className: "dsha-meter-label",
5062
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.cacheHitRatio }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: status.cache.hitRatio === null ? "—" : `${(status.cache.hitRatio * 100).toFixed(1)}%` })]
5063
+ }),
5064
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5065
+ className: `dsha-meter ${(status.cache.hitRatio ?? 0) >= .9 ? "dsha-meter-green" : "dsha-meter-cyan"}`,
5066
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: { width: `${Math.round((status.cache.hitRatio ?? 0) * 100)}%` } })
5067
+ }),
5068
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5069
+ className: "dsha-meter-meta",
5070
+ children: [
5071
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5072
+ t.cacheCached,
5073
+ ": ",
5074
+ status.cache.cachedTokens.toLocaleString()
5075
+ ] }),
5076
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5077
+ t.cacheFresh,
5078
+ ": ",
5079
+ status.cache.freshTokens.toLocaleString()
5080
+ ] }),
5081
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5082
+ t.cacheOutput,
5083
+ ": ",
5084
+ status.cache.outputTokens.toLocaleString()
5085
+ ] }),
5086
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5087
+ t.cacheRequests,
5088
+ ": ",
5089
+ status.cache.requests
5090
+ ] })
5091
+ ]
5092
+ })
5093
+ ]
5094
+ }),
5095
+ status.cache.lastDrift !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5096
+ className: "dsha-row",
5097
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5098
+ className: "dsha-label",
5099
+ children: t.cacheDrift
5100
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5101
+ className: "dsha-value",
5102
+ children: driftLabel(status.cache.lastDrift, t)
5103
+ })]
5104
+ }),
5105
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5106
+ className: "dsha-muted",
5107
+ children: t.cacheHint
5108
+ })
5109
+ ]
6555
5110
  })
6556
5111
  ]
6557
5112
  }),
@@ -6562,8 +5117,8 @@ window.__ModuleLoader__.load({
6562
5117
  className: "dsha-grouphead",
6563
5118
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.modelsSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6564
5119
  className: "dsha-btn",
6565
- disabled: busy !== null || !authenticated,
6566
- onClick: () => void refreshCatalog(),
5120
+ disabled: busy !== null,
5121
+ onClick: () => void handleRefreshCatalog(),
6567
5122
  children: busy === "catalog" ? t.refreshingCatalog : t.refreshCatalog
6568
5123
  })]
6569
5124
  }),
@@ -6572,33 +5127,27 @@ window.__ModuleLoader__.load({
6572
5127
  children: t.modelsHint
6573
5128
  }),
6574
5129
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelChecklist, {
6575
- items: (status?.models ?? []).map((model) => {
6576
- const multiplier = creditMultiplierHint(model.credits, status?.account?.region ?? null, {
6577
- multiplier: t.creditMultiplier,
6578
- region: (value, key) => t.creditMultiplierRegion.replace("{value}", value).replace("{region}", key === "cn" ? t.regionCn : t.regionIntl),
6579
- pair: (first, second) => t.creditMultiplierPair.replace("{first}", first).replace("{second}", second)
6580
- });
6581
- return {
6582
- id: model.id,
6583
- name: model.name,
6584
- hint: [
6585
- formatCapacity$1(model.contextWindow),
6586
- model.supportsImage ? t.imageSupport : t.textOnly,
6587
- ...model.reasoningEfforts && model.reasoningEfforts.length > 0 ? [model.reasoningEfforts.join("/")] : [],
6588
- ...multiplier === null ? [] : [multiplier]
6589
- ].join(" · "),
6590
- enabled: model.enabled
6591
- };
6592
- }),
5130
+ items: (status?.models ?? []).map((model) => ({
5131
+ id: model.id,
5132
+ name: model.name,
5133
+ hint: [
5134
+ model.wire === "anthropic" ? t.wireAnthropic : t.wireOpenai,
5135
+ ...model.supportsVideo ? [t.capVideo] : [],
5136
+ ...model.supportsDynamicTools ? [t.capDynamicTools] : [],
5137
+ ...model.minimumPlan ? [t.capPlan.replace("{plan}", model.minimumPlan)] : []
5138
+ ].join(" · "),
5139
+ enabled: model.enabled
5140
+ })),
6593
5141
  busy: busy !== null,
6594
- onToggle: (id, enabled) => void toggleModel(id, enabled),
6595
- onToggleAll: (enabled) => void setAllModels(enabled),
5142
+ onToggle: toggleModel,
5143
+ onToggleAll: setAllModels,
6596
5144
  labels: {
6597
5145
  selectAll: t.selectAll,
6598
5146
  clearAll: t.unselectAll,
6599
5147
  list: t.modelsSection
6600
5148
  }
6601
- })
5149
+ }),
5150
+ status !== null && status.models.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KimiModelCapabilities, { models: status.models })
6602
5151
  ]
6603
5152
  }),
6604
5153
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
@@ -6610,45 +5159,57 @@ window.__ModuleLoader__.load({
6610
5159
  }),
6611
5160
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6612
5161
  className: "dsha-pref-row",
6613
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
6614
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.defaultReasoningEffort }),
6615
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6616
- className: "dsha-muted",
6617
- children: t.defaultReasoningEffortHint
6618
- }),
6619
- strayEffort !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6620
- className: "dsha-muted",
6621
- children: t.defaultEffortKept
6622
- }) : null
6623
- ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
5162
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.defaultReasoningEffort }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5163
+ className: "dsha-muted",
5164
+ children: t.defaultReasoningEffortHint
5165
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
6624
5166
  className: "dsha-select",
6625
5167
  "aria-label": t.defaultReasoningEffort,
6626
5168
  value: status?.defaultReasoningEffort ?? "",
6627
5169
  disabled: busy !== null,
6628
5170
  onChange: (event) => {
6629
5171
  const value = event.currentTarget.value;
6630
- updateEffort(value === "" ? null : value);
5172
+ handleUpdateEffort(value === "" ? null : value);
5173
+ },
5174
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5175
+ value: "",
5176
+ children: t.defaultEffortAuto
5177
+ }), KIMI_CODE_REASONING_EFFORTS.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5178
+ value: effort,
5179
+ children: EFFORT_LABEL[effort]
5180
+ }, effort))]
5181
+ })]
5182
+ }),
5183
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5184
+ className: "dsha-pref-row",
5185
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.cacheTtl }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5186
+ className: "dsha-muted",
5187
+ children: t.cacheTtlHint
5188
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
5189
+ className: "dsha-select",
5190
+ "aria-label": t.cacheTtl,
5191
+ value: status?.cacheTtl ?? "",
5192
+ disabled: busy !== null,
5193
+ onChange: (event) => {
5194
+ const value = event.currentTarget.value;
5195
+ handleUpdateCacheTtl(value === "" ? null : value);
6631
5196
  },
6632
5197
  children: [
6633
5198
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6634
5199
  value: "",
6635
- children: t.defaultEffortAuto
5200
+ children: t.cacheTtlDefault
6636
5201
  }),
6637
- strayEffort !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6638
- value: strayEffort,
6639
- children: `${EFFORT_LABELS$2[strayEffort]} (${t.effortUnsupported})`
6640
- }) : null,
6641
- effortChoices.map((choice) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
6642
- value: choice.value,
6643
- children: choice.models.length === allModels.length ? EFFORT_LABELS$2[choice.value] : `${EFFORT_LABELS$2[choice.value]} (${choice.models.length}/${allModels.length})`
6644
- }, choice.value))
5202
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5203
+ value: "5m",
5204
+ children: t.cacheTtl5m
5205
+ }),
5206
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
5207
+ value: "1h",
5208
+ children: t.cacheTtl1h
5209
+ })
6645
5210
  ]
6646
5211
  })]
6647
- }),
6648
- effortChoices.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6649
- className: "dsha-muted",
6650
- children: t.noReasoningModels
6651
- }) : null
5212
+ })
6652
5213
  ]
6653
5214
  }),
6654
5215
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
@@ -6667,12 +5228,13 @@ window.__ModuleLoader__.load({
6667
5228
  id: model.id,
6668
5229
  name: model.name,
6669
5230
  draft: contextDrafts[model.id] ?? "",
5231
+ meta: model.defaultContextWindow < model.contextWindow ? formatCapacity$1(model.contextWindow) : void 0,
6670
5232
  inputLabel: `${model.name} context window`,
6671
5233
  hasOverride: status?.contextWindowOverrides[model.id] !== void 0,
6672
5234
  saving: savingModel === model.id
6673
5235
  })),
6674
5236
  labels: {
6675
- tokens: "tokens",
5237
+ tokens: t.tokens,
6676
5238
  save: t.save,
6677
5239
  saving: t.saving,
6678
5240
  reset: t.contextWindowReset,
@@ -6681,10 +5243,14 @@ window.__ModuleLoader__.load({
6681
5243
  },
6682
5244
  busy: busy !== null,
6683
5245
  overrideCount,
6684
- onDraftChange: (id, draft) => updateContextDraft(id, draft),
6685
- onCommit: (id) => void saveContextWindow(id),
6686
- onReset: (id) => void resetContextWindow(id),
6687
- onResetAll: () => void resetAllContextWindows()
5246
+ metaClassName: "dsha-model-meta",
5247
+ onDraftChange: (id, draft) => setContextDrafts((prev) => ({
5248
+ ...prev,
5249
+ [id]: draft
5250
+ })),
5251
+ onCommit: (id) => void handleSaveContextWindow(id),
5252
+ onReset: (id) => void handleResetContextWindow(id),
5253
+ onResetAll: () => void handleResetAllContextWindows()
6688
5254
  })
6689
5255
  ]
6690
5256
  }),
@@ -6695,8 +5261,8 @@ window.__ModuleLoader__.load({
6695
5261
  className: "dsha-grouphead",
6696
5262
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.quotaSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
6697
5263
  className: "dsha-btn",
6698
- disabled: busy !== null || !authenticated,
6699
- onClick: () => void refreshQuota(),
5264
+ disabled: busy !== null || !status?.authenticated,
5265
+ onClick: () => void handleRefreshQuota(),
6700
5266
  children: busy === "quota" ? t.refreshingQuota : t.refreshQuota
6701
5267
  })]
6702
5268
  }),
@@ -6706,9 +5272,13 @@ window.__ModuleLoader__.load({
6706
5272
  }),
6707
5273
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
6708
5274
  className: "dsha-muted",
6709
- children: poolLabels.quotaFactsScope
5275
+ children: t.quotaFactsScope
6710
5276
  }),
6711
- !authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5277
+ status?.quotaError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
5278
+ className: "dsha-notice",
5279
+ children: status.quotaError
5280
+ }),
5281
+ !status?.authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6712
5282
  className: "dsha-empty",
6713
5283
  children: t.signedOut
6714
5284
  }) : quota === null || quota === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -6719,58 +5289,23 @@ window.__ModuleLoader__.load({
6719
5289
  children: [
6720
5290
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6721
5291
  className: "dsha-quota-title",
6722
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: quota.packageName || t.quotaPackage }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: quota.remainingCredits !== null ? `${quota.remainingCredits} ${t.credits}` : "—" })]
6723
- }),
6724
- quota.cycleUsedCredits !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6725
- className: "dsha-row",
6726
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6727
- className: "dsha-label",
6728
- children: t.quotaCycle
6729
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6730
- className: "dsha-value",
6731
- children: [
6732
- quota.cycleUsedCredits,
6733
- quota.cycleCredits !== null ? ` / ${quota.cycleCredits}` : "",
6734
- ` ${t.credits}`
6735
- ]
6736
- })]
5292
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.quotaPlan }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: quota.planName || t.planUnknown })]
6737
5293
  }),
6738
- quota.cycleEndsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6739
- className: "dsha-row",
6740
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6741
- className: "dsha-label",
6742
- children: t.quotaReset
6743
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6744
- className: "dsha-value",
6745
- children: [formatDate$1(quota.cycleEndsAt), formatReset$1(quota.cycleEndsAt) ? ` · ${formatReset$1(quota.cycleEndsAt)}` : ""]
5294
+ quota.extraUsage !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5295
+ className: "dsha-meter-wrap",
5296
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5297
+ className: "dsha-meter-label",
5298
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.quotaWallet }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: formatMoney(quota.extraUsage.balanceCents, quota.extraUsage.currency) })]
5299
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5300
+ className: "dsha-meter-meta",
5301
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatMoney(quota.extraUsage.totalCents, quota.extraUsage.currency) }), quota.extraUsage.monthlyChargeLimitEnabled && quota.extraUsage.monthlyChargeLimitCents !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
5302
+ t.quotaWalletLimit,
5303
+ ": ",
5304
+ formatMoney(quota.extraUsage.monthlyChargeLimitCents, quota.extraUsage.currency)
5305
+ ] })]
6746
5306
  })]
6747
5307
  }),
6748
- quota.meters.filter((meter) => meter.remainingFraction === null).map((meter) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6749
- className: "dsha-meter-wrap",
6750
- children: [
6751
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6752
- className: "dsha-meter-label",
6753
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: meter.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: meter.limit ?? "—" })]
6754
- }),
6755
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6756
- className: "dsha-meter-meta",
6757
- children: [meter.used !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6758
- meter.used,
6759
- " / ",
6760
- meter.limit ?? "—"
6761
- ] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
6762
- t.quotaReset,
6763
- ": ",
6764
- formatReset$1(meter.resetsAt)
6765
- ] })]
6766
- }),
6767
- meter.description !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6768
- className: "dsha-meter-meta",
6769
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: meter.description })
6770
- })
6771
- ]
6772
- }, meter.id)),
6773
- quota.meters.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
5308
+ quota.windows.length === 0 && quota.extraUsage === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6774
5309
  className: "dsha-empty",
6775
5310
  children: t.quotaEmpty
6776
5311
  }),
@@ -6804,10 +5339,10 @@ window.__ModuleLoader__.load({
6804
5339
  * The names stay as they were so the hook that consumes them does not have to
6805
5340
  * change with the reader.
6806
5341
  */
6807
- const api$12 = createLineApi(MINIMAX_CODE_ROUTE_PREFIX, "MiniMax Code");
6808
- api$12.request;
6809
- const get$3 = api$12.get;
6810
- const post$4 = api$12.post;
5342
+ const api$11 = createLineApi(MINIMAX_CODE_ROUTE_PREFIX, "MiniMax Code");
5343
+ api$11.request;
5344
+ const get$3 = api$11.get;
5345
+ const post$4 = api$11.post;
6811
5346
  function messageOf$3(cause) {
6812
5347
  return cause instanceof Error ? cause.message : String(cause);
6813
5348
  }
@@ -7272,7 +5807,6 @@ window.__ModuleLoader__.load({
7272
5807
  cooldownLeft: t("cooldownLeft"),
7273
5808
  cooldownRemaining: t("cooldownRemaining"),
7274
5809
  cooldownRemainingSeconds: t("cooldownRemainingSeconds"),
7275
- modelCooldown: t("modelCooldown"),
7276
5810
  clearCooldown: t("clearCooldown"),
7277
5811
  needsRelogin: t("needsRelogin"),
7278
5812
  relogin: t("relogin"),
@@ -9558,9 +8092,9 @@ window.__ModuleLoader__.load({
9558
8092
  * 除 adopt 与 connection/test 外,全部走共享的 { ok, value } 信封,
9559
8093
  * 因此答案都是裸 DTO——createLineApi 已经把信封拆掉了。
9560
8094
  */
9561
- const api$11 = createLineApi(GLM_CODING_PLAN_ROUTE_PREFIX, "GLM(ZCode 账号)");
9562
- const get$2 = api$11.get;
9563
- const post$3 = api$11.post;
8095
+ const api$10 = createLineApi(GLM_CODING_PLAN_ROUTE_PREFIX, "GLM(ZCode 账号)");
8096
+ const get$2 = api$10.get;
8097
+ const post$3 = api$10.post;
9564
8098
  function messageOf$2(cause) {
9565
8099
  return cause instanceof Error ? cause.message : String(cause);
9566
8100
  }
@@ -9569,7 +8103,7 @@ window.__ModuleLoader__.load({
9569
8103
  /**
9570
8104
  * GLM(ZCode 账号)设置卡片的状态、副作用与动作。
9571
8105
  *
9572
- * 与 WorkBuddy / MiniMax Code 同样的分工:这个文件是行为,GlmCodingPlanSection.tsx
8106
+ * 与 MiniMax Code / Step Code 同样的分工:这个文件是行为,GlmCodingPlanSection.tsx
9573
8107
  * 是渲染,两者之间只通过下面这一个具名结构交接,卡片因此保持「只画」的状态。
9574
8108
  *
9575
8109
  * 一条设计约束贯穿全文件:**能力与文案都不在本文件重算**。模型行的一句话描述来自
@@ -9600,7 +8134,6 @@ window.__ModuleLoader__.load({
9600
8134
  cooldownLeft: t("cooldownLeft"),
9601
8135
  cooldownRemaining: t("cooldownRemaining"),
9602
8136
  cooldownRemainingSeconds: t("cooldownRemainingSeconds"),
9603
- modelCooldown: t("modelCooldown"),
9604
8137
  clearCooldown: t("clearCooldown"),
9605
8138
  needsRelogin: t("needsRelogin"),
9606
8139
  relogin: t("relogin"),
@@ -9984,7 +8517,7 @@ window.__ModuleLoader__.load({
9984
8517
  * GLM(ZCode 账号)设置卡片。
9985
8518
  *
9986
8519
  * 纯渲染:状态、副作用与请求都在 'useGlmCodingPlanSection.ts',两者之间只通过
9987
- * 一个具名结构交接(WorkBuddySection / MinimaxCodeSection 同款分工)。
8520
+ * 一个具名结构交接(MinimaxCodeSection / StepCodeSection 同款分工)。
9988
8521
  *
9989
8522
  * 三条需求方的 UI 硬要求由现成共享组件承担,本文件没有新建任何 UI 组件:
9990
8523
  *
@@ -10723,7 +9256,7 @@ window.__ModuleLoader__.load({
10723
9256
  * `ClaudeSectionView` — so the contract between the two is visible here rather
10724
9257
  * than inferred from a thousand lines of JSX.
10725
9258
  */
10726
- const api$10 = createLineApi("/claude/api", "Claude");
9259
+ const api$9 = createLineApi("/claude/api", "Claude");
10727
9260
  /**
10728
9261
  * The poll cadence of a pending sign-in.
10729
9262
  *
@@ -10756,7 +9289,7 @@ window.__ModuleLoader__.load({
10756
9289
  const loadStatus = (0, react.useCallback)(async (quiet = false) => {
10757
9290
  if (!quiet) setError(null);
10758
9291
  try {
10759
- const data = await api$10.request("/status");
9292
+ const data = await api$9.request("/status");
10760
9293
  setStatus(data);
10761
9294
  setContextDrafts(contextDraftsFor(data));
10762
9295
  quotaFollowUp.current ??= createQuotaFollowUp();
@@ -10787,7 +9320,7 @@ window.__ModuleLoader__.load({
10787
9320
  const timer = window.setInterval(() => {
10788
9321
  (async () => {
10789
9322
  try {
10790
- const poll = await api$10.request("/login/status");
9323
+ const poll = await api$9.request("/login/status");
10791
9324
  setFlow(poll);
10792
9325
  if (poll.status === "complete") {
10793
9326
  setPasteValue("");
@@ -10809,7 +9342,7 @@ window.__ModuleLoader__.load({
10809
9342
  setBusy("login");
10810
9343
  setError(null);
10811
9344
  setPasteValue("");
10812
- const next = await api$10.request("/login", {
9345
+ const next = await api$9.request("/login", {
10813
9346
  method: "POST",
10814
9347
  body: JSON.stringify({})
10815
9348
  });
@@ -10823,7 +9356,7 @@ window.__ModuleLoader__.load({
10823
9356
  };
10824
9357
  const cancelLogin = async () => {
10825
9358
  try {
10826
- const next = await api$10.request("/login/cancel", { method: "POST" });
9359
+ const next = await api$9.request("/login/cancel", { method: "POST" });
10827
9360
  setFlow(next);
10828
9361
  } catch (err) {
10829
9362
  reportError(err);
@@ -10835,7 +9368,7 @@ window.__ModuleLoader__.load({
10835
9368
  try {
10836
9369
  setBusy("login-input");
10837
9370
  setError(null);
10838
- const updated = await api$10.request("/login/input", {
9371
+ const updated = await api$9.request("/login/input", {
10839
9372
  method: "POST",
10840
9373
  body: JSON.stringify({ input: pasteValue })
10841
9374
  });
@@ -10859,7 +9392,7 @@ window.__ModuleLoader__.load({
10859
9392
  try {
10860
9393
  setBusy("adopt");
10861
9394
  setError(null);
10862
- const updated = await api$10.request("/adopt", { method: "POST" });
9395
+ const updated = await api$9.request("/adopt", { method: "POST" });
10863
9396
  setStatus(updated);
10864
9397
  setContextDrafts(contextDraftsFor(updated));
10865
9398
  notifyChange();
@@ -10874,7 +9407,7 @@ window.__ModuleLoader__.load({
10874
9407
  try {
10875
9408
  setBusy(accountId === void 0 ? "adopt-disable" : `adopt-disable-${accountId}`);
10876
9409
  setError(null);
10877
- const updated = await api$10.request("/adopt/disable", {
9410
+ const updated = await api$9.request("/adopt/disable", {
10878
9411
  method: "POST",
10879
9412
  body: JSON.stringify(accountId === void 0 ? {} : { accountId })
10880
9413
  });
@@ -10891,7 +9424,7 @@ window.__ModuleLoader__.load({
10891
9424
  try {
10892
9425
  setBusy(`${action}-${accountId}`);
10893
9426
  setError(null);
10894
- const updated = await api$10.request("/accounts", {
9427
+ const updated = await api$9.request("/accounts", {
10895
9428
  method: "POST",
10896
9429
  body: JSON.stringify({
10897
9430
  action,
@@ -10910,7 +9443,7 @@ window.__ModuleLoader__.load({
10910
9443
  try {
10911
9444
  setBusy("strategy");
10912
9445
  setError(null);
10913
- const updated = await api$10.request("/accounts", {
9446
+ const updated = await api$9.request("/accounts", {
10914
9447
  method: "POST",
10915
9448
  body: JSON.stringify({
10916
9449
  action: "strategy",
@@ -10937,7 +9470,7 @@ window.__ModuleLoader__.load({
10937
9470
  setBusy(`relogin-${accountId}`);
10938
9471
  setError(null);
10939
9472
  setPasteValue("");
10940
- const next = await api$10.request("/login", {
9473
+ const next = await api$9.request("/login", {
10941
9474
  method: "POST",
10942
9475
  body: JSON.stringify({ accountId })
10943
9476
  });
@@ -10954,7 +9487,7 @@ window.__ModuleLoader__.load({
10954
9487
  try {
10955
9488
  setBusy("quota");
10956
9489
  setError(null);
10957
- const updated = await api$10.request("/quota", { method: "POST" });
9490
+ const updated = await api$9.request("/quota", { method: "POST" });
10958
9491
  setStatus(updated);
10959
9492
  } catch (err) {
10960
9493
  reportError(err);
@@ -10967,7 +9500,7 @@ window.__ModuleLoader__.load({
10967
9500
  try {
10968
9501
  setBusy("catalog");
10969
9502
  setError(null);
10970
- const updated = await api$10.request("/catalog/refresh", { method: "POST" });
9503
+ const updated = await api$9.request("/catalog/refresh", { method: "POST" });
10971
9504
  setStatus(updated);
10972
9505
  setContextDrafts(contextDraftsFor(updated));
10973
9506
  notifyChange();
@@ -10982,7 +9515,7 @@ window.__ModuleLoader__.load({
10982
9515
  setBusy("connection");
10983
9516
  setError(null);
10984
9517
  setConnection(null);
10985
- const result = await api$10.request("/connection/test", { method: "POST" });
9518
+ const result = await api$9.request("/connection/test", { method: "POST" });
10986
9519
  setConnection(result);
10987
9520
  await loadStatus(true);
10988
9521
  } catch (err) {
@@ -10993,7 +9526,7 @@ window.__ModuleLoader__.load({
10993
9526
  };
10994
9527
  const applyEnabled = async (enabledModelIds) => {
10995
9528
  try {
10996
- const updated = await api$10.request("/models", {
9529
+ const updated = await api$9.request("/models", {
10997
9530
  method: "POST",
10998
9531
  body: JSON.stringify({ enabledModelIds })
10999
9532
  });
@@ -11016,7 +9549,7 @@ window.__ModuleLoader__.load({
11016
9549
  };
11017
9550
  const updateEffort = async (effort) => {
11018
9551
  try {
11019
- const updated = await api$10.request("/settings", {
9552
+ const updated = await api$9.request("/settings", {
11020
9553
  method: "POST",
11021
9554
  body: JSON.stringify({ defaultReasoningEffort: effort })
11022
9555
  });
@@ -11028,7 +9561,7 @@ window.__ModuleLoader__.load({
11028
9561
  };
11029
9562
  const updateCacheTtl = async (ttl) => {
11030
9563
  try {
11031
- const updated = await api$10.request("/settings", {
9564
+ const updated = await api$9.request("/settings", {
11032
9565
  method: "POST",
11033
9566
  body: JSON.stringify({ cacheTtl: ttl })
11034
9567
  });
@@ -11048,7 +9581,7 @@ window.__ModuleLoader__.load({
11048
9581
  try {
11049
9582
  setSavingModel(modelId);
11050
9583
  setError(null);
11051
- const updated = await api$10.request("/settings", {
9584
+ const updated = await api$9.request("/settings", {
11052
9585
  method: "POST",
11053
9586
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
11054
9587
  });
@@ -11075,7 +9608,7 @@ window.__ModuleLoader__.load({
11075
9608
  try {
11076
9609
  setSavingModel(modelId);
11077
9610
  setError(null);
11078
- const updated = await api$10.request("/settings", {
9611
+ const updated = await api$9.request("/settings", {
11079
9612
  method: "POST",
11080
9613
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
11081
9614
  });
@@ -11102,7 +9635,7 @@ window.__ModuleLoader__.load({
11102
9635
  try {
11103
9636
  setBusy("context");
11104
9637
  setError(null);
11105
- const updated = await api$10.request("/settings", {
9638
+ const updated = await api$9.request("/settings", {
11106
9639
  method: "POST",
11107
9640
  body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
11108
9641
  });
@@ -12708,9 +11241,9 @@ window.__ModuleLoader__.load({
12708
11241
  * **仅有的两处**带秘密的形状,它们只在这两个函数调用点的字面量里出现,
12709
11242
  * 既不进 URL、也不进日志,卡片那边同样没有别的地方可以读到它们。
12710
11243
  */
12711
- const api$9 = createLineApi(STEP_CODE_ROUTE_PREFIX, STEP_CODE_PROVIDER_NAME);
12712
- const get$1 = api$9.get;
12713
- const post$1 = api$9.post;
11244
+ const api$8 = createLineApi(STEP_CODE_ROUTE_PREFIX, STEP_CODE_PROVIDER_NAME);
11245
+ const get$1 = api$8.get;
11246
+ const post$1 = api$8.post;
12714
11247
  function messageOf$1(cause) {
12715
11248
  return cause instanceof Error ? cause.message : String(cause);
12716
11249
  }
@@ -12719,7 +11252,7 @@ window.__ModuleLoader__.load({
12719
11252
  /**
12720
11253
  * Step Code(Step Plan 订阅)设置卡片的状态、副作用与动作。
12721
11254
  *
12722
- * 与 GLM / WorkBuddy / MiniMax Code 同样的分工:这个文件是行为,StepCodeSection.tsx
11255
+ * 与 GLM / MiniMax Code 同样的分工:这个文件是行为,StepCodeSection.tsx
12723
11256
  * 是渲染,两者之间只通过下面这一个具名结构交接,卡片因此保持「只画」的状态。
12724
11257
  *
12725
11258
  * 一条设计约束贯穿全文件:**能力与文案都不在本文件重算**。模型行的一句话描述来自
@@ -12754,7 +11287,6 @@ window.__ModuleLoader__.load({
12754
11287
  cooldownLeft: t("cooldownLeft"),
12755
11288
  cooldownRemaining: t("cooldownRemaining"),
12756
11289
  cooldownRemainingSeconds: t("cooldownRemainingSeconds"),
12757
- modelCooldown: t("modelCooldown"),
12758
11290
  clearCooldown: t("clearCooldown"),
12759
11291
  needsRelogin: t("needsRelogin"),
12760
11292
  relogin: t("relogin"),
@@ -13294,7 +11826,7 @@ window.__ModuleLoader__.load({
13294
11826
  * Step Code(Step Plan 订阅)设置卡片。
13295
11827
  *
13296
11828
  * 纯渲染:状态、副作用与请求都在 'useStepCodeSection.ts',两者之间只通过一个具名结构
13297
- * 交接(GLM / WorkBuddy / MiniMax Code 同款分工)。
11829
+ * 交接(GLM / MiniMax Code 同款分工)。
13298
11830
  *
13299
11831
  * 本文件没有新建任何 UI 组件:进入入口(hub 卡片)在 hub/providers.tsx,账号池与它的
13300
11832
  * 配额条在 AccountPoolSection,模型勾选在 ModelChecklist,上下文窗口在
@@ -14188,7 +12720,7 @@ window.__ModuleLoader__.load({
14188
12720
  }
14189
12721
  //#endregion
14190
12722
  //#region src/client/cline-pass/api.ts
14191
- const api$8 = createLineApi(CLINE_PASS_ROUTE_PREFIX, "Cline Pass");
12723
+ const api$7 = createLineApi(CLINE_PASS_ROUTE_PREFIX, "Cline Pass");
14192
12724
  /**
14193
12725
  * The Cline Pass settings API, as the card uses it.
14194
12726
  *
@@ -14197,86 +12729,86 @@ window.__ModuleLoader__.load({
14197
12729
  */
14198
12730
  var ClinePassApi = class {
14199
12731
  status() {
14200
- return api$8.get("/status");
12732
+ return api$7.get("/status");
14201
12733
  }
14202
12734
  updateSettings(patch) {
14203
- return api$8.post("/settings", patch).then(() => this.status());
12735
+ return api$7.post("/settings", patch).then(() => this.status());
14204
12736
  }
14205
12737
  accountAction(action, body = {}) {
14206
- return api$8.post("/accounts", {
12738
+ return api$7.post("/accounts", {
14207
12739
  action,
14208
12740
  ...body
14209
12741
  });
14210
12742
  }
14211
12743
  /** Verify a key without storing it; the host answers the verdict directly. */
14212
12744
  testKey(body) {
14213
- return api$8.post("/accounts", {
12745
+ return api$7.post("/accounts", {
14214
12746
  action: "test",
14215
12747
  ...body
14216
12748
  });
14217
12749
  }
14218
12750
  /** Start the Cline device-code sign-in. */
14219
12751
  startLogin() {
14220
- return api$8.post("/login/start", {});
12752
+ return api$7.post("/login/start", {});
14221
12753
  }
14222
12754
  /** One poll of the pending sign-in; the host throttles it to WorkOS's interval. */
14223
12755
  loginStatus(id) {
14224
- return api$8.get(`/login/status?id=${encodeURIComponent(id)}`);
12756
+ return api$7.get(`/login/status?id=${encodeURIComponent(id)}`);
14225
12757
  }
14226
12758
  cancelLogin(id) {
14227
- return api$8.post("/login/cancel", { id });
12759
+ return api$7.post("/login/cancel", { id });
14228
12760
  }
14229
12761
  setEnabledModels(enabledModelIds) {
14230
- return api$8.post("/models", { enabledModelIds });
12762
+ return api$7.post("/models", { enabledModelIds });
14231
12763
  }
14232
12764
  setContextWindow(model, contextWindow) {
14233
- return api$8.post("/models/context-window", {
12765
+ return api$7.post("/models/context-window", {
14234
12766
  model,
14235
12767
  contextWindow
14236
12768
  });
14237
12769
  }
14238
12770
  pinModel(model, pin) {
14239
- return api$8.post("/models/pin", {
12771
+ return api$7.post("/models/pin", {
14240
12772
  model,
14241
12773
  ...pin
14242
12774
  });
14243
12775
  }
14244
12776
  resetPin(model) {
14245
- return api$8.post("/models/reset", { model });
12777
+ return api$7.post("/models/reset", { model });
14246
12778
  }
14247
12779
  probe(model) {
14248
- return api$8.post("/models/probe", { model });
12780
+ return api$7.post("/models/probe", { model });
14249
12781
  }
14250
12782
  validate(model) {
14251
- return api$8.post("/models/validate", { model });
12783
+ return api$7.post("/models/validate", { model });
14252
12784
  }
14253
12785
  test(model, pin = {}) {
14254
- return api$8.post("/models/test", {
12786
+ return api$7.post("/models/test", {
14255
12787
  model,
14256
12788
  ...pin
14257
12789
  });
14258
12790
  }
14259
12791
  setVisibility(model, visible) {
14260
- return api$8.post("/models/visibility", {
12792
+ return api$7.post("/models/visibility", {
14261
12793
  model,
14262
12794
  visible
14263
12795
  });
14264
12796
  }
14265
12797
  setVisibilityAll(mode) {
14266
- return api$8.post("/models/visibility-all", { mode });
12798
+ return api$7.post("/models/visibility-all", { mode });
14267
12799
  }
14268
12800
  refreshCatalog() {
14269
- return api$8.post("/catalog/refresh", {});
12801
+ return api$7.post("/catalog/refresh", {});
14270
12802
  }
14271
12803
  readUsage() {
14272
- return api$8.post("/usage", {});
12804
+ return api$7.post("/usage", {});
14273
12805
  }
14274
12806
  history(limit = 25, model = "") {
14275
12807
  const query = new URLSearchParams({
14276
12808
  limit: String(limit),
14277
12809
  ...model === "" ? {} : { model }
14278
12810
  });
14279
- return api$8.get("/history?" + query.toString());
12811
+ return api$7.get("/history?" + query.toString());
14280
12812
  }
14281
12813
  };
14282
12814
  //#endregion
@@ -16193,9 +14725,9 @@ window.__ModuleLoader__.load({
16193
14725
  * 凭据边界也写在这里:/login/manual 的请求体是本文件里**唯一**带秘密的形状,
16194
14726
  * 它只在这个函数调用点的字面量里出现,既不进 URL、也不进日志。
16195
14727
  */
16196
- const api$7 = createLineApi(QODER_ROUTE_PREFIX, QODER_PROVIDER_NAME);
16197
- const get = api$7.get;
16198
- const post = api$7.post;
14728
+ const api$6 = createLineApi(QODER_ROUTE_PREFIX, QODER_PROVIDER_NAME);
14729
+ const get = api$6.get;
14730
+ const post = api$6.post;
16199
14731
  function messageOf(cause) {
16200
14732
  return cause instanceof Error ? cause.message : String(cause);
16201
14733
  }
@@ -16204,7 +14736,7 @@ window.__ModuleLoader__.load({
16204
14736
  /**
16205
14737
  * Qoder(订阅)设置卡片的状态、副作用与动作。
16206
14738
  *
16207
- * 与 GLM / WorkBuddy / Step Code 同样的分工:这个文件是行为,QoderSection.tsx
14739
+ * 与 GLM / Step Code 同样的分工:这个文件是行为,QoderSection.tsx
16208
14740
  * 是渲染,两者之间只通过下面这一个具名结构交接,卡片因此保持「只画」的状态。
16209
14741
  *
16210
14742
  * 一条设计约束贯穿全文件:**能力与文案都不在本文件重算**。模型行的一句话描述来自
@@ -16237,7 +14769,6 @@ window.__ModuleLoader__.load({
16237
14769
  cooldownLeft: t("cooldownLeft"),
16238
14770
  cooldownRemaining: t("cooldownRemaining"),
16239
14771
  cooldownRemainingSeconds: t("cooldownRemainingSeconds"),
16240
- modelCooldown: t("modelCooldown"),
16241
14772
  clearCooldown: t("clearCooldown"),
16242
14773
  needsRelogin: t("needsRelogin"),
16243
14774
  relogin: t("relogin"),
@@ -16710,7 +15241,7 @@ window.__ModuleLoader__.load({
16710
15241
  * Qoder(订阅)设置卡片。
16711
15242
  *
16712
15243
  * 纯渲染:状态、副作用与请求都在 'useQoderSection.ts',两者之间只通过一个具名结构
16713
- * 交接(GLM / WorkBuddy / Step Code 同款分工)。
15244
+ * 交接(GLM / Step Code 同款分工)。
16714
15245
  *
16715
15246
  * 本文件没有新建任何 UI 组件:进入入口(hub 卡片)在 hub/providers.tsx,账号池与它的
16716
15247
  * 配额条在 AccountPoolSection,模型勾选在 ModelChecklist,上下文窗口在
@@ -17298,7 +15829,7 @@ window.__ModuleLoader__.load({
17298
15829
  const OPENDESIGN_ROUTE_PREFIX = "/opendesign/api";
17299
15830
  //#endregion
17300
15831
  //#region src/client/opendesign/api.ts
17301
- const api$6 = createLineApi(OPENDESIGN_ROUTE_PREFIX, "OpenDesign");
15832
+ const api$5 = createLineApi(OPENDESIGN_ROUTE_PREFIX, "OpenDesign");
17302
15833
  /**
17303
15834
  * The OpenDesign settings API, as the card uses it.
17304
15835
  *
@@ -17307,59 +15838,59 @@ window.__ModuleLoader__.load({
17307
15838
  */
17308
15839
  var OpenDesignApi = class {
17309
15840
  status() {
17310
- return api$6.get("/status");
15841
+ return api$5.get("/status");
17311
15842
  }
17312
15843
  updateSettings(patch) {
17313
- return api$6.post("/settings", patch).then(() => this.status());
15844
+ return api$5.post("/settings", patch).then(() => this.status());
17314
15845
  }
17315
15846
  accountAction(action, body = {}) {
17316
- return api$6.post("/accounts", {
15847
+ return api$5.post("/accounts", {
17317
15848
  action,
17318
15849
  ...body
17319
15850
  });
17320
15851
  }
17321
15852
  /** Verify a key without storing it; the host answers the verdict directly. */
17322
15853
  testKey(body) {
17323
- return api$6.post("/accounts", {
15854
+ return api$5.post("/accounts", {
17324
15855
  action: "test",
17325
15856
  ...body
17326
15857
  });
17327
15858
  }
17328
15859
  /** Start the browser device-authorization sign-in. */
17329
15860
  startLogin() {
17330
- return api$6.post("/login/start", {});
15861
+ return api$5.post("/login/start", {});
17331
15862
  }
17332
15863
  /** One poll of the pending sign-in; the host throttles it to the advertised interval. */
17333
15864
  loginStatus(id) {
17334
- return api$6.get(`/login/status?id=${encodeURIComponent(id)}`);
15865
+ return api$5.get(`/login/status?id=${encodeURIComponent(id)}`);
17335
15866
  }
17336
15867
  cancelLogin(id) {
17337
- return api$6.post("/login/cancel", { id });
15868
+ return api$5.post("/login/cancel", { id });
17338
15869
  }
17339
15870
  /** Read each OAuth account's wallet balance once (one upstream call per account). */
17340
15871
  readUsage() {
17341
- return api$6.post("/usage", {});
15872
+ return api$5.post("/usage", {});
17342
15873
  }
17343
15874
  setEnabledModels(enabledModelIds) {
17344
- return api$6.post("/models", { enabledModelIds });
15875
+ return api$5.post("/models", { enabledModelIds });
17345
15876
  }
17346
15877
  setContextWindow(model, contextWindow) {
17347
- return api$6.post("/models/context-window", {
15878
+ return api$5.post("/models/context-window", {
17348
15879
  model,
17349
15880
  contextWindow
17350
15881
  });
17351
15882
  }
17352
15883
  setVisibility(model, visible) {
17353
- return api$6.post("/models/visibility", {
15884
+ return api$5.post("/models/visibility", {
17354
15885
  model,
17355
15886
  visible
17356
15887
  });
17357
15888
  }
17358
15889
  setVisibilityAll(mode) {
17359
- return api$6.post("/models/visibility-all", { mode });
15890
+ return api$5.post("/models/visibility-all", { mode });
17360
15891
  }
17361
15892
  refreshCatalog() {
17362
- return api$6.post("/catalog/refresh", {});
15893
+ return api$5.post("/catalog/refresh", {});
17363
15894
  }
17364
15895
  };
17365
15896
  //#endregion
@@ -18327,12 +16858,6 @@ window.__ModuleLoader__.load({
18327
16858
  setEnabled: (enabled) => postLineSettings("/kimi-code/api", { enabled }),
18328
16859
  renderDetail: ({ onModelChange }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KimiCodeSection, { onModelChange })
18329
16860
  },
18330
- {
18331
- id: "workbuddy",
18332
- name: "WorkBuddy",
18333
- setEnabled: (enabled) => postLineSettings("/workbuddy/api", { enabled }),
18334
- renderDetail: ({ onModelChange }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkBuddySection, { onModelChange })
18335
- },
18336
16861
  {
18337
16862
  id: "minimax-code",
18338
16863
  name: "MiniMax Code",
@@ -18559,6 +17084,241 @@ window.__ModuleLoader__.load({
18559
17084
  ]
18560
17085
  });
18561
17086
  }
17087
+ /**
17088
+ * The exact spec the one-tap update installs.
17089
+ *
17090
+ * Written here rather than accepted from the request body: a route that took the
17091
+ * package name from its caller would let any same-origin POST install an
17092
+ * arbitrary package into the profile.
17093
+ */
17094
+ const UPDATE_INSTALL_SPEC = `@eddyskywalker/dsh-chatgpt-subscription@latest`;
17095
+ /**
17096
+ * The `dsh plugin add` command for one exact install spec.
17097
+ *
17098
+ * The manual recovery path after a failed update needs a command pinned to the
17099
+ * version that was running, not `@latest`: reinstalling `@latest` right after a
17100
+ * failed attempt would repeat the same install. Both commands are built here so
17101
+ * the wording of "add this spec by hand" exists once.
17102
+ *
17103
+ * @param spec - The install spec; defaults to {@link UPDATE_INSTALL_SPEC}.
17104
+ * @returns the command line a user can paste into a terminal.
17105
+ */
17106
+ function updateAddCommand(spec = UPDATE_INSTALL_SPEC) {
17107
+ return `dsh plugin add ${spec}`;
17108
+ }
17109
+ updateAddCommand();
17110
+ const UPDATE_CHECK_PATH = `${ROUTE_PREFIX}/update/check`;
17111
+ const UPDATE_APPLY_PATH = `${ROUTE_PREFIX}/update/apply`;
17112
+ //#endregion
17113
+ //#region src/client/hub/UpdateCheck.tsx
17114
+ /**
17115
+ * The hub's update control: one 28px ring-icon button at the right end of the
17116
+ * section header, with a line of 11px text to its left saying which version is
17117
+ * running and what the last check found. The icon carries no text label — its
17118
+ * name is the state-dependent `aria-label`, which the button also mirrors as a
17119
+ * hover title — so the control stays quiet until the pointer is on it.
17120
+ *
17121
+ * Nothing is requested on mount. Opening the settings page costs exactly the one
17122
+ * overview request it always did, and the registry is asked only when the user
17123
+ * asks it to be — a settings page that reached out to npm on every render would
17124
+ * be a network round trip nobody requested and, on a machine behind a proxy that
17125
+ * is down, a spinner that never settles.
17126
+ *
17127
+ * The four outcomes the card renders are all derivable from the check's DTO:
17128
+ * already latest, a newer version one click away, a newer version that can only
17129
+ * be installed by hand (with the command to copy), and a check that failed.
17130
+ * Failures of either request are shown in place, in the same line, as small red
17131
+ * text — never an alert, which would take the user out of the page they were
17132
+ * reading to say something they can read here.
17133
+ *
17134
+ * An update that succeeded says whether a restart is still pending and whether
17135
+ * the old copy had to be removed first, both read from the route's answer rather
17136
+ * than assumed. An update that failed after that removal also says what happened
17137
+ * to the previous version, including the case where it could not be put back.
17138
+ */
17139
+ /**
17140
+ * The button's whole face: a ring arrow, drawn in `currentColor` so the button's
17141
+ * own color (tertiary, primary on hover) is the only color it ever has. The class
17142
+ * is what the busy state animates, so the rotation is a stylesheet fact rather
17143
+ * than an inline style on the icon.
17144
+ */
17145
+ const REFRESH_SVG = "<svg class=\"dsh-hub-update-icon\" viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M14 8a6 6 0 1 1-6-6c1.68 0 3.29.67 4.49 1.83L14 5.33\"/><path d=\"M14 2v3.33h-3.33\"/></svg>";
17146
+ /** A refused update, carrying the route's machine-readable code so the card can word it. */
17147
+ var UpdateApplyError = class extends Error {
17148
+ code;
17149
+ rollback;
17150
+ restoredVersion;
17151
+ constructor(code, message, rollback, restoredVersion) {
17152
+ super(message);
17153
+ this.code = code;
17154
+ this.rollback = rollback;
17155
+ this.restoredVersion = restoredVersion;
17156
+ this.name = "UpdateApplyError";
17157
+ }
17158
+ };
17159
+ async function fetchCheck() {
17160
+ const response = await fetch(UPDATE_CHECK_PATH, { credentials: "same-origin" });
17161
+ const envelope = await response.json();
17162
+ if (!response.ok || !envelope.ok) throw new Error(envelope.ok ? `Request failed (${response.status})` : envelope.error.message);
17163
+ return envelope.value;
17164
+ }
17165
+ /**
17166
+ * Ask the Host to install the published version.
17167
+ *
17168
+ * The request carries no package name or version: the server installs the spec
17169
+ * it owns, so a caller cannot choose what lands in the profile.
17170
+ */
17171
+ async function postApply() {
17172
+ const response = await fetch(UPDATE_APPLY_PATH, {
17173
+ method: "POST",
17174
+ credentials: "same-origin"
17175
+ });
17176
+ const body = await response.json();
17177
+ if (!body.ok) throw new UpdateApplyError(body.error.code, body.error.message, body.error.rollback, body.error.restoredVersion);
17178
+ if (!response.ok) throw new UpdateApplyError(null, `Request failed (${response.status})`);
17179
+ return body.value;
17180
+ }
17181
+ /**
17182
+ * What a successful update should say.
17183
+ *
17184
+ * Two facts decide the wording and neither may be assumed: whether a restart is
17185
+ * still pending (the Host's own `application` answer), and whether the update had
17186
+ * to remove the installed copy first, which is worth naming because it is the one
17187
+ * path that leaves the plugin briefly uninstalled.
17188
+ */
17189
+ function appliedText(applied, t) {
17190
+ return formatPoolLabel(t(applied.restartRequired ? applied.removedFirst ? "hubUpdateInstalledReplaced" : "hubUpdateInstalled" : applied.removedFirst ? "hubUpdateInstalledReplacedLive" : "hubUpdateInstalledLive"), { version: applied.installed });
17191
+ }
17192
+ /**
17193
+ * The red line a refused update leaves behind.
17194
+ *
17195
+ * The route's message is carried through untouched — it is the only text that
17196
+ * says what pnpm did — and the rollback state is prefixed to it, because "the
17197
+ * update failed" and "the update failed and your plugin is gone" are not the same
17198
+ * message and a user has to be able to tell them apart.
17199
+ */
17200
+ function failureText(failure, t) {
17201
+ if (!(failure instanceof UpdateApplyError)) return failure instanceof Error ? failure.message : String(failure);
17202
+ if (failure.rollback === "restored") return `${formatPoolLabel(t("hubUpdateFailedRestored"), { version: failure.restoredVersion ?? "" })} ${failure.message}`;
17203
+ if (failure.rollback === "failed") return `${t("hubUpdateFailedRollbackFailed")}: ${failure.message}`;
17204
+ if (failure.rollback === "skipped") return `${t("hubUpdateFailedRollbackSkipped")}: ${failure.message}`;
17205
+ return failure.message;
17206
+ }
17207
+ /** The one line of text beside the icon: what the last answer means. */
17208
+ function statusOf(check, applied, t) {
17209
+ if (applied !== null) return {
17210
+ text: appliedText(applied, t),
17211
+ danger: false
17212
+ };
17213
+ if (check.reason === "registry-unreachable") return {
17214
+ text: t("hubUpdateCheckFailed"),
17215
+ danger: true
17216
+ };
17217
+ if (check.current === null) return {
17218
+ text: formatPoolLabel(t("hubUpdateLatestWithUnknownCurrent"), { version: check.latest ?? "" }),
17219
+ danger: false
17220
+ };
17221
+ if (!check.updateAvailable) return {
17222
+ text: formatPoolLabel(t("hubUpdateUpToDate"), { version: check.current }),
17223
+ danger: false
17224
+ };
17225
+ const values = {
17226
+ version: check.latest ?? "",
17227
+ current: check.current
17228
+ };
17229
+ if (check.canApply) return {
17230
+ text: formatPoolLabel(t("hubUpdateAvailable"), values),
17231
+ danger: false
17232
+ };
17233
+ if (check.reason === "development-install") return {
17234
+ text: formatPoolLabel(t("hubUpdateDevelopmentInstall"), values),
17235
+ danger: false
17236
+ };
17237
+ if (check.reason === "plugin-manager-missing") return {
17238
+ text: formatPoolLabel(t("hubUpdatePluginManagerMissing"), values),
17239
+ danger: false
17240
+ };
17241
+ return {
17242
+ text: formatPoolLabel(t("hubUpdateManualOnly"), values),
17243
+ danger: false
17244
+ };
17245
+ }
17246
+ function UpdateCheck({ t }) {
17247
+ const [phase, setPhase] = (0, react.useState)("idle");
17248
+ const [check, setCheck] = (0, react.useState)(null);
17249
+ const [applied, setApplied] = (0, react.useState)(null);
17250
+ const [error, setError] = (0, react.useState)(null);
17251
+ const busy = phase === "checking" || phase === "applying";
17252
+ const canOfferApply = applied === null && check !== null && check.updateAvailable && check.canApply;
17253
+ const runCheck = (0, react.useCallback)(async () => {
17254
+ setPhase("checking");
17255
+ setError(null);
17256
+ setApplied(null);
17257
+ try {
17258
+ const value = await fetchCheck();
17259
+ setCheck(value);
17260
+ setPhase("checked");
17261
+ } catch (failure) {
17262
+ setCheck(null);
17263
+ setError(failure instanceof Error ? failure.message : String(failure));
17264
+ setPhase("idle");
17265
+ }
17266
+ }, []);
17267
+ const runApply = (0, react.useCallback)(async () => {
17268
+ setPhase("applying");
17269
+ setError(null);
17270
+ try {
17271
+ const value = await postApply();
17272
+ setApplied(value);
17273
+ setPhase("applied");
17274
+ } catch (failure) {
17275
+ setError(failureText(failure, t));
17276
+ setPhase("checked");
17277
+ }
17278
+ }, [t]);
17279
+ const label = phase === "checking" ? t("hubUpdateChecking") : phase === "applying" ? t("hubUpdateApplying") : canOfferApply ? formatPoolLabel(t("hubUpdateApply"), { version: check?.latest ?? "" }) : t("hubUpdateCheck");
17280
+ const status = check === null ? null : statusOf(check, applied, t);
17281
+ const showCommand = check !== null && check.updateAvailable && !check.canApply && check.reason !== "registry-unreachable";
17282
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
17283
+ className: "dsh-hub-update",
17284
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
17285
+ className: "dsh-hub-update-row",
17286
+ children: [
17287
+ status === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
17288
+ className: `dsh-hub-update-state${status.danger ? " dsh-hub-note-danger" : ""}`,
17289
+ role: "status",
17290
+ children: status.text
17291
+ }),
17292
+ error === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
17293
+ className: "dsh-hub-update-state dsh-hub-note-danger",
17294
+ role: "alert",
17295
+ children: error
17296
+ }),
17297
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
17298
+ type: "button",
17299
+ className: `dsh-hub-update-button${busy ? " dsh-hub-update-busy" : ""}`,
17300
+ "aria-label": label,
17301
+ title: label,
17302
+ disabled: busy,
17303
+ onClick: () => {
17304
+ canOfferApply ? runApply() : runCheck();
17305
+ },
17306
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
17307
+ "aria-hidden": "true",
17308
+ dangerouslySetInnerHTML: { __html: REFRESH_SVG }
17309
+ }), canOfferApply ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
17310
+ className: "dsh-hub-update-dot",
17311
+ "aria-hidden": "true"
17312
+ }) : null]
17313
+ })
17314
+ ]
17315
+ }), showCommand ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
17316
+ className: "dsh-hub-update-command",
17317
+ "aria-label": t("hubUpdateCommandLabel"),
17318
+ children: check.command
17319
+ }) : null]
17320
+ });
17321
+ }
18562
17322
  //#endregion
18563
17323
  //#region src/client/ProviderHubSection.tsx
18564
17324
  const STORAGE_KEY = "dsh-chatgpt-subscription:hub-view";
@@ -18614,11 +17374,14 @@ window.__ModuleLoader__.load({
18614
17374
  if (view.view === "overview") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
18615
17375
  className: "dsh-codex-page",
18616
17376
  "aria-labelledby": "dsh-hub-title",
18617
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("header", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
18618
- id: "dsh-hub-title",
18619
- className: "dsh-codex-title",
18620
- children: t("hubTitle")
18621
- }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HubOverview, {
17377
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
17378
+ className: "dsh-hub-head",
17379
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
17380
+ id: "dsh-hub-title",
17381
+ className: "dsh-codex-title dsh-hub-head-title",
17382
+ children: t("hubTitle")
17383
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UpdateCheck, { t })]
17384
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HubOverview, {
18622
17385
  t,
18623
17386
  onOpen: open
18624
17387
  })]
@@ -18805,6 +17568,25 @@ window.__ModuleLoader__.load({
18805
17568
  hubSwitchOn: "启用 {name}",
18806
17569
  hubSwitchOff: "停用 {name}",
18807
17570
  hubCardLabel: "{name},{annotation}",
17571
+ hubUpdateCheck: "检测更新",
17572
+ hubUpdateChecking: "检测中…",
17573
+ hubUpdateApply: "更新到 v{version}",
17574
+ hubUpdateApplying: "更新中…",
17575
+ hubUpdateUpToDate: "已是最新版本 {version}",
17576
+ hubUpdateLatestWithUnknownCurrent: "最新版本 {version},当前版本未知",
17577
+ hubUpdateAvailable: "有新版本 {version},当前 {current}",
17578
+ hubUpdateInstalled: "已安装 v{version},重启宿主后生效",
17579
+ hubUpdateInstalledReplaced: "已移除旧版并安装 v{version},重启宿主后生效",
17580
+ hubUpdateInstalledLive: "已安装 v{version},当前已生效,无需重启",
17581
+ hubUpdateInstalledReplacedLive: "已移除旧版并安装 v{version},当前已生效,无需重启",
17582
+ hubUpdateFailedRestored: "更新失败,已恢复 v{version}",
17583
+ hubUpdateFailedRollbackFailed: "更新失败,且旧版本也没能重新装回来——插件可能已不可用",
17584
+ hubUpdateFailedRollbackSkipped: "更新失败,且无法自动恢复原版本——插件可能已被移除",
17585
+ hubUpdateDevelopmentInstall: "有新版本 {version};当前是本地链接安装,无法自动更新",
17586
+ hubUpdatePluginManagerMissing: "有新版本 {version};宿主未提供 pluginManager,无法自动更新",
17587
+ hubUpdateManualOnly: "有新版本 {version};当前安装方式无法自动更新",
17588
+ hubUpdateCheckFailed: "检测失败:无法连接 npm 源,请检查网络或代理",
17589
+ hubUpdateCommandLabel: "手动更新命令",
18808
17590
  localCodexLoginImport: "导入本机 Codex CLI 登录",
18809
17591
  localCodexLoginImporting: "导入中…",
18810
17592
  stopImporting: "停止导入全部本机登录",
@@ -18961,6 +17743,25 @@ window.__ModuleLoader__.load({
18961
17743
  hubSwitchOn: "Enable {name}",
18962
17744
  hubSwitchOff: "Disable {name}",
18963
17745
  hubCardLabel: "{name}, {annotation}",
17746
+ hubUpdateCheck: "Check for updates",
17747
+ hubUpdateChecking: "Checking…",
17748
+ hubUpdateApply: "Update to v{version}",
17749
+ hubUpdateApplying: "Updating…",
17750
+ hubUpdateUpToDate: "Up to date ({version})",
17751
+ hubUpdateLatestWithUnknownCurrent: "Latest is {version}; the running version is unknown",
17752
+ hubUpdateAvailable: "{version} is available — you have {current}",
17753
+ hubUpdateInstalled: "Installed v{version} — restart the Host to apply it",
17754
+ hubUpdateInstalledReplaced: "Removed the old copy and installed v{version} — restart the Host to apply it",
17755
+ hubUpdateInstalledLive: "Installed v{version} — active now, no restart needed",
17756
+ hubUpdateInstalledReplacedLive: "Removed the old copy and installed v{version} — active now, no restart needed",
17757
+ hubUpdateFailedRestored: "Update failed; v{version} was restored",
17758
+ hubUpdateFailedRollbackFailed: "Update failed, and the previous version could not be reinstalled — the plugin may no longer be available",
17759
+ hubUpdateFailedRollbackSkipped: "Update failed, and the previous version could not be restored — the plugin may have been removed",
17760
+ hubUpdateDevelopmentInstall: "{version} is available, but this copy is a local link and cannot update itself",
17761
+ hubUpdatePluginManagerMissing: "{version} is available, but this Host exposes no pluginManager to install it",
17762
+ hubUpdateManualOnly: "{version} is available, but this install cannot update itself",
17763
+ hubUpdateCheckFailed: "Check failed: the npm registry could not be reached — check the network or proxy",
17764
+ hubUpdateCommandLabel: "Manual update command",
18964
17765
  localCodexLoginImport: "Import the local Codex CLI sign-in",
18965
17766
  localCodexLoginImporting: "Importing…",
18966
17767
  stopImporting: "Stop importing all local sign-ins",
@@ -19173,6 +17974,43 @@ window.__ModuleLoader__.load({
19173
17974
  .dsh-hub-skeleton span{background:var(--dsw-alias-bg-layer-2,#f2f1ea);border-radius:5px;display:block;height:12px}
19174
17975
  .dsh-hub-skeleton .dsh-hub-skel-name{width:120px;margin-bottom:6px}
19175
17976
  .dsh-hub-skeleton .dsh-hub-skel-note{width:180px;height:10px}
17977
+ /* The section header carries the title and the one page-level control: title
17978
+ left, control right, nothing else. A space-between row gives its LAST item the
17979
+ row's right edge, and every line that can appear lives to the left of the icon,
17980
+ so the icon owns that edge in all four states. */
17981
+ .dsh-hub-head{align-items:center;display:flex;gap:12px;justify-content:space-between;min-width:0}
17982
+ /* On a narrow window the title gives way (ellipsis) rather than the icon, which
17983
+ the control keeps at a fixed size. */
17984
+ .dsh-hub-head .dsh-hub-head-title{flex:0 1 auto;margin:0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
17985
+ /* Inside the control the status text shrinks and the icon does not, so a long
17986
+ error or a version sentence grows leftwards instead of moving the icon. */
17987
+ .dsh-hub-update{align-items:flex-end;display:flex;flex:0 1 auto;flex-direction:column;gap:4px;min-width:0}
17988
+ .dsh-hub-update-row{align-items:center;display:flex;gap:10px;justify-content:flex-end;min-width:0}
17989
+ /* A 28px icon button: no frame, no label. Quiet until hovered, which is why the
17990
+ section header can carry it without turning into a toolbar. */
17991
+ .dsh-hub-update-button{align-items:center;background:transparent;border:none;border-radius:8px;color:var(--dsw-alias-label-tertiary,#8f8d84);cursor:pointer;display:inline-flex;flex:none;height:28px;justify-content:center;padding:0;position:relative;transition:background .15s ease,color .15s ease;width:28px}
17992
+ .dsh-hub-update-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04));color:var(--dsw-alias-label-primary,#141413)}
17993
+ .dsh-hub-update-button:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}
17994
+ .dsh-hub-update-button:disabled{cursor:default;opacity:.5}
17995
+ .dsh-hub-update-icon{display:block}
17996
+ /* A check or an install is a wait with no progress to report, so the ring turns
17997
+ instead of the control growing a spinner and changing size. */
17998
+ .dsh-hub-update-button.dsh-hub-update-busy .dsh-hub-update-icon{animation:dsh-hub-update-spin .9s linear infinite}
17999
+ @keyframes dsh-hub-update-spin{to{transform:rotate(360deg)}}
18000
+ /* One accent dot instead of a wider button: the offer stays visible and the icon
18001
+ keeps both its size and its position. */
18002
+ .dsh-hub-update-dot{background:var(--dsw-alias-button-info-fill,#397ee8);border-radius:50%;height:6px;position:absolute;right:2px;top:2px;width:6px}
18003
+ /* 11px, like the cards' annotation line, so the control reads as a note about
18004
+ the page rather than a second call to action. Right-aligned, because a wrapped
18005
+ line then stays against the icon it belongs to; shrinkable, so its length can
18006
+ never move that icon. */
18007
+ .dsh-hub-update-state{color:var(--dsw-alias-label-tertiary,#8f8d84);flex:0 1 auto;font-size:11px;line-height:1.45;max-width:320px;min-width:0;text-align:right}
18008
+ .dsh-hub-update-state.dsh-hub-note-danger{color:var(--dsw-alias-label-danger,#d94b4b)}
18009
+ /* The escape hatch when the icon cannot act. It sits on its own line under the
18010
+ header row, inside the control, so it never widens the row it belongs to.
18011
+ user-select:all makes one click take the whole command, which is the only
18012
+ clipboard the page needs. */
18013
+ .dsh-hub-update-command{color:var(--dsw-alias-label-tertiary,#8f8d84);display:block;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;line-height:1.45;margin:0 0 10px;max-width:320px;overflow-wrap:anywhere;text-align:right;user-select:all}
19176
18014
  .dsh-hub-backbar{align-items:center;display:flex;gap:10px;margin-bottom:14px;min-height:32px}
19177
18015
  .dsh-hub-back{align-items:center;background:transparent;border:none;border-radius:6px;color:var(--dsw-alias-label-secondary,#5d5c52);cursor:pointer;display:inline-flex;font:inherit;font-size:13px;font-weight:550;gap:2px;padding:5px 8px 5px 2px}
19178
18016
  .dsh-hub-back:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(0,0,0,.04));color:var(--dsw-alias-label-primary,#141413)}
@@ -19224,7 +18062,7 @@ window.__ModuleLoader__.load({
19224
18062
  }
19225
18063
  //#endregion
19226
18064
  //#region src/client/antigravity/styles.ts
19227
- const STYLE_ID$7 = "dsh-antigravity-settings-style";
18065
+ const STYLE_ID$6 = "dsh-antigravity-settings-style";
19228
18066
  function installAntigravityStyles() {
19229
18067
  installPluginStyle("antigravity", `
19230
18068
  .dsha-page{box-sizing:border-box;color:var(--dsw-alias-label-primary);display:flex;flex-direction:column;gap:20px;max-width:780px;min-width:0;padding:2px 0 30px}
@@ -19294,7 +18132,7 @@ window.__ModuleLoader__.load({
19294
18132
  .dsha-account-details{display:flex;flex-wrap:wrap;gap:14px;font-size:12px;color:var(--dsw-alias-label-secondary)}
19295
18133
  .dsha-account-actions{display:flex;flex-wrap:wrap;gap:6px;margin-top:2px}
19296
18134
  .dsha-account-actions .dsha-btn{padding:5px 10px;font-size:12px}
19297
- `, STYLE_ID$7);
18135
+ `, STYLE_ID$6);
19298
18136
  }
19299
18137
  //#endregion
19300
18138
  //#region src/client/common/styles.ts
@@ -19328,14 +18166,6 @@ window.__ModuleLoader__.load({
19328
18166
  .dsha-account-quota-row[data-level=danger] .dsha-account-quota-fill{background:var(--dsw-alias-label-danger,#d94b4b)}
19329
18167
  .dsha-account-quota-value{color:var(--dsw-alias-label-primary);flex:none;font-variant-numeric:tabular-nums;min-width:40px;text-align:right}
19330
18168
  .dsha-account-quota-meta{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;font-variant-numeric:tabular-nums}
19331
- /* Models parked on one account. A model park is not the account's own
19332
- cooldown - the account keeps serving every other model it has - so the row
19333
- names the model and gives that park a countdown of its own. */
19334
- .dsha-account-model-cooldowns{display:flex;flex-direction:column;gap:4px;margin-top:9px}
19335
- .dsha-account-model-cooldown-row{align-items:center;display:flex;font-size:12px;gap:8px}
19336
- .dsha-account-model-cooldown-tag{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px}
19337
- .dsha-account-model-cooldown-name{color:var(--dsw-alias-label-secondary);flex:none;max-width:38%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
19338
- .dsha-account-model-cooldown-time{color:var(--dsw-alias-label-primary);flex:none;font-variant-numeric:tabular-nums}
19339
18169
  @media(max-width:560px){.dsha-account-quota-meta{display:none}}
19340
18170
  `, POOL_STYLE_ID);
19341
18171
  }
@@ -19424,7 +18254,7 @@ window.__ModuleLoader__.load({
19424
18254
  }
19425
18255
  //#endregion
19426
18256
  //#region src/client/antigravity/AntigravityComposerQuota.tsx
19427
- const api$5 = createLineApi("/antigravity/api", "Antigravity");
18257
+ const api$4 = createLineApi("/antigravity/api", "Antigravity");
19428
18258
  /**
19429
18259
  * The bucket this badge should speak for, or null when it cannot speak for one.
19430
18260
  *
@@ -19470,7 +18300,7 @@ window.__ModuleLoader__.load({
19470
18300
  }
19471
18301
  }
19472
18302
  /** The allowance the selected model actually draws on, as the badge's facts. */
19473
- function selectBadgeFacts$8(status, modelId) {
18303
+ function selectBadgeFacts$7(status, modelId) {
19474
18304
  const info = selectQuotaBucketForModel(status?.quota?.groups ?? [], modelId);
19475
18305
  if (info === null) return {
19476
18306
  text: "—",
@@ -19489,14 +18319,14 @@ window.__ModuleLoader__.load({
19489
18319
  directory,
19490
18320
  loadModelDirectory,
19491
18321
  providerId: "antigravity",
19492
- readStatus: (refresh) => refresh ? api$5.post("/quota") : api$5.get("/status"),
19493
- selectFacts: selectBadgeFacts$8,
18322
+ readStatus: (refresh) => refresh ? api$4.post("/quota") : api$4.get("/status"),
18323
+ selectFacts: selectBadgeFacts$7,
19494
18324
  label: t("composerLabel")
19495
18325
  });
19496
18326
  }
19497
18327
  //#endregion
19498
18328
  //#region src/client/claude/ClaudeComposerQuota.tsx
19499
- const api$4 = createLineApi("/claude/api", "Claude");
18329
+ const api$3 = createLineApi("/claude/api", "Claude");
19500
18330
  /**
19501
18331
  * Pick the most meaningful number for the badge.
19502
18332
  *
@@ -19512,7 +18342,7 @@ window.__ModuleLoader__.load({
19512
18342
  * remaining is 100 - used. A window at 0% used is the normal empty state and
19513
18343
  * grades as 'normal', not as an error.
19514
18344
  */
19515
- function selectBadgeFacts$7(status) {
18345
+ function selectBadgeFacts$6(status) {
19516
18346
  const quota = status?.quota;
19517
18347
  if (quota === null || quota === void 0) return {
19518
18348
  text: "—",
@@ -19545,22 +18375,22 @@ window.__ModuleLoader__.load({
19545
18375
  directory,
19546
18376
  loadModelDirectory,
19547
18377
  providerId: "claude-subscription",
19548
- readStatus: (refresh) => refresh ? api$4.post("/quota") : api$4.get("/status"),
19549
- selectFacts: selectBadgeFacts$7,
18378
+ readStatus: (refresh) => refresh ? api$3.post("/quota") : api$3.get("/status"),
18379
+ selectFacts: selectBadgeFacts$6,
19550
18380
  label: t("composerLabel")
19551
18381
  });
19552
18382
  }
19553
18383
  //#endregion
19554
18384
  //#region src/client/claude/styles.ts
19555
- const STYLE_ID$6 = "dsh-claude-settings-style";
18385
+ const STYLE_ID$5 = "dsh-claude-settings-style";
19556
18386
  /**
19557
18387
  * Claude-only additions to the shared settings design system.
19558
18388
  *
19559
18389
  * The base control styles ('.dsha-page', '.dsha-group', '.dsha-models', the
19560
18390
  * account card, the meters, the composer badge, …) come from the stylesheet the
19561
18391
  * Kimi Code sibling installs, in the same order the client installs them, so
19562
- * this file declares only what stays unique to this card — the same rule the
19563
- * WorkBuddy and GLM cards follow.
18392
+ * this file declares only what stays unique to this card — the same rule the GLM
18393
+ * and Step Code cards follow.
19564
18394
  *
19565
18395
  * What stays unique here is the sign-in flow block and the borrowed-sign-in
19566
18396
  * markers, neither of which a sibling line renders.
@@ -19576,18 +18406,18 @@ window.__ModuleLoader__.load({
19576
18406
  .dshcl-mono{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;overflow-wrap:anywhere}
19577
18407
  .dshcl-model-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;margin-left:5px}
19578
18408
  .dshcl-empty-inline{color:var(--dsw-alias-label-tertiary);font-size:12px}
19579
- `, STYLE_ID$6);
18409
+ `, STYLE_ID$5);
19580
18410
  }
19581
18411
  //#endregion
19582
18412
  //#region src/client/command-code/CommandCodeComposerQuota.tsx
19583
- const api$3 = createLineApi("/command-code/api", "Command Code");
18413
+ const api$2 = createLineApi("/command-code/api", "Command Code");
19584
18414
  /**
19585
18415
  * Pick the most meaningful number for the badge.
19586
18416
  *
19587
18417
  * A bounded usage window is the number a user actually spends down, so it wins
19588
18418
  * over a credit balance; the balance shows only when no window is reported.
19589
18419
  */
19590
- function selectBadgeFacts$6(status) {
18420
+ function selectBadgeFacts$5(status) {
19591
18421
  const quota = status?.quota;
19592
18422
  if (quota === null || quota === void 0) return {
19593
18423
  text: "—",
@@ -19633,14 +18463,14 @@ window.__ModuleLoader__.load({
19633
18463
  directory,
19634
18464
  loadModelDirectory,
19635
18465
  providerId: "command-code",
19636
- readStatus: (refresh) => refresh ? api$3.post("/quota") : api$3.get("/status"),
19637
- selectFacts: selectBadgeFacts$6,
18466
+ readStatus: (refresh) => refresh ? api$2.post("/quota") : api$2.get("/status"),
18467
+ selectFacts: selectBadgeFacts$5,
19638
18468
  label: t("composerLabel")
19639
18469
  });
19640
18470
  }
19641
18471
  //#endregion
19642
18472
  //#region src/client/kimi-code/KimiCodeComposerQuota.tsx
19643
- const api$2 = createLineApi("/kimi-code/api", "Kimi Code");
18473
+ const api$1 = createLineApi("/kimi-code/api", "Kimi Code");
19644
18474
  /**
19645
18475
  * Pick the most meaningful number for the badge.
19646
18476
  *
@@ -19648,7 +18478,7 @@ window.__ModuleLoader__.load({
19648
18478
  * blocks work soonest, so it wins over the longer pools; the 7-day allowance
19649
18479
  * shows only when no 5-hour window is reported.
19650
18480
  */
19651
- function selectBadgeFacts$5(status) {
18481
+ function selectBadgeFacts$4(status) {
19652
18482
  const quota = status?.quota;
19653
18483
  if (quota === null || quota === void 0) return {
19654
18484
  text: "—",
@@ -19684,14 +18514,14 @@ window.__ModuleLoader__.load({
19684
18514
  directory,
19685
18515
  loadModelDirectory,
19686
18516
  providerId: "kimi-code",
19687
- readStatus: (refresh) => refresh ? api$2.post("/quota") : api$2.get("/status"),
19688
- selectFacts: selectBadgeFacts$5,
18517
+ readStatus: (refresh) => refresh ? api$1.post("/quota") : api$1.get("/status"),
18518
+ selectFacts: selectBadgeFacts$4,
19689
18519
  label: t("composerLabel")
19690
18520
  });
19691
18521
  }
19692
18522
  //#endregion
19693
18523
  //#region src/client/kimi-code/styles.ts
19694
- const STYLE_ID$5 = "dsh-kimi-code-settings-style";
18524
+ const STYLE_ID$4 = "dsh-kimi-code-settings-style";
19695
18525
  /**
19696
18526
  * Node the base control styles come from.
19697
18527
  *
@@ -19777,11 +18607,11 @@ window.__ModuleLoader__.load({
19777
18607
  `;
19778
18608
  /** Kimi-specific rules layered on top of the shared control styles. */
19779
18609
  function installKimiCodeStyles() {
19780
- installPluginStyle("kimi-code", BASE, STYLE_ID$5);
18610
+ installPluginStyle("kimi-code", BASE, STYLE_ID$4);
19781
18611
  }
19782
18612
  //#endregion
19783
18613
  //#region src/client/minimax-code/MinimaxCodeComposerQuota.tsx
19784
- const api$1 = createLineApi("/minimax-code/api", "MiniMax Code");
18614
+ const api = createLineApi("/minimax-code/api", "MiniMax Code");
19785
18615
  /**
19786
18616
  * Pick the badge facts for one status answer, or nothing at all.
19787
18617
  *
@@ -19791,7 +18621,7 @@ window.__ModuleLoader__.load({
19791
18621
  * is not rendered, rather than showing a placeholder that would read as a broken
19792
18622
  * meter. Callers must treat null as "hide the badge".
19793
18623
  */
19794
- function selectBadgeFacts$4(status) {
18624
+ function selectBadgeFacts$3(status) {
19795
18625
  const quota = status?.quota;
19796
18626
  if (quota === void 0) return null;
19797
18627
  if (quota.usedPercent !== void 0 && Number.isFinite(quota.usedPercent)) {
@@ -19813,8 +18643,8 @@ window.__ModuleLoader__.load({
19813
18643
  directory,
19814
18644
  loadModelDirectory,
19815
18645
  providerId: "minimax-code",
19816
- readStatus: () => api$1.get("/quota"),
19817
- selectFacts: selectBadgeFacts$4,
18646
+ readStatus: () => api.get("/quota"),
18647
+ selectFacts: selectBadgeFacts$3,
19818
18648
  label: t("composerLabel")
19819
18649
  });
19820
18650
  }
@@ -20319,7 +19149,7 @@ window.__ModuleLoader__.load({
20319
19149
  }
20320
19150
  //#endregion
20321
19151
  //#region src/client/minimax-code/styles.ts
20322
- const STYLE_ID$4 = "dsh-minimax-code-settings-style";
19152
+ const STYLE_ID$3 = "dsh-minimax-code-settings-style";
20323
19153
  /**
20324
19154
  * MiniMax Code-only additions to the shared settings design system.
20325
19155
  *
@@ -20488,92 +19318,6 @@ window.__ModuleLoader__.load({
20488
19318
  .dshm-video-history-meta{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;font-variant-numeric:tabular-nums}
20489
19319
  @media(max-width:560px){.dshm-video-modal-root{padding:12px 8px}.dshm-video-modal{max-height:calc(100vh - 24px)}.dshm-video-field-row{flex-direction:column;gap:8px}.dshm-video-foot-hint{display:none}}
20490
19320
  @media(prefers-reduced-motion:reduce){.dshm-video-skeleton span{animation:none;opacity:.6}}
20491
- `, STYLE_ID$4);
20492
- }
20493
- //#endregion
20494
- //#region src/client/workbuddy/WorkBuddyComposerQuota.tsx
20495
- const api = createLineApi("/workbuddy/api", "WorkBuddy");
20496
- /**
20497
- * Pick the most meaningful number for the badge.
20498
- *
20499
- * A bounded allowance is what a user spends down, so it wins over a bare credit
20500
- * balance; the balance shows only when no percentage is reported. The billing
20501
- * payload reports both a cycle meter and a package meter, and the cycle meter
20502
- * is the one that actually resets, so it is preferred when both exist.
20503
- */
20504
- function selectBadgeFacts$3(status) {
20505
- const quota = status?.quota;
20506
- if (quota === null || quota === void 0) return {
20507
- text: "—",
20508
- tooltip: "WorkBuddy quota unavailable — click to refresh",
20509
- level: "normal"
20510
- };
20511
- const meter = (quota.meters ?? []).find((candidate) => candidate.id === "cycle" && candidate.remainingFraction !== null) ?? (quota.meters ?? []).find((candidate) => candidate.remainingFraction !== null);
20512
- if (meter !== void 0 && meter.remainingFraction !== null) {
20513
- const remaining = Math.round(meter.remainingFraction * 100);
20514
- return {
20515
- text: `${remaining}%`,
20516
- tooltip: `[WorkBuddy] ${meter.label}: ${remaining}% left`,
20517
- level: quotaLevel(remaining)
20518
- };
20519
- }
20520
- if (quota.remainingCredits !== null) return {
20521
- text: String(quota.remainingCredits),
20522
- tooltip: `[WorkBuddy] Remaining credits: ${quota.remainingCredits}`,
20523
- level: "normal"
20524
- };
20525
- return {
20526
- text: "—",
20527
- tooltip: "WorkBuddy quota unavailable — click to refresh",
20528
- level: "normal"
20529
- };
20530
- }
20531
- function WorkBuddyComposerQuota({ directory, loadModelDirectory, t }) {
20532
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ComposerQuotaBadge, {
20533
- directory,
20534
- loadModelDirectory,
20535
- providerId: "workbuddy-subscription",
20536
- readStatus: (refresh) => refresh ? api.post("/quota") : api.get("/status"),
20537
- selectFacts: selectBadgeFacts$3,
20538
- label: t("composerLabel")
20539
- });
20540
- }
20541
- //#endregion
20542
- //#region src/client/workbuddy/styles.ts
20543
- const STYLE_ID$3 = "dsh-workbuddy-settings-style";
20544
- /**
20545
- * WorkBuddy-only additions to the shared settings design system.
20546
- *
20547
- * The base control styles (`.dsha-page`, `.dsha-group`, `.dsha-models`, the
20548
- * account card, …) come from the stylesheet the sibling routes install, in the
20549
- * same order the client installs them, so this file declares only what stays
20550
- * unique to this card: the mono credential paths and the login-progress line.
20551
- *
20552
- * Everything this tab used to declare locally — the per-model capability line
20553
- * and the account-region headings — is gone: the model pill is name-only like
20554
- * every sibling tab, and the account card is the shared one.
20555
- */
20556
- function installWorkBuddyStyles() {
20557
- installPluginStyle("workbuddy", `
20558
- .dshwb-mono{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px}
20559
- .dsha-account-add-actions{display:flex;flex-wrap:wrap;gap:8px}
20560
- .dsha-account-add-actions .dsha-btn{background:var(--dsw-alias-button-info-fill,#397ee8);border-color:transparent;color:var(--dsw-alias-button-info-label,#fff)}
20561
- .dsha-account-add-actions .dsha-btn:hover:not(:disabled){opacity:.9;background:var(--dsw-alias-button-info-fill,#397ee8)}
20562
- /* Guardrails: one field per line, label left and control right — the same
20563
- rhythm the context-window rows use, without a divider per row. Deliberately
20564
- NOT .dsha-pref-row (a 58px full-width row with a border under it). */
20565
- .dshwb-fields{display:grid;gap:10px;margin:10px 0 14px}
20566
- .dshwb-field{align-items:center;display:flex;font-size:12px;gap:12px;justify-content:space-between}
20567
- .dshwb-control{align-items:center;display:flex;gap:8px}
20568
- .dshwb-control input{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);font:inherit;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;padding:7px 9px;width:120px;text-align:right;box-sizing:border-box}
20569
- .dshwb-control input:disabled{opacity:.5}
20570
- .dshwb-control small{color:var(--dsw-alias-label-tertiary);font-size:11px;width:52px;text-align:left}
20571
- /* One control row: a flexible input with its actions beside it, never wrapped
20572
- into two ragged lines. */
20573
- .dshwb-inputrow{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:10px 0 14px}
20574
- .dshwb-inputrow>input{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;padding:7px 9px;flex:1 1 260px;min-width:220px;max-width:420px;box-sizing:border-box}
20575
- .dshwb-inputrow>input:disabled{opacity:.5}
20576
-
20577
19321
  `, STYLE_ID$3);
20578
19322
  }
20579
19323
  //#endregion
@@ -20639,8 +19383,9 @@ window.__ModuleLoader__.load({
20639
19383
  * 本文件只声明没有兄弟线路共用过的东西:登录流程块、兜底入口行与手工粘贴面板、
20640
19384
  * 等宽文本、模型行右侧的窗口数字,以及「导入的登录态」徽标。
20641
19385
  *
20642
- * 两区登录入口复用的 .dsha-account-add-actions 由 workbuddy/styles.ts 声明;
20643
- * Claude 卡片同样直接用它而不在自己文件里重复声明,本卡沿用同一做法。
19386
+ * 两区登录入口复用的 .dsha-account-add-actions 是跨线路共享的声明,现在随本文件
19387
+ * 一起安装;Claude / Step Code / Qoder / Cline Pass / OpenDesign / Codex 卡片都直接
19388
+ * 用它而不在自己文件里重复声明,本卡沿用同一做法。
20644
19389
  */
20645
19390
  function installGlmCodingPlanStyles() {
20646
19391
  installPluginStyle("glm-coding-plan", `
@@ -20659,6 +19404,13 @@ window.__ModuleLoader__.load({
20659
19404
  .dshglm-mono{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;overflow-wrap:anywhere}
20660
19405
  .dshglm-model-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;margin-left:5px}
20661
19406
  .dsha-badge.glm-adopted{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 16%,var(--dsw-alias-bg-layer-1));border-color:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 45%,var(--dsw-alias-border-l2));color:var(--dsw-alias-label-primary)}
19407
+
19408
+ /* 跨线路共享的登录入口按钮行:两区登录入口把多个「添加账号」按钮排进同一行,
19409
+ 按钮沿用基础 .dsha-btn 的形状,只在这里统一换成信息色填充。原先是另一张卡片的
19410
+ 样式表带出来的,那张卡片下线后这份声明移到这里,选择器与取值一字未改。 */
19411
+ .dsha-account-add-actions{display:flex;flex-wrap:wrap;gap:8px}
19412
+ .dsha-account-add-actions .dsha-btn{background:var(--dsw-alias-button-info-fill,#397ee8);border-color:transparent;color:var(--dsw-alias-button-info-label,#fff)}
19413
+ .dsha-account-add-actions .dsha-btn:hover:not(:disabled){opacity:.9;background:var(--dsw-alias-button-info-fill,#397ee8)}
20662
19414
  `, STYLE_ID$2);
20663
19415
  }
20664
19416
  //#endregion
@@ -20708,8 +19460,8 @@ window.__ModuleLoader__.load({
20708
19460
  * 输入框右侧的额度胶囊本体。
20709
19461
  *
20710
19462
  * **槽位号由波次 4 注册,本文件不注册任何槽位**:conversation.input.right 现有
20711
- * 35–42(codex → antigravity → command-code → kimi-code → workbuddy → minimax-code →
20712
- * claude → glm-coding-plan),本线路取下一个号 43,id 沿用命名习惯
19463
+ * 35–42(codex → antigravity → command-code → kimi-code → minimax-code → claude →
19464
+ * glm-coding-plan,39 号空出),本线路取下一个号 43,id 沿用命名习惯
20713
19465
  * 'step-code-quota',locale 为 NS_STEP_CODE。顺延而不是插号:给新线路重排既有号会让
20714
19466
  * 已上线线路的槽位位置无谓地变一次。
20715
19467
  */
@@ -20733,7 +19485,7 @@ window.__ModuleLoader__.load({
20733
19485
  * 负责,账号卡与其配额条(.dsha-account-*)由 common/styles.ts 负责,基础控件
20734
19486
  * (.dsha-page / .dsha-group / .dsha-row / 计量条 .dsha-meter-* 等)由兄弟线路的安装器
20735
19487
  * 负责;本卡直接用它们,不在这里再写一遍。.dsha-account-add-actions 同样沿用
20736
- * workbuddy/styles.ts 的那份声明。
19488
+ * glm-coding-plan/styles.ts 随安装器带出的那份共享声明。
20737
19489
  *
20738
19490
  * 本文件只声明三样别处没有的东西:
20739
19491
  *
@@ -51651,7 +50403,7 @@ window.__ModuleLoader__.load({
51651
50403
  installModelChecklistStyles();
51652
50404
  return () => {};
51653
50405
  }, "dsh-chatgpt-subscription: hub styles");
51654
- ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries$13), "dsh-antigravity: dictionaries");
50406
+ ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries$12), "dsh-antigravity: dictionaries");
51655
50407
  ctx.effect(() => {
51656
50408
  installAntigravityStyles();
51657
50409
  return () => {};
@@ -51661,8 +50413,8 @@ window.__ModuleLoader__.load({
51661
50413
  installClaudeStyles();
51662
50414
  return () => {};
51663
50415
  }, "dsh-claude: styles");
51664
- ctx.effect(() => ctx.locale.register(NS_COMMAND_CODE, dictionaries$12), "dsh-command-code: dictionaries");
51665
- ctx.effect(() => ctx.locale.register(NS_KIMI_CODE, dictionaries$11), "dsh-kimi-code: dictionaries");
50416
+ ctx.effect(() => ctx.locale.register(NS_COMMAND_CODE, dictionaries$11), "dsh-command-code: dictionaries");
50417
+ ctx.effect(() => ctx.locale.register(NS_KIMI_CODE, dictionaries$10), "dsh-kimi-code: dictionaries");
51666
50418
  ctx.effect(() => {
51667
50419
  installKimiCodeStyles();
51668
50420
  return () => {};
@@ -51672,17 +50424,12 @@ window.__ModuleLoader__.load({
51672
50424
  installMinimaxCodeStyles();
51673
50425
  return () => {};
51674
50426
  }, "dsh-minimax-code: styles");
51675
- ctx.effect(() => ctx.locale.register(NS_WORKBUDDY, dictionaries$10), "dsh-workbuddy: dictionaries");
51676
50427
  ctx.effect(() => ctx.locale.register(NS_GLM_CODING_PLAN, dictionaries$8), "dsh-glm-coding-plan: dictionaries");
51677
50428
  ctx.effect(() => {
51678
50429
  installGlmCodingPlanStyles();
51679
50430
  return () => {};
51680
50431
  }, "dsh-glm-coding-plan: styles");
51681
50432
  ctx.effect(() => ctx.locale.register(NS_OLLAMA, dictionaries$6), "dsh-ollama: dictionaries");
51682
- ctx.effect(() => {
51683
- installWorkBuddyStyles();
51684
- return () => {};
51685
- }, "dsh-workbuddy: styles");
51686
50433
  ctx.effect(() => ctx.locale.register(NS_PROGRESS_UPDATES, dictionaries), "dsh-progress-updates: dictionaries");
51687
50434
  ctx.effect(() => {
51688
50435
  installProgressUpdatesStyles();
@@ -51762,13 +50509,6 @@ window.__ModuleLoader__.load({
51762
50509
  locale: NS_KIMI_CODE,
51763
50510
  inject: (sessionId) => composerBadgeInject(ctx, sessionId)
51764
50511
  }, KimiCodeComposerQuota));
51765
- ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
51766
- name: "conversation.input.right",
51767
- id: "workbuddy-quota",
51768
- order: 39,
51769
- locale: NS_WORKBUDDY,
51770
- inject: (sessionId) => composerBadgeInject(ctx, sessionId)
51771
- }, WorkBuddyComposerQuota));
51772
50512
  ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
51773
50513
  name: "conversation.input.right",
51774
50514
  id: "minimax-code-quota",