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

口袋远控台 Zheyi-D/dsh-pocket

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

用手机远程操作本机 DSH 并管理整台电脑

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

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

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

状态速览

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

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

验证判据与等级说明 →

可信度证据

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

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

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 67 处,展示前 59 条)
  • 读取本地文件
    integrations/dsh-patch/apply.mjs:34
    if (existsSync(c)) return c;
  • 读取本地文件
    integrations/dsh-patch/apply.mjs:157
    if (!existsSync(full)) {
  • 读取本地文件
    integrations/dsh-patch/apply.mjs:162
    let text = readFileSync(full, "utf8");
  • 写入本地文件
    integrations/dsh-patch/apply.mjs:185
    writeFileSync(full, text);
  • 写入本地文件
    integrations/dsh-patch/apply.mjs:193
    writeFileSync(full, next);
  • 执行外部命令来自配置/变量
    integrations/dsh-patch/apply.mjs:195
    execFileSync(process.execPath, ["--check", full], { stdio: "pipe" });
  • 写入本地文件
    integrations/dsh-patch/apply.mjs:220
    writeFileSync(full, text.replace(p.find, p.replace));
  • 执行外部命令来自配置/变量
    integrations/dsh-patch/apply.mjs:222
    execFileSync(process.execPath, ["--check", full], { stdio: "pipe" });
  • 读取本地文件
    src/config.js:115
    if (fs.existsSync(CONFIG_FILE)) {
  • 读取本地文件
    src/config.js:118
    const raw = fs.readFileSync(CONFIG_FILE, "utf8").replace(/^ FEFF/, "");
  • 读取本地文件
    src/config.js:180
    if (fs.statSync(candidate).isFile()) return candidate;
  • 读取本地文件
    src/config.js:199
    if (fs.existsSync(guess)) return guess;
  • 读取本地文件
    src/config.js:211
    if (fs.existsSync(guess)) return guess;
  • 读取本地文件
    src/config.js:267
    rows.push({ name: "终端 · SSH 私钥", ok: fs.existsSync(key), detail: fs.existsSync(key) ? key : "缺少 " + key + "(网页终端不可用)" });
  • 读取本地文件
    src/jobs.js:95
    const j = JSON.parse(fs.readFileSync(STATE, "utf8"));
  • 写入本地文件
    src/jobs.js:104
    fs.mkdirSync(JOBS_DIR, { recursive: true });
  • 写入本地文件
    src/jobs.js:105
    fs.writeFileSync(STATE, JSON.stringify(list, null, 1));
  • 读取本地文件
    src/jobs.js:145
    try { st = fs.statSync(dir); } catch {}
  • 写入本地文件
    src/jobs.js:153
    fs.mkdirSync(JOBS_DIR, { recursive: true });
  • 写入本地文件
    src/jobs.js:155
    fs.writeFileSync(logFile, "");
  • 写入本地文件
    src/jobs.js:156
    try { fs.writeFileSync(path.join(JOBS_DIR, id + ".prompt.txt"), text); } catch {}
  • 执行外部命令来自配置/变量
    src/jobs.js:190
    child = spawn(cmd, args, { cwd: dir, detached: true, windowsHide: true, stdio: ["ignore", fd, fd] });
  • 执行外部命令固定命令
    src/jobs.js:234
    execFile("taskkill", ["/PID", String(j.pid), "/T", "/F"], { windowsHide: true }, (err) => {
  • 读取本地文件
    src/jobs.js:246
    try { cfg = JSON.parse(fs.readFileSync(path.join(JOBS_DIR, "notify.json"), "utf8")); } catch { }
  • 发起网络请求
    src/jobs.js:259
    fetch(target, Object.assign({ signal: AbortSignal.timeout(8000) }, init))
  • 读取本地文件
    src/jobs.js:366
    try { size = fs.statSync(job.log).size; } catch {}
  • 写入本地文件
    src/serve-files.js:19
    try { fs.mkdirSync(DATA_DIR, { recursive: true }); } catch {}
  • 写入本地文件
    src/serve-files.js:20
    const log = (m) => { try { fs.appendFileSync(LOG, new Date().toISOString() + " [files] " + m + "\n"); } catch {} };
  • 读取本地文件
    src/serve-files.js:133
    const st = await fsp.stat(r);
  • 读取本地文件
    src/serve-files.js:157
    items = await fsp.readdir(dir, { withFileTypes: true });
  • 读取本地文件
    src/serve-files.js:166
    const st = await fsp.stat(full);
  • 读取本地文件
    src/serve-files.js:394
    const st = await fsp.stat(p);
  • 读取本地文件
    src/serve-files.js:543
    try { entries = await fsp.readdir(dir, { withFileTypes: true }); } catch { continue; }
  • 读取本地文件
    src/serve-files.js:548
    try { st = await fsp.stat(full); } catch { continue; }
  • 写入本地文件
    src/serve-files.js:596
    await fsp.mkdir(target);
  • 写入本地文件
    src/serve-files.js:612
    await fsp.rename(src, dst);
  • 删除本地文件
    src/serve-files.js:626
    if (st.isDirectory()) await fsp.rm(target, { recursive: true, force: true });
  • 删除本地文件
    src/serve-files.js:627
    else await fsp.unlink(target);
  • 写入本地文件
    src/serve-files.js:686
    const ws = fs.createWriteStream(target);
  • 写入本地文件
    src/serve-menu.js:28
    try { fs.mkdirSync(DATA_DIR, { recursive: true }); } catch {}
  • 写入本地文件
    src/serve-menu.js:29
    const log = (m) => { try { fs.appendFileSync(LOG, new Date().toISOString() + " [portal] " + m + "\n"); } catch {} };
  • 读取本地文件
    src/serve-menu.js:142
    const html = fs.readFileSync(path.join(__dirname, "public", "index.html"), "utf8");
  • 发起网络请求
    src/serve-menu.js:203
    const req = http.get({ host: "127.0.0.1", port, path: "/", timeout: 3000 }, (res) => {
  • 执行外部命令固定命令
    src/serve-menu.js:217
    execFile("netstat", ["-ano"], { windowsHide: true, maxBuffer: 8 << 20 }, (err, stdout) => {
  • 执行外部命令固定命令
    src/serve-menu.js:238
    execFile("tasklist", ["/FI", "PID eq " + pid, "/FO", "CSV", "/NH"], { windowsHide: true }, (err, stdout) => {
  • 执行外部命令固定命令
    src/serve-menu.js:266
    execFile("taskkill", args, { windowsHide: true }, (err) => {
  • 执行外部命令固定命令
    src/serve-menu.js:295
    const child = spawn("cmd", ["/c", "start", "", "/min", svc.script], { detached: true, stdio: "ignore", windowsHide: true });
  • 执行外部命令来自配置/变量
    src/serve-menu.js:299
    const child = spawn(process.execPath, [path.join(__dirname, svc.js)], {
  • 读取本地文件
    src/serve-menu.js:348
    try { t = fs.readFileSync(f, "utf8"); } catch { continue; }
  • 读取本地文件
    src/serve-menu.js:364
    try { lines = fs.readFileSync(HISTORY_FILE, "utf8").trim().split("\n").filter(Boolean); } catch {}
  • 写入本地文件
    src/serve-menu.js:369
    fs.writeFileSync(HISTORY_FILE, lines.join("\n") + "\n");
  • 读取本地文件
    src/serve-menu.js:377
    return fs.readFileSync(HISTORY_FILE, "utf8").trim().split("\n").filter(Boolean)
  • 发起网络请求
    src/serve-menu.js:395
    const r = await fetch(BALANCE_URL, {
  • 执行外部命令固定命令
    src/serve-menu.js:499
    execFile(
  • 读取本地文件
    src/serve-menu.js:626
    fs.readFile(asset[0], (err, buf) => {
  • 写入本地文件
    src/serve-term.js:39
    try { fs.mkdirSync(DATA_DIR, { recursive: true }); } catch {}
  • 写入本地文件
    src/serve-term.js:40
    const log = (m) => { try { fs.appendFileSync(LOG, new Date().toISOString() + " [term] " + m + "\n"); } catch {} };
  • 读取本地文件
    src/serve-term.js:413
    fs.readFile(asset[0], (err, buf) => {
  • 读取本地文件
    src/serve-term.js:459
    key = fs.readFileSync(KEY_FILE);
扫描于 2026/11/4(1 天前) · 范围 全包扫描 · 来源 GitHub 仓库

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

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

功能亮点

  • 手机远程控制本机
  • 管理整台电脑

用手机控制本地 DeepSeek Harness,连同它所在的整台电脑。

README

由 DeepSeek 最新模型翻译生成
dsh-pocket English · 简体中文 把本机的 DeepSeek Harness 装进口袋:用手机远程操作它,顺带管理这台电脑。 一个轻量、依赖很少的 Node 网页面板,跑在你自己的机器上,通过私有网络(Tailscale、WireGuard,或者就局域网)访问。没有云服务、没有账号、没有遥测,数据只在你的设备之间流动。 安全提醒,务必先看 docs/SECURITY.md。 这套面板没有任何登录。能连上端口的人就能浏览整台电脑的文件、执行任意命令。 请只在回环地址加私有网络里使用,不要暴露到公网。 网页界面目前只有中文;文档是中英双语(本文件和 README.md)。 为什么推荐用 Tailscale 这套面板没有登录(见 docs/SECURITY.md),所以网络本身就是认证层,而 Tailscale 把这件事变成一条命令: - 只有你自己的设备能连上。tailscale serve 只把面板暴露给你的 tailnet,不暴露到公网;能控制这台机器的,就是加入了 tailnet 的设备。 - 白拿一个固定域名和 HTTPS。MagicDNS 给你 <机器名>.<tailnet>.ts.net,它的 TLS 终止正好满足浏览器对安全上下文的要求(crypto.randomUUID 这类接口),不用你自己折腾证书。 - 路由器上不用开任何端口。
展开完整文档(README 剩余 1 节)
dsh-pocket

English · 简体中文

把本机的 DeepSeek Harness 装进口袋:用手机远程操作它,顺带管理这台电脑。

一个轻量、依赖很少的 Node 网页面板,跑在你自己的机器上,通过私有网络(Tailscale、WireGuard,或者就局域网)访问。没有云服务、没有账号、没有遥测,数据只在你的设备之间流动。

安全提醒,务必先看 docs/SECURITY.md。
这套面板没有任何登录。能连上端口的人就能浏览整台电脑的文件、执行任意命令。
请只在回环地址加私有网络里使用,不要暴露到公网。

网页界面目前只有中文;文档是中英双语(本文件和 README.md)。

为什么推荐用 Tailscale

这套面板没有登录(见 docs/SECURITY.md),所以网络本身就是认证层,而 Tailscale 把这件事变成一条命令:

- 只有你自己的设备能连上。tailscale serve 只把面板暴露给你的 tailnet,不暴露到公网;能控制这台机器的,就是加入了 tailnet 的设备。
- 白拿一个固定域名和 HTTPS。MagicDNS 给你 <机器名>.<tailnet>.ts.net,它的 TLS 终止正好满足浏览器对安全上下文的要求(crypto.randomUUID 这类接口),不用你自己折腾证书。
- 路由器上不用开任何端口。没有端口转发,也就没有「哪天忘了关」的公网入口。

完整步骤(安装、MagicDNS、三条 serve 命令、终端要登记的 SSH 公钥、DSH 的主机参数、用 IP 访问的注意事项)见 docs/TAILSCALE.zh-CN.md。

其它私有网络也完全可行(WireGuard、ZeroTier,或者就局域网),Tailscale 只是「手机连家里电脑」这件事上折腾最少的一个。

有什么

| 功能 | 说明 |
| 门户(8080) | 卡片菜单、服务实时状态、启动/停止按钮、配置自检 |
| 文件浏览(8082) | 全盘浏览、上传、重命名、删除、打包下载、按文件名搜索 |
| 预览 | 图片、视频/音频(支持 Range,手机上能拖进度)、PDF、Markdown、JSON、CSV 表格、代码;自动识别 GBK 老文件 |
| 网页终端(8083) | 走本机 OpenSSH 的真 PTY,claude / vim / top 都能用;锁屏和切网络不会丢会话;带一排手机功能键(Esc / Ctrl+C / 方向键 / PgUp…) |
| 任务台(/jobs) | 把一句话派给 Claude Code 或 DSH(无头模式),实时看翻译后的日志、随时停止、看到 token 用量 |
| API 余额(可选) | DeepSeek 余额和充值入口;默认关闭,API key 不出本机 |
| 可选适配 | 按需启动 DSH Web 与 VS Code serve-web;可选的 DSH 源码补丁工具(注意 integrations/dsh-patch 里的警告) |

可选功能都会优雅降级:没装 OpenSSH、没装 agent、模块被关掉,页面都会给人话提示,而不是报错。

前置条件

- Node.js 20+
- Windows 10/11(主要目标)。核心部分(门户、文件浏览、预览、终端)在 macOS/Linux 上也能跑;盘符枚举、服务启停、.bat/.vbs 启动器这些 Windows 专属能力会跳过或降级为只读状态。
- 按功能需要:
- OpenSSH 服务端 —— 网页终端需要。Windows 上装「OpenSSH 服务器」可选功能,并确认服务在跑。
- Tailscale(或 WireGuard、ZeroTier 这类私有网络,或者就局域网)—— 手机远程访问需要。
配置教程见 docs/TAILSCALE.zh-CN.md。
- Claude Code 和/或 DSH —— 任务台需要。
- VS Code 命令行 —— serve-web 卡片需要。

安装

第一次上手?看 docs/SETUP.zh-CN.md —— 电脑端从零到能用的完整步骤:装 Node、跑安装脚本、每个配置项什么时候要改、OpenSSH 与 agent 这些可选项怎么开、改完怎么重启。

git clone https://github.com/Zheyi-D/dsh-pocket.git
cd dsh-pocket
powershell -ExecutionPolicy Bypass -File scripts\install.ps1

安装脚本会:检查 Node → npm install → 现场生成一把新的 SSH 密钥(仓库里永远不带密钥)→ 生成 config.json → 可选地注册开机启动 → 最后跑一遍自检。

常用参数:-NoAutostart(不注册启动项)、-SkipInstall(跳过 npm)、-Force(重建配置)。

之后:

node scripts\start.js # 启动门户 + 文件浏览 + 终端
node scripts\diagnose.js # 看当前配置、还缺什么
node test\smoke.mjs # 17 项冒烟测试(用临时端口,不动你正在跑的服务)
node scripts\scan.mjs # 提交前扫描:有没有把密钥 / 本机路径带进仓库

打开 http://127.0.0.1:8080/。

macOS / Linux:npm install && node scripts/start.js。

把公钥登记给 sshd(网页终端用)

安装脚本会把公钥打印出来。Windows 上如果你的账号在管理员组里,sshd 读取的是 C:\ProgramData\ssh\administrators_authorized_keys,而不是 ~/.ssh/authorized_keys:

Add-Content -Path C:\ProgramData\ssh\administrators_authorized_keys -Value "<你的公钥>"

(需要在管理员终端里执行。)

交给你的 agent

把下面这段直接丢给能在你电脑上执行命令的编码 agent(Claude Code、DSH、Cursor 都行)。这段提示词是自带坑位说明的:常见的几处坑都写进去了,并且明确告诉它哪一步必须由人来完成。

请在这台电脑上配置 dsh-pocket(https://github.com/Zheyi-D/dsh-pocket),完成后向我汇报。

1. 把仓库放到不含空格和非 ASCII 字符的路径下,然后 cd 进去。
2. 确认 node -v 是 20 或更高。不满足就停下告诉我,不要自己装 Node。
3. 执行:powershell -ExecutionPolicy Bypass -File scripts/install.ps1 -NoAutostart (先不开机自启,之后我来决定)。这一步会装依赖、在本机生成 SSH 密钥、写出 config.json。
4. 执行 node scripts/diagnose.js,逐条告诉我还缺什么。
5. 未经我要求,不要开启可选项:网页终端需要 OpenSSH 服务端并把公钥登记给 sshd;任务台需要 PATH 里有 Claude Code 或 DSH;VS Code、DeepSeek 余额都是可选的。
6. 用 node scripts/start.js 启动,然后用 node test/smoke.mjs 验证(它用临时端口,每条断言打印 PASS/FAIL)。
7. 所有跟本机有关的值都写在 config.json 里,不要动 src/ 下的代码,除非我明确要求。
8. 不要把 ssh/、config.json、data/、scan.local.json 提交进仓库。任何提交之前先跑
node scripts/scan.mjs,并把结果给我看。
9. 自己发挥容易踩的坑(都记在 docs/TROUBLESHOOTING.md):
- PowerShell 5.1 会把无 BOM 的 UTF-8 当 ANSI 读:含非 ASCII 的 .ps1 必须存成 UTF-8 带 BOM;.bat/.cmd/.vbs 只能用 ASCII。它还会丢掉空字符串参数(所以 ssh-keygen -N '' 会失败),而 Set-Content -Encoding UTF8 会写出 BOM,导致 JSON.parse 直接报错。
- Windows 上如果账号在管理员组里,sshd 会忽略 ~/.ssh/authorized_keys,改读 C:\ProgramData\ssh\administrators_authorized_keys。追加公钥需要管理员终端,这一步请让我来做,不要自己尝试。
- Tailscale 的转发会让 tailscaled 监听同样的端口号:不能只看端口就断定服务活着。
- 这套面板没有任何登录。bindHost 保持 127.0.0.1,只通过私有网络访问。
10. 完成后汇报:实际使用的端口、服务的启动/停止方式、还需要我做什么、以及你执行过的完整命令。

配置

把 config.example.json 复制成 config.json(安装脚本会做),然后按需修改。所有跟本机有关的东西都在这里——源码里没有任何用户名、盘符或绝对路径。

| 键 | 含义 |
| bindHost、portalPort、filesPort、termPort | 各服务的监听地址与端口。除非你清楚后果,否则保持 127.0.0.1 |
| portal.title | 门户标题(也用作浏览器标签) |
| terminal. | SSH 主机/端口/用户、私钥路径、shell 命令、会话摘挂保留时长、enabled |
| jobs. | enabled、默认工作目录、显式的 CLI 路径、并发上限、推送地址 |
| vscode. | enabled、端口、codePath |
| files. | 列表条数上限、预览字节上限 |
| security.allowedHosts | 允许的 Host/Origin(支持 .example.com)。默认放行回环地址和 .ts.net。用 IP 访问的话必须把 IP 加进去,否则会被 403。 |
| balance. | enabled(默认 false)、接口地址、从哪里读 key、充值/用量链接 |
| services | 状态页上的服务清单(启停按钮就靠它) |

留空的路径表示「自动探测」——比如任务台会自己在 PATH 里找 claude 和 dsh(并且能从 npm 的 shim 推出真正的 claude.exe)。

从手机访问(以 Tailscale 为例)

tailscale serve --bg 443 http://127.0.0.1:8080 # 门户:https://<机器名>.<tailnet>.ts.net/ tailscale serve --bg --tls-terminated-tcp=8082 tcp://127.0.0.1:8082 tailscale serve --bg --tls-terminated-tcp=8083 tcp://127.0.0.1:8083

请用 HTTPS 转发,不要用裸 TCP:浏览器只在安全上下文里提供 crypto.randomUUID 这类接口。

目录结构

src/ config.js、serve-menu.js(门户)、serve-files.js、serve-term.js、jobs.js、markdown.js src/public/ index.html(卡片由服务端按配置注入)、icon.svg scripts/ install.ps1、start.js、start-vscode.js、diagnose.js、scan.mjs、.bat/*.vbs、shell.ps1 integrations/ dsh-patch/apply.mjs —— 可选的 DSH 本地适配 test/ smoke.mjs data/ 运行时产物(日志、任务记录)—— 已被 gitignore

排错

见 docs/TROUBLESHOOTING.md。最常见的三个:

- .ps1 里的中文导致解析报错 —— PowerShell 5.1 会把无 BOM 的 UTF-8 当 ANSI 读。含非 ASCII 的脚本必须存成 UTF-8 带 BOM;.bat/.vbs 请只用 ASCII。
- 网页终端连上却没有任何反应 —— 公钥没登记给 sshd(Windows 上就是上面那个 administrators_authorized_keys 的坑)。
- 端口看着被占用,但服务其实是死的 —— Windows 上 Tailscale 的转发会让 tailscaled 也监听同样的端口号。本项目判断服务身份靠的是「回环监听地址 + 进程名」,从不只看端口。

许可

MIT —— 见 LICENSE。本项目与 DeepSeek、Anthropic、微软没有隶属关系,文中出现的产品名仅用于说明兼容性。
预览分享卡片长什么样 ↓Zheyi-D/dsh-pocket
分享 · DeepSeek Harness Hub
Zheyi-D/dsh-pocket

用手机远程操作本机 DSH 并管理整台电脑

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