@feiyang666/dsh-mobile-remote 1.0.1 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +86 -14
- package/LICENSE +1 -1
- package/README.md +195 -63
- package/README.zh.md +194 -62
- package/RELEASE_NOTES.md +52 -0
- package/cordis.patch.yml +12 -16
- package/lib/client.js +976 -503
- package/lib/external.js +729 -0
- package/lib/index.js +1173 -188
- package/lib/password.js +218 -0
- package/lib/qrcode.js +2300 -0
- package/package.json +30 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,21 +1,93 @@
|
|
|
1
|
-
# Changelog
|
|
1
|
+
# 更新日志 / Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## v1.4.1 (2026-08-20)
|
|
4
4
|
|
|
5
|
-
###
|
|
5
|
+
### 新增 / Added
|
|
6
|
+
- **外网隧道真实状态判定**(`lib/external.js` + `lib/client.js`):
|
|
7
|
+
- 开启外网时不再"进程活着 = 在线",改为探测 frpc 日志确认隧道真正建立(`start proxy success`)才判 `online`;
|
|
8
|
+
- 新增 `probeTunnelHealth()`:`/status` 轮询时复查日志,发现断线(`connect to server error`)降级为「连接中」、token 不匹配(`token in login doesn't match`)降级为「出错」,重连成功后自动恢复在线;
|
|
9
|
+
- 前端新增红色「出错」徽标 + 错误卡,直接展示 frpc 真实报错与解决指引(服务器 `FRP_TOKEN` 与 `frps.toml` 的 `auth.token` 不一致等),并提供「查看 frpc 日志」按钮;
|
|
10
|
+
- `error` 状态支持一键重试(kill 旧进程重新绑定)。
|
|
11
|
+
- **隧道持续心跳保活**(`lib/external.js`):隧道在线期间每 60s 上报一次心跳,让中转端 `last_seen` 保持新鲜;停止隧道时主动上报 `offline`,配合后端在线判定实时反映真实状态。
|
|
12
|
+
- **FRP_TOKEN 占位符检测**(前后端联动):中转端 `/status`、`/stats` 返回 `frpTokenWarning`;插件面板显示黄色警告条,提示服务器 `.env` 的 `FRP_TOKEN` 仍是占位符导致隧道必然 502。
|
|
13
|
+
- **DSH 状态卡默认折叠**(`lib/client.js`):折叠态只显示摘要行(会话 / 工作区 / 插件 / 模型数),点击标题展开详情,节省面板空间。
|
|
6
14
|
|
|
7
|
-
|
|
8
|
-
-
|
|
15
|
+
### 修复 / Fixed
|
|
16
|
+
- **设置页空白崩溃**:修复 `status` 首次渲染为 `null` 时,`status.external...` 无守卫导致的 `Cannot read properties of null` 崩溃(面板内容区被错误边界吞成空白);同时加固 `extErrText` 的完整守卫。
|
|
17
|
+
- 外网状态不再被 `/status` 覆盖为假在线(`externalView` 直接透传真实状态)。
|
|
9
18
|
|
|
10
|
-
|
|
19
|
+
### 变更 / Changed
|
|
20
|
+
- `lib/client.js`:外网隧道卡新增 frpc 进程 PID / 已运行时长 / 脱敏绑定码展示。
|
|
21
|
+
- 依赖后端 `dsh-update-server` 同步升级(成员端在线判定 / `/stats` / `heartbeat` 离线支持),旧后端自动回退兼容。
|
|
11
22
|
|
|
12
|
-
|
|
23
|
+
## v1.4.0 (2026-08-20)
|
|
13
24
|
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
25
|
+
### 新增 / Added
|
|
26
|
+
- **运行时信息卡扩充**(host `lib/index.js`):新增 CPU 型号 / 频率、系统负载(1m / 5m / 15m)、系统开机时长、内存使用率(%)。
|
|
27
|
+
- **DSH 应用层状态卡**(host + client):
|
|
28
|
+
- **版本号**:多位置探测 dsh 版本(profile 本地 / 桌面版 `dsh-local` / 全局安装);
|
|
29
|
+
- **会话总数**:`ctx.sessionPersistence.list()`(带 2s 超时保护);
|
|
30
|
+
- **工作区列表**:路径 / 标题 / 会话数(`ctx.workspaceRegistry.list()`);
|
|
31
|
+
- **已安装插件列表**:插件名 / 启用状态 / fiber 阶段(`ctx.pluginInventory.list()`);
|
|
32
|
+
- **模型提供方**:提供方 id / 名称(`ctx.llm.listProviders()`)。
|
|
33
|
+
- 以上数据由**后台每 60s 缓存刷新**,`/status` 直接读缓存,不拖慢 5s 轮询;任一服务不可用时自动降级隐藏。
|
|
34
|
+
- **设备详情补强**(`MOBILE_JS` + host + client):新增**设备内存(GB)/ CPU 核数 / 电池电量(含是否充电)**。
|
|
35
|
+
- **外网隧道详情补强**(host + client):新增 **frpc 进程 PID / 已运行时长 / 脱敏绑定码**(前 4 位 + `****`)。
|
|
20
36
|
|
|
21
|
-
|
|
37
|
+
### 变更 / Changed
|
|
38
|
+
- host 侧通过 `ctx.get()` 可选获取 `sessionPersistence` / `workspaceRegistry` / `pluginInventory` / `llm`,**不新增必选 inject 依赖**,保证精简启动方式下插件仍可正常运行。
|
|
39
|
+
- `lib/external.js`:frpc 启动时记录 `startedAt`,停止时清除。
|
|
40
|
+
|
|
41
|
+
## v1.3.0 (2026-08-20)
|
|
42
|
+
|
|
43
|
+
### 新增 / Added
|
|
44
|
+
- **更丰富的数据展示**(host `lib/index.js` + client `lib/client.js`):
|
|
45
|
+
- **设备详情可展开**:已连接设备列表改为可点击展开,展示系统 / 浏览器、屏幕 / 视口 / DPR、触屏标记、网络连接(effectiveType / 下行带宽 / RTT)、在线状态、语言 / 平台、当前页面(标题 + 路径)、首次连接 / 最后活跃时间、心跳次数;
|
|
46
|
+
- **心跳元数据补全**:移动端心跳上报由原来的 `id + ua` 扩充为完整设备信息(`platform` / `lang` / `online` / `touch` / `dpr` / `screen` / `viewport` / `connection` / `path` / `title` / `mobile`);
|
|
47
|
+
- **统计区扩充**:由 2 格变为 4 格 —— 当前连接设备 / 累计设备 / 累计心跳 / 局域网地址;
|
|
48
|
+
- **运行时信息卡**:运行时长、Node.js 版本、进程 PID、主机名、系统(平台 / 版本 / 架构)、CPU 核数、可用内存 / 总内存、RSS、堆内存、当前 Profile、DSH 数据目录;
|
|
49
|
+
- **网络接口卡**:所有 IPv4 网卡的网卡名 / IP / CIDR / 掩码 / MAC / 是否回环;
|
|
50
|
+
- **外网隧道详情**:域名、隧道端口、frpc 版本、中转服务器状态 / 最后心跳 / 服务器时间,以及「查看 frpc 日志」按钮(新 host API `GET /__dsh_remote/external/log`)。
|
|
51
|
+
|
|
52
|
+
### 修复 / Fixed
|
|
53
|
+
- **累计心跳数恒为 0**:`tracker.beats()` 之前只是读取、从不自增,导致 `totalHeartbeats` 永远为 0;改为 `recordBeat()` 每次心跳 +1。
|
|
54
|
+
- 累计去重设备数 / 心跳数改为设备粒度统计(每台设备 `beatCount`)。
|
|
55
|
+
|
|
56
|
+
### 变更 / Changed
|
|
57
|
+
- `lib/external.js`:启动时探测并记录 frpc 版本(`state.frpcVersion`),供设置页展示;导出 `frpcLogTail()`。
|
|
58
|
+
- `lib/client.js`:设置面板新增多个数据展示区块,布局保持主题 token 自适应深色 / 浅色。
|
|
59
|
+
|
|
60
|
+
## v1.2.0 (2026-08-20)
|
|
61
|
+
|
|
62
|
+
### 新增 / Added
|
|
63
|
+
- **远程访问密码门禁**(host half `lib/index.js` + `lib/password.js` + client half `lib/client.js`):
|
|
64
|
+
- 设置页「远程控制 → 远程访问密码」卡片:管理员本机设置 / 修改 / 清除密码;
|
|
65
|
+
- 远程(外网隧道 / HTTPS 反代)访问进入 DSH 页面时,弹出全屏密码验证页,输入正确密码方可使用;本机 / 局域网直连不受影响;
|
|
66
|
+
- 密码仅以 `scrypt` 哈希 + 随机盐存于本地 `~/.dsh/plugins/dsh-mobile-remote/config.json`,绝不落盘明文;`timingSafeEqual` 校验 + 登录失败次数限制防爆破;
|
|
67
|
+
- **完全本地、不依赖任何中转后端**(兼容自建 frp / 中转服务 / 其它中转方案);
|
|
68
|
+
- 新增 host API:`/__dsh_remote/auth-status`、`auth`、`logout`、`set-password`;`/__dsh_remote/*` 对远程未认证请求返回 401。
|
|
69
|
+
|
|
70
|
+
### 性能优化 / Performance
|
|
71
|
+
- **远程访问加载提速**:`lib/external.js` 为生成的 `frpc.toml` 注入 `poolCount`(默认 20,可用 `DSH_FRPC_POOL_COUNT` 覆盖),缓解 DSH 首屏大量并发请求触发 frpc “work connection pool is full” 导致的转圈/排队;
|
|
72
|
+
- 配套:服务端模板 `deploy/frps.toml` 调大 `transport.maxPoolCount` 到 64(部署后生效)。
|
|
73
|
+
|
|
74
|
+
## v1.1.0 (2026-08-19)
|
|
75
|
+
|
|
76
|
+
### 新增 / Added
|
|
77
|
+
- **设置页「远程控制」面板**(client half:`lib/client.js` 注册 `settings.section`):
|
|
78
|
+
- 连接二维码(host 端 `GET /__dsh_remote/qr` 生成 SVG)
|
|
79
|
+
- 开启 / 关闭开关(写入 / 移除 profile `cordis.patch.yml` 的 `webserver` 覆盖块,经 dsh HMR 热重载生效,无需重启)
|
|
80
|
+
- 当前连接的设备数量(移动端心跳上报,host 端活跃设备统计)
|
|
81
|
+
- **host 侧远程控制 API**(`lib/index.js`):`/__dsh_remote/status` / `toggle` / `heartbeat` / `qr`
|
|
82
|
+
- **命令行远程控制支持**:无需桌面端,官方 `dsh --profile web` 即可通过设置页开关或 `--patch` overlay 开启
|
|
83
|
+
- 内联 MIT QR 生成器(`lib/qrcode.js`),零运行时依赖
|
|
84
|
+
- 双语 README(README.md / README.zh.md)、RELEASE_NOTES.md
|
|
85
|
+
|
|
86
|
+
### 变更 / Changed
|
|
87
|
+
- `package.json`:新增 `dsh.client` 声明与 `./client` export;版本升至 1.1.0
|
|
88
|
+
|
|
89
|
+
## v1.0.0 (2026-08-19)
|
|
90
|
+
|
|
91
|
+
### 新增 / Added
|
|
92
|
+
- 初始版本:移动端输入栏窄屏适配(选择器换行分排、限宽防粘连、按钮触控目标 ≥ 40px)+ iOS 触屏优化(输入框 16px 防聚焦缩放)
|
|
93
|
+
- host 侧 `tapIndex` 注入移动端 CSS/JS,不破坏 DSH 原生 rail + 汉堡抽屉交互
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
# dsh-mobile-remote 📱
|
|
3
|
+
# DeepSeek Harness Mobile Remote Control (dsh-mobile-remote) 📱
|
|
4
4
|
|
|
5
|
-
[简体中文](./README.zh.md)
|
|
5
|
+
**English** · [简体中文](./README.zh.md)
|
|
6
6
|
|
|
7
|
-
[
|
|
7
|
+
[GitHub](https://github.com/feiyang-dev/dsh-mobile-remote) · [npm](https://www.npmjs.com/package/@feiyang666/dsh-mobile-remote) · MIT License
|
|
8
8
|
|
|
9
|
-
**A plugin for DeepSeek Harness
|
|
9
|
+
**A community plugin for DeepSeek Harness** — adds a built-in "Remote Control" page to the Web settings: connection QR code, one-click toggle, and live connected-device count. Access and control your desktop DeepSeek Harness from your phone over LAN, with mobile-first UI polish.
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+

|
|
13
|
+

|
|
10
14
|
|
|
11
15
|
</div>
|
|
12
16
|
|
|
@@ -14,102 +18,230 @@
|
|
|
14
18
|
|
|
15
19
|
## Overview
|
|
16
20
|
|
|
17
|
-
`dsh-mobile-remote`
|
|
21
|
+
`dsh-mobile-remote` is a DeepSeek Harness ecosystem **mobile remote-control plugin** (DSH plugin, Host + Client in one package). After installation, a management panel appears under **Settings → Remote Control** in the Web UI:
|
|
22
|
+
|
|
23
|
+
- **Connection QR code**: auto-generates a QR for `http://<lan-ip>:<port>` — scan it with your phone's camera / browser to connect.
|
|
24
|
+
- **On / Off toggle**: switches the webserver listen address (`0.0.0.0` ↔ `127.0.0.1`) with one click. Applied via dsh's official HMR hot-reload — **no service restart needed**.
|
|
25
|
+
- **Connected device count**: mobile heartbeats report online devices in real time.
|
|
26
|
+
- **Remote access password gate** (v1.2.0+): set a password locally; external-tunnel visitors must enter it before the page loads — local/LAN access stays password-free.
|
|
27
|
+
- **Faster remote loading** (v1.2.0+): larger frpc connection pool to stop the slow initial spinner over tunnels.
|
|
28
|
+
- **Rich telemetry** (v1.4.0): click any connected device to expand its full reported details (OS / browser / screen / viewport / DPR / device memory / CPU cores / battery / network / current page / first-seen / heartbeat count); a system-runtime card (uptime / boot time / Node version / PID / CPU model & cores / load average / memory usage / RSS / heap); a **DSH app-state card** (dsh version, session count, workspace list, installed plugins, model providers — cached in the background); per-interface network details (name / IP / mask / MAC); and external-tunnel details (domain / port / frpc version / PID / uptime / masked bind code / live log viewer).
|
|
29
|
+
- **Real external-tunnel status** (v1.4.1): no more fake "online" — the panel probes frpc's log to confirm the tunnel is really up, downgrades to "connecting" during reconnects, and shows a red **error card with the exact frpc reason** (e.g. `token in login doesn't match`) plus a one-click retry; FRP_TOKEN placeholder warnings from the relay show as a yellow banner; keep-alive heartbeats keep the relay's online state truthful.
|
|
30
|
+
- LAN address list, phone access URLs, and config location at a glance.
|
|
31
|
+
|
|
32
|
+
**Key selling point: pure CLI users don't need the desktop app.** The official CLI deliberately rejects `--host 0.0.0.0` for safety, but this plugin writes `webserver.host: 0.0.0.0` through the profile's `cordis.patch.yml` (or a `--patch <overlay>`) — exactly how the desktop app's "Mobile Remote Control" switch works. The phone and the computer share the same dsh backend process and the same `~/.dsh` data, so **sessions, history, workspace and settings are naturally two-way synced — no data copying involved**.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Remote Access Password (customizable / self-hostable)
|
|
37
|
+
|
|
38
|
+
To make **remote (external-tunnel) access** safer, the plugin ships a **remote access password gate**:
|
|
39
|
+
|
|
40
|
+
- In **Settings → Remote Control → "Remote Access Password"**, an admin sets / changes / clears a password **locally**;
|
|
41
|
+
- Once set, any browser reaching this DSH **through the external tunnel (`*.dsh.xxx.top`, HTTPS reverse-proxied)** is blocked by a full-screen password page and **must enter the correct password** to use it; local (`127.0.0.1`) and LAN-direct access are unaffected, so the admin can always log in locally to manage / repair;
|
|
42
|
+
- The password is stored **entirely locally** (`~/.dsh/plugins/dsh-mobile-remote/config.json`) as an **scrypt hash + random salt — never plaintext**, verified with `timingSafeEqual` (timing-attack safe) and rate-limited to prevent brute force.
|
|
43
|
+
|
|
44
|
+
> **Key design: fully local, decoupled from any relay backend.** Whether you use the bundled `dsh-update-server` relay or self-host any other frp / tunneling solution (including a different relay service), the password gate works directly — it applies to any "remote HTTPS access" and does not depend on your relay.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Backend (dsh-update-server) API
|
|
49
|
+
|
|
50
|
+
The plugin's external-tunnel status uses the relay server's **member-side** endpoints (no admin login):
|
|
51
|
+
|
|
52
|
+
- `GET /api/tunnel/status` — basic member status (name / online / port / last-seen).
|
|
53
|
+
- `GET /api/tunnel/stats` — **rich member tunnel stats** (added in this release, requires the relay server to be updated): same basic fields plus live **frps** proxy details — today's inbound/outbound traffic, current connection count, local forwarded port, and proxy start time.
|
|
54
|
+
|
|
55
|
+
The plugin tries `/stats` first and **falls back to `/status`** if the relay server hasn't been upgraded yet, so an outdated backend never breaks the panel.
|
|
56
|
+
|
|
57
|
+
> Deploy these updated files to your relay server (e.g. via `dsh-update-server` deployment): `src/routes/tunnel.js` and `src/tunnel-service.js`. Then restart the relay service.
|
|
58
|
+
|
|
59
|
+
## Remote Access Performance
|
|
18
60
|
|
|
19
|
-
|
|
61
|
+
A common reason remote (external-tunnel) access feels slower than LAN: DSH's first screen fires many concurrent requests (JS/CSS / API / WebSocket), while frp's default work-connection pool (`poolCount`) is too small, so frpc repeatedly logs `work connection pool is full, discarding` — connections get dropped, queued and retried, making the initial page spin for a long time.
|
|
20
62
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- **
|
|
63
|
+
This plugin optimizes it by:
|
|
64
|
+
|
|
65
|
+
- **Larger frpc pool**: it injects `poolCount = 20` into each `[[proxies]]` of the generated `frpc.toml` (override with env `DSH_FRPC_POOL_COUNT`);
|
|
66
|
+
- **Server-side match**: the `dsh-update-server` `deploy/frps.toml` template raises `transport.maxPoolCount` to `64` (takes effect after you deploy it to the relay server), so the server won't cap the client pool.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Screenshots
|
|
71
|
+
|
|
72
|
+
### Settings → Remote Control
|
|
73
|
+

|
|
74
|
+
|
|
75
|
+
## Recommended Installation
|
|
76
|
+
|
|
77
|
+
> Either method works and is equivalent. **We recommend the desktop app** — fully graphical, no command line needed.
|
|
78
|
+
|
|
79
|
+
### Option 1 (recommended): One-click via the desktop app
|
|
80
|
+
|
|
81
|
+
Install [DeepSeek Harness Desktop](https://github.com/feiyang-dev/DeepSeek-Harness-Desktop), open it, then go to **"Install Plugins" → Recommended → Mobile Remote Control → Install** and click **"Restart Service Now"** to activate.
|
|
82
|
+
|
|
83
|
+
### Option 2: Command line
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Prerequisite: install dsh (npm install -g @deepseek-ai/dsh)
|
|
87
|
+
dsh plugin --profile web add @feiyang666/dsh-mobile-remote
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Restart the dsh web service to activate.
|
|
91
|
+
|
|
92
|
+
---
|
|
24
93
|
|
|
25
|
-
|
|
94
|
+
## Usage
|
|
26
95
|
|
|
27
|
-
|
|
96
|
+
1. Start dsh (any way: desktop app / `npx @deepseek-ai/dsh web` / from source).
|
|
97
|
+
2. Open `http://127.0.0.1:3080` in a desktop browser → **Settings → Remote Control**.
|
|
98
|
+
3. Toggle the switch **ON** (hot-reloaded, no restart).
|
|
99
|
+
4. Put your phone and computer on the **same Wi-Fi**, **scan the QR** or open the LAN URL.
|
|
100
|
+
5. The phone now shows all desktop data — sessions, history, workspace, settings — and can send messages to control the desktop.
|
|
28
101
|
|
|
29
|
-
|
|
30
|
-
|---|---|
|
|
31
|
-
| **Remote-control settings page** | A new「远程控制」page in the Web settings: live switch state, bind host/port, session count, LAN IPv4 addresses, one-tap copy of the phone URL, QR code, connection test and usage guide |
|
|
32
|
-
| **Mobile UI adaptation** | On screens ≤768px: three-column layout collapses to a single column, the sidebar becomes a slide-in drawer with backdrop, touch targets are enlarged, double-tap zoom is disabled, iOS safe-area is respected |
|
|
33
|
-
| **Floating control dock** | Top-right floating buttons on phones: `☰` opens the session-list drawer anytime; the status dot shows connection state (green = connected over LAN, yellow = enabled but accessing locally, gray = off). Tap it to view and copy the phone address |
|
|
34
|
-
| **Status polling** | The dock queries the host every 15 seconds to keep sessions, addresses and connection state fresh |
|
|
35
|
-
| **Model tool** | Registers `mobile_remote_status` so the model can query remote-control status and phone URLs directly |
|
|
36
|
-
| **Host JSON API** | `POST /api/dsh-mobile-remote`: `status` (full snapshot) / `ping` (heartbeat) |
|
|
102
|
+
### Pure CLI startup (no desktop app)
|
|
37
103
|
|
|
38
|
-
|
|
104
|
+
```bash
|
|
105
|
+
# Way 1: use the settings-page toggle (recommended)
|
|
106
|
+
dsh --profile web
|
|
107
|
+
# then open http://127.0.0.1:3080 → Settings → Remote Control → ON
|
|
39
108
|
|
|
109
|
+
# Way 2: manual overlay
|
|
110
|
+
dsh --profile web --patch remote-control.patch.yml
|
|
40
111
|
```
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
112
|
+
|
|
113
|
+
`remote-control.patch.yml`:
|
|
114
|
+
|
|
115
|
+
```yaml
|
|
116
|
+
- id: webserver
|
|
117
|
+
config:
|
|
118
|
+
host: '0.0.0.0'
|
|
119
|
+
port: !!js ctx.webStartup.port ?? 3080
|
|
46
120
|
```
|
|
47
121
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
122
|
+
> **Security note**: enabling remote control exposes the service to your LAN. Use it only on trusted home / office networks — **do not expose it to the public internet**.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## What This Package Is
|
|
127
|
+
|
|
128
|
+
One npm package = **host half** (Node-side Cordis plugin: `/__dsh_remote/*` API, patch-file management, heartbeat device counting, index.html injection — see `lib/index.js`) + **client half** (browser settings panel — see `lib/client.js`, talking to the host via `/__dsh_remote/status` etc.).
|
|
129
|
+
|
|
130
|
+
It plugs into DSH through two declarations:
|
|
131
|
+
|
|
132
|
+
| Declaration | Purpose |
|
|
133
|
+
| --- | --- |
|
|
134
|
+
| `dsh.bundle.patch` (`cordis.patch.yml`) | Lets DSH treat it as a **standard bundle plugin package**: `dsh plugin --profile <name> add <pkg>` installs and wires it in one command |
|
|
135
|
+
| `dsh.client` + `exports["./client"]` | Lets the web client auto-load the settings panel at `/plugins/<pkg>/client.js` |
|
|
136
|
+
|
|
137
|
+
So for users, **installing is one command** — no YAML editing, no manual file copying.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## How It Works
|
|
142
|
+
|
|
143
|
+
| Layer | File | Responsibility |
|
|
144
|
+
| --- | --- | --- |
|
|
145
|
+
| host | `lib/index.js` | `/__dsh_remote/status` / `toggle` / `heartbeat` / `qr` API; patch-file read/write; heartbeat device counting; index.html injection |
|
|
146
|
+
| client | `lib/client.js` | Registers the `settings.section` "Remote Control" panel (toggle / QR / device count) |
|
|
147
|
+
| qrcode | `lib/qrcode.js` | Inlined MIT QR generator (`qrcode-generator`), zero runtime deps |
|
|
148
|
+
|
|
149
|
+
- **Toggle**: `POST /__dsh_remote/toggle` → writes/removes a `webserver` override block in the profile's `cordis.patch.yml` → dsh's `watchUserPatches` (Cordis HMR) hot-reloads the webserver entry to re-listen.
|
|
150
|
+
- **Device count**: mobile-injected JS heartbeats every 30s; the host keeps an active-device map (90s TTL). Each heartbeat now reports full device metadata (screen / viewport / DPR / network / current page / language / platform), shown in the expandable device rows of the settings panel.
|
|
151
|
+
- **QR code**: `GET /__dsh_remote/qr?url=...` returns SVG.
|
|
152
|
+
- **Mobile polish**: `tapIndex` injects mobile CSS/JS — composer toolbar wraps on narrow screens, selects get width-capped, iOS inputs get 16px to prevent focus zoom; **DSH's native rail + hamburger drawer interactions are untouched**.
|
|
153
|
+
|
|
154
|
+
---
|
|
51
155
|
|
|
52
|
-
##
|
|
156
|
+
## Installation (for users)
|
|
53
157
|
|
|
54
|
-
###
|
|
158
|
+
### 0. Prerequisites
|
|
55
159
|
|
|
56
|
-
|
|
160
|
+
- DeepSeek Harness installed (`npm install -g @deepseek-ai/dsh` globally, or via the desktop app / `npx @deepseek-ai/dsh web`).
|
|
161
|
+
- `dsh` on your PATH (use the desktop app's own terminal if it manages its environment).
|
|
57
162
|
|
|
58
|
-
###
|
|
163
|
+
### 1. One-command install
|
|
59
164
|
|
|
60
165
|
```bash
|
|
61
|
-
# Requires dsh (npm install -g @deepseek-ai/dsh)
|
|
62
166
|
dsh plugin --profile web add @feiyang666/dsh-mobile-remote
|
|
63
167
|
```
|
|
64
168
|
|
|
65
|
-
|
|
169
|
+
This command does three things automatically:
|
|
66
170
|
|
|
67
|
-
1.
|
|
68
|
-
2.
|
|
69
|
-
3.
|
|
70
|
-
4. **Start controlling**: the phone shows the exact same interface as the desktop. Use `☰` anytime to open the session drawer; tap the status dot to check the connection.
|
|
171
|
+
1. Installs the package into `~/.dsh/profiles/web` via pnpm (initializes the profile on first use);
|
|
172
|
+
2. Detects the `dsh.bundle` declaration and registers the package in the profile's `dsh.profile.bundles`;
|
|
173
|
+
3. After restart, DSH reads the package's `cordis.patch.yml` and mounts the plugin entry into the app tree — **no manual config editing**.
|
|
71
174
|
|
|
72
|
-
|
|
175
|
+
The same works for other profiles — replace `web` with your profile name.
|
|
73
176
|
|
|
74
|
-
|
|
177
|
+
> Local tarball testing: `dsh plugin --profile web add C:\path\to\feiyang666-dsh-mobile-remote-1.4.1.tgz`
|
|
75
178
|
|
|
76
|
-
|
|
179
|
+
### 2. Restart and verify
|
|
77
180
|
|
|
78
|
-
|
|
181
|
+
Restart the dsh web app (CLI: stop the old process and run `dsh web` again; desktop: fully quit and reopen). Then:
|
|
79
182
|
|
|
80
|
-
|
|
81
|
-
|---|---|---|
|
|
82
|
-
| `enabled` | boolean | Whether remote control is active (listening on a non-loopback address) |
|
|
83
|
-
| `host` | string | Actual bind host (e.g. `0.0.0.0`) |
|
|
84
|
-
| `port` | number | Actual listen port (e.g. `3080`) |
|
|
85
|
-
| `lanAddresses` | string[] | LAN IPv4 addresses of the desktop |
|
|
86
|
-
| `urls` | string[] | Phone-accessible URLs (`http://<ip>:<port>`) |
|
|
87
|
-
| `sessionCount` | number | Current session count |
|
|
88
|
-
| `serverTime` / `serverTimeIso` | number / string | Server time (clock sync / heartbeat) |
|
|
89
|
-
| `pid` / `workspace` | number / string | Process PID and working directory |
|
|
183
|
+
- Refresh http://127.0.0.1:3080 → Settings → the **"Remote Control"** panel should appear.
|
|
90
184
|
|
|
91
|
-
|
|
185
|
+
---
|
|
92
186
|
|
|
93
|
-
|
|
187
|
+
## Uninstall
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
dsh plugin --profile web remove @feiyang666/dsh-mobile-remote
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Then restart the app.
|
|
194
|
+
|
|
195
|
+
---
|
|
94
196
|
|
|
95
197
|
## FAQ
|
|
96
198
|
|
|
97
|
-
|
|
199
|
+
| Symptom | Cause / Fix |
|
|
200
|
+
| --- | --- |
|
|
201
|
+
| No "Remote Control" panel in Settings | Plugin not activated. Check the `cordis.patch.yml` row exists with the right `name`; restart and hard-refresh |
|
|
202
|
+
| Phone still can't connect after toggling ON | Same Wi-Fi? Firewall allowing port 3080? Accessing the LAN IP (not `127.0.0.1`)? |
|
|
203
|
+
| Phone connects but shows 403 | dsh's trust fence: make sure the plugin is installed and dsh is started the supported way (`--patch` / profile patch overriding `webserver.host`) |
|
|
204
|
+
| Device count stays 0 | The phone page must be opened once to start heartbeat; wait a few seconds and refresh |
|
|
205
|
+
| QR won't scan | Confirm Remote Control is ON; use a camera app that supports QR |
|
|
206
|
+
| External access blocked by a full-screen password page | That's the **remote access password gate** (v1.2.0+). Enter the correct password set locally under Settings → Remote Control → Remote Access Password; if forgotten, reset it on the host machine |
|
|
207
|
+
| Remote loading still spins for a long time | Make sure the relay server's frps has `transport.maxPoolCount = 64` applied (`deploy/frps.toml`) and restart frps; re-enable external access once to rebuild the tunnel (`DSH_FRPC_POOL_COUNT` defaults to 20) |
|
|
208
|
+
| Panel shows a red **"外网隧道鉴权失败"** error | frpc's `auth.token` doesn't match the frps server's `auth.token`. Sync the relay `.env`'s `FRP_TOKEN` with `/www/server/frps/frps.toml`'s `auth.token`, restart frps + the relay service, then toggle external access off and on |
|
|
209
|
+
| External tunnel shows **"连接中"** but never turns online | frpc is retrying after a disconnect; open the panel's **查看 frpc 日志** to see the exact reason (server down / port blocked / token mismatch) |
|
|
210
|
+
| A yellow banner warns **FRP_TOKEN 仍是占位符** | The relay `.env` still uses a placeholder `FRP_TOKEN`; it must be replaced with the real value matching frps.toml or the tunnel can never come up (502) |
|
|
98
211
|
|
|
99
|
-
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Related Projects
|
|
215
|
+
|
|
216
|
+
| Project | Description | Installation |
|
|
217
|
+
| --- | --- | --- |
|
|
218
|
+
| [DeepSeek Harness Desktop](https://github.com/feiyang-dev/DeepSeek-Harness-Desktop) | Windows desktop console: install/start/stop/restart the dsh web service with one click, built-in plugin management — **install this plugin from its Recommended section** | Download the desktop app and click a few buttons |
|
|
219
|
+
| [Usage & Cost Tracker (dsh-usage-plugin)](https://github.com/feiyang-dev/dsh-usage-plugin) | Per-call token/cache-hit stats, peak/off-peak billing, balance query, CSV/JSON/PNG export | One-click from the desktop app, or `dsh plugin add @feiyang666/dsh-usage-plugin` |
|
|
220
|
+
| [Data Vault (dsh-vault)](https://github.com/feiyang-dev/dsh-vault) | Auto-backup, wipe detection, one-click restore for chat history and workspace data | One-click from the desktop app, or `dsh plugin add @feiyang666/dsh-vault` |
|
|
221
|
+
| [DeepSeek-Harness](https://github.com/deepseek-ai/DeepSeek-Harness) | Official CLI / Web service | Quick start below |
|
|
222
|
+
|
|
223
|
+
### Running DeepSeek Harness
|
|
100
224
|
|
|
101
|
-
**
|
|
225
|
+
**Quick start (via npm)**
|
|
102
226
|
|
|
103
|
-
|
|
227
|
+
Install Node.js, then run:
|
|
104
228
|
|
|
105
|
-
|
|
229
|
+
```bash
|
|
230
|
+
npx @deepseek-ai/dsh web
|
|
231
|
+
```
|
|
106
232
|
|
|
107
|
-
|
|
233
|
+
This starts the Web UI at http://127.0.0.1:3080 by default. See the [Web UI Guide](https://github.com/deepseek-ai/DeepSeek-Harness).
|
|
108
234
|
|
|
109
|
-
**
|
|
235
|
+
**Run from source**
|
|
110
236
|
|
|
111
|
-
|
|
237
|
+
```bash
|
|
238
|
+
git clone https://github.com/deepseek-ai/deepseek-harness.git
|
|
239
|
+
cd deepseek-harness
|
|
240
|
+
pnpm install
|
|
241
|
+
pnpm run build
|
|
242
|
+
pnpm dsh web
|
|
243
|
+
```
|
|
112
244
|
|
|
113
245
|
## License
|
|
114
246
|
|
|
115
|
-
|
|
247
|
+
MIT © dsh-mobile-remote
|