workstation: harden memory hooks — prune dead plugin refs + homelab-CLI-only store
All checks were successful
ci/woodpecker/push/default Pipeline was successful
All checks were successful
ci/woodpecker/push/default Pipeline was successful
wire-memory-hooks.py now PRUNES any settings.json hook still pointing at the retired claude-memory plugin (plugins/claude-memory/hooks/) before the additive pass. install_memory() rm -rf's that dir, so those entries are dangling — and a missing UserPromptSubmit hook exits 2, a BLOCKING error that erases the prompt and froze emo's sessions (2026-06-22). The plugin shares basenames with the homelab hooks, so the old additive-only logic saw the dead plugin path as "already present" and skipped installing the real ~/.claude/hooks/ copy; pruning first fixes that. Verified against emo's exact original config: yields the correct 4-hook set, drops the dead PermissionRequest entry, idempotent on rerun. auto-learn.py now stores via the `homelab memory` CLI only — dropped the direct HTTP path and the local-SQLite fallback (memory is homelab-CLI-only per Viktor; never local files). No-ops silently when no API key is in env (e.g. ancamilea). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
aeed461591
commit
2169e0de5f
2 changed files with 58 additions and 55 deletions
|
|
@ -1,11 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Wire the homelab-memory hooks into a user's ~/.claude/settings.json, if-absent.
|
||||
"""Wire the homelab-memory hooks into a user's ~/.claude/settings.json.
|
||||
|
||||
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.
|
||||
Two passes, idempotent, never touching `env` (the per-user MEMORY_API_KEY) or any
|
||||
other setting:
|
||||
(0) PRUNE any hook command still pointing at the retired claude-memory plugin
|
||||
(`plugins/claude-memory/hooks/`). install_memory() rm -rf's that dir, so
|
||||
those entries are dangling — and a missing UserPromptSubmit hook exits 2,
|
||||
a BLOCKING error that erases the prompt and freezes the session (devvm emo
|
||||
incident 2026-06-22). Must run BEFORE the additive pass: the plugin shares
|
||||
basenames with the homelab hooks, so without pruning, the "already present"
|
||||
check below matches the dead plugin path and skips the real install.
|
||||
(1) ADD each homelab hook group when no existing command references its script.
|
||||
|
||||
Usage: wire-memory-hooks.py <home_dir>
|
||||
Exit 0 on success (changed or already-present); 1 only on an unreadable settings file.
|
||||
|
|
@ -38,6 +44,28 @@ except (json.JSONDecodeError, OSError) as e:
|
|||
|
||||
hooks = data.setdefault("hooks", {})
|
||||
changed = False
|
||||
|
||||
# (0) Prune dead claude-memory plugin hooks (see module docstring). Must precede
|
||||
# the additive pass so shared basenames don't mask a needed install.
|
||||
DEAD_REF = "plugins/claude-memory/hooks/"
|
||||
for event in list(hooks.keys()):
|
||||
new_groups = []
|
||||
removed_any = False
|
||||
for g in (hooks.get(event) or []):
|
||||
original = g.get("hooks") or []
|
||||
kept = [h for h in original if DEAD_REF not in (h.get("command", "") or "")]
|
||||
if len(kept) != len(original):
|
||||
removed_any = True
|
||||
if kept:
|
||||
new_groups.append({**g, "hooks": kept})
|
||||
if removed_any:
|
||||
changed = True
|
||||
if new_groups:
|
||||
hooks[event] = new_groups
|
||||
else:
|
||||
del hooks[event]
|
||||
|
||||
# (1) Additively wire each homelab hook, if no command already references it.
|
||||
for event, basename, command, extra in WANT:
|
||||
groups = hooks.setdefault(event, [])
|
||||
already = any(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue