Add CLAUDE.md, SPEC.md and bootstrap scripts

This commit is contained in:
Filip Zubík 2026-03-13 16:35:31 +01:00
parent 8e413ab06d
commit fb74a820dc
6 changed files with 1042 additions and 0 deletions

121
CLAUDE.md Normal file
View file

@ -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 |

137
Remove-ClaudeCode.ps1 Normal file
View file

@ -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

273
SPEC.md Normal file
View file

@ -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 |

140
Setup-ClaudeCode.ps1 Normal file
View file

@ -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
}

157
setup.ps1 Normal file
View file

@ -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

214
setup.sh Executable file
View file

@ -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