stop.py 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. #!/usr/bin/env python3
  2. """Stop hook executor for hookify plugin.
  3. This script is called by Claude Code when agent wants to stop.
  4. It reads .claude/hookify.*.local.md files and evaluates stop rules.
  5. """
  6. import os
  7. import sys
  8. import json
  9. # CRITICAL: Add plugin root to Python path for imports
  10. PLUGIN_ROOT = os.environ.get('CLAUDE_PLUGIN_ROOT')
  11. if PLUGIN_ROOT:
  12. parent_dir = os.path.dirname(PLUGIN_ROOT)
  13. if parent_dir not in sys.path:
  14. sys.path.insert(0, parent_dir)
  15. if PLUGIN_ROOT not in sys.path:
  16. sys.path.insert(0, PLUGIN_ROOT)
  17. try:
  18. from hookify.core.config_loader import load_rules
  19. from hookify.core.rule_engine import RuleEngine
  20. except ImportError as e:
  21. error_msg = {"systemMessage": f"Hookify import error: {e}"}
  22. print(json.dumps(error_msg), file=sys.stdout)
  23. sys.exit(0)
  24. def main():
  25. """Main entry point for Stop hook."""
  26. try:
  27. # Read input from stdin
  28. input_data = json.load(sys.stdin)
  29. # Load stop rules
  30. rules = load_rules(event='stop')
  31. # Evaluate rules
  32. engine = RuleEngine()
  33. result = engine.evaluate_rules(rules, input_data)
  34. # Always output JSON (even if empty)
  35. print(json.dumps(result), file=sys.stdout)
  36. except Exception as e:
  37. # On any error, allow the operation
  38. error_output = {
  39. "systemMessage": f"Hookify error: {str(e)}"
  40. }
  41. print(json.dumps(error_output), file=sys.stdout)
  42. finally:
  43. # ALWAYS exit 0
  44. sys.exit(0)
  45. if __name__ == '__main__':
  46. main()