fix(scripts): template 來源改指活帳號,404 不再靜默寫入垃圾內容

scripts/install.sh 與 scripts/update.sh 的更新來源指向已被 GitHub suspend 的
uncle6me-web 帳號,實測全部 404 ⇒ 自動更新靜默失效。改成與 system-dev-template
本體、以及本 repo 現行世代 system-dev/scripts/ 一致的正解:預設公開 GitHub
youlinhsieh/system-dev-template,可用 TEMPLATE_SOURCE 環境變數覆寫,不改檔。

同時補上 looks_like_error_page 判斷(沿用 template repo 已修好的寫法):curl
對 404 常回傳非空的錯誤頁內容,只判斷「非空」會把它當成正常檔案寫入且不報錯。
現在錯誤頁會被偵測、檔案不寫入、FAILED 清單於結尾列出、腳本以非零狀態碼結束。

實測:
- 修正後來源多個路徑回真實 HTTP 200(CLAUDE.md/VERSION/self-update 兩支腳本)。
- 刻意把 TEMPLATE_SOURCE 指回死帳號重跑兩支腳本:全部項目進 FAILED 清單、
  無任何檔案被錯誤頁污染、exit code 1。
- 兩支腳本 bash -n 語法檢查通過。

已知缺口(不在本次範圍,留待另決):template repo 內部檔案佈局已從
.claude/wiki/、docs/ 搬到 system-dev/ 前綴,這兩支舊世代腳本仍用舊路徑,
其中一部分檔案(wiki 範本、docs/README、SDD 範本等)在新帳號上仍 404——
現在會清楚回報失敗而不是靜默吞掉,但尚未逐一改點新路徑。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
uncle6me-web
2026-08-09 20:54:01 +08:00
parent bfc98fe41a
commit 453dec60b1
2 changed files with 87 additions and 7 deletions
+42 -3
View File
@@ -26,9 +26,29 @@ t() { if [ "$IS_ZH" = "yes" ]; then printf '%s\n' "$1"; else printf '%s\n' "$2";
# tn = 不換行版(給 prompt 用)
tn() { if [ "$IS_ZH" = "yes" ]; then printf '%s' "$1"; else printf '%s' "$2"; fi; }
REPO_URL="https://raw.githubusercontent.com/uncle6me-web/system-dev-template/main/template"
# 來源預設=公開 GitHubleo 2026-07-21:「要發佈的正稿,從頭就不要用奇怪的網址,
# 以免改來改去」)。舊的 uncle6me-web 帳號已被 suspend(讀 404)=自動更新靜默失效,
# 這顆雷已在 system-dev-template 本體修過(正解=改指 youlinhsieh 這個公開帳號),
# 這裡只是把同一個修法補進 Arcrun 這份沒跟到的 copy。
# 內部要指私有草稿源時用環境變數覆寫,不改檔:
# TEMPLATE_SOURCE=https://<私有 raw base> bash scripts/install.sh
TEMPLATE_SOURCE="${TEMPLATE_SOURCE:-https://raw.githubusercontent.com/youlinhsieh/system-dev-template/main}"
REPO_URL="$TEMPLATE_SOURCE/template"
CREATED=()
SKIPPED=()
FAILED=()
# 404 頁面常常「非空」(GitHub raw 對不存在的路徑回 "404: Not Found"),
# 只判斷 [ -s file ] 會把錯誤頁內容當成檔案寫進去且完全不報錯(template issue #13 撞過的雷)。
# 這裡量身做一個輕量判斷:檔案很短又長得像錯誤訊息 → 當失敗。
looks_like_error_page() {
local f="$1"
[ -s "$f" ] || return 0
if [ "$(wc -l < "$f" | tr -d ' ')" -le 2 ] && head -c 200 "$f" | grep -qiE '40[0-9]|not found|<html'; then
return 0
fi
return 1
}
# ── 解析模組參數 ──────────────────────────────────
MODULE=""
@@ -211,8 +231,12 @@ download_if_missing() {
local dest="$1" src="$2"
if [ ! -f "$dest" ]; then
mkdir -p "$(dirname "$dest")"
curl -sSL "$src" -o "$dest"
CREATED+=("$dest")
if curl -sSL "$src" -o "$dest" 2>/dev/null && ! looks_like_error_page "$dest"; then
CREATED+=("$dest")
else
rm -f "$dest"
FAILED+=("$dest $(tn "(來源抓不到:$src)" "(source unreachable: $src)")")
fi
else
SKIPPED+=("$dest $(tn '(已存在,跳過)' '(already exists, skipped)')")
fi
@@ -332,6 +356,16 @@ if [ ${#SKIPPED[@]} -gt 0 ]; then
for item in "${SKIPPED[@]}"; do echo " - $item"; done
fi
# 來源抓不到要出聲,不能安靜吞掉——404 內容不會被寫進檔案(已在 download_if_missing 擋掉),
# 但使用者必須知道「這幾個檔沒裝到」,不然會誤以為裝完整了。
if [ ${#FAILED[@]} -gt 0 ]; then
echo ""
t "❌ 抓取失敗(來源不可達,未寫入任何檔案):" "❌ Fetch failed (source unreachable, no file was written):"
for item in "${FAILED[@]}"; do echo " x $item"; done
t " 請檢查網路,或用 TEMPLATE_SOURCE=<其他來源> 重跑。" \
" Check your network, or rerun with TEMPLATE_SOURCE=<alternate source>."
fi
echo ""
echo "─────────────────────────────────"
@@ -429,3 +463,8 @@ fi
t " GitHub issueCC 可直接 /issue-handle 讀回自己 repo 的 issue(禁自動輪詢)" \
" GitHub issues: CC can use /issue-handle to read issues from its own repo (no auto-polling)"
echo ""
# 有任何來源抓取失敗 → 用非零 exit code 出聲,不能靜靜地當「裝完了」收工。
if [ ${#FAILED[@]} -gt 0 ]; then
exit 1
fi
+45 -4
View File
@@ -23,18 +23,43 @@ esac
t() { if [ "$IS_ZH" = "yes" ]; then printf '%s\n' "$1"; else printf '%s\n' "$2"; fi; }
tn() { if [ "$IS_ZH" = "yes" ]; then printf '%s' "$1"; else printf '%s' "$2"; fi; }
REPO_RAW="https://raw.githubusercontent.com/uncle6me-web/system-dev-template/main"
# 來源預設=公開 GitHubleo 2026-07-21:「要發佈的正稿,從頭就不要用奇怪的網址,
# 以免改來改去」)。舊的 uncle6me-web 帳號已被 suspend(讀 404)=自動更新靜默失效,
# 這顆雷已在 system-dev-template 本體修過(正解=改指 youlinhsieh 這個公開帳號),
# 這裡只是把同一個修法補進 Arcrun 這份沒跟到的 copy。
# 內部要指私有草稿源時用環境變數覆寫,不改檔:
# TEMPLATE_SOURCE=https://<私有 raw base> bash scripts/update.sh
REPO_RAW="${TEMPLATE_SOURCE:-https://raw.githubusercontent.com/youlinhsieh/system-dev-template/main}"
TEMPLATE_URL="$REPO_RAW/template"
UPDATED=()
KEPT=()
NEW=()
TEMPLATED=()
FAILED=()
# 404 頁面常常「非空」(GitHub raw 對不存在的路徑回 "404: Not Found"),
# 只判斷 [ -s file ] 會把錯誤頁內容當成檔案寫進去且完全不報錯(template issue #13 撞過的雷)。
looks_like_error_page() {
local f="$1"
[ -s "$f" ] || return 0
if [ "$(wc -l < "$f" | tr -d ' ')" -le 2 ] && head -c 200 "$f" | grep -qiE '40[0-9]|not found|<html'; then
return 0
fi
return 1
}
# ── 版本比對:先看本機 vs 遠端,給使用者「值不值得更新」的判斷 ──
LOCAL_VER="$(tn '(未知)' '(unknown)')"
[ -f ".claude/VERSION" ] && LOCAL_VER="$(tr -d '[:space:]' < .claude/VERSION)"
REMOTE_VER="$(curl -sSL "$TEMPLATE_URL/.claude/VERSION" 2>/dev/null | tr -d '[:space:]' || echo '')"
# 容錯:curl 對 404 會把「404: Not Found」當內容輸出(非空),舊版直接把它寫進 REMOTE_VER
# 拿去跟本機版本比對,比對邏輯不會報錯、只會靜靜判斷「版本不同」或誤判「已最新」。
# 這裡驗證必須像版號(X.Y.Z),否則一律視為取不到。
case "$REMOTE_VER" in
[0-9]*.[0-9]*.[0-9]*) : ;; # 形如 1.9.0 → 合法
*) REMOTE_VER="" ;; # 404 / HTML 錯誤頁 / 其他 → 當作沒抓到
esac
echo ""
echo "🔄 system-dev-template updater"
@@ -64,7 +89,7 @@ update_file() {
local dest="$1" src="$2"
mkdir -p "$(dirname "$dest")"
if [ -f "$dest" ]; then
if curl -sSL "$src" -o "$dest.tmp" 2>/dev/null && [ -s "$dest.tmp" ]; then
if curl -sSL "$src" -o "$dest.tmp" 2>/dev/null && ! looks_like_error_page "$dest.tmp"; then
if cmp -s "$dest" "$dest.tmp"; then
rm -f "$dest.tmp" # 內容相同,不算更新
else
@@ -73,13 +98,15 @@ update_file() {
fi
else
rm -f "$dest.tmp"
FAILED+=("$dest")
t " ⚠️ 抓取失敗,保留原檔:$dest" " ⚠️ Download failed, keeping the original: $dest"
fi
else
if curl -sSL "$src" -o "$dest" 2>/dev/null && [ -s "$dest" ]; then
if curl -sSL "$src" -o "$dest" 2>/dev/null && ! looks_like_error_page "$dest"; then
NEW+=("$dest") # 新功能:舊版沒有的檔
else
rm -f "$dest"
FAILED+=("$dest")
t " ⚠️ 抓取失敗:$dest" " ⚠️ Download failed: $dest"
fi
fi
@@ -98,7 +125,7 @@ keep_with_template() {
if [ -f "$dest" ]; then
KEPT+=("$dest")
local tmpl="${dest%.sh}.template.sh"
if curl -sSL "$src" -o "$tmpl.tmp" 2>/dev/null && [ -s "$tmpl.tmp" ]; then
if curl -sSL "$src" -o "$tmpl.tmp" 2>/dev/null && ! looks_like_error_page "$tmpl.tmp"; then
if [ -f "$tmpl" ] && cmp -s "$tmpl" "$tmpl.tmp"; then
rm -f "$tmpl.tmp" # 模板版沒變,不重複提示
else
@@ -227,8 +254,22 @@ if [ -f ".claude/settings.json" ]; then
fi
fi
# 有任何檔案抓取失敗要出聲,不能安靜吞掉(404 內容已被 looks_like_error_page 擋掉、
# 不會污染既有檔案,但使用者必須知道「這幾個檔沒更新到」)。
if [ ${#FAILED[@]} -gt 0 ]; then
echo ""
t "❌ 抓取失敗(來源不可達,原檔已保留不動):" "❌ Fetch failed (source unreachable, original files kept untouched):"
for f in "${FAILED[@]}"; do echo " x $f"; done
t " 請檢查網路,或用 TEMPLATE_SOURCE=<其他來源> 重跑。" \
" Check your network, or rerun with TEMPLATE_SOURCE=<alternate source>."
fi
echo ""
t "🚀 更新完成:${LOCAL_VER}${REMOTE_VER}" "🚀 Update complete: ${LOCAL_VER}${REMOTE_VER}"
t " 下次更新直接跑:bash scripts/update.sh" " Next time, just run: bash scripts/update.sh"
t " 改了什麼看:CHANGELOG.md" " See what changed: CHANGELOG.md"
echo ""
if [ ${#FAILED[@]} -gt 0 ]; then
exit 1
fi