Initial monorepo — everything BlackRoad in one place

bin/       230 CLI tools (ask-*, br-*, agent-*, roadid, carpool)
scripts/   99 automation scripts
fleet/     Node configs and deployment
workers/   Cloudflare Worker sources (roadpay, road-search, squad webhooks)
roadc/     RoadC programming language
roadnet/   Mesh network (5 APs, WireGuard)
operator/  Memory system scripts
config/    System configs
dotfiles/  Shell configs
docs/      Documentation

BlackRoad OS — Pave Tomorrow.

RoadChain-SHA2048: d1a24f55318d338b
RoadChain-Identity: alexa@sovereign
RoadChain-Full: d1a24f55318d338b24b60bad7be39286379c76ae5470817482100cb0ddbbcb97e147d07ac7243da0a9f0363e4e5c833d612b9c0df3a3cd20802465420278ef74875a5b77f55af6fe42a931b8b635b3d0d0b6bde9abf33dc42eea52bc03c951406d8cbe49f1a3d29b26a94dade05e9477f34a7d4d4c6ec4005c3c2ac54e73a68440c512c8e83fd9b1fe234750b898ef8f4032c23db173961fe225e67a0432b5293a9714f76c5c57ed5fdf35b9fb40fd73c03ebf88b7253c6a0575f5afb6a6b49b3bda310602fb1ef676859962dad2aebbb2875814b30eee0a8ba195e482d4cbc91d8819e7f38f6db53e8063401649c77bb994371473cabfb917fb53e8cbe73d60
This commit is contained in:
2026-03-14 17:07:35 -05:00
commit 78fbe80f2a
511 changed files with 102646 additions and 0 deletions

256
scripts/road-phone.sh Executable file
View File

@@ -0,0 +1,256 @@
#!/bin/bash
# ☎️ RoadPhone — Pi-side landline to Alexandria
#
# Each Pi runs this as a service. It watches local files for changes,
# then "dials" the Mac via rsync over SSH to drop off its payload.
# Mac's ring daemon picks it up and pushes to git.
#
# Old school landline routing:
# Pi detects change → picks up phone → dials Mac (rsync)
# → Mac switchboard receives → routes to git
#
# Usage:
# road-phone.sh # Run foreground
# road-phone.sh --install # Install as systemd service
# road-phone.sh --uninstall # Remove service
# road-phone.sh --call # One-shot dial (no watching)
set -euo pipefail
# ── identity ─────────────────────────────────────────────
HOSTNAME=$(hostname)
SWITCHBOARD="alexa@192.168.4.28" # Alexandria Mac
DROPOFF="~/local/fleet/$HOSTNAME"
LOGFILE="/var/log/road-phone.log"
PIDFILE="/tmp/road-phone.pid"
RING_INTERVAL=60 # check every 60s
CALL_COUNT=0
# Colors
P='\033[38;5;205m' # pink
G='\033[38;5;82m' # green
A='\033[38;5;214m' # amber
V='\033[38;5;135m' # violet
R='\033[0m' # reset
log() { echo -e "${P}[phone:$HOSTNAME]${R} $(date '+%H:%M:%S') $1" | tee -a "$LOGFILE" 2>/dev/null || echo "$1"; }
ring() { echo -e "${G}☎️ RING${R} $(date '+%H:%M:%S') $1" | tee -a "$LOGFILE" 2>/dev/null || echo "$1"; }
busy() { echo -e "${A}📞 BUSY${R} $(date '+%H:%M:%S') $1" | tee -a "$LOGFILE" 2>/dev/null || echo "$1"; }
tone() { echo -e "${V}📱 TONE${R} $(date '+%H:%M:%S') $1" | tee -a "$LOGFILE" 2>/dev/null || echo "$1"; }
# ── what to watch (each Pi's "phone book") ───────────────
WATCH_DIRS=(
/opt/blackroad
/etc/systemd/system
)
SNAPSHOT_DIR="/tmp/road-phone-snapshot"
mkdir -p "$SNAPSHOT_DIR"
# ── gather payload ───────────────────────────────────────
gather_payload() {
local payload_dir="/tmp/road-phone-payload"
rm -rf "$payload_dir"
mkdir -p "$payload_dir"
# 1. Crontab for all users
mkdir -p "$payload_dir/crontabs"
for user in $(cut -d: -f1 /etc/passwd 2>/dev/null | head -20); do
crontab -u "$user" -l > "$payload_dir/crontabs/$user.txt" 2>/dev/null || true
done
# Remove empty ones
find "$payload_dir/crontabs" -empty -delete 2>/dev/null || true
# 2. Running services
systemctl list-units --type=service --state=running --no-pager --no-legend 2>/dev/null \
| awk '{print $1}' > "$payload_dir/services-running.txt" || true
# 3. System info snapshot
cat > "$payload_dir/system-info.txt" << SYSEOF
hostname: $(hostname)
date: $(date -Iseconds)
uptime: $(uptime)
kernel: $(uname -r)
temp: $(cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null | awk '{printf "%.1f°C", $1/1000}' || echo "N/A")
memory: $(free -h 2>/dev/null | awk '/Mem:/{print $3"/"$2}' || echo "N/A")
disk: $(df -h / 2>/dev/null | awk 'NR==2{print $3"/"$2" ("$5")"}' || echo "N/A")
load: $(cat /proc/loadavg 2>/dev/null | awk '{print $1, $2, $3}' || echo "N/A")
throttle: $(vcgencmd get_throttled 2>/dev/null || echo "N/A")
voltage: $(vcgencmd measure_volts core 2>/dev/null || echo "N/A")
SYSEOF
# 4. /opt/blackroad scripts and configs
if [ -d /opt/blackroad ]; then
rsync -a --exclude='.git/' --exclude='node_modules/' --exclude='__pycache__/' \
--exclude='*.db' --exclude='*.log' --exclude='venv/' \
/opt/blackroad/ "$payload_dir/opt-blackroad/" 2>/dev/null || true
fi
# 5. BlackRoad user scripts
for user_home in /home/blackroad /home/pi /home/octavia; do
if [ -d "$user_home" ]; then
local uname=$(basename "$user_home")
mkdir -p "$payload_dir/home-$uname"
# Grab shell scripts
find "$user_home" -maxdepth 2 -name "*.sh" -size -100k 2>/dev/null \
| while read -r f; do
cp "$f" "$payload_dir/home-$uname/" 2>/dev/null || true
done
# Grab .bashrc/.profile
cp "$user_home/.bashrc" "$payload_dir/home-$uname/bashrc" 2>/dev/null || true
cp "$user_home/.profile" "$payload_dir/home-$uname/profile" 2>/dev/null || true
cp "$user_home/.bash_aliases" "$payload_dir/home-$uname/bash_aliases" 2>/dev/null || true
fi
done
# 6. Key system configs
mkdir -p "$payload_dir/etc"
cp /boot/firmware/config.txt "$payload_dir/etc/config.txt" 2>/dev/null || \
cp /boot/config.txt "$payload_dir/etc/config.txt" 2>/dev/null || true
cp /etc/dhcpcd.conf "$payload_dir/etc/dhcpcd.conf" 2>/dev/null || true
cp /etc/hosts "$payload_dir/etc/hosts" 2>/dev/null || true
cp /etc/hostname "$payload_dir/etc/hostname" 2>/dev/null || true
# 7. Docker state
if command -v docker &>/dev/null; then
docker ps --format '{{.Names}}\t{{.Image}}\t{{.Status}}' \
> "$payload_dir/docker-containers.txt" 2>/dev/null || true
docker images --format '{{.Repository}}:{{.Tag}}\t{{.Size}}' \
> "$payload_dir/docker-images.txt" 2>/dev/null || true
fi
# 8. Network state
ip addr show 2>/dev/null | grep -E 'inet |state ' > "$payload_dir/network.txt" || true
ss -tlnp 2>/dev/null > "$payload_dir/listening-ports.txt" || true
# 9. Ollama models (if running)
if command -v ollama &>/dev/null; then
ollama list > "$payload_dir/ollama-models.txt" 2>/dev/null || true
fi
echo "$payload_dir"
}
# ── detect changes ───────────────────────────────────────
has_changes() {
local new_hash
# Hash key files to detect changes
new_hash=$(find /opt/blackroad /etc/systemd/system -name '*.sh' -o -name '*.service' -o -name '*.conf' -o -name '*.py' 2>/dev/null \
| sort | head -200 | xargs md5sum 2>/dev/null | md5sum | awk '{print $1}')
local old_hash=""
[ -f "$SNAPSHOT_DIR/last_hash" ] && old_hash=$(cat "$SNAPSHOT_DIR/last_hash")
if [ "$new_hash" != "$old_hash" ]; then
echo "$new_hash" > "$SNAPSHOT_DIR/last_hash"
return 0 # changed
fi
return 1 # no change
}
# ── dial the switchboard ─────────────────────────────────
dial() {
local payload_dir
payload_dir=$(gather_payload)
tone "Dialing switchboard ($SWITCHBOARD)..."
# Ring ring — rsync payload to Mac
if rsync -az --timeout=30 --delete \
"$payload_dir/" \
"$SWITCHBOARD:$DROPOFF/" 2>/dev/null; then
CALL_COUNT=$((CALL_COUNT + 1))
ring "Call #$CALL_COUNT connected — payload delivered to $HOSTNAME line"
rm -rf "$payload_dir"
return 0
else
busy "Switchboard didn't pick up (Mac offline?)"
rm -rf "$payload_dir"
return 1
fi
}
# ── service install ──────────────────────────────────────
install_service() {
local script_path
script_path=$(readlink -f "$0")
cat > /tmp/road-phone.service << SVCEOF
[Unit]
Description=RoadPhone — BlackRoad landline to Alexandria
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
ExecStart=$script_path
Restart=always
RestartSec=30
Environment=PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
[Install]
WantedBy=multi-user.target
SVCEOF
sudo mv /tmp/road-phone.service /etc/systemd/system/road-phone.service
sudo systemctl daemon-reload
sudo systemctl enable road-phone.service
sudo systemctl start road-phone.service
log "Service installed and started"
sudo systemctl status road-phone.service --no-pager
}
uninstall_service() {
sudo systemctl stop road-phone.service 2>/dev/null || true
sudo systemctl disable road-phone.service 2>/dev/null || true
sudo rm -f /etc/systemd/system/road-phone.service
sudo systemctl daemon-reload
log "Service uninstalled"
}
# ── handle args ──────────────────────────────────────────
case "${1:-}" in
--install) install_service; exit ;;
--uninstall) uninstall_service; exit ;;
--call) dial; exit ;;
esac
# ── main loop ────────────────────────────────────────────
echo $$ > "$PIDFILE"
trap 'rm -f "$PIDFILE"; log "Phone hanging up"; exit 0' INT TERM
log "☎️ RoadPhone online — $HOSTNAME picking up the landline"
log "Switchboard: $SWITCHBOARD | Ring interval: ${RING_INTERVAL}s"
# Initial call on boot
dial
# Watch loop
SECONDS_SINCE_CALL=0
while true; do
sleep "$RING_INTERVAL"
SECONDS_SINCE_CALL=$((SECONDS_SINCE_CALL + RING_INTERVAL))
if has_changes; then
tone "Change detected on the line!"
dial
SECONDS_SINCE_CALL=0
elif (( SECONDS_SINCE_CALL >= 900 )); then
# Heartbeat call every 15 min even if nothing changed
tone "Heartbeat ring (15m keepalive)"
dial
SECONDS_SINCE_CALL=0
fi
done