dsh-codex-subscription 2.0.0 → 2.0.1
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 +34 -15
- package/README.md +33 -13
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/compatibility.json +9 -3
- package/lib/client.js +291 -211
- package/lib/index.js +2 -1
- package/package.json +33 -34
- package/README.zh-CN.md +0 -16
package/README.en.md
CHANGED
|
@@ -42,7 +42,7 @@ DSH-Portable exposes the same standard plugin command, so the command above also
|
|
|
42
42
|
| **Subscription models** | Sign in to ChatGPT and use Codex without an OpenAI API key or Codex CLI |
|
|
43
43
|
| **Recoverable and diagnosable** | Sign-in state reconciles automatically; failed reads can be retried in place, while timeouts and stale account responses cannot overwrite current state; Settings can create a support report without credentials or account identifiers |
|
|
44
44
|
| **Visible quota** | Keep backend-provided standard Codex, Spark, and other limits separate |
|
|
45
|
-
| **Composer quota** | Choose a compact percentage, progress bar, or no inline
|
|
45
|
+
| **Composer quota** | Choose a compact percentage, progress bar, Beta runway forecast, or no inline display |
|
|
46
46
|
| **Safe quota reset** | See each reset credit separately and deliberately try one with a cooldown and acknowledgement |
|
|
47
47
|
| **Subscription search** | Explicitly route search globally through DSH default search or the signed-in Codex subscription |
|
|
48
48
|
| **Codex image generation and editing (Beta)** | Generate without references, or explicitly edit one selected image; preview, zoom, annotate regions, download the original, and get the original host path for new or edited images |
|
|
@@ -55,10 +55,10 @@ These capabilities reuse the same local ChatGPT sign-in. Subscription routing fa
|
|
|
55
55
|
## Product screen
|
|
56
56
|
|
|
57
57
|
<p align="center">
|
|
58
|
-
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/context-settings
|
|
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">
|
|
59
59
|
</p>
|
|
60
60
|
|
|
61
|
-
|
|
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).
|
|
62
62
|
|
|
63
63
|
## Prepare DSH
|
|
64
64
|
|
|
@@ -92,9 +92,9 @@ dsh --profile headless "Reply with only the word: ok"
|
|
|
92
92
|
The official `npx @deepseek-ai/dsh web` command does not create a global `dsh` command. Keep the full `npx` prefix when installing the plugin:
|
|
93
93
|
|
|
94
94
|
```sh
|
|
95
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
96
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
97
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
95
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 plugin --profile web add dsh-codex-subscription
|
|
96
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 plugin --profile web list dsh-codex-subscription --depth 0
|
|
97
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 --profile web --dump-config
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
</details>
|
|
@@ -142,12 +142,13 @@ When the official model catalog exposes GPT-6 Astra, Standard preserves the cata
|
|
|
142
142
|
### Composer quota
|
|
143
143
|
|
|
144
144
|
<p align="center">
|
|
145
|
-
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/composer-quota
|
|
145
|
+
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/composer-quota.png" width="800" alt="Codex quota inside the composer">
|
|
146
146
|
</p>
|
|
147
147
|
|
|
148
|
-
Choose Off, Percent, Progress bar, or Beta Runway
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
Choose Off, Percent, Progress bar, or Beta Runway under Account & preferences. When a five-hour window exists, the composer shows that window only; the popover retains all windows. A weekly-only display omits the week label and uses compact durations such as `36% · ≈10h–12h`.
|
|
149
|
+
|
|
150
|
+
Runway uses official observations from the recent two hours, including unchanged readings. Repeated boundary crossings can refine the rate interval when the assumptions hold; insufficient evidence or changing intensity falls back to a conservative estimate. It remains Beta and is not a guarantee of working time. History is bounded and stored locally; resets, long gaps or disabling the feature restart calibration.
|
|
151
|
+
Spark keeps its independent quota. The plugin does not invent five-hour limits, Credits, or spending caps that the service did not return.
|
|
151
152
|
|
|
152
153
|
### Safe quota reset
|
|
153
154
|
|
|
@@ -173,6 +174,24 @@ A new image request does not silently include earlier images. GPT Image 2 can ta
|
|
|
173
174
|
|
|
174
175
|
The screenshot above illustrates image viewing and on-image notes; available buttons can vary with the image and installed viewer version.
|
|
175
176
|
|
|
177
|
+
### Sketch canvas (Beta)
|
|
178
|
+
|
|
179
|
+

|
|
180
|
+
|
|
181
|
+
Open Sketch from the composer button or `@Sketch`, or choose Open in sketch from an enhanced image preview. Attachment intake and removal use the native DSH component.
|
|
182
|
+
|
|
183
|
+
Sketch supports local drafts, image layers, aspect ratios, brushes, lines and shapes, two erasers, undo/redo, pan/zoom and configurable shortcuts. Smoothing processes a completed stroke only after release. Up to 20 drafts stay in the current browser; attaching a sketch never sends it automatically. Its image panel manages only the current sketch, not the conversation library.
|
|
184
|
+
|
|
185
|
+
**Sketch-to-image example**: draw, click Attach, describe the desired result in the composer, then send.
|
|
186
|
+
|
|
187
|
+
| Original sketch | Actual plugin output |
|
|
188
|
+
| --- | --- |
|
|
189
|
+
|  |  |
|
|
190
|
+
|
|
191
|
+
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.
|
|
192
|
+
|
|
193
|
+
Flare / Sunburst request overrides remain experimental: successful generation does not confirm which image engine or quality the subscription backend used.
|
|
194
|
+
|
|
176
195
|
### Composer speed
|
|
177
196
|
|
|
178
197
|
With a supported Codex model selected, open the composer's model menu to choose Standard or Fast.
|
|
@@ -205,22 +224,22 @@ These operations preserve the DSH profile, other plugins, and saved sign-in.
|
|
|
205
224
|
### Update and verify
|
|
206
225
|
|
|
207
226
|
```sh
|
|
208
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
209
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
210
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
227
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 plugin --profile web update dsh-codex-subscription
|
|
228
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 plugin --profile web list dsh-codex-subscription --depth 0
|
|
229
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 --profile web --dump-config
|
|
211
230
|
```
|
|
212
231
|
|
|
213
232
|
### Uninstall
|
|
214
233
|
|
|
215
234
|
```sh
|
|
216
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
235
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 plugin --profile web remove dsh-codex-subscription
|
|
217
236
|
```
|
|
218
237
|
|
|
219
238
|
</details>
|
|
220
239
|
|
|
221
240
|
## Troubleshooting
|
|
222
241
|
|
|
223
|
-
- **`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.
|
|
242
|
+
- **`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.5-rc.1 ...` command above;
|
|
224
243
|
- **More than one DSH exists:** run the standard command from the intended DSH environment so that product selects the corresponding profile;
|
|
225
244
|
- **Setup still fails:** confirm the command is running in the intended DSH environment. Do not delete the profile or change the system PATH to force an install.
|
|
226
245
|
- **Need to report a problem:** generate a **Support diagnostics** report at the bottom of Settings, then open the [bug report form](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml). The report includes the OS/runtime, bounded sign-in phase, and safe request-failure categories, but excludes credentials, account identifiers, proxy addresses, raw responses, and full logs. Paste it into the required diagnostics field; never attach sign-in URLs, authorization codes, or browser callback addresses.
|
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ DSH-Portable 也提供相同的标准插件命令,因此同样使用上面的
|
|
|
43
43
|
| **订阅模型直连** | 登录 ChatGPT 后直接使用 Codex,不需要 OpenAI API Key 或 Codex CLI |
|
|
44
44
|
| **可恢复、可诊断** | 登录状态会自动对账;读取失败时可在原处重试,超时和旧账号响应不会覆盖当前状态;设置页可生成不含凭据和账号标识的支持报告 |
|
|
45
45
|
| **额度可见** | 普通 Codex、Spark 等服务端实际返回的额度分开显示 |
|
|
46
|
-
| **输入框额度** |
|
|
46
|
+
| **输入框额度** | 可选择紧凑百分比、进度条、Beta 续航预测或关闭显示 |
|
|
47
47
|
| **安全额度重置** | 每张重置卡单独显示,并通过冷静期和知情确认主动尝试重置 |
|
|
48
48
|
| **订阅搜索** | 可将全部模型的搜索明确路由到 DSH 默认搜索或已登录的 Codex 订阅 |
|
|
49
49
|
| **Codex 图片生成与编辑(Beta)** | 可无参考图全新生成,也可明确选择会话图片继续编辑;支持预览、缩放、区域备注、下载原图,并为新生成或编辑的图片提供 DSH 主机上的原图路径 |
|
|
@@ -56,10 +56,10 @@ DSH-Portable 也提供相同的标准插件命令,因此同样使用上面的
|
|
|
56
56
|
## 实际界面
|
|
57
57
|
|
|
58
58
|
<p align="center">
|
|
59
|
-
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/context-settings.png" width="820" alt="
|
|
59
|
+
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/context-settings.png" width="820" alt="2.0.0 账号与偏好:登录、额度、显示模式与提醒">
|
|
60
60
|
</p>
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
2.0.0 设置分为“账号与偏好”和“高级与诊断”。截图已隐藏账号信息,并展开滚动内容便于阅读;[查看高级页](docs/assets/settings-advanced-2.0.png)。
|
|
63
63
|
|
|
64
64
|
## 准备 DSH
|
|
65
65
|
|
|
@@ -93,9 +93,9 @@ dsh --profile headless "只回复:ok"
|
|
|
93
93
|
官方的 `npx @deepseek-ai/dsh web` 不会创建全局 `dsh` 命令,因此安装插件时也要保留完整的 `npx` 前缀:
|
|
94
94
|
|
|
95
95
|
```sh
|
|
96
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
97
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
98
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
96
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 plugin --profile web add dsh-codex-subscription
|
|
97
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 plugin --profile web list dsh-codex-subscription --depth 0
|
|
98
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 --profile web --dump-config
|
|
99
99
|
```
|
|
100
100
|
|
|
101
101
|
</details>
|
|
@@ -143,10 +143,12 @@ dsh --profile web --dump-config
|
|
|
143
143
|
### 输入框额度
|
|
144
144
|
|
|
145
145
|
<p align="center">
|
|
146
|
-
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/composer-quota.png" width="800" alt="中文 DSH 输入框内的 Codex
|
|
146
|
+
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/composer-quota.png" width="800" alt="中文 DSH 输入框内的 Codex 剩余额度和紧凑续航预测">
|
|
147
147
|
</p>
|
|
148
148
|
|
|
149
|
-
|
|
149
|
+
可在“账号与偏好”选择关闭、百分比、进度条或 Beta 续航预测。存在 5 小时额度时,输入框只显示短窗口;每周额度等完整信息留在悬浮详情。仅有周额度时省略“周”字,预测采用 `36% · ≈10h–12h` 这样的紧凑格式。
|
|
150
|
+
|
|
151
|
+
续航预测根据最近两小时的官方读数估算,额度不变的采样同样参与计算。满足条件时利用连续跳格约束速度,读数不足或使用强度变化时会退回保守估计。范围不是实际可工作时间的保证,仍标记 Beta。历史在本机有限保存;重置、长时间离线或关闭预测会重新校准。
|
|
150
152
|
Spark 使用独立额度。只返回每周额度的账号仍只显示每周,不会虚构 5 小时窗口、Credits 或消费上限。
|
|
151
153
|
|
|
152
154
|
### 安全使用额度重置
|
|
@@ -171,6 +173,24 @@ ChatGPT 返回可用重置卡时,设置页会把每张卡分别显示为紧凑
|
|
|
171
173
|
|
|
172
174
|
上图展示图片查看与图上备注的基本交互;具体按钮会随图片和所安装的查看器版本变化。
|
|
173
175
|
|
|
176
|
+
### 草图画板(Beta)
|
|
177
|
+
|
|
178
|
+

|
|
179
|
+
|
|
180
|
+
点击输入框的草图按钮或输入 `@Sketch` 打开。图片预览中可选择“进入草图”;上传、粘贴和移除附件仍由 DSH 原生组件处理。
|
|
181
|
+
|
|
182
|
+
草图支持多份本地草稿、图片图层、画布比例、三种笔刷、直线和形状、两种橡皮、撤销重做、拖动缩放与可配置快捷键。平滑仅在抬笔后处理整笔路径,不拖慢绘画光标。草稿最多 20 份,仅保存在当前浏览器;附加草图不会自动发送。左侧图片面板只管理当前草图的图片,不是会话图片库。
|
|
183
|
+
|
|
184
|
+
**草图生成图片实测**:画好后点击“附加”,在输入框说明想要的效果,再发送。
|
|
185
|
+
|
|
186
|
+
| 画板原草图 | 插件实际生成结果 |
|
|
187
|
+
| --- | --- |
|
|
188
|
+
|  |  |
|
|
189
|
+
|
|
190
|
+
示例要求:保留山峰与小屋的构图,生成温暖的水彩旅行插画,青绿山峰、橙色屋顶、草地小溪与柔和晨光,不保留蓝色线条。此例通过 GPT-5.6-Luna 发起一次图片工具调用,请求低质量;Luna 是对话模型,实际出图型号由订阅后端决定。
|
|
191
|
+
|
|
192
|
+
图片请求中的 Flare / Sunburst 型号选项仍属实验性功能。成功生成不代表订阅后端确认采用指定型号或质量;不会把请求参数当成实际返回型号。
|
|
193
|
+
|
|
174
194
|
### 输入框速度
|
|
175
195
|
|
|
176
196
|
选择支持的 Codex 模型后,可在输入框的模型菜单中切换标准与高速。标准模式不增加图标,
|
|
@@ -203,22 +223,22 @@ dsh plugin --profile web remove dsh-codex-subscription
|
|
|
203
223
|
### 更新并检查
|
|
204
224
|
|
|
205
225
|
```sh
|
|
206
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
207
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
208
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
226
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 plugin --profile web update dsh-codex-subscription
|
|
227
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 plugin --profile web list dsh-codex-subscription --depth 0
|
|
228
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 --profile web --dump-config
|
|
209
229
|
```
|
|
210
230
|
|
|
211
231
|
### 卸载
|
|
212
232
|
|
|
213
233
|
```sh
|
|
214
|
-
npx -y @deepseek-ai/dsh@0.1.
|
|
234
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.1 plugin --profile web remove dsh-codex-subscription
|
|
215
235
|
```
|
|
216
236
|
|
|
217
237
|
</details>
|
|
218
238
|
|
|
219
239
|
## 常见问题
|
|
220
240
|
|
|
221
|
-
- **`dsh` 无法识别**:官方 npm 方式本来就不会创建全局 `dsh` 命令,请使用上面的完整 `npx -y @deepseek-ai/dsh@0.1.
|
|
241
|
+
- **`dsh` 无法识别**:官方 npm 方式本来就不会创建全局 `dsh` 命令,请使用上面的完整 `npx -y @deepseek-ai/dsh@0.1.5-rc.1 ...` 命令;
|
|
222
242
|
- **电脑上有多个 DSH**:请从目标 DSH 环境运行标准命令,由该产品自身选择对应 profile;
|
|
223
243
|
- **安装仍然失败**:确认命令是在目标 DSH 环境中运行,不要删除 profile 或随意修改系统 PATH。
|
|
224
244
|
- **需要提交问题**:在设置页底部生成“支持诊断”,然后打开[使用问题表单](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml)。报告包含系统/运行时、有限的登录阶段和安全的请求失败分类,但不含凭据、账号标识、代理地址、原始响应或完整日志;请粘贴到必填诊断栏,且不要附上登录链接、授权码或浏览器回调地址。
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -7,7 +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
|
-
| dsh-image-viewer 0.1.0-beta.9 (3d121d3) | Adapted built-in image viewer, interaction state, and styles | MIT, Copyright (c) 2026 WSL043; full license included in LICENSE | https://github.com/WSL043/dsh-image-viewer |
|
|
10
|
+
| dsh-image-viewer 0.1.0-beta.9 (3d121d3), with 0.1.0 (7f3be2c) zoom and annotation improvements | Adapted built-in image viewer, interaction state, and styles | MIT, Copyright (c) 2026 WSL043; full license included in LICENSE | https://github.com/WSL043/dsh-image-viewer |
|
|
11
11
|
| Heroicons | Composer speed icon | MIT | https://github.com/tailwindlabs/heroicons |
|
|
12
12
|
| `https-proxy-agent` 7.0.6 | HTTPS proxy transport for Codex OAuth token requests | MIT | https://github.com/TooTallNate/proxy-agents |
|
|
13
13
|
| QuotaPin for Codex | Design basis for the opt-in local quota runway forecast | MIT | https://github.com/WSL043/QuotaPin-for-Codex |
|
package/compatibility.json
CHANGED
package/lib/client.js
CHANGED
|
@@ -2311,12 +2311,17 @@ window.__ModuleLoader__.load({
|
|
|
2311
2311
|
}
|
|
2312
2312
|
//#endregion
|
|
2313
2313
|
//#region src/image-composer.js
|
|
2314
|
-
function attachImageFiles(conversation, input, files) {
|
|
2315
|
-
const
|
|
2314
|
+
function attachImageFiles(conversation, input, files, sessionId) {
|
|
2315
|
+
const modern = typeof conversation.createDrafts === "function";
|
|
2316
|
+
const create = modern ? () => conversation.createDrafts(sessionId, files) : () => conversation.createDraftImages(files);
|
|
2317
|
+
const release = modern ? (items) => conversation.releaseDraftAttachments(items) : (items) => conversation.releaseDraftImages(items);
|
|
2318
|
+
const add = modern ? input.addAttachments : input.addImages;
|
|
2319
|
+
if (typeof add !== "function" || modern && !sessionId) throw new Error("Image composer is unavailable");
|
|
2320
|
+
const created = create();
|
|
2316
2321
|
try {
|
|
2317
|
-
if (!
|
|
2322
|
+
if (!add.call(input, created.map((item) => item.id))) throw new Error("The composer is busy");
|
|
2318
2323
|
} catch (error) {
|
|
2319
|
-
|
|
2324
|
+
release(created);
|
|
2320
2325
|
throw error;
|
|
2321
2326
|
}
|
|
2322
2327
|
return created;
|
|
@@ -3335,10 +3340,10 @@ window.__ModuleLoader__.load({
|
|
|
3335
3340
|
const PIN_OUTER_STROKE = "#111827";
|
|
3336
3341
|
const PIN_INNER_STROKE = "#ffffff";
|
|
3337
3342
|
const finiteDimension = (value) => Number.isSafeInteger(value) && value > 0;
|
|
3338
|
-
const clamp$
|
|
3343
|
+
const clamp$2 = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
3339
3344
|
const clampCenter = (value, size, edge) => {
|
|
3340
3345
|
const margin = Math.min(edge, size / 2);
|
|
3341
|
-
return clamp$
|
|
3346
|
+
return clamp$2(value, margin, size - margin);
|
|
3342
3347
|
};
|
|
3343
3348
|
function getBitmapFactory(options) {
|
|
3344
3349
|
const factory = options?.createImageBitmap ?? options?.bitmapFactory ?? globalThis.createImageBitmap;
|
|
@@ -3470,6 +3475,182 @@ window.__ModuleLoader__.load({
|
|
|
3470
3475
|
@media(max-width:760px){.dcsiv-actions{flex-wrap:wrap;justify-content:center}.dcsiv-edit-short{display:inline;white-space:normal;max-width:min(280px,calc(100vw - 80px))}.dcsiv-edit-action{height:auto;min-height:32px}.dcsiv-close-floating{top:12px;right:12px;width:40px;height:40px}.dcsiv-workspace{padding:60px 12px 68px}.dcsiv-image{max-width:calc(100vw - 24px);max-height:calc(100vh - 136px)}.dcsiv-topbar{bottom:12px;max-width:calc(100vw - 24px)}.dcsiv-button{padding:0 8px}.dcsiv-button span.dcsiv-label{display:none}.dcsiv-inline-note{width:min(260px,calc(100vw - 40px))}.dcsiv-copy-notes{display:none}}
|
|
3471
3476
|
@media(prefers-reduced-motion:reduce){.dcsiv-surface{transition:none}}
|
|
3472
3477
|
`;
|
|
3478
|
+
//#endregion
|
|
3479
|
+
//#region src/subscription-image-transform.js
|
|
3480
|
+
const clamp$1 = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
3481
|
+
const fitted = () => ({
|
|
3482
|
+
zoom: 1,
|
|
3483
|
+
x: 0,
|
|
3484
|
+
y: 0
|
|
3485
|
+
});
|
|
3486
|
+
function useImageTransform(identity) {
|
|
3487
|
+
const [transform, setTransform] = (0, react.useState)(fitted);
|
|
3488
|
+
const [dragging, setDragging] = (0, react.useState)(false);
|
|
3489
|
+
const [pixelScale, setPixelScale] = (0, react.useState)(1);
|
|
3490
|
+
const [geometry, setGeometry] = (0, react.useState)({
|
|
3491
|
+
width: 0,
|
|
3492
|
+
height: 0,
|
|
3493
|
+
stageWidth: 0,
|
|
3494
|
+
stageHeight: 0
|
|
3495
|
+
});
|
|
3496
|
+
const stageRef = (0, react.useRef)(null), surfaceRef = (0, react.useRef)(null), imageRef = (0, react.useRef)(null);
|
|
3497
|
+
const transformRef = (0, react.useRef)(transform);
|
|
3498
|
+
const pointers = (0, react.useRef)(/* @__PURE__ */ new Map()), gesture = (0, react.useRef)();
|
|
3499
|
+
transformRef.current = transform;
|
|
3500
|
+
const resetGesture = (0, react.useCallback)(() => {
|
|
3501
|
+
pointers.current.clear();
|
|
3502
|
+
gesture.current = void 0;
|
|
3503
|
+
setDragging(false);
|
|
3504
|
+
}, []);
|
|
3505
|
+
const fit = (0, react.useCallback)(() => {
|
|
3506
|
+
resetGesture();
|
|
3507
|
+
setTransform(fitted());
|
|
3508
|
+
}, [resetGesture]);
|
|
3509
|
+
(0, react.useEffect)(() => {
|
|
3510
|
+
fit();
|
|
3511
|
+
}, [identity, fit]);
|
|
3512
|
+
const actualScale = () => imageRef.current?.naturalWidth / Math.max(1, surfaceRef.current?.offsetWidth || 1) || 1;
|
|
3513
|
+
const boundedPan = (0, react.useCallback)((zoom, x, y) => {
|
|
3514
|
+
const stage = stageRef.current, surface = surfaceRef.current;
|
|
3515
|
+
if (!stage || !surface || zoom <= 1) return {
|
|
3516
|
+
x: 0,
|
|
3517
|
+
y: 0
|
|
3518
|
+
};
|
|
3519
|
+
const limitX = Math.max(0, (surface.offsetWidth * zoom - stage.clientWidth) / 2);
|
|
3520
|
+
const limitY = Math.max(0, (surface.offsetHeight * zoom - stage.clientHeight) / 2);
|
|
3521
|
+
return {
|
|
3522
|
+
x: clamp$1(x, -limitX, limitX),
|
|
3523
|
+
y: clamp$1(y, -limitY, limitY)
|
|
3524
|
+
};
|
|
3525
|
+
}, []);
|
|
3526
|
+
const setZoomAt = (0, react.useCallback)((zoom, clientX, clientY) => {
|
|
3527
|
+
const stage = stageRef.current;
|
|
3528
|
+
if (!stage) return;
|
|
3529
|
+
setTransform((current) => {
|
|
3530
|
+
const next = clamp$1(zoom, .5, Math.max(8, actualScale()));
|
|
3531
|
+
const box = stage.getBoundingClientRect();
|
|
3532
|
+
const px = clientX - box.left - box.width / 2, py = clientY - box.top - box.height / 2;
|
|
3533
|
+
const ratio = next / current.zoom;
|
|
3534
|
+
return {
|
|
3535
|
+
zoom: next,
|
|
3536
|
+
...boundedPan(next, px - (px - current.x) * ratio, py - (py - current.y) * ratio)
|
|
3537
|
+
};
|
|
3538
|
+
});
|
|
3539
|
+
}, [boundedPan]);
|
|
3540
|
+
const actual = (0, react.useCallback)(() => {
|
|
3541
|
+
if (!imageRef.current?.naturalWidth) return;
|
|
3542
|
+
resetGesture();
|
|
3543
|
+
setTransform({
|
|
3544
|
+
zoom: actualScale(),
|
|
3545
|
+
x: 0,
|
|
3546
|
+
y: 0
|
|
3547
|
+
});
|
|
3548
|
+
}, [resetGesture]);
|
|
3549
|
+
const measure = (0, react.useCallback)(() => {
|
|
3550
|
+
const next = {
|
|
3551
|
+
width: surfaceRef.current?.offsetWidth ?? 0,
|
|
3552
|
+
height: surfaceRef.current?.offsetHeight ?? 0,
|
|
3553
|
+
stageWidth: stageRef.current?.clientWidth ?? 0,
|
|
3554
|
+
stageHeight: stageRef.current?.clientHeight ?? 0
|
|
3555
|
+
};
|
|
3556
|
+
setGeometry((current) => Object.keys(next).every((key) => current[key] === next[key]) ? current : next);
|
|
3557
|
+
setPixelScale(1 / actualScale());
|
|
3558
|
+
setTransform((current) => ({
|
|
3559
|
+
...current,
|
|
3560
|
+
...boundedPan(current.zoom, current.x, current.y)
|
|
3561
|
+
}));
|
|
3562
|
+
}, [boundedPan]);
|
|
3563
|
+
(0, react.useEffect)(() => {
|
|
3564
|
+
if (!stageRef.current || !surfaceRef.current) return;
|
|
3565
|
+
const observer = new ResizeObserver(measure);
|
|
3566
|
+
observer.observe(stageRef.current);
|
|
3567
|
+
observer.observe(surfaceRef.current);
|
|
3568
|
+
measure();
|
|
3569
|
+
return () => observer.disconnect();
|
|
3570
|
+
}, [identity, measure]);
|
|
3571
|
+
(0, react.useEffect)(() => {
|
|
3572
|
+
const stage = stageRef.current;
|
|
3573
|
+
if (!stage) return;
|
|
3574
|
+
const wheel = (event) => {
|
|
3575
|
+
event.preventDefault();
|
|
3576
|
+
const delta = event.deltaY * (event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? stage.clientHeight : 1);
|
|
3577
|
+
setZoomAt(transformRef.current.zoom * Math.exp(-delta * .0015), event.clientX, event.clientY);
|
|
3578
|
+
};
|
|
3579
|
+
stage.addEventListener("wheel", wheel, { passive: false });
|
|
3580
|
+
return () => stage.removeEventListener("wheel", wheel);
|
|
3581
|
+
}, [identity, setZoomAt]);
|
|
3582
|
+
const onPointerDown = (event) => {
|
|
3583
|
+
if (event.button !== 0 || event.target.closest("button,a,input,textarea,select")) return;
|
|
3584
|
+
const current = transformRef.current;
|
|
3585
|
+
if (event.pointerType === "mouse" && current.zoom <= 1) return;
|
|
3586
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
3587
|
+
pointers.current.set(event.pointerId, {
|
|
3588
|
+
x: event.clientX,
|
|
3589
|
+
y: event.clientY
|
|
3590
|
+
});
|
|
3591
|
+
if (pointers.current.size === 2) {
|
|
3592
|
+
const [a, b] = [...pointers.current.values()];
|
|
3593
|
+
gesture.current = {
|
|
3594
|
+
kind: "pinch",
|
|
3595
|
+
distance: Math.hypot(a.x - b.x, a.y - b.y),
|
|
3596
|
+
transform: current
|
|
3597
|
+
};
|
|
3598
|
+
} else gesture.current = {
|
|
3599
|
+
kind: "pan",
|
|
3600
|
+
x: event.clientX,
|
|
3601
|
+
y: event.clientY,
|
|
3602
|
+
transform: current
|
|
3603
|
+
};
|
|
3604
|
+
setDragging(true);
|
|
3605
|
+
};
|
|
3606
|
+
const onPointerMove = (event) => {
|
|
3607
|
+
if (!pointers.current.has(event.pointerId)) return;
|
|
3608
|
+
pointers.current.set(event.pointerId, {
|
|
3609
|
+
x: event.clientX,
|
|
3610
|
+
y: event.clientY
|
|
3611
|
+
});
|
|
3612
|
+
const start = gesture.current;
|
|
3613
|
+
if (start?.kind === "pinch" && pointers.current.size >= 2) {
|
|
3614
|
+
const [a, b] = [...pointers.current.values()];
|
|
3615
|
+
setZoomAt(start.transform.zoom * Math.hypot(a.x - b.x, a.y - b.y) / Math.max(1, start.distance), (a.x + b.x) / 2, (a.y + b.y) / 2);
|
|
3616
|
+
} else if (start?.kind === "pan") setTransform({
|
|
3617
|
+
zoom: start.transform.zoom,
|
|
3618
|
+
...boundedPan(start.transform.zoom, start.transform.x + event.clientX - start.x, start.transform.y + event.clientY - start.y)
|
|
3619
|
+
});
|
|
3620
|
+
};
|
|
3621
|
+
const endPointer = (event) => {
|
|
3622
|
+
pointers.current.delete(event.pointerId);
|
|
3623
|
+
const remaining = [...pointers.current.values()][0];
|
|
3624
|
+
if (remaining) gesture.current = {
|
|
3625
|
+
kind: "pan",
|
|
3626
|
+
...remaining,
|
|
3627
|
+
transform: transformRef.current
|
|
3628
|
+
};
|
|
3629
|
+
else resetGesture();
|
|
3630
|
+
};
|
|
3631
|
+
return {
|
|
3632
|
+
transform,
|
|
3633
|
+
transformRef,
|
|
3634
|
+
dragging,
|
|
3635
|
+
pixelScale,
|
|
3636
|
+
geometry,
|
|
3637
|
+
stageRef,
|
|
3638
|
+
surfaceRef,
|
|
3639
|
+
imageRef,
|
|
3640
|
+
fit,
|
|
3641
|
+
actual,
|
|
3642
|
+
measure,
|
|
3643
|
+
setZoomAt,
|
|
3644
|
+
resetGesture,
|
|
3645
|
+
pointerHandlers: {
|
|
3646
|
+
onPointerDown,
|
|
3647
|
+
onPointerMove,
|
|
3648
|
+
onPointerUp: endPointer,
|
|
3649
|
+
onPointerCancel: endPointer,
|
|
3650
|
+
onLostPointerCapture: endPointer
|
|
3651
|
+
}
|
|
3652
|
+
};
|
|
3653
|
+
}
|
|
3473
3654
|
//#endregion
|
|
3474
3655
|
//#region src/subscription-image-viewer.jsx
|
|
3475
3656
|
const fill$1 = (value, variables) => Object.entries(variables).reduce((text, [key, replacement]) => text.replaceAll(`{${key}}`, String(replacement)), value);
|
|
@@ -3482,8 +3663,15 @@ window.__ModuleLoader__.load({
|
|
|
3482
3663
|
const noteText = (annotations, t) => annotations.map((annotation, index) => {
|
|
3483
3664
|
return `${fill$1(t("imageAnnotation"), { value: index + 1 })} (${Math.round(annotation.x * 100)}%, ${Math.round(annotation.y * 100)}%): ${annotation.note.trim()}`;
|
|
3484
3665
|
}).filter((line) => !line.endsWith(": ")).join("\n");
|
|
3485
|
-
function ViewerAction({ action, annotations, item, service, t }) {
|
|
3666
|
+
function ViewerAction({ action, annotations, item, service, revision, t }) {
|
|
3486
3667
|
const [state, setState] = (0, react.useState)("idle");
|
|
3668
|
+
const active = (0, react.useRef)(true);
|
|
3669
|
+
(0, react.useEffect)(() => {
|
|
3670
|
+
active.current = true;
|
|
3671
|
+
return () => {
|
|
3672
|
+
active.current = false;
|
|
3673
|
+
};
|
|
3674
|
+
}, []);
|
|
3487
3675
|
const invoke = async () => {
|
|
3488
3676
|
if (state === "pending") return;
|
|
3489
3677
|
setState("pending");
|
|
@@ -3493,10 +3681,11 @@ window.__ModuleLoader__.load({
|
|
|
3493
3681
|
item,
|
|
3494
3682
|
src: item.src
|
|
3495
3683
|
});
|
|
3684
|
+
if (!active.current || service.getSnapshot()?.revision !== revision) return;
|
|
3496
3685
|
setState("idle");
|
|
3497
3686
|
if (action.closeOnSuccess) service.close();
|
|
3498
3687
|
} catch {
|
|
3499
|
-
setState("failed");
|
|
3688
|
+
if (active.current) setState("failed");
|
|
3500
3689
|
}
|
|
3501
3690
|
};
|
|
3502
3691
|
const label = state === "pending" ? action.pendingLabel : state === "failed" ? action.errorLabel : action.label;
|
|
@@ -3571,13 +3760,15 @@ window.__ModuleLoader__.load({
|
|
|
3571
3760
|
}
|
|
3572
3761
|
function SubscriptionImageViewerOverlay({ service, t }) {
|
|
3573
3762
|
const request = (0, react.useSyncExternalStore)(service.subscribe, service.getSnapshot);
|
|
3574
|
-
const [
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
x: 0,
|
|
3578
|
-
y: 0
|
|
3763
|
+
const [cursor, setCursor] = (0, react.useState)({
|
|
3764
|
+
revision: 0,
|
|
3765
|
+
index: 0
|
|
3579
3766
|
});
|
|
3580
|
-
const
|
|
3767
|
+
const index = cursor.revision === request?.revision ? cursor.index : request?.index ?? 0;
|
|
3768
|
+
const setIndex = (update) => setCursor((current) => ({
|
|
3769
|
+
revision: request.revision,
|
|
3770
|
+
index: typeof update === "function" ? update(current.revision === request.revision ? current.index : request.index) : update
|
|
3771
|
+
}));
|
|
3581
3772
|
const [annotating, setAnnotating] = (0, react.useState)(false);
|
|
3582
3773
|
const [annotationsByImage, setAnnotationsByImage] = (0, react.useState)(service.getAnnotationsSnapshot);
|
|
3583
3774
|
const annotationsByImageRef = (0, react.useRef)(annotationsByImage);
|
|
@@ -3585,28 +3776,15 @@ window.__ModuleLoader__.load({
|
|
|
3585
3776
|
const [focusNote, setFocusNote] = (0, react.useState)();
|
|
3586
3777
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
3587
3778
|
const rootRef = (0, react.useRef)(null);
|
|
3588
|
-
const stageRef = (0, react.useRef)(null);
|
|
3589
|
-
const surfaceRef = (0, react.useRef)(null);
|
|
3590
|
-
const imageRef = (0, react.useRef)(null);
|
|
3591
|
-
const pointersRef = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
3592
|
-
const gestureRef = (0, react.useRef)();
|
|
3593
|
-
const transformRef = (0, react.useRef)(transform);
|
|
3594
|
-
transformRef.current = transform;
|
|
3595
3779
|
annotationsByImageRef.current = annotationsByImage;
|
|
3596
3780
|
(0, react.useEffect)(() => {
|
|
3597
3781
|
if (request === void 0) return;
|
|
3598
|
-
setIndex(request.index);
|
|
3599
|
-
setTransform({
|
|
3600
|
-
zoom: 1,
|
|
3601
|
-
x: 0,
|
|
3602
|
-
y: 0
|
|
3603
|
-
});
|
|
3604
|
-
setDragging(false);
|
|
3605
3782
|
setAnnotating(false);
|
|
3606
3783
|
setSelected(void 0);
|
|
3607
3784
|
setCopied(false);
|
|
3608
3785
|
}, [request?.revision]);
|
|
3609
3786
|
const item = request?.items[index];
|
|
3787
|
+
const { transform, transformRef, dragging, pixelScale, geometry, stageRef, surfaceRef, imageRef, fit, actual, measure, setZoomAt, resetGesture, pointerHandlers } = useImageTransform(`${request?.revision}:${item?.id}:${item?.src}`);
|
|
3610
3788
|
const annotations = item === void 0 ? [] : annotationsByImage[item.id] ?? [];
|
|
3611
3789
|
const setAnnotations = (0, react.useCallback)((update) => {
|
|
3612
3790
|
if (item === void 0) return;
|
|
@@ -3620,53 +3798,6 @@ window.__ModuleLoader__.load({
|
|
|
3620
3798
|
service.setAnnotations(item.id, next);
|
|
3621
3799
|
setAnnotationsByImage(snapshot);
|
|
3622
3800
|
}, [item?.id, service]);
|
|
3623
|
-
const boundedPan = (0, react.useCallback)((zoom, x, y) => {
|
|
3624
|
-
const stage = stageRef.current;
|
|
3625
|
-
const surface = surfaceRef.current;
|
|
3626
|
-
if (stage === null || surface === null || zoom <= 1) return {
|
|
3627
|
-
x: 0,
|
|
3628
|
-
y: 0
|
|
3629
|
-
};
|
|
3630
|
-
const limitX = Math.max(0, (surface.offsetWidth * zoom - stage.clientWidth) / 2) + 28;
|
|
3631
|
-
const limitY = Math.max(0, (surface.offsetHeight * zoom - stage.clientHeight) / 2) + 28;
|
|
3632
|
-
return {
|
|
3633
|
-
x: clamp(x, -limitX, limitX),
|
|
3634
|
-
y: clamp(y, -limitY, limitY)
|
|
3635
|
-
};
|
|
3636
|
-
}, []);
|
|
3637
|
-
const setZoomAt = (0, react.useCallback)((nextZoom, clientX, clientY) => {
|
|
3638
|
-
const stage = stageRef.current;
|
|
3639
|
-
if (stage === null) return;
|
|
3640
|
-
setTransform((current) => {
|
|
3641
|
-
const next = clamp(nextZoom, .5, 8);
|
|
3642
|
-
const box = stage.getBoundingClientRect();
|
|
3643
|
-
const px = clientX - box.left - box.width / 2;
|
|
3644
|
-
const py = clientY - box.top - box.height / 2;
|
|
3645
|
-
const ratio = next / current.zoom;
|
|
3646
|
-
return {
|
|
3647
|
-
zoom: next,
|
|
3648
|
-
...boundedPan(next, px - (px - current.x) * ratio, py - (py - current.y) * ratio)
|
|
3649
|
-
};
|
|
3650
|
-
});
|
|
3651
|
-
}, [boundedPan]);
|
|
3652
|
-
const fit = (0, react.useCallback)(() => {
|
|
3653
|
-
setTransform({
|
|
3654
|
-
zoom: 1,
|
|
3655
|
-
x: 0,
|
|
3656
|
-
y: 0
|
|
3657
|
-
});
|
|
3658
|
-
}, []);
|
|
3659
|
-
const actual = (0, react.useCallback)(() => {
|
|
3660
|
-
const image = imageRef.current;
|
|
3661
|
-
const surface = surfaceRef.current;
|
|
3662
|
-
if (image === null || surface === null || image.naturalWidth === 0) return;
|
|
3663
|
-
const zoom = clamp(image.naturalWidth / Math.max(1, surface.offsetWidth), 1, 8);
|
|
3664
|
-
setTransform({
|
|
3665
|
-
zoom,
|
|
3666
|
-
x: 0,
|
|
3667
|
-
y: 0
|
|
3668
|
-
});
|
|
3669
|
-
}, []);
|
|
3670
3801
|
(0, react.useEffect)(() => {
|
|
3671
3802
|
if (request === void 0) return void 0;
|
|
3672
3803
|
const previousOverflow = document.body.style.overflow;
|
|
@@ -3734,77 +3865,13 @@ window.__ModuleLoader__.load({
|
|
|
3734
3865
|
annotations.length
|
|
3735
3866
|
]);
|
|
3736
3867
|
(0, react.useEffect)(() => {
|
|
3737
|
-
setTransform({
|
|
3738
|
-
zoom: 1,
|
|
3739
|
-
x: 0,
|
|
3740
|
-
y: 0
|
|
3741
|
-
});
|
|
3742
|
-
setDragging(false);
|
|
3743
3868
|
setAnnotating(false);
|
|
3744
3869
|
setSelected(void 0);
|
|
3745
|
-
}, [
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
(0, react.useEffect)(() => {
|
|
3751
|
-
const stage = stageRef.current;
|
|
3752
|
-
if (stage === null || request === void 0) return void 0;
|
|
3753
|
-
stage.addEventListener("wheel", onWheel, { passive: false });
|
|
3754
|
-
return () => stage.removeEventListener("wheel", onWheel);
|
|
3755
|
-
}, [onWheel, request]);
|
|
3756
|
-
const onPointerDown = (event) => {
|
|
3757
|
-
const target = event.target;
|
|
3758
|
-
if (event.button !== 0 || annotating || target instanceof Element && target.closest("button,textarea,input,a,select,[contenteditable=true]") !== null) return;
|
|
3759
|
-
pointersRef.current.set(event.pointerId, {
|
|
3760
|
-
x: event.clientX,
|
|
3761
|
-
y: event.clientY
|
|
3762
|
-
});
|
|
3763
|
-
if (pointersRef.current.size === 2) {
|
|
3764
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
3765
|
-
const [a, b] = [...pointersRef.current.values()];
|
|
3766
|
-
gestureRef.current = {
|
|
3767
|
-
kind: "pinch",
|
|
3768
|
-
distance: Math.hypot(a.x - b.x, a.y - b.y),
|
|
3769
|
-
transform
|
|
3770
|
-
};
|
|
3771
|
-
} else if (!annotating && transform.zoom > 1) {
|
|
3772
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
3773
|
-
gestureRef.current = {
|
|
3774
|
-
kind: "pan",
|
|
3775
|
-
x: event.clientX,
|
|
3776
|
-
y: event.clientY,
|
|
3777
|
-
transform
|
|
3778
|
-
};
|
|
3779
|
-
setDragging(true);
|
|
3780
|
-
}
|
|
3781
|
-
};
|
|
3782
|
-
const onPointerMove = (event) => {
|
|
3783
|
-
if (!pointersRef.current.has(event.pointerId)) return;
|
|
3784
|
-
pointersRef.current.set(event.pointerId, {
|
|
3785
|
-
x: event.clientX,
|
|
3786
|
-
y: event.clientY
|
|
3787
|
-
});
|
|
3788
|
-
const gesture = gestureRef.current;
|
|
3789
|
-
if (gesture?.kind === "pinch" && pointersRef.current.size >= 2) {
|
|
3790
|
-
const [a, b] = [...pointersRef.current.values()];
|
|
3791
|
-
const distance = Math.max(1, Math.hypot(a.x - b.x, a.y - b.y));
|
|
3792
|
-
setZoomAt(gesture.transform.zoom * distance / Math.max(1, gesture.distance), (a.x + b.x) / 2, (a.y + b.y) / 2);
|
|
3793
|
-
} else if (gesture?.kind === "pan") {
|
|
3794
|
-
const pan = boundedPan(gesture.transform.zoom, gesture.transform.x + event.clientX - gesture.x, gesture.transform.y + event.clientY - gesture.y);
|
|
3795
|
-
setTransform({
|
|
3796
|
-
zoom: gesture.transform.zoom,
|
|
3797
|
-
...pan
|
|
3798
|
-
});
|
|
3799
|
-
}
|
|
3800
|
-
};
|
|
3801
|
-
const endPointer = (event) => {
|
|
3802
|
-
pointersRef.current.delete(event.pointerId);
|
|
3803
|
-
if (pointersRef.current.size === 0) {
|
|
3804
|
-
gestureRef.current = void 0;
|
|
3805
|
-
setDragging(false);
|
|
3806
|
-
}
|
|
3807
|
-
};
|
|
3870
|
+
}, [
|
|
3871
|
+
item?.id,
|
|
3872
|
+
item?.src,
|
|
3873
|
+
request?.revision
|
|
3874
|
+
]);
|
|
3808
3875
|
const addAnnotation = (event) => {
|
|
3809
3876
|
if (!annotating || event.target.closest(".dcsiv-annotation")) return;
|
|
3810
3877
|
const bounds = surfaceRef.current?.getBoundingClientRect();
|
|
@@ -3836,6 +3903,15 @@ window.__ModuleLoader__.load({
|
|
|
3836
3903
|
if (request === void 0 || item === void 0) return null;
|
|
3837
3904
|
const meta = [item.width && item.height ? `${item.width} × ${item.height}` : void 0, bytesLabel(item.bytes)].filter(Boolean).join(" · ");
|
|
3838
3905
|
const showCounter = request.items.length > 1;
|
|
3906
|
+
const annotationPosition = (annotation) => {
|
|
3907
|
+
const ratio = globalThis.devicePixelRatio || 1;
|
|
3908
|
+
const align = (value) => Math.round(value * ratio) / ratio;
|
|
3909
|
+
return {
|
|
3910
|
+
left: align(geometry.stageWidth / 2 + transform.x + (annotation.x - .5) * geometry.width * transform.zoom - 12),
|
|
3911
|
+
top: align(geometry.stageHeight / 2 + transform.y + (annotation.y - .5) * geometry.height * transform.zoom - 12),
|
|
3912
|
+
visibility: geometry.width > 0 ? "visible" : "hidden"
|
|
3913
|
+
};
|
|
3914
|
+
};
|
|
3839
3915
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3840
3916
|
ref: rootRef,
|
|
3841
3917
|
className: "dcsiv-root",
|
|
@@ -3861,7 +3937,10 @@ window.__ModuleLoader__.load({
|
|
|
3861
3937
|
"data-active": annotating,
|
|
3862
3938
|
"aria-label": annotating ? t("imageAnnotateCancel") : t("imageAnnotate"),
|
|
3863
3939
|
"aria-pressed": annotating,
|
|
3864
|
-
onClick: () =>
|
|
3940
|
+
onClick: () => {
|
|
3941
|
+
resetGesture();
|
|
3942
|
+
setAnnotating((value) => !value);
|
|
3943
|
+
},
|
|
3865
3944
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3866
3945
|
className: "dcsiv-label",
|
|
3867
3946
|
children: annotating ? t("imageAnnotateCancel") : t("imageAnnotate")
|
|
@@ -3903,7 +3982,7 @@ window.__ModuleLoader__.load({
|
|
|
3903
3982
|
}),
|
|
3904
3983
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3905
3984
|
className: "dcsiv-zoom",
|
|
3906
|
-
children: [Math.round(transform.zoom * 100), "%"]
|
|
3985
|
+
children: [Math.round(transform.zoom * pixelScale * 100), "%"]
|
|
3907
3986
|
}),
|
|
3908
3987
|
item.download === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
|
|
3909
3988
|
className: "dcsiv-download",
|
|
@@ -3923,8 +4002,9 @@ window.__ModuleLoader__.load({
|
|
|
3923
4002
|
annotations,
|
|
3924
4003
|
item,
|
|
3925
4004
|
service,
|
|
4005
|
+
revision: request.revision,
|
|
3926
4006
|
t
|
|
3927
|
-
}, action.id))
|
|
4007
|
+
}, `${request.revision}:${index}:${action.id}`))
|
|
3928
4008
|
]
|
|
3929
4009
|
})
|
|
3930
4010
|
}),
|
|
@@ -3945,34 +4025,33 @@ window.__ModuleLoader__.load({
|
|
|
3945
4025
|
onClick: (event) => {
|
|
3946
4026
|
if (event.target === event.currentTarget && !annotating && transform.zoom === 1) service.close();
|
|
3947
4027
|
},
|
|
3948
|
-
|
|
3949
|
-
onPointerMove,
|
|
3950
|
-
onPointerUp: endPointer,
|
|
3951
|
-
onPointerCancel: endPointer,
|
|
4028
|
+
...!annotating ? pointerHandlers : {},
|
|
3952
4029
|
onDoubleClick: () => {
|
|
3953
4030
|
if (transform.zoom === 1) actual();
|
|
3954
4031
|
else fit();
|
|
3955
4032
|
},
|
|
3956
|
-
children: [
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
4033
|
+
children: [
|
|
4034
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4035
|
+
ref: surfaceRef,
|
|
4036
|
+
className: "dcsiv-surface",
|
|
4037
|
+
onClick: addAnnotation,
|
|
4038
|
+
style: { transform: `translate3d(${transform.x}px,${transform.y}px,0) scale(${transform.zoom})` },
|
|
4039
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
4040
|
+
ref: imageRef,
|
|
4041
|
+
className: "dcsiv-image",
|
|
4042
|
+
src: item.src,
|
|
4043
|
+
alt: item.name,
|
|
4044
|
+
draggable: "false",
|
|
4045
|
+
onLoad: () => {
|
|
4046
|
+
measure();
|
|
4047
|
+
}
|
|
4048
|
+
}, `${request.revision}:${item.id}`)
|
|
4049
|
+
}),
|
|
4050
|
+
annotations.map((annotation, position) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3968
4051
|
className: "dcsiv-annotation",
|
|
3969
4052
|
"data-x": annotation.x < .38 ? "right" : annotation.x > .62 ? "left" : "center",
|
|
3970
4053
|
"data-y": annotation.y < .28 ? "down" : "up",
|
|
3971
|
-
style:
|
|
3972
|
-
left: `${annotation.x * 100}%`,
|
|
3973
|
-
top: `${annotation.y * 100}%`,
|
|
3974
|
-
transform: `translate(-50%,-50%) scale(${1 / transform.zoom})`
|
|
3975
|
-
},
|
|
4054
|
+
style: annotationPosition(annotation),
|
|
3976
4055
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3977
4056
|
type: "button",
|
|
3978
4057
|
className: "dcsiv-pin",
|
|
@@ -4028,43 +4107,44 @@ window.__ModuleLoader__.load({
|
|
|
4028
4107
|
})
|
|
4029
4108
|
]
|
|
4030
4109
|
}) : null]
|
|
4031
|
-
}, annotation.id))
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4110
|
+
}, annotation.id)),
|
|
4111
|
+
showCounter ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4112
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4113
|
+
type: "button",
|
|
4114
|
+
className: "dcsiv-button dcsiv-icon-only dcsiv-nav dcsiv-prev",
|
|
4115
|
+
"aria-label": t("imagePrevious"),
|
|
4116
|
+
onClick: (event) => {
|
|
4117
|
+
event.stopPropagation();
|
|
4118
|
+
setIndex((value) => (value - 1 + request.items.length) % request.items.length);
|
|
4119
|
+
},
|
|
4120
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronLeftOutline14, {})
|
|
4121
|
+
}),
|
|
4122
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4123
|
+
type: "button",
|
|
4124
|
+
className: "dcsiv-button dcsiv-icon-only dcsiv-nav dcsiv-next",
|
|
4125
|
+
"aria-label": t("imageNext"),
|
|
4126
|
+
onClick: (event) => {
|
|
4127
|
+
event.stopPropagation();
|
|
4128
|
+
setIndex((value) => (value + 1) % request.items.length);
|
|
4129
|
+
},
|
|
4130
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {})
|
|
4131
|
+
}),
|
|
4132
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4133
|
+
className: "dcsiv-counter",
|
|
4134
|
+
children: [
|
|
4135
|
+
index + 1,
|
|
4136
|
+
" / ",
|
|
4137
|
+
request.items.length
|
|
4138
|
+
]
|
|
4139
|
+
})
|
|
4140
|
+
] }) : annotating ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4141
|
+
className: "dcsiv-hint",
|
|
4142
|
+
children: t("imageAnnotateHint")
|
|
4143
|
+
}) : transform.zoom === 1 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4144
|
+
className: "dcsiv-hint",
|
|
4145
|
+
children: t("imageZoomHint")
|
|
4146
|
+
}) : null
|
|
4147
|
+
]
|
|
4068
4148
|
}), annotations.some((annotation) => annotation.note.trim() !== "") ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
4069
4149
|
type: "button",
|
|
4070
4150
|
className: "dcsiv-copy-notes",
|
|
@@ -4100,7 +4180,7 @@ window.__ModuleLoader__.load({
|
|
|
4100
4180
|
const items = (Array.isArray(request?.items) ? request.items : []).flatMap((item, position) => {
|
|
4101
4181
|
if (typeof item?.src !== "string" || item.src === "") return [];
|
|
4102
4182
|
return [{
|
|
4103
|
-
id: typeof item.id === "string" && item.id !== "" ? item.id :
|
|
4183
|
+
id: typeof item.id === "string" && item.id !== "" ? item.id : item.src,
|
|
4104
4184
|
src: item.src,
|
|
4105
4185
|
name: typeof item.name === "string" && item.name !== "" ? item.name : `Image ${position + 1}`,
|
|
4106
4186
|
width: boundedNumber(item.width, void 0),
|
|
@@ -4849,7 +4929,7 @@ window.__ModuleLoader__.load({
|
|
|
4849
4929
|
}
|
|
4850
4930
|
//#endregion
|
|
4851
4931
|
//#region src/version.js
|
|
4852
|
-
const PACKAGE_VERSION = "2.0.
|
|
4932
|
+
const PACKAGE_VERSION = "2.0.1";
|
|
4853
4933
|
//#endregion
|
|
4854
4934
|
//#region src/client-recovery.js
|
|
4855
4935
|
async function recoveryCall(rpc, endpoint, payload = {}, timeoutMs = 1e4) {
|
|
@@ -7193,7 +7273,7 @@ window.__ModuleLoader__.load({
|
|
|
7193
7273
|
})), "codex-subscription: Image trigger"));
|
|
7194
7274
|
const sessionInput = (sessionId) => {
|
|
7195
7275
|
const actx = sessions.scope(sessionId);
|
|
7196
|
-
if (!actx ||
|
|
7276
|
+
if (!actx || !conversation.input?.for) throw new Error("Image composer is unavailable");
|
|
7197
7277
|
return conversation.input.for(actx);
|
|
7198
7278
|
};
|
|
7199
7279
|
const openSketchImage = (sessionId) => async (src, name) => {
|
|
@@ -7209,7 +7289,7 @@ window.__ModuleLoader__.load({
|
|
|
7209
7289
|
const attachForEdit = (sessionId) => async (src, filename, draft, annotations = [], referenceName, sourceInDraft = false) => {
|
|
7210
7290
|
if (!preference.getSnapshot().imageEditing) throw new Error("Image editing is disabled");
|
|
7211
7291
|
const actx = sessions.scope(sessionId);
|
|
7212
|
-
if (actx === void 0 ||
|
|
7292
|
+
if (actx === void 0 || conversation.input?.for === void 0) throw new Error("This DSH version does not provide the image composer bridge");
|
|
7213
7293
|
const response = await fetch(src);
|
|
7214
7294
|
if (!response.ok) throw new Error("Could not read generated image");
|
|
7215
7295
|
const blob = await response.blob();
|
|
@@ -7220,7 +7300,7 @@ window.__ModuleLoader__.load({
|
|
|
7220
7300
|
}
|
|
7221
7301
|
const input = conversation.input.for(actx);
|
|
7222
7302
|
if (!preference.getSnapshot().imageEditing) throw new Error("Image editing is disabled");
|
|
7223
|
-
if (files.length) attachImageFiles(conversation, input, files);
|
|
7303
|
+
if (files.length) attachImageFiles(conversation, input, files, sessionId);
|
|
7224
7304
|
sessions.open(sessionId);
|
|
7225
7305
|
if (sourceInDraft && !annotations.length) return;
|
|
7226
7306
|
if (!input.state.getSnapshot().draft.trim()) input.setDraft(draft);
|
|
@@ -7279,7 +7359,7 @@ window.__ModuleLoader__.load({
|
|
|
7279
7359
|
attachSketch: (blob) => {
|
|
7280
7360
|
const current = preference.getSnapshot();
|
|
7281
7361
|
if (!current.imageSketch || !current.imageEditing) throw new Error("Sketch editing is disabled");
|
|
7282
|
-
attachImageFiles(conversation, sessionInput(sessionId), [new File([blob], "sketch-reference.png", { type: "image/png" })]);
|
|
7362
|
+
attachImageFiles(conversation, sessionInput(sessionId), [new File([blob], "sketch-reference.png", { type: "image/png" })], sessionId);
|
|
7283
7363
|
}
|
|
7284
7364
|
})
|
|
7285
7365
|
}, ImageWorkspace));
|
package/lib/index.js
CHANGED
|
@@ -1615,7 +1615,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
|
|
|
1615
1615
|
}
|
|
1616
1616
|
//#endregion
|
|
1617
1617
|
//#region src/version.js
|
|
1618
|
-
const PACKAGE_VERSION = "2.0.
|
|
1618
|
+
const PACKAGE_VERSION = "2.0.1";
|
|
1619
1619
|
const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
|
|
1620
1620
|
//#endregion
|
|
1621
1621
|
//#region src/model-catalog.js
|
|
@@ -3882,6 +3882,7 @@ function apply(ctx) {
|
|
|
3882
3882
|
displayName: "ChatGPT subscription",
|
|
3883
3883
|
piProvider: provider,
|
|
3884
3884
|
configuredMaxTokens: /* @__PURE__ */ new Map(),
|
|
3885
|
+
modelErrors: /* @__PURE__ */ new Map(),
|
|
3885
3886
|
streamIdleTimeoutMs: 600 * 1e3,
|
|
3886
3887
|
maxRequestImageBytes: MAX_REQUEST_IMAGE_BYTES,
|
|
3887
3888
|
requestImagePixelBudget: REQUEST_IMAGE_PIXEL_BUDGET,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codex-subscription",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
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",
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
"cordis.patch.yml",
|
|
16
16
|
"README.md",
|
|
17
17
|
"README.en.md",
|
|
18
|
-
"README.zh-CN.md",
|
|
19
18
|
"DIRECTORY.md",
|
|
20
19
|
"compatibility.json",
|
|
21
20
|
"LICENSE",
|
|
@@ -75,21 +74,21 @@
|
|
|
75
74
|
},
|
|
76
75
|
"peerDependencies": {
|
|
77
76
|
"@deepseek-ai/cordis": "4.0.1 || 4.0.2",
|
|
78
|
-
"@deepseek-ai/dsh-api-remotes": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
79
|
-
"@deepseek-ai/dsh-client-connection": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
80
|
-
"@deepseek-ai/dsh-client-locale": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
81
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
82
|
-
"@deepseek-ai/dsh-client-ui-model-selection": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
83
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
84
|
-
"@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
85
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
86
|
-
"@deepseek-ai/dsh-client-ui-tool": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
87
|
-
"@deepseek-ai/dsh-credentials": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
88
|
-
"@deepseek-ai/dsh-llm": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
89
|
-
"@deepseek-ai/dsh-llm-pi-ai": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
90
|
-
"@deepseek-ai/dsh-settings": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
91
|
-
"@deepseek-ai/dsh-tools": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
92
|
-
"@deepseek-ai/dsh-web": "0.1.2-rc.1 || 0.1.5-alpha.1",
|
|
77
|
+
"@deepseek-ai/dsh-api-remotes": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
78
|
+
"@deepseek-ai/dsh-client-connection": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
79
|
+
"@deepseek-ai/dsh-client-locale": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
80
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
81
|
+
"@deepseek-ai/dsh-client-ui-model-selection": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
82
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
83
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
84
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
85
|
+
"@deepseek-ai/dsh-client-ui-tool": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
86
|
+
"@deepseek-ai/dsh-credentials": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
87
|
+
"@deepseek-ai/dsh-llm": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
88
|
+
"@deepseek-ai/dsh-llm-pi-ai": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
89
|
+
"@deepseek-ai/dsh-settings": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
90
|
+
"@deepseek-ai/dsh-tools": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
91
|
+
"@deepseek-ai/dsh-web": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
|
|
93
92
|
"@deepseek-ai/schemastery": "3.18.1 || ^3.18.2",
|
|
94
93
|
"@earendil-works/pi-ai": "0.82.1",
|
|
95
94
|
"react": "^18.2.0",
|
|
@@ -97,23 +96,23 @@
|
|
|
97
96
|
},
|
|
98
97
|
"devDependencies": {
|
|
99
98
|
"@deepseek-ai/cordis": "4.0.2",
|
|
100
|
-
"@deepseek-ai/dsh-api-remotes": "0.1.
|
|
101
|
-
"@deepseek-ai/dsh-client-connection": "0.1.
|
|
102
|
-
"@deepseek-ai/dsh-client-locale": "0.1.
|
|
103
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.1.
|
|
104
|
-
"@deepseek-ai/dsh-client-ui-model-selection": "0.1.
|
|
105
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.1.
|
|
106
|
-
"@deepseek-ai/dsh-client-ui-settings": "0.1.
|
|
107
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.1.
|
|
108
|
-
"@deepseek-ai/dsh-client-ui-tool": "0.1.
|
|
109
|
-
"@deepseek-ai/dsh-credentials": "0.1.
|
|
110
|
-
"@deepseek-ai/dsh-invariants": "0.1.
|
|
111
|
-
"@deepseek-ai/dsh-llm": "0.1.
|
|
112
|
-
"@deepseek-ai/dsh-llm-pi-ai": "0.1.
|
|
113
|
-
"@deepseek-ai/dsh-settings": "0.1.
|
|
114
|
-
"@deepseek-ai/dsh-session": "0.1.
|
|
115
|
-
"@deepseek-ai/dsh-tools": "0.1.
|
|
116
|
-
"@deepseek-ai/dsh-web": "0.1.
|
|
99
|
+
"@deepseek-ai/dsh-api-remotes": "0.1.5-rc.1",
|
|
100
|
+
"@deepseek-ai/dsh-client-connection": "0.1.5-rc.1",
|
|
101
|
+
"@deepseek-ai/dsh-client-locale": "0.1.5-rc.1",
|
|
102
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.5-rc.1",
|
|
103
|
+
"@deepseek-ai/dsh-client-ui-model-selection": "0.1.5-rc.1",
|
|
104
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.5-rc.1",
|
|
105
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.1",
|
|
106
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.1",
|
|
107
|
+
"@deepseek-ai/dsh-client-ui-tool": "0.1.5-rc.1",
|
|
108
|
+
"@deepseek-ai/dsh-credentials": "0.1.5-rc.1",
|
|
109
|
+
"@deepseek-ai/dsh-invariants": "0.1.5-rc.1",
|
|
110
|
+
"@deepseek-ai/dsh-llm": "0.1.5-rc.1",
|
|
111
|
+
"@deepseek-ai/dsh-llm-pi-ai": "0.1.5-rc.1",
|
|
112
|
+
"@deepseek-ai/dsh-settings": "0.1.5-rc.1",
|
|
113
|
+
"@deepseek-ai/dsh-session": "0.1.5-rc.1",
|
|
114
|
+
"@deepseek-ai/dsh-tools": "0.1.5-rc.1",
|
|
115
|
+
"@deepseek-ai/dsh-web": "0.1.5-rc.1",
|
|
117
116
|
"@deepseek-ai/schemastery": "3.18.2",
|
|
118
117
|
"@earendil-works/pi-ai": "0.82.1",
|
|
119
118
|
"@heroicons/react": "2.2.0",
|
package/README.zh-CN.md
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# DSH Codex Subscription
|
|
2
|
-
|
|
3
|
-
本项目现在默认使用简体中文 README:
|
|
4
|
-
|
|
5
|
-
- [打开完整中文说明](README.md)
|
|
6
|
-
- [Open the complete English README](README.en.md)
|
|
7
|
-
|
|
8
|
-
旧的 `README.zh-CN.md` 地址会继续保留,已有书签和外部链接无需修改。
|
|
9
|
-
|
|
10
|
-
安装:
|
|
11
|
-
|
|
12
|
-
```powershell
|
|
13
|
-
dsh plugin --profile web add dsh-codex-subscription
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
遇到问题请使用[使用问题表单](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml)。
|