repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources15d ago| #1 | """ |
| #2 | Clawd Memory Hermes Installer |
| #3 | ============================= |
| #4 | |
| #5 | One-command setup for Clawd Memory through the Mnemosyne-compatible Hermes MemoryProvider. |
| #6 | |
| #7 | Usage: |
| #8 | python -m mnemosyne.install |
| #9 | # or after pip install: |
| #10 | mnemosyne-install |
| #11 | """ |
| #12 | |
| #13 | from __future__ import annotations |
| #14 | |
| #15 | import os |
| #16 | import sys |
| #17 | from pathlib import Path |
| #18 | |
| #19 | |
| #20 | def _get_mnemosyne_root() -> Path: |
| #21 | """Return the absolute path to the Clawd Memory repo root.""" |
| #22 | # This file is at mnemosyne/install.py, so parent.parent is repo root |
| #23 | return Path(__file__).resolve().parent.parent |
| #24 | |
| #25 | |
| #26 | def _get_hermes_home() -> Path: |
| #27 | """Return the Hermes home directory, or None if not found.""" |
| #28 | # Check env var first |
| #29 | env = os.environ.get("HERMES_HOME") |
| #30 | if env: |
| #31 | return Path(env) |
| #32 | # Default location |
| #33 | default = Path.home() / ".hermes" |
| #34 | if default.exists(): |
| #35 | return default |
| #36 | return None |
| #37 | |
| #38 | |
| #39 | def _get_hermes_agent_path() -> Path | None: |
| #40 | """Try to find the hermes-agent installation.""" |
| #41 | # Check common locations |
| #42 | candidates = [ |
| #43 | Path.home() / ".hermes" / "hermes-agent", |
| #44 | Path.home() / "hermes-agent", |
| #45 | Path("/opt/hermes/hermes-agent"), |
| #46 | ] |
| #47 | for c in candidates: |
| #48 | if (c / "run_agent.py").exists(): |
| #49 | return c |
| #50 | return None |
| #51 | |
| #52 | |
| #53 | def _ensure_symlink() -> bool: |
| #54 | """Create the symlink from ~/.hermes/plugins/mnemosyne -> hermes_memory_provider.""" |
| #55 | hermes_home = _get_hermes_home() |
| #56 | if not hermes_home: |
| #57 | print("❌ Hermes not found. Is Hermes installed?") |
| #58 | print(" Expected: ~/.hermes/ or $HERMES_HOME set") |
| #59 | return False |
| #60 | |
| #61 | plugins_dir = hermes_home / "plugins" |
| #62 | plugins_dir.mkdir(parents=True, exist_ok=True) |
| #63 | |
| #64 | target = plugins_dir / "mnemosyne" |
| #65 | source = _get_mnemosyne_root() / "hermes_memory_provider" |
| #66 | |
| #67 | if not source.exists(): |
| #68 | print(f"❌ Clawd MemoryProvider not found at {source}") |
| #69 | return False |
| #70 | |
| #71 | # Remove existing |
| #72 | if target.is_symlink() or target.exists(): |
| #73 | if target.is_symlink(): |
| #74 | target.unlink() |
| #75 | else: |
| #76 | import shutil |
| #77 | shutil.rmtree(target) |
| #78 | print(f"🔄 Removed existing {target}") |
| #79 | |
| #80 | target.symlink_to(source, target_is_directory=True) |
| #81 | print(f"✅ Symlinked: {target} -> {source}") |
| #82 | return True |
| #83 | |
| #84 | |
| #85 | def _configure_hermes() -> bool: |
| #86 | """Set memory.provider = mnemosyne in Hermes config.""" |
| #87 | hermes_home = _get_hermes_home() |
| #88 | if not hermes_home: |
| #89 | return False |
| #90 | |
| #91 | config_path = hermes_home / "config.yaml" |
| #92 | |
| #93 | # Read existing config |
| #94 | config_text = "" |
| #95 | if config_path.exists(): |
| #96 | config_text = config_path.read_text(encoding="utf-8") |
| #97 | |
| #98 | # Check if already configured |
| #99 | if "provider: mnemosyne" in config_text: |
| #100 | print("✅ Hermes config already has memory.provider = mnemosyne") |
| #101 | return True |
| #102 | |
| #103 | # Simple append approach (YAML-compatible) |
| #104 | if "memory:" in config_text: |
| #105 | # Replace existing memory block |
| #106 | import re |
| #107 | # Find memory: block and replace provider |
| #108 | new_config = re.sub( |
| #109 | r'(memory:\s*)\n(\s*provider:\s*\S+)?', |
| #110 | r'\1\n provider: mnemosyne\n', |
| #111 | config_text, |
| #112 | count=1, |
| #113 | ) |
| #114 | if new_config == config_text: |
| #115 | # No provider line found, insert one |
| #116 | new_config = config_text.replace( |
| #117 | "memory:", |
| #118 | "memory:\n provider: mnemosyne" |
| #119 | ) |
| #120 | config_path.write_text(new_config, encoding="utf-8") |
| #121 | else: |
| #122 | # Append memory block |
| #123 | with open(config_path, "a", encoding="utf-8") as f: |
| #124 | f.write("\nmemory:\n provider: mnemosyne\n") |
| #125 | |
| #126 | print(f"✅ Updated {config_path}: memory.provider = mnemosyne") |
| #127 | return True |
| #128 | |
| #129 | |
| #130 | def _verify() -> bool: |
| #131 | """Try to import and verify the provider works.""" |
| #132 | hermes_home = _get_hermes_home() |
| #133 | if not hermes_home: |
| #134 | return False |
| #135 | |
| #136 | # Add Hermes to path for verification |
| #137 | agent_path = _get_hermes_agent_path() |
| #138 | if agent_path and str(agent_path) not in sys.path: |
| #139 | sys.path.insert(0, str(agent_path)) |
| #140 | |
| #141 | try: |
| #142 | from plugins.memory import load_memory_provider |
| #143 | provider = load_memory_provider("mnemosyne") |
| #144 | if provider and provider.is_available(): |
| #145 | print(f"✅ Provider verified: {provider.name} is_available=True") |
| #146 | return True |
| #147 | else: |
| #148 | print("⚠️ Provider loaded but not available (memory engine not importable)") |
| #149 | return False |
| #150 | except Exception as e: |
| #151 | print(f"⚠️ Verification skipped: {e}") |
| #152 | return False |
| #153 | |
| #154 | |
| #155 | def install(): |
| #156 | """Run the full Clawd Memory Hermes installation.""" |
| #157 | print("🌀 Clawd Memory Hermes Installer") |
| #158 | print("=" * 40) |
| #159 | print() |
| #160 | |
| #161 | # Step 1: Symlink |
| #162 | if not _ensure_symlink(): |
| #163 | print() |
| #164 | print("❌ Install failed at symlink step.") |
| #165 | sys.exit(1) |
| #166 | |
| #167 | # Step 2: Configure |
| #168 | _configure_hermes() |
| #169 | |
| #170 | # Step 3: Verify |
| #171 | print() |
| #172 | print("🔍 Verifying...") |
| #173 | _verify() |
| #174 | |
| #175 | print() |
| #176 | print("✅ Clawd Memory is ready!") |
| #177 | print() |
| #178 | print("Next steps:") |
| #179 | print(" • Restart Hermes (if running)") |
| #180 | print(" • Run: hermes memory status") |
| #181 | print(" • Run: hermes mnemosyne stats") |
| #182 | print() |
| #183 | |
| #184 | |
| #185 | def uninstall(): |
| #186 | """Remove Clawd Memory from Hermes.""" |
| #187 | hermes_home = _get_hermes_home() |
| #188 | if not hermes_home: |
| #189 | print("❌ Hermes not found.") |
| #190 | return |
| #191 | |
| #192 | target = hermes_home / "plugins" / "mnemosyne" |
| #193 | if target.exists() or target.is_symlink(): |
| #194 | if target.is_symlink(): |
| #195 | target.unlink() |
| #196 | else: |
| #197 | import shutil |
| #198 | shutil.rmtree(target) |
| #199 | print(f"🗑️ Removed {target}") |
| #200 | else: |
| #201 | print("ℹ️ Clawd Memory plugin not found in Hermes.") |
| #202 | |
| #203 | # Reset config |
| #204 | config_path = hermes_home / "config.yaml" |
| #205 | if config_path.exists(): |
| #206 | text = config_path.read_text(encoding="utf-8") |
| #207 | if "provider: mnemosyne" in text: |
| #208 | new_text = text.replace("provider: mnemosyne", "provider: null") |
| #209 | config_path.write_text(new_text, encoding="utf-8") |
| #210 | print("✅ Reset memory.provider to null") |
| #211 | |
| #212 | print("\n✅ Clawd Memory uninstalled. Hermes will use built-in memory.") |
| #213 | |
| #214 | |
| #215 | if __name__ == "__main__": |
| #216 | import argparse |
| #217 | parser = argparse.ArgumentParser(description="Clawd Memory Hermes Installer") |
| #218 | parser.add_argument("--uninstall", action="store_true", help="Remove Clawd Memory from Hermes") |
| #219 | args = parser.parse_args() |
| #220 | |
| #221 | if args.uninstall: |
| #222 | uninstall() |
| #223 | else: |
| #224 | install() |
| #225 |