DeepSeek Harness 插件

KyoMio/dsh-zen-remote

Star 数 ★ 10 下载量(近 30 天) 2,608 分类 远程与移动端 收录于 2026-08-19 npm dsh-zen-remote

手机优先的移动端界面重排 + 配对码网关:经自建反代或 Cloudflare Tunnel 把 DSH 变成可安装、带推送的 PWA。

安装

# npm 包(预构建)

dsh plugin --profile web add dsh-zen-remote

# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)

dsh plugin --profile web add github:KyoMio/dsh-zen-remote

装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。

README

会话列表主屏 会话页 会话信息卡
会话列表主屏 会话页 会话信息卡
composer 权限 sheet 公网设备看到的配对页
composer 权限 sheet 配对页

截图为 390×844 手机视口、浅色主题;深浅主题均适配。配对页由网关绘制,按 DSH 官方风格、跟随系统浅色 / 深色。


一个插件、两种角色

同一个包、同一行插件。跑哪一半由 DSH「插件」页设置区块里的 role 决定:

主服务端(role: host,默认) 子客户端(role: client)
机器 跑会话的那台 另一台装了 DSH 桌面端的电脑
加载什么 手机界面、网关(子进程)、Web 推送、会话共享、中继服务端 中继客户端 + 侧边栏与会话页的远程部件
不加载什么 — 不起网关、不注册推送、手机界面不生效——不和主服务端抢端口

已配对的桌面应用端只看得到服务端开启了远程的会话,在本地工作区后面按「服务端名 · 工作区名」分组。服务端的工作区只有其中至少一个会话开启了远程才会出现——没动过的工作区不会显示成空分组;已经显示过的分组里会话全部关闭远程后,空分组会留到刷新页面为止。子客户端本地的会话完全不受影响。


远程连接

适合什么场景:一台电脑常开、跑会话(主服务端),另一台电脑的 DSH 桌面端(子客户端)远程查看、接着干活——历史、实时进度、发消息、审批、终端都能用,所有执行都发生在主服务端。手机、平板走的是另一条路:浏览器经网关访问主服务端(Web 应用端),见配置公网访问。

怎么用,四步:

  1. 配对:主服务端设置页生成「桌面应用端」配对码,子客户端设置页填服务端地址和配对码。逐步说明见下面的设置页配置引导。

  2. 开启远程:远程按会话逐个开。主服务端在会话的「…」菜单里点「开启远程」(也可以用标题行的地球图标、设置页的共享列表,见会话共享)。

    主服务端在会话的「…」菜单里开启远程

  3. 在子客户端使用:侧边栏本地工作区后面出现「服务端设备名称 · 工作区名」分组,点开就像本地会话一样用;标题行的地球图标显示连接状态(在线 / 离线 / 版本有差异)。服务端上没有开启远程会话的工作区不会出现。

    子客户端侧边栏里的「书房 · Desktop」分组,标题行是远程连接状态图标

  4. 关闭与恢复:服务端关闭远程、会话闲置休眠(默认 48 小时无动静)、或在子客户端自己关闭时,正打开的会话页会显示「远程已关闭」横幅并禁用输入,切到别的会话后它从列表里隐藏;重新开启远程后自动回来。断线期间页面保持原样,连上后自动续上。

    远程被关闭后,会话页输入框上方的「远程已关闭」横幅

手机上也能开关:用手机(Web 应用端)访问主服务端时,会话页的信息卡片里有一行「远程访问」,显示是否已开启、剩余闲置时间,点开关即可开启或关闭。

能做什么、不能做什么,见功能和已知限制;已配对的桌面应用端被视为可信设备,信任边界见安全模型。

以上截图中,红框圈出的是本插件加入 DSH 界面的部分;会话标题为演示用,对话内容已模糊处理。


安装

界面安装(桌面端 App 与 Web 端都适用;桌面端是 2.0 主服务端的实际形态):左侧「插件」页 →「添加插件」→ 输入 dsh-zen-remote → 装完点「立即启用」,然后重启桌面端 App(Web 端重启 dsh web)。

Web 服务命令行(无头机器上跑 dsh web 的主服务端,手机访问也指向这里):

dsh plugin --profile web add dsh-zen-remote
# 然后重启 dsh web

dsh plugin 必须用 --profile 指明装进哪个 profile,不带会直接报错。桌面端的 desktop profile 由 App 独占管理,命令行会拒绝 --profile desktop,所以桌面端只能用上面的界面安装。

手工改 profile(本地开发、link: 装法):把依赖写进 profile 的 package.json(桌面端在 ~/.dsh/profiles/desktop,Web 端在 ~/.dsh/profiles/web),装完重启:

// ~/.dsh/profiles/desktop/package.json
{
  "dependencies": {
    "dsh-zen-remote": "^2.0.0"        // 本地开发换成 "link:/path/to/dsh-zen-remote"
  }
}
cd ~/.dsh/profiles/desktop && pnpm install
# 然后重启 DSH 桌面端 App(Web 端重启 dsh web)

pnpm install 只装包、不启用。还要到「插件」页打开它的开关,或者自己把 "dsh-zen-remote" 追加到同一个文件 dsh.profile.bundles 数组的末尾(数组里原有的项别动)。界面安装和 dsh plugin 会自动写这一项,手工装法要自己补。

无论哪种装法,组合层都只有一行。2.0.0 起挂载层只剩 dsh-zen-remote 一行,主入口按角色自己加载网关与推送子插件。不要再把旧的 dsh-zen-remote-gateway / dsh-zen-remote-push 两行加回来:loader 会警告后跳过;真挂两行网关就是两个网关进程抢 3088 端口。

把 cordis.patch.yml.example 抄进 profile 的 cordis.patch.yml、换成绝对路径即可——同样只有一行,附带的 config: 示例列了可写的行配置。用界面或 dsh plugin 正常安装的不需要它。

卸载:在「插件」页打开 dsh-zen-remote,点「卸载」并确认;Web 服务也可以用命令行 dsh plugin --profile web remove dsh-zen-remote;手工装的从 profile 的 dependencies 和 dsh.profile.bundles 里删掉它。之后重启;要清掉配对与共享状态再删 ~/.dsh/lan-gate-state.json、~/.dsh/lan-gate.config.json、~/.dsh/zen-remote-shares.json 与 ~/.dsh/zen-remote-server.json(服务端 id;删了之后已配对的子客户端会把它当成一台新服务端)。


从 1.x 升级

一次性的事实,按踩到的概率排序:

  • 三行合并为一行。 profile 补丁里残留的 dsh-zen-remote-gateway / dsh-zen-remote-push 旧行会被 loader 警告后跳过。原来写在那两行上的 config: 不再生效——搬到 dsh-zen-remote 行,或者直接在插件设置页里改。
  • 1.0 时代在 profile 补丁里手工 insert 过 dsh-zen-remote/dsh-push.mjs 那一行的,需要删掉——主入口现在按角色自动加载推送子插件,残留的那一行会让推送加载两次。
  • ~/.dsh/lan-gate.config.json 继续生效。 无需迁移,它的值会显示在设置页里。每个字段的优先级:环境变量 > 插件行设置 > lan-gate.config.json > 内置默认值。插件从不改写、也从不删除这个文件。
  • 已配对设备自动归为 Web 应用端,继续照常用,不需要重新配对。
  • 管理页搬家了。 /lan-gate/admin 现在只剩一段指向插件设置页的说明(对非本机直连的请求仍然 403)。配对码、设备管理、测试推送、会话共享全部在 DSH「插件」页的 dsh-zen-remote 设置区块里。
  • 什么配置都不动的话,插件按主服务端起来,网关、推送、手机界面的行为与 1.1.x 完全一致。

配置公网访问(主服务端)

装完在本机 127.0.0.1:3080 就能用手机界面。要从外面访问:给自己的网关配一个终结 TLS 的反代,用 403 自检确认,再配对设备。nginx / Caddy / Cloudflare Tunnel / Lucky 的完整配置见 docs/remote-access.md,简版:

  1. 网关只监听 127.0.0.1:3088,由反代(nginx、Caddy、Cloudflare Tunnel、Lucky)终结 HTTPS 并转发。自检:用手机流量(别连家里 Wi-Fi)访问 https://你的域名/lan-gate/admin,正确结果是 403。能看到说明页就代表反代没带 X-Forwarded-* 头、公网请求被当成了本机用户——先修转发头再往下走。
  2. 在服务端这台机器打开 DSH「插件」页,展开 dsh-zen-remote 设置区块,先选要配的设备角色,再点生成 8 位配对码(10 分钟有效、只能用一次)。
  3. 手机打开你的 HTTPS 域名,在配对页输入配对码。配对成功即进入 DSH,身份存在长期 Cookie 里。浏览器菜单「添加到主屏幕」装成 App,同意通知权限,agent 干完活推到锁屏。

配对设备

配对码生成时绑定设备角色,兑换时校验角色——拿错通道用码会被明确拒绝,码不被消耗,也不计入错码锁定。

Web 应用端 桌面应用端
形态 手机、平板及各类浏览器,经网关访问 装了 DSH 桌面端、zen-remote 设为子客户端角色的计算机
可见范围 服务端全部会话 仅服务端已开启远程的会话(服务端强制)
配对方式 浏览器打开网关地址,在配对页输入配对码 在子客户端的插件设置页填服务端地址和配对码

桌面应用端配对,逐步:

  1. 在服务端的插件设置区块选「桌面应用端」,生成配对码。
  2. 在另一台电脑的 DSH 桌面端里打开插件设置区块,角色切到子客户端,填入服务端地址和配对码。
  3. 地址必须 https://,内网地址才允许 http——局域网段(192.168.x、10.x、172.16–31.x)、Tailscale/CGNAT(100.64.x)、回环、localhost / *.local、IPv6 ::1 / fc00::/7 / fe80::/10。公网地址走明文 http 会被拒绝,设备令牌不会明文过公网。
  4. 配对成功后令牌存在插件行里(密钥字段),客户端自动连接。设置区块显示连接状态——已连接 / 离线 / 版本有差异 / 令牌已吊销——并可以解配。

服务端的设置区块可以改设备名、改设备角色(set-role)、单独或全部吊销。吊销立即生效:连接与推送订阅一并失效。桌面应用端够不到任何管理路由——网关只把它的请求转进中继前缀。

设备名称:设置页「角色」卡片里的「设备名称」字段(配置项 serverName)两种角色共用:主服务端上它是其他设备侧边栏分组标题里的名字(默认取电脑名);子客户端上它是配对时注册到服务端的名字。名字双向自动同步:服务端改自己的名字,子客户端分组标题约 15 秒内跟随;子客户端保存新名字,服务端设备列表跟着更新;服务端在设备列表里给子客户端改名,子客户端约 30 秒内跟随。子客户端只在主动保存设置时推送自己的名字,其余时候以服务端记录为准;离线时改的名字如果进程在推送前退出,下次启动以服务端记录为准。名字 1–40 个字符。


会话共享

远程按会话逐个开启,有四个入口:

  1. 侧边栏会话行的「…」菜单里的「开启远程 / 关闭远程」;
  2. 会话页标题行的远程图标(点击开关、带二次确认;悬停显示剩余闲置时间;图标带小圆点表示此刻有桌面应用端在看);
  3. 插件设置区块的「已开启远程的会话」列表,含一键全部关闭;
  4. 手机(Web 应用端)会话页信息卡片里的「远程访问」开关。

闲置休眠:开启远程的会话在 48 小时(可配,idleHours)内没有任何会话动静——回合开始或结束、发消息、审批或提问得到回答,不分服务端还是子客户端——就自动关闭远程。运行中的回合、等待审批/回答的会话永远不会被扫掉;只开窗口「看着」不算活跃。剩余时间悬停标题行图标可见,设置区块里逐条列出。

新建会话:autoShareNewSessions 打开时,服务端新建的会话自动开启远程;经中继新建的会话(子客户端远程分组里点的)一律自动开启,这条入口的安全性正建立在此之上。子智能体会话与分叉会话自动跟随父会话,不用逐个开启。

「关闭远程」意味着什么:未开启远程的会话,其列表、历史、实时进度、审批/提问事件,全部在中继处拒绝或过滤——不只是界面上藏起来。@ 引用候选只列已共享会话;发消息、改写排队消息、斜杠命令里内嵌的会话引用指向未共享会话时,整个调用被拒绝。

关闭远程后在子客户端的表现:服务端关闭某个会话的远程(或它闲置休眠)时,该会话直接从子客户端的侧边栏列表里隐藏——按「已归档」处理,在 DSH 里打开「显示已归档」筛选还能看到它。唯一的例外是此刻正打开着的会话页:页面停在原处,composer 上方出现「远程已关闭」横幅并注明原因(服务端关闭 / 闲置休眠 / 已在本机关闭),输入禁用;切到别的会话后它也随之隐藏。服务端重新开启远程(或重新共享)后,会话回到原工作区,打开着的页面自动恢复——横幅消失、输入恢复可用。

断线与恢复:服务端(或链路)断线期间,已打开的远程会话页保持原状——横幅提示离线、输入禁用;连接恢复后自动续上:会话流与任务列表类面板自动重新拉取最新快照,不用手动刷新。例外是文件树变更与终端面板,断线后需要重新打开。


配置

设置页配置引导

在哪打开:DSH 左侧点「插件」→ 插件列表里点 dsh-zen-remote → 在「包含的组件」里再点一次 dsh-zen-remote,下面就是设置区块。

通用操作:字段右上角出现「已覆盖」表示这个值保存在插件设置里(覆盖了配置文件或默认值),点「重置」恢复成下一层的值;改完点卡片底部的「保存」。需要重载的字段会有提示,保存后插件自己重载,不用重启 App。

主服务端

  1. 「运行角色」选「主服务端」,「设备名称」填一个好认的名字(比如「书房」)——子客户端侧边栏的分组标题、手机上都显示它。保存。

    主服务端设置页:角色卡片里的运行角色与设备名称

  2. 「网关与反代」:只在本机和手机经反代访问时保持默认即可,公网访问见配置公网访问。要让局域网里的子客户端直连网关,把「监听地址」改成 0.0.0.0(必须包含本机回环,设置页靠回环地址管理网关)。

  3. 「配对」:选「Web 应用端」(手机、浏览器)或「桌面应用端」(另一台 DSH 桌面端),点「生成配对码」,10 分钟内在对方那里输入。「设备」列表里可以改名、改设备角色、吊销。

    生成配对码与设备列表

  4. 「远程共享」:闲置休眠时长、是否自动共享新会话。卡片下方的「已开启远程的会话」列出当前开着远程的会话、剩余闲置时间、是否有设备正在查看,可以逐个或全部关闭。

    已开启远程的会话列表

  5. 「推送」:推送内容摘要、回合结束推送等,按需开启,说明见通知什么时候会响。

子客户端

  1. 「运行角色」选「子客户端」,保存——插件自动重载,设置页换成子客户端的内容。

  2. 「设备名称」填这台电脑的名字(比如「客厅」),配对时它会登记到服务端的设备列表里。保存。

  3. 「连接服务端」:填服务端的网关地址(局域网例如 http://192.168.1.10:3088,公网必须 https://)和服务端生成的「桌面应用端」配对码,点「配对」。

  4. 「连接状态」显示「已连接到『服务端设备名称』」就完成了,侧边栏随即出现服务端的分组。「诊断」区列出请求拦截器状态和最近的远程调用失败,排障先看这里。

    子客户端设置页:角色、设备名称、连接服务端与连接状态

截图中的地址、配对码为演示值。

字段参考

全部在 DSH「插件」页 → dsh-zen-remote 设置区块里改。每个字段按此顺序取第一个合法值:环境变量 > 插件行设置 > ~/.dsh/lan-gate.config.json > 默认值;某层的值类型/范围/枚举不合法时该层视为未设置。改完需要重启网关/推送的字段(role、port、host、targetPort、rateLimit、trustedProxies、vapidSubject、lang 与推送各字段),插件会自己重载插件行——不用手动重启 App;其余字段立即生效。

插件行字段(与 src/config.ts 一致):

字段 默认 说明
role host host 跑网关 + 推送 + 共享;client 连接服务端。不是精确的 client 就按 host 处理
port 3088 网关端口;被占用自动往上试(最多 +20)
host 127.0.0.1 网关监听地址;反代不在本机时才需要放开
targetPort (自动) 本机 DSH Web UI 端口。留空即可:网关自动发现宿主实际监听端口(桌面端构建的端口可配置)
rateLimit 120 未配对请求的每分钟上限(按真实客户端 IP)
trustedProxies 空 逗号分隔 IP;反代不在本机时必填
vapidSubject mailto:admin@localhost 推送联系人。iOS 必须改成真实邮箱或 https 网址,否则 Apple 拒发
lang auto 网关页面、推送开关卡片与通知文案的语言。auto 跟随浏览器的 Accept-Language(认不出就用中文),zh/en 写死
pushTurnEnd 关 「回合结束」也推一条。默认不推——回合结束不代表需要你。等授权/等回答的通知不受影响,永远推
pushEvents agent/turn-stopping 「回合结束」算哪些事件,逗号分隔;只在 pushTurnEnd 开时有意义
pushDebounceMs 15000 两条自动推送的最小间隔;等授权/等回答的通知不受压制
pushSummary 关 通知带上本回合的最终回复(只取正文,不含思考过程;截 120 字)和提问原文
pushTool 开 设 false 关掉模型可调用的 push_notify 工具
serverName 电脑名 设备名称(≤ 40 字),两种角色共用:主服务端是子客户端分组标题里的显示名;子客户端是配对时注册的名字;与服务端双向自动同步
idleHours 48 远程会话的闲置休眠时长(小时),范围 (0, 8760]
autoShareNewSessions 关 服务端新建的会话自动开启远程
serverUrl(子客户端) 空 服务端网关地址,按上文规则校验
deviceToken(子客户端) 空 配对拿到的设备令牌;密钥字段,处处打码
turnFoldDesktop 关 回合过程折叠在任意宽度生效(默认仅手机宽度)
keyboardLiftRatio / keyboardLiftMaxPx / keyboardSafetyPadPx 0.42 / 400 / 15 软键盘抬升校准,给浏览器拿不到键盘高度的环境用(见已知问题一节)
maxUploadBytes 20 MB 附件上传上限

旧的环境变量继续可用且优先级最高:LAN_GATE_PORT、LAN_GATE_HOST、LAN_GATE_TARGET_PORT、LAN_GATE_RATE_LIMIT、LAN_GATE_TRUSTED_PROXIES、LAN_GATE_VAPID_SUBJECT、LAN_GATE_LANG、DSH_PUSH_TURN_END、DSH_PUSH_EVENTS、DSH_PUSH_DEBOUNCE_MS、DSH_PUSH_SUMMARY、DSH_PUSH_TOOL、DSH_PUSH_LANG(通知文案覆盖;不设时由 lang 决定)、DSH_PUSH_APPROVAL_GRACE_MS(「等授权」推送前的等待窗口,给更快的自动审批插件让路;默认 5000;它与仅文件层的 pushApprovalGraceMs 键不在设置面板里)。LAN_GATE_RELAY_SECRET 不可外部指定:插件每次加载现生成、自己交给网关。

上传上限、键盘校准、回合折叠这几个旋钮与 1.x 行为一致——只是从「插件行 YAML」搬到了「设置页」(手写插件行 YAML 也照样有效)。


通知什么时候会响

默认只在真正需要你的时候响,分两条互不依赖的线。

一、系统自己判断的(恒开,且不受最小间隔压制)

情况 通知
某个工具在等你授权 「DSH 等你授权」,带工具名
模型调用 ask_user_question 在等你回答 「DSH 等你回答」

这两类不看会话层级——子代理自己卡在授权上,照样喊你,因为等的还是你。也不受最小间隔压制:「有操作等你点头」是最不能被吞掉的一条。2.0 起桌面端 App 里跑的会话同样覆盖:钩子挂在服务端侧,会话在哪跑都一样。

有机器答复者时的时机:审批事件的顺序是「先记 asked → 问答复者 → 记 decided」,所以推送并不是一见到 asked 就发,而是等 DSH_PUSH_APPROVAL_GRACE_MS(默认 5 秒)——这段时间内被答复掉的就不推。换了更慢的模型答复者就把这个值调大(实测平均 2.4 秒)。策略自动放行的授权不会打扰你。

二、模型自己决定的

push_notify 工具,模型在这些时候该调:你明确要求做完通知、需要你介入才能继续、出现你大概率想立刻知道的意外。不该调的场景同样写在工具描述里,同一段文字还作为会话上下文注入,两处共用同一个常量、不会各改各的。

默认不会响的:普通跑完一轮不推(想要旧行为设 pushTurnEnd 或 DSH_PUSH_TURN_END=1);子代理跑完永远不推,无论上面那个开关。

通知里写什么:默认只有标题。开 pushSummary 才带这一轮的最终回复——只取正文,不含思考过程;这一轮没说话就退回「最后执行了 xx 工具」。推送 payload 是 aes128gcm 端到端加密的。


功能

主服务端(手机访问,1.x 的延续)

  • 会话列表主屏 + 独立会话页两级页面栈,横向推入推出
  • 主屏插件入口 chips,按已装插件自动出现,显隐可自定义
  • composer 重排:控件图标化,权限/模型菜单变成底部 sheet
  • 会话信息卡:六格统计 + 导出日志 / 重命名 / Fork / 归档;分享图一键导出 PNG 长图;2.0 起多一行「远程访问」开关
  • 回合过程折叠、左缘右滑返回、安卓返回手势接管、手机本地附件上传
  • 配对码换长期设备令牌,认令牌不认 IP,可随时吊销
  • 真 PWA + 真 Web Push(VAPID + aes128gcm),默认只在等授权/等回答时响

主服务端(2.0 新增)

  • 会话共享:四个开关入口(含手机信息卡片)、闲置休眠、新建自动共享、子会话跟随
  • 以上全部在 DSH 跑桌面端 App 时同样成立:网关自动转发到桌面端后台的实际端口,桌面端会话的等授权/等回答照推手机

桌面应用端(2.0 新增)

  • 侧边栏远程分组(「服务端名 · 工作区名」),远程会话与本地会话同等使用:完整历史、实时进度、发消息、取消、排队调整、审批与提问应答、模型选择、文件树、改动列表与改动摘要 / diff、目标、斜杠命令、预设切换、子智能体提问/中断、附件与 @ 引用、开在服务端的终端
  • 远程会话可附加非图片文件:上传请求由子客户端在本机后台接住、经中继流式转到服务端会话;上限 100 MiB 是中继自定的(本机上传无此限),超限在子客户端本地即提示;慢速链路受 300 秒超时约束
  • 远程会话里的模型下拉框显示服务端的模型目录(分组名「服务端名 · 分组名」),本机会话只显示本机模型;中继离线时保留上次拉到的服务端分组;视觉路由等本机设置里不会出现服务端分组。已知边界:服务端新建且未发过消息的会话,下拉框按本机默认模型显示
  • 远程分组里新建的会话跑在服务端对应工作区、自动开启远程;远程会话可改名、归档、置顶、分叉,也可从子客户端关闭其远程(带确认)
  • 远程会话标题行连接图标(在线 / 离线 / 版本有差异);会话被休眠或服务端关闭时显示「远程已关闭」及原因;服务端离线时分组变灰、输入禁用,后台自动退避重连
  • 审批/提问先到先得:服务端自己的界面先答了,子客户端自动同步成「已处理」

深度说明:界面 · 公网接入 + 中继协议


版本容错

三层,从严到宽:

  1. 中继协议版本必须一致——实际操作上,两端 zen-remote 需同为 2.0.x。服务端若还是 1.x,它的网关不认子客户端的 Bearer 令牌,请求会撞上通用配对墙,子客户端报「令牌已失效(或服务端 zen-remote 低于 2.0.0)」。DSH 版本可以不同。
  2. DSH 接口指纹决定其余:两端各自对中继会用到的几组远程接口生成规范化指纹,握手时比对。全部一致即完全兼容,版本号不同也无关;有差异照常连接,远程分组标注「(版本有差异)」,设置页诊断区列出差异组,只有受影响的面板降级。
  3. 运行时降级:某次转发调用因参数或结果校验失败,只有那个面板显示「与服务端版本不兼容」并记入诊断区,其余功能继续可用。

安全模型

一台已配对设备被信任到什么程度,明说:

  • 已配对的桌面应用端被视为可信设备。 远程会话里的终端是以服务端用户身份运行的 shell,不受智能体沙箱与审批限制。文件预览接口(workspaceFiles/read 等)不限制在会话目录内——服务端进程读得到的文件都读得到。已配对设备可以在服务端任意工作区新建会话(不受「开启远程」限制;新建的会话自动开启远程)。
  • 「只有开启远程的会话可见」约束的是会话数据:未开启远程的会话,其列表、历史、实时进度、审批/提问事件都被中继拒绝或过滤;@ 引用候选只列已共享会话;发消息、改写排队消息、斜杠命令里内嵌的 dsh-session: 会话引用一旦指向未开启远程的会话,整个调用被服务端拒绝。它不是围住整台机器的沙箱。
  • 管理操作只在服务端本机:生成配对码、改角色、吊销只能在跑服务端那台机器的设置页做——经网关进来的请求可以查看状态,但变更动作被拒——唯一例外是开关会话的远程:Web 应用端(手机)可以开关,手机信息卡片里的「远程访问」开关就走这条;桌面应用端根本够不到管理路由。

已知限制

  • 同时开多个 DSH 窗口(包括用浏览器打开桌面端的后台页面)时,子客户端对「当前打开的是哪个会话」可能判断不准:关闭远程的会话隐藏时机可能不对,极端情况下正打开着的会话会被当成后台会话、被踢回首页。
  • 换到另一台服务端后再换回原来那台,或服务端删除某工作区后又以同一 id 重建:相关远程分组要重载页面才会再出现(DSH 侧边栏对移除过的工作区 id,在页面生命周期内不再接受)。
  • 远程会话里「导出会话」已禁用(菜单项隐藏,后台对虚拟会话 id 一律拒绝);改动面板的摘要与 diff 可以看(经中继转发),但「打开 / 在访达中显示 / 在应用中打开」这类会在服务端机器上弹窗的入口在远程会话里隐藏(交付物卡片同理)。
  • @ 引用候选由宿主先截前 50 条再按共享过滤:服务端会话很多时,已共享会话可能不出现在候选列表里(不影响引用检查本身——直接写出的引用仍会被逐条校验)。
  • 第三方插件自己的非标准接口不转发——它们的面板在远程会话里降级或隐藏。插件的工具跑在服务端,不受影响;受影响的是插件在界面上带着会话 id 调它自己后台接口的部分(dsh-better-sidebar 就是典型,已按下一条处理)。
  • 装了 dsh-better-sidebar 时,远程会话里它的文件浏览、编辑器、git、任务、底部工作台等界面会被隐藏——它们读写的是子客户端本机的文件;又因为它接管了宿主的「文件」标签,远程会话里暂时没有侧栏文件浏览;聊天或交付物里的文件链接在远程会话里会打开一个空的右栏。
  • 两端 zen-remote 需同为 2.0.x(中继协议版本一致);DSH 版本可以不同,接口指纹有差异时远程分组标注「(版本有差异)」。

已知问题

iOS 26.x 独立 PWA 视口缩水:加到主屏后视口底部会少掉一条状态栏高度,普通 Safari 标签页正常。这是 iOS 系统缺陷,缺掉的区域在文档之外,CSS 够不着;本插件做了三层缓解(浅色 manifest 背景 + 安全区补偿 + 强制重排),能减轻但不保证复原。彻底恢复只能整个 App 退出重开。

个别环境软键盘对浏览器完全不可见,输入框抬升靠估算兜底:部分组合里系统不把键盘高度告知页面(visualViewport、VirtualKeyboard API 一并失效,均已实测排除)。插件聚焦后探测约 1.2 秒,判定「键盘不可见」就按估计高度抬升输入框。抬升高度差得明显的话,在设置页里调 keyboardLiftRatio / keyboardLiftMaxPx / keyboardSafetyPadPx。正常环境完全不走这条路径。

经反代访问时设置页打不开(插件配置列表空白、模型卡片报「settings are unavailable in this browser」):DSH 官方设计是设置类 RPC 只对回环连接开放,远程浏览器的设置镜像初始即 unavailable。绕法:回跑 DSH 的那台机器用本机浏览器改。经网关打开的插件设置页同样受此限制。与本插件无关。


权限与数据

  • 网络:网关只监听本机(默认 127.0.0.1:3088),对外暴露完全由你的反代/隧道决定;推送经浏览器推送服务商中转(aes128gcm 端到端加密);桌面应用端与主服务端之间的中继也走这条网关,授权在服务端逐请求复核。插件自身不向任何第三方上报数据。
  • 文件:附件上传只写入当前会话工作目录下的 .dsh-uploads/;配对状态在 ~/.dsh/lan-gate-state.json,配置在 ~/.dsh/lan-gate.config.json,共享表在 ~/.dsh/zen-remote-shares.json,服务端 id 在 ~/.dsh/zen-remote-server.json。
  • 凭据:不收集、不存储任何账号密码;设备身份是本插件自己签发的随机令牌(Web 应用端为 HttpOnly Cookie,桌面应用端为密钥字段),外加一枚每次加载现生成的中继共享密钥,不出这台机器对。

排障:运行日志在 ~/.dsh/logs/web.log(网关与推送的行带 [dsh-zen-remote-*] 前缀;桌面端构建打到 App 控制台)。安全问题请走 GitHub Security Advisories 私下报告,不要公开提 issue。


已适配的第三方插件

移动端 UI 对下列插件做了专门适配。所有适配都锚定对应插件自己的 DOM 标记: 没装该插件时规则不生效,装了未列出的插件也不会被误伤。

插件 移动端适配内容 实测版本
dsh-better-sidebar 0.19+:它的全部 tab 都在 DSH 0.1.5 官方右侧栏里、手机上宿主自己切全屏(避让刘海与底部指示条)——会话页头部留入口按钮,左缘回退手势收它,文件树里点 @ 引用后自动收起。≤ 0.18(自绘右栏,只在 DSH < 0.1.5 上):手机全宽抽屉并避让刘海安全区、底部居中的关闭按钮 0.19.1(老版规则 0.15.0)
@nanmicoder/dsh-agent-teams AgentTeams 活动浮层挪到会话头部下方(原位置压住头部按钮)、会话列表页自动隐藏;子代理会话头部保留可点的父会话标题,一键切回主会话 0.1.9
@ychris12138/dsh-usage-stats 用量与余额入口收进主屏 chips 行 0.2.9
@opendsh/dsh-plugin-scheduled-tasks 定时任务入口收进主屏 chips 行 0.2.3
dsh-at-file @文件引用,配合附件上传的 @ 路径引用使用;它和本插件的附件 chip 读同一份草稿 token,手机端隐藏它 .dsh-uploads/ 下那几行以免同一个文件被画两遍(缩略图 + 文件名),其余 @ 引用不动 0.6.7
@ace-zone/dsh-market 插件市场弹窗顶栏在手机上放不下,关闭的 × 被挤出面板外(触屏没有 Esc,等于关不掉);隐藏标语 / 版本号 / 官网链接三个装饰位,标题改成省略号收缩,语言切换和 × 保留并加大点按面积 0.1.66
dsh-vision-toolkit 图像 Q&A/OCR,配合手机端附件上传使用 —
dsh-web-ui 全家桶 沿用上游 dsh-web-mobile 的兼容规则(文件树 / 预览浮层限宽居中等) —

各项适配的技术细节(锚点选择器、断点、取舍记录)见界面文档的「兼容插件」一节。


上游致谢

本插件的界面层衍生自 mexiaosqwq/dsh-web-mobile,通道层衍生自 zylzyqzz/dsh-mobile-pwa(其自身衍生自 Bernardxu123/dsh-mobile-gate),均为 MIT,原始版权行保留在 LICENSE。

License

MIT

内容来自项目 README(GitHub)↗

链接

同类插件

查看整个分类 →

社区评论

评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。