clawdie-ai/setup.sh
Sam & Pi e1d4fd4441
Some checks failed
CI / ci (pull_request) Has been cancelled
chore(freebsd): align host baseline with Python 3.12 (Sam & Pi)
---
Build: FAIL | Tests: FAIL
2026-06-17 14:57:19 +02:00

277 lines
7 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
# setup.sh — Bootstrap script for Clawdie AI
# Handles Node.js/npm setup, then hands off to the Node.js setup modules.
# This is the only bash script in the setup flow.
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_FILE="$PROJECT_ROOT/logs/setup.log"
# shellcheck source=scripts/date-format.sh
. "$PROJECT_ROOT/scripts/date-format.sh"
mkdir -p "$PROJECT_ROOT/logs"
log() { echo "[$(format_display_timestamp_now)] [bootstrap] $*" >> "$LOG_FILE"; }
# --- Platform detection ---
detect_platform() {
local uname_s
uname_s=$(uname -s)
case "$uname_s" in
FreeBSD*) PLATFORM="freebsd" ;;
*)
echo "ERROR: Clawdie AI requires FreeBSD. Detected: $uname_s" >&2
exit 1
;;
esac
IS_ROOT="false"
if [ "$(id -u)" -eq 0 ]; then
IS_ROOT="true"
fi
log "Platform: $PLATFORM, Root: $IS_ROOT"
}
# --- Host package baseline ---
install_host_pkg_baseline() {
HOST_PKG_BASELINE_STATUS="skipped"
HOST_PKG_BASELINE_MISSING=""
HOST_PKG_BASELINE_INSTALL_CMD="none"
[ "$PLATFORM" = "freebsd" ] || return
local -a missing_pkgs=()
local package_file="$PROJECT_ROOT/infra/packages/host-baseline.txt"
local pkg
while IFS= read -r pkg; do
[ -n "$pkg" ] || continue
case "$pkg" in
\#*) continue ;;
node24)
command -v node >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
npm)
command -v npm >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
bsddialog)
command -v bsddialog >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
bastille)
command -v bastille >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
git)
command -v git >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
tmux)
command -v tmux >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
python312)
command -v python3.12 >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
uv)
command -v uv >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
ripgrep)
command -v rg >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
fd)
command -v fd >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
rsync)
command -v rsync >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
postgresql18-client)
command -v psql >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
rust)
command -v rustc >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
dejavu)
[ -f /usr/local/share/fonts/dejavu/DejaVuSansMono.ttf ] || missing_pkgs+=("$pkg")
;;
*)
command -v "$pkg" >/dev/null 2>&1 || missing_pkgs+=("$pkg")
;;
esac
done < "$package_file"
if [ "${#missing_pkgs[@]}" -eq 0 ]; then
HOST_PKG_BASELINE_STATUS="already_present"
log "Host package baseline already present"
return
fi
HOST_PKG_BASELINE_MISSING="${missing_pkgs[*]}"
if [ "$IS_ROOT" = "true" ]; then
HOST_PKG_BASELINE_INSTALL_CMD="pkg install -y ${HOST_PKG_BASELINE_MISSING}"
elif command -v sudo >/dev/null 2>&1; then
HOST_PKG_BASELINE_INSTALL_CMD="sudo pkg install -y ${HOST_PKG_BASELINE_MISSING}"
else
HOST_PKG_BASELINE_STATUS="missing_no_sudo"
log "Host package baseline missing and sudo unavailable: ${HOST_PKG_BASELINE_MISSING}"
return
fi
log "Installing missing host package baseline: ${HOST_PKG_BASELINE_MISSING}"
if $HOST_PKG_BASELINE_INSTALL_CMD >> "$LOG_FILE" 2>&1; then
HOST_PKG_BASELINE_STATUS="installed"
log "Host package baseline installed successfully"
else
HOST_PKG_BASELINE_STATUS="install_failed"
log "Host package baseline installation failed"
fi
}
# --- Node.js check ---
check_node() {
NODE_OK="false"
NODE_VERSION="not_found"
NODE_PATH_FOUND=""
if command -v node >/dev/null 2>&1; then
NODE_VERSION=$(node --version 2>/dev/null | sed 's/^v//')
NODE_PATH_FOUND=$(command -v node)
local major
major=$(echo "$NODE_VERSION" | cut -d. -f1)
if [ "$major" -ge 24 ] 2>/dev/null; then
NODE_OK="true"
fi
log "Node $NODE_VERSION at $NODE_PATH_FOUND (major=$major, ok=$NODE_OK)"
else
log "Node not found"
fi
}
# --- bsddialog check ---
check_bsddialog() {
BSDDIALOG_OK="false"
BSDDIALOG_PATH="not_found"
if command -v bsddialog >/dev/null 2>&1; then
BSDDIALOG_OK="true"
BSDDIALOG_PATH=$(command -v bsddialog)
fi
log "bsddialog: $BSDDIALOG_OK (${BSDDIALOG_PATH:-not_found})"
}
# --- npm install ---
install_deps() {
DEPS_OK="false"
if [ "$NODE_OK" = "false" ]; then
log "Skipping npm install — Node not available"
return
fi
cd "$PROJECT_ROOT"
# npm install with --unsafe-perm if root (needed for native modules)
local npm_flags=""
if [ "$IS_ROOT" = "true" ]; then
npm_flags="--unsafe-perm"
log "Running as root, using --unsafe-perm"
fi
log "Running npm install $npm_flags"
if npm install $npm_flags >> "$LOG_FILE" 2>&1; then
DEPS_OK="true"
log "npm install succeeded"
else
log "npm install failed"
return
fi
}
# --- Build tools check ---
check_build_tools() {
HAS_BUILD_TOOLS="false"
if command -v cc >/dev/null 2>&1 && command -v make >/dev/null 2>&1; then
HAS_BUILD_TOOLS="true"
fi
log "Build tools: $HAS_BUILD_TOOLS"
}
# --- Main ---
log "=== Bootstrap started ==="
detect_platform
install_host_pkg_baseline
check_node
check_bsddialog
install_deps
check_build_tools
# Emit status block
STATUS="success"
if [ "$HOST_PKG_BASELINE_STATUS" = "missing_no_sudo" ] || [ "$HOST_PKG_BASELINE_STATUS" = "install_failed" ]; then
STATUS="host_packages_failed"
elif [ "$NODE_OK" = "false" ]; then
STATUS="node_missing"
elif [ "$DEPS_OK" = "false" ]; then
STATUS="deps_failed"
fi
cat <<EOF
=== CLAWDIE SETUP: BOOTSTRAP ===
PLATFORM: $PLATFORM
IS_ROOT: $IS_ROOT
HOST_PKG_BASELINE_STATUS: $HOST_PKG_BASELINE_STATUS
HOST_PKG_BASELINE_MISSING: ${HOST_PKG_BASELINE_MISSING:-none}
HOST_PKG_BASELINE_INSTALL_CMD: ${HOST_PKG_BASELINE_INSTALL_CMD:-none}
NODE_VERSION: $NODE_VERSION
NODE_OK: $NODE_OK
NODE_PATH: ${NODE_PATH_FOUND:-not_found}
DEPS_OK: $DEPS_OK
HAS_BUILD_TOOLS: $HAS_BUILD_TOOLS
BSDDIALOG_OK: $BSDDIALOG_OK
BSDDIALOG_PATH: ${BSDDIALOG_PATH:-not_found}
STATUS: $STATUS
LOG: logs/setup.log
=== END ===
EOF
log "=== Bootstrap completed: $STATUS ==="
if [ "$HOST_PKG_BASELINE_STATUS" = "missing_no_sudo" ] || [ "$HOST_PKG_BASELINE_STATUS" = "install_failed" ]; then
exit 1
fi
if [ "$NODE_OK" = "false" ]; then
exit 2
fi
if [ "$DEPS_OK" = "false" ]; then
exit 1
fi
# Wire tracked git hooks (idempotent)
git config core.hooksPath hooks/ 2>/dev/null || true
log "Git hooks path set to hooks/"
# Detect host locale silently — reads $LANG / locale / ~/.login_conf from the FreeBSD install
# Falls back to en-US on neutral/cloud environments. No prompt needed.
log "Detecting host locale"
npx tsx setup/index.ts --step profile --accept-detected >> "$LOG_FILE" 2>&1 || true
if [ "${CLAWDIE_SKIP_ONBOARDING:-0}" != "1" ] \
&& [ -t 0 ] \
&& [ -t 1 ]; then
log "Launching interactive onboarding"
echo
echo "Launching interactive onboarding..."
npm run wizard
fi