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>
234 lines
8.5 KiB
Python
Executable File
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())
|