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

手机遥控台 hanzheng-dev/dsh-access-phone-remote

DeepSeek Harness
hanzheng-dev29 天前有提交已提供中文文档扫描:含敏感能力

用手机接续电脑 AI 对话并遥控这台电脑

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

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

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

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么[目录]—
dsh 原生插件 · other
暂无时间戳·判据 →
装得上吗[实装验证]✓
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
数据截至 2026/11/04·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/03·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 29 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

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

验证判据与等级说明 →

可信度证据

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件写入剪贴板(不计风险)读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 119 处,展示前 101 条)
  • 读取本地文件
    src/config.js:128
    return JSON.parse(fs.readFileSync(file, 'utf8'));
  • 读取本地文件
    src/config.js:135
    const usingExample = !fs.existsSync(CONFIG_FILE);
  • 读取密钥环境变量
    src/config.js:153
    if (process.env.HUB_TOKEN) cfg.authToken = process.env.HUB_TOKEN;
  • 读取密钥环境变量
    src/config.js:154
    if (process.env.AMAP_WEB_KEY) cfg.amap.webKey = process.env.AMAP_WEB_KEY;
  • 读取本地文件
    src/config.js:180
    token = fs.readFileSync(config.tokenFile, 'utf8').trim();
  • 写入本地文件
    src/config.js:187
    fs.writeFileSync(config.tokenFile, token, 'utf8');
  • 执行外部命令固定命令
    src/commands.js:26
    execFile('powershell', ['-NoProfile', '-NonInteractive', '-Command', wrapped],
  • 写入本地文件
    src/commands.js:49
    fs.mkdirSync(path.dirname(out), { recursive: true });
  • 读取本地文件
    src/commands.js:51
    if (!r.ok || !fs.existsSync(out)) return { ok: false, text: '截图失败: ' + (r.err || '文件未生成') };
  • 执行外部命令固定命令
    src/commands.js:145
    execFile(
  • 读取本地文件
    src/store.js:45
    const j = JSON.parse(fs.readFileSync(STORE_FILE, 'utf8'));
  • 写入本地文件
    src/store.js:57
    fs.mkdirSync(config.absRoot, { recursive: true });
  • 写入本地文件
    src/store.js:58
    fs.writeFileSync(STORE_FILE, JSON.stringify({ messages: messages.slice(-200), nextId }, null, 2), 'utf8');
  • 读取本地文件
    src/store.js:110
    const j = JSON.parse(fs.readFileSync(PENDING_FILE, 'utf8'));
  • 写入本地文件
    src/store.js:117
    fs.writeFileSync(PENDING_FILE, JSON.stringify(pending.slice(-PENDING_MAX), null, 1), 'utf8');
  • 读取本地文件
    src/store.js:151
    try { sz = fs.statSync(fp).size; } catch (e) { sz = 0; }
  • 读取本地文件
    src/store.js:221
    const st = fs.statSync(path.join(config.projectRoot, 'public', 'index.html'));
  • 读取本地文件
    src/store.js:249
    try { sz = fs.statSync(fp).size; } catch (e) { sz = 0; }
  • 请求外部主机restapi.amap.com
    src/routes/loc.js:31
    const r = await fetch('https://restapi.amap.com' + pathname + '?' + qs.toString(), { signal: ctl.signal });
  • 发起网络请求
    src/routes/loc.js:31
    const r = await fetch('https://restapi.amap.com' + pathname + '?' + qs.toString(), { signal: ctl.signal });
  • 读取本地文件
    src/routes/push.js:152
    if (fs.existsSync(pf)) fileMeta.pdf = String(body.file.pdf);
  • 读取本地文件
    src/routes/file.js:93
    const rs = fs.createReadStream(abs);
  • 读取本地文件
    src/routes/file.js:104
    const st = fs.statSync(abs);
  • 读取本地文件
    src/routes/file.js:107
    const text = fs.readFileSync(abs, 'utf8');
  • 读取本地文件
    src/routes/file.js:124
    const st = fs.statSync(abs);
  • 写入本地文件
    src/routes/file.js:133
    fs.copyFileSync(abs, bak);
  • 读取本地文件
    src/routes/file.js:138
    try { all = fs.readdirSync(dir); } catch (e) { all = []; }
  • 删除本地文件
    src/routes/file.js:145
    try { fs.unlinkSync(oldest); } catch (e) { }
  • 写入本地文件
    src/routes/file.js:148
    fs.writeFileSync(abs, text, 'utf8');
  • 读取本地文件
    src/routes/file.js:149
    const now = fs.statSync(abs).size;
  • 写入本地文件
    src/routes/file.js:183
    fs.mkdirSync(config.uploadsPath, { recursive: true });
  • 写入本地文件
    src/routes/file.js:190
    fs.writeFileSync(dst, data);
  • 读取本地文件
    src/routes/addresses.js:111
    return fs.readFileSync(config.tokenFile, 'utf8').trim();
  • 发起网络请求
    src/routes/chat.js:88
    const req = http.request({
  • 读取本地文件
    src/routes/chat.js:136
    try { groups = fs.readdirSync(base); } catch (e) { return ids; }
  • 读取本地文件
    src/routes/chat.js:141
    try { st = fs.statSync(gp); } catch (e) { continue; }
  • 读取本地文件
    src/routes/chat.js:144
    try { subs = fs.readdirSync(gp); } catch (e) { continue; }
  • 读取本地文件
    src/routes/chat.js:146
    if (fs.existsSync(path.join(gp, sid, 'session.v3.jsonl.zstd'))) {
  • 读取本地文件
    src/routes/chat.js:181
    return JSON.parse(fs.readFileSync(bridgeStatePath(), 'utf8'));
  • 执行外部命令固定命令
    src/routes/chat.js:211
    cmdline = execFileSync('powershell.exe',
  • 执行外部命令固定命令
    src/routes/chat.js:216
    cmdline = execFileSync('wmic.exe', ['process', 'where', `ProcessId=${n}`, 'get', 'CommandLine'],
  • 写入本地文件
    src/routes/chat.js:238
    fs.writeFileSync(bridgeStatePath(),
  • 读取本地文件
    src/routes/chat.js:289
    const buf = fs.readFileSync(file);
  • 执行外部命令来自配置/变量
    src/routes/chat.js:587
    const child = spawn(process.execPath, [BRIDGE, text, hitchImgPath], {
  • 读取密钥环境变量
    src/routes/cost.js:36
    if (process.env.DEEPSEEK_API_KEY) return String(process.env.DEEPSEEK_API_KEY).trim();
  • 读取本地文件
    src/routes/cost.js:39
    const t = fs.readFileSync(path.resolve(c.balanceKeyFile), 'utf8');
  • 请求外部主机api.deepseek.com
    src/routes/cost.js:59
    const res = await fetch('https://api.deepseek.com/user/balance', {
  • 发起网络请求
    src/routes/cost.js:59
    const res = await fetch('https://api.deepseek.com/user/balance', {
  • 读取本地文件
    src/cost.js:58
    try { dirs = fs.readdirSync(SESS_ROOT, { withFileTypes: true }); } catch (e) { return null; }
  • 读取本地文件
    src/cost.js:63
    try { subs = fs.readdirSync(p, { withFileTypes: true }); } catch (e) { continue; }
  • 读取本地文件
    src/cost.js:68
    try { files = fs.readdirSync(sp); } catch (e) { continue; }
  • 读取本地文件
    src/cost.js:73
    const st = fs.statSync(fp);
  • 读取本地文件
    src/cost.js:93
    try { size = fs.statSync(file).size; } catch (e) { return out; }
  • 读取本地文件
    src/cost.js:141
    try { return fs.statSync(f).size; } catch (e) { return 0; }
  • 读取本地文件
    src/terminal-qr.js:22
    const src = fs.readFileSync(p, 'utf8');
  • 读取本地文件
    src/dsh/auth.js:62
    if (fs.existsSync(path.join(dir, '.credentials.yaml'))) return dir;
  • 读取本地文件
    src/dsh/auth.js:98
    const files = fs.readdirSync(d)
  • 读取本地文件
    src/dsh/auth.js:102
    try { return { p, t: fs.statSync(p).mtimeMs }; } catch (e) { return null; }
  • 读取本地文件
    src/dsh/auth.js:124
    const raw = fs.readFileSync(p, 'utf8');
  • 读取本地文件
    src/dsh/auth.js:169
    const txt = fs.readFileSync(f, 'utf8');
  • 发起网络请求
    src/dsh/auth.js:182
    const req = http.request({
  • 写入本地文件
    android/make-icons.js:93
    fs.mkdirSync(dir, { recursive: true });
  • 写入本地文件
    android/make-icons.js:94
    fs.writeFileSync(path.join(dir, 'ic_launcher.png'), makePng(size, iconPixel));
  • 写入本地文件
    android/make-icons.js:97
    fs.writeFileSync(path.join(dir, 'ic_launcher_bg.png'),
  • 写入本地文件
    android/make-icons.js:102
    fs.mkdirSync(path.join(base, 'drawable'), { recursive: true });
  • 写入本地文件
    android/make-icons.js:103
    fs.writeFileSync(path.join(base, 'drawable', 'ic_launcher_fg.png'), makePng(192, iconPixel));
  • 写入本地文件
    android/make-icons.js:106
    fs.mkdirSync(path.join(base, 'mipmap-anydpi-v26'), { recursive: true });
  • 发起网络请求
    plugin/src/client.js:62
    const res = await fetch(PREFIX + path, options)
  • 写入剪贴板
    plugin/src/client.js:843
    await navigator.clipboard.writeText(text)
  • 读取本地文件
    plugin/src/index.js:68
    return JSON.parse(readFileSync(configFile(), 'utf8'))
  • 写入本地文件
    plugin/src/index.js:84
    mkdirSync(configDir(), { recursive: true })
  • 写入本地文件
    plugin/src/index.js:85
    writeFileSync(configFile(), JSON.stringify(next, null, 2), 'utf8')
  • 读取本地文件
    plugin/src/index.js:123
    if (!existsSync(entry)) {
  • 执行外部命令来自配置/变量
    plugin/src/index.js:131
    child = spawn(process.execPath, [entry], {
  • 读取本地文件
    plugin/src/index.js:199
    return readFileSync(join(projectDir, '.hub-token'), 'utf8').trim()
  • 发起网络请求
    src/doctor.js:54
    const req = require('http').request(
  • 读取本地文件
    src/doctor.js:91
    if (fs.existsSync(cfgPath)) {
  • 读取本地文件
    src/doctor.js:92
    config = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
  • 读取本地文件
    src/doctor.js:94
    } else if (fs.existsSync(exPath)) {
  • 读取本地文件
    src/doctor.js:95
    config = JSON.parse(fs.readFileSync(exPath, 'utf8'));
  • 读取本地文件
    src/doctor.js:120
    if (fs.existsSync(tokenFile)) {
  • 读取本地文件
    src/doctor.js:121
    const t = fs.readFileSync(tokenFile, 'utf8').trim();
  • 写入本地文件
    src/doctor.js:162
    fs.writeFileSync(probe, 'x');
  • 删除本地文件
    src/doctor.js:163
    fs.unlinkSync(probe);
  • 读取本地文件
    src/dsh/bridge.js:57
    if (fs.existsSync(LOG_FILE) && fs.statSync(LOG_FILE).size > 2 * 1024 * 1024) fs.rmSync(LOG_FILE, { force: true });
  • 写入本地文件
    src/dsh/bridge.js:58
    fs.appendFileSync(LOG_FILE, line + '\n', 'utf8');
  • 发起网络请求
    src/dsh/bridge.js:103
    const req = http.request({
  • 读取本地文件
    src/dsh/bridge.js:137
    const j = JSON.parse(fs.readFileSync(AUTH_CACHE_FILE, 'utf8'));
  • 写入本地文件
    src/dsh/bridge.js:146
    fs.writeFileSync(AUTH_CACHE_FILE, JSON.stringify({ cookie, savedAt: Date.now(), authority: AUTHORITY }), 'utf8');
  • 发起网络请求
    src/dsh/bridge.js:262
    await fetch(HUB_BASE + '/api/delta', {
  • 发起网络请求
    src/dsh/bridge.js:272
    await fetch(HUB_BASE + '/api/push', {
  • 读取本地文件
    src/dsh/bridge.js:453
    if (!fs.existsSync(p)) continue;
  • 写入本地文件
    src/dsh/bridge.js:456
    fs.mkdirSync(config.shotsPath, { recursive: true });
  • 写入本地文件
    src/dsh/bridge.js:457
    fs.copyFileSync(p, path.join(config.shotsPath, name));
  • 读取本地文件
    src/dsh/bridge.js:598
    const j = JSON.parse(fs.readFileSync(STATE, 'utf8'));
  • 写入本地文件
    src/dsh/bridge.js:607
    fs.mkdirSync(path.dirname(STATE), { recursive: true });
  • 写入本地文件
    src/dsh/bridge.js:608
    fs.writeFileSync(tmp, JSON.stringify(s), 'utf8');
  • 执行外部命令固定命令
    src/dsh/bridge.js:772
    cmdline = execFileSync('powershell', ['-NoProfile', '-Command',
  • 读取本地文件
    src/dsh/bridge.js:897
    const LIVE_ENABLED = process.env.DSH_BRIDGE_LIVE !== '0' && !fs.existsSync(LIVE_OFF_FILE);
  • 读取本地文件
    src/dsh/bridge.js:1015
    const buf = fs.readFileSync(hitchImg);
  • 读取本地文件
    src/dsh/live.js:113
    const j = JSON.parse(fs.readFileSync(AUTH_CACHE_FILE, 'utf8'));
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库
涉及外部主机:restapi.amap.com、api.deepseek.com

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

社区实装还没有人打卡 · 装过的第一个就是你
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 手机接续电脑AI对话
  • 遥控电脑
  • 推送与传文件

把手机变成你电脑的遥控器:推送、传文件、位置、可扩展动作,还能在手机上跟电脑里的 AI 对话。数据全部留在自己电脑上,零 npm 依赖。出门在外可配 Tailscale。

README

由 DeepSeek 最新模型翻译生成
dsh-access-phone-remote 在手机上与你电脑上的 AI 对话,并遥控这台电脑。 所有数据保留在本地,零 npm 依赖,仅使用 Node.js 内置模块。 简介 这个项目让手机连回自己的电脑。作者已在自己电脑上自用两个多月,2026 年 10 月开源。 其中真正构成差异的有四项能力,其余属于常规远程控制范畴,列于本节末尾。 一、在手机上延续电脑上的 AI 会话 电脑上运行 dsh(DeepSeek Harness)时,手机打开即接续那段对话。 模型、会话上下文与工具全部位于电脑,手机只承担显示与输入。 生成过程完全可见:正文逐字返回,推理内容折叠显示(标题实时标注「思考中 · N 字」),工具调用各占一行摘要、展开后为完整参数,而不是一次性返回整段结果。 - 推理档位可在手机上直接切换(off / high / max) - 「发送」与「停止」为两个独立按钮,生成过程中可随时中断,避免误触 该能力默认关闭。将 config.json 中的 dsh.enabled 改为 true 并配置 dsh.base 之后入口才会出现;未安装 dsh 可跳过本节,其余功能不受影响。
展开完整文档(README 剩余 1 节)
dsh-access-phone-remote

在手机上与你电脑上的 AI 对话,并遥控这台电脑。

所有数据保留在本地,零 npm 依赖,仅使用 Node.js 内置模块。

简介

这个项目让手机连回自己的电脑。作者已在自己电脑上自用两个多月,2026 年 10 月开源。

其中真正构成差异的有四项能力,其余属于常规远程控制范畴,列于本节末尾。

一、在手机上延续电脑上的 AI 会话

电脑上运行 dsh(DeepSeek Harness)时,手机打开即接续那段对话。
模型、会话上下文与工具全部位于电脑,手机只承担显示与输入。

生成过程完全可见:正文逐字返回,推理内容折叠显示(标题实时标注「思考中 · N 字」),工具调用各占一行摘要、展开后为完整参数,而不是一次性返回整段结果。

- 推理档位可在手机上直接切换(off / high / max)
- 「发送」与「停止」为两个独立按钮,生成过程中可随时中断,避免误触

该能力默认关闭。将 config.json 中的 dsh.enabled 改为 true 并配置 dsh.base 之后入口才会出现;未安装 dsh 可跳过本节,其余功能不受影响。

会话页:正文逐字返回,推理与工具调用折叠在侧

二、搭便车:图片与消息在同一轮送达

手机拍摄或上传的图片不会立即发送,而是先进入待发队列;在你发送下一条消息时,它自动附加到该消息上一并提交给 AI。

因此拍摄后直接输入文字即可,图片与问题在同一轮送达,无需先发送图片再补充说明。
(队列中每项保留 3 分钟,超时丢弃。)

三、推送是可操作的卡片,网页在内置 WebView 里打开

推送到手机的不只是一条通知。POST /api/push 可以携带:

- 交互按钮(最多 6 个):点一下把对应值作为消息回传 —— 电脑上的提问可以在手机上直接作答
- 选项卡(最多 8 项,支持多选):选完作为消息回传
- 网页卡片({url,title},仅接受 http/https):点开后进入应用内置的独立 WebView,不跳转系统浏览器。该 WebView 是独立实例而非内嵌框架,数据目录本身持久,因此登录状态得以保留 —— 电脑上推来的内部页面可以直接在手机上登录并继续使用。

消息正文里的明文链接同样会自动生成一张可折叠的网页卡片,原文保持不变。

推送也可以携带文本附件:它折叠成一行,点开即在对话里显示全文;右上角的「编辑」可以当场修改,保存后写回电脑上的原文件(写前自动备份)。

推送卡片(正文 · 网页卡 · 交互按钮) · 内置 WebView 浮层 · 文本附件展开 · 在手机上直接编辑并写回

四、无需配置 IP 与端口

服务端每 3 秒在局域网内广播一次,手机客户端自动发现电脑,无需手动填写地址。
需要外网访问时使用 Tailscale,两端登录同一账号即可回连,不需要公网 IP,也不需要端口映射。

其余能力

任务完成与提醒的通知推送、双向文件传输、周边搜索与路线规划、一键截图与显示桌面,以及自定义指令(修改 config.json 即可新增按钮,无需改动代码)。

主页抽屉(传文件 · 位置 · 截图 · 自定义按钮) · 内置帮助页

与云服务的区别:所有数据保留在本地电脑,不经过任何第三方。

下载

| 你要什么 | 拿哪个 | 必需吗 |
| 服务端 | 本仓库 clone 下来,node src/server.js。零 npm 依赖 | 必需 |
| Android 客户端 | Releases 里的 APK(约 50 KB,Android 7+) | 可选 |
| HarmonyOS 客户端 | 预发布 里的 HAP —— ⚠️ 见下面的说明,别当成品用 | 可选 |
| dsh 插件 | dsh plugin --profile web add github:hanzheng-dev/dsh-access-phone-remote#path:/plugin,或 npm 的 dsh-access-phone-remote | 可选 |

不装 APK 也能用 —— 手机浏览器打开服务端地址即可,功能一致;装 APK 才有的额外好处是系统通知推送。

⚠️ 关于 HarmonyOS 那个 HAP:它是预览版,不是成品。
它证到的是「不用 IDE、不用华为账号,纯命令行链能产出运行时真的会加载的 HAP」——已在 SDK 自带 Previewer 里跑通并渲染出配置页。
但从没在真机/模拟器上验过(手头没有纯血鸿蒙设备),而且签名用的是 OpenHarmony 社区证书,商业版 HarmonyOS NEXT 真机可能不认。
这个 App 的全部 UI 又都在全屏 Web 壳里,而那个壳恰好是预览器验不了的部分。
所以:装不上、或起来白屏,都属于已知的未知,欢迎开 issue。
全过程(三个致命缺陷 + 判定标准)在 harmonyos/RUN-NOTES.md。

给 AI 用的部署向导

如果你在使用 Claude / ChatGPT / Cursor 等 AI 助手协助部署:

将本仓库的 AGENTS.md 提供给该助手,由它引导你完成部署。

它是一份专为 AI 阅读而写的部署剧本,会逐步确认环境、判断分支、处理报错。

这是本项目区别于同类工具的一点:部署知识不以「让人读懂」为目标,而是交给使用者自己的 AI 读懂。

快速开始

1. 需要 Node.js 18+
node --version

2. 起服务
node src/server.js

3. 终端里会直接出现一个二维码 —— 手机扫一下就连上了(也会打印地址,形如 http://192.168.1.100:3099/?t=<token>)

启动后的终端长这样:

[07:41:49] ===== dsh-access-phone-remote 启动,监听 0.0.0.0:3099,功能 5 个 ===== [07:41:49] 本机: http://127.0.0.1:3099/ [07:41:49] 手机访问: http://192.168.1.100:3099/

手机扫这个(或复制上面那行):

█▀▀▀▀▀█ ▄█ ▄▄▄▀▄ █▀▀▀▀▀█
█ ███ █ ▄█▀█ ▄▀ ▀ █ ███ █
...(二维码)

[07:41:49] 其他可用地址: 100.64.1.20(tailscale) 192.168.56.1(virtual)

地址会自动挑:局域网 IP 优先(不用装任何东西),Tailscale 次之,虚拟网卡(VirtualBox 等)会标注出来 —— 因为手机连不上虚拟网卡。

局域网内零配置:服务端会持续发 UDP 广播(每 3 秒一次),配套的手机 App 在同一 WiFi 下能自动发现电脑,连地址都不用填。
(不想要这个?config.json 里把 discovery.enabled 设为 false。)

手机在外面也能访问 → 用 Tailscale(免费)。

先自检一下环境(可选但推荐):

node src/doctor.js # 或 npm run doctor

它会告诉你:Node 版本够不够、端口通不通、网络地址有哪些、高德 key 配了没、缺什么、下一步做什么。

详细步骤:
- 给 AI:AGENTS.md
- 给人:docs/ARCHITECTURE.md
- 遇到问题:docs/TROUBLESHOOT.md(按症状走决策树)
- 坑清单:docs/PITFALLS.md(88 条实测坑)

为什么值得一看

1. 有一个「给 AI 的说明书」

AGENTS.md 不是代码风格指南 —— 是部署剧本。

设计意图:用户不需要读懂技术细节,让用户自己的 AI 去读懂。出了问题,用户的 AI 就地解决,不依赖作者支持。

2. docs/PITFALLS.md 是两个月踩出来的

88 条真实坑,每条都有症状 → 根因 → 解法:

- adb tcpip 5555 vs Android「无线调试」的本质区别
- Tailscale MagicDNS 把自己当 DNS → 手机上不了网
- WGS84/GCJ02 混用偏 500 米
- .bat 用 LF 换行 → 整个自启链从没跑过
- 计划任务闪黑框,-WindowStyle Hidden 救不了
- d8 在 JDK 24 上遇到匿名内部类必崩
- …

这些不是查文档能查到的,是踩出来的。

3. Windows-only MVP

核心功能跨平台,但 screenshot / show_desktop 依赖 Win32。

架构

手机(浏览器 / WebView APK) │ │ HTTP(局域网 或 Tailscale) ▼ 电脑:Node 服务(零依赖) ├─ /api/chat /api/sessions /api/busy │ /api/delta /api/stop /api/effort 会话页:跟电脑里的 AI 接着聊 ├─ /api/push /api/inbox /api/events 推送(含 SSE 实时流) ├─ /api/file /api/upload 文件读 / 下载 / 写回 / 上传 ├─ /api/loc /api/poi /api/route 定位 / 附近搜索 / 路径规划 ├─ /api/run /api/commands 指令分发(白名单) └─ /api/addresses /api/features /api/ping 地址列举 / 功能开关 / 健康检查 │ ├──────────────► 你电脑上的 dsh(DeepSeek Harness) ← 会话页注入这条 │ └──────────────► 你电脑上的其它东西(截图 / 文件 / 桌面)

服务端零 npm 依赖 —— 只用 Node 内置模块。

文档

| 文件 | 给谁 | 内容 |
| AGENTS.md | AI | 部署剧本(核心) |
| docs/PITFALLS.md | 都行 | 88 条实测坑 |
| docs/TROUBLESHOOT.md | AI | 排障决策树(按症状走) |
| docs/ONBOARDING.md | 人 | 上手引导 |
| docs/FOR-AI-EXTEND.md | AI | 扩展指南(含「不改代码加功能」) |
| docs/ARCHITECTURE.md | 人 | 架构说明 |
| docs/SECURITY.md | 人 | 安全说明 |
| android/README.md | 人 | 安卓客户端(APK)—— 构建与配置 |
| harmonyos/README.md | 人 | 鸿蒙客户端(HAP)—— 构建与配置(不需要 IDE / 华为账号) |
| harmonyos/RUN-NOTES.md | 人 + AI | ★ 鸿蒙产物「怎么才真的跑起来」:三个致命缺陷、Previewer 启动参数、判定标准 |
| harmonyos/BUILD-NOTES.md | 人 | 鸿蒙手工构建链的逐步实测记录 |
| llms.txt | AI 爬虫 | 索引 |

安全

- 服务只在你自己的网络里(局域网 / Tailscale)
- 鉴权:访问 token(首次启动自动生成)
- 指令白名单:只能执行预设动作,不能执行任意命令
- ⚠️ 不要暴露到公网(除非你清楚风险)

详见 docs/SECURITY.md。

许可

MIT

状态

早期项目(MVP)。核心功能可用,文档持续完善。

遇到问题时:先查 docs/PITFALLS.md;或将其与 AGENTS.md 一并交给你的 AI 助手处理。
预览分享卡片长什么样 ↓hanzheng-dev/dsh-access-phone-remote
分享 · DeepSeek Harness Hub
hanzheng-dev/dsh-access-phone-remote

用手机接续电脑 AI 对话并遥控这台电脑

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部