diff --git a/README.md b/README.md index bccebb9..98f3813 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ git clone https://github.com/Furyfree/niriland.git ~/.local/share/niriland ~/.local/share/niriland/install ``` -Post-install note: after your first successful login into Niri, reboot one more time. Some systems do not start all user-session autostarts/services (`niriusd`, `1Password`) until the second boot. JetBrains Toolbox remains installed but does not start automatically. +Post-install note: after your first successful login into Niri, reboot one more time. Some systems do not start all user-session autostarts/services (`niriusd`, `1Password`) until the second boot. ## Requirements @@ -38,14 +38,14 @@ Post-install note: after your first successful login into Niri, reboot one more ## What It Does -After you install CachyOS by following [CACHYOS_INSTALL.md](CACHYOS_INSTALL.md), Niriland installs the extra packages, configs, and tools used by this setup. It deploys Niri, DMS, Ghostty, and Zsh configs; sets up theming; installs Brave Origin and Zen Browser; configures dev tools like Docker, mise, Neovim/LazyVim, VSCodium, and Zed; and installs optional helper scripts for AI, gaming, VMs, fingerprint auth, and more. +After you install CachyOS by following [CACHYOS_INSTALL.md](CACHYOS_INSTALL.md), Niriland installs the shared workstation baseline. It deploys Niri, DMS, Ghostty, and Zsh configs; sets up theming; installs Brave Origin and Prism Launcher; configures Docker, user-local Mise, Neovim/LazyVim, VSCodium, and Zed; and installs optional helper scripts for gaming, AI, VMs, fingerprint auth, and more. For known issues and operational fixes, see [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md). For one-time migration steps on older setups, see [docs/MIGRATIONS.md](docs/MIGRATIONS.md). For repo-local unfinished work, see [docs/ROADMAP.md](docs/ROADMAP.md). For the expected fresh-install baseline for the default Niriland flow, see [CACHYOS_INSTALL.md](CACHYOS_INSTALL.md). -Current gaming recommendation in this setup: use `Lutris` as the unified launcher for `Steam` and `Battle.net`, and use `Heroic` for `Epic Games`. +Prism Launcher is part of the shared baseline. The full gaming stack is opt-in through `niriland-setup-gaming`; it uses Lutris for Steam and Battle.net workflows and Heroic for Epic Games. ## Who It Is For @@ -69,6 +69,8 @@ Current gaming recommendation in this setup: use `Lutris` as the unified launche - The repo must live at `~/.local/share/niriland`. - Shared tracked config is loaded from the repo. - Machine-local changes belong outside the tracked tree. +- The default package manifests describe the shared workstation baseline. +- `packages/gaming.packages` is optional and is never read by the normal installer or updater. - The deployed Niri config layers repo config first, DMS-managed includes second, and user overrides last. Use these override locations for local customization: @@ -118,20 +120,23 @@ Current update behavior: - requires a clean git worktree - runs `git pull --ff-only` - runs a full package upgrade through `niriland-pkg upgrade` -- replays selected install steps +- replays selected shared-baseline install steps - preserves existing local config during `20-deploy-configs` +- does not install or remove the optional gaming profile ## Repository Layout - `bootstrap` — clone/update repo and run installer - `install` — installer orchestrator +- `cleanup` — plan-first, staged cleanup of retired application data and rebuildable caches - `scripts/install/lib/common` — shared installer helpers - `scripts/install/steps/` — numbered install steps - `scripts/tools/` — helper scripts copied to `~/.local/bin/niriland` - `configs/base/` — files deployed to `$HOME` - `configs/modules/` — modular shared config fragments (Niri/Zsh/Ghostty) - `configs/system/` — system-level assets used by steps/tools -- `packages/*.packages` — package manifests +- `packages/base.packages`, `aur.packages`, `cachyos.packages`, and `chaotic.packages` — shared package manifests +- `packages/gaming.packages` — optional full gaming profile used only by `niriland-setup-gaming` - `packages/vscodium.extensions` — VSCodium extension list ## Helper Tools @@ -147,7 +152,7 @@ Main tools: Optional follow-up helpers: - AI -- gaming +- gaming (`niriland-setup-gaming`; explicit per-machine opt-in) - WoW - Helix - Helium browser compatibility, including Widevine @@ -155,6 +160,22 @@ Optional follow-up helpers: - fingerprint auth - virtualization +## Post-baseline Cleanup + +The root-level `cleanup` script inventories data left by applications and +development runtimes removed from the shared baseline. It also reports +rebuildable Pacman, uv, npm, AUR-helper, and Nix caches. Plan mode is read-only: + +```bash +./cleanup plan +``` + +Run `./cleanup apply` only after the common-baseline package migration has +completed. Application data, Flutter/Android data, and caches use separate +typed confirmations. Docker pruning is excluded unless `--docker` is passed, +and Docker volumes, projects, documents, gaming data, Wine prefixes, and +snapshots are never selected. + ## License [GNU Affero General Public License v3](LICENSE) diff --git a/cleanup b/cleanup new file mode 100755 index 0000000..926530d --- /dev/null +++ b/cleanup @@ -0,0 +1,704 @@ +#!/usr/bin/env bash + +set -euo pipefail + +STATE_ROOT="$HOME/.local/state/niriland/cleanup" + +MODE="plan" +CLEAN_USERDATA=true +CLEAN_RUNTIMES=true +CLEAN_CACHES=true +INCLUDE_DOCKER=false + +declare -a APP_USER_PATHS=() +declare -a APP_SYSTEM_PATHS=() +declare -a RUNTIME_PATHS=() +declare -a CACHE_PATHS=() +declare -a SHELL_CONFIG_PATHS=() +declare -a RETIRED_PACKAGES=( + alacritty + chromium + drawio-desktop + gimp + glances + helix + httpie + imv + jetbrains-toolbox + kdenlive + micro + ollama + opencode-desktop-bin + shelly + showtime + solaar + teams-for-linux + vlc-plugins-all + yazi + zen-browser-bin +) + +log() { + printf '==> %s\n' "$*" +} + +warn() { + printf 'WARNING: %s\n' "$*" >&2 +} + +die() { + printf 'ERROR: %s\n' "$*" >&2 + exit 1 +} + +usage() { + cat <<'EOF' +Usage: ./cleanup [plan|apply] [options] + +One-time post-baseline cleanup for rebuildable caches and data belonging to +applications and development runtimes removed from the shared workstation. +Plan is the default and never changes the system. + +Options: + --no-userdata Skip retired application data and stale launchers/config + --no-runtimes Skip Flutter, Android SDK, Android Studio, Gradle, and Dart data + --no-caches Skip Pacman, uv, npm, AUR-helper, and Nix cache cleanup + --docker Include stopped containers and unused Docker images/networks; + Docker volumes are always preserved + -h, --help Show this help + +Apply is deliberately staged. Each selected destructive stage requires its own +typed confirmation. The script records a path/size and package inventory under +~/.local/state/niriland/cleanup/ before deleting anything. + +This script never removes projects, documents, Minecraft or gaming data, Wine +prefixes, Steam libraries, Docker volumes, generic OpenCode state, or snapshots. +EOF +} + +parse_args() { + if [[ $# -gt 0 && "$1" != -* ]]; then + MODE="$1" + shift + fi + + case "$MODE" in + plan|apply) + ;; + help) + usage + exit 0 + ;; + *) + usage >&2 + die "Unknown mode: $MODE" + ;; + esac + + while [[ $# -gt 0 ]]; do + case "$1" in + --no-userdata) + CLEAN_USERDATA=false + ;; + --no-runtimes) + CLEAN_RUNTIMES=false + ;; + --no-caches) + CLEAN_CACHES=false + ;; + --docker) + INCLUDE_DOCKER=true + ;; + -h|--help) + usage + exit 0 + ;; + *) + usage >&2 + die "Unknown option: $1" + ;; + esac + shift + done +} + +build_path_lists() { + shopt -s nullglob + + APP_USER_PATHS=( + "$HOME/.cache/JetBrains" + "$HOME/.config/JetBrains" + "$HOME/.local/share/JetBrains" + "$HOME/.local/state/JetBrains" + "$HOME/.config/helix" + "$HOME/.cache/helix" + "$HOME/.local/share/helix" + "$HOME/.local/state/helix" + "$HOME/.config/teams-for-linux" + "$HOME/.cache/teams-for-linux" + "$HOME/.local/share/teams-for-linux" + "$HOME/.zen" + "$HOME/.config/zen" + "$HOME/.cache/zen" + "$HOME/.local/share/zen" + "$HOME/.config/GIMP" + "$HOME/.cache/gimp" + "$HOME/.config/alacritty" + "$HOME/.cache/alacritty" + "$HOME/.local/share/alacritty" + "$HOME/.config/chromium" + "$HOME/.cache/chromium" + "$HOME/.config/micro" + "$HOME/.cache/micro" + "$HOME/.config/yazi" + "$HOME/.cache/yazi" + "$HOME/.local/share/yazi" + "$HOME/.local/state/yazi" + "$HOME/.config/kdenlive" + "$HOME/.config/kdenliverc" + "$HOME/.local/share/kdenlive" + "$HOME/.local/state/kdenlivestaterc" + "$HOME/.cache/kdenlive" + "$HOME/.config/vlc" + "$HOME/.cache/vlc" + "$HOME/.local/share/vlc" + "$HOME/.config/draw.io" + "$HOME/.cache/draw.io" + "$HOME/.config/drawio" + "$HOME/.cache/drawio" + "$HOME/.config/imv" + "$HOME/.cache/imv" + "$HOME/.config/glances" + "$HOME/.local/share/glances" + "$HOME/.config/httpie" + "$HOME/.cache/httpie" + "$HOME/.config/solaar" + "$HOME/.cache/solaar" + "$HOME/.config/shelly" + "$HOME/.cache/Shelly" + "$HOME/.local/share/Shelly" + "$HOME/.local/state/showtime" + "$HOME/.ollama" + "$HOME/.cache/ollama" + "$HOME/.config/ai.opencode.desktop" + "$HOME/.cache/ai.opencode.desktop" + "$HOME/.local/share/ai.opencode.desktop" + "$HOME/.local/state/ai.opencode.desktop" + "$HOME/.config/autostart/jetbrains-toolbox.desktop" + "$HOME/.local/share/applications/OpenWebUI.desktop" + "$HOME/.local/share/icons/OpenWebUI.png" + "$HOME"/.local/share/applications/jetbrains-*.desktop + "$HOME/.local/share/applications/jetbrainsd.desktop" + ) + + APP_SYSTEM_PATHS=( + /var/lib/ollama + ) + + RUNTIME_PATHS=( + "$HOME/develop/flutter" + "$HOME/Android/Sdk" + "$HOME/.pub-cache" + "$HOME/.gradle" + "$HOME/.android" + "$HOME/.dart-tool" + "$HOME/.flutter" + "$HOME/.config/flutter" + "$HOME"/.cache/Google/AndroidStudio* + "$HOME"/.config/Google/AndroidStudio* + "$HOME"/.local/share/Google/AndroidStudio* + "$HOME"/.local/state/Google/AndroidStudio* + ) + + CACHE_PATHS=( + "$HOME/.cache/yay" + "$HOME/.cache/paru" + ) + + SHELL_CONFIG_PATHS=( + "$HOME/.zshenv" + "$HOME/.zprofile" + "$HOME/.config/zsh/.zprofile" + ) + + shopt -u nullglob +} + +path_exists() { + [[ -e "$1" || -L "$1" ]] +} + +path_size_bytes() { + local output + + output="$(du -sB1 -- "$1" 2>/dev/null || true)" + awk 'END { print $1 + 0 }' <<<"$output" +} + +human_bytes() { + numfmt --to=iec-i --suffix=B "${1:-0}" 2>/dev/null || printf '%s B' "${1:-0}" +} + +print_path_group() { + local title="$1" + shift + local total=0 + local size=0 + local count=0 + local path + + printf '\n%s:\n' "$title" + for path in "$@"; do + path_exists "$path" || continue + size="$(path_size_bytes "$path" || printf '0')" + printf ' %8s %s\n' "$(human_bytes "$size")" "$path" + total=$((total + size)) + count=$((count + 1)) + done + + if ((count == 0)); then + printf ' (none)\n' + else + printf ' Total: %s across %d paths\n' "$(human_bytes "$total")" "$count" + fi +} + +print_installed_blockers() { + local package_name + local -a installed=() + + for package_name in "${RETIRED_PACKAGES[@]}"; do + if pacman -Qq "$package_name" >/dev/null 2>&1; then + installed+=("$package_name") + fi + done + + printf '\nRetired application packages still installed:\n' + if [[ ${#installed[@]} -eq 0 ]]; then + printf ' (none)\n' + else + printf ' %s\n' "${installed[@]}" + printf ' Apply will refuse retired application-data cleanup until these leave.\n' + fi +} + +print_stale_config() { + local file + local found=false + + printf '\nStale shell and MIME references:\n' + for file in "${SHELL_CONFIG_PATHS[@]}"; do + [[ -f "$file" ]] || continue + if grep -Eq 'develop/flutter/bin|\.local/share/JetBrains/Toolbox/scripts' "$file"; then + printf ' %s\n' "$file" + found=true + fi + done + + file="$HOME/.config/mimeapps.list" + if [[ -f "$file" ]] && grep -Eq '^x-scheme-handler/(jetbrains|air)=' "$file"; then + printf ' %s (JetBrains URI handlers)\n' "$file" + found=true + fi + + file="$HOME/.config/environment.d/90-dms.conf" + if [[ -f "$file" ]] && grep -Eq 'develop/flutter|JetBrains/Toolbox' "$file"; then + printf ' %s (baseline migration must replace this file)\n' "$file" + found=true + fi + + if [[ "$found" == "false" ]]; then + printf ' (none)\n' + fi +} + +print_cache_plan() { + local path + local summary + local dead_paths + + printf '\nRebuildable caches and stores:\n' + for path in /var/cache/pacman/pkg "$HOME/.cache/uv" "$HOME/.npm" /nix/store; do + if path_exists "$path"; then + printf ' %8s %s\n' "$(human_bytes "$(path_size_bytes "$path" || printf '0')")" "$path" + fi + done + for path in "${CACHE_PATHS[@]}"; do + if path_exists "$path"; then + printf ' %8s %s\n' "$(human_bytes "$(path_size_bytes "$path" || printf '0')")" "$path" + fi + done + + printf ' Pacman keeps two installed versions and removes cached uninstalled packages.\n' + printf ' uv, npm, Yay, and Paru caches are rebuildable; Nix garbage collection removes dead store paths.\n' + + if command -v paccache >/dev/null 2>&1; then + summary="$(paccache -d -k2 2>/dev/null | tail -n 1 || true)" + [[ -n "$summary" ]] && printf ' Pacman installed-package preview: %s\n' "$summary" + summary="$(paccache -d -u -k0 2>/dev/null | tail -n 1 || true)" + [[ -n "$summary" ]] && printf ' Pacman uninstalled-package preview: %s\n' "$summary" + fi + + if command -v nix-store >/dev/null 2>&1; then + dead_paths="$(nix-store --gc --print-dead 2>/dev/null | wc -l || true)" + if [[ -n "$dead_paths" ]]; then + printf ' Nix currently reports %s dead store paths.\n' "$dead_paths" + else + warn "Could not inspect dead Nix store paths." + fi + fi +} + +print_docker_plan() { + printf '\nDocker state:\n' + if ! command -v docker >/dev/null 2>&1; then + printf ' Docker is unavailable.\n' + return + fi + + docker system df 2>/dev/null || warn "Could not inspect Docker state." + if [[ "$INCLUDE_DOCKER" == "true" ]]; then + printf ' Selected: prune stopped containers and unused images/networks/build cache.\n' + printf ' Docker volumes remain protected.\n' + else + printf ' Analysis only. Pass --docker to select pruning; volumes are never removed.\n' + fi +} + +show_plan() { + log "Cleanup mode: $MODE" + if [[ "$MODE" == "plan" ]]; then + log "This command does not change files, packages, caches, or Docker state." + else + log "Previewing the selected stages before any confirmation or mutation." + fi + + if [[ "$CLEAN_USERDATA" == "true" ]]; then + print_installed_blockers + print_path_group "Retired application user data" "${APP_USER_PATHS[@]}" + print_path_group "Retired application system data" "${APP_SYSTEM_PATHS[@]}" + print_stale_config + fi + if [[ "$CLEAN_RUNTIMES" == "true" ]]; then + print_path_group "Retired Flutter and Android development data" "${RUNTIME_PATHS[@]}" + fi + if [[ "$CLEAN_CACHES" == "true" ]]; then + print_cache_plan + fi + print_docker_plan + + if [[ "$MODE" == "plan" ]]; then + printf '\nPlan only. No system or user state was changed.\n' + fi +} + +validate_user_target() { + local target="$1" + + [[ -n "$target" && "$target" != "$HOME" ]] || die "Refusing unsafe user target: $target" + case "$target" in + "$HOME"/.*|"$HOME/develop/flutter"|"$HOME/Android/Sdk") + ;; + *) + die "Refusing user target outside the approved cleanup paths: $target" + ;; + esac +} + +assert_application_packages_removed() { + local package_name + local -a installed=() + + for package_name in "${RETIRED_PACKAGES[@]}"; do + if pacman -Qq "$package_name" >/dev/null 2>&1; then + installed+=("$package_name") + fi + done + + if [[ ${#installed[@]} -gt 0 ]]; then + printf 'Still installed:\n %s\n' "${installed[@]}" >&2 + die "Run and validate the common-baseline package migration before deleting retired application data." + fi + + if [[ -f "$HOME/.config/environment.d/90-dms.conf" ]] \ + && grep -Eq 'develop/flutter|JetBrains/Toolbox' "$HOME/.config/environment.d/90-dms.conf"; then + die "The graphical environment still contains stale Flutter or JetBrains paths; finish the baseline migration first." + fi +} + +confirm_stage() { + local phrase="$1" + local answer + + [[ -r /dev/tty ]] || die "Apply requires an interactive terminal." + printf '\nType %s to run this stage: ' "$phrase" >/dev/tty + read -r answer >"$output_file" + done +} + +backup_file() { + local inventory_root="$1" + local source_path="$2" + local relative_path + local destination + + [[ -f "$source_path" || -L "$source_path" ]] || return 0 + relative_path="${source_path#$HOME/}" + destination="$inventory_root/home/$relative_path" + mkdir -p "$(dirname "$destination")" + cp -a -- "$source_path" "$destination" +} + +create_inventory() { + local timestamp + local inventory_root + local file + + timestamp="$(date +%Y%m%d%H%M%S)" + inventory_root="$STATE_ROOT/$timestamp" + mkdir -p "$inventory_root" + + pacman -Qq >"$inventory_root/pacman-all.txt" + pacman -Qqe >"$inventory_root/pacman-explicit.txt" + : >"$inventory_root/cleanup-paths.tsv" + record_path_group "$inventory_root/cleanup-paths.tsv" "${APP_USER_PATHS[@]}" + record_path_group "$inventory_root/cleanup-paths.tsv" "${APP_SYSTEM_PATHS[@]}" + record_path_group "$inventory_root/cleanup-paths.tsv" "${RUNTIME_PATHS[@]}" + record_path_group "$inventory_root/cleanup-paths.tsv" "${CACHE_PATHS[@]}" + record_path_group "$inventory_root/cleanup-paths.tsv" \ + /var/cache/pacman/pkg "$HOME/.cache/uv" "$HOME/.npm" /nix/store + + for file in "${SHELL_CONFIG_PATHS[@]}" "$HOME/.config/mimeapps.list" "$HOME/.config/environment.d/90-dms.conf"; do + backup_file "$inventory_root" "$file" + done + + if command -v docker >/dev/null 2>&1; then + docker system df >"$inventory_root/docker-system-df.txt" 2>&1 || true + docker ps -a --no-trunc >"$inventory_root/docker-containers.txt" 2>&1 || true + docker image ls --no-trunc >"$inventory_root/docker-images.txt" 2>&1 || true + docker volume ls >"$inventory_root/docker-volumes.txt" 2>&1 || true + fi + + printf '%s\n' "$inventory_root" +} + +filter_stale_shell_paths() { + local file="$1" + local temporary + + [[ -f "$file" ]] || return 0 + if [[ -L "$file" ]]; then + warn "Shell config is a symbolic link and requires manual cleanup: $file" + return 0 + fi + temporary="$(mktemp)" + awk -v home="$HOME" ' + $0 == "export PATH=\"$HOME/develop/flutter/bin:$PATH\"" { next } + $0 == " \"$HOME/develop/flutter/bin\"" { next } + $0 == "# Added by Toolbox App" { next } + $0 == "export PATH=\"$PATH:" home "/.local/share/JetBrains/Toolbox/scripts\"" { next } + { print } + ' "$file" >"$temporary" + chmod --reference="$file" "$temporary" + mv -f -- "$temporary" "$file" +} + +filter_stale_mime_handlers() { + local file="$HOME/.config/mimeapps.list" + local temporary + + [[ -f "$file" ]] || return 0 + if [[ -L "$file" ]]; then + warn "MIME config is a symbolic link and requires manual cleanup: $file" + return 0 + fi + temporary="$(mktemp)" + awk '!/^x-scheme-handler\/(jetbrains|air)=/' "$file" >"$temporary" + chmod --reference="$file" "$temporary" + mv -f -- "$temporary" "$file" +} + +remove_user_path_group() { + local path + + for path in "$@"; do + path_exists "$path" || continue + validate_user_target "$path" + rm -rf -- "$path" + done +} + +stop_ollama_before_data_removal() { + sudo systemctl stop ollama.service >/dev/null 2>&1 || true + + if systemctl is-active --quiet ollama.service 2>/dev/null; then + die "Ollama service is still active; refusing to remove /var/lib/ollama." + fi + + command -v pgrep >/dev/null 2>&1 || die "pgrep is required to verify that Ollama is stopped." + if pgrep -x ollama >/dev/null 2>&1; then + die "An Ollama process is still running; stop it before removing /var/lib/ollama." + fi +} + +clean_application_data() { + local file + local path + + assert_application_packages_removed + if path_exists /var/lib/ollama || path_exists "$HOME/.ollama"; then + stop_ollama_before_data_removal + fi + remove_user_path_group "${APP_USER_PATHS[@]}" + + for path in "${APP_SYSTEM_PATHS[@]}"; do + path_exists "$path" || continue + [[ "$path" == "/var/lib/ollama" ]] || die "Refusing unknown system target: $path" + sudo rm -rf -- "$path" + done + + for file in "${SHELL_CONFIG_PATHS[@]}"; do + filter_stale_shell_paths "$file" + done + filter_stale_mime_handlers + + if command -v update-desktop-database >/dev/null 2>&1; then + update-desktop-database "$HOME/.local/share/applications" >/dev/null 2>&1 || \ + warn "Could not refresh the user desktop-entry database." + fi +} + +clean_runtime_data() { + remove_user_path_group "${RUNTIME_PATHS[@]}" +} + +clean_rebuildable_caches() { + local uv_bin="" + local npm_bin="" + + if command -v paccache >/dev/null 2>&1; then + sudo paccache -rk2 + sudo paccache -ruk0 + else + warn "paccache is unavailable; Pacman cache was not cleaned." + fi + + if [[ -x "$HOME/.local/share/mise/shims/uv" ]]; then + uv_bin="$HOME/.local/share/mise/shims/uv" + elif command -v uv >/dev/null 2>&1; then + uv_bin="$(command -v uv)" + fi + if [[ -n "$uv_bin" ]]; then + "$uv_bin" cache clean + else + warn "uv is unavailable; uv cache was not cleaned." + fi + + if [[ -x "$HOME/.local/share/mise/shims/npm" ]]; then + npm_bin="$HOME/.local/share/mise/shims/npm" + elif command -v npm >/dev/null 2>&1; then + npm_bin="$(command -v npm)" + fi + if [[ -n "$npm_bin" ]]; then + "$npm_bin" cache clean --force + else + warn "npm is unavailable; npm cache was not cleaned." + fi + + remove_user_path_group "${CACHE_PATHS[@]}" + + if command -v nix-store >/dev/null 2>&1; then + sudo nix-store --gc + else + warn "nix-store is unavailable; Nix garbage collection was skipped." + fi +} + +clean_docker_data() { + command -v docker >/dev/null 2>&1 || { + warn "Docker is unavailable; Docker cleanup was skipped." + return 0 + } + docker system prune --all +} + +apply_cleanup() { + local inventory_root + + command -v pacman >/dev/null 2>&1 || die "pacman is required." + command -v numfmt >/dev/null 2>&1 || die "numfmt is required." + command -v sudo >/dev/null 2>&1 || die "sudo is required." + + show_plan + inventory_root="$(create_inventory)" + log "Inventory created: $inventory_root" + warn "The inventory records paths and metadata; it is not a backup of deleted application or runtime data." + + if [[ "$CLEAN_USERDATA" == "true" ]]; then + if confirm_stage "DELETE RETIRED APP DATA"; then + clean_application_data + log "Retired application data and stale launchers/config were removed." + else + warn "Retired application-data stage skipped." + fi + fi + + if [[ "$CLEAN_RUNTIMES" == "true" ]]; then + warn "The runtime stage deletes the Flutter checkout, Android SDK/Studio state, Gradle state, and Android debug/AVD state." + if confirm_stage "DELETE FLUTTER AND ANDROID DATA"; then + clean_runtime_data + log "Retired Flutter and Android data were removed." + else + warn "Flutter and Android stage skipped." + fi + fi + + if [[ "$CLEAN_CACHES" == "true" ]]; then + if confirm_stage "CLEAN REBUILDABLE CACHES"; then + clean_rebuildable_caches + log "Selected rebuildable caches were cleaned." + else + warn "Cache stage skipped." + fi + fi + + if [[ "$INCLUDE_DOCKER" == "true" ]]; then + warn "Docker pruning deletes stopped containers and unused images, networks, and build cache. Volumes remain untouched." + if confirm_stage "PRUNE DOCKER DATA"; then + clean_docker_data + log "Docker prune completed." + else + warn "Docker stage skipped." + fi + fi + + log "Cleanup stages finished. Re-run './cleanup plan' to inspect remaining state." + log "Log out and back in after shell or graphical environment cleanup." +} + +main() { + parse_args "$@" + build_path_lists + + command -v pacman >/dev/null 2>&1 || die "pacman is required." + command -v numfmt >/dev/null 2>&1 || die "numfmt is required." + + if [[ "$MODE" == "plan" ]]; then + show_plan + else + apply_cleanup + fi +} + +main "$@" diff --git a/configs/base/.config/DankMaterialShell/settings.json b/configs/base/.config/DankMaterialShell/settings.json index 06d8729..2e971d5 100644 --- a/configs/base/.config/DankMaterialShell/settings.json +++ b/configs/base/.config/DankMaterialShell/settings.json @@ -294,7 +294,7 @@ "matugenTemplateQt6ct": true, "matugenTemplateFirefox": false, "matugenTemplatePywalfox": false, - "matugenTemplateZenBrowser": true, + "matugenTemplateZenBrowser": false, "matugenTemplateVesktop": true, "matugenTemplateEquibop": false, "matugenTemplateGhostty": true, @@ -573,4 +573,4 @@ "launcherPluginVisibility": {}, "launcherPluginOrder": [], "configVersion": 5 -} \ No newline at end of file +} diff --git a/configs/base/.config/autostart/jetbrains-toolbox.desktop b/configs/base/.config/autostart/jetbrains-toolbox.desktop deleted file mode 100644 index ef7f69a..0000000 --- a/configs/base/.config/autostart/jetbrains-toolbox.desktop +++ /dev/null @@ -1,16 +0,0 @@ -[Desktop Entry] -Icon=jetbrains-toolbox -Exec=/opt/jetbrains-toolbox/jetbrains-toolbox --minimize -Version=1.0 -Type=Application -Categories=Development; -Name=JetBrains Toolbox -StartupWMClass=jetbrains-toolbox -Terminal=false -MimeType= -Hidden=true -X-GNOME-Autostart-enabled=false -StartupNotify=false -X-GNOME-Autostart-Delay=10 -X-MATE-Autostart-Delay=10 -X-KDE-autostart-after=panel diff --git a/configs/base/.config/environment.d/90-dms.conf b/configs/base/.config/environment.d/90-dms.conf index 659a7e2..6e5f5b5 100644 --- a/configs/base/.config/environment.d/90-dms.conf +++ b/configs/base/.config/environment.d/90-dms.conf @@ -8,5 +8,5 @@ XDG_SESSION_DESKTOP=niri TERMINAL=ghostty QT_QPA_PLATFORMTHEME=qt6ct EDITOR=nvim -PATH=$HOME/.cargo/bin:$HOME/.local/share/JetBrains/Toolbox/scripts:$HOME/.local/bin:$HOME/.local/bin/niriland:$HOME/.local/bin/scripts:$HOME/.opencode/bin:$HOME/.lmstudio/bin:$HOME/.dotnet/tools:$PATH +PATH=$HOME/.cargo/bin:$HOME/.local/share/mise/shims:$HOME/.local/bin:$HOME/.local/bin/niriland:$PATH GTK_IM_MODULE=simple diff --git a/configs/base/.config/helix/config.toml b/configs/base/.config/helix/config.toml deleted file mode 100644 index c635fd5..0000000 --- a/configs/base/.config/helix/config.toml +++ /dev/null @@ -1,12 +0,0 @@ -theme = "myterm" - -[editor] -line-number = "relative" -cursorline = false -bufferline = "multiple" -color-modes = true -popup-border = "none" - -[editor.statusline] -left = ["mode", "file-name"] -right = ["diagnostics", "position", "file-type"] diff --git a/configs/base/.config/helix/languages.toml b/configs/base/.config/helix/languages.toml deleted file mode 100644 index b61e23e..0000000 --- a/configs/base/.config/helix/languages.toml +++ /dev/null @@ -1,5 +0,0 @@ -# Override the stale gotmpl grammar source used by the packaged Helix release. -# The old dannylongeuay/tree-sitter-go-template repository is unavailable. -[[grammar]] -name = "gotmpl" -source = { git = "https://github.com/ngalaiko/tree-sitter-go-template", rev = "ca26229bafcd3f37698a2496c2a5efa2f07e86bc" } diff --git a/configs/base/.config/helix/themes/myterm.toml b/configs/base/.config/helix/themes/myterm.toml deleted file mode 100644 index 20b9d08..0000000 --- a/configs/base/.config/helix/themes/myterm.toml +++ /dev/null @@ -1,23 +0,0 @@ -inherits = "default" - -"ui.background" = {} -"ui.text" = { fg = "foreground" } - -"ui.linenr" = { fg = "gray" } -"ui.linenr.selected" = { fg = "white", modifiers = ["bold"] } - -"ui.statusline" = {} -"ui.statusline.inactive" = {} - -"ui.popup" = {} -"ui.popup.info" = {} -"ui.help" = {} -"ui.menu" = {} -"ui.menu.scroll" = {} -"ui.window" = {} - -"ui.menu.selected" = { modifiers = ["reversed"] } -"ui.selection" = { modifiers = ["reversed"] } -"ui.cursorline.primary" = { modifiers = ["underlined"] } - -"ui.text.inactive" = { fg = "gray" } diff --git a/configs/base/.config/mimeapps.list b/configs/base/.config/mimeapps.list index 4050dfb..ea24a2a 100644 --- a/configs/base/.config/mimeapps.list +++ b/configs/base/.config/mimeapps.list @@ -16,15 +16,15 @@ image/svg+xml=org.gnome.Loupe.desktop image/avif=org.gnome.Loupe.desktop image/heic=org.gnome.Loupe.desktop -# Video (Showtime) -video/mp4=org.gnome.Showtime.desktop -video/x-matroska=org.gnome.Showtime.desktop -video/webm=org.gnome.Showtime.desktop -video/x-msvideo=org.gnome.Showtime.desktop -video/quicktime=org.gnome.Showtime.desktop -video/x-flv=org.gnome.Showtime.desktop -video/ogg=org.gnome.Showtime.desktop -video/3gpp=org.gnome.Showtime.desktop +# Video (mpv) +video/mp4=mpv.desktop +video/x-matroska=mpv.desktop +video/webm=mpv.desktop +video/x-msvideo=mpv.desktop +video/quicktime=mpv.desktop +video/x-flv=mpv.desktop +video/ogg=mpv.desktop +video/3gpp=mpv.desktop # Audio (mpv) audio/mpeg=mpv.desktop @@ -41,14 +41,8 @@ application/oxps=org.pwmt.zathura-pdf-mupdf.desktop application/epub+zip=org.pwmt.zathura-pdf-mupdf.desktop application/x-fictionbook=org.pwmt.zathura-pdf-mupdf.desktop application/x-mobipocket-ebook=org.pwmt.zathura-pdf-mupdf.desktop -image/vnd.djvu=org.pwmt.zathura-djvu.desktop -application/x-cb7=org.pwmt.zathura-cb.desktop -application/x-cbr=org.pwmt.zathura-cb.desktop -application/x-cbt=org.pwmt.zathura-cb.desktop -application/x-cbz=org.pwmt.zathura-cb.desktop - -# Plaintext (Gnome Text Editor) -text/plain=org.gnome.TextEditor.desktop +# Plaintext (Zed) +text/plain=dev.zed.Zed.desktop # Code / Text (VSCodium) text/x-csrc=vscodium-wayland.desktop diff --git a/configs/base/.config/mise/config.toml b/configs/base/.config/mise/config.toml index 60e6bb6..f8b9107 100644 --- a/configs/base/.config/mise/config.toml +++ b/configs/base/.config/mise/config.toml @@ -1,13 +1,15 @@ [tools] -bun = "1.3" -dotnet = "10" -go = "1.26" +dotnet = "9" +go = "1.25" java = "corretto-25" node = "24" rust = "stable" -terraform = "latest" -uv = "0.11.8" -zig = "0.15" +uv = "latest" +"npm:@anthropic-ai/claude-code" = "latest" +"npm:@openai/codex" = "latest" +"npm:@xai-official/grok" = "latest" +"npm:markdownlint-cli" = "latest" +"go:golang.org/x/tools/gopls" = "latest" [settings] python.uv_venv_auto = true diff --git a/configs/base/.config/topgrade.toml b/configs/base/.config/topgrade.toml index 8dab9e8..e90e65d 100644 --- a/configs/base/.config/topgrade.toml +++ b/configs/base/.config/topgrade.toml @@ -28,12 +28,10 @@ pre_sudo = true # sudo_command = "sudo" # Disable specific steps - same options as the command line flag -# Bun itself is managed by mise; keep bun_packages enabled for global packages. -# Poetry is not part of the baseline mise toolset; a stale mise shim makes Topgrade probe it noisily. -# The built-in node/npm step follows the active mise Node; system npm globals are updated explicitly below. +# Poetry is not part of the baseline; disable probes from any stale shim. +# The Node step would duplicate updates already owned by the active mise tools. # Docker/Podman images are managed manually or outside this workstation. -# JetBrains Toolbox manages IDE and plugin updates itself; Topgrade's JetBrains steps are noisy and restart Toolbox. -disable = ["bun", "poetry", "node", "containers", "android_studio", "jetbrains_aqua", "jetbrains_clion", "jetbrains_datagrip", "jetbrains_dataspell", "jetbrains_gateway", "jetbrains_goland", "jetbrains_idea", "jetbrains_mps", "jetbrains_phpstorm", "jetbrains_pycharm", "jetbrains_rider", "jetbrains_rubymine", "jetbrains_rustrover", "jetbrains_toolbox", "jetbrains_webstorm"] +disable = ["poetry", "node", "containers"] # Run these steps before all others # first = ["chezmoi"] @@ -147,7 +145,6 @@ notify_end = "on_failure" [commands] # "Python Environment" = "~/dev/.env/bin/pip install -i https://pypi.python.org/simple -U --upgrade-strategy eager jupyter" # "Custom command using interactive shell (unix)" = "-i vim_upgrade" -"Codex CLI via system npm" = "sudo env PATH=/usr/bin:/bin /usr/bin/npm install --global @openai/codex@latest" [python] diff --git a/configs/base/.config/yazi/yazi.toml b/configs/base/.config/yazi/yazi.toml deleted file mode 100644 index e5ff226..0000000 --- a/configs/base/.config/yazi/yazi.toml +++ /dev/null @@ -1,3 +0,0 @@ -# yazi.toml -[mgr] -show_hidden = true diff --git a/configs/base/.config/zsh/.zprofile b/configs/base/.config/zsh/.zprofile index 7001e50..a3e366c 100644 --- a/configs/base/.config/zsh/.zprofile +++ b/configs/base/.config/zsh/.zprofile @@ -3,13 +3,8 @@ path=( "$HOME/.local/bin" "$HOME/.local/bin/niriland" - "$HOME/develop/flutter/bin" $path ) -if [[ -d "$HOME/.local/share/JetBrains/Toolbox/scripts" ]]; then - path+=("$HOME/.local/share/JetBrains/Toolbox/scripts") -fi - typeset -U path export PATH diff --git a/configs/base/.config/zsh/.zshenv b/configs/base/.config/zsh/.zshenv index f714084..510bfb2 100644 --- a/configs/base/.config/zsh/.zshenv +++ b/configs/base/.config/zsh/.zshenv @@ -13,7 +13,7 @@ if [[ -t 0 ]]; then fi export STARSHIP_CONFIG="$ZDOTDIR/starship.toml" -export CHROME_EXECUTABLE="${CHROME_EXECUTABLE:-/usr/bin/helium-browser}" +export CHROME_EXECUTABLE="${CHROME_EXECUTABLE:-/usr/bin/brave-origin}" if command -v bat >/dev/null 2>&1; then export MANPAGER="${MANPAGER:-bat -l man -p}" diff --git a/configs/base/.local/share/applications/OpenWebUI.desktop b/configs/base/.local/share/applications/OpenWebUI.desktop deleted file mode 100644 index b648331..0000000 --- a/configs/base/.local/share/applications/OpenWebUI.desktop +++ /dev/null @@ -1,8 +0,0 @@ -[Desktop Entry] -Type=Application -Name=Open WebUI -Comment=Local AI chat powered by Open WebUI and Ollama -Exec=niriland-launch-webapp http://127.0.0.1:3210 -Icon=OpenWebUI -Terminal=false -Categories=Utility; diff --git a/configs/base/.local/share/applications/jetbrains-toolbox.desktop b/configs/base/.local/share/applications/jetbrains-toolbox.desktop deleted file mode 100644 index e84c719..0000000 --- a/configs/base/.local/share/applications/jetbrains-toolbox.desktop +++ /dev/null @@ -1,14 +0,0 @@ -[Desktop Entry] -Exec=/opt/jetbrains-toolbox/jetbrains-toolbox %u -Icon=jetbrains-toolbox -MimeType=x-scheme-handler/jetbrains; -Name=JetBrains Toolbox -StartupNotify=false -StartupWMClass=jetbrains-toolbox -Terminal=false -Type=Application -Version=1.0 -X-GNOME-Autostart-Delay=10 -X-GNOME-Autostart-enabled=false -X-KDE-autostart-after=panel -X-MATE-Autostart-Delay=10 diff --git a/configs/base/.local/share/icons/OpenWebUI.png b/configs/base/.local/share/icons/OpenWebUI.png deleted file mode 100644 index e5a308a..0000000 Binary files a/configs/base/.local/share/icons/OpenWebUI.png and /dev/null differ diff --git a/configs/modules/.config/ghostty/config b/configs/modules/.config/ghostty/config index f88e577..12d429c 100644 --- a/configs/modules/.config/ghostty/config +++ b/configs/modules/.config/ghostty/config @@ -33,7 +33,7 @@ keybind = super+control+shift+alt+arrow_right=resize_split:right,100 # Mouse scrolling speed mouse-scroll-multiplier = 2.0 -mouse-reporting = false +mouse-reporting = true # Copy selection to PRIMARY only. Middle-click paste uses PRIMARY; # Ctrl+Shift+C/V still use the regular clipboard. diff --git a/configs/modules/.config/niri/modular/binds.kdl b/configs/modules/.config/niri/modular/binds.kdl index 69aea12..a56eaef 100644 --- a/configs/modules/.config/niri/modular/binds.kdl +++ b/configs/modules/.config/niri/modular/binds.kdl @@ -65,12 +65,6 @@ binds { Mod+Shift+B hotkey-overlay-title="Browser (New)" { spawn "niriland-launch-browser"; } - Mod+Alt+X hotkey-overlay-title="Zen (New)" { - spawn "zen-browser"; - } - Mod+Shift+X hotkey-overlay-title="Zen (Focus)" { - spawn "nirius" "focus-or-spawn" "--app-id" "zen" "--" "zen-browser"; - } Mod+Shift+C hotkey-overlay-title=null { spawn "nirius" "focus-or-spawn" "--title" "Claude" "--" "niriland-launch-webapp" "https://claude.ai/new"; } diff --git a/configs/modules/.config/niri/modular/rules.kdl b/configs/modules/.config/niri/modular/rules.kdl index d3cda89..e89b9a4 100644 --- a/configs/modules/.config/niri/modular/rules.kdl +++ b/configs/modules/.config/niri/modular/rules.kdl @@ -46,18 +46,13 @@ window-rule { } window-rule { - match app-id=r#"^org\.wezfurlong\.wezterm$"# - match app-id="Alacritty" - match app-id="zen" - match app-id="helium" match app-id="com.mitchellh.ghostty" - match app-id="kitty" draw-border-with-background false } window-rule { match app-id=r#"firefox$"# title="^Picture-in-Picture$" - match app-id=r#"helium$"# title="^Picture-in-Picture$" + match app-id=r#"brave-origin$"# title="^Picture-in-Picture$" // match app-id="zoom" open-floating true } diff --git a/docs/KEYBINDINGS.md b/docs/KEYBINDINGS.md index e894aa6..c34102e 100644 --- a/docs/KEYBINDINGS.md +++ b/docs/KEYBINDINGS.md @@ -54,8 +54,6 @@ These bindings are active when the Alt+Tab switcher overlay is open. |------------|---------|-------------| | `Mod+Alt+B` | `spawn "sh" "-lc" "nirius focus-or-spawn --app-id \"$(niriland-get-default-browser)\" -- niriland-launch-browser"` | Focus default browser or launch if not running | | `Mod+Shift+B` | `spawn "niriland-launch-browser"` | Launch new browser window | -| `Mod+Alt+X` | `spawn "zen-browser"` | Launch new Zen Browser window | -| `Mod+Shift+X` | `spawn "nirius" "focus-or-spawn" "--app-id" "zen" "--" "zen-browser"` | Focus Zen Browser or launch if not running | | `Mod+Shift+C` | `spawn "nirius" "focus-or-spawn" "--title" "Claude" "--" "niriland-launch-webapp" "https://claude.ai/new"` | Focus or launch Claude AI | | `Mod+Alt+C` | `spawn "niriland-launch-webapp" "https://claude.ai/new"` | Launch new Claude AI window | | `Mod+Shift+A` | `spawn "nirius" "focus-or-spawn" "--title" "ChatGPT" "--" "niriland-launch-webapp" "https://chatgpt.com/"` | Focus or launch ChatGPT | diff --git a/docs/MIGRATIONS.md b/docs/MIGRATIONS.md index faf13ea..c47aefb 100644 --- a/docs/MIGRATIONS.md +++ b/docs/MIGRATIONS.md @@ -9,53 +9,66 @@ Migration policy: - Remove entries once all active systems are expected to be converged or the old state is no longer realistic. - This file is for operational one-time fixes, not as a permanent changelog. -## 14. august 2026 - Disable JetBrains Toolbox Autostart +## 19. august 2026 - Adopt the Shared Workstation Baseline Who: -Existing installs where JetBrains Toolbox created -`~/.config/autostart/jetbrains-toolbox.desktop` and starts automatically with -the graphical session. +Existing installs that predate the shared post-cleanup package and development +tool baseline. `cachytop` keeps the full optional gaming profile; other machines +use the common baseline without it. -Run: +Inspect first: ```bash -mkdir -p \ - ~/.config/autostart \ - ~/.config/backups/niriland/migrations \ - ~/.local/share/applications - -if [[ -f ~/.config/autostart/jetbrains-toolbox.desktop ]]; then - cp -a \ - ~/.config/autostart/jetbrains-toolbox.desktop \ - ~/.config/backups/niriland/migrations/jetbrains-toolbox-autostart.desktop -fi - -cp -a \ - ~/.local/share/niriland/configs/base/.config/autostart/jetbrains-toolbox.desktop \ - ~/.config/autostart/jetbrains-toolbox.desktop -cp -a \ - ~/.local/share/niriland/configs/base/.local/share/applications/jetbrains-toolbox.desktop \ - ~/.local/share/applications/jetbrains-toolbox.desktop - -if command -v update-desktop-database >/dev/null 2>&1; then - update-desktop-database ~/.local/share/applications -fi +# cachytop +~/.local/share/niriland/migrations/2026-08-19-common-baseline.sh plan --keep-gaming -systemctl --user daemon-reload +# a machine without the full gaming profile +~/.local/share/niriland/migrations/2026-08-19-common-baseline.sh plan ``` -What it changes: +The plan resolves Pacman's complete recursive removal transaction and aborts if +it contains a protected `lib32` package. With `--keep-gaming`, it also aborts if +the transaction contains the protected Steam/Lutris/Wine/Proton set, a package +from `packages/gaming.packages`, or Prism Launcher. + +After reviewing the exact transaction, apply explicitly: -- Backs up an existing Toolbox-created autostart entry -- Deploys a user application entry that overrides the packaged desktop entry -- Deploys the matching XDG autostart entry with `Hidden=true` and autostart - disabled -- Prevents Toolbox from starting in future graphical sessions without stopping - an instance that is already running +```bash +# cachytop +~/.local/share/niriland/migrations/2026-08-19-common-baseline.sh apply --keep-gaming + +# a machine without the full gaming profile +~/.local/share/niriland/migrations/2026-08-19-common-baseline.sh apply +``` + +Apply requires the typed phrase `APPLY COMMON BASELINE` and leaves Pacman's own +confirmation enabled. It records package, Mise, and Cargo inventories under +`~/.local/state/niriland/migrations/`, creates a Snapper snapshot when Snapper +is available, installs the tracked user-local Mise and Cargo tool baseline, +removes superseded system-owned tools and the legacy Node-global Grok CLI, and +retargets video and plain-text MIME defaults to mpv and Zed. Defaults for +comic-book archives and DjVu are removed because their Zathura plugins leave +the baseline. Mise shims are regenerated and added to the graphical session +PATH so T3 Code can resolve the shared CLI agents after login. It then applies +the shared Snapper/Limine retention settings. Packages declared by the shared +manifests, protected platform foundations, every installed `lib32` package, +and the selected gaming profile are marked explicit before recursive removal +so Pacman preserves them; the original explicit and dependency reason lists +remain in the inventory. + +The migration does not delete application data, game installations, Wine +prefixes, saves, containers, caches, or other home-directory state. Package +removal does not make the newly added shared packages appear; replay +`10-install-packages` separately after the migration when its transaction has +also been reviewed. Fresh installs: -Not needed manually. Fresh installs already deploy both tracked Toolbox desktop -entries. +Not needed. The normal manifests install only the common baseline. Prism +Launcher is common; the full gaming profile is installed explicitly with +`niriland-setup-gaming` on selected machines. + +Log out and back in after applying the migration so the graphical session reads +the updated environment. ## 14. august 2026 - Replace Helium with Brave Origin @@ -84,7 +97,7 @@ sudo sed -i \ -e '/^brave-origin$/d' \ -e '/^zen-bin$/d' \ /etc/1password/custom_allowed_browsers -printf "brave-origin\nzen-bin\n" | sudo tee -a /etc/1password/custom_allowed_browsers >/dev/null +printf "brave-origin\n" | sudo tee -a /etc/1password/custom_allowed_browsers >/dev/null # Package manifests install additions but do not uninstall packages removed from # the manifests, so clean up the old browser packages when they are present. @@ -184,42 +197,6 @@ What it changes: Fresh installs: Not needed manually. Fresh installs already deploy the current tracked VSCodium settings and keybindings. -## 5. maj 2026 - Pin `uv` in mise Until Latest Installs Cleanly - -Who: -Existing installs whose local mise config still requests `uv = "latest"` and fails during Topgrade because `uv@0.11.9` cannot verify GitHub artifact attestations through the aqua backend. - -Symptoms: - -```text -mise ERROR Failed to install aqua:astral-sh/uv@latest: No GitHub artifact attestations found for aqua:astral-sh/uv@0.11.9, but they are expected per aqua registry configuration -``` - -Run: - -```bash -mkdir -p ~/.config/mise -cp -a ~/.local/share/niriland/configs/base/.config/mise/config.toml ~/.config/mise/config.toml - -mise ls uv -topgrade --only mise -``` - -Expected: - -```text -uv 0.11.8 ~/.config/mise/config.toml 0.11.8 -``` - -What it changes: - -- Refreshes the local mise config from the latest tracked Niriland copy in `~/.local/share/niriland` -- Pins `uv` to `0.11.8` instead of tracking `latest` -- Keeps Topgrade's mise step from failing on the current `uv@0.11.9` attestation mismatch - -Fresh installs: -Not needed manually. Fresh installs already deploy the current tracked mise config. - ## 30. april 2026 - Run All Migrations for This Date Who: diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 95f4efe..3878e7f 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -42,8 +42,6 @@ Keep entries short: problem, target state, and any important constraint. - [ ] Split optional development tooling out of the default install path and keep only true baseline developer setup in the main flow. -- [ ] Recheck whether the packaged Helix `gotmpl` grammar source has moved off the unavailable `dannylongeuay/tree-sitter-go-template` repository, then remove `configs/base/.config/helix/languages.toml` if the override is no longer needed. - - [ ] Make Zed smarter for Typst work, especially opening generated PDFs in the default viewer without first landing on Zed's binary-file error tab. - [ ] Add an explicit opt-in Flutter setup path with sane release resolution, browser configuration, Android prerequisites, and clear Linux versus macOS boundaries. @@ -56,6 +54,13 @@ Keep entries short: problem, target state, and any important constraint. ### Platform refinements +#### Shared workstation baseline + +- [x] Align the default package and development-tool manifests with the accepted post-cleanup workstation baseline. +- [x] Keep Prism Launcher shared while moving the full gaming stack into an explicit per-machine manifest that normal install and update paths do not consume. +- [x] Add a plan-first migration that protects `lib32`, optional gaming packages, and home-directory data before any removal is allowed. +- [x] Standardize Ghostty mouse reporting across the active machines. + #### Virtualization stack rebuild - [x] Remove the current VM helper/tooling path and rebuild virtualization support from scratch around a smaller, explicitly supported stack. diff --git a/migrations/2026-08-19-common-baseline.sh b/migrations/2026-08-19-common-baseline.sh new file mode 100755 index 0000000..38655f5 --- /dev/null +++ b/migrations/2026-08-19-common-baseline.sh @@ -0,0 +1,470 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=scripts/install/lib/common +source "$SCRIPT_DIR/../scripts/install/lib/common" + +MODE="plan" +KEEP_GAMING=false +GAMING_MANIFEST="$REPO_ROOT/packages/gaming.packages" +MISE_CONFIG_SOURCE="$REPO_ROOT/configs/base/.config/mise/config.toml" +MIMEAPPS_SOURCE="$REPO_ROOT/configs/base/.config/mimeapps.list" +SESSION_ENV_SOURCE="$REPO_ROOT/configs/base/.config/environment.d/90-dms.conf" +STALE_MANAGED_HOME_FILES=( + ".config/autostart/jetbrains-toolbox.desktop" + ".local/share/applications/jetbrains-toolbox.desktop" +) +SHARED_MANIFESTS=( + "$REPO_ROOT/packages/base.packages" + "$REPO_ROOT/packages/aur.packages" + "$REPO_ROOT/packages/cachyos.packages" + "$REPO_ROOT/packages/chaotic.packages" +) + +COMMON_REMOVALS=( + alacritty + archinstall + baobab + bash-language-server + cachyos-micro-settings + cachyos-packageinstaller + chromium + cosmic-files + curlie + drawio-desktop + fsarchiver + gimp + glances + gnome-text-editor + gopls + helix + httpie + imv + jetbrains-toolbox + just + kdenlive + markdownlint + micro + mise + npm + octopi + ollama + opencode-desktop-bin + papers + shelly + showtime + solaar + t3code-bin + teams-for-linux + typescript-language-server + vim + vlc-plugins-all + vscode-css-languageserver + vscode-html-languageserver + vscode-json-languageserver + vue-language-server + yaml-language-server + yazi + zathura-cb + zathura-djvu + zen-browser-bin + zls + zoom +) + +GAMING_REMOVALS=( + cachyos-gaming-applications + cachyos-gaming-meta + dosbox + gamescope + goverlay + heroic-games-launcher-bin + lutris + mangohud + proton-cachyos-slr + protontricks + protonup-qt + scummvm + steam + umu-launcher + wine + winetricks + wowup-cf-bin +) + +SYSTEM_NPM_REMOVALS=( + @anthropic-ai/claude-code + @openai/codex + @xai-official/grok + @vue/language-server + bash-language-server + svgo + typescript + typescript-language-server + vscode-css-languageserver + vscode-html-languageserver + vscode-json-languageserver + vscode-langservers-extracted + yaml-language-server +) + +PROTECTED_COMMON=( + avahi + cifs-utils + cups + cups-filters + cups-pdf + dms-shell + dms-shell-niri + greetd-dms-greeter-bin + gutenprint + hplip + linux-cachyos + linux-cachyos-headers + linux-cachyos-lts + linux-cachyos-lts-headers + niri + nix + polkit-gnome + power-profiles-daemon + python + python-pycups + qt6-multimedia-ffmpeg + quickshell-git + smbclient + swtpm + wtype + xdg-desktop-portal-gnome + xdg-desktop-portal-gtk + xwayland-satellite +) + +usage() { + cat <<'EOF' +Usage: migrations/2026-08-19-common-baseline.sh [plan|apply] [--keep-gaming] + +Commands: + plan Print the resolved Pacman removal transaction (default) + apply Back up state, install replacement tools, and run the removal + +Options: + --keep-gaming Preserve the optional Niriland gaming profile + +The migration never removes home-directory application data, game data, +containers, caches, or lib32 packages. Apply requires a typed confirmation and +leaves Pacman's own transaction confirmation enabled. +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + plan) + MODE="plan" + ;; + apply) + MODE="apply" + ;; + --keep-gaming) + KEEP_GAMING=true + ;; + help|-h|--help) + usage + exit 0 + ;; + *) + usage >&2 + die "Unexpected argument: $1" + ;; + esac + shift +done + +require_cmd pacman +require_cmd fakeroot +[[ -f "$GAMING_MANIFEST" ]] || die "Missing gaming manifest: $GAMING_MANIFEST" +[[ -f "$MISE_CONFIG_SOURCE" ]] || die "Missing mise config: $MISE_CONFIG_SOURCE" +[[ -f "$MIMEAPPS_SOURCE" ]] || die "Missing MIME applications config: $MIMEAPPS_SOURCE" +[[ -f "$SESSION_ENV_SOURCE" ]] || die "Missing graphical session environment: $SESSION_ENV_SOURCE" + +declare -a removal_candidates=("${COMMON_REMOVALS[@]}") +declare -a removal_targets=() +declare -a resolved_removals=() +declare -a gaming_manifest_packages=() +declare -a protected_gaming=() +declare -a protected_packages=("${PROTECTED_COMMON[@]}") +declare -a installed_protected=() +declare -A protected_gaming_set=() +declare -A protected_package_set=() + +for manifest in "${SHARED_MANIFESTS[@]}"; do + [[ -f "$manifest" ]] || die "Missing shared package manifest: $manifest" + mapfile -t manifest_packages < <(grep -Ev '^\s*(#|$)' "$manifest") + protected_packages+=("${manifest_packages[@]}") +done + +while IFS= read -r package_name; do + case "$package_name" in + lib32-*|foomatic-*|cups-*) + protected_packages+=("$package_name") + ;; + esac +done < <(pacman -Qq) + +if [[ "$KEEP_GAMING" == "false" ]]; then + removal_candidates+=("${GAMING_REMOVALS[@]}") +else + mapfile -t gaming_manifest_packages < <(grep -Ev '^\s*(#|$)' "$GAMING_MANIFEST") + protected_gaming=("${GAMING_REMOVALS[@]}" "${gaming_manifest_packages[@]}" prismlauncher) + + for package_name in "${protected_gaming[@]}"; do + protected_gaming_set["$package_name"]=1 + done + + protected_packages+=("${protected_gaming[@]}") +fi + +for package_name in "${protected_packages[@]}"; do + [[ -n "$package_name" ]] || continue + protected_package_set["$package_name"]=1 +done + +for package_name in "${!protected_package_set[@]}"; do + if pacman -Qq "$package_name" >/dev/null 2>&1; then + installed_protected+=("$package_name") + fi +done + +for package_name in "${removal_candidates[@]}"; do + if pacman -Qq "$package_name" >/dev/null 2>&1; then + removal_targets+=("$package_name") + fi +done + +resolved_output="" +simulation_db="" +cleanup_simulation() { + if [[ -n "${simulation_db:-}" && -d "$simulation_db" ]]; then + find "$simulation_db" -depth -delete + fi +} +trap cleanup_simulation EXIT + +if [[ ${#removal_targets[@]} -eq 0 ]]; then + log_success "No installed packages need removal for the selected baseline." +else + simulation_db="$(mktemp -d)" + cp -a /var/lib/pacman/local "$simulation_db/local" + ln -s /var/lib/pacman/sync "$simulation_db/sync" + if [[ ${#installed_protected[@]} -gt 0 ]]; then + fakeroot pacman --dbpath "$simulation_db" -D --asexplicit "${installed_protected[@]}" >/dev/null + fi + + if ! resolved_output="$(fakeroot pacman --dbpath "$simulation_db" -Rs --print-format '%n' -- "${removal_targets[@]}")"; then + die "Pacman could not resolve the removal transaction." + fi + mapfile -t resolved_removals <<<"$resolved_output" + + for package_name in "${resolved_removals[@]}"; do + [[ -n "$package_name" ]] || continue + + if [[ "$package_name" == lib32-* ]]; then + die "Refusing transaction because it would remove protected package: $package_name" + fi + + if [[ "$KEEP_GAMING" == "true" && -n "${protected_gaming_set[$package_name]:-}" ]]; then + die "Refusing transaction because it would remove protected gaming package: $package_name" + fi + done +fi + +log "Selected baseline: common" +if [[ "$KEEP_GAMING" == "true" ]]; then + log "Machine exception: full gaming profile preserved" +else + log "Machine exception: none" +fi + +printf '\nDirect installed removal roots:\n' +if [[ ${#removal_targets[@]} -gt 0 ]]; then + printf ' %s\n' "${removal_targets[@]}" +else + printf ' (none)\n' +fi +printf '\nProtected baseline roots: %d installed packages\n' "${#installed_protected[@]}" +printf '\nResolved Pacman removal transaction:\n' +if [[ ${#resolved_removals[@]} -gt 0 ]]; then + printf ' %s\n' "${resolved_removals[@]}" +else + printf ' (none)\n' +fi + +if [[ "$MODE" == "plan" ]]; then + printf '\nPlan only. No files, packages, or system state were changed.\n' + exit 0 +fi + +printf '\nApply replaces ~/.config/mise/config.toml with the tracked baseline.\n' +printf 'The current file is backed up and restored if mise installation fails.\n' +printf '\nType APPLY COMMON BASELINE to continue: ' +read -r confirmation "$inventory_root/pacman-all.txt" +pacman -Qqe >"$inventory_root/pacman-explicit.txt" +pacman -Qqd >"$inventory_root/pacman-dependencies.txt" +pacman -Qqm >"$inventory_root/pacman-foreign.txt" +pacman -Qdtq >"$inventory_root/pacman-orphans.txt" || true +cargo install --list >"$inventory_root/cargo-install-list.txt" +if command -v mise >/dev/null 2>&1; then + mise ls --global >"$inventory_root/mise-global.txt" 2>&1 || true +fi +if [[ -x /usr/bin/npm ]]; then + env PATH=/usr/bin:/bin /usr/bin/npm --global list --depth=0 \ + >"$inventory_root/system-npm-global.txt" 2>&1 || true +fi +for relative_path in "${STALE_MANAGED_HOME_FILES[@]}"; do + source_path="$HOME/$relative_path" + if [[ -e "$source_path" || -L "$source_path" ]]; then + backup_path="$inventory_root/home/$relative_path" + mkdir -p "$(dirname "$backup_path")" + cp -a "$source_path" "$backup_path" + fi +done + +mimeapps_target="$HOME/.config/mimeapps.list" +if [[ -f "$mimeapps_target" ]]; then + mimeapps_backup="$inventory_root/home/.config/mimeapps.list" + mkdir -p "$(dirname "$mimeapps_backup")" + cp -a "$mimeapps_target" "$mimeapps_backup" +fi + +session_env_target="$HOME/.config/environment.d/90-dms.conf" +if [[ -f "$session_env_target" ]]; then + session_env_backup="$inventory_root/home/.config/environment.d/90-dms.conf" + mkdir -p "$(dirname "$session_env_backup")" + cp -a "$session_env_target" "$session_env_backup" +fi + +mise_config_target="$HOME/.config/mise/config.toml" +mise_config_existed=false +mkdir -p "$(dirname "$mise_config_target")" +if [[ -f "$mise_config_target" ]]; then + cp -a "$mise_config_target" "$inventory_root/mise-config.toml" + mise_config_existed=true +fi + +if command -v snapper >/dev/null 2>&1; then + sudo snapper -c root create --description "Before Niriland common baseline migration" +else + warn "snapper is unavailable; continuing with inventory but no filesystem snapshot." +fi + +ensure_user_mise +cp -a "$MISE_CONFIG_SOURCE" "$mise_config_target" +if ! "$MISE_BIN" install; then + if [[ "$mise_config_existed" == "true" ]]; then + cp -a "$inventory_root/mise-config.toml" "$mise_config_target" + else + rm -f -- "$mise_config_target" + fi + die "Mise baseline installation failed; the pre-migration config state was restored." +fi + +mise_node_npm="$("$MISE_BIN" which npm 2>/dev/null || true)" +if [[ -x "$mise_node_npm" ]] \ + && "$mise_node_npm" --global list --depth=0 @xai-official/grok >/dev/null 2>&1; then + log "Removing the superseded Node-global Grok CLI." + "$mise_node_npm" uninstall --global @xai-official/grok +fi + +"$MISE_BIN" reshim +eval "$("$MISE_BIN" activate bash)" +install_baseline_cargo_tools + +if [[ -x /usr/bin/npm ]]; then + installed_system_npm=() + for npm_package in "${SYSTEM_NPM_REMOVALS[@]}"; do + if env PATH=/usr/bin:/bin /usr/bin/npm --global list --depth=0 "$npm_package" >/dev/null 2>&1; then + installed_system_npm+=("$npm_package") + fi + done + + if [[ ${#installed_system_npm[@]} -gt 0 ]]; then + log "Removing superseded system-global npm tools: ${installed_system_npm[*]}" + sudo env PATH=/usr/bin:/bin /usr/bin/npm uninstall --global "${installed_system_npm[@]}" + fi +fi + +log "Marking reviewed baseline packages explicit so recursive cleanup preserves them." +if [[ ${#installed_protected[@]} -gt 0 ]]; then + sudo pacman -D --asexplicit "${installed_protected[@]}" +fi + +if [[ ${#removal_targets[@]} -gt 0 ]]; then + if ! apply_resolved_output="$(pacman -Rs --print-format '%n' -- "${removal_targets[@]}")"; then + die "Pacman could not re-resolve the removal transaction after protection." + fi + if [[ "$apply_resolved_output" != "$resolved_output" ]]; then + die "Pacman transaction changed after planning; aborting before removal." + fi + + log "Starting the reviewed Pacman removal transaction." + sudo pacman -Rn -- "${resolved_removals[@]}" +else + log "No Pacman removal transaction is needed; continuing baseline convergence." +fi + +for relative_path in "${STALE_MANAGED_HOME_FILES[@]}"; do + rm -f -- "$HOME/$relative_path" +done +log "Removed stale managed JetBrains Toolbox launchers." + +log "Applying shared Snapper and Limine retention settings." +bash "$REPO_ROOT/scripts/install/steps/07-setup-snapper" + +if [[ -f "$mimeapps_target" ]]; then + mimeapps_tmp="$(mktemp)" + awk ' + /^\[Default Applications\]$/ { + in_defaults = 1 + print + next + } + /^\[/ { + in_defaults = 0 + } + in_defaults && /^(image\/vnd\.djvu|application\/x-cb[7rtz])=/ { + next + } + in_defaults { + gsub(/org\.gnome\.Showtime\.desktop/, "mpv.desktop") + gsub(/org\.gnome\.TextEditor\.desktop/, "dev.zed.Zed.desktop") + } + { print } + ' "$mimeapps_target" >"$mimeapps_tmp" + chmod --reference="$mimeapps_target" "$mimeapps_tmp" + mv -f -- "$mimeapps_tmp" "$mimeapps_target" +else + mkdir -p "$(dirname "$mimeapps_target")" + cp -a "$MIMEAPPS_SOURCE" "$mimeapps_target" +fi +log "Updated MIME defaults for the retained application baseline." + +mkdir -p "$(dirname "$session_env_target")" +cp -a "$SESSION_ENV_SOURCE" "$session_env_target" +log "Added mise shims to the graphical session PATH; log out and back in to activate it." + +[[ -x "$HOME/.local/bin/mise" ]] || die "User-local mise is missing after migration." +log_success "Common baseline migration completed. Inventory: $inventory_root" diff --git a/packages/aur.packages b/packages/aur.packages index a26d852..40e59e0 100644 --- a/packages/aur.packages +++ b/packages/aur.packages @@ -1,5 +1,4 @@ 1password 1password-cli -t3code-bin +t3code-nightly-bin dsearch-bin -jetbrains-toolbox diff --git a/packages/base.packages b/packages/base.packages index 569c36a..c2be797 100644 --- a/packages/base.packages +++ b/packages/base.packages @@ -10,18 +10,14 @@ noto-fonts-emoji seahorse starship tldr -httpie bandwhich udiskie gvfs platformio-core signal-desktop -gimp obsidian -drawio-desktop base-devel networkmanager nm-connection-editor -showtime limine gnome-calculator diff --git a/packages/cachyos.packages b/packages/cachyos.packages index 13a0c69..d1f28c4 100644 --- a/packages/cachyos.packages +++ b/packages/cachyos.packages @@ -10,8 +10,6 @@ fzf btop fastfetch neovim -vim -yazi lazygit lazydocker fd @@ -19,7 +17,6 @@ duf dust ripgrep bat -curlie github-cli eza tokei @@ -34,14 +31,10 @@ unrar 7zip zip unzip -mise playerctl mpv -imv spotify-launcher obs-studio -kdenlive -baobab docker docker-compose gcc @@ -51,12 +44,9 @@ pacman-contrib bluez bluez-utils ghostty -gnome-text-editor loupe zathura zathura-pdf-mupdf -zathura-cb -zathura-djvu tesseract-data-eng pipewire-alsa pipewire-pulse @@ -72,10 +62,8 @@ brave-origin-bin vscodium typst tinymist -teams-for-linux -zen-browser-bin vesktop yay paru -shelly topgrade +prismlauncher diff --git a/packages/chaotic.packages b/packages/chaotic.packages index 0b03658..f2d3333 100644 --- a/packages/chaotic.packages +++ b/packages/chaotic.packages @@ -2,7 +2,6 @@ bibata-cursor-theme qt6ct-kde pinta vscodium-marketplace -zoom xdg-terminal-exec-git epson-inkjet-printer-escpr epson-inkjet-printer-escpr2 diff --git a/packages/gaming.packages b/packages/gaming.packages new file mode 100644 index 0000000..e50e437 --- /dev/null +++ b/packages/gaming.packages @@ -0,0 +1,33 @@ +# Optional gaming profile. Read by niriland-setup-gaming and by the common +# baseline migration when validating --keep-gaming protection. + +# Install the preferred Heroic provider before the application meta package. +heroic-games-launcher-bin + +# CachyOS profiles. +cachyos-gaming-meta +cachyos-gaming-applications + +# Gaming-facing dependencies supplied by the CachyOS profiles. They remain +# explicit here so status and migration output show the complete retained stack. +steam +lutris +vulkan-icd-loader +lib32-vulkan-icd-loader +proton-cachyos-slr +wine +gst-plugins-base +gst-plugins-good +winetricks +protontricks +gamescope +mangohud +goverlay +umu-launcher + +# Additional launchers and classic-game support. +wowup-cf-bin +protonup-qt +dosbox +scummvm +timidity++ diff --git a/packages/vscodium.extensions b/packages/vscodium.extensions index a388ef4..db9e21f 100644 --- a/packages/vscodium.extensions +++ b/packages/vscodium.extensions @@ -32,5 +32,4 @@ tamasfe.even-better-toml usernamehw.errorlens visualstudioexptteam.vscodeintellicode vscjava.vscode-java-pack -ziglang.vscode-zig -myriad-dreamin.tinymist \ No newline at end of file +myriad-dreamin.tinymist diff --git a/scripts/install/lib/common b/scripts/install/lib/common index b71595a..2df8561 100755 --- a/scripts/install/lib/common +++ b/scripts/install/lib/common @@ -7,6 +7,8 @@ set -euo pipefail ############################################################################## LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Consumers use this value after sourcing the library. +# shellcheck disable=SC2034 REPO_ROOT="$(cd "$LIB_DIR/../../.." && pwd)" ############################################################################## @@ -112,6 +114,74 @@ require_cmd() { command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1" } +ensure_user_mise() { + local architecture + local asset_name + local downloaded_binary + local expected_sha256 + local mise_version="2026.8.8" + + MISE_BIN="$HOME/.local/bin/mise" + export MISE_BIN + + if [[ -x "$MISE_BIN" ]]; then + log "Using user-local mise: $MISE_BIN" + return 0 + fi + + require_cmd curl + require_cmd sha256sum + + architecture="$(uname -m)" + case "$architecture" in + x86_64) + asset_name="mise-v${mise_version}-linux-x64" + expected_sha256="1fce52a3656cf14bef6feeb9f0b90d545126a0bb598f0a69afbb9e4702f8f3e3" + ;; + aarch64|arm64) + asset_name="mise-v${mise_version}-linux-arm64" + expected_sha256="76f570105249348a228af9411ca8c7869cfb4ca59de2d1dc025ac53305c5f1d5" + ;; + *) + die "Unsupported architecture for mise bootstrap: $architecture" + ;; + esac + + downloaded_binary="$(mktemp)" + + if ! curl -fsSL \ + "https://github.com/jdx/mise/releases/download/v${mise_version}/${asset_name}" \ + -o "$downloaded_binary"; then + rm -f -- "$downloaded_binary" + die "Failed to download mise v${mise_version}." + fi + + if ! printf '%s %s\n' "$expected_sha256" "$downloaded_binary" \ + | sha256sum --check --status; then + rm -f -- "$downloaded_binary" + die "Checksum verification failed for mise v${mise_version}." + fi + + mkdir -p "$(dirname "$MISE_BIN")" + if ! install -m 0755 "$downloaded_binary" "$MISE_BIN"; then + rm -f -- "$downloaded_binary" + die "Failed to install user-local mise." + fi + + rm -f -- "$downloaded_binary" + [[ -x "$MISE_BIN" ]] || die "mise installer did not create $MISE_BIN" + log_success "Installed verified mise v${mise_version}: $MISE_BIN" +} + +install_baseline_cargo_tools() { + require_cmd cargo + + cargo install --locked cargo-update + cargo install --locked just + cargo install --locked nirius + cargo install --locked watchexec-cli +} + ############################################################################## # Package Management ############################################################################## @@ -172,7 +242,8 @@ copy_file() { [[ -f "$src" ]] || die "File not found: $src" if [[ "$backup" == "true" ]] && [[ -f "$dest" ]] && ! cmp -s "$src" "$dest"; then - local backup_path="${dest}.bak.$(date +%s)" + local backup_path + backup_path="${dest}.bak.$(date +%s)" log "Backing up $dest to $backup_path..." run_sudo cp "$dest" "$backup_path" || die "Failed to backup $dest" fi diff --git a/scripts/install/steps/60-setup-dev b/scripts/install/steps/60-setup-dev index cd2bcea..e67b908 100755 --- a/scripts/install/steps/60-setup-dev +++ b/scripts/install/steps/60-setup-dev @@ -3,6 +3,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=scripts/install/lib/common source "$SCRIPT_DIR/../lib/common" log "Starting development environment setup..." @@ -40,11 +41,12 @@ fi # Mise Setup # ==================== log "Configuring mise..." -install_package mise +ensure_user_mise MISE_CONFIG="$HOME/.config/mise/config.toml" if [[ -f "$MISE_CONFIG" ]]; then - if mise install; then + if "$MISE_BIN" install; then + "$MISE_BIN" reshim log_success "mise runtimes installed from $MISE_CONFIG" else warn "mise install failed. You may need to run it manually after setup." @@ -54,9 +56,9 @@ else fi if [ -n "${BASH_VERSION:-}" ]; then - eval "$(mise activate bash)" + eval "$("$MISE_BIN" activate bash)" elif [ -n "${ZSH_VERSION:-}" ]; then - eval "$(mise activate zsh)" + eval "$("$MISE_BIN" activate zsh)" else echo "Unsupported shell: $(ps -p $$ -o comm=)" fi @@ -117,10 +119,7 @@ fi # Cargo Tools # ==================== log "Installing Cargo tools..." -require_cmd cargo - -cargo install cargo-update 2>/dev/null || true -cargo install nirius 2>/dev/null || true +install_baseline_cargo_tools # Niri user session PATH may omit ~/.cargo/bin. # Expose nirius/niriusd from ~/.local/bin so keybinds and startup spawns diff --git a/scripts/install/steps/75-setup-browser b/scripts/install/steps/75-setup-browser index 94d67ca..5f4acbc 100755 --- a/scripts/install/steps/75-setup-browser +++ b/scripts/install/steps/75-setup-browser @@ -3,6 +3,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=scripts/install/lib/common source "$SCRIPT_DIR/../lib/common" log "Installing browser dependencies" @@ -10,11 +11,19 @@ install_package "brave-origin-bin" require_paru install_aur_package "1password" -log "Adding Brave Origin and Zen to 1Password trusted browsers" +log "Adding Brave Origin to 1Password trusted browsers" log "Creating 1Password config directory" run_sudo mkdir -p /etc/1password +run_sudo touch /etc/1password/custom_allowed_browsers -printf "brave-origin\nzen-bin\n" | run_sudo tee /etc/1password/custom_allowed_browsers >/dev/null +run_sudo sed -i \ + -e '/^helium$/d' \ + -e '/^brave-origin$/d' \ + -e '/^zen-bin$/d' \ + /etc/1password/custom_allowed_browsers +printf "brave-origin\n" | run_sudo tee -a /etc/1password/custom_allowed_browsers >/dev/null +run_sudo chown root:root /etc/1password/custom_allowed_browsers +run_sudo chmod 755 /etc/1password/custom_allowed_browsers log_success "1Password trusted browsers updated" log_success "Browser setup complete." diff --git a/scripts/tools/niriland-get-default-browser b/scripts/tools/niriland-get-default-browser index 9d9d43e..300e78d 100755 --- a/scripts/tools/niriland-get-default-browser +++ b/scripts/tools/niriland-get-default-browser @@ -3,7 +3,7 @@ # Print a browser app-id matcher for nirius based on the current default browser. fallback_browser_app_id() { - echo "zen|brave-origin" + echo "brave-origin" } if ! command -v xdg-settings >/dev/null 2>&1; then diff --git a/scripts/tools/niriland-setup-ai b/scripts/tools/niriland-setup-ai index 705c093..2daaec0 100755 --- a/scripts/tools/niriland-setup-ai +++ b/scripts/tools/niriland-setup-ai @@ -37,7 +37,7 @@ usage() { Usage: niriland-setup-ai [setup|status|help] Commands: - setup Install and configure Opencode, Codex, Claude Code, Ollama, and OpenWebUI (default) + setup Install and configure Opencode, Ollama, and OpenWebUI (default) status Show service/tool status help Show this help @@ -106,36 +106,6 @@ install_opencode_if_missing() { fi } -install_codex_if_missing() { - if command -v codex >/dev/null 2>&1 || [[ -x "$HOME/.local/bin/codex" ]]; then - log "Codex already installed, skipping." - return 0 - fi - - install_package_if_missing npm - log "Installing Codex..." - if npm i -g @openai/codex --prefix "$HOME/.local"; then - log "Codex installed." - else - warn "Codex installation failed, continuing." - fi -} - -install_claude_if_missing() { - if command -v claude >/dev/null 2>&1 || [[ -x "$HOME/.local/bin/claude" ]]; then - log "Claude Code already installed, skipping." - return 0 - fi - - install_package_if_missing npm - log "Installing Claude Code..." - if npm i -g @anthropic-ai/claude-code --prefix "$HOME/.local"; then - log "Claude Code installed." - else - warn "Claude Code installation failed, continuing." - fi -} - pull_model_if_missing() { local model="$1" @@ -202,8 +172,12 @@ setup_ai() { log "Using repo: $REPO_ROOT" log "Setting up local AI tools" install_opencode_if_missing - install_codex_if_missing - install_claude_if_missing + + for baseline_tool in codex claude grok; do + if ! command -v "$baseline_tool" >/dev/null 2>&1; then + warn "$baseline_tool is missing; rerun 60-setup-dev to install the shared mise tool baseline." + fi + done log "Setting up Ollama and Docker" install_package_if_missing ollama docker diff --git a/scripts/tools/niriland-setup-gaming b/scripts/tools/niriland-setup-gaming index 71f2948..505fe32 100755 --- a/scripts/tools/niriland-setup-gaming +++ b/scripts/tools/niriland-setup-gaming @@ -4,25 +4,10 @@ set -euo pipefail NIRILAND_ROOT="${HOME}/.local/share/niriland" PRISMLAUNCHER_MRPACK="${NIRILAND_ROOT}/configs/base/.local/share/minecraft/Main.mrpack" +GAMING_PACKAGE_MANIFEST="${NIRILAND_ROOT}/packages/gaming.packages" -PACMAN_PACKAGES=( - cachyos-gaming-meta - cachyos-gaming-applications - prismlauncher - wowup-cf-bin - vulkan-icd-loader - lib32-vulkan-icd-loader - proton-cachyos-slr - protonup-qt - dosbox - inotify-tools - scummvm - timidity++ - wget - xdotool - xorg-xwininfo - yad -) +COMMON_PACKAGES=(prismlauncher) +GAMING_PACKAGES=() log() { printf '==> %s\n' "$*" @@ -59,6 +44,15 @@ require_sudo() { sudo -v || die "sudo authentication failed" } +load_gaming_packages() { + [[ -f "$GAMING_PACKAGE_MANIFEST" ]] \ + || die "Gaming package manifest not found: $GAMING_PACKAGE_MANIFEST" + + mapfile -t GAMING_PACKAGES < <(grep -Ev '^\s*(#|$)' "$GAMING_PACKAGE_MANIFEST") + [[ ${#GAMING_PACKAGES[@]} -gt 0 ]] \ + || die "Gaming package manifest is empty: $GAMING_PACKAGE_MANIFEST" +} + install_package_if_missing() { local pkg @@ -76,7 +70,9 @@ install_package_if_missing() { show_package_status() { local pkg - for pkg in "${PACMAN_PACKAGES[@]}"; do + load_gaming_packages + + for pkg in "${COMMON_PACKAGES[@]}" "${GAMING_PACKAGES[@]}"; do if pacman -Qq "$pkg" >/dev/null 2>&1; then log "$pkg is installed." else @@ -89,9 +85,10 @@ setup_gaming() { require_cmd pacman require_cmd sudo require_sudo + load_gaming_packages log "Installing gaming apps..." - install_package_if_missing "${PACMAN_PACKAGES[@]}" + install_package_if_missing "${COMMON_PACKAGES[@]}" "${GAMING_PACKAGES[@]}" if [[ -f "${PRISMLAUNCHER_MRPACK}" ]]; then log "Importing PrismLauncher pack: ${PRISMLAUNCHER_MRPACK}"