From e17598e419b598000e2d30a329be91efae6c0758 Mon Sep 17 00:00:00 2001 From: Martin Perez Rodriguez Date: Thu, 5 Mar 2026 13:57:22 +0100 Subject: [PATCH 01/10] Improve macOS installer flow and runtime compatibility --- README.md | 43 ++++++-- install.sh | 287 +++++++++++++++++++++++--------------------------- launcher.sh | 297 +++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 432 insertions(+), 195 deletions(-) diff --git a/README.md b/README.md index c2e1ffa..ddeada6 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Interactive wizard that clones the BugTraceAI repos, builds Docker images, gener **One-liner install** (recommended): ```bash -git clone https://github.com/BugTraceAI/BugTraceAI-Launcher.git ~/bugtraceai-launcher && ~/bugtraceai-launcher/launcher.sh +curl -fsSL https://raw.githubusercontent.com/BugTraceAI/BugTraceAI-Launcher/main/install.sh | bash ``` Or step by step: @@ -46,7 +46,7 @@ The wizard will guide you step by step: choose deployment mode, enter your OpenR | Requirement | Details | |-------------|---------| | **OS** | Linux (x86_64) or macOS (Intel / Apple Silicon) | -| **Docker** | 24.0+ with Docker Compose v2 — [Docker Desktop](https://www.docker.com/products/docker-desktop/) on macOS | +| **Container Runtime** | Docker Engine 24.0+ + Compose (Linux), or on macOS: **Docker Desktop** OR **Colima** | | **Git** | Any recent version | | **curl** | For the one-liner installer | | **RAM** | 4 GB minimum (8 GB recommended) | @@ -63,9 +63,24 @@ The wizard will guide you step by step: choose deployment mode, enter your OpenR You'll be prompted for confirmation before anything is installed. If you're on a non-Debian system, the installer will provide manual installation instructions. -### macOS +### Auto-Installation (macOS) -Install [Docker Desktop](https://docs.docker.com/desktop/install/mac-install/) before running the launcher. The script automatically detects Docker Desktop's install location (`~/.docker/bin`, `/usr/local/bin`, Homebrew) and adds it to the PATH if needed. Git and curl are included with Xcode Command Line Tools (`xcode-select --install`). +The launcher now supports **two runtime paths** on macOS: + +- **Docker Desktop** (traditional) +- **Colima** (Docker Desktop-free) + +If Docker is not ready, the wizard can: + +- Prompt you to choose Docker Desktop or Colima +- Install missing dependencies with Homebrew (`docker`, `docker-compose`, `colima`, `qemu`, `lima-additional-guestagents`) +- Start the selected runtime automatically and continue installation + +For best automation, install Xcode CLT first if missing: + +```bash +xcode-select --install +``` ## Deployment Modes @@ -94,7 +109,7 @@ In **Full** mode the launcher automatically configures CORS and points the WEB f ./launcher.sh help # Show usage ``` -> No `sudo` required. On Linux, your user needs Docker permissions (`sudo usermod -aG docker $USER`). On macOS, Docker Desktop handles permissions automatically. +> No `sudo` required. On Linux, your user needs Docker permissions (`sudo usermod -aG docker $USER`). On macOS, the launcher can bootstrap either Docker Desktop or Colima. ## Architecture @@ -213,7 +228,14 @@ docker ps -a | grep bugtraceai # Raw container status **Permission issues (Linux):** Your user needs Docker permissions. Run `sudo usermod -aG docker $USER` and re-login. -**Docker not found (macOS):** Make sure Docker Desktop is installed and running. The launcher auto-detects common install paths, but if Docker still isn't found, open Docker Desktop first and try again. +**Docker not found (macOS):** Re-run `./launcher.sh` and choose a runtime when prompted. If you pick Colima, the launcher can install/start it automatically via Homebrew. + +**Colima start fails with missing guest agent:** Install and retry: + +```bash +brew install lima-additional-guestagents +colima start --runtime docker +``` **Existing installation detected:** If `~/bugtraceai/` already exists, the wizard offers to reinstall (wipe + fresh setup) or update (pull + rebuild). @@ -221,10 +243,11 @@ docker ps -a | grep bugtraceai # Raw container status The one-liner clones this repo to `~/bugtraceai-launcher/` and launches the interactive wizard, which: -1. **Checks dependencies**: Docker, Docker Compose, Git, curl, RAM, and disk space -2. **Selects deployment mode**: Full (WEB + CLI), Standalone WEB, or Standalone CLI -3. **Configures**: Asks for OpenRouter API key, proposes ports, generates `.env` files -4. **Deploys**: Clones repos, builds Docker images, starts services, runs health checks +1. **Bootstraps dependencies**: Git/curl first, then Docker runtime + Compose checks +2. **Selects macOS runtime when needed**: Docker Desktop or Colima +3. **Selects deployment mode**: Full (WEB + CLI), Standalone WEB, or Standalone CLI +4. **Configures**: Asks for OpenRouter API key, proposes ports, generates `.env` files +5. **Deploys**: Clones repos, builds Docker images, starts services, runs health checks ## License diff --git a/install.sh b/install.sh index ab567a0..e92e1fe 100755 --- a/install.sh +++ b/install.sh @@ -1,196 +1,167 @@ -#!/bin/bash +#!/usr/bin/env bash # -# BugTraceAI One-Liner Installer +# BugTraceAI one-liner bootstrap installer # # Usage: -# curl -fsSL https://raw.githubusercontent.com/BugTraceAI/BugTraceAI-Launcher/main/install.sh | sudo bash +# curl -fsSL https://raw.githubusercontent.com/BugTraceAI/BugTraceAI-Launcher/main/install.sh | bash # -set -e +set -euo pipefail -RED='\033[0;31m' GREEN='\033[0;32m' CYAN='\033[0;36m' -YELLOW='\033[1;33m' BOLD='\033[1m' NC='\033[0m' +RED='\033[0;31m' +GREEN='\033[0;32m' +CYAN='\033[0;36m' +YELLOW='\033[1;33m' +BOLD='\033[1m' +DIM='\033[2m' +NC='\033[0m' REPO_URL="https://github.com/BugTraceAI/BugTraceAI-Launcher.git" -LAUNCHER_DIR="/opt/bugtraceai-launcher" info() { echo -e "${CYAN}[INFO]${NC} $1"; } success() { echo -e "${GREEN}[OK]${NC} $1"; } warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } error() { echo -e "${RED}[ERROR]${NC} $1" >&2; } -# ── Dependency Auto-Installer ─────────────────────────────────────────────── +IS_MACOS=false +[[ "$(uname -s)" == "Darwin" ]] && IS_MACOS=true -if [[ $EUID -ne 0 ]]; then - error "This installer must be run as root." - echo -e " ${YELLOW}Usage:${NC} curl -fsSL | ${BOLD}sudo${NC} bash" +TARGET_USER="${SUDO_USER:-$USER}" +TARGET_HOME="$(eval echo "~$TARGET_USER")" +LAUNCHER_DIR="${BUGTRACEAI_LAUNCHER_DIR:-$TARGET_HOME/bugtraceai-launcher}" + +if $IS_MACOS && [[ $EUID -eq 0 ]] && [[ -z "${SUDO_USER:-}" ]]; then + error "On macOS, run this installer as your normal user (without sudo)." exit 1 fi -echo "" -echo -e "${CYAN}${BOLD}BugTraceAI Installer${NC}" -echo "" -info "Checking system requirements..." -echo "" - -# Check basic tools -missing_basic=() -for cmd in git curl; do - if ! command -v "$cmd" &>/dev/null; then - missing_basic+=("$cmd") - fi -done - -if [[ ${#missing_basic[@]} -gt 0 ]]; then - warn "Missing: ${missing_basic[*]}" - - # Detect package manager - if command -v apt-get &>/dev/null; then - echo -e " ${CYAN}Would you like to install them now? [Y/n]${NC}" - read -r confirm - if [[ "${confirm,,}" != "n" ]]; then - info "Installing ${missing_basic[*]}..." - apt-get update -qq - apt-get install -y "${missing_basic[@]}" - success "Installed ${missing_basic[*]}" - else - error "Cannot proceed without: ${missing_basic[*]}" - exit 1 - fi +run_privileged() { + if [[ $EUID -eq 0 ]]; then + "$@" else - error "Please install: ${missing_basic[*]}" - exit 1 + sudo "$@" fi -fi +} -# Check Docker -if ! command -v docker &>/dev/null; then - error "Docker is not installed." - echo "" - echo -e " ${YELLOW}Install Docker:${NC}" - echo -e " ${CYAN}https://docs.docker.com/engine/install/${NC}" - echo "" - echo -e " ${DIM}Quick install for Ubuntu/Debian:${NC}" - echo -e " ${DIM}curl -fsSL https://get.docker.com | sudo bash${NC}" - echo "" - exit 1 -fi +run_as_target() { + if [[ $EUID -eq 0 ]] && [[ -n "${SUDO_USER:-}" ]]; then + sudo -u "$TARGET_USER" "$@" + else + "$@" + fi +} -# Check Docker is running -if ! docker info &>/dev/null 2>&1; then - error "Docker is installed but not running." - echo -e " ${YELLOW}Start Docker:${NC} sudo systemctl start docker" - exit 1 -fi +detect_brew() { + if command -v brew >/dev/null 2>&1; then + command -v brew + return 0 + fi + if [[ -x /opt/homebrew/bin/brew ]]; then + echo "/opt/homebrew/bin/brew" + return 0 + fi + if [[ -x /usr/local/bin/brew ]]; then + echo "/usr/local/bin/brew" + return 0 + fi + return 1 +} + +ensure_homebrew() { + local brew_bin + if brew_bin="$(detect_brew)"; then + echo "$brew_bin" + return 0 + fi -# Check Docker Compose -has_compose_plugin=false -has_compose_standalone=false + warn "Homebrew is required to auto-install dependencies on macOS." + read -rp "$(echo -e "${YELLOW}Install Homebrew now? [Y/n]: ${NC}")" confirm + if [[ "${confirm:-}" =~ ^[Nn]$ ]]; then + return 1 + fi -if docker compose version &>/dev/null 2>&1; then - has_compose_plugin=true -fi + run_as_target env NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -if command -v docker-compose &>/dev/null && docker-compose version &>/dev/null 2>&1; then - has_compose_standalone=true -fi + brew_bin="$(detect_brew)" || return 1 + echo "$brew_bin" +} -if [[ "$has_compose_plugin" == false ]] && [[ "$has_compose_standalone" == false ]]; then - warn "Docker Compose is not installed." - echo "" - - # Try to auto-install the plugin on Ubuntu/Debian - if command -v apt-get &>/dev/null; then - echo -e " ${CYAN}Install Docker Compose plugin now? [Y/n]${NC}" - read -r confirm - if [[ "${confirm,,}" != "n" ]]; then - info "Installing docker-compose-plugin..." - if apt-get install -y docker-compose-plugin 2>/dev/null; then - success "Docker Compose plugin installed" - has_compose_plugin=true - else - warn "Could not install via apt. Trying standalone binary..." - # Fallback: install standalone binary - COMPOSE_VERSION=$(curl -fsSL https://api.github.com/repos/docker/compose/releases/latest | grep -Po '"tag_name": "\K.*?(?=")') - curl -fsSL "https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - chmod +x /usr/local/bin/docker-compose - - if docker-compose version &>/dev/null; then - success "Docker Compose standalone installed" - has_compose_standalone=true - else - error "Failed to install Docker Compose" - exit 1 - fi - fi - else - error "Docker Compose is required to continue." - echo -e " ${YELLOW}Install manually:${NC} https://docs.docker.com/compose/install/" - exit 1 +ensure_basic_tools() { + local missing=() + local cmd + for cmd in git curl; do + if ! command -v "$cmd" >/dev/null 2>&1; then + missing+=("$cmd") fi - else - error "Docker Compose is required." - echo -e " ${YELLOW}Install:${NC} https://docs.docker.com/compose/install/" - exit 1 + done + + if [[ ${#missing[@]} -eq 0 ]]; then + return 0 fi -fi -# Show what we detected -echo "" -success "All requirements met:" -echo -e " ✓ Docker $(docker --version 2>/dev/null | awk '{print $3}' | tr -d ',')" -if [[ "$has_compose_plugin" == true ]]; then - echo -e " ✓ Docker Compose (plugin) $(docker compose version 2>/dev/null | grep -oP '\d+\.\d+\.\d+' | head -1)" -elif [[ "$has_compose_standalone" == true ]]; then - echo -e " ✓ Docker Compose (standalone) $(docker-compose --version 2>/dev/null | grep -oP '\d+\.\d+\.\d+' | head -1)" -fi -echo -e " ✓ Git $(git --version | awk '{print $3}')" -echo -e " ✓ curl" -echo "" + warn "Missing required tools: ${missing[*]}" + + if $IS_MACOS; then + local brew_bin + brew_bin="$(ensure_homebrew)" || { + error "Cannot continue without: ${missing[*]}" + return 1 + } + info "Installing tools with Homebrew..." + run_as_target "$brew_bin" install "${missing[@]}" + return 0 + fi -# ── Download Launcher ──────────────────────────────────────────────────────── + if command -v apt-get >/dev/null 2>&1; then + info "Installing tools with apt-get..." + run_privileged apt-get update -qq + run_privileged apt-get install -y "${missing[@]}" + return 0 + fi + error "Please install manually: ${missing[*]}" + return 1 +} -if [[ -d "$LAUNCHER_DIR/.git" ]]; then - info "Launcher exists at $LAUNCHER_DIR, updating..." - (cd "$LAUNCHER_DIR" && git pull --quiet) || true - success "Launcher updated" -else - info "Downloading BugTraceAI Launcher..." - if git clone --depth 1 "$REPO_URL" "$LAUNCHER_DIR" 2>/dev/null; then - success "Launcher downloaded" - else - info "Git clone failed, trying tarball..." - tmpfile=$(mktemp) - if curl -fsSL "https://github.com/BugTraceAI/BugTraceAI-Launcher/archive/refs/heads/main.tar.gz" -o "$tmpfile"; then - mkdir -p "$LAUNCHER_DIR" - tar xzf "$tmpfile" -C "$LAUNCHER_DIR" --strip-components=1 - rm -f "$tmpfile" - success "Launcher downloaded (tarball)" - else - rm -f "$tmpfile" - error "Failed to download BugTraceAI Launcher" - exit 1 - fi +install_or_update_launcher() { + if [[ -d "$LAUNCHER_DIR/.git" ]]; then + info "Launcher already exists at $LAUNCHER_DIR, updating..." + run_as_target git -C "$LAUNCHER_DIR" pull --ff-only --quiet || warn "Could not fast-forward update launcher repo." + return 0 fi -fi -chmod +x "$LAUNCHER_DIR/launcher.sh" + info "Cloning BugTraceAI Launcher into $LAUNCHER_DIR..." + mkdir -p "$(dirname "$LAUNCHER_DIR")" + run_as_target git clone --depth 1 "$REPO_URL" "$LAUNCHER_DIR" +} -# ── Launch Wizard ──────────────────────────────────────────────────────────── +fix_permissions_if_needed() { + if [[ $EUID -eq 0 ]] && [[ -n "${SUDO_USER:-}" ]]; then + chown -R "$TARGET_USER":"$TARGET_USER" "$LAUNCHER_DIR" + fi +} + +launch_wizard() { + chmod +x "$LAUNCHER_DIR/launcher.sh" -if [[ -t 0 ]]; then - # Already interactive info "Starting BugTraceAI setup wizard..." - exec "$LAUNCHER_DIR/launcher.sh" -else - # Piped/Redirected - Try to reconnect to TTY - if [[ -c /dev/tty ]]; then - info "Piped execution detected. Reconnecting to terminal..." - exec "$LAUNCHER_DIR/launcher.sh" < /dev/tty - else - warn "No terminal detected. You might need to run the launcher manually:" - echo -e " ${BOLD}sudo $LAUNCHER_DIR/launcher.sh${NC}" - exit 0 + if [[ $EUID -eq 0 ]] && [[ -n "${SUDO_USER:-}" ]]; then + exec sudo -u "$TARGET_USER" "$LAUNCHER_DIR/launcher.sh" fi -fi + exec "$LAUNCHER_DIR/launcher.sh" +} + +echo "" +echo -e "${CYAN}${BOLD}BugTraceAI Bootstrap Installer${NC}" +echo "" + +ensure_basic_tools +install_or_update_launcher +fix_permissions_if_needed + +echo "" +success "Launcher is ready at: $LAUNCHER_DIR" +echo -e " ${DIM}The launcher will handle Docker/Colima runtime setup and dependency checks.${NC}" +echo "" + +launch_wizard diff --git a/launcher.sh b/launcher.sh index 6d980ba..39ec4bb 100755 --- a/launcher.sh +++ b/launcher.sh @@ -16,11 +16,6 @@ # uninstall Remove everything # -# ── Restore stdin if piped (e.g. curl | bash) ─────────────────────────────── -if [ ! -t 0 ]; then - exec /dev/null; then + COMPOSE_CMD="docker compose" + elif command -v docker-compose &>/dev/null && docker-compose version &>/dev/null 2>&1; then + COMPOSE_CMD="docker-compose" + fi +} + +wait_for_docker_daemon() { + local timeout=${1:-120} + local elapsed=0 + local interval=3 + while [[ $elapsed -lt $timeout ]]; do + if docker info &>/dev/null 2>&1; then + return 0 + fi + sleep "$interval" + elapsed=$((elapsed + interval)) + done + return 1 +} + +ensure_homebrew() { + if command -v brew &>/dev/null; then + return 0 + fi + + warn "Homebrew is required for automated macOS dependency installation." + read -rp "$(echo -e "${YELLOW}Install Homebrew now? [Y/n]: ${NC}")" confirm + if [[ "$(to_lower "${confirm:-}")" == "n" ]]; then + return 1 + fi + + NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || return 1 + + if [[ -x /opt/homebrew/bin/brew ]]; then + eval "$(/opt/homebrew/bin/brew shellenv)" + elif [[ -x /usr/local/bin/brew ]]; then + eval "$(/usr/local/bin/brew shellenv)" + fi + + command -v brew &>/dev/null +} + +ensure_macos_brew_packages() { + local formulas=("$@") + local missing=() + local formula + for formula in "${formulas[@]}"; do + if ! brew list --formula "$formula" &>/dev/null; then + missing+=("$formula") + fi + done + + if [[ ${#missing[@]} -eq 0 ]]; then + return 0 + fi + + info "Installing Homebrew packages: ${missing[*]}" + brew install "${missing[@]}" +} + +colima_profile_arch() { + colima list 2>/dev/null | awk 'NR==2{print $3}' +} + +maybe_fix_colima_arch() { + # On Apple Silicon, running an x86_64 Colima VM causes image arch mismatches. + if [[ "$(uname -m)" != "arm64" ]]; then + return 0 + fi + + local arch + arch="$(colima_profile_arch)" + if [[ "$arch" != "x86_64" ]]; then + return 0 + fi + + warn "Detected Colima profile arch=x86_64 on Apple Silicon." + warn "This can fail with container image format errors." + read -rp "$(echo -e "${YELLOW}Recreate Colima as arm64 (aarch64)? [Y/n]: ${NC}")" confirm + if [[ "$(to_lower "${confirm:-}")" == "n" ]]; then + warn "Continuing with x86_64 Colima profile (may fail for some images)." + return 0 + fi + + info "Recreating Colima profile with arm64 architecture..." + colima stop >/dev/null 2>&1 || true + colima delete -f >/dev/null 2>&1 || true +} + +ensure_docker_desktop_runtime() { + ensure_macos_docker_path + + if docker info &>/dev/null 2>&1; then + return 0 + fi + + if [[ ! -d "/Applications/Docker.app" ]]; then + if ! ensure_homebrew; then + error "Homebrew is required to install Docker Desktop automatically." + return 1 + fi + info "Installing Docker Desktop..." + brew install --cask docker + fi + + info "Starting Docker Desktop..." + open -a Docker || true + + if wait_for_docker_daemon 150; then + ensure_macos_docker_path + return 0 + fi + + error "Docker Desktop did not become ready in time." + return 1 +} + +ensure_colima_runtime() { + ensure_macos_docker_path + + if ! ensure_homebrew; then + error "Homebrew is required for Colima setup." + return 1 + fi + + ensure_macos_brew_packages docker docker-compose colima qemu lima-additional-guestagents + ensure_macos_docker_path + maybe_fix_colima_arch + + if docker info &>/dev/null 2>&1; then + return 0 + fi + + info "Starting Colima (Docker runtime)..." + local start_cmd=(colima start --runtime docker) + if [[ "$(uname -m)" == "arm64" ]]; then + start_cmd+=(--arch aarch64) + fi + local start_output + start_output=$("${start_cmd[@]}" 2>&1) || { + if echo "$start_output" | grep -qi "guest agent"; then + warn "Missing Lima guest agents detected. Installing helper package and retrying..." + ensure_macos_brew_packages lima-additional-guestagents || true + "${start_cmd[@]}" >/dev/null 2>&1 || { + error "Colima failed to start." + echo "$start_output" >&2 + return 1 + } + else + error "Colima failed to start." + echo "$start_output" >&2 + return 1 + fi + } + + if wait_for_docker_daemon 90; then + detect_compose_cmd + return 0 + fi + + error "Docker daemon did not become ready after Colima start." + return 1 +} + +ensure_macos_runtime_ready() { + ensure_macos_docker_path + detect_compose_cmd + + if docker info &>/dev/null 2>&1; then + return 0 + fi + + local has_colima=false + local has_docker_desktop=false + command -v colima &>/dev/null && has_colima=true + [[ -d "/Applications/Docker.app" ]] && has_docker_desktop=true + + if $has_colima; then + read -rp "$(echo -e "${YELLOW}Docker daemon is down. Start Colima now? [Y/n]: ${NC}")" confirm_colima + if [[ "$(to_lower "${confirm_colima:-}")" != "n" ]] && ensure_colima_runtime; then + return 0 + fi + fi + + if $has_docker_desktop; then + read -rp "$(echo -e "${YELLOW}Start Docker Desktop instead? [y/N]: ${NC}")" confirm_desktop + if [[ "$(to_lower "${confirm_desktop:-}")" == "y" ]] && ensure_docker_desktop_runtime; then + return 0 + fi + fi + + echo "" + select_option "Select container runtime for macOS setup:" \ + "Colima (Docker Desktop-free, recommended for OSS stack)" \ + "Docker Desktop" + + case $MENU_SELECTION in + 0) ensure_colima_runtime ;; + 1) ensure_docker_desktop_runtime ;; + *) return 1 ;; + esac +} + # Propose port with max 3 attempts. Exits if none accepted. # Usage: propose_port "Label" default_port RESULT_VAR propose_port() { @@ -423,29 +633,25 @@ check_for_updates() { # ── Pre-flight Checks ─────────────────────────────────────────────────────── -# On macOS, Docker Desktop may not be in PATH by default -if $IS_MACOS && ! command -v docker &>/dev/null; then - for p in "$HOME/.docker/bin" "/usr/local/bin" "/opt/homebrew/bin"; do - if [[ -x "$p/docker" ]]; then - export PATH="$p:$PATH" - break - fi - done -fi - -# Detect docker compose command -COMPOSE_CMD="" -if docker compose version &>/dev/null; then - COMPOSE_CMD="docker compose" -elif docker-compose version &>/dev/null; then - COMPOSE_CMD="docker-compose" +if $IS_MACOS; then + ensure_macos_docker_path fi +detect_compose_cmd check_deps() { info "Checking requirements..." echo "" local ok=true + if $IS_MACOS; then + ensure_macos_docker_path + if ! docker info &>/dev/null 2>&1; then + if ! ensure_macos_runtime_ready; then + ok=false + fi + fi + fi + if command -v docker &>/dev/null && docker info &>/dev/null 2>&1; then echo -e " ${OK} Docker $(docker --version 2>/dev/null | awk '{print $3}' | tr -d ',')" else @@ -453,12 +659,22 @@ check_deps() { ok=false fi + detect_compose_cmd if [[ -n "$COMPOSE_CMD" ]]; then version=$($COMPOSE_CMD version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) echo -e " ${OK} Docker Compose $version" else - # Try auto-installing Docker Compose v2 plugin - if ! $IS_MACOS; then + if $IS_MACOS; then + if ensure_homebrew && ensure_macos_brew_packages docker-compose; then + detect_compose_cmd + fi + fi + + if [[ -n "$COMPOSE_CMD" ]]; then + version=$($COMPOSE_CMD version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) + echo -e " ${OK} Docker Compose $version" + elif ! $IS_MACOS; then + # Try auto-installing Docker Compose v2 plugin echo -e " ${YELLOW}⚠${NC} Docker Compose not found — attempting auto-install..." local compose_installed=false @@ -511,7 +727,7 @@ check_deps() { fi else echo -e " ${FAIL} Docker Compose not found" - echo -e " ${DIM}Install Docker Desktop: https://docs.docker.com/desktop/install/mac-install/${NC}" + echo -e " ${DIM}Install via Homebrew: brew install docker-compose${NC}" ok=false fi fi @@ -665,18 +881,20 @@ wizard_select_provider() { } wizard_ask_api_key() { - local key_label key_url key_prefix key_env_var + local key_label key_url key_prefix key_env_var key_min_len if [[ "$LLM_PROVIDER" == "zai" ]]; then key_label="Z.ai (GLM)" key_url="https://open.bigmodel.cn/usercenter/apikeys" key_prefix="" key_env_var="GLM_API_KEY" + key_min_len=20 else key_label="OpenRouter" key_url="https://openrouter.ai/keys" key_prefix="sk-or-" key_env_var="OPENROUTER_API_KEY" + key_min_len=32 fi echo -e " ${DIM}BugTraceAI uses ${key_label} for AI-powered analysis.${NC}" @@ -692,6 +910,11 @@ wizard_ask_api_key() { continue fi + if (( ${#API_KEY} < key_min_len )); then + error "${key_label} API key appears too short (minimum ${key_min_len} characters)" + continue + fi + # Show masked key with last 4 chars for confirmation local key_len=${#API_KEY} if [[ $key_len -ge 8 ]]; then @@ -795,6 +1018,11 @@ wizard_show_summary() { } run_wizard() { + # Restore stdin if piped (e.g. curl | bash) + if [ ! -t 0 ] && [ -c /dev/tty ]; then + exec /dev/null || true + fi + show_banner # Detect existing installation @@ -1575,10 +1803,23 @@ _teardown_all() { # ── Docker Check ───────────────────────────────────────────────────────────── check_docker() { + if $IS_MACOS; then + ensure_macos_docker_path + if ! docker info &>/dev/null 2>&1; then + if ! ensure_macos_runtime_ready; then + error "Docker runtime is not ready." + exit 1 + fi + fi + fi + if ! command -v docker &>/dev/null; then error "Docker not found." if $IS_MACOS; then - echo -e " Install Docker Desktop: ${CYAN}https://docs.docker.com/desktop/install/mac-install/${NC}" + echo -e " Install runtime with launcher helper (recommended): rerun ./launcher.sh" + echo -e " Or install manually:" + echo -e " - Docker Desktop: ${CYAN}https://docs.docker.com/desktop/install/mac-install/${NC}" + echo -e " - Colima stack: ${DIM}brew install docker docker-compose colima qemu lima-additional-guestagents${NC}" else echo -e " Install Docker: ${CYAN}https://docs.docker.com/engine/install/${NC}" fi @@ -1605,6 +1846,8 @@ check_docker() { info "Applying new group, restarting launcher..." exec sg docker "$0 $*" fi + + detect_compose_cmd } # ── Help ───────────────────────────────────────────────────────────────────── From 2ec0f642a5cf33b5e57062adbeb7fde12bb63ac9 Mon Sep 17 00:00:00 2001 From: Martin Perez Rodriguez Date: Thu, 5 Mar 2026 14:16:56 +0100 Subject: [PATCH 02/10] Simplify macOS runtime selection prompt flow --- launcher.sh | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/launcher.sh b/launcher.sh index 39ec4bb..94cd434 100755 --- a/launcher.sh +++ b/launcher.sh @@ -337,27 +337,8 @@ ensure_macos_runtime_ready() { return 0 fi - local has_colima=false - local has_docker_desktop=false - command -v colima &>/dev/null && has_colima=true - [[ -d "/Applications/Docker.app" ]] && has_docker_desktop=true - - if $has_colima; then - read -rp "$(echo -e "${YELLOW}Docker daemon is down. Start Colima now? [Y/n]: ${NC}")" confirm_colima - if [[ "$(to_lower "${confirm_colima:-}")" != "n" ]] && ensure_colima_runtime; then - return 0 - fi - fi - - if $has_docker_desktop; then - read -rp "$(echo -e "${YELLOW}Start Docker Desktop instead? [y/N]: ${NC}")" confirm_desktop - if [[ "$(to_lower "${confirm_desktop:-}")" == "y" ]] && ensure_docker_desktop_runtime; then - return 0 - fi - fi - echo "" - select_option "Select container runtime for macOS setup:" \ + select_option "Docker daemon is down. Select runtime for macOS setup:" \ "Colima (Docker Desktop-free, recommended for OSS stack)" \ "Docker Desktop" From e086ea0ec450f155eaf8bf1f3b2dde3ffed94d14 Mon Sep 17 00:00:00 2001 From: Martin Perez Rodriguez Date: Thu, 5 Mar 2026 14:24:55 +0100 Subject: [PATCH 03/10] Fix macOS installer guard and reconFTW arm64 compatibility --- install.sh | 15 ++++++++++++--- launcher.sh | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/install.sh b/install.sh index e92e1fe..8c83195 100755 --- a/install.sh +++ b/install.sh @@ -23,15 +23,24 @@ success() { echo -e "${GREEN}[OK]${NC} $1"; } warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } error() { echo -e "${RED}[ERROR]${NC} $1" >&2; } +is_macos() { + local kernel + kernel="$(uname -s 2>/dev/null || true)" + [[ "$kernel" == "Darwin" ]] && return 0 + command -v sw_vers >/dev/null 2>&1 +} + IS_MACOS=false -[[ "$(uname -s)" == "Darwin" ]] && IS_MACOS=true +if is_macos; then + IS_MACOS=true +fi TARGET_USER="${SUDO_USER:-$USER}" TARGET_HOME="$(eval echo "~$TARGET_USER")" LAUNCHER_DIR="${BUGTRACEAI_LAUNCHER_DIR:-$TARGET_HOME/bugtraceai-launcher}" -if $IS_MACOS && [[ $EUID -eq 0 ]] && [[ -z "${SUDO_USER:-}" ]]; then - error "On macOS, run this installer as your normal user (without sudo)." +if [[ "$IS_MACOS" == true && $EUID -eq 0 ]]; then + error "On macOS, do not run this installer with sudo/root. Run as your normal user." exit 1 fi diff --git a/launcher.sh b/launcher.sh index 94cd434..419436c 100755 --- a/launcher.sh +++ b/launcher.sh @@ -153,6 +153,29 @@ sed_inplace() { fi } +ensure_recon_amd64_platform() { + local compose_file=$1 + local tmp_file + tmp_file="$(mktemp)" + + # six2dez/reconftw:main is amd64-only at the moment; force platform so ARM hosts + # use emulation instead of failing manifest resolution. + awk ' + BEGIN { in_recon=0; has_platform=0 } + /^ reconftw-mcp:[[:space:]]*$/ { in_recon=1; print; next } + in_recon && /^ [^[:space:]]/ { + if (!has_platform) print " platform: linux/amd64" + in_recon=0 + } + in_recon && /^[[:space:]]+platform:[[:space:]]*linux\/amd64[[:space:]]*$/ { has_platform=1 } + { print } + END { + if (in_recon && !has_platform) print " platform: linux/amd64" + }' "$compose_file" > "$tmp_file" + + mv "$tmp_file" "$compose_file" +} + ensure_macos_docker_path() { for p in "$HOME/.docker/bin" "/usr/local/bin" "/opt/homebrew/bin"; do if [[ -x "$p/docker" ]]; then @@ -1273,12 +1296,19 @@ patch_compose() { # Patch WEB docker-compose for MCP agents if [[ -f "$WEB_DIR/docker-compose.yml" ]] && [[ -n "$profiles" ]]; then local web_compose="$WEB_DIR/docker-compose.yml" + local host_arch + host_arch="$(uname -m)" # Patch reconFTW port if non-default if $MCP_RECON_ENABLED && [[ -n "$RECON_PORT" && "$RECON_PORT" != "8002" ]]; then sed_inplace "s/\"8002:8002\"/\"${RECON_PORT}:8002\"/" "$web_compose" fi + # reconFTW base image is currently amd64-only; enforce emulation on ARM hosts. + if $MCP_RECON_ENABLED && [[ "$host_arch" == "arm64" || "$host_arch" == "aarch64" ]]; then + ensure_recon_amd64_platform "$web_compose" + fi + # Patch CLI MCP port if non-default if $MCP_CLI_ENABLED && [[ -n "$MCP_PORT" && "$MCP_PORT" != "8001" ]]; then sed_inplace "s/\"8001:8001\"/\"${MCP_PORT}:8001\"/" "$web_compose" From dfee733782987930e2f5667b3408006450e75e5a Mon Sep 17 00:00:00 2001 From: Martin Perez Rodriguez Date: Thu, 5 Mar 2026 15:06:52 +0100 Subject: [PATCH 04/10] Patch reconFTW Dockerfile for ARM and venv compatibility --- launcher.sh | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/launcher.sh b/launcher.sh index 419436c..1026c41 100755 --- a/launcher.sh +++ b/launcher.sh @@ -176,6 +176,45 @@ ensure_recon_amd64_platform() { mv "$tmp_file" "$compose_file" } +patch_recon_dockerfile_venv() { + local dockerfile="$RECON_DIR/Dockerfile" + local host_arch + local tmp_file + + [[ -f "$dockerfile" ]] || return 0 + + host_arch="$(uname -m)" + if [[ "$host_arch" == "arm64" || "$host_arch" == "aarch64" ]]; then + if ! grep -q "^FROM --platform=linux/amd64 six2dez/reconftw:main" "$dockerfile"; then + sed_inplace -E 's|^FROM[[:space:]]+six2dez/reconftw:main|FROM --platform=linux/amd64 six2dez/reconftw:main|' "$dockerfile" + info "Applied reconftw-mcp amd64 base image pin for ARM hosts." + fi + fi + + # Already patched or upstream fixed. + if grep -q "python3 -m virtualenv /opt/mcp-venv" "$dockerfile"; then + return 0 + fi + + if ! grep -q "RUN python3 -m venv /opt/mcp-venv" "$dockerfile"; then + return 0 + fi + + tmp_file="$(mktemp)" + awk ' + /RUN python3 -m venv \/opt\/mcp-venv/ { + print "RUN python3 -m venv /opt/mcp-venv || \\" + print " ( (python3 -m pip install --no-cache-dir virtualenv || python3 -m pip install --no-cache-dir --break-system-packages virtualenv) && \\" + print " python3 -m virtualenv /opt/mcp-venv )" + next + } + { print } + ' "$dockerfile" > "$tmp_file" + + mv "$tmp_file" "$dockerfile" + info "Applied reconftw-mcp Python venv compatibility patch." +} + ensure_macos_docker_path() { for p in "$HOME/.docker/bin" "/usr/local/bin" "/opt/homebrew/bin"; do if [[ -x "$p/docker" ]]; then @@ -1159,6 +1198,7 @@ clone_repos() { exit 1 fi fi + patch_recon_dockerfile_venv echo -e " ${OK} reconftw-mcp" fi } @@ -1759,6 +1799,7 @@ cmd_update() { if ! (cd "$RECON_DIR" && git pull --quiet); then warn "Failed to pull Recon updates" fi + patch_recon_dockerfile_venv echo -e " ${OK} Recon updated" fi From a6860505176d8fefdc60d0bee3d1a2c3a3513f32 Mon Sep 17 00:00:00 2001 From: Martin Perez Rodriguez Date: Thu, 5 Mar 2026 15:31:32 +0100 Subject: [PATCH 05/10] Force recon MCP SSE mode and relax ARM startup checks --- launcher.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/launcher.sh b/launcher.sh index 1026c41..41b9bda 100755 --- a/launcher.sh +++ b/launcher.sh @@ -1339,6 +1339,14 @@ patch_compose() { local host_arch host_arch="$(uname -m)" + # Launcher expects MCP agents over SSE; make SSE default for WEB-managed MCP services. + if $MCP_RECON_ENABLED; then + sed_inplace 's/SSE_MODE=${RECON_SSE_MODE:-false}/SSE_MODE=${RECON_SSE_MODE:-true}/' "$web_compose" + fi + if $MCP_CLI_ENABLED; then + sed_inplace 's/SSE_MODE=${CLI_SSE_MODE:-false}/SSE_MODE=${CLI_SSE_MODE:-true}/' "$web_compose" + fi + # Patch reconFTW port if non-default if $MCP_RECON_ENABLED && [[ -n "$RECON_PORT" && "$RECON_PORT" != "8002" ]]; then sed_inplace "s/\"8002:8002\"/\"${RECON_PORT}:8002\"/" "$web_compose" @@ -1472,7 +1480,14 @@ health_checks() { fi if $MCP_RECON_ENABLED && [[ -n "$RECON_PORT" ]]; then - wait_for_url "http://localhost:${RECON_PORT}/sse" "reconFTW MCP (port ${RECON_PORT})" 120 || all_ok=false + local recon_timeout=180 + local host_arch + host_arch="$(uname -m)" + if [[ "$host_arch" == "arm64" || "$host_arch" == "aarch64" ]]; then + # reconFTW runs in amd64 emulation on Apple Silicon and may need extra warmup time. + recon_timeout=300 + fi + wait_for_url "http://localhost:${RECON_PORT}/sse" "reconFTW MCP (port ${RECON_PORT})" "$recon_timeout" || all_ok=false fi if $MCP_KALI_ENABLED && [[ -n "$KALI_PORT" ]]; then From 0b34e6aa1ff8dd4455c847d89696500cb949959f Mon Sep 17 00:00:00 2001 From: Martin Perez Rodriguez Date: Thu, 5 Mar 2026 15:50:44 +0100 Subject: [PATCH 06/10] Stabilize reconFTW MCP startup on macOS ARM --- launcher.sh | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/launcher.sh b/launcher.sh index 41b9bda..3aab300 100755 --- a/launcher.sh +++ b/launcher.sh @@ -176,6 +176,83 @@ ensure_recon_amd64_platform() { mv "$tmp_file" "$compose_file" } +ensure_recon_health_timing() { + local compose_file=$1 + local tmp_file + tmp_file="$(mktemp)" + + awk ' + BEGIN { in_recon=0 } + /^ reconftw-mcp:[[:space:]]*$/ { in_recon=1; print; next } + in_recon && /^ [^[:space:]]/ { in_recon=0 } + in_recon && /^[[:space:]]+retries:[[:space:]]*[0-9]+[[:space:]]*$/ { print " retries: 10"; next } + in_recon && /^[[:space:]]+start_period:[[:space:]]*[0-9]+s[[:space:]]*$/ { print " start_period: 300s"; next } + { print } + ' "$compose_file" > "$tmp_file" + + mv "$tmp_file" "$compose_file" +} + +patch_recon_entrypoint_startup() { + local entrypoint="$RECON_DIR/entrypoint.sh" + local tmp_file + + [[ -f "$entrypoint" ]] || return 0 + + # Already patched. + if grep -q "RECONFTW_AUTO_INSTALL" "$entrypoint"; then + return 0 + fi + + tmp_file="$(mktemp)" + awk ' + BEGIN { in_old_block=0 } + /^# Check if reconftw\.sh exists$/ { + in_old_block=1 + print "# Check if reconftw.sh exists" + print "# Try to discover an existing install first to avoid expensive bootstrap on container start." + print "if [ ! -f \"$RECONFTW_DIR/reconftw.sh\" ]; then" + print " FOUND_RECONFTW_SCRIPT=\"$(find /opt /root /usr /home -maxdepth 5 -type f -name reconftw.sh 2>/dev/null | head -n 1 || true)\"" + print " if [ -n \"$FOUND_RECONFTW_SCRIPT\" ]; then" + print " RECONFTW_DIR=\"$(dirname \"$FOUND_RECONFTW_SCRIPT\")\"" + print " log_info \"Detected existing reconftw at $RECONFTW_DIR\"" + print " fi" + print "fi" + print "" + print "if [ ! -f \"$RECONFTW_DIR/reconftw.sh\" ]; then" + print " log_warn \"reconftw.sh not found at $RECONFTW_DIR/reconftw.sh\"" + print " log_info \"Attempting to clone reconftw repository...\"" + print "" + print " git clone --depth 1 https://github.com/six2dez/reconftw.git \"$RECONFTW_DIR\" 2>/dev/null || {" + print " log_error \"Failed to clone reconftw repository\"" + print " exit 1" + print " }" + print "" + print " cd \"$RECONFTW_DIR\"" + print " chmod +x reconftw.sh" + print "" + print " if [ \"${RECONFTW_AUTO_INSTALL:-false}\" = \"true\" ] && [ -f \"install.sh\" ]; then" + print " log_info \"Installing reconftw dependencies...\"" + print " ./install.sh 2>/dev/null || log_warn \"Some dependencies may have failed to install\"" + print " else" + print " log_warn \"Skipping reconftw install.sh bootstrap during startup (set RECONFTW_AUTO_INSTALL=true to enable).\"" + print " fi" + print "fi" + next + } + in_old_block && /^# Make reconftw executable$/ { + in_old_block=0 + print + next + } + in_old_block { next } + { print } + ' "$entrypoint" > "$tmp_file" + + mv "$tmp_file" "$entrypoint" + info "Applied reconftw-mcp startup bootstrap compatibility patch." +} + patch_recon_dockerfile_venv() { local dockerfile="$RECON_DIR/Dockerfile" local host_arch @@ -191,6 +268,8 @@ patch_recon_dockerfile_venv() { fi fi + patch_recon_entrypoint_startup + # Already patched or upstream fixed. if grep -q "python3 -m virtualenv /opt/mcp-venv" "$dockerfile"; then return 0 @@ -1355,6 +1434,7 @@ patch_compose() { # reconFTW base image is currently amd64-only; enforce emulation on ARM hosts. if $MCP_RECON_ENABLED && [[ "$host_arch" == "arm64" || "$host_arch" == "aarch64" ]]; then ensure_recon_amd64_platform "$web_compose" + ensure_recon_health_timing "$web_compose" fi # Patch CLI MCP port if non-default From cacd71abae1dcf4a93dc6718bf43bc91d0bb6447 Mon Sep 17 00:00:00 2001 From: Martin Perez Rodriguez Date: Thu, 5 Mar 2026 15:56:55 +0100 Subject: [PATCH 07/10] Make recon auto-install disable explicit in compose patch --- launcher.sh | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/launcher.sh b/launcher.sh index 3aab300..200a8c2 100755 --- a/launcher.sh +++ b/launcher.sh @@ -193,6 +193,36 @@ ensure_recon_health_timing() { mv "$tmp_file" "$compose_file" } +ensure_recon_env_defaults() { + local compose_file=$1 + local tmp_file + tmp_file="$(mktemp)" + + awk ' + BEGIN { in_recon=0; has_auto=0; inserted=0 } + /^ reconftw-mcp:[[:space:]]*$/ { in_recon=1; has_auto=0; inserted=0; print; next } + in_recon && /^[[:space:]]+- RECONFTW_AUTO_INSTALL=/ { has_auto=1 } + in_recon && /^[[:space:]]+- MCP_PORT=8002[[:space:]]*$/ { + print + if (!has_auto && !inserted) { + print " - RECONFTW_AUTO_INSTALL=false" + inserted=1 + } + next + } + in_recon && /^ [^[:space:]]/ { + if (!has_auto && !inserted) print " - RECONFTW_AUTO_INSTALL=false" + in_recon=0 + } + { print } + END { + if (in_recon && !has_auto && !inserted) print " - RECONFTW_AUTO_INSTALL=false" + } + ' "$compose_file" > "$tmp_file" + + mv "$tmp_file" "$compose_file" +} + patch_recon_entrypoint_startup() { local entrypoint="$RECON_DIR/entrypoint.sh" local tmp_file @@ -1436,6 +1466,9 @@ patch_compose() { ensure_recon_amd64_platform "$web_compose" ensure_recon_health_timing "$web_compose" fi + if $MCP_RECON_ENABLED; then + ensure_recon_env_defaults "$web_compose" + fi # Patch CLI MCP port if non-default if $MCP_CLI_ENABLED && [[ -n "$MCP_PORT" && "$MCP_PORT" != "8001" ]]; then From ff47b76c3ef9a3aacd5f3a55d9f40c0e000008db Mon Sep 17 00:00:00 2001 From: Martin Perez Rodriguez Date: Thu, 5 Mar 2026 16:04:06 +0100 Subject: [PATCH 08/10] Fix Kali MCP startup command parsing on macOS --- launcher.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/launcher.sh b/launcher.sh index 200a8c2..05e8850 100755 --- a/launcher.sh +++ b/launcher.sh @@ -223,6 +223,34 @@ ensure_recon_env_defaults() { mv "$tmp_file" "$compose_file" } +ensure_kali_startup_command() { + local compose_file=$1 + local tmp_file + tmp_file="$(mktemp)" + + awk ' + BEGIN { in_kali=0; in_cmd=0 } + /^ kali-mcp:[[:space:]]*$/ { in_kali=1; print; next } + in_kali && /^ [^[:space:]]/ { in_kali=0 } + in_kali && /^[[:space:]]+command:[[:space:]]*>[[:space:]]*$/ { + in_cmd=1 + print " command: >" + print " bash -lc \"set -e; echo '\''Waiting for network initialization...'\''; sleep 5; apt-get update; DEBIAN_FRONTEND=noninteractive apt-get install -y nmap ffuf nuclei sqlmap dirb gobuster nikto hydra john hashcat curl wget netcat-openbsd python3 python3-pip git vim; command -v nmap hydra python3 >/dev/null; echo '\''Kali MCP Server ready!'\''; tail -f /dev/null\"" + next + } + in_cmd { + if (in_kali && /^[[:space:]]+(extra_hosts:|restart:|networks:|ports:|volumes:|environment:|cap_add:|security_opt:|profiles:|container_name:|image:)/) { + in_cmd=0 + print + } + next + } + { print } + ' "$compose_file" > "$tmp_file" + + mv "$tmp_file" "$compose_file" +} + patch_recon_entrypoint_startup() { local entrypoint="$RECON_DIR/entrypoint.sh" local tmp_file @@ -1469,6 +1497,9 @@ patch_compose() { if $MCP_RECON_ENABLED; then ensure_recon_env_defaults "$web_compose" fi + if $MCP_KALI_ENABLED; then + ensure_kali_startup_command "$web_compose" + fi # Patch CLI MCP port if non-default if $MCP_CLI_ENABLED && [[ -n "$MCP_PORT" && "$MCP_PORT" != "8001" ]]; then From 0435814a3f5b3da2f5442bad9a9f1f3274f566c0 Mon Sep 17 00:00:00 2001 From: Martin Perez Rodriguez Date: Thu, 5 Mar 2026 16:14:11 +0100 Subject: [PATCH 09/10] Document reconFTW/Kali deployment hardening and risk notes --- README.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/README.md b/README.md index ddeada6..9947f40 100644 --- a/README.md +++ b/README.md @@ -237,6 +237,41 @@ brew install lima-additional-guestagents colima start --runtime docker ``` +### macOS MCP Compatibility Notes (reconFTW + Kali) + +The launcher now applies macOS-focused compatibility patches during deployment when these MCPs are enabled. + +**reconFTW MCP (Apple Silicon):** +- Forces `linux/amd64` for `six2dez/reconftw:main` on ARM hosts. +- Patches `reconftw-mcp` Dockerfile for Python venv fallback (`virtualenv`) when `ensurepip` fails. +- Forces SSE mode for WEB-managed MCP startup (`/sse` health path consistency). +- Extends reconFTW health timing on ARM emulation. +- Patches startup behavior to skip heavy `reconftw/install.sh` auto-bootstrap by default (`RECONFTW_AUTO_INSTALL=false`) to avoid health timeouts. + +**Kali MCP:** +- Rewrites the Kali startup command into a robust single `bash -lc` command to avoid multiline parsing/continuation issues during package install. +- Verifies key binaries (`nmap`, `hydra`, `python3`) after install in container startup. + +If you still see MCP issues after pulling latest launcher changes, rebuild only the affected service: + +```bash +cd ~/bugtraceai/BugTraceAI-WEB +docker compose --env-file .env.docker build --no-cache reconftw-mcp kali-mcp +docker compose --env-file .env.docker up -d reconftw-mcp kali-mcp +``` + +Then inspect logs: + +```bash +docker logs --tail 200 reconftw-mcp +docker logs --tail 200 kali-mcp-server +``` + +### Regression Risk (non-macOS) + +- Expected risk for Linux users is **low**: most new behavior is gated to macOS and/or ARM and only applies when optional MCP profiles are enabled. +- Main maintenance risk is future upstream format changes in patched compose/Dockerfile/entrypoint files; launcher patch anchors may need updates if upstream structure changes. + **Existing installation detected:** If `~/bugtraceai/` already exists, the wizard offers to reinstall (wipe + fresh setup) or update (pull + rebuild). ## How the Install Script Works From 511451623135d5e3c0b42e0b23bce02479655f8b Mon Sep 17 00:00:00 2001 From: Martin Perez Rodriguez <45662294+piartz@users.noreply.github.com> Date: Thu, 5 Mar 2026 16:16:38 +0100 Subject: [PATCH 10/10] Remove regression risk section for Linux users Removed regression risk section for non-macOS users from README. --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index 9947f40..e293ea1 100644 --- a/README.md +++ b/README.md @@ -267,11 +267,6 @@ docker logs --tail 200 reconftw-mcp docker logs --tail 200 kali-mcp-server ``` -### Regression Risk (non-macOS) - -- Expected risk for Linux users is **low**: most new behavior is gated to macOS and/or ARM and only applies when optional MCP profiles are enabled. -- Main maintenance risk is future upstream format changes in patched compose/Dockerfile/entrypoint files; launcher patch anchors may need updates if upstream structure changes. - **Existing installation detected:** If `~/bugtraceai/` already exists, the wizard offers to reinstall (wipe + fresh setup) or update (pull + rebuild). ## How the Install Script Works