dsh-desktop-web-access
Verifieddsh-desktop-web-access · v0.1.0 · MIT · Web UI
DSH desktop plugin: surface and copy the Web GUI launch-token URL (loopback + LAN) so the desktop app's built-in Web server can be opened from another device.
Install
dsh plugin add dsh-desktop-web-access Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Published to npm without a public repository. Inspect the package contents before installing.
Tags
Creators
Readme
dsh-desktop-web-access
一个 DSH 插件:把桌面端 Web 服务的启动令牌找出来,并放到你能复制到的地方。
关于包名:npm 上的
dsh-web-access已被另一个项目占用(NexusAgentX/dsh-web-access,做的是ctx.web搜索/抓取,与本插件无关),所以本包注册为dsh-desktop-web-access。
要解决的问题
DeepSeek Harness 桌面端启动时会拉起内置 Web 服务(默认 127.0.0.1:19387)。这个服务要求带启动令牌才能打开:
http://127.0.0.1:19387/?token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
问题在于:dsh-web-app 确实把这行 URL 打印到了标准输出,但桌面端是 GUI 程序、stdout 没有人看得到,日志里也没有。于是令牌拿不到 —— 而后面这个 Web 界面却会返回 401,提示 dsh web authentication required。
令牌每次启动都会重新随机生成,并且只能用来换取一次 cookie(cookie 有效期 30 天,绑定到 host:port,换取成功后浏览器就不再需要令牌了)。
插件做了什么
| 位置 | 作用 |
|---|---|
| 设置 → Web 访问 | 完整链接、单独的令牌、局域网/虚拟网卡地址、当前绑定与可达性说明,每项都能单独复制或直接打开 |
web_access_url 工具 |
直接问 Agent「给我 Web 访问链接」即可,URL 出现在对话里就能复制 |
$DSH_HOME/web-access-url.txt |
便利文件;插件激活时写入,之后每次读取链接都会刷新 |
复制按钮把文本放进当前浏览器所在设备的剪贴板里 —— 所以哪怕你是从另一台设备远程连进来的,复制到的也是那台设备的剪贴板,这正是远程场景需要的。
为什么不放侧边栏:侧边栏底部行动区、品牌标记与名称、shell.leading 都是单占用座位,且已被官方 wordmark 与账号菜单占据;在那里常驻一个图标,等于为"每次启动只查一次"的东西付每天的视觉成本。所以链接只放在设置页里,需要时打开即可。
实现要点
令牌本身不落盘(便利文件除外,可用
writeFile: false关闭)、不进页面:宿主半边通过ctx.connection.authenticatedUrl()重新推导出与桌面端完全一致的 URL,再经一条受认证保护的路由提供出去:GET /x-dsh-web-access/url -> JSON该路由用
ctx.connection.admit()做与/api相同的 Host/Origin 围栏 + 浏览器 cookie 校验,未认证请求只会得到 401,不会看到令牌。插件也不会把令牌注入index.html。token字段独立给出,方便只要令牌本身的场景。
安装
从 npm(发布后):
# 在桌面端 profile 目录($DSH_HOME/profiles/desktop)里
pnpm add dsh-desktop-web-access
或者更省事:在桌面端 Web GUI 里让 Agent 用 plugin_manager → install_bundle 装(本地目录、tarball、npm 包名都行)。
本地开发时用 link: 即可,源码改动无需重装:
pnpm add link:/path/to/dsh-desktop-web-access
然后把包名加进 package.json 的 dsh.profile.bundles(plugin_manager 会自动做这一步)。本仓库的 cordis.patch.yml 负责把宿主半边挂到 Loader 上,随包一起安装。
安装后是热生效的,无需重启桌面端。
改宿主半边(
src/host.js)后需要重启桌面端:客户端包每次请求都从磁盘重新读取,所以lib/client.js的改动刷新页面即可;但宿主半边由 Loader 按模块缓存,实测连 disable/enable 都不会重新执行 —— 想立刻看到宿主改动,重启桌面端最稳。
从另一台设备访问
插件会明确告诉你当前是否可达:
绑定
0.0.0.0(dsh web --bind 0.0.0.0,或桌面端 profile 里配置)→ 直接用「局域网链接」,同一网络的设备打开即可。只绑定
127.0.0.1(桌面端默认)→ 任何设备都无法通过 IP 直接访问。需要先做端口转发,例如:ssh -L 19387:127.0.0.1:19387 <user>@<跑着桌面端的机器>然后在另一台设备上打开插件给出的那条
127.0.0.1:19387链接即可(令牌照常有效)。
安全说明
- 令牌等同于登录凭据:拿到它的任何人只要能连到这个端口,就能拿到 30 天的 cookie。请只发给你信任的设备/通道。
- 令牌随进程重启变化;旧令牌在新一次启动后立即失效。
- 插件不写日志、不上传任何东西;唯一写入的文件是
$DSH_HOME/web-access-url.txt(可用配置writeFile: false关闭,或用file指定路径)。
配置
宿主半边支持三个可选配置项:
- id: dsh-desktop-web-access
name: dsh-desktop-web-access
config:
tool: true # 注册 web_access_url 工具(默认 true)
writeFile: true # 写 $DSH_HOME/web-access-url.txt(默认 true)
file: "" # 自定义便利文件路径
配置项之外的说明
- 插件只依赖
webServer与connection两个服务,不引入任何 npm 依赖。 - 浏览器半边只
require("react")(平台模块表已提供),无额外 external。
构建
node build.mjs
产出两个文件:
lib/client.js—— 浏览器半边(CJS + ModuleLoader 握手;由 Web 宿主作为dsh-desktop-web-access这一行提供给浏览器,实际请求形如/plugins/??dsh-desktop-web-access/client.js&rev=...)lib/index.js—— 宿主半边(由src/host.js打包而来)
build.mjs 从 package.json 的 name 推导插件标识,并同时写进 Loader 行名、name 导出与 ModuleLoader bundle id —— 改名时只需改 package.json,三处不会走偏。发布前 prepublishOnly 会自动构建。
License
MIT