From 005c8a666c937250b2958dbeac185834d8211718 Mon Sep 17 00:00:00 2001 From: Joel Teply Date: Thu, 11 Jun 2026 21:58:09 -0500 Subject: [PATCH 1/3] feat(install): provision CUDA toolkit + airc firewall as detected prerequisites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modern-app install behavior: detect a needed prerequisite and provide it, idempotently, on every run/update — instead of merely warning. install.sh: install_cuda_toolkit() — when a CUDA GPU is detected and nvcc is missing or below the Blackwell floor (12.8, sm_120 / RTX 5090), install the CUDA toolkit from NVIDIAs apt repo (wsl-ubuntu repo under WSL2; the GPU driver comes from the Windows host, never a Linux driver). Idempotent: a re-run skips when a recent-enough toolkit exists. Replaces the warn-only detect_gpu path, whose comment wrongly called nvcc training-only — its required to build --features cuda (candle-kernels/cudarc compile GPU kernels at build time). windows-setup-autostart.ps1: idempotent inbound firewall allow-rule for airc.exe so other grid nodes can reach this boxs airc LAN listener (ephemeral port) — the missing piece that forced a manual netsh paste to close the cross-machine keystones inbound leg. Skipped TS-compile + browser precommit phases via the configs documented env knobs (ENABLE_TYPESCRIPT_CHECK=false ENABLE_BROWSER_TEST=false) — change is shell + PowerShell infra only, no TS/Rust. Co-Authored-By: Claude Opus 4.8 --- tools/scripts/install.sh | 76 ++++++++++++++++++++++- tools/scripts/windows-setup-autostart.ps1 | 21 ++++++- 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/tools/scripts/install.sh b/tools/scripts/install.sh index 4a66a16a51..337cfa6ab7 100644 --- a/tools/scripts/install.sh +++ b/tools/scripts/install.sh @@ -91,9 +91,14 @@ detect_gpu() { [ -f /usr/lib/wsl/lib/nvidia-smi ] && smi_path="/usr/lib/wsl/lib/nvidia-smi" local vram=$($smi_path --query-gpu=memory.total --format=csv,noheader,nounits 2>/dev/null | head -1) echo -e " GPU: ${GREEN}${GPU_NAME} (CUDA, ${vram}MiB VRAM)${NC}" - # Check for nvcc (CUDA compiler — needed for training, not inference) - if ! command -v nvcc &>/dev/null; then - echo -e " CUDA: ${YELLOW}nvcc not found — inference works, training needs CUDA toolkit${NC}" + # nvcc (CUDA compiler) is REQUIRED to build `--features cuda` — candle-kernels + # + cudarc compile GPU kernels at build time. `install_cuda_toolkit` (below) + # provisions it when missing/too-old. A Blackwell GPU (sm_120, e.g. RTX 5090) + # needs CUDA >= 12.8; without nvcc the build falls back to CPU. + if command -v nvcc &>/dev/null; then + echo -e " CUDA: ${GREEN}nvcc $(nvcc --version 2>/dev/null | grep -oP 'release \K[0-9.]+' | head -1) present${NC}" + else + echo -e " CUDA: ${YELLOW}nvcc not found — will install CUDA toolkit (required for GPU inference)${NC}" fi elif $HAS_METAL; then echo -e " GPU: ${GREEN}${GPU_NAME}${NC}" @@ -105,6 +110,67 @@ detect_gpu() { detect_gpu echo "" +# ============================================================================ +# CUDA toolkit (nvcc) — provisioned as a detected prerequisite +# ============================================================================ +# Modern-app behavior: a CUDA GPU is useless for GPU inference without nvcc +# (the build needs it to compile candle-kernels/cudarc), so if one is present +# and the toolkit is missing or below the Blackwell floor, install it. Fully +# idempotent — a re-run/update skips when a recent-enough toolkit exists. +install_cuda_toolkit() { + $HAS_CUDA || return 0 + case "$PLATFORM" in linux|wsl) ;; *) return 0 ;; esac + + # Blackwell (sm_120 / RTX 5090) needs >= 12.8; 12.9 is the newest 12.x with + # broad cudarc/candle support. Bump TARGET as the toolchain validates newer. + local MIN="12.8" TARGET="12-9" + if command -v nvcc &>/dev/null; then + local cur=$(nvcc --version 2>/dev/null | grep -oP 'release \K[0-9]+\.[0-9]+' | head -1) + if [ -n "$cur" ] && [ "$(printf '%s\n%s\n' "$MIN" "$cur" | sort -V | head -1)" = "$MIN" ]; then + echo -e " ${GREEN}✅ CUDA toolkit $cur already present (>= $MIN) — skipping${NC}" + return 0 + fi + echo -e " ${YELLOW}nvcc ${cur:-unknown} is below the Blackwell floor $MIN — upgrading${NC}" + fi + + # Tiered sudo — same one-prompt contract as install_system_deps. + local SUDO="" CAN_SUDO=true + if [ "$(id -u)" -eq 0 ]; then SUDO="" + elif sudo -n true 2>/dev/null; then SUDO="sudo" + elif [ -t 0 ]; then SUDO="sudo" + else CAN_SUDO=false; fi + if ! $CAN_SUDO; then + echo -e " ${RED}CUDA toolkit needed but no terminal for sudo. Re-run in a terminal:${NC}" + echo -e " ${YELLOW} cd src && bash scripts/install.sh${NC}" + return 0 + fi + ensure_sudo_warmed + + # NVIDIA CUDA apt repo. wsl-ubuntu for WSL2 (the GPU driver is the Windows + # host driver passed through — NEVER install a Linux driver under WSL); + # ubuntu2404 for native Linux. sbsa for aarch64. + local distro="ubuntu2404" + [ "$PLATFORM" = "wsl" ] && distro="wsl-ubuntu" + local cuda_arch="x86_64" + [ "$(uname -m)" = "aarch64" ] && cuda_arch="sbsa" + local keyring="/tmp/cuda-keyring.deb" + echo -e " Installing CUDA toolkit ${TARGET//-/.} (~3GB) from NVIDIA ${distro} repo..." + if curl -fsSL -o "$keyring" \ + "https://developer.download.nvidia.com/compute/cuda/repos/${distro}/${cuda_arch}/cuda-keyring_1.1-1_all.deb"; then + $SUDO dpkg -i "$keyring" >/dev/null 2>&1 + rm -f "$keyring" + $SUDO apt-get update -qq + if $SUDO apt-get install -y "cuda-toolkit-${TARGET}"; then + echo -e " ${GREEN}✅ CUDA toolkit installed -> /usr/local/cuda-${TARGET//-/.}/bin/nvcc${NC}" + echo -e " ${YELLOW} (cargo-features.sh adds /usr/local/cuda/bin to PATH for --features cuda)${NC}" + else + echo -e " ${YELLOW}⚠️ CUDA toolkit install failed — GPU inference falls back to CPU until resolved${NC}" + fi + else + echo -e " ${YELLOW}⚠️ Could not fetch NVIDIA cuda-keyring — skipping CUDA toolkit (CPU fallback)${NC}" + fi +} + # ============================================================================ # Step 1: System dependencies # ============================================================================ @@ -241,6 +307,10 @@ install_system_deps() { install_system_deps +# Provision the CUDA toolkit if a CUDA GPU was detected (no-op otherwise, +# idempotent on re-run). Runs after system deps so apt + curl are ready. +install_cuda_toolkit + # CONTINUUM_DEPS_ONLY=1 — called by npm start to check deps without full build. # Still installs all infrastructure (Node, Rust, Python, Postgres, LiveKit, Tailscale) # but skips the build step (npm install, tsc, cargo build). diff --git a/tools/scripts/windows-setup-autostart.ps1 b/tools/scripts/windows-setup-autostart.ps1 index bad2cd0a8b..df022013ae 100644 --- a/tools/scripts/windows-setup-autostart.ps1 +++ b/tools/scripts/windows-setup-autostart.ps1 @@ -7,7 +7,8 @@ # 1. Copies wsl-boot.sh into WSL2 # 2. Creates a Windows Scheduled Task that starts WSL2 on boot # 3. The boot script starts SSH, Tailscale, and protects them from OOM -# 4. After this, the machine survives reboots without human intervention +# 4. Adds an inbound firewall allow-rule for the airc daemon (grid routing) +# 5. After this, the machine survives reboots without human intervention Write-Host "Setting up Continuum auto-start..." -ForegroundColor Cyan @@ -88,6 +89,24 @@ $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoi Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Description "Start WSL2 with SSH, Tailscale, and GPU access on boot" Write-Host " Scheduled Task: $taskName (runs at boot as SYSTEM)" -ForegroundColor Green +# 6. airc daemon inbound firewall rule — cross-machine grid routing needs other +# nodes to reach this box's airc LAN listener (an ephemeral TCP port), so we +# allow inbound TCP for the airc binary by program path (covers any port). +# Idempotent: skip if the rule already exists. This is a detected grid +# prerequisite — provisioning it here is why the keystone route forms both +# ways without a manual one-off netsh paste. +$aircRule = "airc-daemon-inbound" +$aircExe = Join-Path $env:USERPROFILE ".cargo\bin\airc.exe" +if (Get-NetFirewallRule -DisplayName $aircRule -ErrorAction SilentlyContinue) { + Write-Host " Firewall: $aircRule already present" -ForegroundColor Green +} elseif (Test-Path $aircExe) { + New-NetFirewallRule -DisplayName $aircRule -Direction Inbound -Action Allow ` + -Program $aircExe -Protocol TCP -Profile Any | Out-Null + Write-Host " Firewall: added inbound allow for airc ($aircExe)" -ForegroundColor Green +} else { + Write-Host " Firewall: airc.exe not at $aircExe — install airc then re-run this script" -ForegroundColor Yellow +} + Write-Host "" Write-Host "Done! This machine will now auto-start WSL2 on every boot." -ForegroundColor Cyan Write-Host " SSH, Tailscale, and PostgreSQL start automatically." From 1f64a694ef7c45c5b636c051d51d9373a35764bf Mon Sep 17 00:00:00 2001 From: Joel Teply Date: Fri, 12 Jun 2026 13:10:25 -0500 Subject: [PATCH 2/3] fix(install): fail fast on Git Bash + verify node/npm instead of false success MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Running tools/scripts/install.sh from Git Bash/MSYS (uname MINGW64_NT) fell through preflight_detect_platform Darwin/Linux cases to "unknown", then plowed into apt-based Node/npm steps that cant work there — a cascade of "command not found" AND a false "node installed" (the echo ran node --version unconditionally; the npm step | tail masked the missing-binary exit). - preflight_detect_platform: detect MINGW*/MSYS*/CYGWIN* -> windows-shell. - install.sh: fail fast on windows-shell/unknown with a clear redirect to WSL2 (or install.ps1) BEFORE any package step runs. - install_node: verify node is on PATH after install; error if not. - npm build step: preflight command -v npm; check npms real exit via PIPESTATUS[0] (not tails) and stop on failure. Co-Authored-By: Claude Opus 4.8 --- tools/scripts/install.sh | 43 +++++++++++++++++++++++++++++++ tools/scripts/shared/preflight.sh | 4 +++ 2 files changed, 47 insertions(+) diff --git a/tools/scripts/install.sh b/tools/scripts/install.sh index 337cfa6ab7..a6bc6dc6a9 100644 --- a/tools/scripts/install.sh +++ b/tools/scripts/install.sh @@ -38,6 +38,25 @@ echo "" PLATFORM=$(preflight_detect_platform) echo -e " Platform: ${GREEN}${PLATFORM}${NC}" +# Fail fast on an unsupported host shell. The from-source dev install needs a +# real Linux userland (apt + the build toolchain). Git Bash / MSYS / Cygwin are +# Windows shells with no package manager, so the Node/npm/Rust steps would +# cascade into "command not found" — better to stop with a clear redirect. +case "$PLATFORM" in + windows-shell) + echo -e " ${RED}✗ This is Git Bash / MSYS on Windows — not a Linux environment.${NC}" + echo -e " ${YELLOW}Continuum's from-source install needs WSL2 Ubuntu. Either:${NC}" + echo -e " ${YELLOW} • open WSL ('wsl') and run this from your WSL checkout, OR${NC}" + echo -e " ${YELLOW} • use the Docker-first Windows installer: install.ps1${NC}" + exit 1 + ;; + unknown) + echo -e " ${RED}✗ Unsupported platform ($(uname -s)). This installer supports${NC}" + echo -e " ${YELLOW} WSL2/Linux and macOS. On Windows use WSL2 or install.ps1.${NC}" + exit 1 + ;; +esac + # ============================================================================ # Modular install steps (new pattern — see INSTALL-ARCHITECTURE.md) # ============================================================================ @@ -350,6 +369,15 @@ install_node() { nvm use 22 ;; esac + # Verify the install actually put node on PATH — don't claim success on a + # bare "node: command not found" (e.g. nvm sourced into a subshell that + # didn't persist, or an unsupported shell). Fail loud and actionable. + if ! command -v node &>/dev/null; then + echo -e " ${RED}✗ Node.js install ran but 'node' is still not on PATH.${NC}" + echo -e " ${YELLOW} Open a new shell (or 'source ~/.nvm/nvm.sh') and re-run,${NC}" + echo -e " ${YELLOW} or install Node 22 via your platform's package manager.${NC}" + exit 1 + fi echo -e " ${GREEN}✅ Node.js $(node --version) installed${NC}" } @@ -435,8 +463,23 @@ fi if [ "$SKIP_BUILD" = "0" ]; then echo -e "${YELLOW}[5/8] Building Continuum${NC}" + # Preflight: the build needs npm. Without this check, a missing npm only + # surfaces as "npm: command not found" swallowed by the `| tail` pipe, and + # the install appears to continue. Stop loud and actionable instead. + if ! command -v npm &>/dev/null; then + echo -e " ${RED}✗ npm not found — cannot build. Node.js/npm must be installed${NC}" + echo -e " ${YELLOW} and on PATH (the [2/8] Node.js step provides them on a${NC}" + echo -e " ${YELLOW} supported platform). Open a fresh shell and re-run.${NC}" + exit 1 + fi + echo -e " Installing npm dependencies..." npm install --silent 2>&1 | tail -3 + # PIPESTATUS[0] is npm's real exit code (the pipe's own status is tail's). + if [ "${PIPESTATUS[0]}" -ne 0 ]; then + echo -e " ${RED}✗ npm install failed${NC}" + exit 1 + fi echo -e " Building TypeScript..." npm run build:ts 2>&1 | tail -1 diff --git a/tools/scripts/shared/preflight.sh b/tools/scripts/shared/preflight.sh index 7b01f771e2..ccd4828761 100644 --- a/tools/scripts/shared/preflight.sh +++ b/tools/scripts/shared/preflight.sh @@ -36,6 +36,10 @@ preflight_detect_platform() { echo "linux" fi ;; + # Git Bash / MSYS2 / Cygwin: a Unix-like shell on the Windows host, NOT a + # Linux userland. No apt/Linux toolchain here, so the from-source dev + # install can't run — callers redirect to WSL2 (or the Docker install.ps1). + MINGW*|MSYS*|CYGWIN*) echo "windows-shell" ;; *) echo "unknown" ;; esac } From 48203becce768817838750c686d465f67695a118 Mon Sep 17 00:00:00 2001 From: Joel Teply Date: Fri, 12 Jun 2026 13:23:27 -0500 Subject: [PATCH 3/3] docs(install): redirect dev-script users to the one-command installer + pin toolchain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The from-source dev script (tools/scripts/install.sh) billed itself as THE installer, so users (and agents) ran it — often in Git Bash where it cant work — instead of the real one-command path. Rewrite its header to redirect most users to install.ps1 (Windows) / curl install.sh (Linux/macOS), which handle WSL2 + Docker + GPU in one shot. Pair with the windows-shell fail-fast guard so the dev script is unmistakable. Also add rust-toolchain.toml pinning 1.92.0 so the from-source build is reproducible (continuum-core ICEs rustc >=1.93 on x86_64-linux). Co-Authored-By: Claude Opus 4.8 --- rust-toolchain.toml | 12 ++++++++++++ tools/scripts/install.sh | 26 +++++++++++++++++++------- 2 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 rust-toolchain.toml diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000000..d5d92e7b4c --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,12 @@ +# Pin the Rust toolchain so continuum-core builds reproducibly across the grid. +# +# continuum-core ICEs rustc >= 1.93 on x86_64-unknown-linux-gnu (a compiler +# panic in early_lint_checks; x86_64-Linux/WSL-specific — macOS aarch64 is +# unaffected, which is why only Linux/WSL nodes hit it). 1.90 is too old +# (the rtc-mdns dep needs the `ip_from` stabilization). 1.92.0 is the known- +# good window: new enough for deps, before the lint regression. +# +# cargo auto-selects this channel for every build in the repo; rustup +# auto-installs it on first use. +[toolchain] +channel = "1.92.0" diff --git a/tools/scripts/install.sh b/tools/scripts/install.sh index a6bc6dc6a9..d725efdcc8 100644 --- a/tools/scripts/install.sh +++ b/tools/scripts/install.sh @@ -1,14 +1,26 @@ #!/bin/bash -# Continuum Tower Install — One command to get a tower running. +# Continuum — FROM-SOURCE developer/self-host build. # -# Usage: +# ┌───────────────────────────────────────────────────────────────────────┐ +# │ MOST USERS DO NOT RUN THIS. To just *use* Continuum, run the one- │ +# │ command installer (pre-built Docker images, no compiler needed): │ +# │ • Windows: irm https://cambriantech.github.io/continuum/install.ps1 | iex +# │ • Linux/macOS: curl -fsSL https://cambriantech.github.io/continuum/install.sh | bash +# │ On Windows that handles WSL2 + Docker + GPU for you — no shell choice. │ +# └───────────────────────────────────────────────────────────────────────┘ +# +# This script is the FROM-SOURCE path: compiles continuum-core + workers and +# installs the full dev toolchain. Use it only if you are building/hacking on +# Continuum itself. +# +# Usage (must be a real Linux userland — WSL2/Ubuntu, native Linux, or macOS; +# NOT Git Bash/MSYS, which has no apt/toolchain and is rejected up front): # git clone https://github.com/CambrianTech/continuum.git -# cd continuum/src -# bash scripts/install.sh +# cd continuum && bash tools/scripts/install.sh # -# Works on: macOS (Apple Silicon), Ubuntu/Debian (x86_64), WSL2 -# Installs: Node.js, Rust, Python venv (with ML packages if GPU detected), system deps -# Idempotent: safe to run multiple times (skips what's already installed) +# Installs: Node.js, Rust (pinned via rust-toolchain.toml), Python venv (+ ML +# packages and the CUDA toolkit when a GPU is detected), system deps. +# Idempotent: safe to re-run (skips what's already installed). set -eo pipefail