This repository has been archived on 2026-07-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
code-review/skills/code-review-sync/SKILL.md
T

229 lines
14 KiB
Markdown
Raw 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.
---
name: code-review-sync
description: 透過 `GITEA_TOKEN` 取得使用者有讀取權限的所有 Gitea 專案,依擁有者(owner)分組後列出讓使用者多選,再把選定擁有者底下有讀取權限的專案,於目標目錄(預設家目錄)依擁有者建立資料夾並逐一 clone;若專案已存在,則切換到 develop(再退而 master)並更新到最新。當使用者說同步 Gitea 專案、批次 clone、把某些擁有者的 repo 全抓下來、依擁有者分類 clone、批次更新本機專案到最新時觸發。不適用於:建立/刪除遠端 repo、單一專案的 clone(直接用 git 即可)、非 Gitea 的來源,或需要 push/改動遠端的操作。
argument-hint: "[--target-dir <根目錄>] [--owner <擁有者,以逗號分隔>] [--host <gitea 主機>] [--include-forks] [--ssh] [--yes]"
---
# code-review-sync — 依擁有者批次 clone/更新 Gitea 專案
五階段 skill:先做**前置設定**(解析 token、gitea 主機、目標根目錄),再**取得使用者有讀取權限的所有專案並依擁有者分組**,接著**列出所有擁有者讓使用者多選**,然後**列出選定擁有者底下有讀取權限的專案**,最後在目標根目錄**依擁有者建立資料夾並逐一 clone**;專案已存在時改為**切換到 develop(再退而 master)並更新到最新**。
| 階段 | 動作 |
| --- | --- |
| A. 前置設定 | 確認 `GITEA_TOKEN` → 決定 gitea 主機(`--host``$GITEA_HOST`/目前 repo 的 origin/詢問)→ 決定目標根目錄(`--target-dir`,預設家目錄) |
| B. 取得可讀專案 | 以 token 呼叫 Gitea API 分頁取回使用者有讀取(`pull`)權限的所有專案 → 依 `owner.login` 分組 |
| C. 選擇擁有者 | 列出所有擁有者(含各自專案數)→ 讓使用者**多選**(`--owner` 已指定則沿用,不再詢問) |
| D. 列出選定專案 | 列出選定擁有者底下所有有讀取權限的專案(含是否已存在於本機) |
| E. Clone/更新 | 依擁有者建立資料夾 → 不存在則 clone;已存在則 `fetch` → 切到 develop(再退而 master)→ `pull` 更新到最新 |
---
## 輸出規範(務必遵守)
- **語言**:所有面向使用者的輸出(擁有者清單、專案清單、進度、總結、反問)一律使用**繁體中文(台灣用語)**;僅識別字、檔名、git/curl 指令、API 路徑等技術標識保留原文,**不可**使用簡體字。
- **編碼無亂碼**:凡輸出含繁體中文、全形標點、emoji,一律 **UTF-8(不含 BOM**,不得出現問號方框或錯碼。
- **Token 機密保護(極重要)**gitea token 一律**從環境變數讀取**(如 `$GITEA_TOKEN`),**絕不**寫死在 skill、log 或任何輸出;**不可** echo 含 token 的指令或 URL。所有顯示給使用者的指令/錯誤訊息都要**遮蔽 token**(如以 `***` 取代)。clone 時帶 token 的 URL 用變數帶入、**不可印出**,且 clone 完成後要把 origin 還原成不含 token 的乾淨 URL(見 E3),避免 token 落地在 `.git/config`
- **自動執行原則**:除非使用者明確要求先確認,或遇到不可忽略的必要決策(例如缺 token、無法決定 gitea 主機、目標目錄不可寫、單一專案更新時工作區有未提交變更需使用者裁示),否則各階段只需輸出簡短計畫/進度後直接執行到完成。**唯一一定會中斷的點是階段 C 的擁有者多選**(除非已帶 `--owner`)。
- **不破壞既有工作**:更新既有專案時若工作區有未提交變更而導致切換/pull 失敗,**停止該專案的更新並回報**,請使用者自行處理;**絕不**強制丟棄(不可 `reset --hard``checkout -f``clean`)。
- **唯讀本意**:本 skill 只做 clone 與本機分支更新,**不 push、不改遠端、不刪本機未追蹤檔**。
---
## 參數
格式:`[--target-dir <根目錄>] [--owner <擁有者,以逗號分隔>] [--host <gitea 主機>] [--include-forks] [--ssh] [--yes]`
- `--target-dir <根目錄>`:clone 的根目錄。**省略時預設家目錄**(`$HOME`Windows 為 `%USERPROFILE%`)。實際每個專案會 clone 到 `<根目錄>/<擁有者>/<專案名>`
- `--owner <擁有者,以逗號分隔>`:預先指定要同步的擁有者(可多個,以逗號分隔,例如 `plugins,jeffery`)。**帶此參數時跳過階段 C 的多選詢問**,直接同步這些擁有者;若指定的擁有者不在可讀清單內,回報並略過該擁有者。
- `--host <gitea 主機>`gitea 主機(如 `gitea.jsc.idv.tw`)。省略時依 A2 規則決定。
- `--include-forks`:一併納入 fork 來的專案;**省略時預設排除 fork**(`fork=true` 的 repo 不列入)。
- `--ssh`:改用 SSH`ssh_url`clone,不帶 token**省略時預設用 HTTPStoken**。
- `--yes`:全自動。即使未帶此參數,也依「自動執行原則」盡量不中斷;但階段 C 的擁有者多選仍會詢問(除非已帶 `--owner`)。
---
## 階段 A:前置設定
### A1. 確認 token
讀取環境變數 `GITEA_TOKEN`(或助理慣用的等價變數名)。
```bash
[ -n "${GITEA_TOKEN}" ] && echo "GITEA_TOKEN 已設定" || echo "GITEA_TOKEN 未設定"
```
- **未設定** → 回報「缺少 `GITEA_TOKEN` 環境變數,無法存取 Gitea API」並停止;提示使用者於環境變數提供 token(不要請使用者把 token 貼進對話)。
- **不可** echo token 本身,只確認是否存在。
### A2. 決定 gitea 主機
依序決定主機(取第一個成功者):
1.`--host <主機>` → 直接採用。
2. 否則讀環境變數 `$GITEA_HOST`(若有)。
3. 否則若**目前工作目錄是 git repo** 且 `git remote get-url origin` 指向某 gitea 主機 → 取該 host。
4. 以上皆無 → **詢問使用者** gitea 主機,**不臆測**。
主機僅取 host 部分(如 `gitea.jsc.idv.tw`),組 API base 為 `https://<host>/api/v1`
### A3. 決定目標根目錄
-`--target-dir <根目錄>` → 採用(可含 `~`,需展開為實際家目錄)。
- 省略 → 預設家目錄(`$HOME`)。
- 確認根目錄存在且可寫;不存在時先建立(`mkdir -p`)。若無法建立或不可寫,回報並停止。
輸出本次設定摘要(主機、根目錄、是否含 fork、HTTPS/SSH),再進入階段 B。
---
## 階段 B:取得使用者有讀取權限的所有專案並依擁有者分組
### B1. 分頁取回可讀專案
以 token 呼叫 `GET /api/v1/user/repos`(回傳 token 對應使用者**有權限存取**的 repo:自有、組織成員、協作者),**逐頁抓到取回筆數不足一頁為止**(每頁上限以 API 為準,常見 `limit=50`):
```bash
# 不可印出含 token 的指令;token 以 Header 帶入,輸出時遮蔽
page=1
curl -sS \
-H "Authorization: token ${GITEA_TOKEN}" \
"https://<host>/api/v1/user/repos?page=${page}&limit=50"
```
- 持續累加 `page` 直到某頁回傳筆數 `< limit`(或回空陣列)為止,確保**取得全部**而非只第一頁。
- API 失敗(401/403/網路錯誤)→ 回報錯誤(**遮蔽 token**)並停止;401403 多半是 token 失效或權限不足。
### B2. 篩選與正規化
每筆 repo 取下列欄位:`owner.login``name``full_name``clone_url``ssh_url``permissions.pull``fork``default_branch`
- **只保留 `permissions.pull == true`** 的專案(確有讀取權限)。
- **預設排除 `fork == true`**;帶 `--include-forks` 才納入。
- 去除重複(以 `full_name` 為鍵)。
### B3. 依擁有者分組
`owner.login` 分組,統計每個擁有者底下的可讀專案數,並依擁有者名稱排序(專案數多者可優先列出)。**無任何可讀專案** → 回報並結束。
---
## 階段 C:列出所有擁有者讓使用者多選
輸出一張「擁有者清單」表,含編號、擁有者、可讀專案數:
| # | 擁有者 | 可讀專案數 |
| --- | --- | --- |
選擇方式:
- **帶 `--owner` 參數** → 直接採用其中的擁有者,**跳過詢問**;清單中沒有的擁有者回報並略過。
- **未帶 `--owner`** → 這是**不可忽略的必要決策**,必須讓使用者**多選**:
- 擁有者數量 ≤ 4 時,可用助理的多選提問元件(如 Claude Code 的多選問題)。
- 擁有者較多時,請使用者直接以**編號或擁有者名稱**回覆(支援多個,以逗號或空白分隔),並支援回覆 `all``全部` 代表全選。
- 解析使用者回覆為擁有者集合;無法對應的輸入請回報並請使用者重選,**不臆測**。
選定後輸出「將同步的擁有者:…」再進入階段 D。
---
## 階段 D:列出選定擁有者底下有讀取權限的專案
對每個選定擁有者,列出其底下所有可讀專案,並標示本機是否已存在(`<根目錄>/<擁有者>/<專案名>/.git` 是否存在):
| 擁有者 | 專案 | 狀態 |
| --- | --- | --- |
| | | 🆕 將 clone/♻️ 已存在將更新 |
輸出總計(將 clone N 個、將更新 M 個),除非使用者要求先確認,否則直接進入階段 E 執行。
---
## 階段 E:依擁有者建立資料夾並逐一 clone/更新
對選定擁有者底下的每個專案,依序處理(一次一個,互不干擾):
### E1. 建立擁有者資料夾
```bash
mkdir -p "<根目錄>/<擁有者>"
```
專案目標路徑為 `<根目錄>/<擁有者>/<專案名>`
### E2. 專案不存在 → clone
- **HTTPS(預設)**:以 token 組 clone URL**用變數帶入、不可印出**;clone 完成後**還原乾淨 origin**
```bash
dest="<根目錄>/<擁有者>/<專案名>"
# GITEA_TOKEN 來自環境變數;clone_url 形如 https://<host>/<owner>/<repo>.git
git clone "https://oauth2:${GITEA_TOKEN}@<host>/<owner>/<repo>.git" "${dest}"
# 還原成不含 token 的乾淨 URL,避免 token 落地在 .git/config
git -C "${dest}" remote set-url origin "https://<host>/<owner>/<repo>.git"
```
- **SSH`--ssh`**:直接用 `ssh_url`,不帶 token
```bash
git clone "<ssh_url>" "<根目錄>/<擁有者>/<專案名>"
```
- clone 後若遠端有 `develop`,將工作分支切到 `develop`(沒有則維持 `default_branch``master`);clone 失敗回報原因(**遮蔽 token**)並繼續下一個專案,不中斷整批。
### E3. 專案已存在 → 切到 develop(再退而 master)並更新到最新
先盤點該專案狀態,**有未提交變更則不強切**:
```bash
dest="<根目錄>/<擁有者>/<專案名>"
git -C "${dest}" rev-parse --is-inside-work-tree # 確認是 git repo
git -C "${dest}" status --porcelain # 是否乾淨
git -C "${dest}" fetch --all --prune
```
- **目錄存在但不是 git repo**(無 `.git`)→ 回報「目標已存在且非 git repo,略過」並繼續下一個;**不刪除、不覆蓋**。
- **工作區有未提交變更**`status --porcelain` 非空)→ 回報「有未提交變更,略過更新以免覆蓋」並繼續下一個;**絕不**強制丟棄。
- **工作區乾淨** → 依序選擇要更新的分支並切換、拉取:
```bash
if git -C "${dest}" rev-parse --verify --quiet origin/develop; then
git -C "${dest}" switch develop 2>/dev/null || git -C "${dest}" switch -c develop --track origin/develop
elif git -C "${dest}" rev-parse --verify --quiet origin/master; then
git -C "${dest}" switch master 2>/dev/null || git -C "${dest}" switch -c master --track origin/master
fi
git -C "${dest}" pull --ff-only
```
- `origin/develop` 存在 → 切到 `develop`;否則 `origin/master` 存在 → 切到 `master`;兩者都不存在 → 回報「找不到 develop/master」並維持原分支、略過該專案。
- `pull --ff-only` 無法快進(本地與遠端分歧)→ 回報該專案需人工處理(**不**自動 mergerebasereset),繼續下一個。
- 已在目標分支時直接 `pull --ff-only` 更新即可。
### E4. 逐一處理、彙整結果
- 每個專案處理完記錄結果:🆕 已 clone/♻️ 已更新到最新/⏭️ 已略過(原因)/❌ 失敗(原因,遮蔽 token)。
- 單一專案失敗或略過**不應中斷整批**;全部處理完再輸出總結。
---
## 總結
各階段執行後輸出:
- **階段 A**:使用的 gitea 主機、目標根目錄、是否含 fork、HTTPSSSH。
- **階段 B/C**:可讀專案總數、擁有者總數、使用者選定的擁有者。
- **階段 D/E**:本批處理結果統計 —— 新 clone N 個、更新 M 個、略過 K 個(列原因)、失敗 J 個(列原因,遮蔽 token),並列出各專案的本機路徑。
- 若過程曾在指令中帶入 token,提醒確認輸出與 log 無明文 token。
---
## 呼叫方式
格式:`[--target-dir <根目錄>] [--owner <擁有者,以逗號分隔>] [--host <gitea 主機>] [--include-forks] [--ssh] [--yes]` —
全部可省略(根目錄預設家目錄;未帶 `--owner` 時於階段 C 詢問多選)。token 一律由環境變數(如 `GITEA_TOKEN`)提供,不寫死、不印出。
| 助理 | 呼叫 |
| --- | --- |
| Claude Code / Antigravity | `/jsc:code-review-sync`,或 `/jsc:code-review-sync --owner plugins --target-dir ~/work`、`/jsc:code-review-sync --include-forks --ssh` |
| Codex | `$code-review-sync`,或 `$code-review-sync --owner plugins --target-dir ~/work`,或用 `/skills` 選單 |
| OpenCode | 描述需求(如「用 GITEA_TOKEN 取得我有讀取權限的所有 Gitea 專案,依擁有者分組讓我多選,把選定擁有者的專案 clone 到家目錄;已存在的切到 develop/master 更新到最新」)自動觸發 |