#!/usr/bin/env python3 """ Emergency recovery script for DAARION City. Restores essential data after database loss: - Core MicroDAOs - City districts - Basic city rooms - Core agents for NODE1 - Asset URLs (from MinIO/S3) """ import asyncio import os import sys import asyncpg from typing import List, Dict, Any # Add parent directory to path for imports sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) DATABASE_URL = os.getenv( "DATABASE_URL", "postgresql://postgres:postgres@localhost:5432/daarion" ) # Base MicroDAOs with S3 asset URLs BASE_MICRODAO = [ { "id": "dao_daarion", "slug": "daarion", "name": "DAARION DAO", "description": "Main ecosystem DAO", "district": "Core", "is_public": True, "is_platform": True, "is_active": True, "is_pinned": True, "pinned_weight": 1, "orchestrator_agent_id": "daarwizz", "logo_url": "https://assets.daarion.space/daarion-assets/microdao/logo/daarion.png", "banner_url": None, }, { "id": "dao_energy", "slug": "energy-union", "name": "Energy Union", "description": "Energy optimization & sustainability", "district": "Energy", "is_public": True, "is_platform": True, "is_active": True, "is_pinned": True, "pinned_weight": 2, "orchestrator_agent_id": "helion", "logo_url": "https://assets.daarion.space/daarion-assets/microdao/logo/energy-union.png", "banner_url": None, }, { "id": "dao_greenfood", "slug": "greenfood", "name": "GreenFood DAO", "description": "Sustainable food systems", "district": "Green", "is_public": True, "is_platform": True, "is_active": True, "is_pinned": True, "pinned_weight": 3, "orchestrator_agent_id": "greenfood", "logo_url": "https://assets.daarion.space/daarion-assets/microdao/logo/greenfood.png", "banner_url": None, }, { "id": "dao_soul", "slug": "soul-retreat", "name": "Soul Retreat Hub", "description": "Identity & reputation system", "district": "Soul", "is_public": True, "is_platform": True, "is_active": True, "is_pinned": True, "pinned_weight": 4, "orchestrator_agent_id": "soul", "logo_url": "https://assets.daarion.space/daarion-assets/microdao/logo/soul-retreat.png", "banner_url": None, }, ] # Core agents for NODE1 CORE_AGENTS_NODE1 = [ { "id": "daarwizz", "display_name": "DAARWIZZ", "kind": "orchestrator", "role": "Core Orchestrator", "node_id": "node-1-hetzner-gex44", "home_node_id": "node-1-hetzner-gex44", "district": "Core", "is_public": True, "is_orchestrator": True, "status": "online", }, { "id": "helion", "display_name": "Helion", "kind": "orchestrator", "role": "Energy Orchestrator", "node_id": "node-1-hetzner-gex44", "home_node_id": "node-1-hetzner-gex44", "district": "Energy", "is_public": True, "is_orchestrator": True, "status": "online", }, { "id": "greenfood", "display_name": "GreenFood Bot", "kind": "orchestrator", "role": "Green Orchestrator", "node_id": "node-1-hetzner-gex44", "home_node_id": "node-1-hetzner-gex44", "district": "Green", "is_public": True, "is_orchestrator": True, "status": "online", }, { "id": "soul", "display_name": "Soul Bot", "kind": "orchestrator", "role": "Soul Orchestrator", "node_id": "node-1-hetzner-gex44", "home_node_id": "node-1-hetzner-gex44", "district": "Soul", "is_public": True, "is_orchestrator": True, "status": "online", }, ] async def seed_microdaos(conn: asyncpg.Connection): """Seed base MicroDAOs.""" print("📦 Seeding MicroDAOs...") for dao in BASE_MICRODAO: await conn.execute(""" INSERT INTO microdao ( id, slug, name, description, district, is_public, is_platform, is_active, is_pinned, pinned_weight, orchestrator_agent_id, logo_url, banner_url ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13 ) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description, district = EXCLUDED.district, is_public = EXCLUDED.is_public, is_platform = EXCLUDED.is_platform, is_active = EXCLUDED.is_active, is_pinned = EXCLUDED.is_pinned, pinned_weight = EXCLUDED.pinned_weight, orchestrator_agent_id = EXCLUDED.orchestrator_agent_id, logo_url = EXCLUDED.logo_url, banner_url = EXCLUDED.banner_url, updated_at = NOW() """, dao["id"], dao["slug"], dao["name"], dao["description"], dao["district"], dao["is_public"], dao["is_platform"], dao["is_active"], dao["is_pinned"], dao["pinned_weight"], dao["orchestrator_agent_id"], dao["logo_url"], dao["banner_url"] ) print(f" ✅ {dao['name']}") print(f"✅ Seeded {len(BASE_MICRODAO)} MicroDAOs") async def seed_core_agents(conn: asyncpg.Connection): """Seed core agents for NODE1.""" print("🤖 Seeding core agents (NODE1)...") for agent in CORE_AGENTS_NODE1: await conn.execute(""" INSERT INTO agents ( id, display_name, kind, role, node_id, home_node_id, district, is_public, is_orchestrator, status, slug, public_slug, public_title, public_tagline, public_district, is_listed_in_directory ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16 ) ON CONFLICT (id) DO UPDATE SET display_name = EXCLUDED.display_name, kind = EXCLUDED.kind, role = EXCLUDED.role, node_id = EXCLUDED.node_id, home_node_id = EXCLUDED.home_node_id, district = EXCLUDED.district, is_public = EXCLUDED.is_public, is_orchestrator = EXCLUDED.is_orchestrator, status = EXCLUDED.status, updated_at = NOW() """, agent["id"], agent["display_name"], agent["kind"], agent["role"], agent["node_id"], agent["home_node_id"], agent["district"], agent["is_public"], agent["is_orchestrator"], agent["status"], agent["id"], agent["id"], agent["display_name"], agent["role"], agent["district"], True ) print(f" ✅ {agent['display_name']}") print(f"✅ Seeded {len(CORE_AGENTS_NODE1)} core agents") async def link_agents_to_microdaos(conn: asyncpg.Connection): """Link orchestrator agents to their MicroDAOs.""" print("🔗 Linking agents to MicroDAOs...") links = [ ("daarwizz", "dao_daarion", True), # is_core ("helion", "dao_energy", True), ("greenfood", "dao_greenfood", True), ("soul", "dao_soul", True), ] for agent_id, microdao_id, is_core in links: await conn.execute(""" INSERT INTO microdao_agents (microdao_id, agent_id, is_core, role) VALUES ($1, $2, $3, 'orchestrator') ON CONFLICT (microdao_id, agent_id) DO UPDATE SET is_core = EXCLUDED.is_core, role = EXCLUDED.role """, microdao_id, agent_id, is_core) print(f" ✅ Linked {agent_id} → {microdao_id}") print("✅ Linked agents to MicroDAOs") async def main(): """Main recovery function.""" print("=" * 60) print("🏙️ DAARION City Emergency Recovery") print("=" * 60) print() conn = None try: print(f"🔗 Connecting to database...") conn = await asyncpg.connect(DATABASE_URL) print("✅ Connected") print() # Seed in order await seed_microdaos(conn) print() await seed_core_agents(conn) print() await link_agents_to_microdaos(conn) print() # Summary microdao_count = await conn.fetchval("SELECT COUNT(*) FROM microdao") agent_count = await conn.fetchval("SELECT COUNT(*) FROM agents") print("=" * 60) print("✅ Recovery complete!") print(f" MicroDAOs: {microdao_count}") print(f" Agents: {agent_count}") print() print("📝 Next steps:") print(" 1. Run migrations if needed") print(" 2. Run scripts/sync-node2-dagi-agents.py for NODE2 agents") print(" 3. Upload logos/banners to MinIO if not already done") print("=" * 60) except Exception as e: print(f"❌ Error during recovery: {e}") import traceback traceback.print_exc() sys.exit(1) finally: if conn: await conn.close() if __name__ == "__main__": asyncio.run(main())