mirror of
https://github.com/cexll/myclaude.git
synced 2026-03-02 15:23:16 +08:00
feat: add harness skill with hooks install/uninstall support (#156)
Add multi-session autonomous agent harness with progress checkpointing, failure recovery, task dependencies, and post-completion self-reflection. - Add harness module to config.json (copy_dir with hooks.json) - Add 7 hook scripts: stop, sessionstart, teammateidle, subagentstop, claim, renew, self-reflect-stop + shared _harness_common.py - Fix self-reflect-stop: only triggers when harness was initialized (checks harness-tasks.json existence), not on every session - Add unmerge_hooks_from_settings() to uninstall.py for clean hook removal - Add unit tests (57 tests) and E2E test (100 tasks + 5 self-reflect) Generated with SWE-Agent.ai Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
This commit is contained in:
42
uninstall.py
42
uninstall.py
@@ -12,6 +12,7 @@ from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, Set
|
||||
|
||||
DEFAULT_INSTALL_DIR = "~/.claude"
|
||||
SETTINGS_FILE = "settings.json"
|
||||
|
||||
# Files created by installer itself (not by modules)
|
||||
INSTALLER_FILES = ["install.log", "installed_modules.json", "installed_modules.json.bak"]
|
||||
@@ -80,6 +81,42 @@ def load_config(install_dir: Path) -> Dict[str, Any]:
|
||||
return {}
|
||||
|
||||
|
||||
def unmerge_hooks_from_settings(module_name: str, install_dir: Path) -> bool:
|
||||
"""Remove hooks tagged with __module__=module_name from settings.json."""
|
||||
settings_path = install_dir / SETTINGS_FILE
|
||||
if not settings_path.exists():
|
||||
return False
|
||||
|
||||
try:
|
||||
with settings_path.open("r", encoding="utf-8") as f:
|
||||
settings = json.load(f)
|
||||
except (json.JSONDecodeError, OSError):
|
||||
return False
|
||||
|
||||
if "hooks" not in settings:
|
||||
return False
|
||||
|
||||
modified = False
|
||||
for hook_type in list(settings["hooks"].keys()):
|
||||
original_len = len(settings["hooks"][hook_type])
|
||||
settings["hooks"][hook_type] = [
|
||||
entry for entry in settings["hooks"][hook_type]
|
||||
if entry.get("__module__") != module_name
|
||||
]
|
||||
if len(settings["hooks"][hook_type]) < original_len:
|
||||
modified = True
|
||||
# Remove empty hook type arrays
|
||||
if not settings["hooks"][hook_type]:
|
||||
del settings["hooks"][hook_type]
|
||||
|
||||
if modified:
|
||||
with settings_path.open("w", encoding="utf-8") as f:
|
||||
json.dump(settings, f, indent=2, ensure_ascii=False)
|
||||
f.write("\n")
|
||||
|
||||
return modified
|
||||
|
||||
|
||||
def get_module_files(module_name: str, config: Dict[str, Any]) -> Set[str]:
|
||||
"""Extract files/dirs that a module installs based on config.json operations."""
|
||||
files: Set[str] = set()
|
||||
@@ -261,6 +298,11 @@ def main(argv: Optional[List[str]] = None) -> int:
|
||||
except OSError as e:
|
||||
print(f" ✗ Failed to remove {item}: {e}", file=sys.stderr)
|
||||
|
||||
# Remove module hooks from settings.json
|
||||
for m in selected:
|
||||
if unmerge_hooks_from_settings(m, install_dir):
|
||||
print(f" ✓ Removed hooks for module '{m}' from settings.json")
|
||||
|
||||
# Update installed_modules.json
|
||||
status_file = install_dir / "installed_modules.json"
|
||||
if status_file.exists() and selected != list(installed_modules.keys()):
|
||||
|
||||
Reference in New Issue
Block a user