From 01b72f016b84a5bb96409a040b71def7944d4ae7 Mon Sep 17 00:00:00 2001 From: LehaoLin Date: Sat, 7 Mar 2026 00:58:57 +0800 Subject: [PATCH 1/2] feat: add uninstall.sh and update README.md README_EN.md --- README.md | 21 ++++ README_EN.md | 21 ++++ uninstall.sh | 303 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 uninstall.sh diff --git a/README.md b/README.md index 1d07ecb..a1f5a62 100644 --- a/README.md +++ b/README.md @@ -308,6 +308,27 @@ open http://127.0.0.1:7891 > 💡 详细教程请看 [Getting Started 指南](docs/getting-started.md) +#### 卸载 + +```bash +# 普通卸载(推荐先用这个) +chmod +x uninstall.sh && ./uninstall.sh + +# 深度卸载(额外清理缓存/备份) +./uninstall.sh --purge +``` + +卸载脚本会执行: +- 备份现有 OpenClaw 工作区与配置到 `~/.openclaw/backups/pre-uninstall-*` +- 删除三省六部相关 workspace(`~/.openclaw/workspace-*`) +- 从 `~/.openclaw/openclaw.json` 注销三省六部 agents +- 清理仓库 `data/` 下安装脚本初始化的文件 + +`--purge` 会额外执行: +- 删除 `~/.openclaw/agents/` 下三省六部相关目录(若存在) +- 清理 `openclaw.json.bak.sansheng-*` 等本项目生成的备份文件 +- 清理 `pre-uninstall-*` 备份目录,并在 `data/` 为空时删除该目录 + --- ## 🏛️ 架构 diff --git a/README_EN.md b/README_EN.md index 106493b..2cbb238 100644 --- a/README_EN.md +++ b/README_EN.md @@ -225,6 +225,27 @@ open http://127.0.0.1:7891 > 📖 See [Getting Started Guide](docs/getting-started.md) for detailed walkthrough. +### Uninstall + +```bash +# Standard uninstall (recommended first) +chmod +x uninstall.sh && ./uninstall.sh + +# Deep uninstall (extra cache/backup cleanup) +./uninstall.sh --purge +``` + +The uninstall script will: +- Back up existing OpenClaw workspaces and config to `~/.openclaw/backups/pre-uninstall-*` +- Remove Three Departments & Six Ministries workspaces (`~/.openclaw/workspace-*`) +- Unregister related agents from `~/.openclaw/openclaw.json` +- Clean installer-initialized files in the repo `data/` directory + +`--purge` additionally: +- Removes related directories under `~/.openclaw/agents/` (if present) +- Cleans project-generated backups like `openclaw.json.bak.sansheng-*` +- Cleans `pre-uninstall-*` backups and removes `data/` if it becomes empty + --- ## 🏛️ Architecture diff --git a/uninstall.sh b/uninstall.sh new file mode 100644 index 0000000..c0781b8 --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,303 @@ +#!/bin/bash +# ══════════════════════════════════════════════════════════════ +# 三省六部 · OpenClaw Multi-Agent System 一键卸载脚本 +# ══════════════════════════════════════════════════════════════ +set -e + +REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OC_HOME="$HOME/.openclaw" +OC_CFG="$OC_HOME/openclaw.json" + +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m' + +PURGE=false + +banner() { + echo "" + echo -e "${BLUE}╔══════════════════════════════════════════╗${NC}" + echo -e "${BLUE}║ 🧹 三省六部 · OpenClaw Multi-Agent ║${NC}" + echo -e "${BLUE}║ 卸载向导 ║${NC}" + echo -e "${BLUE}╚══════════════════════════════════════════╝${NC}" + echo "" +} + +usage() { + echo "用法: ./uninstall.sh [--purge]" + echo "" + echo "选项:" + echo " --purge 执行严格深度清理(尽可能彻底移除安装/首次同步产物)" + echo " -h, --help 显示帮助" +} + +log() { echo -e "${GREEN}✅ $1${NC}"; } +warn() { echo -e "${YELLOW}⚠️ $1${NC}"; } +error() { echo -e "${RED}❌ $1${NC}"; } +info() { echo -e "${BLUE}ℹ️ $1${NC}"; } + +AGENTS=(taizi zhongshu menxia shangshu hubu libu bingbu xingbu gongbu libu_hr zaochao) +ALL_RUNTIME_IDS=(taizi zhongshu menxia shangshu hubu libu bingbu xingbu gongbu libu_hr zaochao main) + +parse_args() { + while [ "$#" -gt 0 ]; do + case "$1" in + --purge) + PURGE=true + ;; + -h|--help) + usage + exit 0 + ;; + *) + error "未知参数: $1" + usage + exit 1 + ;; + esac + shift + done +} + +# ── Step 0: 依赖检查 ────────────────────────────────────────── +check_deps() { + info "检查依赖..." + + if ! command -v python3 &>/dev/null; then + error "未找到 python3" + exit 1 + fi + log "Python3: $(python3 --version)" + + if [ ! -d "$OC_HOME" ]; then + warn "未找到 OpenClaw 目录: $OC_HOME(可能已卸载)" + else + log "OpenClaw 目录: $OC_HOME" + fi + + if [ ! -f "$OC_CFG" ]; then + warn "未找到 openclaw.json(将跳过注销步骤)" + else + log "openclaw.json: $OC_CFG" + fi +} + +# ── Step 1: 备份已有数据 ────────────────────────────────────── +backup_existing() { + BACKUP_DIR="$OC_HOME/backups/pre-uninstall-$(date +%Y%m%d-%H%M%S)" + NEED_BACKUP=false + + for d in "$OC_HOME"/workspace-*/; do + if [ -d "$d" ]; then + NEED_BACKUP=true + break + fi + done + + if [ -f "$OC_CFG" ] || [ -d "$OC_HOME/agents" ]; then + NEED_BACKUP=true + fi + + if $NEED_BACKUP; then + info "检测到已有数据,自动备份中..." + mkdir -p "$BACKUP_DIR" + + for d in "$OC_HOME"/workspace-*/; do + if [ -d "$d" ]; then + ws_name=$(basename "$d") + cp -R "$d" "$BACKUP_DIR/$ws_name" + fi + done + + if [ -f "$OC_CFG" ]; then + cp "$OC_CFG" "$BACKUP_DIR/openclaw.json" + fi + + if [ -d "$OC_HOME/agents" ]; then + cp -R "$OC_HOME/agents" "$BACKUP_DIR/agents" + fi + + log "已备份到: $BACKUP_DIR" + else + warn "未发现可备份内容,跳过" + fi +} + +# ── Step 2: 删除 Workspace ─────────────────────────────────── +remove_workspaces() { + info "删除三省六部 Workspace..." + removed=0 + + for agent in "${AGENTS[@]}"; do + ws="$OC_HOME/workspace-$agent" + if [ -d "$ws" ]; then + rm -rf "$ws" + removed=$((removed+1)) + log "已删除: $ws" + fi + done + + if [ "$removed" -eq 0 ]; then + warn "未找到三省六部 Workspace(可能已删除)" + fi +} + +# ── Step 3: 注销 Agents ───────────────────────────────────── +unregister_agents() { + info "从 openclaw.json 注销三省六部 Agents..." + + if [ ! -f "$OC_CFG" ]; then + warn "openclaw.json 不存在,跳过注销" + return + fi + + cp "$OC_CFG" "$OC_CFG.bak.sansheng-uninstall-$(date +%Y%m%d-%H%M%S)" + log "已备份配置: $OC_CFG.bak.*" + + python3 << 'PYEOF' +import json +import pathlib + +cfg_path = pathlib.Path.home() / '.openclaw' / 'openclaw.json' +cfg = json.loads(cfg_path.read_text()) + +remove_ids = { + 'taizi', 'zhongshu', 'menxia', 'shangshu', + 'hubu', 'libu', 'bingbu', 'xingbu', 'gongbu', + 'libu_hr', 'zaochao', +} + +agents_cfg = cfg.get('agents', {}) +agents_list = agents_cfg.get('list', []) +before = len(agents_list) + +agents_cfg['list'] = [a for a in agents_list if a.get('id') not in remove_ids] +cfg['agents'] = agents_cfg + +cfg_path.write_text(json.dumps(cfg, ensure_ascii=False, indent=2)) +print(f'Done: {before - len(agents_cfg["list"])} agents removed') +PYEOF + + log "Agents 注销完成" +} + +# ── Step 4: 清理仓库数据 ───────────────────────────────────── +cleanup_repo_data() { + info "清理仓库 data 初始化文件..." + + if [ ! -d "$REPO_DIR/data" ]; then + warn "未找到 $REPO_DIR/data,跳过" + return + fi + + FILES=( + "$REPO_DIR/data/live_status.json" + "$REPO_DIR/data/agent_config.json" + "$REPO_DIR/data/model_change_log.json" + "$REPO_DIR/data/pending_model_changes.json" + "$REPO_DIR/data/tasks_source.json" + ) + + removed_any=false + for f in "${FILES[@]}"; do + if [ -f "$f" ]; then + rm -f "$f" + log "已删除: $f" + removed_any=true + fi + done + + if ! $removed_any; then + warn "未发现需要清理的初始化文件" + fi +} + +# ── Step 5: 严格深度清理(--purge)─────────────────────────── +purge_cleanup() { + if ! $PURGE; then + return + fi + + info "执行 --purge 严格深度清理..." + + # 1) 删除 ~/.openclaw/agents 下相关目录(含 legacy main) + for agent in "${ALL_RUNTIME_IDS[@]}"; do + if [ -d "$OC_HOME/agents/$agent" ]; then + rm -rf "$OC_HOME/agents/$agent" + log "已删除: $OC_HOME/agents/$agent" + fi + done + + # 2) 清理首次同步写入的 workspace scripts(含 legacy main) + for runtime_id in "${ALL_RUNTIME_IDS[@]}"; do + ws_scripts="$OC_HOME/workspace-$runtime_id/scripts" + if [ -d "$ws_scripts" ]; then + rm -rf "$ws_scripts" + log "已删除: $ws_scripts" + fi + done + + # 3) 删除可能由首次同步创建的 legacy 兼容目录 + if [ -d "$OC_HOME/workspace-main" ]; then + rmdir "$OC_HOME/workspace-main" 2>/dev/null || true + fi + + # 4) 清理本项目生成的配置备份 + rm -f "$OC_CFG".bak.sansheng-* "$OC_CFG".bak.sansheng-uninstall-* 2>/dev/null || true + log "已清理 openclaw.json 相关备份(sansheng 前缀)" + + # 5) 清理本仓库 data 目录(若为空则删除) + if [ -d "$REPO_DIR/data" ] && [ -z "$(ls -A "$REPO_DIR/data" 2>/dev/null)" ]; then + rmdir "$REPO_DIR/data" 2>/dev/null || true + log "data 目录为空,已删除: $REPO_DIR/data" + fi + + # 6) 清理 pre-uninstall/pre-install 备份(仅本项目脚本创建) + if [ -d "$OC_HOME/backups" ]; then + rm -rf "$OC_HOME/backups"/pre-uninstall-* 2>/dev/null || true + rm -rf "$OC_HOME/backups"/pre-install-* 2>/dev/null || true + log "已清理 pre-uninstall/pre-install 备份" + fi +} + +# ── Step 6: 重启 Gateway ──────────────────────────────────── +restart_gateway() { + info "重启 OpenClaw Gateway..." + if command -v openclaw &>/dev/null; then + if openclaw gateway restart 2>/dev/null; then + log "Gateway 重启成功" + else + warn "Gateway 重启失败,请手动重启:openclaw gateway restart" + fi + else + warn "未找到 openclaw CLI,跳过 Gateway 重启" + fi +} + +# ── Main ──────────────────────────────────────────────────── +parse_args "$@" +banner +check_deps +backup_existing +remove_workspaces +unregister_agents +cleanup_repo_data +purge_cleanup +restart_gateway + +echo "" +echo -e "${GREEN}╔══════════════════════════════════════════════════╗${NC}" +if $PURGE; then + echo -e "${GREEN}║ 🧹 三省六部严格深度卸载完成(--purge)! ║${NC}" +else + echo -e "${GREEN}║ 🧹 三省六部卸载完成! ║${NC}" +fi +echo -e "${GREEN}╚══════════════════════════════════════════════════╝${NC}" +echo "" +echo "说明:" +echo " 1. 已移除三省六部 agents 注册与 workspace" +echo " 2. 已清理本仓库 data 下初始化文件" +if $PURGE; then + echo " 3. 已执行严格深度清理(含 legacy main 兼容产物、同步脚本产物、备份清理)" +else + echo " 3. 如需严格深度清理,请执行: ./uninstall.sh --purge" +fi +echo "" From 67f1b223b883dad7762a500412989d172d2b51cf Mon Sep 17 00:00:00 2001 From: LehaoLin Date: Sat, 7 Mar 2026 17:18:03 +0800 Subject: [PATCH 2/2] feat: update uninstall.sh and README --- README.md | 16 ++++----- README_EN.md | 16 ++++----- uninstall.sh | 92 +++++++++++++++++++++++++++------------------------- 3 files changed, 63 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index a1f5a62..117d454 100644 --- a/README.md +++ b/README.md @@ -314,20 +314,20 @@ open http://127.0.0.1:7891 # 普通卸载(推荐先用这个) chmod +x uninstall.sh && ./uninstall.sh -# 深度卸载(额外清理缓存/备份) +# 深度卸载(额外清理安装备份) ./uninstall.sh --purge ``` 卸载脚本会执行: -- 备份现有 OpenClaw 工作区与配置到 `~/.openclaw/backups/pre-uninstall-*` -- 删除三省六部相关 workspace(`~/.openclaw/workspace-*`) -- 从 `~/.openclaw/openclaw.json` 注销三省六部 agents -- 清理仓库 `data/` 下安装脚本初始化的文件 +- ✅ 备份现有数据到 `~/.openclaw/backups/pre-uninstall-*` +- ✅ 删除三省六部 workspace(`~/.openclaw/workspace-{taizi,zhongshu,menxia,...}`) +- ✅ 从 `openclaw.json` 注销三省六部 agents +- ✅ 清理仓库 `data/` 下安装脚本初始化的文件 `--purge` 会额外执行: -- 删除 `~/.openclaw/agents/` 下三省六部相关目录(若存在) -- 清理 `openclaw.json.bak.sansheng-*` 等本项目生成的备份文件 -- 清理 `pre-uninstall-*` 备份目录,并在 `data/` 为空时删除该目录 +- ✅ 删除 `~/.openclaw/agents/` 下三省六部相关目录(若存在) +- ✅ 清理安装脚本产生的 `pre-install-*` 备份 +- ✅ 清理 `openclaw.json.bak.sansheng-*` 等配置备份文件 --- diff --git a/README_EN.md b/README_EN.md index 2cbb238..1aa4852 100644 --- a/README_EN.md +++ b/README_EN.md @@ -231,20 +231,20 @@ open http://127.0.0.1:7891 # Standard uninstall (recommended first) chmod +x uninstall.sh && ./uninstall.sh -# Deep uninstall (extra cache/backup cleanup) +# Deep uninstall (extra cleanup of installer backups) ./uninstall.sh --purge ``` The uninstall script will: -- Back up existing OpenClaw workspaces and config to `~/.openclaw/backups/pre-uninstall-*` -- Remove Three Departments & Six Ministries workspaces (`~/.openclaw/workspace-*`) -- Unregister related agents from `~/.openclaw/openclaw.json` -- Clean installer-initialized files in the repo `data/` directory +- ✅ Back up existing data to `~/.openclaw/backups/pre-uninstall-*` +- ✅ Remove Three Departments & Six Ministries workspaces (`~/.openclaw/workspace-{taizi,zhongshu,menxia,...}`) +- ✅ Unregister related agents from `openclaw.json` +- ✅ Clean installer-initialized files in the repo `data/` directory `--purge` additionally: -- Removes related directories under `~/.openclaw/agents/` (if present) -- Cleans project-generated backups like `openclaw.json.bak.sansheng-*` -- Cleans `pre-uninstall-*` backups and removes `data/` if it becomes empty +- ✅ Removes related directories under `~/.openclaw/agents/` (if present) +- ✅ Cleans installer-generated `pre-install-*` backups +- ✅ Cleans project-generated backups like `openclaw.json.bak.sansheng-*` --- diff --git a/uninstall.sh b/uninstall.sh index c0781b8..59e775b 100644 --- a/uninstall.sh +++ b/uninstall.sh @@ -25,7 +25,7 @@ usage() { echo "用法: ./uninstall.sh [--purge]" echo "" echo "选项:" - echo " --purge 执行严格深度清理(尽可能彻底移除安装/首次同步产物)" + echo " --purge 执行深度清理(清理安装脚本产生的备份)" echo " -h, --help 显示帮助" } @@ -35,7 +35,6 @@ error() { echo -e "${RED}❌ $1${NC}"; } info() { echo -e "${BLUE}ℹ️ $1${NC}"; } AGENTS=(taizi zhongshu menxia shangshu hubu libu bingbu xingbu gongbu libu_hr zaochao) -ALL_RUNTIME_IDS=(taizi zhongshu menxia shangshu hubu libu bingbu xingbu gongbu libu_hr zaochao main) parse_args() { while [ "$#" -gt 0 ]; do @@ -59,13 +58,7 @@ parse_args() { # ── Step 0: 依赖检查 ────────────────────────────────────────── check_deps() { - info "检查依赖..." - - if ! command -v python3 &>/dev/null; then - error "未找到 python3" - exit 1 - fi - log "Python3: $(python3 --version)" + info "检查环境..." if [ ! -d "$OC_HOME" ]; then warn "未找到 OpenClaw 目录: $OC_HOME(可能已卸载)" @@ -149,15 +142,28 @@ unregister_agents() { return fi + if ! command -v python3 &>/dev/null; then + warn "未找到 python3,跳过 agents 注销" + warn "请手动编辑 openclaw.json 移除三省六部 agents" + return + fi + cp "$OC_CFG" "$OC_CFG.bak.sansheng-uninstall-$(date +%Y%m%d-%H%M%S)" log "已备份配置: $OC_CFG.bak.*" python3 << 'PYEOF' import json import pathlib +import tempfile +import shutil cfg_path = pathlib.Path.home() / '.openclaw' / 'openclaw.json' -cfg = json.loads(cfg_path.read_text()) + +try: + cfg = json.loads(cfg_path.read_text()) +except Exception as e: + print(f'ERROR: Failed to parse {cfg_path}: {e}') + exit(1) remove_ids = { 'taizi', 'zhongshu', 'menxia', 'shangshu', @@ -172,8 +178,17 @@ before = len(agents_list) agents_cfg['list'] = [a for a in agents_list if a.get('id') not in remove_ids] cfg['agents'] = agents_cfg -cfg_path.write_text(json.dumps(cfg, ensure_ascii=False, indent=2)) -print(f'Done: {before - len(agents_cfg["list"])} agents removed') +# 原子写入:先写临时文件,再 mv +temp_fd, temp_path = tempfile.mkstemp(dir=cfg_path.parent, suffix='.tmp') +try: + with open(temp_fd, 'w') as f: + json.dump(cfg, f, ensure_ascii=False, indent=2) + shutil.move(temp_path, cfg_path) + print(f'Done: {before - len(agents_cfg["list"])} agents removed') +except Exception as e: + pathlib.Path(temp_path).unlink(missing_ok=True) + print(f'ERROR: Failed to write config: {e}') + exit(1) PYEOF log "Agents 注销完成" @@ -210,52 +225,37 @@ cleanup_repo_data() { fi } -# ── Step 5: 严格深度清理(--purge)─────────────────────────── +# ── Step 5: 深度清理(--purge)─────────────────────────── purge_cleanup() { if ! $PURGE; then return fi - info "执行 --purge 严格深度清理..." + info "执行 --purge 深度清理..." - # 1) 删除 ~/.openclaw/agents 下相关目录(含 legacy main) - for agent in "${ALL_RUNTIME_IDS[@]}"; do + # 1) 删除 ~/.openclaw/agents 下相关目录(如果存在) + for agent in "${AGENTS[@]}"; do if [ -d "$OC_HOME/agents/$agent" ]; then rm -rf "$OC_HOME/agents/$agent" log "已删除: $OC_HOME/agents/$agent" fi done - # 2) 清理首次同步写入的 workspace scripts(含 legacy main) - for runtime_id in "${ALL_RUNTIME_IDS[@]}"; do - ws_scripts="$OC_HOME/workspace-$runtime_id/scripts" - if [ -d "$ws_scripts" ]; then - rm -rf "$ws_scripts" - log "已删除: $ws_scripts" - fi - done + # 2) 清理本项目生成的配置备份 + rm -f "$OC_CFG".bak.sansheng-* 2>/dev/null || true + log "已清理 openclaw.json 相关备份(sansheng 前缀)" - # 3) 删除可能由首次同步创建的 legacy 兼容目录 - if [ -d "$OC_HOME/workspace-main" ]; then - rmdir "$OC_HOME/workspace-main" 2>/dev/null || true + # 3) 清理安装脚本产生的备份(仅 pre-install-*, 不删 pre-uninstall-*) + if [ -d "$OC_HOME/backups" ]; then + rm -rf "$OC_HOME/backups"/pre-install-* 2>/dev/null || true + log "已清理 pre-install 备份" fi - # 4) 清理本项目生成的配置备份 - rm -f "$OC_CFG".bak.sansheng-* "$OC_CFG".bak.sansheng-uninstall-* 2>/dev/null || true - log "已清理 openclaw.json 相关备份(sansheng 前缀)" - - # 5) 清理本仓库 data 目录(若为空则删除) + # 4) 清理本仓库 data 目录(若为空则删除) if [ -d "$REPO_DIR/data" ] && [ -z "$(ls -A "$REPO_DIR/data" 2>/dev/null)" ]; then rmdir "$REPO_DIR/data" 2>/dev/null || true log "data 目录为空,已删除: $REPO_DIR/data" fi - - # 6) 清理 pre-uninstall/pre-install 备份(仅本项目脚本创建) - if [ -d "$OC_HOME/backups" ]; then - rm -rf "$OC_HOME/backups"/pre-uninstall-* 2>/dev/null || true - rm -rf "$OC_HOME/backups"/pre-install-* 2>/dev/null || true - log "已清理 pre-uninstall/pre-install 备份" - fi } # ── Step 6: 重启 Gateway ──────────────────────────────────── @@ -286,18 +286,20 @@ restart_gateway echo "" echo -e "${GREEN}╔══════════════════════════════════════════════════╗${NC}" if $PURGE; then - echo -e "${GREEN}║ 🧹 三省六部严格深度卸载完成(--purge)! ║${NC}" + echo -e "${GREEN}║ 🧹 三省六部深度卸载完成(--purge)! ║${NC}" else echo -e "${GREEN}║ 🧹 三省六部卸载完成! ║${NC}" fi echo -e "${GREEN}╚══════════════════════════════════════════════════╝${NC}" echo "" -echo "说明:" -echo " 1. 已移除三省六部 agents 注册与 workspace" -echo " 2. 已清理本仓库 data 下初始化文件" +echo "已执行:" +echo " 1. 备份现有数据到 ~/.openclaw/backups/pre-uninstall-*" +echo " 2. 删除三省六部 workspace(~/.openclaw/workspace-*)" +echo " 3. 从 openclaw.json 注销三省六部 agents" +echo " 4. 清理本仓库 data/ 下初始化文件" if $PURGE; then - echo " 3. 已执行严格深度清理(含 legacy main 兼容产物、同步脚本产物、备份清理)" + echo " 5. 深度清理(安装备份、sansheng-* 配置备份)" else - echo " 3. 如需严格深度清理,请执行: ./uninstall.sh --purge" + echo " 5. 如需深度清理,请执行: ./uninstall.sh --purge" fi echo ""