Files
alex fcf7680e49 chore: 自 fox monorepo 移出成獨立公開倉庫(fox #49)
- 自 alterminal/fox 的 cli/ 目錄以 git subtree split 移出(保留 git 歷史)。
- package.json:改為獨立專案(移除 private、補 repository/homepage/files、
  增加 packageManager pnpm@9.15.3)。
- README/docs/cli-install.md:路徑與指令改為本倉庫根目錄版型
  (node dist/cli.js、pnpm build;獨立安裝不會建立 node_modules/.bin/fox,
  掛 PATH 改用 symlink)。
- 新增 .gitignore 與 pnpm-lock.yaml。
- 驗證:pnpm install + pnpm build + node dist/cli.js --help(exit 0)、
  未知命令 exit 2。
2026-09-07 21:14:23 +08:00

98 lines
7.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Fox CLI — 與 Fox 後端互動的命令列工具
> **本倉庫已從 `alterminal/fox` monorepo 的 `cli/` 目錄移出成獨立專案**(見 `alterminal/fox` issue #49),改為公開倉庫以開放安裝;git 歷史一併保留。
> 專案狀態:M0–M3 已實作(M1:HTTP client、設定讀取、`tokens verify`/`auth status`;M2:`tokens create/list/revoke`、公開的 `novels get`;M3:`novels list/create/update`、`chapters …`、`generate …`)|日期:2026-09-06
`fox` 是一個命令列工具,讓人與 **AI agent** 不經過前端,直接與 Fox 後端 API 互動:查詢/建立/編輯作品、管理 access token 等。目標是「一句命令拿到機器可解析的結果」,方便腳本、CI 與 agent 排程使用。
## 一、設計原則
1. **非互動優先**:所有命令不跳 prompt,參數與環境變數給齊即可執行。缺少必要參數直接報錯(非零 exit code),適合 AI agent 與 cron。
2. **機器可讀輸出**:資料命令預設輸出 JSON(stdout 僅印 JSON,其餘訊息一律走 stderr);人用格式之後再以 `--pretty` 提供。
3. **穩定的 exit code**:`0` 成功;`1` 執行失敗(後端 4xx/5xx、網路錯誤);用法錯誤(缺參數、未知子命令)同樣回非零,訊息在 stderr。
4. **冪等意識**:文件會標明各命令是否幂等(如 `tokens revoke` 冪等、`novels create` 會因 slug 重複而失敗),供 agent 重試決策。
5. **Secret 不落檔**:token 只從環境變數或本機設定檔讀取(見下),絕不寫進 commit/issue/PR。
## 二、授權(access token)
後端的 access token(`fpat_` 前綴)是 CLI 的主要憑證:
- **建立**:先在 Fox 網頁端以帳號建立,或由管理員以 `POST /access-tokens` 建立;原始值只在建立時顯示一次。
- **讀取優先順序**:
1. 環境變數 `FOX_API_TOKEN`(推薦,適合 agent/CI)
2. `--token <value>` 參數(注意:會留在 shell 歷史,僅供本機快速測試)
3. 本機設定檔 `~/.config/fox/cli.json`(`{"apiUrl": "...", "token": "..."}`,權限應設 600)
- **使用方式**:每個請求帶 `Authorization: Bearer <token>`;先用 `fox tokens verify` 確認有效(過期/撤銷會回 401)。
後端 API 位址由 `FOX_API_URL`(或設定檔 `apiUrl`)指定,本機開發預設 `http://localhost:3000`。
## 三、命令規劃(對應後端端點)
| 命令 | 後端端點 | 說明 |
|------|----------|------|
| `fox auth status` | `GET /auth/status` | 查詢登入/SSO 設定(公開) |
| `fox tokens verify` | `GET /access-tokens/verify` | 驗證手中 token 是否有效 |
| `fox tokens create --name <名稱> [--expires-at <ISO8601>] [--scopes read,write,generate]` | `POST /access-tokens` | 建立新 token(回傳只出現一次的原始值) |
| `fox tokens list` | `GET /access-tokens` | 列出 token(不含 hash/原始值) |
| `fox tokens revoke <id>` | `DELETE /access-tokens/:id` | 撤銷 token(冪等) |
| `fox novels get <slug>` | `GET /novels/:slug` | 查單一作品(公開) |
| `fox novels list` | `GET /novels` | 列出自己的作品(需授權) |
| `fox novels create --title <書名> [--slug <slug>] [--synopsis <簡介>] [--tags <標籤1,標籤2>]` | `POST /novels` | 建立作品(需授權;標題非拉丁字元時建議附 `--slug`) |
| `fox novels update <slug> [--title …] [--slug …] [--synopsis …] [--tags …] [--status <狀態>]` | `PATCH /novels/:slug` | 更新作品(需授權;只傳要改的欄位) |
| `fox chapters list <novelSlug>` | `GET /novels/:novelSlug/chapters` | 列章節(公開僅 published;帶作者 token 可見全部) |
| `fox chapters get <novelSlug> <chapterSlug>` | `GET /novels/:novelSlug/chapters/:chapterSlug` | 查單一章節(draft 僅作者/admin) |
| `fox chapters create <novelSlug> --title <標題> [--slug <slug>] [--content <內容|->] [--sort-order <N>] [--status <狀態>]` | `POST /novels/:novelSlug/chapters` | 建立章節(需授權;狀態預設 draft) |
| `fox chapters update <novelSlug> <chapterSlug> [--title …] [--slug …] [--content …] [--sort-order …] [--status …]` | `PATCH /novels/:novelSlug/chapters/:chapterSlug` | 更新章節(需授權;只傳要改的欄位) |
| `fox chapters delete <novelSlug> <chapterSlug>` | `DELETE /novels/:novelSlug/chapters/:chapterSlug` | 刪除章節(需授權;冪等) |
| `fox generate draft <novelSlug> --prompt <指示|-> [--previous-context <前文摘要|->]` | `POST /novels/:novelSlug/generate` | 草稿生成(需授權;token 需 generate scope) |
| `fox generate continue <novelSlug> --previous-context <前文摘要|-> [--prompt <指示|->]` | `POST /novels/:novelSlug/generate/continue` | 續寫(前文摘要必填) |
| `fox generate rewrite <novelSlug> --prompt <原文|-> [--previous-context …]` | `POST /novels/:novelSlug/generate/rewrite` | 改寫(原文放在 `--prompt`) |
| `fox generate usages <novelSlug>` | `GET /novels/:novelSlug/generate/usages` | 查詢生成用量記帳(需授權) |
> **授權**:受保護端點的 `AuthGuard` 同時接受 `Authorization: Bearer <access token>` 與瀏覽器 session(Bearer 優先)。access token 需綁定帳號(`POST /access-tokens` 帶 `accountId`,或由管理員建立時指定),未綁帳號的系統 token 只能用於 `tokens verify`。**生成命令需具備 `generate` scope**(建立 token 時 `--scopes read,write,generate`;缺 scope 回 403)。
> **多行內容**:`--content`/`--prompt`/`--previous-context` 的值為 `-` 時改從 stdin 讀入全部內容,適合管線傳入多行文字:`cat 章節.md | fox chapters create <novelSlug> --title <標題> --content -`。
## 四、AI agent 使用指引
- 每個命令都有 `--help`;未知命令回非零 exit code。
- 輸出為單一 JSON 物件,可直接 `jq` 解析;錯誤時 stderr 有人類可讀訊息,stdout 不印半成品。
- agent 拿到 token 的建議流程:由人透過加密渠道交付(組織公開金鑰加密,見 `alterminal/agents` 的 AGENTS.md 2.3),存入環境變數或設定檔,不寫入任何儲存庫內容。
## 五、技術棧與開發計畫
- **實作語言**:Node.js(≥22)+ TypeScript,與 `frontend`/`backend` 同語言。
- **獨立倉庫**:本專案位於 `alterminal/fox-cli`(自 `alterminal/fox` 移出,issue #49),不屬於 fox monorepo workspace;以 pnpm 於本倉庫根目錄安裝與建置。
里程碑:
- **M0**:子項目目錄+README(完成)。
- **M1**:HTTP client、設定讀取、`tokens verify`/`auth status`(完成,見 `src/http.ts`、`src/config.ts`)。
- **M2**:`tokens create/list/revoke`、公開的 `novels get`(完成)。
- **M3**:`novels list/create/update`、`chapters list/get/create/update/delete`、`generate draft/continue/rewrite/usages`(完成,2026-09-06,issue #43)。
## 開發
> 使用者安裝與設定說明見 [docs/cli-install.md](./docs/cli-install.md)。
```bash
git clone https://gitea.alterminal.com/alterminal/fox-cli.git
cd fox-cli
pnpm install
pnpm build
node dist/cli.js <子命令> # 例如 auth status
```
結構:`src/cli.ts`(進入點與分發)、`src/command.ts`(參數解析與註冊表)、
`src/config.ts`(設定讀取)、`src/http.ts`(fetch 封裝)、`src/commands.ts`(各命令實作)、
`src/errors.ts`(錯誤與 exit code)。
exit code:`0` 成功;`1` 執行失敗(後端 4xx/5xx、網路錯誤);`2` 用法錯誤。
`tokens revoke` 成功時輸出 `{"ok": true, "id": <id>}`(後端回 204 無內容)。
## 維護說明
1. 後端端點異動時,同步更新第三節對應表。
2. 命令列介面(參數、輸出欄位)保持向下相容;破壞性變更須在 README 註明版本。