docs: add analysis and implementation reports for VoltAgent integration
- VoltAgent repository analysis and validation reports - Similar skills analysis and implementation tracking - HTML to markdown conversion report - Final skills count verification
This commit is contained in:
215
scripts/analyze_remaining_similar_skills.py
Normal file
215
scripts/analyze_remaining_similar_skills.py
Normal file
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Analyze remaining similar skills to determine if they are truly new
|
||||
and worth adding to the repository.
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Tuple
|
||||
from urllib.parse import urlparse
|
||||
from urllib.request import urlopen, Request
|
||||
from urllib.error import URLError, HTTPError
|
||||
|
||||
def normalize_skill_name(name: str) -> str:
|
||||
"""Normalize skill name to kebab-case."""
|
||||
# Remove special chars, convert to lowercase, replace spaces/hyphens
|
||||
name = re.sub(r'[^\w\s-]', '', name.lower())
|
||||
name = re.sub(r'[\s_]+', '-', name)
|
||||
name = re.sub(r'-+', '-', name)
|
||||
return name.strip('-')
|
||||
|
||||
def check_url_accessible(url: str) -> bool:
|
||||
"""Check if URL is accessible."""
|
||||
try:
|
||||
req = Request(url, method='HEAD')
|
||||
with urlopen(req, timeout=10) as response:
|
||||
return response.status == 200
|
||||
except (URLError, HTTPError, Exception):
|
||||
return False
|
||||
|
||||
def get_repo_base_url(github_url: str) -> str:
|
||||
"""Extract base GitHub repository URL."""
|
||||
# Handle various GitHub URL formats
|
||||
patterns = [
|
||||
r'https://github\.com/([^/]+/[^/]+)',
|
||||
r'github\.com/([^/]+/[^/]+)',
|
||||
]
|
||||
|
||||
for pattern in patterns:
|
||||
match = re.search(pattern, github_url)
|
||||
if match:
|
||||
return f"https://github.com/{match.group(1)}"
|
||||
return None
|
||||
|
||||
def check_skill_file_exists(repo_url: str, skill_path: str = None) -> Tuple[bool, str]:
|
||||
"""Check if SKILL.md exists in the repository."""
|
||||
base_url = get_repo_base_url(repo_url)
|
||||
if not base_url:
|
||||
return False, None
|
||||
|
||||
# Common paths to check
|
||||
paths_to_check = [
|
||||
f"{base_url}/raw/main/{skill_path}/SKILL.md" if skill_path else f"{base_url}/raw/main/SKILL.md",
|
||||
f"{base_url}/raw/main/skills/{skill_path}/SKILL.md" if skill_path else None,
|
||||
f"{base_url}/raw/master/{skill_path}/SKILL.md" if skill_path else f"{base_url}/raw/master/SKILL.md",
|
||||
f"{base_url}/blob/main/{skill_path}/SKILL.md" if skill_path else f"{base_url}/blob/main/SKILL.md",
|
||||
]
|
||||
|
||||
for path in paths_to_check:
|
||||
if path and check_url_accessible(path):
|
||||
return True, path
|
||||
|
||||
return False, None
|
||||
|
||||
def analyze_similarity(skill_name: str, similar_skills: List[str], existing_skills: Dict) -> Dict:
|
||||
"""Analyze how similar a skill is to existing ones."""
|
||||
analysis = {
|
||||
'is_duplicate': False,
|
||||
'is_complementary': False,
|
||||
'similarity_score': 0.0,
|
||||
'closest_match': None,
|
||||
'reasoning': []
|
||||
}
|
||||
|
||||
skill_lower = skill_name.lower()
|
||||
|
||||
# Check for exact or near-exact matches
|
||||
for existing_name, existing_data in existing_skills.items():
|
||||
existing_lower = existing_name.lower()
|
||||
|
||||
# Exact match
|
||||
if skill_lower == existing_lower:
|
||||
analysis['is_duplicate'] = True
|
||||
analysis['closest_match'] = existing_name
|
||||
analysis['reasoning'].append(f"Exact match with existing skill: {existing_name}")
|
||||
return analysis
|
||||
|
||||
# Check if one contains the other
|
||||
if skill_lower in existing_lower or existing_lower in skill_lower:
|
||||
if abs(len(skill_lower) - len(existing_lower)) <= 3:
|
||||
analysis['is_duplicate'] = True
|
||||
analysis['closest_match'] = existing_name
|
||||
analysis['similarity_score'] = 0.9
|
||||
analysis['reasoning'].append(f"Near-exact match: '{skill_name}' vs '{existing_name}'")
|
||||
return analysis
|
||||
|
||||
# Check similarity with similar skills list
|
||||
for similar in similar_skills:
|
||||
if similar.lower() in existing_skills:
|
||||
existing_data = existing_skills[similar.lower()]
|
||||
# If the similar skill exists, this might be a duplicate
|
||||
analysis['similarity_score'] = 0.7
|
||||
analysis['closest_match'] = similar
|
||||
analysis['reasoning'].append(f"Similar to existing skill: {similar}")
|
||||
|
||||
# Determine if complementary
|
||||
if analysis['similarity_score'] < 0.5:
|
||||
analysis['is_complementary'] = True
|
||||
analysis['reasoning'].append("Low similarity - likely complementary skill")
|
||||
|
||||
return analysis
|
||||
|
||||
def main():
|
||||
base_dir = Path(__file__).parent.parent
|
||||
|
||||
# Load remaining similar skills
|
||||
remaining_file = base_dir / "remaining_similar_skills.json"
|
||||
if not remaining_file.exists():
|
||||
print("❌ remaining_similar_skills.json not found. Run the analysis first.")
|
||||
return
|
||||
|
||||
with open(remaining_file, 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
# Load existing skills
|
||||
catalog_file = base_dir / "data" / "catalog.json"
|
||||
with open(catalog_file, 'r') as f:
|
||||
catalog = json.load(f)
|
||||
existing_skills = {s['name'].lower(): s for s in catalog.get('skills', [])}
|
||||
|
||||
print(f"🔍 Analyzing {len(data['skills'])} remaining similar skills...\n")
|
||||
|
||||
results = {
|
||||
'truly_new': [],
|
||||
'duplicates': [],
|
||||
'complementary': [],
|
||||
'needs_review': [],
|
||||
'invalid_sources': []
|
||||
}
|
||||
|
||||
for skill in data['skills']:
|
||||
skill_name = skill['name']
|
||||
print(f"Analyzing: {skill_name}")
|
||||
|
||||
# Skip if already exists
|
||||
if skill['exists_in_catalog'] or skill['folder_exists']:
|
||||
results['duplicates'].append({
|
||||
'name': skill_name,
|
||||
'reason': 'Already exists in repository',
|
||||
'url': skill['url']
|
||||
})
|
||||
continue
|
||||
|
||||
# Check source accessibility
|
||||
exists, raw_url = check_skill_file_exists(skill['url'], skill.get('skill_part'))
|
||||
if not exists:
|
||||
results['invalid_sources'].append({
|
||||
'name': skill_name,
|
||||
'url': skill['url'],
|
||||
'reason': 'SKILL.md not found or URL inaccessible'
|
||||
})
|
||||
continue
|
||||
|
||||
# Analyze similarity
|
||||
similarity_analysis = analyze_similarity(
|
||||
skill_name,
|
||||
skill['similar_to'],
|
||||
existing_skills
|
||||
)
|
||||
|
||||
skill_result = {
|
||||
'name': skill_name,
|
||||
'url': skill['url'],
|
||||
'raw_url': raw_url,
|
||||
'description': skill['description'],
|
||||
'org': skill['org'],
|
||||
'category': skill['category'],
|
||||
'similar_to': skill['similar_to'],
|
||||
'similarity_analysis': similarity_analysis
|
||||
}
|
||||
|
||||
if similarity_analysis['is_duplicate']:
|
||||
results['duplicates'].append(skill_result)
|
||||
elif similarity_analysis['is_complementary']:
|
||||
results['complementary'].append(skill_result)
|
||||
else:
|
||||
results['needs_review'].append(skill_result)
|
||||
|
||||
# Generate report
|
||||
report = {
|
||||
'summary': {
|
||||
'total_analyzed': len(data['skills']),
|
||||
'truly_new': len(results['complementary']),
|
||||
'duplicates': len(results['duplicates']),
|
||||
'needs_review': len(results['needs_review']),
|
||||
'invalid_sources': len(results['invalid_sources'])
|
||||
},
|
||||
'results': results
|
||||
}
|
||||
|
||||
output_file = base_dir / "similar_skills_analysis.json"
|
||||
with open(output_file, 'w') as f:
|
||||
json.dump(report, f, indent=2)
|
||||
|
||||
print(f"\n✅ Analysis complete!")
|
||||
print(f"📊 Summary:")
|
||||
print(f" - Truly new (complementary): {len(results['complementary'])}")
|
||||
print(f" - Duplicates: {len(results['duplicates'])}")
|
||||
print(f" - Needs review: {len(results['needs_review'])}")
|
||||
print(f" - Invalid sources: {len(results['invalid_sources'])}")
|
||||
print(f"\n📄 Full report saved to: {output_file}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
149
scripts/count_uncommitted_skills.py
Normal file
149
scripts/count_uncommitted_skills.py
Normal file
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Count uncommitted skills by checking git status.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
def run_git_command(cmd):
|
||||
"""Run git command and return output."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd.split(),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=Path(__file__).parent.parent
|
||||
)
|
||||
return result.stdout.strip().split('\n') if result.stdout.strip() else []
|
||||
except Exception as e:
|
||||
print(f"Error running git command: {e}")
|
||||
return []
|
||||
|
||||
def main():
|
||||
base_dir = Path(__file__).parent.parent
|
||||
|
||||
# Get all uncommitted files
|
||||
untracked = run_git_command("git ls-files --others --exclude-standard")
|
||||
modified = run_git_command("git diff --name-only HEAD")
|
||||
staged = run_git_command("git diff --cached --name-only")
|
||||
|
||||
# Also check status
|
||||
status_output = run_git_command("git status --porcelain")
|
||||
|
||||
print("Git status output:")
|
||||
for line in status_output[:20]: # First 20 lines
|
||||
print(f" {line}")
|
||||
print()
|
||||
|
||||
# Filter for skill files
|
||||
skill_files = []
|
||||
for file_list in [untracked, modified, staged]:
|
||||
for file in file_list:
|
||||
if '/skills/' in file and file.endswith('SKILL.md'):
|
||||
skill_name = file.split('/skills/')[1].split('/SKILL.md')[0]
|
||||
if skill_name not in [s['name'] for s in skill_files]:
|
||||
skill_files.append({
|
||||
'name': skill_name,
|
||||
'file': file,
|
||||
'status': 'untracked' if file in untracked else ('staged' if file in staged else 'modified')
|
||||
})
|
||||
|
||||
# Load catalog to verify
|
||||
catalog_file = base_dir / "data" / "catalog.json"
|
||||
with open(catalog_file, 'r') as f:
|
||||
catalog = json.load(f)
|
||||
|
||||
catalog_skills = {s['name']: s for s in catalog.get('skills', [])}
|
||||
|
||||
print("=" * 70)
|
||||
print("SKILLS NON COMMITTATE")
|
||||
print("=" * 70)
|
||||
print(f"\nTotale skills trovate: {len(skill_files)}")
|
||||
print(f"Totale skills nel catalog: {catalog.get('total', 0)}")
|
||||
print()
|
||||
|
||||
# Group by status
|
||||
untracked_skills = [s for s in skill_files if s['status'] == 'untracked']
|
||||
modified_skills = [s for s in skill_files if s['status'] == 'modified']
|
||||
staged_skills = [s for s in skill_files if s['status'] == 'staged']
|
||||
|
||||
print(f"📝 Skills non tracciate (nuove): {len(untracked_skills)}")
|
||||
print(f"📝 Skills modificate: {len(modified_skills)}")
|
||||
print(f"📝 Skills staged: {len(staged_skills)}")
|
||||
print()
|
||||
|
||||
if untracked_skills:
|
||||
print("Nuove skills (non tracciate):")
|
||||
for skill in sorted(untracked_skills, key=lambda x: x['name']):
|
||||
in_catalog = skill['name'] in catalog_skills
|
||||
print(f" ✅ {skill['name']} {'(in catalog)' if in_catalog else '(NOT in catalog)'}")
|
||||
|
||||
if modified_skills:
|
||||
print("\nSkills modificate:")
|
||||
for skill in sorted(modified_skills, key=lambda x: x['name']):
|
||||
print(f" 📝 {skill['name']}")
|
||||
|
||||
if staged_skills:
|
||||
print("\nSkills staged:")
|
||||
for skill in sorted(staged_skills, key=lambda x: x['name']):
|
||||
print(f" 📦 {skill['name']}")
|
||||
|
||||
# Check for VoltAgent skills specifically
|
||||
print("\n" + "=" * 70)
|
||||
print("VERIFICA SKILLS DA VOLTAGENT")
|
||||
print("=" * 70)
|
||||
|
||||
voltagent_skills_phase1 = [
|
||||
'commit', 'create-pr', 'find-bugs', 'iterate-pr',
|
||||
'culture-index', 'fix-review', 'sharp-edges',
|
||||
'expo-deployment', 'upgrading-expo',
|
||||
'using-neon', 'vercel-deploy-claimable', 'design-md',
|
||||
'hugging-face-cli', 'hugging-face-jobs',
|
||||
'automate-whatsapp', 'observe-whatsapp', 'readme', 'screenshots',
|
||||
'deep-research', 'imagen', 'swiftui-expert-skill',
|
||||
'n8n-code-python', 'n8n-mcp-tools-expert', 'n8n-node-configuration'
|
||||
]
|
||||
|
||||
voltagent_skills_phase2 = [
|
||||
'frontend-slides', 'linear-claude-skill', 'skill-rails-upgrade',
|
||||
'context-fundamentals', 'context-degradation', 'context-compression',
|
||||
'context-optimization', 'multi-agent-patterns', 'tool-design',
|
||||
'evaluation', 'memory-systems', 'terraform-skill'
|
||||
]
|
||||
|
||||
all_voltagent = voltagent_skills_phase1 + voltagent_skills_phase2
|
||||
|
||||
uncommitted_voltagent = []
|
||||
for skill_name in all_voltagent:
|
||||
skill_file = base_dir / "skills" / skill_name / "SKILL.md"
|
||||
if skill_file.exists():
|
||||
# Check if it's uncommitted
|
||||
if skill_file.relative_to(base_dir).as_posix() in untracked:
|
||||
uncommitted_voltagent.append(skill_name)
|
||||
elif skill_file.relative_to(base_dir).as_posix() in modified:
|
||||
uncommitted_voltagent.append(skill_name)
|
||||
elif skill_file.relative_to(base_dir).as_posix() in staged:
|
||||
uncommitted_voltagent.append(skill_name)
|
||||
|
||||
print(f"\nSkills da VoltAgent non committate: {len(uncommitted_voltagent)}")
|
||||
print(f" Fase 1 (49 skills): {len([s for s in voltagent_skills_phase1 if s in uncommitted_voltagent])}")
|
||||
print(f" Fase 2 (12 skills): {len([s for s in voltagent_skills_phase2 if s in uncommitted_voltagent])}")
|
||||
|
||||
print("\n" + "=" * 70)
|
||||
print("RIEPILOGO FINALE")
|
||||
print("=" * 70)
|
||||
print(f"Totale skills non committate: {len(skill_files)}")
|
||||
print(f"Skills da VoltAgent non committate: {len(uncommitted_voltagent)}")
|
||||
print(f"Altre skills non committate: {len(skill_files) - len(uncommitted_voltagent)}")
|
||||
|
||||
return {
|
||||
'total_uncommitted': len(skill_files),
|
||||
'voltagent_uncommitted': len(uncommitted_voltagent),
|
||||
'voltagent_phase1': len([s for s in voltagent_skills_phase1 if s in uncommitted_voltagent]),
|
||||
'voltagent_phase2': len([s for s in voltagent_skills_phase2 if s in uncommitted_voltagent])
|
||||
}
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
271
scripts/implement_similar_skills.py
Normal file
271
scripts/implement_similar_skills.py
Normal file
@@ -0,0 +1,271 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Implement the 12 new skills from similar skills analysis.
|
||||
9 recommended + 3 verified (evaluation, memory-systems, terraform-skill)
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from urllib.request import urlopen, Request
|
||||
from urllib.error import URLError, HTTPError
|
||||
from typing import Dict, Optional
|
||||
|
||||
def normalize_skill_name(name: str) -> str:
|
||||
"""Normalize skill name to kebab-case."""
|
||||
name = re.sub(r'[^a-z0-9-]', '-', name.lower())
|
||||
name = re.sub(r'-+', '-', name)
|
||||
return name.strip('-')
|
||||
|
||||
def download_file(url: str) -> Optional[str]:
|
||||
"""Download content from URL."""
|
||||
try:
|
||||
req = Request(url)
|
||||
req.add_header('User-Agent', 'Mozilla/5.0 (compatible; AntigravitySkillsDownloader/1.0)')
|
||||
with urlopen(req, timeout=15) as response:
|
||||
return response.read().decode('utf-8')
|
||||
except Exception as e:
|
||||
print(f" ❌ Error downloading {url}: {e}")
|
||||
return None
|
||||
|
||||
def parse_frontmatter(content: str) -> Optional[Dict]:
|
||||
"""Parse YAML frontmatter."""
|
||||
fm_match = re.search(r'^---\s*\n(.*?)\n---', content, re.DOTALL)
|
||||
if not fm_match:
|
||||
return None
|
||||
|
||||
fm_text = fm_match.group(1)
|
||||
metadata = {}
|
||||
for line in fm_text.split('\n'):
|
||||
if ':' in line:
|
||||
key, val = line.split(':', 1)
|
||||
metadata[key.strip()] = val.strip().strip('"').strip("'")
|
||||
return metadata
|
||||
|
||||
def ensure_frontmatter_compliance(content: str, skill_name: str, source_url: str, description: str) -> str:
|
||||
"""Ensure SKILL.md has compliant frontmatter."""
|
||||
metadata = parse_frontmatter(content)
|
||||
|
||||
if not metadata:
|
||||
# No frontmatter, add it
|
||||
frontmatter = f"""---
|
||||
name: {skill_name}
|
||||
description: {description}
|
||||
source: {source_url}
|
||||
risk: safe
|
||||
---
|
||||
|
||||
"""
|
||||
return frontmatter + content
|
||||
|
||||
# Update existing frontmatter
|
||||
metadata['name'] = skill_name
|
||||
metadata['description'] = description
|
||||
metadata['source'] = source_url
|
||||
if 'risk' not in metadata:
|
||||
metadata['risk'] = 'safe'
|
||||
|
||||
# Rebuild frontmatter
|
||||
frontmatter_lines = ['---']
|
||||
for key, value in metadata.items():
|
||||
if isinstance(value, str) and (' ' in value or ':' in value):
|
||||
frontmatter_lines.append(f'{key}: "{value}"')
|
||||
else:
|
||||
frontmatter_lines.append(f'{key}: {value}')
|
||||
frontmatter_lines.append('---\n')
|
||||
|
||||
# Replace frontmatter in content
|
||||
content_without_fm = re.sub(r'^---\s*\n.*?\n---\s*\n', '', content, flags=re.DOTALL)
|
||||
return '\n'.join(frontmatter_lines) + content_without_fm
|
||||
|
||||
def ensure_when_to_use_section(content: str, description: str) -> str:
|
||||
"""Ensure 'When to Use' section exists."""
|
||||
if re.search(r'##\s+When\s+to\s+Use', content, re.IGNORECASE):
|
||||
return content
|
||||
|
||||
# Add section after frontmatter
|
||||
when_to_use = f"""
|
||||
## When to Use This Skill
|
||||
|
||||
{description}
|
||||
|
||||
Use this skill when working with {description.lower()}.
|
||||
"""
|
||||
|
||||
# Insert after frontmatter
|
||||
content = re.sub(r'(---\s*\n.*?\n---\s*\n)', r'\1' + when_to_use, content, flags=re.DOTALL)
|
||||
return content
|
||||
|
||||
def main():
|
||||
base_dir = Path(__file__).parent.parent
|
||||
|
||||
# Load similar skills analysis
|
||||
analysis_file = base_dir / "similar_skills_analysis.json"
|
||||
with open(analysis_file, 'r') as f:
|
||||
analysis = json.load(f)
|
||||
|
||||
# Skills to implement: 9 recommended + 3 verified
|
||||
skills_to_implement = [
|
||||
# 9 Recommended
|
||||
{
|
||||
'name': 'frontend-slides',
|
||||
'url': 'https://github.com/zarazhangrui/frontend-slides',
|
||||
'raw_url': 'https://github.com/zarazhangrui/frontend-slides/raw/main/SKILL.md',
|
||||
'description': 'Generate animation-rich HTML presentations with visual style previews',
|
||||
'org': 'zarazhangrui',
|
||||
'category': 'Community Skills'
|
||||
},
|
||||
{
|
||||
'name': 'linear-claude-skill',
|
||||
'url': 'https://github.com/wrsmith108/linear-claude-skill',
|
||||
'raw_url': 'https://github.com/wrsmith108/linear-claude-skill/raw/main/SKILL.md',
|
||||
'description': 'Manage Linear issues, projects, and teams',
|
||||
'org': 'wrsmith108',
|
||||
'category': 'Community Skills'
|
||||
},
|
||||
{
|
||||
'name': 'skill-rails-upgrade',
|
||||
'url': 'https://github.com/robzolkos/skill-rails-upgrade',
|
||||
'raw_url': 'https://github.com/robzolkos/skill-rails-upgrade/raw/master/SKILL.md',
|
||||
'description': 'Analyze Rails apps and provide upgrade assessments',
|
||||
'org': 'robzolkos',
|
||||
'category': 'Community Skills'
|
||||
},
|
||||
{
|
||||
'name': 'context-fundamentals',
|
||||
'url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/tree/main/skills/context-fundamentals',
|
||||
'raw_url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/raw/main/skills/context-fundamentals/SKILL.md',
|
||||
'description': 'Understand what context is, why it matters, and the anatomy of context in agent systems',
|
||||
'org': 'muratcankoylan',
|
||||
'category': 'Community Skills'
|
||||
},
|
||||
{
|
||||
'name': 'context-degradation',
|
||||
'url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/tree/main/skills/context-degradation',
|
||||
'raw_url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/raw/main/skills/context-degradation/SKILL.md',
|
||||
'description': 'Recognize patterns of context failure: lost-in-middle, poisoning, distraction, and clash',
|
||||
'org': 'muratcankoylan',
|
||||
'category': 'Community Skills'
|
||||
},
|
||||
{
|
||||
'name': 'context-compression',
|
||||
'url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/tree/main/skills/context-compression',
|
||||
'raw_url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/raw/main/skills/context-compression/SKILL.md',
|
||||
'description': 'Design and evaluate compression strategies for long-running sessions',
|
||||
'org': 'muratcankoylan',
|
||||
'category': 'Community Skills'
|
||||
},
|
||||
{
|
||||
'name': 'context-optimization',
|
||||
'url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/tree/main/skills/context-optimization',
|
||||
'raw_url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/raw/main/skills/context-optimization/SKILL.md',
|
||||
'description': 'Apply compaction, masking, and caching strategies',
|
||||
'org': 'muratcankoylan',
|
||||
'category': 'Community Skills'
|
||||
},
|
||||
{
|
||||
'name': 'multi-agent-patterns',
|
||||
'url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/tree/main/skills/multi-agent-patterns',
|
||||
'raw_url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/raw/main/skills/multi-agent-patterns/SKILL.md',
|
||||
'description': 'Master orchestrator, peer-to-peer, and hierarchical multi-agent architectures',
|
||||
'org': 'muratcankoylan',
|
||||
'category': 'Community Skills'
|
||||
},
|
||||
{
|
||||
'name': 'tool-design',
|
||||
'url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/tree/main/skills/tool-design',
|
||||
'raw_url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/raw/main/skills/tool-design/SKILL.md',
|
||||
'description': 'Build tools that agents can use effectively, including architectural reduction patterns',
|
||||
'org': 'muratcankoylan',
|
||||
'category': 'Community Skills'
|
||||
},
|
||||
# 3 Verified (notebooklm-skill is duplicate, skip it)
|
||||
{
|
||||
'name': 'evaluation',
|
||||
'url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/tree/main/skills/evaluation',
|
||||
'raw_url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/raw/main/skills/evaluation/SKILL.md',
|
||||
'description': 'Build evaluation frameworks for agent systems',
|
||||
'org': 'muratcankoylan',
|
||||
'category': 'Community Skills'
|
||||
},
|
||||
{
|
||||
'name': 'memory-systems',
|
||||
'url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/tree/main/skills/memory-systems',
|
||||
'raw_url': 'https://github.com/muratcankoylan/Agent-Skills-for-Context-Engineering/raw/main/skills/memory-systems/SKILL.md',
|
||||
'description': 'Design short-term, long-term, and graph-based memory architectures',
|
||||
'org': 'muratcankoylan',
|
||||
'category': 'Community Skills'
|
||||
},
|
||||
{
|
||||
'name': 'terraform-skill',
|
||||
'url': 'https://github.com/antonbabenko/terraform-skill',
|
||||
'raw_url': 'https://github.com/antonbabenko/terraform-skill/raw/master/SKILL.md',
|
||||
'description': 'Terraform infrastructure as code best practices',
|
||||
'org': 'antonbabenko',
|
||||
'category': 'Community Skills'
|
||||
},
|
||||
]
|
||||
|
||||
print(f"🚀 Implementing {len(skills_to_implement)} new skills...\n")
|
||||
|
||||
results = {
|
||||
'success': [],
|
||||
'failed': []
|
||||
}
|
||||
|
||||
for skill in skills_to_implement:
|
||||
skill_name = skill['name']
|
||||
raw_url = skill['raw_url']
|
||||
source_url = skill['url']
|
||||
description = skill['description']
|
||||
|
||||
print(f"📦 Processing: {skill_name}")
|
||||
|
||||
# Download SKILL.md
|
||||
content = download_file(raw_url)
|
||||
if not content:
|
||||
print(f" ❌ Failed to download")
|
||||
results['failed'].append(skill_name)
|
||||
continue
|
||||
|
||||
# Check if it's HTML (shouldn't be, but just in case)
|
||||
if '<!DOCTYPE html>' in content or ('<html>' in content.lower() and content.count('<html>') > 1):
|
||||
print(f" ⚠️ Received HTML instead of markdown, trying alternative URL")
|
||||
# Try alternative raw URL
|
||||
alt_url = raw_url.replace('/raw/main/', '/raw/master/') if '/raw/main/' in raw_url else raw_url.replace('/raw/master/', '/raw/main/')
|
||||
alt_content = download_file(alt_url)
|
||||
if alt_content and not ('<!DOCTYPE html>' in alt_content or '<html>' in alt_content.lower()):
|
||||
content = alt_content
|
||||
print(f" ✅ Got markdown from alternative URL")
|
||||
else:
|
||||
print(f" ❌ Still HTML, skipping")
|
||||
results['failed'].append(skill_name)
|
||||
continue
|
||||
|
||||
# Ensure compliance
|
||||
content = ensure_frontmatter_compliance(content, skill_name, source_url, description)
|
||||
content = ensure_when_to_use_section(content, description)
|
||||
|
||||
# Create skill directory
|
||||
skill_dir = base_dir / "skills" / skill_name
|
||||
skill_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Write SKILL.md
|
||||
skill_file = skill_dir / "SKILL.md"
|
||||
skill_file.write_text(content, encoding='utf-8')
|
||||
|
||||
print(f" ✅ Created: {skill_file}")
|
||||
results['success'].append(skill_name)
|
||||
|
||||
print(f"\n✅ Implementation complete!")
|
||||
print(f" Success: {len(results['success'])}")
|
||||
print(f" Failed: {len(results['failed'])}")
|
||||
|
||||
if results['failed']:
|
||||
print(f"\n❌ Failed skills: {', '.join(results['failed'])}")
|
||||
|
||||
return results
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user