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 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-08-30 16:55:29 -05:00
co-authored by Claude Opus 5
parent 8e64d8a34f
commit a718caeb08
+115 -32
View File
@@ -21,39 +21,85 @@ echo ============================================
echo. echo.
REM ---------------------------------------------------------------- git check REM ---------------------------------------------------------------- git check
REM Git for Windows only adds itself to PATH if "Git from the command line" was REM Git for Windows only lands on PATH if "Git from the command line" was chosen
REM chosen at install time, and an already-open cmd keeps its old PATH anyway. REM at install time, and an already-open cmd keeps its old PATH regardless. So:
REM So probe the usual install homes before giving up. 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 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%\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 "%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%" if exist "%LOCALAPPDATA%\Programs\Git\cmd\git.exe" set "PATH=%LOCALAPPDATA%\Programs\Git\cmd;%PATH%"
where git >nul 2>&1 where git >nul 2>&1
if not errorlevel 1 ( if not errorlevel 1 goto :git_found_offpath
echo [ok] git ^(found off PATH, added for this run^) if "%GIT_TRIED%"=="1" goto :git_missing
goto :git_done 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 [X] Git not found on PATH, and not in any of:
echo %ProgramFiles%\Git\cmd echo %ProgramFiles%\Git\cmd
echo %LOCALAPPDATA%\Programs\Git\cmd echo %LOCALAPPDATA%\Programs\Git\cmd
echo. 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 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 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 goto :fail
:git_ok
echo [ok] git
:git_done :git_done
echo [ok] git
REM --------------------------------------------------------------- node check 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 where node >nul 2>&1
if not errorlevel 1 goto :node_found if not errorlevel 1 goto :node_found
if exist "%ProgramFiles%\nodejs\node.exe" set "PATH=%ProgramFiles%\nodejs;%PATH%" if exist "%ProgramFiles%\nodejs\node.exe" set "PATH=%ProgramFiles%\nodejs;%PATH%"
if exist "%LOCALAPPDATA%\Programs\nodejs\node.exe" set "PATH=%LOCALAPPDATA%\Programs\nodejs;%PATH%" if exist "%LOCALAPPDATA%\Programs\nodejs\node.exe" set "PATH=%LOCALAPPDATA%\Programs\nodejs;%PATH%"
where node >nul 2>&1 where node >nul 2>&1
if not errorlevel 1 goto :node_found 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 [X] Node.js not found on PATH, and not in any of:
echo %ProgramFiles%\nodejs echo %ProgramFiles%\nodejs
echo %LOCALAPPDATA%\Programs\nodejs echo %LOCALAPPDATA%\Programs\nodejs
@@ -84,15 +130,40 @@ if /i not "%GOON%"=="y" goto :fail
:node_ok :node_ok
REM ------------------------------------------------------------------- python REM ------------------------------------------------------------------- python
where python >nul 2>&1 REM Only the clicker needs Python; the dashboard runs without it.
if errorlevel 1 ( REM
echo [--] python not found - the dashboard will still work. REM Detection is deliberately "run it and see" rather than `where python`:
echo Needed only for the clicker ^(clicker\runner.py^). REM Windows ships a stub python.exe in WindowsApps that only opens the Microsoft
set "HAVE_PY=0" REM Store. `where` finds it, running it does nothing useful. Asking it to print
) else ( REM its major version separates a real interpreter from the stub. The py
echo [ok] python REM launcher is preferred when present - it is not shadowed by the stub.
set "HAVE_PY=1" :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 REM ------------------------------------------------------------------- prompts
echo. echo.
@@ -169,17 +240,29 @@ if errorlevel 1 (
) )
REM ------------------------------------------------------ python deps (option) REM ------------------------------------------------------ python deps (option)
if "%HAVE_PY%"=="1" ( echo.
echo. if not defined PYCMD goto :deps_skip
echo [5/5] Installing clicker Python dependencies... echo [5/5] Installing clicker Python dependencies...
python -m pip install --quiet --disable-pip-version-check -r clicker\requirements.txt REM requirements.txt guards its pyobjc entries with sys_platform == "darwin",
if errorlevel 1 ( REM so on Windows this resolves to pyautogui and its wheels only.
echo [!] pip install failed - the dashboard still works, the clicker will not. %PYCMD% -m pip install --upgrade --quiet --disable-pip-version-check pip
) %PYCMD% -m pip install --quiet --disable-pip-version-check -r clicker\requirements.txt
) else ( if errorlevel 1 goto :deps_failed
echo. %PYCMD% -c "import pyautogui" 2>nul
echo [5/5] Skipping Python dependencies ^(python not found^). 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 REM ---------------------------------------------------------------- start file
> "%~dp0start-autofirmer.bat" ( > "%~dp0start-autofirmer.bat" (