Last active
May 19, 2026 22:54
-
-
Save wpsmith/4c8389fe19292074138b0573191602c4 to your computer and use it in GitHub Desktop.
Claude Code Setup Scripts — UConn MBA Leading with AI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "hooks": { | |
| "PreToolUse": [] | |
| }, | |
| "env": { | |
| "ANTHROPIC_BASE_URL": "https://litellm.sparkai.brightlysoftware.io", | |
| "ANTHROPIC_DEFAULT_SONNET_MODEL": "sparkai-developer-claude", | |
| "ANTHROPIC_DEFAULT_HAIKU_MODEL": "sparkai-developer-claude", | |
| "ANTHROPIC_DEFAULT_OPUS_MODEL": "sparkai-developer-claude", | |
| "DISABLE_PROMPT_CACHING": "0", | |
| "CLAUDE_CODE_DISABLE_1M_CONTEXT": "1", | |
| "CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS": "1", | |
| "CLAUDE_CODE_BLOCKING_LIMIT_OVERRIDE": "200000", | |
| "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "75", | |
| "CLAUDE_CODE_EFFORT_LEVEL": "medium", | |
| "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", | |
| "CLAUDE_CODE_FORK_SUBAGENT": "1", | |
| "CLAUDE_CODE_ENABLE_TELEMETRY": "1", | |
| }, | |
| "skipWebFetchPreflight": true, | |
| "mcpServers": { | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #Requires -RunAsAdministrator | |
| <# | |
| .SYNOPSIS | |
| UConn MBA — Leading with AI: Windows Setup for Claude Code | |
| .DESCRIPTION | |
| Automates the full Claude Code setup for students on Windows: | |
| 1. Pre-flight (winget check) | |
| 2. Install Chocolatey | |
| 3. Install Git for Windows (Git Bash) | |
| 4. Install Node.js | |
| 5. Install Claude Code CLI | |
| 6. Install Visual Studio Code and Claude Code extension | |
| 7. Configure LiteLLM environment variables | |
| 8. Install Claude Code settings.json | |
| 9. Run a quick smoke test | |
| Run as Administrator: Right-click PowerShell -> "Run as Administrator" | |
| Then: Set-ExecutionPolicy Bypass -Scope Process; .\setup-claude-code.ps1 | |
| #> | |
| Set-StrictMode -Version Latest | |
| $ErrorActionPreference = "Stop" | |
| # Configure execution policy | |
| # Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser | |
| # Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\PowerShell -Name ExecutionPolicy -Value ByPass | |
| # --------------------------------------------------------------------------- | |
| # LiteLLM constants | |
| # --------------------------------------------------------------------------- | |
| $LiteLLMUrl = "https://litellm.sparkai.brightlysoftware.io" | |
| $DefaultSonnet = "Claude-Sonnet-4.6-us" | |
| $DefaultHaiku = "Claude-Haiku-4.5-us" | |
| $DefaultOpus = "Claude-Sonnet-4.6-us" | |
| # --------------------------------------------------------------------------- | |
| # Helpers | |
| # --------------------------------------------------------------------------- | |
| function Write-Header { | |
| Write-Host "" | |
| Write-Host "===========================================================================" | |
| Write-Host " UConn MBA — Leading with AI: Claude Code Setup (Windows)" | |
| Write-Host "===========================================================================" | |
| Write-Host "" | |
| } | |
| function Write-Info { param([string]$Message) Write-Host " [INFO] $Message" } | |
| function Write-Ok { param([string]$Message) Write-Host " [OK] $Message" -ForegroundColor Green } | |
| function Write-Warn { param([string]$Message) Write-Host " [WARN] $Message" -ForegroundColor Yellow } | |
| function Write-Skip { param([string]$Message) Write-Host " [SKIP] $Message" -ForegroundColor DarkGray } | |
| function Write-Fail { param([string]$Message) Write-Host " [ERROR] $Message" -ForegroundColor Red; exit 1 } | |
| function Confirm-Step { | |
| param([string]$Prompt) | |
| $answer = Read-Host " $Prompt [Y/n]" | |
| if ([string]::IsNullOrWhiteSpace($answer)) { $answer = "Y" } | |
| return ($answer -match '^[Yy]') | |
| } | |
| function Install-WithWinget { | |
| param( | |
| [string]$PackageId, | |
| [string]$DisplayName, | |
| [string]$TestCommand | |
| ) | |
| if ($TestCommand -and (Get-Command $TestCommand -ErrorAction SilentlyContinue)) { | |
| Write-Ok "$DisplayName already installed" | |
| return | |
| } | |
| Write-Info "Installing $DisplayName..." | |
| winget install --id $PackageId --accept-source-agreements --accept-package-agreements --silent | |
| if ($LASTEXITCODE -ne 0) { | |
| Write-Warn "winget install for $DisplayName exited with code $LASTEXITCODE. Check output above." | |
| } else { | |
| Write-Ok "$DisplayName installed" | |
| } | |
| } | |
| function Set-EnvVar { | |
| param( | |
| [string]$Name, | |
| [string]$Value | |
| ) | |
| $existing = [System.Environment]::GetEnvironmentVariable($Name, [System.EnvironmentVariableTarget]::User) | |
| if ($existing) { | |
| Write-Info "$Name already set - skipping" | |
| return | |
| } | |
| [System.Environment]::SetEnvironmentVariable($Name, $Value, [System.EnvironmentVariableTarget]::User) | |
| Set-Item -Path "Env:\$Name" -Value $Value | |
| Write-Ok "Added $Name" | |
| } | |
| function Refresh-Path { | |
| $machinePath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine) | |
| $userPath = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User) | |
| $env:Path = "$machinePath;$userPath" | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Overview | |
| # --------------------------------------------------------------------------- | |
| function Show-Overview { | |
| Write-Host " This script will walk you through installing the tools needed for" | |
| Write-Host " Thursday's build day. Each step will ask for your permission before" | |
| Write-Host " making changes." | |
| Write-Host "" | |
| Write-Host " Here's what we'll cover:" | |
| Write-Host "" | |
| Write-Host " +--------------------+------------------------------------------------+" | |
| Write-Host " | TOOL | WHY |" | |
| Write-Host " +--------------------+------------------------------------------------+" | |
| Write-Host " | Chocolatey | Windows package manager - helps install tools |" | |
| Write-Host " | Git for Windows | Version control + Git Bash terminal |" | |
| Write-Host " | Node.js | Required runtime for Claude Code CLI |" | |
| Write-Host " | Claude Code CLI | AI coding assistant you'll use to build your |" | |
| Write-Host " | | prototype on Thursday |" | |
| Write-Host " | Visual Studio Code| Code editor with Claude Code integration |" | |
| Write-Host " | LiteLLM Config | Connects Claude Code to the course AI gateway |" | |
| Write-Host " | | using your personal API key |" | |
| Write-Host " +--------------------+------------------------------------------------+" | |
| Write-Host "" | |
| Write-Host " Tools already installed will be detected and skipped automatically." | |
| Write-Host "" | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 1 - Pre-flight | |
| # --------------------------------------------------------------------------- | |
| function Step-Preflight { | |
| Write-Host "" | |
| Write-Host "--- Step 1: Pre-flight ---" | |
| Write-Host " Checking that winget (Windows package manager) is available." | |
| Write-Host "" | |
| if (-not (Get-Command winget -ErrorAction SilentlyContinue)) { | |
| Write-Fail "winget is required but not found. Install 'App Installer' from the Microsoft Store, then re-run this script." | |
| } | |
| Write-Ok "winget available" | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 2 - Chocolatey | |
| # --------------------------------------------------------------------------- | |
| function Step-Chocolatey { | |
| Write-Host "" | |
| Write-Host "--- Step 2: Chocolatey ---" | |
| Write-Host " Chocolatey is a package manager for Windows. Some tools install" | |
| Write-Host " more reliably through it than winget alone." | |
| Write-Host "" | |
| if (Get-Command choco -ErrorAction SilentlyContinue) { | |
| Write-Ok "Chocolatey already installed ($(choco --version))" | |
| return | |
| } | |
| if (-not (Confirm-Step "Install Chocolatey?")) { | |
| Write-Skip "Chocolatey" | |
| return | |
| } | |
| Write-Info "Installing Chocolatey..." | |
| try { | |
| Set-ExecutionPolicy Bypass -Scope Process -Force | |
| } catch { | |
| Write-Info "Execution policy already permissive — continuing" | |
| } | |
| [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 | |
| Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) | |
| Refresh-Path | |
| Write-Ok "Chocolatey installed" | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 3 - Git for Windows (Git Bash) | |
| # --------------------------------------------------------------------------- | |
| function Step-Git { | |
| Write-Host "" | |
| Write-Host "--- Step 3: Git for Windows ---" | |
| Write-Host " Git is version control software. Git Bash gives you a Unix-like" | |
| Write-Host " terminal on Windows, which is useful for development work." | |
| Write-Host "" | |
| if (Get-Command git -ErrorAction SilentlyContinue) { | |
| Write-Ok "Git already installed" | |
| return | |
| } | |
| if (-not (Confirm-Step "Install Git for Windows?")) { | |
| Write-Skip "Git for Windows" | |
| return | |
| } | |
| Install-WithWinget -PackageId "Git.Git" -DisplayName "Git for Windows" -TestCommand "git" | |
| Refresh-Path | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 4 - Node.js | |
| # --------------------------------------------------------------------------- | |
| function Step-Node { | |
| Write-Host "" | |
| Write-Host "--- Step 4: Node.js ---" | |
| Write-Host " Node.js is the JavaScript runtime that Claude Code is built on." | |
| Write-Host " Without it, the Claude Code CLI cannot run." | |
| Write-Host "" | |
| if (Get-Command node -ErrorAction SilentlyContinue) { | |
| Write-Ok "Node.js already installed ($(node --version))" | |
| Write-Info "npm version: $(npm --version)" | |
| return | |
| } | |
| if (-not (Confirm-Step "Install Node.js LTS?")) { | |
| Write-Skip "Node.js — Claude Code will not work without it" | |
| return | |
| } | |
| Install-WithWinget -PackageId "OpenJS.NodeJS.LTS" -DisplayName "Node.js LTS" -TestCommand "node" | |
| Refresh-Path | |
| if (Get-Command node -ErrorAction SilentlyContinue) { | |
| Write-Info "npm version: $(npm --version)" | |
| } | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 5 - Claude Code CLI | |
| # --------------------------------------------------------------------------- | |
| function Step-ClaudeCode { | |
| Write-Host "" | |
| Write-Host "--- Step 5: Claude Code CLI ---" | |
| Write-Host " Claude Code is the AI developer tool you'll use on Thursday to" | |
| Write-Host " build your prototype. It reads files, writes code, and runs commands." | |
| Write-Host "" | |
| if (Get-Command claude -ErrorAction SilentlyContinue) { | |
| Write-Ok "Claude Code CLI already installed" | |
| return | |
| } | |
| if (-not (Confirm-Step "Install Claude Code CLI?")) { | |
| Write-Skip "Claude Code — this is required for Thursday's build day" | |
| return | |
| } | |
| Install-WithWinget -PackageId "Anthropic.ClaudeCode" -DisplayName "Claude Code CLI" -TestCommand "claude" | |
| Refresh-Path | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 6 - Visual Studio Code + Claude Code extension | |
| # --------------------------------------------------------------------------- | |
| function Step-VSCode { | |
| Write-Host "" | |
| Write-Host "--- Step 6: Visual Studio Code ---" | |
| Write-Host " VS Code is a code editor with a Claude Code extension that gives" | |
| Write-Host " you an integrated AI assistant inside the editor. Optional but" | |
| Write-Host " recommended." | |
| Write-Host "" | |
| $vscodeInstalled = Get-Command code -ErrorAction SilentlyContinue | |
| if (-not $vscodeInstalled) { | |
| if (-not (Confirm-Step "Install Visual Studio Code?")) { | |
| Write-Skip "VS Code — you can still use Claude Code from the terminal" | |
| return | |
| } | |
| Install-WithWinget -PackageId "Microsoft.VisualStudioCode" -DisplayName "VS Code" -TestCommand "code" | |
| Refresh-Path | |
| $vscodeInstalled = Get-Command code -ErrorAction SilentlyContinue | |
| } else { | |
| Write-Ok "VS Code already installed" | |
| } | |
| if ($vscodeInstalled) { | |
| Write-Host "" | |
| Write-Host " The Claude Code extension adds AI assistance directly inside VS Code." | |
| Write-Host "" | |
| if (Confirm-Step "Install the Claude Code extension for VS Code?") { | |
| Write-Info "Installing Claude Code extension..." | |
| code --install-extension "anthropic.claude-code" --force 2>&1 | Out-Null | |
| Write-Ok "anthropic.claude-code extension installed" | |
| } else { | |
| Write-Skip "Claude Code extension — install it later from the VS Code marketplace" | |
| } | |
| } | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 7 - LiteLLM environment variables | |
| # --------------------------------------------------------------------------- | |
| function Step-Environment { | |
| Write-Host "" | |
| Write-Host "--- Step 7: LiteLLM Environment ---" | |
| Write-Host " Claude Code needs to connect to the course AI gateway (LiteLLM" | |
| Write-Host " proxy) instead of Anthropic directly. This step saves your API" | |
| Write-Host " key and the gateway URL so Claude Code uses them automatically." | |
| Write-Host "" | |
| if (-not (Confirm-Step "Configure LiteLLM environment variables?")) { | |
| Write-Skip "LiteLLM config — Claude Code will not connect without this" | |
| return | |
| } | |
| Write-Host "" | |
| Write-Host " Enter the API key provided to you by the instructor." | |
| Write-Host "" | |
| $apiKey = "" | |
| while ([string]::IsNullOrWhiteSpace($apiKey)) { | |
| $apiKey = Read-Host " Your LiteLLM API key" | |
| if ([string]::IsNullOrWhiteSpace($apiKey)) { | |
| Write-Warn "Key cannot be empty. Please try again." | |
| } | |
| } | |
| Write-Host "" | |
| Write-Info "Setting user-level environment variables..." | |
| Set-EnvVar -Name "ANTHROPIC_BASE_URL" -Value $LiteLLMUrl | |
| Set-EnvVar -Name "ANTHROPIC_API_KEY" -Value $apiKey | |
| Set-EnvVar -Name "ANTHROPIC_DEFAULT_SONNET_MODEL" -Value $DefaultSonnet | |
| Set-EnvVar -Name "ANTHROPIC_DEFAULT_HAIKU_MODEL" -Value $DefaultHaiku | |
| Set-EnvVar -Name "ANTHROPIC_DEFAULT_OPUS_MODEL" -Value $DefaultOpus | |
| Set-EnvVar -Name "DISABLE_COMPACT" -Value "1" | |
| Write-Ok "Environment variables loaded" | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 8 — Claude Code settings.json | |
| # --------------------------------------------------------------------------- | |
| function Step-ClaudeSettings { | |
| Write-Host "" | |
| Write-Host "--- Step 8: Claude Code Settings ---" | |
| Write-Host " Claude Code uses a settings.json file to configure behavior like" | |
| Write-Host " model routing, context limits, and gateway connection. This step" | |
| Write-Host " installs the course-recommended settings." | |
| Write-Host "" | |
| if (-not (Confirm-Step "Install Claude Code settings?")) { | |
| Write-Skip "Claude Code settings — you can configure manually later" | |
| return | |
| } | |
| $claudeDir = Join-Path $env:USERPROFILE ".claude" | |
| $settingsPath = Join-Path $claudeDir "settings.json" | |
| if (-not (Test-Path $claudeDir)) { | |
| New-Item -ItemType Directory -Path $claudeDir -Force | Out-Null | |
| } | |
| $courseSettings = @{ | |
| env = @{ | |
| ANTHROPIC_BASE_URL = $LiteLLMUrl | |
| ANTHROPIC_DEFAULT_SONNET_MODEL = "sparkai-developer-claude" | |
| ANTHROPIC_DEFAULT_HAIKU_MODEL = "sparkai-developer-claude" | |
| ANTHROPIC_DEFAULT_OPUS_MODEL = "sparkai-developer-claude" | |
| DISABLE_PROMPT_CACHING = "0" | |
| CLAUDE_CODE_DISABLE_1M_CONTEXT = "1" | |
| CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = "1" | |
| CLAUDE_CODE_BLOCKING_LIMIT_OVERRIDE = "200000" | |
| CLAUDE_AUTOCOMPACT_PCT_OVERRIDE = "75" | |
| CLAUDE_CODE_EFFORT_LEVEL = "medium" | |
| CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = "1" | |
| CLAUDE_CODE_FORK_SUBAGENT = "1" | |
| CLAUDE_CODE_ENABLE_TELEMETRY = "1" | |
| } | |
| skipWebFetchPreflight = $true | |
| } | |
| if (Test-Path $settingsPath) { | |
| Write-Info "Existing settings.json found — merging..." | |
| try { | |
| $existing = Get-Content $settingsPath -Raw | ConvertFrom-Json | |
| $existingHash = @{} | |
| $existing.PSObject.Properties | ForEach-Object { $existingHash[$_.Name] = $_.Value } | |
| if ($existingHash.ContainsKey("env")) { | |
| $existingEnv = @{} | |
| $existingHash["env"].PSObject.Properties | ForEach-Object { $existingEnv[$_.Name] = $_.Value } | |
| foreach ($key in $courseSettings.env.Keys) { | |
| $existingEnv[$key] = $courseSettings.env[$key] | |
| } | |
| $existingHash["env"] = $existingEnv | |
| } else { | |
| $existingHash["env"] = $courseSettings.env | |
| } | |
| $existingHash["skipWebFetchPreflight"] = $true | |
| $existingHash | ConvertTo-Json -Depth 5 | Set-Content $settingsPath -Encoding UTF8 | |
| } catch { | |
| Write-Warn "Could not parse existing settings — backing up and replacing" | |
| Copy-Item $settingsPath "$settingsPath.bak" | |
| $courseSettings | ConvertTo-Json -Depth 5 | Set-Content $settingsPath -Encoding UTF8 | |
| } | |
| } else { | |
| $courseSettings | ConvertTo-Json -Depth 5 | Set-Content $settingsPath -Encoding UTF8 | |
| } | |
| Write-Ok "Claude Code settings installed at $settingsPath" | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 9 — Smoke test | |
| # --------------------------------------------------------------------------- | |
| function Step-SmokeTest { | |
| Write-Host "" | |
| Write-Host "--- Step 9: Smoke Test ---" | |
| Write-Host " This launches Claude Code to verify everything is working." | |
| Write-Host "" | |
| if (-not $env:ANTHROPIC_BASE_URL) { | |
| Write-Warn "ANTHROPIC_BASE_URL not set — skipping smoke test" | |
| return | |
| } | |
| if (-not (Get-Command claude -ErrorAction SilentlyContinue)) { | |
| Write-Warn "Claude CLI not found in PATH — skipping smoke test. Restart your terminal and run: claude" | |
| return | |
| } | |
| if (-not (Confirm-Step "Launch Claude Code now to verify the setup?")) { | |
| Write-Skip "Smoke test — run 'claude' manually after restarting your terminal" | |
| return | |
| } | |
| Write-Info "Running a quick test prompt..." | |
| Write-Host "" | |
| $result = claude --print "Say hello and confirm you are working. One sentence only." 2>&1 | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Host " $result" | |
| Write-Host "" | |
| Write-Ok "Claude Code is working!" | |
| } else { | |
| Write-Warn "Claude Code returned an error: $result" | |
| Write-Info "Try running 'claude' manually after restarting your terminal." | |
| } | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Main | |
| # --------------------------------------------------------------------------- | |
| Write-Header | |
| Show-Overview | |
| if (-not (Confirm-Step "Ready to begin?")) { | |
| Write-Host "" | |
| Write-Info "No problem. Run this script again when you're ready." | |
| exit 0 | |
| } | |
| Step-Preflight | |
| Step-Chocolatey | |
| Step-Git | |
| Step-Node | |
| Step-ClaudeCode | |
| Step-VSCode | |
| Step-Environment | |
| Step-ClaudeSettings | |
| Step-SmokeTest | |
| Write-Host "" | |
| Write-Host "===========================================================================" | |
| Write-Host " Setup complete." | |
| Write-Host "" | |
| Write-Host " To start Claude Code in any project, run:" | |
| Write-Host " claude" | |
| Write-Host "" | |
| Write-Host " If this is your first time, restart your terminal first so the" | |
| Write-Host " environment variables take effect." | |
| Write-Host "===========================================================================" | |
| Write-Host "" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # ============================================================================= | |
| # UConn MBA — Leading with AI: macOS Setup for Claude Code | |
| # ============================================================================= | |
| # | |
| # Automates the full Claude Code setup for students on macOS: | |
| # 1. Install Homebrew (if missing) | |
| # 2. Install Node.js via brew | |
| # 3. Install Claude Code CLI via brew | |
| # 4. Install Visual Studio Code and Claude Code extension | |
| # 5. Configure LiteLLM environment variables | |
| # 6. Run a quick smoke test | |
| # | |
| # Usage: | |
| # ./setup-claude-code.sh | |
| # | |
| # Prerequisites: | |
| # - macOS | |
| # | |
| # ============================================================================= | |
| set -euo pipefail | |
| # --------------------------------------------------------------------------- | |
| # LiteLLM constants | |
| # --------------------------------------------------------------------------- | |
| LITELLM_BASE_URL="https://litellm.sparkai.brightlysoftware.io" | |
| DEFAULT_SONNET="Claude-Sonnet-4.6-us" | |
| DEFAULT_HAIKU="Claude-Haiku-4.5-us" | |
| DEFAULT_OPUS="Claude-Sonnet-4.6-us" | |
| # --------------------------------------------------------------------------- | |
| # Helpers | |
| # --------------------------------------------------------------------------- | |
| header() { | |
| echo "" | |
| echo "===========================================================================" | |
| echo " UConn MBA — Leading with AI: Claude Code Setup (macOS)" | |
| echo "===========================================================================" | |
| echo "" | |
| } | |
| info() { echo " [INFO] $*"; } | |
| ok() { echo " [OK] $*"; } | |
| warn() { echo " [WARN] $*"; } | |
| skip() { echo " [SKIP] $*"; } | |
| fail() { echo " [ERROR] $*" >&2; exit 1; } | |
| # Prompt the user for yes/no. Default is yes. | |
| confirm() { | |
| local prompt="$1" | |
| local answer | |
| read -rp " $prompt [Y/n]: " answer | |
| answer="${answer:-Y}" | |
| [[ "${answer,,}" == "y" || "${answer,,}" == "yes" ]] | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Detect shell profile | |
| # --------------------------------------------------------------------------- | |
| detect_profile() { | |
| local shell_name | |
| shell_name="$(basename "${SHELL:-/bin/zsh}")" | |
| case "$shell_name" in | |
| zsh) echo "${HOME}/.zshrc" ;; | |
| bash) echo "${HOME}/.bashrc" ;; | |
| *) echo "${HOME}/.zshrc" ;; | |
| esac | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Idempotent export writer | |
| # --------------------------------------------------------------------------- | |
| ensure_export() { | |
| local profile="$1" var="$2" value="$3" | |
| if grep -q "^export ${var}=" "$profile" 2>/dev/null; then | |
| info "${var} already set in $(basename "$profile") — skipping" | |
| else | |
| echo "export ${var}=\"${value}\"" >> "$profile" | |
| ok "Added ${var} to $(basename "$profile")" | |
| fi | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Overview | |
| # --------------------------------------------------------------------------- | |
| show_overview() { | |
| echo " This script will walk you through installing the tools needed for" | |
| echo " Thursday's build day. Each step will ask for your permission before" | |
| echo " making changes." | |
| echo "" | |
| echo " Here's what we'll cover:" | |
| echo "" | |
| echo " ┌─────────────────────────────────────────────────────────────────────┐" | |
| echo " │ TOOL │ WHY │" | |
| echo " ├─────────────────────────────────────────────────────────────────────┤" | |
| echo " │ Homebrew │ macOS package manager — installs everything │" | |
| echo " │ │ else on this list │" | |
| echo " │ Node.js │ Required runtime for Claude Code CLI │" | |
| echo " │ Claude Code CLI │ AI coding assistant you'll use to build your │" | |
| echo " │ │ prototype on Thursday │" | |
| echo " │ Visual Studio Code│ Code editor with Claude Code integration │" | |
| echo " │ LiteLLM Config │ Connects Claude Code to the course AI gateway │" | |
| echo " │ │ using your personal API key │" | |
| echo " └─────────────────────────────────────────────────────────────────────┘" | |
| echo "" | |
| echo " Tools already installed will be detected and skipped automatically." | |
| echo "" | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 1 — Homebrew | |
| # --------------------------------------------------------------------------- | |
| install_homebrew() { | |
| echo "" | |
| echo "--- Step 1: Homebrew ---" | |
| echo " Homebrew is the standard macOS package manager. It's needed to install" | |
| echo " Node.js, Claude Code, and VS Code in the following steps." | |
| echo "" | |
| if command -v brew &>/dev/null; then | |
| ok "Homebrew already installed ($(brew --version | head -1))" | |
| return | |
| fi | |
| if ! confirm "Install Homebrew?"; then | |
| skip "Homebrew — you'll need to install Node.js and Claude Code manually" | |
| return | |
| fi | |
| info "Installing Homebrew..." | |
| /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | |
| # Ensure brew is on PATH for Apple Silicon | |
| if [[ -f /opt/homebrew/bin/brew ]]; then | |
| eval "$(/opt/homebrew/bin/brew shellenv)" | |
| fi | |
| ok "Homebrew installed" | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 2 — Node.js | |
| # --------------------------------------------------------------------------- | |
| install_node() { | |
| echo "" | |
| echo "--- Step 2: Node.js ---" | |
| echo " Node.js is the JavaScript runtime that Claude Code is built on." | |
| echo " Without it, the Claude Code CLI cannot run." | |
| echo "" | |
| if command -v node &>/dev/null; then | |
| ok "Node.js already installed ($(node --version))" | |
| info "npm version: $(npm --version)" | |
| return | |
| fi | |
| if ! confirm "Install Node.js via Homebrew?"; then | |
| skip "Node.js — Claude Code will not work without it" | |
| return | |
| fi | |
| info "Installing Node.js via brew..." | |
| brew install node | |
| ok "Node.js installed ($(node --version))" | |
| info "npm version: $(npm --version)" | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 3 — Claude Code CLI | |
| # --------------------------------------------------------------------------- | |
| install_claude_code() { | |
| echo "" | |
| echo "--- Step 3: Claude Code CLI ---" | |
| echo " Claude Code is the AI developer tool you'll use on Thursday to build" | |
| echo " your prototype. It reads files, writes code, and runs commands." | |
| echo "" | |
| if command -v claude &>/dev/null; then | |
| ok "Claude Code CLI already installed ($(claude --version 2>/dev/null || echo 'unknown version'))" | |
| return | |
| fi | |
| if ! confirm "Install Claude Code CLI via Homebrew?"; then | |
| skip "Claude Code — this is required for Thursday's build day" | |
| return | |
| fi | |
| info "Installing Claude Code CLI via brew..." | |
| brew install claude-code | |
| ok "Claude Code CLI installed" | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 4 — Visual Studio Code + Claude Code extension | |
| # --------------------------------------------------------------------------- | |
| install_vscode() { | |
| echo "" | |
| echo "--- Step 4: Visual Studio Code ---" | |
| echo " VS Code is a code editor with a Claude Code extension that gives you" | |
| echo " an integrated AI assistant inside the editor. Optional but recommended." | |
| echo "" | |
| if command -v code &>/dev/null; then | |
| ok "VS Code already installed" | |
| else | |
| if confirm "Install Visual Studio Code?"; then | |
| info "Installing Visual Studio Code via brew..." | |
| brew install --cask visual-studio-code | |
| ok "VS Code installed" | |
| else | |
| skip "VS Code — you can still use Claude Code from the terminal" | |
| return | |
| fi | |
| fi | |
| if command -v code &>/dev/null; then | |
| echo "" | |
| echo " The Claude Code extension adds AI assistance directly inside VS Code." | |
| echo "" | |
| if confirm "Install the Claude Code extension for VS Code?"; then | |
| info "Installing Claude Code extension..." | |
| code --install-extension "anthropic.claude-code" --force 2>/dev/null | |
| ok "anthropic.claude-code extension installed" | |
| else | |
| skip "Claude Code extension — you can install it later from the VS Code marketplace" | |
| fi | |
| fi | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 5 — LiteLLM environment variables | |
| # --------------------------------------------------------------------------- | |
| configure_environment() { | |
| echo "" | |
| echo "--- Step 5: LiteLLM Environment ---" | |
| echo " Claude Code needs to connect to the course AI gateway (LiteLLM proxy)" | |
| echo " instead of Anthropic directly. This step saves your API key and the" | |
| echo " gateway URL so Claude Code uses them automatically." | |
| echo "" | |
| if ! confirm "Configure LiteLLM environment variables?"; then | |
| skip "LiteLLM config — Claude Code will not connect without this" | |
| return | |
| fi | |
| echo "" | |
| echo " Enter the API key provided to you by the instructor." | |
| echo "" | |
| local api_key="" | |
| while [[ -z "$api_key" ]]; do | |
| read -rp " Your LiteLLM API key: " api_key | |
| if [[ -z "$api_key" ]]; then | |
| warn "Key cannot be empty. Please try again." | |
| fi | |
| done | |
| local profile | |
| profile="$(detect_profile)" | |
| # Create the profile if it doesn't exist | |
| if [[ ! -f "$profile" ]]; then | |
| touch "$profile" | |
| info "Created $(basename "$profile")" | |
| fi | |
| echo "" | |
| info "Writing environment variables to $(basename "$profile")..." | |
| ensure_export "$profile" "ANTHROPIC_BASE_URL" "$LITELLM_BASE_URL" | |
| ensure_export "$profile" "ANTHROPIC_API_KEY" "$api_key" | |
| ensure_export "$profile" "ANTHROPIC_DEFAULT_SONNET_MODEL" "$DEFAULT_SONNET" | |
| ensure_export "$profile" "ANTHROPIC_DEFAULT_HAIKU_MODEL" "$DEFAULT_HAIKU" | |
| ensure_export "$profile" "ANTHROPIC_DEFAULT_OPUS_MODEL" "$DEFAULT_OPUS" | |
| ensure_export "$profile" "DISABLE_COMPACT" "1" | |
| # Source the profile so the current shell picks up the new vars | |
| # shellcheck disable=SC1090 | |
| source "$profile" | |
| ok "Environment variables loaded" | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 6 — Claude Code settings.json | |
| # --------------------------------------------------------------------------- | |
| install_claude_settings() { | |
| echo "" | |
| echo "--- Step 6: Claude Code Settings ---" | |
| echo " Claude Code uses a settings.json file to configure behavior like" | |
| echo " model routing, context limits, and gateway connection. This step" | |
| echo " installs the course-recommended settings." | |
| echo "" | |
| if ! confirm "Install Claude Code settings?"; then | |
| skip "Claude Code settings — you can configure manually later" | |
| return | |
| fi | |
| local claude_dir="$HOME/.claude" | |
| local settings_path="$claude_dir/settings.json" | |
| mkdir -p "$claude_dir" | |
| local course_settings | |
| course_settings=$(cat <<'SETTINGS_EOF' | |
| { | |
| "env": { | |
| "ANTHROPIC_BASE_URL": "https://litellm.sparkai.brightlysoftware.io", | |
| "ANTHROPIC_DEFAULT_SONNET_MODEL": "sparkai-developer-claude", | |
| "ANTHROPIC_DEFAULT_HAIKU_MODEL": "sparkai-developer-claude", | |
| "ANTHROPIC_DEFAULT_OPUS_MODEL": "sparkai-developer-claude", | |
| "DISABLE_PROMPT_CACHING": "0", | |
| "CLAUDE_CODE_DISABLE_1M_CONTEXT": "1", | |
| "CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS": "1", | |
| "CLAUDE_CODE_BLOCKING_LIMIT_OVERRIDE": "200000", | |
| "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "75", | |
| "CLAUDE_CODE_EFFORT_LEVEL": "medium", | |
| "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1", | |
| "CLAUDE_CODE_FORK_SUBAGENT": "1", | |
| "CLAUDE_CODE_ENABLE_TELEMETRY": "1" | |
| }, | |
| "skipWebFetchPreflight": true | |
| } | |
| SETTINGS_EOF | |
| ) | |
| if [[ -f "$settings_path" ]]; then | |
| info "Existing settings.json found — merging..." | |
| if command -v python3 &>/dev/null; then | |
| python3 -c " | |
| import json, sys | |
| existing = json.load(open('$settings_path')) | |
| course = json.loads('''$course_settings''') | |
| existing.setdefault('env', {}).update(course['env']) | |
| existing['skipWebFetchPreflight'] = True | |
| json.dump(existing, open('$settings_path', 'w'), indent=2) | |
| " 2>/dev/null | |
| if [[ $? -ne 0 ]]; then | |
| warn "Could not merge — backing up and replacing" | |
| cp "$settings_path" "$settings_path.bak" | |
| echo "$course_settings" > "$settings_path" | |
| fi | |
| else | |
| warn "python3 not found — backing up and replacing existing settings" | |
| cp "$settings_path" "$settings_path.bak" | |
| echo "$course_settings" > "$settings_path" | |
| fi | |
| else | |
| echo "$course_settings" > "$settings_path" | |
| fi | |
| ok "Claude Code settings installed at $settings_path" | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Step 7 — Smoke test | |
| # --------------------------------------------------------------------------- | |
| smoke_test() { | |
| echo "" | |
| echo "--- Step 7: Smoke Test ---" | |
| echo " This launches Claude Code to verify everything is working." | |
| echo "" | |
| if [[ -z "${ANTHROPIC_BASE_URL:-}" ]]; then | |
| warn "ANTHROPIC_BASE_URL not set — skipping smoke test" | |
| return | |
| fi | |
| if ! command -v claude &>/dev/null; then | |
| warn "Claude CLI not found in PATH — skipping smoke test. Restart your terminal and run: claude" | |
| return | |
| fi | |
| if ! confirm "Launch Claude Code now to verify the setup?"; then | |
| skip "Smoke test — run 'claude' manually after restarting your terminal" | |
| return | |
| fi | |
| info "Launching Claude Code... (type 'exit' or press Ctrl+C to quit)" | |
| echo "" | |
| claude | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Main | |
| # --------------------------------------------------------------------------- | |
| main() { | |
| header | |
| show_overview | |
| if ! confirm "Ready to begin?"; then | |
| echo "" | |
| info "No problem. Run this script again when you're ready." | |
| exit 0 | |
| fi | |
| install_homebrew | |
| install_node | |
| install_claude_code | |
| install_vscode | |
| configure_environment | |
| install_claude_settings | |
| smoke_test | |
| echo "" | |
| echo "===========================================================================" | |
| echo " Setup complete." | |
| echo "" | |
| echo " To start Claude Code in any project, run:" | |
| echo " claude" | |
| echo "" | |
| echo " If this is your first time, restart your terminal first so the" | |
| echo " environment variables take effect." | |
| echo "===========================================================================" | |
| echo "" | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment