feat: Mac 支持 v1.5 同步 + 模板清理 + 卸载脚本
- 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) <noreply@anthropic.com>
This commit is contained in:
parent
83c1e613a1
commit
d499342271
@ -1,7 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Bookworm Portable - macOS One-Click Setup
|
# Bookworm Portable - macOS Setup (从 boot 仓库内运行)
|
||||||
# Version: 1.5
|
# Version: 1.5
|
||||||
|
#
|
||||||
|
# 用法: cd ~/bookworm-boot && bash Bookworm-Setup.sh
|
||||||
|
#
|
||||||
|
# 前提: 已 git clone bookworm-boot 到本地
|
||||||
|
# 功能: 检查依赖 → 代理检测 → 克隆配置 → 解密凭证 → 配置别名
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
@ -12,18 +17,21 @@ GREEN='\033[0;32m'
|
|||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
BLUE='\033[0;34m'
|
BLUE='\033[0;34m'
|
||||||
CYAN='\033[0;36m'
|
CYAN='\033[0;36m'
|
||||||
NC='\033[0m' # No Color
|
NC='\033[0m'
|
||||||
BOLD='\033[1m'
|
BOLD='\033[1m'
|
||||||
|
|
||||||
# 配置
|
# 配置
|
||||||
GITEA_URL="https://code.letcareme.com/bookworm/bookworm-boot.git"
|
BOOT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
BOOT_DIR="$HOME/bookworm-boot"
|
CLAUDE_DIR="$HOME/.claude"
|
||||||
|
CONFIG_REPO="https://code.letcareme.com/bookworm/bookworm-config.git"
|
||||||
|
SECRETS_ENC="$BOOT_DIR/secrets.enc"
|
||||||
|
TOTAL_STEPS=6
|
||||||
|
|
||||||
banner() {
|
banner() {
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${CYAN} ____ _"
|
echo -e "${CYAN} ____ _"
|
||||||
echo " | __ ) ___ ___ | | ____ _____ _ __ _ __ ___"
|
echo " | __ ) ___ ___ | | ____ _____ _ __ _ __ ___"
|
||||||
echo " | _ \\ / _ \\ / _ \\| |/ /\\ \\ /\\ / / _ \\| '__| '_ \` _ \\"
|
echo " | _ \\ / _ \\ / _ \\| |/ /\\ \\ /\\ / / _ \\| '__| '\` _ \\"
|
||||||
echo " | |_) | (_) | (_) | < \\ V V / (_) | | | | | | | |"
|
echo " | |_) | (_) | (_) | < \\ V V / (_) | | | | | | | |"
|
||||||
echo " |____/ \\___/ \\___/|_|\\_\\ \\_/\\_/ \\___/|_| |_| |_| |_|"
|
echo " |____/ \\___/ \\___/|_|\\_\\ \\_/\\_/ \\___/|_| |_| |_| |_|"
|
||||||
echo ""
|
echo ""
|
||||||
@ -32,16 +40,14 @@ banner() {
|
|||||||
echo -e "${NC}"
|
echo -e "${NC}"
|
||||||
}
|
}
|
||||||
|
|
||||||
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
info() { echo -e " ${BLUE}[INFO]${NC} $1"; }
|
||||||
success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
success() { echo -e " ${GREEN}[OK]${NC} $1"; }
|
||||||
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
warn() { echo -e " ${YELLOW}[!]${NC} $1"; }
|
||||||
error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
fail() { echo -e " ${RED}[!!]${NC} $1"; }
|
||||||
step() { echo -e "\n${BOLD}[$1/$TOTAL_STEPS]${NC} ${CYAN}$2${NC}"; }
|
step() { echo -e "\n${BOLD} [$1/$TOTAL_STEPS]${NC} ${CYAN}$2${NC}"; }
|
||||||
|
|
||||||
TOTAL_STEPS=6
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Step 0: Banner
|
# Banner
|
||||||
# ============================================================
|
# ============================================================
|
||||||
banner
|
banner
|
||||||
|
|
||||||
@ -51,59 +57,60 @@ banner
|
|||||||
step 1 "检查依赖软件"
|
step 1 "检查依赖软件"
|
||||||
|
|
||||||
# Homebrew
|
# Homebrew
|
||||||
if ! command -v brew &> /dev/null; then
|
if ! command -v brew &>/dev/null; then
|
||||||
warn "Homebrew 未安装,正在安装..."
|
warn "Homebrew 未安装, 正在安装 (可能需要输入系统密码)..."
|
||||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||||
# Apple Silicon PATH
|
|
||||||
if [ -f /opt/homebrew/bin/brew ]; then
|
if [ -f /opt/homebrew/bin/brew ]; then
|
||||||
eval "$(/opt/homebrew/bin/brew shellenv)"
|
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
|
fi
|
||||||
success "Homebrew 安装完成"
|
success "Homebrew 安装完成"
|
||||||
else
|
else
|
||||||
success "Homebrew $(brew --version | head -1)"
|
success "Homebrew $(brew --version | head -1 | awk '{print $2}')"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Node.js
|
# Node.js
|
||||||
if ! command -v node &> /dev/null; then
|
if ! command -v node &>/dev/null; then
|
||||||
warn "Node.js 未安装,正在通过 Homebrew 安装..."
|
info "通过 Homebrew 安装 Node.js..."
|
||||||
brew install node
|
brew install node
|
||||||
success "Node.js 安装完成"
|
success "Node.js $(node -v) 安装完成"
|
||||||
else
|
else
|
||||||
success "Node.js $(node -v)"
|
success "Node.js $(node -v)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Git
|
# Git
|
||||||
if ! command -v git &> /dev/null; then
|
if ! command -v git &>/dev/null; then
|
||||||
warn "Git 未安装,正在通过 Homebrew 安装..."
|
info "通过 Homebrew 安装 Git..."
|
||||||
brew install git
|
brew install git
|
||||||
success "Git 安装完成"
|
success "Git $(git --version | awk '{print $3}') 安装完成"
|
||||||
else
|
else
|
||||||
success "Git $(git --version)"
|
success "Git $(git --version | awk '{print $3}')"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# openssl
|
# OpenSSL
|
||||||
OPENSSL_CMD=""
|
OPENSSL_CMD=""
|
||||||
if command -v /opt/homebrew/opt/openssl/bin/openssl &> /dev/null; then
|
for p in /opt/homebrew/opt/openssl/bin/openssl /usr/local/opt/openssl/bin/openssl openssl; do
|
||||||
OPENSSL_CMD="/opt/homebrew/opt/openssl/bin/openssl"
|
if command -v "$p" &>/dev/null; then
|
||||||
elif command -v /usr/local/opt/openssl/bin/openssl &> /dev/null; then
|
OPENSSL_CMD="$p"
|
||||||
OPENSSL_CMD="/usr/local/opt/openssl/bin/openssl"
|
break
|
||||||
elif command -v openssl &> /dev/null; then
|
fi
|
||||||
OPENSSL_CMD="openssl"
|
done
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$OPENSSL_CMD" ]; then
|
if [ -z "$OPENSSL_CMD" ]; then
|
||||||
warn "OpenSSL 未找到,正在安装..."
|
info "通过 Homebrew 安装 OpenSSL..."
|
||||||
brew install openssl
|
brew install openssl
|
||||||
OPENSSL_CMD="/opt/homebrew/opt/openssl/bin/openssl"
|
OPENSSL_CMD="/opt/homebrew/opt/openssl/bin/openssl"
|
||||||
success "OpenSSL 安装完成"
|
success "OpenSSL 安装完成"
|
||||||
else
|
else
|
||||||
success "OpenSSL: $($OPENSSL_CMD version)"
|
success "OpenSSL: $($OPENSSL_CMD version 2>/dev/null | head -1)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Claude Code
|
# Claude Code
|
||||||
if ! command -v claude &> /dev/null; then
|
if ! command -v claude &>/dev/null; then
|
||||||
warn "Claude Code 未安装,正在通过 npm 安装..."
|
info "通过 npm 安装 Claude Code..."
|
||||||
npm i -g @anthropic-ai/claude-code
|
npm i -g @anthropic-ai/claude-code
|
||||||
success "Claude Code 安装完成"
|
success "Claude Code 安装完成"
|
||||||
else
|
else
|
||||||
@ -115,82 +122,130 @@ fi
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
step 2 "检测网络代理"
|
step 2 "检测网络代理"
|
||||||
|
|
||||||
# macOS 系统代理检测
|
export NO_PROXY="bww.letcareme.com,code.letcareme.com,letcareme.com,localhost,127.0.0.1"
|
||||||
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="$NO_PROXY"
|
export no_proxy="$NO_PROXY"
|
||||||
success "NO_PROXY 已设置: bww.letcareme.com,code.letcareme.com"
|
|
||||||
|
|
||||||
# ============================================================
|
PROXY_FOUND=""
|
||||||
# Step 3: 克隆/更新引导仓库
|
|
||||||
# ============================================================
|
|
||||||
step 3 "同步引导仓库"
|
|
||||||
|
|
||||||
if [ -d "$BOOT_DIR/.git" ]; then
|
# 环境变量
|
||||||
info "引导仓库已存在,正在更新..."
|
if [ -n "$HTTPS_PROXY" ] || [ -n "$https_proxy" ]; then
|
||||||
cd "$BOOT_DIR"
|
PROXY_FOUND="${HTTPS_PROXY:-$https_proxy}"
|
||||||
git pull --ff-only 2>/dev/null || git pull
|
success "环境变量代理: $PROXY_FOUND"
|
||||||
success "引导仓库已更新"
|
|
||||||
else
|
|
||||||
info "正在克隆引导仓库..."
|
|
||||||
git clone "$GITEA_URL" "$BOOT_DIR"
|
|
||||||
cd "$BOOT_DIR"
|
|
||||||
success "引导仓库克隆完成"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ============================================================
|
# macOS 系统代理
|
||||||
# Step 4: 运行安装脚本
|
if [ -z "$PROXY_FOUND" ]; then
|
||||||
# ============================================================
|
PROXY_HOST=$(scutil --proxy 2>/dev/null | grep "HTTPSProxy" | awk '{print $3}')
|
||||||
step 4 "执行安装"
|
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
|
# 常见端口扫描 (500ms 超时)
|
||||||
info "检测到 install-mac.sh,正在执行..."
|
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"
|
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
|
else
|
||||||
# 如果还没有 mac 专用脚本,提示用户
|
info "首次安装, 克隆配置仓库 (需输入 Gitea 密码)..."
|
||||||
warn "macOS 安装脚本尚未就绪。"
|
mkdir -p "$(dirname "$CLAUDE_DIR")"
|
||||||
info "请联系管理员获取 install-mac.sh,或手动参考安装手册操作。"
|
git clone --depth 1 "$CONFIG_REPO" "$CLAUDE_DIR"
|
||||||
info "安装手册: https://portable.bookwormweb.com/mac"
|
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
|
fi
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@ -198,20 +253,37 @@ fi
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
step 5 "配置终端快捷命令"
|
step 5 "配置终端快捷命令"
|
||||||
|
|
||||||
ZSHRC="$HOME/.zshrc"
|
SHELL_RC="$HOME/.zshrc"
|
||||||
ALIAS_MARKER="# Bookworm Portable aliases"
|
if [ -n "$BASH_VERSION" ] && [ -f "$HOME/.bashrc" ]; then
|
||||||
|
SHELL_RC="$HOME/.bashrc"
|
||||||
|
fi
|
||||||
|
|
||||||
if ! grep -q "$ALIAS_MARKER" "$ZSHRC" 2>/dev/null; then
|
ALIAS_MARKER="# Bookworm Portable aliases"
|
||||||
cat >> "$ZSHRC" << 'ALIASES'
|
if ! grep -q "$ALIAS_MARKER" "$SHELL_RC" 2>/dev/null; then
|
||||||
|
cat >> "$SHELL_RC" << 'ALIASES'
|
||||||
|
|
||||||
# Bookworm Portable aliases
|
# Bookworm Portable aliases
|
||||||
alias bookworm='cd ~/bookworm-boot && bash start-mac.sh'
|
alias bw='NO_PROXY="bww.letcareme.com,code.letcareme.com,localhost,127.0.0.1" claude'
|
||||||
alias bookworm-update='cd ~/bookworm-boot && bash install-mac.sh'
|
alias bw-update='cd ~/bookworm-boot && git pull && cd ~/.claude && git pull && echo "Updated!"'
|
||||||
alias bookworm-stop='cd ~/bookworm-boot && bash stop-mac.sh'
|
|
||||||
ALIASES
|
ALIASES
|
||||||
success "已添加别名到 ~/.zshrc (bookworm / bookworm-update / bookworm-stop)"
|
success "已添加到 $SHELL_RC:"
|
||||||
|
info " bw -- 启动 Bookworm"
|
||||||
|
info " bw-update -- 更新 Bookworm"
|
||||||
else
|
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
|
fi
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@ -220,13 +292,28 @@ fi
|
|||||||
step 6 "安装完成"
|
step 6 "安装完成"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${GREEN}============================================================${NC}"
|
echo -e "${GREEN} ============================================================${NC}"
|
||||||
echo -e "${GREEN} Bookworm Portable for macOS 安装完成!${NC}"
|
echo -e "${GREEN} Bookworm Smart Assistant for macOS 安装完成!${NC}"
|
||||||
echo -e "${GREEN}============================================================${NC}"
|
echo -e "${GREEN} ============================================================${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${BOLD}日常启动:${NC} 在终端输入 ${CYAN}bookworm${NC}"
|
echo -e " 已安装:"
|
||||||
echo -e " ${BOLD}同步更新:${NC} 在终端输入 ${CYAN}bookworm-update${NC}"
|
echo -e " ${GREEN}[v]${NC} Homebrew ${GREEN}[v]${NC} Node.js $(node -v 2>/dev/null)"
|
||||||
echo -e " ${BOLD}卸载清理:${NC} 在终端输入 ${CYAN}bookworm-stop${NC}"
|
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 ""
|
||||||
echo -e " ${BLUE}安装手册:${NC} https://portable.bookwormweb.com/mac"
|
echo -e " ${BOLD}启动方式:${NC}"
|
||||||
|
echo -e " 终端输入: ${CYAN}bw${NC}"
|
||||||
echo ""
|
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
|
||||||
|
|||||||
@ -6,8 +6,8 @@
|
|||||||
deploy-gitea.sh ECS Gitea 部署 (服务端,执行一次)
|
deploy-gitea.sh ECS Gitea 部署 (服务端,执行一次)
|
||||||
prepare-repo.ps1 仓库准备 (本机执行一次)
|
prepare-repo.ps1 仓库准备 (本机执行一次)
|
||||||
encrypt-secrets.ps1 凭证加密 (本机执行一次)
|
encrypt-secrets.ps1 凭证加密 (本机执行一次)
|
||||||
settings.template.json settings.json 模板
|
|
||||||
settings.local.template.json settings.local.json 模板 (权限白名单)
|
settings.local.template.json settings.local.json 模板 (权限白名单)
|
||||||
|
(settings.template.json 已由 build-portable.js 管理,存于 config 仓库)
|
||||||
install.ps1 安装/启动 (目标机执行)
|
install.ps1 安装/启动 (目标机执行)
|
||||||
stop.ps1 清理/卸载 (目标机执行)
|
stop.ps1 清理/卸载 (目标机执行)
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,7 @@ $patterns = @(
|
|||||||
"hooks/lib/*.js",
|
"hooks/lib/*.js",
|
||||||
"scripts/paths.config.js",
|
"scripts/paths.config.js",
|
||||||
"CLAUDE.md",
|
"CLAUDE.md",
|
||||||
"settings.template.json",
|
"settings.json",
|
||||||
"settings.local.template.json"
|
"settings.local.template.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -439,9 +439,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="code-block" onclick="copyCode(this)">
|
<div class="code-block" onclick="copyCode(this)">
|
||||||
<code><span class="cmd">bash</span> install-mac.sh</code>
|
<code><span class="cmd">bash</span> Bookworm-Setup.sh</code>
|
||||||
</div>
|
</div>
|
||||||
<p style="color:var(--text-dim);font-size:0.85rem">如果提示权限不足:<code>chmod +x install-mac.sh && ./install-mac.sh</code></p>
|
<p style="color:var(--text-dim);font-size:0.85rem">如果提示权限不足:<code>chmod +x Bookworm-Setup.sh && ./Bookworm-Setup.sh</code></p>
|
||||||
|
|
||||||
<div class="step">
|
<div class="step">
|
||||||
<div class="step-icon purple">3</div>
|
<div class="step-icon purple">3</div>
|
||||||
@ -464,14 +464,12 @@
|
|||||||
<h4>等待完成</h4>
|
<h4>等待完成</h4>
|
||||||
<p>脚本会显示步骤进度 [1/8] 到 [8/8],自动完成:</p>
|
<p>脚本会显示步骤进度 [1/8] 到 [8/8],自动完成:</p>
|
||||||
<ul style="color:var(--text-dim);font-size:0.9rem;padding-left:1.2rem;margin-top:0.3rem">
|
<ul style="color:var(--text-dim);font-size:0.9rem;padding-left:1.2rem;margin-top:0.3rem">
|
||||||
<li>[1/8] 前置检查 (Claude Code / Node.js / Git / openssl)</li>
|
<li>[1/6] 检查依赖 (Homebrew / Node.js / Git / OpenSSL / Claude Code)</li>
|
||||||
<li>[2/8] 自动检测代理 + 设置 NO_PROXY</li>
|
<li>[2/6] 自动检测代理 + 设置 NO_PROXY</li>
|
||||||
<li>[3/8] 解密凭证 (输入主密码)</li>
|
<li>[3/6] 同步配置 (克隆/更新 92 个 Skills)</li>
|
||||||
<li>[4/8] 同步配置 (下载 92 个 Skills)</li>
|
<li>[4/6] 解密凭证 (输入主密码) + 渲染配置模板</li>
|
||||||
<li>[5/8] 完整性校验 (SHA256 哈希验证)</li>
|
<li>[5/6] 配置终端别名 (bw / bw-update)</li>
|
||||||
<li>[6/8] 渲染配置模板</li>
|
<li>[6/6] 完成 — 可选立即启动</li>
|
||||||
<li>[7/8] Bookworm 系统验证 + MCP 检查</li>
|
|
||||||
<li>[8/8] 启动 Claude Code</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -505,8 +503,8 @@
|
|||||||
<p>安装脚本已自动添加别名到 <code>~/.zshrc</code>,直接在终端输入:</p>
|
<p>安装脚本已自动添加别名到 <code>~/.zshrc</code>,直接在终端输入:</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="code-block" onclick="copyCode(this)">
|
<div class="code-block" onclick="copyCode(this)">
|
||||||
<code><span class="cmd">bookworm</span> <span class="comment"># 快速启动</span>
|
<code><span class="cmd">bw</span> <span class="comment"># 快速启动</span>
|
||||||
<span class="cmd">bookworm-update</span> <span class="comment"># 同步更新后启动</span></code>
|
<span class="cmd">bw-update</span> <span class="comment"># 同步更新</span></code>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card" style="margin-top:1rem">
|
<div class="card" style="margin-top:1rem">
|
||||||
@ -517,13 +515,13 @@
|
|||||||
<tr><th>操作</th><th>命令</th><th>说明</th></tr>
|
<tr><th>操作</th><th>命令</th><th>说明</th></tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>快速启动</strong></td>
|
<td><strong>快速启动</strong></td>
|
||||||
<td><code>cd ~/bookworm-boot && bash start-mac.sh</code></td>
|
<td><code>bw</code></td>
|
||||||
<td>直接启动,不更新配置</td>
|
<td>直接启动 Claude Code + Bookworm</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>同步更新</strong></td>
|
<td><strong>同步更新</strong></td>
|
||||||
<td><code>cd ~/bookworm-boot && bash install-mac.sh</code></td>
|
<td><code>bw-update</code></td>
|
||||||
<td>先同步最新 Skills 再启动</td>
|
<td>更新 boot + 配置仓库</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@ -531,7 +529,7 @@
|
|||||||
<span class="alert-icon">💡</span>
|
<span class="alert-icon">💡</span>
|
||||||
<div>
|
<div>
|
||||||
<strong>启动时显示 "有 N 个新更新可用"?</strong><br>
|
<strong>启动时显示 "有 N 个新更新可用"?</strong><br>
|
||||||
说明管理员更新了 Skills 或 Hooks。执行 <code>bookworm-update</code> 即可同步。
|
说明管理员更新了 Skills 或 Hooks。执行 <code>bw-update</code> 即可同步。
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -582,18 +580,18 @@
|
|||||||
<tr><th>场景</th><th>命令</th><th>说明</th></tr>
|
<tr><th>场景</th><th>命令</th><th>说明</th></tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>基础清理</strong></td>
|
<td><strong>基础清理</strong></td>
|
||||||
<td><code>bash stop-mac.sh</code></td>
|
<td><code>rm -rf ~/.claude</code></td>
|
||||||
<td>清除环境变量,保留配置供下次快速启动</td>
|
<td>删除 Bookworm 配置,保留引导仓库供重新安装</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>完整恢复</strong></td>
|
<td><strong>完整恢复</strong></td>
|
||||||
<td><code>bash stop-mac.sh --restore</code></td>
|
<td><code>rm -rf ~/.claude ~/bookworm-boot</code></td>
|
||||||
<td>删除 Bookworm,恢复电脑原始状态</td>
|
<td>删除所有 Bookworm 文件</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>深度清理</strong></td>
|
<td><strong>深度清理</strong></td>
|
||||||
<td><code>bash stop-mac.sh --restore --deep</code></td>
|
<td><code>rm -rf ~/.claude ~/bookworm-boot && sed -i '' '/Bookworm Portable/,+2d' ~/.zshrc && git credential-osxkeychain erase <<< "host=code.letcareme.com"</code></td>
|
||||||
<td>完整恢复 + 清除历史 + 清除 Git 凭证 + 钥匙串</td>
|
<td>完整恢复 + 清除别名 + 清除 Git 凭证</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@ -601,7 +599,7 @@
|
|||||||
<span class="alert-icon">⚠</span>
|
<span class="alert-icon">⚠</span>
|
||||||
<div>
|
<div>
|
||||||
<strong>在他人电脑/公用电脑上务必清理:</strong><br>
|
<strong>在他人电脑/公用电脑上务必清理:</strong><br>
|
||||||
执行 <code>cd ~/bookworm-boot && bash stop-mac.sh --restore --deep</code>
|
执行深度清理命令,确保不留下任何凭证或配置
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -678,8 +676,7 @@
|
|||||||
<span class="cmd">export</span> NO_PROXY="bww.letcareme.com,code.letcareme.com"
|
<span class="cmd">export</span> NO_PROXY="bww.letcareme.com,code.letcareme.com"
|
||||||
|
|
||||||
<span class="comment"># 重新启动</span>
|
<span class="comment"># 重新启动</span>
|
||||||
<span class="cmd">cd</span> ~/bookworm-boot
|
<span class="cmd">bw</span></code>
|
||||||
<span class="cmd">bash</span> start-mac.sh</code>
|
|
||||||
</div>
|
</div>
|
||||||
<p style="color:var(--text-dim);font-size:0.85rem">或在代理软件中将 <code>*.letcareme.com</code> 加入直连规则。</p>
|
<p style="color:var(--text-dim);font-size:0.85rem">或在代理软件中将 <code>*.letcareme.com</code> 加入直连规则。</p>
|
||||||
|
|
||||||
@ -688,8 +685,8 @@
|
|||||||
<p><strong>原因:</strong>API 凭证是进程级环境变量,只在安装脚本启动的进程中有效。</p>
|
<p><strong>原因:</strong>API 凭证是进程级环境变量,只在安装脚本启动的进程中有效。</p>
|
||||||
<p><strong>解决:</strong><strong>不要直接运行 <code>claude</code></strong>,必须通过以下方式启动:</p>
|
<p><strong>解决:</strong><strong>不要直接运行 <code>claude</code></strong>,必须通过以下方式启动:</p>
|
||||||
<ul style="color:var(--text-dim);font-size:0.9rem;padding-left:1.2rem;margin-top:0.3rem">
|
<ul style="color:var(--text-dim);font-size:0.9rem;padding-left:1.2rem;margin-top:0.3rem">
|
||||||
<li>终端输入 <code>bookworm</code>(推荐)</li>
|
<li>终端输入 <code>bw</code>(推荐)</li>
|
||||||
<li><code>cd ~/bookworm-boot && bash start-mac.sh</code></li>
|
<li><code>cd ~/bookworm-boot && bash Bookworm-Setup.sh</code></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -740,12 +737,12 @@
|
|||||||
<h2>快速参考</h2>
|
<h2>快速参考</h2>
|
||||||
<table>
|
<table>
|
||||||
<tr><th>操作</th><th>快捷方式</th><th>完整命令</th></tr>
|
<tr><th>操作</th><th>快捷方式</th><th>完整命令</th></tr>
|
||||||
<tr><td>首次安装</td><td>git clone + <code>bash install-mac.sh</code></td><td><code>cd ~/bookworm-boot && bash install-mac.sh</code></td></tr>
|
<tr><td>首次安装</td><td>git clone + <code>bash Bookworm-Setup.sh</code></td><td><code>cd ~/bookworm-boot && bash Bookworm-Setup.sh</code></td></tr>
|
||||||
<tr><td>快速启动</td><td><code>bookworm</code></td><td><code>cd ~/bookworm-boot && bash start-mac.sh</code></td></tr>
|
<tr><td>快速启动</td><td><code>bw</code></td><td><code>NO_PROXY="bww.letcareme.com,code.letcareme.com,localhost,127.0.0.1" claude</code></td></tr>
|
||||||
<tr><td>同步更新</td><td><code>bookworm-update</code></td><td><code>cd ~/bookworm-boot && bash install-mac.sh</code></td></tr>
|
<tr><td>同步更新</td><td><code>bw-update</code></td><td><code>cd ~/bookworm-boot && git pull && cd ~/.claude && git pull</code></td></tr>
|
||||||
<tr><td>基础清理</td><td colspan="2"><code>cd ~/bookworm-boot && bash stop-mac.sh</code></td></tr>
|
<tr><td>基础清理</td><td colspan="2"><code>rm -rf ~/.claude</code></td></tr>
|
||||||
<tr><td>完整恢复</td><td colspan="2"><code>cd ~/bookworm-boot && bash stop-mac.sh --restore</code></td></tr>
|
<tr><td>完整恢复</td><td colspan="2"><code>rm -rf ~/.claude ~/bookworm-boot</code></td></tr>
|
||||||
<tr><td>深度清理</td><td colspan="2"><code>cd ~/bookworm-boot && bash stop-mac.sh --restore --deep</code></td></tr>
|
<tr><td>深度清理</td><td colspan="2"><code>rm -rf ~/.claude ~/bookworm-boot && sed -i '' '/Bookworm/,+2d' ~/.zshrc</code></td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
8
install-mac.sh
Normal file
8
install-mac.sh
Normal file
@ -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" "$@"
|
||||||
@ -27,18 +27,9 @@ if (-not (Test-Path $ClaudeDir)) {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# 1. 拷贝 settings.template.json
|
# 1. settings.template.json (由 build-portable.js 自动生成,无需手动拷贝)
|
||||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
$templateSrc = Join-Path $ScriptDir "settings.template.json"
|
Write-Host "[1/6] settings.template.json 由 build-portable.js 管理,跳过" -ForegroundColor Gray
|
||||||
$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
|
|
||||||
}
|
|
||||||
|
|
||||||
# 2. 创建 .gitignore
|
# 2. 创建 .gitignore
|
||||||
Write-Host "[2/6] 生成 .gitignore..." -ForegroundColor White
|
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
|
git commit -m "Bookworm v6.5.1 portable commit
|
||||||
|
|
||||||
Includes: CLAUDE.md, skills (92), agents (18), hooks (29),
|
Includes: CLAUDE.md, skills (92), agents (18), hooks (29),
|
||||||
scripts, constitution, settings.template.json
|
scripts, constitution
|
||||||
|
|
||||||
Excludes: credentials, mcp-servers, node_modules, cache,
|
Excludes: credentials, mcp-servers, node_modules, cache,
|
||||||
sessions, debug logs, project-specific data, gstack/browse binaries"
|
sessions, debug logs, project-specific data, gstack/browse binaries"
|
||||||
|
|||||||
@ -279,7 +279,6 @@
|
|||||||
├── deploy-gitea.sh Gitea 部署 (ECS)
|
├── deploy-gitea.sh Gitea 部署 (ECS)
|
||||||
├── setup-https.sh HTTPS 配置 (ECS)
|
├── setup-https.sh HTTPS 配置 (ECS)
|
||||||
├── secure-firewall.sh 防火墙加固 (ECS)
|
├── secure-firewall.sh 防火墙加固 (ECS)
|
||||||
├── settings.template.json settings.json 模板
|
|
||||||
├── settings.local.template.json settings.local.json 模板
|
├── settings.local.template.json settings.local.json 模板
|
||||||
├── guide.html HTML 保姆式教程
|
├── guide.html HTML 保姆式教程
|
||||||
├── quick-reference.txt 本文档
|
├── quick-reference.txt 本文档
|
||||||
|
|||||||
@ -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
|
|
||||||
}
|
|
||||||
181
uninstall-mac.sh
Normal file
181
uninstall-mac.sh
Normal file
@ -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 ""
|
||||||
Loading…
Reference in New Issue
Block a user