Ctrl K
ComunidadGuías…

install.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env bash
#
# GlucoPilot — one-command local installer.
#
# Gets GlucoPilot running on your own machine at http://localhost:<port>.
# Works on macOS, Linux, and Windows (via WSL2 / Git Bash). All it needs is
# Docker. Run it from the folder you cloned this repo into:
#
#     ./install.sh
#
# It's safe to re-run: it won't overwrite an existing .env unless you say so.

set -euo pipefail

# ── pretty output ───────────────────────────────────────────────────────────
if [ -t 1 ]; then
  B=$'\033[1m'; DIM=$'\033[2m'; G=$'\033[32m'; Y=$'\033[33m'; R=$'\033[31m'; C=$'\033[36m'; N=$'\033[0m'
else
  B=""; DIM=""; G=""; Y=""; R=""; C=""; N=""
fi
say()  { printf '%s\n' "$*"; }
ok()   { printf '%s✓%s %s\n' "$G" "$N" "$*"; }
warn() { printf '%s!%s %s\n' "$Y" "$N" "$*"; }
die()  { printf '%s✗ %s%s\n' "$R" "$*" "$N" >&2; exit 1; }
ask() { # ask "Prompt" "default" -> echoes answer (default if non-interactive/empty)
  local prompt="$1" default="${2:-}" reply=""
  if [ -t 0 ]; then
    printf '%s%s%s ' "$C" "$prompt" "$N" >&2
    [ -n "$default" ] && printf '%s[%s]%s ' "$DIM" "$default" "$N" >&2
    read -r reply || true
  fi
  printf '%s' "${reply:-$default}"
}

say ""
say "${B}GlucoPilot installer${N}"
say "${DIM}A private, self-hosted health companion. This sets it up on this machine.${N}"
say ""

# ── 1. preflight: docker ────────────────────────────────────────────────────
command -v docker >/dev/null 2>&1 || die "Docker isn't installed. Get it at https://docs.docker.com/get-docker/ then re-run this."
if docker compose version >/dev/null 2>&1; then DC="docker compose"
elif command -v docker-compose >/dev/null 2>&1; then DC="docker-compose"
else die "Docker Compose isn't available. Install Docker Desktop (macOS/Windows) or the compose plugin (Linux)."
fi
docker info >/dev/null 2>&1 || die "Docker is installed but not running. Start Docker Desktop (or the docker service) and re-run."
ok "Docker is ready"

# ── 2. in the repo? ─────────────────────────────────────────────────────────
cd "$(dirname "$0")"
[ -f docker-compose.local.yml ] || die "Run this from the folder you cloned GlucoPilot into (docker-compose.local.yml not found)."

# ── 3. wizard ───────────────────────────────────────────────────────────────
detect_tz() {
  if command -v timedatectl >/dev/null 2>&1; then timedatectl show -p Timezone --value 2>/dev/null && return; fi
  [ -f /etc/timezone ] && { cat /etc/timezone; return; }
  if [ -L /etc/localtime ]; then readlink /etc/localtime | sed 's#.*/zoneinfo/##'; return; fi
  printf 'America/New_York'
}

if [ -f .env ]; then
  warn "An .env already exists."
  if [ "$(ask 'Keep it and just (re)start? y/n' 'y')" = "y" ]; then
    KEEP_ENV=1
  else
    KEEP_ENV=0; cp .env ".env.bak.$(date +%s 2>/dev/null || echo old)" 2>/dev/null || true
    ok "Backed up your old .env"
  fi
else
  KEEP_ENV=0
fi

PORT="8000"
if [ "${KEEP_ENV:-0}" = "0" ]; then
  say ""
  PORT="$(ask 'Which port should GlucoPilot use?' '8000')"
  [[ "$PORT" =~ ^[0-9]+$ ]] || die "Port must be a number."
  TZ_DEFAULT="$(detect_tz)"; [ -n "$TZ_DEFAULT" ] || TZ_DEFAULT="America/New_York"
  APP_TZ="$(ask 'Your timezone (IANA name)?' "$TZ_DEFAULT")"
  say ""
  say "${DIM}Optional: the AI features (Companion, insights, Visit Report) can use the"
  say "Anthropic API, a local model, or be set up later in Settings. Leave blank to skip.${N}"
  ANTHROPIC_KEY="$(ask 'Anthropic API key (optional, starts with sk-ant-):' '')"

  # random secret for signing session cookies
  if command -v openssl >/dev/null 2>&1; then SECRET="$(openssl rand -hex 32)"
  else SECRET="$(head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n')"; fi

  {
    echo "# GlucoPilot — generated by install.sh. Advanced/server options: see .env.example"
    echo "APP_PUBLIC_URL=http://localhost:${PORT}"
    echo "APP_SECRET_KEY=${SECRET}"
    echo "APP_TIMEZONE=${APP_TZ}"
    echo "SYNC_ENABLED=true"
    echo "PORT=${PORT}"
    [ -n "$ANTHROPIC_KEY" ] && echo "ANTHROPIC_API_KEY=${ANTHROPIC_KEY}"
  } > .env
  ok "Wrote .env (secret key generated for you)"
else
  # reuse the port already in .env if present
  PORT="$(grep -E '^PORT=' .env 2>/dev/null | head -1 | cut -d= -f2)"; [ -n "$PORT" ] || PORT="8000"
fi

# ── 4. launch ───────────────────────────────────────────────────────────────
say ""
say "${B}Starting GlucoPilot…${N} ${DIM}(first run downloads the image — a few minutes)${N}"
if ! PORT="$PORT" $DC -f docker-compose.local.yml up -d 2>/dev/null; then
  warn "Prebuilt image unavailable — building from source instead (slower, one-time)."
  PORT="$PORT" $DC -f docker-compose.local.yml up -d --build
fi

# ── 5. wait for it to answer ────────────────────────────────────────────────
URL="http://localhost:${PORT}"
printf '%sWaiting for GlucoPilot to come up' "$DIM"
up=0
for _ in $(seq 1 60); do
  code="$(curl -s -o /dev/null -w '%{http_code}' "$URL" 2>/dev/null || echo 000)"
  if [ "$code" != "000" ]; then up=1; break; fi
  printf '.'; sleep 2
done
printf '%s\n' "$N"

say ""
if [ "$up" = "1" ]; then
  ok "GlucoPilot is running!"
else
  warn "It didn't answer yet — it may still be starting. Check logs with: $DC -f docker-compose.local.yml logs -f"
fi

say ""
say "${B}Open:${N}  ${C}${URL}${N}"
say "  ${DIM}The first visit lets you create your login. Then open Settings to connect"
say "  data sources (Dexcom, Oura, …) and choose your AI. That's it.${N}"
say ""
say "${B}Handy commands${N}"
say "  ${DIM}Stop:${N}    $DC -f docker-compose.local.yml down"
say "  ${DIM}Update:${N}  git pull && $DC -f docker-compose.local.yml pull && $DC -f docker-compose.local.yml up -d"
say "  ${DIM}Logs:${N}    $DC -f docker-compose.local.yml logs -f"
say "  ${DIM}Backup:${N}  see docs/DEPLOY.md"
say ""