mirror of
https://github.com/SuperClaude-Org/SuperClaude_Framework.git
synced 2025-12-29 16:16:08 +00:00
feat: add comprehensive test suite, CI/CD workflows, and install command
Major improvements to SuperClaude Framework infrastructure and testing: ## New Features - Add 'superclaude install' command to install slash commands (/research, /index-repo, /agent, /recommend) - Create comprehensive test suite with 71 tests (70 passing, 1 skipped) - Add GitHub Actions CI/CD workflows for automated testing - Add essential documentation files (PLANNING.md, TASK.md, KNOWLEDGE.md) ## Testing - tests/unit/: 59 tests covering PM Agent components - test_confidence.py: 13 tests for ConfidenceChecker - test_self_check.py: 14 tests for SelfCheckProtocol - test_reflexion.py: 9 tests for ReflexionPattern - test_token_budget.py: 12 tests for TokenBudgetManager - test_cli_install.py: 12 tests for install command (NEW) - tests/integration/: 11 tests for pytest plugin integration - tests/conftest.py: Shared fixtures for all tests ## CI/CD Workflows - .github/workflows/test.yml: Comprehensive test matrix - Tests on Python 3.10, 3.11, 3.12 - Lint and format checks with ruff - Pytest plugin verification - SuperClaude doctor health checks - Coverage reporting with Codecov - .github/workflows/quick-check.yml: Fast PR validation (~2-3 min) - .github/workflows/README.md: Workflow documentation ## Documentation - PLANNING.md: Architecture, design principles, absolute rules - TASK.md: Current tasks, priorities, backlog - KNOWLEDGE.md: Accumulated insights, best practices, troubleshooting ## Bug Fixes - Fix .gitignore contradictions (remove conflicting Claude Code patterns) - Fix TokenBudgetManager to properly validate and default invalid complexity - Update package.json version to 4.1.6 (sync with VERSION file) ## CLI Improvements - src/superclaude/cli/install_commands.py: Command installation logic - src/superclaude/cli/main.py: Add 'install' command with --list and --force options - README.md: Update installation instructions with correct commands ## Breaking Changes None - all changes are backwards compatible ## Migration Guide Users should run 'superclaude install' after upgrading to install slash commands Fixes #466 (indirectly by clarifying installation process) Refs #419 (plugin system - documentation updated) 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
163
src/superclaude/cli/install_commands.py
Normal file
163
src/superclaude/cli/install_commands.py
Normal file
@@ -0,0 +1,163 @@
|
||||
"""
|
||||
Command Installation
|
||||
|
||||
Installs SuperClaude slash commands to ~/.claude/commands/ directory.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple
|
||||
import shutil
|
||||
|
||||
|
||||
def install_commands(
|
||||
target_path: Path = None,
|
||||
force: bool = False
|
||||
) -> Tuple[bool, str]:
|
||||
"""
|
||||
Install all SuperClaude commands to Claude Code
|
||||
|
||||
Args:
|
||||
target_path: Target installation directory (default: ~/.claude/commands)
|
||||
force: Force reinstall if commands exist
|
||||
|
||||
Returns:
|
||||
Tuple of (success: bool, message: str)
|
||||
"""
|
||||
# Default to ~/.claude/commands
|
||||
if target_path is None:
|
||||
target_path = Path.home() / ".claude" / "commands"
|
||||
|
||||
# Get command source directory
|
||||
command_source = _get_commands_source()
|
||||
|
||||
if not command_source or not command_source.exists():
|
||||
return False, f"Command source directory not found: {command_source}"
|
||||
|
||||
# Create target directory
|
||||
target_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Get all command files
|
||||
command_files = list(command_source.glob("*.md"))
|
||||
|
||||
if not command_files:
|
||||
return False, f"No command files found in {command_source}"
|
||||
|
||||
installed_commands = []
|
||||
skipped_commands = []
|
||||
failed_commands = []
|
||||
|
||||
for command_file in command_files:
|
||||
target_file = target_path / command_file.name
|
||||
command_name = command_file.stem
|
||||
|
||||
# Check if already exists
|
||||
if target_file.exists() and not force:
|
||||
skipped_commands.append(command_name)
|
||||
continue
|
||||
|
||||
# Copy command file
|
||||
try:
|
||||
shutil.copy2(command_file, target_file)
|
||||
installed_commands.append(command_name)
|
||||
except Exception as e:
|
||||
failed_commands.append(f"{command_name}: {e}")
|
||||
|
||||
# Build result message
|
||||
messages = []
|
||||
|
||||
if installed_commands:
|
||||
messages.append(f"✅ Installed {len(installed_commands)} commands:")
|
||||
for cmd in installed_commands:
|
||||
messages.append(f" - /{cmd}")
|
||||
|
||||
if skipped_commands:
|
||||
messages.append(f"\n⚠️ Skipped {len(skipped_commands)} existing commands (use --force to reinstall):")
|
||||
for cmd in skipped_commands:
|
||||
messages.append(f" - /{cmd}")
|
||||
|
||||
if failed_commands:
|
||||
messages.append(f"\n❌ Failed to install {len(failed_commands)} commands:")
|
||||
for fail in failed_commands:
|
||||
messages.append(f" - {fail}")
|
||||
|
||||
if not installed_commands and not skipped_commands:
|
||||
return False, "No commands were installed"
|
||||
|
||||
messages.append(f"\n📁 Installation directory: {target_path}")
|
||||
messages.append("\n💡 Tip: Restart Claude Code to use the new commands")
|
||||
|
||||
success = len(failed_commands) == 0
|
||||
return success, "\n".join(messages)
|
||||
|
||||
|
||||
def _get_commands_source() -> Path:
|
||||
"""
|
||||
Get source directory for commands
|
||||
|
||||
Commands are stored in:
|
||||
plugins/superclaude/commands/
|
||||
|
||||
Returns:
|
||||
Path to commands source directory
|
||||
"""
|
||||
# Get package root (src/superclaude/)
|
||||
package_root = Path(__file__).resolve().parent.parent
|
||||
|
||||
# Check if running from source checkout
|
||||
# package_root = src/superclaude/
|
||||
# repo_root = src/superclaude/../../ = project root
|
||||
repo_root = package_root.parent.parent
|
||||
|
||||
# Try plugins/superclaude/commands/ in project root
|
||||
commands_dir = repo_root / "plugins" / "superclaude" / "commands"
|
||||
|
||||
if commands_dir.exists():
|
||||
return commands_dir
|
||||
|
||||
# If not found, try relative to package (for installed package)
|
||||
# This would be in site-packages/superclaude/commands/
|
||||
alt_commands_dir = package_root / "commands"
|
||||
if alt_commands_dir.exists():
|
||||
return alt_commands_dir
|
||||
|
||||
return commands_dir # Return first candidate even if doesn't exist
|
||||
|
||||
|
||||
def list_available_commands() -> List[str]:
|
||||
"""
|
||||
List all available commands
|
||||
|
||||
Returns:
|
||||
List of command names
|
||||
"""
|
||||
command_source = _get_commands_source()
|
||||
|
||||
if not command_source.exists():
|
||||
return []
|
||||
|
||||
commands = []
|
||||
for file in command_source.glob("*.md"):
|
||||
if file.stem != "README":
|
||||
commands.append(file.stem)
|
||||
|
||||
return sorted(commands)
|
||||
|
||||
|
||||
def list_installed_commands() -> List[str]:
|
||||
"""
|
||||
List installed commands in ~/.claude/commands/
|
||||
|
||||
Returns:
|
||||
List of installed command names
|
||||
"""
|
||||
commands_dir = Path.home() / ".claude" / "commands"
|
||||
|
||||
if not commands_dir.exists():
|
||||
return []
|
||||
|
||||
installed = []
|
||||
for file in commands_dir.glob("*.md"):
|
||||
if file.stem != "README":
|
||||
installed.append(file.stem)
|
||||
|
||||
return sorted(installed)
|
||||
@@ -25,6 +25,69 @@ def main():
|
||||
pass
|
||||
|
||||
|
||||
@main.command()
|
||||
@click.option(
|
||||
"--target",
|
||||
default="~/.claude/commands",
|
||||
help="Installation directory (default: ~/.claude/commands)",
|
||||
)
|
||||
@click.option(
|
||||
"--force",
|
||||
is_flag=True,
|
||||
help="Force reinstall if commands already exist",
|
||||
)
|
||||
@click.option(
|
||||
"--list",
|
||||
"list_only",
|
||||
is_flag=True,
|
||||
help="List available commands without installing",
|
||||
)
|
||||
def install(target: str, force: bool, list_only: bool):
|
||||
"""
|
||||
Install SuperClaude commands to Claude Code
|
||||
|
||||
Installs all slash commands (/research, /index-repo, etc.) to your
|
||||
~/.claude/commands directory so you can use them in Claude Code.
|
||||
|
||||
Examples:
|
||||
superclaude install
|
||||
superclaude install --force
|
||||
superclaude install --list
|
||||
superclaude install --target /custom/path
|
||||
"""
|
||||
from .install_commands import (
|
||||
install_commands,
|
||||
list_available_commands,
|
||||
list_installed_commands,
|
||||
)
|
||||
|
||||
# List only mode
|
||||
if list_only:
|
||||
available = list_available_commands()
|
||||
installed = list_installed_commands()
|
||||
|
||||
click.echo("📋 Available Commands:")
|
||||
for cmd in available:
|
||||
status = "✅ installed" if cmd in installed else "⬜ not installed"
|
||||
click.echo(f" /{cmd:20} {status}")
|
||||
|
||||
click.echo(f"\nTotal: {len(available)} available, {len(installed)} installed")
|
||||
return
|
||||
|
||||
# Install commands
|
||||
target_path = Path(target).expanduser()
|
||||
|
||||
click.echo(f"📦 Installing SuperClaude commands to {target_path}...")
|
||||
click.echo()
|
||||
|
||||
success, message = install_commands(target_path=target_path, force=force)
|
||||
|
||||
click.echo(message)
|
||||
|
||||
if not success:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@main.command()
|
||||
@click.argument("skill_name")
|
||||
@click.option(
|
||||
|
||||
@@ -37,8 +37,12 @@ class TokenBudgetManager:
|
||||
Args:
|
||||
complexity: Task complexity level (simple, medium, complex)
|
||||
"""
|
||||
# Validate complexity and default to "medium" if invalid
|
||||
if complexity not in self.LIMITS:
|
||||
complexity = "medium"
|
||||
|
||||
self.complexity = complexity
|
||||
self.limit = self.LIMITS.get(complexity, 1000)
|
||||
self.limit = self.LIMITS[complexity]
|
||||
self.used = 0
|
||||
|
||||
def allocate(self, amount: int) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user