From 6da34c486936811bb57e824517a80ece1e3d702d Mon Sep 17 00:00:00 2001 From: zfc Date: Mon, 9 Mar 2026 22:17:01 +0800 Subject: [PATCH] feat: support codex sh download --- README.md | 16 ++++- install.sh | 202 ++++++++++++++++++++++++++++++----------------------- 2 files changed, 126 insertions(+), 92 deletions(-) diff --git a/README.md b/README.md index f440f71..2848b17 100644 --- a/README.md +++ b/README.md @@ -54,10 +54,13 @@ RequirementsDoc ──▶ PRD ──▶ FeatureSummary ──▶ DevelopmentPlan 一行命令搞定安装和更新。脚本会智能处理:新 skill 直接装,已有的对比更新,本地魔改自动备份。 ```bash -# Codex(默认) +# Claude Code + Codex(推荐) +bash <(curl -sL https://git.internal.intelligrow.cn/zhangfucai/spec-coding-skills/raw/branch/main/install.sh) both + +# Codex only bash <(curl -sL https://git.internal.intelligrow.cn/zhangfucai/spec-coding-skills/raw/branch/main/install.sh) codex -# Claude Code +# Claude Code only bash <(curl -sL https://git.internal.intelligrow.cn/zhangfucai/spec-coding-skills/raw/branch/main/install.sh) claude ``` @@ -65,15 +68,22 @@ bash <(curl -sL https://git.internal.intelligrow.cn/zhangfucai/spec-coding-skill ```bash curl -sL https://git.internal.intelligrow.cn/zhangfucai/spec-coding-skills/raw/branch/main/install.sh -o /tmp/install-skills.sh -bash /tmp/install-skills.sh codex +bash /tmp/install-skills.sh both ``` ### 安装脚本行为 +- `both` 模式:同时安装 `.codex/skills/` 和 `.claude/skills/`,并生成 `AGENTS.md` + `CLAUDE.md` - `codex` 模式:安装到 `.codex/skills/`,并在项目根目录生成或更新 `AGENTS.md` - `claude` 模式:安装到 `.claude/skills/`,并在项目根目录生成或更新 `CLAUDE.md` - 如果传入自定义目标目录,脚本会优先安装 Codex 版 skills;目标路径包含 `.claude/skills` 时自动切到 Claude 版 +### 推荐用法 + +- 团队项目、模板仓库:用 `both`,一次安装双端,最省心 +- 只有你自己在 Codex 里用:用 `codex` +- 仓库明确只服务 Claude Code:用 `claude` + ### 更新策略 | 情况 | 处理方式 | diff --git a/install.sh b/install.sh index c3ac141..f15cba5 100644 --- a/install.sh +++ b/install.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash # ============================================================ # spec-coding-skills 安装/更新脚本 -# 用法: bash <(curl -sL /install.sh) [codex|claude] -# 或: bash install.sh [codex|claude|目标目录] +# 用法: bash <(curl -sL /install.sh) [codex|claude|both] +# 或: bash install.sh [codex|claude|both|目标目录] # ============================================================ set -euo pipefail @@ -19,6 +19,11 @@ 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" @@ -38,6 +43,10 @@ resolve_layout() { GUIDE_SRC="CLAUDE.md.template" GUIDE_DST="CLAUDE.md" ;; + both) + log_warn "both 不是单一布局,请在主流程中单独处理" + exit 1 + ;; *) TARGET="$input" case "$TARGET" in @@ -58,10 +67,92 @@ resolve_layout() { esac } -resolve_layout "${1:-$DEFAULT_MODE}" 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 +} + +install_layout() { + local input="$1" + local skill_dir + local skill_name + local src_file + 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") + src_file="$skill_dir/SKILL.md" + dst_dir="$TARGET/$skill_name" + dst_file="$dst_dir/SKILL.md" + + [ -f "$src_file" ] || continue + + sync_file \ + "$src_file" \ + "$dst_file" \ + "✨ 新增: $skill_name ($MODE)" \ + "🔄 更新: $skill_name ($MODE) (本地版本已备份为 SKILL.md.local.bak)" + 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_file \ + "$guide_src_path" \ + "$GUIDE_DST" \ + "✨ 新增项目引导: $GUIDE_DST" \ + "🔄 更新项目引导: $GUIDE_DST (本地版本已备份为 ${GUIDE_DST}.local.bak)" + fi + + INSTALLED_TARGETS="${INSTALLED_TARGETS}${INSTALLED_TARGETS:+, }$TARGET" +} + # ---------- 拉取最新 ---------- log_title "📦 spec-coding-skills 安装/更新" echo "" @@ -70,102 +161,35 @@ 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" -log_info "模式: $MODE" -if [ ! -d "$TMP_DIR/$SKILLS_SRC" ]; then - log_warn "上游仓库中不存在技能目录: $SKILLS_SRC" - exit 1 -fi - -# ---------- 统计变更 ---------- -NEW=0 -UPDATED=0 -SKIPPED=0 -KEPT=0 - -mkdir -p "$TARGET" - -# 遍历上游 skill 目录 -for skill_dir in "$TMP_DIR/$SKILLS_SRC"/*/; do - [ -d "$skill_dir" ] || continue - skill_name=$(basename "$skill_dir") - src_file="$skill_dir/SKILL.md" - dst_dir="$TARGET/$skill_name" - dst_file="$dst_dir/SKILL.md" - - [ -f "$src_file" ] || continue - - if [ ! -f "$dst_file" ]; then - # 新 skill,直接复制 - mkdir -p "$dst_dir" - cp "$src_file" "$dst_file" - log_info "✨ 新增: $skill_name" - NEW=$((NEW + 1)) - elif diff -q "$src_file" "$dst_file" >/dev/null 2>&1; then - # 内容一致,跳过 - SKIPPED=$((SKIPPED + 1)) - else - # 内容不同:上游有更新 或 用户本地修改过 - # 策略:备份本地版本,写入上游新版本 - cp "$dst_file" "$dst_file.local.bak" - cp "$src_file" "$dst_file" - log_warn "🔄 更新: $skill_name (本地版本已备份为 SKILL.md.local.bak)" - UPDATED=$((UPDATED + 1)) - fi -done - -# 复制模板文件(非 skill 目录的文件) -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" - - if [ ! -f "$dst" ]; then - cp "$tpl_file" "$dst" - log_info "✨ 新增模板: $tpl_name" - NEW=$((NEW + 1)) - elif ! diff -q "$tpl_file" "$dst" >/dev/null 2>&1; then - cp "$dst" "$dst.local.bak" - cp "$tpl_file" "$dst" - log_warn "🔄 更新模板: $tpl_name (本地版本已备份为 ${tpl_name}.local.bak)" - UPDATED=$((UPDATED + 1)) - else - SKIPPED=$((SKIPPED + 1)) - fi -done - -# 安装项目根目录引导文件 -guide_src_path="$TMP_DIR/$GUIDE_SRC" -if [ -f "$guide_src_path" ]; then - if [ ! -f "$GUIDE_DST" ]; then - cp "$guide_src_path" "$GUIDE_DST" - log_info "✨ 新增项目引导: $GUIDE_DST" - NEW=$((NEW + 1)) - elif ! diff -q "$guide_src_path" "$GUIDE_DST" >/dev/null 2>&1; then - cp "$GUIDE_DST" "$GUIDE_DST.local.bak" - cp "$guide_src_path" "$GUIDE_DST" - log_warn "🔄 更新项目引导: $GUIDE_DST (本地版本已备份为 ${GUIDE_DST}.local.bak)" - UPDATED=$((UPDATED + 1)) - else - SKIPPED=$((SKIPPED + 1)) - fi -fi +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 " 🧭 模式: $MODE" -echo " 📁 目标目录: $TARGET" +echo " 🧭 模式: $REQUEST" +echo " 📁 目标目录: $INSTALLED_TARGETS" echo " 📦 版本: $VERSION" echo "" -echo " ✨ 新增: $NEW" -echo " 🔄 更新: $UPDATED(本地版本已备份为 .local.bak)" -echo " ⏭️ 无变化: $SKIPPED" +echo " ✨ 新增: $TOTAL_NEW" +echo " 🔄 更新: $TOTAL_UPDATED(本地版本已备份为 .local.bak)" +echo " ⏭️ 无变化: $TOTAL_SKIPPED" echo "" -if [ "$UPDATED" -gt 0 ]; then - log_warn "有 $UPDATED 个文件被更新,本地修改已备份为 .local.bak" +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