#!/usr/bin/env bash # Butler v4 — 新环境一键部署 # Usage: bash scripts/deploy-new-env.sh [--extras EXTRA1,EXTRA2] [--lock] [--systemd] set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" BUTLER_HOME="${BUTLER_HOME:-$HOME/.butler}" EXTRAS="" USE_LOCK=0 INSTALL_SYSTEMD=0 INSTALL_LANGFUSE=0 INSTALL_GATEWAY=0 DRY_RUN=0 while [[ $# -gt 0 ]]; do case "$1" in --extras) EXTRAS="$2"; shift ;; --lock) USE_LOCK=1 ;; --systemd) INSTALL_SYSTEMD=1 ;; --gateway) INSTALL_GATEWAY=1 ;; --langfuse) INSTALL_LANGFUSE=1 ;; --dry-run) DRY_RUN=1 ;; -h|--help) cat <&2; exit 1 ;; esac shift done run_cmd() { if [[ "$DRY_RUN" -eq 1 ]]; then echo " [DRY-RUN] $*" else "$@" fi } if [[ "$DRY_RUN" -eq 1 ]]; then echo "=== Butler v4 部署 (DRY-RUN 模式) ===" else echo "=== Butler v4 部署 ===" fi echo "项目根: $ROOT" echo "数据目录: $BUTLER_HOME" echo "" # --- Step 1: Python 版本检查 --- echo "[1/7] 检查 Python 版本..." PYTHON="$(command -v python3 || true)" if [[ -z "$PYTHON" ]]; then echo "ERROR: 未找到 python3" >&2 exit 1 fi PY_VER=$("$PYTHON" -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')") PY_MAJOR=$("$PYTHON" -c "import sys; print(sys.version_info.major)") PY_MINOR=$("$PYTHON" -c "import sys; print(sys.version_info.minor)") if [[ "$PY_MAJOR" -lt 3 ]] || [[ "$PY_MAJOR" -eq 3 && "$PY_MINOR" -lt 11 ]]; then echo "ERROR: 需要 Python >= 3.11,当前 $PY_VER" >&2 exit 1 fi echo " Python $PY_VER ✓" # --- Step 2: 虚拟环境 --- echo "[2/7] 检查虚拟环境..." if [[ -z "${VIRTUAL_ENV:-}" ]]; then if [[ -d "$ROOT/.venv" ]]; then echo " 激活已有 .venv" if [[ "$DRY_RUN" -eq 0 ]]; then source "$ROOT/.venv/bin/activate"; fi else echo " 创建 .venv..." run_cmd "$PYTHON" -m venv "$ROOT/.venv" if [[ "$DRY_RUN" -eq 0 ]]; then source "$ROOT/.venv/bin/activate"; fi fi fi echo " venv: $VIRTUAL_ENV ✓" # --- Step 3: 安装依赖 --- echo "[3/7] 安装依赖..." run_cmd pip install --upgrade pip -q if [[ "$USE_LOCK" -eq 1 ]] && [[ -f "$ROOT/requirements.lock" ]]; then echo " 使用 requirements.lock 锁定版本..." run_cmd pip install -r "$ROOT/requirements.lock" -q run_cmd pip install -e "$ROOT" -q elif [[ "$INSTALL_GATEWAY" -eq 1 ]] || [[ "$INSTALL_SYSTEMD" -eq 1 ]]; then run_cmd pip install -e "$ROOT[gateway]" -q else run_cmd pip install -e "$ROOT[all]" -q fi if [[ -n "$EXTRAS" ]]; then IFS=',' read -ra EXTRA_LIST <<< "$EXTRAS" for extra in "${EXTRA_LIST[@]}"; do echo " 安装 extra: $extra" run_cmd pip install -e "$ROOT[$extra]" -q done fi echo " 依赖安装完成 ✓" # --- Step 4: 配置文件 --- echo "[4/7] 初始化配置..." run_cmd mkdir -p "$BUTLER_HOME" if [[ ! -f "$ROOT/.env" ]]; then run_cmd cp "$ROOT/.env.example" "$ROOT/.env" echo " 已创建 .env(请编辑填入 API keys)" else echo " .env 已存在 ✓" fi if [[ -f "$ROOT/scripts/setup-butler-config.sh" ]]; then run_cmd bash "$ROOT/scripts/setup-butler-config.sh" fi # --- Step 5: 数据目录结构 --- echo "[5/7] 初始化数据目录..." run_cmd mkdir -p "$BUTLER_HOME"/{sessions,runtime,skills,wechat,exports,gateway} run_cmd mkdir -p "$BUTLER_HOME"/gateway/{outbox/pending,outbox/sent,outbox/failed} echo " $BUTLER_HOME 结构就绪 ✓" # --- bubblewrap(网关 + terminal 沙箱推荐)--- if [[ "$INSTALL_GATEWAY" -eq 1 ]] && [[ "$(uname -s)" == "Linux" ]]; then if command -v bwrap >/dev/null 2>&1 || command -v bubblewrap >/dev/null 2>&1; then echo " bubblewrap: ✓" else echo " bubblewrap: — (未安装;启用 BUTLER_TERMINAL_SANDBOX=1 前建议安装)" if command -v apt-get >/dev/null 2>&1 && [[ "$DRY_RUN" -eq 0 ]]; then echo " 尝试安装: sudo apt-get install -y bubblewrap" if sudo -n true 2>/dev/null; then sudo apt-get install -y bubblewrap -qq || true fi fi fi fi # --- Step 6: 健康检查 --- echo "[6/7] 运行健康检查..." if python3 -m butler doctor 2>/dev/null; then echo " butler doctor ✓" else butler doctor 2>/dev/null || echo " WARNING: butler doctor 返回非零(检查 .env 配置)" fi # --- Step 7: systemd 服务(可选) --- if [[ "$INSTALL_LANGFUSE" -eq 1 ]]; then echo "[7/8] 部署 LangFuse 可观测栈(~/gongju/langfuse)..." GONGJU_OPS="${GONGJU_LANGFUSE:-$HOME/gongju/langfuse}/ops.sh" if [[ -x "$GONGJU_OPS" ]]; then run_cmd bash "$GONGJU_OPS" up if [[ -f "$ROOT/scripts/butler-observability-provision.sh" ]]; then run_cmd bash "$ROOT/scripts/butler-observability-provision.sh" fi echo " LangFuse 部署完成 ✓" else echo " WARNING: $GONGJU_OPS 未找到 — 请先初始化 ~/gongju/langfuse" fi else echo "[7/8] 跳过 LangFuse(使用 --langfuse 启用;栈在 ~/gongju/langfuse)" fi if [[ "$INSTALL_SYSTEMD" -eq 1 ]]; then echo "[8/8] 安装 systemd 服务..." if [[ -f "$ROOT/scripts/install-butler-gateway-service.sh" ]]; then bash "$ROOT/scripts/install-butler-gateway-service.sh" --no-restart fi if [[ -f "$ROOT/scripts/install-butler-ops-bundle.sh" ]]; then bash "$ROOT/scripts/install-butler-ops-bundle.sh" --no-restart fi echo " systemd 服务已安装 ✓" else echo "[8/8] 跳过 systemd(使用 --systemd 启用)" fi echo "" echo "=== 部署完成 ===" echo "" echo "后续步骤:" echo " 1. 编辑 $ROOT/.env 填入 API keys" echo " 2. 编辑 $BUTLER_HOME/config.yaml 调整模型配置" echo " 3. 启动 CLI: butler" echo " 4. 启动网关: butler wechat serve" echo " 5. 快速冒烟: PYTHONPATH=. pytest tests/test_cc_p3_p4_features.py -q" echo " 6. 终端沙箱: BUTLER_ENABLE_TERMINAL=1 时建议 BUTLER_TERMINAL_SANDBOX=1 + bubblewrap" echo " 7. Env profile: python3 scripts/apply-butler-env-profile.py lead|dev-gateway|dev-local" echo "" echo "如需迁移旧数据: bash scripts/restore-butler-data.sh "