@mrrisega/dsh-remote 0.7.1 → 0.7.2-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/clients/dsh-remote/dsh-bridge.mjs +16 -0
- package/clients/dsh-remote/mirror-diag-script.js +154 -0
- package/clients/dsh-remote/mirror-diag.mjs +106 -0
- package/clients/dsh-remote/mobile-adapter.mjs +236 -22
- package/clients/dsh-remote/test/bridge-html-inject.test.mjs +46 -10
- package/clients/dsh-remote/test/bridge-upstream-refresh.test.mjs +40 -0
- package/clients/dsh-remote/test/mirror-diag.test.mjs +82 -0
- package/clients/dsh-remote/test/mobile-adapter-guards.test.mjs +31 -11
- package/clients/dsh-remote/test/mobile-adapter-load-watch.test.mjs +408 -0
- package/package.json +1 -1
- package/packages/dsh-remote-web/lib/client.js +152 -155
- package/packages/dsh-remote-web/lib/index.js +396 -14
- package/packages/dsh-remote-web/package.json +1 -1
- package/packages/dsh-remote-web/runtime/clients/dsh-remote/dsh-bridge.mjs +16 -0
- package/packages/dsh-remote-web/runtime/clients/dsh-remote/mirror-diag-script.js +154 -0
- package/packages/dsh-remote-web/runtime/clients/dsh-remote/mirror-diag.mjs +106 -0
- package/packages/dsh-remote-web/runtime/clients/dsh-remote/mobile-adapter.mjs +236 -22
- package/packages/dsh-remote-web/test/announcements-ui.test.mjs +6 -3
- package/packages/dsh-remote-web/test/desktop-compat.test.mjs +12 -6
- package/packages/dsh-remote-web/test/remote-access-ui.test.mjs +116 -3
- package/packages/dsh-remote-web/test/repair-backup.test.mjs +599 -0
|
@@ -436,13 +436,23 @@ test("「更多」只收纳营销入口:档位规格数字(Mbps / GB / 价
|
|
|
436
436
|
assert.ok(!textHas(tree, "Mbps"), "账号卡里不得出现 Mbps");
|
|
437
437
|
assert.ok(!textHas(tree, "¥"), "账号卡里不得出现价格");
|
|
438
438
|
|
|
439
|
-
//
|
|
440
|
-
|
|
439
|
+
// 2026-10-17 版式简化(业主):正面只留「升级/续费 + 用户反馈 + 更多」;
|
|
440
|
+
// 「带新用户换会员 / 修改密码」收进「更多」。升级入口**永远在正面**(不再随收纳状态搬家)。
|
|
441
|
+
const upsell = find(tree, (n) => n.type === "button" && (n.children || []).some((c) => typeof c === "string" && c.includes("升级 PRO")));
|
|
441
442
|
const invite = find(body, (n) => n.type === "button" && (n.children || []).some((c) => typeof c === "string" && c.includes("带新用户换会员")));
|
|
442
|
-
assert.ok(upsell, "
|
|
443
|
+
assert.ok(upsell, "正面应保留「🚀 升级 PRO」入口(主行动,位置稳定)");
|
|
443
444
|
assert.ok(invite, "「更多」里应保留「🎁 带新用户换会员」入口");
|
|
444
445
|
assert.equal(typeof upsell.props.onClick, "function");
|
|
445
446
|
assert.equal(typeof invite.props.onClick, "function");
|
|
447
|
+
// 正面不应再出现「带新用户换会员」(已收进「更多」)
|
|
448
|
+
const actions = find(tree, (n) => n.props?.className === "dru-actions");
|
|
449
|
+
assert.ok(actions, "应有主按钮行");
|
|
450
|
+
assert.ok(!textHas(actions, "带新用户换会员"), "带新用户入口不再占正面按钮行");
|
|
451
|
+
// 「更多」现在与主行动同排:按钮本体带 .dru-btn(原来的整宽 .dru-disclose 披露条已去掉)
|
|
452
|
+
const moreBtn = find(tree, (n) => n.props?.id === "dru-account-more");
|
|
453
|
+
assert.ok(moreBtn, "「更多」按钮应存在");
|
|
454
|
+
assert.match(String(moreBtn.props.className || ""), /dru-btn/, "「更多」必须与主行动同排(按钮样式,不再是整宽披露条)");
|
|
455
|
+
assert.doesNotMatch(String(moreBtn.props.className || ""), /dru-disclose(?!-inline)/, "不得再继承整宽披露条样式");
|
|
446
456
|
|
|
447
457
|
// 源码级:函数与其调用都删掉了(不留死代码)。
|
|
448
458
|
// ⚠️ 断言「代码形态」而不是裸标识符 —— 注释里**故意**留着「这里原本是什么、为什么删」的说明
|
|
@@ -473,3 +483,106 @@ test("E2EE 徽标(源码级约束):client 含徽标字段/文案与 reason
|
|
|
473
483
|
assert.match(SOURCE, /describeE2ee/);
|
|
474
484
|
assert.match(SOURCE, /dru-e2ee-line/);
|
|
475
485
|
});
|
|
486
|
+
|
|
487
|
+
// ── 2026-10-17 版式与文案精简(业主 UX 反馈)──────────────────────────────────
|
|
488
|
+
// 动线:账号(我是谁 / 退出)→ 主行动(升级或续费)→ 次要(反馈)→ 更多(其它入口)。
|
|
489
|
+
|
|
490
|
+
test("★ 正面按钮收敛为三个:升级/续费 + 用户反馈 + 更多(不再一排按钮疯狂换行)", () => {
|
|
491
|
+
const plugin = loadPlugin();
|
|
492
|
+
plugin.states[0] = { config: { phone: "13800000000", deviceId: "dev-x" }, service: { running: true } };
|
|
493
|
+
const tree = plugin.render();
|
|
494
|
+
// 面板里可能有多处 .dru-actions(访问密钥卡等);账号卡那一处用「更多」按钮定位。
|
|
495
|
+
const actions = find(tree, (n) => {
|
|
496
|
+
if (n.props?.className !== "dru-actions") return false;
|
|
497
|
+
let hit = false;
|
|
498
|
+
walk(n, (x) => { if (x.props?.id === "dru-account-more") hit = true; });
|
|
499
|
+
return hit;
|
|
500
|
+
});
|
|
501
|
+
assert.ok(actions, "应有账号卡主按钮行");
|
|
502
|
+
|
|
503
|
+
const btns = [];
|
|
504
|
+
walk(actions, (n) => { if (n.type === "button") btns.push(n); });
|
|
505
|
+
// 三个按钮:主行动、用户反馈、更多
|
|
506
|
+
assert.equal(btns.length, 3, `正面按钮应为 3 个,实际 ${btns.length} 个(多了就是又回到"按钮墙")`);
|
|
507
|
+
const labels = btns.map((b) => JSON.stringify(b.children || []));
|
|
508
|
+
assert.ok(labels.some((t) => t.includes("升级 PRO") || t.includes("续费会员")), "第一个是主行动");
|
|
509
|
+
assert.ok(labels.some((t) => t.includes("用户反馈")), "用户反馈留在正面");
|
|
510
|
+
assert.ok(labels.some((t) => t.includes("更多")), "「更多」与主行动同排");
|
|
511
|
+
|
|
512
|
+
// 退出登录**不在**主按钮行里,而在账号行(.dru-user)右侧
|
|
513
|
+
const logoutInActions = btns.some((b) => (b.children || []).some((c) => c === "退出登录"));
|
|
514
|
+
assert.equal(logoutInActions, false, "退出登录不得再占主按钮行");
|
|
515
|
+
const userRow = find(tree, (n) => n.props?.className === "dru-user");
|
|
516
|
+
assert.ok(userRow, "应有账号行");
|
|
517
|
+
const logout = find(userRow, (n) => n.type === "button" && (n.children || []).includes("退出登录"));
|
|
518
|
+
assert.ok(logout, "退出登录应在账号行里(业主:放到账号那一行旁边)");
|
|
519
|
+
assert.match(String(logout.props.className || ""), /dru-user-logout/);
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
test("★ 次要入口全部在「更多」里:带新用户 / 修改密码 / 加入交流群(展开后可见)", () => {
|
|
523
|
+
const plugin = loadPlugin();
|
|
524
|
+
plugin.states[0] = { config: { phone: "13800000000", deviceId: "dev-x" }, service: { running: true } };
|
|
525
|
+
let tree = plugin.render();
|
|
526
|
+
const toggle = find(tree, (n) => n.props?.id === "dru-account-more");
|
|
527
|
+
assert.ok(toggle, "应有「更多」按钮");
|
|
528
|
+
toggle.props.onClick(); // 展开
|
|
529
|
+
tree = plugin.render();
|
|
530
|
+
const body = find(tree, (n) => n.props?.className === "dru-more-body");
|
|
531
|
+
assert.ok(body && body.props.hidden === false, "展开后「更多」内容体可见");
|
|
532
|
+
const btns = [];
|
|
533
|
+
walk(body, (n) => { if (n.type === "button") btns.push(n); });
|
|
534
|
+
const labels = btns.map((b) => JSON.stringify(b.children || []));
|
|
535
|
+
assert.ok(labels.some((t) => t.includes("带新用户换会员")), "带新用户换会员在「更多」里");
|
|
536
|
+
assert.ok(labels.some((t) => t.includes("修改密码")), "修改密码在「更多」里");
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
test("★ 删除了两段解释性文案:升级带登录态说明 / 重启 DeepSeek Harness 说明", () => {
|
|
540
|
+
assert.doesNotMatch(SOURCE, /升级\/续费以带登录态方式打开/, "升级说明必须删除(用户点一下就知道,不需要解释机制)");
|
|
541
|
+
assert.doesNotMatch(SOURCE, /桌面端由应用本身托管运行环境/, "重启说明必须删除");
|
|
542
|
+
assert.doesNotMatch(SOURCE, /请直接退出并重新打开应用/, "不得再引导退出重开应用");
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
// ── 2026-10-17 安装/配对自检(真机事故:~/.dsh-remote 被删后面板没有明确提示)────────
|
|
546
|
+
test("★ setup=配对缺失:面板顶部明确提示 + 可一键恢复历史配对", async () => {
|
|
547
|
+
const plugin = loadPlugin();
|
|
548
|
+
plugin.states[0] = {
|
|
549
|
+
config: {},
|
|
550
|
+
service: { running: false },
|
|
551
|
+
setup: {
|
|
552
|
+
kind: "pairing_missing", runtimePresent: true, configPresent: false,
|
|
553
|
+
text: "未配对:需要在面板里登录一次(账号密码),登录后会自动重建运行环境并启动 bridge",
|
|
554
|
+
detail: "本机有运行环境,但缺少账号配对信息",
|
|
555
|
+
relayDir: "/tmp/relay",
|
|
556
|
+
backup: {
|
|
557
|
+
available: true, name: "dsh-config-20261017.json", at: 1792200000000,
|
|
558
|
+
text: "检测到历史配对备份(2026-10-17 12:34),可一键恢复",
|
|
559
|
+
action: { kind: "restore_config", method: "POST", path: "/dsh-remote/config/restore", body: { backup: "dsh-config-20261017.json" } },
|
|
560
|
+
},
|
|
561
|
+
},
|
|
562
|
+
};
|
|
563
|
+
const tree = plugin.render();
|
|
564
|
+
assert.ok(textHas(tree, "未配对:需要在面板里登录一次"), "必须显示明确的配对缺失结论");
|
|
565
|
+
const restore = find(tree, (n) => n.type === "button" && (n.children || []).includes("恢复历史配对"));
|
|
566
|
+
assert.ok(restore, "有备份时必须给「恢复历史配对」按钮(不自动恢复,防误用旧账号)");
|
|
567
|
+
restore.props.onClick();
|
|
568
|
+
await flush();
|
|
569
|
+
await flush();
|
|
570
|
+
await flush();
|
|
571
|
+
const call = plugin.requests.find((r) => r.path === "/dsh-remote/config/restore");
|
|
572
|
+
assert.ok(call, "点击后必须调用恢复接口");
|
|
573
|
+
assert.equal(call.method, "POST");
|
|
574
|
+
assert.equal(call.body.backup, "dsh-config-20261017.json", "必须带上选定的备份文件名");
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
test("★ setup=ok / 缺字段:不渲染自检提示(绝不无病呻吟)", () => {
|
|
578
|
+
const plugin = loadPlugin();
|
|
579
|
+
plugin.states[0] = { config: { phone: "13800000000", deviceId: "dev-x" }, service: { running: true }, setup: { kind: "ok", runtimePresent: true, configPresent: true } };
|
|
580
|
+
const tree = plugin.render();
|
|
581
|
+
assert.equal(textHas(tree, "未配对"), false);
|
|
582
|
+
assert.equal(textHas(tree, "运行环境缺失"), false);
|
|
583
|
+
// 缺 setup 字段(旧 node 半)同样安静
|
|
584
|
+
const plugin2 = loadPlugin();
|
|
585
|
+
plugin2.states[0] = { config: { phone: "13800000000", deviceId: "dev-x" }, service: { running: true } };
|
|
586
|
+
const tree2 = plugin2.render();
|
|
587
|
+
assert.equal(textHas(tree2, "未配对"), false);
|
|
588
|
+
});
|