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:
203
send_to_claude.py
Executable file
203
send_to_claude.py
Executable 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()
|
||||
Reference in New Issue
Block a user