What:依 jsc-meta:skill-check 的稽核結果修正技能與工具——補上每個步驟的可檢核完成條件、 把留在內文的標準輸入輸出流程下放 tools/、修正查表與退碼路由造成的誤判。 Why:稽核發現這些缺失會讓技能在實際執行時走錯分支或靜默通過。 完成條件缺漏是最常被違反的一項;退碼誤判與查表錯誤則會讓良性狀況被當成失敗。 How:逐項對照 references/guidelines.md 的審核檢查清單修正,新增的工具都有 documented exit codes,並以真實執行驗證每條路徑。 Who:jsc-meta:skill-check 例行稽核(2026-08-25)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
90 lines
4.0 KiB
Bash
Executable File
90 lines
4.0 KiB
Bash
Executable File
#!/usr/bin/env sh
|
||
# sync-domains.sh — 依 Gitea 正本 marketplace 把所有 domain 存取庫同步到本機。
|
||
#
|
||
# 用法: sync-domains.sh(不吃參數)
|
||
#
|
||
# 流程:
|
||
# 1. 透過 jsc-gitea/tools/gitea.sh 讀正本 marketplace
|
||
# (plugins/meta 的 .claude-plugin/marketplace.json),取得權威 domain 清單。
|
||
# 2. 本機缺少的 domain:用 gitea.sh clone-url plugins/{domain} 取網址後 clone。
|
||
# 3. 本機已有的 domain:git pull。工作區有未提交變更就跳過 pull,只在 stderr 提醒——
|
||
# 正在改的 repo 不該被自動 pull 覆蓋。
|
||
#
|
||
# 根目錄: 預設取本腳本位置的上兩層(meta/tools -> meta -> 根)。
|
||
# 用 JSC_PLUGINS_ROOT 覆寫,換機器不必改腳本。
|
||
# 存取庫目錄名: 先找 {root}/{domain},再找 {root}/jsc-{domain};都沒有才 clone 成 {root}/{domain}。
|
||
#
|
||
# 輸出: 一行一個 domain,格式 {domain}<TAB>{path}(stdout);警告與失敗說明走 stderr。
|
||
# 結束碼: 0=正本讀到、每個 domain 都在本機,而且每個既有存取庫都更新到最新
|
||
# 1=讀不到正本 marketplace 或找不到 gitea.sh(不輸出任何 domain)
|
||
# 2=正本讀到,但有 domain 沒能取得或 clone 失敗(已輸出其餘 domain)
|
||
# 3=每個 domain 都在本機,但有存取庫沒更新到最新:工作區脏而跳過 pull,
|
||
# 或 pull 失敗。stderr 會逐一列出這些路徑。**exit 0 才代表「全部最新」**;
|
||
# 拿 3 當乾淨會讓後續步驟改在落後的檔案上。
|
||
# 同時發生時回較嚴重的那個:2 蓋過 3。
|
||
# 環境變數: JSC_PLUGINS_ROOT(根目錄)
|
||
# JSC_SYNC_DRY_RUN=1(只印出會做什麼,不動檔案;不執行 pull/clone,
|
||
# 所以也不因為「沒更新」回 3)
|
||
set -u
|
||
|
||
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||
ROOT="${JSC_PLUGINS_ROOT:-$(CDPATH= cd -- "$HERE/../.." && pwd)}"
|
||
DRY="${JSC_SYNC_DRY_RUN:-}"
|
||
|
||
[ -d "$ROOT" ] || { echo "找不到 plugins 根目錄:$ROOT(可用 JSC_PLUGINS_ROOT 指定)" >&2; exit 1; }
|
||
|
||
GITEA=""
|
||
for g in "$ROOT/gitea/tools/gitea.sh" "$ROOT/jsc-gitea/tools/gitea.sh"; do
|
||
[ -f "$g" ] && { GITEA="$g"; break; }
|
||
done
|
||
[ -n "$GITEA" ] || { echo "找不到 gitea.sh:請先取得 jsc-gitea 存取庫" >&2; exit 1; }
|
||
|
||
mkt=$(sh "$GITEA" api GET /repos/plugins/meta/raw/.claude-plugin/marketplace.json 2>/dev/null) || mkt=""
|
||
[ -n "$mkt" ] || { echo "讀不到正本 marketplace:檢查 GITEA_HOST、GITEA_TOKEN 或 tea 登入" >&2; exit 1; }
|
||
|
||
DOMAINS=$(printf '%s\n' "$mkt" | sed -n 's/.*"name": *"jsc-\([a-z0-9-]*\)".*/\1/p' | sort -u)
|
||
[ -n "$DOMAINS" ] || { echo "正本 marketplace 裡沒有 jsc-{domain} 條目" >&2; exit 1; }
|
||
|
||
repo_path() { # $1=domain;印出既有路徑(return 0)或預設路徑(return 1)
|
||
for d in "$ROOT/$1" "$ROOT/jsc-$1"; do
|
||
[ -d "$d" ] && { printf '%s' "$d"; return 0; }
|
||
done
|
||
printf '%s' "$ROOT/$1"
|
||
return 1
|
||
}
|
||
|
||
rc=0
|
||
stale=0
|
||
for domain in $DOMAINS; do
|
||
if path=$(repo_path "$domain"); then
|
||
if [ -n "$(git -C "$path" status --porcelain 2>/dev/null)" ]; then
|
||
echo "工作區有未提交變更,跳過 pull,未更新到最新:$path" >&2
|
||
stale=1
|
||
elif [ "$DRY" = 1 ]; then
|
||
echo "[dry-run] git -C $path pull --ff-only" >&2
|
||
elif ! git -C "$path" pull --quiet --ff-only >/dev/null 2>&1; then
|
||
echo "pull 失敗,保留本機版本,未更新到最新:$path" >&2
|
||
stale=1
|
||
fi
|
||
else
|
||
url=$(sh "$GITEA" clone-url "plugins/$domain" 2>/dev/null) || url=""
|
||
if [ -z "$url" ]; then
|
||
echo "取不到 clone 網址,略過:plugins/$domain" >&2
|
||
rc=2
|
||
continue
|
||
fi
|
||
if [ "$DRY" = 1 ]; then
|
||
echo "[dry-run] git clone $url $path" >&2
|
||
elif ! git clone --quiet "$url" "$path" >/dev/null 2>&1; then
|
||
echo "clone 失敗:$url" >&2
|
||
rc=2
|
||
continue
|
||
fi
|
||
fi
|
||
printf '%s\t%s\n' "$domain" "$path"
|
||
done
|
||
|
||
# 2(取不到或 clone 失敗)比 3(沒更新到最新)嚴重,優先回報。
|
||
[ "$rc" -eq 0 ] && [ "$stale" -eq 1 ] && rc=3
|
||
exit $rc
|