dsh-codex-subscription 1.1.3 → 1.1.5

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 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.1.3` package below; do not install a moving branch.
9
+ - Use the exact `1.1.5` 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.
@@ -38,19 +38,19 @@ For an official DSH installation run through npm, keep the complete `npx` prefix
38
38
  run command does not create a global `dsh` command:
39
39
 
40
40
  ```sh
41
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 plugin --profile web add dsh-codex-subscription@1.1.3
41
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 plugin --profile web add dsh-codex-subscription@1.1.5
42
42
  ```
43
43
 
44
44
  With an existing global `dsh` command:
45
45
 
46
46
  ```sh
47
- dsh plugin --profile web add dsh-codex-subscription@1.1.3
47
+ dsh plugin --profile web add dsh-codex-subscription@1.1.5
48
48
  ```
49
49
 
50
50
  From a DSH-Portable folder:
51
51
 
52
52
  ```powershell
53
- .\dsh.exe plugin --profile web add dsh-codex-subscription@1.1.3
53
+ .\dsh.exe plugin --profile web add dsh-codex-subscription@1.1.5
54
54
  ```
55
55
 
56
56
  Use the same `add` command to update or repair. This is the complete package-changing operation.
@@ -68,9 +68,9 @@ dsh --profile web --dump-config
68
68
 
69
69
  For DSH-Portable, replace `dsh` with `.\dsh.exe`. Static acceptance requires:
70
70
 
71
- For the official npm route, run the same checks with `npx -y @deepseek-ai/dsh@0.1.0-rc.8` in place of `dsh`.
71
+ For the official npm route, run the same checks with `npx -y @deepseek-ai/dsh@0.1.1-rc.1` in place of `dsh`.
72
72
 
73
- 1. `dsh-codex-subscription` version `1.1.3` appears exactly once.
73
+ 1. `dsh-codex-subscription` version `1.1.5` appears exactly once.
74
74
  2. `codex-subscription` appears exactly once in the composed config.
75
75
  3. No unrelated plugin or profile was changed and DSH was not restarted.
76
76
 
@@ -94,7 +94,7 @@ For DSH-Portable:
94
94
  For the official npm route:
95
95
 
96
96
  ```sh
97
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 plugin --profile web remove dsh-codex-subscription
97
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 plugin --profile web remove dsh-codex-subscription
98
98
  ```
99
99
 
100
100
  Uninstall removes only this plugin. It must preserve the profile, sessions, other plugins, and saved
package/README.en.md CHANGED
@@ -47,7 +47,7 @@ These capabilities reuse the same local ChatGPT sign-in. Subscription routing fa
47
47
 
48
48
  ## Prepare DSH
49
49
 
50
- This plugin is currently compatible through DeepSeek Harness `0.1.0-rc.8` and requires a ChatGPT account that currently has Codex access.
50
+ This plugin is currently compatible through DeepSeek Harness `0.1.1-rc.1` and requires a ChatGPT account that currently has Codex access.
51
51
 
52
52
  - Do not want to configure Node.js? Use the [community DSH-Portable package](https://github.com/WSL043/DSH-Portable).
53
53
  - Prefer the official route? Follow the [DeepSeek Harness run guide](https://github.com/deepseek-ai/deepseek-harness#run).
@@ -74,11 +74,11 @@ Open PowerShell and paste this one line:
74
74
  irm 'https://github.com/WSL043/dsh-codex-subscription/releases/latest/download/dsh-codex-setup.ps1' | iex
75
75
  ```
76
76
 
77
- The lightweight setup checks the current folder, the system command, common locations, and any running
77
+ The lightweight setup checks the current folder, the system command, common locations, and any running official DSH or
78
78
  [DSH-Portable](https://github.com/WSL043/DSH-Portable), then invokes the official `plugin add`
79
79
  operation once. It does not recursively scan disks, install pnpm, create a resident command, snapshot a
80
80
  profile, or download the plugin twice. It needs no administrator access and never restarts DSH. Only
81
- when no existing DSH is found does it use the official npm route pinned to `0.1.0-rc.8`; the setup warns
81
+ when no existing DSH is found does it use the official npm route pinned to `0.1.1-rc.1`; the setup warns
82
82
  that first-time dependency resolution can take a while.
83
83
 
84
84
  <details>
@@ -87,9 +87,9 @@ that first-time dependency resolution can take a while.
87
87
  The official `npx @deepseek-ai/dsh web` command does not create a global `dsh` command. Keep the full `npx` prefix when installing the plugin:
88
88
 
89
89
  ```sh
90
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 plugin --profile web add dsh-codex-subscription
91
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 plugin --profile web list dsh-codex-subscription --depth 0
92
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 --profile web --dump-config
90
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 plugin --profile web add dsh-codex-subscription
91
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 plugin --profile web list dsh-codex-subscription --depth 0
92
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 --profile web --dump-config
93
93
  ```
94
94
 
95
95
  </details>
@@ -138,8 +138,8 @@ window returned by the service; Spark uses its independent quota. The plugin doe
138
138
 
139
139
  ### Composer speed (Beta)
140
140
 
141
- With a supported Codex model selected, `1×` or a lightning icon appears immediately before the model name.
142
- Click it to choose Standard or Fast. Spark does not show this control. Fast mode increases speed and uses more Credits;
141
+ With a supported Codex model selected, open the composer's model menu to choose Standard or Fast.
142
+ Standard adds no icon; only Fast shows a lightning icon before the model name. Spark does not show the speed entry. Fast mode increases speed and uses more Credits;
143
143
  see the [OpenAI Codex Speed documentation](https://learn.chatgpt.com/docs/agent-configuration/speed) for the current rules.
144
144
 
145
145
  ## Update and uninstall
@@ -147,10 +147,10 @@ see the [OpenAI Codex Speed documentation](https://learn.chatgpt.com/docs/agent-
147
147
  On Windows, rerun the one-line setup above to update. For the official npm route, use:
148
148
 
149
149
  ```sh
150
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 plugin --profile web update dsh-codex-subscription
151
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 plugin --profile web list dsh-codex-subscription --depth 0
152
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 --profile web --dump-config
153
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 plugin --profile web remove dsh-codex-subscription
150
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 plugin --profile web update dsh-codex-subscription
151
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 plugin --profile web list dsh-codex-subscription --depth 0
152
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 --profile web --dump-config
153
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 plugin --profile web remove dsh-codex-subscription
154
154
  ```
155
155
 
156
156
  These operations preserve the DSH profile, other plugins, and saved sign-in.
@@ -171,7 +171,7 @@ From a DSH-Portable folder, replace `dsh` above with `.\dsh.exe`.
171
171
 
172
172
  ## Troubleshooting
173
173
 
174
- - **`dsh` is not recognized:** the official npm route does not create a global `dsh` command; use the complete `npx -y @deepseek-ai/dsh@0.1.0-rc.8 ...` command above;
174
+ - **`dsh` is not recognized:** the official npm route does not create a global `dsh` command; use the complete `npx -y @deepseek-ai/dsh@0.1.1-rc.1 ...` command above;
175
175
  - **`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;
176
176
  - **DSH-Portable is not found:** enter its folder and rerun setup, or run `.\dsh.exe plugin --profile web add dsh-codex-subscription` directly;
177
177
  - **More than one DSH exists:** the one-line setup combines running copies with Portable folders detected in common locations; enter its number. For an Agent, use the intended folder or pass `-DshPath` explicitly;
package/README.md CHANGED
@@ -48,7 +48,7 @@
48
48
 
49
49
  ## 准备 DSH
50
50
 
51
- 本插件当前适配到 DeepSeek Harness `0.1.0-rc.8`,并需要一个当前具有 Codex 使用资格的 ChatGPT 账户。
51
+ 本插件当前适配到 DeepSeek Harness `0.1.1-rc.1`,并需要一个当前具有 Codex 使用资格的 ChatGPT 账户。
52
52
 
53
53
  - 不想配置 Node.js:使用 [DSH-Portable(社区便携包)](https://github.com/WSL043/DSH-Portable);
54
54
  - 想按官方方式运行:查看 [DeepSeek Harness 官方说明](https://github.com/deepseek-ai/deepseek-harness#run)。
@@ -75,10 +75,10 @@ Agent 文档包含安装、更新、卸载和验收步骤,并要求保留 DSH
75
75
  irm 'https://github.com/WSL043/dsh-codex-subscription/releases/latest/download/dsh-codex-setup.ps1' | iex
76
76
  ```
77
77
 
78
- 这个轻量助手会检查当前目录、系统命令、常见位置以及正在运行的
78
+ 这个轻量助手会检查当前目录、系统命令、常见位置以及正在运行的官方 DSH 或
79
79
  [DSH-Portable](https://github.com/WSL043/DSH-Portable),然后调用一次官方
80
80
  `plugin add`。它不会递归扫盘、安装 pnpm、创建常驻命令、保存 profile 快照或重复下载插件。
81
- 无需管理员权限,也不会擅自重启 DSH。找不到现有 DSH 时才会使用固定为 `0.1.0-rc.8`
81
+ 无需管理员权限,也不会擅自重启 DSH。找不到现有 DSH 时才会使用固定为 `0.1.1-rc.1`
82
82
  的官方 npm 运行方式;首次解析依赖可能较慢,安装器会先明确提示。
83
83
 
84
84
  <details>
@@ -87,9 +87,9 @@ irm 'https://github.com/WSL043/dsh-codex-subscription/releases/latest/download/d
87
87
  官方的 `npx @deepseek-ai/dsh web` 不会创建全局 `dsh` 命令,因此安装插件时也要保留完整的 `npx` 前缀:
88
88
 
89
89
  ```sh
90
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 plugin --profile web add dsh-codex-subscription
91
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 plugin --profile web list dsh-codex-subscription --depth 0
92
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 --profile web --dump-config
90
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 plugin --profile web add dsh-codex-subscription
91
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 plugin --profile web list dsh-codex-subscription --depth 0
92
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 --profile web --dump-config
93
93
  ```
94
94
 
95
95
  </details>
@@ -137,8 +137,8 @@ Spark 使用独立额度。插件不会写死“5 小时 + 每周”,也不会
137
137
 
138
138
  ### 输入框速度(Beta)
139
139
 
140
- 选择支持的 Codex 模型后,模型名称左侧会显示 `1×` 或闪电。点击即可切换标准与高速;
141
- Spark 不显示这个入口。高速模式会提高速度,也会消耗更多 Credits;具体规则见
140
+ 选择支持的 Codex 模型后,可在输入框的模型菜单中切换标准与高速。标准模式不增加图标,
141
+ 只有高速模式会在模型名称左侧显示闪电;Spark 不显示速度入口。高速模式会提高速度,也会消耗更多 Credits;具体规则见
142
142
  [OpenAI Codex Speed 文档](https://learn.chatgpt.com/docs/agent-configuration/speed)。
143
143
 
144
144
  ## 更新与卸载
@@ -146,10 +146,10 @@ Spark 不显示这个入口。高速模式会提高速度,也会消耗更多 C
146
146
  Windows 用户重新运行上面的单行助手即可更新。官方 npm 用户使用:
147
147
 
148
148
  ```sh
149
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 plugin --profile web update dsh-codex-subscription
150
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 plugin --profile web list dsh-codex-subscription --depth 0
151
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 --profile web --dump-config
152
- npx -y @deepseek-ai/dsh@0.1.0-rc.8 plugin --profile web remove dsh-codex-subscription
149
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 plugin --profile web update dsh-codex-subscription
150
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 plugin --profile web list dsh-codex-subscription --depth 0
151
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 --profile web --dump-config
152
+ npx -y @deepseek-ai/dsh@0.1.1-rc.1 plugin --profile web remove dsh-codex-subscription
153
153
  ```
154
154
 
155
155
  这些操作会保留 DSH profile、其他插件和登录信息。
@@ -170,7 +170,7 @@ DSH-Portable 在其目录中把上述 `dsh` 换成 `.\dsh.exe`。
170
170
 
171
171
  ## 常见问题
172
172
 
173
- - **`dsh` 无法识别**:官方 npm 方式本来就不会创建全局 `dsh` 命令,请使用上面的完整 `npx -y @deepseek-ai/dsh@0.1.0-rc.8 ...` 命令;
173
+ - **`dsh` 无法识别**:官方 npm 方式本来就不会创建全局 `dsh` 命令,请使用上面的完整 `npx -y @deepseek-ai/dsh@0.1.1-rc.1 ...` 命令;
174
174
  - **`dsh.exe` 无法识别**:当前目录没有该文件。请先进入 DSH-Portable 目录,或使用 Windows 单行助手;
175
175
  - **找不到 DSH-Portable**:进入它的目录后重新执行安装命令,或直接运行 `.\dsh.exe plugin --profile web add dsh-codex-subscription`;
176
176
  - **电脑上有多个 DSH**:单行助手会合并正在运行的副本与常用目录内检测到的 Portable,输入对应编号即可;交给 Agent 时让它进入目标目录,或明确传入 `-DshPath`;
@@ -7,6 +7,7 @@ This project depends on software distributed under its own terms. The dependency
7
7
  | DeepSeek Harness packages | Plugin host, client slots, credential and LLM interfaces | MIT | https://github.com/deepseek-ai/deepseek-harness |
8
8
  | `@earendil-works/pi-ai` 0.82.1 | OpenAI Codex OAuth, model catalog, Responses transport, and WebSocket continuation | MIT | https://github.com/earendil-works/pi |
9
9
  | React | DSH settings component runtime | MIT | https://github.com/facebook/react |
10
+ | Heroicons | Composer speed icon | MIT | https://github.com/tailwindlabs/heroicons |
10
11
  | tsdown | Development-time bundler | MIT | https://github.com/rolldown/tsdown |
11
12
 
12
13
  No third-party project endorses this community plugin. See each installed package for its complete license text and transitive dependency notices.
@@ -0,0 +1,9 @@
1
+ {
2
+ "latestTested": "0.1.1-rc.1",
3
+ "supported": [
4
+ "0.1.0-rc.6",
5
+ "0.1.0-rc.7",
6
+ "0.1.0-rc.8",
7
+ "0.1.1-rc.1"
8
+ ]
9
+ }
package/lib/client.js CHANGED
@@ -4,9 +4,50 @@ window.__ModuleLoader__.load({
4
4
  var module = { exports: {} };
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ //#region \0rolldown/runtime.js
8
+ var __create = Object.create;
9
+ var __defProp = Object.defineProperty;
10
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
11
+ var __getOwnPropNames = Object.getOwnPropertyNames;
12
+ var __getProtoOf = Object.getPrototypeOf;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
16
+ key = keys[i];
17
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
18
+ get: ((k) => from[k]).bind(null, key),
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
25
+ value: mod,
26
+ enumerable: true
27
+ }) : target, mod));
28
+ //#endregion
7
29
  let react = require("react");
30
+ react = __toESM(react, 1);
8
31
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
32
  let react_jsx_runtime = require("react/jsx-runtime");
33
+ //#region node_modules/.pnpm/@heroicons+react@2.2.0_react@18.3.1/node_modules/@heroicons/react/16/solid/esm/BoltIcon.js
34
+ function BoltIcon({ title, titleId, ...props }, svgRef) {
35
+ return /*#__PURE__*/ react.createElement("svg", Object.assign({
36
+ xmlns: "http://www.w3.org/2000/svg",
37
+ viewBox: "0 0 16 16",
38
+ fill: "currentColor",
39
+ "aria-hidden": "true",
40
+ "data-slot": "icon",
41
+ ref: svgRef,
42
+ "aria-labelledby": titleId
43
+ }, props), title ? /*#__PURE__*/ react.createElement("title", { id: titleId }, title) : null, /*#__PURE__*/ react.createElement("path", {
44
+ fillRule: "evenodd",
45
+ d: "M9.58 1.077a.75.75 0 0 1 .405.82L9.165 6h4.085a.75.75 0 0 1 .567 1.241l-6.5 7.5a.75.75 0 0 1-1.302-.638L6.835 10H2.75a.75.75 0 0 1-.567-1.241l6.5-7.5a.75.75 0 0 1 .897-.182Z",
46
+ clipRule: "evenodd"
47
+ }));
48
+ }
49
+ const ForwardRef = /*#__PURE__*/ react.forwardRef(BoltIcon);
50
+ //#endregion
10
51
  //#region src/settings-contract.js
11
52
  const SETTINGS_NAMESPACE = "codex-subscription";
12
53
  const QUICK_QUOTA_FIELD = "quickQuotaVisible";
@@ -46,7 +87,8 @@ window.__ModuleLoader__.load({
46
87
  "remote",
47
88
  "settingsScope",
48
89
  "modelDirectories",
49
- "conversation"
90
+ "conversation",
91
+ "sessions"
50
92
  ];
51
93
  const NS = "settings.codexSubscription";
52
94
  const CHANNEL = "/codex-subscription";
@@ -112,6 +154,17 @@ window.__ModuleLoader__.load({
112
154
  speedStandardHint: "标准速度",
113
155
  speedFast: "高速",
114
156
  speedFastHint: "1.5 倍,消耗更多 Credits",
157
+ modelMenuAria: "模型、推理等级与速度",
158
+ modelLabel: "模型",
159
+ effortLabel: "推理等级",
160
+ providerDefault: "Default",
161
+ selectModel: "选择模型",
162
+ modelsLoading: "正在读取模型…",
163
+ modelsEmpty: "没有可用模型。",
164
+ effortsEmpty: "当前模型未提供推理等级。",
165
+ modelRetry: "重试",
166
+ modelFailed: "模型目录加载失败:{value}",
167
+ groupFailed: "{name}:{value}",
115
168
  imageGenerate: "生成图片",
116
169
  imageGenerating: "正在生成…",
117
170
  imageGenerated: "已生成",
@@ -184,6 +237,17 @@ window.__ModuleLoader__.load({
184
237
  speedStandardHint: "Standard speed",
185
238
  speedFast: "Fast",
186
239
  speedFastHint: "1.5x; higher Credits use",
240
+ modelMenuAria: "Model, effort, and speed",
241
+ modelLabel: "Model",
242
+ effortLabel: "Effort",
243
+ providerDefault: "Default",
244
+ selectModel: "Select model",
245
+ modelsLoading: "Loading models…",
246
+ modelsEmpty: "No models available.",
247
+ effortsEmpty: "This model provides no reasoning effort levels.",
248
+ modelRetry: "Retry",
249
+ modelFailed: "Could not load models: {value}",
250
+ groupFailed: "{name}: {value}",
187
251
  imageGenerate: "Generate image",
188
252
  imageGenerating: "Generating…",
189
253
  imageGenerated: "Generated",
@@ -222,8 +286,10 @@ window.__ModuleLoader__.load({
222
286
  .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)}
223
287
  .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}
224
288
  .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}
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)}
289
+ .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}
290
+ .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)}
291
+ .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}
292
+ .codexModelSelectMenu{overflow:visible}
227
293
  .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)}}
228
294
  @container (max-width:560px){.codexSubscriptionCreditRows{grid-template-columns:1fr}}
229
295
  @container (max-width:480px){.codexSubscriptionAccountRow,.codexSubscriptionSectionHead{align-items:flex-start;flex-direction:column}.codexSubscriptionActions{width:100%}.codexSubscriptionSearchChoices{grid-template-columns:1fr}}
@@ -622,68 +688,288 @@ window.__ModuleLoader__.load({
622
688
  ]
623
689
  });
624
690
  }
625
- function CodexComposerControls({ preference, rpc, t, directory }) {
626
- const [speedOpen, setSpeedOpen] = (0, react.useState)(false);
691
+ function CodexComposerQuota({ preference, rpc, t, directory }) {
627
692
  const preferenceSnapshot = usePreferenceSnapshot(preference);
628
693
  const current = (0, react.useSyncExternalStore)((listener) => directory.subscribe(listener), () => directory.getSnapshot()).current;
629
694
  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
695
  const quotaEnabled = preferenceSnapshot.status === "ready" && preferenceSnapshot.visible && codex;
634
696
  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,
697
+ if (!quotaEnabled || quota === void 0) return null;
698
+ const value = percent(quota.remainingPercent);
699
+ const label = fill(t("quickQuotaStatus"), { value });
700
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
701
+ className: "codexComposerQuota",
702
+ role: "status",
703
+ "aria-label": label,
704
+ title: label,
705
+ children: [value, "%"]
706
+ });
707
+ }
708
+ function CodexModelSelect({ locked, available, directory, load, select, preference, t }) {
709
+ const state = (0, react.useSyncExternalStore)(directory.subscribe, directory.getSnapshot);
710
+ const preferenceSnapshot = usePreferenceSnapshot(preference);
711
+ const [open, setOpen] = (0, react.useState)(false);
712
+ const [pane, setPane] = (0, react.useState)("root");
713
+ const rootRef = (0, react.useRef)(null);
714
+ const triggerRef = (0, react.useRef)(null);
715
+ const id = (0, react.useId)();
716
+ const choices = (0, react.useMemo)(() => state.groups.flatMap((group) => group.models.map((model) => ({
717
+ group,
718
+ model,
719
+ selection: {
720
+ provider: group.id,
721
+ model: model.id,
722
+ ...model.reasoning?.defaultEffort === void 0 ? {} : { reasoningEffort: model.reasoning.defaultEffort }
723
+ }
724
+ }))), [state.groups]);
725
+ const currentChoice = choices.find((choice) => choice.selection.provider === state.current?.provider && choice.selection.model === state.current?.model);
726
+ const reasoning = currentChoice?.model.reasoning;
727
+ const effectiveEffort = state.current?.reasoningEffort ?? reasoning?.defaultEffort;
728
+ const effortLabel = reasoning === void 0 ? void 0 : effectiveEffort === void 0 ? t("providerDefault") : reasoning.efforts.find((level) => level.id === effectiveEffort)?.name ?? effectiveEffort;
729
+ const effortChoices = (0, react.useMemo)(() => reasoning === void 0 ? [] : [...reasoning.defaultEffort === void 0 ? [{
730
+ key: "provider-default",
731
+ effort: void 0,
732
+ label: t("providerDefault")
733
+ }] : [], ...reasoning.efforts.map((effort) => ({
734
+ key: `effort:${effort.id}`,
735
+ effort: effort.id,
736
+ label: effort.name,
737
+ ...effort.description === void 0 ? {} : { description: effort.description }
738
+ }))], [reasoning, t]);
739
+ const modelLabel = currentChoice?.model.name ?? t("selectModel");
740
+ const speedSupported = state.current?.provider === "openai-codex" && supportsCodexFastMode(state.current?.model);
741
+ const speedWritable = preferenceSnapshot.status === "ready" && preferenceSnapshot.writable === true;
742
+ const fast = speedSupported && preferenceSnapshot.speedMode === "fast";
743
+ const busy = state.status === "selecting";
744
+ (0, react.useEffect)(() => {
745
+ if (available) load();
746
+ }, [available, load]);
747
+ (0, react.useEffect)(() => {
748
+ if (!open) return void 0;
749
+ const closeOutside = (event) => {
750
+ if (!rootRef.current?.contains(event.target)) {
751
+ setOpen(false);
752
+ setPane("root");
753
+ }
754
+ };
755
+ document.addEventListener("mousedown", closeOutside);
756
+ return () => document.removeEventListener("mousedown", closeOutside);
757
+ }, [open]);
758
+ (0, react.useEffect)(() => {
759
+ if (!speedSupported && pane === "speed") setPane("root");
760
+ }, [pane, speedSupported]);
761
+ if (!available) return null;
762
+ const close = (restoreFocus = false) => {
763
+ setOpen(false);
764
+ setPane("root");
765
+ if (restoreFocus) queueMicrotask(() => triggerRef.current?.focus());
766
+ };
767
+ const settleSelection = (accepted) => {
768
+ if (accepted) close(true);
769
+ };
770
+ const chooseModel = (selection) => {
771
+ if (state.current?.provider === selection.provider && state.current.model === selection.model) {
772
+ close(true);
773
+ return;
774
+ }
775
+ select(selection).then(settleSelection);
776
+ };
777
+ const chooseEffort = (effort) => {
778
+ if (state.current === null) return;
779
+ if (effectiveEffort === effort) {
780
+ close(true);
781
+ return;
782
+ }
783
+ select({
784
+ provider: state.current.provider,
785
+ model: state.current.model,
786
+ ...effort === void 0 ? {} : { reasoningEffort: effort }
787
+ }).then(settleSelection);
788
+ };
789
+ const chooseSpeed = (speedMode) => {
790
+ close(true);
791
+ preference.set({ [SPEED_MODE_FIELD]: speedMode });
792
+ };
793
+ const option = ({ key, label, description, selected, disabled, onClick }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
794
+ type: "button",
795
+ role: "menuitemradio",
796
+ "aria-checked": selected,
797
+ className: "codexModelSelectOption",
798
+ disabled,
799
+ onClick,
800
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
801
+ className: "codexModelSelectOptionCopy",
802
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
803
+ className: "codexModelSelectOptionName",
804
+ children: label
805
+ }), description === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
806
+ className: "codexModelSelectOptionDescription",
807
+ children: description
808
+ })]
809
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
810
+ className: "codexModelSelectCheck",
811
+ children: selected ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutline16, {}) : null
812
+ })]
813
+ }, key);
814
+ const cell = (target, label, value) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
815
+ type: "button",
816
+ role: "menuitem",
817
+ className: "codexModelSelectCell",
818
+ "data-open": pane === target,
819
+ "aria-haspopup": "menu",
820
+ "aria-expanded": pane === target,
821
+ onClick: () => setPane((current) => current === target ? "root" : target),
822
+ children: [
823
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
824
+ className: "codexModelSelectCellLabel",
825
+ children: label
826
+ }),
827
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
828
+ className: "codexModelSelectCellValue",
829
+ children: value
830
+ }),
831
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, { className: "codexModelSelectCellChevron" })
832
+ ]
833
+ });
834
+ let submenu = null;
835
+ if (pane === "model") submenu = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
836
+ className: "codexModelSelectSubmenu",
837
+ role: "menu",
838
+ "aria-label": t("modelLabel"),
839
+ children: [
840
+ state.status === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
841
+ className: "codexModelSelectStatus",
842
+ children: t("modelsLoading")
843
+ }) : null,
844
+ state.error === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
845
+ className: "codexModelSelectError",
846
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fill(t("modelFailed"), { value: state.error }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
847
+ className: "codexModelSelectRetry",
848
+ type: "button",
849
+ onClick: load,
850
+ children: t("modelRetry")
851
+ })]
852
+ }),
853
+ state.failures.map((failure) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
854
+ className: "codexModelSelectWarning",
855
+ children: fill(t("groupFailed"), {
856
+ name: failure.name,
857
+ value: failure.message
858
+ })
859
+ }, failure.id)),
860
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
861
+ className: "codexModelSelectGroups scrollable",
862
+ children: state.groups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
863
+ className: "codexModelSelectGroup",
864
+ role: "group",
865
+ "aria-labelledby": `${id}-${group.id}`,
866
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
867
+ className: "codexModelSelectGroupTitle",
868
+ id: `${id}-${group.id}`,
869
+ children: group.name
870
+ }), group.models.map((model) => option({
871
+ key: model.id,
872
+ label: model.name,
873
+ description: model.description,
874
+ selected: state.current?.provider === group.id && state.current.model === model.id,
875
+ disabled: busy,
876
+ onClick: () => chooseModel({
877
+ provider: group.id,
878
+ model: model.id
879
+ })
880
+ }))]
881
+ }, group.id))
882
+ }),
883
+ state.status === "ready" && choices.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
884
+ className: "codexModelSelectEmpty",
885
+ children: t("modelsEmpty")
886
+ }) : null
887
+ ]
888
+ });
889
+ else if (pane === "effort") submenu = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
890
+ className: "codexModelSelectSubmenu",
891
+ role: "menu",
892
+ "aria-label": t("effortLabel"),
893
+ children: effortChoices.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
894
+ className: "codexModelSelectEmpty",
895
+ children: t("effortsEmpty")
896
+ }) : effortChoices.map((level) => option({
897
+ key: level.key,
898
+ label: level.label,
899
+ description: level.description,
900
+ selected: effectiveEffort === level.effort,
901
+ disabled: busy,
902
+ onClick: () => chooseEffort(level.effort)
903
+ }))
904
+ });
905
+ else if (pane === "speed") submenu = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
906
+ className: "codexModelSelectSubmenu",
907
+ role: "menu",
908
+ "aria-label": t("speedTitle"),
909
+ children: [option({
910
+ key: SPEED_MODE_STANDARD,
911
+ label: t("speedStandard"),
912
+ description: t("speedStandardHint"),
913
+ selected: !fast,
656
914
  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 });
915
+ onClick: () => chooseSpeed(SPEED_MODE_STANDARD)
916
+ }), option({
917
+ key: SPEED_MODE_FAST,
918
+ label: t("speedFast"),
919
+ description: t("speedFastHint"),
920
+ selected: fast,
921
+ disabled: !speedWritable,
922
+ onClick: () => chooseSpeed(SPEED_MODE_FAST)
923
+ })]
924
+ });
925
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
926
+ className: "codexModelSelect",
927
+ ref: rootRef,
928
+ onKeyDown: (event) => {
929
+ if (event.key !== "Escape" || !open) return;
930
+ event.preventDefault();
931
+ if (pane === "root") close(true);
932
+ else setPane("root");
665
933
  },
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
- }
684
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
685
- className: "codexComposerControls",
686
- children: [quotaView, speed]
934
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
935
+ ref: triggerRef,
936
+ type: "button",
937
+ className: "codexModelSelectTrigger",
938
+ "aria-label": modelLabel,
939
+ "aria-haspopup": "menu",
940
+ "aria-expanded": open,
941
+ "aria-controls": open ? `${id}-menu` : void 0,
942
+ title: modelLabel,
943
+ disabled: locked,
944
+ onClick: () => open ? close() : (setPane("root"), setOpen(true), load()),
945
+ children: [
946
+ fast && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ForwardRef, {
947
+ className: "codexModelSelectBolt",
948
+ "aria-hidden": "true"
949
+ }),
950
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
951
+ className: "codexModelSelectLabel",
952
+ children: modelLabel
953
+ }),
954
+ effortLabel === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
955
+ className: "codexModelSelectEffort",
956
+ children: effortLabel
957
+ }),
958
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: "codexModelSelectChevron" })
959
+ ]
960
+ }), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
961
+ className: "codexModelSelectMenu",
962
+ id: `${id}-menu`,
963
+ role: "menu",
964
+ "aria-label": t("modelMenuAria"),
965
+ "aria-busy": state.status === "loading" || busy,
966
+ children: [
967
+ cell("model", t("modelLabel"), modelLabel),
968
+ reasoning === void 0 ? null : cell("effort", t("effortLabel"), effortLabel),
969
+ speedSupported && cell("speed", t("speedTitle"), t(fast ? "speedFast" : "speedStandard")),
970
+ submenu
971
+ ]
972
+ }) : null]
687
973
  });
688
974
  }
689
975
  function AccountCard({ rpc, t, account, setAccount, onSignedOut }) {
@@ -1149,7 +1435,26 @@ window.__ModuleLoader__.load({
1149
1435
  t,
1150
1436
  directory: ctx.modelDirectories.directoryFor(sessionId).store
1151
1437
  })
1152
- }, CodexComposerControls));
1438
+ }, CodexComposerQuota));
1439
+ const sessions = ctx.get("sessions");
1440
+ ctx.slots.inject("conversation.input.model", () => ctx.slots.register({
1441
+ name: "conversation.input.model",
1442
+ priority: -10,
1443
+ locale: NS,
1444
+ inject: (sessionId) => {
1445
+ const directory = ctx.modelDirectories.directoryFor(sessionId);
1446
+ const available = sessions.subagentAddress(sessionId) === void 0;
1447
+ return {
1448
+ available,
1449
+ directory: directory.store,
1450
+ load: () => {
1451
+ if (available) directory.load();
1452
+ },
1453
+ select: (selection) => available ? directory.select(selection).then(() => true, () => false) : Promise.resolve(false),
1454
+ preference
1455
+ };
1456
+ }
1457
+ }, CodexModelSelect));
1153
1458
  const conversation = ctx.get("conversation");
1154
1459
  ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
1155
1460
  name: "tool.call.toolview",
package/lib/index.js CHANGED
@@ -446,12 +446,13 @@ const supportsCodexFastMode = (modelId) => typeof modelId === "string" && (/^gpt
446
446
  * Preserve pi-ai's native Codex OAuth provider while allowing DSH's generic
447
447
  * PiAiAdapter to pass the access token resolved by the host credential store.
448
448
  *
449
- * PiAiAdapter owns a request-local Models collection without a credential
450
- * store. A pure OAuth provider ignores its `apiKey` request override and fails
451
- * before dispatch with "Provider is not configured". This non-interactive
452
- * bridge teaches that collection how to consume only the already-refreshed
453
- * token for this request; login, refresh, persistence, headers, transport, and
454
- * model behavior remain owned by the original provider.
449
+ * PiAiAdapter owns a request-local Models collection backed by the same DSH
450
+ * credential store as this provider. A pure OAuth provider ignores its
451
+ * `apiKey` request override and otherwise fails before dispatch with "Provider
452
+ * is not configured". This non-interactive bridge teaches that collection how
453
+ * to consume only the already-refreshed token for this request; login, refresh,
454
+ * persistence, headers, transport, and model behavior remain owned by the
455
+ * original provider.
455
456
  */
456
457
  function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0 } = {}) {
457
458
  const provider = createOpenAICodexProvider();
@@ -494,7 +495,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0 } = {
494
495
  streamSimple: (model, context, options) => provider.streamSimple(model, context, withSpeed(model, options))
495
496
  });
496
497
  }
497
- const USER_AGENT = `dsh-codex-subscription/1.1.3`;
498
+ const USER_AGENT = `dsh-codex-subscription/1.1.5`;
498
499
  //#endregion
499
500
  //#region src/codex-search.js
500
501
  const CODEX_SEARCH_PROVIDER_ID = "codex-subscription";
@@ -1120,6 +1121,13 @@ function apply(ctx) {
1120
1121
  });
1121
1122
  const profiles = /* @__PURE__ */ new Map([[PROVIDER, profile]]);
1122
1123
  const resolveAuth = () => authModels.getAuth(PROVIDER);
1124
+ const adapterAuth = Object.freeze({
1125
+ credentials: store,
1126
+ authContext: Object.freeze({
1127
+ env: async () => void 0,
1128
+ fileExists: async () => false
1129
+ })
1130
+ });
1123
1131
  ctx.tools.register(createCodexImageTool({
1124
1132
  getAuth: resolveAuth,
1125
1133
  readCredential: (options) => store.read(PROVIDER, options),
@@ -1137,6 +1145,7 @@ function apply(ctx) {
1137
1145
  if (typeof resolved?.auth.apiKey !== "string" || resolved.auth.apiKey.length === 0) throw new LlmError("ChatGPT subscription is not signed in", "MISSING_CREDENTIAL");
1138
1146
  return resolved.auth.apiKey;
1139
1147
  },
1148
+ auth: adapterAuth,
1140
1149
  resolveAttachments: () => ctx.get?.("attachments")
1141
1150
  });
1142
1151
  ctx.llm.registerAdapter([PROVIDER], adapter);
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "dsh-codex-subscription",
3
- "version": "1.1.3",
4
- "packageManager": "pnpm@11.19.0",
3
+ "version": "1.1.5",
5
4
  "description": "ChatGPT and Codex subscriptions for DeepSeek Harness with OAuth login, image generation, quota, and subscription web search",
6
5
  "type": "module",
7
6
  "main": "./lib/index.js",
@@ -17,6 +16,7 @@
17
16
  "README.md",
18
17
  "README.en.md",
19
18
  "AGENTS.md",
19
+ "compatibility.json",
20
20
  "LICENSE",
21
21
  "SECURITY.md",
22
22
  "THIRD_PARTY_NOTICES.md",
@@ -40,11 +40,6 @@
40
40
  "platform": "web"
41
41
  }
42
42
  },
43
- "scripts": {
44
- "build": "tsdown --config tsdown.config.mjs",
45
- "test": "node --test tests/*.test.mjs",
46
- "check": "pnpm run test && pnpm run build && pnpm pack --pack-destination .artifacts"
47
- },
48
43
  "keywords": [
49
44
  "dsh-plugin",
50
45
  "deepseek",
@@ -79,47 +74,53 @@
79
74
  },
80
75
  "peerDependencies": {
81
76
  "@deepseek-ai/cordis": "4.0.1",
82
- "@deepseek-ai/dsh-api-remotes": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
83
- "@deepseek-ai/dsh-client-connection": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
84
- "@deepseek-ai/dsh-client-locale": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
85
- "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
86
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
87
- "@deepseek-ai/dsh-client-ui-model-selection": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
88
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
89
- "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
90
- "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
91
- "@deepseek-ai/dsh-client-ui-tool": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
92
- "@deepseek-ai/dsh-credentials": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
93
- "@deepseek-ai/dsh-llm": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
94
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
95
- "@deepseek-ai/dsh-settings": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
96
- "@deepseek-ai/dsh-tools": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
97
- "@deepseek-ai/dsh-web": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8",
77
+ "@deepseek-ai/dsh-api-remotes": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
78
+ "@deepseek-ai/dsh-client-connection": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
79
+ "@deepseek-ai/dsh-client-locale": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
80
+ "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
81
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
82
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
83
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
84
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
85
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
86
+ "@deepseek-ai/dsh-client-ui-tool": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
87
+ "@deepseek-ai/dsh-credentials": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
88
+ "@deepseek-ai/dsh-llm": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
89
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
90
+ "@deepseek-ai/dsh-settings": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
91
+ "@deepseek-ai/dsh-tools": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
92
+ "@deepseek-ai/dsh-web": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1",
98
93
  "@deepseek-ai/schemastery": "3.18.1",
99
94
  "@earendil-works/pi-ai": "0.82.1",
100
95
  "react": "^18.2.0"
101
96
  },
102
97
  "devDependencies": {
103
98
  "@deepseek-ai/cordis": "4.0.1",
104
- "@deepseek-ai/dsh-api-remotes": "0.1.0-rc.8",
105
- "@deepseek-ai/dsh-client-connection": "0.1.0-rc.8",
106
- "@deepseek-ai/dsh-client-locale": "0.1.0-rc.8",
107
- "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.8",
108
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.8",
109
- "@deepseek-ai/dsh-client-ui-model-selection": "0.1.0-rc.8",
110
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.8",
111
- "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.8",
112
- "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.8",
113
- "@deepseek-ai/dsh-client-ui-tool": "0.1.0-rc.8",
114
- "@deepseek-ai/dsh-credentials": "0.1.0-rc.8",
115
- "@deepseek-ai/dsh-llm": "0.1.0-rc.8",
116
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.8",
117
- "@deepseek-ai/dsh-settings": "0.1.0-rc.8",
118
- "@deepseek-ai/dsh-tools": "0.1.0-rc.8",
119
- "@deepseek-ai/dsh-web": "0.1.0-rc.8",
99
+ "@deepseek-ai/dsh-api-remotes": "0.1.1-rc.1",
100
+ "@deepseek-ai/dsh-client-connection": "0.1.1-rc.1",
101
+ "@deepseek-ai/dsh-client-locale": "0.1.1-rc.1",
102
+ "@deepseek-ai/dsh-client-runtime": "0.1.1-rc.1",
103
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.1-rc.1",
104
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.1.1-rc.1",
105
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.1-rc.1",
106
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.1-rc.1",
107
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.1-rc.1",
108
+ "@deepseek-ai/dsh-client-ui-tool": "0.1.1-rc.1",
109
+ "@deepseek-ai/dsh-credentials": "0.1.1-rc.1",
110
+ "@deepseek-ai/dsh-llm": "0.1.1-rc.1",
111
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.1-rc.1",
112
+ "@deepseek-ai/dsh-settings": "0.1.1-rc.1",
113
+ "@deepseek-ai/dsh-tools": "0.1.1-rc.1",
114
+ "@deepseek-ai/dsh-web": "0.1.1-rc.1",
120
115
  "@deepseek-ai/schemastery": "3.18.1",
121
116
  "@earendil-works/pi-ai": "0.82.1",
117
+ "@heroicons/react": "2.2.0",
122
118
  "react": "18.3.1",
123
119
  "tsdown": "0.22.2"
120
+ },
121
+ "scripts": {
122
+ "build": "tsdown --config tsdown.config.mjs",
123
+ "test": "node --test tests/*.test.mjs",
124
+ "check": "pnpm run test && pnpm run build && pnpm pack --pack-destination .artifacts"
124
125
  }
125
- }
126
+ }