dsh-grok-provider 1.0.5 → 1.0.6

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/CHANGELOG.md CHANGED
@@ -1,7 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.6 - 2026-09-18
4
+
5
+ - Fix `UNSUPPORTED_CONTENT` before the network request when DSH normalizes transparent attachments to `image/webp`.
6
+ - Accept bounded WebP projections during capture, transcode transparent WebP to PNG and opaque WebP to JPEG, and keep unsupported WebP off the Responses wire.
7
+ - Add focused WebP regressions and complete a redacted real `grok-4.6` request using the local authenticated Grok account.
8
+
3
9
  ## 1.0.5 - 2026-09-13
4
10
 
11
+ - Published from `49f08ba62bd9eb77fbf122413e08f28fc56d7207` after dual-platform CI `34734335106` via Trusted Publisher `34734462191`. The unique 81-file, 280,675-byte artifact is byte-identical across local, GitHub Release and npm; `latest=1.0.5`, Registry installation, signatures and provenance verify. SHA-256: `7e4772a8335ed9560db2ed59a34b9154f3f1ddc1a60be9707443648d6a72e77f`.
5
12
  - Restore Grok account RPC after the DSH 0.1.5-rc.2 upgrade. Custom-channel registration failed with `cannot get property "webServer" without inject`, leaving the visible settings page unable to read account state or CLI versions.
6
13
  - Register six exact POST routes on the host-authenticated shared `/api` carrier and use namespaced Connection RPC methods from the browser. Retain host trust/authentication, request-schema validation, cancellation, and fiber-owned disposal.
7
14
  - Align Harness peers and locked development dependencies with 0.1.5-rc.2. Add real Connection registry and malformed-envelope regressions.
package/README.en.md CHANGED
@@ -4,11 +4,11 @@
4
4
 
5
5
  Use an already authenticated official Grok Build account from DeepSeek Harness, with dynamic model discovery, streaming reasoning, image input, optional Web/X Search, tool calls, and an account quota/model capability dashboard.
6
6
 
7
- > Unofficial community project; not affiliated with xAI or DeepSeek Harness. This README describes the `dsh-grok-provider@1.0.5` artifact; version `0.1.8` was published and then withdrawn and cannot be reused.
7
+ > Unofficial community project; not affiliated with xAI or DeepSeek Harness. This README describes the `dsh-grok-provider@1.0.6` artifact; version `0.1.8` was published and then withdrawn and cannot be reused.
8
8
 
9
- `1.0.5` repairs unavailable account services and unknown CLI versions after upgrading to DeepSeek Harness `0.1.5-rc.2`. Six account operations now use the host-authenticated shared `/api/grok-auth/*` routes, restoring status, CLI diagnostics, model discovery, and quota reads.
9
+ `1.0.6` fixes transparent WebP attachments being rejected before a Grok request. Transparent WebP images are transcoded to PNG before the Responses request; opaque WebP images are transcoded to JPEG.
10
10
 
11
- This README is included in the `1.0.5` npm tarball, and the exact installation command below is pinned to `1.0.5`. The previous version with completed supply-chain readback is `1.0.4`.
11
+ This README is included in the `1.0.6` npm tarball, and the exact installation command below is pinned to `1.0.6`. The previous version with completed supply-chain readback is `1.0.5`.
12
12
 
13
13
  ## What it provides
14
14
 
@@ -18,7 +18,7 @@ This README is included in the `1.0.5` npm tarball, and the exact installation c
18
18
  | Credentials | Reuses official CLI session state without creating a second token store |
19
19
  | Models | Discovers every model visible to the account at runtime; no static model allowlist |
20
20
  | Conversations | Streaming Responses text, reasoning, encrypted reasoning replay, usage, and finish reasons |
21
- | Images | Only exact `grok-4.6` accepts bounded JPEG/PNG images from Harness attachments; `grok-4.5` and all other models remain text-only |
21
+ | Images | Only exact `grok-4.6` accepts bounded JPEG/PNG/WebP images from Harness attachments; WebP is converted to Grok-compatible PNG/JPEG before sending; `grok-4.5` and all other models remain text-only |
22
22
  | Search | Exact `grok-4.6` provides default-off Web/X Search; switches are saved through the live settings service |
23
23
  | Tools | Returns function calls to the Harness permission layer; the provider never executes tools, and local `web_search` / `x_search` remain when the corresponding Search setting is off |
24
24
  | Account dashboard | Login status, weekly/monthly quota, reset time, dynamic model capabilities and reasoning efforts |
@@ -47,7 +47,7 @@ When the network is reachable and OIDC discovery succeeds, the official CLI open
47
47
  Install the exact version:
48
48
 
49
49
  ```sh
50
- dsh plugin --profile web add dsh-grok-provider@1.0.5
50
+ dsh plugin --profile web add dsh-grok-provider@1.0.6
51
51
  dsh web
52
52
  ```
53
53
 
@@ -145,8 +145,15 @@ Directory inclusion is not an endorsement by xAI or DeepSeek Harness. [Listing P
145
145
 
146
146
  ## Compatibility and scope
147
147
 
148
+ ### `1.0.6` fix boundary
149
+
150
+ - Fix the pre-network `UNSUPPORTED_CONTENT` failure caused when DSH normalizes transparent image attachments to `image/webp`.
151
+ - Accept bounded WebP during capture; transcode transparent WebP to PNG and opaque WebP to JPEG. WebP is never sent directly on the Responses wire.
152
+ - Add transparent and opaque WebP regressions; a real Grok request confirms transparent WebP is sent with PNG MIME and completes SSE.
153
+
148
154
  ### `1.0.5` fix boundary
149
155
 
156
+ - [Release 1.0.5](https://github.com/yoshino-xiao7/dsh-grok-provider/releases/tag/v1.0.5) and npm `latest` are available; dual-platform CI, exact artifact bytes, Registry signatures, and provenance have been verified.
150
157
  - Move six account operations to exact POST routes on shared `/api`; the host retains browser-session authentication, Host/Origin checks, and body limits.
151
158
  - Validate requests with the host schema, reject malformed or mismatched methods, and remove routes with the plugin.
152
159
  - Align dependencies with DSH `0.1.5-rc.2`. An isolated macOS instance verifies status, CLI `1.0.5`, both models, and quota; unauthenticated requests return 401 and foreign Origins return 403.
@@ -191,7 +198,7 @@ Directory inclusion is not an endorsement by xAI or DeepSeek Harness. [Listing P
191
198
  - Two-layer redacted real-account verification passed against the final source: raw Web/X probes each completed one 64-event response, observed the requested Search kind, and reached `completed`; the production adapter completed 5 Responses calls, with direct Web/X both ending in `stop` and a Harness-shaped local `x_search` call/result continuation ending `tool-calls`, `tool-calls`, then `stop`, with one local call in each of the first two turns. That continuation did not place a Harness `x_search` function definition beside an xAI `{ type: "x_search" }` server descriptor in the same wire request; `1.0.1` later isolated that combination as an HTTP 400 conflict. No results, URLs, prompts, identity, or credentials were retained; this is not publication, OAuth, or real-device Windows evidence.
192
199
  - The manifest and lockfile are synchronized at `1.0.0`; the Node 24 suite reports 245 tests, 243 pass, 0 fail, and 2 platform skips. Production audit reports zero vulnerabilities, and the deterministic build/bundle comparison, 72-entry dry-run pack, secret scan, and diff check pass. Code PR #28, main CI run [`33308371009`](https://github.com/yoshino-xiao7/dsh-grok-provider/actions/runs/33308371009), the final release commit, dual-platform final CI, unique artifact, exact authorization, and Registry/signature/attestation/provenance readback are complete.
193
200
 
194
- | Item | `1.0.5` compatibility boundary |
201
+ | Item | `1.0.6` compatibility boundary |
195
202
  | --- | --- |
196
203
  | DeepSeek Harness | Exact support for `0.1.5-rc.2` |
197
204
  | Node.js | `>=24.19.0` |
@@ -201,7 +208,7 @@ Directory inclusion is not an endorsement by xAI or DeepSeek Harness. [Listing P
201
208
  | Grok CLI | No full-version lock; official path, `login --oauth` capability, and production OIDC credential contract are enforced |
202
209
  | Models | Every account catalog model whose backend has a strict codec in this release |
203
210
 
204
- `0.1.11` preserves the published image boundary: image input is enabled only for exact `grok-4.6`, while `grok-4.5` and every other dynamically discovered model remain text-only. Image sending has been confirmed in a real Harness conversation. Images must be verified JPEG/PNG projections from the Harness attachment service. Ordinary user content and images nested one level inside a tool result are supported with fixed `detail:"high"`; URLs, filesystem paths, file IDs, and caller-supplied data URLs are rejected. Private reasoning in ordinary user/system history is omitted while adjacent visible text remains ordered.
211
+ `1.0.6` preserves the published image boundary: image input is enabled only for exact `grok-4.6`, while `grok-4.5` and every other dynamically discovered model remain text-only. Images must be verified JPEG/PNG/WebP projections from the Harness attachment service; WebP is converted to Grok-compatible PNG/JPEG before sending. Ordinary user content and images nested one level inside a tool result are supported with fixed `detail:"high"`; URLs, filesystem paths, file IDs, and caller-supplied data URLs are rejected. Private reasoning in ordinary user/system history is omitted while adjacent visible text remains ordered.
205
212
 
206
213
  Each projected image is limited to 4 MiB, 16,777,216 pixels, and 8192px per side. A request retains at most eight images and 8 MiB of projected image bytes. When a limit is exceeded, the globally oldest images are offloaded to Harness text placeholders; the final JSON remains capped at 16 MiB.
207
214
 
package/README.md CHANGED
@@ -4,11 +4,11 @@
4
4
 
5
5
  让 DeepSeek Harness 使用你已登录的官方 Grok Build 账号:动态模型发现、流式推理、图片输入、可选 Web/X Search、工具调用,以及账号额度与模型能力面板。
6
6
 
7
- > 非官方社区项目,与 xAI 或 DeepSeek Harness 官方无隶属关系。本说明对应 `dsh-grok-provider@1.0.5` 制品;`0.1.8` 曾发布后撤回且版本号不可复用。
7
+ > 非官方社区项目,与 xAI 或 DeepSeek Harness 官方无隶属关系。本说明对应 `dsh-grok-provider@1.0.6` 制品;`0.1.8` 曾发布后撤回且版本号不可复用。
8
8
 
9
- `1.0.5` 修复更新到 DeepSeek Harness `0.1.5-rc.2` 后账户页面显示“服务不可用”、CLI 版本未知的问题。六个账户操作改用主机认证的共享 `/api/grok-auth/*` 路由,恢复登录状态、CLI 检测、模型目录与额度读取。
9
+ `1.0.6` 修复带透明通道的 WebP 图片在 Grok 请求前被拒绝的问题。透明 WebP 会在写入 Responses 请求前转码为 PNG,不透明 WebP 转码为 JPEG。
10
10
 
11
- 本 README 随 `1.0.5` 一起进入 npm tarball,下面的精确安装命令也固定为 `1.0.5`。上一份已完成供应链回读的版本为 `1.0.4`。
11
+ 本 README 随 `1.0.6` 一起进入 npm tarball,下面的精确安装命令也固定为 `1.0.6`。上一份已完成供应链回读的版本为 `1.0.5`。
12
12
 
13
13
  ## 它解决什么问题
14
14
 
@@ -18,7 +18,7 @@
18
18
  | 凭据 | 复用官方 CLI 的登录状态;插件不创建第二份 token 存储 |
19
19
  | 模型 | 运行时读取账号可见的全部 Grok Build 模型,不维护静态模型白名单 |
20
20
  | 对话 | Responses 流式文本、reasoning、加密 reasoning replay、usage 与 finish reason |
21
- | 图片 | 仅精确 `grok-4.6` 接收 Harness attachment 中有界的 JPEG/PNG 图片;`grok-4.5` 与其他模型保持 text-only |
21
+ | 图片 | 仅精确 `grok-4.6` 接收 Harness attachment 中有界的 JPEG/PNG/WebP 图片;WebP 在发送前转为 Grok 接受的 PNG/JPEG,`grok-4.5` 与其他模型保持 text-only |
22
22
  | 搜索 | 精确 `grok-4.6` 提供默认关闭的 Web/X Search;使用实时 settings service 保存开关 |
23
23
  | 工具 | 将 function call 交回 Harness 权限层;Provider 本身不执行工具,关闭对应 Search 开关时保留本地 `web_search` / `x_search` |
24
24
  | 账户面板 | 登录状态、每周/月额度、重置时间、动态模型能力与 reasoning 档位 |
@@ -47,7 +47,7 @@ grok models
47
47
  安装精确版本:
48
48
 
49
49
  ```sh
50
- dsh plugin --profile web add dsh-grok-provider@1.0.5
50
+ dsh plugin --profile web add dsh-grok-provider@1.0.6
51
51
  dsh web
52
52
  ```
53
53
 
@@ -145,8 +145,15 @@ dsh web
145
145
 
146
146
  ## 兼容性与范围
147
147
 
148
+ ### `1.0.6` 修复边界
149
+
150
+ - 修复 DSH 附件库把带透明通道的图片规范化为 `image/webp` 后,`grok-4.6` 在网络请求前失败的问题。
151
+ - 捕获阶段接受有界 WebP;透明 WebP 转为 PNG,不透明 WebP 转为 JPEG,Responses wire 不直接发送 WebP。
152
+ - 增加透明与不透明 WebP 的回归覆盖;本地真实 Grok 请求确认透明 WebP 以 PNG MIME 发出并完成 SSE。
153
+
148
154
  ### `1.0.5` 修复边界
149
155
 
156
+ - [1.0.5 发布](https://github.com/yoshino-xiao7/dsh-grok-provider/releases/tag/v1.0.5) 与 npm `latest` 已更新;双平台 CI、唯一制品字节、Registry 签名和 provenance 均已验证。
150
157
  - 六个账户操作迁移到共享 `/api` 精确 POST 路由;主机保留浏览器会话认证、Host/Origin 检查和请求体限制。
151
158
  - 使用主机请求 schema,拒绝错误方法、畸形请求和路径不匹配;随插件卸载清理路由。
152
159
  - 依赖对齐 DSH `0.1.5-rc.2`。macOS 隔离实例验证状态、CLI `1.0.5`、两个模型和额度;未认证返回 401,跨来源返回 403。
@@ -191,7 +198,7 @@ dsh web
191
198
  - 最终源码完成两层脱敏真实账号复验:原始 Web/X 协议探针各 1 次请求、各 64 events,分别观察到对应 Search 且终态 `completed`;生产 adapter 共完成 5 次 Responses,direct Web/X 均为 `stop`,Harness 形状的本地 `x_search` call/result 续跑三轮依次为 `tool-calls`、`tool-calls`、`stop`,前两轮各 1 次本地调用。该续跑没有在同一 wire request 中同时放入 Harness `x_search` function definition 与 xAI `{ type: "x_search" }` server descriptor;`1.0.1` 后续才隔离出这一 HTTP 400 冲突。未保存结果、URL、prompt、身份或凭据;这些不是发布、OAuth 或 Windows 真机证据。
192
199
  - manifest/lock 已同步为 `1.0.0`;Node 24 全量测试为 245 项、243 pass、0 fail、2 项平台跳过,生产依赖审计为 0 漏洞,确定性 build/bundle、72 项 dry-run pack、秘密模式扫描与 diff 检查均通过。代码 PR #28、main CI run [`33308371009`](https://github.com/yoshino-xiao7/dsh-grok-provider/actions/runs/33308371009)、最终 release commit、双平台 final CI、唯一制品、精确授权及 Registry/signature/attestation/provenance 回读均已完成。
193
200
 
194
- | 项目 | `1.0.5` 兼容边界 |
201
+ | 项目 | `1.0.6` 兼容边界 |
195
202
  | --- | --- |
196
203
  | DeepSeek Harness | 精确支持 `0.1.5-rc.2` |
197
204
  | Node.js | `>=24.19.0` |
@@ -201,7 +208,7 @@ dsh web
201
208
  | Grok CLI | 不锁完整版本;严格校验官方路径、`login --oauth` 能力与生产 OIDC 凭据契约 |
202
209
  | 模型 | 当前账号目录中 backend 已被严格 codec 支持的全部模型 |
203
210
 
204
- `0.1.11` 沿用已发布版本的图片边界:只为精确的 `grok-4.6` 开启图片输入;`grok-4.5` 与其他动态发现的模型继续按 text-only 处理。图片发送已在真实 Harness 对话中确认可用。图片只能来自 Harness attachment service 的已验证 JPEG/PNG 投影,支持普通用户内容和一层工具结果中的图片,并固定使用 `detail:"high"`;不接受 URL、文件路径、file ID 或调用方预制的 data URL。普通 user/system 历史中的私有 reasoning 会被省略并保留相邻可见文本。
211
+ `1.0.6` 沿用已发布版本的图片边界:只为精确的 `grok-4.6` 开启图片输入;`grok-4.5` 与其他动态发现的模型继续按 text-only 处理。图片只能来自 Harness attachment service 的已验证 JPEG/PNG/WebP 投影;WebP 在发送前转换为 Grok 接受的 PNG/JPEG。支持普通用户内容和一层工具结果中的图片,并固定使用 `detail:"high"`;不接受 URL、文件路径、file ID 或调用方预制的 data URL。普通 user/system 历史中的私有 reasoning 会被省略并保留相邻可见文本。
205
212
 
206
213
  每张投影图片最多 4 MiB、16,777,216 像素且任一边不超过 8192px;每次请求最多保留 8 张、投影字节合计最多 8 MiB。超限时按全局最旧优先移除图片并保留 Harness 的文本占位,最终 JSON 仍受 16 MiB 上限约束。
207
214
 
package/SECURITY.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## 支持范围
6
6
 
7
- 本安全策略对应 `dsh-grok-provider@1.0.5` 制品。账户操作使用 DSH `0.1.5-rc.2` 的共享 `/api` 精确 POST 路由;浏览器会话认证、Host/Origin 检查和请求体限制由主机保留。请求使用主机 schema 校验并拒绝路径/方法不匹配。官方 CLI 凭据、固定 xAI origin、Search、工具权限和流后不重放规则保持不变。Windows 真机外部浏览器弹出仍未验收。
7
+ 本安全策略对应 `dsh-grok-provider@1.0.6` 制品。账户操作使用 DSH `0.1.5-rc.2` 的共享 `/api` 精确 POST 路由;浏览器会话认证、Host/Origin 检查和请求体限制由主机保留。请求使用主机 schema 校验并拒绝路径/方法不匹配。官方 CLI 凭据、固定 xAI origin、Search、工具权限和流后不重放规则保持不变。Windows 真机外部浏览器弹出仍未验收。
8
8
 
9
9
  `1.0.3` 不把 HTTP 401/403 解释为 API Key 模式,也不自行刷新 OAuth grant:固定且有界的官方 `grok models` 子进程拥有刷新行为,插件随后重新读取并严格校验共享凭据。第二次拒绝仍为 `AUTH`。SSE source 的无状态 transport failure 和干净过早 EOF 与畸形事件分开;只有前两者能进入安全部分输出保留,status-bearing transport error、工具调用和所有 `INVALID_RESPONSE` 均不得被吞掉。部分内容不生成 replay metadata,提示不包含上游错误正文。
10
10
 
@@ -16,7 +16,7 @@
16
16
 
17
17
  `1.0.2` 的发布回读已关闭:最终 release commit `be200f9352afe93b27dd2856d89c01674f0cd637`,annotated tag object `b7efd3aabb99c73e1747d2d87890cdf9b284c438`,macOS 14 / Windows 2022 final CI run `33318426571`,Trusted Publisher run `33319150964` attempt 1。仓库所有者明确授权的唯一 74 文件制品为 255,282 bytes packed / 789,962 bytes unpacked,SHA-1 `3feddb7048fe4c796037804518999b12ae491802`、SHA-256 `010a21770cb3e4e42b7195984df1f5bf8dc5027066198cf99b7d713ac045f605`、SRI `sha512-TcvvPUXBJZEA728pVnUrXSZebGfIoB5ATG5041wA1OFzOE+hFTO98C5Fxl99WuFW2y7V89gkusYIKCpGlLNQIg==`;冻结候选、GitHub Release asset 与 npm Registry tarball 逐字节一致,npm `latest=1.0.2`。锁定隔离安装、本包 1 个 Registry signature / 2 个 package attestations、安装图 11 个 signed / 2 个 attested packages,以及精确绑定 `release.yml` / `refs/tags/v1.0.2` / release commit / publish run 的 SLSA provenance 均已验证。候选源码的真实账号验收只保留 Web `5/1/0/1/1` 与 X `3/1/0/1/1` 的 Search/non-empty-reasoning/empty-reasoning/non-empty-text/finish 计数;不保存内容、URL、身份、凭据或原始响应。上述证据均不构成 OAuth、完整桌面会话或网络可达 Windows 真机外部浏览器弹出验收。
18
18
 
19
- `0.1.11` 沿用已发布版本的图片边界:只为精确 `grok-4.6` 提供有界图片输入;`grok-4.5` 与所有其他模型保持 text-only。普通 user/system 历史中的私有 reasoning 会被省略并保留相邻可见 text/image;只有有效的同 Provider assistant 历史可进入加密 reasoning replay,一层 tool-result 仍只接受公开 text/image。图片只能来自 Harness attachment service 的已验证 JPEG/PNG 投影,以 `detail:"high"` 发送,并受单图字节、像素、边长、数量、总字节与最终 JSON 上限约束;URL、路径、file ID 和调用方预制 data URL 都会被拒绝。
19
+ `1.0.6` 沿用已发布版本的图片边界:只为精确 `grok-4.6` 提供有界图片输入;`grok-4.5` 与所有其他模型保持 text-only。普通 user/system 历史中的私有 reasoning 会被省略并保留相邻可见 text/image;只有有效的同 Provider assistant 历史可进入加密 reasoning replay,一层 tool-result 仍只接受公开 text/image。图片只能来自 Harness attachment service 的已验证 JPEG/PNG/WebP 投影;WebP 在发送前转为 PNG/JPEG,以 `detail:"high"` 发送,并受单图字节、像素、边长、数量、总字节与最终 JSON 上限约束;URL、路径、file ID 和调用方预制 data URL 都会被拒绝。
20
20
 
21
21
  `0.1.7` 的闭合运行时诊断、CLI 安装恢复、OIDC timeout 脱敏结算和 `IconThinkOutline16` 兼容层在本版保持不变。官方 CLI 仍负责生成登录 URL 与打开外部浏览器;插件不修复系统 DNS、代理、防火墙、VPN 或 CLI 行为。
22
22
 
@@ -0,0 +1,59 @@
1
+ let sharpModule
2
+
3
+ /**
4
+ * Convert a WebP request projection to a format accepted by xAI Responses.
5
+ * Transparent images stay lossless as PNG; opaque images use JPEG to keep the
6
+ * request bounded without sending an unsupported WebP data URL upstream.
7
+ */
8
+ export async function transcodeRequestImage(
9
+ { data, hasAlpha },
10
+ { maxBytes, maxPixels, maxDimension },
11
+ ) {
12
+ const mediaType = hasAlpha ? "image/png" : "image/jpeg"
13
+ const sharp = await loadSharp()
14
+ const image = sharp(data, {
15
+ failOn: "error",
16
+ limitInputPixels: maxPixels,
17
+ }).toColourspace("srgb")
18
+ const metadata = await image.metadata()
19
+ if (
20
+ !Number.isSafeInteger(metadata.width) ||
21
+ !Number.isSafeInteger(metadata.height) ||
22
+ metadata.width <= 0 ||
23
+ metadata.height <= 0 ||
24
+ metadata.width > maxDimension ||
25
+ metadata.height > maxDimension ||
26
+ metadata.width * metadata.height > maxPixels
27
+ ) {
28
+ throw new Error("The source image exceeds the route policy")
29
+ }
30
+ const encoded = hasAlpha
31
+ ? image.png({ compressionLevel: 9 })
32
+ : image.jpeg({ quality: 90, chromaSubsampling: "4:4:4" })
33
+ const result = await encoded.toBuffer({ resolveWithObject: true })
34
+ if (
35
+ !(result.data instanceof Uint8Array) ||
36
+ result.data.byteLength === 0 ||
37
+ result.data.byteLength > maxBytes ||
38
+ !Number.isSafeInteger(result.info.width) ||
39
+ !Number.isSafeInteger(result.info.height) ||
40
+ result.info.width <= 0 ||
41
+ result.info.height <= 0 ||
42
+ result.info.width * result.info.height > maxPixels
43
+ ) {
44
+ throw new Error("The transcoded request image exceeds the route policy")
45
+ }
46
+ return {
47
+ data: new Uint8Array(result.data),
48
+ mediaType,
49
+ bytes: result.data.byteLength,
50
+ width: result.info.width,
51
+ height: result.info.height,
52
+ hasAlpha,
53
+ }
54
+ }
55
+
56
+ async function loadSharp() {
57
+ sharpModule ??= import("sharp").then((module) => module.default ?? module)
58
+ return sharpModule
59
+ }
@@ -1,5 +1,6 @@
1
1
  import { offloadRequestImagesWithPolicy, offloadedImageText } from "@deepseek-ai/dsh-llm"
2
2
 
3
+ import { transcodeRequestImage } from "./image-transcoder.mjs"
3
4
  import {
4
5
  ResponsesRequestTooLargeError,
5
6
  UnsupportedResponsesRequestError,
@@ -12,7 +13,7 @@ const MAX_CONTENT_BLOCKS = 20_000
12
13
  const FUNCTION_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/
13
14
  const SEARCH_MODEL_ID = "grok-4.6"
14
15
  const CAPTURE_IMAGE_POLICY = Object.freeze({
15
- mediaTypes: Object.freeze(["image/jpeg", "image/png"]),
16
+ mediaTypes: Object.freeze(["image/jpeg", "image/png", "image/webp"]),
16
17
  })
17
18
  const EMPTY_SERVER_TOOLS = Object.freeze([])
18
19
  const DEFAULT_SEARCH_POLICY = Object.freeze({
@@ -48,11 +49,15 @@ export class InvalidRequestImageProjectionError extends Error {
48
49
 
49
50
  export function createResponsesRequestCompiler({
50
51
  getAttachmentStore = () => undefined,
52
+ transcodeImage = transcodeRequestImage,
51
53
  searchPolicy,
52
54
  } = {}) {
53
55
  if (typeof getAttachmentStore !== "function") {
54
56
  throw new TypeError("Invalid Grok attachment store source")
55
57
  }
58
+ if (typeof transcodeImage !== "function") {
59
+ throw new TypeError("Invalid Grok image transcoder")
60
+ }
56
61
  const capturedSearchPolicy = captureSearchPolicy(searchPolicy)
57
62
 
58
63
  const prepare = (options) => {
@@ -95,7 +100,7 @@ export function createResponsesRequestCompiler({
95
100
  validateImagePlacements(messages)
96
101
  const imageMessages = snapshotImageRequestMessages(messages, model)
97
102
  const blocks = collectImageBlocks(imageMessages)
98
- const refs = indexUniqueImageRefs(blocks, CAPTURE_IMAGE_POLICY)
103
+ const refs = indexUniqueImageRefs(blocks)
99
104
  encodeRequest({ messages: imageMessages, requestImages: placeholderRequestImages(blocks) })
100
105
 
101
106
  return Object.freeze({
@@ -113,6 +118,7 @@ export function createResponsesRequestCompiler({
113
118
  route,
114
119
  serverTools,
115
120
  signal,
121
+ transcodeImage,
116
122
  }),
117
123
  })
118
124
  }
@@ -135,19 +141,20 @@ async function compileImageRequest({
135
141
  route,
136
142
  serverTools,
137
143
  signal,
144
+ transcodeImage,
138
145
  }) {
139
146
  if (!isMatchingRoute({ model, provider }, route)) throw new UnsupportedResponsesRequestError()
140
147
  validateSearchRoute(route, serverTools, model)
141
148
  signal?.throwIfAborted()
142
149
  const policy = parseImagePolicy(route)
143
- for (const ref of capturedRefs.values()) validateImageRef(ref, policy)
150
+ for (const ref of capturedRefs.values()) validateImageRef(ref, CAPTURE_IMAGE_POLICY)
144
151
  let messages = offloadRequestImagesWithPolicy(capturedMessages, {
145
152
  representation: "raw",
146
153
  maxImages: policy.maxImages,
147
154
  placeholder: offloadedImageText,
148
155
  })
149
156
  const blocks = collectImageBlocks(messages)
150
- const refs = indexUniqueImageRefs(blocks, policy)
157
+ const refs = indexUniqueImageRefs(blocks)
151
158
  const store = getAttachmentStore()
152
159
  if (!store || typeof store.readImageRequest !== "function") {
153
160
  throw new UnsupportedImageInputError()
@@ -159,7 +166,10 @@ async function compileImageRequest({
159
166
  signal?.throwIfAborted()
160
167
  const version = captureRequestImage(returned, policy)
161
168
  validateRequestImage(version, ref, policy)
162
- versionsById.set(attachmentId, version)
169
+ versionsById.set(
170
+ attachmentId,
171
+ await normalizeRequestImage(version, policy, transcodeImage),
172
+ )
163
173
  }))
164
174
 
165
175
  const requestImages = new Map(blocks.map((block) => [
@@ -612,10 +622,10 @@ function collectImageBlocks(messages) {
612
622
  return blocks
613
623
  }
614
624
 
615
- function indexUniqueImageRefs(blocks, policy) {
625
+ function indexUniqueImageRefs(blocks) {
616
626
  const refs = new Map()
617
627
  for (const block of blocks) {
618
- validateImageRef(block.attachment, policy)
628
+ validateImageRef(block.attachment, CAPTURE_IMAGE_POLICY)
619
629
  const attachmentId = String(block.attachment.attachmentId)
620
630
  const existing = refs.get(attachmentId)
621
631
  if (existing !== undefined && !sameImageRef(existing, block.attachment)) {
@@ -653,7 +663,7 @@ function validateRequestImage(version, ref, policy) {
653
663
  !isPlainObject(version.attachment) ||
654
664
  !sameImageRef(version.attachment, ref) ||
655
665
  !(version.data instanceof Uint8Array) ||
656
- !policy.mediaTypes.includes(version.mediaType) ||
666
+ !isSupportedProjectionMediaType(version.mediaType, policy) ||
657
667
  !isPositiveSafeInteger(version.bytes) ||
658
668
  version.bytes !== version.data.byteLength ||
659
669
  version.bytes > policy.readPolicy.maxBytes ||
@@ -671,6 +681,42 @@ function validateRequestImage(version, ref, policy) {
671
681
  }
672
682
  }
673
683
 
684
+ async function normalizeRequestImage(version, policy, transcodeImage) {
685
+ if (version.mediaType !== "image/webp") return version
686
+
687
+ let transcoded
688
+ try {
689
+ transcoded = await transcodeImage(version, {
690
+ ...policy.readPolicy,
691
+ maxDimension: policy.maxDimension,
692
+ })
693
+ } catch (error) {
694
+ if (error instanceof InvalidRequestImageProjectionError) throw error
695
+ throw new InvalidRequestImageProjectionError()
696
+ }
697
+ if (!isPlainObject(transcoded) || !policy.mediaTypes.includes(transcoded.mediaType)) {
698
+ throw new InvalidRequestImageProjectionError()
699
+ }
700
+ const normalized = {
701
+ ...version,
702
+ variantId: `${version.variantId}:grok-${transcoded?.mediaType ?? "unknown"}`,
703
+ data: transcoded?.data,
704
+ mediaType: transcoded?.mediaType,
705
+ bytes: transcoded?.bytes,
706
+ width: transcoded?.width,
707
+ height: transcoded?.height,
708
+ depth: "uchar",
709
+ space: "srgb",
710
+ hasAlpha: transcoded?.hasAlpha,
711
+ }
712
+ validateRequestImage(normalized, version.attachment, policy)
713
+ return captureRequestImage(normalized, policy)
714
+ }
715
+
716
+ function isSupportedProjectionMediaType(mediaType, policy) {
717
+ return policy.mediaTypes.includes(mediaType) || mediaType === "image/webp"
718
+ }
719
+
674
720
  function captureRequestImage(version, policy) {
675
721
  if (!isPlainObject(version)) throw new InvalidRequestImageProjectionError()
676
722
  const captured = {
@@ -769,6 +815,11 @@ function hasExpectedMagic(data, mediaType) {
769
815
  if (mediaType === "image/jpeg") {
770
816
  return data.length >= 3 && data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff
771
817
  }
818
+ if (mediaType === "image/webp") {
819
+ return data.length >= 12 &&
820
+ data[0] === 0x52 && data[1] === 0x49 && data[2] === 0x46 && data[3] === 0x46 &&
821
+ data[8] === 0x57 && data[9] === 0x45 && data[10] === 0x42 && data[11] === 0x50
822
+ }
772
823
  return data.length >= 8 &&
773
824
  data[0] === 0x89 && data[1] === 0x50 && data[2] === 0x4e && data[3] === 0x47 &&
774
825
  data[4] === 0x0d && data[5] === 0x0a && data[6] === 0x1a && data[7] === 0x0a
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## 1.0.5 / DSH 0.1.5-rc.2
4
4
 
5
+ 发布完成:npm `latest=1.0.5`;最终提交 `49f08ba62bd9eb77fbf122413e08f28fc56d7207`,双平台 CI `34734335106`,Trusted Publisher `34734462191`。唯一 81 文件制品的 SHA-256 为 `7e4772a8335ed9560db2ed59a34b9154f3f1ddc1a60be9707443648d6a72e77f`;Release/Registry 字节一致,Registry 安装、签名和 SLSA provenance 已验证。详见 [发布检查表](10-release-checklist.md)。
6
+
5
7
  当前制品:`dsh-grok-provider@1.0.5`。账户 RPC 使用主机认证的共享 `/api/grok-auth/*` 路由,修复升级宿主后的状态、CLI 检测、模型目录和额度不可用。依赖对齐 DSH `0.1.5-rc.2`;旧版宿主需先升级。
6
8
 
7
9
  macOS 隔离宿主已验证状态、CLI `1.0.5`、两个模型和额度读取,以及 401/403 认证边界。真实生成和 Windows 真机浏览器登录未重测。版本说明见 [v1.0.5](releases/v1.0.5.md),设计见 [ADR-0012](adr/0012-shared-api-auth-routes.md)。发布制品摘要和 Registry 回读记录由发布检查表保存。
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## 1.0.5 / DSH 0.1.5-rc.2
4
4
 
5
+ 发布完成:npm `latest=1.0.5`;最终提交 `49f08ba62bd9eb77fbf122413e08f28fc56d7207`,双平台 CI `34734335106`,Trusted Publisher `34734462191`。唯一 81 文件制品的 SHA-256 为 `7e4772a8335ed9560db2ed59a34b9154f3f1ddc1a60be9707443648d6a72e77f`;Release/Registry 字节一致,Registry 安装、签名和 SLSA provenance 已验证。详见 [发布检查表](10-release-checklist.md)。
6
+
5
7
  当前制品:`dsh-grok-provider@1.0.5`。账户 RPC 使用主机认证的共享 `/api/grok-auth/*` 路由,修复升级宿主后的状态、CLI 检测、模型目录和额度不可用。依赖对齐 DSH `0.1.5-rc.2`;旧版宿主需先升级。
6
8
 
7
9
  macOS 隔离宿主已验证状态、CLI `1.0.5`、两个模型和额度读取,以及 401/403 认证边界。真实生成和 Windows 真机浏览器登录未重测。版本说明见 [v1.0.5](releases/v1.0.5.md),设计见 [ADR-0012](adr/0012-shared-api-auth-routes.md)。发布制品摘要和 Registry 回读记录由发布检查表保存。
@@ -295,6 +295,19 @@ English summary: every release must close documentation, security, tests, determ
295
295
  - [x] 账户操作使用主机认证的共享 API 精确路由;测试覆盖 schema、路径/方法一致性、取消、路由清理和真实 Connection 注册。
296
296
  - [x] macOS 隔离 DSH 0.1.5-rc.2 只读检查恢复登录状态、CLI 1.0.5、grok-4.6/grok-4.5 与额度;无认证为 401、跨来源为 403。
297
297
  - [x] GitHub PR/双平台 CI、防强推/删除保护和私密漏洞报告已核对;npm environment 的 Secret 名称列表为空。
298
- - [ ] 最终双平台 CI、唯一 tarball 摘要、隔离制品安装、GitHub Release、Trusted Publisher、Registry 字节与 provenance 回读在发布完成后登记。
298
+ - [x] 最终双平台 CI、唯一 tarball 摘要、隔离制品安装、GitHub Release、Trusted Publisher、Registry 字节与 provenance 已完成,记录见下。
299
299
 
300
300
  本次未重测真实模型生成或 Windows 真机浏览器登录,也未替换用户桌面的受管插件。
301
+
302
+ ## 1.0.5 发布完成(2026-09-13)
303
+
304
+ - [x] 代码与发布 PR [#46](https://github.com/yoshino-xiao7/dsh-grok-provider/pull/46) 合并为 `49f08ba62bd9eb77fbf122413e08f28fc56d7207`;主分支 CI [34734335106](https://github.com/yoshino-xiao7/dsh-grok-provider/actions/runs/34734335106) 的 macOS 14 / Windows 2022 均成功。
305
+ - [x] 最终提交的 Node 24.19.0 测试为 278 项、276 通过、0 失败、2 平台跳过;生产依赖审计为 0 漏洞。
306
+ - [x] 从干净最终提交冻结唯一 `dsh-grok-provider-1.0.5.tgz`:81 文件,280,675 bytes packed、865,584 bytes unpacked;SHA-256 `7e4772a8335ed9560db2ed59a34b9154f3f1ddc1a60be9707443648d6a72e77f`;SRI `sha512-GPXfCgxJGJ+CGzSkTwTaSiXmhLYs8cgw7JOjwd9P7gHmTG3LZ2wqqMhKlfEtZw0Rc10foSVqwN8d8P2iK2RAKQ==`。
307
+ - [x] 同一 tarball 安装到全新隔离 DSH 0.1.5-rc.2 profile,状态、CLI 版本 1.0.5、模型和额度均返回成功;无认证 401、跨来源 403。测试实例已关闭。
308
+ - [x] Annotated tag `v1.0.5` 指向最终提交;[GitHub Release](https://github.com/yoshino-xiao7/dsh-grok-provider/releases/tag/v1.0.5) 只有这一份 tarball。Trusted Publisher [34734462191 attempt 1](https://github.com/yoshino-xiao7/dsh-grok-provider/actions/runs/34734462191/attempts/1) 成功。
309
+ - [x] npm `latest=1.0.5`;本地、GitHub Release 和 Registry tarball 逐字节一致。Registry 精确版本安装、Host 导出和 client 字节验证通过。
310
+ - [x] Registry metadata 含 1 个签名和 2 个 attestations;`npm audit signatures` 验证安装图中的 18 个签名包、3 个 attested 包。SLSA subject digest、repository、workflow、tag、commit 与发布 run 全部匹配。
311
+ - [x] 受管目录仍固定历史已验收的 0.1.0 / darwin-arm64 条目;本次没有伪造 1.0.5 的受管桌面安装验收或修改该来源。
312
+
313
+ 本次发布未替换用户正在使用的桌面插件。Windows 真机浏览器登录和真实模型生成仍未重测。正式 tarball 保持不可变,本记录只更新仓库文档。
package/docs/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## 1.0.5 / DSH 0.1.5-rc.2
4
4
 
5
+ 发布完成:npm `latest=1.0.5`;最终提交 `49f08ba62bd9eb77fbf122413e08f28fc56d7207`,双平台 CI `34734335106`,Trusted Publisher `34734462191`。唯一 81 文件制品的 SHA-256 为 `7e4772a8335ed9560db2ed59a34b9154f3f1ddc1a60be9707443648d6a72e77f`;Release/Registry 字节一致,Registry 安装、签名和 SLSA provenance 已验证。详见 [发布检查表](10-release-checklist.md)。
6
+
5
7
  当前制品:`dsh-grok-provider@1.0.5`。账户 RPC 使用主机认证的共享 `/api/grok-auth/*` 路由,修复升级宿主后的状态、CLI 检测、模型目录和额度不可用。依赖对齐 DSH `0.1.5-rc.2`;旧版宿主需先升级。
6
8
 
7
9
  macOS 隔离宿主已验证状态、CLI `1.0.5`、两个模型和额度读取,以及 401/403 认证边界。真实生成和 Windows 真机浏览器登录未重测。版本说明见 [v1.0.5](releases/v1.0.5.md),设计见 [ADR-0012](adr/0012-shared-api-auth-routes.md)。发布制品摘要和 Registry 回读记录由发布检查表保存。
@@ -0,0 +1,43 @@
1
+ ## 中文
2
+
3
+ `1.0.6` 修复 DSH 附件库把带透明通道的图片规范化为 `image/webp` 后,Grok 请求在网络请求之前失败的问题。
4
+
5
+ 发布后安装精确版本:
6
+
7
+ ```sh
8
+ dsh plugin --profile web add dsh-grok-provider@1.0.6
9
+ ```
10
+
11
+ ### 修复
12
+
13
+ - 捕获阶段接受有界 `image/webp` 附件引用。
14
+ - 带 alpha 的 WebP 在写入 Responses `input_image` 前转为 PNG。
15
+ - 不透明 WebP 转为 JPEG。
16
+ - WebP 不会直接透传到 Grok;其他图片输入和精确 `grok-4.6` 路由边界保持不变。
17
+
18
+ ### 验证
19
+
20
+ - 回归测试覆盖透明 WebP → PNG 和不透明 WebP → JPEG。
21
+ - 使用本机已登录的 Grok Build 凭据对 `grok-4.6` 完成真实透明 WebP 请求:HTTP 200、SSE 正常完成,wire MIME 为 `image/png`。
22
+
23
+ ## English
24
+
25
+ `1.0.6` fixes pre-network failures when DSH normalizes transparent image attachments to `image/webp`.
26
+
27
+ Install the exact version after publication:
28
+
29
+ ```sh
30
+ dsh plugin --profile web add dsh-grok-provider@1.0.6
31
+ ```
32
+
33
+ ### Fix
34
+
35
+ - Accept bounded `image/webp` attachment references during capture.
36
+ - Transcode alpha WebP to PNG before writing a Responses `input_image`.
37
+ - Transcode opaque WebP to JPEG.
38
+ - Never send WebP directly to Grok; existing image and exact `grok-4.6` route boundaries remain unchanged.
39
+
40
+ ### Verification
41
+
42
+ - Regression coverage checks transparent WebP → PNG and opaque WebP → JPEG.
43
+ - A real `grok-4.6` transparent WebP request using the local authenticated Grok Build account returned HTTP 200, completed SSE, and sent `image/png` on the wire.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-grok-provider",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Clean-room Grok Build provider for DeepSeek Harness with official CLI browser authentication",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -79,6 +79,9 @@
79
79
  "@deepseek-ai/dsh-commands": { "optional": true },
80
80
  "@deepseek-ai/dsh-subprocess": { "optional": true }
81
81
  },
82
+ "dependencies": {
83
+ "sharp": "^0.35.4"
84
+ },
82
85
  "devDependencies": {
83
86
  "@deepseek-ai/cordis": "4.0.2",
84
87
  "@deepseek-ai/dsh-commands": "0.1.5-rc.2",