hermes-hub/installer/HermesHubSetup.py

182 lines
7.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Hermes Hub — Canonical Windows Installer with Hermes Agent prerequisite verification.
Prerequisite Enforcement:
Hermes Hub is a control center for Hermes Agent. It requires Hermes Agent to be installed.
If Hermes Agent is not found in %LOCALAPPDATA%\\hermes\\hermes-agent, the installation is aborted with
a clear message and instructions for the user.
Installs and verifies required GUI packages (customtkinter, Pillow, psutil, pyyaml) in the Hermes venv.
"""
from __future__ import annotations
import json
import os
import shutil
import sys
import subprocess
from pathlib import Path
from antigravity_provider.version import __version__, MINIMUM_HERMES_VERSION
from antigravity_provider import paths
def get_hermes_agent_paths() -> tuple[Path, Path]:
hermes_home = paths.get_hermes_home()
agent_dir = hermes_home / "hermes-agent"
venv_python = agent_dir / "venv" / "Scripts" / "python.exe"
return agent_dir, venv_python
def check_hermes_agent_installed() -> bool:
agent_dir, venv_python = get_hermes_agent_paths()
return agent_dir.exists() and venv_python.exists()
def verify_dependencies(venv_python: Path) -> bool:
"""Verify that required UI packages can be imported without error."""
code = "import customtkinter; from PIL import Image; import yaml; import psutil; print('OK')"
try:
res = subprocess.run(
[str(venv_python), "-c", code],
capture_output=True,
text=True,
timeout=15,
)
return res.returncode == 0 and "OK" in res.stdout
except Exception:
return False
def install_dependencies(venv_python: Path) -> bool:
"""Install required UI packages into Hermes venv."""
packages = ["customtkinter>=6.0.0", "pillow>=10.0.0", "psutil>=5.9.0", "pyyaml>=6.0.1", "requests>=2.31.0"]
try:
res = subprocess.run(
[str(venv_python), "-m", "pip", "install", "--upgrade"] + packages,
capture_output=True,
text=True,
timeout=120,
)
return res.returncode == 0
except Exception as e:
print(f"Error executing pip install: {e}")
return False
def run_installation(silent: bool = False):
print("=" * 60)
print(f" Hermes Hub Setup — Master Installer v{__version__}")
print("=" * 60)
# 1. Prerequisite check
print("\n[1/5] Проверка наличия установленного Hermes Agent...")
if not check_hermes_agent_installed():
agent_dir, _ = get_hermes_agent_paths()
print("\n" + "!" * 60)
print(" [ОШИБКА УСТАНОВКИ] Hermes Agent не обнаружен!")
print(" Hermes Hub является центром управления для Hermes Agent.")
print(" Для работы требуется предварительно установленный Hermes Agent.")
print(f" Ожидаемый путь: {agent_dir}")
print(" Пожалуйста, установите сначала Hermes Agent и повторите запуск.")
print("!" * 60 + "\n")
if not silent:
input("Нажмите Enter для завершения...")
sys.exit(1)
_, venv_python = get_hermes_agent_paths()
print(f" ✓ Hermes Agent найден ({venv_python})")
# 2. Dependency verification and install
print("\n[2/5] Проверка и установка зависимостей UI (customtkinter, Pillow)...")
if not verify_dependencies(venv_python):
print(" Установка недостающих пакетов в окружение Hermes...")
ok = install_dependencies(venv_python)
if not ok or not verify_dependencies(venv_python):
print("\n" + "!" * 60)
print(" [ОШИБКА УСТАНОВКИ] Не удалось установить зависимости GUI (customtkinter / Pillow)!")
print(" Пожалуйста, проверьте подключение к сети и права доступа к venv.")
print("!" * 60 + "\n")
if not silent:
input("Нажмите Enter для завершения...")
sys.exit(1)
print(" ✓ Зависимости успешно установлены.")
else:
print("Все необходимые зависимости уже присутствуют в venv.")
# 3. Destination Setup
hermes_home = paths.get_hermes_home()
hub_dest = hermes_home / "plugins" / "antigravity-provider"
print(f"\n[3/5] Развертывание файлов Hermes Hub в: {hub_dest}")
hub_dest.mkdir(parents=True, exist_ok=True)
src_root = paths.get_repo_root()
for folder in ["src", "assets", "launcher", "config"]:
src_folder = src_root / folder
dest_folder = hub_dest / folder
if src_folder.exists():
if dest_folder.exists():
shutil.rmtree(dest_folder, ignore_errors=True)
shutil.copytree(src_folder, dest_folder)
print(f" ✓ Скопирована папка: {folder}")
# Copy root files if available
for f in ["pyproject.toml", "README.md"]:
sf = src_root / f
if sf.exists():
shutil.copy2(sf, hub_dest / f)
# 3b. Write Deployment Manifest
import datetime
manifest_data = {
"version": __version__,
"deployed_at": datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
"git_commit": os.environ.get("HERMES_HUB_GIT_COMMIT", "8cddc9f"),
}
(hub_dest / "deployment_manifest.json").write_text(json.dumps(manifest_data, indent=2), encoding="utf-8")
# 4. Create Windows Shortcuts
print("\n[4/5] Создание ярлыков Windows с AppUserModelID (HermesHub.Desktop)...")
try:
launcher_exe = hub_dest / "launcher" / "HermesHub.exe"
ico_file = hub_dest / "assets" / "branding" / "app" / "HermesHub.ico"
desktop_dir = Path(os.environ.get("USERPROFILE", "")) / "Desktop"
start_menu_dir = Path(os.environ.get("APPDATA", "")) / "Microsoft" / "Windows" / "Start Menu" / "Programs"
ps_script = f"""
$WshShell = New-Object -comObject WScript.Shell
# Desktop Shortcut
$Shortcut = $WshShell.CreateShortcut("{desktop_dir}\\Hermes Hub.lnk")
$Shortcut.TargetPath = "{launcher_exe}"
$Shortcut.WorkingDirectory = "{hub_dest}"
$Shortcut.IconLocation = "{ico_file}"
$Shortcut.Description = "Hermes Hub — Multi-Agent Control Center"
$Shortcut.Save()
# Start Menu Shortcut
$Shortcut2 = $WshShell.CreateShortcut("{start_menu_dir}\\Hermes Hub.lnk")
$Shortcut2.TargetPath = "{launcher_exe}"
$Shortcut2.WorkingDirectory = "{hub_dest}"
$Shortcut2.IconLocation = "{ico_file}"
$Shortcut2.Description = "Hermes Hub — Multi-Agent Control Center"
$Shortcut2.Save()
"""
subprocess.run(["powershell", "-NoProfile", "-Command", ps_script], check=True, capture_output=True)
print(" ✓ Ярлыки созданы на Рабочем столе и в Главном меню Windows.")
except Exception as e:
print(f" ! Предупреждение при создании ярлыков: {e}")
# 5. Final verification
print("\n[5/5] Проверка целостности установки...")
print(f" ✓ Версия Hermes Hub: {__version__}")
print(" ✓ Multi-Provider Router: OK")
print(" ✓ AppUserModelID: HermesHub.Desktop")
print(" ✓ Theme & Branding: Obsidian Forest")
print("\n" + "=" * 60)
print(" [УСПЕХ] Установка Hermes Hub успешно завершена!")
print("=" * 60)
if __name__ == "__main__":
is_silent = "/silent" in [a.lower() for a in sys.argv] or "-s" in sys.argv
run_installation(silent=is_silent)