76 lines
2.4 KiB
Python
76 lines
2.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
[OPS] Sovereign Skill Installer
|
|
Part of the Gemini Sovereign Infrastructure Suite.
|
|
|
|
Packages and installs Hermes skills onto remote wizard nodes.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import argparse
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
# --- CONFIGURATION ---
|
|
# Assumes hermes-agent is a sibling directory to timmy-config
|
|
HERMES_ROOT = "../hermes-agent"
|
|
SKILLS_DIR = "skills"
|
|
|
|
class SkillInstaller:
|
|
def __init__(self, host: str, ip: str):
|
|
self.host = host
|
|
self.ip = ip
|
|
self.hermes_path = Path(HERMES_ROOT).resolve()
|
|
|
|
def log(self, message: str):
|
|
print(f"[*] {message}")
|
|
|
|
def error(self, message: str):
|
|
print(f"[!] ERROR: {message}")
|
|
sys.exit(1)
|
|
|
|
def install_skill(self, skill_name: str):
|
|
self.log(f"Installing skill '{skill_name}' to {self.host} ({self.ip})...")
|
|
|
|
skill_path = self.hermes_path / SKILLS_DIR / skill_name
|
|
if not skill_path.exists():
|
|
self.error(f"Skill '{skill_name}' not found in {skill_path}")
|
|
|
|
# 1. Compress skill
|
|
self.log("Compressing skill...")
|
|
tar_file = f"{skill_name}.tar.gz"
|
|
subprocess.run(["tar", "-czf", tar_file, "-C", str(skill_path.parent), skill_name])
|
|
|
|
# 2. Upload to remote
|
|
self.log("Uploading to remote...")
|
|
remote_path = f"/opt/hermes/skills/{skill_name}"
|
|
subprocess.run(["ssh", f"root@{self.ip}", f"mkdir -p /opt/hermes/skills"])
|
|
subprocess.run(["scp", tar_file, f"root@{self.ip}:/tmp/"])
|
|
|
|
# 3. Extract and register
|
|
self.log("Extracting and registering...")
|
|
extract_cmd = f"tar -xzf /tmp/{tar_file} -C /opt/hermes/skills/ && rm /tmp/{tar_file}"
|
|
subprocess.run(["ssh", f"root@{self.ip}", extract_cmd])
|
|
|
|
# Registration logic (simplified)
|
|
# In a real scenario, we'd update the wizard's config.yaml
|
|
self.log(f"[SUCCESS] Skill '{skill_name}' installed on {self.host}")
|
|
|
|
# Cleanup local tar
|
|
os.remove(tar_file)
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Gemini Skill Installer")
|
|
parser.add_argument("host", help="Target host name")
|
|
parser.add_argument("ip", help="Target host IP")
|
|
parser.add_argument("skill", help="Skill name to install")
|
|
|
|
args = parser.parse_args()
|
|
|
|
installer = SkillInstaller(args.host, args.ip)
|
|
installer.install_skill(args.skill)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|