Add apps modules and improve captain_claude logging

- Add apps/ directory with modular components:
  - captain.py: Main orchestrator
  - corp/, deck/, devops/, docker/, hst/: Domain-specific apps
- Fix duplicate logger handlers in long sessions
- Add flush=True to print statements for real-time output

Note: flow-ui, mindlink, tzzr-cli are separate repos (not included)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
ARCHITECT
2026-01-02 01:13:30 +00:00
parent acffd2a2a7
commit d35f11e2f7
7 changed files with 1796 additions and 38 deletions

165
apps/captain.py Normal file
View File

@@ -0,0 +1,165 @@
#!/usr/bin/env python3
"""
CAPTAIN CLAUDE - CLI Unificado para el Sistema TZZR
Punto de entrada principal para todas las apps
"""
import sys
import os
import subprocess
APPS_DIR = os.path.dirname(os.path.abspath(__file__))
APPS = {
"devops": {
"path": f"{APPS_DIR}/devops/app.py",
"desc": "Gestión de despliegues y construcción",
"alias": ["deploy", "build"]
},
"deck": {
"path": f"{APPS_DIR}/deck/app.py",
"desc": "Servidor DECK (72.62.1.113) - Agentes, Mail, Apps",
"alias": ["d"]
},
"corp": {
"path": f"{APPS_DIR}/corp/app.py",
"desc": "Servidor CORP (92.112.181.188) - Margaret, Jared, Mason, Feldman",
"alias": ["c"]
},
"hst": {
"path": f"{APPS_DIR}/hst/app.py",
"desc": "Servidor HST (72.62.2.84) - Directus, Imágenes",
"alias": ["h"]
},
"docker": {
"path": f"{APPS_DIR}/docker/app.py",
"desc": "Gestión Docker multi-servidor",
"alias": ["dk"]
}
}
def print_banner():
print("""
╔═══════════════════════════════════════════════════════════════╗
║ CAPTAIN CLAUDE ║
║ Sistema Multiagente TZZR ║
╠═══════════════════════════════════════════════════════════════╣
║ Servidor Central: 69.62.126.110 (Gitea, PostgreSQL) ║
║ DECK: 72.62.1.113 │ CORP: 92.112.181.188 ║
║ HST: 72.62.2.84 │ R2: Cloudflare Storage ║
╚═══════════════════════════════════════════════════════════════╝
""")
def print_help():
print_banner()
print("Uso: python captain.py <app> [comando] [argumentos]\n")
print("Apps disponibles:")
print("" * 60)
for name, info in APPS.items():
aliases = ", ".join(info["alias"]) if info["alias"] else ""
alias_str = f" (alias: {aliases})" if aliases else ""
print(f" {name}{alias_str}")
print(f" └─ {info['desc']}")
print()
print("Ejemplos:")
print(" python captain.py devops deploy clara deck")
print(" python captain.py deck agents")
print(" python captain.py corp pending")
print(" python captain.py docker ps all")
print(" python captain.py hst directus")
print()
print("Atajos rápidos:")
print(" python captain.py d agents # DECK agents")
print(" python captain.py c flows # CORP flows")
print(" python captain.py dk dashboard # Docker dashboard")
def resolve_app(name: str) -> str:
"""Resuelve nombre o alias a nombre de app"""
if name in APPS:
return name
for app_name, info in APPS.items():
if name in info.get("alias", []):
return app_name
return None
def run_app(app: str, args: list):
"""Ejecuta una app con los argumentos dados"""
app_name = resolve_app(app)
if not app_name:
print(f"❌ App no encontrada: {app}")
print(f" Apps disponibles: {', '.join(APPS.keys())}")
return 1
app_path = APPS[app_name]["path"]
if not os.path.exists(app_path):
print(f"❌ Archivo no encontrado: {app_path}")
return 1
cmd = ["python3", app_path] + args
try:
result = subprocess.run(cmd)
return result.returncode
except KeyboardInterrupt:
print("\n⚠️ Interrumpido")
return 130
except Exception as e:
print(f"❌ Error: {e}")
return 1
def quick_status():
"""Muestra estado rápido de todos los servidores"""
print_banner()
print("📊 Estado rápido del sistema:\n")
servers = [
("DECK", "root@72.62.1.113"),
("CORP", "root@92.112.181.188"),
("HST", "root@72.62.2.84")
]
for name, host in servers:
cmd = f"ssh -i ~/.ssh/tzzr -o ConnectTimeout=3 {host} 'docker ps -q | wc -l' 2>/dev/null"
try:
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=5)
if result.returncode == 0:
count = result.stdout.strip()
print(f"{name} ({host.split('@')[1]}): {count} contenedores")
else:
print(f"{name} ({host.split('@')[1]}): No responde")
except:
print(f"{name} ({host.split('@')[1]}): Timeout")
print()
def main():
if len(sys.argv) < 2:
print_help()
return 0
cmd = sys.argv[1]
# Comandos especiales
if cmd in ["-h", "--help", "help"]:
print_help()
return 0
if cmd in ["status", "s"]:
quick_status()
return 0
if cmd in ["version", "-v", "--version"]:
print("Captain Claude v1.0.0")
return 0
# Ejecutar app
args = sys.argv[2:] if len(sys.argv) > 2 else []
return run_app(cmd, args)
if __name__ == "__main__":
sys.exit(main())