🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

手机遥控台 MoonlitDropOfBlood/dsh-remote-control

DeepSeek Harness
MoonlitDropOfBlood5 天前有提交已提供中文文档扫描:高危

远程控制dsh

31.1/100
综合分
2
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/11/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add MoonlitDropOfBlood/dsh-remote-control
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · other
装得上吗
实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 5 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
⚠︎ 实装验证未通过(unknown · 2026/10/27) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
🔴 安全扫描发现高危能力自动 · 静态分析源码
v2.7.0
🔴 扫描:高危尚无人工评估

静态扫描发现安装期即执行代码,或命令参数由运行时变量拼接(参数来源无法静态判定,从严处理)。

命令参数由运行时变量拼接读写/删除本地文件发起外部网络请求
查看扫描证据(共 96 处,展示前 77 条)
  • 读取本地文件
    app/live-order-node-test.mjs:93
    const linkSource = readFileSync(new URL('./entry/src/main/ets/model/link.ets', import.meta.url), 'utf8');
  • 读取本地文件
    app/live-order-node-test.mjs:97
    const storeSource = readFileSync(new URL('./entry/src/main/ets/model/sessionstore.ets', import.meta.url), 'utf8');
  • 读取本地文件
    app/session-detail-contract-test.mjs:5
    const page = readFileSync(new URL('./entry/src/main/ets/pages/SessionDetailPage.ets', import.meta.url), 'utf8');
  • 读取本地文件
    app/session-detail-contract-test.mjs:6
    const store = readFileSync(new URL('./entry/src/main/ets/model/sessionstore.ets', import.meta.url), 'utf8');
  • 读取本地文件
    app/session-detail-contract-test.mjs:7
    const link = readFileSync(new URL('./entry/src/main/ets/model/link.ets', import.meta.url), 'utf8');
  • 读取本地文件
    app/session-detail-contract-test.mjs:8
    const protocol = readFileSync(new URL('./entry/src/main/ets/model/protocol.ets', import.meta.url), 'utf8');
  • 读取本地文件
    e2e/auto-test.mjs:43
    readFileSync(join(process.env.DSH_HOME ?? join(homedir(), ".dsh"), "remote-control", "config.json"), "utf8"),
  • 发起网络请求
    e2e/auto-test.mjs:138
    const caps = await client.request("session.capabilities", {}, 5000);
  • 发起网络请求
    e2e/auto-test.mjs:145
    const created = await client.request(
  • 发起网络请求
    e2e/auto-test.mjs:155
    await client.request("session.prompt", { sessionId: sid, text: "hello" }, 5000);
  • 发起网络请求
    e2e/auto-test.mjs:174
    const hist = await client.request("session.history", { sessionId: sid }, 5000);
  • 发起网络请求
    e2e/auto-test.mjs:192
    await client.request("session.create", { agentPreset: "no-such-preset" }, 5000);
  • 发起网络请求
    e2e/auto-test.mjs:211
    const withModel = await client.request(
  • 删除本地文件
    e2e/auto-test.mjs:438
    unlinkSync(epochFile);
  • 执行外部命令来自配置/变量
    e2e/auto-test.mjs:462
    const child = spawn(process.execPath, [RELAY_SERVER], {
  • 读取本地文件
    e2e/deliver-queue-probe.mjs:11
    readFileSync(join(process.env.DSH_HOME ?? join(homedir(), ".dsh"), "remote-control", "config.json"), "utf8"),
  • 发起网络请求
    e2e/deliver-queue-probe.mjs:35
    const hello = await link.request("hello", { proto: 1, clientName: "deliver-probe", appVersion: "1.0.0" }, 15000);
  • 发起网络请求
    e2e/deliver-queue-probe.mjs:38
    const list = await link.request("session.list", {}, 15000);
  • 发起网络请求
    e2e/deliver-queue-probe.mjs:49
    const page = await link.request("session.history", { sessionId: target.sessionId, maxMessages: 40 }, 30000);
  • 发起网络请求
    e2e/deliver-queue-probe.mjs:69
    await link.request("session.prompt", {
  • 读取本地文件
    e2e/history-test.mjs:13
    readFileSync(join(process.env.DSH_HOME ?? join(homedir(), ".dsh"), "remote-control", "config.json"), "utf8"),
  • 发起网络请求
    e2e/history-test.mjs:55
    const hello = await link.request("hello", { proto: 1, clientName: "history-test", appVersion: "1.0.0" }, 15000);
  • 发起网络请求
    e2e/history-test.mjs:60
    const list = await link.request("session.list", {}, 15000);
  • 发起网络请求
    e2e/history-test.mjs:84
    const v = await link.request("session.history", { sessionId: s.sessionId, maxMessages: 10 }, 30000);
  • 发起网络请求
    e2e/history-test.mjs:113
    const v2 = await link.request("session.history",
  • 发起网络请求
    e2e/link.mjs:456
    return this.corr.request((m) => this.send(m), type, payload, timeoutMs);
  • 发起网络请求
    e2e/link.mjs:596
    return this.corr.request((m) => this.send(m), type, payload, timeoutMs);
  • 发起网络请求
    e2e/mock-phone.mjs:36
    .request("hello", { proto: 1, clientName: "mock-phone", appVersion: "1.0.0" })
  • 发起网络请求
    e2e/mock-phone.mjs:48
    console.log(JSON.stringify(await link.request("session.list", {}), null, 2));
  • 发起网络请求
    e2e/mock-phone.mjs:51
    console.log(JSON.stringify(await link.request("session.create", { title: rest.join(" ") || undefined })));
  • 发起网络请求
    e2e/mock-phone.mjs:55
    console.log(JSON.stringify(await link.request("session.prompt", { sessionId, text: rest.join(" ") })));
  • 发起网络请求
    e2e/mock-phone.mjs:59
    console.log(JSON.stringify(await link.request("session.cancel", { sessionId: rest[0] })));
  • 发起网络请求
    e2e/mock-phone.mjs:63
    console.log(JSON.stringify(await link.request("approval.answer", { askId, decision }, 5000)));
  • 读取本地文件
    e2e/protocol.mjs:164
    const raw = readFileSync(this.#file, "utf8");
  • 写入本地文件
    e2e/protocol.mjs:178
    writeFileSync(this.#file, JSON.stringify(this.#data), "utf8");
  • 读取本地文件
    e2e/subagents-test.mjs:20
    const cfg = JSON.parse(readFileSync(configPath, "utf8"));
  • 发起网络请求
    e2e/subagents-test.mjs:40
    const list = await link.request("session.list", {}, 15000);
  • 发起网络请求
    e2e/subagents-test.mjs:52
    const cat = await link.request("session.subagents", { sessionId: parent }, 20000);
  • 发起网络请求
    e2e/subagents-test.mjs:70
    .request("session.subagentPrompt", {
  • 发起网络请求
    e2e/subagents-test.mjs:86
    .request("session.subagentCancel", {
  • 读取本地文件
    market/generate-index.mjs:25
    const pluginPkg = JSON.parse(readFileSync(join(here, "..", "plugin", "package.json"), "utf8"));
  • 请求外部主机registry.npmjs.org
    market/generate-index.mjs:31
    const res = await fetch(`https://registry.npmjs.org/${encodeURIComponent(name).replace("%40", "@")}`, {
  • 发起网络请求
    market/generate-index.mjs:31
    const res = await fetch(`https://registry.npmjs.org/${encodeURIComponent(name).replace("%40", "@")}`, {
  • 执行外部命令运行时拼接
    market/generate-index.mjs:46
    const out = execSync(`git log -1 --format=%ct "v${version}" 2>/dev/null || git log -1 --format=%ct`, { encoding: "utf8" });
  • 读取本地文件
    market/generate-index.mjs:148
    const disk = readFileSync(outPath, "utf8");
  • 写入本地文件
    market/generate-index.mjs:155
    writeFileSync(outPath, json);
  • 读取本地文件
    market/sync-into-plugin.mjs:24
    const src = readFileSync(SRC, "utf8");
  • 读取本地文件
    market/sync-into-plugin.mjs:29
    disk = readFileSync(DST, "utf8");
  • 写入本地文件
    market/sync-into-plugin.mjs:40
    mkdirSync(DST_DIR, { recursive: true });
  • 写入本地文件
    market/sync-into-plugin.mjs:41
    writeFileSync(DST, src);
  • 读取本地文件
    plugin/lib/config.mjs:155
    raw = JSON.parse(readFileSync(path, "utf8"));
  • 写入本地文件
    plugin/lib/config.mjs:161
    renameSync(path, path + ".corrupt-" + Date.now());
  • 写入本地文件
    plugin/lib/config.mjs:197
    mkdirSync(dirname(path), { recursive: true });
  • 写入本地文件
    plugin/lib/config.mjs:201
    writeFileSync(tmp, JSON.stringify(out, null, 2), "utf8");
  • 写入本地文件
    plugin/lib/config.mjs:202
    renameSync(tmp, path);
  • 读取本地文件
    plugin/lib/config.mjs:212
    const raw = JSON.parse(readFileSync(configFile(), "utf8"));
  • 读取本地文件
    plugin/lib/config.mjs:225
    const raw = JSON.parse(readFileSync(configFile(), "utf8"));
  • 读取本地文件
    plugin/lib/config.mjs:237
    const raw = JSON.parse(readFileSync(path, "utf8"));
  • 写入本地文件
    plugin/lib/config.mjs:240
    mkdirSync(dirname(path), { recursive: true });
  • 写入本地文件
    plugin/lib/config.mjs:242
    writeFileSync(tmp, JSON.stringify(raw, null, 2), "utf8");
  • 读取本地文件
    plugin/lib/host-bridge.mjs:372
    const bytes = readFileSync(path);
  • 写入本地文件
    plugin/lib/host-bridge.mjs:909
    : (p) => mkdir(p, { recursive: true });
  • 读取本地文件
    plugin/lib/host-bridge.mjs:1525
    const bytes = await readFile(path);
  • 写入本地文件
    plugin/lib/host-bridge.mjs:2249
    await this.#mkdir(cwd);
  • 写入本地文件
    plugin/lib/pairing.mjs:128
    mkdirSync(dataDir(), { recursive: true });
  • 写入本地文件
    plugin/lib/pairing.mjs:130
    writeFileSync(tmp, svg, "utf8");
  • 删除本地文件
    plugin/lib/pairing.mjs:134
    unlinkSync(path);
  • 写入本地文件
    plugin/lib/pairing.mjs:138
    renameSync(tmp, path);
  • 删除本地文件
    plugin/lib/pairing.mjs:146
    unlinkSync(path);
  • 执行外部命令固定命令
    plugin/lib/pairing.mjs:166
    child = spawn("cmd /c start \"\" " + quoted, { shell: true, detached: true, stdio: "ignore", windowsHide: true });
  • 执行外部命令固定命令
    plugin/lib/pairing.mjs:168
    child = spawn("open " + quoted, { shell: true, detached: true, stdio: "ignore" });
  • 执行外部命令固定命令
    plugin/lib/pairing.mjs:170
    child = spawn("xdg-open " + quoted, { shell: true, detached: true, stdio: "ignore" });
  • 发起网络请求
    plugin/lib/push.mjs:55
    return await fetch(url, { ...init, signal: ac.signal });
  • 读取本地文件
    plugin/lib/relay-supervisor.mjs:60
    if (existsSync(c)) return c;
  • 读取本地文件
    plugin/lib/relay-supervisor.mjs:336
    if (this.entry === "" || !existsSync(this.entry)) {
  • 读取本地文件
    relay/server.js:125
    cert = readFileSync(rawCert);
  • 读取本地文件
    relay/server.js:130
    key = readFileSync(rawKey);
扫描于 2026/11/4(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库
涉及外部主机:registry.npmjs.org

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

README

由 DeepSeek 最新模型翻译生成
dsh-remote-control 用 HarmonyOS 手机远程控制 DeepSeek Harness (DSH):会话遥控、审批/提问应答、任务通知。 ┌─ DSH 插件 (PC) ──────┐ WSS ┌─ 中继 (自选部署) ──┐ WSS ┌─ HarmonyOS App ─┐ │ 会话 / 审批桥接 │────────▶│ 只转发密文 │◀────────│ 遥控器 UI │ │ 端到端加密 │ 出站 └──────────────────┘ 出站 └─────────────────┘ └──────┬───────────────┘ └── (可选) Push Kit 通知 ──────────────────────────────▶ 📱 - 两端都以 WebSocket 客户端出站连接中继:中继放局域网 PC 或任一 VPS,手机在局域网或公网都能连;中继只转发 AES-256-GCM 密文,被攻破也读不到内容(协议见 docs/PROTOCOL.md)。 - 零公网部署模式:中继直接跑在 PC 上,手机连 ws://<PC-IP>:<端口> 即可(同一 Wi-Fi)。 - fail-open 安全设计:手机永远不是任务的单点阻塞——超时/断线一律放行给桌面答案器。
展开完整文档(README 剩余 1 节)
dsh-remote-control

用 HarmonyOS 手机远程控制 DeepSeek Harness (DSH):会话遥控、审批/提问应答、任务通知。

┌─ DSH 插件 (PC) ──────┐ WSS ┌─ 中继 (自选部署) ──┐ WSS ┌─ HarmonyOS App ─┐ │ 会话 / 审批桥接 │────────▶│ 只转发密文 │◀────────│ 遥控器 UI │ │ 端到端加密 │ 出站 └──────────────────┘ 出站 └─────────────────┘ └──────┬───────────────┘
└── (可选) Push Kit 通知 ──────────────────────────────▶ 📱

- 两端都以 WebSocket 客户端出站连接中继:中继放局域网 PC 或任一 VPS,手机在局域网或公网都能连;中继只转发 AES-256-GCM 密文,被攻破也读不到内容(协议见 docs/PROTOCOL.md)。
- 零公网部署模式:中继直接跑在 PC 上,手机连 ws://<PC-IP>:<端口> 即可(同一 Wi-Fi)。
- fail-open 安全设计:手机永远不是任务的单点阻塞——超时/断线一律放行给桌面答案器。

功能

| 能力 | 说明 |
| 会话遥控 | 会话列表(实时状态)/ 新建 / 发送提示词 / 流式查看回复 / 取消任务 |
| 审批 · 提问应答 | 智能体请求审批或用户提问时手机上直接允许 / 拒绝 / 回答(带倒计时) |
| 任务通知 | 华为 Push Kit 推送(可选;未配置时优雅降级) |

仓库结构

| 目录 | 内容 | 技术栈 |
| plugin/ | DSH 插件(Host 侧半边),安装进 DSH 配置档 | Node.js / Cordis |
| relay/ | 中继服务器(哑管道,只转发密文帧) | Node.js + ws |
| app/ | HarmonyOS 手机 App(DevEco 工程) | ArkTS / ArkUI |
| e2e/ | 协议参考实现 + mock 手机/DSH + 自动化联调 | Node.js |
| docs/PROTOCOL.md | 线协议契约 v1.0.2(三方共同合同) | — |

快速开始

1. 起中继(局域网:跑在 PC 上即可)
cd relay && npm install && node server.js # 默认 0.0.0.0:8787

2. 安装 DSH 插件(link 安装)
dsh plugin add ./plugin # 或 DSH 的 plugin_manager install_bundle

3. 配对(推荐扫码) DSH 会话里发送 /remote-pairing → PC 屏幕显示配对二维码手机 App 配对页点「扫码配对」→ 自动填参并连接(手动输入兜底:config.json 的 channel/secret + relayUrl 三项照填)

App 侧构建与装机见 app/README.md;mock 联调(无真机/无 DSH)见 e2e/README.md。

安全模型

- 配对 secret 经 HKDF-SHA256 派生端到端密钥;每帧 AES-256-GCM(iv||ct||tag),AAD 绑定发送方 role 与 seq 防串帧。
- 中继只见密文;channel 是随机能力串;hello 用 HMAC 签名证明持有 secret。
- 启动即跑协议 KAT 自测(docs/PROTOCOL.md §7),失败即禁用连接,绝不带病上线。
- 审批拦截 fail-open:超时(默认 120s)/出错/断线 → 放行桌面答案器。

License

MIT
预览分享卡片长什么样 ↓MoonlitDropOfBlood/dsh-remote-control
分享 · DeepSeek Harness Hub
MoonlitDropOfBlood/dsh-remote-control

远程控制dsh

这是你的仓库?认领条目

回到顶部