dsh-codex-subscription 1.6.0 → 1.7.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/AGENTS.md CHANGED
@@ -6,7 +6,7 @@ Use this guide when a user asks an Agent to install, update, verify, or remove
6
6
  ## Safety
7
7
 
8
8
  - Confirm the target DSH installation and profile. Use `web` only when it is the user's target.
9
- - Use the exact `1.6.0` package below; do not install a moving branch.
9
+ - Use the exact `1.7.1` package below; do not install a moving branch.
10
10
  - Never print OAuth credentials, account IDs, authorization callbacks, or credential-store contents.
11
11
  - Preserve the DSH profile, unrelated plugins, sessions, and saved sign-in.
12
12
  - Do not start, stop, or restart DSH without explicit permission.
@@ -34,13 +34,13 @@ For an official DSH installation run through npm, keep the complete `npx` prefix
34
34
  run command does not create a global `dsh` command:
35
35
 
36
36
  ```sh
37
- npx -y @deepseek-ai/dsh@0.1.1-rc.2 plugin --profile web add dsh-codex-subscription@1.6.0
37
+ npx -y @deepseek-ai/dsh@0.1.1-rc.2 plugin --profile web add dsh-codex-subscription@1.7.1
38
38
  ```
39
39
 
40
40
  With an existing global `dsh` command:
41
41
 
42
42
  ```sh
43
- dsh plugin --profile web add dsh-codex-subscription@1.6.0
43
+ dsh plugin --profile web add dsh-codex-subscription@1.7.1
44
44
  ```
45
45
 
46
46
  Use the same `add` command to update or repair. This is the complete package-changing operation.
@@ -58,7 +58,7 @@ dsh --profile web --dump-config
58
58
 
59
59
  For the official npm route, run the same checks with `npx -y @deepseek-ai/dsh@0.1.1-rc.2` in place of `dsh`.
60
60
 
61
- 1. `dsh-codex-subscription` version `1.6.0` appears exactly once.
61
+ 1. `dsh-codex-subscription` version `1.7.1` appears exactly once.
62
62
  2. `codex-subscription` appears exactly once in the composed config.
63
63
  3. No unrelated plugin or profile was changed and DSH was not restarted.
64
64
 
package/README.md CHANGED
@@ -49,7 +49,7 @@ DSH-Portable exposes the same standard plugin command, so the command above also
49
49
  | **Composer quota** | Choose a compact percentage, progress bar, or no inline quota display |
50
50
  | **Safe quota reset** | See the next expiry and deliberately try a reset with a cooldown and acknowledgement |
51
51
  | **Subscription search** | Explicitly choose DSH default search or Codex subscription search |
52
- | **Codex image generation and editing (Beta)** | Generate without references, or explicitly edit selected conversation images; preview, zoom, and download the original |
52
+ | **Codex image generation and editing (Beta)** | Generate without references, or explicitly edit one selected image; preview, zoom, annotate regions, download the original, and continue in the same composer |
53
53
  | **Fast mode** | Switch between Standard and Fast directly in the composer |
54
54
 
55
55
  These capabilities reuse the same local ChatGPT sign-in. Subscription routing failures stay visible and never silently switch to another paid route.
@@ -169,11 +169,15 @@ clicks are single-flight, and an uncertain network result is never retried autom
169
169
 
170
170
  ### Image generation and editing (Beta)
171
171
 
172
- Generated images open in a DSH-native preview with zoom, fit, dimensions, and **Download original**. A new image request
173
- does not silently include earlier images. To refine a result, explicitly ask to edit that image in the same conversation;
174
- the plugin sends only the selected durable image references, up to five. GPT Image 2 can take longer than a normal text
172
+ Generated images open in a DSH-native preview with zoom, fit, dimensions, **Download original**, and numbered region notes.
173
+ **Continue editing in composer** attaches exactly the image you opened and writes the region notes into the draft without
174
+ sending it. A new image request does not silently include earlier images. GPT Image 2 can take longer than a normal text
175
175
  turn, and detailed text, exact composition, or repeated-character consistency may still need another pass.
176
176
 
177
+ <p align="center">
178
+ <img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/image-preview-annotations-en.png" width="900" alt="DSH-native generated-image preview with zoom, original download, and numbered region annotations">
179
+ </p>
180
+
177
181
  ### Composer speed
178
182
 
179
183
  With a supported Codex model selected, open the composer's model menu to choose Standard or Fast.
@@ -210,7 +214,7 @@ dsh plugin --profile web remove dsh-codex-subscription
210
214
  - **`dsh` is not recognized:** the official npm route does not create a global `dsh` command; use the complete `npx -y @deepseek-ai/dsh@0.1.1-rc.2 ...` command above;
211
215
  - **More than one DSH exists:** run the standard command from the intended DSH environment. For an Agent, specify the target or pass `-DshPath` explicitly;
212
216
  - **Setup still fails:** send the Agent guide above to an Agent. Do not delete the profile or change the system PATH to force an install.
213
- - **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 form collects exact DSH/plugin versions and reproduction steps. The generated report excludes credentials and account identifiers; still do not attach sign-in URLs, authorization codes, or browser callback addresses.
217
+ - **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 and a bounded sign-in phase, but excludes credentials, account identifiers, raw errors, and full logs. Paste it into the required diagnostics field; never attach sign-in URLs, authorization codes, or browser callback addresses.
214
218
 
215
219
  The ChatGPT Codex backend and DSH can change independently. This community project is not affiliated with or endorsed by DeepSeek or OpenAI.
216
220
 
package/README.zh-CN.md CHANGED
@@ -166,9 +166,13 @@ ChatGPT 返回可用重置卡时,设置页会用紧凑的一行显示数量和
166
166
 
167
167
  ### 图片生成与编辑(Beta)
168
168
 
169
- 生成的图片会在 DSH 原生风格的查看器中打开,支持缩放、适合窗口、查看尺寸和下载原图。全新生成不会静默带入历史图片;
170
- 需要继续修改时,要在同一会话明确说明编辑这张图,插件只会发送明确选中的持久图片引用,最多 5 张。GPT Image 2 的耗时可能明显长于
171
- 文本回复,复杂文字、精确构图和连续角色一致性也可能需要再次调整。
169
+ 生成图片会在 DSH 原生查看器中打开,可缩放、适合窗口、查看尺寸、下载原图,并对具体部位添加编号标注。
170
+ 点击“在输入框中继续编辑”时,只会附上当前打开的这一张图,并把部位标注写入草稿,不会自动发送。
171
+ 新的图片请求不会静默带入历史图片。GPT Image 2 的耗时可能明显长于文本回复,复杂文字、精确构图和连续角色一致性也可能需要再次调整。
172
+
173
+ <p align="center">
174
+ <img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/image-preview-annotations.png" width="900" alt="DSH 原生图片预览中的缩放、原图下载与编号部位标注">
175
+ </p>
172
176
 
173
177
  ### 输入框速度
174
178
 
@@ -206,7 +210,7 @@ dsh plugin --profile web remove dsh-codex-subscription
206
210
  - **`dsh` 无法识别**:官方 npm 方式本来就不会创建全局 `dsh` 命令,请使用上面的完整 `npx -y @deepseek-ai/dsh@0.1.1-rc.2 ...` 命令;
207
211
  - **电脑上有多个 DSH**:请在目标 DSH 环境中运行标准命令;交给 Agent 时明确目标,或传入 `-DshPath`;
208
212
  - **安装仍然失败**:把上面的 Agent 文档链接发给 Agent,不要删除 profile 或随意修改系统 PATH。
209
- - **需要提交问题**:在设置页底部生成“支持诊断”,然后打开[使用问题表单](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml)。表单会收集准确的 DSH/插件版本和复现步骤;报告不含凭据和账号标识,仍不要附上登录链接、授权码或浏览器回调地址。
213
+ - **需要提交问题**:在设置页底部生成“支持诊断”,然后打开[使用问题表单](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml)。报告包含系统/运行时和有限的登录阶段,但不含凭据、账号标识、原始错误或完整日志;请粘贴到必填诊断栏,且不要附上登录链接、授权码或浏览器回调地址。
210
214
 
211
215
  ## 边界与支持
212
216
 
package/lib/client.js CHANGED
@@ -28,6 +28,7 @@ window.__ModuleLoader__.load({
28
28
  //#endregion
29
29
  let react = require("react");
30
30
  react = __toESM(react, 1);
31
+ let react_dom = require("react-dom");
31
32
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
32
33
  let react_jsx_runtime = require("react/jsx-runtime");
33
34
  //#region node_modules/.pnpm/@heroicons+react@2.2.0_react@18.3.1/node_modules/@heroicons/react/16/solid/esm/BoltIcon.js
@@ -91,6 +92,19 @@ window.__ModuleLoader__.load({
91
92
  async function readLoginProgress({ flow, readFlow, readAccount }) {
92
93
  try {
93
94
  const nextFlow = await readFlow();
95
+ if (nextFlow.phase === "failed") try {
96
+ const account = await readAccount();
97
+ if (account?.authenticated === true) return {
98
+ flow: {
99
+ id: flow.id,
100
+ method: flow.method,
101
+ phase: "authenticated",
102
+ authenticated: true
103
+ },
104
+ account,
105
+ recovered: true
106
+ };
107
+ } catch {}
94
108
  if (nextFlow.phase !== "authenticated") return { flow: nextFlow };
95
109
  return {
96
110
  flow: nextFlow,
@@ -250,8 +264,17 @@ window.__ModuleLoader__.load({
250
264
  imageZoomOut: "缩小",
251
265
  imageZoomIn: "放大",
252
266
  imageFit: "适合窗口",
253
- imageRefineHint: "要修改这张图,请在当前会话明确说“编辑这张图片……”;插件只会把这张图作为参考。",
254
- imageNewHint: "要重新生成,请直接描述一张新图片;不会自动带入历史图片。"
267
+ imageAnnotate: "标注部位",
268
+ imageAnnotateHint: "点击图片添加编号标注",
269
+ imageAnnotation: "标注 {value}",
270
+ imageAnnotationPlaceholder: "描述这个部位要修改什么",
271
+ imageEditPrompt: "描述你想怎样修改这张图",
272
+ imageEditDefault: "编辑这张图片。",
273
+ imageRegionNotes: "部位修改:",
274
+ imageEdit: "在输入框中继续编辑",
275
+ imageEditPreparing: "正在添加到输入框…",
276
+ imageEditFailed: "无法把图片添加到输入框。",
277
+ imageRemoveAnnotation: "删除标注"
255
278
  };
256
279
  const en = {
257
280
  nav: "Codex",
@@ -373,8 +396,17 @@ window.__ModuleLoader__.load({
373
396
  imageZoomOut: "Zoom out",
374
397
  imageZoomIn: "Zoom in",
375
398
  imageFit: "Fit to window",
376
- imageRefineHint: "To change this image, say “Edit this image…” in this conversation; only this image is sent as a reference.",
377
- imageNewHint: "To start over, describe a new image; prior images are not included automatically."
399
+ imageAnnotate: "Annotate",
400
+ imageAnnotateHint: "Click the image to add a numbered note",
401
+ imageAnnotation: "Note {value}",
402
+ imageAnnotationPlaceholder: "Describe what should change in this area",
403
+ imageEditPrompt: "Describe how you want to change this image",
404
+ imageEditDefault: "Edit this image.",
405
+ imageRegionNotes: "Region changes:",
406
+ imageEdit: "Continue editing in composer",
407
+ imageEditPreparing: "Adding to composer…",
408
+ imageEditFailed: "Could not add the image to the composer.",
409
+ imageRemoveAnnotation: "Remove note"
378
410
  };
379
411
  const STYLE = `
380
412
  .codexSubscription{display:flex;flex-direction:column;gap:10px;max-width:720px;color:var(--dsw-alias-label-primary);container-type:inline-size}
@@ -409,11 +441,24 @@ window.__ModuleLoader__.load({
409
441
  .codexModelSelect{position:relative;min-width:0}.codexModelSelectTrigger{display:flex;align-items:center;gap:4px;min-width:0;max-width:min(360px,45cqw);height:28px;padding:0 4px 0 8px;border:0;border-radius:24px;outline:0;background:transparent;color:var(--dsw-alias-label-secondary);font-size:13px;font-weight:500;line-height:20px;cursor:pointer}.codexModelSelectTrigger:hover:not(:disabled),.codexModelSelectTrigger[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover)}.codexModelSelectTrigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.codexModelSelectTrigger:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.codexModelSelectBolt{display:block;flex:none;width:14px;height:14px;color:var(--dsw-alias-label-primary)}.codexModelSelectLabel{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.codexModelSelectEffort{flex:none;color:var(--dsw-alias-label-caption)}.codexModelSelectChevron{flex:none;color:var(--dsw-alias-label-caption);transition:transform 120ms}.codexModelSelectTrigger[aria-expanded=true] .codexModelSelectChevron{transform:rotate(180deg)}
410
442
  .codexModelSelectMenu,.codexModelSelectSubmenu{position:absolute;z-index:30;box-sizing:border-box;width:max-content;min-width:min(240px,calc(100vw - 32px));max-width:min(420px,calc(100vw - 32px));max-height:min(360px,calc(100vh - 96px));padding:4px;border:1px solid var(--dsw-alias-border-inverted);border-radius:12px;background:var(--dsw-specific-menu);box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);overflow:hidden}.codexModelSelectMenu{right:0;bottom:calc(100% + 8px)}.codexModelSelectSubmenu{right:calc(100% + 8px);bottom:0;min-width:min(230px,calc(100vw - 32px))}.codexModelSelectCell{display:flex;align-items:center;gap:8px;width:100%;min-width:100%;height:40px;box-sizing:border-box;padding:0 10px;border:0;border-radius:10px;background:transparent;color:inherit;font-size:14px;line-height:22px;text-align:left;cursor:pointer}.codexModelSelectCell:hover,.codexModelSelectCell:focus-visible,.codexModelSelectCell[data-open=true]{background:var(--dsw-alias-interactive-bg-hover);outline:0}.codexModelSelectCell:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.codexModelSelectCellLabel{flex:none;white-space:nowrap}.codexModelSelectCellValue{flex:auto;min-width:0;overflow:hidden;color:var(--dsw-alias-label-tertiary);text-align:right;text-overflow:ellipsis;white-space:nowrap}.codexModelSelectCellChevron{flex:none;color:var(--dsw-alias-label-tertiary)}.codexModelSelectGroups{min-height:0;max-height:352px;overflow-y:auto}.codexModelSelectGroup+.codexModelSelectGroup{margin-top:4px}.codexModelSelectGroupTitle{position:sticky;top:0;z-index:1;padding:5px 8px 3px;background:var(--dsw-specific-menu);color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:500;line-height:18px}.codexModelSelectOption{display:flex;align-items:center;gap:8px;width:100%;min-width:100%;min-height:38px;box-sizing:border-box;padding:6px 8px;border:0;border-radius:10px;outline:0;background:transparent;color:inherit;text-align:left;cursor:pointer}.codexModelSelectOption:hover:not(:disabled),.codexModelSelectOption:focus-visible{background:var(--dsw-alias-interactive-bg-hover)}.codexModelSelectOption:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.codexModelSelectOptionCopy{display:flex;flex:1;min-width:0;flex-direction:column}.codexModelSelectOptionName{overflow:hidden;color:inherit;font-size:14px;font-weight:500;line-height:20px;text-overflow:ellipsis;white-space:nowrap}.codexModelSelectOptionDescription{overflow:hidden;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;text-overflow:ellipsis;white-space:nowrap}.codexModelSelectCheck{display:grid;place-items:center;flex:0 0 18px;color:var(--dsw-alias-label-primary)}.codexModelSelectStatus,.codexModelSelectEmpty{padding:10px;color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}.codexModelSelectError,.codexModelSelectWarning{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;margin-bottom:4px;padding:7px 8px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}.codexModelSelectWarning{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-state-warn-label)}.codexModelSelectRetry{flex:none;padding:0;border:0;background:transparent;color:inherit;font:inherit;font-weight:600;cursor:pointer}
411
443
  .codexModelSelectMenu{overflow:visible}
412
- .codexImageTool{display:flex;flex-direction:column;gap:8px;margin:4px 0;color:var(--dsw-alias-label-primary)}.codexImageToolRow{display:flex;align-items:center;min-height:24px;gap:8px;font-size:13px;line-height:20px}.codexImageToolIcon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;color:var(--dsw-alias-label-secondary)}.codexImageToolIcon::before{content:'';width:8px;height:8px;border:1.5px solid currentColor;border-radius:3px}.codexImageTool[data-state=running] .codexImageToolIcon::before{border-radius:50%;border-right-color:transparent;animation:codexImageSpin 800ms linear infinite}.codexImageTool[data-state=error] .codexImageToolIcon::before{border-color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-state-error-primary)}.codexImageToolTitle{font-weight:500}.codexImageToolState{color:var(--dsw-alias-label-tertiary)}.codexImageToolError{margin:0 0 0 24px;font-size:12px;line-height:18px;color:var(--dsw-alias-state-error-primary)}.codexImageToolGallery{margin-left:24px}.codexGeneratedImageFrame{display:flex;align-items:center;justify-content:center;width:min(240px,100%);min-height:120px;padding:0;overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-tertiary);cursor:pointer}.codexGeneratedImageFrame img{display:block;width:100%;max-height:240px;object-fit:contain}.codexGeneratedImageRetry{min-height:36px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);cursor:pointer}.codexGeneratedImageModal{width:min(920px,calc(100vw - 32px));max-height:calc(100vh - 32px)}.codexGeneratedImageModalContent{min-height:0;overflow:hidden}.codexGeneratedImageViewer{display:flex;min-width:0;flex-direction:column;gap:12px}.codexGeneratedImageStage{display:grid;place-items:center;min-height:280px;max-height:calc(100vh - 260px);overflow:auto;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-module-platform)}.codexGeneratedImageStage img{display:block;max-width:100%;max-height:calc(100vh - 280px);object-fit:contain;transform-origin:center;transition:transform 120ms ease}.codexGeneratedImageMeta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.codexGeneratedImageToolbar{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}.codexGeneratedImageZoom{display:flex;align-items:center;gap:6px}.codexGeneratedImageZoomValue{min-width:44px;color:var(--dsw-alias-label-secondary);font-size:12px;text-align:center}.codexGeneratedImageDownload{display:inline-flex;align-items:center;gap:6px;min-height:32px;box-sizing:border-box;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-primary);font-size:13px;text-decoration:none}.codexGeneratedImageDownload:hover{background:var(--dsw-alias-interactive-bg-hover)}.codexGeneratedImageGuidance{display:flex;flex-direction:column;gap:2px;padding-top:2px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}@keyframes codexImageSpin{to{transform:rotate(360deg)}}
444
+ .codexImageTool{display:flex;flex-direction:column;gap:8px;margin:4px 0;color:var(--dsw-alias-label-primary)}.codexImageToolRow{display:flex;align-items:center;min-height:24px;gap:8px;font-size:13px;line-height:20px}.codexImageToolIcon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;color:var(--dsw-alias-label-secondary)}.codexImageToolIcon::before{content:'';width:8px;height:8px;border:1.5px solid currentColor;border-radius:3px}.codexImageTool[data-state=running] .codexImageToolIcon::before{border-radius:50%;border-right-color:transparent;animation:codexImageSpin 800ms linear infinite}.codexImageTool[data-state=error] .codexImageToolIcon::before{border-color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-state-error-primary)}.codexImageToolTitle{font-weight:500}.codexImageToolState{color:var(--dsw-alias-label-tertiary)}.codexImageToolError{margin:0 0 0 24px;font-size:12px;line-height:18px;color:var(--dsw-alias-state-error-primary)}.codexImageToolGallery{margin-left:24px}.codexGeneratedImageFrame{display:flex;align-items:center;justify-content:center;width:min(240px,100%);height:240px;padding:0;overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:16px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-tertiary);cursor:pointer}.codexGeneratedImageFrame img{display:block;width:100%;height:100%;object-fit:cover}.codexGeneratedImageRetry{min-height:36px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);cursor:pointer}.codexGeneratedImageModal{width:min(920px,calc(100vw - 32px));max-height:calc(100vh - 32px)}.codexGeneratedImageModalContent{min-height:0;overflow:hidden}.codexGeneratedImageViewer{display:flex;min-width:0;flex-direction:column;gap:12px}.codexGeneratedImageStage{display:grid;place-items:center;min-height:280px;max-height:calc(100vh - 260px);overflow:auto;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-module-platform)}.codexGeneratedImageStage img{display:block;max-width:100%;max-height:calc(100vh - 280px);object-fit:contain;transform-origin:center;transition:transform 120ms ease}.codexGeneratedImageMeta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.codexGeneratedImageToolbar{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}.codexGeneratedImageZoom{display:flex;align-items:center;gap:6px}.codexGeneratedImageZoomValue{min-width:44px;color:var(--dsw-alias-label-secondary);font-size:12px;text-align:center}.codexGeneratedImageDownload{display:inline-flex;align-items:center;gap:6px;min-height:32px;box-sizing:border-box;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-primary);font-size:13px;text-decoration:none}.codexGeneratedImageDownload:hover{background:var(--dsw-alias-interactive-bg-hover)}.codexGeneratedImageGuidance{display:flex;flex-direction:column;gap:2px;padding-top:2px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}@keyframes codexImageSpin{to{transform:rotate(360deg)}}
413
445
  .codexImageBeta{padding:0 5px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;color:var(--dsw-alias-label-tertiary);font-size:10px;line-height:16px}
414
446
  @container (max-width:560px){.codexSubscriptionCreditRows{grid-template-columns:1fr}}
415
447
  @container (max-width:480px){.codexSubscriptionAccountRow,.codexSubscriptionSectionHead{align-items:flex-start;flex-direction:column}.codexSubscriptionActions{width:100%}.codexSubscriptionSearchChoices{grid-template-columns:1fr}}
416
448
  @media(max-width:640px){.codexSubscriptionCard{padding:14px}}
449
+ `;
450
+ const IMAGE_STYLE = String.raw`
451
+ .codexGeneratedImageLightbox{position:fixed;inset:0;z-index:1000;display:grid;grid-template-rows:auto minmax(0,1fr) auto;background:var(--dsw-alias-bg-base,#111);color:var(--dsw-alias-label-primary);outline:0}.codexGeneratedImageTopbar{display:flex;align-items:center;justify-content:space-between;gap:20px;min-height:58px;padding:8px 14px;border-bottom:1px solid var(--dsw-alias-border-l2);background:color-mix(in srgb,var(--dsw-alias-bg-base,#111) 92%,transparent);backdrop-filter:blur(18px)}.codexGeneratedImageTopbar>div:first-child{display:flex;min-width:0;flex-direction:column}.codexGeneratedImageTopbar strong{overflow:hidden;font-size:13px;font-weight:600;line-height:20px;text-overflow:ellipsis;white-space:nowrap}.codexGeneratedImageTopbar small{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:17px}.codexGeneratedImageActions{display:flex;align-items:center;gap:6px}.codexGeneratedImageActions button,.codexGeneratedImageActions a{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:5px;height:32px;padding:0 10px;border:1px solid transparent;border-radius:16px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;text-decoration:none;cursor:pointer}.codexGeneratedImageActions button:hover,.codexGeneratedImageActions a:hover,.codexGeneratedImageActions button.is-active{background:var(--dsw-alias-interactive-bg-hover)}.codexGeneratedImageActions button:focus-visible,.codexGeneratedImageActions a:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:1px}.codexGeneratedImageActions button:disabled{opacity:.4;cursor:default}.codexGeneratedImageActions>span{min-width:38px;color:var(--dsw-alias-label-tertiary);font-size:11px;text-align:center}.codexGeneratedImageClose{font-size:20px!important}.codexGeneratedImageCanvas{position:relative;display:grid;place-items:center;min-height:0;overflow:auto;padding:24px;background:var(--dsw-alias-bg-base,#111)}.codexGeneratedImageSurface{position:relative;display:inline-flex;max-width:calc(100vw - 48px);max-height:calc(100vh - 210px);transform-origin:center;transition:transform 120ms ease}.codexGeneratedImageSurface img{display:block;max-width:100%;max-height:calc(100vh - 210px);border-radius:12px;object-fit:contain}.codexGeneratedImageCanvas.is-annotating .codexGeneratedImageSurface{cursor:crosshair}.codexGeneratedImagePin{position:absolute;display:grid;place-items:center;width:24px;height:24px;padding:0;border:2px solid white;border-radius:50%;background:var(--dsw-alias-label-primary);box-shadow:0 1px 4px rgba(0,0,0,.35);color:var(--dsw-alias-bg-base,#111);font:inherit;font-size:11px;font-weight:700;transform:translate(-50%,-50%);cursor:pointer}.codexGeneratedImagePin.is-active{background:var(--dsw-alias-state-business-primary,#3964fe);color:white}.codexGeneratedImageAnnotateHint{position:absolute;bottom:14px;left:50%;padding:6px 10px;border-radius:14px;background:color-mix(in srgb,var(--dsw-alias-bg-layer-3) 90%,transparent);box-shadow:var(--dsw-shadow-lv2);color:var(--dsw-alias-label-secondary);font-size:11px;transform:translateX(-50%)}.codexGeneratedImageEditDock{display:flex;flex-direction:column;gap:8px;padding:10px 14px 14px;border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base))}.codexGeneratedImagePrompt,.codexGeneratedImageAnnotation{display:flex;align-items:center;gap:8px;width:min(820px,100%);margin:0 auto}.codexGeneratedImagePrompt>*:first-child,.codexGeneratedImageAnnotation>*:nth-child(2){min-width:0;flex:1}.codexGeneratedImagePrompt button{flex:none;white-space:nowrap}.codexGeneratedImageAnnotation>span{flex:none;color:var(--dsw-alias-label-secondary);font-size:12px}.codexGeneratedImageAnnotation>button{flex:none;height:28px;padding:0 8px;border:0;border-radius:14px;background:transparent;color:var(--dsw-alias-label-tertiary);font:inherit;font-size:11px;cursor:pointer}.codexGeneratedImageAnnotation>button:hover{background:var(--dsw-alias-interactive-bg-hover)}.codexGeneratedImageEditError{width:min(820px,100%);margin:0 auto;color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:17px}@media(max-width:760px){.codexGeneratedImageTopbar{align-items:flex-start;flex-direction:column}.codexGeneratedImageActions{width:100%;overflow-x:auto}.codexGeneratedImageActions>span{display:none}.codexGeneratedImageCanvas{padding:12px}.codexGeneratedImageSurface{max-width:calc(100vw - 24px);max-height:calc(100vh - 270px)}.codexGeneratedImageSurface img{max-height:calc(100vh - 270px)}.codexGeneratedImagePrompt,.codexGeneratedImageAnnotation{align-items:stretch;flex-direction:column}.codexGeneratedImagePrompt button{width:100%}}
452
+ `;
453
+ const IMAGE_LAYOUT_STYLE = String.raw`
454
+ .codexGeneratedImageWorkspace{display:grid;min-height:0;grid-template-columns:minmax(0,1fr)}
455
+ .codexGeneratedImageWorkspace.has-comments{grid-template-columns:minmax(0,1fr) 296px}
456
+ .codexGeneratedImageComments{display:flex;min-width:0;flex-direction:column;gap:12px;overflow:auto;padding:18px 14px;border-left:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base))}
457
+ .codexGeneratedImageComments>header{display:flex;flex-direction:column;gap:2px}.codexGeneratedImageComments>header strong{font-size:13px;font-weight:600;line-height:20px}.codexGeneratedImageComments>header small{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:17px}
458
+ .codexGeneratedImageCommentList{display:flex;flex-direction:column;gap:8px}.codexGeneratedImageCommentList article{display:grid;grid-template-columns:24px minmax(0,1fr) 24px;align-items:start;gap:7px;padding:9px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-3)}.codexGeneratedImageCommentList article.is-active{border-color:var(--dsw-alias-state-business-primary,#3964fe)}
459
+ .codexGeneratedImageCommentList article>span{display:grid;place-items:center;width:22px;height:22px;border-radius:50%;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-base,#111);font-size:10px;font-weight:700}.codexGeneratedImageCommentList textarea{box-sizing:border-box;width:100%;min-height:64px;resize:vertical;border:0;outline:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;line-height:18px}.codexGeneratedImageCommentList textarea::placeholder{color:var(--dsw-alias-label-dimmed)}
460
+ .codexGeneratedImageCommentList article>button{display:grid;place-items:center;width:22px;height:22px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--dsw-alias-label-tertiary);font:inherit;font-size:17px;cursor:pointer}.codexGeneratedImageCommentList article>button:hover{background:var(--dsw-alias-interactive-bg-hover)}
461
+ @media(max-width:760px){.codexGeneratedImageWorkspace.has-comments{grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr) minmax(118px,34vh)}.codexGeneratedImageComments{border-top:1px solid var(--dsw-alias-border-l2);border-left:0;padding:10px 12px}}
417
462
  `;
418
463
  const unwrap = (response) => {
419
464
  if (!response?.ok) throw new Error(response?.error?.message ?? "Codex RPC failed");
@@ -443,13 +488,28 @@ window.__ModuleLoader__.load({
443
488
  return cleaned.toLowerCase().endsWith(".png") ? cleaned : `${cleaned}.png`;
444
489
  };
445
490
  const imageByteSize = (bytes) => bytes < 1024 * 1024 ? `${Math.max(.1, bytes / 1024).toLocaleString(void 0, { maximumFractionDigits: 1 })} KB` : `${(bytes / 1024 / 1024).toLocaleString(void 0, { maximumFractionDigits: 1 })} MB`;
446
- function CodexGeneratedImage({ attachment, loadImage, t }) {
491
+ function editDraft(prompt, annotations, t) {
492
+ const notes = annotations.map((annotation, index) => ({
493
+ number: index + 1,
494
+ note: annotation.note.trim()
495
+ })).filter((annotation) => annotation.note !== "").map((annotation) => String(annotation.number) + ". " + annotation.note);
496
+ const base = prompt.trim() === "" ? t("imageEditDefault") : prompt.trim();
497
+ return notes.length === 0 ? base : base + "\n\n" + t("imageRegionNotes") + "\n" + notes.join("\n");
498
+ }
499
+ function CodexGeneratedImage({ attachment, loadImage, attachForEdit, t }) {
447
500
  const [attempt, setAttempt] = (0, react.useState)(0);
448
501
  const [error, setError] = (0, react.useState)(false);
449
502
  const [open, setOpen] = (0, react.useState)(false);
450
503
  const [src, setSrc] = (0, react.useState)();
451
504
  const [zoom, setZoom] = (0, react.useState)(1);
505
+ const [annotationMode, setAnnotationMode] = (0, react.useState)(false);
506
+ const [annotations, setAnnotations] = (0, react.useState)([]);
507
+ const [selectedAnnotation, setSelectedAnnotation] = (0, react.useState)();
508
+ const [prompt, setPrompt] = (0, react.useState)("");
509
+ const [editBusy, setEditBusy] = (0, react.useState)(false);
510
+ const [editError, setEditError] = (0, react.useState)(false);
452
511
  const triggerRef = (0, react.useRef)(null);
512
+ const dialogRef = (0, react.useRef)(null);
453
513
  (0, react.useEffect)(() => {
454
514
  let live = true;
455
515
  setError(false);
@@ -471,15 +531,224 @@ window.__ModuleLoader__.load({
471
531
  setOpen(false);
472
532
  window.requestAnimationFrame(() => triggerRef.current?.focus());
473
533
  };
534
+ (0, react.useEffect)(() => {
535
+ if (!open) return void 0;
536
+ const previousOverflow = document.body.style.overflow;
537
+ document.body.style.overflow = "hidden";
538
+ dialogRef.current?.focus();
539
+ const keydown = (event) => {
540
+ if (event.key === "Escape") {
541
+ event.preventDefault();
542
+ close();
543
+ return;
544
+ }
545
+ if (event.key === "Tab") {
546
+ const focusable = [...dialogRef.current.querySelectorAll("button:not(:disabled),a[href],input:not(:disabled),textarea:not(:disabled),[tabindex]:not([tabindex=\"-1\"])")];
547
+ if (focusable.length === 0) return;
548
+ const first = focusable[0];
549
+ const last = focusable.at(-1);
550
+ if (event.shiftKey && document.activeElement === first) {
551
+ event.preventDefault();
552
+ last.focus();
553
+ } else if (!event.shiftKey && document.activeElement === last) {
554
+ event.preventDefault();
555
+ first.focus();
556
+ }
557
+ }
558
+ };
559
+ document.addEventListener("keydown", keydown);
560
+ return () => {
561
+ document.body.style.overflow = previousOverflow;
562
+ document.removeEventListener("keydown", keydown);
563
+ };
564
+ }, [open]);
474
565
  const label = attachment.name ?? t("imageLabel");
475
566
  const downloadName = imageDownloadName(attachment);
476
- const imageMeta = `${attachment.width} × ${attachment.height} · ${imageByteSize(attachment.bytes)}`;
567
+ const imageMeta = attachment.width + " × " + attachment.height + " · " + imageByteSize(attachment.bytes);
568
+ const addAnnotation = (event) => {
569
+ if (!annotationMode || event.target.closest(".codexGeneratedImagePin")) return;
570
+ const bounds = event.currentTarget.getBoundingClientRect();
571
+ const annotation = {
572
+ id: crypto.randomUUID(),
573
+ x: Math.max(0, Math.min(1, (event.clientX - bounds.left) / bounds.width)),
574
+ y: Math.max(0, Math.min(1, (event.clientY - bounds.top) / bounds.height)),
575
+ note: ""
576
+ };
577
+ setAnnotations((value) => [...value, annotation]);
578
+ setSelectedAnnotation(annotation.id);
579
+ };
580
+ const continueEditing = async () => {
581
+ if (editBusy || src === void 0) return;
582
+ setEditBusy(true);
583
+ setEditError(false);
584
+ try {
585
+ await attachForEdit(src, downloadName, editDraft(prompt, annotations, t));
586
+ close();
587
+ } catch {
588
+ setEditError(true);
589
+ } finally {
590
+ setEditBusy(false);
591
+ }
592
+ };
477
593
  if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
478
594
  type: "button",
479
595
  className: "codexGeneratedImageRetry",
480
596
  onClick: () => setAttempt((value) => value + 1),
481
597
  children: t("imageLoadFailed")
482
598
  });
599
+ const lightbox = !open || src === void 0 ? null : (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
600
+ ref: dialogRef,
601
+ className: "codexGeneratedImageLightbox",
602
+ role: "dialog",
603
+ "aria-modal": "true",
604
+ "aria-label": t("imagePreview"),
605
+ tabIndex: -1,
606
+ children: [
607
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
608
+ className: "codexGeneratedImageTopbar",
609
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: imageMeta })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
610
+ className: "codexGeneratedImageActions",
611
+ children: [
612
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
613
+ type: "button",
614
+ className: annotationMode ? "is-active" : "",
615
+ "aria-pressed": annotationMode,
616
+ onClick: () => setAnnotationMode((value) => !value),
617
+ children: t("imageAnnotate")
618
+ }),
619
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
620
+ type: "button",
621
+ "aria-label": t("imageZoomOut"),
622
+ disabled: zoom <= .5,
623
+ onClick: () => setZoom((value) => Math.max(.5, value - .25)),
624
+ children: "−"
625
+ }),
626
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [Math.round(zoom * 100), "%"] }),
627
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
628
+ type: "button",
629
+ "aria-label": t("imageZoomIn"),
630
+ disabled: zoom >= 3,
631
+ onClick: () => setZoom((value) => Math.min(3, value + .25)),
632
+ children: "+"
633
+ }),
634
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
635
+ type: "button",
636
+ onClick: () => setZoom(1),
637
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFullscreenOutline16, { "aria-hidden": "true" }), t("imageFit")]
638
+ }),
639
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
640
+ href: src,
641
+ download: downloadName,
642
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDownloadOutline16, { "aria-hidden": "true" }), t("imageDownload")]
643
+ }),
644
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
645
+ type: "button",
646
+ className: "codexGeneratedImageClose",
647
+ "aria-label": t("imageClosePreview"),
648
+ onClick: close,
649
+ children: "×"
650
+ })
651
+ ]
652
+ })]
653
+ }),
654
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
655
+ className: "codexGeneratedImageWorkspace " + (annotationMode || annotations.length > 0 ? "has-comments" : ""),
656
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("main", {
657
+ className: "codexGeneratedImageCanvas " + (annotationMode ? "is-annotating" : ""),
658
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
659
+ className: "codexGeneratedImageSurface",
660
+ onClick: addAnnotation,
661
+ style: { transform: "scale(" + zoom + ")" },
662
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
663
+ src,
664
+ alt: label
665
+ }), annotations.map((annotation, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
666
+ type: "button",
667
+ className: "codexGeneratedImagePin " + (annotation.id === selectedAnnotation ? "is-active" : ""),
668
+ "aria-label": fill(t("imageAnnotation"), { value: index + 1 }),
669
+ style: {
670
+ left: annotation.x * 100 + "%",
671
+ top: annotation.y * 100 + "%"
672
+ },
673
+ onClick: (event) => {
674
+ event.stopPropagation();
675
+ setSelectedAnnotation(annotation.id);
676
+ },
677
+ children: index + 1
678
+ }, annotation.id))]
679
+ }), annotationMode ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
680
+ className: "codexGeneratedImageAnnotateHint",
681
+ children: t("imageAnnotateHint")
682
+ }) : null]
683
+ }), annotationMode || annotations.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
684
+ className: "codexGeneratedImageComments",
685
+ "aria-label": t("imageAnnotate"),
686
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("imageAnnotate") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("imageAnnotateHint") })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
687
+ className: "codexGeneratedImageCommentList",
688
+ children: annotations.map((annotation, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
689
+ className: annotation.id === selectedAnnotation ? "is-active" : "",
690
+ onClick: () => setSelectedAnnotation(annotation.id),
691
+ children: [
692
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: index + 1 }),
693
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
694
+ value: annotation.note,
695
+ rows: 3,
696
+ "aria-label": fill(t("imageAnnotation"), { value: index + 1 }),
697
+ placeholder: t("imageAnnotationPlaceholder"),
698
+ onFocus: () => setSelectedAnnotation(annotation.id),
699
+ onChange: (event) => {
700
+ const note = event.target.value;
701
+ setAnnotations((value) => value.map((item) => item.id === annotation.id ? {
702
+ ...item,
703
+ note
704
+ } : item));
705
+ }
706
+ }),
707
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
708
+ type: "button",
709
+ "aria-label": t("imageRemoveAnnotation"),
710
+ onClick: (event) => {
711
+ event.stopPropagation();
712
+ setAnnotations((value) => value.filter((item) => item.id !== annotation.id));
713
+ if (selectedAnnotation === annotation.id) setSelectedAnnotation(void 0);
714
+ },
715
+ children: "×"
716
+ })
717
+ ]
718
+ }, annotation.id))
719
+ })]
720
+ }) : null]
721
+ }),
722
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
723
+ className: "codexGeneratedImageEditDock",
724
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
725
+ className: "codexGeneratedImagePrompt",
726
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
727
+ value: prompt,
728
+ placeholder: t("imageEditPrompt"),
729
+ onChange: (event) => setPrompt(event.target.value),
730
+ onKeyDown: (event) => {
731
+ if (event.key === "Enter" && !event.shiftKey) {
732
+ event.preventDefault();
733
+ continueEditing();
734
+ }
735
+ }
736
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
737
+ type: "button",
738
+ disabled: editBusy,
739
+ onClick: () => {
740
+ continueEditing();
741
+ },
742
+ children: editBusy ? t("imageEditPreparing") : t("imageEdit")
743
+ })]
744
+ }), editError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
745
+ className: "codexGeneratedImageEditError",
746
+ role: "alert",
747
+ children: t("imageEditFailed")
748
+ }) : null]
749
+ })
750
+ ]
751
+ }), document.body);
483
752
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
484
753
  ref: triggerRef,
485
754
  type: "button",
@@ -496,78 +765,9 @@ window.__ModuleLoader__.load({
496
765
  src,
497
766
  alt: label
498
767
  })
499
- }), src === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
500
- open,
501
- onClose: close,
502
- title: t("imagePreview"),
503
- closeLabel: t("imageClosePreview"),
504
- className: "codexGeneratedImageModal",
505
- contentClassName: "codexGeneratedImageModalContent",
506
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
507
- className: "codexGeneratedImageViewer",
508
- children: [
509
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
510
- className: "codexGeneratedImageStage",
511
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
512
- src,
513
- alt: label,
514
- style: { transform: `scale(${zoom})` }
515
- })
516
- }),
517
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
518
- className: "codexGeneratedImageMeta",
519
- children: imageMeta
520
- }),
521
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
522
- className: "codexGeneratedImageToolbar",
523
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
524
- className: "codexGeneratedImageZoom",
525
- children: [
526
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
527
- type: "button",
528
- variant: "outline",
529
- "aria-label": t("imageZoomOut"),
530
- title: t("imageZoomOut"),
531
- disabled: zoom <= .5,
532
- onClick: () => setZoom((value) => Math.max(.5, value - .25)),
533
- children: "−"
534
- }),
535
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
536
- className: "codexGeneratedImageZoomValue",
537
- children: [Math.round(zoom * 100), "%"]
538
- }),
539
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
540
- type: "button",
541
- variant: "outline",
542
- "aria-label": t("imageZoomIn"),
543
- title: t("imageZoomIn"),
544
- disabled: zoom >= 3,
545
- onClick: () => setZoom((value) => Math.min(3, value + .25)),
546
- children: "+"
547
- }),
548
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Button, {
549
- type: "button",
550
- variant: "outline",
551
- onClick: () => setZoom(1),
552
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFullscreenOutline16, { "aria-hidden": "true" }), t("imageFit")]
553
- })
554
- ]
555
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
556
- className: "codexGeneratedImageDownload",
557
- href: src,
558
- download: downloadName,
559
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDownloadOutline16, { "aria-hidden": "true" }), t("imageDownload")]
560
- })]
561
- }),
562
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
563
- className: "codexGeneratedImageGuidance",
564
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("imageRefineHint") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("imageNewHint") })]
565
- })
566
- ]
567
- })
568
- })] });
768
+ }), lightbox] });
569
769
  }
570
- function CodexImageToolRow({ block, loadImage, t }) {
770
+ function CodexImageToolRow({ block, loadImage, attachForEdit, t }) {
571
771
  const settled = block?.kind === "tool-result";
572
772
  const image = settled ? block.content.find((item) => item?.type === "image" && item.attachment !== void 0) : void 0;
573
773
  const failed = settled && block.isError === true;
@@ -604,6 +804,7 @@ window.__ModuleLoader__.load({
604
804
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodexGeneratedImage, {
605
805
  attachment: image.attachment,
606
806
  loadImage,
807
+ attachForEdit,
607
808
  t
608
809
  })
609
810
  }),
@@ -1868,7 +2069,7 @@ window.__ModuleLoader__.load({
1868
2069
  ctx.effect(() => {
1869
2070
  const tag = document.createElement("style");
1870
2071
  tag.dataset.plugin = "dsh-codex-subscription";
1871
- tag.textContent = STYLE;
2072
+ tag.textContent = STYLE + IMAGE_STYLE + IMAGE_LAYOUT_STYLE;
1872
2073
  document.head.append(tag);
1873
2074
  return () => tag.remove();
1874
2075
  }, "codex-subscription: style");
@@ -1935,7 +2136,22 @@ window.__ModuleLoader__.load({
1935
2136
  locale: NS,
1936
2137
  inject: (sessionId) => ({
1937
2138
  t,
1938
- loadImage: (attachment) => conversation.resolveImage(sessionId, attachment)
2139
+ loadImage: (attachment) => conversation.resolveImage(sessionId, attachment),
2140
+ attachForEdit: async (src, filename, draft) => {
2141
+ const actx = sessions.scope(sessionId);
2142
+ if (actx === void 0 || typeof conversation.createDraftImages !== "function" || conversation.input?.for === void 0) throw new Error("This DSH version does not provide the image composer bridge");
2143
+ const response = await fetch(src);
2144
+ if (!response.ok) throw new Error("Could not read generated image");
2145
+ const blob = await response.blob();
2146
+ const created = conversation.createDraftImages([new File([blob], filename, { type: blob.type || "image/png" })]);
2147
+ const input = conversation.input.for(actx);
2148
+ if (!input.addImages(created.map((item) => item.id))) {
2149
+ conversation.releaseDraftImages(created);
2150
+ throw new Error("The composer is busy");
2151
+ }
2152
+ sessions.open(sessionId);
2153
+ input.setDraft(draft);
2154
+ }
1939
2155
  })
1940
2156
  }, CodexImageToolRow));
1941
2157
  }
package/lib/index.js CHANGED
@@ -229,6 +229,14 @@ var CodexLoginCoordinator = class {
229
229
  async accountStatus(options) {
230
230
  return publicClone(await this.auth.status(options));
231
231
  }
232
+ supportState() {
233
+ const active = this.#activeId === void 0 ? void 0 : this.#sessions.get(this.#activeId);
234
+ if (active === void 0) return { phase: "idle" };
235
+ return {
236
+ method: active.view.method,
237
+ phase: active.view.phase
238
+ };
239
+ }
232
240
  async start({ method }) {
233
241
  if (!LOGIN_METHODS.has(method)) throw new Error(`unsupported Codex login method: ${String(method)}`);
234
242
  const active = this.#activeId === void 0 ? void 0 : this.#sessions.get(this.#activeId);
@@ -317,7 +325,7 @@ var CodexLoginCoordinator = class {
317
325
  authenticated: status.authenticated === true,
318
326
  ...typeof status.expiresAt === "number" ? { expiresAt: status.expiresAt } : {}
319
327
  };
320
- }).catch((error) => {
328
+ }).catch(async (error) => {
321
329
  if (controller.signal.aborted) {
322
330
  session.view = {
323
331
  id,
@@ -328,6 +336,20 @@ var CodexLoginCoordinator = class {
328
336
  };
329
337
  return;
330
338
  }
339
+ try {
340
+ const status = await this.auth.status();
341
+ if (status.authenticated === true) {
342
+ session.view = {
343
+ id,
344
+ provider: "openai-codex",
345
+ method,
346
+ phase: "authenticated",
347
+ authenticated: true,
348
+ ...typeof status.expiresAt === "number" ? { expiresAt: status.expiresAt } : {}
349
+ };
350
+ return;
351
+ }
352
+ } catch {}
331
353
  session.view = {
332
354
  id,
333
355
  provider: "openai-codex",
@@ -504,7 +526,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0 } = {
504
526
  }
505
527
  //#endregion
506
528
  //#region src/version.js
507
- const PACKAGE_VERSION = "1.6.0";
529
+ const PACKAGE_VERSION = "1.7.1";
508
530
  const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
509
531
  //#endregion
510
532
  //#region src/codex-search.js
@@ -898,7 +920,7 @@ function createCodexImageTool(options) {
898
920
  //#endregion
899
921
  //#region src/diagnostics.js
900
922
  /** Build a support report that deliberately excludes OAuth and account metadata. */
901
- async function createSubscriptionDiagnostics({ auth, preferences }) {
923
+ async function createSubscriptionDiagnostics({ auth, preferences, login = { phase: "idle" } }) {
902
924
  let account = { status: "unknown" };
903
925
  const issues = [];
904
926
  try {
@@ -907,11 +929,16 @@ async function createSubscriptionDiagnostics({ auth, preferences }) {
907
929
  issues.push({ code: "account-status-unavailable" });
908
930
  }
909
931
  return {
910
- schemaVersion: 1,
932
+ schemaVersion: 2,
911
933
  package: "dsh-codex-subscription",
912
934
  version: PACKAGE_VERSION,
913
- runtime: { node: process.version },
935
+ runtime: {
936
+ node: process.version,
937
+ platform: process.platform,
938
+ arch: process.arch
939
+ },
914
940
  account,
941
+ login,
915
942
  provider: {
916
943
  id: "openai-codex",
917
944
  transport: "sse",
@@ -1558,7 +1585,8 @@ function apply(ctx) {
1558
1585
  preferences,
1559
1586
  diagnosticsReader: () => createSubscriptionDiagnostics({
1560
1587
  auth,
1561
- preferences
1588
+ preferences,
1589
+ login: coordinator.supportState()
1562
1590
  })
1563
1591
  });
1564
1592
  ctx.effect(() => ctx.connection.rpc.handle(CHANNEL, handler, { authority: "loopback" }), "codex-subscription: loopback account RPC");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-codex-subscription",
3
- "version": "1.6.0",
3
+ "version": "1.7.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",
@@ -20,8 +20,7 @@
20
20
  "compatibility.json",
21
21
  "LICENSE",
22
22
  "SECURITY.md",
23
- "THIRD_PARTY_NOTICES.md",
24
- "docs/assets/*.png"
23
+ "THIRD_PARTY_NOTICES.md"
25
24
  ],
26
25
  "dsh": {
27
26
  "bundle": {
@@ -95,7 +94,8 @@
95
94
  "@deepseek-ai/dsh-web": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2",
96
95
  "@deepseek-ai/schemastery": "3.18.1",
97
96
  "@earendil-works/pi-ai": "0.82.1",
98
- "react": "^18.2.0"
97
+ "react": "^18.2.0",
98
+ "react-dom": "^18.2.0"
99
99
  },
100
100
  "devDependencies": {
101
101
  "@deepseek-ai/cordis": "4.0.1",
@@ -119,6 +119,7 @@
119
119
  "@earendil-works/pi-ai": "0.82.1",
120
120
  "@heroicons/react": "2.2.0",
121
121
  "react": "18.3.1",
122
+ "react-dom": "18.3.1",
122
123
  "tsdown": "0.22.2"
123
124
  },
124
125
  "scripts": {
Binary file
Binary file
Binary file
Binary file
Binary file