dsh-remote-web 0.6.10-beta.4 → 0.6.10-beta.6
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/lib/index.js +32 -4
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -90,6 +90,20 @@ const DEFAULT_API = String(process.env.DSH_RELAY_DEFAULT_API || "").trim()
|
|
|
90
90
|
|| "https://n.risegao.cn:13443/relay-api";
|
|
91
91
|
const DEFAULT_APP_URL = "https://n.risegao.cn:13443/app/";
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* 自启动服务(launchd plist / systemd unit)与子进程使用的 PATH。
|
|
95
|
+
*
|
|
96
|
+
* ⚠️ **必须含 `/usr/sbin` 与 `/sbin`**:它们是系统管理命令所在目录(`ioreg`、`sysctl`…),
|
|
97
|
+
* 而 bridge 会用这些命令探测本机信息。
|
|
98
|
+
* 真机实证(2026-09-22):本文件此前**硬编码**了不含 `/usr/sbin` 的 PATH,而插件每次
|
|
99
|
+
* 自愈/启动都会重写 plist —— 于是它覆盖掉了 dsh-setup.mjs 里那份**正确**的 SERVICE_PATH,
|
|
100
|
+
* 结果 bridge 日志里刷 `/bin/sh: ioreg: command not found`,机器指纹静默退化成
|
|
101
|
+
* hostname 哈希(用户改一次主机名就被当成新设备)。
|
|
102
|
+
* ⚠️ 与 `dsh-setup.mjs` 的 `SERVICE_PATH` **必须一致** —— 两处都会写同一个 plist,
|
|
103
|
+
* 谁写谁说了算;有测试锁死这条一致性(跨文件不变量)。
|
|
104
|
+
*/
|
|
105
|
+
const SERVICE_PATH = "/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin";
|
|
106
|
+
|
|
93
107
|
/**
|
|
94
108
|
* 把文件权限收紧到「只有本人可读写」。
|
|
95
109
|
*
|
|
@@ -226,7 +240,9 @@ function spawnEnv(extra) {
|
|
|
226
240
|
// PATH 分隔符必须按平台取(Windows 是 ";",POSIX 是 ":"):写死 ":" 会把整条 PATH
|
|
227
241
|
// 在 Windows 上拼成一个不存在的路径,node/npx 全部找不到。
|
|
228
242
|
// 追加的 POSIX 目录只在类 Unix 上有意义,Windows 上不追加。
|
|
229
|
-
|
|
243
|
+
// 含 /usr/sbin 与 /sbin:插件用 spawnEnv 拉起的是 watcher,它会再拉起 bridge,
|
|
244
|
+
// 而 bridge 要用 ioreg 之类系统命令(缺了它 → 机器指纹静默退化,见 SERVICE_PATH 注释)。
|
|
245
|
+
const posixDirs = isWindows() ? [] : ["/usr/local/bin", "/opt/homebrew/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"];
|
|
230
246
|
const PATH = [nodeDir, base, ...posixDirs].filter(Boolean).join(delimiter);
|
|
231
247
|
return { ...process.env, PATH, ...(extra || {}) };
|
|
232
248
|
}
|
|
@@ -1007,7 +1023,18 @@ function ensureRuntime(relayDir) {
|
|
|
1007
1023
|
}
|
|
1008
1024
|
}
|
|
1009
1025
|
|
|
1010
|
-
/**
|
|
1026
|
+
/**
|
|
1027
|
+
* 生成 plist(与 dsh-setup.mjs 的 writeAutostartFile **必须同构**),返回路径。
|
|
1028
|
+
*
|
|
1029
|
+
* ⚠️ 两份模板历史上漂移过、并因此各造成一个真机事故(插件每次自愈/启动都会重写 plist,
|
|
1030
|
+
* 所以**插件这份谁写谁说了算**,漂移等于把安装器那份正确的覆盖掉):
|
|
1031
|
+
* · 漏 `/usr/sbin`、`/sbin`(SERVICE_PATH)→ bridge 找不到 `ioreg` → 机器指纹静默退化成
|
|
1032
|
+
* hostname 哈希(改一次主机名就被当成新设备);
|
|
1033
|
+
* · 漏 `LimitLoadToSessionType` → `bootstrap user/<uid>` 失败(rc=5)→ 域阶梯回退到
|
|
1034
|
+
* gui/<uid>,而 macOS 26 上 gui 域是 on-demand-only、`RunAtLoad`/`KeepAlive` 失效 →
|
|
1035
|
+
* **服务被系统(BTM)回收后再也回不来**,只能手动点面板「启动」。
|
|
1036
|
+
* 两者都由 launchd-domain.test.mjs 的跨文件不变量锁死。
|
|
1037
|
+
*/
|
|
1011
1038
|
function writeAutostartFile(relayDir) {
|
|
1012
1039
|
const plistPath = launchAgentPath();
|
|
1013
1040
|
if (!plistPath) return null;
|
|
@@ -1021,9 +1048,10 @@ function writeAutostartFile(relayDir) {
|
|
|
1021
1048
|
<key>RunAtLoad</key><true/>
|
|
1022
1049
|
<key>KeepAlive</key><true/>
|
|
1023
1050
|
<key>ThrottleInterval</key><integer>10</integer>
|
|
1051
|
+
<key>LimitLoadToSessionType</key><array><string>Aqua</string><string>Background</string></array>
|
|
1024
1052
|
<key>StandardOutPath</key><string>${join(relayDir, ".dsh-bridge.log")}</string>
|
|
1025
1053
|
<key>StandardErrorPath</key><string>${join(relayDir, ".dsh-bridge.log")}</string>
|
|
1026
|
-
<key>EnvironmentVariables</key><dict><key>PATH</key><string
|
|
1054
|
+
<key>EnvironmentVariables</key><dict><key>PATH</key><string>${SERVICE_PATH}</string><key>DSH_BRIDGE_INSTALL_SOURCE</key><string>${installSourceOf(relayDir)}</string><key>DSH_BRIDGE_INSTALL_VERSION</key><string>${PLUGIN_VERSION}</string></dict>
|
|
1027
1055
|
</dict></plist>`;
|
|
1028
1056
|
mkdirSync(dirname(plistPath), { recursive: true });
|
|
1029
1057
|
writeFileSync(plistPath, plist, { mode: 0o644 });
|
|
@@ -2453,7 +2481,7 @@ const PLUGIN_ID = "dsh-remote-web";
|
|
|
2453
2481
|
const PLUGIN_LEGACY_IDS = ["dsh-remote-ui"];
|
|
2454
2482
|
const PLUGIN_ALL_IDS = [PLUGIN_ID, ...PLUGIN_LEGACY_IDS];
|
|
2455
2483
|
/** 插件自身发布版本(与 dsh-remote 根包同步递增)。 */
|
|
2456
|
-
const PLUGIN_VERSION = "0.6.10-beta.
|
|
2484
|
+
const PLUGIN_VERSION = "0.6.10-beta.6";
|
|
2457
2485
|
const UPDATE_LOG = ".dsh-update.log";
|
|
2458
2486
|
const UPDATE_MARKER = ".dsh-update-running";
|
|
2459
2487
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-remote-web",
|
|
3
|
-
"version": "0.6.10-beta.
|
|
3
|
+
"version": "0.6.10-beta.6",
|
|
4
4
|
"description": "公网远程控制 DeepSeek Harness(dsh web):安装即得专属加密地址,人在外面也能用手机访问电脑上的 dsh——无需同一局域网/WiFi、无需公网 IP 与内网穿透,全程加密;手机端 100% 还原电脑体验(对话/工具/审批/设置)。技术用户可选自建服务,流量走自己的服务器。Remote control DeepSeek Harness (dsh web) from anywhere over the public internet — install, get an encrypted URL, use it from your phone on any network (dual-half cordis plugin: Settings panel + same-origin /dsh-remote routes). (2026-09 由 dsh-remote-ui 更名 / renamed from dsh-remote-ui; dsh-remote 的 dsh web 插件半,不是纯 UI/皮肤插件)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|