dsh-mobile 0.5.3 → 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 CHANGED
@@ -2,6 +2,28 @@
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
+
16
+ ## 0.5.4 - 2026-10-02
17
+
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).
19
+ - Resolve pairing and renewal conflicts from same-name Cookies on a shared hostname. Handle authentication Cookies individually, use protected Host-session/CSRF Cookies and a non-secret device binding, and keep the persistent device credential restricted to its renewal path. Android 0.5.4 (build 74) writes matching session/CSRF aliases so stale WebView Cookies can be replaced; the native pairing and renewal protocol remains compatible. Thanks @snailium for [#144](https://github.com/saya-ch/dsh-mobile/issues/144).
20
+ - Set a 16px minimum for mobile editables, including empty `contenteditable` attributes, while retaining larger inherited text and DSH font preferences on narrow and wide layouts. Thanks @chintoleung for [PR #147](https://github.com/saya-ch/dsh-mobile/pull/147).
21
+ - Dismiss the software keyboard after a trusted touch Send, Queue, or Steer consumes the active draft, including references, attachments, and asynchronous commands. Preserve keyboard, menu, Stop, and IME composition handling; cancel pending checks when input, focus, Session, or layout changes. Thanks @chintoleung for [PR #148](https://github.com/saya-ch/dsh-mobile/pull/148).
22
+ - Add optional WebSocket compression on exact, already authorized paths. The default remains an uncompressed relay; enabled paths negotiate stateless compression with the browser while keeping the DSH side uncompressed and relaying real Ping/Pong frames. Bound message and queue sizes; see the [configuration guide](docs/SLOW_CONNECTIONS.en.md#optional-websocket-compression). Thanks @xhwxt for [#145](https://github.com/saya-ch/dsh-mobile/issues/145).
23
+ - Add a [slow-link and reconnection guide](docs/SLOW_CONNECTIONS.en.md) covering WebSocket failures, DSH heartbeat and initialization settings, and the tradeoffs of longer deadlines. Thanks @xhwxt for [#146](https://github.com/saya-ch/dsh-mobile/issues/146).
24
+ - Verify the question-card component from a real npm tarball installed in an isolated DSH profile, using DSH's own dependency resolver and boot discovery. Preserve the bundled component distribution and strengthen installation checks. Thanks @fengfanfan-max for [PR #143](https://github.com/saya-ch/dsh-mobile/pull/143).
25
+ - Remove the obsolete `session.history` HTTP request clamp and endpoint-specific gzip handling. DSH versions in the current compatibility matrix use `session.follow` and `session.page` over WebSocket; DSH controls their history window and page budgets. Correct the README's 10-message paging claim. Thanks @xhwxt for [#149](https://github.com/saya-ch/dsh-mobile/issues/149).
26
+
5
27
  ## 0.5.3 - 2026-10-01
6
28
 
7
29
  - Add a default-enabled, separately switchable question-card component: long questions, options, and footer actions share one bounded scroll area, while collapsed titles show up to two lines. Keep touch Enter as a newline without intercepting desktop shortcuts or IME composition; Android applies it only with an active software keyboard and no hardware keyboard. Answers remain in DSH's existing draft store rather than browser localStorage. Thanks @ayiejosh for [PR #133](https://github.com/saya-ch/dsh-mobile/pull/133).
package/CONTRIBUTORS.md CHANGED
@@ -1,17 +1,19 @@
1
1
  # 贡献者 / Contributors
2
2
 
3
- GitHub 的 [Contributors 图表](https://github.com/saya-ch/dsh-mobile/graphs/contributors) 按进入默认分支的提交自动统计,无法手动加入仅提交 issue 或 PR 提案的成员。本页按实际参与方式感谢社区成员;仓库维护者与自动依赖更新仍可在 GitHub 历史记录中查看。
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-01. The repository maintainer and automated dependency updates remain visible in GitHub's history.
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) |
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) |
16
+ | [@fengfanfan-max](https://github.com/fengfanfan-max) | [#143](https://github.com/saya-ch/dsh-mobile/pull/143) |
15
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) |
16
18
  | [@JackRushante](https://github.com/JackRushante) | [#16](https://github.com/saya-ch/dsh-mobile/pull/16) |
17
19
  | [@liudasheng](https://github.com/liudasheng) | [#100](https://github.com/saya-ch/dsh-mobile/pull/100), [#130](https://github.com/saya-ch/dsh-mobile/pull/130) |
@@ -37,6 +39,7 @@ GitHub's Contributors graph counts commits on the default branch; issue reports
37
39
  | 反馈贡献者 / Issue reporter | 提交的问题 / Issues |
38
40
  | --- | --- |
39
41
  | [@1624318455](https://github.com/1624318455) | [#92](https://github.com/saya-ch/dsh-mobile/issues/92) |
42
+ | [@Ann-luo](https://github.com/Ann-luo) | [#150](https://github.com/saya-ch/dsh-mobile/issues/150) |
40
43
  | [@azri57806-design](https://github.com/azri57806-design) | [#97](https://github.com/saya-ch/dsh-mobile/issues/97) |
41
44
  | [@BrainZombie](https://github.com/BrainZombie) | [#128](https://github.com/saya-ch/dsh-mobile/issues/128) |
42
45
  | [@CESAEREE](https://github.com/CESAEREE) | [#1](https://github.com/saya-ch/dsh-mobile/issues/1) |
@@ -54,10 +57,12 @@ GitHub's Contributors graph counts commits on the default branch; issue reports
54
57
  | [@LWping](https://github.com/LWping) | [#94](https://github.com/saya-ch/dsh-mobile/issues/94) |
55
58
  | [@oliverwan97](https://github.com/oliverwan97) | [#26](https://github.com/saya-ch/dsh-mobile/issues/26) |
56
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) |
57
61
  | [@reducm](https://github.com/reducm) | [#127](https://github.com/saya-ch/dsh-mobile/issues/127) |
58
62
  | [@rgshendong](https://github.com/rgshendong) | [#87](https://github.com/saya-ch/dsh-mobile/issues/87) |
59
63
  | [@RonaldinhoL](https://github.com/RonaldinhoL) | [#89](https://github.com/saya-ch/dsh-mobile/issues/89) |
60
64
  | [@shengyvself](https://github.com/shengyvself) | [#13](https://github.com/saya-ch/dsh-mobile/issues/13), [#14](https://github.com/saya-ch/dsh-mobile/issues/14) |
65
+ | [@snailium](https://github.com/snailium) | [#144](https://github.com/saya-ch/dsh-mobile/issues/144) |
61
66
  | [@sznyhgm](https://github.com/sznyhgm) | [#96](https://github.com/saya-ch/dsh-mobile/issues/96) |
62
67
  | [@sortjiajun](https://github.com/sortjiajun) | [#90](https://github.com/saya-ch/dsh-mobile/issues/90) |
63
68
  | [@StrawberryAO](https://github.com/StrawberryAO) | [#39](https://github.com/saya-ch/dsh-mobile/issues/39) |
@@ -66,6 +71,6 @@ GitHub's Contributors graph counts commits on the default branch; issue reports
66
71
  | [@taki-ohh](https://github.com/taki-ohh) | [#19](https://github.com/saya-ch/dsh-mobile/issues/19) |
67
72
  | [@tianyimc](https://github.com/tianyimc) | [#126](https://github.com/saya-ch/dsh-mobile/issues/126) |
68
73
  | [@Xingcheng-wang](https://github.com/Xingcheng-wang) | [#76](https://github.com/saya-ch/dsh-mobile/issues/76) |
69
- | [@xhwxt](https://github.com/xhwxt) | [#107](https://github.com/saya-ch/dsh-mobile/issues/107), [#108](https://github.com/saya-ch/dsh-mobile/issues/108) |
74
+ | [@xhwxt](https://github.com/xhwxt) | [#107](https://github.com/saya-ch/dsh-mobile/issues/107), [#108](https://github.com/saya-ch/dsh-mobile/issues/108), [#145](https://github.com/saya-ch/dsh-mobile/issues/145), [#146](https://github.com/saya-ch/dsh-mobile/issues/146), [#149](https://github.com/saya-ch/dsh-mobile/issues/149) |
70
75
  | [@Yurzi](https://github.com/Yurzi) | [#17](https://github.com/saya-ch/dsh-mobile/issues/17) |
71
76
  | [@Ztyss](https://github.com/Ztyss) | [#22](https://github.com/saya-ch/dsh-mobile/issues/22), [#23](https://github.com/saya-ch/dsh-mobile/issues/23) |
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 version: 0.5.3**. Improve question cards, folded-process spacing, and composer layout with community plugins; refine focus and screen wake-lock handling during dictation, and expand troubleshooting for failed settings saves. [Release notes](CHANGELOG.md#053---2026-10-01).
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**: the plugin and Android app can both be updated to 0.5.3. This APK only synchronizes version metadata; existing devices do not need re-pairing. [Compatibility notes](#compatibility).
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.3/dsh-mobile-android-v0.5.3.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.3/dsh-mobile-android-v0.5.3.apk"><strong>Download Android app 0.5.3</strong></a><br>
41
- <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.5.3">Release notes and checksums</a></sub>
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:
@@ -124,7 +130,9 @@ Browser pairing and reauthentication pages use the browser's `Accept-Language` t
124
130
 
125
131
  Use this after the phone leaves the computer's network. Remote access is disabled by default, and the phone needs no separate Tailscale, cpolar, cloudflared, or FRP app.
126
132
 
127
- Remote providers may impose bandwidth and connection limits: the [cpolar Free plan](https://svip.cpolar.com/pricing) currently lists 1 Mbps, while [Tailscale Funnel](https://tailscale.com/docs/features/tailscale-funnel#requirements-and-limitations) has non-configurable bandwidth limits, and a cloudflared quick tunnel is a free Cloudflare address with randomized hostnames and rate limiting. DSH Mobile reduces transfer and waiting with 10-message pages, load-on-scroll history, gzip, and a persistent WebSocket, but it cannot raise provider quotas.
133
+ Remote providers may impose bandwidth and connection limits: the [cpolar Free plan](https://svip.cpolar.com/pricing) currently lists 1 Mbps, while [Tailscale Funnel](https://tailscale.com/docs/features/tailscale-funnel#requirements-and-limitations) has non-configurable bandwidth limits, and a cloudflared quick tunnel is a free Cloudflare address with randomized hostnames and rate limiting. DSH Mobile uses gzip for static assets, persistent WebSockets, and load-on-scroll history to improve loading; DSH controls the Session history window and page sizes, and the plugin cannot raise provider quotas.
134
+
135
+ If the page opens but stays on “Reconnecting,” distinguish WebSocket upgrade failures, slow synchronization, and heartbeat deadlines using the [slow-link and reconnection guide](docs/SLOW_CONNECTIONS.en.md). Version 0.5.4 also offers opt-in WebSocket compression per exact path, disabled by default; for long Sessions or metered links, follow the guide and compare actual transfer volume.
128
136
 
129
137
  <p align="center">
130
138
  <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/remote-access-en.png" width="82%" alt="DSH Mobile remote access and provider selection">
@@ -149,7 +157,7 @@ Managed self-hosted FRP uses an HTTP vhost to the DSH loopback gateway. Its plai
149
157
 
150
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.
151
159
 
152
- The public remote origin still requires DSH device pairing. The bundled Funnel and the managed cpolar and cloudflared components support Windows x64 and Linux x64/arm64; on-demand FRP 0.70.1 supports Windows, Linux, and macOS on x64 and arm64. See [Compatibility](#compatibility) for the per-channel OS matrix.
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.
153
161
 
154
162
  ## Extend and customize
155
163
 
@@ -287,12 +295,14 @@ Three layers: the Host face for discovery, pairing, HTTPS, loopback proxying, an
287
295
  - cloudflared likewise downloads a pinned build from the official GitHub Release only after confirmation and verifies the exact size and SHA-256, and it launches the client with automatic updates disabled so the running binary is always the verified one. A quick tunnel needs no account, token, or DNS record; a named tunnel token is stored only in the plugin private directory and reaches cloudflared through the environment, and cleanup deletes every file it manages.
288
296
  - Self-hosted FRP downloads pinned official `frpc` only after confirmation and verifies the origin, exact size, SHA-256, archive paths, and executable version. The shared token never appears in status, diagnostics, or attachment-plan responses. Copying a server template, or explicitly copying a token-bearing attach config after re-entering its token, places it on the system clipboard; clear it after use. Local cleanup removes only plugin-managed files. Managed VPS deployments require separate uninstall-script or one-click cleanup; attaching to an existing frps neither changes nor cleans up that VPS. Automatic deployment and server cleanup require SSH host-key verification against the VPS console.
289
297
  - A paired device is a fully trusted DeepSeek Harness operator and can run tools on the computer; revoke lost devices from the computer.
298
+ - The mobile gateway proxies requests as a local DSH operator and supports `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, and `DELETE` on ordinary plugin routes; writes still require a paired Session, exact Origin, and CSRF validation. Third-party plugins must not treat the upstream loopback Host as proof that the client is physically local to the computer.
290
299
  - The LAN gateway listens only while Mobile Access is enabled; with it off, DSH keeps running normally on the computer.
291
300
 
292
301
  See [SECURITY.md](SECURITY.md).
293
302
 
294
303
  ## Troubleshooting
295
304
 
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`.
296
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).
297
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.
298
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.
@@ -314,14 +324,16 @@ Version 0.5.2 keeps the DSH host peer names but does not block installation by D
314
324
  | Local network | Yes (firewall automated) | Yes (open the firewall yourself) | Yes | Yes |
315
325
  | Tailscale Funnel | Yes (bundled) | Yes (bundled) | Yes (bundled) | No |
316
326
  | cpolar | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) | No |
317
- | cloudflared quick/named tunnel | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) | No |
327
+ | cloudflared quick/named tunnel | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) | Yes, x64/arm64 (on-demand) |
318
328
  | Self-hosted FRP | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) | Yes (on-demand) |
319
329
  | Own reverse proxy | Yes (config only) | Yes (config only) | Yes (config only) | Yes (config only) |
320
330
 
321
- On macOS, local network, self-hosted FRP, and the own reverse proxy work; the three managed components have no macOS build yet. The diagnostics firewall check currently covers Windows only and reports “not applicable” elsewhere.
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.
322
332
 
323
333
  | DSH Mobile plugin | Verified DeepSeek Harness version |
324
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) |
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) |
325
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) |
326
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) |
327
339
  | `0.5.1` | `0.1.7-alpha.2`, `0.1.7-rc.1`, `0.1.7-rc.2`, and `0.2.0-rc.1`; official Desktop `0.1.7-rc.2` (administration surface) |
@@ -343,6 +355,8 @@ On macOS, local network, self-hosted FRP, and the own reverse proxy work; the th
343
355
 
344
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.
345
357
 
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.
359
+
346
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.
347
361
 
348
362
  ## Uninstall
package/README.md CHANGED
@@ -31,14 +31,14 @@
31
31
 
32
32
  > DSH Mobile 是 DeepSeek Harness 社区插件,原生 App 仅支持 Android。
33
33
  >
34
- > **当前版本:0.5.3**。优化提问卡片、折叠过程间距和第三方插件输入栏布局,改善语音输入期间的焦点与常亮处理,并补充设置保存故障排查。[更新记录](CHANGELOG.md#053---2026-10-01)。
34
+ > **当前正式版本:0.5.5**。优化手机输入栏与模型搜索字号,修复 Android 模型菜单返回、旋转时附件丢失和撤销状态覆盖,新增 macOS cloudflared 支持。[更新记录](CHANGELOG.md#055---2026-10-04)。
35
35
  >
36
- > **升级提醒**:插件与 Android App 可同步更新至 0.5.3。App 本次仅同步版本信息,现有设备无需重新配对。[兼容说明](#兼容性)。
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.3/dsh-mobile-android-v0.5.3.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.3/dsh-mobile-android-v0.5.3.apk"><strong>下载 Android App 0.5.3</strong></a><br>
41
- <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.5.3">版本说明与校验文件</a></sub>
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` 命令:
@@ -124,7 +130,9 @@ dsh plugin --profile web add dshmarket
124
130
 
125
131
  适合手机离开电脑所在网络后使用。远程访问默认关闭,手机不需要另外安装 Tailscale、cpolar、cloudflared 或 FRP。
126
132
 
127
- 远程服务可能受带宽和连接限额影响:[cpolar 免费方案](https://svip.cpolar.com/pricing) 当前为 1 Mbps,[Tailscale Funnel](https://tailscale.com/docs/features/tailscale-funnel#requirements-and-limitations) 也存在不可配置的带宽限制,cloudflared 的 quick tunnel 由 Cloudflare 免费提供、地址随机且有限流。DSH Mobile 通过 10 条分页、顶部按需加载、gzip 和 WebSocket 长连接减少流量与等待,但无法突破服务商限额。
133
+ 远程服务可能受带宽和连接限额影响:[cpolar 免费方案](https://svip.cpolar.com/pricing) 当前为 1 Mbps,[Tailscale Funnel](https://tailscale.com/docs/features/tailscale-funnel#requirements-and-limitations) 也存在不可配置的带宽限制,cloudflared 的 quick tunnel 由 Cloudflare 免费提供、地址随机且有限流。DSH Mobile 使用静态资源 gzip、WebSocket 长连接和顶部按需加载改善体验;会话的历史窗口与分页大小由 DSH 决定,插件无法提高服务商限额。
134
+
135
+ 页面能打开但一直“重连中”,应先区分 WebSocket 升级失败、慢速数据同步和心跳超时,操作见[慢链路与反复重连指南](docs/SLOW_CONNECTIONS.md)。0.5.4 还提供按确切路径启用的 WebSocket 压缩,默认关闭;长会话或计量网络可按指南尝试,并对比实际传输量。
128
136
 
129
137
  <p align="center">
130
138
  <img src="https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/assets/screenshots/remote-access.png" width="82%" alt="DSH Mobile 远程访问与通道选择">
@@ -149,7 +157,7 @@ Tailscale Funnel 覆盖范围广,但在中国大陆网络下可能不稳定。
149
157
 
150
158
  自有反向代理的 HTTP 后端只允许留在可信私网;**不要把它映射到公网,也不要绕过它直连 DSH 或现有 LAN 3443**。来源 CIDR 匹配代理的直接 TCP 来源,不信任转发头;反代须保留外部 Host(含端口)、Origin、Cookie 和 WebSocket。清除代理配置不会删除已配对远程设备。
151
159
 
152
- 远程公开地址仍受 DSH 设备配对保护。内置 Funnel 与托管 cpolar、cloudflared 支持 Windows x64 与 Linux x64/arm64;按需安装的 FRP 0.70.1 支持 Windows、Linux、macOS 的 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。各通道的系统支持矩阵见[兼容性](#兼容性)。
153
161
 
154
162
  ## 扩展与自定义
155
163
 
@@ -288,12 +296,14 @@ flowchart LR
288
296
  - cloudflared 同样仅在用户确认后从官方 GitHub Release 下载固定版本并校验精确大小和 SHA-256,且启动时关闭自动更新,以保证运行的始终是已校验的那份二进制;快速隧道不需要账号、Token 或 DNS 记录;命名隧道令牌只存插件私有目录、只经环境变量传给 cloudflared,清理时删除插件托管的全部文件。
289
297
  - 自建 FRP 仅在用户确认后从官方 Release 下载固定版本 `frpc`,校验来源、精确大小、SHA-256、压缩包路径和可执行文件版本;共享 Token 不会出现在状态、诊断或接入清单响应中。复制服务器模板,或重新输入 Token 后显式复制含 Token 的接入配置时,它会进入系统剪贴板,请粘贴后及时清除。本机清理只删除插件管理的文件;托管部署的 VPS 需用面板卸载脚本或一键清理单独清除,接入既有 frps 则不会改动或清理你的 VPS。自动部署与一键清理前都需核对 SSH 主机指纹。
290
298
  - 配对设备拥有控制电脑端 DeepSeek Harness 的能力,应视为完全可信设备;丢失手机后应在电脑端撤销设备。
299
+ - 移动网关以 DSH 本机操作者身份代理请求,支持普通插件路由的 `GET`、`HEAD`、`POST`、`PUT`、`PATCH`、`DELETE`;写请求仍校验配对 Session、精确 Origin 与 CSRF。第三方插件不能把上游回环 Host 当成请求来自电脑物理本机的证明。
291
300
  - 移动网关开启时才监听局域网;关闭后 DeepSeek Harness 仍正常在电脑本机运行。
292
301
 
293
302
  完整说明见 [SECURITY.md](SECURITY.md)。
294
303
 
295
304
  ## 故障排查
296
305
 
306
+ - **配对成功后仍反复提示重新配对或续期 `401`**:同一域名上的其他服务或旧 Cookie 可能干扰认证。更新至最新插件及 App,再从当前移动访问入口重试;浏览器重新扫描当前二维码可更新本插件的认证 Cookie,无需清除所有网站数据。若仍失败,查看失败请求与脱敏日志,其他认证或代理错误也可能返回 `401`。
297
307
  - **内测声明无法确认或设置无法保存**:先在电脑端直接打开 DSH 的本机地址,查看终端日志或浏览器 Network 中失败的设置请求。连接诊断不检查设置写入;保留现有配置及 `settings.yaml.imported`,按具体错误排查。相同界面提示可能有不同原因,见 [DSH #860](https://github.com/deepseek-ai/deepseek-harness/discussions/860)。
298
308
  - **设置请求返回 HTTP `403`**:先检查 DSH 的 Host/Origin 信任校验及代理响应。检查 iframe、代理和浏览器扩展是否改变请求来源,使用本机直接访问验证;保持信任检查启用。
299
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/)修复依赖;仍失败时将版本、模块路径及脱敏后的完整错误提交上游。
@@ -315,14 +325,16 @@ flowchart LR
315
325
  | 局域网 | 支持(自动配防火墙) | 支持(防火墙自理) | 支持 | 支持 |
316
326
  | Tailscale Funnel | 支持(随包提供) | 支持(随包提供) | 支持(随包提供) | 不支持 |
317
327
  | cpolar | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) | 不支持 |
318
- | cloudflared 快速/命名隧道 | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) | 不支持 |
328
+ | cloudflared 快速/命名隧道 | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) | 支持 x64/arm64(按需下载) |
319
329
  | 自建 FRP | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) | 支持(按需下载) |
320
330
  | 自有反向代理 | 支持(纯配置) | 支持(纯配置) | 支持(纯配置) | 支持(纯配置) |
321
331
 
322
- macOS 上局域网、自建 FRP 与自有反向代理可用;三个托管组件暂未提供 macOS 包。诊断页的防火墙检查目前仅覆盖 Windows,其他系统显示“不适用”。
332
+ macOS 上局域网、cloudflared、自建 FRP 与自有反向代理可用;Funnel 与 cpolar 暂未提供 macOS 组件。诊断页的防火墙检查目前仅覆盖 Windows,其他系统显示“不适用”。
323
333
 
324
334
  | DSH Mobile 插件 | 验证支持的 DeepSeek Harness 版本 |
325
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 工作区读取) |
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 工作区读取) |
326
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 工作区读取) |
327
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 工作区读取) |
328
340
  | `0.5.1` | `0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2`、`0.2.0-rc.1`;官方 Desktop `0.1.7-rc.2`(桌面管理入口) |
@@ -344,6 +356,8 @@ macOS 上局域网、自建 FRP 与自有反向代理可用;三个托管组件
344
356
 
345
357
  现有 App(0.3.3 及更新)无需重新配对;cpolar 用户应使用 0.3.15 或更新 App,较早版本可能在免费线路的慢速首次加载完成前超时;更早的 App 还使用不同的状态栏策略。App 0.4.0 才支持多设备列表、启动行为设置和电脑端撤销状态同步;旧版 App 仍可连接已保存的单台设备。App 0.1.3 及更早版本需卸载重装并重新配对。
346
358
 
359
+ 0.5.5 的原生配对与续期协议保持兼容,旧 App 的正常连接可继续使用;建议同步升级至 0.5.5(build 75),以获得旋转保持页面、模型菜单返回和撤销状态修复,同时保留 0.5.4 的认证 Cookie 修正。
360
+
347
361
  GitHub Release 的正式 APK 使用固定签名,可从同一签名的旧正式版原位升级并保留配对。自行构建的 Debug APK 若使用不同签名,不能直接覆盖安装正式版;切换前请准备重新配对。
348
362
 
349
363
  ## 卸载
@@ -378,7 +392,7 @@ npm run verify
378
392
 
379
393
  修改提问卡片或移动布局时,完成构建后运行 `npx playwright install chromium --only-shell`、`npm run smoke:question-fixes` 和 `npm run smoke:native-layout`,检查实际客户端产物的滚动、键盘与布局行为。
380
394
 
381
- 真实启动冒烟另用临时 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` 装在独立目录,避免替换插件的开发依赖:
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` 装在独立目录,避免替换插件的开发依赖:
382
396
 
383
397
  ```powershell
384
398
  $dshMobileTestRuntime = Join-Path $env:TEMP 'dsh-mobile-test-runtime'
package/SECURITY.md CHANGED
@@ -32,7 +32,7 @@ The maintainer will acknowledge a complete report within seven days. Publication
32
32
  - The FRP token stays in a private file under `$DSH_HOME/mobile-access/`, is never returned by status, diagnostic, or attachment-plan responses, and is never logged. Copying a server template or an attach-mode `frpc.toml` after re-entering its token puts that token on the system clipboard; clear it after use and protect the VPS configuration. Local FRP cleanup removes the managed `frpc`, token, runtime configuration, ingress certificate material, staging files, and logs. Server-side cleanup scripts apply only to plugin-managed deployment and delete solely DSH Mobile-owned files, services, and tagged firewall rules; attach mode never deletes the operator's existing frps or Caddy files.
33
33
  - Automatic VPS deployment and one-click VPS cleanup first read the server's SSH host keys and require the operator to confirm every `SHA256:` fingerprint against the VPS console before any authenticated connection. All SSH/SCP channels pin `StrictHostKeyChecking=yes` to a temporary known_hosts file built from the confirmed keys; unknown, rotated, or extra keys abort the operation instead of being silently accepted. SSH credentials themselves are key-or-agent only, never passwords; the private key path is convenience state in the current browser profile, and key material is never uploaded or logged.
34
34
  - Disabling remote access stops the selected provider process without affecting LAN access. Resetting remote access also removes provider state and the independent remote device registry.
35
- - Treat every paired device as a fully trusted operator. Stock DSH methods reached through the authenticated loopback proxy may read configuration or run tools with the desktop user's authority.
35
+ - Treat every paired device as a fully trusted operator. The authenticated proxy forwards ordinary DSH and community-plugin routes using GET, HEAD, POST, PUT, PATCH, or DELETE; writes require the gateway's exact Origin, valid Session, and Session-bound CSRF token. Upstream requests use DSH's loopback Host and the gateway's own DSH authentication, so a plugin cannot distinguish a paired phone from the computer user merely by checking that Host. Routes may read configuration, save settings, or run tools with the desktop user's authority; pairing is not a read-only sandbox. The separate `/api/mobile-access` admin API remains inaccessible through the mobile listener.
36
36
  - Android stores the paired-device list as an encrypted record. Removing a local row erases its local credential but does not revoke the phone at the computer; use the computer-side device controls to revoke access. A computer-side revocation invalidates the token even if the App retains the row's name for re-pairing. Network timeouts are not evidence of revocation.
37
37
  - Android grants WebView microphone access only for an audio-only request from the current paired HTTPS Origin, after Android's `RECORD_AUDIO` permission is granted. Other WebView resources and Origins remain denied. Client plugins within the authenticated page share that Origin and can invoke page APIs; install only trusted plugins before granting microphone access.
38
38
  - Treat `mobile.js` as application code with the paired page's same-origin authority. Restrict write access to trusted host-side DSH sessions and review generated API calls or browser-permission use.
@@ -8,7 +8,7 @@ The optional [FRP](https://github.com/fatedier/frp) client is not included in th
8
8
 
9
9
  The optional [cloudflared](https://github.com/cloudflare/cloudflared) client is not included in the npm package or Android App. When a user explicitly chooses cloudflared installation, DSH Mobile downloads the pinned official release asset for the supported host platform (version recorded in `src/cloudflared-component.ts`), verifies its exact size and SHA-256 digest, and stores it only under the user's DSH Mobile data directory. The client is started with automatic updates disabled. Quick tunnels do not require account credentials; named tunnels use an operator-supplied connector token stored in the plugin's private directory. cloudflared is distributed under the Apache License 2.0; use of Cloudflare's quick tunnels remains subject to Cloudflare's [website terms](https://www.cloudflare.com/website-terms/).
10
10
 
11
- The npm package declares direct runtime dependencies on [Schemastery](https://github.com/shigma/schemastery) `^3.18.1`, [bonjour-service](https://github.com/onlxltd/bonjour-service) `1.4.4`, [qrcode](https://github.com/soldair/node-qrcode) `^1.5.4`, and [selfsigned](https://github.com/jfromaniello/selfsigned) `^5.5.0`. These packages are distributed under the MIT License; the release checkout's exact transitive versions appear in the attached CycloneDX npm SBOM.
11
+ The npm package declares direct runtime dependencies on [Schemastery](https://github.com/shigma/schemastery) `^3.18.1`, [bonjour-service](https://github.com/onlxltd/bonjour-service) `1.4.4`, [qrcode](https://github.com/soldair/node-qrcode) `^1.5.4`, [selfsigned](https://github.com/jfromaniello/selfsigned) `^5.5.0`, and [ws](https://github.com/websockets/ws) `8.22.0`. These packages are distributed under the MIT License; the release checkout's exact transitive versions appear in the attached CycloneDX npm SBOM.
12
12
 
13
13
  The Android App runtime contains [Kotlin standard library](https://github.com/JetBrains/kotlin) `2.1.0`, [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) `1.6.4`, [JetBrains annotations](https://github.com/JetBrains/java-annotations) `13.0`, [AndroidX Core](https://developer.android.com/jetpack/androidx/releases/core) `1.15.0`, [AndroidX WebKit](https://developer.android.com/jetpack/androidx/releases/webkit) `1.17.1`, their AndroidX transitive components, [Guava listenablefuture](https://github.com/google/guava) `1.0`, and [ZXing Core](https://github.com/zxing/zxing) `3.5.4`. These runtime libraries are distributed under the Apache License 2.0; the exact resolved tree is attached to each release as `dsh-mobile-android-v<version>-dependencies.txt`.
14
14
 
@@ -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 (currently Windows x64 and Linux x64/arm64). |
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` | 当前平台不在支持范围内(目前支持 Windows x64 与 Linux x64/arm64)。 |
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/docs/README.md CHANGED
@@ -10,6 +10,7 @@
10
10
  | [自建 FRP 使用指南](SELF_HOSTED_FRP.md) | [Self-hosted FRP guide](SELF_HOSTED_FRP.en.md) | 已有 VPS 时用 frps + Caddy 自建远程通道,避开公共隧道带宽限制 |
11
11
  | [接入你既有的 frps](ATTACH_EXISTING_FRPS.md) | [Attach to an existing frps](ATTACH_EXISTING_FRPS.en.md) | 复用 VPS 上已运行的 frps,不自动修改服务器;可选公开 CA + Caddy 或自签 CA + TCP 透传,须核对监听与证书有效期。 |
12
12
  | [自有 HTTPS 反向代理](SELF_HOSTED_ORIGIN.md) | [Own HTTPS reverse proxy](SELF_HOSTED_ORIGIN.en.md) | 复用已有的 Lucky / Nginx / Caddy 公网 HTTPS 入口,无需隧道组件 |
13
+ | [慢链路与反复重连](SLOW_CONNECTIONS.md) | [Slow links and repeated reconnection](SLOW_CONNECTIONS.en.md) | 区分 HTTP 与实时连接故障,按需配置 DSH 等待时间或启用 WebSocket 压缩 |
13
14
 
14
15
  > 命名隧道与两个自建提供方都要求手机端走 App 的**远程访问**扫码流程;`SELF_HOSTED_ORIGIN.en.md` 是精简版,字段表与排错清单以中文版为准。
15
16
 
@@ -0,0 +1,77 @@
1
+ # Slow links and repeated reconnection
2
+
3
+ [中文](SLOW_CONNECTIONS.md)
4
+
5
+ The remote page may open and `/mobile-access/health` may respond normally while DSH stays on “Reconnecting” or delays model and Workspace lists. HTTP reachability only shows that requests pass through; DSH's live data also needs a WebSocket connection to finish initialization and remain connected.
6
+
7
+ ## Identify the stage that fails
8
+
9
+ First update DSH, the DSH Mobile plugin, and the Android app together. On the computer, check the current channel under **Mobile Access → Connection diagnostics**, then inspect DSH startup logs and the browser's developer tools under Network → WS. Remove Tokens, Cookies, and complete pairing URLs before sharing logs.
10
+
11
+ - **WebSocket never connects**: check for `101 Switching Protocols` and errors such as `401`, `403`, `404`, or `502`. Authentication, Host/Origin checks, proxy upgrade support, paths, and version differences can all cause this. Heartbeat adjustments do not resolve these failures. Allow blocked third-party plugin paths individually in Connection diagnostics; DSH's built-in paths do not need to be added again.
12
+ - **The request gets 101 but connections keep closing**: record the interval and compare the same page and Session through LAN and remote access. If a long Session repeatedly disconnects only through the remote channel while downloads saturate the link, investigate the heartbeat and initialization deadlines below. Browser close code `1006` means an abnormal end and does not identify which layer disconnected.
13
+ - **Initialization reaches its deadline**: a console message such as `connection generation was not ready within 15000ms` means that attempt did not finish initializing in time. Check server errors, proxy interference, and incomplete data subscriptions as well as slow transfers.
14
+
15
+ Both [#126](https://github.com/saya-ch/dsh-mobile/issues/126) and [#146](https://github.com/saya-ch/dsh-mobile/issues/146) report healthy HTTP access with a reconnecting live connection. The same interface message does not establish the same cause.
16
+
17
+ ## Slow transfers can exceed the default deadlines
18
+
19
+ DSH 0.2.0-rc.2's API gateway sends a WebSocket Ping every **2 seconds** by default and ends the connection after two missed Pongs, allowing roughly **4–6 seconds** in practice. The client separately allows **15 seconds** for live-connection initialization. Large Session data, a slow uplink, or congestion can delay a Pong or the first synchronization and trigger disconnection and another synchronization.
20
+
21
+ In the deployment reported in #146, the contributor measured a Session window of about 2.18 MiB and a 2.68 Mbps uplink, and reported fewer reconnections after increasing both intervals. These are observations from that deployment. Transfer sizes and improvements depend on the Session, plugins, and network; they are not a general performance guarantee.
22
+
23
+ ## Increase two existing DSH settings when needed
24
+
25
+ After confirming this slow-link case, try a **30-second heartbeat interval** and a **120-second initialization deadline**. These are settings of existing DSH plugins, not DSH Mobile's `upstreamTimeoutMs`; the latter cannot change DSH's heartbeat or client initialization deadline.
26
+
27
+ Find the enabled `@deepseek-ai/dsh-api-gateway` and `@deepseek-ai/dsh-client-connection` entries in the current profile on the computer. If your DSH version provides configuration controls for them, edit their existing configuration there. Otherwise back up and edit the current profile's `cordis.patch.yml`. CLI Web normally uses `$DSH_HOME/profiles/web/cordis.patch.yml`; official Desktop defaults to `$DSH_HOME/profiles/desktop/cordis.patch.yml`. Use the actual running profile for a custom deployment.
28
+
29
+ The following example targets the standard Web/official Desktop composition in DSH 0.2.0-rc.2, whose existing entry IDs are `typert-gateway` and `connection`. Check your entry IDs first. If an override already exists for an ID, edit its `config` instead of inserting another plugin.
30
+
31
+ ```yaml
32
+ - id: typert-gateway
33
+ config:
34
+ websocketHeartbeatIntervalMs: 30000
35
+
36
+ - id: connection
37
+ config:
38
+ trustedHosts: !!js ctx.webRuntime.trustedHosts
39
+ recovery:
40
+ generationReadyTimeoutMs: 120000
41
+ ```
42
+
43
+ **A patch replaces the target entry's entire `config`.** The example shows the trusted-Host expression retained by the standard composition and the two adjusted fields. Preserve any existing custom `trustedHosts`, Cookie lifetime, request size, `streamInboxBytes`, and other `recovery` settings as well. Merge the changes into the original file's top-level YAML list and preserve other entries. Do not replace the whole file with this example or edit `node_modules`.
44
+
45
+ Save and restart the current DSH instance, then reopen the phone page so it receives the new client recovery settings. If startup reports an unknown entry or unsupported field, restore the backup and check the running DSH version and configuration. Do not apply this example unchanged to another version or a custom composition.
46
+
47
+ ## Check the result
48
+
49
+ Open the Session that previously reconnected and compare connection lifetime, reconnection count, and actual transfer volume. A 30-second heartbeat detects a genuinely disconnected peer more slowly; a 120-second initialization deadline also makes failed attempts wait longer. If the adjustment does not help, restore the original values and continue diagnosing instead of increasing deadlines indefinitely. Longer deadlines do not increase tunnel bandwidth or repair authentication, proxy, or server failures.
50
+
51
+ Settings and defaults were checked against DSH 0.2.0-rc.2: [API gateway configuration and heartbeat implementation](https://github.com/deepseek-ai/deepseek-harness/tree/dsh-v0.2.0-rc.2/packages/api/gateway/src), [client recovery settings](https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.2.0-rc.2/packages/client/connection/src/recovery-config.ts), and [standard Web entries](https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.2.0-rc.2/packages/bundle/web-app/cordis.patch.yml).
52
+
53
+ ## Optional WebSocket compression
54
+
55
+ DSH Mobile 0.5.4 can compress selected live-connection paths. This suits limited bandwidth, metered links, or large Session data, trading extra CPU and memory use for reduced transfer volume. The path list is empty by default, retaining the existing uncompressed relay.
56
+
57
+ Add the following property to the existing `config` of the current `mobile-access` entry. This is a **configuration fragment, not a complete profile patch**. Keep the entry's existing interface, certificate, pairing-state, and management settings; do not replace the whole `config` with the fragment.
58
+
59
+ ```yaml
60
+ websocketCompression:
61
+ paths:
62
+ - /api/remote.mux
63
+ ```
64
+
65
+ `/api/remote.mux` is the main live-data path in the current DSH. The list selects **exact paths** for compression and does not grant access: device authentication, Host/Origin checks, and WebSocket approval must still succeed. Before adding a community plugin's path, verify and approve it in Connection diagnostics. Compression is negotiated only between the phone/browser and the Mobile gateway; the DSH side remains uncompressed. Each message uses no compression dictionary retained from previous messages. The gateway relays the real Ping/Pong frames from both ends, adds no separate heartbeat, and does not change the DSH deadlines described above.
66
+
67
+ These optional fields sit alongside `paths`; their defaults normally suffice:
68
+
69
+ | Field | Default | Purpose |
70
+ | --- | --- | --- |
71
+ | `maxMessageBytes` | `33554432` (32 MiB) | Maximum decompressed message size; exceeding it closes the connection |
72
+ | `maxQueuedBytes` | `67108864` (64 MiB) | Maximum pending data and frame headers per relay direction; must cover the message limit plus a 14-byte frame header |
73
+ | `thresholdBytes` | `1024` | Messages sent to the phone/browser below this size are not considered for compression |
74
+ | `concurrencyLimit` | `4` | Concurrent compression work; `ws` establishes this shared limit on the process's first compressed connection, so restart DSH after changing it |
75
+ | `level` | `3` | Compression level (0–9); higher values may use more CPU |
76
+
77
+ Restart DSH and reopen the phone page after a change. Developer tools can show whether the WebSocket handshake negotiated `permessage-deflate`; a client that does not negotiate it can still connect without compression. Compare actual channel transfer volume and CPU use for the same Session, rather than judging savings from the decompressed message lengths shown in developer tools. Set `paths` back to `[]` to disable it. Compression does not raise provider quotas or replace connection troubleshooting.
@@ -0,0 +1,77 @@
1
+ # 慢速链路与反复重连
2
+
3
+ [English](SLOW_CONNECTIONS.en.md)
4
+
5
+ 远程页面能打开、`/mobile-access/health` 返回正常,仍可能出现“重连中”、模型或工作区迟迟不显示。HTTP 可达只说明请求能通过;DSH 的实时数据还需要 WebSocket 连接完成初始化并保持在线。
6
+
7
+ ## 先判断重连发生在哪一步
8
+
9
+ 先同步更新 DSH、DSH Mobile 插件和 Android App,再在电脑端 **移动访问 → 连接诊断** 检查当前通道;查看 DSH 启动日志和浏览器开发者工具的 Network → WS。分享日志时去掉 Token、Cookie 和完整配对地址。
10
+
11
+ - **WebSocket 没有连接成功**:检查请求是否获得 `101 Switching Protocols`,并留意 `401`、`403`、`404`、`502` 等错误。认证、Host/Origin、反向代理升级支持、连接路径或版本差异都可能造成这种情况。调整心跳不能解决这些问题;第三方插件被拦截的路径可在连接诊断中按需允许,不必把 DSH 内置路径全部重新添加。
12
+ - **已获得 101,但连接反复关闭**:记录关闭间隔,并对比同一页面、同一会话的局域网与远程访问。如果只在远程打开长会话时频繁断开,同时下载长时间占满链路,才进一步检查下面的心跳和初始化等待时间。浏览器显示 `1006` 表示连接异常结束,本身不能确定是哪一层断开。
13
+ - **初始化等待超时**:若控制台出现 `connection generation was not ready within 15000ms`,说明该次实时连接没有在等待期限内完成初始化。除了慢速传输,还要排查服务端错误、代理阻断及未完成的数据订阅。
14
+
15
+ [#126](https://github.com/saya-ch/dsh-mobile/issues/126) 和 [#146](https://github.com/saya-ch/dsh-mobile/issues/146) 都报告过“HTTP 正常但实时连接重连”,它们不能仅凭界面文案判定为同一个原因。
16
+
17
+ ## 慢速传输可能超过默认等待时间
18
+
19
+ DSH 0.2.0-rc.2 的 API 网关默认每 **2 秒**发送一次 WebSocket Ping,连续两次未收到 Pong 后会结束连接,实际容忍时间约为 **4–6 秒**。客户端另有 **15 秒**的实时连接初始化期限。较大的会话数据、低速上行或拥塞可能延迟 Pong 或首次数据同步,触发断开和重新同步。
20
+
21
+ 在 #146 的部署中,反馈者测量到约 2.18 MiB 的会话窗口与 2.68 Mbps 上行,并报告增大这两个时间后重连减少。这是该部署的观测结果,传输大小和改善程度取决于会话、插件及网络,不能作为通用性能保证。
22
+
23
+ ## 按需增加两个 DSH 参数
24
+
25
+ 确认是上述慢速链路后,可先试 **30 秒心跳间隔**和 **120 秒初始化等待**。这两个参数属于 DSH 已有插件配置,不是 DSH Mobile 的 `upstreamTimeoutMs`;后者不能改变 DSH 的心跳或客户端初始化期限。
26
+
27
+ 在电脑端找到当前 profile 中已启用的 `@deepseek-ai/dsh-api-gateway` 与 `@deepseek-ai/dsh-client-connection` 条目。如果当前 DSH 提供相应配置编辑入口,修改其已有配置;没有入口时,先备份当前 profile 的 `cordis.patch.yml`,再编辑这个文件。命令行 Web 通常使用 `$DSH_HOME/profiles/web/cordis.patch.yml`,官方 Desktop 默认使用 `$DSH_HOME/profiles/desktop/cordis.patch.yml`;自定义 profile 以实际运行配置为准。
28
+
29
+ 下例适用于 DSH 0.2.0-rc.2 的标准 Web/官方 Desktop 组装,现有条目 ID 分别为 `typert-gateway` 和 `connection`。先确认自己的条目 ID;同一个 ID 已有覆盖项时,修改它的 `config`,不要重复插入插件。
30
+
31
+ ```yaml
32
+ - id: typert-gateway
33
+ config:
34
+ websocketHeartbeatIntervalMs: 30000
35
+
36
+ - id: connection
37
+ config:
38
+ trustedHosts: !!js ctx.webRuntime.trustedHosts
39
+ recovery:
40
+ generationReadyTimeoutMs: 120000
41
+ ```
42
+
43
+ **Patch 会替换目标条目的整个 `config`。** 以上仅展示标准配置需要保留的可信 Host 表达式与两个调整项;若已有自定义 `trustedHosts`、Cookie 有效期、请求大小、`streamInboxBytes` 或其他 `recovery` 参数,须一并保留。把修改合入原文件的顶层 YAML 列表,保留其他条目;不要用示例覆盖整个文件或修改 `node_modules`。
44
+
45
+ 保存后重启当前 DSH 实例,并重新打开手机页面,让页面取得新的客户端恢复参数。若启动提示条目不存在或字段不支持,恢复备份,核对当前 DSH 版本和配置;不同版本或自定义组装不要直接套用本例。
46
+
47
+ ## 调整后检查效果
48
+
49
+ 重新打开原先会反复重连的会话,比较连接持续时间、重连次数和实际传输量。30 秒心跳会让真正失联的发现变慢,120 秒初始化期限也会让失败连接等待更久;如果没有改善,恢复原值并继续定位,不要无限放大等待时间。通道带宽不会因延长时间而增加,也不能修复认证、代理或服务端故障。
50
+
51
+ 参数与默认值已按 DSH 0.2.0-rc.2 核对:[API 网关配置与心跳实现](https://github.com/deepseek-ai/deepseek-harness/tree/dsh-v0.2.0-rc.2/packages/api/gateway/src)、[客户端恢复配置](https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.2.0-rc.2/packages/client/connection/src/recovery-config.ts)、[标准 Web 条目](https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.2.0-rc.2/packages/bundle/web-app/cordis.patch.yml)。
52
+
53
+ ## 可选的 WebSocket 压缩
54
+
55
+ 从 DSH Mobile 0.5.4 起,可以为指定的实时连接路径启用压缩。它适合带宽有限、计量网络或会话数据较大的场景,以额外 CPU 和内存开销换取较少的传输量;默认路径列表为空,仍使用原来的无压缩转发。
56
+
57
+ 在当前 `mobile-access` 条目的已有 `config` 中加入下面这段属性;这是**配置片段,不是完整 profile patch**。保留该条目已有的网卡、证书、配对状态与管理设置,不要用这个片段替换整个 `config`。
58
+
59
+ ```yaml
60
+ websocketCompression:
61
+ paths:
62
+ - /api/remote.mux
63
+ ```
64
+
65
+ `/api/remote.mux` 是当前 DSH 的主要实时数据路径。这里只选择要压缩的**准确路径**,不会新增访问权限;设备认证、Host/Origin 与 WebSocket 放行规则仍需通过。社区插件的路径若需要压缩,应先确认并通过连接诊断放行,再加入这个列表。压缩只在手机/浏览器与移动网关之间协商,与 DSH 之间仍不压缩;每条消息不复用先前消息的压缩字典。网关转发两端真实的 Ping/Pong,不另设心跳,也不会因此修改上文的 DSH 等待时间。
66
+
67
+ 以下可选字段与 `paths` 同级,通常保持默认即可:
68
+
69
+ | 字段 | 默认值 | 用途 |
70
+ | --- | --- | --- |
71
+ | `maxMessageBytes` | `33554432`(32 MiB) | 单条解压后消息的上限;超过时结束该连接 |
72
+ | `maxQueuedBytes` | `67108864`(64 MiB) | 每个转发方向的待发送数据与帧头上限;至少覆盖消息上限加 14 字节帧头 |
73
+ | `thresholdBytes` | `1024` | 向手机/浏览器发送消息时,小于此大小不尝试压缩 |
74
+ | `concurrencyLimit` | `4` | 压缩任务并发上限;`ws` 在当前进程首次建立压缩连接时确定这个共享上限,改动后重启 DSH |
75
+ | `level` | `3` | 压缩等级(0–9);提高可能增加 CPU 开销 |
76
+
77
+ 修改后重启 DSH 并重新打开手机页面。可在开发者工具中查看 WebSocket 握手是否协商了 `permessage-deflate`;客户端没有协商时仍可无压缩连接。对比同一会话的实际通道传输量与 CPU 使用,不能仅以开发者工具显示的解压后消息长度判断节省比例。需要关闭时把 `paths` 改回 `[]`;压缩不能提高服务商限额,也不能替代连接故障排查。