dsh-mobile 0.3.5 → 0.3.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 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.3.7 - 2026-09-02
6
+
7
+ - Fix the Windows DSH Desktop startup failure reported in [#22](https://github.com/saya-ch/dsh-mobile/issues/22): capture subprocess output through the callback API instead of relying on `execFile` promisify metadata that a host wrapper may omit. Thanks @XChen446 for the precise 0.3.6 stack trace.
8
+ - Apply the same output handling to Windows SID resolution, private-file ACLs, route selection, and firewall diagnostics/setup. Invalid SID output and ACL failures still reject the operation; a failed SID lookup can be retried and Windows permission commands have bounded execution time.
9
+ - Retain the 0.3.6 removal of the exact DSH version allowlist. Existing 0.3.3-0.3.6 Android apps and paired devices remain compatible; the 0.3.7 APK updates version metadata only.
10
+
11
+ ## 0.3.6 - 2026-09-02
12
+
13
+ - Remove the fixed DeepSeek Harness version allowlist from plugin startup and npm peer metadata. A compatible future DSH release can now load without waiting for DSH Mobile to enumerate its exact prerelease version.
14
+ - Verify the mobile frontend and trust contracts against DSH 0.1.2-alpha.3 and 0.1.2-alpha.4, while retaining the upstream-source CI gate that rejects actual interface changes instead of version-number changes.
15
+ - Keep the pairing protocol and Android behavior unchanged; existing 0.3.3-0.3.5 apps and paired devices remain compatible.
16
+
5
17
  ## 0.3.5 - 2026-09-01
6
18
 
7
19
  - Fix [#26](https://github.com/saya-ch/dsh-mobile/issues/26): prevent mobile startup from remaining on “Loading plugins” over LAN or remote access when DSH sends the WebSocket upgrade response and initial snapshot together. The gateway now preserves that snapshot without relaxing its 16 KiB response-header limit. Thanks @oliverwan97 for the detailed report.
package/README.en.md CHANGED
@@ -19,14 +19,14 @@
19
19
 
20
20
  > DSH Mobile is a DeepSeek Harness community plugin; the native app supports Android only.
21
21
  >
22
- > **0.3.5 update**: fix a mobile startup hang when DSH sends a large first WebSocket payload immediately after the upgrade response; the fix applies to both LAN and remote access, and existing 0.3.3/0.3.4 apps do not need re-pairing. [Details and acknowledgements](CHANGELOG.md).
22
+ > **0.3.7 update**: fix a Windows DSH Desktop startup crash when capturing system-command output, including the related route-selection and firewall-diagnostic paths. The 0.3.6 DSH version policy and private-file protections remain intact. [Details](CHANGELOG.md).
23
23
  >
24
- > **Upgrade reminder**: the plugin is evolving rapidly; keep it and the app updated together. DSH 0.1.2-alpha.2 requires Mobile plugin 0.3.4 or later. [Compatibility notes](#compatibility).
24
+ > **Upgrade reminder**: Windows DSH Desktop users should update to plugin 0.3.7. Existing 0.3.3-0.3.6 apps and paired devices remain compatible without re-pairing. [Compatibility notes](#compatibility).
25
25
 
26
26
  <p align="center">
27
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.5/dsh-mobile-android-v0.3.5.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile Android app icon" width="72" height="72"></a><br>
28
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.5/dsh-mobile-android-v0.3.5.apk"><strong>Download Android app 0.3.5</strong></a><br>
29
- <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.5">Release notes and checksums</a></sub>
27
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.7/dsh-mobile-android-v0.3.7.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile Android app icon" width="72" height="72"></a><br>
28
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.7/dsh-mobile-android-v0.3.7.apk"><strong>Download Android app 0.3.7</strong></a><br>
29
+ <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.7">Release notes and checksums</a></sub>
30
30
  </p>
31
31
 
32
32
  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, or self-hosted FRP 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.
@@ -190,10 +190,11 @@ See [SECURITY.md](SECURITY.md).
190
190
 
191
191
  ## Compatibility
192
192
 
193
- Use Mobile plugin 0.3.4 or later with DSH 0.1.2-alpha.2; plugin and app 0.3.2 or later are recommended for DSH 0.1.2-alpha.1. Plugin 0.3.5 remains compatible with existing 0.3.3/0.3.4 apps without re-pairing; the 0.3.5 Android build changes version metadata only and keeps the same behavior. Earlier apps use a different status-bar strategy, so updating both is recommended. App 0.1.3 or earlier requires reinstalling and pairing again.
193
+ DSH Mobile 0.3.6 no longer blocks startup by exact DSH version and has verified the mobile frontend and connection interfaces in DSH 0.1.2-alpha.3/alpha.4. Existing 0.3.3-0.3.5 apps do not need re-pairing; the 0.3.6 Android build changes version metadata only. Earlier apps use a different status-bar strategy, so updating both is recommended. App 0.1.3 or earlier requires reinstalling and pairing again.
194
194
 
195
195
  | DSH Mobile | Verified DeepSeek Harness releases |
196
196
  | --- | --- |
197
+ | `0.3.6` | `0.1.0-rc.5`, `rc.6`, `rc.7`, `0.1.1-rc.2`, and `0.1.2-alpha.1` through `alpha.4`; unlisted versions are no longer rejected by version alone |
197
198
  | `0.3.5` | `0.1.0-rc.5`, `0.1.0-rc.6`, `0.1.0-rc.7`, `0.1.1-rc.2`, `0.1.2-alpha.1`, `0.1.2-alpha.2` |
198
199
  | `0.3.4` | `0.1.0-rc.5`, `0.1.0-rc.6`, `0.1.0-rc.7`, `0.1.1-rc.2`, `0.1.2-alpha.1`, `0.1.2-alpha.2` |
199
200
  | `0.3.3` | `0.1.0-rc.5`, `0.1.0-rc.6`, `0.1.0-rc.7`, `0.1.1-rc.2`, `0.1.2-alpha.1` |
@@ -205,7 +206,7 @@ Use Mobile plugin 0.3.4 or later with DSH 0.1.2-alpha.2; plugin and app 0.3.2 or
205
206
  | `0.2.0` | `0.1.0-rc.5`, `0.1.0-rc.6`, `0.1.0-rc.7`, `0.1.1-rc.2` |
206
207
  | `0.1.4` | `0.1.0-rc.5`, `0.1.0-rc.6`, `0.1.0-rc.7`, `0.1.1-rc.2` |
207
208
 
208
- At startup, the plugin verifies the DSH Host version and the frontend dependencies required by the mobile layout; an unverified release fails with a clear error instead of serving a broken page. CI also tracks the DSH main branch layout contract. If a DSH upgrade reports an incompatibility, update DSH Mobile first.
209
+ The plugin no longer uses a runtime version allowlist. CI continuously checks the frontend, connection, and trust interfaces used from the DSH main branch, so adaptation is required only when those interfaces actually change. If a future DSH update causes a real display or connection failure, update DSH Mobile and include diagnostics in the report.
209
210
 
210
211
  0.3.4 fixes duplicate directory-picker registration in Windows [DSH Desktop](https://github.com/anywhere-labs/dsh-desktop). It reuses the desktop host's in-page directory browser; standalone Web launches still let phones select workspaces on the computer. Mobile access through Desktop requires compatibility mode and browser access enabled, with Mobile's upstream address matching Desktop's listening port.
211
212
 
package/README.md CHANGED
@@ -26,14 +26,14 @@
26
26
 
27
27
  > DSH Mobile 是 DeepSeek Harness 社区插件,原生 App 仅支持 Android。
28
28
  >
29
- > **0.3.5 更新**:修复 DSH WebSocket 握手后立即发送较大首批数据时,移动端可能一直停在插件加载界面的问题,局域网与远程连接均适用;现有 0.3.3/0.3.4 App 无需重新配对。[详细记录与致谢](CHANGELOG.md)。
29
+ > **0.3.7 更新**:修复 Windows DSH Desktop 获取系统命令输出时的启动崩溃,同步完善网卡选择与防火墙诊断;保留 0.3.6 DSH 版本开放策略和私有文件权限保护。[详细记录](CHANGELOG.md)。
30
30
  >
31
- > **升级提醒**:插件仍在快速迭代,建议与 App 同步更新;DSH 0.1.2-alpha.2 需使用 Mobile 插件 0.3.4 或更高版本。[兼容说明](#兼容性)。
31
+ > **升级提醒**:Windows DSH Desktop 用户请更新至插件 0.3.7;现有 0.3.3-0.3.6 App 可继续使用,无需重新配对。[兼容说明](#兼容性)。
32
32
 
33
33
  <p align="center">
34
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.5/dsh-mobile-android-v0.3.5.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile 安卓应用图标" width="72" height="72"></a><br>
35
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.5/dsh-mobile-android-v0.3.5.apk"><strong>下载 Android App 0.3.5</strong></a><br>
36
- <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.5">版本说明与校验文件</a></sub>
34
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.7/dsh-mobile-android-v0.3.7.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile 安卓应用图标" width="72" height="72"></a><br>
35
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.7/dsh-mobile-android-v0.3.7.apk"><strong>下载 Android App 0.3.7</strong></a><br>
36
+ <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.7">版本说明与校验文件</a></sub>
37
37
  </p>
38
38
 
39
39
  DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App 通过局域网,或可选的 Tailscale Funnel、cpolar、自建 FRP 远程通道连接电脑,继续使用同一份会话、工作区、消息和工具。局域网与远程访问分别启停、分别管理设备,且都不修改 DeepSeek Harness 源码。
@@ -199,10 +199,11 @@ flowchart LR
199
199
 
200
200
  ## 兼容性
201
201
 
202
- DSH 0.1.2-alpha.2 需搭配 Mobile 插件 0.3.4 或更高版本;DSH 0.1.2-alpha.1 建议搭配插件与 App 0.3.2 或更高版本。0.3.5 插件兼容现有 0.3.3/0.3.4 App,无需重新配对;本次 Android App 仅同步版本号,功能行为不变。更早的 App 使用不同的状态栏策略,建议同步升级;App 0.1.3 及更早版本需卸载重装并重新配对。
202
+ DSH Mobile 0.3.6 不再按 DSH 精确版本号阻止启动,并已验证 DSH 0.1.2-alpha.3/alpha.4 的移动前端与连接接口。现有 0.3.3-0.3.5 App 无需重新配对;0.3.6 Android App 仅同步版本信息,功能行为不变。更早的 App 使用不同的状态栏策略,建议同步升级;App 0.1.3 及更早版本需卸载重装并重新配对。
203
203
 
204
204
  | DSH Mobile | 已验证的 DeepSeek Harness |
205
205
  | ------------ | ------------------------------------------------------------------------- |
206
+ | `0.3.6` | `0.1.0-rc.5`、`0.1.0-rc.6`、`0.1.0-rc.7`、`0.1.1-rc.2`、`0.1.2-alpha.1` 至 `alpha.4`;未列版本不再仅因版本号被拒绝 |
206
207
  | `0.3.5` | `0.1.0-rc.5`、`0.1.0-rc.6`、`0.1.0-rc.7`、`0.1.1-rc.2`、`0.1.2-alpha.1`、`0.1.2-alpha.2` |
207
208
  | `0.3.4` | `0.1.0-rc.5`、`0.1.0-rc.6`、`0.1.0-rc.7`、`0.1.1-rc.2`、`0.1.2-alpha.1`、`0.1.2-alpha.2` |
208
209
  | `0.3.3` | `0.1.0-rc.5`、`0.1.0-rc.6`、`0.1.0-rc.7`、`0.1.1-rc.2`、`0.1.2-alpha.1` |
@@ -214,7 +215,7 @@ DSH 0.1.2-alpha.2 需搭配 Mobile 插件 0.3.4 或更高版本;DSH 0.1.2-alph
214
215
  | `0.2.0` | `0.1.0-rc.5`、`0.1.0-rc.6`、`0.1.0-rc.7`、`0.1.1-rc.2` |
215
216
  | `0.1.4` | `0.1.0-rc.5`、`0.1.0-rc.6`、`0.1.0-rc.7`、`0.1.1-rc.2` |
216
217
 
217
- 插件启动时会检查 DSH Host 版本和移动布局所需的前端依赖,遇到未经验证的版本会直接报错而不是带病启动;CI 也会持续跟踪 DSH 主分支的布局契约。升级 DSH 后如遇兼容提示,请先升级 DSH Mobile
218
+ 插件不再使用运行时版本白名单;CI 会持续检查 DSH 主分支真实使用的前端、连接与信任接口,只有接口变化才需要适配。未来 DSH 更新若出现实际显示或连接异常,请升级 DSH Mobile 并提交诊断信息。
218
219
 
219
220
  0.3.4 修复 Windows [DSH Desktop](https://github.com/anywhere-labs/dsh-desktop) 的目录选择器重复注册问题:复用桌面宿主的页面内目录浏览器,普通 Web 启动仍保留手机选择电脑工作区的能力。Desktop 连接手机时需使用兼容模式并启用浏览器访问,Mobile 的上游地址应与 Desktop 的监听端口一致。
220
221
 
package/lib/cli.js CHANGED
@@ -3,27 +3,54 @@ import { execFile } from "node:child_process";
3
3
  import { chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
4
4
  import { homedir, networkInterfaces } from "node:os";
5
5
  import { basename, dirname, join, resolve } from "node:path";
6
- import { promisify } from "node:util";
7
6
  import { X509Certificate, createPrivateKey, createPublicKey } from "node:crypto";
8
7
  import { generate } from "selfsigned";
9
8
  import "@deepseek-ai/cordis";
10
9
  import "@deepseek-ai/schemastery";
10
+ //#region src/exec-file.ts
11
+ /** Capture both output streams even when a desktop host wraps execFile without Node's promisify metadata. */
12
+ function execFileText(file, args, options = {}) {
13
+ return new Promise((resolve, reject) => {
14
+ execFile(file, [...args], {
15
+ windowsHide: true,
16
+ ...options,
17
+ encoding: "utf8"
18
+ }, (error, stdout, stderr) => {
19
+ if (error !== null) {
20
+ reject(error);
21
+ return;
22
+ }
23
+ if (typeof stdout !== "string" || typeof stderr !== "string") {
24
+ reject(/* @__PURE__ */ new Error("subprocess returned invalid text output"));
25
+ return;
26
+ }
27
+ resolve({
28
+ stdout,
29
+ stderr
30
+ });
31
+ });
32
+ });
33
+ }
34
+ //#endregion
11
35
  //#region src/private-file.ts
12
- const execFile$3 = promisify(execFile);
13
36
  let userSidTask;
14
37
  async function currentWindowsUserSid() {
15
- userSidTask ??= execFile$3("whoami.exe", [
38
+ userSidTask ??= execFileText("whoami.exe", [
16
39
  "/user",
17
40
  "/fo",
18
41
  "csv",
19
42
  "/nh"
20
43
  ], {
21
44
  encoding: "utf8",
22
- windowsHide: true
45
+ windowsHide: true,
46
+ timeout: 1e4
23
47
  }).then(({ stdout }) => {
24
48
  const match = /,"(S-\d(?:-\d+)+)"\s*$/u.exec(stdout.trim());
25
49
  if (match?.[1] === void 0) throw new Error("unable to resolve the current Windows user SID");
26
50
  return match[1];
51
+ }).catch((error) => {
52
+ userSidTask = void 0;
53
+ throw error;
27
54
  });
28
55
  return userSidTask;
29
56
  }
@@ -31,12 +58,11 @@ async function currentWindowsUserSid() {
31
58
  async function restrictPrivateFile(file, mode = 384) {
32
59
  await chmod(file, mode);
33
60
  if (process.platform !== "win32") return;
34
- const userSid = await currentWindowsUserSid();
35
- await execFile$3("icacls.exe", [
61
+ await execFileText("icacls.exe", [
36
62
  file,
37
63
  "/inheritance:r",
38
64
  "/grant:r",
39
- `*${userSid}:(F)`,
65
+ `*${await currentWindowsUserSid()}:(F)`,
40
66
  "*S-1-5-18:(F)",
41
67
  "*S-1-5-32-544:(F)",
42
68
  "/remove:g",
@@ -45,12 +71,12 @@ async function restrictPrivateFile(file, mode = 384) {
45
71
  "*S-1-5-32-545"
46
72
  ], {
47
73
  encoding: "utf8",
48
- windowsHide: true
74
+ windowsHide: true,
75
+ timeout: 1e4
49
76
  });
50
77
  }
51
78
  //#endregion
52
79
  //#region src/managed-setup.ts
53
- const execFile$2 = promisify(execFile);
54
80
  const VIRTUAL_INTERFACE_MARKERS = [
55
81
  "bridge",
56
82
  "docker",
@@ -98,7 +124,7 @@ function likelyVirtualInterface(name) {
98
124
  return VIRTUAL_INTERFACE_MARKERS.some((marker) => normalized.includes(marker.replaceAll("-", " "))) || /^(?:br|wg)\d*\b/u.test(normalized);
99
125
  }
100
126
  async function runRouteCommand(file, args) {
101
- return (await execFile$2(file, [...args], {
127
+ return (await execFileText(file, [...args], {
102
128
  encoding: "utf8",
103
129
  windowsHide: true
104
130
  })).stdout;
@@ -325,7 +351,6 @@ function assertExtensionId(value) {
325
351
  }
326
352
  //#endregion
327
353
  //#region src/cli.ts
328
- const execFile$1 = promisify(execFile);
329
354
  const FIREWALL_TCP_RULE = "DSH Mobile HTTPS";
330
355
  const FIREWALL_UDP_RULE = "DSH Mobile Discovery";
331
356
  function parseOptions(args) {
@@ -370,16 +395,15 @@ function dshHome() {
370
395
  return resolve(process.env.DSH_HOME ?? join(homedir(), ".dsh"));
371
396
  }
372
397
  async function runElevatedPowerShell(script) {
373
- const launch = [
374
- "$ErrorActionPreference = 'Stop'; $process = Start-Process -FilePath 'powershell.exe' -Verb RunAs -WindowStyle Hidden -Wait -PassThru",
375
- ` -ArgumentList @('-NoProfile','-NonInteractive','-EncodedCommand','${Buffer.from(script, "utf16le").toString("base64")}')`,
376
- "; exit $process.ExitCode"
377
- ].join(" ");
378
- await execFile$1("powershell.exe", [
398
+ await execFileText("powershell.exe", [
379
399
  "-NoProfile",
380
400
  "-NonInteractive",
381
401
  "-Command",
382
- launch
402
+ [
403
+ "$ErrorActionPreference = 'Stop'; $process = Start-Process -FilePath 'powershell.exe' -Verb RunAs -WindowStyle Hidden -Wait -PassThru",
404
+ ` -ArgumentList @('-NoProfile','-NonInteractive','-EncodedCommand','${Buffer.from(script, "utf16le").toString("base64")}')`,
405
+ "; exit $process.ExitCode"
406
+ ].join(" ")
383
407
  ], { windowsHide: true });
384
408
  }
385
409
  async function configureWindowsFirewall(port) {