# 執行工具

在前景或背景執行指令的工具。

| 工具 | 說明 |
|---|---|
| `run_command` | 以 argv 在前景執行程式（argv-only schema，透過 `go-pkg/sandbox` 包裹沙箱），行程結束後回傳合併的輸出。不含 shell metacharacter（`\|`、`&&`、`>`、`*`、`~`）的單純指令直接呼叫，不會被包進 sh；pipe、重導向與 globbing 需明確使用 `['sh','-c','...']`，其腳本會被逐指令解析驗證 —— 每個執行檔都必須是**裸指令名**，列於 `denied_command` 者一律拒絕。`['cd', ...]` 一律拒絕：工作目錄由使用者決定（在 TUI 以 `Shift+P` 設定），呼叫端改傳絕對路徑或 `['sh','-c','cd <dir> && <command>']` —— 原本會切換 `Executor.WorkDir` 的 agent `cd` 已移除於 v1.3.0；`rm` 會改為移入垃圾桶而非刪除（工作目錄內於 `auto` 下直接執行，`$HOME` 內其他位置會詢問，`$HOME` 外需系統密碼），在 `sh -c` 內則直接拒絕；macOS 上的 `open` 會被拒絕並指向 `open_file`，因為 sandbox 連不到啟動 app 的服務。每次呼叫上限 30 分鐘（`RUN_COMMAND_TIMEOUT`）；file watcher、預期超過 5 分鐘（`BACKGROUND_THRESHOLD_MIN`）的工作，或「跑完告訴我」「背景跑」一類需求，改走 `background_command`。自 v1.0.25 起沙箱預設關閉網路：需要連線的指令（`git clone` / `fetch` / `pull` / `push`、`npm` / `pip install`、`go mod download`、`curl`）須設定 `network: true`，而這類呼叫永不視為唯讀，因此 `safe` 下需確認，`auto` 下不跳提示直接執行。自 v1.3.2 起系統套件直接經 `run_command` 安裝：Linux → `['sudo','apt-get','install','-y','<pkg>']`（或 dnf / yum / pacman / apk），macOS → 帶 `sandbox: false` 的 `['brew','install','<pkg>']`，brew 一律不搭配 `sudo`。自 v1.3.3 起套件管理器取自 system prompt 的 `Host OS` 行（該行也列出作業系統版本），該行沒列出時才以 `command -v` 尋找。唯讀 allowlist（`configs/jsons/read_only_command.json`，v1.3.3 起為 532 筆，v1.3.0 移除 `cd` 後為 409 筆，並合併 `config.json` 的 `read_only_command`）上的指令跳過確認 gate：自 v1.0.25 起比對執行檔加上最多兩個後續參數（`git status`、`docker ps`、`kubectl get`、`ls`...），任一參數為敏感路徑時取消比對結果。v1.0.23 新增的專用唯讀指令工具（`run_command_readonly`，可並行執行）已於 v1.0.25 移除，短暫存在的 `run_script` 則從未進入正式版本；請改用 `run_command`；自 v1.3.3 起命中 allowlist 的呼叫並行執行，其餘循序執行。要寫到 `$HOME` 之外時，該次呼叫帶上 `write_paths`，經密碼驗證核准後才綁入。自 v1.3.2 起接受 argv `['sudo','<binary>', ...]`：不接受 sudo 旗標、不可巢狀 `sudo` / `su`，目標必須是不在 `denied_command` 上的裸執行檔名；它會觸發標示為 `sudo: <cmd>` 的確認，且一律要求輸入系統密碼（allow-all 模式下亦同；allow 規則也不能略過），之後在沙箱外以 `sudo -n <binary> ...` 執行；v1.3.11 起取消這類呼叫（此處或 `background_command`）時改送 `SIGTERM` 給 `sudo`，由它轉送給 root 指令，超過 2 秒的 `WaitDelay` 仍在執行才 kill `sudo`。`sudo rm` 會真的刪除，單純的 `rm` 仍移入垃圾桶。`sh -c` 內的 `sudo` 仍一律拒絕，錯誤訊息會指向 argv 形式。自 v1.3.0 起 `sandbox: false` 會在沙箱外以使用者的完整權限執行，此時 `network` 與 `write_paths` 不再作用；只適用於沙箱擋下、且 `network` 或 `write_paths` 都解決不了的權限錯誤（Homebrew 需要它，因為其自身的沙箱無法巢狀），每次呼叫都要求輸入系統密碼 —— allow 規則與 allow-all 都不能略過這道確認，無法收集密碼的 channel 會收到未執行的結果。沙箱內的指令因權限錯誤失敗、且沒有可經 `write_paths` 授予的 `$HOME` 外路徑時，結果附上的建議把離開沙箱視為最後手段（v1.3.11 起；v1.3.2 至 v1.3.10 是要求立即以 `sandbox: false` 重跑）：連線或認證失敗（`Permission denied (publickey)`、`could not resolve host`）→ 改用 `network: true` 或回報憑證問題；寫入 → 改用工作目錄下的路徑或 `write_paths`；確實需要系統 socket、裝置或服務，或目標為 root 擁有 → `sandbox: false` 或 argv `['sudo', ...]`；其餘情況回報被擋下的內容後停止。v1.3.11 起串流輸出與結果都會遮蔽密鑰，argv 含先前工具結果產生的遮罩值時以 `[Invalid]` 拒絕；需要金鑰的指令在同一次呼叫內讀取（`['sh','-c','set -a; . ./.env; set +a; curl ...']`）。自 v1.0.11 起 file watcher 在啟動前就被擋下：`--watch` / `--watch=...`、`chokidar` 執行檔，或解析後會跑到 watcher 的 `npm` / `pnpm` / `yarn` / `bun` script —— package script 會從 `package.json` 解析出來並最多往下追 4 層（v1.1.2 前為 5 層），`sh -c` 內的也一樣，且 v1.1.2 起已追過的 script 不再重複追 —— 因為 `run_command` 會等行程結束，而 watcher 永遠不會結束。自 v1.3.1 起錯誤訊息改為指向帶 `timeout_min` 的背景工具（v1.3.2 起為 `background_command`），或改跑 one-shot build |
| `background_command` | `run_command_background` 已更名為 `background_command`（移除於 v1.3.2）。v1.3.1 以 `run_command_background` 之名新增；v1.3.0 時同樣的行為是 `run_command` 的背景模式，現在 `run_command` 只在前景執行。參數與 `run_command` 相同（`argv`、`network`、`write_paths`、`sandbox`；v1.3.8 起另有 `objective` 與 `next`），沙箱、確認、唯讀 allowlist 與 allow 規則的檢查也相同，呼叫後立即回傳 task id，當輪繼續進行。用於 file watcher（只能在這裡跑）、幾乎確定超過 5 分鐘且輸出不影響下一步工具呼叫的工作，或「跑完告訴我」「背景跑」。`timeout_min`（1-60，預設 60）到時終止指令並回報逾時；最終回報保留輸出的最後 31 KiB。輸出一律受監看：新輸出行含有 `keywords` 其中之一（不分大小寫；預設 `error`、`err!`、`fail`、`fatal`、`panic`、`exception`、`traceback`、`segmentation fault`、`core dumped`、`out of memory`、`permission denied`、`command not found`、`no such file`）時，待輸出穩定（安靜 2 秒，最多等 10 秒）後回報最新輸出（上限 8 KiB），指令繼續執行，每 30 秒最多回報一次。設定 decision model 時，先由 decision 檢查剔除無害的命中（例如 `0 errors`）與重複上次回報的內容；檢查失敗時不經檢查直接送出，並註明檢查失敗。未設定 decision model 時每次命中都會回報。`interval` 與 `prompt` 參數已移除於 v1.3.2；請改用 `keywords`。指令執行期間輸出會附加到 `~/.config/agenvoy/sessions/<session>/background/<task id>.log`，指令結束即刪除；啟動結果會給出該路徑，並要求 agent 被問到進度時先以 `read_files` 讀取其尾端。請求不是來自 TUI（`cli-` origin 且沒有 deliver target）時排除 —— v1.3.2 起不再取決於是否設定 decision model。每個 session 最多同時執行 `MAX_BACKGROUND_TASKS` 個背景任務（`DEFAULT_CONCURRENCY`：CPU 核心數的一半，至少 3），與 `background_subagents` 共用。v1.3.8 起同一回合開的 leg 組成一組：發起的任務執行中或 pending 時報告送進該任務；任務結束後，整組 leg 全部完成才以 `objective`＋`next`＋所有報告另開新任務（先前是每個背景任務完成後各自接回原任務）。暫停或取消發起的任務會停止其 leg；單一 leg 可從 TUI 的 `Esc` 選單取消 |

`pkg_manage` 已移除於 v1.3.2；請改用帶 argv `['sudo', ...]`（Linux 套件管理器）或 `sandbox: false`（Homebrew）的 `run_command`。
