Add CLAUDE.md, SPEC.md and bootstrap scripts
This commit is contained in:
parent
8e413ab06d
commit
fb74a820dc
6 changed files with 1042 additions and 0 deletions
121
CLAUDE.md
Normal file
121
CLAUDE.md
Normal 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
137
Remove-ClaudeCode.ps1
Normal 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
273
SPEC.md
Normal 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
140
Setup-ClaudeCode.ps1
Normal 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
157
setup.ps1
Normal 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
214
setup.sh
Executable 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
|
||||||
Loading…
Reference in a new issue