From f98606dcce3dc2bb617f932bf5ec8035cdd4d658 Mon Sep 17 00:00:00 2001 From: OlivierChiasson Date: Fri, 8 May 2026 19:12:16 -0300 Subject: [PATCH] Rebase to flake parts #7 --- modules/hosts/14900k/configuration.nix | 5 - modules/hosts/t2mbp/_private/firmware.nix | 14 ++ modules/hosts/t2mbp/_private/platform.nix | 30 ++++ modules/hosts/t2mbp/configuration.nix | 5 - .../t2mbp/t2linux/_private/boot-tuning.nix | 27 ++++ .../hosts/t2mbp/t2linux/_private/kernel.nix | 65 +++++++++ modules/hosts/t2mbp/t2linux/default.nix | 8 ++ modules/system/bluetooth.nix | 50 +++++++ modules/system/default.nix | 1 - modules/system/docker.nix | 36 +++++ modules/system/flatpak.nix | 125 +++++++++++++++++ modules/system/gaming.nix | 128 ++++++++++++++++++ modules/system/ideapad-mruby-overlay.nix | 43 ++++++ modules/system/librepods.nix | 19 +++ modules/system/localization.nix | 48 +++++++ modules/system/networking.nix | 90 ++++++++++++ modules/system/uconsole-kernel-builder.nix | 30 ++++ modules/system/users/catalog-default.nix | 76 +++++++++++ modules/wisdom/apps/discord.nix | 49 +++++++ modules/wisdom/apps/localsend.nix | 41 ++++++ modules/wisdom/apps/pokeclicker/default.nix | 16 +++ .../apps/pokeclicker/package/default.nix | 107 +++++++++++++++ modules/wisdom/apps/spotify.nix | 58 ++++++++ 23 files changed, 1060 insertions(+), 11 deletions(-) create mode 100644 modules/hosts/t2mbp/_private/firmware.nix create mode 100644 modules/hosts/t2mbp/_private/platform.nix create mode 100644 modules/hosts/t2mbp/t2linux/_private/boot-tuning.nix create mode 100644 modules/hosts/t2mbp/t2linux/_private/kernel.nix create mode 100644 modules/hosts/t2mbp/t2linux/default.nix create mode 100644 modules/system/bluetooth.nix create mode 100644 modules/system/docker.nix create mode 100644 modules/system/flatpak.nix create mode 100644 modules/system/gaming.nix create mode 100644 modules/system/ideapad-mruby-overlay.nix create mode 100644 modules/system/librepods.nix create mode 100644 modules/system/localization.nix create mode 100644 modules/system/networking.nix create mode 100644 modules/system/uconsole-kernel-builder.nix create mode 100644 modules/system/users/catalog-default.nix create mode 100644 modules/wisdom/apps/discord.nix create mode 100644 modules/wisdom/apps/localsend.nix create mode 100644 modules/wisdom/apps/pokeclicker/default.nix create mode 100644 modules/wisdom/apps/pokeclicker/package/default.nix create mode 100644 modules/wisdom/apps/spotify.nix diff --git a/modules/hosts/14900k/configuration.nix b/modules/hosts/14900k/configuration.nix index f1a7de9..f861969 100644 --- a/modules/hosts/14900k/configuration.nix +++ b/modules/hosts/14900k/configuration.nix @@ -74,11 +74,6 @@ gpuPassthrough.enable = false; }; - remoteDesktop = { - enable = false; - moonlight.enable = false; - sunshine.enable = false; - }; audio.enable = true; docker.enable = true; gaming.enable = true; diff --git a/modules/hosts/t2mbp/_private/firmware.nix b/modules/hosts/t2mbp/_private/firmware.nix new file mode 100644 index 0000000..178a26e --- /dev/null +++ b/modules/hosts/t2mbp/_private/firmware.nix @@ -0,0 +1,14 @@ +{ pkgs, ... }: { + # Apple T2 machines often need additional Broadcom firmware not shipped in + # linux-firmware. Firmware is stored in this host directory. + hardware.firmware = [ + (pkgs.stdenvNoCC.mkDerivation (final: { + name = "t2mbp-brcm-firmware"; + src = ./firmware/brcm; + installPhase = '' + mkdir -p "$out/lib/firmware/brcm" + cp -v ${final.src}/* "$out/lib/firmware/brcm" + ''; + })) + ]; +} diff --git a/modules/hosts/t2mbp/_private/platform.nix b/modules/hosts/t2mbp/_private/platform.nix new file mode 100644 index 0000000..186c581 --- /dev/null +++ b/modules/hosts/t2mbp/_private/platform.nix @@ -0,0 +1,30 @@ +{ ... }: { + # Bootloader and EFI + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + boot.loader.efi.efiSysMountPoint = "/boot"; + boot.loader.systemd-boot.configurationLimit = 5; + + # Hibernate support (resume from swap partition). + boot.resumeDevice = "/dev/disk/by-uuid/403c9698-b501-4198-96cf-f27f82f1eb1a"; + + # Suspend is allowed again: kernel cmdline + out-of-tree apple-bce are in + # `t2linux/_private/boot-tuning.nix` and `t2linux/_private/kernel.nix`. If you need + # to block sleep while debugging: `systemd.sleep.settings.Sleep.AllowSuspend = "no";` + + # Power and thermal management. + powerManagement.cpuFreqGovernor = "ondemand"; + services.thermald.enable = true; + hardware.sensor.iio.enable = true; + + + + # Pull in linux-firmware (and friends) from nixpkgs. + hardware.enableRedistributableFirmware = true; + hardware.enableAllFirmware = true; + + # Enable flakes and the newer CLI. + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + + system.stateVersion = "25.11"; +} diff --git a/modules/hosts/t2mbp/configuration.nix b/modules/hosts/t2mbp/configuration.nix index 7efb4d3..493c844 100644 --- a/modules/hosts/t2mbp/configuration.nix +++ b/modules/hosts/t2mbp/configuration.nix @@ -98,11 +98,6 @@ }; chiasson.system = { - remoteDesktop = { - enable = false; - moonlight.enable = false; - sunshine.enable = false; - }; audio.enable = true; extraPackages = [ pkgs.sops ]; networking = { diff --git a/modules/hosts/t2mbp/t2linux/_private/boot-tuning.nix b/modules/hosts/t2mbp/t2linux/_private/boot-tuning.nix new file mode 100644 index 0000000..6d0c441 --- /dev/null +++ b/modules/hosts/t2mbp/t2linux/_private/boot-tuning.nix @@ -0,0 +1,27 @@ +{ ... }: { + # T2: align with https://github.com/deqrocks/apple-bce#required-kernel-parameters (suspend stack). + # (Older t2linux guidance used s2idle + pcie_ports=compat; deqrocks fork expects deep + auto + pm_async=off.) + boot.kernelParams = [ + "mem_sleep_default=deep" + "intel_iommu=on" + "iommu=pt" + "pcie_ports=auto" + "pm_async=off" + # https://wiki.t2linux.org/guides/hybrid-graphics/#enabling-the-igpu — helps some post-suspend black screens. + "i915.enable_guc=3" + ]; + + # Hybrid T2 Macs: prefer Intel for display/GL (saves power; avoids broken AMDGPU after resume). + # https://wiki.t2linux.org/guides/hybrid-graphics/ + boot.extraModprobeConfig = '' + options apple-gmux force_igd=y + ''; + + # If the AMD dGPU misbehaves after S3 (Electron apps won’t start, suspend breaks), keep it unloaded. + # See https://github.com/deqrocks/apple-bce#notes-for-dgpu-models — drop this list if you need DRI_PRIME + # or external displays wired through the dGPU. + boot.blacklistedKernelModules = [ "amdgpu" ]; + + boot.kernelModules = [ "apple-bce" ]; + boot.initrd.availableKernelModules = [ "apple-bce" ]; +} diff --git a/modules/hosts/t2mbp/t2linux/_private/kernel.nix b/modules/hosts/t2mbp/t2linux/_private/kernel.nix new file mode 100644 index 0000000..7c0c44b --- /dev/null +++ b/modules/hosts/t2mbp/t2linux/_private/kernel.nix @@ -0,0 +1,65 @@ +{ lib, pkgs, inputs, config, ... }: +let + # Two-stage callPackage matches nixos-hardware apple/t2 generic.nix. + linuxT2GenericFromDir = + { lib, ... }@args: + { kernel, t2linuxPatchesSrc }: + let + patchNames = lib.sort lib.lessThan ( + lib.filter (n: builtins.match "^[0-9]{4}-.*\\.patch$" n != null) ( + lib.attrNames (builtins.readDir t2linuxPatchesSrc) + ) + ); + t2Patches = map + (name: { + inherit name; + patch = "${t2linuxPatchesSrc}/${name}"; + }) + patchNames; + in + kernel.override ( + args + // { + pname = "linux-t2"; + structuredExtraConfig = with lib.kernel; { + # In-tree staging driver disabled; we ship deqrocks/apple-bce via boot.extraModulePackages. + APPLE_BCE = no; + APPLE_GMUX = module; + APFS_FS = module; + BRCMFMAC = module; + BT_BCM = module; + BT_HCIBCM4377 = module; + BT_HCIUART_BCM = yes; + BT_HCIUART = module; + HID_APPLETB_BL = module; + HID_APPLETB_KBD = module; + HID_APPLE = module; + HID_MAGICMOUSE = module; + DRM_APPLETBDRM = module; + HID_SENSOR_ALS = module; + SND_PCM = module; + STAGING = yes; + }; + kernelPatches = t2Patches ++ (args.kernelPatches or [ ]); + argsOverride.extraMeta = { + description = "The Linux kernel (with patches from the T2 Linux project)"; + maintainers = with lib.maintainers; [ soopyc ]; + }; + } + // (args.argsOverride or { }) + ); + + linuxT2Kernel = (pkgs.callPackage linuxT2GenericFromDir { }) { + kernel = pkgs.linux_6_19; + t2linuxPatchesSrc = inputs.t2linux-patches; + }; +in +{ + boot.kernelPackages = lib.mkForce (pkgs.linuxPackagesFor linuxT2Kernel); + + # https://github.com/deqrocks/apple-bce (branch no-state-suspend) — BCE + suspend-oriented fixes. + # README also mentions companion userspace: t2-upower, t2-kbd-tb (not packaged here yet). + boot.extraModulePackages = [ + (config.boot.kernelPackages.callPackage ./apple-bce.nix { }) + ]; +} diff --git a/modules/hosts/t2mbp/t2linux/default.nix b/modules/hosts/t2mbp/t2linux/default.nix new file mode 100644 index 0000000..0c3b5c8 --- /dev/null +++ b/modules/hosts/t2mbp/t2linux/default.nix @@ -0,0 +1,8 @@ +{ ... }: { + flake.nixosModules.t2linux = { + imports = [ + ./_private/kernel.nix + ./_private/boot-tuning.nix + ]; + }; +} diff --git a/modules/system/bluetooth.nix b/modules/system/bluetooth.nix new file mode 100644 index 0000000..071ef91 --- /dev/null +++ b/modules/system/bluetooth.nix @@ -0,0 +1,50 @@ +{ ... }: { + flake.nixosModules.systemBluetooth = + { config, lib, pkgs, ... }: + let + cfg = config.chiasson.system.bluetooth; + d = config.chiasson.desktop or { }; + guiEnabled = + ((d.hyprland or { }).enable or false) + || ((d.niri or { }).enable or false) + || ((d.plasma or { }).enable or false); + in + { + options.chiasson.system.bluetooth = { + enable = lib.mkEnableOption '' + BlueZ defaults (power on boot, experimental, fast connectable). Pull via `client-services` or direct import; off on BT-less boxes. + '' // { + default = true; + }; + + installBluejay = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + [Bluejay](https://invent.kde.org/plasma/bluejay) on GUI hosts with BT. False → `bluetoothctl` only. + ''; + }; + }; + + config = lib.mkMerge [ + (lib.mkIf cfg.enable { + hardware.bluetooth = { + enable = true; + powerOnBoot = true; + settings = { + General = { + Experimental = true; + FastConnectable = true; + }; + Policy = { + AutoEnable = true; + }; + }; + }; + }) + (lib.mkIf (cfg.enable && cfg.installBluejay && guiEnabled) { + environment.systemPackages = [ pkgs.bluejay ]; + }) + ]; + }; +} diff --git a/modules/system/default.nix b/modules/system/default.nix index a85e08e..e090bfc 100644 --- a/modules/system/default.nix +++ b/modules/system/default.nix @@ -5,7 +5,6 @@ self.nixosModules.systemLocalization self.nixosModules.systemFonts self.nixosModules.systemNetworking - self.nixosModules.systemRemoteDesktop self.nixosModules.systemLocalsend self.nixosModules.systemMonitorInput self.nixosModules.systemSpotify diff --git a/modules/system/docker.nix b/modules/system/docker.nix new file mode 100644 index 0000000..8d382d0 --- /dev/null +++ b/modules/system/docker.nix @@ -0,0 +1,36 @@ +{ ... }: { + flake.nixosModules.systemDocker = + { config, lib, pkgs, ... }: + let + cfg = config.chiasson.system.docker; + in + { + options.chiasson.system.docker = { + enable = lib.mkEnableOption '' + `virtualisation.docker` — add users to `docker` if they need the socket. + ''; + + compose.enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Install `docker-compose` in `environment.systemPackages`."; + }; + + daemonSettings = lib.mkOption { + type = lib.types.attrs; + default = { }; + description = "Merged into `virtualisation.docker.daemon.settings`."; + }; + }; + + config = lib.mkIf cfg.enable { + virtualisation.docker = { + enable = true; + enableOnBoot = true; + daemon.settings = cfg.daemonSettings; + }; + + environment.systemPackages = lib.optionals cfg.compose.enable [ pkgs.docker-compose ]; + }; + }; +} diff --git a/modules/system/flatpak.nix b/modules/system/flatpak.nix new file mode 100644 index 0000000..6ec52f3 --- /dev/null +++ b/modules/system/flatpak.nix @@ -0,0 +1,125 @@ +{ ... }: { + flake.nixosModules.systemFlatpak = + { config, lib, pkgs, ... }: + let + cfg = config.chiasson.system.flatpak; + flathubForSystem = + lib.filter + ( + app: + if lib.elem app cfg.flathub.x86Only + then pkgs.stdenv.hostPlatform.system == "x86_64-linux" + else true + ) + cfg.flathub.appIds; + allowedAppIds = cfg.flathub.appIds ++ cfg.unmanaged.appIds; + # Bump in Nix when allowlists change; used to skip slow `flatpak update` / `uninstall --unused` on no-op rebuilds. + declarativeHash = builtins.hashString "sha256" ( + lib.concatStringsSep "\n" ( + [ "allowed" ] + ++ lib.sort lib.lessThan allowedAppIds + ++ [ "flathub" ] + ++ lib.sort lib.lessThan flathubForSystem + ) + ); + stateFile = "/var/lib/nixos/flatpak-declarative.hash"; + in + { + options.chiasson.system.flatpak = { + enable = lib.mkEnableOption '' + System Flatpak (`services.flatpak`) plus an activation script: Flathub remote, allowlisted apps, + and removals for anything else. User Flatpak stays in Home Manager. + ''; + + runHeavyMaintenanceEverySwitch = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + When false (default), `flatpak update` and `flatpak uninstall --unused` run only if the + allowlists changed (hash in `/var/lib/nixos/flatpak-declarative.hash`). Remotes, removals, + and per-app `install` still run every activation. True = full update/unused every switch. + ''; + }; + + flathub.appIds = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Flathub app IDs to install system-wide."; + }; + + flathub.x86Only = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Subset of `flathub.appIds` only installed on x86_64-linux."; + }; + + unmanaged.appIds = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ "com.hypixel.HytaleLauncher" ]; + description = '' + Installed from elsewhere (not Flathub); never auto-installed and never removed by the script. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + services.flatpak.enable = true; + + system.activationScripts.flatpakManagement = { + text = '' + STATE_FILE=${lib.escapeShellArg stateFile} + WANT_HASH=${lib.escapeShellArg declarativeHash} + HEAVY=${if cfg.runHeavyMaintenanceEverySwitch then "1" else "0"} + + mkdir -p /var/lib/nixos + + # Never remote-delete flathub here — interactive and breaks unattended rebuilds. + ${pkgs.flatpak}/bin/flatpak --system remote-add --if-not-exists flathub \ + https://flathub.org/repo/flathub.flatpakrepo || true + ${pkgs.flatpak}/bin/flatpak --system remote-modify flathub \ + --url=https://flathub.org/repo/flathub.flatpakrepo 2>/dev/null || true + + allowed=( ${lib.concatStringsSep " " (map lib.escapeShellArg allowedAppIds)} ) + + installedFlatpaks=$(${pkgs.flatpak}/bin/flatpak --system list --app --columns=application) + + for installed in $installedFlatpaks; do + keep=0 + for a in "''${allowed[@]}"; do + if [ "$installed" = "$a" ]; then + keep=1 + break + fi + done + if [ "$keep" -eq 0 ]; then + echo "flatpak: removing $installed (not in allowed list)." + ${pkgs.flatpak}/bin/flatpak --system uninstall -y --noninteractive "$installed" + fi + done + + for app in ${lib.escapeShellArgs flathubForSystem}; do + echo "flatpak: ensuring $app (Flathub)." + if ! ${pkgs.flatpak}/bin/flatpak --system install -y --noninteractive flathub "$app"; then + echo "flatpak: WARN failed to install $app (skip)." >&2 + fi + done + + run_heavy=0 + if [ "$HEAVY" -eq 1 ]; then + run_heavy=1 + elif [ ! -f "$STATE_FILE" ] || [ "$(cat "$STATE_FILE")" != "$WANT_HASH" ]; then + run_heavy=1 + fi + + if [ "$run_heavy" -eq 1 ]; then + ${pkgs.flatpak}/bin/flatpak --system uninstall --unused -y --noninteractive || true + ${pkgs.flatpak}/bin/flatpak --system update -y --noninteractive || true + printf '%s' "$WANT_HASH" > "$STATE_FILE" + else + echo "flatpak: allowlists unchanged — skipping update and uninstall --unused." + fi + ''; + }; + }; + }; +} diff --git a/modules/system/gaming.nix b/modules/system/gaming.nix new file mode 100644 index 0000000..6cd4288 --- /dev/null +++ b/modules/system/gaming.nix @@ -0,0 +1,128 @@ +{ ... }: { + flake.nixosModules.systemGaming = + { config, lib, pkgs, ... }: + let + cfg = config.chiasson.system.gaming; + launcherPkgs = + with pkgs; + [ + lutris + bottles + wine + winetricks + gamemode + mangohud + goverlay + ] + ++ lib.optionals pkgs.stdenv.isx86_64 [ heroic ]; + + steamExtraPkgs = + if !cfg.steam.steamTinkerLaunch.enable then + [ ] + else + lib.optional (lib.meta.availableOn pkgs.stdenv.hostPlatform pkgs.steamtinkerlaunch) pkgs.steamtinkerlaunch; + in + { + options.chiasson.system.gaming = { + enable = lib.mkEnableOption '' + Steam (+ firewall toggles), 32-bit GL/Vulkan, gamemode, JACK via PipeWire, launcher bundle. + ''; + + steam = { + remotePlay.openFirewall = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Open firewall for Steam Remote Play."; + }; + dedicatedServer.openFirewall = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Open firewall for Steam dedicated servers."; + }; + + steamTinkerLaunch.enable = lib.mkEnableOption '' + [SteamTinkerLaunch](https://github.com/frostworx/steamtinkerlaunch) — Steam wrapper for + custom launch options, Proton helpers, and third-party tools. Adds `pkgs.steamtinkerlaunch` + next to the launcher package set (`environment.systemPackages` or `launchers.forUsers`). + ''; + }; + + graphics = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "`hardware.graphics.enable` (Vulkan/GL stack)."; + }; + enable32Bit = lib.mkOption { + type = lib.types.bool; + default = true; + description = "`hardware.graphics.enable32Bit` (Steam / Proton 32-bit)."; + }; + }; + + gamemode.enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "`programs.gamemode` (Feral GameMode)."; + }; + + jack.enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Set `chiasson.system.audio.pipewire.jack.enable` (PipeWire JACK). Requires + `chiasson.system.audio.enable` on the host. + ''; + }; + + launchers = { + forUsers = lib.mkOption { + type = lib.types.nullOr (lib.types.listOf lib.types.str); + default = null; + description = '' + Per-user `packages` for launchers; `null` → `environment.systemPackages`. + ''; + }; + extraPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; + default = [ ]; + description = "Additional packages merged with the default launcher set."; + }; + }; + }; + + config = lib.mkIf cfg.enable (lib.mkMerge [ + { + programs.steam = { + enable = true; + remotePlay.openFirewall = cfg.steam.remotePlay.openFirewall; + dedicatedServer.openFirewall = cfg.steam.dedicatedServer.openFirewall; + }; + + hardware.graphics = lib.mkIf cfg.graphics.enable { + enable = true; + enable32Bit = cfg.graphics.enable32Bit; + }; + + programs.gamemode.enable = cfg.gamemode.enable; + + chiasson.system.audio.pipewire.jack.enable = lib.mkIf (cfg.jack.enable) (lib.mkDefault true); + + assertions = [ + { + assertion = !cfg.enable || !cfg.jack.enable || config.chiasson.system.audio.enable; + message = "chiasson.system.gaming with JACK requires `chiasson.system.audio.enable` (PipeWire)."; + } + ]; + } + (lib.mkIf (cfg.launchers.forUsers == null) { + environment.systemPackages = launcherPkgs ++ steamExtraPkgs ++ cfg.launchers.extraPackages; + }) + (lib.mkIf (cfg.launchers.forUsers != null) { + users.users = lib.genAttrs cfg.launchers.forUsers (_: { + packages = launcherPkgs ++ steamExtraPkgs ++ cfg.launchers.extraPackages; + }); + }) + ]); + }; +} diff --git a/modules/system/ideapad-mruby-overlay.nix b/modules/system/ideapad-mruby-overlay.nix new file mode 100644 index 0000000..7ba0764 --- /dev/null +++ b/modules/system/ideapad-mruby-overlay.nix @@ -0,0 +1,43 @@ +# Mobile NixOS mruby fails tests in sandbox — strip checks + rebuild script-loader. Import before device config. +{ inputs, ... }: { + flake.nixosModules.systemIdeapadMrubyOverlay = + { config, lib, ... }: + let + cfg = config.chiasson.system.ideapadMrubyOverlay; + mobileNixosSrc = inputs.mobile-nixos; + in + { + options.chiasson.system.ideapadMrubyOverlay = { + enable = lib.mkEnableOption '' + Fix mruby for Mobile NixOS (no tests) + script-loader rebuild. Needs `mobile-nixos` input. + ''; + }; + + config = lib.mkIf cfg.enable { + nixpkgs.overlays = lib.mkOrder 1000 [ + (final: prev: + let + fixMruby = + drv: + drv.overrideAttrs (old: { + doCheck = false; + preCheck = (old.preCheck or "") + '' + export SHELL="${final.bash}/bin/bash" + unset SOURCE_DATE_EPOCH + ''; + }); + mrubyFixed = + prev.lib.makeOverridable (args: fixMruby (prev.mruby.override args)) { }; + in + { + mruby = mrubyFixed; + mobile-nixos = (prev.mobile-nixos or { }) // { + script-loader = final.callPackage "${mobileNixosSrc}/boot/script-loader" { + mruby = mrubyFixed; + }; + }; + }) + ]; + }; + }; +} diff --git a/modules/system/librepods.nix b/modules/system/librepods.nix new file mode 100644 index 0000000..24f84d0 --- /dev/null +++ b/modules/system/librepods.nix @@ -0,0 +1,19 @@ +# LibrePods from NUR (nur.repos.chiasson) + Apple-ish BlueZ DeviceID for AirPods. +{ ... }: { + flake.nixosModules.systemLibrepods = + { config, lib, pkgs, ... }: + let + cfg = config.chiasson.system.librepods; + librepodsPkg = pkgs.nur.repos.chiasson.librepods; + in + { + options.chiasson.system.librepods.enable = lib.mkEnableOption '' + LibrePods (NUR chiasson) + BlueZ DeviceID tweak. Needs working Bluetooth. + ''; + + config = lib.mkIf cfg.enable { + hardware.bluetooth.settings.General.DeviceID = lib.mkDefault "bluetooth:004C:0000:0000"; + environment.systemPackages = [ librepodsPkg ]; + }; + }; +} diff --git a/modules/system/localization.nix b/modules/system/localization.nix new file mode 100644 index 0000000..f351212 --- /dev/null +++ b/modules/system/localization.nix @@ -0,0 +1,48 @@ +{ self, lib, ... }: { + flake.nixosModules.systemLocalization = { + config, + ... + }: + let + cfg = config.chiasson.system.localization; + in + { + options.chiasson.system.localization = { + timeZone = lib.mkOption { + type = lib.types.str; + default = "America/Moncton"; + description = "Default system timezone."; + }; + defaultLocale = lib.mkOption { + type = lib.types.str; + default = "en_CA.UTF-8"; + description = "Default system locale."; + }; + xkb = { + layout = lib.mkOption { + type = lib.types.str; + default = "ca"; + description = "Default XKB layout."; + }; + variant = lib.mkOption { + type = lib.types.str; + default = ""; + description = "Default XKB variant."; + }; + }; + consoleKeyMap = lib.mkOption { + type = lib.types.str; + default = "cf"; + description = "Default Linux console keymap."; + }; + }; + + config = { + time.timeZone = lib.mkDefault cfg.timeZone; + i18n.defaultLocale = lib.mkDefault cfg.defaultLocale; + services.xserver.xkb.layout = lib.mkDefault cfg.xkb.layout; + services.xserver.xkb.variant = lib.mkDefault cfg.xkb.variant; + console.keyMap = lib.mkDefault cfg.consoleKeyMap; + }; + }; +} diff --git a/modules/system/networking.nix b/modules/system/networking.nix new file mode 100644 index 0000000..08de3c9 --- /dev/null +++ b/modules/system/networking.nix @@ -0,0 +1,90 @@ +{ ... }: { + flake.nixosModules.systemNetworking = { + config, + lib, + pkgs, + ... + }: + let + cfg = config.chiasson.system.networking; + in + { + options.chiasson.system.networking = { + hostName = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "t2mbp"; + description = "System hostname."; + }; + + networkManager = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable NetworkManager."; + }; + unmanaged = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Interfaces/patterns for NetworkManager to leave unmanaged."; + }; + }; + + wifi.tools = { + enabled = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Install Wi-Fi troubleshooting tools."; + }; + packages = lib.mkOption { + type = lib.types.listOf lib.types.package; + default = with pkgs; [ + iw + wirelesstools + ]; + description = "Wi-Fi troubleshooting packages."; + }; + }; + + firewall = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable host firewall."; + }; + allowedTCPPorts = lib.mkOption { + type = lib.types.listOf lib.types.port; + default = [ ]; + description = "TCP ports allowed through firewall."; + }; + allowedUDPPorts = lib.mkOption { + type = lib.types.listOf lib.types.port; + default = [ ]; + description = "UDP ports allowed through firewall."; + }; + }; + }; + + config = lib.mkMerge [ + (lib.mkIf (cfg.hostName != null) { + networking.hostName = cfg.hostName; + }) + (lib.mkIf cfg.networkManager.enable { + networking.networkmanager.enable = true; + networking.networkmanager.unmanaged = cfg.networkManager.unmanaged; + }) + (lib.mkIf cfg.wifi.tools.enabled { + environment.systemPackages = cfg.wifi.tools.packages; + }) + { + networking.firewall.enable = cfg.firewall.enable; + } + (lib.mkIf (cfg.firewall.allowedTCPPorts != [ ]) { + networking.firewall.allowedTCPPorts = cfg.firewall.allowedTCPPorts; + }) + (lib.mkIf (cfg.firewall.allowedUDPPorts != [ ]) { + networking.firewall.allowedUDPPorts = cfg.firewall.allowedUDPPorts; + }) + ]; + }; +} diff --git a/modules/system/uconsole-kernel-builder.nix b/modules/system/uconsole-kernel-builder.nix new file mode 100644 index 0000000..816573e --- /dev/null +++ b/modules/system/uconsole-kernel-builder.nix @@ -0,0 +1,30 @@ +{ ... }: { + flake.nixosModules.systemUconsoleKernelBuilder = + { config, lib, pkgs, ... }: + let + cfg = config.chiasson.system.uconsoleKernelBuilder; + in + { + options.chiasson.system.uconsoleKernelBuilder = { + enable = lib.mkEnableOption '' + x86_64 box: binfmt aarch64, looser sandbox, uConsole cache, ccache — for building the Pi image. Not for the device. + ''; + }; + + config = lib.mkIf cfg.enable { + nix.settings = { + extra-platforms = lib.mkDefault [ "aarch64-linux" ]; + + # Cross builds hit seccomp weirdness — turn sandbox off on this role. + sandbox = lib.mkDefault false; + filter-syscalls = lib.mkDefault false; + + extra-sandbox-paths = [ config.programs.ccache.cacheDir ]; + }; + + boot.binfmt.emulatedSystems = lib.mkDefault [ "aarch64-linux" ]; + + programs.ccache.enable = true; + }; + }; +} diff --git a/modules/system/users/catalog-default.nix b/modules/system/users/catalog-default.nix new file mode 100644 index 0000000..590aa19 --- /dev/null +++ b/modules/system/users/catalog-default.nix @@ -0,0 +1,76 @@ +# Shared user definitions for all hosts that import `nixosModules.users`. +# Module (not bare attrset) so catalog entries can use `config.*` for sops paths etc. +{ ... }: { + flake.nixosModules.usersCatalogDefaults = + { config, ... }: + { + config.chiasson.users.catalog = { + olivier = { + isNormalUser = true; + description = "Olivier"; + extraGroups = [ + "networkmanager" + "wheel" + "libvirtd" + "docker" + "fuse" + "uinput" + "kvm" + ]; + + # Host must set `sops.secrets."users/olivier/hashedPassword".neededForUsers = true`. + # With that, `.path` is under /run/secrets-for-users/… (sops-nix README). + hashedPasswordFile = config.sops.secrets."users/olivier/hashedPassword".path; + + homeManager = { + enable = true; + module = + { ... }: + { + home.username = "olivier"; + home.homeDirectory = "/home/olivier"; + home.stateVersion = "25.11"; + programs.home-manager.enable = true; + }; + }; + + ssh = { + inbound = { + enable = true; + authorizedHosts = "all"; + }; + outbound = { + rbw = { + enable = true; + hosts = "all"; + }; + }; + }; + }; + + server = { + isNormalUser = true; + description = "Server user"; + extraGroups = [ "wheel" ]; + + homeManager = { + enable = false; + module = null; + }; + + ssh = { + inbound = { + enable = true; + authorizedHosts = "all"; + }; + outbound = { + rbw = { + enable = false; + hosts = "all"; + }; + }; + }; + }; + }; + }; +} diff --git a/modules/wisdom/apps/discord.nix b/modules/wisdom/apps/discord.nix new file mode 100644 index 0000000..fe991d1 --- /dev/null +++ b/modules/wisdom/apps/discord.nix @@ -0,0 +1,49 @@ +{ inputs, ... }: { + flake.homeManagerModules.wisdomAppsDiscord = + { config, lib, pkgs, ... }: + let + root = config.chiasson.home; + cfg = config.chiasson.home.apps.discord; + # nixcord still pulls `discord` on some paths; that package is not built for aarch64-linux. + nixcordSupported = lib.meta.availableOn pkgs.stdenv.hostPlatform pkgs.discord; + in + { + imports = [ inputs.nixcord.homeModules.default ]; + + options.chiasson.home.apps.discord.enable = lib.mkEnableOption '' + Vesktop (nixcord). Needs nixpkgs `discord` — breaks on e.g. aarch64-linux. + ''; + + config = lib.mkIf root.enable (lib.mkMerge [ + { + assertions = lib.mkIf cfg.enable [ + { + assertion = nixcordSupported; + message = "chiasson.home.apps.discord uses nixcord, which currently requires nixpkgs `discord` (not available on ${pkgs.stdenv.hostPlatform.system}). Disable `chiasson.home.apps.discord` on this host."; + } + ]; + } + (lib.mkIf (cfg.enable && nixcordSupported) { + programs.nixcord = { + enable = true; + vesktop.enable = true; + dorion.enable = false; + config = { + useQuickCss = true; + transparent = true; + enabledThemes = lib.optionals ( + lib.attrByPath [ "programs" "dank-material-shell" "enable" ] false config + ) [ "dank-discord.css" ]; + plugins = { + showHiddenChannels = { + enable = true; + showMode = 0; + }; + platformIndicators.enable = true; + }; + }; + }; + }) + ]); + }; +} diff --git a/modules/wisdom/apps/localsend.nix b/modules/wisdom/apps/localsend.nix new file mode 100644 index 0000000..b0312ed --- /dev/null +++ b/modules/wisdom/apps/localsend.nix @@ -0,0 +1,41 @@ +{ ... }: { + flake.nixosModules.systemLocalsend = + { config, lib, ... }: + let + cfg = config.chiasson.system.localsend; + in + { + options.chiasson.system.localsend.openFirewall = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Open TCP/UDP **53317** for LocalSend. Use with `wisdomAppsLocalsend` on the user side. + ''; + }; + + config = lib.mkIf cfg.openFirewall { + networking.firewall.allowedTCPPorts = [ 53317 ]; + networking.firewall.allowedUDPPorts = [ 53317 ]; + }; + }; + + flake.homeManagerModules.wisdomAppsLocalsend = + { config, lib, pkgs, ... }: + let + root = config.chiasson.home; + cfg = config.chiasson.home.apps.localsend; + in + { + options.chiasson.home.apps.localsend = { + enable = lib.mkEnableOption '' + LocalSend client; open the firewall on NixOS with `system.localsend` if you want inbound. + ''; + + package = lib.mkPackageOption pkgs "localsend" { }; + }; + + config = lib.mkIf (root.enable && cfg.enable) { + home.packages = [ cfg.package ]; + }; + }; +} diff --git a/modules/wisdom/apps/pokeclicker/default.nix b/modules/wisdom/apps/pokeclicker/default.nix new file mode 100644 index 0000000..9edad47 --- /dev/null +++ b/modules/wisdom/apps/pokeclicker/default.nix @@ -0,0 +1,16 @@ +{ ... }: { + flake.homeManagerModules.wisdomAppsPokeclicker = + { config, lib, pkgs, ... }: + let + root = config.chiasson.home; + cfg = config.chiasson.home.apps.pokeclicker; + pokeclickerPkg = pkgs.callPackage ./package { }; + in + { + options.chiasson.home.apps.pokeclicker.enable = lib.mkEnableOption "PokéClicker desktop (Farigh fork .deb → nix)."; + + config = lib.mkIf (root.enable && cfg.enable) { + home.packages = [ pokeclickerPkg ]; + }; + }; +} diff --git a/modules/wisdom/apps/pokeclicker/package/default.nix b/modules/wisdom/apps/pokeclicker/package/default.nix new file mode 100644 index 0000000..4a2857d --- /dev/null +++ b/modules/wisdom/apps/pokeclicker/package/default.nix @@ -0,0 +1,107 @@ +{ + lib, + stdenvNoCC, + fetchurl, + dpkg, + makeWrapper, + autoPatchelfHook, + alsa-lib, + gtk3, + libnotify, + nss, + xdg-utils, + at-spi2-core, + libsecret, + libuuid, + mesa, + xorg, +}: + +let + version = "1.2.13"; + + srcInfo = + if stdenvNoCC.hostPlatform.system == "x86_64-linux" then + { + url = "https://github.com/Farigh/pokeclicker-automation-desktop/releases/download/v${version}/pokeclicker-desktop-with-scripts_${version}_amd64.deb"; + hash = "sha256-V4z0RDyaJHICUBcFanfZqGVHNVJcKakABx9RSen6hZw="; + } + else if stdenvNoCC.hostPlatform.system == "aarch64-linux" then + { + url = "https://github.com/Farigh/pokeclicker-automation-desktop/releases/download/v${version}/pokeclicker-desktop-with-scripts_${version}_arm64.deb"; + hash = "sha256-tcVD0eV3hT9Iq75cJ7o/EK7uLHHBWhxdUHsWdJvcNlk="; + } + else + throw "pokeclicker-automation-desktop: unsupported platform: ${stdenvNoCC.hostPlatform.system}"; +in +stdenvNoCC.mkDerivation { + pname = "pokeclicker-automation-desktop"; + inherit version; + + src = fetchurl srcInfo; + + nativeBuildInputs = [ + dpkg + makeWrapper + autoPatchelfHook + ]; + + buildInputs = [ + alsa-lib + gtk3 + libnotify + mesa + nss + xdg-utils + at-spi2-core + libsecret + libuuid + xorg.libXScrnSaver + xorg.libXtst + ]; + + unpackPhase = "true"; + + installPhase = '' + runHook preInstall + + dpkg-deb -x "$src" "$out" + + if [ -d "$out/usr/share" ]; then + mkdir -p "$out/share" + mv "$out/usr/share/"* "$out/share/" + rmdir -p --ignore-fail-on-non-empty "$out/usr" || true + fi + + mkdir -p "$out/bin" + + appDir="$out/opt/PokéClicker with Scripts" + makeWrapper "$appDir/pokeclicker-desktop-with-scripts" "$out/bin/pokeclicker-desktop-with-scripts" \ + --add-flags "--no-sandbox" + + ln -s "$out/bin/pokeclicker-desktop-with-scripts" "$out/bin/pokeclicker-automation-desktop" + + desktopFile="$out/share/applications/pokeclicker-desktop-with-scripts.desktop" + if [ -f "$desktopFile" ]; then + substituteInPlace "$desktopFile" \ + --replace 'Exec="/opt/PokéClicker with Scripts/pokeclicker-desktop-with-scripts" %U' \ + 'Exec=pokeclicker-desktop-with-scripts %U' + fi + + runHook postInstall + ''; + + autoPatchelfIgnoreMissingDeps = true; + + meta = with lib; { + description = "PokéClicker desktop wrapper with scripts support (Farigh fork)"; + homepage = "https://github.com/Farigh/pokeclicker-automation-desktop"; + license = licenses.isc; + platforms = [ + "x86_64-linux" + "aarch64-linux" + ]; + mainProgram = "pokeclicker-desktop-with-scripts"; + sourceProvenance = with sourceTypes; [ binaryNativeCode ]; + }; +} diff --git a/modules/wisdom/apps/spotify.nix b/modules/wisdom/apps/spotify.nix new file mode 100644 index 0000000..d961f7a --- /dev/null +++ b/modules/wisdom/apps/spotify.nix @@ -0,0 +1,58 @@ +{ inputs, ... }: { + flake.homeManagerModules.wisdomAppsSpotify = + { config, lib, pkgs, ... }: + let + root = config.chiasson.home; + cfg = config.chiasson.home.apps.spotify; + spicePkgs = inputs.spicetify-nix.legacyPackages.${pkgs.stdenv.hostPlatform.system}; + in + { + imports = [ inputs.spicetify-nix.homeManagerModules.default ]; + + options.chiasson.home.apps.spotify.enable = lib.mkEnableOption '' + x86_64: spicetify + Spotify; others: `spotify-player`; aarch64 also gets `ncspot`. + ''; + + options.chiasson.home.apps.spotify.openDiscoveryFirewall = lib.mkEnableOption '' + Punch TCP 57621 / UDP 5353 on the host firewall for LAN discovery (needs Spotify enabled here). + ''; + + config = lib.mkIf (root.enable && cfg.enable) { + programs.spicetify = lib.mkIf pkgs.stdenv.isx86_64 { + enable = true; + enabledCustomApps = [ + spicePkgs.apps.ncsVisualizer + spicePkgs.apps.lyricsPlus + ]; + enabledExtensions = [ spicePkgs.extensions.fullScreen ]; + }; + + home.packages = + with pkgs; + [ spotify-player ] + ++ lib.optionals pkgs.stdenv.hostPlatform.isAarch64 [ ncspot ]; + }; + }; + + # Opens Spotify LAN ports when any wired HM user sets `chiasson.home.apps.spotify.*` (requires HM+NixOS). + flake.nixosModules.systemSpotify = + { config, lib, ... }: + let + users = config.home-manager.users or { }; + userOpensDiscovery = + name: + let + u = users.${name}; + in + (lib.attrByPath [ "chiasson" "home" "enable" ] false u) + && (lib.attrByPath [ "chiasson" "home" "apps" "spotify" "enable" ] false u) + && (lib.attrByPath [ "chiasson" "home" "apps" "spotify" "openDiscoveryFirewall" ] false u); + anyDiscovery = lib.any userOpensDiscovery (lib.attrNames users); + in + { + config = lib.mkIf anyDiscovery { + networking.firewall.allowedTCPPorts = [ 57621 ]; + networking.firewall.allowedUDPPorts = [ 5353 ]; + }; + }; +}