Make install.sh --handoff self-sufficient for a stock machine

A fresh generic install wants input sharing without the packages, config,
themes or plugins steps dragging personalizations along, so the handoff
step now stands alone: it installs lan-mouse and rust, drops in the
wrapper, builds the patch, installs and enables the unit, and opens the
firewall. Everything is idempotent, so a later full run does no extra
work. Verified by running it twice on omarchy-air -- second pass is all
skips, and the daemon comes back armed with a real barrier.

Drops python-evdev from the required set. packages.txt calls it a
lan-mouse dependency, but omarchy-air runs this entire setup without it
installed, so it is not needed for sharing and a minimal install should
not pull it.

The ufw section now degrades instead of half-applying: if sudo needs a
password and there is no terminal to prompt on, it prints the exact
commands to run and says what breaks without them, rather than emitting
raw sudo errors.

Hardware note for whoever reads this next: Omarchy's own installer covers
most of what packages.txt lists under hardware. install/hardware has
per-vendor trees (apple, asus, framework, intel, lenovo) plus vulkan.sh,
zram.sh, fix-fkeys.sh, sof-firmware.sh and thermald.sh, and the installer
prompts for keyboard, user, hostname and timezone. So vulkan-intel,
sof-firmware, thermald, zram-generator and the hid_apple fnmode drop-in
are all redundant on a fresh install, and the intel-* entries are wrong
on non-Intel hardware. Apply the hardware block only on the machine it
was captured from.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LrgrMhPG8CTo9XZF326rjZ
This commit is contained in:
2026-10-10 17:38:39 -04:00
co-authored by Claude Opus 5
parent 50176b78ee
commit b3f3f46b98
+45 -2
View File
@@ -274,6 +274,27 @@ step_services() {
step_handoff() {
head_ "omarchy-handoff (lan-mouse)"
# Self-sufficient on purpose: `install.sh handoff` alone brings input sharing up
# on an otherwise stock machine, without the packages/config/themes steps that
# would drag personalizations along. Everything here is idempotent, so running
# the full install.sh afterwards does no extra work.
# lan-mouse: the signed package, for the GUI/CLI and as the unpatched fallback.
# rust: only to compile handoff/patch/, removable afterwards.
# NOT python-evdev: packages.txt calls it a dependency, but omarchy-air runs
# this whole setup without it installed, so it is not required for sharing.
local need=() p
for p in lan-mouse rust; do
pacman -Qq "$p" &>/dev/null || need+=("$p")
done
if (( ${#need[@]} )); then
say " installing: ${need[*]}"
run omarchy pkg add "${need[@]}" || warn "package install failed: ${need[*]}"
else
skip "lan-mouse, rust"
fi
install_file "$REPO/bin/omarchy-handoff" "$HOME/.local/bin/omarchy-handoff" 0755
# 1. The patched daemon. systemd/user/lan-mouse.service points at this path, so
# it has to exist before the services step enables the unit. Per-architecture:
# this laptop is x86_64 and omarchy-air is aarch64, so each builds its own.
@@ -289,7 +310,17 @@ step_handoff() {
else err "build failed - the unit will not start until this succeeds"; fi
fi
# 2. The firewall. THE bug that cost a full day: ufw is default-deny inbound, so
# 2. The unit, which points at the binary built above.
install_file "$REPO/systemd/user/lan-mouse.service" \
"$HOME/.config/systemd/user/lan-mouse.service" 0644
if (( ! DRY )); then
systemctl --user daemon-reload
systemctl --user is-enabled --quiet lan-mouse.service 2>/dev/null \
&& skip "lan-mouse.service already enabled" \
|| { systemctl --user enable lan-mouse.service >/dev/null && ok "enabled lan-mouse.service"; }
fi
# 3. The firewall. THE bug that cost a full day: ufw is default-deny inbound, so
# the peer's DTLS handshake dies at the wire and presents EXACTLY like a bad
# certificate. Authorization is receiver-side only (connect.rs sets
# insecure_skip_verify), so the RECEIVER's firewall must allow 4242/udp or
@@ -298,7 +329,19 @@ step_handoff() {
skip "ufw not installed - nothing to open"
else
local ip rules=""
# Reading the ruleset needs root, so don't probe it on a dry run.
# Both reading and changing the ruleset need root. If sudo can't run without
# a prompt and there's no terminal to prompt on, say exactly what to run
# instead of emitting raw sudo errors and half-applying.
if (( ! DRY )) && ! sudo -n true 2>/dev/null && [[ ! -t 0 ]]; then
warn "sudo needs a password and there is no terminal; run these yourself:"
for ip in "${HANDOFF_PEER_IPS[@]}"; do
say " sudo ufw allow from $ip to any port 4242 proto udp comment 'lan-mouse peer $ip'"
done
say ""
say " Without them, anything the peer INITIATES toward this machine is"
say " dropped at the wire and looks exactly like a bad certificate."
return 0
fi
(( DRY )) || rules=$(sudo ufw status 2>/dev/null || true)
for ip in "${HANDOFF_PEER_IPS[@]}"; do
if [[ $rules == *"4242"*"$ip"* ]]; then