Files
AIPass/src/aipass/backup/apps/backup.py
T
AIOSAIandClaude Opus 4.6 babedd9c64 feat(system): seedgo v2 operational, full system audit, 14/15 branches at 99%
Three days of intensive work bringing seedgo to full operational status
and driving all branches through comprehensive standards compliance.

Seedgo v2.0.0:
- 22 checkers active (up from 20), standards pack fully operational
- New introspection standard researched from Dev-Pass, FPLAN-0017 open
- Bypass system for false positives (.seedgo config)
- Standards query and audit commands fully functional

System-wide audit (FPLAN-0016):
- All 14 auditable branches at 99%+ compliance
- CLI imports standardized across all branches (console from cli.apps.modules)
- handle_command(command, args) → bool contract added to all modules
- print_help() function naming fixed for checker pattern matching
- Handler extraction: large modules split, file I/O moved to handler layer
- New handlers created across ai_mail, backup, daemon, flow, skills, spawn, seedgo

Branch-specific highlights:
- ai_mail: email.py split 840→420 lines, 4 new handlers
- flow: dplan_flow.py 688→591 lines, 4 new handlers
- seedgo: massive restructure — standards moved to handlers/aipass_standards/,
  old standards/ tree removed, bypass system added, diagnostics module
- commons: database module added, CLI imports fixed
- skills: 5 handle_commands added, help function renamed
- trigger: error reporter handler, handle_command routing
- All branches: consistent architecture, clean drone routing

Culture doc (CLAUDE.md) added — documents AIPass philosophy, identity,
memory system, and collaboration principles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 01:26:42 -07:00

234 lines
8.5 KiB
Python
Executable File

# =================== AIPass ====================
# Name: backup.py
# Description: Entry point CLI for drone @backup
# Version: 1.0.0
# Created: 2026-03-08
# Modified: 2026-03-08
# =============================================
"""
Backup System - Main Entry Point
Modular architecture with explicit module imports.
Main handles routing, modules implement functionality.
"""
# Standard library imports
import sys
import argparse
from pathlib import Path
from typing import Any, List
from aipass.cli.apps.modules import console
from aipass.prax import logger
# Explicit module imports (replaces dynamic discover_modules)
from aipass.backup.apps.modules import backup_core, google_drive_sync, integrations, reauth_drive
def get_modules():
"""Return list of modules with handle_command() interface"""
modules = []
for mod in [backup_core, google_drive_sync, integrations, reauth_drive]:
if hasattr(mod, 'handle_command'):
modules.append(mod)
return modules
# =============================================================================
# CONSTANTS & CONFIG
# =============================================================================
# Module root (same directory as this file)
MODULE_ROOT = Path(__file__).parent
# =============================================================================
# COMMAND ROUTING
# =============================================================================
def route_command(args: argparse.Namespace, modules: List[Any]) -> bool:
"""
Route command to appropriate module
Args:
args: Parsed command line arguments
modules: List of discovered modules
Returns:
True if command was handled
"""
for module in modules:
try:
if module.handle_command(args):
return True
except Exception as e:
logger.error(f"Module error: {e}")
return False
# =============================================================================
# INTROSPECTION DISPLAY
# =============================================================================
def print_introspection():
"""Display discovered modules - SEED pattern"""
console.print()
console.print("[bold cyan]Backup System - Automated File Protection[/bold cyan]")
console.print()
console.print("[dim]AIPass backup orchestration and versioning[/dim]")
console.print()
# Discover modules
modules = get_modules()
console.print(f"[yellow]Discovered Modules:[/yellow] {len(modules)}")
console.print()
for module in modules:
module_name = module.__name__ if hasattr(module, '__name__') else str(module)
# Extract just the module filename (last part)
if '.' in module_name:
module_name = module_name.split('.')[-1]
console.print(f" [cyan]•[/cyan] {module_name}")
console.print()
console.print("[dim]Run 'backup --help' for usage information[/dim]")
console.print()
# =============================================================================
# MAIN
# =============================================================================
def show_version():
"""Print version from META DATA HEADER."""
console.print("BACKUP_SYSTEM v1.2.0")
def main():
"""Main entry point - follows Seed CLI flags standard."""
# 1. No args → introspection
if len(sys.argv) == 1:
print_introspection()
return 0
# 2. Universal flags (checked before command routing, execute and exit)
if sys.argv[1] in ['--help', '-h', 'help']:
console.print()
console.print("[bold cyan]BACKUP_SYSTEM[/bold cyan] — Automated File Protection")
console.print()
console.print("[yellow]Commands:[/yellow]")
console.print(" --all Run snapshot + versioned + drive-sync (full backup cycle)")
console.print(" snapshot Create a system snapshot backup")
console.print(" versioned Create a versioned backup")
console.print(" drive-test Test Google Drive connectivity")
console.print(" drive-sync Sync backups to Google Drive")
console.print(" drive-sync --test Run a small test sync to verify integration")
console.print(" drive-stats Show Drive file tracker statistics")
console.print(" drive-clear-tracker Clear Drive file tracker cache")
console.print()
console.print("[yellow]Options:[/yellow]")
console.print(" --verbose, -v Extra diagnostic output")
console.print(" --dry-run Preview what would happen, execute nothing")
console.print(" --note NOTE Add a backup note/description")
console.print(" --project NAME Project name for Drive sync (default: AIPass)")
console.print(" --force Force sync all files (ignore change tracker)")
console.print(" --limit N Limit drive-sync to first N files")
console.print(" --version, -V Show version and exit")
console.print()
return 0
if sys.argv[1] in ['--version', '-V']:
show_version()
return 0
# Normalize --all flag → 'all' command (so both syntaxes work)
if sys.argv[1] == '--all':
sys.argv[1] = 'all'
# 3. Parse args (behavioral flags handled by argparse)
parser = argparse.ArgumentParser(
description='backup_system Branch Operations',
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument('command', nargs='?', help='Command to execute')
parser.add_argument('path', nargs='?', default=None, help='Path argument (for sync commands)')
parser.add_argument('--verbose', '-v', action='store_true', help='Verbose output')
parser.add_argument('--note', type=str, default='No note provided', help='Backup note/description')
parser.add_argument('--dry-run', action='store_true', help='Scan files without copying (test mode)')
parser.add_argument('--project', type=str, default='AIPass', help='Project name for Drive sync')
parser.add_argument('--force', action='store_true', help='Force sync all files')
parser.add_argument('--test', action='store_true', help='Run test mode (small test sync)')
parser.add_argument('--limit', type=int, default=0, help='Limit sync to first N files (0 = no limit)')
args = parser.parse_args()
if not args.command:
print_introspection()
return 0
# 4. Discover modules
modules = get_modules()
if not modules:
console.print("❌ ERROR: No modules found")
return 1
# 5. Handle 'all' command: snapshot → versioned → drive-sync
if args.command == 'all':
console.print("[bold cyan]Full Backup Cycle: snapshot → versioned → drive-sync[/bold cyan]")
console.print()
# Step 1: Snapshot
snapshot_args = argparse.Namespace(
command='snapshot', path=None, verbose=args.verbose,
note=args.note, dry_run=args.dry_run, project=args.project,
force=args.force, test=False, limit=0
)
if not route_command(snapshot_args, modules):
console.print("[red]Snapshot failed - aborting[/red]")
return 1
console.print()
console.print("[dim]─── snapshot complete, starting versioned ───[/dim]")
console.print()
# Step 2: Versioned
versioned_args = argparse.Namespace(
command='versioned', path=None, verbose=args.verbose,
note=args.note, dry_run=args.dry_run, project=args.project,
force=args.force, test=False, limit=0
)
if not route_command(versioned_args, modules):
console.print("[red]Versioned backup failed - aborting[/red]")
return 1
console.print()
console.print("[dim]─── versioned complete, starting drive-sync ───[/dim]")
console.print()
# Step 3: Drive sync
sync_args = argparse.Namespace(
command='drive-sync', path=None, verbose=args.verbose,
note=args.note, dry_run=args.dry_run, project=args.project,
force=args.force, test=False, limit=args.limit
)
if not route_command(sync_args, modules):
console.print("[red]Drive sync failed[/red]")
return 1
console.print()
console.print("[green]Full backup cycle complete[/green]")
return 0
# 6. Route command to modules
if route_command(args, modules):
return 0
else:
console.print(f"❌ ERROR: Unknown command: {args.command}")
return 1
if __name__ == "__main__":
sys.exit(main())