dsh-remote-web 0.6.10-beta.2 → 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/client.js +6 -3
- package/lib/index.js +32 -4
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -4442,15 +4442,18 @@ window.__ModuleLoader__.load({
|
|
|
4442
4442
|
|
|
4443
4443
|
// ── 首屏「这功能是干什么用的」导览(业主口径:先讲清用途,它就是绑定的理由) ──────────
|
|
4444
4444
|
// 位置:内嵌内容体的**最上面**,在「连接微信机器人」按钮之前(DOM 顺序也一样)——
|
|
4445
|
-
//
|
|
4445
|
+
// 第一次进来的人先看懂用途,再决定要不要绑。紧凑小字,
|
|
4446
4446
|
// 不会把连接按钮挤出首屏(见 .dru-wx-intro 的样式注释)。
|
|
4447
|
-
//
|
|
4447
|
+
// 只讲**产品真的会做的事**,且必须**按档位如实分层**:
|
|
4448
|
+
// 免费档只能收通知 + 回数字拍板,「在微信里交代任务」是会员能力 ——
|
|
4449
|
+
// 在面板里含糊其辞,用户绑完去微信发句话拿到付费提示,只会觉得产品骗人。
|
|
4448
4450
|
// 已绑定态同样保留:它是常驻的用途说明(不是一次性引导气泡),不占用任何按钮。
|
|
4449
4451
|
var intro = h("div", { className: "dru-wx-intro", role: "note", "aria-label": "微信机器人通道能做什么" },
|
|
4450
4452
|
h("div", { className: "dru-wx-intro-title" }, "绑定后能做什么"),
|
|
4451
4453
|
h("div", { className: "dru-wx-intro-row" }, "· 任务完成 / 出错 / 停下时**推送**到微信 —— 不用守着电脑。"),
|
|
4452
4454
|
h("div", { className: "dru-wx-intro-row" }, "· 需要你拍板时,在微信里**回一个数字**就完成决定(放行 / 拒绝 / 选哪个)。"),
|
|
4453
|
-
h("div", { className: "dru-wx-intro-row" }, "·
|
|
4455
|
+
h("div", { className: "dru-wx-intro-row" }, "· 以上两项**免费用**。"),
|
|
4456
|
+
h("div", { className: "dru-wx-intro-row" }, "· **会员**:还能直接在微信里交代任务、切换会话,并对同一个任务继续追问。")
|
|
4454
4457
|
);
|
|
4455
4458
|
|
|
4456
4459
|
if (loading && !wx && !fail) {
|
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",
|