@mrrisega/dsh-remote 0.6.6 → 0.6.7-beta.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrrisega/dsh-remote",
3
- "version": "0.6.6",
3
+ "version": "0.6.7-beta.2",
4
4
  "description": "手机远程控制 DeepSeek Harness · Remote control DeepSeek Harness (dsh web) from any phone browser — 100% 全功能 App 级体验:发消息、看工具执行、审批权限、改设置、管凭据,含特权操作,免内网穿透。一条命令安装 npx @mrrisega/dsh-remote。Mobile remote control for DSH, self-host or SaaS, no server needed on LAN.",
5
5
  "keywords": [
6
6
  "deepseek-harness",
@@ -50,11 +50,11 @@
50
50
  },
51
51
  "scripts": {
52
52
  "test": "npm run test:router && npm run test:plugin && npm run test:bridge",
53
- "test:router": "node --test packages/relay-router/test/native-device-selection.test.mjs packages/relay-router/test/quotas.test.mjs packages/relay-router/test/presence-report.test.mjs",
53
+ "test:router": "node --test packages/relay-router/test/native-device-selection.test.mjs packages/relay-router/test/presence-report.test.mjs packages/relay-router/test/logger.test.mjs",
54
54
  "_comment:test:plugin": "DSH_RELAY_SKIP_SERVICE=1 = 测试隔离:插件加载时不做真实系统操作(npx 补装 / launchctl / 重启 harness);需要真实分支的用例自行 unset(见 account-switch / runtime-provision / harness-restart 用例注释)",
55
55
  "test:plugin": "DSH_REMOTE_TELEMETRY=0 DSH_RELAY_SKIP_SERVICE=1 node --test --test-concurrency=1 packages/dsh-remote-web/test/*.test.mjs",
56
56
  "test:bridge": "node --test clients/dsh-remote/test/*.test.mjs",
57
- "check": "node --check clients/dsh-remote/dsh-bridge.mjs && node --check clients/dsh-remote/e2ee-shim.mjs && node --check dsh-setup.mjs && node --check packages/dsh-remote-web/lib/index.js && node --check packages/dsh-remote-web/lib/client.js && bash -n deploy/install-open.sh",
57
+ "check": "node --check clients/dsh-remote/dsh-bridge.mjs && node --check clients/dsh-remote/e2ee-shim.mjs && node --check dsh-setup.mjs && node --check packages/dsh-remote-web/lib/index.js && node --check packages/dsh-remote-web/lib/client.js && node --check packages/relay-router/src/index.mjs && node --check packages/relay-router/src/logger.mjs && bash -n deploy/install-open.sh && grep -q 'command -v setsid' deploy/install-open.sh && grep -q 'command -v ss' deploy/install-open.sh",
58
58
  "release:tarballs": "bash scripts/release-tarballs.sh"
59
59
  },
60
60
  "dependencies": {
@@ -359,7 +359,7 @@ window.__ModuleLoader__.load({
359
359
  return api(path, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(data || {}) });
360
360
  };
361
361
 
362
- // ── 交流群(运营二维码;管理后台统一上传,node 半经公开配置下发) ─────────
362
+ // ── 交流群(二维码由图层面板上传统一配置,node 半经公开配置下发) ─────────
363
363
  // 设置面板「加入交流群」按钮与用户反馈页都展示同一张码;未配置(qrcode 为空)→ 不展示任何入口。
364
364
  var COMMUNITY_TTL_MS = 5 * 60 * 1000; // 面板/反馈卡共用缓存:5 分钟内不重复请求
365
365
  var communityCache = { at: 0, data: null };
@@ -414,6 +414,14 @@ window.__ModuleLoader__.load({
414
414
  var connInFlight = { v: false };
415
415
  /** 最近一次连接阶段(供自调度定时器决定快/慢轮询节奏,避免依赖渲染闭包)。 */
416
416
  var connPhaseRef = { v: "" };
417
+ /**
418
+ * 连接阶段轮询的**连续失败**计数(0.6.7 新增)。
419
+ * 背景(用户实测):轮询失败原来被 `.catch` 静默吞掉,而 node 半一旦 500
420
+ * (Windows 上 `process.getuid is not a function`),面板就永久停在「查询中…」转圈,
421
+ * 用户完全看不出发生了什么。现在连续失败到阈值就把失败原因摆到连接卡上。
422
+ */
423
+ var connFailRef = { v: 0 };
424
+ var CONN_FAIL_VISIBLE = 3; // ≈ 2.5s × 3:既要够快让用户看见,又要避免一次抖动就报红
417
425
  /** 连接阶段轮询节奏:未连通时 2.5s(自动推进),已连接后退避到 15s;页面隐藏时完全停下。 */
418
426
  var CONN_POLL_FAST_MS = 2500;
419
427
  var CONN_POLL_SLOW_MS = 15000;
@@ -1113,7 +1121,7 @@ window.__ModuleLoader__.load({
1113
1121
  log ? h("div", { className: "dru-up-log", title: "更新日志(尾部)" }, log) : null,
1114
1122
  selfMsg ? h("div", { className: "dru-msg dru-msg-" + selfMsg.kind }, selfMsg.text) : null,
1115
1123
  h("div", { className: "dru-hint", style: { marginTop: 8 } },
1116
- armed ? "⚠ 再次点击后即开始彻底卸载:① 移除 dsh web 配置中的插件引用与本地文件;② 停止并移除 bridge 自启动服务(macOS com.dshremote.bridge / Linux dsh-bridge)并结束残留进程;③ 清空本地配置目录(~/.dsh-remote:账号、设备密钥、固化运行时等)。此操作不可撤销,如需再次使用请在插件市场重新安装。" :
1124
+ armed ? "⚠ 再次点击后即开始彻底卸载:① 移除 dsh web 配置中的插件引用与本地文件;② 停止并移除 bridge 自启动服务(macOS com.dshremote.bridge / Linux dsh-bridge / Windows 任务计划程序 dsh-remote-bridge)并结束残留进程;③ 清空本地配置目录(~/.dsh-remote:账号、设备密钥、固化运行时等)。此操作不可撤销,如需再次使用请在插件市场重新安装。" :
1117
1125
  "检测新版、一键在线更新、彻底卸载都在本卡片完成。")
1118
1126
  );
1119
1127
  }
@@ -1621,6 +1629,7 @@ window.__ModuleLoader__.load({
1621
1629
  connInFlight.v = true;
1622
1630
  api("/dsh-remote/bridge-status").then(function (b) {
1623
1631
  if (!b || !b.ok || !b.connect) return;
1632
+ connFailRef.v = 0; // 成功即清零:一次抖动不该把面板染红
1624
1633
  var prev = connPhaseRef.v;
1625
1634
  connPhaseRef.v = b.connect.phase || "";
1626
1635
  setConn(b.connect);
@@ -1634,7 +1643,26 @@ window.__ModuleLoader__.load({
1634
1643
  refreshDeviceList(); // 手机扫码后设备列表自动出现,无需刷新页面
1635
1644
  }
1636
1645
  }
1637
- }).catch(function () { /* 轮询失败静默:下一轮自动重试 */ })
1646
+ }).catch(function (e) {
1647
+ // 【0.6.7】原来这里是空 catch("轮询失败静默:下一轮自动重试")。在 Windows 上
1648
+ // node 半因 process.getuid 崩溃返回 500 时,这段静默让面板**永久**停在
1649
+ // 「查询中…」,用户完全无从判断(正是收到的那份诊断报告里的现象)。
1650
+ // 现在:连续失败到阈值就把原因摆到连接卡上,并提示可以直接重试。
1651
+ connFailRef.v += 1;
1652
+ if (connFailRef.v >= CONN_FAIL_VISIBLE) {
1653
+ setConn({
1654
+ phase: "error",
1655
+ online: false,
1656
+ text: "状态读取失败",
1657
+ detail: "本机状态接口连续 " + connFailRef.v + " 次请求失败:"
1658
+ + ((e && e.message) ? e.message : String(e))
1659
+ + "(面板读不到 bridge 状态,扫码/远程访问都不会推进)。可点「重试」,或刷新页面;若持续失败请把诊断信息发给客服。",
1660
+ error: { code: "status_unreachable", message: "无法读取本机 bridge 状态(/dsh-remote/bridge-status 请求失败)" },
1661
+ retryable: true,
1662
+ attempts: connFailRef.v,
1663
+ });
1664
+ }
1665
+ })
1638
1666
  .finally(function () { connInFlight.v = false; });
1639
1667
  }
1640
1668
 
@@ -1970,7 +1998,20 @@ window.__ModuleLoader__.load({
1970
1998
  var endsAt = a && (a.plan_ends_at || a.trial_expires_at) ? Number(a.plan_ends_at || a.trial_expires_at) : 0;
1971
1999
  var quotaPct = quota && quota.limit_enabled ? quota.percent : null;
1972
2000
  var planText;
1973
- if (!isMember) planText = "免费额度: 带宽 ≈1Mbps" + (quotaPct !== null ? " · 本月流量已用 " + quotaPct + "%" : " · 本月流量限额 1GB");
2001
+ // 免费档文案只依据**服务端实际下发的额度数据**,不猜具体数值:
2002
+ // · 中继压根不限制(自建)→ 只说“免费用户”,不显示任何限制
2003
+ // · 中继报告不限量 → 如实说明
2004
+ // · 中继报告限量 → 显示用量;带宽值服务端有下发才写
2005
+ if (!isMember) {
2006
+ if (quota && quota.limit_enabled) {
2007
+ var speedText = quota.max_mbps ? "带宽 ≈" + quota.max_mbps + "Mbps" : "已限速";
2008
+ planText = "免费额度: " + speedText + (quotaPct !== null ? " · 本月流量已用 " + quotaPct + "%" : "");
2009
+ } else if (quota) {
2010
+ planText = "免费用户 · 当前不限速、不限流量";
2011
+ } else {
2012
+ planText = "免费用户";
2013
+ }
2014
+ }
1974
2015
  else if (source === "trial") planText = "试用 PRO 会员 · 到期 " + fmtDate(a.trial_expires_at);
1975
2016
  else if (endsAt) planText = plan === "pro_max" ? "Pro Max 会员 · 到期 " + fmtDate(endsAt) : "PRO 会员 · 到期 " + fmtDate(endsAt);
1976
2017
  else planText = plan === "pro_max" ? "Pro Max 长期会员" : "PRO 长期会员";
@@ -2408,7 +2449,13 @@ window.__ModuleLoader__.load({
2408
2449
  : h("button", { type: "button", className: "dru-btn dru-btn-danger", disabled: busy !== "", onClick: function () { toggleBridge(false); } }, busy === "stop" ? "停止中…" : "停止 bridge")
2409
2450
  ),
2410
2451
  h("div", { className: "dru-meta" }, st && st.config && st.config.deviceId ? "设备 ID:" + st.config.deviceId : "设备 ID:生成中"),
2411
- h("div", { className: "dru-meta" }, st ? (st.service && st.service.plistExists ? "自启动服务已安装" : "自启动服务未安装(启动时自动创建)") : ""),
2452
+ h("div", { className: "dru-meta" }, st ? (st.service && (st.service.plistExists || st.service.serviceManager === "detached")
2453
+ ? (st.service.serviceManager === "detached"
2454
+ ? (st.service.autostartTask
2455
+ ? "自启动:已注册登录任务(任务计划程序 dsh-remote-bridge)"
2456
+ : "自启动:未注册登录任务(由面板在 dsh web 启动时自动拉起 bridge)")
2457
+ : "自启动服务已安装")
2458
+ : "自启动服务未安装(启动时自动创建)") : ""),
2412
2459
  // 0.6.2:把「运行环境缺失 / launchd 崩溃循环」如实告诉用户,而不是显示「运行中」
2413
2460
  st && !serviceRuntimeReady
2414
2461
  ? h("div", { className: "dru-hint", style: { marginTop: 8 } },
@@ -2431,7 +2478,7 @@ window.__ModuleLoader__.load({
2431
2478
  card("📖 关于 dsh-remote", [
2432
2479
  h("div", { className: "dru-hint", style: { marginBottom: 6 } }, "📱 远程访问:用手机或另一台电脑的浏览器,随时随地使用同一份 dsh web——人在哪都能用(免公网 IP、免内网穿透);官方托管中继,4G/5G 即用,也可自建服务。"),
2433
2480
  h("div", { className: "dru-hint", style: { marginBottom: 6 } }, "🛠 电脑端一键安装:bridge 与「远程访问」面板一次到位——云端/自建切换、账号登录、bridge 启停、一次性扫码访问、已授权设备管理、意见反馈都在这里。"),
2434
- h("div", { className: "dru-hint", style: { marginBottom: 6 } }, "🔒 安全与通道:HTTP / WebSocket 全量透传,一次性访问密钥认证,面板实时显示设备与已授权设备列表;服务端可配置流量配额。"),
2481
+ h("div", { className: "dru-hint", style: { marginBottom: 6 } }, "🔒 安全与通道:HTTP / WebSocket 全量透传,一次性访问密钥认证,面板实时显示设备与已授权设备列表。"),
2435
2482
  h("div", { className: "dru-hint" }, "🛡 端到端加密:手机↔电脑之间的消息内容用「你的账号密码派生密钥」端到端加密——密钥与密码不落服务端(仅存校验值),中继只可见路径/大小/时间(详见 README「安全与隐私」)。"),
2436
2483
  // 匿名装机统计(隐私披露):开源项目必须把「采什么 / 不采什么 / 怎么关」写在用户看得到的地方。
2437
2484
  // 只保留结论式的说明句:不再单列「隐私说明: README… · docs/telemetry.md」那一行文档链接
@@ -2604,6 +2651,10 @@ window.__ModuleLoader__.load({
2604
2651
  // 侧栏「远程访问」快捷入口(2026-09 恢复注入:与官方「设置」按钮共存不遮挡)
2605
2652
  navEnsureStart();
2606
2653
 
2654
+ // 满意度弹窗已停用(不再调度);组件与调度代码保留,便于日后恢复。
2655
+ var FB_POPUP_RETIRED = true;
2656
+ if (FB_POPUP_RETIRED) return; // 改回 false 即恢复原行为
2657
+
2607
2658
  // 满意度弹窗调度:首次观察到 bridge 运行(即“安装完成并体验”)后约 10 分钟弹出;
2608
2659
  // 每 60 秒复查一次,避免 dsh web 启动晚于到点时间。
2609
2660
  // 弹窗状态按「账号/设备」分作用域(见 fbPopScope);旧版无后缀键视为已完成并迁移,不再打扰老用户。