@yezack/dsh-remote-mobile 0.0.0-stage → 1.9.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/README.md CHANGED
@@ -1,3 +1,455 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
1
+ <div align="center">
2
+
3
+ # dsh-remote-mobile
4
+
5
+ **DeepSeek Harness (DSH) 远程与移动端安全网关插件**
6
+
7
+ [![npm version](https://img.shields.io/npm/v/dsh-remote-mobile.svg?style=flat-square&color=3b82f6)](https://www.npmjs.com/package/dsh-remote-mobile)
8
+ [![npm downloads](https://img.shields.io/npm/dm/dsh-remote-mobile.svg?style=flat-square&color=22c55e)](https://www.npmjs.com/package/dsh-remote-mobile)
9
+ [![node](https://img.shields.io/badge/node-%3E%3D18.0.0-8b5cf6?style=flat-square)](https://nodejs.org)
10
+ [![license](https://img.shields.io/npm/l/dsh-remote-mobile.svg?style=flat-square&color=10b981)](https://github.com/IceApriler/dsh-remote-mobile/blob/master/LICENSE)
11
+ [![DSH](https://img.shields.io/badge/DSH-Web%20Profile-0ea5e9?style=flat-square)](https://github.com/IceApriler/dsh-remote-mobile)
12
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/IceApriler/dsh-remote-mobile/pulls)
13
+
14
+ <p align="center">
15
+ <b>零改动底层代码 · 局域网 / Tailscale 安全接入 · 扫码配对 · 移动端样式适配 · 工作区能力复用 · 实时状态推送</b>
16
+ </p>
17
+
18
+ <p align="center">
19
+ 📱 <b>桌面级移动工作台</b>:手机上也能新建 / 切换工作区、执行终端命令<br>
20
+ 🛡️ <b>多重安全认证</b>:扫码配对 · 长期密码 · 免密直连 + RSA 加密 + 防爆破封禁<br>
21
+ 🎨 <b>移动端样式片段</b>:内置三段预设,不满意可自定义 CSS
22
+ </p>
23
+
24
+ [English Documentation](./README_EN.md) · [简体中文](./README.md)
25
+
26
+ <p align="center">
27
+ <a href="#about">这是什么</a> •
28
+ <a href="#advantages">核心优势</a> •
29
+ <a href="#quick-start">快速开始</a> •
30
+ <a href="#config">必备配置</a> •
31
+ <a href="#preview">界面预览</a> •
32
+ <a href="#features">功能特性</a> •
33
+ <a href="#install">安装与更新</a> •
34
+ <a href="#advanced">高级配置</a> •
35
+ <a href="#storage">本地文件存储</a> •
36
+ <a href="#faq">常见问题</a>
37
+ </p>
38
+
39
+ ---
40
+
41
+ </div>
42
+
43
+ <span id="about"></span>
44
+ ## 📖 这是什么
45
+
46
+ `dsh-remote-mobile` 是专为 **DeepSeek Harness (DSH)** 深度定制的远程与移动端安全治理插件。
47
+
48
+ DSH 核心服务出于安全考虑默认仅监听本地回环地址(`127.0.0.1`),手机、平板或其他电脑无法从外部访问 Web 控制台。本项目通过**访问控制中间件**与**请求隔离技术**,安全地开放了 **Tailscale 虚拟私网** 以及 **本地局域网 (Wi-Fi/LAN)** 访问能力,并提供传输加密、扫码配对、长期密码认证与防暴力破解审计体系。
49
+
50
+ 手机端访问时,插件还针对 DSH 界面做了**移动端样式适配**:侧边栏抽屉折叠与可拖拽展开把手、新版官方三栏 Grid 布局与右侧边栏兼容、设置弹窗居中微缩、对话正文高密度排版等,让手机上的使用体验更贴近桌面端。
51
+
52
+ ---
53
+
54
+ <span id="advantages"></span>
55
+ ## ⚡ 核心优势
56
+
57
+ * 🚀 **突破网络壁垒,复用桌面端能力**:用于在局域网 / Tailscale 下访问 DSH Web。在移动端或外部设备访问时,**支持新建工作区、切换工作区、执行终端命令等常用桌面端操作**。
58
+ * 📱 **手机端专属适配与同源复用**:直接复用 DSH 官方 Web 前端(手机与桌面是同一套界面)与各类生态插件(如侧边栏、任务看板、终端面板等),无需单独维护手机端后台。插件已针对移动端做好了基础响应式适配(如侧边栏抽屉折叠、设置弹窗居中、对话正文字号与行距精细调小以提升一屏信息量),并内置**样式片段覆写功能**,支持开箱即用或按需注入自定义 CSS 样式小插件。
59
+ * 🛡️ **安全门禁与传输加密**:内置 RSA 非对称公钥加密、`scrypt` 加盐慢哈希密码落盘、连续输错自动熔断锁定 IP,拦截公网/局域网未经授权的访问。
60
+ * 📲 **扫码快速配对**:自动识别并生成 Tailscale CGNAT 与局域网专属访问链接与二维码,手机扫码即可完成长效授权。
61
+ * 🔄 **SSE 实时状态推送**:设备上线、下线、注销、IP 锁定等安全事件即时推送,无需前端轮询。
62
+ * 🤝 **插件通用共存保护**:与其他远程/Web 接入类插件并存时自动让出共享服务、保证正常启动,设置页提供冲突警示横幅与一键复制的「诊断与修复报告」。
63
+
64
+ ---
65
+
66
+ <span id="quick-start"></span>
67
+ ## 🚀 快速开始
68
+
69
+ ### 1. 一键安装插件
70
+
71
+ 在终端执行 DSH 官方插件安装指令(推荐):
72
+
73
+ ```bash
74
+ dsh plugin --profile web add dsh-remote-mobile
75
+ ```
76
+
77
+ > [!IMPORTANT]
78
+ > **生态插件安装建议**:**不建议安装 `@linxin666/dsh-web-all` 全家桶**,更推荐**按需安装单体功能插件**。全家桶将多个前端模块合并打包,可能引发移动端悬浮入口重复与手势交互冲突;如需任务看板、宠物等生态功能,建议直接安装对应的单体包(原因、推荐命令与共存说明见 [常见问题 Q6](#faq))。
79
+
80
+ ---
81
+
82
+ <span id="config"></span>
83
+ ### 2. 前置配置(开放外部监听)
84
+
85
+ 由于 DSH 默认仅监听 `127.0.0.1`,为了使 Tailscale 私网或局域网设备能够正常连通,请确保在 `~/.dsh/profiles/web/cordis.patch.yml`(Windows 对应 `C:\Users\<用户名>\.dsh\profiles\web\cordis.patch.yml` 或在资源管理器直接输入 `%USERPROFILE%\.dsh`)中包含以下配置:
86
+
87
+ ```yaml
88
+ # 1. 允许 webserver 监听外部网络连接(必选)
89
+ - id: webserver
90
+ name: '@deepseek-ai/dsh-host-webserver'
91
+ inject: [webStartup]
92
+ config:
93
+ host: '0.0.0.0'
94
+ port: 3080
95
+
96
+ # 2. (推荐)只保留一款远程/Web 接入类插件,避免功能重复与入口混乱
97
+ # 本插件与其他远程接入类插件共存时也能正常启动:检测到配对共享服务被占用
98
+ # 会自动让出,并在设置页顶部展示警示横幅说明详情。
99
+ # 示例:禁用 @linxin666/dsh-web-ui-all 内置的远程插件
100
+ - id: web-ui-remote-web-ui
101
+ disabled: true
102
+ ```
103
+
104
+ > **💡 说明**:插件自身注册已由 DSH Bundle 体系全自动处理,**无需**在 `cordis.patch.yml` 中额外添加 `id: remote-mobile`。Windows 用户可按 `Win + R` 键输入 `%USERPROFILE%\.dsh\profiles\web` 快速直达配置目录。
105
+
106
+ > [!WARNING]
107
+ > **不建议安装聚合全家桶(`@linxin666/dsh-web-all`)**:它会把多个子插件的前端逻辑合并打包到同一个 `client.js` 中,加载时自执行,可能与本插件产生移动端入口重复与手势冲突。推荐**按需安装所需单体插件**(如任务看板、宠物等)。完整原因、推荐命令与共存说明见 [常见问题 Q6](#faq)。
108
+
109
+ ---
110
+
111
+ ### 3. 启动并使用
112
+
113
+ ```bash
114
+ dsh web --no-open
115
+ ```
116
+
117
+ 启动后,在电脑浏览器打开 DSH Web 控制台,进入 **设置 ⚙️ -> 远程与移动端**,使用手机微信或系统相机扫描二维码即可立即开启移动端接入!
118
+
119
+ > 设置面板按 **「接入 / 设备与安全 / 样式覆写 / 本地数据」** 四个页签分组显示,避免长页面;页签选择会被记住,切换不重置配对码等状态。
120
+
121
+ ---
122
+
123
+ <span id="preview"></span>
124
+ ## 🖼️ 界面预览
125
+
126
+ ### PC 端 DSH 插件控制面板
127
+
128
+ | 网络接入与扫码配对 | 设备与安全 |
129
+ | :---: | :---: |
130
+ | ![PC 设置面板 - 网络接入与扫码配对](images/pc-dsh-setting-1.png) | ![PC 设置面板 - 设备与安全](images/pc-dsh-setting-2.png) |
131
+ | **样式片段覆写** | **本地数据存储** |
132
+ | ![PC 设置面板 - 样式片段覆写](images/pc-dsh-setting-3.png) | ![PC 设置面板 - 本地数据存储](images/pc-dsh-setting-4.png) |
133
+
134
+ ---
135
+
136
+ ### 手机端实机演示(同源免登与工作区能力)
137
+
138
+ | 登录 | 对话列表字号缩放 | 侧边栏移动端样式 | 官方轨迹查看 |
139
+ | :---: | :---: | :---: | :---: |
140
+ | ![登录](images/mobile-auth.jpg) | ![对话列表字号缩放](images/mobile-dsh-1.jpg) | ![侧边栏移动端样式](images/mobile-dsh-2.jpg) | ![官方轨迹查看](images/mobile-dsh-3.jpg) |
141
+
142
+ ---
143
+
144
+ <span id="features"></span>
145
+ ## 🌟 功能特性
146
+
147
+ ### 1. 网络接入支持
148
+ - **Tailscale 虚拟私网**:自动识别本机 Tailscale IP(`100.64.0.0/10` CGNAT 网段),生成专属访问二维码,支持开启免密直连(底层传输加密由 Tailscale WireGuard 隧道保障)。
149
+ - **本地局域网 (LAN / Wi-Fi)**:自动识别 RFC 1918 私有 IP(如 `192.168.x.x`、`10.x.x.x`、`172.16-31.x.x`),提供局域网专属二维码与直达链接预览,附带醒目的高危风险提示。
150
+ - **二维码快速配对**:支持手机相机或微信扫码直达授权页面。
151
+
152
+ ### 2. 多重认证机制
153
+ - **动态 6 位配对码**:生成 6 位短期配对码(5 分钟有效,一次性使用),手机端扫码输入后换取 365 天有效期的安全认证 Cookie。
154
+ - **长期访问密码**:支持设置自定义长期访问密码(长度需至少 6 位且含字母与数字),便于多设备长期固定登录。
155
+ - **免密直连模式**:可针对 Tailscale 或局域网环境单独切换免密直连。关闭免密直连后会自动清理临时设备凭证并重置状态。
156
+ - **设备会话管理**:实时查看已连接设备的类型、操作系统、浏览器、来源 IP 及最近活跃时间,支持单设备注销与一键注销全部设备。
157
+
158
+ ### 3. 安全防护
159
+ - **传输层 RSA 非对称加密**:登录认证接口在客户端即完成 RSA 加密,敏感密码与配对码加密后才经网络传输。
160
+ - **HTTPS 等安全上下文**:优先使用 Web Crypto 原生 `RSA-OAEP-SHA256`;
161
+ - **DSH 默认的 HTTP 局域网 / Tailscale 访问(非安全上下文)**:回退至纯 JS 垫片,并使用 `crypto.getRandomValues()` 做密码学安全随机数填充。
162
+ - **scrypt 慢哈希存储**:服务端采用 `scrypt` 加盐慢哈希算法(`scrypt:${salt}:${hash}`)对密码进行落盘存储,比对过程采用 `crypto.timingSafeEqual` 恒定时间比较以防范时序侧信道攻击。
163
+ - **防暴力破解与限频保护**:
164
+ - 连续输错凭证达到阈值(默认 5 次)自动锁定该 IP 15 分钟,拦截后续验证请求并返回 HTTP 429;
165
+ - 滑动窗口限频(默认 60 次/分钟),防范高频恶意刷量探测;
166
+ - 访问审计与锁定状态持久化落盘,服务重启后自动恢复;
167
+ - 支持管理员在管理面板中一键解锁指定 IP。
168
+ - **智能静态资源放行机制**:安全门禁内置智能前端静态扩展名识别(放行 `.js`、`.css`、`.png`、`.svg`、`.woff2` 等 20 种合法资源),拦截无扩展名或动态管理 API 请求(如 `/plugins/xxx/admin`),确保第三方生态插件前端正常展示的同时严密保护后台动态接口,无需用户在设置界面手动维护白名单。(DSH 核心静态目录 `/assets/` 属官方资源,单独无条件放行。)
169
+ - **高可靠原子持久化与防抖**:采用毫秒级写盘防抖节流保护磁盘 I/O(会话数据 500ms、样式片段 300ms),配合 `beforeExit` 进程退出 Flush 保证数据不丢失;`settings.json` 与 `style-snippets.json` 采用临时文件原子替换(`renameSync`),防止异常中断损坏数据。
170
+ - **真实 IP 安全提取**:仅信任底层 Socket 真实连接地址,防范伪造的 `X-Forwarded-For` 欺骗攻击。
171
+ - **本机回环 CSRF 防御**:插件的变更类 API 会校验浏览器同源信号(`Origin` / `Sec-Fetch-Site`),恶意网页驱使浏览器向 `127.0.0.1` 发起的跨站写请求将被直接拒绝;curl / 本机脚本等无浏览器信号的客户端不受影响。
172
+ - **本机回环请求不做上下文改写**:上下文虚拟化仅作用于外部来源流量;本机回环请求保留原始 Host / Origin(不"洗白"),使 DSH 自带的 DNS-Rebinding 与同源校验对外部域名继续生效。SSE 事件流仅限同源连接,不开放跨域读取。
173
+
174
+ ### 4. 实时状态同步与国际化
175
+ - **SSE 实时事件推送**:基于 Server-Sent Events 实现新设备接入、设备重连、会话撤销及安全告警的实时通知,内置连接双向关闭监听与幂等清理。
176
+ - **全界面中英文双语自适应**:根据 DSH 全局语言偏好与浏览器环境,动态自适应中英文面板、提示及手机端界面。
177
+ - **非 HTTPS 兼容补丁**:自动注入 `crypto.randomUUID` 与 `navigator.clipboard` Polyfill,解决移动端浏览器在 HTTP 非安全上下文下缺少原生 API 的报错(`clipboard` polyfill 保证非安全上下文下复制/样式复制功能正常)。
178
+
179
+ ### 5. 移动端样式片段(样式小插件)
180
+
181
+ DSH Web 界面在手机上仍有不少沿袭桌面端的样式问题,插件内置「移动端样式片段」模块,把移动端适配拆分为可独立启停的 CSS 片段:
182
+
183
+ - **按界面区域划分的三段内置预设**(默认移动端启用、PC 关闭):
184
+ - `preset-sidebar` **侧边栏抽屉导航**:折叠时侧边栏 0 宽度占用、可拖拽悬浮把手、自适应抽屉宽度、44px 触控友好区;
185
+ - `preset-settings` **设置面板适配**:上下堆叠自适应、顶部导航横滑、内容纵向自然滚览;
186
+ - `preset-main` **对话正文高密度排版**:小字号 12.5px + 紧凑行距 + 收紧边距,每行展示更多内容;基于稳定 HTML 元素与 localName 后缀,不做布局缩放,无右侧留白;
187
+ - **PC / 移动端分别启停(按视口宽度判定,与设备无关)**:每段预设和每个自定义片段都有独立的「🖥️ PC」「📱 移动端」两个开关;「移动端」= 窄视口(≤900px)生效——**PC 浏览器拉小窗口也会生效**,「PC」= 宽视口(>900px)生效,两端都开 = 全宽度生效;
188
+ - **关于 `html[data-dsh-mobile]` 选择器**:该标记仅在**移动端 UA** 请求时写入。若自定义 CSS 以 `html[data-dsh-mobile]` 打头,则只在手机等移动端 UA 下命中;希望「窄屏桌面窗口也生效」时请直接写选择器(无需 `html[data-dsh-mobile]` 前缀),注入层会自动包裹媒体查询。
189
+ - **用户自定义(样式小插件)**:在 **设置 ⚙️ → 远程与移动端 → 🎨 移动端样式片段** 中粘贴自己的 CSS 即可新增片段,支持编辑/启停/删除/**一键复制**(每个片段「查看 CSS」旁都有「📋 复制样式」按钮),持久化于 `~/.dsh/remote-mobile/style-snippets.json`,保存后下一次页面加载即生效,无需重启;
190
+ - **按 UA 打标记 + 按宽度生效**:样式按视口宽度档生效(见上),与设备 UA 无关;移动端 UA 请求额外给 `<html>` 打上 `data-dsh-mobile="1"` 标记作为作用域钩子(以其作为选择器时仅移动端 UA 命中,详见上条),并注入可拖拽的展开把手脚本(全端注入,运行时仅在侧边栏折叠时生效)。
191
+
192
+ ### 6. 插件通用共存保护
193
+
194
+ - **启动零冲突**:`remoteWebUiPairing` 配对共享服务被其他远程/Web 接入类插件占用时,本插件自动让出(延迟裁决:等待激活窗口结束后检测服务名归属),避免服务重名导致的整树回滚崩溃——从插件市场安装后可直接启动,无需任何手动配置;
195
+ - **冲突状态可见化**:检测到共存时,设置页顶部展示可关闭的警示横幅(中英文),说明让出行为与「只保留其一」的建议;处理完成后刷新页面即不再出现;
196
+ - **一键诊断报告**:横幅内 **「📋 复制诊断与修复信息」** 按钮可复制完整诊断报告——运行时自动识别占用方插件包名与 loader entry id,报告含精确到行的修复配置与命令(禁用对方 / 卸载本插件二选一),粘贴给 AI 助手即可按步骤处理。
197
+
198
+ ---
199
+
200
+ <span id="install"></span>
201
+ ## 📦 安装与更新
202
+
203
+ <details>
204
+ <summary><b>展开查看全部 4 种安装方式</b></summary>
205
+
206
+ ### 方式 1:通过 DSH 命令行一键安装(最推荐)
207
+ ```bash
208
+ dsh plugin --profile web add dsh-remote-mobile
209
+ ```
210
+
211
+ ### 方式 2:通过 Web 设置页「插件管理」图形化安装
212
+ 1. 在浏览器打开 DSH Web 控制台;
213
+ 2. 点击左下角 **设置 ⚙️ -> 插件**;
214
+ 3. 切换到顶部的 **「插件管理」** Tab;
215
+ 4. 在输入框中输入 npm 包名 **`dsh-remote-mobile`**,点击 **「安装」**;
216
+ 5. 安装完成后重启 DSH 即可生效。
217
+
218
+ ### 方式 3:在 Profile 目录中通过包管理器安装
219
+ ```bash
220
+ # 1. 进入 DSH Web Profile 目录
221
+ cd ~/.dsh/profiles/web
222
+
223
+ # 2. 通过 pnpm 安装
224
+ pnpm add dsh-remote-mobile
225
+ ```
226
+
227
+ ### 方式 4:本地源码开发与调试(软链接即时生效)
228
+
229
+ ```bash
230
+ # 1. 克隆代码至本地
231
+ git clone https://github.com/IceApriler/dsh-remote-mobile.git
232
+ cd dsh-remote-mobile
233
+
234
+ # 2. 安装依赖并编译打包
235
+ npm install
236
+ npm run build
237
+ ```
238
+
239
+ **建立软链接到 DSH 运行环境(开发修改后 `npm run build` 即时生效):**
240
+
241
+ * **macOS / Linux**:
242
+ ```bash
243
+ rm -rf ~/.dsh/profiles/web/node_modules/dsh-remote-mobile
244
+ ln -s $(pwd) ~/.dsh/profiles/web/node_modules/dsh-remote-mobile
245
+ ```
246
+
247
+ * **Windows (PowerShell)**:
248
+ ```powershell
249
+ Remove-Item -Recurse -Force "$HOME\.dsh\profiles\web\node_modules\dsh-remote-mobile"
250
+ New-Item -ItemType Junction -Path "$HOME\.dsh\profiles\web\node_modules\dsh-remote-mobile" -Target (Get-Location)
251
+ ```
252
+
253
+ * **Windows (CMD)**:
254
+ ```cmd
255
+ rmdir /s /q %USERPROFILE%\.dsh\profiles\web\node_modules\dsh-remote-mobile
256
+ mklink /J %USERPROFILE%\.dsh\profiles\web\node_modules\dsh-remote-mobile %CD%
257
+ ```
258
+
259
+ </details>
260
+
261
+ ### 🔄 更新插件
262
+
263
+ 在终端执行更新指令,更新后重启 DSH 即可生效:
264
+
265
+ ```bash
266
+ # 方式 1:通过 DSH 命令行一键更新(推荐)
267
+ dsh plugin --profile web update dsh-remote-mobile
268
+
269
+ # 方式 2:通过 Profile 目录包管理器更新
270
+ cd ~/.dsh/profiles/web && pnpm update dsh-remote-mobile
271
+ ```
272
+
273
+ > **💡 提示**:也可以在 Web 控制台 **设置 ⚙️ -> 插件 -> 插件管理** 中点击对应插件的更新按钮,或重新执行 `dsh plugin --profile web add dsh-remote-mobile@latest`。
274
+
275
+ ### 🗑️ 卸载插件
276
+
277
+ ```bash
278
+ dsh plugin --profile web remove dsh-remote-mobile
279
+ ```
280
+
281
+ ---
282
+
283
+ <span id="advanced"></span>
284
+ ## ⚙️ 高级配置
285
+
286
+ 配置持久化于插件自有文件 `~/.dsh/remote-mobile/settings.json`,可在 Web 界面中直观调整,也可直接编辑该文件:
287
+
288
+ ```jsonc
289
+ {
290
+ "allowTailscale": false, // boolean,默认 false:是否允许 Tailscale 虚拟私网免密访问
291
+ "allowLan": false, // boolean,默认 false:是否允许局域网免密访问(高危警示)
292
+ "secretHash": "", // string,默认空:长期访问密码的 scrypt 加盐哈希值
293
+ "maxVisitsPerMinute": 60, // number,默认 60:单 IP 每分钟最大访问登录页次数
294
+ "maxFailedAttempts": 5, // number,默认 5:触发封禁的连续认证失败最大次数
295
+ "lockDurationMs": 900000 // number,默认 900000 (15分钟):IP 锁定持续时间(毫秒)
296
+ }
297
+ ```
298
+
299
+ > **关于配置存储**:DSH 自 **0.1.7** 起(最早见于 v0.1.7-alpha.1 的 release notes,0.2.x 延续)官方已弃用 `~/.dsh/settings.yaml` 作为**实时配置源**——该文件会在启动时被一次性迁移进当前 profile 的 `cordis.patch.yml`,并改名为 `settings.yaml.imported`(详见 [Q8](#faq))。因此本插件不再写入 settings.yaml,而是持久化到上述自有 `settings.json`;首次启动时会自动从旧 `settings.yaml` / `settings.yaml.imported` 迁移一次(把旧长期密码、限频等配置救回)。
300
+
301
+ ### 🎨 移动端样式片段(可选)
302
+
303
+ 自定义样式片段(样式小插件)与启停状态持久化于 `~/.dsh/remote-mobile/style-snippets.json`,可在设置面板图形化管理,也可直接编辑该文件:
304
+
305
+ ```json
306
+ {
307
+ "version": 2,
308
+ "presetStates": {
309
+ "preset-sidebar": { "pc": false, "mobile": true },
310
+ "preset-settings": { "pc": false, "mobile": true },
311
+ "preset-main": { "pc": false, "mobile": true }
312
+ },
313
+ "custom": [
314
+ {
315
+ "id": "custom-xxx",
316
+ "name": "我的样式小插件",
317
+ "css": "html[data-dsh-mobile] .我的选择器 { ... }",
318
+ "pcEnabled": false,
319
+ "mobileEnabled": true
320
+ }
321
+ ],
322
+ "customOrder": ["custom-xxx"]
323
+ }
324
+ ```
325
+
326
+ > 所有启用片段会拼接为单个 `<style>` 注入主页面与 `/auth` 登录页,**生效与否由视口宽度决定**:`mobileEnabled` 的片段包在 `@media (max-width: 900px)`(≤900px 生效,PC 拉小窗口同样生效),`pcEnabled` 的片段包在 `@media (min-width: 901px)`(宽视口生效),两端都开则全宽度生效(v1 旧格式自动迁移,`presetStates` 按三个预设分组齐全落盘)。注意:PC 开启侧边栏抽屉预设会改变桌面布局,如不想用可关闭该预设的 PC 开关。
327
+
328
+ ---
329
+
330
+ <span id="storage"></span>
331
+ ## 📂 本地文件存储位置
332
+
333
+ > **💡 路径提示**:在 macOS / Linux 下根目录为 `~/.dsh/`;在 Windows 下对应为 `C:\Users\<你的用户名>\.dsh\`(可在文件资源管理器地址栏直接输入 `%USERPROFILE%\.dsh` 直达)。
334
+
335
+ | 文件路径 | 说明 | 安全级别 |
336
+ |---|---|---|
337
+ | `~/.dsh/remote-mobile/settings.json` | 插件配置:免密开关、长期密码哈希与限频/锁定策略 | 本地落盘,权限 `0o600`(仅当前用户可读写) |
338
+ | `~/.dsh/remote-mobile/devices.json` | 已授权设备会话、IP 访问计数与安全审计数据(内含长效 Token,权限 `0o600`) | 本地落盘,仅当前用户可读写 |
339
+ | `~/.dsh/remote-mobile/rsa-keys.json` | 服务端 RSA 密钥对文件(含公钥与私钥) | 本地落盘,权限 `0o600`(仅当前用户可读写) |
340
+ | `~/.dsh/remote-mobile/style-snippets.json` | 移动端样式片段(内置预设启停状态 + 用户自定义 CSS 小插件) | 本地落盘持久化 |
341
+
342
+ ---
343
+
344
+ <span id="faq"></span>
345
+ ## ❓ 常见问题 (FAQ)
346
+
347
+ <details>
348
+ <summary><b>Q0: 启动报错 <code>listen EADDRINUSE: address already in use 0.0.0.0:3080</code>?</b></summary>
349
+
350
+ **答**:这是 **3080 端口被其他进程占用**(绝大多数是上一个 `dsh web` 实例尚未完全退出,例如桌面快捷方式拉起的隐藏实例、或重启时新旧进程交叠),**与安装了哪个插件无关**。排查步骤:
351
+
352
+ 1. **查找占用端口的进程**:
353
+ * **macOS / Linux**:`lsof -nP -iTCP:3080`
354
+ * **Windows**:`netstat -ano | findstr 3080`(最后一列为 PID)
355
+ 2. **结束旧实例**:
356
+ * **macOS / Linux**:`kill <PID>`
357
+ * **Windows**:`taskkill /F /PID <PID>`(或在任务管理器中结束对应 Node 进程)
358
+ 3. 重新启动 `dsh web` 即可。
359
+ 4. **注意**:桌面快捷方式(dsh-desktop-launcher 生成的后台实例)与终端手动启动的实例不能同时运行。
360
+
361
+ 另:若日志显示的是 `service "remoteWebUiPairing" has been registered` 类错误,请升级本插件至最新版本——新版已内置通用共存保护,与其他远程接入类插件并存时可正常启动并自动让出服务,并在设置面板顶部提示冲突详情。
362
+ </details>
363
+
364
+ <details>
365
+ <summary><b>Q1: 手机扫码后提示「连接被拒绝」或无法打开页面?</b></summary>
366
+
367
+ **答**:请按以下步骤逐一排查:
368
+ 1. **配置检查**:确保电脑上的 `cordis.patch.yml` 中已配置 `host: '0.0.0.0'`,且 DSH 已经重启;
369
+ 2. **同一局域网**:局域网访问时,确保手机与电脑连接在同一个 Wi-Fi / 路由器下,且未开启手机端的独立代理/VPN(避免流量绕过局域网);
370
+ 3. **Windows 防火墙排查(Windows 用户常见原因)**:
371
+ * 启动 DSH 时如弹出「Windows Defender 防火墙」警报,请务必勾选 **「专用网络」** 和 **「公用网络」** 并允许访问;
372
+ * 若错过弹窗或依然无法连通,可使用**管理员权限打开 PowerShell** 执行以下命令一键放行端口:
373
+ ```powershell
374
+ New-NetFirewallRule -DisplayName "DSH Web 3080" -Direction Inbound -LocalPort 3080 -Protocol TCP -Action Allow
375
+ ```
376
+ * **检查 Wi-Fi 网络类型**:在 Windows「设置 -> 网络和 Internet -> Wi-Fi」中,确保当前 Wi-Fi 网络配置文件类型已设为 **「专用网络」**(若为「公用网络」,Windows 防火墙会默认拦截局域网入站请求);
377
+ 4. **多网卡环境(WSL / 虚拟机)**:Windows 如安装了 WSL2 或 Hyper-V,可能会生成虚拟网卡 IP(如 `172.x.x.x`)。请在插件设置面板中确认使用的是物理无线网卡(WLAN / Wi-Fi)对应的局域网 IP 或 Tailscale 二维码。
378
+ </details>
379
+
380
+ <details>
381
+ <summary><b>Q2: Tailscale 免密直连和局域网免密有什么区别?</b></summary>
382
+
383
+ **答**:
384
+ * **Tailscale 免密**:高度安全。因为 Tailscale 是基于 WireGuard 的传输加密虚拟私网,只有你自己登录了同一账号的设备才能连通。
385
+ * **局域网免密**:存在安全隐患。任何连入你家 Wi-Fi 的设备(包括访客或蹭网设备)均可直接控制你的工作区,因此非完全可信环境**切勿开启**。
386
+ </details>
387
+
388
+ <details>
389
+ <summary><b>Q3: 手机端切换或新建工作区能正常使用吗?</b></summary>
390
+
391
+ **答**:**支持**。本插件通过请求隔离技术,使手机端与 PC 桌面端拥有一致的工作区管理与执行能力。
392
+ </details>
393
+
394
+ <details>
395
+ <summary><b>Q4: 手机端样式还是不满意,想完全自己定制?</b></summary>
396
+
397
+ **答**:打开 **设置 ⚙️ → 远程与移动端 → 🎨 移动端样式片段**,先尝试启停三段内置预设(侧边栏 / 设置面板 / 正文,每段都有独立的 PC 与移动端开关);还不够就在「自定义片段」里粘贴自己的 CSS(例如 `.我的选择器 { ... }`)。保存后手机端刷新页面立即可见,改动全部落在 `~/.dsh/remote-mobile/style-snippets.json`,升级插件不会丢失。
398
+ > 小提示:若选择器写成 `html[data-dsh-mobile] .xxx`,则只在移动端 UA 下生效,窄屏桌面窗口不会命中;希望两端窄屏都生效,请直接写选择器。
399
+ </details>
400
+
401
+ <details>
402
+ <summary><b>Q5: 设置页顶部出现黄色横幅「⚠️ 检测到其他远程接入插件」是什么意思?</b></summary>
403
+
404
+ **答**:说明当前有另一款远程/Web 接入类插件与本插件同时启用,且对方先占用了配对共享服务。为避免启动冲突,本插件已**自动让出**该服务(自身的安全门禁与远程接入不受影响),但两套远程功能并存可能出现重复入口。建议只保留其一:
405
+
406
+ 1. 点击横幅中的 **「📋 复制诊断与修复信息」**,将报告粘贴给 AI 助手按步骤处理(报告已自动识别占用方包名与条目 id,并给出精确的修复配置);
407
+ 2. 推荐保留本插件时:按报告指引在 `~/.dsh/profiles/web/cordis.patch.yml` 末尾追加对应的 `disabled: true` 两行,然后重启 DSH;
408
+ 3. 横幅可点击 ✕ 临时关闭;冲突解除后刷新页面即不再出现。
409
+ </details>
410
+
411
+ <details>
412
+ <summary><b>Q6: 为什么建议按需安装单体功能插件,而不建议安装聚合全家桶(如 @linxin666/dsh-web-all)?</b></summary>
413
+
414
+ **答**:主要是基于**避免功能冲突**与**环境轻量解耦**的考量:
415
+ 1. **避免移动端入口重复与手势交互冲突**:全家桶插件会将十几个独立功能插件的前端代码编译打包在同一个 `client.js` 中,其内置的移动端自适应逻辑在模块加载时会自执行。即使在 `cordis.patch.yml` 中配置了 `web-ui-remote-web-ui: disabled: true`,浏览器加载脚本后仍可能渲染出小鲸鱼悬浮按钮(`#dshRemoteWhale`),导致两个插件的移动端悬浮入口重叠以及触控手势冲突。
416
+ 2. **轻量可控与独立升级**:按需单独安装所需插件,既能保证环境轻盈,也便于各个插件独立升级、回滚与维护,避免依赖绑定。推荐按需安装各自独立的单体包,例如:
417
+ ```bash
418
+ # 需要哪个装哪个,职责清晰、互不干扰
419
+ dsh plugin --profile web add @linxin666/dsh-client-ui-task-board
420
+ dsh plugin --profile web add @linxin666/dsh-client-ui-web-ui-settings
421
+ dsh plugin --profile web add @linxin666/dsh-pet
422
+ dsh plugin --profile web add @linxin666/dsh-ssh
423
+ ```
424
+ *(注:自 v1.6.0 起,`dsh-remote-mobile` 已内置兼容防护——注入抑制脚本向 `sessionStorage` 写入 `dsh-remote-force-desktop=1` 并协同 CSS,避免 `#dshRemoteWhale` 被**重复挂载**;但小鲸鱼入口本身仍可能由对方渲染,入口重叠的根源在对方,故仍建议按需安装单体包)*。
425
+ </details>
426
+
427
+ <details>
428
+ <summary><b>Q7: 部署在 NAS / 统一网关 / Nginx 反向代理下(如飞牛 fnOS <code>/app/dsh/</code>)有什么注意事项?</b></summary>
429
+
430
+ **答**:
431
+ 1. **子路径与前缀自适应**:自 v1.8.0 起,前端已原生适配 `<base href="...">`,服务端重定向已支持 `X-Forwarded-Prefix` 请求头。经网关子路径代理访问时(如 `http://<ip>:5666/app/dsh/`),各项请求都会自动保持在当前子路径下:
432
+ * **设置面板与 SSE 长连接**:基于 `<base>` 动态解析 API 路径,保存配置、生成配对码、事件推送均不会丢失 `/app/dsh` 前缀(旧版本此处会表现为「点击毫无反应」);
433
+ * **独立手机登录页与 302 重定向**:登录校验、登录成功后的跳转,以及门禁 / `/auth` 的重定向都会保留当前子路径,不再跳回宿主根目录;
434
+ * **注意**:服务端 302 重定向依赖反向代理透传 `X-Forwarded-Prefix`;若代理未透传该头,重定向将回退到安全默认路径 `/auth`。
435
+ 2. **网关回环 (127.0.0.1) 放行机制**:
436
+ * 出于严密的安全防护考量(防止外部恶意客户端伪造 `X-Forwarded-For` 请求头绕过认证),插件门禁严格基于底层物理 Socket 连接判断客户端真实来源。
437
+ * 当反向代理/宿主网关直接从本机 `127.0.0.1` 代理至 DSH 时,请求会被识别为本地回环连接并直接放行——此时由网关/NAS 宿主自身的登录与权限隔离机制进行安全兜底。
438
+ * 若你希望通过外部统一域名/网关访问时仍强制要求输入本插件的动态配对码或长期访问密码,建议配置反向代理透明透传客户端源 IP,或直接通过 DSH 开放的外部端口(如默认的 `3080` 或自定义映射端口)直连访问。
439
+ </details>
440
+
441
+ <details>
442
+ <summary><b>Q8: 升级 DSH 0.1.7+(含 0.2.x)后 <code>~/.dsh/settings.yaml</code> 不见了 / 我的配置丢了?</b></summary>
443
+
444
+ **答**:这是 **DSH 官方自 0.1.7 起的行为变更**(最早见于 v0.1.7-alpha.1 的 release notes,0.2.x 延续),与本插件无关:
445
+
446
+ - DSH 自 **0.1.7** 起已**不再把 `~/.dsh/settings.yaml` 当作实时配置源**。启动时它由官方 `dsh-settings` 的 `importLegacyDocument()` **一次性导入**到当前 profile 的 `~/.dsh/profiles/<profile>/cordis.patch.yml`,随后原文件被**改名为 `settings.yaml.imported`**(先改名、再导入;若某个 section 找不到对应 entry,则会跳过,仅保留在该文件中,且不会重试)。官方 release notes 原文:「设置改由当前 Profile 的插件配置保存,支持声明过的实时更新字段;旧 settings.yaml 仅尝试导入一次,自定义设置插件需适配。」
447
+ - 因此升级后 `settings.yaml` 消失、只剩 `settings.yaml.imported` 属**正常现象**;模型 provider、locale 等应改为在 profile 的 `cordis.patch.yml` 中查看/编辑。
448
+ - **本插件自 v1.9.0 起**已改为把自身配置持久化到 `~/.dsh/remote-mobile/settings.json`,并在首次启动时**自动从旧 `settings.yaml` / `settings.yaml.imported` 迁移一次**(把长期密码哈希、免密开关、限频阈值等救回),不再依赖 DSH 的 settings.yaml。若你曾发现"长期密码失效/限频重置",升级到 v1.9.0 后会自动恢复。
449
+ </details>
450
+
451
+ ---
452
+
453
+ ## 📄 开源许可证
454
+
455
+ 本项目采用 [MIT License](LICENSE) 协议开源。