394 lines
12 KiB
Bash
Executable File
394 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
# skill.sh - Skills 管理器主入口
|
|
# 用法:
|
|
# ./skill.sh list - 列出已安装技能
|
|
# ./skill.sh install <repo> - 安装新技能
|
|
# ./skill.sh upgrade [name] - 升级技能
|
|
# ./skill.sh uninstall <name> - 卸载技能
|
|
# ./skill.sh rollback <name> <version> - 回滚版本
|
|
# ./skill.sh info <name> - 查看技能详情
|
|
# ./skill.sh enable <name> - 启用技能
|
|
# ./skill.sh disable <name> - 禁用技能
|
|
# ./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 <repo>${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 <name>${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 <name> <version>${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 <name>${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 <name>${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 <name>${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 <command> [args]"
|
|
echo ""
|
|
echo "命令:"
|
|
echo " list 列出已安装技能"
|
|
echo " install <repo> 安装新技能"
|
|
echo " upgrade [name] 升级技能(不指定则升级全部)"
|
|
echo " uninstall <name> 卸载技能"
|
|
echo " rollback <name> <version> 回滚到指定版本"
|
|
echo " info <name> 查看技能详情"
|
|
echo " enable <name> 启用技能"
|
|
echo " disable <name> 禁用技能"
|
|
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
|