#!/bin/bash # Officer — host dependencies for the optional, sidecar-backed features. # # Usage: # bash scripts/setup/setup-sidecars.sh # # WHAT THIS IS # Everything here was part of setup.sh and is not any more. setup.sh installs what the app needs to # serve itself; this installs what a handful of *optional* features need on the host, and it is never # invoked by setup.sh — running it is a deliberate act. # # The sections keep the numbering they had in setup.sh so the two files can be read against each # other: # # 1 (was 8) Rust # 2 (was 9) PulseAudio + audio dev headers # 3 (was 10) cliamp # 4 (was 13) yt-dlp # 5 (was 17) Remote desktop (delegates to setup-desktop.sh) # # There is no `light`/`full` profile here. In setup.sh these sections were the ones `light` skipped, # so gating them again would only mean "run this script and have it do nothing" — running it at all # IS the opt-in. # # ORDER MATTERS: section 3 needs Go, which setup.sh installs. Run setup.sh first. # Section 5 rewrites GRUB and switches the display manager — it takes effect on the next reboot. set -e GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' ok() { echo -e " ${GREEN}✓${NC} $1"; } warn() { echo -e " ${YELLOW}!${NC} $1"; } fail() { echo -e " ${RED}✗${NC} $1"; } skip() { echo -e " - $1 (already installed)"; } has() { command -v "$1" &>/dev/null; } SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # setup.sh installed Go and rustup into the user's home and exported them for its own run only. A # fresh shell has neither on PATH, which would make `has go` false (silently skipping the cliamp # build) and `has rustc` false (re-running rustup over an existing toolchain). Put them back. export PATH="$HOME/.local/go/bin:$HOME/.cargo/bin:$PATH" # ─── detect package manager ──────────────────────────────────────────────────── if has apt; then PM=apt elif has pacman; then PM=pacman elif has brew; then PM=brew else fail "No supported package manager found (apt, pacman, brew)" exit 1 fi install_pkg() { case $PM in apt) sudo apt install -y "$@" ;; pacman) sudo pacman -S --noconfirm "$@" ;; brew) brew install "$@" ;; esac } echo "" echo "═══════════════════════════════════════════" echo " Officer — optional host dependencies ($PM)" echo "═══════════════════════════════════════════" # ─── 1. Rust (was setup.sh section 8) ───────────────────────────────────────── echo "" echo "── Rust ──" if has rustc && has cargo; then skip "rust ($(rustc --version 2>/dev/null | awk '{print $2}'))" else curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal export PATH="$HOME/.cargo/bin:$PATH" if has rustc; then ok "rust installed"; else warn "rust install failed"; fi fi # ─── 2. PulseAudio (headless audio for cliamp) (was section 9) ──────────────── echo "" echo "── PulseAudio (headless audio) ──" PULSE_PKGS=() if has pulseaudio; then skip "pulseaudio"; else case $PM in apt) PULSE_PKGS+=(pulseaudio) ;; pacman) PULSE_PKGS+=(pulseaudio) ;; brew) warn "PulseAudio: brew install pulseaudio (cliamp audio won't work without it)" ;; esac fi # pulseaudio-utils provides parec and pactl if has parec && has pactl; then skip "pulseaudio-utils (parec, pactl)"; else case $PM in apt) PULSE_PKGS+=(pulseaudio-utils) ;; pacman) ;; # included in pulseaudio package brew) ;; # included in pulseaudio formula esac fi # ALSA dev headers (needed to compile cliamp's Go audio library) case $PM in apt) if dpkg -s libasound2-dev &>/dev/null 2>&1; then skip "libasound2-dev"; else PULSE_PKGS+=(libasound2-dev); fi ;; pacman) if pacman -Qi alsa-lib &>/dev/null 2>&1; then skip "alsa-lib"; else PULSE_PKGS+=(alsa-lib); fi ;; brew) ;; # not needed on macOS esac # Vorbis/OGG/FLAC dev headers (needed by cliamp's Go dependencies) case $PM in apt) for pkg in libvorbis-dev libogg-dev libflac-dev; do if dpkg -s "$pkg" &>/dev/null 2>&1; then skip "$pkg"; else PULSE_PKGS+=("$pkg"); fi done ;; pacman) for pkg in libvorbis libogg flac; do if pacman -Qi "$pkg" &>/dev/null 2>&1; then skip "$pkg"; else PULSE_PKGS+=("$pkg"); fi done ;; brew) ;; # not needed on macOS esac if [ ${#PULSE_PKGS[@]} -gt 0 ]; then install_pkg "${PULSE_PKGS[@]}" ok "Installed: ${PULSE_PKGS[*]}" fi # ─── 3. cliamp (music player) (was section 10) ──────────────────────────────── echo "" echo "── cliamp ──" # Export GOPATH (not just PATH) so `go install` lands in GOPATH_BIN — even when Go was already present # this run and install_go (which sets GOPATH) never ran. Otherwise go uses its default ~/go/bin and the # check below wrongly reports a build failure. export GOPATH="${GOPATH:-$HOME/.local/go-path}" GOPATH_BIN="$GOPATH/bin" export PATH="$GOPATH_BIN:$PATH" if has cliamp; then skip "cliamp ($(command -v cliamp))" else if ! has go; then warn "Go not installed — skipping cliamp build (run setup.sh first)" else echo " Building cliamp from source..." TMPDIR=$(mktemp -d) git clone --depth=1 https://github.com/bjarneo/cliamp.git "$TMPDIR/cliamp" (cd "$TMPDIR/cliamp" && go install .) rm -rf "$TMPDIR" if [ -f "$GOPATH_BIN/cliamp" ]; then ok "cliamp installed at $GOPATH_BIN/cliamp" else warn "cliamp build failed" fi fi fi # ─── 4. yt-dlp (video/audio download) (was section 13) ──────────────────────── echo "" echo "── yt-dlp ──" # Always install/upgrade via pip to get the latest version (apt repos are outdated). # Remove apt version first if present, then install via pip to /usr/local/bin. if has pip3; then # Remove outdated apt version if installed case $PM in apt) if dpkg -s yt-dlp &>/dev/null 2>&1; then echo " Removing outdated apt version..." sudo apt remove -y yt-dlp > /dev/null 2>&1 fi ;; esac echo " Installing/upgrading yt-dlp via pip..." sudo pip3 install --break-system-packages --upgrade yt-dlp 2>/dev/null if has yt-dlp; then ok "yt-dlp $(yt-dlp --version) installed"; else warn "yt-dlp pip install failed"; fi else case $PM in apt) install_pkg yt-dlp 2>/dev/null && ok "yt-dlp installed (apt — may be outdated)" || warn "yt-dlp not available" ;; pacman) install_pkg yt-dlp && ok "yt-dlp installed" ;; brew) install_pkg yt-dlp && ok "yt-dlp installed" ;; esac fi # ─── 5. remote desktop (Ubuntu Desktop + VNC) (was section 17) ──────────────── echo "" echo "── Remote Desktop (Ubuntu Desktop + VNC) ──" # No "already installed" guard here on purpose. This used to skip on `dpkg -s ubuntu-desktop`, which # treats one package being present as proof the whole remote desktop is configured — and those are very # different things. A host can have ubuntu-desktop and still be missing every part that makes the mirror # work: GDM auto-login, the forced Xorg session, the captured EDID and its kernel command line, the # login-time mode setter. That was not hypothetical; it was this machine on 2026-08-02, where the guard # reported "skip" while five of setup-desktop.sh's steps had never run and /desktop could not survive a # reboot. setup-desktop.sh is idempotent throughout — every step either no-ops or is individually # guarded — so letting it run each time converges a partially configured host instead of trusting a # proxy for state it never actually checked. # # This is by far the most expensive section — it pulls the whole ubuntu-desktop meta-package, rewrites # /etc/default/grub and switches the display manager. case $PM in apt) bash "$SCRIPT_DIR/setup-desktop.sh" ;; *) warn "Remote desktop setup is Ubuntu/Debian only — skipping" ;; esac # ─── verification ───────────────────────────────────────────────────────────── echo "" echo "═══════════════════════════════════════════" echo " Verification" echo "═══════════════════════════════════════════" echo "" check() { if has "$1"; then ok "$1"; else fail "$1 — NOT FOUND"; fi } echo "Rust:" check rustc check cargo echo "" echo "Audio (cliamp):" check pulseaudio check parec check pactl check cliamp echo "" echo "Download:" check yt-dlp echo "" echo "═══════════════════════════════════════════" echo " Done" echo "═══════════════════════════════════════════" echo "" echo "Notes:" echo " • PulseAudio null sink starts automatically with the server" echo " • Make sure ~/.cargo/bin is in your PATH for Rust tools" echo " • Make sure ~/.local/go-path/bin is in your PATH for Go-installed tools (cliamp)" echo " • REBOOT to switch into the GNOME-on-Xorg session the remote desktop mirrors" echo ""