diff --git a/config/features.json b/config/features.json index e22c69a..e9d9197 100644 --- a/config/features.json +++ b/config/features.json @@ -36,6 +36,15 @@ "enabled": true, "required_tools": ["uvx", "python3", "claude_cli"] }, + "agents": { + "name": "agents", + "version": "4.0.0", + "description": "13 specialized AI agents with domain expertise and intelligent routing", + "category": "agents", + "dependencies": ["core"], + "enabled": true, + "required_tools": [] + }, "hooks": { "name": "hooks", "version": "2.0.0", diff --git a/profiles/developer.json b/profiles/developer.json index 457aa73..0f0bc49 100644 --- a/profiles/developer.json +++ b/profiles/developer.json @@ -4,6 +4,7 @@ "components": [ "core", "commands", + "agents", "mcp" ], "features": { diff --git a/profiles/quick.json b/profiles/quick.json index 82a32f7..d38fc64 100644 --- a/profiles/quick.json +++ b/profiles/quick.json @@ -3,7 +3,8 @@ "description": "Recommended installation with core framework and essential components", "components": [ "core", - "commands" + "commands", + "agents" ], "features": { "auto_update": false, diff --git a/setup/components/__init__.py b/setup/components/__init__.py index 0b9a23f..cb0cac4 100644 --- a/setup/components/__init__.py +++ b/setup/components/__init__.py @@ -3,11 +3,13 @@ from .core import CoreComponent from .commands import CommandsComponent from .mcp import MCPComponent +from .agents import AgentsComponent # from .hooks import HooksComponent # Commented out - not yet implemented __all__ = [ 'CoreComponent', 'CommandsComponent', 'MCPComponent', + 'AgentsComponent', # 'HooksComponent' # Commented out - not yet implemented ] \ No newline at end of file diff --git a/setup/components/agents.py b/setup/components/agents.py new file mode 100644 index 0000000..c7ee7d7 --- /dev/null +++ b/setup/components/agents.py @@ -0,0 +1,239 @@ +""" +Agents component for SuperClaude specialized AI agents installation +""" + +from typing import Dict, List, Tuple, Optional, Any +from pathlib import Path + +from ..base.component import Component + + +class AgentsComponent(Component): + """SuperClaude specialized AI agents component""" + + def __init__(self, install_dir: Optional[Path] = None): + """Initialize agents component""" + super().__init__(install_dir, Path("agents")) + + def get_metadata(self) -> Dict[str, str]: + """Get component metadata""" + return { + "name": "agents", + "version": "4.0.0", + "description": "13 specialized AI agents with domain expertise and intelligent routing", + "category": "agents" + } + + def get_metadata_modifications(self) -> Dict[str, Any]: + """Get metadata modifications for agents""" + return { + "components": { + "agents": { + "version": "4.0.0", + "installed": True, + "agents_count": len(self.component_files), + "install_directory": str(self.install_component_subdir) + } + } + } + + def _install(self, config: Dict[str, Any]) -> bool: + """Install agents component""" + self.logger.info("Installing SuperClaude specialized agents...") + + # Call parent install method + success = super()._install(config) + + if success: + # Run post-install setup + success = self._post_install() + + if success: + self.logger.success(f"Successfully installed {len(self.component_files)} specialized agents") + + return success + + def _post_install(self) -> bool: + """Post-install setup for agents""" + try: + # Update metadata with agents registration + metadata_mods = self.get_metadata_modifications() + self.settings_manager.update_metadata(metadata_mods) + self.logger.info("Updated metadata with agents configuration") + + # Add component registration + self.settings_manager.add_component_registration("agents", { + "version": "4.0.0", + "category": "agents", + "agents_count": len(self.component_files), + "agents_list": self.component_files + }) + + self.logger.info("Registered agents component in metadata") + return True + + except Exception as e: + self.logger.error(f"Failed to complete agents post-install: {e}") + return False + + def uninstall(self) -> bool: + """Uninstall agents component""" + try: + self.logger.info("Uninstalling SuperClaude agents component...") + + # Remove agent files + removed_count = 0 + for filename in self.component_files: + file_path = self.install_component_subdir / filename + if self.file_manager.remove_file(file_path): + removed_count += 1 + self.logger.debug(f"Removed agent: {filename}") + else: + self.logger.warning(f"Could not remove agent: {filename}") + + # Remove agents directory if empty + try: + if self.install_component_subdir.exists() and not any(self.install_component_subdir.iterdir()): + self.install_component_subdir.rmdir() + self.logger.debug("Removed empty agents directory") + except Exception as e: + self.logger.warning(f"Could not remove agents directory: {e}") + + # Update metadata to remove agents component + try: + if self.settings_manager.is_component_installed("agents"): + self.settings_manager.remove_component_registration("agents") + self.logger.info("Removed agents component from metadata") + except Exception as e: + self.logger.warning(f"Could not update metadata: {e}") + + self.logger.success(f"Agents component uninstalled ({removed_count} agents removed)") + return True + + except Exception as e: + self.logger.exception(f"Unexpected error during agents uninstallation: {e}") + return False + + def get_dependencies(self) -> List[str]: + """Get component dependencies""" + return ["core"] + + def update(self, config: Dict[str, Any]) -> bool: + """Update agents component""" + try: + self.logger.info("Updating SuperClaude agents component...") + + # Check current version + current_version = self.settings_manager.get_component_version("agents") + target_version = self.get_metadata()["version"] + + if current_version == target_version: + self.logger.info(f"Agents component already at version {target_version}") + return True + + self.logger.info(f"Updating agents component from {current_version} to {target_version}") + + # Create backup of existing agents + backup_files = [] + for filename in self.component_files: + file_path = self.install_component_subdir / filename + if file_path.exists(): + backup_path = self.file_manager.backup_file(file_path) + if backup_path: + backup_files.append(backup_path) + self.logger.debug(f"Backed up agent: {filename}") + + # Perform installation (will overwrite existing files) + if self._install(config): + self.logger.success(f"Agents component updated to version {target_version}") + return True + else: + # Restore backups on failure + self.logger.error("Agents update failed, restoring backups...") + for backup_path in backup_files: + try: + original_path = self.install_component_subdir / backup_path.name.replace('.backup', '') + self.file_manager.copy_file(backup_path, original_path) + self.logger.debug(f"Restored {original_path.name}") + except Exception as e: + self.logger.warning(f"Could not restore {backup_path}: {e}") + return False + + except Exception as e: + self.logger.exception(f"Unexpected error during agents update: {e}") + return False + + def _get_source_dir(self) -> Path: + """Get source directory for agent files""" + # Assume we're in SuperClaude/setup/components/agents.py + # and agent files are in SuperClaude/SuperClaude/Agents/ + project_root = Path(__file__).parent.parent.parent + return project_root / "SuperClaude" / "Agents" + + def get_size_estimate(self) -> int: + """Get estimated installation size""" + total_size = 0 + source_dir = self._get_source_dir() + + for filename in self.component_files: + file_path = source_dir / filename + if file_path.exists(): + total_size += file_path.stat().st_size + + # Add overhead for directories and metadata + total_size += 5120 # ~5KB overhead + + return total_size + + def get_installation_summary(self) -> Dict[str, Any]: + """Get installation summary""" + return { + "component": self.get_metadata()["name"], + "version": self.get_metadata()["version"], + "agents_installed": len(self.component_files), + "agent_files": self.component_files, + "estimated_size": self.get_size_estimate(), + "install_directory": str(self.install_component_subdir), + "dependencies": self.get_dependencies() + } + + def validate_installation(self) -> Tuple[bool, List[str]]: + """Validate that agents component is correctly installed""" + errors = [] + + # Check if agents directory exists + if not self.install_component_subdir.exists(): + errors.append(f"Agents directory not found: {self.install_component_subdir}") + return False, errors + + # Check if all agent files exist + missing_agents = [] + for filename in self.component_files: + agent_path = self.install_component_subdir / filename + if not agent_path.exists(): + missing_agents.append(filename) + + if missing_agents: + errors.append(f"Missing agent files: {missing_agents}") + + # Check version in settings + if not self.get_installed_version(): + errors.append("Agents component not registered in metadata") + + # Check if at least some standard agents are present + expected_agents = [ + "system-architect.md", + "frontend-specialist.md", + "backend-engineer.md", + "security-auditor.md" + ] + + missing_core_agents = [] + for agent in expected_agents: + if agent not in self.component_files: + missing_core_agents.append(agent) + + if missing_core_agents: + errors.append(f"Missing core agent files: {missing_core_agents}") + + return len(errors) == 0, errors \ No newline at end of file diff --git a/setup/operations/install.py b/setup/operations/install.py index 02928e9..a147656 100644 --- a/setup/operations/install.py +++ b/setup/operations/install.py @@ -138,7 +138,7 @@ def get_components_to_install(args: argparse.Namespace, registry: ComponentRegis # Explicit components specified if args.components: if 'all' in args.components: - return ["core", "commands", "mcp"] # hooks removed - not yet implemented + return ["core", "commands", "agents", "mcp"] # hooks removed - not yet implemented return args.components # Profile-based selection