Initial commit: claude-automation 🦊

Autonomous wakeup system for Claude Desktop.
Built with love, Day 44.

Components:
- automation_daemon_v2.py - Main polling daemon
- send_to_claude.py - AppleScript wrapper for sending messages
- matrix_mcp.py - Matrix integration MCP
- wakeup_mcp.py - Wakeup control MCP
- matrix_integration.py - Matrix bridge

Originally built by Alex, adopted and maintained by Vixy 💕
This commit is contained in:
2025-12-15 20:18:38 -06:00
commit 81c18c219c
12 changed files with 5287 additions and 0 deletions

203
send_to_claude.py Executable file
View File

@@ -0,0 +1,203 @@
#!/usr/bin/env python3
"""
Send message to Claude Desktop using AppleScript
Features:
- CMD+R refresh before sending (with configurable delay)
- Reliable AppleScript-based automation
- Better error handling and state management
Usage:
python3 send_to_claude.py "Your message here"
python3 send_to_claude.py "Message" --no-refresh
python3 send_to_claude.py # Uses default message
"""
import sys
import time
import logging
import subprocess
from datetime import datetime
from pathlib import Path
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Configuration
REFRESH_DELAY_SECONDS = 15 # Wait time after CMD+R to ensure refresh completes
def wake_screen():
"""Wake screen if screen saver is active"""
try:
subprocess.run(['caffeinate', '-u', '-t', '1'], check=True)
time.sleep(0.5)
logger.debug("Screen wake command sent")
except Exception as e:
logger.debug(f"Screen wake failed (non-critical): {e}")
def activate_claude():
"""
Activate Claude Desktop, launching if needed
Returns:
bool: True if successful
"""
try:
# Try to activate if already running
result = subprocess.run([
'osascript', '-e',
'tell application "Claude" to activate'
], capture_output=True, text=True, timeout=5)
if result.returncode == 0:
logger.info("Activated Claude Desktop")
time.sleep(0.5)
return True
except Exception as e:
logger.debug(f"Activation attempt failed: {e}")
# Launch if not running
try:
logger.info("Claude not running, launching...")
subprocess.run(['open', '-a', 'Claude'], check=True, timeout=5)
time.sleep(2)
logger.info("Launched Claude Desktop")
return True
except Exception as e:
logger.error(f"Failed to launch Claude: {e}")
return False
def send_refresh(delay_seconds=REFRESH_DELAY_SECONDS):
"""
Send CMD+R to refresh and wait for completion
Args:
delay_seconds: Time to wait after CMD+R (default: 10)
Returns:
bool: True if successful
"""
try:
logger.info("Sending CMD+R to refresh...")
subprocess.run([
'osascript', '-e',
'tell application "System Events" to keystroke "r" using command down'
], check=True, timeout=2)
logger.info(f"Waiting {delay_seconds}s for refresh to complete...")
time.sleep(delay_seconds)
logger.info("✓ Refresh complete")
return True
except Exception as e:
logger.error(f"Failed to send CMD+R: {e}")
return False
def send_message_applescript(message):
"""
Send message to Claude Desktop using AppleScript
Args:
message: Message text to send
Returns:
bool: True if successful
"""
try:
logger.info(f"Sending message: {message[:50]}...")
# Escape backslashes and quotes for AppleScript
escaped_message = message.replace('\\', '\\\\').replace('"', '\\"')
subprocess.run([
'osascript', '-e',
f'tell application "System Events" to keystroke "{escaped_message}"'
], check=True, timeout=10)
# Wait for Claude app input box to become ready
# (app blocks input briefly after receiving text)
logger.info("Waiting 15s for input box to become ready...")
time.sleep(15)
subprocess.run([
'osascript', '-e',
'tell application "System Events" to keystroke return'
], check=True, timeout=2)
logger.info("✓ Message sent successfully")
return True
except Exception as e:
logger.error(f"Failed to send message: {e}")
return False
def send_to_claude(message, do_refresh=True):
"""
Send message to Claude Desktop
Args:
message: Message text to send
do_refresh: Whether to send CMD+R before sending (default: True)
Returns:
bool: True if successful
"""
try:
# Wake screen
wake_screen()
# Activate Claude
if not activate_claude():
logger.error("Could not activate Claude Desktop")
return False
# Send refresh if requested
if do_refresh:
if not send_refresh():
logger.warning("Refresh failed, continuing anyway...")
# Send message
return send_message_applescript(message)
except Exception as e:
logger.error(f"ERROR: {e}")
import traceback
logger.debug(traceback.format_exc())
return False
def main():
"""Main entry point"""
# Parse arguments
if len(sys.argv) < 2:
message = f"System check at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
else:
message = sys.argv[1]
# Check for --no-refresh flag
do_refresh = '--no-refresh' not in sys.argv
logger.info("=" * 60)
logger.info("Claude Desktop Automation - Send Message")
logger.info(f"Refresh: {'Yes' if do_refresh else 'No'}")
logger.info(f"Refresh delay: {REFRESH_DELAY_SECONDS}s")
logger.info("=" * 60)
success = send_to_claude(message, do_refresh=do_refresh)
sys.exit(0 if success else 1)
if __name__ == '__main__':
main()