# AnyBot Windows 一鍵安裝(x64、arm64)。桌面、手腳、第一次設定。 # # irm https://code.30cm.net/daniel.w/AnyBot/raw/branch/main/install.ps1 | iex # powershell -NoProfile -ExecutionPolicy Bypass -File install.ps1 app # powershell -File install.ps1 hands https://你的網域 482913 # powershell -File install.ps1 -Print # # 代理程式不要問問題: # $env:ANYBOT_NONINTERACTIVE='1' # $env:ANYBOT_MODE='hands' # $env:ANYBOT_PAIR_URL='https://…' # $env:ANYBOT_PAIR_CODE='482913' # irm https://code.30cm.net/daniel.w/AnyBot/raw/branch/main/install.ps1 | iex # # 伺服器(帳號+大腦+HTTPS)請在 Linux 上用 install.sh server。Windows 可以當大腦或手腳。 #Requires -Version 5.1 param( [Parameter(Position = 0)][string]$Mode = "", [Parameter(Position = 1)][string]$PairUrl = "", [Parameter(Position = 2)][string]$PairCode = "", [switch]$Print ) $ErrorActionPreference = "Stop" $Repo = if ($env:ANYBOT_REPO) { $env:ANYBOT_REPO } else { "https://code.30cm.net/daniel.w/AnyBot.git" } $Branch = if ($env:ANYBOT_BRANCH) { $env:ANYBOT_BRANCH } else { "main" } $Src = if ($env:ANYBOT_DIR) { $env:ANYBOT_DIR } else { Join-Path $env:USERPROFILE "AnyBot" } $RustMin = 95 if (-not $Mode -and $env:ANYBOT_MODE) { $Mode = $env:ANYBOT_MODE } if (-not $PairUrl -and $env:ANYBOT_PAIR_URL) { $PairUrl = $env:ANYBOT_PAIR_URL } if (-not $PairCode -and $env:ANYBOT_PAIR_CODE) { $PairCode = $env:ANYBOT_PAIR_CODE } if ($env:ANYBOT_PRINT -eq "1") { $Print = $true } if ($Mode -eq "--print" -or $Mode -eq "print" -or $Mode -eq "doctor") { $Print = $true; if ($Mode -eq "doctor") { $script:Doctor = $true } } function Say($msg) { Write-Host " $msg" } function Ok($msg) { Write-Host " ✓ $msg" -ForegroundColor Green } function Warn($msg) { Write-Host " ! $msg" -ForegroundColor Yellow } function Die($msg, $hint) { Write-Host "`n ✗ $msg" -ForegroundColor Red; if ($hint) { Write-Host " $hint" }; exit 1 } $ArchRaw = $env:PROCESSOR_ARCHITECTURE if ($env:PROCESSOR_ARCHITEW6432) { $ArchRaw = $env:PROCESSOR_ARCHITEW6432 } $ArchId = "x86_64" $RustHost = "x86_64-pc-windows-msvc" if ($ArchRaw -eq "ARM64") { $ArchId = "arm64"; $RustHost = "aarch64-pc-windows-msvc" } elseif ($ArchRaw -ne "AMD64") { $ArchId = $ArchRaw; $RustHost = "" } $Interactive = (-not $env:ANYBOT_NONINTERACTIVE) -and (-not $env:CI) -and [Environment]::UserInteractive -and -not [Console]::IsInputRedirected function Report { $ok = [bool]$RustHost if ($script:Doctor) { Write-Host "AnyBot 安裝檢查 Windows $ArchRaw" Write-Host " Rust 目標 $(if ($RustHost) { $RustHost } else { '不支援' })" Write-Host " 建議 app(有桌面)或 hands(讓大腦操控這台登入中的桌面)" Write-Host " 伺服器 請在 Linux 上架(install.sh server)。這台當大腦:裝完 anybot setup --brain" return } $obj = [ordered]@{ ok = $ok os = "Windows" arch = "$ArchRaw" arch_id = "$ArchId" rust_host = "$RustHost" distro = "Windows" libc = "msvc" pm = "winget" desktop = $true headless = $false wsl = $false systemd = $false recommended = "app" server_ok = $false modes = @("app", "hands", "deps") notes = @( "操控的是登入中的 Windows 桌面(工作排程器只在使用者登入時執行)。", "伺服器請用 Linux 的 install.sh server。" ) one_click = @{ app = "irm https://code.30cm.net/daniel.w/AnyBot/raw/branch/main/install.ps1 | iex" hands = "`$env:ANYBOT_MODE='hands'; `$env:ANYBOT_PAIR_URL='網址'; `$env:ANYBOT_PAIR_CODE='配對碼'; irm https://code.30cm.net/daniel.w/AnyBot/raw/branch/main/install.ps1 | iex" server = "curl -fsSL https://code.30cm.net/daniel.w/AnyBot/raw/branch/main/install.sh | sh -s -- server" print = "powershell -File install.ps1 -Print" } } $obj | ConvertTo-Json -Compress if (-not $ok) { exit 1 } } if ($Print) { Report; exit 0 } if (-not $RustHost) { Die "不支援的 Windows 架構:$ArchRaw" "支援 x64 與 arm64。" } if (-not $Mode -or $Mode -eq "auto" -or $Mode -eq "guide") { if ($Interactive) { Write-Host "" Write-Host " ◆ AnyBot Windows $ArchRaw" -ForegroundColor Cyan Write-Host " 1 桌面 App" Write-Host " 2 手腳(讓另一台的 Bot 操控這台登入中的桌面)" Write-Host " 3 只裝編譯需要的東西" Write-Host " 伺服器請在 Linux 上安裝。選 1/2/3 [1]: " -NoNewline $c = Read-Host switch ($c) { "2" { $Mode = "hands" } "3" { $Mode = "deps" } default { $Mode = "app" } } } else { $Mode = "app" } } if ($Mode -eq "server") { Die "Windows 不架帳號伺服器。" "請在任何有 Docker 的 Linux 執行 install.sh server。這台當大腦或手腳即可。" } if ($Mode -notin @("app", "hands", "deps")) { Die "不認得「$Mode」。" "可以用 app、hands、deps、-Print。" } Write-Host "" Write-Host " ◆ AnyBot 安裝 $Mode · Windows $ArchRaw" -ForegroundColor Cyan function Have($name) { [bool](Get-Command $name -ErrorAction SilentlyContinue) } function Ensure-WingetPackage($id, $override) { if (-not (Have "winget")) { return $false } $args = @("install", "--id", $id, "-e", "--accept-package-agreements", "--accept-source-agreements") if ($override) { $args += @("--override", $override) } & winget @args return $LASTEXITCODE -eq 0 } function Ensure-Git { if (Have "git") { Ok "git"; return } Say "安裝 Git…" if (-not (Ensure-WingetPackage "Git.Git" $null)) { Die "沒有 git。" "請安裝 https://git-scm.com/download/win 後再開一個 PowerShell。" } $git = "C:\Program Files\Git\cmd" if (Test-Path $git) { $env:Path = "$git;" + $env:Path } if (-not (Have "git")) { Die "Git 裝了,但這個視窗還沒看到。" "請關掉 PowerShell 再開一次,然後重跑同一行。" } Ok "git" } function Rust-Ok { if (-not (Have "rustc")) { return $false } $v = & rustc --version if ($v -match "rustc (\d+)\.(\d+)") { $maj = [int]$Matches[1]; $min = [int]$Matches[2] return ($maj -gt 1) -or ($maj -eq 1 -and $min -ge $RustMin) } return $false } function Ensure-Msvc { $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" if (Test-Path $vswhere) { $found = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath 2>$null if ($found) { Ok "Visual Studio C++ 工具"; return } } if (Have "cl") { Ok "cl.exe"; return } Say "安裝 Visual Studio Build Tools(C++,編譯 Rust 需要,約幾個 GB)…" $override = "--wait --passive --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended" if (-not (Ensure-WingetPackage "Microsoft.VisualStudio.2022.BuildTools" $override)) { Die "沒有 C++ 編譯器。" "請安裝 Visual Studio Build Tools 的「使用 C++ 的桌面開發」,再開一個 PowerShell:https://visualstudio.microsoft.com/visual-cpp-build-tools/" } Ok "已安裝 Build Tools。若接下來 rustc 仍找不到 link.exe,請關掉 PowerShell 再開一次。" } function Ensure-Rust { $cargoBin = Join-Path $env:USERPROFILE ".cargo\bin" if (Test-Path $cargoBin) { $env:Path = "$cargoBin;" + $env:Path } if (Rust-Ok) { Ok "Rust $((rustc --version).Split(' ')[1])"; return } Ensure-Msvc if (Have "rustup") { Say "更新 Rust…" & rustup update stable & rustup default stable } else { Say "安裝 Rust(rustup,目標 $RustHost)…" $init = Join-Path $env:TEMP "rustup-init.exe" Invoke-WebRequest -Uri "https://win.rustup.rs/x86_64" -OutFile $init if ($ArchId -eq "arm64") { Invoke-WebRequest -Uri "https://win.rustup.rs/aarch64" -OutFile $init } & $init -y --profile minimal --default-host $RustHost if ($LASTEXITCODE -ne 0) { Die "安裝 Rust 失敗。" "手動:https://rustup.rs" } } $env:Path = "$cargoBin;" + $env:Path if (-not (Rust-Ok)) { Die "Rust 還是太舊或找不到。" "關掉視窗再開,執行 rustup update stable。" } if (-not ((& rustup target list --installed) -contains $RustHost)) { & rustup target add $RustHost } Ok "Rust $((rustc --version).Split(' ')[1])" } function Find-Source { $here = $PSScriptRoot if ($here -and (Test-Path (Join-Path $here "Cargo.toml"))) { $toml = Get-Content (Join-Path $here "Cargo.toml") -Raw if ($toml -match 'name = "anybot"') { $script:Src = $here; Ok "用這份原始碼:$here"; return } } Ensure-Git if (Test-Path (Join-Path $Src ".git")) { Say "更新 $Src …" & git -C $Src pull --ff-only if ($LASTEXITCODE -ne 0) { Warn "沒辦法更新,用現有的版本" } } else { if (Test-Path $Src) { Die "$Src 已經存在,但不是 AnyBot 的原始碼。" "設 ANYBOT_DIR 換一個資料夾。" } Say "下載原始碼到 $Src …" & git clone --depth 1 -b $Branch $Repo $Src if ($LASTEXITCODE -ne 0) { Die "下載原始碼失敗。" "網路連得到 $Repo 嗎?" } } $script:Src = $Src Ok "原始碼:$Src" } function Build-Anybot { Say "編譯中,第一次約 5–15 分鐘…" Push-Location $script:Src & cargo build --release --bin anybot $code = $LASTEXITCODE Pop-Location if ($code -ne 0) { Die "編譯失敗。" "把最後幾行錯誤貼給維護的人。常見原因:沒有 C++ 建置工具,或記憶體不夠。" } Ok "編譯完成" } function Install-Bin { $from = Join-Path $script:Src "target\release\anybot.exe" if (-not (Test-Path $from)) { Die "找不到 $from" "" } $destDir = Join-Path $env:LOCALAPPDATA "AnyBot" New-Item -ItemType Directory -Force -Path $destDir | Out-Null $dest = Join-Path $destDir "anybot.exe" Copy-Item $from $dest -Force $userPath = [Environment]::GetEnvironmentVariable("Path", "User") if ($userPath -notlike "*$destDir*") { [Environment]::SetEnvironmentVariable("Path", "$userPath;$destDir", "User") } $env:Path = "$destDir;" + $env:Path $script:Bin = $dest Ok "已安裝 $dest" } function First-Config { if ($PairUrl -and $PairCode) { Say "用配對碼接上大腦,不另外詢問。" & $script:Bin setup $PairUrl $PairCode if ($LASTEXITCODE -ne 0) { Die "配對失敗。" "配對碼 10 分鐘、一次。到大腦按「加一台電腦」再拿一組。" } return } if ($env:ANYBOT_PROVIDER) { Say "寫入第一次的模型設定。" & $script:Bin setup --seed if ($LASTEXITCODE -ne 0) { Die "寫入第一次設定失敗。" "" } return } if (-not $Interactive) { Say "尚未做第一次設定。請設 ANYBOT_PAIR_URL 與 ANYBOT_PAIR_CODE,或 ANYBOT_PROVIDER 與 ANYBOT_API_KEY。" return } Write-Host "" Write-Host " 第一次設定(可略過)" Write-Host " 1 稍後在 App 裡設定" Write-Host " 2 貼上 API 金鑰,建立第一個 Bot" Write-Host " 3 接到大腦,這台當手腳" Write-Host " 選 1/2/3 [1]: " -NoNewline switch (Read-Host) { "2" { $env:ANYBOT_PROVIDER = Read-Host " 服務 openai / anthropic / xai / gemini / openrouter / opencode / ollama / custom" $sec = Read-Host " API 金鑰(ollama 可直接 Enter)" -AsSecureString $env:ANYBOT_API_KEY = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)) & $script:Bin setup --seed } "3" { $u = Read-Host " 網址" $c = Read-Host " 配對碼" if ($u -and $c) { & $script:Bin setup $u $c } } } } if ($Mode -eq "deps") { Ensure-Git Ensure-Rust Write-Host "`n 好了。在原始碼資料夾:cargo build --release --bin anybot" -ForegroundColor Green exit 0 } Ensure-Git Ensure-Rust Find-Source Build-Anybot Install-Bin if ($Mode -eq "hands") { if (-not $PairUrl -and $Interactive) { Write-Host "" Write-Host " 把這台接到大腦(AnyBot 按「加一台電腦」)" $PairUrl = Read-Host " 網址(直接 Enter 先跳過)" if ($PairUrl) { $PairCode = Read-Host " 配對碼" } } if ($PairUrl -and $PairCode) { & $script:Bin setup $PairUrl $PairCode if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } } else { Write-Host "`n 裝好了。接著:anybot setup 網址 配對碼" -ForegroundColor Green Say "配對後會在登入時自動執行。Bot 操控的是這個已登入的桌面,不是鎖定畫面。" } } else { First-Config Write-Host "`n 裝好了。從開始功能表找不到時,直接執行:" -ForegroundColor Green Write-Host " $($script:Bin)" Say "要讓 Bot 操控這台:在大腦按「加一台電腦」,用裡面的 Windows 那一行。" } Say "要更新:再執行一次同一行指令。"