dsh-mobile 0.4.6 → 0.4.7
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 +12 -0
- package/CONTRIBUTORS.md +7 -1
- package/README.en.md +23 -8
- package/README.md +23 -8
- package/lib/client.js +63 -1
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +6 -2
- package/lib/index.mjs +156 -36
- package/lib/index.mjs.map +1 -1
- package/lib/mobile-compat.js.map +1 -1
- package/lib/mobile-layout.js +75 -20
- package/lib/mobile-layout.js.map +1 -1
- package/package.json +13 -13
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
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.4.7 - 2026-09-25
|
|
6
|
+
|
|
7
|
+
- Expose `panelInfo` on the mobile layout service for DSH `0.1.7-rc.2`, so built-in panels such as Plugin Manager can mount without breaking the dedicated mobile frontend (thanks @chintoleung for [PR #104](https://github.com/saya-ch/dsh-mobile/pull/104) and [#103](https://github.com/saya-ch/dsh-mobile/issues/103)).
|
|
8
|
+
- Derive mobile boot batches in a canonical entry order. The same module set now produces stable batch URLs, response bodies and ETags when upstream entry order changes, avoiding unnecessary new cache entries (thanks @xhwxt for [PR #105](https://github.com/saya-ch/dsh-mobile/pull/105)).
|
|
9
|
+
- Remove the original application-batch preload when the dedicated mobile page replaces that batch, preventing a duplicate multi-megabyte transfer. On WebView 151+, raise this app's HTTP cache quota to at least 64 MiB so large versioned scripts can be reused after a cold start; older WebViews retain their default policy (thanks @xhwxt for [#107](https://github.com/saya-ch/dsh-mobile/issues/107)).
|
|
10
|
+
- Extend source-contract and isolated browser-startup checks to DSH `0.1.7-rc.2`, alongside `0.1.7-alpha.2` and `0.1.7-rc.1`.
|
|
11
|
+
- Add opt-in `excludedClientModules` for mobile-only boot slimming. Exact package ids are checked against the live graph; boot-critical entries and modules still required by retained entries are refused. The default graph, desktop page, and stock frontend remain unchanged (thanks @xhwxt for [#108](https://github.com/saya-ch/dsh-mobile/issues/108)).
|
|
12
|
+
- Let the right sidebar fill the phone viewport instead of clipping file and plugin panels behind a narrow overlay edge; keep the wide-screen column layout and a reachable collapse control.
|
|
13
|
+
- Keep the on-screen keyboard closed when opening the composer Add menu, without affecting other listbox controls (thanks @ayiejosh for [PR #109](https://github.com/saya-ch/dsh-mobile/pull/109)).
|
|
14
|
+
- In the Android App, use plain Enter to add a draft line when the on-screen keyboard is visible and no hardware keyboard is attached; retain DSH's original Enter behavior for browsers, unknown keyboard state, menus and IME composition (thanks @ayiejosh for [PR #110](https://github.com/saya-ch/dsh-mobile/pull/110)).
|
|
15
|
+
- Clear the Android page-load timer when WebView reports the same root document with a normalized URL, preventing a completed load from becoming a delayed false timeout. After native session renewal, keep a live DSH WebView instead of rebuilding it; reload only when the document is unavailable, and bound repeated renderer-crash recovery.
|
|
16
|
+
|
|
5
17
|
## 0.4.6 - 2026-09-24
|
|
6
18
|
|
|
7
19
|
- Use the configured HTTP proxy as a second, bounded remote-health probe only when the direct probe fails. The diagnostic respects `NO_PROXY`, reports proxy-only reachability as a warning rather than proof that a phone can connect, and retains the direct result if both routes fail (thanks @abworks-dev for [PR #99](https://github.com/saya-ch/dsh-mobile/pull/99)).
|
package/CONTRIBUTORS.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
GitHub 的 [Contributors 图表](https://github.com/saya-ch/dsh-mobile/graphs/contributors) 按进入默认分支的提交自动统计,无法手动加入仅提交 issue 或 PR 提案的成员。本页按实际参与方式感谢社区成员;仓库维护者与自动依赖更新仍可在 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-09-
|
|
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-09-25. The repository maintainer and automated dependency updates remain visible in GitHub's history.
|
|
6
6
|
|
|
7
7
|
## 已发布版本中的合并 PR / Merged PRs in released versions
|
|
8
8
|
|
|
@@ -10,12 +10,15 @@ GitHub's Contributors graph counts commits on the default branch; issue reports
|
|
|
10
10
|
| --- | --- |
|
|
11
11
|
| [@1624318455](https://github.com/1624318455) | [#93](https://github.com/saya-ch/dsh-mobile/pull/93) |
|
|
12
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) |
|
|
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) |
|
|
14
|
+
| [@chintoleung](https://github.com/chintoleung) | [#104](https://github.com/saya-ch/dsh-mobile/pull/104) |
|
|
13
15
|
| [@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) |
|
|
14
16
|
| [@JackRushante](https://github.com/JackRushante) | [#16](https://github.com/saya-ch/dsh-mobile/pull/16) |
|
|
15
17
|
| [@liudasheng](https://github.com/liudasheng) | [#100](https://github.com/saya-ch/dsh-mobile/pull/100) |
|
|
16
18
|
| [@longisland-icetea](https://github.com/longisland-icetea) | [#59](https://github.com/saya-ch/dsh-mobile/pull/59), [#60](https://github.com/saya-ch/dsh-mobile/pull/60), [#63](https://github.com/saya-ch/dsh-mobile/pull/63) |
|
|
17
19
|
| [@qzyqmzn](https://github.com/qzyqmzn) | [#38](https://github.com/saya-ch/dsh-mobile/pull/38), [#75](https://github.com/saya-ch/dsh-mobile/pull/75) |
|
|
18
20
|
| [@StrawberryAO](https://github.com/StrawberryAO) | [#34](https://github.com/saya-ch/dsh-mobile/pull/34), [#40](https://github.com/saya-ch/dsh-mobile/pull/40) |
|
|
21
|
+
| [@xhwxt](https://github.com/xhwxt) | [#105](https://github.com/saya-ch/dsh-mobile/pull/105) |
|
|
19
22
|
| [@xingleiwu](https://github.com/xingleiwu) | [#79](https://github.com/saya-ch/dsh-mobile/pull/79), [#84](https://github.com/saya-ch/dsh-mobile/pull/84), [#85](https://github.com/saya-ch/dsh-mobile/pull/85), [#86](https://github.com/saya-ch/dsh-mobile/pull/86) |
|
|
20
23
|
|
|
21
24
|
## 已吸收但未直接合并的 PR / Incorporated without a direct merge
|
|
@@ -36,6 +39,7 @@ GitHub's Contributors graph counts commits on the default branch; issue reports
|
|
|
36
39
|
| [@azri57806-design](https://github.com/azri57806-design) | [#97](https://github.com/saya-ch/dsh-mobile/issues/97) |
|
|
37
40
|
| [@CESAEREE](https://github.com/CESAEREE) | [#1](https://github.com/saya-ch/dsh-mobile/issues/1) |
|
|
38
41
|
| [@CharlesLueng](https://github.com/CharlesLueng) | [#68](https://github.com/saya-ch/dsh-mobile/issues/68) |
|
|
42
|
+
| [@chintoleung](https://github.com/chintoleung) | [#103](https://github.com/saya-ch/dsh-mobile/issues/103) |
|
|
39
43
|
| [@chmzs](https://github.com/chmzs) | [#73](https://github.com/saya-ch/dsh-mobile/issues/73) |
|
|
40
44
|
| [@idoall](https://github.com/idoall) | [#42](https://github.com/saya-ch/dsh-mobile/issues/42), [#45](https://github.com/saya-ch/dsh-mobile/issues/45), [#46](https://github.com/saya-ch/dsh-mobile/issues/46), [#47](https://github.com/saya-ch/dsh-mobile/issues/47), [#62](https://github.com/saya-ch/dsh-mobile/issues/62), [#64](https://github.com/saya-ch/dsh-mobile/issues/64) |
|
|
41
45
|
| [@IvyC-zz](https://github.com/IvyC-zz) | [#58](https://github.com/saya-ch/dsh-mobile/issues/58), [#78](https://github.com/saya-ch/dsh-mobile/issues/78) |
|
|
@@ -44,6 +48,7 @@ GitHub's Contributors graph counts commits on the default branch; issue reports
|
|
|
44
48
|
| [@KMGTPEZY](https://github.com/KMGTPEZY) | [#95](https://github.com/saya-ch/dsh-mobile/issues/95) |
|
|
45
49
|
| [@LWping](https://github.com/LWping) | [#94](https://github.com/saya-ch/dsh-mobile/issues/94) |
|
|
46
50
|
| [@oliverwan97](https://github.com/oliverwan97) | [#26](https://github.com/saya-ch/dsh-mobile/issues/26) |
|
|
51
|
+
| [@optttt](https://github.com/optttt) | [#111](https://github.com/saya-ch/dsh-mobile/issues/111) |
|
|
47
52
|
| [@rgshendong](https://github.com/rgshendong) | [#87](https://github.com/saya-ch/dsh-mobile/issues/87) |
|
|
48
53
|
| [@RonaldinhoL](https://github.com/RonaldinhoL) | [#89](https://github.com/saya-ch/dsh-mobile/issues/89) |
|
|
49
54
|
| [@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) |
|
|
@@ -53,5 +58,6 @@ GitHub's Contributors graph counts commits on the default branch; issue reports
|
|
|
53
58
|
| [@Surpass567](https://github.com/Surpass567) | [#80](https://github.com/saya-ch/dsh-mobile/issues/80), [#81](https://github.com/saya-ch/dsh-mobile/issues/81) |
|
|
54
59
|
| [@taki-ohh](https://github.com/taki-ohh) | [#19](https://github.com/saya-ch/dsh-mobile/issues/19) |
|
|
55
60
|
| [@Xingcheng-wang](https://github.com/Xingcheng-wang) | [#76](https://github.com/saya-ch/dsh-mobile/issues/76) |
|
|
61
|
+
| [@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) |
|
|
56
62
|
| [@Yurzi](https://github.com/Yurzi) | [#17](https://github.com/saya-ch/dsh-mobile/issues/17) |
|
|
57
63
|
| [@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.4.
|
|
34
|
+
> **Current version: 0.4.7**. It supports DSH `0.1.7-rc.2`, avoids duplicate mobile boot downloads, and improves Android recovery, the phone-width sidebar, and input handling. [Release notes](CHANGELOG.md#047---2026-09-25).
|
|
35
35
|
>
|
|
36
|
-
> **Upgrade reminder**: update both the plugin and Android app to 0.4.
|
|
36
|
+
> **Upgrade reminder**: update both the plugin and Android app to 0.4.7 when practical. Existing pairings remain intact. The self-signed FRP entry requires at least the 0.4.6 app; older apps can still use existing LAN and trusted-certificate remote connections. [Compatibility notes](#compatibility).
|
|
37
37
|
|
|
38
38
|
<p align="center">
|
|
39
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.
|
|
40
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.
|
|
41
|
-
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.4.
|
|
39
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.7/dsh-mobile-android-v0.4.7.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.4.7/dsh-mobile-android-v0.4.7.apk"><strong>Download Android app 0.4.7</strong></a><br>
|
|
41
|
+
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.4.7">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. Local and remote access keep the same sessions, Workspaces, messages, and tools while using separate switches and paired-device stores without modifying DeepSeek Harness source.
|
|
@@ -216,11 +216,23 @@ Compatibility and WebSocket rules:
|
|
|
216
216
|
|
|
217
217
|
Proxied pages allow HTTP frames for compatibility with some community plugins; those pages are unencrypted and can be altered, and browsers may still block them as mixed content. Use HTTPS for sensitive work. The same warning appears at the top of the remote panel when it is opened over HTTPS.
|
|
218
218
|
|
|
219
|
-
- Version 0.4.
|
|
219
|
+
- Version 0.4.7 has been contract-checked and boot-tested against DSH `0.1.7-alpha.2`, `0.1.7-rc.1`, and `0.1.7-rc.2` (renderer-v2). The DSH page must expose the standard session, `main`/`panelInfo`, and `rightbar` slots; the community plugin must register its panel or sidebar content through DSH's standard entry points.
|
|
220
220
|
- The gateway allows first-party DSH WebSocket paths by default, including `/sidebar/ws/terminal`. Other paths used by community sidebar plugins are blocked by default and appear in Diagnostics; the `/sidebar/ws/agent-opens` and `/sidebar/ws/agent-terminals` paths in the image are examples that must be reviewed for the actual plugin.
|
|
221
221
|
- In **Connection diagnostics → Third-party WebSocket paths**, select **Allow** only for an exact path you have verified. Query strings and fuzzy prefixes are rejected; **Allow all** is not recommended. Approved paths can be removed at any time, and the same policy applies to LAN and remote connections.
|
|
222
222
|
- Approval only lets that path pass through the authenticated, same-origin DSH Mobile gateway. It does not open arbitrary TCP/UDP ports or bypass device pairing. If a community plugin still fails, check the path recorded by Diagnostics and approve one path at a time.
|
|
223
223
|
|
|
224
|
+
If another remote-access plugin shows its own “not paired” page inside DSH Mobile, the two authorization systems are separate. Temporarily turn off the other plugin's remote access on the computer to check whether the Mobile path recovers; do not enter a DSH Mobile pairing key on that page. Excluding its client module below does not necessarily remove a request-rewriting script injected before client boot. See [#111](https://github.com/saya-ch/dsh-mobile/issues/111).
|
|
225
|
+
|
|
226
|
+
Advanced users can reduce mobile startup traffic by adding exact package ids to `excludedClientModules` in the current profile's `mobile-access` plugin configuration, then restarting DSH. This changes only the dedicated mobile page served through the gateway; desktop and `?frontend=stock` pages are unaffected. If both packages are present in the current boot graph, this example removes document preview and its dependent “Open In…” feature:
|
|
227
|
+
|
|
228
|
+
```yaml
|
|
229
|
+
excludedClientModules:
|
|
230
|
+
- '@deepseek-ai/dsh-client-ui-sidebar-documentpreview'
|
|
231
|
+
- '@deepseek-ai/dsh-client-ui-open-in-app'
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
There is no default exclusion list. The plugin rejects unknown or boot-critical modules and modules still referenced through `inject` or `external` by retained entries. If a DSH or community-plugin update invalidates the selection, the mobile page returns `409 excluded_client_modules_invalid` with the conflicting module; the computer also warns so you can adjust or remove the option. Bundle sizes and dependencies change between DSH installations and versions; another user's savings are not a prediction for yours.
|
|
235
|
+
|
|
224
236
|
<table>
|
|
225
237
|
<tr>
|
|
226
238
|
<td align="center" valign="top" width="50%">
|
|
@@ -304,6 +316,7 @@ On macOS, local network, self-hosted FRP, and the own reverse proxy work; the th
|
|
|
304
316
|
|
|
305
317
|
| DSH Mobile plugin | Verified DeepSeek Harness version |
|
|
306
318
|
| --- | --- |
|
|
319
|
+
| `0.4.7` | `0.1.7-alpha.2`, `0.1.7-rc.1`, and `0.1.7-rc.2` (source contract, isolated pairing, and workspace baseline over WebSocket) |
|
|
307
320
|
| `0.4.6` | `0.1.7-alpha.2` and `0.1.7-rc.1` (source contract, isolated pairing, and workspace baseline over WebSocket) |
|
|
308
321
|
| `0.4.5` | `0.1.7-alpha.2` (source contract check, local and remote gateway integration) |
|
|
309
322
|
| `0.4.4` | `0.1.6-alpha.2` (local source and renderer-v2 contract check) |
|
|
@@ -320,6 +333,8 @@ On macOS, local network, self-hosted FRP, and the own reverse proxy work; the th
|
|
|
320
333
|
|
|
321
334
|
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.
|
|
322
335
|
|
|
336
|
+
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.
|
|
337
|
+
|
|
323
338
|
## Uninstall
|
|
324
339
|
|
|
325
340
|
```powershell
|
|
@@ -346,11 +361,11 @@ npm ci
|
|
|
346
361
|
npm run verify
|
|
347
362
|
```
|
|
348
363
|
|
|
349
|
-
The real browser-startup smoke uses a temporary DSH home, OS-assigned loopback ports, and Chromium pairing. It neither reads an existing user profile nor sends a model request. CI tests
|
|
364
|
+
The real browser-startup smoke uses a temporary DSH home, OS-assigned loopback ports, and Chromium pairing. It neither reads an existing user profile nor sends a model request. CI tests DSH `0.1.7-alpha.2`, `0.1.7-rc.1`, and `0.1.7-rc.2`; install rc.2 in a separate directory locally so it does not replace the plugin's development dependencies:
|
|
350
365
|
|
|
351
366
|
```powershell
|
|
352
367
|
$dshMobileTestRuntime = Join-Path $env:TEMP 'dsh-mobile-test-runtime'
|
|
353
|
-
npm install --prefix $dshMobileTestRuntime --no-save --package-lock=false @deepseek-ai/dsh@0.1.7-rc.
|
|
368
|
+
npm install --prefix $dshMobileTestRuntime --no-save --package-lock=false @deepseek-ai/dsh@0.1.7-rc.2
|
|
354
369
|
$env:DSH_BOOT_SMOKE_BIN = Join-Path $dshMobileTestRuntime 'node_modules/@deepseek-ai/dsh/lib/bin.js'
|
|
355
370
|
npx playwright install chromium --only-shell
|
|
356
371
|
npm run smoke:dsh-boot
|
package/README.md
CHANGED
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
|
|
32
32
|
> DSH Mobile 是 DeepSeek Harness 社区插件,原生 App 仅支持 Android。
|
|
33
33
|
>
|
|
34
|
-
> **当前版本:0.4.
|
|
34
|
+
> **当前版本:0.4.7**。适配 DSH `0.1.7-rc.2`,减少移动端启动资源的重复下载,并改善 Android 连接恢复、窄屏侧栏与输入体验。[更新记录](CHANGELOG.md#047---2026-09-25)。
|
|
35
35
|
>
|
|
36
|
-
> **升级提醒**:建议插件与 Android App 同步更新至 0.4.
|
|
36
|
+
> **升级提醒**:建议插件与 Android App 同步更新至 0.4.7,已有配对会保留。自签 FRP 入口需要至少 0.4.6 App;更早的 App 仍可使用原有局域网和受信任证书的远程连接。[兼容说明](#兼容性)。
|
|
37
37
|
|
|
38
38
|
<p align="center">
|
|
39
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.
|
|
40
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.
|
|
41
|
-
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.4.
|
|
39
|
+
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.4.7/dsh-mobile-android-v0.4.7.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.4.7/dsh-mobile-android-v0.4.7.apk"><strong>下载 Android App 0.4.7</strong></a><br>
|
|
41
|
+
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.4.7">版本说明与校验文件</a></sub>
|
|
42
42
|
</p>
|
|
43
43
|
|
|
44
44
|
DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App 通过局域网,或可选的 Tailscale Funnel、cpolar、cloudflared、自建 FRP 或自有反向代理远程通道连接电脑,继续使用同一份会话、工作区、消息和工具。局域网与远程访问分别启停、分别管理设备,且都不修改 DeepSeek Harness 源码。
|
|
@@ -216,11 +216,23 @@ Android App 用一个“已配对设备”列表同时显示多台电脑:局
|
|
|
216
216
|
|
|
217
217
|
代理页面为兼容部分社区插件允许嵌入 HTTP 页面;这类内容未加密,可能被篡改,浏览器也可能因混合内容策略拦截。处理敏感内容时请使用 HTTPS。通过 HTTPS 管理入口打开远程面板时,页面顶部会显示相同提醒。
|
|
218
218
|
|
|
219
|
-
- 0.4.
|
|
219
|
+
- 0.4.7 已按 DSH `0.1.7-alpha.2`、`0.1.7-rc.1` 和 `0.1.7-rc.2` 做 renderer-v2 契约检查与隔离启动联调。DSH 页面需要提供标准的会话、`main`/`panelInfo` 和 `rightbar` 插槽;插件自身需要通过 DSH 的标准面板或侧边栏入口注册内容。
|
|
220
220
|
- 网关默认只允许 DSH 内置的第一方 WebSocket 路径。社区侧边栏插件使用的其他路径默认拦截,通常会在诊断页显示为待处理项目;截图中的`/sidebar/ws/agent-opens` 和`/sidebar/ws/agent-terminals` 就属于这类需要按实际插件确认的路径。
|
|
221
221
|
- 在 **连接诊断 → 第三方 WebSocket 路径** 中,只对确认过的精确路径点击 **允许**。系统不接受带查询字符串或模糊前缀的路径;不建议使用“全部允许”。已允许的路径可以随时移除,局域网和远程连接使用同一套规则。
|
|
222
222
|
- 放行只代表该路径可以通过已认证、同源的 DSH Mobile 网关,不会开放任意 TCP/UDP 端口,也不会绕过设备配对。若社区插件仍然连接失败,先看诊断页的实际拦截路径,再按一条路径放行。
|
|
223
223
|
|
|
224
|
+
若另一个远程访问插件在 DSH Mobile 页面上显示自己的“未配对”提示,那是两套不同的授权。可先在电脑端暂时关闭另一插件的远程访问,确认 Mobile 链路是否恢复;不要把 DSH Mobile 密钥输入它的配对页。仅用下面的模块排除选项不能保证移除该插件在页面启动前注入的请求改写脚本,参见 [#111](https://github.com/saya-ch/dsh-mobile/issues/111)。
|
|
225
|
+
|
|
226
|
+
若某个不需要的客户端插件显著增加手机首次加载流量,高级用户可在当前 profile 的 `mobile-access` 插件配置中设置 `excludedClientModules`,填入启动清单中的**准确包名**,重启 DSH 后生效。它只改变经网关提供的专用移动页面;电脑端和 `?frontend=stock` 页面不变。例如,若当前启动清单同时包含以下两个包,下面的配置会移除文档预览及依赖它的“在应用中打开”功能:
|
|
227
|
+
|
|
228
|
+
```yaml
|
|
229
|
+
excludedClientModules:
|
|
230
|
+
- '@deepseek-ai/dsh-client-ui-sidebar-documentpreview'
|
|
231
|
+
- '@deepseek-ai/dsh-client-ui-open-in-app'
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
这是按安装环境选择的高级配置,没有默认排除列表。插件会拒绝不存在的包、启动必需模块,以及仍被保留模块通过 `inject` 或 `external` 引用的包;配置不匹配当前 DSH 或社区插件时,移动页面返回 `409 excluded_client_modules_invalid` 和冲突详情,电脑端也会提示,移除或调整配置即可恢复。模块内容与依赖会随 DSH 版本变化,不能把其他人的节省比例当作自己的预期。
|
|
235
|
+
|
|
224
236
|
<table>
|
|
225
237
|
<tr>
|
|
226
238
|
<td align="center" valign="top" width="50%">
|
|
@@ -304,6 +316,7 @@ macOS 上局域网、自建 FRP 与自有反向代理可用;三个托管组件
|
|
|
304
316
|
|
|
305
317
|
| DSH Mobile 插件 | 验证支持的 DeepSeek Harness 版本 |
|
|
306
318
|
| ----------------------------------------- | -------------------------------------------------------------- |
|
|
319
|
+
| `0.4.7` | `0.1.7-alpha.2`、`0.1.7-rc.1`、`0.1.7-rc.2`(源码契约、隔离配对及 WebSocket 工作区读取) |
|
|
307
320
|
| `0.4.6` | `0.1.7-alpha.2`、`0.1.7-rc.1`(源码契约、隔离配对及 WebSocket 工作区读取) |
|
|
308
321
|
| `0.4.5` | `0.1.7-alpha.2`(源码契约检查、本机局域网及远程网关联调) |
|
|
309
322
|
| `0.4.4` | `0.1.6-alpha.2`(本机源码与 renderer-v2 契约检查) |
|
|
@@ -320,6 +333,8 @@ macOS 上局域网、自建 FRP 与自有反向代理可用;三个托管组件
|
|
|
320
333
|
|
|
321
334
|
现有 App(0.3.3 及更新)无需重新配对;cpolar 用户应使用 0.3.15 或更新 App,较早版本可能在免费线路的慢速首次加载完成前超时;更早的 App 还使用不同的状态栏策略。App 0.4.0 才支持多设备列表、启动行为设置和电脑端撤销状态同步;旧版 App 仍可连接已保存的单台设备。App 0.1.3 及更早版本需卸载重装并重新配对。
|
|
322
335
|
|
|
336
|
+
GitHub Release 的正式 APK 使用固定签名,可从同一签名的旧正式版原位升级并保留配对。自行构建的 Debug APK 若使用不同签名,不能直接覆盖安装正式版;切换前请准备重新配对。
|
|
337
|
+
|
|
323
338
|
## 卸载
|
|
324
339
|
|
|
325
340
|
```powershell
|
|
@@ -346,11 +361,11 @@ npm ci
|
|
|
346
361
|
npm run verify
|
|
347
362
|
```
|
|
348
363
|
|
|
349
|
-
真实启动冒烟另用临时 DSH Home、随机回环端口和 Chromium 配对,不访问现有用户配置,也不发送模型请求。CI 分别测试 DSH `0.1.7-alpha.2` 与 `0.1.7-rc.
|
|
364
|
+
真实启动冒烟另用临时 DSH Home、随机回环端口和 Chromium 配对,不访问现有用户配置,也不发送模型请求。CI 分别测试 DSH `0.1.7-alpha.2`、`0.1.7-rc.1` 与 `0.1.7-rc.2`;本机可把 rc.2 装在独立目录,避免替换插件的开发依赖:
|
|
350
365
|
|
|
351
366
|
```powershell
|
|
352
367
|
$dshMobileTestRuntime = Join-Path $env:TEMP 'dsh-mobile-test-runtime'
|
|
353
|
-
npm install --prefix $dshMobileTestRuntime --no-save --package-lock=false @deepseek-ai/dsh@0.1.7-rc.
|
|
368
|
+
npm install --prefix $dshMobileTestRuntime --no-save --package-lock=false @deepseek-ai/dsh@0.1.7-rc.2
|
|
354
369
|
$env:DSH_BOOT_SMOKE_BIN = Join-Path $dshMobileTestRuntime 'node_modules/@deepseek-ai/dsh/lib/bin.js'
|
|
355
370
|
npx playwright install chromium --only-shell
|
|
356
371
|
npm run smoke:dsh-boot
|
package/lib/client.js
CHANGED
|
@@ -2839,6 +2839,48 @@ window.__ModuleLoader__.load({
|
|
|
2839
2839
|
function drawerScrimVisible(sidebarCollapsed, overlayActive) {
|
|
2840
2840
|
return !sidebarCollapsed && overlayActive;
|
|
2841
2841
|
}
|
|
2842
|
+
/** Only a known on-screen keyboard in an active App composer may change Enter into a line break. */
|
|
2843
|
+
function isSoftKeyboardEnterLineBreak(event, context) {
|
|
2844
|
+
if (context.nativeState?.imeVisible !== true || context.nativeState.noHardwareKeyboard !== true || !context.editable || !context.activeSession || context.commandMenuOpen || context.recentlyComposing) return false;
|
|
2845
|
+
if (!event.isTrusted || event.key !== "Enter" || event.isComposing || event.keyCode === 229 || event.repeat) return false;
|
|
2846
|
+
return !event.shiftKey && !event.altKey && !event.ctrlKey && !event.metaKey && !event.getModifierState("AltGraph");
|
|
2847
|
+
}
|
|
2848
|
+
/** Attach the App-only Enter translation while retaining DSH's original physical-key semantics. */
|
|
2849
|
+
function bindComposerSoftEnter(editor, context) {
|
|
2850
|
+
let composing = false;
|
|
2851
|
+
let composingUntil = 0;
|
|
2852
|
+
const onCompositionStart = () => {
|
|
2853
|
+
composing = true;
|
|
2854
|
+
};
|
|
2855
|
+
const onCompositionEnd = () => {
|
|
2856
|
+
composing = false;
|
|
2857
|
+
composingUntil = performance.now() + 10;
|
|
2858
|
+
};
|
|
2859
|
+
const onKeyDown = (event) => {
|
|
2860
|
+
if (!isSoftKeyboardEnterLineBreak(event, {
|
|
2861
|
+
...context(),
|
|
2862
|
+
recentlyComposing: composing || editor.hasAttribute("data-composer-composing") || performance.now() < composingUntil
|
|
2863
|
+
})) return;
|
|
2864
|
+
event.preventDefault();
|
|
2865
|
+
event.stopImmediatePropagation();
|
|
2866
|
+
editor.dispatchEvent(new KeyboardEvent("keydown", {
|
|
2867
|
+
key: "Enter",
|
|
2868
|
+
code: "Enter",
|
|
2869
|
+
shiftKey: true,
|
|
2870
|
+
bubbles: true,
|
|
2871
|
+
cancelable: true,
|
|
2872
|
+
composed: true
|
|
2873
|
+
}));
|
|
2874
|
+
};
|
|
2875
|
+
editor.addEventListener("compositionstart", onCompositionStart);
|
|
2876
|
+
editor.addEventListener("compositionend", onCompositionEnd);
|
|
2877
|
+
editor.addEventListener("keydown", onKeyDown, { capture: true });
|
|
2878
|
+
return () => {
|
|
2879
|
+
editor.removeEventListener("compositionstart", onCompositionStart);
|
|
2880
|
+
editor.removeEventListener("compositionend", onCompositionEnd);
|
|
2881
|
+
editor.removeEventListener("keydown", onKeyDown, { capture: true });
|
|
2882
|
+
};
|
|
2883
|
+
}
|
|
2842
2884
|
/** Check that an asynchronous picker result still belongs to its originating session and composer. */
|
|
2843
2885
|
function isComposerMediaOriginCurrent(origin, current) {
|
|
2844
2886
|
return !current.disposed && origin.generation === current.generation && origin.href === current.href && origin.composer !== null && current.composerConnected && origin.composer === current.composer && origin.sessionRoot !== null && origin.sessionRoot === current.sessionRoot && origin.sessionId !== null && origin.sessionId === current.sessionId;
|
|
@@ -2935,6 +2977,9 @@ window.__ModuleLoader__.load({
|
|
|
2935
2977
|
const canAcceptComposerDrop = () => preflightComposerImageDrop(document, [preflightFile]);
|
|
2936
2978
|
const mediaPickerAbortController = new AbortController();
|
|
2937
2979
|
const browserPickerCleanups = /* @__PURE__ */ new Set();
|
|
2980
|
+
let boundEnterEditor = null;
|
|
2981
|
+
let boundEnterCard = null;
|
|
2982
|
+
let disposeEnterBinding;
|
|
2938
2983
|
const sessionTokens = /* @__PURE__ */ new WeakMap();
|
|
2939
2984
|
let nextSessionToken = 0;
|
|
2940
2985
|
const currentSessionOrigin = () => {
|
|
@@ -3200,6 +3245,19 @@ window.__ModuleLoader__.load({
|
|
|
3200
3245
|
});
|
|
3201
3246
|
};
|
|
3202
3247
|
document.addEventListener("click", animateNavigation);
|
|
3248
|
+
const syncComposerEnterNewline = (composerCard) => {
|
|
3249
|
+
const editor = composerCard?.querySelector("[data-composer-input][contenteditable=\"true\"]") ?? null;
|
|
3250
|
+
if (editor === boundEnterEditor && composerCard === boundEnterCard) return;
|
|
3251
|
+
disposeEnterBinding?.();
|
|
3252
|
+
boundEnterEditor = editor;
|
|
3253
|
+
boundEnterCard = composerCard;
|
|
3254
|
+
disposeEnterBinding = editor === null || composerCard === null ? void 0 : bindComposerSoftEnter(editor, () => ({
|
|
3255
|
+
nativeState: window.__DSH_MOBILE_NATIVE__ === void 0 ? null : window.__DSH_MOBILE_KEYBOARD_STATE__,
|
|
3256
|
+
editable: editor.isConnected && editor.getAttribute("contenteditable") === "true" && editor.getAttribute("aria-disabled") !== "true" && editor.getAttribute("aria-haspopup") !== "menu" && composerCard.getAttribute("aria-busy") !== "true",
|
|
3257
|
+
activeSession: currentSessionOrigin().sessionId !== null,
|
|
3258
|
+
commandMenuOpen: composerCard.querySelector("[data-trigger-menu],button[aria-haspopup=\"listbox\"][aria-expanded=\"true\"]") !== null
|
|
3259
|
+
}));
|
|
3260
|
+
};
|
|
3203
3261
|
const syncMediaBinding = (composer) => {
|
|
3204
3262
|
const previousComposer = boundComposer;
|
|
3205
3263
|
boundComposer = composer;
|
|
@@ -3222,6 +3280,7 @@ window.__ModuleLoader__.load({
|
|
|
3222
3280
|
const handle = frame === void 0 ? void 0 : firstByClassSuffix(frame, "_handle");
|
|
3223
3281
|
markNativeMobileSettings(document);
|
|
3224
3282
|
if (center === void 0) {
|
|
3283
|
+
syncComposerEnterNewline(null);
|
|
3225
3284
|
bindHistoryScroller(void 0);
|
|
3226
3285
|
syncMediaBinding(null);
|
|
3227
3286
|
setCameraActionDisabled(true, label("Apri prima una sessione", "Open a session first", "请先打开会话"));
|
|
@@ -3262,6 +3321,7 @@ window.__ModuleLoader__.load({
|
|
|
3262
3321
|
const composerCard = center.querySelector("[data-composer-card]");
|
|
3263
3322
|
const composerRow = composerCard?.querySelector(":scope > [data-input-scroll]")?.nextElementSibling;
|
|
3264
3323
|
if (!(composerRow instanceof HTMLElement)) {
|
|
3324
|
+
syncComposerEnterNewline(null);
|
|
3265
3325
|
syncMediaBinding(null);
|
|
3266
3326
|
setCameraActionDisabled(true, label("Apri prima una sessione", "Open a session first", "请先打开会话"));
|
|
3267
3327
|
cameraButton.remove();
|
|
@@ -3274,6 +3334,7 @@ window.__ModuleLoader__.load({
|
|
|
3274
3334
|
if (composerTools !== void 0) {
|
|
3275
3335
|
composerTools.dataset.dshMobileComposerTools = "true";
|
|
3276
3336
|
syncMediaBinding(composerCard ?? null);
|
|
3337
|
+
syncComposerEnterNewline(composerCard ?? null);
|
|
3277
3338
|
const composerInput = composerCard?.querySelector("textarea");
|
|
3278
3339
|
const composerEditor = composerCard?.querySelector("[contenteditable=\"true\"],[contenteditable=\"plaintext-only\"]");
|
|
3279
3340
|
const composerBusy = composerCard?.getAttribute("aria-busy") === "true" || composerInput?.disabled === true || composerInput?.readOnly === true || composerEditor?.getAttribute("aria-disabled") === "true";
|
|
@@ -3284,7 +3345,7 @@ window.__ModuleLoader__.load({
|
|
|
3284
3345
|
const commandMenu = composerCard?.querySelector("[data-trigger-menu]") ?? null;
|
|
3285
3346
|
if (commandMenu !== null) placeCameraAction(commandMenu);
|
|
3286
3347
|
else cameraButton.remove();
|
|
3287
|
-
}
|
|
3348
|
+
} else syncComposerEnterNewline(null);
|
|
3288
3349
|
if (composerTrailing !== void 0 && composerTrailing !== composerTools) {
|
|
3289
3350
|
composerTrailing.dataset.dshMobileComposerTrailing = "true";
|
|
3290
3351
|
const modelTrigger = composerTrailing.querySelector("button[aria-label^=\"选择模型\"],button[aria-label^=\"Select model\"],button[aria-label^=\"Seleziona modello\"]");
|
|
@@ -3356,6 +3417,7 @@ window.__ModuleLoader__.load({
|
|
|
3356
3417
|
mediaPickerAbortController.abort();
|
|
3357
3418
|
restoreLanguageMarker();
|
|
3358
3419
|
for (const cleanup of [...browserPickerCleanups]) cleanup();
|
|
3420
|
+
disposeEnterBinding?.();
|
|
3359
3421
|
observer.disconnect();
|
|
3360
3422
|
overlayQuery.removeEventListener("change", schedule);
|
|
3361
3423
|
document.removeEventListener("click", onBranchClick, true);
|