move host setup into scripts/setup/
scripts/ was holding two unrelated kinds of thing: install-this-machine, and run-this-occasionally. The eight installers now live in scripts/setup/; what stays at the top level is the build steps (gen-index, prebuild, build/) and the two maintenance scripts (reindex-music, rebuild-soulseek-tree). The move is not just a rename. Three of these derive the repo root from their own location: setup.sh:51 PROJECT_DIR="$(dirname "$SCRIPT_DIR")" setup_mac_light.sh:51 same cleanup-desktop.sh:134 ENV_FILE="$(dirname "$0")/../.env" Left alone, all three would now resolve to scripts/ — and nothing downstream complains. PROJECT_DIR is where .env is written, where `bun install`, `gen:index` and `db:push` run, and what pm2 is pointed at, so a fresh install would have quietly provisioned scripts/ and reported success. cleanup-desktop.sh fails the other way: it would find no .env, print "No .env — skipping", and leave the real VNC_PASSWORD in the real file. All three are now `../..` with a comment saying why the level matters. provision-user-dirs.ts imports data-path.ts relatively; that one tsgo caught. Also disambiguated `setup.sh` where it had become two files. app-store/templates/<name>/setup.sh is a per-sidecar installer with its own contract, and preflight.ts + docs/sidecar-app-store.md discussed both in the same paragraph. The host one is now spelled with its full path at those sites. Verified: bash -n on all six shell scripts, tsgo clean, os-user tests pass, both derivations resolve to the repo root, starship.toml still resolves from os-user-shell.ts, and provision-user-dirs.ts runs under DRY_RUN. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Executable
+173
@@ -0,0 +1,173 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Officer Remote Desktop Setup — Ubuntu GNOME desktop on Xorg, mirrored over VNC.
|
||||
#
|
||||
# The platform mirrors the single physical display :0 with x11vnc (see vnc-manager.ts). x11vnc can only
|
||||
# capture an Xorg server, NOT a Wayland compositor — so we install the full GNOME desktop but force GDM
|
||||
# onto the Xorg session (WaylandEnable=false). Auto-login is enabled so a user session owns :0 for the
|
||||
# mirror to attach to. Switching the display manager takes effect on the next reboot.
|
||||
# Usage: ./scripts/setup/setup-desktop.sh
|
||||
|
||||
echo "=== Officer Remote Desktop Setup (Ubuntu GNOME on Xorg) ==="
|
||||
echo ""
|
||||
|
||||
DESKTOP_USER="$(whoami)"
|
||||
|
||||
# --- Step 1: Install GNOME desktop + GDM + x11vnc ---
|
||||
echo "[1/6] Installing ubuntu-desktop, GDM, x11vnc..."
|
||||
sudo apt update -qq
|
||||
sudo DEBIAN_FRONTEND=noninteractive apt install -y -qq \
|
||||
ubuntu-desktop \
|
||||
gdm3 \
|
||||
x11vnc \
|
||||
dbus-x11
|
||||
echo " Done."
|
||||
# No tigervnc package is needed. The VNC sidecar writes the .vnc/passwd rfbauth file with
|
||||
# `x11vnc -storepasswd` (see vnc-manager.ts). tigervnc-common was installed here for `vncpasswd`,
|
||||
# but it does not ship that binary — it only provides tigervncconfig — so the rfbauth file was never
|
||||
# created and the desktop could not authenticate.
|
||||
|
||||
# --- Step 2: Force GDM onto Xorg + enable auto-login (x11vnc cannot mirror Wayland) ---
|
||||
echo "[2/6] Forcing Xorg session and auto-login in GDM..."
|
||||
GDM_CONF=/etc/gdm3/custom.conf
|
||||
sudo mkdir -p /etc/gdm3
|
||||
[ -f "$GDM_CONF" ] || echo "[daemon]" | sudo tee "$GDM_CONF" > /dev/null
|
||||
# Ensure a [daemon] section exists to anchor the keys under.
|
||||
sudo grep -qE '^\[daemon\]' "$GDM_CONF" || echo "[daemon]" | sudo tee -a "$GDM_CONF" > /dev/null
|
||||
|
||||
# Set key=value under [daemon]: rewrite an existing (possibly commented) line, else insert after [daemon].
|
||||
set_gdm_key() {
|
||||
local key="$1" val="$2"
|
||||
if sudo grep -qE "^[[:space:]]*#?[[:space:]]*${key}=" "$GDM_CONF"; then
|
||||
sudo sed -i "s|^[[:space:]]*#\?[[:space:]]*${key}=.*|${key}=${val}|" "$GDM_CONF"
|
||||
else
|
||||
sudo sed -i "/^\[daemon\]/a ${key}=${val}" "$GDM_CONF"
|
||||
fi
|
||||
}
|
||||
|
||||
set_gdm_key WaylandEnable false
|
||||
set_gdm_key AutomaticLoginEnable true
|
||||
set_gdm_key AutomaticLogin "$DESKTOP_USER"
|
||||
echo " Xorg forced (WaylandEnable=false), auto-login as $DESKTOP_USER."
|
||||
|
||||
# --- Step 3: Make GDM the default display manager ---
|
||||
echo "[3/6] Setting GDM as the default display manager..."
|
||||
echo "/usr/sbin/gdm3" | sudo tee /etc/X11/default-display-manager > /dev/null
|
||||
sudo systemctl enable gdm3 >/dev/null 2>&1 || sudo systemctl enable gdm >/dev/null 2>&1 || true
|
||||
sudo systemctl set-default graphical.target >/dev/null 2>&1 || true
|
||||
# Disable any prior display manager so it doesn't fight GDM. lightdm is named because earlier versions
|
||||
# of this script installed XFCE; a host set up back then still has it and it would win the boot race.
|
||||
sudo systemctl disable lightdm >/dev/null 2>&1 || true
|
||||
echo " Done (takes effect on next reboot)."
|
||||
|
||||
# --- Step 4: Install Brave browser (native .deb, not snap) ---
|
||||
echo "[4/6] Installing Brave browser..."
|
||||
if ! command -v brave-browser-stable > /dev/null 2>&1; then
|
||||
sudo curl -fsSLo /usr/share/keyrings/brave-browser-archive-keyring.gpg \
|
||||
https://brave-browser-apt-release.s3.brave.com/brave-browser-archive-keyring.gpg
|
||||
echo "deb [signed-by=/usr/share/keyrings/brave-browser-archive-keyring.gpg] https://brave-browser-apt-release.s3.brave.com/ stable main" \
|
||||
| sudo tee /etc/apt/sources.list.d/brave-browser-release.list > /dev/null
|
||||
sudo apt update -qq
|
||||
sudo DEBIAN_FRONTEND=noninteractive apt install -y -qq brave-browser
|
||||
fi
|
||||
# Fix launcher symlink
|
||||
if [ -f /opt/brave.com/brave/brave-browser ]; then
|
||||
sudo rm -f /usr/bin/brave-browser-stable
|
||||
sudo ln -s /opt/brave.com/brave/brave-browser /usr/bin/brave-browser-stable
|
||||
fi
|
||||
# Tell Brave to use basic password store (no keyring prompts)
|
||||
sudo mkdir -p /etc/brave
|
||||
echo '--password-store=basic' | sudo tee /etc/brave/brave-flags.conf > /dev/null
|
||||
echo " Done."
|
||||
|
||||
# --- Step 5: Remove GNOME Keyring + set default browser (prevents password prompts on login) ---
|
||||
echo "[5/6] Removing GNOME Keyring and setting default browser..."
|
||||
sudo apt remove -y --purge gnome-keyring > /dev/null 2>&1 || true
|
||||
rm -rf ~/.local/share/keyrings
|
||||
if command -v brave-browser-stable > /dev/null 2>&1; then
|
||||
sudo update-alternatives --set x-www-browser /opt/brave.com/brave/brave 2>/dev/null || true
|
||||
echo " Brave set as default."
|
||||
else
|
||||
echo " No supported browser found, skipping default."
|
||||
fi
|
||||
|
||||
# --- Step 6: Headless display (keep a desktop when no monitor is attached) ---
|
||||
echo "[6/6] Configuring the headless display..."
|
||||
|
||||
# x11vnc mirrors :0, but with nothing plugged in the connector has no EDID and no CRTC, so GNOME
|
||||
# renders nothing and the mirror is black. Replaying a real monitor's EDID makes the connector look
|
||||
# permanently attached. The EDID has to be captured from a screen that is plugged in *now* — there is
|
||||
# nothing to copy otherwise — so this step is skipped on a headless run and can be re-run later.
|
||||
EDID_DIR=/lib/firmware/edid
|
||||
EDID_FILE="$EDID_DIR/officer-screen.bin"
|
||||
CONNECTED_SYSFS=""
|
||||
for c in /sys/class/drm/card*-*/status; do
|
||||
[ "$(cat "$c" 2>/dev/null)" = "connected" ] || continue
|
||||
CONNECTED_SYSFS="$(basename "$(dirname "$c")")"
|
||||
break
|
||||
done
|
||||
|
||||
if [ -z "$CONNECTED_SYSFS" ] && [ ! -f "$EDID_FILE" ]; then
|
||||
echo " ! No display connected and no EDID saved — skipping."
|
||||
echo " Plug a monitor in and re-run this script to capture one, otherwise the remote"
|
||||
echo " desktop will be black whenever nothing is attached."
|
||||
else
|
||||
# cardN-HDMI-A-1 -> HDMI-A-1, which is the name the kernel parameters use (card numbering can
|
||||
# change between boots; the connector name does not).
|
||||
if [ -n "$CONNECTED_SYSFS" ]; then
|
||||
CONNECTOR="${CONNECTED_SYSFS#*-}"
|
||||
sudo mkdir -p "$EDID_DIR"
|
||||
sudo cp "/sys/class/drm/$CONNECTED_SYSFS/edid" "$EDID_FILE"
|
||||
echo " Captured EDID from $CONNECTOR ($(stat -c%s "$EDID_FILE") bytes)."
|
||||
echo "$CONNECTOR" | sudo tee "$EDID_DIR/officer-connector" > /dev/null
|
||||
else
|
||||
CONNECTOR="$(cat "$EDID_DIR/officer-connector" 2>/dev/null || echo HDMI-A-1)"
|
||||
echo " Reusing the saved EDID for $CONNECTOR."
|
||||
fi
|
||||
|
||||
# drm.edid_firmware makes the connector report that EDID; the trailing "e" on video= forces it
|
||||
# enabled with nothing attached. amdgpu is not in the initramfs, so /lib/firmware is readable by
|
||||
# the time the driver loads and no initramfs rebuild is needed.
|
||||
KERNEL_ARGS="drm.edid_firmware=$CONNECTOR:edid/officer-screen.bin video=$CONNECTOR:1920x1080e"
|
||||
if grep -q "drm.edid_firmware=" /etc/default/grub; then
|
||||
echo " GRUB already carries a forced EDID — leaving it alone."
|
||||
else
|
||||
sudo cp /etc/default/grub "/etc/default/grub.bak-$(date +%Y%m%d%H%M%S)"
|
||||
CURRENT=$(grep "^GRUB_CMDLINE_LINUX_DEFAULT=" /etc/default/grub | sed 's/^[^"]*"//; s/"$//')
|
||||
sudo sed -i "s|^GRUB_CMDLINE_LINUX_DEFAULT=.*|GRUB_CMDLINE_LINUX_DEFAULT=\"${CURRENT:+$CURRENT }$KERNEL_ARGS\"|" /etc/default/grub
|
||||
sudo update-grub > /dev/null 2>&1
|
||||
echo " Added the forced EDID to the kernel command line (takes effect on reboot)."
|
||||
fi
|
||||
|
||||
# The EDID's preferred mode is whatever the captured panel was, which may be small. GNOME picks
|
||||
# preferred, so raise it at session start.
|
||||
install -d "$HOME/.local/bin" "$HOME/.config/autostart"
|
||||
install -m 755 "$(dirname "$0")/officer-set-display.sh" "$HOME/.local/bin/officer-set-display.sh"
|
||||
cat > "$HOME/.config/autostart/officer-set-display.desktop" <<AUTOSTART
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Officer display mode
|
||||
Comment=Raise the headless display to its largest usable mode at login
|
||||
Exec=$HOME/.local/bin/officer-set-display.sh
|
||||
X-GNOME-Autostart-enabled=true
|
||||
NoDisplay=true
|
||||
AUTOSTART
|
||||
echo " Installed the login-time mode setter."
|
||||
fi
|
||||
echo " Done."
|
||||
|
||||
# --- Cleanup old systemd service if it exists ---
|
||||
if systemctl list-unit-files officer-vnc.service &>/dev/null; then
|
||||
echo ""
|
||||
echo "Removing old officer-vnc systemd service..."
|
||||
sudo systemctl stop officer-vnc 2>/dev/null || true
|
||||
sudo systemctl disable officer-vnc 2>/dev/null || true
|
||||
sudo rm -f /etc/systemd/system/officer-vnc.service
|
||||
sudo systemctl daemon-reload
|
||||
echo " Done."
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Setup complete. The screen mirror (x11vnc on :0) is managed by the VNC sidecar."
|
||||
echo "REBOOT to switch into the GNOME-on-Xorg session with auto-login."
|
||||
Reference in New Issue
Block a user