安装
在 DeepSeek Harness 里通过 dsh-market 安装
dsh plugin --profile web add dshmarket
或使用命令行
dsh plugin --profile web add @tr1v3r/dsh-proxy
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络。请先审阅源码,并尽量锁定 commit(github:owner/repo#sha)。
README
English readme: README.md。

@tr1v3r/dsh-proxy 是 DeepSeek Harness 插件,把进程内所有出站请求——
LLM 提供方、web_search / web_fetch、streamable-http MCP——经由
HTTP(S) CONNECT 或 SOCKS5 代理转发,并且支持运行时随时开关、随时换代理:
可以在 Web「设置 → 通用 → 网络代理」中操作,也可以编辑 profile 的
cordis.patch.yml 中的 dsh-proxy 条目(热加载),全程零重启。
上面的动图展示路由引擎,安装后可运行 node scripts/demo.mjs 复现。
工作原理
DSH 与 pi-ai 的请求都走 globalThis.fetch,而它读取的是 undici 的全局
dispatcher 槽位(Symbol.for('undici.globalDispatcher.1'))。本插件接管该槽位:
http(s)://代理 →EnvHttpProxyAgent(https 走 CONNECT 隧道)socks5://代理 → undici 内置Socks5ProxyAgent(支持 URL 内鉴权;socks5h:///socks://自动归一;域名在代理端远程解析)noProxy规则 → 两条路径统一走RoutingDispatcher分流,HTTP 与 SOCKS 语义完全一致(undici 风格:裸条目匹配主机及点边界子域;host:port锁定 端口;*全部直连;前导点 /*.前缀视同裸条目等价写法)。manual模式 下 dispatcher 刻意忽略环境变量里的NO_PROXY/HTTP_PROXY——导出的 env 只引导子进程,进程内路由完全由 profile 条目配置决定;system模式则相反, 跟随环境代理——HTTP_PROXY/HTTPS_PROXY/ALL_PROXY/NO_PROXY,环境变量 缺失时再回退到 macOS 系统设置里的网络代理(scutil --proxy)——每次分节 应用时重新探测一次,而非持续轮询)
exportEnv: true(默认)时,切换还会同步导出
HTTP_PROXY/HTTPS_PROXY/ALL_PROXY/NO_PROXY 到 dsh 进程环境——切换后
新拉起的子进程(bash 工具里的 curl/git、stdio MCP server)跟着走同一
代理。启动时由你自己设置的环境变量绝不会被覆盖;禁用/卸载时全部还原。回环直连开启
(默认)时,导出的 NO_PROXY 还会并入回环默认集(localhost,127.0.0.1,::1,与你的
规则去重合并);bypassLoopback: false 时按你自己的列表原样导出。
被替换下来的旧 dispatcher 先优雅关闭、30 秒后强制销毁,确保切换真正切断
旧的 keep-alive 连接。在途请求同样只有这 30 秒宽限(RETIRE_DESTROY_MS):
切换后仍持续超过约 30 秒的流式响应,会在旧 dispatcher 的 socket 被强制销毁时
被中断。
凭据安全
代理 URL 中内嵌的 user:pass@ 凭据以明文存放在磁盘上——profile 的
cordis.patch.yml 与 settings 持久化中——仅靠文件权限保护。默认
exportEnv: true 时,凭据还会随 HTTP(S)_PROXY 环境变量写入 dsh 进程,
切换后拉起的子进程都会携带(同一用户可通过 ps -E 或
/proc/<PID>/environ 看到;其他用户通常需要 root 等特权才能读取,
具体取决于平台权限设置,并非所有同机用户都可见)。为此不引入新的配置项;凭据敏感的场景,
建议让 dsh-proxy 指向本机免鉴权的代理入口(例如 http://127.0.0.1:7890,
由它再对接需要鉴权的上游),而不是把 user:pass@ 写进 URL。
安装
在目标 profile 目录(~/.config/dsh/profiles/<name>/):
package.json加依赖与 bundle(合并进现有dsh.profile.bundles列表):{ "dependencies": { "@tr1v3r/dsh-proxy": "^0.2.4" }, "dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@tr1v3r/dsh-proxy"] } } }安装:
dsh plugin --profile <name> install --no-frozen-lockfile重启一次 dsh 挂载插件;此后再无需重启——切换全在 settings 里。
使用
Web 主界面侧栏底部(设置上方)只有「代理状态」图标;悬浮、聚焦或打开菜单可查看
当前选择的模式,并在直连、跟随系统和手动代理之间切换。它与设置页共用同一个配置条目,外部编辑
profile 的 cordis.patch.yml 后也会同步更新;悬浮提示中的手动代理地址会隐藏用户名和密码。
「跟随系统」表示已选择的模式,不保证系统探测到了可用代理;实际出口以 DSH
日志为准。没有有效代理地址时,快捷菜单不会启用手动模式。要编辑地址、直连规则
或子进程开关,请打开「设置 → 通用 → 网络代理」。
Web profile 也可打开「设置 → 通用 → 网络代理」:从下拉列表选择直连、跟随系统或手动代理,
选择后立即生效,无需「应用」按钮。手动模式可填写 HTTP(S)/SOCKS5 URL、直连地址
(每行一个)和子进程环境变量开关;URL 与直连地址失焦后保存,开关切换后立即保存,
无效 URL 不写入文件。图形界面写入同一个 dsh-proxy 配置条目,文件配置仍然完整保留:
直接编辑 profile 的 cordis.patch.yml 会热加载并同步到图形界面;并发修改由修订号保护,
避免覆盖新值。

下拉菜单提供三种出站模式:

也可以在 ~/.config/dsh/profiles/<name>/cordis.patch.yml 添加如下条目
(热加载,立即生效);如果文件已有条目,就追加到现有 YAML 列表中;已有
dsh-proxy 条目时直接修改该条目。mode 可在
direct(直连)、system(跟随系统)、manual(手动)间切换:
- id: dsh-proxy
config:
mode: manual # direct | system | manual
proxy: socks5://127.0.0.1:1080 # 仅 manual——http://…、https://…、
# socks5://user:pass@host:1080、socks5h://…
noProxy: # 仅 manual——可选分流规则
- localhost
- .internal.example
- registry.corp:443
bypassLoopback: true # manual 与 system 均生效——本地回环默认直连
# (false 可改为走代理)
exportEnv: true # 仅 manual——同步设置子进程的 HTTP(S)_PROXY
mode |
行为 |
|---|---|
direct |
直连,不走任何代理(等价于旧的 enabled: false)。 |
system |
跟随主机代理,每次分节应用时探测一次:读取 HTTP_PROXY/HTTPS_PROXY/ALL_PROXY/NO_PROXY 环境变量;环境变量缺失时,在 macOS 上再读取系统设置里的网络代理(scutil --proxy)。是保存时探测、非持续轮询;Windows 注册表、Linux 桌面与 PAC 暂未覆盖。忽略 proxy/noProxy/exportEnv。 |
manual |
走 proxy URL,可用 noProxy 分流(等价于旧的 enabled: true)。 |
enabled: true/false 仍作为旧写法兼容——未设置 mode 时分别映射到
manual/direct:
- id: dsh-proxy
config:
enabled: true # ≡ mode: manual
proxy: http://127.0.0.1:7890
每次保存立即重路由。插件会记录每次切换:
dsh-proxy: routing global fetch via socks5://***@127.0.0.1:1080, noProxy 3 rule(s)
dsh-proxy: following system proxy (http://127.0.0.1:7890, noProxy 3 rule(s))
dsh-proxy: direct (mode: direct)
(日志中代理 URL 的用户名密码会打码。system 模式只读环境/系统代理,
不会回写这些环境变量。)
覆盖范围
| 流量 | 是否代理 |
|---|---|
pi-ai 各提供方(zai-coding-cn、自定义 openai 兼容路由……) |
✅ |
dsh-llm-deepseek(deepseek-official) |
✅ |
web_search / web_fetch |
✅ |
| streamable-http MCP server | ✅ |
stdio MCP、bash 工具子进程(curl、git……) |
✅ 经导出的环境变量,仅对切换后新拉起的进程生效 |
本地回环目标(localhost、127.0.0.0/8、::1、0.0.0.0) |
❌ 默认直连;设置 bypassLoopback: false 可改为走代理 |
| pi-ai Bedrock 路由 | ⚠️ AWS SDK 自管代理(它会读 HTTPS_PROXY 环境变量) |
| 内置浏览器 host / 浏览器下载 | ❌ 独立进程,请在浏览器侧配置 |
另请注意:切换时已在运行的子进程保留其启动时的环境;undici 的 SOCKS5 agent 上游目前标注 experimental。
开发
npm install
npm test # 单测 + 本地 e2e:HTTP 代理、SOCKS5、noProxy、热切换、env
node scripts/boot-probe.mjs # boot 真实 DSH 插件树,通过 Settings 热切换验证
boot probe 需要 DSH >= 0.1.7-rc.1 的安装(依赖旧版本缺失的
createRuntimeResolution / PluginPackages 导出——在 dsh 0.1.5.x 上会报
TypeError: createRuntimeResolution is not a function)。不必升级全局安装:
用 DSH_ROOT 指向任意满足版本要求的安装树即可,例如装到临时目录:
npm install --prefix /tmp/dsh-probe-root @deepseek-ai/dsh@0.1.7-rc.1
DSH_ROOT=/tmp/dsh-probe-root node scripts/boot-probe.mjs
两行都在本仓库根目录运行。scratch 安装会把依赖提升到
/tmp/dsh-probe-root/node_modules,因此 DSH_ROOT 指向安装锚点目录
/tmp/dsh-probe-root 本身——而不是包目录。
不设置 DSH_ROOT 时,probe 解析 PATH 上的 dsh,并要求该安装已满足
版本要求。
许可
MIT © tr1v3r
评论
评论存放在 GitHub Discussions。用 GitHub 账号登录后可发表评论或点表情。