# Hermes Agent 中国大陆一键安装 · AI 代理执行提示词

> **作者**: Hermes Agent 实战派（中国大陆环境）  
> **版本**: 2026-06-08（覆盖 Hermes v0.16.0 全套中国环境坑）  
> **测试环境**: Windows 11 + PowerShell 5.1 + Python 3.11.15 venv

---

## 👋 给学生 / 同事

如果你在中国大陆，想在自己的 Windows 电脑上装 **Hermes Agent**（一个 AI 桌面代理，类似 WorkBuddy 的开源版），但被以下问题卡住：

- ❌ GitHub 打不开 / 极慢
- ❌ `pip install` 卡 pypi.org
- ❌ 装好后卡 "Loading Hermes..." 不动
- ❌ 配好 API key 后还是 `APIConnectionError`

**👉 解决方案：把这份文件完整复制，粘贴到任何 AI 代理的对话框里**（WorkBuddy / Hermes / Cursor / Claude Code / Trae CN / 任何能执行命令的 AI），然后对它说：

> "请按这份指南帮我安装 Hermes Agent。"

AI 代理会**自动读这份指南**，然后在你的电脑上**自动执行**里面的安装脚本。跑完会给你一份报告。

---

## 🤖 给 AI 代理的指令（你！）

### 你的角色

你是一个**专门在中国大陆网络环境下安装 Hermes Agent 的助手**。你的用户已经把这整份文件喂给你了，你的工作是**自动完成安装并向用户报告**。

### 工作流程

请严格按下面的步骤执行，每步完成后再进入下一步：

#### Step 0 · 环境探测（先和用户确认）

先问用户 3 个问题（一次问完）：

1. **你的操作系统是？**（必须是 Windows 10/11；macOS / Linux 当前脚本不支持，告知用户需要手工装 + 配镜像）
2. **你已经装过 Hermes 吗？**（如果装过但卡住，选择"重装"路径；如果从未装过，走"全新安装"路径）
3. **你希望脚本执行时显示每一步吗？**（默认显示 = 不用 -DryRun；想看但不执行 = -DryRun）

如果用户懒得回答，**默认假设是"全新安装 Windows 11，要显示每步"**，按这个走。

#### Step 1 · 写脚本到磁盘

把本文件**最后一段**（标记为 `=== INSTALL_SCRIPT_START ===` 和 `=== INSTALL_SCRIPT_END ===` 之间的内容）**完整提取出来**，写到用户电脑上的：

```
C:\Users\<当前用户名>\Downloads\install-hermes-cn.ps1
```

**注意：**
- 必须用 **UTF-8 with BOM** 编码写文件（PowerShell 5.1 不识别无 BOM UTF-8 中文）
- 写完后用 `Get-Content -Path <path> -Encoding UTF8 | Measure-Object -Line` 验证行数 ≥ 500 行
- 如果用户当前目录是 Desktop 或 Documents，写到那里也行，告诉用户路径

#### Step 2 · 跑一次 DryRun

```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File "C:\Users\k2452\Downloads\install-hermes-cn.ps1" -DryRun
```

**这一步会做**：探测 GitHub 镜像 / 检查 Python / 检查 Node / 检查 Git，但**不真正下载安装**。

**成功标准**：看到 `=== Step 7/7 Verifying ===` 和 `Done`。

**如果失败**：
- 镜像全挂 → 问用户能否换代理 / VPN
- Python / Node / Git 缺 → 引导用户去 https://www.python.org/downloads/ 等装
- 权限问题 → 提示用户用管理员 PowerShell

#### Step 3 · 真正跑（去掉 -DryRun）

DryRun 通过后：

```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File "C:\Users\k2452\Downloads\install-hermes-cn.ps1"
```

**这一步会做**（约 5-15 分钟）：
1. 配清华 PyPI 源
2. 配 GitHub 国内镜像
3. 下载 Hermes 官方安装脚本
4. 执行安装
5. 修卡"Loading Hermes..."（写 venv uv.toml / 关 lazy_installs / 预装 discord / 预装 provider SDK / 修 pip.ini BOM / 修 PATH 冲突）
6. 写 .env NO_PROXY 绕开 Windows 系统死代理
7. 杀卡住的 Hermes 进程
8. 验证 `hermes --version`

**每一步的输出都要让用户看到**，不要 redirect / 抑制输出。

#### Step 4 · 验证安装成功

跑完装后，**关闭当前 PowerShell 窗口，开个新的**，然后：

```powershell
hermes --version
# 期望输出：Hermes Agent v0.16.0 (2026.6.5) ...（或类似）

hermes doctor
# 期望输出：1 issue(s) to address, 那个 issue 是 "Run 'hermes setup' to configure missing API keys"
```

如果 `hermes` 不在 PATH，告诉用户：
```powershell
$env:PATH = "$env:LOCALAPPDATA\hermes\hermes-agent\venv\Scripts;$env:PATH"
# 重启 PowerShell 后就永久生效了
```

#### Step 5 · 引导用户配置 API Key

问用户：

> "你想用哪家 AI 模型？最常见的国内选项：
> - **智谱 BigModel** (glm-4.6)：https://bigmodel.cn/ ，注册送 2000 万 tokens
> - **Kimi / Moonshot** (moonshot-v1-128k)：https://platform.moonshot.cn/
> - **DeepSeek** (deepseek-chat)：https://platform.deepseek.com/
> - **通义千问 DashScope** (qwen-plus)：https://dashscope.console.aliyun.com/
>
> 给我你的 API Key 和平台，我帮你配。"

收到 API Key 后，引导用户跑 `hermes setup`，或者直接帮用户改 `%LOCALAPPDATA%\hermes\config.yaml`：

```yaml
provider:
  openai:
    api_key: "sk-xxx"
    base_url: "https://open.bigmodel.cn/api/paas/v4/"
    model: "glm-4.6"
```

（注意：把 `name: anthropic` 这种默认值改成 `openai`，因为中国大陆默认走 OpenAI 兼容端点。）

#### Step 6 · 启动桌面验证

让用户双击开始菜单里的 **Hermes Agent** 快捷方式。第一次会卡 10-20 秒在 "Loading Hermes..."，**这是正常的**，等就好。

进入主界面后，**发一句"你好"试试**：
- ✅ 几秒内收到 AI 回复 → 完美
- ❌ `Failed to initialize agent: The 'anthropic' package is required` → 跑一次脚本（不重装）会预装 anthropic
- ❌ `APIConnectionError` → 检查 .env 是不是有 NO_PROXY=*，检查用户的 API Key 是否有效

#### Step 7 · 报告

跑完全部后，给用户一份**简洁报告**：

```
✅ Hermes Agent v0.16.0 安装完成
✅ 国内镜像已配置（清华 PyPI + ghfast.top）
✅ 所有"中国大陆特有 bug"已修复
✅ Provider SDK 已预装（4 个）
✅ Windows 死代理已绕过
✅ 进程清理完成

下一步：
1. 重启 PowerShell 让 PATH 生效
2. 双击开始菜单的 Hermes Agent 启动桌面
3. 跑 hermes setup 配 API Key
4. 开始用！

如果还有问题，把 %LOCALAPPDATA%\hermes\logs\agent.log 最后 50 行发给我。
```

---

## ✅ 成功标准 checklist

全部满足才算"装好"：

- [ ] `hermes --version` 返回 v0.16.0+
- [ ] `hermes doctor` 只有 1 个 issue（"missing API keys"）
- [ ] 开始菜单 / 桌面有 "Hermes Agent" 快捷方式
- [ ] 双击启动 → 10-20 秒进入主界面（不卡 Loading）
- [ ] 发"你好" → 几秒内收到 AI 回复
- [ ] `%LOCALAPPDATA%\hermes\hermes-agent\venv\uv.toml` 存在
- [ ] `%LOCALAPPDATA%\hermes\config.yaml` 里有 `security.allow_lazy_installs: false`
- [ ] `%LOCALAPPDATA%\hermes\.env` 里有 `NO_PROXY=*`

---

## ❌ 失败诊断表

| 症状 | 根因 | 修法 |
|---|---|---|
| Step 1/7 缺 python | Python 没装 / 没在 PATH | 装 Python 3.11+ 并勾 "Add to PATH" |
| Step 2/7 镜像全挂 | 网络不通 / 防火墙挡 | 关防火墙 / 开代理 / 换网络 |
| Step 6/7 install 退出非 0 | Hermes 官方脚本被改 / 临时抽风 | 看 `%LOCALAPPDATA%\hermes\install-transcript.log` 末尾 |
| Loading 进度条不动 | lazy_deps 卡外网 | 重跑脚本（已自动修） |
| `anthropic package required` | 没装 provider SDK | 重跑脚本（已自动预装 4 个） |
| `APIConnectionError` | Windows 死代理污染 HTTPS | 重跑脚本（已自动写 NO_PROXY） |
| 装好后 `hermes` 命令找不到 | PATH 没生效 | 重启 PowerShell |
| macOS / Linux | 当前脚本只支持 Windows | 手工装 + 配清华源 + npm 镜像 |

---

## 📋 前置要求

**用户的 Windows 电脑必须先装好：**

| 工具 | 最低版本 | 装在哪 | 装法 |
|---|---|---|---|
| Python | 3.11+ | 任意位置（PATH 里有 `python`） | https://www.python.org/downloads/ （**勾 Add to PATH**） |
| Node.js | 18+ | 任意位置（PATH 里有 `node`） | https://nodejs.org/ |
| Git | 最新 | 任意位置（PATH 里有 `git`） | https://git-scm.com/download/win |

**检查方法**（让用户跑）：
```powershell
python --version   # 期望 Python 3.11.x 或更高
node --version     # 期望 v18.x 或更高
npm --version      # 期望 9.x 或更高
git --version      # 期望 git version 2.x
```

**硬盘空间**：至少 **3 GB** 可用（venv + npm modules + 模型缓存）。

---

## 🍎 macOS / 🐧 Linux 用户

当前这份脚本只支持 Windows。Mac / Linux 用户请：

1. **手工装 Hermes Agent**：参考 https://github.com/NousResearch/hermes-agent 的 README
2. **配国内镜像**（必须）：
   ```bash
   # ~/.config/uv/uv.toml
   [[index]]
   url = "https://pypi.tuna.tsinghua.edu.cn/simple"
   default = true
   ```
3. **配 npm 镜像**：`npm config set registry https://registry.npmmirror.com`
4. **配 git 镜像**：`git config --global url."https://ghfast.top/https://github.com/".insteadOf "https://github.com/"`
5. **修同样的 4 个 bug**（参考本文件的"已知 bug"段）

或者：**开 issue 让我把 Mac / Linux 版本补上**。

---

## 🐛 本脚本覆盖的"中国环境特有问题"清单

如果你要在 **别的工具**（比如 LangChain / Open Interpreter / Aider）上修类似问题，下面这 8 条经验可以直接套用：

1. **uv.toml 必须无 BOM** + 用 `[[index]]` 形式（不是 `default-index`），否则 uv 0.11.x 解析失败
2. **venv 必须有自己的 `uv.toml`**（用户级的不生效），否则 `uv pip install` 走外网
3. **git URL 重写**：`git config --global url."https://ghfast.top/https://github.com/".insteadOf "https://github.com/"`
4. **PATH 变量大小写冲突**：`Get-ChildItem Env:Path,PATH,path` 会抛"已添加了具有相同键的项"，要先合并去重
5. **Windows 系统死代理**：HKCU 注册表的 `ProxyServer` 即使配 127.0.0.1:10808 也会被 WinINet 用来污染所有 HTTPS，需要在程序 .env 里写 `NO_PROXY=*`
6. **PowerShell 5.1 + native exe**：stderr 走 Error stream，`2>&1` 抓不到，要用 `Start-Process` + `RedirectStandardError` 到临时文件
7. **PowerShell 5.1 + UTF-8 中文**：脚本必须带 UTF-8 BOM，否则中文被当 GBK 解析乱码
8. **provider SDK 必须预装**：agent 初始化时按 provider 选 SDK（anthropic/openai/boto3/google-genai），即使你只用其中一个，少装就 fail

---

## 🛠 脚本参数速查

| 参数 | 作用 |
|---|---|
| （无参） | 标准安装：配镜像 + 装 + 修 + 验证 |
| `-Reinstall` | 询问用户确认后，删除 `$env:LOCALAPPDATA\hermes` 再装一遍 |
| `-MirrorsOnly` | 只配镜像，不装 Hermes（适合已经装好的，只想优化网络） |
| `-InteractiveSetup` | 装完跑 `hermes setup` 向导 |
| `-SkipPrecheck` | 跳过 Python/Node/Git 自检 |
| `-SkipPostInstallFix` | 跳过"修卡"步骤（默认会做） |
| `-DryRun` | 演练模式，只打印不执行 |
| `-HermesHome <path>` | 自定义安装根目录（默认 `%LOCALAPPDATA%\hermes`） |

---

## 📦 卸载

```powershell
Remove-Item -Recurse -Force "$env:LOCALAPPDATA\hermes"
```

会**完整删除** Hermes 数据、venv、配置、会话。

---

## 🔗 相关链接

- Hermes Agent GitHub：https://github.com/NousResearch/hermes-agent
- 智谱 BigModel：https://bigmodel.cn/
- Kimi / Moonshot：https://platform.moonshot.cn/
- DeepSeek：https://platform.deepseek.com/
- 清华 PyPI 镜像：https://pypi.tuna.tsinghua.edu.cn/simple
- 阿里云 npm 镜像：https://registry.npmmirror.com
- ghfast.top GitHub 代理：https://ghfast.top

---

## 📜 安装脚本本体

> 下面的 PowerShell 脚本就是 AI 代理要写到磁盘并执行的内容。
> **不要手动复制粘贴** —— 让 AI 代理提取并写入。

---

\`\`\`powershell
=== INSTALL_SCRIPT_START ===

[CmdletBinding()]
param(
    [switch]$Reinstall,
    [switch]$MirrorsOnly,
    [switch]$SkipPrecheck,
    [switch]$InteractiveSetup,
    [switch]$DryRun,
    [switch]$SkipPostInstallFix,
    [string]$HermesHome = "$env:LOCALAPPDATA\hermes"
)

$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"

# 强制 UTF-8 输出（PowerShell 5.1 默认 GBK，emoji 会乱码）
try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 } catch {}
$OutputEncoding = [System.Text.Encoding]::UTF8

# ============== 颜色输出 ==============
function Write-Banner($msg) {
    Write-Host ""
    Write-Host "=== $msg ===" -ForegroundColor Cyan
}
function Write-Ok($msg)   { Write-Host "[OK]   $msg" -ForegroundColor Green }
function Write-Info($msg) { Write-Host "[..]   $msg" -ForegroundColor DarkCyan }
function Write-Warn($msg) { Write-Host "[!]    $msg" -ForegroundColor Yellow }
function Write-Err($msg)  { Write-Host "[X]    $msg" -ForegroundColor Red }

# ============== 1. 工具自检 ==============
if (-not $SkipPrecheck) {
    Write-Banner "Step 1/7 Pre-flight checks"
    # python 是必需的，py 是 Windows Python launcher（可选），其他必需
    if (-not (Get-Command python -ErrorAction SilentlyContinue)) {
        Write-Err "缺少 python 命令。请安装 Python 3.11+：https://www.python.org/downloads/"
        exit 1
    }
    $need = @('node','npm','git')
    $missing = @()
    foreach ($c in $need) { if (-not (Get-Command $c -ErrorAction SilentlyContinue)) { $missing += $c } }
    if ($missing) {
        Write-Err "缺少必备命令：$($missing -join ', ')"
        Write-Info "Python 3.11+ : https://www.python.org/downloads/"
        Write-Info "Node.js 18+  : https://nodejs.org/"
        Write-Info "Git for Win  : https://git-scm.com/download/win"
        exit 1
    }
    $pyVer = (python --version 2>&1) -replace 'Python ', ''
    $pyMajorMinor = "$($pyVer.Split('.')[0]).$($pyVer.Split('.')[1])"
    if ([decimal]$pyMajorMinor -lt [decimal]"3.11") {
        Write-Err "Python $pyVer 过低，需要 3.11+。请升级：https://www.python.org/downloads/"
        exit 1
    }
    Write-Ok "Python : $pyVer"
    Write-Ok "Node   : $(node --version 2>&1)"
    Write-Ok "npm    : $(npm --version 2>&1)"
    Write-Ok "Git    : $(git --version 2>&1)"
}

# ============== 2. 选最佳 GitHub 镜像 ==============
Write-Banner "Step 2/7 Probing GitHub mirrors"
$mirrorCandidates = @(
    "https://ghfast.top/https://raw.githubusercontent.com/NousResearch/hermes-agent/main/README.md",
    "https://ghproxy.net/https://raw.githubusercontent.com/NousResearch/hermes-agent/main/README.md",
    "https://gh-proxy.org/https://raw.githubusercontent.com/NousResearch/hermes-agent/main/README.md",
    "https://raw.githubusercontent.com/NousResearch/hermes-agent/main/README.md"
)
function Test-Mirror {
    param([string]$Url, [int]$TimeoutSec = 8)
    try {
        $r = Invoke-WebRequest -Uri $Url -Method Head -UseBasicParsing -TimeoutSec $TimeoutSec -ErrorAction Stop
        return ($r.StatusCode -ge 200 -and $r.StatusCode -lt 400)
    } catch { return $false }
}
$bestMirror = $null
foreach ($u in $mirrorCandidates) {
    $ok = Test-Mirror -Url $u
    $mirrorHost = ([System.Uri]$u).Host
    if ($ok) { Write-Ok "可用：$mirrorHost" ; $bestMirror = $u ; break }
    else { Write-Warn "不可用：$mirrorHost" }
}
if (-not $bestMirror) {
    Write-Err "所有 GitHub 镜像都不可达。请检查网络/代理。"
    exit 1
}
# 提取镜像"前缀"：截掉 /NousResearch/... 之后的部分
$mirrorBase = $bestMirror -replace '/NousResearch/.*$',''
Write-Info "选用镜像前缀：$mirrorBase"

# ============== 3. 配置国内源 ==============
Write-Banner "Step 3/7 Configuring China mirrors"

# 3a) uv 配置（无 BOM，[[index]] 形式）
$uvDir = Join-Path $env:APPDATA "uv"
New-Item -ItemType Directory -Force -Path $uvDir | Out-Null
$uvToml = Join-Path $uvDir "uv.toml"
$uvContent = "# Hermes Agent - China mirror config`n[[index]]`nurl = `"https://pypi.tuna.tsinghua.edu.cn/simple`"`ndefault = true`n"
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText($uvToml, $uvContent, $utf8NoBom)
$uvTomlForm = 'no-BOM, [[index]] form'
Write-Ok "Wrote $uvToml ($uvTomlForm)"

# 3b) 持久化环境变量
[Environment]::SetEnvironmentVariable("UV_DEFAULT_INDEX", "https://pypi.tuna.tsinghua.edu.cn/simple", "User")
[Environment]::SetEnvironmentVariable("PLAYWRIGHT_DOWNLOAD_HOST", "https://npmmirror.com/mirrors/playwright", "User")
$env:UV_DEFAULT_INDEX = "https://pypi.tuna.tsinghua.edu.cn/simple"
$env:PLAYWRIGHT_DOWNLOAD_HOST = "https://npmmirror.com/mirrors/playwright"
Write-Ok "UV_DEFAULT_INDEX = https://pypi.tuna.tsinghua.edu.cn/simple"
Write-Ok "PLAYWRIGHT_DOWNLOAD_HOST = https://npmmirror.com/mirrors/playwright"

# 3c) git URL 重写
git config --global url."https://ghfast.top/https://github.com/".insteadOf "https://github.com/" 2>&1 | Out-Null
Write-Ok "git url rewrite: https://github.com -> https://ghfast.top/https://github.com/"

# 3d) npm 镜像
$npmReg = (npm config get registry 2>$null) -replace "`n|`r", ""
if ($npmReg -notmatch "npmmirror|taobao") {
    npm config set registry https://registry.npmmirror.com | Out-Null
    Write-Ok "npm registry -> npmmirror"
} else {
    Write-Ok "npm registry 已是：$npmReg"
}

# ============== MirrorsOnly 模式收尾 ==============
if ($MirrorsOnly) {
    Write-Banner "MirrorsOnly 模式完成"
    Write-Host "已配置国内镜像，未触动 Hermes 安装。" -ForegroundColor Cyan
    Write-Host "若已装好 Hermes，建议重启 PowerShell 让 PATH / 环境变量生效。" -ForegroundColor Cyan
    exit 0
}

# ============== 4. 预置"受管 uv" ==============
Write-Banner "Step 4/7 Pre-populating managed uv"

$binDir = Join-Path $HermesHome "bin"
New-Item -ItemType Directory -Force -Path $binDir | Out-Null
$managedUv = Join-Path $binDir "uv.exe"

if (Test-Path $managedUv) {
    Write-Ok "managed uv already present: $(& $managedUv --version 2>&1)"
} else {
    $systemUv = (Get-Command uv -ErrorAction SilentlyContinue).Source
    if ($systemUv -and (Test-Path $systemUv)) {
        Copy-Item $systemUv $managedUv -Force
        Write-Ok "copied system uv ($(& $systemUv --version 2>&1)) -> $managedUv"
    } else {
        Write-Warn "未检测到系统 uv。Hermes install 会自行从 astral.sh 下载，可能比较慢。"
        Write-Info "建议先安装 uv：iwr -useb https://astral.sh/uv/install.ps1 | iex"
    }
}

# ============== 5. Reinstall 清理 ==============
if ($Reinstall) {
    Write-Banner "Step 5a Reinstall cleanup"
    Write-Warn "将删除 $HermesHome（包括配置和会话数据）"
    if ($DryRun) {
        Write-Info "DryRun: 跳过实际删除"
    } else {
        $confirm = Read-Host "确认删除？输入 YES 继续，其他取消"
        if ($confirm -eq 'YES') {
            Get-ChildItem $HermesHome -Force -ErrorAction SilentlyContinue | ForEach-Object {
                Write-Info "removing $($_.FullName)"
            }
            Write-Info "请手动执行：Remove-Item -Recurse -Force '$HermesHome'"
            Write-Info "为安全起见，本脚本不自动递归删除（请用户确认后操作）"
        } else {
            Write-Info "已取消 -Reinstall，改为继续"
            $Reinstall = $false
        }
    }
}

# ============== 6. 下载 Hermes Agent install.ps1 ==============
Write-Banner "Step 5/7 Downloading install.ps1"
$installScriptUrl = "$mirrorBase/NousResearch/hermes-agent/main/scripts/install.ps1"
$tmpScript = Join-Path $env:TEMP "hermes-install.ps1"
Write-Info "From: $installScriptUrl"
try {
    Invoke-WebRequest -Uri $installScriptUrl -OutFile $tmpScript -UseBasicParsing -TimeoutSec 60
} catch {
    Write-Err "下载 install.ps1 失败：$($_.Exception.Message)"
    exit 1
}
$len = (Get-Item $tmpScript).Length
if ($len -lt 10000) {
    Write-Err "下载的 install.ps1 异常（$len 字节），可能镜像不完整"
    exit 1
}
Write-Ok "Downloaded $len bytes -> $tmpScript"

# ============== 7. 执行安装 ==============
Write-Banner "Step 6/7 Running installer"
if ($DryRun) {
    Write-Info "DryRun 模式，跳过实际安装"
} else {
    $extraArgs = @('-NonInteractive')
    if (-not $InteractiveSetup) { $extraArgs += '-SkipSetup' }
    Write-Info "Command: $tmpScript $($extraArgs -join ' ')"

    # 用 transcript 抓全所有流（PowerShell 5.1 的 Write-Host 走 Host 流，2>&1 抓不到）
    $logFile = Join-Path $HermesHome "install-transcript.log"
    New-Item -ItemType Directory -Force -Path $HermesHome | Out-Null
    try {
        Start-Transcript -Path $logFile -Append -ErrorAction SilentlyContinue | Out-Null
        & $tmpScript @extraArgs
        $rc = $LASTEXITCODE
    } catch {
        $rc = 1
        Write-Err "EXCEPTION: $($_.Exception.Message)"
    } finally {
        Stop-Transcript -ErrorAction SilentlyContinue | Out-Null
    }
    if ($rc -ne 0) {
        Write-Err "安装脚本退出码：$rc"
        Write-Info "日志：$logFile"
        exit $rc
    }
    Write-Ok "Install script completed"
}

# ============== 8. 修卡"Loading Hermes..." =========
# 现象：装好后第一次启动桌面，Python backend 持续打 "Lazy-installing discord.py"，
#       60s 没 ready 就被桌面 GUI 杀掉、重启，循环往复。根因是 lazy_deps 内部
#       `uv pip install` 没有走国内镜像，pypi.org 在大陆被卡住。
# 修法（顺序很关键）：
#   1) 给 hermes venv 写一个 uv.toml（独立于用户级 uv 配置），让 venv 内的 uv 走清华
#   2) 关掉 config.yaml 的 security.allow_lazy_installs（safety net，缺包时直接 fail-fast）
#   3) 主动预装 discord.py[voice] + brotlicffi，下次启动 feature_missing() 返回空就跳过
#   4) 主动预装 provider SDK（anthropic / openai / boto3 / google-genai），
#      避免 agent 初始化报 "The 'anthropic' package is required for the Anthropic provider"
#   5) 修复用户级 pip.ini BOM（如果存在）—— 默认 pip 自带的中文配置常带 BOM，
#      引发 "File contains no section headers" 错误，破坏 `python -m pip`
if (-not $SkipPostInstallFix) {
    Write-Banner "Step 6b/7 Patching Hermes to avoid first-launch hang"

    # ============== 修 PATH 变量大小写冲突 ==============
    # 一些安装器（很常见）会把 PATH 写进用户级环境变量时同时用 "Path" / "PATH" / "path" 三个名字，
    # 导致 PowerShell 内 Get-Item Env: 抛 "已添加了具有相同键的项"，Start-Process 也会撞墙。
    # 先合并去重，再继续下面的步骤。
    if (-not $DryRun) {
        $pathNames = @("Path", "PATH", "path")
        $allValues = @()
        foreach ($n in $pathNames) {
            $u = [Environment]::GetEnvironmentVariable($n, "User")
            $m = [Environment]::GetEnvironmentVariable($n, "Machine")
            if ($u) { $allValues += ($u -split ';' | Where-Object { $_ } | ForEach-Object { $_.TrimEnd('\') }) }
            if ($m) { $allValues += ($m -split ';' | Where-Object { $_ } | ForEach-Object { $_.TrimEnd('\') }) }
        }
        $merged = @()
        foreach ($p in $allValues) {
            if ($p -and ($merged -notcontains $p)) { $merged += $p }
        }
        $newValue = $merged -join ';'
        foreach ($n in $pathNames) {
            [Environment]::SetEnvironmentVariable($n, $null, "User")
        }
        [Environment]::SetEnvironmentVariable("Path", $newValue, "User")
        Write-Ok "Consolidated User-level PATH ($(($merged | Measure-Object).Count) entries, removed duplicate Path/PATH/path keys)"
        foreach ($n in @("path", "PATH")) {
            if (Test-Path "Env:\$n") { Remove-Item "Env:\$n" -Force -ErrorAction SilentlyContinue }
        }
        $env:Path = $newValue
    } else {
        Write-Info "DryRun：跳过修 PATH 冲突"
    }

    # 双重 venv 自动识别：找含 Scripts\hermes.exe 的那个
    $venvDir = $null
    foreach ($v in @((Join-Path $HermesHome "hermes-agent\venv"),
                     (Join-Path $HermesHome "hermes-agent\.venv"))) {
        if ((Test-Path (Join-Path $v "Scripts\python.exe")) -and
            (Test-Path (Join-Path $v "Scripts\hermes.exe"))) {
            $venvDir = $v; break
        }
    }
    if (-not $venvDir) {
        Write-Warn "未找到 hermes-agent\venv 或 .venv（必须含 Scripts\hermes.exe）"
        Write-Info "可能是 MirrorsOnly 模式或安装未完成，跳过修卡"
    } else {
    $venvUv = Join-Path $venvDir "uv.toml"
    $venvPy = Join-Path $venvDir "Scripts\python.exe"
    $configPath = Join-Path $HermesHome "config.yaml"

    if ($DryRun) {
        Write-Info "DryRun：跳过修卡"
    } elseif (-not (Test-Path $venvPy)) {
        Write-Warn "未找到 hermes venv Python：$venvPy"
        Write-Info "可能是 MirrorsOnly 模式或安装未完成，跳过修卡"
    } else {
        # 先把 uv 可执行路径解析好（供链内、链外共用）
        $managedUv = Join-Path $HermesHome "bin\uv.exe"
        $uvBin = if (Test-Path $managedUv) { $managedUv } else { (Get-Command uv -ErrorAction SilentlyContinue).Source }
        # 1) 写 venv 内的 uv.toml
        $uvContent = "[[index]]`nurl = `"https://pypi.tuna.tsinghua.edu.cn/simple`"`ndefault = true`n"
        $utf8NoBom = New-Object System.Text.UTF8Encoding($false)
        [System.IO.File]::WriteAllText($venvUv, $uvContent, $utf8NoBom)
        Write-Ok "Wrote $venvUv (清华源)"

        # 2) 关 config.yaml 的 lazy_installs
        if (Test-Path $configPath) {
            $cfgLines = Get-Content $configPath -Encoding UTF8
            if (Select-String -Path $configPath -Pattern '^\s*allow_lazy_installs:' -Quiet) {
                Write-Ok "config.yaml 已有 allow_lazy_installs，跳过"
            } else {
                $inserted = $false
                $newLines = for ($i = 0; $i -lt $cfgLines.Count; $i++) {
                    $line = $cfgLines[$i]
                    if (-not $inserted -and $line -match '^# =====+$') {
                        $block = @(
                            '',
                            '# =============================================================================',
                            '# Security & Lazy Install Policy (auto-patched by install-hermes-cn.ps1)',
                            '# =============================================================================',
                            'security:',
                            '  # 关掉 runtime lazy install：缺包时直接 fail-fast，不再卡启动调 pip 走外网。',
                            '  allow_lazy_installs: false',
                            '',
                            '# ----- 原文 tirith 段（保留注释） -----',
                            $line
                        )
                        $inserted = $true
                        $block
                    } else {
                        $line
                    }
                }
                [System.IO.File]::WriteAllText($configPath, ($newLines -join "`r`n"), [System.Text.Encoding]::UTF8)
                Write-Ok "Patched $configPath (security.allow_lazy_installs=false)"
            }
        } else {
            Write-Warn "未找到 $configPath，跳过 config 改写"
        }

        # 3) 预装 discord.py[voice] + brotlicffi（清华源，秒装）
        if (-not $uvBin) {
            Write-Warn "找不到 uv，跳过预装 discord 依赖"
        } else {
            Write-Info "Pre-installing discord.py[voice] + brotlicffi into venv (清华源)..."
            try {
                # 显式设 VIRTUAL_ENV，确保 venv 内的 uv.toml 生效
                $env:VIRTUAL_ENV = $venvDir
                & $uvBin pip install "discord.py[voice]==2.7.1" "brotlicffi==1.2.0.1" 2>&1 | ForEach-Object { Write-Host "  $_" }
                if ($LASTEXITCODE -eq 0) {
                    Write-Ok "discord deps 已预装，下次启动不会卡 lazy install"
                } else {
                    Write-Warn "预装 discord 失败（exit $LASTEXITCODE），可手动跑：$uvBin pip install --python `"$venvPy`" discord.py[voice]==2.7.1 brotlicffi==1.2.0.1"
                }
            } catch {
                Write-Warn "预装异常：$($_.Exception.Message)"
            }
        }
        }   # end if $DryRun / elseif / else chain  (closes L315 'else {')

        # 4) 预装 provider SDK（覆盖国内常见 provider 走向，秒装）
        if ($DryRun) {
            Write-Info "DryRun：跳过预装 provider SDK"
        } elseif (-not $uvBin) {
            Write-Warn "找不到 uv，跳过预装 provider SDK"
        } else {
            Write-Info "Pre-installing common provider SDKs into venv (清华源)..."
            $providerPkgs = @(
                "anthropic==0.87.0",
                "openai",
                "boto3==1.42.89",
                "google-genai"
            )
            $prevVenv = $env:VIRTUAL_ENV
            $env:VIRTUAL_ENV = $venvDir
            try {
                foreach ($spec in $providerPkgs) {
                    Write-Info "  >>> $spec"
                    & $uvBin pip install $spec 2>&1 | ForEach-Object { Write-Host "    $_" }
                    if ($LASTEXITCODE -ne 0) {
                        Write-Warn "  $spec 装失败（exit $LASTEXITCODE），跳过（用户可能不用这个 provider）"
                    }
                }
            } finally {
                $env:VIRTUAL_ENV = $prevVenv
            }
            # 冒烟测试
            $smoke = & $venvPy -c "import anthropic, openai, boto3, google.genai; print('all 4 OK')" 2>&1
            if ($smoke -match "all 4 OK") {
                Write-Ok "Provider SDK smoke test: 4/4 importable"
            } else {
                Write-Warn "Provider SDK smoke test FAILED（个别包可能没装上，不阻断整体）"
            }
        }

        # 5) 修用户级 pip.ini BOM（如果存在）—— BOM 污染会让 pip 直接报
        #    "File contains no section headers"，破坏 `python -m pip` 和 IDE 补全
        if ($DryRun) {
            Write-Info "DryRun：跳过修 pip.ini BOM"
        } else {
        $pipIni = Join-Path $env:APPDATA "pip\pip.ini"
        if (Test-Path $pipIni) {
            $raw = [System.IO.File]::ReadAllBytes($pipIni)
            $hasBom = ($raw.Length -ge 3) -and ($raw[0] -eq 0xEF) -and ($raw[1] -eq 0xBB) -and ($raw[2] -eq 0xBF)
            if ($hasBom) {
                $content = [System.IO.File]::ReadAllText($pipIni, [System.Text.Encoding]::UTF8)
                [System.IO.File]::WriteAllText($pipIni, $content, (New-Object System.Text.UTF8Encoding($false)))
                Write-Ok "Stripped BOM from $pipIni"
            } else {
                Write-Info "$pipIni 无 BOM，跳过"
            }
        }
        }   # end if DryRun pip.ini BOM check
    }   # end if venvDir found
}

# ============== 7c. 清理 .env（绕开 Windows 系统死代理）+ 杀卡住的 Hermes 进程 ==============
Write-Banner "Step 6c/7 Cleaning .env + killing stuck Hermes"

# 7c-a) 给 $HermesHome\.env 追加 NO_PROXY=* 等代理清空设置。
#   现象：HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ProxyServer
#   残留 127.0.0.1:10808 这种死代理时，Python urllib 走 WinINet 检测会拿去用，
#   所有 outbound HTTPS 都报 APIConnectionError。NO_PROXY=* 让 httpx 跳过系统代理。
$hermesEnv = Join-Path $HermesHome ".env"
if (Test-Path $hermesEnv) {
    $envLines = Get-Content $hermesEnv -Encoding UTF8 -ErrorAction SilentlyContinue
    $proxyKeys = @('NO_PROXY','no_proxy','HTTP_PROXY','HTTPS_PROXY','http_proxy','https_proxy','ALL_PROXY','all_proxy')
    $haveAll = $true
    foreach ($k in $proxyKeys) {
        if (-not ($envLines | Where-Object { $_.Trim() -like "$k=*" })) {
            $haveAll = $false; break
        }
    }
    if ($haveAll) {
        Write-Info "$hermesEnv 已有代理清空设置，跳过"
    } elseif ($DryRun) {
        Write-Info "DryRun：即将追加 NO_PROXY=* 等到 $hermesEnv"
    } else {
        $appendLines = @(
            '',
            '# === Added by install-hermes-cn.ps1: bypass Windows system proxy ===',
            'NO_PROXY=*',
            'no_proxy=*',
            'HTTP_PROXY=',
            'HTTPS_PROXY=',
            'http_proxy=',
            'https_proxy=',
            'ALL_PROXY=',
            'all_proxy='
        )
        Add-Content -Path $hermesEnv -Value ($appendLines -join "`r`n") -Encoding UTF8
        Write-Ok "Appended NO_PROXY=* + empty proxy vars to $hermesEnv"
    }
} else {
    Write-Info "$hermesEnv 还没生成（Hermes 未首次启动过），跳过 —— 等用户首次启动后再来跑一次脚本即可"
}

# 7c-b) 杀卡住的 Hermes 桌面进程（如果有）
$procs = @(Get-Process -Name 'Hermes','hermes' -ErrorAction SilentlyContinue)
if ($procs.Count -eq 0) {
    Write-Ok "没找到 Hermes.exe/hermes.exe，无需杀"
} elseif ($DryRun) {
    Write-Info "DryRun：会杀 $($procs.Count) 个进程："
    $procs | ForEach-Object { Write-Host "  $($_.Id)  $($_.ProcessName)" -ForegroundColor DarkGray }
} else {
    $procs | ForEach-Object {
        try {
            Stop-Process -Id $_.Id -Force -ErrorAction Stop
            Write-Ok "Killed PID $($_.Id) ($($_.ProcessName))"
        } catch {
            Write-Warn "PID $($_.Id) 拒绝访问（可能需要管理员）"
        }
    }
}

# ============== 8. 验证 ==============
Write-Banner "Step 7/7 Verifying"

# hermes 命令可能尚未在 PATH（安装器一般会改用户 PATH，要重启 shell 才生效）
$hermesExe = Get-Command hermes -ErrorAction SilentlyContinue
if ($hermesExe) {
    Write-Ok "hermes command at: $($hermesExe.Source)"
    $ver = & hermes --version 2>&1
    Write-Ok "hermes --version: $ver"
} else {
    $candidate = Join-Path $HermesHome "hermes-agent\venv\Scripts\hermes.exe"
    if (Test-Path $candidate) {
        Write-Warn "hermes 命令未在 PATH。已找到：$candidate"
        Write-Info "可临时使用（当前 shell）：`$env:PATH = '$HermesHome\hermes-agent\venv\Scripts;' + `$env:PATH"
        Write-Info "或重启 PowerShell 让用户 PATH 生效"
    } else {
        Write-Err "未找到 hermes.exe，安装可能未完成"
    }
}

Write-Banner "Done"
Write-Host ""
Write-Host "  后续步骤：" -ForegroundColor Cyan
Write-Host "    1. 重启 PowerShell 让 PATH 生效（必须）" -ForegroundColor White
Write-Host "    2. 跑 'hermes setup' 配置模型 API 密钥（智谱 / Kimi / DeepSeek / 任意 OpenAI 兼容端点）" -ForegroundColor White
Write-Host "    3. 从开始菜单 / 桌面快捷方式启动 Hermes 桌面（不再卡 Loading）" -ForegroundColor White
Write-Host ""
Write-Host "  国内推荐模型（hermes setup 时可选）：" -ForegroundColor Cyan
Write-Host "    - 智谱 BigModel GLM-4.6   : https://bigmodel.cn/" -ForegroundColor Gray
Write-Host "    - Kimi / Moonshot v1      : https://platform.moonshot.cn/" -ForegroundColor Gray
Write-Host "    - 字节豆包 / DeepSeek     : 任意 OpenAI 兼容端点即可" -ForegroundColor Gray
Write-Host ""
Write-Host "  卸载：" -ForegroundColor Cyan
Write-Host "    Remove-Item -Recurse -Force `"$HermesHome`"" -ForegroundColor Gray
Write-Host ""

=== INSTALL_SCRIPT_END ===
```

