dsh-codex-subscription 1.0.6 → 1.1.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 +22 -13
- package/README.en.md +39 -13
- package/README.md +38 -12
- package/lib/client.js +143 -35
- package/lib/index.js +42 -11
- 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.0
|
|
9
|
+
- Use the exact `1.1.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.
|
|
@@ -18,6 +18,7 @@ On Windows, check the command and common Portable entry points without recursive
|
|
|
18
18
|
|
|
19
19
|
```powershell
|
|
20
20
|
Get-Command dsh -ErrorAction SilentlyContinue
|
|
21
|
+
Get-Command npx -ErrorAction SilentlyContinue
|
|
21
22
|
Test-Path -LiteralPath '.\dsh.exe' -PathType Leaf
|
|
22
23
|
Test-Path -LiteralPath "$env:USERPROFILE\Downloads\DSH-Portable\dsh.exe" -PathType Leaf
|
|
23
24
|
```
|
|
@@ -28,28 +29,29 @@ instead of recreating its package-manager environment in this installer.
|
|
|
28
29
|
|
|
29
30
|
## Install or update
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
For an official DSH installation run through npm, keep the complete `npx` prefix because the official
|
|
33
|
+
run command does not create a global `dsh` command:
|
|
32
34
|
|
|
33
35
|
```sh
|
|
34
|
-
dsh plugin --profile web add dsh-codex-subscription@1.0
|
|
36
|
+
npx -y @deepseek-ai/dsh plugin --profile web add dsh-codex-subscription@1.1.0
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
With an existing global `dsh` command:
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
dsh plugin --profile web add dsh-codex-subscription@1.1.0
|
|
35
43
|
```
|
|
36
44
|
|
|
37
45
|
From a DSH-Portable folder:
|
|
38
46
|
|
|
39
47
|
```powershell
|
|
40
|
-
.\dsh.exe plugin --profile web add dsh-codex-subscription@1.0
|
|
48
|
+
.\dsh.exe plugin --profile web add dsh-codex-subscription@1.1.0
|
|
41
49
|
```
|
|
42
50
|
|
|
43
51
|
Use the same `add` command to update or repair. This is the complete package-changing operation.
|
|
44
52
|
Do not download pnpm, create a second package store, save profile snapshots, add a resident manager,
|
|
45
53
|
or restart DSH automatically. The DSH CLI owns package resolution, locking, and profile composition.
|
|
46
54
|
|
|
47
|
-
For a legacy installation, first add and verify the current package. Only then remove the old package:
|
|
48
|
-
|
|
49
|
-
```sh
|
|
50
|
-
dsh plugin --profile web remove @wsl043/dsh-codex-subscription
|
|
51
|
-
```
|
|
52
|
-
|
|
53
55
|
## Verify
|
|
54
56
|
|
|
55
57
|
Use the same executable selected above:
|
|
@@ -61,10 +63,11 @@ dsh --profile web --dump-config
|
|
|
61
63
|
|
|
62
64
|
For DSH-Portable, replace `dsh` with `.\dsh.exe`. Static acceptance requires:
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
For the official npm route, run the same checks with `npx -y @deepseek-ai/dsh` in place of `dsh`.
|
|
67
|
+
|
|
68
|
+
1. `dsh-codex-subscription` version `1.1.0` appears exactly once.
|
|
65
69
|
2. `codex-subscription` appears exactly once in the composed config.
|
|
66
|
-
3.
|
|
67
|
-
4. No unrelated plugin or profile was changed and DSH was not restarted.
|
|
70
|
+
3. No unrelated plugin or profile was changed and DSH was not restarted.
|
|
68
71
|
|
|
69
72
|
With permission to restart DSH, open **Settings -> Codex** and verify the settings page loads. Confirm
|
|
70
73
|
that search offers both **DSH default** and **Codex subscription**, the composer quota switch defaults
|
|
@@ -83,6 +86,12 @@ For DSH-Portable:
|
|
|
83
86
|
.\dsh.exe plugin --profile web remove dsh-codex-subscription
|
|
84
87
|
```
|
|
85
88
|
|
|
89
|
+
For the official npm route:
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
npx -y @deepseek-ai/dsh plugin --profile web remove dsh-codex-subscription
|
|
93
|
+
```
|
|
94
|
+
|
|
86
95
|
Uninstall removes only this plugin. It must preserve the profile, sessions, other plugins, and saved
|
|
87
96
|
ChatGPT sign-in. Signing out is a separate action and requires explicit permission.
|
|
88
97
|
|
package/README.en.md
CHANGED
|
@@ -8,6 +8,7 @@ No OpenAI API key or Codex CLI. Models, search, quota, and image generation stay
|
|
|
8
8
|
|
|
9
9
|
[](https://github.com/WSL043/dsh-codex-subscription/actions/workflows/ci.yml)
|
|
10
10
|
[](https://www.npmjs.com/package/dsh-codex-subscription)
|
|
11
|
+
[](https://www.npmjs.com/package/dsh-codex-subscription)
|
|
11
12
|
[](LICENSE)
|
|
12
13
|
[](https://github.com/WSL043/dsh-codex-subscription/stargazers)
|
|
13
14
|
|
|
@@ -27,8 +28,9 @@ No OpenAI API key or Codex CLI. Models, search, quota, and image generation stay
|
|
|
27
28
|
| **Subscription models** | Sign in to ChatGPT and use Codex without an OpenAI API key or Codex CLI |
|
|
28
29
|
| **Subscription search** | Explicitly choose DSH default search or Codex subscription search |
|
|
29
30
|
| **Visible quota** | Keep backend-provided standard Codex, Spark, and other limits separate |
|
|
31
|
+
| **Fast mode (Beta)** | Switch between Standard and Fast directly in the composer |
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
These capabilities reuse the same local ChatGPT sign-in. Subscription routing failures stay visible and never silently switch to another paid route.
|
|
32
34
|
|
|
33
35
|
## Product screen
|
|
34
36
|
|
|
@@ -45,7 +47,7 @@ All four capabilities reuse the same local ChatGPT sign-in. Subscription routing
|
|
|
45
47
|
|
|
46
48
|
## Prepare DSH
|
|
47
49
|
|
|
48
|
-
This plugin
|
|
50
|
+
This plugin is currently compatible through DeepSeek Harness `0.1.0-rc.8` and requires a ChatGPT account that currently has Codex access.
|
|
49
51
|
|
|
50
52
|
- Do not want to configure Node.js? Use the [community DSH-Portable package](https://github.com/WSL043/DSH-Portable).
|
|
51
53
|
- Prefer the official route? Follow the [DeepSeek Harness run guide](https://github.com/deepseek-ai/deepseek-harness#run).
|
|
@@ -78,7 +80,20 @@ operation once. It does not recursively scan disks, install pnpm, create a resid
|
|
|
78
80
|
profile, or download the plugin twice. It needs no administrator access and never restarts DSH.
|
|
79
81
|
|
|
80
82
|
<details>
|
|
81
|
-
<summary>
|
|
83
|
+
<summary>Official npm route (Node.js installed)</summary>
|
|
84
|
+
|
|
85
|
+
The official `npx @deepseek-ai/dsh web` command does not create a global `dsh` command. Keep the full `npx` prefix when installing the plugin:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
npx -y @deepseek-ai/dsh plugin --profile web add dsh-codex-subscription
|
|
89
|
+
npx -y @deepseek-ai/dsh plugin --profile web list dsh-codex-subscription --depth 0
|
|
90
|
+
npx -y @deepseek-ai/dsh --profile web --dump-config
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
</details>
|
|
94
|
+
|
|
95
|
+
<details>
|
|
96
|
+
<summary>An existing <code>dsh</code> command or a DSH-Portable folder</summary>
|
|
82
97
|
|
|
83
98
|
```sh
|
|
84
99
|
dsh plugin --profile web add dsh-codex-subscription
|
|
@@ -86,8 +101,8 @@ dsh plugin --profile web list dsh-codex-subscription --depth 0
|
|
|
86
101
|
dsh --profile web --dump-config
|
|
87
102
|
```
|
|
88
103
|
|
|
89
|
-
|
|
90
|
-
`codex-subscription` entry.
|
|
104
|
+
For DSH-Portable, replace `dsh` with `./dsh` (`.\dsh.exe` in PowerShell). The plugin list should contain
|
|
105
|
+
one `dsh-codex-subscription`, and the config should contain one `codex-subscription` entry.
|
|
91
106
|
|
|
92
107
|
</details>
|
|
93
108
|
|
|
@@ -106,6 +121,7 @@ Restart DSH manually after installation, then:
|
|
|
106
121
|
- Actual backend-provided quota, reset time, and freshness;
|
|
107
122
|
- Separate standard Codex, Codex-Spark, Credits, and other independent limits;
|
|
108
123
|
- Optional composer quota for the selected Codex model (Beta, off by default);
|
|
124
|
+
- Standard or Fast mode for supported Codex models directly in the composer (Beta);
|
|
109
125
|
- Visible errors when subscription routing is unavailable, with no silent paid fallback.
|
|
110
126
|
|
|
111
127
|
### Composer quota
|
|
@@ -118,10 +134,24 @@ The compact percentage appears only for a selected Codex model. Standard Codex u
|
|
|
118
134
|
window returned by the service; Spark uses its independent quota. The plugin does not hard-code a
|
|
119
135
|
“5-hour + weekly” layout or invent Credits and spending caps that the service did not return.
|
|
120
136
|
|
|
137
|
+
### Composer speed (Beta)
|
|
138
|
+
|
|
139
|
+
With a supported Codex model selected, `1×` or a lightning icon appears immediately before the model name.
|
|
140
|
+
Click it to choose Standard or Fast. Spark does not show this control. Fast mode increases speed and uses more Credits;
|
|
141
|
+
see the [OpenAI Codex Speed documentation](https://learn.chatgpt.com/docs/agent-configuration/speed) for the current rules.
|
|
142
|
+
|
|
121
143
|
## Update and uninstall
|
|
122
144
|
|
|
123
|
-
On Windows, rerun the one-line setup above to update.
|
|
124
|
-
|
|
145
|
+
On Windows, rerun the one-line setup above to update. For the official npm route, use:
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
npx -y @deepseek-ai/dsh plugin --profile web update dsh-codex-subscription
|
|
149
|
+
npx -y @deepseek-ai/dsh plugin --profile web list dsh-codex-subscription --depth 0
|
|
150
|
+
npx -y @deepseek-ai/dsh --profile web --dump-config
|
|
151
|
+
npx -y @deepseek-ai/dsh plugin --profile web remove dsh-codex-subscription
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
These operations preserve the DSH profile, other plugins, and saved sign-in.
|
|
125
155
|
|
|
126
156
|
<details>
|
|
127
157
|
<summary>Update or uninstall with an existing <code>dsh</code> command</summary>
|
|
@@ -133,18 +163,14 @@ dsh --profile web --dump-config
|
|
|
133
163
|
dsh plugin --profile web remove dsh-codex-subscription
|
|
134
164
|
```
|
|
135
165
|
|
|
136
|
-
When migrating manually from v0.2.1, remove the old package only after the new one installs successfully:
|
|
137
|
-
|
|
138
|
-
```sh
|
|
139
|
-
dsh plugin --profile web remove @wsl043/dsh-codex-subscription
|
|
140
|
-
```
|
|
141
|
-
|
|
142
166
|
</details>
|
|
143
167
|
|
|
144
168
|
From a DSH-Portable folder, replace `dsh` above with `.\dsh.exe`.
|
|
145
169
|
|
|
146
170
|
## Troubleshooting
|
|
147
171
|
|
|
172
|
+
- **`dsh` is not recognized:** the official npm route does not create a global `dsh` command; use the complete `npx -y @deepseek-ai/dsh ...` command above;
|
|
173
|
+
- **`dsh.exe` is not recognized:** that file is not in the current folder; enter the DSH-Portable folder first or use the one-line Windows setup;
|
|
148
174
|
- **DSH-Portable is not found:** enter its folder and rerun setup, or run `.\dsh.exe plugin --profile web add dsh-codex-subscription` directly;
|
|
149
175
|
- **More than one DSH exists:** enter the intended DSH-Portable folder before running setup;
|
|
150
176
|
- **Setup still fails:** send the Agent guide above to an Agent. Do not delete the profile or change the system PATH to force an install.
|
package/README.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
[](https://github.com/WSL043/dsh-codex-subscription/actions/workflows/ci.yml)
|
|
11
11
|
[](https://www.npmjs.com/package/dsh-codex-subscription)
|
|
12
|
+
[](https://www.npmjs.com/package/dsh-codex-subscription)
|
|
12
13
|
[](LICENSE)
|
|
13
14
|
[](https://github.com/WSL043/dsh-codex-subscription/stargazers)
|
|
14
15
|
|
|
@@ -28,6 +29,7 @@
|
|
|
28
29
|
| **订阅模型直连** | 登录 ChatGPT 后直接使用 Codex,不需要 OpenAI API Key 或 Codex CLI |
|
|
29
30
|
| **订阅搜索** | 可在 DSH 默认搜索与 Codex 订阅搜索之间明确切换 |
|
|
30
31
|
| **额度可见** | 普通 Codex、Spark 等服务端实际返回的额度分开显示 |
|
|
32
|
+
| **高速模式(Beta)** | 直接在输入框切换标准或高速,无需离开当前会话 |
|
|
31
33
|
|
|
32
34
|
这些能力共用同一份本机 ChatGPT 登录。订阅路由失败时会明确报错,不会静默切换到其他付费路由。
|
|
33
35
|
|
|
@@ -46,7 +48,7 @@
|
|
|
46
48
|
|
|
47
49
|
## 准备 DSH
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
本插件当前适配到 DeepSeek Harness `0.1.0-rc.8`,并需要一个当前具有 Codex 使用资格的 ChatGPT 账户。
|
|
50
52
|
|
|
51
53
|
- 不想配置 Node.js:使用 [DSH-Portable(社区便携包)](https://github.com/WSL043/DSH-Portable);
|
|
52
54
|
- 想按官方方式运行:查看 [DeepSeek Harness 官方说明](https://github.com/deepseek-ai/deepseek-harness#run)。
|
|
@@ -79,7 +81,20 @@ irm 'https://github.com/WSL043/dsh-codex-subscription/releases/latest/download/d
|
|
|
79
81
|
无需管理员权限,也不会擅自重启 DSH。
|
|
80
82
|
|
|
81
83
|
<details>
|
|
82
|
-
<summary
|
|
84
|
+
<summary>官方 npm 方式(已安装 Node.js)</summary>
|
|
85
|
+
|
|
86
|
+
官方的 `npx @deepseek-ai/dsh web` 不会创建全局 `dsh` 命令,因此安装插件时也要保留完整的 `npx` 前缀:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
npx -y @deepseek-ai/dsh plugin --profile web add dsh-codex-subscription
|
|
90
|
+
npx -y @deepseek-ai/dsh plugin --profile web list dsh-codex-subscription --depth 0
|
|
91
|
+
npx -y @deepseek-ai/dsh --profile web --dump-config
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
</details>
|
|
95
|
+
|
|
96
|
+
<details>
|
|
97
|
+
<summary>已经能运行 <code>dsh</code>,或位于 DSH-Portable 目录</summary>
|
|
83
98
|
|
|
84
99
|
```sh
|
|
85
100
|
dsh plugin --profile web add dsh-codex-subscription
|
|
@@ -87,8 +102,8 @@ dsh plugin --profile web list dsh-codex-subscription --depth 0
|
|
|
87
102
|
dsh --profile web --dump-config
|
|
88
103
|
```
|
|
89
104
|
|
|
90
|
-
|
|
91
|
-
`codex-subscription` 条目。
|
|
105
|
+
DSH-Portable 请把 `dsh` 换成 `./dsh`(PowerShell 使用 `.\dsh.exe`)。安装列表中应只有一个
|
|
106
|
+
`dsh-codex-subscription`,配置中应只有一个 `codex-subscription` 条目。
|
|
92
107
|
|
|
93
108
|
</details>
|
|
94
109
|
|
|
@@ -107,6 +122,7 @@ dsh --profile web --dump-config
|
|
|
107
122
|
- 设置页显示服务端返回的额度、重置时间和更新时间;
|
|
108
123
|
- 普通 Codex、Codex-Spark、Credits 等独立额度分开显示;
|
|
109
124
|
- 输入框可显示当前 Codex 模型的剩余额度(Beta,默认关闭);
|
|
125
|
+
- 输入框可为支持的 Codex 模型切换标准或高速模式(Beta);
|
|
110
126
|
- 订阅路由不可用时明确报错,不会静默切换到其他付费路由。
|
|
111
127
|
|
|
112
128
|
### 输入框额度
|
|
@@ -118,10 +134,24 @@ dsh --profile web --dump-config
|
|
|
118
134
|
快捷百分比只在选择 Codex 模型时显示。普通 Codex 使用服务端返回窗口中剩余最少的一项,
|
|
119
135
|
Spark 使用独立额度。插件不会写死“5 小时 + 每周”,也不会虚构服务端没有返回的 Credits 或消费上限。
|
|
120
136
|
|
|
137
|
+
### 输入框速度(Beta)
|
|
138
|
+
|
|
139
|
+
选择支持的 Codex 模型后,模型名称左侧会显示 `1×` 或闪电。点击即可切换标准与高速;
|
|
140
|
+
Spark 不显示这个入口。高速模式会提高速度,也会消耗更多 Credits;具体规则见
|
|
141
|
+
[OpenAI Codex Speed 文档](https://learn.chatgpt.com/docs/agent-configuration/speed)。
|
|
142
|
+
|
|
121
143
|
## 更新与卸载
|
|
122
144
|
|
|
123
|
-
Windows
|
|
124
|
-
|
|
145
|
+
Windows 用户重新运行上面的单行助手即可更新。官方 npm 用户使用:
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
npx -y @deepseek-ai/dsh plugin --profile web update dsh-codex-subscription
|
|
149
|
+
npx -y @deepseek-ai/dsh plugin --profile web list dsh-codex-subscription --depth 0
|
|
150
|
+
npx -y @deepseek-ai/dsh --profile web --dump-config
|
|
151
|
+
npx -y @deepseek-ai/dsh plugin --profile web remove dsh-codex-subscription
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
这些操作会保留 DSH profile、其他插件和登录信息。
|
|
125
155
|
|
|
126
156
|
<details>
|
|
127
157
|
<summary>使用现有 <code>dsh</code> 命令更新或卸载</summary>
|
|
@@ -133,18 +163,14 @@ dsh --profile web --dump-config
|
|
|
133
163
|
dsh plugin --profile web remove dsh-codex-subscription
|
|
134
164
|
```
|
|
135
165
|
|
|
136
|
-
从 v0.2.1 手动迁移时,确认新包安装成功后再移除旧包名:
|
|
137
|
-
|
|
138
|
-
```sh
|
|
139
|
-
dsh plugin --profile web remove @wsl043/dsh-codex-subscription
|
|
140
|
-
```
|
|
141
|
-
|
|
142
166
|
</details>
|
|
143
167
|
|
|
144
168
|
DSH-Portable 在其目录中把上述 `dsh` 换成 `.\dsh.exe`。
|
|
145
169
|
|
|
146
170
|
## 常见问题
|
|
147
171
|
|
|
172
|
+
- **`dsh` 无法识别**:官方 npm 方式本来就不会创建全局 `dsh` 命令,请使用上面的完整 `npx -y @deepseek-ai/dsh ...` 命令;
|
|
173
|
+
- **`dsh.exe` 无法识别**:当前目录没有该文件。请先进入 DSH-Portable 目录,或使用 Windows 单行助手;
|
|
148
174
|
- **找不到 DSH-Portable**:进入它的目录后重新执行安装命令,或直接运行 `.\dsh.exe plugin --profile web add dsh-codex-subscription`;
|
|
149
175
|
- **电脑上有多个 DSH**:进入要使用的那个 DSH-Portable 目录再运行助手;
|
|
150
176
|
- **安装仍然失败**:把上面的 Agent 文档链接发给 Agent,不要删除 profile 或随意修改系统 PATH。
|
package/lib/client.js
CHANGED
|
@@ -12,7 +12,13 @@ window.__ModuleLoader__.load({
|
|
|
12
12
|
const QUICK_QUOTA_FIELD = "quickQuotaVisible";
|
|
13
13
|
const SEARCH_PROVIDER_FIELD = "searchProvider";
|
|
14
14
|
const SEARCH_PROVIDER_CODEX = "codex";
|
|
15
|
+
const SPEED_MODE_FIELD = "speedMode";
|
|
16
|
+
const SPEED_MODE_STANDARD = "standard";
|
|
17
|
+
const SPEED_MODE_FAST = "fast";
|
|
18
|
+
const DEFAULT_SPEED_MODE = SPEED_MODE_STANDARD;
|
|
15
19
|
const normalizeSearchProvider = (value) => ["dsh", "codex"].includes(value) ? value : "dsh";
|
|
20
|
+
const normalizeSpeedMode = (value) => ["standard", "fast"].includes(value) ? value : DEFAULT_SPEED_MODE;
|
|
21
|
+
const supportsCodexFastMode = (modelId) => typeof modelId === "string" && (/^gpt-5\.(?:5|6)(?:$|-)/u.test(modelId) || modelId === "gpt-5.4");
|
|
16
22
|
//#endregion
|
|
17
23
|
//#region src/sidebar-quota.js
|
|
18
24
|
const isDisplayableWindow = (window) => Number.isFinite(window?.remainingPercent) && window.remainingPercent >= 0 && window.remainingPercent <= 100 && Number.isFinite(window?.windowSeconds) && window.windowSeconds > 0;
|
|
@@ -62,13 +68,15 @@ window.__ModuleLoader__.load({
|
|
|
62
68
|
deviceHint: "在登录页输入此设备代码:",
|
|
63
69
|
waiting: "正在等待登录完成…",
|
|
64
70
|
failed: "登录失败,请重试。",
|
|
65
|
-
loadFailed: "
|
|
71
|
+
loadFailed: "无法读取账户状态。",
|
|
72
|
+
accountRetry: "重试",
|
|
66
73
|
searchTitle: "搜索来源",
|
|
67
74
|
searchDsh: "DSH 默认",
|
|
68
75
|
searchDshHint: "当前搜索服务",
|
|
69
76
|
searchCodex: "Codex 订阅",
|
|
70
77
|
searchCodexHint: "ChatGPT 订阅搜索",
|
|
71
|
-
preferenceFailed: "
|
|
78
|
+
preferenceFailed: "设置未保存。",
|
|
79
|
+
preferenceRetry: "重试",
|
|
72
80
|
usage: "订阅额度",
|
|
73
81
|
refresh: "刷新",
|
|
74
82
|
refreshing: "刷新中…",
|
|
@@ -99,6 +107,11 @@ window.__ModuleLoader__.load({
|
|
|
99
107
|
quickQuotaSetting: "输入框额度",
|
|
100
108
|
quickQuotaBeta: "Beta",
|
|
101
109
|
quickQuotaStatus: "Codex 剩余额度 {value}%",
|
|
110
|
+
speedTitle: "速度",
|
|
111
|
+
speedStandard: "标准",
|
|
112
|
+
speedStandardHint: "标准速度",
|
|
113
|
+
speedFast: "高速",
|
|
114
|
+
speedFastHint: "1.5 倍,消耗更多 Credits",
|
|
102
115
|
imageGenerate: "生成图片",
|
|
103
116
|
imageGenerating: "正在生成…",
|
|
104
117
|
imageGenerated: "已生成",
|
|
@@ -127,13 +140,15 @@ window.__ModuleLoader__.load({
|
|
|
127
140
|
deviceHint: "Enter this device code on the sign-in page:",
|
|
128
141
|
waiting: "Waiting for sign-in to finish…",
|
|
129
142
|
failed: "Sign-in failed. Try again.",
|
|
130
|
-
loadFailed: "Could not read
|
|
143
|
+
loadFailed: "Could not read account status.",
|
|
144
|
+
accountRetry: "Retry",
|
|
131
145
|
searchTitle: "Search source",
|
|
132
146
|
searchDsh: "DSH default",
|
|
133
147
|
searchDshHint: "Current search service",
|
|
134
148
|
searchCodex: "Codex subscription",
|
|
135
149
|
searchCodexHint: "ChatGPT subscription search",
|
|
136
|
-
preferenceFailed: "
|
|
150
|
+
preferenceFailed: "The setting was not saved.",
|
|
151
|
+
preferenceRetry: "Retry",
|
|
137
152
|
usage: "Subscription quota",
|
|
138
153
|
refresh: "Refresh",
|
|
139
154
|
refreshing: "Refreshing…",
|
|
@@ -164,6 +179,11 @@ window.__ModuleLoader__.load({
|
|
|
164
179
|
quickQuotaSetting: "Composer quota",
|
|
165
180
|
quickQuotaBeta: "Beta",
|
|
166
181
|
quickQuotaStatus: "Codex quota: {value}% remaining",
|
|
182
|
+
speedTitle: "Speed",
|
|
183
|
+
speedStandard: "Standard",
|
|
184
|
+
speedStandardHint: "Standard speed",
|
|
185
|
+
speedFast: "Fast",
|
|
186
|
+
speedFastHint: "1.5x; higher Credits use",
|
|
167
187
|
imageGenerate: "Generate image",
|
|
168
188
|
imageGenerating: "Generating…",
|
|
169
189
|
imageGenerated: "Generated",
|
|
@@ -191,6 +211,7 @@ window.__ModuleLoader__.load({
|
|
|
191
211
|
.codexSubscriptionActions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.codexSubscriptionFlow{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border-radius:10px;background:var(--dsw-alias-bg-module-platform)}
|
|
192
212
|
.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}
|
|
193
213
|
.codexSubscriptionError{font-size:13px;line-height:20px;color:var(--dsw-alias-state-error-primary)}.codexSubscriptionInput{width:100%;box-sizing:border-box}
|
|
214
|
+
.codexSubscriptionRecover{display:flex;align-items:center;justify-content:space-between;gap:12px}.codexSubscriptionRecover .codexSubscriptionError{flex:1}.codexSubscriptionRecover button{flex:0 0 auto}
|
|
194
215
|
.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)}
|
|
195
216
|
.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}
|
|
196
217
|
.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)}
|
|
@@ -202,6 +223,7 @@ window.__ModuleLoader__.load({
|
|
|
202
223
|
.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}
|
|
203
224
|
.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}
|
|
204
225
|
.codexComposerQuota{display:inline-flex;align-items:center;flex:0 0 auto;height:28px;box-sizing:border-box;margin-right:-4px;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}
|
|
226
|
+
.codexComposerControls{display:inline-flex;align-items:center;gap:6px;flex:0 0 auto}.codexComposerSpeed{display:inline-flex;align-items:center;justify-content:center;min-width:28px;height:28px;box-sizing:border-box;padding:0 7px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary);font:500 12px/20px inherit;cursor:pointer;white-space:nowrap}.codexComposerSpeed:hover,.codexComposerSpeed[aria-expanded=true]{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}.codexComposerSpeed:disabled{cursor:not-allowed;opacity:.5}.codexComposerSpeedFast{font-size:14px}.codexComposerSpeedChoice{display:flex;min-width:150px;flex-direction:column;gap:1px}.codexComposerSpeedChoice strong{font-size:13px;line-height:18px;font-weight:500}.codexComposerSpeedChoice span{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}
|
|
205
227
|
.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 - 64px);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}@keyframes codexImageSpin{to{transform:rotate(360deg)}}
|
|
206
228
|
@container (max-width:560px){.codexSubscriptionCreditRows{grid-template-columns:1fr}}
|
|
207
229
|
@container (max-width:480px){.codexSubscriptionAccountRow,.codexSubscriptionSectionHead{align-items:flex-start;flex-direction:column}.codexSubscriptionActions{width:100%}.codexSubscriptionSearchChoices{grid-template-columns:1fr}}
|
|
@@ -357,6 +379,7 @@ window.__ModuleLoader__.load({
|
|
|
357
379
|
let error = false;
|
|
358
380
|
let fallbackStatus = "loading";
|
|
359
381
|
let fallback;
|
|
382
|
+
let failedPatch;
|
|
360
383
|
let generation = 0;
|
|
361
384
|
const nativeSnapshot = () => scope.getSnapshot();
|
|
362
385
|
const read = () => {
|
|
@@ -366,6 +389,7 @@ window.__ModuleLoader__.load({
|
|
|
366
389
|
status: updating ? "updating" : current.status,
|
|
367
390
|
visible: current.value?.[QUICK_QUOTA_FIELD] === true,
|
|
368
391
|
searchProvider: normalizeSearchProvider(current.value?.[SEARCH_PROVIDER_FIELD]),
|
|
392
|
+
speedMode: normalizeSpeedMode(current.value?.[SPEED_MODE_FIELD]),
|
|
369
393
|
writable: !updating && current.status === "ready" && current.writable === true,
|
|
370
394
|
error
|
|
371
395
|
});
|
|
@@ -378,6 +402,7 @@ window.__ModuleLoader__.load({
|
|
|
378
402
|
};
|
|
379
403
|
const disposeScope = scope.subscribe(() => {
|
|
380
404
|
error = false;
|
|
405
|
+
failedPatch = void 0;
|
|
381
406
|
publish();
|
|
382
407
|
});
|
|
383
408
|
const acceptFallback = (value) => {
|
|
@@ -386,7 +411,8 @@ window.__ModuleLoader__.load({
|
|
|
386
411
|
status: "ready",
|
|
387
412
|
value: {
|
|
388
413
|
[QUICK_QUOTA_FIELD]: value?.[QUICK_QUOTA_FIELD] === true,
|
|
389
|
-
[SEARCH_PROVIDER_FIELD]: normalizeSearchProvider(value?.[SEARCH_PROVIDER_FIELD])
|
|
414
|
+
[SEARCH_PROVIDER_FIELD]: normalizeSearchProvider(value?.[SEARCH_PROVIDER_FIELD]),
|
|
415
|
+
[SPEED_MODE_FIELD]: normalizeSpeedMode(value?.[SPEED_MODE_FIELD])
|
|
390
416
|
},
|
|
391
417
|
writable: value?.writable === true
|
|
392
418
|
};
|
|
@@ -416,6 +442,7 @@ window.__ModuleLoader__.load({
|
|
|
416
442
|
const entries = Object.entries(patch);
|
|
417
443
|
updating = true;
|
|
418
444
|
error = false;
|
|
445
|
+
failedPatch = void 0;
|
|
419
446
|
publish();
|
|
420
447
|
try {
|
|
421
448
|
if (nativeSnapshot().status === "ready") {
|
|
@@ -432,7 +459,10 @@ window.__ModuleLoader__.load({
|
|
|
432
459
|
acceptFallback(value);
|
|
433
460
|
}
|
|
434
461
|
} catch {
|
|
435
|
-
if (current === generation)
|
|
462
|
+
if (current === generation) {
|
|
463
|
+
error = true;
|
|
464
|
+
failedPatch = patch;
|
|
465
|
+
}
|
|
436
466
|
} finally {
|
|
437
467
|
if (current === generation) {
|
|
438
468
|
updating = false;
|
|
@@ -448,6 +478,7 @@ window.__ModuleLoader__.load({
|
|
|
448
478
|
},
|
|
449
479
|
load,
|
|
450
480
|
set,
|
|
481
|
+
retry: () => failedPatch === void 0 ? load() : set(failedPatch),
|
|
451
482
|
dispose: disposeScope
|
|
452
483
|
};
|
|
453
484
|
}
|
|
@@ -573,28 +604,86 @@ window.__ModuleLoader__.load({
|
|
|
573
604
|
preference,
|
|
574
605
|
t
|
|
575
606
|
}),
|
|
576
|
-
snapshot.error ? /* @__PURE__ */ (0, react_jsx_runtime.
|
|
577
|
-
className: "
|
|
607
|
+
snapshot.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
608
|
+
className: "codexSubscriptionRecover",
|
|
578
609
|
role: "alert",
|
|
579
|
-
children:
|
|
610
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
611
|
+
className: "codexSubscriptionError",
|
|
612
|
+
children: t("preferenceFailed")
|
|
613
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
614
|
+
type: "button",
|
|
615
|
+
variant: "outline",
|
|
616
|
+
onClick: () => {
|
|
617
|
+
preference.retry();
|
|
618
|
+
},
|
|
619
|
+
children: t("preferenceRetry")
|
|
620
|
+
})]
|
|
580
621
|
}) : null
|
|
581
622
|
]
|
|
582
623
|
});
|
|
583
624
|
}
|
|
584
|
-
function
|
|
625
|
+
function CodexComposerControls({ preference, rpc, t, directory }) {
|
|
626
|
+
const [speedOpen, setSpeedOpen] = (0, react.useState)(false);
|
|
585
627
|
const preferenceSnapshot = usePreferenceSnapshot(preference);
|
|
586
628
|
const current = (0, react.useSyncExternalStore)((listener) => directory.subscribe(listener), () => directory.getSnapshot()).current;
|
|
587
|
-
const
|
|
588
|
-
const
|
|
589
|
-
|
|
590
|
-
const
|
|
591
|
-
const
|
|
629
|
+
const codex = current?.provider === "openai-codex";
|
|
630
|
+
const speedSupported = codex && supportsCodexFastMode(current?.model);
|
|
631
|
+
const speedWritable = preferenceSnapshot.status === "ready" && preferenceSnapshot.writable === true;
|
|
632
|
+
const fast = preferenceSnapshot.speedMode === SPEED_MODE_FAST;
|
|
633
|
+
const quotaEnabled = preferenceSnapshot.status === "ready" && preferenceSnapshot.visible && codex;
|
|
634
|
+
const quota = useQuickQuota(rpc, quotaEnabled, current?.model);
|
|
635
|
+
if (!speedSupported && (!quotaEnabled || quota === void 0)) return null;
|
|
636
|
+
const speedItems = [{
|
|
637
|
+
id: SPEED_MODE_STANDARD,
|
|
638
|
+
label: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
639
|
+
className: "codexComposerSpeedChoice",
|
|
640
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("speedStandard") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("speedStandardHint") })]
|
|
641
|
+
})
|
|
642
|
+
}, {
|
|
643
|
+
id: SPEED_MODE_FAST,
|
|
644
|
+
label: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
645
|
+
className: "codexComposerSpeedChoice",
|
|
646
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("speedFast") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("speedFastHint") })]
|
|
647
|
+
})
|
|
648
|
+
}];
|
|
649
|
+
const speed = speedSupported ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
650
|
+
open: speedOpen,
|
|
651
|
+
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
652
|
+
className: `codexComposerSpeed${fast ? " codexComposerSpeedFast" : ""}`,
|
|
653
|
+
type: "button",
|
|
654
|
+
"aria-label": `${t("speedTitle")}: ${t(fast ? "speedFast" : "speedStandard")}`,
|
|
655
|
+
"aria-expanded": speedOpen,
|
|
656
|
+
disabled: !speedWritable,
|
|
657
|
+
onClick: () => setSpeedOpen((value) => !value),
|
|
658
|
+
children: fast ? "⚡" : "1×"
|
|
659
|
+
}),
|
|
660
|
+
items: speedItems,
|
|
661
|
+
selectedId: preferenceSnapshot.speedMode,
|
|
662
|
+
onSelect: (id) => {
|
|
663
|
+
setSpeedOpen(false);
|
|
664
|
+
preference.set({ [SPEED_MODE_FIELD]: id });
|
|
665
|
+
},
|
|
666
|
+
onClose: () => setSpeedOpen(false),
|
|
667
|
+
align: "end",
|
|
668
|
+
side: "top",
|
|
669
|
+
portal: true,
|
|
670
|
+
compact: true
|
|
671
|
+
}) : null;
|
|
672
|
+
let quotaView = null;
|
|
673
|
+
if (quotaEnabled && quota !== void 0) {
|
|
674
|
+
const value = percent(quota.remainingPercent);
|
|
675
|
+
const label = fill(t("quickQuotaStatus"), { value });
|
|
676
|
+
quotaView = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
677
|
+
className: "codexComposerQuota",
|
|
678
|
+
role: "status",
|
|
679
|
+
"aria-label": label,
|
|
680
|
+
title: label,
|
|
681
|
+
children: [value, "%"]
|
|
682
|
+
});
|
|
683
|
+
}
|
|
592
684
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
593
|
-
className: "
|
|
594
|
-
|
|
595
|
-
"aria-label": label,
|
|
596
|
-
title: label,
|
|
597
|
-
children: [value, "%"]
|
|
685
|
+
className: "codexComposerControls",
|
|
686
|
+
children: [quotaView, speed]
|
|
598
687
|
});
|
|
599
688
|
}
|
|
600
689
|
function AccountCard({ rpc, t, account, setAccount, onSignedOut }) {
|
|
@@ -767,6 +856,21 @@ window.__ModuleLoader__.load({
|
|
|
767
856
|
]
|
|
768
857
|
});
|
|
769
858
|
}
|
|
859
|
+
function AccountFailureCard({ retry, t }) {
|
|
860
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
861
|
+
className: "codexSubscriptionCard codexSubscriptionRecover",
|
|
862
|
+
role: "alert",
|
|
863
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
864
|
+
className: "codexSubscriptionError",
|
|
865
|
+
children: t("loadFailed")
|
|
866
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
867
|
+
type: "button",
|
|
868
|
+
variant: "outline",
|
|
869
|
+
onClick: retry,
|
|
870
|
+
children: t("accountRetry")
|
|
871
|
+
})]
|
|
872
|
+
});
|
|
873
|
+
}
|
|
770
874
|
function ResetTime({ resetsAt, t }) {
|
|
771
875
|
const date = Number.isSafeInteger(resetsAt) ? validDate(resetsAt * 1e3) : void 0;
|
|
772
876
|
if (date === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetUnknown") });
|
|
@@ -948,17 +1052,23 @@ window.__ModuleLoader__.load({
|
|
|
948
1052
|
}
|
|
949
1053
|
function CodexSection({ preference, rpc, t }) {
|
|
950
1054
|
const [account, setAccount] = (0, react.useState)();
|
|
951
|
-
const [
|
|
1055
|
+
const [accountError, setAccountError] = (0, react.useState)();
|
|
952
1056
|
const [resetKey, setResetKey] = (0, react.useState)(0);
|
|
953
|
-
(0, react.
|
|
954
|
-
|
|
1057
|
+
const accountRequest = (0, react.useRef)(0);
|
|
1058
|
+
const loadAccount = () => {
|
|
1059
|
+
const id = ++accountRequest.current;
|
|
1060
|
+
setAccount(void 0);
|
|
1061
|
+
setAccountError(void 0);
|
|
955
1062
|
rpc.call(CHANNEL, "status", {}).then(unwrap).then((next) => {
|
|
956
|
-
if (
|
|
1063
|
+
if (accountRequest.current === id) setAccount(next);
|
|
957
1064
|
}).catch(() => {
|
|
958
|
-
if (
|
|
1065
|
+
if (accountRequest.current === id) setAccountError(true);
|
|
959
1066
|
});
|
|
1067
|
+
};
|
|
1068
|
+
(0, react.useEffect)(() => {
|
|
1069
|
+
loadAccount();
|
|
960
1070
|
return () => {
|
|
961
|
-
|
|
1071
|
+
accountRequest.current += 1;
|
|
962
1072
|
};
|
|
963
1073
|
}, []);
|
|
964
1074
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
@@ -968,26 +1078,24 @@ window.__ModuleLoader__.load({
|
|
|
968
1078
|
className: "codexSubscriptionHead",
|
|
969
1079
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", { children: t("title") })
|
|
970
1080
|
}),
|
|
971
|
-
|
|
972
|
-
className: "codexSubscriptionError",
|
|
973
|
-
role: "alert",
|
|
974
|
-
children: error
|
|
975
|
-
}),
|
|
976
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountCard, {
|
|
1081
|
+
accountError === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountCard, {
|
|
977
1082
|
rpc,
|
|
978
1083
|
t,
|
|
979
1084
|
account,
|
|
980
1085
|
setAccount,
|
|
981
1086
|
onSignedOut: () => setResetKey((value) => value + 1)
|
|
1087
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountFailureCard, {
|
|
1088
|
+
retry: loadAccount,
|
|
1089
|
+
t
|
|
982
1090
|
}),
|
|
983
1091
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PreferencesCard, {
|
|
984
1092
|
preference,
|
|
985
1093
|
t
|
|
986
1094
|
}),
|
|
987
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageCard, {
|
|
1095
|
+
account === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageCard, {
|
|
988
1096
|
rpc,
|
|
989
1097
|
t,
|
|
990
|
-
signedIn: account
|
|
1098
|
+
signedIn: account.authenticated === true,
|
|
991
1099
|
resetKey
|
|
992
1100
|
})
|
|
993
1101
|
]
|
|
@@ -1041,7 +1149,7 @@ window.__ModuleLoader__.load({
|
|
|
1041
1149
|
t,
|
|
1042
1150
|
directory: ctx.modelDirectories.directoryFor(sessionId).store
|
|
1043
1151
|
})
|
|
1044
|
-
},
|
|
1152
|
+
}, CodexComposerControls));
|
|
1045
1153
|
const conversation = ctx.get("conversation");
|
|
1046
1154
|
ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
|
|
1047
1155
|
name: "tool.call.toolview",
|
package/lib/index.js
CHANGED
|
@@ -430,6 +430,17 @@ function createCodexRpcHandler(coordinator, options = {}) {
|
|
|
430
430
|
};
|
|
431
431
|
}
|
|
432
432
|
//#endregion
|
|
433
|
+
//#region src/settings-contract.js
|
|
434
|
+
const SETTINGS_NAMESPACE = "codex-subscription";
|
|
435
|
+
const QUICK_QUOTA_FIELD = "quickQuotaVisible";
|
|
436
|
+
const SEARCH_PROVIDER_FIELD = "searchProvider";
|
|
437
|
+
const SEARCH_PROVIDER_CODEX = "codex";
|
|
438
|
+
const SPEED_MODE_FIELD = "speedMode";
|
|
439
|
+
const SPEED_MODE_STANDARD = "standard";
|
|
440
|
+
const SPEED_MODE_FAST = "fast";
|
|
441
|
+
const DEFAULT_SPEED_MODE = SPEED_MODE_STANDARD;
|
|
442
|
+
const supportsCodexFastMode = (modelId) => typeof modelId === "string" && (/^gpt-5\.(?:5|6)(?:$|-)/u.test(modelId) || modelId === "gpt-5.4");
|
|
443
|
+
//#endregion
|
|
433
444
|
//#region src/pi-ai-runtime.js
|
|
434
445
|
/**
|
|
435
446
|
* Preserve pi-ai's native Codex OAuth provider while allowing DSH's generic
|
|
@@ -442,7 +453,7 @@ function createCodexRpcHandler(coordinator, options = {}) {
|
|
|
442
453
|
* token for this request; login, refresh, persistence, headers, transport, and
|
|
443
454
|
* model behavior remain owned by the original provider.
|
|
444
455
|
*/
|
|
445
|
-
function openaiCodexSubscriptionProvider() {
|
|
456
|
+
function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0 } = {}) {
|
|
446
457
|
const provider = createOpenAICodexProvider();
|
|
447
458
|
const requestToken = Object.freeze({
|
|
448
459
|
name: "DSH-managed Codex OAuth request token",
|
|
@@ -455,15 +466,35 @@ function openaiCodexSubscriptionProvider() {
|
|
|
455
466
|
};
|
|
456
467
|
}
|
|
457
468
|
});
|
|
469
|
+
const withSpeed = (model, options = {}) => {
|
|
470
|
+
if (resolveSpeedMode() !== "fast" || !supportsCodexFastMode(model?.id)) return options;
|
|
471
|
+
const onPayload = options.onPayload;
|
|
472
|
+
return {
|
|
473
|
+
...options,
|
|
474
|
+
serviceTier: "fast",
|
|
475
|
+
async onPayload(payload, requestModel) {
|
|
476
|
+
const fastPayload = {
|
|
477
|
+
...payload,
|
|
478
|
+
service_tier: "fast"
|
|
479
|
+
};
|
|
480
|
+
return {
|
|
481
|
+
...await onPayload?.(fastPayload, requestModel) ?? fastPayload,
|
|
482
|
+
service_tier: "fast"
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
};
|
|
458
487
|
return Object.freeze({
|
|
459
488
|
...provider,
|
|
460
489
|
auth: Object.freeze({
|
|
461
490
|
...provider.auth,
|
|
462
491
|
apiKey: requestToken
|
|
463
|
-
})
|
|
492
|
+
}),
|
|
493
|
+
stream: (model, context, options) => provider.stream(model, context, withSpeed(model, options)),
|
|
494
|
+
streamSimple: (model, context, options) => provider.streamSimple(model, context, withSpeed(model, options))
|
|
464
495
|
});
|
|
465
496
|
}
|
|
466
|
-
const USER_AGENT = `dsh-codex-subscription/1.0
|
|
497
|
+
const USER_AGENT = `dsh-codex-subscription/1.1.0`;
|
|
467
498
|
//#endregion
|
|
468
499
|
//#region src/codex-search.js
|
|
469
500
|
const CODEX_SEARCH_PROVIDER_ID = "codex-subscription";
|
|
@@ -791,12 +822,6 @@ function createCodexImageTool(options) {
|
|
|
791
822
|
});
|
|
792
823
|
}
|
|
793
824
|
//#endregion
|
|
794
|
-
//#region src/settings-contract.js
|
|
795
|
-
const SETTINGS_NAMESPACE = "codex-subscription";
|
|
796
|
-
const QUICK_QUOTA_FIELD = "quickQuotaVisible";
|
|
797
|
-
const SEARCH_PROVIDER_FIELD = "searchProvider";
|
|
798
|
-
const SEARCH_PROVIDER_CODEX = "codex";
|
|
799
|
-
//#endregion
|
|
800
825
|
//#region src/usage.js
|
|
801
826
|
const CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
|
|
802
827
|
const DEFAULT_TTL_MS = 6e4;
|
|
@@ -1012,6 +1037,10 @@ function createSubscriptionRpcHandler({ authHandler, usageReader, preferences })
|
|
|
1012
1037
|
if (!["dsh", "codex"].includes(payload["searchProvider"])) return publicError("internal", "Invalid search provider preference");
|
|
1013
1038
|
patch[SEARCH_PROVIDER_FIELD] = payload[SEARCH_PROVIDER_FIELD];
|
|
1014
1039
|
}
|
|
1040
|
+
if (Object.hasOwn(payload ?? {}, "speedMode")) {
|
|
1041
|
+
if (!["standard", "fast"].includes(payload["speedMode"])) return publicError("internal", "Invalid speed mode preference");
|
|
1042
|
+
patch[SPEED_MODE_FIELD] = payload[SPEED_MODE_FIELD];
|
|
1043
|
+
}
|
|
1015
1044
|
if (Object.keys(patch).length === 0) return publicError("internal", "Invalid preference update");
|
|
1016
1045
|
await preferences.update(patch);
|
|
1017
1046
|
}
|
|
@@ -1063,19 +1092,21 @@ function createSearchProviderSwitcher(loader) {
|
|
|
1063
1092
|
function apply(ctx) {
|
|
1064
1093
|
const settings = ctx.settings.register(settingsNamespace(SETTINGS_NAMESPACE), z.object({
|
|
1065
1094
|
[QUICK_QUOTA_FIELD]: z.boolean().default(false),
|
|
1066
|
-
[SEARCH_PROVIDER_FIELD]: z.union(["dsh", SEARCH_PROVIDER_CODEX]).default("dsh")
|
|
1095
|
+
[SEARCH_PROVIDER_FIELD]: z.union(["dsh", SEARCH_PROVIDER_CODEX]).default("dsh"),
|
|
1096
|
+
[SPEED_MODE_FIELD]: z.union([SPEED_MODE_STANDARD, SPEED_MODE_FAST]).default(DEFAULT_SPEED_MODE)
|
|
1067
1097
|
}));
|
|
1068
1098
|
const searchProvider = createSearchProviderSwitcher(ctx.loader);
|
|
1069
1099
|
const preferences = {
|
|
1070
1100
|
status: () => ({
|
|
1071
1101
|
[QUICK_QUOTA_FIELD]: settings.get()[QUICK_QUOTA_FIELD],
|
|
1072
1102
|
[SEARCH_PROVIDER_FIELD]: settings.get()[SEARCH_PROVIDER_FIELD],
|
|
1103
|
+
[SPEED_MODE_FIELD]: settings.get()[SPEED_MODE_FIELD],
|
|
1073
1104
|
writable: ctx.settings.writable
|
|
1074
1105
|
}),
|
|
1075
1106
|
update: (patch) => settings.update(patch)
|
|
1076
1107
|
};
|
|
1077
1108
|
const store = new DshOAuthCredentialStore(ctx.credentials, CREDENTIAL_REF, [LEGACY_CREDENTIAL_REF]);
|
|
1078
|
-
const provider = openaiCodexSubscriptionProvider();
|
|
1109
|
+
const provider = openaiCodexSubscriptionProvider({ resolveSpeedMode: () => settings.get()[SPEED_MODE_FIELD] });
|
|
1079
1110
|
const authModels = createModels({ credentials: store });
|
|
1080
1111
|
authModels.setProvider(provider);
|
|
1081
1112
|
const profile = Object.freeze({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codex-subscription",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"packageManager": "pnpm@11.19.0",
|
|
5
5
|
"description": "ChatGPT and Codex subscriptions for DeepSeek Harness with OAuth login, image generation, quota, and subscription web search",
|
|
6
6
|
"type": "module",
|