dsh-codex-subscription 2.1.3-beta.1 → 2.1.3

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/README.en.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <div align="center">
2
2
 
3
- # DSH Codex Subscription
3
+ # DSH Codex Subscription — Use ChatGPT subscriptions in DeepSeek Harness
4
4
 
5
5
  [简体中文](https://github.com/WSL043/dsh-codex-subscription/blob/main/README.md) · **English**
6
6
 
@@ -19,18 +19,20 @@ No OpenAI API key or Codex CLI. Models, search, quota, and image generation stay
19
19
  </div>
20
20
 
21
21
  <p align="center">
22
- <img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/readme-hero-en.webp" width="900" alt="Your Codex subscription inside DSH: models, web search, quota and safe reset, image generation, and Fast mode">
22
+ <img src="docs/assets/codex-subscription-overview-en.webp" width="900" alt="Use ChatGPT and Codex subscriptions in DeepSeek Harness: sign in without an API key, choose models and view remaining quota">
23
23
  </p>
24
24
 
25
25
  ## Three-step start
26
26
 
27
- 1. **Install the plugin.** Run the standard DSH bundle command:
27
+ 1. **Install the plugin.** In newer DSH, open **Plugins → Add plugin** and enter `dsh-codex-subscription`. To select a candidate, enter `package@version`, for example `dsh-codex-subscription@2.1.3-beta.1`. This field does not accept a full terminal command.
28
+
29
+ For older DSH or terminal use, run:
28
30
 
29
31
  ```sh
30
32
  dsh plugin --profile web add dsh-codex-subscription
31
33
  ```
32
34
 
33
- 2. **Sign in.** Restart DSH yourself, open **Settings -> Codex**, and choose browser sign-in. No Codex CLI and no pasted token are required.
35
+ 2. **Sign in.** Follow the installation result; save your work and restart only if requested. Open **Settings -> Codex**, and choose browser sign-in. No Codex CLI and no pasted token are required.
34
36
  3. **Use Codex.** Select a Codex model. Quota, subscription search, image generation, and Fast mode remain inside DSH.
35
37
 
36
38
  DSH-Portable exposes the same standard plugin command, so the command above also applies there. See below for the complete official npm, update, and uninstall routes.
@@ -55,10 +57,10 @@ These capabilities reuse the same local ChatGPT sign-in. Subscription routing fa
55
57
  ## Product screen
56
58
 
57
59
  <p align="center">
58
- <img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/context-settings.png" width="820" alt="2.0.0 account and preference settings: sign-in, quota display and alerts">
60
+ <img src="docs/assets/subscription-account-en.png" width="820" alt="DSH Codex subscription main screen: ChatGPT sign-in, remaining quota and composer preferences">
59
61
  </p>
60
62
 
61
- 2.0.0 groups settings into Account & preferences and Advanced & diagnostics. Screenshots use the Chinese UI, with the account label hidden and scrollable content expanded for readability. [View advanced settings](docs/assets/settings-advanced-2.0.png).
63
+ The actual Account & preferences screen shows sign-in status, subscription quota and composer preferences. Account, quota, balance and time values are demo data, not fixed plan entitlements. Advanced options and optional components are described below.
62
64
 
63
65
  ## Prepare DSH
64
66
 
@@ -134,6 +136,10 @@ Restart DSH manually after installation, then:
134
136
  - Visible errors when subscription routing is unavailable, with no silent paid fallback.
135
137
 
136
138
 
139
+ ### GPT-Reserve (Experimental)
140
+
141
+ When the account’s official catalog advertises `gpt-reserve`, it appears at the end of the model picker as an experimental option. Availability and billing are determined by the service; a successful response does not confirm use of a separate reserve allowance. The composer shows only a matching quota bucket returned by the service, and does not substitute ordinary Codex quota when none is returned.
142
+
137
143
  ### GPT-6 Astra context
138
144
 
139
145
  When the official model catalog exposes GPT-6 Astra, Standard preserves the catalog window, Extended uses 872000 tokens, and Custom accepts 128000–872000 tokens (initially 272000). This limit follows the [official Codex model catalog](https://github.com/openai/codex/blob/6af345407d9c2a568da9d01b6c4b81a9e61495c0/codex-rs/models-manager/models.json#L33-L34), not the API model's total context capacity. These settings only adjust DSH's local context budget; they do not grant model access or guarantee an account's server-side capacity. Actual availability remains subject to the service.
@@ -141,7 +147,7 @@ When the official model catalog exposes GPT-6 Astra, Standard preserves the cata
141
147
  ### Composer quota
142
148
 
143
149
  <p align="center">
144
- <img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/composer-quota.png" width="800" alt="Live DSH composer with GPT-6-Astra, Max reasoning, Fast mode, and remaining quota">
150
+ <img src="docs/assets/composer-quota.png" width="800" alt="Live DSH composer with GPT-6-Astra, Max reasoning, Fast mode, and remaining quota">
145
151
  </p>
146
152
 
147
153
  Live example: GPT-6-Astra with Max (the highest reasoning level) and Fast mode (lightning icon), with remaining quota visible on the left.
@@ -170,14 +176,14 @@ New and edited images return the exact original path on the current DSH host in
170
176
  A new image request does not silently include earlier images. GPT Image 2 can take longer than a normal text turn, and detailed text, exact composition, or repeated-character consistency may still need another pass.
171
177
 
172
178
  <p align="center">
173
- <img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/image-preview-annotations-en.png" width="800" alt="Generated image, region note, and continue editing inside the DSH Image Viewer">
179
+ <img src="docs/assets/image-preview-annotations-en.png" width="800" alt="Generated image, region note, and continue editing inside the DSH Image Viewer">
174
180
  </p>
175
181
 
176
182
  The screenshot above illustrates image viewing and on-image notes; available buttons can vary with the image and installed viewer version.
177
183
 
178
184
  ### Sketch canvas (Beta)
179
185
 
180
- ![Sketch canvas in the Chinese UI: aspect ratio, brushes, shapes, layers and zoom](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-canvas.png)
186
+ ![Sketch canvas in the Chinese UI: aspect ratio, brushes, shapes, layers and zoom](docs/assets/sketch-canvas.png)
181
187
 
182
188
  Use the composer pen button for manual drawing. Selecting `@sketch` only inserts the Agent entry into the composer; the Agent opens the board after you send your drawing request. You can also choose Open in sketch from an enhanced image preview. Attachment intake and removal use the native DSH component.
183
189
 
@@ -189,7 +195,7 @@ The board supports editable shapes and text, native curves, and a side control f
189
195
 
190
196
  | Original sketch | Actual plugin output |
191
197
  | --- | --- |
192
- | ![Mountains and cabin sketch](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-demo-source.png) | ![Watercolor mountain cabin generated from the sketch](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-demo-result.png) |
198
+ | ![Mountains and cabin sketch](docs/assets/sketch-demo-source.png) | ![Watercolor mountain cabin generated from the sketch](docs/assets/sketch-demo-result.png) |
193
199
 
194
200
  The request preserves the mountain and cabin composition while creating a warm watercolor travel illustration with green peaks, an orange roof, a meadow stream and morning light, without the blue outlines. GPT-5.6-Luna made one image-tool call requesting low quality. Luna is the conversation model; the subscription backend determines the actual image model.
195
201
 
@@ -202,7 +208,7 @@ The request preserves the mountain and cabin composition while creating a warm w
202
208
 
203
209
  | Native sketch | Generated result |
204
210
  | --- | --- |
205
- | ![Sketch](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-advanced-source.png) | ![Result](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-advanced-result.png) |
211
+ | ![Sketch](docs/assets/sketch-advanced-source.png) | ![Result](docs/assets/sketch-advanced-result.png) |
206
212
 
207
213
  **Sketch reproduction prompt (reconstructed from the artwork, not the original conversation)**
208
214
 
@@ -228,7 +234,7 @@ Actual results supplied by the user from another computer: Astra draws on a port
228
234
 
229
235
  | Native Astra sketch | GPT-generated oil painting |
230
236
  | --- | --- |
231
- | ![Mona Lisa sketch drawn by Astra](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-mona-lisa-source.png) | ![Mona Lisa oil painting generated from the sketch](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-mona-lisa-result.png) |
237
+ | ![Mona Lisa sketch drawn by Astra](docs/assets/sketch-mona-lisa-source.png) | ![Mona Lisa oil painting generated from the sketch](docs/assets/sketch-mona-lisa-result.png) |
232
238
 
233
239
  Original sketch prompt: `@sketch 用竖版画板画一幅《蒙娜丽莎》` (Draw the Mona Lisa on a portrait canvas.)
234
240
 
@@ -249,7 +255,47 @@ see the [OpenAI Codex Speed documentation](https://learn.chatgpt.com/docs/agent-
249
255
  Opt in under **Advanced & diagnostics**. SSE and DSH subtasks remain the defaults:
250
256
 
251
257
  - **WebSocket** reuses connections and eligible context transfers. Failed handshakes can fall back to SSE; interrupted responses surface an error without automatic replay. Applies to the next request, does not expand context limits, and is not guaranteed to be faster.
252
- - **Codex independent subtasks** reuse your subscription login and the official DSH Codex runtime, without a separate login or CLI setup. They inherit the current subscription model and workspace permissions by default. Enable DSH subtask model selection, configure allowed models and start a new session to specify the child model and reasoning effort in chat. Non-subscription sessions must explicitly select a subscription model. Shared-context subtasks remain with DSH.
258
+ - **Codex independent subtasks** reuse your subscription login and the official DSH Codex runtime, without a separate login; install its optional component in settings. They inherit the current subscription model and workspace permissions by default. Enable DSH subtask model selection, configure allowed models and start a new session to specify the child model and reasoning effort in chat. Non-subscription sessions must explicitly select a subscription model. Shared-context subtasks remain with DSH.
259
+
260
+ <a id="codex-subtask-runtime"></a>
261
+
262
+ ## Optional Codex subtask runtime
263
+
264
+ Subscription chat, images, and native DSH subtasks do not need Codex CLI. Only **Codex independent subtasks (Beta)** require the optional official runtime. The plugin never downloads it in the background.
265
+
266
+ In **Settings → Codex → Advanced → Independent subtasks**, click **Install component**. DSH handles installation; the page shows its stage and offers cancellation before applying. Restart after completion, then choose Codex. Installation does not enable subtasks automatically.
267
+
268
+ ![Optional component management](docs/assets/settings-runtime-current-en.png)
269
+
270
+ For older hosts without the management interface, run this in the target DSH environment, then restart:
271
+
272
+ ```sh
273
+ dsh plugin --profile web add @deepseek-ai/dsh-subagent-codex@0.1.5-rc.2
274
+ ```
275
+
276
+ In the plugin installation UI, enter only `@deepseek-ai/dsh-subagent-codex@0.1.5-rc.2`, not the full command. Select Codex in advanced settings after preparation. Missing or failed preparation does not block subscription chat or the DSH backend. Shared-context subtasks remain in DSH.
277
+
278
+ For offline preparation, install and verify beforehand on the target operating system and architecture, retaining the complete profile dependencies when moving it. The subscription archive or Codex wrapper alone is insufficient without the platform binary. First-time installation cannot complete offline unless dependencies are already prepared. Existing runtime checks and startup do not download anything; model requests still require connectivity. Do not use `--force` to install foreign-platform optional packages.
279
+
280
+ **Upgrading an existing installation:** if you use Codex subtasks, run the preparation command before upgrading this plugin to retain the runtime explicitly in the same profile. A runtime only installed transitively by an older version may be removed during dependency reconciliation. The same command repairs an already-upgraded installation; restart afterwards.
281
+
282
+ The runtime version is pinned separately; subscription updates do not silently upgrade it. This integration uses the official provider package-local CLI, never searches PATH or desktop-private runtimes, and removes the component only after an explicit uninstall request. Shared package caches are not deleted.
283
+
284
+ ### When you no longer need it
285
+
286
+ To disable it, switch back to **DSH** in Advanced settings. The component stays installed so you can enable it again later.
287
+
288
+ To uninstall it, click **Uninstall component** in the same section and confirm. The plugin blocks removal while Codex subtasks are running, switches back to DSH, and uses the official uninstall interface. Restart after completion. On older hosts, run this in a terminal, replacing `web` with the profile where you installed it:
289
+
290
+ ```sh
291
+ dsh plugin --profile web remove @deepseek-ai/dsh-subagent-codex
292
+ ```
293
+
294
+ This removes the optional subtask component, not the subscription plugin. Subscription chat, image generation and native DSH subtasks are unaffected. The package manager may keep the component if another plugin still depends on it.
295
+
296
+ ### Storage and cleanup
297
+
298
+ Uninstalling does not clear shared package caches or guarantee a fixed amount of reclaimed space. DSH or Portable manages those caches centrally; this plugin does not delete shared directories. Sketches, conversation history, generated originals and sign-in data are not package caches. Use their respective management controls when you want to remove them.
253
299
 
254
300
  ## Update and uninstall
255
301
 
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # DSH Codex Subscription
1
+ # DSH Codex Subscription — 在 DeepSeek Harness 使用 ChatGPT 订阅
2
2
 
3
3
  <div align="center">
4
4
 
@@ -20,18 +20,20 @@
20
20
  </div>
21
21
 
22
22
  <p align="center">
23
- <img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/readme-hero.webp" width="900" alt="Codex 订阅直接用在 DSH:订阅模型、联网搜索、额度与安全重置、图片生成和高速模式">
23
+ <img src="docs/assets/codex-subscription-overview.webp" width="900" alt="在 DeepSeek Harness 登录 ChatGPT 并使用 Codex 订阅:无需 API Key,支持模型选择和剩余额度显示">
24
24
  </p>
25
25
 
26
26
  ## 三步开始
27
27
 
28
- 1. **安装插件**:直接运行 DSH 标准 bundle 命令:
28
+ 1. **安装插件**:在新版 DSH 的 **插件 → 添加插件** 中填写 `dsh-codex-subscription`;指定候选版本时填写完整的 `包名@版本`,例如 `dsh-codex-subscription@2.1.3-beta.1`。这个输入框不接受整条终端命令。
29
+
30
+ 旧版 DSH 或偏好终端操作时,才在终端运行:
29
31
 
30
32
  ```sh
31
33
  dsh plugin --profile web add dsh-codex-subscription
32
34
  ```
33
35
 
34
- 2. **登录订阅**:手动重启 DSH,打开 **设置 -> Codex 订阅**,点击浏览器登录。无需 Codex CLI,也不要粘贴 token。
36
+ 2. **登录订阅**:按安装结果提示操作;若提示需要重启,先保存工作再重启。打开 **设置 -> Codex 订阅**,点击浏览器登录。无需 Codex CLI,也不要粘贴 token。
35
37
  3. **开始使用**:在模型选择器中选择 Codex;额度、订阅搜索、图片生成和高速模式都在 DSH 内使用。
36
38
 
37
39
  DSH-Portable 也提供相同的标准插件命令,因此同样使用上面的命令。完整的官方 npm、更新和卸载方式见下文。
@@ -56,10 +58,10 @@ DSH-Portable 也提供相同的标准插件命令,因此同样使用上面的
56
58
  ## 实际界面
57
59
 
58
60
  <p align="center">
59
- <img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/context-settings.png" width="820" alt="2.0.0 账号与偏好:登录、额度、显示模式与提醒">
61
+ <img src="docs/assets/subscription-account.png" width="820" alt="DSH Codex 订阅主界面:ChatGPT 登录、剩余额度与输入框偏好">
60
62
  </p>
61
63
 
62
- 2.0.0 设置分为“账号与偏好”和“高级与诊断”。截图已隐藏账号信息,并展开滚动内容便于阅读;[查看高级页](docs/assets/settings-advanced-2.0.png)。
64
+ 上图为“账号与偏好”主界面,展示登录状态、订阅额度和输入框偏好。截图中的账号、额度、余额与时间均为演示数据,不代表套餐固定权益。高级功能与可选组件见下文。
63
65
 
64
66
  ## 准备 DSH
65
67
 
@@ -135,6 +137,10 @@ dsh --profile web --dump-config
135
137
  - 订阅路由不可用时明确报错,不会静默切换到其他付费路由。
136
138
 
137
139
 
140
+ ### GPT-Reserve(实验性)
141
+
142
+ 账号的官方模型目录提供 `gpt-reserve` 时,模型选择器末尾会出现实验性选项。可用性和扣费归属由服务端决定;请求成功不代表已确认使用独立备用额度。输入框只显示服务端返回的匹配额度桶,未返回时不会借用普通 Codex 额度。
143
+
138
144
  ### GPT-6 Astra 上下文
139
145
 
140
146
  当官方模型目录提供 GPT-6 Astra 时,标准模式保留目录默认窗口;扩展模式使用 872000 Token,自定义模式可设置 128000–872000 Token(初始值为 272000)。该上限依据 [Codex 官方模型目录](https://github.com/openai/codex/blob/6af345407d9c2a568da9d01b6c4b81a9e61495c0/codex-rs/models-manager/models.json#L33-L34),不是 API 模型的总上下文容量。这些设置只调整 DSH 的本地上下文预算,不授予模型访问权限,也不保证账号的服务端容量;实际可用性以服务端为准。
@@ -142,7 +148,7 @@ dsh --profile web --dump-config
142
148
  ### 输入框额度
143
149
 
144
150
  <p align="center">
145
- <img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/composer-quota.png" width="800" alt="DSH 实机输入框:GPT-6-Astra、Max 推理、高速模式和剩余额度">
151
+ <img src="docs/assets/composer-quota.png" width="800" alt="DSH 实机输入框:GPT-6-Astra、Max 推理、高速模式和剩余额度">
146
152
  </p>
147
153
 
148
154
  实机示例:GPT-6-Astra · Max(最高推理档)· 高速模式(闪电标识),左侧直接显示剩余额度。
@@ -169,14 +175,14 @@ ChatGPT 返回可用重置卡时,设置页会把每张卡分别显示为紧凑
169
175
  新的图片请求不会静默带入历史图片。GPT Image 2 可能比文本回复耗时更长,复杂文字、精确构图和连续角色一致性也可能需要再次调整。
170
176
 
171
177
  <p align="center">
172
- <img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/image-preview-annotations.png" width="800" alt="DSH 图片查看器中的生成图、区域备注和继续编辑">
178
+ <img src="docs/assets/image-preview-annotations.png" width="800" alt="DSH 图片查看器中的生成图、区域备注和继续编辑">
173
179
  </p>
174
180
 
175
181
  上图展示图片查看与图上备注的基本交互;具体按钮会随图片和所安装的查看器版本变化。
176
182
 
177
183
  ### 草图画板(Beta)
178
184
 
179
- ![草图画板实机界面:画布比例、笔刷、形状、图层与缩放](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-canvas.png)
185
+ ![草图画板实机界面:画布比例、笔刷、形状、图层与缩放](docs/assets/sketch-canvas.png)
180
186
 
181
187
  点击输入框的草图按钮手动画图。`@sketch` 是 Agent 绘图入口:选择时只填入输入框,发送绘图请求后才由 Agent 打开画板。图片预览中可选择“进入草图”;上传、粘贴和移除附件仍由 DSH 原生组件处理。
182
188
 
@@ -188,7 +194,7 @@ ChatGPT 返回可用重置卡时,设置页会把每张卡分别显示为紧凑
188
194
 
189
195
  | 画板原草图 | 插件实际生成结果 |
190
196
  | --- | --- |
191
- | ![山峰与小屋草图](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-demo-source.png) | ![根据草图生成的水彩山间小屋](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-demo-result.png) |
197
+ | ![山峰与小屋草图](docs/assets/sketch-demo-source.png) | ![根据草图生成的水彩山间小屋](docs/assets/sketch-demo-result.png) |
192
198
 
193
199
  示例要求:保留山峰与小屋的构图,生成温暖的水彩旅行插画,青绿山峰、橙色屋顶、草地小溪与柔和晨光,不保留蓝色线条。此例通过 GPT-5.6-Luna 发起一次图片工具调用,请求低质量;Luna 是对话模型,实际出图型号由订阅后端决定。
194
200
 
@@ -201,7 +207,7 @@ ChatGPT 返回可用重置卡时,设置页会把每张卡分别显示为紧凑
201
207
 
202
208
  | 原生草图 | 实际生成结果 |
203
209
  | --- | --- |
204
- | ![Sketch](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-advanced-source.png) | ![Result](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-advanced-result.png) |
210
+ | ![Sketch](docs/assets/sketch-advanced-source.png) | ![Result](docs/assets/sketch-advanced-result.png) |
205
211
 
206
212
  **草图复现提示词(按原画面整理,非完整原始对话)**
207
213
 
@@ -227,7 +233,7 @@ ChatGPT 返回可用重置卡时,设置页会把每张卡分别显示为紧凑
227
233
 
228
234
  | Astra 原生草图 | GPT 生图:油画效果 |
229
235
  | --- | --- |
230
- | ![Astra 绘制的蒙娜丽莎草图](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-mona-lisa-source.png) | ![草图转换后的蒙娜丽莎油画](https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/sketch-mona-lisa-result.png) |
236
+ | ![Astra 绘制的蒙娜丽莎草图](docs/assets/sketch-mona-lisa-source.png) | ![草图转换后的蒙娜丽莎油画](docs/assets/sketch-mona-lisa-result.png) |
231
237
 
232
238
  草图提示词:`@sketch 用竖版画板画一幅《蒙娜丽莎》`
233
239
 
@@ -248,7 +254,47 @@ ChatGPT 返回可用重置卡时,设置页会把每张卡分别显示为紧凑
248
254
  在 **高级与诊断** 中按需开启,默认仍使用 SSE 和 DSH 子任务:
249
255
 
250
256
  - **WebSocket**:复用连接和可复用的上下文传输;握手失败可回退 SSE,已开始的响应中断会报错,不自动重放。下次请求生效,不增加模型上下文容量,也不保证更快。
251
- - **Codex 独立子任务**:复用订阅登录和官方 DSH Codex 运行时,无需另行登录或配置 CLI。默认继承当前订阅模型及工作区权限。开启 DSH 子任务模型选择、配置允许模型并新建会话后,可在聊天中指定子任务模型与推理档位;非订阅会话需明确选择订阅模型。共享上下文的子任务仍交给 DSH。
257
+ - **Codex 独立子任务**:复用订阅登录和官方 DSH Codex 运行时,无需另行登录;可选组件在高级设置中安装。默认继承当前订阅模型及工作区权限。开启 DSH 子任务模型选择、配置允许模型并新建会话后,可在聊天中指定子任务模型与推理档位;非订阅会话需明确选择订阅模型。共享上下文的子任务仍交给 DSH。
258
+
259
+ <a id="codex-subtask-runtime"></a>
260
+
261
+ ## 可选 Codex 子任务运行时
262
+
263
+ 普通订阅聊天、图片和 DSH 原生子任务不需要 Codex CLI。只有高级设置中的 **Codex 独立子任务(Beta)** 需要额外准备官方运行时,插件不会后台自动下载。
264
+
265
+ 在 **设置 → Codex 订阅 → 高级与诊断 → 独立子任务** 点击 **安装组件**。DSH 负责安装,页面显示当前阶段,可取消尚未应用的安装;完成后重启,再选择 Codex。安装不会自动开启子任务。
266
+
267
+ ![可选组件管理实机界面](docs/assets/settings-runtime-current.png)
268
+
269
+ 旧版宿主没有管理接口时,才在目标 DSH 环境的终端执行,然后重启:
270
+
271
+ ```sh
272
+ dsh plugin --profile web add @deepseek-ai/dsh-subagent-codex@0.1.5-rc.2
273
+ ```
274
+
275
+ 如果使用插件安装页面,在包名框只填 `@deepseek-ai/dsh-subagent-codex@0.1.5-rc.2`,不要粘贴整条命令。安装到订阅插件所在的同一个 profile。之后在高级设置选择 Codex;共享上下文子任务仍由 DSH 处理。准备失败或尚未准备不影响普通订阅聊天,可继续选择 DSH。
276
+
277
+ 离线使用前,应在同系统、同架构的目标环境提前安装并验证运行时,迁移时保留完整的 DSH profile 依赖。只有订阅插件压缩包或 Codex 主包不能代替当前平台的可执行包;未提前准备时,断网无法完成首次安装。已有运行时的检查和启动不需要下载安装,但模型请求本身仍需要联网。不要使用 `--force` 安装其他平台的可选包。
278
+
279
+ **旧版升级**:如果已使用 Codex 独立子任务,请在升级订阅插件前执行上面的准备命令,将运行时显式保留在同一个 profile;仅由旧版间接安装的运行时可能随依赖整理移除。已经升级也可执行同一命令补齐,然后重启。
280
+
281
+ 运行时版本单独固定,不会随订阅插件更新而自动下载新 CLI。现阶段沿用官方 provider 的包内 CLI,不自动查找 PATH,也不复用桌面应用的私有 CLI。只有明确点击卸载才移除组件,安装缓存不由插件清理。
282
+
283
+ ### 不再使用时
284
+
285
+ 只想停用:在高级设置切回 **DSH**,组件仍保留,之后可再次开启。
286
+
287
+ 要卸载:在同一位置点击 **卸载组件** 并确认。插件会检查正在运行的子任务,切回 DSH 后交给官方接口卸载;有任务运行时不能卸载。完成后重启。旧版宿主可在终端执行(将 `web` 替换为实际安装的 profile):
288
+
289
+ ```sh
290
+ dsh plugin --profile web remove @deepseek-ai/dsh-subagent-codex
291
+ ```
292
+
293
+ 卸载的是可选子任务组件,不是订阅插件;普通订阅聊天、生图和 DSH 原生子任务不受影响。若其他插件仍依赖该组件,包管理器可能保留它。
294
+
295
+ ### 存储与清理
296
+
297
+ 卸载不等于清空共享安装缓存,也不能保证释放某个固定大小。安装缓存由 DSH/Portable 统一管理,本插件不直接删除共享目录。草稿、会话记录、生成原图和登录信息不是安装缓存;需要删除时应使用各自的管理入口,不做一键混合清理。
252
298
 
253
299
  ## 更新与卸载
254
300
 
package/lib/client.js CHANGED
@@ -872,6 +872,10 @@ window.__ModuleLoader__.load({
872
872
  "preferences/status",
873
873
  "preferences/models",
874
874
  "preferences/update",
875
+ "runtime/status",
876
+ "runtime/install",
877
+ "runtime/remove",
878
+ "runtime/cancel",
875
879
  "reset-credit/inspect",
876
880
  "reset-credit/prepare",
877
881
  "reset-credit/consume",
@@ -4502,6 +4506,24 @@ window.__ModuleLoader__.load({
4502
4506
  //#endregion
4503
4507
  //#region src/client-locales.js
4504
4508
  const zh = {
4509
+ runtimeLoading: "正在检查组件…",
4510
+ runtimeRestart: "组件已更新,请重启 DSH 后使用。",
4511
+ runtime_installing: "正在通过 DSH 安装组件…",
4512
+ runtime_removing: "正在通过 DSH 卸载组件…",
4513
+ runtime_applying: "正在应用安装结果…",
4514
+ runtimeInstall: "安装组件",
4515
+ runtimeRemove: "卸载组件",
4516
+ runtimeCancel: "取消安装",
4517
+ runtimeKeep: "保留",
4518
+ runtimeConfirmRemove: "确认卸载",
4519
+ runtimeRefresh: "刷新状态",
4520
+ runtimeActive: "有 Codex 子任务正在运行,结束后才能安装或卸载。",
4521
+ runtimeConfirm: "卸载后将切回 DSH 子任务。普通订阅聊天、生图、登录和草稿保留。确定卸载可选组件?",
4522
+ runtimeFailed: "操作未完成。请刷新状态后重试;详细原因可在 DSH 插件管理中查看。",
4523
+ runtimeBuildBlocked: "DSH 拦截了依赖安装脚本。请在官方插件管理中审核后再安装。",
4524
+ runtimeCancelled: "安装已取消,可重新安装。",
4525
+ runtimeUnavailable: "当前宿主未提供组件管理接口,请更新 DSH 或按说明手动管理。",
4526
+ runtimeInstallHint: "此处只管理官方 Codex 子任务组件,由 DSH 负责安装与卸载。安装后不会自动开启子任务;仅切回 DSH 不会卸载组件。",
4505
4527
  compactionTitle: "云端压缩",
4506
4528
  compaction_dsh: "关闭",
4507
4529
  compaction_cloud: "开启",
@@ -4514,6 +4536,11 @@ window.__ModuleLoader__.load({
4514
4536
  connectionHint: "默认 SSE。WebSocket 实验性复用连接与上下文传输;连接失败可回退 SSE。下次请求生效,不扩大上下文容量。",
4515
4537
  subagentBackendHint: "Codex 复用订阅登录和工作区权限;默认继承当前订阅模型。开启 DSH 子任务模型选择并新建会话后,可在聊天中指定允许的订阅模型与推理档位;非订阅会话需指定。共享上下文子任务仍用 DSH。",
4516
4538
  subagentBackendUnavailable: "当前宿主缺少子代理服务,请更新 DSH。",
4539
+ subagentRuntimeMissing: "尚未准备 Codex 子任务运行时,仅影响此选项。普通订阅对话无需安装。",
4540
+ subagentRuntimePrepare: "准备方法(含离线说明)",
4541
+ subagentRuntimeInstalled: "已检测到 Codex 子任务组件;启动时会检查可执行文件。",
4542
+ subagentRuntimeManage: "安装、卸载与存储",
4543
+ subagentRuntimeCacheHint: "卸载后安装缓存可能仍保留,由 DSH 或 Portable 统一管理。此处不会删除登录、草稿或生成图片。",
4517
4544
  sketchRecovered: "已恢复未保存草稿",
4518
4545
  sketchRecoveryFailed: "恢复检查点保存失败,请手动保存或导出草稿。",
4519
4546
  sketchStorageBlocked: "草稿正被其他窗口占用,请关闭其他草图窗口后重试。",
@@ -4930,6 +4957,24 @@ window.__ModuleLoader__.load({
4930
4957
  imageRemoveAnnotation: "删除标注"
4931
4958
  };
4932
4959
  const en = {
4960
+ runtimeLoading: "Checking component…",
4961
+ runtimeRestart: "Component changed. Restart DSH before using it.",
4962
+ runtime_installing: "Installing through DSH…",
4963
+ runtime_removing: "Uninstalling through DSH…",
4964
+ runtime_applying: "Applying installation…",
4965
+ runtimeInstall: "Install component",
4966
+ runtimeRemove: "Uninstall component",
4967
+ runtimeCancel: "Cancel installation",
4968
+ runtimeKeep: "Keep",
4969
+ runtimeConfirmRemove: "Confirm uninstall",
4970
+ runtimeRefresh: "Refresh status",
4971
+ runtimeActive: "Codex subtasks are running. Wait for them to finish before installing or uninstalling.",
4972
+ runtimeConfirm: "Uninstalling switches subtasks back to DSH. Subscription chat, images, sign-in and sketches stay available. Uninstall this optional component?",
4973
+ runtimeFailed: "The operation did not complete. Refresh and retry; see DSH plugin management for details.",
4974
+ runtimeBuildBlocked: "DSH blocked dependency build scripts. Review them in the official plugin manager before installing.",
4975
+ runtimeCancelled: "Installation cancelled. You can try again.",
4976
+ runtimeUnavailable: "This host has no component management interface. Update DSH or use the manual instructions.",
4977
+ runtimeInstallHint: "DSH installs and removes the official Codex subtask component here. Installation does not enable subtasks automatically. Switching to DSH alone does not uninstall it.",
4933
4978
  compactionTitle: "Cloud compaction",
4934
4979
  compaction_dsh: "Off",
4935
4980
  compaction_cloud: "On",
@@ -4942,6 +4987,11 @@ window.__ModuleLoader__.load({
4942
4987
  connectionHint: "SSE by default. Experimental WebSocket reuses connections and context transfers and can fall back to SSE on connection failure. Applies to the next request; context limits stay the same.",
4943
4988
  subagentBackendHint: "Codex reuses subscription login and workspace permissions, inheriting the current subscription model by default. Enable DSH subtask model selection and start a new session to request an allowed subscription model and reasoning effort in chat; other model sessions require an explicit selection. Shared-context subtasks stay in DSH.",
4944
4989
  subagentBackendUnavailable: "Subagent services are unavailable. Update DSH to use this option.",
4990
+ subagentRuntimeMissing: "Codex subtask runtime is not prepared. Subscription chat does not require it.",
4991
+ subagentRuntimePrepare: "Setup and offline instructions",
4992
+ subagentRuntimeInstalled: "Codex subtask component detected; its executable is checked on startup.",
4993
+ subagentRuntimeManage: "Install, uninstall and storage",
4994
+ subagentRuntimeCacheHint: "Package caches may remain after uninstalling. DSH or Portable manages them centrally. Sign-in, sketches and generated images are not deleted here.",
4945
4995
  sketchRecovered: "Unsaved sketch recovered",
4946
4996
  sketchRecoveryFailed: "Recovery checkpoint failed. Save or export your draft.",
4947
4997
  sketchStorageBlocked: "Draft storage is in use. Close other sketch windows and retry.",
@@ -5576,6 +5626,14 @@ window.__ModuleLoader__.load({
5576
5626
  @container (max-width:480px){.codexSubscriptionAccountRow,.codexSubscriptionSectionHead{align-items:flex-start;flex-direction:column}
5577
5627
  .codexSubscriptionActions{width:100%}
5578
5628
  .codexSubscriptionSearchChoices{grid-template-columns:1fr}}
5629
+ .codexSubscriptionRuntime{font-size:12px;line-height:1.6;margin-top:12px;color:var(--dsw-alias-label-secondary)}
5630
+ .codexSubscriptionRuntime summary{cursor:pointer;width:fit-content;color:var(--dsw-alias-label-primary);border-radius:6px}
5631
+ .codexSubscriptionRuntime summary:focus-visible{outline:2px solid currentColor;outline-offset:4px}
5632
+ .codexSubscriptionRuntime p{margin:8px 0}
5633
+ .codexSubscriptionRuntime .codexSubscriptionPreference{flex-wrap:wrap;align-items:flex-start}
5634
+ .codexSubscriptionRuntime .codexSubscriptionPreference>span{flex:1;min-width:180px;font-size:12px;color:var(--dsw-alias-label-secondary)}
5635
+ .codexSubscriptionRuntime button{flex-shrink:0;white-space:nowrap}
5636
+ .codexSubscriptionRuntime code{display:block;overflow-wrap:anywhere;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;user-select:text}
5579
5637
  @media(max-width:640px){.codexSubscriptionCard{padding:14px}}
5580
5638
  `;
5581
5639
  //#endregion
@@ -6712,6 +6770,7 @@ window.__ModuleLoader__.load({
6712
6770
  let modelRefreshStarted = false;
6713
6771
  let disposed = false;
6714
6772
  let subagentBackendAvailable = false;
6773
+ let subagentRuntimeInstalled = false;
6715
6774
  const sameModels = (left, right) => left.length === right.length && left.every((model, index) => JSON.stringify(model) === JSON.stringify(right[index]));
6716
6775
  const nativeSnapshot = () => scope.getSnapshot();
6717
6776
  const read = () => {
@@ -6729,6 +6788,7 @@ window.__ModuleLoader__.load({
6729
6788
  compactionMode: value?.compactionMode === "cloud" ? "cloud" : "dsh",
6730
6789
  subagentBackend: value?.subagentBackend === "codex" ? "codex" : "dsh",
6731
6790
  subagentBackendAvailable,
6791
+ subagentRuntimeInstalled,
6732
6792
  quickQuotaMode: normalizeQuickQuotaMode(value?.[QUICK_QUOTA_MODE_FIELD], value?.[LEGACY_QUICK_QUOTA_FIELD]),
6733
6793
  searchProvider: normalizeSearchProvider(value?.[SEARCH_PROVIDER_FIELD]),
6734
6794
  speedMode: normalizeSpeedMode(value?.[SPEED_MODE_FIELD]),
@@ -6763,6 +6823,7 @@ window.__ModuleLoader__.load({
6763
6823
  });
6764
6824
  const acceptFallback = (value) => {
6765
6825
  subagentBackendAvailable = value?.subagentBackendAvailable === true;
6826
+ subagentRuntimeInstalled = value?.subagentRuntimeInstalled === true;
6766
6827
  if (!modelRefreshStarted) {
6767
6828
  contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
6768
6829
  verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
@@ -6800,6 +6861,7 @@ window.__ModuleLoader__.load({
6800
6861
  const value = unwrap(await rpc.call(CHANNEL, "preferences/status", {}));
6801
6862
  if (current !== generation || disposed) return;
6802
6863
  subagentBackendAvailable = value?.subagentBackendAvailable === true;
6864
+ subagentRuntimeInstalled = value?.subagentRuntimeInstalled === true;
6803
6865
  if (nativeSnapshot().status === "ready") {
6804
6866
  if (!modelRefreshStarted) {
6805
6867
  contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
@@ -7172,12 +7234,19 @@ window.__ModuleLoader__.load({
7172
7234
  //#region src/sidebar-quota.js
7173
7235
  const isDisplayableWindow = (window) => Number.isFinite(window?.remainingPercent) && window.remainingPercent >= 0 && window.remainingPercent <= 100 && Number.isFinite(window?.windowSeconds) && window.windowSeconds > 0;
7174
7236
  const normalized = (value) => String(value ?? "").toLocaleLowerCase("en-US").replaceAll(/[^a-z0-9]+/gu, "-");
7175
- const limitMatchesModel = (limit, model) => {
7237
+ const exactModelLimit = (limit, model) => {
7238
+ const id = normalized(model);
7239
+ return id.length > 0 && [limit?.id, limit?.name].some((value) => typeof value === "string" && normalized(value) === id);
7240
+ };
7241
+ const limitMatchesModel = (limit, model, hasExactLimit) => {
7242
+ if (hasExactLimit) return exactModelLimit(limit, model);
7243
+ if (normalized(model) === "gpt-reserve") return false;
7176
7244
  if (/\bspark\b/u.test(normalized(model))) return /\bspark\b/u.test(normalized(`${limit?.id ?? ""} ${limit?.name ?? ""}`));
7177
7245
  return limit?.id === "codex";
7178
7246
  };
7179
7247
  function selectModelQuotaWindows(usage, model) {
7180
- return (Array.isArray(usage?.rateLimits) ? usage.rateLimits.filter((limit) => limitMatchesModel(limit, model) && Array.isArray(limit.windows)).flatMap((limit) => limit.windows).filter(isDisplayableWindow) : []).map((selected) => ({
7248
+ const hasExactLimit = Array.isArray(usage?.rateLimits) && usage.rateLimits.some((limit) => exactModelLimit(limit, model));
7249
+ return (Array.isArray(usage?.rateLimits) ? usage.rateLimits.filter((limit) => limitMatchesModel(limit, model, hasExactLimit) && Array.isArray(limit.windows)).flatMap((limit) => limit.windows).filter(isDisplayableWindow) : []).map((selected) => ({
7181
7250
  remainingPercent: selected.remainingPercent,
7182
7251
  windowSeconds: selected.windowSeconds,
7183
7252
  ...Number.isSafeInteger(selected.resetsAt) ? { resetsAt: selected.resetsAt } : {},
@@ -7186,7 +7255,7 @@ window.__ModuleLoader__.load({
7186
7255
  }
7187
7256
  //#endregion
7188
7257
  //#region src/version.js
7189
- const PACKAGE_VERSION = "2.1.3-beta.1";
7258
+ const PACKAGE_VERSION = "2.1.3";
7190
7259
  //#endregion
7191
7260
  //#region src/client-recovery.js
7192
7261
  async function recoveryCall(rpc, endpoint, payload = {}, timeoutMs = 1e4) {
@@ -8043,6 +8112,158 @@ window.__ModuleLoader__.load({
8043
8112
  ] });
8044
8113
  }
8045
8114
  //#endregion
8115
+ //#region src/client-runtime-management.jsx
8116
+ function RuntimeManagement({ rpc, preference, t }) {
8117
+ const [state, setState] = (0, react.useState)();
8118
+ const [error, setError] = (0, react.useState)(false);
8119
+ const [sending, setSending] = (0, react.useState)(false);
8120
+ const [confirm, setConfirm] = (0, react.useState)(false);
8121
+ const alive = (0, react.useRef)(false);
8122
+ const busy = [
8123
+ "installing",
8124
+ "removing",
8125
+ "applying"
8126
+ ].includes(state?.phase);
8127
+ const read = async () => {
8128
+ try {
8129
+ const result = await rpc.call(CHANNEL, "runtime/status", {});
8130
+ if (!alive.current) return;
8131
+ if (!result.ok) {
8132
+ setError(true);
8133
+ return;
8134
+ }
8135
+ setState(result.value);
8136
+ setError(false);
8137
+ } catch {
8138
+ if (alive.current) setError(true);
8139
+ }
8140
+ };
8141
+ (0, react.useEffect)(() => {
8142
+ alive.current = true;
8143
+ read();
8144
+ return () => {
8145
+ alive.current = false;
8146
+ };
8147
+ }, [rpc]);
8148
+ (0, react.useEffect)(() => {
8149
+ if (!busy) return;
8150
+ let stopped = false, timer;
8151
+ const poll = async () => {
8152
+ await read();
8153
+ if (!stopped) timer = setTimeout(poll, 1500);
8154
+ };
8155
+ timer = setTimeout(poll, 1500);
8156
+ return () => {
8157
+ stopped = true;
8158
+ clearTimeout(timer);
8159
+ };
8160
+ }, [busy, rpc]);
8161
+ const act = async (action) => {
8162
+ if (sending) return;
8163
+ setSending(true);
8164
+ setError(false);
8165
+ setConfirm(false);
8166
+ try {
8167
+ const result = await rpc.call(CHANNEL, `runtime/${action}`, {});
8168
+ if (!alive.current) return;
8169
+ if (!result.ok) {
8170
+ await read();
8171
+ if (alive.current) setError(true);
8172
+ return;
8173
+ }
8174
+ setState(result.value);
8175
+ if (action === "remove") preference.load();
8176
+ } catch {
8177
+ if (alive.current) setError(true);
8178
+ } finally {
8179
+ if (alive.current) setSending(false);
8180
+ }
8181
+ };
8182
+ const locked = sending || busy || state?.restartRequired || state?.active > 0;
8183
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8184
+ className: "codexSubscriptionRuntime",
8185
+ children: [
8186
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8187
+ className: "codexSubscriptionPreference",
8188
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8189
+ role: "status",
8190
+ children: t(!state ? "runtimeLoading" : state.restartRequired ? "runtimeRestart" : busy ? `runtime_${state.phase}` : state.installed ? "subagentRuntimeInstalled" : "subagentRuntimeMissing")
8191
+ }), state?.available ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8192
+ type: "button",
8193
+ variant: "outline",
8194
+ disabled: locked || state.installed && !state.removable,
8195
+ onClick: () => state.installed ? setConfirm(true) : void act("install"),
8196
+ children: t(state.installed ? "runtimeRemove" : "runtimeInstall")
8197
+ }) : null]
8198
+ }),
8199
+ state?.active > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("runtimeActive") }) : null,
8200
+ busy && state.phase === "installing" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8201
+ type: "button",
8202
+ variant: "outline",
8203
+ disabled: sending,
8204
+ onClick: () => {
8205
+ act("cancel");
8206
+ },
8207
+ children: t("runtimeCancel")
8208
+ }) : null,
8209
+ confirm ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8210
+ role: "group",
8211
+ "aria-label": t("runtimeRemove"),
8212
+ children: [
8213
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("runtimeConfirm") }),
8214
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8215
+ type: "button",
8216
+ variant: "outline",
8217
+ onClick: () => setConfirm(false),
8218
+ children: t("runtimeKeep")
8219
+ }),
8220
+ " ",
8221
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8222
+ type: "button",
8223
+ variant: "outline",
8224
+ disabled: locked,
8225
+ onClick: () => {
8226
+ act("remove");
8227
+ },
8228
+ children: t("runtimeConfirmRemove")
8229
+ })
8230
+ ]
8231
+ }) : null,
8232
+ error || state?.phase === "failed" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8233
+ role: "alert",
8234
+ children: t(state?.error === "build-blocked" ? "runtimeBuildBlocked" : "runtimeFailed")
8235
+ }) : null,
8236
+ state?.phase === "cancelled" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8237
+ role: "status",
8238
+ children: t("runtimeCancelled")
8239
+ }) : null,
8240
+ !busy ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
8241
+ type: "button",
8242
+ variant: "outline",
8243
+ disabled: sending,
8244
+ onClick: () => {
8245
+ read();
8246
+ preference.load();
8247
+ },
8248
+ children: t("runtimeRefresh")
8249
+ }) : null,
8250
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [
8251
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: t("subagentRuntimeManage") }),
8252
+ state && !state.available ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("runtimeUnavailable") }) : null,
8253
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("runtimeInstallHint") }),
8254
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: "@deepseek-ai/dsh-subagent-codex@0.1.5-rc.2" }),
8255
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("subagentRuntimeCacheHint") }),
8256
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
8257
+ href: "https://github.com/WSL043/dsh-codex-subscription/blob/main/README.md#codex-subtask-runtime",
8258
+ target: "_blank",
8259
+ rel: "noreferrer",
8260
+ children: t("subagentRuntimePrepare")
8261
+ })
8262
+ ] })
8263
+ ]
8264
+ });
8265
+ }
8266
+ //#endregion
8046
8267
  //#region src/context-draft-state.js
8047
8268
  const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value ?? {}, key);
8048
8269
  /**
@@ -8314,7 +8535,7 @@ window.__ModuleLoader__.load({
8314
8535
  ]
8315
8536
  });
8316
8537
  }
8317
- function PreferencesCard({ preference, t, section = "display" }) {
8538
+ function PreferencesCard({ preference, rpc, t, section = "display" }) {
8318
8539
  const snapshot = usePreferenceSnapshot(preference);
8319
8540
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8320
8541
  className: section === "advanced" ? "codexSubscriptionAdvancedPreferences" : "codexSubscriptionCard codexSubscriptionPreferencesCard",
@@ -8411,10 +8632,10 @@ window.__ModuleLoader__.load({
8411
8632
  })]
8412
8633
  })
8413
8634
  }),
8414
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
8635
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
8415
8636
  className: "codexSubscriptionCard codexSubscriptionPreferencesCard",
8416
8637
  "aria-label": t("subagentBackendTitle"),
8417
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8638
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8418
8639
  className: "codexSubscriptionPreference",
8419
8640
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8420
8641
  className: "codexSubscriptionPreferenceCopy",
@@ -8440,14 +8661,18 @@ window.__ModuleLoader__.load({
8440
8661
  type: "radio",
8441
8662
  name: "codex-subagent-backend",
8442
8663
  checked: snapshot.subagentBackend === value,
8443
- disabled: !snapshot.writable || !snapshot.subagentBackendAvailable,
8664
+ disabled: !snapshot.writable || !snapshot.subagentBackendAvailable || value === "codex" && !snapshot.subagentRuntimeInstalled,
8444
8665
  onChange: () => {
8445
8666
  preference.set({ subagentBackend: value });
8446
8667
  }
8447
8668
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(`subagentBackend_${value}`) })]
8448
8669
  }, value))
8449
8670
  })]
8450
- })
8671
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RuntimeManagement, {
8672
+ rpc,
8673
+ preference,
8674
+ t
8675
+ })]
8451
8676
  })
8452
8677
  ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuickQuotaPreference, {
8453
8678
  preference,
@@ -9493,6 +9718,7 @@ window.__ModuleLoader__.load({
9493
9718
  preference
9494
9719
  }, resetKey),
9495
9720
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PreferencesCard, {
9721
+ rpc,
9496
9722
  preference,
9497
9723
  t
9498
9724
  })
@@ -9505,6 +9731,7 @@ window.__ModuleLoader__.load({
9505
9731
  hidden: tab !== "advanced",
9506
9732
  children: [
9507
9733
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PreferencesCard, {
9734
+ rpc,
9508
9735
  preference,
9509
9736
  t,
9510
9737
  section: "advanced"
package/lib/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { createRequire } from "node:module";
1
2
  import { createHash, randomBytes, randomUUID } from "node:crypto";
2
3
  import { closeOpenAICodexWebSocketSessions, resetOpenAICodexWebSocketDebugStats } from "@earendil-works/pi-ai/api/openai-codex-responses";
3
4
  import { execFile, spawn } from "node:child_process";
@@ -9,6 +10,9 @@ import { HttpsProxyAgent } from "https-proxy-agent";
9
10
  import WebSocket from "ws";
10
11
  import { clientRequestSchema } from "@deepseek-ai/dsh-client-connection";
11
12
  import { lstat, mkdir, open, readFile, rename, rm, stat } from "node:fs/promises";
13
+ import { constants, readFileSync } from "node:fs";
14
+ import { dirname, join, resolve } from "node:path";
15
+ import { pathToFileURL } from "node:url";
12
16
  import { defineTool } from "@deepseek-ai/dsh-tools";
13
17
  import * as dshCredentials from "@deepseek-ai/dsh-credentials";
14
18
  import { dshHomePath, resolveDshHome } from "@deepseek-ai/dsh-home-paths";
@@ -18,8 +22,6 @@ import z from "@deepseek-ai/schemastery";
18
22
  import { openaiCodexProvider as createOpenAICodexProvider } from "@earendil-works/pi-ai/providers/openai-codex";
19
23
  import { createModels } from "@earendil-works/pi-ai";
20
24
  import { WebError } from "@deepseek-ai/dsh-web";
21
- import { constants } from "node:fs";
22
- import { dirname, join, resolve } from "node:path";
23
25
  //#region src/image-models.js
24
26
  const DEFAULT_IMAGE_MODEL = "gpt-image-2";
25
27
  const IMAGE_MODELS = Object.freeze({
@@ -875,6 +877,10 @@ const RPC_ENDPOINTS = Object.freeze([
875
877
  "preferences/status",
876
878
  "preferences/models",
877
879
  "preferences/update",
880
+ "runtime/status",
881
+ "runtime/install",
882
+ "runtime/remove",
883
+ "runtime/cancel",
878
884
  "reset-credit/inspect",
879
885
  "reset-credit/prepare",
880
886
  "reset-credit/consume",
@@ -1048,6 +1054,45 @@ function authenticatedSubagentChild(child, { Transport, getTokens, thread, signa
1048
1054
  } });
1049
1055
  }
1050
1056
  //#endregion
1057
+ //#region src/subagent-runtime.js
1058
+ const SUBAGENT_RUNTIME_PACKAGE = "@deepseek-ai/dsh-subagent-codex";
1059
+ const SUBAGENT_RUNTIME_VERSION = "0.1.5-rc.2";
1060
+ const require = createRequire(import.meta.url);
1061
+ const execute = promisify(execFile);
1062
+ function inspectSubagentRuntime(resolve = require.resolve) {
1063
+ try {
1064
+ const manifestPath = resolve(`${SUBAGENT_RUNTIME_PACKAGE}/package.json`);
1065
+ if (JSON.parse(readFileSync(manifestPath, "utf8")).version !== "0.1.5-rc.2") return { installed: false };
1066
+ return { installed: true };
1067
+ } catch {
1068
+ return { installed: false };
1069
+ }
1070
+ }
1071
+ async function loadSubagentRuntime({ resolve: resolve$1 = require.resolve, run = execute, importModule = (url) => import(url) } = {}) {
1072
+ if (!inspectSubagentRuntime(resolve$1).installed) throw new Error("Codex subtask runtime is not prepared");
1073
+ const entry = resolve$1(SUBAGENT_RUNTIME_PACKAGE);
1074
+ const providerRequire = createRequire(entry);
1075
+ const codexManifestPath = providerRequire.resolve("@openai/codex/package.json");
1076
+ const codex = JSON.parse(readFileSync(codexManifestPath, "utf8"));
1077
+ if (codex.version !== "0.153.4" || typeof codex.bin?.codex !== "string") throw new Error("Codex subtask runtime version is unsupported");
1078
+ const wrapper = resolve(dirname(codexManifestPath), codex.bin.codex);
1079
+ try {
1080
+ const { stdout } = await run(process.execPath, [wrapper, "--version"], {
1081
+ timeout: 1e4,
1082
+ maxBuffer: 4096,
1083
+ windowsHide: true
1084
+ });
1085
+ if (stdout.trim() !== "codex-cli 0.153.4") throw new Error("Unexpected CLI version");
1086
+ } catch {
1087
+ throw new Error("Codex subtask runtime is incomplete; prepare it for this platform");
1088
+ }
1089
+ const [official, { JsonRpcLineTransport: Transport }] = await Promise.all([importModule(pathToFileURL(entry).href), importModule(pathToFileURL(providerRequire.resolve("@deepseek-ai/dsh-sdk-protocol")).href)]);
1090
+ return {
1091
+ official,
1092
+ Transport
1093
+ };
1094
+ }
1095
+ //#endregion
1051
1096
  //#region src/subagent-backend.js
1052
1097
  const SUBAGENT_PROVIDER = "codex-subscription-subagent";
1053
1098
  const MODES = /* @__PURE__ */ new Set([
@@ -1086,7 +1131,7 @@ function subagentThreadPolicy(parent, policy, requested = {}) {
1086
1131
  };
1087
1132
  }
1088
1133
  /** Reuse the official DSH process/turn provider; keep only subscription auth here. */
1089
- function createSubscriptionSubagent({ ctx, nativeHome, resolveAuth, store, refresh, loadRuntime }) {
1134
+ function createSubscriptionSubagent({ ctx, nativeHome, resolveAuth, store, refresh, loadRuntime, maintenance = () => false }) {
1090
1135
  let runtime;
1091
1136
  const load = () => runtime ??= loadRuntime().catch((error) => {
1092
1137
  runtime = void 0;
@@ -1107,6 +1152,7 @@ function createSubscriptionSubagent({ ctx, nativeHome, resolveAuth, store, refre
1107
1152
  inheritsParentContext: false,
1108
1153
  async start(request) {
1109
1154
  if (disposed) throw new Error("Codex subagent is unavailable");
1155
+ if (maintenance()) throw new Error("Codex subtask component is being changed; restart DSH after completion");
1110
1156
  const controller = new AbortController();
1111
1157
  active.add(controller);
1112
1158
  const signal = AbortSignal.any([request.signal, controller.signal]);
@@ -1178,7 +1224,11 @@ function createSubscriptionSubagent({ ctx, nativeHome, resolveAuth, store, refre
1178
1224
  }
1179
1225
  }
1180
1226
  },
1181
- prepare: load,
1227
+ activeCount: () => active.size,
1228
+ prepare: () => {
1229
+ if (maintenance()) return Promise.reject(/* @__PURE__ */ new Error("Restart DSH after changing the Codex subtask component"));
1230
+ return load();
1231
+ },
1182
1232
  dispose() {
1183
1233
  disposed = true;
1184
1234
  for (const controller of active) controller.abort();
@@ -1252,11 +1302,104 @@ function createSubagentBackendSwitcher({ entries, prepare, persist }) {
1252
1302
  }
1253
1303
  };
1254
1304
  }
1255
- async function loadSubagentRuntime() {
1256
- const [official, { JsonRpcLineTransport: Transport }] = await Promise.all([import("@deepseek-ai/dsh-subagent-codex"), import("@deepseek-ai/dsh-sdk-protocol")]);
1305
+ //#endregion
1306
+ //#region src/runtime-management.js
1307
+ function createRuntimeManagement({ manager, inspect, active, selectDsh }) {
1308
+ let operation;
1309
+ let state = {
1310
+ phase: "idle",
1311
+ restartRequired: false
1312
+ };
1313
+ const supported = (value) => [
1314
+ "listBundles",
1315
+ "installBundle",
1316
+ "removeBundle",
1317
+ "cancelInstall"
1318
+ ].every((key) => typeof value?.[key] === "function");
1319
+ const status = async () => {
1320
+ const host = manager();
1321
+ let bundle;
1322
+ let available = supported(host);
1323
+ try {
1324
+ if (available) bundle = (await host.listBundles()).find((value) => value.name === SUBAGENT_RUNTIME_PACKAGE);
1325
+ } catch {
1326
+ available = false;
1327
+ }
1328
+ return {
1329
+ ...state,
1330
+ available,
1331
+ installed: inspect().installed,
1332
+ removable: available && bundle?.installed === true && !bundle.readOnlyReason,
1333
+ active: active()
1334
+ };
1335
+ };
1336
+ const start = async (action) => {
1337
+ if (!["install", "remove"].includes(action)) throw Error("invalid-action");
1338
+ if (operation) throw Error("busy");
1339
+ if (state.restartRequired) throw Error("restart-required");
1340
+ if (active() > 0) throw Error("active-tasks");
1341
+ const host = manager();
1342
+ if (!supported(host)) throw Error("unavailable");
1343
+ const requestId = randomUUID();
1344
+ const current = {
1345
+ action,
1346
+ requestId,
1347
+ host
1348
+ };
1349
+ operation = current;
1350
+ state = {
1351
+ phase: action === "install" ? "installing" : "removing",
1352
+ restartRequired: false
1353
+ };
1354
+ current.done = (async () => {
1355
+ try {
1356
+ if (action === "remove") {
1357
+ const bundle = (await host.listBundles()).find((value) => value.name === SUBAGENT_RUNTIME_PACKAGE);
1358
+ if (!bundle?.installed || bundle.readOnlyReason) throw Error("not-removable");
1359
+ await selectDsh();
1360
+ }
1361
+ const result = action === "install" ? await host.installBundle(`${SUBAGENT_RUNTIME_PACKAGE}@${SUBAGENT_RUNTIME_VERSION}`, {
1362
+ enabled: false,
1363
+ requestId
1364
+ }) : await host.removeBundle(SUBAGENT_RUNTIME_PACKAGE);
1365
+ if (result.application === "cancelled") state = {
1366
+ phase: "cancelled",
1367
+ restartRequired: false
1368
+ };
1369
+ else if (["applied", "restart-required"].includes(result.application)) state = {
1370
+ phase: "done",
1371
+ restartRequired: true
1372
+ };
1373
+ else state = {
1374
+ phase: "failed",
1375
+ restartRequired: false,
1376
+ error: result.packageResult?.kind ?? result.error?.code ?? "operation-error"
1377
+ };
1378
+ } catch (error) {
1379
+ state = {
1380
+ phase: "failed",
1381
+ restartRequired: false,
1382
+ error: error.message === "not-removable" ? "not-removable" : "operation-error"
1383
+ };
1384
+ } finally {
1385
+ operation = void 0;
1386
+ }
1387
+ })();
1388
+ return status();
1389
+ };
1257
1390
  return {
1258
- official,
1259
- Transport
1391
+ status,
1392
+ start,
1393
+ blocked: () => operation !== void 0 || state.restartRequired,
1394
+ progress(value) {
1395
+ if (operation?.action === "install" && value.requestId === operation.requestId && value.phase === "applying") state.phase = "applying";
1396
+ },
1397
+ async cancel() {
1398
+ const current = operation;
1399
+ if (current?.action !== "install") return status();
1400
+ if ((await current.host.cancelInstall(current.requestId)).status === "cancelled") await current.done;
1401
+ return status();
1402
+ }
1260
1403
  };
1261
1404
  }
1262
1405
  //#endregion
@@ -2644,7 +2787,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
2644
2787
  Object.freeze(["0.82.1", "0.85.1"]);
2645
2788
  //#endregion
2646
2789
  //#region src/version.js
2647
- const PACKAGE_VERSION = "2.1.3-beta.1";
2790
+ const PACKAGE_VERSION = "2.1.3";
2648
2791
  const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
2649
2792
  //#endregion
2650
2793
  //#region src/model-catalog.js
@@ -2689,7 +2832,8 @@ function unsupportedCapabilities(value) {
2689
2832
  function visibleModel(value) {
2690
2833
  if (!record$4(value)) return void 0;
2691
2834
  const id = nonEmpty$2(value.slug);
2692
- if (id === void 0 || value.visibility !== "list") return void 0;
2835
+ const reserve = id === "gpt-reserve" && ["list", "hide"].includes(value.visibility);
2836
+ if (id === void 0 || value.visibility !== "list" && !reserve) return void 0;
2693
2837
  const supported = Array.isArray(value.supported_reasoning_levels) ? value.supported_reasoning_levels : [];
2694
2838
  const input = Array.isArray(value.input_modalities) ? value.input_modalities.filter((item) => ["text", "image"].includes(item)) : ["text", "image"];
2695
2839
  const unsupported = unsupportedCapabilities({
@@ -2699,7 +2843,7 @@ function visibleModel(value) {
2699
2843
  return {
2700
2844
  ...Object.keys(unsupported).length ? { unsupported } : {},
2701
2845
  id,
2702
- name: nonEmpty$2(value.display_name) ?? id,
2846
+ name: reserve ? "GPT-Reserve (Experimental)" : nonEmpty$2(value.display_name) ?? id,
2703
2847
  description: nonEmpty$2(value.description),
2704
2848
  priority: Number.isFinite(value.priority) ? value.priority : 0,
2705
2849
  input: input.length > 0 ? input : ["text"],
@@ -2719,7 +2863,7 @@ function visibleModel(value) {
2719
2863
  function parseOfficialModelCatalog(value) {
2720
2864
  if (!record$4(value) || !Array.isArray(value.models)) throw new Error("Codex returned a malformed model catalog");
2721
2865
  const seen = /* @__PURE__ */ new Set();
2722
- return value.models.map(visibleModel).filter((model) => model !== void 0 && !seen.has(model.id) && seen.add(model.id)).sort((left, right) => right.priority - left.priority);
2866
+ return value.models.map(visibleModel).filter((model) => model !== void 0 && !seen.has(model.id) && seen.add(model.id)).sort((left, right) => Number(left.id === "gpt-reserve") - Number(right.id === "gpt-reserve") || right.priority - left.priority);
2723
2867
  }
2724
2868
  function mergeModel(baseModels, remote) {
2725
2869
  const base = baseModels.find((model) => model.id === remote.id) ?? baseModels.find((model) => model.id !== "gpt-5.3-codex-spark") ?? baseModels[0];
@@ -4693,8 +4837,31 @@ const publicError = (code, message) => ({
4693
4837
  details: { issues: [] }
4694
4838
  }
4695
4839
  });
4696
- function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditService, preferences, diagnosticsReader, modelCatalog, originalImages, resolveInheritedOriginal, closeConnections }) {
4840
+ function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditService, preferences, runtimeManagement, diagnosticsReader, modelCatalog, originalImages, resolveInheritedOriginal, closeConnections }) {
4697
4841
  return async (endpoint, payload, signal) => {
4842
+ if ([
4843
+ "runtime/status",
4844
+ "runtime/install",
4845
+ "runtime/remove",
4846
+ "runtime/cancel"
4847
+ ].includes(endpoint)) try {
4848
+ signal.throwIfAborted();
4849
+ if (!runtimeManagement) return publicError("unavailable", "Runtime management is unavailable");
4850
+ const action = endpoint.split("/")[1];
4851
+ return {
4852
+ ok: true,
4853
+ value: action === "status" ? await runtimeManagement.status() : action === "cancel" ? await runtimeManagement.cancel() : await runtimeManagement.start(action)
4854
+ };
4855
+ } catch (error) {
4856
+ if (signal.aborted) throw error;
4857
+ const code = [
4858
+ "busy",
4859
+ "active-tasks",
4860
+ "restart-required",
4861
+ "unavailable"
4862
+ ].includes(error.message) ? error.message : "operation-error";
4863
+ return publicError(code, code);
4864
+ }
4698
4865
  if (endpoint === "image/original/chunk") try {
4699
4866
  signal.throwIfAborted();
4700
4867
  if (typeof payload?.sessionId !== "string" || payload.sessionId.length === 0 || payload.sessionId.length > 512 || typeof payload?.assetId !== "string" || !ORIGINAL_IMAGE_ID_PATTERN.test(payload.assetId) || !Number.isSafeInteger(payload?.offset) || payload.offset < 0 || payload.offset % 4194304 !== 0) return publicError("invalid-input", "Invalid original image request");
@@ -4915,6 +5082,16 @@ function apply(ctx) {
4915
5082
  const baseProvider = createOpenAICodexProvider();
4916
5083
  let resolveAuth = async () => void 0;
4917
5084
  let subagentBackend;
5085
+ const runtimeManagement = createRuntimeManagement({
5086
+ manager: () => ctx.get?.("pluginManager"),
5087
+ inspect: inspectSubagentRuntime,
5088
+ active: () => subagentBackend?.activeCount() ?? 0,
5089
+ selectDsh: async () => {
5090
+ if (subagentBackend) await subagentBackend.select("dsh");
5091
+ else await settings.update({ subagentBackend: "dsh" });
5092
+ }
5093
+ });
5094
+ ctx.effect(() => ctx.on?.("plugin-manager/install-state", (value) => runtimeManagement.progress(value)));
4918
5095
  const modelCatalog = createOfficialModelCatalog({
4919
5096
  getAuth: (options) => resolveAuth(options),
4920
5097
  readCredential: (options) => store.read(PROVIDER, options),
@@ -4953,6 +5130,7 @@ function apply(ctx) {
4953
5130
  connectionMode: settings.get().connectionMode ?? "sse",
4954
5131
  subagentBackend: settings.get().subagentBackend ?? "dsh",
4955
5132
  subagentBackendAvailable: subagentBackend !== void 0,
5133
+ subagentRuntimeInstalled: inspectSubagentRuntime().installed,
4956
5134
  ...readCapabilitySettings(settings.get()),
4957
5135
  [QUICK_QUOTA_MODE_FIELD]: normalizeQuickQuotaMode(settings.get()[QUICK_QUOTA_MODE_FIELD], settings.get()[LEGACY_QUICK_QUOTA_FIELD]),
4958
5136
  [SEARCH_PROVIDER_FIELD]: settings.get()[SEARCH_PROVIDER_FIELD],
@@ -5019,7 +5197,8 @@ function apply(ctx) {
5019
5197
  resolveAuth,
5020
5198
  store,
5021
5199
  refresh: (credential) => network.run("oauth", () => baseProvider.auth.oauth.refresh(credential)),
5022
- loadRuntime: loadSubagentRuntime
5200
+ loadRuntime: loadSubagentRuntime,
5201
+ maintenance: runtimeManagement.blocked
5023
5202
  });
5024
5203
  scoped.subagents.registerProvider(instance.provider);
5025
5204
  const switcher = createSubagentBackendSwitcher({
@@ -5040,7 +5219,10 @@ function apply(ctx) {
5040
5219
  throw error;
5041
5220
  }
5042
5221
  };
5043
- subagentBackend = { select };
5222
+ subagentBackend = {
5223
+ select,
5224
+ activeCount: instance.activeCount
5225
+ };
5044
5226
  const sync = (value) => {
5045
5227
  const mode = value.subagentBackend ?? "dsh";
5046
5228
  if (mode !== requested) select(mode).catch(() => scoped.logger.warn("Could not switch the subscription subagent backend"));
@@ -5185,6 +5367,7 @@ function apply(ctx) {
5185
5367
  usageReader,
5186
5368
  resetCreditService,
5187
5369
  preferences,
5370
+ runtimeManagement,
5188
5371
  diagnosticsReader: () => createSubscriptionDiagnostics({
5189
5372
  auth,
5190
5373
  preferences,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-codex-subscription",
3
- "version": "2.1.3-beta.1",
3
+ "version": "2.1.3",
4
4
  "description": "Use ChatGPT and Codex subscriptions in DeepSeek Harness with OAuth, quota, safe resets, web search, images, and Fast mode",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -92,7 +92,8 @@
92
92
  "@deepseek-ai/schemastery": "3.18.1 || ^3.18.2",
93
93
  "@earendil-works/pi-ai": "0.82.1 || 0.85.1",
94
94
  "react": "^18.2.0",
95
- "react-dom": "^18.2.0"
95
+ "react-dom": "^18.2.0",
96
+ "@deepseek-ai/dsh-subagent-codex": "0.1.5-rc.2"
96
97
  },
97
98
  "devDependencies": {
98
99
  "@deepseek-ai/cordis": "4.0.2",
@@ -120,16 +121,18 @@
120
121
  "fake-indexeddb": "6.2.5",
121
122
  "react": "18.3.1",
122
123
  "react-dom": "18.3.1",
123
- "tsdown": "0.22.2"
124
+ "tsdown": "0.22.2",
125
+ "@deepseek-ai/dsh-subagent-codex": "0.1.5-rc.2"
124
126
  },
125
127
  "dependencies": {
126
128
  "@deepseek-ai/dsh-home-paths": "0.1.1-rc.2",
127
129
  "https-proxy-agent": "7.0.6",
128
130
  "ws": "8.21.3"
129
131
  },
130
- "optionalDependencies": {
131
- "@deepseek-ai/dsh-sdk-protocol": "0.1.5-rc.2",
132
- "@deepseek-ai/dsh-subagent-codex": "0.1.5-rc.2"
132
+ "peerDependenciesMeta": {
133
+ "@deepseek-ai/dsh-subagent-codex": {
134
+ "optional": true
135
+ }
133
136
  },
134
137
  "scripts": {
135
138
  "build": "tsdown --config tsdown.config.mjs",