From d4993422718dd91845c6a0a22caeb516cdd4dc13 Mon Sep 17 00:00:00 2001 From: bookworm Date: Mon, 6 Apr 2026 13:48:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Mac=20=E6=94=AF=E6=8C=81=20v1.5=20?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=20+=20=E6=A8=A1=E6=9D=BF=E6=B8=85=E7=90=86?= =?UTF-8?q?=20+=20=E5=8D=B8=E8=BD=BD=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bookworm-Setup.sh: 重写为完整 Mac 安装器(依赖检测/代理/配置克隆/凭证解密/别名bw) - install-mac.sh: 新建重定向脚本,消除文档断链 - uninstall-mac.sh: 新建 Mac 卸载脚本(进程/凭证/历史/别名清理) - guide-mac.html: 修复所有过时引用(install-mac.sh/start-mac.sh/bookworm→bw) - settings.template.json: 从 boot 仓库移除(由 build-portable.js 管理) - prepare-repo.ps1/README/quick-reference: 更新模板引用 Co-Authored-By: Claude Opus 4.6 (1M context) --- Bookworm-Setup.sh | 329 ++++++++++++++++++++++++++--------------- README.txt | 2 +- generate-integrity.ps1 | 2 +- guide-mac.html | 65 ++++---- install-mac.sh | 8 + prepare-repo.ps1 | 15 +- quick-reference.txt | 1 - settings.template.json | 163 -------------------- uninstall-mac.sh | 181 +++++++++++++++++++++++ 9 files changed, 433 insertions(+), 333 deletions(-) create mode 100644 install-mac.sh delete mode 100644 settings.template.json create mode 100644 uninstall-mac.sh diff --git a/Bookworm-Setup.sh b/Bookworm-Setup.sh index 899aeae..4cb5f88 100644 --- a/Bookworm-Setup.sh +++ b/Bookworm-Setup.sh @@ -1,7 +1,12 @@ #!/bin/bash # ============================================================ -# Bookworm Portable - macOS One-Click Setup +# Bookworm Portable - macOS Setup (从 boot 仓库内运行) # Version: 1.5 +# +# 用法: cd ~/bookworm-boot && bash Bookworm-Setup.sh +# +# 前提: 已 git clone bookworm-boot 到本地 +# 功能: 检查依赖 → 代理检测 → 克隆配置 → 解密凭证 → 配置别名 # ============================================================ set -e @@ -12,18 +17,21 @@ GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' -NC='\033[0m' # No Color +NC='\033[0m' BOLD='\033[1m' # 配置 -GITEA_URL="https://code.letcareme.com/bookworm/bookworm-boot.git" -BOOT_DIR="$HOME/bookworm-boot" +BOOT_DIR="$(cd "$(dirname "$0")" && pwd)" +CLAUDE_DIR="$HOME/.claude" +CONFIG_REPO="https://code.letcareme.com/bookworm/bookworm-config.git" +SECRETS_ENC="$BOOT_DIR/secrets.enc" +TOTAL_STEPS=6 banner() { echo "" echo -e "${CYAN} ____ _" echo " | __ ) ___ ___ | | ____ _____ _ __ _ __ ___" - echo " | _ \\ / _ \\ / _ \\| |/ /\\ \\ /\\ / / _ \\| '__| '_ \` _ \\" + echo " | _ \\ / _ \\ / _ \\| |/ /\\ \\ /\\ / / _ \\| '__| '\` _ \\" echo " | |_) | (_) | (_) | < \\ V V / (_) | | | | | | | |" echo " |____/ \\___/ \\___/|_|\\_\\ \\_/\\_/ \\___/|_| |_| |_| |_|" echo "" @@ -32,16 +40,14 @@ banner() { echo -e "${NC}" } -info() { echo -e "${BLUE}[INFO]${NC} $1"; } -success() { echo -e "${GREEN}[OK]${NC} $1"; } -warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } -error() { echo -e "${RED}[ERROR]${NC} $1"; } -step() { echo -e "\n${BOLD}[$1/$TOTAL_STEPS]${NC} ${CYAN}$2${NC}"; } - -TOTAL_STEPS=6 +info() { echo -e " ${BLUE}[INFO]${NC} $1"; } +success() { echo -e " ${GREEN}[OK]${NC} $1"; } +warn() { echo -e " ${YELLOW}[!]${NC} $1"; } +fail() { echo -e " ${RED}[!!]${NC} $1"; } +step() { echo -e "\n${BOLD} [$1/$TOTAL_STEPS]${NC} ${CYAN}$2${NC}"; } # ============================================================ -# Step 0: Banner +# Banner # ============================================================ banner @@ -51,59 +57,60 @@ banner step 1 "检查依赖软件" # Homebrew -if ! command -v brew &> /dev/null; then - warn "Homebrew 未安装,正在安装..." +if ! command -v brew &>/dev/null; then + warn "Homebrew 未安装, 正在安装 (可能需要输入系统密码)..." /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - # Apple Silicon PATH if [ -f /opt/homebrew/bin/brew ]; then eval "$(/opt/homebrew/bin/brew shellenv)" - echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> "$HOME/.zprofile" + PROFILE="$HOME/.zprofile" + if ! grep -q 'homebrew' "$PROFILE" 2>/dev/null; then + echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> "$PROFILE" + fi fi success "Homebrew 安装完成" else - success "Homebrew $(brew --version | head -1)" + success "Homebrew $(brew --version | head -1 | awk '{print $2}')" fi # Node.js -if ! command -v node &> /dev/null; then - warn "Node.js 未安装,正在通过 Homebrew 安装..." +if ! command -v node &>/dev/null; then + info "通过 Homebrew 安装 Node.js..." brew install node - success "Node.js 安装完成" + success "Node.js $(node -v) 安装完成" else success "Node.js $(node -v)" fi # Git -if ! command -v git &> /dev/null; then - warn "Git 未安装,正在通过 Homebrew 安装..." +if ! command -v git &>/dev/null; then + info "通过 Homebrew 安装 Git..." brew install git - success "Git 安装完成" + success "Git $(git --version | awk '{print $3}') 安装完成" else - success "Git $(git --version)" + success "Git $(git --version | awk '{print $3}')" fi -# openssl +# OpenSSL OPENSSL_CMD="" -if command -v /opt/homebrew/opt/openssl/bin/openssl &> /dev/null; then - OPENSSL_CMD="/opt/homebrew/opt/openssl/bin/openssl" -elif command -v /usr/local/opt/openssl/bin/openssl &> /dev/null; then - OPENSSL_CMD="/usr/local/opt/openssl/bin/openssl" -elif command -v openssl &> /dev/null; then - OPENSSL_CMD="openssl" -fi +for p in /opt/homebrew/opt/openssl/bin/openssl /usr/local/opt/openssl/bin/openssl openssl; do + if command -v "$p" &>/dev/null; then + OPENSSL_CMD="$p" + break + fi +done if [ -z "$OPENSSL_CMD" ]; then - warn "OpenSSL 未找到,正在安装..." + info "通过 Homebrew 安装 OpenSSL..." brew install openssl OPENSSL_CMD="/opt/homebrew/opt/openssl/bin/openssl" success "OpenSSL 安装完成" else - success "OpenSSL: $($OPENSSL_CMD version)" + success "OpenSSL: $($OPENSSL_CMD version 2>/dev/null | head -1)" fi # Claude Code -if ! command -v claude &> /dev/null; then - warn "Claude Code 未安装,正在通过 npm 安装..." +if ! command -v claude &>/dev/null; then + info "通过 npm 安装 Claude Code..." npm i -g @anthropic-ai/claude-code success "Claude Code 安装完成" else @@ -115,82 +122,130 @@ fi # ============================================================ step 2 "检测网络代理" -# macOS 系统代理检测 -PROXY_DETECTED="" -if [ -n "$https_proxy" ] || [ -n "$HTTPS_PROXY" ]; then - PROXY_DETECTED="${HTTPS_PROXY:-$https_proxy}" - success "环境变量代理: $PROXY_DETECTED" -elif [ -n "$http_proxy" ] || [ -n "$HTTP_PROXY" ]; then - PROXY_DETECTED="${HTTP_PROXY:-$http_proxy}" - success "环境变量代理: $PROXY_DETECTED" -else - # 尝试从 macOS 网络设置检测 - SCUTIL_PROXY=$(scutil --proxy 2>/dev/null | grep -E "HTTPSPort|HTTPSProxy" || true) - if [ -n "$SCUTIL_PROXY" ]; then - PROXY_HOST=$(scutil --proxy 2>/dev/null | grep "HTTPSProxy" | awk '{print $3}') - PROXY_PORT=$(scutil --proxy 2>/dev/null | grep "HTTPSPort" | awk '{print $3}') - if [ -n "$PROXY_HOST" ] && [ "$PROXY_HOST" != "0" ]; then - PROXY_DETECTED="http://$PROXY_HOST:$PROXY_PORT" - export HTTPS_PROXY="$PROXY_DETECTED" - export HTTP_PROXY="$PROXY_DETECTED" - success "macOS 系统代理: $PROXY_DETECTED" - fi - fi - # 尝试常见端口 - if [ -z "$PROXY_DETECTED" ]; then - for PORT in 7890 7893 1087 1080 8118; do - if nc -z 127.0.0.1 $PORT 2>/dev/null; then - PROXY_DETECTED="http://127.0.0.1:$PORT" - export HTTPS_PROXY="$PROXY_DETECTED" - export HTTP_PROXY="$PROXY_DETECTED" - success "本地代理端口: $PROXY_DETECTED" - break - fi - done - fi -fi - -if [ -z "$PROXY_DETECTED" ]; then - warn "未检测到代理。如果在国内,Claude Code 可能无法启动。" - warn "请启动代理软件 (ClashX / Surge / V2Ray) 后重试。" -fi - -# NO_PROXY 设置 -export NO_PROXY="bww.letcareme.com,code.letcareme.com,localhost,127.0.0.1" +export NO_PROXY="bww.letcareme.com,code.letcareme.com,letcareme.com,localhost,127.0.0.1" export no_proxy="$NO_PROXY" -success "NO_PROXY 已设置: bww.letcareme.com,code.letcareme.com" -# ============================================================ -# Step 3: 克隆/更新引导仓库 -# ============================================================ -step 3 "同步引导仓库" +PROXY_FOUND="" -if [ -d "$BOOT_DIR/.git" ]; then - info "引导仓库已存在,正在更新..." - cd "$BOOT_DIR" - git pull --ff-only 2>/dev/null || git pull - success "引导仓库已更新" -else - info "正在克隆引导仓库..." - git clone "$GITEA_URL" "$BOOT_DIR" - cd "$BOOT_DIR" - success "引导仓库克隆完成" +# 环境变量 +if [ -n "$HTTPS_PROXY" ] || [ -n "$https_proxy" ]; then + PROXY_FOUND="${HTTPS_PROXY:-$https_proxy}" + success "环境变量代理: $PROXY_FOUND" fi -# ============================================================ -# Step 4: 运行安装脚本 -# ============================================================ -step 4 "执行安装" +# macOS 系统代理 +if [ -z "$PROXY_FOUND" ]; then + PROXY_HOST=$(scutil --proxy 2>/dev/null | grep "HTTPSProxy" | awk '{print $3}') + PROXY_PORT=$(scutil --proxy 2>/dev/null | grep "HTTPSPort" | awk '{print $3}') + if [ -n "$PROXY_HOST" ] && [ "$PROXY_HOST" != "0" ] && [ -n "$PROXY_PORT" ] && [ "$PROXY_PORT" != "0" ]; then + PROXY_FOUND="http://$PROXY_HOST:$PROXY_PORT" + export HTTPS_PROXY="$PROXY_FOUND" + export HTTP_PROXY="$PROXY_FOUND" + success "macOS 系统代理: $PROXY_FOUND" + fi +fi -if [ -f "$BOOT_DIR/install-mac.sh" ]; then - info "检测到 install-mac.sh,正在执行..." +# 常见端口扫描 (500ms 超时) +if [ -z "$PROXY_FOUND" ]; then + for PORT in 7890 7893 7891 1087 1080 8118; do + if nc -z -w1 127.0.0.1 $PORT 2>/dev/null; then + PROXY_FOUND="http://127.0.0.1:$PORT" + export HTTPS_PROXY="$PROXY_FOUND" + export HTTP_PROXY="$PROXY_FOUND" + success "本地代理端口: $PORT" + break + fi + done +fi + +if [ -z "$PROXY_FOUND" ]; then + warn "未检测到代理。在国内 Claude Code 可能无法启动。" + warn "请启动代理软件 (ClashX / Surge / V2Ray) 后重试。" + echo "" + read -p " 无代理继续? (y/n): " CONTINUE + if [ "$CONTINUE" != "y" ]; then exit 1; fi +fi + +success "NO_PROXY: bww.letcareme.com,code.letcareme.com" + +# ============================================================ +# Step 3: 克隆/更新配置仓库到 ~/.claude +# ============================================================ +step 3 "同步 Bookworm 配置" + +git config --global credential.helper osxkeychain 2>/dev/null || true + +if [ -d "$CLAUDE_DIR/.git" ]; then + info "配置仓库已存在, 更新..." + cd "$CLAUDE_DIR" && git pull --ff-only 2>/dev/null || git pull 2>/dev/null || true cd "$BOOT_DIR" - bash install-mac.sh + success "配置仓库已更新" +elif [ -f "$CLAUDE_DIR/CLAUDE.md" ]; then + warn "~/.claude 已存在但非 git 仓库, 备份后克隆..." + mv "$CLAUDE_DIR" "$CLAUDE_DIR.bak.$(date +%s)" + git clone --depth 1 "$CONFIG_REPO" "$CLAUDE_DIR" + success "配置仓库克隆完成 (旧目录已备份)" else - # 如果还没有 mac 专用脚本,提示用户 - warn "macOS 安装脚本尚未就绪。" - info "请联系管理员获取 install-mac.sh,或手动参考安装手册操作。" - info "安装手册: https://portable.bookwormweb.com/mac" + info "首次安装, 克隆配置仓库 (需输入 Gitea 密码)..." + mkdir -p "$(dirname "$CLAUDE_DIR")" + git clone --depth 1 "$CONFIG_REPO" "$CLAUDE_DIR" + success "配置仓库克隆完成" +fi + +# 创建本地运行时目录 +for d in debug sessions cache backups telemetry memory projects; do + mkdir -p "$CLAUDE_DIR/$d" 2>/dev/null +done + +# ============================================================ +# Step 4: 解密凭证 +# ============================================================ +step 4 "解密凭证" + +if [ -f "$SECRETS_ENC" ] && [ -n "$OPENSSL_CMD" ]; then + DECRYPTED="" + for attempt in 1 2 3; do + echo "" + read -rs -p " 输入主密码解密凭证 (第 $attempt/3 次): " PASSWORD + echo "" + DECRYPTED=$($OPENSSL_CMD enc -aes-256-cbc -d -pbkdf2 -iter 600000 -in "$SECRETS_ENC" -pass pass:"$PASSWORD" 2>/dev/null) || true + PASSWORD="" + if [ -n "$DECRYPTED" ]; then + while IFS= read -r line; do + [ -z "$line" ] && continue + key="${line%%=*}" + value="${line#*=}" + key=$(echo "$key" | tr -d ' ') + if [ -n "$key" ] && [ -n "$value" ]; then + export "$key=$value" + success "已注入: $key" + fi + done <<< "$DECRYPTED" + DECRYPTED="" + break + else + if [ $attempt -lt 3 ]; then + warn "密码错误, 剩余重试: $((3 - attempt)) 次" + else + fail "3 次密码均错误, 凭证未解密" + warn "可稍后手动配置 API Key" + fi + fi + done +else + if [ ! -f "$SECRETS_ENC" ]; then + warn "secrets.enc 不存在, 跳过凭证解密" + info "请联系管理员获取加密凭证文件" + fi +fi + +# 渲染 settings.json (替换占位符) +TEMPLATE_FILE="$CLAUDE_DIR/settings.template.json" +SETTINGS_FILE="$CLAUDE_DIR/settings.json" +if [ -f "$TEMPLATE_FILE" ]; then + CLAUDE_ROOT=$(echo "$CLAUDE_DIR" | sed 's/\\/\//g') + sed "s|{{CLAUDE_ROOT}}|$CLAUDE_ROOT|g; s|{{HOME}}|$HOME|g" "$TEMPLATE_FILE" > "$SETTINGS_FILE" + success "settings.json 已渲染" fi # ============================================================ @@ -198,20 +253,37 @@ fi # ============================================================ step 5 "配置终端快捷命令" -ZSHRC="$HOME/.zshrc" -ALIAS_MARKER="# Bookworm Portable aliases" +SHELL_RC="$HOME/.zshrc" +if [ -n "$BASH_VERSION" ] && [ -f "$HOME/.bashrc" ]; then + SHELL_RC="$HOME/.bashrc" +fi -if ! grep -q "$ALIAS_MARKER" "$ZSHRC" 2>/dev/null; then - cat >> "$ZSHRC" << 'ALIASES' +ALIAS_MARKER="# Bookworm Portable aliases" +if ! grep -q "$ALIAS_MARKER" "$SHELL_RC" 2>/dev/null; then + cat >> "$SHELL_RC" << 'ALIASES' # Bookworm Portable aliases -alias bookworm='cd ~/bookworm-boot && bash start-mac.sh' -alias bookworm-update='cd ~/bookworm-boot && bash install-mac.sh' -alias bookworm-stop='cd ~/bookworm-boot && bash stop-mac.sh' +alias bw='NO_PROXY="bww.letcareme.com,code.letcareme.com,localhost,127.0.0.1" claude' +alias bw-update='cd ~/bookworm-boot && git pull && cd ~/.claude && git pull && echo "Updated!"' ALIASES - success "已添加别名到 ~/.zshrc (bookworm / bookworm-update / bookworm-stop)" + success "已添加到 $SHELL_RC:" + info " bw -- 启动 Bookworm" + info " bw-update -- 更新 Bookworm" else - success "终端别名已配置" + # 更新旧别名 (bookworm → bw) + if grep -q "alias bookworm=" "$SHELL_RC" 2>/dev/null; then + # 删除旧别名块,然后追加新的 + sed -i '' '/# Bookworm Portable aliases/,/^$/d' "$SHELL_RC" 2>/dev/null || true + cat >> "$SHELL_RC" << 'ALIASES' + +# Bookworm Portable aliases +alias bw='NO_PROXY="bww.letcareme.com,code.letcareme.com,localhost,127.0.0.1" claude' +alias bw-update='cd ~/bookworm-boot && git pull && cd ~/.claude && git pull && echo "Updated!"' +ALIASES + success "终端别名已更新 (bookworm → bw)" + else + success "终端别名已配置" + fi fi # ============================================================ @@ -220,13 +292,28 @@ fi step 6 "安装完成" echo "" -echo -e "${GREEN}============================================================${NC}" -echo -e "${GREEN} Bookworm Portable for macOS 安装完成!${NC}" -echo -e "${GREEN}============================================================${NC}" +echo -e "${GREEN} ============================================================${NC}" +echo -e "${GREEN} Bookworm Smart Assistant for macOS 安装完成!${NC}" +echo -e "${GREEN} ============================================================${NC}" echo "" -echo -e " ${BOLD}日常启动:${NC} 在终端输入 ${CYAN}bookworm${NC}" -echo -e " ${BOLD}同步更新:${NC} 在终端输入 ${CYAN}bookworm-update${NC}" -echo -e " ${BOLD}卸载清理:${NC} 在终端输入 ${CYAN}bookworm-stop${NC}" +echo -e " 已安装:" +echo -e " ${GREEN}[v]${NC} Homebrew ${GREEN}[v]${NC} Node.js $(node -v 2>/dev/null)" +echo -e " ${GREEN}[v]${NC} Git ${GREEN}[v]${NC} OpenSSL" +echo -e " ${GREEN}[v]${NC} Claude Code ${GREEN}[v]${NC} Bookworm (92 Skills)" echo "" -echo -e " ${BLUE}安装手册:${NC} https://portable.bookwormweb.com/mac" +echo -e " ${BOLD}启动方式:${NC}" +echo -e " 终端输入: ${CYAN}bw${NC}" echo "" +echo -e " ${BOLD}更新:${NC}" +echo -e " 终端输入: ${CYAN}bw-update${NC}" +echo "" + +# 询问是否立即启动 +read -p " 立即启动 Bookworm? (y/n): " START_NOW +if [ "$START_NOW" = "y" ] || [ "$START_NOW" = "Y" ]; then + echo "" + info "正在启动 Claude Code..." + cd "$HOME" + export NO_PROXY="bww.letcareme.com,code.letcareme.com,letcareme.com,localhost,127.0.0.1" + exec claude +fi diff --git a/README.txt b/README.txt index 3740988..b316869 100644 --- a/README.txt +++ b/README.txt @@ -6,8 +6,8 @@ deploy-gitea.sh ECS Gitea 部署 (服务端,执行一次) prepare-repo.ps1 仓库准备 (本机执行一次) encrypt-secrets.ps1 凭证加密 (本机执行一次) - settings.template.json settings.json 模板 settings.local.template.json settings.local.json 模板 (权限白名单) + (settings.template.json 已由 build-portable.js 管理,存于 config 仓库) install.ps1 安装/启动 (目标机执行) stop.ps1 清理/卸载 (目标机执行) diff --git a/generate-integrity.ps1 b/generate-integrity.ps1 index 77e6ffc..98a7506 100644 --- a/generate-integrity.ps1 +++ b/generate-integrity.ps1 @@ -25,7 +25,7 @@ $patterns = @( "hooks/lib/*.js", "scripts/paths.config.js", "CLAUDE.md", - "settings.template.json", + "settings.json", "settings.local.template.json" ) diff --git a/guide-mac.html b/guide-mac.html index 695c820..9f13633 100644 --- a/guide-mac.html +++ b/guide-mac.html @@ -439,9 +439,9 @@
- bash install-mac.sh + bash Bookworm-Setup.sh
-

如果提示权限不足:chmod +x install-mac.sh && ./install-mac.sh

+

如果提示权限不足:chmod +x Bookworm-Setup.sh && ./Bookworm-Setup.sh

3
@@ -464,14 +464,12 @@

等待完成

脚本会显示步骤进度 [1/8] 到 [8/8],自动完成:

    -
  • [1/8] 前置检查 (Claude Code / Node.js / Git / openssl)
  • -
  • [2/8] 自动检测代理 + 设置 NO_PROXY
  • -
  • [3/8] 解密凭证 (输入主密码)
  • -
  • [4/8] 同步配置 (下载 92 个 Skills)
  • -
  • [5/8] 完整性校验 (SHA256 哈希验证)
  • -
  • [6/8] 渲染配置模板
  • -
  • [7/8] Bookworm 系统验证 + MCP 检查
  • -
  • [8/8] 启动 Claude Code
  • +
  • [1/6] 检查依赖 (Homebrew / Node.js / Git / OpenSSL / Claude Code)
  • +
  • [2/6] 自动检测代理 + 设置 NO_PROXY
  • +
  • [3/6] 同步配置 (克隆/更新 92 个 Skills)
  • +
  • [4/6] 解密凭证 (输入主密码) + 渲染配置模板
  • +
  • [5/6] 配置终端别名 (bw / bw-update)
  • +
  • [6/6] 完成 — 可选立即启动
@@ -505,8 +503,8 @@

安装脚本已自动添加别名到 ~/.zshrc,直接在终端输入:

- bookworm # 快速启动 -bookworm-update # 同步更新后启动 + bw # 快速启动 +bw-update # 同步更新
@@ -517,13 +515,13 @@ 操作命令说明 快速启动 - cd ~/bookworm-boot && bash start-mac.sh - 直接启动,不更新配置 + bw + 直接启动 Claude Code + Bookworm 同步更新 - cd ~/bookworm-boot && bash install-mac.sh - 先同步最新 Skills 再启动 + bw-update + 更新 boot + 配置仓库 @@ -531,7 +529,7 @@ 💡
启动时显示 "有 N 个新更新可用"?
- 说明管理员更新了 Skills 或 Hooks。执行 bookworm-update 即可同步。 + 说明管理员更新了 Skills 或 Hooks。执行 bw-update 即可同步。
@@ -582,18 +580,18 @@ 场景命令说明 基础清理 - bash stop-mac.sh - 清除环境变量,保留配置供下次快速启动 + rm -rf ~/.claude + 删除 Bookworm 配置,保留引导仓库供重新安装 完整恢复 - bash stop-mac.sh --restore - 删除 Bookworm,恢复电脑原始状态 + rm -rf ~/.claude ~/bookworm-boot + 删除所有 Bookworm 文件 深度清理 - bash stop-mac.sh --restore --deep - 完整恢复 + 清除历史 + 清除 Git 凭证 + 钥匙串 + rm -rf ~/.claude ~/bookworm-boot && sed -i '' '/Bookworm Portable/,+2d' ~/.zshrc && git credential-osxkeychain erase <<< "host=code.letcareme.com" + 完整恢复 + 清除别名 + 清除 Git 凭证 @@ -601,7 +599,7 @@
在他人电脑/公用电脑上务必清理:
- 执行 cd ~/bookworm-boot && bash stop-mac.sh --restore --deep + 执行深度清理命令,确保不留下任何凭证或配置
@@ -678,8 +676,7 @@ export NO_PROXY="bww.letcareme.com,code.letcareme.com" # 重新启动 -cd ~/bookworm-boot -bash start-mac.sh +bw

或在代理软件中将 *.letcareme.com 加入直连规则。

@@ -688,8 +685,8 @@

原因:API 凭证是进程级环境变量,只在安装脚本启动的进程中有效。

解决:不要直接运行 claude,必须通过以下方式启动:

@@ -740,12 +737,12 @@

快速参考

- - - - - - + + + + + +
操作快捷方式完整命令
首次安装git clone + bash install-mac.shcd ~/bookworm-boot && bash install-mac.sh
快速启动bookwormcd ~/bookworm-boot && bash start-mac.sh
同步更新bookworm-updatecd ~/bookworm-boot && bash install-mac.sh
基础清理cd ~/bookworm-boot && bash stop-mac.sh
完整恢复cd ~/bookworm-boot && bash stop-mac.sh --restore
深度清理cd ~/bookworm-boot && bash stop-mac.sh --restore --deep
首次安装git clone + bash Bookworm-Setup.shcd ~/bookworm-boot && bash Bookworm-Setup.sh
快速启动bwNO_PROXY="bww.letcareme.com,code.letcareme.com,localhost,127.0.0.1" claude
同步更新bw-updatecd ~/bookworm-boot && git pull && cd ~/.claude && git pull
基础清理rm -rf ~/.claude
完整恢复rm -rf ~/.claude ~/bookworm-boot
深度清理rm -rf ~/.claude ~/bookworm-boot && sed -i '' '/Bookworm/,+2d' ~/.zshrc
diff --git a/install-mac.sh b/install-mac.sh new file mode 100644 index 0000000..db313e5 --- /dev/null +++ b/install-mac.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# ============================================================ +# install-mac.sh — 重定向到 Bookworm-Setup.sh +# +# 多个文档引用此文件名,实际安装逻辑在 Bookworm-Setup.sh 中。 +# ============================================================ +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +exec bash "$SCRIPT_DIR/Bookworm-Setup.sh" "$@" diff --git a/prepare-repo.ps1 b/prepare-repo.ps1 index 4915728..4e7c7ce 100644 --- a/prepare-repo.ps1 +++ b/prepare-repo.ps1 @@ -27,18 +27,9 @@ if (-not (Test-Path $ClaudeDir)) { exit 1 } -# 1. 拷贝 settings.template.json +# 1. settings.template.json (由 build-portable.js 自动生成,无需手动拷贝) $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$templateSrc = Join-Path $ScriptDir "settings.template.json" -$templateDst = Join-Path $ClaudeDir "settings.template.json" - -if (Test-Path $templateSrc) { - Copy-Item $templateSrc $templateDst -Force - Write-Host "[1/6] settings.template.json 已放入 .claude/" -ForegroundColor Green -} -else { - Write-Host "[1/6] [WARN] settings.template.json 不在脚本目录,请手动创建" -ForegroundColor Yellow -} +Write-Host "[1/6] settings.template.json 由 build-portable.js 管理,跳过" -ForegroundColor Gray # 2. 创建 .gitignore Write-Host "[2/6] 生成 .gitignore..." -ForegroundColor White @@ -165,7 +156,7 @@ Write-Host "[5/6] 提交..." -ForegroundColor White git commit -m "Bookworm v6.5.1 portable commit Includes: CLAUDE.md, skills (92), agents (18), hooks (29), -scripts, constitution, settings.template.json +scripts, constitution Excludes: credentials, mcp-servers, node_modules, cache, sessions, debug logs, project-specific data, gstack/browse binaries" diff --git a/quick-reference.txt b/quick-reference.txt index d249d7c..20f5965 100644 --- a/quick-reference.txt +++ b/quick-reference.txt @@ -279,7 +279,6 @@ ├── deploy-gitea.sh Gitea 部署 (ECS) ├── setup-https.sh HTTPS 配置 (ECS) ├── secure-firewall.sh 防火墙加固 (ECS) - ├── settings.template.json settings.json 模板 ├── settings.local.template.json settings.local.json 模板 ├── guide.html HTML 保姆式教程 ├── quick-reference.txt 本文档 diff --git a/settings.template.json b/settings.template.json deleted file mode 100644 index ce2a4f2..0000000 --- a/settings.template.json +++ /dev/null @@ -1,163 +0,0 @@ -{ - "env": { - "HOME": "{{HOME}}" - }, - "permissions": { - "allow": [ - "Read", - "Write", - "Edit", - "Glob", - "Grep", - "WebSearch", - "WebFetch", - "Skill", - "Task", - "TaskCreate", - "TaskUpdate", - "TaskList", - "TaskGet", - "Agent", - "AskUserQuestion" - ] - }, - "hooks": { - "UserPromptSubmit": [ - { - "hooks": [ - { - "type": "command", - "command": "node {{CLAUDE_ROOT}}/hooks/nda-probe-detector.js", - "timeout": 2000 - } - ] - }, - { - "hooks": [ - { - "type": "command", - "command": "node {{CLAUDE_ROOT}}/hooks/prompt-dispatcher.js", - "timeout": 3000 - } - ] - }, - { - "hooks": [ - { - "type": "command", - "command": "node {{CLAUDE_ROOT}}/hooks/clipboard-image-hook.js", - "timeout": 5000 - } - ] - } - ], - "PreToolUse": [ - { - "matcher": "Read|Glob|Grep", - "hooks": [ - { - "type": "command", - "command": "node {{CLAUDE_ROOT}}/hooks/nda-read-guard.js", - "timeout": 2000 - } - ] - }, - { - "matcher": "Bash", - "hooks": [ - { - "type": "command", - "command": "node {{CLAUDE_ROOT}}/hooks/bash-precheck-dispatcher.js", - "timeout": 5000 - } - ] - }, - { - "matcher": "Skill", - "hooks": [ - { - "type": "command", - "command": "node {{CLAUDE_ROOT}}/hooks/route-compliance-gate.js", - "timeout": 2000 - } - ] - }, - { - "matcher": "mcp__", - "hooks": [ - { - "type": "command", - "command": "node {{CLAUDE_ROOT}}/hooks/mcp-safety-gate.js", - "timeout": 3000 - } - ] - } - ], - "PostToolUse": [ - { - "matcher": "Edit|Write|NotebookEdit", - "hooks": [ - { - "type": "command", - "command": "node {{CLAUDE_ROOT}}/hooks/post-edit-dispatcher.js", - "timeout": 8000 - } - ] - }, - { - "matcher": "Edit|Write|Skill|Agent|Bash|mcp__.*", - "hooks": [ - { - "type": "command", - "command": "node {{CLAUDE_ROOT}}/hooks/activity-logger.js", - "timeout": 2000 - } - ] - }, - { - "matcher": "Edit|Write|Skill|Agent|Bash|mcp__.*", - "hooks": [ - { - "type": "command", - "command": "node {{CLAUDE_ROOT}}/hooks/session-heartbeat.js", - "timeout": 2000 - } - ] - }, - { - "matcher": "Bash", - "hooks": [ - { - "type": "command", - "command": "node {{CLAUDE_ROOT}}/hooks/build-outcome-tracker.js", - "timeout": 3000 - } - ] - } - ], - "SubagentStart": [ - { - "hooks": [ - { - "type": "command", - "command": "node {{CLAUDE_ROOT}}/hooks/subagent-route-injector.js", - "timeout": 2000 - } - ] - } - ], - "Stop": [ - { - "hooks": [ - { - "type": "command", - "command": "node {{CLAUDE_ROOT}}/hooks/stop-dispatcher.js 2>>{{CLAUDE_ROOT}}/debug/hook-errors.log || true", - "timeout": 5000 - } - ] - } - ] - }, - "effortLevel": "high", - "skipDangerousModePermissionPrompt": true -} diff --git a/uninstall-mac.sh b/uninstall-mac.sh new file mode 100644 index 0000000..79d402a --- /dev/null +++ b/uninstall-mac.sh @@ -0,0 +1,181 @@ +#!/bin/bash +# ============================================================ +# Bookworm Portable - macOS 卸载脚本 +# 对标 Windows 版 stop.ps1 + 卸载Bookworm.bat +# +# 用法: +# bash uninstall-mac.sh # 基础清理 (保留配置) +# bash uninstall-mac.sh --restore # 完整恢复 (删除 Bookworm) +# bash uninstall-mac.sh --deep # 深度清理 (含历史+凭证) +# ============================================================ + +set -e + +# 颜色 +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' +BLUE='\033[0;34m'; CYAN='\033[0;36m'; NC='\033[0m'; BOLD='\033[1m' + +# 路径 +CLAUDE_DIR="$HOME/.claude" +BACKUP_DIR="$HOME/.claude.bw-backup" +BOOT_DIR="$HOME/bookworm-boot" + +# 参数解析 +RESTORE=false +DEEP=false +for arg in "$@"; do + case "$arg" in + --restore) RESTORE=true ;; + --deep) DEEP=true ;; + esac +done + +info() { echo -e " ${BLUE}[INFO]${NC} $1"; } +success() { echo -e " ${GREEN}[OK]${NC} $1"; } +warn() { echo -e " ${YELLOW}[!]${NC} $1"; } +fail() { echo -e " ${RED}[!!]${NC} $1"; } + +echo "" +echo -e "${CYAN} Bookworm Portable - macOS 卸载${NC}" +echo -e "${CYAN} ================================${NC}" +echo "" + +if $RESTORE || $DEEP; then + echo -e " 将执行:" + echo -e " - 终止 Claude Code 进程" + echo -e " - 清除环境变量" + $RESTORE && echo -e " - 删除 ~/.claude 配置目录" + $RESTORE && echo -e " - 恢复原始 .claude 备份 (如有)" + $DEEP && echo -e " - 清除 shell 历史敏感条目" + $DEEP && echo -e " - 清除 Git 凭证 (Keychain)" + $DEEP && echo -e " - 清除终端别名" + echo "" + read -p " 确认卸载? (y/n): " CONFIRM + if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then + echo " 已取消" + exit 0 + fi +fi + +echo "" + +# ─── 1/5: 终止 Claude Code 进程 ─── +echo -e "${BOLD} [1/5]${NC} 终止 Claude Code 进程..." + +CLAUDE_PIDS=$(pgrep -f "claude" 2>/dev/null || true) +if [ -n "$CLAUDE_PIDS" ]; then + kill $CLAUDE_PIDS 2>/dev/null || true + sleep 2 + # 强制终止残留 + kill -9 $CLAUDE_PIDS 2>/dev/null || true + success "进程已终止" +else + info "无 Claude Code 进程运行" +fi + +# 清理残留 node hook 进程 +NODE_HOOK_PIDS=$(pgrep -f "\.claude/hooks" 2>/dev/null || true) +if [ -n "$NODE_HOOK_PIDS" ]; then + kill $NODE_HOOK_PIDS 2>/dev/null || true + info "Hook 子进程已清理" +fi + +# ─── 2/5: 清除环境变量 ─── +echo -e "${BOLD} [2/5]${NC} 清除环境变量..." + +ENV_VARS=( + CLAUDE_HOME CLAUDE_ROOT ANTHROPIC_API_KEY + ANTHROPIC_BASE_URL SUPABASE_ACCESS_TOKEN + GITHUB_PERSONAL_ACCESS_TOKEN SLACK_BOT_TOKEN + ATLASSIAN_API_TOKEN BROWSERBASE_API_KEY + FIRECRAWL_API_KEY +) +CLEARED=0 +for v in "${ENV_VARS[@]}"; do + if [ -n "${!v}" ]; then + unset "$v" + CLEARED=$((CLEARED + 1)) + fi +done +success "已清除 $CLEARED 个环境变量" + +# ─── 3/5: Git 凭证清除 ─── +echo -e "${BOLD} [3/5]${NC} 清除 Git 凭证缓存..." + +# macOS Keychain 凭证 +for host in code.letcareme.com 8.138.11.105; do + security delete-internet-password -s "$host" 2>/dev/null && info "Keychain: $host 已清除" || true + # git credential reject + printf "protocol=https\nhost=%s\n\n" "$host" | git credential reject 2>/dev/null || true +done +success "Git 凭证已清除" + +# ─── 4/5: 恢复/删除 .claude 目录 ─── +if $RESTORE; then + echo -e "${BOLD} [4/5]${NC} 恢复原始 .claude 目录..." + + if [ -d "$CLAUDE_DIR" ]; then + rm -rf "$CLAUDE_DIR" + info "已删除 Bookworm 配置" + fi + + if [ -d "$BACKUP_DIR" ]; then + mv "$BACKUP_DIR" "$CLAUDE_DIR" + success "原始 .claude 已恢复" + else + warn "无备份可恢复 (.claude.bw-backup 不存在)" + fi + + # 删除 boot 仓库 + if [ -d "$BOOT_DIR" ]; then + rm -rf "$BOOT_DIR" + info "已删除 ~/bookworm-boot" + fi +else + echo -e "${BOLD} [4/5]${NC} 保留 Bookworm 配置 (使用 --restore 可恢复原始)" +fi + +# ─── 5/5: 深度清理 ─── +if $DEEP; then + echo -e "${BOLD} [5/5]${NC} 深度清理..." + + # 清除 shell 历史中的敏感条目 + for histfile in "$HOME/.zsh_history" "$HOME/.bash_history"; do + if [ -f "$histfile" ]; then + BEFORE=$(wc -l < "$histfile") + grep -v -i -E 'secrets\.enc|ANTHROPIC_API_KEY|api[_-]?key|bookworm-portable|主密码' "$histfile" > "${histfile}.tmp" 2>/dev/null || true + mv "${histfile}.tmp" "$histfile" 2>/dev/null || true + AFTER=$(wc -l < "$histfile") + info "$(basename $histfile): 清理 $((BEFORE - AFTER)) 条敏感记录" + fi + done + + # 清除终端别名 + for rcfile in "$HOME/.zshrc" "$HOME/.bashrc"; do + if [ -f "$rcfile" ] && grep -q "Bookworm Portable aliases" "$rcfile" 2>/dev/null; then + # 删除别名块 (标记行 + 后续 alias 行) + sed -i '' '/# Bookworm Portable aliases/,/^$/d' "$rcfile" 2>/dev/null || true + info "$(basename $rcfile): 别名已清除" + fi + done + + # 清除 macOS Keychain 中的 Bookworm 凭证 + security delete-generic-password -s "bookworm-secrets" 2>/dev/null && info "Keychain: bookworm-secrets 已清除" || true + + success "深度清理完成" +else + echo -e "${BOLD} [5/5]${NC} 跳过深度清理 (使用 --deep 可清理历史+凭证)" +fi + +# ─── 完成 ─── +echo "" +echo -e "${GREEN} ================================${NC}" +if $RESTORE; then + echo -e "${GREEN} Bookworm 已完全卸载${NC}" + echo -e "${GREEN} 可安全删除 bookworm-boot 文件夹${NC}" +else + echo -e "${GREEN} Bookworm 已清理完毕${NC}" + echo -e "${GREEN} 配置保留,可重新启动${NC}" +fi +echo -e "${GREEN} ================================${NC}" +echo ""