远程环境管理 std-microblock/dsh-plugin-environments
DeepSeek HarnessDSH 环境插件:远程和本地环境一站搞定。
30.7/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/10 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查未通过:缺少 main/exports/bin 入口声明;engines.node 要求 >=24,不满足 Node 22.19.0;仓库 package.json 标记 private,未发布到 npm,需从源码安装。以下命令仍可尝试,但可能失败。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add std-microblock/dsh-plugin-environments该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · other
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 25 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装缺少 main/exports/bin 入口声明;engines.node 要求 >=24,不满足 Node 22.19.0;仓库 package.json 标记 private,未发布到 npm,需从源码安装
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包dsh-plugin-environments-monorepo(未发布到 npm,仅可源码安装)
✗Node 引擎要求 >=24 · 基线 Node 22.19 不满足
✓dsh CLI 依赖未声明 dsh 版本约束
✗入口文件缺少入口声明
源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/9 17:36:02
安全扫描自动 · 静态分析源码v2.7.0🟢 扫描:未发现敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。
发起外部网络请求
查看扫描证据(共 4 处,展示前 4 条)
- 发起网络请求packages/client/src/api.ts:29
const response = await fetch(ROUTE, { - 发起网络请求packages/plugin/src/host-api.ts:120
fetch(request: Request): Promise<Response> - 发起网络请求packages/protocol/src/client.ts:232
return (await this.request(op, args, payload, signal)).result - 发起网络请求packages/protocol/src/websocket.ts:196
const req = mod.request({
扫描于 2026/11/3(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
README
由 DeepSeek 最新模型翻译生成dsh-plugin-environments
给 DeepSeek Harness(dsh)的环境管理插件。它让智能体可以使用别的设备,例如本机、自己部署的服务器、SSH 主机、Android 真机或模拟器,以及本机上的 Windows 受限测试账户。每个环境有两种用法:
- 挂载:在创建会话时由人选择。会话里内置的 read / write / edit / read_image / glob / grep / bash(Windows 环境为 pwsh)会直接在环境中执行,AGENTS.md 和项目技能也从环境中读取。不挂载时会话就在本机(运行 dsh 的电脑)上运行,这是默认情况,也是开销最小的情况。
- 借用:智能体在需要时调用 env_borrow,借到后获得一组以环境别名为前缀的工具(例如 pixel__exec、pixel__install_apk),用完调用 env_return 归还,这些工具随即消失。
每次占用(挂载或借用)分为无界面(headless:文件、命令、进程、隧道,以及 install_apk、app、logcat 等不操作屏幕的工具)和 GUI(另外可以截图、键鼠输入、操作界面元素和窗口)两种方式。无界面占用可以多个会话同时进行,GUI 同一时间只属于一个会话,详见下文“借用”。
展开完整文档(README 剩余 1 节)
dsh-plugin-environments
给 DeepSeek Harness(dsh)的环境管理插件。它让智能体可以使用别的设备,例如本机、自己部署的服务器、SSH 主机、Android 真机或模拟器,以及本机上的 Windows 受限测试账户。每个环境有两种用法:
- 挂载:在创建会话时由人选择。会话里内置的 read / write / edit / read_image / glob / grep / bash(Windows 环境为 pwsh)会直接在环境中执行,AGENTS.md 和项目技能也从环境中读取。不挂载时会话就在本机(运行 dsh 的电脑)上运行,这是默认情况,也是开销最小的情况。
- 借用:智能体在需要时调用 env_borrow,借到后获得一组以环境别名为前缀的工具(例如 pixel__exec、pixel__install_apk),用完调用 env_return 归还,这些工具随即消失。
每次占用(挂载或借用)分为无界面(headless:文件、命令、进程、隧道,以及 install_apk、app、logcat 等不操作屏幕的工具)和 GUI(另外可以截图、键鼠输入、操作界面元素和窗口)两种方式。无界面占用可以多个会话同时进行,GUI 同一时间只属于一个会话,详见下文“借用”。
安装
发布版本附带全部五个平台的 dsh-env-server(win32-x64、linux-x64、linux-ia32、linux-arm64、darwin-arm64),二进制以 Brotli 压缩存放,首次使用时解压到 ~/.dsh/cache/。任选一种方式安装:
1. 某个版本的发布包(GitHub Release 附件,推荐)
dsh plugin add https://github.com/std-microblock/dsh-plugin-environments/releases/download/vX.Y.Z/dsh-plugin-environments-X.Y.Z.tgz
2. release 分支:始终是最新正式版;也可以用 release-vX.Y.Z 标签固定版本
dsh plugin add github:std-microblock/dsh-plugin-environments#release
dsh plugin add github:std-microblock/dsh-plugin-environments#release-vX.Y.Z
需要指定配置时加 --profile desktop 等参数。每个 Release 还附带 SHA256SUMS,以及各平台的原始服务端二进制 dsh-env-server-X.Y.Z-<平台>.gz,用于在别的机器上运行 dsh-env-server serve。
从源码安装
pnpm install
pnpm run build # 构建 dsh-env-server(本机 + Linux musl 目标)、插件 dist/ 和 client.js
dsh plugin --profile desktop add link:G:/dsh-plugin-remote-environments/packages/plugin
插件包位于 packages/plugin(包名仍是 dsh-plugin-environments)。pnpm run build 会把服务端二进制放到 packages/plugin/bin/<platform>-<arch>/,把插件打包到 packages/plugin/dist/index.js,把界面打包到 packages/plugin/client.js;这些都是构建产物,不进入 git。pnpm run package 生成与发布版本相同的 .tgz(见 CONTRIBUTING.md)。
安装后会出现以下入口:
- 侧边栏的环境页面:管理环境、测试连接、浏览远程文件、新建远程工作区、查看和释放正在使用的环境(每个占用显示无界面 / GUI,环境卡片显示谁持有它的 GUI)。
- 输入框左下角的环境按钮:显示当前会话在哪里运行——没有挂载时显示“本机”,挂载时显示环境名称(持有 GUI 时带 GUI 标记)。会话开始前可以在“本机”和其他环境之间选择(选环境时再选一个目录),挂载失败时查看原因并重试;勾选本会话可借用的环境,把勾选结果保存为该工作区的默认值,或清除工作区的默认值。
- 侧边栏工作区列表:远程工作区在行尾显示它绑定的环境名称,环境不可用时(例如 adb 设备未连接、服务器连不上)显示红点,独占环境被占用时显示橙点。
内置的 local 环境(界面上叫“本机(独立进程)”)是在本机上单独启动的 dsh-env-server 子进程,和其他环境一样可以借用或挂载;它和“本机”不同:“本机”是不挂载、直接在 dsh 所在电脑上运行。
环境类型
| 类型 | 连接方式 | 能力 |
| 本机 local | 把随插件附带的 dsh-env-server 作为 stdio 子进程启动 | 全部能力:文件、进程/PTY、TCP/UDP 正反向隧道、glob/grep、截图、键鼠输入 |
| 环境服务器 server | 连接到目标机器上运行的 dsh-env-server serve,地址可以是 host:port、tcp://、ws://,或经 TLS 反向代理的 wss://。用共享密钥做双向认证并加密(见下文“网络连接”) | 同上;截图和输入目前仅限 Windows 目标 |
| SSH ssh | 使用 ssh2 连接,支持密码、私钥或 ssh-agent。自动识别远端系统和架构(Linux x64/ia32/arm64、macOS arm64、Windows x64 OpenSSH),按内容哈希只上传一次对应的 dsh-env-server(~/.dsh-env/bin/,目录权限 0700);连接时才启动、断开即退出,数据走 SSH 端口转发。SSH 服务端禁止转发时退回 exec 通道的 stdio;没有合适的二进制时退回 SFTP + exec + TCP 转发 | 完整能力,或退回后的基础能力 |
| 反向连接 reverse | 目标机器运行 dsh-env-server connect 主动连到插件开启的 TCP / WebSocket 监听,适合目标机器没有公网地址的情况;断线后自动重连 | 与环境服务器相同 |
| Android adb | 调用 adb CLI。adb devices 发现的设备会自动列出,可以一键加入列表 | 文件(push/pull/exec-out)、shell(含 PTY)、TCP forward/reverse、截图、输入,以及 install_apk、app、ui_dump、logcat |
| Windows 账户 winuser | 创建一个本地标准账户(需要管理员确认),密码用 DPAPI 加密保存。连接时用 CreateProcessWithLogonW 以该账户身份在当前交互桌面上启动 dsh-env-server | 全部能力。该账户启动的图形界面程序会显示在当前桌面,智能体可以截图并操作 |
网络连接
server 和 reverse 两种环境的连接可能经过公网,所以总是先建立一层安全通道:双方用每个环境独立的高熵共享密钥互相认证,再派生出两个方向各自的 AES-256-GCM 密钥加密全部流量。密钥本身从不在网络上传输,也不需要证书。细节见 docs/protocol.md。
| 谁有公网地址 | 做法 |
| 目标机器 | 在目标机器上运行 dsh-env-server serve --listen 0.0.0.0:7461 --token-file token.txt(或 --listen ws://0.0.0.0:7461/dsh-env),然后添加“环境服务器”并选择“直连”,填入地址和 token.txt 里的密钥 |
| dsh 这台电脑 | 添加“环境服务器”并选择“反向连接”。没有开启任何监听时,保存会自动开启 TCP 监听(也可以在“本机监听”里改用 WebSocket)。保存后会显示一次可以直接复制的命令(Linux/macOS 和 PowerShell 两种),在目标机器上运行即可 |
- 密钥通过文件(--token-file)或标准输入(--token-stdin)交给 dsh-env-server。--token 会出现在其他用户可见的进程列表里,不建议使用。
- 需要 TLS 时,把 ws:// 监听放在 nginx、Caddy 等反向代理之后,插件一侧直接填 wss:// 地址;dsh-env-server 本身不带 TLS。
- 反向监听默认端口是 TCP 7462、WebSocket 7463(路径 /dsh-env),默认关闭。也可以在插件配置里用 reverse: { tcp: { enabled, host, port }, ws: { enabled, host, port, path }, publicHost } 预设;在界面里改过之后以界面为准。
- 重新生成密钥会立即断开该环境现有的反向连接。
远程工作区(挂载)
在环境页面或环境卡片上选择“新建远程工作区”,在弹出的远程文件浏览器里选好目录。插件会在 ~/.dsh/env-mounts/ 下创建一个占位目录,并把它注册成普通工作区;在这个工作区里新建的会话(包括它的子智能体)都会自动挂载到该环境。挂载期间:
- 文件工具和 shell 工具在环境中执行。宿主机上的路径会映射到环境里的根目录,模型看到的工作目录就是环境里的真实路径。
- 环境里的 AGENTS.md / CLAUDE.md 会作为项目指令注入。
- 项目技能(.agents/skills、.dsh/skills)从环境中发现和读取。
- 只能在宿主机上运行的工具会被隐藏,包括 terminal、lsp、load_workspace_dependencies,以及与环境系统不匹配的那个 shell 工具。
- 挂载会占用该环境的一个租约,默认是无界面方式:别的会话仍可以无界面借用它,也可以拿走它的 GUI。环境设置里的“挂载方式”(或插件配置 mountMode: 'gui')可以让挂载同时占用 GUI:GUI 空闲时挂载会话直接获得截图等工具(<别名>__screenshot 等),GUI 被别人占用时挂载退回无界面。挂载会话随时可以用 env_borrow { environment: <挂载的环境>, gui: true } 拿 GUI(可排队),用 env_return 还回 GUI,挂载本身不受影响。会话恢复时按上次的状态重新拿 GUI(拿不到就保持无界面)。
- 不允许无界面并行的(独占)环境在挂载期间不能被别的会话借走。
- 子智能体继承父会话的挂载:无论父会话是在远程工作区里,还是单独选择了环境,它的子智能体都挂载到同一个环境、同一个目录,并且共用父会话的租约,不会再占一个租约(所以独占环境不会因为父子会话互相等待而卡住)。子智能体可以拿这个共用租约的 GUI;子智能体结束不会影响父会话的挂载。父会话的挂载断开时,子智能体同样被下面的规则拦下。父会话不挂载时,子智能体也在本机运行。
也可以不建工作区,在普通会话开始前通过输入框里的“环境”按钮选择一个环境和目录。会话一旦开始,运行环境就不能再更改。
挂载失败时对话不会继续。 远程工作区的会话、单独挂载了环境的会话以及它们的子智能体,如果挂载失败(环境不可用、目录不存在、独占环境被占用等),或挂载中途断开,插件不会让它退回宿主机上运行:
- 每一步请求模型之前,插件先重新尝试挂载;仍然失败时,这一轮直接以错误结束(“环境 X 挂载失败:<原因>”),模型不会被调用,这条消息需要在环境恢复后重新发送。
- 挂载缺失期间,这个会话的所有工具调用都会被拒绝,不会读写宿主机上的占位目录,也不会在宿主机上执行命令。
输入框里的「环境」按钮显示红点和失败原因,可以点「重试」重新挂载;环境恢复后直接发送消息也会自动重新挂载。
工作区与环境的绑定
只有远程工作区绑定环境:创建时选择的环境和目录,不能更改,其中的会话都挂载到它上面。其他工作区里的会话默认在本机运行,可以在会话开始前通过「环境」按钮选择别的环境。一个会话最终在哪里运行,按以下顺序决定:
1. 子智能体:跟随父会话(共用父会话的挂载);
2. 会话自己的选择(在「环境」按钮里选的环境);
3. 远程工作区绑定的环境;
4. 都没有时在本机运行。
工作区的「默认可借用列表」(在「环境」按钮里点「设为此工作区默认」)只影响借用:会话自己的列表优先,其次是工作区的列表,都没有时可以借用全部环境。
侧边栏的状态点来自轻量检查,不会建立完整连接:本机始终可用;adb 设备看 adb devices 里是否在线;环境服务器和 SSH 尝试连接它的 TCP 端口;正在被会话使用的环境直接视为可用。结果缓存约 15 秒,侧边栏大约每 10 秒刷新一次。
借用
| 工具 | 作用 |
| env_list | 列出本会话可借用的环境、它们的状态(谁在用、谁持有 GUI、排队情况),以及本会话已经持有的环境和方式 |
| env_borrow | 借用一个环境,默认无界面;gui: true 同时拿 GUI。对已持有的环境(包括挂载的环境)再调用一次:gui: true 升级为 GUI,gui: false 交回 GUI。wait: true 时环境或 GUI 忙会排队(可设超时) |
| env_return | 归还环境,同时关闭通过它开启的进程和隧道;gui_only: true 只交回 GUI、保留无界面租约。对挂载的环境只交回 GUI,挂载保留 |
| env_transfer | 在本会话工作区和已借环境之间、或两个已借环境之间复制文件或目录,位置写成 别名:/路径 |
本会话可借用的环境会写进 system prompt(每个环境一行,形如 - pixel: Pixel 8 [adb, Android 14 测试机],含名称、类型和描述),模型不必先调用 env_list 就知道有哪些可选;实时状态(谁在用、谁持有 GUI、排队情况)仍然只在 env_list 里给出,这样租约变化不会反复改写 system prompt。会话自己的可借用列表变化时(在工作区里改默认值或调整本会话的勾选)这段文字随之更新;没有可借用环境时不出现。
借到之后的工具(无界面和 GUI 都有):<别名>__exec、read_file、read_image、write_file、edit_file、list_dir、glob、grep、process_start / process_io / process_kill(可交互的长时间进程)、tunnel(to_env / from_env,TCP 或 UDP)。
其他工具按环境能力出现;标为 GUI 的只在持有 GUI 时出现,升级后出现、交回 GUI 后消失:
| 工具 | 方式 | 环境 | 作用 |
| screenshot | GUI | Windows、Android | 截图并缩小到长边 ≤ max_size(默认 1280),之后所有坐标都按这张图的像素计算;region 放大局部,window 截单个窗口,display 选显示器,可选 JPEG 和鼠标指针 |
| input | GUI | Windows、Android | 按顺序执行动作:点击(双击、右键、修饰键)、移动、拖动、长按、滑动、滚动、输入 Unicode 文本、组合键、按住键、等待;element: N 直接指向 ui 列出的元素;可附带操作后截图 |
| ui | GUI | Windows、Android | 列出界面元素(Android uiautomator / Windows UI Automation):编号、类型、文字、id、中心坐标、大小、状态;可按文字查找并点击、设置文本、滚动、展开、切换等 |
| windows | GUI | Windows | 列出顶层窗口,聚焦、最小化、最大化、还原、关闭、移动窗口 |
| device | GUI | Android | 设备信息(型号、系统、屏幕尺寸/密度/方向、前台应用、输入法、亮屏/锁屏、电量),唤醒、熄屏、解锁(无密码时)、打开通知栏/快捷设置 |
| app | 无界面 | Android | 启动、停止、清除数据、卸载、查看信息、列出应用、当前前台 Activity、打开 URL、am start 任意 Intent |
| install_apk | 无界面 | Android | 从工作区或其他已借环境安装 APK |
| logcat | 无界面 | Android | 读取最近的日志,可按文字和级别过滤 |
Android 上 ASCII 文本走 input text;非 ASCII(中文、emoji 等)走剪贴板粘贴:插件把几 KB 的 dsh-clipboard.jar 推到设备 /data/local/tmp,以 shell 身份用 app_process 运行它写入系统剪贴板,再发一次 KEYCODE_PASTE,输入法全程不动(input text 和 scrcpy 的文本注入都只能生成 KeyCharacterMap 认得的字符,中文会被直接丢掉)。粘贴后会把设备原来的剪贴板恢复回去。只有设备不允许 app_process(或 Android 7 以下)时才回退到 ADB Keyboard IME;两者都不可用时才明确报不支持。个别禁止粘贴的输入框仍需 ADB Keyboard。
无界面与 GUI 的占用规则
每个环境有一个设置“无界面使用可并行”(headlessParallel,默认开启):
| 环境设置 | 新的无界面租约 | 新的 GUI 租约 / 升级为 GUI |
| 可并行(默认) | 总是立即获得,不受 GUI 持有者影响 | 只要有别的租约持有 GUI 就要等待(或 wait: false 时立即失败) |
| 不可并行(独占) | 只要有任何租约(任一方式)就要等待 | 同左;持有唯一租约的会话升级为 GUI 立即生效 |
- 等待的请求按先后顺序(FIFO)排队;GUI 持有者交回 GUI、归还或断开后,队首的请求获得 GUI。正在建立连接的请求已经算作占用,不会被后来者插队。
- 挂载和借用遵循同一套规则。挂载默认无界面,可以按环境或在插件配置里改为 GUI(见“远程工作区(挂载)”)。
- 同一会话对同一个环境只持有一个借用;对挂载的环境借用 GUI 不会新开租约,而是在挂载的租约上拿 GUI。
- 会话恢复时,插件会尝试重新借回上次持有的环境,并按上次的方式拿 GUI;GUI 已被别的会话占用时先以无界面方式借回。
每个会话能借哪些环境:默认是全部环境;工作区设置了默认列表时继承它;会话也可以随时单独修改。
从旧版本升级:旧版本的“独占使用”(exclusive)设置在加载时自动迁移。Android 和 Windows 账户环境以前默认独占,是为了保护屏幕,现在由 GUI 的独占来保证,所以它们迁移为“无界面可并行”;其他类型上手动开启过“独占使用”的环境迁移为“不可并行”。
生命周期
- 每个连接、租约和隧道都绑定在 Cordis 的 fiber/scope 上,智能体销毁、归还或插件卸载时会自动清理。
- dsh-env-server 在连接断开时会结束它启动的所有进程树(Windows 用 Job Object,Unix 用进程组),并关闭监听和套接字。
- SSH 环境的服务端只在连接期间存在:它以 --lifeline --exit-idle 启动,SSH 通道关闭(主动断开、插件卸载或网络中断)或它唯一的会话结束时立即退出,不会留下孤儿进程。每次启动都使用新的随机密钥,经标准输入传入。
Windows 账户环境(winuser)
在环境页面创建账户后,插件会:
1. 创建(需要管理员确认,弹出 UAC 授权):用 NetUserAdd 建一个本地标准用户,注释为 dsh-env managed,随机密码用当前用户的 DPAPI 加密后存到插件数据目录的 winusers/<账户>.secret。可选地给若干目录授予该账户“修改”权限(icacls /grant <账户>:(OI)(CI)M,继承到已有的子文件)。
2. 连接:把服务端二进制复制到 %ProgramData%\dsh-env\dsh-env-server-<内容哈希>.exe(插件自带的二进制通常在当前用户的配置目录里,其他账户进不去;ProgramData 下的文件继承 “Users:读取和执行”)。然后以当前用户身份运行 dsh-env-server winuser launch --supervise,它用 CreateProcessWithLogonW(LOGON_WITH_PROFILE) 以该账户身份启动 serve --listen 127.0.0.1:<随机端口> --token <随机令牌> --once --cwd ~:
- 首次登录时 Windows 会创建账户的配置文件(C:\Users\<账户>,如果同名目录已存在则是 C:\Users\<账户>.<计算机名>);USERPROFILE、APPDATA、TEMP、HKCU 都是该账户自己的。
- 默认工作目录是该账户的主目录;环境配置里的 cwd 必须是该账户能进入的目录(例如授予过权限的工作区),否则启动会报“目录名称无效”。
- 进程默认在当前交互会话的 WinSta0\Default 桌面上运行(不指定桌面时由 Secondary Logon 服务授予访问权限),所以它启动的窗口程序会显示在当前桌面上,截图和键鼠输入作用于同一块屏幕(坐标是物理像素)。服务端自己没有控制台窗口。
- 服务端被放进由启动器持有的 Job Object(KILL_ON_JOB_CLOSE)。启动器作为插件的子进程一直运行,环境关闭、连接断开或 dsh 退出(启动器的 stdin 关闭)时,以该账户身份启动的整棵进程树都会被结束。
3. 删除(需要管理员确认):结束该账户的所有进程,删除账户,再用 DeleteProfileW 删除它的配置文件(配置文件卸载需要一点时间,会重试约 15 秒;删不掉时账户仍会删除,并返回警告)。
每个账户的桌面:三种模式
环境设置里的“独立桌面 / 独立会话”决定该账户的窗口在哪里:
| 模式 | 窗口在哪 | 鼠标指针 | 输入方式 | 需要什么 |
| 共用(默认) | 你的桌面 | 你的指针 | SendInput | — |
| 独立桌面 | 同一会话内的 WinSta0\dsh-<账户> | 合成指针 | 窗口消息 | — |
| 独立会话 | 该账户自己的 Windows 会话 | 真正的指针 | 真实键鼠 | TermWrap |
- 独立桌面:winuser launch --desktop dsh-<账户> 由启动器创建并持有该桌面(桌面对象是引用计数的,最后一个句柄关闭就销毁),账户的一切进程都落在上面,窗口不会出现在你的屏幕里。因为非活动桌面没有屏幕表面(GetDC(NULL)+BitBlt 会是黑的),截图改成枚举该桌面的窗口、逐个 PrintWindow(PW_RENDERFULLCONTENT) 再按 z 序合成;输入走窗口消息(SendInput 在非输入桌面上被拒绝),指针位置由服务端记录并画进截图。
- 独立会话:真正独立的桌面必须是一个独立的 Terminal Services 会话,而客户端 SKU 只允许一个会话、家庭版还不开放 RDP 主机。环境页面会探测这台机器能不能用,并列出缺什么;缺 TermWrap 时提供一键安装(明文 MIT 二进制随包分发,安装前先把 %ProgramFiles%\RDP Wrapper\ 加入 Defender 排除项——微软对这个家族有官方特征 HackTool:Win64/RDPWrap!MTB)。装完不需要重启电脑:安装会自己重启 TermService/UmRdpService,服务启动时 SCM 会重新读 ServiceDll,补丁随即生效(只有服务停不下来/起不来时才回退到提示重启)。之后连接时由服务端自带的无界面 RDP 客户端(IronRDP,crates/dsh-env-server/src/rdp.rs)把该账户登进自己的会话,并把连接一直挂着(断开的会话不再渲染,截图会变黑);登录前会把该账户自己的 Winlogon\Shell 指向 <服务端> serve … --no-console,于是服务端本身充当那个会话的 shell,账户里不需要注册任何自启动,也不会在账户桌面上留下控制台窗口。不用 mstsc:它常常无视 .rdp 里的密码弹凭据框,窗口还会出现在你的桌面上,失败时也没有任何可读的错误。
- 实时预览:两种模式都可以在环境卡片上点查看桌面,看到该桌面的实时画面(约 4 fps)。有活动会话时预览复用那条连接;独立会话模式下没有活动会话时不会为了截图而新开一个会话,而是提示先去启动会话。
限制:
- 提权由插件自带的 dsh-env-server elevate 完成:它用 ShellExecuteEx 的 runas 动词让 Windows 弹出 UAC 授权,再等被提权的进程结束。不用 gsudo 之类的第三方工具——它们靠替换调用进程的令牌来提权,而宿主机给子进程的是重定向控制台(没有自己的控制台),会以 “Failed to substitute token” 失败;需要管理员权限的每一步(建账户、授权目录、装 TermWrap)都会各自弹一次 UAC。
- 该账户是标准用户,环境里的程序不能提权:直接启动要求管理员权限的程序会失败(错误 740 “请求的操作需要提升”);通过 ShellExecute 提权(例如 Start-Process -Verb RunAs)会在当前桌面弹出索要管理员凭据的 UAC 窗口,需要坐在电脑前的人处理。
- 同一时间只有一个交互桌面,该账户的窗口和当前用户的窗口在同一个桌面上,互相可见、可操作;锁屏时截图和输入可能失败。
- 端口只监听 127.0.0.1,但同一台机器上的其他本地用户也能连接这个端口,靠随机令牌认证;令牌出现在服务端的命令行里(只有该账户本身和管理员能读到)。
- 账户能读取所有对 “Users” 开放的位置(例如 C:\Users\Public、大多数程序目录),不能读写当前用户的配置目录,除非显式授权。
- 依赖 Secondary Logon 服务(seclogon);禁用该服务,或用组策略禁止该账户「本地登录」时,会给出对应的错误说明。
- 密码只能由创建账户的那个 Windows 用户解密(DPAPI);换了用户,或数据目录丢失后,需要删除并重建账户。
Windows 输出编码
中文 Windows 的控制台默认代码页是 936(GBK),cmd、ping、net、Windows PowerShell 等写进管道的文字原本会被当成 UTF-8 解码成乱码。现在:
- proc.spawn 默认(encoding: 'utf8')让子进程运行在 UTF-8 控制台上(服务端通过 dsh-env-server __utf8-console 包装一层,调用 SetConsoleCP/SetConsoleOutputCP(65001)),command 模式还会把 Windows PowerShell 的 $OutputEncoding 设为 UTF-8;仍不是 UTF-8 的输出行按 OEM 代码页转码。这样 GBK 以外的字符(emoji、韩文等)也不会变成 ?。副作用:在 UTF-8 控制台上,ping、net、Windows PowerShell 等系统工具会输出英文提示。
- encoding: 'auto' 保持控制台原来的代码页(提示保持中文),只把非 UTF-8 的输出行按 OEM 代码页转成 UTF-8;encoding: 'raw' 原样转发字节(二进制输出)。
- PTY(ConPTY)本身就输出 UTF-8,不做任何转换。
- 插件在宿主机上运行的程序(adb、提权助手)的输出同样按「UTF-8 优先,否则 OEM 代码页」解码;进程输出按流解码,多字节字符跨数据块时不会被截断。
详见 docs/protocol.md 的 proc.spawn 一节。
协议
文档见 docs/protocol.md:
- 帧格式:长度前缀,JSON 头加二进制负载。
- 请求和响应可以并发、可以取消。
- 通道带 1 MiB 的信用窗口做流控,用于进程标准输入输出、文件流和网络隧道。
- 有心跳机制。
开发
这是一个 TypeScript(strict)pnpm monorepo,目录结构和约定见 CONTRIBUTING.md。
pnpm install
pnpm lint && pnpm typecheck # ESLint(type-aware)+ tsc
pnpm test # 协议单元测试(安全通道、WebSocket)+ 插件集成测试:env-server、ssh、反向连接、adb(模拟设备)、租约、挂载映射
pnpm build:server # cargo 构建 crates/dsh-env-server,并放到 packages/plugin/bin/
pnpm build:plugin # packages/plugin/dist/index.js
pnpm build:client # packages/plugin/client.js
pnpm run package # 发布包 out/dsh-plugin-environments-<版本>.tgz + SHA256SUMS(本地缺少 macOS 二进制时加 --allow-missing)
crates/dsh-env-server 是 Rust 写的 dsh-env-server,子命令有 serve、connect、stdio、elevate、session …、winuser create|delete|list|launch|grant|session。命令行用 clap,glob/grep 基于 ripgrep 的 ignore / globset / grep-* 库;WebSocket 和安全通道是手写的小实现,加密只依赖 RustCrypto 的 aes-gcm、hkdf、hmac、sha2 / sha1。Linux 静态二进制通过 rust-lld 交叉编译,不需要额外的工具链。
已知限制
- 截图和键鼠输入在 Linux/macOS 的 dsh-env-server 上暂不支持。Android 的截图和输入走 adb。
- 走纯 SSH(未运行 dsh-env-server)时只有 TCP 隧道;远端是 Windows 时也不支持 grep。
- 挂载会话中,GUI 侧栏的文件树、diff 摘要和 @ 文件补全仍然显示宿主机上的占位目录。
- 挂载失败而被拦下的那条消息不会进入会话记录(DSH 在进入这一步之前拒绝它),需要在环境恢复后重新发送。
- DSH 没有为工作区行提供插件扩展位,侧边栏里远程工作区的环境名称是按工作区行的 data-row-key 属性插入到页面里的。DSH 改变侧边栏结构后,这些装饰可能不再显示,但不会影响其他功能。
- 同一台 Windows 机器上同一时间只有一个交互桌面,共用模式下 Windows 账户环境的程序和当前用户共用这个桌面(其他限制见上面的「Windows 账户环境」)。
- GUI 的独占按环境计算:指向同一块屏幕的两个环境(例如本机上的 local 环境和 Windows 账户环境)可以各自被一个会话持有 GUI。
- Windows 账户的独立桌面模式没有真实指针:一个会话只有一个输入桌面,其他桌面上的 SendInput/SetCursorPos 会被拒绝,所以那里的键鼠只能作为窗口消息投递(依赖原始输入、低层钩子或 GetAsyncKeyState 的程序可能不灵),指针位置由服务端自己记录并画进截图。
- 独立会话模式依赖第三方未签名补丁(TermWrap,MIT):微软 Defender 会把它识别为 HackTool,Windows 更新后可能需要重装;客户端 SKU 同时多会话也不在 Windows 客户端授权范围内,是否使用请自行判断。详见 docs/session-mode.md。
- Windows 上默认的 UTF-8 模式下,proc.spawn 返回的 pid 是 __utf8-console 包装进程的 pid。
- 安全通道只基于共享密钥,没有前向保密:密钥泄露后,录下的旧流量可以被解密。发现泄露请在界面里重新生成密钥(反向连接)或更换 token 文件(环境服务器)。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
std-microblock/dsh-plugin-environments
DSH 环境插件:远程和本地环境一站搞定。
相关插件 · 其他
模型破甲清洗YuJunZhiXue/dsh-purge
⚔️ DeepSeek Harness 网络安全红队工具dsh-purge
★ 16,148已汉化DeepSeek 客户端
73
女娲蒸馏alchaincyf/nuwa-skill
输入名人名字,提炼其思维模型与决策方式供你调用
★ 37,308已汉化DSH
72
逆向分析桥接Fanqi89/dsh-rea
REA(Reverse Engineer Anything)MCP 桥接,用来把 REA 逆向工具接入 DSH 插件
★ 51已汉化DSH
72
语音女友beiyege-01/dsh-voice-ai-girlfriend
语音 AI 女友Voice AI girlfriend for DeepSeek Harness:Whisper…
★ 888已汉化DSH
71.6
红队越狱测试套件Minglink/dsh-infinite-gen-5
DeepSeek v4.1 flash 逆向工具无限五代 求 Star 收藏 ⭐欢迎大家提交项目的改进
★ 3,759已汉化DSH
71.4
协同办公空间dream-num/univer-workspace
一个让人类与 AI Agent 共同创作、协作和审阅的开源 Office 工作空间。
★ 2,266已汉化DSH
70.7
这是你的仓库?认领条目