# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## 專案性質 這是一個 **Claude Code skill**(根目錄的 `SKILL.md` 就是 skill 定義檔)。本身不是一般應用程式,產物是一組 bash 腳本(`scripts/*.sh`),針對自架 Gitea 做常見操作。`publish.sh` 是最早的腳本,其他腳本是逐步擴充而來。 ## 常用指令 在本 repo 裡沒有測試/build/lint;開發流程就是:改 `scripts/*.sh` → `bash -n` 語法檢查 → 在另一個 tmp 目錄實際跑一次看看。所有腳本共用 `scripts/lib/common.sh`。 實際使用腳本時(在任何專案目錄下): ```bash bash /path/to/gitea-cli/scripts/publish.sh [repo] [public|private] [-m "msg"] bash /path/to/gitea-cli/scripts/list.sh [--private|--public] [--format table|tsv|name] # ... 其他腳本見 SKILL.md / README.md ``` 首次使用前要 `cp config.example.env config.env` 並填入 `GITEA_URL` / `GITEA_USER` / `GITEA_TOKEN`。 ## 架構與關鍵不變量 ### 安全模型:token 絕不落地 **修改任何腳本時都要守住**: 1. `origin` remote 永遠是**乾淨 URL**,不含 token 2. Token 只能出現在 `config.env`、呼叫過程的環境變數、以及 `scripts/lib/common.sh` 裡的 `gitea_api` / `git_*_with_token` 函式內 3. Token 絕不進入 `.git/config`、remote URL、任何 log(stdout/stderr) 4. `config.env` 被 `.gitignore` 排除 ### 共用 lib `scripts/lib/common.sh` 所有 API / push / clone 都走 lib,腳本本身不寫 curl 也不直接操作 credential helper。lib 提供: - `load_config`:讀 `config.env`(或 `GITEA_PROFILE` 指定時讀 `config..env`),檢查三個變數都非空非預設 - `gitea_api [json-body]`:單一 API 呼叫入口;回傳後讀 `$HTTP_CODE` 與 `$GITEA_API_RESP_FILE` - `git_push_with_token ` / `git_push_tag_with_token ` / `git_clone_with_token `:一次性帶 token 的 git 操作 - `infer_repo_from_cwd`:從 `git remote get-url origin` 推斷 `owner/repo` - `confirm_destructive ` / `confirm_exact_match `:破壞性操作互動;`GITEA_YES=1` 或腳本處理的 `-y` 可略過 - `log_info` / `log_ok` / `log_warn` / `log_err` / `log_done`:統一前綴、**全部寫 stderr** **什麼不放進 lib**(刻意留在各腳本): - 各腳本自己的 arg 解析(每支不同) - JSON body 組字串(放在呼叫處最直觀;複雜的用 jq 在呼叫端組) - `publish.sh` 的三種 git 狀態分支(publish 獨有) ### stdout / stderr 分流 - **stderr**:`log_*` 進度訊息、錯誤 - **stdout**:最終結構化輸出 - `publish.sh` / `rename.sh` / `visibility.sh` / `archive.sh` / `meta.sh` → repo web URL - `list.sh` → repo 清單 - `clone.sh` → clone 到的絕對路徑 - `release.sh` → release URL + 每個 asset URL - `tag.sh` → tag 名 - `delete.sh` → 空 使用者可以 `URL=$(publish.sh)` 拿結果。 ### 新腳本骨架(照抄) 寫新腳本時以這個為起點: ```bash #!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=lib/common.sh source "${SCRIPT_DIR}/lib/common.sh" load_config # require_cmd jq # 若會用到 usage() { cat >&2 <<'EOF' Usage: