# 使用說明

> HTML: https://remote.ivjn.us/docs/zh-TW/usage/

這條路徑面向操作員：拿到命令列和裝置端，登入，新增一臺裝置，讓裝置連上，然後執行一條遠端命令並開啟 shell。瀏覽器控制台、手機控制台、Android 裝置端、配對和自更新見文末連結，這裡不重複那些頁面的步驟。

示例裡的地址和令牌請換成你自己的。令牌只在建立時出現一次，不要把它寫進倉庫。

**多重身分與帳號授權。** 全域 `--profile <name>` 優先於 `REMOTE_CLI_PROFILE`。命名身分將 `config.toml`、密封身分私鑰、根信任及 grants 快取儲存在 `<config_base>/remote-cli/profiles/<name>/`；`config_base` 沿用 XDG_CONFIG_HOME、HOME/.config 或 Windows APPDATA。名稱限 1–64 個 ASCII 字母、數字、點、連字號或底線，不能為 `.` 或 `..`。命名 profile 優先於 `REMOTE_CLI_CONFIG`；未指定 profile 時，原有設定路徑及 `REMOTE_CLI_CONFIG` 行為不變。各 profile 分別登入，後續呼叫須選取相同 profile。

`operator set` 接受帳號 ID 或唯一名稱；裝置參數為裝置 ID。`--restricted` 僅顯示明確授權裝置，`--unrestricted` 恢復依角色決定的範圍。僅超級管理員可修改範圍；角色與裝置授權由超級管理員管理，沒有超級管理員時管理員可在允許範圍內管理，不能修改自身。`operator grant list` 僅傳回呼叫者可見的授權。資料庫裝置授權與密封簽章授權是兩層檢查：修改 grant 不能取代 `seal approve`。建立介面目前不支援原子設定範圍，請先保存 `operator add` 傳回的一次性權杖，再執行 `operator set` / `operator grant set`；這些是獨立請求。

所有 operator 動詞支援 `-o text|json|xml`。JSON 請求使用 `op=list|add|set|grant_list|grant_set|grant_remove`；`set` 接受 `operator` 與可選 `role` / `restricted`（至少一個），`grant_set` 接受 `operator`、`device` 與必填布林值 `can_manage`。`grant_list` 可選 `operator`，`grant_remove` 接受 `operator` 與 `device`。`--json` 不與子命令混用。

```bash
remote-cli --profile alice login --server https://exchange.example.com
remote-cli --profile root operator set alice --restricted
remote-cli --profile root operator set alice --role readonly
remote-cli --profile root operator grant list --operator alice -o json
remote-cli --profile root operator grant set alice lab --view
remote-cli --profile root operator grant set alice lab --manage
remote-cli --profile root operator grant remove alice lab
remote-cli --profile root operator set alice --unrestricted
remote-cli --profile root operator --json '{"op":"grant_set","operator":"alice","device":"lab","can_manage":false}' -o json
```


## XML 請求與輸出

先用 `remote-cli --help` 檢查安裝版本是否支援新選項。`--xml` 與 `--xml-file` 為既有 `--json` / `--json-file` 請求入口增加 XML 輸入；四個輸入選項互斥，仍是完整請求內容，不可混用相同命令的選項或子命令，裝置位置參數規則不變。輸入與輸出獨立選擇，`-o text|json|xml` 預設使用文字。

```powershell
remote-cli device --xml '<request><op>list</op></request>' -o xml
remote-cli exec my-device --xml-file request.xml -o xml
```

沒有子元素時預設為字串，有子元素時預設為物件。數字、布林值、陣列、空值分別使用 `type="number"`、`type="boolean"`、`type="array"`、`type="null"`；陣列子元素必須為 `<item>`，空物件使用 `type="object"`。任意鍵可用 `<field name="arbitrary key">value</field>`，空請求使用 `<request type="object"/>`。

```xml
<request>
  <command>echo hello</command>
  <timeout_secs type="number">30</timeout_secs>
  <hold type="boolean">false</hold>
  <env><GREETING>hello &amp; welcome</GREETING></env>
</request>
```

輸出根節點為 `<response type="...">`，物件成員為 `<field name="..." type="...">`，陣列成員為 `<item type="...">`。型別明確保留，文字按 XML 1.0 跳脫。執行階段錯誤回傳 `ok=false` / `error` 且結束代碼非零；命令列語法錯誤仍由參數解析器寫入 `stderr`。

XML 輸出支援 `device list/update`, `operator list/add/set/grant`, `exec`, `session list/kill`, `ui`, `ubus`, `sensors`, `net`, `metrics`, `preset`, `audit`, `browser`，包括 exec 作業操作。其他命令選擇 `-o xml` 時明確報錯；仍可使用 XML 請求和原有輸出格式。

串流 `exec` / `sensors --live` / `browser session` 每行輸出一份獨立 XML 文件，請逐行解析。exec 資料事件包含 `stream` / `encoding=base64` / `data`，Base64 保留原始位元組，一般 exec 最後回傳結束狀態。`browser session` 的互動輸入仍為 JSON Lines。`ui xml` 未指定 `-o xml` 時保留原始 UI 階層 XML。

請求上限為 1 MiB，巢狀深度上限為 64 層；拒絕重複欄位、混合文字與子元素、DTD 和外部實體。XML 1.0 無法表示的控制字元會導致輸出錯誤，需要保留這類文字時請選擇 JSON。Agent 設定和網路協定仍為 JSON，XML 僅轉換 CLI 輸入與輸出。

## 拿到 remote-cli 和 remote-agent

在倉庫根目錄建置：

```bash
cargo build --release
```

命令列是 `target/release/remote-cli`。同一命令也會編出 `target/release/remote-agent`。給 flash 緊張的裝置用體積優先的 agent：

```bash
cargo build -p agent --no-default-features --profile release-small
```

產物是 `target/release-small/remote-agent`。

Windows、Linux、macOS 也可以用網站上的安裝指令碼一次裝好其中一個二進位，說明在 [多平臺裝置部署](/docs/zh-TW/platform-installation.md#一條命令安裝windows--linux--macos--freebsd--netbsd)。下面的命令假定 `remote-cli` 和 `remote-agent` 已經在 `PATH` 裡；若剛在本機編出來，改用上面的 `target/...` 路徑。

自建中轉服務時，先按 [開發說明](/docs/zh-TW/development.md) 用 `DATABASE_URL` 啟動 `exchange`，從啟動紀錄拿到管理員令牌。使用公共例項時，向管理員要運維令牌即可。

## 登入

```bash
remote-cli login --server http://127.0.0.1:8080 --token '<运维令牌>'
```

`--server` 填 `http://` 或 `https://`。命令列會按同樣的安全級別推導 WebSocket 地址：`https` 對應 `wss`，`http` 對應 `ws`。

登入成功後，設定寫在：

- Linux / macOS：`$XDG_CONFIG_HOME/remote-cli/config.toml`，未設定 `XDG_CONFIG_HOME` 時為 `~/.config/remote-cli/config.toml`
- Windows：`%APPDATA%\remote-cli\config.toml`

檔案裡只有兩個鍵：`server` 和 `token`。要用別的路徑時設定 `REMOTE_CLI_CONFIG`。之後的 `device`、`exec`、`shell` 都讀這份設定，不必每次再傳令牌。

## 新增裝置

```bash
remote-cli device add lab-router --name "实验室路由"
```

`<id>` 是裝置 ID，只能含字母、數字和 `-` `_` `.`，最長 64 個字元。`--name` 可省略，省略時顯示名與 ID 相同。命令輸出裡的裝置令牌只顯示這一次。

## 啟動 agent

在要被管理的機器上啟動裝置端，並帶上伺服器端、裝置 ID 和剛才的裝置令牌：

```bash
remote-agent --server wss://127.0.0.1:8080 --device-id lab-router --token '<设备令牌>'
```

三個參數也可以用環境變數：`REMOTE_SERVER`、`REMOTE_DEVICE_ID`、`REMOTE_TOKEN`。

`--server` 必須以 `ws://` 或 `wss://` 開頭。只寫主機（例如 `wss://mgmt.example.com`）時，agent 會自動補上 `/ws/device`；已經寫了路徑則原樣使用。本機 exchange 若沒有 TLS，用 `ws://127.0.0.1:8080`。

不想把令牌放在程序參數裡時，寫一份 JSON，鍵名為 `server`、`device_id`、`token`：

```json
{
  "server": "wss://mgmt.example.com",
  "device_id": "lab-router",
  "token": "<设备令牌>"
}
```

然後 `remote-agent --config /path/to/config.json`。桌面系統的安裝與自啟動見 [多平臺裝置部署](/docs/zh-TW/platform-installation.md)。

`remote-cli` 與 `remote-agent` 的 WebSocket 都按 `HTTPS_PROXY` / `https_proxy` → `ALL_PROXY` / `all_proxy` → `HTTP_PROXY` / `http_proxy` 讀取代理，並遵守 `NO_PROXY` / `no_proxy`；agent 無介面和 `--ui` 模式使用同一連線路徑。代理須支援 HTTP CONNECT（不支援 SOCKS），WSS 的 ALPN 僅宣告 `http/1.1`。後臺服務請在服務環境中設定變數，詳見 [出站代理與連線保活](/docs/zh-TW/platform-installation.md#出站代理與連線保活)。

裝置連上之後：

```bash
remote-cli device list
```

列表裡能看到這臺裝置的線上狀態。

## 執行遠端命令

`--` 後面的內容交給裝置，不再由本機命令列解析：

```bash
remote-cli exec lab-router -- uname -a
```

`--` 後面給幾個參數，決定了遠端怎麼理解它們：

- **多個參數**按 argv 原樣傳過去，每個參數的邊界都保留，和在裝置上直接敲這幾個參數效果一樣。需要時 CLI 會自動加引號（Windows 裝置按 PowerShell 規則）。
- **只有一個參數**時，整串交給裝置的 shell 當命令列解析，可以用管道、`;`、萬用字元和變數。

```bash
remote-cli exec lab-router -- sh -c 'uname -a; cat /proc/uptime'   # 多个参数，第三个参数完整交给 sh -c
remote-cli exec lab-router -- 'dmesg | tail -20'                    # 一个参数，管道在设备上执行
```

注意：多參數形式下，本機 shell 原樣傳過來的 `*`、`$VAR`（在 PowerShell 裡很常見）會被當作字面量，不會在遠端展開。想讓裝置來展開，就寫成單個參數，例如 `-- 'ls /etc/*.conf'`。

exec 預設開啟 hold：逾時預設 3600 秒（硬上限 86400 秒），運維端斷開只分離輸出，不殺作業。用 `--timeout` 指定時限，例如 `remote-cli exec lab-router --timeout 120 -- uname -a`；`--hold-timeout` 可覆蓋 hold 時限。加 `--no-hold` 恢復運維端斷開即取消的行為，預設逾時 60 秒。命令正常回傳時，其退出碼會成為 `remote-cli` 的退出碼。

### 檢視和終止作業、釋放會話槽位

```bash
remote-cli exec-holds lab-router
remote-cli exec-hold-kill lab-router <job_id>
remote-cli exec-hold-tail lab-router <job_id>
remote-cli exec-hold-cat lab-router <job_id>
remote-cli exec-attach lab-router <job_id>
remote-cli sessions lab-router
remote-cli session-kill lab-router <session_id>
```

`exec-holds` 列出 exec 作業和正在進行的下載、上傳、目錄查詢，顯示 `job_id`、`kind`、`status`、`age_secs`、當前裝置側 `session_id`（如有）與截斷的命令/路徑摘要。`exec-hold-kill` 按作業編號終止程序組或中止檔案傳輸；tail、cat、attach 僅用於 exec 作業。

`sessions` 直接讀取 Exchange 路由表，顯示當前 `count/limit` 和裝置側會話編號。`session-kill` 使用這個**裝置側**編號，向裝置傳送取消指令並立即釋放 Exchange 槽位；即使裝置沒有回覆也能釋放。兩者不向裝置發起額外會話，不佔併發槽位，適合處理滿額卡住的會話；唯讀帳號不可使用。

exec 逾時會終止整個程序組，輸出排空及結束訊息傳送均有時間上限。Exchange 在達到併發上限時先自動回收失去運維端或超過截止時間的路由，再嘗試新會話：exec 截止時間為實際執行時限加 15 秒寬限，檔案傳輸為 3600 秒加 15 秒（裝置另有 30 秒空閒逾時），其它會話為 24 小時。hold exec 在截止時間內不會僅因運維端斷開而被殺；斷開仍然只是 detach。顯式 `session-kill` 或超過截止時間則會取消 hold 程序。

## 開啟 shell

```bash
remote-cli shell lab-router
```

這是裝置上的一個 PTY 會話，不是 SSH。退出 shell 即結束這次會話。

## 其它入口

- 瀏覽器控制台：[Web 控制台](/docs/zh-TW/web-console-and-notifications.md)
- 手機控制台：[移動用戶端](/docs/zh-TW/platform-installation.md)
- Android 裝置端 APK：[Android 獨立 APK](/docs/zh-TW/platform-installation.md#android-獨立-apk)
- 二維碼、六位碼和帳號：[初始化與配對](/docs/zh-TW/pairing-and-enrollment.md)
- 命令列與 agent 的自更新：[自更新](/docs/zh-TW/self-update.md)

## 端到端加密（密封會話）

`remote-cli exec <设备> -- <命令>`、`remote-cli shell <设备>` 使用端到端密封，無需額外引數，讓 Exchange 只轉發密文，看不到命令、輸出和終端內容；裝置只信任工作區根（超級管理員的金鑰，超級管理員登入時自動生成）以及根簽發的授權；根客戶端按賬號角色自動給成員簽發。詳見下文連結中的一次性設定。詳見 [端到端密封會話](/docs/zh-TW/sealed-sessions.md)。

所有 CLI 裝置會話只使用端到端密封，無需額外引數。缺少裝置能力資訊或密封握手失敗時，不會改用明文。LAN 直連和瀏覽器操作使用相同的密封要求。

## 持久背景工作

宣告 `tasks` 能力的 Agent 在裝置上執行單一操作或宣告式 DAG。提交後控制端斷線仍繼續執行；重新連線可查詢進度、輸出與本機產物。執行階段重新啟動會將未完成工作標為 `interrupted`，不會自動重播。

建立需要密封 `manage/owner` 授權。表單可設定相依項、固定條件、祖先結果的 JSON Pointer 參照、失敗策略及最多五次明確重試。重試可能重複產生副作用，取消不會復原。Web 與行動控制端支援表單和 JSON 匯入匯出；桌面、Android、瀏覽器及 LuCI 本機介面提供歷史、輸出、取消和刪除。

請先查詢操作目錄，平台支援及排除原因以裝置回傳為準。輸入檔案必須先暫存。預設保留 30 天、最多 1000 個工作、總預算 64 MiB、每工作文字 8 MiB、平行步驟 4（OpenWrt 為 2）；步驟預設逾時 30 分鐘，可設為 24 小時。舊 Agent 不顯示工作入口。
```sh
remote-cli task DEVICE operations
remote-cli task DEVICE create pipeline.json --wait
remote-cli task DEVICE list
remote-cli task DEVICE get TASK_ID
remote-cli task DEVICE logs TASK_ID --offset 0
remote-cli task DEVICE cancel TASK_ID
remote-cli task DEVICE upload ./input.bin
remote-cli task DEVICE download TASK_ID STEP.artifact ./result.json
remote-cli task DEVICE delete TASK_ID
```

## 服務託管

Task 的 Service 模式可託管原生前景命令，支援持久執行意圖、退出重啟策略、指數退避、啟動頻率限制及 Agent 重啟恢復。預設儲存為停止狀態；編輯或刪除前先停止並等待退出。授權到期或撤銷會停止服務。一般 DAG 重啟後仍不重放。Web、行動、本機桌面及 Android 可管理；LuCI 設定使用 Console 或 CLI。瀏覽器 Agent 不支援系統程序託管。

設定使用 command.command 或 command.argv，可設定 cwd/env、restart（never/on_failure/always）、start_secs、stop_grace_secs、backoff_secs、max_backoff_secs、restart_window_secs 與 max_starts。Windows 正常退出需提供 stop_command；Unix 預設 SIGTERM，寬限期後強制清理程序樹。Agent 開機執行須另行設定。service get 回傳 run_id，可用 task get/logs 檢視。

```sh
remote-cli task DEVICE service put worker.json
remote-cli task DEVICE service list
remote-cli task DEVICE service start worker
remote-cli task DEVICE service get worker
remote-cli task DEVICE service restart worker
remote-cli task DEVICE service stop worker
remote-cli task DEVICE service delete worker
remote-agent task service put worker.json
```
