From a718caeb081f817267711ed21ecd4405e60328b8 Mon Sep 17 00:00:00 2001 From: Brandon Li Date: Sun, 30 Aug 2026 16:55:29 -0500 Subject: [PATCH] Auto-install Git, Node and Python via winget Each prerequisite now follows probe -> offer install -> probe again. The second probe matters: a freshly installed tool is never visible to `where` in the session that installed it, since the process inherited its PATH at start. A *_TRIED guard stops the loop at one attempt. Node installs from the LTS package on purpose - better-sqlite3 publishes prebuilt binaries for LTS, so this sidesteps the node-gyp compile that the existing Node >= 23 warning covers. Python detection runs the interpreter instead of calling `where python`. Windows ships a stub python.exe under WindowsApps that only opens the Microsoft Store; `where` finds it but it cannot execute anything. Asking for sys.version_info distinguishes the two, and the py launcher is preferred because the stub does not shadow it. Dependency install now upgrades pip first and verifies pyautogui actually imports, rather than trusting pip's exit code alone. Co-Authored-By: Claude Opus 5 --- setup-windows.bat | 147 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 115 insertions(+), 32 deletions(-) diff --git a/setup-windows.bat b/setup-windows.bat index c2c610f..6daba00 100644 --- a/setup-windows.bat +++ b/setup-windows.bat @@ -21,39 +21,85 @@ echo ============================================ echo. REM ---------------------------------------------------------------- git check -REM Git for Windows only adds itself to PATH if "Git from the command line" was -REM chosen at install time, and an already-open cmd keeps its old PATH anyway. -REM So probe the usual install homes before giving up. +REM Git for Windows only lands on PATH if "Git from the command line" was chosen +REM at install time, and an already-open cmd keeps its old PATH regardless. So: +REM probe the usual homes, then offer to install, then probe again - a fresh +REM install is never visible to `where` in this session. +:git_probe where git >nul 2>&1 -if not errorlevel 1 goto :git_ok +if not errorlevel 1 goto :git_done if exist "%ProgramFiles%\Git\cmd\git.exe" set "PATH=%ProgramFiles%\Git\cmd;%PATH%" if exist "%ProgramFiles(x86)%\Git\cmd\git.exe" set "PATH=%ProgramFiles(x86)%\Git\cmd;%PATH%" if exist "%LOCALAPPDATA%\Programs\Git\cmd\git.exe" set "PATH=%LOCALAPPDATA%\Programs\Git\cmd;%PATH%" where git >nul 2>&1 -if not errorlevel 1 ( - echo [ok] git ^(found off PATH, added for this run^) - goto :git_done -) +if not errorlevel 1 goto :git_found_offpath +if "%GIT_TRIED%"=="1" goto :git_missing +where winget >nul 2>&1 +if errorlevel 1 goto :git_missing +echo. +echo [--] Git is not installed. +set "DOIT=" +set /p "DOIT= Install it now with winget? [Y/n] " +if /i "%DOIT%"=="n" goto :git_missing +set "GIT_TRIED=1" +echo Installing Git ^(a UAC prompt may appear^)... +winget install --id Git.Git -e --source winget --accept-source-agreements --accept-package-agreements --silent +goto :git_probe + +:git_found_offpath +echo [ok] git ^(found off PATH, added for this run^) +goto :git_done + +:git_missing echo [X] Git not found on PATH, and not in any of: echo %ProgramFiles%\Git\cmd echo %LOCALAPPDATA%\Programs\Git\cmd echo. -echo If Git is NOT installed: https://git-scm.com/download/win +echo Install it from https://git-scm.com/download/win echo If you JUST installed it: close this window, open a new Command echo Prompt and run the script again - an open window keeps its old PATH. -echo If it is installed elsewhere: check with where git goto :fail -:git_ok -echo [ok] git + :git_done +echo [ok] git REM --------------------------------------------------------------- node check +REM winget's LTS package is deliberate: better-sqlite3 publishes prebuilt +REM binaries for LTS Node, so installing LTS sidesteps the node-gyp build. +:node_probe where node >nul 2>&1 if not errorlevel 1 goto :node_found if exist "%ProgramFiles%\nodejs\node.exe" set "PATH=%ProgramFiles%\nodejs;%PATH%" if exist "%LOCALAPPDATA%\Programs\nodejs\node.exe" set "PATH=%LOCALAPPDATA%\Programs\nodejs;%PATH%" where node >nul 2>&1 if not errorlevel 1 goto :node_found +if "%NODE_TRIED%"=="1" goto :node_missing +where winget >nul 2>&1 +if errorlevel 1 goto :node_missing +echo. +echo [--] Node.js is not installed. +set "DOIT=" +set /p "DOIT= Install Node 22 LTS now with winget? [Y/n] " +if /i "%DOIT%"=="n" goto :node_missing +set "NODE_TRIED=1" +echo Installing Node LTS ^(a UAC prompt may appear^)... +winget install --id OpenJS.NodeJS.LTS -e --source winget --accept-source-agreements --accept-package-agreements --silent +goto :node_probe + +:node_missing +echo [X] Node.js not found on PATH, and not in any of: +echo %ProgramFiles%\nodejs +echo %LOCALAPPDATA%\Programs\nodejs +echo. +echo Install Node 22 LTS from https://nodejs.org/ then re-run. +echo If you JUST installed it, open a NEW Command Prompt first. +goto :fail + +:node_found +if exist "%ProgramFiles%\nodejs\node.exe" set "PATH=%ProgramFiles%\nodejs;%PATH%" +if exist "%LOCALAPPDATA%\Programs\nodejs\node.exe" set "PATH=%LOCALAPPDATA%\Programs\nodejs;%PATH%" +where node >nul 2>&1 +if not errorlevel 1 goto :node_found echo [X] Node.js not found on PATH, and not in any of: echo %ProgramFiles%\nodejs echo %LOCALAPPDATA%\Programs\nodejs @@ -84,15 +130,40 @@ if /i not "%GOON%"=="y" goto :fail :node_ok REM ------------------------------------------------------------------- python -where python >nul 2>&1 -if errorlevel 1 ( - echo [--] python not found - the dashboard will still work. - echo Needed only for the clicker ^(clicker\runner.py^). - set "HAVE_PY=0" -) else ( - echo [ok] python - set "HAVE_PY=1" -) +REM Only the clicker needs Python; the dashboard runs without it. +REM +REM Detection is deliberately "run it and see" rather than `where python`: +REM Windows ships a stub python.exe in WindowsApps that only opens the Microsoft +REM Store. `where` finds it, running it does nothing useful. Asking it to print +REM its major version separates a real interpreter from the stub. The py +REM launcher is preferred when present - it is not shadowed by the stub. +:py_probe +set "PYCMD=" +for /f "tokens=*" %%v in ('py -3 -c "import sys;print(sys.version_info[0])" 2^>nul') do if "%%v"=="3" set "PYCMD=py -3" +if not defined PYCMD for /f "tokens=*" %%v in ('python -c "import sys;print(sys.version_info[0])" 2^>nul') do if "%%v"=="3" set "PYCMD=python" +if defined PYCMD goto :py_found +if "%PY_TRIED%"=="1" goto :py_skip +where winget >nul 2>&1 +if errorlevel 1 goto :py_skip +echo. +echo [--] Python is not installed ^(needed only for the clicker^). +set "DOIT=" +set /p "DOIT= Install Python 3.12 now with winget? [Y/n] " +if /i "%DOIT%"=="n" goto :py_skip +set "PY_TRIED=1" +echo Installing Python ^(a UAC prompt may appear^)... +winget install --id Python.Python.3.12 -e --source winget --accept-source-agreements --accept-package-agreements --silent +goto :py_probe + +:py_skip +echo [--] python not found - the dashboard will still work. +echo Needed only for the clicker ^(clicker\runner.py^). +goto :py_end + +:py_found +for /f "tokens=*" %%v in ('%PYCMD% -c "import sys;print(sys.version.split()[0])" 2^>nul') do set "PYVER=%%v" +echo [ok] python %PYVER% ^(via "%PYCMD%"^) +:py_end REM ------------------------------------------------------------------- prompts echo. @@ -169,17 +240,29 @@ if errorlevel 1 ( ) REM ------------------------------------------------------ python deps (option) -if "%HAVE_PY%"=="1" ( - echo. - echo [5/5] Installing clicker Python dependencies... - python -m pip install --quiet --disable-pip-version-check -r clicker\requirements.txt - if errorlevel 1 ( - echo [!] pip install failed - the dashboard still works, the clicker will not. - ) -) else ( - echo. - echo [5/5] Skipping Python dependencies ^(python not found^). -) +echo. +if not defined PYCMD goto :deps_skip +echo [5/5] Installing clicker Python dependencies... +REM requirements.txt guards its pyobjc entries with sys_platform == "darwin", +REM so on Windows this resolves to pyautogui and its wheels only. +%PYCMD% -m pip install --upgrade --quiet --disable-pip-version-check pip +%PYCMD% -m pip install --quiet --disable-pip-version-check -r clicker\requirements.txt +if errorlevel 1 goto :deps_failed +%PYCMD% -c "import pyautogui" 2>nul +if errorlevel 1 goto :deps_failed +echo pyautogui imports cleanly. +goto :deps_done + +:deps_failed +echo [!] Python dependency install failed - the dashboard still works, +echo the clicker will not. Retry by hand with: +echo %PYCMD% -m pip install -r clicker\requirements.txt +goto :deps_done + +:deps_skip +echo [5/5] Skipping Python dependencies ^(python not found^). + +:deps_done REM ---------------------------------------------------------------- start file > "%~dp0start-autofirmer.bat" (