diff --git a/installer/linux/build-appimage.sh b/installer/linux/build-appimage.sh index 1d9a372f..8d284397 100644 --- a/installer/linux/build-appimage.sh +++ b/installer/linux/build-appimage.sh @@ -109,9 +109,13 @@ echo "First launch: installing Mayros CLI..." # Try cached tarball first, then npm registry if [[ -f "$MAYROS_LIB/mayros-cli.tgz" ]]; then - "$NPM" install "$MAYROS_LIB/mayros-cli.tgz" --prefix "$MAYROS_LIB" --force --no-fund --no-audit 2>/dev/null || \ - "$NPM" install @apilium/mayros@latest --prefix "$MAYROS_LIB" --force --no-fund --no-audit 2>/dev/null + echo "Using cached CLI package..." + "$NPM" install "$MAYROS_LIB/mayros-cli.tgz" --prefix "$MAYROS_LIB" --force --no-fund --no-audit 2>/dev/null || { + echo "Cached install failed, falling back to npm registry..." + "$NPM" install @apilium/mayros@latest --prefix "$MAYROS_LIB" --force --no-fund --no-audit 2>/dev/null + } else + echo "No cached package found, installing from npm registry..." "$NPM" install @apilium/mayros@latest --prefix "$MAYROS_LIB" --force --no-fund --no-audit 2>/dev/null fi @@ -151,22 +155,46 @@ CLI="$HERE/usr/lib/mayros/node_modules/@apilium/mayros/dist/index.js" # First launch: install CLI via npm if not present if [[ ! -f "$CLI" ]]; then + echo "Installing Mayros... this may take a minute." + notify-send "Mayros" "Installing Mayros... please wait." 2>/dev/null || true bash "$HERE/usr/lib/mayros/install-cli.sh" fi # Onboard if needed ONBOARD_MARKER="$HOME/.mayros/.onboarded" if [[ ! -f "$ONBOARD_MARKER" ]]; then + echo "Configuring Mayros for first use..." "$NODE" "$CLI" onboard --non-interactive --defaults 2>/dev/null || true fi +# Start Cortex if not running and wait for it +if ! pgrep -f "aingle-cortex" >/dev/null 2>&1; then + "$HERE/usr/bin/aingle-cortex" --port 19090 &>/dev/null & +fi +CORTEX_TRIES=0 +while [[ $CORTEX_TRIES -lt 20 ]]; do + if curl -s --max-time 2 "http://127.0.0.1:19090/health" >/dev/null 2>&1; then + break + fi + CORTEX_TRIES=$((CORTEX_TRIES + 1)) + sleep 1 +done + # Start gateway if not running if ! pgrep -f "mayros gateway" >/dev/null 2>&1; then + echo "Starting Mayros Gateway..." "$NODE" "$CLI" gateway start --background 2>/dev/null & fi # If launched without args (e.g., from desktop), open portal if [[ $# -eq 0 ]]; then + # Wait for gateway to be ready + TRIES=0 + while [[ $TRIES -lt 30 ]]; do + curl -s --max-time 2 "http://127.0.0.1:18789/health" >/dev/null 2>&1 && break + TRIES=$((TRIES + 1)) + sleep 1 + done exec "$NODE" "$CLI" dashboard else exec "$NODE" "$CLI" "$@" @@ -203,8 +231,10 @@ if [[ ! -f "$ASSETS_DIR/mayros.png" ]]; then fi fi -# Copy icon into AppDir -if [[ -f "$ASSETS_DIR/mayros.png" ]]; then +# Copy icon into AppDir — use pre-built 256px PNG from assets +if [[ -f "$ASSETS_DIR/mayros-icon-256.png" ]]; then + cp "$ASSETS_DIR/mayros-icon-256.png" "$APPDIR/mayros.png" +elif [[ -f "$ASSETS_DIR/mayros.png" ]]; then cp "$ASSETS_DIR/mayros.png" "$APPDIR/mayros.png" elif [[ -f "$ASSETS_DIR/mayros-logo.svg" ]]; then if command -v rsvg-convert &>/dev/null; then @@ -213,7 +243,6 @@ elif [[ -f "$ASSETS_DIR/mayros-logo.svg" ]]; then convert -background none -resize 256x256 "$ASSETS_DIR/mayros-logo.svg" "$APPDIR/mayros.png" else echo " -> Warning: no icon converter found, icon will be missing" - printf '\x89PNG\r\n\x1a\n' > "$APPDIR/mayros.png" fi fi diff --git a/installer/linux/build-deb.sh b/installer/linux/build-deb.sh index ca2f7ad1..27bc8de3 100644 --- a/installer/linux/build-deb.sh +++ b/installer/linux/build-deb.sh @@ -163,7 +163,9 @@ else /opt/mayros/bin/mayros onboard --non-interactive --defaults || true fi +echo "" echo "Mayros installed. Run 'mayros' to get started." +echo "NOTE: Please restart your terminal or run 'source ~/.bashrc' for the 'mayros' command to be available." POSTINST chmod 755 "$PKG_DIR/DEBIAN/postinst" diff --git a/installer/macos/build-dmg.sh b/installer/macos/build-dmg.sh index 9c2fb3e5..5fb7369d 100644 --- a/installer/macos/build-dmg.sh +++ b/installer/macos/build-dmg.sh @@ -115,6 +115,9 @@ done # Copy icon if [[ -f "$ASSETS_DIR/mayros.icns" ]]; then cp "$ASSETS_DIR/mayros.icns" "$APP_DIR/Contents/Resources/mayros.icns" +else + echo "Error: $ASSETS_DIR/mayros.icns not found. Cannot build .app without icon." + exit 1 fi # Launcher script @@ -131,29 +134,136 @@ ONBOARD_MARKER="$MAYROS_DIR/.onboarded" export PATH="$RESOURCES/bin:$RESOURCES/node/bin:$PATH" +# Progress notification helper (non-blocking, uses app icon, no buttons) +show_progress() { + osascript -e "display notification \"$1\" with title \"Mayros\"" 2>/dev/null || true +} +dismiss_progress() { + : # notifications auto-dismiss +} + # First launch: install Mayros CLI via npm if [[ ! -f "$CLI" ]]; then - osascript -e 'display notification "Installing Mayros..." with title "Mayros"' 2>/dev/null || true - "$NPM" install -g @apilium/mayros@latest --prefix "$MAYROS_DIR" --force --no-fund --no-audit 2>/dev/null + show_progress "Installing Mayros...\n\nThis may take a minute. Please wait." + if ! "$NPM" install -g @apilium/mayros@latest --prefix "$MAYROS_DIR" --force --no-fund --no-audit 2>/dev/null; then + dismiss_progress + osascript -e 'display alert "Mayros Installation Failed" message "npm install failed. Check your internet connection and try again." as critical' 2>/dev/null || true + exit 1 + fi + dismiss_progress +fi + +# Add ~/.mayros/bin to PATH right after install, so PATH is set even if user quits early +SHELL_PROFILE="" +if [[ -f "$HOME/.zshrc" ]]; then + SHELL_PROFILE="$HOME/.zshrc" +elif [[ -f "$HOME/.bash_profile" ]]; then + SHELL_PROFILE="$HOME/.bash_profile" +elif [[ -f "$HOME/.bashrc" ]]; then + SHELL_PROFILE="$HOME/.bashrc" +fi +if [[ -n "$SHELL_PROFILE" ]] && ! grep -q '.mayros/bin' "$SHELL_PROFILE" 2>/dev/null; then + echo '' >> "$SHELL_PROFILE" + echo '# Mayros CLI' >> "$SHELL_PROFILE" + echo 'export PATH="$HOME/.mayros/bin:$PATH"' >> "$SHELL_PROFILE" fi # Copy Cortex binary to ~/.mayros/bin/ mkdir -p "$MAYROS_DIR/bin" if [[ ! -f "$MAYROS_DIR/bin/aingle-cortex" ]]; then + show_progress "Setting up AIngle Cortex..." cp "$CORTEX" "$MAYROS_DIR/bin/aingle-cortex" chmod +x "$MAYROS_DIR/bin/aingle-cortex" + dismiss_progress +fi + +# Create CLI wrapper so 'mayros' works from any terminal +WRAPPER="$MAYROS_DIR/bin/mayros" +if [[ ! -f "$WRAPPER" ]]; then + cat > "$WRAPPER" <<'WRAP' +#!/usr/bin/env bash +MAYROS_DIR="$HOME/.mayros" +NODE="$MAYROS_DIR/node/bin/node" +# Fallback: use app bundle node if ~/.mayros/node doesn't exist +if [[ ! -f "$NODE" ]]; then + APP_NODE="/Applications/Mayros.app/Contents/Resources/node/bin/node" + [[ -f "$APP_NODE" ]] && NODE="$APP_NODE" +fi +# Try installer location (npm --prefix) +CLI="$MAYROS_DIR/lib/node_modules/@apilium/mayros/dist/index.js" +# Fallback: node_modules at root (some npm versions) +if [[ ! -f "$CLI" ]]; then + CLI="$MAYROS_DIR/node_modules/@apilium/mayros/dist/index.js" +fi +# Fallback: standard npm global install +if [[ ! -f "$CLI" ]]; then + GLOBAL_CLI="$(which mayros 2>/dev/null)" + if [[ -n "$GLOBAL_CLI" && "$GLOBAL_CLI" != "$0" ]]; then + exec "$GLOBAL_CLI" "$@" + fi + echo "Mayros is not installed. Open Mayros.app first or run: npm install -g @apilium/mayros" + exit 1 +fi +exec "$NODE" "$CLI" "$@" +WRAP + chmod +x "$WRAPPER" +fi + +# Link bundled node to ~/.mayros/node/ for CLI use outside the app +# Use symlink if the app is in /Applications to avoid ~500MB copy +if [[ ! -d "$MAYROS_DIR/node" ]]; then + if [[ -d "/Applications/Mayros.app/Contents/Resources/node" ]]; then + ln -s "/Applications/Mayros.app/Contents/Resources/node" "$MAYROS_DIR/node" + else + cp -R "$RESOURCES/node" "$MAYROS_DIR/node" + fi fi # Onboard if needed if [[ ! -f "$ONBOARD_MARKER" ]]; then - "$NODE" "$CLI" onboard --non-interactive --defaults 2>/dev/null || true + show_progress "Configuring Mayros for first use..." + if ! "$NODE" "$CLI" onboard --non-interactive --defaults 2>/dev/null; then + osascript -e 'display notification "Initial setup had issues. You can re-run: mayros onboard" with title "Mayros"' 2>/dev/null || true + fi + dismiss_progress fi +# Start Cortex if not running and wait for it +if ! pgrep -f "aingle-cortex" >/dev/null 2>&1; then + "$MAYROS_DIR/bin/aingle-cortex" --port 19090 &>/dev/null & +fi +CORTEX_TRIES=0 +while [[ $CORTEX_TRIES -lt 20 ]]; do + if curl -s --max-time 2 "http://127.0.0.1:19090/health" >/dev/null 2>&1; then + break + fi + CORTEX_TRIES=$((CORTEX_TRIES + 1)) + sleep 1 +done + # Start gateway if not running if ! pgrep -f "mayros gateway" >/dev/null 2>&1; then + show_progress "Starting Mayros Gateway..." "$NODE" "$CLI" gateway start --background 2>/dev/null & fi +# Wait for gateway to be ready before opening the portal +GATEWAY_URL="http://127.0.0.1:18789/health" +TRIES=0 +MAX_TRIES=30 +while [[ $TRIES -lt $MAX_TRIES ]]; do + if curl -s --max-time 2 "$GATEWAY_URL" >/dev/null 2>&1; then + break + fi + TRIES=$((TRIES + 1)) + sleep 1 +done +dismiss_progress 2>/dev/null || true + +if [[ $TRIES -ge $MAX_TRIES ]]; then + osascript -e 'display notification "Gateway is taking longer than expected. Opening portal anyway." with title "Mayros"' 2>/dev/null || true +fi + # Open the portal exec "$NODE" "$CLI" dashboard LAUNCHER diff --git a/installer/shared/download-deps.sh b/installer/shared/download-deps.sh index 76ec380f..ff177089 100644 --- a/installer/shared/download-deps.sh +++ b/installer/shared/download-deps.sh @@ -34,6 +34,25 @@ fi mkdir -p "$OUTPUT_DIR" +# --------------------------------------------------------------------------- +# Network connectivity check +# --------------------------------------------------------------------------- +echo "==> Checking network connectivity..." +if command -v curl &>/dev/null; then + if ! curl -s --max-time 5 https://github.com > /dev/null 2>&1; then + echo "Error: no internet connection detected." + echo "Please check your network and try again." + exit 1 + fi +elif command -v wget &>/dev/null; then + if ! wget -q --timeout=5 --spider https://github.com 2>/dev/null; then + echo "Error: no internet connection detected." + echo "Please check your network and try again." + exit 1 + fi +fi +echo " -> Connection OK" + # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- @@ -114,17 +133,25 @@ echo "==> Downloading AIngle Cortex $CORTEX_VERSION ($PLATFORM)..." CORTEX_URL="https://github.com/${CORTEX_REPO}/releases/download/v${CORTEX_VERSION}/${CORTEX_FILE}" download "$CORTEX_URL" "$OUTPUT_DIR/$CORTEX_FILE" -# Download checksum file if available +# Download checksum file if available (with retries) CORTEX_SHA_URL="https://github.com/${CORTEX_REPO}/releases/download/v${CORTEX_VERSION}/checksums.sha256" -if curl -fSL --head "$CORTEX_SHA_URL" &>/dev/null 2>&1; then - download "$CORTEX_SHA_URL" "$OUTPUT_DIR/cortex-checksums.sha256" - EXPECTED_CORTEX_SHA=$(grep "$CORTEX_FILE" "$OUTPUT_DIR/cortex-checksums.sha256" | awk '{print $1}') - if [[ -n "$EXPECTED_CORTEX_SHA" ]]; then - verify_sha256 "$OUTPUT_DIR/$CORTEX_FILE" "$EXPECTED_CORTEX_SHA" +CHECKSUM_OK=false +for attempt in 1 2 3; do + if curl -fSL --head "$CORTEX_SHA_URL" &>/dev/null 2>&1; then + if download "$CORTEX_SHA_URL" "$OUTPUT_DIR/cortex-checksums.sha256" 2>/dev/null; then + EXPECTED_CORTEX_SHA=$(grep "$CORTEX_FILE" "$OUTPUT_DIR/cortex-checksums.sha256" | awk '{print $1}') + if [[ -n "$EXPECTED_CORTEX_SHA" ]]; then + verify_sha256 "$OUTPUT_DIR/$CORTEX_FILE" "$EXPECTED_CORTEX_SHA" + CHECKSUM_OK=true + fi + rm -f "$OUTPUT_DIR/cortex-checksums.sha256" + break + fi fi - rm -f "$OUTPUT_DIR/cortex-checksums.sha256" -else - echo " (no checksum file available for Cortex release)" + [[ $attempt -lt 3 ]] && echo " Retrying checksum download (attempt $((attempt + 1))/3)..." && sleep 2 +done +if [[ "$CHECKSUM_OK" != "true" ]]; then + echo " Warning: could not verify Cortex checksum after 3 attempts. Continuing without verification." fi # --------------------------------------------------------------------------- diff --git a/installer/windows/build-installer.ps1 b/installer/windows/build-installer.ps1 index d9ef226a..2897194e 100644 --- a/installer/windows/build-installer.ps1 +++ b/installer/windows/build-installer.ps1 @@ -100,16 +100,67 @@ $installCmd = @" @echo off set "MAYROS_DIR=%LOCALAPPDATA%\Mayros" set "PATH=%MAYROS_DIR%\node;%PATH%" -echo Installing Mayros... -call "%MAYROS_DIR%\node\npm.cmd" install -g @apilium/mayros@latest --prefix "%MAYROS_DIR%" --force --no-fund --no-audit +echo. +echo =================================== +echo Installing Mayros... +echo This may take a minute. +echo =================================== +echo. +:: Locate npm.cmd — try portable node root first, then nested path +set "NPM_CMD=%MAYROS_DIR%\node\npm.cmd" +if not exist "%NPM_CMD%" set "NPM_CMD=%MAYROS_DIR%\node\node_modules\npm\bin\npm-cli.js" +if not exist "%NPM_CMD%" ( + echo ERROR: npm not found in portable Node.js directory. + echo Expected: %MAYROS_DIR%\node\npm.cmd + exit /b 1 +) +call "%NPM_CMD%" install -g @apilium/mayros@latest --prefix "%MAYROS_DIR%" --force --no-fund --no-audit +if errorlevel 1 ( + echo. + echo ERROR: npm install failed. Please check your network connection + echo and try running this command manually: + echo "%NPM_CMD%" install -g @apilium/mayros@latest --prefix "%MAYROS_DIR%" + exit /b 1 +) +echo Configuring Mayros for first use... +call "%MAYROS_DIR%\mayros.cmd" onboard --non-interactive --defaults +if errorlevel 1 ( + echo WARNING: initial configuration had issues, but installation will continue. +) +echo. echo Starting Cortex... start "" "%MAYROS_DIR%\bin\aingle-cortex.exe" --port 19090 +:: Wait for Cortex to be ready before starting gateway +echo Waiting for Cortex to be ready... +set CORTEX_TRIES=0 +:cortexwait +if %CORTEX_TRIES% GEQ 20 goto startgateway +powershell -Command "try { (Invoke-WebRequest -Uri http://127.0.0.1:19090/health -UseBasicParsing -TimeoutSec 2).StatusCode } catch { exit 1 }" >nul 2>&1 +if %errorlevel%==0 goto startgateway +set /a CORTEX_TRIES+=1 +timeout /t 1 /nobreak >nul +goto cortexwait +:startgateway echo Starting Gateway... start "" "%MAYROS_DIR%\mayros.cmd" gateway start -timeout /t 3 /nobreak >nul +echo Waiting for gateway to be ready... +set TRIES=0 +:waitloop +if %TRIES% GEQ 30 goto openbrowser +powershell -Command "try { (Invoke-WebRequest -Uri http://127.0.0.1:18789/health -UseBasicParsing -TimeoutSec 2).StatusCode } catch { exit 1 }" >nul 2>&1 +if %errorlevel%==0 goto openbrowser +set /a TRIES+=1 +timeout /t 1 /nobreak >nul +goto waitloop +:openbrowser echo Opening Mayros Dashboard... start http://127.0.0.1:18789 -echo Done. +echo. +echo =================================== +echo Mayros installed successfully! +echo You can now use 'mayros' from +echo any terminal (restart terminal first). +echo =================================== "@ Set-Content -Path (Join-Path $StageDir "install-mayros.cmd") -Value $installCmd -Encoding ASCII diff --git a/installer/windows/mayros-setup.nsi b/installer/windows/mayros-setup.nsi index 1f1b6a5e..25ce89b4 100644 --- a/installer/windows/mayros-setup.nsi +++ b/installer/windows/mayros-setup.nsi @@ -105,8 +105,8 @@ Section "Mayros" SecMain ; --- Start Menu shortcut --- CreateDirectory "$SMPROGRAMS\Mayros" CreateShortcut "$SMPROGRAMS\Mayros\Mayros Dashboard.lnk" \ - "$INSTDIR\node\node.exe" \ - '"$INSTDIR\bin\open-portal.cmd"' \ + "$WINDIR\system32\cmd.exe" \ + '/c "$INSTDIR\bin\open-portal.cmd"' \ "$INSTDIR\mayros.ico" 0 "" "" "Open Mayros Control Dashboard" CreateShortcut "$SMPROGRAMS\Mayros\Uninstall Mayros.lnk" "$INSTDIR\uninstall.exe" @@ -154,7 +154,7 @@ FunctionEnd Function CreateDesktopShortcut CreateShortcut "$DESKTOP\Mayros Dashboard.lnk" \ - "$INSTDIR\node\node.exe" \ - '"$INSTDIR\bin\open-portal.cmd"' \ + "$WINDIR\system32\cmd.exe" \ + '/c "$INSTDIR\bin\open-portal.cmd"' \ "$INSTDIR\mayros.ico" 0 "" "" "Open Mayros Control Dashboard" FunctionEnd diff --git a/installer/windows/mayros.cmd b/installer/windows/mayros.cmd index 2967f721..7f2e7f26 100644 --- a/installer/windows/mayros.cmd +++ b/installer/windows/mayros.cmd @@ -1,2 +1,27 @@ @echo off -"%~dp0node\node.exe" "%~dp0cli\dist\index.js" %* +setlocal +set "MAYROS_DIR=%LOCALAPPDATA%\Mayros" +set "NODE=%MAYROS_DIR%\node\node.exe" + +:: Try npm global prefix location first (npm --prefix installs here) +set "CLI=%MAYROS_DIR%\lib\node_modules\@apilium\mayros\dist\index.js" +if exist "%CLI%" goto :run + +:: Try alternate location (some npm versions) +set "CLI=%MAYROS_DIR%\node_modules\@apilium\mayros\dist\index.js" +if exist "%CLI%" goto :run + +:: Try standard npm global (installed via npm install -g) +for /f "delims=" %%i in ('where mayros 2^>nul') do ( + if not "%%i"=="%~f0" ( + "%%i" %* + exit /b %errorlevel% + ) +) + +echo Mayros is not installed. Install with: npm install -g @apilium/mayros +echo Or download the installer from https://mayros.apilium.com +exit /b 1 + +:run +"%NODE%" "%CLI%" %* diff --git a/installer/windows/open-portal.cmd b/installer/windows/open-portal.cmd index 0e4a1885..db57609b 100644 --- a/installer/windows/open-portal.cmd +++ b/installer/windows/open-portal.cmd @@ -1,2 +1,25 @@ @echo off -"%~dp0..\node\node.exe" "%~dp0..\cli\dist\index.js" dashboard +setlocal + +set "MAYROS_CMD=%LOCALAPPDATA%\Mayros\mayros.cmd" + +:: Start gateway if not running +tasklist /FI "WINDOWTITLE eq Mayros Gateway" 2>nul | find /i "node.exe" >nul +if errorlevel 1 ( + echo Starting Mayros Gateway... + start /min "" cmd /c "%MAYROS_CMD%" gateway start +) + +:: Wait for gateway to be ready (max 30 seconds) +echo Waiting for gateway... +set TRIES=0 +:waitloop +if %TRIES% GEQ 30 goto openportal +powershell -Command "try { (Invoke-WebRequest -Uri http://127.0.0.1:18789/health -UseBasicParsing -TimeoutSec 2).StatusCode } catch { exit 1 }" >nul 2>&1 +if %errorlevel%==0 goto openportal +set /a TRIES+=1 +timeout /t 1 /nobreak >nul +goto waitloop + +:openportal +start http://127.0.0.1:18789