Merge quattro into USB authorization branch

This commit is contained in:
acrogenesis committed 2026-09-21 08:23:51 -06:00
commit 27bbbb2fe9
121 files changed
+2208 -1118

No files matched your search

+20 -5
View File
@@ -15,8 +15,9 @@
# start.
#
# Env: OMARCHY_SCREENRECORD_DEBUG=true appends gpu-screen-recorder's stderr (and
# the picker target it was launched with) to /tmp/omarchy-screenrecord.log so
# users can attach a log when reporting capture failures.
# the picker target it was launched with) to
# $XDG_RUNTIME_DIR/omarchy-screenrecord.log so users can attach a log when
# reporting capture failures.
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
OUTPUT_DIR="${OMARCHY_SCREENRECORD_DIR:-${XDG_VIDEOS_DIR:-$HOME/Videos}}"
@@ -34,9 +35,18 @@ WEBCAM_SIZE="medium"
RESOLUTION=""
FULLSCREEN="false"
STOP_RECORDING="false"
RECORDING_FILE="/tmp/omarchy-screenrecord-filename"
REGION_FILE="${XDG_RUNTIME_DIR:-/tmp}/omarchy-screenrecord-region"
LOG_FILE=$([[ ${OMARCHY_SCREENRECORD_DEBUG:-false} == "true" ]] && echo "/tmp/omarchy-screenrecord.log" || echo "/dev/null")
# Both of these live in the per-user runtime directory, which is 0700. What
# RECORDING_FILE holds is read back on stop and used as a path -- ffmpeg writes
# beside it, `mv` replaces it, and `rm -f` deletes its preview -- so a name in
# world-writable /tmp is a name any other local account can create first and
# then point wherever it likes. The debug log carries the recorder's stderr and
# the picked geometry, which is nobody else's business either. Fall back to
# the state directory when there is no session runtime dir -- :-/tmp would put
# both files back at the fixed names this comment describes.
RUNTIME_DIR="${XDG_RUNTIME_DIR:-${XDG_STATE_HOME:-$HOME/.local/state}/omarchy}"
RECORDING_FILE="$RUNTIME_DIR/omarchy-screenrecord-filename"
REGION_FILE="$RUNTIME_DIR/omarchy-screenrecord-region"
LOG_FILE=$([[ ${OMARCHY_SCREENRECORD_DEBUG:-false} == "true" ]] && echo "$RUNTIME_DIR/omarchy-screenrecord.log" || echo "/dev/null")
for arg in "$@"; do
case "$arg" in
@@ -144,6 +154,11 @@ select_capture_target() {
}
start_screenrecording() {
mkdir -p "$RUNTIME_DIR" || return 1
# XDG_STATE_HOME may be outside a private home; protect existing fallbacks too.
if [[ -z ${XDG_RUNTIME_DIR:-} ]]; then
chmod 700 "$RUNTIME_DIR" || return 1
fi
local capture_args=()
local target
+11 -70
View File
@@ -2,81 +2,22 @@
# omarchy:summary=Take a screenshot
# omarchy:group=capture
# omarchy:args=[smart|region|windows|fullscreen] [slurp|copy|save] [--editor=<name>]
# omarchy:args=[smart|region|windows|fullscreen|scroll] [copy|save]
# omarchy:examples=omarchy screenshot | omarchy capture screenshot region
# omarchy:aliases=omarchy screenshot
[[ -f ~/.config/user-dirs.dirs ]] && source ~/.config/user-dirs.dirs
OUTPUT_DIR="${OMARCHY_SCREENSHOT_DIR:-${XDG_PICTURES_DIR:-$HOME/Pictures}}"
if [[ ! -d $OUTPUT_DIR ]]; then
mkdir -p "$OUTPUT_DIR"
omarchy-notification-send "Created screenshot directory: $OUTPUT_DIR" -t 2000
if [[ -n ${OMARCHY_SCREENSHOT_DIR:-} && -z ${OMASNAP_SCREENSHOT_DIR:-} ]]; then
export OMASNAP_SCREENSHOT_DIR="$OMARCHY_SCREENSHOT_DIR"
fi
pkill slurp && exit 0
SCREENSHOT_EDITOR="${OMARCHY_SCREENSHOT_EDITOR:-tensaku-edit}"
# Parse --editor flag from any position
ARGS=()
omasnap_args=()
for arg in "$@"; do
if [[ $arg == --editor=* ]]; then
SCREENSHOT_EDITOR="${arg#--editor=}"
else
ARGS+=("$arg")
fi
case "$arg" in
copy) omasnap_args+=(--copy) ;;
save) omasnap_args+=(--save) ;;
slurp) ;;
*) omasnap_args+=("$arg") ;;
esac
done
set -- "${ARGS[@]}"
MODE="${1:-smart}"
PROCESSING="${2:-slurp}"
# The picker leaves the screen freeze running (PID on its first output line)
# so grim captures the frozen overlay rather than live content shifting
# during teardown.
#
# Software-composited cursors (Hyprland's fallback on GPUs without working
# hardware cursors) are baked into the frames grim captures, so force
# hardware cursors until after grim runs and restore the setting on exit.
NO_HW_CURSORS=$(hyprctl getoption cursor:no_hardware_cursors -j | jq '.int')
set_no_hw_cursors() {
hyprctl eval "hl.config({ cursor = { no_hardware_cursors = $1 } })" &>/dev/null ||
hyprctl keyword cursor:no_hardware_cursors "$1" &>/dev/null
}
cleanup() {
[[ -n $FREEZE_PID ]] && kill $FREEZE_PID 2>/dev/null
set_no_hw_cursors "$NO_HW_CURSORS"
}
trap cleanup EXIT
set_no_hw_cursors 0
{ read -r FREEZE_PID; read -r SELECTION; } < <(omarchy-capture-region "$MODE" --keep-freeze)
[[ -z $SELECTION ]] && exit 0
FILENAME="screenshot-$(date +'%Y-%m-%d_%H-%M-%S').png"
FILEPATH="$OUTPUT_DIR/$FILENAME"
case "$PROCESSING" in
slurp)
grim -g "$SELECTION" "$FILEPATH" || exit 1
echo "$FILEPATH"
wl-copy --type image/png <"$FILEPATH"
# Best-effort: the screenshot is already saved and on the clipboard, so a
# notification outage must not report the capture itself as failed.
omarchy-notification-send "Screenshot saved to clipboard and file" "Edit with Super + Alt + , (or click this)" \
--image "$FILEPATH" \
--exec "$SCREENSHOT_EDITOR" "$FILEPATH" || true
;;
copy)
grim -g "$SELECTION" - | wl-copy --type image/png
;;
save)
grim -g "$SELECTION" "$FILEPATH" || exit 1
echo "$FILEPATH"
;;
esac
exec omasnap "${omasnap_args[@]}"
+4 -1
View File
@@ -8,7 +8,10 @@
set -euo pipefail
readonly MARGIN=40
readonly REGION_FILE="${XDG_RUNTIME_DIR:-/tmp}/omarchy-screenrecord-region"
# Has to resolve to whatever omarchy-capture-screenrecording writes, fallback
# included, or a recording without a session runtime dir anchors the camera to
# the whole monitor instead of the region it recorded.
readonly REGION_FILE="${XDG_RUNTIME_DIR:-${XDG_STATE_HOME:-$HOME/.local/state}/omarchy}/omarchy-screenrecord-region"
usage() {
echo "Usage: omarchy-capture-webcam-resize <smaller|larger|reset|small|medium|large>" >&2
+1 -1
View File
@@ -30,7 +30,7 @@ open_image() {
local path="$1"
[[ -r $path ]] || exit 1
exec tensaku-edit "$path"
exec omasnap "$path"
}
open_text() {
+4
View File
@@ -86,6 +86,10 @@ if ! agent_install; then
exit 1
fi
if [[ $agent == "claude" ]]; then
omarchy-install-chromium-claude 2>/dev/null || true
fi
mkdir -p "$(dirname "$agent_file")"
printf '%s\n' "$agent" >"$agent_file"
+12
View File
@@ -11,6 +11,18 @@ if (( $# < 1 )); then
fi
HOOK=$1
# Hook names are fixed labels chosen by Omarchy code (post-update, theme-set,
# font-set). The name becomes a filename under the hooks directory. A slash
# would turn it into directory levels, and a bare `.` or `..` would point bash
# at the directory itself or its parent. Refuse those rather than follow them.
# Dots inside a name (a..b) are fine; once slashes are out, only the whole
# name being `.` or `..` can leave the directory.
if [[ -z $HOOK || $HOOK == */* || $HOOK == "." || $HOOK == ".." ]]; then
echo "Invalid hook name: $HOOK" >&2
exit 2
fi
HOOK_PATH="$HOME/.config/omarchy/hooks/$1"
HOOK_DIR="$HOOK_PATH.d"
shift
+11
View File
@@ -15,6 +15,17 @@ fi
HOOK_TYPE=$1
HOOK_FILE=$2
# Hook types are the same labels omarchy-hook runs (post-update, theme-set).
# The type becomes a directory under the hooks directory. A slash would turn
# it into directory levels. A bare `.` or `..` is a name the runner already
# refuses, so installing under it would write a hook nothing can run. Refuse
# those rather than mkdir/cp into them. Dots inside a name (a..b) are fine.
if [[ -z $HOOK_TYPE || $HOOK_TYPE == */* || $HOOK_TYPE == "." || $HOOK_TYPE == ".." ]]; then
echo "Invalid hook name: $HOOK_TYPE" >&2
exit 2
fi
HOOK_DIR="$HOME/.config/omarchy/hooks/$HOOK_TYPE.d"
HOOK_NAME=$(basename "$HOOK_FILE")
HOOK_PATH="$HOOK_DIR/$HOOK_NAME"
+43
View File
@@ -0,0 +1,43 @@
#!/bin/bash
# omarchy:summary=Install the Claude extension for Chromium-based browsers
# omarchy:requires-sudo=true
set -euo pipefail
if (( EUID == 0 )); then
export PATH=/usr/bin:/bin
fi
EXTENSION_ID="fcoeoabgfenejglbffodgkkbkcdhcgfn"
EXTENSION_JSON='{ "external_update_url": "https://clients2.google.com/service/update2/crx" }'
PACKAGED_PATH=/usr/bin/omarchy-install-chromium-claude
# Brave and Brave Origin share Chromium's external extension directory.
# Seed all supported browsers, including those installed after choosing Claude.
EXTENSION_DIRS=(
/usr/share/chromium/extensions
/usr/share/google-chrome/extensions
/usr/share/microsoft-edge/extensions
)
installed=true
for dir in "${EXTENSION_DIRS[@]}"; do
if [[ ! -f $dir/$EXTENSION_ID.json ]] || [[ $(cat "$dir/$EXTENSION_ID.json") != "$EXTENSION_JSON" ]]; then
installed=false
fi
done
if [[ $installed == "true" ]]; then
exit 0
fi
if (( EUID == 0 )); then
for dir in "${EXTENSION_DIRS[@]}"; do
printf '%s\n' "$EXTENSION_JSON" | install -D -m 0644 /dev/stdin "$dir/$EXTENSION_ID.json"
done
elif [[ -t 0 ]]; then
exec sudo "$PACKAGED_PATH"
else
exec pkexec "$PACKAGED_PATH"
fi
+4 -31
View File
@@ -12,37 +12,10 @@ if [[ -z $1 ]]; then
fi
install_php() {
omarchy-pkg-add php composer php-sqlite xdebug
mise tool-alias set php github:nunomaduro/static-php-builds
mise use --global php@latest
# Install Path for Composer
if [[ :$PATH: != *:$HOME/.config/composer/vendor/bin:* ]]; then
echo 'export PATH="$HOME/.config/composer/vendor/bin:$PATH"' >>"$HOME/.bashrc"
source "$HOME/.bashrc"
echo "Added Composer global bin directory to PATH."
else
echo "Composer global bin directory already in PATH."
fi
# Enable some extensions
local php_ini_path="/etc/php/php.ini"
local extensions_to_enable=(
"bcmath"
"intl"
"iconv"
"openssl"
"pdo_sqlite"
"pdo_mysql"
)
# Enable Xdebug
sudo sed -i \
-e 's/^;zend_extension=xdebug.so/zend_extension=xdebug.so/' \
-e 's/^;xdebug.mode=debug/xdebug.mode=debug/' \
/etc/php/conf.d/xdebug.ini
for ext in "${extensions_to_enable[@]}"; do
sudo sed -i "s/^;extension=${ext}/extension=${ext}/" "$php_ini_path"
done
mise x php -- composer global config bin-dir "$HOME/.local/bin"
}
install_node() {
@@ -84,7 +57,7 @@ laravel)
echo -e "Installing PHP and Laravel...\n"
install_php
install_node
composer global require laravel/installer
mise x php -- composer global require laravel/installer
echo -e "\nYou can now run: laravel new myproject"
;;
symfony)
+1 -1
View File
@@ -10,7 +10,7 @@ set -e
echo "Installing Xbox controller Bluetooth support..."
# Install xpadneo to ensure controllers work out of the box
omarchy-pkg-add linux-headers xpadneo-dkms
omarchy-pkg-add xpadneo-dkms
# Prevent xpad/xpadneo driver conflict
echo blacklist xpad | sudo tee /etc/modprobe.d/blacklist-xpad.conf >/dev/null
+1 -1
View File
@@ -28,7 +28,7 @@ echo "Installing 1Password extension for Chromium..."
install_chromium_extension
echo "Opening 1Password..."
uwsm-app -- 1password >/dev/null 2>&1 &
setsid uwsm-app -- 1password >/dev/null 2>&1 &
echo ""
echo "1Password has been installed. Restart Chromium to load the browser extension."
+3 -1
View File
@@ -22,7 +22,9 @@ if [[ -z $interface ]]; then
# menu's visibility gate describe. Fall back to the first connected Wi-Fi
# device. nmcli localizes state names, so pin the locale, and the prefix
# match accepts states like "connected (externally)".
route_device=$(ip route get 1.1.1.1 2>/dev/null | awk '{ for (i = 1; i <= NF; i++) if ($i == "dev") { print $(i + 1); exit } }')
if ! route_device=$(ip route get 1.1.1.1 2>/dev/null | awk '{ for (i = 1; i <= NF; i++) if ($i == "dev") { print $(i + 1); exit } }'); then
route_device=""
fi
if [[ -n $route_device && -d /sys/class/net/$route_device/wireless ]]; then
interface=$route_device
else
+8 -1
View File
@@ -10,6 +10,11 @@ if [[ -z $1 ]]; then
fi
remove_php() {
mise uninstall php --all
mise rm -g php
mise tool-alias unset php
# PHP from before it moved to mise
omarchy-pkg-drop php composer php-sqlite xdebug
}
@@ -46,7 +51,9 @@ php)
;;
laravel)
echo -e "Removing Laravel...\n"
composer global remove laravel/installer 2>/dev/null || true
mise x php -- composer global remove laravel/installer 2>/dev/null || true
rm -f "$HOME/.local/bin/laravel" "$HOME/.config/composer/vendor/bin/laravel"
;;
symfony)
echo -e "Removing Symfony CLI...\n"
+14 -1
View File
@@ -21,6 +21,19 @@ if [[ -z $STATE_NAME ]]; then
fi
case "$COMMAND" in
set) touch "$STATE_DIR/$STATE_NAME" ;;
set)
# State names are fixed labels (reboot-required, restart-*-required). The
# name becomes a filename under the state directory. A slash would turn it
# into directory levels, and a bare `.` or `..` would touch the directory
# itself or its parent. Refuse those. Dots inside a name (a..b) are fine;
# once slashes are out, only the whole name being `.` or `..` can leave the
# directory. clear needs no such guard: find -name matches basenames only,
# so a pattern can never walk out of the directory.
if [[ $STATE_NAME == */* || $STATE_NAME == "." || $STATE_NAME == ".." ]]; then
echo "Invalid state name: $STATE_NAME" >&2
exit 2
fi
touch "$STATE_DIR/$STATE_NAME"
;;
clear) find "$STATE_DIR" -maxdepth 1 -type f -name "$STATE_NAME" -delete ;;
esac
+25 -14
View File
@@ -297,19 +297,34 @@ rebuild_next_boot() {
umount "$next$esp_mount"
}
# Both the staged system and the retained baseline must lose the old hashes.
scrub_factory_accounts() {
local root="$1" user users
users=$(awk -F: '$3 >= 1000 && $3 < 60000 { print $1 }' "$root/etc/passwd") || return 1
for user in $users; do
userdel --root "$root" "$user" 2>>"$LOG_FILE" || return 1
rm -rf "${root:?}/home/$user" || return 1
done
# passwd --lock preserves the hash. Replace it, then remove the backups
# that userdel and usermod leave behind.
usermod --root "$root" --password '!' root >>"$LOG_FILE" 2>&1 || return 1
rm -f "$root/etc/"{shadow-,gshadow-,passwd-,group-,subuid-,subgid-}
}
# Remove the seller's account material and machine identity from the retained
# @factory baseline so it can neither be mounted for recovery nor restore the
# seller's account on a future reset. Idempotent (a scrubbed baseline has no
# uid>=1000 accounts left to remove).
sanitize_factory_baseline() {
local factory="$1" user
local factory="$1"
btrfs property set -ts "$factory" ro false
for user in $(awk -F: '$3 >= 1000 && $3 < 60000 { print $1 }' "$factory/etc/passwd"); do
userdel --root "$factory" "$user" 2>>"$LOG_FILE" || true
rm -rf "${factory:?}/home/$user"
done
passwd --root "$factory" --lock root >>"$LOG_FILE" 2>&1 || true
if ! scrub_factory_accounts "$factory"; then
btrfs property set -ts "$factory" ro true
fail "could not remove account credentials from the factory baseline (see $LOG_FILE)"
fi
rm -f "$factory"/etc/ssh/ssh_host_*
rm -f "$factory"/etc/NetworkManager/system-connections/*
rm -rf "$factory"/var/lib/NetworkManager/* "$factory/var/lib/tailscale" "$factory/var/lib/iwd"
@@ -345,17 +360,13 @@ stage_full_reset() {
rm -rf "$next"/var/lib/NetworkManager/* "$next/var/lib/tailscale" "$next/var/lib/iwd"
rm -f "$next/var/lib/sddm/state.conf" "$next/etc/sddm.conf.d/autologin.conf"
# A factory snapshot from a normal (normal) install contains the original
# A factory snapshot from a normal install contains the original
# user account; first-boot setup must start from none. A leftover account
# would keep its password hash and group memberships (including wheel), so
# failure here has to abort the reset, not be shrugged off.
local user
for user in $(awk -F: '$3 >= 1000 && $3 < 60000 { print $1 }' "$next/etc/passwd"); do
log "Removing user $user from the factory system"
userdel --root "$next" "$user" 2>>"$LOG_FILE" ||
fail "could not remove user $user from the factory system (see $LOG_FILE)"
done
passwd --root "$next" --lock root >>"$LOG_FILE" 2>&1 || true
log "Removing account credentials from the factory system"
scrub_factory_accounts "$next" ||
fail "could not remove account credentials from the factory system (see $LOG_FILE)"
# @factory itself survives the wipe as the baseline for future resets. If it
# came from a normal install it still holds the seller's account and
+1
View File
@@ -1,6 +1,7 @@
#!/bin/bash
# omarchy:summary=Update Omarchy and system packages
# omarchy:alias=omarchy up
# omarchy:args=[-y]
# omarchy:examples=omarchy update | omarchy update -y
# omarchy:requires-sudo=true
+9
View File
@@ -3,6 +3,11 @@
# omarchy:summary=Ensure the Omarchy and Arch keyring packages are installed and populated
# omarchy:requires-sudo=true
# omarchy-update runs this under set -e as a trusted pre-step, so a failed recv
# or a broken keyring has to stop this script here, not surface later as
# signature errors in the middle of the main transaction.
set -euo pipefail
if omarchy-pkg-missing omarchy-keyring || ! sudo pacman-key --list-keys 40DFB630FF42BCFFB047046CF0134EE680CAC571 &>/dev/null; then
sudo pacman-key --recv-keys 40DFB630FF42BCFFB047046CF0134EE680CAC571 --keyserver keys.openpgp.org
sudo pacman-key --lsign-key 40DFB630FF42BCFFB047046CF0134EE680CAC571
@@ -19,4 +24,8 @@ fi
# Always reinstall, as the keyring can be updated without a package version bump.
echo -e "\e[32m\nUpdate Arch signing keys\e[0m"
sudo pacman -Sy --noconfirm archlinux-keyring >/dev/null 2> >(grep -vE '^warning: archlinux-keyring-[^ ]+ is up to date -- reinstalling$' >&2)
# Say "correct" only once the key verifiably is: before the failure checks
# above, a failed recv or reinstall still ended here with exit 0.
sudo pacman-key --list-keys 40DFB630FF42BCFFB047046CF0134EE680CAC571 >/dev/null
echo "Keys are correct"
+25 -2
View File
@@ -1457,8 +1457,31 @@ To stop: omarchy-windows-vm stop"
fi
# If scale is less than 130%, don't set any scale (use default 100)
# Connect with RDP in fullscreen (auto-detects resolution)
xfreerdp3 /u:"$WIN_USER" /p:"$WIN_PASS" /v:127.0.0.1:3389 -grab-keyboard /sound /microphone /clipboard /cert:ignore /title:"Windows VM - Omarchy" /dynamic-resolution /gfx:AVC444 /floatbar:sticky:off,default:visible,show:fullscreen $RDP_SCALE
RDP_ARGS=(
"/u:$WIN_USER"
"/p:$WIN_PASS"
/v:127.0.0.1:3389
-grab-keyboard
/sound
/microphone
/clipboard
/cert:ignore
"/title:Windows VM - Omarchy"
/dynamic-resolution
/gfx:AVC444
/floatbar:sticky:off,default:visible,show:fullscreen
)
if [[ -n $RDP_SCALE ]]; then
RDP_ARGS+=("$RDP_SCALE")
fi
# Connect with RDP in fullscreen (auto-detects resolution). The arguments go
# in over stdin rather than on the command line: /proc/<pid>/cmdline is
# world-readable, so passing the VM password as /p:"$WIN_PASS" would show it
# to every other user on the machine for as long as the session is open.
# /args-from must stay the only argument here — FreeRDP rejects it outright
# when it is combined with any other, so new flags belong in RDP_ARGS above.
printf '%s\n' "${RDP_ARGS[@]}" | xfreerdp3 /args-from:stdin
# After RDP closes, stop the container unless --keep-alive was specified
if [[ $KEEP_ALIVE = "false" ]]; then