#!/bin/sh # One-click "Join Hive" — registers this machine as a Colibri agent. # Runs in a visible terminal so the operator sees the result. # Idempotent: safe to re-run on an already-registered agent. SOCKET="${COLIBRI_SOCKET:-/var/run/colibri/colibri.sock}" PROVIDER_ENV="/usr/local/etc/colibri/provider.env" finish() { _code="${1:-0}" echo "" echo "Press Enter to close." read -r _ exit "${_code}" } have() { command -v "$1" >/dev/null 2>&1 } provider_env_has_bw_creds() { _check='test -f "$1" && grep -Eq "^BW_CLIENTID=.+" "$1" && grep -Eq "^BW_CLIENTSECRET=.+" "$1" && grep -Eq "^BW_PASSWORD=.+" "$1"' if have mdo; then mdo -u root sh -c "${_check}" sh "${PROVIDER_ENV}" >/dev/null 2>&1 return $? fi sh -c "${_check}" sh "${PROVIDER_ENV}" >/dev/null 2>&1 } echo "========================================" echo " Clawdie — Join Hive" echo "========================================" echo "" # 1. Check daemon if [ ! -S "$SOCKET" ]; then echo "[1/4] Starting colibri daemon..." if have mdo; then if ! mdo -u root service colibri_daemon start; then echo " WARNING: could not start colibri_daemon via mdo." fi elif [ "$(id -u)" -eq 0 ]; then if ! service colibri_daemon start; then echo " WARNING: could not start colibri_daemon." fi else echo " WARNING: mdo is unavailable and this user is not root." fi _tries=0 while [ "$_tries" -lt 5 ] && [ ! -S "$SOCKET" ]; do sleep 1 _tries=$(( _tries + 1 )) done else echo "[1/4] Daemon already running." fi if [ ! -S "$SOCKET" ]; then echo " ERROR: Colibri socket is still missing: ${SOCKET}" echo " Check: mdo -u root service colibri_daemon status" finish 1 fi # 2. Vault creds. provider.env is intentionally 0600, so check via mdo when possible. echo "[2/4] Checking vault credentials..." if provider_env_has_bw_creds; then echo " provider.env contains Vaultwarden bootstrap credential fields." else echo " WARNING: provider.env is missing, unreadable, or lacks BW_CLIENTID/BW_CLIENTSECRET/BW_PASSWORD." echo " Vault provisioning will be skipped until the operator adds them." echo " Edit ${PROVIDER_ENV} and keep it mode 0600, then re-run." fi # 3. Detect capabilities HOST=$(hostname 2>/dev/null || echo "clawdie-live") OS=$(uname -s 2>/dev/null | tr '[:upper:]' '[:lower:]') [ -n "$OS" ] || OS="unknown" CAPS="$OS,shell" # Add optional capabilities have colibri && CAPS="$CAPS,colibri" have hermes && CAPS="$CAPS,hermes" have pi && CAPS="$CAPS,pi" if have tailscale && tailscale status >/dev/null 2>&1; then CAPS="$CAPS,tailscale" fi [ "$OS" = "freebsd" ] && CAPS="$CAPS,rc.d,jail,zfs" if have python3; then CAPS_JSON=$(printf '%s' "$CAPS" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read().strip().split(",")))' 2>/dev/null) else CAPS_JSON='["shell"]' fi [ -n "$CAPS_JSON" ] || CAPS_JSON='["shell"]' AGENT_NAME="${HOST}" echo "[3/4] Registering agent: ${AGENT_NAME}" echo " capabilities: ${CAPS}" if ! have nc; then echo " ERROR: nc is not installed; cannot talk to ${SOCKET}." finish 1 fi RESP=$(printf '{"cmd":"register-agent","name":"%s","capabilities":%s}\n' \ "$AGENT_NAME" "$CAPS_JSON" \ | nc -U "$SOCKET" -w 3 2>/dev/null) if echo "$RESP" | grep -q '"ok":true'; then echo " registered." elif echo "$RESP" | grep -Eiq 'already exists|unique constraint|constraint failed|agents\.name'; then echo " already registered (idempotent)." else echo " registration did not complete cleanly." if [ -n "$RESP" ]; then echo " response: ${RESP}" else echo " no response from ${SOCKET}" fi finish 1 fi # 4. Apply identity wallpaper as visual confirmation echo "[4/4] Agent ${AGENT_NAME} is live on the Colibri board." echo "" if have clawdie-wallpaper-gen; then echo " Setting identity wallpaper..." if have xfconf-query; then WP="/tmp/clawdie-wallpaper.png" clawdie-wallpaper-gen "$WP" 2>/dev/null && \ xfconf-query -c xfce4-desktop -p /backdrop/screen0/monitor0/workspace0/last-image -s "$WP" 2>/dev/null fi fi echo " Check: colibri status" echo " Tasks: colibri list-tasks --status started" echo " Board: colibri list-agents" echo "" echo "Hive joined." finish 0