Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| Utility functions for Skill Seeker CLI tools | |
| """ | |
| import os | |
| import sys | |
| import subprocess | |
| import platform | |
| from pathlib import Path | |
| def open_folder(folder_path): | |
| """ | |
| Open a folder in the system file browser | |
| Args: | |
| folder_path: Path to folder to open | |
| Returns: | |
| bool: True if successful, False otherwise | |
| """ | |
| folder_path = Path(folder_path).resolve() | |
| if not folder_path.exists(): | |
| print(f"β οΈ Folder not found: {folder_path}") | |
| return False | |
| system = platform.system() | |
| try: | |
| if system == "Linux": | |
| # Try xdg-open first (standard) | |
| subprocess.run(["xdg-open", str(folder_path)], check=True) | |
| elif system == "Darwin": # macOS | |
| subprocess.run(["open", str(folder_path)], check=True) | |
| elif system == "Windows": | |
| subprocess.run(["explorer", str(folder_path)], check=True) | |
| else: | |
| print(f"β οΈ Unknown operating system: {system}") | |
| return False | |
| return True | |
| except subprocess.CalledProcessError: | |
| print(f"β οΈ Could not open folder automatically") | |
| return False | |
| except FileNotFoundError: | |
| print(f"β οΈ File browser not found on system") | |
| return False | |
| def has_api_key(): | |
| """ | |
| Check if ANTHROPIC_API_KEY is set in environment | |
| Returns: | |
| bool: True if API key is set, False otherwise | |
| """ | |
| api_key = os.environ.get('ANTHROPIC_API_KEY', '').strip() | |
| return len(api_key) > 0 | |
| def get_api_key(): | |
| """ | |
| Get ANTHROPIC_API_KEY from environment | |
| Returns: | |
| str: API key or None if not set | |
| """ | |
| api_key = os.environ.get('ANTHROPIC_API_KEY', '').strip() | |
| return api_key if api_key else None | |
| def get_upload_url(): | |
| """ | |
| Get the Claude skills upload URL | |
| Returns: | |
| str: Claude skills upload URL | |
| """ | |
| return "https://claude.ai/skills" | |
| def print_upload_instructions(zip_path): | |
| """ | |
| Print clear upload instructions for manual upload | |
| Args: | |
| zip_path: Path to the .zip file to upload | |
| """ | |
| zip_path = Path(zip_path) | |
| print() | |
| print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ") | |
| print("β NEXT STEP β") | |
| print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ") | |
| print() | |
| print(f"π€ Upload to Claude: {get_upload_url()}") | |
| print() | |
| print(f"1. Go to {get_upload_url()}") | |
| print("2. Click \"Upload Skill\"") | |
| print(f"3. Select: {zip_path}") | |
| print("4. Done! β ") | |
| print() | |
| def format_file_size(size_bytes): | |
| """ | |
| Format file size in human-readable format | |
| Args: | |
| size_bytes: Size in bytes | |
| Returns: | |
| str: Formatted size (e.g., "45.3 KB") | |
| """ | |
| if size_bytes < 1024: | |
| return f"{size_bytes} bytes" | |
| elif size_bytes < 1024 * 1024: | |
| return f"{size_bytes / 1024:.1f} KB" | |
| else: | |
| return f"{size_bytes / (1024 * 1024):.1f} MB" | |
| def validate_skill_directory(skill_dir): | |
| """ | |
| Validate that a directory is a valid skill directory | |
| Args: | |
| skill_dir: Path to skill directory | |
| Returns: | |
| tuple: (is_valid, error_message) | |
| """ | |
| skill_path = Path(skill_dir) | |
| if not skill_path.exists(): | |
| return False, f"Directory not found: {skill_dir}" | |
| if not skill_path.is_dir(): | |
| return False, f"Not a directory: {skill_dir}" | |
| skill_md = skill_path / "SKILL.md" | |
| if not skill_md.exists(): | |
| return False, f"SKILL.md not found in {skill_dir}" | |
| return True, None | |
| def validate_zip_file(zip_path): | |
| """ | |
| Validate that a file is a valid skill .zip file | |
| Args: | |
| zip_path: Path to .zip file | |
| Returns: | |
| tuple: (is_valid, error_message) | |
| """ | |
| zip_path = Path(zip_path) | |
| if not zip_path.exists(): | |
| return False, f"File not found: {zip_path}" | |
| if not zip_path.is_file(): | |
| return False, f"Not a file: {zip_path}" | |
| if not zip_path.suffix == '.zip': | |
| return False, f"Not a .zip file: {zip_path}" | |
| return True, None | |