Compare commits

...

3 Commits

Author SHA1 Message Date
97e4b81930 docs: add moonarch-doctor and shorthand aliases to README and CLAUDE.md
Some checks failed
Update PKGBUILD version / update-pkgver (push) Failing after 3s
2026-04-10 08:21:38 +02:00
b8753bf84f fix: remove docker from defaults, fix cliphist-image ordering cycle
Docker is a dev dependency, not a desktop environment default. Remove
from package list, archinstall config, services and README.

Fix systemd ordering cycle that prevented cliphist-image from starting:
cliphist-text had After=graphical-session.target which combined with
PartOf= and cliphist-image's After=cliphist-text created a cycle.
2026-04-10 08:18:55 +02:00
a55c7ea9d1 feat: add moonarch-doctor system health checker
Diagnostic script that verifies services, configs, packages and paths
against the expected moonarch system state. Reports pass/fail/warn with
colored output and summary. Deployed as moonarch-doctor (alias: moondoc).
2026-04-10 08:18:45 +02:00
8 changed files with 342 additions and 11 deletions

View File

@ -38,6 +38,17 @@ Waybar wird über `moonarch-waybar` gestartet (nicht direkt). Der Wrapper merged
- Benötigt `jq` (in PKGBUILD als Dependency) - Benötigt `jq` (in PKGBUILD als Dependency)
- System-Config muss valides JSON sein (kein JSONC) - System-Config muss valides JSON sein (kein JSONC)
## System Health Check (moonarch-doctor / moondoc)
Diagnose-Script das den Systemzustand gegen moonarch-Defaults prüft:
- Pakete (official.txt + aur.txt installiert? Orphans?)
- System-Services (NetworkManager, bluetooth, greetd, ufw, auto-cpufreq, etc.)
- User-Services (kanshi, stasis, cliphist-text, cliphist-image)
- Config-Dateien (SHA256-Vergleich deployed vs. moonarch-Default)
- Helper-Scripts + Symlinks (moonup, moondoc)
- System-Config (UFW, Pacman/Paru Repos, Default Shell)
- Verzeichnisse + Permissions
## Konventionen ## Konventionen
- Paketlisten sind einfache Textdateien, ein Paket pro Zeile, Kommentare mit `#` - Paketlisten sind einfache Textdateien, ein Paket pro Zeile, Kommentare mit `#`

View File

@ -86,13 +86,23 @@ The script will:
### Update ### Update
```bash ```bash
moonarch-update moonup # or: moonarch-update
``` ```
Interactive updater that upgrades system and AUR packages, reconciles package lists Interactive updater that upgrades system and AUR packages, reconciles package lists
against what's installed, and cleans orphaned packages. Config deployment happens against what's installed, and cleans orphaned packages. Config deployment happens
automatically via the moonarch-git package on `paru -Syu`. automatically via the moonarch-git package on `paru -Syu`.
### Health Check
```bash
moondoc # or: moonarch-doctor
```
Diagnostic tool that verifies the system state against moonarch defaults: services,
configs, packages, helper scripts, firewall, shell and directory permissions. Reports
pass/fail/warn per check with a summary at the end.
## Project Structure ## Project Structure
``` ```
@ -107,7 +117,8 @@ scripts/
lib.sh Shared helpers sourced by all scripts lib.sh Shared helpers sourced by all scripts
post-install.sh Main automation (packages, configs, themes, services) post-install.sh Main automation (packages, configs, themes, services)
transform.sh Convert existing Arch+Wayland system to Moonarch transform.sh Convert existing Arch+Wayland system to Moonarch
moonarch-update Interactive updater (deployed to /usr/bin/ by package) moonarch-update Interactive updater (deployed to /usr/bin/ as moonup)
moonarch-doctor System health checker (deployed to /usr/bin/ as moondoc)
defaults/ defaults/
xdg/ System-wide XDG configs (deployed to /etc/xdg/) xdg/ System-wide XDG configs (deployed to /etc/xdg/)
@ -213,7 +224,6 @@ are part of the system and updated via `paru -Syu`.
| greetd | Login greeter (runs moongreet inside Niri) | | greetd | Login greeter (runs moongreet inside Niri) |
| NetworkManager | Network management (WiFi, VPN, Ethernet) | | NetworkManager | Network management (WiFi, VPN, Ethernet) |
| bluetooth | Bluetooth stack (bluez) | | bluetooth | Bluetooth stack (bluez) |
| docker | Container runtime |
| systemd-timesyncd | NTP time synchronization | | systemd-timesyncd | NTP time synchronization |
| ufw | Firewall (deny incoming, allow outgoing) | | ufw | Firewall (deny incoming, allow outgoing) |
| auto-cpufreq | CPU frequency scaling (AC: performance, battery: powersave) | | auto-cpufreq | CPU frequency scaling (AC: performance, battery: powersave) |

View File

@ -43,8 +43,6 @@
"pipewire-jack", "pipewire-jack",
"pipewire-pulse", "pipewire-pulse",
"wireplumber", "wireplumber",
"docker",
"docker-compose",
"fwupd", "fwupd",
"ufw", "ufw",
"greetd", "greetd",
@ -68,7 +66,6 @@
"services": [ "services": [
"NetworkManager", "NetworkManager",
"bluetooth", "bluetooth",
"docker",
"greetd", "greetd",
"systemd-timesyncd", "systemd-timesyncd",
"ufw" "ufw"

View File

@ -4,7 +4,6 @@
[Unit] [Unit]
Description=Clipboard history manager (text) Description=Clipboard history manager (text)
PartOf=graphical-session.target PartOf=graphical-session.target
After=graphical-session.target
[Service] [Service]
Type=simple Type=simple

View File

@ -98,8 +98,6 @@ npm
rustup rustup
# System # System
docker
docker-compose
fwupd fwupd
plocate plocate
rebuild-detector rebuild-detector

318
scripts/moonarch-doctor Executable file
View File

@ -0,0 +1,318 @@
#!/bin/bash
# ABOUTME: Moonarch system health checker — verifies services, configs, packages and paths.
# ABOUTME: Shipped as /usr/bin/moonarch-doctor (alias: moondoc) by the moonarch-git package.
set -uo pipefail
# --- Output helpers ---
PASS=0
FAIL=0
WARN=0
pass() {
echo -e " \e[1;32m✓\e[0m $*"
((PASS++))
}
fail() {
echo -e " \e[1;31m✗\e[0m $*"
((FAIL++))
}
warn() {
echo -e " \e[1;33m⚠\e[0m $*"
((WARN++))
}
section() {
echo
echo -e "\e[1;34m[$1]\e[0m"
}
# --- Check functions ---
check_system_service() {
local svc="$1"
local type
type=$(systemctl show "$svc" --property=Type 2>/dev/null | cut -d= -f2)
if systemctl is-enabled "$svc" &>/dev/null; then
if systemctl is-active "$svc" &>/dev/null; then
pass "$svc (enabled, active)"
elif [[ "$type" == "oneshot" ]]; then
# Oneshot services are inactive after completion — check if they succeeded
local result
result=$(systemctl show "$svc" --property=Result 2>/dev/null | cut -d= -f2)
if [[ "$result" == "success" ]]; then
pass "$svc (enabled, oneshot completed)"
else
fail "$svc (enabled, oneshot failed: $result)"
fi
else
fail "$svc (enabled, NOT active)"
fi
else
fail "$svc (NOT enabled)"
fi
}
check_user_service() {
local svc="$1"
if systemctl --user is-enabled "$svc" &>/dev/null; then
if systemctl --user is-active "$svc" &>/dev/null; then
pass "$svc (enabled, active)"
else
# User services may be inactive if not in a graphical session
warn "$svc (enabled, not active — may need graphical session)"
fi
else
fail "$svc (NOT enabled)"
fi
}
check_config_match() {
local deployed="$1"
local source="$2"
local label="${deployed}"
if [[ ! -f "$deployed" ]]; then
fail "$label (missing)"
return
fi
if [[ ! -f "$source" ]]; then
warn "$label (exists, but no source to compare at $source)"
return
fi
local hash_deployed hash_source
hash_deployed=$(sha256sum "$deployed" | cut -d' ' -f1)
hash_source=$(sha256sum "$source" | cut -d' ' -f1)
if [[ "$hash_deployed" == "$hash_source" ]]; then
pass "$label"
else
warn "$label (differs from moonarch default)"
fi
}
# --- Header ---
echo -e "\e[1;34m"
echo " Moonarch Doctor"
echo -e "\e[0m"
# --- 1. Packages ---
section "Packages"
OFFICIAL="/usr/share/moonarch/official.txt"
AUR="/usr/share/moonarch/aur.txt"
if [[ -f "$OFFICIAL" ]]; then
INSTALLED=$(pacman -Qq 2>/dev/null)
MISSING_OFFICIAL=()
while IFS= read -r pkg; do
[[ "$pkg" =~ ^[[:space:]]*# ]] && continue
[[ -z "${pkg// }" ]] && continue
if ! echo "$INSTALLED" | grep -qx "$pkg"; then
MISSING_OFFICIAL+=("$pkg")
fi
done < "$OFFICIAL"
if [[ ${#MISSING_OFFICIAL[@]} -eq 0 ]]; then
pass "All official packages installed"
else
fail "Missing official packages: ${MISSING_OFFICIAL[*]}"
fi
else
warn "$OFFICIAL not found (moonarch-git not installed?)"
fi
if [[ -f "$AUR" ]]; then
MISSING_AUR=()
while IFS= read -r pkg; do
[[ "$pkg" =~ ^[[:space:]]*# ]] && continue
[[ -z "${pkg// }" ]] && continue
if ! echo "$INSTALLED" | grep -qx "$pkg"; then
MISSING_AUR+=("$pkg")
fi
done < "$AUR"
if [[ ${#MISSING_AUR[@]} -eq 0 ]]; then
pass "All AUR packages installed"
else
fail "Missing AUR packages: ${MISSING_AUR[*]}"
fi
else
warn "$AUR not found (moonarch-git not installed?)"
fi
ORPHANS=$(pacman -Qdtq 2>/dev/null || true)
if [[ -z "$ORPHANS" ]]; then
pass "No orphaned packages"
else
ORPHAN_COUNT=$(echo "$ORPHANS" | wc -l)
warn "$ORPHAN_COUNT orphaned package(s) (run moonup to clean)"
fi
# --- 2. System Services ---
section "System Services"
for svc in NetworkManager bluetooth greetd systemd-timesyncd ufw auto-cpufreq; do
check_system_service "$svc"
done
# Battery conservation service (laptop only)
if [[ -f /sys/class/power_supply/BAT0/charge_control_end_threshold ]]; then
check_system_service moonarch-batsaver
else
pass "moonarch-batsaver (skipped — no battery threshold support)"
fi
# --- 3. User Services ---
section "User Services"
if [[ $EUID -eq 0 ]]; then
warn "Running as root — skipping user service checks"
else
for svc in kanshi stasis cliphist-text cliphist-image; do
check_user_service "$svc"
done
fi
# --- 4. Config Files ---
section "Config Files"
SRC="/usr/share/moonarch"
check_config_match "/etc/xdg/foot/foot.ini" "$SRC/foot/foot.ini"
check_config_match "/etc/xdg/waybar/style.css" "$SRC/waybar/style.css"
check_config_match "/etc/xdg/swaync/config.json" "$SRC/swaync/config.json"
check_config_match "/etc/xdg/swaync/style.css" "$SRC/swaync/style.css"
check_config_match "/etc/greetd/config.toml" "$SRC/greetd/config.toml"
check_config_match "/etc/greetd/niri-greeter.kdl" "$SRC/greetd/niri-greeter.kdl"
check_config_match "/etc/moongreet/moongreet.toml" "$SRC/moongreet/moongreet.toml"
if [[ -f /etc/zsh/zshrc.moonarch ]]; then
pass "/etc/zsh/zshrc.moonarch"
else
fail "/etc/zsh/zshrc.moonarch (missing)"
fi
# --- 5. Helper Scripts ---
section "Helper Scripts"
EXPECTED_SCRIPTS=(
moonarch-batsaver-toggle
moonarch-btnote
moonarch-capsnote
moonarch-cpugov
moonarch-doctor
moonarch-nightlight
moonarch-sink-switcher
moonarch-update
moonarch-vpn
moonarch-waybar
moonarch-waybar-batsaver
moonarch-waybar-cpugov
moonarch-waybar-gpustat
moonarch-waybar-hidpp
moonarch-waybar-nightlight
moonarch-waybar-updates
)
MISSING_SCRIPTS=()
for script in "${EXPECTED_SCRIPTS[@]}"; do
if [[ ! -x "/usr/bin/$script" ]]; then
MISSING_SCRIPTS+=("$script")
fi
done
if [[ ${#MISSING_SCRIPTS[@]} -eq 0 ]]; then
pass "All ${#EXPECTED_SCRIPTS[@]} helper scripts present"
else
fail "Missing scripts: ${MISSING_SCRIPTS[*]}"
fi
# Symlinks
for link in moonup moondoc; do
if [[ -L "/usr/bin/$link" ]]; then
pass "$link symlink"
else
fail "$link symlink (missing)"
fi
done
# --- 6. System Config ---
section "System Config"
# UFW (check via systemd, no sudo needed)
if command -v ufw &>/dev/null; then
if systemctl is-active ufw &>/dev/null; then
pass "UFW active"
else
fail "UFW not active"
fi
else
fail "UFW not installed"
fi
# Pacman moonarch repo
if grep -q '^\[moonarch\]' /etc/pacman.conf 2>/dev/null; then
pass "Pacman [moonarch] repo configured"
else
fail "Pacman [moonarch] repo missing from /etc/pacman.conf"
fi
# Paru PKGBUILD repo
if grep -q '\[moonarch-pkgbuilds\]' /etc/paru.conf 2>/dev/null; then
pass "Paru [moonarch-pkgbuilds] repo configured"
else
fail "Paru [moonarch-pkgbuilds] repo missing from /etc/paru.conf"
fi
# Default shell
USER_SHELL=$(getent passwd "$USER" | cut -d: -f7)
if [[ "$USER_SHELL" == */zsh ]]; then
pass "Default shell: zsh"
else
warn "Default shell: $USER_SHELL (expected zsh)"
fi
# --- 7. Directories ---
section "Directories"
if [[ -d /var/lib/moonarch ]]; then
DIR_PERMS=$(stat -c '%a' /var/lib/moonarch)
DIR_GROUP=$(stat -c '%G' /var/lib/moonarch)
if [[ "$DIR_GROUP" == "wheel" ]]; then
pass "/var/lib/moonarch/ (group: wheel, mode: $DIR_PERMS)"
else
warn "/var/lib/moonarch/ (group: $DIR_GROUP, expected wheel)"
fi
else
warn "/var/lib/moonarch/ missing (created on first battery toggle)"
fi
if [[ -d /usr/share/moonarch ]]; then
pass "/usr/share/moonarch/"
else
fail "/usr/share/moonarch/ missing (moonarch-git not installed?)"
fi
# --- Summary ---
echo
TOTAL=$((PASS + FAIL + WARN))
echo -e "\e[1;34m[Summary]\e[0m $TOTAL checks: \e[1;32m$PASS passed\e[0m, \e[1;31m$FAIL failed\e[0m, \e[1;33m$WARN warnings\e[0m"
if [[ $FAIL -gt 0 ]]; then
exit 1
fi

View File

@ -144,7 +144,6 @@ log "Enabling services..."
SERVICES=( SERVICES=(
"NetworkManager" "NetworkManager"
"bluetooth" "bluetooth"
"docker"
"greetd" "greetd"
"systemd-timesyncd" "systemd-timesyncd"
"ufw" "ufw"

View File

@ -346,7 +346,6 @@ log "Enabling services..."
SERVICES=( SERVICES=(
"NetworkManager" "NetworkManager"
"bluetooth" "bluetooth"
"docker"
"greetd" "greetd"
"systemd-timesyncd" "systemd-timesyncd"
"ufw" "ufw"