diff --git a/scripts/skill_installer.py b/scripts/skill_installer.py new file mode 100644 index 00000000..516e8175 --- /dev/null +++ b/scripts/skill_installer.py @@ -0,0 +1,75 @@ +#!/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()