修复插件读取压缩 JSON 时解析崩溃的问题
29.6/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/9/27 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Geighlord007/dshpatch该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 修复压缩响应解析崩溃
展开完整介绍(131 字)↓
给通过 Node 内置 fetch 读 JSON 的 DSH(DeepSeek Harness)插件打补丁:undici 8 的全局 dispatcher 会丢掉 content-encoding,压缩过的响应体到 JSON.parse 手里还是原始 gzip。
README
由 DeepSeek 最新模型翻译生成dshpatch
在 DSH(DeepSeek Harness)0.1.7-rc.1 上,对两个第三方插件的修复补丁。
一句话:DSH 宿主进程里 undici 8 注册的全局 dispatcher 会让 Node 内置 fetch 丢掉 content-encoding,压缩响应于是变成“裸压缩字节”——所有直接用全局 fetch 读 JSON 的插件都会崩。
症状
搜索类工具会报成这样(长得很怪,但很好认):
WebError: WEB_PROVIDER_ERROR
Error: Exa returned an unprocessable response body: SyntaxError: Unexpected token '', "�"... is not valid JSON
Error: Unexpected token '', "�"... is not valid JSON
注意状态码是 200——不是网络错误,是“收到了但读不懂”。
展开完整文档(README 剩余 1 节)
dshpatch
在 DSH(DeepSeek Harness)0.1.7-rc.1 上,对两个第三方插件的修复补丁。
一句话:DSH 宿主进程里 undici 8 注册的全局 dispatcher 会让 Node 内置 fetch 丢掉 content-encoding,压缩响应于是变成“裸压缩字节”——所有直接用全局 fetch 读 JSON 的插件都会崩。
症状
搜索类工具会报成这样(长得很怪,但很好认):
WebError: WEB_PROVIDER_ERROR
Error: Exa returned an unprocessable response body: SyntaxError: Unexpected token '', "�"... is not valid JSON
Error: Unexpected token '', "�"... is not valid JSON
注意状态码是 200——不是网络错误,是“收到了但读不懂”。
根因
三份 undici 同时存在于一个进程:
| 位置 | 版本 | 谁在用 | 说明 |
| Node 22.23.2 内置 | 无版本号(旧世代) | 你的插件里直接写的 fetch() | globalThis.fetch |
| DSH 安装树 dsh/node_modules/undici | 8.11.0 | @deepseek-ai/dsh-http-proxy、dsh-web-fetch-http(web_fetch) | 被注册成全局 dispatcher |
| profile profiles/web/node_modules/undici | 7.29.0 | dshmarket 等 profile 插件 | 插件市场自带的依赖 |
关键机制:npm 版 undici 只要被 import,就会把自己的一份 Agent 注册到
Symbol.for('undici.globalDispatcher.1') —— 这是跨副本共享的注册符号,
而 Node 内置 fetch 也读这个符号。跨大版本之后,响应头被丢掉、响应体仍是压缩的。
实测矩阵(同机、同 Node、同一个 Exa 请求):
| fetch 实现 | 全局 dispatcher | 结果 |
| Node 内置 fetch | 无 | ✅ |
| Node 内置 fetch | app undici 8.11.0 | ❌ 复现(ce=null,body 是裸 gzip) |
| Node 内置 fetch | profile undici 7.29.0 | ✅ |
| undici 8.11.0 自带 fetch | app undici 8.11.0 | ✅ |
| undici 7.29.0 自带 fetch | app undici 8.11.0 | ❌ |
规律:fetch 与 dispatcher 必须来自同一份 undici。
导入顺序实验(tools/exa-dispatcher-trigger.mjs):
刚启动 dispatcher=none 内置 fetch OK import 8.11.0 之后 dispatcher=Dispatcher1Wrapper 内置 fetch BROKEN 先 import 7.29.0 dispatcher=Agent 内置 fetch OK 再 import 8.11.0 dispatcher=Dispatcher1Wrapper 内置 fetch BROKEN ← v8 会覆盖
所以触发时刻是:进程里第一次走到会 import npm undici 的路径(例如第一次用 web_fetch)之后,所有用全局 fetch 的插件都开始中招。这解释了“同一台机器上,先好好的,后来突然全报错”。
补丁
| 补丁 | 目标 | 改动 |
| patches/qp-exa-dynamic-0.1.0.patch | qp-exa-dynamic@0.1.0 → lib/index.js | 请求头加 accept-encoding: identity;响应体改由新增的 readSearchBody() 读取(先取字节,按魔数解 gzip / zstd,brotli 兜底,容忍 BOM) |
| patches/dsh-find-plugin-0.3.7.patch | dsh-find-plugin@0.3.7 → lib/github.js、lib/registry.js | 同上;新增共用模块 lib/safe-json.js(导出 readJson 与 IDENTITY_ACCEPT_ENCODING) |
设计原则:与 undici 版本彻底解耦 ——不依赖任何一份 undici 的解压行为,同时不绕过 DSH 的代理策略(仍然走全局 dispatcher 发请求)。
用法
默认路径($env:USERPROFILE\.dsh\...) pwsh -File .\apply.ps1
自定义 profile / 插件目录 pwsh -File .\apply.ps1 -Profile "D:\other\.dsh\profiles\web" -ExaPlugin "D:\other\plugins\qp-exa-dynamic"
脚本会先 git apply --check,通过才应用;已打过补丁会自动跳过。
改完必须重启 DSH 才生效(插件不做热重载)。
手动应用单个补丁:
cd "$env:USERPROFILE\.dsh\plugins\qp-exa-dynamic"
git -c core.autocrlf=false apply "\patches\qp-exa-dynamic-0.1.0.patch"
-c core.autocrlf=false 不能省:否则 Windows 上的 git 会改写行尾,补丁结果与预期不一致。
验证
node tools\identity-demo.mjs # 演示 identity 头的作用(压缩 vs 不压缩)bash
node tools\exa-dispatcher-trigger.mjs # 证明“import 即注册”与覆盖顺序
node tools\find-plugin-verify.mjs # 在坏环境下验证补丁后的插件
node tools\plugin-fetch-exposure.mjs # 扫描本机哪些插件暴露(宿主端裸 fetch)
实测输出节选(在故意装上坏 dispatcher 的环境里):
control res.json()-style: ce=null magic=1f8b -> BROKEN (raw compressed body)
patched searchGitHub("pet"): 5 hits
patched loadRegistry(): source=live plugins=4225
qp-exa-dynamic 自带单元测试:node test/index.test.js → 40/40 通过。
为什么用 accept-encoding: identity
服务器通常会压缩响应省流量,压缩件靠 content-encoding 这个“标签”来告诉客户端要不要拆压。
本 bug 就是标签被撕了但货还是压缩的。直接要求“别压缩”,就没有拆压这一步,标签丢了也无所谓。
代价只有传输体积:同一个响应 5.0 KB → 13.2 KB。
解码后的内容大小完全一致,所以它不影响工具输出的长度,也不影响模型上下文/token 消耗。
注意
- 补丁改的是 pnpm 安装目录里的包,下次安装/更新这些插件会被覆盖 → 重新跑 apply.ps1 即可(脚本可重复执行)。
- 不建议为此降级 undici:两份 undici 各有其主(app 那份服务 DSH 自带组件的 zstd 等能力, profile 那份是插件市场的依赖),降级会牵动别的插件。补丁侧解决更干净。
- 浏览器端插件不受影响:lib/client.js 跑在页面里,用的是浏览器的 fetch(另一套实现)。
- 只有“宿主端 + 直接调全局 fetch + 对方返回压缩响应”三条同时成立才会中招。
- 上游更值得修:@deepseek-ai/dsh-http-proxy 注册的全局 dispatcher 与宿主 Node 内置 undici 跨大版本。
复现与证据
- 全部结论都出自本机对照实验,脚本在 tools/,都可在本机直接重跑。
- 同一请求的两组实测:
- 压缩传输 5,007 字节,content-encoding: null,JSON.parse 失败
- 不压缩 13,213 字节,content-encoding: null,正常解析出 3 条结果
License
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Geighlord007/dshpatch
修复插件读取压缩 JSON 时解析崩溃的问题
相关插件 · 其他
模型破甲清洗HunYiSage/dsh-purge
⚔️ DeepSeek Harness 网络安全红队工具dsh-purge
★ 16,993已汉化DeepSeek 客户端
73
女娲蒸馏alchaincyf/nuwa-skill
输入名人名字,提炼其思维模型与决策方式供你调用
★ 37,308已汉化DSH
72
逆向分析桥接Fanqi89/dsh-rea
REA(Reverse Engineer Anything)MCP 桥接,用来把 REA 逆向工具接入 DSH 插件
★ 51已汉化DSH
72
语音女友beiyege-01/dsh-voice-ai-girlfriend
语音 AI 女友Voice AI girlfriend for DeepSeek Harness:Whisper…
★ 888已汉化DSH
71.6
红队越狱测试套件Minglink/dsh-infinite-gen-5
DeepSeek v4.1 flash 逆向工具无限五代 求 Star 收藏 ⭐欢迎大家提交项目的改进
★ 3,759已汉化DSH
71.4
协同办公空间dream-num/univer-workspace
一个让人类与 AI Agent 共同创作、协作和审阅的开源 Office 工作空间。
★ 2,270已汉化DSH
70.8
这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。