webdsh 浏览器侧的 Network 设置面板子插件:在 Settings 里插入一个面板,让用户选择/测试/关闭 CORS 代理,代理只在直接请求被浏览器拒收后兜底使用。
ⓘ 此插件是大仓库 futrime/webdsh 的子包,星数与活跃度统计的是整个仓库。
- 语言
- TypeScript
- License
- Apache-2.0
- 分支
- main
安装
$ dsh plugin --profile web add github:futrime/webdsh#path:packages/dsh-web-network在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程
对话式安装
帮我安装 DeepSeek Harness 插件 futrime/webdsh/packages/dsh-web-network:先查看仓库 https://github.com/futrime/webdsh 确认安全性,然后执行安装命令并验证插件加载成功。
把这段指令粘贴给 DSH Web GUI 里的助手,由它代你完成安装与验证。
一句话定位
webdsh 是把 DeepSeek Harness 跑在浏览器里的纯静态发布版。本条目描述它自带的 Network 设置面板子包 @dsh-web/network:在 webdsh 的 Settings 里插一个 "Network" 面板,让你选/测/关页面的 CORS 兜底代理——浏览器直接请求被拒时,自动改走这个代理再试一次。
核心能力
- 在 Settings 里渲染一个独立的 "Network" 面板(顺序排在 Models=10 与 Plugins=15 之间,order=12),含启用开关、代理 URL 输入框、Save/Test/Reset 按钮,以及本次会话被代理过的 origin 列表(client.tsx:246-252)。
- 把代理配置存到 localStorage 的
dsh-web:network键;键里只有enabled与template两项,默认{ enabled: true, template: 'https://proxy.cors.sh/{url}' }(cors-proxy.ts:75-78)。 - 提供一个 Test 按钮:对候选代理做一次
GET https://api.openai.com/v1/models,401 视为成功("到了 OpenAI,没带 key"),429 报被限流,其他 4xx 报被拒,15 秒无应答报超时;被测代理在测试期间临时进excluded,不会被配置的代理"救回来"误报可用(cors-proxy.ts:292-347,client.tsx:99-110)。 - 每 2 秒拉一次"本次会话已代理过哪些 origin",只有非空才显示;这就是"代理有没有真用上"的可信答案(client.tsx:79-82,206-214)。
- 在面板下方写明:代理看得到完整请求(URL、头、body,含模型请求里的 API key),并提示可填自己的代理或干脆关掉(client.tsx:198-204)。
技术实现
- 语言: TypeScript + React (
.tsx),跑在浏览器 webdsh 内 - 关键依赖:
@deepseek-ai/cordis(ctx.get('slots')拿注册入口);React 18 hooks(useState/useEffect/useCallback);宿主由@deepseek-ai/dsh-client-runtime与@deepseek-ai/dsh-client-ui-settings提供注入点(见 package.jsondsh.client.inject);实际代理执行在src/net/cors-proxy.ts,由@deepseek-ai/dsh-web-app在启动时publishNetworkBridge()挂到globalThis.__DSH_WEB_NETWORK__上(bridges.ts:303-314,main.ts:89) - 架构模式: cordis bundle 子包,profile bundle 层。
cordis.patch.yml用- insert把id: web-network、name: '@dsh-web/network'写进 host profile 的 composition。分两半:src/index.ts是 host 半区(故意空——只为了把dsh.client声明挂在 composition 里;代理策略本身在 app 侧,早于任何 plugin 加载);src/client.tsx是 browser 半区,等slots服务后,把 React 组件注册成settings.sectionslot(order 12,label "Network") - 入口文件:
packages/dsh-web-network/src/index.ts(host,空壳)、packages/dsh-web-network/src/client.tsx(browser,面板)、packages/dsh-web-network/cordis.patch.yml、packages/dsh-web-network/package.json
适用场景
当用户通过浏览器跑 webdsh,想用对浏览器不开 CORS 的 provider(OpenAI、NVIDIA、Cerebras、Vercel AI gateway、codeload.github.com,以及默认的 opencode.ai/zen 免费通道)却发现请求一直 Failed to fetch 时,打开这个面板:勾选启用、把代理 URL 改成自己跑的或公共代理,Save 后下一次跨域失败就会自动重试一次,且面板下方会把"哪些 host 真的走了代理"列出来供你判断。
前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DSH / Harness | 0.1.0-rc.7+ | 与同仓锁定的 @deepseek-ai/dsh-* 同代,子包 package.json 未单独声明 peer |
| webdsh profile | 必须安装 | 浏览器端 webdsh,仅 platform: "web" 的 profile 有效 |
| 构建侧 Node | >=22 | 跑 webdsh 仓库自身的 npm run build 等脚本需要,但插件运行(浏览器)不依赖 Node |
| 平台 | 跨平台 | 仅在浏览器执行,无 host OS 限制 |
| 原生模块 | 无 | 全部走浏览器标准 API,无 Node 原生依赖 |
| 持久化 | localStorage dsh-web:network | 配置只活在浏览器本地,清掉浏览数据即重置 |
安装方式
dsh plugin --profile web add github:futrime/webdsh/packages/dsh-web-network
配置项
本插件没有独立的 Schema 字段。它呈现的是 webdsh 内置 CORS 代理策略的设置界面;实际读写由 src/net/cors-proxy.ts 完成,持久化在 localStorage 的 dsh-web:network 键。
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| 启用代理(enabled) | 布尔 | 控制是否允许把浏览器直接拒收的跨域请求重试一次走代理;关掉后直接失败,不再兜底 | true |
| 代理 URL 模板(template) | 字符串 | 占位符 {url} 替换为目标地址原文,{encoded} 替换为 percent-encoded 形式;同时支持前缀式(https://host/{url})与 query 参数式(https://host/?url={encoded}) | https://proxy.cors.sh/{url} |
常见问题
Q: 安装后从哪里打开 Network 面板?
A: 进入 webdsh 的 Settings,Network 一节排在 Models(顺序 10)与 Plugins(顺序 15)之间,标着 "Network";点开就是本子包渲染的面板。
Q: 这个面板在改什么?
A: 改的是页面里所有跨域请求的兜底代理:勾选开关 / 输入代理 URL(支持 {url} 与 {encoded} 占位符) / 点 Test 实际试一次 / 点 Reset 回到默认。代理执行在 src/net/cors-proxy.ts,本插件只管设置页。
Q: 默认代理是什么?能换吗?
A: 默认是 https://proxy.cors.sh/{url},备选是 https://cors.eu.org/{url}——这两个都从该页面实测过能用(带 authorization 头与 JSON body 的 POST 通过,并返回 access-control-allow-origin: *);文本框接受任何带 {url} 或 {encoded} 占位符的前缀或 query 参数代理,Reset 一键还原默认。
Q: 代理什么时候会被用?所有请求都过它吗?
A: 不是。所有请求都先直发,只有浏览器以 TypeError(就是 CORS / DNS / 连接失败那一类)拒收时才用代理重试一次;一旦该 origin 走代理成功,就被记入 memo,下次直接走代理;若代理本身又失败,memo 立刻被清,重新测量。代理本身被排除,不会自递归。
Q: WebContainer 里 agent 跑的命令也会过这个代理吗?
A: 不会。WebContainer 的请求从 StackBlitz 的 worker 出去,sw.js 与本代理都碰不到;src/host/jsh-tool.ts 读的是同一份配置,把可用 host 列出来告诉 model。因此改完面板后需要刷新页面让 shell 工具读到新值。
Q: Test 按钮在测什么?
A: 对候选代理做一次 GET https://api.openai.com/v1/models,被测代理在测试期间临时加进 excluded(防止它被配置的代理"救回来"误报可用),15 秒超时;返回 401 = 到了 OpenAI 但没带 key,正是预期;<400 也算通;429 报被限流;其他 4xx 报被拒;超时专门报。
Q: 面板里那个 "Proxied this session" 列表是什么?
A: 本次会话里"必须靠代理才答得上"的 origin 列表,每 2 秒从 __DSH_WEB_NETWORK__.proxied() 拉一次,只有非空才显示;它就是"代理有没有真用上"的可信答案,而不是估算。
Q: 关掉代理有什么副作用?
A: 关掉后,直接请求被浏览器拒收的 origin(OpenAI、NVIDIA、Cerebras、Vercel AI gateway、codeload.github.com,以及默认用的 opencode.ai/zen 免费通道)会一直失败,直到你在 Models 里改用对浏览器开 CORS 的 provider。面板在关闭状态下会显式提示这件事。
上手难度
入门——装上即在 Settings 多一个 "Network" 项,默认开着就能用,改不改 URL 都不影响普通使用;想自托管代理或临时关掉,看一眼面板上的提示即可。
已知问题与限制
- 公共代理(
proxy.cors.sh、cors.eu.org)会缓冲响应:流式模型回复会整段一次性返回,期间页面看起来"什么都没发生",只有回复完整了才一次性出现;想避免只能跑自己的代理(client.tsx:190-195)。 - WebContainer 里 agent 跑的命令(
jsh、python3、git等)走的是 StackBlitz worker 的出栈,本页面的代理碰不到,所以"代理帮得了浏览器请求,帮不了容器里的命令"(cors-proxy.ts:28-32,jsh-tool.ts:70)。 - 配置生效需要刷新页面:agent 的 shell 工具是在页面加载时读的 proxy 配置,改完保存后,下一次刷新才会让模型知道新的可用 host 列表(README.md:103-104 与 client.tsx:135-139)。
- 已代理 origin 列表每 2 秒拉一次,不实时;若你刚保存了一个新代理、立刻发起了一个被拒请求,列表可能要等到下一次轮询才更新(client.tsx:79-82)。
DeepSeek Harness in a browser tab — the real agent, real Node, no server to run.
DeepSeek Harness (dsh) is an
agent harness where everything is a plugin. dsh web runs a Node host and serves
a browser client to it. webdsh is that, as static files — the host runs inside
the page, and the agent's commands run in WebContainers:
Node itself, in the tab.
- ⚡ Nothing to run. No server, no install, no local Node — the harness boots in the page.
- 🖥️ Real Node, real Python.
npm installandpip installboth work, and the terminal and the agent share one container. - 💾 Or a whole PC. Switch the runtime to v86 and the session runs FreeDOS, Windows 1.01, Windows 3.1, Windows 98 or Linux — emulated x86, booted from a disk image, with the tool set that machine actually has.
- 🧩 Real plugins. Install from npm, a tarball, GitHub, or a path — from the browser.
- 📦 Real dsh. The published
@deepseek-ai/*packages, unmodified: 114 of 129 rows compose exactly asdsh webcomposes them. - 🔒 Yours. Files, sessions and keys live in your browser's storage. Nothing is uploaded.
Table of Contents
Background
Nothing here is a fork of dsh. The agent loop, tool registry, model adapters and
the entire web client come from npm at install time; the only modification is a
cordis.patch.yml layer — the mechanism dsh documents for exactly this.
What this repository adds is the platform underneath: a synchronous POSIX
filesystem mirrored to IndexedDB (src/vfs), node:* implemented over it
(src/node), the two runtimes a session can run on — WebContainers and an
emulated x86 PC (src/runtime) — an in-page virtual server for /api plus the
CORS policy every outbound request goes through (src/net), and the plugins
this build ships (packages/).
Six composition rows are swapped, each because the shipped one names something a
page cannot have — or, in the shell's case, cannot honestly describe. Four more
are reconfigured rather than replaced, including the one that decides whether
this deployment can open a path at all. npx tsx scripts/alignment.ts prints
the whole difference.
Install
Nothing to install — open the page. To run it yourself:
npm ci
npm run build # → dist/
node scripts/serve.mjs 4173
Node 22 or newer. dist/ is plain static files with relative URLs, so it works
at a domain root, a project path, or a local directory.
Usage
Open the page, choose a workspace, start talking.
- Files — the sidebar action above the terminal. Browse the workspace, open a file, drop files in, and take things out: one file as itself, a directory or a tick-box selection as a zip. It is the same filesystem the agent and the terminal use, not a copy. A file path the assistant names in the chat opens here when you click it.
- Terminal —
Ctrl+`or the sidebar action. It is Node in this tab, and the same machine the agent's tools run in. Closing it hides it; the session, its scrollback and its working directory are still there when you reopen. - Python —
python3andpipare there for both of them. The first call fetches a 14 MB interpreter; after that it is stored, and packages installed withpipsurvive a reload. Writepython3:jshaliasespythonto it and loses the quoting on the way, sopython -c "…"is a syntax error. - Runtime — the sidebar action below the terminal. A session runs on one machine and this is where you pick it. The default is the Node container above; the alternative is an emulated 32-bit PC, and the panel is that PC's screen — live, with a working keyboard, showing what the assistant is doing. Five machines need no setup at all: Linux (busybox on a serial console, the shortest way here to a real POSIX shell), FreeDOS, MS-DOS 7, Windows 1.01 and KolibriOS. Eleven more boot exactly the same way but are not this deployment's to serve a disk for — Windows 2.03, 3.0, 3.1, 95, 98, ME, NT 4.0 and 2000, MS-DOS 6.22, Buildroot Linux, and Arch Linux, which is a 2022 kernel with bash, python3 and gcc and resumes from a saved machine in about two seconds. For those, open a disk image from your computer or point the panel at a host that has one. Nothing is downloaded until you choose a machine, and a change applies on the next load.
- Plugins — Settings → Plugins, or
/plugin add <package>in the composer. Takes an npm name, a tarball URL,owner/repo#ref, or a path. The Installed tab turns one off or removes it; the composition is fixed at boot, so a change applies on the next reload and the panel says so. - Models — 42 models across six routes are registered up front and need no account, so the page answers before it asks for anything. Settings → Models offers the rest of the provider catalog; typing a key is the whole of configuring one.
- Network — Settings → Network picks the CORS proxy, used only after a direct request has actually failed, and reported to you when it is.
- Persistence — workspace, sessions and transcripts survive a reload.
window.dsh.exportFs()downloads a zip;window.dsh.reset()clears it all.
On an emulated machine the assistant is given different tools, because it is a
different machine: sh on the Linux guest, dos on the DOS ones — both reading
a real character stream, so a command's whole output comes back rather than the
last 25 lines of it — and vm_screenshot, vm_screen, vm_key, vm_type,
vm_mouse and vm_wait everywhere, which is the whole of the tool set on a
guest that only draws pixels. There is no jsh, no Node and no Python in that
session, and the guest's disk shares nothing with the workspace your file tools
read. The panel and the tools say so.
Worth knowing: the container's shell is jsh, not bash, and it ships no git;
python3 is CPython 3.14 compiled to WebAssembly, fetched on first use and kept
afterwards, so it has pip but no compiler, no subprocesses and no sockets; and a
host that refuses browsers is reachable only through the proxy, which does not
extend to the container.
Maintainers
Contributing
Issues and PRs welcome at futrime/webdsh.
Commits follow Conventional Commits;
npx tsc --noEmit and npx tsx scripts/e2e.ts should pass first.
License
Apache-2.0 © Zijian Zhang. The
@deepseek-ai/* packages it composes are published by DeepSeek AI under their
own terms.
查看使用指南 →
该插件的安装步骤、关键要点、FAQ 与兼容性说明(基于已收录字段派生)。
收录徽章
[](https://deepseek-plugin.org/plugins/futrime/webdsh/packages/dsh-web-network)把这段 markdown 粘贴到你的 GitHub README,链接回本插件详情页。徽章只声明已被本站收录,不代表安全认证。