refactor: 通用技能按类别拆分为独立目录
skills/ → skills-dev(9), skills-req(10), skills-ops(4), skills-integration(8), skills-biz(4), skills-workflow(7) generate-marketplace.py 改为自动扫描所有 skills-* 目录。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
306
skills-workflow/skill-manager-plugin/scripts/git-ops.sh
Executable file
306
skills-workflow/skill-manager-plugin/scripts/git-ops.sh
Executable file
@@ -0,0 +1,306 @@
|
||||
#!/bin/bash
|
||||
# git-ops.sh - Git 操作封装
|
||||
# 用法:
|
||||
# ./git-ops.sh clone <repo> <name> - 克隆仓库
|
||||
# ./git-ops.sh pull <name> - 拉取更新
|
||||
# ./git-ops.sh checkout <name> <ref> - 切换版本
|
||||
# ./git-ops.sh fetch <name> - 获取远程更新
|
||||
# ./git-ops.sh status <name> - 查看状态
|
||||
# ./git-ops.sh has-updates <name> - 检查是否有更新
|
||||
|
||||
set -e
|
||||
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
REPOS_DIR="$SKILLS_DIR/repos"
|
||||
REGISTRY_SCRIPT="$SKILLS_DIR/skill-manager/scripts/registry.sh"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
# 从 URL 提取技能名称
|
||||
extract_name() {
|
||||
local repo="$1"
|
||||
# 处理各种格式
|
||||
# https://github.com/org/skill-name.git -> skill-name
|
||||
# git@github.com:org/skill-name.git -> skill-name
|
||||
echo "$repo" | sed -E 's|.*/([^/]+)(\.git)?$|\1|' | sed 's/\.git$//'
|
||||
}
|
||||
|
||||
# 克隆仓库
|
||||
cmd_clone() {
|
||||
local repo="$1"
|
||||
local name="${2:-$(extract_name "$repo")}"
|
||||
|
||||
if [ -z "$repo" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh clone <repo> [name]${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local target_dir="$REPOS_DIR/$name"
|
||||
|
||||
# 检查是否已存在
|
||||
if [ -d "$target_dir" ]; then
|
||||
echo -e "${YELLOW}技能已存在: $name${NC}"
|
||||
echo "使用 'git-ops.sh pull $name' 更新"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}克隆技能: $name${NC}"
|
||||
echo "仓库: $repo"
|
||||
echo "目标: $target_dir"
|
||||
echo "----------------------------------------"
|
||||
|
||||
# 确保 repos 目录存在
|
||||
mkdir -p "$REPOS_DIR"
|
||||
|
||||
# 克隆仓库
|
||||
if git clone "$repo" "$target_dir"; then
|
||||
echo -e "${GREEN}✓ 克隆成功${NC}"
|
||||
|
||||
# 检查 skill.yaml
|
||||
if [ ! -f "$target_dir/skill.yaml" ]; then
|
||||
echo -e "${YELLOW}⚠ 警告: 未找到 skill.yaml${NC}"
|
||||
fi
|
||||
|
||||
# 获取版本
|
||||
local version="unknown"
|
||||
if [ -f "$target_dir/skill.yaml" ] && command -v yq &> /dev/null; then
|
||||
version=$(yq e '.version // "1.0.0"' "$target_dir/skill.yaml")
|
||||
fi
|
||||
|
||||
# 添加到 registry
|
||||
"$REGISTRY_SCRIPT" add "$name" "$repo" "$version"
|
||||
|
||||
echo -e "${GREEN}✓ 技能安装完成: $name ($version)${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ 克隆失败${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 拉取更新
|
||||
cmd_pull() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh pull <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}更新技能: $name${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
cd "$repo_dir"
|
||||
|
||||
# 获取当前版本
|
||||
local old_version="unknown"
|
||||
if [ -f "skill.yaml" ] && command -v yq &> /dev/null; then
|
||||
old_version=$(yq e '.version // "unknown"' skill.yaml)
|
||||
fi
|
||||
|
||||
# 拉取更新
|
||||
if git pull origin main 2>/dev/null || git pull origin master 2>/dev/null; then
|
||||
# 获取新版本
|
||||
local new_version="unknown"
|
||||
if [ -f "skill.yaml" ] && command -v yq &> /dev/null; then
|
||||
new_version=$(yq e '.version // "unknown"' skill.yaml)
|
||||
fi
|
||||
|
||||
if [ "$old_version" != "$new_version" ]; then
|
||||
echo -e "${GREEN}✓ 版本更新: $old_version → $new_version${NC}"
|
||||
"$REGISTRY_SCRIPT" update "$name" version "$new_version"
|
||||
else
|
||||
echo -e "${GREEN}✓ 已是最新版本: $new_version${NC}"
|
||||
fi
|
||||
|
||||
# 更新 last_updated
|
||||
"$REGISTRY_SCRIPT" update "$name" last_updated "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
else
|
||||
echo -e "${RED}✗ 更新失败${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 切换版本
|
||||
cmd_checkout() {
|
||||
local name="$1"
|
||||
local ref="$2"
|
||||
|
||||
if [ -z "$name" ] || [ -z "$ref" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh checkout <name> <ref>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}切换版本: $name → $ref${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
cd "$repo_dir"
|
||||
|
||||
# 获取当前版本
|
||||
local old_ref=$(git describe --tags --always 2>/dev/null || git rev-parse --short HEAD)
|
||||
|
||||
# 切换版本
|
||||
if git checkout "$ref" 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ 版本切换: $old_ref → $ref${NC}"
|
||||
|
||||
# 更新 registry
|
||||
"$REGISTRY_SCRIPT" update "$name" version "$ref"
|
||||
"$REGISTRY_SCRIPT" update "$name" last_updated "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
else
|
||||
echo -e "${RED}✗ 切换失败: $ref 不存在${NC}"
|
||||
echo "可用的 tag:"
|
||||
git tag -l | head -10
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 获取远程更新
|
||||
cmd_fetch() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh fetch <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$repo_dir"
|
||||
git fetch origin --tags --quiet
|
||||
echo -e "${GREEN}✓ 已获取远程更新: $name${NC}"
|
||||
}
|
||||
|
||||
# 查看状态
|
||||
cmd_status() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh status <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}技能状态: $name${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
cd "$repo_dir"
|
||||
|
||||
local branch=$(git branch --show-current 2>/dev/null || echo "detached")
|
||||
local commit=$(git rev-parse --short HEAD)
|
||||
local remote_url=$(git config --get remote.origin.url)
|
||||
|
||||
echo "分支: $branch"
|
||||
echo "Commit: $commit"
|
||||
echo "远程: $remote_url"
|
||||
|
||||
if [ -f "skill.yaml" ] && command -v yq &> /dev/null; then
|
||||
local version=$(yq e '.version // "unknown"' skill.yaml)
|
||||
echo "版本: $version"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "最近提交:"
|
||||
git log --oneline -3
|
||||
}
|
||||
|
||||
# 检查是否有更新
|
||||
cmd_has_updates() {
|
||||
local name="$1"
|
||||
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: git-ops.sh has-updates <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local repo_dir="$REPOS_DIR/$name"
|
||||
|
||||
if [ ! -d "$repo_dir" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$repo_dir"
|
||||
|
||||
# 获取远程更新
|
||||
git fetch origin --quiet 2>/dev/null || true
|
||||
|
||||
# 比较本地和远程
|
||||
local local_head=$(git rev-parse HEAD)
|
||||
local remote_head=$(git rev-parse origin/main 2>/dev/null || git rev-parse origin/master 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$remote_head" ]; then
|
||||
echo "unknown"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$local_head" != "$remote_head" ]; then
|
||||
echo "yes"
|
||||
# 显示更新数量
|
||||
local behind=$(git rev-list HEAD..origin/main --count 2>/dev/null || git rev-list HEAD..origin/master --count 2>/dev/null || echo "0")
|
||||
echo "behind: $behind commits"
|
||||
else
|
||||
echo "no"
|
||||
fi
|
||||
}
|
||||
|
||||
# 主命令分发
|
||||
case "${1:-help}" in
|
||||
clone)
|
||||
cmd_clone "$2" "$3"
|
||||
;;
|
||||
pull)
|
||||
cmd_pull "$2"
|
||||
;;
|
||||
checkout)
|
||||
cmd_checkout "$2" "$3"
|
||||
;;
|
||||
fetch)
|
||||
cmd_fetch "$2"
|
||||
;;
|
||||
status)
|
||||
cmd_status "$2"
|
||||
;;
|
||||
has-updates)
|
||||
cmd_has_updates "$2"
|
||||
;;
|
||||
*)
|
||||
echo "用法: git-ops.sh <command> [args]"
|
||||
echo ""
|
||||
echo "命令:"
|
||||
echo " clone <repo> [name] 克隆仓库"
|
||||
echo " pull <name> 拉取更新"
|
||||
echo " checkout <name> <ref> 切换版本"
|
||||
echo " fetch <name> 获取远程更新"
|
||||
echo " status <name> 查看状态"
|
||||
echo " has-updates <name> 检查是否有更新"
|
||||
;;
|
||||
esac
|
||||
58
skills-workflow/skill-manager-plugin/scripts/init-registry.sh
Executable file
58
skills-workflow/skill-manager-plugin/scripts/init-registry.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
# init-registry.sh - 初始化技能注册表
|
||||
# 用法: ./init-registry.sh
|
||||
|
||||
set -e
|
||||
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
REGISTRY_FILE="$SKILLS_DIR/registry.yaml"
|
||||
REPOS_DIR="$SKILLS_DIR/repos"
|
||||
|
||||
# 颜色定义
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo "初始化 Skills Registry..."
|
||||
echo "----------------------------------------"
|
||||
|
||||
# 创建 repos 目录
|
||||
if [ ! -d "$REPOS_DIR" ]; then
|
||||
mkdir -p "$REPOS_DIR"
|
||||
echo -e "${GREEN}✓ 创建 repos 目录${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ repos 目录已存在${NC}"
|
||||
fi
|
||||
|
||||
# 创建 registry.yaml
|
||||
if [ ! -f "$REGISTRY_FILE" ]; then
|
||||
cat > "$REGISTRY_FILE" << 'EOF'
|
||||
# Skills Registry - 技能注册表
|
||||
# 由 skill-manager 自动管理,请勿手动编辑
|
||||
|
||||
version: 1
|
||||
updated_at: $(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
# 全局配置
|
||||
config:
|
||||
auto_update_check: true # 启动时检查更新
|
||||
update_check_interval: 86400 # 检查间隔(秒),默认24小时
|
||||
default_branch: main # 默认分支
|
||||
|
||||
# 已安装技能
|
||||
skills: {}
|
||||
EOF
|
||||
# 替换日期
|
||||
sed -i '' "s/\$(date -u +\"%Y-%m-%dT%H:%M:%SZ\")/$(date -u +"%Y-%m-%dT%H:%M:%SZ")/" "$REGISTRY_FILE"
|
||||
echo -e "${GREEN}✓ 创建 registry.yaml${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ registry.yaml 已存在${NC}"
|
||||
fi
|
||||
|
||||
echo "----------------------------------------"
|
||||
echo -e "${GREEN}✓ 初始化完成${NC}"
|
||||
echo ""
|
||||
echo "目录结构:"
|
||||
echo " $SKILLS_DIR/"
|
||||
echo " ├── registry.yaml"
|
||||
echo " └── repos/"
|
||||
204
skills-workflow/skill-manager-plugin/scripts/registry.sh
Executable file
204
skills-workflow/skill-manager-plugin/scripts/registry.sh
Executable file
@@ -0,0 +1,204 @@
|
||||
#!/bin/bash
|
||||
# registry.sh - Registry 管理工具
|
||||
# 用法:
|
||||
# ./registry.sh list - 列出所有技能
|
||||
# ./registry.sh get <name> - 获取技能信息
|
||||
# ./registry.sh add <name> <repo> - 添加技能记录
|
||||
# ./registry.sh remove <name> - 移除技能记录
|
||||
# ./registry.sh update <name> <field> <value> - 更新字段
|
||||
|
||||
set -e
|
||||
|
||||
SKILLS_DIR="$HOME/.claude/skills"
|
||||
REGISTRY_FILE="$SKILLS_DIR/registry.yaml"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
# 检查 yq 是否安装
|
||||
check_yq() {
|
||||
if ! command -v yq &> /dev/null; then
|
||||
echo -e "${RED}错误: 需要安装 yq${NC}"
|
||||
echo "安装方法: brew install yq"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查 registry 文件
|
||||
check_registry() {
|
||||
if [ ! -f "$REGISTRY_FILE" ]; then
|
||||
echo -e "${YELLOW}Registry 不存在,正在初始化...${NC}"
|
||||
"$SKILLS_DIR/skill-manager/scripts/init-registry.sh"
|
||||
fi
|
||||
}
|
||||
|
||||
# 列出所有技能
|
||||
cmd_list() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
echo -e "${BLUE}已安装技能:${NC}"
|
||||
echo "----------------------------------------"
|
||||
|
||||
SKILLS=$(yq e '.skills | keys | .[]' "$REGISTRY_FILE" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$SKILLS" ]; then
|
||||
echo "(无已安装技能)"
|
||||
return
|
||||
fi
|
||||
|
||||
printf "%-20s %-10s %-10s %s\n" "名称" "版本" "状态" "最后更新"
|
||||
echo "----------------------------------------"
|
||||
|
||||
for skill in $SKILLS; do
|
||||
VERSION=$(yq e ".skills.$skill.version // \"unknown\"" "$REGISTRY_FILE")
|
||||
STATUS=$(yq e ".skills.$skill.status // \"unknown\"" "$REGISTRY_FILE")
|
||||
UPDATED=$(yq e ".skills.$skill.last_updated // \"unknown\"" "$REGISTRY_FILE" | cut -d'T' -f1)
|
||||
|
||||
# 状态颜色
|
||||
case $STATUS in
|
||||
active) STATUS_COLOR="${GREEN}$STATUS${NC}" ;;
|
||||
disabled) STATUS_COLOR="${YELLOW}$STATUS${NC}" ;;
|
||||
error) STATUS_COLOR="${RED}$STATUS${NC}" ;;
|
||||
*) STATUS_COLOR="$STATUS" ;;
|
||||
esac
|
||||
|
||||
printf "%-20s %-10s " "$skill" "$VERSION"
|
||||
echo -e "$STATUS_COLOR\t$UPDATED"
|
||||
done
|
||||
}
|
||||
|
||||
# 获取技能信息
|
||||
cmd_get() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
local name="$1"
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: registry.sh get <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local exists=$(yq e ".skills.$name // \"\"" "$REGISTRY_FILE")
|
||||
if [ -z "$exists" ] || [ "$exists" == "null" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}技能: $name${NC}"
|
||||
echo "----------------------------------------"
|
||||
yq e ".skills.$name" "$REGISTRY_FILE"
|
||||
}
|
||||
|
||||
# 添加技能记录
|
||||
cmd_add() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
local name="$1"
|
||||
local repo="$2"
|
||||
local version="${3:-1.0.0}"
|
||||
|
||||
if [ -z "$name" ] || [ -z "$repo" ]; then
|
||||
echo -e "${RED}用法: registry.sh add <name> <repo> [version]${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
local local_path="$SKILLS_DIR/repos/$name"
|
||||
|
||||
# 添加技能记录
|
||||
yq e -i ".skills.$name.repo = \"$repo\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.local_path = \"$local_path\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.version = \"$version\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.installed_at = \"$now\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.last_updated = \"$now\"" "$REGISTRY_FILE"
|
||||
yq e -i ".skills.$name.status = \"active\"" "$REGISTRY_FILE"
|
||||
|
||||
# 更新 registry 时间
|
||||
yq e -i ".updated_at = \"$now\"" "$REGISTRY_FILE"
|
||||
|
||||
echo -e "${GREEN}✓ 已添加技能: $name${NC}"
|
||||
}
|
||||
|
||||
# 移除技能记录
|
||||
cmd_remove() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
local name="$1"
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${RED}用法: registry.sh remove <name>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local exists=$(yq e ".skills.$name // \"\"" "$REGISTRY_FILE")
|
||||
if [ -z "$exists" ] || [ "$exists" == "null" ]; then
|
||||
echo -e "${YELLOW}技能不存在: $name${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
yq e -i "del(.skills.$name)" "$REGISTRY_FILE"
|
||||
yq e -i ".updated_at = \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"" "$REGISTRY_FILE"
|
||||
|
||||
echo -e "${GREEN}✓ 已移除技能: $name${NC}"
|
||||
}
|
||||
|
||||
# 更新技能字段
|
||||
cmd_update() {
|
||||
check_yq
|
||||
check_registry
|
||||
|
||||
local name="$1"
|
||||
local field="$2"
|
||||
local value="$3"
|
||||
|
||||
if [ -z "$name" ] || [ -z "$field" ] || [ -z "$value" ]; then
|
||||
echo -e "${RED}用法: registry.sh update <name> <field> <value>${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local exists=$(yq e ".skills.$name // \"\"" "$REGISTRY_FILE")
|
||||
if [ -z "$exists" ] || [ "$exists" == "null" ]; then
|
||||
echo -e "${RED}技能不存在: $name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
yq e -i ".skills.$name.$field = \"$value\"" "$REGISTRY_FILE"
|
||||
yq e -i ".updated_at = \"$(date -u +"%Y-%m-%dT%H:%M:%SZ")\"" "$REGISTRY_FILE"
|
||||
|
||||
echo -e "${GREEN}✓ 已更新 $name.$field = $value${NC}"
|
||||
}
|
||||
|
||||
# 主命令分发
|
||||
case "${1:-list}" in
|
||||
list)
|
||||
cmd_list
|
||||
;;
|
||||
get)
|
||||
cmd_get "$2"
|
||||
;;
|
||||
add)
|
||||
cmd_add "$2" "$3" "$4"
|
||||
;;
|
||||
remove)
|
||||
cmd_remove "$2"
|
||||
;;
|
||||
update)
|
||||
cmd_update "$2" "$3" "$4"
|
||||
;;
|
||||
*)
|
||||
echo "用法: registry.sh <command> [args]"
|
||||
echo ""
|
||||
echo "命令:"
|
||||
echo " list 列出所有技能"
|
||||
echo " get <name> 获取技能信息"
|
||||
echo " add <name> <repo> 添加技能记录"
|
||||
echo " remove <name> 移除技能记录"
|
||||
echo " update <name> <f> <v> 更新字段"
|
||||
;;
|
||||
esac
|
||||
393
skills-workflow/skill-manager-plugin/scripts/skill.sh
Executable file
393
skills-workflow/skill-manager-plugin/scripts/skill.sh
Executable file
@@ -0,0 +1,393 @@
|
||||
#!/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
|
||||
88
skills-workflow/skill-manager-plugin/scripts/validate.sh
Executable file
88
skills-workflow/skill-manager-plugin/scripts/validate.sh
Executable file
@@ -0,0 +1,88 @@
|
||||
#!/bin/bash
|
||||
# validate.sh - 验证 skill.yaml 格式
|
||||
# 用法: ./validate.sh <skill-directory>
|
||||
|
||||
set -e
|
||||
|
||||
SKILL_DIR="${1:-.}"
|
||||
SKILL_YAML="$SKILL_DIR/skill.yaml"
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo "验证技能目录: $SKILL_DIR"
|
||||
echo "----------------------------------------"
|
||||
|
||||
# 检查 skill.yaml 是否存在
|
||||
if [ ! -f "$SKILL_YAML" ]; then
|
||||
echo -e "${RED}✗ skill.yaml 不存在${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ skill.yaml 存在${NC}"
|
||||
|
||||
# 检查 YAML 格式(需要 yq 或 python)
|
||||
if command -v yq &> /dev/null; then
|
||||
if ! yq e '.' "$SKILL_YAML" > /dev/null 2>&1; then
|
||||
echo -e "${RED}✗ YAML 格式错误${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ YAML 格式正确${NC}"
|
||||
|
||||
# 检查必填字段
|
||||
NAME=$(yq e '.name' "$SKILL_YAML")
|
||||
VERSION=$(yq e '.version' "$SKILL_YAML")
|
||||
DESCRIPTION=$(yq e '.description' "$SKILL_YAML")
|
||||
|
||||
if [ "$NAME" == "null" ] || [ -z "$NAME" ]; then
|
||||
echo -e "${RED}✗ 缺少必填字段: name${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ name: $NAME${NC}"
|
||||
|
||||
if [ "$VERSION" == "null" ] || [ -z "$VERSION" ]; then
|
||||
echo -e "${RED}✗ 缺少必填字段: version${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ version: $VERSION${NC}"
|
||||
|
||||
if [ "$DESCRIPTION" == "null" ] || [ -z "$DESCRIPTION" ]; then
|
||||
echo -e "${RED}✗ 缺少必填字段: description${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ description: 已设置${NC}"
|
||||
|
||||
# 验证 name 格式
|
||||
if ! echo "$NAME" | grep -qE '^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$'; then
|
||||
echo -e "${RED}✗ name 格式错误: 只能包含小写字母、数字、连字符${NC}"
|
||||
exit 1
|
||||
fi
|
||||
if [ ${#NAME} -gt 64 ]; then
|
||||
echo -e "${RED}✗ name 超过 64 字符${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ name 格式正确${NC}"
|
||||
|
||||
# 检查 prompt_file
|
||||
PROMPT_FILE=$(yq e '.prompt_file // "SKILL.md"' "$SKILL_YAML")
|
||||
if [ ! -f "$SKILL_DIR/$PROMPT_FILE" ]; then
|
||||
echo -e "${YELLOW}⚠ prompt_file 不存在: $PROMPT_FILE${NC}"
|
||||
else
|
||||
echo -e "${GREEN}✓ prompt_file: $PROMPT_FILE${NC}"
|
||||
fi
|
||||
|
||||
elif command -v python3 &> /dev/null; then
|
||||
python3 -c "import yaml; yaml.safe_load(open('$SKILL_YAML'))" 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}✗ YAML 格式错误${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓ YAML 格式正确 (使用 Python 验证)${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ 无法验证 YAML 格式 (需要 yq 或 python3)${NC}"
|
||||
fi
|
||||
|
||||
echo "----------------------------------------"
|
||||
echo -e "${GREEN}✓ 验证通过${NC}"
|
||||
Reference in New Issue
Block a user