dsh-mobile 0.3.6 → 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 +6 -0
- package/README.en.md +5 -5
- package/README.md +5 -5
- package/lib/cli.js +42 -18
- package/lib/cli.js.map +1 -1
- package/lib/index.mjs +39 -11
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
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
|
+
|
|
5
11
|
## 0.3.6 - 2026-09-02
|
|
6
12
|
|
|
7
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.
|
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.
|
|
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**:
|
|
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.
|
|
28
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.
|
|
29
|
-
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.
|
|
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.
|
package/README.md
CHANGED
|
@@ -26,14 +26,14 @@
|
|
|
26
26
|
|
|
27
27
|
> DSH Mobile 是 DeepSeek Harness 社区插件,原生 App 仅支持 Android。
|
|
28
28
|
>
|
|
29
|
-
> **0.3.
|
|
29
|
+
> **0.3.7 更新**:修复 Windows DSH Desktop 获取系统命令输出时的启动崩溃,同步完善网卡选择与防火墙诊断;保留 0.3.6 的 DSH 版本开放策略和私有文件权限保护。[详细记录](CHANGELOG.md)。
|
|
30
30
|
>
|
|
31
|
-
> **升级提醒**:DSH
|
|
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.
|
|
35
|
-
<a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.
|
|
36
|
-
<sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.
|
|
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 源码。
|
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 ??=
|
|
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
|
-
|
|
35
|
-
await execFile$3("icacls.exe", [
|
|
61
|
+
await execFileText("icacls.exe", [
|
|
36
62
|
file,
|
|
37
63
|
"/inheritance:r",
|
|
38
64
|
"/grant:r",
|
|
39
|
-
`*${
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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) {
|