chore(wiki): wiki-init 補骨架 + system-dev-template 安裝/更新腳本
wiki 已初始化過(push 檔活躍維護),本次補從沒建的 pull 層 + arcrun 化範本: - cards/decisions/ 14 張決策原子卡(含 gloss/實體/typed-edge 三元組): 從 decisions-summary 全量改寫 13 + 新增「薄殼規則晚於實作-MCP漂移是歷史債」1 - TAXONOMY 從 PKM 範本換成 arcrun 軸(子系統 零件架構/cypher/credential/recipe/kbdb/ 薄殼/部署/平台原則 + 形態 架構決策/踩坑/機制說明/禁令/案例經驗) - principles 填 13 條跨全局原則(從 rules/ + mindset 蒸餾) - INDEX 真實視圖(子系統角度 + 決策角度,指向 cards) - system-dev/scripts/ + scripts/ install/update 安裝腳本(template 接入) 純基建/文檔,無業務 code(功能 code 見前一 commit)。 raw source(docs/)0 異動、wiki 卡際連結無斷鏈。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Executable
+472
@@ -0,0 +1,472 @@
|
||||
#!/bin/bash
|
||||
# system-dev-template installer
|
||||
# 已有專案接入腳本——只建立缺少的東西,已有的一律不動。
|
||||
#
|
||||
# 模組化安裝:
|
||||
# --wiki 只裝 LLM Wiki(記憶系統 + 機敏防護)
|
||||
# --sdd 只裝 SDD 系統(動 code 前必須有 design.md)
|
||||
# --all 兩個都裝(預設)
|
||||
# 無參數 互動式詢問
|
||||
#
|
||||
# 為什麼留在同一個 repo 用參數選,而不是 fork:
|
||||
# 使用者多半非專業,最怕「我要去哪個 repo」。一個入口 + 選單最友善。
|
||||
# 等未來功能多到 3+ 個再演進成「模板組合器」。模組邊界先在這裡劃好。
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── i18n:依 locale 選語言,預設英文 ──────────────────
|
||||
# 為什麼預設英文:curl | bash 常是 LANG=C,外國人預設就該看得懂;
|
||||
# 台灣使用者 locale 多為 zh_TW,會自動切回繁中。
|
||||
case "${LC_ALL:-${LC_MESSAGES:-${LANG:-}}}" in
|
||||
zh*|*Hant*|*Hans*) IS_ZH="yes" ;;
|
||||
*) IS_ZH="no" ;;
|
||||
esac
|
||||
# t "中文" "English" → 依語系印出對應字串
|
||||
t() { if [ "$IS_ZH" = "yes" ]; then printf '%s\n' "$1"; else printf '%s\n' "$2"; fi; }
|
||||
# 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"
|
||||
# install.sh / update.sh 住在 main/scripts/(不在 template/)。
|
||||
SCRIPTS_URL="https://raw.githubusercontent.com/uncle6me-web/system-dev-template/main/scripts"
|
||||
CREATED=()
|
||||
SKIPPED=()
|
||||
|
||||
# ── 解析模組參數 ──────────────────────────────────
|
||||
MODULE=""
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--wiki|--wiki-only) MODULE="wiki" ;;
|
||||
--sdd|--sdd-only) MODULE="sdd" ;;
|
||||
--all) MODULE="all" ;;
|
||||
-h|--help)
|
||||
if [ "$IS_ZH" = "yes" ]; then
|
||||
cat <<'HELP'
|
||||
用法:install.sh [--wiki | --sdd | --all]
|
||||
--wiki 只裝 LLM Wiki(CC 記憶系統 + 機敏防護)
|
||||
--sdd 只裝 SDD 系統(動 code 前強制要有設計文件)
|
||||
--all 兩個都裝(預設)
|
||||
無參數 互動式詢問要裝哪個
|
||||
HELP
|
||||
else
|
||||
cat <<'HELP'
|
||||
Usage: install.sh [--wiki | --sdd | --all]
|
||||
--wiki Install LLM Wiki only (CC memory system + secret protection)
|
||||
--sdd Install SDD system only (require a design doc before touching code)
|
||||
--all Install both (default)
|
||||
no flag Interactively ask which to install
|
||||
HELP
|
||||
fi
|
||||
exit 0 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "🔧 system-dev-template installer"
|
||||
echo "================================="
|
||||
t "只建立缺少的目錄和檔案,已有的不動。" \
|
||||
"Only creates missing dirs and files; never touches what already exists."
|
||||
echo ""
|
||||
|
||||
# ── 無參數 → 互動式詢問(給非專業使用者)──────────
|
||||
if [ -z "$MODULE" ]; then
|
||||
if [ -t 0 ]; then
|
||||
t "要安裝哪一塊?" "Which part do you want to install?"
|
||||
t " 1) LLM Wiki —— 讓 CC 記住決策、不重複犯錯(含機敏防護)" \
|
||||
" 1) LLM Wiki — let CC remember decisions and avoid repeating mistakes (with secret protection)"
|
||||
t " 2) SDD —— 動 code 前強制先有設計文件" \
|
||||
" 2) SDD — require a design doc before touching code"
|
||||
t " 3) 兩個都裝(推薦)" " 3) Install both (recommended)"
|
||||
echo ""
|
||||
tn "請輸入 1 / 2 / 3 [預設 3]:" "Enter 1 / 2 / 3 [default 3]: "
|
||||
read -r choice || choice=3
|
||||
case "$choice" in
|
||||
1) MODULE="wiki" ;;
|
||||
2) MODULE="sdd" ;;
|
||||
*) MODULE="all" ;;
|
||||
esac
|
||||
else
|
||||
# 非互動環境(如 curl | bash 無 tty)→ 預設全裝
|
||||
MODULE="all"
|
||||
fi
|
||||
fi
|
||||
|
||||
WANT_WIKI=false
|
||||
WANT_SDD=false
|
||||
case "$MODULE" in
|
||||
wiki) WANT_WIKI=true ;;
|
||||
sdd) WANT_SDD=true ;;
|
||||
all) WANT_WIKI=true; WANT_SDD=true ;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
t "📦 安裝模組:$MODULE" "📦 Module: $MODULE"
|
||||
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(原始文件)路徑 ──────────
|
||||
# 為什麼:這個模板原本假設「原始文件在 docs/」,但 Logseq / Obsidian
|
||||
# 這種 PKM vault 有自己的目錄慣例,整理時不能照 docs/ 那套搬動,
|
||||
# 否則會破壞 vault 結構、讓筆記變不可讀。
|
||||
# 偵測結果寫進 CLAUDE.md,讓 CC 和未來的 Cowork skill 都知道
|
||||
# 「該讀/該整理哪裡」而不是亂動。
|
||||
# 必須在建立 CLAUDE.md 之前跑完。
|
||||
VAULT_TYPE=""
|
||||
RAW_SOURCE=""
|
||||
IS_VAULT="no" # 只有 logseq/obsidian 這種「筆記軟體 vault」才算 yes
|
||||
if [ -d "logseq" ]; then
|
||||
VAULT_TYPE="logseq"
|
||||
RAW_SOURCE="pages/, journals/"
|
||||
IS_VAULT="yes"
|
||||
elif [ -d ".obsidian" ]; then
|
||||
VAULT_TYPE="obsidian"
|
||||
RAW_SOURCE="$(tn './ (整個 vault 根目錄的 .md)' './ (all .md under the vault root)')"
|
||||
IS_VAULT="yes"
|
||||
else
|
||||
VAULT_TYPE="docs"
|
||||
RAW_SOURCE="docs/"
|
||||
fi
|
||||
# 偵測到是筆記 vault → 出聲告訴使用者「我看到了,會小心、不破壞你的筆記結構」。
|
||||
# 不是筆記(一般開發案等)→ 不囉嗦,默默把 docs/ 當原始文件夾安裝完成。
|
||||
if [ "$IS_VAULT" = "yes" ]; then
|
||||
t "🗂️ 偵測到 ${VAULT_TYPE} 筆記庫 → 原始文件:${RAW_SOURCE}" \
|
||||
"🗂️ Detected a ${VAULT_TYPE} note vault → raw source: ${RAW_SOURCE}"
|
||||
t " (會保留你筆記軟體的目錄/檔名結構,不搬動、不改名)" \
|
||||
" (your note app's directory/file structure is preserved — nothing is moved or renamed)"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# 把「raw source 宣告區塊」吐出來,給新建的 CLAUDE.md append 或
|
||||
# 給已存在的 CLAUDE.md 當手動補貼的提示。內容對 CC / Cowork 都是
|
||||
# 機器可讀的指令(明確路徑 + 不可破壞 vault 結構的約束)。
|
||||
# 寫進 CLAUDE.md 的 raw source 宣告區塊。給人也給 AI 看:
|
||||
# 依 locale 只寫「一種語言」進 CLAUDE.md(雙語會讓每個 session 的 context 更滿)。
|
||||
emit_raw_source_block() {
|
||||
local source_kind
|
||||
if [ "$IS_ZH" = "yes" ]; then
|
||||
if [ "$IS_VAULT" = "yes" ]; then source_kind="${VAULT_TYPE} 筆記庫"
|
||||
else source_kind="一般專案(原始文件放 raw source 路徑)"; fi
|
||||
cat <<BLOCK
|
||||
|
||||
---
|
||||
|
||||
## 原始文件空間(raw source)
|
||||
|
||||
> 安裝時偵測到的來源型態:**${source_kind}**
|
||||
> CC 與 Cowork 整理/讀取「人寫的原始文件」時,**只在這裡找、只在這裡動**。
|
||||
|
||||
| 項目 | 值 |
|
||||
|------|----|
|
||||
| 來源型態 | \`${source_kind}\` |
|
||||
| raw source | \`${RAW_SOURCE}\` |
|
||||
|
||||
**約束(CC 與 Cowork 都必須遵守)**
|
||||
|
||||
- 整理 wiki/知識時,原始文件**一律從上方 raw source 路徑讀取**,不要假設是 \`docs/\`。
|
||||
BLOCK
|
||||
if [ "$IS_VAULT" = "yes" ]; then
|
||||
cat <<BLOCK
|
||||
- 這是 **${VAULT_TYPE} 筆記庫**:保留它原本的目錄與檔名慣例,**不得搬動、改名、重新分類** \`.md\` 檔,
|
||||
以免破壞筆記軟體結構造成筆記不可讀。整理只在 \`system-dev/wiki/\` 產出,**不動 raw source 本身**。
|
||||
BLOCK
|
||||
fi
|
||||
else
|
||||
if [ "$IS_VAULT" = "yes" ]; then source_kind="${VAULT_TYPE} note vault"
|
||||
else source_kind="regular project (raw source lives at the path below)"; fi
|
||||
cat <<BLOCK
|
||||
|
||||
---
|
||||
|
||||
## Raw source space
|
||||
|
||||
> Source type detected at install time: **${source_kind}**
|
||||
> When CC and Cowork curate/read human-written raw source, **look only here and act only here**.
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Source type | \`${source_kind}\` |
|
||||
| raw source | \`${RAW_SOURCE}\` |
|
||||
|
||||
**Constraints (both CC and Cowork must obey)**
|
||||
|
||||
- When curating the wiki/knowledge, **always read raw source from the path above** — don't assume \`docs/\`.
|
||||
BLOCK
|
||||
if [ "$IS_VAULT" = "yes" ]; then
|
||||
cat <<BLOCK
|
||||
- This is a **${VAULT_TYPE} note vault**: keep its original directory and file-naming conventions. **Do not move, rename, or re-classify** \`.md\` files,
|
||||
or you'll break the note-app structure and make notes unreadable. Curation output goes only into \`system-dev/wiki/\`; **never touch the raw source itself**.
|
||||
BLOCK
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# ── 工具函式 ──────────────────────────────────────
|
||||
create_dir() {
|
||||
if [ ! -d "$1" ]; then
|
||||
mkdir -p "$1"
|
||||
CREATED+=("$1/")
|
||||
else
|
||||
SKIPPED+=("$1/ $(tn '(已存在)' '(already exists)')")
|
||||
fi
|
||||
}
|
||||
|
||||
download_if_missing() {
|
||||
local dest="$1" src="$2"
|
||||
if [ ! -f "$dest" ]; then
|
||||
mkdir -p "$(dirname "$dest")"
|
||||
curl -sSL "$src" -o "$dest"
|
||||
CREATED+=("$dest")
|
||||
else
|
||||
SKIPPED+=("$dest $(tn '(已存在,跳過)' '(already exists, skipped)')")
|
||||
fi
|
||||
}
|
||||
|
||||
# ── 共用結構 ──────────────────────────────────────
|
||||
# 工具自己的文件骨架收進 system-dev/docs/(不污染用戶根目錄、不跟用戶自己的 docs/ 混)。
|
||||
# 注意語義分離:這裡的 system-dev/docs/ 是「工具文件」;用戶的 raw source(原始文件)
|
||||
# 另有其處(見上方 vault 偵測),工具只讀、不搬。
|
||||
# .claude/ 只留 CC 死綁的 commands/ + hooks/,工具資料一律不放這。
|
||||
create_dir "system-dev/docs/1-vision"
|
||||
create_dir "system-dev/docs/2-architecture/decisions"
|
||||
create_dir "system-dev/docs/4-guides"
|
||||
create_dir "system-dev/docs/5-records/incidents"
|
||||
create_dir "system-dev/docs/5-records/test-reports"
|
||||
create_dir "system-dev/docs/6-user"
|
||||
create_dir ".claude/commands"
|
||||
create_dir ".claude/hooks"
|
||||
download_if_missing "system-dev/docs/README.md" "$REPO_URL/system-dev/docs/README.md"
|
||||
|
||||
# 工具版號:放 system-dev/,不寄生 .claude/。
|
||||
download_if_missing "system-dev/VERSION" "$REPO_URL/system-dev/VERSION"
|
||||
|
||||
# ── WIKI 模組 ─────────────────────────────────────
|
||||
# wiki 是工具資料 → 放 system-dev/wiki/(不放 .claude/)。
|
||||
# commands/ 與 hooks/ 是 CC 機制檔 → 維持 .claude/。
|
||||
if $WANT_WIKI; then
|
||||
create_dir "system-dev/wiki"
|
||||
download_if_missing "system-dev/wiki/INDEX.md" "$REPO_URL/system-dev/wiki/INDEX.md"
|
||||
download_if_missing "system-dev/wiki/TAXONOMY.md" "$REPO_URL/system-dev/wiki/TAXONOMY.md"
|
||||
download_if_missing "system-dev/wiki/status.md" "$REPO_URL/system-dev/wiki/status.md"
|
||||
download_if_missing "system-dev/wiki/mistakes.md" "$REPO_URL/system-dev/wiki/mistakes.md"
|
||||
download_if_missing "system-dev/wiki/principles.md" "$REPO_URL/system-dev/wiki/principles.md"
|
||||
download_if_missing "system-dev/wiki/.wikiignore" "$REPO_URL/system-dev/wiki/.wikiignore"
|
||||
|
||||
# wiki 改寫產物(AI 自讀定稿卡片)的正式落點:由工具建好,不靠用戶自救。
|
||||
create_dir "system-dev/wiki/cards"
|
||||
[ -f "system-dev/wiki/cards/.gitkeep" ] || { : > "system-dev/wiki/cards/.gitkeep"; CREATED+=("system-dev/wiki/cards/.gitkeep"); }
|
||||
|
||||
download_if_missing ".claude/commands/wiki-init.md" "$REPO_URL/.claude/commands/wiki-init.md"
|
||||
download_if_missing ".claude/commands/wiki-capture.md" "$REPO_URL/.claude/commands/wiki-capture.md"
|
||||
download_if_missing ".claude/commands/wiki-update.md" "$REPO_URL/.claude/commands/wiki-update.md"
|
||||
download_if_missing ".claude/commands/wiki-recall.md" "$REPO_URL/.claude/commands/wiki-recall.md"
|
||||
|
||||
# wiki 相關 hooks:接關 + 機敏掃描
|
||||
download_if_missing ".claude/hooks/session-start-recall.sh" "$REPO_URL/.claude/hooks/session-start-recall.sh"
|
||||
download_if_missing ".claude/hooks/wiki-secret-scan.sh" "$REPO_URL/.claude/hooks/wiki-secret-scan.sh"
|
||||
|
||||
# Cowork(claude.ai)整理 wiki 用的 skill:與 CC 的 /wiki-init 共用同一套規則
|
||||
# (含 typed-edge、frontmatter 標籤、gloss)。沒這支 → claude.ai 來掃時身上沒規則。
|
||||
download_if_missing "system-dev/docs/SKILL.md" "$REPO_URL/system-dev/docs/SKILL.md"
|
||||
fi
|
||||
|
||||
# ── SDD 模組 ──────────────────────────────────────
|
||||
if $WANT_SDD; then
|
||||
create_dir "system-dev/docs/3-specs"
|
||||
download_if_missing "system-dev/docs/3-specs/TEMPLATE-sdd/design.md" "$REPO_URL/system-dev/docs/3-specs/TEMPLATE-sdd/design.md"
|
||||
download_if_missing "system-dev/docs/3-specs/TEMPLATE-sdd/tasks.md" "$REPO_URL/system-dev/docs/3-specs/TEMPLATE-sdd/tasks.md"
|
||||
download_if_missing "system-dev/docs/2-architecture/decisions/TEMPLATE-adr.md" "$REPO_URL/system-dev/docs/2-architecture/decisions/TEMPLATE-adr.md"
|
||||
|
||||
download_if_missing ".claude/commands/sdd-check.md" "$REPO_URL/.claude/commands/sdd-check.md"
|
||||
download_if_missing ".claude/hooks/sdd-guard.sh" "$REPO_URL/.claude/hooks/sdd-guard.sh"
|
||||
fi
|
||||
|
||||
# ── 安裝/更新腳本:一開始就放進 system-dev/scripts/ ──
|
||||
# 為什麼一開始就裝:之後要更新,用戶(或 CC)直接 `bash system-dev/scripts/update.sh`,
|
||||
# 不必每次都記那串 curl。腳本來源在 main/scripts/(不在 template/)。
|
||||
create_dir "system-dev/scripts"
|
||||
download_if_missing "system-dev/scripts/install.sh" "$SCRIPTS_URL/install.sh"
|
||||
download_if_missing "system-dev/scripts/update.sh" "$SCRIPTS_URL/update.sh"
|
||||
|
||||
# ── 共用 hook:專案自訂禁令骨架(預設停用)────────
|
||||
download_if_missing ".claude/hooks/pre-write-guard.sh" "$REPO_URL/.claude/hooks/pre-write-guard.sh"
|
||||
|
||||
# ── 共用指引:GitHub issue 處理(讀/回普世,跨 repo 發要先問,禁自動輪詢)──
|
||||
download_if_missing ".claude/commands/issue-handle.md" "$REPO_URL/.claude/commands/issue-handle.md"
|
||||
|
||||
chmod +x .claude/hooks/*.sh 2>/dev/null || true
|
||||
|
||||
# ── 依模組產生 settings.json 的 hooks 區塊 ────────
|
||||
# settings.json 因模組而異,不能直接下載單一靜態檔,改條件組裝。
|
||||
build_hooks_json() {
|
||||
local session_hooks="" pretool_hooks=""
|
||||
|
||||
if $WANT_WIKI; then
|
||||
session_hooks='{ "type": "command", "command": ".claude/hooks/session-start-recall.sh" }'
|
||||
fi
|
||||
|
||||
# PreToolUse 依模組疊加
|
||||
local pt=()
|
||||
$WANT_SDD && pt+=('{ "type": "command", "command": ".claude/hooks/sdd-guard.sh" }')
|
||||
pt+=('{ "type": "command", "command": ".claude/hooks/pre-write-guard.sh" }')
|
||||
$WANT_WIKI && pt+=('{ "type": "command", "command": ".claude/hooks/wiki-secret-scan.sh" }')
|
||||
local IFS=,
|
||||
pretool_hooks="${pt[*]}"
|
||||
|
||||
printf '{\n "hooks": {\n'
|
||||
if [ -n "$session_hooks" ]; then
|
||||
printf ' "SessionStart": [\n { "matcher": "startup|resume|clear",\n "hooks": [ %s ] }\n ],\n' "$session_hooks"
|
||||
fi
|
||||
printf ' "PreToolUse": [\n { "matcher": "Write|Edit",\n "hooks": [ %s ] }\n ]\n' "$pretool_hooks"
|
||||
printf ' }\n}\n'
|
||||
}
|
||||
|
||||
if [ ! -f ".claude/settings.json" ]; then
|
||||
build_hooks_json > .claude/settings.json
|
||||
CREATED+=(".claude/settings.json $(tn "(依 $MODULE 模組產生)" "(generated for module: $MODULE)")")
|
||||
else
|
||||
SKIPPED+=(".claude/settings.json $(tn '(已存在,請手動合併 hooks)' '(already exists — merge hooks manually)')")
|
||||
fi
|
||||
|
||||
# ── CLAUDE.md:只在完全不存在時建立 ────────────────
|
||||
# 新建時把偵測到的 raw source 宣告 append 進去(在建立的當下寫入,
|
||||
# 不回頭改使用者既有的 CLAUDE.md,維持「已有不覆蓋」原則)。
|
||||
if [ ! -f "CLAUDE.md" ]; then
|
||||
download_if_missing "CLAUDE.md" "$REPO_URL/CLAUDE.md"
|
||||
if [ -f "CLAUDE.md" ]; then
|
||||
emit_raw_source_block >> CLAUDE.md
|
||||
CREATED+=("CLAUDE.md $(tn "← 已寫入 raw source 宣告(${VAULT_TYPE})" "← raw source declaration written (${VAULT_TYPE})")")
|
||||
fi
|
||||
else
|
||||
SKIPPED+=("CLAUDE.md $(tn '(已存在,請手動加入對應區塊)' '(already exists — add the block manually)')")
|
||||
fi
|
||||
|
||||
# ── 輸出結果 ──────────────────────────────────────
|
||||
echo ""
|
||||
t "✅ 建立了:" "✅ Created:"
|
||||
# 注意:macOS bash 3.2 在 set -u 下展開「空陣列」會炸 unbound variable,
|
||||
# 所以這裡先確認有元素才展開(SKIPPED 區塊在下方本來就有守,CREATED 補上)。
|
||||
if [ ${#CREATED[@]} -gt 0 ]; then
|
||||
for item in "${CREATED[@]}"; do echo " + $item"; done
|
||||
fi
|
||||
|
||||
if [ ${#SKIPPED[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
t "⚠️ 跳過(已存在):" "⚠️ Skipped (already exists):"
|
||||
for item in "${SKIPPED[@]}"; do echo " - $item"; done
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "─────────────────────────────────"
|
||||
|
||||
# CLAUDE.md 已存在 → 依模組提醒手動加區塊
|
||||
if [ -f "CLAUDE.md" ]; then
|
||||
if ! grep -q "raw source" CLAUDE.md; then
|
||||
echo ""
|
||||
t "📌 CLAUDE.md 已存在但缺少 raw source 宣告。" \
|
||||
"📌 CLAUDE.md exists but lacks a raw source declaration."
|
||||
t " 請手動把以下區塊貼進去,讓 CC 與 Cowork 知道原始文件在哪、不要亂動既有結構:" \
|
||||
" Paste the block below in so CC and Cowork know where the raw source is and won't disturb your structure:"
|
||||
emit_raw_source_block | sed 's/^/ /'
|
||||
fi
|
||||
if $WANT_WIKI && ! grep -q "wiki/status.md" CLAUDE.md; then
|
||||
echo ""
|
||||
t "📌 CLAUDE.md 已存在但缺少 wiki 讀取順序,請手動加入:" \
|
||||
"📌 CLAUDE.md exists but lacks the wiki reading order — please add it manually:"
|
||||
echo ""
|
||||
if [ "$IS_ZH" = "yes" ]; then
|
||||
cat <<'SNIP'
|
||||
## Wiki 讀取順序(push:hook 開 session 自動注入)
|
||||
| 檔案 | 時機 | 用途 |
|
||||
|------|------|------|
|
||||
| `system-dev/wiki/status.md` | session 開始第一件事 | 當前進度 |
|
||||
| `system-dev/wiki/principles.md` | 設計任何東西前 | 跨全局原則,必服從 |
|
||||
| `system-dev/wiki/mistakes.md` | 做新功能前 | 已知踩坑 |
|
||||
SNIP
|
||||
else
|
||||
cat <<'SNIP'
|
||||
## Wiki reading order (push: auto-injected at session start)
|
||||
| File | When | Purpose |
|
||||
|------|------|---------|
|
||||
| `system-dev/wiki/status.md` | first thing at session start | current progress |
|
||||
| `system-dev/wiki/principles.md` | before designing anything | global principles, must obey |
|
||||
| `system-dev/wiki/mistakes.md` | before building a new feature | known pitfalls |
|
||||
SNIP
|
||||
fi
|
||||
fi
|
||||
if $WANT_SDD && ! grep -q "system-dev/docs/3-specs" CLAUDE.md; then
|
||||
echo ""
|
||||
t "📌 CLAUDE.md 已存在但缺少 SDD 鐵律,請手動加入:" \
|
||||
"📌 CLAUDE.md exists but lacks the SDD iron rule — please add it manually:"
|
||||
echo ""
|
||||
if [ "$IS_ZH" = "yes" ]; then
|
||||
cat <<'SNIP'
|
||||
## 絕對鐵律
|
||||
1. 任何 code 變動前必須有對應 SDD(system-dev/docs/3-specs/[子系統]/design.md)
|
||||
找不到 → 停手問負責人,不要自行建立。
|
||||
SNIP
|
||||
else
|
||||
cat <<'SNIP'
|
||||
## Iron rule
|
||||
1. Every code change must have a matching SDD (system-dev/docs/3-specs/[subsystem]/design.md).
|
||||
Not found → stop and ask the owner; do not create one on your own.
|
||||
SNIP
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# settings.json 已存在 → 依模組提醒要合併哪些 hook
|
||||
if [ -f ".claude/settings.json" ]; then
|
||||
MISSING_HOOKS=()
|
||||
$WANT_WIKI && ! grep -q "session-start-recall.sh" .claude/settings.json && MISSING_HOOKS+=("SessionStart: session-start-recall.sh")
|
||||
$WANT_WIKI && ! grep -q "wiki-secret-scan.sh" .claude/settings.json && MISSING_HOOKS+=("PreToolUse(Write|Edit): wiki-secret-scan.sh")
|
||||
$WANT_SDD && ! grep -q "sdd-guard.sh" .claude/settings.json && MISSING_HOOKS+=("PreToolUse(Write|Edit): sdd-guard.sh")
|
||||
if [ ${#MISSING_HOOKS[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
t "📌 .claude/settings.json 已存在,請手動把以下 hooks 合併進去(保留既有設定):" \
|
||||
"📌 .claude/settings.json exists — merge the hooks below in manually (keep your existing settings):"
|
||||
for h in "${MISSING_HOOKS[@]}"; do echo " • $h"; done
|
||||
fi
|
||||
fi
|
||||
|
||||
# pre-write-guard 是空殼,提醒它預設不攔(避免「以為有保護其實沒有」的安全錯覺)
|
||||
echo ""
|
||||
t "ℹ️ .claude/hooks/pre-write-guard.sh 是「按需手填的空插槽」,預設不攔任何東西。" \
|
||||
"ℹ️ .claude/hooks/pre-write-guard.sh is an empty slot to fill on demand — by default it blocks nothing."
|
||||
t " 需要專案禁令?最簡單是叫你的 CC 寫一支貼合的 guard hook(比範本表達力強);" \
|
||||
" Need project-specific bans? Easiest is to ask your CC to write a tailored guard hook (more expressive than the template);"
|
||||
t " 或自己填 FORBIDDEN_PATTERNS 並到 settings.json 掛上才會生效。" \
|
||||
" or fill in FORBIDDEN_PATTERNS yourself and wire it into settings.json to take effect."
|
||||
|
||||
echo ""
|
||||
t "🚀 下一步:" "🚀 Next steps:"
|
||||
if $WANT_WIKI; then
|
||||
t " 在 Claude Code 對話裡執行 /wiki-init" \
|
||||
" In a Claude Code conversation, run /wiki-init"
|
||||
t " CC 會掃描現有文件、套用 .wikiignore、建立 wiki。" \
|
||||
" CC will scan your existing docs, apply .wikiignore, and build the wiki."
|
||||
fi
|
||||
if $WANT_SDD; then
|
||||
t " 動 code 前先在 system-dev/docs/3-specs/[子系統]/ 建 design.md(可用 /sdd-check 協助)" \
|
||||
" Before touching code, create design.md under system-dev/docs/3-specs/[subsystem]/ (use /sdd-check to help)"
|
||||
fi
|
||||
t " GitHub issue:CC 可直接 /issue-handle 讀回自己 repo 的 issue(禁自動輪詢)" \
|
||||
" GitHub issues: CC can use /issue-handle to read issues from its own repo (no auto-polling)"
|
||||
echo ""
|
||||
Executable
+332
@@ -0,0 +1,332 @@
|
||||
#!/bin/bash
|
||||
# system-dev-template updater
|
||||
# 已安裝舊版的人,一鍵更新到新版。
|
||||
#
|
||||
# 核心安全原則:只覆蓋「模板/邏輯檔」,絕不碰「使用者資料檔」。
|
||||
# ✅ 可覆蓋:hooks/*.sh、commands/*.md、TEMPLATE-*、wiki/INDEX.md
|
||||
# ——這些由模板維護,使用者不會手改,新版直接換掉。
|
||||
# 🔒 絕不碰:wiki/status.md、mistakes.md、decisions-summary.md、TAXONOMY.md、.wikiignore、
|
||||
# settings.json、CLAUDE.md
|
||||
# ——這些是使用者自己填的內容,覆蓋=清空他的記憶與設定。
|
||||
#
|
||||
# 「第一次更新」的雞生蛋問題:
|
||||
# 舊版本機沒有 update.sh。所以第一次靠 README 那行 curl 從遠端抓這支腳本來跑。
|
||||
# 跑完它會把自己也更新進 scripts/update.sh,之後就能直接跑本機的 `bash scripts/update.sh`。
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── i18n:依 locale 選語言,預設英文(curl | bash 常為 LANG=C)──
|
||||
case "${LC_ALL:-${LC_MESSAGES:-${LANG:-}}}" in
|
||||
zh*|*Hant*|*Hans*) IS_ZH="yes" ;;
|
||||
*) IS_ZH="no" ;;
|
||||
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"
|
||||
TEMPLATE_URL="$REPO_RAW/template"
|
||||
|
||||
UPDATED=()
|
||||
KEPT=()
|
||||
NEW=()
|
||||
TEMPLATED=()
|
||||
MIGRATED=()
|
||||
COEXIST=()
|
||||
|
||||
# ── 版本比對:先看本機 vs 遠端,給使用者「值不值得更新」的判斷 ──
|
||||
# VERSION 新位置在 system-dev/,舊位置在 .claude/(1.8.x 以前)。優先讀新、回退舊。
|
||||
LOCAL_VER="$(tn '(未知)' '(unknown)')"
|
||||
if [ -f "system-dev/VERSION" ]; then
|
||||
LOCAL_VER="$(tr -d '[:space:]' < system-dev/VERSION)"
|
||||
elif [ -f ".claude/VERSION" ]; then
|
||||
LOCAL_VER="$(tr -d '[:space:]' < .claude/VERSION)"
|
||||
fi
|
||||
REMOTE_VER="$(curl -sSL "$TEMPLATE_URL/system-dev/VERSION" 2>/dev/null | tr -d '[:space:]' || echo '')"
|
||||
# 容錯:curl 對 404 會把「404:NotFound」當內容輸出(非空),舊版誤把它寫進 VERSION。
|
||||
# 這裡驗證必須像版號(X.Y.Z),否則一律視為取不到,避免污染 VERSION 檔。
|
||||
case "$REMOTE_VER" in
|
||||
[0-9]*.[0-9]*.[0-9]*) : ;; # 形如 1.9.0 → 合法
|
||||
*) REMOTE_VER="" ;; # 404 / HTML 錯誤頁 / 其他 → 當作沒抓到
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "🔄 system-dev-template updater"
|
||||
echo "================================="
|
||||
t " 本機版本:${LOCAL_VER}" " Local version: ${LOCAL_VER}"
|
||||
t " 最新版本:${REMOTE_VER:-取不到(檢查網路)}" \
|
||||
" Latest version: ${REMOTE_VER:-unavailable (check network)}"
|
||||
echo ""
|
||||
|
||||
if [ -z "$REMOTE_VER" ]; then
|
||||
t "❌ 取不到遠端版本,可能是網路問題。請稍後再試。" \
|
||||
"❌ Could not fetch the remote version (likely a network issue). Please try again later."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$LOCAL_VER" = "$REMOTE_VER" ]; then
|
||||
t "✅ 已是最新版(${LOCAL_VER}),不需更新。" \
|
||||
"✅ Already up to date (${LOCAL_VER}), nothing to update."
|
||||
t " (仍會同步模板邏輯檔,確保 hooks/commands 與最新一致。)" \
|
||||
" (Template logic files will still be synced to keep hooks/commands in line with the latest.)"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# ── 結構遷移(1.9.0):舊版把 wiki/VERSION 放 .claude/、工具 docs 放根 docs/ ──
|
||||
# 新版一律收進 system-dev/。這裡冪等遷移:偵測舊位置 → 搬到 system-dev/,已搬過則略過。
|
||||
# 必須在「模組偵測」之前跑(偵測靠目錄存在與否判斷,搬完才看得到新位置)。
|
||||
#
|
||||
# 安全原則:
|
||||
# - wiki 整包搬(含 cards/ 與可能的 wiki/.git),用 mv 保留內含 .git。
|
||||
# - docs 只搬「工具自己鋪的白名單」子目錄;用戶自填在 docs/ 的其他內容一律不動。
|
||||
# - 目的地已存在同名 → 不覆蓋(保留用戶在新位置的東西),略過該項。
|
||||
migrate_dir() { # $1=舊路徑 $2=新路徑
|
||||
local from="$1" to="$2"
|
||||
[ -e "$from" ] || return 0 # 舊的不存在 → 無需遷移
|
||||
if [ -e "$to" ]; then
|
||||
# 目的地已存在。兩種可能:
|
||||
# (a) 已遷移過 → 舊位置不該還在;冪等略過即可。
|
||||
# (b) 用戶先 install 建了空殼 → 舊位置仍有真資料,現在「並存」。
|
||||
# 不能靜默跳過 (b),也絕不自動合併(覆蓋風險)。→ 記為「並存待合併」,警告。
|
||||
COEXIST+=("$from ↔ $to")
|
||||
return 0
|
||||
fi
|
||||
mkdir -p "$(dirname "$to")"
|
||||
if mv "$from" "$to" 2>/dev/null; then
|
||||
MIGRATED+=("$from → $to")
|
||||
fi
|
||||
}
|
||||
|
||||
# 任一舊位置還在 → 需要遷移(遷移本身冪等:已搬的項目會被 migrate_dir 略過)。
|
||||
NEEDS_MIGRATE="no"
|
||||
if [ -d ".claude/wiki" ] || [ -f ".claude/VERSION" ] \
|
||||
|| [ -d "docs/3-specs" ] || [ -f "docs/SKILL.md" ] || [ -f "docs/README.md" ]; then
|
||||
NEEDS_MIGRATE="yes"
|
||||
fi
|
||||
|
||||
if [ "$NEEDS_MIGRATE" = "yes" ]; then
|
||||
t "🔧 偵測到舊版結構,遷移到 system-dev/ …" "🔧 Old layout detected — migrating into system-dev/ …"
|
||||
mkdir -p system-dev
|
||||
|
||||
# wiki(含 cards/ 與內含的 .git)整包搬
|
||||
migrate_dir ".claude/wiki" "system-dev/wiki"
|
||||
# 工具版號
|
||||
migrate_dir ".claude/VERSION" "system-dev/VERSION"
|
||||
# 工具文件白名單(只搬工具鋪的,用戶自填的 docs 內容不動)
|
||||
migrate_dir "docs/SKILL.md" "system-dev/docs/SKILL.md"
|
||||
migrate_dir "docs/README.md" "system-dev/docs/README.md"
|
||||
migrate_dir "docs/1-vision" "system-dev/docs/1-vision"
|
||||
migrate_dir "docs/2-architecture" "system-dev/docs/2-architecture"
|
||||
migrate_dir "docs/3-specs" "system-dev/docs/3-specs"
|
||||
migrate_dir "docs/4-guides" "system-dev/docs/4-guides"
|
||||
migrate_dir "docs/5-records" "system-dev/docs/5-records"
|
||||
migrate_dir "docs/6-user" "system-dev/docs/6-user"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# ── 工具函式 ───────────────────────────────────────
|
||||
# 覆蓋更新:模板/邏輯檔,無條件抓最新版蓋掉。
|
||||
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 cmp -s "$dest" "$dest.tmp"; then
|
||||
rm -f "$dest.tmp" # 內容相同,不算更新
|
||||
else
|
||||
mv "$dest.tmp" "$dest"
|
||||
UPDATED+=("$dest")
|
||||
fi
|
||||
else
|
||||
rm -f "$dest.tmp"
|
||||
t " ⚠️ 抓取失敗,保留原檔:$dest" " ⚠️ Download failed, keeping the original: $dest"
|
||||
fi
|
||||
else
|
||||
if curl -sSL "$src" -o "$dest" 2>/dev/null && [ -s "$dest" ]; then
|
||||
NEW+=("$dest") # 新功能:舊版沒有的檔
|
||||
else
|
||||
rm -f "$dest"
|
||||
t " ⚠️ 抓取失敗:$dest" " ⚠️ Download failed: $dest"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 保留:使用者資料檔,只記錄「有保留」,永遠不動。
|
||||
keep_file() {
|
||||
[ -f "$1" ] && KEPT+=("$1") || true
|
||||
}
|
||||
|
||||
# 補新檔:舊版沒有、新版才有的「使用者資料檔」(如 principles.md)。
|
||||
# 不存在 → 抓範本下來(之後由使用者/CC 填);已存在 → 當用戶資料保留,絕不覆蓋。
|
||||
add_if_missing() {
|
||||
local dest="$1" src="$2"
|
||||
if [ -f "$dest" ]; then
|
||||
KEPT+=("$dest")
|
||||
elif curl -sSL "$src" -o "$dest" 2>/dev/null && [ -s "$dest" ]; then
|
||||
NEW+=("$dest")
|
||||
else
|
||||
rm -f "$dest"
|
||||
fi
|
||||
}
|
||||
|
||||
# 客製檔:使用者一定會手填內容(如 pre-write-guard.sh)。
|
||||
# - 已存在 → 絕不覆蓋,但把最新模板版抓到 <檔名>.template.sh 旁邊,供使用者自行 diff 採納。
|
||||
# - 不存在 → 視同新檔,直接抓本體(第一次安裝才會走這條)。
|
||||
keep_with_template() {
|
||||
local dest="$1" src="$2"
|
||||
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 [ -f "$tmpl" ] && cmp -s "$tmpl" "$tmpl.tmp"; then
|
||||
rm -f "$tmpl.tmp" # 模板版沒變,不重複提示
|
||||
else
|
||||
mv "$tmpl.tmp" "$tmpl"
|
||||
TEMPLATED+=("$tmpl")
|
||||
fi
|
||||
else
|
||||
rm -f "$tmpl.tmp"
|
||||
fi
|
||||
else
|
||||
update_file "$dest" "$src" # 還沒裝過 → 當新檔處理
|
||||
fi
|
||||
}
|
||||
|
||||
# ── 偵測已安裝哪些模組(依現有檔案判斷,更新只動已裝的)──
|
||||
# 遷移已在上面跑完,這裡看新位置 system-dev/。
|
||||
HAS_WIKI=false
|
||||
HAS_SDD=false
|
||||
[ -d "system-dev/wiki" ] && HAS_WIKI=true
|
||||
if [ -f ".claude/hooks/sdd-guard.sh" ] || [ -d "system-dev/docs/3-specs/TEMPLATE-sdd" ]; then HAS_SDD=true; fi
|
||||
|
||||
t "📦 偵測到已安裝模組:" "📦 Detected installed modules:"
|
||||
$HAS_WIKI && echo " • LLM Wiki"
|
||||
$HAS_SDD && echo " • SDD"
|
||||
{ $HAS_WIKI || $HAS_SDD; } || \
|
||||
t " (未偵測到任何模組——這裡可能還沒安裝,請改跑 install.sh)" \
|
||||
" (No modules detected — nothing installed here yet; run install.sh instead.)"
|
||||
echo ""
|
||||
|
||||
# ── 客製檔:使用者手填的 guardrail,永不覆蓋(issue #3)──
|
||||
# pre-write-guard.sh 的定位是「空白客製模板,使用者沒配置前不提供保護」(CHANGELOG 1.2.0)。
|
||||
# 下游通常已塞滿自己的 enforcement,直接覆蓋=無聲關掉整套 guardrail。
|
||||
# 改為:保留原檔不動,新版範本另存 pre-write-guard.template.sh,由使用者自行 diff 採納。
|
||||
keep_with_template ".claude/hooks/pre-write-guard.sh" "$TEMPLATE_URL/.claude/hooks/pre-write-guard.sh"
|
||||
|
||||
# ── 模板/邏輯檔:覆蓋更新 ──────────────────────────
|
||||
# 共用 hook 與指引
|
||||
update_file ".claude/commands/issue-handle.md" "$TEMPLATE_URL/.claude/commands/issue-handle.md"
|
||||
update_file "system-dev/VERSION" "$TEMPLATE_URL/system-dev/VERSION"
|
||||
|
||||
if $HAS_WIKI; then
|
||||
# wiki 的「邏輯檔」:導航與 hooks,可覆蓋。wiki 資料在 system-dev/,hooks/commands 留 .claude/。
|
||||
update_file "system-dev/wiki/INDEX.md" "$TEMPLATE_URL/system-dev/wiki/INDEX.md"
|
||||
update_file ".claude/hooks/session-start-recall.sh" "$TEMPLATE_URL/.claude/hooks/session-start-recall.sh"
|
||||
update_file ".claude/hooks/wiki-secret-scan.sh" "$TEMPLATE_URL/.claude/hooks/wiki-secret-scan.sh"
|
||||
update_file ".claude/commands/wiki-init.md" "$TEMPLATE_URL/.claude/commands/wiki-init.md"
|
||||
update_file ".claude/commands/wiki-capture.md" "$TEMPLATE_URL/.claude/commands/wiki-capture.md"
|
||||
update_file ".claude/commands/wiki-update.md" "$TEMPLATE_URL/.claude/commands/wiki-update.md"
|
||||
update_file ".claude/commands/wiki-recall.md" "$TEMPLATE_URL/.claude/commands/wiki-recall.md"
|
||||
# Cowork(claude.ai)的 wiki 整理 skill:規則檔,可覆蓋
|
||||
update_file "system-dev/docs/SKILL.md" "$TEMPLATE_URL/system-dev/docs/SKILL.md"
|
||||
|
||||
# wiki 的「使用者資料」:絕不碰
|
||||
keep_file "system-dev/wiki/status.md"
|
||||
keep_file "system-dev/wiki/mistakes.md"
|
||||
# principles.md(1.10):舊版沒有 → 補範本;已有 → 當用戶資料保留
|
||||
add_if_missing "system-dev/wiki/principles.md" "$TEMPLATE_URL/system-dev/wiki/principles.md"
|
||||
keep_file "system-dev/wiki/decisions-summary.md"
|
||||
keep_file "system-dev/wiki/TAXONOMY.md"
|
||||
keep_file "system-dev/wiki/.wikiignore"
|
||||
fi
|
||||
|
||||
if $HAS_SDD; then
|
||||
# SDD 範本與 hook:可覆蓋
|
||||
update_file "system-dev/docs/3-specs/TEMPLATE-sdd/design.md" "$TEMPLATE_URL/system-dev/docs/3-specs/TEMPLATE-sdd/design.md"
|
||||
update_file "system-dev/docs/3-specs/TEMPLATE-sdd/tasks.md" "$TEMPLATE_URL/system-dev/docs/3-specs/TEMPLATE-sdd/tasks.md"
|
||||
update_file "system-dev/docs/2-architecture/decisions/TEMPLATE-adr.md" "$TEMPLATE_URL/system-dev/docs/2-architecture/decisions/TEMPLATE-adr.md"
|
||||
update_file ".claude/commands/sdd-check.md" "$TEMPLATE_URL/.claude/commands/sdd-check.md"
|
||||
update_file ".claude/hooks/sdd-guard.sh" "$TEMPLATE_URL/.claude/hooks/sdd-guard.sh"
|
||||
fi
|
||||
|
||||
# ── 自我更新:把最新的 update.sh / install.sh 抓到 system-dev/scripts/ ──
|
||||
# 這兩支在 main/scripts/ 下(不在 template/);落地位置新版收進 system-dev/scripts/。
|
||||
update_file "system-dev/scripts/update.sh" "$REPO_RAW/scripts/update.sh"
|
||||
update_file "system-dev/scripts/install.sh" "$REPO_RAW/scripts/install.sh"
|
||||
|
||||
chmod +x .claude/hooks/*.sh system-dev/scripts/*.sh 2>/dev/null || true
|
||||
|
||||
# ── 使用者資料檔:絕不碰,但提醒「設定可能有新欄位要手動補」──
|
||||
keep_file ".claude/settings.json"
|
||||
keep_file "CLAUDE.md"
|
||||
|
||||
# ── 結果輸出 ───────────────────────────────────────
|
||||
echo ""
|
||||
echo "─────────────────────────────────"
|
||||
if [ ${#MIGRATED[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
t "📦 結構遷移(已收進 system-dev/):" "📦 Layout migrated (moved into system-dev/):"
|
||||
for f in "${MIGRATED[@]}"; do echo " ⇒ $f"; done
|
||||
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
|
||||
echo ""
|
||||
t "🆕 新功能(舊版沒有,已加入):" "🆕 New features (absent in the old version, now added):"
|
||||
for f in "${NEW[@]}"; do echo " + $f"; done
|
||||
fi
|
||||
if [ ${#UPDATED[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
t "⬆️ 已更新(覆蓋成新版):" "⬆️ Updated (overwritten with the new version):"
|
||||
for f in "${UPDATED[@]}"; do echo " ~ $f"; done
|
||||
fi
|
||||
if [ ${#NEW[@]} -eq 0 ] && [ ${#UPDATED[@]} -eq 0 ]; then
|
||||
echo ""
|
||||
t "✨ 模板邏輯檔已全部最新,無需變動。" \
|
||||
"✨ All template logic files are already up to date — no changes needed."
|
||||
fi
|
||||
if [ ${#KEPT[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
t "🔒 完整保留(你的內容/設定,從未碰過):" \
|
||||
"🔒 Fully preserved (your content/settings, never touched):"
|
||||
for f in "${KEPT[@]}"; do echo " = $f"; done
|
||||
fi
|
||||
if [ ${#TEMPLATED[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
t "📋 客製檔有新版範本(你的原檔沒動,新版另存旁邊,請自行 diff 採納):" \
|
||||
"📋 Custom files have a new template version (your original is untouched; the new one is saved alongside — diff and adopt as you like):"
|
||||
for f in "${TEMPLATED[@]}"; do
|
||||
echo " → $f"
|
||||
t " 比對:diff \"${f%.template.sh}.sh\" \"$f\"" \
|
||||
" compare: diff \"${f%.template.sh}.sh\" \"$f\""
|
||||
done
|
||||
fi
|
||||
|
||||
# ── settings.json 提醒:新模組 hook 可能要手動補 ──
|
||||
if [ -f ".claude/settings.json" ]; then
|
||||
MISSING=()
|
||||
$HAS_WIKI && ! grep -q "session-start-recall.sh" .claude/settings.json && MISSING+=("SessionStart: session-start-recall.sh")
|
||||
$HAS_WIKI && ! grep -q "wiki-secret-scan.sh" .claude/settings.json && MISSING+=("PreToolUse(Write|Edit): wiki-secret-scan.sh")
|
||||
$HAS_SDD && ! grep -q "sdd-guard.sh" .claude/settings.json && MISSING+=("PreToolUse(Write|Edit): sdd-guard.sh")
|
||||
if [ ${#MISSING[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
t "📌 settings.json 是你的設定(沒動),但偵測到缺以下 hook,請手動補上:" \
|
||||
"📌 settings.json is yours (untouched), but these hooks are missing — please add them manually:"
|
||||
for h in "${MISSING[@]}"; do echo " • $h"; done
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
t "🚀 更新完成:${LOCAL_VER} → ${REMOTE_VER}" "🚀 Update complete: ${LOCAL_VER} → ${REMOTE_VER}"
|
||||
t " 下次更新直接跑:bash system-dev/scripts/update.sh" " Next time, just run: bash system-dev/scripts/update.sh"
|
||||
t " 改了什麼看:CHANGELOG.md" " See what changed: CHANGELOG.md"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user