dsh-remote

DSH PLUGIN浏览器与联网

仓库 aide-family/dsh-remote · npm @aide-family/dsh-remote

浏览器与联网 L5 · 运行验证通过 安全审查:低风险 可信度:金 可安装插件
安装这个插件

为 DeepSeek Harness 提供 SSH 远程运维能力:发现主机、执行命令、SFTP 读写文件、持久远程 shell,并对变更操作做风险审查与审批。

一句话选型结论

按资料字段整理

dsh-remote 是浏览器与联网类的 DSH 可安装插件,验证等级 L5 · 运行验证通过,安全审查为低风险,列出 5 项功能,有可直接复制的安装命令。验证通过不等于安全:插件会读写文件、执行命令或联网,装前先到仓库确认它做了什么;涉及密钥或系统权限的,建议先在隔离环境试装。

分类浏览器与联网 收录类型可安装插件 验证等级L5 · 运行验证通过 安全审查低风险
验证等级 L5 L5 · 运行验证通过
GitHub 星标 0 复刻 0 · 未关闭 issue 0
最近更新 2026-11-11 创建于 2026-11-01
README 51.2 KB 正文体量,越大说明说明书写得越细

安装

可安装插件
在 DSH 里执行,装完用 dsh plugin list 确认已挂上;标了 L4 / L5 的命令已在沙盒里真实跑通
dsh plugin --profile web add @aide-family/dsh-remote@0.10.1
  1. 1
    确认版本与运行环境

    兼容的 DSH 版本为 0.2.2-rc.1 等 2 个,Node.js 要求 ^22.19.0 || >=24.0.0;版本不匹配时安装会报错。

  2. 2
    执行安装命令

    在 DSH 里执行上面的命令;多包仓库要注意区分具体子包名,别装错包。

  3. 3
    确认已挂载

    用 dsh plugin list 查看列表里是否出现这个插件,出现即挂载成功。

  4. 4
    试跑并检查权限

    加载后跑一个最小用例,确认它能正常工作;同时看它申请了哪些文件、命令或网络权限。

兼容 DSH 版本0.2.2-rc.1、0.2.1-rc.5版本不匹配时安装会报错
Node.js 要求^22.19.0 || >=24.0.0来自仓库 package.json 的 engines 字段
前置依赖@deepseek-ai/cordis@^4.0.5、@deepseek-ai/dsh@^0.2.2-rc.1 等 4 个需要同时安装的同级依赖
npm 包名@aide-family/dsh-remote可用 npm view 查看包信息

能做什么

5 项功能
字段来自项目仓库与公开索引,中文说明由本站标注

dsh-remote:让 DeepSeek Harness 真正操作远程服务器

  • 复用 ~/.ssh/config 主机清单
  • 远程命令执行与退出码
  • SFTP 读写与上传下载
  • 持久远程 PTY shell
  • 命令风险审查与审批

适用场景

终端命令文件读写存储

上游标签

dsh-plugindsh-pluginsdsh-remote

验证等级与安全审查

L5 · 运行验证通过
自动化流程结论,不是人工审核
验证等级L5 · 运行验证通过在 dsh 沙盒中完成安装与运行冒烟——装得上、跑得起来
安全审查低风险静态分析结论,未标注不代表已通过审查
仓库健康度活跃按仓库活跃度与最近更新时间给出
可信度金综合仓库活跃度与验证结果

上面的结论来自上游最近一次自动化验证(2026-11-12): 同一套检查会在插件发新版后重跑,页面显示的是最新一次的逐项结果。

逐项检查结果

L1 · 已找到 ✓ 通过
  • L1.0_DEFAULTED_FROM_L3 由 L3 推定 默认通过——L3 安装规范已通过(全库 L3 扫描策略)
L2 · 结构化 ✓ 通过
  • L2.0_DEFAULTED_FROM_L3 由 L3 推定 默认通过——L3 安装规范已通过(全库 L3 扫描策略)
L3 · 安装规范 ✓ 通过
  • L3.1_INSTALL_COMMAND_PARSED 安装命令已解析 方式:安装规范解析
  • L3.2_DSH_VERSION_DECLARED DSH 版本已声明 方式:DSH 版本声明
L4 · 安装已测 ✓ 通过
  • L4.1_INSTALL_EXECUTED_CONFINED 受限沙盒内执行安装 方式:沙盒安装执行
  • L4.2_INSTALL_SUCCESS 沙盒安装成功 方式:沙盒安装执行
  • L4.3_ARTIFACT_CONFIRMED 安装产物已确认 方式:沙盒安装执行
L5 · 运行已测 ✓ 通过
  • L5.1_INSTALL_PASSED_SANDBOXED 沙盒安装通过 方式:沙盒安装执行
  • L5.2_WEB_BOOT_READY Web 启动就绪 方式:Web 启动
  • L5.3_HTTP_SERVED HTTP 服务响应 方式:HTTP 请求
  • L5.4_PLUGIN_INVENTORY_ACTIVE 插件清单中已激活 方式:插件清单查询

风险详情

  • 结论说明 静态扫描 低;动态审计无结论(以下以静态为准)→ 总评级 低。
  • 风险计数 严重 0 / 高 0

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 验证等级 L5:安装和运行都在沙盒里跑通过,装完能直接用的概率高。
  • 静态安全审查为低风险,没有发现明显可疑行为。
  • 有可直接复制的安装命令,不用自己翻文档找入口。
  • 标注了兼容的 DSH 版本(0.2.2-rc.1 等 2 个),按版本装不容易报错。
  • 列出了 5 项功能,能直接看出它解决什么问题。

先想清楚的地方

  • 需要同时装好同级依赖,漏装会启动失败。
  • 验证通过不等于安全:插件会读写文件、执行命令或联网,装前先到仓库确认它做了什么。

更适合

  • 需要在浏览器与联网场景里给 DSH 补能力的人。
  • 想装完就能用、不想自己排依赖的人。
  • 能接受在本地装依赖、愿意自己确认权限的人。

不太适合

  • 只使用 DSH 官方内置能力、不接受第三方插件的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
插件验证等级安全审查星标兼容版本安装命令
dsh-remote当前 L5 · 运行验证通过 低风险 0 0.2.2-rc.1 等 2 个 有
dsh-our-free-model L3 · 安装规范通过 低风险 8,796 未标注 有
dsh-web L3 · 安装规范通过 低风险 8,549 未标注 无
BrowserSkill L4 · 沙盒安装通过 低风险 8,456 未标注 有
dsh-pocket L5 · 运行验证通过 低风险 1,656 0.2.0-rc.2 等 12 个 有
Browser4 L4 · 沙盒安装通过 中风险 1,152 未标注 有

仓库档案

浏览器与联网
字段来自项目仓库与公开索引,中文说明由本站标注
作者 / 维护方aide-family仓库 dsh-remote · 默认分支 main
分类浏览器与联网network
收录类型可安装插件声明了 dsh.bundle、可用 dsh plugin add 安装的条目
开发语言JavaScript仓库主语言
许可证MIT商用或二次分发前请确认条款原文
星标 / 复刻 / issue0 / 0 / 0收录时的数值,非实时
创建 / 更新2026-11-01 · 2026-11-11最后推送 2026-11-11
本站收录2026-11-01首次进入本站目录的时间

README 全文

51.2 KB
作者原文,中文版优先;只做安全转义,不改内容

dsh-remote

SSH remote-server operations for DeepSeek Harness (DSH).

Quick start

1. Install DSH

dsh-remote is a DSH plugin, so install and launch DSH first.

Desktop app (recommended). Download the official app for
macOS or Windows, open it, and finish the
first-run sign-in. The desktop app bundles its own dsh CLI and Node.js.

CLI / Web UI. Requires Node.js >= 24.9.0:

# run without a global install
npx -y @deepseek-ai/dsh web

# or install the CLI once and reuse it
npm install -g @deepseek-ai/dsh
dsh web

dsh web prints an authenticated local URL (for example
http://127.0.0.1:3080/). Open it in a browser. Then check the version:

dsh --version   # must be >= 0.2.2-rc.1

> With the Desktop app, dsh may not be on your shell PATH; either use the
> app or install the CLI as above. The plugin also needs SSH access to the
> target hosts: key files, ssh-agent, or a password supplied through an
> environment variable. ~/.ssh/config settings (HostName, User, Port,
> IdentityFile, ProxyJump) are honored.

2. Install dsh-remote

From npm:

dsh plugin --profile desktop add @aide-family/dsh-remote --ignore-scripts

From a local checkout:

cd /path/to/dsh-remote
npm install                       # once: ssh2 + test devDependencies
npm run install:profile           # packs dist/aide-family-dsh-remote-.tgz and installs
# it into the "desktop" profile

Or pack and install manually into another profile:

npm run pack:plugin
dsh plugin --profile desktop add file:$PWD/dist/aide-family-dsh-remote-0.6.2.tgz --ignore-scripts

Install into the profile you actually boot: desktop for the Desktop app, or
web when you launched dsh web (the CLI also accepts --profile web).

Then fully quit and reopen the DSH Desktop app (a newly installed bundle is
loaded on the next boot), or boot the CLI profile you installed into. Open the
远程运维 panel in the sidebar, or ask the agent to call remote_hosts, to
confirm the plugin loaded.

> --ignore-scripts is required with pnpm 11. pnpm refuses to install
> packages that declare unapproved install scripts, and ssh2 declares an
> install script for its optional native cipher-speed addon (cpu-features).
> ssh2's pure-JavaScript implementation is fully functional without it, so
> skipping the scripts is safe and avoids needing a C toolchain. (Alternatively,
> add allowBuilds: [ssh2, cpu-features] to the profile's pnpm-workspace.yaml
> and install without the flag; that does require a working compiler setup.)
>
> Do not install a development checkout with link:. DSH routes
> @deepseek-ai/* imports only for packages that physically live inside the
> profile's node_modules; a symlink to a directory outside the profile cannot
> resolve them and the plugin fails to load. Use the tarball (file:…tgz) for
> local installs, or the npm package when published.

The plugin is a DSH bundle: installing it adds the
@aide-family/dsh-remote package and a dsh-remote plugin row to the profile.
To remove it:

dsh plugin --profile desktop remove @aide-family/dsh-remote

What dsh-remote does

dsh-remote lets the agent in your DSH session actually operate remote servers:
list the hosts you already configured in ~/.ssh/config, probe a box, run
non-interactive commands, read and edit remote files over SFTP, and move files
between the session workspace and a server — with a Crescent-style static
command-risk review in front of every mutating action and the DSH approval
dialog as the human gate.

It is inspired by the Crescent
operations workbench: the same idea that the agent should gather evidence on the
real host, one bounded action at a time, with risky commands reviewed before
execution.

Screenshots

The screenshots below come from an isolated documentation profile: synthetic
hosts on RFC 5737 documentation addresses, a loopback SSH fixture, and synthetic
command output. No real host, account, key, or local path is shown.

Remote Ops management page. Host inventory, per-host detail, live shell
sessions, and the recent-operation audit trail in one panel.

Live terminal mirror. Every agent command streams into the conversation's
right sidebar; the same panel opens DSH's native terminal on a chosen host.

Host manager. Add, edit, or remove managed connections. Secrets stay as
environment-variable names or key paths.

Per-host audit. Filter by host, expand the full command, or export
JSON/CSV/TXT.

Native remote terminal. A real xterm attached to the per-conversation SSH
session; close and re-open the tab to reattach it.

Features

  • Hosts you already have — discovers every concrete Host in
    ~/.ssh/config (including Includes) and merges a configurable host list;
    the model refers to hosts by name, exactly like ssh.
  • Remote exec — one-shot, non-interactive commands with working directory,
    timeout, bounded output, and a clear [exit code: N] result line.
  • Remote files over SFTP — read (line-numbered, paginated), list, write
    (atomic temp + rename), exact-string edit, and upload/download transfers.
  • Persistent remote shells — open an interactive PTY shell on a host and
    keep using it across tool calls (remote_shell_*): send input, read
    scrollback, interrupt with signals, close. Every submitted line is
    risk-reviewed like remote_exec.
  • Live terminal mirror — a Remote Terminal tab in the conversation's
    right sidebar shows every remote command the agent runs as it runs, with
    streamed stdout/stderr and status lines. It opens automatically on the first
    command (or from the sidebar's Start page). See Live terminal.

  • Interactive remote terminal — the same right-sidebar 远程终端 panel
    picks an available host and opens DSH's native terminal attached to a
    persistent, per-conversation SSH session through a local relay: you type
    commands in a real xterm, close and re-open the tab to reattach the same
    session, and an SSH drop reconnects automatically with backoff. See
    Interactive remote terminal.

  • Quick connect from the host list — one 连接 action creates the SSH
    session, opens a new conversation, attaches DSH's native terminal to it,
    and hands the host to the agent there ("已连接远程主机 …") so operations start
    in a dedicated conversation. Failures after the switch are shown in the
    远程终端 panel (never a silent local shell), and 复制连接命令 copies the exact
    shell line for any terminal when the native-terminal integration is
    unavailable.
  • Host manager — add, edit and delete connection entries from the Remote Ops
    page (persisted in $DSH_HOME/remote/hosts.json; auth stays
    environment-variable names, never stored secrets).
  • Per-host audit — an 审计 action on every host row lists that host's
    command and terminal-session history recorded by the plugin.
  • Non-mutating commands never ask — under the default policy only commands
    the static classifier proves mutating need approval; read-only and
    unprovable-but-non-mutating commands (e.g. curl, awk, python -c) run
    directly, while policy: never, read-only hosts, denyCommandPatterns and the
    approval seam keep their stricter behaviour.
  • Remote Ops management page — a first-level panel in the DSH Web GUI with
    the discovered host inventory (per-row read-only connection test), live remote
    shell sessions (scrollback preview + close), and a persisted audit trail of
    recent remote operations. See Management page.
  • Command risk review — a port of Crescent's static classifier separates
    statically read-only commands (low) from clearly mutating ones (high) and
    unknown ones (gray); it understands shell lists, wrappers (sudo, env,
    nohup, time, xargs), sh -c/ssh/kubectl exec inner commands,
    find -delete, sed -i, yq -i, docker/kubectl/systemctl subcommands,
    and quoting.
  • Approval policy — auto (read-only runs, mutations ask), always, or
    never (fail-closed headless stance). Denials, cancelled prompts, and a
    missing answerer all fail closed.
  • Hard limits — per-host read-only lock, host allowlist, command deny
    patterns, output caps, transfer caps, and TOFU host-key verification.

Production change safety

Safe file changes and approved recovery

remote_write and remote_edit now show a bounded contextual Diff in the approval
request. Before overwriting, the plugin durably saves the original file under
$DSH_HOME/remote/backups (directory 0700, records 0600), then re-reads the target
after approval. A content/owner/group/mode version conflict stops the change;
it never silently overwrites a file modified while you were reviewing it.

Results include backupId, beforeVersion, and afterVersion. To recover an
existing file, ask the Agent to call remote_restore(host, backup_id). Recovery
has its own Diff approval, backs up the current file, and refuses a changed
connection endpoint or a file that no longer matches the recorded changed
version. An invalid/corrupted backup is rejected. Newly created files have no
original to restore: deleting them is a separate destructive operation.

Optional verify_command and verify_timeout_ms on write/edit/restore authorize
a validation command independently before the file change and run it once
after the change. For example, use nginx -t before deciding whether to
request a separate reload. Failed, cancelled, or timed-out validation leaves a
recovery record and stops the tool; it does not reload or automatically restore.

Important boundaries:

  • Only bounded regular files are changed; symlink destinations are rejected.
    Supported POSIX owner/group/mode are preserved before atomic replacement;
    missing metadata or inability to preserve it fails closed. New files default
    to private mode 0600. ACLs/xattrs/SELinux labels/hard-link identity are not preserved.
  • Writes require an absolute path; relative SFTP paths are resolved against the
    remote home. Backup capacity is 1000 records / 64 MiB; a full or unavailable
    backup store blocks overwrites rather than silently deleting recovery points.
  • Plugin changes serialize by normalized endpoint/user/path. Parent-directory
    symlinks, different endpoint names/users, and external writers are not a global
    physical-file lock. Revalidation is not an atomic filesystem CAS.
  • SFTP servers must support atomic replacement (regular or OpenSSH POSIX rename).
    There is no delete-original-and-rename fallback. Uncertain exec/file-write
    failures are not automatically replayed.
  • Approval Diff may contain sensitive configuration and is for the operator;
    file contents and full Diff are not written to operation audit or denial logs.

Per-host / tag safety profiles

Use profiles to tighten production operations without making every test host
strict. Host-name selectors are case-insensitive */? globs; tags are exact,
case-sensitive matches. Hosts or tags can select a profile. Every matching
profile composes restrictively: readonly and denies accumulate, never overrides
always/auto, and unknown-command approval cannot be weakened by another rule.
Profiles never loosen global locks or policy.

- id: dsh-remote
config:
policy: auto
unprovenCommands: allow
profiles:
- name: production
hosts: ["prod-*"]
tags: [prod]
environment: production
unprovenCommands: ask
impact: "可能影响生产服务可用性;确认完整命令与目标"
- name: protected-db
tags: [critical-db]
readonly: true
denyCommandPatterns: ['\b(reboot|shutdown|mkfs)\b']
auditLimit: 500
auditMaxBytes: 8388608
auditRetentionDays: 30

An environment of prod or production itself requires approval for unknown
commands, even if that profile specifies allow. No profiles preserves the
existing default. Approval includes the logical host, real SSH connection target,
matched profiles/environment, configured impact and complete command (commands
larger than 64 KiB are rejected, not approved from a truncated summary).

Cluster shortcuts inherit entrance policy names and tags so a shortcut cannot
hide a production entrance. Approval distinguishes that entrance from the
initialized terminal destination. This is not continuous attestation of the
current shell destination or kubectl context/namespace; verify these explicitly
before dangerous operations. Previously saved trusted connection actions still
initialize once without Agent approval, as requested; subsequent Agent commands
remain gated. Direct human terminal input remains operator-owned.

Truthful operation audit

A returned tool call is not proof of a successful change. Audit distinguishes
remote nonzero exit, timeout, cancellation, denial, unknown completion and failed
validation, and correlates calls/sessions/agents with operation IDs. File changes
retain backup/version/validation facts, not file contents. Command and result
summaries are bounded and redacted; do not embed credentials in commands.

Retention is bounded by count, bytes and age during operation, not only on
restart. Age cleanup is triggered by record/list/count/health access; there is no
background expiry timer while the application is idle. The management API
(audit.health, overview.auditHealth, audit.list.health) exposes persistence
health and cumulative write failures; health polling or flush can retry retained
pending records after storage recovers. retainedBytes describes the in-memory
retained JSONL, not a disk measurement after a write failure.

Writes use a short exclusive lock and merge only newly pending operations with
the current disk tail, preventing normal cross-instance lost updates and revival
of already-cleared history. A live or crash-left .audit.jsonl.lock makes writes
fail visibly; never remove it while writers are running. Stop writers and verify
the recorded PID before manually recovering a stale lock. One private fixed
.audit.jsonl.tmp bounds crash leftovers; auditMaxBytes caps the active JSONL,
not the extra temporary copy. Audit directories must remain trusted and private.
Exports paginate the retained trail (up to 10000 rows) and reject detected changes
during export rather than silently producing a partial file.

Command redaction covers common named secrets, PEM and URL credentials, but is
best-effort, not a guarantee for arbitrary embedded secrets or custom headers.
This local audit remains editable by the local operator; it is not a tamper-proof
compliance log. See TODO for the remaining batch inspection/change,
monitoring and multi-user work.

Runtime target checks

Target checks remain available independently of any workflow feature. Open
远程运维, select a logical host and click 目标检查 to manage exact expected
identity/context facts. Saving only changes operator settings; it never runs a
probe or grants remote execution permission. Configured checks remain read-only
and compose restrictively with page-managed checks.

Use remote_target_check to inspect actual declared facts. Guarded commands use
nonce frames and explicit exit codes in the actual POSIX exec/owned PTY context;
unknown input requires separately approved preparation. Current policy, check
hash and connection/action routing are revalidated before dispatch. Existing
SSH host management, safe file changes, command approvals and truthful audit remain.

See target configuration and safety boundaries.

Configure

All settings live on the plugin's row in the profile patch. The desktop profile
patch is ~/.dsh/profiles/desktop/cordis.patch.yml; a --patch overlay works
too (useful for headless and CI):

- id: dsh-remote
config:
# Hosts not present in ~/.ssh/config. Never put secrets here — only the NAME
# of an environment variable that holds the secret.
hosts:
- name: prod-web-1
host: 10.0.0.11
port: 22
username: ops
identityFile: ~/.ssh/prod_ed25519
tags: [prod, web]
description: primary web node
- name: legacy-db
host: 10.0.0.31
username: dba
passwordEnv: LEGACY_DB_SSH_PASSWORD   # exported in the DSH environment
policy: auto                 # auto | always | never
readonlyHosts: ["prod-*"]    # every mutating action on these is denied
allowHosts: []               # empty = all; otherwise only matching hosts usable
denyCommandPatterns: ["\\b(shutdown|reboot|mkfs)\\b"]
connectTimeoutMs: 20000
execTimeoutMs: 120000
maxOutputBytes: 200000
maxReadBytes: 800000
maxTransferBytes: 52428800
knownHostsPolicy: tofu       # tofu | strict | insecure
unprovenCommands: allow      # allow (only provably mutating asks) | ask
liveTerminal: true           # right-sidebar live terminal + /dsh-remote/live
autoOpenLiveTerminal: true
userTerminal: true           # interactive SSH terminal (relay + local bridge)
userTerminalTtlMs: 1800000   # keep an unattached SSH session this long (0 = forever)
userTerminalReconnectAttempts: 5
userTerminalScrollbackBytes: 400000
hostRegistryPath: ""         # default: $DSH_HOME/remote/hosts.json

Hosts from ~/.ssh/config need no configuration at all. If ~/.ssh/config
contains Host prod-* patterns, those wildcard entries are skipped (a pattern
is not a concrete target); add a concrete host block or a hosts: entry.

Cluster shortcuts with ordered terminal actions

The host manager can save a cluster shortcut through an existing SSH entry
(for example bastion-demo). Replace the former fixed login command with an ordered
action list: add/remove/reorder actions, select each type, and configure its
completion condition and timeout. The same actions field works in plugin hosts
configuration:

{
"name": "cluster-a",
"viaHost": "bastion-demo",
"actions": [
{ "type": "command", "value": "sww -r -u demo.user cluster-a", "expectCluster": "cluster-a" },
{ "type": "command", "value": "cd /tmp" }
],
"tags": ["cluster", "cluster-a"],
"description": "cluster-a cluster through bastion-demo"
}

After entrance SSH authentication, actions run sequentially in the same shared
PTY
used by the human and Agent. A new ordinary-shell sequence waits for the
entry prompt before sending. For a menu or custom entrance prompt, put a literal
wait action first: that output becomes the readiness barrier instead of a generic
Shell prompt. Connection readiness means all configured action completion
conditions were met, not merely that a terminal tab opened.

Type Input Completion
command Printable single-line value, automatically followed by Enter Shell prompt by default; optional literal expect, or expectCluster for a root prompt on that cluster
text Printable value, no Enter appended Input issuance, or optional literal expect
key Enter, Tab, Escape, Ctrl-C, Ctrl-D, arrow keys, or Backspace Input issuance, or optional literal expect
wait Literal output value, not a regular expression That unconsumed output is observed
delay durationMs Cancellable timer completes

Example menu interaction: wait for Select cluster: → text with 1 → key
Enter → wait for the target's success message. Text/key issuance alone does
not prove an interaction completed. A Shell prompt does not prove exit code 0
or the intended target was reached; for a login/target change, configure explicit
target-success output or the target-cluster root check.

Since 0.6.1, default completion accepts mode-prefixed user@host prompts such as
[ K8S-RONLY ]root@web1.region-a.example.test:~#, including streamed ANSI output.
The explicit expectCluster check still matches the actual root hostname's domain
segment, not a Kubernetes context name: a logical cluster-b context may use a
.region-a pod hostname. In that case use observed literal expect output rather than
requiring a nonexistent .cluster-b hostname. Mode labels alone do not mark ready;
matching a prompt does not grant write permission or override read-only policy.

There may be 1–32 actions, each optionally labelled. Send text is bounded to 4096
characters with no control characters; waits are bounded to 2048 characters.
timeoutMs defaults to 30000, range 100–120000. Delays are 0–120000 ms and the
whole sequence is capped at 20 minutes. Progress exposes counts/type/label only,
not raw action input or output. Do not embed passwords, tokens or private keys
in actions
; entrance authentication uses the secure user-only dialog or existing
credential references.

A timeout, cancellation, PTY exit or execution error stops the sequence without
sending remaining actions. Observing a completion condition is not a command
exit-code check. Reattaching/adopting an initialized PTY does not replay actions;
user-terminal reconnects initialize the genuinely new channel once. Agent-owned
PTYs keep the no-silent-reconnect rule. Legacy viaHost + loginCommand records
are automatically migrated into one command action while retaining the original
root-on-target confirmation; saving the editor uses actions only.

Shortcuts inherit entrance SSH settings, allowHosts and read-only restrictions;
missing entrances, self-reference, cycles and multi-level shortcuts still fail.
They remain terminal-only: select the shortcut in Remote Ops or use
remote_shell_open, then reuse its session id with remote_shell_send/read/signal.
Exec, probe and SFTP would target the entrance and remain disabled. Saved connection
actions are operator-trusted initialization, not Agent commands: they run without
approval regardless of policy / unprovenCommands, including sudo su - root.
Only save actions you intend to execute whenever a genuinely new SSH PTY is opened.
denyCommandPatterns, allowHosts, and inherited read-only restrictions still apply;
read-only hosts reject mutating or unproven input. Agent-submitted commands after
initialization continue through the normal risk review and approval gate.
Reattaching the same PTY never repeats initialization.

Authentication

The transport tries, in order, and uses the first that applies:

  1. passwordEnv — password auth; the env var is read at connect time.
  2. identityFile — public-key auth (from plugin config or ~/.ssh/config), with
    an optional passphrase from passphraseEnv.
  3. ssh-agent (SSH_AUTH_SOCK).
  4. Default keys: ~/.ssh/id_ed25519, ~/.ssh/id_ecdsa, ~/.ssh/id_rsa.

For an interactive terminal connection that fails with AUTH, the UI now opens
a masked SSH 密码登录 dialog. A successful fixed password is retained only in
Host process memory for that exact host/port/user until plugin disposal or app
restart; it is never saved to the host registry, sent to the Agent, or recorded
in audit/debug logs. Failed passwords are not cached or automatically retried.
The browser uses the existing authenticated Host/Origin-fenced API.

Password auth also supports a single non-echoing Password: keyboard-interactive
challenge. OTP/MFA prompts, multiple prompts, echoing prompts, repeated rounds,
and interactive password login through ProxyJump are not supported; a fixed
password is never automatically supplied to those challenges. The parser honors
PubkeyAuthentication, PasswordAuthentication, and
KbdInteractiveAuthentication for concrete SSH Host blocks. In particular,
PubkeyAuthentication no prevents fallback to default private keys.

Secrets are never read from YAML, never logged, and never included in tool
results or approval prompts.

Host keys

knownHostsPolicy controls verification against
$DSH_HOME/remote/known-hosts.json:

  • tofu (default) — trust and remember a host's key on first use; reject a
    changed key.
  • strict — only previously remembered hosts connect.
  • insecure — accept any key (the result carries a warning; not for production).

Tools

Tool Read-only Purpose
remote_hosts yes List usable hosts, auth hints, and policy flags.
remote_probe yes Connect and report hostname, OS/kernel, uptime, load, memory, disk, and latency.
remote_exec per classifier Run one non-interactive command with optional workdir and timeout; only provably mutating commands ask for approval.
remote_read yes Read a remote text file with line numbers, offset/limit, and a continue hint.
remote_list yes List a remote directory with type/size/mtime/mode.
remote_write no Write a remote file atomically, creating missing directories.
remote_edit no Replace one exact string with Diff approval, backup, version check and optional validation.
remote_restore no Restore an existing file from a bound backup, with Diff approval and a new recovery point.
remote_transfer no Upload/download between the session workspace and the host.
remote_shell_open no Open a persistent interactive PTY shell on a host.
remote_shell_send per line Write input (Enter submitted by default) and wait for output silence/timeout/exit.
remote_shell_read yes Read a bounded scrollback page (newest-relative).
remote_shell_signal yes Deliver SIGINT/SIGTERM/SIGKILL/SIGTSTP/SIGHUP to the foreground process group.
remote_shell_close no Release the Agent handle; preserve a shared user SSH terminal. Standalone Agent PTYs close normally.
remote_shell_list yes List this agent's live shell sessions.

Typical agent loop:

  1. remote_hosts → choose the host name.
  2. remote_probe → confirm reachability and rough state.
  3. remote_exec read-only checks (systemctl status, df -h, kubectl get pods) → they run without asking.
  4. Mutating step (systemctl restart nginx, rm …, remote_write, remote_edit) → command review + approval prompt, then execution.
  5. remote_read the log/config to verify.

Persistent remote shells

remote_exec is deliberately one-shot. For work that needs shell state across
calls — a REPL, an interactive prompt, a long-lived cd, environment variables,
or a running command you want to interrupt — open a PTY session instead:

remote_shell_open  { host: "me" }                       -> sessionId + shell motd
remote_shell_send  { sessionId, text: "cd /var/log" }   -> output delta
remote_shell_send  { sessionId, text: "tail -n 20 syslog" }
remote_shell_read  { sessionId, offset: 0, count: 200 } -> scrollback page
remote_shell_signal{ sessionId, signal: "SIGINT" }      -> interrupt a command
remote_shell_close { sessionId }

How a send settles: output silence (inferred_idle), the send timeout
(timeout), or the shell exiting (session_exit). inferred_idle and timeout
never prove the foreground command exited — read again or check with
remote_shell_read. Only one send may be active per session, and sessions are
owned by the agent that opened them.

Safety: every submitted line is classified exactly like remote_exec — read-only
lines run, mutating/unknown lines need approval, policy: never and read-only
hosts deny mutating input. submit: false raw control input is not classified
(it does not execute a line by itself); signals are mutating actions.

Limits: output is ANSI-sanitized line text, so full-screen TUIs (vim, top,
less) are not usable — run non-interactive commands instead, and put
long-running work in nohup … > log 2>&1 & then check it with remote_read.
Sessions are process-local and end when the harness restarts.

Configure with:

- id: dsh-remote
config:
terminalEnabled: true          # register remote_shell_* (default true)
terminalRows: 40
terminalCols: 120
terminalIdleSilenceMs: 800     # silence that settles a send
terminalTimeoutMs: 30000       # absolute bound on one send
terminalStartupTimeoutMs: 15000
terminalScrollbackLines: 2000
terminalScrollbackBytes: 2000000
terminalMaxReadBytes: 262144

Interactive remote terminal (type and watch)

The agent-side shell above shows each send's output in its tool card. The
interactive terminal is different: the 远程终端 panel picks a host and opens
DSH's native terminal (real xterm) connected by SSH, and you type in it.

How it works:

  1. On the Remote Ops page, select a host and click 连接并开始运维.
    It creates a fresh conversation in the fixed local operations workspace
    $DSH_HOME/workspaces/remote-ops (default ~/.dsh/workspaces/remote-ops),
    shows real connection stages in a progress dialog, and does not send an
    unsolicited Agent task. Password prompts appear above progress; successful
    connection automatically closes progress. Native terminal tabs use the SSH
    name. 打开终端 in the live panel keeps the current conversation; explicit
    Agent handoff remains a separate action.
  2. The plugin opens a native terminal tab in the right sidebar of that
    conversation. A small local bridge (bin/dsh-remote-terminal →
    lib/terminal/bridge.cjs) connects to the Host's terminal relay over a
    user-only local socket; the relay in the DSH Host process owns the SSH PTY
    (transport.openPty). This is an interactive SSH shell in DSH's native
    terminal, not a local
    ssh process
    . The browser plugin cannot spawn OS processes; it writes one
    quoted bridge-launch line via DSH's terminal-view API and verifies the relay
    attachment.
    Everything you type reaches the remote shell, and its output (ANSI included)
    renders in xterm. If the tab or the bridge cannot be established, the panel
    says so, shows the exact command with 复制命令, and points at
    $DSH_HOME/remote/terminal-bridge.log — paste the command into any local
    terminal to connect manually.
  3. The Agent and human share the exact PTY. The relay's canonical key is
    (DSH conversation id, host). When remote_shell_open runs in that
    conversation, the Agent shell manager borrows that relay PTY rather than
    opening another SSH shell channel; opens are reused per Agent + host. Reopening
    the native terminal attaches to the same relay session. Closing its tab does
    not idle-close an Agent-owned PTY. remote_shell_close, Agent disposal, and
    shell-manager cleanup release only the Agent's borrowed handle; the shared
    user SSH PTY remains available. Its idle TTL applies after the last Agent and
    bridge detach. Explicit management-page SSH close or relay/plugin shutdown
    terminates the actual shared connection.
  4. Recovery is state-aware. A terminal-only relay can reconnect with backoff
    (1s/2s/4s/8s/16s/30s, up to userTerminalReconnectAttempts) and the bridge
    retries temporary socket outages. A negotiated SESSION_GONE rejection stops
    bridge retries and asks for an explicit new connection; it never replays old
    input or pretends a new shell preserves old state. If an Agent owns the PTY and its SSH
    channel exits, the relay marks that shared shell ended instead of reconnecting
    to a fresh shell that would falsely appear to preserve state; explicitly open
    a new session to continue.

The terminal must actually be connected. Opening a tab is not proof: after
writing the local bridge launch line once, the panel waits for a new bridge
attach beyond the session's pre-launch counter and requires the relay SSH state
to be connected. It never replays the launch line automatically: if the first
write was delayed, replaying it could reach an already-connected remote shell as
user input. On failure it does not claim success; it shows the exact command
with a 复制命令 button plus the path of
$DSH_HOME/remote/terminal-bridge.log. The shell line
does not depend on the terminal's PATH: it uses the Host's own node binary
(directly, through ELECTRON_RUN_AS_NODE in the Desktop app, or the bundled
runtime node) and falls back to the packaged launcher. The panel also shows the
live session state — 接入 N (attached terminals), the short session key, and a
复用 badge when the same SSH session was reattached — so connection reuse is
visible instead of assumed. The relay records terminal attach/detach audit
events, so a session that opened but never attached is visible in the host's
audit history.

Limits: the relay keeps a bounded replay buffer (userTerminalScrollbackBytes,
default 400 KB) so a reattached terminal shows recent output. The native terminal
is a full PTY and supports TUI interaction; Agent remote_shell_read returns
ANSI-sanitized line text, so the Agent should use it for shell state and rely on
the native terminal for full-screen rendering. Agent-submitted lines retain the
normal risk/approval checks. Human keystrokes are explicit operator actions and
are never copied into the audit trail (they may contain passwords). Terminal
sessions are process-local: a harness restart ends the remote process shell; do
not infer that a new shell has the old state.

The old host-picker shell (scripts/dsh-remote-shell, an ssh -t session
configured through terminal-controller's shell profile) still exists as a
standalone fallback, but it is not used by the panel.

Live terminal (right sidebar)

Every remote_exec command and submitted remote_shell_send line is mirrored
into a right-sidebar tab, so you watch the real execution instead of only the
final tool card:

  • Opens automatically on the first remote command of the session (the
    right-sidebar column expands), and is also available from the right sidebar's
    Start page as a 远程终端 entry.
  • Streams in real time: a prompt line ($ command, host, session), the
    command's stdout/stderr chunks as they arrive, and a status line
    ([exit 0 · 812ms] / [error: …] / [running]). Denied commands appear too,
    so you see exactly what the agent attempted.
  • Bounded and private: the stream is served from the running Host over a
    fenced same-origin SSE route (/dsh-remote/live); the Host keeps a bounded
    replay buffer (last 200 commands, 64 KiB per command, 1 MiB total) so a late
    panel still shows recent activity. Nothing is written to disk for the stream.
  • Controls: connection state, per-host filter, local clear, auto-scroll
    (unless you scrolled up), automatic reconnect.
- id: dsh-remote
config:
liveTerminal: true            # serve /dsh-remote/live + register the tab
autoOpenLiveTerminal: true    # auto-open on the first command

Approval policy (default auto): only provably mutating commands ask. Set
unprovenCommands: "ask" to require approval for commands the classifier cannot
prove read-only (unknown binaries, curl, awk, …), or keep the strict
policy: never for unattended runs (mutating and unproven commands are denied,
read-only commands run).

Management page (Remote Ops / 远程运维)

The plugin registers a first-level sidebar panel in the DSH Web/Desktop GUI:

Section What you get
Connection rail + host workbench The connection rail selects a discovered host; the workbench shows source, user@host:port, auth hint, readonly / allowHosts policy, connectivity, terminal and Agent-session state, and the selected host's actions.
Host actions 测试连接 / Test connection runs a read-only probe (connect + uname -srm; hostname) and shows latency/output; 连接 creates a conversation, opens its native terminal, and hands the host to the Agent using the same conversation-host PTY; 审计, 编辑 / 删除 for managed hosts. 添加主机 opens the connection form.
Remote shell sessions Live remote_shell_* sessions for every agent (session id, host, status) with a bounded scrollback preview and a 结束会话 / Close action.
Recent operations The newest 20 audit entries: time, tool, host, action, risk level (low/gray/high/write), outcome (success / failure / denied / cancelled / timeout / unknown / validation failure), duration, and the bounded redacted command/path, with a JSON/CSV/TXT export of the full retained trail.

Host manager

添加主机 opens a form for a connection entry that does not live in
~/.ssh/config: name, host, port, user, key file, environment-variable names for
the password/passphrase, proxy jump, tags and description. Entries are persisted
in $DSH_HOME/remote/hosts.json (mode 0600, atomic writes) and merged into the
same host list as ~/.ssh/config and the plugin hosts: config, winning on a
name collision. Raw secrets are never accepted: auth values are environment
variable names. Hosts discovered from ~/.ssh/config or the plugin config
are listed read-only here (edit/delete only for managed entries).

Per-host audit

审计 on a host row opens that host's operation history from the same audit
trail: every model-facing remote call (tool, action, risk, outcome, duration,
command/path) plus interactive-terminal lifecycle events (open / attach /
reconnect / close). Each row expands to the bounded, redacted command (whitespace
preserved — the table keeps a short one-line summary) and correlation/recovery facts, and
JSON / CSV / TXT export covers either the current host or the whole retained
trail. User keystrokes typed in the interactive terminal are never recorded
(they can contain passwords typed at a sudo prompt).

The page polls the Host every 10 seconds and has manual refresh and audit-clear
buttons. It is backed by a small same-origin JSON API at /dsh-remote/api
(overview, host.test, host.create, host.update, host.delete,
audit.list, terminal.open, terminal.list, terminal.close, session.read,
session.close, audit.clear) that is mounted only when a web server exists and
is fenced by the same Host/Origin + browser-cookie check DSH's own /api uses.
The audit trail is also appended to $DSH_HOME/remote/audit.jsonl (bounded tail
reloaded on startup), so it survives a restart.

Disable the HTTP API/page backend with managementApi: false in the plugin
config if you do not want the route registered.

Safety model

  • Static review before approval. Every remote_exec command and submitted
    remote_shell_send line is classified by the ported Crescent classifier.
    Under policy: auto only high (provably mutating) commands need approval;
    low and gray (unproven) run directly, with the live terminal and audit
    trail recording Agent actions. Direct keystrokes in the native terminal are
    explicit human operator actions: they bypass Agent approval and are not stored
    in audit payloads. unprovenCommands: ask restores approval for the unproven
    class, and remote_write / remote_edit / remote_transfer always need
    approval.
  • Fail closed. No approval answerer mounted, a cancelled prompt, a rejected
    prompt, or an approval-service failure all deny the action.
  • policy: never is the headless/unattended stance: statically read-only
    actions work; mutating and unproven actions are denied with an explanation.
  • Host-level guards. readonlyHosts denies every mutating action on matching
    hosts in every policy mode; allowHosts (non-empty) hides and rejects
    everything else; denyCommandPatterns always denies a matching command.
  • Bounded everything. Exec output is capped (tail kept, marker added), reads
    are paginated, transfers are capped, and connections/commands time out.
  • Workspace-scoped transfers. Local transfer paths resolve against the
    session working directory and must stay inside it unless
    allowLocalOutsideWorkspace: true.

Development

npm install --ignore-scripts --legacy-peer-deps  # ssh2 + explicit test SDK peers
npm test                          # unit + integration tests (no real servers)
npm run e2e                       # real DSH headless run against a fixture SSH server
npm run dev:profile               # create the isolated DSH dev profile
npm run dev:sync                  # copy lib/ into the dev profile's node_modules

The integration and e2e suites run a real SSH server fixture
(test/fixtures/ssh-server.mjs, built on ssh2's server) on 127.0.0.1, so no
external host, key, or network access is required.

The e2e suite uses an isolated DSH_HOME (./.dsh-test), a remotedev profile
created from the shipped headless template, and the credentials already saved by
the desktop app (symlinked, never copied). It asserts the real harness loads the
plugin, registers the tools, and executes read-only remote actions; mutating
actions are asserted to fail closed in headless mode.

Automated npm publishing

The npm package name is @aide-family/dsh-remote; the DSH plugin row id remains
dsh-remote. Before enabling releases, add a repository Actions secret named
NPM_TOKEN with publish permission for the @aide-family scope. Do not put the
token in the repository or a checked-in .npmrc.

Before tagging a release, run the CI checks locally in a clean checkout:

npm ci --ignore-scripts
npm test
npm pack --dry-run

Pushing a tag that exactly matches the manifest version (for example, v0.10.1)
starts the publish workflow.
The workflow installs locked dependencies, builds the client and runs all unit
and integration tests, checks the tag/package version match, previews the tarball,
then publishes publicly with provenance.
The publisher must have rights to create packages in the @aide-family scope.

git tag -a v0.10.1 -m "Release v0.10.1"
git push origin v0.10.1

Published versions cannot be reused. If a release has a mistake, fix it and
publish a higher version; do not try to overwrite the existing version.

Known limitations

  • No persistent remote shell. remote_exec is one-shot (no PTY): each call
    is a fresh shell. Long-running processes must be started detached
    (nohup … &); interactive programs (vim, top) are not supported.
  • remote_read pages within maxReadBytes. Line offset/limit work on
    the file window returned by one read; a file larger than maxReadBytes
    cannot be paged past that window. Use remote_exec with tail -n/grep/
    sed -n or remote_transfer for very large files.
  • Workspace containment is lexical. Transfer local paths are checked
    lexically against the session working directory (no symlink resolution);
    keep allowLocalOutsideWorkspace: false unless you need otherwise.
  • Saved host authentication contains references only. The host form stores
    metadata and environment-variable names, never raw passwords. Interactive
    terminal connections can request a fixed password in the masked login dialog,
    retained only in Host memory; encrypted-key passphrases still use environment
    references. A restart requires entering a transient password again.
  • One connection per host. Operations for one host are serialized through a
    single pooled SSH connection (plus ProxyJump hops), so concurrent calls to the
    same host queue rather than open many sessions.
  • No full-screen TUI in agent shells. remote_shell_* output is
    line-sanitized, so vim/top/less are not usable from the agent; use
    non-interactive commands. The interactive terminal (above) is a real xterm and
    supports them for the user.
  • Shell sessions and the live stream are process-local. The terminal mirror
    retains a bounded in-memory buffer only; a harness restart clears it (the audit
    trail persists). Interactive-terminal sessions behave the same way: the relay
    keeps them across terminal close/reload and reconnects an SSH drop, but a
    harness restart starts a fresh shell on the next open.
  • The interactive terminal is user-driven. It runs with the Host user's SSH
    credentials and is not gated by the agent approval policy; allowHosts still
    restricts which hosts may be opened. The local bridge needs node on the
    terminal PATH (or DSH_REMOTE_NODE).
  • The live mirror shows remote_exec and shell sends, not file reads/writes
    (those keep their tool cards) and not commands run outside the plugin.
  • One send at a time per remote shell, bounded by terminalTimeoutMs.
  • The management page needs the Web/Desktop surface. Headless CLI runs have
    no HTTP server, so the API and page are not mounted there (tools still work).
  • Session list is process-local. The page shows sessions of the running
    harness process; the audit trail is persisted, sessions are not.
  • No port forwarding / tunnels. The plugin runs commands and file transfers;
    ssh -L-style forwarding is out of scope.

Layout

lib/
index.js        plugin entry (apply, Config, prompt section, wiring)
client.js       browser half: sidebar "Remote Ops" panel + page
api.js          Host JSON API behind the management page (fenced)
audit.js        bounded audit trail (memory ring + JSONL persistence)
live.js         live command hub for the right-sidebar terminal
live-stream.js  fenced SSE transport (/dsh-remote/live)
tools.js        8 defineTool definitions
render.js       canonical value -> model text
approval.js     policy + risk review + DSH approval seam
host-store.js   cached host discovery/resolution
config.js       Schemastery Config + normalizeConfig
hosts.js        ~/.ssh/config + config + managed host merge/resolve
host-registry.js persisted managed-host CRUD ($DSH_HOME/remote/hosts.json)
ssh-config.js   ~/.ssh/config parser (Include, ProxyJump, …)
policy/         ported Crescent static command-risk classifier
ssh/            ssh2 pool, auth, exec, SFTP, known hosts
terminal/       agent PTY shells (v0.2) + interactive user terminal relay/bridge (v0.5)
bin/
dsh-remote-terminal  POSIX launcher run inside the native terminal (v0.5)
test/
unit/           pure-module tests
integration/    fake-ctx plugin tests + fixture SSH server
fixtures/       ssh-server.mjs
scripts/          dev-profile, sync-profile, e2e, dev-web, docs-screenshots
docs/assets/      README screenshots (generated from the synthetic profile only)

Attribution: the command-risk classifier in lib/policy/ is ported from the
Crescent project (aide-family/Crescent, src/shared/command-guard.ts,
src/shared/shell-command.ts, src/shared/command-policy/).

Repository privacy

Source, tests, examples, documentation and published assets must not contain
private organization names, personal identifiers or real test connection details.
Use synthetic cluster/host aliases and accounts, reserved example domains such as
example.test, and documentation IP ranges (192.0.2.0/24, 198.51.100.0/24,
203.0.113.0/24). Keep loopback addresses for local fixture servers. Use generic
paths instead of a developer's home directory.

Browser captures must disable SSH-config discovery (includeSshConfig: false),
use isolated fixture inventory, and show synthetic command output rather than
local usernames or machine details. Review images, logs, archives and package
contents before publication; never commit live connection records or secrets.

Verification

npm test        # unit + real-fixture integration (no external servers)
npm run e2e     # real DSH headless run against a fixture SSH server
node scripts/dev-web-test.mjs --remote-terminal --docs-shots   # real browser loop (v0.5)
npm run docs:screenshots   # regenerate docs/assets/ from an isolated synthetic profile

The e2e suite proves the model actually calls the tools through the DSH pipeline,
that read-only remote actions work, that mutating actions fail closed in headless
mode, that a persistent PTY shell opens, echoes a command, and closes cleanly,
and that an unproven (gray) command now runs without approval. The management page is verified in a real browser against an isolated
DSH Web profile (npm run dev:web boots it, drives it with headless Chrome, and
writes a local screenshot). npm run docs:screenshots regenerates the README
images from a profile that disables SSH-config discovery, contains only synthetic
inventory and a loopback fixture, and refuses to write a capture if the page
shows a real-looking host, account, or local path. Earlier screenshots were
removed because they contained real connection details; the README now uses
generated synthetic captures, but still review every image before publishing it.
--emit-live verifies the v0.4 live mirror (guide entry, auto-open, streamed
commands/output, session and host filters, scrolling, Clear). --remote-terminal
boots the same profile with a real SSH fixture host and verifies v0.5 end to end:
the actions column, quick connect creating the relay PTY and opening DSH's native
terminal, typing a command into the xterm, the 已连接远程主机 … conversation
handoff, the per-host audit modal, the host-manager add/delete round-trip, and
per-conversation session reuse (same sessionKey on a second open) — with zero
browser console errors. --docs-shots additionally captures
a local terminal screenshot from a fixture-only panel with synthetic output (no
agent handoff). Review captures for private data before publishing them. The v0.5.1 pass additionally asserts the relay attached/attachCount
/bytesIn counters (the local bridge really reached the SSH session), the
per-host audit attach event, one-click full-detail expansion, a real JSON
export download with detailFull, and that overview.audit returns at most the
newest 20 entries. Run the browser loop with full process access: the DSH Host must be able
to allocate a POSIX PTY for the native terminal, which an agent workspace sandbox
can deny (posix_openpt: Operation not permitted). A packaged tarball
install is verified separately:

npm run pack:plugin
dsh plugin --profile  add file:$PWD/dist/aide-family-dsh-remote-.tgz --ignore-scripts
E2E_SKIP_SYNC=1 DSH_TEST_PROFILE= node scripts/e2e.mjs

Troubleshooting

Symptom Cause / fix
Cannot find package '@deepseek-ai/dsh-tools' The plugin was installed with a symlink (link:) outside the profile. Reinstall from a tarball/npm so it lives under /node_modules.
denied because no approval answerer is mounted Headless or unattended run; use policy: never for read-only automation, or run the interactive Web/Desktop surface for mutating work.
HOST_KEY / changed host key A previous key is remembered in $DSH_HOME/remote/known-hosts.json; verify the server key and remove the stale entry (or switch knownHostsPolicy).
AUTH failure Check ssh -v works with the same user/key; verify identityFile, SSH_AUTH_SOCK, or the passwordEnv variable is visible to the DSH process (the app may not inherit your shell's exports).
Host missing from remote_hosts Wildcard-only Host blocks and hostname-less entries are skipped; add a concrete host block or a hosts: config entry.

License

MIT. See LICENSE.

常见问题

9 问
答案由本站依据条目字段整理,不引用上游原文
dsh-remote 怎么安装?

在 DSH 里执行 `dsh plugin --profile web add @aide-family/dsh-remote@0.10.1` 即可。对应的 npm 包名是 `@aide-family/dsh-remote`。

dsh-remote 的验证等级是什么意思?

L5 · 运行验证通过。在 dsh 沙盒中完成安装与运行冒烟——装得上、跑得起来

dsh-remote 安全吗?

低风险。静态扫描 低;动态审计无结论(以下以静态为准)→ 总评级 低。

dsh-remote 装之前要先确认什么?

先看它会读写哪些文件、执行哪些命令、连接哪些网络地址;验证等级只说明装得上、跑得起来,不等于安全。涉及密钥或系统权限的,建议先在隔离环境试装。

dsh-remote 支持哪些 DSH 版本?

上游记录的兼容版本包括 0.2.2-rc.1、0.2.1-rc.5。

dsh-remote 需要什么运行环境?

Node.js ^22.19.0 || >=24.0.0;需要同时安装 @deepseek-ai/cordis@^4.0.5、@deepseek-ai/dsh@^0.2.2-rc.1、@deepseek-ai/dsh-tools@^0.2.1-rc.5、@deepseek-ai/schemastery@^3.18.2。环境不满足时安装会失败,建议先确认本机版本。

dsh-remote 用的是什么许可证?

上游标注为 MIT。商用或二次分发前请到仓库确认许可证原文。

dsh-remote 有哪些功能?

复用 ~/.ssh/config 主机清单、远程命令执行与退出码、SFTP 读写与上传下载、持久远程 PTY shell、命令风险审查与审批。

这条记录的数据可靠吗?

本站按仓库名去重后合并整理,字段以作者仓库与 npm 元数据为准;安装命令、仓库地址与 README 保持原文,带 L4 / L5 标记的安装命令已在隔离沙盒里真实跑通。

同名或近似条目

8 条
不同作者的仓库分开列,请确认你要装的是哪一个
浏览器与联网
按星标排序,可作替代方案

dsh-our-free-model

dsh-our-free-model

在 DeepSeek Harness 中装上这个 DSH plugin,无需登录、注册或填 API Key,即可直接调用 DeepSeek

L3 · 安装规范通过 8,796 星

dsh-web

dsh-web

侧边栏多列任务看板:卡片交给真实 DSH 智能体会话执行,支持 cron 定时(Host 侧到点执行,关浏览器也生效)。

L3 · 安装规范通过 8,549 星

BrowserSkill

BrowserSkill

BrowserSkill 的 DeepSeek Harness 浏览器自动化桥接插件,通过原生浏览器工具控制可见的 Chrome 和 Edg

L4 · 沙盒安装通过 8,456 星

dsh-pocket

dsh-pocket

DSH Pocket 让 DeepSeek Harness 装进口袋:电脑跑 dsh web,手机扫码即实时同步访问(局域网+公网),人在外

L5 · 运行验证通过 1,656 星

Browser4

Browser4

L4 · 沙盒安装通过 1,152 星

agentrq

agentrq

L4 · 沙盒安装通过 1,140 星

插件的元信息来自作者仓库;分类、验证等级与安全结论的中文说明为中文整理,最近核验 2026-11-12。