From fb74a820dca8d2cd47f261263fc4d277aa2a6034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Zub=C3=ADk?= Date: Fri, 13 Mar 2026 16:35:31 +0100 Subject: [PATCH] Add CLAUDE.md, SPEC.md and bootstrap scripts --- CLAUDE.md | 121 +++++++++++++++++++ Remove-ClaudeCode.ps1 | 137 +++++++++++++++++++++ SPEC.md | 273 ++++++++++++++++++++++++++++++++++++++++++ Setup-ClaudeCode.ps1 | 140 ++++++++++++++++++++++ setup.ps1 | 157 ++++++++++++++++++++++++ setup.sh | 214 +++++++++++++++++++++++++++++++++ 6 files changed, 1042 insertions(+) create mode 100644 CLAUDE.md create mode 100644 Remove-ClaudeCode.ps1 create mode 100644 SPEC.md create mode 100644 Setup-ClaudeCode.ps1 create mode 100644 setup.ps1 create mode 100755 setup.sh diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f4518a0 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,121 @@ +# CLAUDE.md - Instructions for Claude Code + +## Project context + +MSP deployment script for X9.cz - automated preparation of new Windows 10/11 computers for clients. +Replaces ~3 hours of manual setup with a single PowerShell script. + +**Key parameters:** +- Target OS: Windows 10 and Windows 11 (x64), including unsupported HW +- Execution: as Administrator on already-installed Windows (not WinPE/autounattend) +- Volume: ~20 machines per month, various clients +- Operator: MSP technician on-site at client + +--- + +## Repo structure + +``` +windows-deployment/ +├── CLAUDE.md <- this file +├── SPEC.md <- technical specification +├── Deploy-Windows.ps1 <- master script (entry point) +├── scripts/ +│ ├── 01-bloatware.ps1 <- remove AppX, Capabilities, Features +│ ├── 02-software.ps1 <- winget installs + Adobe PDF default +│ ├── 03-system-registry.ps1 <- HKLM tweaks +│ ├── 04-default-profile.ps1 <- C:\Users\Default\NTUSER.DAT changes +│ ├── 05-personalization.ps1 <- colors, wallpaper, theme +│ ├── 06-scheduled-tasks.ps1 <- register scheduled tasks +│ └── 07-desktop-info.ps1 <- custom desktop info (replaces BackInfo) +├── config/ +│ └── config.json <- per-client config (future) +├── assets/ +│ └── DesktopInfo/ <- resources for desktop info script +└── tests/ + └── Test-Deployment.ps1 <- post-deployment verification +``` + +--- + +## Conventions and rules + +### PowerShell +- Always `#Requires -RunAsAdministrator` in master script +- `$ErrorActionPreference = "Continue"` - script must survive partial failures +- Log every step to `C:\Windows\Setup\Scripts\Deploy.log` +- Logging via `Write-Log` function defined in master script +- `Invoke-Step` function wraps every step - catches errors, logs, continues +- Comments in English, code in English +- NO diacritics - no accented characters anywhere: not in comments, not in user messages, not in log output +- NO emoticons - not in comments, not in output messages +- Reason: encoding issues across systems, log readability, compatibility + +### Master script structure +```powershell +# 1. Load config.json +# 2. Run individual scripts in order +# 3. Print summary report at end (OK/ERROR counts) +``` + +### Master script switches +| Switch | Behavior | +|---|---| +| `-SkipBloatware` | Skip step 1 | +| `-SkipSoftware` | Skip step 2 | +| `-SkipDefaultProfile` | Skip step 4 | +| `-DryRun` | Run without changes, log only | + +### Testing +- Test VM: Windows 10/11 x64 on VMware ESXi (X9.cz internal infrastructure) +- Before each test: take snapshot +- After test: revert snapshot +- Dev environment: x64 VM only - NOT ARM (no Parallels/Apple Silicon for testing) + +--- + +## Important notes + +### BackInfo replacement - custom solution +BackInfo.exe is NOT used. Instead: custom scheduled task DesktopInfo: +- Triggers on every user logon +- PS script reads: hostname, IP, Windows version, username, install date +- Renders text onto desktop via WPF/System.Drawing -> saves as BMP -> sets as wallpaper +- Works on Win10 and Win11 without registry hacks + +### Adobe Reader as default PDF app +- After install: set .pdf -> AcroRd32 association +- Scheduled task PDF-DefaultApp restores association on every logon (guard against Edge overwriting it) + +### Default Profile +- Changes to C:\Users\Default\NTUSER.DAT via reg load / reg unload +- Applies to all new users - critical for MSP deployment +- Currently logged-in user gets changes via direct write to HKCU + +### Winget +- Always use --accept-package-agreements --accept-source-agreements +- Check winget availability before running installs +- Log result of every install + +--- + +## DO NOT + +- Do not use $ErrorActionPreference = "Stop" - script must survive partial failure +- Do not remove Calculator (Microsoft.WindowsCalculator) - intentionally kept +- Do not use ARM VM for testing +- Do not write scripts depending on specific username - script is universal +- Do not use hardcoded paths that do not exist on clean Windows +- NO diacritics - no accented characters in any part of any script +- NO emoticons - none in comments, log messages or output + +--- + +## Open questions + +| # | Question | Status | +|---|---|---| +| 1 | BackInfo replacement | DONE - custom PS scheduled task DesktopInfo | +| 2 | Complete SW list for winget | TODO - list incomplete | +| 3 | Per-client variability via config.json | FUTURE | +| 4 | Admin account adminx9 - script or manual? | OPEN | diff --git a/Remove-ClaudeCode.ps1 b/Remove-ClaudeCode.ps1 new file mode 100644 index 0000000..cb207c2 --- /dev/null +++ b/Remove-ClaudeCode.ps1 @@ -0,0 +1,137 @@ +#Requires -Version 5.1 +<# +.SYNOPSIS + Claude Code - odstraneni citlivych dat a volitelne cele instalace +.USAGE + # Jen citliva data (API key + repo): + .\Remove-ClaudeCode.ps1 -RepoPath "C:\Projects\windows-deployment" + + # Vse vcetne Claude Code a Node.js: + .\Remove-ClaudeCode.ps1 -RepoPath "C:\Projects\windows-deployment" -Full +#> + +param( + [Parameter(Mandatory)] + [string] $RepoPath, + + [switch] $Full +) + +$ErrorActionPreference = "Continue" + +function Write-Step { param([string]$Msg) Write-Host "`n[REMOVE] $Msg" -ForegroundColor Yellow } +function Write-OK { param([string]$Msg) Write-Host " OK: $Msg" -ForegroundColor Green } +function Write-Skip { param([string]$Msg) Write-Host " SKIP: $Msg" -ForegroundColor DarkGray } + +Write-Host "`n========================================" -ForegroundColor Red +Write-Host " Claude Code Cleanup" -ForegroundColor Red +Write-Host "========================================`n" -ForegroundColor Red + +# ------------------------------------------------------------ +# 1. API KEY +# ------------------------------------------------------------ +Write-Step "Removing ANTHROPIC_API_KEY..." + +[System.Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", $null, "User") +[System.Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", $null, "Machine") +$env:ANTHROPIC_API_KEY = $null +Write-OK "API key removed from environment variables" + +# Claude Code si uklada API key take v ~/.claude +$claudeConfig = Join-Path $HOME ".claude" +if (Test-Path $claudeConfig) { + Remove-Item $claudeConfig -Recurse -Force + Write-OK "Removed ~/.claude config directory" +} else { + Write-Skip "~/.claude not found" +} + +# ------------------------------------------------------------ +# 2. REPO +# ------------------------------------------------------------ +Write-Step "Removing repository at $RepoPath..." + +if (Test-Path $RepoPath) { + # Nejdriv over ze je to skutecne git repo - pojistka + $gitDir = Join-Path $RepoPath ".git" + if (Test-Path $gitDir) { + Remove-Item $RepoPath -Recurse -Force + Write-OK "Repository removed" + } else { + Write-Host " WARN: $RepoPath does not look like a git repo. Skipping for safety." -ForegroundColor Yellow + } +} else { + Write-Skip "Repo path not found: $RepoPath" +} + +# ------------------------------------------------------------ +# 3. GIT CREDENTIALS (pokud byly ulozeny) +# ------------------------------------------------------------ +Write-Step "Clearing git credentials for repo..." + +try { + git credential reject | Out-Null +} catch {} + +# Windows Credential Manager - GitHub tokeny +try { + $creds = cmdkey /list 2>$null | Select-String "github" + foreach ($cred in $creds) { + $target = ($cred -split '\s+') | Where-Object { $_ -like "*github*" } | Select-Object -First 1 + if ($target) { + cmdkey /delete:$target | Out-Null + Write-OK "Removed credential: $target" + } + } +} catch { + Write-Skip "No GitHub credentials found in Credential Manager" +} + +# ------------------------------------------------------------ +# 4. VOLITELNE - Claude Code + Node.js +# ------------------------------------------------------------ +if ($Full) { + Write-Step "Uninstalling Claude Code..." + try { + npm uninstall -g @anthropic-ai/claude-code + Write-OK "Claude Code uninstalled" + } catch { + Write-Skip "Claude Code not installed via npm or npm not available" + } + + Write-Step "Uninstalling Node.js..." + try { + winget uninstall OpenJS.NodeJS.LTS --silent + Write-OK "Node.js uninstalled" + } catch { + Write-Skip "Node.js not found via winget - remove manually if needed" + } +} + +# ------------------------------------------------------------ +# 5. POWERSHELL HISTORY (muze obsahovat API key z parametru) +# ------------------------------------------------------------ +Write-Step "Clearing PowerShell history..." + +$historyPath = (Get-PSReadlineOption).HistorySavePath +if ($historyPath -and (Test-Path $historyPath)) { + # Vymaz pouze radky obsahujici ApiKey / sk-ant + $lines = Get-Content $historyPath | Where-Object { $_ -notmatch 'ApiKey|sk-ant-|ANTHROPIC' } + $lines | Set-Content $historyPath + Write-OK "Sensitive lines removed from PS history" +} else { + Write-Skip "PS history file not found" +} + +# ------------------------------------------------------------ +# SUMMARY +# ------------------------------------------------------------ +Write-Host "`n========================================" -ForegroundColor Green +Write-Host " Cleanup complete!" -ForegroundColor Green +if ($Full) { + Write-Host " Removed: API key, repo, ~/.claude, Node.js, Claude Code" -ForegroundColor White +} else { + Write-Host " Removed: API key, repo, ~/.claude config" -ForegroundColor White + Write-Host " Node.js and Claude Code kept (use -Full to remove)" -ForegroundColor DarkGray +} +Write-Host "========================================`n" -ForegroundColor Green diff --git a/SPEC.md b/SPEC.md new file mode 100644 index 0000000..092a598 --- /dev/null +++ b/SPEC.md @@ -0,0 +1,273 @@ +# MSP Windows Deployment - Specification (SPEC.md) + +> Version: 0.2 (draft) +> Author: X9.cz +> Purpose: Automated preparation of new Windows 10/11 computers for clients + +--- + +## Overview + +Script replaces ~3 hours of manual computer setup. Run once as Administrator on +already-installed Windows, performs everything automatically, saves result to Default +Profile so settings apply to every subsequent user. + +--- + +## Prerequisites + +- Windows 10 or Windows 11 (x64) +- Run as Administrator +- Internet connection (for winget installs) +- Computer received either as clean OEM install or with manufacturer pre-installed Windows + +--- + +## What the script does NOT do + +- Does not install Windows (not an autounattend.xml for clean install) +- Does not create images +- Does not manage the computer ongoing (one-time deployment) + +--- + +## Script structure + +Script is divided into steps. Each step logs its result. Steps can be skipped with switches. + +--- + +## STEP 1 - Bloatware removal + +### 1a - AppX packages (UWP apps) + +Removed for all users (-AllUsers) and from provisioned packages (so they do not return for new users). + +| Package | Description | +|---|---| +| Microsoft.Microsoft3DViewer | 3D Viewer | +| Microsoft.BingSearch | Bing Search | +| Microsoft.WindowsCamera | Camera | +| Clipchamp.Clipchamp | Clipchamp video editor | +| Microsoft.WindowsAlarms | Clock / Alarm | +| Microsoft.Copilot | Copilot AI | +| Microsoft.549981C3F5F10 | Cortana | +| Microsoft.Windows.DevHome | Dev Home | +| MicrosoftCorporationII.MicrosoftFamily | Family Safety | +| Microsoft.WindowsFeedbackHub | Feedback Hub | +| Microsoft.Edge.GameAssist | Game Assist | +| Microsoft.GetHelp | Help | +| Microsoft.Getstarted | Tips / Get Started | +| microsoft.windowscommunicationsapps | Mail and Calendar | +| Microsoft.WindowsMaps | Maps | +| Microsoft.MixedReality.Portal | Mixed Reality | +| Microsoft.BingNews | News | +| Microsoft.MicrosoftOfficeHub | Office Hub | +| Microsoft.Office.OneNote | OneNote | +| Microsoft.OutlookForWindows | Outlook (new) | +| Microsoft.Paint | Paint (new UWP) | +| Microsoft.MSPaint | Paint (legacy) | +| Microsoft.People | People | +| Microsoft.Windows.Photos | Photos | +| Microsoft.PowerAutomateDesktop | Power Automate | +| MicrosoftCorporationII.QuickAssist | Quick Assist | +| Microsoft.SkypeApp | Skype | +| Microsoft.ScreenSketch | Snipping Tool | +| Microsoft.MicrosoftSolitaireCollection | Solitaire | +| Microsoft.MicrosoftStickyNotes | Sticky Notes | +| MicrosoftTeams / MSTeams | Teams (personal) | +| Microsoft.Todos | To Do | +| Microsoft.WindowsSoundRecorder | Voice Recorder | +| Microsoft.Wallet | Wallet | +| Microsoft.BingWeather | Weather | +| Microsoft.WindowsTerminal | Windows Terminal | +| Microsoft.Xbox.TCUI | Xbox UI | +| Microsoft.XboxApp | Xbox | +| Microsoft.XboxGameOverlay | Xbox Game Overlay | +| Microsoft.XboxGamingOverlay | Xbox Gaming Overlay | +| Microsoft.XboxIdentityProvider | Xbox Identity | +| Microsoft.XboxSpeechToTextOverlay | Xbox Speech | +| Microsoft.GamingApp | Gaming App | +| Microsoft.YourPhone | Phone Link | +| Microsoft.ZuneMusic | Music | +| Microsoft.ZuneVideo | Movies and TV | + +NOTE: Microsoft.WindowsCalculator is intentionally KEPT. + +### 1b - Windows Capabilities + +| Capability | Description | +|---|---| +| Print.Fax.Scan | Fax and Scan | +| Language.Handwriting | Handwriting | +| Browser.InternetExplorer | Internet Explorer | +| MathRecognizer | Math Input | +| OneCoreUAP.OneSync | OneSync | +| OpenSSH.Client | OpenSSH client | +| Microsoft.Windows.MSPaint | Paint (Win32) | +| Microsoft.Windows.PowerShell.ISE | PowerShell ISE | +| App.Support.QuickAssist | Quick Assist | +| Microsoft.Windows.SnippingTool | Snipping Tool | +| App.StepsRecorder | Steps Recorder | +| Hello.Face.* | Windows Hello face | +| Media.WindowsMediaPlayer | Windows Media Player | +| Microsoft.Windows.WordPad | WordPad | + +### 1c - Windows Optional Features + +| Feature | Description | +|---|---| +| MediaPlayback | Media playback | +| MicrosoftWindowsPowerShellV2Root | PowerShell 2.0 | +| Microsoft-RemoteDesktopConnection | RDP client | +| Recall | Windows Recall (AI) | +| Microsoft-SnippingTool | Snipping Tool (feature) | + +--- + +## STEP 2 - Software installation (winget) + +| Software | Winget ID | Notes | +|---|---|---| +| 7-Zip | `7zip.7zip` | OK | +| Adobe Acrobat Reader | `Adobe.Acrobat.Reader.64-bit` | OK, see note | +| OpenVPN Connect | `OpenVPNTechnologies.OpenVPNConnect` | OK | +| ... | ... | TODO: complete list | + +> Adobe Acrobat Reader: After install, script sets .pdf -> AcroRd32 as default. +> Scheduled task PDF-DefaultApp restores this association on every logon as a guard +> against Edge overwriting it. + +> BackInfo: NOT used. Replaced by custom PowerShell scheduled task DesktopInfo. +> See STEP 7. + +--- + +## STEP 3 - System settings (HKLM - applies to whole system) + +| Setting | Value | Notes | +|---|---|---| +| Disable NRO (bypass network check) | HKLM\...\OOBE\BypassNRO = 1 | | +| Disable auto-install of Teams | ConfigureChatAutoInstall = 0 | | +| Disable Cloud Optimized Content | DisableCloudOptimizedContent = 1 | | +| Disable Widgets (News and Interests) | HKLM\...\Dsh\AllowNewsAndInterests = 0 | | +| Edge - hide First Run Experience | HKLM\Policies\Edge\HideFirstRunExperience = 1 | | +| Passwords - no expiration | net accounts /maxpwage:UNLIMITED | | +| Time zone | Central Europe Standard Time | | +| OneDrive - remove | Delete OneDriveSetup.exe + Start Menu lnk | | +| Outlook (new) - disable auto-install | Delete UScheduler registry key | | +| Disable GameDVR | AppCaptureEnabled = 0 | | + +--- + +## STEP 4 - Default Profile (NTUSER.DAT) + +Settings applied to C:\Users\Default\NTUSER.DAT - inherited by every new user on first logon. + +Method: script loads Default hive (reg load), makes changes, unloads (reg unload). + +| Setting | Key / Value | Description | +|---|---|---| +| Taskbar - align left | TaskbarAl = 0 | Win11 default is center | +| Taskbar - hide Search box | SearchboxTaskbarMode = 0 | | +| Taskbar - hide Copilot button | ShowCopilotButton = 0 | | +| Taskbar - hide Task View button | ShowTaskViewButton = 0 | | +| Taskbar - hide Widgets | TaskbarDa = 0 | | +| Taskbar - hide Chat/Teams button | TaskbarMn = 0 | | +| Taskbar - show all tray icons | Scheduled task ShowAllTrayIcons | Runs on every logon | +| Taskbar - empty pinlist | TaskbarLayoutModification.xml | Removes default pinned apps | +| Explorer - show file extensions | HideFileExt = 0 | | +| Explorer - open to This PC | LaunchTo = 1 | Instead of Quick Access | +| Start menu - empty pins | ConfigureStartPins = {"pinnedList":[]} | Win11 | +| Start menu - disable Bing results | DisableSearchBoxSuggestions = 1 | | +| Copilot - disable | TurnOffWindowsCopilot = 1 | | +| GameDVR - disable | AppCaptureEnabled = 0 | | +| OneDrive - remove RunOnce key | Delete OneDriveSetup from Run | | +| Num Lock on startup - enable | InitialKeyboardIndicators = 2 | | +| Accent color on title bars | ColorPrevalence = 1 | | + +--- + +## STEP 5 - Personalization (colors, wallpaper) + +Applied to both Default Profile and currently logged-in user. + +| Setting | Value | +|---|---| +| System theme (taskbar, Start) | Dark | +| App theme | Light | +| Accent color | #223B47 (dark blue-gray) | +| Accent color on Start and taskbar | Yes | +| Accent color on title bars | Yes | +| Transparency | Disabled | +| Wallpaper | Solid color #223B47 (no image) | + +NOTE: DesktopInfo scheduled task (STEP 7) will overwrite the wallpaper with a system +info BMP. The solid color here is only a fallback if DesktopInfo is not running. + +--- + +## STEP 6 - Scheduled Tasks + +| Task | Trigger | Purpose | +|---|---|---| +| ShowAllTrayIcons | Every logon, every 1 min | Show all icons in system tray (Win11) | +| UnlockStartLayout | Once after layout is applied | Unlock Start menu layout | +| PDF-DefaultApp | Every logon | Restore .pdf -> Adobe Reader if Edge overwrote it | +| DesktopInfo | Every logon | Render system info onto desktop wallpaper | + +--- + +## STEP 7 - DesktopInfo (BackInfo replacement) + +Custom PowerShell scheduled task. No external dependencies. + +**What it displays:** +- Computer name (hostname) +- IP address +- Windows version and build +- Logged-in username +- Deployment date + +**How it works:** +1. PS script collects system info +2. Renders text onto bitmap via WPF / System.Drawing +3. Saves BMP to C:\Windows\Setup\Scripts\desktopinfo.bmp +4. Sets BMP as desktop wallpaper via SystemParametersInfo +5. Runs on every user logon via Scheduled Task + +**Why not BackInfo:** +- BackInfo has Win11 rendering issues requiring registry hacks +- External EXE dependency is hard to distribute +- Custom PS solution = full control, no dependencies, works on Win10 and Win11 + +--- + +## STEP 8 - Logging and output + +- Every step writes to C:\Windows\Setup\Scripts\Deploy.log +- Format: [HH:mm:ss] Step description - OK / ERROR: ... +- At end: summary report (how many steps OK, how many failed) +- Log stays on disk for diagnostics + +--- + +## Script switches + +| Switch | Behavior | +|---|---| +| `-SkipBloatware` | Skip step 1 | +| `-SkipSoftware` | Skip step 2 | +| `-SkipDefaultProfile` | Skip step 4 | +| `-DryRun` | Run through steps without changes, log only | + +--- + +## Open questions + +| # | Question | Status | +|---|---|---| +| 1 | BackInfo replacement | DONE - custom PS scheduled task DesktopInfo | +| 2 | Complete SW list for winget | TODO | +| 3 | Per-client variability via config.json | FUTURE | +| 4 | Admin account adminx9 - script or manual? | OPEN | diff --git a/Setup-ClaudeCode.ps1 b/Setup-ClaudeCode.ps1 new file mode 100644 index 0000000..8a970fa --- /dev/null +++ b/Setup-ClaudeCode.ps1 @@ -0,0 +1,140 @@ +#Requires -Version 5.1 +<# +.SYNOPSIS + Claude Code - rychla instalace a nastaveni prostredi +.USAGE + # Windows PS: + .\Setup-ClaudeCode.ps1 -ApiKey "sk-ant-..." -RepoUrl "https://github.com/org/repo" + + # S volitelnym cilove adresarem: + .\Setup-ClaudeCode.ps1 -ApiKey "sk-ant-..." -RepoUrl "https://github.com/org/repo" -WorkDir "C:\Projects" +#> + +param( + [Parameter(Mandatory)] + [string] $ApiKey, + + [Parameter(Mandatory)] + [string] $RepoUrl, + + [string] $WorkDir = "$HOME\Projects" +) + +$ErrorActionPreference = "Stop" + +function Write-Step { param([string]$Msg) Write-Host "`n[SETUP] $Msg" -ForegroundColor Cyan } +function Write-OK { param([string]$Msg) Write-Host " OK: $Msg" -ForegroundColor Green } +function Write-Fail { param([string]$Msg) Write-Host " ERR: $Msg" -ForegroundColor Red; exit 1 } + +# ------------------------------------------------------------ +# 1. NODE.JS +# ------------------------------------------------------------ +Write-Step "Checking Node.js..." + +$nodeOk = $false +try { + $nodeVer = node --version 2>$null + if ($nodeVer -match 'v(\d+)' -and [int]$Matches[1] -ge 18) { + Write-OK "Node.js $nodeVer already installed" + $nodeOk = $true + } +} catch {} + +if (-not $nodeOk) { + Write-Step "Installing Node.js via winget..." + try { + winget install OpenJS.NodeJS.LTS --accept-package-agreements --accept-source-agreements --silent + # Reload PATH + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + + [System.Environment]::GetEnvironmentVariable("Path","User") + Write-OK "Node.js installed" + } catch { + Write-Fail "Node.js install failed: $_. Install manually from https://nodejs.org" + } +} + +# ------------------------------------------------------------ +# 2. CLAUDE CODE +# ------------------------------------------------------------ +Write-Step "Checking Claude Code..." + +$ccOk = $false +try { + $ccVer = claude --version 2>$null + Write-OK "Claude Code $ccVer already installed" + $ccOk = $true +} catch {} + +if (-not $ccOk) { + Write-Step "Installing Claude Code..." + try { + npm install -g @anthropic-ai/claude-code + Write-OK "Claude Code installed" + } catch { + Write-Fail "Claude Code install failed: $_" + } +} + +# ------------------------------------------------------------ +# 3. API KEY +# ------------------------------------------------------------ +Write-Step "Setting ANTHROPIC_API_KEY..." + +[System.Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", $ApiKey, "User") +$env:ANTHROPIC_API_KEY = $ApiKey +Write-OK "API key set (User environment variable)" + +# ------------------------------------------------------------ +# 4. GIT +# ------------------------------------------------------------ +Write-Step "Checking Git..." + +try { + git --version | Out-Null + Write-OK "Git available" +} catch { + Write-Step "Installing Git via winget..." + try { + winget install Git.Git --accept-package-agreements --accept-source-agreements --silent + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + + [System.Environment]::GetEnvironmentVariable("Path","User") + Write-OK "Git installed" + } catch { + Write-Fail "Git install failed: $_. Install manually from https://git-scm.com" + } +} + +# ------------------------------------------------------------ +# 5. CLONE REPO +# ------------------------------------------------------------ +Write-Step "Cloning repository..." + +New-Item -ItemType Directory -Path $WorkDir -Force | Out-Null + +$repoName = ($RepoUrl -split '/')[-1] -replace '\.git$', '' +$targetPath = Join-Path $WorkDir $repoName + +if (Test-Path $targetPath) { + Write-OK "Repo already exists at $targetPath — pulling latest..." + Push-Location $targetPath + git pull + Pop-Location +} else { + git clone $RepoUrl $targetPath + Write-OK "Cloned to $targetPath" +} + +# ------------------------------------------------------------ +# 6. LAUNCH +# ------------------------------------------------------------ +Write-Host "`n========================================" -ForegroundColor Green +Write-Host " Setup complete!" -ForegroundColor Green +Write-Host " Repo: $targetPath" -ForegroundColor White +Write-Host " Run: cd '$targetPath' && claude" -ForegroundColor White +Write-Host "========================================`n" -ForegroundColor Green + +$launch = Read-Host "Launch Claude Code now? (Y/n)" +if ($launch -ne 'n') { + Set-Location $targetPath + claude +} diff --git a/setup.ps1 b/setup.ps1 new file mode 100644 index 0000000..8eade80 --- /dev/null +++ b/setup.ps1 @@ -0,0 +1,157 @@ +# setup.ps1 - Claude Code bootstrap for Windows +# Usage: +# irm https://gist.githubusercontent.com/YOUR_GIST_URL/raw/setup.ps1 | iex +# +# Or with parameters (paste as one line): +# $env:CC_API_KEY="sk-ant-..."; $env:CC_REPO="https://github.com/org/repo"; irm https://gist.../raw/setup.ps1 | iex + +$ErrorActionPreference = "Stop" + +function Write-Step { param([string]$Msg) Write-Host "[SETUP] $Msg" -ForegroundColor Cyan } +function Write-OK { param([string]$Msg) Write-Host " OK: $Msg" -ForegroundColor Green } +function Write-Fail { param([string]$Msg) Write-Host " ERR: $Msg" -ForegroundColor Red; exit 1 } + +Write-Host "" +Write-Host " Claude Code Bootstrap - X9.cz" -ForegroundColor Cyan +Write-Host " ==============================" -ForegroundColor Cyan +Write-Host "" + +# ------------------------------------------------------------ +# API KEY +# ------------------------------------------------------------ +$apiKey = $env:CC_API_KEY +if (-not $apiKey) { + $apiKey = Read-Host "Enter Anthropic API key (sk-ant-...)" +} +if (-not $apiKey -or -not $apiKey.StartsWith("sk-")) { + Write-Fail "Invalid API key" +} + +# ------------------------------------------------------------ +# REPO URL +# ------------------------------------------------------------ +$repoUrl = $env:CC_REPO +if (-not $repoUrl) { + $repoUrl = Read-Host "Enter repo URL (https://github.com/org/repo)" +} +if (-not $repoUrl) { + Write-Fail "No repo URL provided" +} + +$workDir = if ($env:CC_WORKDIR) { $env:CC_WORKDIR } else { "$HOME\Projects" } + +# ------------------------------------------------------------ +# NODE.JS +# ------------------------------------------------------------ +Write-Step "Checking Node.js..." + +$nodeOk = $false +try { + $nodeVer = & node --version 2>$null + if ($nodeVer -match 'v(\d+)' -and [int]$Matches[1] -ge 18) { + Write-OK "Node.js $nodeVer" + $nodeOk = $true + } +} catch {} + +if (-not $nodeOk) { + Write-Step "Installing Node.js via winget..." + try { + winget install OpenJS.NodeJS.LTS --accept-package-agreements --accept-source-agreements --silent + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + + [System.Environment]::GetEnvironmentVariable("Path","User") + Write-OK "Node.js installed" + } catch { + Write-Fail "Node.js install failed. Install manually: https://nodejs.org" + } +} + +# ------------------------------------------------------------ +# GIT +# ------------------------------------------------------------ +Write-Step "Checking Git..." + +$gitOk = $false +try { git --version | Out-Null; $gitOk = $true; Write-OK "Git available" } catch {} + +if (-not $gitOk) { + Write-Step "Installing Git via winget..." + try { + winget install Git.Git --accept-package-agreements --accept-source-agreements --silent + $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + + [System.Environment]::GetEnvironmentVariable("Path","User") + Write-OK "Git installed" + } catch { + Write-Fail "Git install failed. Install manually: https://git-scm.com" + } +} + +# ------------------------------------------------------------ +# CLAUDE CODE +# ------------------------------------------------------------ +Write-Step "Checking Claude Code..." + +$ccOk = $false +try { $ccVer = claude --version 2>$null; Write-OK "Claude Code $ccVer"; $ccOk = $true } catch {} + +if (-not $ccOk) { + Write-Step "Installing Claude Code..." + try { + npm install -g @anthropic-ai/claude-code + Write-OK "Claude Code installed" + } catch { + Write-Fail "Claude Code install failed" + } +} + +# ------------------------------------------------------------ +# API KEY - ulozit +# ------------------------------------------------------------ +Write-Step "Saving API key..." +[System.Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", $apiKey, "User") +$env:ANTHROPIC_API_KEY = $apiKey +# Vymazat z env aby nezustal v historii procesu +Remove-Item Env:\CC_API_KEY -ErrorAction SilentlyContinue +Write-OK "API key saved" + +# ------------------------------------------------------------ +# CLONE / PULL REPO +# ------------------------------------------------------------ +Write-Step "Setting up repository..." +New-Item -ItemType Directory -Path $workDir -Force | Out-Null + +$repoName = ($repoUrl -split '/')[-1] -replace '\.git$', '' +$targetPath = Join-Path $workDir $repoName + +if (Test-Path (Join-Path $targetPath ".git")) { + Write-Step "Repo exists, pulling latest..." + Push-Location $targetPath + git pull + Pop-Location +} else { + git clone $repoUrl $targetPath + Write-OK "Cloned to $targetPath" +} + +# ------------------------------------------------------------ +# CLEAN PS HISTORY - odstranit radky s API key +# ------------------------------------------------------------ +try { + $histPath = (Get-PSReadlineOption).HistorySavePath + if ($histPath -and (Test-Path $histPath)) { + $clean = Get-Content $histPath | Where-Object { $_ -notmatch 'sk-ant-|CC_API_KEY|ANTHROPIC' } + $clean | Set-Content $histPath + } +} catch {} + +# ------------------------------------------------------------ +# LAUNCH +# ------------------------------------------------------------ +Write-Host "" +Write-Host " ==============================" -ForegroundColor Green +Write-Host " Ready! Repo: $targetPath" -ForegroundColor Green +Write-Host " ==============================" -ForegroundColor Green +Write-Host "" + +Set-Location $targetPath +claude diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..82beb37 --- /dev/null +++ b/setup.sh @@ -0,0 +1,214 @@ +#!/usr/bin/env bash +# setup.sh - Claude Code bootstrap for macOS / Linux +# Usage: +# curl -fsSL https://gist.githubusercontent.com/YOUR_GIST_URL/raw/setup.sh | bash +# +# Or with parameters: +# CC_API_KEY="sk-ant-..." CC_REPO="https://github.com/org/repo" bash <(curl -fsSL https://gist.../raw/setup.sh) + +set -e + +CYAN='\033[0;36m' +GREEN='\033[0;32m' +RED='\033[0;31m' +GRAY='\033[0;90m' +NC='\033[0m' + +step() { echo -e "\n${CYAN}[SETUP] $1${NC}"; } +ok() { echo -e " ${GREEN}OK: $1${NC}"; } +fail() { echo -e " ${RED}ERR: $1${NC}"; exit 1; } +skip() { echo -e " ${GRAY}SKIP: $1${NC}"; } + +echo "" +echo -e "${CYAN} Claude Code Bootstrap - X9.cz" +echo -e " ==============================${NC}" +echo "" + +# ------------------------------------------------------------ +# API KEY +# ------------------------------------------------------------ +API_KEY="${CC_API_KEY:-}" +if [ -z "$API_KEY" ]; then + read -rsp "Enter Anthropic API key (sk-ant-...): " API_KEY + echo "" +fi +if [[ ! "$API_KEY" == sk-* ]]; then + fail "Invalid API key" +fi + +# ------------------------------------------------------------ +# REPO URL +# ------------------------------------------------------------ +REPO_URL="${CC_REPO:-}" +if [ -z "$REPO_URL" ]; then + read -rp "Enter repo URL (https://github.com/org/repo): " REPO_URL +fi +if [ -z "$REPO_URL" ]; then + fail "No repo URL provided" +fi + +WORK_DIR="${CC_WORKDIR:-$HOME/Projects}" + +# ------------------------------------------------------------ +# DETECT OS +# ------------------------------------------------------------ +OS="$(uname -s)" +step "Detected OS: $OS" + +# ------------------------------------------------------------ +# NODE.JS +# ------------------------------------------------------------ +step "Checking Node.js..." + +node_ok=false +if command -v node &>/dev/null; then + NODE_VER=$(node --version | sed 's/v//' | cut -d. -f1) + if [ "$NODE_VER" -ge 18 ]; then + ok "Node.js $(node --version)" + node_ok=true + fi +fi + +if [ "$node_ok" = false ]; then + step "Installing Node.js..." + case "$OS" in + Darwin) + if command -v brew &>/dev/null; then + brew install node + else + step "Installing Homebrew first..." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + brew install node + fi + ;; + Linux) + # Node via NodeSource + curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - + if command -v apt-get &>/dev/null; then + sudo apt-get install -y nodejs + elif command -v dnf &>/dev/null; then + sudo dnf install -y nodejs + elif command -v yum &>/dev/null; then + sudo yum install -y nodejs + else + fail "Cannot detect package manager. Install Node.js manually: https://nodejs.org" + fi + ;; + *) + fail "Unsupported OS: $OS. Install Node.js manually: https://nodejs.org" + ;; + esac + ok "Node.js installed" +fi + +# ------------------------------------------------------------ +# GIT +# ------------------------------------------------------------ +step "Checking Git..." + +if command -v git &>/dev/null; then + ok "Git available" +else + step "Installing Git..." + case "$OS" in + Darwin) brew install git ;; + Linux) + if command -v apt-get &>/dev/null; then sudo apt-get install -y git + elif command -v dnf &>/dev/null; then sudo dnf install -y git + elif command -v yum &>/dev/null; then sudo yum install -y git + else fail "Cannot install Git automatically" + fi + ;; + esac + ok "Git installed" +fi + +# ------------------------------------------------------------ +# CLAUDE CODE +# ------------------------------------------------------------ +step "Checking Claude Code..." + +if command -v claude &>/dev/null; then + ok "Claude Code $(claude --version)" +else + step "Installing Claude Code..." + npm install -g @anthropic-ai/claude-code + ok "Claude Code installed" +fi + +# ------------------------------------------------------------ +# API KEY - ulozit +# ------------------------------------------------------------ +step "Saving API key..." + +SHELL_RC="" +case "$SHELL" in + */zsh) SHELL_RC="$HOME/.zshrc" ;; + */bash) + if [ "$OS" = "Darwin" ]; then + SHELL_RC="$HOME/.bash_profile" + else + SHELL_RC="$HOME/.bashrc" + fi + ;; + *) SHELL_RC="$HOME/.profile" ;; +esac + +# Odstrante stary zaznam pokud existuje +if [ -f "$SHELL_RC" ]; then + grep -v 'ANTHROPIC_API_KEY' "$SHELL_RC" > "${SHELL_RC}.tmp" && mv "${SHELL_RC}.tmp" "$SHELL_RC" +fi + +echo "export ANTHROPIC_API_KEY=\"$API_KEY\"" >> "$SHELL_RC" +export ANTHROPIC_API_KEY="$API_KEY" +unset CC_API_KEY +ok "API key saved to $SHELL_RC" + +# ------------------------------------------------------------ +# CLONE / PULL REPO +# ------------------------------------------------------------ +step "Setting up repository..." +mkdir -p "$WORK_DIR" + +REPO_NAME=$(basename "$REPO_URL" .git) +TARGET_PATH="$WORK_DIR/$REPO_NAME" + +if [ -d "$TARGET_PATH/.git" ]; then + step "Repo exists, pulling latest..." + git -C "$TARGET_PATH" pull +else + git clone "$REPO_URL" "$TARGET_PATH" + ok "Cloned to $TARGET_PATH" +fi + +# ------------------------------------------------------------ +# CLEAN SHELL HISTORY - odstranit radky s API key +# ------------------------------------------------------------ +HIST_FILE="${HISTFILE:-$HOME/.bash_history}" +if [ -f "$HIST_FILE" ]; then + grep -v 'sk-ant-\|CC_API_KEY\|ANTHROPIC' "$HIST_FILE" > "${HIST_FILE}.tmp" && mv "${HIST_FILE}.tmp" "$HIST_FILE" +fi +# zsh history +ZSH_HIST="$HOME/.zsh_history" +if [ -f "$ZSH_HIST" ]; then + grep -v 'sk-ant-\|CC_API_KEY\|ANTHROPIC' "$ZSH_HIST" > "${ZSH_HIST}.tmp" && mv "${ZSH_HIST}.tmp" "$ZSH_HIST" +fi + +# ------------------------------------------------------------ +# LAUNCH +# ------------------------------------------------------------ +echo "" +echo -e "${GREEN} ==============================" +echo -e " Ready! Repo: $TARGET_PATH" +echo -e " ==============================${NC}" +echo "" +echo -e " Run: ${CYAN}source $SHELL_RC && cd $TARGET_PATH && claude${NC}" +echo "" + +# Pokud je skript spusten primo (ne pres pipe), rovnou spustit +if [ -t 0 ]; then + cd "$TARGET_PATH" + # shellcheck disable=SC1090 + source "$SHELL_RC" + claude +fi