Private
Public Access
1
0
Files
xcodecli-shells/setup.ps1

377 lines
11 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# XCodeCLI Setup Launcher (Windows)
# 一站式安装和配置 Claude Code, Gemini CLI, Codex
param(
[string]$ApiKey,
[switch]$Help
)
# 支持一行命令传入 API Key: $key='xxx'; iwr ... | iex
if (-not $ApiKey -and (Test-Path Variable:key)) { $ApiKey = $key }
# ========== 颜色输出函数 ==========
function Write-Info { param([string]$Message); Write-Host "[INFO]" -ForegroundColor Blue -NoNewline; Write-Host " $Message" }
function Write-Success { param([string]$Message); Write-Host "[SUCCESS]" -ForegroundColor Green -NoNewline; Write-Host " $Message" }
function Write-Warning { param([string]$Message); Write-Host "[WARNING]" -ForegroundColor Yellow -NoNewline; Write-Host " $Message" }
function Write-Error { param([string]$Message); Write-Host "[ERROR]" -ForegroundColor Red -NoNewline; Write-Host " $Message" }
# ========== 工具配置表 ==========
$ToolsConfig = @{
1 = @{
Name = "Claude Code"
Command = "claude"
Package = "@anthropic-ai/claude-code"
SetupUrl = "https://gitea.sususu.cf/sususu/xcodecli-shells/raw/branch/main/ClaudeCode/setup-claude-code.ps1"
}
2 = @{
Name = "Gemini CLI"
Command = "gemini"
Package = "@google/gemini-cli@latest"
SetupUrl = "https://gitea.sususu.cf/sususu/xcodecli-shells/raw/branch/main/GeminiCLI/setup-gemini.ps1"
}
3 = @{
Name = "Codex"
Command = "codex"
Package = "@openai/codex"
SetupUrl = "https://gitea.sususu.cf/sususu/xcodecli-shells/raw/branch/main/codex/setup-codex.ps1"
}
}
# ========== 帮助信息 ==========
function Show-Help {
Write-Host @"
XCodeCLI Setup Launcher (Windows)
Claude Code, Gemini CLI, Codex
Usage: powershell -ExecutionPolicy Bypass -File setup.ps1 [OPTIONS]
Options:
-ApiKey <KEY> API
-Help
:
- Node.js >= 20.x
- Node.js fnm Node.js 24.x
使:
`$key='YOUR_API_KEY'; iwr -useb https://gitea.sususu.cf/sususu/xcodecli-shells/raw/branch/main/setup.ps1 | iex
"@
exit 0
}
# ========== 工具函数 ==========
function Test-Command {
param([string]$Name)
return [bool](Get-Command $Name -ErrorAction SilentlyContinue)
}
function Refresh-Path {
$env:Path = [Environment]::GetEnvironmentVariable("Path", "User") + ";" + [Environment]::GetEnvironmentVariable("Path", "Machine")
}
# ========== Node.js 版本检测 ==========
function Get-NodeVersion {
if (Test-Command "node") {
try {
$versionStr = (& node --version 2>$null) -replace 'v', ''
$major = [int]($versionStr -split '\.')[0]
return @{ Version = $versionStr; Major = $major }
}
catch { }
}
return $null
}
# ========== fnm 安装 ==========
function Install-Fnm {
Write-Host ""
Write-Info "正在安装 fnm (Fast Node Manager)..."
try {
# 使用 winget 安装 fnm
if (Test-Command "winget") {
Write-Info "使用 winget 安装 fnm..."
& winget install Schniz.fnm -e --accept-source-agreements --accept-package-agreements
}
else {
# 备选:使用 cargo 或手动下载
Write-Info "使用 PowerShell 脚本安装 fnm..."
Invoke-Expression "& { $(Invoke-RestMethod https://fnm.vercel.app/install.ps1) }"
}
Refresh-Path
# 配置 fnm 环境
if (Test-Command "fnm") {
Write-Success "fnm 安装成功!"
# 初始化 fnm
$fnmEnv = & fnm env --use-on-cd 2>$null
if ($fnmEnv) {
$fnmEnv | Out-String | Invoke-Expression
}
return $true
}
else {
Write-Warning "fnm 可能已安装,但需要重新打开终端才能生效"
Write-Info "请重新打开 PowerShell 后再运行此脚本"
return $false
}
}
catch {
Write-Error "fnm 安装失败: $($_.Exception.Message)"
return $false
}
}
# ========== 使用 fnm 安装 Node.js ==========
function Install-NodeWithFnm {
Write-Info "使用 fnm 安装 Node.js 24.x..."
try {
& fnm install 24
& fnm use 24
& fnm default 24
Refresh-Path
if (Test-Command "node") {
$nodeInfo = Get-NodeVersion
Write-Success "Node.js v$($nodeInfo.Version) 安装成功!"
return $true
}
else {
Write-Warning "Node.js 可能已安装,但需要重新打开终端才能生效"
return $false
}
}
catch {
Write-Error "Node.js 安装失败: $($_.Exception.Message)"
return $false
}
}
# ========== 确保 Node.js 环境就绪 ==========
function Ensure-NodeEnvironment {
$nodeInfo = Get-NodeVersion
if ($nodeInfo) {
Write-Info "检测到 Node.js v$($nodeInfo.Version)"
if ($nodeInfo.Major -lt 20) {
Write-Warning "Node.js 版本过低 (需要 >= 20.x)"
Write-Info "请升级 Node.js 或让脚本使用 fnm 安装新版本"
$upgrade = Read-Host "是否使用 fnm 安装 Node.js 24.x? (Y/n)"
if ($upgrade -eq "n" -or $upgrade -eq "N") {
Write-Error "Node.js 版本不满足要求,请手动升级后重试"
return $false
}
# 安装 fnm (如果未安装)
if (-not (Test-Command "fnm")) {
if (-not (Install-Fnm)) { return $false }
}
return Install-NodeWithFnm
}
return $true
}
# 未安装 Node.js
Write-Warning "未检测到 Node.js"
Write-Info "将使用 fnm 安装 Node.js 24.x"
$install = Read-Host "是否继续? (Y/n)"
if ($install -eq "n" -or $install -eq "N") {
return $false
}
# 安装 fnm
if (-not (Test-Command "fnm")) {
if (-not (Install-Fnm)) { return $false }
}
return Install-NodeWithFnm
}
# ========== 工具安装 ==========
function Install-Tool {
param(
[hashtable]$Tool
)
# 确保 Node.js 环境就绪
if (-not (Ensure-NodeEnvironment)) {
return $false
}
Write-Info "使用 npm 安装 $($Tool.Name)..."
$installCmd = "npm install -g $($Tool.Package)"
Write-Host " 执行: $installCmd" -ForegroundColor Gray
try {
Invoke-Expression $installCmd
$exitCode = $LASTEXITCODE
Refresh-Path
if ($exitCode -ne 0) {
Write-Error "安装命令返回错误码: $exitCode"
return $false
}
if (Test-Command $Tool.Command) {
Write-Success "$($Tool.Name) 安装成功!"
return $true
}
else {
Write-Warning "$($Tool.Name) 可能已安装,但需要重新打开终端才能生效"
$continue = Read-Host "是否继续进行配置? (Y/n)"
return ($continue -ne "n" -and $continue -ne "N")
}
}
catch {
Write-Error "安装失败: $($_.Exception.Message)"
return $false
}
}
# ========== 远程配置脚本调用 ==========
function Invoke-RemoteSetup {
param(
[hashtable]$Tool,
[string]$ApiKey
)
Write-Host ""
Write-Info "下载并执行 $($Tool.Name) 配置脚本..."
Write-Host " URL: $($Tool.SetupUrl)" -ForegroundColor Gray
Write-Host ""
$tempFile = $null
try {
# 下载脚本到临时文件
$tempFile = [System.IO.Path]::ChangeExtension([System.IO.Path]::GetTempFileName(), ".ps1")
Invoke-WebRequest -Uri $Tool.SetupUrl -UseBasicParsing -OutFile $tempFile
# 执行脚本,正确传递参数
$LASTEXITCODE = 0
if ($ApiKey) {
& $tempFile -ApiKey $ApiKey
}
else {
& $tempFile
}
$scriptSucceeded = $?
$exitCode = $LASTEXITCODE
# 清理临时文件
Remove-Item $tempFile -ErrorAction SilentlyContinue
# 检查执行结果
if (-not $scriptSucceeded -or $exitCode -ne 0) {
Write-Error "配置脚本执行失败,退出码: $exitCode"
return $false
}
Write-Host ""
Write-Success "$($Tool.Name) 配置完成!"
return $true
}
catch {
if ($tempFile) { Remove-Item $tempFile -ErrorAction SilentlyContinue }
Write-Error "配置脚本执行失败: $($_.Exception.Message)"
return $false
}
}
# ========== 菜单显示 ==========
function Show-Menu {
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " XCodeCLI Setup Launcher" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# 显示 Node.js 环境状态
$nodeInfo = Get-NodeVersion
if ($nodeInfo) {
$nodeStatus = if ($nodeInfo.Major -ge 20) { "[OK]" } else { "[需升级]" }
$nodeColor = if ($nodeInfo.Major -ge 20) { "Green" } else { "Yellow" }
Write-Host " Node.js: v$($nodeInfo.Version) " -NoNewline
Write-Host $nodeStatus -ForegroundColor $nodeColor
}
else {
Write-Host " Node.js: " -NoNewline
Write-Host "[未安装]" -ForegroundColor Red
}
Write-Host ""
Write-Host "选择要安装和配置的工具:" -ForegroundColor Yellow
Write-Host ""
foreach ($key in ($ToolsConfig.Keys | Sort-Object)) {
$tool = $ToolsConfig[$key]
$installed = Test-Command $tool.Command
$status = if ($installed) { "[已安装]" } else { "[未安装]" }
$color = if ($installed) { "Green" } else { "Red" }
$label = " [$key] $($tool.Name.PadRight(12))"
Write-Host "$label " -NoNewline
Write-Host $status -ForegroundColor $color
}
Write-Host ""
Write-Host " [0] 退出" -ForegroundColor Gray
Write-Host ""
}
# ========== 主函数 ==========
function Main {
if ($Help) { Show-Help }
Show-Menu
$choice = Read-Host "请选择 (0-3)"
# 退出选项
if ($choice -eq "0") {
Write-Info "再见!"
exit 0
}
# 验证选择
$choiceNum = 0
if (-not [int]::TryParse($choice, [ref]$choiceNum) -or $choiceNum -lt 1 -or $choiceNum -gt 3) {
Write-Error "无效的选择"
exit 1
}
$tool = $ToolsConfig[$choiceNum]
# 检测是否已安装
if (-not (Test-Command $tool.Command)) {
Write-Host ""
Write-Warning "$($tool.Name) 未安装"
$install = Read-Host "是否立即安装? (Y/n)"
if ($install -eq "n" -or $install -eq "N") {
Write-Info "已取消"
exit 0
}
if (-not (Install-Tool -Tool $tool)) {
exit 1
}
}
else {
Write-Host ""
Write-Success "$($tool.Name) 已安装"
}
# 调用远程配置脚本
if (-not (Invoke-RemoteSetup -Tool $tool -ApiKey $ApiKey)) {
exit 1
}
}
Main