- Home
- Plugins
- Tools & Capabilities
- dsh-phone-remote
dsh-phone-remote
wlxyxykj/dsh-phone-remote
Install
dsh plugin --profile web add github:wlxyxykj/dsh-phone-remoteREADME
dsh-phone-remote · 手机遥控
用手机控制 DSH 桌面版里跑着的 Agent:手机上说一句话,电脑上的 Agent 就干活, 输出实时推到手机,随时能叫停。
Phone control for DeepSeek Harness (DSH Desktop): serve a token-protected mobile page from this computer so you can drive the agent from your phone.
目录
它能干什么
DSH 桌面版自带的界面只监听 127.0.0.1,手机打不开。这个插件在电脑上再起一个只服务手机的小网页:
| 在手机上你能做 | 说明 |
|---|---|
| 看会话列表 | 电脑上所有会话(含正在运行的那个)都在列表里 |
| 选一个会话继续聊 | 和电脑上是同一个会话、同一份上下文 |
| 新建会话 | 可以指定工作目录,Agent 就在那个目录里干活 |
| 发指令 | Agent 真的会在电脑上执行:跑命令、改文件、查资料 |
| 传文件给 Agent | 用 📎 把手机里的文件(照片、PDF、表格…)传到电脑,Agent 直接读 |
| 把产出下回手机 | Agent 说一句「发你手机」,手机页就出现下载卡片,点一下存到手机 |
| 实时看输出 | 一个字一个字推过来;工具调用显示成可展开的小卡片 |
| 随时叫停 | 运行中按钮变成 ■,点一下停止当前回合 |
电脑上还有一个控制台(只有本机能打开),用来出示二维码、查看/重置口令、管理访问白名单。
前提条件
| 项目 | 要求 |
|---|---|
| 电脑 | 装有 DSH 桌面版(本插件在 DSH 0.2.0-rc.2 上实测通过) |
| 手机 | 任意浏览器即可(Safari / Chrome / 国产浏览器都行;微信内置浏览器可能限制流式推送,建议用系统浏览器) |
| 网络 | 手机要能直接访问到电脑的某个 IP:同一个 Wi-Fi 最省事;不同网络见 手机连不上? |
| 端口 | 默认用 8790;被占用时会自动往后找(8791、8792…),以控制台/日志显示的为准 |
安装(DSH 桌面版)
方式一:图形界面(推荐)
-
打开 DSH 桌面版 → 设置 → 插件
-
点 添加插件
-
在输入框里粘贴这一行(GitHub 地址,公开仓库,不需要任何账号):
github:wlxyxykj/dsh-phone-remote也可以填本地路径:插件目录,或打好的
.tgz文件路径。 -
点 安装,等它把依赖装完(几秒)
-
重启一次 DSH 桌面版 ← 必须,见下方说明
-
重启后回到 设置 → 插件,应能看到
dsh-phone-remote处于已启用状态
为什么必须重启? DSH 宿主进程按「模块 URL」缓存插件代码,进程活着的时候不会重新读取磁盘上的插件模块。 所以安装或升级插件代码之后必须重启一次;改配置项则可以热生效,不用重启。
方式二:命令行
DSH 自带命令行,桌面版用户也可以用:
dsh plugin --profile desktop add github:wlxyxykj/dsh-phone-remote
装完同样重启一次 DSH 桌面版;重启后到「设置 → 插件」确认它是启用状态(有些情况下需要在那里手动打开开关)。
怎么确认装好了
重启后,设置 → 插件里能看到 dsh-phone-remote;或者直接打开控制台:
http://127.0.0.1:8790/
能打开就说明跑起来了。启动日志里也会打印一段横幅:
[dsh-phone-remote]
┌─ DSH 手机遥控已就绪 ─────────────────────────────────
│ 监听 0.0.0.0:8790
│ 电脑面板 http://127.0.0.1:8790/
│ 访问控制 开放(任何能连到本机的设备都可以,凭口令访问)
│ 手机打开:
│ http://192.168.x.x:8790/m?t=xxxxxxxx WLAN
└──────────────────────────────────────────────────────
使用:三步上手
第 1 步:在电脑上打开控制台
浏览器打开 http://127.0.0.1:8790/
这个页面只在本机能开(手机打不开,故意的),里面是:手机链接 + 二维码 + 口令 + 访问控制 + 会话概览。
第 2 步:手机扫码进来
手机连和电脑同一个 Wi-Fi,然后用相机扫面板上的二维码:
- 二维码里已经带了口令,扫完直接进入,不用手输;
- 手机浏览器会记住口令(存成 Cookie,重启电脑也还在);
- 也可以在手机浏览器里手动输入面板上那条链接(形如
http://192.168.1.23:8790/m?t=xxxxxxxx)。
第 3 步:指挥 Agent
| 想做的事 | 在手机上怎么操作 |
|---|---|
| 切换会话 | 左上角 ☰ → 点会话 |
| 新建会话 | ☰ → 底部「+ 新建会话并接管」,可填工作目录 |
| 发指令 | 底部输入框输入,点 ↑ 发送 |
| 看输出 | 自动流式显示;工具调用是一条可展开的卡片,点开看完整输出 |
| 叫停 | 运行中发送按钮变成 ■,点一下停止当前回合 |
不需要在手机上确认任何授权弹窗——远程会话默认已经设成 approvalPolicy: never,发指令就直接执行。
第 4 步(可选):传文件 / 收文件
手机 → 电脑:给 Agent 喂文件
- 手机页面底部点 📎,选文件(可多选,单个最大 25 MB);
- 上传完成后输入框上方出现文件小标签(⏳ 上传中 → 📎 已就绪,点 ✕ 可移除);
- 正常发指令即可——文件会写进这个会话的工作目录下的
.phone-uploads/, 指令里自动附上路径,Agent 用它自带的文件工具直接读。
落地路径形如
.phone-uploads/20260930-220145-合同.pdf。 你只要说「读一下我刚传的合同,把关键条款列出来」就行。
电脑 → 手机:把产出拿回来
Agent 需要把文件给你时,它会调用工具 phone_send_file;你也可以直接说:
把这个报告发我手机上
手机页面上会出现一张下载卡片(文件名 + 大小 + 备注),点一下就存到手机。 卡片刷新后仍在(有效期 2 小时,单文件最大 25 MB)。
如果点下载没反应,长按卡片选「在新标签页打开」——部分手机浏览器对内联下载有限制。
界面导览
电脑控制台 http://127.0.0.1:8790/
| 区域 | 内容 |
|---|---|
| 手机访问链接 | 所有可用地址(Wi-Fi / 有线 / Tailscale 等),带二维码和「复制」按钮;点链接即复制含口令的完整地址 |
| 状态 | 监听地址、访问口令(显示/复制)、会话数、运行中的会话数、新会话默认目录 |
| 访问控制 | 白名单开关、白名单列表、最近访问过的客户端(被拦的会标「已拦截」,旁边就是「允许」按钮) |
| 会话 | 最近有活动的会话一览 |
| 安全须知 | 口令等于操作权等提醒 |
控制台每 5 秒自动刷新,换了网络后新地址会自动出现在列表里。
手机页 /m
| 区域 | 内容 |
|---|---|
| 顶栏 | 当前会话名、连接/运行状态、☰ 会话列表、⟳ 手动重连 |
| 消息流 | 你说的(右侧气泡)、Agent 回答(Markdown 渲染)、工具调用卡片、折叠的「💭 思考过程」、文件下载卡片、错误提示 |
| 底栏 | 📎 上传文件、输入框、发送/停止按钮;上传中的文件显示为小标签 |
| 口令页 | 如果这个浏览器没有口令,会先显示「需要访问口令」的输入框 |
配置
两种改法,任选一种(改配置不用重启,保存即生效):
A. 在 DSH 里改:设置 → 插件 → dsh-phone-remote → 配置
B. 改 profile 的 cordis.patch.yml($DSH_HOME/profiles/<profile>/cordis.patch.yml),加一行:
- id: phone-remote
name: 'dsh-phone-remote'
config:
port: 8790
cwd: 'D:\work\my-project'
allowCancel: false
配置项
| 键 | 默认 | 说明 |
|---|---|---|
enabled | true | false 时插件完全不启动(不监听、不注册工具) |
host | 0.0.0.0 | 监听地址。0.0.0.0 = 所有网卡都能访问;改成 127.0.0.1 就只有本机能用 |
port | 8790 | 起始端口;被占用时自动向后找,最多试到 8799 |
token | 空 | 访问口令。留空 = 复用已保存的,没有就随机生成 24 位并写入 $DSH_HOME/dsh-phone-remote.json |
cwd | 空 | 手机上新建会话时的默认工作目录 |
agentPreset | 空 | 手机上新建会话使用的 Agent preset(如 standard) |
approvalPolicy | never | 远程会话的授权策略。never = 不再逐条询问(推荐);ask = 跟随桌面端弹窗 |
allowCreate | true | 是否允许手机新建会话 |
allowCancel | true | 是否允许手机叫停回合 |
exposePanel | true | 是否提供本机控制台 / |
allowFrom | [] | IP 白名单(写死在配置里)。非空 = 只有名单里的客户端能访问,且面板不能改;留空则在面板上管理 |
访问控制与安全
口令是怎么工作的
- 口令是 24 位随机字符(约 120 bit),暴力猜解不可行;
- 二维码/链接里带着它(
?t=...),所以扫码等于自动带钥匙; - 服务端校验通过后会种一个
HttpOnly+SameSite=Strict的 Cookie,之后这个浏览器就不用再带; - 校验用 SHA-256 常数时间比较;每个 IP 每分钟失败超过 20 次会被限流(429)。
白名单(可选,建议在有公网 IP 时打开)
默认是开放的:任何能连到这台电脑的设备都能打开登录页(仍需要口令)。
如果电脑有公网 IP(校园网直连、宽带拨号很常见),建议打开「仅白名单」:
- 控制台 → 访问控制 → 「启用『仅白名单』」;
- 让手机先访问一次(被拦没关系),它的 IP 会出现在最近访问的客户端里,标着「已拦截」;
- 点那一行的 允许 —— 立即放行,不用重启。
白名单每行支持三种写法:203.0.113.42(单个 IP)、203.0.113.(整个前缀)、10.0.0.0/8(CIDR 网段)。
代价:手机用移动数据时 IP 会变(开关飞行模式就会变)。变了之后手机会显示「此设备未授权」, 你需要回电脑面板点一下「允许」。如果你经常不在电脑边,就不要开白名单——纯口令模式换任何网络都能连。
两条必须知道的安全提醒
- 链接/二维码就是钥匙,别截图外发、别丢群里;
- 目前是明文 HTTP,链路上的中间人理论上能嗅探到口令。要彻底解决就用
Tailscale 之类的加密隧道,或者用完就把配置里的
enabled设为false。
用 Tailscale:固定地址 + 加密(推荐)
手机用移动数据时 IP 会变、白名单难维护、明文传输有风险——Tailscale 一次解决这三件事:
它把你的设备组成一个私有网络,每台设备拿到固定的 100.x.y.z 地址,设备之间端到端加密。
- 电脑和手机都装 Tailscale,登录同一个账号;
- 电脑上执行
tailscale ip -4拿到形如100.101.102.103的地址(控制台链接列表里也会多出一条,排在最前面); - 手机浏览器打开
http://100.101.102.103:8790/m?t=<口令>,之后无论在 Wi-Fi 还是流量下都能用。
想收得更紧(二选一):
| 方案 | 做法 | 效果 |
|---|---|---|
| A. 只换地址 | 保持 host: '0.0.0.0',白名单写 100.64.0.0/10 | 公网仍能连到端口,但一律 403,只有你的 tailnet 能进 |
| B. 只监听 Tailscale 网卡 | 配置 host: '100.101.102.103' | 公网连 TCP 都连不上,最彻底 |
方案 B 的注意点:Tailscale 必须在 DSH 启动前已经连上,否则那个地址不存在。 插件遇到这种情况会自动退回监听
0.0.0.0并打一条告警,不会整个起不来(此时请确保白名单是开的)。国内提示:
login.tailscale.com偶尔不好访问,连不上可以换 ZeroTier,原理一样(插件同样会把它的网卡排在前面)。
手机连不上?逐个排查
按顺序试,基本三步内能定位:
1. 手机和电脑网络通不通
- 同一个 Wi-Fi 是最省事的(注意有些公共/校园 Wi-Fi 开了「客户端隔离」,同网段也互相不通);
- 电脑有公网 IP 时,手机用移动数据也可能直接连上(取决于网络是否放行);
- 都通不了就用手机开热点,让电脑连手机热点——控制台几秒内会自动列出新地址,扫新的码即可;
- 想随时随地用,见上面的 Tailscale。
2. 电脑上的控制台打得开吗
- 打不开 → 插件没跑起来:确认
设置 → 插件里是启用状态,并重启一次 DSH 桌面版; - 端口不是 8790 → 被占用了,看控制台标题/启动日志里的实际端口。
3. 手机显示什么
| 手机上的现象 | 原因 | 怎么办 |
|---|---|---|
| 「此设备未授权访问」 | 白名单开着,手机 IP 不在名单里 | 回电脑控制台 → 访问控制 → 最近访问 → 点「允许」;或关掉白名单 |
| 「需要访问口令」输入框 | 链接里没带口令,或这个浏览器没存过 | 粘贴面板上的口令,或重新扫码 |
| 黑屏 / 「页面没能启动」卡片 | 页面脚本没加载成功 | 下拉刷新;不行就重新扫码 |
| 页面能开但没反应 | 局域网能开页面、流式被中间设备掐断 | 换系统浏览器(别用微信内置) |
| 一直转圈 | 网络到了但服务没回 | 确认电脑没休眠、插件还在运行 |
4. 还是不行?放行防火墙
Windows 防火墙可能拦了入站端口。管理员 PowerShell 执行一次(端口按实际的改):
New-NetFirewallRule -DisplayName "DSH Phone Remote" -Direction Inbound -Action Allow `
-Protocol TCP -LocalPort 8790 -Profile Private
Wi-Fi 被 Windows 标成「公用网络」时,
-Profile Private不生效;要么把该网络改成专用网络,要么用-Profile Any(暴露面更大,慎用)。
5. 忘记口令了怎么办
打开电脑控制台 → 状态 → 显示 就能看到口令;点 重置口令 会作废旧链接和所有已登录的手机,然后重新扫码即可。
升级 / 卸载
DSH 目前不支持插件自动更新,升级要手动来:
升级:设置 → 插件 → 卸载 dsh-phone-remote → 重新「添加插件」新版本 → 重启 DSH
卸载:设置 → 插件 → 卸载 dsh-phone-remote → 重启 DSH
命令行方式:
dsh plugin --profile desktop remove dsh-phone-remote # 卸载
dsh plugin --profile desktop add github:wlxyxykj/dsh-phone-remote#v1.1.0 # 装指定版本
用 GitHub 安装时可以用 tag 锁定版本,例如 github:wlxyxykj/dsh-phone-remote#v1.1.0。
工作原理
┌──────────────┐ 扫码/链接 ┌────────────────────┐ 局域网/公网 ┌──────────────────────┐
│ 手机浏览器 │ ─────────────▶ │ 电脑控制台 (仅本机) │ ◀───────────── │ DSH 桌面版宿主进程 │
│ /m?t=<口令> │ ◀───────────── │ 127.0.0.1:8790 │ │ ctx.sessionController│
│ 发指令/看输出 │ SSE 流式推送 │ 二维码/白名单 │ │ (真正在跑 Agent) │
└──────────────┘ └────────────────────┘ └──────────────────────┘
- 插件作为 DSH 的一个 bundle 被加载,在宿主进程里监听一个端口;
- 手机面
/m与/api/m/*需要口令;控制台/、/api/panel/*、/api/qr只接受 127.0.0.1; - 发指令走
ctx.sessionController(list / create / resolveAgent / prompt / cancel / follow), 输出通过follow的 SSE 流推送;远程会话在第一条指令前就被设成approvalPolicy: never; - 口令、白名单存在
$DSH_HOME/dsh-phone-remote.json(旧版本名mobile-remote.json会被自动沿用)。
文件结构
| 文件 | 作用 |
|---|---|
lib/index.js | 插件入口:配置、口令、启动监听、注册 phone_remote 工具、卸载清理 |
lib/server.js | HTTP 路由、口令校验、IP 白名单、SSE、端口顺延、优雅停止 |
lib/session.js | 到 DSH 宿主服务的桥接 |
lib/app.html | 手机页(原生 JS,无前端依赖) |
lib/panel.html | 电脑控制台 |
lib/markdown.js | 零依赖 Markdown 渲染器(转 DOM 只用 textContent,模型输出的 HTML 不会被当标签执行) |
lib/qr.js | 零依赖 QR 编码器(字节模式,版本 1–10,EC L/M/Q/H) |
lib/net.js / lib/store.js | 局域网地址探测 / 状态文件读写 |
locale/*.json | 插件在 DSH 里的显示名与描述(中文/英文) |
另外注册了两个给 Agent 用的工具:
| 工具 | 作用 |
|---|---|
phone_remote | 你说「给我手机遥控的链接」,它返回链接和控制台地址 |
phone_send_file | 把电脑上的文件推到手机(你在手机页看到下载卡片),说「这个文件发我手机」即可 |
文件传输的两个方向用的是不同机制:上传是把文件写进会话工作目录后,把路径写进指令(Agent 用自己的文件工具读,不依赖模型的附件能力);
下发是把文件登记到插件的下载表,再通过手机正在监听的 SSE 流推一张卡片过去,下载走 /api/m/download/<id>(同样要口令)。
开发与测试
node --test "test/*.test.mjs"
93 项测试,覆盖:HTTP 路由 / 口令栅栏 / 限流、IP 白名单(含真实非回环地址的拦截测试)、 SSE 流、会话桥接、文件上传与下载(含越权、超限、过期文件、SSE 推送)、插件装配、Markdown 渲染、QR 编码。
其中有 4 项是与两套独立 QR 实现(node-qrcode、qrcode-generator)的逐模块交叉比对,
需要 scratch/ 下的参考实现;克隆下来没有它时会自动跳过,其余 89 项照常通过。
License
MIT © tofar
Related plugins
archify (deepseek-harness)
tt-a1i/archify
WeKnora (dsh-weknora)
tencent/weknora
weknora
tencent/weknora
BrowserSkill (dsh-plugin-browserskill)
tencent/browserskill