# 執行工具

執行指令與管理套件的工具。

| 工具 | 說明 |
|---|---|
| `run_command` | 以 argv 執行程式（argv-only schema，透過 `go-pkg/sandbox` 包裹沙箱）。不含 shell metacharacter（`\|`、`&&`、`>`、`*`、`~`）的單純指令直接呼叫，不會被包進 sh；pipe、重導向與 globbing 需明確使用 `['sh','-c','...']`，其腳本會被逐指令解析驗證 —— 每個執行檔都必須是**裸指令名**，列於 `denied_command` 者一律拒絕。`['cd','<path>']` 為特例，驗證路徑後會變更 `Executor.WorkDir`；`rm` 會改為移入垃圾桶而非刪除，在 `sh -c` 內則直接拒絕；macOS 上的 `open` 會被拒絕並指向 `open_file`，因為 sandbox 連不到啟動 app 的服務。每次呼叫上限 30 分鐘（`RUN_COMMAND_TIMEOUT`）。自 v1.0.25 起沙箱預設關閉網路：需要連線的指令（`git clone` / `fetch` / `pull` / `push`、`npm` / `pip install`、`go mod download`、`curl`）須設定 `network: true`，而這類呼叫永不視為唯讀，一律經過確認 gate。安裝或移除系統套件（含 Homebrew）走 `pkg_manage`，不走 `run_command`。唯讀 allowlist（`configs/jsons/read_only_command.json`，410 筆，並合併 `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`，它一律循序執行。要寫到 `$HOME` 之外時，該次呼叫帶上 `write_paths`，經密碼驗證核准後才綁入。`sudo` 一律拒絕（無論單獨執行或在 `sh -c` 內），並提示去掉 `sudo` 改宣告 `write_paths`，由此觸發 sudo 確認。自 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 永遠不會結束。錯誤訊息會指出該改跑哪個 one-shot build |
| `pkg_manage` | 在沙箱**外**驅動系統套件管理器 —— Linux：apt / dnf / yum / pacman / apk；macOS：Homebrew —— 讓 `bwrap` 無法授予的 root 操作與 Homebrew 自身的巢狀沙箱仍可運作。`action` 為 `install` / `remove` / `update` / `upgrade` / `search` / `info`；`package` 只接受裸套件名 —— 不帶旗標、不指定版本、不接受第二個套件 —— 除 `update` 與 `upgrade` 外皆為必填。在 Linux 與 macOS 註冊（macOS 自 v1.2.0 起）。Linux 上 `install` / `remove` / `update` / `upgrade` 除非 daemon 本身為 root，否則經 `sudo -n` 執行並觸發需密碼的確認；macOS 上 `brew` 不經 `sudo`，該呼叫只走一般確認。`run_command` 無法取代：sudo 在 `bwrap` 內沒有作用。語言執行環境（node / python）→ 以 `run_command` 搭配 mise、fnm 或 uv；語言層套件（pip / npm / cargo）→ `run_command` |
