1 line
18 KiB
JSON
1 line
18 KiB
JSON
{"repo": "blackhatdevx/claudefree-installer", "files": {"setup.ps1": {"8b63f8f33ff311e7252cbd43a41c4457392006ed": {"t": 1785846936.2347102, "n": 17205, "h": "a15fa65413c93428", "c": "# ============================================================\n# ClaudeFree v1.4.0 (Final)\n# Claude Code + OpenCode AI Auto Setup – Windows\n# ============================================================\n\n$ErrorActionPreference = \"Stop\"\n$ProgressPreference = \"SilentlyContinue\"\n\n# ----------------------------- Colors -----------------------------\n$ESC = [char]27\n$RED = \"${ESC}[31m\"\n$GREEN = \"${ESC}[32m\"\n$YELLOW = \"${ESC}[33m\"\n$BLUE = \"${ESC}[34m\"\n$NC = \"${ESC}[0m\"\n\nfunction log { Write-Host \"${BLUE}[*]${NC} $args\" }\nfunction success { Write-Host \"${GREEN}[OK]${NC} $args\" }\nfunction warn { Write-Host \"${YELLOW}[!]${NC} $args\" }\nfunction error { Write-Host \"${RED}[X]${NC} $args\" }\n\nfunction pause-exit {\n Write-Host \"\"\n if ($Host.Name -eq \"ConsoleHost\") { Read-Host \"Press Enter to exit...\" }\n exit 1\n}\n\nfunction ensure-admin {\n if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {\n error \"This script must be run as Administrator.\"\n Read-Host \"Press Enter to exit...\"\n exit 1\n }\n}\n\nfunction check-network {\n log \"Checking internet connection...\"\n try { $null = Invoke-WebRequest -Uri \"https://opencode.ai\" -TimeoutSec 20 -UseBasicParsing -ErrorAction Stop; success \"Internet connection OK\" }\n catch { error \"No internet connection or opencode.ai unreachable.\"; pause-exit }\n}\n\nfunction check-storage {\n log \"Checking available storage...\"\n try {\n $drive = Get-PSDrive -Name $PWD.Root.Name | Select-Object -First 1\n $freeGB = [math]::Round($drive.Free / 1GB, 2)\n if ($drive.Free / 1MB -lt 500) { error \"At least 500MB free space required. Currently: ${freeGB}GB free\"; pause-exit }\n success \"Sufficient storage available (${freeGB}GB free)\"\n } catch { warn \"Could not determine free space, continuing...\" }\n}\n\nfunction detect-windows {\n log \"Detecting Windows version...\"\n try {\n $os = Get-CimInstance -ClassName Win32_OperatingSystem\n $major = $os.Version.Split('.')[0]\n $build = $os.BuildNumber\n $product = $os.Caption\n } catch {\n $osVersion = [System.Environment]::OSVersion.Version\n $major = $osVersion.Major; $build = $osVersion.Build; $product = \"Windows\"\n }\n if ($major -ge 10) { success \"Detected $product (Version $major.$build)\" }\n else { error \"Windows 10 or later is required. Detected: $product (Version $major.$build)\"; pause-exit }\n}\n\nfunction refresh-path { $env:Path = [Environment]::GetEnvironmentVariable(\"Path\",\"Machine\") + \";\" + [Environment]::GetEnvironmentVariable(\"Path\",\"User\") }\n\n# ----------------------------- Installers -----------------------------\nfunction install-chocolatey {\n log \"Installing Chocolatey...\"\n if (Get-Command choco -ErrorAction SilentlyContinue) { success \"Chocolatey already installed\"; return }\n Set-ExecutionPolicy Bypass -Scope Process -Force\n [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072\n try { Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) }\n catch { error \"Chocolatey installation failed: $_\"; pause-exit }\n refresh-path\n if (Get-Command choco -ErrorAction SilentlyContinue) { success \"Chocolatey installed\" }\n else { error \"Chocolatey not found after installation\"; pause-exit }\n}\n\nfunction install-vscode {\n log \"Installing VS Code...\"\n if (Get-Command code -ErrorAction SilentlyContinue) { success \"VS Code already installed\"; return }\n choco install vscode -y --no-progress --limit-output\n refresh-path; Start-Sleep -Seconds 5\n foreach ($dir in @(\"${env:ProgramFiles}\\Microsoft VS Code\\bin\", \"${env:ProgramFiles(x86)}\\Microsoft VS Code\\bin\", \"C:\\ProgramData\\chocolatey\\bin\")) {\n if ((Test-Path \"$dir\\code.exe\") -and ($env:Path -notlike \"*$dir*\")) { $env:Path = \"$dir;$env:Path\" }\n }\n refresh-path\n if (Get-Command code -ErrorAction SilentlyContinue) { success \"VS Code installed\" }\n else { warn \"VS Code installed but 'code' command not in PATH.\" }\n}\n\nfunction install-nodejs {\n log \"Installing Node.js v24.15.0...\"\n try { $null = Get-Command node -ErrorAction Stop; $nodeVersion = (node --version 2>$null); if ($nodeVersion) { success \"Node.js already installed ($nodeVersion)\"; return } } catch {}\n choco install nodejs --version=24.15.0 -y --no-progress --limit-output\n refresh-path; Start-Sleep -Seconds 5\n foreach ($dir in @(\"${env:ProgramFiles}\\nodejs\", \"${env:ProgramFiles(x86)}\\nodejs\", \"C:\\ProgramData\\chocolatey\\bin\")) {\n if ((Test-Path \"$dir\\node.exe\") -and ($env:Path -notlike \"*$dir*\")) { $env:Path = \"$dir;$env:Path\" }\n }\n refresh-path\n try { $nodeVersion = (node --version 2>$null); if ($nodeVersion) { success \"Node.js installed ($nodeVersion)\"; return } } catch {}\n error \"Node.js installation failed - node command not found\"; pause-exit\n}\n\nfunction install-opencode {\n log \"Installing OpenCode AI...\"\n if (Get-Command opencode -ErrorAction SilentlyContinue) { success \"OpenCode already installed\"; return }\n try {\n npm install -g opencode-ai\n refresh-path; Start-Sleep -Seconds 3\n if (Get-Command opencode -ErrorAction SilentlyContinue) { success \"OpenCode AI installed\" }\n else { error \"OpenCode installation failed\"; pause-exit }\n } catch { error \"Failed to install OpenCode: $_\"; pause-exit }\n}\n\nfunction install-claude-code {\n log \"Installing Claude Code CLI...\"\n if (Get-Command claude -ErrorAction SilentlyContinue) { success \"Claude Code already installed\"; return }\n try {\n Invoke-WebRequest -Uri \"https://claude.ai/install.ps1\" -OutFile \"$env:TEMP\\claude_install.ps1\" -UseBasicParsing\n powershell -ExecutionPolicy Bypass -File \"$env:TEMP\\claude_install.ps1\"\n Remove-Item \"$env:TEMP\\claude_install.ps1\" -Force -ErrorAction SilentlyContinue\n Start-Sleep -Seconds 3\n $localBin = \"$env:USERPROFILE\\.local\\bin\"\n if (Test-Path \"$localBin\\claude.exe\") {\n if ($env:Path -notlike \"*$localBin*\") { $env:Path = \"$localBin;$env:Path\" }\n $userPath = [Environment]::GetEnvironmentVariable(\"Path\", \"User\")\n if ($userPath -notlike \"*$localBin*\") {\n $newUserPath = if ($userPath) { \"$userPath;$localBin\" } else { $localBin }\n [Environment]::SetEnvironmentVariable(\"Path\", $newUserPath, \"User\")\n success \"Added $localBin to user PATH (permanent)\"\n }\n if (Get-Command claude -ErrorAction SilentlyContinue) { success \"Claude Code CLI installed\" }\n else { & \"$localBin\\claude.exe\" --version | Out-Null; if ($LASTEXITCODE -eq 0) { success \"Claude Code CLI installed (available at $localBin\\claude.exe)\" } else { error \"Claude Code installation failed\"; pause-exit } }\n } else { error \"Claude Code binary not found at expected location: $localBin\"; pause-exit }\n } catch { error \"Failed to install Claude Code: $_\"; pause-exit }\n}\n\nfunction validate-api-key {\n param([string]$key)\n log \"Validating API key...\"\n try { $response = Invoke-WebRequest -Uri \"https://opencode.ai/zen/go/v1/models\" -Headers @{ \"Authorization\" = \"Bearer $key\" } -TimeoutSec 20 -UseBasicParsing -ErrorAction Stop; $httpCode = $response.StatusCode }\n catch { $httpCode = $_.Exception.Response.StatusCode.value__ }\n if ($httpCode -eq 200) { success \"API key validated\"; return $true }\n elseif ($httpCode -eq 401) { error \"Invalid API key\"; return $false }\n else { warn \"Validation returned HTTP $httpCode - proceeding anyway\"; return $true }\n}\n\nfunction install-claude-extension {\n log \"Installing Claude Code extension...\"\n if (-not (Get-Command code -ErrorAction SilentlyContinue)) { error \"VS Code 'code' command not found. Install it via VS Code.\"; pause-exit }\n $extensions = code --list-extensions 2>$null\n if ($extensions -match \"anthropic.claude-code\") { success \"Claude Code extension already installed\"; return }\n try { code --install-extension anthropic.claude-code --force; success \"Claude Code extension installed\" }\n catch { error \"Failed to install Claude extension.\"; pause-exit }\n}\n\nfunction setup-claude-config {\n param([string]$apiKey)\n log \"Configuring Claude settings...\"\n\n # Remove any line breaks (CR, LF) and trim surrounding whitespace\n $cleanKey = $apiKey -replace \"`r`n\", \"\" -replace \"`n\", \"\" -replace \"`r\", \"\"\n $cleanKey = $cleanKey.Trim()\n\n $configDir = \"$HOME\\.claude\"\n if (-not (Test-Path $configDir)) {\n New-Item -ItemType Directory -Path $configDir -Force | Out-Null\n }\n\n $configFile = \"$configDir\\settings.json\"\n \n # Escape double quotes (just in case)\n $escapedKey = $cleanKey -replace '\"', '\\\"'\n \n $configJson = @\"\n{\n \"env\": {\n \"ANTHROPIC_BASE_URL\": \"https://opencode.ai/zen/\",\n \"ANTHROPIC_API_KEY\": \"$escapedKey\",\n \"ANTHROPIC_MODEL\": \"minimax-m2.5-free\",\n \"ENABLE_TOOL_SEARCH\": \"true\"\n }\n}\n\"@\n\n try {\n $utf8NoBom = New-Object System.Text.UTF8Encoding $false\n [System.IO.File]::WriteAllText($configFile, $configJson, $utf8NoBom)\n success \"Claude configuration saved to $configFile\"\n } catch {\n error \"Failed to write config file: $_\"\n pause-exit\n }\n}\n\nfunction append-shell-env {\n param([string]$apiKey)\n $profilePath = $PROFILE\n if ([string]::IsNullOrEmpty($profilePath)) { warn \"PowerShell profile path not found. Skipping environment variable setup.\"; return }\n $profileDir = Split-Path $profilePath\n if (-not (Test-Path $profileDir)) { try { New-Item -ItemType Directory -Path $profileDir -Force | Out-Null } catch { warn \"Could not create profile directory: $profileDir\"; return } }\n $envContent = @\"\n\n# OpenCode Claude Setup\n`$env:ANTHROPIC_BASE_URL = `\"https://opencode.ai/zen/`\"\n`$env:ANTHROPIC_API_KEY = `\"$apiKey`\"\n`$env:ANTHROPIC_MODEL = `\"minimax-m2.5-free`\"\n`$env:ENABLE_TOOL_SEARCH = `\"true`\"\n\"@\n if (Test-Path $profilePath) {\n $existing = Get-Content $profilePath -Raw -ErrorAction SilentlyContinue\n if ($existing -notmatch \"opencode.ai/zen/\") { Add-Content -Path $profilePath -Value $envContent -Encoding UTF8; success \"Shell environment configured in profile\" }\n else { success \"Shell environment already configured\" }\n } else { Set-Content -Path $profilePath -Value $envContent -Encoding UTF8; success \"Shell environment configured in new profile\" }\n}\n\n# ----------------------------- Claude Interactive (new window) -----------------------------\nfunction run-claude-setup {\n log \"Launching Claude Code CLI for initial configuration...\"\n Write-Host \"\"\n Write-Host \"${YELLOW}A new terminal window will open with Claude CLI.${NC}\"\n Write-Host \"${YELLOW}Please complete any setup steps (Enter > Pointer UP > Enter x 4 > type /exit).${NC}\"\n Write-Host \"${YELLOW}When you are done, type ${GREEN}/exit${YELLOW} inside Claude, then close the terminal window.${NC}\"\n Write-Host \"\"\n Read-Host \"Press Enter to open Claude in a new window...\"\n\n if (Get-Command claude -ErrorAction SilentlyContinue) {\n Write-Host \"${GREEN}Opening Claude in a new terminal window...${NC}\"\n Start-Process cmd -ArgumentList \"/k claude\"\n Write-Host \"\"\n Write-Host \"${YELLOW}Claude is running in another window.${NC}\"\n Write-Host \"${YELLOW}After you type ${GREEN}/exit${YELLOW} (and see the prompt return), please close that terminal window.${NC}\"\n Write-Host \"\"\n Read-Host \"Press Enter after you have closed the Claude terminal window...\"\n success \"Claude CLI session ended. Returning to setup script.\"\n } else {\n warn \"Claude command not found. Skipping interactive setup.\"\n warn \"You can launch Claude manually by typing 'claude' in a new terminal.\"\n }\n}\n\nfunction open-ide {\n if (Get-Command code -ErrorAction SilentlyContinue) { Write-Host \"${GREEN}Opening VS Code...${NC}\"; code . }\n else { warn \"Cannot open VS Code - 'code' command not found\" }\n}\n\n# ----------------------------- Main -----------------------------\nClear-Host\nWrite-Host \"====================================================\"\nWrite-Host \" ClaudeFree v1.4.0 (Final)\"\nWrite-Host \" Claude Code + OpenCode AI Auto Setup\"\nWrite-Host \"====================================================\"\nWrite-Host \"\"\n\n# --- Load module for secure strings (if available)\ntry {\n Import-Module Microsoft.PowerShell.SecretManagement -Force -ErrorAction Stop\n $secureModuleAvailable = $true\n} catch {\n $secureModuleAvailable = $false\n warn \"Secure credential module not available. API key will be stored in plain text (less secure).\"\n}\n\n$secureSecretPath = \"$env:USERPROFILE\\.claude_free\\secret.claude\"\n$secretKey = $null\n\n# --- Check for saved key\nif (Test-Path $secureSecretPath) {\n Write-Host \"${YELLOW}A saved API key was found.${NC}\"\n $useSavedKey = Read-Host \"Use it? (Y/N)\"\n if ($useSavedKey -eq 'Y') {\n if ($secureModuleAvailable) {\n try {\n $secureKey = Get-Content $secureSecretPath | ConvertTo-SecureString\n $secretKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureKey))\n $secretKey = $secretKey.Trim() -replace \"`r`n\", \"\" -replace \"`n\", \"\" -replace \"`r\", \"\"\n success \"Using saved API key.\"\n } catch {\n warn \"Could not read saved key. You will be prompted for a new one.\"\n $secretKey = $null\n }\n } else {\n # Fallback: read plain text (not recommended but works)\n $secretKey = Get-Content $secureSecretPath -Raw\n success \"Using saved API key (plain text).\"\n }\n }\n}\n\n# --- If no saved key or user declined, prompt for new key\nif (-not $secretKey) {\n Write-Host \"${YELLOW}Opening OpenCode website to get your API key...${NC}\"\n Start-Process \"https://opencode.ai/auth\"\n Write-Host \"\"\n if ($secureModuleAvailable) {\n $secureKey = Read-Host \"Enter your OpenCode Secret Key\" -AsSecureString\n $secretKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureKey))\n # Save encrypted\n $secureDir = Split-Path $secureSecretPath\n if (-not (Test-Path $secureDir)) { New-Item -ItemType Directory -Path $secureDir -Force | Out-Null }\n $secureKey | ConvertFrom-SecureString | Out-File $secureSecretPath\n success \"API key saved securely for future use.\"\n } else {\n $secretKey = Read-Host \"Enter your OpenCode Secret Key\"\n # Save plain text (fallback)\n $secureDir = Split-Path $secureSecretPath\n if (-not (Test-Path $secureDir)) { New-Item -ItemType Directory -Path $secureDir -Force | Out-Null }\n $secretKey | Out-File $secureSecretPath\n success \"API key saved (plain text) for future use.\"\n }\n}\n\nif ([string]::IsNullOrWhiteSpace($secretKey)) {\n error \"Secret key cannot be empty.\"\n pause-exit\n}\n\n# --- Validate key\nif (-not (validate-api-key $secretKey)) { pause-exit }\n\n# --- Pre-flight checks\ncheck-network\ncheck-storage\ndetect-windows\n\n# --- Installation\nWrite-Host \"\"\nlog \"Starting installation...\"\nWrite-Host \"\"\n\nensure-admin\nrefresh-path\ninstall-chocolatey\nWrite-Host \"\"\ninstall-vscode\nWrite-Host \"\"\ninstall-nodejs\nWrite-Host \"\"\ninstall-opencode\nWrite-Host \"\"\ninstall-claude-code\nWrite-Host \"\"\ninstall-claude-extension\nWrite-Host \"\"\n\ntry { setup-claude-config $secretKey } catch { error \"Claude configuration failed: $_\"; pause-exit }\nWrite-Host \"\"\ntry { append-shell-env $secretKey } catch { warn \"Could not update PowerShell profile: $_\" }\n\n# --- Interactive Claude session (new window)\nrun-claude-setup\n\n# --- Final message\nWrite-Host \"\"\nWrite-Host \"====================================================\"\nWrite-Host \"${GREEN}Setup complete!${NC}\"\nWrite-Host \"====================================================\"\nWrite-Host \"\"\n$nodeVer = & cmd /c \"node --version 2>nul\"\n$npmVer = & cmd /c \"npm --version 2>nul\"\nWrite-Host \"Node.js version: $nodeVer\"\nWrite-Host \"npm version: $npmVer\"\nWrite-Host \"VS Code: $(if (Get-Command code -ErrorAction SilentlyContinue) { 'Available' } else { 'Not in PATH' })\"\nWrite-Host \"Claude Code: $(if (Get-Command claude -ErrorAction SilentlyContinue) { 'Available' } else { 'Not in PATH' })\"\nWrite-Host \"OpenCode: $(if (Get-Command opencode -ErrorAction SilentlyContinue) { 'Available' } else { 'Not in PATH' })\"\nWrite-Host \"\"\nWrite-Host \"${GREEN}Claude is FREE and ready to be used in VS Code${NC}\"\nWrite-Host \"\"\nWrite-Host \"${BLUE}GitHub Repository:${NC} https://github.com/BlackHatDevX/claudefree-installer\"\nWrite-Host \"\"\nWrite-Host \"${YELLOW}Star us on GitHub to support this project!${NC}\"\nWrite-Host \"\"\nWrite-Host \"${BLUE}Found an issue?${NC} https://github.com/BlackHatDevX/claudefree-installer/issues\"\nWrite-Host \"\"\n\n$openVscode = Read-Host \"Press Enter to open VS Code, or type 'no' to skip\"\nif ($openVscode -ne \"no\") { open-ide }\n\nWrite-Host \"\"\nRead-Host \"Press Enter to exit...\""}}}} |