diff --git a/LICENSE b/LICENSE index 5165cec..8a23721 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,6 @@ MIT License +Copyright (c) 2026 sliverp Copyright (c) 2026 Tencent Connect Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/README.md b/README.md index c1fad8c..efe6cb1 100644 --- a/README.md +++ b/README.md @@ -358,14 +358,14 @@ STT supports two-level configuration with priority fallback: ### Via upgrade-and-run.sh (One-Click) ```bash -bash ./upgrade-and-run.sh +bash ./scripts/upgrade-and-run.sh ``` When no `--appid` / `--secret` is provided, the script reads existing config from `~/.openclaw/openclaw.json` automatically. ```bash # First-time or override credentials -bash ./upgrade-and-run.sh --appid YOUR_APPID --secret YOUR_SECRET +bash ./scripts/upgrade-and-run.sh --appid YOUR_APPID --secret YOUR_SECRET ```
@@ -385,16 +385,16 @@ Environment variables `QQBOT_APPID`, `QQBOT_SECRET`, `QQBOT_TOKEN` (AppID:Secret ### Via pull-latest.sh (Git Source) ```bash -bash ./pull-latest.sh +bash ./scripts/pull-latest.sh ```
Options ```bash -bash ./pull-latest.sh --branch main # specify branch (default: main) -bash ./pull-latest.sh --force # skip prompts, force update -bash ./pull-latest.sh --repo # use a different repo +bash ./scripts/pull-latest.sh --branch main # specify branch (default: main) +bash ./scripts/pull-latest.sh --force # skip prompts, force update +bash ./scripts/pull-latest.sh --repo # use a different repo ```
diff --git a/README.zh.md b/README.zh.md index 364258c..354447c 100644 --- a/README.zh.md +++ b/README.zh.md @@ -354,14 +354,14 @@ STT 支持两级配置,按优先级查找: ### 通过 upgrade-and-run.sh 一键升级 ```bash -bash ./upgrade-and-run.sh +bash ./scripts/upgrade-and-run.sh ``` 不传 `--appid` / `--secret` 参数时,脚本会自动读取 `~/.openclaw/openclaw.json` 中已有的配置。 ```bash # 首次配置或需要覆盖时 -bash ./upgrade-and-run.sh --appid YOUR_APPID --secret YOUR_SECRET +bash ./scripts/upgrade-and-run.sh --appid YOUR_APPID --secret YOUR_SECRET ```
@@ -381,16 +381,16 @@ bash ./upgrade-and-run.sh --appid YOUR_APPID --secret YOUR_SECRET ### 通过 pull-latest.sh(Git 源码更新) ```bash -bash ./pull-latest.sh +bash ./scripts/pull-latest.sh ```
选项 ```bash -bash ./pull-latest.sh --branch main # 指定分支(默认 main) -bash ./pull-latest.sh --force # 跳过交互,强制更新 -bash ./pull-latest.sh --repo # 使用其他仓库地址 +bash ./scripts/pull-latest.sh --branch main # 指定分支(默认 main) +bash ./scripts/pull-latest.sh --force # 跳过交互,强制更新 +bash ./scripts/pull-latest.sh --repo # 使用其他仓库地址 ```
diff --git a/bin/qqbot-cli.js b/bin/qqbot-cli.js index 8145a07..5b7a24c 100644 --- a/bin/qqbot-cli.js +++ b/bin/qqbot-cli.js @@ -35,18 +35,22 @@ function detectInstallation() { return null; } +// 需要清理的所有可能的插件 ID / 包名(原仓库 + 本仓库 + 框架推断名) +const PLUGIN_IDS = ['qqbot', 'openclaw-qq', '@sliverp/qqbot', '@tencent-connect/openclaw-qq']; +// 可能的扩展目录名 +const EXTENSION_DIR_NAMES = ['qqbot', 'openclaw-qq']; + // 清理旧版本插件,返回旧的 qqbot 配置 function cleanupInstallation(appName) { const home = homedir(); const appDir = join(home, `.${appName}`); const configFile = join(appDir, `${appName}.json`); - const extensionDir = join(appDir, 'extensions', 'qqbot'); let oldQqbotConfig = null; console.log(`\n>>> 处理 ${appName} 安装...`); - // 1. 先读取旧的 qqbot 配置 + // 1. 先读取旧的 qqbot 配置(尝试所有可能的 channel key) if (existsSync(configFile)) { try { const config = JSON.parse(readFileSync(configFile, 'utf8')); @@ -59,36 +63,39 @@ function cleanupInstallation(appName) { } } - // 2. 删除旧的扩展目录 - if (existsSync(extensionDir)) { - console.log(`删除旧版本插件: ${extensionDir}`); - rmSync(extensionDir, { recursive: true, force: true }); - } else { - console.log('未找到旧版本插件目录,跳过删除'); + // 2. 删除所有可能的旧扩展目录 + for (const dirName of EXTENSION_DIR_NAMES) { + const extensionDir = join(appDir, 'extensions', dirName); + if (existsSync(extensionDir)) { + console.log(`删除旧版本插件: ${extensionDir}`); + rmSync(extensionDir, { recursive: true, force: true }); + } } - // 3. 清理配置文件中的 qqbot 相关字段 + // 3. 清理配置文件中所有可能的插件 ID 相关字段 if (existsSync(configFile)) { - console.log('清理配置文件中的 qqbot 字段...'); + console.log('清理配置文件中的插件字段...'); try { const config = JSON.parse(readFileSync(configFile, 'utf8')); - // 删除 channels.qqbot - if (config.channels?.qqbot) { - delete config.channels.qqbot; - console.log(' - 已删除 channels.qqbot'); - } + for (const id of PLUGIN_IDS) { + // 删除 channels. + if (config.channels?.[id]) { + delete config.channels[id]; + console.log(` - 已删除 channels.${id}`); + } - // 删除 plugins.entries.qqbot - if (config.plugins?.entries?.qqbot) { - delete config.plugins.entries.qqbot; - console.log(' - 已删除 plugins.entries.qqbot'); - } + // 删除 plugins.entries. + if (config.plugins?.entries?.[id]) { + delete config.plugins.entries[id]; + console.log(` - 已删除 plugins.entries.${id}`); + } - // 删除 plugins.installs.qqbot - if (config.plugins?.installs?.qqbot) { - delete config.plugins.installs.qqbot; - console.log(' - 已删除 plugins.installs.qqbot'); + // 删除 plugins.installs. + if (config.plugins?.installs?.[id]) { + delete config.plugins.installs[id]; + console.log(` - 已删除 plugins.installs.${id}`); + } } writeFileSync(configFile, JSON.stringify(config, null, 2)); diff --git a/docs/commands.md b/docs/commands.md index 7c0d074..2dfdb5e 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -138,16 +138,16 @@ openclaw config ### 一键升级并启动 ```bash # 基本用法 -./upgrade-and-run.sh +./scripts/upgrade-and-run.sh # 指定 AppID 和 Secret -./upgrade-and-run.sh --appid 123456789 --secret your_secret +./scripts/upgrade-and-run.sh --appid 123456789 --secret your_secret # 同时启用 Markdown -./upgrade-and-run.sh --appid 123456789 --secret your_secret --markdown yes +./scripts/upgrade-and-run.sh --appid 123456789 --secret your_secret --markdown yes # 查看帮助 -./upgrade-and-run.sh --help +./scripts/upgrade-and-run.sh --help ``` **环境变量方式:** @@ -155,22 +155,22 @@ openclaw config export QQBOT_APPID="123456789" export QQBOT_SECRET="your_secret" export QQBOT_MARKDOWN="no" -./upgrade-and-run.sh +./scripts/upgrade-and-run.sh ``` ### Markdown 设置脚本 ```bash # 启用 Markdown -./set-markdown.sh enable +./scripts/set-markdown.sh enable # 禁用 Markdown -./set-markdown.sh disable +./scripts/set-markdown.sh disable # 查看当前状态 -./set-markdown.sh status +./scripts/set-markdown.sh status # 交互式选择 -./set-markdown.sh +./scripts/set-markdown.sh ``` ### 升级脚本(清理旧版本) diff --git a/package.json b/package.json index 7a65a63..6491539 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "bin", "src", "skills", + "scripts", "index.ts", "tsconfig.json", "openclaw.plugin.json", diff --git a/pull-latest.sh b/pull-latest.sh deleted file mode 100755 index 38b7d06..0000000 --- a/pull-latest.sh +++ /dev/null @@ -1,310 +0,0 @@ -#!/bin/bash - -# QQBot 拉取最新源码并更新 -# 从 GitHub 拉取最新代码,安装依赖并重启网关 -# 兼容 clawdbot / openclaw / moltbot,macOS 开箱即用 -# -# 用法: -# pull-latest.sh # 拉取最新代码并更新 -# pull-latest.sh --branch main # 指定分支(默认 main) -# pull-latest.sh --force # 跳过交互,强制更新 -# pull-latest.sh --repo # 指定仓库地址 - -set -euo pipefail - -############################################################################## -# 常量 & 参数 -############################################################################## -readonly DEFAULT_REPO="https://github.com/tencent-connect/openclaw-qq.git" -readonly GATEWAY_PORT=18789 -readonly SUPPORTED_CLIS=(openclaw clawdbot moltbot) - -FORCE=false -BRANCH="main" -REPO_URL="" - -while [[ $# -gt 0 ]]; do - case "$1" in - -f|--force) FORCE=true; shift ;; - -b|--branch) BRANCH="$2"; shift 2 ;; - --repo) REPO_URL="$2"; shift 2 ;; - -h|--help) - echo "QQBot 拉取最新源码并更新" - echo "" - echo "用法:" - echo " pull-latest.sh # 拉取最新代码并更新" - echo " pull-latest.sh --branch main # 指定分支(默认 main)" - echo " pull-latest.sh --force # 跳过交互,强制更新" - echo " pull-latest.sh --repo # 指定仓库地址" - exit 0 - ;; - *) - echo "未知选项: $1 (使用 --help 查看帮助)" - exit 1 - ;; - esac -done -REPO_URL="${REPO_URL:-$DEFAULT_REPO}" - -############################################################################## -# 工具函数 -############################################################################## -json_get() { - local file="$1" expr="$2" - node -e "process.stdout.write(String((function(){$expr})(JSON.parse(require('fs').readFileSync('$file','utf8')))||''))" 2>/dev/null || true -} - -############################################################################## -# 环境检查 -############################################################################## -printf "%b\n" "\033[32m=========================================\033[0m" -printf "%b\n" "\033[32m QQBot 拉取最新源码并更新\033[0m" -printf "%b\n" "\033[32m=========================================\033[0m" -echo "" - -# 检查必要命令 -for dep in node npm git; do - if ! command -v "$dep" &>/dev/null; then - printf "%b\n" "\033[31m❌ 未检测到 $dep,请先安装\033[0m" - exit 1 - fi -done - -printf "%b\n" "\033[34m系统信息:\033[0m" -echo " macOS $(sw_vers -productVersion 2>/dev/null || echo '未知')" -echo " Node $(node -v)" -echo " npm $(npm -v)" -echo " Git $(git --version 2>/dev/null | awk '{print $3}')" -echo " 仓库 $REPO_URL" -echo " 分支 $BRANCH" - -# 检测 CLI -CMD="" -for name in "${SUPPORTED_CLIS[@]}"; do - if command -v "$name" &>/dev/null; then - CMD="$name" - break - fi -done -if [ -z "$CMD" ]; then - printf "%b\n" "\033[31m❌ 未找到 openclaw / clawdbot / moltbot 命令,请先安装其中之一\033[0m" - exit 1 -fi -echo " CLI $CMD ($($CMD --version 2>/dev/null || echo '未知版本'))" - -APP_HOME="$HOME/.$CMD" -APP_CONFIG="$APP_HOME/$CMD.json" - -############################################################################## -# 定位插件目录 -############################################################################## -PROJ_DIR="" -FRESH_INSTALL=false - -for app in "${SUPPORTED_CLIS[@]}"; do - ext_dir="$HOME/.$app/extensions/qqbot" - if [ -d "$ext_dir" ] && [ -f "$ext_dir/package.json" ]; then - PROJ_DIR="$ext_dir" - break - fi -done - -if [ -z "$PROJ_DIR" ]; then - PROJ_DIR="$APP_HOME/extensions/qqbot" - FRESH_INSTALL=true - echo " 插件 未安装(首次安装)" -else - echo " 插件 $PROJ_DIR" -fi - -############################################################################## -# 第一步:获取当前版本 -############################################################################## -echo "" -printf "%b\n" "\033[34m1. 获取当前版本...\033[0m" - -LOCAL_VER="" -LOCAL_COMMIT="" -if [ "$FRESH_INSTALL" = true ]; then - echo " 首次安装,无本地版本" -else - [ -f "$PROJ_DIR/package.json" ] && LOCAL_VER=$(json_get "$PROJ_DIR/package.json" "c => c.version") - [ -d "$PROJ_DIR/.git" ] && LOCAL_COMMIT=$(cd "$PROJ_DIR" && git rev-parse --short HEAD 2>/dev/null || echo "") - echo " 当前版本: ${LOCAL_VER:-未知}${LOCAL_COMMIT:+ (${LOCAL_COMMIT})}" -fi - -############################################################################## -# 第二步:备份通道配置 -############################################################################## -echo "" -printf "%b\n" "\033[34m2. 备份通道配置...\033[0m" - -SAVED_CHANNELS_JSON="" -for app in "${SUPPORTED_CLIS[@]}"; do - cfg="$HOME/.$app/$app.json" - [ -f "$cfg" ] || continue - SAVED_CHANNELS_JSON=$(node -e " - const cfg = JSON.parse(require('fs').readFileSync('$cfg', 'utf8')); - const ch = cfg.channels && cfg.channels.qqbot; - if (ch) process.stdout.write(JSON.stringify(ch)); - " 2>/dev/null || true) - [ -n "$SAVED_CHANNELS_JSON" ] && break -done - -if [ -n "$SAVED_CHANNELS_JSON" ]; then - echo " ✅ 已备份 qqbot 通道配置" -else - echo " ℹ️ 未找到已有通道配置" -fi - -############################################################################## -# 第三步:拉取最新代码 -############################################################################## -echo "" -printf "%b\n" "\033[34m3. 拉取最新代码...\033[0m" - -TMP_DIR="${TMPDIR:-/tmp}/qqbot-update-$$" -cleanup() { rm -rf "$TMP_DIR" 2>/dev/null; } -trap cleanup EXIT INT TERM - -if [ -d "$PROJ_DIR/.git" ] && [ "$FRESH_INSTALL" = false ]; then - cd "$PROJ_DIR" - - # 有本地修改直接重置,插件目录不需要保留用户改动 - if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then - echo " 检测到本地修改,自动重置..." - git checkout -- . 2>/dev/null - git clean -fd 2>/dev/null - fi - - echo " 切换到分支 $BRANCH..." - git fetch --all --prune 2>&1 | tail -3 - git checkout "$BRANCH" 2>/dev/null || git checkout -b "$BRANCH" "origin/$BRANCH" 2>/dev/null || true - git reset --hard "origin/$BRANCH" 2>/dev/null - - REMOTE_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "") - NEW_VER=$(json_get "$PROJ_DIR/package.json" "c => c.version") - - if [ -n "$LOCAL_COMMIT" ] && [ "$LOCAL_COMMIT" = "$REMOTE_COMMIT" ]; then - echo " ✅ 已是最新 ($LOCAL_VER, commit: $LOCAL_COMMIT),继续检查依赖..." - else - echo " 更新: ${LOCAL_COMMIT:-???} → ${REMOTE_COMMIT}" - git --no-pager log --oneline "${LOCAL_COMMIT}..HEAD" 2>/dev/null | head -10 || true - fi -else - rm -rf "$TMP_DIR" - echo " 克隆仓库..." - if ! git clone --branch "$BRANCH" --depth 1 "$REPO_URL" "$TMP_DIR" 2>&1 | tail -3; then - printf "%b\n" "\033[31m❌ Git clone 失败\033[0m" - echo "" - echo "请排查:" - echo " 1. 检查网络: curl -I https://github.com" - echo " 2. 检查仓库地址: $REPO_URL" - echo " 3. 如果是私有仓库,确认已配置 SSH key 或 token" - exit 1 - fi - - mkdir -p "$PROJ_DIR" - rsync -a --delete --exclude 'node_modules' "$TMP_DIR/" "$PROJ_DIR/" - - cd "$PROJ_DIR" - REMOTE_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "") - NEW_VER=$(json_get "$PROJ_DIR/package.json" "c => c.version") - echo " 已克隆到版本: ${NEW_VER:-未知} (${REMOTE_COMMIT})" - cleanup -fi - -NEW_VER="${NEW_VER:-未知}" -printf "%b\n" "\033[32m ✅ 代码已更新到 $NEW_VER\033[0m" - -############################################################################## -# 第四步:安装依赖 -############################################################################## -echo "" -printf "%b\n" "\033[34m4. 安装依赖...\033[0m" - -cd "$PROJ_DIR" -if ! npm install --omit=dev 2>&1 | tail -5; then - printf "%b\n" "\033[31m❌ npm 依赖安装失败\033[0m" - echo "" - echo "请排查:" - echo " 1. 手动重试: cd $PROJ_DIR && npm install --omit=dev" - echo " 2. 清理后重试: rm -rf $PROJ_DIR/node_modules && npm install --omit=dev" - echo " 3. 切换镜像: npm config set registry https://registry.npmmirror.com/" - exit 1 -fi -echo " ✅ 依赖安装完成" - -############################################################################## -# 第五步:恢复配置 → 重启网关 -############################################################################## -echo "" -printf "%b\n" "\033[34m5. 恢复配置并重启网关...\033[0m" - -# 恢复通道配置 -if [ -n "$SAVED_CHANNELS_JSON" ]; then - if node -e " - const fs = require('fs'); - const cfg = JSON.parse(fs.readFileSync('$APP_CONFIG', 'utf8')); - cfg.channels = cfg.channels || {}; - cfg.channels.qqbot = $SAVED_CHANNELS_JSON; - fs.writeFileSync('$APP_CONFIG', JSON.stringify(cfg, null, 4) + '\n'); - " 2>/dev/null; then - echo " ✅ 通道配置已恢复" - else - printf "%b\n" "\033[33m ⚠️ 通道配置写入失败,请手动检查: $APP_CONFIG\033[0m" - fi -elif [ "$FRESH_INSTALL" = true ]; then - echo "" - printf "%b\n" "\033[33m ⚠️ 首次安装,请配置 QQ Bot 凭据:\033[0m" - echo " $CMD channels add --channel qqbot --token 'YOUR_APPID:YOUR_SECRET'" - echo "" -fi - -# 停止旧 gateway -echo " 停止旧网关..." -$CMD gateway stop 2>/dev/null || true -sleep 1 - -# 强制杀占用端口的进程 -PORT_PID=$(lsof -ti:"$GATEWAY_PORT" 2>/dev/null || true) -if [ -n "$PORT_PID" ]; then - printf "%b\n" "\033[33m ⚠️ 端口 $GATEWAY_PORT 仍被占用 (PID: $PORT_PID),强制终止...\033[0m" - kill -9 $PORT_PID 2>/dev/null || true - sleep 1 -fi - -# 卸载 launchd 服务(防止自动拉起旧进程) -for svc in ai.openclaw.gateway ai.clawdbot.gateway ai.moltbot.gateway; do - launchctl bootout "gui/$(id -u)/$svc" 2>/dev/null || true -done - -# 启动网关 -echo " 启动网关..." -if $CMD gateway 2>&1; then - printf "%b\n" "\033[32m ✅ 网关已启动\033[0m" -else - echo "" - printf "%b\n" "\033[33m ⚠️ 网关启动失败(不影响已安装的插件)\033[0m" - echo "" - echo " 请手动启动:" - echo " 1. 安装服务: $CMD gateway install" - echo " 2. 启动网关: $CMD gateway" - echo " 3. 查看日志: $CMD logs --follow" -fi - -############################################################################## -# 完成 -############################################################################## -echo "" -printf "%b\n" "\033[32m=========================================\033[0m" -printf "%b\n" "\033[32m ✅ QQBot 已更新到 ${NEW_VER}${REMOTE_COMMIT:+ (${REMOTE_COMMIT})}\033[0m" -[ -n "$LOCAL_VER" ] && printf "%b\n" "\033[32m (从 ${LOCAL_VER}${LOCAL_COMMIT:+ (${LOCAL_COMMIT})} 升级)\033[0m" -printf "%b\n" "\033[32m=========================================\033[0m" -echo "" -echo "常用命令:" -echo " $CMD logs --follow # 跟踪日志" -echo " $CMD gateway restart # 重启服务" -echo " $CMD plugins list # 查看插件列表" -echo " cd $PROJ_DIR && git log # 查看更新历史" -echo "=========================================" diff --git a/scripts/pull-latest.sh b/scripts/pull-latest.sh index 9775382..759d15f 100755 --- a/scripts/pull-latest.sh +++ b/scripts/pull-latest.sh @@ -1,336 +1,316 @@ #!/bin/bash -# QQBot 拉取最新 npm 包并更新脚本 -# 从 npm 下载 @tencent-connect/openclaw-qq@latest,解压覆盖本地源码,重新安装插件并重启 +# QQBot 拉取最新源码并更新 +# 从 GitHub 拉取最新代码,安装依赖并重启网关 # 兼容 clawdbot / openclaw / moltbot,macOS 开箱即用 # # 用法: -# ./scripts/pull-latest.sh # 更新到最新版 -# ./scripts/pull-latest.sh @tencent-connect/openclaw-qq@1.5.2 # 更新到指定版本 -# ./scripts/pull-latest.sh --force # 跳过交互,强制重新安装 -# ./scripts/pull-latest.sh --force @tencent-connect/openclaw-qq@1.5.3 +# pull-latest.sh # 拉取最新代码并更新 +# pull-latest.sh --branch main # 指定分支(默认 main) +# pull-latest.sh --force # 跳过交互,强制更新 +# pull-latest.sh --repo # 指定仓库地址 -set -e +set -euo pipefail + +############################################################################## +# 常量 & 参数 +############################################################################## +readonly DEFAULT_REPO="https://github.com/tencent-connect/openclaw-qq.git" +readonly GATEWAY_PORT=18789 +readonly SUPPORTED_CLIS=(openclaw clawdbot moltbot) -# ============================================================ -# 参数解析 -# ============================================================ FORCE=false -PKG_NAME="@tencent-connect/openclaw-qq" -PKG_SPEC="" +BRANCH="main" +REPO_URL="" -for arg in "$@"; do - case "$arg" in - -f|--force) FORCE=true ;; - *) PKG_SPEC="$arg" ;; +while [[ $# -gt 0 ]]; do + case "$1" in + -f|--force) FORCE=true; shift ;; + -b|--branch) BRANCH="$2"; shift 2 ;; + --repo) REPO_URL="$2"; shift 2 ;; + -h|--help) + echo "QQBot 拉取最新源码并更新" + echo "" + echo "用法:" + echo " pull-latest.sh # 拉取最新代码并更新" + echo " pull-latest.sh --branch main # 指定分支(默认 main)" + echo " pull-latest.sh --force # 跳过交互,强制更新" + echo " pull-latest.sh --repo # 指定仓库地址" + exit 0 + ;; + *) + echo "未知选项: $1 (使用 --help 查看帮助)" + exit 1 + ;; esac done -PKG_SPEC="${PKG_SPEC:-${PKG_NAME}@latest}" +REPO_URL="${REPO_URL:-$DEFAULT_REPO}" -# ============================================================ -# 定位项目目录(兼容从任意位置执行) -# ============================================================ -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -# 如果脚本在 scripts/ 子目录里,往上一级就是项目根目录 -if [ "$(basename "$SCRIPT_DIR")" = "scripts" ]; then - PROJ_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -else - PROJ_DIR="$SCRIPT_DIR" -fi -cd "$PROJ_DIR" - -# ============================================================ -# 前置依赖检查 -# ============================================================ -check_cmd() { - if ! command -v "$1" &>/dev/null; then - echo "❌ 缺少必要命令: $1" - echo " $2" - exit 1 - fi +############################################################################## +# 工具函数 +############################################################################## +json_get() { + local file="$1" expr="$2" + node -e "process.stdout.write(String((function(){$expr})(JSON.parse(require('fs').readFileSync('$file','utf8')))||''))" 2>/dev/null || true } -check_cmd node "请先安装 Node.js: https://nodejs.org/ 或 brew install node" -check_cmd npm "npm 通常随 Node.js 一起安装" -check_cmd tar "macOS 自带 tar,如果缺失请检查系统完整性" - -echo "=========================================" -echo " QQBot 拉取最新版本并更新" -echo "=========================================" +############################################################################## +# 环境检查 +############################################################################## +printf "%b\n" "\033[32m=========================================\033[0m" +printf "%b\n" "\033[32m QQBot 拉取最新源码并更新\033[0m" +printf "%b\n" "\033[32m=========================================\033[0m" echo "" -echo "系统信息:" -echo " macOS $(sw_vers -productVersion 2>/dev/null || echo '未知')" -echo " Node $(node -v 2>/dev/null)" -echo " npm $(npm -v 2>/dev/null)" -# ============================================================ -# 0. 检测 openclaw / clawdbot / moltbot -# ============================================================ +# 检查必要命令 +for dep in node npm git; do + if ! command -v "$dep" &>/dev/null; then + printf "%b\n" "\033[31m❌ 未检测到 $dep,请先安装\033[0m" + exit 1 + fi +done + +printf "%b\n" "\033[34m系统信息:\033[0m" +echo " macOS $(sw_vers -productVersion 2>/dev/null || echo '未知')" +echo " Node $(node -v)" +echo " npm $(npm -v)" +echo " Git $(git --version 2>/dev/null | awk '{print $3}')" +echo " 仓库 $REPO_URL" +echo " 分支 $BRANCH" + +# 检测 CLI CMD="" -for name in openclaw clawdbot moltbot; do +for name in "${SUPPORTED_CLIS[@]}"; do if command -v "$name" &>/dev/null; then CMD="$name" break fi done if [ -z "$CMD" ]; then - echo "" - echo "❌ 未找到 openclaw / clawdbot / moltbot 命令" - echo " 请先安装其中之一,参考: https://docs.openclaw.ai" + printf "%b\n" "\033[31m❌ 未找到 openclaw / clawdbot / moltbot 命令,请先安装其中之一\033[0m" exit 1 fi -echo " CLI $CMD ($($CMD --version 2>/dev/null || echo '未知版本'))" +echo " CLI $CMD ($($CMD --version 2>/dev/null || echo '未知版本'))" -# ============================================================ -# 1. 获取当前本地版本 -# ============================================================ -LOCAL_VER="" -if [ -f "$PROJ_DIR/package.json" ]; then - LOCAL_VER=$(node -e "process.stdout.write(JSON.parse(require('fs').readFileSync('$PROJ_DIR/package.json','utf8')).version||'')" 2>/dev/null || true) -fi -echo "" -echo "[1/5] 当前本地版本: ${LOCAL_VER:-未知}" +APP_HOME="$HOME/.$CMD" +APP_CONFIG="$APP_HOME/$CMD.json" -# ============================================================ -# 2. 查询 npm 远程版本 -# ============================================================ -echo "" -echo "[2/5] 查询 npm 版本..." +############################################################################## +# 定位插件目录 +############################################################################## +PROJ_DIR="" +FRESH_INSTALL=false -# 如果指定了具体版本号,直接从 PKG_SPEC 提取;否则查询 latest -if echo "$PKG_SPEC" | grep -qE '@[0-9]+\.[0-9]+'; then - REMOTE_VER=$(echo "$PKG_SPEC" | sed 's/.*@//') -else - REMOTE_VER=$(npm view "$PKG_NAME" version 2>/dev/null || echo "") -fi - -if [ -z "$REMOTE_VER" ]; then - echo "❌ 无法查询 $PKG_NAME 的版本,请检查网络" - echo " 当前 npm 源: $(npm config get registry 2>/dev/null)" - echo "" - echo " 可尝试切换镜像源:" - echo " npm config set registry https://registry.npmmirror.com/" - exit 1 -fi -echo "目标版本: ${REMOTE_VER}" - -if [ "$LOCAL_VER" = "$REMOTE_VER" ]; then - echo "" - echo "✅ 本地版本已是最新 ($LOCAL_VER)" - if [ "$FORCE" = true ]; then - echo "已指定 --force,继续重新安装..." - else - printf "是否强制重新安装? (y/N): " - read -r force_choice /dev/null || force_choice="N" - case "$force_choice" in - [Yy]* ) echo "强制重新安装..." ;; - * ) echo "跳过更新。"; exit 0 ;; - esac - fi -fi - -# ============================================================ -# 3. 备份通道配置 -# ============================================================ -echo "" -echo "[3/5] 备份已有通道配置..." - -SAVED_QQBOT_TOKEN="" -SAVED_MARKDOWN="" - -for APP_NAME in openclaw clawdbot moltbot; do - CONFIG_FILE="$HOME/.$APP_NAME/$APP_NAME.json" - [ -f "$CONFIG_FILE" ] || continue - - if [ -z "$SAVED_QQBOT_TOKEN" ]; then - SAVED_QQBOT_TOKEN=$(node -e " - const cfg = JSON.parse(require('fs').readFileSync('$CONFIG_FILE', 'utf8')); - const ch = cfg.channels && cfg.channels.qqbot; - if (!ch) process.exit(0); - if (ch.token) { process.stdout.write(ch.token); process.exit(0); } - if (ch.appId && ch.clientSecret) { process.stdout.write(ch.appId + ':' + ch.clientSecret); process.exit(0); } - " 2>/dev/null || true) - fi - - if [ -z "$SAVED_MARKDOWN" ]; then - SAVED_MARKDOWN=$(node -e " - const cfg = JSON.parse(require('fs').readFileSync('$CONFIG_FILE', 'utf8')); - const v = (cfg.channels && cfg.channels.qqbot && cfg.channels.qqbot.markdownSupport); - if (v !== undefined && v !== null) process.stdout.write(String(v)); - " 2>/dev/null || true) - fi - - [ -n "$SAVED_QQBOT_TOKEN" ] && [ -n "$SAVED_MARKDOWN" ] && break +for app in "${SUPPORTED_CLIS[@]}"; do + for plugin_dir in qqbot openclaw-qq; do + ext_dir="$HOME/.$app/extensions/$plugin_dir" + if [ -d "$ext_dir" ] && [ -f "$ext_dir/package.json" ]; then + PROJ_DIR="$ext_dir" + break 2 + fi + done done -if [ -n "$SAVED_QQBOT_TOKEN" ]; then - echo "已备份 qqbot 通道 token: ${SAVED_QQBOT_TOKEN:0:10}..." +if [ -z "$PROJ_DIR" ]; then + PROJ_DIR="$APP_HOME/extensions/qqbot" + FRESH_INSTALL=true + echo " 插件 未安装(首次安装)" else - echo "未找到已有通道配置(首次安装或已清理)" + echo " 插件 $PROJ_DIR" fi -# ============================================================ -# 4. 下载并解压最新包 -# ============================================================ +############################################################################## +# 第一步:获取当前版本 +############################################################################## echo "" -echo "[4/5] 下载 $PKG_SPEC 并更新本地文件..." +printf "%b\n" "\033[34m1. 获取当前版本...\033[0m" -TMP_DIR="$PROJ_DIR/.qqbot-update-tmp" +LOCAL_VER="" +LOCAL_COMMIT="" +if [ "$FRESH_INSTALL" = true ]; then + echo " 首次安装,无本地版本" +else + [ -f "$PROJ_DIR/package.json" ] && LOCAL_VER=$(json_get "$PROJ_DIR/package.json" "c => c.version") + [ -d "$PROJ_DIR/.git" ] && LOCAL_COMMIT=$(cd "$PROJ_DIR" && git rev-parse --short HEAD 2>/dev/null || echo "") + echo " 当前版本: ${LOCAL_VER:-未知}${LOCAL_COMMIT:+ (${LOCAL_COMMIT})}" +fi -# 清理函数:删除临时文件夹 -cleanup() { - if [ -d "$TMP_DIR" ]; then - echo "清理临时文件夹: $TMP_DIR" - rm -rf "$TMP_DIR" - fi -} -# 正常退出、中断、终止时都清理 +############################################################################## +# 第二步:备份通道配置 +############################################################################## +echo "" +printf "%b\n" "\033[34m2. 备份通道配置...\033[0m" + +SAVED_CHANNELS_JSON="" +for app in "${SUPPORTED_CLIS[@]}"; do + cfg="$HOME/.$app/$app.json" + [ -f "$cfg" ] || continue + SAVED_CHANNELS_JSON=$(node -e " + const cfg = JSON.parse(require('fs').readFileSync('$cfg', 'utf8')); + // 尝试所有可能的 channel key(原仓库 + 本仓库) + const keys = ['qqbot', 'openclaw-qq']; + for (const key of keys) { + const ch = cfg.channels && cfg.channels[key]; + if (ch) { process.stdout.write(JSON.stringify(ch)); process.exit(0); } + } + " 2>/dev/null || true) + [ -n "$SAVED_CHANNELS_JSON" ] && break +done + +if [ -n "$SAVED_CHANNELS_JSON" ]; then + echo " ✅ 已备份 qqbot 通道配置" +else + echo " ℹ️ 未找到已有通道配置" +fi + +############################################################################## +# 第三步:拉取最新代码 +############################################################################## +echo "" +printf "%b\n" "\033[34m3. 拉取最新代码...\033[0m" + +TMP_DIR="${TMPDIR:-/tmp}/qqbot-update-$$" +cleanup() { rm -rf "$TMP_DIR" 2>/dev/null; } trap cleanup EXIT INT TERM -# 如果上次意外残留,先清理 -[ -d "$TMP_DIR" ] && rm -rf "$TMP_DIR" -mkdir -p "$TMP_DIR" +if [ -d "$PROJ_DIR/.git" ] && [ "$FRESH_INSTALL" = false ]; then + cd "$PROJ_DIR" -echo "下载中..." -TARBALL=$(cd "$TMP_DIR" && npm pack "$PKG_SPEC" 2>/dev/null) -if [ -z "$TARBALL" ] || [ ! -f "$TMP_DIR/$TARBALL" ]; then - echo "❌ 下载失败" - echo " 请检查网络连接,或尝试:" - echo " npm pack $PKG_SPEC" - exit 1 -fi -echo "已下载: $TARBALL" - -echo "解压中..." -tar xzf "$TMP_DIR/$TARBALL" -C "$TMP_DIR" - -PACK_DIR="$TMP_DIR/package" -if [ ! -d "$PACK_DIR" ]; then - echo "❌ 解压后未找到 package 目录" - exit 1 -fi - -NEW_VER=$(node -e "process.stdout.write(JSON.parse(require('fs').readFileSync('$PACK_DIR/package.json','utf8')).version||'')" 2>/dev/null || echo "$REMOTE_VER") -echo "将更新到版本: $NEW_VER" - -# 同步文件(不用 rsync,用 tar + cp 保证 macOS 原生兼容) -echo "同步文件到本地..." - -# 把包中所有文件复制过来,跳过不该覆盖的目录 -( - cd "$PACK_DIR" - find . -type f | while IFS= read -r f; do - case "$f" in - ./.DS_Store|./.git/*|./node_modules/*) continue ;; - esac - dir=$(dirname "$f") - mkdir -p "$PROJ_DIR/$dir" - cp -f "$f" "$PROJ_DIR/$f" - done -) - -echo "✅ 文件已更新到 $NEW_VER" - -# 删除临时文件夹(不等到 EXIT,立即清理) -echo "删除临时文件夹..." -rm -rf "$TMP_DIR" - -echo "安装依赖..." -cd "$PROJ_DIR" -npm install --omit=dev 2>&1 | tail -5 - -# ============================================================ -# 5. 卸载旧插件、安装新插件、恢复配置、重启 -# ============================================================ -echo "" -echo "[5/5] 重新安装插件并重启..." - -# 清理旧版本(配置 + 扩展目录) -if [ -f "$PROJ_DIR/scripts/upgrade.sh" ]; then - echo "清理旧版本插件..." - bash "$PROJ_DIR/scripts/upgrade.sh" -fi - -# 强制删除已有扩展目录,防止 "plugin already exists" 错误 -for APP_NAME in openclaw clawdbot moltbot; do - EXT_DIR="$HOME/.$APP_NAME/extensions/qqbot" - if [ -d "$EXT_DIR" ]; then - echo "删除已有扩展目录: $EXT_DIR" - rm -rf "$EXT_DIR" + # 有本地修改直接重置,插件目录不需要保留用户改动 + if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then + echo " 检测到本地修改,自动重置..." + git checkout -- . 2>/dev/null + git clean -fd 2>/dev/null fi -done -# 安装插件 + echo " 切换到分支 $BRANCH..." + git fetch --all --prune 2>&1 | tail -3 + git checkout "$BRANCH" 2>/dev/null || git checkout -b "$BRANCH" "origin/$BRANCH" 2>/dev/null || true + git reset --hard "origin/$BRANCH" 2>/dev/null + + REMOTE_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "") + NEW_VER=$(json_get "$PROJ_DIR/package.json" "c => c.version") + + if [ -n "$LOCAL_COMMIT" ] && [ "$LOCAL_COMMIT" = "$REMOTE_COMMIT" ]; then + echo " ✅ 已是最新 ($LOCAL_VER, commit: $LOCAL_COMMIT),继续检查依赖..." + else + echo " 更新: ${LOCAL_COMMIT:-???} → ${REMOTE_COMMIT}" + git --no-pager log --oneline "${LOCAL_COMMIT}..HEAD" 2>/dev/null | head -10 || true + fi +else + rm -rf "$TMP_DIR" + echo " 克隆仓库..." + if ! git clone --branch "$BRANCH" --depth 1 "$REPO_URL" "$TMP_DIR" 2>&1 | tail -3; then + printf "%b\n" "\033[31m❌ Git clone 失败\033[0m" + echo "" + echo "请排查:" + echo " 1. 检查网络: curl -I https://github.com" + echo " 2. 检查仓库地址: $REPO_URL" + echo " 3. 如果是私有仓库,确认已配置 SSH key 或 token" + exit 1 + fi + + mkdir -p "$PROJ_DIR" + rsync -a --delete --exclude 'node_modules' "$TMP_DIR/" "$PROJ_DIR/" + + cd "$PROJ_DIR" + REMOTE_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "") + NEW_VER=$(json_get "$PROJ_DIR/package.json" "c => c.version") + echo " 已克隆到版本: ${NEW_VER:-未知} (${REMOTE_COMMIT})" + cleanup +fi + +NEW_VER="${NEW_VER:-未知}" +printf "%b\n" "\033[32m ✅ 代码已更新到 $NEW_VER\033[0m" + +############################################################################## +# 第四步:安装依赖 +############################################################################## echo "" -echo "安装新版本插件..." -if ! $CMD plugins install . 2>&1; then - echo "❌ 插件安装失败,请检查上方错误信息" +printf "%b\n" "\033[34m4. 安装依赖...\033[0m" + +cd "$PROJ_DIR" +if ! npm install --omit=dev 2>&1 | tail -5; then + printf "%b\n" "\033[31m❌ npm 依赖安装失败\033[0m" + echo "" + echo "请排查:" + echo " 1. 手动重试: cd $PROJ_DIR && npm install --omit=dev" + echo " 2. 清理后重试: rm -rf $PROJ_DIR/node_modules && npm install --omit=dev" + echo " 3. 切换镜像: npm config set registry https://registry.npmmirror.com/" exit 1 fi -echo "✅ 插件安装成功" +echo " ✅ 依赖安装完成" + +############################################################################## +# 第五步:恢复配置 → 重启网关 +############################################################################## +echo "" +printf "%b\n" "\033[34m5. 恢复配置并重启网关...\033[0m" # 恢复通道配置 -if [ -n "$SAVED_QQBOT_TOKEN" ]; then - echo "" - echo "恢复 qqbot 通道配置..." - $CMD channels add --channel qqbot --token "$SAVED_QQBOT_TOKEN" 2>&1 || true -fi - -# 恢复 markdown 配置 -if [ "$SAVED_MARKDOWN" = "true" ]; then - echo "恢复 Markdown 配置 (已启用)..." - APP_CONFIG="$HOME/.$CMD/$CMD.json" - if [ -f "$APP_CONFIG" ]; then - node -e " - var fs = require('fs'); - var cfg = JSON.parse(fs.readFileSync('$APP_CONFIG', 'utf-8')); - if (!cfg.channels) cfg.channels = {}; - if (!cfg.channels.qqbot) cfg.channels.qqbot = {}; - cfg.channels.qqbot.markdownSupport = true; - fs.writeFileSync('$APP_CONFIG', JSON.stringify(cfg, null, 4) + '\n'); - " 2>/dev/null && echo "✅ Markdown 配置已恢复" || echo "⚠️ Markdown 配置恢复失败" +if [ -n "$SAVED_CHANNELS_JSON" ]; then + if node -e " + const fs = require('fs'); + const cfg = JSON.parse(fs.readFileSync('$APP_CONFIG', 'utf8')); + cfg.channels = cfg.channels || {}; + cfg.channels.qqbot = $SAVED_CHANNELS_JSON; + fs.writeFileSync('$APP_CONFIG', JSON.stringify(cfg, null, 4) + '\n'); + " 2>/dev/null; then + echo " ✅ 通道配置已恢复" + else + printf "%b\n" "\033[33m ⚠️ 通道配置写入失败,请手动检查: $APP_CONFIG\033[0m" fi +elif [ "$FRESH_INSTALL" = true ]; then + echo "" + printf "%b\n" "\033[33m ⚠️ 首次安装,请配置 QQ Bot 凭据:\033[0m" + echo " $CMD channels add --channel qqbot --token 'YOUR_APPID:YOUR_SECRET'" + echo "" fi -# 重启网关(先确保旧进程停掉,避免无限重启循环) -echo "" -echo "重启网关服务..." - -# 先尝试正常停止 +# 停止旧 gateway +echo " 停止旧网关..." $CMD gateway stop 2>/dev/null || true sleep 1 -# 如果端口还被占用,强制杀进程 -PORT_PID=$(lsof -ti:18789 2>/dev/null || true) +# 强制杀占用端口的进程 +PORT_PID=$(lsof -ti:"$GATEWAY_PORT" 2>/dev/null || true) if [ -n "$PORT_PID" ]; then - echo "端口 18789 仍被占用 (pid: $PORT_PID),强制终止..." + printf "%b\n" "\033[33m ⚠️ 端口 $GATEWAY_PORT 仍被占用 (PID: $PORT_PID),强制终止...\033[0m" kill -9 $PORT_PID 2>/dev/null || true sleep 1 fi # 卸载 launchd 服务(防止自动拉起旧进程) -for SVC_NAME in ai.openclaw.gateway ai.clawdbot.gateway ai.moltbot.gateway; do - launchctl bootout "gui/$(id -u)/$SVC_NAME" 2>/dev/null || true +for svc in ai.openclaw.gateway ai.clawdbot.gateway ai.moltbot.gateway; do + launchctl bootout "gui/$(id -u)/$svc" 2>/dev/null || true done -# 启动新的 gateway +# 启动网关 +echo " 启动网关..." if $CMD gateway 2>&1; then - echo "" - echo "✅ 网关已启动" - echo "查看日志: $CMD gateway log" + printf "%b\n" "\033[32m ✅ 网关已启动\033[0m" else echo "" - echo "⚠️ 网关启动失败,尝试手动启动:" - echo " $CMD gateway install && $CMD gateway" + printf "%b\n" "\033[33m ⚠️ 网关启动失败(不影响已安装的插件)\033[0m" + echo "" + echo " 请手动启动:" + echo " 1. 安装服务: $CMD gateway install" + echo " 2. 启动网关: $CMD gateway" + echo " 3. 查看日志: $CMD logs --follow" fi +############################################################################## +# 完成 +############################################################################## echo "" -echo "=========================================" -echo " ✅ QQBot 已从 ${LOCAL_VER:-未知} 更新到 ${NEW_VER}" -echo "=========================================" +printf "%b\n" "\033[32m=========================================\033[0m" +printf "%b\n" "\033[32m ✅ QQBot 已更新到 ${NEW_VER}${REMOTE_COMMIT:+ (${REMOTE_COMMIT})}\033[0m" +[ -n "$LOCAL_VER" ] && printf "%b\n" "\033[32m (从 ${LOCAL_VER}${LOCAL_COMMIT:+ (${LOCAL_COMMIT})} 升级)\033[0m" +printf "%b\n" "\033[32m=========================================\033[0m" echo "" echo "常用命令:" -echo " $CMD gateway log # 查看日志" +echo " $CMD logs --follow # 跟踪日志" echo " $CMD gateway restart # 重启服务" echo " $CMD plugins list # 查看插件列表" +echo " cd $PROJ_DIR && git log # 查看更新历史" echo "=========================================" diff --git a/set-markdown.sh b/scripts/set-markdown.sh similarity index 100% rename from set-markdown.sh rename to scripts/set-markdown.sh diff --git a/upgrade-and-run.sh b/scripts/upgrade-and-run.sh similarity index 93% rename from upgrade-and-run.sh rename to scripts/upgrade-and-run.sh index 3e6fbc3..e1337e6 100755 --- a/upgrade-and-run.sh +++ b/scripts/upgrade-and-run.sh @@ -13,7 +13,13 @@ set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -cd "$SCRIPT_DIR" +# 如果脚本在 scripts/ 子目录里,往上一级就是项目根目录 +if [ "$(basename "$SCRIPT_DIR")" = "scripts" ]; then + PROJ_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +else + PROJ_DIR="$SCRIPT_DIR" +fi +cd "$PROJ_DIR" # 解析命令行参数 APPID="" @@ -75,17 +81,19 @@ echo "=========================================" echo "" echo "[1/6] 备份已有配置..." SAVED_QQBOT_TOKEN="" -for APP_NAME in openclaw clawdbot; do +for APP_NAME in openclaw clawdbot moltbot; do CONFIG_FILE="$HOME/.$APP_NAME/$APP_NAME.json" if [ -f "$CONFIG_FILE" ]; then SAVED_QQBOT_TOKEN=$(node -e " const cfg = JSON.parse(require('fs').readFileSync('$CONFIG_FILE', 'utf8')); - const ch = cfg.channels && cfg.channels.qqbot; - if (!ch) process.exit(0); - // token 字段(openclaw channels add 写入) - if (ch.token) { process.stdout.write(ch.token); process.exit(0); } - // appId + clientSecret 字段(openclaw 实际存储格式) - if (ch.appId && ch.clientSecret) { process.stdout.write(ch.appId + ':' + ch.clientSecret); process.exit(0); } + // 尝试所有可能的 channel key(原仓库 + 本仓库) + const keys = ['qqbot', 'openclaw-qq']; + for (const key of keys) { + const ch = cfg.channels && cfg.channels[key]; + if (!ch) continue; + if (ch.token) { process.stdout.write(ch.token); process.exit(0); } + if (ch.appId && ch.clientSecret) { process.stdout.write(ch.appId + ':' + ch.clientSecret); process.exit(0); } + } " 2>/dev/null || true) if [ -n "$SAVED_QQBOT_TOKEN" ]; then echo "已备份 qqbot 通道 token: ${SAVED_QQBOT_TOKEN:0:10}..." @@ -97,8 +105,8 @@ done # 2. 移除老版本 echo "" echo "[2/6] 移除老版本..." -if [ -f "./scripts/upgrade.sh" ]; then - bash ./scripts/upgrade.sh +if [ -f "$PROJ_DIR/scripts/upgrade.sh" ]; then + bash "$PROJ_DIR/scripts/upgrade.sh" else echo "警告: upgrade.sh 不存在,跳过移除步骤" fi diff --git a/scripts/upgrade.sh b/scripts/upgrade.sh index 452f7ad..b31c164 100755 --- a/scripts/upgrade.sh +++ b/scripts/upgrade.sh @@ -18,49 +18,55 @@ detect_installation() { fi } +# 可能的扩展目录名(原仓库 qqbot + 本仓库框架推断名 openclaw-qq) +EXTENSION_DIRS=("qqbot" "openclaw-qq") + # 清理指定目录的函数 cleanup_installation() { local APP_NAME="$1" local APP_DIR="$HOME/.$APP_NAME" local CONFIG_FILE="$APP_DIR/$APP_NAME.json" - local EXTENSION_DIR="$APP_DIR/extensions/qqbot" echo "" echo ">>> 处理 $APP_NAME 安装..." - # 1. 删除旧的扩展目录 - if [ -d "$EXTENSION_DIR" ]; then - echo "删除旧版本插件: $EXTENSION_DIR" - rm -rf "$EXTENSION_DIR" - else - echo "未找到旧版本插件目录,跳过删除" - fi + # 1. 删除所有可能的旧扩展目录 + for dir_name in "${EXTENSION_DIRS[@]}"; do + local ext_dir="$APP_DIR/extensions/$dir_name" + if [ -d "$ext_dir" ]; then + echo "删除旧版本插件: $ext_dir" + rm -rf "$ext_dir" + fi + done - # 2. 清理配置文件中的 qqbot 相关字段 + # 2. 清理配置文件中所有可能的插件 ID 相关字段 if [ -f "$CONFIG_FILE" ]; then - echo "清理配置文件中的 qqbot 字段..." + echo "清理配置文件中的插件字段..." # 使用 node 处理 JSON(比 jq 更可靠处理复杂结构) node -e " const fs = require('fs'); const config = JSON.parse(fs.readFileSync('$CONFIG_FILE', 'utf8')); + const ids = ['qqbot', 'openclaw-qq', '@sliverp/qqbot', '@tencent-connect/openclaw-qq']; - // 删除 channels.qqbot - if (config.channels && config.channels.qqbot) { - delete config.channels.qqbot; - console.log(' - 已删除 channels.qqbot'); - } - - // 删除 plugins.entries.qqbot - if (config.plugins && config.plugins.entries && config.plugins.entries.qqbot) { - delete config.plugins.entries.qqbot; - console.log(' - 已删除 plugins.entries.qqbot'); - } - - // 删除 plugins.installs.qqbot - if (config.plugins && config.plugins.installs && config.plugins.installs.qqbot) { - delete config.plugins.installs.qqbot; - console.log(' - 已删除 plugins.installs.qqbot'); + for (const id of ids) { + // 删除 channels. + if (config.channels && config.channels[id]) { + delete config.channels[id]; + console.log(' - 已删除 channels.' + id); + } + + // 删除 plugins.entries. + if (config.plugins && config.plugins.entries && config.plugins.entries[id]) { + delete config.plugins.entries[id]; + console.log(' - 已删除 plugins.entries.' + id); + } + + // 删除 plugins.installs. + if (config.plugins && config.plugins.installs && config.plugins.installs[id]) { + delete config.plugins.installs[id]; + console.log(' - 已删除 plugins.installs.' + id); + } } fs.writeFileSync('$CONFIG_FILE', JSON.stringify(config, null, 2)); @@ -86,10 +92,16 @@ if [ -d "$HOME/.openclaw" ]; then FOUND_INSTALLATION="openclaw" fi +# 检查 moltbot +if [ -d "$HOME/.moltbot" ]; then + cleanup_installation "moltbot" + FOUND_INSTALLATION="moltbot" +fi + # 如果都没找到 if [ -z "$FOUND_INSTALLATION" ]; then - echo "未找到 clawdbot 或 openclaw 安装目录" - echo "请确认已安装 clawdbot 或 openclaw" + echo "未找到 clawdbot / openclaw / moltbot 安装目录" + echo "请确认已安装其中之一" exit 1 fi @@ -100,7 +112,7 @@ echo "" echo "=== 清理完成 ===" echo "" echo "接下来请执行以下命令重新安装插件:" -echo " cd /path/to/qqbot" +echo " cd /path/to/openclaw-qq" echo " $CMD plugins install ." echo " $CMD channels add --channel qqbot --token \"AppID:AppSecret\"" echo " $CMD gateway restart"