#!/usr/bin/env python3 """ deploy_windows.py — Script de packaging du client Windows pour Agent V1. Copie uniquement les fichiers nécessaires au fonctionnement de l'agent sur le PC cible (Windows), sans le serveur ni les dépendances lourdes. Usage : python deploy_windows.py # Crée le dossier deploy/windows_client/ python deploy_windows.py --zip # Idem + archive .zip """ from __future__ import annotations import argparse import os import shutil import sys from datetime import datetime from pathlib import Path # Répertoire racine de agent_v0 (là où vit ce script) AGENT_V0_DIR = Path(__file__).resolve().parent # Répertoire de sortie DEPLOY_DIR = AGENT_V0_DIR / "deploy" / "windows_client" # ───────────────────────────────────────────────────────── # Manifeste des fichiers à déployer # Chaque entrée : (source relative à agent_v0, destination relative à windows_client) # ───────────────────────────────────────────────────────── FILE_MANIFEST: list[tuple[str, str]] = [ # === agent_v1 — package principal === ("agent_v1/__init__.py", "agent_v1/__init__.py"), ("agent_v1/config.py", "agent_v1/config.py"), ("agent_v1/main.py", "agent_v1/main.py"), ("agent_v1/window_info.py", "agent_v1/window_info.py"), ("agent_v1/window_info_crossplatform.py", "agent_v1/window_info_crossplatform.py"), # agent_v1/core ("agent_v1/core/__init__.py", "agent_v1/core/__init__.py"), ("agent_v1/core/captor.py", "agent_v1/core/captor.py"), ("agent_v1/core/executor.py", "agent_v1/core/executor.py"), # agent_v1/network ("agent_v1/network/__init__.py", "agent_v1/network/__init__.py"), ("agent_v1/network/streamer.py", "agent_v1/network/streamer.py"), # agent_v1/session ("agent_v1/session/__init__.py", "agent_v1/session/__init__.py"), ("agent_v1/session/storage.py", "agent_v1/session/storage.py"), # agent_v1/ui — smart_tray (PAS tray.py, c'est l'ancien PyQt5) ("agent_v1/ui/__init__.py", "agent_v1/ui/__init__.py"), ("agent_v1/ui/notifications.py", "agent_v1/ui/notifications.py"), ("agent_v1/ui/smart_tray.py", "agent_v1/ui/smart_tray.py"), # agent_v1/vision ("agent_v1/vision/__init__.py", "agent_v1/vision/__init__.py"), ("agent_v1/vision/capturer.py", "agent_v1/vision/capturer.py"), # agent_v1/monitoring ("agent_v1/monitoring/__init__.py", "agent_v1/monitoring/__init__.py"), # === lea_ui — communication chat/workflow (utilisée par smart_tray) === ("lea_ui/__init__.py", "lea_ui/__init__.py"), ("lea_ui/server_client.py", "lea_ui/server_client.py"), # === Racine agent_v0 — fichiers nécessaires à l'exécution === ("__init__.py", "__init__.py"), ("config.py", "config.py"), ("agent_config.json", "agent_config.json"), ("run_agent_v1.py", "run_agent_v1.py"), ("setup_v1.bat", "setup.bat"), ("agent_v1/requirements.txt", "requirements.txt"), ] # Contenu du fichier LISEZMOI.txt LISEZMOI_CONTENT = """\ === Agent V1 — RPA Vision — Client Windows === Installation : 1. Double-cliquer sur setup.bat 2. Configurer le serveur : éditer agent_config.json ou définir la variable RPA_SERVER_HOST=192.168.1.x 3. Lancer : python run_agent_v1.py L'agent apparaît dans la zone de notification (systray). Clic droit pour accéder au menu : démarrer une session, lancer un replay, voir les workflows appris, etc. Léa communique par des notifications toast sur votre écran. Prérequis : - Python 3.10 ou plus récent - Connexion réseau vers le serveur Linux """ def nettoyer_deploy_dir() -> None: """Supprime le répertoire de déploiement s'il existe déjà.""" if DEPLOY_DIR.exists(): print(f" Nettoyage de {DEPLOY_DIR} ...") shutil.rmtree(DEPLOY_DIR) def copier_fichiers() -> tuple[list[str], list[str]]: """ Copie tous les fichiers du manifeste vers le répertoire de déploiement. Retourne : (fichiers_copies, fichiers_manquants) — deux listes de chemins relatifs """ copies: list[str] = [] manquants: list[str] = [] for src_rel, dst_rel in FILE_MANIFEST: src = AGENT_V0_DIR / src_rel dst = DEPLOY_DIR / dst_rel if not src.exists(): print(f" [ATTENTION] Fichier manquant, ignoré : {src_rel}") manquants.append(src_rel) continue # Créer les répertoires parents si nécessaire dst.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(src, dst) copies.append(dst_rel) return copies, manquants def creer_lisezmoi() -> None: """Crée le fichier LISEZMOI.txt dans le répertoire de déploiement.""" lisezmoi_path = DEPLOY_DIR / "LISEZMOI.txt" lisezmoi_path.write_text(LISEZMOI_CONTENT, encoding="utf-8") print(f" LISEZMOI.txt créé") def creer_archive_zip() -> Path: """ Crée une archive .zip du répertoire de déploiement. Retourne le chemin de l'archive créée. """ horodatage = datetime.now().strftime("%Y%m%d_%H%M%S") nom_archive = f"windows_client_{horodatage}" chemin_archive = DEPLOY_DIR.parent / nom_archive # shutil.make_archive ajoute automatiquement l'extension .zip archive_path = shutil.make_archive( str(chemin_archive), "zip", root_dir=str(DEPLOY_DIR.parent), base_dir="windows_client", ) return Path(archive_path) def afficher_resume(copies: list[str], manquants: list[str], archive: Path | None) -> None: """Affiche un résumé des opérations effectuées.""" print() print("=" * 55) print(" Résumé du déploiement — Agent V1 Client Windows") print("=" * 55) print(f" Destination : {DEPLOY_DIR}") print(f" Fichiers copiés : {len(copies)}") if manquants: print(f" Fichiers manquants : {len(manquants)}") for f in manquants: print(f" - {f}") if archive: taille_mo = archive.stat().st_size / (1024 * 1024) print(f" Archive : {archive.name} ({taille_mo:.1f} Mo)") print() # Afficher l'arborescence simplifiée print(" Arborescence :") for f in sorted(copies): print(f" {f}") print() print(" Terminé.") print("=" * 55) def main() -> None: parser = argparse.ArgumentParser( description="Prépare le package de déploiement Windows pour Agent V1" ) parser.add_argument( "--zip", action="store_true", help="Créer aussi une archive .zip du package", ) args = parser.parse_args() print() print("=== Déploiement Agent V1 — Client Windows ===") print() # Étape 1 : Nettoyage nettoyer_deploy_dir() # Étape 2 : Création du répertoire de déploiement DEPLOY_DIR.mkdir(parents=True, exist_ok=True) print(f" Répertoire créé : {DEPLOY_DIR}") # Étape 3 : Copie des fichiers print(" Copie des fichiers...") copies, manquants = copier_fichiers() # Étape 4 : Création du LISEZMOI.txt creer_lisezmoi() # Étape 5 : Archive .zip (optionnel) archive = None if args.zip: print(" Création de l'archive .zip...") archive = creer_archive_zip() print(f" Archive créée : {archive}") # Résumé afficher_resume(copies, manquants, archive) if __name__ == "__main__": main()