Release v1.9.0: Add video-comparer skill and enhance transcript-fixer

## New Skill: video-comparer v1.0.0
- Compare original and compressed videos with interactive HTML reports
- Calculate quality metrics (PSNR, SSIM) for compression analysis
- Generate frame-by-frame visual comparisons (slider, side-by-side, grid)
- Extract video metadata (codec, resolution, bitrate, duration)
- Multi-platform FFmpeg support with security features

## transcript-fixer Enhancements
- Add async AI processor for parallel processing
- Add connection pool management for database operations
- Add concurrency manager and rate limiter
- Add audit log retention and database migrations
- Add health check and metrics monitoring
- Add comprehensive test suite (8 new test files)
- Enhance security with domain and path validators

## Marketplace Updates
- Update marketplace version from 1.8.0 to 1.9.0
- Update skills count from 15 to 16
- Update documentation (README.md, CLAUDE.md, CHANGELOG.md)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
daymade
2025-10-30 00:23:12 +08:00
parent bd0aa12004
commit 9b724f33e3
49 changed files with 15357 additions and 270 deletions

View File

@@ -0,0 +1,385 @@
#!/usr/bin/env python3
"""
Database Migration CLI - Migration Management Commands
CRITICAL FIX (P1-6): Production database migration CLI commands
Features:
- Run migrations with dry-run support
- Migration status and history
- Rollback capability
- Migration validation
- Migration planning
"""
from __future__ import annotations
import argparse
import json
import logging
import sys
from pathlib import Path
from typing import Dict, Any, List
from dataclasses import asdict
from .database_migration import DatabaseMigrationManager, MigrationRecord, MigrationStatus
from .migrations import MIGRATION_REGISTRY, LATEST_VERSION, get_migration, get_migrations_up_to
from .config import get_config
logger = logging.getLogger(__name__)
class DatabaseMigrationCLI:
"""CLI interface for database migrations"""
def __init__(self, db_path: Path = None):
"""
Initialize migration CLI
Args:
db_path: Database path (uses config if not provided)
"""
if db_path is None:
config = get_config()
db_path = config.database.path
self.db_path = Path(db_path)
self.migration_manager = DatabaseMigrationManager(self.db_path)
# Register all migrations
for migration in MIGRATION_REGISTRY.values():
self.migration_manager.register_migration(migration)
def cmd_status(self, args) -> None:
"""
Show migration status
Args:
args: Command line arguments
"""
try:
current_version = self.migration_manager.get_current_version()
history = self.migration_manager.get_migration_history()
pending = self.migration_manager.get_pending_migrations()
print("Database Migration Status")
print("=" * 40)
print(f"Database Path: {self.db_path}")
print(f"Current Version: {current_version}")
print(f"Latest Version: {LATEST_VERSION}")
print(f"Pending Migrations: {len(pending)}")
print(f"Total Migrations Applied: {len([h for h in history if h.status == MigrationStatus.COMPLETED])}")
if pending:
print("\nPending Migrations:")
for migration in pending:
print(f" - {migration.version}: {migration.name}")
if history:
print("\nRecent Migration History:")
for i, record in enumerate(history[:5]):
status_icon = "" if record.status == MigrationStatus.COMPLETED else ""
print(f" {status_icon} {record.version}: {record.name} ({record.status.value})")
except Exception as e:
print(f"❌ Error getting status: {e}")
sys.exit(1)
def cmd_history(self, args) -> None:
"""
Show migration history
Args:
args: Command line arguments
"""
try:
history = self.migration_manager.get_migration_history()
if not history:
print("No migration history found")
return
if args.format == 'json':
records = [record.to_dict() for record in history]
print(json.dumps(records, indent=2, default=str))
else:
print("Migration History")
print("=" * 40)
for record in history:
status_icon = {
MigrationStatus.COMPLETED: "",
MigrationStatus.FAILED: "",
MigrationStatus.ROLLED_BACK: "↩️",
MigrationStatus.RUNNING: "",
}.get(record.status, "")
print(f"{status_icon} {record.version} ({record.direction.value})")
print(f" Name: {record.name}")
print(f" Status: {record.status.value}")
print(f" Executed: {record.executed_at}")
print(f" Duration: {record.execution_time_ms}ms")
if record.error_message:
print(f" Error: {record.error_message}")
print()
except Exception as e:
print(f"❌ Error getting history: {e}")
sys.exit(1)
def cmd_migrate(self, args) -> None:
"""
Run migrations
Args:
args: Command line arguments
"""
try:
target_version = args.version if args.version else LATEST_VERSION
dry_run = args.dry_run
force = args.force
print(f"Running migrations to version: {target_version}")
if dry_run:
print("🚨 DRY RUN MODE - No changes will be applied")
if force:
print("🚨 FORCE MODE - Safety checks bypassed")
# Get migration plan
plan = self.migration_manager.get_migration_plan(target_version)
if not plan:
print("✅ No migrations to apply")
return
print(f"\nMigration Plan:")
print("=" * 40)
for i, step in enumerate(plan, 1):
breaking_icon = "🔴" if step.get('is_breaking') else "🟢"
print(f"{i}. {breaking_icon} {step['version']}: {step['name']}")
print(f" Description: {step['description']}")
if step.get('dependencies'):
print(f" Dependencies: {', '.join(step['dependencies'])}")
if step.get('is_breaking'):
print(" ⚠️ Breaking change - may require data migration")
print()
if not args.yes and not dry_run:
response = input("Continue with migration? (y/N): ")
if response.lower() != 'y':
print("Migration cancelled")
return
# Run migration
self.migration_manager.migrate_to_version(target_version, dry_run, force)
if dry_run:
print("✅ Dry run completed successfully")
else:
print("✅ Migration completed successfully")
# Show new status
new_version = self.migration_manager.get_current_version()
print(f"Database is now at version: {new_version}")
except Exception as e:
print(f"❌ Migration failed: {e}")
sys.exit(1)
def cmd_rollback(self, args) -> None:
"""
Rollback migration
Args:
args: Command line arguments
"""
try:
target_version = args.version
dry_run = args.dry_run
force = args.force
if not target_version:
print("❌ Target version is required for rollback")
sys.exit(1)
current_version = self.migration_manager.get_current_version()
print(f"Rolling back from version {current_version} to {target_version}")
if dry_run:
print("🚨 DRY RUN MODE - No changes will be applied")
if force:
print("🚨 FORCE MODE - Safety checks bypassed")
# Warn about potential data loss
if not args.yes and not dry_run:
response = input("⚠️ WARNING: Rollback may cause data loss. Continue? (y/N): ")
if response.lower() != 'y':
print("Rollback cancelled")
return
# Run rollback
self.migration_manager.migrate_to_version(target_version, dry_run, force)
if dry_run:
print("✅ Dry run completed successfully")
else:
print("✅ Rollback completed successfully")
# Show new status
new_version = self.migration_manager.get_current_version()
print(f"Database is now at version: {new_version}")
except Exception as e:
print(f"❌ Rollback failed: {e}")
sys.exit(1)
def cmd_plan(self, args) -> None:
"""
Show migration plan
Args:
args: Command line arguments
"""
try:
target_version = args.version if args.version else LATEST_VERSION
plan = self.migration_manager.get_migration_plan(target_version)
if not plan:
print("✅ No migrations to apply")
return
print(f"Migration Plan (to version {target_version})")
print("=" * 50)
current_version = self.migration_manager.get_current_version()
print(f"Current Version: {current_version}")
print(f"Target Version: {target_version}")
print()
for i, step in enumerate(plan, 1):
breaking_icon = "🔴" if step.get('is_breaking') else "🟢"
rollback_icon = "" if step.get('has_rollback') else ""
print(f"{i}. {breaking_icon} {step['version']}: {step['name']}")
print(f" Description: {step['description']}")
print(f" Rollback: {rollback_icon}")
if step.get('dependencies'):
print(f" Dependencies: {', '.join(step['dependencies'])}")
print()
# Safety validation
is_safe, issues = self.migration_manager.validate_migration_safety(target_version)
if is_safe:
print("✅ Migration plan is safe")
else:
print("⚠️ Safety issues detected:")
for issue in issues:
print(f" - {issue}")
except Exception as e:
print(f"❌ Error getting migration plan: {e}")
sys.exit(1)
def cmd_validate(self, args) -> None:
"""
Validate migration safety
Args:
args: Command line arguments
"""
try:
target_version = args.version if args.version else LATEST_VERSION
is_safe, issues = self.migration_manager.validate_migration_safety(target_version)
if is_safe:
print("✅ Migration plan is safe")
sys.exit(0)
else:
print("❌ Migration safety issues found:")
for issue in issues:
print(f" - {issue}")
sys.exit(1)
except Exception as e:
print(f"❌ Validation failed: {e}")
sys.exit(1)
def cmd_create_migration(self, args) -> None:
"""
Create a new migration template
Args:
args: Command line arguments
"""
try:
version = args.version
name = args.name
description = args.description
if not version or not name:
print("❌ Version and name are required")
sys.exit(1)
# Check if migration already exists
if version in MIGRATION_REGISTRY:
print(f"❌ Migration {version} already exists")
sys.exit(1)
# Create migration template
template = f'''
# Migration {version}: {name}
# Description: {description}
from __future__ import annotations
import sqlite3
from typing import Tuple
from .database_migration import Migration
from utils.migrations import get_migration
def _validate_migration(conn: sqlite3.Connection, migration: Migration) -> Tuple[bool, str]:
"""Validate migration"""
# Add custom validation logic here
return True, "Migration validation passed"
MIGRATION_{version.replace(".", "_")} = Migration(
version="{version}",
name="{name}",
description="{description}",
forward_sql=\"\"\"
-- Add your forward migration SQL here
\"\"\",
backward_sql=\"\"\"
-- Add your backward migration SQL here (optional)
\"\"\",
dependencies=["2.2"], # List required migrations
check_function=_validate_migration,
is_breaking=False # Set to True for breaking changes
)
# Add to MIGRATION_REGISTRY in migrations.py
# ALL_MIGRATIONS.append(MIGRATION_{version.replace(".", "_")})
# MIGRATION_REGISTRY["{version}"] = MIGRATION_{version.replace(".", "_")}
# LATEST_VERSION = "{version}" # Update if this is the latest
'''.strip()
print("Migration Template:")
print("=" * 50)
print(template)
print("\n⚠️ Remember to:")
print("1. Add the migration to ALL_MIGRATIONS list in migrations.py")
print("2. Update MIGRATION_REGISTRY and LATEST_VERSION")
print("3. Test the migration before deploying")
except Exception as e:
print(f"❌ Error creating template: {e}")
sys.exit(1)
def create_migration_cli(db_path: Path = None) -> DatabaseMigrationCLI:
"""Create migration CLI instance"""
return DatabaseMigrationCLI(db_path)