dsh-codex-subscription 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -4
- package/DIRECTORY.md +1 -1
- package/README.md +12 -8
- package/README.zh-CN.md +9 -7
- package/lib/client.js +120 -73
- package/lib/index.js +32 -21
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -6,7 +6,7 @@ Use this guide when a user asks an Agent to install, update, verify, or remove
|
|
|
6
6
|
## Safety
|
|
7
7
|
|
|
8
8
|
- Confirm the target DSH installation and profile. Use `web` only when it is the user's target.
|
|
9
|
-
- Use the exact `1.
|
|
9
|
+
- Use the exact `1.5.0` package below; do not install a moving branch.
|
|
10
10
|
- Never print OAuth credentials, account IDs, authorization callbacks, or credential-store contents.
|
|
11
11
|
- Preserve the DSH profile, unrelated plugins, sessions, and saved sign-in.
|
|
12
12
|
- Do not start, stop, or restart DSH without explicit permission.
|
|
@@ -34,13 +34,13 @@ For an official DSH installation run through npm, keep the complete `npx` prefix
|
|
|
34
34
|
run command does not create a global `dsh` command:
|
|
35
35
|
|
|
36
36
|
```sh
|
|
37
|
-
npx -y @deepseek-ai/dsh@0.1.1-rc.2 plugin --profile web add dsh-codex-subscription@1.
|
|
37
|
+
npx -y @deepseek-ai/dsh@0.1.1-rc.2 plugin --profile web add dsh-codex-subscription@1.5.0
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
With an existing global `dsh` command:
|
|
41
41
|
|
|
42
42
|
```sh
|
|
43
|
-
dsh plugin --profile web add dsh-codex-subscription@1.
|
|
43
|
+
dsh plugin --profile web add dsh-codex-subscription@1.5.0
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
Use the same `add` command to update or repair. This is the complete package-changing operation.
|
|
@@ -58,7 +58,7 @@ dsh --profile web --dump-config
|
|
|
58
58
|
|
|
59
59
|
For the official npm route, run the same checks with `npx -y @deepseek-ai/dsh@0.1.1-rc.2` in place of `dsh`.
|
|
60
60
|
|
|
61
|
-
1. `dsh-codex-subscription` version `1.
|
|
61
|
+
1. `dsh-codex-subscription` version `1.5.0` appears exactly once.
|
|
62
62
|
2. `codex-subscription` appears exactly once in the composed config.
|
|
63
63
|
3. No unrelated plugin or profile was changed and DSH was not restarted.
|
|
64
64
|
|
package/DIRECTORY.md
CHANGED
|
@@ -18,7 +18,7 @@ Use a ChatGPT subscription in DeepSeek Harness through independent OAuth sign-in
|
|
|
18
18
|
- Codex CLI required: no
|
|
19
19
|
- OpenAI API key required: no
|
|
20
20
|
- Platforms: official DSH plus DSH-Portable product forms for Windows, macOS, and Linux
|
|
21
|
-
- Main capabilities: Codex models, quota, web search, image
|
|
21
|
+
- Main capabilities: Codex models, quota and expiring resets, web search, image preview/download/refinement, optional composer quota, optional Fast mode, secret-free support diagnostics and direct feedback
|
|
22
22
|
- Safety boundary: subscription failures remain visible and never silently fall back to another paid provider
|
|
23
23
|
|
|
24
24
|
## Install
|
package/README.md
CHANGED
|
@@ -47,9 +47,9 @@ DSH-Portable exposes the same standard plugin command, so the command above also
|
|
|
47
47
|
| **Recoverable and diagnosable** | Sign-in state reconciles automatically; Settings can create a support report without credentials or account identifiers |
|
|
48
48
|
| **Visible quota** | Keep backend-provided standard Codex, Spark, and other limits separate |
|
|
49
49
|
| **Composer quota** | Choose a compact percentage, progress bar, or no inline quota display |
|
|
50
|
-
| **Safe quota reset** |
|
|
50
|
+
| **Safe quota reset** | See the next expiry and deliberately try a reset with a cooldown and acknowledgement |
|
|
51
51
|
| **Subscription search** | Explicitly choose DSH default search or Codex subscription search |
|
|
52
|
-
| **Codex image generation** |
|
|
52
|
+
| **Codex image generation** | Preview or download the original, then describe refinements in the same conversation |
|
|
53
53
|
| **Fast mode (Beta)** | Switch between Standard and Fast directly in the composer |
|
|
54
54
|
|
|
55
55
|
These capabilities reuse the same local ChatGPT sign-in. Subscription routing failures stay visible and never silently switch to another paid route.
|
|
@@ -143,10 +143,10 @@ Restart DSH manually after installation, then:
|
|
|
143
143
|
- A clear choice between DSH default search and Codex subscription search;
|
|
144
144
|
- Actual backend-provided quota, reset time, and freshness;
|
|
145
145
|
- Separate standard Codex, Codex-Spark, Credits, and other independent limits;
|
|
146
|
-
-
|
|
146
|
+
- Visible quota-reset count and earliest expiry, with deliberate early redemption, layered confirmation, and no automatic retry;
|
|
147
147
|
- Optional percentage or progress bar for the selected Codex model (off by default);
|
|
148
148
|
- Standard or Fast mode for supported Codex models directly in the composer (Beta);
|
|
149
|
-
- A copyable support report in Settings
|
|
149
|
+
- A copyable support report and direct feedback link in Settings; the report excludes OAuth credentials, account identifiers, and authorization timestamps;
|
|
150
150
|
- Visible errors when subscription routing is unavailable, with no silent paid fallback.
|
|
151
151
|
|
|
152
152
|
### Composer quota
|
|
@@ -161,10 +161,14 @@ Standard Codex uses the lowest remaining window returned by the service; Spark u
|
|
|
161
161
|
|
|
162
162
|
### Safe quota reset
|
|
163
163
|
|
|
164
|
-
If ChatGPT reports an available quota reset, Settings shows
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
If ChatGPT reports an available quota reset, Settings shows its count and earliest disclosed expiry in a compact row.
|
|
165
|
+
You may deliberately try it before a quota reaches 100%, which is useful for a reset nearing expiry. ChatGPT still
|
|
166
|
+
decides whether a window needs resetting and may return **nothing to reset** without spending the reset. The final
|
|
167
|
+
action requires an acknowledgement checkbox and five-second cooldown. Cancel never consumes a reset, rapid repeated
|
|
168
|
+
clicks are single-flight, and an uncertain network result is never retried automatically.
|
|
169
|
+
|
|
170
|
+
Generated images open in a plugin-owned preview with **Download original**. To refine one, continue describing the
|
|
171
|
+
change in the same conversation; the durable conversation image remains available to the next model turn.
|
|
168
172
|
|
|
169
173
|
### Composer speed (Beta)
|
|
170
174
|
|
package/README.zh-CN.md
CHANGED
|
@@ -48,9 +48,9 @@ DSH-Portable 也提供相同的标准插件命令,因此同样使用上面的
|
|
|
48
48
|
| **可恢复、可诊断** | 登录状态会自动对账;设置页可生成不含凭据和账号标识的支持报告 |
|
|
49
49
|
| **额度可见** | 普通 Codex、Spark 等服务端实际返回的额度分开显示 |
|
|
50
50
|
| **输入框额度** | 可选择紧凑百分比、进度条或完全关闭输入框额度显示 |
|
|
51
|
-
| **安全额度重置** |
|
|
51
|
+
| **安全额度重置** | 直接查看最早到期时间,并通过冷静期和知情确认主动尝试重置 |
|
|
52
52
|
| **订阅搜索** | 可在 DSH 默认搜索与 Codex 订阅搜索之间明确切换 |
|
|
53
|
-
| **Codex 图片生成** |
|
|
53
|
+
| **Codex 图片生成** | 预览或下载原图,并在同一会话继续描述修改内容 |
|
|
54
54
|
| **高速模式(Beta)** | 直接在输入框切换标准或高速,无需离开当前会话 |
|
|
55
55
|
|
|
56
56
|
这些能力共用同一份本机 ChatGPT 登录。订阅路由失败时会明确报错,不会静默切换到其他付费路由。
|
|
@@ -143,10 +143,10 @@ dsh --profile web --dump-config
|
|
|
143
143
|
- DSH 默认搜索与 Codex 订阅搜索可随时切换;
|
|
144
144
|
- 设置页显示服务端返回的额度、重置时间和更新时间;
|
|
145
145
|
- 普通 Codex、Codex-Spark、Credits 等独立额度分开显示;
|
|
146
|
-
-
|
|
146
|
+
- 显示重置卡数量与最早到期时间,也允许在额度未完全用尽时主动尝试,并经过分层确认且不会自动重试;
|
|
147
147
|
- 输入框可用百分比或进度条显示当前 Codex 模型的剩余额度(默认关闭);
|
|
148
148
|
- 输入框可为支持的 Codex 模型切换标准或高速模式(Beta);
|
|
149
|
-
-
|
|
149
|
+
- 设置页可生成并复制无敏感信息的支持诊断,并直接打开反馈入口;报告不包含 OAuth 凭据、账号标识或授权时间;
|
|
150
150
|
- 订阅路由不可用时明确报错,不会静默切换到其他付费路由。
|
|
151
151
|
|
|
152
152
|
### 输入框额度
|
|
@@ -160,9 +160,11 @@ Spark 使用独立额度。插件不会写死“5 小时 + 每周”,也不会
|
|
|
160
160
|
|
|
161
161
|
### 安全使用额度重置
|
|
162
162
|
|
|
163
|
-
ChatGPT
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
ChatGPT 返回可用重置卡时,设置页会用紧凑的一行显示数量和服务端提供的最早到期时间。即使额度尚未到 100%,
|
|
164
|
+
也可以主动尝试使用,适合重置卡即将过期的情况;是否需要重置仍由 ChatGPT 判断,服务端可能返回“当前无需重置”且不扣次数。
|
|
165
|
+
最终操作需要勾选知情确认并等待 5 秒。取消不会消耗,快速连续点击只允许一次请求,网络结果不确定时也不会自动重试。
|
|
166
|
+
|
|
167
|
+
生成的图片可在插件自有预览中下载原图。需要继续修改时,直接在同一会话描述改动;持久化的会话图片会继续提供给下一轮模型。
|
|
166
168
|
|
|
167
169
|
### 输入框速度(Beta)
|
|
168
170
|
|
package/lib/client.js
CHANGED
|
@@ -127,6 +127,7 @@ window.__ModuleLoader__.load({
|
|
|
127
127
|
];
|
|
128
128
|
const NS = "settings.codexSubscription";
|
|
129
129
|
const CHANNEL = "/codex-subscription";
|
|
130
|
+
const SUPPORT_ISSUE_URL = "https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml";
|
|
130
131
|
const QUICK_QUOTA_REFRESH_EVENT = "dsh-codex-subscription:refresh-quick-quota";
|
|
131
132
|
const QUICK_QUOTA_REFRESH_MS = 6e4;
|
|
132
133
|
const zh = {
|
|
@@ -153,6 +154,7 @@ window.__ModuleLoader__.load({
|
|
|
153
154
|
diagnosticsCopy: "复制诊断",
|
|
154
155
|
diagnosticsCopied: "已复制",
|
|
155
156
|
diagnosticsFailed: "无法生成诊断信息。",
|
|
157
|
+
feedbackOpen: "反馈问题",
|
|
156
158
|
searchTitle: "搜索来源",
|
|
157
159
|
searchDsh: "DSH 默认",
|
|
158
160
|
searchDshHint: "当前搜索服务",
|
|
@@ -183,13 +185,14 @@ window.__ModuleLoader__.load({
|
|
|
183
185
|
monthlyCreditLimit: "Credits 月度消费上限",
|
|
184
186
|
resetCredits: "可用额度重置次数",
|
|
185
187
|
resetCreditsValue: "{count} 次",
|
|
186
|
-
resetUse: "
|
|
187
|
-
resetUnavailable: "仅当至少一个 Codex 模型额度已用尽时可使用。",
|
|
188
|
+
resetUse: "查看并使用",
|
|
188
189
|
resetPreparing: "正在读取重置详情…",
|
|
189
190
|
resetConfirmTitle: "确认使用额度重置",
|
|
190
|
-
resetWarning: "
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
resetWarning: "若 ChatGPT 执行重置,将立即消耗 1 次且无法撤销。",
|
|
192
|
+
resetEarlyWarning: "当前模型额度尚未用尽;ChatGPT 可能执行重置,也可能判定暂无需重置且不消耗次数。",
|
|
193
|
+
resetAcknowledge: "我知道这次操作可能立即消耗 1 次重置",
|
|
194
|
+
resetCreditExpires: "最早到期:{value}",
|
|
195
|
+
resetCreditExpiryUnknown: "到期时间未提供",
|
|
193
196
|
resetWait: "请再等待 {count} 秒",
|
|
194
197
|
resetFinal: "消耗 1 次并重置额度",
|
|
195
198
|
resetUsing: "正在重置…",
|
|
@@ -202,8 +205,7 @@ window.__ModuleLoader__.load({
|
|
|
202
205
|
resetExpired: "本次确认已失效,请重新开始。",
|
|
203
206
|
resetInProgress: "额度重置正在处理中。",
|
|
204
207
|
resetTooEarly: "请等待冷静期结束后再确认。",
|
|
205
|
-
|
|
206
|
-
resetNotExhausted: "当前 Codex 模型额度尚未用尽。",
|
|
208
|
+
resetAcknowledgeRequired: "请先确认已了解这次操作可能消耗重置次数。",
|
|
207
209
|
resetAccountChanged: "登录账号已变更,请重新开始。",
|
|
208
210
|
creditsNote: "仅显示 Codex 为此账户或工作区实际返回的额外 Credits、消费上限或额度重置次数;三者不是同一项。",
|
|
209
211
|
creditsUsed: "已用 {used} / {limit} credits",
|
|
@@ -240,7 +242,9 @@ window.__ModuleLoader__.load({
|
|
|
240
242
|
imageLoading: "正在加载图片…",
|
|
241
243
|
imageLoadFailed: "图片加载失败,点击重试",
|
|
242
244
|
imagePreview: "图片预览",
|
|
243
|
-
imageClosePreview: "关闭预览"
|
|
245
|
+
imageClosePreview: "关闭预览",
|
|
246
|
+
imageDownload: "下载原图",
|
|
247
|
+
imageRefineHint: "继续在当前会话描述修改内容,即可基于这张图片继续调整。"
|
|
244
248
|
};
|
|
245
249
|
const en = {
|
|
246
250
|
nav: "Codex",
|
|
@@ -266,6 +270,7 @@ window.__ModuleLoader__.load({
|
|
|
266
270
|
diagnosticsCopy: "Copy report",
|
|
267
271
|
diagnosticsCopied: "Copied",
|
|
268
272
|
diagnosticsFailed: "Could not create diagnostics.",
|
|
273
|
+
feedbackOpen: "Report a problem",
|
|
269
274
|
searchTitle: "Search source",
|
|
270
275
|
searchDsh: "DSH default",
|
|
271
276
|
searchDshHint: "Current search service",
|
|
@@ -296,13 +301,14 @@ window.__ModuleLoader__.load({
|
|
|
296
301
|
monthlyCreditLimit: "Monthly Credits spending cap",
|
|
297
302
|
resetCredits: "Available quota resets",
|
|
298
303
|
resetCreditsValue: "{count} available",
|
|
299
|
-
resetUse: "
|
|
300
|
-
resetUnavailable: "Available only when at least one Codex model quota is exhausted.",
|
|
304
|
+
resetUse: "Review and use",
|
|
301
305
|
resetPreparing: "Reading reset details…",
|
|
302
306
|
resetConfirmTitle: "Confirm quota reset",
|
|
303
|
-
resetWarning: "
|
|
304
|
-
|
|
305
|
-
|
|
307
|
+
resetWarning: "If ChatGPT performs the reset, one reset is consumed immediately and cannot be restored.",
|
|
308
|
+
resetEarlyWarning: "No model quota is exhausted. ChatGPT may reset it, or report that nothing needs resetting without consuming a reset.",
|
|
309
|
+
resetAcknowledge: "I understand this may consume one reset now",
|
|
310
|
+
resetCreditExpires: "Earliest expiry: {value}",
|
|
311
|
+
resetCreditExpiryUnknown: "Expiration time not provided",
|
|
306
312
|
resetWait: "Wait {count} more seconds",
|
|
307
313
|
resetFinal: "Consume one reset",
|
|
308
314
|
resetUsing: "Resetting…",
|
|
@@ -315,8 +321,7 @@ window.__ModuleLoader__.load({
|
|
|
315
321
|
resetExpired: "This confirmation expired. Start again.",
|
|
316
322
|
resetInProgress: "A quota reset is already in progress.",
|
|
317
323
|
resetTooEarly: "Wait for the cooldown before confirming.",
|
|
318
|
-
|
|
319
|
-
resetNotExhausted: "The current Codex model quota is not exhausted.",
|
|
324
|
+
resetAcknowledgeRequired: "Confirm that you understand this may consume a reset.",
|
|
320
325
|
resetAccountChanged: "The signed-in account changed. Start again.",
|
|
321
326
|
creditsNote: "Shows only extra Credits, spending caps, or quota resets returned for this account or workspace; these are separate items.",
|
|
322
327
|
creditsUsed: "{used} / {limit} credits used",
|
|
@@ -353,7 +358,9 @@ window.__ModuleLoader__.load({
|
|
|
353
358
|
imageLoading: "Loading image…",
|
|
354
359
|
imageLoadFailed: "Image failed to load. Click to retry",
|
|
355
360
|
imagePreview: "Image preview",
|
|
356
|
-
imageClosePreview: "Close preview"
|
|
361
|
+
imageClosePreview: "Close preview",
|
|
362
|
+
imageDownload: "Download original",
|
|
363
|
+
imageRefineHint: "Describe the changes in this conversation to continue refining this image."
|
|
357
364
|
};
|
|
358
365
|
const STYLE = `
|
|
359
366
|
.codexSubscription{display:flex;flex-direction:column;gap:10px;max-width:720px;color:var(--dsw-alias-label-primary);container-type:inline-size}
|
|
@@ -372,7 +379,7 @@ window.__ModuleLoader__.load({
|
|
|
372
379
|
.codexSubscriptionFlow p{font-size:13px;line-height:20px;color:var(--dsw-alias-label-secondary)}.codexSubscriptionCode{width:max-content;max-width:100%;font:600 16px/22px ui-monospace,SFMono-Regular,Consolas,monospace;letter-spacing:.08em;overflow-wrap:anywhere}
|
|
373
380
|
.codexSubscriptionError{font-size:13px;line-height:20px;color:var(--dsw-alias-state-error-primary)}.codexSubscriptionInput{width:100%;box-sizing:border-box}
|
|
374
381
|
.codexSubscriptionRecover{display:flex;align-items:center;justify-content:space-between;gap:12px}.codexSubscriptionRecover .codexSubscriptionError{flex:1}.codexSubscriptionRecover button{flex:0 0 auto}
|
|
375
|
-
.codexSubscriptionDiagnostics pre{max-height:240px;margin:0;padding:10px 12px;border-radius:8px;background:var(--dsw-alias-bg-module-platform);overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font:11px/17px ui-monospace,SFMono-Regular,Consolas,monospace;color:var(--dsw-alias-label-secondary)}
|
|
382
|
+
.codexSubscriptionDiagnostics pre{max-height:240px;margin:0;padding:10px 12px;border-radius:8px;background:var(--dsw-alias-bg-module-platform);overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font:11px/17px ui-monospace,SFMono-Regular,Consolas,monospace;color:var(--dsw-alias-label-secondary)}.codexSubscriptionLink{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:32px;padding:0 13px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;text-decoration:none;white-space:nowrap}.codexSubscriptionLink:hover{background:var(--dsw-alias-bg-module-platform)}.codexSubscriptionLink:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}
|
|
376
383
|
.codexSubscriptionSectionTitle{display:flex;flex:1;min-width:0;flex-direction:column;gap:2px}.codexSubscriptionFreshness{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
|
|
377
384
|
.codexSubscriptionRefresh{flex:0 0 auto;min-width:72px;width:max-content;white-space:nowrap!important;word-break:keep-all!important;overflow-wrap:normal!important;writing-mode:horizontal-tb!important}.codexSubscriptionRefresh *{white-space:nowrap!important;word-break:keep-all!important;writing-mode:horizontal-tb!important}
|
|
378
385
|
.codexSubscriptionEmpty{padding:18px;border:1px dashed var(--dsw-alias-border-l3);border-radius:10px;text-align:center;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}
|
|
@@ -382,13 +389,13 @@ window.__ModuleLoader__.load({
|
|
|
382
389
|
.codexSubscriptionLimit progress::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.codexSubscriptionLimit progress::-webkit-progress-value{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}.codexSubscriptionLimit progress::-moz-progress-bar{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}.codexSubscriptionLimitMeta{display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
|
|
383
390
|
.codexSubscriptionCreditSection{display:flex;flex-direction:column;gap:7px}.codexSubscriptionCreditNote{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionCreditRows{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px}.codexSubscriptionCreditBalance,.codexSubscriptionSpendLimit{min-width:0;border-radius:10px;padding:12px 14px;background:var(--dsw-alias-bg-module-platform)}
|
|
384
391
|
.codexSubscriptionCreditBalance{display:flex;flex-direction:column;gap:6px}.codexSubscriptionCreditBalance span,.codexSubscriptionCreditLabel{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}.codexSubscriptionCreditBalance strong{font:600 18px/24px ui-monospace,SFMono-Regular,Consolas,monospace;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
|
|
385
|
-
.codexSubscriptionResetSummary{display:flex;align-items:center;justify-content:space-between;gap:10px}.codexSubscriptionResetBalance{display:flex;flex-direction:column;gap:8px}.codexSubscriptionResetBalance .codexSubscriptionActions{justify-content:flex-start}.codexSubscriptionResetFlow{display:flex;flex-direction:column;gap:
|
|
392
|
+
.codexSubscriptionResetSummary{display:flex;align-items:center;justify-content:space-between;gap:10px}.codexSubscriptionResetMeta{display:flex;min-width:0;flex-direction:column;gap:1px}.codexSubscriptionResetBalance{display:flex;flex-direction:column;gap:8px}.codexSubscriptionResetBalance .codexSubscriptionActions{justify-content:flex-start}.codexSubscriptionResetFlow{display:flex;flex-direction:column;gap:10px;border-top:1px solid var(--dsw-alias-border-l2);padding-top:10px}.codexSubscriptionResetFlow h4{margin:0;font-size:13px;line-height:20px;font-weight:500}.codexSubscriptionResetWarning{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}.codexSubscriptionResetExpiry{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionResetCheck{display:flex;align-items:flex-start;gap:8px;padding:9px 10px;border-radius:8px;background:var(--dsw-alias-bg-module-platform);font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary);cursor:pointer}.codexSubscriptionResetCheck input{margin:3px 0 0;accent-color:var(--dsw-alias-label-primary)}.codexSubscriptionResetFinal{border-color:var(--dsw-alias-state-error-primary)!important;color:var(--dsw-alias-state-error-primary)!important}.codexSubscriptionResetResult{font-size:12px;line-height:18px;color:var(--dsw-alias-state-success-primary)}
|
|
386
393
|
.codexSubscriptionSpendLimit{display:flex;flex-direction:column;gap:8px}.codexSubscriptionSpendTop{display:flex;align-items:baseline;justify-content:space-between;gap:12px}.codexSubscriptionSpendTop strong{font:600 16px/22px ui-monospace,SFMono-Regular,Consolas,monospace;font-variant-numeric:tabular-nums}.codexSubscriptionSpendLimit progress{width:100%;height:6px;border:0;border-radius:999px;overflow:hidden;background:var(--dsw-alias-border-l3);accent-color:var(--dsw-alias-brand-primary,#3964fe);-webkit-appearance:none;appearance:none}.codexSubscriptionSpendLimit progress::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.codexSubscriptionSpendLimit progress::-webkit-progress-value{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}.codexSubscriptionSpendLimit progress::-moz-progress-bar{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}
|
|
387
394
|
.codexComposerQuota{display:inline-flex;align-items:center;flex:0 0 auto;height:28px;box-sizing:border-box;padding:0;color:var(--dsw-alias-label-secondary);font-family:inherit;font-size:12px;line-height:20px;font-weight:500;font-variant-numeric:tabular-nums;white-space:nowrap;user-select:none}.codexComposerQuotaBar{display:block;width:40px;height:4px;border:0;border-radius:999px;overflow:hidden;background:var(--dsw-alias-border-l3);accent-color:var(--dsw-alias-label-secondary);-webkit-appearance:none;appearance:none}.codexComposerQuotaBar::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.codexComposerQuotaBar::-webkit-progress-value{background:var(--dsw-alias-label-secondary);border-radius:999px}.codexComposerQuotaBar::-moz-progress-bar{background:var(--dsw-alias-label-secondary);border-radius:999px}
|
|
388
395
|
.codexModelSelect{position:relative;min-width:0}.codexModelSelectTrigger{display:flex;align-items:center;gap:4px;min-width:0;max-width:min(360px,45cqw);height:28px;padding:0 4px 0 8px;border:0;border-radius:24px;outline:0;background:transparent;color:var(--dsw-alias-label-secondary);font-size:13px;font-weight:500;line-height:20px;cursor:pointer}.codexModelSelectTrigger:hover:not(:disabled),.codexModelSelectTrigger[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover)}.codexModelSelectTrigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.codexModelSelectTrigger:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.codexModelSelectBolt{display:block;flex:none;width:14px;height:14px;color:var(--dsw-alias-label-primary)}.codexModelSelectLabel{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.codexModelSelectEffort{flex:none;color:var(--dsw-alias-label-caption)}.codexModelSelectChevron{flex:none;color:var(--dsw-alias-label-caption);transition:transform 120ms}.codexModelSelectTrigger[aria-expanded=true] .codexModelSelectChevron{transform:rotate(180deg)}
|
|
389
396
|
.codexModelSelectMenu,.codexModelSelectSubmenu{position:absolute;z-index:30;box-sizing:border-box;width:max-content;min-width:min(240px,calc(100vw - 32px));max-width:min(420px,calc(100vw - 32px));max-height:min(360px,calc(100vh - 96px));padding:4px;border:1px solid var(--dsw-alias-border-inverted);border-radius:12px;background:var(--dsw-specific-menu);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);overflow:hidden}.codexModelSelectMenu{right:0;bottom:calc(100% + 8px)}.codexModelSelectSubmenu{right:calc(100% + 8px);bottom:0;min-width:min(230px,calc(100vw - 32px))}.codexModelSelectCell{display:flex;align-items:center;gap:8px;width:100%;min-width:100%;height:40px;box-sizing:border-box;padding:0 10px;border:0;border-radius:10px;background:transparent;color:inherit;font-size:14px;line-height:22px;text-align:left;cursor:pointer}.codexModelSelectCell:hover,.codexModelSelectCell:focus-visible,.codexModelSelectCell[data-open=true]{background:var(--dsw-alias-interactive-bg-hover);outline:0}.codexModelSelectCell:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.codexModelSelectCellLabel{flex:none;white-space:nowrap}.codexModelSelectCellValue{flex:auto;min-width:0;overflow:hidden;color:var(--dsw-alias-label-tertiary);text-align:right;text-overflow:ellipsis;white-space:nowrap}.codexModelSelectCellChevron{flex:none;color:var(--dsw-alias-label-tertiary)}.codexModelSelectGroups{min-height:0;max-height:352px;overflow-y:auto}.codexModelSelectGroup+.codexModelSelectGroup{margin-top:4px}.codexModelSelectGroupTitle{position:sticky;top:0;z-index:1;padding:5px 8px 3px;background:var(--dsw-specific-menu);color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:500;line-height:18px}.codexModelSelectOption{display:flex;align-items:center;gap:8px;width:100%;min-width:100%;min-height:38px;box-sizing:border-box;padding:6px 8px;border:0;border-radius:10px;outline:0;background:transparent;color:inherit;text-align:left;cursor:pointer}.codexModelSelectOption:hover:not(:disabled),.codexModelSelectOption:focus-visible{background:var(--dsw-alias-interactive-bg-hover)}.codexModelSelectOption:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.codexModelSelectOptionCopy{display:flex;flex:1;min-width:0;flex-direction:column}.codexModelSelectOptionName{overflow:hidden;color:inherit;font-size:14px;font-weight:500;line-height:20px;text-overflow:ellipsis;white-space:nowrap}.codexModelSelectOptionDescription{overflow:hidden;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;text-overflow:ellipsis;white-space:nowrap}.codexModelSelectCheck{display:grid;place-items:center;flex:0 0 18px;color:var(--dsw-alias-label-primary)}.codexModelSelectStatus,.codexModelSelectEmpty{padding:10px;color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}.codexModelSelectError,.codexModelSelectWarning{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;margin-bottom:4px;padding:7px 8px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}.codexModelSelectWarning{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-state-warn-label)}.codexModelSelectRetry{flex:none;padding:0;border:0;background:transparent;color:inherit;font:inherit;font-weight:600;cursor:pointer}
|
|
390
397
|
.codexModelSelectMenu{overflow:visible}
|
|
391
|
-
.codexImageTool{display:flex;flex-direction:column;gap:8px;margin:4px 0;color:var(--dsw-alias-label-primary)}.codexImageToolRow{display:flex;align-items:center;min-height:24px;gap:8px;font-size:13px;line-height:20px}.codexImageToolIcon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;color:var(--dsw-alias-label-secondary)}.codexImageToolIcon::before{content:'';width:8px;height:8px;border:1.5px solid currentColor;border-radius:3px}.codexImageTool[data-state=running] .codexImageToolIcon::before{border-radius:50%;border-right-color:transparent;animation:codexImageSpin 800ms linear infinite}.codexImageTool[data-state=error] .codexImageToolIcon::before{border-color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-state-error-primary)}.codexImageToolTitle{font-weight:500}.codexImageToolState{color:var(--dsw-alias-label-tertiary)}.codexImageToolError{margin:0 0 0 24px;font-size:12px;line-height:18px;color:var(--dsw-alias-state-error-primary)}.codexImageToolGallery{margin-left:24px}.codexGeneratedImageFrame{display:flex;align-items:center;justify-content:center;width:min(240px,100%);min-height:120px;padding:0;overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-tertiary);cursor:pointer}.codexGeneratedImageFrame img{display:block;width:100%;max-height:240px;object-fit:contain}.codexGeneratedImageRetry{min-height:36px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);cursor:pointer}.codexGeneratedImageLightbox{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;padding:32px;border:0;background:rgba(0,0,0,.72)}.codexGeneratedImageLightbox img{display:block;max-width:min(1100px,calc(100vw - 64px));max-height:calc(100vh -
|
|
398
|
+
.codexImageTool{display:flex;flex-direction:column;gap:8px;margin:4px 0;color:var(--dsw-alias-label-primary)}.codexImageToolRow{display:flex;align-items:center;min-height:24px;gap:8px;font-size:13px;line-height:20px}.codexImageToolIcon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;color:var(--dsw-alias-label-secondary)}.codexImageToolIcon::before{content:'';width:8px;height:8px;border:1.5px solid currentColor;border-radius:3px}.codexImageTool[data-state=running] .codexImageToolIcon::before{border-radius:50%;border-right-color:transparent;animation:codexImageSpin 800ms linear infinite}.codexImageTool[data-state=error] .codexImageToolIcon::before{border-color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-state-error-primary)}.codexImageToolTitle{font-weight:500}.codexImageToolState{color:var(--dsw-alias-label-tertiary)}.codexImageToolError{margin:0 0 0 24px;font-size:12px;line-height:18px;color:var(--dsw-alias-state-error-primary)}.codexImageToolGallery{margin-left:24px}.codexGeneratedImageFrame{display:flex;align-items:center;justify-content:center;width:min(240px,100%);min-height:120px;padding:0;overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-tertiary);cursor:pointer}.codexGeneratedImageFrame img{display:block;width:100%;max-height:240px;object-fit:contain}.codexGeneratedImageRetry{min-height:36px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);cursor:pointer}.codexGeneratedImageLightbox{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;padding:32px;border:0;background:rgba(0,0,0,.72)}.codexGeneratedImageLightbox img{display:block;max-width:min(1100px,calc(100vw - 64px));max-height:calc(100vh - 112px);object-fit:contain}.codexGeneratedImageClose{position:absolute;top:16px;right:16px;width:36px;height:36px;border:1px solid rgba(255,255,255,.35);border-radius:50%;background:rgba(0,0,0,.48);color:#fff;font-size:20px;line-height:1;cursor:pointer}.codexGeneratedImageActions{position:absolute;left:50%;bottom:18px;transform:translateX(-50%);display:flex;align-items:center;gap:10px;max-width:min(90vw,720px);padding:6px 8px 6px 12px;border:1px solid rgba(255,255,255,.2);border-radius:999px;background:rgba(20,20,20,.82);color:rgba(255,255,255,.72);font-size:12px;line-height:18px;backdrop-filter:blur(12px)}.codexGeneratedImageDownload{flex:0 0 auto;padding:5px 10px;border-radius:999px;background:rgba(255,255,255,.12);color:#fff;text-decoration:none;white-space:nowrap}.codexGeneratedImageDownload:hover{background:rgba(255,255,255,.2)}.codexGeneratedImageDownload:focus-visible,.codexGeneratedImageClose:focus-visible{outline:2px solid #fff;outline-offset:2px}.codexGeneratedImageRefineHint{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@keyframes codexImageSpin{to{transform:rotate(360deg)}}
|
|
392
399
|
@container (max-width:560px){.codexSubscriptionCreditRows{grid-template-columns:1fr}}
|
|
393
400
|
@container (max-width:480px){.codexSubscriptionAccountRow,.codexSubscriptionSectionHead{align-items:flex-start;flex-direction:column}.codexSubscriptionActions{width:100%}.codexSubscriptionSearchChoices{grid-template-columns:1fr}}
|
|
394
401
|
@media(max-width:640px){.codexSubscriptionCard{padding:14px}}
|
|
@@ -413,12 +420,20 @@ window.__ModuleLoader__.load({
|
|
|
413
420
|
const date = new Date(value);
|
|
414
421
|
return Number.isFinite(date.getTime()) ? date : void 0;
|
|
415
422
|
};
|
|
423
|
+
const imageDownloadName = (attachment) => {
|
|
424
|
+
const fallback = "codex-generated-image.png";
|
|
425
|
+
if (typeof attachment?.name !== "string") return fallback;
|
|
426
|
+
const cleaned = attachment.name.replace(/[<>:"/\\|?*\u0000-\u001f]/gu, "-").replace(/[. ]+$/u, "").trim();
|
|
427
|
+
if (cleaned === "") return fallback;
|
|
428
|
+
return cleaned.toLowerCase().endsWith(".png") ? cleaned : `${cleaned}.png`;
|
|
429
|
+
};
|
|
416
430
|
function CodexGeneratedImage({ attachment, loadImage, t }) {
|
|
417
431
|
const [attempt, setAttempt] = (0, react.useState)(0);
|
|
418
432
|
const [error, setError] = (0, react.useState)(false);
|
|
419
433
|
const [open, setOpen] = (0, react.useState)(false);
|
|
420
434
|
const [src, setSrc] = (0, react.useState)();
|
|
421
435
|
const closeRef = (0, react.useRef)(null);
|
|
436
|
+
const downloadRef = (0, react.useRef)(null);
|
|
422
437
|
const triggerRef = (0, react.useRef)(null);
|
|
423
438
|
(0, react.useEffect)(() => {
|
|
424
439
|
let live = true;
|
|
@@ -445,7 +460,9 @@ window.__ModuleLoader__.load({
|
|
|
445
460
|
setOpen(false);
|
|
446
461
|
} else if (event.key === "Tab") {
|
|
447
462
|
event.preventDefault();
|
|
448
|
-
closeRef.current
|
|
463
|
+
const controls = [downloadRef.current, closeRef.current].filter(Boolean);
|
|
464
|
+
const current = controls.indexOf(document.activeElement);
|
|
465
|
+
controls[event.shiftKey ? current <= 0 ? controls.length - 1 : current - 1 : (current + 1) % controls.length]?.focus();
|
|
449
466
|
}
|
|
450
467
|
};
|
|
451
468
|
document.addEventListener("keydown", handleKeyDown);
|
|
@@ -456,6 +473,7 @@ window.__ModuleLoader__.load({
|
|
|
456
473
|
};
|
|
457
474
|
}, [open]);
|
|
458
475
|
const label = attachment.name ?? t("imageLabel");
|
|
476
|
+
const downloadName = imageDownloadName(attachment);
|
|
459
477
|
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
460
478
|
type: "button",
|
|
461
479
|
className: "codexGeneratedImageRetry",
|
|
@@ -481,18 +499,35 @@ window.__ModuleLoader__.load({
|
|
|
481
499
|
"aria-modal": "true",
|
|
482
500
|
"aria-label": t("imagePreview"),
|
|
483
501
|
onClick: () => setOpen(false),
|
|
484
|
-
children: [
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
502
|
+
children: [
|
|
503
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
504
|
+
src,
|
|
505
|
+
alt: label,
|
|
506
|
+
onClick: (event) => event.stopPropagation()
|
|
507
|
+
}),
|
|
508
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
509
|
+
className: "codexGeneratedImageActions",
|
|
510
|
+
onClick: (event) => event.stopPropagation(),
|
|
511
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
512
|
+
className: "codexGeneratedImageRefineHint",
|
|
513
|
+
children: t("imageRefineHint")
|
|
514
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
515
|
+
ref: downloadRef,
|
|
516
|
+
className: "codexGeneratedImageDownload",
|
|
517
|
+
href: src,
|
|
518
|
+
download: downloadName,
|
|
519
|
+
children: t("imageDownload")
|
|
520
|
+
})]
|
|
521
|
+
}),
|
|
522
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
523
|
+
ref: closeRef,
|
|
524
|
+
type: "button",
|
|
525
|
+
className: "codexGeneratedImageClose",
|
|
526
|
+
"aria-label": t("imageClosePreview"),
|
|
527
|
+
onClick: () => setOpen(false),
|
|
528
|
+
children: "×"
|
|
529
|
+
})
|
|
530
|
+
]
|
|
496
531
|
})] });
|
|
497
532
|
}
|
|
498
533
|
function CodexImageToolRow({ block, loadImage, t }) {
|
|
@@ -1311,18 +1346,28 @@ window.__ModuleLoader__.load({
|
|
|
1311
1346
|
})]
|
|
1312
1347
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1313
1348
|
className: "codexSubscriptionActions",
|
|
1314
|
-
children: [
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1349
|
+
children: [
|
|
1350
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1351
|
+
type: "button",
|
|
1352
|
+
variant: "outline",
|
|
1353
|
+
disabled: busy,
|
|
1354
|
+
onClick: load,
|
|
1355
|
+
children: t("diagnosticsLoad")
|
|
1356
|
+
}),
|
|
1357
|
+
report === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1358
|
+
type: "button",
|
|
1359
|
+
variant: "outline",
|
|
1360
|
+
onClick: copy,
|
|
1361
|
+
children: copied ? t("diagnosticsCopied") : t("diagnosticsCopy")
|
|
1362
|
+
}),
|
|
1363
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
1364
|
+
className: "codexSubscriptionLink",
|
|
1365
|
+
href: SUPPORT_ISSUE_URL,
|
|
1366
|
+
target: "_blank",
|
|
1367
|
+
rel: "noreferrer",
|
|
1368
|
+
children: t("feedbackOpen")
|
|
1369
|
+
})
|
|
1370
|
+
]
|
|
1326
1371
|
})]
|
|
1327
1372
|
}),
|
|
1328
1373
|
report === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: JSON.stringify(report, null, 2) }),
|
|
@@ -1349,11 +1394,21 @@ window.__ModuleLoader__.load({
|
|
|
1349
1394
|
children: fill(t("resets"), { value })
|
|
1350
1395
|
});
|
|
1351
1396
|
}
|
|
1352
|
-
function
|
|
1397
|
+
function ResetCreditExpiry({ expiresAt, t }) {
|
|
1398
|
+
const date = validDate(expiresAt);
|
|
1399
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1400
|
+
className: "codexSubscriptionResetExpiry",
|
|
1401
|
+
children: date === void 0 ? t("resetCreditExpiryUnknown") : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("time", {
|
|
1402
|
+
dateTime: date.toISOString(),
|
|
1403
|
+
title: date.toLocaleString(),
|
|
1404
|
+
children: fill(t("resetCreditExpires"), { value: date.toLocaleString() })
|
|
1405
|
+
})
|
|
1406
|
+
});
|
|
1407
|
+
}
|
|
1408
|
+
function ResetCreditControl({ rpc, t, count, nextExpiresAt, hasExhaustedQuota, onConsumed }) {
|
|
1353
1409
|
const [challenge, setChallenge] = (0, react.useState)();
|
|
1354
1410
|
const [resetBusy, setResetBusy] = (0, react.useState)(false);
|
|
1355
1411
|
const [resetAcknowledged, setResetAcknowledged] = (0, react.useState)(false);
|
|
1356
|
-
const [resetPhrase, setResetPhrase] = (0, react.useState)("");
|
|
1357
1412
|
const [resetCountdown, setResetCountdown] = (0, react.useState)(0);
|
|
1358
1413
|
const [resetError, setResetError] = (0, react.useState)();
|
|
1359
1414
|
const [resetResult, setResetResult] = (0, react.useState)();
|
|
@@ -1368,24 +1423,22 @@ window.__ModuleLoader__.load({
|
|
|
1368
1423
|
return () => window.clearInterval(timer);
|
|
1369
1424
|
}, [challenge]);
|
|
1370
1425
|
const prepareReset = () => {
|
|
1371
|
-
if (resetBusy
|
|
1426
|
+
if (resetBusy) return;
|
|
1372
1427
|
setResetBusy(true);
|
|
1373
1428
|
setResetError(void 0);
|
|
1374
1429
|
setResetResult(void 0);
|
|
1375
1430
|
rpc.call(CHANNEL, "reset-credit/prepare", {}).then(unwrap).then((next) => {
|
|
1376
1431
|
setChallenge(next);
|
|
1377
1432
|
setResetAcknowledged(false);
|
|
1378
|
-
setResetPhrase("");
|
|
1379
1433
|
}).catch((error) => setResetError(resetCreditErrorText(error, t))).finally(() => setResetBusy(false));
|
|
1380
1434
|
};
|
|
1381
1435
|
const cancelReset = () => {
|
|
1382
1436
|
if (resetBusy) return;
|
|
1383
1437
|
setChallenge(void 0);
|
|
1384
1438
|
setResetAcknowledged(false);
|
|
1385
|
-
setResetPhrase("");
|
|
1386
1439
|
setResetError(void 0);
|
|
1387
1440
|
};
|
|
1388
|
-
const resetReady = challenge !== void 0 && resetAcknowledged &&
|
|
1441
|
+
const resetReady = challenge !== void 0 && resetAcknowledged && resetCountdown === 0;
|
|
1389
1442
|
const consumeReset = () => {
|
|
1390
1443
|
if (resetBusy) return;
|
|
1391
1444
|
if (!resetReady) return;
|
|
@@ -1394,11 +1447,10 @@ window.__ModuleLoader__.load({
|
|
|
1394
1447
|
setResetResult(void 0);
|
|
1395
1448
|
rpc.call(CHANNEL, "reset-credit/consume", {
|
|
1396
1449
|
challengeId: challenge.challengeId,
|
|
1397
|
-
|
|
1450
|
+
acknowledged: resetAcknowledged
|
|
1398
1451
|
}).then(unwrap).then((result) => {
|
|
1399
1452
|
setChallenge(void 0);
|
|
1400
1453
|
setResetAcknowledged(false);
|
|
1401
|
-
setResetPhrase("");
|
|
1402
1454
|
const message = result.code === "reset" ? t("resetSuccess") : result.code === "nothing_to_reset" ? t("resetNothing") : result.code === "no_credit" ? t("resetNoCredit") : t("resetAlready");
|
|
1403
1455
|
setResetResult(message);
|
|
1404
1456
|
onConsumed();
|
|
@@ -1409,14 +1461,19 @@ window.__ModuleLoader__.load({
|
|
|
1409
1461
|
children: [
|
|
1410
1462
|
challenge === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1411
1463
|
className: "codexSubscriptionResetSummary",
|
|
1412
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1464
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1465
|
+
className: "codexSubscriptionResetMeta",
|
|
1466
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: fill(t("resetCreditsValue"), { count }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditExpiry, {
|
|
1467
|
+
expiresAt: nextExpiresAt,
|
|
1468
|
+
t
|
|
1469
|
+
})]
|
|
1470
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1413
1471
|
className: "codexSubscriptionActions",
|
|
1414
1472
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1415
1473
|
type: "button",
|
|
1416
1474
|
variant: "outline",
|
|
1417
|
-
disabled:
|
|
1475
|
+
disabled: resetBusy,
|
|
1418
1476
|
"aria-busy": resetBusy,
|
|
1419
|
-
title: !exhausted ? t("resetUnavailable") : void 0,
|
|
1420
1477
|
onClick: prepareReset,
|
|
1421
1478
|
children: resetBusy ? t("resetPreparing") : t("resetUse")
|
|
1422
1479
|
})
|
|
@@ -1434,9 +1491,13 @@ window.__ModuleLoader__.load({
|
|
|
1434
1491
|
className: "codexSubscriptionResetWarning",
|
|
1435
1492
|
children: challenge.description
|
|
1436
1493
|
}) : null,
|
|
1494
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditExpiry, {
|
|
1495
|
+
expiresAt: challenge.creditExpiresAt,
|
|
1496
|
+
t
|
|
1497
|
+
}),
|
|
1437
1498
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1438
1499
|
className: "codexSubscriptionResetWarning",
|
|
1439
|
-
children: t("resetWarning")
|
|
1500
|
+
children: t(hasExhaustedQuota ? "resetWarning" : "resetEarlyWarning")
|
|
1440
1501
|
}),
|
|
1441
1502
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1442
1503
|
className: "codexSubscriptionResetCheck",
|
|
@@ -1447,20 +1508,6 @@ window.__ModuleLoader__.load({
|
|
|
1447
1508
|
onChange: (event) => setResetAcknowledged(event.target.checked)
|
|
1448
1509
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetAcknowledge") })]
|
|
1449
1510
|
}),
|
|
1450
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1451
|
-
className: "codexSubscriptionPreferenceCopy",
|
|
1452
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1453
|
-
className: "codexSubscriptionCreditLabel",
|
|
1454
|
-
children: fill(t("resetTypeHint"), { phrase: challenge.confirmPhrase })
|
|
1455
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
1456
|
-
className: "codexSubscriptionInput codexSubscriptionResetPhrase",
|
|
1457
|
-
value: resetPhrase,
|
|
1458
|
-
disabled: resetBusy,
|
|
1459
|
-
autoComplete: "off",
|
|
1460
|
-
spellCheck: false,
|
|
1461
|
-
onChange: (event) => setResetPhrase(event.target.value)
|
|
1462
|
-
})]
|
|
1463
|
-
}),
|
|
1464
1511
|
resetCountdown > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1465
1512
|
className: "codexSubscriptionCreditNote",
|
|
1466
1513
|
role: "status",
|
|
@@ -1509,8 +1556,7 @@ window.__ModuleLoader__.load({
|
|
|
1509
1556
|
["This quota reset confirmation is no longer valid", "resetExpired"],
|
|
1510
1557
|
["This quota reset is already in progress", "resetInProgress"],
|
|
1511
1558
|
["Wait before confirming this quota reset", "resetTooEarly"],
|
|
1512
|
-
["
|
|
1513
|
-
["The current Codex quota is not exhausted", "resetNotExhausted"],
|
|
1559
|
+
["You must acknowledge that this may consume one quota reset", "resetAcknowledgeRequired"],
|
|
1514
1560
|
["The signed-in ChatGPT account changed", "resetAccountChanged"]
|
|
1515
1561
|
])).get(error instanceof Error ? error.message : "") ?? "resetFailed");
|
|
1516
1562
|
}
|
|
@@ -1648,7 +1694,8 @@ window.__ModuleLoader__.load({
|
|
|
1648
1694
|
rpc,
|
|
1649
1695
|
t,
|
|
1650
1696
|
count: visibleUsage.resetCredits.availableCount,
|
|
1651
|
-
|
|
1697
|
+
nextExpiresAt: visibleUsage.resetCredits.nextExpiresAt,
|
|
1698
|
+
hasExhaustedQuota: exhausted,
|
|
1652
1699
|
onConsumed: () => load(true)
|
|
1653
1700
|
})]
|
|
1654
1701
|
}) : null,
|
package/lib/index.js
CHANGED
|
@@ -503,7 +503,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0 } = {
|
|
|
503
503
|
}
|
|
504
504
|
//#endregion
|
|
505
505
|
//#region src/version.js
|
|
506
|
-
const PACKAGE_VERSION = "1.
|
|
506
|
+
const PACKAGE_VERSION = "1.5.0";
|
|
507
507
|
const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
|
|
508
508
|
//#endregion
|
|
509
509
|
//#region src/codex-search.js
|
|
@@ -948,7 +948,18 @@ function spendControlReachedOf(value) {
|
|
|
948
948
|
function resetCreditsOf(value) {
|
|
949
949
|
if (value === void 0 || value === null) return void 0;
|
|
950
950
|
if (!record$1(value) || !Number.isSafeInteger(value.available_count) || value.available_count < 0) throw new Error("Codex returned malformed reset credit details");
|
|
951
|
-
|
|
951
|
+
if (value.credits !== void 0 && value.credits !== null && !Array.isArray(value.credits)) throw new Error("Codex returned malformed reset credit details");
|
|
952
|
+
const expirations = (value.credits ?? []).filter((credit) => record$1(credit) && credit.status?.toLowerCase?.() === "available").map((credit) => {
|
|
953
|
+
if (Number.isSafeInteger(credit.expires_at) && credit.expires_at > 0) return credit.expires_at * 1e3;
|
|
954
|
+
if (typeof credit.expires_at === "string" && credit.expires_at.length <= 64) {
|
|
955
|
+
const parsed = Date.parse(credit.expires_at);
|
|
956
|
+
if (Number.isFinite(parsed) && parsed > 0) return parsed;
|
|
957
|
+
}
|
|
958
|
+
}).filter((expiration) => expiration !== void 0);
|
|
959
|
+
return {
|
|
960
|
+
availableCount: value.available_count,
|
|
961
|
+
...expirations.length === 0 ? {} : { nextExpiresAt: Math.min(...expirations) }
|
|
962
|
+
};
|
|
952
963
|
}
|
|
953
964
|
/** Reduce the provider payload to a browser-safe quota projection. */
|
|
954
965
|
function parseCodexUsage(value) {
|
|
@@ -1054,7 +1065,6 @@ function createCodexUsageReader(options) {
|
|
|
1054
1065
|
//#region src/reset-credits.js
|
|
1055
1066
|
const CODEX_RESET_CREDITS_URL = "https://chatgpt.com/backend-api/wham/rate-limit-reset-credits";
|
|
1056
1067
|
const CODEX_RESET_CONSUME_URL = `${CODEX_RESET_CREDITS_URL}/consume`;
|
|
1057
|
-
const RESET_CONFIRM_PHRASE = "USE RESET";
|
|
1058
1068
|
const DEFAULT_CONFIRM_DELAY_MS = 5e3;
|
|
1059
1069
|
const DEFAULT_CHALLENGE_TTL_MS = 6e4;
|
|
1060
1070
|
const DEFAULT_TIMEOUT_MS = 15e3;
|
|
@@ -1076,15 +1086,22 @@ function credentialsOf(auth, credential) {
|
|
|
1076
1086
|
accountId
|
|
1077
1087
|
};
|
|
1078
1088
|
}
|
|
1089
|
+
function expirationOf(value) {
|
|
1090
|
+
if (value === void 0 || value === null) return void 0;
|
|
1091
|
+
if (Number.isSafeInteger(value) && value > 0) return value * 1e3;
|
|
1092
|
+
if (typeof value === "string" && value.length > 0 && value.length <= 64) {
|
|
1093
|
+
const parsed = Date.parse(value);
|
|
1094
|
+
if (Number.isFinite(parsed) && parsed > 0) return parsed;
|
|
1095
|
+
}
|
|
1096
|
+
throw new Error("ChatGPT returned malformed quota reset details");
|
|
1097
|
+
}
|
|
1079
1098
|
function parseDetails(value, now) {
|
|
1080
1099
|
if (!record(value) || !Number.isSafeInteger(value.available_count) || value.available_count < 0 || !Array.isArray(value.credits)) throw new Error("ChatGPT returned malformed quota reset details");
|
|
1081
1100
|
if (value.available_count === 0) throw new Error("No quota reset is available");
|
|
1082
1101
|
const available = value.credits.filter((credit) => record(credit) && typeof credit.id === "string" && credit.id.length > 0 && credit.id.length <= 256 && typeof credit.status === "string" && credit.status.toLowerCase() === "available").map((credit) => {
|
|
1083
|
-
const expiresAt = credit.expires_at === void 0 || credit.expires_at === null ? void 0 : credit.expires_at * 1e3;
|
|
1084
|
-
if (expiresAt !== void 0 && (!Number.isSafeInteger(credit.expires_at) || credit.expires_at <= 0)) throw new Error("ChatGPT returned malformed quota reset details");
|
|
1085
1102
|
return {
|
|
1086
1103
|
credit,
|
|
1087
|
-
expiresAt
|
|
1104
|
+
expiresAt: expirationOf(credit.expires_at)
|
|
1088
1105
|
};
|
|
1089
1106
|
}).filter(({ expiresAt }) => expiresAt === void 0 || expiresAt > now).sort((a, b) => (a.expiresAt ?? Number.MAX_SAFE_INTEGER) - (b.expiresAt ?? Number.MAX_SAFE_INTEGER));
|
|
1090
1107
|
if (available.length === 0) throw new Error("No usable quota reset is available");
|
|
@@ -1104,14 +1121,13 @@ function parseConsumeResult(value) {
|
|
|
1104
1121
|
"already_redeemed"
|
|
1105
1122
|
].includes(value.code)) throw new Error("ChatGPT returned an unreadable quota reset response");
|
|
1106
1123
|
const windowsReset = Array.isArray(value.windows_reset) ? value.windows_reset.filter((item) => typeof item === "string").slice(0, 16) : [];
|
|
1124
|
+
const windowsResetCount = Number.isSafeInteger(value.windows_reset) && value.windows_reset >= 0 && value.windows_reset <= 16 ? value.windows_reset : void 0;
|
|
1107
1125
|
return {
|
|
1108
1126
|
code: value.code,
|
|
1109
|
-
windowsReset
|
|
1127
|
+
windowsReset,
|
|
1128
|
+
...windowsResetCount === void 0 ? {} : { windowsResetCount }
|
|
1110
1129
|
};
|
|
1111
1130
|
}
|
|
1112
|
-
function quotaIsExhausted(usage) {
|
|
1113
|
-
return Array.isArray(usage?.rateLimits) && usage.rateLimits.some((limit) => limit?.id !== "code_review" && Array.isArray(limit?.windows) && limit.windows.some((window) => Number.isFinite(window?.usedPercent) && window.usedPercent >= 100));
|
|
1114
|
-
}
|
|
1115
1131
|
/**
|
|
1116
1132
|
* Host-only reset redemption. The browser receives an opaque, short-lived
|
|
1117
1133
|
* challenge; account ids, bearer tokens, credit ids, and idempotency keys stay
|
|
@@ -1168,14 +1184,14 @@ function createCodexResetCreditService(options) {
|
|
|
1168
1184
|
return {
|
|
1169
1185
|
challengeId,
|
|
1170
1186
|
availableCount: details.availableCount,
|
|
1171
|
-
confirmPhrase: RESET_CONFIRM_PHRASE,
|
|
1172
1187
|
readyAt,
|
|
1173
1188
|
expiresAt,
|
|
1189
|
+
...details.creditExpiresAt === void 0 ? {} : { creditExpiresAt: details.creditExpiresAt },
|
|
1174
1190
|
...details.title === void 0 ? {} : { title: details.title },
|
|
1175
1191
|
...details.description === void 0 ? {} : { description: details.description }
|
|
1176
1192
|
};
|
|
1177
1193
|
},
|
|
1178
|
-
async consume({ challengeId,
|
|
1194
|
+
async consume({ challengeId, acknowledged, signal } = {}) {
|
|
1179
1195
|
const challenge = typeof challengeId === "string" ? challenges.get(challengeId) : void 0;
|
|
1180
1196
|
if (challenge === void 0) throw new Error("This quota reset confirmation is no longer valid");
|
|
1181
1197
|
if (challenge.state === "pending") throw new Error("This quota reset is already in progress");
|
|
@@ -1184,13 +1200,9 @@ function createCodexResetCreditService(options) {
|
|
|
1184
1200
|
challenges.delete(challengeId);
|
|
1185
1201
|
throw new Error("This quota reset confirmation is no longer valid");
|
|
1186
1202
|
}
|
|
1187
|
-
if (
|
|
1203
|
+
if (acknowledged !== true) throw new Error("You must acknowledge that this may consume one quota reset");
|
|
1188
1204
|
challenge.state = "pending";
|
|
1189
1205
|
try {
|
|
1190
|
-
if (!quotaIsExhausted(await usageReader.read({
|
|
1191
|
-
force: true,
|
|
1192
|
-
signal
|
|
1193
|
-
}))) throw new Error("The current Codex quota is not exhausted");
|
|
1194
1206
|
const { access, accountId } = await resolveCredentials(signal);
|
|
1195
1207
|
if (accountId !== challenge.accountId) throw new Error("The signed-in ChatGPT account changed");
|
|
1196
1208
|
const response = await fetchReset(CODEX_RESET_CONSUME_URL, {
|
|
@@ -1323,7 +1335,7 @@ function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditSer
|
|
|
1323
1335
|
ok: true,
|
|
1324
1336
|
value: endpoint === "reset-credit/prepare" ? await resetCreditService.prepare({ signal }) : await resetCreditService.consume({
|
|
1325
1337
|
challengeId: payload?.challengeId,
|
|
1326
|
-
|
|
1338
|
+
acknowledged: payload?.acknowledged,
|
|
1327
1339
|
signal
|
|
1328
1340
|
})
|
|
1329
1341
|
};
|
|
@@ -1338,8 +1350,7 @@ function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditSer
|
|
|
1338
1350
|
"This quota reset confirmation is no longer valid",
|
|
1339
1351
|
"This quota reset is already in progress",
|
|
1340
1352
|
"Wait before confirming this quota reset",
|
|
1341
|
-
"
|
|
1342
|
-
"The current Codex quota is not exhausted",
|
|
1353
|
+
"You must acknowledge that one quota reset will be consumed",
|
|
1343
1354
|
"The signed-in ChatGPT account changed"
|
|
1344
1355
|
]);
|
|
1345
1356
|
const fallback = endpoint === "reset-credit/prepare" ? "Could not prepare a quota reset" : "Could not use the quota reset";
|
|
@@ -1483,4 +1494,4 @@ function apply(ctx) {
|
|
|
1483
1494
|
ctx.effect(() => ctx.connection.rpc.handle(CHANNEL, handler, { authority: "loopback" }), "codex-subscription: loopback account RPC");
|
|
1484
1495
|
}
|
|
1485
1496
|
//#endregion
|
|
1486
|
-
export { CODEX_IMAGE_GENERATION_URL, CODEX_IMAGE_TOOL_NAME, CODEX_RESET_CONSUME_URL, CODEX_RESET_CREDITS_URL, CODEX_USAGE_URL, CodexLoginCoordinator, DshOAuthCredentialStore,
|
|
1497
|
+
export { CODEX_IMAGE_GENERATION_URL, CODEX_IMAGE_TOOL_NAME, CODEX_RESET_CONSUME_URL, CODEX_RESET_CREDITS_URL, CODEX_USAGE_URL, CodexLoginCoordinator, DshOAuthCredentialStore, apply, assertCodexAuthUrl, commandForCodexAuthUrl, createCodexAuthService, createCodexImageTool, createCodexResetCreditService, createCodexRpcHandler, createCodexUsageReader, createSearchProviderSwitcher, createSubscriptionDiagnostics, createSubscriptionRpcHandler, decodeCodexPng, inject, name, openCodexAuthUrl, parseCodexUsage };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codex-subscription",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Use ChatGPT and Codex subscriptions in DeepSeek Harness with OAuth, quota, safe resets, web search, images, and Fast mode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|