From a0def375e131024be82e7f3baa701d89a93a5932 Mon Sep 17 00:00:00 2001 From: NomenAK Date: Tue, 15 Jul 2025 11:16:58 +0200 Subject: [PATCH] Implement dynamic file discovery for components (PR #133) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace hardcoded file arrays with dynamic discovery system: - CoreComponent: Auto-discovers framework .md files in Core directory - CommandsComponent: Auto-discovers command .md files in Commands directory - Eliminates manual maintenance of file lists - Maintains backward compatibility and error handling - Adds comprehensive logging and validation Key changes: - Added _discover_framework_files() and _discover_command_files() methods - Added shared _discover_files_in_directory() utility - Replaced hardcoded arrays with dynamic discovery calls - Includes filtering, sorting, and error handling - Validates 9 framework files and 16 command files correctly - Clean up documentation formatting Resolves maintenance burden described in PR #133 while preserving all existing functionality and security validation. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- SuperClaude/Core/COMMANDS.md | 6 --- SuperClaude/Core/ORCHESTRATOR.md | 5 -- setup/components/commands.py | 83 ++++++++++++++++++++++++-------- setup/components/core.py | 76 ++++++++++++++++++++++++----- 4 files changed, 128 insertions(+), 42 deletions(-) diff --git a/SuperClaude/Core/COMMANDS.md b/SuperClaude/Core/COMMANDS.md index a053d00..3d9e7c6 100644 --- a/SuperClaude/Core/COMMANDS.md +++ b/SuperClaude/Core/COMMANDS.md @@ -1,11 +1,5 @@ # COMMANDS.md - SuperClaude Command Execution Framework ---- -framework: "SuperClaude v3.0" -execution-engine: "Claude Code" -wave-compatibility: "Full" ---- - Command execution framework for Claude Code SuperClaude integration. ## Command System Architecture diff --git a/SuperClaude/Core/ORCHESTRATOR.md b/SuperClaude/Core/ORCHESTRATOR.md index be58847..96b6931 100644 --- a/SuperClaude/Core/ORCHESTRATOR.md +++ b/SuperClaude/Core/ORCHESTRATOR.md @@ -531,8 +531,3 @@ orchestrator_config: ### Custom Routing Rules Users can add custom routing patterns via YAML configuration files. - - ---- - - diff --git a/setup/components/commands.py b/setup/components/commands.py index 82532bb..59de6e2 100644 --- a/setup/components/commands.py +++ b/setup/components/commands.py @@ -22,25 +22,8 @@ class CommandsComponent(Component): self.file_manager = FileManager() self.settings_manager = SettingsManager(self.install_dir) - # Define command files to install - self.command_files = [ - "analyze.md", - "build.md", - "implement.md", - "cleanup.md", - "design.md", - "document.md", - "estimate.md", - "explain.md", - "git.md", - "improve.md", - "index.md", - "load.md", - "spawn.md", - "task.md", - "test.md", - "troubleshoot.md" - ] + # Dynamically discover command files to install + self.command_files = self._discover_command_files() def get_metadata(self) -> Dict[str, str]: """Get component metadata""" @@ -343,6 +326,68 @@ class CommandsComponent(Component): return len(errors) == 0, errors + def _discover_command_files(self) -> List[str]: + """ + Dynamically discover command .md files in the Commands directory + + Returns: + List of command filenames (e.g., ['analyze.md', 'build.md', ...]) + """ + return self._discover_files_in_directory( + self._get_source_dir(), + extension='.md', + exclude_patterns=['README.md', 'CHANGELOG.md', 'LICENSE.md'] + ) + + def _discover_files_in_directory(self, directory: Path, extension: str = '.md', + exclude_patterns: List[str] = None) -> List[str]: + """ + Shared utility for discovering files in a directory + + Args: + directory: Directory to scan + extension: File extension to look for (default: '.md') + exclude_patterns: List of filename patterns to exclude + + Returns: + List of filenames found in the directory + """ + if exclude_patterns is None: + exclude_patterns = [] + + try: + if not directory.exists(): + self.logger.warning(f"Source directory not found: {directory}") + return [] + + if not directory.is_dir(): + self.logger.warning(f"Source path is not a directory: {directory}") + return [] + + # Discover files with the specified extension + files = [] + for file_path in directory.iterdir(): + if (file_path.is_file() and + file_path.suffix.lower() == extension.lower() and + file_path.name not in exclude_patterns): + files.append(file_path.name) + + # Sort for consistent ordering + files.sort() + + self.logger.debug(f"Discovered {len(files)} {extension} files in {directory}") + if files: + self.logger.debug(f"Files found: {files}") + + return files + + except PermissionError: + self.logger.error(f"Permission denied accessing directory: {directory}") + return [] + except Exception as e: + self.logger.error(f"Error discovering files in {directory}: {e}") + return [] + def _get_source_dir(self) -> Path: """Get source directory for command files""" # Assume we're in SuperClaude/setup/components/commands.py diff --git a/setup/components/core.py b/setup/components/core.py index 9a0081e..b2b7994 100644 --- a/setup/components/core.py +++ b/setup/components/core.py @@ -24,18 +24,8 @@ class CoreComponent(Component): self.file_manager = FileManager() self.settings_manager = SettingsManager(self.install_dir) - # Define framework files to install - self.framework_files = [ - "CLAUDE.md", - "COMMANDS.md", - "FLAGS.md", - "PRINCIPLES.md", - "RULES.md", - "MCP.md", - "PERSONAS.md", - "ORCHESTRATOR.md", - "MODES.md" - ] + # Dynamically discover framework files to install + self.framework_files = self._discover_framework_files() def get_metadata(self) -> Dict[str, str]: """Get component metadata""" @@ -323,6 +313,68 @@ class CoreComponent(Component): return len(errors) == 0, errors + def _discover_framework_files(self) -> List[str]: + """ + Dynamically discover framework .md files in the Core directory + + Returns: + List of framework filenames (e.g., ['CLAUDE.md', 'COMMANDS.md', ...]) + """ + return self._discover_files_in_directory( + self._get_source_dir(), + extension='.md', + exclude_patterns=['README.md', 'CHANGELOG.md', 'LICENSE.md'] + ) + + def _discover_files_in_directory(self, directory: Path, extension: str = '.md', + exclude_patterns: List[str] = None) -> List[str]: + """ + Shared utility for discovering files in a directory + + Args: + directory: Directory to scan + extension: File extension to look for (default: '.md') + exclude_patterns: List of filename patterns to exclude + + Returns: + List of filenames found in the directory + """ + if exclude_patterns is None: + exclude_patterns = [] + + try: + if not directory.exists(): + self.logger.warning(f"Source directory not found: {directory}") + return [] + + if not directory.is_dir(): + self.logger.warning(f"Source path is not a directory: {directory}") + return [] + + # Discover files with the specified extension + files = [] + for file_path in directory.iterdir(): + if (file_path.is_file() and + file_path.suffix.lower() == extension.lower() and + file_path.name not in exclude_patterns): + files.append(file_path.name) + + # Sort for consistent ordering + files.sort() + + self.logger.debug(f"Discovered {len(files)} {extension} files in {directory}") + if files: + self.logger.debug(f"Files found: {files}") + + return files + + except PermissionError: + self.logger.error(f"Permission denied accessing directory: {directory}") + return [] + except Exception as e: + self.logger.error(f"Error discovering files in {directory}: {e}") + return [] + def _get_source_dir(self) -> Path: """Get source directory for framework files""" # Assume we're in SuperClaude/setup/components/core.py