dsh-codex-subscription 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md 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.0` package below; do not install a moving branch.
10
10
  - Never print OAuth credentials, account IDs, authorization callbacks, or credential-store contents.
11
11
  - Preserve the DSH profile, unrelated plugins, sessions, and saved sign-in.
12
12
  - Do not start, stop, or restart DSH without explicit permission.
@@ -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.0
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.0
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.0` 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.
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
 
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
@@ -250,8 +251,17 @@ window.__ModuleLoader__.load({
250
251
  imageZoomOut: "缩小",
251
252
  imageZoomIn: "放大",
252
253
  imageFit: "适合窗口",
253
- imageRefineHint: "要修改这张图,请在当前会话明确说“编辑这张图片……”;插件只会把这张图作为参考。",
254
- imageNewHint: "要重新生成,请直接描述一张新图片;不会自动带入历史图片。"
254
+ imageAnnotate: "标注部位",
255
+ imageAnnotateHint: "点击图片添加编号标注",
256
+ imageAnnotation: "标注 {value}",
257
+ imageAnnotationPlaceholder: "描述这个部位要修改什么",
258
+ imageEditPrompt: "描述你想怎样修改这张图",
259
+ imageEditDefault: "编辑这张图片。",
260
+ imageRegionNotes: "部位修改:",
261
+ imageEdit: "在输入框中继续编辑",
262
+ imageEditPreparing: "正在添加到输入框…",
263
+ imageEditFailed: "无法把图片添加到输入框。",
264
+ imageRemoveAnnotation: "删除标注"
255
265
  };
256
266
  const en = {
257
267
  nav: "Codex",
@@ -373,8 +383,17 @@ window.__ModuleLoader__.load({
373
383
  imageZoomOut: "Zoom out",
374
384
  imageZoomIn: "Zoom in",
375
385
  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."
386
+ imageAnnotate: "Annotate",
387
+ imageAnnotateHint: "Click the image to add a numbered note",
388
+ imageAnnotation: "Note {value}",
389
+ imageAnnotationPlaceholder: "Describe what should change in this area",
390
+ imageEditPrompt: "Describe how you want to change this image",
391
+ imageEditDefault: "Edit this image.",
392
+ imageRegionNotes: "Region changes:",
393
+ imageEdit: "Continue editing in composer",
394
+ imageEditPreparing: "Adding to composer…",
395
+ imageEditFailed: "Could not add the image to the composer.",
396
+ imageRemoveAnnotation: "Remove note"
378
397
  };
379
398
  const STYLE = `
380
399
  .codexSubscription{display:flex;flex-direction:column;gap:10px;max-width:720px;color:var(--dsw-alias-label-primary);container-type:inline-size}
@@ -409,11 +428,24 @@ window.__ModuleLoader__.load({
409
428
  .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
429
  .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
430
  .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)}}
431
+ .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
432
  .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
433
  @container (max-width:560px){.codexSubscriptionCreditRows{grid-template-columns:1fr}}
415
434
  @container (max-width:480px){.codexSubscriptionAccountRow,.codexSubscriptionSectionHead{align-items:flex-start;flex-direction:column}.codexSubscriptionActions{width:100%}.codexSubscriptionSearchChoices{grid-template-columns:1fr}}
416
435
  @media(max-width:640px){.codexSubscriptionCard{padding:14px}}
436
+ `;
437
+ const IMAGE_STYLE = String.raw`
438
+ .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%}}
439
+ `;
440
+ const IMAGE_LAYOUT_STYLE = String.raw`
441
+ .codexGeneratedImageWorkspace{display:grid;min-height:0;grid-template-columns:minmax(0,1fr)}
442
+ .codexGeneratedImageWorkspace.has-comments{grid-template-columns:minmax(0,1fr) 296px}
443
+ .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))}
444
+ .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}
445
+ .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)}
446
+ .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)}
447
+ .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)}
448
+ @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
449
  `;
418
450
  const unwrap = (response) => {
419
451
  if (!response?.ok) throw new Error(response?.error?.message ?? "Codex RPC failed");
@@ -443,13 +475,28 @@ window.__ModuleLoader__.load({
443
475
  return cleaned.toLowerCase().endsWith(".png") ? cleaned : `${cleaned}.png`;
444
476
  };
445
477
  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 }) {
478
+ function editDraft(prompt, annotations, t) {
479
+ const notes = annotations.map((annotation, index) => ({
480
+ number: index + 1,
481
+ note: annotation.note.trim()
482
+ })).filter((annotation) => annotation.note !== "").map((annotation) => String(annotation.number) + ". " + annotation.note);
483
+ const base = prompt.trim() === "" ? t("imageEditDefault") : prompt.trim();
484
+ return notes.length === 0 ? base : base + "\n\n" + t("imageRegionNotes") + "\n" + notes.join("\n");
485
+ }
486
+ function CodexGeneratedImage({ attachment, loadImage, attachForEdit, t }) {
447
487
  const [attempt, setAttempt] = (0, react.useState)(0);
448
488
  const [error, setError] = (0, react.useState)(false);
449
489
  const [open, setOpen] = (0, react.useState)(false);
450
490
  const [src, setSrc] = (0, react.useState)();
451
491
  const [zoom, setZoom] = (0, react.useState)(1);
492
+ const [annotationMode, setAnnotationMode] = (0, react.useState)(false);
493
+ const [annotations, setAnnotations] = (0, react.useState)([]);
494
+ const [selectedAnnotation, setSelectedAnnotation] = (0, react.useState)();
495
+ const [prompt, setPrompt] = (0, react.useState)("");
496
+ const [editBusy, setEditBusy] = (0, react.useState)(false);
497
+ const [editError, setEditError] = (0, react.useState)(false);
452
498
  const triggerRef = (0, react.useRef)(null);
499
+ const dialogRef = (0, react.useRef)(null);
453
500
  (0, react.useEffect)(() => {
454
501
  let live = true;
455
502
  setError(false);
@@ -471,15 +518,224 @@ window.__ModuleLoader__.load({
471
518
  setOpen(false);
472
519
  window.requestAnimationFrame(() => triggerRef.current?.focus());
473
520
  };
521
+ (0, react.useEffect)(() => {
522
+ if (!open) return void 0;
523
+ const previousOverflow = document.body.style.overflow;
524
+ document.body.style.overflow = "hidden";
525
+ dialogRef.current?.focus();
526
+ const keydown = (event) => {
527
+ if (event.key === "Escape") {
528
+ event.preventDefault();
529
+ close();
530
+ return;
531
+ }
532
+ if (event.key === "Tab") {
533
+ const focusable = [...dialogRef.current.querySelectorAll("button:not(:disabled),a[href],input:not(:disabled),textarea:not(:disabled),[tabindex]:not([tabindex=\"-1\"])")];
534
+ if (focusable.length === 0) return;
535
+ const first = focusable[0];
536
+ const last = focusable.at(-1);
537
+ if (event.shiftKey && document.activeElement === first) {
538
+ event.preventDefault();
539
+ last.focus();
540
+ } else if (!event.shiftKey && document.activeElement === last) {
541
+ event.preventDefault();
542
+ first.focus();
543
+ }
544
+ }
545
+ };
546
+ document.addEventListener("keydown", keydown);
547
+ return () => {
548
+ document.body.style.overflow = previousOverflow;
549
+ document.removeEventListener("keydown", keydown);
550
+ };
551
+ }, [open]);
474
552
  const label = attachment.name ?? t("imageLabel");
475
553
  const downloadName = imageDownloadName(attachment);
476
- const imageMeta = `${attachment.width} × ${attachment.height} · ${imageByteSize(attachment.bytes)}`;
554
+ const imageMeta = attachment.width + " × " + attachment.height + " · " + imageByteSize(attachment.bytes);
555
+ const addAnnotation = (event) => {
556
+ if (!annotationMode || event.target.closest(".codexGeneratedImagePin")) return;
557
+ const bounds = event.currentTarget.getBoundingClientRect();
558
+ const annotation = {
559
+ id: crypto.randomUUID(),
560
+ x: Math.max(0, Math.min(1, (event.clientX - bounds.left) / bounds.width)),
561
+ y: Math.max(0, Math.min(1, (event.clientY - bounds.top) / bounds.height)),
562
+ note: ""
563
+ };
564
+ setAnnotations((value) => [...value, annotation]);
565
+ setSelectedAnnotation(annotation.id);
566
+ };
567
+ const continueEditing = async () => {
568
+ if (editBusy || src === void 0) return;
569
+ setEditBusy(true);
570
+ setEditError(false);
571
+ try {
572
+ await attachForEdit(src, downloadName, editDraft(prompt, annotations, t));
573
+ close();
574
+ } catch {
575
+ setEditError(true);
576
+ } finally {
577
+ setEditBusy(false);
578
+ }
579
+ };
477
580
  if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
478
581
  type: "button",
479
582
  className: "codexGeneratedImageRetry",
480
583
  onClick: () => setAttempt((value) => value + 1),
481
584
  children: t("imageLoadFailed")
482
585
  });
586
+ const lightbox = !open || src === void 0 ? null : (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
587
+ ref: dialogRef,
588
+ className: "codexGeneratedImageLightbox",
589
+ role: "dialog",
590
+ "aria-modal": "true",
591
+ "aria-label": t("imagePreview"),
592
+ tabIndex: -1,
593
+ children: [
594
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
595
+ className: "codexGeneratedImageTopbar",
596
+ 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", {
597
+ className: "codexGeneratedImageActions",
598
+ children: [
599
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
600
+ type: "button",
601
+ className: annotationMode ? "is-active" : "",
602
+ "aria-pressed": annotationMode,
603
+ onClick: () => setAnnotationMode((value) => !value),
604
+ children: t("imageAnnotate")
605
+ }),
606
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
607
+ type: "button",
608
+ "aria-label": t("imageZoomOut"),
609
+ disabled: zoom <= .5,
610
+ onClick: () => setZoom((value) => Math.max(.5, value - .25)),
611
+ children: "−"
612
+ }),
613
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [Math.round(zoom * 100), "%"] }),
614
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
615
+ type: "button",
616
+ "aria-label": t("imageZoomIn"),
617
+ disabled: zoom >= 3,
618
+ onClick: () => setZoom((value) => Math.min(3, value + .25)),
619
+ children: "+"
620
+ }),
621
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
622
+ type: "button",
623
+ onClick: () => setZoom(1),
624
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFullscreenOutline16, { "aria-hidden": "true" }), t("imageFit")]
625
+ }),
626
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
627
+ href: src,
628
+ download: downloadName,
629
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDownloadOutline16, { "aria-hidden": "true" }), t("imageDownload")]
630
+ }),
631
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
632
+ type: "button",
633
+ className: "codexGeneratedImageClose",
634
+ "aria-label": t("imageClosePreview"),
635
+ onClick: close,
636
+ children: "×"
637
+ })
638
+ ]
639
+ })]
640
+ }),
641
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
642
+ className: "codexGeneratedImageWorkspace " + (annotationMode || annotations.length > 0 ? "has-comments" : ""),
643
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("main", {
644
+ className: "codexGeneratedImageCanvas " + (annotationMode ? "is-annotating" : ""),
645
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
646
+ className: "codexGeneratedImageSurface",
647
+ onClick: addAnnotation,
648
+ style: { transform: "scale(" + zoom + ")" },
649
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
650
+ src,
651
+ alt: label
652
+ }), annotations.map((annotation, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
653
+ type: "button",
654
+ className: "codexGeneratedImagePin " + (annotation.id === selectedAnnotation ? "is-active" : ""),
655
+ "aria-label": fill(t("imageAnnotation"), { value: index + 1 }),
656
+ style: {
657
+ left: annotation.x * 100 + "%",
658
+ top: annotation.y * 100 + "%"
659
+ },
660
+ onClick: (event) => {
661
+ event.stopPropagation();
662
+ setSelectedAnnotation(annotation.id);
663
+ },
664
+ children: index + 1
665
+ }, annotation.id))]
666
+ }), annotationMode ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
667
+ className: "codexGeneratedImageAnnotateHint",
668
+ children: t("imageAnnotateHint")
669
+ }) : null]
670
+ }), annotationMode || annotations.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
671
+ className: "codexGeneratedImageComments",
672
+ "aria-label": t("imageAnnotate"),
673
+ 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", {
674
+ className: "codexGeneratedImageCommentList",
675
+ children: annotations.map((annotation, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
676
+ className: annotation.id === selectedAnnotation ? "is-active" : "",
677
+ onClick: () => setSelectedAnnotation(annotation.id),
678
+ children: [
679
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: index + 1 }),
680
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
681
+ value: annotation.note,
682
+ rows: 3,
683
+ "aria-label": fill(t("imageAnnotation"), { value: index + 1 }),
684
+ placeholder: t("imageAnnotationPlaceholder"),
685
+ onFocus: () => setSelectedAnnotation(annotation.id),
686
+ onChange: (event) => {
687
+ const note = event.target.value;
688
+ setAnnotations((value) => value.map((item) => item.id === annotation.id ? {
689
+ ...item,
690
+ note
691
+ } : item));
692
+ }
693
+ }),
694
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
695
+ type: "button",
696
+ "aria-label": t("imageRemoveAnnotation"),
697
+ onClick: (event) => {
698
+ event.stopPropagation();
699
+ setAnnotations((value) => value.filter((item) => item.id !== annotation.id));
700
+ if (selectedAnnotation === annotation.id) setSelectedAnnotation(void 0);
701
+ },
702
+ children: "×"
703
+ })
704
+ ]
705
+ }, annotation.id))
706
+ })]
707
+ }) : null]
708
+ }),
709
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
710
+ className: "codexGeneratedImageEditDock",
711
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
712
+ className: "codexGeneratedImagePrompt",
713
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
714
+ value: prompt,
715
+ placeholder: t("imageEditPrompt"),
716
+ onChange: (event) => setPrompt(event.target.value),
717
+ onKeyDown: (event) => {
718
+ if (event.key === "Enter" && !event.shiftKey) {
719
+ event.preventDefault();
720
+ continueEditing();
721
+ }
722
+ }
723
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
724
+ type: "button",
725
+ disabled: editBusy,
726
+ onClick: () => {
727
+ continueEditing();
728
+ },
729
+ children: editBusy ? t("imageEditPreparing") : t("imageEdit")
730
+ })]
731
+ }), editError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
732
+ className: "codexGeneratedImageEditError",
733
+ role: "alert",
734
+ children: t("imageEditFailed")
735
+ }) : null]
736
+ })
737
+ ]
738
+ }), document.body);
483
739
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
484
740
  ref: triggerRef,
485
741
  type: "button",
@@ -496,78 +752,9 @@ window.__ModuleLoader__.load({
496
752
  src,
497
753
  alt: label
498
754
  })
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
- })] });
755
+ }), lightbox] });
569
756
  }
570
- function CodexImageToolRow({ block, loadImage, t }) {
757
+ function CodexImageToolRow({ block, loadImage, attachForEdit, t }) {
571
758
  const settled = block?.kind === "tool-result";
572
759
  const image = settled ? block.content.find((item) => item?.type === "image" && item.attachment !== void 0) : void 0;
573
760
  const failed = settled && block.isError === true;
@@ -604,6 +791,7 @@ window.__ModuleLoader__.load({
604
791
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodexGeneratedImage, {
605
792
  attachment: image.attachment,
606
793
  loadImage,
794
+ attachForEdit,
607
795
  t
608
796
  })
609
797
  }),
@@ -1868,7 +2056,7 @@ window.__ModuleLoader__.load({
1868
2056
  ctx.effect(() => {
1869
2057
  const tag = document.createElement("style");
1870
2058
  tag.dataset.plugin = "dsh-codex-subscription";
1871
- tag.textContent = STYLE;
2059
+ tag.textContent = STYLE + IMAGE_STYLE + IMAGE_LAYOUT_STYLE;
1872
2060
  document.head.append(tag);
1873
2061
  return () => tag.remove();
1874
2062
  }, "codex-subscription: style");
@@ -1935,7 +2123,22 @@ window.__ModuleLoader__.load({
1935
2123
  locale: NS,
1936
2124
  inject: (sessionId) => ({
1937
2125
  t,
1938
- loadImage: (attachment) => conversation.resolveImage(sessionId, attachment)
2126
+ loadImage: (attachment) => conversation.resolveImage(sessionId, attachment),
2127
+ attachForEdit: async (src, filename, draft) => {
2128
+ const actx = sessions.scope(sessionId);
2129
+ 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");
2130
+ const response = await fetch(src);
2131
+ if (!response.ok) throw new Error("Could not read generated image");
2132
+ const blob = await response.blob();
2133
+ const created = conversation.createDraftImages([new File([blob], filename, { type: blob.type || "image/png" })]);
2134
+ const input = conversation.input.for(actx);
2135
+ if (!input.addImages(created.map((item) => item.id))) {
2136
+ conversation.releaseDraftImages(created);
2137
+ throw new Error("The composer is busy");
2138
+ }
2139
+ sessions.open(sessionId);
2140
+ input.setDraft(draft);
2141
+ }
1939
2142
  })
1940
2143
  }, CodexImageToolRow));
1941
2144
  }
package/lib/index.js CHANGED
@@ -504,7 +504,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0 } = {
504
504
  }
505
505
  //#endregion
506
506
  //#region src/version.js
507
- const PACKAGE_VERSION = "1.6.0";
507
+ const PACKAGE_VERSION = "1.7.0";
508
508
  const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
509
509
  //#endregion
510
510
  //#region src/codex-search.js
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.0",
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