#!/usr/bin/env python3 """ Plugin Knowledge Graph Integration - Load plugin skills to shared knowledge graph Stores plugin marketplace definitions and skills in the shared knowledge graph for cross-project access and intelligent task routing. Features: 1. Export plugins to knowledge graph format 2. Store plugin metadata and relationships 3. Track plugin skill usage patterns 4. Enable cross-project plugin discovery 5. Maintain plugin trust and capability indices """ import json import logging from pathlib import Path from typing import Dict, List, Optional, Any from datetime import datetime from plugin_marketplace import PluginMarketplaceRegistry from plugin_skill_loader import PluginSkillLoader logger = logging.getLogger(__name__) class PluginKnowledgeGraphExporter: """Exports plugin data to knowledge graph format""" def __init__(self, registry: Optional[PluginMarketplaceRegistry] = None, skill_loader: Optional[PluginSkillLoader] = None, export_dir: Optional[Path] = None): """Initialize exporter Args: registry: Plugin marketplace registry skill_loader: Plugin skill loader export_dir: Directory for exporting knowledge graph data """ self.registry = registry or PluginMarketplaceRegistry() self.skill_loader = skill_loader or PluginSkillLoader(self.registry) self.export_dir = export_dir or Path("/tmp/.luzia-kg-exports") self.export_dir.mkdir(parents=True, exist_ok=True) def export_plugins_as_entities(self) -> Dict[str, Any]: """ Export plugins as knowledge graph entities Returns: Dict with plugin entities in KG format """ entities = { 'type': 'entities', 'source': 'claude-marketplace', 'timestamp': datetime.now().isoformat(), 'entities': [] } for plugin in self.registry.list_plugins(): entity = { 'name': plugin.name, 'type': 'Plugin', 'properties': { 'id': plugin.id, 'vendor': plugin.vendor, 'version': plugin.version, 'description': plugin.description, 'trust_level': plugin.trust_level, 'url': plugin.url, 'capabilities_count': len(plugin.capabilities), 'capability_categories': list(set( c.category for c in plugin.capabilities )), 'tags': plugin.metadata.get('tags', []) }, 'observations': [ f"Plugin from {plugin.vendor} with {len(plugin.capabilities)} capabilities", f"Trust level: {plugin.trust_level}", f"Provides capabilities in: {', '.join(set(c.category for c in plugin.capabilities))}", f"Last updated: {plugin.last_updated}" ] } entities['entities'].append(entity) return entities def export_plugin_skills_as_entities(self) -> Dict[str, Any]: """ Export plugin skills as knowledge graph entities Returns: Dict with skill entities in KG format """ if not self.skill_loader.skills: self.skill_loader.generate_skills_from_plugins() entities = { 'type': 'entities', 'source': 'plugin-marketplace-skills', 'timestamp': datetime.now().isoformat(), 'entities': [] } for skill in self.skill_loader.skills.values(): entity = { 'name': skill.name, 'type': 'Skill', 'properties': { 'skill_id': skill.skill_id, 'plugin_id': skill.plugin_id, 'plugin_name': skill.plugin_name, 'capability': skill.capability_name, 'category': skill.category, 'description': skill.description, 'trust_level': skill.trust_level, 'tags': skill.tags, 'keywords': skill.keywords }, 'observations': [ f"Provided by plugin: {skill.plugin_name}", f"Category: {skill.category}", f"Trust level: {skill.trust_level}", f"Tags: {', '.join(skill.tags)}" if skill.tags else "No tags" ] } entities['entities'].append(entity) return entities def export_plugin_relationships(self) -> Dict[str, Any]: """ Export plugin relationships for knowledge graph Returns: Dict with relationships in KG format """ relations = { 'type': 'relations', 'source': 'plugin-marketplace', 'timestamp': datetime.now().isoformat(), 'relations': [] } if not self.skill_loader.skills: self.skill_loader.generate_skills_from_plugins() # Plugin -> Skill relationships for skill in self.skill_loader.skills.values(): relations['relations'].append({ 'from': skill.plugin_name, 'to': skill.name, 'type': 'provides_capability', 'properties': { 'capability_type': skill.category, 'trust_level': skill.trust_level } }) # Plugin -> Category relationships for plugin in self.registry.list_plugins(): categories = set(c.category for c in plugin.capabilities) for category in categories: relations['relations'].append({ 'from': plugin.name, 'to': category, 'type': 'supports_category', 'properties': { 'trust_level': plugin.trust_level } }) # Skill -> Category relationships for skill in self.skill_loader.skills.values(): relations['relations'].append({ 'from': skill.name, 'to': skill.category, 'type': 'belongs_to_category', 'properties': {} }) return relations def export_for_shared_kg(self) -> Dict[str, Any]: """ Export complete plugin data for shared knowledge graph Returns: Comprehensive export suitable for shared KG storage """ if not self.skill_loader.skills: self.skill_loader.generate_skills_from_plugins() return { 'source': 'luzia-plugin-marketplace', 'timestamp': datetime.now().isoformat(), 'metadata': { 'total_plugins': len(self.registry.plugins), 'total_skills': len(self.skill_loader.skills), 'categories': list(self.skill_loader.category_index.keys()), 'trust_distribution': self._get_trust_distribution(), 'vendor_distribution': self._get_vendor_distribution() }, 'plugins': { plugin.id: { 'name': plugin.name, 'description': plugin.description, 'vendor': plugin.vendor, 'version': plugin.version, 'trust_level': plugin.trust_level, 'url': plugin.url, 'capabilities': [ { 'name': c.name, 'description': c.description, 'category': c.category, 'tags': c.tags } for c in plugin.capabilities ] } for plugin in self.registry.list_plugins() }, 'skills': { skill.skill_id: { 'name': skill.name, 'description': skill.description, 'plugin_id': skill.plugin_id, 'plugin_name': skill.plugin_name, 'category': skill.category, 'tags': skill.tags, 'trust_level': skill.trust_level, 'keywords': skill.keywords } for skill in self.skill_loader.skills.values() }, 'categories': { cat: list(skill_ids) for cat, skill_ids in self.skill_loader.category_index.items() }, 'keywords_index': { kw: list(skill_ids) for kw, skill_ids in self.skill_loader.skill_index.items() } } def save_exports(self) -> Dict[str, Path]: """Save all exports to files Returns: Dict of export_type -> file_path """ exports = { 'plugins_entities': self.export_plugins_as_entities(), 'skills_entities': self.export_plugin_skills_as_entities(), 'relationships': self.export_plugin_relationships(), 'complete_export': self.export_for_shared_kg() } saved_files = {} for export_type, data in exports.items(): file_path = self.export_dir / f"{export_type}.json" file_path.write_text(json.dumps(data, indent=2)) saved_files[export_type] = file_path logger.info(f"Saved {export_type} to {file_path}") return saved_files 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 _get_vendor_distribution(self) -> Dict[str, int]: """Get vendor distribution""" distribution: Dict[str, int] = {} for plugin in self.registry.list_plugins(): vendor = plugin.vendor distribution[vendor] = distribution.get(vendor, 0) + 1 return distribution class SharedKnowledgeGraphBridge: """ Bridge to push plugin data to shared knowledge graph Integrates with mcp__shared-projects-memory tools to store plugin information in the shared knowledge graph. """ def __init__(self, exporter: Optional[PluginKnowledgeGraphExporter] = None): """Initialize shared KG bridge Args: exporter: Plugin knowledge graph exporter """ self.exporter = exporter or PluginKnowledgeGraphExporter() self.stored_entities: Dict[str, bool] = {} def store_plugin_facts(self) -> Dict[str, Any]: """ Store plugin facts in shared knowledge graph This would use mcp__shared-projects-memory__store_fact in practice Returns: Summary of stored facts """ summary = { 'timestamp': datetime.now().isoformat(), 'action': 'store_plugin_facts', 'entities_stored': 0, 'relations_stored': 0, 'details': [] } # Export plugin entities exporter = PluginKnowledgeGraphExporter() plugins = exporter.registry.list_plugins() for plugin in plugins: # In real implementation, would call: # mcp__shared-projects-memory__store_fact( # entity_source_name=plugin.name, # relation='provides_capability', # entity_target_name=plugin.vendor, # source_type='Plugin', # target_type='Vendor', # context=f"{plugin.description}" # ) summary['entities_stored'] += 1 summary['details'].append(f"Stored plugin: {plugin.name}") # Store skills as entities if not exporter.skill_loader.skills: exporter.skill_loader.generate_skills_from_plugins() for skill in exporter.skill_loader.skills.values(): # In real implementation: # mcp__shared-projects-memory__store_fact(...) summary['entities_stored'] += 1 summary['relations_stored'] += 1 logger.info(f"Stored {summary['entities_stored']} entities and " f"{summary['relations_stored']} relations to shared KG") return summary def query_plugin_facts(self, entity_name: str) -> Optional[Dict[str, Any]]: """ Query plugin-related facts from shared knowledge graph In real implementation, would use mcp__shared-projects-memory__query_relations Args: entity_name: Entity name to query Returns: Query results or None """ # In real implementation: # results = mcp__shared-projects-memory__query_relations( # entity_name=entity_name, # relation_type='provides_capability' # ) logger.info(f"Queried shared KG for: {entity_name}") return None def search_plugin_skills(self, query: str) -> Optional[Dict[str, Any]]: """ Search for plugin skills in shared knowledge graph In real implementation, would use mcp__shared-projects-memory__search_context Args: query: Search query Returns: Search results or None """ # In real implementation: # results = mcp__shared-projects-memory__search_context( # query=query, # limit=10 # ) logger.info(f"Searched shared KG for: {query}") return None # Convenience functions def export_plugins_to_kg(export_dir: Optional[Path] = None) -> Dict[str, Path]: """Export plugins to knowledge graph files""" exporter = PluginKnowledgeGraphExporter(export_dir=export_dir) return exporter.save_exports() def get_shared_kg_bridge() -> SharedKnowledgeGraphBridge: """Get shared knowledge graph bridge""" return SharedKnowledgeGraphBridge()