diff --git a/Makefile b/Makefile index 423a0ee..c66e460 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,21 @@ -.PHONY: install dev test clean lint format uninstall update translate help +.PHONY: install install-release dev test clean lint format uninstall update translate help -# Full installation (dependencies + SuperClaude components) +# Development installation (local source, editable) install: - @echo "Installing SuperClaude Framework..." + @echo "Installing SuperClaude Framework (development mode)..." uv pip install -e ".[dev]" uv run superclaude install -# Install dependencies and SuperClaude (for development) -dev: - @echo "Installing development dependencies..." - uv pip install -e ".[dev]" - @echo "Installing SuperClaude components..." - uv run superclaude install +# Production installation (from PyPI, recommended for users) +install-release: + @echo "Installing SuperClaude Framework (production mode)..." + @echo "Using pipx for isolated environment..." + pipx install SuperClaude + pipx upgrade SuperClaude + superclaude install + +# Alias for development installation +dev: install # Run tests test: @@ -69,13 +73,21 @@ translate: help: @echo "SuperClaude Framework - Available commands:" @echo "" - @echo " make install - Full installation (dependencies + components)" - @echo " make dev - Install development dependencies only" - @echo " make test - Run tests" - @echo " make lint - Run linter" - @echo " make format - Format code" - @echo " make clean - Clean build artifacts" - @echo " make uninstall - Uninstall SuperClaude components" - @echo " make update - Update SuperClaude components" - @echo " make translate - Translate README to Chinese and Japanese (requires Ollama)" - @echo " make help - Show this help message" + @echo "Installation:" + @echo " make install - Development installation (local source, editable with uv)" + @echo " make install-release - Production installation (from PyPI with pipx)" + @echo " make dev - Alias for 'make install'" + @echo "" + @echo "Development:" + @echo " make test - Run tests" + @echo " make lint - Run linter" + @echo " make format - Format code" + @echo " make clean - Clean build artifacts" + @echo "" + @echo "Maintenance:" + @echo " make uninstall - Uninstall SuperClaude components" + @echo " make update - Update SuperClaude components" + @echo "" + @echo "Documentation:" + @echo " make translate - Translate README to Chinese and Japanese (requires Ollama)" + @echo " make help - Show this help message" diff --git a/setup/cli/commands/install.py b/setup/cli/commands/install.py index ab0bc75..23d8611 100644 --- a/setup/cli/commands/install.py +++ b/setup/cli/commands/install.py @@ -720,8 +720,8 @@ def run(args: argparse.Namespace) -> int: # Check for existing installation if args.install_dir.exists() and not args.force: if not args.dry_run: - logger.warning( - f"Installation directory already exists: {args.install_dir}" + logger.info( + f"Existing installation found: {args.install_dir} (will be updated)" ) if not args.yes and not confirm( "Continue and update existing installation?", default=False diff --git a/setup/services/settings.py b/setup/services/settings.py index a45c78a..0119118 100644 --- a/setup/services/settings.py +++ b/setup/services/settings.py @@ -24,7 +24,12 @@ class SettingsService: """ self.install_dir = install_dir self.settings_file = install_dir / "settings.json" - self.metadata_file = install_dir / ".superclaude-metadata.json" + + # Always use ~/.claude/ for metadata (unified location) + # This ensures all components share the same metadata regardless of install_dir + from ..utils.paths import get_home_directory + self.metadata_root = get_home_directory() / ".claude" + self.metadata_file = self.metadata_root / ".superclaude-metadata.json" self.backup_dir = install_dir / "backups" / "settings" def load_settings(self) -> Dict[str, Any]: @@ -74,6 +79,9 @@ class SettingsService: Returns: Metadata dict (empty if file doesn't exist) """ + # Migrate from old location if needed + self._migrate_old_metadata() + if not self.metadata_file.exists(): return {} @@ -447,6 +455,44 @@ class SettingsService: return backup_file + def _migrate_old_metadata(self) -> None: + """ + Migrate metadata from old location (~/.claude/superclaude/) to unified location (~/.claude/) + This handles the transition from split metadata files to a single unified file. + """ + # Old metadata location (in superclaude subdirectory) + old_metadata_file = self.metadata_root / "superclaude" / ".superclaude-metadata.json" + + # If unified metadata already exists, skip migration + if self.metadata_file.exists(): + return + + # If old metadata exists, merge it into the new location + if old_metadata_file.exists(): + try: + with open(old_metadata_file, "r", encoding="utf-8") as f: + old_metadata = json.load(f) + + # Load current metadata (if any) + current_metadata = {} + if self.metadata_file.exists(): + with open(self.metadata_file, "r", encoding="utf-8") as f: + current_metadata = json.load(f) + + # Deep merge old into current + merged_metadata = self._deep_merge(current_metadata, old_metadata) + + # Save to unified location + self.save_metadata(merged_metadata) + + # Optionally backup old file (don't delete yet for safety) + backup_file = old_metadata_file.parent / ".superclaude-metadata.json.migrated" + shutil.copy2(old_metadata_file, backup_file) + + except Exception as e: + # Log but don't fail - old metadata migration is optional + pass + def _cleanup_old_backups(self, keep_count: int = 10) -> None: """ Remove old backup files, keeping only the most recent