dsh-mobile 0.5.4 → 0.5.5
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 +11 -0
- package/CONTRIBUTORS.md +6 -4
- package/README.en.md +17 -10
- package/README.md +18 -11
- package/docs/CLOUDFLARE_TUNNEL.en.md +3 -1
- package/docs/CLOUDFLARE_TUNNEL.md +3 -1
- package/lib/client.js +51 -10
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +21 -5
- package/lib/index.mjs +133 -23
- package/lib/index.mjs.map +1 -1
- package/lib/mobile-layout.js +3 -2
- package/lib/mobile-layout.js.map +1 -1
- package/node_modules/dsh-mobile-question-fixes/package.json +1 -1
- package/package.json +4 -1
- package/packages/question-fixes/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
Notable changes to DSH Mobile are recorded here. GitHub Releases remain the source for downloadable packages and complete generated commit notes.
|
|
4
4
|
|
|
5
|
+
## 0.5.5 - 2026-10-04
|
|
6
|
+
|
|
7
|
+
- Extend the mobile editable font floor to body-level model-search portals and the pairing page, while keeping desktop text and composer-dock spacing unchanged. Thanks @chintoleung for [PR #158](https://github.com/saya-ch/dsh-mobile/pull/158).
|
|
8
|
+
- Let Android Back return from the model list to its root menu, then close that menu through DSH's existing Escape handling, without selecting a model or submitting the draft.
|
|
9
|
+
- Keep the live Android WebView through rotation, window resizing and keyboard-availability changes, preserving the page, reference chips and unsent images. Locale, font-scale and system-theme changes retain Android's normal Activity recreation.
|
|
10
|
+
- Preserve a known **Removed on computer** status through automatic or manual reachability checks. Discard late results from an older credential so they cannot overwrite a revoked or re-paired device.
|
|
11
|
+
- Support on-demand cloudflared installation on macOS x64 and arm64. Verify the official compressed artifact and extracted executable separately, retain the pinned Windows/Linux files, and add isolated installation, reinitialization, and cleanup checks. Thanks @cjxh21 for [PR #155](https://github.com/saya-ch/dsh-mobile/pull/155).
|
|
12
|
+
- Keep an unfocused narrow-screen composer as a scrollable 72px draft preview and enlarge existing touch controls without changing DSH's draft or submission handlers. Expand browser coverage for focus, portaled menus, references, attachments, and keyboard states. Thanks @abworks-dev for [PR #152](https://github.com/saya-ch/dsh-mobile/pull/152).
|
|
13
|
+
- Add a real packed-profile screenshot tool for pairing, conversation, drawer, and settings surfaces. Mask pairing credentials and share isolated startup, readiness, and cleanup with browser checks. Thanks @cjxh21 for [PR #154](https://github.com/saya-ch/dsh-mobile/pull/154).
|
|
14
|
+
- Release Android 0.5.5 (build 75) with the same established signing certificate and compatible pairing protocol. Update the plugin and app together to receive all fixes; official same-signer upgrades retain paired devices.
|
|
15
|
+
|
|
5
16
|
## 0.5.4 - 2026-10-02
|
|
6
17
|
|
|
7
18
|
- Allow authenticated `PUT`, `PATCH`, and `DELETE` requests to ordinary DSH plugin routes, fixing mobile settings saves that returned `method_not_allowed`. Preserve same-origin, Session, CSRF, body-size, and request limits; document that paired devices operate through the gateway with local DSH privileges. Thanks @Ann-luo for [#150](https://github.com/saya-ch/dsh-mobile/issues/150).
|
package/CONTRIBUTORS.md
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
# 贡献者 / Contributors
|
|
2
2
|
|
|
3
|
-
GitHub 的 [Contributors 图表](https://github.com/saya-ch/dsh-mobile/graphs/contributors) 按进入默认分支的提交自动统计,无法手动加入仅提交 issue 或 PR 提案的成员。本页按截至 2026-10-
|
|
3
|
+
GitHub 的 [Contributors 图表](https://github.com/saya-ch/dsh-mobile/graphs/contributors) 按进入默认分支的提交自动统计,无法手动加入仅提交 issue 或 PR 提案的成员。本页按截至 2026-10-04 的实际参与方式感谢社区成员;仓库维护者与自动依赖更新仍可在 GitHub 历史记录中查看。
|
|
4
4
|
|
|
5
|
-
GitHub's Contributors graph counts commits on the default branch; issue reports and PR proposals cannot be manually added to it. This page credits community members by how they contributed, through 2026-10-
|
|
5
|
+
GitHub's Contributors graph counts commits on the default branch; issue reports and PR proposals cannot be manually added to it. This page credits community members by how they contributed, through 2026-10-04. The repository maintainer and automated dependency updates remain visible in GitHub's history.
|
|
6
6
|
|
|
7
7
|
## 已合并 PR / Merged PRs
|
|
8
8
|
|
|
9
9
|
| 社区成员 / Community member | 已合并 PR / Merged PRs |
|
|
10
10
|
| --- | --- |
|
|
11
11
|
| [@1624318455](https://github.com/1624318455) | [#93](https://github.com/saya-ch/dsh-mobile/pull/93) |
|
|
12
|
-
| [@abworks-dev](https://github.com/abworks-dev) | [#91](https://github.com/saya-ch/dsh-mobile/pull/91), [#98](https://github.com/saya-ch/dsh-mobile/pull/98), [#99](https://github.com/saya-ch/dsh-mobile/pull/99) |
|
|
12
|
+
| [@abworks-dev](https://github.com/abworks-dev) | [#91](https://github.com/saya-ch/dsh-mobile/pull/91), [#98](https://github.com/saya-ch/dsh-mobile/pull/98), [#99](https://github.com/saya-ch/dsh-mobile/pull/99), [#152](https://github.com/saya-ch/dsh-mobile/pull/152) |
|
|
13
13
|
| [@ayiejosh](https://github.com/ayiejosh) | [#109](https://github.com/saya-ch/dsh-mobile/pull/109), [#110](https://github.com/saya-ch/dsh-mobile/pull/110), [#116](https://github.com/saya-ch/dsh-mobile/pull/116), [#117](https://github.com/saya-ch/dsh-mobile/pull/117), [#119](https://github.com/saya-ch/dsh-mobile/pull/119), [#124](https://github.com/saya-ch/dsh-mobile/pull/124), [#125](https://github.com/saya-ch/dsh-mobile/pull/125), [#133](https://github.com/saya-ch/dsh-mobile/pull/133), [#136](https://github.com/saya-ch/dsh-mobile/pull/136) |
|
|
14
|
-
| [@chintoleung](https://github.com/chintoleung) | [#104](https://github.com/saya-ch/dsh-mobile/pull/104), [#147](https://github.com/saya-ch/dsh-mobile/pull/147), [#148](https://github.com/saya-ch/dsh-mobile/pull/148) |
|
|
14
|
+
| [@chintoleung](https://github.com/chintoleung) | [#104](https://github.com/saya-ch/dsh-mobile/pull/104), [#147](https://github.com/saya-ch/dsh-mobile/pull/147), [#148](https://github.com/saya-ch/dsh-mobile/pull/148), [#158](https://github.com/saya-ch/dsh-mobile/pull/158) |
|
|
15
|
+
| [@cjxh21](https://github.com/cjxh21) | [#154](https://github.com/saya-ch/dsh-mobile/pull/154), [#155](https://github.com/saya-ch/dsh-mobile/pull/155) |
|
|
15
16
|
| [@fengfanfan-max](https://github.com/fengfanfan-max) | [#143](https://github.com/saya-ch/dsh-mobile/pull/143) |
|
|
16
17
|
| [@idoall](https://github.com/idoall) | [#61](https://github.com/saya-ch/dsh-mobile/pull/61), [#66](https://github.com/saya-ch/dsh-mobile/pull/66), [#67](https://github.com/saya-ch/dsh-mobile/pull/67), [#77](https://github.com/saya-ch/dsh-mobile/pull/77) |
|
|
17
18
|
| [@JackRushante](https://github.com/JackRushante) | [#16](https://github.com/saya-ch/dsh-mobile/pull/16) |
|
|
@@ -56,6 +57,7 @@ GitHub's Contributors graph counts commits on the default branch; issue reports
|
|
|
56
57
|
| [@LWping](https://github.com/LWping) | [#94](https://github.com/saya-ch/dsh-mobile/issues/94) |
|
|
57
58
|
| [@oliverwan97](https://github.com/oliverwan97) | [#26](https://github.com/saya-ch/dsh-mobile/issues/26) |
|
|
58
59
|
| [@optttt](https://github.com/optttt) | [#111](https://github.com/saya-ch/dsh-mobile/issues/111) |
|
|
60
|
+
| [@qjjer](https://github.com/qjjer) | [#156](https://github.com/saya-ch/dsh-mobile/issues/156) |
|
|
59
61
|
| [@reducm](https://github.com/reducm) | [#127](https://github.com/saya-ch/dsh-mobile/issues/127) |
|
|
60
62
|
| [@rgshendong](https://github.com/rgshendong) | [#87](https://github.com/saya-ch/dsh-mobile/issues/87) |
|
|
61
63
|
| [@RonaldinhoL](https://github.com/RonaldinhoL) | [#89](https://github.com/saya-ch/dsh-mobile/issues/89) |
|
package/README.en.md
CHANGED
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
|
|
32
32
|
> DSH Mobile is a DeepSeek Harness community plugin; the native app supports Android only.
|
|
33
33
|
>
|
|
34
|
-
> **Current
|
|
34
|
+
> **Current stable release: 0.5.5**. Improve the phone composer and model-search input sizes, fix Android model-menu Back, rotation attachment loss and revocation status, and add macOS cloudflared support. [Release notes](CHANGELOG.md#055---2026-10-04).
|
|
35
35
|
>
|
|
36
|
-
> **Upgrade reminder**: update the plugin and Android app together to 0.5.
|
|
36
|
+
> **Upgrade reminder**: update the plugin and Android app together to 0.5.5 for all fixes. Older official apps with the same signer can be upgraded in place while keeping pairings. [Compatibility notes](#compatibility).
|
|
37
37
|
|
|
38
38
|
<p align="center">
|
|
39
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.5.
|
|
40
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.5.
|
|
41
|
-
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.5.
|
|
39
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.5.5/dsh-mobile-android-v0.5.5.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile Android app icon" width="72" height="72"></a><br>
|
|
40
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.5.5/dsh-mobile-android-v0.5.5.apk"><strong>Download Android app 0.5.5</strong></a><br>
|
|
41
|
+
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.5.5">Release notes and checksums</a></sub>
|
|
42
42
|
</p>
|
|
43
43
|
|
|
44
44
|
DSH Mobile is a DeepSeek Harness plugin that lets a mobile browser or the Android app connect over a protected LAN or an optional Tailscale Funnel, cpolar, cloudflared, self-hosted FRP, or own reverse-proxy remote path. Both routes reach the same sessions, Workspaces, messages, and tools. The computer manages their switches and pairing authorizations separately; the Android app lists paired computers together. The plugin does not modify DeepSeek Harness source.
|
|
@@ -60,6 +60,12 @@ It also lets you customize the phone from a DSH conversation: `/mobile <what you
|
|
|
60
60
|
|
|
61
61
|
A paired device can operate DSH on the computer and must be treated as fully trusted. Enable LAN access only on trusted networks, and use a reliable HTTPS channel for remote access. Revoke a lost phone from the computer immediately.
|
|
62
62
|
|
|
63
|
+
## Mobile improvements in 0.5.5
|
|
64
|
+
|
|
65
|
+
At widths up to 720px, an inactive composer retains a scrollable 72px draft preview, leaving more room for the conversation; editor or toolbar focus restores the expanded view. Text, references, and attachments remain intact, and Send, Queue, Steer, and Stop controls have touch targets of at least 44px. Existing DSH and app mechanisms retain submission and IME behavior.
|
|
66
|
+
|
|
67
|
+
Model-search and pairing-page input sizes are corrected, and Android Back navigates the model menu one level at a time. Rotation and window resizing retain the page, references and unsent images; a known **Removed on computer** status survives later checks. Update both the plugin and app. Unsent attachments may still be lost after app-process termination.
|
|
68
|
+
|
|
63
69
|
## Quick start
|
|
64
70
|
|
|
65
71
|
With an installed `dsh` command:
|
|
@@ -151,7 +157,7 @@ Managed self-hosted FRP uses an HTTP vhost to the DSH loopback gateway. Its plai
|
|
|
151
157
|
|
|
152
158
|
The own-proxy HTTP backend must remain on a trusted private network: **never port-forward it publicly or bypass it by proxying to DSH or the existing LAN 3443 gateway**. CIDRs match the proxy's direct TCP peer, not forwarded headers. Preserve the external Host (including port), Origin, cookies and WebSocket. Clearing proxy settings keeps paired remote devices.
|
|
153
159
|
|
|
154
|
-
The public remote origin still requires DSH device pairing. The bundled Funnel and
|
|
160
|
+
The public remote origin still requires DSH device pairing. The bundled Funnel and managed cpolar and cloudflared components support Windows x64 and Linux x64/arm64; cloudflared also supports on-demand installation for macOS x64/arm64. FRP 0.70.1 supports Windows, Linux, and macOS on x64 and arm64. See [Compatibility](#compatibility) for the per-channel OS matrix.
|
|
155
161
|
|
|
156
162
|
## Extend and customize
|
|
157
163
|
|
|
@@ -296,7 +302,7 @@ See [SECURITY.md](SECURITY.md).
|
|
|
296
302
|
|
|
297
303
|
## Troubleshooting
|
|
298
304
|
|
|
299
|
-
- **Pairing succeeds but renewal returns `401` or repeatedly asks to pair again**: other services on the same hostname or stale Cookies may interfere with authentication. Update the plugin and app
|
|
305
|
+
- **Pairing succeeds but renewal returns `401` or repeatedly asks to pair again**: other services on the same hostname or stale Cookies may interfere with authentication. Update to the latest plugin and app, then retry through the current Mobile Access entry. In a browser, scanning the current QR code again refreshes this plugin's authentication Cookies without clearing all website data. If it still fails, inspect the failed request and sanitized logs; other authentication or proxy errors can also return `401`.
|
|
300
306
|
- **The testing notice cannot be confirmed or settings cannot be saved**: open DSH directly at its local address on the computer, then inspect the terminal log or the failed settings request in the browser's Network panel. Connection diagnostics do not test settings writes. Keep the existing configuration and `settings.yaml.imported`, and investigate the specific error; the same UI message can have different causes. See [DSH #860](https://github.com/deepseek-ai/deepseek-harness/discussions/860).
|
|
301
307
|
- **A settings request returns HTTP `403`**: first inspect DSH's Host/Origin trust checks and any proxy response. Check whether an iframe, proxy, or browser extension changes the request's origin, and verify direct local access. Keep the trust checks enabled.
|
|
302
308
|
- **The error contains `profile reload requires the root Include entry`**: this error occurs while DSH reloads the profile. [Issue #132](https://github.com/saya-ch/dsh-mobile/issues/132) reports it after two copies of `dsh-app-boot` were loaded, but the message alone does not establish that cause. Compare the versions and installation paths used by the running DSH command and the active profile; keep the configuration and follow the [official DSH documentation](https://deepseek-harness.github.io/deepseek-harness/) to repair the dependencies. If it still fails, report the versions, module paths, and full sanitized error upstream.
|
|
@@ -318,14 +324,15 @@ Version 0.5.2 keeps the DSH host peer names but does not block installation by D
|
|
|
318
324
|
| Local network | Yes (firewall automated) | Yes (open the firewall yourself) | Yes | Yes |
|
|
319
325
|
| Tailscale Funnel | Yes (bundled) | Yes (bundled) | Yes (bundled) | No |
|
|
320
326
|
| cpolar | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) | No |
|
|
321
|
-
| cloudflared quick/named tunnel | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) |
|
|
327
|
+
| cloudflared quick/named tunnel | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) | Yes, x64/arm64 (on-demand) |
|
|
322
328
|
| Self-hosted FRP | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) |
|
|
323
329
|
| Own reverse proxy | Yes (config only) | Yes (config only) | Yes (config only) | Yes (config only) |
|
|
324
330
|
|
|
325
|
-
On macOS, local network, self-hosted FRP
|
|
331
|
+
On macOS, local network, cloudflared, self-hosted FRP and the own reverse proxy work; Funnel and cpolar have no managed macOS component yet. The diagnostics firewall check currently covers Windows only and reports “not applicable” elsewhere.
|
|
326
332
|
|
|
327
333
|
| DSH Mobile plugin | Verified DeepSeek Harness version |
|
|
328
334
|
| --- | --- |
|
|
335
|
+
| `0.5.5` | `0.1.7-alpha.2`, `0.1.7-rc.1`, `0.1.7-rc.2`, `0.2.0-rc.1`, and `0.2.0-rc.2` (npm installation, isolated pairing, mobile-page boot, and WebSocket Workspace baseline) |
|
|
329
336
|
| `0.5.4` | `0.1.7-alpha.2`, `0.1.7-rc.1`, `0.1.7-rc.2`, `0.2.0-rc.1`, and `0.2.0-rc.2` (npm installation, isolated pairing, mobile-page boot, and WebSocket Workspace baseline) |
|
|
330
337
|
| `0.5.3` | `0.1.7-alpha.2`, `0.1.7-rc.1`, `0.1.7-rc.2`, `0.2.0-rc.1`, and `0.2.0-rc.2` (source contract, npm installation, isolated pairing, mobile-page boot, and WebSocket Workspace baseline) |
|
|
331
338
|
| `0.5.2` | `0.1.7-alpha.2`, `0.1.7-rc.1`, `0.1.7-rc.2`, and `0.2.0-rc.1` (carried forward from earlier verification); `0.2.0-rc.2` (source contract, isolated pairing, mobile-page boot, and WebSocket Workspace baseline) |
|
|
@@ -348,7 +355,7 @@ On macOS, local network, self-hosted FRP, and the own reverse proxy work; the th
|
|
|
348
355
|
|
|
349
356
|
Existing apps (0.3.3 and later) do not need re-pairing. cpolar users should use app 0.3.15 or later because earlier apps may time out before a slow first load over the free route finishes; earlier apps also use a different status-bar strategy. The 0.4.0 app adds the multi-device list, startup behavior, and computer-side revocation status; older apps continue to connect to their saved single device. App 0.1.3 or earlier requires reinstalling and pairing again.
|
|
350
357
|
|
|
351
|
-
Version 0.5.
|
|
358
|
+
Version 0.5.5 keeps the native pairing and renewal protocol compatible, so normally working older apps can continue connecting. Update to app 0.5.5 (build 75) for rotation state preservation, model-menu Back and revocation-status fixes, while retaining the authentication Cookie corrections from 0.5.4.
|
|
352
359
|
|
|
353
360
|
GitHub Release APKs use a stable signing certificate, so an older official APK with the same signer can be upgraded in place while retaining pairings. A locally built Debug APK with a different signer cannot be overwritten by the official APK; plan to pair again when switching between them.
|
|
354
361
|
|
package/README.md
CHANGED
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
|
|
32
32
|
> DSH Mobile 是 DeepSeek Harness 社区插件,原生 App 仅支持 Android。
|
|
33
33
|
>
|
|
34
|
-
>
|
|
34
|
+
> **当前正式版本:0.5.5**。优化手机输入栏与模型搜索字号,修复 Android 模型菜单返回、旋转时附件丢失和撤销状态覆盖,新增 macOS cloudflared 支持。[更新记录](CHANGELOG.md#055---2026-10-04)。
|
|
35
35
|
>
|
|
36
|
-
>
|
|
36
|
+
> **升级提醒**:请同步更新插件与 Android App 至 0.5.5,以获得完整修复;同一正式签名的旧 App 可原位升级并保留配对。[兼容说明](#兼容性)。
|
|
37
37
|
|
|
38
38
|
<p align="center">
|
|
39
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.5.
|
|
40
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.5.
|
|
41
|
-
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.5.
|
|
39
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.5.5/dsh-mobile-android-v0.5.5.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile 安卓应用图标" width="72" height="72"></a><br>
|
|
40
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.5.5/dsh-mobile-android-v0.5.5.apk"><strong>下载 Android App 0.5.5</strong></a><br>
|
|
41
|
+
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.5.5">版本说明与校验文件</a></sub>
|
|
42
42
|
</p>
|
|
43
43
|
|
|
44
44
|
DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App 通过局域网,或可选的 Tailscale Funnel、cpolar、cloudflared、自建 FRP 或自有反向代理远程通道连接电脑,继续使用同一份会话、工作区、消息和工具。电脑端分别启停局域网与远程访问、分别管理配对授权;Android App 统一显示已配对电脑。插件不修改 DeepSeek Harness 源码。
|
|
@@ -60,6 +60,12 @@ DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App
|
|
|
60
60
|
|
|
61
61
|
配对设备可以操作电脑上的 DSH,应视为完全受信任的设备。局域网只在可信网络开启;远程访问应使用可靠的 HTTPS 通道。手机丢失时,请立即从电脑端撤销设备。
|
|
62
62
|
|
|
63
|
+
## 0.5.5 移动体验改进
|
|
64
|
+
|
|
65
|
+
屏幕宽度不超过 720px 时,未编辑的输入栏保留可滚动的 72px 草稿预览,为会话留出更多空间;编辑区或工具栏获得焦点后恢复展开。文字、引用和附件保留,发送、排队、引导与停止按钮的触摸区域至少为 44px。提交和输入法行为继续由既有 DSH 与 App 机制处理。
|
|
66
|
+
|
|
67
|
+
模型搜索框与配对页的输入字号已补齐,Android 返回键可逐级退出模型菜单。App 旋转和调整窗口大小时保留当前页面、引用与未发送图片,已收到的“电脑端已移除”状态不会被后续检测覆盖。请同步更新插件与 App;App 进程终止后,未发送附件仍可能丢失。
|
|
68
|
+
|
|
63
69
|
## 快速开始
|
|
64
70
|
|
|
65
71
|
已经安装 `dsh` 命令:
|
|
@@ -151,7 +157,7 @@ Tailscale Funnel 覆盖范围广,但在中国大陆网络下可能不稳定。
|
|
|
151
157
|
|
|
152
158
|
自有反向代理的 HTTP 后端只允许留在可信私网;**不要把它映射到公网,也不要绕过它直连 DSH 或现有 LAN 3443**。来源 CIDR 匹配代理的直接 TCP 来源,不信任转发头;反代须保留外部 Host(含端口)、Origin、Cookie 和 WebSocket。清除代理配置不会删除已配对远程设备。
|
|
153
159
|
|
|
154
|
-
远程公开地址仍受 DSH 设备配对保护。内置 Funnel 与托管 cpolar、cloudflared 支持 Windows x64 与 Linux x64/arm64
|
|
160
|
+
远程公开地址仍受 DSH 设备配对保护。内置 Funnel 与托管 cpolar、cloudflared 支持 Windows x64 与 Linux x64/arm64;cloudflared 还支持 macOS x64/arm64 按需安装。FRP 0.70.1 支持 Windows、Linux、macOS 的 x64 与 arm64。各通道的系统支持矩阵见[兼容性](#兼容性)。
|
|
155
161
|
|
|
156
162
|
## 扩展与自定义
|
|
157
163
|
|
|
@@ -297,7 +303,7 @@ flowchart LR
|
|
|
297
303
|
|
|
298
304
|
## 故障排查
|
|
299
305
|
|
|
300
|
-
- **配对成功后仍反复提示重新配对或续期 `401`**:同一域名上的其他服务或旧 Cookie
|
|
306
|
+
- **配对成功后仍反复提示重新配对或续期 `401`**:同一域名上的其他服务或旧 Cookie 可能干扰认证。更新至最新插件及 App,再从当前移动访问入口重试;浏览器重新扫描当前二维码可更新本插件的认证 Cookie,无需清除所有网站数据。若仍失败,查看失败请求与脱敏日志,其他认证或代理错误也可能返回 `401`。
|
|
301
307
|
- **内测声明无法确认或设置无法保存**:先在电脑端直接打开 DSH 的本机地址,查看终端日志或浏览器 Network 中失败的设置请求。连接诊断不检查设置写入;保留现有配置及 `settings.yaml.imported`,按具体错误排查。相同界面提示可能有不同原因,见 [DSH #860](https://github.com/deepseek-ai/deepseek-harness/discussions/860)。
|
|
302
308
|
- **设置请求返回 HTTP `403`**:先检查 DSH 的 Host/Origin 信任校验及代理响应。检查 iframe、代理和浏览器扩展是否改变请求来源,使用本机直接访问验证;保持信任检查启用。
|
|
303
309
|
- **错误包含 `profile reload requires the root Include entry`**:该错误发生在 DSH 重载 profile 时。[Issue #132](https://github.com/saya-ch/dsh-mobile/issues/132) 报告过加载两份 `dsh-app-boot` 导致此错误,但单凭提示不能确认原因。核对实际运行的 DSH 命令与当前 profile 的版本和安装路径,保留配置并按 [DSH 官方文档](https://deepseek-harness.github.io/deepseek-harness/)修复依赖;仍失败时将版本、模块路径及脱敏后的完整错误提交上游。
|
|
@@ -319,14 +325,15 @@ flowchart LR
|
|
|
319
325
|
| 局域网 | 支持(自动配防火墙) | 支持(防火墙自理) | 支持 | 支持 |
|
|
320
326
|
| Tailscale Funnel | 支持(随包提供) | 支持(随包提供) | 支持(随包提供) | 不支持 |
|
|
321
327
|
| cpolar | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) | 不支持 |
|
|
322
|
-
| cloudflared 快速/命名隧道 | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) |
|
|
328
|
+
| cloudflared 快速/命名隧道 | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) | 支持 x64/arm64(按需下载) |
|
|
323
329
|
| 自建 FRP | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) |
|
|
324
330
|
| 自有反向代理 | 支持(纯配置) | 支持(纯配置) | 支持(纯配置) | 支持(纯配置) |
|
|
325
331
|
|
|
326
|
-
macOS
|
|
332
|
+
macOS 上局域网、cloudflared、自建 FRP 与自有反向代理可用;Funnel 与 cpolar 暂未提供 macOS 组件。诊断页的防火墙检查目前仅覆盖 Windows,其他系统显示“不适用”。
|
|
327
333
|
|
|
328
334
|
| DSH Mobile 插件 | 验证支持的 DeepSeek Harness 版本 |
|
|
329
335
|
| ----------------------------------------- | -------------------------------------------------------------- |
|
|
336
|
+
| `0.5.5` | `0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2`、`0.2.0-rc.1`、`0.2.0-rc.2`(npm 打包安装、隔离配对、移动页面启动及 WebSocket 工作区读取) |
|
|
330
337
|
| `0.5.4` | `0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2`、`0.2.0-rc.1`、`0.2.0-rc.2`(npm 打包安装、隔离配对、移动页面启动及 WebSocket 工作区读取) |
|
|
331
338
|
| `0.5.3` | `0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2`、`0.2.0-rc.1`、`0.2.0-rc.2`(源码契约、npm 打包安装、隔离配对、移动页面启动及 WebSocket 工作区读取) |
|
|
332
339
|
| `0.5.2` | `0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2`、`0.2.0-rc.1`(延续既有验证);`0.2.0-rc.2`(源码契约、隔离配对、移动页面启动和 WebSocket 工作区读取) |
|
|
@@ -349,7 +356,7 @@ macOS 上局域网、自建 FRP 与自有反向代理可用;三个托管组件
|
|
|
349
356
|
|
|
350
357
|
现有 App(0.3.3 及更新)无需重新配对;cpolar 用户应使用 0.3.15 或更新 App,较早版本可能在免费线路的慢速首次加载完成前超时;更早的 App 还使用不同的状态栏策略。App 0.4.0 才支持多设备列表、启动行为设置和电脑端撤销状态同步;旧版 App 仍可连接已保存的单台设备。App 0.1.3 及更早版本需卸载重装并重新配对。
|
|
351
358
|
|
|
352
|
-
0.5.
|
|
359
|
+
0.5.5 的原生配对与续期协议保持兼容,旧 App 的正常连接可继续使用;建议同步升级至 0.5.5(build 75),以获得旋转保持页面、模型菜单返回和撤销状态修复,同时保留 0.5.4 的认证 Cookie 修正。
|
|
353
360
|
|
|
354
361
|
GitHub Release 的正式 APK 使用固定签名,可从同一签名的旧正式版原位升级并保留配对。自行构建的 Debug APK 若使用不同签名,不能直接覆盖安装正式版;切换前请准备重新配对。
|
|
355
362
|
|
|
@@ -385,7 +392,7 @@ npm run verify
|
|
|
385
392
|
|
|
386
393
|
修改提问卡片或移动布局时,完成构建后运行 `npx playwright install chromium --only-shell`、`npm run smoke:question-fixes` 和 `npm run smoke:native-layout`,检查实际客户端产物的滚动、键盘与布局行为。
|
|
387
394
|
|
|
388
|
-
真实启动冒烟另用临时 DSH Home、随机回环端口和 Chromium
|
|
395
|
+
真实启动冒烟另用临时 DSH Home、随机回环端口和 Chromium 配对,不访问现有用户配置,也不发送模型请求。CI 分别测试 DSH `0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2`、`0.2.0-rc.1` 与 `0.2.0-rc.2`;本机可把 DSH `0.2.0-rc.2` 装在独立目录,避免替换插件的开发依赖:
|
|
389
396
|
|
|
390
397
|
```powershell
|
|
391
398
|
$dshMobileTestRuntime = Join-Path $env:TEMP 'dsh-mobile-test-runtime'
|
|
@@ -20,6 +20,8 @@ Cloudflare terminates DNS and TLS for the public hostname. The plugin only runs
|
|
|
20
20
|
2. Cloudflare Zero Trust (a team domain) enabled, because the tunnel console lives inside it.
|
|
21
21
|
3. The cloudflared component installed in the panel. Named and quick tunnels share the same official client.
|
|
22
22
|
|
|
23
|
+
The component supports Windows x64, Linux x64/arm64 and macOS x64/arm64. Official downloads are verified before installation; macOS also verifies the extracted executable. Components remain inside DSH Mobile's private directory.
|
|
24
|
+
|
|
23
25
|
## Create the tunnel in the Cloudflare dashboard
|
|
24
26
|
|
|
25
27
|
1. Open **Zero Trust → Networks → Tunnels** and choose **Create a tunnel** → **Cloudflared**.
|
|
@@ -79,7 +81,7 @@ The old address may show **Address may have changed** or temporarily unreachable
|
|
|
79
81
|
| Could not reserve a local port | `cloudflared_port_reservation_failed` | Reserving the loopback port failed for a reason other than the port being busy. Retry, and check system resources if it persists. |
|
|
80
82
|
| Component download failed verification | `cloudflared_download_hash_mismatch` / `cloudflared_download_size_mismatch` | The downloaded binary does not match the pinned size or SHA-256. Install again; repeated failures mean something is rewriting the transfer. |
|
|
81
83
|
| Installed component failed verification | `cloudflared_executable_hash_mismatch` | The local cloudflared no longer matches the verified build. Remove it completely and install again. |
|
|
82
|
-
| This build cannot run the component | `cloudflared_component_unsupported` | The platform is outside the supported set (
|
|
84
|
+
| This build cannot run the component | `cloudflared_component_unsupported` | The platform is outside the supported set (Windows x64, Linux x64/arm64 and macOS x64/arm64). |
|
|
83
85
|
| Timed out waiting for the tunnel | `cloudflared_start_timeout` | The connector did not print `Registered tunnel connection` within the startup budget. In named mode a live connector keeps waiting (up to about 5 minutes); usually it cannot reach a Cloudflare edge. |
|
|
84
86
|
| Component not installed | `cloudflared_component_missing` | The official component is absent. Complete the preparation steps above. |
|
|
85
87
|
| Component verification failed | `cloudflared_component_invalid` | The local component does not match the verified build. Remove it completely and install again. |
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
2. Cloudflare Zero Trust(团队域名)已启用——隧道控制台位于其中。
|
|
21
21
|
3. 面板中 cloudflared 组件已安装(命名隧道和快速隧道使用同一个官方客户端)。
|
|
22
22
|
|
|
23
|
+
组件支持 Windows x64、Linux x64/arm64 与 macOS x64/arm64。所有平台都在安装前校验官方发布文件;macOS 另校验解压后的可执行文件,组件仅保存在 DSH Mobile 私有目录。
|
|
24
|
+
|
|
23
25
|
## 在 Cloudflare 控制台创建隧道
|
|
24
26
|
|
|
25
27
|
1. 打开 **Zero Trust → Networks → Tunnels**,选择 **Create a tunnel**,类型选 **Cloudflared**。
|
|
@@ -79,7 +81,7 @@
|
|
|
79
81
|
| 无法预留本机端口 | `cloudflared_port_reservation_failed` | 本机端口预留本身失败(不是端口被占)。重试;若持续出现请检查系统资源。 |
|
|
80
82
|
| 组件下载校验失败 | `cloudflared_download_hash_mismatch` / `cloudflared_download_size_mismatch` | 下载到的二进制与固定版本的大小或 SHA-256 不符。重新安装;若反复失败说明中间链路在改包。 |
|
|
81
83
|
| 已安装组件校验失败 | `cloudflared_executable_hash_mismatch` | 本机那份 cloudflared 与校验过的版本不一致。彻底移除后重新安装。 |
|
|
82
|
-
| 当前构建不支持该组件 | `cloudflared_component_unsupported` |
|
|
84
|
+
| 当前构建不支持该组件 | `cloudflared_component_unsupported` | 当前平台不在支持范围内(支持 Windows x64、Linux x64/arm64 与 macOS x64/arm64)。 |
|
|
83
85
|
| 等待隧道可用超时 | `cloudflared_start_timeout` | connector 在超时预算内没有打印 `Registered tunnel connection`。命名隧道下进程活着会继续等(最多约 5 分钟);常见原因是网络到 Cloudflare 边缘不通。 |
|
|
84
86
|
| 组件未安装 | `cloudflared_component_missing` | 还没安装官方组件。按上面的准备步骤安装。 |
|
|
85
87
|
| 组件校验失败 | `cloudflared_component_invalid` | 本机组件与校验过的版本不符。彻底移除后重新安装。 |
|
package/lib/client.js
CHANGED
|
@@ -1212,7 +1212,7 @@ window.__ModuleLoader__.load({
|
|
|
1212
1212
|
cloudflaredBadge: "Account optional",
|
|
1213
1213
|
cloudflaredDescription: "Installs the official cloudflared client on demand. A quick tunnel needs no account and gives a temporary public address; a named tunnel uses a Cloudflare account token and keeps one hostname that survives restarts.",
|
|
1214
1214
|
prepareCloudflared: "Prepare cloudflared",
|
|
1215
|
-
cloudflaredUnsupported: "Windows x64 and
|
|
1215
|
+
cloudflaredUnsupported: "Windows x64, Linux x64/arm64, and macOS x64/arm64 are supported.",
|
|
1216
1216
|
cloudflaredNotInstalled: "Not installed. A fixed version is downloaded from the official cloudflared release page only after you click the button below.",
|
|
1217
1217
|
cloudflaredReady: "Official component {version} is ready.",
|
|
1218
1218
|
cloudflaredQuickNote: "Quick tunnel: no Cloudflare account is needed, but Cloudflare positions quick tunnels for testing — the address is random, rate-limited, and carries no uptime guarantee. Do not rely on one for access that must stay reachable.",
|
|
@@ -1280,7 +1280,7 @@ window.__ModuleLoader__.load({
|
|
|
1280
1280
|
cloudflaredBadge: "Account facoltativo",
|
|
1281
1281
|
cloudflaredDescription: "Installa su richiesta il client cloudflared ufficiale. Il tunnel rapido non richiede account e fornisce un indirizzo pubblico temporaneo; il tunnel con nome usa il token di un account Cloudflare e mantiene un hostname stabile tra i riavvii.",
|
|
1282
1282
|
prepareCloudflared: "Prepara cloudflared",
|
|
1283
|
-
cloudflaredUnsupported: "
|
|
1283
|
+
cloudflaredUnsupported: "Sono supportati Windows x64, Linux x64/arm64 e macOS x64/arm64.",
|
|
1284
1284
|
cloudflaredNotInstalled: "Non installato. Una versione fissa viene scaricata dalla pagina ufficiale di cloudflared solo dopo aver premuto il pulsante.",
|
|
1285
1285
|
cloudflaredReady: "Componente ufficiale {version} pronto.",
|
|
1286
1286
|
cloudflaredQuickNote: "Tunnel rapido: non serve un account Cloudflare, ma Cloudflare li considera pensati per i test — l’indirizzo è casuale, soggetto a limiti di frequenza e senza garanzia di disponibilità. Non usarlo per un accesso che deve restare raggiungibile.",
|
|
@@ -1348,7 +1348,7 @@ window.__ModuleLoader__.load({
|
|
|
1348
1348
|
cloudflaredBadge: "账号可选",
|
|
1349
1349
|
cloudflaredDescription: "按需安装官方 cloudflared 客户端。快速隧道无需账号,提供临时公网地址;命名隧道使用 Cloudflare 账号令牌,地址固定、重启不变。",
|
|
1350
1350
|
prepareCloudflared: "准备 cloudflared",
|
|
1351
|
-
cloudflaredUnsupported: "
|
|
1351
|
+
cloudflaredUnsupported: "支持 Windows x64、Linux x64/arm64 与 macOS x64/arm64。",
|
|
1352
1352
|
cloudflaredNotInstalled: "尚未安装。只有点击下方按钮后,才会从 cloudflared 官方发布页下载固定版本。",
|
|
1353
1353
|
cloudflaredReady: "官方组件 {version} 已就绪。",
|
|
1354
1354
|
cloudflaredQuickNote: "快速隧道:无需 Cloudflare 账号,但官方定位是测试用途 —— 地址随机、有限流、无可用性保证。请勿用于必须长期可达的访问。",
|
|
@@ -2631,7 +2631,13 @@ window.__ModuleLoader__.load({
|
|
|
2631
2631
|
the query restores the fixed scrim, and its more specific [hidden] rule
|
|
2632
2632
|
keeps winning there. */
|
|
2633
2633
|
.dsh-native-mobile-backdrop,.dsh-mobile-branch-toast,.dsh-mobile-media-toast { display:none; }
|
|
2634
|
-
/* The content-font preference may exceed Safari's focused-editable minimum.
|
|
2634
|
+
/* The content-font preference may exceed Safari's focused-editable minimum.
|
|
2635
|
+
The html-level class exists on every non-desktop mobile page, so it also
|
|
2636
|
+
covers body-level portals (model picker search) the center column never
|
|
2637
|
+
contained; the center marker stays alongside it because a disposed
|
|
2638
|
+
surface removes the html class while styles applied from its string can
|
|
2639
|
+
outlive the class on a page that still carries the center column. */
|
|
2640
|
+
html.dsh-native-mobile-active :is(input,textarea,[contenteditable="true"],[contenteditable="plaintext-only"],[contenteditable=""]),
|
|
2635
2641
|
[data-dsh-mobile-center] :is(input,textarea,[contenteditable="true"],[contenteditable="plaintext-only"],[contenteditable=""]) { font-size:max(16px,1em,var(--dsh-content-font-size,1em)) !important; }
|
|
2636
2642
|
.dsh-mobile-settings_row { display:flex; align-items:center; gap:8px; padding:16px 0; border-bottom:0.5px solid var(--dsw-alias-border-l2); }
|
|
2637
2643
|
.dsh-mobile-settings_rowText { flex:1; min-width:0; display:flex; flex-direction:column; gap:4px; padding-right:48px; }
|
|
@@ -2751,12 +2757,15 @@ window.__ModuleLoader__.load({
|
|
|
2751
2757
|
[data-dsh-mobile-message-column] [class*="_body"] { max-width:100% !important; overflow-wrap:anywhere; }
|
|
2752
2758
|
/* Keep folded and expanded reasoning visually separate from the reply. */
|
|
2753
2759
|
[data-dsh-mobile-message-column] [class*="_body"] > div:has(> [data-variant="think"]) { margin-bottom:12px !important; }
|
|
2754
|
-
[data-dsh-mobile-center] [data-composer-card] ~ [class*="_root"],
|
|
2755
|
-
[data-dsh-mobile-center] [data-composer-card] ~ * [class*="_root"] { box-sizing:border-box !important; width:100% !important; max-width:100% !important; margin-bottom:-6px !important; padding:3px 4px 0 !important; font-size:11px !important; line-height:18px !important; white-space:normal !important; overflow:visible !important; text-overflow:clip !important; }
|
|
2760
|
+
[data-dsh-mobile-center] [data-composer-card] ~ [class*="_root"]:not(:where(input,textarea,[contenteditable])),
|
|
2761
|
+
[data-dsh-mobile-center] [data-composer-card] ~ * [class*="_root"]:not(:where(input,textarea,[contenteditable])) { box-sizing:border-box !important; width:100% !important; max-width:100% !important; margin-bottom:-6px !important; padding:3px 4px 0 !important; font-size:11px !important; line-height:18px !important; white-space:normal !important; overflow:visible !important; text-overflow:clip !important; }
|
|
2756
2762
|
[data-dsh-mobile-center] [data-composer-card] ~ [class*="_root"] [class*="_sep"],
|
|
2757
2763
|
[data-dsh-mobile-center] [data-composer-card] ~ * [class*="_root"] [class*="_sep"] { margin:0 6px !important; }
|
|
2758
|
-
/* Composer dock stats strip (turns/steps/tokens) reads small on phones.
|
|
2759
|
-
|
|
2764
|
+
/* Composer dock stats strip (turns/steps/tokens) reads small on phones.
|
|
2765
|
+
:not(:where(...)) keeps editables exempt at zero specificity cost, so
|
|
2766
|
+
the small !important fonts cannot beat the 16px editable floor while
|
|
2767
|
+
the dock spacing rules keep their cascade position. */
|
|
2768
|
+
[data-dsh-mobile-center] [data-slot="conversation.composer.dock"] [class*="_root"]:not(:where(input,textarea,[contenteditable])) { font-size:10px !important; line-height:16px !important; }
|
|
2760
2769
|
/* The context ring is a composer-metadata _root too, so the metadata rule
|
|
2761
2770
|
above stretched it across the whole dock. It cannot shrink, which left the
|
|
2762
2771
|
session statistics beside it a few pixels wide, every number clipped to an
|
|
@@ -2813,7 +2822,13 @@ window.__ModuleLoader__.load({
|
|
|
2813
2822
|
.dsh-mobile-media-action svg { flex:none; width:16px; height:16px; color:var(--dsw-alias-label-tertiary,currentColor); }
|
|
2814
2823
|
.dsh-mobile-media-action span { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
2815
2824
|
[data-dsh-mobile-center] [class*="_composer"] { padding-left:8px !important; padding-right:8px !important; padding-bottom:max(8px,env(safe-area-inset-bottom)) !important; }
|
|
2816
|
-
/*
|
|
2825
|
+
/* Collapse the scroll viewport only; the editor, draft and attachments stay
|
|
2826
|
+
owned by DSH. Toolbar focus keeps the card expanded during menu taps. */
|
|
2827
|
+
[data-dsh-mobile-center] [data-composer-card]:not(:focus-within) > [data-input-scroll] { max-height:72px !important; overflow-y:auto !important; }
|
|
2828
|
+
/* Stock Send/Queue/Steer and Stop keep their handlers and disabled state. */
|
|
2829
|
+
[data-dsh-mobile-composer-row] button { min-height:44px !important; touch-action:manipulation; }
|
|
2830
|
+
[data-dsh-mobile-composer-row] button[class*="_primary"] { min-width:44px !important; flex-shrink:0 !important; }
|
|
2831
|
+
/* The desktop composer intentionally wraps whole toolbar groups. On a phone,
|
|
2817
2832
|
dynamic model and status labels made that row alternate between one and
|
|
2818
2833
|
two lines. Keep two stable columns and let only the model label shrink. */
|
|
2819
2834
|
[data-dsh-mobile-composer-row] { display:grid !important; grid-template-columns:max-content minmax(0,1fr) !important; align-items:center !important; gap:4px 8px !important; }
|
|
@@ -3997,6 +4012,7 @@ window.__ModuleLoader__.load({
|
|
|
3997
4012
|
}
|
|
3998
4013
|
/**
|
|
3999
4014
|
* Consume page-level surfaces and dismissible DSH overlays before layout navigation.
|
|
4015
|
+
* Composer model popups use DSH's Escape handling to return from a pane before closing.
|
|
4000
4016
|
* @param view - the page window receiving the native Back request.
|
|
4001
4017
|
* @param page - the current DSH document.
|
|
4002
4018
|
* @param blocked - feedback for a foreground layer without a safe close action.
|
|
@@ -4015,10 +4031,35 @@ window.__ModuleLoader__.load({
|
|
|
4015
4031
|
claim();
|
|
4016
4032
|
return;
|
|
4017
4033
|
}
|
|
4018
|
-
const
|
|
4034
|
+
const modelPopups = /* @__PURE__ */ new Map();
|
|
4035
|
+
for (const trigger of page.querySelectorAll("[data-dsh-mobile-composer-model-trigger][aria-expanded=\"true\"]")) {
|
|
4036
|
+
const popupId = trigger.getAttribute("aria-controls");
|
|
4037
|
+
const popup = popupId === null ? null : page.getElementById(popupId);
|
|
4038
|
+
if (popup !== null && visibleBackLayer(view, trigger) && visibleBackLayer(view, popup) && (popup.getAttribute("role") === "menu" || popup.getAttribute("role") === "group")) modelPopups.set(popup, trigger);
|
|
4039
|
+
}
|
|
4040
|
+
const layers = [...page.querySelectorAll("[role=\"dialog\"][aria-modal=\"true\"], [role=\"menu\"], [role=\"group\"][id]")].filter((element) => visibleBackLayer(view, element) && (element.getAttribute("role") !== "group" || modelPopups.has(element)));
|
|
4019
4041
|
const top = layers.at(-1);
|
|
4020
4042
|
if (top === void 0) return;
|
|
4021
4043
|
claim();
|
|
4044
|
+
const modelEntry = [...modelPopups].find(([popup]) => popup.contains(top));
|
|
4045
|
+
if (modelEntry !== void 0) {
|
|
4046
|
+
const [modelPopup, trigger] = modelEntry;
|
|
4047
|
+
if (layers.some((layer) => !modelPopup.contains(layer))) {
|
|
4048
|
+
blocked();
|
|
4049
|
+
return;
|
|
4050
|
+
}
|
|
4051
|
+
const focused = page.activeElement;
|
|
4052
|
+
const target = focused !== null && modelPopup.contains(focused) ? focused : trigger;
|
|
4053
|
+
const escape = new KeyboardEvent("keydown", {
|
|
4054
|
+
key: "Escape",
|
|
4055
|
+
code: "Escape",
|
|
4056
|
+
bubbles: true,
|
|
4057
|
+
cancelable: true
|
|
4058
|
+
});
|
|
4059
|
+
target.dispatchEvent(escape);
|
|
4060
|
+
if (!escape.defaultPrevented) blocked();
|
|
4061
|
+
return;
|
|
4062
|
+
}
|
|
4022
4063
|
if (top.getAttribute("role") === "dialog") {
|
|
4023
4064
|
const wrapper = top.parentElement;
|
|
4024
4065
|
const mask = wrapper?.firstElementChild;
|