feat: Mac v2.2.4 - MCP inject + git robustness + credential whitelist
This commit is contained in:
parent
b2d5e4aa7b
commit
9c595fae86
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Bookworm Smart Assistant - macOS 全自动安装 v2.0
|
# Bookworm Smart Assistant - macOS 全自动安装 v2.2.4
|
||||||
#
|
#
|
||||||
# 用法 (任选一种):
|
# 用法 (任选一种):
|
||||||
# 方式1: 下载后运行
|
# 方式1: 下载后运行
|
||||||
@ -39,7 +39,7 @@ echo " | _ \\ / _ \\ / _ \\| |/ /\\ \\ /\\ / / _ \\| '__| '\`_ \` _ \\"
|
|||||||
echo " | |_) | (_) | (_) | < \\ V V / (_) | | | | | | | |"
|
echo " | |_) | (_) | (_) | < \\ V V / (_) | | | | | | | |"
|
||||||
echo " |____/ \\___/ \\___/|_|\\_\\ \\_/\\_/ \\___/|_| |_| |_| |_|"
|
echo " |____/ \\___/ \\___/|_|\\_\\ \\_/\\_/ \\___/|_| |_| |_| |_|"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${BOLD}全自动安装 v2.0 — macOS${NC}"
|
echo -e " ${BOLD}全自动安装 v2.2.4 — macOS${NC}"
|
||||||
echo -e " ${BLUE}92 Skills | 18 Agents | 34 Hooks${NC}"
|
echo -e " ${BLUE}92 Skills | 18 Agents | 34 Hooks${NC}"
|
||||||
echo -e "${NC}"
|
echo -e "${NC}"
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,7 @@ banner() {
|
|||||||
echo " | |_) | (_) | (_) | < \\ V V / (_) | | | | | | | |"
|
echo " | |_) | (_) | (_) | < \\ V V / (_) | | | | | | | |"
|
||||||
echo " |____/ \\___/ \\___/|_|\\_\\ \\_/\\_/ \\___/|_| |_| |_| |_|"
|
echo " |____/ \\___/ \\___/|_|\\_\\ \\_/\\_/ \\___/|_| |_| |_| |_|"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${BOLD}Portable macOS Setup v1.5${NC}"
|
echo -e " ${BOLD}Portable macOS Setup v2.2.4${NC}"
|
||||||
echo -e " ${BLUE}92 Skills | 18 Agents | 34 Hooks${NC}"
|
echo -e " ${BLUE}92 Skills | 18 Agents | 34 Hooks${NC}"
|
||||||
echo -e "${NC}"
|
echo -e "${NC}"
|
||||||
}
|
}
|
||||||
@ -177,9 +177,18 @@ git config --global credential.helper osxkeychain 2>/dev/null || true
|
|||||||
|
|
||||||
if [ -d "$CLAUDE_DIR/.git" ]; then
|
if [ -d "$CLAUDE_DIR/.git" ]; then
|
||||||
info "配置仓库已存在, 更新..."
|
info "配置仓库已存在, 更新..."
|
||||||
cd "$CLAUDE_DIR" && git pull --ff-only 2>/dev/null || git pull 2>/dev/null || true
|
cd "$CLAUDE_DIR"
|
||||||
cd "$BOOT_DIR"
|
# 设置 git 身份 (auto-resolve 需要)
|
||||||
|
git config user.email "bookworm@auto.local" 2>/dev/null
|
||||||
|
git config user.name "Bookworm" 2>/dev/null
|
||||||
|
# 清除冲突状态 (运行时文件不重要, 后续会重新渲染)
|
||||||
|
git reset --hard HEAD 2>/dev/null || true
|
||||||
|
if git pull --rebase --autostash 2>/dev/null; then
|
||||||
success "配置仓库已更新"
|
success "配置仓库已更新"
|
||||||
|
else
|
||||||
|
warn "git pull 失败, 使用本地版本"
|
||||||
|
fi
|
||||||
|
cd "$BOOT_DIR"
|
||||||
elif [ -f "$CLAUDE_DIR/CLAUDE.md" ]; then
|
elif [ -f "$CLAUDE_DIR/CLAUDE.md" ]; then
|
||||||
warn "~/.claude 已存在但非 git 仓库, 备份后克隆..."
|
warn "~/.claude 已存在但非 git 仓库, 备份后克隆..."
|
||||||
mv "$CLAUDE_DIR" "$CLAUDE_DIR.bak.$(date +%s)"
|
mv "$CLAUDE_DIR" "$CLAUDE_DIR.bak.$(date +%s)"
|
||||||
@ -341,24 +350,27 @@ elif [ -f "$SECRETS_ENC" ] || ls "$BOOT_DIR"/secrets-*.enc 2>/dev/null | head -1
|
|||||||
DECRYPTED=$(_decrypt_secrets "$TOKEN" "$ENC_FILE") || true
|
DECRYPTED=$(_decrypt_secrets "$TOKEN" "$ENC_FILE") || true
|
||||||
TOKEN=""
|
TOKEN=""
|
||||||
if [ -n "$DECRYPTED" ]; then
|
if [ -n "$DECRYPTED" ]; then
|
||||||
|
# 白名单校验 (与 Windows 版对齐)
|
||||||
|
ALLOWED_KEYS="ANTHROPIC_API_KEY ANTHROPIC_BASE_URL GITHUB_PERSONAL_ACCESS_TOKEN SLACK_BOT_TOKEN ATLASSIAN_API_TOKEN BROWSERBASE_API_KEY FIRECRAWL_API_KEY GEMINI_API_KEY"
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
[ -z "$line" ] && continue
|
[ -z "$line" ] && continue
|
||||||
key="${line%%=*}"
|
key="${line%%=*}"
|
||||||
value="${line#*=}"
|
value="${line#*=}"
|
||||||
key=$(echo "$key" | tr -d ' ')
|
key=$(echo "$key" | tr -d ' ')
|
||||||
if [ -n "$key" ] && [ -n "$value" ]; then
|
if [ -n "$key" ] && [ -n "$value" ]; then
|
||||||
|
# 白名单 + 长度校验
|
||||||
|
if echo "$ALLOWED_KEYS" | grep -qw "$key" && [ ${#value} -lt 512 ]; then
|
||||||
export "$key=$value"
|
export "$key=$value"
|
||||||
success "已注入: $key"
|
success "已注入: $key"
|
||||||
|
else
|
||||||
|
warn "跳过未知 key: $key"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done <<< "$DECRYPTED"
|
done <<< "$DECRYPTED"
|
||||||
DECRYPTED=""
|
DECRYPTED=""
|
||||||
|
|
||||||
# 询问是否缓存
|
# 自动缓存 (不再询问, 与 Windows 版对齐)
|
||||||
echo ""
|
|
||||||
read -p " 今日内免密启动? (y/n): " CACHE_CHOICE
|
|
||||||
if [ "$CACHE_CHOICE" = "y" ] || [ "$CACHE_CHOICE" = "Y" ]; then
|
|
||||||
save_secrets_to_cache
|
save_secrets_to_cache
|
||||||
fi
|
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
if [ $valid_attempts -lt 3 ]; then
|
if [ $valid_attempts -lt 3 ]; then
|
||||||
@ -376,6 +388,59 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ── MCP 注入到 ~/.claude.json (Claude Code v2.1+ 正确位置) ──
|
||||||
|
INJECT_SCRIPT="$CLAUDE_DIR/inject-mcp.js"
|
||||||
|
MCP_INJECTED=false
|
||||||
|
|
||||||
|
# 方案 A: 调用 config 仓库里的 inject-mcp.js
|
||||||
|
if [ -f "$INJECT_SCRIPT" ] && command -v node &>/dev/null; then
|
||||||
|
MCP_OUT=$(node "$INJECT_SCRIPT" 2>&1) && {
|
||||||
|
success "$MCP_OUT"
|
||||||
|
MCP_INJECTED=true
|
||||||
|
} || warn "inject-mcp.js 执行失败"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 方案 B: 内嵌 fallback (git pull 失败时)
|
||||||
|
if [ "$MCP_INJECTED" = false ] && command -v node &>/dev/null; then
|
||||||
|
info "inject-mcp.js 不可用, 使用内嵌 MCP 注入..."
|
||||||
|
FALLBACK_JS=$(mktemp /tmp/bw-mcp-XXXXXX.js)
|
||||||
|
cat > "$FALLBACK_JS" << 'MCPEOF'
|
||||||
|
var fs=require("fs"),p=require("path");
|
||||||
|
var H=process.env.HOME||process.env.USERPROFILE;
|
||||||
|
var f=p.join(H,".claude.json");
|
||||||
|
var d={};try{d=JSON.parse(fs.readFileSync(f,"utf8"))}catch(e){}
|
||||||
|
var N="npx",Y="--yes",S={};
|
||||||
|
S.context7={command:N,args:[Y,"@upstash/context7-mcp@2.1.1"],type:"stdio"};
|
||||||
|
S.playwright={command:N,args:[Y,"@playwright/mcp@0.0.68","--headless"],type:"stdio"};
|
||||||
|
S["session-continuity"]={command:N,args:[Y,"claude-session-continuity-mcp@1.13.0"],type:"stdio"};
|
||||||
|
S["browser-mcp"]={command:N,args:[Y,"@browsermcp/mcp@latest"],type:"stdio"};
|
||||||
|
S["desktop-commander"]={command:N,args:[Y,"@wonderwhy-er/desktop-commander@latest"],type:"stdio"};
|
||||||
|
S["chrome-devtools"]={command:N,args:[Y,"chrome-devtools-mcp@0.18.1"],type:"stdio"};
|
||||||
|
S.github={command:N,args:[Y,"@modelcontextprotocol/server-github"],type:"stdio"};
|
||||||
|
S.slack={command:N,args:[Y,"@modelcontextprotocol/server-slack"],type:"stdio"};
|
||||||
|
S.firecrawl={command:N,args:[Y,"firecrawl-mcp"],type:"stdio"};
|
||||||
|
S["mcp-image"]={command:N,args:[Y,"mcp-image"],type:"stdio"};
|
||||||
|
S["google-drive"]={command:N,args:[Y,"@piotr-agier/google-drive-mcp"],type:"stdio"};
|
||||||
|
S.browserbase={command:N,args:[Y,"@anthropic-ai/browserbase-mcp"],type:"stdio"};
|
||||||
|
S.notebooklm={command:N,args:[Y,"notebooklm-mcp@latest"],type:"stdio"};
|
||||||
|
S.cloudflare={command:N,args:[Y,"mcp-remote","https://docs.mcp.cloudflare.com/sse"],type:"stdio"};
|
||||||
|
S.mobile={command:N,args:[Y,"@mobilenext/mobile-mcp@0.0.35"],type:"stdio"};
|
||||||
|
var K="@modelcontextprotocol/server-sequential-thinking";
|
||||||
|
S["sequential-thinking"]={command:N,args:[Y,K+"@2025.12.18"],type:"stdio"};
|
||||||
|
S.linear={type:"http",url:"https://mcp.linear.app/mcp"};
|
||||||
|
S.supabase={type:"http",url:"https://mcp.supabase.com/mcp?project_ref=oepmihbtoylosbsxlmfo"};
|
||||||
|
S.figma={type:"http",url:"https://mcp.figma.com/mcp"};
|
||||||
|
S["windows-mcp"]={command:"uvx",args:["--python","3.13","windows-mcp"],type:"stdio"};
|
||||||
|
S.atlassian={command:"uvx",args:["mcp-atlassian"],type:"stdio"};
|
||||||
|
S["computer-control-mcp"]={command:"uvx",args:["computer-control-mcp@latest"],type:"stdio"};
|
||||||
|
d.mcpServers=S;
|
||||||
|
fs.writeFileSync(f,JSON.stringify(d,null,2));
|
||||||
|
console.log("OK: "+Object.keys(S).length+" MCP servers (fallback)");
|
||||||
|
MCPEOF
|
||||||
|
MCP_OUT=$(node "$FALLBACK_JS" 2>&1) && success "$MCP_OUT" || warn "MCP fallback 注入失败"
|
||||||
|
rm -f "$FALLBACK_JS"
|
||||||
|
fi
|
||||||
|
|
||||||
# 渲染 settings.json (替换占位符)
|
# 渲染 settings.json (替换占位符)
|
||||||
TEMPLATE_FILE="$CLAUDE_DIR/settings.template.json"
|
TEMPLATE_FILE="$CLAUDE_DIR/settings.template.json"
|
||||||
SETTINGS_FILE="$CLAUDE_DIR/settings.json"
|
SETTINGS_FILE="$CLAUDE_DIR/settings.json"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user