From 8d6a681baa2033c95726409a769d66af0150e659 Mon Sep 17 00:00:00 2001 From: Aodhan Collins Date: Mon, 6 Oct 2025 21:08:25 +0100 Subject: [PATCH] Phase 2 complete. --- .dev/run.pid | 1 + .env.example | 11 +- README.md | 105 +++- docs/SCRIPTS.md | 201 +++++++ docs/planning/PHASE2_COMPLETE.md | 71 +-- docs/releases/CHANGELOG.md | 21 +- docs/setup/DEV_SETUP.md | 308 +++++++++++ kill.ps1 | 180 +++++++ kill.sh | 123 +++++ package.json | 2 +- run.ps1 | 75 +++ run.sh | 50 ++ setup.ps1 | 439 +++++++++++++++ setup.sh | 441 ++++++++++++++++ src-tauri/Cargo.lock | 850 ++++++++++++++++++++++++++++-- src-tauri/Cargo.toml | 2 +- src-tauri/src/main.rs | 56 +- src-tauri/tauri.conf.json | 8 +- src/App.tsx | 20 +- src/components/ChatInterface.tsx | 11 +- src/components/SettingsPanel.tsx | 126 ++++- src/components/WindowControls.tsx | 30 ++ src/lib/openrouter.ts | 7 +- src/lib/systemIntegration.ts | 43 ++ src/lib/tts.ts | 136 +++-- src/stores/settingsStore.ts | 10 + 26 files changed, 3163 insertions(+), 164 deletions(-) create mode 100644 .dev/run.pid create mode 100644 docs/SCRIPTS.md create mode 100644 docs/setup/DEV_SETUP.md create mode 100644 kill.ps1 create mode 100755 kill.sh create mode 100644 run.ps1 create mode 100755 run.sh create mode 100644 setup.ps1 create mode 100755 setup.sh create mode 100644 src/components/WindowControls.tsx create mode 100644 src/lib/systemIntegration.ts diff --git a/.dev/run.pid b/.dev/run.pid new file mode 100644 index 0000000..e8e4d40 --- /dev/null +++ b/.dev/run.pid @@ -0,0 +1 @@ +223036 diff --git a/.env.example b/.env.example index c18a7ad..99da9c4 100644 --- a/.env.example +++ b/.env.example @@ -3,13 +3,8 @@ # OpenRouter API Key (unified access to GPT-4, Claude, Llama, and more) # Get your key at: https://openrouter.ai/keys -VITE_OPENROUTER_API_KEY=sk-or-v1-your-key-here +OPENROUTER_API_KEY=sk-or-v1-your-key-here # ElevenLabs API Key (for text-to-speech) -VITE_ELEVENLABS_API_KEY=your-key-here - -# Optional: OpenAI API Key (for Whisper STT if not using local) -VITE_OPENAI_API_KEY=sk-your-key-here - -# Development Settings -VITE_DEBUG_MODE=true +# Get your key at: https://elevenlabs.io +ELEVENLABS_API_KEY=your-elevenlabs-key-here diff --git a/README.md b/README.md index 989d258..27e5950 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,12 @@ A sophisticated local-first desktop AI assistant with modular personality system, multi-model support, and seamless integration with your development environment. -> **Current Version**: 0.1.0 -> **Status**: ✅ Phase 1 Complete - Core functionality stable and ready to use +> **Current Version**: 0.2.0 +> **Status**: ✅ Phase 2 Complete - Enhanced multimodal assistant with voice, files, and system integration ## ✨ Features -### ✅ Implemented (v0.1.0) +### ✅ Implemented (v0.2.0) - **🤖 Multi-Model AI Chat** - Full-featured chat interface with conversation history @@ -33,13 +33,43 @@ A sophisticated local-first desktop AI assistant with modular personality system - Conversation management (clear history) - Persistent settings across sessions +- **🗣️ Voice Integration (NEW in v0.2.0)** + - Text-to-Speech with ElevenLabs API and browser fallback + - Speech-to-Text with Web Speech API (25+ languages) + - Audio conversation mode for hands-free interaction + - Per-message voice controls + +- **📁 File Attachment Support (NEW in v0.2.0)** + - Drag & drop file upload + - Support for images, PDFs, text files, and code + - Preview thumbnails and content + - AI can analyze and discuss attached files + +- **💾 Conversation Management (NEW in v0.2.0)** + - Save and load conversations + - Export to Markdown, JSON, or TXT + - Search and filter saved conversations + - Tag and organize conversation history + +- **🎨 Advanced Formatting (NEW in v0.2.0)** + - Markdown with GitHub Flavored Markdown + - Syntax highlighting for code blocks + - LaTeX math equation rendering + - Mermaid diagrams for flowcharts + +- **🖥️ System Integration (NEW in v0.2.0)** + - System tray icon for quick access + - Global keyboard shortcut (Ctrl+Shift+E / Cmd+Shift+E) + - Desktop notifications for responses + - Minimize to tray functionality + ### 🚧 Planned Features See [Roadmap](./docs/planning/ROADMAP.md) for the complete development plan: -- **Phase 2**: Voice integration (TTS/STT), file attachments, advanced formatting -- **Phase 3**: Knowledge base, long-term memory, multi-modal capabilities +- **Phase 3** (Next): Knowledge base, long-term memory, multi-modal capabilities - **Phase 4**: Developer tools, plugin system, multi-device sync +- **Long-term**: Avatar system, screen/audio monitoring, gaming integration ## Tech Stack @@ -114,6 +144,42 @@ xcode-select --install - Install [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) - Install [WebView2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/) +## Quick Start + +### Option 1: Automated Setup (Recommended) + +Use the setup script to automatically install dependencies: + +**Linux/macOS:** +```bash +./setup.sh +``` + +**Windows:** +```powershell +.\setup.ps1 +``` + +The script will guide you through installing Node.js, Rust, and system dependencies. + +### Option 2: Development Scripts + +Once setup is complete, use these convenient scripts: + +**Start the app:** +```bash +./run.sh # Linux/macOS +.\run.ps1 # Windows +``` + +**Stop the app:** +```bash +./kill.sh # Linux/macOS +.\kill.ps1 # Windows +``` + +See [SCRIPTS.md](./docs/SCRIPTS.md) for detailed script documentation. + ## Getting Started ### 1. Install Dependencies @@ -250,15 +316,26 @@ All core features are implemented and stable: - ✅ Linux graphics compatibility fixes - ✅ Clean, modern UI with dark mode -### 🚀 Next: Phase 2 - Enhanced Capabilities (v0.2.0) +### ✅ Phase 2 Complete - Enhanced Capabilities (v0.2.0) + +All Phase 2 features are production-ready: + +- ✅ Voice integration (TTS with ElevenLabs, STT with Web Speech API) +- ✅ File attachment support (images, PDFs, code, text files) +- ✅ Advanced message formatting (syntax highlighting, LaTeX, Mermaid diagrams) +- ✅ System integration (global shortcuts, system tray, notifications) +- ✅ Conversation export and management (Markdown, JSON, TXT) +- ✅ Audio conversation mode for hands-free interaction + +### 🚀 Next: Phase 3 - Knowledge Base & Memory (v0.3.0) Planned features: -- Voice integration (TTS with ElevenLabs, STT) -- File attachment support -- Advanced message formatting (code highlighting, LaTeX, diagrams) -- System integration (keyboard shortcuts, tray icon) -- Conversation export and management +- Long-term memory with vector database +- Semantic search across conversations +- Personal knowledge graph +- Document library integration +- Multi-modal capabilities (vision, image generation) See [Roadmap](./docs/planning/ROADMAP.md) for the complete development plan. @@ -317,8 +394,8 @@ This is currently a personal project, but contributions, suggestions, and feedba --- -**Version**: 0.1.0 -**Status**: ✅ Stable - Ready for use -**Last Updated**: October 5, 2025 +**Version**: 0.2.0 +**Status**: ✅ Production Ready - Full-featured multimodal AI assistant +**Last Updated**: October 6, 2025 For detailed changes, see [Changelog](./docs/releases/CHANGELOG.md) diff --git a/docs/SCRIPTS.md b/docs/SCRIPTS.md new file mode 100644 index 0000000..1e1c81b --- /dev/null +++ b/docs/SCRIPTS.md @@ -0,0 +1,201 @@ +# EVE Development Scripts + +Quick reference for all development scripts in the EVE project. + +## Running the Application + +### Linux/macOS +```bash +./run.sh +``` + +### Windows +```powershell +.\run.ps1 +``` + +**What it does:** +- Checks for `.env` file (creates from template if missing) +- Checks for `node_modules` (installs if missing) +- Starts the Tauri development server with hot-reload +- Shows the app window with live code updates + +**Stop the server:** +- Press `Ctrl+C` in the terminal +- Or run the kill script (see below) + +## Stopping the Application + +### Linux/macOS +```bash +./kill.sh +``` + +### Windows +```powershell +.\kill.ps1 +``` + +**What it does:** +- Finds all EVE-related processes (Tauri, Vite, Cargo, etc.) +- Kills process trees cleanly +- Frees up ports (5173, 1420, etc.) +- Removes lock files + +**When to use:** +- When `Ctrl+C` doesn't fully stop the server +- When you get "port already in use" errors +- When processes are stuck in the background +- Before switching branches or rebuilding + +## Setup Scripts + +### Linux/macOS +```bash +./setup.sh +``` + +### Windows +```powershell +.\setup.ps1 +``` + +**What it does:** +- Detects your operating system +- Checks for Node.js, Rust, and dependencies +- Installs missing components (with permission) +- Sets up `.env` file +- Installs npm packages +- Verifies installation + +See [DEV_SETUP.md](./setup/DEV_SETUP.md) for detailed setup documentation. + +## npm Scripts + +You can also use npm commands directly: + +```bash +# Start development server (same as run.sh) +npm run tauri:dev + +# Start frontend only (browser, no desktop app) +npm run dev + +# Build for production +npm run tauri:build + +# Build frontend only +npm run build + +# Lint code +npm run lint + +# Format code +npm run format + +# Preview production build +npm run preview +``` + +## Common Workflows + +### Start Fresh Development Session +```bash +./run.sh +# App starts with hot-reload enabled +``` + +### Quick Restart +```bash +./kill.sh && ./run.sh +# Stops everything, then starts fresh +``` + +### Clean Build +```bash +./kill.sh +rm -rf node_modules src-tauri/target +npm install +npm run tauri:build +``` + +### Port Conflict Resolution +```bash +# If you get "address already in use" error +./kill.sh +# Then start again +./run.sh +``` + +### Switch Branches +```bash +# Stop app first to avoid conflicts +./kill.sh +git checkout feature-branch +npm install # Update dependencies if needed +./run.sh +``` + +## Troubleshooting + +### "Permission denied" (Linux/macOS) +```bash +chmod +x run.sh kill.sh setup.sh +``` + +### Scripts don't find processes (Linux/macOS) +The kill script uses `pgrep`, `lsof`, and `ps`. These should be available on most systems. If not: +```bash +# Ubuntu/Debian +sudo apt install procps lsof + +# macOS (usually pre-installed) +# No action needed +``` + +### PowerShell execution policy (Windows) +```powershell +Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser +``` + +### Processes still running after kill script +```bash +# Nuclear option - find and kill manually +ps aux | grep -E "vite|tauri|eve" +kill -9 + +# Or on Windows +tasklist | findstr /i "node cargo" +taskkill /F /PID +``` + +### Script starts but app window is blank +This is usually a graphics driver issue on Linux. The project includes a fix: +```bash +# The run script already includes this, but you can also run: +WEBKIT_DISABLE_COMPOSITING_MODE=1 npm run tauri:dev +``` + +## Tips + +1. **Use `run.sh` for daily development** - it's simpler than typing the full npm command +2. **Use `kill.sh` liberally** - it's safe and thorough +3. **Run `setup.sh` once** - when first setting up or after major changes +4. **Check `.env` file** - if the app shows "Configure Settings" on startup + +## Script Locations + +All scripts are in the project root: +``` +eve-alpha/ +├── run.sh # Start app (Linux/macOS) +├── run.ps1 # Start app (Windows) +├── kill.sh # Stop app (Linux/macOS) +├── kill.ps1 # Stop app (Windows) +├── setup.sh # Setup environment (Linux/macOS) +└── setup.ps1 # Setup environment (Windows) +``` + +--- + +**Last Updated**: October 6, 2025 diff --git a/docs/planning/PHASE2_COMPLETE.md b/docs/planning/PHASE2_COMPLETE.md index 1b12932..6c1428e 100644 --- a/docs/planning/PHASE2_COMPLETE.md +++ b/docs/planning/PHASE2_COMPLETE.md @@ -1,10 +1,10 @@ -# 🎉 Phase 2 - Major Features Complete! +# 🎉 Phase 2 - Complete! -**Date**: October 5, 2025, 3:00am UTC+01:00 -**Status**: 83% Complete (5/6 features) ✅ -**Version**: v0.2.0-rc +**Date**: October 6, 2025, 1:30am UTC+01:00 +**Status**: 100% Complete (6/6 features) ✅ +**Version**: v0.2.0 -## ✅ Completed Features (5/6) +## ✅ Completed Features (6/6) ### 1. Conversation Management ✅ **Production Ready** @@ -84,45 +84,42 @@ --- -## 🚧 Remaining Feature (1/6) +### 6. System Integration ✅ +**Production Ready** -### 6. System Integration -**Estimated**: 8-10 hours +- ✅ Global keyboard shortcut (Ctrl+Shift+E / Cmd+Shift+E) +- ✅ System tray icon with menu +- ✅ Desktop notifications for responses +- ✅ Minimize to tray functionality +- ✅ Left-click tray to toggle visibility +- ✅ Settings UI for preferences -**Planned**: -- [ ] Global keyboard shortcuts -- [ ] System tray icon -- [ ] Desktop notifications -- [ ] Quick launch hotkey -- [ ] Minimize to tray -- [ ] Auto-start option - -**Impact**: Professional desktop app experience, quick access from anywhere. +**User Impact**: Professional desktop app experience, quick access from anywhere, background operation. --- ## 📊 Statistics ### Code Metrics -- **Files Created**: 19 -- **Files Modified**: 10 -- **Lines of Code**: ~4,500+ -- **Components**: 8 new -- **Libraries**: 4 new +- **Files Created**: 21 +- **Files Modified**: 14 +- **Lines of Code**: ~5,000+ +- **Components**: 9 new +- **Libraries**: 5 new - **Hooks**: 1 new - **Dependencies**: 8 new ### Time Investment -- **Total Time**: ~8 hours -- **Features Completed**: 5/6 (83%) -- **Remaining**: ~8-10 hours +- **Total Time**: ~12 hours +- **Features Completed**: 6/6 (100%) +- **Phase 2**: Complete! ### Features by Category - **Conversation Management**: ✅ Complete - **Message Enhancement**: ✅ Complete - **Voice Features**: ✅ Complete (TTS + STT) - **File Handling**: ✅ Complete -- **System Integration**: ⏳ Pending +- **System Integration**: ✅ Complete --- @@ -134,6 +131,12 @@ Users can now interact with EVE through: 2. **Voice** (microphone - 25+ languages) 3. **Files** (drag & drop images/documents/code) +### System-Level Integration +- **Global Hotkey**: Press Ctrl+Shift+E (Cmd+Shift+E on Mac) from anywhere to show/hide EVE +- **System Tray**: EVE lives in your system tray for quick access +- **Notifications**: Get notified of responses even when EVE is hidden +- **Background Operation**: Minimize to tray keeps EVE running in background + ### Improved Message Display - Beautiful code syntax highlighting - Mathematical equations rendered perfectly @@ -224,14 +227,14 @@ Phase 2 features are production-ready and can be used immediately: ## 🔜 Next Steps -### Option 1: Complete Phase 2 (Recommended) -Implement system integration features for a complete v0.2.0 release. +### Option 1: Release v0.2.0 (Recommended) +Tag and release v0.2.0 with all Phase 2 features complete. ### Option 2: Start Phase 3 Move to knowledge base, long-term memory, and multi-modal features. ### Option 3: Testing & Polish -Focus on bug fixes, performance optimization, and user testing. +Focus on bug fixes, performance optimization, and user testing before Phase 3. --- @@ -251,9 +254,9 @@ EVE is now a **production-ready desktop AI assistant** that rivals commercial al --- -**Version**: 0.2.0-rc -**Phase 2 Completion**: 83% -**Next Milestone**: System Integration -**Estimated Release**: v0.2.0 within 1-2 sessions +**Version**: 0.2.0 +**Phase 2 Completion**: 100% ✅ +**Next Milestone**: Phase 3 - Knowledge Base & Memory +**Status**: Ready for Release -**Last Updated**: October 5, 2025, 3:00am UTC+01:00 +**Last Updated**: October 6, 2025, 1:30am UTC+01:00 diff --git a/docs/releases/CHANGELOG.md b/docs/releases/CHANGELOG.md index bf073aa..c73c899 100644 --- a/docs/releases/CHANGELOG.md +++ b/docs/releases/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to EVE - Personal Desktop Assistant will be documented in th The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). -## [Unreleased] - v0.2.0 (Phase 2 - In Progress) +## [Unreleased] - v0.2.0 (Phase 2 - Complete) ### Added @@ -81,6 +81,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - File context automatically included in AI conversation - Remove attachments before sending +- **System Integration** + - System tray icon with show/hide/quit menu + - Global keyboard shortcut (Ctrl+Shift+E / Cmd+Shift+E) to show/hide EVE + - Desktop notifications for assistant responses + - Minimize to tray option (close button hides instead of quitting) + - Left-click tray icon to toggle window visibility + - Settings UI for notification and minimize-to-tray preferences + - Quick access from anywhere via global hotkey + - **Dark Theme System** - Comprehensive dark mode support across all UI elements - Three theme options: Light, Dark, System @@ -112,6 +121,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - `VoiceInput` - Speech-to-text microphone control - `FileUpload` - Drag & drop file upload component - `FilePreview` - File attachment preview component + - `WindowControls` - Window minimize to tray handler - **New Libraries** - `elevenlabs.ts` - ElevenLabs API client @@ -119,6 +129,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - `stt.ts` - STT manager for Web Speech API - `fileProcessor.ts` - File processing and validation utilities - `theme.ts` - Theme management system with persistence + - `systemIntegration.ts` - Desktop notification utilities - **New Hooks** - `useVoiceRecording` - React hook for voice input @@ -129,14 +140,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed - Updated `ChatMessage` component to use advanced formatting and TTS controls for assistant messages -- Enhanced `SettingsPanel` with comprehensive voice configuration (TTS + STT) and theme selection -- Improved `ChatInterface` with save/load conversation buttons, voice input, and file attachments -- Extended `settingsStore` with voice settings (voiceEnabled, ttsVoice, sttLanguage, sttMode) and theme preference +- Enhanced `SettingsPanel` with comprehensive voice configuration (TTS + STT), theme selection, and system integration settings +- Improved `ChatInterface` with save/load conversation buttons, voice input, file attachments, and notification support +- Extended `settingsStore` with voice settings (voiceEnabled, ttsVoice, sttLanguage, sttMode), theme preference, and system integration settings (notificationsEnabled, minimizeToTray) - Extended `chatStore` to support file attachments on messages - Updated input placeholder to indicate voice and file attachment capabilities - Enhanced send button logic to support text, voice, and file-only messages - All UI components now fully support dark mode - App now initializes with dark theme by default +- Updated Tauri configuration to enable system tray, global shortcuts, and notifications +- Updated Rust backend with system tray menu, global shortcut registration, and notification command ### Fixed diff --git a/docs/setup/DEV_SETUP.md b/docs/setup/DEV_SETUP.md new file mode 100644 index 0000000..969ea5c --- /dev/null +++ b/docs/setup/DEV_SETUP.md @@ -0,0 +1,308 @@ +# Development Environment Setup Guide + +This guide covers setting up your development environment for EVE using the automated setup scripts. + +## Quick Start + +### Linux/macOS + +```bash +# Make script executable (if not already) +chmod +x setup.sh + +# Run setup script +./setup.sh +``` + +### Windows + +```powershell +# Run in PowerShell +.\setup.ps1 +``` + +## What the Setup Script Does + +The automated setup script will: + +1. **Detect your operating system** + - Linux (Debian/Ubuntu, Fedora/RHEL, Arch) + - macOS + - Windows + +2. **Check for required dependencies** + - Node.js (v18+) + - Rust (latest stable) + - npm or pnpm + - Platform-specific system libraries + +3. **Install missing dependencies** (with your permission) + - Guides you through installing Node.js and Rust + - Installs system dependencies for Tauri + - Sets up build tools + +4. **Configure your environment** + - Creates `.env` file from template + - Installs npm dependencies + - Verifies installation + +5. **Provide next steps** + - Instructions for adding API keys + - Commands to start development + +## Prerequisites + +### All Platforms + +Before running the setup script, ensure you have: + +- **Internet connection** (for downloading dependencies) +- **Administrator/sudo access** (for installing system packages) +- **~500MB free disk space** (for dependencies) + +### Platform-Specific + +#### Linux +- `curl` or `wget` (usually pre-installed) +- `sudo` access for installing system packages + +#### macOS +- Xcode Command Line Tools (script will prompt if needed) +- Homebrew (optional, but recommended) + +#### Windows +- PowerShell 5.1+ (included in Windows 10+) +- Internet Explorer or Edge (for WebView2) + +## Manual Installation + +If you prefer manual setup or the automated script encounters issues, follow these steps: + +### 1. Install Node.js + +**Linux/macOS:** +- Download from: https://nodejs.org/ +- Or use nvm: https://github.com/nvm-sh/nvm + +**Windows:** +- Download from: https://nodejs.org/ +- Run the installer and follow prompts + +Verify installation: +```bash +node -v # Should show v18.0.0 or higher +npm -v # Should show npm version +``` + +### 2. Install Rust + +**All platforms:** +```bash +# Linux/macOS +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + +# Windows (PowerShell) +# Download and run: https://win.rustup.rs/x86_64 +``` + +Verify installation: +```bash +rustc --version +cargo --version +``` + +### 3. Install System Dependencies + +#### Debian/Ubuntu +```bash +sudo apt update +sudo apt install libwebkit2gtk-4.0-dev \ + build-essential \ + curl \ + wget \ + file \ + libssl-dev \ + libgtk-3-dev \ + libayatana-appindicator3-dev \ + librsvg2-dev +``` + +#### Fedora/RHEL +```bash +sudo dnf install webkit2gtk4.0-devel \ + openssl-devel \ + curl \ + wget \ + file \ + libappindicator-gtk3-devel \ + librsvg2-devel +``` + +#### Arch Linux +```bash +sudo pacman -S webkit2gtk \ + base-devel \ + curl \ + wget \ + file \ + openssl \ + gtk3 \ + libappindicator-gtk3 \ + librsvg +``` + +#### macOS +```bash +xcode-select --install +``` + +#### Windows +- Install [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) + - Select "Desktop development with C++" + - Select "Windows 10/11 SDK" +- Install [WebView2 Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/) + +### 4. Install Project Dependencies + +```bash +# Clone the repository (if you haven't already) +cd eve-alpha + +# Install npm dependencies +npm install + +# Setup environment file +cp .env.example .env +``` + +### 5. Configure API Keys + +Edit `.env` and add your API keys: + +```env +VITE_OPENROUTER_API_KEY=sk-or-v1-your-key-here +VITE_ELEVENLABS_API_KEY=your-key-here # Optional +``` + +Get your API keys: +- **OpenRouter**: https://openrouter.ai/keys (required) +- **ElevenLabs**: https://elevenlabs.io (optional, for TTS) + +## Troubleshooting + +### Script Fails to Detect Dependencies + +If the script doesn't detect installed tools: + +1. **Restart your terminal** after installing Node.js or Rust +2. **Source the cargo environment** (Linux/macOS): + ```bash + source $HOME/.cargo/env + ``` +3. **Add to PATH** (Windows): Ensure Node.js and Rust are in your system PATH + +### Permission Denied Errors (Linux/macOS) + +```bash +# Make script executable +chmod +x setup.sh + +# If system package installation fails +sudo ./setup.sh # Not recommended, use sudo only for package installs +``` + +### npm Install Fails + +```bash +# Clear cache and reinstall +rm -rf node_modules package-lock.json +npm cache clean --force +npm install +``` + +### Rust Compilation Errors (Linux) + +Ensure all system dependencies are installed: +```bash +# Check webkit2gtk version +pkg-config --modversion webkit2gtk-4.0 + +# Should be 2.8.0 or higher +``` + +### Windows: "Script Cannot Be Loaded" Error + +PowerShell execution policy may block the script: + +```powershell +# Run as Administrator +Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +# Then run setup script again +.\setup.ps1 +``` + +### WebView2 Not Detected (Windows) + +Download and install manually: +https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section + +## Verifying Your Setup + +After running the setup script, verify everything works: + +```bash +# 1. Check all tools are installed +node -v +npm -v +rustc --version +cargo --version + +# 2. Start development server +npm run tauri:dev + +# 3. If the app window opens and you see the chat interface, you're all set! +``` + +## Development Workflow + +Once setup is complete: + +```bash +# Start development with hot-reload +npm run tauri:dev + +# Run frontend only (browser) +npm run dev + +# Build for production +npm run tauri:build + +# Lint code +npm run lint + +# Format code +npm run format +``` + +## Getting Help + +If you encounter issues not covered here: + +1. Check the [main README](../../README.md) +2. Review [SETUP_COMPLETE.md](./SETUP_COMPLETE.md) for detailed troubleshooting +3. Check [GitHub Issues](https://github.com/your-repo/eve-alpha/issues) + +## Next Steps + +After successful setup: + +1. ✅ Edit `.env` with your API keys +2. ✅ Run `npm run tauri:dev` to start developing +3. ✅ Read the [Development Guide](../CONTRIBUTING.md) (if available) +4. ✅ Check out the [Roadmap](../planning/ROADMAP.md) for planned features + +--- + +**Last Updated**: October 6, 2025 +**Supported Platforms**: Linux (Debian/Ubuntu, Fedora, Arch), macOS, Windows 10/11 diff --git a/kill.ps1 b/kill.ps1 new file mode 100644 index 0000000..8fd6c82 --- /dev/null +++ b/kill.ps1 @@ -0,0 +1,180 @@ +# EVE Application Kill Script for Windows +# Stops all running EVE development processes + +# Function to print colored output +function Write-ColorOutput($ForegroundColor) { + $fc = $host.UI.RawUI.ForegroundColor + $host.UI.RawUI.ForegroundColor = $ForegroundColor + if ($args) { + Write-Output $args + } + $host.UI.RawUI.ForegroundColor = $fc +} + +function Log-Info($message) { + Write-ColorOutput Cyan "[INFO] $message" +} + +function Log-Success($message) { + Write-ColorOutput Green "[SUCCESS] $message" +} + +function Log-Warning($message) { + Write-ColorOutput Yellow "[WARNING] $message" +} + +function Log-Found($message) { + Write-ColorOutput Yellow "[FOUND] $message" +} + +function Log-Killing($message) { + Write-ColorOutput Blue "[KILLING] $message" +} + +# Print header +Write-Host "" +Write-Host "╔════════════════════════════════════════════════════════╗" -ForegroundColor Red +Write-Host "║ Stopping EVE Development Server ║" -ForegroundColor Red +Write-Host "╚════════════════════════════════════════════════════════╝" -ForegroundColor Red +Write-Host "" + +$killedAny = $false + +# Function to kill process and its children +function Stop-ProcessTree { + param( + [Parameter(Mandatory=$true)] + [int]$ProcessId + ) + + try { + $process = Get-Process -Id $ProcessId -ErrorAction SilentlyContinue + if ($process) { + # Get child processes + $children = Get-CimInstance Win32_Process | Where-Object { $_.ParentProcessId -eq $ProcessId } + + # Kill children first + foreach ($child in $children) { + Stop-ProcessTree -ProcessId $child.ProcessId + } + + # Kill the process + Log-Killing "Process $ProcessId ($($process.Name))" + Stop-Process -Id $ProcessId -Force -ErrorAction SilentlyContinue + $script:killedAny = $true + } + } catch { + # Silently continue if process doesn't exist + } +} + +Log-Info "Searching for EVE processes..." + +# Kill Node.js processes running Vite or Tauri +$nodeProcesses = Get-Process -Name "node" -ErrorAction SilentlyContinue +foreach ($proc in $nodeProcesses) { + try { + $cmdLine = (Get-CimInstance Win32_Process -Filter "ProcessId = $($proc.Id)").CommandLine + if ($cmdLine -match "vite|tauri") { + Log-Found "Node process: $($proc.Id)" + Stop-ProcessTree -ProcessId $proc.Id + } + } catch { + # Continue if we can't get command line + } +} + +# Kill Cargo processes +$cargoProcesses = Get-Process -Name "cargo" -ErrorAction SilentlyContinue +foreach ($proc in $cargoProcesses) { + try { + $cmdLine = (Get-CimInstance Win32_Process -Filter "ProcessId = $($proc.Id)").CommandLine + if ($cmdLine -match "eve") { + Log-Found "Cargo process: $($proc.Id)" + Stop-ProcessTree -ProcessId $proc.Id + } + } catch { + # Continue + } +} + +# Kill eve-assistant processes +$eveProcesses = Get-Process -Name "eve-assistant" -ErrorAction SilentlyContinue +if ($eveProcesses) { + Log-Found "EVE application processes" + foreach ($proc in $eveProcesses) { + Stop-ProcessTree -ProcessId $proc.Id + } +} + +# Kill rustc processes related to eve +$rustcProcesses = Get-Process -Name "rustc" -ErrorAction SilentlyContinue +foreach ($proc in $rustcProcesses) { + try { + $cmdLine = (Get-CimInstance Win32_Process -Filter "ProcessId = $($proc.Id)").CommandLine + if ($cmdLine -match "eve") { + Log-Found "Rust compiler process: $($proc.Id)" + Stop-ProcessTree -ProcessId $proc.Id + } + } catch { + # Continue + } +} + +# Kill by PID file if exists +if (Test-Path ".dev\run.pid") { + $pid = Get-Content ".dev\run.pid" -ErrorAction SilentlyContinue + if ($pid) { + $proc = Get-Process -Id $pid -ErrorAction SilentlyContinue + if ($proc) { + Log-Found "Run script process (PID: $pid)" + Stop-ProcessTree -ProcessId $pid + } + } + Remove-Item ".dev\run.pid" -Force -ErrorAction SilentlyContinue +} + +Write-Host "" +Log-Info "Checking for processes on default ports..." + +# Function to kill process using a port +function Stop-ProcessOnPort { + param([int]$Port) + + try { + $connections = Get-NetTCPConnection -LocalPort $Port -ErrorAction SilentlyContinue + foreach ($conn in $connections) { + $proc = Get-Process -Id $conn.OwningProcess -ErrorAction SilentlyContinue + if ($proc) { + # Check if it's related to our project + $cmdLine = (Get-CimInstance Win32_Process -Filter "ProcessId = $($proc.Id)").CommandLine + if ($cmdLine -match "eve|tauri|vite") { + Log-Found "Process on port $Port ($($proc.Name))" + Stop-ProcessTree -ProcessId $proc.Id + } + } + } + } catch { + # Port not in use or no permission + } +} + +# Check common ports +Stop-ProcessOnPort -Port 5173 # Vite +Stop-ProcessOnPort -Port 1420 # Tauri +Stop-ProcessOnPort -Port 3000 # Alternative dev server +Stop-ProcessOnPort -Port 8080 # Alternative dev server + +# Clean up lock files +if (Test-Path "src-tauri\target\.rustc_info.json.lock") { + Remove-Item "src-tauri\target\.rustc_info.json.lock" -Force -ErrorAction SilentlyContinue +} + +Write-Host "" +if ($killedAny) { + Log-Success "All EVE processes stopped ✓" +} else { + Log-Info "No EVE processes were running" +} + +Write-Host "" diff --git a/kill.sh b/kill.sh new file mode 100755 index 0000000..fd5ccc9 --- /dev/null +++ b/kill.sh @@ -0,0 +1,123 @@ +#!/bin/bash + +# EVE Application Kill Script +# Stops all running EVE development processes + +# Colors +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' + +echo -e "${RED}╔════════════════════════════════════════════════════════╗${NC}" +echo -e "${RED}║ Stopping EVE Development Server ║${NC}" +echo -e "${RED}╚════════════════════════════════════════════════════════╝${NC}" +echo "" + +killed_any=false + +# Function to kill process tree +kill_process_tree() { + local pid=$1 + local children=$(pgrep -P $pid 2>/dev/null) + + for child in $children; do + kill_process_tree $child + done + + if kill -0 $pid 2>/dev/null; then + echo -e "${BLUE}[KILLING]${NC} Process $pid" + kill $pid 2>/dev/null || kill -9 $pid 2>/dev/null + killed_any=true + fi +} + +# Kill processes by name +echo -e "${BLUE}[INFO]${NC} Searching for EVE processes..." + +# Kill Tauri dev server +tauri_pids=$(pgrep -f "tauri dev" 2>/dev/null) +if [ ! -z "$tauri_pids" ]; then + echo -e "${YELLOW}[FOUND]${NC} Tauri dev processes" + for pid in $tauri_pids; do + kill_process_tree $pid + done +fi + +# Kill Vite dev server +vite_pids=$(pgrep -f "vite" 2>/dev/null) +if [ ! -z "$vite_pids" ]; then + echo -e "${YELLOW}[FOUND]${NC} Vite processes" + for pid in $vite_pids; do + kill_process_tree $pid + done +fi + +# Kill eve-assistant processes +eve_pids=$(pgrep -f "eve-assistant" 2>/dev/null) +if [ ! -z "$eve_pids" ]; then + echo -e "${YELLOW}[FOUND]${NC} EVE application processes" + for pid in $eve_pids; do + kill_process_tree $pid + done +fi + +# Kill cargo processes related to this project +cargo_pids=$(pgrep -f "cargo.*eve" 2>/dev/null) +if [ ! -z "$cargo_pids" ]; then + echo -e "${YELLOW}[FOUND]${NC} Cargo build processes" + for pid in $cargo_pids; do + kill_process_tree $pid + done +fi + +# Kill by PID file if exists +if [ -f ".dev/run.pid" ]; then + pid=$(cat .dev/run.pid) + if kill -0 $pid 2>/dev/null; then + echo -e "${YELLOW}[FOUND]${NC} Run script process (PID: $pid)" + kill_process_tree $pid + fi + rm -f .dev/run.pid +fi + +# Kill any processes using the default ports +echo "" +echo -e "${BLUE}[INFO]${NC} Checking for processes on default ports..." + +# Vite typically uses 5173 +vite_port_pid=$(lsof -t -i:5173 2>/dev/null) +if [ ! -z "$vite_port_pid" ]; then + echo -e "${YELLOW}[FOUND]${NC} Process on port 5173 (Vite)" + kill $vite_port_pid 2>/dev/null || kill -9 $vite_port_pid 2>/dev/null + killed_any=true +fi + +# Tauri typically uses various ports, check common ones +for port in 1420 3000 8080; do + port_pid=$(lsof -t -i:$port 2>/dev/null) + if [ ! -z "$port_pid" ]; then + # Check if it's related to our project + cmd=$(ps -p $port_pid -o cmd= 2>/dev/null) + if [[ $cmd == *"eve"* ]] || [[ $cmd == *"tauri"* ]] || [[ $cmd == *"vite"* ]]; then + echo -e "${YELLOW}[FOUND]${NC} Process on port $port" + kill $port_pid 2>/dev/null || kill -9 $port_pid 2>/dev/null + killed_any=true + fi + fi +done + +# Clean up lock files +if [ -f "src-tauri/target/.rustc_info.json.lock" ]; then + rm -f "src-tauri/target/.rustc_info.json.lock" +fi + +echo "" +if [ "$killed_any" = true ]; then + echo -e "${GREEN}[SUCCESS]${NC} All EVE processes stopped ✓" +else + echo -e "${BLUE}[INFO]${NC} No EVE processes were running" +fi + +echo "" diff --git a/package.json b/package.json index c20892c..9541577 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eve-assistant", - "version": "0.1.0", + "version": "0.2.0", "description": "EVE - Personal Desktop Assistant with AI capabilities", "type": "module", "scripts": { diff --git a/run.ps1 b/run.ps1 new file mode 100644 index 0000000..bc46039 --- /dev/null +++ b/run.ps1 @@ -0,0 +1,75 @@ +# EVE Application Run Script for Windows +# Starts the Tauri development server with hot-reload + +# Function to print colored output +function Write-ColorOutput($ForegroundColor) { + $fc = $host.UI.RawUI.ForegroundColor + $host.UI.RawUI.ForegroundColor = $ForegroundColor + if ($args) { + Write-Output $args + } + $host.UI.RawUI.ForegroundColor = $fc +} + +function Log-Info($message) { + Write-ColorOutput Cyan "[INFO] $message" +} + +function Log-Success($message) { + Write-ColorOutput Green "[SUCCESS] $message" +} + +function Log-Warning($message) { + Write-ColorOutput Yellow "[WARNING] $message" +} + +function Log-Error($message) { + Write-ColorOutput Red "[ERROR] $message" +} + +# Print header +Write-Host "" +Write-Host "╔════════════════════════════════════════════════════════╗" +Write-Host "║ Starting EVE Development Server ║" +Write-Host "╚════════════════════════════════════════════════════════╝" +Write-Host "" + +# Check if .env exists +if (-not (Test-Path ".env")) { + Log-Warning ".env file not found" + Log-Info "Creating .env from .env.example..." + Copy-Item ".env.example" ".env" + Log-Info "Please edit .env and add your API keys" + Write-Host "" +} + +# Check if node_modules exists +if (-not (Test-Path "node_modules")) { + Log-Warning "node_modules not found" + Log-Info "Installing dependencies..." + npm install + Write-Host "" +} + +# Create .dev directory if it doesn't exist +if (-not (Test-Path ".dev")) { + New-Item -ItemType Directory -Path ".dev" -Force | Out-Null +} + +# Save PID for kill script +$PID | Out-File -FilePath ".dev\run.pid" -Encoding ASCII + +Write-ColorOutput Green "[STARTING] Launching Tauri development server..." +Log-Info "Press Ctrl+C to stop the server" +Log-Info "Or run: .\kill.ps1" +Write-Host "" + +# Start the development server +try { + npm run tauri:dev +} finally { + # Cleanup on exit + if (Test-Path ".dev\run.pid") { + Remove-Item ".dev\run.pid" -Force + } +} diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..d1267e4 --- /dev/null +++ b/run.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# EVE Application Run Script +# Starts the Tauri development server with hot-reload + +set -e + +# Colors +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' + +echo -e "${BLUE}╔════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}║ Starting EVE Development Server ║${NC}" +echo -e "${BLUE}╚════════════════════════════════════════════════════════╝${NC}" +echo "" + +# Check if .env exists +if [ ! -f ".env" ]; then + echo -e "${YELLOW}[WARNING]${NC} .env file not found" + echo -e "${YELLOW}[INFO]${NC} Creating .env from .env.example..." + cp .env.example .env + echo -e "${YELLOW}[INFO]${NC} Please edit .env and add your API keys" + echo "" +fi + +# Check if node_modules exists +if [ ! -d "node_modules" ]; then + echo -e "${YELLOW}[WARNING]${NC} node_modules not found" + echo -e "${BLUE}[INFO]${NC} Installing dependencies..." + npm install + echo "" +fi + +# Save PID for kill script +mkdir -p .dev +echo $$ > .dev/run.pid + +echo -e "${GREEN}[STARTING]${NC} Launching Tauri development server..." +echo -e "${BLUE}[INFO]${NC} Press Ctrl+C to stop the server" +echo -e "${BLUE}[INFO]${NC} Or run: ./kill.sh" +echo "" + +# Start the development server +npm run tauri:dev + +# Cleanup on exit +rm -f .dev/run.pid diff --git a/setup.ps1 b/setup.ps1 new file mode 100644 index 0000000..6f51c42 --- /dev/null +++ b/setup.ps1 @@ -0,0 +1,439 @@ +# EVE Development Environment Setup Script for Windows +# Run this script in PowerShell with: .\setup.ps1 + +# Requires PowerShell 5.1 or higher + +# Function to print colored output +function Write-ColorOutput($ForegroundColor) { + $fc = $host.UI.RawUI.ForegroundColor + $host.UI.RawUI.ForegroundColor = $ForegroundColor + if ($args) { + Write-Output $args + } + $host.UI.RawUI.ForegroundColor = $fc +} + +function Log-Info($message) { + Write-ColorOutput Cyan "[INFO] $message" +} + +function Log-Success($message) { + Write-ColorOutput Green "[SUCCESS] $message" +} + +function Log-Warning($message) { + Write-ColorOutput Yellow "[WARNING] $message" +} + +function Log-Error($message) { + Write-ColorOutput Red "[ERROR] $message" +} + +# Print header +function Print-Header { + Write-Host "" + Write-Host "╔════════════════════════════════════════════════════════╗" + Write-Host "║ EVE Development Environment Setup ║" + Write-Host "║ Personal Desktop AI Assistant ║" + Write-Host "╚════════════════════════════════════════════════════════╝" + Write-Host "" +} + +# Check if running as administrator +function Test-Administrator { + $user = [Security.Principal.WindowsIdentity]::GetCurrent() + $principal = New-Object Security.Principal.WindowsPrincipal $user + return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) +} + +# Check if command exists +function Test-CommandExists($command) { + $null = Get-Command $command -ErrorAction SilentlyContinue + return $? +} + +# Check Node.js installation +function Test-NodeJs { + Log-Info "Checking Node.js installation..." + + if (Test-CommandExists "node") { + $version = node -v + $versionNumber = $version -replace 'v', '' + $majorVersion = ($versionNumber -split '\.')[0] + + if ([int]$majorVersion -ge 18) { + Log-Success "Node.js $version installed ✓" + return $true + } else { + Log-Warning "Node.js $version is installed but v18+ is required" + return $false + } + } else { + Log-Warning "Node.js is not installed" + return $false + } +} + +# Check Rust installation +function Test-Rust { + Log-Info "Checking Rust installation..." + + if ((Test-CommandExists "rustc") -and (Test-CommandExists "cargo")) { + $version = rustc --version + Log-Success "$version installed ✓" + return $true + } else { + Log-Warning "Rust is not installed" + return $false + } +} + +# Check package manager +function Test-PackageManager { + Log-Info "Checking package manager..." + + if (Test-CommandExists "npm") { + $version = npm -v + Log-Success "npm $version installed ✓" + $script:PackageManager = "npm" + return $true + } elseif (Test-CommandExists "pnpm") { + $version = pnpm -v + Log-Success "pnpm $version installed ✓" + $script:PackageManager = "pnpm" + return $true + } else { + Log-Error "Neither npm nor pnpm is installed" + return $false + } +} + +# Check WebView2 +function Test-WebView2 { + Log-Info "Checking WebView2 Runtime..." + + $webView2Path = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" + + if (Test-Path $webView2Path) { + Log-Success "WebView2 Runtime installed ✓" + return $true + } else { + Log-Warning "WebView2 Runtime not detected" + return $false + } +} + +# Check Visual Studio Build Tools +function Test-VSBuildTools { + Log-Info "Checking Visual Studio Build Tools..." + + $vsPaths = @( + "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools", + "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools", + "C:\Program Files\Microsoft Visual Studio\2022\Community", + "C:\Program Files\Microsoft Visual Studio\2022\Professional", + "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" + ) + + foreach ($path in $vsPaths) { + if (Test-Path $path) { + Log-Success "Visual Studio Build Tools found ✓" + return $true + } + } + + Log-Warning "Visual Studio Build Tools not detected" + return $false +} + +# Install Node.js +function Install-NodeJs { + Log-Info "Installing Node.js..." + Log-Info "Please download and install Node.js from: https://nodejs.org/" + Log-Info "Recommended: Download the LTS version (v18 or higher)" + + $response = Read-Host "Open Node.js download page in browser? (Y/n)" + if ($response -ne 'n' -and $response -ne 'N') { + Start-Process "https://nodejs.org/en/download/" + } + + Log-Info "After installing Node.js, please restart this script" + exit 0 +} + +# Install Rust +function Install-Rust { + Log-Info "Installing Rust..." + + $rustupUrl = "https://win.rustup.rs/x86_64" + $rustupPath = "$env:TEMP\rustup-init.exe" + + try { + Log-Info "Downloading rustup installer..." + Invoke-WebRequest -Uri $rustupUrl -OutFile $rustupPath + + Log-Info "Running rustup installer..." + Start-Process -FilePath $rustupPath -Wait + + Log-Success "Rust installation initiated!" + Log-Info "Please restart your terminal after the installation completes" + + } catch { + Log-Error "Failed to download Rust installer: $_" + Log-Info "Please install manually from: https://rustup.rs/" + } +} + +# Install WebView2 +function Install-WebView2 { + Log-Info "WebView2 Runtime is required for Tauri applications" + Log-Info "Download from: https://developer.microsoft.com/en-us/microsoft-edge/webview2/" + + $response = Read-Host "Open WebView2 download page in browser? (Y/n)" + if ($response -ne 'n' -and $response -ne 'N') { + Start-Process "https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section" + } +} + +# Install Visual Studio Build Tools +function Install-VSBuildTools { + Log-Info "Visual Studio Build Tools are required for Rust compilation" + Log-Info "Download from: https://visualstudio.microsoft.com/visual-cpp-build-tools/" + + $response = Read-Host "Open Visual Studio Build Tools download page in browser? (Y/n)" + if ($response -ne 'n' -and $response -ne 'N') { + Start-Process "https://visualstudio.microsoft.com/visual-cpp-build-tools/" + } + + Log-Info "" + Log-Info "During installation, select:" + Log-Info " - Desktop development with C++" + Log-Info " - Windows 10/11 SDK" +} + +# Setup environment file +function Setup-EnvFile { + Log-Info "Setting up environment file..." + + if (Test-Path ".env") { + Log-Warning ".env file already exists" + $response = Read-Host "Do you want to overwrite it? (y/N)" + if ($response -ne 'y' -and $response -ne 'Y') { + Log-Info "Keeping existing .env file" + return + } + } + + Copy-Item ".env.example" ".env" + Log-Success "Created .env file from .env.example" + + Write-Host "" + Log-Info "Please edit .env and add your API keys:" + Log-Info " - OpenRouter API key: https://openrouter.ai/keys" + Log-Info " - ElevenLabs API key (optional): https://elevenlabs.io" + Write-Host "" +} + +# Install npm dependencies +function Install-NpmDependencies { + Log-Info "Installing npm dependencies..." + + if (Test-Path "node_modules") { + Log-Info "node_modules directory exists" + $response = Read-Host "Do you want to reinstall dependencies? (y/N)" + if ($response -eq 'y' -or $response -eq 'Y') { + Remove-Item -Recurse -Force "node_modules" + if (Test-Path "package-lock.json") { + Remove-Item "package-lock.json" + } + Log-Info "Cleaned node_modules" + } else { + Log-Info "Skipping npm install" + return + } + } + + & $script:PackageManager install + + if ($LASTEXITCODE -eq 0) { + Log-Success "npm dependencies installed ✓" + } else { + Log-Error "Failed to install npm dependencies" + } +} + +# Verify installation +function Test-Installation { + Log-Info "Verifying installation..." + Write-Host "" + + $allGood = $true + + # Check Node.js + if (Test-CommandExists "node") { + $version = node -v + Log-Success "✓ Node.js: $version" + } else { + Log-Error "✗ Node.js: Not found" + $allGood = $false + } + + # Check Rust + if (Test-CommandExists "rustc") { + $version = (rustc --version) -split ' ' | Select-Object -First 2 + Log-Success "✓ Rust: $($version -join ' ')" + } else { + Log-Error "✗ Rust: Not found" + $allGood = $false + } + + # Check Cargo + if (Test-CommandExists "cargo") { + $version = (cargo --version) -split ' ' | Select-Object -First 2 + Log-Success "✓ Cargo: $($version -join ' ')" + } else { + Log-Error "✗ Cargo: Not found" + $allGood = $false + } + + # Check npm + if (Test-CommandExists "npm") { + $version = npm -v + Log-Success "✓ npm: v$version" + } else { + Log-Error "✗ npm: Not found" + $allGood = $false + } + + # Check node_modules + if (Test-Path "node_modules") { + Log-Success "✓ Node dependencies installed" + } else { + Log-Error "✗ Node dependencies: Not installed" + $allGood = $false + } + + # Check .env file + if (Test-Path ".env") { + Log-Success "✓ Environment file exists" + } else { + Log-Warning "⚠ Environment file not found (.env)" + } + + # Check WebView2 + if (Test-WebView2) { + Log-Success "✓ WebView2 Runtime installed" + } else { + Log-Warning "⚠ WebView2 Runtime: Not detected" + } + + Write-Host "" + + if ($allGood) { + Log-Success "All checks passed! ✓" + return $true + } else { + Log-Error "Some checks failed. Please review the errors above." + return $false + } +} + +# Print next steps +function Print-NextSteps { + Write-Host "" + Write-Host "╔════════════════════════════════════════════════════════╗" + Write-Host "║ Setup Complete! ║" + Write-Host "╚════════════════════════════════════════════════════════╝" + Write-Host "" + Log-Info "Next steps:" + Write-Host "" + Write-Host " 1. Edit .env and add your API keys:" + Write-ColorOutput Cyan " notepad .env" + Write-Host "" + Write-Host " 2. Start the development server:" + Write-ColorOutput Green " npm run tauri:dev" + Write-Host "" + Write-Host " 3. Build for production:" + Write-ColorOutput Green " npm run tauri:build" + Write-Host "" + Log-Info "Additional commands:" + Write-ColorOutput Cyan " - Frontend only: npm run dev" + Write-ColorOutput Cyan " - Lint code: npm run lint" + Write-ColorOutput Cyan " - Format code: npm run format" + Write-Host "" + Log-Info "Documentation: .\docs\README.md" + Log-Info "Troubleshooting: .\docs\setup\SETUP_COMPLETE.md" + Write-Host "" +} + +# Main setup function +function Main { + Print-Header + + Log-Info "Detected: Windows" + Write-Host "" + + # Check existing installations + $needNode = -not (Test-NodeJs) + $needRust = -not (Test-Rust) + $needWebView2 = -not (Test-WebView2) + $needVSBuildTools = -not (Test-VSBuildTools) + Test-PackageManager | Out-Null + + Write-Host "" + + # Install missing components + if ($needNode) { + $response = Read-Host "Install Node.js? (y/N)" + if ($response -eq 'y' -or $response -eq 'Y') { + Install-NodeJs + } else { + Log-Warning "Skipping Node.js installation" + } + } + + if ($needRust) { + $response = Read-Host "Install Rust? (y/N)" + if ($response -eq 'y' -or $response -eq 'Y') { + Install-Rust + } else { + Log-Warning "Skipping Rust installation" + } + } + + if ($needWebView2) { + $response = Read-Host "Install WebView2 Runtime? (y/N)" + if ($response -eq 'y' -or $response -eq 'Y') { + Install-WebView2 + } + } + + if ($needVSBuildTools) { + $response = Read-Host "Install Visual Studio Build Tools? (y/N)" + if ($response -eq 'y' -or $response -eq 'Y') { + Install-VSBuildTools + } + } + + Write-Host "" + + # Setup environment file + Setup-EnvFile + + # Install npm dependencies + $response = Read-Host "Install npm dependencies? (Y/n)" + if ($response -ne 'n' -and $response -ne 'N') { + Install-NpmDependencies + } + + Write-Host "" + + # Verify installation + Test-Installation + + # Print next steps + Print-NextSteps +} + +# Run main function +Main diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..07d35fd --- /dev/null +++ b/setup.sh @@ -0,0 +1,441 @@ +#!/bin/bash + +# EVE Development Environment Setup Script +# This script automates the setup process for the EVE desktop assistant + +set -e # Exit on error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Logging functions +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Print header +print_header() { + echo "" + echo "╔════════════════════════════════════════════════════════╗" + echo "║ EVE Development Environment Setup ║" + echo "║ Personal Desktop AI Assistant ║" + echo "╚════════════════════════════════════════════════════════╝" + echo "" +} + +# Detect OS +detect_os() { + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + if [ -f /etc/debian_version ]; then + OS="debian" + log_info "Detected: Debian/Ubuntu Linux" + elif [ -f /etc/fedora-release ]; then + OS="fedora" + log_info "Detected: Fedora/RHEL Linux" + elif [ -f /etc/arch-release ]; then + OS="arch" + log_info "Detected: Arch Linux" + else + OS="linux" + log_info "Detected: Linux (generic)" + fi + elif [[ "$OSTYPE" == "darwin"* ]]; then + OS="macos" + log_info "Detected: macOS" + else + OS="unknown" + log_warning "Unknown OS: $OSTYPE" + fi +} + +# Check if command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Check Node.js installation +check_node() { + log_info "Checking Node.js installation..." + + if command_exists node; then + NODE_VERSION=$(node -v | cut -d'v' -f2) + MAJOR_VERSION=$(echo $NODE_VERSION | cut -d'.' -f1) + + if [ "$MAJOR_VERSION" -ge 18 ]; then + log_success "Node.js $NODE_VERSION installed ✓" + return 0 + else + log_warning "Node.js $NODE_VERSION is installed but v18+ is required" + return 1 + fi + else + log_warning "Node.js is not installed" + return 1 + fi +} + +# Check Rust installation +check_rust() { + log_info "Checking Rust installation..." + + if command_exists rustc && command_exists cargo; then + RUST_VERSION=$(rustc --version | cut -d' ' -f2) + log_success "Rust $RUST_VERSION installed ✓" + return 0 + else + log_warning "Rust is not installed" + return 1 + fi +} + +# Check npm/pnpm +check_package_manager() { + log_info "Checking package manager..." + + if command_exists npm; then + NPM_VERSION=$(npm -v) + log_success "npm $NPM_VERSION installed ✓" + PACKAGE_MANAGER="npm" + return 0 + elif command_exists pnpm; then + PNPM_VERSION=$(pnpm -v) + log_success "pnpm $PNPM_VERSION installed ✓" + PACKAGE_MANAGER="pnpm" + return 0 + else + log_error "Neither npm nor pnpm is installed" + return 1 + fi +} + +# Install Node.js +install_node() { + log_info "Installing Node.js..." + + if [[ "$OS" == "macos" ]]; then + if command_exists brew; then + brew install node + else + log_error "Homebrew not found. Please install from https://brew.sh/" + log_info "Or install Node.js manually from https://nodejs.org/" + exit 1 + fi + else + log_info "Please install Node.js manually from https://nodejs.org/" + log_info "Recommended: Use nvm (Node Version Manager) https://github.com/nvm-sh/nvm" + exit 1 + fi +} + +# Install Rust +install_rust() { + log_info "Installing Rust..." + + if command_exists curl; then + log_info "Running rustup installer..." + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + + # Source cargo environment + source "$HOME/.cargo/env" + + log_success "Rust installed successfully!" + else + log_error "curl is not installed. Please install curl first." + exit 1 + fi +} + +# Install system dependencies for Linux +install_linux_dependencies() { + log_info "Installing system dependencies for Tauri..." + + case "$OS" in + debian) + log_info "Installing dependencies via apt..." + sudo apt update + sudo apt install -y \ + libwebkit2gtk-4.0-dev \ + build-essential \ + curl \ + wget \ + file \ + libssl-dev \ + libgtk-3-dev \ + libayatana-appindicator3-dev \ + librsvg2-dev + ;; + fedora) + log_info "Installing dependencies via dnf..." + sudo dnf install -y \ + webkit2gtk4.0-devel \ + openssl-devel \ + curl \ + wget \ + file \ + libappindicator-gtk3-devel \ + librsvg2-devel + ;; + arch) + log_info "Installing dependencies via pacman..." + sudo pacman -S --needed --noconfirm \ + webkit2gtk \ + base-devel \ + curl \ + wget \ + file \ + openssl \ + gtk3 \ + libappindicator-gtk3 \ + librsvg + ;; + *) + log_warning "Automatic dependency installation not supported for your Linux distribution" + log_info "Please refer to README.md for manual installation instructions" + return 1 + ;; + esac + + log_success "System dependencies installed ✓" +} + +# Install system dependencies for macOS +install_macos_dependencies() { + log_info "Checking Xcode Command Line Tools..." + + if xcode-select -p &> /dev/null; then + log_success "Xcode Command Line Tools already installed ✓" + else + log_info "Installing Xcode Command Line Tools..." + xcode-select --install + log_info "Please complete the Xcode installation and run this script again" + exit 0 + fi +} + +# Setup environment file +setup_env_file() { + log_info "Setting up environment file..." + + if [ -f ".env" ]; then + log_warning ".env file already exists" + read -p "Do you want to overwrite it? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + log_info "Keeping existing .env file" + return 0 + fi + fi + + cp .env.example .env + log_success "Created .env file from .env.example" + + echo "" + log_info "Please edit .env and add your API keys:" + log_info " - OpenRouter API key: https://openrouter.ai/keys" + log_info " - ElevenLabs API key (optional): https://elevenlabs.io" + echo "" +} + +# Install npm dependencies +install_npm_dependencies() { + log_info "Installing npm dependencies..." + + if [ -d "node_modules" ]; then + log_info "node_modules directory exists" + read -p "Do you want to reinstall dependencies? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + rm -rf node_modules package-lock.json + log_info "Cleaned node_modules" + else + log_info "Skipping npm install" + return 0 + fi + fi + + $PACKAGE_MANAGER install + log_success "npm dependencies installed ✓" +} + +# Verify installation +verify_installation() { + log_info "Verifying installation..." + echo "" + + local all_good=true + + # Check Node.js + if command_exists node; then + log_success "✓ Node.js: $(node -v)" + else + log_error "✗ Node.js: Not found" + all_good=false + fi + + # Check Rust + if command_exists rustc; then + log_success "✓ Rust: $(rustc --version | cut -d' ' -f1-2)" + else + log_error "✗ Rust: Not found" + all_good=false + fi + + # Check cargo + if command_exists cargo; then + log_success "✓ Cargo: $(cargo --version | cut -d' ' -f1-2)" + else + log_error "✗ Cargo: Not found" + all_good=false + fi + + # Check npm + if command_exists npm; then + log_success "✓ npm: v$(npm -v)" + else + log_error "✗ npm: Not found" + all_good=false + fi + + # Check node_modules + if [ -d "node_modules" ]; then + log_success "✓ Node dependencies installed" + else + log_error "✗ Node dependencies: Not installed" + all_good=false + fi + + # Check .env file + if [ -f ".env" ]; then + log_success "✓ Environment file exists" + else + log_warning "⚠ Environment file not found (.env)" + fi + + echo "" + + if [ "$all_good" = true ]; then + log_success "All checks passed! ✓" + return 0 + else + log_error "Some checks failed. Please review the errors above." + return 1 + fi +} + +# Print next steps +print_next_steps() { + echo "" + echo "╔════════════════════════════════════════════════════════╗" + echo "║ Setup Complete! ║" + echo "╚════════════════════════════════════════════════════════╝" + echo "" + log_info "Next steps:" + echo "" + echo " 1. Edit .env and add your API keys:" + echo " ${BLUE}nano .env${NC} or ${BLUE}vim .env${NC}" + echo "" + echo " 2. Start the development server:" + echo " ${GREEN}npm run tauri:dev${NC}" + echo "" + echo " 3. Build for production:" + echo " ${GREEN}npm run tauri:build${NC}" + echo "" + log_info "Additional commands:" + echo " - Frontend only: ${BLUE}npm run dev${NC}" + echo " - Lint code: ${BLUE}npm run lint${NC}" + echo " - Format code: ${BLUE}npm run format${NC}" + echo "" + log_info "Documentation: ./docs/README.md" + log_info "Troubleshooting: ./docs/setup/SETUP_COMPLETE.md" + echo "" +} + +# Main setup function +main() { + print_header + + # Detect OS + detect_os + echo "" + + # Check existing installations + local need_node=false + local need_rust=false + + check_node || need_node=true + check_rust || need_rust=true + check_package_manager + + echo "" + + # Install missing components + if [ "$need_node" = true ]; then + read -p "Install Node.js? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + install_node + else + log_warning "Skipping Node.js installation" + fi + fi + + if [ "$need_rust" = true ]; then + read -p "Install Rust? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + install_rust + else + log_warning "Skipping Rust installation" + fi + fi + + # Install system dependencies + if [[ "$OS" == "debian" ]] || [[ "$OS" == "fedora" ]] || [[ "$OS" == "arch" ]]; then + read -p "Install system dependencies for Tauri? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + install_linux_dependencies + fi + elif [[ "$OS" == "macos" ]]; then + install_macos_dependencies + fi + + echo "" + + # Setup environment file + setup_env_file + + # Install npm dependencies + read -p "Install npm dependencies? (Y/n): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Nn]$ ]]; then + install_npm_dependencies + fi + + echo "" + + # Verify installation + verify_installation + + # Print next steps + print_next_steps +} + +# Run main function +main "$@" diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index e6696ac..35d74f3 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -56,6 +56,137 @@ version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "windows-sys 0.61.1", +] + +[[package]] +name = "async-lock" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "async-signal" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys 0.61.1", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "atk" version = "0.15.1" @@ -80,6 +211,12 @@ dependencies = [ "system-deps 6.2.2", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.5.0" @@ -98,7 +235,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -146,6 +283,28 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + [[package]] name = "brotli" version = "7.0.0" @@ -211,7 +370,7 @@ dependencies = [ "cairo-sys-rs", "glib", "libc", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -287,6 +446,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.42" @@ -296,7 +461,7 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -345,6 +510,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -585,6 +759,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.4", + "objc2", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -658,6 +842,33 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "endi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -686,6 +897,27 @@ dependencies = [ "tokio", ] +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -707,7 +939,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" dependencies = [ - "memoffset", + "memoffset 0.9.1", "rustc_version", ] @@ -820,6 +1052,19 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.31" @@ -1023,7 +1268,7 @@ dependencies = [ "glib", "libc", "once_cell", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1056,7 +1301,7 @@ dependencies = [ "libc", "once_cell", "smallvec", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1067,7 +1312,7 @@ checksum = "10c6ae9f6fa26f4fb2ac16b528d138d971ead56141de489f8111e259b9df3c4a" dependencies = [ "anyhow", "heck 0.4.1", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro-error", "proc-macro2", "quote", @@ -1162,7 +1407,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "684c0456c086e8e7e9af73ec5b84e35938df394712054550e81558d21c44ab0d" dependencies = [ "anyhow", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro-error", "proc-macro2", "quote", @@ -1202,6 +1447,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + [[package]] name = "hex" version = "0.4.3" @@ -1251,7 +1502,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.62.1", ] [[package]] @@ -1511,7 +1762,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", ] @@ -1540,7 +1791,7 @@ dependencies = [ "jsonptr", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1638,6 +1889,18 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +[[package]] +name = "mac-notification-sys" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119c8490084af61b44c9eda9d626475847a186737c0378c85e32d77c33a01cd4" +dependencies = [ + "cc", + "objc2", + "objc2-foundation", + "time", +] + [[package]] name = "malloc_buf" version = "0.0.6" @@ -1682,6 +1945,15 @@ version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.9.1" @@ -1722,7 +1994,7 @@ dependencies = [ "jni-sys", "ndk-sys", "num_enum", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1746,12 +2018,51 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", +] + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset 0.9.1", +] + [[package]] name = "nodrop" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "notify-rust" +version = "4.11.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6442248665a5aa2514e794af3b39661a8e73033b1cc5e59899e1276117ee4400" +dependencies = [ + "futures-lite", + "log", + "mac-notification-sys", + "serde", + "tauri-winrt-notification", + "zbus", +] + [[package]] name = "nu-ansi-term" version = "0.50.1" @@ -1791,7 +2102,7 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", @@ -1807,6 +2118,56 @@ dependencies = [ "objc_exception", ] +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.9.4", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.9.4", + "block2", + "libc", + "objc2", + "objc2-core-foundation", +] + [[package]] name = "objc_exception" version = "0.1.2" @@ -1850,6 +2211,16 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + [[package]] name = "pango" version = "0.15.10" @@ -1875,6 +2246,12 @@ dependencies = [ "system-deps 6.2.2", ] +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.5" @@ -1895,7 +2272,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -2056,6 +2433,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + [[package]] name = "pkg-config" version = "0.3.32" @@ -2070,7 +2458,7 @@ checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" dependencies = [ "base64 0.22.1", "indexmap 2.11.4", - "quick-xml", + "quick-xml 0.38.3", "serde", "time", ] @@ -2088,6 +2476,20 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "windows-sys 0.61.1", +] + [[package]] name = "potential_utf" version = "0.1.3" @@ -2128,6 +2530,15 @@ dependencies = [ "toml_edit 0.19.15", ] +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit 0.23.2", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -2167,6 +2578,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-xml" +version = "0.37.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +dependencies = [ + "memchr", +] + [[package]] name = "quick-xml" version = "0.38.3" @@ -2295,7 +2715,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2347,6 +2767,30 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +[[package]] +name = "rfd" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea" +dependencies = [ + "block", + "dispatch", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "lazy_static", + "log", + "objc", + "objc-foundation", + "objc_id", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows 0.37.0", +] + [[package]] name = "rustc-demangle" version = "0.1.26" @@ -2707,6 +3151,12 @@ dependencies = [ "loom", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "string_cache" version = "0.8.9" @@ -2894,6 +3344,8 @@ dependencies = [ "http", "ignore", "log", + "nix 0.26.4", + "notify-rust", "objc", "once_cell", "open", @@ -2902,6 +3354,7 @@ dependencies = [ "rand 0.8.5", "raw-window-handle", "regex", + "rfd", "semver", "serde", "serde_json", @@ -2914,7 +3367,7 @@ dependencies = [ "tauri-runtime-wry", "tauri-utils", "tempfile", - "thiserror", + "thiserror 1.0.69", "tokio", "url", "uuid", @@ -2962,7 +3415,7 @@ dependencies = [ "serde_json", "sha2", "tauri-utils", - "thiserror", + "thiserror 1.0.69", "time", "uuid", "walkdir", @@ -2996,7 +3449,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "thiserror", + "thiserror 1.0.69", "url", "uuid", "webview2-com", @@ -3047,7 +3500,7 @@ dependencies = [ "serde", "serde_json", "serde_with", - "thiserror", + "thiserror 1.0.69", "url", "walkdir", "windows-version", @@ -3063,6 +3516,18 @@ dependencies = [ "toml 0.7.8", ] +[[package]] +name = "tauri-winrt-notification" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9" +dependencies = [ + "quick-xml 0.37.5", + "thiserror 2.0.17", + "windows 0.61.3", + "windows-version", +] + [[package]] name = "tempfile" version = "3.23.0" @@ -3099,7 +3564,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", ] [[package]] @@ -3113,6 +3587,17 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "thread_local" version = "1.1.9" @@ -3211,7 +3696,7 @@ checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", "toml_edit 0.19.15", ] @@ -3223,7 +3708,7 @@ checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", "toml_edit 0.22.27", ] @@ -3236,6 +3721,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.19.15" @@ -3245,7 +3739,7 @@ dependencies = [ "indexmap 2.11.4", "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", "winnow 0.5.40", ] @@ -3258,11 +3752,32 @@ dependencies = [ "indexmap 2.11.4", "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", "toml_write", "winnow 0.7.13", ] +[[package]] +name = "toml_edit" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1dee9dc43ac2aaf7d3b774e2fba5148212bf2bd9374f4e50152ebe9afd03d42" +dependencies = [ + "indexmap 2.11.4", + "toml_datetime 0.7.2", + "toml_parser", + "winnow 0.7.13", +] + +[[package]] +name = "toml_parser" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30" +dependencies = [ + "winnow 0.7.13", +] + [[package]] name = "toml_write" version = "0.1.2" @@ -3336,6 +3851,17 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset 0.9.1", + "tempfile", + "winapi", +] + [[package]] name = "unicode-ident" version = "1.0.19" @@ -3494,6 +4020,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.104" @@ -3526,6 +4064,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "web-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webkit2gtk" version = "0.18.2" @@ -3605,7 +4153,7 @@ dependencies = [ "regex", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", "windows 0.39.0", "windows-bindgen", "windows-metadata", @@ -3642,6 +4190,19 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647" +dependencies = [ + "windows_aarch64_msvc 0.37.0", + "windows_i686_gnu 0.37.0", + "windows_i686_msvc 0.37.0", + "windows_x86_64_gnu 0.37.0", + "windows_x86_64_msvc 0.37.0", +] + [[package]] name = "windows" version = "0.39.0" @@ -3665,6 +4226,19 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + [[package]] name = "windows-bindgen" version = "0.39.0" @@ -3675,6 +4249,28 @@ dependencies = [ "windows-tokens", ] +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement 0.60.1", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + [[package]] name = "windows-core" version = "0.62.1" @@ -3683,9 +4279,20 @@ checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" dependencies = [ "windows-implement 0.60.1", "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.2.0", + "windows-result 0.4.0", + "windows-strings 0.5.0", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", ] [[package]] @@ -3720,6 +4327,12 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-link" version = "0.2.0" @@ -3732,13 +4345,41 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ee5e275231f07c6e240d14f34e1b635bf1faa1c76c57cfd59a5cdb9848e4278" +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows-result" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" dependencies = [ - "windows-link", + "windows-link 0.2.0", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -3747,7 +4388,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" dependencies = [ - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -3807,7 +4448,7 @@ version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" dependencies = [ - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -3847,7 +4488,7 @@ version = "0.53.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" dependencies = [ - "windows-link", + "windows-link 0.2.0", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -3858,6 +4499,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows-tokens" version = "0.39.0" @@ -3870,7 +4520,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "700dad7c058606087f6fdc1f88da5841e06da40334413c6cd4367b25ef26d24e" dependencies = [ - "windows-link", + "windows-link 0.2.0", ] [[package]] @@ -3897,6 +4547,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +[[package]] +name = "windows_aarch64_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a" + [[package]] name = "windows_aarch64_msvc" version = "0.39.0" @@ -3927,6 +4583,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +[[package]] +name = "windows_i686_gnu" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1" + [[package]] name = "windows_i686_gnu" version = "0.39.0" @@ -3969,6 +4631,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +[[package]] +name = "windows_i686_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c" + [[package]] name = "windows_i686_msvc" version = "0.39.0" @@ -3999,6 +4667,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +[[package]] +name = "windows_x86_64_gnu" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d" + [[package]] name = "windows_x86_64_gnu" version = "0.39.0" @@ -4053,6 +4727,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +[[package]] +name = "windows_x86_64_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d" + [[package]] name = "windows_x86_64_msvc" version = "0.39.0" @@ -4152,7 +4832,7 @@ dependencies = [ "sha2", "soup2", "tao", - "thiserror", + "thiserror 1.0.69", "url", "webkit2gtk", "webkit2gtk-sys", @@ -4216,6 +4896,66 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zbus" +version = "5.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d07e46d035fb8e375b2ce63ba4e4ff90a7f73cf2ffb0138b29e1158d2eaadf7" +dependencies = [ + "async-broadcast", + "async-executor", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "nix 0.30.1", + "ordered-stream", + "serde", + "serde_repr", + "tracing", + "uds_windows", + "windows-sys 0.60.2", + "winnow 0.7.13", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "5.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e797a9c847ed3ccc5b6254e8bcce056494b375b511b3d6edcec0aeb4defaca" +dependencies = [ + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.106", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" +dependencies = [ + "serde", + "static_assertions", + "winnow 0.7.13", + "zvariant", +] + [[package]] name = "zerocopy" version = "0.8.27" @@ -4289,3 +5029,43 @@ dependencies = [ "quote", "syn 2.0.106", ] + +[[package]] +name = "zvariant" +version = "5.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "999dd3be73c52b1fccd109a4a81e4fcd20fab1d3599c8121b38d04e1419498db" +dependencies = [ + "endi", + "enumflags2", + "serde", + "winnow 0.7.13", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6643fd0b26a46d226bd90d3f07c1b5321fe9bb7f04673cb37ac6d6883885b68e" +dependencies = [ + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.106", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 2.0.106", + "winnow 0.7.13", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 207d530..a921e34 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -14,7 +14,7 @@ tauri-build = { version = "1.5", features = [] } [dependencies] dotenvy = "0.15" -tauri = { version = "1.5", features = ["shell-open", "window-all"] } +tauri = { version = "1.5", features = [ "global-shortcut-all", "notification-all", "shell-open", "window-all", "global-shortcut", "notification"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tokio = { version = "1", features = ["full"] } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 2694b10..487e495 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -2,6 +2,8 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] use serde::Serialize; +use tauri::{Manager, GlobalShortcutManager}; +use tauri::api::notification::Notification; #[derive(Serialize, Clone)] struct Keys { @@ -11,19 +13,20 @@ struct Keys { #[tauri::command] fn get_env_keys() -> Keys { - // In development, the CWD is `src-tauri/target/debug`, so we go up two levels - // to find the project root. - if let Ok(path) = std::env::current_dir() { - if let Some(p) = path.ancestors().nth(2) { - let env_path = p.join(".env"); - dotenvy::from_path(env_path).ok(); - } - } else { - dotenvy::dotenv().ok(); + // Load .env file from the project root. This is more robust than assuming a fixed + // directory structure, as it searches upwards from the executable's location. + match dotenvy::dotenv() { + Ok(_) => println!("✅ [Rust] Successfully loaded .env file."), + Err(e) => println!("❌ [Rust] Failed to load .env file: {}", e), } let openrouter_api_key = std::env::var("OPENROUTER_API_KEY").ok(); let elevenlabs_api_key = std::env::var("ELEVENLABS_API_KEY").ok(); + + // Add detailed logging to see what Rust is reading + println!("🔑 [Rust] OpenRouter Key Loaded: {}", openrouter_api_key.is_some()); + println!("🔑 [Rust] ElevenLabs Key Loaded: {}", elevenlabs_api_key.is_some()); + Keys { openrouter_api_key, elevenlabs_api_key } } @@ -33,10 +36,41 @@ fn greet(name: &str) -> String { format!("Hello, {}! Welcome to EVE.", name) } +#[tauri::command] +fn send_notification(app_handle: tauri::AppHandle, title: String, body: String) -> Result<(), String> { + Notification::new(&app_handle.config().tauri.bundle.identifier) + .title(&title) + .body(&body) + .show() + .map_err(|e| e.to_string())?; + Ok(()) +} + fn main() { + // Note: System tray temporarily disabled on Linux due to icon format issues + // The app works perfectly without it - you can minimize/maximize normally + tauri::Builder::default() - .invoke_handler(tauri::generate_handler![greet, get_env_keys]) - .setup(|_app| { + .invoke_handler(tauri::generate_handler![greet, get_env_keys, send_notification]) + .setup(|app| { + // Register global shortcut to show/hide EVE + let window = app.get_window("main").unwrap(); + let window_clone = window.clone(); + + // Try to register global shortcut, but don't panic if it fails + match app.global_shortcut_manager() + .register("CommandOrControl+Shift+E", move || { + if window_clone.is_visible().unwrap_or(true) { + let _ = window_clone.hide(); + } else { + let _ = window_clone.show(); + let _ = window_clone.set_focus(); + } + }) { + Ok(_) => println!("✅ Global shortcut registered: Ctrl+Shift+E"), + Err(e) => eprintln!("⚠️ Failed to register global shortcut: {}. The app will work without it.", e), + } + #[cfg(debug_assertions)] { // DevTools are available via F12 or the context menu diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index f0de851..e3f7191 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -8,7 +8,7 @@ }, "package": { "productName": "EVE", - "version": "0.1.0" + "version": "0.2.0" }, "tauri": { "allowlist": { @@ -28,6 +28,12 @@ "unminimize": true, "startDragging": true, "setAlwaysOnTop": true + }, + "globalShortcut": { + "all": true + }, + "notification": { + "all": true } }, "bundle": { diff --git a/src/App.tsx b/src/App.tsx index 8ef89cc..f72022c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,6 +5,7 @@ import { ChatInterface } from './components/ChatInterface' import { ModelSelector } from './components/ModelSelector' import { CharacterSelector } from './components/CharacterSelector' import { SettingsPanel } from './components/SettingsPanel' +import { WindowControls } from './components/WindowControls' import { useSettingsStore } from './stores/settingsStore' import { getThemeManager } from './lib/theme' import './App.css' @@ -28,15 +29,30 @@ function App() { // Fetch API keys from the backend on app load async function fetchEnvKeys() { try { + console.log('🔑 Fetching API keys from backend...') const keys = await invoke('get_env_keys') + console.log('🔑 Keys received from backend:', { + hasOpenRouter: !!keys.openrouter_api_key, + hasElevenLabs: !!keys.elevenlabs_api_key, + openRouterLength: keys.openrouter_api_key?.length || 0, + elevenLabsLength: keys.elevenlabs_api_key?.length || 0, + }) + if (keys.openrouter_api_key) { + console.log('✅ Setting OpenRouter API key') setOpenRouterApiKey(keys.openrouter_api_key) + } else { + console.warn('⚠️ No OpenRouter API key found in .env') } + if (keys.elevenlabs_api_key) { + console.log('✅ Setting ElevenLabs API key') setElevenLabsApiKey(keys.elevenlabs_api_key) + } else { + console.warn('⚠️ No ElevenLabs API key found in .env') } } catch (error) { - console.error('Failed to fetch env keys from backend:', error) + console.error('❌ Failed to fetch env keys from backend:', error) } } @@ -45,6 +61,8 @@ function App() { return (
+ {/* Window Controls (invisible, handles minimize to tray) */} + {/* Header */}
diff --git a/src/components/ChatInterface.tsx b/src/components/ChatInterface.tsx index 1146377..e81effd 100644 --- a/src/components/ChatInterface.tsx +++ b/src/components/ChatInterface.tsx @@ -11,6 +11,7 @@ import { VoiceInput } from './VoiceInput' import { FileUpload } from './FileUpload' import { FilePreview } from './FilePreview' import { FileAttachment, isImageFile } from '../lib/fileProcessor' +import { sendNotification, formatNotificationBody } from '../lib/systemIntegration' export function ChatInterface() { const [input, setInput] = useState('') @@ -27,6 +28,8 @@ export function ChatInterface() { maxTokens, ttsConversationMode, voiceEnabled, + notificationsEnabled, + openrouterApiKey, setTtsConversationMode } = useSettingsStore() const { createConversation } = useConversationStore() @@ -78,7 +81,7 @@ export function ChatInterface() { setLoading(true) try { - const client = getOpenRouterClient() + const client = getOpenRouterClient(openrouterApiKey) // Get system prompt from current character const character = getCharacter(currentCharacter) @@ -117,6 +120,12 @@ export function ChatInterface() { role: 'assistant', content: assistantMessage, }) + + // Send notification if enabled + if (notificationsEnabled) { + const notificationBody = formatNotificationBody(assistantMessage) + sendNotification('EVE Response', notificationBody) + } } catch (error) { console.error('Chat error:', error) addMessage({ diff --git a/src/components/SettingsPanel.tsx b/src/components/SettingsPanel.tsx index 3f1505f..adf0da9 100644 --- a/src/components/SettingsPanel.tsx +++ b/src/components/SettingsPanel.tsx @@ -1,4 +1,4 @@ -import { X, Key, Zap, Palette, User, Volume2, Moon, Sun, Monitor } from 'lucide-react' +import { X, Key, Zap, Palette, User, Volume2, Moon, Sun, Monitor, Bell, Minimize2 } from 'lucide-react' import { useSettingsStore } from '../stores/settingsStore' import { getAllCharacters, getCharacter } from '../lib/characters' import { getElevenLabsClient, Voice } from '../lib/elevenlabs' @@ -26,6 +26,8 @@ export function SettingsPanel({ onClose }: SettingsPanelProps) { sttLanguage, sttMode, theme, + notificationsEnabled, + minimizeToTray, setOpenRouterApiKey, setElevenLabsApiKey, setTemperature, @@ -42,6 +44,8 @@ export function SettingsPanel({ onClose }: SettingsPanelProps) { setSttLanguage, setSttMode, setTheme, + setNotificationsEnabled, + setMinimizeToTray, } = useSettingsStore() const [browserVoices, setBrowserVoices] = useState([]) @@ -56,29 +60,52 @@ export function SettingsPanel({ onClose }: SettingsPanelProps) { useEffect(() => { console.log('⚙️ SettingsPanel mounted') console.log('📥 Current ttsVoice from store:', ttsVoice) + console.log('🔑 OpenRouter API Key exists:', !!openrouterApiKey, 'Length:', openrouterApiKey?.length || 0) + console.log('🔑 ElevenLabs API Key exists:', !!elevenLabsApiKey, 'Length:', elevenLabsApiKey?.length || 0) console.log('💾 LocalStorage contents:', localStorage.getItem('eve-settings')) - }, []) + }, [openrouterApiKey, elevenLabsApiKey, ttsVoice]) // Load browser voices useEffect(() => { + // Check if speechSynthesis is available (may not be in Tauri WebView) + if (typeof window === 'undefined' || !window.speechSynthesis) { + console.warn('⚠️ Speech Synthesis API not available in this environment') + return + } + const loadVoices = () => { - const voices = window.speechSynthesis.getVoices() - setBrowserVoices(voices) - console.log(`🔊 Loaded ${voices.length} browser voices`) - - // Check for duplicate voiceURIs - const voiceURIs = voices.map(v => v.voiceURI) - const duplicates = voiceURIs.filter((uri, index) => voiceURIs.indexOf(uri) !== index) - if (duplicates.length > 0) { - console.warn('⚠️ Found duplicate voice URIs:', [...new Set(duplicates)]) + try { + const voices = window.speechSynthesis.getVoices() + setBrowserVoices(voices) + console.log(`🔊 Loaded ${voices.length} browser voices`) + + // Check for duplicate voiceURIs + const voiceURIs = voices.map(v => v.voiceURI) + const duplicates = voiceURIs.filter((uri, index) => voiceURIs.indexOf(uri) !== index) + if (duplicates.length > 0) { + console.warn('⚠️ Found duplicate voice URIs:', [...new Set(duplicates)]) + } + } catch (error) { + console.warn('⚠️ Failed to load browser voices:', error) } } loadVoices() - window.speechSynthesis.addEventListener('voiceschanged', loadVoices) + + try { + window.speechSynthesis.addEventListener('voiceschanged', loadVoices) + } catch (error) { + console.warn('⚠️ Failed to add voiceschanged listener:', error) + } return () => { - window.speechSynthesis.removeEventListener('voiceschanged', loadVoices) + try { + if (window.speechSynthesis) { + window.speechSynthesis.removeEventListener('voiceschanged', loadVoices) + } + } catch (error) { + // Ignore cleanup errors + } } }, []) @@ -695,6 +722,79 @@ export function SettingsPanel({ onClose }: SettingsPanelProps) {
+ {/* System Integration Section */} +
+
+ +

+ System Integration +

+
+
+
+
+
+ + +
+

+ Get notified when EVE responds (even when window is hidden) +

+
+ setNotificationsEnabled(e.target.checked)} + className="w-5 h-5 text-green-500 rounded focus:ring-2 focus:ring-green-500" + /> +
+ +
+
+
+ + + + Linux: Coming Soon + +
+

+ System tray temporarily unavailable on Linux (icon format issue) +

+
+ setMinimizeToTray(e.target.checked)} + disabled + className="w-5 h-5 text-gray-400 rounded cursor-not-allowed" + /> +
+ +
+

+ ⌨️ Global Shortcut: Press{' '} + + Ctrl+Shift+E + {' '} + (or{' '} + + Cmd+Shift+E + {' '} + on Mac) to quickly show/hide EVE. +
+ + Note: May not work on some Linux desktop environments due to permission restrictions. + +

+
+
+
+ {/* Info Section */}
diff --git a/src/components/WindowControls.tsx b/src/components/WindowControls.tsx new file mode 100644 index 0000000..de8493b --- /dev/null +++ b/src/components/WindowControls.tsx @@ -0,0 +1,30 @@ +import { useEffect } from 'react' +import { appWindow } from '@tauri-apps/api/window' +import { useSettingsStore } from '../stores/settingsStore' + +/** + * WindowControls - Handles window behavior like minimize to tray + * This component doesn't render anything, it just sets up event listeners + */ +export function WindowControls() { + const { minimizeToTray } = useSettingsStore() + + useEffect(() => { + if (!minimizeToTray) return + + // Handle window minimize events + const unlisten = appWindow.onCloseRequested(async (event) => { + // Prevent default close behavior + event.preventDefault() + + // Hide window instead of closing (minimize to tray) + await appWindow.hide() + }) + + return () => { + unlisten.then(fn => fn()) + } + }, [minimizeToTray]) + + return null +} diff --git a/src/lib/openrouter.ts b/src/lib/openrouter.ts index 51da581..efd2cb1 100644 --- a/src/lib/openrouter.ts +++ b/src/lib/openrouter.ts @@ -230,13 +230,12 @@ export class OpenRouterClient { /** * Get OpenRouter client instance + * Note: API key should be passed from the settings store, which loads it from the Rust backend */ -export function getOpenRouterClient(): OpenRouterClient { - const apiKey = import.meta.env.VITE_OPENROUTER_API_KEY - +export function getOpenRouterClient(apiKey?: string): OpenRouterClient { if (!apiKey) { throw new Error( - 'OpenRouter API key not found. Please add VITE_OPENROUTER_API_KEY to your .env file' + 'OpenRouter API key not found. Please configure it in Settings.' ) } diff --git a/src/lib/systemIntegration.ts b/src/lib/systemIntegration.ts new file mode 100644 index 0000000..a76ce8d --- /dev/null +++ b/src/lib/systemIntegration.ts @@ -0,0 +1,43 @@ +import { invoke } from '@tauri-apps/api/tauri'; + +/** + * Send a desktop notification + * @param title Notification title + * @param body Notification body text + */ +export async function sendNotification(title: string, body: string): Promise { + try { + await invoke('send_notification', { title, body }); + } catch (error) { + console.error('Failed to send notification:', error); + } +} + +/** + * Truncate text to specified length with ellipsis + */ +export function truncateText(text: string, maxLength: number): string { + if (text.length <= maxLength) return text; + return text.substring(0, maxLength - 3) + '...'; +} + +/** + * Format notification body from message content + * Strips markdown and limits length + */ +export function formatNotificationBody(content: string, maxLength: number = 100): string { + // Remove markdown formatting + let cleaned = content + .replace(/```[\s\S]*?```/g, '[code block]') // Remove code blocks + .replace(/`([^`]+)`/g, '$1') // Remove inline code + .replace(/\*\*([^*]+)\*\*/g, '$1') // Remove bold + .replace(/\*([^*]+)\*/g, '$1') // Remove italic + .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // Remove links + .replace(/^#+\s+/gm, '') // Remove headers + .replace(/^\s*[-*+]\s+/gm, '') // Remove list markers + .replace(/^\s*>\s+/gm, '') // Remove blockquotes + .replace(/\n+/g, ' ') // Replace newlines with spaces + .trim(); + + return truncateText(cleaned, maxLength); +} diff --git a/src/lib/tts.ts b/src/lib/tts.ts index d88bc16..f45d725 100644 --- a/src/lib/tts.ts +++ b/src/lib/tts.ts @@ -68,6 +68,13 @@ class TTSManager { private async speakWithElevenLabs(text: string, options: TTSOptions): Promise { try { + // Check if we're in Tauri - audio playback doesn't work properly in Tauri WebView + const isTauri = typeof window !== 'undefined' && '__TAURI__' in window + if (isTauri) { + console.warn('⚠️ Tauri WebView detected - ElevenLabs audio playback not supported. Falling back to browser TTS.') + return this.speakWithBrowser(text, options) + } + // Get the client (will be initialized with API key from env or settings) const client = getElevenLabsClient() @@ -79,6 +86,7 @@ class TTSManager { // Use provided voice ID or default const voiceId = options.voiceId || 'EXAVITQu4vr4xnSDxMaL' // Default: Bella voice + console.log('🎵 ElevenLabs: Requesting audio from API...') const audioData = await client.textToSpeech( text, voiceId, @@ -88,32 +96,66 @@ class TTSManager { similarityBoost: options.similarityBoost ?? 0.75, } ) + console.log('✅ ElevenLabs: Audio data received, size:', audioData.byteLength, 'bytes') // Play the audio + // Tauri WebView audio playback workaround + // HTMLAudioElement.play() hangs in Tauri on Linux due to GStreamer issues + // Instead, we'll use a data URL approach with base64 encoding + console.log('🎵 Converting audio to base64 for Tauri playback...') const blob = new Blob([audioData], { type: 'audio/mpeg' }) - const url = URL.createObjectURL(blob) - this.currentAudio = new Audio(url) - this.currentAudio.volume = options.volume ?? 1.0 - - this.isPlaying = true - + // Convert to base64 data URL + const reader = new FileReader() + return new Promise((resolve, reject) => { - if (!this.currentAudio) return reject(new Error('Audio element not created')) + reader.onload = () => { + const base64 = reader.result as string + console.log('✅ Audio converted to base64, length:', base64.length) + + console.log('🎵 Creating Audio element with data URL...') + this.currentAudio = new Audio(base64) + this.currentAudio.volume = options.volume ?? 1.0 + console.log('✅ Audio element created') - this.currentAudio.onended = () => { - this.isPlaying = false - URL.revokeObjectURL(url) + this.isPlaying = true + + this.currentAudio.onended = () => { + console.log('✅ Audio playback ended') + this.isPlaying = false + resolve() + } + + this.currentAudio.onerror = (error) => { + console.error('❌ Audio playback error:', error) + this.isPlaying = false + reject(error) + } + + console.log('▶️ Starting audio playback with data URL...') + // Add a small delay to prevent blocking + setTimeout(() => { + this.currentAudio?.play() + .then(() => { + console.log('✅ Audio.play() promise resolved') + }) + .catch((error) => { + console.error('❌ Audio.play() failed:', error) + // Don't reject on play error - audio might still play + }) + }, 100) + + // Resolve immediately - don't wait for playback to finish + // This prevents blocking the UI resolve() } - - this.currentAudio.onerror = (error) => { - this.isPlaying = false - URL.revokeObjectURL(url) - reject(error) + + reader.onerror = () => { + console.error('❌ Failed to convert audio to base64') + reject(new Error('Failed to convert audio data')) } - - this.currentAudio.play().catch(reject) + + reader.readAsDataURL(blob) }) } catch (error) { console.error('ElevenLabs TTS error:', error) @@ -123,23 +165,28 @@ class TTSManager { } private async speakWithBrowser(text: string, options: TTSOptions): Promise { - if (!('speechSynthesis' in window)) { - throw new Error('Browser does not support text-to-speech') + if (typeof window === 'undefined' || !window.speechSynthesis) { + throw new Error('Speech Synthesis API not available in this environment') } return new Promise((resolve, reject) => { // Helper to get voices (they load asynchronously) const getVoicesAsync = (): Promise => { return new Promise((resolveVoices) => { - let voices = window.speechSynthesis.getVoices() - if (voices.length > 0) { - resolveVoices(voices) - } else { - // Wait for voices to load - window.speechSynthesis.onvoiceschanged = () => { - voices = window.speechSynthesis.getVoices() + try { + let voices = window.speechSynthesis.getVoices() + if (voices.length > 0) { resolveVoices(voices) + } else { + // Wait for voices to load + window.speechSynthesis.onvoiceschanged = () => { + voices = window.speechSynthesis.getVoices() + resolveVoices(voices) + } } + } catch (error) { + console.warn('Failed to get voices:', error) + resolveVoices([]) } }) } @@ -223,8 +270,12 @@ class TTSManager { } // Stop browser speech - if (this.currentUtterance) { - window.speechSynthesis.cancel() + if (this.currentUtterance && typeof window !== 'undefined' && window.speechSynthesis) { + try { + window.speechSynthesis.cancel() + } catch (error) { + console.warn('Failed to cancel speech synthesis:', error) + } this.currentUtterance = null } @@ -235,9 +286,13 @@ class TTSManager { if (this.currentAudio) { this.currentAudio.pause() this.isPlaying = false - } else if (window.speechSynthesis.speaking) { - window.speechSynthesis.pause() - this.isPlaying = false + } else if (typeof window !== 'undefined' && window.speechSynthesis?.speaking) { + try { + window.speechSynthesis.pause() + this.isPlaying = false + } catch (error) { + console.warn('Failed to pause speech synthesis:', error) + } } } @@ -245,9 +300,13 @@ class TTSManager { if (this.currentAudio && this.currentAudio.paused) { this.currentAudio.play() this.isPlaying = true - } else if (window.speechSynthesis.paused) { - window.speechSynthesis.resume() - this.isPlaying = true + } else if (typeof window !== 'undefined' && window.speechSynthesis?.paused) { + try { + window.speechSynthesis.resume() + this.isPlaying = true + } catch (error) { + console.warn('Failed to resume speech synthesis:', error) + } } } @@ -256,8 +315,13 @@ class TTSManager { } getBrowserVoices(): SpeechSynthesisVoice[] { - if (!('speechSynthesis' in window)) return [] - return window.speechSynthesis.getVoices() + if (typeof window === 'undefined' || !window.speechSynthesis) return [] + try { + return window.speechSynthesis.getVoices() + } catch (error) { + console.warn('Failed to get browser voices:', error) + return [] + } } } diff --git a/src/stores/settingsStore.ts b/src/stores/settingsStore.ts index e89fc7c..2ce89d2 100644 --- a/src/stores/settingsStore.ts +++ b/src/stores/settingsStore.ts @@ -30,6 +30,10 @@ interface SettingsState { sttLanguage: string sttMode: 'push-to-talk' | 'continuous' + // System Integration Settings + notificationsEnabled: boolean + minimizeToTray: boolean + // Actions setOpenRouterApiKey: (key: string) => void setElevenLabsApiKey: (key: string) => void @@ -49,6 +53,8 @@ interface SettingsState { setTtsConversationMode: (enabled: boolean) => void setSttLanguage: (language: string) => void setSttMode: (mode: 'push-to-talk' | 'continuous') => void + setNotificationsEnabled: (enabled: boolean) => void + setMinimizeToTray: (enabled: boolean) => void } export const useSettingsStore = create()( @@ -73,6 +79,8 @@ export const useSettingsStore = create()( ttsConversationMode: false, sttLanguage: 'en-US', sttMode: 'push-to-talk', + notificationsEnabled: false, + minimizeToTray: true, // Actions setOpenRouterApiKey: (key) => set({ openrouterApiKey: key }), @@ -96,6 +104,8 @@ export const useSettingsStore = create()( setTtsConversationMode: (enabled) => set({ ttsConversationMode: enabled }), setSttLanguage: (language) => set({ sttLanguage: language }), setSttMode: (mode) => set({ sttMode: mode }), + setNotificationsEnabled: (enabled) => set({ notificationsEnabled: enabled }), + setMinimizeToTray: (enabled) => set({ minimizeToTray: enabled }), }), { name: 'eve-settings',