infra/scripts/workstation/claude-hooks/wire-memory-hooks.py

63 lines
2.2 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
"""Wire the homelab-memory hooks into a user's ~/.claude/settings.json, if-absent.
Part of the claude-memory MCP -> homelab CLI migration (all-users rollout).
Idempotent + ADDITIVE: only ADDS a hook group when no existing command references
that hook script. Never removes/reorders existing hooks, and never touches `env`
(the per-user MEMORY_API_KEY) or any other setting. Safe to run on every reconcile
and on a user's already-populated config.
Usage: wire-memory-hooks.py <home_dir>
Exit 0 on success (changed or already-present); 1 only on an unreadable settings file.
"""
import json
import os
import sys
home = sys.argv[1]
settings = os.path.join(home, ".claude", "settings.json")
hooks_dir = os.path.join(home, ".claude", "hooks")
# (event, script-basename used for the if-absent check, full command, extra fields)
WANT = [
("PreCompact", "pre-compact-backup.sh", f"{hooks_dir}/pre-compact-backup.sh", {"timeout": 30}),
("UserPromptSubmit", "post-compact-recovery.sh", f"{hooks_dir}/post-compact-recovery.sh", {"timeout": 10}),
("UserPromptSubmit", "homelab-memory-recall.py", f"python3 {hooks_dir}/homelab-memory-recall.py", {"timeout": 8}),
("Stop", "auto-learn.py", f"python3 {hooks_dir}/auto-learn.py", {"async": True}),
]
try:
if os.path.exists(settings) and os.path.getsize(settings) > 0:
with open(settings) as fh:
data = json.load(fh)
else:
data = {}
except (json.JSONDecodeError, OSError) as e:
print(f"ERROR: cannot read {settings}: {e}", file=sys.stderr)
sys.exit(1)
hooks = data.setdefault("hooks", {})
changed = False
for event, basename, command, extra in WANT:
groups = hooks.setdefault(event, [])
already = any(
basename in (h.get("command", "") or "")
for g in groups
for h in (g.get("hooks", []) or [])
)
if already:
continue
entry = {"type": "command", "command": command}
entry.update(extra)
groups.append({"hooks": [entry]})
changed = True
if changed:
tmp = settings + ".tmp"
with open(tmp, "w") as fh:
json.dump(data, fh, indent=2)
os.replace(tmp, settings)
print(f"wired memory hooks -> {settings}")
else:
print(f"memory hooks already present -> {settings} (no change)")