217 lines
5.4 KiB
Bash
Raw Permalink 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.

#!/usr/bin/env bash
# ============================================================
# spec-coding-skills 安装/更新脚本
# 用法: bash <(curl -sL <raw-url>/install.sh) [codex|claude|both]
# 或: bash install.sh [codex|claude|both|目标目录]
# ============================================================
set -euo pipefail
REPO_URL="https://git.internal.intelligrow.cn/zhangfucai/spec-coding-skills.git"
DEFAULT_MODE="codex"
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_title() { echo -e "${CYAN}$1${NC}"; }
MODE=""
TARGET=""
SKILLS_SRC=""
GUIDE_SRC=""
GUIDE_DST=""
REQUEST="${1:-$DEFAULT_MODE}"
TOTAL_NEW=0
TOTAL_UPDATED=0
TOTAL_SKIPPED=0
INSTALLED_TARGETS=""
resolve_layout() {
local input="$1"
case "$input" in
""|codex)
MODE="codex"
TARGET=".codex/skills"
SKILLS_SRC=".codex/skills"
GUIDE_SRC="AGENTS.md.template"
GUIDE_DST="AGENTS.md"
;;
claude)
MODE="claude"
TARGET=".claude/skills"
SKILLS_SRC=".claude/skills"
GUIDE_SRC="CLAUDE.md.template"
GUIDE_DST="CLAUDE.md"
;;
both)
log_warn "both 不是单一布局,请在主流程中单独处理"
exit 1
;;
*)
TARGET="$input"
case "$TARGET" in
*".claude/skills"*)
MODE="claude"
SKILLS_SRC=".claude/skills"
GUIDE_SRC="CLAUDE.md.template"
GUIDE_DST="CLAUDE.md"
;;
*)
MODE="codex"
SKILLS_SRC=".codex/skills"
GUIDE_SRC="AGENTS.md.template"
GUIDE_DST="AGENTS.md"
;;
esac
;;
esac
}
TMP_DIR=$(mktemp -d)
trap "rm -rf $TMP_DIR" EXIT
sync_file() {
local src="$1"
local dst="$2"
local create_msg="$3"
local update_msg="$4"
if [ ! -f "$dst" ]; then
mkdir -p "$(dirname "$dst")"
cp "$src" "$dst"
log_info "$create_msg"
TOTAL_NEW=$((TOTAL_NEW + 1))
elif ! diff -q "$src" "$dst" >/dev/null 2>&1; then
cp "$dst" "$dst.local.bak"
cp "$src" "$dst"
log_warn "$update_msg"
TOTAL_UPDATED=$((TOTAL_UPDATED + 1))
else
TOTAL_SKIPPED=$((TOTAL_SKIPPED + 1))
fi
}
sync_guide_file() {
local src="$1"
local dst="$2"
local create_msg="$3"
local skip_msg="$4"
if [ ! -f "$dst" ]; then
mkdir -p "$(dirname "$dst")"
cp "$src" "$dst"
log_info "$create_msg"
TOTAL_NEW=$((TOTAL_NEW + 1))
else
log_info "$skip_msg"
TOTAL_SKIPPED=$((TOTAL_SKIPPED + 1))
fi
}
install_layout() {
local input="$1"
local skill_dir
local skill_name
local src_file
local rel_path
local dst_dir
local dst_file
local tpl_file
local tpl_name
local dst
local guide_src_path
resolve_layout "$input"
if [ ! -d "$TMP_DIR/$SKILLS_SRC" ]; then
log_warn "上游仓库中不存在技能目录: $SKILLS_SRC"
exit 1
fi
log_info "同步 $MODE: $TARGET"
mkdir -p "$TARGET"
for skill_dir in "$TMP_DIR/$SKILLS_SRC"/*/; do
[ -d "$skill_dir" ] || continue
skill_name=$(basename "$skill_dir")
dst_dir="$TARGET/$skill_name"
[ -f "$skill_dir/SKILL.md" ] || continue
while IFS= read -r -d '' src_file; do
rel_path="${src_file#$skill_dir}"
dst_file="$dst_dir/$rel_path"
sync_file \
"$src_file" \
"$dst_file" \
"✨ 新增: $skill_name/$rel_path ($MODE)" \
"🔄 更新: $skill_name/$rel_path ($MODE) (本地版本已备份为 $(basename "$rel_path").local.bak"
done < <(find "$skill_dir" -type f -print0)
done
for tpl_file in "$TMP_DIR/$SKILLS_SRC"/*.template "$TMP_DIR/$SKILLS_SRC"/*.md; do
[ -f "$tpl_file" ] || continue
tpl_name=$(basename "$tpl_file")
dst="$TARGET/$tpl_name"
sync_file \
"$tpl_file" \
"$dst" \
"✨ 新增模板: $tpl_name ($MODE)" \
"🔄 更新模板: $tpl_name ($MODE) (本地版本已备份为 ${tpl_name}.local.bak"
done
guide_src_path="$TMP_DIR/$GUIDE_SRC"
if [ -f "$guide_src_path" ]; then
sync_guide_file \
"$guide_src_path" \
"$GUIDE_DST" \
"✨ 新增项目引导: ${GUIDE_DST}" \
"⏭️ 跳过项目引导: ${GUIDE_DST}(已存在,保持原样)"
fi
INSTALLED_TARGETS="${INSTALLED_TARGETS}${INSTALLED_TARGETS:+, }$TARGET"
}
# ---------- 拉取最新 ----------
log_title "📦 spec-coding-skills 安装/更新"
echo ""
log_info "拉取最新版本..."
git clone --depth 1 --quiet "$REPO_URL" "$TMP_DIR"
VERSION=$(git -C "$TMP_DIR" describe --tags --always 2>/dev/null || git -C "$TMP_DIR" rev-parse --short HEAD)
log_info "版本: $VERSION"
case "$REQUEST" in
both)
log_info "模式: both"
install_layout codex
install_layout claude
;;
*)
resolve_layout "$REQUEST"
log_info "模式: $MODE"
install_layout "$REQUEST"
;;
esac
# ---------- 汇总 ----------
echo ""
log_title "✅ 完成!"
echo ""
echo " 🧭 模式: $REQUEST"
echo " 📁 目标目录: $INSTALLED_TARGETS"
echo " 📦 版本: $VERSION"
echo ""
echo " ✨ 新增: $TOTAL_NEW"
echo " 🔄 更新: ${TOTAL_UPDATED}(本地版本已备份为 .local.bak"
echo " ⏭️ 无变化: $TOTAL_SKIPPED"
echo ""
if [ "$TOTAL_UPDATED" -gt 0 ]; then
log_warn "${TOTAL_UPDATED} 个文件被更新,本地修改已备份为 .local.bak"
log_warn "如需恢复本地版本: mv SKILL.md.local.bak SKILL.md"
log_warn "如需对比差异: diff SKILL.md SKILL.md.local.bak"
fi