#!/usr/bin/env bash # ================================================================ # Skill Manager — Agent Skills 管理工具 # 用法: bash scripts/skill-manager.sh [args] # ================================================================ set -euo pipefail SKILLS_DIR=".cursor/skills" AGENTS_DIR=".cursor/agents" GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' BLUE='\033[0;34m' NC='\033[0m' # ================================================================ # Commands # ================================================================ cmd_list() { echo -e "${BLUE}📦 Agent Skills${NC}" echo "─────────────────────────────────────────────" if [ ! -d "$SKILLS_DIR" ]; then echo -e "${RED} ✗ Skills 目录不存在${NC}" return 1 fi local count=0 for skill_dir in "$SKILLS_DIR"/*/; do [ -d "$skill_dir" ] || continue local skill_file="$skill_dir/SKILL.md" if [ -f "$skill_file" ]; then local name=$(grep -m1 '^name:' "$skill_file" | sed 's/name:\s*//') local desc=$(grep -A2 '^description:' "$skill_file" | tail -1 | sed 's/^\s*//') local lines=$(wc -l < "$skill_file") local has_refs=$( [ -d "${skill_dir}references" ] && echo "📚" || echo " " ) local has_scripts=$( [ -d "${skill_dir}scripts" ] && echo "⚡" || echo " " ) printf " ${GREEN}%-22s${NC} ${has_refs}${has_scripts} (%3d lines) %s\n" \ "$name" "$lines" "$desc" count=$((count + 1)) fi done echo "─────────────────────────────────────────────" echo -e " 共 ${GREEN}${count}${NC} 个技能" echo "" echo -e "${BLUE}🤖 Subagents${NC}" echo "─────────────────────────────────────────────" if [ -d "$AGENTS_DIR" ]; then for agent_file in "$AGENTS_DIR"/*.md; do [ -f "$agent_file" ] || continue local name=$(grep -m1 '^name:' "$agent_file" | sed 's/name:\s*//') local desc=$(grep -A1 '^description:' "$agent_file" | tail -1 | sed 's/^\s*//') local readonly_flag=$(grep -m1 '^readonly:' "$agent_file" | sed 's/readonly:\s*//') local mode=$( [ "$readonly_flag" = "true" ] && echo "🔒只读" || echo "✏️读写" ) printf " ${GREEN}%-22s${NC} ${mode} %s\n" "$name" "$desc" done else echo -e " ${YELLOW}⚠ Agents 目录不存在${NC}" fi } cmd_validate() { echo -e "${BLUE}🔍 验证 Agent Skills 规范合规性${NC}" echo "─────────────────────────────────────────────" local errors=0 local warnings=0 for skill_dir in "$SKILLS_DIR"/*/; do [ -d "$skill_dir" ] || continue local skill_name=$(basename "$skill_dir") local skill_file="$skill_dir/SKILL.md" # Check SKILL.md exists if [ ! -f "$skill_file" ]; then echo -e " ${RED}✗${NC} ${skill_name}: 缺少 SKILL.md" errors=$((errors + 1)) continue fi # Check name field if ! grep -q '^name:' "$skill_file"; then echo -e " ${RED}✗${NC} ${skill_name}: 缺少 name 字段" errors=$((errors + 1)) fi # Check description field if ! grep -q '^description:' "$skill_file"; then echo -e " ${RED}✗${NC} ${skill_name}: 缺少 description 字段" errors=$((errors + 1)) fi # Check name format (kebab-case) local name_val=$(grep -m1 '^name:' "$skill_file" | sed 's/name:[[:space:]]*//') if ! echo "$name_val" | grep -qE '^[a-z0-9]+(-[a-z0-9]+)*$'; then echo -e " ${RED}✗${NC} ${skill_name}: name 不符合 kebab-case 格式: '${name_val}'" errors=$((errors + 1)) fi # Check description length local desc_len=$(sed -n '/^description:/,/^---/{/^description:/d;/^---/d;p;}' "$skill_file" | wc -c) if [ "$desc_len" -gt 1024 ]; then echo -e " ${YELLOW}⚠${NC} ${skill_name}: description 超过 1024 字符 (${desc_len})" warnings=$((warnings + 1)) fi # Check file length local lines=$(wc -l < "$skill_file") if [ "$lines" -gt 300 ]; then echo -e " ${YELLOW}⚠${NC} ${skill_name}: SKILL.md 超过 300 行 (${lines}),建议拆分到 references/" warnings=$((warnings + 1)) fi # Check YAML frontmatter local fm_count=$(grep -c '^---$' "$skill_file") if [ "$fm_count" -lt 2 ]; then echo -e " ${RED}✗${NC} ${skill_name}: YAML frontmatter 格式不完整" errors=$((errors + 1)) fi # All checks passed if [ "$errors" -eq 0 ] && [ "$warnings" -eq 0 ]; then echo -e " ${GREEN}✓${NC} ${skill_name}" fi done echo "─────────────────────────────────────────────" if [ "$errors" -gt 0 ]; then echo -e " ${RED}✗ ${errors} 个错误${NC}, ${YELLOW}${warnings} 个警告${NC}" return 1 elif [ "$warnings" -gt 0 ]; then echo -e " ${GREEN}✓ 全部通过${NC}, ${YELLOW}${warnings} 个警告${NC}" else echo -e " ${GREEN}✓ 全部验证通过${NC}" fi } cmd_stats() { echo -e "${BLUE}📊 Skills 统计${NC}" echo "─────────────────────────────────────────────" local total_skills=0 local total_lines=0 local total_refs=0 local total_scripts=0 for skill_dir in "$SKILLS_DIR"/*/; do [ -d "$skill_dir" ] || continue local skill_file="$skill_dir/SKILL.md" [ -f "$skill_file" ] || continue total_skills=$((total_skills + 1)) total_lines=$((total_lines + $(wc -l < "$skill_file"))) if [ -d "${skill_dir}references" ]; then total_refs=$((total_refs + $(find "${skill_dir}references" -name "*.md" | wc -l))) fi if [ -d "${skill_dir}scripts" ]; then total_scripts=$((total_scripts + $(find "${skill_dir}scripts" -type f | wc -l))) fi done local agents=0 if [ -d "$AGENTS_DIR" ]; then agents=$(find "$AGENTS_DIR" -name "*.md" | wc -l) fi echo " Skills: ${total_skills}" echo " Subagents: ${agents}" echo " 总行数: ${total_lines} lines" echo " 平均行数: $((total_lines / (total_skills > 0 ? total_skills : 1))) lines/skill" echo " 参考文档: ${total_refs} files" echo " 脚本: ${total_scripts} files" echo "" echo " 预估 Token (Tier 1 发现): ~$((total_skills * 40)) tokens" echo " 预估 Token (全量加载): ~$((total_lines * 2)) tokens" } cmd_create() { local name="${1:-}" if [ -z "$name" ]; then echo -e "${RED}用法: skill-manager.sh create ${NC}" echo " 名称必须是 kebab-case 格式" return 1 fi # Validate name format if ! echo "$name" | grep -qE '^[a-z0-9]+(-[a-z0-9]+)*$'; then echo -e "${RED}✗ 名称必须是 kebab-case: a-z, 0-9, 连字符${NC}" return 1 fi local dir="$SKILLS_DIR/$name" if [ -d "$dir" ]; then echo -e "${RED}✗ 技能已存在: $dir${NC}" return 1 fi mkdir -p "$dir" cat > "$dir/SKILL.md" << 'TEMPLATE' --- name: SKILL_NAME description: > Describe what this skill does and when to use it. Include trigger keywords in both English and Chinese. --- # Skill Title ## 触发条件 Describe when this skill should be activated. ## 执行流程 ### 1. Step One Specific, actionable instructions. ### 2. Step Two More instructions. ## 验证 1. [ ] Check item 1 2. [ ] Check item 2 TEMPLATE sed "s/SKILL_NAME/$name/g" "$dir/SKILL.md" > "$dir/SKILL.md.tmp" && mv "$dir/SKILL.md.tmp" "$dir/SKILL.md" echo -e "${GREEN}✓ 技能已创建: $dir${NC}" echo " 编辑 $dir/SKILL.md 完善技能内容" } # ================================================================ # Main # ================================================================ cmd="${1:-help}" shift || true case "$cmd" in list|ls) cmd_list ;; validate|v) cmd_validate ;; stats|s) cmd_stats ;; create|new) cmd_create "$@" ;; help|--help|-h) echo "Skill Manager — Agent Skills 管理工具" echo "" echo "用法: bash scripts/skill-manager.sh " echo "" echo "命令:" echo " list 列出所有 Skills 和 Subagents" echo " validate 验证 SKILL.md 规范合规性" echo " stats 显示 Skills 统计信息" echo " create 创建新技能脚手架" echo " help 显示此帮助信息" ;; *) echo -e "${RED}未知命令: $cmd${NC}" echo "运行 'bash scripts/skill-manager.sh help' 查看帮助" exit 1 ;; esac