#requires -Version 5.1 <# 凯洛 Kailoo · Claude Code 一键接入(Windows PowerShell) 裸机可用:没装 Node / VS Code / Git / Python 也能跑——会自动装好。 最省事的入口 = 下载 kailoo-install.bat 双击运行(它会自动调本脚本)。 也可在 PowerShell 里一行: irm https://kailoo.ai/install/kailoo-claude-code-setup.ps1 | iex 做的事: 1. 检测 Node.js(>= 18),没有就 winget 自动装(无 winget 兜底 nodejs.org) 2. 检测 VS Code,没有就 winget 自动装(用户级·免管理员) 3. 检测 Git for Windows,没有就装(Claude Code 在 Windows 必须有 bash;走国内镜像绕开 GitHub 封锁) 4. 安装 Claude Code(npm -g)+ 放开 PowerShell 执行策略(否则装好也跑不了 claude) 5. 写入凯洛后端环境变量(持久 setx + 当前会话) 6. 实跑一次最小 /v1/messages 验证,确认密钥和链路通 7.(可选)配联网搜索 MCP(需 Python 3.10+,没有也会试着用 winget 装) 也可下载后运行: powershell -ExecutionPolicy Bypass -File .\kailoo-claude-code-setup.ps1 鉴权方式与凯洛 /docs 文档一致:x-api-key + anthropic-version: 2023-06-01。 #> $ErrorActionPreference = 'Stop' # 老 Win10 默认可能用 TLS1.0/1.1,强制 1.2 防 Invoke-RestMethod / 镜像下载握手失败 try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} # ---- 配置(与 sites/domestic-site/src/app/docs/page.tsx 对齐)---- $BASE = 'https://kailoo.ai' $DEFAULT_MODEL = 'claude-opus-4-8[1m]' # 重度 agent 首选 $HAIKU_MODEL = 'claude-haiku-4-5-20251001' # Claude Code 后台小模型(标题/索引等),必须是 kailoo 实际服务的 haiku,否则后台任务报错 $MIN_NODE = 18 # Git 国内镜像兜底(npmmirror 动态取最新失败时用)。版本旧也无妨:Claude Code 只需要它提供 bash。 $GIT_MIRROR_FALLBACK = 'https://mirrors.huaweicloud.com/git-for-windows/v2.54.0.windows.1/Git-2.54.0-64-bit.exe' function Write-Step($n, $msg) { Write-Host "`n[$n] $msg" -ForegroundColor Cyan } function Write-Ok($msg) { Write-Host " OK $msg" -ForegroundColor Green } function Write-Warn($msg) { Write-Host " ! $msg" -ForegroundColor Yellow } function Write-Err($msg) { Write-Host " X $msg" -ForegroundColor Red } # 从注册表刷新本会话 PATH,让 winget / npm / git 刚装好的命令本进程也能立刻找到 function Update-SessionPath { $machine = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') $user = [System.Environment]::GetEnvironmentVariable('Path', 'User') $env:Path = (@($machine, $user) | Where-Object { $_ }) -join ';' } # 返回 node 主版本号(int);未安装返回 $null function Get-NodeMajor { if (-not (Get-Command node -ErrorAction SilentlyContinue)) { return $null } try { $raw = (& node --version) } catch { return $null } # 形如 v22.22.2 if ([string]::IsNullOrWhiteSpace($raw)) { return $null } try { return [int]($raw.TrimStart('v').Split('.')[0]) } catch { return $null } } # VS Code 是否已装(命令在 PATH 或常见安装路径存在) function Test-VSCodeInstalled { if (Get-Command code -ErrorAction SilentlyContinue) { return $true } $paths = @( (Join-Path $env:LOCALAPPDATA 'Programs\Microsoft VS Code\Code.exe'), (Join-Path $env:ProgramFiles 'Microsoft VS Code\Code.exe'), (Join-Path ${env:ProgramFiles(x86)} 'Microsoft VS Code\Code.exe') ) foreach ($p in $paths) { if ($p -and (Test-Path $p)) { return $true } } return $false } # 找一个 >= 3.10 的 python 命令名;找不到返回 $null function Find-Python { foreach ($cand in @('python', 'python3', 'py')) { if (Get-Command $cand -ErrorAction SilentlyContinue) { try { $v = (& $cand -c "import sys;print('%d.%d'%sys.version_info[:2])" 2>$null) } catch { $v = $null } if ($v -and ([version]$v -ge [version]'3.10')) { return $cand } } } return $null } # 从 npmmirror 找最新 git-for-windows 64-bit 安装包 URL;任何失败返回 $null(外层用固定兜底) function Get-LatestGitMirrorUrl { try { $base = 'https://registry.npmmirror.com/-/binary/git-for-windows/' $idx = Invoke-RestMethod -Uri $base -TimeoutSec 20 $latest = $idx | Where-Object { $_.name -match '^v\d+\.\d+\.\d+\.windows\.\d+/?$' } | ForEach-Object { $null = $_.name -match '^v(\d+)\.(\d+)\.(\d+)\.windows\.(\d+)' [pscustomobject]@{ name = $_.name.TrimEnd('/'); ver = [version]("$($Matches[1]).$($Matches[2]).$($Matches[3]).$($Matches[4])") } } | Sort-Object ver | Select-Object -Last 1 if (-not $latest) { return $null } $files = Invoke-RestMethod -Uri ($base + $latest.name + '/') -TimeoutSec 20 $exe = $files | Where-Object { $_.name -match '64-bit\.exe$' -and $_.name -notmatch '(?i)rc|beta' } | Select-Object -First 1 if (-not $exe) { return $null } return ($base + $latest.name + '/' + $exe.name) } catch { return $null } } Write-Host '======================================================' -ForegroundColor Magenta Write-Host ' 凯洛 Kailoo · Claude Code 一键接入 (Windows)' -ForegroundColor Magenta Write-Host '======================================================' -ForegroundColor Magenta $hasWinget = [bool](Get-Command winget -ErrorAction SilentlyContinue) if (-not $hasWinget) { Write-Warn '本机没有 winget(部分旧版 Windows 10 缺)。缺啥软件会改成引导你手动下载。' } # ---- 1. 检测 / 自动安装 Node.js ---- Write-Step 1 '检测 Node.js' $nodeMajor = Get-NodeMajor if (($null -eq $nodeMajor) -or ($nodeMajor -lt $MIN_NODE)) { if ($null -eq $nodeMajor) { Write-Warn '未检测到 Node.js。' } else { Write-Warn "Node.js 版本过低(v$nodeMajor,需 >= v$MIN_NODE)。" } if ($hasWinget) { Write-Host ' 正在用 winget 自动安装 Node.js LTS...' -ForegroundColor Gray Write-Host ' (会弹一个「用户账户控制 / 是否允许此应用更改」窗口,请点【是】)' -ForegroundColor Gray try { & winget install --id OpenJS.NodeJS.LTS -e --source winget ` --accept-package-agreements --accept-source-agreements } catch { Write-Warn ('winget 安装 Node 报错:' + $_.Exception.Message) } Update-SessionPath $nodeMajor = Get-NodeMajor } if (($null -eq $nodeMajor) -or ($nodeMajor -lt $MIN_NODE)) { Write-Err '没能自动装好 Node.js。' Write-Host ' 请手动到 https://nodejs.org 下载 LTS 安装包,双击运行(功能页全默认、别取消组件),' -ForegroundColor Yellow Write-Host ' 然后【完全关闭并重新打开 VSCode】,再重跑本命令。' -ForegroundColor Yellow try { Start-Process 'https://nodejs.org/zh-cn/download/prebuilt-installer' } catch {} exit 1 } } Write-Ok "Node.js v$nodeMajor" # ---- 2. 检测 / 自动安装 VS Code ---- Write-Step 2 '检测 VS Code' if (Test-VSCodeInstalled) { Write-Ok 'VS Code 已安装' } elseif ($hasWinget) { Write-Host ' 未检测到 VS Code,正在用 winget 自动安装(用户级·免管理员,约 1-2 分钟)...' -ForegroundColor Gray try { & winget install --id Microsoft.VisualStudioCode -e --source winget --scope user ` --accept-package-agreements --accept-source-agreements } catch { Write-Warn ('winget 安装 VS Code 报错:' + $_.Exception.Message) } Update-SessionPath if (Test-VSCodeInstalled) { Write-Ok 'VS Code 安装完成' } else { Write-Warn 'VS Code 没装上(不影响下面的 Claude Code 接入)。可手动到 https://code.visualstudio.com 下载。' } } else { Write-Warn '无 winget,跳过 VS Code 自动安装。可手动到 https://code.visualstudio.com 下载(不影响接入)。' } # ---- 3. 检测 / 自动安装 Git for Windows ---- # Claude Code 在 Windows 上必须借 Git 自带的 bash 执行命令,否则启动报 # “requires either Git for Windows (for bash) or PowerShell”。 # winget / 官方都从 github.com 下,境内常失败(0x80072efd),故优先国内镜像。 Write-Step 3 '检测 Git for Windows' if (Get-Command git -ErrorAction SilentlyContinue) { Write-Ok ('Git 已安装:' + (& git --version 2>$null)) } else { Write-Warn '未检测到 Git(Claude Code 在 Windows 需要它提供 bash)。' $gitOk = $false # 优先国内镜像(npmmirror 取最新,失败用华为固定兜底) $url = Get-LatestGitMirrorUrl if (-not $url) { $url = $GIT_MIRROR_FALLBACK } if ($url) { try { $exe = Join-Path $env:TEMP 'kailoo-git-setup.exe' Write-Host ' 正在从国内镜像下载 Git(约 60MB,有进度条)...' -ForegroundColor Gray Invoke-WebRequest -Uri $url -OutFile $exe -TimeoutSec 600 Write-Host ' 下载完成,正在静默安装 Git(全默认,约 1 分钟,无需点向导)...' -ForegroundColor Gray Start-Process -FilePath $exe -ArgumentList '/VERYSILENT','/SUPPRESSMSGBOXES','/NORESTART','/NOCANCEL','/SP-' -Wait Update-SessionPath if (Get-Command git -ErrorAction SilentlyContinue) { $gitOk = $true } } catch { Write-Warn ('Git 镜像安装失败:' + $_.Exception.Message) } } # 镜像没成功,再试 winget(非境内环境 github 可达时能装上) if (-not $gitOk -and $hasWinget) { Write-Host ' 镜像未成功,改用 winget 装 Git...' -ForegroundColor Gray try { & winget install --id Git.Git -e --source winget ` --accept-package-agreements --accept-source-agreements } catch {} Update-SessionPath if (Get-Command git -ErrorAction SilentlyContinue) { $gitOk = $true } } if ($gitOk) { Write-Ok ('Git 安装完成:' + (& git --version 2>$null)) } else { Write-Warn 'Git 没装上。Claude Code 可能因缺 bash 启动报错。' Write-Host ' 可手动从国内镜像下载安装:https://mirrors.huaweicloud.com/git-for-windows/' -ForegroundColor Yellow } } # ---- 4. 安装 Claude Code + 放开执行策略 ---- Write-Step 4 '安装 Claude Code' # 放开 PowerShell 执行策略:claude 命令本体是个 .ps1,默认 Restricted 会拦下「禁止运行脚本」。 try { $cur = Get-ExecutionPolicy -Scope CurrentUser if ($cur -notin @('RemoteSigned', 'Unrestricted', 'Bypass')) { Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force Write-Ok '已放开 PowerShell 执行策略(CurrentUser RemoteSigned),claude 命令才能跑。' } } catch { Write-Warn ('设执行策略失败(可能被组策略锁):' + $_.Exception.Message) Write-Host ' 若稍后 claude 报「禁止运行脚本」,改用 claude.cmd 运行。' -ForegroundColor Yellow } if (Get-Command claude -ErrorAction SilentlyContinue) { Write-Ok ("Claude Code 已安装:" + (& claude --version 2>$null)) Write-Host ' (如需更新可手动跑:npm update -g @anthropic-ai/claude-code)' } else { Write-Host ' 未检测到 claude,开始 npm 全局安装...' & npm install -g '@anthropic-ai/claude-code' if ($LASTEXITCODE -ne 0) { Write-Err 'npm 安装 Claude Code 失败。检查网络或 npm 配置后重跑本命令。' exit 1 } Update-SessionPath Write-Ok 'Claude Code 安装完成' Write-Warn '若稍后 claude 命令找不到,请完全重启 VSCode 后再试。' } # ---- 5. 输入密钥 + 写环境变量 ---- Write-Step 5 '配置凯洛后端' $key = (Read-Host ' 请粘贴你的凯洛密钥 (zk_ 开头)').Trim() if ([string]::IsNullOrWhiteSpace($key)) { Write-Err '密钥为空,已中止。重跑本命令再粘贴一次即可。' exit 1 } if (-not $key.StartsWith('zk_')) { Write-Warn '密钥不是 zk_ 开头,可能填错。仍继续,但验证可能失败。' } $model = (Read-Host " 默认模型 [回车用 $DEFAULT_MODEL]").Trim() if ([string]::IsNullOrWhiteSpace($model)) { $model = $DEFAULT_MODEL } # 持久(写用户环境变量,新开终端生效) & setx ANTHROPIC_BASE_URL $BASE | Out-Null & setx ANTHROPIC_AUTH_TOKEN $key | Out-Null # 注意:AUTH_TOKEN,不是 API_KEY & setx ANTHROPIC_MODEL $model | Out-Null & setx ANTHROPIC_DEFAULT_HAIKU_MODEL $HAIKU_MODEL | Out-Null # 后台小模型,必须是 kailoo 服务的 haiku,否则 claude 后台任务报错 & setx ANTHROPIC_SMALL_FAST_MODEL $HAIKU_MODEL | Out-Null # 旧版 Claude Code 变量名,兼容老版本 # 当前会话也设上,让本脚本能立刻验证、且本窗口可直接试跑 claude $env:ANTHROPIC_BASE_URL = $BASE $env:ANTHROPIC_AUTH_TOKEN = $key $env:ANTHROPIC_MODEL = $model $env:ANTHROPIC_DEFAULT_HAIKU_MODEL = $HAIKU_MODEL $env:ANTHROPIC_SMALL_FAST_MODEL = $HAIKU_MODEL Write-Ok "已写入环境变量(BASE_URL / AUTH_TOKEN / MODEL=$model / HAIKU=$HAIKU_MODEL)" Write-Warn 'setx 只对“新开”的终端生效;VSCode 需完全重启(见末尾「下一步」)。' # ---- 6. 实跑验证 ---- Write-Step 6 '验证密钥与链路' # 第一步用 GET /v1/models 校验密钥:它只验密钥、不依赖任何模型 channel 是否在线, # 不会因为某模型暂时无可用渠道(503)而把有效密钥误判为无效。 $authOk = $false try { $null = Invoke-RestMethod -Uri "$BASE/v1/models" -Method Get ` -Headers @{ 'Authorization' = "Bearer $key" } -TimeoutSec 30 Write-Ok '密钥有效,账号鉴权通过。' $authOk = $true } catch { $code = $null if ($_.Exception.Response) { try { $code = [int]$_.Exception.Response.StatusCode } catch {} } if ($code -eq 401) { Write-Err '401 鉴权失败:密钥错误 / 已过期。请核对 zk_ 密钥。' } elseif ($code) { Write-Err "鉴权请求失败,HTTP $code。" } else { Write-Err ("连接失败:" + $_.Exception.Message) } } # 第二步用 1 token 最小请求探所选模型当前是否有可用渠道(与密钥有效性分开判)。 if ($authOk) { try { $null = Invoke-RestMethod -Uri "$BASE/v1/messages" -Method Post ` -Headers @{ 'x-api-key' = $key; 'anthropic-version' = '2023-06-01'; 'content-type' = 'application/json' } ` -Body (@{ model = $model; max_tokens = 8; messages = @(@{ role = 'user'; content = 'hi' }) } | ConvertTo-Json -Depth 6) ` -TimeoutSec 30 Write-Ok "模型 $model 当前可用,凯洛后端已就绪。" } catch { $c2 = $null if ($_.Exception.Response) { try { $c2 = [int]$_.Exception.Response.StatusCode } catch {} } if ($c2 -eq 403) { Write-Warn "模型 $model 不在你密钥放行清单内(试用仅 opus-4-7 / sonnet-4-6 / haiku-4-5),换个模型即可。" } elseif ($c2 -eq 503) { Write-Warn "密钥有效,但模型 $model 当前无可用渠道(服务端暂时缺后端)。可稍后再试 / 换模型 / 联系 support@kailoo.ai。" } elseif ($c2 -eq 429) { Write-Warn "密钥有效,但当前限流(429),稍后再试。" } else { Write-Warn "模型可用性探测未通过:HTTP $c2(密钥本身有效)。" } } } if (-not $authOk) { Write-Warn '鉴权未过,但环境变量已写入。修正密钥后可重跑本命令,或手动启动 claude 排查。' } # ---- 6.5 迁移:恢复内置 WebSearch(旧版安装器曾写 permissions.deny:["WebSearch"]·现统一走官方原生满血搜索)---- if (Get-Command node -ErrorAction SilentlyContinue) { $undenyOut = (& node -e "const fs=require('fs'),os=require('os'),path=require('path');const p=path.join(os.homedir(),'.claude','settings.json');try{const d=JSON.parse(fs.readFileSync(p,'utf8'));if(d&&d.permissions&&Array.isArray(d.permissions.deny)&&d.permissions.deny.includes('WebSearch')){d.permissions.deny=d.permissions.deny.filter(x=>x!=='WebSearch');fs.writeFileSync(p,JSON.stringify(d,null,2));console.log('KAILOO_WEBSEARCH_RESTORED');}}catch(e){}" 2>&1) if ($undenyOut -match 'KAILOO_WEBSEARCH_RESTORED') { Write-Ok '已移除旧版安装器禁用的内置 WebSearch(恢复官方原生联网搜索)。' } } # ---- 7.(可选)联网搜索 MCP ---- # 2026-06-28 实测:原生 WebSearch(Anthropic web_search server tool)经 kailoo 已满血可用, # 客户端无需任何额外设置,也【不】再禁用内置 WebSearch(旧做法会把能用的搜索弄没)。 # 故默认【不】装 kailoo-search MCP。仅当要用 /v1/search(SerpAPI·可控成本)替代原生时改 $true。 $EnableSearchSetup = $false # 默认走官方原生 WebSearch(满血·无上限) $McpSpec = 'https://kailoo.ai/install/kailoo_search_mcp-0.1.0-py3-none-any.whl' # 自托管 wheel if ($EnableSearchSetup -and $authOk) { Write-Step 7 '配置联网搜索(MCP)' try { $py = Find-Python if ((-not $py) -and $hasWinget) { Write-Host ' 未找到 Python 3.10+,正在用 winget 自动安装 Python 3.12(联网搜索用)...' -ForegroundColor Gray Write-Host ' (同样可能弹「是否允许更改」窗口,请点【是】)' -ForegroundColor Gray try { & winget install --id Python.Python.3.12 -e --source winget ` --accept-package-agreements --accept-source-agreements } catch { Write-Warn ('winget 安装 Python 报错:' + $_.Exception.Message) } Update-SessionPath $py = Find-Python } if (-not $py) { Write-Warn '没有 Python 3.10+(也没装上),跳过联网搜索。装好 Python 后重跑本命令即可启用(不影响上面的 Claude Code 接入)。' } else { & $py -m pip install --user --quiet $McpSpec if ($LASTEXITCODE -ne 0) { Write-Warn '联网搜索依赖安装失败(不影响上面的 Claude Code 接入)。装好后重跑。' } else { # 用户级注册 MCP:直接写 ~/.claude.json 的 mcpServers(幂等·覆盖同名键)。 # 不走 `claude mcp add ... -- python -m ...`:PowerShell + npm 的 claude shim 会吃掉 # `--`,使 `python -m` 的 -m 被当成 claude 选项报 unknown option '-m'(Windows 坑)。 # 参数走环境变量传入·避免 key 进命令行·避免 JSON 引号转义。 $env:KAILOO_MCP_PY = $py $env:KAILOO_MCP_KEY = $key $env:KAILOO_MCP_BASE = $BASE $registerMcp = @' import json, os p = os.path.join(os.path.expanduser("~"), ".claude.json") try: d = json.load(open(p, encoding="utf-8")) except Exception: d = {} d.setdefault("mcpServers", {})["kailoo-search"] = { "type": "stdio", "command": os.environ["KAILOO_MCP_PY"], "args": ["-m", "kailoo_search_mcp.server"], "env": { "KAILOO_API_KEY": os.environ["KAILOO_MCP_KEY"], "KAILOO_BASE_URL": os.environ["KAILOO_MCP_BASE"], }, } tmp = p + ".kailoo.tmp" json.dump(d, open(tmp, "w", encoding="utf-8"), ensure_ascii=False, indent=2) os.replace(tmp, p) print("KAILOO_MCP_OK") '@ $mcpOut = ($registerMcp | & $py -) 2>&1 Remove-Item Env:\KAILOO_MCP_PY, Env:\KAILOO_MCP_KEY, Env:\KAILOO_MCP_BASE -ErrorAction SilentlyContinue if ($LASTEXITCODE -eq 0 -and ($mcpOut -match 'KAILOO_MCP_OK')) { # 关键:禁用内置 WebSearch(经 kailoo 走不通·会抢着用导致搜不到/降智), # 让模型改用 kailoo-search。合并进用户级 settings.json,保留其它配置。 $disableWebSearch = @' import json, os p = os.path.expanduser("~/.claude/settings.json") os.makedirs(os.path.dirname(p), exist_ok=True) try: d = json.load(open(p, encoding="utf-8")) except Exception: d = {} perm = d.setdefault("permissions", {}) allow = perm.setdefault("allow", []); deny = perm.setdefault("deny", []) if "WebSearch" in allow: allow.remove("WebSearch") if "WebSearch" not in deny: deny.append("WebSearch") json.dump(d, open(p, "w", encoding="utf-8"), ensure_ascii=False, indent=2) '@ $disableWebSearch | & $py - if ($LASTEXITCODE -eq 0) { Write-Ok '联网搜索已启用:已禁用走不通的内置 WebSearch,Claude 改用 kailoo-search 联网(带源)。' } else { Write-Ok '联网搜索 MCP 已注册(但未能自动禁用内置 WebSearch,搜索若不准请手动在 settings.json 加 permissions.deny: ["WebSearch"])。' } } else { Write-Warn '联网搜索注册失败(不影响上面的 Claude Code 接入)。' } } } } catch { Write-Warn ('联网搜索配置未完成:' + $_.Exception.Message + '(不影响 Claude Code 接入)。') } } # ---- 完成 ---- Write-Host "`n======================================================" -ForegroundColor Magenta Write-Host ' 下一步' -ForegroundColor Magenta Write-Host '======================================================' -ForegroundColor Magenta Write-Host ' 环境变量是「用户级」的,VSCode 必须【完全重启】才会读到:' Write-Host ' 1. 关掉整个 VSCode 窗口(不是只关终端),再重新打开' Write-Host ' 2. 顶部菜单 终端 → 新建终端' Write-Host ' 3. cd 进你的项目文件夹,运行:claude' Write-Host ' 4. 会话内切模型:/model(可选 claude-sonnet-4-6 / claude-haiku-4-5-20251001)' Write-Host '' Write-Host ' 想现在就试:本窗口已设好变量,可直接运行 claude(仅本窗口有效;新终端要先重启 VSCode)。' -ForegroundColor DarkGray Write-Host ' 遇到问题:support@kailoo.ai' -ForegroundColor DarkGray