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.
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" (