@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 CHANGED
@@ -1,21 +1,93 @@
1
- # Changelog
1
+ # 更新日志 / Changelog
2
2
 
3
- ## [1.0.1] - 2026-08-19
3
+ ## v1.4.1 (2026-08-20)
4
4
 
5
- ### 修复(Fixed)
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
- - **修复 client bundle 加载失败导致移动端适配不生效**:`package.json` 的 `dsh.client.inject` 中误声明了 `@deepseek-ai/dsh-client-ui-slots`(该包是纯类型契约包,无 `dsh.client` 声明与 `./client` 入口,不是合法的 client 加载条目)。这会导致 client loader 无法为该插件创建 fiber,整个浏览器端代码(移动端适配 CSS、浮动控制条、设置页)被丢弃。已移除该无效依赖,仅保留 `@deepseek-ai/dsh-client-ui-layout`。
8
- - Host 端 `/api/dsh-mobile-remote` 不受影响(已验证 HTTP 200、`0.0.0.0:3080` 监听、64 个会话可见)。
15
+ ### 修复 / Fixed
16
+ - **设置页空白崩溃**:修复 `status` 首次渲染为 `null` 时,`status.external...` 无守卫导致的 `Cannot read properties of null` 崩溃(面板内容区被错误边界吞成空白);同时加固 `extErrText` 的完整守卫。
17
+ - 外网状态不再被 `/status` 覆盖为假在线(`externalView` 直接透传真实状态)。
9
18
 
10
- ## [1.0.0] - 2026-08-19
19
+ ### 变更 / Changed
20
+ - `lib/client.js`:外网隧道卡新增 frpc 进程 PID / 已运行时长 / 脱敏绑定码展示。
21
+ - 依赖后端 `dsh-update-server` 同步升级(成员端在线判定 / `/stats` / `heartbeat` 离线支持),旧后端自动回退兼容。
11
22
 
12
- ### 新增(Added)
23
+ ## v1.4.0 (2026-08-20)
13
24
 
14
- - 初始版本:手机端远程控制 DeepSeek Harness。
15
- - Host 半:`/api/dsh-mobile-remote` JSON API(status / ping)、局域网 IPv4 枚举、`mobile_remote_status` 模型工具。
16
- - Client 半:
17
- - 设置页「远程控制」:开关状态、监听地址/端口、会话数、手机访问地址(一键复制)、二维码、连接测试、使用说明。
18
- - 移动端界面适配(≤768px):单列布局、侧栏抽屉化(滑入滑出 + 遮罩)、触控优化、iOS 安全区。
19
- - 浮动控制条(shell.overlay):会话列表抽屉开关 + 远程连接状态指示,每 15 秒轮询状态。
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
- [1.0.0]: https://github.com/feiyang-dev/dsh-mobile-remote/releases/tag/v1.0.0
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
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 feiyang-dev
3
+ Copyright (c) 2026 dsh-mobile-remote contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
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) | **English**
5
+ **English** · [简体中文](./README.zh.md)
6
6
 
7
- [MIT License](./LICENSE)
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 that lets your phone sync with and remotely control your desktop**, with full two-way synchronization of conversations, session lists and settings, plus mobile-optimized UI.
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
+ ![License](https://img.shields.io/badge/license-MIT-blue.svg)
12
+ ![Node](https://img.shields.io/badge/node-%3E%3D18-339933)
13
+ ![Platform](https://img.shields.io/badge/platform-web%20%26%20desktop-4d9fff)
10
14
 
11
15
  </div>
12
16
 
@@ -14,102 +18,230 @@
14
18
 
15
19
  ## Overview
16
20
 
17
- `dsh-mobile-remote` builds on the built-in **「移动端远程控制」 (mobile remote control)** switch of the DeepSeek Harness desktop app (`dsh-desktop`). When enabled, the dsh web service listens on all interfaces (`0.0.0.0`), so any phone on the same Wi-Fi can open the desktop's LAN address in a browser and use **the very same Web UI**.
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
- Because the phone and the desktop access the same session data:
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
- - **Real-time two-way sync**: conversations, session list, settings — everything stays consistent. An action on either side shows up on the other instantly;
22
- - **Full control from your phone**: send messages, switch sessions, inspect details, manage settings — everything the desktop can do, the phone can do;
23
- - **Mobile UI adaptation**: this plugin optimizes touch targets and layout for phone screens.
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
+ ![Remote Control](./docs/assets/remote-control.png)
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
- npm package: `@feiyang666/dsh-mobile-remote` (same series as `@feiyang666/dsh-usage-plugin` and `@feiyang666/dsh-vault`).
94
+ ## Usage
26
95
 
27
- ## Features
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
- | Capability | Description |
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
- ## How it works
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
- ┌─────────────┐ same Wi-Fi ┌──────────────────────────┐
42
- │ Phone browser │ ──────────▶ │ dsh web (desktop, :3080) │
43
- │ (mobile UI) │ http://LAN │ - the same Web UI │
44
- │ ☰ drawer/FAB │ ◀────────── │ - the same session data │
45
- └─────────────┘ two-way sync └──────────────────────────┘
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
- - The phone and the desktop access the **same web app and the same `~/.dsh` session data**, so synchronization is inherent and real-time (no intermediate layer, no copying);
49
- - The dsh-desktop switch makes the service listen on `0.0.0.0` via an overlay config (only the listen address changes; the desktop itself still uses `127.0.0.1`);
50
- - This plugin adds what is missing: mobile UI adaptation, a setup/guide settings page, and connection-status indicators.
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
- ## Install
156
+ ## Installation (for users)
53
157
 
54
- ### Option 1: dsh-desktop (recommended)
158
+ ### 0. Prerequisites
55
159
 
56
- Install [DeepSeek Harness 桌面版](https://github.com/feiyang-dev/DeepSeek-Harness-Desktop), open **「安装插件」→ recommended plugins → 手机端远程控制 → 一键安装**, then click **「立即重启服务」**.
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
- ### Option 2: command line
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
- ## Usage
169
+ This command does three things automatically:
66
170
 
67
- 1. **Enable remote control**: open dsh-desktop settings, turn on **「移动端远程控制」**, restart the service;
68
- 2. **Get the phone URL**: open the Web UI → Settings → **「远程控制」**, copy any「手机访问地址」or scan the QR code;
69
- 3. **Open on your phone**: make sure the phone and desktop are on the **same Wi-Fi**, then open the address in the phone browser;
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
- > Phone URLs look like `http://192.168.x.x:3080`. If the page says「not enabled」, make sure the dsh-desktop switch is on and the service has been restarted.
175
+ The same works for other profiles — replace `web` with your profile name.
73
176
 
74
- ## API reference
177
+ > Local tarball testing: `dsh plugin --profile web add C:\path\to\feiyang666-dsh-mobile-remote-1.4.1.tgz`
75
178
 
76
- `POST /api/dsh-mobile-remote` with body `{ "action": "status" | "ping" }`.
179
+ ### 2. Restart and verify
77
180
 
78
- ### status
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
- | Field | Type | Description |
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
- ### ping
185
+ ---
92
186
 
93
- Returns `{ ok: true, serverTime, serverTimeIso }` for link probing.
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
- **Q: The phone cannot open the desktop address?**
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
- A: Make sure ① the phone and desktop are on the same Wi-Fi/LAN segment; ② the dsh-desktop「移动端远程控制」switch is on and the service has **been restarted**; ③ the firewall allows the dsh port.
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
- **Q: Does the phone need a dedicated app?**
225
+ **Quick start (via npm)**
102
226
 
103
- A: No. Any mobile browser works, nothing to install.
227
+ Install Node.js, then run:
104
228
 
105
- **Q: Does enabling remote control affect desktop usage?**
229
+ ```bash
230
+ npx @deepseek-ai/dsh web
231
+ ```
106
232
 
107
- A: No. dsh-desktop's health checks, main window and logs still use `127.0.0.1`; only the LAN listening is added.
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
- **Q: Is the phone data the same as the desktop?**
235
+ **Run from source**
110
236
 
111
- A: Yes, and it stays in sync in real time. The phone and desktop share one service and one set of session data, with no intermediate sync layer.
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
- [MIT](./LICENSE)
247
+ MIT © dsh-mobile-remote