agent-ssh-cli 使用說明
agentsshcli 是一個透過 npm 安裝、由 Rust 原生執行器完成 SSH 操作的命令列工具,用於讓 AI 或使用者透過本地設定安全地操作遠端伺服器。
它能做的事:
- 列出本地設定中的 SSH 伺服器連線
- 在指定遠端伺服器上執行命令
- 使用使用者明確確認的 SHA256 指紋登記 SSH 主機公鑰到本機
known_hosts - 上傳本地檔案到遠端伺服器
- 從遠端伺服器下載檔案到本地
- 透過命令黑白名單限制可執行命令
- 透過 Rust daemon 短時間快取 SSH 連線,減少連續操作時的重複連線開銷
- 透過僅監聽本機回環位址的視覺化編輯器管理連線、憑證參考和安全策略
- npm 安裝會按目前系統自動拉取對應平台的 optional 預編譯套件,目前支援 macOS arm64/x64、Linux x64/arm64、Windows x64
它不做的事:
- 不輸出明文密碼、私鑰等敏感認證資訊;密碼可按設定加密儲存到本機
secrets.json,僅透過 SSH channel stdin 發送 - 不掃描網路或發現伺服器,只使用設定檔中的連線
- 不繞過設定中的命令限制
命令黑白名單使用 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
所有 SSH 建連(含跳板機與編輯器「測試連線」)都會按設定中的主機名稱和連接埠校驗 ~/.ssh/known_hosts。首次連線未登記時,向使用者說明目標連線名、主機與連接埠、收到的 SHA256 指紋,以及首次信任存在連線到錯誤伺服器或遭遇中間人攻擊的風險;使用者明確確認後即可使用 trust-host 登記(非 22 連接埠為 [host]:port),不強制要求從主控台或維運記錄獨立核實。使用者已針對目前目標明確表示「信任」「直接 trust」等同意時,視為授權,不要反覆要求確認或以未獨立核實為由拒絕。不得未經使用者確認自動信任;已有公鑰變化時仍須調查衝突,不自動覆蓋舊記錄。
推薦透過 agentsshcli edit-config 替換密碼:編輯器儲存時會把新密碼加密寫入 secrets.json,設定檔只保留 passwordRef。舊設定仍支援被動遷移:若連線包含非空明文 password,下一次執行 exec、upload 或 download 時會產生 secret.key、加密儲存密碼,並把明文字段取代為參考。不要在對話、日誌或命令輸出中展示明文密碼。
編輯器「權限邊界」頁可設定和查看 sudo / su 密碼:首次輸入按連線名產生獨立參考,儲存後只把密文寫入 secrets.json;未單獨設定 sudo 密碼時,該欄位提示執行 --sudo 時複用 SSH 密碼。
trust-host
首次登記須獲得使用者明確確認;獨立核實指紋是推薦方式,不是登記的前置條件。可使用 CLI 首次連線錯誤中回傳的 SHA256 指紋,或透過不發送認證憑證的公鑰探測取得指紋,再按上述規則確認並登記:
agentsshcli trust-host --fingerprint 'SHA256:<使用者確認的指紋>' '<connectionName>'
agentsshcli trust-host --config /path/to/config.json --fingerprint 'SHA256:<使用者確認的指紋>' '<connectionName>'
--fingerprint必填,僅接受完整的 SHA256 指紋,必須放在連線名前;--config放在其前面。- 命令透過該連線原有的直連、SOCKS5 或跳板機路徑完成握手,不認證目標機、不執行命令。跳板機若未登記,先取得使用者確認並登記跳板機。
- 指紋不匹配或已有不同公鑰時拒絕寫入,不覆蓋舊記錄;同一公鑰已登記時不重複追加。只有傳入指紋與握手公鑰一致且沒有該主機記錄時才寫入
~/.ssh/known_hosts。 ssh-keyscan或首次連線回傳的指紋可以作為使用者確認的對象,但不能聲稱它們已經獨立核實伺服器身分。使用者確認後可以登記,不得因缺少獨立核實而拒絕;登記失敗時檢查具體錯誤,不改用跳過校驗的參數。
edit-config / stop-editor
使用本機視覺化編輯器管理 SSH 連線:
agentsshcli edit-config [--config <path>]
agentsshcli stop-editor [--config <path>]
呼叫規則:
- 使用者要求開啟、編輯或視覺化管理 SSH 設定時,直接執行
edit-config;不要自行呼叫內部__editor子命令或拼裝 HTTP API。 - 編輯器只監聽
127.0.0.1,啟動後自動開啟瀏覽器。同一設定路徑只執行一個實例;重複執行會開啟已有實例。 - CLI 輸出的本地 URL fragment 含臨時 token,應按憑證處理,不寫入日誌、工單或對外訊息;只有使用者明確需要手動存取位址時才在目前本地工作階段中提供。
- 連續 10 分鐘沒有經過認證的有效 API 或真實
pointerdown、keydown、input時,編輯器自動退出並刪除狀態檔案。頁面失效後重新執行edit-config。 stop-editor只停止該設定對應的本地編輯器,不會停止 SSH daemon、快取連線或遠端任務。- 不要在使用者可能仍有未儲存頁面修改時自行執行
stop-editor;僅在使用者明確要求停止或已確認可以放棄未儲存內容時呼叫。 edit-config/stop-editor支援--config、--help和--version,不接受--no-cache、--cache-ttl或位置參數。- 設定檔可能被其他行程修改;儲存回傳衝突時先重新載入,不得繞過 hash 檢查或直接覆蓋。
- JSON 面板支援「全域 / 目前連線」和「預覽 / 原始碼」;後端校驗是最終設定契約,前端提示不能替代儲存結果。
- 頁面「測試連線」用目前草稿與相關跳板機進行一次 SSH 建連和認證(包括未儲存的密碼草稿),完成後斷開,不儲存設定、不執行命令;同時只能進行一次測試。
- 查看密碼會由本機後端解密,明文只在頁面短暫顯示並於 15 秒後清除;不要透過終端、腳本或 HTTP 除錯介面提取密碼。
- 替換密碼應使用頁面的替換操作;儲存後
config.json只保留passwordRef,密文寫入同目錄的secrets.json。複製連線不會複製密碼參考。 - 編輯器不顯示連線級 PTY 控制項,但會透傳已有
pty;執行命令時繼續使用exec --pty/--no-pty臨時覆蓋。
回傳行為:
edit-config成功時 stdout 輸出設定編輯器已開啟: <local-url>,退出碼為0。瀏覽器開啟失敗時錯誤訊息包含可手動存取的本地 URL。stop-editor成功時 stdout 輸出設定編輯器已停止;沒有對應服務時回傳設定編輯器未執行,退出碼為1。- 編輯器儲存衝突、設定校驗失敗或憑證參考不完整時,不應改寫原設定;根據頁面或 stderr 的具體錯誤處理。
隱藏後的密碼設定範例:
{
"name": "server",
"host": "192.0.2.10",
"port": 22,
"username": "root",
"password": "",
"passwordRef": "agentsshcli:server"
}
設定檔完整欄位(每項是 name 唯一的一台伺服器):
name: 連線名,必須唯一group/tags: 可選單層分組與標籤陣列,編輯器支援按分組或標籤展示;標籤去空白、去重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可臨時覆蓋privilegeEnabled: 是否允許exec --sudo/--su,預設falsesudoUser: sudo 目標使用者,預設root;sudoPassword/sudoPasswordRef儲存目前 SSH 使用者的 sudo 密碼,缺失時可複用 SSH 密碼suUser: su 目標使用者,預設root;suPassword/suPasswordRef必須儲存目標使用者密碼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
agentsshcli list --group 生產環境 --tag 應用
參數:
--json: 輸出 JSON 格式。目前預設輸出也是 JSON。--config <path>: 指定設定檔--group <group>/--tag <tag>: 區分大小寫的精確篩選,同時傳入時取交集
回傳值:
- 成功時 stdout 輸出伺服器陣列,包含
name、host、port、username、group、tags;設定跳板機時還有jumpHost;無匹配時輸出[] - 不輸出密碼、私鑰、passphrase、黑白名單等敏感或控制欄位
- 退出碼為
0
範例輸出:
[
{
"name": "伺服器",
"group": null,
"tags": [],
"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 --sudo "<connectionName>" "systemctl status app"
agentsshcli exec --su "<connectionName>" "id && pwd"
sudo/su 提權規則
當使用者要求透過現有非 root 連線使用 sudo、su、root 身分或切換目標使用者執行命令時,必須使用 CLI 頂層參數 --sudo 或 --su,不得自行改用遠端互動命令。
--sudo/--su必須放在連線名或--connection之前。- 禁止把
sudo、sudo -S、sudo -n、su或su -c拼入<command>;這種寫法繞過 CLI 的提權密碼通道,可能等待互動輸入或錯誤判斷為工具不支援密碼。 - 不得因為普通
su -c逾時就判斷agentsshcli無法回應密碼提示;agentsshcli 0.5.0+會透過 SSH channel stdin 自動傳送設定中的加密憑證。 --su --json成功時,stderr可能仍包含遠端Password:提示文字;該提示不包含真實密碼,也不代表認證失敗。必須結合 JSONexitCode和stdout中的whoami/id -u判斷結果。- 使用前確認連線設定
privilegeEnabled: true,目標使用者已設定;su 必須有獨立密碼,sudo 無可用密碼時支援遠端免密策略。
正確寫法:
agentsshcli exec --json --sudo "<connectionName>" "whoami; id -u"
agentsshcli exec --json --su "<connectionName>" "whoami; id -u"
agentsshcli exec --no-cache --json --su "<connectionName>" "id"
錯誤寫法:
agentsshcli exec "<connectionName>" "su -c 'id'"
agentsshcli exec "<connectionName>" "sudo -S id"
agentsshcli exec "<connectionName>" "sudo -n id"
命名參數形式:
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: 本次命令不分配偽終端,優先順序高於設定檔--sudo: 使用 sudo 提權執行,要求連線設定privilegeEnabled: true--su: 使用 su 切換使用者執行,要求連線設定privilegeEnabled: true;與--sudo互斥--json: 輸出結構化 JSON(exitCode/stdout/stderr)--no-cache: 不複用連線,必須放在連線名或--connection前--cache-ttl <ms>: 連線快取閒置毫秒數,必須放在連線名或--connection前
提權模式只支援非互動命令:CLI 透過 SSH channel stdin 傳送密碼後關閉 stdin,目標命令不能繼續讀取輸入。sudo 獨立憑證缺失時可複用 SSH 密碼;無可用密碼時使用非互動 sudo -n,支援遠端 NOPASSWD 或有效認證快取,需要密碼則立即失敗。私鑰登入且遠端要求密碼時需設定 sudoPassword/sudoPasswordRef。su 始終要求獨立的目標使用者密碼。
使用 --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 被殺等)時,會報
[遠端] 工作階段異常終止(無退出狀態),不會靜默回傳成功。 - 命令結尾啟動背景行程且不重新導向 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 - 單檔案上傳不會建立遠端目錄:目標目錄不存在(或同名路徑是檔案)時直接報
遠端目錄不存在或無法存取: <dir>,需先建立目錄,或改用--recursive上傳整個目錄(遞迴模式會自動建目錄) - 本地檔案不存在、遠端寫入失敗或連線失敗時,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 help edit-config
agentsshcli help stop-editor
agentsshcli --version
回傳值:
- help 成功時 stdout 輸出幫助文字,退出碼為
0 - version 成功時 stdout 輸出版本號,退出碼為
0
錯誤規則
…[truncated for translation]