buddymon/hooks-handlers/roster-stop.py
pyr0ball a42c003202 fix: structured roster, stop-hook delivery, stale buddy guard
Roster (cli.py):
- Fully restructured cmd_roster with four clearly-labelled sections:
  BUDDYMON (✓ levels via XP), LANGUAGE MASCOTS (✓ levels via XP),
  LANGUAGE AFFINITIES (◑ passive), BUG TROPHY CASE (✗ trophies only)
- Evolution chain shown inline per-buddy (Debuglin → [Verifex] → Veritarch)
- Active buddy marked ← ACTIVE; next-evo target with levels-to-go
- Language affinities show element + 🦎 tag when a mascot is available
- Bug trophy grid: two-column, element tags, notable levels shown
- Writes roster_pending.txt to trigger Stop hook delivery (no truncation)

Stop hook (roster-stop.py + hooks.json):
- New Stop hook reads roster_pending.txt; runs cli.py roster; emits full
  output as additionalContext; clears the flag — fires once per invocation
- Avoids Bash tool result truncation for long roster output

Bug fixes (post-tool-use.py):
- get_session_state(): fall through to active.json when buddymon_id is null
  or missing (pgrp mismatch between CLI process and hook process)
- get_active_buddy_id(): guard against caught_bug_monster type slipping in
  as the active buddy (ThrottleDemon state corruption fix)
- Language "new territory" message now uses affinity XP == 0 as the sole
  signal — drops volatile session.json languages_seen check that caused
  spurious "New language spotted" fires across sessions
- Already-owned encounter shortcut: instant dismiss with no wound cycle
2026-04-12 18:36:23 -07:00

52 lines
1.1 KiB
Python

#!/usr/bin/env python3
"""
Buddymon Stop hook — roster re-emitter.
Checks for roster_pending.txt written by `cli.py roster`.
If present, runs the roster CLI and emits full output as additionalContext,
guaranteeing the full roster is visible without Bash-tool truncation.
"""
import json
import os
import subprocess
import sys
from pathlib import Path
BUDDYMON_DIR = Path.home() / ".claude" / "buddymon"
PENDING_FLAG = BUDDYMON_DIR / "roster_pending.txt"
CLI = BUDDYMON_DIR / "cli.py"
def main():
try:
json.load(sys.stdin)
except Exception:
pass
if not PENDING_FLAG.exists():
sys.exit(0)
PENDING_FLAG.unlink(missing_ok=True)
if not CLI.exists():
sys.exit(0)
result = subprocess.run(
["python3", str(CLI), "roster"],
capture_output=True, text=True, timeout=10,
)
output = result.stdout.strip()
if not output:
sys.exit(0)
print(json.dumps({
"hookSpecificOutput": {
"hookEventName": "Stop",
"additionalContext": output,
}
}))
sys.exit(0)
if __name__ == "__main__":
main()