#!/bin/bash # skill.sh - Skills 管理器主入口 # 用法: # ./skill.sh list - 列出已安装技能 # ./skill.sh install - 安装新技能 # ./skill.sh upgrade [name] - 升级技能 # ./skill.sh uninstall - 卸载技能 # ./skill.sh rollback - 回滚版本 # ./skill.sh info - 查看技能详情 # ./skill.sh enable - 启用技能 # ./skill.sh disable - 禁用技能 # ./skill.sh check - 检查所有技能更新 set -e SKILLS_DIR="$HOME/.claude/skills" REPOS_DIR="$SKILLS_DIR/repos" SCRIPTS_DIR="$SKILLS_DIR/skill-manager/scripts" REGISTRY_SCRIPT="$SCRIPTS_DIR/registry.sh" GIT_OPS_SCRIPT="$SCRIPTS_DIR/git-ops.sh" # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # 显示 banner show_banner() { echo -e "${CYAN}" echo "╔═══════════════════════════════════════╗" echo "║ Skills Manager v1.0.0 ║" echo "║ 自我进化技能管理器 ║" echo "╚═══════════════════════════════════════╝" echo -e "${NC}" } # 从 URL 提取技能名称 extract_name() { local repo="$1" echo "$repo" | sed -E 's|.*/([^/]+)(\.git)?$|\1|' | sed 's/\.git$//' } # 列出所有技能 cmd_list() { echo -e "${BLUE}已安装技能:${NC}" echo "════════════════════════════════════════" "$REGISTRY_SCRIPT" list } # 安装技能 cmd_install() { local repo="$1" if [ -z "$repo" ]; then echo -e "${RED}用法: skill install ${NC}" echo "示例: skill install https://github.com/org/skill-name.git" exit 1 fi local name=$(extract_name "$repo") echo -e "${BLUE}安装技能: $name${NC}" echo "════════════════════════════════════════" # 检查是否已安装 if [ -d "$REPOS_DIR/$name" ]; then echo -e "${YELLOW}技能已安装,使用 'skill upgrade $name' 更新${NC}" exit 1 fi # 克隆仓库 "$GIT_OPS_SCRIPT" clone "$repo" "$name" # 验证 skill.yaml local skill_yaml="$REPOS_DIR/$name/skill.yaml" if [ -f "$skill_yaml" ]; then "$SCRIPTS_DIR/validate.sh" "$REPOS_DIR/$name" fi # 创建符号链接到 skills 目录 local skill_dir="$SKILLS_DIR/$name" if [ ! -d "$skill_dir" ]; then mkdir -p "$skill_dir" # 复制 SKILL.md local prompt_file=$(yq e '.prompt_file // "SKILL.md"' "$skill_yaml" 2>/dev/null || echo "SKILL.md") if [ -f "$REPOS_DIR/$name/$prompt_file" ]; then cp "$REPOS_DIR/$name/$prompt_file" "$skill_dir/SKILL.md" fi fi # 执行 post_install 钩子 if command -v yq &> /dev/null && [ -f "$skill_yaml" ]; then local hooks=$(yq e '.hooks.post_install[]' "$skill_yaml" 2>/dev/null || echo "") if [ -n "$hooks" ]; then echo -e "${YELLOW}执行安装后钩子...${NC}" echo "$hooks" | while read -r cmd; do [ -n "$cmd" ] && eval "$cmd" done fi fi echo "" echo -e "${GREEN}✓ 技能安装完成: $name${NC}" } # 升级技能 cmd_upgrade() { local name="$1" echo -e "${BLUE}升级技能${NC}" echo "════════════════════════════════════════" if [ -z "$name" ]; then # 升级所有技能 echo "升级所有技能..." local skills=$(ls -1 "$REPOS_DIR" 2>/dev/null || echo "") if [ -z "$skills" ]; then echo "没有已安装的技能" exit 0 fi for skill in $skills; do echo "" echo -e "${CYAN}>>> $skill${NC}" "$GIT_OPS_SCRIPT" pull "$skill" || echo -e "${YELLOW}跳过 $skill${NC}" done else # 升级指定技能 if [ ! -d "$REPOS_DIR/$name" ]; then echo -e "${RED}技能不存在: $name${NC}" exit 1 fi "$GIT_OPS_SCRIPT" pull "$name" # 同步 SKILL.md local skill_yaml="$REPOS_DIR/$name/skill.yaml" if [ -f "$skill_yaml" ]; then local prompt_file=$(yq e '.prompt_file // "SKILL.md"' "$skill_yaml" 2>/dev/null || echo "SKILL.md") if [ -f "$REPOS_DIR/$name/$prompt_file" ]; then mkdir -p "$SKILLS_DIR/$name" cp "$REPOS_DIR/$name/$prompt_file" "$SKILLS_DIR/$name/SKILL.md" fi # 执行 post_update 钩子 local hooks=$(yq e '.hooks.post_update[]' "$skill_yaml" 2>/dev/null || echo "") if [ -n "$hooks" ]; then echo -e "${YELLOW}执行更新后钩子...${NC}" echo "$hooks" | while read -r cmd; do [ -n "$cmd" ] && eval "$cmd" done fi fi fi echo "" echo -e "${GREEN}✓ 升级完成${NC}" } # 卸载技能 cmd_uninstall() { local name="$1" if [ -z "$name" ]; then echo -e "${RED}用法: skill uninstall ${NC}" exit 1 fi echo -e "${BLUE}卸载技能: $name${NC}" echo "════════════════════════════════════════" if [ ! -d "$REPOS_DIR/$name" ]; then echo -e "${YELLOW}技能不存在: $name${NC}" exit 0 fi # 确认 echo -e "${YELLOW}确认卸载 $name? [y/N]${NC}" read -r confirm if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then echo "取消卸载" exit 0 fi # 执行 post_uninstall 钩子 local skill_yaml="$REPOS_DIR/$name/skill.yaml" if command -v yq &> /dev/null && [ -f "$skill_yaml" ]; then local hooks=$(yq e '.hooks.post_uninstall[]' "$skill_yaml" 2>/dev/null || echo "") if [ -n "$hooks" ]; then echo -e "${YELLOW}执行卸载钩子...${NC}" echo "$hooks" | while read -r cmd; do [ -n "$cmd" ] && eval "$cmd" done fi fi # 删除仓库 rm -rf "$REPOS_DIR/$name" echo -e "${GREEN}✓ 已删除仓库: $REPOS_DIR/$name${NC}" # 删除技能目录 rm -rf "$SKILLS_DIR/$name" echo -e "${GREEN}✓ 已删除技能目录: $SKILLS_DIR/$name${NC}" # 从 registry 移除 "$REGISTRY_SCRIPT" remove "$name" echo "" echo -e "${GREEN}✓ 技能已卸载: $name${NC}" } # 回滚版本 cmd_rollback() { local name="$1" local version="$2" if [ -z "$name" ] || [ -z "$version" ]; then echo -e "${RED}用法: skill rollback ${NC}" exit 1 fi echo -e "${BLUE}回滚技能: $name → $version${NC}" echo "════════════════════════════════════════" "$GIT_OPS_SCRIPT" checkout "$name" "$version" # 同步 SKILL.md local skill_yaml="$REPOS_DIR/$name/skill.yaml" if [ -f "$skill_yaml" ]; then local prompt_file=$(yq e '.prompt_file // "SKILL.md"' "$skill_yaml" 2>/dev/null || echo "SKILL.md") if [ -f "$REPOS_DIR/$name/$prompt_file" ]; then mkdir -p "$SKILLS_DIR/$name" cp "$REPOS_DIR/$name/$prompt_file" "$SKILLS_DIR/$name/SKILL.md" fi fi echo "" echo -e "${GREEN}✓ 回滚完成${NC}" } # 查看技能详情 cmd_info() { local name="$1" if [ -z "$name" ]; then echo -e "${RED}用法: skill info ${NC}" exit 1 fi echo -e "${BLUE}技能详情: $name${NC}" echo "════════════════════════════════════════" "$GIT_OPS_SCRIPT" status "$name" # 显示 skill.yaml 信息 local skill_yaml="$REPOS_DIR/$name/skill.yaml" if [ -f "$skill_yaml" ] && command -v yq &> /dev/null; then echo "" echo "技能配置:" echo "----------------------------------------" echo "描述: $(yq e '.description' "$skill_yaml" | head -1)" echo "作者: $(yq e '.author // "未知"' "$skill_yaml")" local deps=$(yq e '.dependencies[]' "$skill_yaml" 2>/dev/null || echo "") if [ -n "$deps" ]; then echo "依赖: $deps" fi local keywords=$(yq e '.triggers.keywords[]' "$skill_yaml" 2>/dev/null | tr '\n' ', ' | sed 's/,$//') if [ -n "$keywords" ]; then echo "关键词: $keywords" fi fi } # 启用技能 cmd_enable() { local name="$1" if [ -z "$name" ]; then echo -e "${RED}用法: skill enable ${NC}" exit 1 fi "$REGISTRY_SCRIPT" update "$name" status "active" echo -e "${GREEN}✓ 已启用技能: $name${NC}" } # 禁用技能 cmd_disable() { local name="$1" if [ -z "$name" ]; then echo -e "${RED}用法: skill disable ${NC}" exit 1 fi "$REGISTRY_SCRIPT" update "$name" status "disabled" echo -e "${GREEN}✓ 已禁用技能: $name${NC}" } # 检查更新 cmd_check() { echo -e "${BLUE}检查技能更新${NC}" echo "════════════════════════════════════════" local skills=$(ls -1 "$REPOS_DIR" 2>/dev/null || echo "") if [ -z "$skills" ]; then echo "没有已安装的技能" exit 0 fi local has_updates=0 for skill in $skills; do local result=$("$GIT_OPS_SCRIPT" has-updates "$skill" 2>/dev/null | head -1) if [ "$result" == "yes" ]; then local behind=$("$GIT_OPS_SCRIPT" has-updates "$skill" 2>/dev/null | tail -1) echo -e "${YELLOW}✓ $skill 有更新 ($behind)${NC}" has_updates=1 else echo -e "${GREEN}✓ $skill 已是最新${NC}" fi done echo "" if [ $has_updates -eq 1 ]; then echo -e "${YELLOW}执行 'skill upgrade' 升级所有技能${NC}" else echo -e "${GREEN}所有技能已是最新版本${NC}" fi } # 主命令分发 case "${1:-help}" in list|ls) cmd_list ;; install|add) cmd_install "$2" ;; upgrade|update) cmd_upgrade "$2" ;; uninstall|remove) cmd_uninstall "$2" ;; rollback) cmd_rollback "$2" "$3" ;; info|show) cmd_info "$2" ;; enable) cmd_enable "$2" ;; disable) cmd_disable "$2" ;; check) cmd_check ;; help|--help|-h) show_banner echo "用法: skill [args]" echo "" echo "命令:" echo " list 列出已安装技能" echo " install 安装新技能" echo " upgrade [name] 升级技能(不指定则升级全部)" echo " uninstall 卸载技能" echo " rollback 回滚到指定版本" echo " info 查看技能详情" echo " enable 启用技能" echo " disable 禁用技能" echo " check 检查所有技能更新" echo "" echo "示例:" echo " skill install https://github.com/org/skill-name.git" echo " skill upgrade coolbuy-paas" echo " skill rollback coolbuy-paas v1.1.0" ;; *) echo -e "${RED}未知命令: $1${NC}" echo "使用 'skill help' 查看帮助" exit 1 ;; esac