AI Newsletter Digest improvements: fixed QP soft line break decoding, URL extraction, and content cleaning
This commit is contained in:
58
archive/inactive-skills/openclaw-toolbox/SKILL.md
Normal file
58
archive/inactive-skills/openclaw-toolbox/SKILL.md
Normal file
@@ -0,0 +1,58 @@
|
||||
---
|
||||
name: "openclaw-toolbox"
|
||||
description: "Integrated OpenClaw management suite for environment initialization, maintenance, and multi-mode backup (Full/Skills)."
|
||||
author: "Wilsonsliu95 (https://github.com/WilsonLiu95)"
|
||||
---
|
||||
|
||||
# OpenClaw Toolbox
|
||||
|
||||
OpenClaw 综合管理工具箱,集成环境初始化、系统维护及多模式备份功能。
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. 环境初始化 (Setup)
|
||||
```bash
|
||||
# 适合新设备首次部署或环境修复
|
||||
"~/.openclaw/workspace/skills/openclaw-toolbox/scripts/setup.sh"
|
||||
```
|
||||
|
||||
### 2. 系统备份 (Backup)
|
||||
```bash
|
||||
# 备份整个 OpenClaw 仓库(系统配置、人设、记忆等)
|
||||
"~/.openclaw/workspace/skills/openclaw-toolbox/scripts/backup-now.sh" --full "定期备份"
|
||||
|
||||
# 备份 Skills 开发仓库
|
||||
"~/.openclaw/workspace/skills/openclaw-toolbox/scripts/backup-now.sh" --skills "更新技能库"
|
||||
|
||||
# 备份并升级(先拉取再备份)
|
||||
"~/.openclaw/workspace/skills/openclaw-toolbox/scripts/backup-now.sh" --pull
|
||||
```
|
||||
|
||||
## 常用命令与参数
|
||||
|
||||
### Setup 脚本参数
|
||||
- `--update`: 拉取最新仓库(工作区干净时)
|
||||
- `--verify-only`: 仅验证安装状态
|
||||
- `--reset-env`: 重新生成 `.env`(自动备份旧文件)
|
||||
- `--skip-node` / `--skip-packages` / `--skip-env` / `--skip-mcp`
|
||||
|
||||
### Backup 脚本参数
|
||||
- `--full`: 备份整个 OpenClaw 仓库 (默认)
|
||||
- `--skills`: 备份 `workspace/projects/openclaw-skills` 仓库
|
||||
- `--pull`: 备份前先执行 `git pull --rebase` (升级同步)
|
||||
- `--no-push`: 只提交,不推送
|
||||
- `--dry-run`: 仅显示变更预览
|
||||
- `-m, --message`: 自定义提交信息
|
||||
|
||||
## 环境要求
|
||||
|
||||
- 已设置 `OPENCLAW_SKILLS_GITHUB_URL` 环境变量(用于 Skills 备份)
|
||||
- 已安装 Git 且配置好 GitHub 访问权限(SSH 或 PAT)
|
||||
|
||||
## 运行逻辑
|
||||
|
||||
- **Setup**: 自动化配置 Node.js、安装核心 CLI、生成配置文件模板并验证环境。
|
||||
- **Backup**: 智能识别仓库类型,处理 Git 暂存、提交及远程推送。
|
||||
|
||||
---
|
||||
*🦐 虾宝宝工具箱 —— 守护刘家 AI 环境*
|
||||
6
archive/inactive-skills/openclaw-toolbox/_meta.json
Normal file
6
archive/inactive-skills/openclaw-toolbox/_meta.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"ownerId": "kn7fy1v71qjr44t45px34w2a0580mmfz",
|
||||
"slug": "openclaw-toolbox",
|
||||
"version": "1.0.0",
|
||||
"publishedAt": 1770414272979
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "OpenClaw Setup"
|
||||
short_description: "Initialize OpenClaw environment"
|
||||
default_prompt: "Run the OpenClaw setup script and summarize the results."
|
||||
207
archive/inactive-skills/openclaw-toolbox/scripts/backup-now.sh
Normal file
207
archive/inactive-skills/openclaw-toolbox/scripts/backup-now.sh
Normal file
@@ -0,0 +1,207 @@
|
||||
#!/bin/bash
|
||||
|
||||
# OpenClaw 立即备份脚本
|
||||
# 使用方法: ./backup-now.sh ["自定义提交信息"]
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# 尝试寻找 OpenClaw 根目录 (~/.openclaw)
|
||||
# 逻辑:从脚本目录向上查找,直到找到 openclaw.json 或 .env 文件
|
||||
FIND_ROOT="$SCRIPT_DIR"
|
||||
ROOT_DIR=""
|
||||
while [ "$FIND_ROOT" != "/" ]; do
|
||||
if [ -f "$FIND_ROOT/openclaw.json" ] || [ -f "$FIND_ROOT/.env" ]; then
|
||||
ROOT_DIR="$FIND_ROOT"
|
||||
break
|
||||
fi
|
||||
FIND_ROOT="$(dirname "$FIND_ROOT")"
|
||||
done
|
||||
|
||||
# 如果没找到,退回到预设的相对路径
|
||||
if [ -z "$ROOT_DIR" ]; then
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/../../../../" && pwd)"
|
||||
fi
|
||||
|
||||
SKILLS_DIR="$ROOT_DIR/workspace/projects/openclaw-skills"
|
||||
|
||||
# 加载 .env 环境变量
|
||||
if [ -f "$ROOT_DIR/.env" ]; then
|
||||
# 使用 grep 和 sed 处理 .env 文件,避免直接 source 可能带来的安全风险或语法错误
|
||||
export $(grep -v '^#' "$ROOT_DIR/.env" | xargs)
|
||||
fi
|
||||
|
||||
BACKUP_TYPE="full"
|
||||
BACKUP_DIR="$ROOT_DIR"
|
||||
GIT_REMOTE="origin"
|
||||
|
||||
NO_PUSH=0
|
||||
DRY_RUN=0
|
||||
PULL_BEFORE=0
|
||||
COMMIT_MSG=""
|
||||
|
||||
# 颜色输出
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
Usage:
|
||||
backup-now.sh [message] [options]
|
||||
|
||||
Options:
|
||||
--full 备份整个 OpenClaw 仓库 (默认)
|
||||
--skills 备份 openclaw-skills 仓库
|
||||
--pull 备份前先 git pull --rebase(要求工作区干净)
|
||||
--no-push 只提交,不推送
|
||||
--dry-run 仅显示变更,不提交
|
||||
-m, --message 提交信息
|
||||
-h, --help 显示帮助
|
||||
|
||||
USAGE
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--full)
|
||||
BACKUP_TYPE="full"
|
||||
BACKUP_DIR="$ROOT_DIR"
|
||||
;;
|
||||
--skills)
|
||||
BACKUP_TYPE="skills"
|
||||
BACKUP_DIR="$SKILLS_DIR"
|
||||
;;
|
||||
--pull) PULL_BEFORE=1 ;;
|
||||
--no-push) NO_PUSH=1 ;;
|
||||
--dry-run) DRY_RUN=1 ;;
|
||||
-m|--message)
|
||||
shift
|
||||
COMMIT_MSG="$1"
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
if [ -z "$COMMIT_MSG" ]; then
|
||||
COMMIT_MSG="$1"
|
||||
else
|
||||
COMMIT_MSG="$COMMIT_MSG $1"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
parse_args "$@"
|
||||
|
||||
echo -e "${BLUE}🔄 开始 ${BACKUP_TYPE} 备份...${NC}"
|
||||
|
||||
if [ ! -d "$BACKUP_DIR" ]; then
|
||||
if [ "$BACKUP_TYPE" == "skills" ] && [ -n "$OPENCLAW_SKILLS_GITHUB_URL" ]; then
|
||||
echo -e "${YELLOW}⚠️ Skills 目录不存在,尝试克隆...${NC}"
|
||||
mkdir -p "$(dirname "$SKILLS_DIR")"
|
||||
git clone "$OPENCLAW_SKILLS_GITHUB_URL" "$SKILLS_DIR"
|
||||
else
|
||||
echo -e "${RED}✗ 备份目录不存在: $BACKUP_DIR${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
cd "$BACKUP_DIR"
|
||||
|
||||
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
echo -e "${RED}✗ 当前目录不是 Git 仓库: $BACKUP_DIR${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! git remote get-url "$GIT_REMOTE" >/dev/null 2>&1; then
|
||||
GIT_REMOTE="$(git remote | head -n1)"
|
||||
fi
|
||||
if [ -z "$GIT_REMOTE" ]; then
|
||||
echo -e "${YELLOW}⚠️ 未找到 Git 远端${NC}"
|
||||
fi
|
||||
|
||||
REPO_URL=""
|
||||
if [ -n "$GIT_REMOTE" ]; then
|
||||
REPO_URL="$(git remote get-url "$GIT_REMOTE" 2>/dev/null || true)"
|
||||
fi
|
||||
CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
|
||||
|
||||
echo -e "${BLUE}🔄 开始 ${BACKUP_TYPE} 备份...${NC}"
|
||||
|
||||
if [ "$PULL_BEFORE" -eq 1 ]; then
|
||||
if git diff --quiet && git diff --staged --quiet; then
|
||||
echo -e "${BLUE}⬇️ 拉取最新代码...${NC}"
|
||||
git pull --rebase || echo -e "${YELLOW}⚠️ git pull 失败,请手动处理${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ 工作区有未提交变更,跳过 git pull${NC}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 检查是否有更改
|
||||
if [ -z "$(git status --porcelain)" ]; then
|
||||
echo -e "${YELLOW}⚠️ 没有需要备份的更改${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$DRY_RUN" -eq 1 ]; then
|
||||
echo -e "${BLUE}📄 变更预览:${NC}"
|
||||
git status --short
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 统计更改的文件
|
||||
CHANGED_FILES=$(git status --short | wc -l | tr -d ' ')
|
||||
echo -e "${BLUE}📁 发现 ${CHANGED_FILES} 个文件有更改${NC}"
|
||||
|
||||
# 默认提交信息
|
||||
if [ -z "$COMMIT_MSG" ]; then
|
||||
case "$BACKUP_TYPE" in
|
||||
full) DISPLAY_TYPE="Full" ;;
|
||||
skills) DISPLAY_TYPE="Skills" ;;
|
||||
*) DISPLAY_TYPE="Manual" ;;
|
||||
esac
|
||||
COMMIT_MSG="$DISPLAY_TYPE backup: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
fi
|
||||
|
||||
# 添加所有更改
|
||||
echo -e "${BLUE}➕ 添加更改到暂存区...${NC}"
|
||||
git add -A
|
||||
|
||||
# 提交
|
||||
echo -e "${BLUE}💾 提交更改...${NC}"
|
||||
git commit -m "$COMMIT_MSG"
|
||||
|
||||
# 推送到 GitHub
|
||||
if [ "$NO_PUSH" -eq 0 ]; then
|
||||
echo -e "${BLUE}☁️ 推送到 GitHub...${NC}"
|
||||
if [ -n "$GIT_REMOTE" ] && [ -n "$CURRENT_BRANCH" ]; then
|
||||
if ! git push "$GIT_REMOTE" "$CURRENT_BRANCH"; then
|
||||
echo -e "${RED}✗ 推送失败:可能需要先 git pull --rebase${NC}"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if ! git push; then
|
||||
echo -e "${RED}✗ 推送失败:请检查 Git 远端或设置上游分支${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ 跳过推送(--no-push)${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✅ 备份完成!${NC}"
|
||||
echo -e "${BLUE}📦 仓库地址: ${REPO_URL:-N/A}${NC}"
|
||||
if [ -n "$CURRENT_BRANCH" ]; then
|
||||
echo -e "${BLUE}🌿 分支: ${GIT_REMOTE:-?}/${CURRENT_BRANCH}${NC}"
|
||||
fi
|
||||
echo -e "${BLUE}📝 提交信息: ${COMMIT_MSG}${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}💡 提示: 可以设置定时自动备份${NC}"
|
||||
136
archive/inactive-skills/openclaw-toolbox/scripts/backup.sh
Normal file
136
archive/inactive-skills/openclaw-toolbox/scripts/backup.sh
Normal file
@@ -0,0 +1,136 @@
|
||||
#!/bin/bash
|
||||
|
||||
# OpenClaw 自动备份脚本
|
||||
# 使用方法: ./backup.sh [commit message]
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BACKUP_DIR="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
GIT_REMOTE="origin"
|
||||
|
||||
NO_PUSH=0
|
||||
DRY_RUN=0
|
||||
PULL_BEFORE=0
|
||||
COMMIT_MSG=""
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
Usage:
|
||||
backup.sh [message]
|
||||
|
||||
Options:
|
||||
--pull 备份前先 git pull --rebase(要求工作区干净)
|
||||
--no-push 只提交,不推送
|
||||
--dry-run 仅显示变更,不提交
|
||||
-m, --message 提交信息
|
||||
-h, --help 显示帮助
|
||||
|
||||
USAGE
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--pull) PULL_BEFORE=1 ;;
|
||||
--no-push) NO_PUSH=1 ;;
|
||||
--dry-run) DRY_RUN=1 ;;
|
||||
-m|--message)
|
||||
shift
|
||||
COMMIT_MSG="$1"
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
if [ -z "$COMMIT_MSG" ]; then
|
||||
COMMIT_MSG="$1"
|
||||
else
|
||||
COMMIT_MSG="$COMMIT_MSG $1"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
parse_args "$@"
|
||||
|
||||
cd "$BACKUP_DIR"
|
||||
|
||||
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
echo "✗ 当前目录不是 Git 仓库: $BACKUP_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! git remote get-url "$GIT_REMOTE" >/dev/null 2>&1; then
|
||||
GIT_REMOTE="$(git remote | head -n1)"
|
||||
fi
|
||||
if [ -z "$GIT_REMOTE" ]; then
|
||||
echo "⚠️ 未找到 Git 远端"
|
||||
fi
|
||||
|
||||
REPO_URL=""
|
||||
if [ -n "$GIT_REMOTE" ]; then
|
||||
REPO_URL="$(git remote get-url "$GIT_REMOTE" 2>/dev/null || true)"
|
||||
fi
|
||||
CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
|
||||
|
||||
echo "🔄 开始备份 OpenClaw 配置..."
|
||||
|
||||
if [ "$PULL_BEFORE" -eq 1 ]; then
|
||||
if git diff --quiet && git diff --staged --quiet; then
|
||||
echo "⬇️ 拉取最新代码..."
|
||||
git pull --rebase || echo "⚠️ git pull 失败,请手动处理"
|
||||
else
|
||||
echo "⚠️ 工作区有未提交变更,跳过 git pull"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 检查是否有更改
|
||||
if [ -z "$(git status --porcelain)" ]; then
|
||||
echo "✅ 没有需要备份的更改"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$DRY_RUN" -eq 1 ]; then
|
||||
echo "📄 变更预览:"
|
||||
git status --short
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 默认提交信息
|
||||
if [ -z "$COMMIT_MSG" ]; then
|
||||
COMMIT_MSG="Backup: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
fi
|
||||
|
||||
echo "➕ 添加更改到暂存区..."
|
||||
git add -A
|
||||
|
||||
echo "💾 提交更改..."
|
||||
git commit -m "$COMMIT_MSG"
|
||||
|
||||
if [ "$NO_PUSH" -eq 0 ]; then
|
||||
echo "☁️ 推送到 GitHub..."
|
||||
if [ -n "$GIT_REMOTE" ] && [ -n "$CURRENT_BRANCH" ]; then
|
||||
if ! git push "$GIT_REMOTE" "$CURRENT_BRANCH"; then
|
||||
echo "✗ 推送失败:可能需要先 git pull --rebase"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if ! git push; then
|
||||
echo "✗ 推送失败:请检查 Git 远端或设置上游分支"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "⚠️ 跳过推送(--no-push)"
|
||||
fi
|
||||
|
||||
echo "✅ 备份完成!"
|
||||
echo "📦 仓库地址: ${REPO_URL:-N/A}"
|
||||
if [ -n "$CURRENT_BRANCH" ]; then
|
||||
echo "🌿 分支: ${GIT_REMOTE:-?}/${CURRENT_BRANCH}"
|
||||
fi
|
||||
echo "📝 提交信息: $COMMIT_MSG"
|
||||
487
archive/inactive-skills/openclaw-toolbox/scripts/setup.sh
Normal file
487
archive/inactive-skills/openclaw-toolbox/scripts/setup.sh
Normal file
@@ -0,0 +1,487 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# OpenClaw 一键初始化脚本
|
||||
# 用于在新电脑上快速部署 OpenClaw 环境
|
||||
# 作者: 虾宝宝 🦐
|
||||
# 创建时间: 2026-02-05
|
||||
#
|
||||
|
||||
set -e # 遇到错误立即退出
|
||||
|
||||
# 颜色定义
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# OpenClaw 根目录(基于脚本位置)
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/../../../../" && pwd)"
|
||||
|
||||
# 执行开关(可通过参数控制)
|
||||
SKIP_NODE=0
|
||||
SKIP_PACKAGES=0
|
||||
SKIP_ENV=0
|
||||
SKIP_MCP=0
|
||||
SKIP_CLAUDE=0
|
||||
SKIP_VERIFY=0
|
||||
VERIFY_ONLY=0
|
||||
UPDATE_REPO=0
|
||||
RESET_ENV=0
|
||||
|
||||
# 打印函数
|
||||
print_header() {
|
||||
echo -e "${BLUE}================================${NC}"
|
||||
echo -e "${BLUE}$1${NC}"
|
||||
echo -e "${BLUE}================================${NC}"
|
||||
}
|
||||
|
||||
print_success() {
|
||||
echo -e "${GREEN}✓ $1${NC}"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}⚠ $1${NC}"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}✗ $1${NC}"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
OpenClaw Setup Script
|
||||
|
||||
Usage:
|
||||
setup.sh [options]
|
||||
|
||||
Options:
|
||||
--update 拉取最新仓库(git pull --rebase,工作区需干净)
|
||||
--verify-only 仅做验证,不执行安装
|
||||
--reset-env 重新生成 .env(会备份旧文件)
|
||||
--skip-node 跳过 Node.js 安装
|
||||
--skip-packages 跳过全局 CLI 安装
|
||||
--skip-env 跳过 .env 配置
|
||||
--skip-mcp 跳过 MCP 检查/配置
|
||||
--skip-claude 跳过 Claude MCP 配置
|
||||
--skip-verify 跳过安装验证
|
||||
-h, --help 显示帮助
|
||||
USAGE
|
||||
}
|
||||
|
||||
# 检查命令是否存在
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# 解析参数
|
||||
parse_args() {
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--update) UPDATE_REPO=1 ;;
|
||||
--verify-only) VERIFY_ONLY=1 ;;
|
||||
--reset-env) RESET_ENV=1 ;;
|
||||
--skip-node) SKIP_NODE=1 ;;
|
||||
--skip-packages) SKIP_PACKAGES=1 ;;
|
||||
--skip-env) SKIP_ENV=1 ;;
|
||||
--skip-mcp) SKIP_MCP=1 ;;
|
||||
--skip-claude) SKIP_CLAUDE=1 ;;
|
||||
--skip-verify) SKIP_VERIFY=1 ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*)
|
||||
print_error "未知参数: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
# 检查基础依赖
|
||||
check_prereqs() {
|
||||
print_header "检查基础依赖"
|
||||
|
||||
if command_exists git; then
|
||||
print_success "Git 已安装"
|
||||
else
|
||||
print_error "未安装 Git(请先安装)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if command_exists curl; then
|
||||
print_success "curl 已安装"
|
||||
else
|
||||
print_error "未安装 curl(请先安装)"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查 Node.js 版本
|
||||
check_node_version() {
|
||||
if command_exists node; then
|
||||
NODE_VERSION=$(node --version | cut -d'v' -f2)
|
||||
REQUIRED_VERSION="22.0.0"
|
||||
|
||||
if [ "$(printf '%s\n' "$REQUIRED_VERSION" "$NODE_VERSION" | sort -V | head -n1)" = "$REQUIRED_VERSION" ]; then
|
||||
print_success "Node.js 版本符合要求: $NODE_VERSION"
|
||||
return 0
|
||||
else
|
||||
print_warning "Node.js 版本过低: $NODE_VERSION,需要 >= $REQUIRED_VERSION"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
print_error "Node.js 未安装"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 安装 Node.js
|
||||
install_node() {
|
||||
print_header "安装 Node.js"
|
||||
|
||||
if command_exists nvm; then
|
||||
print_success "nvm 已安装"
|
||||
else
|
||||
print_warning "安装 nvm..."
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
|
||||
fi
|
||||
|
||||
nvm install 22
|
||||
nvm use 22
|
||||
nvm alias default 22
|
||||
|
||||
print_success "Node.js $(node --version) 安装完成"
|
||||
}
|
||||
|
||||
# 安装全局 npm 包
|
||||
install_global_packages() {
|
||||
print_header "安装全局 CLI"
|
||||
|
||||
if ! command_exists npm; then
|
||||
print_error "npm 未安装,无法安装全局 CLI"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# package:command
|
||||
PACKAGES=(
|
||||
"openclaw:openclaw"
|
||||
"@openclaw/mcporter:mcporter"
|
||||
"codex:codex"
|
||||
"@anthropic-ai/claude-code:claude"
|
||||
"@google/gemini-cli:gemini"
|
||||
)
|
||||
|
||||
for entry in "${PACKAGES[@]}"; do
|
||||
IFS=':' read -r pkg cmd <<< "$entry"
|
||||
if command_exists "$cmd"; then
|
||||
print_success "$cmd 已安装"
|
||||
else
|
||||
print_warning "安装 $pkg..."
|
||||
npm install -g "$pkg" || print_error "$pkg 安装失败"
|
||||
fi
|
||||
done
|
||||
|
||||
print_success "全局 CLI 安装完成"
|
||||
}
|
||||
|
||||
backup_file() {
|
||||
local file_path="$1"
|
||||
if [ -f "$file_path" ]; then
|
||||
local ts
|
||||
ts=$(date '+%Y%m%d-%H%M%S')
|
||||
cp "$file_path" "${file_path}.bak.${ts}"
|
||||
print_warning "已备份: ${file_path}.bak.${ts}"
|
||||
fi
|
||||
}
|
||||
|
||||
check_env_placeholders() {
|
||||
if [ -f ".env" ]; then
|
||||
if grep -n "your_\\|YOUR_" .env >/dev/null 2>&1; then
|
||||
print_warning "发现未替换的 .env 占位符,请尽快填写"
|
||||
grep -n "your_\\|YOUR_" .env || true
|
||||
else
|
||||
print_success ".env 已填写(未发现占位符)"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 配置环境变量
|
||||
setup_environment() {
|
||||
print_header "配置环境变量"
|
||||
|
||||
if [ -f ".env" ] && [ "$RESET_ENV" -eq 0 ]; then
|
||||
print_warning ".env 文件已存在,跳过创建"
|
||||
print_warning "请检查 .env 文件中的 API Keys 是否正确配置"
|
||||
check_env_placeholders
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -f ".env" ] && [ "$RESET_ENV" -eq 1 ]; then
|
||||
backup_file ".env"
|
||||
rm -f .env
|
||||
fi
|
||||
|
||||
if [ -f ".env.example" ]; then
|
||||
cp .env.example .env
|
||||
print_warning "已从 .env.example 创建 .env 文件"
|
||||
print_warning "⚠️ 请编辑 .env 文件,填入你的实际 API Keys!"
|
||||
else
|
||||
cat > .env << 'EOF'
|
||||
# ============================================
|
||||
# 模型/厂商 API Keys(按需填写)
|
||||
# ============================================
|
||||
ARK_API_KEY=your_ark_api_key_here
|
||||
ZAI_API_KEY=your_zai_api_key_here
|
||||
Z_AI_API_KEY=your_zai_api_key_here
|
||||
OPENAI_API_KEY=your_openai_api_key_here
|
||||
OPENCODE_API_KEY=your_opencode_api_key_here
|
||||
ANTHROPIC_API_KEY=your_anthropic_api_key_here
|
||||
GEMINI_API_KEY=your_gemini_api_key_here
|
||||
|
||||
# ============================================
|
||||
# 飞书 (Feishu)
|
||||
# ============================================
|
||||
FEISHU_APP_ID=your_feishu_app_id_main
|
||||
FEISHU_APP_SECRET=your_feishu_app_secret_main
|
||||
FEISHU_APP_ID_TEST=your_feishu_app_id_test
|
||||
FEISHU_APP_SECRET_TEST=your_feishu_app_secret_test
|
||||
|
||||
# ============================================
|
||||
# Telegram
|
||||
# ============================================
|
||||
TELEGRAM_BOT_TOKEN=your_telegram_bot_token
|
||||
|
||||
# ============================================
|
||||
# OpenClaw Gateway
|
||||
# ============================================
|
||||
OPENCLAW_GATEWAY_TOKEN=your_gateway_token
|
||||
|
||||
EOF
|
||||
print_warning "已创建默认 .env 文件"
|
||||
print_warning "⚠️ 请编辑 .env 文件,填入你的实际 API Keys!"
|
||||
fi
|
||||
|
||||
# 加载环境变量
|
||||
export $(cat .env | grep -v '^#' | xargs) 2>/dev/null || true
|
||||
|
||||
check_env_placeholders
|
||||
print_success "环境变量配置完成"
|
||||
}
|
||||
|
||||
# 配置 MCP 服务器
|
||||
setup_mcp_servers() {
|
||||
print_header "配置 MCP 服务器"
|
||||
|
||||
if ! command_exists mcporter; then
|
||||
print_warning "mcporter 未安装,跳过 MCP 检查"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 确保配置目录存在
|
||||
mkdir -p "$ROOT_DIR/config"
|
||||
|
||||
# 检查 mcporter 配置
|
||||
if [ -f "config/mcporter.json" ]; then
|
||||
print_success "发现 mcporter.json 配置"
|
||||
|
||||
# 验证配置
|
||||
if mcporter list >/dev/null 2>&1; then
|
||||
print_success "MCP 服务器验证通过"
|
||||
mcporter list
|
||||
else
|
||||
print_error "MCP 服务器验证失败,请检查配置和 API Keys"
|
||||
fi
|
||||
else
|
||||
print_warning "未找到 config/mcporter.json,跳过 MCP 配置"
|
||||
fi
|
||||
|
||||
print_success "MCP 服务器配置完成"
|
||||
}
|
||||
|
||||
# 配置 Claude Code MCP
|
||||
setup_claude_mcp() {
|
||||
print_header "配置 Claude Code MCP"
|
||||
|
||||
mkdir -p ~/.claude
|
||||
|
||||
# 从仓库配置复制
|
||||
if [ -f ".claude/mcp.json" ]; then
|
||||
if [ -f ~/.claude/mcp.json ]; then
|
||||
backup_file ~/.claude/mcp.json
|
||||
fi
|
||||
cp .claude/mcp.json ~/.claude/mcp.json
|
||||
print_success "已复制 Claude Code MCP 配置"
|
||||
else
|
||||
# 创建默认配置
|
||||
if [ -f ~/.claude/mcp.json ]; then
|
||||
print_warning "~/.claude/mcp.json 已存在,跳过创建"
|
||||
else
|
||||
cat > ~/.claude/mcp.json << 'EOF'
|
||||
{
|
||||
"mcpServers": {
|
||||
"zai-mcp-server": {
|
||||
"type": "stdio",
|
||||
"command": "npx",
|
||||
"args": ["-y", "@z_ai/mcp-server"],
|
||||
"env": {
|
||||
"Z_AI_API_KEY": "your_zai_api_key_here",
|
||||
"Z_AI_MODE": "ZHIPU"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
print_warning "已创建默认 Claude Code MCP 配置"
|
||||
print_warning "⚠️ 请编辑 ~/.claude/mcp.json,填入你的实际 API Keys!"
|
||||
fi
|
||||
fi
|
||||
|
||||
print_success "Claude Code MCP 配置完成"
|
||||
}
|
||||
|
||||
# 更新仓库
|
||||
update_repo() {
|
||||
if [ "$UPDATE_REPO" -eq 0 ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
print_header "更新仓库"
|
||||
|
||||
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
print_warning "当前目录不是 Git 仓库,跳过更新"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! git diff --quiet || ! git diff --staged --quiet; then
|
||||
print_warning "工作区有未提交变更,跳过 git pull"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print_warning "拉取最新代码..."
|
||||
git pull --rebase || print_error "git pull 失败,请手动处理"
|
||||
}
|
||||
|
||||
# 验证安装
|
||||
verify_installation() {
|
||||
print_header "验证安装"
|
||||
|
||||
CHECKS=(
|
||||
"node:Node.js"
|
||||
"npm:npm"
|
||||
"git:Git"
|
||||
"openclaw:OpenClaw CLI"
|
||||
"mcporter:McPorter"
|
||||
"codex:Codex CLI"
|
||||
"claude:Claude Code"
|
||||
"gemini:Gemini CLI"
|
||||
)
|
||||
|
||||
for check in "${CHECKS[@]}"; do
|
||||
IFS=':' read -r cmd name <<< "$check"
|
||||
if command_exists "$cmd"; then
|
||||
version=$($cmd --version 2>/dev/null | head -n1 | tr -d '\n')
|
||||
print_success "$name: $version"
|
||||
else
|
||||
print_error "$name: 未安装"
|
||||
fi
|
||||
done
|
||||
|
||||
print_success "安装验证完成"
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
parse_args "$@"
|
||||
|
||||
print_header "OpenClaw 一键初始化脚本"
|
||||
echo ""
|
||||
echo "项目名称: OpenClaw AI Assistant Environment"
|
||||
echo "主人: 深圳刘家(虾宝宝 🦐)"
|
||||
echo "仓库: https://github.com/YOUR_USERNAME/YOUR_REPO"
|
||||
echo ""
|
||||
|
||||
# 切到 OpenClaw 根目录
|
||||
if [ ! -d "$ROOT_DIR" ]; then
|
||||
print_error "未找到 OpenClaw 根目录: $ROOT_DIR"
|
||||
print_error "请确认此脚本位于 OpenClaw 仓库中"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
# 检查是否在正确的目录
|
||||
if [ ! -f "openclaw.json" ]; then
|
||||
print_error "请在 OpenClaw 根目录运行此脚本"
|
||||
print_error "请运行: cd $ROOT_DIR && ./workspace/skills/openclaw-toolbox/scripts/setup.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check_prereqs
|
||||
|
||||
update_repo
|
||||
|
||||
if [ "$VERIFY_ONLY" -eq 1 ]; then
|
||||
check_node_version || true
|
||||
verify_installation
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 执行安装步骤
|
||||
if [ "$SKIP_NODE" -eq 0 ]; then
|
||||
if ! check_node_version; then
|
||||
install_node
|
||||
fi
|
||||
else
|
||||
print_warning "跳过 Node.js 安装"
|
||||
fi
|
||||
|
||||
if [ "$SKIP_PACKAGES" -eq 0 ]; then
|
||||
install_global_packages
|
||||
else
|
||||
print_warning "跳过全局 CLI 安装"
|
||||
fi
|
||||
|
||||
if [ "$SKIP_ENV" -eq 0 ]; then
|
||||
setup_environment
|
||||
else
|
||||
print_warning "跳过 .env 配置"
|
||||
fi
|
||||
|
||||
if [ "$SKIP_MCP" -eq 0 ]; then
|
||||
setup_mcp_servers
|
||||
else
|
||||
print_warning "跳过 MCP 配置"
|
||||
fi
|
||||
|
||||
if [ "$SKIP_CLAUDE" -eq 0 ]; then
|
||||
setup_claude_mcp
|
||||
else
|
||||
print_warning "跳过 Claude MCP 配置"
|
||||
fi
|
||||
|
||||
if [ "$SKIP_VERIFY" -eq 0 ]; then
|
||||
verify_installation
|
||||
else
|
||||
print_warning "跳过安装验证"
|
||||
fi
|
||||
|
||||
print_header "初始化完成!"
|
||||
echo ""
|
||||
echo "🎉 OpenClaw 环境已成功初始化!"
|
||||
echo ""
|
||||
echo "下一步操作:"
|
||||
echo "1. 编辑 .env 文件,填入你的 API Keys"
|
||||
echo "2. 启动 OpenClaw: openclaw gateway start"
|
||||
echo "3. 查看状态: openclaw status"
|
||||
echo ""
|
||||
echo "详细文档: $ROOT_DIR/workspace/skills/openclaw-setup/SETUP.md"
|
||||
echo "🦐 虾宝宝为刘家服务"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# 运行主函数
|
||||
main "$@"
|
||||
@@ -0,0 +1,60 @@
|
||||
import { execSync } from 'child_process';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const SCRIPT_DIR = path.join(__dirname, '../scripts');
|
||||
const ROOT_DIR = path.join(__dirname, '../../../../');
|
||||
console.log(`ROOT_DIR: ${ROOT_DIR}`);
|
||||
|
||||
const testResults = {
|
||||
total: 0,
|
||||
passed: 0,
|
||||
failed: []
|
||||
};
|
||||
|
||||
function runTest(name, command) {
|
||||
testResults.total++;
|
||||
console.log(`\n▶️ Running Test: ${name}`);
|
||||
try {
|
||||
const output = execSync(command, {
|
||||
encoding: 'utf8',
|
||||
stdio: 'pipe',
|
||||
cwd: ROOT_DIR // Run from project root
|
||||
});
|
||||
console.log(`✅ Passed: ${name}`);
|
||||
testResults.passed++;
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.log(`❌ Failed: ${name}`);
|
||||
console.log(`Error: ${error.message}`);
|
||||
if (error.stdout) console.log(`Stdout: ${error.stdout}`);
|
||||
if (error.stderr) console.log(`Stderr: ${error.stderr}`);
|
||||
testResults.failed.push({ name, error: error.message });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('🦐 OpenClaw Toolbox Sanity Tests');
|
||||
console.log('=================================');
|
||||
|
||||
// Test 1: Backup Dry Run (Full)
|
||||
runTest('Backup Full (Dry Run)', `bash ${path.join(SCRIPT_DIR, 'backup-now.sh')} --full --dry-run`);
|
||||
|
||||
// Test 2: Backup Dry Run (Skills)
|
||||
runTest('Backup Skills (Dry Run)', `bash ${path.join(SCRIPT_DIR, 'backup-now.sh')} --skills --dry-run`);
|
||||
|
||||
// Test 3: Setup Verify Only
|
||||
runTest('Setup Verification', `bash ${path.join(SCRIPT_DIR, 'setup.sh')} --verify-only`);
|
||||
|
||||
// Summary
|
||||
console.log('\n=================================');
|
||||
console.log(`📊 Test Summary: ${testResults.passed}/${testResults.total} passed`);
|
||||
if (testResults.failed.length > 0) {
|
||||
console.log('❌ Failures:');
|
||||
testResults.failed.forEach(f => console.log(` - ${f.name}: ${f.error}`));
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log('✅ All sanity tests passed!');
|
||||
process.exit(0);
|
||||
}
|
||||
Reference in New Issue
Block a user