#!/usr/bin/env python3 """ Plugin CLI Integration - Command handlers for plugin marketplace operations Provides CLI commands for: - luzia plugins list - luzia plugins - luzia plugins skills - luzia plugins find - luzia plugins export """ import json import sys from pathlib import Path from typing import Dict, Any, Optional, List from plugin_marketplace import get_marketplace_registry from plugin_skill_loader import get_plugin_skill_loader from dispatcher_plugin_integration import get_dispatcher_bridge from plugin_kg_integration import export_plugins_to_kg class PluginCLI: """CLI handler for plugin marketplace operations""" def __init__(self): self.registry = get_marketplace_registry() self.skill_loader = get_plugin_skill_loader() self.bridge = get_dispatcher_bridge(self.registry) def handle_plugins_command(self, args: List[str]) -> int: """ Handle: luzia plugins [args...] Subcommands: - list: List all available plugins - : Show plugin details - skills: List all plugin skills - find : Find plugins for a task - export: Export all plugin data - stats: Show statistics """ if not args: return self.show_plugins_help() subcommand = args[0] if subcommand == "list": return self.cmd_list_plugins(args[1:]) elif subcommand == "skills": return self.cmd_list_skills(args[1:]) elif subcommand == "find": return self.cmd_find_plugins(args[1:]) elif subcommand == "export": return self.cmd_export_plugins(args[1:]) elif subcommand == "stats": return self.cmd_show_stats(args[1:]) elif subcommand == "help": return self.show_plugins_help() else: # Try as plugin name for details return self.cmd_show_plugin(subcommand) def show_plugins_help(self) -> int: """Show plugin CLI help""" help_text = """ Plugin Marketplace Commands: luzia plugins list List all plugins luzia plugins Show plugin details luzia plugins skills List all plugin skills luzia plugins find "" Find plugins for a task luzia plugins export Export plugin data to files luzia plugins stats Show statistics luzia plugins help Show this help Examples: luzia plugins list luzia plugins code-simplifier luzia plugins find "review code for security" luzia plugins export """ print(help_text) return 0 def cmd_list_plugins(self, args: List[str]) -> int: """Handle: luzia plugins list""" plugins = self.registry.list_plugins() if not plugins: print("No plugins available") return 0 print(f"\n{'Name':<30} {'Vendor':<15} {'Trust':<10} {'Capabilities'}") print("-" * 75) for plugin in plugins: cap_count = len(plugin.capabilities) print(f"{plugin.name:<30} {plugin.vendor:<15} {plugin.trust_level:<10} {cap_count}") print(f"\nTotal: {len(plugins)} plugins\n") return 0 def cmd_show_plugin(self, plugin_id: str) -> int: """Show plugin details""" plugin = self.registry.get_plugin(plugin_id) if not plugin: # Try to find by name plugins = self.registry.list_plugins() for p in plugins: if p.name.lower() == plugin_id.lower() or p.id.lower() == plugin_id.lower(): plugin = p break if not plugin: print(f"Plugin not found: {plugin_id}") return 1 output = { 'id': plugin.id, 'name': plugin.name, 'description': plugin.description, 'vendor': plugin.vendor, 'version': plugin.version, 'url': plugin.url, 'trust_level': plugin.trust_level, 'capabilities': [ { 'name': c.name, 'description': c.description, 'category': c.category, 'tags': c.tags } for c in plugin.capabilities ] } print(json.dumps(output, indent=2)) return 0 def cmd_list_skills(self, args: List[str]) -> int: """Handle: luzia plugins skills""" if not self.skill_loader.skills: self.skill_loader.generate_skills_from_plugins() skills = self.skill_loader.list_skills() if not skills: print("No skills available") return 0 print(f"\n{'Skill ID':<40} {'Category':<20} {'Trust':<10}") print("-" * 75) for skill in skills: print(f"{skill.skill_id:<40} {skill.category:<20} {skill.trust_level:<10}") print(f"\nTotal: {len(skills)} skills\n") return 0 def cmd_find_plugins(self, args: List[str]) -> int: """Handle: luzia plugins find """ if not args: print("Usage: luzia plugins find ''") return 1 task = " ".join(args) matched_skills = self.skill_loader.find_skills_for_task(task, min_relevance=0.3) if not matched_skills: print(f"No matching skills found for: {task}\n") return 0 output = { 'query': task, 'matched_skills': matched_skills, 'count': len(matched_skills) } print(json.dumps(output, indent=2)) return 0 def cmd_export_plugins(self, args: List[str]) -> int: """Handle: luzia plugins export""" output_dir = None if args and args[0].startswith('--output='): output_dir = Path(args[0].split('=')[1]) saved_files = export_plugins_to_kg(export_dir=output_dir) output = { 'action': 'export_plugins', 'status': 'success', 'files': {k: str(v) for k, v in saved_files.items()}, 'count': len(saved_files) } print(json.dumps(output, indent=2)) return 0 def cmd_show_stats(self, args: List[str]) -> int: """Handle: luzia plugins stats""" if not self.skill_loader.skills: self.skill_loader.generate_skills_from_plugins() stats = { 'total_plugins': len(self.registry.plugins), 'total_skills': len(self.skill_loader.skills), 'categories': list(self.skill_loader.category_index.keys()), 'category_counts': { cat: len(skill_ids) for cat, skill_ids in self.skill_loader.category_index.items() }, 'keywords': len(self.skill_loader.skill_index), 'trust_distribution': self._get_trust_distribution() } print(json.dumps(stats, indent=2)) return 0 def _get_trust_distribution(self) -> Dict[str, int]: """Get trust level distribution""" distribution: Dict[str, int] = {} for plugin in self.registry.list_plugins(): trust = plugin.trust_level distribution[trust] = distribution.get(trust, 0) + 1 return distribution def cmd_dispatch_with_plugins(self, task: str, project: str = "test", job_id: str = "job-test") -> Dict[str, Any]: """ Example: Dispatch a task with plugin context Returns dispatch result with plugin recommendations """ dispatch_result = self.bridge.dispatch_with_plugin_context(task, project, job_id) return dispatch_result # Integration functions for main CLI def match_plugins_command(args: list) -> Optional[list]: """Match 'luzia plugins' command""" if args and args[0] == "plugins": return args[1:] return None def route_plugins_command(config: dict, args: list, kwargs: dict) -> int: """Route to plugin CLI handler""" cli = PluginCLI() return cli.handle_plugins_command(args) # Convenience functions def get_plugin_cli() -> PluginCLI: """Get plugin CLI instance""" return PluginCLI()