fix: install 防重複安裝,已裝過導去 update(杜絕 wiki 並存)+ bump 1.10.1

實測:裝過舊版的專案「先 install 發現裝過再 update」→ install 先建空殼,
update 遷移見目的地已存在就冪等跳過 → 真資料卡舊位置、空殼佔新位置、並存。

職責切分:install 只管全新安裝,一切已裝過的後續歸 update。

- install 防呆:偵測裝過沒(system-dev/ 或 .claude/wiki/ 或 .claude/VERSION
  任一存在,不分新舊版)→ 不動任何東西,導去 update。源頭杜絕並存。
- update 偵測並存:migrate_dir 遇目的地已存在但舊位置仍有真資料 → COEXIST
  警告需合併,不靜默跳過、不自動合併(絕不覆蓋用戶資料),引導 CC 逐檔合併。
- install↔update 互相導向,閉環無死結。
- 沙盒驗證:四種狀態(新結構/舊wiki/舊VERSION/全新)防呆正確、並存偵測不吃資料。

對應 SDD: install-layout(內部,不推)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-26 17:51:18 +08:00
parent 671503fd70
commit 21ba319934
5 changed files with 50 additions and 3 deletions
+10
View File
@@ -10,6 +10,16 @@
--- ---
## 1.10.1 — install 防重複安裝:已裝過一律導去 update(杜絕 wiki 並存)
實測踩到:一個裝過舊版的專案,「先跑 install、發現裝過、再跑 update」→ install 先在 system-dev/ 建了空白範本,update 的遷移看到「目的地已存在」就冪等跳過 → 真資料卡在舊 .claude/wiki/、空殼佔新位置,兩套 wiki 並存內容不同。
職責切分:**install 只管全新安裝,一切已裝過的後續(更新/遷移/補新檔)歸 update。**
- **install 防呆**:偵測「裝過沒」(system-dev/ 或 .claude/wiki/ 或 .claude/VERSION 任一存在,不分新舊版)→ 不動任何東西,導去 update 並 exit。從源頭杜絕「重複 install 製造並存」。
- **update 偵測並存**migrate_dir 遇「目的地已存在但舊位置仍有真資料」→ 警告 COEXIST「並存需合併」,不靜默跳過、不自動合併(絕不覆蓋用戶資料),引導叫 CC 逐檔合併。
- install↔update 互相導向(update 遇全新專案也導回 install),閉環無死結。
## 1.10.0 — wiki 資訊架構:push/pull 判準 + principles(原則)push 檔 ## 1.10.0 — wiki 資訊架構:push/pull 判準 + principles(原則)push 檔
從「用戶所有檔案一律改寫成 wiki」的新前提,用 **pushCC 行動前必主動看見)vs pull(按需檢索)** 重新推導 wiki/ 每個檔的存廢——因為 wiki 主要是給 AI 看的,判準是「CC 做事時會不會被動看見」,不是分類美學。對應 SDDwiki-architecture。 從「用戶所有檔案一律改寫成 wiki」的新前提,用 **pushCC 行動前必主動看見)vs pull(按需檢索)** 重新推導 wiki/ 每個檔的存廢——因為 wiki 主要是給 AI 看的,判準是「CC 做事時會不會被動看見」,不是分類美學。對應 SDDwiki-architecture。
+19
View File
@@ -103,6 +103,25 @@ echo ""
t "📦 安裝模組:$MODULE" "📦 Module: $MODULE" t "📦 安裝模組:$MODULE" "📦 Module: $MODULE"
echo "" echo ""
# ── 重複安裝防呆(1.10.1):install 只管「全新安裝」,一切後續歸 update ──
# 判準是「裝過沒」,不分新版舊版:
# - 新結構 system-dev/ 已存在,或
# - 舊結構 .claude/wiki/ 或 .claude/VERSION 存在(裝過舊版、待遷移)
# 裝過了還跑 install → 會重複建範本、甚至跟真資料並存(先 install 建空殼,遷移就被擋)。
# 正解:偵測到裝過 → 不動任何東西,導去 update(更新/遷移/補新檔都由它處理)。
if [ -d "system-dev" ] || [ -d ".claude/wiki" ] || [ -f ".claude/VERSION" ]; then
t "🛑 偵測到這個專案已經安裝過 system-dev-template。" \
"🛑 system-dev-template is already installed in this project."
t " 後續的更新、遷移、補新檔,一律由「更新腳本」處理(不要重跑 install):" \
" All updates, migrations, and new-file additions are handled by the UPDATER (don't re-run install):"
echo ""
echo " curl -sSL https://raw.githubusercontent.com/uncle6me-web/system-dev-template/main/scripts/update.sh | bash"
echo ""
t " (重跑 install 可能建出空白範本、跟你的真資料並存,故在此停止。)" \
" (Re-running install could create empty templates alongside your real data, so it stops here.)"
exit 0
fi
# ── 偵測 vault 類型 → 決定 raw source(原始文件)路徑 ────────── # ── 偵測 vault 類型 → 決定 raw source(原始文件)路徑 ──────────
# 為什麼:這個模板原本假設「原始文件在 docs/」,但 Logseq / Obsidian # 為什麼:這個模板原本假設「原始文件在 docs/」,但 Logseq / Obsidian
# 這種 PKM vault 有自己的目錄慣例,整理時不能照 docs/ 那套搬動, # 這種 PKM vault 有自己的目錄慣例,整理時不能照 docs/ 那套搬動,
+19 -1
View File
@@ -31,6 +31,7 @@ KEPT=()
NEW=() NEW=()
TEMPLATED=() TEMPLATED=()
MIGRATED=() MIGRATED=()
COEXIST=()
# ── 版本比對:先看本機 vs 遠端,給使用者「值不值得更新」的判斷 ── # ── 版本比對:先看本機 vs 遠端,給使用者「值不值得更新」的判斷 ──
# VERSION 新位置在 system-dev/,舊位置在 .claude/(1.8.x 以前)。優先讀新、回退舊。 # VERSION 新位置在 system-dev/,舊位置在 .claude/(1.8.x 以前)。優先讀新、回退舊。
@@ -82,7 +83,12 @@ migrate_dir() { # $1=舊路徑 $2=新路徑
local from="$1" to="$2" local from="$1" to="$2"
[ -e "$from" ] || return 0 # 舊的不存在 → 無需遷移 [ -e "$from" ] || return 0 # 舊的不存在 → 無需遷移
if [ -e "$to" ]; then if [ -e "$to" ]; then
return 0 # 新的已存在 → 冪等略過,不覆蓋 # 目的地已存在。兩種可能:
# (a) 已遷移過 → 舊位置不該還在;冪等略過即可。
# (b) 用戶先 install 建了空殼 → 舊位置仍有真資料,現在「並存」。
# 不能靜默跳過 (b),也絕不自動合併(覆蓋風險)。→ 記為「並存待合併」,警告。
COEXIST+=("$from$to")
return 0
fi fi
mkdir -p "$(dirname "$to")" mkdir -p "$(dirname "$to")"
if mv "$from" "$to" 2>/dev/null; then if mv "$from" "$to" 2>/dev/null; then
@@ -261,6 +267,18 @@ if [ ${#MIGRATED[@]} -gt 0 ]; then
t "📦 結構遷移(已收進 system-dev/):" "📦 Layout migrated (moved into system-dev/):" t "📦 結構遷移(已收進 system-dev/):" "📦 Layout migrated (moved into system-dev/):"
for f in "${MIGRATED[@]}"; do echo "$f"; done for f in "${MIGRATED[@]}"; do echo "$f"; done
fi fi
if [ ${#COEXIST[@]} -gt 0 ]; then
echo ""
t "🛑 偵測到 wiki 並存(新舊位置都有資料,需要合併):" \
"🛑 Coexisting wiki detected (both old and new locations have data — needs merging):"
for f in "${COEXIST[@]}"; do echo "$f"; done
t " 成因:先跑過 install(建了空殼)才遷移,舊位置真資料沒被搬。" \
" Cause: install ran first (created an empty shell), so migration skipped your real data in the old location."
t " 不自動合併(避免覆蓋你的資料)。請叫你的 CC:" \
" Not auto-merged (to avoid overwriting your data). Ask your CC:"
t " 「.claude/wiki/ 和 system-dev/wiki/ 並存,請逐檔比對、把真資料合進 system-dev/,再刪舊的」" \
" \"There are two wikis (.claude/wiki/ and system-dev/wiki/) — diff each file, merge the real data into system-dev/, then delete the old one.\""
fi
if [ ${#NEW[@]} -gt 0 ]; then if [ ${#NEW[@]} -gt 0 ]; then
echo "" echo ""
t "🆕 新功能(舊版沒有,已加入):" "🆕 New features (absent in the old version, now added):" t "🆕 新功能(舊版沒有,已加入):" "🆕 New features (absent in the old version, now added):"
+1 -1
View File
@@ -1 +1 @@
1.10.0 1.10.1
+1 -1
View File
@@ -1 +1 @@
1.10.0 1.10.1