前言¶
DeepSeek Harness(DSH)是「一切皆插件」的设计思路,插件运行在 DSH 进程的沙箱内。传统的「agent 远程执行」通常另开一条 SSH 通道,导致会话与主终端分离、agent 输出无法回看、shell 状态(如 cd、export)在两次调用间丢失。
dsh-remote-console 插件把 agent 放进你正在看的那个终端:agent 的命令像人打字一样出现在窗口里,退出码由 shell 的 PROMPT_COMMAND 钩子(OSC 序列)回报,人的操作和 agent 的操作落在同一条可回看的日志里。
核心定位¶
- 插件名:
dsh-remote-console - 维护者:cccodder
- 分类:客户端
- 作用:DSH 右侧栏的「SSH 远程控制终端」,在同一个 PTY 里同时支持人与 agent 的交互
插件不重新实现终端:渲染、输入、窗口管理全部复用 DSH 自带的终端,只做三件事——往 shell 列表里加远端启动器、捕获这条 PTY 的字节流、给 agent 一组写进同一个终端的工具。
安装与启用¶
环境要求¶
- DSH 版本:
>=0.2.1-rc.2 <0.3.0 - 本机有系统
ssh客户端 - Node.js
>=20
插件市场安装(推荐)¶
- 在 DSH 侧栏启用实验性 bundle:
@deepseek-ai/dsh-experimental-plugin-market-bundle - 进入「发现」页面 →「添加索引源」
- 粘贴插件市场索引:
https://cccodder.github.io/dsh-remote-console/market/index.json
如果 GitHub Pages 不通,可改用:
https://cdn.jsdelivr.net/gh/cccodder/dsh-remote-console@main/market/index.json
或 GitHub 原链:
https://raw.githubusercontent.com/cccodder/dsh-remote-console/main/market/index.json
- 在列表里找到
dsh-remote-console→ 点击安装 - 以后有新版本会在同一位置显示「有新版本」,直接更新
CLI 管理的 profile 安装¶
以 web profile 为例:
# 1. 装进 profile
dsh plugin --profile web add dsh-remote-console
# 2. 编辑 $DSH_HOME/profiles/web/package.json
# 把插件加进该 profile 的 bundle 列表:
# "dsh": { "profile": { "bundles": [ ..., "dsh-remote-console" ] } }
# 3. 确认插件层被组合进来
dsh --profile web --dump-config | grep -A2 dsh-remote-console
Electron 桌面版安装¶
桌面版 desktop profile 由 App 独占管理,CLI 会直接拒绝:
profile "desktop" is managed exclusively by the Electron application
请使用 App 内置的插件管理器:
- 方式一:包名填
dsh-remote-console(从 npm 装) - 方式二:粘贴
github:cccodder/dsh-remote-console(从 git 装最新提交)
App 会自动写入 profile 的 dependencies 与 dsh.profile.bundles。注意全局 dsh CLI 版本可能低于 App 自带的 DSH,以 App 内的版本为准。
典型用法¶
启动远程会话¶
- 右侧栏 →「SSH 远程」卡片 → 选中一个远端(来自
~/.ssh/config的 Host,或手动新建) - 终端里执行:
ssh -M -S <sock> -t <host>
- 密码/口令由
ssh自己提示,插件不接触 - 插件不修改
~/.ssh/config,不改 shell rc
Agent 可用的工具¶
登录成功后,agent 可用以下工具:
| 工具 | 作用 |
|---|---|
remote_status |
终端、主机、socket、状态、最后几行屏幕 |
remote_run(command) |
写进同一个 PTY(窗口里可见),返回输出 + 真实退出码(PTY 会把 stderr 并进输出) |
remote_exec(command, cwd?) |
复用 ControlMaster socket 的带外执行:原生 stdout/stderr/退出码,不污染终端窗口 |
remote_screen(lines) |
当前屏幕纯文本(剥 ANSI) |
remote_log(cursor) |
统一 JSONL 日志的增量读:人敲的命令、agent 的命令、两边输出 |
remote_close() |
断开 ssh master 并清理 socket/rendezvous 文件 |
使用建议:
remote_run:要你看着执行、需要 TTY(sudo/vim/嵌套 ssh)、需要在两次调用间保留 shell 状态remote_exec:纯数据收集、脚本、必须用退出码判断成败的事
注意 exit 的语义:
面板里的主机启动器和「新建会话」都是一次性的——远端 shell 退出(命令里带 exit、logout,或 ssh 断开)后,整个终端就结束了,所有 remote_* 工具失效,需要人工重新打开终端并重新输密码。插件会拦下这类命令要一次审批,并在终端里明确提示「这个终端已经结束」。
安全模型¶
- 凭据不经过插件:密码只在
ssh自己的提示符里输入。hosts.tsv只记 host/user/port(0600),数据目录 0700;仓库里不含任何密钥。 - 认证期拒写:屏幕停在
password:、(yes/no)?、Permission denied等状态时,agent 的任何写入都会被拒绝(AUTH_REQUIRED),避免它替你回答认证问题。 - 危险命令审批:
remote_run/remote_exec绕过 DSH 沙箱,插件额外加了一道闸门:命中rm -rf、mkfs、dd of=/dev/*、shutdown/reboot、fork bomb、curl | sh、git push --force、DROP TABLE等模式时,通过 DSH 的ctx.approval弹一次审批卡片,一次授权只对本次命令有效;没有审批服务时直接拒绝执行。remote_run里会结束整个终端的exit/logout/pkill ssh同样需要审批。 - 日志会消失:PTY 结束即删除会话日志(保留内存事件供当场回看);DSH 崩溃留下的残留日志会在下次插件启动时清扫。日志写入前会对 Bearer token、
sk-*、password=/token:/secret=一类赋值做脱敏,但命令参数里的明文密钥仍可能出现在会话期间,敏感操作请用环境变量或ssh-agent。 - 关窗即失能:关终端标签立即杀进程树;关浏览器在最后一个窗口持有消失 8 秒后杀(刷新会重连并取消);DSH 崩溃时 PTY master 消失,
ssh随 HUP 退出。
威胁模型:插件保护的是「凭据不被 agent/日志带走」和「破坏性操作需你点头」,它不能防御你已经授权的 agent 在远端做任何事。远端命令本身就是你给 agent 的能力。
环境变量¶
| 变量 | 默认 | 作用 |
|---|---|---|
DSH_REMOTE_CONSOLE_DIR |
$DSH_HOME/remote-console |
数据目录(logs/sessions/socks/bin) |
DSH_SSH_CONFIG |
~/.ssh/config |
主机别名来源 |
DSH_RC_DANGER_GUARD |
approve |
设为 off 关闭危险命令审批(自担风险,仍会记审计事件) |
DSH_RC_DRYRUN |
0 |
包装器 dry-run:只打印 ssh 命令不执行(测试用) |
DSH_RC_NO_CLEAR |
0 |
设为 1 不自动清屏(排查时用) |
DSH_RC_SELFTEST |
0 |
启动后跑一次内建自测并写 selftest.log |
数据目录¶
${DSH_HOME:-~/.dsh}/remote-console/
bin/:按~/.ssh/config生成的主机启动器(dsh-ssh-<host>)hosts.tsv:手动新建过的主机(host/user/port)sessions/:terminal ↔ socket的 rendezvous(进程退出即清)socks/:ControlMaster socketlogs/:会话 JSONL(会话结束即删)plugin.log:插件诊断日志(不含凭据)
兼容性与限制¶
- 插件包住的是 DSH 的终端服务(
ctx.subprocess.spawnTerminal、ctx.terminalController.shells|retain、客户端ctx.webTerminals.launchShells),这与社区插件的常用手法一致,但不是文档化扩展点;DSH 改动这些内部实现时需要同步适配(package.json的engines.dsh声明了已验证范围)。 - 远端默认用
bash -li启动以挂PROMPT_COMMAND钩子;远端没有 bash 时自动退回哨兵模式(窗口里会看到一行__dsh包装命令),功能不受影响、只是观感略差。 - 终端输出没有做全终端模拟:行内覆盖用「保留最后一个
\r之后内容」的简化处理,极端 TUI 场景下remote_screen可能与真实画面有出入,命令结果以remote_run/remote_exec为准。
开发与测试¶
npm test # 69 个测试:纯函数、危险命令/终止命令判定、菜单包装器、插件装载、命令通道模拟
测试不需要 ssh,也不需要真 PTY:tests/link-peers.mjs 会把全局安装的 DSH 里的 peer 包软链进本目录(node_modules/@deepseek-ai/{dsh-home-paths,dsh-tools}),tests/console.test.mjs 用一个假远端 shell 回放 OSC 帧来验证退出码、回显剥离和超时。
结语¶
dsh-remote-console 把 SSH 远程执行从「另开通道」变成「同屏协作」,让 agent 的操作可见、可控、可审计。适合需要在终端里与 agent 交互、依赖 shell 状态、需要 TTY 的场景。
- 插件主页:https://github.com/cccodder/dsh-remote-console
- 插件目录:https://www.skillhub.cn/plugins/cccodder/dsh-remote-console
- 许可证:MIT