#!/usr/bin/env python3
"""
Skill Manager CLI - Unified skill management for AI IDEs.

Usage:
    skills                  # Interactive menu
    skills list             # List installed skills
    skills search "query"   # Search community skills
    skills install <url>    # Install from GitHub
    skills create <name>    # Create new skill
    skills sync             # Sync to all IDEs
    skills remove <name>    # Remove skill
    skills validate         # Validate skills
    skills export           # Export profile
    skills import <file>    # Import profile
    skills status           # Check status
"""

import os
import sys

# Add scripts directory to path
scripts_dir = os.path.dirname(os.path.abspath(__file__))
if scripts_dir not in sys.path:
    sys.path.insert(0, scripts_dir)

# Now we can import using absolute imports within the package
# But since this is a standalone script, we need to modify cli.py imports too
# Let's use a different approach - import the module directly

def main():
    """Main entry point."""
    import argparse
    import json
    from pathlib import Path
    
    # Import utility functions directly
    exec_globals = {}
    exec(open(os.path.join(scripts_dir, "utils.py")).read(), exec_globals)
    
    expand_path = exec_globals['expand_path']
    load_config = exec_globals['load_config']
    get_skills_from_dir = exec_globals['get_skills_from_dir']
    find_project_root = exec_globals['find_project_root']
    get_skill_description = exec_globals['get_skill_description']
    print_json = exec_globals['print_json']
    
    def show_interactive_menu():
        """Show interactive menu when called without arguments."""
        config = load_config()
        source_dir = expand_path(config.get("source_dir", "~/.ai-skills"))
        exclude = config.get("exclude_skills", [])
        skills = get_skills_from_dir(source_dir, exclude)
        enabled_ides = config.get("enabled_ides", [])
        
        print()
        print("╔════════════════════════════════════════════════════╗")
        print("║         Skill Manager - Interactive Mode           ║")
        print("╠════════════════════════════════════════════════════╣")
        print(f"║ Installed Skills: {len(skills):<33}║")
        print(f"║ Enabled IDEs: {', '.join(enabled_ides[:4]):<37}║")
        print("╚════════════════════════════════════════════════════╝")
        print()
        print("1. List installed skills")
        print("2. Search community skills")
        print("3. Install a skill")
        print("4. Create new skill")
        print("5. Sync to all IDEs")
        print("6. Validate skills")
        print("7. Export profile")
        print("8. Import profile")
        print("9. Check status")
        print("10. Upstream management")
        print("0. Exit")
        print()

        try:
            choice = input("Enter choice [0-10]: ").strip()
        except (KeyboardInterrupt, EOFError):
            print("\nExiting.")
            return

        if choice == "0" or not choice:
            return
        elif choice == "1":
            cmd_list(config, expand_path, get_skills_from_dir, get_skill_description)
        elif choice == "2":
            query = input("Search query: ").strip()
            if query:
                cmd_search(query, scripts_dir)
        elif choice == "3":
            url = input("GitHub URL: ").strip()
            if url:
                cmd_install(url, config, expand_path, scripts_dir)
        elif choice == "4":
            name = input("Skill name: ").strip()
            if name:
                cmd_create(name, config, expand_path, scripts_dir)
        elif choice == "5":
            cmd_sync(config, expand_path, get_skills_from_dir, scripts_dir)
        elif choice == "6":
            cmd_validate(config, expand_path, get_skills_from_dir, scripts_dir)
        elif choice == "7":
            cmd_export(config, expand_path, get_skills_from_dir, scripts_dir)
        elif choice == "8":
            path = input("Profile path or Gist ID: ").strip()
            if path:
                cmd_import_profile(path, scripts_dir)
        elif choice == "9":
            cmd_status(config, expand_path, get_skills_from_dir)
        elif choice == "10":
            cmd_upstream_menu(scripts_dir, exec_globals, config)
        else:
            print("Invalid choice.")

    def cmd_list(config, expand_path, get_skills_from_dir, get_skill_description, 
                 scope="global", project_dir=None, json_output=False):
        """List installed skills."""
        exclude = config.get("exclude_skills", [])
        result = {"global": [], "local": []}
        
        if scope in ("global", "all"):
            source_dir = expand_path(config.get("source_dir", "~/.ai-skills"))
            skills = get_skills_from_dir(source_dir, exclude)
            
            if not json_output:
                print(f"[GLOBAL] {source_dir}\n")
                if skills:
                    for skill in skills:
                        skill_path = source_dir / skill
                        desc = get_skill_description(skill_path)
                        print(f"  - {skill}")
                        if desc:
                            print(f"    {desc}")
                    print(f"\n  Total: {len(skills)} skill(s)")
                else:
                    print("  (no skills)")
            
            for skill in skills:
                skill_path = source_dir / skill
                result["global"].append({
                    "name": skill,
                    "path": str(skill_path),
                    "description": get_skill_description(skill_path),
                })
        
        if json_output:
            print(json.dumps(result, indent=2, ensure_ascii=False))
        
        return result

    def cmd_status(config, expand_path, get_skills_from_dir):
        """Check status."""
        exclude = config.get("exclude_skills", [])
        
        print("Skill Manager Status\n")
        print("=" * 50)
        
        source_dir = expand_path(config.get("source_dir", "~/.ai-skills"))
        skills = get_skills_from_dir(source_dir, exclude)
        
        print(f"\n[GLOBAL]")
        print(f"  Source: {source_dir}")
        print(f"  Skills: {len(skills)}")
        
        print(f"\n  IDE Targets:")
        for ide_name in config.get("enabled_ides", []):
            target_path = config.get("targets", {}).get(ide_name)
            if target_path:
                target_dir = expand_path(target_path)
                exists = target_dir.exists()
                count = len(list(target_dir.iterdir())) if exists else 0
                status = f"{count} skills" if exists else "not created"
                print(f"    [{ide_name}] {target_dir} ({status})")
        
        print(f"\n[CONFIG]")
        print(f"  Auto-commit: {config.get('git', {}).get('auto_commit', True)}")
        print(f"  Auto-sync after install: {config.get('sync', {}).get('auto_after_install', True)}")

    def cmd_search(query, scripts_dir):
        """Search for skills."""
        import subprocess
        subprocess.run([sys.executable, "-c", f"""
import sys
sys.path.insert(0, '{scripts_dir}')
exec(open('{scripts_dir}/search.py').read().replace('from .utils', '# from .utils'))

# Re-import needed functions
import json
import os
import time
from pathlib import Path

def expand_path(path, base_dir=None):
    expanded = os.path.expandvars(os.path.expanduser(path))
    p = Path(expanded)
    if not p.is_absolute() and base_dir:
        return base_dir / p
    return p

def load_config():
    config_path = expand_path("~/.ai-skills/skill-manager/config.json")
    if config_path.exists():
        with open(config_path) as f:
            return json.load(f)
    return {{}}

# Run search
db_path = Path('{scripts_dir}').parent / "data" / "all_skills_with_cn.json"
if db_path.exists():
    with open(db_path) as f:
        skills = json.load(f)
    
    query_lower = "{query}".lower()
    results = []
    for skill in skills:
        name = skill.get("name", "").lower()
        desc = skill.get("description", "").lower()
        score = 0
        if query_lower in name:
            score += 10
        if query_lower == name:
            score += 20
        if query_lower in desc:
            score += 5
        if score > 0:
            results.append((score, skill))
    
    results.sort(key=lambda x: -x[0])
    results = results[:15]
    
    print(f'Searching for "{query}" in {{len(skills):,}} skills...\\n')
    print(f"Found {{len(results)}} results:\\n")
    
    for i, (score, skill) in enumerate(results, 1):
        name = skill.get("name", "unknown")
        repo = skill.get("repo", "")
        desc = skill.get("description", "")[:80]
        url = skill.get("url", "")
        print(f"{{i}}. {{repo}}/{{name}}" if repo else f"{{i}}. {{name}}")
        if desc:
            print(f"   {{desc}}")
        if url:
            print(f"   URL: {{url}}")
        print()
    
    print("Install: skills install <url>")
else:
    print("Skills database not found.")
"""])

    def cmd_install(url, config, expand_path, scripts_dir, dest_override=None,
                    scope="global", project_dir=None):
        """Install a skill."""
        import subprocess
        dest_dir = dest_override or expand_path(config.get("source_dir", "~/.ai-skills"))
        installer_script = expand_path("~/.ai-skills/skill-installer/scripts/install-skill-from-github.py")

        scope_label = "[LOCAL]" if scope == "local" else "[GLOBAL]"
        print(f"{scope_label} Installing to: {dest_dir}\n")

        if installer_script.exists():
            # URL is validated by install.py's _parse_github_url (domain allowlist)
            result = subprocess.run([
                sys.executable,
                str(installer_script),
                "--url", url,
                "--dest", str(dest_dir)
            ])

            # Auto-sync after install if successful
            if result.returncode == 0 and config.get("sync", {}).get("auto_after_install", True):
                print(f"\n[Auto-sync] Syncing to IDEs ({scope} scope)...")
                if scope == "local" and project_dir:
                    cmd_sync_local(config, expand_path, get_skills_from_dir, project_dir)
                else:
                    cmd_sync(config, expand_path, get_skills_from_dir, scripts_dir)
        else:
            print(f"Error: Installer script not found: {installer_script}")
            print("Please ensure skill-installer is available.")

    def cmd_create(name, config, expand_path, scripts_dir):
        """Create a new skill."""
        import subprocess
        dest_dir = expand_path(config.get("source_dir", "~/.ai-skills"))
        creator_script = os.path.join(scripts_dir, "..", "references", "skill-creator", "scripts", "init_skill.py")
        if os.path.exists(creator_script):
            subprocess.run([sys.executable, creator_script, name, "--path", str(dest_dir)])
        else:
            # Fallback: create minimal skill
            skill_dir = dest_dir / name
            skill_dir.mkdir(parents=True, exist_ok=True)
            skill_md = skill_dir / "SKILL.md"
            skill_title = " ".join(word.capitalize() for word in name.split("-"))
            skill_md.write_text(f"""---
name: {name}
description: [TODO: Add description]
---

# {skill_title}

[TODO: Add content]
""")
            print(f"Created skill at {skill_dir}")

    def cmd_sync(config, expand_path, get_skills_from_dir, scripts_dir, skill_name=None):
        """Sync skills to all IDEs."""
        import shutil
        
        source_dir = expand_path(config.get("source_dir", "~/.ai-skills"))
        exclude = config.get("exclude_skills", [])
        use_symlinks = config.get("sync", {}).get("use_symlinks", False)
        preserve_target_skills = config.get("preserve_target_skills", {})
        
        if skill_name:
            skills = [skill_name]
        else:
            skills = get_skills_from_dir(source_dir, exclude)
        
        if not skills:
            print(f"[GLOBAL] No skills found in {source_dir}")
            return
        
        print(f"[GLOBAL] Source: {source_dir}")
        print(f"[GLOBAL] Syncing {len(skills)} skill(s)...\n")
        
        for ide_name in config.get("enabled_ides", []):
            target_path = config.get("targets", {}).get(ide_name)
            if not target_path:
                continue
            
            target_dir = expand_path(target_path)
            print(f"  [{ide_name.upper()}] {target_dir}")
            
            target_dir.mkdir(parents=True, exist_ok=True)
            
            for skill in skills:
                source = source_dir / skill
                target = target_dir / skill
                
                if not source.exists():
                    print(f"    [FAIL] {skill} (not found)")
                    continue
                
                if target.exists() or target.is_symlink():
                    if target.is_symlink():
                        target.unlink()
                    elif target.is_dir():
                        shutil.rmtree(target)
                
                if use_symlinks:
                    try:
                        target.symlink_to(source.resolve())
                        print(f"    [OK] {skill} (symlink)")
                    except OSError:
                        shutil.copytree(source, target)
                        print(f"    [OK] {skill} (copy)")
                else:
                    shutil.copytree(source, target)
                    print(f"    [OK] {skill} (copy)")
            
            # Cleanup orphaned
            if not skill_name:
                preserve_dirs = preserve_target_skills.get(ide_name, [])
                for item in target_dir.iterdir():
                    if item.is_dir() or item.is_symlink():
                        if item.name not in skills and item.name not in exclude and item.name not in preserve_dirs:
                            if (item / "SKILL.md").exists() if item.is_dir() and not item.is_symlink() else True:
                                if item.is_symlink():
                                    item.unlink()
                                else:
                                    shutil.rmtree(item)
                                print(f"    [DEL] {item.name} (orphaned)")
        
        print("\n[GLOBAL] Sync complete!")

    def cmd_validate(config, expand_path, get_skills_from_dir, scripts_dir, skill_name=None):
        """Validate skills."""
        import re
        
        source_dir = expand_path(config.get("source_dir", "~/.ai-skills"))
        exclude = config.get("exclude_skills", [])
        
        if skill_name:
            skills = [skill_name]
        else:
            skills = get_skills_from_dir(source_dir, exclude)
        
        print(f"Validating {len(skills)} skill(s) from {source_dir}\n")
        
        for skill in skills:
            skill_path = source_dir / skill
            skill_md = skill_path / "SKILL.md"
            
            print(f"Validating: {skill}")
            print("=" * 60)
            
            if not skill_md.exists():
                print("[FAIL] SKILL.md not found")
                continue
            
            content = skill_md.read_text()
            
            # Check name format
            if re.match(r"^[a-z0-9-]+$", skill):
                print(f"[PASS] name: valid format")
            else:
                print(f"[FAIL] name: must be kebab-case")
            
            # Check frontmatter
            if content.startswith("---"):
                if "name:" in content and "description:" in content:
                    print("[PASS] YAML: has required fields")
                else:
                    print("[WARN] YAML: missing name or description")
            else:
                print("[FAIL] YAML: no frontmatter found")
            
            # Check file size
            lines = len(content.split("\n"))
            if lines <= 500:
                print(f"[PASS] SKILL.md: {lines} lines")
            else:
                print(f"[WARN] SKILL.md: {lines} lines (> 500)")
            
            print()
        
        print("Validation complete!")

    def cmd_export(config, expand_path, get_skills_from_dir, scripts_dir):
        """Export profile."""
        import time
        
        source_dir = expand_path(config.get("source_dir", "~/.ai-skills"))
        exclude = config.get("exclude_skills", [])
        skills = get_skills_from_dir(source_dir, exclude)
        
        profile = {
            "version": "1.0.0",
            "exported_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
            "skills": [{"name": s, "source": "local"} for s in skills],
        }
        
        output_path = expand_path("~/.skills-profile.json")
        with open(output_path, "w") as f:
            json.dump(profile, f, indent=2)
        
        print(f"Exported {len(skills)} skills to {output_path}")

    def cmd_import_profile(source, config, expand_path, get_skills_from_dir, scripts_dir):
        """Import profile."""
        source_dir = expand_path(config.get("source_dir", "~/.ai-skills"))
        exclude = config.get("exclude_skills", [])
        installed_skills = set(get_skills_from_dir(source_dir, exclude))
        
        # Load profile
        profile_path = Path(source)
        if not profile_path.exists():
            print(f"Error: Profile not found: {source}")
            return
        
        with open(profile_path) as f:
            profile = json.load(f)
        
        print(f"Importing from: {source}")
        print(f"Profile version: {profile.get('version', 'unknown')}")
        print(f"Exported at: {profile.get('exported_at', 'unknown')}")
        print(f"\nSkills in profile: {len(profile.get('skills', []))}")
        print(f"Currently installed: {len(installed_skills)}\n")
        
        profile_skills = {s["name"] for s in profile.get("skills", [])}
        
        # Find differences
        to_restore = profile_skills - installed_skills
        extra = installed_skills - profile_skills
        
        if to_restore:
            print(f"Missing (need to restore): {', '.join(sorted(to_restore))}")
        if extra:
            print(f"Extra (not in profile): {', '.join(sorted(extra))}")
        
        if not to_restore and not extra:
            print("Profile matches current state - nothing to do.")
            return
        
        print(f"\nNote: Profile restore for local skills requires manual reinstall.")
        print(f"Use 'skills install <url>' for each missing skill.")

    def cmd_remove(skill_name, config, expand_path, get_skills_from_dir, scripts_dir, force=False):
        """Remove a skill."""
        import shutil
        
        source_dir = expand_path(config.get("source_dir", "~/.ai-skills"))
        exclude = config.get("exclude_skills", [])
        
        if skill_name in exclude and not force:
            print(f"Error: Cannot remove protected skill: {skill_name}")
            print("Use --force to override.")
            return False
        
        skill_path = source_dir / skill_name
        if not skill_path.exists():
            print(f"Error: Skill not found: {skill_name}")
            return False
        
        print(f"Removing skill: {skill_name}\n")
        
        # Remove from IDE targets
        for ide_name in config.get("enabled_ides", []):
            target_path = config.get("targets", {}).get(ide_name)
            if target_path:
                target_dir = expand_path(target_path) / skill_name
                if target_dir.exists() or target_dir.is_symlink():
                    if target_dir.is_symlink():
                        target_dir.unlink()
                    else:
                        shutil.rmtree(target_dir)
                    print(f"  [{ide_name.upper()}] removed")
                else:
                    print(f"  [{ide_name.upper()}] not present")
        
        # Remove from source
        shutil.rmtree(skill_path)
        print(f"\n  [SOURCE] Removed: {skill_path}")
        
        print(f"\nRemoval complete!")
        return True

    def cmd_sync_local(config, expand_path, get_skills_from_dir, project_dir, skill_name=None):
        """Sync local/project skills to project IDE targets."""
        import shutil
        
        source_dir = project_dir / config.get("project_source_dir", ".ai-skills")
        exclude = config.get("exclude_skills", [])
        use_symlinks = config.get("sync", {}).get("use_symlinks", False)
        
        if not source_dir.exists():
            print(f"[LOCAL] Source not found: {source_dir}")
            print(f"Create with: mkdir -p {source_dir}")
            return
        
        if skill_name:
            skills = [skill_name]
        else:
            skills = get_skills_from_dir(source_dir, exclude)
        
        if not skills:
            print(f"[LOCAL] No skills found in {source_dir}")
            return
        
        print(f"[LOCAL] Project: {project_dir}")
        print(f"[LOCAL] Source: {source_dir}")
        print(f"[LOCAL] Syncing {len(skills)} skill(s)...\n")
        
        for ide_name in config.get("enabled_ides", []):
            target_path = config.get("project_targets", {}).get(ide_name)
            if not target_path:
                continue
            
            target_dir = project_dir / target_path
            print(f"  [{ide_name.upper()}] {target_dir}")
            
            target_dir.mkdir(parents=True, exist_ok=True)
            
            for skill in skills:
                source = source_dir / skill
                target = target_dir / skill
                
                if not source.exists():
                    print(f"    [FAIL] {skill} (not found)")
                    continue
                
                if target.exists() or target.is_symlink():
                    if target.is_symlink():
                        target.unlink()
                    elif target.is_dir():
                        shutil.rmtree(target)
                
                if use_symlinks:
                    try:
                        target.symlink_to(source.resolve())
                        print(f"    [OK] {skill} (symlink)")
                    except OSError:
                        shutil.copytree(source, target)
                        print(f"    [OK] {skill} (copy)")
                else:
                    shutil.copytree(source, target)
                    print(f"    [OK] {skill} (copy)")
        
        print("\n[LOCAL] Sync complete!")

    def _load_upstream_module(scripts_dir, exec_globals):
        """加载 upstream 模块到 exec_globals 命名空间。"""
        # 加载 git_ops 模块
        git_ops_code = open(os.path.join(scripts_dir, "git_ops.py")).read()
        git_ops_code = git_ops_code.replace('from .utils import', '# from .utils import')
        exec(git_ops_code, exec_globals)

        # 加载 upstream 模块
        upstream_code = open(os.path.join(scripts_dir, "upstream.py")).read()
        upstream_code = upstream_code.replace('from .utils import', '# from .utils import')
        upstream_code = upstream_code.replace('from .git_ops import', '# from .git_ops import')
        upstream_code = upstream_code.replace('from .sync import', '# from .sync import')
        exec(upstream_code, exec_globals)

    def cmd_upstream_menu(scripts_dir, exec_globals, config):
        """上游源管理交互式菜单。"""
        print()
        print("=== Upstream Management ===")
        print("1. Add upstream source")
        print("2. Update upstream sources")
        print("3. Import skills from upstream")
        print("4. List available skills")
        print("5. Check status")
        print("6. Compare differences")
        print("0. Back")
        print()

        try:
            choice = input("Enter choice [0-6]: ").strip()
        except (KeyboardInterrupt, EOFError):
            print()
            return

        if choice == "0" or not choice:
            return

        # 按需加载 upstream 模块
        _load_upstream_module(scripts_dir, exec_globals)

        if choice == "1":
            url = input("Git repository URL: ").strip()
            if not url:
                return
            name = input("Source name (Enter for auto): ").strip() or None
            branch = input("Branch (Enter for main): ").strip() or "main"
            exec_globals['cmd_upstream_add'](url, name=name, branch=branch)
        elif choice == "2":
            name = input("Source name (Enter for all): ").strip() or None
            exec_globals['cmd_upstream_update'](name)
        elif choice == "3":
            source = input("Source name: ").strip()
            if not source:
                return
            skills_input = input("Skill names (space-separated): ").strip()
            if not skills_input:
                return
            skills_list = skills_input.split()
            force = input("Force overwrite? (y/N): ").strip().lower() == "y"
            adopt = input("Adopt existing? (y/N): ").strip().lower() == "y"
            exec_globals['cmd_upstream_import'](
                skills_list, source, force=force, adopt=adopt,
            )
        elif choice == "4":
            source = input("Source name (Enter for all): ").strip() or None
            exec_globals['cmd_upstream_list'](source)
        elif choice == "5":
            exec_globals['cmd_upstream_status']()
        elif choice == "6":
            skill = input("Skill name: ").strip()
            if skill:
                exec_globals['cmd_upstream_diff'](skill)
        else:
            print("Invalid choice.")

    # Parse arguments
    parser = argparse.ArgumentParser(
        description="Unified skill management for AI IDEs",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    
    parser.add_argument("--json", action="store_true", help="Output as JSON")
    parser.add_argument("--version", action="version", version="skill-manager 1.0.0")
    
    subparsers = parser.add_subparsers(dest="command", help="Command")
    
    # list
    list_parser = subparsers.add_parser("list", help="List installed skills")
    list_parser.add_argument("-g", "--global", dest="global_scope", action="store_true")
    list_parser.add_argument("-l", "--local", dest="local_scope", action="store_true")
    
    # search
    search_parser = subparsers.add_parser("search", help="Search community skills")
    search_parser.add_argument("query", help="Search query")
    
    # install
    install_parser = subparsers.add_parser("install", help="Install a skill")
    install_parser.add_argument("url", help="GitHub URL")
    install_parser.add_argument("-g", "--global", dest="global_scope", action="store_true",
                                help="Install to global scope (~/.ai-skills)")
    install_parser.add_argument("-l", "--local", dest="local_scope", action="store_true",
                                help="Install to project scope (.ai-skills)")
    
    # create
    create_parser = subparsers.add_parser("create", help="Create a new skill")
    create_parser.add_argument("name", help="Skill name")
    create_parser.add_argument("--resources", help="Resource dirs")
    
    # sync
    sync_parser = subparsers.add_parser("sync", help="Sync skills to IDEs")
    sync_parser.add_argument("skill", nargs="?", help="Specific skill")
    sync_parser.add_argument("-l", "--local", dest="local_scope", action="store_true", help="Sync local/project skills")
    sync_parser.add_argument("--project-dir", type=Path, default=None, help="Project directory")
    
    # validate
    validate_parser = subparsers.add_parser("validate", help="Validate skills")
    validate_parser.add_argument("skill", nargs="?", help="Specific skill")
    
    # status
    status_parser = subparsers.add_parser("status", help="Check status")
    
    # export
    export_parser = subparsers.add_parser("export", help="Export profile")
    
    # import
    import_parser = subparsers.add_parser("import", help="Import profile")
    import_parser.add_argument("source", help="Profile file path")
    
    # remove
    remove_parser = subparsers.add_parser("remove", help="Remove a skill")
    remove_parser.add_argument("skill", help="Skill name")
    remove_parser.add_argument("-f", "--force", action="store_true", help="Force remove")
    
    # verify
    verify_parser = subparsers.add_parser("verify", help="Verify sync")
    
    # init (for local projects)
    init_parser = subparsers.add_parser("init", help="Initialize local skills")
    init_parser.add_argument("--project-dir", type=Path, default=None)

    # upstream
    upstream_parser = subparsers.add_parser("upstream", help="Manage upstream sources")
    upstream_sub = upstream_parser.add_subparsers(dest="upstream_command", help="Upstream command")

    # upstream add
    up_add = upstream_sub.add_parser("add", help="Add upstream source")
    up_add.add_argument("url", help="Git repository URL")
    up_add.add_argument("--name", help="Source name (default: derived from URL)")
    up_add.add_argument("--branch", default="main", help="Branch (default: main)")

    # upstream update
    up_update = upstream_sub.add_parser("update", help="Update upstream sources")
    up_update.add_argument("name", nargs="?", help="Source name (default: all)")

    # upstream import
    up_import = upstream_sub.add_parser("import", help="Import skills from upstream")
    up_import.add_argument("skills", nargs="+", help="Skill names to import")
    up_import.add_argument("--from", dest="source", required=True, help="Source name")
    up_import.add_argument("--force", action="store_true", help="Force overwrite")
    up_import.add_argument("--adopt", action="store_true", help="Adopt existing skills")

    # upstream list
    up_list = upstream_sub.add_parser("list", help="List available upstream skills")
    up_list.add_argument("source", nargs="?", help="Source name")

    # upstream status
    upstream_sub.add_parser("status", help="Show upstream status")

    # upstream diff
    up_diff = upstream_sub.add_parser("diff", help="Compare local vs upstream")
    up_diff.add_argument("skill", help="Skill name")
    
    args = parser.parse_args()
    config = load_config()
    
    if not args.command:
        show_interactive_menu()
    elif args.command == "list":
        cmd_list(config, expand_path, get_skills_from_dir, get_skill_description, 
                json_output=args.json)
    elif args.command == "search":
        cmd_search(args.query, scripts_dir)
    elif args.command == "install":
        # Determine scope: explicit flags > default_scope config
        default_scope = config.get("sync", {}).get("default_scope", "global")
        local_scope = getattr(args, "local_scope", False)
        global_scope = getattr(args, "global_scope", False)

        # If no explicit flag, use default_scope from config
        if not local_scope and not global_scope:
            local_scope = (default_scope == "project")

        if local_scope:
            project_dir = find_project_root(Path.cwd()) or Path.cwd()
            dest_dir = project_dir / config.get("project_source_dir", ".ai-skills")
            dest_dir.mkdir(parents=True, exist_ok=True)
            cmd_install(args.url, config, expand_path, scripts_dir,
                       dest_override=dest_dir, scope="local", project_dir=project_dir)
        else:
            cmd_install(args.url, config, expand_path, scripts_dir, scope="global")
    elif args.command == "create":
        cmd_create(args.name, config, expand_path, scripts_dir)
    elif args.command == "sync":
        skill = getattr(args, "skill", None)
        local = getattr(args, "local_scope", False)
        if local:
            project_dir = getattr(args, "project_dir", None) or find_project_root(Path.cwd()) or Path.cwd()
            cmd_sync_local(config, expand_path, get_skills_from_dir, project_dir, skill)
        else:
            cmd_sync(config, expand_path, get_skills_from_dir, scripts_dir, skill)
    elif args.command == "validate" or args.command == "verify":
        cmd_validate(config, expand_path, get_skills_from_dir, scripts_dir,
                    getattr(args, "skill", None))
    elif args.command == "status":
        cmd_status(config, expand_path, get_skills_from_dir)
    elif args.command == "export":
        cmd_export(config, expand_path, get_skills_from_dir, scripts_dir)
    elif args.command == "import":
        cmd_import_profile(args.source, config, expand_path, get_skills_from_dir, scripts_dir)
    elif args.command == "remove":
        cmd_remove(args.skill, config, expand_path, get_skills_from_dir, scripts_dir, 
                  getattr(args, "force", False))
    elif args.command == "init":
        project_dir = getattr(args, "project_dir", None) or Path.cwd()
        local_source = project_dir / config.get("project_source_dir", ".ai-skills")
        if local_source.exists():
            print(f"Local skills directory already exists: {local_source}")
        else:
            local_source.mkdir(parents=True)
            print(f"Created local skills directory: {local_source}")
            print(f"\nNext steps:")
            print(f"  1. Add skills to {local_source}/<skill-name>/SKILL.md")
            print(f"  2. Run: skills sync --local")
    elif args.command == "upstream":
        # 加载上游管理模块
        _load_upstream_module(scripts_dir, exec_globals)

        uc = getattr(args, "upstream_command", None)
        if uc == "add":
            exec_globals['cmd_upstream_add'](args.url, name=args.name, branch=args.branch)
        elif uc == "update":
            exec_globals['cmd_upstream_update'](args.name)
        elif uc == "import":
            exec_globals['cmd_upstream_import'](
                args.skills, args.source,
                force=args.force, adopt=args.adopt,
            )
        elif uc == "list":
            exec_globals['cmd_upstream_list'](args.source)
        elif uc == "status":
            exec_globals['cmd_upstream_status']()
        elif uc == "diff":
            exec_globals['cmd_upstream_diff'](args.skill)
        else:
            print("Usage: skills upstream {add|update|import|list|status|diff}")


if __name__ == "__main__":
    main()
