name: 🏛️ 铸渊主权服务器 · 部署

# ═══════════════════════════════════════════════════════════
# 铸渊主权服务器部署工作流
# 编号: ZY-WF-铸体 (新器官 · 服务器部署引擎)
# 守护: 铸渊 · ICE-GL-ZY001
# 版权: 国作登字-2026-A-00037559
# ═══════════════════════════════════════════════════════════

on:
  push:
    branches: [main]
    paths:
      - 'server/**'
      - 'glada/**'
      - 'ops-agent/**'
      - 'docs/index.html'
      - 'docs/css/**'
      - 'docs/js/**'
      - 'docs/zh/**'
  workflow_dispatch:
    inputs:
      action:
        description: '部署动作'
        required: true
        default: 'deploy'
        type: choice
        options:
          - deploy
          - init
          - health-check
          - promote
          - setup-ssl
      deploy_target:
        description: '部署目标站点'
        required: false
        default: 'preview'
        type: choice
        options:
          - preview
          - production
      ssl_domain:
        description: 'SSL域名 (仅setup-ssl时需要，如: guanghulab.online)'
        required: false
        type: string

concurrency:
  group: zhuyuan-server-deploy
  cancel-in-progress: false

permissions:
  contents: read

jobs:
  # ═══ §1 初始化 (仅首次) ═══
  init:
    name: 🔧 服务器初始化
    if: github.event.inputs.action == 'init'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: 🔐 配置SSH
        env:
          SSH_KEY: ${{ secrets.ZY_SERVER_KEY }}
        run: |
          mkdir -p ~/.ssh
          echo "$SSH_KEY" > ~/.ssh/zy_key
          chmod 600 ~/.ssh/zy_key
          # 验证私钥格式完整性
          if head -1 ~/.ssh/zy_key | grep -q "BEGIN" && tail -1 ~/.ssh/zy_key | grep -q "END"; then
            echo "✅ SSH私钥格式正确（BEGIN/END标记完整）"
          else
            echo "❌ SSH私钥格式异常 — 请检查 GitHub Secrets 中 ZY_SERVER_KEY 的内容"
            echo "   应以 '-----BEGIN' 开头，以 '-----END' 结尾"
            exit 1
          fi
          ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null

      - name: 🔍 SSH连接测试
        run: |
          echo "🔍 测试SSH连接到 ${{ secrets.ZY_SERVER_HOST }}..."
          ssh -i ~/.ssh/zy_key -o BatchMode=yes -o ConnectTimeout=10 \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \
            'echo "✅ SSH连接成功 · $(hostname) · $(date)"' || {
            echo ""
            echo "═══════════════════════════════════════════════"
            echo "❌ SSH连接失败 · 排查指南"
            echo "═══════════════════════════════════════════════"
            echo ""
            echo "可能原因:"
            echo "  1. 服务器未配置对应的SSH公钥"
            echo "  2. GitHub Secrets中的私钥不完整或格式错误"
            echo "  3. SSH用户名不正确"
            echo ""
            echo "修复步骤（冰朔操作）:"
            echo "  ① 登录腾讯云控制台 → 轻量应用服务器 → 选择新加坡服务器"
            echo "  ② 点击「远程登录」→ 使用网页终端登录"
            echo "  ③ 在终端中执行以下命令生成新密钥:"
            echo "     ssh-keygen -t ed25519 -f ~/.ssh/github_deploy -N ''"
            echo "     cat ~/.ssh/github_deploy.pub >> ~/.ssh/authorized_keys"
            echo "     chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys"
            echo "     cat ~/.ssh/github_deploy"
            echo "  ④ 复制输出的私钥内容（从 -----BEGIN 到 -----END 完整复制）"
            echo "  ⑤ 打开 GitHub → Settings → Secrets → 更新 ZY_SERVER_KEY"
            echo "═══════════════════════════════════════════════"
            exit 1
          }

      - name: 📦 上传初始化脚本
        run: |
          scp -i ~/.ssh/zy_key \
            server/setup/zhuyuan-server-init.sh \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/tmp/

      - name: 🚀 执行初始化
        run: |
          ssh -i ~/.ssh/zy_key \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \
            'chmod +x /tmp/zhuyuan-server-init.sh && sudo /tmp/zhuyuan-server-init.sh'

  # ═══ §2 部署应用 (默认部署到预览站) ═══
  deploy:
    name: 🚀 部署应用代码
    if: github.event.inputs.action == 'deploy' || github.event.inputs.action == '' || github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: 🔐 配置SSH
        env:
          SSH_KEY: ${{ secrets.ZY_SERVER_KEY }}
        run: |
          mkdir -p ~/.ssh
          echo "$SSH_KEY" > ~/.ssh/zy_key
          chmod 600 ~/.ssh/zy_key
          ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null

      - name: 📦 同步应用代码
        run: |
          # 确定部署目标: preview (默认) 或 production
          TARGET="${{ github.event.inputs.deploy_target || 'preview' }}"
          TARGET_DIR="/opt/zhuyuan/sites/${TARGET}"
          echo "📦 部署目标: ${TARGET} → ${TARGET_DIR}"

          # 确保目标目录存在
          ssh -i ~/.ssh/zy_key \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \
            "mkdir -p ${TARGET_DIR} /opt/zhuyuan/app /opt/age-os/mcp-server /opt/age-os/agents /opt/age-os/schema /opt/age-os/scripts /opt/age-os/logs /opt/glada /opt/zhuyuan/ops-agent /opt/zhuyuan/ops-agent/data /opt/zhuyuan/data/logs"

          # 同步后端应用代码
          rsync -avz --delete \
            -e "ssh -i ~/.ssh/zy_key" \
            server/app/ \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/zhuyuan/app/

          # 同步 AGE OS MCP Server 代码
          rsync -avz --delete \
            -e "ssh -i ~/.ssh/zy_key" \
            --exclude='node_modules' \
            server/age-os/mcp-server/ \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/age-os/mcp-server/

          # 同步 AGE OS Agents 代码（活模块 · S5新增）
          rsync -avz --delete \
            -e "ssh -i ~/.ssh/zy_key" \
            server/age-os/agents/ \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/age-os/agents/

          # 同步 AGE OS Schema
          rsync -avz \
            -e "ssh -i ~/.ssh/zy_key" \
            server/age-os/schema/ \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/age-os/schema/

          # 同步 AGE OS PM2 配置
          scp -i ~/.ssh/zy_key \
            server/age-os/ecosystem.config.js \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/age-os/

          # 同步 AGE OS package.json
          scp -i ~/.ssh/zy_key \
            server/age-os/package.json \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/age-os/

          # 同步 GLADA 自主开发Agent 代码
          rsync -avz --delete \
            -e "ssh -i ~/.ssh/zy_key" \
            --exclude='node_modules' \
            --exclude='queue/*.json' \
            --exclude='logs/' \
            --exclude='receipts/' \
            --exclude='.env.glada' \
            glada/ \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/glada/

          # 同步 OPS Agent 运维守卫代码
          rsync -avz --delete \
            -e "ssh -i ~/.ssh/zy_key" \
            --exclude='node_modules' \
            --exclude='data/' \
            --exclude='.env.ops-agent' \
            ops-agent/ \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/zhuyuan/ops-agent/

      - name: 🔄 同步 docs → portal (单一数据源保障)
        run: |
          # docs/index.html 是 GitHub Pages 的数据源
          # server/sites/portal/ 是服务器部署的数据源
          # 自动同步确保两者一致，防止修改 docs/ 后服务器未更新
          if [ -f "docs/index.html" ] && [ -d "server/sites/portal" ]; then
            cp docs/index.html server/sites/portal/index.html
            echo "✅ docs/index.html → server/sites/portal/index.html 已同步"
          fi

      - name: 🌐 同步前端内容到站点
        run: |
          # Push事件: 直接部署到 production (guanghulab.online = ZY_DOMAIN_MAIN = production)
          # 手动触发: 使用选定的目标 (默认 preview)
          if [ "${{ github.event_name }}" = "push" ]; then
            TARGET="production"
          else
            TARGET="${{ github.event.inputs.deploy_target || 'preview' }}"
          fi
          TARGET_DIR="/opt/zhuyuan/sites/${TARGET}"
          echo "🌐 同步前端 → ${TARGET_DIR}"

          # 确保零点原核频道目录存在
          ssh -i ~/.ssh/zy_key \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \
            "mkdir -p /opt/zhuyuan/sites/yaoming /opt/zhuyuan/sites/production /opt/zhuyuan/sites/preview"

          # 同步主站门户 (server/sites/portal/) 到目标站点目录
          if [ -d "server/sites/portal" ]; then
            rsync -avz --delete \
              -e "ssh -i ~/.ssh/zy_key" \
              server/sites/portal/ \
              ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:${TARGET_DIR}/
            echo "✅ 主站门户已部署到 ${TARGET_DIR}"

            # Push事件额外同步到 preview 保持两站一致
            if [ "${{ github.event_name }}" = "push" ]; then
              rsync -avz --delete \
                -e "ssh -i ~/.ssh/zy_key" \
                server/sites/portal/ \
                ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/zhuyuan/sites/preview/
              echo "✅ 主站门户已同步到 preview (保持一致)"
            fi
          else
            # 降级: 使用 docs/ 目录
            rsync -avz --delete \
              -e "ssh -i ~/.ssh/zy_key" \
              --exclude='CNAME' \
              --exclude='*.md' \
              --exclude='.nojekyll' \
              --exclude='ontology/' \
              --exclude='daily-reports/' \
              --exclude='dashboard/' \
              --exclude='dev-portal/' \
              docs/ \
              ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:${TARGET_DIR}/
            echo "✅ 前端内容(docs/)已部署到 ${TARGET_DIR}"
          fi

          # 同步零点原核频道 (server/sites/yaoming/) 到 yaoming 目录
          if [ -d "server/sites/yaoming" ]; then
            rsync -avz --delete \
              -e "ssh -i ~/.ssh/zy_key" \
              server/sites/yaoming/ \
              ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/zhuyuan/sites/yaoming/
            echo "✅ 零点原核频道已部署到 /opt/zhuyuan/sites/yaoming/"
          fi

          # 同步智库节点 novel-db (server/novel-db/) 到服务器
          # 与主站同服务器部署 · PM2 管理 · 端口 4000
          if [ -d "server/novel-db" ]; then
            ssh -i ~/.ssh/zy_key \
              ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \
              "mkdir -p /opt/zhuyuan/novel-db/app /opt/zhuyuan/novel-db/data/books /opt/zhuyuan/novel-db/data/chapters"
            rsync -avz \
              -e "ssh -i ~/.ssh/zy_key" \
              --exclude='node_modules' \
              --exclude='.env' \
              server/novel-db/ \
              ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/zhuyuan/novel-db/
            echo "✅ 智库节点 novel-db 已同步到 /opt/zhuyuan/novel-db/"
          fi

      - name: 📦 同步配置文件
        env:
          ZY_DOMAIN_MAIN: ${{ secrets.ZY_DOMAIN_MAIN }}
          ZY_DOMAIN_PREVIEW: ${{ secrets.ZY_DOMAIN_PREVIEW }}
          ZY_FACE_DOMAIN: ${{ secrets.ZY_FACE_DOMAIN }}
        run: |
          # PM2 配置
          scp -i ~/.ssh/zy_key \
            server/ecosystem.config.js \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/zhuyuan/config/pm2/

          # Nginx 配置 — 主站 · 注入域名
          cp server/nginx/zhuyuan-sovereign.conf /tmp/zhuyuan-sovereign.conf
          if [ -n "$ZY_DOMAIN_MAIN" ]; then
            sed -i "s/ZY_DOMAIN_MAIN_PLACEHOLDER/$ZY_DOMAIN_MAIN/g" /tmp/zhuyuan-sovereign.conf
            echo "✅ 主域名已注入: $ZY_DOMAIN_MAIN"
          else
            echo "⚠️ ZY_DOMAIN_MAIN 未配置，使用IP访问"
            sed -i "s/ZY_DOMAIN_MAIN_PLACEHOLDER//g" /tmp/zhuyuan-sovereign.conf
          fi
          if [ -n "$ZY_DOMAIN_PREVIEW" ]; then
            sed -i "s/ZY_DOMAIN_PREVIEW_PLACEHOLDER/$ZY_DOMAIN_PREVIEW/g" /tmp/zhuyuan-sovereign.conf
            echo "✅ 预览域名已注入: $ZY_DOMAIN_PREVIEW"
          else
            echo "⚠️ ZY_DOMAIN_PREVIEW 未配置，预览站使用默认server_name"
            # Nginx中 _ 是标准的catch-all server_name，不匹配任何实际域名
            sed -i "s/ZY_DOMAIN_PREVIEW_PLACEHOLDER/_/g" /tmp/zhuyuan-sovereign.conf
          fi
          ZY_BRAIN_HOST="${{ secrets.ZY_BRAIN_HOST }}"
          if [ -n "$ZY_BRAIN_HOST" ]; then
            sed -i "s/ZY_BRAIN_HOST_PLACEHOLDER/$ZY_BRAIN_HOST/g" /tmp/zhuyuan-sovereign.conf
            echo "✅ 大脑服务器已注入V3桥接: $ZY_BRAIN_HOST"
          else
            echo "⚠️ ZY_BRAIN_HOST 未配置，V3桥接不可用"
            sed -i '/ZY_BRAIN_HOST_PLACEHOLDER/d' /tmp/zhuyuan-sovereign.conf
          fi
          scp -i ~/.ssh/zy_key \
            /tmp/zhuyuan-sovereign.conf \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/zhuyuan/config/nginx/zhuyuan-sovereign.conf

          # Nginx 配置 — 零点原核频道 · 注入域名
          if [ -f "server/nginx/guanghuyaoming.conf" ]; then
            cp server/nginx/guanghuyaoming.conf /tmp/guanghuyaoming.conf
            if [ -n "$ZY_FACE_DOMAIN" ]; then
              sed -i "s/ZY_FACE_DOMAIN_PLACEHOLDER/$ZY_FACE_DOMAIN/g" /tmp/guanghuyaoming.conf
              echo "✅ 零点原核域名已注入: $ZY_FACE_DOMAIN"
            else
              echo "⚠️ ZY_FACE_DOMAIN 未配置，零点原核频道使用默认server_name"
              sed -i "s/ZY_FACE_DOMAIN_PLACEHOLDER/_/g" /tmp/guanghuyaoming.conf
            fi
            scp -i ~/.ssh/zy_key \
              /tmp/guanghuyaoming.conf \
              ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/zhuyuan/config/nginx/guanghuyaoming.conf
            echo "✅ 零点原核Nginx配置已上传"
          fi

      - name: 📦 同步迁移脚本
        run: |
          # 同步数据库迁移运行器
          rsync -avz \
            -e "ssh -i ~/.ssh/zy_key" \
            server/age-os/scripts/ \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/opt/age-os/scripts/

      - name: 📥 安装依赖 & 重启
        env:
          ZHUYUAN_API_KEY: ${{ secrets.ZHUYUAN_API_KEY }}
          ZY_DB_HOST: ${{ secrets.ZY_DB_HOST }}
          ZY_DB_USER: ${{ secrets.ZY_DB_USER }}
          ZY_DB_PASS: ${{ secrets.ZY_DB_PASS }}
          ZY_DB_NAME: ${{ secrets.ZY_DB_NAME }}
          ZY_DB_PORT: ${{ secrets.ZY_DB_PORT }}
          ZY_DEEPSEEK_API_KEY: ${{ secrets.ZY_DEEPSEEK_API_KEY }}
          ZY_QIANWEN_API_KEY: ${{ secrets.ZY_QIANWEN_API_KEY }}
          ZY_KIMI_API_KEY: ${{ secrets.ZY_KIMI_API_KEY }}
          ZY_QINGYAN_API_KEY: ${{ secrets.ZY_QINGYAN_API_KEY }}
          ZY_LLM_API_KEY: ${{ secrets.ZY_LLM_API_KEY }}
          ZY_LLM_BASE_URL: ${{ secrets.ZY_LLM_BASE_URL }}
          ZY_OSS_KEY: ${{ secrets.ZY_OSS_KEY }}
          ZY_OSS_SECRET: ${{ secrets.ZY_OSS_SECRET }}
          ZY_COS_REGION: ${{ secrets.ZY_COS_REGION }}
          ZY_NOTION_TOKEN: ${{ secrets.ZY_NOTION_TOKEN }}
          ZY_CN_LLM_RELAY_HOST: ${{ secrets.ZY_CN_LLM_RELAY_HOST }}
          ZY_CN_LLM_RELAY_KEY: ${{ secrets.ZY_CN_LLM_RELAY_KEY }}
          ZY_SMTP_USER: ${{ secrets.ZY_SMTP_USER }}
          ZY_SMTP_PASS: ${{ secrets.ZY_SMTP_PASS }}
          ZY_DOMAIN_MAIN: ${{ secrets.ZY_DOMAIN_MAIN }}
          ZY_DOMAIN_PREVIEW: ${{ secrets.ZY_DOMAIN_PREVIEW }}
          ZY_FACE_DOMAIN: ${{ secrets.ZY_FACE_DOMAIN }}
        run: |
          COMMIT_SHA="${{ github.sha }}"
          REF_NAME="${{ github.ref_name }}"
          ssh -i ~/.ssh/zy_key \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} << DEPLOY_CMD

          set -e
          cd /opt/zhuyuan/app

          # 安装依赖
          npm install --production 2>&1

          # ─── 写入主应用环境变量配置 ───
          # 注意: PORT 和 ZY_SITE_MODE 不写入 .env.app
          # 这两个值由 ecosystem.config.js 按实例设置 (主站3800/预览站3801)
          # 写入 .env.app 会导致 loadEnvFile() 覆盖预览实例的端口 → 两实例抢端口 → 502
          #
          # ─── SMTP 备份：在清空 .env.app 之前先备份已有 SMTP 行 ───
          # 注意: 此命令在服务器上执行（不含 $ 变量展开），正确地从服务器读取现有 SMTP 凭据
          # 若 GitHub Secret 未配置，后续会从此备份中恢复，避免每次部署把已配置的 SMTP 清空
          grep "^ZY_SMTP" /opt/zhuyuan/app/.env.app > /tmp/.zy_smtp_bak 2>/dev/null || true
          echo "NODE_ENV=production" > /opt/zhuyuan/app/.env.app
          echo "ZY_ROOT=/opt/zhuyuan" >> /opt/zhuyuan/app/.env.app
          echo "ZY_DEEPSEEK_API_KEY=${ZY_DEEPSEEK_API_KEY}" >> /opt/zhuyuan/app/.env.app
          echo "ZY_QIANWEN_API_KEY=${ZY_QIANWEN_API_KEY}" >> /opt/zhuyuan/app/.env.app
          echo "ZY_KIMI_API_KEY=${ZY_KIMI_API_KEY}" >> /opt/zhuyuan/app/.env.app
          echo "ZY_QINGYAN_API_KEY=${ZY_QINGYAN_API_KEY}" >> /opt/zhuyuan/app/.env.app
          echo "ZY_NOTION_TOKEN=${ZY_NOTION_TOKEN}" >> /opt/zhuyuan/app/.env.app
          # ─── QQ邮箱SMTP配置（零点原核频道邮箱验证码登录） ───
          # 优先使用 CI/CD 注入的 Secret；Secret 未配置时从部署前备份中恢复
          # 修复说明: 原来用 $(grep ...) 读取服务器文件，但 unquoted heredoc 中命令替换在本地
          #           runner 执行，/opt/zhuyuan/app/.env.app 本地不存在，导致 PREV_SMTP 始终为空
          #           现在改为：清空前先 grep 备份（服务器端执行），清空后从备份恢复
          if [ -n "${ZY_SMTP_USER}" ] && [ -n "${ZY_SMTP_PASS}" ]; then
            echo "ZY_SMTP_USER=${ZY_SMTP_USER}" >> /opt/zhuyuan/app/.env.app
            echo "ZY_SMTP_PASS=${ZY_SMTP_PASS}" >> /opt/zhuyuan/app/.env.app
            echo "✅ QQ邮箱SMTP凭据已配置 (来自 GitHub Secret)"
            rm -f /tmp/.zy_smtp_bak
          elif [ -s /tmp/.zy_smtp_bak ]; then
            cat /tmp/.zy_smtp_bak >> /opt/zhuyuan/app/.env.app
            rm -f /tmp/.zy_smtp_bak
            echo "✅ QQ邮箱SMTP凭据已恢复 (来自服务器现有值·Secret未设置)"
          else
            echo "⚠️ ZY_SMTP_USER/ZY_SMTP_PASS未配置·邮箱验证码功能不可用·请在 GitHub Settings → Secrets 中设置"
          fi
          # ─── 通用LLM聊天引擎配置（国内模型网关的备用通道） ───
          if [ -n "${ZY_LLM_API_KEY}" ]; then
            echo "ZY_LLM_API_KEY=${ZY_LLM_API_KEY}" >> /opt/zhuyuan/app/.env.app
            echo "✅ 通用LLM API密钥已配置"
          fi
          if [ -n "${ZY_LLM_BASE_URL}" ]; then
            echo "ZY_LLM_BASE_URL=${ZY_LLM_BASE_URL}" >> /opt/zhuyuan/app/.env.app
            echo "✅ 通用LLM API地址已配置: ${ZY_LLM_BASE_URL}"
          fi
          # ─── 广州CN中继配置（可选·配置后国内API走广州中继） ───
          if [ -n "${ZY_CN_LLM_RELAY_HOST}" ]; then
            echo "ZY_CN_LLM_RELAY_HOST=${ZY_CN_LLM_RELAY_HOST}" >> /opt/zhuyuan/app/.env.app
            echo "ZY_CN_LLM_RELAY_KEY=${ZY_CN_LLM_RELAY_KEY}" >> /opt/zhuyuan/app/.env.app
            echo "ZY_CN_LLM_RELAY_PORT=3900" >> /opt/zhuyuan/app/.env.app
            echo "✅ 广州CN中继已配置: ${ZY_CN_LLM_RELAY_HOST}:3900"
          else
            echo "ℹ️ 广州CN中继未配置·国内API走直连"
          fi

          # ─── 服务器区域标识（Phase A3·决定中继路由策略） ───
          echo "ZY_SERVER_REGION=sg" >> /opt/zhuyuan/app/.env.app

          # ─── 数据库连接配置（Phase A2·记忆桥接需要） ───
          echo "ZY_DB_HOST=${ZY_DB_HOST:-127.0.0.1}" >> /opt/zhuyuan/app/.env.app
          echo "ZY_DB_USER=${ZY_DB_USER:-zy_admin}" >> /opt/zhuyuan/app/.env.app
          echo "ZY_DB_PASS=${ZY_DB_PASS}" >> /opt/zhuyuan/app/.env.app
          echo "ZY_DB_NAME=${ZY_DB_NAME:-age_os}" >> /opt/zhuyuan/app/.env.app
          echo "ZY_DB_PORT=${ZY_DB_PORT:-5432}" >> /opt/zhuyuan/app/.env.app

          chmod 600 /opt/zhuyuan/app/.env.app

          # 复制Nginx配置
          sudo cp /opt/zhuyuan/config/nginx/zhuyuan-sovereign.conf /etc/nginx/sites-available/zhuyuan.conf
          sudo ln -sf /etc/nginx/sites-available/zhuyuan.conf /etc/nginx/sites-enabled/zhuyuan.conf

          # 零点原核频道Nginx配置
          if [ -f "/opt/zhuyuan/config/nginx/guanghuyaoming.conf" ]; then
            sudo cp /opt/zhuyuan/config/nginx/guanghuyaoming.conf /etc/nginx/sites-available/guanghuyaoming.conf
            sudo ln -sf /etc/nginx/sites-available/guanghuyaoming.conf /etc/nginx/sites-enabled/guanghuyaoming.conf
            echo "✅ 零点原核Nginx配置已启用"
          fi

          # 移除默认配置文件，避免 duplicate default_server 冲突
          # zhuyuan.conf 已声明 listen 80 default_server，不能与 default 文件共存
          sudo rm -f /etc/nginx/sites-enabled/default

          sudo nginx -t && sudo systemctl reload nginx

          # PM2 重启 · 主应用 + 预览进程 + 智库节点 (全部清理·否则残留errored进程导致502)
          pm2 delete zhuyuan-server 2>/dev/null || true
          pm2 delete zhuyuan-preview 2>/dev/null || true
          pm2 delete novel-api 2>/dev/null || true

          # ─── 智库节点 novel-db 依赖安装 + 环境变量 ───
          if [ -d "/opt/zhuyuan/novel-db/app" ]; then
            cd /opt/zhuyuan/novel-db/app
            npm install --production
            # 写入 novel-db 环境变量（复用主站 LLM API 密钥）
            echo "NODE_ENV=production" > /opt/zhuyuan/novel-db/.env
            echo "PORT=4000" >> /opt/zhuyuan/novel-db/.env
            echo "BOOKS_DIR=/opt/zhuyuan/novel-db/data/books" >> /opt/zhuyuan/novel-db/.env
            echo "CHAPTERS_DIR=/opt/zhuyuan/novel-db/data/chapters" >> /opt/zhuyuan/novel-db/.env
            # AI 模型密钥（智库 Agent 对话 + AI 辅助写作）
            echo "DEEPSEEK_API_KEY=${ZY_DEEPSEEK_API_KEY}" >> /opt/zhuyuan/novel-db/.env
            echo "ZY_DEEPSEEK_API_KEY=${ZY_DEEPSEEK_API_KEY}" >> /opt/zhuyuan/novel-db/.env
            echo "KIMI_API_KEY=${ZY_KIMI_API_KEY}" >> /opt/zhuyuan/novel-db/.env
            echo "ZY_KIMI_API_KEY=${ZY_KIMI_API_KEY}" >> /opt/zhuyuan/novel-db/.env
            echo "DASHSCOPE_API_KEY=${ZY_QIANWEN_API_KEY}" >> /opt/zhuyuan/novel-db/.env
            echo "ZY_QIANWEN_API_KEY=${ZY_QIANWEN_API_KEY}" >> /opt/zhuyuan/novel-db/.env
            if [ -n "${ZY_LLM_API_KEY}" ]; then
              echo "LLM_API_KEY=${ZY_LLM_API_KEY}" >> /opt/zhuyuan/novel-db/.env
            fi
            if [ -n "${ZY_LLM_BASE_URL}" ]; then
              echo "LLM_BASE_URL=${ZY_LLM_BASE_URL}" >> /opt/zhuyuan/novel-db/.env
            fi
            chmod 600 /opt/zhuyuan/novel-db/.env
            echo "✅ 智库节点 novel-db 依赖已安装 + 环境变量已写入"
          fi

          cd /opt/zhuyuan/app
          pm2 start /opt/zhuyuan/config/pm2/ecosystem.config.js
          pm2 save

          # ─── AGE OS MCP Server 部署 ───
          cd /opt/age-os
          npm install --production 2>&1

          # 写入 MCP Server 环境变量配置
          echo "NODE_ENV=production" > /opt/age-os/.env.mcp
          echo "MCP_PORT=3100" >> /opt/age-os/.env.mcp
          echo "MCP_BIND_HOST=127.0.0.1" >> /opt/age-os/.env.mcp

          # 注入密钥（从 GitHub Secrets）
          echo "ZHUYUAN_API_KEY=${ZHUYUAN_API_KEY}" >> /opt/age-os/.env.mcp
          echo "ZY_DB_HOST=${ZY_DB_HOST:-127.0.0.1}" >> /opt/age-os/.env.mcp
          echo "ZY_DB_USER=${ZY_DB_USER:-zy_admin}" >> /opt/age-os/.env.mcp
          echo "ZY_DB_PASS=${ZY_DB_PASS}" >> /opt/age-os/.env.mcp
          echo "ZY_DB_NAME=${ZY_DB_NAME:-age_os}" >> /opt/age-os/.env.mcp
          echo "ZY_DB_PORT=${ZY_DB_PORT:-5432}" >> /opt/age-os/.env.mcp
          echo "ZY_DEEPSEEK_API_KEY=${ZY_DEEPSEEK_API_KEY}" >> /opt/age-os/.env.mcp
          echo "ZY_QIANWEN_API_KEY=${ZY_QIANWEN_API_KEY}" >> /opt/age-os/.env.mcp
          echo "ZY_KIMI_API_KEY=${ZY_KIMI_API_KEY}" >> /opt/age-os/.env.mcp
          echo "ZY_QINGYAN_API_KEY=${ZY_QINGYAN_API_KEY}" >> /opt/age-os/.env.mcp
          echo "ZY_OSS_KEY=${ZY_OSS_KEY}" >> /opt/age-os/.env.mcp
          echo "ZY_OSS_SECRET=${ZY_OSS_SECRET}" >> /opt/age-os/.env.mcp
          echo "ZY_COS_REGION=${ZY_COS_REGION:-ap-guangzhou}" >> /opt/age-os/.env.mcp
          echo "ZY_NOTION_TOKEN=${ZY_NOTION_TOKEN}" >> /opt/age-os/.env.mcp
          # ─── 通用LLM引擎密钥（MCP Server也可能需要） ───
          if [ -n "${ZY_LLM_API_KEY}" ]; then
            echo "ZY_LLM_API_KEY=${ZY_LLM_API_KEY}" >> /opt/age-os/.env.mcp
          fi
          if [ -n "${ZY_LLM_BASE_URL}" ]; then
            echo "ZY_LLM_BASE_URL=${ZY_LLM_BASE_URL}" >> /opt/age-os/.env.mcp
          fi
          chmod 600 /opt/age-os/.env.mcp

          # ─── 自动执行数据库迁移 ───
          echo ""
          echo "═══ 数据库迁移 ═══"
          cd /opt/age-os
          # 加载环境变量供迁移脚本使用
          export ZY_DB_HOST="${ZY_DB_HOST:-127.0.0.1}"
          export ZY_DB_USER="${ZY_DB_USER:-zy_admin}"
          export ZY_DB_PASS="${ZY_DB_PASS}"
          export ZY_DB_NAME="${ZY_DB_NAME:-age_os}"
          export ZY_DB_PORT="${ZY_DB_PORT:-5432}"
          node scripts/db-migrate.js || echo "⚠️ 数据库迁移有警告（非致命·应用仍会启动）"
          echo "═══════════════════"
          echo ""

          # PM2 重启 MCP Server（读取 .env.mcp）
          pm2 delete age-os-mcp 2>/dev/null || true
          pm2 delete age-os-agents 2>/dev/null || true
          cd /opt/age-os && pm2 start ecosystem.config.js
          pm2 save

          # ─── GLADA 自主开发Agent 部署 ───
          echo ""
          echo "═══ GLADA 自主开发Agent 部署 ═══"
          mkdir -p /opt/glada/queue /opt/glada/logs/executions /opt/glada/logs/notifications /opt/glada/receipts /var/log/glada

          # 安装 GLADA 依赖
          cd /opt/glada
          npm install --production 2>&1

          # 写入 GLADA 环境变量
          echo "NODE_ENV=production" > /opt/glada/.env.glada
          echo "GLADA_PORT=3900" >> /opt/glada/.env.glada
          echo "GLADA_POLL_INTERVAL=30000" >> /opt/glada/.env.glada
          echo "GLADA_MODEL=deepseek-chat" >> /opt/glada/.env.glada
          echo "GLADA_MODEL_PREFERENCE=" >> /opt/glada/.env.glada
          echo "GLADA_MODEL_REFRESH_MS=600000" >> /opt/glada/.env.glada
          echo "GLADA_STOP_ON_FAILURE=true" >> /opt/glada/.env.glada
          if [ -n "${ZY_LLM_API_KEY}" ]; then
            echo "ZY_LLM_API_KEY=${ZY_LLM_API_KEY}" >> /opt/glada/.env.glada
          fi
          if [ -n "${ZY_LLM_BASE_URL}" ]; then
            echo "ZY_LLM_BASE_URL=${ZY_LLM_BASE_URL}" >> /opt/glada/.env.glada
          fi
          # ─── GLADA 邮件通知（复用零点原核 QQ 邮箱 SMTP 凭据） ───
          if [ -n "${ZY_SMTP_USER}" ] && [ -n "${ZY_SMTP_PASS}" ]; then
            echo "ZY_SMTP_USER=${ZY_SMTP_USER}" >> /opt/glada/.env.glada
            echo "ZY_SMTP_PASS=${ZY_SMTP_PASS}" >> /opt/glada/.env.glada
            echo "✅ GLADA 邮件通知 SMTP 已配置"
          else
            echo "⚠️ GLADA 邮件通知未配置（ZY_SMTP_USER/ZY_SMTP_PASS 缺失）"
          fi
          chmod 600 /opt/glada/.env.glada

          # 预飞检查
          cd /opt/glada && node install-check.js || echo "⚠️ GLADA 预飞检查有警告（非致命·仍尝试启动）"

          # PM2 重启 GLADA Agent
          pm2 delete glada-agent 2>/dev/null || true
          cd /opt/glada && pm2 start ecosystem.config.js
          pm2 save
          echo "═══════════════════"
          echo ""

          # ─── OPS Agent 运维守卫部署 ───
          echo ""
          echo "═══ OPS Agent 运维守卫部署 ═══"
          mkdir -p /opt/zhuyuan/ops-agent/data /opt/zhuyuan/data/logs

          # 安装 OPS Agent 依赖
          cd /opt/zhuyuan/ops-agent
          npm install --production 2>&1

          # 写入 OPS Agent 环境变量
          echo "NODE_ENV=production" > /opt/zhuyuan/ops-agent/.env.ops-agent
          echo "OPS_AGENT_PORT=3950" >> /opt/zhuyuan/ops-agent/.env.ops-agent
          if [ -n "${ZY_LLM_API_KEY}" ]; then
            echo "ZY_LLM_API_KEY=${ZY_LLM_API_KEY}" >> /opt/zhuyuan/ops-agent/.env.ops-agent
          fi
          if [ -n "${ZY_LLM_BASE_URL}" ]; then
            echo "ZY_LLM_BASE_URL=${ZY_LLM_BASE_URL}" >> /opt/zhuyuan/ops-agent/.env.ops-agent
          fi
          if [ -n "${ZY_DEEPSEEK_API_KEY}" ]; then
            echo "ZY_DEEPSEEK_API_KEY=${ZY_DEEPSEEK_API_KEY}" >> /opt/zhuyuan/ops-agent/.env.ops-agent
          fi
          # OPS Agent 邮件通知（复用零点原核 QQ 邮箱 SMTP 凭据）
          if [ -n "${ZY_SMTP_USER}" ] && [ -n "${ZY_SMTP_PASS}" ]; then
            echo "ZY_SMTP_USER=${ZY_SMTP_USER}" >> /opt/zhuyuan/ops-agent/.env.ops-agent
            echo "ZY_SMTP_PASS=${ZY_SMTP_PASS}" >> /opt/zhuyuan/ops-agent/.env.ops-agent
            echo "✅ OPS Agent 邮件通知 SMTP 已配置"
          else
            echo "⚠️ OPS Agent 邮件通知未配置（ZY_SMTP_USER/ZY_SMTP_PASS 缺失）"
          fi
          chmod 600 /opt/zhuyuan/ops-agent/.env.ops-agent

          # 预飞检查
          cd /opt/zhuyuan/ops-agent && node install-check.js || echo "⚠️ OPS Agent 预飞检查有警告（非致命·仍尝试启动）"

          # PM2 重启 OPS Agent
          pm2 delete ops-agent 2>/dev/null || true
          cd /opt/zhuyuan/ops-agent && pm2 start ecosystem.config.js
          pm2 save
          echo "═══════════════════"
          echo ""

          # 健康检查 · 主应用(3800) + 预览进程(3801) + MCP(3100) + 智库节点(4000) + GLADA(3900) + OPS(3950)
          sleep 3
          curl -sf http://localhost:3800/api/health || echo "⚠️ 主应用健康检查失败，等待更长时间..."
          curl -sf http://localhost:3801/api/health || echo "⚠️ 预览进程健康检查失败，等待更长时间..."
          curl -sf http://localhost:3100/health || echo "⚠️ MCP Server健康检查失败，等待更长时间..."
          curl -sf http://localhost:4000/api/health || echo "⚠️ 智库节点健康检查失败，等待更长时间..."
          curl -sf http://localhost:3900/api/glada/health || echo "⚠️ GLADA Agent健康检查失败，等待更长时间..."
          curl -sf http://localhost:3950/health || echo "⚠️ OPS Agent健康检查失败，等待更长时间..."
          sleep 5
          curl -sf http://localhost:3800/api/health && echo "✅ 主应用已上线 (3800)" || echo "❌ 主应用启动失败 (3800)"
          curl -sf http://localhost:3801/api/health && echo "✅ 预览进程已上线 (3801)" || echo "❌ 预览进程启动失败 (3801) · 若 ZY_DOMAIN_PREVIEW 域名指向此端口则该域名可能502"
          curl -sf http://localhost:3100/health && echo "✅ MCP Server已上线 (3100)" || echo "❌ MCP Server启动失败 (3100)"
          curl -sf http://localhost:4000/api/health && echo "✅ 智库节点已上线 (4000)" || echo "❌ 智库节点启动失败 (4000) · zhiku.html API将不可用"
          curl -sf http://localhost:3900/api/glada/health && echo "✅ GLADA Agent已上线 (3900)" || echo "❌ GLADA Agent启动失败 (3900) · 自主开发Agent离线"
          curl -sf http://localhost:3950/health && echo "✅ OPS Agent已上线 (3950)" || echo "❌ OPS Agent启动失败 (3950) · 运维守卫离线"

          # DNS 诊断 · 检查域名是否指向本服务器
          echo ""
          echo "═══ DNS 诊断 ═══"
          SERVER_IP="43.134.16.246"
          for DOMAIN in "${ZY_DOMAIN_MAIN}" "${ZY_DOMAIN_PREVIEW}" "${ZY_FACE_DOMAIN}"; do
            if [ -n "$DOMAIN" ] && [ "$DOMAIN" != "_" ]; then
              RESOLVED=$(dig +short "$DOMAIN" A 2>/dev/null | head -1)
              if [ -z "$RESOLVED" ]; then
                echo "❌ DNS 未解析: $DOMAIN (无A记录·网站不可达)"
              elif [ "$RESOLVED" = "$SERVER_IP" ]; then
                echo "✅ DNS 正确: $DOMAIN → $RESOLVED"
              else
                echo "⚠️ DNS 错误: $DOMAIN → $RESOLVED (应为 $SERVER_IP)"
              fi
            fi
          done
          echo "═══════════════════"

          # LLM API 密钥诊断 · 检查聊天功能所需密钥
          echo ""
          echo "═══ 聊天API密钥诊断 ═══"
          LLM_KEY_COUNT=0
          for KEY_NAME in ZY_DEEPSEEK_API_KEY ZY_QIANWEN_API_KEY ZY_KIMI_API_KEY ZY_QINGYAN_API_KEY; do
            if grep -q "${KEY_NAME}=.\{6,\}" /opt/zhuyuan/app/.env.app 2>/dev/null; then
              echo "✅ ${KEY_NAME}: 已配置"
              LLM_KEY_COUNT=$((LLM_KEY_COUNT + 1))
            else
              echo "❌ ${KEY_NAME}: 未配置或为空 · 人格体对话功能受影响"
            fi
          done
          echo "可用国内模型数: ${LLM_KEY_COUNT}/4"
          if [ "$LLM_KEY_COUNT" -eq 0 ]; then
            echo "⚠️ 警告: 所有国内模型API密钥未配置 · 聊天功能将不可用"
          fi
          # 检查通用LLM聊天引擎（备用通道）
          if grep -q "ZY_LLM_API_KEY=.\{6,\}" /opt/zhuyuan/app/.env.app 2>/dev/null; then
            echo "✅ ZY_LLM_API_KEY: 已配置 (通用聊天引擎备用通道)"
          else
            if [ "$LLM_KEY_COUNT" -eq 0 ]; then
              echo "❌ ZY_LLM_API_KEY: 未配置 · 国内模型+通用引擎均不可用 · 聊天完全离线"
            else
              echo "ℹ️ ZY_LLM_API_KEY: 未配置 · 国内模型可用则不影响"
            fi
          fi
          echo "═══════════════════"

          # Nginx 配置诊断 · 检查 server_name 冲突
          echo ""
          echo "═══ Nginx 诊断 ═══"
          CONFLICT_COUNT=$(sudo nginx -T 2>&1 | grep -c "conflicting server name" || true)
          echo "Nginx server_name 冲突数: $CONFLICT_COUNT"
          echo "当前启用的站点配置:"
          ls -la /etc/nginx/sites-enabled/ 2>/dev/null || echo "(无 sites-enabled 目录)"
          echo "═══════════════════"

          # 记录部署操作
          curl -sf -X POST http://localhost:3800/api/operations \
            -H "Content-Type: application/json" \
            -d "{
              \"operator\": \"铸渊 · GitHub Actions\",
              \"action\": \"自动部署\",
              \"details\": \"commit: ${COMMIT_SHA}, branch: ${REF_NAME}\"
            }" || true

          DEPLOY_CMD

  # ═══ §3 健康检查 ═══
  health-check:
    name: 💚 健康检查
    if: github.event.inputs.action == 'health-check'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: 🔐 配置SSH
        env:
          SSH_KEY: ${{ secrets.ZY_SERVER_KEY }}
        run: |
          mkdir -p ~/.ssh
          echo "$SSH_KEY" > ~/.ssh/zy_key
          chmod 600 ~/.ssh/zy_key
          ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null

      - name: 💚 执行健康检查
        env:
          ZY_DOMAIN_MAIN: ${{ secrets.ZY_DOMAIN_MAIN }}
          ZY_DOMAIN_PREVIEW: ${{ secrets.ZY_DOMAIN_PREVIEW }}
          ZY_FACE_DOMAIN: ${{ secrets.ZY_FACE_DOMAIN }}
        run: |
          ssh -i ~/.ssh/zy_key \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} << 'HEALTH_CMD'

          echo "═══ 铸渊主权服务器健康报告 ═══"
          echo ""

          echo "§1 系统状态:"
          uptime
          echo ""

          echo "§2 磁盘使用:"
          df -h /
          echo ""

          echo "§3 内存使用:"
          free -m
          echo ""

          echo "§4 PM2 进程:"
          pm2 list 2>/dev/null || echo "PM2 未运行"
          echo ""

          echo "§5 Nginx 状态:"
          systemctl is-active nginx && echo "Nginx: 运行中" || echo "Nginx: 已停止"
          echo "Nginx server_name 冲突检测:"
          sudo nginx -T 2>&1 | grep "conflicting server name" || echo "  无冲突 ✅"
          echo "启用的站点配置:"
          ls /etc/nginx/sites-enabled/ 2>/dev/null || echo "  (无 sites-enabled 目录)"
          echo ""

          echo "§6 应用健康:"
          curl -sf http://localhost:3800/api/health | jq . 2>/dev/null || echo "应用未响应"
          echo ""

          echo "§7 大脑状态:"
          curl -sf http://localhost:3800/api/brain | jq '.files_present, .files_total' 2>/dev/null || echo "大脑API未响应"
          echo ""

          echo "§8 双站点状态:"
          curl -sf http://localhost:3800/api/sites | jq . 2>/dev/null || echo "站点API未响应"

          HEALTH_CMD

      - name: 🌐 DNS 域名解析检查
        env:
          ZY_DOMAIN_MAIN: ${{ secrets.ZY_DOMAIN_MAIN }}
          ZY_DOMAIN_PREVIEW: ${{ secrets.ZY_DOMAIN_PREVIEW }}
          ZY_FACE_DOMAIN: ${{ secrets.ZY_FACE_DOMAIN }}
        run: |
          echo "═══ DNS 域名解析诊断 ═══"
          SERVER_IP="43.134.16.246"
          for DOMAIN in "$ZY_DOMAIN_MAIN" "$ZY_DOMAIN_PREVIEW" "$ZY_FACE_DOMAIN"; do
            if [ -n "$DOMAIN" ] && [ "$DOMAIN" != "_" ]; then
              RESOLVED=$(dig +short "$DOMAIN" A 2>/dev/null | head -1)
              if [ -z "$RESOLVED" ]; then
                echo "❌ $DOMAIN → 无法解析 (无A记录·网站不可达)"
              elif [ "$RESOLVED" = "$SERVER_IP" ]; then
                echo "✅ $DOMAIN → $RESOLVED"
              else
                echo "⚠️ $DOMAIN → $RESOLVED (应为 $SERVER_IP · DNS配置错误!)"
              fi
            fi
          done
          echo "═══════════════════"

  # ═══ §4 一键推送: 预览站 → 主站 ═══
  promote:
    name: 🚀 预览站→主站 一键推送
    if: github.event.inputs.action == 'promote'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: 🔐 配置SSH
        env:
          SSH_KEY: ${{ secrets.ZY_SERVER_KEY }}
        run: |
          mkdir -p ~/.ssh
          echo "$SSH_KEY" > ~/.ssh/zy_key
          chmod 600 ~/.ssh/zy_key
          ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null

      - name: 🚀 执行推送
        run: |
          echo "🚀 一键推送: 预览站 → 主站"
          RUN_ID="${{ github.run_id }}"
          ssh -i ~/.ssh/zy_key \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} << PROMOTE_CMD

          # 调用铸渊 API 执行推送
          RESULT=\$(curl -sf -X POST http://localhost:3800/api/sites/promote \
            -H "Content-Type: application/json" \
            -d "{
              \"operator\": \"冰朔 · 通过 GitHub Actions 授权推送\",
              \"note\": \"workflow_dispatch promote · run_id: ${RUN_ID}\"
            }" 2>/dev/null)

          if [ \$? -eq 0 ]; then
            echo "\$RESULT" | jq . 2>/dev/null || echo "\$RESULT"
            echo ""
            echo "✅ 预览站已推送到主站"
          else
            echo "❌ 推送失败"
            echo "尝试手动执行..."
            if [ -d /opt/zhuyuan/sites/preview ] && [ -f /opt/zhuyuan/sites/preview/index.html ]; then
              rsync -a --delete /opt/zhuyuan/sites/preview/ /opt/zhuyuan/sites/production/
              echo "✅ 手动推送完成"
            else
              echo "❌ 预览站无内容，无法推送"
              exit 1
            fi
          fi

          PROMOTE_CMD

      - name: 💚 推送后验证
        run: |
          ssh -i ~/.ssh/zy_key \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} << 'VERIFY_CMD'

          echo "═══ 推送后验证 ═══"
          echo ""
          echo "主站内容:"
          ls -la /opt/zhuyuan/sites/production/ | head -10
          echo ""
          echo "站点状态:"
          curl -sf http://localhost:3800/api/sites | jq . 2>/dev/null || echo "API未响应"

          VERIFY_CMD

  # ═══ §5 SSL证书配置 ═══
  setup-ssl:
    name: 🔒 SSL证书配置
    if: github.event.inputs.action == 'setup-ssl'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: 🔐 配置SSH
        env:
          SSH_KEY: ${{ secrets.ZY_SERVER_KEY }}
        run: |
          mkdir -p ~/.ssh
          echo "$SSH_KEY" > ~/.ssh/zy_key
          chmod 600 ~/.ssh/zy_key
          if head -1 ~/.ssh/zy_key | grep -q "BEGIN" && tail -1 ~/.ssh/zy_key | grep -q "END"; then
            echo "✅ SSH私钥格式正确"
          else
            echo "❌ SSH私钥格式异常"
            exit 1
          fi
          ssh-keyscan -H ${{ secrets.ZY_SERVER_HOST }} >> ~/.ssh/known_hosts 2>/dev/null

      - name: 🔍 SSH连接测试
        run: |
          ssh -i ~/.ssh/zy_key -o BatchMode=yes -o ConnectTimeout=10 \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \
            'echo "✅ SSH连接成功 · $(hostname)"'

      - name: 📦 上传SSL配置脚本
        run: |
          scp -i ~/.ssh/zy_key \
            server/setup/setup-ssl.sh \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }}:/tmp/setup-ssl.sh

      - name: 🔒 执行SSL配置
        run: |
          SSL_DOMAIN="${{ github.event.inputs.ssl_domain }}"
          ZY_DOMAIN_PREVIEW="${{ secrets.ZY_DOMAIN_PREVIEW }}"

          # 如果未指定域名，使用预览域名
          if [ -z "$SSL_DOMAIN" ]; then
            SSL_DOMAIN="$ZY_DOMAIN_PREVIEW"
          fi

          if [ -z "$SSL_DOMAIN" ]; then
            echo "❌ 未指定SSL域名"
            echo ""
            echo "请在触发工作流时填写 ssl_domain 参数"
            echo "例如: guanghulab.online"
            exit 1
          fi

          echo "🔒 配置SSL: $SSL_DOMAIN"
          echo ""

          ssh -i ~/.ssh/zy_key \
            ${{ secrets.ZY_SERVER_USER }}@${{ secrets.ZY_SERVER_HOST }} \
            "chmod +x /tmp/setup-ssl.sh && sudo bash /tmp/setup-ssl.sh $SSL_DOMAIN"

      - name: 💚 SSL验证
        run: |
          SSL_DOMAIN="${{ github.event.inputs.ssl_domain || secrets.ZY_DOMAIN_PREVIEW }}"
          if [ -n "$SSL_DOMAIN" ]; then
            echo "🔍 验证HTTPS: https://$SSL_DOMAIN"
            sleep 3
            HTTP_CODE=$(curl -sf -o /dev/null -w "%{http_code}" "https://${SSL_DOMAIN}/" 2>/dev/null || echo "000")
            echo "HTTPS状态码: $HTTP_CODE"
            if [ "$HTTP_CODE" != "000" ]; then
              echo "✅ HTTPS可访问"
            else
              echo "⚠️ HTTPS暂时不可访问 (可能需要等待DNS传播)"
            fi
          fi
