mirror of
https://github.com/SuperClaude-Org/SuperClaude_Framework.git
synced 2025-12-29 16:16:08 +00:00
fix: unify metadata location and improve installer UX
## Changes ### Unified Metadata Location - All components now use `~/.claude/.superclaude-metadata.json` - Previously split between root and superclaude subdirectory - Automatic migration from old location on first load - Eliminates confusion from duplicate metadata files ### Improved Installation Messages - Changed WARNING to INFO for existing installations - Message now clearly states "will be updated" instead of implying problem - Reduces user confusion during reinstalls/updates ### Updated Makefile - `make install`: Development mode (uv, local source, editable) - `make install-release`: Production mode (pipx, from PyPI) - `make dev`: Alias for install - Improved help output with categorized commands ## Technical Details **Metadata Unification** (setup/services/settings.py): - SettingsService now always uses `~/.claude/.superclaude-metadata.json` - Added `_migrate_old_metadata()` for automatic migration - Deep merge strategy preserves existing data - Old file backed up as `.superclaude-metadata.json.migrated` **User File Protection**: - Verified: User-created files preserved during updates - Only SuperClaude-managed files (tracked in metadata) are updated - Obsolete framework files automatically removed ## Migration Path Existing installations automatically migrate on next `make install`: 1. Old metadata detected at `~/.claude/superclaude/.superclaude-metadata.json` 2. Merged into `~/.claude/.superclaude-metadata.json` 3. Old file backed up 4. No user action required 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
50
Makefile
50
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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user