@feiyang666/dsh-mobile-remote 1.4.1 → 1.4.3

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,5 +1,23 @@
1
1
  # 更新日志 / Changelog
2
2
 
3
+ ## v1.4.3 (2026-08-22)
4
+
5
+ ### 修复 / Fixed
6
+ - **移动端设置页空白 + 无法上下滚动**(`lib/index.js` MOBILE_CSS):v1.4.2 虽把设置弹窗改为全屏单栏,但面板仍是横向 `flex`(row)布局,内容列被压成 0 宽度 → 内容区整块空白;且内容列 `min-height:auto` 无法收缩,`.options` 区拿不到受限高度 → 不能滑动。本版:
7
+ - 面板强制 `flex-direction: column !important`,导航栏成顶部横向标签、内容列独占剩余空间;
8
+ - 内容列 `min-height: 0` + `overflow: hidden`,让设置选项区在手机端可正常上下滚动。
9
+ - **内网(非安全上下文)远程连接失败**(`lib/index.js` GATE_JS):当前 DSH 客户端多处裸调用 `crypto.randomUUID()`(RPC ID / 消息 ID / 实例令牌等),而该 Web Crypto API 仅在 HTTPS 或 localhost 存在。内网 http 直连(非安全上下文)下缺失(或存在但调用抛 `NotSupportedError`),导致连接与所有 RPC 失败,模型设置页因此报 `settings are unavailable in this browser`。本版在插件注入 `<head>` 的脚本里,用 `crypto.getRandomValues`(非安全上下文也可用)补一个 RFC 4122 v4 `crypto.randomUUID` 兜底,覆盖应用内全部调用点,内网访问 / 扫码连接恢复正常;DSH 自行修复后该兜底自动失效,无副作用。
10
+
11
+ ## v1.4.2 (2026-08-21)
12
+
13
+ ### 修复 / Fixed
14
+ - **移动端 Tooltip 常驻屏幕**(`lib/index.js` MOBILE_CSS):DSH 原生 Tooltip 气泡由 hover/focus 触发,触屏设备点击按钮后焦点停留、气泡一直显示在屏幕上(如「停止」「开始」「关闭菜单栏」等按钮的提示文字)。移动端直接隐藏 `[role="tooltip"]` 气泡,按钮仍保留 aria-label 无障碍名。
15
+ - **设置页未适配移动端**(`lib/index.js` MOBILE_CSS + MOBILE_JS):原生设置弹窗为 800px 双栏(188px 导航栏 + 内容列),手机上几乎无法使用。改为全屏单栏:
16
+ - 导航栏 → 顶部横向滚动胶囊标签(加大触控目标);
17
+ - 内容列独占剩余空间、边距收紧,各设置 section 获得完整宽度;
18
+ - 用 MutationObserver 识别设置弹窗(`role=dialog` 且直子元素为 `<nav>`)打上 `data-dsh-settings` 标记,**不依赖 harness 内部哈希类名**,harness 升级后仍可直接适配。
19
+ - **远程控制面板窄屏细节**(`lib/client.js`):设备详情 / 外网状态行的长文本允许换行(`overflowWrap`),行内放不下时允许换行(`flexWrap`),避免手机端溢出卡片。
20
+
3
21
  ## v1.4.1 (2026-08-20)
4
22
 
5
23
  ### 新增 / Added
package/README.md CHANGED
@@ -149,7 +149,8 @@ So for users, **installing is one command** — no YAML editing, no manual file
149
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
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
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**.
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
+ - **Mobile settings page** (v1.4.2+): the native settings dialog becomes a full-screen single column on phones — the nav rail turns into a horizontally scrollable tab bar and the content column fills the remaining space; persistent native tooltip bubbles (e.g. the "stop / start / close sidebar" hints that stick on touch) are suppressed. The dialog is detected structurally, **not via harness-internal hashed class names**, so the plugin keeps working after DeepSeek Harness updates without modification. **v1.4.3** fixes the single-column settings layout — the panel was still a row-flex, collapsing the content column to zero width (blank content) and blocking vertical scroll; it now forces `flex-direction: column` plus `min-height: 0` so the options area actually scrolls on phones. It also adds a **`crypto.randomUUID` fallback for insecure contexts (LAN `http://`)**: current DSH clients call `crypto.randomUUID()` on the wire, which is only defined on HTTPS or localhost, so LAN direct access failed with `crypto.randomUUID is not a function` / `settings are unavailable in this browser`; the injected head script now provides an RFC 4122 v4 shim backed by `getRandomValues`.
153
154
 
154
155
  ---
155
156
 
@@ -174,7 +175,7 @@ This command does three things automatically:
174
175
 
175
176
  The same works for other profiles — replace `web` with your profile name.
176
177
 
177
- > Local tarball testing: `dsh plugin --profile web add C:\path\to\feiyang666-dsh-mobile-remote-1.4.1.tgz`
178
+ > Local tarball testing: `dsh plugin --profile web add C:\path\to\feiyang666-dsh-mobile-remote-1.4.3.tgz`
178
179
 
179
180
  ### 2. Restart and verify
180
181
 
package/README.zh.md CHANGED
@@ -149,7 +149,8 @@ dsh --profile web --patch remote-control.patch.yml
149
149
  - **开关**:`POST /__dsh_remote/toggle` → 写入 / 移除 profile `cordis.patch.yml` 的 `webserver` 覆盖块 → dsh `watchUserPatches`(Cordis HMR)热重载 webserver 行重新监听。
150
150
  - **设备数**:移动端注入 JS 每 30s 心跳上报,host 维护活跃设备表(90s 过期)。每次心跳会上报完整设备元数据(屏幕 / 视口 / DPR / 网络 / 当前页面 / 语言 / 平台),设置面板的设备行可展开查看。
151
151
  - **二维码**:`GET /__dsh_remote/qr?url=...` 返回 SVG。
152
- - **移动端适配**:`tapIndex` 注入移动端 CSS/JS,composer 输入栏窄屏换行、选择器限宽、iOS 输入框 16px 防缩放;**不破坏 DSH 原生 rail + 汉堡抽屉交互**。
152
+ - **移动端适配**:`tapIndex` 注入移动端 CSS/JS,composer 输入栏窄屏换行、选择器限宽、iOS 输入框 16px 防缩放;**不破坏 DSH 原生 rail + 汉堡抽屉交互**;
153
+ - **移动端设置页适配**(v1.4.2+):原生设置弹窗在手机上自动变为全屏单栏——导航栏变顶部横向滚动标签、内容区占满剩余空间;同时抑制触屏上常驻的原生 Tooltip 气泡(如「停止 / 开始 / 关闭菜单栏」提示文字)。通过结构标记识别设置弹窗,**不依赖 harness 内部哈希类名**,harness 升级后无需修改插件即可直接适配。**v1.4.3** 修复该单栏布局——面板原本仍是横向 `flex`,内容列被压成 0 宽度(内容空白)且无法上下滚动;现强制 `flex-direction: column` + `min-height: 0`,设置选项区在手机上可正常滚动。并新增**内网(非安全上下文)`crypto.randomUUID` 兜底**:当前 DSH 客户端在连接时直接调用 `crypto.randomUUID()`,该 Web Crypto API 仅在 HTTPS / localhost 存在,内网 http 直连会报 `crypto.randomUUID is not a function` / `settings are unavailable in this browser`;插件注入的头部脚本用 `getRandomValues` 补一个 RFC 4122 v4 实现,内网访问 / 扫码连接恢复正常。
153
154
 
154
155
  ---
155
156
 
@@ -174,7 +175,7 @@ dsh plugin --profile web add @feiyang666/dsh-mobile-remote
174
175
 
175
176
  其它 profile 同理,把 `web` 换成你的 profile 名即可(如 `dsh plugin --profile headless add ...`)。
176
177
 
177
- > 想用本地 tarball 测试:`dsh plugin --profile web add C:\path\to\feiyang666-dsh-mobile-remote-1.4.1.tgz`
178
+ > 想用本地 tarball 测试:`dsh plugin --profile web add C:\path\to\feiyang666-dsh-mobile-remote-1.4.3.tgz`
178
179
 
179
180
  ### 2. 重启并验证
180
181
 
package/RELEASE_NOTES.md CHANGED
@@ -1,52 +1,33 @@
1
- # dsh-mobile-remote v1.4.1
2
-
3
- **DeepSeek Harness 移动端远程控制插件** —— 在 Web UI 设置页内置「远程控制」:连接二维码、一键开关、在线设备数,让手机通过局域网访问并操控电脑上的 DeepSeek Harness。本版聚焦**外网隧道真实状态诊断**:不再"假在线",token 鉴权失败 / 断线重连一目了然。
4
-
5
- ## 安装方式
6
-
7
- ```bash
8
- dsh plugin --profile web add @feiyang666/dsh-mobile-remote
9
- ```
10
-
11
- 安装完成后**重启 dsh web 服务**,打开 `http://127.0.0.1:3080` → **设置 → 远程控制** 即可使用。
12
-
13
- ## 本版更新(v1.4.1)
14
-
15
- ### 🚦 外网隧道真实状态判定(核心)
16
-
17
- 之前插件把「frpc 进程存活」误判为「隧道在线」——frpc 即使登录被拒、隧道从未建立,面板也显示绿色「在线」(打开链接却是 502)。本版彻底修复:
18
-
19
- - **启动探测**:开启外网时读 frpc 日志,确认 `start proxy success` 隧道真正建立才算 `online`;
20
- - **轮询复查**:`/status` 每 5s 复查日志——断线降级「连接中」(自动重连中)、token 不匹配降级「出错」,重连成功后自动恢复;
21
- - **明确报错**:前端红色「出错」徽标 + 错误卡直接展示 frpc 真实原因(如 `token in login doesn't match token from configuration`),并附解决指引;
22
- - **一键重试**:出错状态点开关即可 kill 旧进程重新绑定。
23
-
24
- ### 🔁 隧道持续心跳保活
25
-
26
- - 隧道在线期间每 60s 向中转端上报心跳,`last_seen` 保持新鲜;
27
- - 停止隧道时主动上报 `offline`,配合后端在线判定让管理端 / 面板实时反映真实状态。
28
-
29
- ### ⚠️ FRP_TOKEN 占位符检测
30
-
31
- - 中转端新增 `frpTokenWarning` 字段;插件面板检测到服务器 `.env` 的 `FRP_TOKEN` 仍是占位符时,显示黄色警告条并说明会导致隧道 502。
32
-
33
- ### 🗂 DSH 状态卡默认折叠
34
-
35
- - 折叠态只显示摘要行(会话 / 工作区 / 插件 / 模型数),点击标题展开详情,节省面板空间。
36
-
37
- ### 🐛 修复
38
-
39
- - 修复设置页空白崩溃(`status` 首次渲染为 `null` 时的守卫缺失)。
40
-
41
- ## 后端配套(dsh-update-server)
42
-
43
- 外网隧道详情、真实在线判定依赖中转端新接口(`/api/tunnel/stats`、`/heartbeat` 离线支持、成员端在线判定)。**旧后端不影响插件使用**:插件自动回退到 `/status` 接口。若要展示流量 / 连接数等丰富信息,请同步升级中转端(见 `dsh-update-server` 的 `DEPLOY_CHECKLIST.md`)。
44
-
45
- ## 已知事项
46
-
47
- - 开启后服务暴露到公网,**请务必设置远程访问密码**,并仅在可信网络上使用
48
- - 外网隧道需确保服务器 `.env` 的 `FRP_TOKEN` 与 `/www/server/frps/frps.toml` 的 `auth.token` 完全一致,否则面板会明确提示鉴权失败
49
-
50
- ## 变更日志
51
-
52
- 详见 [CHANGELOG.md](./CHANGELOG.md)。
1
+ # dsh-mobile-remote v1.4.3
2
+
3
+ **DeepSeek Harness 移动端远程控制插件** —— 在 Web UI 设置页内置「远程控制」:连接二维码、一键开关、在线设备数,让手机通过局域网访问并操控电脑上的 DeepSeek Harness。本版**修复移动端设置页空白 / 无法滚动**,并新增**内网(非安全上下文)远程连接的 `crypto.randomUUID` 兜底**,让内网直连与手机扫码访问不再失败。
4
+
5
+ ## 安装方式
6
+
7
+ ```bash
8
+ dsh plugin --profile web add @feiyang666/dsh-mobile-remote
9
+ ```
10
+
11
+ 安装完成后**重启 dsh web 服务**,打开 `http://127.0.0.1:3080` → **设置 → 远程控制** 即可使用。
12
+
13
+ ## 本版更新(v1.4.3)
14
+
15
+ ### 🖱️ 移动端设置页:内容空白 + 无法上下滚动
16
+
17
+ 上一版已把设置弹窗改为全屏单栏,但面板仍是横向布局,导致内容列被压成 0 宽度、设置内容区整块空白;内容列也无法收缩,设置选项区不能上下滑动。本版:
18
+
19
+ - 面板强制 `flex-direction: column`,导航栏成为顶部横向标签、内容列独占剩余空间;
20
+ - 内容列 `min-height: 0` + `overflow: hidden`,设置选项区在手机端可正常上下滚动。
21
+
22
+ ### 🔐 内网远程连接:`crypto.randomUUID` 兜底
23
+
24
+ 当前 DSH 客户端多处裸调用 `crypto.randomUUID()`,该 Web Crypto API 仅在 HTTPS 或 localhost 存在。内网 http 直连(非安全上下文)下缺失(或存在但调用即抛),导致连接与所有 RPC 失败,模型设置页因此报 `settings are unavailable in this browser`。本版在插件注入 `<head>` 的脚本里,用 `crypto.getRandomValues`(非安全上下文也可用)补一个 RFC 4122 v4 `crypto.randomUUID` 兜底,覆盖应用内全部调用点,内网访问 / 扫码连接恢复正常;DSH 自行修复后该兜底自动失效,无副作用。
25
+
26
+ ## 已知事项
27
+
28
+ - 开启后服务暴露到公网,**请务必设置远程访问密码**,并仅在可信网络上使用
29
+ - 外网隧道需确保服务器 `.env` 的 `FRP_TOKEN` 与 `/www/server/frps/frps.toml` 的 `auth.token` 完全一致,否则面板会明确提示鉴权失败
30
+
31
+ ## 变更日志
32
+
33
+ 详见 [CHANGELOG.md](./CHANGELOG.md)。
package/lib/client.js CHANGED
@@ -40,7 +40,8 @@ window.__ModuleLoader__.load({
40
40
  border: '1px solid var(--dsw-alias-border-l2, rgba(127,127,127,.18))',
41
41
  boxSizing: 'border-box',
42
42
  },
43
- row: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 },
43
+ // flexWrap: 窄屏下内容放不下时允许换行(如外网隧道详情行的长文本),桌面端无感知
44
+ row: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' },
44
45
  title: { fontSize: 15, fontWeight: 600, margin: 0, lineHeight: 1.4 },
45
46
  sub: { fontSize: 13, color: 'var(--dsw-alias-label-tertiary, #767676)', lineHeight: 1.6, margin: 0 },
46
47
  hint: { fontSize: 13, color: 'var(--dsw-alias-label-tertiary, #767676)', lineHeight: 1.6, margin: 0 },
@@ -118,7 +119,8 @@ window.__ModuleLoader__.load({
118
119
  },
119
120
  dotOn: { width: 8, height: 8, borderRadius: 999, flex: 'none', background: '#18a058' },
120
121
  deviceName: { fontSize: 13, fontWeight: 600, lineHeight: 1.4, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
121
- meta: { fontSize: 12, color: 'var(--dsw-alias-label-tertiary, #767676)', lineHeight: 1.5 },
122
+ // minWidth + overflowWrap:窄屏下长文本(设备详情、外网状态行)不溢出卡片
123
+ meta: { fontSize: 12, color: 'var(--dsw-alias-label-tertiary, #767676)', lineHeight: 1.5, minWidth: 0, overflowWrap: 'break-word' },
122
124
  dotOff: { width: 8, height: 8, borderRadius: 999, flex: 'none', background: 'rgba(127,127,127,.38)' },
123
125
  chevron: {
124
126
  fontSize: 10, color: 'var(--dsw-alias-label-tertiary, #767676)', flex: 'none',
package/lib/index.js CHANGED
@@ -956,6 +956,40 @@ const GATE_CSS = `
956
956
  const GATE_JS = `
957
957
  (function () {
958
958
  'use strict';
959
+
960
+ /* 内网 http(非安全上下文)兜底:crypto.randomUUID 仅在 HTTPS / localhost 存在,
961
+ 而 DSH 客户端连接时会直接调用 crypto.randomUUID()(dsh-client-connection 的
962
+ createMessage / mintRpcId),非安全上下文下缺失会抛 "crypto.randomUUID is not
963
+ a function",导致内网远程连接失败(外网 https 正常)。此处用 getRandomValues
964
+ (非安全上下文也可用)补一个 RFC 4122 v4 实现,让内网访问/扫码连接恢复正常。
965
+ 本脚本注入于 <head>,先于 DSH 应用 bundle 执行,故对应用内所有调用点生效。 */
966
+ var __cryptoShim = globalThis.crypto;
967
+ if (__cryptoShim) {
968
+ /* 部分浏览器非安全上下文里 randomUUID 不是 undefined,而是存在但调用即抛
969
+ NotSupportedError;此处试调一次并校验返回字符串,两种情况都判定为不可用。 */
970
+ var __uuidUsable = false;
971
+ try {
972
+ __uuidUsable = typeof __cryptoShim.randomUUID === 'function'
973
+ && typeof __cryptoShim.randomUUID() === 'string';
974
+ } catch (e) { __uuidUsable = false; }
975
+ if (!__uuidUsable) {
976
+ try {
977
+ __cryptoShim.randomUUID = function () {
978
+ var b = __cryptoShim.getRandomValues(new Uint8Array(16));
979
+ b[6] = (b[6] & 0x0f) | 0x40;
980
+ b[8] = (b[8] & 0x3f) | 0x80;
981
+ var h = '';
982
+ for (var i = 0; i < b.length; i++) {
983
+ var x = b[i].toString(16);
984
+ if (x.length === 1) x = '0' + x;
985
+ h += x;
986
+ }
987
+ return h.slice(0, 8) + '-' + h.slice(8, 12) + '-' + h.slice(12, 16) + '-' + h.slice(16, 20) + '-' + h.slice(20);
988
+ };
989
+ } catch (e) { /* 写入 crypto 失败则放弃,交由 DSH 自身逻辑处理 */ }
990
+ }
991
+ }
992
+
959
993
  function canCover() {
960
994
  try { return document.getElementById('dsh-remote-gate') === null; } catch (e) { return true; }
961
995
  }
@@ -1094,6 +1128,99 @@ html[data-dsh-mobile] input[type='text'],
1094
1128
  html[data-dsh-mobile] input[type='search'] {
1095
1129
  font-size: 16px !important;
1096
1130
  }
1131
+
1132
+ /* ----- 移动端 Tooltip 抑制 -----
1133
+ * DSH 原生 Tooltip 气泡由 hover / focus 触发(<span role="tooltip">)。
1134
+ * 触屏设备上没有 hover,点击按钮后焦点停留在按钮上,气泡会一直显示在屏幕上
1135
+ * (点击空白 / 滚动也不会消失)——即“停止 / 开始 / 关闭菜单栏等按钮的提示文字
1136
+ * 常驻屏幕”问题。移动端直接隐藏气泡,按钮仍保留 aria-label 无障碍名。
1137
+ */
1138
+ html[data-dsh-mobile] [role='tooltip'] {
1139
+ display: none !important;
1140
+ visibility: hidden !important;
1141
+ opacity: 0 !important;
1142
+ pointer-events: none !important;
1143
+ }
1144
+
1145
+ /* ----- 移动端设置页适配 -----
1146
+ * 原生设置弹窗是 800px 双栏布局(188px 导航栏 + 内容列),手机上内容被挤得
1147
+ * 几乎没有空间。由 MOBILE_JS 的 MutationObserver 把设置弹窗打上
1148
+ * data-dsh-settings 标记(结构:role=dialog 且首个子元素为 <nav>),这里改为
1149
+ * 全屏单栏:导航栏变顶部横向滚动标签,内容区独占剩余空间。
1150
+ * 不依赖 harness 内部哈希类名,harness 升级后仍能直接适配。
1151
+ */
1152
+ html[data-dsh-mobile] [data-dsh-settings] {
1153
+ display: flex !important;
1154
+ flex-direction: column !important;
1155
+ width: 100vw !important;
1156
+ max-width: 100vw !important;
1157
+ height: 100vh !important;
1158
+ height: 100dvh !important;
1159
+ max-height: 100vh !important;
1160
+ max-height: 100dvh !important;
1161
+ border-radius: 0 !important;
1162
+ }
1163
+
1164
+ /* 导航栏:横向标签条,可横向滚动 */
1165
+ html[data-dsh-mobile] [data-dsh-settings] > nav {
1166
+ display: flex !important;
1167
+ flex-direction: row !important;
1168
+ align-items: center !important;
1169
+ width: 100% !important;
1170
+ flex: none !important;
1171
+ padding: 8px 10px !important;
1172
+ gap: 6px !important;
1173
+ overflow-x: auto !important;
1174
+ -webkit-overflow-scrolling: touch;
1175
+ border-bottom: 1px solid var(--dsw-alias-border-l2, rgba(127,127,127,.18)) !important;
1176
+ }
1177
+
1178
+ /* 导航标题(设置面板的标题文案)在移动端隐藏,省出空间给标签 */
1179
+ html[data-dsh-mobile] [data-dsh-settings] > nav > div:first-child {
1180
+ display: none !important;
1181
+ }
1182
+
1183
+ /* 导航列表:横向排列、宽度自适应内容 */
1184
+ html[data-dsh-mobile] [data-dsh-settings] > nav > div + div {
1185
+ display: flex !important;
1186
+ flex-direction: row !important;
1187
+ width: max-content !important;
1188
+ gap: 6px !important;
1189
+ }
1190
+
1191
+ /* 导航项:胶囊标签,加大触控目标 */
1192
+ html[data-dsh-mobile] [data-dsh-settings] nav button {
1193
+ flex: none !important;
1194
+ height: 36px !important;
1195
+ padding: 0 14px !important;
1196
+ gap: 6px !important;
1197
+ border-radius: 999px !important;
1198
+ white-space: nowrap !important;
1199
+ }
1200
+
1201
+ /* 内容列:占满剩余空间。
1202
+ * min-height:0 是关键——flex 子项默认 min-height:auto,内容列无法收缩到
1203
+ * 比自身内容更矮,导致内容撑高后被面板 overflow:hidden 裁掉、内部 .options
1204
+ * 区永远拿不到受限高度而不能滚动。设为 0 后内容列可收缩,把高度让给
1205
+ * .options(其自身 overflow-y:auto)去内部滚动。 */
1206
+ html[data-dsh-mobile] [data-dsh-settings] > div {
1207
+ width: 100% !important;
1208
+ flex: 1 1 auto !important;
1209
+ min-width: 0 !important;
1210
+ min-height: 0 !important;
1211
+ overflow: hidden !important;
1212
+ }
1213
+
1214
+ /* 顶部 header 的按钮(关闭等)加大触控目标 */
1215
+ html[data-dsh-mobile] [data-dsh-settings] > div > div:first-child button {
1216
+ min-width: 36px !important;
1217
+ min-height: 36px !important;
1218
+ }
1219
+
1220
+ /* 内容区边距收紧,让 section 内容有更多可用宽度 */
1221
+ html[data-dsh-mobile] [data-dsh-settings] > div > div:last-child {
1222
+ padding: 0 12px 16px !important;
1223
+ }
1097
1224
  `
1098
1225
 
1099
1226
  /* ------------------------------------------------------------------ */
@@ -1190,6 +1317,31 @@ const MOBILE_JS = `
1190
1317
 
1191
1318
  document.documentElement.setAttribute('data-dsh-mobile', '');
1192
1319
 
1320
+ // 标记设置弹窗:原生设置页 = role="dialog" 且首个子元素为 <nav>(双栏弹窗)。
1321
+ // 打上 data-dsh-settings 标记后,上面的移动端 CSS 可精确适配,无需依赖
1322
+ // harness 内部的哈希类名——harness 升级后只要弹窗结构仍是
1323
+ // “dialog 直下 nav + 内容列”,本插件无需修改即可直接适配。
1324
+ function tagSettingsPanel() {
1325
+ var dialogs = document.querySelectorAll('[role="dialog"][aria-modal="true"]');
1326
+ for (var i = 0; i < dialogs.length; i++) {
1327
+ var dlg = dialogs[i];
1328
+ if (dlg.getAttribute('data-dsh-settings') === '1') continue;
1329
+ var kids = dlg.children;
1330
+ var hasNav = false;
1331
+ for (var j = 0; j < kids.length; j++) {
1332
+ if (kids[j].tagName === 'NAV') { hasNav = true; break; }
1333
+ }
1334
+ if (hasNav) dlg.setAttribute('data-dsh-settings', '1');
1335
+ }
1336
+ }
1337
+ tagSettingsPanel();
1338
+ if (typeof MutationObserver !== 'undefined') {
1339
+ // 设置弹窗是动态挂载/卸载的,用 MutationObserver 监听其出现并打标。
1340
+ var obs = new MutationObserver(function () { tagSettingsPanel(); });
1341
+ try { obs.observe(document.documentElement, { childList: true, subtree: true }); } catch (e) {}
1342
+ window.__DSH_MOBILE_REMOTE_SETTINGS_OBSERVER__ = obs;
1343
+ }
1344
+
1193
1345
  // 调试钩子:在控制台暴露状态,便于移动端远程排查。
1194
1346
  window.__DSH_MOBILE_REMOTE_READY__ = {
1195
1347
  mobile: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feiyang666/dsh-mobile-remote",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "description": "DeepSeek Harness mobile remote-control plugin: LAN/external remote control (QR / on-off toggle / remote-access password gate), rich telemetry (expandable device details, system CPU/memory/load, DSH app state: version/sessions/workspaces/plugins/models), real external-tunnel status detection (frpc token / reconnect diagnostics), plus mobile-first UI polish and faster remote loading.",
5
5
  "keywords": [
6
6
  "deepseek",