Migrate to per-agent subdirectories, uniform 8-agent support, cross-platform fixes
- All paths use ~/.elydora/{agentId}/ per-agent isolation
- Add copilot, letta plugins; split kiro into kirocli + kiroide
- Remove augment (SDK-only agent, not one-click)
- Fix guard command: use sys.executable instead of hardcoded python3
- Fix chmod wrapped in try/except for Windows compatibility
- Fix OpenCode chain state: save after HTTP 2xx response
- Fix guard script shebang consistency (sys.executable)
- Uniform 8 agents: claudecode, cursor, gemini, kirocli, kiroide, opencode, copilot, letta
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
eef18a8520
commit
5b92a1dfa3
14 files changed
+973
-259
No files matched your search
+51
-16
@@ -7,7 +7,10 @@ Uses only stdlib argparse — zero external dependencies for the CLI itself.
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
from typing import Dict, Type
|
||||
|
||||
@@ -16,19 +19,23 @@ from .plugins.base import AgentPlugin, InstallConfig
|
||||
from .plugins.registry import SUPPORTED_AGENTS, get_agent_names
|
||||
from .plugins.hook_template import generate_guard_script
|
||||
from .plugins.claudecode import ClaudeCodePlugin
|
||||
from .plugins.copilot import CopilotPlugin
|
||||
from .plugins.cursor import CursorPlugin
|
||||
from .plugins.gemini import GeminiPlugin
|
||||
from .plugins.augment import AugmentPlugin
|
||||
from .plugins.kiro import KiroPlugin
|
||||
from .plugins.kirocli import KiroCliPlugin
|
||||
from .plugins.kiroide import KiroIdePlugin
|
||||
from .plugins.letta import LettaPlugin
|
||||
from .plugins.opencode import OpenCodePlugin
|
||||
|
||||
|
||||
PLUGIN_MAP: Dict[str, Type[AgentPlugin]] = {
|
||||
"claudecode": ClaudeCodePlugin,
|
||||
"copilot": CopilotPlugin,
|
||||
"cursor": CursorPlugin,
|
||||
"gemini": GeminiPlugin,
|
||||
"augment": AugmentPlugin,
|
||||
"kiro": KiroPlugin,
|
||||
"kirocli": KiroCliPlugin,
|
||||
"kiroide": KiroIdePlugin,
|
||||
"letta": LettaPlugin,
|
||||
"opencode": OpenCodePlugin,
|
||||
}
|
||||
|
||||
@@ -56,11 +63,13 @@ def cmd_install(args: argparse.Namespace) -> None:
|
||||
|
||||
print(f"Verified key pair (public key: {pub[:16]}...)")
|
||||
|
||||
# Create per-agent directory under ~/.elydora/{agent_id}/
|
||||
agent_dir = os.path.join(os.path.expanduser("~"), ".elydora", args.agent_id)
|
||||
os.makedirs(agent_dir, exist_ok=True)
|
||||
|
||||
# Generate and write the guard script
|
||||
guard_dir = os.path.join(os.path.expanduser("~"), ".elydora", "hooks")
|
||||
os.makedirs(guard_dir, exist_ok=True)
|
||||
guard_script_path = os.path.join(guard_dir, f"{agent_name}-guard.py")
|
||||
guard_script = generate_guard_script(agent_name)
|
||||
guard_script_path = os.path.join(agent_dir, "guard.py")
|
||||
guard_script = generate_guard_script(agent_name, args.agent_id)
|
||||
with open(guard_script_path, "w", encoding="utf-8") as f:
|
||||
f.write(guard_script)
|
||||
try:
|
||||
@@ -73,6 +82,7 @@ def cmd_install(args: argparse.Namespace) -> None:
|
||||
config: InstallConfig = {
|
||||
"org_id": args.org_id,
|
||||
"agent_id": args.agent_id,
|
||||
"agent_name": agent_name,
|
||||
"private_key": args.private_key,
|
||||
"kid": args.kid,
|
||||
"base_url": args.base_url,
|
||||
@@ -88,15 +98,39 @@ def cmd_install(args: argparse.Namespace) -> None:
|
||||
def cmd_uninstall(args: argparse.Namespace) -> None:
|
||||
"""Handle the 'uninstall' subcommand."""
|
||||
plugin = _get_plugin(args.agent)
|
||||
plugin.uninstall()
|
||||
agent_id = getattr(args, "agent_id", None) or ""
|
||||
plugin.uninstall(agent_id=agent_id)
|
||||
|
||||
# Remove the guard script
|
||||
guard_script_path = os.path.join(
|
||||
os.path.expanduser("~"), ".elydora", "hooks", f"{args.agent}-guard.py"
|
||||
)
|
||||
if os.path.exists(guard_script_path):
|
||||
os.remove(guard_script_path)
|
||||
print(f" Removed guard script: {guard_script_path}")
|
||||
# Determine which agent directory to remove
|
||||
elydora_dir = os.path.join(os.path.expanduser("~"), ".elydora")
|
||||
agent_id = getattr(args, "agent_id", None)
|
||||
|
||||
if not agent_id:
|
||||
# Scan ~/.elydora/*/config.json for matching agent_name
|
||||
pattern = os.path.join(elydora_dir, "*", "config.json")
|
||||
for config_path in glob.glob(pattern):
|
||||
try:
|
||||
with open(config_path, "r", encoding="utf-8") as f:
|
||||
cfg = json.load(f)
|
||||
if cfg.get("agent_name") == args.agent:
|
||||
agent_id = cfg.get("agent_id")
|
||||
break
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if agent_id:
|
||||
agent_dir = os.path.join(elydora_dir, agent_id)
|
||||
if os.path.isdir(agent_dir):
|
||||
shutil.rmtree(agent_dir)
|
||||
print(f" Removed agent directory: {agent_dir}")
|
||||
else:
|
||||
# Fallback: try to remove legacy guard script location
|
||||
guard_script_path = os.path.join(
|
||||
elydora_dir, "hooks", f"{args.agent}-guard.py"
|
||||
)
|
||||
if os.path.exists(guard_script_path):
|
||||
os.remove(guard_script_path)
|
||||
print(f" Removed guard script: {guard_script_path}")
|
||||
|
||||
|
||||
def cmd_status(args: argparse.Namespace) -> None:
|
||||
@@ -144,6 +178,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
# uninstall
|
||||
uninstall_parser = subparsers.add_parser("uninstall", help="Uninstall audit hook for an agent")
|
||||
uninstall_parser.add_argument("--agent", required=True, help="Agent name")
|
||||
uninstall_parser.add_argument("--agent_id", default=None, help="Agent ID (if omitted, scans config files for matching agent name)")
|
||||
|
||||
# status
|
||||
subparsers.add_parser("status", help="Show installation status of all agents")
|
||||
|
||||
Reference in new issue
Block a user