fix: stop hook schema, uninstall cleanup, and README architecture note

- Fix session-stop.sh in 0.1.0 cache to use systemMessage instead of
  hookSpecificOutput (Stop hook schema doesn't support hookSpecificOutput)
- Remove debug scaffolding from post-tool-use.py
- Installer: pre-create hook_debug.log so sandbox can write to it;
  uninstall now removes marketplace plugin symlink
- README: clarify extension vs mod architecture, fix cache path in
  install description
This commit is contained in:
pyr0ball 2026-04-01 22:49:12 -07:00
parent 507a2fc4a9
commit e2a4b66267
3 changed files with 34 additions and 4 deletions

View file

@ -1,9 +1,11 @@
# 🐾 Buddymon
A Claude Code plugin that turns your coding sessions into a creature-collecting game.
A Claude Code **extension** that turns your coding sessions into a creature-collecting game.
Buddymon are discovered, caught, and leveled up through real development work — not separate from it.
> **How it works:** Buddymon uses Claude Code's hook and plugin system — it is not a UI mod. Notifications (encounters, XP, session summaries) appear as system-injected context in the chat thread. They are visible to Claude and displayed in the conversation, but do not appear in a separate UI widget. This is a deliberate constraint of CC's extension API.
---
## What it does
@ -40,8 +42,9 @@ Then **restart Claude Code** and run:
```
The install script:
- Symlinks the repo into `~/.claude/plugins/cache/local/buddymon/0.1.0/`
- Registers the plugin in `~/.claude/plugins/installed_plugins.json`
- Creates a local `circuitforge` marketplace under `~/.claude/plugins/marketplaces/circuitforge/` (required — CC validates plugin names against the marketplace index)
- Symlinks the repo into `~/.claude/plugins/cache/circuitforge/buddymon/<version>/`
- Registers the plugin in `~/.claude/plugins/installed_plugins.json` and `~/.claude/plugins/known_marketplaces.json`
- Enables it in `~/.claude/settings.json`
- Creates `~/.claude/buddymon/` state directory with initial JSON files

View file

@ -18,6 +18,7 @@ import re
import sys
import random
from pathlib import Path
from datetime import datetime
PLUGIN_ROOT = os.environ.get("CLAUDE_PLUGIN_ROOT", str(Path(__file__).parent.parent))
BUDDYMON_DIR = Path.home() / ".claude" / "buddymon"
@ -280,9 +281,22 @@ def main():
if tool_name == "Bash":
output = ""
if isinstance(tool_response, dict):
output = tool_response.get("output", "") or tool_response.get("content", "")
# CC may use any of these keys; combine all text fields
parts = [
tool_response.get("output", ""),
tool_response.get("content", ""),
tool_response.get("stderr", ""),
tool_response.get("text", ""),
]
output = "\n".join(p for p in parts if isinstance(p, str) and p)
elif isinstance(tool_response, str):
output = tool_response
elif isinstance(tool_response, list):
# Array of content blocks: [{"type": "text", "text": "..."}]
output = "\n".join(
b.get("text", "") for b in tool_response
if isinstance(b, dict) and b.get("type") == "text"
)
existing = get_active_encounter()

View file

@ -96,6 +96,13 @@ if '${MARKETPLACE}' in d:
PYEOF
fi
# Remove marketplace plugin symlink (leave marketplace dir in case other CF plugins exist)
MARKETPLACE_PLUGIN_LINK="${PLUGINS_DIR}/marketplaces/${MARKETPLACE}/plugins/${PLUGIN_NAME}"
if [[ -L "${MARKETPLACE_PLUGIN_LINK}" ]]; then
rm "${MARKETPLACE_PLUGIN_LINK}"
ok "Removed marketplace plugin symlink"
fi
echo ""
echo "${PLUGIN_KEY} uninstalled. Restart Claude Code to apply."
}
@ -263,6 +270,12 @@ for name, default in files.items():
print(f" Created {name}")
else:
print(f" {name} already exists — kept")
# Pre-create hook_debug.log so the hook sandbox can write to it
log_path = os.path.join(d, 'hook_debug.log')
if not os.path.exists(log_path):
open(log_path, 'w').close()
print(" Created hook_debug.log")
PYEOF
echo ""