feat: add NSIS installer and classroom admin checklist
Closes #1983 - Add scripts/installer/codewhale.nsi: NSIS installer that installs both codewhale.exe and codewhale-tui.exe to %LOCALAPPDATA%\Programs\CodeWhale\bin, adds to current-user PATH, and includes an uninstaller that cleans PATH - Add docs/CLASSROOM_INSTALL.md: step-by-step checklist for IT admins deploying CodeWhale in labs/classrooms, covering silent install, manual fallback, API key provisioning, imaging notes, and troubleshooting - Update docs/INSTALL.md: add Windows NSIS Installer section referencing the new installer and classroom checklist
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
# CodeWhale Classroom / Lab Install Checklist
|
||||
|
||||
A step-by-step checklist for IT admins deploying CodeWhale on lab or classroom
|
||||
machines running Windows.
|
||||
|
||||
> **Audience**: IT staff, teaching assistants, lab managers.
|
||||
> **Prereq**: Each target machine runs Windows 10 (1809+) or Windows 11.
|
||||
|
||||
---
|
||||
|
||||
## Pre-install checklist (run once per machine)
|
||||
|
||||
| # | Task | Done? |
|
||||
|---|------|-------|
|
||||
| 1 | Confirm Windows version: `winver` → 10 build 17763+ or 11 | ☐ |
|
||||
| 2 | Ensure the user account is a **standard user** (not a local admin). The installer does not require elevation. | ☐ |
|
||||
| 3 | Verify outbound HTTPS (port 443) is open to `api.openai.com` (or whichever LLM provider the course uses). | ☐ |
|
||||
| 4 | Obtain the installer: download `CodeWhaleSetup.exe` from the [latest release](https://github.com/Hmbown/CodeWhale/releases/latest) or from your department mirror. | ☐ |
|
||||
| 5 | (Optional) Verify SHA-256 hash matches the published manifest. | ☐ |
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### Option A — Silent install (recommended for imaging / SCCM / Intune)
|
||||
|
||||
```powershell
|
||||
# Run as admin or via deployment tool
|
||||
CodeWhaleSetup.exe /S
|
||||
```
|
||||
|
||||
The silent installer:
|
||||
- Installs to `%LOCALAPPDATA%\Programs\CodeWhale\bin`
|
||||
- Adds the bin directory to the **current user** PATH
|
||||
- Registers in Windows "Apps & Features" for uninstall
|
||||
|
||||
### Option B — Interactive install
|
||||
|
||||
1. Double-click `CodeWhaleSetup.exe`.
|
||||
2. Accept the license.
|
||||
3. Choose the install directory (default is fine for most setups).
|
||||
4. Click **Install**.
|
||||
|
||||
### Option C — Manual fallback (no installer)
|
||||
|
||||
If the NSIS installer is blocked by group policy, install manually:
|
||||
|
||||
```powershell
|
||||
# 1. Create directory
|
||||
$binDir = "$env:LOCALAPPDATA\Programs\CodeWhale\bin"
|
||||
New-Item -ItemType Directory -Force -Path $binDir
|
||||
|
||||
# 2. Download binaries (adjust URL to your mirror or release tag)
|
||||
$tag = "v0.9.0" # replace with desired version
|
||||
Invoke-WebRequest -Uri "https://github.com/Hmbown/CodeWhale/releases/download/$tag/codewhale-x64.exe" -OutFile "$binDir\codewhale.exe"
|
||||
Invoke-WebRequest -Uri "https://github.com/Hmbown/CodeWhale/releases/download/$tag/codewhale-tui-x64.exe" -OutFile "$binDir\codewhale-tui.exe"
|
||||
|
||||
# 3. Add to user PATH (persistent)
|
||||
$currentPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
||||
if ($currentPath -notlike "*$binDir*") {
|
||||
[Environment]::SetEnvironmentVariable("Path", "$currentPath;$binDir", "User")
|
||||
}
|
||||
|
||||
# 4. Refresh current session PATH
|
||||
$env:Path = [Environment]::GetEnvironmentVariable("Path", "User") + ";" + [Environment]::GetEnvironmentVariable("Path", "Machine")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Post-install verification
|
||||
|
||||
Run these on **each machine** (or spot-check a sample):
|
||||
|
||||
| # | Command | Expected output | Done? |
|
||||
|---|---------|-----------------|-------|
|
||||
| 1 | `codewhale --version` | Prints version string | ☐ |
|
||||
| 2 | `codewhale doctor` | All checks pass | ☐ |
|
||||
| 3 | `codewhale-tui --version` | Prints version string | ☐ |
|
||||
|
||||
If `codewhale` is not found, the user may need to open a **new** terminal window for PATH changes to take effect.
|
||||
|
||||
---
|
||||
|
||||
## API key provisioning
|
||||
|
||||
Each student needs an API key. Options:
|
||||
|
||||
| Method | Pros | Cons |
|
||||
|--------|------|------|
|
||||
| **Per-student key** | Individual usage tracking | More key management |
|
||||
| **Shared lab key** | Simple to deploy | Harder to audit; rate limits shared |
|
||||
|
||||
### Deploying a shared key via environment variable
|
||||
|
||||
```powershell
|
||||
# Set for current user (persists across reboots)
|
||||
[Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "sk-...", "User")
|
||||
```
|
||||
|
||||
Or create a `config.toml` in `%APPDATA%\codewhale\`:
|
||||
|
||||
```toml
|
||||
[provider]
|
||||
api_key = "sk-..."
|
||||
base_url = "https://api.openai.com/v1"
|
||||
```
|
||||
|
||||
### Deploying per-student keys with Intune / GPO
|
||||
|
||||
Use a Group Policy Preference or Intune PowerShell script to set the
|
||||
`OPENAI_API_KEY` environment variable per user. The variable name depends on
|
||||
your LLM provider — see [CONFIGURATION.md](CONFIGURATION.md).
|
||||
|
||||
---
|
||||
|
||||
## Uninstall
|
||||
|
||||
### Silent uninstall
|
||||
|
||||
```powershell
|
||||
& "$env:LOCALAPPDATA\Programs\CodeWhale\Uninstall.exe" /S
|
||||
```
|
||||
|
||||
### Manual uninstall (if installer was not used)
|
||||
|
||||
```powershell
|
||||
$binDir = "$env:LOCALAPPDATA\Programs\CodeWhale\bin"
|
||||
Remove-Item -Recurse -Force (Split-Path $binDir)
|
||||
|
||||
# Remove from PATH
|
||||
$currentPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
||||
$newPath = ($currentPath -split ";" | Where-Object { $_ -ne $binDir }) -join ";"
|
||||
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Fix |
|
||||
|---------|-----|
|
||||
| `codewhale` not found after install | Open a **new** terminal. If still missing, check PATH: `echo $env:Path` |
|
||||
| `MISSING_COMPANION_BINARY` | Ensure both `codewhale.exe` and `codewhale-tui.exe` are in the same directory |
|
||||
| `TLS handshake` errors | Check proxy settings or use the CNB mirror (see [INSTALL.md](INSTALL.md)) |
|
||||
| Antivirus quarantines binaries | Add the install directory to AV exclusions |
|
||||
| `codewhale doctor` fails API check | Verify `OPENAI_API_KEY` is set or `config.toml` exists |
|
||||
|
||||
---
|
||||
|
||||
## Imaging / Golden Image Notes
|
||||
|
||||
If building a golden image (WIM/FFU):
|
||||
|
||||
1. Install CodeWhale using Option A (silent) or Option C (manual).
|
||||
2. Do **not** set API keys in the image — these are per-user/per-student.
|
||||
3. The install directory (`%LOCALAPPDATA%\Programs\CodeWhale\bin`) is per-user,
|
||||
so it will be present for the user who installed it. For other users on the
|
||||
same machine, run the installer again or use Option C.
|
||||
4. Alternatively, install to a shared location like `C:\Tools\CodeWhale\bin`
|
||||
and add it to the **machine** PATH:
|
||||
```powershell
|
||||
[Environment]::SetEnvironmentVariable("Path", "$env:Path;C:\Tools\CodeWhale\bin", "Machine")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference: All file paths
|
||||
|
||||
| Item | Default location |
|
||||
|------|-----------------|
|
||||
| Binaries | `%LOCALAPPDATA%\Programs\CodeWhale\bin\` |
|
||||
| User config | `%APPDATA%\codewhale\config.toml` |
|
||||
| Uninstaller | `%LOCALAPPDATA%\Programs\CodeWhale\Uninstall.exe` |
|
||||
| PATH entry | `HKCU\Environment\Path` (current user) |
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2026-05-25*
|
||||
@@ -299,6 +299,43 @@ Scoop manifests are maintained outside this repository's release workflow and
|
||||
can lag GitHub/npm/Cargo releases. Use npm or manual GitHub release downloads
|
||||
when you need the newest version immediately.
|
||||
|
||||
### Windows NSIS Installer
|
||||
|
||||
A standalone NSIS-based installer is available for Windows users who prefer a
|
||||
traditional double-click setup (no npm, no Scoop, no Cargo required).
|
||||
|
||||
**Download** `CodeWhaleSetup.exe` from the
|
||||
[Releases page](https://github.com/Hmbown/CodeWhale/releases/latest).
|
||||
|
||||
**Install** by double-clicking the setup executable. The installer:
|
||||
|
||||
- Installs `codewhale.exe` and `codewhale-tui.exe` side-by-side into
|
||||
`%LOCALAPPDATA%\Programs\CodeWhale\bin`
|
||||
- Adds the install directory to the **current user** `PATH`
|
||||
- Registers in Windows **Apps & Features** for easy uninstall
|
||||
|
||||
**Silent install** (for IT admins, SCCM, Intune):
|
||||
|
||||
```powershell
|
||||
CodeWhaleSetup.exe /S
|
||||
```
|
||||
|
||||
**Build the installer yourself** (requires [NSIS](https://nsis.sourceforge.io)):
|
||||
|
||||
```powershell
|
||||
cd scripts\installer
|
||||
# Place codewhale.exe and codewhale-tui.exe here, then:
|
||||
makensis /DVERSION=0.9.0 codewhale.nsi
|
||||
```
|
||||
|
||||
**Manual fallback** — if the installer is blocked by group policy, see the
|
||||
[CLASSROOM_INSTALL.md](CLASSROOM_INSTALL.md) guide for step-by-step PowerShell
|
||||
commands.
|
||||
|
||||
> **Deploying to a classroom or lab?** See the full
|
||||
> [Classroom Install Checklist](CLASSROOM_INSTALL.md) for silent install,
|
||||
> API key provisioning, imaging notes, and troubleshooting.
|
||||
|
||||
---
|
||||
|
||||
## 7. Build from source
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
; codewhale.nsi — NSIS installer for CodeWhale (Windows)
|
||||
;
|
||||
; Requirements (see https://github.com/Hmbown/CodeWhale/issues/1983):
|
||||
; - Install codewhale.exe and codewhale-tui.exe side-by-side
|
||||
; - Default to %LOCALAPPDATA%\Programs\CodeWhale\bin
|
||||
; - Add install dir to current-user PATH
|
||||
; - Uninstaller removes the PATH entry
|
||||
;
|
||||
; Usage:
|
||||
; 1. Place both .exe files next to this script:
|
||||
; codewhale.exe
|
||||
; codewhale-tui.exe
|
||||
; 2. Build:
|
||||
; makensis codewhale.nsi
|
||||
; 3. Output: CodeWhaleSetup.exe (in current directory)
|
||||
;
|
||||
; You can override version at build time:
|
||||
; makensis /DVERSION=1.2.3 codewhale.nsi
|
||||
|
||||
;--------------------------------
|
||||
; Includes
|
||||
;--------------------------------
|
||||
!include "MUI2.nsh"
|
||||
!include "FileFunc.nsh"
|
||||
!include "StrFunc.nsh"
|
||||
|
||||
${StrStr}
|
||||
|
||||
;--------------------------------
|
||||
; General
|
||||
;--------------------------------
|
||||
!ifndef VERSION
|
||||
!define VERSION "0.0.0"
|
||||
!endif
|
||||
|
||||
!define PRODUCT_NAME "CodeWhale"
|
||||
!define PRODUCT_PUBLISHER "Hmbown"
|
||||
!define PRODUCT_WEB_SITE "https://github.com/Hmbown/CodeWhale"
|
||||
|
||||
Name "${PRODUCT_NAME} ${VERSION}"
|
||||
OutFile "CodeWhaleSetup.exe"
|
||||
InstallDir "$LOCALAPPDATA\Programs\CodeWhale"
|
||||
RequestExecutionLevel user
|
||||
BrandingText "${PRODUCT_NAME} Installer"
|
||||
|
||||
;--------------------------------
|
||||
; Interface Settings
|
||||
;--------------------------------
|
||||
!define MUI_ABORTWARNING
|
||||
!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
|
||||
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
|
||||
|
||||
;--------------------------------
|
||||
; Pages
|
||||
;--------------------------------
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_LICENSE "..\..\LICENSE"
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
;--------------------------------
|
||||
; Languages
|
||||
;--------------------------------
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
!insertmacro MUI_LANGUAGE "SimpChinese"
|
||||
|
||||
;--------------------------------
|
||||
; Installer Sections
|
||||
;--------------------------------
|
||||
Section "Install" SecInstall
|
||||
SetOutPath "$INSTDIR\bin"
|
||||
|
||||
; Copy binaries
|
||||
File "codewhale.exe"
|
||||
File "codewhale-tui.exe"
|
||||
|
||||
; Write uninstaller
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
|
||||
; Add to current-user PATH
|
||||
; Read existing PATH, append if not already present
|
||||
ReadRegStr $0 HKCU "Environment" "Path"
|
||||
${StrStr} $1 $0 "$INSTDIR\bin"
|
||||
StrCmp $1 "" 0 path_already_set
|
||||
; Not found — append
|
||||
StrCmp $0 "" empty_path
|
||||
WriteRegExpandStr HKCU "Environment" "Path" "$0;$INSTDIR\bin"
|
||||
Goto path_done
|
||||
empty_path:
|
||||
WriteRegExpandStr HKCU "Environment" "Path" "$INSTDIR\bin"
|
||||
path_done:
|
||||
; Notify the system about the environment change
|
||||
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
|
||||
path_already_set:
|
||||
|
||||
; Store install directory for uninstaller
|
||||
WriteRegStr HKCU "Software\${PRODUCT_NAME}" "InstallDir" "$INSTDIR"
|
||||
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayName" "${PRODUCT_NAME}"
|
||||
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\""
|
||||
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "QuietUninstallString" "$\"$INSTDIR\Uninstall.exe$\" /S"
|
||||
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "Publisher" "${PRODUCT_PUBLISHER}"
|
||||
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
|
||||
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayVersion" "${VERSION}"
|
||||
WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "NoModify" 1
|
||||
WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "NoRepair" 1
|
||||
|
||||
; Calculate and store installed size
|
||||
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
|
||||
IntFmt $0 "0x%08X" $0
|
||||
WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "EstimatedSize" "$0"
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
; Uninstaller Section
|
||||
;--------------------------------
|
||||
Section "Uninstall"
|
||||
; Remove binaries
|
||||
Delete "$INSTDIR\bin\codewhale.exe"
|
||||
Delete "$INSTDIR\bin\codewhale-tui.exe"
|
||||
Delete "$INSTDIR\Uninstall.exe"
|
||||
RMDir "$INSTDIR\bin"
|
||||
RMDir "$INSTDIR"
|
||||
|
||||
; Remove from current-user PATH
|
||||
ReadRegStr $0 HKCU "Environment" "Path"
|
||||
${StrStr} $1 $0 "$INSTDIR\bin"
|
||||
StrCmp $1 "" path_clean_done
|
||||
; Remove the entry
|
||||
; Build new PATH without the install dir
|
||||
; This handles: "...\path;$INSTDIR\bin" and "$INSTDIR\bin;...\path" and standalone
|
||||
Push "$0"
|
||||
Push "$INSTDIR\bin"
|
||||
Call un.RemoveFromPath
|
||||
Pop $0
|
||||
WriteRegExpandStr HKCU "Environment" "Path" "$0"
|
||||
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
|
||||
path_clean_done:
|
||||
|
||||
; Remove registry keys
|
||||
DeleteRegKey HKCU "Software\${PRODUCT_NAME}"
|
||||
DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
; Helper: Remove a directory from PATH
|
||||
; Input: PATH string (on stack), directory to remove (on stack)
|
||||
; Output: cleaned PATH (on stack)
|
||||
;--------------------------------
|
||||
Function un.RemoveFromPath
|
||||
Exch $R0 ; directory to remove
|
||||
Exch
|
||||
Exch $R1 ; original PATH
|
||||
Push $R2
|
||||
Push $R3
|
||||
Push $R4
|
||||
|
||||
StrCpy $R2 ""
|
||||
StrCpy $R3 ""
|
||||
|
||||
loop:
|
||||
${StrStr} $R4 $R1 $R0
|
||||
StrCmp $R4 "" done
|
||||
; Found — get substring before match
|
||||
StrLen $R4 $R4
|
||||
StrLen $R3 $R1
|
||||
IntOp $R3 $R3 - $R4
|
||||
StrCpy $R2 $R1 $R3
|
||||
; Get substring after match + dir length
|
||||
StrLen $R3 $R0
|
||||
IntOp $R4 $R4 - $R3
|
||||
StrCpy $R3 $R1 "" $R4
|
||||
; Strip leading semicolon from remainder
|
||||
StrCpy $R4 $R3 1
|
||||
StrCmp $R4 ";" 0 +2
|
||||
StrCpy $R3 $R3 "" 1
|
||||
; Strip trailing semicolon from prefix
|
||||
StrLen $R4 $R2
|
||||
IntOp $R4 $R4 - 1
|
||||
StrCpy $R4 $R2 1 $R4
|
||||
StrCmp $R4 ";" 0 +2
|
||||
StrCpy $R2 $R2 $R4
|
||||
; Concatenate
|
||||
StrCmp $R2 "" 0 +2
|
||||
StrCpy $R2 $R3
|
||||
Goto done
|
||||
StrCmp $R3 "" 0 +2
|
||||
StrCpy $R1 $R2
|
||||
Goto done
|
||||
StrCpy $R1 "$R2;$R3"
|
||||
Goto done
|
||||
|
||||
done:
|
||||
Pop $R4
|
||||
Pop $R3
|
||||
Pop $R2
|
||||
Pop $R0
|
||||
Exch $R1
|
||||
FunctionEnd
|
||||
Reference in New Issue
Block a user