返回项目列表
公开项目 2026 DeepSeek Harness 远程工作区

dsh-ssh

把 DeepSeek Harness 接到任意 SSH 主机、WSL 发行版或 Docker 容器:远程常驻服务加本地原生界面,关掉客户端任务也不停。

远程通道
SSH · WSL · Docker
目标版本
DeepSeek Harness 0.2.1-rc.5
常驻方式
systemd · setsid
远程监听
仅 127.0.0.1
01Highlights

项目要点

  • 三种远程通道:SSH 主机、WSL 发行版、Docker 容器;SSH 支持密码、私钥、passphrase、agent 和 keyboard-interactive。
  • 远程 dsh 以常驻 systemd 服务(或 setsid 会话)运行,关掉本地客户端、断开 SSH 都不会停;重开客户端自动接回同一个进程。
  • 一键创建:通道 → Node ≥ 22(缺失时自动下载便携版)→ 安装 @deepseek-ai/dsh → 同步凭据 → launcher → systemd/setsid → 健康检查。
  • 状态面板给的是实测值:CPU 用 /proc/<pid>/stat 做 0.5 秒差分,RSS 读 /proc/<pid>/status,不用生命周期平均值凑数。
  • 连接向导按 ZCode 3.17.2 的渲染结构与设计令牌 1:1 重建,设备、连接、目录三步,支持 SSH config 导入与后台连接。
  • 远程 Web 只绑 127.0.0.1,不开局域网端口;主机密钥走 TOFU 校验。
02Story

细节

这个项目解决的是「远程工作区」的常驻问题:本地客户端只负责选设备、显示聊天和监控状态,真正的 agent、工具和文件都跑在远程主机、WSL 或 Docker 里。只要远程服务在,关掉客户端甚至断开 SSH,任务都继续跑。

工程上的难点是把三种完全不同的通道统一成一套命令层:SSH 的密钥、代理与交互式认证,WSL 的发行版与用户切换,Docker 的容器命名与存活检查,最后都收敛到同一套「准备 Node 运行时 → 安装 dsh → 起服务 → 健康检查」的流程;状态监控也不做伪数据,全部从 /proc 采样。

03Source

源码

GitHub 仓库的元信息、README 与最近提交会随部署同步;源码仍在 GitHub 查看。

文件
1 个
目录
0 个
默认分支
main
最近更新
2026-11-04
最近提交
2026-11-04 · d69e536
Initialize repository
README.md

dsh-ssh-remote

ZCode-style remote workspaces for DeepSeek Harness (dsh): SSH, WSL and Docker.

The remote dsh runs as a persistent systemd service (or setsid session) inside the SSH host, WSL distribution or Docker container, and remote sessions are executed by a detached dsh --profile headless runner there. The local app selects the workspace, shows the native chat, and monitors status; there is no local console proxy. Closing the local app does not stop the remote dsh.

Target: DeepSeek Harness Desktop 0.2.1-rc.5. Validated end-to-end against 203.0.113.10 (AlmaLinux 9.5).

Screenshots

The Add-connection dialog is a 1:1 rebuild of ZCode's renderer components (OVn / xVn / yVn / nVn / Smt / rmt / hmt / Cmt): the same DOM structure, spacing, type scale and ZCode design tokens (light palette by default, dark palette under body[data-ds-dark-theme]), with device-first interaction:

  • saved device: click connects immediately; edit it from Settings;
  • recent workspace chips under each device open the native workspace in one click;
  • directory step: connected banner, device rename, recent paths and Will open …;
  • minimize is available on every step; connecting/creating continues in a ZCode-style background card.
New connection (Settings → Remote devices) SSH config import
Create project (device picker) Select folder

The three surfaces — new connection, create project and the centered folder picker — are rebuilt from the 3.17.2 renderer with the same DOM structure, class values, type scale and copy as ZCode. The screenshots use documentation-range addresses (192.0.2.0/24, 203.0.113.0/24).

Features

Area What it does
Targets SSH (password / private key / passphrase / agent / keyboard-interactive), WSL distributions on Windows (wsl.exe --exec bash -lc, default or named distro/user) and Docker containers (docker exec -i ... sh -lc, name/id/prefix, must be running)
SSH hosts TOFU host-key check; connection test with latency and remote Node detection
Add connection 1:1 ZCode device flow: wizard steps 选择设备 / 连接 / 选择目录, 已保存的设备, SSH config 中的 Host, WSL 发行版 and 运行中的容器 sections, plus 新建 SSH 连接 / 手动输入 WSL / 手动输入 Docker; the settings step uses ZCode's exact per-kind forms (WSL distribution datalist + Linux user hints/root warning; Docker select/manual picker); minimize is available on every step and parks the wizard in a ZCode-style background card
Recent workspaces clicking a recent path opens that native workspace directly, including from the status panel; a stopped service is started in the background
Background connect both connecting and workspace creation can continue in the background; a bottom-right pill shows progress and opens the workspace on completion, and reopening it resumes the wizard
SSH config import parses ~/.ssh/config Host blocks and fills host, port, username and IdentityFile
One-click create the connect phase installs/reuses the shared dsh runtime; the directory step then only starts the service. Full chain: channel (SSH/WSL/Docker) → Node ≥ 22 (portable download when absent) → @deepseek-ai/dsh → credentials → launcher → systemd/setsid → health check
Persistence systemd Restart=always (system unit, or user unit + linger) or setsid nohup + @reboot cron. Survives SSH disconnect and local app exit
Status monitor running / starting / stopped / error / unreachable; PID, uptime, RSS, CPU, HTTP status, port, last check. CPU is sampled from /proc/<pid>/stat over 0.5 s and RSS from /proc/<pid>/status (no lifetime-average or fabricated values)
Native workspace each remote workspace is projected into the native sidebar; its agent is bridged to a detached remote headless session; device chips and the status panel select that same native row
Lifecycle start, stop, restart, logs (journalctl/tail), remove (service + runtime dir only; project dir kept)
Credentials optionally copies local $DSH_HOME/.credentials.yaml (0600) into each remote workspace's own DSH home
Legacy import imports hosts from ZCode's ~/.dsh/dsh-ssh.json on first load

The local side stays a monitor and chat surface: the agent process, tools and files live on the server.

Install

After DeepSeek Harness has started at least once:

node C:workdsh-ssh-remote\bin\install.mjs --profile desktop

The script adds a link: dependency and the bundle to ~/.dsh/profiles/desktop/package.json, then creates a junction in the profile's node_modules. Fully restart DeepSeek Harness afterwards.

Manual install: add

"dsh-ssh-remote": "link:C:/work/dsh-ssh-remote"

to dependencies, append "dsh-ssh-remote" to dsh.profile.bundles, and create

cmd /c mklink /J "%USERPROFILE%\.dsh\profiles\desktop\node_modules\dsh-ssh-remote" "C:workdsh-ssh-remote"

Use

  1. Settings → Remote devices → add a host (host/port/user/password or key) → Test connection → Save. The wizard can also create it: New SSH connection.
  2. SSH Remote sidebar → New remote workspace (or Add workspace → SSH Remote tab). Saved devices are listed first; clicking one connects immediately. Up to three recent workspace paths appear under each device — click one to open that native workspace directly. The pencil opens the SSH form for editing.
  3. Connecting shows the SSH/runtime phases and can be sent to the background; a bottom-right pill keeps updating and opens the workspace when done. The directory step shows the connected banner, device rename, recent paths and Will open ….
  4. Open workspace here creates the service, closes the wizard and selects the new native workspace. The first create installs dsh on the host (about 1 minute, ~844 MB); later creates reuse the runtime.
  5. Open workspace on the status panel, a recent-path chip, or the native sidebar row all land on the same workspace. Stop / Restart / Logs / Remove are on the status card.
  6. Close DeepSeek Harness. The remote service keeps running. Reopen and the status panel reattaches to the same PID.

Data

Local: $DSH_HOME/ssh-remote/state.json (hosts, workspaces, settings; mode 0600), known_hosts.json.

Remote: ~/.dsh-remote/runtime/dsh-<version>/, ~/.dsh-remote/workspaces/<id>/{home,logs,run}/.

The remote Web listener binds 127.0.0.1 only; no LAN port is opened.

Verified on 203.0.113.10

  • AlmaLinux 9.5, x86_64, 8 vCPU, 31 GB RAM, Node v22.23.2, systemd 252.
  • Remote install of @deepseek-ai/dsh@0.2.1-rc.5 in ~1 minute.
  • Service prints dsh web: ...?token=...; an unauthenticated HTTP request without the token returns 401 (used as readiness evidence only).
  • Real metrics verified against ps: RSS matches VmRSS in /proc/<pid>/status; CPU is a 0.5 s /proc/<pid>/stat delta, not the misleading lifetime pcpu average.
  • Interaction chain verified end-to-end: saved-device click connects (364 ms probe) → runtime prepare hits cache → directory step → create → the new native workspace opens automatically.
  • Recent-path chip and status-panel Open workspace select the same native workspace; Continue in background keeps updating the bottom-right pill, which opens the workspace when the job completes.
  • After a workspace is removed outside the UI, the startup native projection drops the orphaned anchor row (no ghost remote project).
  • After closing the local app for 10 s: same remote PID, uptime kept increasing, systemctl is-active = active.
  • Reopening the local app restored the same PID and continuous uptime.
  • Stop / start / restart, logs, and remote model listing (loaded 2 model(s)) all work.
  • root services log to journal, not a file under /root, to avoid SELinux 209/STDOUT on RHEL-family hosts.
  • SSH/WSL/Docker share one command layer; on the development machine (no WSL optional feature, no Docker daemon) the WSL/Docker discovery and error paths were verified end-to-end in the UI (当前系统未检测到可用的 WSL 环境 / 当前系统未检测到可用的 Docker 环境), including the per-kind forms and badges. Full deploy inside a live WSL distribution or container still needs a host that provides one.

Limitations

  • Linux remotes only: WSL distributions and Docker containers must provide a Linux bash/sh, Node ≥ 22 or a way to download the portable runtime (curl, wget or an existing Node).

  • WSL requires a Windows desktop with the WSL optional feature installed; Docker requires a running daemon and a running container.

  • The remote host needs access to an npm registry (default npmmirror).

  • Credentials are synced, but local model selection/settings are not yet mapped to the remote headless runner.

  • Background connect progress is in-memory: restarting the local app drops the pill (created workspaces are restored from state.json); there is no cancel button for an in-flight install/create.

  • No local mirror of remote project files; the agent and tools run inside the target.

  • Docker workspaces do not survive removal of their container; WSL workspaces survive until the distribution is terminated/unregistered.

  • WSL2 HTTP proxy auto-rewriting (ZCode maps a loopback proxy to the Windows host gateway) is not implemented; use a reachable registry/proxy inside the distribution.

Uninstall

node C:workdsh-ssh-remote\bin\uninstall.mjs --profile desktop

This removes the local link/dependency selection only. Delete remote workspaces from the UI to stop their services.

Reverse-engineering notes

See docs/zcode-ssh-reverse-engineering.md for the ZCode 3.17.2 SSHBackend / WSL / Docker backends, remote asset deployment, the 3.17.2 connect wizard (stages, install confirmation, error card, log panel), the device-management "新建连接" dialog, the "创建项目" dialog and the embedded "选择文件夹" picker, plus the rea evidence summary.

License

MIT

DeepSeek HarnessSSHWSLDockerNode.js