#!/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()