macro_manager:
- All macro reads/writes guarded by a lock; macros.json written atomically
(temp + fsync + os.replace). Commands are copied under the lock and executed
outside it so wait/keyboard steps don't block other threads.
- last_used disk writes debounced (>=5s) instead of a full rewrite per press.
- Validate key/hotkey names against pyautogui.KEYBOARD_KEYS and clamp wait ms;
invalid input is skipped/logged, not blindly executed.
web_server:
- WebSocket receive loop always disconnects (fixes dead-socket leak); broadcast
prunes failed sockets.
- POST /api/execute offloaded to a thread executor so a long macro no longer
blocks the event loop.
- Image upload hardened: 5MB cap (413), real-image validation via Pillow,
server-generated name under macro_images/, returns a relative path only,
cleans up on failure.
gui:
- Execute macros off the Qt main thread (signal back to status bar); debounce
resizeEvent and only rebuild when the column count changes.
- Relay password stored in the OS keyring when available (plaintext JSON blanked;
graceful fallback if no backend); delete dialogs name the macro; honor the
minimize-to-tray setting; surface save failures.
- Add media/system keys (volume, play/pause, track nav) to the macro editor.
- THEME gains shared danger/accent-hover colors; drop dead imports.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>