diff --git a/artemis/core/diagnostics/adb_keys.py b/artemis/core/diagnostics/adb_keys.py index 46eca7a..b3a2d03 100644 --- a/artemis/core/diagnostics/adb_keys.py +++ b/artemis/core/diagnostics/adb_keys.py @@ -211,17 +211,21 @@ def heal_adb_keys(adb_path: str | None = None, force: bool = False) -> dict[str, # Restart ADB server to trigger key generation try: + clean_env = os.environ.copy() + clean_env.pop("ADB_SERVER_SOCKET", None) subprocess.run( [resolved_adb, "kill-server"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=5, + env=clean_env, ) subprocess.run( [resolved_adb, "start-server"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=5, + env=clean_env, ) # Execute adb devices to trigger initial handshake & key material generation if needed subprocess.run( @@ -229,6 +233,7 @@ def heal_adb_keys(adb_path: str | None = None, force: bool = False) -> dict[str, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=5, + env=clean_env, ) except Exception as e: logger.error(f"Error restarting ADB server during key healing: {e}") diff --git a/artemis/core/diagnostics/engine.py b/artemis/core/diagnostics/engine.py index c5a9a43..f09bcf4 100644 --- a/artemis/core/diagnostics/engine.py +++ b/artemis/core/diagnostics/engine.py @@ -246,17 +246,21 @@ class ReadinessEngine: return heal_adb_keys(adb_path=adb_path) try: + clean_env = os.environ.copy() + clean_env.pop("ADB_SERVER_SOCKET", None) subprocess.run( [adb_path, "kill-server"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=5, + env=clean_env, ) res = subprocess.run( [adb_path, "start-server"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=5, + env=clean_env, ) success = res.returncode == 0 return { diff --git a/artemis/runtime/device_pool.py b/artemis/runtime/device_pool.py index d585a24..e6f3338 100644 --- a/artemis/runtime/device_pool.py +++ b/artemis/runtime/device_pool.py @@ -247,11 +247,14 @@ class DevicePool: return proc = None try: + clean_env = os.environ.copy() + clean_env.pop("ADB_SERVER_SOCKET", None) proc = await asyncio.create_subprocess_exec( adb, "start-server", stdout=subprocess.PIPE, stderr=subprocess.PIPE, + env=clean_env, ) await asyncio.wait_for(proc.communicate(), timeout=timeout) except Exception as exc: diff --git a/scripts/install_deps.ps1 b/scripts/install_deps.ps1 index 11e519d..beb8912 100644 --- a/scripts/install_deps.ps1 +++ b/scripts/install_deps.ps1 @@ -39,7 +39,9 @@ function Update-EnvironmentPath { $standardDirs = @( "$env:LOCALAPPDATA\Microsoft\WinGet\Links", "$env:LOCALAPPDATA\Android\Sdk\platform-tools", + "$env:LOCALAPPDATA\Android\android-sdk\platform-tools", "$env:ProgramFiles\Android\platform-tools", + "${env:ProgramFiles(x86)}\Android\android-sdk\platform-tools", "$env:ProgramFiles\nodejs", "${env:ProgramFiles(x86)}\nodejs", "$env:APPDATA\npm", @@ -47,16 +49,34 @@ function Update-EnvironmentPath { "$env:LOCALAPPDATA\Programs\node", "$env:USERPROFILE\.local\share\platform-tools", "$env:USERPROFILE\.local\share\node", + "$env:LOCALAPPDATA\nvm", + "$env:ProgramData\nvm", "C:\ProgramData\chocolatey\bin", "$env:USERPROFILE\scoop\shims", "$env:USERPROFILE\.local\bin", "$env:USERPROFILE\.cargo\bin" ) + if ($env:ANDROID_HOME) { $standardDirs += "$env:ANDROID_HOME\platform-tools" } + if ($env:ANDROID_SDK_ROOT) { $standardDirs += "$env:ANDROID_SDK_ROOT\platform-tools" } + if ($env:NVM_HOME) { $standardDirs += $env:NVM_HOME } + if ($env:NVM_SYMLINK) { $standardDirs += $env:NVM_SYMLINK } + $regPath = [Environment]::GetEnvironmentVariable("Path", "User") + ";" + [Environment]::GetEnvironmentVariable("Path", "Machine") $currentPaths = ($env:PATH -split ";") + ($regPath -split ";") + $standardDirs | Where-Object { [string]::IsNullOrWhiteSpace($_) -eq $false -and (Test-Path $_) } | Select-Object -Unique $env:PATH = $currentPaths -join ";" } +function Start-LocalAdbServer { + if (Test-CommandExists "adb") { + try { + $origSocket = $env:ADB_SERVER_SOCKET + Remove-Item Env:\ADB_SERVER_SOCKET -ErrorAction SilentlyContinue + & adb start-server 2>$null | Out-Null + if ($origSocket) { $env:ADB_SERVER_SOCKET = $origSocket } + } catch {} + } +} + function Test-CommandExists { param([string]$Command) $res = Get-Command $Command -ErrorAction SilentlyContinue @@ -132,6 +152,7 @@ if (-not (Test-CommandExists "scrcpy")) { $missingTools += "scrcpy" } if ($missingTools.Count -eq 0) { Write-Host " ✔ All system toolchains are already installed (ADB, FFmpeg, scrcpy)." -ForegroundColor Green + Start-LocalAdbServer } else { Write-Host " ! Missing toolchains: $($missingTools -join ', ')" -ForegroundColor DarkYellow $useWinGet = $false @@ -175,6 +196,9 @@ if ($missingTools.Count -eq 0) { if (-not (Test-CommandExists "adb")) { Install-PortablePlatformTools } + + # Ensure local ADB daemon is warm & listening + Start-LocalAdbServer } # 2. Check and Install uv (Fast Python Package Manager) @@ -285,6 +309,7 @@ Write-Host " ✨ Artemis Environment Ready! " -Foreground Write-Host "======================================================" -ForegroundColor Cyan if ($Launch -or $Open) { + Start-LocalAdbServer Write-Host "🚀 Launching Showcase UI..." -ForegroundColor Green uv run artemis ui --open } else { diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh index 354330d..9e0cd22 100755 --- a/scripts/install_deps.sh +++ b/scripts/install_deps.sh @@ -127,12 +127,31 @@ install_system_packages() { local need_ffmpeg=false local need_scrcpy=false + if ! has_cmd adb; then + for candidate in \ + "${ANDROID_HOME:-}/platform-tools" \ + "${ANDROID_SDK_ROOT:-}/platform-tools" \ + "${HOME}/Library/Android/sdk/platform-tools" \ + "${HOME}/Android/Sdk/platform-tools" \ + "${HOME}/.local/share/platform-tools" \ + "/opt/homebrew/bin" \ + "/usr/local/bin"; do + if [ -n "${candidate}" ] && [ -x "${candidate}/adb" ]; then + export PATH="${candidate}:${PATH}" + break + fi + done + fi + if ! has_cmd adb; then need_adb=true; fi if ! has_cmd ffmpeg; then need_ffmpeg=true; fi if ! has_cmd scrcpy; then need_scrcpy=true; fi if [ "${need_adb}" = false ] && [ "${need_ffmpeg}" = false ] && [ "${need_scrcpy}" = false ]; then echo -e " ${GREEN}✓ All core system tools are already installed.${NC}" + if has_cmd adb; then + (unset ADB_SERVER_SOCKET; adb start-server >/dev/null 2>&1 || true) + fi return 0 fi @@ -234,6 +253,11 @@ install_system_packages() { fi fi fi + + # Ensure local ADB daemon is warm & listening + if has_cmd adb; then + (unset ADB_SERVER_SOCKET; adb start-server >/dev/null 2>&1 || true) + fi } # Function to ensure uv is installed and ready diff --git a/scripts/start.ps1 b/scripts/start.ps1 index 39d2485..f5f75c8 100644 --- a/scripts/start.ps1 +++ b/scripts/start.ps1 @@ -34,7 +34,9 @@ function Update-EnvironmentPath { $standardDirs = @( "$env:LOCALAPPDATA\Microsoft\WinGet\Links", "$env:LOCALAPPDATA\Android\Sdk\platform-tools", + "$env:LOCALAPPDATA\Android\android-sdk\platform-tools", "$env:ProgramFiles\Android\platform-tools", + "${env:ProgramFiles(x86)}\Android\android-sdk\platform-tools", "$env:ProgramFiles\nodejs", "${env:ProgramFiles(x86)}\nodejs", "$env:APPDATA\npm", @@ -42,16 +44,34 @@ function Update-EnvironmentPath { "$env:LOCALAPPDATA\Programs\node", "$env:USERPROFILE\.local\share\platform-tools", "$env:USERPROFILE\.local\share\node", + "$env:LOCALAPPDATA\nvm", + "$env:ProgramData\nvm", "C:\ProgramData\chocolatey\bin", "$env:USERPROFILE\scoop\shims", "$env:USERPROFILE\.local\bin", "$env:USERPROFILE\.cargo\bin" ) + if ($env:ANDROID_HOME) { $standardDirs += "$env:ANDROID_HOME\platform-tools" } + if ($env:ANDROID_SDK_ROOT) { $standardDirs += "$env:ANDROID_SDK_ROOT\platform-tools" } + if ($env:NVM_HOME) { $standardDirs += $env:NVM_HOME } + if ($env:NVM_SYMLINK) { $standardDirs += $env:NVM_SYMLINK } + $regPath = [Environment]::GetEnvironmentVariable("Path", "User") + ";" + [Environment]::GetEnvironmentVariable("Path", "Machine") $currentPaths = ($env:PATH -split ";") + ($regPath -split ";") + $standardDirs | Where-Object { [string]::IsNullOrWhiteSpace($_) -eq $false -and (Test-Path $_) } | Select-Object -Unique $env:PATH = $currentPaths -join ";" } +function Start-LocalAdbServer { + if (Test-CommandExists "adb") { + try { + $origSocket = $env:ADB_SERVER_SOCKET + Remove-Item Env:\ADB_SERVER_SOCKET -ErrorAction SilentlyContinue + & adb start-server 2>$null | Out-Null + if ($origSocket) { $env:ADB_SERVER_SOCKET = $origSocket } + } catch {} + } +} + function Test-CommandExists { param([string]$Command) $res = Get-Command $Command -ErrorAction SilentlyContinue @@ -164,6 +184,9 @@ if ($missingCore.Count -gt 0) { } } +# Ensure local ADB daemon is warm & listening so probes do not hit 'Connection refused' +Start-LocalAdbServer + # 4. Check or initialize .env if (-not (Test-Path ".env")) { if (Test-Path ".env.example") { @@ -259,6 +282,9 @@ if ($installMcp -match "^[Yy]") { Write-Host "" # 8. Launch unified Showcase UI & open browser +# Ensure local ADB daemon is warm & listening +Start-LocalAdbServer + # Launch via `python -m artemis` (not the `artemis.exe` console-script shim) so the # long-running server never locks .venv\Scripts\artemis.exe against `uv sync` reinstalls. Write-Host " [INFO] Launching Artemis Showcase UI & Admin Console..." -ForegroundColor Green diff --git a/start.sh b/start.sh index a96b589..40c12a1 100755 --- a/start.sh +++ b/start.sh @@ -102,6 +102,23 @@ if ! command -v uv >/dev/null 2>&1; then fi # 3. Check and auto-install missing system toolchains (ADB, FFmpeg, scrcpy) +# Discover standard Android SDK / user-space locations if adb not in PATH +if ! command -v adb >/dev/null 2>&1; then + for candidate in \ + "${ANDROID_HOME:-}/platform-tools" \ + "${ANDROID_SDK_ROOT:-}/platform-tools" \ + "${HOME}/Library/Android/sdk/platform-tools" \ + "${HOME}/Android/Sdk/platform-tools" \ + "${HOME}/.local/share/platform-tools" \ + "/opt/homebrew/bin" \ + "/usr/local/bin"; do + if [ -n "${candidate}" ] && [ -x "${candidate}/adb" ]; then + export PATH="${candidate}:${PATH}" + break + fi + done +fi + MISSING_CORE=() if ! command -v adb >/dev/null 2>&1; then MISSING_CORE+=("adb"); fi if ! command -v ffmpeg >/dev/null 2>&1; then MISSING_CORE+=("ffmpeg"); fi @@ -175,6 +192,11 @@ if [ ${#MISSING_CORE[@]} -gt 0 ]; then fi fi +# Ensure local ADB daemon is warm & listening so probes do not hit 'Connection refused' +if command -v adb >/dev/null 2>&1; then + (unset ADB_SERVER_SOCKET; adb start-server >/dev/null 2>&1 || true) +fi + # 4. Check or initialize .env configuration file if [ ! -f ".env" ]; then if [ -f ".env.example" ]; then @@ -314,6 +336,11 @@ if [ "${IS_REMOTE}" = true ]; then echo "" fi +# Ensure local ADB daemon is active and listening before launching UI +if command -v adb >/dev/null 2>&1; then + (unset ADB_SERVER_SOCKET; adb start-server >/dev/null 2>&1 || true) +fi + # Launch via `python -m artemis` (not the `artemis` console-script shim) so the # long-running server never pins .venv/Scripts/artemis[.exe] against reinstalls. exec uv run python -m artemis ui "${OPEN_FLAG}" "$@"