Imported from sleepinginsummer/agent-ssh-cli (
SKILL.md). Install upstream withnpx skills add sleepinginsummer/agent-ssh-cli. Copyright stays with the author.
agent-ssh-cli 使用说明
agentsshcli 是一个通过 npm 安装、由 Rust 原生执行器完成 SSH 操作的命令行工具,用于让 AI 或用户通过本地配置安全地操作远端服务器。
它能做的事:
- 列出本地配置中的 SSH 服务器连接
- 在指定远端服务器上执行命令
- 上传本地文件到远端服务器
- 从远端服务器下载文件到本地
- 通过命令黑白名单限制可执行命令
- 通过 Rust daemon 短时间缓存 SSH 连接,减少连续操作时的重复连接开销
- npm 安装会按当前系统自动拉取对应平台的 optional 预编译包,当前支持 macOS arm64/x64、Linux x64/arm64、Windows x64
它不做的事:
- 不保存或输出密码、私钥等敏感认证信息
- 不扫描网络或发现服务器,只使用配置文件中的连接
- 不绕过配置中的命令限制
命令黑白名单使用 JavaScript RegExp 语法,不是 POSIX 正则。空白字符要写成 \\s,不要写 [:space:]。例如:
{
"commandBlacklist": [
"(^|[;&|()\\s])rm(\\s|$)",
"(^|[;&|()\\s])shutdown(\\s|$)",
"(^|[;&|()\\s])reboot(\\s|$)"
]
}
安全确认
执行危险操作前必须先向用户确认,不能直接执行。
危险操作包括:
- 删除、清空、覆盖文件或目录,例如
rm、truncate、重定向覆盖、批量删除 - 清理缓存、日志、临时目录或业务数据
- 重启、关机、停止服务或杀进程,例如
reboot、shutdown、systemctl stop、kill - 修改权限、所有者、系统配置或启动项,例如
chmod、chown、编辑/etc下文件 - 上传文件覆盖远端已有文件
- 下载文件覆盖本地已有文件
- 任何不可逆、影响线上服务、影响数据完整性的操作
确认时必须说明目标连接名、命令或文件路径、可能影响,并等待用户明确同意后再执行。
环境校验
调用前优先检查 CLI 本身是否可用:
agentsshcli --help
如果上面的命令失败,再向下检查基础环境:
node --version
npm --version
如果 node 或 npm 不存在,提示用户先安装 Node.js >= 18 和 npm >= 8。
CLI 可用后,再检查配置文件是否存在:
test -f "${AGENT_SSH_CONFIG:-$HOME/.agent-ssh-cli/config.json}"
如果配置文件不存在,提示用户创建配置文件,不继续执行 SSH 命令:
mkdir -p ~/.agent-ssh-cli
# 然后让用户编辑 ~/.agent-ssh-cli/config.json,填入真实服务器配置
默认配置文件:
~/.agent-ssh-cli/config.json
为防止配置文件中的密码泄露,密码认证会在第一次使用该服务器时被动加密保存:如果目标连接的 password 是非空明文,下一次执行 exec、upload 或 download 连接该服务器前,CLI 会把密码加密写入配置目录的 secrets.json,生成本地 secret.key,并把 config.json 中该连接改成 password: "" 加 passwordRef。改密码时直接把空的 password 重新填成新密码,下一次连接会自动覆盖旧密文。私钥认证不参与这个流程。
隐藏后的密码配置示例:
{
"name": "server",
"host": "192.0.2.10",
"port": 22,
"username": "root",
"password": "",
"passwordRef": "agentsshcli:server"
}
配置文件完整字段(每项是 name 唯一的一台服务器):
name: 连接名,必须唯一host/port/username: SSH 主机、端口(默认 22)、用户名password/passwordRef/privateKey: 认证方式,三者只能保留一种;passphrase仅配合privateKey使用jumpHost: 跳板机连接名,填写配置文件中另一台机器的name;连接时先建立到跳板机的 SSH,再通过直连通道到达目标机socksProxy: SOCKS5 代理地址,例如socks5://127.0.0.1:1080;也可省略协议写成127.0.0.1:1080pty: 是否默认分配伪终端,exec --pty/--no-pty可临时覆盖commandWhitelist/commandBlacklist: 命令白/黑名单正则数组
跳板机示例:
[
{
"name": "目标机",
"host": "10.0.0.5",
"username": "root",
"passwordRef": "agentsshcli:目标机",
"jumpHost": "跳板机"
},
{
"name": "跳板机",
"host": "203.0.113.10",
"port": 22,
"username": "ubuntu",
"privateKey": "/path/to/jump_key"
}
]
指定其它配置文件:
AGENT_SSH_CONFIG=/path/to/config.json agentsshcli list
如果 CLI 不可用但 Node/npm 正常,提示用户安装:
npm install -g agent-ssh-cli
agentsshcli --help
从源码开发或本地调试时,需要先构建 Rust 原生执行器:
npm run build:native
npm test
全局参数
--config <path>: 指定配置文件路径,优先级高于默认配置--help,-h: 输出帮助--version,-v: 输出版本
exec、upload、download 默认使用 Rust daemon 连接缓存,用于减少连续操作时重复 SSH 握手和认证的开销;只有传入 --no-cache 时才会跳过缓存并直连。缓存相关参数如下:
--no-cache: 跳过 Rust daemon 连接缓存,本次命令独立建立并关闭连接,即直连模式--cache-ttl <ms>: 设置 Rust daemon 连接缓存空闲毫秒数,默认180000--json:exec、upload、download输出结构化 JSON(字段exitCode/stdout/stderr),便于脚本和 AI 解析
所有参数(--no-cache、--cache-ttl、--json、--timeout、--pty 等)必须放在连接名(第一个位置参数)之前,相互之间可任意顺序混排;放在连接名之后会被当作命令内容的一部分而报「不支持的参数」,命令请用引号包裹。
init-config
生成默认配置文件到 ~/.agent-ssh-cli/config.json(已存在时不覆盖):
agentsshcli init-config
list
列出配置中的服务器。
agentsshcli list
agentsshcli list --json
参数:
--json: 输出 JSON 格式。当前默认输出也是 JSON。--config <path>: 指定配置文件
返回值:
- 成功时 stdout 输出服务器数组,只包含
name、host、port、username - 不输出密码、私钥、passphrase、黑白名单等敏感或控制字段
- 退出码为
0
示例输出:
[
{
"name": "服务器",
"host": "192.0.2.10",
"port": 22,
"username": "root"
}
]
exec
在远端执行命令。
位置参数形式:
agentsshcli exec "<connectionName>" "<command>"
agentsshcli exec --no-cache "<connectionName>" "<command>"
agentsshcli exec --cache-ttl 60000 "<connectionName>" "<command>"
agentsshcli exec --pty "<connectionName>" "<command>"
agentsshcli exec --no-pty "<connectionName>" "<command>"
命名参数形式:
agentsshcli exec --connection "<connectionName>" --command "<command>" --directory "/root" --timeout 5000
agentsshcli exec --connection "<connectionName>" --command-file "./script.sh" --timeout 5000
agentsshcli exec --no-cache --connection "<connectionName>" --command "<command>"
参数:
<connectionName>: 连接名<command>: 远端命令--connection <name>,-c <name>: 连接名--command <command>: 远端命令--command-file <path>: 从本地 UTF-8 文件读取内容作为远端命令执行(不是先上传再执行),适合执行多行脚本;文件必须使用 LF 换行,不能使用 Windows CRLF 换行;不能和--command或位置参数<command>同时使用--directory <dir>,-d <dir>: 远端工作目录--timeout <ms>,-t <ms>: 超时毫秒值,默认30000--pty: 本次命令分配伪终端,优先级高于配置文件--no-pty: 本次命令不分配伪终端,优先级高于配置文件--json: 输出结构化 JSON(exitCode/stdout/stderr)--no-cache: 不复用连接,必须放在连接名或--connection前--cache-ttl <ms>: 连接缓存空闲毫秒数,必须放在连接名或--connection前
使用 --command-file 时,必须确保脚本文件是 LF 换行。CRLF 文件会把 \r 传到远端 bash,可能导致 $'xxx\r': command not found。
macOS/Linux 推荐写法:
cat > /tmp/remote-command.sh <<'EOF'
pwd
EOF
agentsshcli exec --connection "<connectionName>" --command-file /tmp/remote-command.sh
Windows PowerShell 推荐显式写 LF:
[System.IO.File]::WriteAllText("$env:TEMP\remote-command.sh", "pwd`n", [System.Text.UTF8Encoding]::new($false))
agentsshcli exec --connection "<connectionName>" --command-file "$env:TEMP\remote-command.sh"
返回值:
- 成功且有 stdout 时,stdout 输出远端命令结果
- 成功但无 stdout 时不输出内容
- 退出码为
0 - 远端命令非零退出、超时、命中黑名单、未命中白名单或连接失败时,stderr 输出错误信息,退出码为
1 --json模式下输出 JSON,exitCode为远端命令真实退出码(非零表示命令失败),stdout/stderr如实返回远端输出;命令失败时进程退出码仍为1
注意事项:
- 命令里使用
pkill -f/pgrep -f时,匹配串会命中执行该命令的远端 shell 自身(命令行包含该字符串),导致 shell 被杀、命令中断且无输出。需要排除自身时用正则技巧,如pkill -f 'name[.]log'。 - 远端会话被异常终止(shell 被杀等)时,会报
[remote] 会话异常终止(无退出状态),不会静默返回成功。 - 命令末尾启动后台进程且不重定向 stdout 时,远端不会关闭通道,命令会等到总超时;如需后台运行请把 stdout/stderr 重定向到文件(如
> /tmp/x.log 2>&1 < /dev/null &)。 - 命令请用引号包裹(如
--command "<command>"或位置参数"<command>"):命令内容里独立的--json、--timeout等 token 会被当作 CLI 参数解析,未加引号时可能被误吞或报错。
upload
上传本地文件到远端。
位置参数形式:
agentsshcli upload "<connectionName>" "<localPath>" "<remotePath>"
agentsshcli upload --no-cache "<connectionName>" "<localPath>" "<remotePath>"
命名参数形式:
agentsshcli upload --connection "<connectionName>" --local "./tmp/upload.txt" --remote "/usr/local/test/upload.txt"
agentsshcli upload --no-cache --connection "<connectionName>" --local "./tmp/upload.txt" --remote "/usr/local/test/upload.txt"
参数:
<connectionName>: 连接名<localPath>: 本地文件路径<remotePath>: 远端目标文件路径--connection <name>,-c <name>: 连接名--local <path>,-l <path>: 本地文件路径--remote <path>,-r <path>: 远端目标文件路径--timeout <ms>: 总超时毫秒值,默认不限制(大文件允许长时间运行),与exec的默认 30s 不同--recursive: 递归上传目录,保持相对路径;符号链接不跟随——指向目录的链接跳过(防循环),指向文件的链接上传其内容--json: 输出结构化 JSON--no-cache: 不复用连接,必须放在连接名或--connection前--cache-ttl <ms>: 连接缓存空闲毫秒数,必须放在连接名或--connection前
上传稳定性:
- 上传会先写入远端
<remotePath>.part临时文件,完成校验后再 rename 为正式目标文件。 - 同时写入
<remotePath>.part.meta续传元数据;本地文件大小、修改时间或分块大小变化时,会删除旧临时文件并重传,避免错误拼接。 - 如果上传中断,下次上传同一个本地文件到同一个远端路径时,会从
.part已有大小处断点续传。 --no-cache模式可用Ctrl+C停止当前上传;daemon 模式可用stop-daemon粗暴停止连接池,但它会影响同一 daemon 内其它任务,不是精确取消单个上传。
返回值:
- 成功时 stdout 输出
File uploaded successfully - 退出码为
0 - 本地文件不存在、远端写入失败或连接失败时,stderr 输出错误信息,退出码为
1 --json模式下成功时 stdout 为{"exitCode":0,"stdout":"File uploaded successfully","stderr":""},失败时exitCode为1
download
下载远端文件到本地。
位置参数形式:
agentsshcli download "<connectionName>" "<remotePath>" "<localPath>"
agentsshcli download --no-cache "<connectionName>" "<remotePath>" "<localPath>"
命名参数形式:
agentsshcli download --connection "<connectionName>" --remote "/usr/local/test/upload.txt" --local "./tmp/download.txt"
agentsshcli download --no-cache --connection "<connectionName>" --remote "/usr/local/test/upload.txt" --local "./tmp/download.txt"
<connectionName>: 连接名<remotePath>: 远端文件路径<localPath>: 本地目标文件路径--connection <name>,-c <name>: 连接名--remote <path>,-r <path>: 远端文件路径--local <path>,-l <path>: 本地目标文件路径--timeout <ms>: 总超时毫秒值,默认不限制(大文件允许长时间运行),与exec的默认 30s 不同--recursive: 递归下载目录,保持相对路径;远端符号链接跳过--json: 输出结构化 JSON--no-cache: 不复用连接,必须放在连接名或--connection前--cache-ttl <ms>: 连接缓存空闲毫秒数,必须放在连接名或--connection前
下载稳定性:
- 下载会先写入本地
<localPath>.part临时文件,并写入<localPath>.part.meta续传元数据;完成后校验大小再 rename 为正式目标文件。 - 下载中断后,下次下载同一个远端文件到同一个本地路径会从已有
.part大小继续;远端文件特征变化时自动删除旧.part重新下载。
返回值:
- 成功时 stdout 输出
File downloaded successfully - 退出码为
0 - 本地写入失败、远端读取失败或连接失败时,stderr 输出错误信息,退出码为
1 --json模式下成功时 stdout 为{"exitCode":0,"stdout":"File downloaded successfully","stderr":""},失败时exitCode为1
stop-daemon
停止当前配置文件对应的 SSH 缓存进程(连接池)。它是连接池维护命令,不是精确取消单个上传任务,会影响同一 daemon 内其它任务:
agentsshcli stop-daemon [--config <path>]
help/version
agentsshcli --help
agentsshcli help list
agentsshcli help exec
agentsshcli help upload
agentsshcli help download
agentsshcli --version
返回值:
- help 成功时 stdout 输出帮助文本,退出码为
0 - version 成功时 stdout 输出版本号,退出码为
0
错误规则
- 参数重复时失败
- 命名参数和位置参数不能混用同一字段
--no-cache和--cache-ttl必须放在exec、upload、download后、连接名或--connection前timeout和cache-ttl必须是正整数毫秒值list不接受位置参数upload/download的本地路径按传入路径解析,不再限制在当前工作目录、项目目录或allowedLocalPaths内- 出现
启动 SSH 缓存进程失败通常表示本地 Rust daemon 或其 socket 启动/握手失败;如需绕过缓存验证远端命令,应在子命令后添加--no-cache - 所有失败统一在 stderr 输出错误信息,退出码为
1