mirror of
https://github.com/SuperClaude-Org/SuperClaude_Framework.git
synced 2025-12-29 16:16:08 +00:00
Implement dynamic file discovery for components (PR #133)
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 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,5 @@
|
|||||||
# COMMANDS.md - SuperClaude Command Execution Framework
|
# 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 execution framework for Claude Code SuperClaude integration.
|
||||||
|
|
||||||
## Command System Architecture
|
## Command System Architecture
|
||||||
|
|||||||
@@ -531,8 +531,3 @@ orchestrator_config:
|
|||||||
|
|
||||||
### Custom Routing Rules
|
### Custom Routing Rules
|
||||||
Users can add custom routing patterns via YAML configuration files.
|
Users can add custom routing patterns via YAML configuration files.
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,25 +22,8 @@ class CommandsComponent(Component):
|
|||||||
self.file_manager = FileManager()
|
self.file_manager = FileManager()
|
||||||
self.settings_manager = SettingsManager(self.install_dir)
|
self.settings_manager = SettingsManager(self.install_dir)
|
||||||
|
|
||||||
# Define command files to install
|
# Dynamically discover command files to install
|
||||||
self.command_files = [
|
self.command_files = self._discover_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"
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_metadata(self) -> Dict[str, str]:
|
def get_metadata(self) -> Dict[str, str]:
|
||||||
"""Get component metadata"""
|
"""Get component metadata"""
|
||||||
@@ -343,6 +326,68 @@ class CommandsComponent(Component):
|
|||||||
|
|
||||||
return len(errors) == 0, errors
|
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:
|
def _get_source_dir(self) -> Path:
|
||||||
"""Get source directory for command files"""
|
"""Get source directory for command files"""
|
||||||
# Assume we're in SuperClaude/setup/components/commands.py
|
# Assume we're in SuperClaude/setup/components/commands.py
|
||||||
|
|||||||
@@ -24,18 +24,8 @@ class CoreComponent(Component):
|
|||||||
self.file_manager = FileManager()
|
self.file_manager = FileManager()
|
||||||
self.settings_manager = SettingsManager(self.install_dir)
|
self.settings_manager = SettingsManager(self.install_dir)
|
||||||
|
|
||||||
# Define framework files to install
|
# Dynamically discover framework files to install
|
||||||
self.framework_files = [
|
self.framework_files = self._discover_framework_files()
|
||||||
"CLAUDE.md",
|
|
||||||
"COMMANDS.md",
|
|
||||||
"FLAGS.md",
|
|
||||||
"PRINCIPLES.md",
|
|
||||||
"RULES.md",
|
|
||||||
"MCP.md",
|
|
||||||
"PERSONAS.md",
|
|
||||||
"ORCHESTRATOR.md",
|
|
||||||
"MODES.md"
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_metadata(self) -> Dict[str, str]:
|
def get_metadata(self) -> Dict[str, str]:
|
||||||
"""Get component metadata"""
|
"""Get component metadata"""
|
||||||
@@ -323,6 +313,68 @@ class CoreComponent(Component):
|
|||||||
|
|
||||||
return len(errors) == 0, errors
|
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:
|
def _get_source_dir(self) -> Path:
|
||||||
"""Get source directory for framework files"""
|
"""Get source directory for framework files"""
|
||||||
# Assume we're in SuperClaude/setup/components/core.py
|
# Assume we're in SuperClaude/setup/components/core.py
|
||||||
|
|||||||
Reference in New Issue
Block a user