File size: 5,193 Bytes
37d13e8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/usr/bin/env python3
"""
Simple Skill Packager
Packages a skill directory into a .zip file for Claude.

Usage:
    python3 package_skill.py output/steam-inventory/
    python3 package_skill.py output/react/
    python3 package_skill.py output/react/ --no-open  # Don't open folder
"""

import os
import sys
import zipfile
import argparse
from pathlib import Path

# Import utilities
try:
    from utils import (
        open_folder,
        print_upload_instructions,
        format_file_size,
        validate_skill_directory
    )
except ImportError:
    # If running from different directory, add cli to path
    sys.path.insert(0, str(Path(__file__).parent))
    from utils import (
        open_folder,
        print_upload_instructions,
        format_file_size,
        validate_skill_directory
    )


def package_skill(skill_dir, open_folder_after=True):
    """
    Package a skill directory into a .zip file

    Args:
        skill_dir: Path to skill directory
        open_folder_after: Whether to open the output folder after packaging

    Returns:
        tuple: (success, zip_path) where success is bool and zip_path is Path or None
    """
    skill_path = Path(skill_dir)

    # Validate skill directory
    is_valid, error_msg = validate_skill_directory(skill_path)
    if not is_valid:
        print(f"❌ Error: {error_msg}")
        return False, None

    # Create zip filename
    skill_name = skill_path.name
    zip_path = skill_path.parent / f"{skill_name}.zip"

    print(f"📦 Packaging skill: {skill_name}")
    print(f"   Source: {skill_path}")
    print(f"   Output: {zip_path}")

    # Create zip file
    with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zf:
        for root, dirs, files in os.walk(skill_path):
            # Skip backup files
            files = [f for f in files if not f.endswith('.backup')]

            for file in files:
                file_path = Path(root) / file
                arcname = file_path.relative_to(skill_path)
                zf.write(file_path, arcname)
                print(f"   + {arcname}")

    # Get zip size
    zip_size = zip_path.stat().st_size
    print(f"\n✅ Package created: {zip_path}")
    print(f"   Size: {zip_size:,} bytes ({format_file_size(zip_size)})")

    # Open folder in file browser
    if open_folder_after:
        print(f"\n📂 Opening folder: {zip_path.parent}")
        open_folder(zip_path.parent)

    # Print upload instructions
    print_upload_instructions(zip_path)

    return True, zip_path


def main():
    parser = argparse.ArgumentParser(
        description="Package a skill directory into a .zip file for Claude",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Package skill and open folder
  python3 package_skill.py output/react/

  # Package skill without opening folder
  python3 package_skill.py output/react/ --no-open

  # Get help
  python3 package_skill.py --help
        """
    )

    parser.add_argument(
        'skill_dir',
        help='Path to skill directory (e.g., output/react/)'
    )

    parser.add_argument(
        '--no-open',
        action='store_true',
        help='Do not open the output folder after packaging'
    )

    parser.add_argument(
        '--upload',
        action='store_true',
        help='Automatically upload to Claude after packaging (requires ANTHROPIC_API_KEY)'
    )

    args = parser.parse_args()

    success, zip_path = package_skill(args.skill_dir, open_folder_after=not args.no_open)

    if not success:
        sys.exit(1)

    # Auto-upload if requested
    if args.upload:
        # Check if API key is set BEFORE attempting upload
        api_key = os.environ.get('ANTHROPIC_API_KEY', '').strip()

        if not api_key:
            # No API key - show helpful message but DON'T fail
            print("\n" + "="*60)
            print("💡 Automatic Upload")
            print("="*60)
            print()
            print("To enable automatic upload:")
            print("  1. Get API key from https://console.anthropic.com/")
            print("  2. Set: export ANTHROPIC_API_KEY=sk-ant-...")
            print("  3. Run package_skill.py with --upload flag")
            print()
            print("For now, use manual upload (instructions above) ☝️")
            print("="*60)
            # Exit successfully - packaging worked!
            sys.exit(0)

        # API key exists - try upload
        try:
            from upload_skill import upload_skill_api
            print("\n" + "="*60)
            upload_success, message = upload_skill_api(zip_path)
            if not upload_success:
                print(f"❌ Upload failed: {message}")
                print()
                print("💡 Try manual upload instead (instructions above) ☝️")
                print("="*60)
                # Exit successfully - packaging worked even if upload failed
                sys.exit(0)
            else:
                print("="*60)
                sys.exit(0)
        except ImportError:
            print("\n❌ Error: upload_skill.py not found")
            sys.exit(1)

    sys.exit(0)


if __name__ == "__main__":
    main()