feat: Add modern Python packaging - Phase 1 (Foundation)
Implements issue #168 - Modern Python packaging with uv support This is Phase 1 of the modernization effort, establishing the core package structure and build system. ## Major Changes ### 1. Migrated to src/ Layout - Moved cli/ → src/skill_seekers/cli/ - Moved skill_seeker_mcp/ → src/skill_seekers/mcp/ - Created root package: src/skill_seekers/__init__.py - Updated all imports: cli. → skill_seekers.cli. - Updated all imports: skill_seeker_mcp. → skill_seekers.mcp. ### 2. Created pyproject.toml - Modern Python packaging configuration - All dependencies properly declared - 8 CLI entry points configured: * skill-seekers (unified CLI) * skill-seekers-scrape * skill-seekers-github * skill-seekers-pdf * skill-seekers-unified * skill-seekers-enhance * skill-seekers-package * skill-seekers-upload * skill-seekers-estimate - uv tool support enabled - Build system: setuptools with wheel ### 3. Created Unified CLI (main.py) - Git-style subcommands (skill-seekers scrape, etc.) - Delegates to existing tool main() functions - Full help system at top-level and subcommand level - Backwards compatible with individual commands ### 4. Updated Package Versions - cli/__init__.py: 1.3.0 → 2.0.0 - mcp/__init__.py: 1.2.0 → 2.0.0 - Root package: 2.0.0 ### 5. Updated Test Suite - Fixed test_package_structure.py for new layout - All 28 package structure tests passing - Updated all test imports for new structure ## Installation Methods (Working) ```bash # Development install pip install -e . # Run unified CLI skill-seekers --version # → 2.0.0 skill-seekers --help # Run individual tools skill-seekers-scrape --help skill-seekers-github --help ``` ## Test Results - Package structure tests: 28/28 passing ✅ - Package installs successfully ✅ - All entry points working ✅ ## Still TODO (Phase 2) - [ ] Run full test suite (299 tests) - [ ] Update documentation (README, CLAUDE.md, etc.) - [ ] Test with uv tool run/install - [ ] Build and publish to PyPI - [ ] Create PR and merge ## Breaking Changes None - fully backwards compatible. Old import paths still work. ## Migration for Users No action needed. Package works with both pip and uv. Closes #168 (when complete) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
81
src/skill_seekers/cli/package_multi.py
Normal file
81
src/skill_seekers/cli/package_multi.py
Normal file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Multi-Skill Packager
|
||||
|
||||
Package multiple skills at once. Useful for packaging router + sub-skills together.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
|
||||
|
||||
def package_skill(skill_dir: Path) -> bool:
|
||||
"""Package a single skill"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[sys.executable, str(Path(__file__).parent / "package_skill.py"), str(skill_dir)],
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
return result.returncode == 0
|
||||
except Exception as e:
|
||||
print(f"❌ Error packaging {skill_dir}: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Package multiple skills at once",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
# Package all godot skills
|
||||
python3 package_multi.py output/godot*/
|
||||
|
||||
# Package specific skills
|
||||
python3 package_multi.py output/godot-2d/ output/godot-3d/ output/godot-scripting/
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'skill_dirs',
|
||||
nargs='+',
|
||||
help='Skill directories to package'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"MULTI-SKILL PACKAGER")
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
skill_dirs = [Path(d) for d in args.skill_dirs]
|
||||
success_count = 0
|
||||
total_count = len(skill_dirs)
|
||||
|
||||
for skill_dir in skill_dirs:
|
||||
if not skill_dir.exists():
|
||||
print(f"⚠️ Skipping (not found): {skill_dir}")
|
||||
continue
|
||||
|
||||
if not (skill_dir / "SKILL.md").exists():
|
||||
print(f"⚠️ Skipping (no SKILL.md): {skill_dir}")
|
||||
continue
|
||||
|
||||
print(f"📦 Packaging: {skill_dir.name}")
|
||||
if package_skill(skill_dir):
|
||||
success_count += 1
|
||||
print(f" ✅ Success")
|
||||
else:
|
||||
print(f" ❌ Failed")
|
||||
print("")
|
||||
|
||||
print(f"{'='*60}")
|
||||
print(f"SUMMARY: {success_count}/{total_count} skills packaged")
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user