#!/usr/bin/env bash
# bootstrap-reverse.sh — Kali Linux 版自动安装/补齐工具
# 等价于 Windows 版的 bootstrap-reverse.ps1
#
# 用法:
#   bash bootstrap-reverse.sh <capability1> [capability2] ... [--start-services] [--skip-refresh]
#
# 示例:
#   bash bootstrap-reverse.sh jadx apktool frida
#   bash bootstrap-reverse.sh idapro --start-services
#   bash bootstrap-reverse.sh jshookmcp anything-analyzer

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
KALI_MANIFEST="$SCRIPT_DIR/bootstrap-manifest.json"
source "$SCRIPT_DIR/lib/tool-discovery.sh"

# ─── 参数解析 ──────────────────────────────────────────────────────────────────────

CAPABILITIES=()
START_SERVICES=false
SKIP_REFRESH=false
MANUAL_REQUIRED=false
LAST_CAPABILITY_MANUAL=false

for arg in "$@"; do
    case "$arg" in
        --start-services) START_SERVICES=true ;;
        --skip-refresh) SKIP_REFRESH=true ;;
        --list|-l)
            echo "jadx apktool jeb-pro frida frida-ps idalib-mcp jshookmcp reqable-mcp anything-analyzer idapro r2 rabin2 adb agent-browser ghidra-mcp seclists proxycat burpsuite-mcp nmap pentestswarm bkcrack"
            echo "mcp-kali-server metasploitmcp hexstrike-ai adaptixc2 atomic-operator sstimap xsstrike wpprobe fluxion gef coercer evil-winrm-py netexec responder bloodhound certipy"
            exit 0
            ;;
        -*) echo "未知选项: $arg"; exit 1 ;;
        *) CAPABILITIES+=("$arg") ;;
    esac
done

if [[ ${#CAPABILITIES[@]} -eq 0 ]]; then
    echo "用法: $0 <capability1> [capability2] ... [--start-services] [--skip-refresh]"
    echo ""
    echo "可用能力:"
    echo ""
    echo "  [逆向分析]"
    echo "    jadx apktool jeb-pro frida frida-ps idalib-mcp r2 rabin2 adb gef"
    echo ""
    echo "  [渗透测试 - 经典工具]"
    echo "    nmap sqlmap hashcat hydra gobuster ffuf msfconsole nuclei"
    echo "    netexec responder crackmapexec bloodhound certipy wfuzz"
    echo "    aircrack-ng coercer evil-winrm-py"
    echo ""
    echo "  [渗透测试 - Kali 2026.1 新增]"
    echo "    adaptixc2 atomic-operator sstimap xsstrike wpprobe fluxion"
    echo ""
    echo "  [MCP 服务]"
    echo "    jshookmcp reqable-mcp anything-analyzer idapro agent-browser"
    echo "    mcp-kali-server metasploitmcp hexstrike-ai pentestswarm"
    echo ""
    echo "  [CTF 压缩包]"
    echo "    bkcrack"
    echo ""
    echo "  [其他]"
    echo "    ghidra-mcp seclists proxycat burpsuite-mcp"
    echo ""
    echo "示例:"
    echo "  $0 mcp-kali-server metasploitmcp hexstrike-ai pentestswarm  # 全部渗透 MCP"
    echo "  $0 adaptixc2 sstimap xsstrike wpprobe          # 安装 2026.1 新工具"
    echo "  $0 pentestswarm --start-services               # 安装 Swarm AI"
    echo "  $0 idapro --start-services                     # 安装并启动 IDA MCP"
    exit 1
fi

# ─── 辅助函数 ──────────────────────────────────────────────────────────────────────

log_info() { echo -e "\033[36m[INFO]\033[0m $*"; }
log_ok() { echo -e "\033[32m[OK]\033[0m $*"; }
log_warn() { echo -e "\033[33m[WARN]\033[0m $*"; }
log_err() { echo -e "\033[31m[ERR]\033[0m $*"; }

# 检查是否有 sudo 权限
check_sudo() {
    if [[ $EUID -eq 0 ]]; then
        return 0
    fi
    if sudo -n true 2>/dev/null; then
        return 0
    fi
    log_warn "部分操作需要 sudo 权限"
    return 1
}

# apt 安装
install_apt_package() {
    local package="$1"
    log_info "apt install $package ..."
    if [[ $EUID -eq 0 ]]; then
        apt-get update -qq && apt-get install -y -qq "$package"
    else
        sudo apt-get update -qq && sudo apt-get install -y -qq "$package"
    fi
}

# pip 安装
install_pip_package() {
    local package="$1"
    local source="${2:-}"
    local target="${source:-$package}"
    log_info "pip3 install $target ..."
    pip3 install --upgrade "$target" --break-system-packages 2>/dev/null \
        || pip3 install --upgrade "$target"
}

# npm 全局安装
install_npm_global() {
    local package="$1"
    log_info "npm install -g $package ..."
    if [[ $EUID -eq 0 ]]; then
        npm install -g "$package"
    else
        sudo npm install -g "$package" 2>/dev/null || npm install -g "$package"
    fi
}

# Git clone at an immutable commit. Existing mismatched checkouts are rejected
# instead of being overwritten, so local operator changes are never discarded.
install_git_commit() {
    local repo="$1"
    local commit="$2"
    local install_dir="$3"

    if [[ -d "$install_dir/.git" ]]; then
        local current
        current=$(git -C "$install_dir" rev-parse HEAD 2>/dev/null || true)
        if [[ "$current" != "$commit" ]]; then
            log_err "Existing checkout is not at pinned commit $commit: $install_dir"
            log_err "Move it aside explicitly, then retry; bootstrap will not overwrite local changes."
            return 1
        fi
        return 0
    fi
    if [[ -e "$install_dir" ]]; then
        log_err "Install path exists but is not a git checkout: $install_dir"
        return 1
    fi

    mkdir -p "$(dirname "$install_dir")"
    git init -q "$install_dir"
    git -C "$install_dir" remote add origin "$repo"
    git -C "$install_dir" fetch --depth 1 origin "$commit"
    git -C "$install_dir" checkout -q --detach FETCH_HEAD
    local resolved
    resolved=$(git -C "$install_dir" rev-parse HEAD)
    if [[ "$resolved" != "$commit" ]]; then
        log_err "Pinned checkout verification failed (expected $commit, got $resolved)"
        return 1
    fi
}

# GitHub Release 下载并解压。
# Args: repo asset_regex install_dir [release_tag] [expected_sha256]
install_github_release() {
    local repo="$1"
    local asset_regex="$2"
    local install_dir="$3"
    local release_tag="${4:-}"
    local expected_sha256="${5:-}"

    if ! command -v jq &>/dev/null; then
        log_err "jq is required to select and verify GitHub release assets"
        return 1
    fi

    log_info "从 GitHub Release 下载: $repo ..."

    local api_url
    if [[ -n "$release_tag" ]]; then
        api_url="https://api.github.com/repos/${repo}/releases/tags/${release_tag}"
    else
        api_url="https://api.github.com/repos/${repo}/releases/latest"
    fi

    local release_json
    release_json=$(curl --fail --silent --show-error --location "$api_url")

    local asset
    asset=$(printf '%s' "$release_json" | jq -cer --arg regex "$asset_regex" '.assets[] | select(.name | test($regex)) | {name, browser_download_url, digest}' | head -n1)
    if [[ -z "$asset" || "$asset" == "null" ]]; then
        log_err "未找到匹配 $asset_regex 的 release asset (tag=${release_tag:-latest})"
        return 1
    fi

    local download_url filename api_digest
    download_url=$(printf '%s' "$asset" | jq -r '.browser_download_url')
    filename=$(printf '%s' "$asset" | jq -r '.name')
    api_digest=$(printf '%s' "$asset" | jq -r '.digest // empty')
    local tmp_file
    tmp_file=$(mktemp "/tmp/reverse-bootstrap-${filename}.XXXXXX")
    local tmp_extract=''

    cleanup_github_release() {
        rm -f "$tmp_file"
        if [[ -n "$tmp_extract" ]]; then rm -rf "$tmp_extract"; fi
    }

    log_info "下载: $download_url"
    if ! curl --fail --silent --show-error --location -o "$tmp_file" "$download_url"; then
        cleanup_github_release
        return 1
    fi

    local expected="${expected_sha256#sha256:}"
    expected="${expected,,}"
    if [[ -z "$expected" && -n "$api_digest" ]]; then
        expected="${api_digest#sha256:}"
        expected="${expected,,}"
    fi
    if [[ -z "$expected" ]]; then
        log_err "缺少固定 SHA-256 或 GitHub digest，拒绝安装未校验资产: $filename"
        cleanup_github_release
        return 1
    fi

    local actual
    actual=$(sha256sum "$tmp_file" | awk '{print tolower($1)}')
    if [[ "$actual" != "$expected" ]]; then
        log_err "SHA-256 不匹配: $filename (expected $expected, got $actual)"
        cleanup_github_release
        return 1
    fi
    log_ok "SHA-256 校验通过: $actual"

    # 创建安装目录
    mkdir -p "$install_dir"

    # 根据文件类型解压
    case "$filename" in
        *.tar.gz|*.tgz)
            tar -xzf "$tmp_file" -C "$install_dir" --strip-components=1 2>/dev/null \
                || tar -xzf "$tmp_file" -C "$install_dir"
            ;;
        *.zip)
            tmp_extract=$(mktemp -d /tmp/reverse-bootstrap-extract.XXXXXX)
            unzip -qo "$tmp_file" -d "$tmp_extract"
            # 如果只有一个顶层目录，strip 它
            local top_dirs
            top_dirs=$(find "$tmp_extract" -maxdepth 1 -mindepth 1 -type d)
            if [[ $(printf '%s\n' "$top_dirs" | wc -l) -eq 1 ]]; then
                cp -a "$top_dirs"/. "$install_dir/"
            else
                cp -a "$tmp_extract"/. "$install_dir/"
            fi
            ;;
        *.deb)
            if [[ $EUID -eq 0 ]]; then
                dpkg -i "$tmp_file" || apt-get install -f -y
            else
                sudo dpkg -i "$tmp_file" || sudo apt-get install -f -y
            fi
            ;;
        *)
            cp "$tmp_file" "$install_dir/"
            ;;
    esac

    cleanup_github_release

    # 把 bin 目录加入 PATH（当前 session）
    if [[ -d "$install_dir/bin" ]]; then
        export PATH="$install_dir/bin:$PATH"
    else
        export PATH="$install_dir:$PATH"
    fi

    log_ok "已安装到 $install_dir"
}

# 注册 MCP server 到 Claude 配置
register_mcp_server() {
    local server_name="$1"
    local config_json="$2"  # JSON 格式的 server 配置

    local config_path
    config_path=$(get_claude_mcp_config_path)
    local config_dir
    config_dir=$(dirname "$config_path")

    mkdir -p "$config_dir"

    if [[ ! -f "$config_path" ]]; then
        echo '{"mcpServers":{}}' > "$config_path"
    fi

    if command -v jq &>/dev/null; then
        local tmp_file="/tmp/mcp-config-$$.json"
        jq ".mcpServers.\"${server_name}\" = ${config_json}" "$config_path" > "$tmp_file"
        mv "$tmp_file" "$config_path"
        log_ok "MCP server '$server_name' 已注册到 $config_path"
    else
        log_warn "未安装 jq，无法自动注册 MCP server。请手动编辑 $config_path"
    fi
}

# 等待端口就绪
wait_for_port() {
    local port="$1"
    local timeout="${2:-90}"
    local elapsed=0

    while [[ $elapsed -lt $timeout ]]; do
        if test_tcp_port "$port" 2>/dev/null; then
            return 0
        fi
        sleep 2
        elapsed=$((elapsed + 2))
    done
    return 1
}

# ─── 能力安装逻辑 ──────────────────────────────────────────────────────────────────

manifest_field() {
    local capability="$1"
    local field="$2"
    if [[ ! -f "$KALI_MANIFEST" ]] || ! command -v jq &>/dev/null; then
        return 1
    fi
    jq -er --arg name "$capability" --arg field "$field" \
        '.capabilities[] | select(.name == $name) | .[$field] // empty' "$KALI_MANIFEST"
}

install_manifest_release() {
    local capability="$1"
    local repo asset_regex install_dir release_tag asset_sha256
    repo=$(manifest_field "$capability" repo) || {
        log_err "manifest 中缺少 $capability.repo"
        return 1
    }
    asset_regex=$(manifest_field "$capability" assetRegex) || {
        log_err "manifest 中缺少 $capability.assetRegex"
        return 1
    }
    install_dir=$(manifest_field "$capability" installDir) || {
        log_err "manifest 中缺少 $capability.installDir"
        return 1
    }
    release_tag=$(manifest_field "$capability" releaseTag) || {
        log_err "manifest 中缺少 $capability.releaseTag；拒绝使用 latest"
        return 1
    }
    asset_sha256=$(manifest_field "$capability" assetSha256) || {
        log_err "manifest 中缺少 $capability.assetSha256；拒绝下载未固定资产"
        return 1
    }

    install_dir="${install_dir/\$HOME/$HOME}"
    install_github_release "$repo" "$asset_regex" "$install_dir" "$release_tag" "$asset_sha256"
}

ensure_capability() {
    local name="$1"

    # 先检查是否已可用
    if command -v "$name" &>/dev/null; then
        log_ok "$name 已可用: $(command -v "$name")"
        return 0
    fi

    log_info "开始安装: $name"

    case "$name" in
        # ─── apt 预装/可装的工具 ───
        nmap|sqlmap|hashcat|hydra|gobuster|ffuf|adb|bkcrack)
            install_apt_package "$name"
            ;;
        msfconsole)
            install_apt_package "metasploit-framework"
            ;;
        r2|rabin2|rasm2|radiff2|rahash2|rax2)
            if ! command -v r2 &>/dev/null; then
                install_apt_package "radare2"
            fi
            ;;
        apktool)
            install_apt_package "apktool"
            ;;
        seclists)
            install_apt_package "seclists"
            ;;
        # ─── Kali 2026.1 新增工具（全部 apt 直装） ───
        adaptixc2)
            install_apt_package "adaptixc2"
            ;;
        atomic-operator)
            install_apt_package "atomic-operator"
            ;;
        fluxion)
            install_apt_package "fluxion"
            ;;
        gef)
            install_apt_package "gef"
            log_info "GEF 已安装。启动 gdb 时自动加载 GEF 增强功能。"
            ;;
        sstimap)
            install_apt_package "sstimap"
            ;;
        xsstrike)
            install_apt_package "xsstrike"
            ;;
        wpprobe)
            install_apt_package "wpprobe"
            ;;
        evil-winrm-py)
            install_apt_package "evil-winrm-py"
            ;;
        coercer)
            install_apt_package "coercer"
            ;;
        netexec)
            install_apt_package "netexec"
            ;;
        responder)
            install_apt_package "responder"
            ;;
        crackmapexec)
            install_apt_package "crackmapexec"
            ;;
        bloodhound)
            install_apt_package "bloodhound"
            ;;
        certipy)
            install_apt_package "certipy-ad"
            ;;
        wfuzz)
            install_apt_package "wfuzz"
            ;;
        aircrack-ng)
            install_apt_package "aircrack-ng"
            ;;
        # ─── Kali 原生 MCP 工具（apt 安装 + MCP 注册） ───
        mcp-kali-server)
            install_apt_package "mcp-kali-server"
            register_mcp_server "kali-server" '{
                "command": "kali-server-mcp",
                "args": ["--port", "5000"]
            }'
            log_info "启动方式: kali-server-mcp --port 5000"
            log_info "然后用 mcp-server 连接 AI 客户端到 API server"
            ;;
        metasploitmcp)
            install_apt_package "metasploitmcp"
            register_mcp_server "metasploit-mcp" '{
                "command": "metasploitmcp",
                "args": ["--transport", "stdio"]
            }'
            log_info "MetasploitMCP 支持 stdio 和 HTTP 两种模式"
            log_info "  stdio: metasploitmcp --transport stdio"
            log_info "  HTTP:  metasploitmcp --transport http --port 8085"
            ;;
        hexstrike-ai)
            install_apt_package "hexstrike-ai"
            register_mcp_server "hexstrike" '{
                "command": "hexstrike-ai",
                "args": []
            }'
            log_info "HexStrike AI 已安装。150+ 安全工具通过 MCP 暴露给 AI agent。"
            ;;
        # ─── Pentest Swarm AI（群体智能渗透框架） ───
        pentestswarm)
            if command -v pentestswarm &>/dev/null; then
                log_ok "pentestswarm 已可用"
            elif command -v go &>/dev/null; then
                log_info "go install pentestswarm ..."
                go install github.com/Armur-Ai/Pentest-Swarm-AI/cmd/pentestswarm@v0.1.0
            elif command -v docker &>/dev/null; then
                log_info "拉取 pentestswarm Docker 镜像 ..."
                docker pull ghcr.io/armur-ai/pentestswarm:v0.1.0
                log_info "使用方式: docker run --rm ghcr.io/armur-ai/pentestswarm:v0.1.0 scan <target> --scope <scope>"
            else
                log_warn "需要 Go 1.24+ 或 Docker 来安装 pentestswarm"
                log_info "安装 Go: apt install golang-go"
                log_info "然后: go install github.com/Armur-Ai/Pentest-Swarm-AI/cmd/pentestswarm@v0.1.0"
                return 1
            fi
            register_mcp_server "pentestswarm" '{
                "command": "pentestswarm",
                "args": ["mcp", "serve"]
            }'
            log_info "Pentest Swarm AI 已配置"
            log_info "  MCP 模式: pentestswarm mcp serve"
            log_info "  扫描模式: pentestswarm scan <target> --scope <scope> --swarm"
            log_info "  需要设置: export PENTESTSWARM_ORCHESTRATOR_API_KEY=<your-claude-key>"
            ;;

        # ─── pip 安装 ───
        frida|frida-ps)
            install_pip_package "frida-tools==14.10.4"
            ;;
        idalib-mcp)
            install_pip_package "ida-pro-mcp" "git+https://github.com/mrexodia/ida-pro-mcp.git@f82e6e2517a161b77e738951c3071cd446480ba0"
            log_info "运行 ida-pro-mcp --install 完成 IDA 插件安装"
            ;;
        proxycat)
            local proxycat_dir="$HOME/tools/ProxyCat"
            install_git_commit \
                "https://github.com/honmashironeko/ProxyCat.git" \
                "2309b713e2e4f574df14c2ace7e8fa6c00eb6941" \
                "$proxycat_dir"
            pip3 install --upgrade -r "$proxycat_dir/requirements.txt" --break-system-packages 2>/dev/null \
                || pip3 install --upgrade -r "$proxycat_dir/requirements.txt"
            local proxycat_bin_dir="$HOME/.local/bin"
            local proxycat_wrapper="$proxycat_bin_dir/proxycat"
            mkdir -p "$proxycat_bin_dir"
            cat > "$proxycat_wrapper" <<EOF
#!/usr/bin/env bash
exec python3 "$proxycat_dir/ProxyCat.py" "\$@"
EOF
            chmod 0755 "$proxycat_wrapper"
            log_info "ProxyCat installed at pinned commit; command wrapper: $proxycat_wrapper"
            if [[ ":$PATH:" != *":$proxycat_bin_dir:"* ]]; then
                log_warn "Add $proxycat_bin_dir to PATH before using the proxycat command."
            fi
            ;;
        pwntools)
            install_pip_package "pwntools==4.15.0"
            ;;

        # ─── GitHub Release ───
        jadx)
            install_manifest_release "jadx"
            chmod +x "$HOME/tools/jadx/bin/jadx" 2>/dev/null || true
            ;;
        ghidra-mcp)
            if command -v ghidra &>/dev/null; then
                log_ok "ghidra 已通过 apt 安装"
            else
                install_apt_package "ghidra" 2>/dev/null \
                    || install_github_release "NationalSecurityAgency/ghidra" "^ghidra_.*_PUBLIC_.*\\.zip$" "$HOME/tools/ghidra"
            fi
            log_warn "GhidraMCP 插件需手动安装: https://github.com/LaurieWired/GhidraMCP/releases"
            ;;
        nuclei)
            if command -v go &>/dev/null; then
                log_info "go install nuclei ..."
                go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@v3.8.0
            else
                install_github_release "projectdiscovery/nuclei" "^nuclei_.*_linux_amd64\\.zip$" "$HOME/tools/nuclei" "v3.8.0"
            fi
            ;;

        # ─── npm/MCP ───
        jeb-pro)
            log_warn "MANUAL_INSTALL_REQUIRED: jeb-pro"
            log_warn "JEB Pro 是商业工具；请从 PNF Software 获取有效许可证后手动安装。社区 MCP 桥接必须先按 skill-supply-chain.md 审查。"
            LAST_CAPABILITY_MANUAL=true
            MANUAL_REQUIRED=true
            return 0
            ;;
        reqable-mcp)
            if ! command -v node &>/dev/null; then
                install_apt_package "nodejs"
            fi
            if ! command -v npm &>/dev/null; then
                install_apt_package "npm"
            fi
            register_mcp_server "reqable-mcp" '{
                "command": "npx",
                "args": ["-y", "reqable-mcp-server@1.0.1", "--scope", "minimal"]
            }'
            log_warn "Reqable MCP 需要单独安装 Reqable 桌面客户端并启用其本地 API。"
            ;;
        jshookmcp)
            if ! command -v node &>/dev/null; then
                install_apt_package "nodejs"
            fi
            if ! command -v npm &>/dev/null; then
                install_apt_package "npm"
            fi
            register_mcp_server "jshook" '{
                "command": "npx",
                "args": ["-y", "@jshookmcp/jshook@0.3.4"],
                "env": {"JSHOOK_BASE_PROFILE": "search"}
            }'
            ;;
        agent-browser)
            if ! command -v node &>/dev/null; then
                install_apt_package "nodejs"
            fi
            install_npm_global "agent-browser@0.31.1"
            npx playwright install chromium 2>/dev/null || true
            ;;

        # ─── 本地 HTTP MCP 服务 ───
        anything-analyzer)
            register_mcp_server "anything-analyzer" "{\"url\": \"http://localhost:23816/mcp\"}"
            if [[ "$START_SERVICES" == "true" ]]; then
                start_anything_analyzer
            fi
            ;;
        idapro)
            # 先确保 idalib-mcp 已安装
            ensure_capability "idalib-mcp"
            register_mcp_server "idapro" "{\"url\": \"http://127.0.0.1:13337/mcp\"}"
            if [[ "$START_SERVICES" == "true" ]]; then
                start_idapro_service
            fi
            ;;

        # ─── 手动安装 ───
        burpsuite-mcp)
            log_warn "MANUAL_INSTALL_REQUIRED: burpsuite-mcp"
            log_warn "Kali 预装 BurpSuite，在扩展市场搜索 MCP 插件安装"
            register_mcp_server "burpsuite" "{\"url\": \"http://localhost:9876/mcp\"}"
            ;;

        *)
            log_err "未知能力: $name"
            return 1
            ;;
    esac
}

# ─── 服务启动 ──────────────────────────────────────────────────────────────────────

start_anything_analyzer() {
    if test_tcp_port 23816 2>/dev/null; then
        log_ok "anything-analyzer 已在运行 (port 23816)"
        return 0
    fi

    local repo_dir="$HOME/tools/anything-analyzer"

    if [[ ! -d "$repo_dir" ]]; then
        log_info "克隆 anything-analyzer ..."
        git clone https://github.com/Mouseww/anything-analyzer.git "$repo_dir"
    fi

    if ! command -v pnpm &>/dev/null; then
        npm install -g pnpm
    fi

    (cd "$repo_dir" && pnpm install && nohup pnpm dev > /tmp/anything-analyzer.log 2>&1 &)

    log_info "等待 anything-analyzer 启动 (port 23816) ..."
    if wait_for_port 23816 120; then
        log_ok "anything-analyzer 已启动"
    else
        log_err "anything-analyzer 启动超时，查看日志: /tmp/anything-analyzer.log"
        return 1
    fi
}

start_idapro_service() {
    if test_tcp_port 13337 2>/dev/null; then
        log_ok "IDA Pro MCP 已在运行 (port 13337)"
        return 0
    fi

    local ida_start_script="$SCRIPT_DIR/ida-start.sh"
    if [[ -x "$ida_start_script" ]]; then
        bash "$ida_start_script"
    else
        log_warn "IDA 启动脚本不存在: $ida_start_script"
        log_warn "请手动启动 IDA Pro，插件会自动监听 13337 端口"
        return 1
    fi
}

# ─── 主流程 ────────────────────────────────────────────────────────────────────────

RESULTS=()

for cap in "${CAPABILITIES[@]}"; do
    LAST_CAPABILITY_MANUAL=false
    if ensure_capability "$cap"; then
        if [[ "$LAST_CAPABILITY_MANUAL" == "true" ]]; then
            RESULTS+=("{\"name\":\"$cap\",\"status\":\"manual-required\"}")
        else
            RESULTS+=("{\"name\":\"$cap\",\"status\":\"ready\"}")
        fi
    else
        RESULTS+=("{\"name\":\"$cap\",\"status\":\"failed\"}")
    fi
done

# 刷新工具索引
if [[ "$SKIP_REFRESH" != "true" ]]; then
    log_info "刷新工具索引 ..."
    bash "$SCRIPT_DIR/refresh-tool-index.sh" >/dev/null 2>&1 || true
fi

final_exit_code=0
if [[ "$MANUAL_REQUIRED" == "true" ]]; then
    final_exit_code=2
fi

# 输出结果
echo ""
echo "═══════════════════════════════════════════"
echo "  Bootstrap 完成"
echo "═══════════════════════════════════════════"
for r in "${RESULTS[@]}"; do
    name=$(echo "$r" | jq -r '.name' 2>/dev/null || echo "$r")
    status=$(echo "$r" | jq -r '.status' 2>/dev/null || echo "unknown")
    if [[ "$status" == "ready" ]]; then
        echo "  ✓ $name"
    elif [[ "$status" == "manual-required" ]]; then
        echo "  ! $name (manual install required)"
    else
        echo "  ✗ $name (failed)"
    fi
done
echo ""
exit "$final_exit_code"
