layered-soul/skills/iso-visuals/scripts/clawdie-join-hive.sh
Sam & Claude 5a0a00ff66 fix(iso-visuals): wallpaper-on-join honors tmp policy + applies on real hardware
Follow-up to #74. Two concrete fixes to the "identity wallpaper on join" step:

1. tmp policy: the join script hardcoded WP=/tmp/clawdie-wallpaper.png, passing
   it to clawdie-wallpaper-gen and overriding the safe SCRATCH_DIR default that
   9ae8d25 had just introduced (project-local tmp/ or app-owned cache). The
   generator now prints its chosen path on stdout (human note → stderr) and the
   join script captures it: WP=$(clawdie-wallpaper-gen). No host-global /tmp.

2. wallpaper actually applies: replaced the hardcoded
   /backdrop/screen0/monitor0/workspace0/last-image with an enumeration over
   every existing */last-image property (XFCE keys backdrops by connector name,
   e.g. monitorHDMI-1, not monitor0), falling back to creating the default
   property on first boot/headless, then xfdesktop --reload.

SKILL.md updated to document the stdout contract and multi-monitor wiring.

Validation: sh -n on both scripts; prettier@3 --check SKILL.md;
python3 scripts/layered_soul.py validate . — all pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 12:26:20 +02:00

158 lines
5.2 KiB
Bash
Executable file

#!/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 && have xfconf-query; then
echo " Setting identity wallpaper..."
# Let the generator pick a policy-compliant path (project-local tmp/ or an
# app-owned cache dir) and report it on stdout — no host-global /tmp here.
WP=$(clawdie-wallpaper-gen 2>/dev/null)
if [ -n "$WP" ] && [ -f "$WP" ]; then
# XFCE keys backdrops by connector name (monitorHDMI-1, monitoreDP-1, ...),
# not a fixed "monitor0". Set every existing last-image property so the
# change actually applies on real hardware.
_applied=0
for _prop in $(xfconf-query -c xfce4-desktop -l 2>/dev/null | grep '/last-image$'); do
xfconf-query -c xfce4-desktop -p "$_prop" -s "$WP" 2>/dev/null && _applied=1
done
# First boot / headless: no backdrop props exist yet — create the default.
if [ "$_applied" -eq 0 ]; then
xfconf-query -c xfce4-desktop \
-p /backdrop/screen0/monitor0/workspace0/last-image \
-n -t string -s "$WP" 2>/dev/null
fi
xfdesktop --reload >/dev/null 2>&1 || true
fi
fi
echo " Check: colibri status"
echo " Tasks: colibri list-tasks --status started"
echo " Board: colibri list-agents"
echo ""
echo "Hive joined."
finish 0